use std::mem;
#[repr(C)]
pub struct TarHeader {
pub name: [u8; 100],
pub mode: [u8; 8],
pub uid: [u8; 8],
pub gid: [u8; 8],
pub size: [u8; 12],
pub mtime: [u8; 12],
pub checksum: [u8; 8],
pub typeflag: u8,
pub linkname: [u8; 100],
pub magic: [u8; 6],
pub version: [u8; 2],
pub uname: [u8; 32],
pub gname: [u8; 32],
pub devmajor: [u8; 8],
pub devminor: [u8; 8],
pub prefix: [u8; 155],
pub padding: [u8; 12],
}
impl TarHeader {
pub fn new() -> Self {
let mut h = unsafe { mem::zeroed::<TarHeader>() };
h.magic.copy_from_slice(b"ustar ");
h.version.copy_from_slice(b" \0");
h
}
pub fn calculate_checksum(&self) -> u32 {
let bytes = unsafe { std::slice::from_raw_parts(self as *const _ as *const u8, 512) };
bytes.iter().enumerate().fold(0u32, |sum, (i, &b)| {
sum + if i >= 148 && i < 156 { 32 } else { b as u32 }
})
}
pub fn set_octal(dst: &mut [u8], val: u64) {
let len = dst.len();
let s = format!("{:0>width$o}", val, width = len - 1);
dst[..len - 1].copy_from_slice(s.as_bytes());
}
pub fn parse_octal(bytes: &[u8]) -> std::io::Result<u64> {
let clean = bytes.split(|&b| b == 0 || b == b' ').next().unwrap_or(&[]);
if clean.is_empty() {
return Ok(0);
}
let s = std::str::from_utf8(clean)
.map_err(|_| std::io::Error::new(std::io::ErrorKind::InvalidData, "Invalid octal sequence"))?;
u64::from_str_radix(s.trim(), 8)
.map_err(|_| std::io::Error::new(std::io::ErrorKind::InvalidData, "Failed to parse octal"))
}
}