---
title: Links
source: 'https://academia.sh/en/courses/introduction-to-linux/links'
course: 'Introduction to Linux'
language: en
updated: '2026-08-17T18:09:56+00:00'
license: 'CC BY-SA 4.0'
---

# Links

The distinction between a directory entry and an inode, a hard link sharing the same inode, a symbolic link holding a path string, and a comparison of the two kinds' constraints.

The previous lesson defined deletion as "unlinking" and ended by saying a file can
have more than one name. This lesson builds that possibility.

The foundation is the distinction introduced in the navigation lesson: a **directory
entry** maps a name to an inode, while an **inode** holds the file's metadata and the
location of its data blocks. The name is not stored inside the inode, so nothing
prevents more than one entry from pointing to the same inode.

## Hard Link

A **hard link** is adding a new directory entry to an existing inode.

```
$ ln data/raw/measurement-03.csv data/latest-measurement.csv
$ ls -li data/raw/measurement-03.csv data/latest-measurement.csv
22143 -rw-r--r-- 2 student student 47 Jul 26 19:03 data/raw/measurement-03.csv
22143 -rw-r--r-- 2 student student 47 Jul 26 19:03 data/latest-measurement.csv
```

Both lines show inode number `22143`, and the link count column has risen from `1`
to `2`. This is not a copy: there is a single file with two names. No extra disk
space has been used; only a directory entry has been added.

There is **no hierarchy** between the two names. Which one is "real" is meaningless;
both are equally close to the same inode. This shows up in deletion:

```
$ rm data/raw/measurement-03.csv
$ ls -li data/latest-measurement.csv
22143 -rw-r--r-- 1 student student 47 Jul 26 19:03 data/latest-measurement.csv
$ cat data/latest-measurement.csv
zaman,sicaklik,nem
08:00,22.6,58
12:00,26.3,44
```

One of the names has been deleted, the link count has dropped to `1`, and the data
remains in place. The rule from the previous lesson is confirmed here: data blocks
are freed only when the link count reaches zero.

The deleted name can be put back, because the inode is still reachable:

```
$ ln data/latest-measurement.csv data/raw/measurement-03.csv
$ ls -li data/raw/measurement-03.csv data/latest-measurement.csv
22143 -rw-r--r-- 2 student student 47 Jul 26 19:03 data/raw/measurement-03.csv
22143 -rw-r--r-- 2 student student 47 Jul 26 19:03 data/latest-measurement.csv
```

## Two Constraints of the Hard Link

Hard links have two constraints, and both are a direct consequence of the concept of
an inode.

**It cannot cross a file system boundary.** An inode number is meaningful only
within its own file system; an entry cannot be written to an inode on another file
system.

```
$ ln data/raw/measurement-01.csv /dev/shm/measurement-01.csv
ln: failed to create hard link '/dev/shm/measurement-01.csv' => 'data/raw/measurement-01.csv': Invalid cross-device link
```

This is the twin, from the same root, of the observation in the moving lesson:
moving within the same file system is cheap, moving outside it turns into
copying — because a directory entry can only point to inodes within its own file
system.

**It cannot be placed on directories.**

```
$ ln data/raw data/raw-link
ln: data/raw: hard link not allowed for directory
```

The prohibition exists to keep the file system a tree. If a hard link could be
placed on directories, cycles could form, and any tool traversing the tree could fall
into infinite recursion. The only exception to this prohibition is two entries the
system itself sets up:

```
$ ls -lid data/. data/raw/..
21906 drwxr-xr-x 4 student student 4096 Jul 26 19:08 data/.
21906 drwxr-xr-x 4 student student 4096 Jul 26 19:08 data/raw/..
```

`data/.` and `data/raw/..` point to the same inode: both are the `data` directory
itself. This also explains a number left unexplained in the navigation lesson. A
directory's link count consists of: its name in the parent directory, its own `.`
entry, and the `..` entry of every subdirectory. Because the `data` directory has
two subdirectories, the number is $1 + 1 + 2 = 4$.

## Symbolic Link

A **symbolic link** is an entirely different object: a small file with its own
inode, whose content consists of nothing but a **path string**. When the kernel
reads this file, it goes on to resolve the path inside it.

A symbolic link suits accessing the most recent file in the measurements directory
under a fixed name:

```
$ ln -s raw/measurement-03.csv data/current.csv
$ ls -li data
total 8
28322 lrwxrwxrwx 1 student student   22 Jul 26 19:08 current.csv -> raw/measurement-03.csv
21908 drwxr-xr-x 2 student student 4096 Jul 26 19:07 raw
21909 drwxr-xr-x 2 student student 4096 Jul 26 19:03 processed
```

The output has four details worth noting. The type character is `l`. The inode
number differs from the target's — it is a separate file. The size is `22`; this is
not the content of the target, but the length of the `raw/measurement-03.csv` string.
The permission bits appear as `rwxrwxrwx` and are meaningless: access control is
done according to the target's permissions.

The target is read with `readlink`, while the content is accessed directly:

```
$ readlink data/current.csv
raw/measurement-03.csv
$ cat data/current.csv
zaman,sicaklik,nem
08:00,22.6,58
12:00,26.3,44
```

Most commands **follow** a symbolic link: `cat` reads the target, not the link.
Commands that deal with the link itself (`rm`, `mv`, `ls -l`) do not follow it.
`rm current.csv` deletes the link, and does not touch the target.

## Which Directory a Relative Target Is Resolved Against

The path inside a symbolic link can be relative. In that case, resolution is done
not against the directory the command is run from, but against **the directory the
link is located in**.

The link above sits inside `data/` and its target is `raw/measurement-03.csv`;
resolution gives `data/raw/measurement-03.csv`. If the same link were created in a
different directory, the target could not be found:

```
$ ln -s data/raw/measurement-01.csv /dev/shm/measurement-01.csv
$ ls -l /dev/shm/measurement-01.csv
lrwxrwxrwx 1 student student 27 Jul 26 19:08 /dev/shm/measurement-01.csv -> data/raw/measurement-01.csv
$ cat /dev/shm/measurement-01.csv
cat: /dev/shm/measurement-01.csv: No such file or directory
```

The link has been created — whether the target exists is not checked — but it
cannot be resolved. There is no `data/raw` path inside `/dev/shm`. This situation
is called a **dangling link**.

A dangling link is not an error but the natural consequence of the definition: a
symbolic link is a path string, not a handle to the target. If the target is
deleted, moved, or the link is copied somewhere else, the link breaks.

The selection criterion follows from this. A relative target makes the link movable
with its target: when the whole tree is copied elsewhere, the link keeps working. An
absolute target points to the same file wherever the link goes, but breaks when the
tree is moved. Inside a tree, a relative target is preferred; for fixed, system-wide
locations, an absolute target is preferred.

## Comparing the Two Kinds

| Criterion | Hard link | Symbolic link |
|---|---|---|
| What it holds | A second entry to the same inode | The target's path string |
| Its own inode | No | Yes |
| File system boundary | Cannot cross | Can cross |
| Can be placed on a directory | No | Yes |
| When the target is deleted | Data survives, count decreases | Link breaks |
| How to tell them apart | Same number with `ls -i` | `l` and `->` in `ls -l` output |

The choice reduces to a simple question: is a second name needed for the same data,
or a fixed pointer to a target that can change? The first case uses a hard link, the
second a symbolic link. `current.csv` in the project tree is an example of the
second: when a new measurement file arrives, the link's target changes, its name
stays fixed.

The same approach appears in system layout too. The `/bin -> usr/bin` link from the
directory hierarchy lesson keeps the old path working — it could not be a hard
link, since it is placed on a directory.

## Summary

- A name is not a property of a file; a directory entry maps a name to an inode.
- A hard link adds a second entry to the same inode; the link count rises and there
  is no hierarchy among the names.
- A hard link cannot cross a file system boundary and cannot be placed on
  directories; `.` and `..` are the system's own exceptions to this prohibition.
- A symbolic link is a file with its own inode, whose content is a path string; its
  size is the length of the target string.
- A relative-target symbolic link is resolved against the directory the link is
  located in; if the target does not exist, the link is dangling, and this is a
  consequence of the definition, not an error.
- Inside a tree, a relative target is preferred; for fixed, system-wide locations,
  an absolute target is preferred.

## Next Step

The project tree now contains files, copies, and links. Packaging this whole tree
into a single file — to send it to another machine or to preserve a point in time —
raises a separate set of problems: how are links stored, how is the directory
structure converted into a flat byte sequence, and where does compression fit into
this? The next lesson begins by separating archiving from compression.
