use {std, memmap};
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum FATType {
FAT12,
FAT16,
FAT32
}
#[derive(Default, Debug)]
pub struct FAT {
mmap: Option<memmap::Mmap>,
ftype: Option<FATType>,
boot_sector: BootSector,
bios_parameter_block: BiosParameterBlock,
count_of_clusters: usize,
fat_sz: usize,
tot_sec: usize
}
#[derive(Default, Debug)]
pub struct BootSector {
jmp: [u8; 3],
oem_name: [u8; 8]
}
#[derive(Default, Debug)]
pub struct BiosParameterBlock {
bytes_per_sec: u16, sec_per_clus: u8, rsvd_sec_cnt: u16, num_fats: u8, root_ent_cnt: u16, tot_sec_16: u16, media: u8,
fat_sz_16: u16,
tot_sec_32: usize
}
impl FAT {
pub fn new(file: &std::fs::File) -> super::Result<FAT> {
let mmap = unsafe {
memmap::MmapOptions::new().map(file).map_err(super::error::Error::IOError)?
};
if mmap.len() >= 512 {
let mut fat = FAT {
mmap: Some(mmap),
..FAT::default()
};
fat.parse_boot_record()?;
Ok(fat)
} else {
Err(super::error::Error::InvalidFATFormat)
}
}
pub fn from_path(path: &str) -> super::Result<FAT> {
let file = std::fs::File::open(path).map_err(super::error::Error::IOError)?;
FAT::new(&file)
}
fn parse_boot_record(&mut self) -> super::Result<()> {
use super::util::FromSlice;
let mmap = self.mmap.as_ref().unwrap();
let bpb = &mut self.bios_parameter_block;
let bs = &mut self.boot_sector;
bs.jmp.copy_from_slice(&mmap[0x00 .. 0x03]);
if (bs.jmp[0x00] == 0xEB && bs.jmp[0x02] != 0x90)
|| (bs.jmp[0x00] != 0xEB && bs.jmp[0x00] != 0xE9) {
return Err(super::error::Error::InvalidFATFormat);
}
bs.oem_name.copy_from_slice(&mmap[0x03 .. 0x0B]);
bpb.bytes_per_sec = u16::from_slice(&mmap[0x0B .. 0x0D]);
bpb.sec_per_clus = mmap[0x0D];
bpb.rsvd_sec_cnt = u16::from_slice(&mmap[0x0E .. 0x10]);
bpb.num_fats = mmap[0x10];
bpb.root_ent_cnt = u16::from_slice(&mmap[0x11 .. 0x13]);
bpb.tot_sec_16 = u16::from_slice(&mmap[0x13 .. 0x15]);
bpb.tot_sec_32 = usize::from_slice(&mmap[0x20 .. 0x24]);
if bpb.tot_sec_16 == 0 && bpb.tot_sec_32 == 0 {
return Err(super::error::Error::InvalidFATFormat);
}
bpb.media = mmap[0x15];
if bpb.media < 0xF8 && bpb.media != 0xF0 {
return Err(super::error::Error::InvalidFATFormat);
}
bpb.fat_sz_16 = u16::from_slice(&mmap[0x16 .. 0x18]);
let rds = ((bpb.root_ent_cnt * 32) + (bpb.bytes_per_sec -1))
/ bpb.bytes_per_sec;
self.fat_sz = if bpb.fat_sz_16 != 0 {
bpb.fat_sz_16 as usize
} else {
usize::from_slice(&mmap[0x24 .. 0x28])
};
self.tot_sec = if bpb.tot_sec_16 != 0 {
bpb.tot_sec_16 as usize
} else {
bpb.tot_sec_32
};
let data_sec = self.tot_sec - (bpb.rsvd_sec_cnt as usize
+ ((bpb.num_fats as usize * self.fat_sz) as usize) + (rds as usize)) as usize;
self.count_of_clusters = data_sec / (bpb.sec_per_clus as usize);
self.ftype = if self.count_of_clusters < 4085 {
Some(FATType::FAT12)
} else if self.count_of_clusters < 65525 {
Some(FATType::FAT16)
} else {
Some(FATType::FAT32)
};
Ok(())
}
pub fn ftype(&self) -> FATType {
*self.ftype.as_ref().unwrap()
}
}