2017-09-27 20:05:58 +08:00
|
|
|
use core::cell::RefCell;
|
2017-09-27 20:20:52 +08:00
|
|
|
use core::cmp;
|
2017-09-23 02:50:41 +08:00
|
|
|
use std::io::prelude::*;
|
2017-09-27 20:05:58 +08:00
|
|
|
use std::io::{Error, ErrorKind, SeekFrom};
|
2017-09-23 02:50:41 +08:00
|
|
|
use std::io;
|
|
|
|
use std::str;
|
|
|
|
use byteorder::{LittleEndian, ReadBytesExt};
|
2017-09-23 05:20:06 +08:00
|
|
|
|
2017-09-23 04:27:39 +08:00
|
|
|
use file::FatFile;
|
2017-09-27 20:05:58 +08:00
|
|
|
use dir::{FatDirReader, FatDir};
|
2017-09-28 06:11:24 +08:00
|
|
|
use table::FatTable;
|
2017-09-23 02:50:41 +08:00
|
|
|
|
|
|
|
// FAT implementation based on:
|
|
|
|
// http://wiki.osdev.org/FAT
|
|
|
|
// https://www.win.tue.nl/~aeb/linux/fs/fat/fat-1.html
|
|
|
|
|
|
|
|
#[derive(Debug, Copy, Clone, PartialEq)]
|
|
|
|
pub enum FatType {
|
|
|
|
Fat12, Fat16, Fat32, ExFat
|
|
|
|
}
|
|
|
|
|
2017-09-24 01:42:09 +08:00
|
|
|
pub trait ReadSeek: Read + Seek {}
|
|
|
|
impl<T> ReadSeek for T where T: Read + Seek {}
|
|
|
|
|
2017-09-27 20:05:58 +08:00
|
|
|
pub(crate) struct FatSharedState<'a> {
|
|
|
|
pub(crate) rdr: &'a mut ReadSeek,
|
|
|
|
pub(crate) fat_type: FatType,
|
|
|
|
pub(crate) boot: FatBootRecord,
|
|
|
|
pub(crate) first_data_sector: u32,
|
|
|
|
pub(crate) root_dir_sectors: u32,
|
2017-09-28 06:11:24 +08:00
|
|
|
pub(crate) table: FatTable,
|
2017-09-24 01:42:09 +08:00
|
|
|
}
|
|
|
|
|
2017-09-27 20:05:58 +08:00
|
|
|
impl <'a> FatSharedState<'a> {
|
2017-09-24 01:42:09 +08:00
|
|
|
pub(crate) fn offset_from_sector(&self, sector: u32) -> u64 {
|
|
|
|
(sector as u64) * self.boot.bpb.bytes_per_sector as u64
|
|
|
|
}
|
|
|
|
|
|
|
|
pub(crate) fn sector_from_cluster(&self, cluster: u32) -> u32 {
|
|
|
|
((cluster - 2) * self.boot.bpb.sectors_per_cluster as u32) + self.first_data_sector
|
|
|
|
}
|
|
|
|
|
|
|
|
pub(crate) fn get_cluster_size(&self) -> u32 {
|
|
|
|
self.boot.bpb.sectors_per_cluster as u32 * self.boot.bpb.bytes_per_sector as u32
|
|
|
|
}
|
|
|
|
|
2017-09-24 02:16:32 +08:00
|
|
|
pub(crate) fn offset_from_cluster(&self, cluser: u32) -> u64 {
|
|
|
|
self.offset_from_sector(self.sector_from_cluster(cluser))
|
2017-09-24 01:42:09 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-09-23 02:50:41 +08:00
|
|
|
#[allow(dead_code)]
|
2017-09-24 09:08:00 +08:00
|
|
|
#[derive(Default, Debug, Clone)]
|
2017-09-23 02:50:41 +08:00
|
|
|
pub(crate) struct FatBiosParameterBlock {
|
|
|
|
bytes_per_sector: u16,
|
|
|
|
sectors_per_cluster: u8,
|
|
|
|
reserved_sector_count: u16,
|
|
|
|
table_count: u8,
|
|
|
|
root_entry_count: u16,
|
|
|
|
total_sectors_16: u16,
|
|
|
|
media_type: u8,
|
|
|
|
table_size_16: u16,
|
|
|
|
sectors_per_track: u16,
|
|
|
|
head_side_count: u16,
|
|
|
|
hidden_sector_count: u32,
|
|
|
|
total_sectors_32: u32,
|
|
|
|
|
|
|
|
// Extended BIOS Parameter Block
|
|
|
|
table_size_32: u32,
|
|
|
|
extended_flags: u16,
|
|
|
|
fat_version: u16,
|
|
|
|
root_cluster: u32,
|
|
|
|
fat_info: u16,
|
|
|
|
backup_bs_sector: u16,
|
|
|
|
reserved_0: [u8; 12],
|
|
|
|
drive_num: u8,
|
|
|
|
reserved_1: u8,
|
|
|
|
ext_sig: u8,
|
|
|
|
volume_id: u32,
|
|
|
|
volume_label: [u8; 11],
|
|
|
|
fat_type_label: [u8; 8],
|
|
|
|
}
|
|
|
|
|
|
|
|
#[allow(dead_code)]
|
|
|
|
pub(crate) struct FatBootRecord {
|
|
|
|
bootjmp: [u8; 3],
|
|
|
|
oem_name: [u8; 8],
|
|
|
|
bpb: FatBiosParameterBlock,
|
|
|
|
boot_code: [u8; 448],
|
|
|
|
boot_sig: [u8; 2],
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Default for FatBootRecord {
|
|
|
|
fn default() -> FatBootRecord {
|
|
|
|
FatBootRecord {
|
|
|
|
bootjmp: Default::default(),
|
|
|
|
oem_name: Default::default(),
|
|
|
|
bpb: Default::default(),
|
|
|
|
boot_code: [0; 448],
|
|
|
|
boot_sig: Default::default(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-09-27 20:05:58 +08:00
|
|
|
pub(crate) type FatSharedStateCell<'a> = RefCell<FatSharedState<'a>>;
|
|
|
|
pub(crate) type FatSharedStateRef<'a, 'b: 'a> = &'a RefCell<FatSharedState<'b>>;
|
|
|
|
|
|
|
|
pub struct FatFileSystem<'a> {
|
|
|
|
pub(crate) state: FatSharedStateCell<'a>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl <'a> FatFileSystem<'a> {
|
2017-09-23 02:50:41 +08:00
|
|
|
|
2017-09-27 20:05:58 +08:00
|
|
|
pub fn new<T: ReadSeek>(mut rdr: &'a mut T) -> io::Result<FatFileSystem<'a>> {
|
2017-09-24 01:42:09 +08:00
|
|
|
let boot = Self::read_boot_record(&mut *rdr)?;
|
2017-09-23 02:50:41 +08:00
|
|
|
if boot.boot_sig != [0x55, 0xAA] {
|
2017-09-27 20:05:58 +08:00
|
|
|
return Err(Error::new(ErrorKind::Other, "invBox::newalid signature"));
|
2017-09-23 02:50:41 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
let total_sectors = if boot.bpb.total_sectors_16 == 0 { boot.bpb.total_sectors_32 } else { boot.bpb.total_sectors_16 as u32 };
|
|
|
|
let table_size = if boot.bpb.table_size_16 == 0 { boot.bpb.table_size_32 } else { boot.bpb.table_size_16 as u32 };
|
2017-09-24 09:08:00 +08:00
|
|
|
let root_dir_sectors = (((boot.bpb.root_entry_count * 32) + (boot.bpb.bytes_per_sector - 1)) / boot.bpb.bytes_per_sector) as u32;
|
|
|
|
let first_data_sector = boot.bpb.reserved_sector_count as u32 + (boot.bpb.table_count as u32 * table_size) + root_dir_sectors;
|
2017-09-23 02:50:41 +08:00
|
|
|
let data_sectors = total_sectors - (boot.bpb.reserved_sector_count as u32 + (boot.bpb.table_count as u32 * table_size) + root_dir_sectors as u32);
|
|
|
|
let total_clusters = data_sectors / boot.bpb.sectors_per_cluster as u32;
|
2017-09-24 01:42:09 +08:00
|
|
|
let fat_type = Self::fat_type_from_clusters(total_clusters);
|
2017-09-23 02:50:41 +08:00
|
|
|
|
2017-09-24 04:22:25 +08:00
|
|
|
let fat_offset = boot.bpb.reserved_sector_count * boot.bpb.bytes_per_sector;
|
|
|
|
rdr.seek(SeekFrom::Start(fat_offset as u64))?;
|
2017-09-23 20:16:02 +08:00
|
|
|
let table_size_bytes = table_size * boot.bpb.bytes_per_sector as u32;
|
2017-09-28 06:11:24 +08:00
|
|
|
let table = FatTable::from_read(rdr, fat_type, table_size_bytes as usize)?;
|
2017-09-23 20:16:02 +08:00
|
|
|
|
2017-09-24 01:42:09 +08:00
|
|
|
let state = FatSharedState {
|
2017-09-24 09:08:00 +08:00
|
|
|
rdr,
|
|
|
|
fat_type,
|
|
|
|
boot,
|
|
|
|
first_data_sector,
|
|
|
|
root_dir_sectors,
|
|
|
|
table,
|
2017-09-23 02:50:41 +08:00
|
|
|
};
|
|
|
|
|
2017-09-24 01:42:09 +08:00
|
|
|
Ok(FatFileSystem {
|
2017-09-27 20:05:58 +08:00
|
|
|
state: RefCell::new(state),
|
2017-09-24 01:42:09 +08:00
|
|
|
})
|
2017-09-23 02:50:41 +08:00
|
|
|
}
|
|
|
|
|
2017-09-25 04:12:38 +08:00
|
|
|
pub fn fat_type(&self) -> FatType {
|
2017-09-24 09:08:00 +08:00
|
|
|
self.state.borrow().fat_type
|
|
|
|
}
|
|
|
|
|
2017-09-25 04:12:38 +08:00
|
|
|
pub fn volume_id(&self) -> u32 {
|
2017-09-24 09:08:00 +08:00
|
|
|
self.state.borrow().boot.bpb.volume_id
|
|
|
|
}
|
|
|
|
|
2017-09-25 04:12:38 +08:00
|
|
|
pub fn volume_label(&self) -> String {
|
2017-09-24 09:08:00 +08:00
|
|
|
str::from_utf8(&self.state.borrow().boot.bpb.volume_label).unwrap().trim_right().to_string()
|
|
|
|
}
|
|
|
|
|
2017-09-27 20:05:58 +08:00
|
|
|
pub fn root_dir<'b>(&'b self) -> FatDir<'b, 'a> {
|
|
|
|
let root_rdr = {
|
|
|
|
let state = self.state.borrow();
|
|
|
|
match state.fat_type {
|
|
|
|
FatType::Fat12 | FatType::Fat16 => FatDirReader::Root(FatSlice::from_sectors(
|
|
|
|
state.first_data_sector - state.root_dir_sectors, state.root_dir_sectors, &self.state)),
|
|
|
|
_ => FatDirReader::File(FatFile::new(state.boot.bpb.root_cluster, None, &self.state)),
|
|
|
|
}
|
2017-09-24 09:08:00 +08:00
|
|
|
};
|
2017-09-27 20:05:58 +08:00
|
|
|
FatDir::new(root_rdr, &self.state)
|
2017-09-24 09:08:00 +08:00
|
|
|
}
|
|
|
|
|
2017-09-23 02:50:41 +08:00
|
|
|
fn read_bpb(rdr: &mut Read) -> io::Result<FatBiosParameterBlock> {
|
|
|
|
let mut bpb: FatBiosParameterBlock = Default::default();
|
|
|
|
bpb.bytes_per_sector = rdr.read_u16::<LittleEndian>()?;
|
|
|
|
bpb.sectors_per_cluster = rdr.read_u8()?;
|
|
|
|
bpb.reserved_sector_count = rdr.read_u16::<LittleEndian>()?;
|
|
|
|
bpb.table_count = rdr.read_u8()?;
|
|
|
|
bpb.root_entry_count = rdr.read_u16::<LittleEndian>()? ;
|
|
|
|
bpb.total_sectors_16 = rdr.read_u16::<LittleEndian>()?;
|
|
|
|
bpb.media_type = rdr.read_u8()?;
|
|
|
|
bpb.table_size_16 = rdr.read_u16::<LittleEndian>()?;
|
|
|
|
bpb.sectors_per_track = rdr.read_u16::<LittleEndian>()?;
|
|
|
|
bpb.head_side_count = rdr.read_u16::<LittleEndian>()?;
|
|
|
|
bpb.hidden_sector_count = rdr.read_u32::<LittleEndian>()?; // hidden_sector_count
|
|
|
|
bpb.total_sectors_32 = rdr.read_u32::<LittleEndian>()?;
|
|
|
|
|
|
|
|
if bpb.table_size_16 == 0 {
|
|
|
|
bpb.table_size_32 = rdr.read_u32::<LittleEndian>()?;
|
|
|
|
bpb.extended_flags = rdr.read_u16::<LittleEndian>()?;
|
|
|
|
bpb.fat_version = rdr.read_u16::<LittleEndian>()?;
|
|
|
|
bpb.root_cluster = rdr.read_u32::<LittleEndian>()?;
|
|
|
|
bpb.fat_info = rdr.read_u16::<LittleEndian>()?;
|
|
|
|
bpb.backup_bs_sector = rdr.read_u16::<LittleEndian>()?;
|
|
|
|
rdr.read(&mut bpb.reserved_0)?;
|
|
|
|
bpb.drive_num = rdr.read_u8()?;
|
|
|
|
bpb.reserved_1 = rdr.read_u8()?;
|
|
|
|
bpb.ext_sig = rdr.read_u8()?; // 0x29
|
|
|
|
bpb.volume_id = rdr.read_u32::<LittleEndian>()?;
|
|
|
|
rdr.read(&mut bpb.volume_label)?;
|
|
|
|
rdr.read(&mut bpb.fat_type_label)?;
|
|
|
|
//bpb.boot_code = Vec::with_capacity(420);
|
|
|
|
//rdr.read_exact(bpb.boot_code.as_mut_slice())?;
|
|
|
|
} else {
|
|
|
|
bpb.drive_num = rdr.read_u8()?;
|
|
|
|
bpb.reserved_1 = rdr.read_u8()?;
|
|
|
|
bpb.ext_sig = rdr.read_u8()?; // 0x29
|
|
|
|
bpb.volume_id = rdr.read_u32::<LittleEndian>()?;
|
|
|
|
rdr.read(&mut bpb.volume_label)?;
|
|
|
|
rdr.read(&mut bpb.fat_type_label)?;
|
|
|
|
//bpb.boot_code = Vec::with_capacity(448);
|
|
|
|
//rdr.read_exact(bpb.boot_code.as_mut_slice())?;
|
|
|
|
}
|
|
|
|
Ok(bpb)
|
|
|
|
}
|
|
|
|
|
2017-09-24 01:42:09 +08:00
|
|
|
fn fat_type_from_clusters(total_clusters: u32) -> FatType {
|
|
|
|
if total_clusters < 4085 {
|
|
|
|
FatType::Fat12
|
|
|
|
} else if total_clusters < 65525 {
|
|
|
|
FatType::Fat16
|
|
|
|
} else if total_clusters < 268435445 {
|
|
|
|
FatType::Fat32
|
|
|
|
} else {
|
|
|
|
FatType::ExFat
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-09-23 02:50:41 +08:00
|
|
|
fn read_boot_record(rdr: &mut Read) -> io::Result<FatBootRecord> {
|
|
|
|
let mut boot: FatBootRecord = Default::default();
|
|
|
|
rdr.read(&mut boot.bootjmp)?;
|
|
|
|
rdr.read(&mut boot.oem_name)?;
|
2017-09-24 01:42:09 +08:00
|
|
|
boot.bpb = Self::read_bpb(rdr)?;
|
2017-09-23 02:50:41 +08:00
|
|
|
|
|
|
|
if boot.bpb.table_size_16 == 0 {
|
|
|
|
rdr.read_exact(&mut boot.boot_code[0..420])?;
|
|
|
|
} else {
|
|
|
|
rdr.read_exact(&mut boot.boot_code[0..448])?;
|
|
|
|
}
|
|
|
|
rdr.read(&mut boot.boot_sig)?;
|
|
|
|
Ok(boot)
|
|
|
|
}
|
2017-09-24 01:42:09 +08:00
|
|
|
}
|
|
|
|
|
2017-09-27 20:05:58 +08:00
|
|
|
pub(crate) struct FatSlice<'a, 'b: 'a> {
|
2017-09-24 01:42:09 +08:00
|
|
|
begin: u64,
|
|
|
|
size: u64,
|
|
|
|
offset: u64,
|
2017-09-27 20:05:58 +08:00
|
|
|
state: FatSharedStateRef<'a, 'b>,
|
2017-09-24 01:42:09 +08:00
|
|
|
}
|
|
|
|
|
2017-09-27 20:05:58 +08:00
|
|
|
impl <'a, 'b> FatSlice<'a, 'b> {
|
|
|
|
pub(crate) fn new(begin: u64, size: u64, state: FatSharedStateRef<'a, 'b>) -> Self {
|
2017-09-24 01:42:09 +08:00
|
|
|
FatSlice { begin, size, state, offset: 0 }
|
2017-09-23 06:22:31 +08:00
|
|
|
}
|
|
|
|
|
2017-09-27 20:05:58 +08:00
|
|
|
pub(crate) fn from_sectors(first_sector: u32, sectors_count: u32, state: FatSharedStateRef<'a, 'b>) -> Self {
|
2017-09-24 01:42:09 +08:00
|
|
|
let bytes_per_sector = state.borrow().boot.bpb.bytes_per_sector as u64;
|
|
|
|
Self::new(first_sector as u64 * bytes_per_sector, sectors_count as u64 * bytes_per_sector, state)
|
2017-09-23 04:27:39 +08:00
|
|
|
}
|
2017-09-24 01:42:09 +08:00
|
|
|
}
|
2017-09-23 04:27:39 +08:00
|
|
|
|
2017-09-27 20:05:58 +08:00
|
|
|
impl <'a, 'b> Read for FatSlice<'a, 'b> {
|
2017-09-24 01:42:09 +08:00
|
|
|
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
2017-09-24 02:16:32 +08:00
|
|
|
let offset = self.begin + self.offset;
|
|
|
|
let read_size = cmp::min((self.size - self.offset) as usize, buf.len());
|
2017-09-24 01:42:09 +08:00
|
|
|
let mut state = self.state.borrow_mut();
|
|
|
|
state.rdr.seek(SeekFrom::Start(offset))?;
|
|
|
|
let size = state.rdr.read(&mut buf[..read_size])?;
|
|
|
|
self.offset += size as u64;
|
|
|
|
Ok(size)
|
2017-09-23 02:50:41 +08:00
|
|
|
}
|
|
|
|
}
|
2017-09-24 08:10:59 +08:00
|
|
|
|
2017-09-27 20:05:58 +08:00
|
|
|
impl <'a, 'b> Seek for FatSlice<'a, 'b> {
|
2017-09-24 08:10:59 +08:00
|
|
|
fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
|
|
|
|
let new_offset = match pos {
|
|
|
|
SeekFrom::Current(x) => self.offset as i64 + x,
|
|
|
|
SeekFrom::Start(x) => x as i64,
|
|
|
|
SeekFrom::End(x) => self.size as i64 + x,
|
|
|
|
};
|
|
|
|
if new_offset < 0 || new_offset as u64 > self.size {
|
|
|
|
Err(io::Error::new(ErrorKind::InvalidInput, "invalid seek"))
|
|
|
|
} else {
|
|
|
|
self.offset = new_offset as u64;
|
|
|
|
Ok(self.offset)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|