From bc835d59b5f2dd8315435da9a46fabf7688e251f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Harabie=C5=84?= Date: Wed, 4 Oct 2017 13:56:44 +0200 Subject: [PATCH] Don't use boxed buffer in FAT cluster reading code. I assume gived Read object is capable of basic buffering and caching. --- src/dir.rs | 20 +++--- src/file.rs | 27 ++++---- src/fs.rs | 113 ++++++++++++++++----------------- src/table.rs | 174 +++++++++++++++++---------------------------------- 4 files changed, 132 insertions(+), 202 deletions(-) diff --git a/src/dir.rs b/src/dir.rs index f104679..cb6c879 100644 --- a/src/dir.rs +++ b/src/dir.rs @@ -7,7 +7,7 @@ use std::str; use byteorder::{LittleEndian, ReadBytesExt}; use chrono::{DateTime, Date, TimeZone, Local}; -use fs::{FatSharedStateRef, FatSlice}; +use fs::{FatFileSystemRef, FatSlice}; use file::FatFile; pub(crate) enum FatDirReader<'a, 'b: 'a> { @@ -33,8 +33,6 @@ impl <'a, 'b> Seek for FatDirReader<'a, 'b> { } } - - bitflags! { #[derive(Default)] pub struct FatFileAttributes: u8 { @@ -89,7 +87,7 @@ enum FatDirEntryData { pub struct FatDirEntry<'a, 'b: 'a> { data: FatDirFileEntryData, lfn: Vec, - state: FatSharedStateRef<'a, 'b>, + fs: FatFileSystemRef<'a, 'b>, } impl <'a, 'b> FatDirEntry<'a, 'b> { @@ -127,15 +125,15 @@ impl <'a, 'b> FatDirEntry<'a, 'b> { if self.is_dir() { panic!("This is a directory"); } - FatFile::new(self.first_cluster(), Some(self.data.size), self.state) + FatFile::new(self.first_cluster(), Some(self.data.size), self.fs) } pub fn to_dir(&self) -> FatDir<'a, 'b> { if !self.is_dir() { panic!("This is a file"); } - let file = FatFile::new(self.first_cluster(), None, self.state); - FatDir::new(FatDirReader::File(file), self.state) + let file = FatFile::new(self.first_cluster(), None, self.fs); + FatDir::new(FatDirReader::File(file), self.fs) } pub fn len(&self) -> u64 { @@ -173,13 +171,13 @@ impl <'a, 'b> fmt::Debug for FatDirEntry<'a, 'b> { pub struct FatDir<'a, 'b: 'a> { rdr: FatDirReader<'a, 'b>, - state: FatSharedStateRef<'a, 'b>, + fs: FatFileSystemRef<'a, 'b>, } impl <'a, 'b> FatDir<'a, 'b> { - pub(crate) fn new(rdr: FatDirReader<'a, 'b>, state: FatSharedStateRef<'a, 'b>) -> FatDir<'a, 'b> { - FatDir { rdr, state } + pub(crate) fn new(rdr: FatDirReader<'a, 'b>, fs: FatFileSystemRef<'a, 'b>) -> FatDir<'a, 'b> { + FatDir { rdr, fs } } pub fn rewind(&mut self) { @@ -296,7 +294,7 @@ impl <'a, 'b> Iterator for FatDir<'a, 'b> { return Some(Ok(FatDirEntry { data, lfn: lfn_buf, - state: self.state.clone(), + fs: self.fs, })); }, FatDirEntryData::Lfn(data) => { diff --git a/src/file.rs b/src/file.rs index a1bdad4..a6a5202 100644 --- a/src/file.rs +++ b/src/file.rs @@ -3,7 +3,7 @@ use std::io::prelude::*; use std::io::{SeekFrom, ErrorKind}; use std::io; -use fs::FatSharedStateRef; +use fs::FatFileSystemRef; pub struct FatFile<'a, 'b: 'a> { @@ -11,13 +11,13 @@ pub struct FatFile<'a, 'b: 'a> { size: Option, offset: u32, current_cluster: Option, - state: FatSharedStateRef<'a, 'b>, + fs: FatFileSystemRef<'a, 'b>, } impl <'a, 'b> FatFile<'a, 'b> { - pub(crate) fn new(first_cluster: u32, size: Option, state: FatSharedStateRef<'a, 'b>) -> Self { + pub(crate) fn new(first_cluster: u32, size: Option, fs: FatFileSystemRef<'a, 'b>) -> Self { FatFile { - first_cluster, size, state, + first_cluster, size, fs, current_cluster: Some(first_cluster), offset: 0, } @@ -27,8 +27,7 @@ impl <'a, 'b> FatFile<'a, 'b> { impl <'a, 'b> Read for FatFile<'a, 'b> { fn read(&mut self, buf: &mut [u8]) -> io::Result { let mut buf_offset: usize = 0; - let cluster_size = self.state.borrow().get_cluster_size(); - let mut state = self.state.borrow_mut(); + let cluster_size = self.fs.get_cluster_size(); loop { let offset_in_cluster = self.offset % cluster_size; let bytes_left_in_cluster = (cluster_size - offset_in_cluster) as usize; @@ -39,16 +38,19 @@ impl <'a, 'b> Read for FatFile<'a, 'b> { break; } let current_cluster = self.current_cluster.unwrap(); - let offset_in_fs = state.offset_from_cluster(current_cluster) + (offset_in_cluster as u64); - state.rdr.seek(SeekFrom::Start(offset_in_fs))?; - let read_bytes = state.rdr.read(&mut buf[buf_offset..buf_offset+read_size])?; + let offset_in_fs = self.fs.offset_from_cluster(current_cluster) + (offset_in_cluster as u64); + let read_bytes = { + let mut rdr = self.fs.rdr.borrow_mut(); + rdr.seek(SeekFrom::Start(offset_in_fs))?; + rdr.read(&mut buf[buf_offset..buf_offset+read_size])? + }; if read_bytes == 0 { break; } self.offset += read_bytes as u32; buf_offset += read_bytes; if self.offset % cluster_size == 0 { - self.current_cluster = state.table.cluster_iter(current_cluster).skip(1).next(); + self.current_cluster = self.fs.cluster_iter(current_cluster).skip(1).next(); } } Ok(buf_offset) @@ -65,12 +67,11 @@ impl <'a, 'b> Seek for FatFile<'a, 'b> { if new_offset < 0 || (self.size.is_some() && new_offset as u64 > self.size.unwrap() as u64) { return Err(io::Error::new(ErrorKind::InvalidInput, "invalid seek")); } - let cluster_size = self.state.borrow().get_cluster_size(); + let cluster_size = self.fs.get_cluster_size(); let cluster_count = (new_offset / cluster_size as i64) as usize; let mut new_cluster = Some(self.first_cluster); - let state = self.state.borrow_mut(); if cluster_count > 0 { - new_cluster = state.table.cluster_iter(new_cluster.unwrap()).skip(cluster_count).next(); + new_cluster = self.fs.cluster_iter(new_cluster.unwrap()).skip(cluster_count).next(); } self.offset = new_offset as u32; self.current_cluster = new_cluster; diff --git a/src/fs.rs b/src/fs.rs index ee83338..5633670 100644 --- a/src/fs.rs +++ b/src/fs.rs @@ -1,5 +1,6 @@ use core::cell::RefCell; use core::cmp; +use core::iter; use std::io::prelude::*; use std::io::{Error, ErrorKind, SeekFrom}; use std::io; @@ -8,7 +9,7 @@ use byteorder::{LittleEndian, ReadBytesExt}; use file::FatFile; use dir::{FatDirReader, FatDir}; -use table::FatTable; +use table::FatClusterIterator; // FAT implementation based on: // http://wiki.osdev.org/FAT @@ -22,33 +23,6 @@ pub enum FatType { pub trait ReadSeek: Read + Seek {} impl ReadSeek for T where T: Read + Seek {} -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, - pub(crate) table: FatTable, -} - -impl <'a> FatSharedState<'a> { - 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 - } - - pub(crate) fn offset_from_cluster(&self, cluser: u32) -> u64 { - self.offset_from_sector(self.sector_from_cluster(cluser)) - } -} - #[allow(dead_code)] #[derive(Default, Debug, Clone)] pub(crate) struct FatBiosParameterBlock { @@ -102,11 +76,14 @@ impl Default for FatBootRecord { } } -pub(crate) type FatSharedStateCell<'a> = RefCell>; -pub(crate) type FatSharedStateRef<'a, 'b: 'a> = &'a RefCell>; +pub(crate) type FatFileSystemRef<'a, 'b: 'a> = &'a FatFileSystem<'b>; pub struct FatFileSystem<'a> { - pub(crate) state: FatSharedStateCell<'a>, + pub(crate) rdr: RefCell<&'a mut ReadSeek>, + pub(crate) fat_type: FatType, + pub(crate) boot: FatBootRecord, + pub(crate) first_data_sector: u32, + pub(crate) root_dir_sectors: u32, } impl <'a> FatFileSystem<'a> { @@ -125,47 +102,36 @@ impl <'a> FatFileSystem<'a> { let total_clusters = data_sectors / boot.bpb.sectors_per_cluster as u32; let fat_type = Self::fat_type_from_clusters(total_clusters); - let fat_offset = boot.bpb.reserved_sectors * boot.bpb.bytes_per_sector; - rdr.seek(SeekFrom::Start(fat_offset as u64))?; - let fat_size = sectors_per_fat * boot.bpb.bytes_per_sector as u32; - let table = FatTable::from_read(rdr, fat_type, fat_size as usize)?; - - let state = FatSharedState { - rdr, + Ok(FatFileSystem { + rdr: RefCell::new(rdr), fat_type, boot, first_data_sector, root_dir_sectors, - table, - }; - - Ok(FatFileSystem { - state: RefCell::new(state), }) } pub fn fat_type(&self) -> FatType { - self.state.borrow().fat_type + self.fat_type } pub fn volume_id(&self) -> u32 { - self.state.borrow().boot.bpb.volume_id + self.boot.bpb.volume_id } pub fn volume_label(&self) -> String { - str::from_utf8(&self.state.borrow().boot.bpb.volume_label).unwrap().trim_right().to_string() + str::from_utf8(&self.boot.bpb.volume_label).unwrap().trim_right().to_string() } pub fn root_dir<'b>(&'b self) -> FatDir<'b, 'a> { let root_rdr = { - let state = self.state.borrow(); - match state.fat_type { + match self.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_dir_first_cluster, None, &self.state)), + self.first_data_sector - self.root_dir_sectors, self.root_dir_sectors, self)), + _ => FatDirReader::File(FatFile::new(self.boot.bpb.root_dir_first_cluster, None, self)), } }; - FatDir::new(root_rdr, &self.state) + FatDir::new(root_rdr, self) } fn read_bpb(rdr: &mut Read) -> io::Result { @@ -232,23 +198,50 @@ impl <'a> FatFileSystem<'a> { rdr.read(&mut boot.boot_sig)?; Ok(boot) } + + 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 + } + + pub(crate) fn offset_from_cluster(&self, cluser: u32) -> u64 { + self.offset_from_sector(self.sector_from_cluster(cluser)) + } + + pub(crate) fn cluster_iter<'b>(&'b self, cluster: u32) -> iter::Chain, FatClusterIterator<'b, 'a>> { + let bytes_per_sector = self.boot.bpb.bytes_per_sector as u64; + let fat_offset = self.boot.bpb.reserved_sectors as u64 * bytes_per_sector; + let sectors_per_fat = + if self.boot.bpb.sectors_per_fat_16 == 0 { self.boot.bpb.sectors_per_fat_32 } + else { self.boot.bpb.sectors_per_fat_16 as u32 }; + let fat_size = sectors_per_fat as u64 * bytes_per_sector; + let fat_slice = FatSlice::new(fat_offset, fat_size, self); + FatClusterIterator::new(fat_slice, self.fat_type, cluster) + } } pub(crate) struct FatSlice<'a, 'b: 'a> { begin: u64, size: u64, offset: u64, - state: FatSharedStateRef<'a, 'b>, + fs: &'a FatFileSystem<'b>, } impl <'a, 'b> FatSlice<'a, 'b> { - pub(crate) fn new(begin: u64, size: u64, state: FatSharedStateRef<'a, 'b>) -> Self { - FatSlice { begin, size, state, offset: 0 } + pub(crate) fn new(begin: u64, size: u64, fs: FatFileSystemRef<'a, 'b>) -> Self { + FatSlice { begin, size, fs, offset: 0 } } - pub(crate) fn from_sectors(first_sector: u32, sectors_count: u32, state: FatSharedStateRef<'a, 'b>) -> Self { - 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) + pub(crate) fn from_sectors(first_sector: u32, sectors_count: u32, fs: FatFileSystemRef<'a, 'b>) -> Self { + let bytes_per_sector = fs.boot.bpb.bytes_per_sector as u64; + Self::new(first_sector as u64 * bytes_per_sector, sectors_count as u64 * bytes_per_sector, fs) } } @@ -256,9 +249,9 @@ impl <'a, 'b> Read for FatSlice<'a, 'b> { fn read(&mut self, buf: &mut [u8]) -> io::Result { let offset = self.begin + self.offset; let read_size = cmp::min((self.size - self.offset) as usize, buf.len()); - let mut state = self.state.borrow_mut(); - state.rdr.seek(SeekFrom::Start(offset))?; - let size = state.rdr.read(&mut buf[..read_size])?; + let mut rdr = self.fs.rdr.borrow_mut(); + rdr.seek(SeekFrom::Start(offset))?; + let size = rdr.read(&mut buf[..read_size])?; self.offset += size as u64; Ok(size) } diff --git a/src/table.rs b/src/table.rs index 4d9b06d..3037734 100644 --- a/src/table.rs +++ b/src/table.rs @@ -1,139 +1,77 @@ -use std::io::prelude::*; use std::io; use byteorder::{LittleEndian, ReadBytesExt}; -use fs::FatType; +use fs::{FatType, FatSlice, ReadSeek}; use core::iter; -pub(crate) struct FatTableData { - table: Box<[T]>, -} - -impl FatTableData { - pub fn new(data: Box<[T]>) -> Self { - Self { - table: data, - } +fn get_next_cluster(rdr: &mut ReadSeek, fat_type: FatType, cluster: u32) -> io::Result> { + match fat_type { + FatType::Fat12 => get_next_cluster_12(rdr, cluster), + FatType::Fat16 => get_next_cluster_16(rdr, cluster), + FatType::Fat32 => get_next_cluster_32(rdr, cluster), } } -pub(crate) type FatTable12 = FatTableData; -pub(crate) type FatTable16 = FatTableData; -pub(crate) type FatTable32 = FatTableData; - -pub(crate) enum FatTable { - Fat12(FatTable12), - Fat16(FatTable16), - Fat32(FatTable32), -} - -impl FatTable { - pub fn from_read(rdr: &mut Read, fat_type: FatType, size: usize) -> io::Result { - let table = match fat_type { - FatType::Fat12 => FatTable::Fat12(FatTable12::from_read(rdr, size)?), - FatType::Fat16 => FatTable::Fat16(FatTable16::from_read(rdr, size)?), - FatType::Fat32 => FatTable::Fat32(FatTable32::from_read(rdr, size)?), - }; - Ok(table) - } +fn get_next_cluster_12(rdr: &mut ReadSeek, cluster: u32) -> io::Result> { + let fat_offset = cluster + (cluster / 2); + let mut bytes = [0;2]; + rdr.seek(io::SeekFrom::Start(fat_offset as u64))?; + rdr.read(&mut bytes)?; + let (val1, val2) = (bytes[0] as u16, bytes[1] as u16); - pub fn cluster_iter(&self, cluster: u32) -> iter::Chain, FatClusterIterator> { + let val = if cluster & 1 == 1 { + (val1 >> 4) | (val2 << 4) + } else { + val1 | (val2 & 0x0F) + }; + if val <= 1 || val >= 0xFF7 { + Ok(None) + } else { + Ok(Some(val as u32)) + } +} + +fn get_next_cluster_16(rdr: &mut ReadSeek, cluster: u32) -> io::Result> { + rdr.seek(io::SeekFrom::Start((cluster*2) as u64))?; + let val = rdr.read_u16::()?; + if val <= 1 || val >= 0xFFF7 { + Ok(None) + } else { + Ok(Some(val as u32)) + } +} + +fn get_next_cluster_32(rdr: &mut ReadSeek, cluster: u32) -> io::Result> { + rdr.seek(io::SeekFrom::Start((cluster*4) as u64))?; + let val = rdr.read_u32::()? & 0x0FFFFFFF; + if val <= 1 || val >= 0x0FFFFFF7 { + Ok(None) + } else { + Ok(Some(val)) + } +} + +pub(crate) struct FatClusterIterator<'a, 'b: 'a> { + part: FatSlice<'a, 'b>, + fat_type: FatType, + cluster: Option, +} + +impl <'a, 'b> FatClusterIterator<'a, 'b> { + pub(crate) fn new(part: FatSlice<'a, 'b>, fat_type: FatType, cluster: u32) -> iter::Chain, FatClusterIterator<'a, 'b>> { let iter = FatClusterIterator { - table: self, + part: part, + fat_type: fat_type, cluster: Some(cluster), }; iter::once(cluster).chain(iter) } } -trait FatNextCluster { - fn get_next_cluster(&self, cluster: u32) -> Option; -} - -impl FatNextCluster for FatTable { - fn get_next_cluster(&self, cluster: u32) -> Option { - match *self { - FatTable::Fat12(ref fat) => fat.get_next_cluster(cluster), - FatTable::Fat16(ref fat) => fat.get_next_cluster(cluster), - FatTable::Fat32(ref fat) => fat.get_next_cluster(cluster), - } - } -} - -impl FatTable12 { - pub fn from_read(rdr: &mut Read, size: usize) -> io::Result { - let mut fat = vec![0;size]; - rdr.read_exact(fat.as_mut())?; - Ok(Self::new(fat.into_boxed_slice())) - } -} - -impl FatTable16 { - pub fn from_read(rdr: &mut Read, size: usize) -> io::Result { - let mut fat = vec![0;size/2]; - rdr.read_u16_into::(fat.as_mut())?; - Ok(Self::new(fat.into_boxed_slice())) - } -} - -impl FatTable32 { - pub fn from_read(rdr: &mut Read, size: usize) -> io::Result { - let mut fat = vec![0;size/4]; - rdr.read_u32_into::(fat.as_mut())?; - Ok(Self::new(fat.into_boxed_slice())) - } -} - -impl FatNextCluster for FatTable12 { - fn get_next_cluster(&self, cluster: u32) -> Option { - let fat_offset = cluster + (cluster / 2); - let val1 = self.table[fat_offset as usize] as u16; - let val2 = self.table[(fat_offset + 1) as usize] as u16; - - let val = if cluster & 1 == 1 { - (val1 >> 4) | (val2 << 4) - } else { - val1 | (val2 & 0x0F) - }; - if val <= 1 || val >= 0xFF7 { - None - } else { - Some(val as u32) - } - } -} - -impl FatNextCluster for FatTable16 { - fn get_next_cluster(&self, cluster: u32) -> Option { - let val = self.table[cluster as usize]; - if val <= 1 || val >= 0xFFF7 { - None - } else { - Some(val as u32) - } - } -} - -impl FatNextCluster for FatTable32 { - fn get_next_cluster(&self, cluster: u32) -> Option { - let val = self.table[cluster as usize] & 0x0FFFFFFF; - if val <= 1 || val >= 0x0FFFFFF7 { - None - } else { - Some(val) - } - } -} - -pub(crate) struct FatClusterIterator<'a> { - table: &'a FatTable, - cluster: Option, -} - -impl <'a> Iterator for FatClusterIterator<'a> { +impl <'a, 'b> Iterator for FatClusterIterator<'a, 'b> { type Item = u32; fn next(&mut self) -> Option { - self.cluster = self.table.get_next_cluster(self.cluster.unwrap()); + self.cluster = get_next_cluster(&mut self.part, self.fat_type, self.cluster.unwrap()).unwrap(); // FIXME: unwrap! self.cluster } }