57

Say I just create directory newDirectory and then I do ls -ld command. I see that the number of hard links is 2. What exactly makes the hard link 2 from the start? Also is the number of subdirectories in the current directory equal to the number of hard links - 2?

1

3 Answers 3

65

Historically, the first Unix filesystem created two entries in every directory: . pointing to the directory itself, and .. pointing to its parent. This provided an easy way to traverse the filesystem, both for applications and for the OS itself.

Thus each directory has a link count of 2+n where n is the number of subdirectories. The links are the entry for that directory in its parent, the directory's own . entry, and the .. entry in each subdirectory. For example, suppose this is the content of the subtree rooted at /parent, all directories:

/parent
/parent/dir
/parent/dir/sub1
/parent/dir/sub2
/parent/dir/sub3

Then dir has a link count of 5: the dir entry in /parent, the . entry in /parent/dir, and the three .. entries in each of /parent/dir/sub1, /parent/dir/sub2 and /parent/dir/sub3. Since /parent/dir/sub1 has no subdirectory, its link count is 2 (the sub1 entry in /parent/dir and the . entry in /parent/dir/sub1).

To minimize the amount of special-casing for the root directory, which doesn't have a “proper” parent, the root directory contains a .. entry pointing to itself. This way it, too, has a link count of 2 plus the number of subdirectories, the 2 being /. and /...

Later filesystems have tended to keep track of parent directories in memory and usually don't need . and .. to exist as actual entries; typical modern unix systems treat . and .. as special values as part of the filesystem-type-independent filesystem code. Some filesystems still include . and .. entries, or pretend to even though nothing appears on the disk.

Note that even when the filesystem itself contains a .. entry, the kernel still has to handle one special case. In the root directory of a mounted filesystem, the entry called .. points to the directory itself: if the root directory is inode 2, then both the . and .. entries in the root directory point to inode 2. But accessing .. from that directory must in fact access the parent directory of the mount point, unless the mount point is /. That is, assuming /media/foo is a mount point, /media/foo/.. must designate /media, not /media/foo, even though the .. entry in the root of the filesystem mounted at /media/foo points to inode 2.

Most filesystems still report a link count of 2+n for directories regardless of whether . and .. entries exist, but there are exceptions, for example btrfs doesn't do this and changing this has been marked as a rejected idea in the btrfs wiki.

8
  • 8
    .. pointing to the parent doesn't affect the link count of the current directory. The count of 2 comes from . and the directory's (original) name listing itself. The way you put it is a little ambiguous, and makes it sound like . and .. are the two. .. should be used only to explain how the math works out to 2+n :)
    – th3an0maly
    Commented Jun 21, 2016 at 16:52
  • 1
    @th3an0maly Pointing to the parent affects the link count of the parent. I really don't see how “the .. entry in each subdirectory” is ambiguous, and I don't understand what you mean by “the directory's name listing itself”. Commented Jun 21, 2016 at 17:42
  • 1
    @th3an0maly I still have no idea what you're hinting at. Could you express it clearly, instead of hinting? Commented Jun 21, 2016 at 18:42
  • 1
    @goldilocks's answer is clear. What I meant to say is that your answer could be more like his. But then I hadn't read his answer when I was reading your answer. The first line is exactly what my original comment said: "There's one for the directory itself, and one for . inside it.". If it's still unclear to you, I'm very sorry I'm unable to clarify any further. All I could do better is copy+paste his answer here in comments.
    – th3an0maly
    Commented Jun 21, 2016 at 18:54
  • 1
    @stolsvik / doesn't have a “proper” parent, but its own .. points to itself, so its link count is 2 + number of subdirectories like any other directory. And sorry, but I still don't see the ambiguity. But I'll add an example. Commented Sep 8, 2017 at 17:08
15

There's one for the directory itself, and one for . inside it.

Also is the number of subdirectories in the current directory equal to the number of hard links - 2?

That makes sense, since each subdirectory creates a .. hardlink, and beyond that you can't create hardlinks to directories.1 However, I would't trust this for anything serious, esp. since it is easy to count the subdirectories and get the real number.

If you are just looking at ls output for an idea of how many subs there are, then it does give you a decent idea.

1 Or at least, you can't with ln. I have not tried to programmatically, and man 2 link is ambiguous -- there's no obvious error for linking to a directory, although there are a couple that might apply (EMLINK, EPERM). So unless there's some standard somewhere that says the only possible hard links to a directory are . and .., again, I would only treat that hard link count as a casual clue.

2
  • 2
    Whether links to directories are allowed, and whether you can count subdirs from the link count, are both dependent on which filesystem you're using - some allow, some don't.
    – alanc
    Commented Nov 17, 2013 at 19:07
  • 1
    Note that macOS's Time Machine actually hardlinks directories to previous backups; that way they can pretend that each incremental backup is a full copy, and they can delete any of the incrementals without impacting the others. It is also very brittle, I was playing with it using regular syscalls and I thoroughly hosed my filesystem.
    – w00t
    Commented Apr 10, 2017 at 14:36
2

This depends on the filesystem. BTRFS breaks with this convention.

# dd if=/dev/zero of=btrfs.img bs=114294784 count=1
1+0 records in
1+0 records out
114294784 bytes (114 MB, 109 MiB) copied, 0.172979 s, 661 MB/s
# mkfs.btrfs btrfs.img 
btrfs-progs v4.20.1 
See http://btrfs.wiki.kernel.org for more information.

Label:              (null)
UUID:               ad5f6c58-ec7a-41db-9d19-ec98db96d725
Node size:          16384
Sector size:        4096
Filesystem size:    109.00MiB
Block group profiles:
  Data:             single            8.00MiB
  Metadata:         DUP              32.00MiB
  System:           DUP               8.00MiB
SSD detected:       no
Incompat features:  extref, skinny-metadata
Number of devices:  1
Devices:
   ID        SIZE  PATH
    1   109.00MiB  btrfs.img
# mount btrfs.img /mnt
# mkdir -p /mnt/{1,2,3}/{1,2,3}
# find /mnt/ -links 2
# find /mnt/ -links 1
/mnt/
/mnt/1
/mnt/1/1
/mnt/1/2
/mnt/1/3
/mnt/2
/mnt/2/1
/mnt/2/2
/mnt/2/3
/mnt/3
/mnt/3/1
/mnt/3/2
/mnt/3/3

The links counter has no meaning for directories on a BTRFS:

# find /mnt/ -printf '%n %p\n'
1 /mnt/
1 /mnt/1
1 /mnt/1/1
1 /mnt/1/2
1 /mnt/1/3
1 /mnt/2
1 /mnt/2/1
1 /mnt/2/2
1 /mnt/2/3
1 /mnt/3
1 /mnt/3/1
1 /mnt/3/2
1 /mnt/3/3

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .