in Frameworks/CoreFoundation/Base.subproj/CFFileUtilities.c [296:584]
CF_PRIVATE CFMutableArrayRef _CFCreateContentsOfDirectory(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 targetExtLen = (extension ? CFStringGetLength(extension) : 0);
#if DEPLOYMENT_TARGET_WINDOWS
// This is a replacement for 'dirent' below, and also uses wchar_t to support unicode paths
wchar_t extBuff[CFMaxPathSize];
int extBuffInteriorDotCount = 0; //people insist on using extensions like ".trace.plist", so we need to know how many dots back to look :(
if (targetExtLen > 0) {
CFIndex usedBytes = 0;
CFStringGetBytes(extension, CFRangeMake(0, targetExtLen), kCFStringEncodingUTF16, 0, false, (uint8_t *)extBuff, CFMaxPathLength, &usedBytes);
targetExtLen = usedBytes / sizeof(wchar_t);
extBuff[targetExtLen] = '\0';
wchar_t *extBuffStr = (wchar_t *)extBuff;
if (extBuffStr[0] == '.')
extBuffStr++; //skip the first dot, it's legitimate to have ".plist" for example
wchar_t *extBuffDotPtr = extBuffStr;
while ((extBuffDotPtr = wcschr(extBuffStr, '.'))) { //find the next . in the extension...
extBuffInteriorDotCount++;
extBuffStr = extBuffDotPtr + 1;
}
}
wchar_t pathBuf[CFMaxPathSize];
if (!dirPath) {
if (!_CFURLGetWideFileSystemRepresentation(dirURL, true, pathBuf, CFMaxPathLength)) {
if (extension) CFRelease(extension);
return NULL;
}
pathLength = wcslen(pathBuf);
} else {
// Convert dirPath to a wide representation and put it into our pathBuf
// Get the real length of the string in UTF16 characters
CFStringRef dirPathStr = CFStringCreateWithCString(kCFAllocatorSystemDefault, dirPath, kCFStringEncodingUTF8);
CFIndex strLen = CFStringGetLength(dirPathStr);
// Copy the string into the buffer and terminate
CFStringGetCharacters(dirPathStr, CFRangeMake(0, strLen), (UniChar *)pathBuf);
pathBuf[strLen] = 0;
CFRelease(dirPathStr);
}
WIN32_FIND_DATAW file;
HANDLE handle;
if (pathLength + 2 >= CFMaxPathLength) {
if (extension) {
CFRelease(extension);
}
return NULL;
}
pathBuf[pathLength] = '\\';
pathBuf[pathLength + 1] = '*';
pathBuf[pathLength + 2] = '\0';
handle = FindFirstFileExW(pathBuf, FindExInfoStandard, (LPWIN32_FIND_DATAW)&file, FindExSearchNameMatch, NULL, 0);
if (INVALID_HANDLE_VALUE == handle) {
pathBuf[pathLength] = '\0';
if (extension) {
CFRelease(extension);
}
return NULL;
}
files = CFArrayCreateMutable(alloc, 0, &kCFTypeArrayCallBacks);
do {
CFURLRef fileURL;
CFIndex namelen = wcslen(file.cFileName);
if (file.cFileName[0] == '.' && (namelen == 1 || (namelen == 2 && file.cFileName[1] == '.'))) {
continue;
}
if (targetExtLen > namelen) continue; // if the extension is the same length or longer than the name, it can't possibly match.
if (targetExtLen > 0) {
if (file.cFileName[namelen - 1] == '.') continue; //filename ends with a dot, no extension
wchar_t *fileExt = NULL;
if (extBuffInteriorDotCount == 0) {
fileExt = wcsrchr(file.cFileName, '.');
} else { //find the Nth occurrence of . from the end of the string, to handle ".foo.bar"
wchar_t *save = file.cFileName;
while ((save = wcschr(save, '.')) && !fileExt) {
wchar_t *temp = save;
int moreDots = 0;
while ((temp = wcschr(temp, '.'))) {
if (++moreDots == extBuffInteriorDotCount) break;
}
if (moreDots == extBuffInteriorDotCount) {
fileExt = save;
}
}
}
if (!fileExt) continue; //no extension
if (((const wchar_t *)extBuff)[0] != '.')
fileExt++; //omit the dot if the target file extension omits the dot
CFIndex fileExtLen = wcslen(fileExt);
//if the extensions are different lengths, they can't possibly match
if (fileExtLen != targetExtLen) continue;
// Check to see if it matches the extension we're looking for.
if (_wcsicmp(fileExt, (const wchar_t *)extBuff) != 0) {
continue;
}
}
if (dirURL == NULL) {
CFStringRef dirURLStr = CFStringCreateWithBytes(alloc, (const uint8_t *)pathBuf, pathLength * sizeof(wchar_t), kCFStringEncodingUTF16, NO);
dirURL = CFURLCreateWithFileSystemPath(alloc, dirURLStr, kCFURLWindowsPathStyle, true);
CFRelease(dirURLStr);
releaseBase = true;
}
// MF:!!! What about the trailing slash?
CFStringRef fileURLStr = CFStringCreateWithBytes(alloc, (const uint8_t *)file.cFileName, namelen * sizeof(wchar_t), kCFStringEncodingUTF16, NO);
fileURL = CFURLCreateWithFileSystemPathRelativeToBase(alloc, fileURLStr, kCFURLWindowsPathStyle, (file.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ? true : false, dirURL);
CFArrayAppendValue(files, fileURL);
CFRelease(fileURL);
CFRelease(fileURLStr);
} while (FindNextFileW(handle, &file));
FindClose(handle);
pathBuf[pathLength] = '\0';
#elif DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI || DEPLOYMENT_TARGET_LINUX || DEPLOYMENT_TARGET_FREEBSD
uint8_t extBuff[CFMaxPathSize];
int extBuffInteriorDotCount = 0; //people insist on using extensions like ".trace.plist", so we need to know how many dots back to look :(
if (targetExtLen > 0) {
CFStringGetBytes(extension, CFRangeMake(0, targetExtLen), CFStringFileSystemEncoding(), 0, false, extBuff, CFMaxPathLength, &targetExtLen);
extBuff[targetExtLen] = '\0';
char *extBuffStr = (char *)extBuff;
if (extBuffStr[0] == '.')
extBuffStr++; //skip the first dot, it's legitimate to have ".plist" for example
char *extBuffDotPtr = extBuffStr;
while ((extBuffDotPtr = strchr(extBuffStr, '.'))) { //find the next . in the extension...
extBuffInteriorDotCount++;
extBuffStr = extBuffDotPtr + 1;
}
}
uint8_t pathBuf[CFMaxPathSize];
if (!dirPath) {
if (!CFURLGetFileSystemRepresentation(dirURL, true, pathBuf, CFMaxPathLength)) {
if (extension) CFRelease(extension);
return NULL;
} else {
dirPath = (char *)pathBuf;
pathLength = strlen(dirPath);
}
}
struct dirent buffer;
struct dirent *dp;
int err;
int no_hang_fd = __CFProphylacticAutofsAccess ? open("/dev/autofs_nowait", 0) : -1;
DIR *dirp = opendir(dirPath);
if (!dirp) {
if (extension) {
CFRelease(extension);
}
if (-1 != no_hang_fd) close(no_hang_fd);
return NULL;
// raiseErrno("opendir", path);
}
files = CFArrayCreateMutable(alloc, 0, & kCFTypeArrayCallBacks);
while((0 == readdir_r(dirp, &buffer, &dp)) && dp) {
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 (targetExtLen > namelen) continue; // if the extension is the same length or longer than the name, it can't possibly match.
if (targetExtLen > 0) {
if (dp->d_name[namelen - 1] == '.') continue; //filename ends with a dot, no extension
char *fileExt = NULL;
if (extBuffInteriorDotCount == 0) {
fileExt = strrchr(dp->d_name, '.');
} else { //find the Nth occurrence of . from the end of the string, to handle ".foo.bar"
char *save = dp->d_name;
while ((save = strchr(save, '.')) && !fileExt) {
char *temp = save;
int moreDots = 0;
while ((temp = strchr(temp, '.'))) {
if (++moreDots == extBuffInteriorDotCount) break;
}
if (moreDots == extBuffInteriorDotCount) {
fileExt = save;
}
}
}
if (!fileExt) continue; //no extension
if (((char *)extBuff)[0] != '.')
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
size_t fileExtLen = strlen(fileExt);
//if the extensions are different lengths, they can't possibly match
if (fileExtLen != targetExtLen) continue;
// Check to see if it matches the extension we're looking for.
if (strncmp(fileExt, (char *)extBuff, fileExtLen) != 0) {
continue;
}
}
if (dirURL == NULL) {
dirURL = CFURLCreateFromFileSystemRepresentation(alloc, (uint8_t *)dirPath, pathLength, true);
releaseBase = true;
}
if (dp->d_type == DT_DIR || dp->d_type == DT_UNKNOWN || dp->d_type == DT_LNK || dp->d_type == DT_WHT) {
Boolean isDir = (dp->d_type == DT_DIR);
if (!isDir) {
// Ugh; must stat.
char subdirPath[CFMaxPathLength];
struct statinfo statBuf;
strlcpy(subdirPath, dirPath, sizeof(subdirPath));
strlcat(subdirPath, "/", sizeof(subdirPath));
strlcat(subdirPath, dp->d_name, sizeof(subdirPath));
if (stat(subdirPath, &statBuf) == 0) {
isDir = ((statBuf.st_mode & S_IFMT) == S_IFDIR);
}
}
#if DEPLOYMENT_TARGET_LINUX
fileURL = CFURLCreateFromFileSystemRepresentationRelativeToBase(alloc, (uint8_t *)dp->d_name, namelen, isDir, dirURL);
#else
fileURL = CFURLCreateFromFileSystemRepresentationRelativeToBase(alloc, (uint8_t *)dp->d_name, dp->d_namlen, isDir, dirURL);
#endif
} else {
#if DEPLOYMENT_TARGET_LINUX
fileURL = CFURLCreateFromFileSystemRepresentationRelativeToBase (alloc, (uint8_t *)dp->d_name, namelen, false, dirURL);
#else
fileURL = CFURLCreateFromFileSystemRepresentationRelativeToBase (alloc, (uint8_t *)dp->d_name, dp->d_namlen, false, dirURL);
#endif
}
CFArrayAppendValue(files, fileURL);
CFRelease(fileURL);
}
err = closedir(dirp);
if (-1 != no_hang_fd) close(no_hang_fd);
if (err != 0) {
CFRelease(files);
if (releaseBase) {
CFRelease(dirURL);
}
if (extension) {
CFRelease(extension);
}
return NULL;
}
#else
#error _CFCreateContentsOfDirectory() unknown architecture, not implemented
#endif
if (extension) {
CFRelease(extension);
}
if (releaseBase) {
CFRelease(dirURL);
}
return files;
}