2 * Copyright (c) 2008 Apple 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: Christopher Kane
28 #include "CFInternal.h"
34 #include <sys/types.h>
40 #define CF_OPENFLGS (0)
43 __private_extern__ CFStringRef
_CFCopyExtensionForAbstractType(CFStringRef abstractType
) {
44 return (abstractType
? (CFStringRef
)CFRetain(abstractType
) : NULL
);
48 __private_extern__ Boolean
_CFCreateDirectory(const char *path
) {
50 return CreateDirectoryA(path
, (LPSECURITY_ATTRIBUTES
)NULL
);
52 int no_hang_fd
= open("/dev/autofs_nowait", 0);
53 int ret
= ((mkdir(path
, 0777) == 0) ? true : false);
59 __private_extern__ Boolean
_CFRemoveDirectory(const char *path
) {
61 return RemoveDirectoryA(path
);
63 int no_hang_fd
= open("/dev/autofs_nowait", 0);
64 int ret
= ((rmdir(path
) == 0) ? true : false);
70 __private_extern__ Boolean
_CFDeleteFile(const char *path
) {
72 return DeleteFileA(path
);
74 int no_hang_fd
= open("/dev/autofs_nowait", 0);
75 int ret
= unlink(path
) == 0;
81 __private_extern__ Boolean
_CFReadBytesFromFile(CFAllocatorRef alloc
, CFURLRef url
, void **bytes
, CFIndex
*length
, CFIndex maxLength
) {
82 // maxLength is the number of bytes desired, or 0 if the whole file is desired regardless of length.
85 char path
[CFMaxPathSize
];
86 if (!CFURLGetFileSystemRepresentation(url
, true, (uint8_t *)path
, CFMaxPathSize
)) {
94 fd
= open(path
, O_RDONLY
|CF_OPENFLGS
, 0666|_S_IREAD
);
96 int no_hang_fd
= open("/dev/autofs_nowait", 0);
97 fd
= open(path
, O_RDONLY
|CF_OPENFLGS
, 0666);
103 if (fstat(fd
, &statBuf
) < 0) {
104 int saveerr
= thread_errno();
107 thread_set_errno(saveerr
);
110 if ((statBuf
.st_mode
& S_IFMT
) != S_IFREG
) {
113 thread_set_errno(EACCES
);
116 if (statBuf
.st_size
== 0) {
117 *bytes
= CFAllocatorAllocate(alloc
, 4, 0); // don't return constant string -- it's freed!
118 if (__CFOASafe
) __CFSetLastAllocationEventName(*bytes
, "CFUtilities (file-bytes)");
121 CFIndex desiredLength
;
122 if ((maxLength
>= statBuf
.st_size
) || (maxLength
== 0)) {
123 desiredLength
= statBuf
.st_size
;
125 desiredLength
= maxLength
;
127 *bytes
= CFAllocatorAllocate(alloc
, desiredLength
, 0);
128 if (__CFOASafe
) __CFSetLastAllocationEventName(*bytes
, "CFUtilities (file-bytes)");
129 // fcntl(fd, F_NOCACHE, 1);
130 if (read(fd
, *bytes
, desiredLength
) < 0) {
131 CFAllocatorDeallocate(alloc
, *bytes
);
136 *length
= desiredLength
;
143 __private_extern__ Boolean
_CFWriteBytesToFile(CFURLRef url
, const void *bytes
, CFIndex length
) {
147 char path
[CFMaxPathSize
];
148 if (!CFURLGetFileSystemRepresentation(url
, true, (uint8_t *)path
, CFMaxPathSize
)) {
154 if (0 == stat(path
, &statBuf
)) {
155 mode
= statBuf
.st_mode
;
156 } else if (thread_errno() != ENOENT
) {
159 fd
= open(path
, O_WRONLY
|O_CREAT
|O_TRUNC
|CF_OPENFLGS
, 0666|_S_IWRITE
);
163 if (length
&& write(fd
, bytes
, length
) != length
) {
164 int saveerr
= thread_errno();
166 thread_set_errno(saveerr
);
169 FlushFileBuffers((HANDLE
)_get_osfhandle(fd
));
172 int no_hang_fd
= open("/dev/autofs_nowait", 0);
174 if (0 == stat(path
, &statBuf
)) {
175 mode
= statBuf
.st_mode
;
176 } else if (thread_errno() != ENOENT
) {
180 fd
= open(path
, O_WRONLY
|O_CREAT
|O_TRUNC
|CF_OPENFLGS
, 0666);
185 if (length
&& write(fd
, bytes
, length
) != length
) {
186 int saveerr
= thread_errno();
189 thread_set_errno(saveerr
);
200 /* On Mac OS 8/9, one of dirSpec and dirURL must be non-NULL. On all other platforms, one of path and dirURL must be non-NULL
201 If both are present, they are assumed to be in-synch; that is, they both refer to the same directory. */
202 /* Lately, dirSpec appears to be (rightfully) unused. */
203 __private_extern__ CFMutableArrayRef
_CFContentsOfDirectory(CFAllocatorRef alloc
, char *dirPath
, void *dirSpec
, CFURLRef dirURL
, CFStringRef matchingAbstractType
) {
204 CFMutableArrayRef files
= NULL
;
205 Boolean releaseBase
= false;
206 CFIndex pathLength
= dirPath
? strlen(dirPath
) : 0;
207 // MF:!!! Need to use four-letter type codes where appropriate.
208 CFStringRef extension
= (matchingAbstractType
? _CFCopyExtensionForAbstractType(matchingAbstractType
) : NULL
);
209 CFIndex extLen
= (extension
? CFStringGetLength(extension
) : 0);
210 uint8_t extBuff
[CFMaxPathSize
];
213 CFStringGetBytes(extension
, CFRangeMake(0, extLen
), CFStringFileSystemEncoding(), 0, false, extBuff
, CFMaxPathLength
, &extLen
);
214 extBuff
[extLen
] = '\0';
217 uint8_t pathBuf
[CFMaxPathSize
];
220 if (!CFURLGetFileSystemRepresentation(dirURL
, true, pathBuf
, CFMaxPathLength
)) {
221 if (extension
) CFRelease(extension
);
224 dirPath
= (char *)pathBuf
;
225 pathLength
= strlen(dirPath
);
229 #if (DEPLOYMENT_TARGET_MACOSX) || defined(__svr4__) || defined(__hpux__) || DEPLOYMENT_TARGET_LINUX || DEPLOYMENT_TARGET_FREEBSD
230 struct dirent buffer
;
234 int no_hang_fd
= open("/dev/autofs_nowait", 0);
236 DIR *dirp
= opendir(dirPath
);
239 CFRelease(extension
);
243 // raiseErrno("opendir", path);
245 files
= CFArrayCreateMutable(alloc
, 0, & kCFTypeArrayCallBacks
);
247 while((0 == readdir_r(dirp
, &buffer
, &dp
)) && dp
) {
249 unsigned namelen
= strlen(dp
->d_name
);
251 // skip . & ..; they cause descenders to go berserk
252 if (dp
->d_name
[0] == '.' && (namelen
== 1 || (namelen
== 2 && dp
->d_name
[1] == '.'))) {
256 if (extLen
> namelen
) continue; // if the extension is the same length or longer than the name, it can't possibly match.
259 // Check to see if it matches the extension we're looking for.
260 if (strncmp(&(dp
->d_name
[namelen
- extLen
]), (char *)extBuff
, extLen
) != 0) {
264 if (dirURL
== NULL
) {
265 dirURL
= CFURLCreateFromFileSystemRepresentation(alloc
, (uint8_t *)dirPath
, pathLength
, true);
268 if (dp
->d_type
== DT_DIR
|| dp
->d_type
== DT_UNKNOWN
) {
269 Boolean isDir
= (dp
->d_type
== DT_DIR
);
272 char subdirPath
[CFMaxPathLength
];
274 strlcpy(subdirPath
, dirPath
, sizeof(subdirPath
));
275 strlcat(subdirPath
, "/", sizeof(subdirPath
));
276 strlcat(subdirPath
, dp
->d_name
, sizeof(subdirPath
));
277 if (stat(subdirPath
, &statBuf
) == 0) {
278 isDir
= ((statBuf
.st_mode
& S_IFMT
) == S_IFDIR
);
281 fileURL
= CFURLCreateFromFileSystemRepresentationRelativeToBase(alloc
, (uint8_t *)dp
->d_name
, dp
->d_namlen
, isDir
, dirURL
);
283 fileURL
= CFURLCreateFromFileSystemRepresentationRelativeToBase (alloc
, (uint8_t *)dp
->d_name
, dp
->d_namlen
, false, dirURL
);
285 CFArrayAppendValue(files
, fileURL
);
288 err
= closedir(dirp
);
296 CFRelease(extension
);
303 #error _CFContentsOfDirectory() unknown architechture, not implemented
308 CFRelease(extension
);
316 __private_extern__ SInt32
_CFGetFileProperties(CFAllocatorRef alloc
, CFURLRef pathURL
, Boolean
*exists
, SInt32
*posixMode
, int64_t *size
, CFDateRef
*modTime
, SInt32
*ownerID
, CFArrayRef
*dirContents
) {
318 Boolean isDirectory
= false;
320 struct stat64 statBuf
;
321 char path
[CFMaxPathSize
];
323 if ((exists
== NULL
) && (posixMode
== NULL
) && (size
== NULL
) && (modTime
== NULL
) && (ownerID
== NULL
) && (dirContents
== NULL
)) {
328 if (!CFURLGetFileSystemRepresentation(pathURL
, true, (uint8_t *)path
, CFMaxPathLength
)) {
332 if (stat64(path
, &statBuf
) != 0) {
333 // stat failed, but why?
334 if (thread_errno() == ENOENT
) {
337 return thread_errno();
341 isDirectory
= ((statBuf
.st_mode
& S_IFMT
) == S_IFDIR
);
345 if (exists
!= NULL
) {
346 *exists
= fileExists
;
349 if (posixMode
!= NULL
) {
352 *posixMode
= statBuf
.st_mode
;
362 *size
= statBuf
.st_size
;
369 if (modTime
!= NULL
) {
371 CFAbsoluteTime theTime
= (CFAbsoluteTime
)statBuf
.st_mtimespec
.tv_sec
- kCFAbsoluteTimeIntervalSince1970
;
372 theTime
+= (CFAbsoluteTime
)statBuf
.st_mtimespec
.tv_nsec
/ 1000000000.0;
373 *modTime
= CFDateCreate(alloc
, theTime
);
379 if (ownerID
!= NULL
) {
382 *ownerID
= statBuf
.st_uid
;
389 if (dirContents
!= NULL
) {
390 if (fileExists
&& isDirectory
) {
392 CFMutableArrayRef contents
= _CFContentsOfDirectory(alloc
, path
, NULL
, pathURL
, NULL
);
395 *dirContents
= contents
;
407 // MF:!!! Should pull in the rest of the UniChar based path utils from Foundation.
408 #if (DEPLOYMENT_TARGET_MACOSX) || defined(__svr4__) || defined(__hpux__) || DEPLOYMENT_TARGET_LINUX || DEPLOYMENT_TARGET_FREEBSD
409 #define UNIX_PATH_SEMANTICS
410 #elif defined(__WIN32__)
411 #define WINDOWS_PATH_SEMANTICS
413 #error Unknown platform
416 #if defined(WINDOWS_PATH_SEMANTICS)
417 #define CFPreferredSlash ((UniChar)'\\')
418 #elif defined(UNIX_PATH_SEMANTICS)
419 #define CFPreferredSlash ((UniChar)'/')
420 #elif defined(HFS_PATH_SEMANTICS)
421 #define CFPreferredSlash ((UniChar)':')
423 #error Cannot define NSPreferredSlash on this platform
426 #if defined(HFS_PATH_SEMANTICS)
427 #define HAS_DRIVE(S) (false)
428 #define HAS_NET(S) (false)
430 #define HAS_DRIVE(S) ((S)[1] == ':' && (('A' <= (S)[0] && (S)[0] <= 'Z') || ('a' <= (S)[0] && (S)[0] <= 'z')))
431 #define HAS_NET(S) ((S)[0] == '\\' && (S)[1] == '\\')
434 #if defined(WINDOWS_PATH_SEMANTICS)
435 #define IS_SLASH(C) ((C) == '\\' || (C) == '/')
436 #elif defined(UNIX_PATH_SEMANTICS)
437 #define IS_SLASH(C) ((C) == '/')
438 #elif defined(HFS_PATH_SEMANTICS)
439 #define IS_SLASH(C) ((C) == ':')
442 __private_extern__ Boolean
_CFIsAbsolutePath(UniChar
*unichars
, CFIndex length
) {
446 #if defined(WINDOWS_PATH_SEMANTICS)
447 if (unichars
[0] == '~') {
453 if (HAS_NET(unichars
)) {
459 if (IS_SLASH(unichars
[2]) && HAS_DRIVE(unichars
)) {
462 #elif defined(HFS_PATH_SEMANTICS)
463 return !IS_SLASH(unichars
[0]);
465 if (unichars
[0] == '~') {
468 if (IS_SLASH(unichars
[0])) {
475 __private_extern__ Boolean
_CFStripTrailingPathSlashes(UniChar
*unichars
, CFIndex
*length
) {
476 Boolean destHasDrive
= (1 < *length
) && HAS_DRIVE(unichars
);
477 CFIndex oldLength
= *length
;
478 while (((destHasDrive
&& 3 < *length
) || (!destHasDrive
&& 1 < *length
)) && IS_SLASH(unichars
[*length
- 1])) {
481 return (oldLength
!= *length
);
484 __private_extern__ Boolean
_CFAppendPathComponent(UniChar
*unichars
, CFIndex
*length
, CFIndex maxLength
, UniChar
*component
, CFIndex componentLength
) {
485 if (0 == componentLength
) {
488 if (maxLength
< *length
+ 1 + componentLength
) {
495 if (!IS_SLASH(unichars
[0])) {
496 unichars
[(*length
)++] = CFPreferredSlash
;
500 if (!HAS_DRIVE(unichars
) && !HAS_NET(unichars
)) {
501 unichars
[(*length
)++] = CFPreferredSlash
;
505 unichars
[(*length
)++] = CFPreferredSlash
;
508 memmove(unichars
+ *length
, component
, componentLength
* sizeof(UniChar
));
509 *length
+= componentLength
;
513 __private_extern__ Boolean
_CFAppendPathExtension(UniChar
*unichars
, CFIndex
*length
, CFIndex maxLength
, UniChar
*extension
, CFIndex extensionLength
) {
514 if (maxLength
< *length
+ 1 + extensionLength
) {
517 if ((0 < extensionLength
&& IS_SLASH(extension
[0])) || (1 < extensionLength
&& HAS_DRIVE(extension
))) {
520 _CFStripTrailingPathSlashes(unichars
, length
);
525 if (IS_SLASH(unichars
[0]) || unichars
[0] == '~') {
530 if (HAS_DRIVE(unichars
) || HAS_NET(unichars
)) {
535 if (IS_SLASH(unichars
[2]) && HAS_DRIVE(unichars
)) {
540 if (0 < *length
&& unichars
[0] == '~') {
542 Boolean hasSlash
= false;
543 for (idx
= 1; idx
< *length
; idx
++) {
544 if (IS_SLASH(unichars
[idx
])) {
553 unichars
[(*length
)++] = '.';
554 memmove(unichars
+ *length
, extension
, extensionLength
* sizeof(UniChar
));
555 *length
+= extensionLength
;
559 __private_extern__ Boolean
_CFTransmutePathSlashes(UniChar
*unichars
, CFIndex
*length
, UniChar replSlash
) {
560 CFIndex didx
, sidx
, scnt
= *length
;
561 sidx
= (1 < *length
&& HAS_NET(unichars
)) ? 2 : 0;
563 while (sidx
< scnt
) {
564 if (IS_SLASH(unichars
[sidx
])) {
565 unichars
[didx
++] = replSlash
;
566 for (sidx
++; sidx
< scnt
&& IS_SLASH(unichars
[sidx
]); sidx
++);
568 unichars
[didx
++] = unichars
[sidx
++];
572 return (scnt
!= didx
);
575 __private_extern__ CFIndex
_CFStartOfLastPathComponent(UniChar
*unichars
, CFIndex length
) {
580 for (idx
= length
- 1; idx
; idx
--) {
581 if (IS_SLASH(unichars
[idx
- 1])) {
585 if ((2 < length
) && HAS_DRIVE(unichars
)) {
591 __private_extern__ CFIndex
_CFLengthAfterDeletingLastPathComponent(UniChar
*unichars
, CFIndex length
) {
596 for (idx
= length
- 1; idx
; idx
--) {
597 if (IS_SLASH(unichars
[idx
- 1])) {
598 if ((idx
!= 1) && (!HAS_DRIVE(unichars
) || idx
!= 3)) {
604 if ((2 < length
) && HAS_DRIVE(unichars
)) {
610 __private_extern__ CFIndex
_CFStartOfPathExtension(UniChar
*unichars
, CFIndex length
) {
615 for (idx
= length
- 1; idx
; idx
--) {
616 if (IS_SLASH(unichars
[idx
- 1])) {
619 if (unichars
[idx
] != '.') {
622 if (idx
== 2 && HAS_DRIVE(unichars
)) {
630 __private_extern__ CFIndex
_CFLengthAfterDeletingPathExtension(UniChar
*unichars
, CFIndex length
) {
631 CFIndex start
= _CFStartOfPathExtension(unichars
, length
);
632 return ((0 < start
) ? start
: length
);
636 #undef UNIX_PATH_SEMANTICS
637 #undef WINDOWS_PATH_SEMANTICS
638 #undef HFS_PATH_SEMANTICS
639 #undef CFPreferredSlash