通常情况下,如果你有
d = opendir(dirname);
while((dir = readdir(d)) != NULL) {
some_operation(dir->d_name);
}
some_operation 对于每个 d_name 都会失败,因为您应该传递给some_operation 的路径是${dirname}/${dir->d_name},而不仅仅是dir->d_name。
不过,您的程序是硬连线的,可以将特殊目录 . 传递给 opendir;当你这样做时,将dir->d_name 传递给some_operation 是安全的,因为. 始终是当前工作目录。相反,您的问题是 readlink 在应用于损坏的符号链接时不会失败,但 在应用于不是符号链接的目录条目时会失败。如果您在错误消息中包含dir->d_name 和strerror(errno),您自己会更容易解决这个问题,如下所示:
d = opendir(".");
while ((dir = readdir(d)) != 0) {
char buff[256];
if (readlink(dir->d_name, buff, sizeof buff) {
printf("%s: readlink failed: %s\n", dir->d_name, strerror(errno));
} else {
printf("%s -> %s\n", dir->d_name, buff);
}
}
如果你这样做了,你会得到这样的输出:
.gnome2: readlink failed: Invalid argument
.python_history: readlink failed: Invalid argument
test.s: readlink failed: Invalid argument
bin -> .local/bin
[etc]
然后您可能会想到查看 readlink 联机帮助页并发现它在应用于非符号链接时返回 EINVAL。
检测损坏的符号链接的正确方法是观察lstat 成功但stat 失败并显示ENOENT:
struct stat lst, st;
if (lstat(dir->d_name, &lst)) {
/* some other kind of problem */
} else if (!S_ISLNK(lst.st_mode)) {
/* not a symlink at all */
} else if (stat(dir->d_name, &st)) {
if (errno == ENOENT) {
/* broken symlink */
} else {
/* some other kind of problem */
}
} else {
/* valid symlink, `lst` tells you about the link,
`st` tells you about what it points to */
}
如果您不需要来自lst 的任何其他信息,并且您的文件系统支持d_type,则可以跳过lstat 调用:
if (dir->d_type == DT_LNK) {
struct stat st;
if (stat(dir->d_name, &st)) {
if (errno == ENOENT) {
/* broken symlink */
}
}
}
但是不要忽视在DT_UNKNOWN 的情况下同时使用lstat 和stat,否则当您尝试在不报告的文件系统上运行程序时会感到难过d_type 信息。