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

1

6

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?

Decurrent answered 21/4, 2016 at 0:31 Comment(5)
I don't understand why you think that a path/filename combo of 7182 characters (be it relative or absolute) is the content of the file?Crisp
@Crisp symbolic link is a file that has l file-type in its inode, but otherwise its contents are the target of the link.Decurrent
I must be missing something (despite the 20+ years of linux experience) ... you operate in a shell; assuming that foobar actually exists in the current working directory, and so does dir, you're instructing ln to try to expand a path of 7182 characters and create a sym-link to the file foobar called foobar1, which would then reside right next to it. This is failing because 7182 exceeds grep PATH_MAX /usr/include/linux/limits.h (4096 in my case). How this makes for content I still don't understand.Crisp
@Crisp the contents of a symlink is that name of the target. I don't know how to say it more clearly. That is the nature of symlink file. Nobody is directing shell to expand anything, as dangling symlinks show, the system is not actually trying to follow the symlink to the target at the time of creation of the symlink, but only later when certain system calls (such as open but not remove) happen.Decurrent
But the shell is still trying to evaluate a path of > 4096 characters ...Crisp
B
8

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
Baal answered 21/4, 2016 at 4:10 Comment(3)
thank you - I did scan the manpage for the symlink system call for PATH_MAX and there was noone so I went away. It just says "too long" without mentioning PATH_MAX. Thank you again.Decurrent
actually for the record, the limit is SYMLINK_MAXDecurrent
@MarkGaleck I've updated the answer. Based on what I found in the kernel it's completely filesystem dependent.Baal

© 2022 - 2024 — McMap. All rights reserved.