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
86
87
88
//! On-disk constants shared across the F2FS reader modules.
//!
//! Sources: kernel docs (`docs.kernel.org/filesystems/f2fs.html`) and the
//! FAST '15 paper. We deliberately do not import any kernel header.
/// F2FS block size in bytes. Fixed at 4 KiB.
pub const F2FS_BLKSIZE: usize = 4096;
/// Offset (within a 4 KiB CP / NAT / SIT / dnode block) of the trailing
/// CRC32 footer that protects the block.
pub const F2FS_BLK_CSUM_OFFSET: usize = F2FS_BLKSIZE - 4;
/// Inode block — number of direct data-block pointers.
///
/// FAST '15 / kernel docs both quote 923; this is `i_addr` after the
/// 360-byte inode header and the inline xattr reservation. The on-disk
/// `i_inline` bitfield can shrink the array (inline data / inline dentry)
/// but those modes are detected at parse time, not here.
pub const ADDRS_PER_INODE: usize = 923;
/// Number of node-id slots in an inode block (2 direct, 2 indirect, 1
/// triple-indirect).
pub const NIDS_PER_INODE: usize = 5;
/// Indices into `i_nid[5]`.
pub const NID_DIRECT_1: usize = 0;
pub const NID_DIRECT_2: usize = 1;
pub const NID_INDIRECT_1: usize = 2;
pub const NID_INDIRECT_2: usize = 3;
pub const NID_TRIPLE_INDIRECT: usize = 4;
/// Direct / indirect node blocks each hold 1018 u32 entries.
pub const ADDRS_PER_BLOCK: usize = 1018;
pub const NIDS_PER_BLOCK: usize = 1018;
/// NAT entry size on disk: version(1) + ino(4) + block_addr(4) = 9 bytes.
pub const NAT_ENTRY_SIZE: usize = 9;
/// NAT entries per NAT page: floor(4096 / 9) = 455.
pub const NAT_ENTRY_PER_BLOCK: usize = F2FS_BLKSIZE / NAT_ENTRY_SIZE;
/// Dentry block layout — 27-byte bitmap + 3 reserved + 11 × 214 dentries +
/// 8 × 214 filenames = 4096 bytes total.
pub const NR_DENTRY_IN_BLOCK: usize = 214;
pub const SIZE_OF_DIR_ENTRY: usize = 11;
pub const SIZE_OF_DENTRY_BITMAP: usize = 27;
pub const SIZE_OF_RESERVED: usize = 3;
pub const F2FS_SLOT_LEN: usize = 8;
/// Bits in `F2fsInode::i_inline`.
pub const F2FS_INLINE_DATA: u8 = 0x02;
pub const F2FS_INLINE_DENTRY: u8 = 0x04;
pub const F2FS_INLINE_XATTR: u8 = 0x01;
pub const F2FS_DATA_EXIST: u8 = 0x08;
/// Checkpoint flag bits we care about (others ignored).
pub const CP_COMPACT_SUM_FLAG: u32 = 0x0001;
pub const CP_ORPHAN_PRESENT_FLAG: u32 = 0x0002;
pub const CP_UMOUNT_FLAG: u32 = 0x0004;
pub const CP_FASTBOOT_FLAG: u32 = 0x0008;
pub const CP_CRC_RECOVERY_FLAG: u32 = 0x0010;
/// Reserved/special block addresses. Anything `>= 1` and `< NEW_ADDR`
/// is a real allocation; the two specials below mark "not yet on disk"
/// (data is in the inode's inline area) and "explicit hole".
pub const NULL_ADDR: u32 = 0;
pub const NEW_ADDR: u32 = u32MAX - 1;
/// Standard POSIX type bits in `i_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;
pub const S_IFCHR: u16 = 0x2000;
pub const S_IFBLK: u16 = 0x6000;
pub const S_IFIFO: u16 = 0x1000;
pub const S_IFSOCK: u16 = 0xC000;
/// On-disk file types stored in the 1-byte `file_type` field of a
/// `f2fs_dir_entry`. Numbering matches the standard d_type set so it
/// reads naturally.
pub const F2FS_FT_UNKNOWN: u8 = 0;
pub const F2FS_FT_REG_FILE: u8 = 1;
pub const F2FS_FT_DIR: u8 = 2;
pub const F2FS_FT_CHRDEV: u8 = 3;
pub const F2FS_FT_BLKDEV: u8 = 4;
pub const F2FS_FT_FIFO: u8 = 5;
pub const F2FS_FT_SOCK: u8 = 6;
pub const F2FS_FT_SYMLINK: u8 = 7;