1. Introduction
Links are pointers to targets that take the form of other filesystem objects. Thus, they can be used to modify properties of those objects, such as permissions. But how do we change some properties of the link itself?
In this tutorial, we’ll look at ways to reference links instead of their targets. First, we delve into raw link content modification. Next, we briefly refresh our knowledge about the main command for creating and manipulating filesystem links in Linux. After that, we talk about copying and moving links. Later, changing ownership and permissions of symbolic links is discussed. Finally, we turn to timestamp changes with a classic tool.
For brevity, we use -> to denote a link pointing to a target.
We tested the code in this tutorial on Debian 11 (Bullseye) with GNU Bash 5.1.4. It should work in most POSIX-compliant environments.
2. Raw Link Contents and System Calls
Unlike most files, Linux considers the contents of a link immutable. In other words, raw read and write system calls always operate on the target instead of the link itself.
Part of the reason is the fact that a symbolic link (symlink) has to be modified atomically, or it would break. Moreover, symbolic links are at most 4095 bytes, the maximum length of a path PATH_MAX. Thus, supporting system calls for changes may take more resources than a simple replacement.
Because of this, the kernel only has two types of specific system calls to work with links:
- symlink() and symlinkat() to create symbolic links
- link() and linkat() to create hard links
Combined with the unlink() system call, we can simply remove and replace a link to change its contents.
All of these options are combined into a tool.
3. The ln Command
The main command for link manipulation is ln.
In fact, ln provides the –force or -f switch to force-remove and replace links:
$ readlink /symlink
/target1
$ ln --symbolic --force /target2 /symlink
First, we use readlink to confirm /symlink -> /target. After that, we replace the link directly with ln. Moreover, *the ln –force switch uses the aforementioned unlink() system call right before calling symlink() or link(), making the whole operation non-atomic*.
Knowing this, we can correct for it.
4. Using mv and cp With Links
To atomically replace a link, thus safely changing its attributes, we can use the –force or -f switch of mv and cp:
$ ln --symbolic /target1 /symlink1
$ ln --symbolic /target2 /symlink2
$ mv --force --no-target-directory /symlink2 /symlink1
After creating /symlink1 -> /target1 and /symlink2 -> /target2, we simply use mv to replace one link with the other atomically. The –no-target-directory or -T switch of mv ensures we don’t treat the destination as a directory since it may be a link to one.
In addition, cp provides the -P or –no-dereference switch to prevent following symbolic links in the source of the copy. In other words, we copy the links themselves, not their targets.
There are several other cp options for the same purpose:
- -R – recursive copy, which never follows links
- –preserve=links – preserve hard links between copied files
- -d – same as –no-dereference –preserve=links
- -a – same as -dR –preserve=all
Combining these as needed enables the proper handling of links.
As we saw, changing the target of a link requires a replacement. How about changes to metadata, such as permissions and dates?
5. Modifying Links With chmod and chown
Changing the permissions of symbolic links is unlike doing the same for regular files. Moreover, ownership switches are specific for symbolic links.
In fact, both chown and chmod follow symlinks, thus operating on their target by default. However, chown offers the -h switch for applying any changes to the symlink itself.
Let’s see these in action.
5.1. Owner Changes and chown
To see how chown works with links, first, we verify our setup and permissions:
$ ls -l /symlink /file
lrwxrwxrwx 1 baeldung baeldung 5 Feb 10 02:10 /symlink -> /file
-rw-r--r-- 1 baeldung baeldung 8 Feb 10 01:10 /file
We have /symlink -> /file, both owned by baeldung:baeldung. Next, we change the owning user and group of /symlink directly:
$ chown x:x /symlink
Now, we check the permissions of both the symbolic link and its target:
$ ls -l /symlink /file
lrwxrwxrwx 1 baeldung baeldung 5 Feb 10 02:10 /symlink -> /file
-rw-r--r-- 1 x x 8 Feb 10 01:10 /file
Evidently, direct chown modifications simply apply to the target of a symlink.
To change the symbolic link itself, we use –no-dereference:
$ chown x:x --no-dereference /symlink
lrwxrwxrwx 1 x x 5 Feb 10 02:10 /symlink -> /file
-rw-r--r-- 1 x x 8 Feb 10 01:10 /file
While this should work, some systems don’t support ownership changes for symbolic links.
5.2. Permissions Changes and chmod
On the other hand, chmod is unable to work on the symlink instead of its target.
The main reason for this is the same as the one behind the lack of a mechanism to change targets – there are no system calls for the purpose. In addition, since the permissions of symbolic links aren’t used, we only need to change the target permissions, which is the default behavior of chmod.
Finally, chmod ignores symlinks altogether when working recursively over directories.
6. touch
Although tools like chmod don’t support it, the -h or –no-dereference flag is fairly universal. For example, the touch command implements it.
The reason that touch can operate on links is that link and target timestamps can differ and, unlike with permissions, both matter.
Let’s see how this works with our last setup:
$ ls -l /symlink /file
lrwxrwxrwx 1 x x 5 Feb 10 02:10 /symlink -> /file
-rw-r--r-- 1 x x 8 Feb 10 01:10 /file
We can see the modification dates and times of both symlink and target. Now, we can attempt a direct change via touch and check the result:
$ touch -t 201010100656 /symlink
$ ls -l /symlink /file
lrwxrwxrwx 1 x x 5 Feb 10 02:10 /symlink -> /file
-rw-r--r-- 1 x x 8 Oct 10 2010 /file
In this case, the -t flag of touch changes the modification time shown by ls for /file, i.e., the target. To work on the link, we add –no-dereference:
$ touch --no-dereference -t 201010100656 /symlink
$ ls -l /symlink /file
lrwxrwxrwx 1 x x 5 Oct 10 2010 /symlink -> /file
-rw-r--r-- 1 x x 8 Oct 10 2010 /file
Although we don’t see the time due to the year change, all timestamps are now modified according to our needs.
7. Summary
In this article, we explored ways to work with links instead of their targets. We saw methods that apply not only to data, but also to metadata changes such as owner, permissions, and timestamps.
In conclusion, the Linux kernel supports fewer operations for links in comparison to other files, and it depends on the tool at hand to tap into that support.