1use crate::{superblock::ChecksumType, tree::DiskKey};
7use bytes::{Buf, BufMut};
8use uuid::Uuid;
9
10pub fn get_uuid(buf: &mut &[u8]) -> Uuid {
16 let bytes: [u8; 16] = buf[..16].try_into().unwrap();
17 buf.advance(16);
18 Uuid::from_bytes(bytes)
19}
20
21pub fn write_disk_key(buf: &mut [u8], off: usize, key: &DiskKey) {
23 (&mut buf[off..off + 8]).put_u64_le(key.objectid);
24 buf[off + 8] = key.key_type.to_raw();
25 (&mut buf[off + 9..off + 17]).put_u64_le(key.offset);
26}
27
28pub fn write_le_u64(buf: &mut [u8], off: usize, val: u64) {
30 buf[off..off + 8].copy_from_slice(&val.to_le_bytes());
31}
32
33pub fn write_le_u32(buf: &mut [u8], off: usize, val: u32) {
35 buf[off..off + 4].copy_from_slice(&val.to_le_bytes());
36}
37
38pub fn write_le_u16(buf: &mut [u8], off: usize, val: u16) {
40 buf[off..off + 2].copy_from_slice(&val.to_le_bytes());
41}
42
43pub fn write_uuid(buf: &mut [u8], off: usize, uuid: &Uuid) {
45 buf[off..off + 16].copy_from_slice(uuid.as_bytes());
46}
47
48#[must_use]
57pub fn raw_crc32c(seed: u32, data: &[u8]) -> u32 {
58 !crc32c::crc32c_append(!seed, data)
62}
63
64#[must_use]
69pub fn btrfs_name_hash(name: &[u8]) -> u32 {
70 raw_crc32c(!1u32, name)
71}
72
73#[must_use]
81pub fn btrfs_csum_data(data: &[u8]) -> u32 {
82 crc32c::crc32c(data)
83}
84
85pub fn csum_tree_block(buf: &mut [u8], csum_type: ChecksumType) {
97 assert!(buf.len() > 32, "buffer too small for tree block checksum");
98 let hash = csum_type.compute(&buf[32..]);
99 let n = csum_type.size();
100 buf[0..n].copy_from_slice(&hash[..n]);
101 buf[n..32].fill(0);
102}
103
104#[cfg(test)]
105mod tests {
106 use super::*;
107
108 #[test]
109 fn test_write_le_u64() {
110 let mut buf = [0u8; 8];
111 write_le_u64(&mut buf, 0, 0x0807060504030201);
112 assert_eq!(buf, [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08]);
113 }
114
115 #[test]
116 fn test_write_le_u32() {
117 let mut buf = [0u8; 4];
118 write_le_u32(&mut buf, 0, 0x04030201);
119 assert_eq!(buf, [0x01, 0x02, 0x03, 0x04]);
120 }
121
122 #[test]
123 fn test_write_le_u16() {
124 let mut buf = [0u8; 2];
125 write_le_u16(&mut buf, 0, 0x0201);
126 assert_eq!(buf, [0x01, 0x02]);
127 }
128
129 #[test]
130 fn test_write_uuid() {
131 let uuid =
132 Uuid::parse_str("deadbeef-dead-beef-dead-beefdeadbeef").unwrap();
133 let mut buf = [0u8; 16];
134 write_uuid(&mut buf, 0, &uuid);
135 assert_eq!(buf, *uuid.as_bytes());
136 }
137
138 #[test]
139 fn test_roundtrip_u64() {
140 let mut buf = [0u8; 16];
141 write_le_u64(&mut buf, 4, 0xDEADBEEF_CAFEBABE);
142 assert_eq!(
143 u64::from_le_bytes(buf[4..12].try_into().unwrap()),
144 0xDEADBEEF_CAFEBABE
145 );
146 }
147
148 #[test]
149 fn test_btrfs_name_hash() {
150 assert_eq!(btrfs_name_hash(b"hello.txt"), 0x415f_eb59);
152 assert_ne!(
154 btrfs_name_hash(b"hello.txt"),
155 btrfs_name_hash(b"world.txt")
156 );
157 }
158
159 #[test]
160 fn test_roundtrip_uuid() {
161 let uuid =
162 Uuid::parse_str("01234567-89ab-cdef-0123-456789abcdef").unwrap();
163 let mut buf = [0u8; 16];
164 write_uuid(&mut buf, 0, &uuid);
165 assert_eq!(Uuid::from_bytes(buf), uuid);
166 }
167}