CFBundle.c
   1  /*      CFBundle.c
   2  	Copyright (c) 1999-2019, Apple Inc. and the Swift project authors
   3   
   4  	Portions Copyright (c) 2014-2019, Apple Inc. and the Swift project authors
   5  	Licensed under Apache License v2.0 with Runtime Library Exception
   6  	See http://swift.org/LICENSE.txt for license information
   7  	See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
   8          Responsibility: Tony Parker
   9  */
  10  
  11  #include <CoreFoundation/CoreFoundation.h>
  12  #include "CFBundle_Internal.h"
  13  #include <CoreFoundation/CFPropertyList.h>
  14  #include <CoreFoundation/CFNumber.h>
  15  #include <CoreFoundation/CFSet.h>
  16  #include <CoreFoundation/CFURLAccess.h>
  17  #include <CoreFoundation/CFError.h>
  18  #include <CoreFoundation/CFError_Private.h>
  19  #include <string.h>
  20  #include <CoreFoundation/CFPriv.h>
  21  #include "CFInternal.h"
  22  #include "CFRuntime_Internal.h"
  23  #include <CoreFoundation/CFByteOrder.h>
  24  #include "CFBundle_BinaryTypes.h"
  25  #include <ctype.h>
  26  #include <sys/stat.h>
  27  #include <stdlib.h>
  28  #include <assert.h>
  29  
  30  
  31  #if defined(BINARY_SUPPORT_DYLD)
  32  #include <unistd.h>
  33  #include <fcntl.h>
  34  #include <sys/mman.h>
  35  #include <crt_externs.h>
  36  #endif /* BINARY_SUPPORT_DYLD */
  37  
  38  #if defined(BINARY_SUPPORT_DLFCN)
  39  #include <dlfcn.h>
  40  #ifndef RTLD_FIRST
  41  #define RTLD_FIRST 0
  42  #endif
  43  #endif /* BINARY_SUPPORT_DLFCN */
  44  
  45  #if TARGET_OS_MAC
  46  #include <fcntl.h>
  47  #elif TARGET_OS_WIN32
  48  #include <fcntl.h>
  49  #include <io.h>
  50  #endif
  51  
  52  
  53  #define LOG_BUNDLE_LOAD 0
  54  
  55  // Public CFBundle Info plist keys
  56  CONST_STRING_DECL(kCFBundleInfoDictionaryVersionKey, "CFBundleInfoDictionaryVersion")
  57  CONST_STRING_DECL(kCFBundleExecutableKey, "CFBundleExecutable")
  58  CONST_STRING_DECL(kCFBundleIdentifierKey, "CFBundleIdentifier")
  59  CONST_STRING_DECL(kCFBundleVersionKey, "CFBundleVersion")
  60  CONST_STRING_DECL(kCFBundleDevelopmentRegionKey, "CFBundleDevelopmentRegion")
  61  CONST_STRING_DECL(kCFBundleLocalizationsKey, "CFBundleLocalizations")
  62  
  63  // Private CFBundle key, used to mean 'I support the same localizations as CoreFoundation'
  64  CONST_STRING_DECL(_kCFBundleUseAppleLocalizationsKey, "_CFBundleUseAppleLocalizations")
  65  
  66  // Private CFBundle Info plist keys, possible candidates for public constants
  67  CONST_STRING_DECL(_kCFBundleAllowMixedLocalizationsKey, "CFBundleAllowMixedLocalizations")
  68  CONST_STRING_DECL(_kCFBundleSupportedPlatformsKey, "CFBundleSupportedPlatforms")
  69  CONST_STRING_DECL(_kCFBundleResourceSpecificationKey, "CFBundleResourceSpecification")
  70  
  71  // Finder stuff
  72  CONST_STRING_DECL(_kCFBundlePackageTypeKey, "CFBundlePackageType")
  73  CONST_STRING_DECL(_kCFBundleSignatureKey, "CFBundleSignature")
  74  CONST_STRING_DECL(_kCFBundleIconFileKey, "CFBundleIconFile")
  75  CONST_STRING_DECL(_kCFBundleDocumentTypesKey, "CFBundleDocumentTypes")
  76  CONST_STRING_DECL(_kCFBundleURLTypesKey, "CFBundleURLTypes")
  77  
  78  // Keys that are usually localized in InfoPlist.strings
  79  CONST_STRING_DECL(kCFBundleNameKey, "CFBundleName")
  80  CONST_STRING_DECL(_kCFBundleDisplayNameKey, "CFBundleDisplayName")
  81  CONST_STRING_DECL(_kCFBundleShortVersionStringKey, "CFBundleShortVersionString")
  82  CONST_STRING_DECL(_kCFBundleGetInfoStringKey, "CFBundleGetInfoString")
  83  CONST_STRING_DECL(_kCFBundleGetInfoHTMLKey, "CFBundleGetInfoHTML")
  84  
  85  // Sub-keys for CFBundleDocumentTypes dictionaries
  86  CONST_STRING_DECL(_kCFBundleTypeNameKey, "CFBundleTypeName")
  87  CONST_STRING_DECL(_kCFBundleTypeRoleKey, "CFBundleTypeRole")
  88  CONST_STRING_DECL(_kCFBundleTypeIconFileKey, "CFBundleTypeIconFile")
  89  CONST_STRING_DECL(_kCFBundleTypeOSTypesKey, "CFBundleTypeOSTypes")
  90  CONST_STRING_DECL(_kCFBundleTypeExtensionsKey, "CFBundleTypeExtensions")
  91  CONST_STRING_DECL(_kCFBundleTypeMIMETypesKey, "CFBundleTypeMIMETypes")
  92  
  93  // Sub-keys for CFBundleURLTypes dictionaries
  94  CONST_STRING_DECL(_kCFBundleURLNameKey, "CFBundleURLName")
  95  CONST_STRING_DECL(_kCFBundleURLIconFileKey, "CFBundleURLIconFile")
  96  CONST_STRING_DECL(_kCFBundleURLSchemesKey, "CFBundleURLSchemes")
  97  
  98  // Compatibility key names
  99  CONST_STRING_DECL(_kCFBundleOldExecutableKey, "NSExecutable")
 100  CONST_STRING_DECL(_kCFBundleOldInfoDictionaryVersionKey, "NSInfoPlistVersion")
 101  CONST_STRING_DECL(_kCFBundleOldNameKey, "NSHumanReadableName")
 102  CONST_STRING_DECL(_kCFBundleOldIconFileKey, "NSIcon")
 103  CONST_STRING_DECL(_kCFBundleOldDocumentTypesKey, "NSTypes")
 104  CONST_STRING_DECL(_kCFBundleOldShortVersionStringKey, "NSAppVersion")
 105  
 106  // Compatibility CFBundleDocumentTypes key names
 107  CONST_STRING_DECL(_kCFBundleOldTypeNameKey, "NSName")
 108  CONST_STRING_DECL(_kCFBundleOldTypeRoleKey, "NSRole")
 109  CONST_STRING_DECL(_kCFBundleOldTypeIconFileKey, "NSIcon")
 110  CONST_STRING_DECL(_kCFBundleOldTypeExtensions1Key, "NSUnixExtensions")
 111  CONST_STRING_DECL(_kCFBundleOldTypeExtensions2Key, "NSDOSExtensions")
 112  CONST_STRING_DECL(_kCFBundleOldTypeOSTypesKey, "NSMacOSType")
 113  
 114  // Internally used keys for loaded Info plists.
 115  CONST_STRING_DECL(_kCFBundleInfoPlistURLKey, "CFBundleInfoPlistURL")
 116  CONST_STRING_DECL(_kCFBundleRawInfoPlistURLKey, "CFBundleRawInfoPlistURL")
 117  CONST_STRING_DECL(_kCFBundleNumericVersionKey, "CFBundleNumericVersion")
 118  CONST_STRING_DECL(_kCFBundleExecutablePathKey, "CFBundleExecutablePath")
 119  CONST_STRING_DECL(_kCFBundleResourcesFileMappedKey, "CSResourcesFileMapped")
 120  CONST_STRING_DECL(_kCFBundleCFMLoadAsBundleKey, "CFBundleCFMLoadAsBundle")
 121  
 122  // Keys used by NSBundle for loaded Info plists.
 123  CONST_STRING_DECL(_kCFBundlePrincipalClassKey, "NSPrincipalClass")
 124  
 125  static _CFMutex CFBundleGlobalDataLock = _CF_MUTEX_STATIC_INITIALIZER;
 126  
 127  static CFMutableDictionaryRef _bundlesByIdentifier = NULL;
 128  static CFMutableDictionaryRef _bundlesByURL = NULL;
 129  static CFMutableArrayRef _allBundles = NULL;
 130  
 131  static CFBundleRef _CFBundleCreate(CFAllocatorRef allocator, CFURLRef bundleURL, Boolean doFinalProcessing, Boolean unique, Boolean addToTables);
 132  static void _CFBundleEnsureBundlesUpToDateWithHint(CFStringRef hint);
 133  static void _CFBundleEnsureAllBundlesUpToDate(void);
 134  static void _CFBundleEnsureBundleExistsForImagePath(CFStringRef imagePath, Boolean permissive);
 135  static void _CFBundleEnsureBundlesExistForImagePaths(CFArrayRef imagePaths);
 136  
 137  #pragma mark -
 138  
 139  #if !DEPLOYMENT_RUNTIME_OBJC && !TARGET_OS_WIN32 && !TARGET_OS_ANDROID
 140  
 141  // Functions and constants for FHS bundles:
 142  #define _CFBundleFHSDirectory_share CFSTR("share")
 143  
 144  static Boolean _CFBundleURLIsForFHSInstalledBundle(CFURLRef bundleURL) {
 145      // Paths of this form are FHS installed bundles:
 146      // <anywhere>/share/<name>.resources
 147      
 148      CFStringRef extension = CFURLCopyPathExtension(bundleURL);
 149      CFURLRef parentURL = CFURLCreateCopyDeletingLastPathComponent(kCFAllocatorSystemDefault, bundleURL);
 150      CFStringRef containingDirectoryName = parentURL ? CFURLCopyLastPathComponent(parentURL) : NULL;
 151      
 152      Boolean isFHSBundle =
 153          extension &&
 154          containingDirectoryName &&
 155          CFEqual(extension, _CFBundleSiblingResourceDirectoryExtension) &&
 156          CFEqual(containingDirectoryName, _CFBundleFHSDirectory_share);
 157      
 158      if (extension) CFRelease(extension);
 159      if (parentURL) CFRelease(parentURL);
 160      if (containingDirectoryName) CFRelease(containingDirectoryName);
 161      
 162      return isFHSBundle;
 163  }
 164  #endif // !DEPLOYMENT_RUNTIME_OBJC && !TARGET_OS_WIN32 && !TARGET_OS_ANDROID
 165  
 166  CF_CROSS_PLATFORM_EXPORT Boolean _CFBundleSupportsFHSBundles() {
 167  #if !DEPLOYMENT_RUNTIME_OBJC && !TARGET_OS_WIN32 && !TARGET_OS_ANDROID
 168      return true;
 169  #else
 170      return false;
 171  #endif
 172  }
 173  
 174  CF_CROSS_PLATFORM_EXPORT Boolean _CFBundleSupportsFreestandingBundles() {
 175  #if !DEPLOYMENT_RUNTIME_OBJC
 176      return true;
 177  #else
 178      return false;
 179  #endif
 180  }
 181  
 182  #pragma mark -
 183  
 184  CF_PRIVATE os_log_t _CFBundleResourceLogger(void) {
 185      static os_log_t _log;
 186      static dispatch_once_t onceToken;
 187      dispatch_once(&onceToken, ^{
 188          _log = os_log_create("com.apple.CFBundle", "resources");
 189      });
 190      return _log;
 191  }
 192  
 193  CF_PRIVATE os_log_t _CFBundleLocalizedStringLogger(void) {
 194      static os_log_t _log;
 195      static dispatch_once_t onceToken;
 196      dispatch_once(&onceToken, ^{
 197          _log = os_log_create("com.apple.CFBundle", "strings");
 198      });
 199      return _log;
 200  }
 201  
 202  CF_PRIVATE os_log_t _CFBundleLoadingLogger(void) {
 203      static os_log_t _log;
 204      static dispatch_once_t onceToken;
 205      dispatch_once(&onceToken, ^{
 206          _log = os_log_create("com.apple.CFBundle", "loading");
 207      });
 208      return _log;
 209  }
 210  
 211  #pragma mark -
 212  
 213  #if TARGET_OS_OSX
 214  // Some apps may rely on the fact that CFBundle used to allow bundle objects to be deallocated (despite handing out unretained pointers via CFBundleGetBundleWithIdentifier or CFBundleGetAllBundles). To remain compatible even in the face of unsafe behavior, we can optionally use unsafe-unretained memory management for holding on to bundles.
 215  static Boolean _useUnsafeUnretainedTables(void) {
 216      return false;
 217  }
 218  #endif
 219  
 220  #pragma mark -
 221  #pragma mark Utilities
 222  
 223  // Create an absolute URL after creating a URL with the supplied URLString, baseURL.
 224  // This is used to resolve symbolic links in the path (For example, for wrapped bundles)
 225  CF_PRIVATE CFURLRef _CFURLCreateResolvedDirectoryWithString(CFAllocatorRef allocator, CFStringRef URLString, CFURLRef baseURL) {
 226      CFURLRef relativeURL = CFURLCreateWithString(allocator, URLString, baseURL);
 227      CFURLRef absoluteURL = CFURLCopyAbsoluteURL(relativeURL);
 228      CFRelease(relativeURL);
 229      CFStringRef absolutePath = CFURLCopyFileSystemPath(absoluteURL, PLATFORM_PATH_STYLE);
 230      CFRelease(absoluteURL);
 231      
 232      char absolutePathCString[PATH_MAX];
 233      Boolean success = CFStringGetFileSystemRepresentation(absolutePath, absolutePathCString, PATH_MAX);
 234      CFRelease(absolutePath);
 235      if (success) {
 236          int fd = open(absolutePathCString, O_RDONLY);
 237          if (fd > 0) {
 238              char resolvedPathCString[PATH_MAX];
 239              if (_CFGetPathFromFileDescriptor(fd, resolvedPathCString)) {
 240                  os_log_error(_CFBundleResourceLogger(), "Unable to resolve directory (%d)", errno);
 241                  close(fd);
 242              } else {
 243                  close(fd);
 244                  CFStringRef resolvedPath = CFStringCreateWithFileSystemRepresentation(allocator, resolvedPathCString);
 245                  CFURLRef result = CFURLCreateWithFileSystemPath(allocator, resolvedPath, PLATFORM_PATH_STYLE, true);
 246                  CFRelease(resolvedPath);
 247                  return result;
 248              }
 249          }
 250      }
 251      
 252      return NULL;
 253  }
 254  
 255  #pragma mark -
 256  #pragma mark Bundle Tables
 257  
 258  static void _CFBundleAddToTablesLocked(CFBundleRef bundle, CFStringRef bundleID) {
 259      if (bundle->_isUnique) return;
 260  
 261      // Add to the _allBundles list
 262      if (!_allBundles) {
 263          CFArrayCallBacks callbacks = kCFTypeArrayCallBacks;
 264  #if TARGET_OS_OSX
 265          if (_useUnsafeUnretainedTables()) {
 266              callbacks.retain = NULL;
 267              callbacks.release = NULL;
 268          }
 269  #endif
 270          // The _allBundles array holds a strong reference on the bundle.
 271          // It does this to prevent a race on bundle deallocation / creation. See: <rdar://problem/6606482> CFBundle isn't thread-safe in RR mode
 272          // Also, the existence of the CFBundleGetBundleWithIdentifier / CFBundleGetAllBundles API means that any bundle we hand out from there must be permanently retained, or callers will potentially have an object that can be deallocated out from underneath them.
 273          _allBundles = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &callbacks);
 274      }
 275      CFArrayAppendValue(_allBundles, bundle);
 276      
 277      // Add to the table that maps urls to bundles
 278      if (!_bundlesByURL) {
 279          CFDictionaryValueCallBacks nonRetainingDictionaryValueCallbacks = kCFTypeDictionaryValueCallBacks;
 280          nonRetainingDictionaryValueCallbacks.retain = NULL;
 281          nonRetainingDictionaryValueCallbacks.release = NULL;
 282          _bundlesByURL = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeDictionaryKeyCallBacks, &nonRetainingDictionaryValueCallbacks);
 283      }
 284      CFDictionarySetValue(_bundlesByURL, bundle->_url, bundle);
 285  
 286      // Add to the table that maps identifiers to bundles
 287      if (bundleID) {
 288          CFMutableArrayRef bundlesWithThisID = NULL;
 289          CFBundleRef existingBundle = NULL;
 290          if (!_bundlesByIdentifier) {
 291              _bundlesByIdentifier = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
 292          }
 293          bundlesWithThisID = (CFMutableArrayRef)CFDictionaryGetValue(_bundlesByIdentifier, bundleID);
 294          if (bundlesWithThisID) {
 295              CFIndex i, count = CFArrayGetCount(bundlesWithThisID);
 296              UInt32 existingVersion, newVersion = CFBundleGetVersionNumber(bundle);
 297              for (i = 0; i < count; i++) {
 298                  existingBundle = (CFBundleRef)CFArrayGetValueAtIndex(bundlesWithThisID, i);
 299                  existingVersion = CFBundleGetVersionNumber(existingBundle);
 300                  // If you load two bundles with the same identifier and the same version, the last one wins.
 301                  if (newVersion >= existingVersion) break;
 302              }
 303              CFArrayInsertValueAtIndex(bundlesWithThisID, i, bundle);
 304  
 305              // We've encountered a bundle with this ID already.
 306              // Output some additional info here. It may not be an error (adding a newer version of a bundle is supported), so use os_log_debug.
 307              if (os_log_debug_enabled(_CFBundleResourceLogger())) {
 308                  CFMutableArrayRef bundleList = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeArrayCallBacks);
 309                  for (CFIndex i = 0; i < CFArrayGetCount(bundlesWithThisID); i++) {
 310                      CFBundleRef bundle = (CFBundleRef)CFArrayGetValueAtIndex(bundlesWithThisID, i);
 311                      CFStringRef desc = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("Bundle %p at %@"), bundle, bundle->_url);
 312                      CFArrayAppendValue(bundleList, desc);
 313                      CFRelease(desc);
 314                  }
 315                  os_log_debug(_CFBundleResourceLogger(), "More than one bundle with the same identifier has been added: %{public}@", bundleList);
 316                  CFRelease(bundleList);
 317              }
 318          } else {
 319              CFArrayCallBacks nonRetainingArrayCallbacks = kCFTypeArrayCallBacks;
 320              nonRetainingArrayCallbacks.retain = NULL;
 321              nonRetainingArrayCallbacks.release = NULL;
 322              bundlesWithThisID = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &nonRetainingArrayCallbacks);
 323              CFArrayAppendValue(bundlesWithThisID, bundle);
 324              CFDictionarySetValue(_bundlesByIdentifier, bundleID, bundlesWithThisID);
 325              CFRelease(bundlesWithThisID);
 326          }
 327      }
 328  }
 329  
 330  static void _CFBundleRemoveFromTables(CFBundleRef bundle, CFURLRef bundleURL, CFStringRef bundleID) {
 331      // Since we no longer allow bundles to be removed from tables, this method does nothing. Modifying the tables during deallocation is risky because if the caller has over-released the bundle object then we will deadlock on the global lock.
 332  #if TARGET_OS_OSX
 333      if (_useUnsafeUnretainedTables()) {
 334          // Except for special cases of unsafe-unretained, where we must clean up the table or risk handing out a zombie object. There may still be outstanding pointers to these bundes (e.g. the result of CFBundleGetBundleWithIdentifier) but there is nothing we can do about that after this point.
 335          
 336          // Unique bundles aren't in the tables anyway
 337          if (bundle->_isUnique) return;
 338          
 339          _CFMutexLock(&CFBundleGlobalDataLock);
 340          // Remove from the table of all bundles
 341          if (_allBundles) {
 342              CFIndex i = CFArrayGetFirstIndexOfValue(_allBundles, CFRangeMake(0, CFArrayGetCount(_allBundles)), bundle);
 343              if (i >= 0) CFArrayRemoveValueAtIndex(_allBundles, i);
 344          }
 345          
 346          // Remove from the table that maps urls to bundles
 347          if (bundleURL && _bundlesByURL) {
 348              CFBundleRef bundleForURL = (CFBundleRef)CFDictionaryGetValue(_bundlesByURL, bundleURL);
 349              if (bundleForURL == bundle) CFDictionaryRemoveValue(_bundlesByURL, bundleURL);
 350          }
 351          
 352          // Remove from the table that maps identifiers to bundles
 353          if (bundleID && _bundlesByIdentifier) {
 354              CFMutableArrayRef bundlesWithThisID = (CFMutableArrayRef)CFDictionaryGetValue(_bundlesByIdentifier, bundleID);
 355              if (bundlesWithThisID) {
 356                  CFIndex count = CFArrayGetCount(bundlesWithThisID);
 357                  while (count-- > 0) if (bundle == (CFBundleRef)CFArrayGetValueAtIndex(bundlesWithThisID, count)) CFArrayRemoveValueAtIndex(bundlesWithThisID, count);
 358                  if (0 == CFArrayGetCount(bundlesWithThisID)) CFDictionaryRemoveValue(_bundlesByIdentifier, bundleID);
 359              }
 360          }
 361          _CFMutexUnlock(&CFBundleGlobalDataLock);
 362      }
 363  #endif
 364  }
 365  
 366  static CFBundleRef _CFBundleGetFromTablesLocked(CFStringRef bundleID) {
 367      CFBundleRef result = NULL, bundle;
 368      if (_bundlesByIdentifier && bundleID) {
 369          // Note that this array is maintained in descending order by version number
 370          CFArrayRef bundlesWithThisID = (CFArrayRef)CFDictionaryGetValue(_bundlesByIdentifier, bundleID);
 371          if (bundlesWithThisID) {
 372              CFIndex i, count = CFArrayGetCount(bundlesWithThisID);
 373              if (count > 0) {
 374                  // First check for loaded bundles so we will always prefer a loaded to an unloaded bundle
 375                  for (i = 0; !result && i < count; i++) {
 376                      bundle = (CFBundleRef)CFArrayGetValueAtIndex(bundlesWithThisID, i);
 377                      if (CFBundleIsExecutableLoaded(bundle)) result = bundle;
 378                  }
 379                  // If no loaded bundle, simply take the first item in the array, i.e. the one with the latest version number
 380                  if (!result) result = (CFBundleRef)CFArrayGetValueAtIndex(bundlesWithThisID, 0);
 381              }
 382          }
 383      }
 384      return result;
 385  }
 386  
 387  static CFBundleRef _CFBundleGetFromTables(CFStringRef bundleID) {
 388      _CFMutexLock(&CFBundleGlobalDataLock);
 389      CFBundleRef result = _CFBundleGetFromTablesLocked(bundleID);
 390      _CFMutexUnlock(&CFBundleGlobalDataLock);
 391      return result;
 392  }
 393  
 394  static CFBundleRef _CFBundleCopyFromTablesForURLLocked(CFURLRef url) {
 395      /*
 396       If you're curious why this doesn't consult the main bundle URL, consider the case where you have a directory structure like this:
 397       
 398       /S/L/F/Foo.framework/Foo
 399       /S/L/F/Foo.framework/food      (a daemon for the Foo framework)
 400       
 401       And the main executable is 'food'.
 402       
 403       This flat structure can happen on iOS, with its more common version 3 bundles. In this scenario, there are theoretically two different bundles that could be returned: one for the framework, one for the daemon. They have the same URL but different bundle identifiers.
 404       
 405       Since the main bundle is not part of the bundle tables, we can support this scenario by having the _bundlesByURL data structure hold the bundle for URL "/S/L/F/Foo.framework/Foo" and _mainBundle (in CFBundle_Main.c) hold the bundle for URL "/S/L/F/Foo.framework/food".
 406       */
 407      CFBundleRef result = NULL;
 408      if (_bundlesByURL) result = (CFBundleRef)CFDictionaryGetValue(_bundlesByURL, url);
 409      if (result && !result->_url) {
 410          result = NULL;
 411          CFDictionaryRemoveValue(_bundlesByURL, url);
 412      }
 413      if (result) CFRetain(result);
 414      return result;
 415  }
 416  
 417  static CFBundleRef _CFBundleCopyFromTablesForURL(CFURLRef url) {
 418      _CFMutexLock(&CFBundleGlobalDataLock);
 419      CFBundleRef result = _CFBundleCopyFromTablesForURLLocked(url);
 420      _CFMutexUnlock(&CFBundleGlobalDataLock);
 421      return result;
 422  }
 423  
 424  #pragma mark -
 425  
 426  CF_PRIVATE _CFBundleVersion _CFBundleEffectiveLayoutVersion(CFBundleRef bundle) {
 427      _CFBundleVersion localVersion = bundle->_version;
 428      // exclude type 0 bundles with no binary (or CFM binary) and no Info.plist, since they give too many false positives
 429      if (_CFBundleVersionOldStyleResources == localVersion) {
 430          CFDictionaryRef infoDict = CFBundleGetInfoDictionary(bundle);
 431          if (!infoDict || 0 == CFDictionaryGetCount(infoDict)) {
 432  #if defined(BINARY_SUPPORT_DYLD)
 433              CFURLRef executableURL = CFBundleCopyExecutableURL(bundle);
 434              if (executableURL) {
 435                  if (bundle->_binaryType == __CFBundleUnknownBinary) bundle->_binaryType = _CFBundleGrokBinaryType(executableURL);
 436                  if (bundle->_binaryType == __CFBundleCFMBinary || bundle->_binaryType == __CFBundleUnreadableBinary) {
 437                      localVersion = _CFBundleVersionNotABundle;
 438                  } else {
 439                      bundle->_resourceData._executableLacksResourceFork = true;
 440                  }
 441                  CFRelease(executableURL);
 442              } else {
 443                  localVersion = _CFBundleVersionNotABundle;
 444              }
 445  #else 
 446              CFURLRef executableURL = CFBundleCopyExecutableURL(bundle);
 447              if (executableURL) {
 448                  CFRelease(executableURL);
 449              } else {
 450                  localVersion = _CFBundleVersionNotABundle;
 451              }
 452  #endif /* BINARY_SUPPORT_DYLD */
 453          }
 454      }
 455      return localVersion;
 456  }
 457  
 458  CFBundleRef _CFBundleCreateIfLooksLikeBundle(CFAllocatorRef allocator, CFURLRef url) {
 459      // It is assumed that users of this SPI do not want this bundle to persist forever.
 460      CFBundleRef bundle = _CFBundleCreateUnique(allocator, url);
 461      if (bundle) {
 462          _CFBundleVersion localVersion = _CFBundleEffectiveLayoutVersion(bundle);
 463          if (_CFBundleVersionFlat == localVersion || _CFBundleVersionNotABundle == localVersion) {
 464              CFRelease(bundle);
 465              bundle = NULL;
 466          }
 467      }
 468      return bundle;
 469  }
 470  
 471  CF_EXPORT Boolean _CFBundleURLLooksLikeBundle(CFURLRef url) {
 472      Boolean result = false;
 473      CFBundleRef bundle = _CFBundleCreateIfLooksLikeBundle(kCFAllocatorSystemDefault, url);
 474      if (bundle) {
 475          result = true;
 476          CFRelease(bundle);
 477      }
 478      return result;
 479  }
 480  
 481  CFBundleRef _CFBundleGetMainBundleIfLooksLikeBundle(void) {
 482      CFBundleRef mainBundle = CFBundleGetMainBundle();
 483      if (mainBundle && (_CFBundleVersionFlat == mainBundle->_version || _CFBundleVersionNotABundle == mainBundle->_version)) mainBundle = NULL;
 484      return mainBundle;
 485  }
 486  
 487  Boolean _CFBundleMainBundleInfoDictionaryComesFromResourceFork(void) {
 488      CFBundleRef mainBundle = CFBundleGetMainBundle();
 489      return (mainBundle && mainBundle->_resourceData._infoDictionaryFromResourceFork);
 490  }
 491  
 492  CF_EXPORT CFBundleRef _CFBundleCreateIfMightBeBundle(CFAllocatorRef allocator, CFURLRef url) {
 493      // This function is obsolete
 494      CFBundleRef bundle = CFBundleCreate(allocator, url);
 495      return bundle;
 496  }
 497          
 498  CF_EXPORT void _CFBundleFlushBundleCaches(CFBundleRef bundle) {
 499      __CFLock(&bundle->_lock);
 500      CFDictionaryRef oldInfoDict = bundle->_infoDict;
 501      CFTypeRef val;
 502      
 503      bundle->_infoDict = NULL;
 504      if (bundle->_localInfoDict) {
 505          CFRelease(bundle->_localInfoDict);
 506          bundle->_localInfoDict = NULL;
 507      }
 508      if (bundle->_infoPlistUrl) {
 509          CFRelease(bundle->_infoPlistUrl);
 510          bundle->_infoPlistUrl = NULL;
 511      }
 512      if (bundle->_developmentRegion) {
 513          CFRelease(bundle->_developmentRegion);
 514          bundle->_developmentRegion = NULL;
 515      }
 516      if (bundle->_executablePath) {
 517          CFRelease(bundle->_executablePath);
 518          bundle->_executablePath = NULL;
 519      }
 520      if (bundle->_searchLanguages) {
 521          CFRelease(bundle->_searchLanguages);
 522          bundle->_searchLanguages = NULL;
 523      }
 524      if (bundle->_stringTable) {
 525          CFRelease(bundle->_stringTable);
 526          bundle->_stringTable = NULL;
 527      }
 528      _CFBundleRefreshInfoDictionaryAlreadyLocked(bundle);
 529      if (oldInfoDict) {
 530          if (!bundle->_infoDict) bundle->_infoDict = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
 531          val = CFDictionaryGetValue(oldInfoDict, _kCFBundlePrincipalClassKey);
 532          if (val) CFDictionarySetValue((CFMutableDictionaryRef)bundle->_infoDict, _kCFBundlePrincipalClassKey, val);
 533          CFRelease(oldInfoDict);
 534      }
 535      _CFBundleFlushQueryTableCache(bundle);
 536      __CFUnlock(&bundle->_lock);
 537  }
 538  
 539  static CFBundleRef _CFBundleGetBundleWithIdentifier(CFStringRef bundleID, void *frameworkHint) {
 540      CFBundleRef result = NULL;
 541      if (bundleID) {
 542          CFBundleRef main = CFBundleGetMainBundle();
 543          if (main) {
 544              CFDictionaryRef infoDict = CFBundleGetInfoDictionary(main);
 545              if (infoDict) {
 546                  CFStringRef mainBundleID = CFDictionaryGetValue(infoDict, kCFBundleIdentifierKey);
 547                  if (mainBundleID && CFGetTypeID(mainBundleID) == CFStringGetTypeID() && CFEqual(mainBundleID, bundleID)) {
 548                      return main;
 549                  }
 550              }
 551          }
 552          
 553          result = _CFBundleGetFromTables(bundleID);
 554  #if TARGET_OS_MAC
 555          if (!result) {
 556              // Try to create the bundle for the caller and try again
 557              if (frameworkHint) {
 558                  CFStringRef imagePath = _CFBundleCopyLoadedImagePathForPointer(frameworkHint);
 559                  if (imagePath) {
 560                      // As this is a fast-path check, we don't want to be aggressive about assuming that the executable URL that we may have received from DYLD via _CFBundleCopyLoadedImagePathForPointer should be turned into a framework URL. If we do, then it is possible that an executable located inside a framework bundle which does not normally link that framework will cause us to load it unintentionally (31165928).
 561                      // For example:
 562                      // Foo.framework/
 563                      //               Resources/
 564                      //                         HelperTool
 565                      //
 566                      // With permissive set to 'true', this would make the 'Foo.framework' bundle exist, but there is no reason why HelperTool is required to have loaded Foo.framework.
 567                      
 568                      _CFBundleEnsureBundleExistsForImagePath(imagePath, false);
 569                      CFRelease(imagePath);
 570                  }
 571                  
 572                  // Now try again
 573                  result = _CFBundleGetFromTables(bundleID);
 574              }
 575          }
 576  #endif
 577          if (!result) {
 578              // Try to guess the bundle from the identifier and try again
 579              _CFBundleEnsureBundlesUpToDateWithHint(bundleID);
 580              
 581              // Now try again
 582              result = _CFBundleGetFromTables(bundleID);
 583          }
 584      }
 585      
 586      if (!result) {
 587          // Make sure all bundles have been created and try again.
 588          _CFBundleEnsureAllBundlesUpToDate();
 589  
 590          // Now try again
 591          result = _CFBundleGetFromTables(bundleID);
 592      }
 593  
 594      return result;
 595  }
 596  
 597  CFBundleRef CFBundleGetBundleWithIdentifier(CFStringRef bundleID) {
 598      // Use the frame that called this as a hint
 599      return _CFBundleGetBundleWithIdentifier(bundleID, __builtin_return_address(0));
 600  }
 601  
 602  CFBundleRef _CFBundleGetBundleWithIdentifierWithHint(CFStringRef bundleID, void *pointer) {
 603      return _CFBundleGetBundleWithIdentifier(bundleID, pointer);
 604  }
 605  
 606  static CFStringRef __CFBundleCopyDescription(CFTypeRef cf) {
 607      char buff[CFMaxPathSize];
 608      CFStringRef path = NULL, binaryType = NULL, retval = NULL;
 609      if (((CFBundleRef)cf)->_url && CFURLGetFileSystemRepresentation(((CFBundleRef)cf)->_url, true, (uint8_t *)buff, CFMaxPathSize)) path = CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault, buff);
 610      switch (((CFBundleRef)cf)->_binaryType) {
 611          case __CFBundleCFMBinary:
 612              binaryType = CFSTR("");
 613              break;
 614          case __CFBundleDYLDExecutableBinary:
 615              binaryType = CFSTR("executable, ");
 616              break;
 617          case __CFBundleDYLDBundleBinary:
 618              binaryType = CFSTR("bundle, ");
 619              break;
 620          case __CFBundleDYLDFrameworkBinary:
 621              binaryType = CFSTR("framework, ");
 622              break;
 623          case __CFBundleDLLBinary:
 624              binaryType = CFSTR("DLL, ");
 625              break;
 626          case __CFBundleUnreadableBinary:
 627              binaryType = CFSTR("");
 628              break;
 629          default:
 630              binaryType = CFSTR("");
 631              break;
 632      }
 633      if (((CFBundleRef)cf)->_plugInData._isPlugIn) {
 634          retval = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("CFBundle/CFPlugIn %p <%@> (%@%@loaded)"), cf, path, binaryType, ((CFBundleRef)cf)->_isLoaded ? CFSTR("") : CFSTR("not "));
 635      } else {
 636          retval = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("CFBundle %p <%@> (%@%@loaded)"), cf, path, binaryType, ((CFBundleRef)cf)->_isLoaded ? CFSTR("") : CFSTR("not "));
 637      }
 638      if (path) CFRelease(path);
 639      return retval;
 640  }
 641  
 642  static void __CFBundleDeallocate(CFTypeRef cf) {
 643      CFBundleRef bundle = (CFBundleRef)cf;
 644      CFURLRef bundleURL;
 645      CFStringRef bundleID = NULL;
 646      
 647      __CFGenericValidateType(cf, CFBundleGetTypeID());
 648      bundleURL = bundle->_url;
 649      bundle->_url = NULL;
 650      if (bundle->_infoDict) bundleID = (CFStringRef)CFDictionaryGetValue(bundle->_infoDict, kCFBundleIdentifierKey);
 651      _CFBundleRemoveFromTables(bundle, bundleURL, bundleID);
 652      CFBundleUnloadExecutable(bundle);
 653      _CFBundleDeallocatePlugIn(bundle);    
 654      if (bundleURL) {
 655          CFRelease(bundleURL);
 656      }
 657      if (bundle->_infoDict) CFRelease(bundle->_infoDict);
 658      if (bundle->_localInfoDict) CFRelease(bundle->_localInfoDict);
 659      if (bundle->_searchLanguages) CFRelease(bundle->_searchLanguages);
 660      if (bundle->_executablePath) CFRelease(bundle->_executablePath);
 661      if (bundle->_developmentRegion) CFRelease(bundle->_developmentRegion);
 662      if (bundle->_infoPlistUrl) CFRelease(bundle->_infoPlistUrl);
 663      if (bundle->_stringTable) CFRelease(bundle->_stringTable);
 664      if (bundle->_bundleBasePath) CFRelease(bundle->_bundleBasePath);
 665      if (bundle->_queryTable) CFRelease(bundle->_queryTable);
 666      
 667      if (bundle->_localizations) CFRelease(bundle->_localizations);
 668      if (bundle->_resourceDirectoryContents) CFRelease(bundle->_resourceDirectoryContents);
 669      
 670      if (bundle->_additionalResourceBundles) CFRelease(bundle->_additionalResourceBundles);
 671      
 672      _CFMutexDestroy(&(bundle->_bundleLoadingLock));
 673  }
 674  
 675  const CFRuntimeClass __CFBundleClass = {
 676      _kCFRuntimeScannedObject,
 677      "CFBundle",
 678      NULL,      // init
 679      NULL,      // copy
 680      __CFBundleDeallocate,
 681      NULL,      // equal
 682      NULL,      // hash
 683      NULL,      // 
 684      __CFBundleCopyDescription
 685  };
 686  
 687  CFTypeID CFBundleGetTypeID(void) {
 688      return _kCFRuntimeIDCFBundle;
 689  }
 690  
 691  // TODO: Remove this SPI, it appears no one is using it
 692  // <rdar://problem/30925651> Remove _CFBundleGetExistingBundleWithBundleURL
 693  CFBundleRef _CFBundleGetExistingBundleWithBundleURL(CFURLRef bundleURL) {
 694      CFBundleRef bundle = NULL;
 695      char buff[CFMaxPathSize];
 696      CFURLRef newURL = NULL;
 697      
 698      if (!CFURLGetFileSystemRepresentation(bundleURL, true, (uint8_t *)buff, CFMaxPathSize)) return NULL;
 699      
 700      newURL = CFURLCreateFromFileSystemRepresentation(kCFAllocatorSystemDefault, (uint8_t *)buff, strlen(buff), true);
 701      if (!newURL) newURL = (CFURLRef)CFRetain(bundleURL);
 702      
 703      // First check the main bundle; otherwise fallback to the other tables
 704      CFBundleRef main = CFBundleGetMainBundle();
 705      if (main->_url && newURL && CFEqual(main->_url, newURL)) {
 706          CFRelease(newURL);
 707          return main;
 708      }
 709  
 710      bundle = _CFBundleCopyFromTablesForURL(newURL);
 711      if (bundle) CFRelease(bundle);
 712      CFRelease(newURL);
 713      return bundle;
 714  }
 715  
 716  static Boolean _CFBundlesHaveEquivalentURL(CFBundleRef b1, CFBundleRef b2) {
 717      CFStringRef path1 = b1->_bundleBasePath;
 718      CFStringRef path2 = b2->_bundleBasePath;
 719      char path1CString[PATH_MAX];
 720      char path2CString[PATH_MAX];
 721  
 722      Boolean result = false;
 723      if (CFStringGetFileSystemRepresentation(path1, path1CString, PATH_MAX) &&
 724          CFStringGetFileSystemRepresentation(path2, path2CString, PATH_MAX)) {
 725          int fd1 = open(path1CString, O_RDONLY);
 726          int fd2 = open(path2CString, O_RDONLY);
 727  
 728          if (fd1 > 0 && fd2 > 0) {
 729              struct stat statbuf1;
 730              struct stat statbuf2;
 731              
 732              if (fstat(fd1, &statbuf1) == 0 &&
 733                  fstat(fd2, &statbuf2) == 0 &&
 734                  statbuf1.st_dev == statbuf2.st_dev &&
 735                  statbuf1.st_ino == statbuf2.st_ino)
 736              {
 737                      result = true;
 738              }
 739          }
 740          
 741          if (fd1 > 0) close(fd1);
 742          if (fd2 > 0) close(fd2);
 743      }
 744      
 745      return result;
 746  }
 747  
 748  /*
 749   The combinations of boolean arguments to this function are as follows:
 750   
 751   doFinal | unique | addToTables
 752   ------- | ------ | -----------
 753   true      false    true            // CFBundleCreate
 754   true      true     false           // _CFBundleCreateUnique
 755   false     false    false           // _CFBundleCreateMain
 756   false     false    true            // _CFBundleEnsureBundleExistsForImagePath
 757   
 758   n.b.
 759   (unique && addToTables) is an invalid configuration and this function will assert.
 760   (unique && doFinalProcessing) does nothing but there is no assert; doFinalProcessing is ignored
 761      This is because doFinalProcessing is primarily about initializing plugins, but unique bundles cannot be plugins.
 762   
 763   */
 764  static CFBundleRef _CFBundleCreate(CFAllocatorRef allocator, CFURLRef bundleURL, Boolean doFinalProcessing, Boolean unique, Boolean addToTables) {
 765      char buff[CFMaxPathSize];
 766      CFURLRef newURL = NULL;
 767      if (!CFURLGetFileSystemRepresentation(bundleURL, true, (uint8_t *)buff, CFMaxPathSize)) return NULL;
 768      newURL = CFURLCreateFromFileSystemRepresentation(allocator, (uint8_t *)buff, strlen(buff), true);
 769      if (!newURL) newURL = (CFURLRef)CFRetain(bundleURL);
 770      
 771      // Don't go searching for the URL in the tables if the bundle is unique or the main bundle (addToTables == false)
 772      if (!unique && addToTables) {
 773          CFBundleRef existingBundle = _CFBundleCopyFromTablesForURL(newURL);
 774          if (existingBundle) {
 775              CFRelease(newURL);
 776              return existingBundle;
 777          }
 778      }
 779      
 780      
 781      // This section of _CFBundleCreate touches the disk, so it should be done outside the lock. This avoids blocking threads which are just attempting to get an existing bundle on file system access, potentially from a lower-piority thread.
 782      _CFBundleVersion localVersion = _CFBundleGetBundleVersionForURL(newURL);
 783      if (_CFBundleVersionFlat == localVersion) {
 784          Boolean exists = false;
 785          SInt32 mode = 0;
 786          SInt32 res = _CFGetPathProperties(allocator, (char *)buff, &exists, &mode, NULL, NULL, NULL, NULL);
 787  #if DEPLOYMENT_RUNTIME_OBJC && TARGET_OS_WIN32
 788          if (!(res == 0 && exists && ((mode & S_IFMT) == S_IFDIR))) {
 789              // 2nd chance at finding a bundle path - remove the last path component (e.g., mybundle.resources) and try again
 790              CFURLRef shorterPath = CFURLCreateCopyDeletingLastPathComponent(allocator, newURL);
 791              CFRelease(newURL);
 792              newURL = shorterPath;
 793              res = _CFGetFileProperties(allocator, newURL, &exists, &mode, NULL, NULL, NULL, NULL);
 794          }
 795  #endif
 796          if (res == 0) {
 797              if (!exists || ((mode & S_IFMT) != S_IFDIR)) {
 798                  CFRelease(newURL);
 799                  return NULL;
 800              }
 801          } else {
 802              CFRelease(newURL);
 803              return NULL;
 804          }
 805      }
 806  
 807      CFBundleRef bundle = (CFBundleRef)_CFRuntimeCreateInstance(allocator, CFBundleGetTypeID(), sizeof(struct __CFBundle) - sizeof(CFRuntimeBase), NULL);
 808      if (!bundle) {
 809          CFRelease(newURL);
 810          return NULL;
 811      }
 812  
 813      bundle->_url = newURL;
 814      
 815  #if !DEPLOYMENT_RUNTIME_OBJC && !TARGET_OS_WIN32 && !TARGET_OS_ANDROID
 816      bundle->_isFHSInstalledBundle = _CFBundleURLIsForFHSInstalledBundle(newURL);
 817  #endif
 818  
 819      bundle->_version = localVersion;
 820  
 821  #if defined(BINARY_SUPPORT_DYLD)
 822      /* We'll have to figure it out later */
 823      bundle->_binaryType = __CFBundleUnknownBinary;
 824  #elif defined(BINARY_SUPPORT_DLL)
 825      /* We support DLL only */
 826      bundle->_binaryType = __CFBundleDLLBinary;
 827  #else
 828      /* We'll have to figure it out later */
 829      bundle->_binaryType = __CFBundleUnknownBinary;
 830  #endif /* BINARY_SUPPORT_DYLD */
 831  
 832      bundle->_isUnique = unique;
 833      
 834  #if TARGET_OS_OSX
 835      if (!__CFgetenv("CFBundleDisableStringsSharing") && 
 836          (strncmp(buff, "/System/Library/Frameworks", 26) == 0) && 
 837          (strncmp(buff + strlen(buff) - 10, ".framework", 10) == 0)) bundle->_sharesStringsFiles = true;
 838  #endif
 839  
 840      _CFMutexCreate(&(bundle->_bundleLoadingLock));
 841  
 842      bundle->_lock = CFLockInit;
 843      bundle->_queryLock = CFLockInit;
 844  
 845      CFURLRef absoURL = CFURLCopyAbsoluteURL(bundle->_url);
 846      bundle->_bundleBasePath = CFURLCopyFileSystemPath(absoURL, PLATFORM_PATH_STYLE);
 847      CFRelease(absoURL);
 848      
 849      bundle->_additionalResourceLock = CFLockInit;
 850      
 851      CFDictionaryRef infoDict = CFBundleGetInfoDictionary(bundle);
 852      CFStringRef bundleID = CFBundleGetIdentifier(bundle);
 853  
 854      // Do this so that we can use the dispatch_once on the ivar of this bundle safely
 855  #pragma GCC diagnostic push
 856  #pragma GCC diagnostic ignored "-Wdeprecated"
 857      OSMemoryBarrier();
 858  #pragma GCC diagnostic pop
 859  
 860      // We cannot add to tables for unique bundles. Return unique bundle results here without heading into the section below where we take a lock.
 861      if (unique) {
 862          assert(!addToTables);
 863          return bundle;
 864      }
 865      
 866      // Locked after here for the global tables
 867      _CFMutexLock(&CFBundleGlobalDataLock);
 868      
 869      // Check to see if we already have a bundle with the same identifier or URL. Someone may have raced us to this point.
 870      CFBundleRef existingBundleWithSameURL = _CFBundleCopyFromTablesForURLLocked(bundle->_url);
 871      if (existingBundleWithSameURL) {
 872          // Deallocating a bundle takes the lock when _useUnsafeUnretainedTables returns true, so release the lock first.
 873          _CFMutexUnlock(&CFBundleGlobalDataLock);
 874          CFRelease(bundle);
 875  
 876          return existingBundleWithSameURL;
 877      }
 878      
 879      // It's unfortunate, but valid, for two different bundles to have the same identifier. However, if they also have the same URL (resolving symlinks), then we can return the original one because they are really the same bundle after all.
 880      CFBundleRef existingBundleWithSameIdentifier = _CFBundleGetFromTablesLocked(bundleID);
 881      if (existingBundleWithSameIdentifier && _CFBundlesHaveEquivalentURL(bundle, existingBundleWithSameIdentifier)) {
 882          // Deallocating a bundle takes the lock when _useUnsafeUnretainedTables returns true, so release the lock first.
 883          _CFMutexUnlock(&CFBundleGlobalDataLock);
 884          CFRelease(bundle);
 885          return (CFBundleRef)CFRetain(existingBundleWithSameIdentifier);
 886      }
 887      
 888      if (doFinalProcessing) {
 889          // Initializing the tables for the list of plugins and initializing the tables for the list of bundles are inherently tied together, because plugins have references back to bundles.
 890          // In order to preserve safety, we take both locks. Always in the order of CFBundleGlobalDataLock -> CFPlugInGlobalDataLock.
 891  
 892          // We have to do this before adding the bundle to the tables, otherwise another thread coming along and fetching the bundle will get the bundle ref but the factories for PlugIn have not yet been registered.
 893          CFBundleRef duplicateFactoryBundle = NULL;
 894          if (!_CFBundleInitPlugIn(bundle, infoDict, &duplicateFactoryBundle)) {
 895              // At this point the most likely explanation is that we have the same factory ID but two different bundles. There is no way to really proceed safely here because the plugin system can only deal with one factory ID -> bundle pairing.
 896              // Get some info for error logging
 897              CFDictionaryRef factoryDict = (CFDictionaryRef)CFDictionaryGetValue(infoDict, kCFPlugInFactoriesKey);
 898              if (factoryDict && CFGetTypeID(factoryDict) != CFDictionaryGetTypeID()) factoryDict = NULL;
 899              os_log_error(_CFBundleLoadingLogger(), "More than one bundle with the same factory UUID detected: %{public}@ in %{public}@ and %{public}@", factoryDict, bundle, duplicateFactoryBundle);
 900  
 901              // Deallocating a bundle takes the lock when _useUnsafeUnretainedTables returns true, so release the lock first.
 902              _CFMutexUnlock(&CFBundleGlobalDataLock);
 903  
 904              // Release the allocated instance
 905              CFRelease(bundle);
 906  
 907              // Release the duplicate factory bundle
 908              if (duplicateFactoryBundle) CFRelease(duplicateFactoryBundle);
 909              return NULL;            
 910          }
 911      }
 912      
 913      if (addToTables) {
 914          _CFBundleAddToTablesLocked(bundle, bundleID);
 915      }
 916      
 917      _CFMutexUnlock(&CFBundleGlobalDataLock);
 918  
 919      if (doFinalProcessing) {
 920          // Outside of the lock, handle dynamic registration
 921          _CFPlugInHandleDynamicRegistration(bundle);
 922          
 923      }
 924  
 925      return bundle;
 926  }
 927  
 928  CFBundleRef CFBundleCreate(CFAllocatorRef allocator, CFURLRef bundleURL) {
 929      if (NULL == bundleURL) return NULL;
 930  
 931      // _CFBundleCreate doesn't know about the main bundle, so we have to check that first. If the URL passed in is the same as the main bundle, then we'll need to return that bundle first.
 932      // Result will be nil if the bundleURL passed in happened to have been the main bundle.
 933      // As a fallback, check now to see if the main bundle URL is equal to bundleURL. If so, return that bundle instead of nil (32988858).
 934      CFBundleRef main = CFBundleGetMainBundle();
 935      if (main && main->_url && CFEqual(main->_url, bundleURL)) {
 936          CFRetain(main);
 937          return main;
 938      }
 939  
 940      return _CFBundleCreate(allocator, bundleURL, true, false, true);
 941  }
 942  
 943  CFBundleRef _CFBundleCreateUnique(CFAllocatorRef allocator, CFURLRef bundleURL) {
 944      // This function can never return an existing CFBundleRef object.
 945      return _CFBundleCreate(allocator, bundleURL, true, true, false);
 946  }
 947  
 948  CF_PRIVATE CFBundleRef _CFBundleCreateMain(CFAllocatorRef allocator, CFURLRef mainBundleURL) {
 949      // Do not add the main bundle to tables
 950      return _CFBundleCreate(allocator, mainBundleURL, false, false, false);
 951  }
 952  
 953  CFArrayRef CFBundleCreateBundlesFromDirectory(CFAllocatorRef alloc, CFURLRef directoryURL, CFStringRef bundleType) {
 954      CFMutableArrayRef bundles = CFArrayCreateMutable(alloc, 0, &kCFTypeArrayCallBacks);
 955      CFArrayRef URLs = _CFCreateContentsOfDirectory(alloc, NULL, NULL, directoryURL, bundleType);
 956      if (URLs) {
 957          CFIndex c = CFArrayGetCount(URLs);
 958          CFURLRef curURL;
 959          CFBundleRef curBundle;
 960  
 961          for (CFIndex i = 0; i < c; i++) {
 962              curURL = (CFURLRef)CFArrayGetValueAtIndex(URLs, i);
 963              curBundle = CFBundleCreate(alloc, curURL);
 964              if (curBundle) {
 965                  CFArrayAppendValue(bundles, curBundle);
 966  #ifdef __clang_analyzer__
 967                  // The contract of this function is that the bundles created inside here are 'not released'.
 968                  CFRelease(curBundle);
 969  #endif
 970              }
 971          }
 972          CFRelease(URLs);
 973      }
 974  
 975      return bundles;
 976  }
 977  
 978  CFURLRef CFBundleCopyBundleURL(CFBundleRef bundle) {
 979      CF_ASSERT_TYPE(_kCFRuntimeIDCFBundle, bundle);
 980      if (bundle->_url) CFRetain(bundle->_url);
 981      return bundle->_url;
 982  }
 983  
 984  UInt32 CFBundleGetVersionNumber(CFBundleRef bundle) {
 985      CFDictionaryRef infoDict = CFBundleGetInfoDictionary(bundle);
 986      CFNumberRef versionValue = (CFNumberRef)CFDictionaryGetValue(infoDict, _kCFBundleNumericVersionKey);
 987      if (!versionValue || CFGetTypeID(versionValue) != CFNumberGetTypeID()) return 0;
 988      
 989      UInt32 vers = 0;
 990      CFNumberGetValue(versionValue, kCFNumberSInt32Type, &vers);
 991      return vers;
 992  }
 993  
 994  CFStringRef CFBundleGetDevelopmentRegion(CFBundleRef bundle) {
 995      CF_ASSERT_TYPE(_kCFRuntimeIDCFBundle, bundle);
 996      dispatch_once(&bundle->_developmentRegionCalculated, ^{
 997          CFStringRef devRegion = NULL;
 998          CFDictionaryRef infoDict = CFBundleGetInfoDictionary(bundle);
 999          if (infoDict) {
1000              devRegion = (CFStringRef)CFDictionaryGetValue(infoDict, kCFBundleDevelopmentRegionKey);
1001              if (devRegion && (CFGetTypeID(devRegion) != CFStringGetTypeID() || CFStringGetLength(devRegion) == 0)) {
1002                  devRegion = NULL;
1003              }
1004          }
1005          
1006          if (devRegion) bundle->_developmentRegion = (CFStringRef)CFRetain(devRegion);
1007      });
1008      return bundle->_developmentRegion;
1009  }
1010  
1011  Boolean _CFBundleGetHasChanged(CFBundleRef bundle) {
1012      // This SPI isn't very useful, so now we just return true (30211007)
1013      return true;
1014  }
1015  
1016  void _CFBundleSetStringsFilesShared(CFBundleRef bundle, Boolean flag) {
1017      bundle->_sharesStringsFiles = flag;
1018  }
1019  
1020  Boolean _CFBundleGetStringsFilesShared(CFBundleRef bundle) {
1021      return bundle->_sharesStringsFiles;
1022  }
1023  
1024  CF_EXPORT CFURLRef CFBundleCopySupportFilesDirectoryURL(CFBundleRef bundle) {
1025      CF_ASSERT_TYPE(_kCFRuntimeIDCFBundle, bundle);
1026      CFURLRef bundleURL = bundle->_url;
1027      _CFBundleVersion version = bundle->_version;
1028      CFURLRef result = NULL;
1029      if (bundleURL) {
1030          if (_CFBundleVersionOldStyleSupportFiles == version) {
1031              result = CFURLCreateWithString(kCFAllocatorSystemDefault, _CFBundleSupportFilesURLFromBase1, bundleURL);
1032          } else if (_CFBundleVersionContentsResources == version) {
1033              result = CFURLCreateWithString(kCFAllocatorSystemDefault, _CFBundleSupportFilesURLFromBase2, bundleURL);
1034          } else if (_CFBundleVersionWrappedContentsResources == version) {
1035              result = _CFURLCreateResolvedDirectoryWithString(kCFAllocatorSystemDefault, _CFBundleWrappedSupportFilesURLFromBase2, bundleURL);
1036          } else if (_CFBundleVersionWrappedFlat == version) {
1037              result = _CFURLCreateResolvedDirectoryWithString(kCFAllocatorSystemDefault, _CFBundleWrappedSupportFilesURLFromBase3, bundleURL);
1038          } else {
1039              result = (CFURLRef)CFRetain(bundleURL);
1040          }
1041      }
1042      return result;
1043  }
1044  
1045  CF_PRIVATE CFURLRef _CFBundleCopyResourcesDirectoryURLInDirectory(CFURLRef bundleURL, _CFBundleVersion version) {
1046      CFURLRef result = NULL;
1047      if (bundleURL) {
1048          if (_CFBundleVersionOldStyleResources == version) {
1049              result = CFURLCreateWithString(kCFAllocatorSystemDefault, _CFBundleResourcesURLFromBase0, bundleURL);
1050          } else if (_CFBundleVersionOldStyleSupportFiles == version) {
1051              result = CFURLCreateWithString(kCFAllocatorSystemDefault, _CFBundleResourcesURLFromBase1, bundleURL);
1052          } else if (_CFBundleVersionContentsResources == version) {
1053              result = CFURLCreateWithString(kCFAllocatorSystemDefault, _CFBundleResourcesURLFromBase2, bundleURL);
1054          } else if (_CFBundleVersionWrappedContentsResources == version) {
1055              result = _CFURLCreateResolvedDirectoryWithString(kCFAllocatorSystemDefault, _CFBundleWrappedResourcesURLFromBase2, bundleURL);
1056          } else if (_CFBundleVersionWrappedFlat == version) {
1057              result = _CFURLCreateResolvedDirectoryWithString(kCFAllocatorSystemDefault, _CFBundleWrappedResourcesURLFromBase3, bundleURL);
1058          } else {
1059              result = (CFURLRef)CFRetain(bundleURL);
1060          }
1061      }
1062      return result;
1063  }
1064  
1065  CF_EXPORT CFURLRef CFBundleCopyResourcesDirectoryURL(CFBundleRef bundle) {
1066      CF_ASSERT_TYPE(_kCFRuntimeIDCFBundle, bundle);
1067      return _CFBundleCopyResourcesDirectoryURLInDirectory(bundle->_url, bundle->_version);
1068  }
1069  
1070  CF_PRIVATE CFURLRef _CFBundleCopyAppStoreReceiptURLInDirectory(CFURLRef bundleURL, _CFBundleVersion version) {
1071      CFURLRef result = NULL;
1072      if (bundleURL) {
1073          if (_CFBundleVersionOldStyleResources == version) {
1074              result = CFURLCreateWithString(kCFAllocatorSystemDefault, _CFBundleAppStoreReceiptURLFromBase0, bundleURL);
1075          } else if (_CFBundleVersionOldStyleSupportFiles == version) {
1076              result = CFURLCreateWithString(kCFAllocatorSystemDefault, _CFBundleAppStoreReceiptURLFromBase1, bundleURL);
1077          } else if (_CFBundleVersionContentsResources == version) {
1078              result = CFURLCreateWithString(kCFAllocatorSystemDefault, _CFBundleAppStoreReceiptURLFromBase2, bundleURL);
1079          } else if (_CFBundleVersionFlat == version) {
1080              result = CFURLCreateWithString(kCFAllocatorSystemDefault, _CFBundleAppStoreReceiptURLFromBase0, bundleURL);
1081          } else if (_CFBundleVersionWrappedContentsResources == version) {
1082              result = CFURLCreateWithString(kCFAllocatorSystemDefault, _CFBundleWrappedAppStoreReceiptURLFromBase2, bundleURL);
1083          } else if (_CFBundleVersionWrappedFlat == version) {
1084              result = CFURLCreateWithString(kCFAllocatorSystemDefault, _CFBundleWrappedAppStoreReceiptURLFromBase3, bundleURL);
1085          }
1086      }
1087      return result;
1088  }
1089  
1090  CFURLRef _CFBundleCopyAppStoreReceiptURL(CFBundleRef bundle) {
1091      return _CFBundleCopyAppStoreReceiptURLInDirectory(bundle->_url, bundle->_version);
1092  }
1093  
1094  CF_EXPORT CFURLRef _CFBundleCopyWrappedBundleURL(CFBundleRef bundle) {
1095      CF_ASSERT_TYPE(_kCFRuntimeIDCFBundle, bundle);
1096      _CFBundleVersion version = bundle->_version;
1097      if (version == _CFBundleVersionWrappedContentsResources || version == _CFBundleVersionWrappedFlat) {
1098          return _CFURLCreateResolvedDirectoryWithString(kCFAllocatorSystemDefault, _CFBundleWrapperLinkName, bundle->_url);
1099      } else {
1100          return NULL;
1101      }
1102  }
1103  
1104  CF_EXPORT CFURLRef _CFBundleCopyWrapperContainerURL(CFBundleRef bundle) {
1105      CF_ASSERT_TYPE(_kCFRuntimeIDCFBundle, bundle);
1106      _CFBundleVersion version = bundle->_version;
1107      if (version == _CFBundleVersionWrappedContentsResources || version == _CFBundleVersionWrappedFlat) {
1108          // This is a directory, not a symlink
1109          return CFURLCreateWithString(kCFAllocatorSystemDefault, _CFBundleWrapperDirectoryName, bundle->_url);
1110      } else {
1111          return NULL;
1112      }
1113  }
1114  
1115  CF_CROSS_PLATFORM_EXPORT CFStringRef _CFBundleCopyExecutablePath(CFBundleRef bundle) {
1116      return _CFBundleCopyExecutableName(bundle, NULL, NULL);
1117  }
1118  
1119  CF_PRIVATE CFStringRef _CFBundleCopyExecutableName(CFBundleRef bundle, CFURLRef url, CFDictionaryRef infoDict) {
1120      CFStringRef executableName = NULL;
1121      
1122      if (!infoDict && bundle) infoDict = CFBundleGetInfoDictionary(bundle);
1123      if (!url && bundle) url = bundle->_url;
1124      
1125      if (infoDict) {
1126          // Figure out the name of the executable.
1127          // First try for the new key in the plist.
1128          executableName = (CFStringRef)CFDictionaryGetValue(infoDict, kCFBundleExecutableKey);
1129          // Second try for the old key in the plist.
1130          if (!executableName) executableName = (CFStringRef)CFDictionaryGetValue(infoDict, _kCFBundleOldExecutableKey);
1131          if (executableName && CFGetTypeID(executableName) == CFStringGetTypeID() && CFStringGetLength(executableName) > 0) {
1132              CFRetain(executableName);
1133          } else {
1134              executableName = NULL;
1135          }
1136      }
1137      if (!executableName && url) {
1138          // Third, take the name of the bundle itself (with path extension stripped)
1139          CFURLRef absoluteURL = CFURLCopyAbsoluteURL(url);
1140          CFStringRef bundlePath = CFURLCopyFileSystemPath(absoluteURL, PLATFORM_PATH_STYLE);
1141          CFRelease(absoluteURL);
1142          if (bundlePath) {
1143              CFIndex len = CFStringGetLength(bundlePath);
1144              CFIndex startOfBundleName = _CFStartOfLastPathComponent2(bundlePath);
1145              CFIndex endOfBundleName = _CFLengthAfterDeletingPathExtension2(bundlePath);
1146              
1147              if (startOfBundleName <= len && endOfBundleName <= len && startOfBundleName < endOfBundleName) {
1148                  executableName = CFStringCreateWithSubstring(kCFAllocatorSystemDefault, bundlePath, CFRangeMake(startOfBundleName, endOfBundleName - startOfBundleName));
1149              }
1150              CFRelease(bundlePath);
1151          }
1152      }
1153      
1154      return executableName;
1155  }
1156  
1157  Boolean CFBundleIsExecutableLoaded(CFBundleRef bundle) {
1158      CF_ASSERT_TYPE(_kCFRuntimeIDCFBundle, bundle);
1159      return bundle->_isLoaded;
1160  }
1161  
1162  CFBundleExecutableType CFBundleGetExecutableType(CFBundleRef bundle) {
1163      CF_ASSERT_TYPE(_kCFRuntimeIDCFBundle, bundle);
1164      CFBundleExecutableType result = kCFBundleOtherExecutableType;
1165      CFURLRef executableURL = CFBundleCopyExecutableURL(bundle);
1166  
1167      if (!executableURL) bundle->_binaryType = __CFBundleNoBinary;
1168  #if defined(BINARY_SUPPORT_DYLD)
1169      if (bundle->_binaryType == __CFBundleUnknownBinary) {
1170          bundle->_binaryType = _CFBundleGrokBinaryType(executableURL);
1171          if (bundle->_binaryType != __CFBundleCFMBinary && bundle->_binaryType != __CFBundleUnreadableBinary) bundle->_resourceData._executableLacksResourceFork = true;
1172      }
1173  #endif /* BINARY_SUPPORT_DYLD */
1174      if (executableURL) CFRelease(executableURL);
1175  
1176      if (bundle->_binaryType == __CFBundleCFMBinary) {
1177          result = kCFBundlePEFExecutableType;
1178      } else if (bundle->_binaryType == __CFBundleDYLDExecutableBinary || bundle->_binaryType == __CFBundleDYLDBundleBinary || bundle->_binaryType == __CFBundleDYLDFrameworkBinary) {
1179          result = kCFBundleMachOExecutableType;
1180      } else if (bundle->_binaryType == __CFBundleDLLBinary) {
1181          result = kCFBundleDLLExecutableType;
1182      } else if (bundle->_binaryType == __CFBundleELFBinary) {
1183          result = kCFBundleELFExecutableType;    
1184      }
1185      return result;
1186  }
1187  
1188  void _CFBundleSetCFMConnectionID(CFBundleRef bundle, void *connectionID) {
1189      bundle->_connectionCookie = connectionID;
1190      bundle->_isLoaded = true;
1191  }
1192  
1193  static CFStringRef _CFBundleCopyLastPathComponent(CFBundleRef bundle) {
1194      CFURLRef bundleURL = CFBundleCopyBundleURL(bundle);
1195      if (!bundleURL) {
1196          return CFSTR("<unknown>");
1197      }
1198      CFStringRef str = CFURLCopyFileSystemPath(bundleURL, kCFURLPOSIXPathStyle);
1199      UniChar buff[CFMaxPathSize];
1200      CFIndex buffLen = CFStringGetLength(str), startOfLastDir = 0;
1201  
1202      CFRelease(bundleURL);
1203      if (buffLen > CFMaxPathSize) buffLen = CFMaxPathSize;
1204      CFStringGetCharacters(str, CFRangeMake(0, buffLen), buff);
1205      CFRelease(str);
1206      if (buffLen > 0) startOfLastDir = _CFStartOfLastPathComponent(buff, buffLen);
1207      return CFStringCreateWithCharacters(kCFAllocatorSystemDefault, &(buff[startOfLastDir]), buffLen - startOfLastDir);
1208  }
1209  
1210  #pragma mark -
1211  
1212  CF_PRIVATE CFErrorRef _CFBundleCreateErrorDebug(CFAllocatorRef allocator, CFBundleRef bundle, CFIndex code, CFStringRef debugString) {
1213      const void *userInfoKeys[6], *userInfoValues[6];
1214      CFIndex numKeys = 0;
1215      CFURLRef bundleURL = CFBundleCopyBundleURL(bundle), absoluteURL = CFURLCopyAbsoluteURL(bundleURL), executableURL = CFBundleCopyExecutableURL(bundle);
1216      CFBundleRef bdl = CFBundleGetBundleWithIdentifier(CFSTR("com.apple.CoreFoundation"));
1217      CFStringRef bundlePath = CFURLCopyFileSystemPath(absoluteURL, PLATFORM_PATH_STYLE), executablePath = executableURL ? CFURLCopyFileSystemPath(executableURL, PLATFORM_PATH_STYLE) : NULL, descFormat = NULL, desc = NULL, reason = NULL, suggestion = NULL;
1218      CFErrorRef error;
1219      if (bdl) {
1220          CFStringRef name = (CFStringRef)CFBundleGetValueForInfoDictionaryKey(bundle, kCFBundleNameKey);
1221          name = name ? (CFStringRef)CFRetain(name) : _CFBundleCopyLastPathComponent(bundle);
1222          if (CFBundleExecutableNotFoundError == code) {
1223              descFormat = CFCopyLocalizedStringWithDefaultValue(CFSTR("BundleErr4"), CFSTR("Error"), bdl, CFSTR("The bundle \\U201c%@\\U201d couldn\\U2019t be loaded because its executable couldn\\U2019t be located."), "NSFileNoSuchFileError");
1224              reason = CFCopyLocalizedStringWithDefaultValue(CFSTR("BundleErr4-C"), CFSTR("Error"), bdl, CFSTR("The bundle\\U2019s executable couldn\\U2019t be located."), "NSFileNoSuchFileError");
1225              suggestion = CFCopyLocalizedStringWithDefaultValue(CFSTR("BundleErr4-R"), CFSTR("Error"), bdl, CFSTR("Try reinstalling the bundle."), "NSFileNoSuchFileError");
1226          } else if (CFBundleExecutableNotLoadableError == code) {
1227              descFormat = CFCopyLocalizedStringWithDefaultValue(CFSTR("BundleErr3584"), CFSTR("Error"), bdl, CFSTR("The bundle \\U201c%@\\U201d couldn\\U2019t be loaded because its executable isn\\U2019t loadable."), "NSExecutableNotLoadableError");
1228              reason = CFCopyLocalizedStringWithDefaultValue(CFSTR("BundleErr3584-C"), CFSTR("Error"), bdl, CFSTR("The bundle\\U2019s executable isn\\U2019t loadable."), "NSExecutableNotLoadableError");
1229              suggestion = CFCopyLocalizedStringWithDefaultValue(CFSTR("BundleErr3584-R"), CFSTR("Error"), bdl, CFSTR("Try reinstalling the bundle."), "NSExecutableNotLoadableError");
1230          } else if (CFBundleExecutableArchitectureMismatchError == code) {
1231              descFormat = CFCopyLocalizedStringWithDefaultValue(CFSTR("BundleErr3585"), CFSTR("Error"), bdl, CFSTR("The bundle \\U201c%@\\U201d couldn\\U2019t be loaded because it doesn\\U2019t contain a version for the current architecture."), "NSExecutableArchitectureMismatchError");
1232              reason = CFCopyLocalizedStringWithDefaultValue(CFSTR("BundleErr3585-C"), CFSTR("Error"), bdl, CFSTR("The bundle doesn\\U2019t contain a version for the current architecture."), "NSExecutableArchitectureMismatchError");
1233              suggestion = CFCopyLocalizedStringWithDefaultValue(CFSTR("BundleErr3585-R"), CFSTR("Error"), bdl, CFSTR("Try installing a universal version of the bundle."), "NSExecutableArchitectureMismatchError");
1234          } else if (CFBundleExecutableRuntimeMismatchError == code) {
1235              descFormat = CFCopyLocalizedStringWithDefaultValue(CFSTR("BundleErr3586"), CFSTR("Error"), bdl, CFSTR("The bundle \\U201c%@\\U201d couldn\\U2019t be loaded because it isn\\U2019t compatible with the current application."), "NSExecutableRuntimeMismatchError");
1236              reason = CFCopyLocalizedStringWithDefaultValue(CFSTR("BundleErr3586-C"), CFSTR("Error"), bdl, CFSTR("The bundle isn\\U2019t compatible with this application."), "NSExecutableRuntimeMismatchError");
1237              suggestion = CFCopyLocalizedStringWithDefaultValue(CFSTR("BundleErr3586-R"), CFSTR("Error"), bdl, CFSTR("Try installing a newer version of the bundle."), "NSExecutableRuntimeMismatchError");
1238          } else if (CFBundleExecutableLoadError == code) {
1239              descFormat = CFCopyLocalizedStringWithDefaultValue(CFSTR("BundleErr3587"), CFSTR("Error"), bdl, CFSTR("The bundle \\U201c%@\\U201d couldn\\U2019t be loaded because it is damaged or missing necessary resources."), "NSExecutableLoadError");
1240              reason = CFCopyLocalizedStringWithDefaultValue(CFSTR("BundleErr3587-C"), CFSTR("Error"), bdl, CFSTR("The bundle is damaged or missing necessary resources."), "NSExecutableLoadError");
1241              suggestion = CFCopyLocalizedStringWithDefaultValue(CFSTR("BundleErr3587-R"), CFSTR("Error"), bdl, CFSTR("Try reinstalling the bundle."), "NSExecutableLoadError");
1242          } else if (CFBundleExecutableLinkError == code) {
1243              descFormat = CFCopyLocalizedStringWithDefaultValue(CFSTR("BundleErr3588"), CFSTR("Error"), bdl, CFSTR("The bundle \\U201c%@\\U201d couldn\\U2019t be loaded."), "NSExecutableLinkError");
1244              reason = CFCopyLocalizedStringWithDefaultValue(CFSTR("BundleErr3588-C"), CFSTR("Error"), bdl, CFSTR("The bundle couldn\\U2019t be loaded."), "NSExecutableLinkError");
1245              suggestion = CFCopyLocalizedStringWithDefaultValue(CFSTR("BundleErr3588-R"), CFSTR("Error"), bdl, CFSTR("Try reinstalling the bundle."), "NSExecutableLinkError");
1246          }
1247          if (descFormat) {
1248              desc = CFStringCreateWithFormat(allocator, NULL, descFormat, name);
1249              CFRelease(descFormat);
1250          }
1251          CFRelease(name);
1252      }
1253      if (bundlePath) {
1254          userInfoKeys[numKeys] = CFSTR("NSBundlePath");
1255          userInfoValues[numKeys] = bundlePath;
1256          numKeys++;
1257      }
1258      if (executablePath) {
1259          userInfoKeys[numKeys] = CFSTR("NSFilePath");
1260          userInfoValues[numKeys] = executablePath;
1261          numKeys++;
1262      }
1263      if (desc) {
1264          userInfoKeys[numKeys] = kCFErrorLocalizedDescriptionKey;
1265          userInfoValues[numKeys] = desc;
1266          numKeys++;
1267      }
1268      if (reason) {
1269          userInfoKeys[numKeys] = kCFErrorLocalizedFailureReasonKey;
1270          userInfoValues[numKeys] = reason;
1271          numKeys++;
1272      }
1273      if (suggestion) {
1274          userInfoKeys[numKeys] = kCFErrorLocalizedRecoverySuggestionKey;
1275          userInfoValues[numKeys] = suggestion;
1276          numKeys++;
1277      }
1278      if (debugString) {
1279          userInfoKeys[numKeys] = kCFErrorDebugDescriptionKey;
1280          userInfoValues[numKeys] = debugString;
1281          numKeys++;
1282      }
1283      error = CFErrorCreateWithUserInfoKeysAndValues(allocator, kCFErrorDomainCocoa, code, userInfoKeys, userInfoValues, numKeys);
1284      if (bundleURL) CFRelease(bundleURL);
1285      if (absoluteURL) CFRelease(absoluteURL);
1286      if (executableURL) CFRelease(executableURL);
1287      if (bundlePath) CFRelease(bundlePath);
1288      if (executablePath) CFRelease(executablePath);
1289      if (desc) CFRelease(desc);
1290      if (reason) CFRelease(reason);
1291      if (suggestion) CFRelease(suggestion);
1292      return error;
1293  }
1294  
1295  CFErrorRef _CFBundleCreateError(CFAllocatorRef allocator, CFBundleRef bundle, CFIndex code) {
1296      return _CFBundleCreateErrorDebug(allocator, bundle, code, NULL);
1297  }
1298  
1299  #pragma mark -
1300  
1301  Boolean _CFBundleLoadExecutableAndReturnError(CFBundleRef bundle, Boolean forceGlobal, CFErrorRef *error) {
1302      CF_ASSERT_TYPE(_kCFRuntimeIDCFBundle, bundle);
1303      Boolean result = false;
1304      CFErrorRef localError = NULL, *subError = (error ? &localError : NULL);
1305      CFURLRef executableURL = CFBundleCopyExecutableURL(bundle);
1306  
1307  
1308      _CFMutexLock(&(bundle->_bundleLoadingLock));
1309      if (!executableURL) bundle->_binaryType = __CFBundleNoBinary;
1310      // make sure we know whether bundle is already loaded or not
1311  #if defined(BINARY_SUPPORT_DLFCN)
1312      if (!bundle->_isLoaded) _CFBundleDlfcnCheckLoaded(bundle);
1313  #elif defined(BINARY_SUPPORT_DYLD)
1314      if (!bundle->_isLoaded) _CFBundleDYLDCheckLoaded(bundle);
1315  #endif /* BINARY_SUPPORT_DLFCN */
1316  #if defined(BINARY_SUPPORT_DYLD)
1317      // We might need to figure out what it is
1318      if (bundle->_binaryType == __CFBundleUnknownBinary) {
1319          bundle->_binaryType = _CFBundleGrokBinaryType(executableURL);
1320          if (bundle->_binaryType != __CFBundleCFMBinary && bundle->_binaryType != __CFBundleUnreadableBinary) bundle->_resourceData._executableLacksResourceFork = true;
1321      }
1322  #endif /* BINARY_SUPPORT_DYLD */
1323      if (executableURL) CFRelease(executableURL);
1324      
1325      if (bundle->_isLoaded) {
1326          _CFMutexUnlock(&(bundle->_bundleLoadingLock));
1327          _CFPlugInUnscheduleForUnloading(bundle);
1328          return true;
1329      }
1330      
1331      // n.b. some applications may call API like CFBundleGetBundleWithIdentifier during library initialization. This could wind up recursively taking this lock. Therefore, even though it results in the potential for a race on the internals of bundle's data structures, we have to unlock before calling out to dlopen. rdar://67319441
1332      _CFMutexUnlock(&(bundle->_bundleLoadingLock));
1333      
1334      switch (bundle->_binaryType) {
1335  #if defined(BINARY_SUPPORT_DLFCN)
1336          case __CFBundleUnreadableBinary:
1337              result = _CFBundleDlfcnLoadBundle(bundle, forceGlobal, subError);
1338              break;
1339  #endif /* BINARY_SUPPORT_DLFCN */
1340  #if defined(BINARY_SUPPORT_DYLD)
1341          case __CFBundleDYLDBundleBinary:
1342  #if defined(BINARY_SUPPORT_DLFCN)
1343              result = _CFBundleDlfcnLoadBundle(bundle, forceGlobal, subError);
1344  #else /* BINARY_SUPPORT_DLFCN */
1345              result = _CFBundleDYLDLoadBundle(bundle, forceGlobal, subError);
1346  #endif /* BINARY_SUPPORT_DLFCN */
1347              break;
1348          case __CFBundleDYLDFrameworkBinary:
1349  #if defined(BINARY_SUPPORT_DLFCN)
1350              result = _CFBundleDlfcnLoadFramework(bundle, subError);
1351  #else /* BINARY_SUPPORT_DLFCN */
1352              result = _CFBundleDYLDLoadFramework(bundle, subError);
1353  #endif /* BINARY_SUPPORT_DLFCN */
1354              break;
1355          case __CFBundleDYLDExecutableBinary:
1356              if (error) {
1357                  localError = _CFBundleCreateError(CFGetAllocator(bundle), bundle, CFBundleExecutableNotLoadableError);
1358              } else {
1359                  CFLog(__kCFLogBundle, CFSTR("Attempt to load executable of a type that cannot be dynamically loaded for %@"), bundle);
1360              }
1361              break;
1362  #endif /* BINARY_SUPPORT_DYLD */
1363  #if defined(BINARY_SUPPORT_DLFCN)
1364          case __CFBundleUnknownBinary:
1365          case __CFBundleELFBinary:
1366              result = _CFBundleDlfcnLoadBundle(bundle, forceGlobal, subError);
1367              break;
1368  #endif /* BINARY_SUPPORT_DLFCN */
1369  #if defined(BINARY_SUPPORT_DLL)
1370          case __CFBundleDLLBinary:
1371              result = _CFBundleDLLLoad(bundle, subError);
1372              break;
1373  #endif /* BINARY_SUPPORT_DLL */
1374          case __CFBundleNoBinary:
1375              if (error) {
1376                  localError = _CFBundleCreateError(CFGetAllocator(bundle), bundle, CFBundleExecutableNotFoundError);
1377              } else {
1378                  CFLog(__kCFLogBundle, CFSTR("Cannot find executable for %@"), bundle);
1379              }
1380              break;     
1381          default:
1382              if (error) {
1383                  localError = _CFBundleCreateError(CFGetAllocator(bundle), bundle, CFBundleExecutableNotLoadableError);
1384              } else {
1385                  CFLog(__kCFLogBundle, CFSTR("Cannot recognize type of executable for %@"), bundle);
1386              }
1387              break;
1388      }
1389      
1390      if (result && bundle->_plugInData._isPlugIn) {
1391          _CFPlugInHandleDynamicRegistration(bundle);
1392      }
1393      if (!result && error) *error = localError;
1394      return result;
1395  }
1396  
1397  Boolean CFBundleLoadExecutableAndReturnError(CFBundleRef bundle, CFErrorRef *error) {
1398      return _CFBundleLoadExecutableAndReturnError(bundle, false, error);
1399  }
1400  
1401  Boolean CFBundleLoadExecutable(CFBundleRef bundle) {
1402      return _CFBundleLoadExecutableAndReturnError(bundle, false, NULL);
1403  }
1404  
1405  Boolean CFBundlePreflightExecutable(CFBundleRef bundle, CFErrorRef *error) {
1406      Boolean result = false;
1407      CFErrorRef localError = NULL;
1408  #if defined(BINARY_SUPPORT_DLFCN)
1409      CFErrorRef *subError = (error ? &localError : NULL);
1410  #endif
1411      CFURLRef executableURL = CFBundleCopyExecutableURL(bundle);
1412  
1413      _CFMutexLock(&(bundle->_bundleLoadingLock));
1414      if (!executableURL) bundle->_binaryType = __CFBundleNoBinary;
1415      // make sure we know whether bundle is already loaded or not
1416  #if defined(BINARY_SUPPORT_DLFCN)
1417      if (!bundle->_isLoaded) _CFBundleDlfcnCheckLoaded(bundle);
1418  #elif defined(BINARY_SUPPORT_DYLD)
1419      if (!bundle->_isLoaded) _CFBundleDYLDCheckLoaded(bundle);
1420  #endif /* BINARY_SUPPORT_DLFCN */
1421  #if defined(BINARY_SUPPORT_DYLD)
1422      // We might need to figure out what it is
1423      if (bundle->_binaryType == __CFBundleUnknownBinary) {
1424          bundle->_binaryType = _CFBundleGrokBinaryType(executableURL);
1425          if (bundle->_binaryType != __CFBundleCFMBinary && bundle->_binaryType != __CFBundleUnreadableBinary) bundle->_resourceData._executableLacksResourceFork = true;
1426      }
1427  #endif /* BINARY_SUPPORT_DYLD */
1428      if (executableURL) CFRelease(executableURL);
1429      
1430      if (bundle->_isLoaded) {
1431          _CFMutexUnlock(&(bundle->_bundleLoadingLock));
1432          return true;
1433      }
1434      _CFMutexUnlock(&(bundle->_bundleLoadingLock));
1435      
1436      switch (bundle->_binaryType) {
1437  #if defined(BINARY_SUPPORT_DLFCN)
1438          case __CFBundleUnreadableBinary:
1439              result = _CFBundleDlfcnPreflight(bundle, subError);
1440              break;
1441  #endif /* BINARY_SUPPORT_DLFCN */
1442  #if defined(BINARY_SUPPORT_DYLD)
1443          case __CFBundleDYLDBundleBinary:
1444              result = true;
1445  #if defined(BINARY_SUPPORT_DLFCN)
1446              result = _CFBundleDlfcnPreflight(bundle, subError);
1447  #endif /* BINARY_SUPPORT_DLFCN */
1448              break;
1449          case __CFBundleDYLDFrameworkBinary:
1450              result = true;
1451  #if defined(BINARY_SUPPORT_DLFCN)
1452              result = _CFBundleDlfcnPreflight(bundle, subError);
1453  #endif /* BINARY_SUPPORT_DLFCN */
1454              break;
1455          case __CFBundleDYLDExecutableBinary:
1456              if (error) localError = _CFBundleCreateError(CFGetAllocator(bundle), bundle, CFBundleExecutableNotLoadableError);
1457              break;
1458  #endif /* BINARY_SUPPORT_DYLD */
1459  #if defined(BINARY_SUPPORT_DLFCN)
1460          case __CFBundleUnknownBinary:
1461          case __CFBundleELFBinary:
1462              result = _CFBundleDlfcnPreflight(bundle, subError);
1463              break;
1464  #endif /* BINARY_SUPPORT_DLFCN */
1465  #if defined(BINARY_SUPPORT_DLL)
1466          case __CFBundleDLLBinary:
1467              result = true;
1468              break;
1469  #endif /* BINARY_SUPPORT_DLL */
1470          case __CFBundleNoBinary:
1471              if (error) localError = _CFBundleCreateError(CFGetAllocator(bundle), bundle, CFBundleExecutableNotFoundError);
1472              break;     
1473          default:
1474              if (error) localError = _CFBundleCreateError(CFGetAllocator(bundle), bundle, CFBundleExecutableNotLoadableError);
1475              break;
1476      }
1477      if (!result && error) *error = localError;
1478      return result;
1479  }
1480  
1481  CFArrayRef CFBundleCopyExecutableArchitectures(CFBundleRef bundle) {
1482      CFArrayRef result = NULL;
1483      CFURLRef executableURL = CFBundleCopyExecutableURL(bundle);
1484      if (executableURL) {
1485          result = _CFBundleCopyArchitecturesForExecutable(executableURL);
1486          CFRelease(executableURL);
1487      }
1488      return result;
1489  }
1490  
1491  void CFBundleUnloadExecutable(CFBundleRef bundle) {
1492      _CFBundleUnloadExecutable(bundle, false);
1493  }
1494  
1495  CF_PRIVATE void _CFBundleUnloadExecutable(CFBundleRef bundle, Boolean unloadingPlugins) {
1496      CF_ASSERT_TYPE(_kCFRuntimeIDCFBundle, bundle);
1497      // First unload bundles scheduled for unloading (if that's not what we are already doing.)
1498      if (!unloadingPlugins) _CFPlugInUnloadScheduledPlugIns();
1499      
1500      if (!bundle->_isLoaded) return;
1501  
1502      // Remove from the scheduled unload set if we are there.
1503      _CFPlugInUnscheduleForUnloading(bundle);
1504      
1505      // Give the plugIn code a chance to realize this...
1506      _CFPlugInWillUnload(bundle);
1507  
1508      _CFMutexLock(&(bundle->_bundleLoadingLock));
1509      if (!bundle->_isLoaded) {
1510          _CFMutexUnlock(&(bundle->_bundleLoadingLock));
1511          return;
1512      }
1513  
1514      switch (bundle->_binaryType) {
1515  #if defined(BINARY_SUPPORT_DYLD)
1516          case __CFBundleDYLDBundleBinary:
1517  #if defined(BINARY_SUPPORT_DLFCN)
1518              if (bundle->_handleCookie) _CFBundleDlfcnUnload(bundle);
1519  #else /* BINARY_SUPPORT_DLFCN */
1520              _CFBundleDYLDUnloadBundle(bundle);
1521  #endif /* BINARY_SUPPORT_DLFCN */
1522              break;
1523          case __CFBundleDYLDFrameworkBinary:
1524  #if defined(BINARY_SUPPORT_DLFCN)
1525              if (bundle->_handleCookie && _CFExecutableLinkedOnOrAfter(CFSystemVersionLeopard)) _CFBundleDlfcnUnload(bundle);
1526  #endif /* BINARY_SUPPORT_DLFCN */
1527              break;
1528  #endif /* BINARY_SUPPORT_DYLD */
1529  #if defined(BINARY_SUPPORT_DLL)
1530          case __CFBundleDLLBinary:
1531              _CFBundleDLLUnload(bundle);
1532              break;
1533  #endif /* BINARY_SUPPORT_DLL */
1534          default:
1535  #if defined(BINARY_SUPPORT_DLFCN)
1536              if (bundle->_handleCookie) _CFBundleDlfcnUnload(bundle);
1537  #endif /* BINARY_SUPPORT_DLFCN */
1538              break;
1539      }
1540      
1541      _CFMutexUnlock(&(bundle->_bundleLoadingLock));
1542  }
1543  
1544  #pragma mark -
1545  
1546  CF_PRIVATE _CFResourceData *__CFBundleGetResourceData(CFBundleRef bundle) {
1547      return &(bundle->_resourceData);
1548  }
1549  
1550  CFPlugInRef CFBundleGetPlugIn(CFBundleRef bundle) {
1551      return (bundle->_plugInData._isPlugIn) ? (CFPlugInRef)bundle : NULL;
1552  }
1553  
1554  CF_PRIVATE _CFPlugInData *__CFBundleGetPlugInData(CFBundleRef bundle) {
1555      return &(bundle->_plugInData);
1556  }
1557  
1558  CF_PRIVATE Boolean _CFBundleCouldBeBundle(CFURLRef url) {
1559      Boolean result = false;
1560      Boolean exists;
1561      SInt32 mode;
1562      if (_CFGetFileProperties(kCFAllocatorSystemDefault, url, &exists, &mode, NULL, NULL, NULL, NULL) == 0) result = (exists && (mode & S_IFMT) == S_IFDIR && (mode & 0444) != 0);
1563      return result;
1564  }
1565  
1566  #define LENGTH_OF(A) (sizeof(A) / sizeof(A[0]))
1567          
1568  //If 'permissive' is set, we will maintain the historical behavior of returning frameworks with names that don't match, and frameworks for executables in Resources/
1569  static CFURLRef __CFBundleCopyFrameworkURLForExecutablePath(CFStringRef executablePath, Boolean permissive) {
1570      // MF:!!! Implement me.  We need to be able to find the bundle from the exe, dealing with old vs. new as well as the Executables dir business on Windows.
1571  #if TARGET_OS_WIN32
1572      UniChar executablesToFrameworksPathBuff[] = {'.', '.', '\\', 'F', 'r', 'a', 'm', 'e', 'w', 'o', 'r', 'k', 's'};
1573      UniChar executablesToPrivateFrameworksPathBuff[] = {'.', '.', '\\', 'P', 'r', 'i', 'v', 'a', 't', 'e', 'F', 'r', 'a', 'm', 'e', 'w', 'o', 'r', 'k', 's'};
1574      UniChar frameworksExtension[] = {'f', 'r', 'a', 'm', 'e', 'w', 'o', 'r', 'k'};
1575  #endif
1576      UniChar pathBuff[CFMaxPathSize] = {0};
1577      UniChar nameBuff[CFMaxPathSize] = {0};
1578      CFIndex length, nameStart, nameLength, savedLength;
1579      CFMutableStringRef cheapStr = CFStringCreateMutableWithExternalCharactersNoCopy(kCFAllocatorSystemDefault, NULL, 0, 0, NULL);
1580      CFURLRef bundleURL = NULL;
1581      
1582      length = CFStringGetLength(executablePath);
1583      if (length > CFMaxPathSize) length = CFMaxPathSize;
1584      CFStringGetCharacters(executablePath, CFRangeMake(0, length), pathBuff);
1585  
1586      // Save the name in nameBuff
1587      length = _CFLengthAfterDeletingPathExtension(pathBuff, length);
1588      nameStart = _CFStartOfLastPathComponent(pathBuff, length);
1589      nameLength = length - nameStart;
1590      memmove(nameBuff, &(pathBuff[nameStart]), nameLength * sizeof(UniChar));
1591  
1592      // Strip the name from pathBuff
1593      length = _CFLengthAfterDeletingLastPathComponent(pathBuff, length);
1594      savedLength = length;
1595  
1596  #if TARGET_OS_WIN32
1597      // * (Windows-only) First check the "Executables" directory parallel to the "Frameworks" directory case.
1598      if (_CFAppendPathComponent(pathBuff, &length, CFMaxPathSize, executablesToFrameworksPathBuff, LENGTH_OF(executablesToFrameworksPathBuff)) && _CFAppendPathComponent(pathBuff, &length, CFMaxPathSize, nameBuff, nameLength) && _CFAppendPathExtension(pathBuff, &length, CFMaxPathSize, frameworksExtension, LENGTH_OF(frameworksExtension))) {
1599          CFStringSetExternalCharactersNoCopy(cheapStr, pathBuff, length, CFMaxPathSize);
1600          bundleURL = CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault, cheapStr, PLATFORM_PATH_STYLE, true);
1601          if (!_CFBundleCouldBeBundle(bundleURL)) {
1602              CFRelease(bundleURL);
1603              bundleURL = NULL;
1604          }
1605      }
1606      // * (Windows-only) Next check the "Executables" directory parallel to the "PrivateFrameworks" directory case.
1607      if (!bundleURL) {
1608          length = savedLength;
1609          if (_CFAppendPathComponent(pathBuff, &length, CFMaxPathSize, executablesToPrivateFrameworksPathBuff, LENGTH_OF(executablesToPrivateFrameworksPathBuff)) && _CFAppendPathComponent(pathBuff, &length, CFMaxPathSize, nameBuff, nameLength) && _CFAppendPathExtension(pathBuff, &length, CFMaxPathSize, frameworksExtension, LENGTH_OF(frameworksExtension))) {
1610              CFStringSetExternalCharactersNoCopy(cheapStr, pathBuff, length, CFMaxPathSize);
1611              bundleURL = CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault, cheapStr, PLATFORM_PATH_STYLE, true);
1612              if (!_CFBundleCouldBeBundle(bundleURL)) {
1613                  CFRelease(bundleURL);
1614                  bundleURL = NULL;
1615              }
1616          }
1617      }
1618  #endif
1619      // * Finally check the executable inside the framework case.
1620      if (!bundleURL) {        
1621          length = savedLength;
1622          // To catch all the cases, we just peel off level looking for one ending in .framework or one called "Supporting Files".
1623          
1624          CFStringRef name = permissive ? CFSTR("") : CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault, (const char *)nameBuff);
1625          
1626          while (length > 0) {
1627              CFIndex curStart = _CFStartOfLastPathComponent(pathBuff, length);
1628              if (curStart >= length) break;
1629              CFStringSetExternalCharactersNoCopy(cheapStr, &(pathBuff[curStart]), length - curStart, CFMaxPathSize - curStart);
1630              if (!permissive && CFEqual(cheapStr, _CFBundleResourcesDirectoryName)) break;
1631              if (CFEqual(cheapStr, _CFBundleSupportFilesDirectoryName1) || CFEqual(cheapStr, _CFBundleSupportFilesDirectoryName2)) {
1632                  if (!permissive) {
1633                      CFIndex fmwkStart = _CFStartOfLastPathComponent(pathBuff, length);
1634                      CFStringSetExternalCharactersNoCopy(cheapStr, &(pathBuff[fmwkStart]), length - fmwkStart, CFMaxPathSize - fmwkStart);
1635                  }
1636                  if (permissive || CFStringHasPrefix(cheapStr, name)) {
1637                      length = _CFLengthAfterDeletingLastPathComponent(pathBuff, length);
1638                      CFStringSetExternalCharactersNoCopy(cheapStr, pathBuff, length, CFMaxPathSize);
1639                      
1640                      bundleURL = CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault, cheapStr, PLATFORM_PATH_STYLE, true);
1641                      if (!_CFBundleCouldBeBundle(bundleURL)) {
1642                          CFRelease(bundleURL);
1643                          bundleURL = NULL;
1644                      }
1645                      break;
1646                  }
1647              } else if (CFStringHasSuffix(cheapStr, CFSTR(".framework")) && (permissive || CFStringHasPrefix(cheapStr, name))) {
1648                  CFStringSetExternalCharactersNoCopy(cheapStr, pathBuff, length, CFMaxPathSize);
1649                  bundleURL = CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault, cheapStr, PLATFORM_PATH_STYLE, true);
1650                  if (!_CFBundleCouldBeBundle(bundleURL)) {
1651                      CFRelease(bundleURL);
1652                      bundleURL = NULL;
1653                  }
1654                  break;
1655              }
1656              length = _CFLengthAfterDeletingLastPathComponent(pathBuff, length);
1657          }
1658          if (!permissive) CFRelease(name);
1659      }
1660      CFStringSetExternalCharactersNoCopy(cheapStr, NULL, 0, 0);
1661      CFRelease(cheapStr);
1662  
1663      return bundleURL;
1664  }
1665          
1666  //SPI version; separated out to minimize linkage changes
1667  CFURLRef _CFBundleCopyFrameworkURLForExecutablePath(CFStringRef executablePath) {
1668      return __CFBundleCopyFrameworkURLForExecutablePath(executablePath, false);
1669  }
1670  
1671  static void _CFBundleEnsureBundleExistsForImagePath(CFStringRef imagePath, Boolean permissive) {
1672      // This finds the bundle for the given path.
1673      // If an image path corresponds to a bundle, we see if there is already a bundle instance.  If there is and it is NOT in the _dynamicBundles array, it is added to the staticBundles.  Do not add the main bundle to the list here.
1674      CFBundleRef bundle;
1675      CFURLRef curURL = __CFBundleCopyFrameworkURLForExecutablePath(imagePath, permissive);
1676  
1677      if (curURL) {
1678          // Ensure bundle exists by creating it if necessary. This will check the tables as a first step.
1679          // NB doFinalProcessing must be false here, see below
1680          bundle = _CFBundleCreate(kCFAllocatorSystemDefault, curURL, false, false, true);
1681          if (bundle) {
1682              _CFMutexLock(&(bundle->_bundleLoadingLock));
1683              if (!bundle->_isLoaded) {
1684                  // make sure that these bundles listed as loaded, and mark them frameworks (we probably can't see anything else here, and we cannot unload them)
1685      #if defined(BINARY_SUPPORT_DLFCN)
1686                  if (!bundle->_isLoaded) _CFBundleDlfcnCheckLoaded(bundle);
1687      #elif defined(BINARY_SUPPORT_DYLD)
1688                  if (!bundle->_isLoaded) _CFBundleDYLDCheckLoaded(bundle);
1689      #endif /* BINARY_SUPPORT_DLFCN */
1690      #if defined(BINARY_SUPPORT_DYLD)
1691                  if (bundle->_binaryType == __CFBundleUnknownBinary) bundle->_binaryType = __CFBundleDYLDFrameworkBinary;
1692                  if (bundle->_binaryType != __CFBundleCFMBinary && bundle->_binaryType != __CFBundleUnreadableBinary) bundle->_resourceData._executableLacksResourceFork = true;
1693      #endif /* BINARY_SUPPORT_DYLD */
1694      #if LOG_BUNDLE_LOAD
1695                  if (!bundle->_isLoaded) printf("ensure bundle %p set loaded fallback, handle %p image %p conn %p\n", bundle, bundle->_handleCookie, bundle->_imageCookie, bundle->_connectionCookie);
1696      #endif /* LOG_BUNDLE_LOAD */
1697                  bundle->_isLoaded = true;
1698              }
1699              _CFMutexUnlock(&(bundle->_bundleLoadingLock));
1700              // Perform delayed final processing steps.
1701              // This must be done after _isLoaded has been set, for security reasons (3624341).
1702              CFDictionaryRef infoDict = CFBundleGetInfoDictionary(bundle);
1703              _CFBundleInitPlugIn(bundle, infoDict, NULL);
1704              _CFPlugInHandleDynamicRegistration(bundle);
1705          }
1706          CFRelease(curURL);
1707      }
1708  }
1709  
1710  static void _CFBundleEnsureBundlesExistForImagePaths(CFArrayRef imagePaths) {
1711      // This finds the bundles for the given paths.
1712      // If an image path corresponds to a bundle, we see if there is already a bundle instance.  If there is and it is NOT in the _dynamicBundles array, it is added to the staticBundles.  Do not add the main bundle to the list here (even if it appears in imagePaths).
1713      CFIndex i, imagePathCount = CFArrayGetCount(imagePaths);
1714      for (i = 0; i < imagePathCount; i++) _CFBundleEnsureBundleExistsForImagePath((CFStringRef)CFArrayGetValueAtIndex(imagePaths, i), true);
1715  }
1716  
1717  static void _CFBundleEnsureBundlesUpToDateWithHint(CFStringRef hint) {
1718      CFArrayRef imagePaths = NULL;
1719      // Tickle the main bundle into existence
1720      (void)CFBundleGetMainBundle();
1721  #if defined(BINARY_SUPPORT_DYLD)
1722      imagePaths = _CFBundleDYLDCopyLoadedImagePathsForHint(hint);
1723  #endif /* BINARY_SUPPORT_DYLD */
1724      if (imagePaths) {
1725          _CFBundleEnsureBundlesExistForImagePaths(imagePaths);
1726          CFRelease(imagePaths);
1727      }
1728  }
1729  
1730  CFBundleRef _CFBundleGetBundleWithIdentifierAndLibraryName(CFStringRef bundleID, CFStringRef libraryName) {
1731      if (libraryName) {
1732          _CFBundleEnsureBundlesUpToDateWithHint(libraryName);
1733      }
1734      return _CFBundleGetFromTables(bundleID);
1735  }
1736  
1737  static void _CFBundleEnsureAllBundlesUpToDate(void) {
1738      // This method returns all the statically linked bundles.  This includes the main bundle as well as any frameworks that the process was linked against at launch time.  It does not include frameworks or opther bundles that were loaded dynamically.
1739      CFArrayRef imagePaths = NULL;
1740      // Tickle the main bundle into existence
1741      (void)CFBundleGetMainBundle();
1742  
1743  #if defined(BINARY_SUPPORT_DLL)
1744  // Don't know how to find static bundles for DLLs
1745  #endif /* BINARY_SUPPORT_DLL */
1746  
1747  #if defined(BINARY_SUPPORT_DYLD)
1748      imagePaths = _CFBundleDYLDCopyLoadedImagePathsIfChanged();
1749  #endif /* BINARY_SUPPORT_DYLD */
1750      if (imagePaths) {
1751          _CFBundleEnsureBundlesExistForImagePaths(imagePaths);
1752          CFRelease(imagePaths);
1753      }
1754  }
1755  
1756  CFArrayRef CFBundleGetAllBundles(void) {
1757      // This API is fundamentally broken from a thread safety point of view. To mitigate the issues, we keep around the last list we handed out. If the list of allBundles changed, we leak the last one and return a new copy. If no bundle loading is done this list would be static.
1758      // Fortunately this method is rarely used.
1759      CFArrayRef result = NULL;
1760      _CFMutexLock(&CFBundleGlobalDataLock);
1761      static CFArrayRef _lastBundleList = NULL;
1762      if (!_lastBundleList) {
1763          // This is the first time we've been asked for a list of all bundles
1764          // Unlock the global lock. CopyAllBundles will use it.
1765          _CFMutexUnlock(&CFBundleGlobalDataLock);
1766          result = _CFBundleCopyAllBundles();
1767          _CFMutexLock(&CFBundleGlobalDataLock);
1768          if (_lastBundleList) {
1769              // Another thread beat us here
1770              CFRelease(result);
1771          } else {
1772              _lastBundleList = result;
1773          }
1774      } else if (!CFEqual(_lastBundleList, _allBundles)) {
1775          // Check if the list of bundles has changed
1776          _CFMutexUnlock(&CFBundleGlobalDataLock);
1777          result = _CFBundleCopyAllBundles();
1778          _CFMutexLock(&CFBundleGlobalDataLock);
1779          // note: intentionally leak the last value in _lastBundleList, due to API contract of 'get'
1780          _lastBundleList = result;
1781      }
1782      result = _lastBundleList;
1783      _CFMutexUnlock(&CFBundleGlobalDataLock);
1784      return result;
1785  }
1786          
1787  CF_EXPORT CFArrayRef _CFBundleCopyAllBundles(void) {
1788      // To answer this properly, we have to have created the static bundles!
1789      _CFBundleEnsureAllBundlesUpToDate();
1790      CFBundleRef main = CFBundleGetMainBundle();
1791      _CFMutexLock(&CFBundleGlobalDataLock);
1792      // _allBundles does not include the main bundle, so insert it here.
1793      CFMutableArrayRef bundles = CFArrayCreateMutableCopy(kCFAllocatorSystemDefault, CFArrayGetCount(_allBundles) + 1, _allBundles);
1794      _CFMutexUnlock(&CFBundleGlobalDataLock);
1795      CFArrayInsertValueAtIndex(bundles, 0, main);
1796      return bundles;
1797  }
1798  
1799  CF_PRIVATE _CFBundleVersion _CFBundleLayoutVersion(CFBundleRef bundle) {
1800      return bundle->_version;
1801  }
1802       
1803  CF_EXPORT CFURLRef _CFBundleCopyPrivateFrameworksURL(CFBundleRef bundle) {
1804      return CFBundleCopyPrivateFrameworksURL(bundle);
1805  }
1806  
1807  CF_EXPORT CFURLRef CFBundleCopyPrivateFrameworksURL(CFBundleRef bundle) {
1808      CF_ASSERT_TYPE(_kCFRuntimeIDCFBundle, bundle);
1809      CFURLRef result = NULL;
1810  
1811      if (_CFBundleVersionOldStyleSupportFiles == bundle->_version) {
1812          result = CFURLCreateWithString(CFGetAllocator(bundle), _CFBundlePrivateFrameworksURLFromBase1, bundle->_url);
1813      } else if (_CFBundleVersionContentsResources == bundle->_version) {
1814          result = CFURLCreateWithString(CFGetAllocator(bundle), _CFBundlePrivateFrameworksURLFromBase2, bundle->_url);
1815      } else if (_CFBundleVersionWrappedContentsResources == bundle->_version) {
1816          result = _CFURLCreateResolvedDirectoryWithString(CFGetAllocator(bundle), _CFBundleWrappedPrivateFrameworksURLFromBase2, bundle->_url);
1817      } else if (_CFBundleVersionWrappedFlat == bundle->_version) {
1818          result = _CFURLCreateResolvedDirectoryWithString(CFGetAllocator(bundle), _CFBundleWrappedPrivateFrameworksURLFromBase3, bundle->_url);
1819      } else {
1820          result = CFURLCreateWithString(CFGetAllocator(bundle), _CFBundlePrivateFrameworksURLFromBase0, bundle->_url);
1821      }
1822      return result;
1823  }
1824  
1825  CF_EXPORT CFURLRef _CFBundleCopySharedFrameworksURL(CFBundleRef bundle) {
1826      return CFBundleCopySharedFrameworksURL(bundle);
1827  }
1828  
1829  CF_EXPORT CFURLRef CFBundleCopySharedFrameworksURL(CFBundleRef bundle) {
1830      CF_ASSERT_TYPE(_kCFRuntimeIDCFBundle, bundle);
1831      CFURLRef result = NULL;
1832  
1833      if (_CFBundleVersionOldStyleSupportFiles == bundle->_version) {
1834          result = CFURLCreateWithString(CFGetAllocator(bundle), _CFBundleSharedFrameworksURLFromBase1, bundle->_url);
1835      } else if (_CFBundleVersionContentsResources == bundle->_version) {
1836          result = CFURLCreateWithString(CFGetAllocator(bundle), _CFBundleSharedFrameworksURLFromBase2, bundle->_url);
1837      } else if (_CFBundleVersionWrappedContentsResources == bundle->_version) {
1838          result = _CFURLCreateResolvedDirectoryWithString(CFGetAllocator(bundle), _CFBundleWrappedSharedFrameworksURLFromBase2, bundle->_url);
1839      } else if (_CFBundleVersionWrappedFlat == bundle->_version) {
1840          result = _CFURLCreateResolvedDirectoryWithString(CFGetAllocator(bundle), _CFBundleWrappedSharedFrameworksURLFromBase3, bundle->_url);
1841      } else {
1842          result = CFURLCreateWithString(CFGetAllocator(bundle), _CFBundleSharedFrameworksURLFromBase0, bundle->_url);
1843      }
1844      return result;
1845  }
1846  
1847  CF_EXPORT CFURLRef _CFBundleCopySharedSupportURL(CFBundleRef bundle) {
1848      return CFBundleCopySharedSupportURL(bundle);
1849  }
1850  
1851  CF_EXPORT CFURLRef CFBundleCopySharedSupportURL(CFBundleRef bundle) {
1852      CF_ASSERT_TYPE(_kCFRuntimeIDCFBundle, bundle);
1853      CFURLRef result = NULL;
1854  
1855      if (_CFBundleVersionOldStyleSupportFiles == bundle->_version) {
1856          result = CFURLCreateWithString(CFGetAllocator(bundle), _CFBundleSharedSupportURLFromBase1, bundle->_url);
1857      } else if (_CFBundleVersionContentsResources == bundle->_version) {
1858          result = CFURLCreateWithString(CFGetAllocator(bundle), _CFBundleSharedSupportURLFromBase2, bundle->_url);
1859      } else if (_CFBundleVersionWrappedContentsResources == bundle->_version) {
1860          result = _CFURLCreateResolvedDirectoryWithString(CFGetAllocator(bundle), _CFBundleWrappedSharedSupportURLFromBase2, bundle->_url);
1861      } else if (_CFBundleVersionWrappedFlat == bundle->_version) {
1862          result = _CFURLCreateResolvedDirectoryWithString(CFGetAllocator(bundle), _CFBundleWrappedSharedSupportURLFromBase3, bundle->_url);
1863      } else {
1864          result = CFURLCreateWithString(CFGetAllocator(bundle), _CFBundleSharedSupportURLFromBase0, bundle->_url);
1865      }
1866      return result;
1867  }
1868  
1869  CF_PRIVATE CFURLRef _CFBundleCopyBuiltInPlugInsURL(CFBundleRef bundle) {
1870      return CFBundleCopyBuiltInPlugInsURL(bundle);
1871  }
1872  
1873  CF_EXPORT CFURLRef CFBundleCopyBuiltInPlugInsURL(CFBundleRef bundle) {
1874      CF_ASSERT_TYPE(_kCFRuntimeIDCFBundle, bundle);
1875      CFURLRef result = NULL, alternateResult = NULL;
1876  
1877      CFAllocatorRef alloc = CFGetAllocator(bundle);
1878      if (_CFBundleVersionOldStyleSupportFiles == bundle->_version) {
1879          result = CFURLCreateWithString(alloc, _CFBundleBuiltInPlugInsURLFromBase1, bundle->_url);
1880      } else if (_CFBundleVersionContentsResources == bundle->_version) {
1881          result = CFURLCreateWithString(alloc, _CFBundleBuiltInPlugInsURLFromBase2, bundle->_url);
1882      } else if (_CFBundleVersionWrappedContentsResources == bundle->_version) {
1883          result = _CFURLCreateResolvedDirectoryWithString(CFGetAllocator(bundle), _CFBundleWrappedBuiltInPlugInsURLFromBase2, bundle->_url);
1884      } else if (_CFBundleVersionWrappedFlat == bundle->_version) {
1885          result = _CFURLCreateResolvedDirectoryWithString(CFGetAllocator(bundle), _CFBundleWrappedBuiltInPlugInsURLFromBase3, bundle->_url);
1886      } else {
1887          result = CFURLCreateWithString(alloc, _CFBundleBuiltInPlugInsURLFromBase0, bundle->_url);
1888      }
1889      if (!result || !_CFURLExists(result)) {
1890          if (_CFBundleVersionOldStyleSupportFiles == bundle->_version) {
1891              alternateResult = CFURLCreateWithString(alloc, _CFBundleAlternateBuiltInPlugInsURLFromBase1, bundle->_url);
1892          } else if (_CFBundleVersionContentsResources == bundle->_version) {
1893              alternateResult = CFURLCreateWithString(alloc, _CFBundleAlternateBuiltInPlugInsURLFromBase2, bundle->_url);
1894          } else if (_CFBundleVersionWrappedContentsResources == bundle->_version) {
1895              alternateResult = _CFURLCreateResolvedDirectoryWithString(CFGetAllocator(bundle), _CFBundleWrappedAlternateBuiltInPlugInsURLFromBase2, bundle->_url);
1896          } else if (_CFBundleVersionWrappedFlat == bundle->_version) {
1897              alternateResult = _CFURLCreateResolvedDirectoryWithString(CFGetAllocator(bundle), _CFBundleWrappedAlternateBuiltInPlugInsURLFromBase3, bundle->_url);
1898          } else {
1899              alternateResult = CFURLCreateWithString(alloc, _CFBundleAlternateBuiltInPlugInsURLFromBase0, bundle->_url);
1900          }
1901          if (alternateResult && _CFURLExists(alternateResult)) {
1902              if (result) CFRelease(result);
1903              result = alternateResult;
1904          } else {
1905              if (alternateResult) CFRelease(alternateResult);
1906          }
1907      }
1908      return result;
1909  }
1910