在 Ubuntu(Linux)下调试 readdir(通常指 readdir(3) / readdir_r / opendir + readdir)相关问题时,可以按下面几个层面来做。
常见有几种:
opendir() / readdir() / closedir()getdents() / getdents64()ls(内部也可能用到 readdir)调试前先明确:
man readdir
man getdents
readdir 出错时通常靠 errno:
#include <dirent.h>
#include <errno.h>
#include <stdio.h>
DIR *dir = opendir("/path");
if (!dir) {
perror("opendir");
return 1;
}
struct dirent *entry;
while ((entry = readdir(dir)) != NULL) {
printf("name: %s, type: %d\n", entry->d_name, entry->d_type);
}
if (errno != 0) {
perror("readdir");
}
closedir(dir);
#include <dirent.h>
switch (entry->d_type) {
case DT_REG: printf("file\n"); break;
case DT_DIR: printf("dir\n"); break;
case DT_LNK: printf("symlink\n"); break;
default: printf("other\n");
}
readdir 最终会调用 getdents64:
strace -e trace=file your_program
或只看目录相关:
strace -e openat,getdents64,readdir your_program
示例输出:
openat(AT_FDCWD, "/path", O_RDONLY|O_DIRECTORY) = 3
getdents64(3, /* 10 entries */, 32768) = 1234
如果看到:
ENOENT:路径不存在EACCES:权限不足EMFILE / ENFILE:文件描述符耗尽ltrace -e readdir your_program
可以看到:
readdir(0x55a1c) = 0x7f...
gcc -g -o test test.c
gdb ./test
在 readdir 处打断点:
break readdir
run
step
print entry
如果是静态链接或内联,可能要:
break opendir
break closedir
ls -ld /path
mount | grep path
NFS / FUSE 下 readdir 行为可能异常。
多线程请用:
readdir_r(dir, entry, &result);
要用 errno 判断:
errno = 0;
entry = readdir(dir);
if (!entry && errno != 0) {
perror("readdir");
}
d_type == DT_LNK,需要 stat 进一步判断。
#include <dirent.h>
#include <stdio.h>
#include <errno.h>
int main(int argc, char *argv[]) {
if (argc < 2) return 1;
DIR *d = opendir(argv[1]);
if (!d) { perror("opendir"); return 1; }
struct dirent *e;
errno = 0;
while ((e = readdir(d))) {
printf("%s\n", e->d_name);
}
if (errno) perror("readdir");
closedir(d);
return 0;
}
如果你愿意,可以把:
发出来,我可以帮你具体分析是哪一步出问题。