Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 489
Mark Galeck Avatar asked Apr 21 '16 00:04

Mark Galeck


1 Answers

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
like image 173
Harry Avatar answered Nov 15 '22 11:11

Harry