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?
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