Skip to main content

btrfs_core/
bytes.rs

1//! Bounds-checked little-endian readers (the Paranoid Gatekeeper standard).
2//!
3//! btrfs is little-endian on disk throughout. Every reader yields `0` when the
4//! requested range lies outside the buffer, so a malformed or truncated image
5//! can never panic a parser. Callers that need to distinguish "field absent"
6//! from "field is zero" bounds-check the buffer length up front and surface
7//! [`crate::BtrfsError::Truncated`].
8
9/// Read a little-endian `u16` at `off`, or `0` if out of range.
10#[must_use]
11pub fn le_u16(data: &[u8], off: usize) -> u16 {
12    let mut b = [0u8; 2];
13    if let Some(s) = data.get(off..off + 2) {
14        b.copy_from_slice(s);
15    }
16    u16::from_le_bytes(b)
17}
18
19/// Read a little-endian `u32` at `off`, or `0` if out of range.
20#[must_use]
21pub fn le_u32(data: &[u8], off: usize) -> u32 {
22    let mut b = [0u8; 4];
23    if let Some(s) = data.get(off..off + 4) {
24        b.copy_from_slice(s);
25    }
26    u32::from_le_bytes(b)
27}
28
29/// Read a little-endian `u64` at `off`, or `0` if out of range.
30#[must_use]
31pub fn le_u64(data: &[u8], off: usize) -> u64 {
32    let mut b = [0u8; 8];
33    if let Some(s) = data.get(off..off + 8) {
34        b.copy_from_slice(s);
35    }
36    u64::from_le_bytes(b)
37}
38
39/// Read a single byte at `off`, or `0` if out of range.
40#[must_use]
41pub fn u8_at(data: &[u8], off: usize) -> u8 {
42    data.get(off).copied().unwrap_or(0)
43}
44
45#[cfg(test)]
46mod unit {
47    use super::{le_u16, le_u32, le_u64, u8_at};
48
49    #[test]
50    fn readers_decode_little_endian_in_range() {
51        let d = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08];
52        assert_eq!(le_u16(&d, 0), 0x0201);
53        assert_eq!(le_u32(&d, 0), 0x0403_0201);
54        assert_eq!(le_u64(&d, 0), 0x0807_0605_0403_0201);
55        assert_eq!(u8_at(&d, 3), 0x04);
56    }
57
58    #[test]
59    fn readers_yield_zero_out_of_range() {
60        assert_eq!(le_u16(&[0x12], 0), 0); // slice too short
61        assert_eq!(le_u32(&[0, 0, 0], 0), 0);
62        assert_eq!(le_u64(&[0, 0, 0, 0, 0, 0, 0], 0), 0);
63        assert_eq!(u8_at(&[], 0), 0);
64        assert_eq!(u8_at(&[0xAA], 5), 0);
65    }
66}