1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
//! XFS on-disk format constants: magics, feature bits, field offsets.
//!
//! All values are facts of the published XFS on-disk format. Offsets are byte
//! offsets into the relevant on-disk structure; every multi-byte field is
//! big-endian (read via [`crate::be`]).
// ---- magic numbers ----
pub const SB_MAGIC: u32 = 0x5846_5342; // "XFSB"
pub const INODE_MAGIC: u16 = 0x494e; // "IN"
pub const DIR3_DATA_MAGIC: u32 = 0x5844_4433; // "XDD3" (v5 data block)
pub const DIR2_DATA_MAGIC: u32 = 0x5844_3244; // "XD2D" (v4 data block)
pub const DIR3_BLOCK_MAGIC: u32 = 0x5844_4233; // "XDB3" (v5 single-block dir)
pub const DIR2_BLOCK_MAGIC: u32 = 0x5844_3242; // "XD2B" (v4 single-block dir)
pub const SYMLINK_MAGIC: u32 = 0x5853_4c4d; // "XSLM" (v5 remote symlink hdr)
// ---- superblock version ----
pub const SB_VERSION_NUMBITS: u16 = 0x000f;
pub const SB_VERSION_4: u16 = 4;
pub const SB_VERSION_5: u16 = 5;
// ---- v5 incompat feature bits (sb_features_incompat) ----
pub const INCOMPAT_FTYPE: u32 = 1 << 0;
pub const INCOMPAT_SPINODES: u32 = 1 << 1;
pub const INCOMPAT_META_UUID: u32 = 1 << 2;
pub const INCOMPAT_BIGTIME: u32 = 1 << 3;
pub const INCOMPAT_NEEDSREPAIR: u32 = 1 << 4;
pub const INCOMPAT_NREXT64: u32 = 1 << 5;
/// Incompat bits this reader understands. Any bit outside this set means the
/// on-disk layout may differ in a way we cannot safely read → reject.
/// `NEEDSREPAIR` is deliberately excluded: it marks a filesystem that must be
/// repaired before use.
pub const INCOMPAT_SUPPORTED: u32 =
INCOMPAT_FTYPE | INCOMPAT_SPINODES | INCOMPAT_META_UUID | INCOMPAT_BIGTIME | INCOMPAT_NREXT64;
// ---- v4 features2 (sb_features2) — the bit relevant to a reader ----
pub const FEATURES2_FTYPE: u32 = 0x0000_0200;
// ---- inode di_format ----
pub const DINODE_FMT_DEV: u8 = 0;
pub const DINODE_FMT_LOCAL: u8 = 1;
pub const DINODE_FMT_EXTENTS: u8 = 2;
pub const DINODE_FMT_BTREE: u8 = 3;
// ---- inode core field offsets (xfs_dinode) ----
pub const DI_MAGIC: usize = 0;
pub const DI_MODE: usize = 2;
pub const DI_VERSION: usize = 4;
pub const DI_FORMAT: usize = 5;
/// 64-bit data-fork extent count when the NREXT64 incompat bit is set. This
/// repurposes the offset-24 union (di_v2_pad/di_flushiter / di_v3_pad).
pub const DI_BIG_NEXTENTS: usize = 24;
pub const DI_SIZE: usize = 56;
/// 32-bit data-fork extent count for the non-NREXT64 layout.
pub const DI_NEXTENTS: usize = 76;
pub const DI_FORKOFF: usize = 82;
/// Inode-core size (where the data fork / literal area begins).
pub const DINODE_CORE_V3: usize = 176; // v5 inodes (di_version 3)
pub const DINODE_CORE_V2: usize = 100; // v4 inodes (di_version 1/2)
// ---- POSIX mode bits (di_mode) ----
pub const S_IFMT: u16 = 0xf000;
pub const S_IFREG: u16 = 0x8000;
pub const S_IFDIR: u16 = 0x4000;
pub const S_IFLNK: u16 = 0xa000;
// ---- directory geometry ----
/// Logical byte offset at which a directory's leaf (hash-index) blocks begin;
/// data blocks live strictly below it. 32 GiB. We enumerate data blocks only —
/// the leaf/free index is a lookup accelerator a reader does not need.
pub const DIR2_LEAF_OFFSET: u64 = 32 * 1024 * 1024 * 1024;
/// v5 directory data-block header size (xfs_dir3_data_hdr): a 48-byte
/// xfs_dir3_blk_hdr + best-free[3] (12) + 4 pad.
pub const DIR3_DATA_HDR_LEN: usize = 64;
/// v4 directory data-block header size (xfs_dir2_data_hdr): magic(4) +
/// best-free[3] (12).
pub const DIR2_DATA_HDR_LEN: usize = 16;
/// Marker u16 for an unused (free) directory data region.
pub const DIR2_DATA_FREE_TAG: u16 = 0xffff;
/// v5 remote-symlink block header length (xfs_dsymlink_hdr): magic(4) + offset(4)
/// + bytes(4) + crc(4) + uuid(16) + owner(8) + blkno(8) + lsn(8) = 56.
pub const SYMLINK_HDR_LEN: usize = 56;