]> git.saurik.com Git - apple/cf.git/blob - CFBundle.c
CF-1153.18.tar.gz
[apple/cf.git] / CFBundle.c
1 /*
2 * Copyright (c) 2015 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 /* CFBundle.c
25 Copyright (c) 1999-2014, Apple Inc. All rights reserved.
26 Responsibility: Tony Parker
27 */
28
29 #include "CFBundle_Internal.h"
30 #include <CoreFoundation/CFPropertyList.h>
31 #include <CoreFoundation/CFNumber.h>
32 #include <CoreFoundation/CFSet.h>
33 #include <CoreFoundation/CFURLAccess.h>
34 #include <CoreFoundation/CFError.h>
35 #include <string.h>
36 #include <CoreFoundation/CFPriv.h>
37 #include "CFInternal.h"
38 #include <CoreFoundation/CFByteOrder.h>
39 #include "CFBundle_BinaryTypes.h"
40 #include <ctype.h>
41 #include <sys/stat.h>
42 #include <stdlib.h>
43
44 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI || DEPLOYMENT_TARGET_WINDOWS
45 #else
46 #error Unknown deployment target
47 #endif
48
49 #define AVOID_WEAK_COLLECTIONS 1
50
51 #if !AVOID_WEAK_COLLECTIONS
52 #include "CFHashTable.h"
53 #include "CFMapTable.h"
54 #include "CFPointerArray.h"
55 #endif /* !AVOID_WEAK_COLLECTIONS */
56
57 #if defined(BINARY_SUPPORT_DYLD)
58 #include <unistd.h>
59 #include <fcntl.h>
60 #include <sys/mman.h>
61 #include <crt_externs.h>
62 #endif /* BINARY_SUPPORT_DYLD */
63
64 #if defined(BINARY_SUPPORT_DLFCN)
65 #include <dlfcn.h>
66 #endif /* BINARY_SUPPORT_DLFCN */
67
68 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
69 #include <fcntl.h>
70 #elif DEPLOYMENT_TARGET_WINDOWS
71 #include <fcntl.h>
72 #include <io.h>
73 #endif
74
75
76 static void _CFBundleFlushBundleCachesAlreadyLocked(CFBundleRef bundle, Boolean alreadyLocked);
77
78 #define LOG_BUNDLE_LOAD 0
79
80 // Public CFBundle Info plist keys
81 CONST_STRING_DECL(kCFBundleInfoDictionaryVersionKey, "CFBundleInfoDictionaryVersion")
82 CONST_STRING_DECL(kCFBundleExecutableKey, "CFBundleExecutable")
83 CONST_STRING_DECL(kCFBundleIdentifierKey, "CFBundleIdentifier")
84 CONST_STRING_DECL(kCFBundleVersionKey, "CFBundleVersion")
85 CONST_STRING_DECL(kCFBundleDevelopmentRegionKey, "CFBundleDevelopmentRegion")
86 CONST_STRING_DECL(kCFBundleLocalizationsKey, "CFBundleLocalizations")
87
88 // Private CFBundle Info plist keys, possible candidates for public constants
89 CONST_STRING_DECL(_kCFBundleAllowMixedLocalizationsKey, "CFBundleAllowMixedLocalizations")
90 CONST_STRING_DECL(_kCFBundleSupportedPlatformsKey, "CFBundleSupportedPlatforms")
91 CONST_STRING_DECL(_kCFBundleResourceSpecificationKey, "CFBundleResourceSpecification")
92
93 // Finder stuff
94 CONST_STRING_DECL(_kCFBundlePackageTypeKey, "CFBundlePackageType")
95 CONST_STRING_DECL(_kCFBundleSignatureKey, "CFBundleSignature")
96 CONST_STRING_DECL(_kCFBundleIconFileKey, "CFBundleIconFile")
97 CONST_STRING_DECL(_kCFBundleDocumentTypesKey, "CFBundleDocumentTypes")
98 CONST_STRING_DECL(_kCFBundleURLTypesKey, "CFBundleURLTypes")
99
100 // Keys that are usually localized in InfoPlist.strings
101 CONST_STRING_DECL(kCFBundleNameKey, "CFBundleName")
102 CONST_STRING_DECL(_kCFBundleDisplayNameKey, "CFBundleDisplayName")
103 CONST_STRING_DECL(_kCFBundleShortVersionStringKey, "CFBundleShortVersionString")
104 CONST_STRING_DECL(_kCFBundleGetInfoStringKey, "CFBundleGetInfoString")
105 CONST_STRING_DECL(_kCFBundleGetInfoHTMLKey, "CFBundleGetInfoHTML")
106
107 // Sub-keys for CFBundleDocumentTypes dictionaries
108 CONST_STRING_DECL(_kCFBundleTypeNameKey, "CFBundleTypeName")
109 CONST_STRING_DECL(_kCFBundleTypeRoleKey, "CFBundleTypeRole")
110 CONST_STRING_DECL(_kCFBundleTypeIconFileKey, "CFBundleTypeIconFile")
111 CONST_STRING_DECL(_kCFBundleTypeOSTypesKey, "CFBundleTypeOSTypes")
112 CONST_STRING_DECL(_kCFBundleTypeExtensionsKey, "CFBundleTypeExtensions")
113 CONST_STRING_DECL(_kCFBundleTypeMIMETypesKey, "CFBundleTypeMIMETypes")
114
115 // Sub-keys for CFBundleURLTypes dictionaries
116 CONST_STRING_DECL(_kCFBundleURLNameKey, "CFBundleURLName")
117 CONST_STRING_DECL(_kCFBundleURLIconFileKey, "CFBundleURLIconFile")
118 CONST_STRING_DECL(_kCFBundleURLSchemesKey, "CFBundleURLSchemes")
119
120 // Compatibility key names
121 CONST_STRING_DECL(_kCFBundleOldExecutableKey, "NSExecutable")
122 CONST_STRING_DECL(_kCFBundleOldInfoDictionaryVersionKey, "NSInfoPlistVersion")
123 CONST_STRING_DECL(_kCFBundleOldNameKey, "NSHumanReadableName")
124 CONST_STRING_DECL(_kCFBundleOldIconFileKey, "NSIcon")
125 CONST_STRING_DECL(_kCFBundleOldDocumentTypesKey, "NSTypes")
126 CONST_STRING_DECL(_kCFBundleOldShortVersionStringKey, "NSAppVersion")
127
128 // Compatibility CFBundleDocumentTypes key names
129 CONST_STRING_DECL(_kCFBundleOldTypeNameKey, "NSName")
130 CONST_STRING_DECL(_kCFBundleOldTypeRoleKey, "NSRole")
131 CONST_STRING_DECL(_kCFBundleOldTypeIconFileKey, "NSIcon")
132 CONST_STRING_DECL(_kCFBundleOldTypeExtensions1Key, "NSUnixExtensions")
133 CONST_STRING_DECL(_kCFBundleOldTypeExtensions2Key, "NSDOSExtensions")
134 CONST_STRING_DECL(_kCFBundleOldTypeOSTypesKey, "NSMacOSType")
135
136 // Internally used keys for loaded Info plists.
137 CONST_STRING_DECL(_kCFBundleInfoPlistURLKey, "CFBundleInfoPlistURL")
138 CONST_STRING_DECL(_kCFBundleRawInfoPlistURLKey, "CFBundleRawInfoPlistURL")
139 CONST_STRING_DECL(_kCFBundleNumericVersionKey, "CFBundleNumericVersion")
140 CONST_STRING_DECL(_kCFBundleExecutablePathKey, "CFBundleExecutablePath")
141 CONST_STRING_DECL(_kCFBundleResourcesFileMappedKey, "CSResourcesFileMapped")
142 CONST_STRING_DECL(_kCFBundleCFMLoadAsBundleKey, "CFBundleCFMLoadAsBundle")
143
144 // Keys used by NSBundle for loaded Info plists.
145 CONST_STRING_DECL(_kCFBundlePrincipalClassKey, "NSPrincipalClass")
146
147 static char __CFBundleMainID__[1026] = {0};
148 CF_PRIVATE char *__CFBundleMainID = __CFBundleMainID__;
149
150 static CFTypeID __kCFBundleTypeID = _kCFRuntimeNotATypeID;
151
152 static pthread_mutex_t CFBundleGlobalDataLock = PTHREAD_MUTEX_INITIALIZER;
153
154 static CFMutableDictionaryRef _bundlesByIdentifier = NULL;
155 #if AVOID_WEAK_COLLECTIONS
156 static CFMutableDictionaryRef _bundlesByURL = NULL;
157 static CFMutableArrayRef _allBundles = NULL;
158 static CFMutableSetRef _bundlesToUnload = NULL;
159 #else /* AVOID_WEAK_COLLECTIONS */
160 static __CFHashTable *_allBundles = nil;
161 static __CFHashTable *_bundlesToUnload = nil;
162 #endif /* AVOID_WEAK_COLLECTIONS */
163 static Boolean _scheduledBundlesAreUnloading = false;
164
165 static Boolean _initedMainBundle = false;
166 static CFBundleRef _mainBundle = NULL;
167
168 // Forward declares functions.
169 static CFBundleRef _CFBundleCreate(CFAllocatorRef allocator, CFURLRef bundleURL, Boolean alreadyLocked, Boolean doFinalProcessing);
170 static CFURLRef _CFBundleCopyExecutableURLIgnoringCache(CFBundleRef bundle);
171 static void _CFBundleEnsureBundlesUpToDateWithHintAlreadyLocked(CFStringRef hint);
172 static void _CFBundleEnsureAllBundlesUpToDateAlreadyLocked(void);
173 static void _CFBundleEnsureBundleExistsForImagePath(CFStringRef imagePath);
174 static void _CFBundleEnsureBundlesExistForImagePaths(CFArrayRef imagePaths);
175
176 #pragma mark -
177
178
179
180
181 #if AVOID_WEAK_COLLECTIONS
182
183 static void _CFBundleAddToTables(CFBundleRef bundle, Boolean alreadyLocked) {
184 CFStringRef bundleID = CFBundleGetIdentifier(bundle);
185
186 if (!alreadyLocked) pthread_mutex_lock(&CFBundleGlobalDataLock);
187
188 // Add to the _allBundles list
189 if (!_allBundles) {
190 CFArrayCallBacks nonRetainingArrayCallbacks = kCFTypeArrayCallBacks;
191 nonRetainingArrayCallbacks.retain = NULL;
192 nonRetainingArrayCallbacks.release = NULL;
193 _allBundles = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &nonRetainingArrayCallbacks);
194 }
195 CFArrayAppendValue(_allBundles, bundle);
196
197 // Add to the table that maps urls to bundles
198 if (!_bundlesByURL) {
199 CFDictionaryValueCallBacks nonRetainingDictionaryValueCallbacks = kCFTypeDictionaryValueCallBacks;
200 nonRetainingDictionaryValueCallbacks.retain = NULL;
201 nonRetainingDictionaryValueCallbacks.release = NULL;
202 _bundlesByURL = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeDictionaryKeyCallBacks, &nonRetainingDictionaryValueCallbacks);
203 }
204 CFDictionarySetValue(_bundlesByURL, bundle->_url, bundle);
205
206 // Add to the table that maps identifiers to bundles
207 if (bundleID) {
208 CFMutableArrayRef bundlesWithThisID = NULL;
209 CFBundleRef existingBundle = NULL;
210 if (!_bundlesByIdentifier) {
211 _bundlesByIdentifier = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
212 }
213 bundlesWithThisID = (CFMutableArrayRef)CFDictionaryGetValue(_bundlesByIdentifier, bundleID);
214 if (bundlesWithThisID) {
215 CFIndex i, count = CFArrayGetCount(bundlesWithThisID);
216 UInt32 existingVersion, newVersion = CFBundleGetVersionNumber(bundle);
217 for (i = 0; i < count; i++) {
218 existingBundle = (CFBundleRef)CFArrayGetValueAtIndex(bundlesWithThisID, i);
219 existingVersion = CFBundleGetVersionNumber(existingBundle);
220 // If you load two bundles with the same identifier and the same version, the last one wins.
221 if (newVersion >= existingVersion) break;
222 }
223 CFArrayInsertValueAtIndex(bundlesWithThisID, i, bundle);
224 } else {
225 CFArrayCallBacks nonRetainingArrayCallbacks = kCFTypeArrayCallBacks;
226 nonRetainingArrayCallbacks.retain = NULL;
227 nonRetainingArrayCallbacks.release = NULL;
228 bundlesWithThisID = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &nonRetainingArrayCallbacks);
229 CFArrayAppendValue(bundlesWithThisID, bundle);
230 CFDictionarySetValue(_bundlesByIdentifier, bundleID, bundlesWithThisID);
231 CFRelease(bundlesWithThisID);
232 }
233 }
234 if (!alreadyLocked) pthread_mutex_unlock(&CFBundleGlobalDataLock);
235 }
236
237 static void _CFBundleRemoveFromTables(CFBundleRef bundle, CFURLRef bundleURL, CFStringRef bundleID) {
238 pthread_mutex_lock(&CFBundleGlobalDataLock);
239 // Remove from the various lists
240 if (_allBundles) {
241 CFIndex i = CFArrayGetFirstIndexOfValue(_allBundles, CFRangeMake(0, CFArrayGetCount(_allBundles)), bundle);
242 if (i >= 0) CFArrayRemoveValueAtIndex(_allBundles, i);
243 }
244
245 // Remove from the table that maps urls to bundles
246 if (bundleURL && _bundlesByURL) {
247 CFBundleRef bundleForURL = (CFBundleRef)CFDictionaryGetValue(_bundlesByURL, bundleURL);
248 if (bundleForURL == bundle) CFDictionaryRemoveValue(_bundlesByURL, bundleURL);
249 }
250
251 // Remove from the table that maps identifiers to bundles
252 if (bundleID && _bundlesByIdentifier) {
253 CFMutableArrayRef bundlesWithThisID = (CFMutableArrayRef)CFDictionaryGetValue(_bundlesByIdentifier, bundleID);
254 if (bundlesWithThisID) {
255 CFIndex count = CFArrayGetCount(bundlesWithThisID);
256 while (count-- > 0) if (bundle == (CFBundleRef)CFArrayGetValueAtIndex(bundlesWithThisID, count)) CFArrayRemoveValueAtIndex(bundlesWithThisID, count);
257 if (0 == CFArrayGetCount(bundlesWithThisID)) CFDictionaryRemoveValue(_bundlesByIdentifier, bundleID);
258 }
259 }
260 pthread_mutex_unlock(&CFBundleGlobalDataLock);
261 }
262
263 static CFBundleRef _CFBundleCopyBundleForURL(CFURLRef url, Boolean alreadyLocked) {
264 CFBundleRef result = NULL;
265 if (!alreadyLocked) pthread_mutex_lock(&CFBundleGlobalDataLock);
266 if (_bundlesByURL) result = (CFBundleRef)CFDictionaryGetValue(_bundlesByURL, url);
267 if (result && !result->_url) {
268 result = NULL;
269 CFDictionaryRemoveValue(_bundlesByURL, url);
270 }
271 if (result) CFRetain(result);
272 if (!alreadyLocked) pthread_mutex_unlock(&CFBundleGlobalDataLock);
273 return result;
274 }
275
276 static CFBundleRef _CFBundlePrimitiveGetBundleWithIdentifierAlreadyLocked(CFStringRef bundleID) {
277 CFBundleRef result = NULL, bundle;
278 if (_bundlesByIdentifier && bundleID) {
279 // Note that this array is maintained in descending order by version number
280 CFArrayRef bundlesWithThisID = (CFArrayRef)CFDictionaryGetValue(_bundlesByIdentifier, bundleID);
281 if (bundlesWithThisID) {
282 CFIndex i, count = CFArrayGetCount(bundlesWithThisID);
283 if (count > 0) {
284 // First check for loaded bundles so we will always prefer a loaded to an unloaded bundle
285 for (i = 0; !result && i < count; i++) {
286 bundle = (CFBundleRef)CFArrayGetValueAtIndex(bundlesWithThisID, i);
287 if (CFBundleIsExecutableLoaded(bundle)) result = bundle;
288 }
289 // If no loaded bundle, simply take the first item in the array, i.e. the one with the latest version number
290 if (!result) result = (CFBundleRef)CFArrayGetValueAtIndex(bundlesWithThisID, 0);
291 }
292 }
293 }
294 return result;
295 }
296
297 #else /* AVOID_WEAK_COLLECTIONS */
298
299 /*
300 An explanation of what I'm doing here is probably in order.
301 8029300 has cast suspicion on the correctness of __CFMapTable with strong keys and weak values, at least under non-GC.
302 An early attempt to work around it by inserting dummy values instead of removing things succeeded, as did turning on the AVOID_WEAK_COLLECTIONS #ifdef
303 This indicates that it's not an overrelease in securityd, since AVOID_WEAK_COLLECTIONS wouldn't help in that case.
304 Therefore, these functions following this comment allow us to have _bundlesByURL be a CFDictionary on non-GC and keep __CFMapTable to GC where it's needed.
305 */
306 static inline id _getBundlesByURL() {
307 static id _bundles = nil;
308 static dispatch_once_t onceToken;
309 dispatch_once(&onceToken, ^{
310 if (CF_USING_COLLECTABLE_MEMORY) {
311 _bundles = [[__CFMapTable alloc] initWithKeyOptions:CFPointerFunctionsStrongMemory valueOptions:CFPointerFunctionsZeroingWeakMemory capacity:0];
312 } else {
313 CFDictionaryValueCallBacks nonRetainingDictionaryValueCallbacks = kCFTypeDictionaryValueCallBacks;
314 nonRetainingDictionaryValueCallbacks.retain = NULL;
315 nonRetainingDictionaryValueCallbacks.release = NULL;
316 _bundles = (id)CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeDictionaryKeyCallBacks, &nonRetainingDictionaryValueCallbacks);
317 }
318 });
319 return _bundles;
320 }
321
322 #define _bundlesByURL _getBundlesByURL()
323
324 static void _setInBundlesByURL(CFURLRef key, CFBundleRef bundle) {
325 if (CF_USING_COLLECTABLE_MEMORY) {
326 [(__CFMapTable *)_bundlesByURL setObject:(id)bundle forKey:(id)key];
327 } else {
328 CFDictionarySetValue((CFMutableDictionaryRef)_bundlesByURL, key, bundle);
329 }
330 }
331
332 static void _removeFromBundlesByURL(CFURLRef key) {
333 if (CF_USING_COLLECTABLE_MEMORY) {
334 [(__CFMapTable *)_bundlesByURL removeObjectForKey:(id)key];
335 } else {
336 CFDictionaryRemoveValue((CFMutableDictionaryRef)_bundlesByURL, key);
337 }
338 }
339
340 static CFBundleRef _getFromBundlesByURL(CFURLRef key) {
341 if (CF_USING_COLLECTABLE_MEMORY) {
342 return (CFBundleRef)[(__CFMapTable *)_bundlesByURL objectForKey:(id)key];
343 } else {
344 return (CFBundleRef)CFDictionaryGetValue((CFMutableDictionaryRef)_bundlesByURL, key);
345 }
346 }
347
348 static void _CFBundleAddToTables(CFBundleRef bundle, Boolean alreadyLocked) {
349 CFStringRef bundleID = CFBundleGetIdentifier(bundle);
350
351 if (!alreadyLocked) pthread_mutex_lock(&CFBundleGlobalDataLock);
352
353 // Add to the _allBundles list
354 if (!_allBundles) _allBundles = [[__CFHashTable alloc] initWithOptions:CFPointerFunctionsZeroingWeakMemory capacity:0];
355 [_allBundles addObject:(id)bundle];
356
357 // Add to the table that maps urls to bundles
358 _setInBundlesByURL(bundle->_url, bundle);
359
360 // Add to the table that maps identifiers to bundles
361 if (bundleID) {
362 __CFPointerArray *bundlesWithThisID = nil;
363 CFBundleRef existingBundle = NULL;
364 if (!_bundlesByIdentifier) {
365 _bundlesByIdentifier = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
366 }
367 bundlesWithThisID = (__CFPointerArray *)CFDictionaryGetValue(_bundlesByIdentifier, bundleID);
368 if (bundlesWithThisID) {
369 CFIndex i, count = (CFIndex)[bundlesWithThisID count];
370 UInt32 existingVersion, newVersion = CFBundleGetVersionNumber(bundle);
371 for (i = 0; i < count; i++) {
372 existingBundle = (CFBundleRef)[bundlesWithThisID pointerAtIndex:i];
373 if (!existingBundle) continue;
374 existingVersion = CFBundleGetVersionNumber(existingBundle);
375 // If you load two bundles with the same identifier and the same version, the last one wins.
376 if (newVersion >= existingVersion) break;
377 }
378 if (i < count) {
379 [bundlesWithThisID insertPointer:bundle atIndex:i];
380 } else {
381 [bundlesWithThisID addPointer:bundle];
382 }
383 } else {
384 bundlesWithThisID = [[__CFPointerArray alloc] initWithOptions:CFPointerFunctionsZeroingWeakMemory];
385 [bundlesWithThisID addPointer:bundle];
386 CFDictionarySetValue(_bundlesByIdentifier, bundleID, bundlesWithThisID);
387 [bundlesWithThisID release];
388 }
389 }
390 if (!alreadyLocked) pthread_mutex_unlock(&CFBundleGlobalDataLock);
391 }
392
393 static void _CFBundleRemoveFromTables(CFBundleRef bundle, CFURLRef bundleURL, CFStringRef bundleID) {
394 pthread_mutex_lock(&CFBundleGlobalDataLock);
395 // Remove from the various lists
396 if (_allBundles && [_allBundles member:(id)bundle]) [_allBundles removeObject:(id)bundle];
397
398 // Remove from the table that maps urls to bundles
399 if (bundleURL) {
400 _removeFromBundlesByURL(bundleURL);
401 }
402
403 // Remove from the table that maps identifiers to bundles
404 if (bundleID && _bundlesByIdentifier) {
405 __CFPointerArray *bundlesWithThisID = (__CFPointerArray *)CFDictionaryGetValue(_bundlesByIdentifier, bundleID);
406 if (bundlesWithThisID) {
407 CFIndex count = (CFIndex)[bundlesWithThisID count];
408 while (count-- > 0) if (bundle == (CFBundleRef)[bundlesWithThisID pointerAtIndex:count]) [bundlesWithThisID removePointerAtIndex:count];
409 [bundlesWithThisID compact];
410 if (0 == [bundlesWithThisID count]) CFDictionaryRemoveValue(_bundlesByIdentifier, bundleID);
411 }
412 }
413 pthread_mutex_unlock(&CFBundleGlobalDataLock);
414 }
415
416 static CFBundleRef _CFBundleCopyBundleForURL(CFURLRef url, Boolean alreadyLocked) {
417 CFBundleRef result = NULL;
418 if (!alreadyLocked) pthread_mutex_lock(&CFBundleGlobalDataLock);
419 result = _getFromBundlesByURL(url);
420 if (result && !result->_url) {
421 result = NULL;
422 _removeFromBundlesByURL(url);
423 }
424 if (result) CFRetain(result);
425 if (!alreadyLocked) pthread_mutex_unlock(&CFBundleGlobalDataLock);
426 return result;
427 }
428
429 static CFBundleRef _CFBundlePrimitiveGetBundleWithIdentifierAlreadyLocked(CFStringRef bundleID) {
430 CFBundleRef result = NULL;
431 if (_bundlesByIdentifier && bundleID) {
432 // Note that this array is maintained in descending order by version number
433 __CFPointerArray *bundlesWithThisID = (__CFPointerArray *)CFDictionaryGetValue(_bundlesByIdentifier, bundleID);
434 if (bundlesWithThisID && [bundlesWithThisID count] > 0) {
435 // First check for loaded bundles so we will always prefer a loaded to an unloaded bundle
436 for (id bundle in bundlesWithThisID) {
437 if (bundle && CFBundleIsExecutableLoaded((CFBundleRef)bundle)) {
438 result = (CFBundleRef)bundle;
439 break;
440 }
441 }
442 // If no loaded bundle, simply take the first item in the array, i.e. the one with the latest version number
443 if (!result) {
444 for (id bundle in bundlesWithThisID) {
445 if (bundle) {
446 result = (CFBundleRef)bundle;
447 break;
448 }
449 }
450 }
451 }
452 }
453 return result;
454 }
455
456 #endif /* AVOID_WEAK_COLLECTIONS */
457
458 static CFURLRef _CFBundleCopyBundleURLForExecutablePath(CFStringRef str) {
459 //!!! need to handle frameworks, NT; need to integrate with NSBundle - drd
460 UniChar buff[CFMaxPathSize];
461 CFIndex buffLen;
462 CFURLRef url = NULL;
463 CFStringRef outstr;
464
465 buffLen = CFStringGetLength(str);
466 if (buffLen > CFMaxPathSize) buffLen = CFMaxPathSize;
467 CFStringGetCharacters(str, CFRangeMake(0, buffLen), buff);
468
469 #if DEPLOYMENT_TARGET_WINDOWS
470 // Is this a .dll or .exe?
471 if (buffLen >= 5 && (_wcsnicmp((wchar_t *)&(buff[buffLen-4]), L".dll", 4) == 0 || _wcsnicmp((wchar_t *)&(buff[buffLen-4]), L".exe", 4) == 0)) {
472 CFIndex extensionLength = CFStringGetLength(_CFBundleWindowsResourceDirectoryExtension);
473 buffLen -= 4;
474 // If this is an _debug, we should strip that before looking for the bundle
475 if (buffLen >= 7 && (_wcsnicmp((wchar_t *)&buff[buffLen-6], L"_debug", 6) == 0)) buffLen -= 6;
476
477 if (buffLen + 1 + extensionLength < CFMaxPathSize) {
478 buff[buffLen] = '.';
479 buffLen ++;
480 CFStringGetCharacters(_CFBundleWindowsResourceDirectoryExtension, CFRangeMake(0, extensionLength), buff + buffLen);
481 buffLen += extensionLength;
482 outstr = CFStringCreateWithCharactersNoCopy(kCFAllocatorSystemDefault, buff, buffLen, kCFAllocatorNull);
483 url = CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault, outstr, PLATFORM_PATH_STYLE, true);
484 CFRelease(outstr);
485 }
486 }
487 #endif
488
489 if (!url) {
490 buffLen = _CFLengthAfterDeletingLastPathComponent(buff, buffLen); // Remove exe name
491
492 if (buffLen > 0) {
493 // See if this is a new bundle. If it is, we have to remove more path components.
494 CFIndex startOfLastDir = _CFStartOfLastPathComponent(buff, buffLen);
495 if (startOfLastDir > 0 && startOfLastDir < buffLen) {
496 CFStringRef lastDirName = CFStringCreateWithCharacters(kCFAllocatorSystemDefault, &(buff[startOfLastDir]), buffLen - startOfLastDir);
497
498 if (CFEqual(lastDirName, _CFBundleGetPlatformExecutablesSubdirectoryName()) || CFEqual(lastDirName, _CFBundleGetAlternatePlatformExecutablesSubdirectoryName()) || CFEqual(lastDirName, _CFBundleGetOtherPlatformExecutablesSubdirectoryName()) || CFEqual(lastDirName, _CFBundleGetOtherAlternatePlatformExecutablesSubdirectoryName())) {
499 // This is a new bundle. Back off a few more levels
500 if (buffLen > 0) {
501 // Remove platform folder
502 buffLen = _CFLengthAfterDeletingLastPathComponent(buff, buffLen);
503 }
504 if (buffLen > 0) {
505 // Remove executables folder (if present)
506 CFIndex startOfNextDir = _CFStartOfLastPathComponent(buff, buffLen);
507 if (startOfNextDir > 0 && startOfNextDir < buffLen) {
508 CFStringRef nextDirName = CFStringCreateWithCharacters(kCFAllocatorSystemDefault, &(buff[startOfNextDir]), buffLen - startOfNextDir);
509 if (CFEqual(nextDirName, _CFBundleExecutablesDirectoryName)) buffLen = _CFLengthAfterDeletingLastPathComponent(buff, buffLen);
510 CFRelease(nextDirName);
511 }
512 }
513 if (buffLen > 0) {
514 // Remove support files folder
515 buffLen = _CFLengthAfterDeletingLastPathComponent(buff, buffLen);
516 }
517 }
518 CFRelease(lastDirName);
519 }
520 }
521
522 if (buffLen > 0) {
523 outstr = CFStringCreateWithCharactersNoCopy(kCFAllocatorSystemDefault, buff, buffLen, kCFAllocatorNull);
524 url = CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault, outstr, PLATFORM_PATH_STYLE, true);
525 CFRelease(outstr);
526 }
527 }
528 return url;
529 }
530
531 static CFURLRef _CFBundleCopyResolvedURLForExecutableURL(CFURLRef url) {
532 // this is necessary so that we match any sanitization CFURL may perform on the result of _CFBundleCopyBundleURLForExecutableURL()
533 CFURLRef absoluteURL, url1, url2, outURL = NULL;
534 CFStringRef str, str1, str2;
535 absoluteURL = CFURLCopyAbsoluteURL(url);
536 str = CFURLCopyFileSystemPath(absoluteURL, PLATFORM_PATH_STYLE);
537 if (str) {
538 UniChar buff[CFMaxPathSize];
539 CFIndex buffLen = CFStringGetLength(str), len1;
540 if (buffLen > CFMaxPathSize) buffLen = CFMaxPathSize;
541 CFStringGetCharacters(str, CFRangeMake(0, buffLen), buff);
542 len1 = _CFLengthAfterDeletingLastPathComponent(buff, buffLen);
543 if (len1 > 0 && len1 + 1 < buffLen) {
544 str1 = CFStringCreateWithCharacters(kCFAllocatorSystemDefault, buff, len1);
545 CFIndex skipSlashCount = 1;
546 #if DEPLOYMENT_TARGET_WINDOWS
547 // On Windows, _CFLengthAfterDeletingLastPathComponent will return a value of 3 if the path is at the root (e.g. C:\). This includes the \, which is not the case for URLs with subdirectories
548 if (len1 == 3 && buff[1] == ':' && buff[2] == '\\') {
549 skipSlashCount = 0;
550 }
551 #endif
552 str2 = CFStringCreateWithCharacters(kCFAllocatorSystemDefault, buff + len1 + skipSlashCount, buffLen - len1 - skipSlashCount);
553 if (str1 && str2) {
554 url1 = CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault, str1, PLATFORM_PATH_STYLE, true);
555 if (url1) {
556 url2 = CFURLCreateWithFileSystemPathRelativeToBase(kCFAllocatorSystemDefault, str2, PLATFORM_PATH_STYLE, false, url1);
557 if (url2) {
558 outURL = CFURLCopyAbsoluteURL(url2);
559 CFRelease(url2);
560 }
561 CFRelease(url1);
562 }
563 }
564 if (str1) CFRelease(str1);
565 if (str2) CFRelease(str2);
566 }
567 CFRelease(str);
568 }
569 if (!outURL) {
570 outURL = absoluteURL;
571 } else {
572 CFRelease(absoluteURL);
573 }
574 return outURL;
575 }
576
577 CFURLRef _CFBundleCopyBundleURLForExecutableURL(CFURLRef url) {
578 CFURLRef resolvedURL, outurl = NULL;
579 CFStringRef str;
580 resolvedURL = _CFBundleCopyResolvedURLForExecutableURL(url);
581 str = CFURLCopyFileSystemPath(resolvedURL, PLATFORM_PATH_STYLE);
582 if (str) {
583 outurl = _CFBundleCopyBundleURLForExecutablePath(str);
584 CFRelease(str);
585 }
586 CFRelease(resolvedURL);
587 return outurl;
588 }
589
590 static uint8_t _CFBundleEffectiveLayoutVersion(CFBundleRef bundle) {
591 uint8_t localVersion = bundle->_version;
592 // exclude type 0 bundles with no binary (or CFM binary) and no Info.plist, since they give too many false positives
593 if (0 == localVersion) {
594 CFDictionaryRef infoDict = CFBundleGetInfoDictionary(bundle);
595 if (!infoDict || 0 == CFDictionaryGetCount(infoDict)) {
596 #if defined(BINARY_SUPPORT_DYLD)
597 CFURLRef executableURL = CFBundleCopyExecutableURL(bundle);
598 if (executableURL) {
599 if (bundle->_binaryType == __CFBundleUnknownBinary) bundle->_binaryType = _CFBundleGrokBinaryType(executableURL);
600 if (bundle->_binaryType == __CFBundleCFMBinary || bundle->_binaryType == __CFBundleUnreadableBinary) {
601 localVersion = 4;
602 } else {
603 bundle->_resourceData._executableLacksResourceFork = true;
604 }
605 CFRelease(executableURL);
606 } else {
607 localVersion = 4;
608 }
609 #else
610 CFURLRef executableURL = CFBundleCopyExecutableURL(bundle);
611 if (executableURL) {
612 CFRelease(executableURL);
613 } else {
614 localVersion = 4;
615 }
616 #endif /* BINARY_SUPPORT_DYLD */
617 }
618 }
619 return localVersion;
620 }
621
622 CFBundleRef _CFBundleCreateIfLooksLikeBundle(CFAllocatorRef allocator, CFURLRef url) {
623 CFBundleRef bundle = CFBundleCreate(allocator, url);
624 if (bundle) {
625 uint8_t localVersion = _CFBundleEffectiveLayoutVersion(bundle);
626 if (3 == localVersion || 4 == localVersion) {
627 CFRelease(bundle);
628 bundle = NULL;
629 }
630 }
631 return bundle;
632 }
633
634 CF_EXPORT Boolean _CFBundleURLLooksLikeBundle(CFURLRef url) {
635 Boolean result = false;
636 CFBundleRef bundle = _CFBundleCreateIfLooksLikeBundle(kCFAllocatorSystemDefault, url);
637 if (bundle) {
638 result = true;
639 CFRelease(bundle);
640 }
641 return result;
642 }
643
644 CFBundleRef _CFBundleGetMainBundleIfLooksLikeBundle(void) {
645 CFBundleRef mainBundle = CFBundleGetMainBundle();
646 if (mainBundle && (3 == mainBundle->_version || 4 == mainBundle->_version)) mainBundle = NULL;
647 return mainBundle;
648 }
649
650 Boolean _CFBundleMainBundleInfoDictionaryComesFromResourceFork(void) {
651 CFBundleRef mainBundle = CFBundleGetMainBundle();
652 return (mainBundle && mainBundle->_resourceData._infoDictionaryFromResourceFork);
653 }
654
655 CFBundleRef _CFBundleCreateWithExecutableURLIfLooksLikeBundle(CFAllocatorRef allocator, CFURLRef url) {
656 CFBundleRef bundle = NULL;
657 CFURLRef bundleURL = _CFBundleCopyBundleURLForExecutableURL(url), resolvedURL = _CFBundleCopyResolvedURLForExecutableURL(url);
658 if (bundleURL && resolvedURL) {
659 // We used to call _CFBundleCreateIfLooksLikeBundle here, but switched to the regular CFBundleCreate because we want this to return a result for certain flat bundles as well.
660 bundle = CFBundleCreate(allocator, bundleURL);
661 if (bundle) {
662 CFURLRef executableURL = _CFBundleCopyExecutableURLIgnoringCache(bundle);
663 char buff1[CFMaxPathSize], buff2[CFMaxPathSize];
664 if (!executableURL || !CFURLGetFileSystemRepresentation(resolvedURL, true, (uint8_t *)buff1, CFMaxPathSize) || !CFURLGetFileSystemRepresentation(executableURL, true, (uint8_t *)buff2, CFMaxPathSize) || 0 != strcmp(buff1, buff2)) {
665 CFRelease(bundle);
666 bundle = NULL;
667 }
668 if (executableURL) CFRelease(executableURL);
669 }
670 }
671 if (bundleURL) CFRelease(bundleURL);
672 if (resolvedURL) CFRelease(resolvedURL);
673 return bundle;
674 }
675
676 CFBundleRef _CFBundleCreateIfMightBeBundle(CFAllocatorRef allocator, CFURLRef url) {
677 // This function is obsolete
678 CFBundleRef bundle = CFBundleCreate(allocator, url);
679 return bundle;
680 }
681
682 CFBundleRef _CFBundleCreateWithExecutableURLIfMightBeBundle(CFAllocatorRef allocator, CFURLRef url) {
683 CFBundleRef result = _CFBundleCreateWithExecutableURLIfLooksLikeBundle(allocator, url);
684
685 // This function applies additional requirements on a bundle to return a result
686 // The above makes sure that:
687 // 0. CFBundleCreate must succeed using a URL derived from the executable URL
688 // 1. The bundle must have an executableURL, and it must match the passed in executable URL
689
690 // This function additionally requires that
691 // 2. If flat, the bundle must have a non-empty Info.plist. (15663535)
692 if (result) {
693 uint8_t localVersion = _CFBundleEffectiveLayoutVersion(result);
694 if (3 == localVersion || 4 == localVersion) {
695 CFDictionaryRef infoPlist = CFBundleGetInfoDictionary(result);
696 if (!infoPlist || (infoPlist && CFDictionaryGetCount(infoPlist) == 0)) {
697 CFRelease(result);
698 result = NULL;
699 }
700 }
701 }
702 return result;
703 }
704
705 CFURLRef _CFBundleCopyMainBundleExecutableURL(Boolean *looksLikeBundle) {
706 // This function is for internal use only; _mainBundle is deliberately accessed outside of the lock to get around a reentrancy issue
707 const char *processPath;
708 CFStringRef str = NULL;
709 CFURLRef executableURL = NULL;
710 processPath = _CFProcessPath();
711 if (processPath) {
712 str = CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault, processPath);
713 if (str) {
714 executableURL = CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault, str, PLATFORM_PATH_STYLE, false);
715 CFRelease(str);
716 }
717 }
718 if (looksLikeBundle) {
719 CFBundleRef mainBundle = _mainBundle;
720 if (mainBundle && (3 == mainBundle->_version || 4 == mainBundle->_version)) mainBundle = NULL;
721 *looksLikeBundle = (mainBundle ? true : false);
722 }
723 return executableURL;
724 }
725
726 static void _CFBundleInitializeMainBundleInfoDictionaryAlreadyLocked(CFStringRef executablePath) {
727 CFBundleGetInfoDictionary(_mainBundle);
728 if (!_mainBundle->_infoDict || CFDictionaryGetCount(_mainBundle->_infoDict) == 0) {
729 // if type 3 bundle and no Info.plist, treat as unbundled, since this gives too many false positives
730 if (_mainBundle->_version == 3) _mainBundle->_version = 4;
731 if (_mainBundle->_version == 0) {
732 // if type 0 bundle and no Info.plist and not main executable for bundle, treat as unbundled, since this gives too many false positives
733 CFStringRef executableName = _CFBundleCopyExecutableName(_mainBundle, NULL, NULL);
734 if (!executableName || !executablePath || !CFStringHasSuffix(executablePath, executableName)) _mainBundle->_version = 4;
735 if (executableName) CFRelease(executableName);
736 }
737 #if defined(BINARY_SUPPORT_DYLD)
738 if (_mainBundle->_binaryType == __CFBundleDYLDExecutableBinary) {
739 if (_mainBundle->_infoDict && !(0)) CFRelease(_mainBundle->_infoDict);
740 _mainBundle->_infoDict = (CFDictionaryRef)_CFBundleCreateInfoDictFromMainExecutable();
741 }
742 #endif /* BINARY_SUPPORT_DYLD */
743 } else {
744 #if defined(BINARY_SUPPORT_DYLD)
745 if (_mainBundle->_binaryType == __CFBundleDYLDExecutableBinary) {
746 // if dyld and not main executable for bundle, prefer info dictionary from executable
747 CFStringRef executableName = _CFBundleCopyExecutableName(_mainBundle, NULL, NULL);
748 if (!executableName || !executablePath || !CFStringHasSuffix(executablePath, executableName)) {
749 CFDictionaryRef infoDictFromExecutable = (CFDictionaryRef)_CFBundleCreateInfoDictFromMainExecutable();
750 if (infoDictFromExecutable && CFDictionaryGetCount(infoDictFromExecutable) > 0) {
751 if (_mainBundle->_infoDict) CFRelease(_mainBundle->_infoDict);
752 _mainBundle->_infoDict = infoDictFromExecutable;
753 } else if (infoDictFromExecutable) {
754 CFRelease(infoDictFromExecutable);
755 }
756 }
757 if (executableName) CFRelease(executableName);
758 }
759 #endif /* BINARY_SUPPORT_DYLD */
760 }
761 if (!_mainBundle->_infoDict) _mainBundle->_infoDict = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
762 if (!_mainBundle->_executablePath && executablePath) _mainBundle->_executablePath = (CFStringRef)CFRetain(executablePath);
763 CFStringRef bundleID = (CFStringRef)CFDictionaryGetValue(_mainBundle->_infoDict, kCFBundleIdentifierKey);
764 if (bundleID) {
765 if (!CFStringGetCString(bundleID, __CFBundleMainID__, sizeof(__CFBundleMainID__) - 2, kCFStringEncodingUTF8)) {
766 __CFBundleMainID__[0] = '\0';
767 }
768 }
769 }
770
771 static void _CFBundleFlushBundleCachesAlreadyLocked(CFBundleRef bundle, Boolean alreadyLocked) {
772 CFDictionaryRef oldInfoDict = bundle->_infoDict;
773 CFTypeRef val;
774
775 bundle->_infoDict = NULL;
776 if (bundle->_localInfoDict) {
777 CFRelease(bundle->_localInfoDict);
778 bundle->_localInfoDict = NULL;
779 }
780 if (bundle->_developmentRegion) {
781 CFRelease(bundle->_developmentRegion);
782 bundle->_developmentRegion = NULL;
783 }
784 if (bundle->_executablePath) {
785 CFRelease(bundle->_executablePath);
786 bundle->_executablePath = NULL;
787 }
788 if (bundle->_searchLanguages) {
789 CFRelease(bundle->_searchLanguages);
790 bundle->_searchLanguages = NULL;
791 }
792 if (bundle->_stringTable) {
793 CFRelease(bundle->_stringTable);
794 bundle->_stringTable = NULL;
795 }
796 if (bundle == _mainBundle) {
797 CFStringRef executablePath = bundle->_executablePath;
798 if (!alreadyLocked) pthread_mutex_lock(&CFBundleGlobalDataLock);
799 _CFBundleInitializeMainBundleInfoDictionaryAlreadyLocked(executablePath);
800 if (!alreadyLocked) pthread_mutex_unlock(&CFBundleGlobalDataLock);
801 } else {
802 CFBundleGetInfoDictionary(bundle);
803 }
804 if (oldInfoDict) {
805 if (!bundle->_infoDict) bundle->_infoDict = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
806 val = CFDictionaryGetValue(oldInfoDict, _kCFBundlePrincipalClassKey);
807 if (val) CFDictionarySetValue((CFMutableDictionaryRef)bundle->_infoDict, _kCFBundlePrincipalClassKey, val);
808 CFRelease(oldInfoDict);
809 }
810
811 _CFBundleFlushQueryTableCache(bundle);
812 }
813
814 CF_EXPORT void _CFBundleFlushBundleCaches(CFBundleRef bundle) {
815 _CFBundleFlushBundleCachesAlreadyLocked(bundle, false);
816 }
817
818 static CFBundleRef _CFBundleGetMainBundleAlreadyLocked(void) {
819 if (!_initedMainBundle) {
820 const char *processPath;
821 CFStringRef str = NULL;
822 CFURLRef executableURL = NULL, bundleURL = NULL;
823 _initedMainBundle = true;
824 processPath = _CFProcessPath();
825 if (processPath) {
826 str = CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault, processPath);
827 if (!executableURL) executableURL = CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault, str, PLATFORM_PATH_STYLE, false);
828 }
829 if (executableURL) bundleURL = _CFBundleCopyBundleURLForExecutableURL(executableURL);
830 if (bundleURL) {
831 // make sure that main bundle has executable path
832 //??? what if we are not the main executable in the bundle?
833 // NB doFinalProcessing must be false here, see below
834 _mainBundle = _CFBundleCreate(kCFAllocatorSystemDefault, bundleURL, true, false);
835 if (_mainBundle) {
836 // make sure that the main bundle is listed as loaded, and mark it as executable
837 _mainBundle->_isLoaded = true;
838 #if defined(BINARY_SUPPORT_DYLD)
839 if (_mainBundle->_binaryType == __CFBundleUnknownBinary) {
840 if (!executableURL) {
841 _mainBundle->_binaryType = __CFBundleNoBinary;
842 } else {
843 _mainBundle->_binaryType = _CFBundleGrokBinaryType(executableURL);
844 if (_mainBundle->_binaryType != __CFBundleCFMBinary && _mainBundle->_binaryType != __CFBundleUnreadableBinary) _mainBundle->_resourceData._executableLacksResourceFork = true;
845 }
846 }
847 #endif /* BINARY_SUPPORT_DYLD */
848 // get cookie for already-loaded main bundle
849 #if defined(BINARY_SUPPORT_DLFCN)
850 if (!_mainBundle->_handleCookie) {
851 _mainBundle->_handleCookie = dlopen(NULL, RTLD_NOLOAD | RTLD_FIRST);
852 #if LOG_BUNDLE_LOAD
853 printf("main bundle %p getting handle %p\n", _mainBundle, _mainBundle->_handleCookie);
854 #endif /* LOG_BUNDLE_LOAD */
855 }
856 #elif defined(BINARY_SUPPORT_DYLD)
857 if (_mainBundle->_binaryType == __CFBundleDYLDExecutableBinary && !_mainBundle->_imageCookie) {
858 _mainBundle->_imageCookie = (void *)_dyld_get_image_header(0);
859 #if LOG_BUNDLE_LOAD
860 printf("main bundle %p getting image %p\n", _mainBundle, _mainBundle->_imageCookie);
861 #endif /* LOG_BUNDLE_LOAD */
862 }
863 #endif /* BINARY_SUPPORT_DLFCN */
864 _CFBundleInitializeMainBundleInfoDictionaryAlreadyLocked(str);
865 // Perform delayed final processing steps.
866 // This must be done after _isLoaded has been set, for security reasons (3624341).
867 if (_CFBundleNeedsInitPlugIn(_mainBundle)) {
868 pthread_mutex_unlock(&CFBundleGlobalDataLock);
869 _CFBundleInitPlugIn(_mainBundle);
870 pthread_mutex_lock(&CFBundleGlobalDataLock);
871 }
872 }
873 }
874 if (bundleURL) CFRelease(bundleURL);
875 if (str) CFRelease(str);
876 if (executableURL) CFRelease(executableURL);
877 }
878 return _mainBundle;
879 }
880
881 CFBundleRef CFBundleGetMainBundle(void) {
882 CFBundleRef mainBundle;
883 pthread_mutex_lock(&CFBundleGlobalDataLock);
884 mainBundle = _CFBundleGetMainBundleAlreadyLocked();
885 pthread_mutex_unlock(&CFBundleGlobalDataLock);
886 return mainBundle;
887 }
888
889 CFBundleRef CFBundleGetBundleWithIdentifier(CFStringRef bundleID) {
890 CFBundleRef result = NULL;
891 if (bundleID) {
892 pthread_mutex_lock(&CFBundleGlobalDataLock);
893 (void)_CFBundleGetMainBundleAlreadyLocked();
894 result = _CFBundlePrimitiveGetBundleWithIdentifierAlreadyLocked(bundleID);
895 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
896 if (!result) {
897 // Try to create the bundle for the caller and try again
898 void *p = __builtin_return_address(0);
899 if (p) {
900 CFStringRef imagePath = _CFBundleCopyLoadedImagePathForPointer(p);
901 if (imagePath) {
902 _CFBundleEnsureBundleExistsForImagePath(imagePath);
903 CFRelease(imagePath);
904 }
905 result = _CFBundlePrimitiveGetBundleWithIdentifierAlreadyLocked(bundleID);
906 }
907 }
908 #endif
909 if (!result) {
910 // Try to guess the bundle from the identifier and try again
911 _CFBundleEnsureBundlesUpToDateWithHintAlreadyLocked(bundleID);
912 result = _CFBundlePrimitiveGetBundleWithIdentifierAlreadyLocked(bundleID);
913 }
914 if (!result) {
915 // Make sure all bundles have been created and try again.
916 _CFBundleEnsureAllBundlesUpToDateAlreadyLocked();
917 result = _CFBundlePrimitiveGetBundleWithIdentifierAlreadyLocked(bundleID);
918 }
919 pthread_mutex_unlock(&CFBundleGlobalDataLock);
920 }
921 return result;
922 }
923
924 static CFStringRef __CFBundleCopyDescription(CFTypeRef cf) {
925 char buff[CFMaxPathSize];
926 CFStringRef path = NULL, binaryType = NULL, retval = NULL;
927 if (((CFBundleRef)cf)->_url && CFURLGetFileSystemRepresentation(((CFBundleRef)cf)->_url, true, (uint8_t *)buff, CFMaxPathSize)) path = CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault, buff);
928 switch (((CFBundleRef)cf)->_binaryType) {
929 case __CFBundleCFMBinary:
930 binaryType = CFSTR("");
931 break;
932 case __CFBundleDYLDExecutableBinary:
933 binaryType = CFSTR("executable, ");
934 break;
935 case __CFBundleDYLDBundleBinary:
936 binaryType = CFSTR("bundle, ");
937 break;
938 case __CFBundleDYLDFrameworkBinary:
939 binaryType = CFSTR("framework, ");
940 break;
941 case __CFBundleDLLBinary:
942 binaryType = CFSTR("DLL, ");
943 break;
944 case __CFBundleUnreadableBinary:
945 binaryType = CFSTR("");
946 break;
947 default:
948 binaryType = CFSTR("");
949 break;
950 }
951 if (((CFBundleRef)cf)->_plugInData._isPlugIn) {
952 retval = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("CFBundle/CFPlugIn %p <%@> (%@%@loaded)"), cf, path, binaryType, ((CFBundleRef)cf)->_isLoaded ? CFSTR("") : CFSTR("not "));
953 } else {
954 retval = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("CFBundle %p <%@> (%@%@loaded)"), cf, path, binaryType, ((CFBundleRef)cf)->_isLoaded ? CFSTR("") : CFSTR("not "));
955 }
956 if (path) CFRelease(path);
957 return retval;
958 }
959
960 static void _CFBundleDeallocateGlue(const void *key, const void *value, void *context) {
961 CFAllocatorRef allocator = (CFAllocatorRef)context;
962 if (value) CFAllocatorDeallocate(allocator, (void *)value);
963 }
964
965 static void __CFBundleDeallocate(CFTypeRef cf) {
966 CFBundleRef bundle = (CFBundleRef)cf;
967 CFURLRef bundleURL;
968 CFStringRef bundleID = NULL;
969
970 __CFGenericValidateType(cf, CFBundleGetTypeID());
971 bundleURL = bundle->_url;
972 bundle->_url = NULL;
973 if (bundle->_infoDict) bundleID = (CFStringRef)CFDictionaryGetValue(bundle->_infoDict, kCFBundleIdentifierKey);
974 _CFBundleRemoveFromTables(bundle, bundleURL, bundleID);
975 CFBundleUnloadExecutable(bundle);
976 _CFBundleDeallocatePlugIn(bundle);
977 if (bundleURL) {
978 CFRelease(bundleURL);
979 }
980 if (bundle->_infoDict && !(0)) CFRelease(bundle->_infoDict);
981 if (bundle->_modDate) CFRelease(bundle->_modDate);
982 if (bundle->_localInfoDict && !(0)) CFRelease(bundle->_localInfoDict);
983 if (bundle->_searchLanguages) CFRelease(bundle->_searchLanguages);
984 if (bundle->_executablePath) CFRelease(bundle->_executablePath);
985 if (bundle->_developmentRegion) CFRelease(bundle->_developmentRegion);
986 if (bundle->_glueDict) {
987 CFDictionaryApplyFunction(bundle->_glueDict, _CFBundleDeallocateGlue, (void *)CFGetAllocator(bundle));
988 CFRelease(bundle->_glueDict);
989 }
990 if (bundle->_stringTable) CFRelease(bundle->_stringTable);
991
992 if (bundle->_bundleBasePath) CFRelease(bundle->_bundleBasePath);
993 if (bundle->_queryTable) CFRelease(bundle->_queryTable);
994
995 if (bundle->_localizations) CFRelease(bundle->_localizations);
996 if (bundle->_resourceDirectoryContents) CFRelease(bundle->_resourceDirectoryContents);
997
998 pthread_mutex_destroy(&(bundle->_bundleLoadingLock));
999 }
1000
1001 static const CFRuntimeClass __CFBundleClass = {
1002 _kCFRuntimeScannedObject,
1003 "CFBundle",
1004 NULL, // init
1005 NULL, // copy
1006 __CFBundleDeallocate,
1007 NULL, // equal
1008 NULL, // hash
1009 NULL, //
1010 __CFBundleCopyDescription
1011 };
1012
1013 // From CFBundle_Resources.c
1014 CF_PRIVATE void _CFBundleResourcesInitialize();
1015
1016 CFTypeID CFBundleGetTypeID(void) {
1017 static dispatch_once_t initOnce;
1018 dispatch_once(&initOnce, ^{ __kCFBundleTypeID = _CFRuntimeRegisterClass(&__CFBundleClass); _CFBundleResourcesInitialize(); });
1019 return __kCFBundleTypeID;
1020 }
1021
1022 CFBundleRef _CFBundleGetExistingBundleWithBundleURL(CFURLRef bundleURL) {
1023 CFBundleRef bundle = NULL;
1024 char buff[CFMaxPathSize];
1025 CFURLRef newURL = NULL;
1026
1027 if (!CFURLGetFileSystemRepresentation(bundleURL, true, (uint8_t *)buff, CFMaxPathSize)) return NULL;
1028
1029 newURL = CFURLCreateFromFileSystemRepresentation(kCFAllocatorSystemDefault, (uint8_t *)buff, strlen(buff), true);
1030 if (!newURL) newURL = (CFURLRef)CFRetain(bundleURL);
1031 bundle = _CFBundleCopyBundleForURL(newURL, false);
1032 if (bundle) CFRelease(bundle);
1033 CFRelease(newURL);
1034 return bundle;
1035 }
1036
1037 static CFBundleRef _CFBundleCreate(CFAllocatorRef allocator, CFURLRef bundleURL, Boolean alreadyLocked, Boolean doFinalProcessing) {
1038 CFBundleRef bundle = NULL;
1039 char buff[CFMaxPathSize];
1040 CFDateRef modDate = NULL; // do not actually fetch the modDate, since that can cause something like 7609956, unless absolutely found to be necessary in the future
1041 Boolean exists = false;
1042 SInt32 mode = 0;
1043 CFURLRef newURL = NULL;
1044 uint8_t localVersion = 0;
1045
1046 if (!CFURLGetFileSystemRepresentation(bundleURL, true, (uint8_t *)buff, CFMaxPathSize)) return NULL;
1047
1048 newURL = CFURLCreateFromFileSystemRepresentation(allocator, (uint8_t *)buff, strlen(buff), true);
1049 if (!newURL) newURL = (CFURLRef)CFRetain(bundleURL);
1050 bundle = _CFBundleCopyBundleForURL(newURL, alreadyLocked);
1051 if (bundle) {
1052 CFRelease(newURL);
1053 return bundle;
1054 }
1055
1056 localVersion = _CFBundleGetBundleVersionForURL(newURL);
1057 if (localVersion == 3) {
1058 SInt32 res = _CFGetPathProperties(allocator, (char *)buff, &exists, &mode, NULL, NULL, NULL, NULL);
1059 #if DEPLOYMENT_TARGET_WINDOWS
1060 if (!(res == 0 && exists && ((mode & S_IFMT) == S_IFDIR))) {
1061 // 2nd chance at finding a bundle path - remove the last path component (e.g., mybundle.resources) and try again
1062 if (modDate) {
1063 CFRelease(modDate);
1064 modDate = NULL;
1065 }
1066 CFURLRef shorterPath = CFURLCreateCopyDeletingLastPathComponent(allocator, newURL);
1067 CFRelease(newURL);
1068 newURL = shorterPath;
1069 res = _CFGetFileProperties(allocator, newURL, &exists, &mode, NULL, NULL, NULL, NULL);
1070 }
1071 #endif
1072 if (res == 0) {
1073 if (!exists || ((mode & S_IFMT) != S_IFDIR)) {
1074 if (modDate) CFRelease(modDate);
1075 CFRelease(newURL);
1076 return NULL;
1077 }
1078 } else {
1079 CFRelease(newURL);
1080 return NULL;
1081 }
1082 }
1083
1084 bundle = (CFBundleRef)_CFRuntimeCreateInstance(allocator, CFBundleGetTypeID(), sizeof(struct __CFBundle) - sizeof(CFRuntimeBase), NULL);
1085 if (!bundle) {
1086 CFRelease(newURL);
1087 return NULL;
1088 }
1089
1090 bundle->_url = newURL;
1091
1092 bundle->_modDate = modDate;
1093 bundle->_version = localVersion;
1094 bundle->_infoDict = NULL;
1095 bundle->_localInfoDict = NULL;
1096 bundle->_searchLanguages = NULL;
1097 bundle->_executablePath = NULL;
1098 bundle->_developmentRegion = NULL;
1099 bundle->_developmentRegionCalculated = 0;
1100 #if defined(BINARY_SUPPORT_DYLD)
1101 /* We'll have to figure it out later */
1102 bundle->_binaryType = __CFBundleUnknownBinary;
1103 #elif defined(BINARY_SUPPORT_DLL)
1104 /* We support DLL only */
1105 bundle->_binaryType = __CFBundleDLLBinary;
1106 bundle->_hModule = NULL;
1107 #else
1108 /* We'll have to figure it out later */
1109 bundle->_binaryType = __CFBundleUnknownBinary;
1110 #endif /* BINARY_SUPPORT_DYLD */
1111
1112 bundle->_isLoaded = false;
1113 bundle->_sharesStringsFiles = false;
1114
1115 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
1116 if (!__CFgetenv("CFBundleDisableStringsSharing") &&
1117 (strncmp(buff, "/System/Library/Frameworks", 26) == 0) &&
1118 (strncmp(buff + strlen(buff) - 10, ".framework", 10) == 0)) bundle->_sharesStringsFiles = true;
1119 #endif
1120
1121 bundle->_connectionCookie = NULL;
1122 bundle->_handleCookie = NULL;
1123 bundle->_imageCookie = NULL;
1124 bundle->_moduleCookie = NULL;
1125
1126 bundle->_glueDict = NULL;
1127
1128 bundle->_resourceData._executableLacksResourceFork = false;
1129 bundle->_resourceData._infoDictionaryFromResourceFork = false;
1130
1131 bundle->_stringTable = NULL;
1132
1133 bundle->_plugInData._isPlugIn = false;
1134 bundle->_plugInData._loadOnDemand = false;
1135 bundle->_plugInData._isDoingDynamicRegistration = false;
1136 bundle->_plugInData._instanceCount = 0;
1137 bundle->_plugInData._factories = NULL;
1138
1139 pthread_mutexattr_t mattr;
1140 pthread_mutexattr_init(&mattr);
1141 pthread_mutexattr_settype(&mattr, PTHREAD_MUTEX_DEFAULT);
1142 int32_t mret = pthread_mutex_init(&(bundle->_bundleLoadingLock), &mattr);
1143 pthread_mutexattr_destroy(&mattr);
1144 if (0 != mret) {
1145 CFLog(4, CFSTR("%s: failed to initialize bundle loading lock for bundle %@."), __PRETTY_FUNCTION__, bundle);
1146 }
1147
1148 bundle->_lock = CFLockInit;
1149 bundle->_resourceDirectoryContents = NULL;
1150
1151 bundle->_localizations = NULL;
1152 bundle->_lookedForLocalizations = false;
1153
1154 bundle->_queryLock = CFLockInit;
1155 bundle->_queryTable = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
1156 CFURLRef absoURL = CFURLCopyAbsoluteURL(bundle->_url);
1157 bundle->_bundleBasePath = CFURLCopyFileSystemPath(absoURL, PLATFORM_PATH_STYLE);
1158 CFRelease(absoURL);
1159
1160 CFBundleGetInfoDictionary(bundle);
1161
1162 // Do this so that we can use the dispatch_once on the ivar of this bundle safely
1163 OSMemoryBarrier();
1164
1165 _CFBundleAddToTables(bundle, alreadyLocked);
1166
1167 if (doFinalProcessing) {
1168 if (_CFBundleNeedsInitPlugIn(bundle)) {
1169 if (alreadyLocked) pthread_mutex_unlock(&CFBundleGlobalDataLock);
1170 _CFBundleInitPlugIn(bundle);
1171 if (alreadyLocked) pthread_mutex_lock(&CFBundleGlobalDataLock);
1172 }
1173 }
1174
1175 return bundle;
1176 }
1177
1178 CFBundleRef CFBundleCreate(CFAllocatorRef allocator, CFURLRef bundleURL) {
1179 return _CFBundleCreate(allocator, bundleURL, false, true);
1180 }
1181
1182 CFArrayRef CFBundleCreateBundlesFromDirectory(CFAllocatorRef alloc, CFURLRef directoryURL, CFStringRef bundleType) {
1183 CFMutableArrayRef bundles = CFArrayCreateMutable(alloc, 0, &kCFTypeArrayCallBacks);
1184 CFArrayRef URLs = _CFCreateContentsOfDirectory(alloc, NULL, NULL, directoryURL, bundleType);
1185 if (URLs) {
1186 CFIndex i, c = CFArrayGetCount(URLs);
1187 CFURLRef curURL;
1188 CFBundleRef curBundle;
1189
1190 for (i = 0; i < c; i++) {
1191 curURL = (CFURLRef)CFArrayGetValueAtIndex(URLs, i);
1192 curBundle = CFBundleCreate(alloc, curURL);
1193 if (curBundle) CFArrayAppendValue(bundles, curBundle);
1194 }
1195 CFRelease(URLs);
1196 }
1197
1198 return bundles;
1199 }
1200
1201 CFURLRef CFBundleCopyBundleURL(CFBundleRef bundle) {
1202 if (bundle->_url) CFRetain(bundle->_url);
1203 return bundle->_url;
1204 }
1205
1206 #define DEVELOPMENT_STAGE 0x20
1207 #define ALPHA_STAGE 0x40
1208 #define BETA_STAGE 0x60
1209 #define RELEASE_STAGE 0x80
1210
1211 #define MAX_VERS_LEN 10
1212
1213 CF_INLINE Boolean _isDigit(UniChar aChar) {return ((aChar >= (UniChar)'0' && aChar <= (UniChar)'9') ? true : false);}
1214
1215 CF_PRIVATE CFStringRef _CFCreateStringFromVersionNumber(CFAllocatorRef alloc, UInt32 vers) {
1216 CFStringRef result = NULL;
1217 uint8_t major1, major2, minor1, minor2, stage, build;
1218
1219 major1 = (vers & 0xF0000000) >> 28;
1220 major2 = (vers & 0x0F000000) >> 24;
1221 minor1 = (vers & 0x00F00000) >> 20;
1222 minor2 = (vers & 0x000F0000) >> 16;
1223 stage = (vers & 0x0000FF00) >> 8;
1224 build = (vers & 0x000000FF);
1225
1226 if (stage == RELEASE_STAGE) {
1227 if (major1 > 0) {
1228 result = CFStringCreateWithFormat(alloc, NULL, CFSTR("%d%d.%d.%d"), major1, major2, minor1, minor2);
1229 } else {
1230 result = CFStringCreateWithFormat(alloc, NULL, CFSTR("%d.%d.%d"), major2, minor1, minor2);
1231 }
1232 } else {
1233 if (major1 > 0) {
1234 result = CFStringCreateWithFormat(alloc, NULL, CFSTR("%d%d.%d.%d%c%d"), major1, major2, minor1, minor2, ((stage == DEVELOPMENT_STAGE) ? 'd' : ((stage == ALPHA_STAGE) ? 'a' : 'b')), build);
1235 } else {
1236 result = CFStringCreateWithFormat(alloc, NULL, CFSTR("%d.%d.%d%c%d"), major2, minor1, minor2, ((stage == DEVELOPMENT_STAGE) ? 'd' : ((stage == ALPHA_STAGE) ? 'a' : 'b')), build);
1237 }
1238 }
1239 return result;
1240 }
1241
1242 CF_PRIVATE UInt32 _CFVersionNumberFromString(CFStringRef versStr) {
1243 // Parse version number from string.
1244 // String can begin with "." for major version number 0. String can end at any point, but elements within the string cannot be skipped.
1245 UInt32 major1 = 0, major2 = 0, minor1 = 0, minor2 = 0, stage = RELEASE_STAGE, build = 0;
1246 UniChar versChars[MAX_VERS_LEN];
1247 UniChar *chars = NULL;
1248 CFIndex len;
1249 UInt32 theVers;
1250 Boolean digitsDone = false;
1251
1252 if (!versStr) return 0;
1253 len = CFStringGetLength(versStr);
1254 if (len <= 0 || len > MAX_VERS_LEN) return 0;
1255
1256 CFStringGetCharacters(versStr, CFRangeMake(0, len), versChars);
1257 chars = versChars;
1258
1259 // Get major version number.
1260 major1 = major2 = 0;
1261 if (_isDigit(*chars)) {
1262 major2 = *chars - (UniChar)'0';
1263 chars++;
1264 len--;
1265 if (len > 0) {
1266 if (_isDigit(*chars)) {
1267 major1 = major2;
1268 major2 = *chars - (UniChar)'0';
1269 chars++;
1270 len--;
1271 if (len > 0) {
1272 if (*chars == (UniChar)'.') {
1273 chars++;
1274 len--;
1275 } else {
1276 digitsDone = true;
1277 }
1278 }
1279 } else if (*chars == (UniChar)'.') {
1280 chars++;
1281 len--;
1282 } else {
1283 digitsDone = true;
1284 }
1285 }
1286 } else if (*chars == (UniChar)'.') {
1287 chars++;
1288 len--;
1289 } else {
1290 digitsDone = true;
1291 }
1292
1293 // Now major1 and major2 contain first and second digit of the major version number as ints.
1294 // Now either len is 0 or chars points at the first char beyond the first decimal point.
1295
1296 // Get the first minor version number.
1297 if (len > 0 && !digitsDone) {
1298 if (_isDigit(*chars)) {
1299 minor1 = *chars - (UniChar)'0';
1300 chars++;
1301 len--;
1302 if (len > 0) {
1303 if (*chars == (UniChar)'.') {
1304 chars++;
1305 len--;
1306 } else {
1307 digitsDone = true;
1308 }
1309 }
1310 } else {
1311 digitsDone = true;
1312 }
1313 }
1314
1315 // Now minor1 contains the first minor version number as an int.
1316 // Now either len is 0 or chars points at the first char beyond the second decimal point.
1317
1318 // Get the second minor version number.
1319 if (len > 0 && !digitsDone) {
1320 if (_isDigit(*chars)) {
1321 minor2 = *chars - (UniChar)'0';
1322 chars++;
1323 len--;
1324 } else {
1325 digitsDone = true;
1326 }
1327 }
1328
1329 // Now minor2 contains the second minor version number as an int.
1330 // Now either len is 0 or chars points at the build stage letter.
1331
1332 // Get the build stage letter. We must find 'd', 'a', 'b', or 'f' next, if there is anything next.
1333 if (len > 0) {
1334 if (*chars == (UniChar)'d') {
1335 stage = DEVELOPMENT_STAGE;
1336 } else if (*chars == (UniChar)'a') {
1337 stage = ALPHA_STAGE;
1338 } else if (*chars == (UniChar)'b') {
1339 stage = BETA_STAGE;
1340 } else if (*chars == (UniChar)'f') {
1341 stage = RELEASE_STAGE;
1342 } else {
1343 return 0;
1344 }
1345 chars++;
1346 len--;
1347 }
1348
1349 // Now stage contains the release stage.
1350 // Now either len is 0 or chars points at the build number.
1351
1352 // Get the first digit of the build number.
1353 if (len > 0) {
1354 if (_isDigit(*chars)) {
1355 build = *chars - (UniChar)'0';
1356 chars++;
1357 len--;
1358 } else {
1359 return 0;
1360 }
1361 }
1362 // Get the second digit of the build number.
1363 if (len > 0) {
1364 if (_isDigit(*chars)) {
1365 build *= 10;
1366 build += *chars - (UniChar)'0';
1367 chars++;
1368 len--;
1369 } else {
1370 return 0;
1371 }
1372 }
1373 // Get the third digit of the build number.
1374 if (len > 0) {
1375 if (_isDigit(*chars)) {
1376 build *= 10;
1377 build += *chars - (UniChar)'0';
1378 chars++;
1379 len--;
1380 } else {
1381 return 0;
1382 }
1383 }
1384
1385 // Range check the build number and make sure we exhausted the string.
1386 if (build > 0xFF || len > 0) return 0;
1387
1388 // Build the number
1389 theVers = major1 << 28;
1390 theVers += major2 << 24;
1391 theVers += minor1 << 20;
1392 theVers += minor2 << 16;
1393 theVers += stage << 8;
1394 theVers += build;
1395
1396 return theVers;
1397 }
1398
1399 UInt32 CFBundleGetVersionNumber(CFBundleRef bundle) {
1400 CFDictionaryRef infoDict = CFBundleGetInfoDictionary(bundle);
1401 CFNumberRef versionValue = (CFNumberRef)CFDictionaryGetValue(infoDict, _kCFBundleNumericVersionKey);
1402 if (!versionValue || CFGetTypeID(versionValue) != CFNumberGetTypeID()) return 0;
1403
1404 UInt32 vers = 0;
1405 CFNumberGetValue(versionValue, kCFNumberSInt32Type, &vers);
1406 return vers;
1407 }
1408
1409 CFStringRef CFBundleGetDevelopmentRegion(CFBundleRef bundle) {
1410 dispatch_once(&bundle->_developmentRegionCalculated, ^{
1411 CFStringRef devRegion = NULL;
1412 CFDictionaryRef infoDict = CFBundleGetInfoDictionary(bundle);
1413 if (infoDict) {
1414 devRegion = (CFStringRef)CFDictionaryGetValue(infoDict, kCFBundleDevelopmentRegionKey);
1415 if (devRegion && (CFGetTypeID(devRegion) != CFStringGetTypeID() || CFStringGetLength(devRegion) == 0)) {
1416 devRegion = NULL;
1417 }
1418 }
1419
1420 if (devRegion) bundle->_developmentRegion = (CFStringRef)CFRetain(devRegion);
1421 });
1422 return bundle->_developmentRegion;
1423 }
1424
1425 Boolean _CFBundleGetHasChanged(CFBundleRef bundle) {
1426 CFDateRef modDate;
1427 Boolean result = false;
1428 Boolean exists = false;
1429 SInt32 mode = 0;
1430
1431 if (_CFGetFileProperties(CFGetAllocator(bundle), bundle->_url, &exists, &mode, NULL, &modDate, NULL, NULL) == 0) {
1432 // If the bundle no longer exists or is not a folder, it must have "changed"
1433 if (!exists || ((mode & S_IFMT) != S_IFDIR)) result = true;
1434 } else {
1435 // Something is wrong. The stat failed.
1436 result = true;
1437 }
1438 if (bundle->_modDate && !CFEqual(bundle->_modDate, modDate)) {
1439 // mod date is different from when we created.
1440 result = true;
1441 }
1442 CFRelease(modDate);
1443 return result;
1444 }
1445
1446 void _CFBundleSetStringsFilesShared(CFBundleRef bundle, Boolean flag) {
1447 bundle->_sharesStringsFiles = flag;
1448 }
1449
1450 Boolean _CFBundleGetStringsFilesShared(CFBundleRef bundle) {
1451 return bundle->_sharesStringsFiles;
1452 }
1453
1454 static Boolean _urlExists(CFURLRef url) {
1455 Boolean exists;
1456 return url && (0 == _CFGetFileProperties(kCFAllocatorSystemDefault, url, &exists, NULL, NULL, NULL, NULL, NULL)) && exists;
1457 }
1458
1459 // This is here because on iPhoneOS with the dyld shared cache, we remove binaries from their
1460 // original locations on disk, so checking whether a binary's path exists is no longer sufficient.
1461 // For performance reasons, we only call dlopen_preflight() after we've verified that the binary
1462 // does not exist at its original path with _urlExists().
1463 // See <rdar://problem/6956670>
1464 static Boolean _binaryLoadable(CFURLRef url) {
1465 Boolean loadable = _urlExists(url);
1466 #if DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
1467 if (!loadable) {
1468 uint8_t path[PATH_MAX];
1469 if (url && CFURLGetFileSystemRepresentation(url, true, path, sizeof(path))) {
1470 loadable = dlopen_preflight((char *)path);
1471 }
1472 }
1473 #endif
1474 return loadable;
1475 }
1476
1477 CF_PRIVATE CFURLRef _CFBundleCopySupportFilesDirectoryURLInDirectory(CFURLRef bundleURL, uint8_t version) {
1478 CFURLRef result = NULL;
1479 if (bundleURL) {
1480 if (1 == version) {
1481 result = CFURLCreateWithString(kCFAllocatorSystemDefault, _CFBundleSupportFilesURLFromBase1, bundleURL);
1482 } else if (2 == version) {
1483 result = CFURLCreateWithString(kCFAllocatorSystemDefault, _CFBundleSupportFilesURLFromBase2, bundleURL);
1484 } else {
1485 result = (CFURLRef)CFRetain(bundleURL);
1486 }
1487 }
1488 return result;
1489 }
1490
1491 CF_EXPORT CFURLRef CFBundleCopySupportFilesDirectoryURL(CFBundleRef bundle) {
1492 return _CFBundleCopySupportFilesDirectoryURLInDirectory(bundle->_url, bundle->_version);
1493 }
1494
1495 CF_PRIVATE CFURLRef _CFBundleCopyResourcesDirectoryURLInDirectory(CFURLRef bundleURL, uint8_t version) {
1496 CFURLRef result = NULL;
1497 if (bundleURL) {
1498 if (0 == version) {
1499 result = CFURLCreateWithString(kCFAllocatorSystemDefault, _CFBundleResourcesURLFromBase0, bundleURL);
1500 } else if (1 == version) {
1501 result = CFURLCreateWithString(kCFAllocatorSystemDefault, _CFBundleResourcesURLFromBase1, bundleURL);
1502 } else if (2 == version) {
1503 result = CFURLCreateWithString(kCFAllocatorSystemDefault, _CFBundleResourcesURLFromBase2, bundleURL);
1504 } else {
1505 result = (CFURLRef)CFRetain(bundleURL);
1506 }
1507 }
1508 return result;
1509 }
1510
1511 CF_EXPORT CFURLRef CFBundleCopyResourcesDirectoryURL(CFBundleRef bundle) {
1512 return _CFBundleCopyResourcesDirectoryURLInDirectory(bundle->_url, bundle->_version);
1513 }
1514
1515 CF_PRIVATE CFURLRef _CFBundleCopyAppStoreReceiptURLInDirectory(CFURLRef bundleURL, uint8_t version) {
1516 CFURLRef result = NULL;
1517 if (bundleURL) {
1518 if (0 == version) {
1519 result = CFURLCreateWithString(kCFAllocatorSystemDefault, _CFBundleAppStoreReceiptURLFromBase0, bundleURL);
1520 } else if (1 == version) {
1521 result = CFURLCreateWithString(kCFAllocatorSystemDefault, _CFBundleAppStoreReceiptURLFromBase1, bundleURL);
1522 } else if (2 == version) {
1523 result = CFURLCreateWithString(kCFAllocatorSystemDefault, _CFBundleAppStoreReceiptURLFromBase2, bundleURL);
1524 }
1525 }
1526 return result;
1527 }
1528
1529 CFURLRef _CFBundleCopyAppStoreReceiptURL(CFBundleRef bundle) {
1530 return _CFBundleCopyAppStoreReceiptURLInDirectory(bundle->_url, bundle->_version);
1531 }
1532
1533 static CFURLRef _CFBundleCopyExecutableURLRaw(CFURLRef urlPath, CFStringRef exeName) {
1534 // Given an url to a folder and a name, this returns the url to the executable in that folder with that name, if it exists, and NULL otherwise. This function deals with appending the ".exe" or ".dll" on Windows.
1535 CFURLRef executableURL = NULL;
1536 if (!urlPath || !exeName) return NULL;
1537
1538 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
1539 const uint8_t *image_suffix = (uint8_t *)__CFgetenv("DYLD_IMAGE_SUFFIX");
1540 if (image_suffix) {
1541 CFStringRef newExeName, imageSuffix;
1542 imageSuffix = CFStringCreateWithCString(kCFAllocatorSystemDefault, (char *)image_suffix, kCFStringEncodingUTF8);
1543 if (CFStringHasSuffix(exeName, CFSTR(".dylib"))) {
1544 CFStringRef bareExeName = CFStringCreateWithSubstring(kCFAllocatorSystemDefault, exeName, CFRangeMake(0, CFStringGetLength(exeName)-6));
1545 newExeName = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("%@%@.dylib"), exeName, imageSuffix);
1546 CFRelease(bareExeName);
1547 } else {
1548 newExeName = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("%@%@"), exeName, imageSuffix);
1549 }
1550 executableURL = CFURLCreateWithFileSystemPathRelativeToBase(kCFAllocatorSystemDefault, newExeName, kCFURLPOSIXPathStyle, false, urlPath);
1551 if (executableURL && !_binaryLoadable(executableURL)) {
1552 CFRelease(executableURL);
1553 executableURL = NULL;
1554 }
1555 CFRelease(newExeName);
1556 CFRelease(imageSuffix);
1557 }
1558 if (!executableURL) {
1559 executableURL = CFURLCreateWithFileSystemPathRelativeToBase(kCFAllocatorSystemDefault, exeName, kCFURLPOSIXPathStyle, false, urlPath);
1560 if (executableURL && !_binaryLoadable(executableURL)) {
1561 CFRelease(executableURL);
1562 executableURL = NULL;
1563 }
1564 }
1565 #elif DEPLOYMENT_TARGET_WINDOWS
1566 if (!executableURL) {
1567 executableURL = CFURLCreateWithFileSystemPathRelativeToBase(kCFAllocatorSystemDefault, exeName, kCFURLWindowsPathStyle, false, urlPath);
1568 if (executableURL && !_urlExists(executableURL)) {
1569 CFRelease(executableURL);
1570 executableURL = NULL;
1571 }
1572 }
1573 if (!executableURL) {
1574 if (!CFStringFindWithOptions(exeName, CFSTR(".dll"), CFRangeMake(0, CFStringGetLength(exeName)), kCFCompareAnchored|kCFCompareBackwards|kCFCompareCaseInsensitive, NULL)) {
1575 #if defined(DEBUG)
1576 CFStringRef extension = CFSTR("_debug.dll");
1577 #else
1578 CFStringRef extension = CFSTR(".dll");
1579 #endif
1580 CFStringRef newExeName = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("%@%@"), exeName, extension);
1581 executableURL = CFURLCreateWithString(kCFAllocatorSystemDefault, newExeName, urlPath);
1582 if (executableURL && !_binaryLoadable(executableURL)) {
1583 CFRelease(executableURL);
1584 executableURL = NULL;
1585 }
1586 CFRelease(newExeName);
1587 }
1588 }
1589 if (!executableURL) {
1590 if (!CFStringFindWithOptions(exeName, CFSTR(".exe"), CFRangeMake(0, CFStringGetLength(exeName)), kCFCompareAnchored|kCFCompareBackwards|kCFCompareCaseInsensitive, NULL)) {
1591 #if defined(DEBUG)
1592 CFStringRef extension = CFSTR("_debug.exe");
1593 #else
1594 CFStringRef extension = CFSTR(".exe");
1595 #endif
1596 CFStringRef newExeName = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("%@%@"), exeName, extension);
1597 executableURL = CFURLCreateWithString(kCFAllocatorSystemDefault, newExeName, urlPath);
1598 if (executableURL && !_binaryLoadable(executableURL)) {
1599 CFRelease(executableURL);
1600 executableURL = NULL;
1601 }
1602 CFRelease(newExeName);
1603 }
1604 }
1605 #endif
1606 return executableURL;
1607 }
1608
1609 CF_PRIVATE CFStringRef _CFBundleCopyExecutableName(CFBundleRef bundle, CFURLRef url, CFDictionaryRef infoDict) {
1610 CFStringRef executableName = NULL;
1611
1612 if (!infoDict && bundle) infoDict = CFBundleGetInfoDictionary(bundle);
1613 if (!url && bundle) url = bundle->_url;
1614
1615 if (infoDict) {
1616 // Figure out the name of the executable.
1617 // First try for the new key in the plist.
1618 executableName = (CFStringRef)CFDictionaryGetValue(infoDict, kCFBundleExecutableKey);
1619 // Second try for the old key in the plist.
1620 if (!executableName) executableName = (CFStringRef)CFDictionaryGetValue(infoDict, _kCFBundleOldExecutableKey);
1621 if (executableName && CFGetTypeID(executableName) == CFStringGetTypeID() && CFStringGetLength(executableName) > 0) {
1622 CFRetain(executableName);
1623 } else {
1624 executableName = NULL;
1625 }
1626 }
1627 if (!executableName && url) {
1628 // Third, take the name of the bundle itself (with path extension stripped)
1629 CFURLRef absoluteURL = CFURLCopyAbsoluteURL(url);
1630 CFStringRef bundlePath = CFURLCopyFileSystemPath(absoluteURL, PLATFORM_PATH_STYLE);
1631 CFRelease(absoluteURL);
1632 if (bundlePath) {
1633 CFIndex len = CFStringGetLength(bundlePath);
1634 CFIndex startOfBundleName = _CFStartOfLastPathComponent2(bundlePath);
1635 CFIndex endOfBundleName = _CFLengthAfterDeletingPathExtension2(bundlePath);
1636
1637 if (startOfBundleName <= len && endOfBundleName <= len && startOfBundleName < endOfBundleName) {
1638 executableName = CFStringCreateWithSubstring(kCFAllocatorSystemDefault, bundlePath, CFRangeMake(startOfBundleName, endOfBundleName - startOfBundleName));
1639 }
1640 CFRelease(bundlePath);
1641 }
1642 }
1643
1644 return executableName;
1645 }
1646
1647 static CFURLRef _CFBundleCopyExecutableURLInDirectory2(CFBundleRef bundle, CFURLRef url, CFStringRef executableName, Boolean ignoreCache, Boolean useOtherPlatform) {
1648 uint8_t version = 0;
1649 CFDictionaryRef infoDict = NULL;
1650 CFStringRef executablePath = NULL;
1651 CFURLRef executableURL = NULL;
1652 Boolean foundIt = false;
1653 Boolean lookupMainExe = (executableName ? false : true);
1654
1655 if (bundle) {
1656 infoDict = CFBundleGetInfoDictionary(bundle);
1657 version = bundle->_version;
1658 } else {
1659 infoDict = _CFBundleCopyInfoDictionaryInDirectory(kCFAllocatorSystemDefault, url, &version);
1660 }
1661
1662 // If we have a bundle instance and an info dict, see if we have already cached the path
1663 if (lookupMainExe && !ignoreCache && !useOtherPlatform && bundle && bundle->_executablePath) {
1664 __CFLock(&bundle->_lock);
1665 executablePath = bundle->_executablePath;
1666 if (executablePath) CFRetain(executablePath);
1667 __CFUnlock(&bundle->_lock);
1668 if (executablePath) {
1669 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
1670 executableURL = CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault, executablePath, kCFURLPOSIXPathStyle, false);
1671 #elif DEPLOYMENT_TARGET_WINDOWS
1672 executableURL = CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault, executablePath, kCFURLWindowsPathStyle, false);
1673 #endif
1674 if (executableURL) {
1675 foundIt = true;
1676 }
1677 CFRelease(executablePath);
1678 }
1679 }
1680
1681 if (!foundIt) {
1682 if (lookupMainExe) executableName = _CFBundleCopyExecutableName(bundle, url, infoDict);
1683 if (executableName) {
1684 #if (DEPLOYMENT_TARGET_EMBEDDED && !TARGET_IPHONE_SIMULATOR)
1685 Boolean doExecSearch = false;
1686 #else
1687 Boolean doExecSearch = true;
1688 #endif
1689 // Now, look for the executable inside the bundle.
1690 if (doExecSearch && 0 != version) {
1691 CFURLRef exeDirURL = NULL;
1692 CFURLRef exeSubdirURL;
1693
1694 if (1 == version) {
1695 exeDirURL = CFURLCreateWithString(kCFAllocatorSystemDefault, _CFBundleExecutablesURLFromBase1, url);
1696 } else if (2 == version) {
1697 exeDirURL = CFURLCreateWithString(kCFAllocatorSystemDefault, _CFBundleExecutablesURLFromBase2, url);
1698 } else {
1699 #if DEPLOYMENT_TARGET_WINDOWS
1700 // On Windows, if the bundle URL is foo.resources, then the executable is at the same level as the .resources directory
1701 CFStringRef extension = CFURLCopyPathExtension(url);
1702 if (extension && CFEqual(extension, _CFBundleWindowsResourceDirectoryExtension)) {
1703 exeDirURL = CFURLCreateCopyDeletingLastPathComponent(kCFAllocatorSystemDefault, url);
1704 } else {
1705 exeDirURL = (CFURLRef)CFRetain(url);
1706 }
1707 #elif DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
1708 exeDirURL = (CFURLRef)CFRetain(url);
1709 #endif
1710 }
1711 CFStringRef platformSubDir = useOtherPlatform ? _CFBundleGetOtherPlatformExecutablesSubdirectoryName() : _CFBundleGetPlatformExecutablesSubdirectoryName();
1712 exeSubdirURL = CFURLCreateWithFileSystemPathRelativeToBase(kCFAllocatorSystemDefault, platformSubDir, kCFURLPOSIXPathStyle, true, exeDirURL);
1713 executableURL = _CFBundleCopyExecutableURLRaw(exeSubdirURL, executableName);
1714 if (!executableURL) {
1715 CFRelease(exeSubdirURL);
1716 platformSubDir = useOtherPlatform ? _CFBundleGetOtherAlternatePlatformExecutablesSubdirectoryName() : _CFBundleGetAlternatePlatformExecutablesSubdirectoryName();
1717 exeSubdirURL = CFURLCreateWithFileSystemPathRelativeToBase(kCFAllocatorSystemDefault, platformSubDir, kCFURLPOSIXPathStyle, true, exeDirURL);
1718 executableURL = _CFBundleCopyExecutableURLRaw(exeSubdirURL, executableName);
1719 }
1720 if (!executableURL) {
1721 CFRelease(exeSubdirURL);
1722 platformSubDir = useOtherPlatform ? _CFBundleGetPlatformExecutablesSubdirectoryName() : _CFBundleGetOtherPlatformExecutablesSubdirectoryName();
1723 exeSubdirURL = CFURLCreateWithFileSystemPathRelativeToBase(kCFAllocatorSystemDefault, platformSubDir, kCFURLPOSIXPathStyle, true, exeDirURL);
1724 executableURL = _CFBundleCopyExecutableURLRaw(exeSubdirURL, executableName);
1725 }
1726 if (!executableURL) {
1727 CFRelease(exeSubdirURL);
1728 platformSubDir = useOtherPlatform ? _CFBundleGetAlternatePlatformExecutablesSubdirectoryName() : _CFBundleGetOtherAlternatePlatformExecutablesSubdirectoryName();
1729 exeSubdirURL = CFURLCreateWithFileSystemPathRelativeToBase(kCFAllocatorSystemDefault, platformSubDir, kCFURLPOSIXPathStyle, true, exeDirURL);
1730 executableURL = _CFBundleCopyExecutableURLRaw(exeSubdirURL, executableName);
1731 }
1732 if (!executableURL) executableURL = _CFBundleCopyExecutableURLRaw(exeDirURL, executableName);
1733 CFRelease(exeDirURL);
1734 CFRelease(exeSubdirURL);
1735 }
1736
1737 // If this was an old bundle, or we did not find the executable in the Executables subdirectory, look directly in the bundle wrapper.
1738 if (!executableURL) executableURL = _CFBundleCopyExecutableURLRaw(url, executableName);
1739
1740 #if DEPLOYMENT_TARGET_WINDOWS
1741 // Windows only: If we still haven't found the exe, look in the Executables folder.
1742 // But only for the main bundle exe
1743 if (lookupMainExe && !executableURL) {
1744 CFURLRef exeDirURL = CFURLCreateWithString(kCFAllocatorSystemDefault, CFSTR("../../Executables"), url);
1745 executableURL = _CFBundleCopyExecutableURLRaw(exeDirURL, executableName);
1746 CFRelease(exeDirURL);
1747 }
1748 #endif
1749
1750 if (lookupMainExe && !ignoreCache && !useOtherPlatform && bundle && executableURL) {
1751 // We found it. Cache the path.
1752 CFURLRef absURL = CFURLCopyAbsoluteURL(executableURL);
1753 #if DEPLOYMENT_TARGET_WINDOWS
1754 executablePath = CFURLCopyFileSystemPath(absURL, kCFURLWindowsPathStyle);
1755 #elif DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
1756 executablePath = CFURLCopyFileSystemPath(absURL, kCFURLPOSIXPathStyle);
1757 #endif
1758 CFRelease(absURL);
1759 __CFLock(&bundle->_lock);
1760 bundle->_executablePath = (CFStringRef)CFRetain(executablePath);
1761 __CFUnlock(&bundle->_lock);
1762 CFRelease(executablePath);
1763 }
1764 if (lookupMainExe && !useOtherPlatform && bundle && !executableURL) bundle->_binaryType = __CFBundleNoBinary;
1765 if (lookupMainExe) CFRelease(executableName);
1766 }
1767 }
1768 if (!bundle && infoDict && !(0)) CFRelease(infoDict);
1769 return executableURL;
1770 }
1771
1772
1773 CFURLRef _CFBundleCopyExecutableURLInDirectory(CFURLRef url) {
1774 return _CFBundleCopyExecutableURLInDirectory2(NULL, url, NULL, true, false);
1775 }
1776
1777 CFURLRef _CFBundleCopyOtherExecutableURLInDirectory(CFURLRef url) {
1778 return _CFBundleCopyExecutableURLInDirectory2(NULL, url, NULL, true, true);
1779 }
1780
1781 CFURLRef CFBundleCopyExecutableURL(CFBundleRef bundle) {
1782 return _CFBundleCopyExecutableURLInDirectory2(bundle, bundle->_url, NULL, false, false);
1783 }
1784
1785 static CFURLRef _CFBundleCopyExecutableURLIgnoringCache(CFBundleRef bundle) {
1786 return _CFBundleCopyExecutableURLInDirectory2(bundle, bundle->_url, NULL, true, false);
1787 }
1788
1789 CFURLRef CFBundleCopyAuxiliaryExecutableURL(CFBundleRef bundle, CFStringRef executableName) {
1790 return _CFBundleCopyExecutableURLInDirectory2(bundle, bundle->_url, executableName, true, false);
1791 }
1792
1793 Boolean CFBundleIsExecutableLoaded(CFBundleRef bundle) {
1794 return bundle->_isLoaded;
1795 }
1796
1797 CFBundleExecutableType CFBundleGetExecutableType(CFBundleRef bundle) {
1798 CFBundleExecutableType result = kCFBundleOtherExecutableType;
1799 CFURLRef executableURL = CFBundleCopyExecutableURL(bundle);
1800
1801 if (!executableURL) bundle->_binaryType = __CFBundleNoBinary;
1802 #if defined(BINARY_SUPPORT_DYLD)
1803 if (bundle->_binaryType == __CFBundleUnknownBinary) {
1804 bundle->_binaryType = _CFBundleGrokBinaryType(executableURL);
1805 if (bundle->_binaryType != __CFBundleCFMBinary && bundle->_binaryType != __CFBundleUnreadableBinary) bundle->_resourceData._executableLacksResourceFork = true;
1806 }
1807 #endif /* BINARY_SUPPORT_DYLD */
1808 if (executableURL) CFRelease(executableURL);
1809
1810 if (bundle->_binaryType == __CFBundleCFMBinary) {
1811 result = kCFBundlePEFExecutableType;
1812 } else if (bundle->_binaryType == __CFBundleDYLDExecutableBinary || bundle->_binaryType == __CFBundleDYLDBundleBinary || bundle->_binaryType == __CFBundleDYLDFrameworkBinary) {
1813 result = kCFBundleMachOExecutableType;
1814 } else if (bundle->_binaryType == __CFBundleDLLBinary) {
1815 result = kCFBundleDLLExecutableType;
1816 } else if (bundle->_binaryType == __CFBundleELFBinary) {
1817 result = kCFBundleELFExecutableType;
1818 }
1819 return result;
1820 }
1821
1822 void _CFBundleSetCFMConnectionID(CFBundleRef bundle, void *connectionID) {
1823 bundle->_connectionCookie = connectionID;
1824 bundle->_isLoaded = true;
1825 }
1826
1827 static CFStringRef _CFBundleCopyLastPathComponent(CFBundleRef bundle) {
1828 CFURLRef bundleURL = CFBundleCopyBundleURL(bundle);
1829 if (!bundleURL) {
1830 return CFSTR("<unknown>");
1831 }
1832 CFStringRef str = CFURLCopyFileSystemPath(bundleURL, kCFURLPOSIXPathStyle);
1833 UniChar buff[CFMaxPathSize];
1834 CFIndex buffLen = CFStringGetLength(str), startOfLastDir = 0;
1835
1836 CFRelease(bundleURL);
1837 if (buffLen > CFMaxPathSize) buffLen = CFMaxPathSize;
1838 CFStringGetCharacters(str, CFRangeMake(0, buffLen), buff);
1839 CFRelease(str);
1840 if (buffLen > 0) startOfLastDir = _CFStartOfLastPathComponent(buff, buffLen);
1841 return CFStringCreateWithCharacters(kCFAllocatorSystemDefault, &(buff[startOfLastDir]), buffLen - startOfLastDir);
1842 }
1843
1844 #pragma mark -
1845
1846 CF_PRIVATE CFErrorRef _CFBundleCreateErrorDebug(CFAllocatorRef allocator, CFBundleRef bundle, CFIndex code, CFStringRef debugString) {
1847 const void *userInfoKeys[6], *userInfoValues[6];
1848 CFIndex numKeys = 0;
1849 CFURLRef bundleURL = CFBundleCopyBundleURL(bundle), absoluteURL = CFURLCopyAbsoluteURL(bundleURL), executableURL = CFBundleCopyExecutableURL(bundle);
1850 CFBundleRef bdl = CFBundleGetBundleWithIdentifier(CFSTR("com.apple.CoreFoundation"));
1851 CFStringRef bundlePath = CFURLCopyFileSystemPath(absoluteURL, PLATFORM_PATH_STYLE), executablePath = executableURL ? CFURLCopyFileSystemPath(executableURL, PLATFORM_PATH_STYLE) : NULL, descFormat = NULL, desc = NULL, reason = NULL, suggestion = NULL;
1852 CFErrorRef error;
1853 if (bdl) {
1854 CFStringRef name = (CFStringRef)CFBundleGetValueForInfoDictionaryKey(bundle, kCFBundleNameKey);
1855 name = name ? (CFStringRef)CFRetain(name) : _CFBundleCopyLastPathComponent(bundle);
1856 if (CFBundleExecutableNotFoundError == code) {
1857 descFormat = CFCopyLocalizedStringWithDefaultValue(CFSTR("BundleErr4"), CFSTR("Error"), bdl, CFSTR("The bundle \\U201c%@\\U201d couldn\\U2019t be loaded because its executable couldn\\U2019t be located."), "NSFileNoSuchFileError");
1858 reason = CFCopyLocalizedStringWithDefaultValue(CFSTR("BundleErr4-C"), CFSTR("Error"), bdl, CFSTR("The bundle\\U2019s executable couldn\\U2019t be located."), "NSFileNoSuchFileError");
1859 suggestion = CFCopyLocalizedStringWithDefaultValue(CFSTR("BundleErr4-R"), CFSTR("Error"), bdl, CFSTR("Try reinstalling the bundle."), "NSFileNoSuchFileError");
1860 } else if (CFBundleExecutableNotLoadableError == code) {
1861 descFormat = CFCopyLocalizedStringWithDefaultValue(CFSTR("BundleErr3584"), CFSTR("Error"), bdl, CFSTR("The bundle \\U201c%@\\U201d couldn\\U2019t be loaded because its executable isn\\U2019t loadable."), "NSExecutableNotLoadableError");
1862 reason = CFCopyLocalizedStringWithDefaultValue(CFSTR("BundleErr3584-C"), CFSTR("Error"), bdl, CFSTR("The bundle\\U2019s executable isn\\U2019t loadable."), "NSExecutableNotLoadableError");
1863 suggestion = CFCopyLocalizedStringWithDefaultValue(CFSTR("BundleErr3584-R"), CFSTR("Error"), bdl, CFSTR("Try reinstalling the bundle."), "NSExecutableNotLoadableError");
1864 } else if (CFBundleExecutableArchitectureMismatchError == code) {
1865 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");
1866 reason = CFCopyLocalizedStringWithDefaultValue(CFSTR("BundleErr3585-C"), CFSTR("Error"), bdl, CFSTR("The bundle doesn\\U2019t contain a version for the current architecture."), "NSExecutableArchitectureMismatchError");
1867 suggestion = CFCopyLocalizedStringWithDefaultValue(CFSTR("BundleErr3585-R"), CFSTR("Error"), bdl, CFSTR("Try installing a universal version of the bundle."), "NSExecutableArchitectureMismatchError");
1868 } else if (CFBundleExecutableRuntimeMismatchError == code) {
1869 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");
1870 reason = CFCopyLocalizedStringWithDefaultValue(CFSTR("BundleErr3586-C"), CFSTR("Error"), bdl, CFSTR("The bundle isn\\U2019t compatible with this application."), "NSExecutableRuntimeMismatchError");
1871 suggestion = CFCopyLocalizedStringWithDefaultValue(CFSTR("BundleErr3586-R"), CFSTR("Error"), bdl, CFSTR("Try installing a newer version of the bundle."), "NSExecutableRuntimeMismatchError");
1872 } else if (CFBundleExecutableLoadError == code) {
1873 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");
1874 reason = CFCopyLocalizedStringWithDefaultValue(CFSTR("BundleErr3587-C"), CFSTR("Error"), bdl, CFSTR("The bundle is damaged or missing necessary resources."), "NSExecutableLoadError");
1875 suggestion = CFCopyLocalizedStringWithDefaultValue(CFSTR("BundleErr3587-R"), CFSTR("Error"), bdl, CFSTR("Try reinstalling the bundle."), "NSExecutableLoadError");
1876 } else if (CFBundleExecutableLinkError == code) {
1877 descFormat = CFCopyLocalizedStringWithDefaultValue(CFSTR("BundleErr3588"), CFSTR("Error"), bdl, CFSTR("The bundle \\U201c%@\\U201d couldn\\U2019t be loaded."), "NSExecutableLinkError");
1878 reason = CFCopyLocalizedStringWithDefaultValue(CFSTR("BundleErr3588-C"), CFSTR("Error"), bdl, CFSTR("The bundle couldn\\U2019t be loaded."), "NSExecutableLinkError");
1879 suggestion = CFCopyLocalizedStringWithDefaultValue(CFSTR("BundleErr3588-R"), CFSTR("Error"), bdl, CFSTR("Try reinstalling the bundle."), "NSExecutableLinkError");
1880 }
1881 if (descFormat) {
1882 desc = CFStringCreateWithFormat(allocator, NULL, descFormat, name);
1883 CFRelease(descFormat);
1884 }
1885 CFRelease(name);
1886 }
1887 if (bundlePath) {
1888 userInfoKeys[numKeys] = CFSTR("NSBundlePath");
1889 userInfoValues[numKeys] = bundlePath;
1890 numKeys++;
1891 }
1892 if (executablePath) {
1893 userInfoKeys[numKeys] = CFSTR("NSFilePath");
1894 userInfoValues[numKeys] = executablePath;
1895 numKeys++;
1896 }
1897 if (desc) {
1898 userInfoKeys[numKeys] = kCFErrorLocalizedDescriptionKey;
1899 userInfoValues[numKeys] = desc;
1900 numKeys++;
1901 }
1902 if (reason) {
1903 userInfoKeys[numKeys] = kCFErrorLocalizedFailureReasonKey;
1904 userInfoValues[numKeys] = reason;
1905 numKeys++;
1906 }
1907 if (suggestion) {
1908 userInfoKeys[numKeys] = kCFErrorLocalizedRecoverySuggestionKey;
1909 userInfoValues[numKeys] = suggestion;
1910 numKeys++;
1911 }
1912 if (debugString) {
1913 userInfoKeys[numKeys] = CFSTR("NSDebugDescription");
1914 userInfoValues[numKeys] = debugString;
1915 numKeys++;
1916 }
1917 error = CFErrorCreateWithUserInfoKeysAndValues(allocator, kCFErrorDomainCocoa, code, userInfoKeys, userInfoValues, numKeys);
1918 if (bundleURL) CFRelease(bundleURL);
1919 if (absoluteURL) CFRelease(absoluteURL);
1920 if (executableURL) CFRelease(executableURL);
1921 if (bundlePath) CFRelease(bundlePath);
1922 if (executablePath) CFRelease(executablePath);
1923 if (desc) CFRelease(desc);
1924 if (reason) CFRelease(reason);
1925 if (suggestion) CFRelease(suggestion);
1926 return error;
1927 }
1928
1929 CFErrorRef _CFBundleCreateError(CFAllocatorRef allocator, CFBundleRef bundle, CFIndex code) {
1930 return _CFBundleCreateErrorDebug(allocator, bundle, code, NULL);
1931 }
1932
1933 #pragma mark -
1934
1935 Boolean _CFBundleLoadExecutableAndReturnError(CFBundleRef bundle, Boolean forceGlobal, CFErrorRef *error) {
1936 Boolean result = false;
1937 CFErrorRef localError = NULL, *subError = (error ? &localError : NULL);
1938 CFURLRef executableURL = CFBundleCopyExecutableURL(bundle);
1939
1940
1941 pthread_mutex_lock(&(bundle->_bundleLoadingLock));
1942 if (!executableURL) bundle->_binaryType = __CFBundleNoBinary;
1943 // make sure we know whether bundle is already loaded or not
1944 #if defined(BINARY_SUPPORT_DLFCN)
1945 if (!bundle->_isLoaded) _CFBundleDlfcnCheckLoaded(bundle);
1946 #elif defined(BINARY_SUPPORT_DYLD)
1947 if (!bundle->_isLoaded) _CFBundleDYLDCheckLoaded(bundle);
1948 #endif /* BINARY_SUPPORT_DLFCN */
1949 #if defined(BINARY_SUPPORT_DYLD)
1950 // We might need to figure out what it is
1951 if (bundle->_binaryType == __CFBundleUnknownBinary) {
1952 bundle->_binaryType = _CFBundleGrokBinaryType(executableURL);
1953 if (bundle->_binaryType != __CFBundleCFMBinary && bundle->_binaryType != __CFBundleUnreadableBinary) bundle->_resourceData._executableLacksResourceFork = true;
1954 }
1955 #endif /* BINARY_SUPPORT_DYLD */
1956 if (executableURL) CFRelease(executableURL);
1957
1958 if (bundle->_isLoaded) {
1959 pthread_mutex_unlock(&(bundle->_bundleLoadingLock));
1960 // Remove from the scheduled unload set if we are there.
1961 pthread_mutex_lock(&CFBundleGlobalDataLock);
1962 #if AVOID_WEAK_COLLECTIONS
1963 if (_bundlesToUnload) CFSetRemoveValue(_bundlesToUnload, bundle);
1964 #else /* AVOID_WEAK_COLLECTIONS */
1965 if (_bundlesToUnload) [_bundlesToUnload removeObject:(id)bundle];
1966 #endif /* AVOID_WEAK_COLLECTIONS */
1967 pthread_mutex_unlock(&CFBundleGlobalDataLock);
1968 return true;
1969 }
1970
1971 // Unload bundles scheduled for unloading
1972 if (!_scheduledBundlesAreUnloading) {
1973 pthread_mutex_unlock(&(bundle->_bundleLoadingLock));
1974 _CFBundleUnloadScheduledBundles();
1975 pthread_mutex_lock(&(bundle->_bundleLoadingLock));
1976 }
1977
1978 if (bundle->_isLoaded) {
1979 pthread_mutex_unlock(&(bundle->_bundleLoadingLock));
1980 // Remove from the scheduled unload set if we are there.
1981 pthread_mutex_lock(&CFBundleGlobalDataLock);
1982 #if AVOID_WEAK_COLLECTIONS
1983 if (_bundlesToUnload) CFSetRemoveValue(_bundlesToUnload, bundle);
1984 #else /* AVOID_WEAK_COLLECTIONS */
1985 if (_bundlesToUnload) [_bundlesToUnload removeObject:(id)bundle];
1986 #endif /* AVOID_WEAK_COLLECTIONS */
1987 pthread_mutex_unlock(&CFBundleGlobalDataLock);
1988 return true;
1989 }
1990 pthread_mutex_unlock(&(bundle->_bundleLoadingLock));
1991
1992 switch (bundle->_binaryType) {
1993 #if defined(BINARY_SUPPORT_DLFCN)
1994 case __CFBundleUnreadableBinary:
1995 result = _CFBundleDlfcnLoadBundle(bundle, forceGlobal, subError);
1996 break;
1997 #endif /* BINARY_SUPPORT_DLFCN */
1998 #if defined(BINARY_SUPPORT_DYLD)
1999 case __CFBundleDYLDBundleBinary:
2000 #if defined(BINARY_SUPPORT_DLFCN)
2001 result = _CFBundleDlfcnLoadBundle(bundle, forceGlobal, subError);
2002 #else /* BINARY_SUPPORT_DLFCN */
2003 result = _CFBundleDYLDLoadBundle(bundle, forceGlobal, subError);
2004 #endif /* BINARY_SUPPORT_DLFCN */
2005 break;
2006 case __CFBundleDYLDFrameworkBinary:
2007 #if defined(BINARY_SUPPORT_DLFCN)
2008 result = _CFBundleDlfcnLoadFramework(bundle, subError);
2009 #else /* BINARY_SUPPORT_DLFCN */
2010 result = _CFBundleDYLDLoadFramework(bundle, subError);
2011 #endif /* BINARY_SUPPORT_DLFCN */
2012 break;
2013 case __CFBundleDYLDExecutableBinary:
2014 if (error) {
2015 localError = _CFBundleCreateError(CFGetAllocator(bundle), bundle, CFBundleExecutableNotLoadableError);
2016 } else {
2017 CFLog(__kCFLogBundle, CFSTR("Attempt to load executable of a type that cannot be dynamically loaded for %@"), bundle);
2018 }
2019 break;
2020 #endif /* BINARY_SUPPORT_DYLD */
2021 #if defined(BINARY_SUPPORT_DLFCN)
2022 case __CFBundleUnknownBinary:
2023 case __CFBundleELFBinary:
2024 result = _CFBundleDlfcnLoadBundle(bundle, forceGlobal, subError);
2025 break;
2026 #endif /* BINARY_SUPPORT_DLFCN */
2027 #if defined(BINARY_SUPPORT_DLL)
2028 case __CFBundleDLLBinary:
2029 result = _CFBundleDLLLoad(bundle, subError);
2030 break;
2031 #endif /* BINARY_SUPPORT_DLL */
2032 case __CFBundleNoBinary:
2033 if (error) {
2034 localError = _CFBundleCreateError(CFGetAllocator(bundle), bundle, CFBundleExecutableNotFoundError);
2035 } else {
2036 CFLog(__kCFLogBundle, CFSTR("Cannot find executable for %@"), bundle);
2037 }
2038 break;
2039 default:
2040 if (error) {
2041 localError = _CFBundleCreateError(CFGetAllocator(bundle), bundle, CFBundleExecutableNotLoadableError);
2042 } else {
2043 CFLog(__kCFLogBundle, CFSTR("Cannot recognize type of executable for %@"), bundle);
2044 }
2045 break;
2046 }
2047 if (result && bundle->_plugInData._isPlugIn) _CFBundlePlugInLoaded(bundle);
2048 if (!result && error) *error = localError;
2049 return result;
2050 }
2051
2052 Boolean CFBundleLoadExecutableAndReturnError(CFBundleRef bundle, CFErrorRef *error) {
2053 return _CFBundleLoadExecutableAndReturnError(bundle, false, error);
2054 }
2055
2056 Boolean CFBundleLoadExecutable(CFBundleRef bundle) {
2057 return _CFBundleLoadExecutableAndReturnError(bundle, false, NULL);
2058 }
2059
2060 Boolean CFBundlePreflightExecutable(CFBundleRef bundle, CFErrorRef *error) {
2061 Boolean result = false;
2062 CFErrorRef localError = NULL;
2063 #if defined(BINARY_SUPPORT_DLFCN)
2064 CFErrorRef *subError = (error ? &localError : NULL);
2065 #endif
2066 CFURLRef executableURL = CFBundleCopyExecutableURL(bundle);
2067
2068 pthread_mutex_lock(&(bundle->_bundleLoadingLock));
2069 if (!executableURL) bundle->_binaryType = __CFBundleNoBinary;
2070 // make sure we know whether bundle is already loaded or not
2071 #if defined(BINARY_SUPPORT_DLFCN)
2072 if (!bundle->_isLoaded) _CFBundleDlfcnCheckLoaded(bundle);
2073 #elif defined(BINARY_SUPPORT_DYLD)
2074 if (!bundle->_isLoaded) _CFBundleDYLDCheckLoaded(bundle);
2075 #endif /* BINARY_SUPPORT_DLFCN */
2076 #if defined(BINARY_SUPPORT_DYLD)
2077 // We might need to figure out what it is
2078 if (bundle->_binaryType == __CFBundleUnknownBinary) {
2079 bundle->_binaryType = _CFBundleGrokBinaryType(executableURL);
2080 if (bundle->_binaryType != __CFBundleCFMBinary && bundle->_binaryType != __CFBundleUnreadableBinary) bundle->_resourceData._executableLacksResourceFork = true;
2081 }
2082 #endif /* BINARY_SUPPORT_DYLD */
2083 if (executableURL) CFRelease(executableURL);
2084
2085 if (bundle->_isLoaded) {
2086 pthread_mutex_unlock(&(bundle->_bundleLoadingLock));
2087 return true;
2088 }
2089 pthread_mutex_unlock(&(bundle->_bundleLoadingLock));
2090
2091 switch (bundle->_binaryType) {
2092 #if defined(BINARY_SUPPORT_DLFCN)
2093 case __CFBundleUnreadableBinary:
2094 result = _CFBundleDlfcnPreflight(bundle, subError);
2095 break;
2096 #endif /* BINARY_SUPPORT_DLFCN */
2097 #if defined(BINARY_SUPPORT_DYLD)
2098 case __CFBundleDYLDBundleBinary:
2099 result = true;
2100 #if defined(BINARY_SUPPORT_DLFCN)
2101 result = _CFBundleDlfcnPreflight(bundle, subError);
2102 #endif /* BINARY_SUPPORT_DLFCN */
2103 break;
2104 case __CFBundleDYLDFrameworkBinary:
2105 result = true;
2106 #if defined(BINARY_SUPPORT_DLFCN)
2107 result = _CFBundleDlfcnPreflight(bundle, subError);
2108 #endif /* BINARY_SUPPORT_DLFCN */
2109 break;
2110 case __CFBundleDYLDExecutableBinary:
2111 if (error) localError = _CFBundleCreateError(CFGetAllocator(bundle), bundle, CFBundleExecutableNotLoadableError);
2112 break;
2113 #endif /* BINARY_SUPPORT_DYLD */
2114 #if defined(BINARY_SUPPORT_DLFCN)
2115 case __CFBundleUnknownBinary:
2116 case __CFBundleELFBinary:
2117 result = _CFBundleDlfcnPreflight(bundle, subError);
2118 break;
2119 #endif /* BINARY_SUPPORT_DLFCN */
2120 #if defined(BINARY_SUPPORT_DLL)
2121 case __CFBundleDLLBinary:
2122 result = true;
2123 break;
2124 #endif /* BINARY_SUPPORT_DLL */
2125 case __CFBundleNoBinary:
2126 if (error) localError = _CFBundleCreateError(CFGetAllocator(bundle), bundle, CFBundleExecutableNotFoundError);
2127 break;
2128 default:
2129 if (error) localError = _CFBundleCreateError(CFGetAllocator(bundle), bundle, CFBundleExecutableNotLoadableError);
2130 break;
2131 }
2132 if (!result && error) *error = localError;
2133 return result;
2134 }
2135
2136 CFArrayRef CFBundleCopyExecutableArchitectures(CFBundleRef bundle) {
2137 CFArrayRef result = NULL;
2138 CFURLRef executableURL = CFBundleCopyExecutableURL(bundle);
2139 if (executableURL) {
2140 result = _CFBundleCopyArchitecturesForExecutable(executableURL);
2141 CFRelease(executableURL);
2142 }
2143 return result;
2144 }
2145
2146 void CFBundleUnloadExecutable(CFBundleRef bundle) {
2147 // First unload bundles scheduled for unloading (if that's not what we are already doing.)
2148 if (!_scheduledBundlesAreUnloading) _CFBundleUnloadScheduledBundles();
2149
2150 if (!bundle->_isLoaded) return;
2151
2152 // Remove from the scheduled unload set if we are there.
2153 if (!_scheduledBundlesAreUnloading) pthread_mutex_lock(&CFBundleGlobalDataLock);
2154 #if AVOID_WEAK_COLLECTIONS
2155 if (_bundlesToUnload) CFSetRemoveValue(_bundlesToUnload, bundle);
2156 #else /* AVOID_WEAK_COLLECTIONS */
2157 if (_bundlesToUnload) [_bundlesToUnload removeObject:(id)bundle];
2158 #endif /* AVOID_WEAK_COLLECTIONS */
2159 if (!_scheduledBundlesAreUnloading) pthread_mutex_unlock(&CFBundleGlobalDataLock);
2160
2161 // Give the plugIn code a chance to realize this...
2162 _CFPlugInWillUnload(bundle);
2163
2164 pthread_mutex_lock(&(bundle->_bundleLoadingLock));
2165 if (!bundle->_isLoaded) {
2166 pthread_mutex_unlock(&(bundle->_bundleLoadingLock));
2167 return;
2168 }
2169 pthread_mutex_unlock(&(bundle->_bundleLoadingLock));
2170
2171 switch (bundle->_binaryType) {
2172 #if defined(BINARY_SUPPORT_DYLD)
2173 case __CFBundleDYLDBundleBinary:
2174 #if defined(BINARY_SUPPORT_DLFCN)
2175 if (bundle->_handleCookie) _CFBundleDlfcnUnload(bundle);
2176 #else /* BINARY_SUPPORT_DLFCN */
2177 _CFBundleDYLDUnloadBundle(bundle);
2178 #endif /* BINARY_SUPPORT_DLFCN */
2179 break;
2180 case __CFBundleDYLDFrameworkBinary:
2181 #if defined(BINARY_SUPPORT_DLFCN)
2182 if (bundle->_handleCookie && _CFExecutableLinkedOnOrAfter(CFSystemVersionLeopard)) _CFBundleDlfcnUnload(bundle);
2183 #endif /* BINARY_SUPPORT_DLFCN */
2184 break;
2185 #endif /* BINARY_SUPPORT_DYLD */
2186 #if defined(BINARY_SUPPORT_DLL)
2187 case __CFBundleDLLBinary:
2188 _CFBundleDLLUnload(bundle);
2189 break;
2190 #endif /* BINARY_SUPPORT_DLL */
2191 default:
2192 #if defined(BINARY_SUPPORT_DLFCN)
2193 if (bundle->_handleCookie) _CFBundleDlfcnUnload(bundle);
2194 #endif /* BINARY_SUPPORT_DLFCN */
2195 break;
2196 }
2197 if (!bundle->_isLoaded && bundle->_glueDict) {
2198 CFDictionaryApplyFunction(bundle->_glueDict, _CFBundleDeallocateGlue, (void *)CFGetAllocator(bundle));
2199 CFRelease(bundle->_glueDict);
2200 bundle->_glueDict = NULL;
2201 }
2202 }
2203
2204 #if AVOID_WEAK_COLLECTIONS
2205
2206 CF_PRIVATE void _CFBundleScheduleForUnloading(CFBundleRef bundle) {
2207 pthread_mutex_lock(&CFBundleGlobalDataLock);
2208 if (!_bundlesToUnload) {
2209 CFSetCallBacks nonRetainingCallbacks = kCFTypeSetCallBacks;
2210 nonRetainingCallbacks.retain = NULL;
2211 nonRetainingCallbacks.release = NULL;
2212 _bundlesToUnload = CFSetCreateMutable(kCFAllocatorSystemDefault, 0, &nonRetainingCallbacks);
2213 }
2214 CFSetAddValue(_bundlesToUnload, bundle);
2215 pthread_mutex_unlock(&CFBundleGlobalDataLock);
2216 }
2217
2218 CF_PRIVATE void _CFBundleUnscheduleForUnloading(CFBundleRef bundle) {
2219 pthread_mutex_lock(&CFBundleGlobalDataLock);
2220 if (_bundlesToUnload) CFSetRemoveValue(_bundlesToUnload, bundle);
2221 pthread_mutex_unlock(&CFBundleGlobalDataLock);
2222 }
2223
2224 CF_PRIVATE void _CFBundleUnloadScheduledBundles(void) {
2225 pthread_mutex_lock(&CFBundleGlobalDataLock);
2226 if (_bundlesToUnload) {
2227 CFIndex i, c = CFSetGetCount(_bundlesToUnload);
2228 if (c > 0) {
2229 CFBundleRef *unloadThese = (CFBundleRef *)CFAllocatorAllocate(kCFAllocatorSystemDefault, sizeof(CFBundleRef) * c, 0);
2230 CFSetGetValues(_bundlesToUnload, (const void **)unloadThese);
2231 _scheduledBundlesAreUnloading = true;
2232 for (i = 0; i < c; i++) {
2233 // This will cause them to be removed from the set. (Which is why we copied all the values out of the set up front.)
2234 CFBundleUnloadExecutable(unloadThese[i]);
2235 }
2236 _scheduledBundlesAreUnloading = false;
2237 CFAllocatorDeallocate(kCFAllocatorSystemDefault, unloadThese);
2238 }
2239 }
2240 pthread_mutex_unlock(&CFBundleGlobalDataLock);
2241 }
2242
2243 #else /* AVOID_WEAK_COLLECTIONS */
2244
2245 CF_PRIVATE void _CFBundleScheduleForUnloading(CFBundleRef bundle) {
2246 pthread_mutex_lock(&CFBundleGlobalDataLock);
2247 if (!_bundlesToUnload) _bundlesToUnload = [[__CFHashTable alloc] initWithOptions:CFPointerFunctionsZeroingWeakMemory capacity:0];
2248 [_bundlesToUnload addObject:(id)bundle];
2249 pthread_mutex_unlock(&CFBundleGlobalDataLock);
2250 }
2251
2252 CF_PRIVATE void _CFBundleUnscheduleForUnloading(CFBundleRef bundle) {
2253 pthread_mutex_lock(&CFBundleGlobalDataLock);
2254 if (_bundlesToUnload) [_bundlesToUnload removeObject:(id)bundle];
2255 pthread_mutex_unlock(&CFBundleGlobalDataLock);
2256 }
2257
2258 CF_PRIVATE void _CFBundleUnloadScheduledBundles(void) {
2259 pthread_mutex_lock(&CFBundleGlobalDataLock);
2260 if (_bundlesToUnload && [_bundlesToUnload count] > 0) {
2261 CFIndex i, c;
2262 CFMutableArrayRef unloadThese = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
2263 for (id value in _bundlesToUnload) CFArrayAppendValue(unloadThese, value);
2264 c = CFArrayGetCount(unloadThese);
2265 if (c > 0) {
2266 _scheduledBundlesAreUnloading = true;
2267 for (i = 0; i < c; i++) {
2268 // This will cause them to be removed from the set. (Which is why we copied all the values out of the set up front.)
2269 CFBundleUnloadExecutable((CFBundleRef)CFArrayGetValueAtIndex(unloadThese, i));
2270 }
2271 _scheduledBundlesAreUnloading = false;
2272 }
2273 CFRelease(unloadThese);
2274 }
2275 pthread_mutex_unlock(&CFBundleGlobalDataLock);
2276 }
2277
2278 #endif /* AVOID_WEAK_COLLECTIONS */
2279
2280 #pragma mark -
2281
2282 CF_PRIVATE _CFResourceData *__CFBundleGetResourceData(CFBundleRef bundle) {
2283 return &(bundle->_resourceData);
2284 }
2285
2286 CFPlugInRef CFBundleGetPlugIn(CFBundleRef bundle) {
2287 return (bundle->_plugInData._isPlugIn) ? (CFPlugInRef)bundle : NULL;
2288 }
2289
2290 CF_PRIVATE _CFPlugInData *__CFBundleGetPlugInData(CFBundleRef bundle) {
2291 return &(bundle->_plugInData);
2292 }
2293
2294 CF_PRIVATE Boolean _CFBundleCouldBeBundle(CFURLRef url) {
2295 Boolean result = false;
2296 Boolean exists;
2297 SInt32 mode;
2298 if (_CFGetFileProperties(kCFAllocatorSystemDefault, url, &exists, &mode, NULL, NULL, NULL, NULL) == 0) result = (exists && (mode & S_IFMT) == S_IFDIR && (mode & 0444) != 0);
2299 return result;
2300 }
2301
2302 #define LENGTH_OF(A) (sizeof(A) / sizeof(A[0]))
2303
2304 //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/
2305 static CFURLRef __CFBundleCopyFrameworkURLForExecutablePath(CFStringRef executablePath, Boolean permissive) {
2306 // 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.
2307 #if DEPLOYMENT_TARGET_WINDOWS
2308 UniChar executablesToFrameworksPathBuff[] = {'.', '.', '\\', 'F', 'r', 'a', 'm', 'e', 'w', 'o', 'r', 'k', 's'};
2309 UniChar executablesToPrivateFrameworksPathBuff[] = {'.', '.', '\\', 'P', 'r', 'i', 'v', 'a', 't', 'e', 'F', 'r', 'a', 'm', 'e', 'w', 'o', 'r', 'k', 's'};
2310 UniChar frameworksExtension[] = {'f', 'r', 'a', 'm', 'e', 'w', 'o', 'r', 'k'};
2311 #endif
2312 UniChar pathBuff[CFMaxPathSize] = {0};
2313 UniChar nameBuff[CFMaxPathSize] = {0};
2314 CFIndex length, nameStart, nameLength, savedLength;
2315 CFMutableStringRef cheapStr = CFStringCreateMutableWithExternalCharactersNoCopy(kCFAllocatorSystemDefault, NULL, 0, 0, NULL);
2316 CFURLRef bundleURL = NULL;
2317
2318 length = CFStringGetLength(executablePath);
2319 if (length > CFMaxPathSize) length = CFMaxPathSize;
2320 CFStringGetCharacters(executablePath, CFRangeMake(0, length), pathBuff);
2321
2322 // Save the name in nameBuff
2323 length = _CFLengthAfterDeletingPathExtension(pathBuff, length);
2324 nameStart = _CFStartOfLastPathComponent(pathBuff, length);
2325 nameLength = length - nameStart;
2326 memmove(nameBuff, &(pathBuff[nameStart]), nameLength * sizeof(UniChar));
2327
2328 // Strip the name from pathBuff
2329 length = _CFLengthAfterDeletingLastPathComponent(pathBuff, length);
2330 savedLength = length;
2331
2332 #if DEPLOYMENT_TARGET_WINDOWS
2333 // * (Windows-only) First check the "Executables" directory parallel to the "Frameworks" directory case.
2334 if (_CFAppendPathComponent(pathBuff, &length, CFMaxPathSize, executablesToFrameworksPathBuff, LENGTH_OF(executablesToFrameworksPathBuff)) && _CFAppendPathComponent(pathBuff, &length, CFMaxPathSize, nameBuff, nameLength) && _CFAppendPathExtension(pathBuff, &length, CFMaxPathSize, frameworksExtension, LENGTH_OF(frameworksExtension))) {
2335 CFStringSetExternalCharactersNoCopy(cheapStr, pathBuff, length, CFMaxPathSize);
2336 bundleURL = CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault, cheapStr, PLATFORM_PATH_STYLE, true);
2337 if (!_CFBundleCouldBeBundle(bundleURL)) {
2338 CFRelease(bundleURL);
2339 bundleURL = NULL;
2340 }
2341 }
2342 // * (Windows-only) Next check the "Executables" directory parallel to the "PrivateFrameworks" directory case.
2343 if (!bundleURL) {
2344 length = savedLength;
2345 if (_CFAppendPathComponent(pathBuff, &length, CFMaxPathSize, executablesToPrivateFrameworksPathBuff, LENGTH_OF(executablesToPrivateFrameworksPathBuff)) && _CFAppendPathComponent(pathBuff, &length, CFMaxPathSize, nameBuff, nameLength) && _CFAppendPathExtension(pathBuff, &length, CFMaxPathSize, frameworksExtension, LENGTH_OF(frameworksExtension))) {
2346 CFStringSetExternalCharactersNoCopy(cheapStr, pathBuff, length, CFMaxPathSize);
2347 bundleURL = CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault, cheapStr, PLATFORM_PATH_STYLE, true);
2348 if (!_CFBundleCouldBeBundle(bundleURL)) {
2349 CFRelease(bundleURL);
2350 bundleURL = NULL;
2351 }
2352 }
2353 }
2354 #endif
2355 // * Finally check the executable inside the framework case.
2356 if (!bundleURL) {
2357 length = savedLength;
2358 // To catch all the cases, we just peel off level looking for one ending in .framework or one called "Supporting Files".
2359
2360 CFStringRef name = permissive ? CFSTR("") : CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault, (const char *)nameBuff);
2361
2362 while (length > 0) {
2363 CFIndex curStart = _CFStartOfLastPathComponent(pathBuff, length);
2364 if (curStart >= length) break;
2365 CFStringSetExternalCharactersNoCopy(cheapStr, &(pathBuff[curStart]), length - curStart, CFMaxPathSize - curStart);
2366 if (!permissive && CFEqual(cheapStr, _CFBundleResourcesDirectoryName)) break;
2367 if (CFEqual(cheapStr, _CFBundleSupportFilesDirectoryName1) || CFEqual(cheapStr, _CFBundleSupportFilesDirectoryName2)) {
2368 if (!permissive) {
2369 CFIndex fmwkStart = _CFStartOfLastPathComponent(pathBuff, length);
2370 CFStringSetExternalCharactersNoCopy(cheapStr, &(pathBuff[fmwkStart]), length - fmwkStart, CFMaxPathSize - fmwkStart);
2371 }
2372 if (permissive || CFStringHasPrefix(cheapStr, name)) {
2373 length = _CFLengthAfterDeletingLastPathComponent(pathBuff, length);
2374 CFStringSetExternalCharactersNoCopy(cheapStr, pathBuff, length, CFMaxPathSize);
2375
2376 bundleURL = CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault, cheapStr, PLATFORM_PATH_STYLE, true);
2377 if (!_CFBundleCouldBeBundle(bundleURL)) {
2378 CFRelease(bundleURL);
2379 bundleURL = NULL;
2380 }
2381 break;
2382 }
2383 } else if (CFStringHasSuffix(cheapStr, CFSTR(".framework")) && (permissive || CFStringHasPrefix(cheapStr, name))) {
2384 CFStringSetExternalCharactersNoCopy(cheapStr, pathBuff, length, CFMaxPathSize);
2385 bundleURL = CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault, cheapStr, PLATFORM_PATH_STYLE, true);
2386 if (!_CFBundleCouldBeBundle(bundleURL)) {
2387 CFRelease(bundleURL);
2388 bundleURL = NULL;
2389 }
2390 break;
2391 }
2392 length = _CFLengthAfterDeletingLastPathComponent(pathBuff, length);
2393 }
2394 if (!permissive) CFRelease(name);
2395 }
2396 CFStringSetExternalCharactersNoCopy(cheapStr, NULL, 0, 0);
2397 CFRelease(cheapStr);
2398
2399 return bundleURL;
2400 }
2401
2402 //SPI version; separated out to minimize linkage changes
2403 CFURLRef _CFBundleCopyFrameworkURLForExecutablePath(CFStringRef executablePath) {
2404 return __CFBundleCopyFrameworkURLForExecutablePath(executablePath, false);
2405 }
2406
2407 static void _CFBundleEnsureBundleExistsForImagePath(CFStringRef imagePath) {
2408 // This finds the bundle for the given path.
2409 // 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.
2410 CFBundleRef bundle;
2411 CFURLRef curURL = __CFBundleCopyFrameworkURLForExecutablePath(imagePath, true);
2412 Boolean createdBundle = false;
2413
2414 if (curURL) {
2415 bundle = _CFBundleCopyBundleForURL(curURL, true);
2416 if (!bundle) {
2417 // Ensure bundle exists by creating it if necessary
2418 // NB doFinalProcessing must be false here, see below
2419 bundle = _CFBundleCreate(kCFAllocatorSystemDefault, curURL, true, false);
2420 createdBundle = true;
2421 }
2422 if (bundle) {
2423 pthread_mutex_lock(&(bundle->_bundleLoadingLock));
2424 if (!bundle->_isLoaded) {
2425 // 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)
2426 #if defined(BINARY_SUPPORT_DLFCN)
2427 if (!bundle->_isLoaded) _CFBundleDlfcnCheckLoaded(bundle);
2428 #elif defined(BINARY_SUPPORT_DYLD)
2429 if (!bundle->_isLoaded) _CFBundleDYLDCheckLoaded(bundle);
2430 #endif /* BINARY_SUPPORT_DLFCN */
2431 #if defined(BINARY_SUPPORT_DYLD)
2432 if (bundle->_binaryType == __CFBundleUnknownBinary) bundle->_binaryType = __CFBundleDYLDFrameworkBinary;
2433 if (bundle->_binaryType != __CFBundleCFMBinary && bundle->_binaryType != __CFBundleUnreadableBinary) bundle->_resourceData._executableLacksResourceFork = true;
2434 #endif /* BINARY_SUPPORT_DYLD */
2435 #if LOG_BUNDLE_LOAD
2436 if (!bundle->_isLoaded) printf("ensure bundle %p set loaded fallback, handle %p image %p conn %p\n", bundle, bundle->_handleCookie, bundle->_imageCookie, bundle->_connectionCookie);
2437 #endif /* LOG_BUNDLE_LOAD */
2438 bundle->_isLoaded = true;
2439 }
2440 pthread_mutex_unlock(&(bundle->_bundleLoadingLock));
2441 if (createdBundle) {
2442 // Perform delayed final processing steps.
2443 // This must be done after _isLoaded has been set, for security reasons (3624341).
2444 if (_CFBundleNeedsInitPlugIn(bundle)) {
2445 pthread_mutex_unlock(&CFBundleGlobalDataLock);
2446 _CFBundleInitPlugIn(bundle);
2447 pthread_mutex_lock(&CFBundleGlobalDataLock);
2448 }
2449 } else {
2450 // Release the bundle if we did not create it here
2451 CFRelease(bundle);
2452 }
2453 }
2454 CFRelease(curURL);
2455 }
2456 }
2457
2458 static void _CFBundleEnsureBundlesExistForImagePaths(CFArrayRef imagePaths) {
2459 // This finds the bundles for the given paths.
2460 // 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).
2461 CFIndex i, imagePathCount = CFArrayGetCount(imagePaths);
2462 for (i = 0; i < imagePathCount; i++) _CFBundleEnsureBundleExistsForImagePath((CFStringRef)CFArrayGetValueAtIndex(imagePaths, i));
2463 }
2464
2465 static void _CFBundleEnsureBundlesUpToDateWithHintAlreadyLocked(CFStringRef hint) {
2466 CFArrayRef imagePaths = NULL;
2467 // Tickle the main bundle into existence
2468 (void)_CFBundleGetMainBundleAlreadyLocked();
2469 #if defined(BINARY_SUPPORT_DYLD)
2470 imagePaths = _CFBundleDYLDCopyLoadedImagePathsForHint(hint);
2471 #endif /* BINARY_SUPPORT_DYLD */
2472 if (imagePaths) {
2473 _CFBundleEnsureBundlesExistForImagePaths(imagePaths);
2474 CFRelease(imagePaths);
2475 }
2476 }
2477
2478 static void _CFBundleEnsureAllBundlesUpToDateAlreadyLocked(void) {
2479 // 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.
2480 CFArrayRef imagePaths = NULL;
2481 // Tickle the main bundle into existence
2482 (void)_CFBundleGetMainBundleAlreadyLocked();
2483
2484 #if defined(BINARY_SUPPORT_DLL)
2485 // Dont know how to find static bundles for DLLs
2486 #endif /* BINARY_SUPPORT_DLL */
2487
2488 #if defined(BINARY_SUPPORT_DYLD)
2489 imagePaths = _CFBundleDYLDCopyLoadedImagePathsIfChanged();
2490 #endif /* BINARY_SUPPORT_DYLD */
2491 if (imagePaths) {
2492 _CFBundleEnsureBundlesExistForImagePaths(imagePaths);
2493 CFRelease(imagePaths);
2494 }
2495 }
2496
2497 CFArrayRef CFBundleGetAllBundles(void) {
2498 // To answer this properly, we have to have created the static bundles!
2499 #if !AVOID_WEAK_COLLECTIONS
2500 static CFMutableArrayRef externalAllBundles = NULL;
2501 #endif /* AVOID_WEAK_COLLECTIONS */
2502 CFArrayRef bundles;
2503 pthread_mutex_lock(&CFBundleGlobalDataLock);
2504 _CFBundleEnsureAllBundlesUpToDateAlreadyLocked();
2505 #if AVOID_WEAK_COLLECTIONS
2506 bundles = _allBundles;
2507 #else /* AVOID_WEAK_COLLECTIONS */
2508 if (!externalAllBundles) {
2509 CFArrayCallBacks nonRetainingArrayCallbacks = kCFTypeArrayCallBacks;
2510 nonRetainingArrayCallbacks.retain = NULL;
2511 nonRetainingArrayCallbacks.release = NULL;
2512 externalAllBundles = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &nonRetainingArrayCallbacks);
2513 }
2514 CFArrayRemoveAllValues(externalAllBundles);
2515 for (id value in _allBundles) CFArrayAppendValue(externalAllBundles, value);
2516 bundles = externalAllBundles;
2517 #endif /* AVOID_WEAK_COLLECTIONS */
2518 pthread_mutex_unlock(&CFBundleGlobalDataLock);
2519 return bundles;
2520 }
2521
2522 CF_EXPORT CFArrayRef _CFBundleCopyAllBundles(void) {
2523 // To answer this properly, we have to have created the static bundles!
2524 pthread_mutex_lock(&CFBundleGlobalDataLock);
2525 _CFBundleEnsureAllBundlesUpToDateAlreadyLocked();
2526 #if AVOID_WEAK_COLLECTIONS
2527 CFArrayRef bundles = CFArrayCreateCopy(kCFAllocatorSystemDefault, _allBundles);
2528 #else /* AVOID_WEAK_COLLECTIONS */
2529 CFMutableArrayRef bundles = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeArrayCallBacks);
2530 for (id value in _allBundles) CFArrayAppendValue(bundles, value);
2531 #endif /* AVOID_WEAK_COLLECTIONS */
2532 pthread_mutex_unlock(&CFBundleGlobalDataLock);
2533 return bundles;
2534 }
2535
2536 CF_PRIVATE uint8_t _CFBundleLayoutVersion(CFBundleRef bundle) {
2537 return bundle->_version;
2538 }
2539
2540 CF_EXPORT CFURLRef _CFBundleCopyPrivateFrameworksURL(CFBundleRef bundle) {
2541 return CFBundleCopyPrivateFrameworksURL(bundle);
2542 }
2543
2544 CF_EXPORT CFURLRef CFBundleCopyPrivateFrameworksURL(CFBundleRef bundle) {
2545 CFURLRef result = NULL;
2546
2547 if (1 == bundle->_version) {
2548 result = CFURLCreateWithString(CFGetAllocator(bundle), _CFBundlePrivateFrameworksURLFromBase1, bundle->_url);
2549 } else if (2 == bundle->_version) {
2550 result = CFURLCreateWithString(CFGetAllocator(bundle), _CFBundlePrivateFrameworksURLFromBase2, bundle->_url);
2551 } else {
2552 result = CFURLCreateWithString(CFGetAllocator(bundle), _CFBundlePrivateFrameworksURLFromBase0, bundle->_url);
2553 }
2554 return result;
2555 }
2556
2557 CF_EXPORT CFURLRef _CFBundleCopySharedFrameworksURL(CFBundleRef bundle) {
2558 return CFBundleCopySharedFrameworksURL(bundle);
2559 }
2560
2561 CF_EXPORT CFURLRef CFBundleCopySharedFrameworksURL(CFBundleRef bundle) {
2562 CFURLRef result = NULL;
2563
2564 if (1 == bundle->_version) {
2565 result = CFURLCreateWithString(CFGetAllocator(bundle), _CFBundleSharedFrameworksURLFromBase1, bundle->_url);
2566 } else if (2 == bundle->_version) {
2567 result = CFURLCreateWithString(CFGetAllocator(bundle), _CFBundleSharedFrameworksURLFromBase2, bundle->_url);
2568 } else {
2569 result = CFURLCreateWithString(CFGetAllocator(bundle), _CFBundleSharedFrameworksURLFromBase0, bundle->_url);
2570 }
2571 return result;
2572 }
2573
2574 CF_EXPORT CFURLRef _CFBundleCopySharedSupportURL(CFBundleRef bundle) {
2575 return CFBundleCopySharedSupportURL(bundle);
2576 }
2577
2578 CF_EXPORT CFURLRef CFBundleCopySharedSupportURL(CFBundleRef bundle) {
2579 CFURLRef result = NULL;
2580
2581 if (1 == bundle->_version) {
2582 result = CFURLCreateWithString(CFGetAllocator(bundle), _CFBundleSharedSupportURLFromBase1, bundle->_url);
2583 } else if (2 == bundle->_version) {
2584 result = CFURLCreateWithString(CFGetAllocator(bundle), _CFBundleSharedSupportURLFromBase2, bundle->_url);
2585 } else {
2586 result = CFURLCreateWithString(CFGetAllocator(bundle), _CFBundleSharedSupportURLFromBase0, bundle->_url);
2587 }
2588 return result;
2589 }
2590
2591 CF_PRIVATE CFURLRef _CFBundleCopyBuiltInPlugInsURL(CFBundleRef bundle) {
2592 return CFBundleCopyBuiltInPlugInsURL(bundle);
2593 }
2594
2595 CF_EXPORT CFURLRef CFBundleCopyBuiltInPlugInsURL(CFBundleRef bundle) {
2596 CFURLRef result = NULL, alternateResult = NULL;
2597
2598 CFAllocatorRef alloc = CFGetAllocator(bundle);
2599 if (1 == bundle->_version) {
2600 result = CFURLCreateWithString(alloc, _CFBundleBuiltInPlugInsURLFromBase1, bundle->_url);
2601 } else if (2 == bundle->_version) {
2602 result = CFURLCreateWithString(alloc, _CFBundleBuiltInPlugInsURLFromBase2, bundle->_url);
2603 } else {
2604 result = CFURLCreateWithString(alloc, _CFBundleBuiltInPlugInsURLFromBase0, bundle->_url);
2605 }
2606 if (!result || !_urlExists(result)) {
2607 if (1 == bundle->_version) {
2608 alternateResult = CFURLCreateWithString(alloc, _CFBundleAlternateBuiltInPlugInsURLFromBase1, bundle->_url);
2609 } else if (2 == bundle->_version) {
2610 alternateResult = CFURLCreateWithString(alloc, _CFBundleAlternateBuiltInPlugInsURLFromBase2, bundle->_url);
2611 } else {
2612 alternateResult = CFURLCreateWithString(alloc, _CFBundleAlternateBuiltInPlugInsURLFromBase0, bundle->_url);
2613 }
2614 if (alternateResult && _urlExists(alternateResult)) {
2615 if (result) CFRelease(result);
2616 result = alternateResult;
2617 } else {
2618 if (alternateResult) CFRelease(alternateResult);
2619 }
2620 }
2621 return result;
2622 }
2623