1

我正在寻找检测 C 程序中符号链接中的循环:

$ ln -s self self
$ ln -s a b
$ ln -s b a

这是我到目前为止所得到的:

#include <sys/stat.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>

int 
main(int argc, char *argv[])
{
     struct stat buffer;
     int status;

     if (argc != 2) {
          fprintf(stderr, "error: file name required\n");
          return 0;
     }

     errno = 0;
     status = lstat(argv[1], &buffer);

     if (errno == ELOOP) {
          fprintf(stderr, "loop found");
     }

     return 1;
}

我正在像这样运行我的程序:

$ findloops self
$ findloops a

知道我做错了什么吗?

不是家庭作业。

就是我得到这个想法的地方。

4

4 回答 4

1

我会看看返回的缓冲区。根据 lstat 的文档,缓冲区包含两个相关的项目:

  • st_ino - 文件的 inode(请注意,此编号对于 Linux 文件系统上的每个不同文件和所有目录都是唯一的,但相同的 inode 编号可以出现在不同的文件系统中)。
  • st_dev - 文件当前所在的设备。

如果您创建一个包含每个元素的这两个项目的列表+链接所在的目录作为先前访问的元素,您可以检测到循环。当您离开创建它们的目录时,也不要忘记将它们弹出。

我不相信 ELOOP 是您认为的价值。据此,识别类路径中允许的最大链接,但它不会告诉您哪个链接首先循环。

页面上的文档声称:“ELOOP:在翻译路径名时遇到了太多符号链接。”

于 2009-12-13T18:05:12.363 回答
1

问题是 ' lstat()' 查看符号链接及其属性,而符号链接实际上是存在的。

如果将调用替换为 ' stat()',则会收到 ELOOP 错误。这试图在符号链接的远端获取信息,并且由于 ELOOP 条件而无法找到。

您应该仅errno在验证status表明失败后进行测试。使用真正的系统调用,调用成功时不太可能设置 errno,但是使用库函数,即使调用成功,您也可以发现设置了 errno。例如,使用一些标准 I/O 库实现,您errno == ENOTTY甚至可以在成功调用函数之后;代码检查文件描述符是否代表终端,设置 errno 表示不是,但由于函数成功,检查errno.

于 2009-12-13T18:52:32.797 回答
0

ELOOP 并不一定意味着存在循环。这也可能意味着从源到目标的符号链接太多,如

a -> b -> c -> d -> e ... -> z

这样做足够多次,操作系统内核(尤其是在 linux 上的某些情况下)将放弃尝试跟踪链接,即使它们都是有效且非循环的。

您可能还对 man 2 readlink 感兴趣。

于 2009-12-13T20:40:56.103 回答
0

在玩了一些代码之后,您似乎发现了 lstat(2) 的功能或错误。根据lstat上的man page,也就是stat和fstat,stat和lstat的区别是:

stat() 统计path指向的文件并填写buf。

lstat() 与 stat() 相同,除了如果 path 是符号链接,则链接本身是 stat-ed,而不是它所引用的文件

我拿了你的程序,玩了一下。我使用 lstat、stat 和 fopen 来检查链接。代码如下。底线是 stat 和 fopen 都正确检测到链接,而 lstat 失败。我对此没有任何解释。

下面的程序在创建为“ln -s bar bar”的文件 bar 上执行,给出以下输出:

./foo ./bar
Errno as returned from lstat = 0
Errno as returned from stat = 92
loop found
Errno as returned from fopen = 92
loop found

代码:

#include <sys/stat.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>

int
main(int argc, char *argv[])
{
     struct stat buffer;
     int status;
     int savedErrno1;
     int savedErrno2;
     int savedErrno3;
     FILE *theFile;

     if (argc != 2) {
          printf("error: file name required\n");
          return 0;
     }

     errno = 0;
     status = lstat(argv[1], &buffer);
     savedErrno1 = errno;

     printf("Errno as returned from lstat = %d\n", savedErrno1);

     if (savedErrno1 == ELOOP) {
          printf("loop found\n");
     }

     errno = 0;
     status = stat(argv[1], &buffer);
     savedErrno2 = errno;

     printf("Errno as returned from stat = %d\n", savedErrno2);

     if (savedErrno2 == ELOOP) {
          printf("loop found\n");
     }

     errno = 0;
     theFile = fopen(argv[1], "w");
     savedErrno3 = errno;

     printf("Errno as returned from fopen = %d\n", savedErrno3);

     if (savedErrno3 == ELOOP) {
          printf("loop found\n");
     }

     return 1;
}
于 2009-12-14T02:24:03.790 回答