]> git.saurik.com Git - apple/cf.git/blob - CFPlatform.c
CF-635.tar.gz
[apple/cf.git] / CFPlatform.c
1 /*
2 * Copyright (c) 2011 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 /* CFPlatform.c
25 Copyright (c) 1999-2011, Apple Inc. All rights reserved.
26 Responsibility: Tony Parker
27 */
28
29 #include "CFInternal.h"
30 #include <CoreFoundation/CFPriv.h>
31 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
32 #include <stdlib.h>
33 #include <sys/stat.h>
34 #include <string.h>
35 #include <unistd.h>
36 #include <fcntl.h>
37 #include <pwd.h>
38 #include <crt_externs.h>
39 #include <mach-o/dyld.h>
40 #endif
41
42 #if DEPLOYMENT_TARGET_WINDOWS
43 #include <shellapi.h>
44 #include <shlobj.h>
45 #include <WinIoCtl.h>
46
47 #define getcwd _NS_getcwd
48
49 #endif
50
51 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS
52 #define kCFPlatformInterfaceStringEncoding kCFStringEncodingUTF8
53 #else
54 #define kCFPlatformInterfaceStringEncoding CFStringGetSystemEncoding()
55 #endif
56
57 static CFStringRef _CFUserName(void);
58
59 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
60 // CoreGraphics and LaunchServices are only projects (1 Dec 2006) that use these
61 char **_CFArgv(void) { return *_NSGetArgv(); }
62 int _CFArgc(void) { return *_NSGetArgc(); }
63 #endif
64
65
66 __private_extern__ Boolean _CFGetCurrentDirectory(char *path, int maxlen) {
67 return getcwd(path, maxlen) != NULL;
68 }
69
70 #if SUPPORT_CFM
71 static Boolean __CFIsCFM = false;
72
73 // If called super early, we just return false
74 __private_extern__ Boolean _CFIsCFM(void) {
75 return __CFIsCFM;
76 }
77 #endif
78
79 #if DEPLOYMENT_TARGET_WINDOWS
80 #define PATH_SEP '\\'
81 #else
82 #define PATH_SEP '/'
83 #endif
84
85
86 #if DEPLOYMENT_TARGET_WINDOWS
87 // Returns the path to the CF DLL, which we can then use to find resources like char sets
88 bool bDllPathCached = false;
89 __private_extern__ const wchar_t *_CFDLLPath(void) {
90 static wchar_t cachedPath[MAX_PATH+1];
91
92 if (!bDllPathCached) {
93 #ifdef _DEBUG
94 // might be nice to get this from the project file at some point
95 wchar_t *DLLFileName = L"CoreFoundation_debug.dll";
96 #else
97 wchar_t *DLLFileName = L"CoreFoundation.dll";
98 #endif
99 HMODULE ourModule = GetModuleHandleW(DLLFileName);
100
101 CFAssert(ourModule, __kCFLogAssertion, "GetModuleHandle failed");
102
103 DWORD wResult = GetModuleFileNameW(ourModule, cachedPath, MAX_PATH+1);
104 CFAssert1(wResult > 0, __kCFLogAssertion, "GetModuleFileName failed: %d", GetLastError());
105 CFAssert1(wResult < MAX_PATH+1, __kCFLogAssertion, "GetModuleFileName result truncated: %s", cachedPath);
106
107 // strip off last component, the DLL name
108 CFIndex idx;
109 for (idx = wResult - 1; idx; idx--) {
110 if ('\\' == cachedPath[idx]) {
111 cachedPath[idx] = '\0';
112 break;
113 }
114 }
115 bDllPathCached = true;
116 }
117 return cachedPath;
118 }
119 #endif
120
121 static const char *__CFProcessPath = NULL;
122 static const char *__CFprogname = NULL;
123
124 const char **_CFGetProgname(void) {
125 if (!__CFprogname)
126 _CFProcessPath(); // sets up __CFprogname as a side-effect
127 return &__CFprogname;
128 }
129
130 const char **_CFGetProcessPath(void) {
131 if (!__CFProcessPath)
132 _CFProcessPath(); // sets up __CFProcessPath as a side-effect
133 return &__CFProcessPath;
134 }
135
136 #if DEPLOYMENT_TARGET_WINDOWS
137 const char *_CFProcessPath(void) {
138 if (__CFProcessPath) return __CFProcessPath;
139 wchar_t buf[CFMaxPathSize] = {0};
140 DWORD rlen = GetModuleFileNameW(NULL, buf, sizeof(buf) / sizeof(buf[0]));
141 if (0 < rlen) {
142 char asciiBuf[CFMaxPathSize] = {0};
143 int res = WideCharToMultiByte(CP_UTF8, 0, buf, rlen, asciiBuf, sizeof(asciiBuf) / sizeof(asciiBuf[0]), NULL, NULL);
144 if (0 < res) {
145 __CFProcessPath = strdup(asciiBuf);
146 __CFprogname = strrchr(__CFProcessPath, PATH_SEP);
147 __CFprogname = (__CFprogname ? __CFprogname + 1 : __CFProcessPath);
148 }
149 }
150 if (!__CFProcessPath) {
151 __CFProcessPath = "";
152 __CFprogname = __CFProcessPath;
153 }
154 return __CFProcessPath;
155 }
156 #endif
157
158 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
159 const char *_CFProcessPath(void) {
160 if (__CFProcessPath) return __CFProcessPath;
161 #if DEPLOYMENT_TARGET_MACOSX
162 if (!issetugid()) {
163 const char *path = (char *)__CFgetenv("CFProcessPath");
164 if (path) {
165 __CFProcessPath = strdup(path);
166 __CFprogname = strrchr(__CFProcessPath, PATH_SEP);
167 __CFprogname = (__CFprogname ? __CFprogname + 1 : __CFProcessPath);
168 return __CFProcessPath;
169 }
170 }
171 #endif
172 uint32_t size = CFMaxPathSize;
173 char buffer[size];
174 if (0 == _NSGetExecutablePath(buffer, &size)) {
175 #if SUPPORT_CFM
176 size_t len = strlen(buffer);
177 if (12 <= len && 0 == strcmp("LaunchCFMApp", buffer + len - 12)) {
178 struct stat exec, lcfm;
179 const char *launchcfm = "/System/Library/Frameworks/Carbon.framework/Versions/Current/Support/LaunchCFMApp";
180 if (0 == stat(launchcfm, &lcfm) && 0 == stat(buffer, &exec) && (lcfm.st_dev == exec.st_dev) && (lcfm.st_ino == exec.st_ino)) {
181 // Executable is LaunchCFMApp, take special action
182 __CFIsCFM = true;
183 if ((*_NSGetArgv())[1] && '/' == *((*_NSGetArgv())[1])) {
184 strlcpy(buffer, (*_NSGetArgv())[1], sizeof(buffer));
185 }
186 }
187 }
188 #endif
189 __CFProcessPath = strdup(buffer);
190 __CFprogname = strrchr(__CFProcessPath, PATH_SEP);
191 __CFprogname = (__CFprogname ? __CFprogname + 1 : __CFProcessPath);
192 }
193 if (!__CFProcessPath) {
194 __CFProcessPath = "";
195 __CFprogname = __CFProcessPath;
196 }
197 return __CFProcessPath;
198 }
199 #endif
200
201 #if DEPLOYMENT_TARGET_LINUX
202 #include <unistd.h>
203
204 const char *_CFProcessPath(void) {
205 if (__CFProcessPath) return __CFProcessPath;
206 char buf[CFMaxPathSize + 1];
207
208 ssize_t res = readlink("/proc/self/exe", buf, CFMaxPathSize);
209 if (res > 0) {
210 // null terminate, readlink does not
211 buf[res] = 0;
212 __CFProcessPath = strdup(buf);
213 __CFprogname = strrchr(__CFProcessPath, PATH_SEP);
214 __CFprogname = (__CFprogname ? __CFprogname + 1 : __CFProcessPath);
215 } else {
216 __CFProcessPath = "";
217 __CFprogname = __CFProcessPath;
218 }
219 return __CFProcessPath;
220 }
221 #endif
222
223 __private_extern__ CFStringRef _CFProcessNameString(void) {
224 static CFStringRef __CFProcessNameString = NULL;
225 if (!__CFProcessNameString) {
226 const char *processName = *_CFGetProgname();
227 if (!processName) processName = "";
228 CFStringRef newStr = CFStringCreateWithCString(kCFAllocatorSystemDefault, processName, kCFPlatformInterfaceStringEncoding);
229 if (!OSAtomicCompareAndSwapPtrBarrier(NULL, (void *) newStr, (void * volatile *)& __CFProcessNameString)) {
230 CFRelease(newStr); // someone else made the assignment, so just release the extra string.
231 }
232 }
233 return __CFProcessNameString;
234 }
235
236 static CFStringRef __CFUserName = NULL;
237 static CFSpinLock_t __CFPlatformCacheLock = CFSpinLockInit;
238
239 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_LINUX || DEPLOYMENT_TARGET_FREEBSD
240
241 #include <pwd.h>
242
243 static CFURLRef __CFHomeDirectory = NULL;
244 static uint32_t __CFEUID = -1;
245 static uint32_t __CFUID = -1;
246
247 static CFURLRef _CFCopyHomeDirURLForUser(struct passwd *upwd) { // __CFPlatformCacheLock must be locked on entry and will be on exit
248 CFURLRef home = NULL;
249 if (!issetugid()) {
250 const char *path = __CFgetenv("CFFIXED_USER_HOME");
251 if (path) {
252 home = CFURLCreateFromFileSystemRepresentation(kCFAllocatorSystemDefault, (uint8_t *)path, strlen(path), true);
253 }
254 }
255 if (!home) {
256 if (upwd && upwd->pw_dir) {
257 home = CFURLCreateFromFileSystemRepresentation(kCFAllocatorSystemDefault, (uint8_t *)upwd->pw_dir, strlen(upwd->pw_dir), true);
258 }
259 }
260 return home;
261 }
262
263 static void _CFUpdateUserInfo(void) { // __CFPlatformCacheLock must be locked on entry and will be on exit
264 struct passwd *upwd;
265
266 __CFEUID = geteuid();
267 __CFUID = getuid();
268 if (__CFHomeDirectory) CFRelease(__CFHomeDirectory);
269 __CFHomeDirectory = NULL;
270 if (__CFUserName) CFRelease(__CFUserName);
271 __CFUserName = NULL;
272
273 upwd = getpwuid(__CFEUID ? __CFEUID : __CFUID);
274 __CFHomeDirectory = _CFCopyHomeDirURLForUser(upwd);
275 if (!__CFHomeDirectory) {
276 const char *cpath = __CFgetenv("HOME");
277 if (cpath) {
278 __CFHomeDirectory = CFURLCreateFromFileSystemRepresentation(kCFAllocatorSystemDefault, (uint8_t *)cpath, strlen(cpath), true);
279 }
280 }
281
282 // This implies that UserManager stores directory info in CString
283 // rather than FileSystemRep. Perhaps this is wrong & we should
284 // expect NeXTSTEP encodings. A great test of our localized system would
285 // be to have a user "O-umlat z e r". XXX
286 if (upwd && upwd->pw_name) {
287 __CFUserName = CFStringCreateWithCString(kCFAllocatorSystemDefault, upwd->pw_name, kCFPlatformInterfaceStringEncoding);
288 } else {
289 const char *cuser = __CFgetenv("USER");
290 if (cuser)
291 __CFUserName = CFStringCreateWithCString(kCFAllocatorSystemDefault, cuser, kCFPlatformInterfaceStringEncoding);
292 }
293 }
294 #endif
295
296 static CFURLRef _CFCreateHomeDirectoryURLForUser(CFStringRef uName) { // __CFPlatformCacheLock must be locked on entry and will be on exit
297 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_LINUX || DEPLOYMENT_TARGET_FREEBSD
298 if (!uName) {
299 if (geteuid() != __CFEUID || getuid() != __CFUID || !__CFHomeDirectory)
300 _CFUpdateUserInfo();
301 if (__CFHomeDirectory) CFRetain(__CFHomeDirectory);
302 return __CFHomeDirectory;
303 } else {
304 struct passwd *upwd = NULL;
305 char buf[128], *user;
306 SInt32 len = CFStringGetLength(uName), size = CFStringGetMaximumSizeForEncoding(len, kCFPlatformInterfaceStringEncoding);
307 CFIndex usedSize;
308 if (size < 127) {
309 user = buf;
310 } else {
311 user = CFAllocatorAllocate(kCFAllocatorSystemDefault, size+1, 0);
312 if (__CFOASafe) __CFSetLastAllocationEventName(user, "CFUtilities (temp)");
313 }
314 if (CFStringGetBytes(uName, CFRangeMake(0, len), kCFPlatformInterfaceStringEncoding, 0, true, (uint8_t *)user, size, &usedSize) == len) {
315 user[usedSize] = '\0';
316 upwd = getpwnam(user);
317 }
318 if (buf != user) {
319 CFAllocatorDeallocate(kCFAllocatorSystemDefault, user);
320 }
321 return _CFCopyHomeDirURLForUser(upwd);
322 }
323 #elif DEPLOYMENT_TARGET_WINDOWS
324 // This code can only get the directory for the current user
325 if (uName && !CFEqual(uName, _CFUserName())) {
326 CFLog(kCFLogLevelError, CFSTR("CFCopyHomeDirectoryURLForUser(): Unable to get home directory for other user"));
327 return NULL;
328 }
329
330 CFURLRef retVal = NULL;
331 CFIndex len = 0;
332 CFStringRef str = NULL;
333
334 UniChar pathChars[MAX_PATH];
335 if (S_OK == SHGetFolderPathW(NULL, CSIDL_PROFILE, NULL, SHGFP_TYPE_CURRENT, (wchar_t *)pathChars)) {
336 len = (CFIndex)wcslen((wchar_t *)pathChars);
337 str = CFStringCreateWithCharacters(kCFAllocatorSystemDefault, pathChars, len);
338 retVal = CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault, str, kCFURLWindowsPathStyle, true);
339 CFRelease(str);
340 }
341
342 if (!retVal) {
343 // Fall back to environment variable, but this will not be unicode compatible
344 const char *cpath = __CFgetenv("HOMEPATH");
345 const char *cdrive = __CFgetenv("HOMEDRIVE");
346 if (cdrive && cpath) {
347 char fullPath[CFMaxPathSize];
348 strlcpy(fullPath, cdrive, sizeof(fullPath));
349 strlcat(fullPath, cpath, sizeof(fullPath));
350 str = CFStringCreateWithCString(kCFAllocatorSystemDefault, fullPath, kCFPlatformInterfaceStringEncoding);
351 retVal = CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault, str, kCFURLWindowsPathStyle, true);
352 CFRelease(str);
353 }
354 }
355
356 if (!retVal) {
357 // Last resort: We have to get "some" directory location, so fall-back to the processes current directory.
358 UniChar currDir[MAX_PATH];
359 DWORD dwChars = GetCurrentDirectoryW(MAX_PATH + 1, (wchar_t *)currDir);
360 if (dwChars > 0) {
361 len = (CFIndex)wcslen((wchar_t *)currDir);
362 str = CFStringCreateWithCharacters(kCFAllocatorDefault, currDir, len);
363 retVal = CFURLCreateWithFileSystemPath(NULL, str, kCFURLWindowsPathStyle, true);
364 CFRelease(str);
365 }
366 }
367
368 // We could do more here (as in KB Article Q101507). If that article is to be believed, we should only run into this case on Win95, or through user error.
369 CFStringRef testPath = CFURLCopyFileSystemPath(retVal, kCFURLWindowsPathStyle);
370 if (CFStringGetLength(testPath) == 0) {
371 CFRelease(retVal);
372 retVal = NULL;
373 }
374 if (testPath) CFRelease(testPath);
375
376 return retVal;
377 #else
378 #error Dont know how to compute users home directories on this platform
379 #endif
380 }
381
382 static CFStringRef _CFUserName(void) { // __CFPlatformCacheLock must be locked on entry and will be on exit
383 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_LINUX || DEPLOYMENT_TARGET_FREEBSD
384 if (geteuid() != __CFEUID || getuid() != __CFUID)
385 _CFUpdateUserInfo();
386 #elif DEPLOYMENT_TARGET_WINDOWS
387 if (!__CFUserName) {
388 wchar_t username[1040];
389 DWORD size = 1040;
390 username[0] = 0;
391 if (GetUserNameW(username, &size)) {
392 // discount the extra NULL by decrementing the size
393 __CFUserName = CFStringCreateWithCharacters(kCFAllocatorSystemDefault, (const UniChar *)username, size - 1);
394 } else {
395 const char *cname = __CFgetenv("USERNAME");
396 if (cname)
397 __CFUserName = CFStringCreateWithCString(kCFAllocatorSystemDefault, cname, kCFPlatformInterfaceStringEncoding);
398 }
399 }
400 #else
401 #error Dont know how to compute user name on this platform
402 #endif
403 if (!__CFUserName)
404 __CFUserName = (CFStringRef)CFRetain(CFSTR(""));
405 return __CFUserName;
406 }
407
408 #define CFMaxHostNameLength 256
409 #define CFMaxHostNameSize (CFMaxHostNameLength+1)
410
411 __private_extern__ CFStringRef _CFStringCreateHostName(void) {
412 char myName[CFMaxHostNameSize];
413
414 // return @"" instead of nil a la CFUserName() and Ali Ozer
415 if (0 != gethostname(myName, CFMaxHostNameSize)) myName[0] = '\0';
416 return CFStringCreateWithCString(kCFAllocatorSystemDefault, myName, kCFPlatformInterfaceStringEncoding);
417 }
418
419 /* These are sanitized versions of the above functions. We might want to eliminate the above ones someday.
420 These can return NULL.
421 */
422 CF_EXPORT CFStringRef CFGetUserName(void) {
423 CFStringRef result = NULL;
424 __CFSpinLock(&__CFPlatformCacheLock);
425 result = CFStringCreateCopy(kCFAllocatorSystemDefault, _CFUserName());
426 __CFSpinUnlock(&__CFPlatformCacheLock);
427 return result;
428 }
429
430 CF_EXPORT CFStringRef CFCopyUserName(void) {
431 CFStringRef result = NULL;
432 __CFSpinLock(&__CFPlatformCacheLock);
433 result = CFStringCreateCopy(kCFAllocatorSystemDefault, _CFUserName());
434 __CFSpinUnlock(&__CFPlatformCacheLock);
435 return result;
436 }
437
438 CF_EXPORT CFURLRef CFCopyHomeDirectoryURLForUser(CFStringRef uName) {
439 CFURLRef result = NULL;
440 __CFSpinLock(&__CFPlatformCacheLock);
441 result = _CFCreateHomeDirectoryURLForUser(uName);
442 __CFSpinUnlock(&__CFPlatformCacheLock);
443 return result;
444 }
445
446 #undef CFMaxHostNameLength
447 #undef CFMaxHostNameSize
448
449 #if DEPLOYMENT_TARGET_WINDOWS
450 CF_INLINE CFIndex strlen_UniChar(const UniChar* p) {
451 CFIndex result = 0;
452 while ((*p++) != 0)
453 ++result;
454 return result;
455 }
456
457 //#include <shfolder.h>
458 /*
459 * _CFCreateApplicationRepositoryPath returns the path to the application's
460 * repository in a CFMutableStringRef. The path returned will be:
461 * <nFolder_path>\Apple Computer\<bundle_name>\
462 * or if the bundle name cannot be obtained:
463 * <nFolder_path>\Apple Computer\
464 * where nFolder_path is obtained by calling SHGetFolderPath with nFolder
465 * (for example, with CSIDL_APPDATA or CSIDL_LOCAL_APPDATA).
466 *
467 * The CFMutableStringRef result must be released by the caller.
468 *
469 * If anything fails along the way, the result will be NULL.
470 */
471 CF_EXPORT CFMutableStringRef _CFCreateApplicationRepositoryPath(CFAllocatorRef alloc, int nFolder) {
472 CFMutableStringRef result = NULL;
473 UniChar szPath[MAX_PATH];
474
475 // get the current path to the data repository: CSIDL_APPDATA (roaming) or CSIDL_LOCAL_APPDATA (nonroaming)
476 if (S_OK == SHGetFolderPathW(NULL, nFolder, NULL, 0, (wchar_t *) szPath)) {
477 CFStringRef directoryPath;
478
479 // make it a CFString
480 directoryPath = CFStringCreateWithCharacters(alloc, szPath, strlen_UniChar(szPath));
481 if (directoryPath) {
482 CFBundleRef bundle;
483 CFStringRef bundleName;
484 CFStringRef completePath;
485
486 // attempt to get the bundle name
487 bundle = CFBundleGetMainBundle();
488 if (bundle) {
489 bundleName = (CFStringRef)CFBundleGetValueForInfoDictionaryKey(bundle, kCFBundleNameKey);
490 }
491 else {
492 bundleName = NULL;
493 }
494
495 if (bundleName) {
496 // the path will be "<directoryPath>\Apple Computer\<bundleName>\" if there is a bundle name
497 completePath = CFStringCreateWithFormat(alloc, NULL, CFSTR("%@\\Apple Computer\\%@\\"), directoryPath, bundleName);
498 }
499 else {
500 // or "<directoryPath>\Apple Computer\" if there is no bundle name.
501 completePath = CFStringCreateWithFormat(alloc, NULL, CFSTR("%@\\Apple Computer\\"), directoryPath);
502 }
503
504 CFRelease(directoryPath);
505
506 // make a mutable copy to return
507 if (completePath) {
508 result = CFStringCreateMutableCopy(alloc, 0, completePath);
509 CFRelease(completePath);
510 }
511 }
512 }
513
514 return ( result );
515 }
516 #endif
517
518 #pragma mark -
519 #pragma mark Thread Functions
520
521 #if DEPLOYMENT_TARGET_WINDOWS
522
523 // This code from here:
524 // http://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx
525
526 const DWORD MS_VC_EXCEPTION=0x406D1388;
527 #pragma pack(push,8)
528 typedef struct tagTHREADNAME_INFO
529 {
530 DWORD dwType; // Must be 0x1000.
531 LPCSTR szName; // Pointer to name (in user addr space).
532 DWORD dwThreadID; // Thread ID (-1=caller thread).
533 DWORD dwFlags; // Reserved for future use, must be zero.
534 } THREADNAME_INFO;
535 #pragma pack(pop)
536
537 CF_EXPORT void _NS_pthread_setname_np(const char *name) {
538 THREADNAME_INFO info;
539 info.dwType = 0x1000;
540 info.szName = name;
541 info.dwThreadID = GetCurrentThreadId();
542 info.dwFlags = 0;
543
544 __try
545 {
546 RaiseException( MS_VC_EXCEPTION, 0, sizeof(info)/sizeof(ULONG_PTR), (ULONG_PTR*)&info );
547 }
548 __except(EXCEPTION_EXECUTE_HANDLER)
549 {
550 }
551 }
552
553 static pthread_t __initialPthread = { NULL, 0 };
554
555 CF_EXPORT int _NS_pthread_main_np() {
556 pthread_t me = pthread_self();
557 if (NULL == __initialPthread.p) {
558 __initialPthread.p = me.p;
559 __initialPthread.x = me.x;
560 }
561 return (pthread_equal(__initialPthread, me));
562 }
563
564 #endif
565
566 #pragma mark -
567 #pragma mark Thread Local Data
568
569 // If slot >= CF_TSD_MAX_SLOTS, the SPI functions will crash at NULL + slot address.
570 // If thread data has been torn down, these functions should crash on CF_TSD_BAD_PTR + slot address.
571 #define CF_TSD_MAX_SLOTS 70
572
573 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
574 #define CF_TSD_KEY 55
575 #endif
576
577 // Windows and Linux, not sure how many times the destructor could get called; CF_TSD_MAX_DESTRUCTOR_CALLS could be 1
578
579 #define CF_TSD_BAD_PTR ((void *)0x1000)
580
581 typedef void (*tsdDestructor)(void *);
582
583 // Data structure to hold TSD data, cleanup functions for each
584 typedef struct __CFTSDTable {
585 uint32_t destructorCount;
586 uintptr_t data[CF_TSD_MAX_SLOTS];
587 tsdDestructor destructors[CF_TSD_MAX_SLOTS];
588 } __CFTSDTable;
589
590 static void __CFTSDFinalize(void *arg);
591
592 #if DEPLOYMENT_TARGET_WINDOWS
593
594 #include "CFVersionCheck.h"
595
596 static DWORD __CFTSDIndexKey = 0xFFFFFFFF;
597
598 // Called from CFRuntime's startup code, on Windows only
599 __private_extern__ void __CFTSDWindowsInitialize() {
600 __CFTSDIndexKey = TlsAlloc();
601 }
602
603 // Called from CFRuntime's cleanup code, on Windows only
604 __private_extern__ void __CFTSDWindowsCleanup() {
605 TlsFree(__CFTSDIndexKey);
606 }
607
608 // Called for each thread as it exits, on Windows only
609 __private_extern__ void __CFFinalizeWindowsThreadData() {
610 // Normally, this should call the finalizer several times to emulate the behavior of pthreads on Windows. However, a few bugs keep us from doing this:
611 // <rdar://problem/8989063> REGRESSION(CF-610-CF-611): Crash closing Safari in BonjourDB destructor (Windows)
612 // <rdar://problem/9326814> SyncUIHandler crashes after conflict is resolved and we do SyncNow
613 // and a bug in dispatch keeps us from using pthreadsWin32 directly, because it does not deal with the case of a dispatch_async happening during process exit (it attempts to create a thread, but that is illegal on Win32 and causes a hang).
614 // So instead we just finalize once, which is the behavior pre-Airwolf anyway
615 __CFTSDFinalize(TlsGetValue(__CFTSDIndexKey));
616 }
617
618 #endif
619
620 #if DEPLOYMENT_TARGET_LINUX
621
622 static pthread_key_t __CFTSDIndexKey;
623
624 // Called from CFRuntime's startup code, on Linux only
625 __private_extern__ void __CFTSDLinuxInitialize() {
626 (void)pthread_key_create(&__CFTSDIndexKey, __CFTSDFinalize);
627 }
628
629 #endif
630
631 static void __CFTSDSetSpecific(void *arg) {
632 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
633 pthread_setspecific(CF_TSD_KEY, arg);
634 #elif DEPLOYMENT_TARGET_LINUX
635 pthread_setspecific(__CFTSDIndexKey, arg);
636 #elif DEPLOYMENT_TARGET_WINDOWS
637 TlsSetValue(__CFTSDIndexKey, arg);
638 #endif
639 }
640
641 static void *__CFTSDGetSpecific() {
642 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
643 return pthread_getspecific(CF_TSD_KEY);
644 #elif DEPLOYMENT_TARGET_LINUX
645 return pthread_getspecific(__CFTSDIndexKey);
646 #elif DEPLOYMENT_TARGET_WINDOWS
647 return TlsGetValue(__CFTSDIndexKey);
648 #endif
649 }
650
651 static void __CFTSDFinalize(void *arg) {
652 // Set our TSD so we're called again by pthreads. It will call the destructor 5 times as long as a value is set in the thread specific data. We handle each case below.
653 __CFTSDSetSpecific(arg);
654
655 if (!arg || arg == CF_TSD_BAD_PTR) {
656 // We've already been destroyed. The call above set the bad pointer again. Now we just return.
657 return;
658 }
659
660 __CFTSDTable *table = (__CFTSDTable *)arg;
661 table->destructorCount++;
662
663 // On 1st, 2nd, 3rd, 4th calls, invoke destructor
664 // Note that invocation of the destructor may cause a value to be set again in the per-thread data slots. The destructor count and destructors are preserved.
665 // This logic is basically the same as what pthreads does. We just skip the 'created' flag.
666 #if COCOA_ARR0
667 uintptr_t pool = _CFAutoreleasePoolPush();
668 #endif
669 for (int32_t i = 0; i < CF_TSD_MAX_SLOTS; i++) {
670 if (table->data[i] && table->destructors[i]) {
671 uintptr_t old = table->data[i];
672 table->data[i] = (uintptr_t)NULL;
673 table->destructors[i]((void *)(old));
674 }
675 }
676 #if COCOA_ARR0
677 _CFAutoreleasePoolPop(pool);
678 #endif
679
680 if (table->destructorCount == PTHREAD_DESTRUCTOR_ITERATIONS - 1) { // On 4th call, destroy our data
681 free(table);
682
683 // Now if the destructor is called again we will take the shortcut at the beginning of this function.
684 __CFTSDSetSpecific(CF_TSD_BAD_PTR);
685 return;
686 }
687 }
688
689 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
690 extern int pthread_key_init_np(int, void (*)(void *));
691 #endif
692
693 // Get or initialize a thread local storage. It is created on demand.
694 static __CFTSDTable *__CFTSDGetTable() {
695 __CFTSDTable *table = (__CFTSDTable *)__CFTSDGetSpecific();
696 // Make sure we're not setting data again after destruction.
697 if (table == CF_TSD_BAD_PTR) {
698 return NULL;
699 }
700 // Create table on demand
701 if (!table) {
702 // This memory is freed in the finalize function
703 table = (__CFTSDTable *)calloc(1, sizeof(__CFTSDTable));
704 // Windows and Linux have created the table already, we need to initialize it here for other platforms. On Windows, the cleanup function is called by DllMain when a thread exits. On Linux the destructor is set at init time.
705 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
706 pthread_key_init_np(CF_TSD_KEY, __CFTSDFinalize);
707 #endif
708 __CFTSDSetSpecific(table);
709 }
710
711 return table;
712 }
713
714
715 // For the use of CF and Foundation only
716 CF_EXPORT void *_CFGetTSD(uint32_t slot) {
717 if (slot > CF_TSD_MAX_SLOTS) {
718 _CFLogSimple(kCFLogLevelError, "Error: TSD slot %d out of range (get)", slot);
719 HALT;
720 }
721 __CFTSDTable *table = __CFTSDGetTable();
722 if (!table) {
723 // Someone is getting TSD during thread destruction. The table is gone, so we can't get any data anymore.
724 _CFLogSimple(kCFLogLevelWarning, "Warning: TSD slot %d retrieved but the thread data has already been torn down.", slot);
725 return NULL;
726 }
727 uintptr_t *slots = (uintptr_t *)(table->data);
728 return (void *)slots[slot];
729 }
730
731 // For the use of CF and Foundation only
732 CF_EXPORT void *_CFSetTSD(uint32_t slot, void *newVal, tsdDestructor destructor) {
733 if (slot > CF_TSD_MAX_SLOTS) {
734 _CFLogSimple(kCFLogLevelError, "Error: TSD slot %d out of range (set)", slot);
735 HALT;
736 }
737 __CFTSDTable *table = __CFTSDGetTable();
738 if (!table) {
739 // Someone is setting TSD during thread destruction. The table is gone, so we can't get any data anymore.
740 _CFLogSimple(kCFLogLevelWarning, "Warning: TSD slot %d set but the thread data has already been torn down.", slot);
741 return NULL;
742 }
743
744 void *oldVal = (void *)table->data[slot];
745
746 table->data[slot] = (uintptr_t)newVal;
747 table->destructors[slot] = destructor;
748
749 return oldVal;
750 }
751
752 #pragma mark -
753 #pragma mark Windows Wide to UTF8 and UTF8 to Wide
754
755 #if DEPLOYMENT_TARGET_WINDOWS
756 /* On Windows, we want to use UTF-16LE for path names to get full unicode support. Internally, however, everything remains in UTF-8 representation. These helper functions stand between CF and the Microsoft CRT to ensure that we are using the right representation on both sides. */
757
758 #include <sys/stat.h>
759 #include <share.h>
760
761 // Creates a buffer of wchar_t to hold a UTF16LE version of the UTF8 str passed in. Caller must free the buffer when done. If resultLen is non-NULL, it is filled out with the number of characters in the string.
762 static wchar_t *createWideFileSystemRepresentation(const char *str, CFIndex *resultLen) {
763 // Get the real length of the string in UTF16 characters
764 CFStringRef cfStr = CFStringCreateWithCString(kCFAllocatorSystemDefault, str, kCFStringEncodingUTF8);
765 CFIndex strLen = CFStringGetLength(cfStr);
766
767 // Allocate a wide buffer to hold the converted string, including space for a NULL terminator
768 wchar_t *wideBuf = (wchar_t *)malloc((strLen + 1) * sizeof(wchar_t));
769
770 // Copy the string into the buffer and terminate
771 CFStringGetCharacters(cfStr, CFRangeMake(0, strLen), (UniChar *)wideBuf);
772 wideBuf[strLen] = 0;
773
774 CFRelease(cfStr);
775 if (resultLen) *resultLen = strLen;
776 return wideBuf;
777 }
778
779 // Copies a UTF16 buffer into a supplied UTF8 buffer.
780 static void copyToNarrowFileSystemRepresentation(const wchar_t *wide, CFIndex dstBufSize, char *dstbuf) {
781 // Get the real length of the wide string in UTF8 characters
782 CFStringRef cfStr = CFStringCreateWithCharacters(kCFAllocatorSystemDefault, (const UniChar *)wide, wcslen(wide));
783 CFIndex strLen = CFStringGetLength(cfStr);
784 CFIndex bytesUsed;
785
786 // Copy the wide string into the buffer and terminate
787 CFStringGetBytes(cfStr, CFRangeMake(0, strLen), kCFStringEncodingUTF8, 0, false, (uint8_t *)dstbuf, dstBufSize, &bytesUsed);
788 dstbuf[bytesUsed] = 0;
789
790 CFRelease(cfStr);
791 }
792
793 CF_EXPORT int _NS_stat(const char *name, struct _stat *st) {
794 wchar_t *wide = createWideFileSystemRepresentation(name, NULL);
795 int res = _wstat(wide, st);
796 free(wide);
797 return res;
798 }
799
800 CF_EXPORT int _NS_mkdir(const char *name) {
801 wchar_t *wide = createWideFileSystemRepresentation(name, NULL);
802 int res = _wmkdir(wide);
803 free(wide);
804 return res;
805 }
806
807 CF_EXPORT int _NS_rmdir(const char *name) {
808 wchar_t *wide = createWideFileSystemRepresentation(name, NULL);
809 int res = _wrmdir(wide);
810 free(wide);
811 return res;
812 }
813
814 CF_EXPORT int _NS_chmod(const char *name, int mode) {
815 wchar_t *wide = createWideFileSystemRepresentation(name, NULL);
816
817 // Convert mode
818 int newMode = 0;
819 if (mode | 0400) newMode |= _S_IREAD;
820 if (mode | 0200) newMode |= _S_IWRITE;
821 if (mode | 0100) newMode |= _S_IEXEC;
822
823 int res = _wchmod(wide, newMode);
824 free(wide);
825 return res;
826 }
827
828 CF_EXPORT int _NS_unlink(const char *name) {
829 wchar_t *wide = createWideFileSystemRepresentation(name, NULL);
830 int res = _wunlink(wide);
831 free(wide);
832 return res;
833 }
834
835 // Warning: this doesn't support dstbuf as null even though 'getcwd' does
836 CF_EXPORT char *_NS_getcwd(char *dstbuf, size_t size) {
837 if (!dstbuf) {
838 CFLog(kCFLogLevelWarning, CFSTR("CFPlatform: getcwd called with null buffer"));
839 return 0;
840 }
841
842 wchar_t *buf = _wgetcwd(NULL, 0);
843 if (!buf) {
844 return NULL;
845 }
846
847 // Convert result to UTF8
848 copyToNarrowFileSystemRepresentation(buf, (CFIndex)size, dstbuf);
849 free(buf);
850 return dstbuf;
851 }
852
853 CF_EXPORT char *_NS_getenv(const char *name) {
854 // todo: wide getenv
855 // We have to be careful what happens here, because getenv is called during cf initialization, and things like cfstring may not be working yet
856 return getenv(name);
857 }
858
859 CF_EXPORT int _NS_rename(const char *oldName, const char *newName) {
860 wchar_t *oldWide = createWideFileSystemRepresentation(oldName, NULL);
861 wchar_t *newWide = createWideFileSystemRepresentation(newName, NULL);
862 // _wrename on Windows does not behave exactly as rename() on Mac OS -- if the file exists, the Windows one will fail whereas the Mac OS version will replace
863 // To simulate the Mac OS behavior, we use the Win32 API then fill out errno if something goes wrong
864 BOOL winRes = MoveFileExW(oldWide, newWide, MOVEFILE_REPLACE_EXISTING);
865 DWORD error = GetLastError();
866 if (!winRes) {
867 switch (error) {
868 case ERROR_SUCCESS:
869 errno = 0;
870 break;
871 case ERROR_FILE_NOT_FOUND:
872 case ERROR_PATH_NOT_FOUND:
873 case ERROR_OPEN_FAILED:
874 errno = ENOENT;
875 break;
876 case ERROR_ACCESS_DENIED:
877 errno = EACCES;
878 break;
879 default:
880 errno = error;
881 }
882 }
883 free(oldWide);
884 free(newWide);
885 return (winRes ? 0 : -1);
886 }
887
888 CF_EXPORT int _NS_open(const char *name, int oflag, int pmode) {
889 wchar_t *wide = createWideFileSystemRepresentation(name, NULL);
890 int fd;
891 _wsopen_s(&fd, wide, oflag, _SH_DENYNO, _S_IREAD | _S_IWRITE);
892 free(wide);
893 return fd;
894 }
895
896 CF_EXPORT int _NS_chdir(const char *name) {
897 wchar_t *wide = createWideFileSystemRepresentation(name, NULL);
898 int res = _wchdir(wide);
899 free(wide);
900 return res;
901 }
902
903 CF_EXPORT int _NS_access(const char *name, int amode) {
904 // execute is always true
905 if (amode == 1) return 0;
906
907 wchar_t *wide = createWideFileSystemRepresentation(name, NULL);
908 // we only care about the read-only (04) and write-only (02) bits, so mask octal 06
909 int res = _waccess(wide, amode & 06);
910 free(wide);
911 return res;
912 }
913
914 // This is a bit different than the standard 'mkstemp', because the size parameter is needed so we know the size of the UTF8 buffer
915 // Also, we don't avoid the race between creating a temporary file name and opening it on Windows like we do on Mac
916 CF_EXPORT int _NS_mkstemp(char *name, int bufSize) {
917 CFIndex nameLen;
918 wchar_t *wide = createWideFileSystemRepresentation(name, &nameLen);
919
920 // First check to see if the directory that this new temporary file will be created in exists. If not, set errno to ENOTDIR. This mimics the behavior of mkstemp on MacOS more closely.
921 // Look for the last '\' in the path
922 wchar_t *lastSlash = wcsrchr(wide, '\\');
923 if (!lastSlash) {
924 free(wide);
925 return -1;
926 }
927
928 // Set the last slash to NULL temporarily and use it for _wstat
929 *lastSlash = 0;
930 struct _stat dirInfo;
931 int res = _wstat(wide, &dirInfo);
932 if (res < 0) {
933 if (errno == ENOENT) {
934 errno = ENOTDIR;
935 }
936 free(wide);
937 return -1;
938 }
939 // Restore the last slash
940 *lastSlash = '\\';
941
942 errno_t err = _wmktemp_s(wide, nameLen + 1);
943 if (err != 0) {
944 free(wide);
945 return 0;
946 }
947
948 int fd;
949 _wsopen_s(&fd, wide, _O_RDWR | _O_CREAT | CF_OPENFLGS, _SH_DENYNO, _S_IREAD | _S_IWRITE);
950
951 // Convert the wide name back into the UTF8 buffer the caller supplied
952 copyToNarrowFileSystemRepresentation(wide, bufSize, name);
953 free(wide);
954 return fd;
955 }
956
957 #endif
958
959 #if DEPLOYMENT_TARGET_WINDOWS
960 // Utilities to convert from a volume name to a drive letter
961
962 Boolean _isAFloppy(char driveLetter)
963 {
964 HANDLE h;
965 TCHAR tsz[8];
966 Boolean retval = false;
967 int iDrive;
968
969 if (driveLetter >= 'a' && driveLetter <= 'z') {
970 driveLetter = driveLetter - 'a' + 'A';
971 }
972
973 if ((driveLetter < 'A') || (driveLetter > 'Z')) {
974 // invalid driveLetter; I guess it's not a floppy...
975 return false;
976 }
977
978 iDrive = driveLetter - 'A' + 1;
979
980 // On Windows NT, use the technique described in the Knowledge Base article Q115828 and in the "FLOPPY" SDK sample.
981 wsprintf(tsz, TEXT("\\\\.\\%c:"), TEXT('@') + iDrive);
982 h = CreateFile(tsz, 0, FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0);
983 if (h != INVALID_HANDLE_VALUE)
984 {
985 DISK_GEOMETRY Geom[20];
986 DWORD cb;
987
988 if (DeviceIoControl (h, IOCTL_DISK_GET_MEDIA_TYPES, 0, 0,
989 Geom, sizeof(Geom), &cb, 0)
990 && cb > 0)
991 {
992 switch (Geom[0].MediaType)
993 {
994 case F5_1Pt2_512: // 5.25 1.2MB floppy
995 case F5_360_512: // 5.25 360K floppy
996 case F5_320_512: // 5.25 320K floppy
997 case F5_320_1024: // 5.25 320K floppy
998 case F5_180_512: // 5.25 180K floppy
999 case F5_160_512: // 5.25 160K floppy
1000 case F3_1Pt44_512: // 3.5 1.44MB floppy
1001 case F3_2Pt88_512: // 3.5 2.88MB floppy
1002 case F3_20Pt8_512: // 3.5 20.8MB floppy
1003 case F3_720_512: // 3.5 720K floppy
1004 retval = true;
1005 break;
1006 }
1007 }
1008
1009 CloseHandle(h);
1010 }
1011
1012 return retval;
1013 }
1014
1015
1016 extern CFStringRef CFCreateWindowsDrivePathFromVolumeName(CFStringRef volNameStr) {
1017 if (!volNameStr) return NULL;
1018
1019 // This code is designed to match as closely as possible code from QuickTime's library
1020 CFIndex strLen = CFStringGetLength(volNameStr);
1021 if (strLen == 0) {
1022 return NULL;
1023 }
1024
1025 // Get drive names
1026 long length, result;
1027 wchar_t *driveNames = NULL;
1028
1029 // Get the size of the buffer to store the list of drives
1030 length = GetLogicalDriveStringsW(0, 0);
1031 if (!length) {
1032 return NULL;
1033 }
1034
1035 driveNames = (wchar_t *)malloc((length + 1) * sizeof(wchar_t));
1036 result = GetLogicalDriveStringsW(length, driveNames);
1037
1038 if (!result || result > length) {
1039 free(driveNames);
1040 return NULL;
1041 }
1042
1043 // Get the volume name string into a wide buffer
1044 wchar_t *theVolumeName = (wchar_t *)malloc((strLen + 1) * sizeof(wchar_t));
1045 CFStringGetCharacters(volNameStr, CFRangeMake(0, strLen), (UniChar *)theVolumeName);
1046 theVolumeName[strLen] = 0;
1047
1048 // lowercase volume name
1049 _wcslwr(theVolumeName);
1050
1051 // Iterate through the drive names, looking for something that matches
1052 wchar_t *drivePtr = driveNames;
1053 CFStringRef drivePathResult = NULL;
1054
1055 while (*drivePtr) {
1056 _wcslwr(drivePtr);
1057
1058 if (!_isAFloppy((char)*drivePtr)) {
1059 UINT oldErrorMode;
1060 DWORD whoCares1, whoCares2;
1061 BOOL getVolInfoSucceeded;
1062 UniChar thisVolumeName[MAX_PATH];
1063
1064 // Convert this drive string into a volume name
1065 oldErrorMode = SetErrorMode(SEM_FAILCRITICALERRORS);
1066 getVolInfoSucceeded = GetVolumeInformationW(drivePtr, (LPWSTR)thisVolumeName, sizeof(thisVolumeName), NULL, &whoCares1, &whoCares2, NULL, 0);
1067 SetErrorMode(oldErrorMode);
1068
1069 if (getVolInfoSucceeded) {
1070 _wcslwr((wchar_t *)thisVolumeName);
1071
1072 // If the volume corresponding to this drive matches the input volume
1073 // then this drive is the winner.
1074 if (!wcscmp((const wchar_t *)thisVolumeName, theVolumeName) ||
1075 (*thisVolumeName == 0x00 && (CFStringCompare(volNameStr, CFSTR("NONAME"), 0) == kCFCompareEqualTo))) {
1076 drivePathResult = CFStringCreateWithCharacters(kCFAllocatorSystemDefault, (const UniChar *)drivePtr, wcslen(drivePtr));
1077 break;
1078 }
1079 }
1080 }
1081
1082 drivePtr += wcslen(drivePtr) + 1;
1083 }
1084
1085
1086 free(driveNames);
1087 free(theVolumeName);
1088 return drivePathResult;
1089 }
1090
1091 #endif // DEPLOYMENT_TARGET_WINDOWS
1092
1093 #pragma mark -
1094 #pragma mark Linux OSAtomic
1095
1096 #if DEPLOYMENT_TARGET_LINUX
1097
1098 bool OSAtomicCompareAndSwapPtr(void *oldp, void *newp, void *volatile *dst)
1099 {
1100 return __sync_bool_compare_and_swap(dst, oldp, newp);
1101 }
1102
1103 bool OSAtomicCompareAndSwapLong(long oldl, long newl, long volatile *dst)
1104 {
1105 return __sync_val_compare_and_swap(dst, oldl, newl);
1106 }
1107
1108 bool OSAtomicCompareAndSwapPtrBarrier(void *oldp, void *newp, void *volatile *dst)
1109 {
1110 return __sync_bool_compare_and_swap(dst, oldp, newp);
1111 }
1112
1113 int32_t OSAtomicAdd32Barrier( int32_t theAmount, volatile int32_t *theValue ) {
1114 return __sync_fetch_and_add(theValue, theAmount) + theAmount;
1115 }
1116
1117 bool OSAtomicCompareAndSwap32Barrier(int32_t oldValue, int32_t newValue, volatile int32_t *theValue) {
1118 return __sync_bool_compare_and_swap(theValue, oldValue, newValue);
1119 }
1120
1121 int32_t OSAtomicDecrement32Barrier(volatile int32_t *dst)
1122 {
1123 return OSAtomicAdd32Barrier(-1, dst);
1124 }
1125
1126 int32_t OSAtomicIncrement32Barrier(volatile int32_t *dst)
1127 {
1128 return OSAtomicAdd32Barrier(1, dst);
1129 }
1130
1131 int32_t OSAtomicAdd32( int32_t theAmount, volatile int32_t *theValue ) {
1132 return OSAtomicAdd32Barrier(theAmount, theValue);
1133 }
1134
1135 int32_t OSAtomicIncrement32(volatile int32_t *theValue) {
1136 return OSAtomicIncrement32Barrier(theValue);
1137 }
1138
1139 int32_t OSAtomicDecrement32(volatile int32_t *theValue) {
1140 return OSAtomicDecrement32Barrier(theValue);
1141 }
1142
1143 void OSMemoryBarrier() {
1144 __sync_synchronize();
1145 }
1146
1147 #endif // DEPLOYMENT_TARGET_LINUX
1148
1149 #pragma mark -
1150 #pragma mark Windows and Linux Helpers
1151
1152 #if DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX
1153
1154 #include <stdio.h>
1155
1156 __private_extern__ int asprintf(char **ret, const char *format, ...) {
1157 va_list args;
1158 size_t sz = 1024;
1159 *ret = (char *) malloc(sz * sizeof(char));
1160 if (!*ret) return -1;
1161 va_start(args, format);
1162 int cnt = vsnprintf(*ret, sz, format, args);
1163 va_end(args);
1164 if (cnt < sz - 1) return cnt;
1165 sz = cnt + 8;
1166 char *oldret = *ret;
1167 *ret = (char *) realloc(*ret, sz * sizeof(char));
1168 if (!*ret && oldret) free(oldret);
1169 if (!*ret) return -1;
1170 va_start(args, format);
1171 cnt = vsnprintf(*ret, sz, format, args);
1172 va_end(args);
1173 if (cnt < sz - 1) return cnt;
1174 free(*ret);
1175 *ret = NULL;
1176 return -1;
1177 }
1178
1179 #endif