]> git.saurik.com Git - apple/cf.git/blob - URL.subproj/CFURLAccess.c
CF-368.tar.gz
[apple/cf.git] / URL.subproj / CFURLAccess.c
1 /*
2 * Copyright (c) 2005 Apple Computer, 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 /* CFURLAccess.c
24 Copyright 1999-2002, Apple, Inc. All rights reserved.
25 Responsibility: Becky Willrich
26 */
27
28 /*------
29 CFData read/write routines
30 -------*/
31
32 #include "CFInternal.h"
33 #include <CoreFoundation/CFBase.h>
34 #include <CoreFoundation/CFURL.h>
35 #include <CoreFoundation/CFDictionary.h>
36 #include <CoreFoundation/CFURLAccess.h>
37 #include <CoreFoundation/CFDate.h>
38 #include <CoreFoundation/CFNumber.h>
39 #include <string.h>
40
41 #if defined(__WIN32__)
42 #include <winsock2.h>
43 #include <io.h>
44 #include <sys/stat.h>
45 #include <sys/types.h>
46 #include <fcntl.h>
47 #include <errno.h>
48 #define timeval xxx_timeval
49 #define BOOLEAN xxx_BOOLEAN
50 #include <windows.h>
51 #undef BOOLEAN
52 #undef timeval
53 #else
54 #include <stdlib.h>
55 #include <unistd.h>
56 #include <dirent.h>
57 #include <sys/stat.h>
58 #include <sys/types.h>
59 #include <pwd.h>
60 #include <fcntl.h>
61 #include <dlfcn.h>
62 #endif
63
64 #if defined(__MACH__)
65
66 DEFINE_WEAK_CFNETWORK_FUNC(Boolean, _CFURLCreateDataAndPropertiesFromResource, (CFAllocatorRef A, CFURLRef B, CFDataRef *C, CFDictionaryRef *D, CFArrayRef E, SInt32 *F), (A, B, C, D, E, F), false)
67 DEFINE_WEAK_CFNETWORK_FUNC(Boolean, _CFURLWriteDataAndPropertiesToResource, (CFURLRef A, CFDataRef B, CFDictionaryRef C, SInt32 *D), (A, B, C, D), false)
68 DEFINE_WEAK_CFNETWORK_FUNC(Boolean, _CFURLDestroyResource, (CFURLRef A, SInt32 *B), (A, B), false)
69
70 #endif
71
72
73 CONST_STRING_DECL(kCFURLFileExists, "kCFURLFileExists")
74 CONST_STRING_DECL(kCFURLFilePOSIXMode, "kCFURLFilePOSIXMode")
75 CONST_STRING_DECL(kCFURLFileDirectoryContents, "kCFURLFileDirectoryContents")
76 CONST_STRING_DECL(kCFURLFileLength, "kCFURLFileLength")
77 CONST_STRING_DECL(kCFURLFileLastModificationTime, "kCFURLFileLastModificationTime")
78 CONST_STRING_DECL(kCFURLFileOwnerID, "kCFURLFileOwnerID")
79 CONST_STRING_DECL(kCFURLHTTPStatusCode, "kCFURLHTTPStatusCode")
80 CONST_STRING_DECL(kCFURLHTTPStatusLine, "kCFURLHTTPStatusLine")
81
82 // Compatibility property strings -- we obsoleted these names pre-DP4. REW, 5/22/2000
83 CONST_STRING_DECL(kCFFileURLExists, "kCFURLFileExists")
84 CONST_STRING_DECL(kCFFileURLPOSIXMode, "kCFURLFilePOSIXMode")
85 CONST_STRING_DECL(kCFFileURLDirectoryContents, "kCFURLFileDirectoryContents")
86 CONST_STRING_DECL(kCFFileURLSize, "kCFURLFileLength")
87 CONST_STRING_DECL(kCFFileURLLastModificationTime, "kCFURLFileLastModificationTime")
88 CONST_STRING_DECL(kCFHTTPURLStatusCode, "kCFURLHTTPStatusCode")
89 CONST_STRING_DECL(kCFHTTPURLStatusLine, "kCFURLHTTPStatusLine")
90
91 // 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
92
93 /*************************/
94 /* file: access routines */
95 /*************************/
96
97 //#warning CF:For the moment file access failures are ill defined and set the error code to kCFURLUnknownError
98
99 static CFDictionaryRef _CFFileURLCreatePropertiesFromResource(CFAllocatorRef alloc, CFURLRef url, CFArrayRef desiredProperties, SInt32 *errorCode) {
100 // MF:!!! This could/should be changed to use _CFGetFileProperties() to do the actual figuring.
101 static CFArrayRef _allProps = NULL;
102 CFRange arrayRange;
103 SInt32 idx;
104 CFMutableDictionaryRef propertyDict = NULL;
105
106 Boolean exists;
107 SInt32 posixMode;
108 int64_t size;
109 CFDateRef modTime = NULL, *modTimePtr = NULL;
110 CFArrayRef contents = NULL, *contentsPtr = NULL;
111 SInt32 ownerID;
112
113 if (errorCode) *errorCode = 0;
114 if (!desiredProperties) {
115 // 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
116 if (!_allProps) {
117 const void *values[9];
118 values[0] = kCFURLFileExists;
119 values[1] = kCFURLFilePOSIXMode;
120 values[2] = kCFURLFileDirectoryContents;
121 values[3] = kCFURLFileLength;
122 values[4] = kCFURLFileLastModificationTime;
123 values[5] = kCFURLFileOwnerID;
124 _allProps = CFArrayCreate(NULL, values, 6, &kCFTypeArrayCallBacks);
125 }
126 desiredProperties = _allProps;
127 }
128
129 arrayRange.location = 0;
130 arrayRange.length = CFArrayGetCount(desiredProperties);
131 propertyDict = CFDictionaryCreateMutable(alloc, 0, & kCFTypeDictionaryKeyCallBacks, & kCFTypeDictionaryValueCallBacks);
132 if (arrayRange.length == 0) return propertyDict;
133
134 if (CFArrayContainsValue(desiredProperties, arrayRange, kCFURLFileDirectoryContents)) {
135 contentsPtr = &contents;
136 }
137 if (CFArrayContainsValue(desiredProperties, arrayRange, kCFURLFileLastModificationTime)) {
138 modTimePtr = &modTime;
139 }
140
141 if (_CFGetFileProperties(alloc, url, &exists, &posixMode, &size, modTimePtr, &ownerID, contentsPtr) != 0) {
142 if (errorCode) {
143 *errorCode = kCFURLUnknownError;
144 }
145 return propertyDict;
146 }
147
148 for (idx = 0; idx < arrayRange.length; idx ++) {
149 CFStringRef key = (CFMutableStringRef )CFArrayGetValueAtIndex(desiredProperties, idx);
150 if (key == kCFURLFilePOSIXMode || CFEqual(kCFURLFilePOSIXMode, key)) {
151 if (exists) {
152 CFNumberRef num = CFNumberCreate(alloc, kCFNumberSInt32Type, &posixMode);
153 CFDictionarySetValue(propertyDict, kCFURLFilePOSIXMode, num);
154 CFRelease(num);
155 } else if (errorCode) {
156 *errorCode = kCFURLUnknownError;
157 }
158 } else if (key == kCFURLFileDirectoryContents || CFEqual(kCFURLFileDirectoryContents, key)) {
159 if (exists && (posixMode & S_IFMT) == S_IFDIR && contents) {
160 CFDictionarySetValue(propertyDict, kCFURLFileDirectoryContents, contents);
161 } else if (errorCode) {
162 *errorCode = kCFURLUnknownError;
163 }
164 } else if (key == kCFURLFileLength || CFEqual(kCFURLFileLength, key)) {
165 if (exists) {
166 CFNumberRef num = CFNumberCreate(alloc, kCFNumberSInt64Type, &size);
167 CFDictionarySetValue(propertyDict, kCFURLFileLength, num);
168 CFRelease(num);
169 } else if (errorCode) {
170 *errorCode = kCFURLUnknownError;
171 }
172 } else if (key == kCFURLFileLastModificationTime || CFEqual(kCFURLFileLastModificationTime, key)) {
173 if (exists && modTime) {
174 CFDictionarySetValue(propertyDict, kCFURLFileLastModificationTime, modTime);
175 } else if (errorCode) {
176 *errorCode = kCFURLUnknownError;
177 }
178 } else if (key == kCFURLFileExists || CFEqual(kCFURLFileExists, key)) {
179 if (exists) {
180 CFDictionarySetValue(propertyDict, kCFURLFileExists, kCFBooleanTrue);
181 } else {
182 CFDictionarySetValue(propertyDict, kCFURLFileExists, kCFBooleanFalse);
183 }
184 } else if (key == kCFURLFileOwnerID || CFEqual(kCFURLFileOwnerID, key)) {
185 if (exists) {
186 CFNumberRef num = CFNumberCreate(alloc, kCFNumberSInt32Type, &ownerID);
187 CFDictionarySetValue(propertyDict, kCFURLFileOwnerID, num);
188 CFRelease(num);
189 } else if (errorCode) {
190 *errorCode = kCFURLUnknownError;
191 }
192 // Add more properties here
193 } else if (errorCode) {
194 *errorCode = kCFURLUnknownPropertyKeyError;
195 }
196 }
197 if (modTime) CFRelease(modTime);
198 if (contents) CFRelease(contents);
199 return propertyDict;
200 }
201
202 static Boolean _CFFileURLWritePropertiesToResource(CFURLRef url, CFDictionaryRef propertyDict, SInt32 *errorCode) {
203 #if defined(__MACOS8__)
204 return false; // No properties are writable on OS 8
205 #else
206 CFTypeRef buffer[16];
207 CFTypeRef *keys;
208 CFTypeRef *values;
209 Boolean result = true;
210 SInt32 idx, count;
211 char cPath[CFMaxPathSize];
212
213 if (!CFURLGetFileSystemRepresentation(url, true, cPath, CFMaxPathSize)) {
214 if (errorCode) *errorCode = kCFURLImproperArgumentsError;
215 return false;
216 }
217
218 count = CFDictionaryGetCount(propertyDict);
219 if (count < 8) {
220 (CFTypeRef)keys = buffer;
221 (CFTypeRef)values = buffer+8;
222 } else {
223 keys = CFAllocatorAllocate(CFGetAllocator(url), sizeof(void *) * count * 2, 0);
224 values = keys + count;
225 }
226 CFDictionaryGetKeysAndValues(propertyDict, keys, values);
227
228 for (idx = 0; idx < count; idx ++) {
229 CFStringRef key = keys[idx];
230 CFTypeRef value = values[idx];
231 if (key == kCFURLFilePOSIXMode || CFEqual(kCFURLFilePOSIXMode, key)) {
232 SInt32 mode;
233 int err;
234 if (CFNumberGetTypeID() == CFGetTypeID(value)) {
235 CFNumberRef modeNum = (CFNumberRef)value;
236 CFNumberGetValue(modeNum, kCFNumberSInt32Type, &mode);
237 } else {
238 #if defined(__WIN32__)
239 const uint16_t *modePtr = (const uint16_t *)CFDataGetBytePtr((CFDataRef)value);
240 #else
241 const mode_t *modePtr = (const mode_t *)CFDataGetBytePtr((CFDataRef)value);
242 #endif
243 mode = *modePtr;
244 }
245 err = chmod(cPath, mode);
246 if (err != 0) result = false;
247 } else {
248 result = false;
249 }
250 }
251
252 if ((CFTypeRef)keys != buffer) CFAllocatorDeallocate(CFGetAllocator(url), keys);
253
254 if (errorCode) *errorCode = result ? 0 : kCFURLUnknownError;
255 return result;
256 #endif
257 }
258
259 static Boolean _CFFileURLCreateDataAndPropertiesFromResource(CFAllocatorRef alloc, CFURLRef url, CFDataRef *fetchedData, CFArrayRef desiredProperties, CFDictionaryRef *fetchedProperties, SInt32 *errorCode) {
260 Boolean success = true;
261
262 if (errorCode) *errorCode = 0;
263 if (fetchedData) {
264 void *bytes;
265 CFIndex length;
266 Boolean releaseAlloc = false;
267
268 if (alloc == NULL) {
269 // We need a real allocator to pass to _CFReadBytesFromFile so that the CFDataRef we create with
270 // CFDataCreateWithBytesNoCopy() can free up the object _CFReadBytesFromFile() returns.
271 alloc = CFRetain(__CFGetDefaultAllocator());
272 releaseAlloc = true;
273 }
274 if (!_CFReadBytesFromFile(alloc, url, &bytes, &length, 0)) {
275 if (errorCode) *errorCode = kCFURLUnknownError;
276 *fetchedData = NULL;
277 success = false;
278 } else {
279 *fetchedData = CFDataCreateWithBytesNoCopy(alloc, bytes, length, alloc);
280 }
281 if (releaseAlloc) {
282 // Now the CFData should be hanging on to it.
283 CFRelease(alloc);
284 }
285 }
286
287 if (fetchedProperties) {
288 *fetchedProperties = _CFFileURLCreatePropertiesFromResource(alloc, url, desiredProperties, errorCode);
289 if (!*fetchedProperties) success = false;
290 }
291
292 return success;
293 }
294 /*************************/
295 /* Public routines */
296 /*************************/
297
298 Boolean CFURLCreateDataAndPropertiesFromResource(CFAllocatorRef alloc, CFURLRef url, CFDataRef *fetchedData, CFDictionaryRef *fetchedProperties, CFArrayRef desiredProperties, SInt32 *errorCode) {
299 CFStringRef scheme = CFURLCopyScheme(url);
300
301 if (!scheme) {
302 if (errorCode) *errorCode = kCFURLImproperArgumentsError;
303 if (fetchedData) *fetchedData = NULL;
304 if (fetchedProperties) *fetchedProperties = NULL;
305 return false;
306 } else {
307 Boolean result;
308 if (CFStringCompare(scheme, CFSTR("file"), 0) == kCFCompareEqualTo) {
309 result = _CFFileURLCreateDataAndPropertiesFromResource(alloc, url, fetchedData, desiredProperties, fetchedProperties, errorCode);
310 } else {
311 #if defined(__MACH__)
312 result = __CFNetwork__CFURLCreateDataAndPropertiesFromResource(alloc, url, fetchedData, fetchedProperties, desiredProperties, errorCode);
313 if (!result) {
314 if (fetchedData) *fetchedData = NULL;
315 if (fetchedProperties) *fetchedProperties = NULL;
316 if (errorCode) *errorCode = kCFURLUnknownSchemeError;
317 }
318 #else
319 if (fetchedData) *fetchedData = NULL;
320 if (fetchedProperties) *fetchedProperties = NULL;
321 if (errorCode) *errorCode = kCFURLUnknownSchemeError;
322 result = false;
323 #endif
324 }
325 CFRelease(scheme);
326 return result;
327 }
328 }
329
330 CFTypeRef CFURLCreatePropertyFromResource(CFAllocatorRef alloc, CFURLRef url, CFStringRef property, SInt32 *errorCode) {
331 CFArrayRef array = CFArrayCreate(alloc, (const void **)&property, 1, &kCFTypeArrayCallBacks);
332 CFDictionaryRef dict;
333
334 if (CFURLCreateDataAndPropertiesFromResource(alloc, url, NULL, &dict, array, errorCode)) {
335 CFTypeRef result = CFDictionaryGetValue(dict, property);
336 if (result) CFRetain(result);
337 CFRelease(array);
338 CFRelease(dict);
339 return result;
340 } else {
341 if (dict) CFRelease(dict);
342 CFRelease(array);
343 return NULL;
344 }
345 }
346
347 Boolean CFURLWriteDataAndPropertiesToResource(CFURLRef url, CFDataRef data, CFDictionaryRef propertyDict, SInt32 *errorCode) {
348 CFStringRef scheme = CFURLCopyScheme(url);
349 if (!scheme) {
350 if (errorCode) *errorCode = kCFURLImproperArgumentsError;
351 return false;
352 } else if (CFStringCompare(scheme, CFSTR("file"), 0) == kCFCompareEqualTo) {
353 Boolean success = true;
354 CFRelease(scheme);
355 if (errorCode) *errorCode = 0;
356 if (data) {
357 if (CFURLHasDirectoryPath(url)) {
358 // Create a directory
359 char cPath[CFMaxPathSize];
360 if (!CFURLGetFileSystemRepresentation(url, true, cPath, CFMaxPathSize)) {
361 if (errorCode) *errorCode = kCFURLImproperArgumentsError;
362 success = false;
363 } else {
364 success = _CFCreateDirectory(cPath);
365 if (!success && errorCode) *errorCode = kCFURLUnknownError;
366 }
367 } else {
368 // Write data
369 SInt32 length = CFDataGetLength(data);
370 const void *bytes = (0 == length) ? (const void *)"" : CFDataGetBytePtr(data);
371 success = _CFWriteBytesToFile(url, bytes, length);
372 if (!success && errorCode) *errorCode = kCFURLUnknownError;
373 }
374 }
375 if (propertyDict) {
376 if (!_CFFileURLWritePropertiesToResource(url, propertyDict, errorCode))
377 success = false;
378 }
379 return success;
380 } else {
381 CFRelease(scheme);
382 #if defined(__MACH__)
383 Boolean result = __CFNetwork__CFURLWriteDataAndPropertiesToResource(url, data, propertyDict, errorCode);
384 if (!result) {
385 if (errorCode) *errorCode = kCFURLUnknownSchemeError;
386 }
387 return result;
388 #else
389 if (errorCode) *errorCode = kCFURLUnknownSchemeError;
390 return false;
391 #endif
392 }
393 }
394
395 Boolean CFURLDestroyResource(CFURLRef url, SInt32 *errorCode) {
396 CFStringRef scheme = CFURLCopyScheme(url);
397 char cPath[CFMaxPathSize];
398
399 if (!scheme) {
400 if (errorCode) *errorCode = kCFURLImproperArgumentsError;
401 return false;
402 } else if (CFStringCompare(scheme, CFSTR("file"), 0) == kCFCompareEqualTo) {
403 CFRelease(scheme);
404 if (!CFURLGetFileSystemRepresentation(url, true, cPath, CFMaxPathSize)) {
405 if (errorCode) *errorCode = kCFURLImproperArgumentsError;
406 return false;
407 }
408
409 if (CFURLHasDirectoryPath(url)) {
410 if (_CFRemoveDirectory(cPath)) {
411 if (errorCode) *errorCode = 0;
412 return true;
413 } else {
414 if (errorCode) *errorCode = kCFURLUnknownError;
415 return false;
416 }
417 } else {
418 if (_CFDeleteFile(cPath)) {
419 if (errorCode) *errorCode = 0;
420 return true;
421 } else {
422 if (errorCode) *errorCode = kCFURLUnknownError;
423 return false;
424 }
425 }
426 } else {
427 CFRelease(scheme);
428 #if defined(__MACH__)
429 Boolean result = __CFNetwork__CFURLDestroyResource(url, errorCode);
430 if (!result) {
431 if (errorCode) *errorCode = kCFURLUnknownSchemeError;
432 }
433 return result;
434 #else
435 if (errorCode) *errorCode = kCFURLUnknownSchemeError;
436 return false;
437 #endif
438 }
439 }
440