use btrfs_disk::raw;
use std::{io, mem, os::unix::io::AsRawFd};
const CSUM_SIZE: usize = raw::BTRFS_CSUM_SIZE as usize;
fn crc32c(data: &[u8]) -> u32 {
crc32c::crc32c(data)
}
pub fn fill_csum(buf: &mut [u8]) {
assert!(buf.len() > CSUM_SIZE);
let crc = crc32c(&buf[CSUM_SIZE..]);
buf[..4].copy_from_slice(&crc.to_le_bytes());
}
pub fn pwrite_all(
fd: &impl AsRawFd,
buf: &[u8],
offset: u64,
) -> io::Result<()> {
let raw_fd = fd.as_raw_fd();
let mut written = 0;
while written < buf.len() {
let ret = unsafe {
libc::pwrite(
raw_fd,
buf[written..].as_ptr() as *const libc::c_void,
buf.len() - written,
(offset + written as u64) as libc::off_t,
)
};
if ret < 0 {
return Err(io::Error::last_os_error());
}
if ret == 0 {
return Err(io::Error::new(
io::ErrorKind::WriteZero,
"pwrite returned 0",
));
}
written += ret as usize;
}
Ok(())
}
pub const SUPER_INFO_SIZE: usize = mem::size_of::<raw::btrfs_super_block>();
pub const SUPER_INFO_OFFSET: u64 = 65536;
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn crc32c_known_value() {
assert_eq!(crc32c(b"123456789"), 0xE3069283);
}
#[test]
fn crc32c_empty() {
assert_eq!(crc32c(b""), 0);
}
#[test]
fn fill_csum_writes_first_4_bytes() {
let mut buf = vec![0u8; 64];
for (i, b) in buf[CSUM_SIZE..].iter_mut().enumerate() {
*b = i as u8;
}
fill_csum(&mut buf);
let expected = crc32c(&buf[CSUM_SIZE..]);
let stored = u32::from_le_bytes(buf[..4].try_into().unwrap());
assert_eq!(stored, expected);
assert!(buf[4..CSUM_SIZE].iter().all(|&b| b == 0));
}
}