Files are byte streams; directories are maps
Unix exposes files as ordered byte streams with seek/read/write. Directories map human-readable names → inode numbers. The inode holds metadata and pointers to data blocks — the filename is not stored in the inode.
What an inode stores
| Field | Purpose |
|---|---|
| Mode & permissions | rwx for owner/group/other |
| UID/GID | Ownership for permission checks |
| Size, timestamps | atime, mtime, ctime |
| Block pointers | Direct, indirect, double-indirect → data blocks |
| Link count | Hard links reference the same inode |
Hard link — another directory entry pointing to the same inode. Symlink — a file whose contents are a path; separate inode.
VFS — one API, many file systems
The Virtual File System layer defines open, read, write, stat syscalls independent of backing store. ext4, xfs, btrfs, NFS, and procfs all register operations with the VFS. Your code calls read(fd) — VFS dispatches to the right file_system_type.
Path resolution
/var/log/app.log → walk from root inode: lookup "var" in /, then "log" in /var, then "app.log" in /var/log. Each step is a directory read. ** dentry cache** and inode cache in kernel RAM accelerate repeat lookups.
Senior-level signal
"No space left on device" with df showing free space often means inodes exhausted (df -i) — millions of tiny files. "Disk full" during a delete can mean an open file still held by a process (lsof | grep deleted) — space returns only when the fd closes.
Where this goes next
I/O Devices & DMA covers how inode block pointers eventually reach spinning rust or NVMe — and why reads block in D state.
Further Reading
Hands-On Tasks (Optional)
Low-setup exercises on your local machine. No autograding — the goal is to build intuition, not pass a test.
- Compare stat on a file and its hard link10m
Create `touch /tmp/ostest && ln /tmp/ostest /tmp/ostest_link`. Run `stat /tmp/ostest /tmp/ostest_link` — same inode number, link count 2. Delete one; the other still works.