File and Directory Abstractions
Files
A file is a named, persistent, linear array of bytes with no intrinsic structure. The OS provides operations to:
| Operation | System call | Effect |
|---|---|---|
| Create/Destroy | open(O_CREAT), unlink() | Bring a file into existence or remove its name |
| Open/Close | open(), close() | Obtain/release a file descriptor |
| Read/Write | read(), write() | Transfer bytes from/to a specified offset |
| Seek | lseek() | Move the current file offset (for sequential access) |
| Get attributes | stat(), fstat() | Read metadata (size, owner, permissions, timestamps) |
| Set attributes | chmod(), chown(), utimes() | Modify metadata |
The kernel tracks two things separately: the file (the data and metadata on disk) and the open file description (the in-memory state for an open instance — current offset, access mode, reference count). Multiple file descriptors (from fork() or dup()) can share the same open file description, meaning they share the current offset.
Directories
A directory is a special file that maps human-readable names to file metadata (or, in UNIX, to inode numbers). Directories provide the naming hierarchy (the directory tree). In UNIX, a directory entry is simply a (name, inode_number) pair.
Operations on directories:
| Operation | System call |
|---|---|
| Create | mkdir() |
| Remove | rmdir() |
| List entries | getdents() (used by ls) |
| Look up | Performed implicitly by open() — the kernel walks the directory path |
The UNIX path-resolution algorithm
Given a path like /home/alice/doc.txt:
- Start at the process’s root directory (or current directory for relative paths).
- For each component of the path (
home,alice,doc.txt):- Check that the current inode is a directory and that the process has execute (search) permission on it.
- Look up the next component name in the directory’s entries.
- If found, the entry gives the inode number of the next component. Load that inode.
- At the final component, open the file (or create it, or return an error).
Symbolic links (soft links) add a twist: if a component is a symlink and O_NOFOLLOW is not set, the kernel replaces the symlink’s target path in the remaining components and continues. To prevent infinite loops, the kernel caps the number of symlink traversals (typically 40 on Linux).
The directory tree
UNIX presents a single tree rooted at /. Different file systems (ext4 on /, NTFS on /mnt/windows, NFS on /net/server) are mounted onto directories in this tree. The mount operation associates a directory (the mount point) with the root of another file system. The kernel’s Virtual File System (VFS) layer routes operations to the correct file system based on mount tables.
Summary
- Files are named, persistent byte arrays; directories map names to inode numbers.
- The kernel tracks the on-disk file (inode + data) separately from in-memory open file descriptions.
- Path resolution walks directory entries component by component, checking permissions at each step.
- Mounting grafts independent file systems into a unified directory tree.