2 * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
24 Copyright 1999-2002, Apple, Inc. All rights reserved.
25 Responsibility: Becky Willrich
29 CFData read/write routines
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>
41 #if defined(__WIN32__)
45 #include <sys/types.h>
48 #define timeval xxx_timeval
49 #define BOOLEAN xxx_BOOLEAN
58 #include <sys/types.h>
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)
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")
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")
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
93 /*************************/
94 /* file: access routines */
95 /*************************/
97 //#warning CF:For the moment file access failures are ill defined and set the error code to kCFURLUnknownError
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
;
104 CFMutableDictionaryRef propertyDict
= NULL
;
109 CFDateRef modTime
= NULL
, *modTimePtr
= NULL
;
110 CFArrayRef contents
= NULL
, *contentsPtr
= NULL
;
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
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
);
126 desiredProperties
= _allProps
;
129 arrayRange
.location
= 0;
130 arrayRange
.length
= CFArrayGetCount(desiredProperties
);
131 propertyDict
= CFDictionaryCreateMutable(alloc
, 0, & kCFTypeDictionaryKeyCallBacks
, & kCFTypeDictionaryValueCallBacks
);
132 if (arrayRange
.length
== 0) return propertyDict
;
134 if (CFArrayContainsValue(desiredProperties
, arrayRange
, kCFURLFileDirectoryContents
)) {
135 contentsPtr
= &contents
;
137 if (CFArrayContainsValue(desiredProperties
, arrayRange
, kCFURLFileLastModificationTime
)) {
138 modTimePtr
= &modTime
;
141 if (_CFGetFileProperties(alloc
, url
, &exists
, &posixMode
, &size
, modTimePtr
, &ownerID
, contentsPtr
) != 0) {
143 *errorCode
= kCFURLUnknownError
;
148 for (idx
= 0; idx
< arrayRange
.length
; idx
++) {
149 CFStringRef key
= (CFMutableStringRef
)CFArrayGetValueAtIndex(desiredProperties
, idx
);
150 if (key
== kCFURLFilePOSIXMode
|| CFEqual(kCFURLFilePOSIXMode
, key
)) {
152 CFNumberRef num
= CFNumberCreate(alloc
, kCFNumberSInt32Type
, &posixMode
);
153 CFDictionarySetValue(propertyDict
, kCFURLFilePOSIXMode
, num
);
155 } else if (errorCode
) {
156 *errorCode
= kCFURLUnknownError
;
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
;
164 } else if (key
== kCFURLFileLength
|| CFEqual(kCFURLFileLength
, key
)) {
166 CFNumberRef num
= CFNumberCreate(alloc
, kCFNumberSInt64Type
, &size
);
167 CFDictionarySetValue(propertyDict
, kCFURLFileLength
, num
);
169 } else if (errorCode
) {
170 *errorCode
= kCFURLUnknownError
;
172 } else if (key
== kCFURLFileLastModificationTime
|| CFEqual(kCFURLFileLastModificationTime
, key
)) {
173 if (exists
&& modTime
) {
174 CFDictionarySetValue(propertyDict
, kCFURLFileLastModificationTime
, modTime
);
175 } else if (errorCode
) {
176 *errorCode
= kCFURLUnknownError
;
178 } else if (key
== kCFURLFileExists
|| CFEqual(kCFURLFileExists
, key
)) {
180 CFDictionarySetValue(propertyDict
, kCFURLFileExists
, kCFBooleanTrue
);
182 CFDictionarySetValue(propertyDict
, kCFURLFileExists
, kCFBooleanFalse
);
184 } else if (key
== kCFURLFileOwnerID
|| CFEqual(kCFURLFileOwnerID
, key
)) {
186 CFNumberRef num
= CFNumberCreate(alloc
, kCFNumberSInt32Type
, &ownerID
);
187 CFDictionarySetValue(propertyDict
, kCFURLFileOwnerID
, num
);
189 } else if (errorCode
) {
190 *errorCode
= kCFURLUnknownError
;
192 // Add more properties here
193 } else if (errorCode
) {
194 *errorCode
= kCFURLUnknownPropertyKeyError
;
197 if (modTime
) CFRelease(modTime
);
198 if (contents
) CFRelease(contents
);
202 static Boolean
_CFFileURLWritePropertiesToResource(CFURLRef url
, CFDictionaryRef propertyDict
, SInt32
*errorCode
) {
203 #if defined(__MACOS8__)
204 return false; // No properties are writable on OS 8
206 CFTypeRef buffer
[16];
209 Boolean result
= true;
211 char cPath
[CFMaxPathSize
];
213 if (!CFURLGetFileSystemRepresentation(url
, true, cPath
, CFMaxPathSize
)) {
214 if (errorCode
) *errorCode
= kCFURLImproperArgumentsError
;
218 count
= CFDictionaryGetCount(propertyDict
);
220 (CFTypeRef
)keys
= buffer
;
221 (CFTypeRef
)values
= buffer
+8;
223 keys
= CFAllocatorAllocate(CFGetAllocator(url
), sizeof(void *) * count
* 2, 0);
224 values
= keys
+ count
;
226 CFDictionaryGetKeysAndValues(propertyDict
, keys
, values
);
228 for (idx
= 0; idx
< count
; idx
++) {
229 CFStringRef key
= keys
[idx
];
230 CFTypeRef value
= values
[idx
];
231 if (key
== kCFURLFilePOSIXMode
|| CFEqual(kCFURLFilePOSIXMode
, key
)) {
234 if (CFNumberGetTypeID() == CFGetTypeID(value
)) {
235 CFNumberRef modeNum
= (CFNumberRef
)value
;
236 CFNumberGetValue(modeNum
, kCFNumberSInt32Type
, &mode
);
238 #if defined(__WIN32__)
239 const uint16_t *modePtr
= (const uint16_t *)CFDataGetBytePtr((CFDataRef
)value
);
241 const mode_t
*modePtr
= (const mode_t
*)CFDataGetBytePtr((CFDataRef
)value
);
245 err
= chmod(cPath
, mode
);
246 if (err
!= 0) result
= false;
252 if ((CFTypeRef
)keys
!= buffer
) CFAllocatorDeallocate(CFGetAllocator(url
), keys
);
254 if (errorCode
) *errorCode
= result
? 0 : kCFURLUnknownError
;
259 static Boolean
_CFFileURLCreateDataAndPropertiesFromResource(CFAllocatorRef alloc
, CFURLRef url
, CFDataRef
*fetchedData
, CFArrayRef desiredProperties
, CFDictionaryRef
*fetchedProperties
, SInt32
*errorCode
) {
260 Boolean success
= true;
262 if (errorCode
) *errorCode
= 0;
266 Boolean releaseAlloc
= false;
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());
274 if (!_CFReadBytesFromFile(alloc
, url
, &bytes
, &length
, 0)) {
275 if (errorCode
) *errorCode
= kCFURLUnknownError
;
279 *fetchedData
= CFDataCreateWithBytesNoCopy(alloc
, bytes
, length
, alloc
);
282 // Now the CFData should be hanging on to it.
287 if (fetchedProperties
) {
288 *fetchedProperties
= _CFFileURLCreatePropertiesFromResource(alloc
, url
, desiredProperties
, errorCode
);
289 if (!*fetchedProperties
) success
= false;
294 /*************************/
295 /* Public routines */
296 /*************************/
298 Boolean
CFURLCreateDataAndPropertiesFromResource(CFAllocatorRef alloc
, CFURLRef url
, CFDataRef
*fetchedData
, CFDictionaryRef
*fetchedProperties
, CFArrayRef desiredProperties
, SInt32
*errorCode
) {
299 CFStringRef scheme
= CFURLCopyScheme(url
);
302 if (errorCode
) *errorCode
= kCFURLImproperArgumentsError
;
303 if (fetchedData
) *fetchedData
= NULL
;
304 if (fetchedProperties
) *fetchedProperties
= NULL
;
308 if (CFStringCompare(scheme
, CFSTR("file"), 0) == kCFCompareEqualTo
) {
309 result
= _CFFileURLCreateDataAndPropertiesFromResource(alloc
, url
, fetchedData
, desiredProperties
, fetchedProperties
, errorCode
);
311 #if defined(__MACH__)
312 result
= __CFNetwork__CFURLCreateDataAndPropertiesFromResource(alloc
, url
, fetchedData
, fetchedProperties
, desiredProperties
, errorCode
);
314 if (fetchedData
) *fetchedData
= NULL
;
315 if (fetchedProperties
) *fetchedProperties
= NULL
;
316 if (errorCode
) *errorCode
= kCFURLUnknownSchemeError
;
319 if (fetchedData
) *fetchedData
= NULL
;
320 if (fetchedProperties
) *fetchedProperties
= NULL
;
321 if (errorCode
) *errorCode
= kCFURLUnknownSchemeError
;
330 CFTypeRef
CFURLCreatePropertyFromResource(CFAllocatorRef alloc
, CFURLRef url
, CFStringRef property
, SInt32
*errorCode
) {
331 CFArrayRef array
= CFArrayCreate(alloc
, (const void **)&property
, 1, &kCFTypeArrayCallBacks
);
332 CFDictionaryRef dict
;
334 if (CFURLCreateDataAndPropertiesFromResource(alloc
, url
, NULL
, &dict
, array
, errorCode
)) {
335 CFTypeRef result
= CFDictionaryGetValue(dict
, property
);
336 if (result
) CFRetain(result
);
341 if (dict
) CFRelease(dict
);
347 Boolean
CFURLWriteDataAndPropertiesToResource(CFURLRef url
, CFDataRef data
, CFDictionaryRef propertyDict
, SInt32
*errorCode
) {
348 CFStringRef scheme
= CFURLCopyScheme(url
);
350 if (errorCode
) *errorCode
= kCFURLImproperArgumentsError
;
352 } else if (CFStringCompare(scheme
, CFSTR("file"), 0) == kCFCompareEqualTo
) {
353 Boolean success
= true;
355 if (errorCode
) *errorCode
= 0;
357 if (CFURLHasDirectoryPath(url
)) {
358 // Create a directory
359 char cPath
[CFMaxPathSize
];
360 if (!CFURLGetFileSystemRepresentation(url
, true, cPath
, CFMaxPathSize
)) {
361 if (errorCode
) *errorCode
= kCFURLImproperArgumentsError
;
364 success
= _CFCreateDirectory(cPath
);
365 if (!success
&& errorCode
) *errorCode
= kCFURLUnknownError
;
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
;
376 if (!_CFFileURLWritePropertiesToResource(url
, propertyDict
, errorCode
))
382 #if defined(__MACH__)
383 Boolean result
= __CFNetwork__CFURLWriteDataAndPropertiesToResource(url
, data
, propertyDict
, errorCode
);
385 if (errorCode
) *errorCode
= kCFURLUnknownSchemeError
;
389 if (errorCode
) *errorCode
= kCFURLUnknownSchemeError
;
395 Boolean
CFURLDestroyResource(CFURLRef url
, SInt32
*errorCode
) {
396 CFStringRef scheme
= CFURLCopyScheme(url
);
397 char cPath
[CFMaxPathSize
];
400 if (errorCode
) *errorCode
= kCFURLImproperArgumentsError
;
402 } else if (CFStringCompare(scheme
, CFSTR("file"), 0) == kCFCompareEqualTo
) {
404 if (!CFURLGetFileSystemRepresentation(url
, true, cPath
, CFMaxPathSize
)) {
405 if (errorCode
) *errorCode
= kCFURLImproperArgumentsError
;
409 if (CFURLHasDirectoryPath(url
)) {
410 if (_CFRemoveDirectory(cPath
)) {
411 if (errorCode
) *errorCode
= 0;
414 if (errorCode
) *errorCode
= kCFURLUnknownError
;
418 if (_CFDeleteFile(cPath
)) {
419 if (errorCode
) *errorCode
= 0;
422 if (errorCode
) *errorCode
= kCFURLUnknownError
;
428 #if defined(__MACH__)
429 Boolean result
= __CFNetwork__CFURLDestroyResource(url
, errorCode
);
431 if (errorCode
) *errorCode
= kCFURLUnknownSchemeError
;
435 if (errorCode
) *errorCode
= kCFURLUnknownSchemeError
;