Everything that is not file data is stored in metadata blocks: the inode table, the directory table, the fragment, export and id tables, the extended attributes and the compressor options. A table is a run of metadata blocks, and a reader sees it as one stream of bytes: the decompressed blocks one after another.
A metadata block
| Offset | Size | Type | Name | Description |
|---|---|---|---|---|
0 | 2 | uint16 | Header | Bit 15 set: the data is stored uncompressed. Bits 0 to 14: the size of the data that follows, from 1 to 8192. A size of 0, or above 8192, is not valid. |
2 | size | bytes | Data | Compressed with the image’s compressor, or stored as it is. It decompresses to at most 8192 bytes; mksquashfs fills every block of a table except the last with exactly 8192. |
The next block starts right after the data. A block is never longer than 8194 bytes in the file, so a table of blocks that would not compress costs 2 bytes in every 8192.
References into a table
The inode table and the directory table are not indexed: a directory entry or the superblock names an inode by a reference, and an inode names the start of its directory listing the same way.
- A 64-bit reference (the root inode in the superblock, the entries of the
export table, the xattr pointers inside an xattr id) is
block × 65536 + offset:blockis the file offset of a metadata block counted from the start of the table, andoffsetis a position in that block after decompression (0 to 8191). - A directory entry gives the same pair in two parts: the header’s 32-bit start (the block) and the entry’s 16-bit offset.
- A directory inode names its listing by a 32-bit start block (counted from the start of the directory table) and a 16-bit offset.
An inode or a directory listing may start near the end of a block and continue in the next one; a reader just carries on across the boundary, as the stream view says. An inode that starts exactly where a block ends is named by the next block, at offset 0.
Lookup tables
The fragment table, the export table and the id table hold fixed-size entries, so they are found by an index instead of by walking: an array of 64-bit file offsets, one for each metadata block of the table, written after the blocks. The superblock gives the offset of this array. Entry i is in block i ÷ (8192 ÷ entry size) of the array at the entry index i mod (8192 ÷ entry size). The xattr table uses the same idea with its own header (see tables and xattrs).