/ CFUtilities.c
CFUtilities.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  /*	CFUtilities.c
  25  	Copyright (c) 1998-2014, Apple Inc. All rights reserved.
  26  	Responsibility: Tony Parker
  27  */
  28  
  29  #include <CoreFoundation/CFPriv.h>
  30  #include "CFInternal.h"
  31  #include "CFLocaleInternal.h"
  32  #include <CoreFoundation/CFPriv.h>
  33  #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS
  34  #include <CoreFoundation/CFBundle.h>
  35  #endif
  36  #include <CoreFoundation/CFURLAccess.h>
  37  #include <CoreFoundation/CFPropertyList.h>
  38  #if DEPLOYMENT_TARGET_WINDOWS
  39  #include <process.h>
  40  #endif
  41  #include <math.h>
  42  #include <string.h>
  43  #include <stdio.h>
  44  #include <stdlib.h>
  45  #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS
  46  #include <asl.h>
  47  #else
  48  #define ASL_LEVEL_EMERG 0
  49  #define ASL_LEVEL_DEBUG 7
  50  #endif
  51  
  52  
  53  #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
  54  #include <unistd.h>
  55  #include <sys/uio.h>
  56  #include <mach/mach.h>
  57  #include <pthread.h>
  58  #include <mach-o/loader.h>
  59  #include <mach-o/dyld.h>
  60  #include <crt_externs.h>
  61  #include <dlfcn.h>
  62  #include <vproc.h>
  63  #include <vproc_priv.h>
  64  #include <sys/sysctl.h>
  65  #include <sys/stat.h>
  66  #include <mach/mach.h>
  67  #include <mach/mach_vm.h>
  68  #include <sys/mman.h>
  69  #include <stdio.h>
  70  #include <sys/errno.h>
  71  #include <mach/mach_time.h>
  72  #include <Block.h>
  73  #endif
  74  #if DEPLOYMENT_TARGET_LINUX || DEPLOYMENT_TARGET_FREEBSD
  75  #include <string.h>
  76  #include <pthread.h>
  77  #include <sys/mman.h>
  78  #endif
  79  
  80  /* Comparator is passed the address of the values. */
  81  /* Binary searches a sorted-increasing array of some type.
  82     Return value is either 1) the index of the element desired,
  83     if the target value exists in the list, 2) greater than or
  84     equal to count, if the element is greater than all the values
  85     in the list, or 3) the index of the element greater than the
  86     target value.
  87  
  88     For example, a search in the list of integers:
  89  	2 3 5 7 11 13 17
  90  
  91     For...		Will Return...
  92  	2		    0
  93     	5		    2
  94  	23		    7
  95  	1		    0
  96  	9		    4
  97  
  98     For instance, if you just care about found/not found:
  99     index = CFBSearch(list, count, elem);
 100     if (count <= index || list[index] != elem) {
 101     	* Not found *
 102     } else {
 103     	* Found *
 104     }
 105     
 106  */
 107  CF_PRIVATE CFIndex CFBSearch(const void *element, CFIndex elementSize, const void *list, CFIndex count, CFComparatorFunction comparator, void *context) {
 108      const char *ptr = (const char *)list;
 109      while (0 < count) {
 110          CFIndex half = count / 2;
 111          const char *probe = ptr + elementSize * half;
 112          CFComparisonResult cr = comparator(element, probe, context);
 113  	if (0 == cr) return (probe - (const char *)list) / elementSize;
 114          ptr = (cr < 0) ? ptr : probe + elementSize;
 115          count = (cr < 0) ? half : (half + (count & 1) - 1);
 116      }
 117      return (ptr - (const char *)list) / elementSize;
 118  }
 119  
 120  
 121  #define ELF_STEP(B) T1 = (H << 4) + B; T2 = T1 & 0xF0000000; if (T2) T1 ^= (T2 >> 24); T1 &= (~T2); H = T1;
 122  
 123  CFHashCode CFHashBytes(uint8_t *bytes, CFIndex length) {
 124      /* The ELF hash algorithm, used in the ELF object file format */
 125      UInt32 H = 0, T1, T2;
 126      SInt32 rem = length;
 127      while (3 < rem) {
 128  	ELF_STEP(bytes[length - rem]);
 129  	ELF_STEP(bytes[length - rem + 1]);
 130  	ELF_STEP(bytes[length - rem + 2]);
 131  	ELF_STEP(bytes[length - rem + 3]);
 132  	rem -= 4;
 133      }
 134      switch (rem) {
 135      case 3:  ELF_STEP(bytes[length - 3]);
 136      case 2:  ELF_STEP(bytes[length - 2]);
 137      case 1:  ELF_STEP(bytes[length - 1]);
 138      case 0:  ;
 139      }
 140      return H;
 141  }
 142  
 143  #undef ELF_STEP
 144  
 145  
 146  #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
 147  CF_PRIVATE uintptr_t __CFFindPointer(uintptr_t ptr, uintptr_t start) {
 148      vm_map_t task = mach_task_self();
 149      mach_vm_address_t address = start;
 150      for (;;) {
 151  	mach_vm_size_t size = 0;
 152  	vm_region_basic_info_data_64_t info;
 153          mach_msg_type_number_t count = VM_REGION_BASIC_INFO_COUNT_64;
 154  	mach_port_t object_name;
 155          kern_return_t ret = mach_vm_region(task, &address, &size, VM_REGION_BASIC_INFO_64, (vm_region_info_t)&info, &count, &object_name);
 156          if (KERN_SUCCESS != ret) break;
 157  	boolean_t scan = (info.protection & VM_PROT_WRITE) ? 1 : 0;
 158  	if (scan) {
 159  	    uintptr_t *addr = (uintptr_t *)((uintptr_t)address);
 160  	    uintptr_t *end = (uintptr_t *)((uintptr_t)address + (uintptr_t)size);
 161  	    while (addr < end) {
 162  	        if ((uintptr_t *)start <= addr && *addr == ptr) {
 163  		    return (uintptr_t)addr;
 164  	        }
 165  	        addr++;
 166  	    }
 167  	}
 168          address += size;
 169      }
 170      return 0;
 171  }
 172  
 173  CF_PRIVATE void __CFDumpAllPointerLocations(uintptr_t ptr) {
 174      uintptr_t addr = 0;
 175      do {
 176          addr = __CFFindPointer(ptr, sizeof(void *) + addr);
 177          printf("%p\n", (void *)addr);
 178      } while (addr != 0);
 179  }
 180  #endif
 181  
 182  // Looks for localized version of "nonLocalized" in the SystemVersion bundle
 183  // If not found, and returnNonLocalizedFlag == true, will return the non localized string (retained of course), otherwise NULL
 184  // If bundlePtr != NULL, will use *bundlePtr and will return the bundle in there; otherwise bundle is created and released
 185  #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
 186  static CFStringRef _CFCopyLocalizedVersionKey(CFBundleRef *bundlePtr, CFStringRef nonLocalized) {
 187      CFStringRef localized = NULL;
 188      CFBundleRef locBundle = bundlePtr ? *bundlePtr : NULL;
 189      if (!locBundle) {
 190          CFURLRef url = CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault, CFSTR("/System/Library/CoreServices/SystemVersion.bundle"), kCFURLPOSIXPathStyle, false);
 191          if (url) {
 192              locBundle = CFBundleCreate(kCFAllocatorSystemDefault, url);
 193              CFRelease(url);
 194          }
 195      }
 196      if (locBundle) {
 197  	localized = CFBundleCopyLocalizedString(locBundle, nonLocalized, nonLocalized, CFSTR("SystemVersion"));
 198  	if (bundlePtr) *bundlePtr = locBundle; else CFRelease(locBundle);
 199      }
 200      return localized ? localized : (CFStringRef)CFRetain(nonLocalized);
 201  }
 202  #endif
 203  
 204  static CFDictionaryRef _CFCopyVersionDictionary(CFStringRef path) {
 205      CFPropertyListRef plist = NULL;
 206      
 207  #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
 208      CFDataRef data;
 209      CFURLRef url;
 210      
 211      url = CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault, path, kCFURLPOSIXPathStyle, false);
 212  #pragma GCC diagnostic push
 213  #pragma GCC diagnostic ignored "-Wdeprecated"
 214      if (url && CFURLCreateDataAndPropertiesFromResource(kCFAllocatorSystemDefault, url, &data, NULL, NULL, NULL)) {
 215  #pragma GCC diagnostic pop
 216          plist = CFPropertyListCreateWithData(kCFAllocatorSystemDefault, data, kCFPropertyListMutableContainers, NULL, NULL);
 217  	CFRelease(data);
 218      }
 219      if (url) CFRelease(url);
 220  
 221      if (plist) {
 222  #if DEPLOYMENT_TARGET_EMBEDDED_MINI
 223  	CFStringRef fullVersion, vers, versExtra, build;
 224  	CFStringRef versionString = CFRetain(_kCFSystemVersionProductVersionStringKey);
 225  	CFStringRef buildString = CFRetain(_kCFSystemVersionBuildStringKey);
 226  	CFStringRef fullVersionString = CFRetain(CFSTR("FullVersionString"));
 227  #else
 228  	CFBundleRef locBundle = NULL;
 229  	CFStringRef fullVersion, vers, versExtra, build;
 230  	CFStringRef versionString = _CFCopyLocalizedVersionKey(&locBundle, _kCFSystemVersionProductVersionStringKey);
 231  	CFStringRef buildString = _CFCopyLocalizedVersionKey(&locBundle, _kCFSystemVersionBuildStringKey);
 232  	CFStringRef fullVersionString = _CFCopyLocalizedVersionKey(&locBundle, CFSTR("FullVersionString"));
 233  	if (locBundle) CFRelease(locBundle);
 234  #endif
 235  
 236          // Now build the full version string
 237          if (CFEqual(fullVersionString, CFSTR("FullVersionString"))) {
 238              CFRelease(fullVersionString);
 239              fullVersionString = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("%@ %%@ (%@ %%@)"), versionString, buildString);
 240          }
 241          vers = (CFStringRef)CFDictionaryGetValue((CFDictionaryRef)plist, _kCFSystemVersionProductVersionKey);
 242          versExtra = (CFStringRef)CFDictionaryGetValue((CFDictionaryRef)plist, _kCFSystemVersionProductVersionExtraKey);
 243          if (vers && versExtra) vers = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("%@ %@"), vers, versExtra);
 244          build = (CFStringRef)CFDictionaryGetValue((CFDictionaryRef)plist, _kCFSystemVersionBuildVersionKey);
 245          fullVersion = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, fullVersionString, (vers ? vers : CFSTR("?")), build ? build : CFSTR("?"));
 246          if (vers && versExtra) CFRelease(vers);
 247          
 248  	CFDictionarySetValue((CFMutableDictionaryRef)plist, _kCFSystemVersionProductVersionStringKey, versionString);
 249  	CFDictionarySetValue((CFMutableDictionaryRef)plist, _kCFSystemVersionBuildStringKey, buildString);
 250  	CFDictionarySetValue((CFMutableDictionaryRef)plist, CFSTR("FullVersionString"), fullVersion);
 251   	CFRelease(versionString);
 252  	CFRelease(buildString);
 253  	CFRelease(fullVersionString);
 254          CFRelease(fullVersion);
 255      }
 256  #elif DEPLOYMENT_TARGET_WINDOWS
 257      OSVERSIONINFOEX osvi;
 258      ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX));
 259      osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
 260      BOOL result = GetVersionEx((OSVERSIONINFO *)&osvi);
 261      if (!result) return NULL;
 262  
 263      plist = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 10, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
 264      
 265      // e.g. 10.7
 266      CFStringRef versionString = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("%ld.%ld(%ld,%ld)"), osvi.dwMajorVersion, osvi.dwMinorVersion, osvi.wServicePackMajor, osvi.wServicePackMinor);
 267      
 268      // e.g. 11A508
 269      CFStringRef buildString = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("%ld"), osvi.dwBuildNumber);
 270          
 271      CFDictionarySetValue((CFMutableDictionaryRef)plist, _kCFSystemVersionProductVersionKey, versionString);
 272      CFDictionarySetValue((CFMutableDictionaryRef)plist, _kCFSystemVersionBuildVersionKey, buildString);    
 273      CFDictionarySetValue((CFMutableDictionaryRef)plist, _kCFSystemVersionProductNameKey, CFSTR("Windows")); // hard coded for now
 274      
 275      CFRelease(versionString);
 276      CFRelease(buildString);
 277  #endif
 278      return (CFDictionaryRef)plist;
 279  }
 280  
 281  CFStringRef CFCopySystemVersionString(void) {
 282      CFStringRef versionString;
 283      CFDictionaryRef dict = _CFCopyServerVersionDictionary();
 284      if (!dict) dict = _CFCopySystemVersionDictionary();
 285      if (!dict) return NULL;
 286      versionString = (CFStringRef)CFDictionaryGetValue(dict, CFSTR("FullVersionString"));
 287      if (versionString) CFRetain(versionString);
 288      CFRelease(dict);
 289      return versionString;
 290  }
 291  
 292  // Obsolete: These two functions cache the dictionaries to avoid calling _CFCopyVersionDictionary() more than once per dict desired
 293  // In fact, they do not cache any more, because the file can change after
 294  // apps are running in some situations, and apps need the new info.
 295  // Proper caching and testing to see if the file has changed, without race
 296  // conditions, would require semi-convoluted use of fstat().
 297  
 298  static CFStringRef copySystemVersionPath(CFStringRef suffix) {
 299  #if TARGET_IPHONE_SIMULATOR
 300      const char *simulatorRoot = getenv("IPHONE_SIMULATOR_ROOT");
 301      if (!simulatorRoot) simulatorRoot = getenv("CFFIXED_USER_HOME");
 302      if (!simulatorRoot) simulatorRoot = "/";
 303      return CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("%s%@"), simulatorRoot, suffix);
 304  #else
 305      return suffix;
 306  #endif
 307  }
 308  
 309  
 310  CFDictionaryRef _CFCopySystemVersionDictionary(void) {
 311      CFStringRef path = copySystemVersionPath(CFSTR("/System/Library/CoreServices/SystemVersion.plist"));
 312      CFPropertyListRef plist = _CFCopyVersionDictionary(path);
 313      CFRelease(path);
 314      return (CFDictionaryRef)plist;
 315  }
 316  
 317  CFDictionaryRef _CFCopyServerVersionDictionary(void) {
 318      CFStringRef path = copySystemVersionPath(CFSTR("/System/Library/CoreServices/ServerVersion.plist"));
 319      CFPropertyListRef plist = _CFCopyVersionDictionary(path);
 320      CFRelease(path);
 321      return (CFDictionaryRef)plist;
 322  }
 323  
 324  CONST_STRING_DECL(_kCFSystemVersionProductNameKey, "ProductName")
 325  CONST_STRING_DECL(_kCFSystemVersionProductCopyrightKey, "ProductCopyright")
 326  CONST_STRING_DECL(_kCFSystemVersionProductVersionKey, "ProductVersion")
 327  CONST_STRING_DECL(_kCFSystemVersionProductVersionExtraKey, "ProductVersionExtra")
 328  CONST_STRING_DECL(_kCFSystemVersionProductUserVisibleVersionKey, "ProductUserVisibleVersion")
 329  CONST_STRING_DECL(_kCFSystemVersionBuildVersionKey, "ProductBuildVersion")
 330  CONST_STRING_DECL(_kCFSystemVersionProductVersionStringKey, "Version")
 331  CONST_STRING_DECL(_kCFSystemVersionBuildStringKey, "Build")
 332  
 333  
 334  CF_EXPORT Boolean _CFExecutableLinkedOnOrAfter(CFSystemVersion version) {
 335      return true;
 336  }
 337  
 338  
 339  
 340  
 341  #if DEPLOYMENT_TARGET_MACOSX
 342  CF_PRIVATE void *__CFLookupCarbonCoreFunction(const char *name) {
 343      static void *image = NULL;
 344      if (NULL == image) {
 345  	image = dlopen("/System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/CarbonCore.framework/Versions/A/CarbonCore", RTLD_LAZY | RTLD_LOCAL);
 346      }
 347      void *dyfunc = NULL;
 348      if (image) {
 349  	dyfunc = dlsym(image, name);
 350      }
 351      return dyfunc;
 352  }
 353  #endif
 354  
 355  #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
 356  CF_PRIVATE void *__CFLookupCoreServicesInternalFunction(const char *name) {
 357      static void *image = NULL;
 358      if (NULL == image) {
 359          image = dlopen("/System/Library/PrivateFrameworks/CoreServicesInternal.framework/CoreServicesInternal", RTLD_LAZY | RTLD_LOCAL);
 360      }
 361      void *dyfunc = NULL;
 362      if (image) {
 363          dyfunc = dlsym(image, name);
 364      }
 365      return dyfunc;
 366  }
 367  
 368  CF_PRIVATE void *__CFLookupCFNetworkFunction(const char *name) {
 369      static void *image = NULL;
 370      if (NULL == image) {
 371  	const char *path = NULL;
 372          if (!__CFProcessIsRestricted()) {
 373  	    path = __CFgetenv("CFNETWORK_LIBRARY_PATH");
 374  	}
 375  	if (!path) {
 376  	    path = "/System/Library/Frameworks/CFNetwork.framework/CFNetwork";
 377  	}
 378  	image = dlopen(path, RTLD_LAZY | RTLD_LOCAL);
 379      }
 380      void *dyfunc = NULL;
 381      if (image) {
 382  	dyfunc = dlsym(image, name);
 383      }
 384      return dyfunc;
 385  }
 386  #endif
 387  
 388  CF_PRIVATE CFIndex __CFActiveProcessorCount() {
 389      int32_t pcnt;
 390  #if DEPLOYMENT_TARGET_WINDOWS
 391      SYSTEM_INFO sysInfo;
 392      GetSystemInfo(&sysInfo);
 393      DWORD_PTR activeProcessorMask = sysInfo.dwActiveProcessorMask;
 394      // assumes sizeof(DWORD_PTR) is 64 bits or less
 395      uint64_t v = activeProcessorMask;
 396      v = v - ((v >> 1) & 0x5555555555555555ULL);
 397      v = (v & 0x3333333333333333ULL) + ((v >> 2) & 0x3333333333333333ULL);
 398      v = (v + (v >> 4)) & 0xf0f0f0f0f0f0f0fULL;
 399      pcnt = (v * 0x0101010101010101ULL) >> ((sizeof(v) - 1) * 8);
 400  #elif DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
 401      int32_t mib[] = {CTL_HW, HW_AVAILCPU};
 402      size_t len = sizeof(pcnt);
 403      int32_t result = sysctl(mib, sizeof(mib) / sizeof(int32_t), &pcnt, &len, NULL, 0);
 404      if (result != 0) {
 405          pcnt = 0;
 406      }
 407  #else
 408      // Assume the worst
 409      pcnt = 1;
 410  #endif
 411      return pcnt;
 412  }
 413  
 414  CF_PRIVATE void __CFGetUGIDs(uid_t *euid, gid_t *egid) {
 415  #if 1 && (DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI)
 416      uid_t uid;
 417      gid_t gid;
 418      if (0 == pthread_getugid_np(&uid, &gid)) {
 419          if (euid) *euid = uid;
 420          if (egid) *egid = gid;
 421      } else
 422  #endif
 423      {
 424          if (euid) *euid = geteuid();
 425          if (egid) *egid = getegid();
 426      }
 427  }
 428  
 429  const char *_CFPrintForDebugger(const void *obj) {
 430  	static char *result = NULL;
 431  	CFStringRef str;
 432  	CFIndex cnt = 0;
 433  
 434  	free(result);	// Let go of result from previous call.
 435  	result = NULL;
 436  	if (obj) {
 437  		if (CFGetTypeID(obj) == CFStringGetTypeID()) {
 438  			// Makes Ali marginally happier
 439  			str = __CFCopyFormattingDescription(obj, NULL);
 440  			if (!str) str = CFCopyDescription(obj);
 441  		} else {
 442  			str = CFCopyDescription(obj);
 443  		}
 444  	} else {
 445  		str = (CFStringRef)CFRetain(CFSTR("(null)"));
 446  	}
 447  	
 448  	if (str != NULL) {
 449  		CFStringGetBytes(str, CFRangeMake(0, CFStringGetLength(str)), kCFStringEncodingUTF8, 0, FALSE, NULL, 0, &cnt);
 450  	}
 451  	result = (char *) malloc(cnt + 2);	// 1 for '\0', 1 for an optional '\n'
 452  	if (str != NULL) {
 453  		CFStringGetBytes(str, CFRangeMake(0, CFStringGetLength(str)), kCFStringEncodingUTF8, 0, FALSE, (UInt8 *) result, cnt, &cnt);
 454  	}
 455  	result[cnt] = '\0';
 456  
 457  	if (str) CFRelease(str);
 458  	return result;
 459  }
 460  
 461  static void _CFShowToFile(FILE *file, Boolean flush, const void *obj) {
 462       CFStringRef str;
 463       CFIndex idx, cnt;
 464       CFStringInlineBuffer buffer;
 465       bool lastNL = false;
 466  
 467       if (obj) {
 468  	if (CFGetTypeID(obj) == CFStringGetTypeID()) {
 469  	    // Makes Ali marginally happier
 470  	    str = __CFCopyFormattingDescription(obj, NULL);
 471  	    if (!str) str = CFCopyDescription(obj);
 472  	} else {
 473  	    str = CFCopyDescription(obj);
 474  	}
 475       } else {
 476  	str = (CFStringRef)CFRetain(CFSTR("(null)"));
 477       }
 478       cnt = CFStringGetLength(str);
 479  
 480  #if DEPLOYMENT_TARGET_WINDOWS
 481      UniChar *ptr = (UniChar *)CFStringGetCharactersPtr(str);
 482      BOOL freePtr = false;
 483      if (!ptr) {
 484  	CFIndex strLen = CFStringGetLength(str);
 485  	// +2, 1 for newline, 1 for null
 486  	CFIndex bufSize = sizeof(UniChar *) * (CFStringGetMaximumSizeForEncoding(strLen, kCFStringEncodingUnicode) + 2);
 487  	CFIndex bytesUsed = 0;
 488  	ptr = (UniChar *)malloc(bufSize);
 489  	CFStringGetCharacters(str, CFRangeMake(0, strLen), ptr);
 490  	ptr[strLen] = L'\n';
 491  	ptr[strLen+1] = 0;
 492  	freePtr = true;
 493      }
 494      OutputDebugStringW((wchar_t *)ptr);
 495      if (freePtr) free(ptr);
 496  #else
 497       CFStringInitInlineBuffer(str, &buffer, CFRangeMake(0, cnt));
 498       for (idx = 0; idx < cnt; idx++) {
 499           UniChar ch = __CFStringGetCharacterFromInlineBufferQuick(&buffer, idx);
 500           if (ch < 128) {
 501               fprintf_l(file, NULL, "%c", ch);
 502               lastNL = (ch == '\n');
 503           } else {
 504               fprintf_l(file, NULL, "\\u%04x", ch);
 505           }
 506       }
 507       if (!lastNL) {
 508  #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
 509           fprintf_l(file, NULL, "\n");
 510  #else
 511           fprintf(file, NULL, "\n");
 512  #endif
 513           if (flush) fflush(file);
 514       }
 515  #endif
 516  
 517       if (str) CFRelease(str);
 518  }
 519  
 520  void CFShow(const void *obj) {
 521       _CFShowToFile(stderr, true, obj);
 522  }
 523  
 524  
 525  // message must be a UTF8-encoded, null-terminated, byte buffer with at least length bytes
 526  typedef void (*CFLogFunc)(int32_t lev, const char *message, size_t length, char withBanner);
 527  
 528  static Boolean also_do_stderr() {
 529  #if DEPLOYMENT_TARGET_EMBEDDED_MINI
 530      // just log to stderr, other logging facilities are out
 531      return true;
 532  #elif DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
 533      if (!issetugid() && __CFgetenv("CFLOG_FORCE_STDERR")) {
 534  	return true;
 535      }
 536      struct stat sb;
 537      int ret = fstat(STDERR_FILENO, &sb);
 538      if (ret < 0) return false;
 539      mode_t m = sb.st_mode & S_IFMT;
 540      if (S_IFREG == m || S_IFSOCK == m) return true;
 541      if (!(S_IFIFO == m || S_IFCHR == m)) return false; // disallow any whacky stuff
 542  #if 0 // launchd no longer repeats everything it hears
 543      // if it could be a pipe back to launchd, fail
 544      int64_t val = 0;
 545      // assumes val is not written to on error
 546      vproc_swap_integer(NULL, VPROC_GSK_IS_MANAGED, NULL, &val);
 547      if (val) return false;
 548  #endif
 549  #endif
 550      return true;
 551  }
 552  
 553  extern char *__CFBundleMainID;
 554  
 555  static void __CFLogCString(int32_t lev, const char *message, size_t length, char withBanner) {
 556      char *banner = NULL;
 557      char *time = NULL;
 558      char *thread = NULL;
 559      char *uid = NULL;
 560      int bannerLen;
 561      bannerLen = 0;
 562  #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX
 563      // The banner path may use CF functions, but the rest of this function should not. It may be called at times when CF is not fully setup or torn down.
 564      if (withBanner) {
 565  	double dummy;
 566  	CFAbsoluteTime at = CFAbsoluteTimeGetCurrent();
 567          time_t tv = floor(at + kCFAbsoluteTimeIntervalSince1970);
 568          struct tm mine;
 569          localtime_r(&tv, &mine);
 570          int32_t year = mine.tm_year + 1900;
 571          int32_t month = mine.tm_mon + 1;
 572          int32_t day = mine.tm_mday;
 573          int32_t hour = mine.tm_hour;
 574          int32_t minute = mine.tm_min;
 575          int32_t second = mine.tm_sec;
 576  	int32_t ms = (int32_t)floor(1000.0 * modf(at, &dummy));
 577  #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
 578          uint64_t tid = 0;
 579          if (0 != pthread_threadid_np(NULL, &tid)) tid = pthread_mach_thread_np(pthread_self());
 580          asprintf(&banner, "%04d-%02d-%02d %02d:%02d:%02d.%03d %s[%d:%llu] ", year, month, day, hour, minute, second, ms, *_CFGetProgname(), getpid(), tid);
 581  	asprintf(&thread, "%x", pthread_mach_thread_np(pthread_self()));
 582  #elif DEPLOYMENT_TARGET_WINDOWS
 583  	bannerLen = asprintf(&banner, "%04d-%02d-%02d %02d:%02d:%02d.%03d %s[%d:%x] ", year, month, day, hour, minute, second, ms, *_CFGetProgname(), getpid(), GetCurrentThreadId());
 584  	asprintf(&thread, "%x", GetCurrentThreadId());
 585  #else
 586  	bannerLen = asprintf(&banner, "%04d-%02d-%02d %02d:%02d:%02d.%03d %s[%d:%x] ", year, month, day, hour, minute, second, ms, *_CFGetProgname(), getpid(), (unsigned int)pthread_self());
 587  	asprintf(&thread, "%lx", pthread_self());
 588  #endif
 589  	asprintf(&time, "%04d-%02d-%02d %02d:%02d:%02d.%03d", year, month, day, hour, minute, second, ms);
 590  
 591      }
 592  #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS
 593      uid_t euid;
 594      __CFGetUGIDs(&euid, NULL);
 595      asprintf(&uid, "%d", euid);
 596      aslclient asl = asl_open(NULL, __CFBundleMainID[0] ? __CFBundleMainID : "com.apple.console", ASL_OPT_NO_DELAY);
 597      aslmsg msg = asl_new(ASL_TYPE_MSG);
 598      asl_set(msg, "CFLog Local Time", time); // not to be documented, not public API
 599      asl_set(msg, "CFLog Thread", thread);   // not to be documented, not public API
 600      asl_set(msg, "ReadUID", uid);
 601      static const char *levstr[] = {"0", "1", "2", "3", "4", "5", "6", "7"};
 602      asl_set(msg, ASL_KEY_LEVEL, levstr[lev]);
 603      asl_set(msg, ASL_KEY_MSG, message);
 604      asl_send(asl, msg);
 605      asl_free(msg);
 606      asl_close(asl);
 607  #endif
 608  #endif // DEPLOYMENT_TARGET
 609  
 610      if (also_do_stderr()) {
 611  #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
 612  	struct iovec v[3];
 613  	v[0].iov_base = banner;
 614  	v[0].iov_len = banner ? strlen(banner) : 0;
 615  	v[1].iov_base = (char *)message;
 616  	v[1].iov_len = length;
 617  	v[2].iov_base = "\n";
 618  	v[2].iov_len = (message[length - 1] != '\n') ? 1 : 0;
 619  	int nv = (v[0].iov_base ? 1 : 0) + 1 + (v[2].iov_len ? 1 : 0);
 620  	static CFLock_t lock = CFLockInit;
 621  	__CFLock(&lock);
 622  	writev(STDERR_FILENO, v[0].iov_base ? v : v + 1, nv);
 623  	__CFUnlock(&lock);
 624  #elif DEPLOYMENT_TARGET_WINDOWS
 625          size_t bufLen = bannerLen + length + 1;
 626          char *buf = (char *)malloc(sizeof(char) * bufLen);
 627          if (banner) {
 628              // Copy the banner into the debug string
 629              memmove_s(buf, bufLen, banner, bannerLen);
 630              
 631              // Copy the message into the debug string
 632              strcpy_s(buf + bannerLen, bufLen - bannerLen, message);
 633          } else {
 634              strcpy_s(buf, bufLen, message);
 635          }
 636          buf[bufLen - 1] = '\0';
 637  	fprintf_s(stderr, "%s\n", buf);
 638  	// This Win32 API call only prints when a debugger is active
 639  	// OutputDebugStringA(buf);
 640          free(buf);
 641  #else
 642          size_t bufLen = bannerLen + length + 1;
 643          char *buf = (char *)malloc(sizeof(char) * bufLen);
 644          if (banner) {
 645              // Copy the banner into the debug string
 646              memmove(buf, banner, bannerLen);
 647              
 648              // Copy the message into the debug string
 649              strncpy(buf + bannerLen, message, bufLen - bannerLen);
 650          } else {
 651              strncpy(buf, message, bufLen);
 652          }
 653          buf[bufLen - 1] = '\0';
 654          fprintf(stderr, "%s\n", buf);
 655          free(buf);
 656  #endif
 657      }
 658      
 659      if (thread) free(thread);
 660      if (time) free(time);
 661      if (banner) free(banner);
 662      if (uid) free(uid);
 663  }
 664      
 665  CF_EXPORT void _CFLogvEx2(CFLogFunc logit, CFStringRef (*copyDescFunc)(void *, const void *), CFStringRef (*contextDescFunc)(void *, const void *, const void *, bool, bool *), CFDictionaryRef formatOptions, int32_t lev, CFStringRef format, va_list args) {
 666  #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
 667      uintptr_t val = (uintptr_t)_CFGetTSD(__CFTSDKeyIsInCFLog);
 668      if (3 < val) return; // allow up to 4 nested invocations
 669      _CFSetTSD(__CFTSDKeyIsInCFLog, (void *)(val + 1), NULL);
 670  #endif
 671      CFStringRef str = format ? _CFStringCreateWithFormatAndArgumentsAux2(kCFAllocatorSystemDefault, copyDescFunc, contextDescFunc, formatOptions, (CFStringRef)format, args) : 0;
 672      CFIndex blen = str ? CFStringGetMaximumSizeForEncoding(CFStringGetLength(str), kCFStringEncodingUTF8) + 1 : 0;
 673      char *buf = str ? (char *)malloc(blen) : 0;
 674      if (str && buf) {
 675  	Boolean converted = CFStringGetCString(str, buf, blen, kCFStringEncodingUTF8);
 676  	size_t len = strlen(buf);
 677  	// silently ignore 0-length or really large messages, and levels outside the valid range
 678  	if (converted && !(len <= 0 || (1 << 24) < len) && !(lev < ASL_LEVEL_EMERG || ASL_LEVEL_DEBUG < lev)) {
 679  	    (logit ? logit : __CFLogCString)(lev, buf, len, 1);
 680  	}
 681      }
 682      if (buf) free(buf);
 683      if (str) CFRelease(str);
 684  #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
 685      _CFSetTSD(__CFTSDKeyIsInCFLog, (void *)val, NULL);
 686  #endif
 687  }
 688      
 689  CF_EXPORT void _CFLogvEx(CFLogFunc logit, CFStringRef (*copyDescFunc)(void *, const void *), CFDictionaryRef formatOptions, int32_t lev, CFStringRef format, va_list args) {
 690      _CFLogvEx2(logit, copyDescFunc, NULL, formatOptions, lev, format, args);
 691  }
 692  
 693  // This CF-only log function uses no CF functionality, so it may be called anywhere within CF - including thread teardown or prior to full CF setup
 694  CF_PRIVATE void _CFLogSimple(int32_t lev, char *format, ...) {
 695      va_list args;
 696      va_start(args, format);
 697      char formattedMessage[1024];
 698      int length = vsnprintf(formattedMessage, 1024, format, args);
 699      if (length > 0) {
 700          __CFLogCString(lev, formattedMessage, length, 0);
 701      }
 702      va_end(args);
 703  }
 704  
 705  void CFLog(int32_t lev, CFStringRef format, ...) {
 706      va_list args;
 707      va_start(args, format); 
 708      _CFLogvEx2(NULL, NULL, NULL, NULL, lev, format, args);
 709      va_end(args);
 710  }
 711  
 712  
 713  
 714  #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
 715  
 716  kern_return_t _CFDiscorporateMemoryAllocate(CFDiscorporateMemory *hm, size_t size, bool purgeable) {
 717      kern_return_t ret = KERN_SUCCESS;
 718      size = round_page(size);
 719      if (0 == size) size = vm_page_size;
 720      memset(hm, 0, sizeof(CFDiscorporateMemory));
 721      void *addr = mmap(0, size, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, VM_MAKE_TAG(0) | (purgeable ? VM_FLAGS_PURGABLE : 0), 0);
 722      if ((uintptr_t)addr == -1) {
 723          ret = KERN_NO_SPACE;
 724      }
 725      if (KERN_SUCCESS == ret) {
 726          hm->address = (mach_vm_address_t)(uintptr_t)addr;
 727          hm->size = (mach_vm_size_t)size;
 728          hm->port = MACH_PORT_NULL;
 729          hm->corporeal = true;
 730          hm->purgeable = purgeable;
 731      }
 732      if (KERN_SUCCESS == ret) ret = mach_make_memory_entry_64(mach_task_self(), &hm->size, hm->address, VM_PROT_DEFAULT, &hm->port, MACH_PORT_NULL);
 733      if (KERN_SUCCESS == ret) hm->corporeal = true;
 734      return ret;
 735  }
 736  
 737  kern_return_t _CFDiscorporateMemoryDeallocate(CFDiscorporateMemory *hm) {
 738      kern_return_t ret1 = KERN_SUCCESS, ret2 = KERN_SUCCESS;
 739      if (hm->corporeal) ret1 = mach_vm_deallocate(mach_task_self(), hm->address, hm->size);
 740      hm->address = MACH_VM_MIN_ADDRESS;
 741      hm->corporeal = false;
 742      ret2 = mach_port_deallocate(mach_task_self(), hm->port);
 743      hm->port = MACH_PORT_NULL;
 744      return ret1 != KERN_SUCCESS ? ret1 : ret2;
 745  }
 746  
 747  kern_return_t _CFDiscorporateMemoryDematerialize(CFDiscorporateMemory *hm) {
 748      kern_return_t ret = KERN_SUCCESS;
 749      if (!hm->corporeal) ret = KERN_INVALID_MEMORY_CONTROL;
 750      int state = VM_PURGABLE_VOLATILE;
 751      if (KERN_SUCCESS == ret) vm_purgable_control(mach_task_self(), (vm_address_t)hm->address, VM_PURGABLE_SET_STATE, &state);
 752      if (KERN_SUCCESS == ret) ret = mach_vm_deallocate(mach_task_self(), hm->address, hm->size);
 753      if (KERN_SUCCESS == ret) hm->address = MACH_VM_MIN_ADDRESS;
 754      if (KERN_SUCCESS == ret) hm->corporeal = false;
 755      return ret;
 756  }
 757  
 758  kern_return_t _CFDiscorporateMemoryMaterialize(CFDiscorporateMemory *hm) {
 759      kern_return_t ret = KERN_SUCCESS;
 760      if (hm->corporeal) ret = KERN_INVALID_MEMORY_CONTROL;
 761      if (KERN_SUCCESS == ret) ret = mach_vm_map(mach_task_self(), &hm->address, hm->size, 0, VM_FLAGS_ANYWHERE, hm->port, 0, FALSE, VM_PROT_DEFAULT, VM_PROT_DEFAULT, VM_INHERIT_DEFAULT);
 762      if (KERN_SUCCESS == ret) hm->corporeal = true;
 763      int state = VM_PURGABLE_NONVOLATILE;
 764      if (KERN_SUCCESS == ret) ret = vm_purgable_control(mach_task_self(), (vm_address_t)hm->address, VM_PURGABLE_SET_STATE, &state);
 765      if (KERN_SUCCESS == ret) if (VM_PURGABLE_EMPTY == state) ret = KERN_PROTECTION_FAILURE; // same as VM_PURGABLE_EMPTY
 766      return ret;
 767  }
 768  
 769  #endif
 770  
 771  #if DEPLOYMENT_TARGET_MACOSX
 772  
 773  #define SUDDEN_TERMINATION_ENABLE_VPROC 1
 774  
 775  #if SUDDEN_TERMINATION_ENABLE_VPROC
 776  
 777  static OSSpinLock __CFProcessKillingLock = OS_SPINLOCK_INIT;
 778  static CFIndex __CFProcessKillingDisablingCount = 1;
 779  static Boolean __CFProcessKillingWasTurnedOn = false;
 780  
 781  void _CFSuddenTerminationDisable(void) {
 782      OSSpinLockLock(&__CFProcessKillingLock);
 783      __CFProcessKillingDisablingCount++;
 784      _vproc_transaction_begin();
 785      OSSpinLockUnlock(&__CFProcessKillingLock);
 786  }
 787  
 788  void _CFSuddenTerminationEnable(void) {
 789      // In our model the first call of _CFSuddenTerminationEnable() that does not balance a previous call of _CFSuddenTerminationDisable() actually enables sudden termination so we have to keep a count that's almost redundant with vproc's.
 790      OSSpinLockLock(&__CFProcessKillingLock);
 791      __CFProcessKillingDisablingCount--;
 792      if (__CFProcessKillingDisablingCount==0 && !__CFProcessKillingWasTurnedOn) {
 793  	_vproc_transactions_enable();
 794  	__CFProcessKillingWasTurnedOn = true;
 795      } else {
 796  	// Mail seems to have sudden termination disabling/enabling imbalance bugs that make _vproc_transaction_end() kill the app but we don't want that to prevent our submission of the fix 6382488.
 797  	if (__CFProcessKillingDisablingCount>=0) {
 798  	    _vproc_transaction_end();
 799  	} else {
 800  	    CFLog(kCFLogLevelError, CFSTR("-[NSProcessInfo enableSuddenTermination] has been invoked more times than necessary to balance invocations of -[NSProcessInfo disableSuddenTermination]. Ignoring."));
 801  	}
 802      }
 803      OSSpinLockUnlock(&__CFProcessKillingLock);
 804  }
 805  
 806  void _CFSuddenTerminationExitIfTerminationEnabled(int exitStatus) {
 807      // This is for when the caller wants to try to exit quickly if possible but not automatically exit the process when it next becomes clean, because quitting might still be cancelled by the user.
 808      OSSpinLockLock(&__CFProcessKillingLock);
 809      // Check _vproc_transaction_count() because other code in the process might go straight to the vproc APIs but also check __CFProcessKillingWasTurnedOn because  _vproc_transaction_count() can return 0 when transactions didn't even get enabled.
 810      if (__CFProcessKillingWasTurnedOn) {
 811          _vproc_transaction_try_exit(exitStatus);
 812      }
 813      OSSpinLockUnlock(&__CFProcessKillingLock);
 814  }
 815  
 816  void _CFSuddenTerminationExitWhenTerminationEnabled(int exitStatus) {
 817      // The user has had their final opportunity to cancel quitting. Exit as soon as the process is clean. Same carefulness as in _CFSuddenTerminationExitIfTerminationEnabled().
 818      OSSpinLockLock(&__CFProcessKillingLock);
 819      if (__CFProcessKillingWasTurnedOn) {
 820      }
 821      OSSpinLockUnlock(&__CFProcessKillingLock);
 822  }
 823  
 824  size_t _CFSuddenTerminationDisablingCount(void) {
 825      // Until sudden termination has been really enabled vproc's notion of the count is off by one but we can't just return __CFProcessKillingDisablingCount() because that doesn't take into account stuff that calls the vproc_transaction functions behind our back.
 826      return _vproc_transaction_count() + (__CFProcessKillingWasTurnedOn ? 0 : 1);
 827  }
 828  
 829  #else
 830  
 831  #warning Building with vproc sudden termination API disabled.
 832  
 833  static OSSpinLockUnlock __CFProcessKillingLock = OS_SPINLOCK_INIT;
 834  static size_t __CFProcessKillingDisablingCount = 1;
 835  static Boolean __CFProcessExitNextTimeKillingIsEnabled = false;
 836  static int32_t __CFProcessExitStatus = 0;
 837  static int __CFProcessIsKillableNotifyToken;
 838  static Boolean __CFProcessIsKillableNotifyTokenIsFigured = false;
 839  
 840  CF_PRIVATE void _CFSetSuddenTerminationEnabled(Boolean isEnabled) {
 841      if (!__CFProcessIsKillableNotifyTokenIsFigured) {
 842          char *notificationName = NULL;
 843          asprintf(&notificationName, "com.apple.isKillable.%i", getpid());
 844          uint32_t notifyResult = notify_register_check(notificationName, &__CFProcessIsKillableNotifyToken);
 845          if (notifyResult != NOTIFY_STATUS_OK) {
 846              CFLog(kCFLogLevelError, CFSTR("%s: notify_register_check() returned %i."), __PRETTY_FUNCTION__, notifyResult);
 847          }
 848          free(notificationName);
 849          __CFProcessIsKillableNotifyTokenIsFigured = true;
 850      }
 851      uint32_t notifyResult = notify_set_state(__CFProcessIsKillableNotifyToken, isEnabled);
 852      if (notifyResult != NOTIFY_STATUS_OK) {
 853          CFLog(kCFLogLevelError, CFSTR("%s: notify_set_state() returned %i"), __PRETTY_FUNCTION__, notifyResult);
 854      }
 855  }
 856  
 857  void _CFSuddenTerminationDisable(void) {
 858      OSSpinLockLock(&__CFProcessKillingLock);
 859      if (__CFProcessKillingDisablingCount == 0) {
 860          _CFSetSuddenTerminationEnabled(false);
 861      }
 862      __CFProcessKillingDisablingCount++;
 863      OSSpinLockUnlock(&__CFProcessKillingLock);
 864  }
 865  
 866  void _CFSuddenTerminationEnable(void) {
 867      OSSpinLockLock(&__CFProcessKillingLock);
 868      __CFProcessKillingDisablingCount--;
 869      if (__CFProcessKillingDisablingCount == 0) {
 870          if (__CFProcessExitNextTimeKillingIsEnabled) {
 871              _exit(__CFProcessExitStatus);
 872          } else {
 873              _CFSetSuddenTerminationEnabled(true);
 874          }
 875      }
 876      OSSpinLockUnlock(&__CFProcessKillingLock);
 877  }
 878  
 879  void _CFSuddenTerminationExitIfTerminationEnabled(int exitStatus) {
 880      OSSpinLockLock(&__CFProcessKillingLock);
 881      if (__CFProcessKillingDisablingCount == 0) {
 882          _exit(exitStatus);
 883      }
 884      OSSpinLockUnlock(&__CFProcessKillingLock);
 885  }
 886  
 887  void _CFSuddenTerminationExitWhenTerminationEnabled(int exitStatus) {
 888      OSSpinLockLock(&__CFProcessKillingLock);
 889      if (__CFProcessKillingDisablingCount == 0) {
 890          _exit(exitStatus);
 891      } else {
 892          __CFProcessExitNextTimeKillingIsEnabled = YES;
 893          __CFProcessExitStatus = exitStatus;
 894      }
 895      OSSpinLockUnlock(&__CFProcessKillingLock);
 896  }
 897  
 898  size_t _CFSuddenTerminationDisablingCount(void) {
 899      return __CFProcessKillingDisablingCount;
 900  }
 901  
 902  #endif
 903  
 904  #endif
 905  
 906  #if 0
 907  #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
 908  
 909  typedef void (^ThrottleTypeA)(void);		// allows calls per nanoseconds
 910  typedef void (^ThrottleTypeB)(uint64_t amt);	// allows amount per nanoseconds
 911  
 912  CF_PRIVATE ThrottleTypeA __CFCreateThrottleTypeA(uint16_t calls, uint64_t nanoseconds) {
 913     struct mach_timebase_info info;
 914     mach_timebase_info(&info);
 915     uint64_t period = nanoseconds / info.numer * info.denom;
 916  
 917     if (0 == calls || 0 == period) return NULL;
 918  
 919     __block OSSpinLock b_lock = OS_SPINLOCK_INIT;
 920     __block uint64_t b_values[calls];
 921     __block uint64_t *b_oldest = b_values;
 922     memset(b_values, 0, sizeof(b_values));
 923  
 924     return Block_copy(^{
 925                 uint64_t curr_time = mach_absolute_time();
 926                 OSSpinLockLock(&b_lock);
 927                 uint64_t next_time = *b_oldest + period;
 928                 *b_oldest = (curr_time < next_time) ? next_time : curr_time;
 929                 b_oldest++;
 930                 if (b_values + calls <= b_oldest) b_oldest = b_values;
 931                 OSSpinLockUnlock(&b_lock);
 932                 if (curr_time < next_time) {
 933                     mach_wait_until(next_time);
 934                 }
 935             });
 936  }
 937  
 938  CF_PRIVATE ThrottleTypeB __CFCreateThrottleTypeB(uint64_t amount, uint64_t nanoseconds) {
 939     struct mach_timebase_info info;
 940     mach_timebase_info(&info);
 941     uint64_t period = nanoseconds / info.numer * info.denom;
 942  
 943     if (0 == amount || 0 == period) return NULL;
 944  
 945     __block OSSpinLock b_lock = OS_SPINLOCK_INIT;
 946     __block uint64_t b_sum = 0ULL;
 947     __block uint16_t b_num_values = 8;
 948     __block uint64_t *b_values = calloc(b_num_values, 2 * sizeof(uint64_t));
 949     __block uint64_t *b_oldest = b_values;
 950  
 951     return Block_copy(^(uint64_t amt){
 952                 OSSpinLockLock(&b_lock);
 953  // unimplemented
 954                 OSSpinLockUnlock(&b_lock);
 955             });
 956  }
 957  
 958  #endif
 959  #endif
 960  
 961  #pragma mark File Reading
 962      
 963  #include <sys/stat.h>
 964  #include <fcntl.h>
 965  #include <errno.h>
 966  #if DEPLOYMENT_TARGET_WINDOWS
 967  #include <io.h>
 968  #include <direct.h>
 969  #define close _close
 970  #define write _write
 971  #define read _read
 972  #define open _NS_open
 973  #define stat _NS_stat
 974  #define fstat _fstat
 975  #define statinfo _stat
 976      
 977  #define mach_task_self() 0
 978  
 979  #else
 980  #define statinfo stat
 981  #endif
 982      
 983  static CFErrorRef _CFErrorWithFilePathCodeDomain(CFStringRef domain, CFIndex code, CFStringRef path) {
 984      CFStringRef key = CFSTR("NSFilePath");
 985      CFDictionaryRef userInfo = CFDictionaryCreate(kCFAllocatorSystemDefault, (const void **)&key, (const void **)&path, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
 986      CFErrorRef result = CFErrorCreate(kCFAllocatorSystemDefault, domain, code, userInfo);
 987      CFRelease(userInfo);
 988      return result;
 989  }
 990  
 991  // Caller is responsible for freeing memory. munmap() if map == true, else malloc().
 992  CF_PRIVATE Boolean _CFReadMappedFromFile(CFStringRef path, Boolean map, Boolean uncached, void **outBytes, CFIndex *outLength, CFErrorRef *errorPtr) {
 993      void *bytes = NULL;
 994      unsigned long length;
 995      char cpath[CFMaxPathSize];
 996      if (!CFStringGetFileSystemRepresentation(path, cpath, CFMaxPathSize)) {
 997          // TODO: real error codes
 998          if (errorPtr) *errorPtr = _CFErrorWithFilePathCodeDomain(kCFErrorDomainCocoa, -1, path);
 999  	return false;
1000      }
1001  
1002      struct statinfo statBuf;
1003      int32_t fd = -1;
1004  
1005      fd = open(cpath, O_RDONLY|CF_OPENFLGS, 0666);
1006      if (fd < 0) {
1007          if (errorPtr) *errorPtr = _CFErrorWithFilePathCodeDomain(kCFErrorDomainPOSIX, errno, path);
1008          return false;
1009      }
1010  #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI    
1011      if (uncached) (void)fcntl(fd, F_NOCACHE, 1);  // Non-zero arg turns off caching; we ignore error as uncached is just a hint
1012  #endif
1013      if (fstat(fd, &statBuf) < 0) {
1014          int32_t savederrno = errno;
1015          close(fd);
1016          if (errorPtr) *errorPtr = _CFErrorWithFilePathCodeDomain(kCFErrorDomainPOSIX, savederrno, path);
1017          return false;
1018      }
1019      if ((statBuf.st_mode & S_IFMT) != S_IFREG) {
1020          close(fd);
1021          if (errorPtr) *errorPtr = _CFErrorWithFilePathCodeDomain(kCFErrorDomainPOSIX, EACCES, path);
1022          return false;
1023      }
1024      if (statBuf.st_size < 0LL) {	// too small
1025          close(fd);
1026          if (errorPtr) *errorPtr = _CFErrorWithFilePathCodeDomain(kCFErrorDomainPOSIX, ENOMEM, path);
1027          return false;
1028      }
1029  #if __LP64__
1030  #else
1031      if (statBuf.st_size > (1LL << 31)) {	// refuse to do more than 2GB
1032          close(fd);
1033          if (errorPtr) *errorPtr = _CFErrorWithFilePathCodeDomain(kCFErrorDomainPOSIX, EFBIG, path);
1034          return false;
1035      }
1036  #endif
1037  
1038      if (0LL == statBuf.st_size) {
1039          bytes = malloc(8); // don't return constant string -- it's freed!
1040  	length = 0;
1041  #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI || DEPLOYMENT_TARGET_LINUX
1042      } else if (map) {
1043          if((void *)-1 == (bytes = mmap(0, (size_t)statBuf.st_size, PROT_READ, MAP_PRIVATE, fd, 0))) {
1044  	    int32_t savederrno = errno;
1045  	    close(fd);
1046              if (errorPtr) *errorPtr = _CFErrorWithFilePathCodeDomain(kCFErrorDomainPOSIX, savederrno, path);
1047  	    return false;
1048  	}
1049  	length = (unsigned long)statBuf.st_size;
1050      } else {
1051          bytes = malloc(statBuf.st_size);
1052          if (bytes == NULL) {
1053              close(fd);
1054              if (errorPtr) *errorPtr = _CFErrorWithFilePathCodeDomain(kCFErrorDomainPOSIX, ENOMEM, path);
1055              return false;
1056          }
1057  	size_t numBytesRemaining = (size_t)statBuf.st_size;
1058  	void *readLocation = bytes;
1059  	while (numBytesRemaining > 0) {
1060  	    size_t numBytesRequested = (numBytesRemaining < (1LL << 31)) ? numBytesRemaining : ((1LL << 31) - 1);	// This loop is basically a workaround for 4870206 
1061  	    ssize_t numBytesRead = read(fd, readLocation, numBytesRequested);
1062  	    if (numBytesRead <= 0) {
1063  		if (numBytesRead < 0) {
1064  		    int32_t savederrno = errno;
1065                      free(bytes);
1066  		    close(fd);
1067                      if (errorPtr) *errorPtr = _CFErrorWithFilePathCodeDomain(kCFErrorDomainPOSIX, savederrno, path);
1068  		    bytes = NULL;
1069  		    return false;
1070  		} else {
1071  		    // This is a bizarre case; 0 bytes read. Might indicate end-of-file?
1072  		    break;
1073  		}
1074  	    } else {
1075  		readLocation += numBytesRead;
1076  		numBytesRemaining -= numBytesRead;
1077  	    }
1078  	}
1079  	length = (unsigned long)statBuf.st_size - numBytesRemaining;
1080      }
1081  #elif DEPLOYMENT_TARGET_WINDOWS
1082      } else {
1083          bytes = malloc(statBuf.st_size);
1084          DWORD numBytesRead;
1085          if (!ReadFile((HANDLE)_get_osfhandle(fd), bytes, statBuf.st_size, &numBytesRead, NULL)) {
1086              DWORD lastError = GetLastError();
1087              if (errorPtr) *errorPtr = _CFErrorWithFilePathCodeDomain(kCFErrorDomainPOSIX, lastError, path);
1088  	    free(bytes);
1089  	    close(fd);
1090  	    errno = lastError;
1091  	    bytes = NULL;
1092  	    return false;
1093          }
1094  	length = numBytesRead;
1095      }
1096  #endif
1097      close(fd);
1098      *outBytes = bytes;
1099      *outLength = length;
1100      return true;
1101  }