Skip to main content

Checksummer

Struct Checksummer 

Source
pub struct Checksummer {
    pub seed: u32,
    pub enabled: bool,
}
Expand description

Per-mount checksum context: the seed and “is it enabled” flag.

Fields§

§seed: u32§enabled: bool

Implementations§

Source§

impl Checksummer

Source

pub fn from_superblock(sb: &Superblock) -> Self

Derive the checksum context from a parsed superblock.

Per spec: if INCOMPAT_CSUM_SEED is set, use the explicit s_checksum_seed field. Otherwise, the seed is the kernel’s __crc32c_le(~0, UUID, 16) — i.e. our linux_crc32c(!0, UUID).

Source

pub fn crc(&self, data: &[u8]) -> u32

Linux-semantics CRC32C of a buffer using the mount-wide seed.

Source

pub fn crc_with_prefix(&self, prefix: u32, data: &[u8]) -> u32

Linux-semantics CRC32C with a 32-bit context prefix folded in first.

Source

pub fn verify_superblock(&self, sb_raw: &[u8]) -> bool

Verify the superblock checksum. Stored at byte offset 0x3FC; CRC covers the first 0x3FC bytes. Initial seed is ~0 (NOT the per-FS seed — superblock checksum is special since the seed lives inside it).

Source

pub fn verify_bgd(&self, group_no: u32, bgd_raw: &[u8], desc_size: u16) -> bool

Verify a block group descriptor’s checksum.

Per spec (ext4/group_descr.html), when RO_COMPAT_METADATA_CSUM is set the GDT checksum is computed as:

  crc32c(seed, group_no_le_u32 || bgd_with_csum_zeroed) & 0xFFFF

desc_size is the on-disk descriptor size (32 or 64). bgd_raw must be at least desc_size bytes; the stored checksum at offset 0x1E is treated as zero for the computation.

Source

pub fn verify_dir_entry_tail( &self, ino: u32, generation: u32, block: &[u8], ) -> bool

Verify a directory block’s trailing ext4_dir_entry_tail checksum.

Linear directory blocks with metadata_csum enabled end in a 12-byte struct ext4_dir_entry_tail { u32 det_reserved_zero1; u16 det_rec_len; u8 det_reserved_zero2; u8 det_reserved_ft; u32 det_checksum; }.

Per Linux fs/ext4/dir.c::ext4_dirent_csum_set the CRC covers block[0..block_size - 12] — i.e. everything BEFORE the tail. The tail’s own bytes (including det_checksum) are excluded:

  crc32c(seed, ino_le) → crc32c(., gen_le) → crc32c(., block[..len-12])

block is the whole directory block including the trailing tail.

Source

pub fn patch_dir_entry_tail( &self, ino: u32, generation: u32, block: &mut [u8], ) -> bool

Plant the ext4_dir_entry_tail and checksum a directory block.

The mirror of Self::verify_dir_entry_tail, and the sibling that was missing: patch_extent_tail and patch_xattr_block both existed, so the one recipe written most often was the one with no helper. It was hand-rolled at sixteen sites across fs.rs, fsck.rs, mkfs.rs and the tests, in two different addressing idioms (bs - 12 with +4/+6/+7, and block.len() with -8/-6/-5) that a reader has to prove equivalent at each one.

The tail is a fake directory entry occupying the last 12 bytes: inode = 0 so no scan mistakes it for a real one, rec_len = 12 so a walk steps over it, name_len = 0, and file_type = 0xDE as the marker has_csum_tail looks for. The CRC then covers block[..len - 12] — the whole block except the tail entry, which is what separates this from Self::patch_extent_tail, where only the trailing 4 bytes are excluded.

Planting is idempotent: a block that already carries the tail gets the same twelve bytes back, so callers that only need the checksum recomputed can use this too rather than keeping a second recipe for that case.

Every constant here has to agree with e2fsprogs, and a disagreement produces no error until the volume is mounted somewhere else — which is the argument for there being one copy of them.

No-op when checksums are disabled or the block is under 12 bytes; returns true when it patched.

Source

pub fn verify_extent_tail( &self, ino: u32, generation: u32, block: &[u8], ) -> bool

Verify an extent-block tail checksum.

Extent index/leaf blocks (those read off-inode when the tree has internal nodes) end in a 4-byte struct ext4_extent_tail { u32 et_checksum; }. Per Linux fs/ext4/extents.c::ext4_extent_block_csum_set the CRC covers block[0..len-4] — only the trailing et_checksum field is excluded:

  crc32c(seed, ino_le) → crc32c(., gen_le) → crc32c(., block[..len-4])

Different from verify_dir_entry_tail, which excludes the full 12-byte tail entry.

Source

pub fn verify_inode(&self, ino: u32, generation: u32, inode_raw: &[u8]) -> bool

Verify a parsed inode’s checksum. Chained: seed → ino_le → gen_le → inode_bytes (with checksum slots zeroed).

Source

pub fn patch_extent_tail( &self, ino: u32, generation: u32, block: &mut [u8], ) -> bool

Write the ext4_extent_tail.et_checksum u32 at the end of a freshly- built extent index/leaf block. Mirrors verify_extent_tail: the CRC covers block[..len-4], chained seed → ino → generation → body. No-op when checksums are disabled; returns true when it patched.

Source

pub fn verify_xattr_block(&self, block_nr: u64, block: &[u8]) -> bool

Verify an external xattr block’s checksum.

Per Linux fs/ext4/xattr.c::ext4_xattr_block_csum, the recipe is:

  crc32c(seed, block_nr_le_u64)
  → crc32c(., block[0x00..0x10])      // magic, refcount, blocks, hash
  → crc32c(., [0u32])                  // h_checksum slot zeroed (4 bytes)
  → crc32c(., block[0x14..end])        // rest of block

The stored u32 lives at offset 0x10 of the block.

Source

pub fn patch_xattr_block(&self, block_nr: u64, block: &mut [u8]) -> bool

Patch the h_checksum field of an external xattr block in place. Mirrors [verify_xattr_block]. No-op when checksums are disabled. Returns true when the block was patched.

Source

pub fn compute_inode_checksum( &self, ino: u32, generation: u32, inode_raw: &[u8], ) -> Option<(u16, u16)>

Compute the inode checksum as two u16 halves (lo=checksum_lo at 0x7C, hi=checksum_hi at 0x82). Returns None when checksums are disabled or the buffer is too short to patch. Callers use this after mutating an inode image to restore the checksum before writing back.

Trait Implementations§

Source§

impl Clone for Checksummer

Source§

fn clone(&self) -> Checksummer

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Copy for Checksummer

Source§

impl Debug for Checksummer

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.