在 Linux 中,符号链接的值可以长于 PATH_MAX 吗?

Mar*_*eck 5 linux filesystems

每个幼儿园的孩子都知道,Linux 中的文件路径不能超过PATH_MAX字符。

但是在我的系统上试验,命令

ln -s $(for i in {0..1024}; do printf dir/../; done)foobar foobar1
Run Code Online (Sandbox Code Playgroud)

失败并显示错误消息File name too long

我不太明白为什么。这里没有长文件名,只有文件的预期内容foobar1很长。甚至还没有人试图遍历符号链接的内容以到达目标。当然,我可以拥有一个内容远大于PATH_MAX.

另一方面,像这样的命令

for i in {0..4096}; do ln -s $i $(expr $i + 1); done
Run Code Online (Sandbox Code Playgroud)

成功。只有当我试图遍历链时,系统才会抱怨。

但我对遍历任何东西都不感兴趣。我正在编写必须读取符号链接值(无需遍历)的软件,我想知道是否需要考虑很长的值。

在 Linux 中哪里记录了这是不允许的?或者它是否依赖于文件系统实现并且可以更改?

Har*_*rry 6

对符号链接的调用失败

ENAMETOOLONG (File name too long)
Run Code Online (Sandbox Code Playgroud)

这是来自内核。它也依赖于文件系统,因此为什么在任何地方都找不到定义的 SYMLINK_MAX 。例如...

XFS

if (pathlen < 0 || pathlen > MAXPATHLEN) {
  xfs_alert(mp, "%s: inode (%llu) bad symlink length (%lld)",
  __func__, (unsigned long long) ip->i_ino,
  .......
}
Run Code Online (Sandbox Code Playgroud)

和 MAXPATHLEN == 1024

重新定义

item_len = ROUND_UP(strlen(symname));
if (item_len > MAX_DIRECT_ITEM_LEN(parent_dir->i_sb->s_blocksize)) {
  retval = -ENAMETOOLONG;
  .......
}
Run Code Online (Sandbox Code Playgroud)

分机2

struct super_block * sb = dir->i_sb;
int err = -ENAMETOOLONG;
unsigned l = strlen(symname)+1;
.....
if (l > sb->s_blocksize)
   goto out;
....
return err;
Run Code Online (Sandbox Code Playgroud)

符号链接应该在文件名所在的任何地方都可用,因此它小于 PATH_MAX 是合乎逻辑的,它里面的内容并不重要。来自 Linux 上的符号链接手册页。

ENAMETOOLONG
    target or linkpath was too long.
Run Code Online (Sandbox Code Playgroud)

这是模糊的,因为文件系统定义了它。您可以达到的另一个限制是_POSIX_SYMLINK_MAX

#define _POSIX_SYMLINK_MAX  255 
Run Code Online (Sandbox Code Playgroud)

要测试它,请在目录中创建以下两个链接。这个会成功

ln -s foo Fh5LNDZYm2vUlf3jypJtAaX1ElqHZAF4ivsuq8sHyKVLDrYi4zR3T2QcXwS5TPRTys9aUxuh3qtnlNnFQGInmLiM7GK1xpN78ZbcD4JWizfPa7VWwhR4XWpvaJLHCIONUTC6A8fjNVfhv434vWckuKDzTacno0LE13mBVHuj5RDgJIkmW1zUcMMh5E38VisPxSN7BGxBVXHtn0cUPmZLmYSzGrOJqEJzimvwh2uDi8uXEOwBLbsfYlxBOz1kw8P
Run Code Online (Sandbox Code Playgroud)

这个会失败

ln -s foo Fh5LNDZYm2vUlf3jypJtAaX1ElqHZAF4ivsuq8sHyKVLDrYi4zR3T2QcXwS5TPRTys9aUxuh3qtnlNnFQGInmLiM7GK1xpN78ZbcD4JWizfPa7VWwhR4XWpvaJLHCIONUTC6A8fjNVfhv434vWckuKDzTacno0LE13mBVHuj5RDgJIkmW1zUcMMh5E38VisPxSN7BGxBVXHtn0cUPmZLmYSzGrOJqEJzimvwh2uDi8uXEOwBLbsfYlxBOz1kw8Pk
Run Code Online (Sandbox Code Playgroud)

一个是 255 个字符长,另一个是 256 个字符。在您的问题中,此命令将起作用,因为每个单独的链接都有自己的 inode 并且名称很短。

for i in {0..4096}; do ln -s $i $(expr $i + 1); done
Run Code Online (Sandbox Code Playgroud)