Skip to main content

btrfs_disk/
util.rs

1//! # Utilities: shared parsing helpers for on-disk structures
2//!
3//! Little-endian reader functions for extracting typed values from raw byte
4//! buffers at known offsets. Used throughout the disk crate to parse packed
5//! on-disk structures safely without pointer casts.
6
7use uuid::Uuid;
8
9/// Read a little-endian u64 from `buf` at byte offset `off`.
10pub fn read_le_u64(buf: &[u8], off: usize) -> u64 {
11    u64::from_le_bytes(buf[off..off + 8].try_into().unwrap())
12}
13
14/// Read a little-endian u32 from `buf` at byte offset `off`.
15pub fn read_le_u32(buf: &[u8], off: usize) -> u32 {
16    u32::from_le_bytes(buf[off..off + 4].try_into().unwrap())
17}
18
19/// Read a little-endian u16 from `buf` at byte offset `off`.
20pub fn read_le_u16(buf: &[u8], off: usize) -> u16 {
21    u16::from_le_bytes(buf[off..off + 2].try_into().unwrap())
22}
23
24/// Read a UUID (16 bytes, big-endian byte order) from `buf` at byte offset `off`.
25pub fn read_uuid(buf: &[u8], off: usize) -> Uuid {
26    Uuid::from_bytes(buf[off..off + 16].try_into().unwrap())
27}
28
29/// Write a little-endian u64 into `buf` at byte offset `off`.
30pub fn write_le_u64(buf: &mut [u8], off: usize, val: u64) {
31    buf[off..off + 8].copy_from_slice(&val.to_le_bytes());
32}
33
34/// Write a little-endian u32 into `buf` at byte offset `off`.
35pub fn write_le_u32(buf: &mut [u8], off: usize, val: u32) {
36    buf[off..off + 4].copy_from_slice(&val.to_le_bytes());
37}
38
39/// Write a little-endian u16 into `buf` at byte offset `off`.
40pub fn write_le_u16(buf: &mut [u8], off: usize, val: u16) {
41    buf[off..off + 2].copy_from_slice(&val.to_le_bytes());
42}
43
44/// Write a UUID (16 bytes) into `buf` at byte offset `off`.
45pub fn write_uuid(buf: &mut [u8], off: usize, uuid: &Uuid) {
46    buf[off..off + 16].copy_from_slice(uuid.as_bytes());
47}
48
49#[cfg(test)]
50mod tests {
51    use super::*;
52
53    #[test]
54    fn test_read_le_u64() {
55        let buf = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08];
56        assert_eq!(read_le_u64(&buf, 0), 0x0807060504030201);
57    }
58
59    #[test]
60    fn test_read_le_u64_with_offset() {
61        let buf = [0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08];
62        assert_eq!(read_le_u64(&buf, 2), 0x0807060504030201);
63    }
64
65    #[test]
66    fn test_read_le_u32() {
67        let buf = [0x01, 0x02, 0x03, 0x04];
68        assert_eq!(read_le_u32(&buf, 0), 0x04030201);
69    }
70
71    #[test]
72    fn test_read_le_u16() {
73        let buf = [0x01, 0x02];
74        assert_eq!(read_le_u16(&buf, 0), 0x0201);
75    }
76
77    #[test]
78    fn test_write_le_u64() {
79        let mut buf = [0u8; 8];
80        write_le_u64(&mut buf, 0, 0x0807060504030201);
81        assert_eq!(buf, [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08]);
82    }
83
84    #[test]
85    fn test_write_le_u32() {
86        let mut buf = [0u8; 4];
87        write_le_u32(&mut buf, 0, 0x04030201);
88        assert_eq!(buf, [0x01, 0x02, 0x03, 0x04]);
89    }
90
91    #[test]
92    fn test_write_le_u16() {
93        let mut buf = [0u8; 2];
94        write_le_u16(&mut buf, 0, 0x0201);
95        assert_eq!(buf, [0x01, 0x02]);
96    }
97
98    #[test]
99    fn test_write_uuid() {
100        let uuid =
101            Uuid::parse_str("deadbeef-dead-beef-dead-beefdeadbeef").unwrap();
102        let mut buf = [0u8; 16];
103        write_uuid(&mut buf, 0, &uuid);
104        assert_eq!(buf, *uuid.as_bytes());
105    }
106
107    #[test]
108    fn test_roundtrip_u64() {
109        let mut buf = [0u8; 16];
110        write_le_u64(&mut buf, 4, 0xDEADBEEF_CAFEBABE);
111        assert_eq!(read_le_u64(&buf, 4), 0xDEADBEEF_CAFEBABE);
112    }
113
114    #[test]
115    fn test_roundtrip_uuid() {
116        let uuid =
117            Uuid::parse_str("01234567-89ab-cdef-0123-456789abcdef").unwrap();
118        let mut buf = [0u8; 16];
119        write_uuid(&mut buf, 0, &uuid);
120        assert_eq!(read_uuid(&buf, 0), uuid);
121    }
122
123    #[test]
124    fn test_read_uuid() {
125        let bytes = [
126            0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe,
127            0xef, 0xde, 0xad, 0xbe, 0xef,
128        ];
129        let uuid = read_uuid(&bytes, 0);
130        assert_eq!(uuid.to_string(), "deadbeef-dead-beef-dead-beefdeadbeef");
131    }
132}