+++ /dev/null
-/*
- * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
- *
- * @APPLE_LICENSE_HEADER_START@
- *
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
- *
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
- * limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
- */
-/* CFFileUtilities.c
- Copyright 1999-2002, Apple, Inc. All rights reserved.
- Responsibility: Christopher Kane
-*/
-
-#include "CFInternal.h"
-#include "CFPriv.h"
-#if defined(__WIN32__)
- #include <io.h>
- #include <fcntl.h>
- #include <sys/stat.h>
- #include <errno.h>
- #define timeval xxx_timeval
- #define BOOLEAN xxx_BOOLEAN
- #include <windows.h>
- #undef BOOLEAN
- #undef timeval
- #define fstat _fstat
- #define open _open
- #define close _close
- #define write _write
- #define read _read
- #define stat _stat
-#else
- #include <string.h>
- #include <unistd.h>
- #include <dirent.h>
- #include <sys/stat.h>
- #include <sys/types.h>
- #include <pwd.h>
- #include <fcntl.h>
- #include <errno.h>
- #include <stdio.h>
-#endif
-
-#if defined(__WIN32__)
- #define CF_OPENFLGS (_O_BINARY|_O_NOINHERIT)
-#else
- #define CF_OPENFLGS (0)
-#endif
-
-
-__private_extern__ CFStringRef _CFCopyExtensionForAbstractType(CFStringRef abstractType) {
- return (abstractType ? CFRetain(abstractType) : NULL);
-}
-
-
-__private_extern__ Boolean _CFCreateDirectory(const char *path) {
-#if defined(__WIN32__)
- return CreateDirectoryA(path, (LPSECURITY_ATTRIBUTES)NULL);
-#else
- return ((mkdir(path, 0777) == 0) ? true : false);
-#endif
-}
-
-__private_extern__ Boolean _CFRemoveDirectory(const char *path) {
-#if defined(__WIN32__)
- return RemoveDirectoryA(path);
-#else
- return ((rmdir(path) == 0) ? true : false);
-#endif
-}
-
-__private_extern__ Boolean _CFDeleteFile(const char *path) {
-#if defined(__WIN32__)
- return DeleteFileA(path);
-#else
- return unlink(path) == 0;
-#endif
-}
-
-__private_extern__ Boolean _CFReadBytesFromFile(CFAllocatorRef alloc, CFURLRef url, void **bytes, CFIndex *length, CFIndex maxLength) {
- // maxLength is the number of bytes desired, or 0 if the whole file is desired regardless of length.
- struct stat statBuf;
- int fd = -1;
- char path[CFMaxPathSize];
- if (!CFURLGetFileSystemRepresentation(url, true, path, CFMaxPathSize)) {
- return false;
- }
-
- *bytes = NULL;
-
-
-#if defined(__WIN32__)
- fd = open(path, O_RDONLY|CF_OPENFLGS, 0666|_S_IREAD);
-#else
- fd = open(path, O_RDONLY|CF_OPENFLGS, 0666);
-#endif
- if (fd < 0) {
- return false;
- }
- if (fstat(fd, &statBuf) < 0) {
- int saveerr = thread_errno();
- close(fd);
- thread_set_errno(saveerr);
- return false;
- }
- if ((statBuf.st_mode & S_IFMT) != S_IFREG) {
- close(fd);
- thread_set_errno(EACCES);
- return false;
- }
- if (statBuf.st_size == 0) {
- *bytes = CFAllocatorAllocate(alloc, 4, 0); // don't return constant string -- it's freed!
- if (__CFOASafe) __CFSetLastAllocationEventName(*bytes, "CFUtilities (file-bytes)");
- *length = 0;
- } else {
- CFIndex desiredLength;
- if ((maxLength >= statBuf.st_size) || (maxLength == 0)) {
- desiredLength = statBuf.st_size;
- } else {
- desiredLength = maxLength;
- }
- *bytes = CFAllocatorAllocate(alloc, desiredLength, 0);
- if (__CFOASafe) __CFSetLastAllocationEventName(*bytes, "CFUtilities (file-bytes)");
-// fcntl(fd, F_NOCACHE, 1);
- if (read(fd, *bytes, desiredLength) < 0) {
- CFAllocatorDeallocate(alloc, *bytes);
- close(fd);
- return false;
- }
- *length = desiredLength;
- }
- close(fd);
- return true;
-}
-
-__private_extern__ Boolean _CFWriteBytesToFile(CFURLRef url, const void *bytes, CFIndex length) {
- struct stat statBuf;
- int fd = -1;
- int mode, mask;
- char path[CFMaxPathSize];
- if (!CFURLGetFileSystemRepresentation(url, true, path, CFMaxPathSize)) {
- return false;
- }
-
-#if defined(__WIN32__)
- mask = 0;
-#else
- mask = umask(0);
- umask(mask);
-#endif
- mode = 0666 & ~mask;
- if (0 == stat(path, &statBuf)) {
- mode = statBuf.st_mode;
- } else if (thread_errno() != ENOENT) {
- return false;
- }
-#if defined(__WIN32__)
- fd = open(path, O_WRONLY|O_CREAT|O_TRUNC|CF_OPENFLGS, 0666|_S_IWRITE);
-#else
- fd = open(path, O_WRONLY|O_CREAT|O_TRUNC|CF_OPENFLGS, 0666);
-#endif
- if (fd < 0) {
- return false;
- }
- if (length && write(fd, bytes, length) != length) {
- int saveerr = thread_errno();
- close(fd);
- thread_set_errno(saveerr);
- return false;
- }
-#if defined(__WIN32__)
- FlushFileBuffers((HANDLE)_get_osfhandle(fd));
-#else
- fsync(fd);
-#endif
- close(fd);
- return true;
-}
-
-
-/* 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
-If both are present, they are assumed to be in-synch; that is, they both refer to the same directory. */
-__private_extern__ CFMutableArrayRef _CFContentsOfDirectory(CFAllocatorRef alloc, char *dirPath, void *dirSpec, CFURLRef dirURL, CFStringRef matchingAbstractType) {
- CFMutableArrayRef files = NULL;
- Boolean releaseBase = false;
- CFIndex pathLength = dirPath ? strlen(dirPath) : 0;
- // MF:!!! Need to use four-letter type codes where appropriate.
- CFStringRef extension = (matchingAbstractType ? _CFCopyExtensionForAbstractType(matchingAbstractType) : NULL);
- CFIndex extLen = (extension ? CFStringGetLength(extension) : 0);
- uint8_t extBuff[CFMaxPathSize];
-
- if (extLen > 0) {
- CFStringGetBytes(extension, CFRangeMake(0, extLen), CFStringFileSystemEncoding(), 0, false, extBuff, CFMaxPathSize, &extLen);
- extBuff[extLen] = '\0';
- }
-
- uint8_t pathBuf[CFMaxPathSize];
-
- if (!dirPath) {
- if (!CFURLGetFileSystemRepresentation(dirURL, true, pathBuf, CFMaxPathLength)) {
- if (extension) CFRelease(extension);
- return NULL;
- } else {
- dirPath = pathBuf;
- pathLength = strlen(dirPath);
- }
- }
-
-#if defined(__WIN32__)
- WIN32_FIND_DATA file;
- HANDLE handle;
-
- if (pathLength + 2 >= CFMaxPathLength) {
- if (extension) {
- CFRelease(extension);
- }
- return NULL;
- }
-
- dirPath[pathLength] = '\\';
- dirPath[pathLength + 1] = '*';
- dirPath[pathLength + 2] = '\0';
- handle = FindFirstFileA(dirPath, &file);
- if (INVALID_HANDLE_VALUE == handle) {
- dirPath[pathLength] = '\0';
- if (extension) {
- CFRelease(extension);
- }
- return NULL;
- }
-
- files = CFArrayCreateMutable(alloc, 0, &kCFTypeArrayCallBacks);
-
- do {
- CFURLRef fileURL;
- CFIndex namelen = strlen(file.cFileName);
- if (file.cFileName[0] == '.' && (namelen == 1 || (namelen == 2 && file.cFileName[1] == '.'))) {
- continue;
- }
- if (extLen > 0) {
- // Check to see if it matches the extension we're looking for.
- if (_stricmp(&(file.cFileName[namelen - extLen]), extBuff) != 0) {
- continue;
- }
- }
- if (dirURL == NULL) {
- dirURL = CFURLCreateFromFileSystemRepresentation(alloc, dirPath, pathLength, true);
- releaseBase = true;
- }
- // MF:!!! What about the trailing slash?
- fileURL = CFURLCreateFromFileSystemRepresentationRelativeToBase(alloc, file.cFileName, namelen, false, dirURL);
- CFArrayAppendValue(files, fileURL);
- CFRelease(fileURL);
- } while (FindNextFileA(handle, &file));
- FindClose(handle);
- dirPath[pathLength] = '\0';
-
-#elif defined(__svr4__) || defined(__hpux__) || defined(__LINUX__) || defined(__FREEBSD__)
- /* Solaris and HPUX Implementation */
- /* The Solaris and HPUX code has not been updated for:
- base has been renamed dirURL
- dirPath may be NULL (in which case dirURL is not)
- if dirPath is NULL, pathLength is 0
- */
- DIR *dirp;
- struct dirent *dp;
- int err;
-
- dirp = opendir(dirPath);
- if (!dirp) {
- if (extension) {
- CFRelease(extension);
- }
- return NULL;
- // raiseErrno("opendir", path);
- }
- files = CFArrayCreateMutable(alloc, 0, & kCFTypeArrayCallBacks);
-
- while((dp = readdir(dirp)) != NULL) {
- CFURLRef fileURL;
- unsigned namelen = strlen(dp->d_name);
-
- // skip . & ..; they cause descenders to go berserk
- if (dp->d_name[0] == '.' && (namelen == 1 || (namelen == 2 && dp->d_name[1] == '.'))) {
- continue;
- }
-
- if (extLen > 0) {
- // Check to see if it matches the extension we're looking for.
- if (strncmp(&(dp->d_name[namelen - extLen]), extBuff, extLen) != 0) {
- continue;
- }
- }
- if (dirURL == NULL) {
- dirURL = CFURLCreateFromFileSystemRepresentation(alloc, dirPath, pathLength, true);
- releaseBase = true;
- }
- // MF:!!! What about the trailing slash?
- fileURL = CFURLCreateFromFileSystemRepresentationRelativeToBase(alloc, dp->d_name, namelen, false, dirURL);
- CFArrayAppendValue(files, fileURL);
- CFRelease(fileURL);
- }
- err = closedir(dirp);
- if (err != 0) {
- CFRelease(files);
- if (releaseBase) {
- CFRelease(dirURL);
- }
- if (extension) {
- CFRelease(extension);
- }
- return NULL;
- // raiseErrno("closedir", path);
- }
-
-#elif defined(__MACH__)
- int fd, numread;
- long basep;
- char dirge[8192];
-
- fd = open(dirPath, O_RDONLY, 0777);
- if (fd < 0) {
- if (extension) {
- CFRelease(extension);
- }
- return NULL;
- }
- files = CFArrayCreateMutable(alloc, 0, &kCFTypeArrayCallBacks);
-
- while ((numread = getdirentries(fd, dirge, sizeof(dirge), &basep)) > 0) {
- struct dirent *dent;
- for (dent = (struct dirent *)dirge; dent < (struct dirent *)(dirge + numread); dent = (struct dirent *)((char *)dent + dent->d_reclen)) {
- CFURLRef fileURL;
- CFIndex nameLen;
-
- nameLen = dent->d_namlen;
- // skip . & ..; they cause descenders to go berserk
- if (0 == dent->d_fileno || (dent->d_name[0] == '.' && (nameLen == 1 || (nameLen == 2 && dent->d_name[1] == '.')))) {
- continue;
- }
- if (extLen > 0) {
- // Check to see if it matches the extension we're looking for.
- if (strncmp(&(dent->d_name[nameLen - extLen]), extBuff, extLen) != 0) {
- continue;
- }
- }
- if (dirURL == NULL) {
- dirURL = CFURLCreateFromFileSystemRepresentation(alloc, dirPath, pathLength, true);
- releaseBase = true;
- }
-
- if (dent->d_type == DT_DIR || dent->d_type == DT_UNKNOWN) {
- Boolean isDir = (dent->d_type == DT_DIR);
- if (!isDir) {
- // Ugh; must stat.
- char subdirPath[CFMaxPathLength];
- struct stat statBuf;
- strncpy(subdirPath, dirPath, pathLength);
- subdirPath[pathLength] = '/';
- strncpy(subdirPath + pathLength + 1, dent->d_name, nameLen);
- subdirPath[pathLength + nameLen + 1] = '\0';
- if (stat(subdirPath, &statBuf) == 0) {
- isDir = ((statBuf.st_mode & S_IFMT) == S_IFDIR);
- }
- }
- fileURL = CFURLCreateFromFileSystemRepresentationRelativeToBase(alloc, dent->d_name, nameLen, isDir, dirURL);
- } else {
- fileURL = CFURLCreateFromFileSystemRepresentationRelativeToBase (alloc, dent->d_name, nameLen, false, dirURL);
- }
- CFArrayAppendValue(files, fileURL);
- CFRelease(fileURL);
- }
- }
- close(fd);
- if (-1 == numread) {
- CFRelease(files);
- if (releaseBase) {
- CFRelease(dirURL);
- }
- if (extension) {
- CFRelease(extension);
- }
- return NULL;
- }
-#else
-
-#error _CFContentsOfDirectory() unknown architechture, not implemented
-
-#endif
-
- if (extension) {
- CFRelease(extension);
- }
- if (releaseBase) {
- CFRelease(dirURL);
- }
- return files;
-}
-
-__private_extern__ SInt32 _CFGetFileProperties(CFAllocatorRef alloc, CFURLRef pathURL, Boolean *exists, SInt32 *posixMode, int64_t *size, CFDateRef *modTime, SInt32 *ownerID, CFArrayRef *dirContents) {
- Boolean fileExists;
- Boolean isDirectory = false;
-
- struct stat statBuf;
- char path[CFMaxPathLength];
-
- if ((exists == NULL) && (posixMode == NULL) && (size == NULL) && (modTime == NULL) && (ownerID == NULL) && (dirContents == NULL)) {
- // Nothing to do.
- return 0;
- }
-
- if (!CFURLGetFileSystemRepresentation(pathURL, true, path, CFMaxPathLength)) {
- return -1;
- }
-
- if (stat(path, &statBuf) != 0) {
- // stat failed, but why?
- if (thread_errno() == ENOENT) {
- fileExists = false;
- } else {
- return thread_errno();
- }
- } else {
- fileExists = true;
- isDirectory = ((statBuf.st_mode & S_IFMT) == S_IFDIR);
- }
-
-
- if (exists != NULL) {
- *exists = fileExists;
- }
-
- if (posixMode != NULL) {
- if (fileExists) {
-
- *posixMode = statBuf.st_mode;
-
- } else {
- *posixMode = 0;
- }
- }
-
- if (size != NULL) {
- if (fileExists) {
-
- *size = statBuf.st_size;
-
- } else {
- *size = 0;
- }
- }
-
- if (modTime != NULL) {
- if (fileExists) {
- CFTimeInterval theTime;
-
- theTime = kCFAbsoluteTimeIntervalSince1970 + statBuf.st_mtime;
-
- *modTime = CFDateCreate(alloc, theTime);
- } else {
- *modTime = NULL;
- }
- }
-
- if (ownerID != NULL) {
- if (fileExists) {
-
- *ownerID = statBuf.st_uid;
-
- } else {
- *ownerID = -1;
- }
- }
-
- if (dirContents != NULL) {
- if (fileExists && isDirectory) {
-
- CFMutableArrayRef contents = _CFContentsOfDirectory(alloc, path, NULL, pathURL, NULL);
-
- if (contents) {
- *dirContents = contents;
- } else {
- *dirContents = NULL;
- }
- } else {
- *dirContents = NULL;
- }
- }
- return 0;
-}
-
-
-// MF:!!! Should pull in the rest of the UniChar based path utils from Foundation.
-#if defined(__MACH__) || defined(__svr4__) || defined(__hpux__) || defined(__LINUX__) || defined(__FREEBSD__)
- #define UNIX_PATH_SEMANTICS
-#elif defined(__WIN32__)
- #define WINDOWS_PATH_SEMANTICS
-#else
-#error Unknown platform
-#endif
-
-#if defined(WINDOWS_PATH_SEMANTICS)
- #define CFPreferredSlash ((UniChar)'\\')
-#elif defined(UNIX_PATH_SEMANTICS)
- #define CFPreferredSlash ((UniChar)'/')
-#elif defined(HFS_PATH_SEMANTICS)
- #define CFPreferredSlash ((UniChar)':')
-#else
- #error Cannot define NSPreferredSlash on this platform
-#endif
-
-#if defined(HFS_PATH_SEMANTICS)
-#define HAS_DRIVE(S) (false)
-#define HAS_NET(S) (false)
-#else
-#define HAS_DRIVE(S) ((S)[1] == ':' && (('A' <= (S)[0] && (S)[0] <= 'Z') || ('a' <= (S)[0] && (S)[0] <= 'z')))
-#define HAS_NET(S) ((S)[0] == '\\' && (S)[1] == '\\')
-#endif
-
-#if defined(WINDOWS_PATH_SEMANTICS)
- #define IS_SLASH(C) ((C) == '\\' || (C) == '/')
-#elif defined(UNIX_PATH_SEMANTICS)
- #define IS_SLASH(C) ((C) == '/')
-#elif defined(HFS_PATH_SEMANTICS)
- #define IS_SLASH(C) ((C) == ':')
-#endif
-
-__private_extern__ Boolean _CFIsAbsolutePath(UniChar *unichars, CFIndex length) {
- if (length < 1) {
- return false;
- }
-#if defined(WINDOWS_PATH_SEMANTICS)
- if (unichars[0] == '~') {
- return true;
- }
- if (length < 2) {
- return false;
- }
- if (HAS_NET(unichars)) {
- return true;
- }
- if (length < 3) {
- return false;
- }
- if (IS_SLASH(unichars[2]) && HAS_DRIVE(unichars)) {
- return true;
- }
-#elif defined(HFS_PATH_SEMANTICS)
- return !IS_SLASH(unichars[0]);
-#else
- if (unichars[0] == '~') {
- return true;
- }
- if (IS_SLASH(unichars[0])) {
- return true;
- }
-#endif
- return false;
-}
-
-__private_extern__ Boolean _CFStripTrailingPathSlashes(UniChar *unichars, CFIndex *length) {
- Boolean destHasDrive = (1 < *length) && HAS_DRIVE(unichars);
- CFIndex oldLength = *length;
- while (((destHasDrive && 3 < *length) || (!destHasDrive && 1 < *length)) && IS_SLASH(unichars[*length - 1])) {
- (*length)--;
- }
- return (oldLength != *length);
-}
-
-__private_extern__ Boolean _CFAppendPathComponent(UniChar *unichars, CFIndex *length, CFIndex maxLength, UniChar *component, CFIndex componentLength) {
- if (0 == componentLength) {
- return true;
- }
- if (maxLength < *length + 1 + componentLength) {
- return false;
- }
- switch (*length) {
- case 0:
- break;
- case 1:
- if (!IS_SLASH(unichars[0])) {
- unichars[(*length)++] = CFPreferredSlash;
- }
- break;
- case 2:
- if (!HAS_DRIVE(unichars) && !HAS_NET(unichars)) {
- unichars[(*length)++] = CFPreferredSlash;
- }
- break;
- default:
- unichars[(*length)++] = CFPreferredSlash;
- break;
- }
- memmove(unichars + *length, component, componentLength * sizeof(UniChar));
- *length += componentLength;
- return true;
-}
-
-__private_extern__ Boolean _CFAppendPathExtension(UniChar *unichars, CFIndex *length, CFIndex maxLength, UniChar *extension, CFIndex extensionLength) {
- if (maxLength < *length + 1 + extensionLength) {
- return false;
- }
- if ((0 < extensionLength && IS_SLASH(extension[0])) || (1 < extensionLength && HAS_DRIVE(extension))) {
- return false;
- }
- _CFStripTrailingPathSlashes(unichars, length);
- switch (*length) {
- case 0:
- return false;
- case 1:
- if (IS_SLASH(unichars[0]) || unichars[0] == '~') {
- return false;
- }
- break;
- case 2:
- if (HAS_DRIVE(unichars) || HAS_NET(unichars)) {
- return false;
- }
- break;
- case 3:
- if (IS_SLASH(unichars[2]) && HAS_DRIVE(unichars)) {
- return false;
- }
- break;
- }
- if (0 < *length && unichars[0] == '~') {
- CFIndex idx;
- Boolean hasSlash = false;
- for (idx = 1; idx < *length; idx++) {
- if (IS_SLASH(unichars[idx])) {
- hasSlash = true;
- break;
- }
- }
- if (!hasSlash) {
- return false;
- }
- }
- unichars[(*length)++] = '.';
- memmove(unichars + *length, extension, extensionLength * sizeof(UniChar));
- *length += extensionLength;
- return true;
-}
-
-__private_extern__ Boolean _CFTransmutePathSlashes(UniChar *unichars, CFIndex *length, UniChar replSlash) {
- CFIndex didx, sidx, scnt = *length;
- sidx = (1 < *length && HAS_NET(unichars)) ? 2 : 0;
- didx = sidx;
- while (sidx < scnt) {
- if (IS_SLASH(unichars[sidx])) {
- unichars[didx++] = replSlash;
- for (sidx++; sidx < scnt && IS_SLASH(unichars[sidx]); sidx++);
- } else {
- unichars[didx++] = unichars[sidx++];
- }
- }
- *length = didx;
- return (scnt != didx);
-}
-
-__private_extern__ CFIndex _CFStartOfLastPathComponent(UniChar *unichars, CFIndex length) {
- CFIndex idx;
- if (length < 2) {
- return 0;
- }
- for (idx = length - 1; idx; idx--) {
- if (IS_SLASH(unichars[idx - 1])) {
- return idx;
- }
- }
- if ((2 < length) && HAS_DRIVE(unichars)) {
- return 2;
- }
- return 0;
-}
-
-__private_extern__ CFIndex _CFLengthAfterDeletingLastPathComponent(UniChar *unichars, CFIndex length) {
- CFIndex idx;
- if (length < 2) {
- return 0;
- }
- for (idx = length - 1; idx; idx--) {
- if (IS_SLASH(unichars[idx - 1])) {
- if ((idx != 1) && (!HAS_DRIVE(unichars) || idx != 3)) {
- return idx - 1;
- }
- return idx;
- }
- }
- if ((2 < length) && HAS_DRIVE(unichars)) {
- return 2;
- }
- return 0;
-}
-
-__private_extern__ CFIndex _CFStartOfPathExtension(UniChar *unichars, CFIndex length) {
- CFIndex idx;
- if (length < 2) {
- return 0;
- }
- for (idx = length - 1; idx; idx--) {
- if (IS_SLASH(unichars[idx - 1])) {
- return 0;
- }
- if (unichars[idx] != '.') {
- continue;
- }
- if (idx == 2 && HAS_DRIVE(unichars)) {
- return 0;
- }
- return idx;
- }
- return 0;
-}
-
-__private_extern__ CFIndex _CFLengthAfterDeletingPathExtension(UniChar *unichars, CFIndex length) {
- CFIndex start = _CFStartOfPathExtension(unichars, length);
- return ((0 < start) ? start : length);
-}
-
-#undef CF_OPENFLGS
-#undef UNIX_PATH_SEMANTICS
-#undef WINDOWS_PATH_SEMANTICS
-#undef HFS_PATH_SEMANTICS
-#undef CFPreferredSlash
-#undef HAS_DRIVE
-#undef HAS_NET
-#undef IS_SLASH
-