How Linux Resolves File Paths Using Hard Links
In the Linux operating system, file path resolution is the core mechanism that translates a human-readable path string into the underlying data stored on a physical disk. Hard links are central to this design because Linux completely decouples a file’s identity and data from its name. This article explains the underlying mechanisms of Linux path resolution, detailing how the Virtual File System (VFS), directory entries, and inodes interact to resolve paths using hard links.
The Foundation: Inodes and Directory Entries
To understand path resolution, you must separate a file's name from its contents:
- Inode (Index Node): The true identity of a file. An inode stores metadata—such as file permissions, ownership, size, timestamps, and pointers to the disk blocks holding the actual file data. Crucially, an inode does not store the file name.
- Directory Entry (dentry): A directory in Linux is simply a special file containing a list of mappings. Each record maps a human-readable filename component to an inode number.
A hard link is simply a directory entry that points directly to an existing inode. Because every standard file entry in a directory is a mapping of a name to an inode, all regular files in Linux are essentially hard links.
Step-by-Step Path Resolution
When a process initiates a system call (such as open(),
stat(), or execve()) with a file path like
/home/user/document.txt, the Linux kernel’s Virtual File
System (VFS) resolves the path component by component:
Determining the Starting Point:
- If the path begins with a forward slash (
/), resolution starts at the root directory inode (defined by the process's root filesystem namespace). - If the path does not begin with a slash, resolution begins at the
inode corresponding to the current working directory (
cwd) of the calling process.
- If the path begins with a forward slash (
Iterative Component Lookup: The kernel splits the path by the
/delimiter and processes each token sequentially:- It checks the permissions of the current directory inode to verify
the process has execute (
+x) permissions, which are required for traversal. - The kernel consults the directory’s entry list to find a match for the target component string.
- Once matched, the kernel retrieves the corresponding inode number associated with that entry.
- It checks the permissions of the current directory inode to verify
the process has execute (
Kernel Optimization via Dcache: Reading directory blocks from disk repeatedly is computationally expensive. Linux maintains a memory cache called the Directory Cache (dcache). The dcache holds
dentrystructures representing recently accessed path components. During resolution, the kernel looks up names in the dcache first; only on a cache miss does it read the directory contents from the storage device.Reaching the Final Target: The kernel repeats this lookup process for each subfolder until it evaluates the final token (
document.txt). The final lookup extracts the target inode number, reads the inode metadata into memory, and makes the file's data blocks accessible to the process.
How Hard Links Function During Path Resolution
When you create a hard link using the command
ln source.txt link.txt, the kernel creates a new directory
entry (link.txt) pointing to the exact same inode number as
source.txt. It also increments the reference counter
(i_nlink) inside that inode.
During path resolution:
- Identical Treatment: The kernel handles
source.txtandlink.txtidentically. When the path resolver parses either name, the lookup yields the exact same inode number. The kernel does not distinguish an "original" file from a "link." - No Redirection: Unlike symbolic links (symlinks), which require the resolver to restart the path traversal using the target path stored inside the link file, a hard link requires zero redirection. Resolution terminates directly at the target inode.
- Decoupled Deletion: The kernel only frees disk
blocks when the inode's link count (
i_nlink) drops to zero and no open file descriptors reference it. Removing one path viaunlink()merely removes that specific name-to-inode mapping without affecting path resolution via any remaining hard links.
Filesystem Boundaries
Because hard links rely on raw inode numbers, they cannot cross filesystem boundaries. Inode numbers are only unique within a single filesystem instance. If a path resolution attempt requires bridging different storage devices or partitions, the operating system relies on mount points and symbolic links rather than hard links.