File System Basics
[!NOTE] This module explores the core principles of File System Basics, deriving solutions from first principles and hardware constraints to build world-class, production-ready expertise.
1. The Persistent Abstraction
A running process is ephemeral. When it crashes, its memory is wiped. To store data permanently, Operating Systems provide the File System abstraction.
[!NOTE] “Everything is a file”: This Unix philosophy means that documents, directories, devices (keyboard, mouse), and even network sockets are represented as files. This unifies the API: you can
read()from a file andread()from a socket using the same syscalls.
The File Interface
At its core, a file is a linear array of bytes. The OS provides a cursor-based API:
- Open: Creates a “session” (File Descriptor).
- Seek: Moves the cursor (Offset) to a specific byte.
- Read/Write: Transfers data and advances the cursor.
- Close: Tears down the session.
Physical Reality vs Logical View
- Logical View: A continuous stream of bytes (0 to N).
- Physical Reality: Data is scattered across the disk in Blocks (usually 4KB). The File System’s job is to map logical offsets to physical block addresses.
2. Hard Links vs Symbolic Links
This is a common interview topic. Understanding the difference requires understanding Inodes.
- Inode (Index Node): The actual data structure on disk that describes the file (permissions, size, block locations). It has a unique number (Inode ID).
- Filename: A string stored in a Directory that maps to an Inode ID.
Hard Link
A directory entry that points to an existing Inode.
- If you have a file with 2 hard links, both names point to the same data.
- Deleting one name just removes that entry. The data remains until the Reference Count hits 0.
- Limitation: Cannot link across partitions (Inode numbers are local to a FS).
Symbolic Link (Soft Link)
A special file that contains a path string to another file.
- It has its own Inode.
- If you delete the target, the link becomes “broken” (dangling).
- Advantage: Can link across partitions and even to non-existent files.
3. Interactive: The Link Simulator
Visualize how Hard Links and Soft Links interact with the Inode layer.
Directory Entries
Inode Table
4. Code Examples: Managing Files
Modern languages provide abstractions, but they map to the same underlying syscalls (link, symlink, unlink).
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
public class FileLinks {
public static void main(String[] args) throws IOException {
Path target = Paths.get("data.txt");
if (!Files.exists(target)) {
Files.createFile(target);
}
// 1. Create a Hard Link
// Both 'data.txt' and 'hard-link.txt' point to the same Inode
Path hardLink = Paths.get("hard-link.txt");
try {
Files.createLink(hardLink, target);
System.out.println("Hard link created");
} catch (IOException e) {
// Fails if on different partitions
e.printStackTrace();
}
// 2. Create a Symbolic Link
// 'soft-link.txt' points to the path "data.txt"
Path softLink = Paths.get("soft-link.txt");
Files.createSymbolicLink(softLink, target);
System.out.println("Soft link created");
// Cleanup
Files.delete(target); // soft-link is now broken!
// hard-link still works and holds the data.
}
}
package main
import (
"fmt"
"os"
)
func main() {
target := "data.txt"
os.Create(target)
// 1. Create a Hard Link
// Corresponds to 'link()' syscall
hardLink := "hard-link.txt"
err := os.Link(target, hardLink)
if err != nil {
fmt.Println("Error creating hard link:", err)
} else {
fmt.Println("Hard link created")
}
// 2. Create a Symbolic Link
// Corresponds to 'symlink()' syscall
softLink := "soft-link.txt"
err = os.Symlink(target, softLink)
if err != nil {
fmt.Println("Error creating soft link:", err)
} else {
fmt.Println("Soft link created")
}
// Cleanup
os.Remove(target) // Soft link is broken
// Data still exists via hardLink
}