How does `ls` find hard links?
Setup
The following sequence of commands is setup for my question.
root@cd330f76096d:/# cd
root@cd330f76096d:~# ls
root@cd330f76096d:~# mkdir -p my_dir/my_subdir
root@cd330f76096d:~# ls -hAil
total 12K
6175969 -rw-r--r-- 1 root root 3.1K Oct 15 2021 .bashrc
6175970 -rw-r--r-- 1 root root 161 Jul 9 2019 .profile
7382820 drwxr-xr-x 3 root root 4.0K Sep 6 19:34 my_dir
Context
Notice that my_dir
has three hard links, as per the output. Presumably they are:
./my_dir
my_dir/.
my_dir/my_subdir/..
However. . .
root@cd330f76096d:~# find . -xdev -inum 7382820
./my_dir
And that’s it. Only one line.
Questions
What am I missing and/or how does ls -l
work?
I’m half expecting that the reason why I can’t locate any more files with find
is that they refer to .
and ..
in which case I ask how exactly does ls -l
work with references to the source code.
Pre setup
The example above was created in a docker container, which for convenience I’m sharing below:
$ docker pull ubuntu:jammy
jammy: Pulling from library/ubuntu
Digest: sha256:aabed3296a3d45cede1dc866a24476c4d7e093aa806263c27ddaadbdce3c1054
Status: Downloaded newer image for ubuntu:jammy
docker.io/library/ubuntu:jammy
$ docker run -it ubuntu:jammy bash
A pathname that find
encounters (i.e., apart from the search paths given on the command line) cannot contain a .
or ..
component, so your command will never show these.
Why? Because the POSIX standard says so (my emphasis):
Each path operand shall be evaluated unaltered as it was provided, including all trailing
<slash>
characters; all pathnames for other files encountered in the hierarchy shall consist of the concatenation of the current path operand, a<slash>
if the current path operand did not end in one, and the filename relative to the path operand. The relative portion shall contain no dot or dot-dot components, no trailing<slash>
characters, and only single<slash>
characters between pathname components.
("The current path operand" mentioned above is one of the search paths on the command line.)
The ls
command can work out the link count of the directory because it makes a stat()
call, which returns a stat
structure, which contains the number of hard links. It strictly speaking does not know where the other hard links are located though.