Search code examples
linuxfilesystemssymlink

in Linux, can the value of a symlink be longer than PATH_MAX?


As every child in kindergarten knows, a file path in Linux cannot be longer than PATH_MAX characters.

But experimenting on my system, the command

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

fails with the error message File name too long.

I don't quite understand why. There is no long file name here, it is only the intended contents of the file foobar1 that are very long. Nobody is even yet trying to traverse the contents of the symbolic link to get to the target. Certainly I can have a file whose contents is much larger than PATH_MAX.

On the other hand, a command such as

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

succeeds. Only if I tried to traverse the chain, does the system complain.

But I am not interested in traversing anything. I am writing software that has to read the value of a symbolic link (without traversing) and I want to know if I need to account for very long values.

Where is it documented in Linux that this is not allowed? Or is it file-system implementation dependent and can change?


Solution

  • The call to symlink fails with

    ENAMETOOLONG (File name too long)
    

    This is coming from the kernel. It's also filesystem dependent hence why you can't find SYMLINK_MAX defined anywhere. For instance...

    XFS

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

    and MAXPATHLEN == 1024

    reiserfs

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

    ext2

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

    A symlink should be usable anywhere a filename is so it makes logical sense for it to be less than PATH_MAX, it matters not what's inside it. From the symlink man page on Linux.

    ENAMETOOLONG
        target or linkpath was too long.
    

    This is vague because the filesystem defines it. The other limit you can hit is _POSIX_SYMLINK_MAX.

    #define _POSIX_SYMLINK_MAX  255 
    

    To test it create the following two links in a directory. This one will succeed

    ln -s foo Fh5LNDZYm2vUlf3jypJtAaX1ElqHZAF4ivsuq8sHyKVLDrYi4zR3T2QcXwS5TPRTys9aUxuh3qtnlNnFQGInmLiM7GK1xpN78ZbcD4JWizfPa7VWwhR4XWpvaJLHCIONUTC6A8fjNVfhv434vWckuKDzTacno0LE13mBVHuj5RDgJIkmW1zUcMMh5E38VisPxSN7BGxBVXHtn0cUPmZLmYSzGrOJqEJzimvwh2uDi8uXEOwBLbsfYlxBOz1kw8P
    

    This one will fail

    ln -s foo Fh5LNDZYm2vUlf3jypJtAaX1ElqHZAF4ivsuq8sHyKVLDrYi4zR3T2QcXwS5TPRTys9aUxuh3qtnlNnFQGInmLiM7GK1xpN78ZbcD4JWizfPa7VWwhR4XWpvaJLHCIONUTC6A8fjNVfhv434vWckuKDzTacno0LE13mBVHuj5RDgJIkmW1zUcMMh5E38VisPxSN7BGxBVXHtn0cUPmZLmYSzGrOJqEJzimvwh2uDi8uXEOwBLbsfYlxBOz1kw8Pk
    

    One is 255 characters long and the other one is 256. In your question this command will work because each individual link has it's own inode and the name is short.

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