检测符号链接中的循环(c编程)

时间:2009-12-13 17:57:18

标签: c errno

我正在寻找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

知道我做错了吗?

这是 NOT 作业。

This是我从中得到这个想法的地方。

4 个答案:

答案 0 :(得分:1)

我会看一下buffer returned。根据lstat的文档,缓冲区包含两个相关的项目:

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

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

我不相信ELOOP是你认为的价值。根据{{​​3}},它标识了类路径中容忍的最大链接,但它不会告诉您首先循环哪个链接。

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

答案 1 :(得分:1)

问题在于'lstat()'查看符号链接及其属性,并且符号链接实际存在。

如果用“stat()”替换呼叫,则会出现ELOOP错误。这会尝试在符号链接的远端获取信息,并且由于ELOOP条件而无法找到该信息。

在验证errno表示失败后,您应该只测试status。使用真正的系统调用,在调用成功时不太可能设置errno,但是使用库函数,即使调用成功,也可以找到errno。例如,对于某些标准I / O库实现,即使在成功调用函数之后,您也可以拥有errno == ENOTTY;代码检查文件描述符是否代表终端,并且errno设置为表示它不是,但由于函数成功,检查errno是不合法的。

答案 2 :(得分:0)

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

a - &gt; b - &gt; c - &gt; d - &gt; e ... - &gt; ž

这样做的时间足够多,操作系统内核(特别是Linux上的某些情况)会放弃尝试跟踪链接,即使它们都是有效且非循环的。

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

答案 3 :(得分:0)

在玩了一些代码之后,看起来你已经找到了lstat(2)的功能或错误。根据lstat上的手册页,也就是stat和fstat,stat和lstat之间的区别是:

  

stat()stats指向的文件   路径和填充buf。

     

lstat()与stat()相同,除了   如果路径是符号链接,那么   链接本身是统计的,而不是   它引用的文件

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

下面的程序在创建为'ln -s 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;
}