2 * Copyright (c) 2012 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@
25 Copyright (c) 1999-2011, Apple Inc. All rights reserved.
26 Responsibility: Tony Parker
29 #include "CFInternal.h"
30 #include <CoreFoundation/CFPriv.h>
31 #if DEPLOYMENT_TARGET_WINDOWS
43 #define mkdir(a,b) _NS_mkdir(a)
44 #define rmdir _NS_rmdir
45 #define unlink _NS_unlink
47 #define statinfo _stat
54 #include <sys/types.h>
64 CF_INLINE
int openAutoFSNoWait() {
65 #if DEPLOYMENT_TARGET_WINDOWS
68 return (__CFProphylacticAutofsAccess
? open("/dev/autofs_nowait", 0) : -1);
72 CF_INLINE
void closeAutoFSNoWait(int fd
) {
73 #if DEPLOYMENT_TARGET_WINDOWS
75 if (-1 != fd
) close(fd
);
79 __private_extern__ CFStringRef
_CFCopyExtensionForAbstractType(CFStringRef abstractType
) {
80 return (abstractType
? (CFStringRef
)CFRetain(abstractType
) : NULL
);
84 __private_extern__ Boolean
_CFCreateDirectory(const char *path
) {
85 int no_hang_fd
= openAutoFSNoWait();
86 int ret
= ((mkdir(path
, 0777) == 0) ? true : false);
87 closeAutoFSNoWait(no_hang_fd
);
91 #if DEPLOYMENT_TARGET_WINDOWS
92 // todo: remove this function and make callers use _CFCreateDirectory
93 __private_extern__ Boolean
_CFCreateDirectoryWide(const wchar_t *path
) {
94 return CreateDirectoryW(path
, 0);
98 __private_extern__ Boolean
_CFRemoveDirectory(const char *path
) {
99 int no_hang_fd
= openAutoFSNoWait();
100 int ret
= ((rmdir(path
) == 0) ? true : false);
101 closeAutoFSNoWait(no_hang_fd
);
105 __private_extern__ Boolean
_CFDeleteFile(const char *path
) {
106 int no_hang_fd
= openAutoFSNoWait();
107 int ret
= unlink(path
) == 0;
108 closeAutoFSNoWait(no_hang_fd
);
112 __private_extern__ Boolean
_CFReadBytesFromFile(CFAllocatorRef alloc
, CFURLRef url
, void **bytes
, CFIndex
*length
, CFIndex maxLength
) {
113 // maxLength is the number of bytes desired, or 0 if the whole file is desired regardless of length.
115 struct statinfo statBuf
;
116 char path
[CFMaxPathSize
];
117 if (!CFURLGetFileSystemRepresentation(url
, true, (uint8_t *)path
, CFMaxPathSize
)) {
124 int no_hang_fd
= openAutoFSNoWait();
125 fd
= open(path
, O_RDONLY
|CF_OPENFLGS
, 0666);
128 closeAutoFSNoWait(no_hang_fd
);
131 if (fstat(fd
, &statBuf
) < 0) {
132 int saveerr
= thread_errno();
134 closeAutoFSNoWait(no_hang_fd
);
135 thread_set_errno(saveerr
);
138 if ((statBuf
.st_mode
& S_IFMT
) != S_IFREG
) {
140 closeAutoFSNoWait(no_hang_fd
);
141 thread_set_errno(EACCES
);
144 if (statBuf
.st_size
== 0) {
145 *bytes
= CFAllocatorAllocate(alloc
, 4, 0); // don't return constant string -- it's freed!
146 if (__CFOASafe
) __CFSetLastAllocationEventName(*bytes
, "CFUtilities (file-bytes)");
149 CFIndex desiredLength
;
150 if ((maxLength
>= statBuf
.st_size
) || (maxLength
== 0)) {
151 desiredLength
= statBuf
.st_size
;
153 desiredLength
= maxLength
;
155 *bytes
= CFAllocatorAllocate(alloc
, desiredLength
, 0);
156 if (__CFOASafe
) __CFSetLastAllocationEventName(*bytes
, "CFUtilities (file-bytes)");
157 // fcntl(fd, F_NOCACHE, 1);
158 if (read(fd
, *bytes
, desiredLength
) < 0) {
159 CFAllocatorDeallocate(alloc
, *bytes
);
161 closeAutoFSNoWait(no_hang_fd
);
164 *length
= desiredLength
;
167 closeAutoFSNoWait(no_hang_fd
);
171 __private_extern__ Boolean
_CFWriteBytesToFile(CFURLRef url
, const void *bytes
, CFIndex length
) {
174 struct statinfo statBuf
;
175 char path
[CFMaxPathSize
];
176 if (!CFURLGetFileSystemRepresentation(url
, true, (uint8_t *)path
, CFMaxPathSize
)) {
180 int no_hang_fd
= openAutoFSNoWait();
182 if (0 == stat(path
, &statBuf
)) {
183 mode
= statBuf
.st_mode
;
184 } else if (thread_errno() != ENOENT
) {
185 closeAutoFSNoWait(no_hang_fd
);
188 fd
= open(path
, O_WRONLY
|O_CREAT
|O_TRUNC
|CF_OPENFLGS
, 0666);
190 closeAutoFSNoWait(no_hang_fd
);
193 if (length
&& write(fd
, bytes
, length
) != length
) {
194 int saveerr
= thread_errno();
196 closeAutoFSNoWait(no_hang_fd
);
197 thread_set_errno(saveerr
);
200 #if DEPLOYMENT_TARGET_WINDOWS
201 FlushFileBuffers((HANDLE
)_get_osfhandle(fd
));
206 closeAutoFSNoWait(no_hang_fd
);
211 /* 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
212 If both are present, they are assumed to be in-synch; that is, they both refer to the same directory. */
213 /* Lately, dirSpec appears to be (rightfully) unused. */
214 __private_extern__ CFMutableArrayRef
_CFContentsOfDirectory(CFAllocatorRef alloc
, char *dirPath
, void *dirSpec
, CFURLRef dirURL
, CFStringRef matchingAbstractType
) {
215 CFMutableArrayRef files
= NULL
;
216 Boolean releaseBase
= false;
217 CFIndex pathLength
= dirPath
? strlen(dirPath
) : 0;
218 // MF:!!! Need to use four-letter type codes where appropriate.
219 CFStringRef extension
= (matchingAbstractType
? _CFCopyExtensionForAbstractType(matchingAbstractType
) : NULL
);
220 CFIndex targetExtLen
= (extension
? CFStringGetLength(extension
) : 0);
222 #if DEPLOYMENT_TARGET_WINDOWS
223 // This is a replacement for 'dirent' below, and also uses wchar_t to support unicode paths
224 wchar_t extBuff
[CFMaxPathSize
];
225 int extBuffInteriorDotCount
= 0; //people insist on using extensions like ".trace.plist", so we need to know how many dots back to look :(
227 if (targetExtLen
> 0) {
228 CFIndex usedBytes
= 0;
229 CFStringGetBytes(extension
, CFRangeMake(0, targetExtLen
), kCFStringEncodingUTF16
, 0, false, (uint8_t *)extBuff
, CFMaxPathLength
, &usedBytes
);
230 targetExtLen
= usedBytes
/ sizeof(wchar_t);
231 extBuff
[targetExtLen
] = '\0';
232 wchar_t *extBuffStr
= (wchar_t *)extBuff
;
233 if (extBuffStr
[0] == '.')
234 extBuffStr
++; //skip the first dot, it's legitimate to have ".plist" for example
236 wchar_t *extBuffDotPtr
= extBuffStr
;
237 while ((extBuffDotPtr
= wcschr(extBuffStr
, '.'))) { //find the next . in the extension...
238 extBuffInteriorDotCount
++;
239 extBuffStr
= extBuffDotPtr
+ 1;
243 wchar_t pathBuf
[CFMaxPathSize
];
246 if (!_CFURLGetWideFileSystemRepresentation(dirURL
, true, pathBuf
, CFMaxPathLength
)) {
247 if (extension
) CFRelease(extension
);
251 pathLength
= wcslen(pathBuf
);
254 // Convert dirPath to a wide representation and put it into our pathBuf
255 // Get the real length of the string in UTF16 characters
256 CFStringRef dirPathStr
= CFStringCreateWithCString(kCFAllocatorSystemDefault
, dirPath
, kCFStringEncodingUTF8
);
257 CFIndex strLen
= CFStringGetLength(dirPathStr
);
259 // Copy the string into the buffer and terminate
260 CFStringGetCharacters(dirPathStr
, CFRangeMake(0, strLen
), (UniChar
*)pathBuf
);
263 CFRelease(dirPathStr
);
266 WIN32_FIND_DATAW file
;
269 if (pathLength
+ 2 >= CFMaxPathLength
) {
271 CFRelease(extension
);
276 pathBuf
[pathLength
] = '\\';
277 pathBuf
[pathLength
+ 1] = '*';
278 pathBuf
[pathLength
+ 2] = '\0';
279 handle
= FindFirstFileW(pathBuf
, (LPWIN32_FIND_DATAW
)&file
);
280 if (INVALID_HANDLE_VALUE
== handle
) {
281 pathBuf
[pathLength
] = '\0';
283 CFRelease(extension
);
288 files
= CFArrayCreateMutable(alloc
, 0, &kCFTypeArrayCallBacks
);
292 CFIndex namelen
= wcslen(file
.cFileName
);
293 if (file
.cFileName
[0] == '.' && (namelen
== 1 || (namelen
== 2 && file
.cFileName
[1] == '.'))) {
297 if (targetExtLen
> namelen
) continue; // if the extension is the same length or longer than the name, it can't possibly match.
299 if (targetExtLen
> 0) {
300 if (file
.cFileName
[namelen
- 1] == '.') continue; //filename ends with a dot, no extension
302 wchar_t *fileExt
= NULL
;
304 if (extBuffInteriorDotCount
== 0) {
305 fileExt
= wcsrchr(file
.cFileName
, '.');
306 } else { //find the Nth occurrence of . from the end of the string, to handle ".foo.bar"
307 wchar_t *save
= file
.cFileName
;
308 while ((save
= wcschr(save
, '.')) && !fileExt
) {
309 wchar_t *temp
= save
;
311 while ((temp
= wcschr(temp
, '.'))) {
312 if (++moreDots
== extBuffInteriorDotCount
) break;
314 if (moreDots
== extBuffInteriorDotCount
) {
320 if (!fileExt
) continue; //no extension
322 if (((const wchar_t *)extBuff
)[0] != '.')
323 fileExt
++; //omit the dot if the target file extension omits the dot
325 CFIndex fileExtLen
= wcslen(fileExt
);
327 //if the extensions are different lengths, they can't possibly match
328 if (fileExtLen
!= targetExtLen
) continue;
330 // Check to see if it matches the extension we're looking for.
331 if (_wcsicmp(fileExt
, (const wchar_t *)extBuff
) != 0) {
335 if (dirURL
== NULL
) {
336 CFStringRef dirURLStr
= CFStringCreateWithBytes(alloc
, (const uint8_t *)pathBuf
, pathLength
* sizeof(wchar_t), kCFStringEncodingUTF16
, NO
);
337 dirURL
= CFURLCreateWithFileSystemPath(alloc
, dirURLStr
, kCFURLWindowsPathStyle
, true);
338 CFRelease(dirURLStr
);
341 // MF:!!! What about the trailing slash?
342 CFStringRef fileURLStr
= CFStringCreateWithBytes(alloc
, (const uint8_t *)file
.cFileName
, namelen
* sizeof(wchar_t), kCFStringEncodingUTF16
, NO
);
343 fileURL
= CFURLCreateWithFileSystemPathRelativeToBase(alloc
, fileURLStr
, kCFURLWindowsPathStyle
, (file
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
) ? true : false, dirURL
);
344 CFArrayAppendValue(files
, fileURL
);
346 CFRelease(fileURLStr
);
347 } while (FindNextFileW(handle
, &file
));
349 pathBuf
[pathLength
] = '\0';
351 #elif DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_LINUX || DEPLOYMENT_TARGET_FREEBSD
352 uint8_t extBuff
[CFMaxPathSize
];
353 int extBuffInteriorDotCount
= 0; //people insist on using extensions like ".trace.plist", so we need to know how many dots back to look :(
355 if (targetExtLen
> 0) {
356 CFStringGetBytes(extension
, CFRangeMake(0, targetExtLen
), CFStringFileSystemEncoding(), 0, false, extBuff
, CFMaxPathLength
, &targetExtLen
);
357 extBuff
[targetExtLen
] = '\0';
358 char *extBuffStr
= (char *)extBuff
;
359 if (extBuffStr
[0] == '.')
360 extBuffStr
++; //skip the first dot, it's legitimate to have ".plist" for example
362 char *extBuffDotPtr
= extBuffStr
;
363 while ((extBuffDotPtr
= strchr(extBuffStr
, '.'))) { //find the next . in the extension...
364 extBuffInteriorDotCount
++;
365 extBuffStr
= extBuffDotPtr
+ 1;
369 uint8_t pathBuf
[CFMaxPathSize
];
372 if (!CFURLGetFileSystemRepresentation(dirURL
, true, pathBuf
, CFMaxPathLength
)) {
373 if (extension
) CFRelease(extension
);
376 dirPath
= (char *)pathBuf
;
377 pathLength
= strlen(dirPath
);
381 struct dirent buffer
;
385 int no_hang_fd
= __CFProphylacticAutofsAccess
? open("/dev/autofs_nowait", 0) : -1;
387 DIR *dirp
= opendir(dirPath
);
390 CFRelease(extension
);
392 if (-1 != no_hang_fd
) close(no_hang_fd
);
394 // raiseErrno("opendir", path);
396 files
= CFArrayCreateMutable(alloc
, 0, & kCFTypeArrayCallBacks
);
398 while((0 == readdir_r(dirp
, &buffer
, &dp
)) && dp
) {
400 unsigned namelen
= strlen(dp
->d_name
);
402 // skip . & ..; they cause descenders to go berserk
403 if (dp
->d_name
[0] == '.' && (namelen
== 1 || (namelen
== 2 && dp
->d_name
[1] == '.'))) {
407 if (targetExtLen
> namelen
) continue; // if the extension is the same length or longer than the name, it can't possibly match.
409 if (targetExtLen
> 0) {
410 if (dp
->d_name
[namelen
- 1] == '.') continue; //filename ends with a dot, no extension
412 char *fileExt
= NULL
;
413 if (extBuffInteriorDotCount
== 0) {
414 fileExt
= strrchr(dp
->d_name
, '.');
415 } else { //find the Nth occurrence of . from the end of the string, to handle ".foo.bar"
416 char *save
= dp
->d_name
;
417 while ((save
= strchr(save
, '.')) && !fileExt
) {
420 while ((temp
= strchr(temp
, '.'))) {
421 if (++moreDots
== extBuffInteriorDotCount
) break;
423 if (moreDots
== extBuffInteriorDotCount
) {
429 if (!fileExt
) continue; //no extension
431 if (((char *)extBuff
)[0] != '.')
432 fileExt
++; //omit the dot if the target extension omits the dot; safe, because we checked to make sure it isn't the last character just before
434 size_t fileExtLen
= strlen(fileExt
);
436 //if the extensions are different lengths, they can't possibly match
437 if (fileExtLen
!= targetExtLen
) continue;
439 // Check to see if it matches the extension we're looking for.
440 if (strncmp(fileExt
, (char *)extBuff
, fileExtLen
) != 0) {
444 if (dirURL
== NULL
) {
445 dirURL
= CFURLCreateFromFileSystemRepresentation(alloc
, (uint8_t *)dirPath
, pathLength
, true);
448 if (dp
->d_type
== DT_DIR
|| dp
->d_type
== DT_UNKNOWN
) {
449 Boolean isDir
= (dp
->d_type
== DT_DIR
);
452 char subdirPath
[CFMaxPathLength
];
453 struct statinfo statBuf
;
454 strlcpy(subdirPath
, dirPath
, sizeof(subdirPath
));
455 strlcat(subdirPath
, "/", sizeof(subdirPath
));
456 strlcat(subdirPath
, dp
->d_name
, sizeof(subdirPath
));
457 if (stat(subdirPath
, &statBuf
) == 0) {
458 isDir
= ((statBuf
.st_mode
& S_IFMT
) == S_IFDIR
);
461 #if DEPLOYMENT_TARGET_LINUX
462 fileURL
= CFURLCreateFromFileSystemRepresentationRelativeToBase(alloc
, (uint8_t *)dp
->d_name
, namelen
, isDir
, dirURL
);
464 fileURL
= CFURLCreateFromFileSystemRepresentationRelativeToBase(alloc
, (uint8_t *)dp
->d_name
, dp
->d_namlen
, isDir
, dirURL
);
467 #if DEPLOYMENT_TARGET_LINUX
468 fileURL
= CFURLCreateFromFileSystemRepresentationRelativeToBase (alloc
, (uint8_t *)dp
->d_name
, namelen
, false, dirURL
);
470 fileURL
= CFURLCreateFromFileSystemRepresentationRelativeToBase (alloc
, (uint8_t *)dp
->d_name
, dp
->d_namlen
, false, dirURL
);
473 CFArrayAppendValue(files
, fileURL
);
476 err
= closedir(dirp
);
477 if (-1 != no_hang_fd
) close(no_hang_fd
);
484 CFRelease(extension
);
491 #error _CFContentsOfDirectory() unknown architecture, not implemented
496 CFRelease(extension
);
504 __private_extern__ SInt32
_CFGetPathProperties(CFAllocatorRef alloc
, char *path
, Boolean
*exists
, SInt32
*posixMode
, int64_t *size
, CFDateRef
*modTime
, SInt32
*ownerID
, CFArrayRef
*dirContents
) {
506 Boolean isDirectory
= false;
508 if ((exists
== NULL
) && (posixMode
== NULL
) && (size
== NULL
) && (modTime
== NULL
) && (ownerID
== NULL
) && (dirContents
== NULL
)) {
513 struct statinfo statBuf
;
515 if (stat(path
, &statBuf
) != 0) {
516 // stat failed, but why?
517 if (thread_errno() == ENOENT
) {
520 return thread_errno();
524 isDirectory
= ((statBuf
.st_mode
& S_IFMT
) == S_IFDIR
);
528 if (exists
!= NULL
) {
529 *exists
= fileExists
;
532 if (posixMode
!= NULL
) {
535 *posixMode
= statBuf
.st_mode
;
545 *size
= statBuf
.st_size
;
552 if (modTime
!= NULL
) {
554 #if DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX
555 struct timespec ts
= {statBuf
.st_mtime
, 0};
557 struct timespec ts
= statBuf
.st_mtimespec
;
559 *modTime
= CFDateCreate(alloc
, _CFAbsoluteTimeFromFileTimeSpec(ts
));
565 if (ownerID
!= NULL
) {
568 *ownerID
= statBuf
.st_uid
;
575 if (dirContents
!= NULL
) {
576 if (fileExists
&& isDirectory
) {
578 CFMutableArrayRef contents
= _CFContentsOfDirectory(alloc
, (char *)path
, NULL
, NULL
, NULL
);
581 *dirContents
= contents
;
592 __private_extern__ SInt32
_CFGetFileProperties(CFAllocatorRef alloc
, CFURLRef pathURL
, Boolean
*exists
, SInt32
*posixMode
, int64_t *size
, CFDateRef
*modTime
, SInt32
*ownerID
, CFArrayRef
*dirContents
) {
594 char path
[CFMaxPathSize
];
596 if (!CFURLGetFileSystemRepresentation(pathURL
, true, (uint8_t *)path
, CFMaxPathLength
)) {
600 return _CFGetPathProperties(alloc
, path
, exists
, posixMode
, size
, modTime
, ownerID
, dirContents
);
604 // MF:!!! Should pull in the rest of the UniChar based path utils from Foundation.
605 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_LINUX || DEPLOYMENT_TARGET_FREEBSD
606 #define UNIX_PATH_SEMANTICS
607 #elif DEPLOYMENT_TARGET_WINDOWS
608 #define WINDOWS_PATH_SEMANTICS
610 #error Unknown platform
613 #if defined(WINDOWS_PATH_SEMANTICS)
614 #define CFPreferredSlash ((UniChar)'\\')
615 #elif defined(UNIX_PATH_SEMANTICS)
616 #define CFPreferredSlash ((UniChar)'/')
617 #elif defined(HFS_PATH_SEMANTICS)
618 #define CFPreferredSlash ((UniChar)':')
620 #error Cannot define NSPreferredSlash on this platform
623 #if defined(HFS_PATH_SEMANTICS)
624 #define HAS_DRIVE(S) (false)
625 #define HAS_NET(S) (false)
627 #define HAS_DRIVE(S) ((S)[1] == ':' && (('A' <= (S)[0] && (S)[0] <= 'Z') || ('a' <= (S)[0] && (S)[0] <= 'z')))
628 #define HAS_NET(S) ((S)[0] == '\\' && (S)[1] == '\\')
631 #if defined(WINDOWS_PATH_SEMANTICS)
632 #define IS_SLASH(C) ((C) == '\\' || (C) == '/')
633 #elif defined(UNIX_PATH_SEMANTICS)
634 #define IS_SLASH(C) ((C) == '/')
635 #elif defined(HFS_PATH_SEMANTICS)
636 #define IS_SLASH(C) ((C) == ':')
639 __private_extern__ Boolean
_CFIsAbsolutePath(UniChar
*unichars
, CFIndex length
) {
643 #if defined(WINDOWS_PATH_SEMANTICS)
644 if (unichars
[0] == '~') {
650 if (HAS_NET(unichars
)) {
656 if (IS_SLASH(unichars
[2]) && HAS_DRIVE(unichars
)) {
659 #elif defined(HFS_PATH_SEMANTICS)
660 return !IS_SLASH(unichars
[0]);
662 if (unichars
[0] == '~') {
665 if (IS_SLASH(unichars
[0])) {
672 __private_extern__ Boolean
_CFStripTrailingPathSlashes(UniChar
*unichars
, CFIndex
*length
) {
673 Boolean destHasDrive
= (1 < *length
) && HAS_DRIVE(unichars
);
674 CFIndex oldLength
= *length
;
675 while (((destHasDrive
&& 3 < *length
) || (!destHasDrive
&& 1 < *length
)) && IS_SLASH(unichars
[*length
- 1])) {
678 return (oldLength
!= *length
);
681 __private_extern__ Boolean
_CFAppendTrailingPathSlash(UniChar
*unichars
, CFIndex
*length
, CFIndex maxLength
) {
682 if (maxLength
< *length
+ 1) {
689 if (!IS_SLASH(unichars
[0])) {
690 unichars
[(*length
)++] = CFPreferredSlash
;
694 if (!HAS_DRIVE(unichars
) && !HAS_NET(unichars
)) {
695 unichars
[(*length
)++] = CFPreferredSlash
;
699 unichars
[(*length
)++] = CFPreferredSlash
;
705 __private_extern__ Boolean
_CFAppendPathComponent(UniChar
*unichars
, CFIndex
*length
, CFIndex maxLength
, UniChar
*component
, CFIndex componentLength
) {
706 if (0 == componentLength
) {
709 if (maxLength
< *length
+ 1 + componentLength
) {
712 _CFAppendTrailingPathSlash(unichars
, length
, maxLength
);
713 memmove(unichars
+ *length
, component
, componentLength
* sizeof(UniChar
));
714 *length
+= componentLength
;
718 __private_extern__ Boolean
_CFAppendPathExtension(UniChar
*unichars
, CFIndex
*length
, CFIndex maxLength
, UniChar
*extension
, CFIndex extensionLength
) {
719 if (maxLength
< *length
+ 1 + extensionLength
) {
722 if ((0 < extensionLength
&& IS_SLASH(extension
[0])) || (1 < extensionLength
&& HAS_DRIVE(extension
))) {
725 _CFStripTrailingPathSlashes(unichars
, length
);
730 if (IS_SLASH(unichars
[0]) || unichars
[0] == '~') {
735 if (HAS_DRIVE(unichars
) || HAS_NET(unichars
)) {
740 if (IS_SLASH(unichars
[2]) && HAS_DRIVE(unichars
)) {
745 if (0 < *length
&& unichars
[0] == '~') {
747 Boolean hasSlash
= false;
748 for (idx
= 1; idx
< *length
; idx
++) {
749 if (IS_SLASH(unichars
[idx
])) {
758 unichars
[(*length
)++] = '.';
759 memmove(unichars
+ *length
, extension
, extensionLength
* sizeof(UniChar
));
760 *length
+= extensionLength
;
764 __private_extern__ Boolean
_CFTransmutePathSlashes(UniChar
*unichars
, CFIndex
*length
, UniChar replSlash
) {
765 CFIndex didx
, sidx
, scnt
= *length
;
766 sidx
= (1 < *length
&& HAS_NET(unichars
)) ? 2 : 0;
768 while (sidx
< scnt
) {
769 if (IS_SLASH(unichars
[sidx
])) {
770 unichars
[didx
++] = replSlash
;
771 for (sidx
++; sidx
< scnt
&& IS_SLASH(unichars
[sidx
]); sidx
++);
773 unichars
[didx
++] = unichars
[sidx
++];
777 return (scnt
!= didx
);
780 __private_extern__ CFIndex
_CFStartOfLastPathComponent(UniChar
*unichars
, CFIndex length
) {
785 for (idx
= length
- 1; idx
; idx
--) {
786 if (IS_SLASH(unichars
[idx
- 1])) {
790 if ((2 < length
) && HAS_DRIVE(unichars
)) {
796 __private_extern__ CFIndex
_CFLengthAfterDeletingLastPathComponent(UniChar
*unichars
, CFIndex length
) {
801 for (idx
= length
- 1; idx
; idx
--) {
802 if (IS_SLASH(unichars
[idx
- 1])) {
803 if ((idx
!= 1) && (!HAS_DRIVE(unichars
) || idx
!= 3)) {
809 if ((2 < length
) && HAS_DRIVE(unichars
)) {
815 __private_extern__ CFIndex
_CFStartOfPathExtension(UniChar
*unichars
, CFIndex length
) {
820 for (idx
= length
- 1; idx
; idx
--) {
821 if (IS_SLASH(unichars
[idx
- 1])) {
824 if (unichars
[idx
] != '.') {
827 if (idx
== 2 && HAS_DRIVE(unichars
)) {
835 __private_extern__ CFIndex
_CFLengthAfterDeletingPathExtension(UniChar
*unichars
, CFIndex length
) {
836 CFIndex start
= _CFStartOfPathExtension(unichars
, length
);
837 return ((0 < start
) ? start
: length
);
841 #undef UNIX_PATH_SEMANTICS
842 #undef WINDOWS_PATH_SEMANTICS
843 #undef HFS_PATH_SEMANTICS
844 #undef CFPreferredSlash