File System Structure & Inodes
IntermediateAn inode is a metadata structure that stores file attributes and pointers to data blocks; the directory system maps human-readable names to inode numbers.
Overview
Every file in a Unix-like filesystem has an inode — a fixed-size metadata record stored in the inode table. The inode holds file size, permissions (rwxrwxrwx), owner UID/GID, timestamps (atime/mtime/ctime), link count, and an array of pointers to data blocks (direct, single-indirect, double-indirect, triple-indirect). The file's name is NOT in the inode; names live in directory entries (dentries), which are simply mappings of name → inode number. This design enables hard links (multiple names pointing to the same inode) and makes file renaming within a filesystem an O(1) operation. The superblock stores filesystem-level metadata.
Inode Structure and Block Pointers
A typical inode has 12 direct block pointers, 1 single-indirect pointer (points to a block of pointers), 1 double-indirect pointer, and 1 triple-indirect pointer. For 4 KB blocks and 4-byte pointers, a single-indirect block holds 1024 pointers. This hierarchical structure allows small files to be accessed quickly (direct blocks) while supporting very large files.
// Inode structure (pseudocode representation)
class Inode {
int fileSize; // bytes
short permissions; // rwxrwxrwx bitmask
int ownerId;
int groupId;
long accessTime; // atime: last read
long modifyTime; // mtime: last content write
long changeTime; // ctime: last metadata change
int linkCount; // number of hard links pointing here
int blockCount; // number of 512-byte blocks allocated
// Block pointers (ext2/ext3 style)
int[] directBlocks = new int[12]; // 12 × 4KB = 48 KB directly
int singleIndirect; // → block of 1024 pointers → 4 MB
int doubleIndirect; // → block → 1024 blocks of pointers → 4 GB
int tripleIndirect; // → 4 TB (rarely reached)
}
// Max file size calculation (4KB blocks, 4-byte pointers):
long blockSize = 4096; // 4 KB
long ptrsPerBlock = blockSize / 4; // 1024 pointers per indirect block
long direct = 12 * blockSize; // 48 KB
long singleInd = ptrsPerBlock * blockSize; // 4 MB
long doubleInd = ptrsPerBlock * ptrsPerBlock * blockSize; // 4 GB
long tripleInd = ptrsPerBlock * ptrsPerBlock * ptrsPerBlock * blockSize; // 4 TB
System.out.printf("Max file size ≈ %d TB%n",
(direct + singleInd + doubleInd + tripleInd) / (1024L*1024*1024*1024)); // ~4 TBHard Links vs Symbolic Links in Java
A hard link creates a new directory entry pointing to the same inode — both names are equally valid, and the inode's link count is incremented. Deleting one name decrements the count; the data is freed only when count reaches zero. A symbolic link is a separate inode containing the path to the target — it can cross filesystems but breaks if the target is deleted.
import java.nio.file.*;
import java.nio.file.attribute.*;
Path original = Path.of("/tmp/data.txt");
Files.writeString(original, "Hello, filesystem!");
// HARD LINK: same inode, different directory entry
Path hardLink = Path.of("/tmp/data-hard.txt");
Files.createLink(hardLink, original); // both point to same inode
// Verify: same inode number
BasicFileAttributes origAttrs = Files.readAttributes(original,
BasicFileAttributes.class);
BasicFileAttributes hardAttrs = Files.readAttributes(hardLink,
BasicFileAttributes.class);
System.out.println("Same file key (inode): " +
origAttrs.fileKey().equals(hardAttrs.fileKey())); // true
// SYMBOLIC LINK: different inode, stores path to target
Path symLink = Path.of("/tmp/data-sym.txt");
Files.createSymbolicLink(symLink, original);
System.out.println("Symlink target: " + Files.readSymbolicLink(symLink));
System.out.println("Is symlink: " + Files.isSymbolicLink(symLink)); // true
System.out.println("Is symlink: " + Files.isSymbolicLink(hardLink)); // false
// Delete original — symlink breaks, hard link still works
Files.delete(original);
System.out.println("Hard link readable: " + Files.exists(hardLink)); // true
System.out.println("Symlink valid: " + Files.exists(symLink)); // falseKey Points to Remember
- 1An inode stores file metadata and block pointers but NOT the filename — filenames live in directory entries.
- 2Directories are files too: they contain a list of (name, inode_number) pairs.
- 3Hard links share an inode; the file is deleted only when link count reaches zero.
- 4Symbolic links are separate inodes containing a path string; they can cross filesystems and can dangle.
- 5The superblock contains filesystem-level metadata: total inodes, total blocks, block size, free inode/block counts.
- 6stat <filename> in the terminal shows the inode number and all inode fields; ls -i shows inode numbers.
Interview Questions
Sign in to ask AriaWhat is an inode and what information does it store?
What is the difference between a hard link and a symbolic link?
How does the kernel resolve a file path like /home/user/docs/file.txt to an inode?
Why can you rename a file within the same filesystem in O(1) but moving across filesystems requires a copy?
Ask Aria about File System Structure & Inodes
Your personal AI tutor — ask anything about this concept
Revision Status
Personal Notes
Sign in to save personal notes for this topic.
Discussion
Sign in to join the discussion.