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.

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:

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.

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?

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.