我正在尝试创建一个递归返回文件夹内容的函数。在测试时,我遇到了一些问题。对于某些文件夹,它可以工作,对于其他文件夹,它会给我一个 EXC_BAD_ACCESS,有时它会停止。
很长一段时间以来,我一直在尝试使用 GDB 对其进行调试,但我就是找不到解决问题的方法。该函数并没有退出,而是如下所示。
#include <stdlib.h>
#include <stdio.h>
#include <dirent.h>
#include <string.h>
#include <errno.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <pwd.h>
/* THIS IS AN EXTRACT FROM A LARGER FILE
THERE MAY BE TO MUCH INCLUDE STATEMENTS
*/
struct Directory {
DIR *handle;
const char *filename;
};
typedef struct Directory Directory;
int DirectoryCreate(const char *n, Directory *d) {
DIR *dh;
char *str;
dh = opendir(n);
if(dh == NULL) {
return -1;
}
d->handle = dh;
str = malloc(strlen(n) + 1);
if(str == NULL) {
errno = ENOMEM;
closedir(d->handle);
return -1;
}
strcpy(str, n);
d->filename = (const char *)str;
return 0;
}
void DirectoryFree(Directory *s) {
if(s->handle) {
closedir(s->handle);
}
if(s->filename) {
free((void *)s->filename);
}
}
void FreeDirectoryArray(Directory *array, size_t size) {
register size_t i;
for(i = 0; i < size; i++) {
DirectoryFree(&(array[i]));
}
free(array);
}
Directory *ReadFolders = NULL;
size_t ReadFoldersSize = 0;
const char *ReadFolderFilename = NULL;
const char *ReadNextRecursiveItemInFolder(const char *folder) {
struct dirent *entry;
struct stat fileStatus;
int status;
mode_t mode;
const char *newFilename;
char *fullName;
char *ptr;
size_t strLen;
if(folder == NULL && ReadFolders == NULL) {
errno = 0;
return NULL;
}
if(folder != NULL) {
/* free the previous directory list */
FreeDirectoryArray(ReadFolders, ReadFoldersSize);
ReadFolders = NULL;
ReadFoldersSize = 0;
/* open the new directory */
ReadFolders = (Directory *)realloc(ReadFolders, sizeof(Directory));
ReadFoldersSize++;
status = DirectoryCreate(folder, ReadFolders);
if(status != 0) {
FreeDirectoryArray(ReadFolders, ReadFoldersSize-1);
ReadFolders = NULL;
return NULL;
}
}
entry = readdir(ReadFolders[ReadFoldersSize - 1].handle);
/* If NULL, go to previous folder */
if(entry == NULL) {
DirectoryFree(&(ReadFolders[ReadFoldersSize - 1]));
--ReadFoldersSize;
/* if it's empty, we've reached the end */
if(ReadFoldersSize == 0) {
free(ReadFolders);
ReadFolders = NULL;
errno = 0;
return NULL;
}
newFilename = ReadNextRecursiveItemInFolder(NULL);
return newFilename;
}
/* Make sure the entry name is not . or .. */
if(strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) {
newFilename = ReadNextRecursiveItemInFolder(NULL);
return newFilename;
}
/* we've got an entry, now construct the full path */
strLen =
strlen(ReadFolders[ReadFoldersSize - 1].filename) +
1 +
strlen(entry->d_name);
fullName = malloc(strLen + 1);
ptr = fullName;
strcpy(ptr, ReadFolders[ReadFoldersSize - 1].filename);
ptr += strlen(ReadFolders[ReadFoldersSize - 1].filename);
strcpy(ptr, "/");
ptr++;
strcpy(ptr, entry->d_name);
newFilename = fullName;
/* no recurse on symbolic links */
status = lstat(newFilename, &fileStatus);
if(status != 0) {
FreeDirectoryArray(ReadFolders, ReadFoldersSize);
ReadFolders = NULL;
ReadFoldersSize = 0;
return NULL;
}
mode = fileStatus.st_mode;
/* if not readable for file or not searchable for folder, get next */
/* if folder and not link, recursively continue */
/* else return the new name */
if((((mode & S_IFDIR) == S_IFDIR) && (mode & S_IXUSR) != S_IXUSR) ||
(mode & S_IRUSR) != S_IRUSR) {
free((void *)newFilename);
newFilename = ReadNextRecursiveItemInFolder(NULL);
return newFilename;
} else if((mode & S_IFDIR) && (mode & S_IFLNK) != S_IFLNK) {
ReadFolders = realloc(ReadFolders, ReadFoldersSize + 1);
ReadFoldersSize++;
errno = 0;
status = DirectoryCreate(newFilename, &(ReadFolders[ReadFoldersSize - 1]));
if(status != 0) {
FreeDirectoryArray(ReadFolders, ReadFoldersSize - 1);
ReadFolders = NULL;
ReadFoldersSize = 0;
return NULL;
}
if(newFilename != ReadFolderFilename) {
free((void *)ReadFolderFilename);
ReadFolderFilename = newFilename;
}
} else {
if(newFilename != ReadFolderFilename) {
free((void *)ReadFolderFilename);
ReadFolderFilename = newFilename;
}
errno = 0;
}
return ReadFolderFilename;
}
int main() {
const char *filename = "/Users/";
const char *entry;
while(1) {
entry = ReadNextRecursiveItemInFolder(filename);
filename = NULL;
if(entry == NULL) {
if(errno == 0) {
printf("End reached\n");
} else {
printf("Error: %s\n", strerror(errno));
}
break;
}
printf("Entry: %s\n", entry);
}
return 0;
}
我将简要说明代码的工作原理。要开始循环目录,您必须为该函数提供完整的目录路径。所有后续调用都必须传递 NULL 以获取行中的下一项,除非它们想要处理另一个目录。
代码递归地计算文件夹中的每个文件和文件夹。它不遵循符号链接(symbolic link),只计算可读文件和可执行目录。为了跟踪其“流程”,该函数使用了 3 个全局变量:
ReadFolders
:Directory
结构数组,用于跟踪不同级别的文件夹。最后一个在后面。ReadFoldersSize
:ReadFolders 中Directory
结构的数量。ReadFolderFilename
:包含最后处理的项目的字符串。
我希望我能在这里找到一些帮助, ief2.
最佳答案
重新分配大小错误:不是“n”而是“n*size”。
所以第 153 行应该是:
ReadFolders = realloc(ReadFolders, (ReadFoldersSize + 1)*sizeof(Directory));
关于c - 尝试递归循环文件夹内容,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4538801/