1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
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, // 2 bytes
  sec_per_clus: u8, // 1 byte
  rsvd_sec_cnt: u16, // 2 bytes
  num_fats: u8, // 1 byte
  root_ent_cnt: u16, // 2 bytes
  tot_sec_16: u16, // 2 bytes
  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()
  }
}