File links are an integral part of the Linux filesystem, and a good understanding of them is essential if we are to manage our Linux systems effectively. It seems that most people sort of know what they are, but few understand them in detail.
Hard and Soft
There are two types of links, “hard” and “soft” (or “symbolic”). A hard link points to an inode, which in turn describes a filesystem object such as a file or a directory. A long directory listing will show how many hard links each entry has:
$ ls -l /etc |head -5 total 1812 drwxr-xr-x 3 root root 4096 Jul 13 10:04 acpi -rw-r--r-- 1 root root 2981 Mar 20 2013 adduser.conf -rw-r--r-- 1 root root 44 Jan 12 2015 adjtime -rw-r--r-- 1 root root 458 Oct 28 2016 aliases
The number after the permissions mask is the number of hard links to that inode. For the regular files in the examples above, that’s 1 – the name on the line is the link to the file.
For the acpi
directory, though, it’s 3, which implies that there are three names pointing to that entry. One of them is the name on the line, and looking inside the acpi
directory tells us what the other two are:
$ ls -la /etc/acpi total 24 drwxr-xr-x 3 root root 4096 Jul 13 10:04 . drwxr-xr-x 195 root root 12288 Aug 3 00:54 .. drwxr-xr-x 2 root root 4096 Jul 13 10:04 events -rwxr-xr-x 1 root root 1191 Oct 23 2014 powerbtn-acpi-support.sh
The first additional name is the .
directory, which points to itself (acpi
), and the second extra name is the ..
directory inside events
, which points to its parent (acpi
). So, the three names that point to the acpi entry are:
/etc/acpi /etc/acpi/. /etc/acip/events/..
We can see from that example that the number of links to most directories will be 2 plus the number of subdirectories within that directory.
Creating Hard Links
We can create additional hard links to regular files with the ln
command. It may be easier to remember the syntax of the command by comparing it to the copy (cp
) command, which has the format:
cp <from> <to>
Similarly, the syntax for the ln
command is:
ln <from> <to>
Here’s a directory with one file:
$ ls -l total 4 -rw-r--r-- 1 kae kae 211 Aug 3 08:34 myfile
We can create a new link to the file with ln
:
$ ln myfile mynewlink $ ls -l total 8 -rw-r--r-- 2 kae kae 211 Aug 3 08:34 myfile -rw-r--r-- 2 kae kae 211 Aug 3 08:34 mynewlink
This isn’t two files: it’s two names that point to the same file, and we can see that each entry has two links. If we display the inode numbers that each name points to, it becomes apparent that there is only one file:
$ ls -i1 37861771 myfile 37861771 mynewlink
Removing a link
The rm
command, strictly speaking, doesn’t delete files: rather, it removes a link to a file. Let’s remove one of the links:
$ rm myfile $ ls -l total 4 -rw-r--r-- 1 kae kae 211 Aug 3 08:34 mynewlink
The link count has decremented to one, but the file itself is unchanged. If we were to rm mynewlink
, the remaining link would be removed, the link count would become zero, and the filesystem would reclaim the space used by the file.
The file itself – the data – would still exist, but be unreferenced by any directory entry. The space that the data occupies would be available for use by another file and, in the fullness of time, would be overwritten. That’s why simply using rm
on a file with sensitive data isn’t secure.
Hard Link Restrictions
The filesystem is very particular about hard links to directory names because it would be easy to set up directory loops that are hard to parse. For that reason, it’s difficult to set up additional hard links to a directory:
$ mkdir mydir $ ln mydir dirlink ln: mydir: hard link not allowed for directory
Hard links to files are only possible within the same disk partition because the hard link is a pointer to the inode, and inode numbers are only unique within a partition:
$ ln /etc/hosts mylink ln: failed to create hard link 'mylink' => '/etc/hosts': Invalid cross-device link
Symbolic Links
Symbolic links, soft links or symlinks are all names for the same thing. A symlink is a pointer to another filename entry, as opposed to a pointer to the inode (file) itself. We can create a symlink with ln -s
:
$ ls -l total 4 -rw-r--r-- 1 kae kae 211 Aug 3 08:34 mydata drwxr-xr-x 2 kae kae 40 Aug 3 08:44 mydir $ ln -s mydata mysymlink $ ls -l total 4 -rw-r--r-- 1 kae kae 211 Aug 3 08:34 mydata drwxr-xr-x 2 kae kae 40 Aug 3 08:44 mydir lrwxrwxrwx 1 kae kae 6 Aug 3 08:52 mysymlink -> mydata
Here we can clearly see that mysymlink
points to a file name, and the leading l
in the permissions shows that this is a (symbolic) link. In truth, all directory entries are links, and the symbolic links are distinguished from hard links by that leading l
.
We can see that the symlink doesn’t directly reference the file by looking at the inode numbers:
$ ls -li total 4 37861771 -rw-r--r-- 1 kae kae 211 Aug 3 08:34 mydata 37875969 drwxr-xr-x 2 kae kae 40 Aug 3 08:44 mydir 37888876 lrwxrwxrwx 1 kae kae 6 Aug 3 08:52 mysymlink -> mydata
Here, the symlink inode number (37888876) differs from the filename it points to (37861771), showing that the symlink is a file in its own right.
Unlike hard links, a symlink can point to a directory or a file (or directory) on another partition:
$ ln -s mydir link-to-mydir $ ls -l total 4 lrwxrwxrwx 1 kae kae 5 Aug 3 08:56 link-to-mydir -> mydir -rw-r--r-- 1 kae kae 211 Aug 3 08:34 mydata drwxr-xr-x 2 kae kae 40 Aug 3 08:44 mydir lrwxrwxrwx 1 kae kae 6 Aug 3 08:52 mysymlink -> mydata
Symlinks In Real Life
Most applications will follow symlinks without complaint, so if your application expects its configuration file to be called /usr/lib/myapp/myapp.conf
but you want to keep your configuration file under /etc/myapp
, we can do this:
$ mv /usr/lib/myapp/myapp.conf /etc/myapp/myapp.conf $ ln -s /etc/myapp/myapp.conf /usr/lib/myapp/myapp.conf
Your application will try to open /usr/lib/myapp/myapp.conf
, follow the symlink to /etc/myapp/myapp.conf
, and open it seamlessly.
There’s a shortcut we can use when creating a symlink that has the same name as the real file (but in a different directory, of course). In the above example, we could do this:
$ cd /usr/lib/myapp $ mv myapp.conf /etc/myapp $ ln -s /etc/myapp/myapp.conf
In the ln -s
command above, we haven’t specified the name or location of the symlink, so by default it is created in the current directory with the same name as the real file:
$ ln -s /etc/hosts $ ls -l total 0 lrwxrwxrwx 1 kae kae 10 Aug 3 09:05 hosts -> /etc/hosts
Could this Linux Tip Be Improved?
Let us know in the comments below.