I have recently written some extensive articles about various aspects of Linux filesystems.
- The Linux EXT4 filesystem
- An introduction to Linux filesystems
- A Linux user’s guide to Logical Volume Management
There is an interesting feature of Linux filesystems that I have briefly mentioned that can make some tasks easier by providing access to files from multiple locations in the filesystem directory tree. There are two types of links; hard and soft. The difference between the two types of links is significant but both types are used to solve similar problems. Both types of links provide multiple directory entries, i.e., references, to a single file but they do it quite differently. Links are powerful and add flexibility to Linux filesystems because Everything is a file.
I have found in the past, for instance, that some application programs required a particular version of a library. When an upgrade to that library replaced the old version the program would crash with an error specifying the name of the old library that was missing. Usually the only change in the library name was the version number. Acting on a hunch, I simply added a link to the new library but named the link after the old library name. I tried the program again and it worked perfectly. And, OK, the program was a game, and everyone knows the lengths that gamers will go to to keep their games running.
In fact almost all applications are linked to libraries using a generic name with only a major version number in the link name while the link points to the actual library file that also has a minor version number. In other instances required files have been moved from one directory to another in order to be in compliance with the Linux File Specification and links have been provided in the old directories to provide backward compatibility for those programs that have not yet caught up with the new locations. If you do a long listing of the /lib64 directory you can find many examples of both.
lrwxrwxrwx. 1 root root 36 Dec 8 2016 cracklib_dict.hwm -> ../../usr/share/cracklib/pw_dict.hwm lrwxrwxrwx. 1 root root 36 Dec 8 2016 cracklib_dict.pwd -> ../../usr/share/cracklib/pw_dict.pwd lrwxrwxrwx. 1 root root 36 Dec 8 2016 cracklib_dict.pwi -> ../../usr/share/cracklib/pw_dict.pwi lrwxrwxrwx. 1 root root 27 Jun 9 2016 libaccountsservice.so.0 -> libaccountsservice.so.0.0.0 -rwxr-xr-x. 1 root root 288456 Jun 9 2016 libaccountsservice.so.0.0.0 lrwxrwxrwx. 1 root root 15 May 17 11:47 libacl.so.1 -> libacl.so.1.1.0 -rwxr-xr-x. 1 root root 36472 May 17 11:47 libacl.so.1.1.0 lrwxrwxrwx. 1 root root 15 Feb 4 2016 libaio.so.1 -> libaio.so.1.0.1 -rwxr-xr-x. 1 root root 6224 Feb 4 2016 libaio.so.1.0.0 -rwxr-xr-x. 1 root root 6224 Feb 4 2016 libaio.so.1.0.1 lrwxrwxrwx. 1 root root 30 Jan 16 16:39 libakonadi-calendar.so.4 -> libakonadi-calendar.so.4.14.26 -rwxr-xr-x. 1 root root 816160 Jan 16 16:39 libakonadi-calendar.so.4.14.26 lrwxrwxrwx. 1 root root 29 Jan 16 16:39 libakonadi-contact.so.4 -> libakonadi-contact.so.4.14.26
Listing 1: A few of the links in the /lib64 directory.
The long listing of the /lib64 directory in Listing 1 shows that the first character in the filemode is an “l” which means that this is a soft or symbolic link.
If you read my article “The Linux EXT4 filesystem”, I discuss the fact that each file has one iNode that contains information about that file including the location of the data belonging to that file. Figure 2, in that article shows a single directory entry that points to the iNode. Every file must have at least one directory entry that points to the iNode that describes the file. The directory entry is a hard link and thus every file has at least one hard link.
In Figure 1, below, multiple directory entries point to single Inode. These are all hard links. I have abbreviated the locations of three of the directory entries using the tilde (~) convention for home directory, so that ~ is equivalent to /home/user in this example. Note that the fourth directory entry is in a completely different directory, /home/shared, which might be a location for sharing files between users of the computer.
Hard links are limited to files contained within a single filesystem. The term filesystem is used here in the sense of a partition or logical volume that is mounted on a specified mount point, such as in this case, /home. This is because iNode numbers are unique only within each filesystem and a different filesystem, /var or /opt for example, will have iNodes with the same number as the iNode for our file.
Because all of the hard links point to the single iNode which contains the metadata about the file, all of these attributes are part of the file, such as ownerships, permissions, and the total number of hard links to the iNode, and cannot be different for each hard link. It is one file with one set of attributes. The only attribute that can be different is the file name, which is not contained in the iNode. Hard links to a single file/iNode that are located in the same directory must have different names due to the fact that there can be no duplicate file names within a single directory.
The number of hard links for a file is displayed with the ls -l command. If you want to display the actual iNode numbers, the command ls -li does that.
Symbolic (soft) Links
The difference between a hard link and a soft link is that, while hard links point directly to the iNode belonging to the file, soft links point to a directory entry, i.e., one of the hard links. Because soft links point to a hard link for the file and not the iNode, they are not dependent upon the iNode number and can work across filesystems, spanning partitions and logical volumes.
The downside to this is that if the hard link to which the symlink points is deleted or renamed, the symlink is broken. The symbolic link is still there but it points to a hard link that no longer exists. Fortunately the ls command highlights broken links with flashing white text on a red background in a long listing.
Lab project – Experimenting with links
I think the easiest way to understand the use of and differences between hard and soft links to with a lab project that you can do for yourself. This project should be done in an empty directory as a non-root user. I created the ~/temp directory for use with this project so you should, too. It makes a safe place to perform the project and provides a new, empty directory to work in so that only files associated with this project will be located there.
First, create the temporary directory in which you will perform the tasks needed for this project. Ensure that the present working directory (pwd) is your home directory, then enter the following command.
Change into ~/temp so it is the pwd.
In order to get started, we need to create a file that we can link to. The following command does that and provides some content as well.
du -h > main.file.txt
Use the ls -l long list verify that the file was created correctly. It should look similar to my results. Note that the file size is only 7 bytes but the size of yours may vary by a byte or two.
[dboth@david temp]$ ls -l total 4 -rw-rw-r-- 1 dboth dboth 7 Jun 13 07:34 main.file.txt
Notice the number “1” following the file mode in the listing. That number represents the number of hard links that exist for the file. For now, it should be 1 because we have not created any additional links to our test file.
Experimenting with hard links
Hard links create a new directory entry pointing to the same inode, so when hard links are added to a file you will see the number of links increase. Ensure that the pwd is still ~/temp. Create a hard link to the file main.file.txt and then do another long list of the directory.
[dboth@david temp]$ ln main.file.txt link1.file.txt [dboth@david temp]$ ls -l total 8 -rw-rw-r-- 2 dboth dboth 7 Jun 13 07:34 link1.file.txt -rw-rw-r-- 2 dboth dboth 7 Jun 13 07:34 main.file.txt
Notice that both files have 2 links and are exactly the same size. The date stamp is also the same. This is really one file with one Inode and two links, i.e., directory entries to it. Create a second hard link to this file and list the directory contents. The link can be created to either of the existing ones, link1.file.txt or main.file.txt.
[dboth@david temp]$ ln link1.file.txt link2.file.txt ; ls -l total 16 -rw-rw-r-- 3 dboth dboth 7 Jun 13 07:34 link1.file.txt -rw-rw-r-- 3 dboth dboth 7 Jun 13 07:34 link2.file.txt -rw-rw-r-- 3 dboth dboth 7 Jun 13 07:34 main.file.txt
Notice that each new hard link in this directory must have a different name because two files – really directory entries – cannot have the same name within the same directory. Try to create another link using the same name as one of the existing ones as the target name for the new link.
[dboth@david temp]$ ln main.file.txt link2.file.txt ln: failed to create hard link 'link2.file.txt': File exists
Clearly that does not work because link2.file.txt already exists. So far we have only created hard links that are located in the same directory. So create a link in your home directory, the parent of the temp directory in which we have been working so far.
[dboth@david temp]$ ln main.file.txt ../main.file.txt ; ls -l ../main* -rw-rw-r-- 4 dboth dboth 7 Jun 13 07:34 main.file.txt
The ls command in the above listing shows that the main.file.txt file does exist in the home directory with the same name as the file in the temp directory. Of course, these are not different files, they are the same file with multiple links – directory entries – to the same iNode. To help illustrate the next point, add a file that is not a link.
[dboth@david temp]$ touch unlinked.file ; ls -l total 12 -rw-rw-r-- 4 dboth dboth 7 Jun 13 07:34 link1.file.txt -rw-rw-r-- 4 dboth dboth 7 Jun 13 07:34 link2.file.txt -rw-rw-r-- 4 dboth dboth 7 Jun 13 07:34 main.file.txt -rw-rw-r-- 1 dboth dboth 0 Jun 14 08:18 unlinked.file
Look at the iNode number of the hard links and that of the new file using the -i option to the ls command.
[dboth@david temp]$ ls -li total 12 657024 -rw-rw-r-- 4 dboth dboth 7 Jun 13 07:34 link1.file.txt 657024 -rw-rw-r-- 4 dboth dboth 7 Jun 13 07:34 link2.file.txt 657024 -rw-rw-r-- 4 dboth dboth 7 Jun 13 07:34 main.file.txt 657863 -rw-rw-r-- 1 dboth dboth 0 Jun 14 08:18 unlinked.file
Notice the number 657024 to the left of the file mode in the example above. That is the iNode number and all three file links point to the same iNode. You can use the -i option to view the iNode number for the link we created in the home directory as well and that will also show the same value. The iNode number of the file that has only the one link is different from the others. Note that the iNode numbers will be different on your system.
Let’s change the size of one of the hard linked files and list the directory contents.
[dboth@david temp]$ df -h > link2.file.txt ; ls -li total 12 657024 -rw-rw-r-- 4 dboth dboth 1157 Jun 14 14:14 link1.file.txt 657024 -rw-rw-r-- 4 dboth dboth 1157 Jun 14 14:14 link2.file.txt 657024 -rw-rw-r-- 4 dboth dboth 1157 Jun 14 14:14 main.file.txt 657863 -rw-rw-r-- 1 dboth dboth 0 Jun 14 08:18 unlinked.file
The file size is of all of the hard linked files is now larger than before. That is because there is really only one file that is linked to by multiple directory entries.
I know this next experiement will work on my computer because my /tmp directory is on a separate logical volume. If you have a separate logical volume or a filesystem on a different partition if your are not using Logical Volumes, determine whether or notyou have access to that LV or partition. If you don’t, you can try to insert a USB memory stick and mount it. If one of those options works for you, you can do this experiment.
Try to create a link to one of the files in your ~/temp directory in /tmp or whatever directory your different filesystem is locate in.
[dboth@david temp]$ ln link2.file.txt /tmp/link3.file.txt ln: failed to create hard link '/tmp/link3.file.txt' => 'link2.file.txt': Invalid cross-device link
Why does this error occur? The reason is that each separate mountable filesystem has its own set of iNode numbers. Simply referring to a file by an iNode number across the entire Linux directory structure can result in confusion because the same iNode number can exist in each mounted filesystem.
There may be a time when you will want to locate all of the hard links that belong to a single iNode. You can find the iNode number using the ls -li command. Then you can use the find command to locate all links with that iNode number.
[dboth@david temp]$ find . -inum 657024 ./main.file.txt ./link1.file.txt ./link2.file.txt
Note that the find command did not find all four of the hard links to this iNode because we started at the current directory of ~/temp. The find command only finds files in the PWD and its subdirectories. To find all of the links we can use the following command which specifies your home directory as the starting place for the search.
[dboth@david temp]$ find ~ -samefile main.file.txt /home/dboth/temp/main.file.txt /home/dboth/temp/link1.file.txt /home/dboth/temp/link2.file.txt /home/dboth/main.file.txt
Note that you may see some error messages if you do not have permissions as a non-root user. This command also uses the -samefile option instead of specifying the iNode number. This works the same as using the iNode number and can be easier if you know the name one of the hard links.
Experimenting with soft links
As you have just seen, creating hard links is not possible across filesystem boundaries, that is from a filesystem on one logical volume or partition to a filesystem on another. Soft links, which are also known as symbolic links, or symlinks, are a means to answer that problem with hard links. Although they can accomplish the same end, they are very different and knowing these differences is important.
Let’s start by creating a symlink in our ~/temp directory to start our exploration.
[dboth@david temp]$ ln -s link2.file.txt link3.file.txt ; ls -li total 12 657024 -rw-rw-r-- 4 dboth dboth 1157 Jun 14 14:14 link1.file.txt 657024 -rw-rw-r-- 4 dboth dboth 1157 Jun 14 14:14 link2.file.txt 658270 lrwxrwxrwx 1 dboth dboth 14 Jun 14 15:21 link3.file.txt -> link2.file.txt 657024 -rw-rw-r-- 4 dboth dboth 1157 Jun 14 14:14 main.file.txt 657863 -rw-rw-r-- 1 dboth dboth 0 Jun 14 08:18 unlinked.file
The hard links, those that have the iNode number 657024, are unchanged and the number of hard links shown for each has not changed. The newly created symlink has a different iNode, number 658270. The soft link named link3.file.txt points to link2.file.txt. Use the cat command to display the contents of link3.file.txt. The file mode information for the symlink starts with an “l” which indicates that this file is actually a symbolic link.
The size of the symlink link3.file.txt is only 14 bytes in the example above. That is the size of the text “link3.file.txt -> link2.file.txt” which is the actual content of the directory entry. The directory entry link3.file.txt does not point to an iNode, it points to another directory entry which makes it useful for creating links that span file system boundaries. So let’s create that link we tried before from the /tmp directory.
[dboth@david temp]$ ln -s /home/dboth/temp/link2.file.txt /tmp/link3.file.txt ; ls -l /tmp/link* lrwxrwxrwx 1 dboth dboth 31 Jun 14 21:53 /tmp/link3.file.txt -> /home/dboth/temp/link2.file.txt
There are some considerations that you should take into account when you delete links or the files to which they point. First, let’s delete the link main.file.txt. Remember that every directory entry that points to an iNode is simply a hard link.
[dboth@david temp]$ rm main.file.txt ; ls -li total 8 657024 -rw-rw-r-- 3 dboth dboth 1157 Jun 14 14:14 link1.file.txt 657024 -rw-rw-r-- 3 dboth dboth 1157 Jun 14 14:14 link2.file.txt 658270 lrwxrwxrwx 1 dboth dboth 14 Jun 14 15:21 link3.file.txt -> link2.file.txt 657863 -rw-rw-r-- 1 dboth dboth 0 Jun 14 08:18 unlinked.file
The link main.file.txt was the first link created when the file was created. Deleting it now still leaves the original file and its data on the hard drive along with all of the remaining hard links. In order to delete the file and its data it would be necessary to delete all of the remaining hard links.
Now delete the link2.file.txt hard link.
[dboth@david temp]$ rm link2.file.txt ; ls -li total 8 657024 -rw-rw-r-- 3 dboth dboth 1157 Jun 14 14:14 link1.file.txt 658270 lrwxrwxrwx 1 dboth dboth 14 Jun 14 15:21 link3.file.txt -> link2.file.txt 657024 -rw-rw-r-- 3 dboth dboth 1157 Jun 14 14:14 main.file.txt 657863 -rw-rw-r-- 1 dboth dboth 0 Jun 14 08:18 unlinked.file
Notice what happens to the soft link. Deleting the hard link to which the soft link points leaves a broken link. On my system the broken link is highlighted in colors and the target hard link is flashing. If the broken link needs to be fixed, you can create another hard link in the same directory with the same name as the old one, so long not all of the hard links have been deleted. You could also recreate the link itself with the link maintaining the same name but pointing to one of the remaining hard links. Of course if the soft link is no longer needed it can be deleted with the rm command.
The unlink command can also be used to delete files and links. It is very simple and has no options as the rm command does. It does, however, more accurately reflect the underlying process of deletion in that it removes the link – the directory entry – to the file being deleted.
It took me a long time working with both types of links before I began to understand their capabilities and idiosyncrasies. It took writing a the lab project that is the predecessor to this one to fully appreciate how links work. The lab project in this article was one that I used in a Linux class I used to teach; I have simplified and shortened it a bit for this article.
I hope this speeds your learning curve.