目录递归和符号链接

时间:2011-09-11 10:54:35

标签: unix recursion directory symlink

如果通过显式方法递归遍历目录树,当符号链接指向父目录时,您将遇到无限递归问题。

一个明显的解决方案是只检查符号链接,而不是完全遵循它们。但对于那些不希望出于其他目的行为的用户来说,这可能是一个令人不快的意外,例如一个完全正常的目录被忽略。

另一种解决方案可能是保留到目前为止访问过的所有目录的哈希表,并使用它来检查循环。但这需要有一些规范的表示形式,以某种方式来获取您当前正在查看的目录的身份(无论您到达目的地的路径如何)。

Unix用户通常会认为第二种解决方案不那么令人惊讶吗?

如果是这样,有没有办法获得这样一个目录的规范表示/身份,可以在Unix系统中移植? (我希望它适用于Linux,BSD,Mac OS,Solaris等。我希望必须为Windows编写单独的代码。)

6 个答案:

答案 0 :(得分:4)

此字段中最常被忽略的API将是

nftw

Nftw可以选择避免遍历符号链接。它具有比这更先进的功能。以下是手册页本身的简单示例:

#define _XOPEN_SOURCE 500
#include <ftw.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>

static int
display_info(const char *fpath, const struct stat *sb,
             int tflag, struct FTW *ftwbuf)
{
    printf("%-3s %2d %7jd   %-40s %d %s\n",
           (tflag == FTW_D) ?   "d"   : (tflag == FTW_DNR) ? "dnr" :
           (tflag == FTW_DP) ?  "dp"  : (tflag == FTW_F) ?   "f" :
           (tflag == FTW_NS) ?  "ns"  : (tflag == FTW_SL) ?  "sl" :
           (tflag == FTW_SLN) ? "sln" : "???",
           ftwbuf->level, (intmax_t) sb->st_size,
           fpath, ftwbuf->base, fpath + ftwbuf->base);
    return 0;           /* To tell nftw() to continue */
}

int
main(int argc, char *argv[])
{
    int flags = 0;

    if (argc > 2 && strchr(argv[2], 'd') != NULL)
        flags |= FTW_DEPTH;
    if (argc > 2 && strchr(argv[2], 'p') != NULL)
        flags |= FTW_PHYS;

    if (nftw((argc < 2) ? "." : argv[1], display_info, 20, flags)
            == -1)
    {
        perror("nftw");
        exit(EXIT_FAILURE);
    }
    exit(EXIT_SUCCESS);
}

另见

答案 1 :(得分:3)

目录的绝对路径就是这样的表示。您可以使用POSIX标准中定义的realpath函数来获取它,因此它可以在任何符合POSIX的系统上运行。请参阅man 3 realpath

答案 2 :(得分:2)

不仅是符号链接,还有硬链接。不是很常见,但不是禁止的。 (只有root可以硬链接目录) 唯一的规范是{device_number,inode_number}。但网络文件系统可能行为不端。

答案 3 :(得分:2)

许多应用程序必须解决相同文件的问题,例如文件双截面检查(缩进内容,不同名称)和作用于整个目录层次结构的实用程序,如tar

一个好的实现不希望通过符号链接到父目录或文件来为硬链接文件和符号链接文件提供误报。

解决此问题的最便携方法是通过查看POSIX stat / fstat函数以及struct statst_dev成员填写的st_ino来识别文件。 使用此策略的C中文件欺骗检查器的真实世界实现是samefile(其中一个不同的实现是1998 IOCCC的获胜条目: - )

答案 4 :(得分:2)

还有 Linux/BSD 函数 fts_open()

它为您提供了一个易于使用的迭代器,用于遍历所有子目录内容,同时还检测此类符号链接递归。

事实上,nftw 的手册页(在 macOS 上)说它是一个旧函数,现在被我在这里提到的 fts API 取代:

<块引用>

提供这些函数是为了与旧代码兼容。新代码应使用 fts(3) 函数。

答案 5 :(得分:1)

由于你没有指定你正在使用的语言(如果有的话),让我们从shell开始:如果你在使用GNU readlink的系统上,只需使用readlink -f <path>规范化它。

如果您使用的是Mac(非GNU readlink的行为不同),请参阅How can I get the behavior of GNU's readlink -f on a Mac?了解完成相同任务的方法。

另一个选项是使用inode ID来跟踪唯一文件(通过stat或类似的),但这需要首先跟踪所有符号链接(因为符号链接本身确实有自己唯一的inode id)并且,遵循所有符号链接的最简单方法是readlink


或者,许多编程语言都绑定到POSIX realpath函数,它基本上执行与readlink -f相同的功能(但作为库调用)。例如,Python有os.path.realpath(),C将它作为stdlib.h中的函数,等等。

如果您已经使用具有此类功能的语言,强烈建议使用它,因为您经常可以免费获得跨平台兼容性(假设您的语言是跨平台的)。