diff --git a/src/dir.rs b/src/dir.rs new file mode 100644 index 0000000..d6c33f6 --- /dev/null +++ b/src/dir.rs @@ -0,0 +1,120 @@ +use std::fs::File; +use std::io::prelude::*; +use std::io::BufReader; +use std::io; +use std::str; +use std::io::{Error, ErrorKind, SeekFrom}; +use byteorder::{LittleEndian, ReadBytesExt}; +use fs::{FatFileSystem, FatType}; + +#[derive(Debug, PartialEq)] +#[allow(dead_code)] +enum FatFileAttribute { + READ_ONLY = 0x01, + HIDDEN = 0x02, + SYSTEM = 0x04, + VOLUME_ID = 0x08, + DIRECTORY = 0x10, + ARCHIVE = 0x20, + LFN = 0x0F, +} + +#[allow(dead_code)] +pub struct FatDirEntry { + name: [u8; 11], + attrs: u8, + reserved_0: u8, + creation_time_0: u8, + creation_time_1: u16, + creation_date: u16, + access_date: u16, + first_cluster_hi: u16, + mod_time: u16, + mod_date: u16, + first_cluster_lo: u16, + size: u32, +} + +pub struct FatDir { + cluster: u32, +} + +impl FatDir { + pub fn new(cluster: u32) -> FatDir { + FatDir { + cluster: cluster, + } + } +} + +trait DirEntry { + fn get_name(&self) -> str; +} + +trait ReadDir { + fn read_dir(&mut self, dir: &FatDir) -> io::Result>; +} + +impl FatFileSystem { + pub fn read_dir(&mut self, dir: FatDir) -> io::Result> { + let mut entries = Vec::new(); + loop { + let entry = read_dir_entry(&mut self.rdr)?; + if entry.name[0] == 0 { + break; // end of dir + } + if entry.name[0] == 0xE5 { + continue; // deleted + } + let name_str = str::from_utf8(&entry.name).unwrap().trim_right(); + println!("name {} size {} cluster {}", name_str, entry.size, entry.first_cluster_lo); + } + Ok(entries) + } +} + +fn read_dir_entry(rdr: &mut Read) -> io::Result { + let mut name = [0; 11]; + rdr.read(&mut name)?; + Ok(FatDirEntry { + name: name, + attrs: rdr.read_u8()?, + reserved_0: rdr.read_u8()?, + creation_time_0: rdr.read_u8()?, + creation_time_1: rdr.read_u16::()?, + creation_date: rdr.read_u16::()?, + access_date: rdr.read_u16::()?, + first_cluster_hi: rdr.read_u16::()?, + mod_time: rdr.read_u16::()?, + mod_date: rdr.read_u16::()?, + first_cluster_lo: rdr.read_u16::()?, + size: rdr.read_u32::()?, + }) +} + +// impl FatDir { +// pub fn new(rdr: &mut Read) -> io::Result { +// let dir = FatDir { +// entries: Vec::new(), +// }; +// read_dir_entry(rdr)?; +// Ok(dir) +// } +// +// pub fn print(&mut self) -> io::Result<()> { +// //let pos = self.rdr.seek(SeekFrom::Current(0))?; +// //println!("Reading dir at {}", pos); +// loop { +// let entry = self.read_dir_entry()?; +// if entry.name[0] == 0 { +// break; // end of dir +// } +// if entry.name[0] == 0xE5 { +// continue; // deleted +// } +// let name_str = str::from_utf8(&entry.name).unwrap().trim_right(); +// println!("name {} size {} cluster {}", name_str, entry.size, entry.first_cluster_lo); +// } +// Ok(()) +// } +// } diff --git a/src/fs.rs b/src/fs.rs new file mode 100644 index 0000000..cf0c402 --- /dev/null +++ b/src/fs.rs @@ -0,0 +1,209 @@ +use std::fs::File; +use std::io::prelude::*; +use std::io::BufReader; +use std::io; +use std::str; +use std::io::{Error, ErrorKind, SeekFrom}; +use byteorder::{LittleEndian, ReadBytesExt}; +use dir::FatDir; + +// 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 +} + +pub struct FatFileSystem { + pub(crate) rdr: T, + pub(crate) fat_type: FatType, + pub(crate) boot: FatBootRecord, + pub(crate) first_fat_sector: u32, + pub(crate) first_data_sector: u32, + pub(crate) root_dir_sectors: u32, +} + +#[allow(dead_code)] +#[derive(Default, Debug)] +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(), + } + } +} + +impl FatFileSystem { + 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 + } + } + + pub fn new(rdr: &mut T) -> io::Result> { + let boot = FatFileSystem::::read_boot_record(rdr)?; + if boot.boot_sig != [0x55, 0xAA] { + return Err(Error::new(ErrorKind::Other, "invalid signature")); + } + + 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 }; + let root_dir_sectors = ((boot.bpb.root_entry_count * 32) + (boot.bpb.bytes_per_sector - 1)) / (boot.bpb.bytes_per_sector); + let first_data_sector = boot.bpb.reserved_sector_count as u32 + (boot.bpb.table_count as u32 * table_size) + root_dir_sectors as u32; + let first_fat_sector = boot.bpb.reserved_sector_count as u32; + 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; + let fat_type = FatFileSystem::::fat_type_from_clusters(total_clusters); + + { + let oem_name_str = str::from_utf8(&boot.oem_name).unwrap().trim_right(); + let volume_label_str = str::from_utf8(&boot.bpb.volume_label).unwrap().trim_right(); + let fat_type_label_str = str::from_utf8(&boot.bpb.fat_type_label).unwrap().trim_right(); + + println!("fat_type {:?}", fat_type); + println!("volume_id {}", boot.bpb.volume_id); + println!("oem_name {}", oem_name_str); + println!("volume_label {}", volume_label_str); + println!("fat_type_label {}", fat_type_label_str); + } + + let fs = FatFileSystem { + rdr: rdr, + fat_type: fat_type, + boot: boot, + first_data_sector: first_data_sector, + first_fat_sector: first_fat_sector, + root_dir_sectors: root_dir_sectors as u32, + }; + + Ok(fs) + } + + fn read_bpb(rdr: &mut Read) -> io::Result { + let mut bpb: FatBiosParameterBlock = Default::default(); + bpb.bytes_per_sector = rdr.read_u16::()?; + bpb.sectors_per_cluster = rdr.read_u8()?; + bpb.reserved_sector_count = rdr.read_u16::()?; + bpb.table_count = rdr.read_u8()?; + bpb.root_entry_count = rdr.read_u16::()? ; + bpb.total_sectors_16 = rdr.read_u16::()?; + bpb.media_type = rdr.read_u8()?; + bpb.table_size_16 = rdr.read_u16::()?; + bpb.sectors_per_track = rdr.read_u16::()?; + bpb.head_side_count = rdr.read_u16::()?; + bpb.hidden_sector_count = rdr.read_u32::()?; // hidden_sector_count + bpb.total_sectors_32 = rdr.read_u32::()?; + + if bpb.table_size_16 == 0 { + bpb.table_size_32 = rdr.read_u32::()?; + bpb.extended_flags = rdr.read_u16::()?; + bpb.fat_version = rdr.read_u16::()?; + bpb.root_cluster = rdr.read_u32::()?; + bpb.fat_info = rdr.read_u16::()?; + bpb.backup_bs_sector = rdr.read_u16::()?; + 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::()?; + 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::()?; + 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) + } + + fn read_boot_record(rdr: &mut Read) -> io::Result { + let mut boot: FatBootRecord = Default::default(); + rdr.read(&mut boot.bootjmp)?; + rdr.read(&mut boot.oem_name)?; + boot.bpb = FatFileSystem::::read_bpb(rdr)?; + + 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) + } + + pub fn seek_to_sector(&mut self, sector: u64) -> io::Result<()> { + self.rdr.seek(SeekFrom::Start(sector*512))?; + Ok(()) + } + + pub fn sector_from_cluster(&self, cluster: u32) -> u32 { + ((cluster - 2) * self.boot.bpb.sectors_per_cluster as u32) + self.first_data_sector + } + + pub fn open_root_dir(&mut self) -> io::Result { + let first_root_dir_sector = match self.fat_type { + FatType::Fat12 | FatType::Fat16 => self.first_data_sector - self.root_dir_sectors, + _ => self.sector_from_cluster(self.boot.bpb.root_cluster) + }; + self.seek_to_sector(first_root_dir_sector as u64)?; + Ok(FatDir::new(0)) + } +} diff --git a/src/main.rs b/src/main.rs index 0d0bfe1..1222c10 100644 --- a/src/main.rs +++ b/src/main.rs @@ -7,279 +7,17 @@ use std::io; use std::str; use std::io::{Error, ErrorKind, SeekFrom}; use byteorder::{LittleEndian, ReadBytesExt}; +use fs::FatFileSystem; -// 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)] -enum FatType { - Fat12, Fat16, Fat32, ExFat -} - -struct FatFileSystem { - rdr: T, - fat_type: FatType, - boot: FatBootRecord, - first_fat_sector: u32, - first_data_sector: u32, - root_dir_sectors: u32, -} - -#[derive(Debug, PartialEq)] -#[allow(dead_code)] -enum FatFileAttribute { - READ_ONLY = 0x01, - HIDDEN = 0x02, - SYSTEM = 0x04, - VOLUME_ID = 0x08, - DIRECTORY = 0x10, - ARCHIVE = 0x20, - LFN = 0x0F, -} - -#[allow(dead_code)] -#[derive(Default, Debug)] -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)] -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(), - } - } -} - -#[allow(dead_code)] -struct FatDirEntry { - name: [u8; 11], - attrs: u8, - reserved_0: u8, - creation_time_0: u8, - creation_time_1: u16, - creation_date: u16, - access_date: u16, - first_cluster_hi: u16, - mod_time: u16, - mod_date: u16, - first_cluster_lo: u16, - size: u32, -} - -impl FatFileSystem { - 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 - } - } - - pub fn new(rdr: &mut T) -> io::Result> { - let boot = FatFileSystem::::read_boot_record(rdr)?; - if boot.boot_sig != [0x55, 0xAA] { - return Err(Error::new(ErrorKind::Other, "invalid signature")); - } - - 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 }; - let root_dir_sectors = ((boot.bpb.root_entry_count * 32) + (boot.bpb.bytes_per_sector - 1)) / (boot.bpb.bytes_per_sector); - let first_data_sector = boot.bpb.reserved_sector_count as u32 + (boot.bpb.table_count as u32 * table_size) + root_dir_sectors as u32; - let first_fat_sector = boot.bpb.reserved_sector_count as u32; - 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; - let fat_type = FatFileSystem::::fat_type_from_clusters(total_clusters); - - { - let oem_name_str = str::from_utf8(&boot.oem_name).unwrap().trim_right(); - let volume_label_str = str::from_utf8(&boot.bpb.volume_label).unwrap().trim_right(); - let fat_type_label_str = str::from_utf8(&boot.bpb.fat_type_label).unwrap().trim_right(); - - println!("fat_type {:?}", fat_type); - println!("volume_id {}", boot.bpb.volume_id); - println!("oem_name {}", oem_name_str); - println!("volume_label {}", volume_label_str); - println!("fat_type_label {}", fat_type_label_str); - } - - let fs = FatFileSystem { - rdr: rdr, - fat_type: fat_type, - boot: boot, - first_data_sector: first_data_sector, - first_fat_sector: first_fat_sector, - root_dir_sectors: root_dir_sectors as u32, - }; - - - Ok(fs) - } - - fn read_bpb(rdr: &mut Read) -> io::Result { - let mut bpb: FatBiosParameterBlock = Default::default(); - bpb.bytes_per_sector = rdr.read_u16::()?; - bpb.sectors_per_cluster = rdr.read_u8()?; - bpb.reserved_sector_count = rdr.read_u16::()?; - bpb.table_count = rdr.read_u8()?; - bpb.root_entry_count = rdr.read_u16::()? ; - bpb.total_sectors_16 = rdr.read_u16::()?; - bpb.media_type = rdr.read_u8()?; - bpb.table_size_16 = rdr.read_u16::()?; - bpb.sectors_per_track = rdr.read_u16::()?; - bpb.head_side_count = rdr.read_u16::()?; - bpb.hidden_sector_count = rdr.read_u32::()?; // hidden_sector_count - bpb.total_sectors_32 = rdr.read_u32::()?; - - if bpb.table_size_16 == 0 { - bpb.table_size_32 = rdr.read_u32::()?; - bpb.extended_flags = rdr.read_u16::()?; - bpb.fat_version = rdr.read_u16::()?; - bpb.root_cluster = rdr.read_u32::()?; - bpb.fat_info = rdr.read_u16::()?; - bpb.backup_bs_sector = rdr.read_u16::()?; - 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::()?; - 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::()?; - 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) - } - - fn read_boot_record(rdr: &mut Read) -> io::Result { - let mut boot: FatBootRecord = Default::default(); - rdr.read(&mut boot.bootjmp)?; - rdr.read(&mut boot.oem_name)?; - boot.bpb = FatFileSystem::::read_bpb(rdr)?; - - 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) - } - - fn seek_to_sector(&mut self, sector: u64) -> io::Result<()> { - self.rdr.seek(SeekFrom::Start(sector*512))?; - Ok(()) - } - - fn sector_from_cluster(&self, cluster: u32) -> u32 { - ((cluster - 2) * self.boot.bpb.sectors_per_cluster as u32) + self.first_data_sector - } - - fn read_dir_entry(&mut self) -> io::Result { - let mut name = [0; 11]; - self.rdr.read(&mut name)?; - Ok(FatDirEntry { - name: name, - attrs: self.rdr.read_u8()?, - reserved_0: self.rdr.read_u8()?, - creation_time_0: self.rdr.read_u8()?, - creation_time_1: self.rdr.read_u16::()?, - creation_date: self.rdr.read_u16::()?, - access_date: self.rdr.read_u16::()?, - first_cluster_hi: self.rdr.read_u16::()?, - mod_time: self.rdr.read_u16::()?, - mod_date: self.rdr.read_u16::()?, - first_cluster_lo: self.rdr.read_u16::()?, - size: self.rdr.read_u32::()?, - }) - } - - fn read_dir(&mut self) -> io::Result<()> { - let pos = self.rdr.seek(SeekFrom::Current(0))?; - println!("Reading dir at {}", pos); - loop { - let entry = self.read_dir_entry()?; - if entry.name[0] == 0 { - break; // end of dir - } - if entry.name[0] == 0xE5 { - continue; // deleted - } - let name_str = str::from_utf8(&entry.name).unwrap().trim_right(); - println!("name {} size {} cluster {}", name_str, entry.size, entry.first_cluster_lo); - } - Ok(()) - } - - pub fn read_root_dir(&mut self) -> io::Result<()> { - let first_root_dir_sector = match self.fat_type { - FatType::Fat12 | FatType::Fat16 => self.first_data_sector - self.root_dir_sectors, - _ => self.sector_from_cluster(self.boot.bpb.root_cluster) - }; - self.seek_to_sector(first_root_dir_sector as u64)?; - self.read_dir()?; - Ok(()) - } -} +mod fs; +mod dir; fn fat_test() -> io::Result<()> { let file = File::open("resources/floppy.img")?; let mut buf_rdr = BufReader::new(file); let mut fs = FatFileSystem::new(&mut buf_rdr)?; - fs.read_root_dir()?; + let root_dir = fs.open_root_dir()?; + fs.read_dir(root_dir)?; Ok(()) }