pub const BOOT_SECTOR_SIZE: usize = 512;
#[derive(Debug, Clone)]
pub struct BootSector {
pub bytes_per_sector: u16,
pub sectors_per_cluster: u8,
pub reserved_sector_count: u16,
pub num_fats: u8,
pub media: u8,
pub sectors_per_track: u16,
pub num_heads: u16,
pub hidden_sectors: u32,
pub total_sectors: u32,
pub fat_size: u32,
pub root_cluster: u32,
pub fs_info_sector: u16,
pub backup_boot_sector: u16,
pub drive_number: u8,
pub volume_id: u32,
pub volume_label: [u8; 11],
}
impl BootSector {
pub fn fat32_default() -> Self {
Self {
bytes_per_sector: 512,
sectors_per_cluster: 1,
reserved_sector_count: 32,
num_fats: 2,
media: 0xF8,
sectors_per_track: 32,
num_heads: 8,
hidden_sectors: 0,
total_sectors: 0,
fat_size: 0,
root_cluster: 2,
fs_info_sector: 1,
backup_boot_sector: 6,
drive_number: 0x80,
volume_id: 0,
volume_label: *b"NO NAME ",
}
}
pub fn data_start_sector(&self) -> u32 {
self.reserved_sector_count as u32 + self.num_fats as u32 * self.fat_size
}
pub fn cluster_count(&self) -> u32 {
let data_sectors = self.total_sectors - self.data_start_sector();
data_sectors / self.sectors_per_cluster as u32
}
pub fn encode(&self) -> [u8; BOOT_SECTOR_SIZE] {
let mut b = [0u8; BOOT_SECTOR_SIZE];
b[0..3].copy_from_slice(&[0xEB, 0x58, 0x90]);
b[3..11].copy_from_slice(b"fstool ");
b[11..13].copy_from_slice(&self.bytes_per_sector.to_le_bytes());
b[13] = self.sectors_per_cluster;
b[14..16].copy_from_slice(&self.reserved_sector_count.to_le_bytes());
b[16] = self.num_fats;
b[21] = self.media;
b[24..26].copy_from_slice(&self.sectors_per_track.to_le_bytes());
b[26..28].copy_from_slice(&self.num_heads.to_le_bytes());
b[28..32].copy_from_slice(&self.hidden_sectors.to_le_bytes());
b[32..36].copy_from_slice(&self.total_sectors.to_le_bytes());
b[36..40].copy_from_slice(&self.fat_size.to_le_bytes());
b[44..48].copy_from_slice(&self.root_cluster.to_le_bytes());
b[48..50].copy_from_slice(&self.fs_info_sector.to_le_bytes());
b[50..52].copy_from_slice(&self.backup_boot_sector.to_le_bytes());
b[64] = self.drive_number;
b[66] = 0x29; b[67..71].copy_from_slice(&self.volume_id.to_le_bytes());
b[71..82].copy_from_slice(&self.volume_label);
b[82..90].copy_from_slice(b"FAT32 ");
b[510] = 0x55;
b[511] = 0xAA;
b
}
pub fn decode(b: &[u8; BOOT_SECTOR_SIZE]) -> crate::Result<Self> {
if b[510] != 0x55 || b[511] != 0xAA {
return Err(crate::Error::InvalidImage(
"fat32: missing 0x55AA boot-sector signature".into(),
));
}
if &b[82..87] != b"FAT32" {
return Err(crate::Error::InvalidImage(
"fat32: fs_type is not \"FAT32\"".into(),
));
}
let mut volume_label = [0u8; 11];
volume_label.copy_from_slice(&b[71..82]);
Ok(Self {
bytes_per_sector: u16::from_le_bytes(b[11..13].try_into().unwrap()),
sectors_per_cluster: b[13],
reserved_sector_count: u16::from_le_bytes(b[14..16].try_into().unwrap()),
num_fats: b[16],
media: b[21],
sectors_per_track: u16::from_le_bytes(b[24..26].try_into().unwrap()),
num_heads: u16::from_le_bytes(b[26..28].try_into().unwrap()),
hidden_sectors: u32::from_le_bytes(b[28..32].try_into().unwrap()),
total_sectors: u32::from_le_bytes(b[32..36].try_into().unwrap()),
fat_size: u32::from_le_bytes(b[36..40].try_into().unwrap()),
root_cluster: u32::from_le_bytes(b[44..48].try_into().unwrap()),
fs_info_sector: u16::from_le_bytes(b[48..50].try_into().unwrap()),
backup_boot_sector: u16::from_le_bytes(b[50..52].try_into().unwrap()),
drive_number: b[64],
volume_id: u32::from_le_bytes(b[67..71].try_into().unwrap()),
volume_label,
})
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn roundtrip() {
let mut bs = BootSector::fat32_default();
bs.total_sectors = 131072;
bs.fat_size = 1009;
bs.volume_id = 0x1234_5678;
bs.volume_label = *b"REFVOL ";
let enc = bs.encode();
let dec = BootSector::decode(&enc).unwrap();
assert_eq!(dec.total_sectors, 131072);
assert_eq!(dec.fat_size, 1009);
assert_eq!(dec.root_cluster, 2);
assert_eq!(dec.reserved_sector_count, 32);
assert_eq!(dec.num_fats, 2);
assert_eq!(dec.volume_id, 0x1234_5678);
assert_eq!(&dec.volume_label, b"REFVOL ");
}
#[test]
fn data_start_and_cluster_count() {
let mut bs = BootSector::fat32_default();
bs.total_sectors = 131072;
bs.fat_size = 1009;
assert_eq!(bs.data_start_sector(), 2050);
assert_eq!(bs.cluster_count(), 129022);
}
#[test]
fn bad_signature_rejected() {
let buf = [0u8; BOOT_SECTOR_SIZE];
assert!(BootSector::decode(&buf).is_err());
}
}