pub const FSINFO_SIZE: usize = 512;
const LEAD_SIG: u32 = 0x4161_5252;
const STRUCT_SIG: u32 = 0x6141_7272;
const TRAIL_SIG: u32 = 0xAA55_0000;
#[derive(Debug, Clone, Copy)]
pub struct FsInfo {
pub free_count: u32,
pub next_free: u32,
}
impl FsInfo {
pub fn encode(&self) -> [u8; FSINFO_SIZE] {
let mut b = [0u8; FSINFO_SIZE];
b[0..4].copy_from_slice(&LEAD_SIG.to_le_bytes());
b[484..488].copy_from_slice(&STRUCT_SIG.to_le_bytes());
b[488..492].copy_from_slice(&self.free_count.to_le_bytes());
b[492..496].copy_from_slice(&self.next_free.to_le_bytes());
b[508..512].copy_from_slice(&TRAIL_SIG.to_le_bytes());
b
}
pub fn decode(b: &[u8; FSINFO_SIZE]) -> crate::Result<Self> {
let lead = u32::from_le_bytes(b[0..4].try_into().unwrap());
let strukt = u32::from_le_bytes(b[484..488].try_into().unwrap());
let trail = u32::from_le_bytes(b[508..512].try_into().unwrap());
if lead != LEAD_SIG || strukt != STRUCT_SIG || trail != TRAIL_SIG {
return Err(crate::Error::InvalidImage(
"fat32: bad FSInfo signature".into(),
));
}
Ok(Self {
free_count: u32::from_le_bytes(b[488..492].try_into().unwrap()),
next_free: u32::from_le_bytes(b[492..496].try_into().unwrap()),
})
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn roundtrip() {
let fi = FsInfo {
free_count: 129021,
next_free: 3,
};
let dec = FsInfo::decode(&fi.encode()).unwrap();
assert_eq!(dec.free_count, 129021);
assert_eq!(dec.next_free, 3);
}
#[test]
fn signatures_checked() {
assert!(FsInfo::decode(&[0u8; FSINFO_SIZE]).is_err());
}
}