]> git.saurik.com Git - apple/cf.git/blob - URL.subproj/CFURLAccess.c
CF-299.tar.gz
[apple/cf.git] / URL.subproj / CFURLAccess.c
1 /*
2 * Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
7 *
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * file.
14 *
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
22 *
23 * @APPLE_LICENSE_HEADER_END@
24 */
25 /* CFURLAccess.c
26 Copyright 1999-2002, Apple, Inc. All rights reserved.
27 Responsibility: Becky Willrich
28 */
29
30 /*------
31 CFData read/write routines
32 -------*/
33
34 #include "CFInternal.h"
35 #include <CoreFoundation/CFBase.h>
36 #include <CoreFoundation/CFURL.h>
37 #include <CoreFoundation/CFDictionary.h>
38 #include <CoreFoundation/CFURLAccess.h>
39 #include <CoreFoundation/CFDate.h>
40 #include <CoreFoundation/CFNumber.h>
41 #include <string.h>
42
43 #if defined(__WIN32__)
44 #include <winsock.h>
45 #include <io.h>
46 #include <sys/stat.h>
47 #include <sys/types.h>
48 #include <fcntl.h>
49 #include <errno.h>
50 #define timeval xxx_timeval
51 #define BOOLEAN xxx_BOOLEAN
52 #include <windows.h>
53 #undef BOOLEAN
54 #undef timeval
55 #else
56 #include <unistd.h>
57 #include <dirent.h>
58 #include <sys/stat.h>
59 #include <sys/types.h>
60 #include <pwd.h>
61 #include <fcntl.h>
62 #endif
63
64 #if defined(__MACH__)
65
66 #include <mach-o/dyld.h>
67
68 extern char *getenv(const char *name);
69
70 static void *__CFLoadCFNetwork(void) {
71 static const void *image = NULL;
72 if (NULL == image) {
73 // OS 10.3 change to NSAddImage options here:
74 // a) Use NSADDIMAGE_OPTION_WITH_SEARCHING to support setting common DYLD_ environment variables
75 // including DYLD_IMAGE_SUFFIX and DYLD_LIBRARY_PATH.
76 // b) Use NSADDIMAGE_OPTION_MATCH_FILENAME_BY_INSTALLNAME to fix a nasty problem where two copies of
77 // a given framework are loaded into the same address space (See bug # 3060641).
78 image = ((void*)NSAddImage("/System/Library/Frameworks/CoreServices.framework/Frameworks/CFNetwork.framework/CFNetwork", NSADDIMAGE_OPTION_WITH_SEARCHING | NSADDIMAGE_OPTION_MATCH_FILENAME_BY_INSTALLNAME));
79 }
80 return (void *)image;
81 }
82
83 static Boolean __CFURLCreateDataAndPropertiesFromResource(CFAllocatorRef A, CFURLRef B, CFDataRef *C, CFDictionaryRef *D, CFArrayRef E, SInt32 *F) {
84 static Boolean (*dyfunc)(CFAllocatorRef, CFURLRef, CFDataRef *, CFDictionaryRef *, CFArrayRef, SInt32 *) = NULL;
85 if (NULL == dyfunc) {
86 void *image = __CFLoadCFNetwork();
87 dyfunc = NSAddressOfSymbol(NSLookupSymbolInImage(image, "__CFURLCreateDataAndPropertiesFromResource", NSLOOKUPSYMBOLINIMAGE_OPTION_BIND));
88 }
89 if (dyfunc) {
90 return dyfunc(A, B, C, D, E, F);
91 } else {
92 if (C) *C = NULL;
93 if (D) *D = NULL;
94 if (F) *F = kCFURLUnknownSchemeError;
95 return false;
96 }
97 }
98
99 static Boolean __CFURLWriteDataAndPropertiesToResource(CFURLRef A, CFDataRef B, CFDictionaryRef C, SInt32 *D) {
100 static Boolean (*dyfunc)(CFURLRef, CFDataRef, CFDictionaryRef, SInt32 *) = NULL;
101 if (NULL == dyfunc) {
102 void *image = __CFLoadCFNetwork();
103 dyfunc = NSAddressOfSymbol(NSLookupSymbolInImage(image, "__CFURLWriteDataAndPropertiesToResource", NSLOOKUPSYMBOLINIMAGE_OPTION_BIND));
104 }
105 if (dyfunc) {
106 return dyfunc(A, B, C, D);
107 } else {
108 if (D) *D = kCFURLUnknownSchemeError;
109 return false;
110 }
111 }
112
113 static Boolean __CFURLDestroyResource(CFURLRef A, SInt32 *B) {
114 static Boolean (*dyfunc)(CFURLRef, SInt32 *) = NULL;
115 if (NULL == dyfunc) {
116 void *image = __CFLoadCFNetwork();
117 dyfunc = NSAddressOfSymbol(NSLookupSymbolInImage(image, "__CFURLDestroyResource", NSLOOKUPSYMBOLINIMAGE_OPTION_BIND));
118 }
119 if (dyfunc) {
120 return dyfunc(A, B);
121 } else {
122 if (B) *B = kCFURLUnknownSchemeError;
123 return false;
124 }
125 }
126
127 #endif
128
129
130 CONST_STRING_DECL(kCFURLFileExists, "kCFURLFileExists")
131 CONST_STRING_DECL(kCFURLFilePOSIXMode, "kCFURLFilePOSIXMode")
132 CONST_STRING_DECL(kCFURLFileDirectoryContents, "kCFURLFileDirectoryContents")
133 CONST_STRING_DECL(kCFURLFileLength, "kCFURLFileLength")
134 CONST_STRING_DECL(kCFURLFileLastModificationTime, "kCFURLFileLastModificationTime")
135 CONST_STRING_DECL(kCFURLFileOwnerID, "kCFURLFileOwnerID")
136 CONST_STRING_DECL(kCFURLHTTPStatusCode, "kCFURLHTTPStatusCode")
137 CONST_STRING_DECL(kCFURLHTTPStatusLine, "kCFURLHTTPStatusLine")
138
139 // Compatibility property strings -- we obsoleted these names pre-DP4. REW, 5/22/2000
140 CONST_STRING_DECL(kCFFileURLExists, "kCFURLFileExists")
141 CONST_STRING_DECL(kCFFileURLPOSIXMode, "kCFURLFilePOSIXMode")
142 CONST_STRING_DECL(kCFFileURLDirectoryContents, "kCFURLFileDirectoryContents")
143 CONST_STRING_DECL(kCFFileURLSize, "kCFURLFileLength")
144 CONST_STRING_DECL(kCFFileURLLastModificationTime, "kCFURLFileLastModificationTime")
145 CONST_STRING_DECL(kCFHTTPURLStatusCode, "kCFURLHTTPStatusCode")
146 CONST_STRING_DECL(kCFHTTPURLStatusLine, "kCFURLHTTPStatusLine")
147
148 // Copied pretty much verbatim from NSData; note that files are still special cased in this code. Ultimately, we probably want to treat file URLs the same way as any other URL (go through the URL Access layer). -- REW, 10/21/98
149
150 /*************************/
151 /* file: access routines */
152 /*************************/
153
154 //#warning CF:For the moment file access failures are ill defined and set the error code to kCFURLUnknownError
155
156 static CFDictionaryRef _CFFileURLCreatePropertiesFromResource(CFAllocatorRef alloc, CFURLRef url, CFArrayRef desiredProperties, SInt32 *errorCode) {
157 // MF:!!! This could/should be changed to use _CFGetFileProperties() to do the actual figuring.
158 static CFArrayRef _allProps = NULL;
159 CFRange arrayRange;
160 SInt32 idx;
161 CFMutableDictionaryRef propertyDict = NULL;
162
163 Boolean exists;
164 SInt32 posixMode;
165 int64_t size;
166 CFDateRef modTime = NULL, *modTimePtr = NULL;
167 CFArrayRef contents = NULL, *contentsPtr = NULL;
168 SInt32 ownerID;
169
170 if (errorCode) *errorCode = 0;
171 if (!desiredProperties) {
172 // Cheap and dirty hack to make this work for the moment; ultimately we need to do something more sophisticated. This will result in an error return whenever a property key is defined which isn't applicable to all file URLs. REW, 3/2/99
173 if (!_allProps) {
174 const void *values[9];
175 values[0] = kCFURLFileExists;
176 values[1] = kCFURLFilePOSIXMode;
177 values[2] = kCFURLFileDirectoryContents;
178 values[3] = kCFURLFileLength;
179 values[4] = kCFURLFileLastModificationTime;
180 values[5] = kCFURLFileOwnerID;
181 _allProps = CFArrayCreate(NULL, values, 6, &kCFTypeArrayCallBacks);
182 }
183 desiredProperties = _allProps;
184 }
185
186 arrayRange.location = 0;
187 arrayRange.length = CFArrayGetCount(desiredProperties);
188 propertyDict = CFDictionaryCreateMutable(alloc, 0, & kCFTypeDictionaryKeyCallBacks, & kCFTypeDictionaryValueCallBacks);
189 if (arrayRange.length == 0) return propertyDict;
190
191 if (CFArrayContainsValue(desiredProperties, arrayRange, kCFURLFileDirectoryContents)) {
192 contentsPtr = &contents;
193 }
194 if (CFArrayContainsValue(desiredProperties, arrayRange, kCFURLFileLastModificationTime)) {
195 modTimePtr = &modTime;
196 }
197
198 if (_CFGetFileProperties(alloc, url, &exists, &posixMode, &size, modTimePtr, &ownerID, contentsPtr) != 0) {
199 if (errorCode) {
200 *errorCode = kCFURLUnknownError;
201 }
202 return propertyDict;
203 }
204
205 for (idx = 0; idx < arrayRange.length; idx ++) {
206 CFStringRef key = (CFMutableStringRef )CFArrayGetValueAtIndex(desiredProperties, idx);
207 if (key == kCFURLFilePOSIXMode || CFEqual(kCFURLFilePOSIXMode, key)) {
208 if (exists) {
209 CFNumberRef num = CFNumberCreate(alloc, kCFNumberSInt32Type, &posixMode);
210 CFDictionarySetValue(propertyDict, kCFURLFilePOSIXMode, num);
211 CFRelease(num);
212 } else if (errorCode) {
213 *errorCode = kCFURLUnknownError;
214 }
215 } else if (key == kCFURLFileDirectoryContents || CFEqual(kCFURLFileDirectoryContents, key)) {
216 if (exists && (posixMode & S_IFMT) == S_IFDIR && contents) {
217 CFDictionarySetValue(propertyDict, kCFURLFileDirectoryContents, contents);
218 } else if (errorCode) {
219 *errorCode = kCFURLUnknownError;
220 }
221 } else if (key == kCFURLFileLength || CFEqual(kCFURLFileLength, key)) {
222 if (exists) {
223 CFNumberRef num = CFNumberCreate(alloc, kCFNumberSInt64Type, &size);
224 CFDictionarySetValue(propertyDict, kCFURLFileLength, num);
225 CFRelease(num);
226 } else if (errorCode) {
227 *errorCode = kCFURLUnknownError;
228 }
229 } else if (key == kCFURLFileLastModificationTime || CFEqual(kCFURLFileLastModificationTime, key)) {
230 if (exists && modTime) {
231 CFDictionarySetValue(propertyDict, kCFURLFileLastModificationTime, modTime);
232 } else if (errorCode) {
233 *errorCode = kCFURLUnknownError;
234 }
235 } else if (key == kCFURLFileExists || CFEqual(kCFURLFileExists, key)) {
236 if (exists) {
237 CFDictionarySetValue(propertyDict, kCFURLFileExists, kCFBooleanTrue);
238 } else {
239 CFDictionarySetValue(propertyDict, kCFURLFileExists, kCFBooleanFalse);
240 }
241 } else if (key == kCFURLFileOwnerID || CFEqual(kCFURLFileOwnerID, key)) {
242 if (exists) {
243 CFNumberRef num = CFNumberCreate(alloc, kCFNumberSInt32Type, &ownerID);
244 CFDictionarySetValue(propertyDict, kCFURLFileOwnerID, num);
245 CFRelease(num);
246 } else if (errorCode) {
247 *errorCode = kCFURLUnknownError;
248 }
249 // Add more properties here
250 } else if (errorCode) {
251 *errorCode = kCFURLUnknownPropertyKeyError;
252 }
253 }
254 if (modTime) CFRelease(modTime);
255 if (contents) CFRelease(contents);
256 return propertyDict;
257 }
258
259 static Boolean _CFFileURLWritePropertiesToResource(CFURLRef url, CFDictionaryRef propertyDict, SInt32 *errorCode) {
260 #if defined(__MACOS8__)
261 return false; // No properties are writable on OS 8
262 #else
263 CFTypeRef buffer[16];
264 CFTypeRef *keys;
265 CFTypeRef *values;
266 Boolean result = true;
267 SInt32 idx, count;
268 char cPath[CFMaxPathSize];
269
270 if (!CFURLGetFileSystemRepresentation(url, true, cPath, CFMaxPathSize)) {
271 if (errorCode) *errorCode = kCFURLImproperArgumentsError;
272 return false;
273 }
274
275 count = CFDictionaryGetCount(propertyDict);
276 if (count < 8) {
277 (CFTypeRef)keys = buffer;
278 (CFTypeRef)values = buffer+8;
279 } else {
280 keys = CFAllocatorAllocate(CFGetAllocator(url), sizeof(void *) * count * 2, 0);
281 values = keys + count;
282 }
283 CFDictionaryGetKeysAndValues(propertyDict, keys, values);
284
285 for (idx = 0; idx < count; idx ++) {
286 CFStringRef key = keys[idx];
287 CFTypeRef value = values[idx];
288 if (key == kCFURLFilePOSIXMode || CFEqual(kCFURLFilePOSIXMode, key)) {
289 SInt32 mode;
290 int err;
291 if (CFNumberGetTypeID() == CFGetTypeID(value)) {
292 CFNumberRef modeNum = (CFNumberRef)value;
293 CFNumberGetValue(modeNum, kCFNumberSInt32Type, &mode);
294 } else {
295 #if defined(__WIN32__)
296 const unsigned short *modePtr = (const unsigned short *)CFDataGetBytePtr((CFDataRef)value);
297 #else
298 const mode_t *modePtr = (const mode_t *)CFDataGetBytePtr((CFDataRef)value);
299 #endif
300 mode = *modePtr;
301 }
302 err = chmod(cPath, mode);
303 if (err != 0) result = false;
304 } else {
305 result = false;
306 }
307 }
308
309 if ((CFTypeRef)keys != buffer) CFAllocatorDeallocate(CFGetAllocator(url), keys);
310
311 if (errorCode) *errorCode = result ? 0 : kCFURLUnknownError;
312 return result;
313 #endif
314 }
315
316 static Boolean _CFFileURLCreateDataAndPropertiesFromResource(CFAllocatorRef alloc, CFURLRef url, CFDataRef *fetchedData, CFArrayRef desiredProperties, CFDictionaryRef *fetchedProperties, SInt32 *errorCode) {
317 Boolean success = true;
318
319 if (errorCode) *errorCode = 0;
320 if (fetchedData) {
321 void *bytes;
322 CFIndex length;
323 Boolean releaseAlloc = false;
324
325 if (alloc == NULL) {
326 // We need a real allocator to pass to _CFReadBytesFromFile
327 alloc = CFRetain(__CFGetDefaultAllocator());
328 releaseAlloc = true;
329 }
330 if (!_CFReadBytesFromFile(alloc, url, &bytes, &length, 0)) {
331 if (errorCode) *errorCode = kCFURLUnknownError;
332 *fetchedData = NULL;
333 success = false;
334 } else {
335 *fetchedData = CFDataCreateWithBytesNoCopy(alloc, bytes, length, alloc);
336 }
337 if (releaseAlloc) {
338 // Now the CFData should be hanging on to it.
339 CFRelease(alloc);
340 }
341 }
342
343 if (fetchedProperties) {
344 *fetchedProperties = _CFFileURLCreatePropertiesFromResource(alloc, url, desiredProperties, errorCode);
345 if (!*fetchedProperties) success = false;
346 }
347
348 return success;
349 }
350 /*************************/
351 /* Public routines */
352 /*************************/
353
354 Boolean CFURLCreateDataAndPropertiesFromResource(CFAllocatorRef alloc, CFURLRef url, CFDataRef *fetchedData, CFDictionaryRef *fetchedProperties, CFArrayRef desiredProperties, SInt32 *errorCode) {
355 CFStringRef scheme = CFURLCopyScheme(url);
356
357 if (!scheme) {
358 if (errorCode) *errorCode = kCFURLImproperArgumentsError;
359 if (fetchedData) *fetchedData = NULL;
360 if (fetchedProperties) *fetchedProperties = NULL;
361 return false;
362 } else {
363 Boolean result;
364 if (CFStringCompare(scheme, CFSTR("file"), 0) == kCFCompareEqualTo) {
365 result = _CFFileURLCreateDataAndPropertiesFromResource(alloc, url, fetchedData, desiredProperties, fetchedProperties, errorCode);
366 } else {
367 #if defined(__MACH__)
368 result = __CFURLCreateDataAndPropertiesFromResource(alloc, url, fetchedData, fetchedProperties, desiredProperties, errorCode);
369 #else
370 if (fetchedData) *fetchedData = NULL;
371 if (fetchedProperties) *fetchedProperties = NULL;
372 if (errorCode) *errorCode = kCFURLUnknownSchemeError;
373 result = false;
374 #endif
375 }
376 CFRelease(scheme);
377 return result;
378 }
379 }
380
381 CFTypeRef CFURLCreatePropertyFromResource(CFAllocatorRef alloc, CFURLRef url, CFStringRef property, SInt32 *errorCode) {
382 CFArrayRef array = CFArrayCreate(alloc, (const void **)&property, 1, &kCFTypeArrayCallBacks);
383 CFDictionaryRef dict;
384
385 if (CFURLCreateDataAndPropertiesFromResource(alloc, url, NULL, &dict, array, errorCode)) {
386 CFTypeRef result = CFDictionaryGetValue(dict, property);
387 if (result) CFRetain(result);
388 CFRelease(array);
389 CFRelease(dict);
390 return result;
391 } else {
392 if (dict) CFRelease(dict);
393 CFRelease(array);
394 return NULL;
395 }
396 }
397
398 Boolean CFURLWriteDataAndPropertiesToResource(CFURLRef url, CFDataRef data, CFDictionaryRef propertyDict, SInt32 *errorCode) {
399 CFStringRef scheme = CFURLCopyScheme(url);
400 if (!scheme) {
401 if (errorCode) *errorCode = kCFURLImproperArgumentsError;
402 return false;
403 } else if (CFStringCompare(scheme, CFSTR("file"), 0) == kCFCompareEqualTo) {
404 Boolean success = true;
405 CFRelease(scheme);
406 if (errorCode) *errorCode = 0;
407 if (data) {
408 if (CFURLHasDirectoryPath(url)) {
409 // Create a directory
410 char cPath[CFMaxPathSize];
411 if (!CFURLGetFileSystemRepresentation(url, true, cPath, CFMaxPathSize)) {
412 if (errorCode) *errorCode = kCFURLImproperArgumentsError;
413 success = false;
414 } else {
415 success = _CFCreateDirectory(cPath);
416 if (!success && errorCode) *errorCode = kCFURLUnknownError;
417 }
418 } else {
419 // Write data
420 SInt32 length = CFDataGetLength(data);
421 const void *bytes = (0 == length) ? (const void *)"" : CFDataGetBytePtr(data);
422 success = _CFWriteBytesToFile(url, bytes, length);
423 if (!success && errorCode) *errorCode = kCFURLUnknownError;
424 }
425 }
426 if (propertyDict) {
427 if (!_CFFileURLWritePropertiesToResource(url, propertyDict, errorCode))
428 success = false;
429 }
430 return success;
431 } else {
432 CFRelease(scheme);
433 #if defined(__MACH__)
434 return __CFURLWriteDataAndPropertiesToResource(url, data, propertyDict, errorCode);
435 #else
436 if (errorCode) *errorCode = kCFURLUnknownSchemeError;
437 return false;
438 #endif
439 }
440 }
441
442 Boolean CFURLDestroyResource(CFURLRef url, SInt32 *errorCode) {
443 CFStringRef scheme = CFURLCopyScheme(url);
444 char cPath[CFMaxPathSize];
445
446 if (!scheme) {
447 if (errorCode) *errorCode = kCFURLImproperArgumentsError;
448 return false;
449 } else if (CFStringCompare(scheme, CFSTR("file"), 0) == kCFCompareEqualTo) {
450 CFRelease(scheme);
451 if (!CFURLGetFileSystemRepresentation(url, true, cPath, CFMaxPathSize)) {
452 if (errorCode) *errorCode = kCFURLImproperArgumentsError;
453 return false;
454 }
455
456 if (CFURLHasDirectoryPath(url)) {
457 if (_CFRemoveDirectory(cPath)) {
458 if (errorCode) *errorCode = 0;
459 return true;
460 } else {
461 if (errorCode) *errorCode = kCFURLUnknownError;
462 return false;
463 }
464 } else {
465 if (_CFDeleteFile(cPath)) {
466 if (errorCode) *errorCode = 0;
467 return true;
468 } else {
469 if (errorCode) *errorCode = kCFURLUnknownError;
470 return false;
471 }
472 }
473 } else {
474 CFRelease(scheme);
475 #if defined(__MACH__)
476 return __CFURLDestroyResource(url, errorCode);
477 #else
478 if (errorCode) *errorCode = kCFURLUnknownSchemeError;
479 return false;
480 #endif
481 }
482 }
483