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