5

Symbolic links do take room, of course, but just the room it takes to store the name and target plus a few bytes for other metadata

Do symbolic links actually make a difference in disk usage?

My question is, can we determine how many bytes a symlink is taking up?

$ touch alfa.txt
$ ln -s alfa.txt bravo.txt

Both du and ls report 8, which is "alfa.txt":

$ du -b bravo.txt
8       bravo.txt

$ ls -l bravo.txt
lrwxrwxrwx 1 Steven None 8 Mar  8 18:17 bravo.txt -> alfa.txt

Is some command available that can print the true size of the symlink with the "few bytes for other metadata" included?

8

Sort of, but note that the size of a file is not well-defined at that level of precision.

A symbolic link involves four parts:

  • The name of the link, which is stored in the directory where it is an entry.
  • Other metadata that is present for every directory entry, to locate the rest of the metadata. This is typically the location of an inode. In addition, each directory entry costs a few more bytes, for example to pad file names and to maintain a data structure such as a balanced tree or hash.
  • Other metadata of the symbolic link itself such as timestamps. This metadata is also present for other file types (e.g. an empty regular file).
  • The target of the link.

If the filesystem allows symbolic links to have multiple hard links, the first two parts are per directory entry, the last two parts are present only once per symlink.

In ext2/ext3/ext4, the target of a symbolic link is stored in the inode if it's at most 60 bytes long. You can confirm that by asking du: it reports 0 for symlinks whose target is ≤60 bytes and one block for larger targets.

Just like for a regular file, the figure reported by du excludes the storage for the directory entry and the inode. If you want to know exactly how much space the symlink takes, you have to count those as well. Most classical filesystems allocate inodes at filesystem creation time, so the cost is split: the size of the directory entry counts against the number of blocks of data, the inode counts against the inode pool size.

For the size of the directory entry itself, the exact number of bytes taken up by an entry can depend on what other entries are present in the directory. However a directory usually takes up a whole number of blocks, so if you create more and more entries, the size of the directory remains the same, until the entries no longer fit in one block and a second block is allocated, and so on. To see exactly how the directory entries are stored in the block, you'd need a filesystem debugger and a passable understanding of the filesystem format, or a good to excellent understanding of the filesystem format as well as the knowledge of what other entries are present in the directory and possibly the order in which they were created and other entries were removed.

In summary, the “few bytes for other metadata” are:

  • The directory entry, of a variable size. Creating the symbolic link may either make no difference or add one block.
  • The inode.

And the target may occupy anywhere from 0 to one block in addition to that.

  • You beat me to the tail-packing of ext2/3/4 of the symlinks (+1), but am confident that that also happens on resiserfs and btrfs (and probably a couple of others). And, I guess, there may be something else about the ext2 dividing the disk in several groups of inode+data blocks (e.g. so if a new block is created there may be more usage). In general, though, you would definitely need an FS debugger to be 100% sure of the size. – grochmal Mar 9 '17 at 1:03
  • @grochmal, I can confirm, from experiments on my system, that btrfs does use some kind of tail packing for symlinks. The cutoff seems to be 59 characters, with 60 characters requiring the allocation of another block on the disk, and du -B1 reporting 4096 rather than 0. – Gypsy Spellweaver Mar 9 '17 at 2:32
0

The ls command shows the true size of the symlink, not counting the inode it uses. In saying that 8 is "alfa.txt" you were totally correct. That's the "true size" of the symlink you created. Again, the size doesn't include the inode it uses, just as the size of all other files doesn't include that. If you create a symlink to some long path, then the size will reflect the length of that path.

  • That's the size as in the length of the target, not the size as in the disk space that it takes up. – Gilles Mar 9 '17 at 0:56
  • @Gilles recreate the test symlink using an absolute path and the size will change to the length of that path. As created in the question, alfa.txt has a size of zero. According to the "size of the target" theory, the reported size of bravo.txt should also be zero. It is 8 because the path of the symlink is alfa.txt exactly 8 characters. – Gypsy Spellweaver Mar 9 '17 at 1:00
  • it is correct that the size of the file, as reported on the inode, will be exactly the length of the symlink path (not even including a terminating null byte since the inode keeps the length). But OP is really asking about disk usage, which is considerably different from that. The inode itself often takes more disk space and there is the tail-packing of inodes too. I'll argue that >90% of all symlinks on a system take exactly 1 inode of disk space due to the tail-packing. – grochmal Mar 9 '17 at 1:35
  • @grochmal All the information inGilles answer above come in to play when looking for the total "disk cost" of any file, directory, or directory entry (even sockets), and can be highly implementation specific. The size of the inodes on the system, the file system type, even whether or not it is some form of RAID. If that "total cost" is what the OP is looking for, then I know of no "command available" that prints that. That's not the same as saying there isn't one however. I do have my doubts though. – Gypsy Spellweaver Mar 9 '17 at 2:26
  • Fair point I guess (+1). For a good deal of filesystems things a re very implementation specific and pretty hard to make exact measures. On ext2 though (not ext3/4) I'd argue that it is completely plausible to read /dev/<whatever> and debug the filesystem by hand; the original implementation of ext2 only had about 5000 lines of C code. – grochmal Mar 10 '17 at 1:37

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.