]>
Commit | Line | Data |
---|---|---|
b1ab9ed8 | 1 | /* |
d8f41ccd | 2 | * Copyright (c) 2000-2004,2011,2014 Apple Inc. All Rights Reserved. |
b1ab9ed8 A |
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 | ||
25 | // | |
26 | // Utilities | |
27 | // | |
28 | #include <security_utilities/utilities.h> | |
29 | #include <CoreFoundation/CoreFoundation.h> | |
30 | #include <dispatch/dispatch.h> | |
31 | ||
32 | namespace Security | |
33 | { | |
34 | ||
35 | static CFMutableDictionaryRef gCacheDictionaryRef = NULL; | |
36 | static dispatch_once_t gDictionaryCreated = 0; | |
37 | static dispatch_queue_t gSerializeQueue; | |
38 | ||
39 | char *cached_realpath(const char * file_name, char * resolved_name) | |
40 | { | |
41 | dispatch_once(&gDictionaryCreated, | |
42 | ^{ | |
43 | gCacheDictionaryRef = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); | |
44 | gSerializeQueue = dispatch_queue_create("com.apple.SecurityLookupCacheQueue", DISPATCH_QUEUE_SERIAL); | |
45 | }); | |
46 | ||
47 | ||
48 | __block char* valueToReturn = NULL; | |
49 | ||
50 | dispatch_sync(gSerializeQueue, | |
51 | ^{ | |
52 | // Put a maximum limit on the size of this cache. | |
53 | CFIndex entryCount = CFDictionaryGetCount(gCacheDictionaryRef); | |
54 | ||
55 | // make the incoming name a string | |
56 | CFStringRef input = CFStringCreateWithCString(NULL, file_name, kCFStringEncodingUTF8); | |
57 | if (entryCount < OPEN_MAX && input != NULL) // is it acceptable to use the cache? | |
58 | { | |
59 | // see if we can find that string in our dictionary | |
60 | CFStringRef output = (CFStringRef) CFDictionaryGetValue(gCacheDictionaryRef, input); | |
61 | ||
62 | if (output == NULL) | |
63 | { | |
64 | // the string is not in our cache, so use realpath | |
65 | valueToReturn = realpath(file_name, resolved_name); | |
66 | if (valueToReturn != NULL) // no error, so continue | |
67 | { | |
68 | // make a new entry in the dictionary for our string | |
69 | output = CFStringCreateWithCString(NULL, valueToReturn, kCFStringEncodingUTF8); | |
70 | CFDictionaryAddValue(gCacheDictionaryRef, input, output); | |
71 | CFRelease(output); | |
72 | } | |
73 | } | |
74 | else | |
75 | { | |
76 | char* valueToFree = NULL; | |
77 | ||
78 | // we need to extract the value from the output | |
79 | ||
80 | // figure out how big to make our buffer | |
81 | CFIndex size = CFStringGetMaximumSizeForEncoding(CFStringGetLength(output), kCFStringEncodingUTF8) + 1; // account for NULL termination | |
82 | ||
83 | // if the user has passed in a buffer, use it. If not, allocate our own | |
84 | ||
85 | // technically, we don't know the size of the buffer that the | |
86 | // user has passed in. It has to be large enough to hold the | |
87 | // string, however, so we can use size as an estimator. The | |
88 | // result will be the same, however: If the user didn't supply | |
89 | // enough memory, he will crash. We behave exactly the same | |
90 | // as realpath, which is the idea. | |
91 | char *buffer = resolved_name; | |
92 | ||
93 | // allocate a buffer if none was passed in | |
94 | if (buffer == NULL) { | |
95 | valueToFree = buffer = (char*) malloc(size); | |
96 | } | |
97 | ||
98 | if (buffer != NULL) // check to see if malloc failed earlier | |
99 | { | |
100 | if (!CFStringGetCString(output, buffer, size, kCFStringEncodingUTF8)) | |
101 | { | |
102 | free((void*) valueToFree); | |
103 | valueToReturn = NULL; | |
104 | } | |
105 | else | |
106 | { | |
107 | valueToReturn = buffer; | |
108 | } | |
109 | } | |
110 | } | |
111 | } | |
112 | else | |
113 | { | |
114 | valueToReturn = realpath(file_name, resolved_name); | |
115 | } | |
116 | ||
117 | CFRelease(input); | |
118 | }); | |
119 | ||
120 | return valueToReturn; | |
121 | } | |
122 | ||
123 | } | |
124 | ||
125 |