diff --git a/README.md b/README.md index 73ee049..53b940d 100644 --- a/README.md +++ b/README.md @@ -33,8 +33,8 @@ Put this in your crate root: You can start using library now: let img_file = File::open("fat.img")?; - let mut buf_stream = fatfs::BufStream::new(img_file); - let fs = fatfs::FileSystem::new(&mut buf_stream, fatfs::FsOptions::new())?; + let buf_stream = fatfs::BufStream::new(img_file); + let fs = fatfs::FileSystem::new(buf_stream, fatfs::FsOptions::new())?; let root_dir = fs.root_dir(); let mut file = root_dir.create_file("hello.txt")?; file.write_all(b"Hello World!")?; diff --git a/src/dir.rs b/src/dir.rs index ef82369..1be161a 100644 --- a/src/dir.rs +++ b/src/dir.rs @@ -6,7 +6,7 @@ use io::prelude::*; use io; use io::{ErrorKind, SeekFrom}; -use fs::{FileSystemRef, DiskSlice}; +use fs::{FileSystem, DiskSlice, ReadWriteSeek}; use file::File; use dir_entry::{DirEntry, DirEntryData, DirFileEntryData, DirLfnEntryData, FileAttributes, ShortName, DIR_ENTRY_SIZE}; @@ -16,13 +16,12 @@ use dir_entry::{LFN_PART_LEN, LFN_ENTRY_LAST_FLAG}; #[cfg(all(not(feature = "std"), feature = "alloc"))] use alloc::Vec; -#[derive(Clone)] -pub(crate) enum DirRawStream<'a, 'b: 'a> { - File(File<'a, 'b>), - Root(DiskSlice<'a, 'b>), +pub(crate) enum DirRawStream<'a, T: ReadWriteSeek + 'a> { + File(File<'a, T>), + Root(DiskSlice<'a, T>), } -impl <'a, 'b> DirRawStream<'a, 'b> { +impl <'a, T: ReadWriteSeek> DirRawStream<'a, T> { fn abs_pos(&self) -> Option { match self { &DirRawStream::File(ref file) => file.abs_pos(), @@ -38,7 +37,17 @@ impl <'a, 'b> DirRawStream<'a, 'b> { } } -impl <'a, 'b> Read for DirRawStream<'a, 'b> { +// Note: derive cannot be used because of invalid bounds. See: https://github.com/rust-lang/rust/issues/26925 +impl <'a, T: ReadWriteSeek> Clone for DirRawStream<'a, T> { + fn clone(&self) -> Self { + match self { + &DirRawStream::File(ref file) => DirRawStream::File(file.clone()), + &DirRawStream::Root(ref raw) => DirRawStream::Root(raw.clone()), + } + } +} + +impl <'a, T: ReadWriteSeek> Read for DirRawStream<'a, T> { fn read(&mut self, buf: &mut [u8]) -> io::Result { match self { &mut DirRawStream::File(ref mut file) => file.read(buf), @@ -47,7 +56,7 @@ impl <'a, 'b> Read for DirRawStream<'a, 'b> { } } -impl <'a, 'b> Write for DirRawStream<'a, 'b> { +impl <'a, T: ReadWriteSeek> Write for DirRawStream<'a, T> { fn write(&mut self, buf: &[u8]) -> io::Result { match self { &mut DirRawStream::File(ref mut file) => file.write(buf), @@ -62,7 +71,7 @@ impl <'a, 'b> Write for DirRawStream<'a, 'b> { } } -impl <'a, 'b> Seek for DirRawStream<'a, 'b> { +impl <'a, T: ReadWriteSeek> Seek for DirRawStream<'a, T> { fn seek(&mut self, pos: SeekFrom) -> io::Result { match self { &mut DirRawStream::File(ref mut file) => file.seek(pos), @@ -80,19 +89,19 @@ fn split_path<'c>(path: &'c str) -> (&'c str, Option<&'c str>) { } /// FAT directory -#[derive(Clone)] -pub struct Dir<'a, 'b: 'a> { - stream: DirRawStream<'a, 'b>, - fs: FileSystemRef<'a, 'b>, +pub struct Dir<'a, T: ReadWriteSeek + 'a> { + stream: DirRawStream<'a, T>, + fs: &'a FileSystem, } -impl <'a, 'b> Dir<'a, 'b> { - pub(crate) fn new(stream: DirRawStream<'a, 'b>, fs: FileSystemRef<'a, 'b>) -> Self { +impl <'a, T: ReadWriteSeek + 'a> Dir<'a, T> { + pub(crate) fn new(stream: DirRawStream<'a, T>, fs: &'a FileSystem) -> Self { Dir { stream, fs } } /// Creates directory entries iterator - pub fn iter(&self) -> DirIter<'a, 'b> { + pub fn iter(&self) -> DirIter<'a, T> { + self.stream.clone(); DirIter { stream: self.stream.clone(), fs: self.fs.clone(), @@ -100,7 +109,7 @@ impl <'a, 'b> Dir<'a, 'b> { } } - fn find_entry(&self, name: &str, is_dir: Option, mut short_name_gen: Option<&mut ShortNameGenerator>) -> io::Result> { + fn find_entry(&self, name: &str, is_dir: Option, mut short_name_gen: Option<&mut ShortNameGenerator>) -> io::Result> { for r in self.iter() { let e = r?; // compare name ignoring case @@ -130,7 +139,7 @@ impl <'a, 'b> Dir<'a, 'b> { } /// Opens existing file. - pub fn open_file(&self, path: &str) -> io::Result> { + pub fn open_file(&self, path: &str) -> io::Result> { // traverse path let (name, rest_opt) = split_path(path); if let Some(rest) = rest_opt { @@ -143,7 +152,7 @@ impl <'a, 'b> Dir<'a, 'b> { } /// Creates new file or opens existing without truncating. - pub fn create_file(&self, path: &str) -> io::Result> { + pub fn create_file(&self, path: &str) -> io::Result> { // traverse path let (name, rest_opt) = split_path(path); if let Some(rest) = rest_opt { @@ -255,7 +264,7 @@ impl <'a, 'b> Dir<'a, 'b> { /// Destination directory can be cloned source directory in case of rename without moving operation. /// Make sure there is no reference to this file (no File instance) or filesystem corruption /// can happen. - pub fn rename(&self, src_path: &str, dst_dir: &Dir, dst_path: &str) -> io::Result<()> { + pub fn rename(&self, src_path: &str, dst_dir: &Dir, dst_path: &str) -> io::Result<()> { // traverse source path let (name, rest_opt) = split_path(src_path); if let Some(rest) = rest_opt { @@ -272,7 +281,7 @@ impl <'a, 'b> Dir<'a, 'b> { self.rename_internal(src_path, dst_dir, dst_path) } - fn rename_internal(&self, src_name: &str, dst_dir: &Dir, dst_name: &str) -> io::Result<()> { + fn rename_internal(&self, src_name: &str, dst_dir: &Dir, dst_name: &str) -> io::Result<()> { trace!("moving {} to {}", src_name, dst_name); // find existing file let e = self.find_entry(src_name, None, None)?; @@ -300,7 +309,7 @@ impl <'a, 'b> Dir<'a, 'b> { Ok(()) } - fn find_free_entries(&self, num_entries: usize) -> io::Result> { + fn find_free_entries(&self, num_entries: usize) -> io::Result> { let mut stream = self.stream.clone(); let mut first_free = 0; let mut num_free = 0; @@ -334,7 +343,7 @@ impl <'a, 'b> Dir<'a, 'b> { } #[cfg(feature = "alloc")] - fn create_lfn_entries(&self, name: &str, short_name: &[u8]) -> io::Result<(DirRawStream<'a, 'b>, u64)> { + fn create_lfn_entries(&self, name: &str, short_name: &[u8]) -> io::Result<(DirRawStream<'a, T>, u64)> { // get short name checksum let lfn_chsum = lfn_checksum(&short_name); // convert long name to UTF-16 @@ -351,7 +360,7 @@ impl <'a, 'b> Dir<'a, 'b> { Ok((stream, start_pos)) } #[cfg(not(feature = "alloc"))] - fn create_lfn_entries(&self, _name: &str, _short_name: &[u8]) -> io::Result<(DirRawStream<'a, 'b>, u64)> { + fn create_lfn_entries(&self, _name: &str, _short_name: &[u8]) -> io::Result<(DirRawStream<'a, T>, u64)> { let mut stream = self.find_free_entries(1)?; let start_pos = stream.seek(io::SeekFrom::Current(0))?; Ok((stream, start_pos)) @@ -366,7 +375,7 @@ impl <'a, 'b> Dir<'a, 'b> { raw_entry } - fn write_entry(&self, name: &str, raw_entry: DirFileEntryData) -> io::Result> { + fn write_entry(&self, name: &str, raw_entry: DirFileEntryData) -> io::Result> { trace!("write_entry {}", name); // check if name doesn't contain unsupported characters validate_long_name(name)?; @@ -390,16 +399,25 @@ impl <'a, 'b> Dir<'a, 'b> { } } +// Note: derive cannot be used because of invalid bounds. See: https://github.com/rust-lang/rust/issues/26925 +impl <'a, T: ReadWriteSeek> Clone for Dir<'a, T> { + fn clone(&self) -> Self { + Self { + stream: self.stream.clone(), + fs: self.fs, + } + } +} + /// Directory entries iterator. -#[derive(Clone)] -pub struct DirIter<'a, 'b: 'a> { - stream: DirRawStream<'a, 'b>, - fs: FileSystemRef<'a, 'b>, +pub struct DirIter<'a, T: ReadWriteSeek + 'a> { + stream: DirRawStream<'a, T>, + fs: &'a FileSystem, err: bool, } -impl <'a, 'b> DirIter<'a, 'b> { - fn read_dir_entry(&mut self) -> io::Result>> { +impl <'a, T: ReadWriteSeek> DirIter<'a, T> { + fn read_dir_entry(&mut self) -> io::Result>> { #[cfg(feature = "alloc")] let mut lfn_buf = LongNameBuilder::new(); let mut offset = self.stream.seek(SeekFrom::Current(0))?; @@ -454,8 +472,19 @@ impl <'a, 'b> DirIter<'a, 'b> { } } -impl <'a, 'b> Iterator for DirIter<'a, 'b> { - type Item = io::Result>; +// Note: derive cannot be used because of invalid bounds. See: https://github.com/rust-lang/rust/issues/26925 +impl <'a, T: ReadWriteSeek> Clone for DirIter<'a, T> { + fn clone(&self) -> Self { + Self { + stream: self.stream.clone(), + fs: self.fs, + err: self.err, + } + } +} + +impl <'a, T: ReadWriteSeek> Iterator for DirIter<'a, T> { + type Item = io::Result>; fn next(&mut self) -> Option { if self.err { diff --git a/src/dir_entry.rs b/src/dir_entry.rs index f379792..a8d77d2 100644 --- a/src/dir_entry.rs +++ b/src/dir_entry.rs @@ -13,7 +13,7 @@ use chrono; #[cfg(all(not(feature = "std"), feature = "alloc"))] use alloc::{Vec, String, string::ToString}; -use fs::{FileSystemRef, FatType}; +use fs::{FileSystem, FatType, ReadWriteSeek}; use file::File; use dir::{Dir, DirRawStream}; @@ -589,7 +589,7 @@ impl DirEntryEditor { self.dirty = true; } - pub(crate) fn flush(&mut self, fs: FileSystemRef) -> io::Result<()> { + pub(crate) fn flush(&mut self, fs: &FileSystem) -> io::Result<()> { if self.dirty { self.write(fs)?; self.dirty = false; @@ -597,7 +597,7 @@ impl DirEntryEditor { Ok(()) } - fn write(&self, fs: FileSystemRef) -> io::Result<()> { + fn write(&self, fs: &FileSystem) -> io::Result<()> { let mut disk = fs.disk.borrow_mut(); disk.seek(io::SeekFrom::Start(self.pos))?; self.data.serialize(&mut *disk) @@ -608,17 +608,17 @@ impl DirEntryEditor { /// /// Returned by DirIter. #[derive(Clone)] -pub struct DirEntry<'a, 'b: 'a> { +pub struct DirEntry<'a, T: ReadWriteSeek + 'a> { pub(crate) data: DirFileEntryData, pub(crate) short_name: ShortName, #[cfg(feature = "alloc")] pub(crate) lfn: Vec, pub(crate) entry_pos: u64, pub(crate) offset_range: (u64, u64), - pub(crate) fs: FileSystemRef<'a, 'b>, + pub(crate) fs: &'a FileSystem, } -impl <'a, 'b> DirEntry<'a, 'b> { +impl <'a, T: ReadWriteSeek> DirEntry<'a, T> { /// Returns short file name #[cfg(feature = "alloc")] pub fn short_file_name(&self) -> String { @@ -669,7 +669,7 @@ impl <'a, 'b> DirEntry<'a, 'b> { /// Returns File struct for this entry. /// /// Panics if this is not a file. - pub fn to_file(&self) -> File<'a, 'b> { + pub fn to_file(&self) -> File<'a, T> { assert!(!self.is_dir(), "Not a file entry"); File::new(self.first_cluster(), Some(self.editor()), self.fs) } @@ -677,7 +677,7 @@ impl <'a, 'b> DirEntry<'a, 'b> { /// Returns Dir struct for this entry. /// /// Panics if this is not a directory. - pub fn to_dir(&self) -> Dir<'a, 'b> { + pub fn to_dir(&self) -> Dir<'a, T> { assert!(self.is_dir(), "Not a directory entry"); match self.first_cluster() { Some(n) => { @@ -713,7 +713,7 @@ impl <'a, 'b> DirEntry<'a, 'b> { } } -impl <'a, 'b> fmt::Debug for DirEntry<'a, 'b> { +impl <'a, T: ReadWriteSeek> fmt::Debug for DirEntry<'a, T> { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { self.data.fmt(f) } diff --git a/src/file.rs b/src/file.rs index b4b86c8..4a9a78c 100644 --- a/src/file.rs +++ b/src/file.rs @@ -4,14 +4,13 @@ use io::prelude::*; use io::{SeekFrom, ErrorKind}; use io; -use fs::FileSystemRef; +use fs::{FileSystem, ReadWriteSeek}; use dir_entry::{DirEntryEditor, DateTime, Date}; const MAX_FILE_SIZE: u32 = core::u32::MAX; /// FAT file used for reading and writing. -#[derive(Clone)] -pub struct File<'a, 'b: 'a> { +pub struct File<'a, T: ReadWriteSeek + 'a> { // Note first_cluster is None if file is empty first_cluster: Option, // Note: if offset points between clusters current_cluster is the previous cluster @@ -21,11 +20,11 @@ pub struct File<'a, 'b: 'a> { // file dir entry editor - None for root dir entry: Option, // file-system reference - fs: FileSystemRef<'a, 'b>, + fs: &'a FileSystem, } -impl <'a, 'b> File<'a, 'b> { - pub(crate) fn new(first_cluster: Option, entry: Option, fs: FileSystemRef<'a, 'b>) -> Self { +impl <'a, T: ReadWriteSeek> File<'a, T> { + pub(crate) fn new(first_cluster: Option, entry: Option, fs: &'a FileSystem) -> Self { File { first_cluster, entry, fs, current_cluster: None, // cluster before first one @@ -132,7 +131,7 @@ impl <'a, 'b> File<'a, 'b> { } } -impl<'a, 'b> Drop for File<'a, 'b> { +impl<'a, T: ReadWriteSeek> Drop for File<'a, T> { fn drop(&mut self) { if let Err(err) = self.flush() { error!("flush failed {}", err); @@ -140,7 +139,20 @@ impl<'a, 'b> Drop for File<'a, 'b> { } } -impl<'a, 'b> Read for File<'a, 'b> { +// Note: derive cannot be used because of invalid bounds. See: https://github.com/rust-lang/rust/issues/26925 +impl <'a, T: ReadWriteSeek> Clone for File<'a, T> { + fn clone(&self) -> Self { + File { + first_cluster: self.first_cluster, + current_cluster: self.current_cluster, + offset: self.offset, + entry: self.entry.clone(), + fs: self.fs, + } + } +} + +impl<'a, T: ReadWriteSeek> Read for File<'a, T> { fn read(&mut self, buf: &mut [u8]) -> io::Result { let cluster_size = self.fs.cluster_size(); let current_cluster_opt = if self.offset % cluster_size == 0 { @@ -191,7 +203,7 @@ impl<'a, 'b> Read for File<'a, 'b> { } } -impl<'a, 'b> Write for File<'a, 'b> { +impl<'a, T: ReadWriteSeek> Write for File<'a, T> { fn write(&mut self, buf: &[u8]) -> io::Result { let cluster_size = self.fs.cluster_size(); let offset_in_cluster = self.offset % cluster_size; @@ -271,7 +283,7 @@ impl<'a, 'b> Write for File<'a, 'b> { } } -impl<'a, 'b> Seek for File<'a, 'b> { +impl<'a, T: ReadWriteSeek> Seek for File<'a, T> { fn seek(&mut self, pos: SeekFrom) -> io::Result { let mut new_pos = match pos { SeekFrom::Current(x) => self.offset as i64 + x, diff --git a/src/fs.rs b/src/fs.rs index a166dfd..11d5d06 100644 --- a/src/fs.rs +++ b/src/fs.rs @@ -100,7 +100,7 @@ struct BiosParameterBlock { } impl BiosParameterBlock { - fn deserialize(rdr: &mut Read) -> io::Result { + fn deserialize(rdr: &mut T) -> io::Result { let mut bpb: BiosParameterBlock = Default::default(); bpb.bytes_per_sector = rdr.read_u16::()?; bpb.sectors_per_cluster = rdr.read_u8()?; @@ -188,7 +188,7 @@ struct BootRecord { } impl BootRecord { - fn deserialize(rdr: &mut Read) -> io::Result { + fn deserialize(rdr: &mut T) -> io::Result { let mut boot: BootRecord = Default::default(); rdr.read_exact(&mut boot.bootjmp)?; rdr.read_exact(&mut boot.oem_name)?; @@ -228,7 +228,7 @@ impl FsInfoSector { const STRUC_SIG: u32 = 0x61417272; const TRAIL_SIG: u32 = 0xAA550000; - fn deserialize(rdr: &mut Read) -> io::Result { + fn deserialize(rdr: &mut T) -> io::Result { let lead_sig = rdr.read_u32::()?; if lead_sig != Self::LEAD_SIG { return Err(Error::new(ErrorKind::Other, "invalid lead_sig in FsInfo sector")); @@ -259,7 +259,7 @@ impl FsInfoSector { }) } - fn serialize(&self, wrt: &mut Write) -> io::Result<()> { + fn serialize(&self, wrt: &mut T) -> io::Result<()> { wrt.write_u32::(Self::LEAD_SIG)?; let reserved = [0u8; 480]; wrt.write(&reserved)?; @@ -343,11 +343,9 @@ impl FileSystemStats { } } -pub(crate) type FileSystemRef<'a, 'b> = &'a FileSystem<'b>; - /// FAT filesystem main struct. -pub struct FileSystem<'a> { - pub(crate) disk: RefCell<&'a mut ReadWriteSeek>, +pub struct FileSystem { + pub(crate) disk: RefCell, pub(crate) options: FsOptions, fat_type: FatType, bpb: BiosParameterBlock, @@ -357,7 +355,7 @@ pub struct FileSystem<'a> { fs_info: RefCell, } -impl <'a> FileSystem<'a> { +impl FileSystem { /// Creates new filesystem object instance. /// /// Supplied disk parameter cannot be seeked. If there is a need to read a fragment of disk image (e.g. partition) @@ -365,13 +363,13 @@ impl <'a> FileSystem<'a> { /// /// Note: creating multiple filesystem objects with one underlying device/disk image can /// cause filesystem corruption. - pub fn new(disk: &'a mut T, options: FsOptions) -> io::Result { - // make sure given image is not seeked + pub fn new(mut disk: T, options: FsOptions) -> io::Result { + // Make sure given image is not seeked debug_assert!(disk.seek(SeekFrom::Current(0))? == 0); // read boot sector let bpb = { - let boot = BootRecord::deserialize(disk)?; + let boot = BootRecord::deserialize(&mut disk)?; if boot.boot_sig != [0x55, 0xAA] { return Err(Error::new(ErrorKind::Other, "invalid signature")); } @@ -395,7 +393,7 @@ impl <'a> FileSystem<'a> { // read FSInfo sector if this is FAT32 let mut fs_info = if fat_type == FatType::Fat32 { disk.seek(SeekFrom::Start(bpb.fs_info_sector as u64 * 512))?; - FsInfoSector::deserialize(disk)? + FsInfoSector::deserialize(&mut disk)? } else { FsInfoSector::default() }; @@ -442,7 +440,7 @@ impl <'a> FileSystem<'a> { } /// Returns root directory object allowing futher penetration of filesystem structure. - pub fn root_dir<'b>(&'b self) -> Dir<'b, 'a> { + pub fn root_dir<'b>(&'b self) -> Dir<'b, T> { let root_rdr = { match self.fat_type { FatType::Fat12 | FatType::Fat16 => DirRawStream::Root(DiskSlice::from_sectors( @@ -469,7 +467,7 @@ impl <'a> FileSystem<'a> { self.offset_from_sector(self.sector_from_cluster(cluser)) } - fn fat_slice<'b>(&'b self) -> DiskSlice<'b, 'a> { + fn fat_slice<'b>(&'b self) -> DiskSlice<'b, T> { let sectors_per_fat = if self.bpb.sectors_per_fat_16 == 0 { self.bpb.sectors_per_fat_32 } else { self.bpb.sectors_per_fat_16 as u32 }; @@ -484,7 +482,7 @@ impl <'a> FileSystem<'a> { DiskSlice::from_sectors(fat_first_sector, sectors_per_fat, mirrors, self) } - pub(crate) fn cluster_iter<'b>(&'b self, cluster: u32) -> ClusterIterator<'b, 'a> { + pub(crate) fn cluster_iter<'b>(&'b self, cluster: u32) -> ClusterIterator> { let disk_slice = self.fat_slice(); ClusterIterator::new(disk_slice, self.fat_type, cluster) } @@ -574,7 +572,7 @@ impl <'a> FileSystem<'a> { } } -impl<'a> Drop for FileSystem<'a> { +impl Drop for FileSystem { fn drop(&mut self) { if let Err(err) = self.unmount_internal() { error!("unmount failed {}", err); @@ -582,21 +580,20 @@ impl<'a> Drop for FileSystem<'a> { } } -#[derive(Clone)] -pub(crate) struct DiskSlice<'a, 'b: 'a> { +pub(crate) struct DiskSlice<'a, T: ReadWriteSeek + 'a> { begin: u64, size: u64, offset: u64, mirrors: u8, - fs: &'a FileSystem<'b>, + fs: &'a FileSystem, } -impl <'a, 'b> DiskSlice<'a, 'b> { - pub(crate) fn new(begin: u64, size: u64, mirrors: u8, fs: FileSystemRef<'a, 'b>) -> Self { +impl <'a, T: ReadWriteSeek> DiskSlice<'a, T> { + pub(crate) fn new(begin: u64, size: u64, mirrors: u8, fs: &'a FileSystem) -> Self { DiskSlice { begin, size, mirrors, fs, offset: 0 } } - pub(crate) fn from_sectors(first_sector: u32, sector_count: u32, mirrors: u8, fs: FileSystemRef<'a, 'b>) -> Self { + pub(crate) fn from_sectors(first_sector: u32, sector_count: u32, mirrors: u8, fs: &'a FileSystem) -> Self { let bytes_per_sector = fs.bpb.bytes_per_sector as u64; Self::new(first_sector as u64 * bytes_per_sector, sector_count as u64 * bytes_per_sector, mirrors, fs) } @@ -606,7 +603,20 @@ impl <'a, 'b> DiskSlice<'a, 'b> { } } -impl <'a, 'b> Read for DiskSlice<'a, 'b> { +// Note: derive cannot be used because of invalid bounds. See: https://github.com/rust-lang/rust/issues/26925 +impl <'a, T: ReadWriteSeek> Clone for DiskSlice<'a, T> { + fn clone(&self) -> Self { + DiskSlice { + begin: self.begin, + size: self.size, + offset: self.offset, + mirrors: self.mirrors, + fs: self.fs, + } + } +} + +impl <'a, T: ReadWriteSeek> Read for DiskSlice<'a, T> { 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()); @@ -618,7 +628,7 @@ impl <'a, 'b> Read for DiskSlice<'a, 'b> { } } -impl <'a, 'b> Write for DiskSlice<'a, 'b> { +impl <'a, T: ReadWriteSeek> Write for DiskSlice<'a, T> { fn write(&mut self, buf: &[u8]) -> io::Result { let offset = self.begin + self.offset; let write_size = cmp::min((self.size - self.offset) as usize, buf.len()); @@ -637,7 +647,7 @@ impl <'a, 'b> Write for DiskSlice<'a, 'b> { } } -impl <'a, 'b> Seek for DiskSlice<'a, 'b> { +impl <'a, T: ReadWriteSeek> Seek for DiskSlice<'a, T> { fn seek(&mut self, pos: SeekFrom) -> io::Result { let new_offset = match pos { SeekFrom::Current(x) => self.offset as i64 + x, diff --git a/src/table.rs b/src/table.rs index a81edcb..ab832e0 100644 --- a/src/table.rs +++ b/src/table.rs @@ -1,8 +1,7 @@ use io; -use io::prelude::*; use byteorder::LittleEndian; use byteorder_ext::{ReadBytesExt, WriteBytesExt}; -use fs::{FatType, FsStatusFlags, DiskSlice, ReadSeek}; +use fs::{ReadWriteSeek, ReadSeek, FatType, FsStatusFlags}; struct Fat { #[allow(dead_code)] @@ -24,14 +23,14 @@ enum FatValue { } trait FatTrait { - fn get_raw(fat: &mut ReadSeek, cluster: u32) -> io::Result; - fn get(fat: &mut ReadSeek, cluster: u32) -> io::Result; - fn set(fat: &mut DiskSlice, cluster: u32, value: FatValue) -> io::Result<()>; - fn find_free(fat: &mut ReadSeek, start_cluster: u32, end_cluster: u32) -> io::Result; - fn count_free(fat: &mut ReadSeek, end_cluster: u32) -> io::Result; + fn get_raw(fat: &mut T, cluster: u32) -> io::Result; + fn get(fat: &mut T, cluster: u32) -> io::Result; + fn set(fat: &mut T, cluster: u32, value: FatValue) -> io::Result<()>; + fn find_free(fat: &mut T, start_cluster: u32, end_cluster: u32) -> io::Result; + fn count_free(fat: &mut T, end_cluster: u32) -> io::Result; } -fn read_fat(fat: &mut ReadSeek, fat_type: FatType, cluster: u32) -> io::Result { +fn read_fat(fat: &mut T, fat_type: FatType, cluster: u32) -> io::Result { match fat_type { FatType::Fat12 => Fat12::get(fat, cluster), FatType::Fat16 => Fat16::get(fat, cluster), @@ -39,7 +38,7 @@ fn read_fat(fat: &mut ReadSeek, fat_type: FatType, cluster: u32) -> io::Result io::Result<()> { +fn write_fat(fat: &mut T, fat_type: FatType, cluster: u32, value: FatValue) -> io::Result<()> { trace!("write FAT - cluster {} value {:?}", cluster, value); match fat_type { FatType::Fat12 => Fat12::set(fat, cluster, value), @@ -48,7 +47,7 @@ fn write_fat(fat: &mut DiskSlice, fat_type: FatType, cluster: u32, value: FatVal } } -fn get_next_cluster(fat: &mut ReadSeek, fat_type: FatType, cluster: u32) -> io::Result> { +fn get_next_cluster(fat: &mut T, fat_type: FatType, cluster: u32) -> io::Result> { let val = read_fat(fat, fat_type, cluster)?; match val { FatValue::Data(n) => Ok(Some(n)), @@ -56,7 +55,7 @@ fn get_next_cluster(fat: &mut ReadSeek, fat_type: FatType, cluster: u32) -> io:: } } -fn find_free_cluster(fat: &mut ReadSeek, fat_type: FatType, start_cluster: u32, end_cluster: u32) -> io::Result { +fn find_free_cluster(fat: &mut T, fat_type: FatType, start_cluster: u32, end_cluster: u32) -> io::Result { match fat_type { FatType::Fat12 => Fat12::find_free(fat, start_cluster, end_cluster), FatType::Fat16 => Fat16::find_free(fat, start_cluster, end_cluster), @@ -64,7 +63,7 @@ fn find_free_cluster(fat: &mut ReadSeek, fat_type: FatType, start_cluster: u32, } } -pub(crate) fn alloc_cluster(fat: &mut DiskSlice, fat_type: FatType, prev_cluster: Option, hint: Option, total_clusters: u32) -> io::Result { +pub(crate) fn alloc_cluster(fat: &mut T, fat_type: FatType, prev_cluster: Option, hint: Option, total_clusters: u32) -> io::Result { let end_cluster = total_clusters + RESERVED_FAT_ENTRIES; let start_cluster = match hint { Some(n) if n < end_cluster => n, @@ -83,7 +82,7 @@ pub(crate) fn alloc_cluster(fat: &mut DiskSlice, fat_type: FatType, prev_cluster Ok(new_cluster) } -pub(crate) fn read_fat_flags(fat: &mut DiskSlice, fat_type: FatType) -> io::Result { +pub(crate) fn read_fat_flags(fat: &mut T, fat_type: FatType) -> io::Result { // check MSB (except in FAT12) let val = match fat_type { FatType::Fat12 => 0xFFF, @@ -105,7 +104,7 @@ pub(crate) fn read_fat_flags(fat: &mut DiskSlice, fat_type: FatType) -> io::Resu }) } -pub(crate) fn count_free_clusters(fat: &mut ReadSeek, fat_type: FatType, total_clusters: u32) -> io::Result { +pub(crate) fn count_free_clusters(fat: &mut T, fat_type: FatType, total_clusters: u32) -> io::Result { let end_cluster = total_clusters + RESERVED_FAT_ENTRIES; match fat_type { FatType::Fat12 => Fat12::count_free(fat, end_cluster), @@ -115,7 +114,7 @@ pub(crate) fn count_free_clusters(fat: &mut ReadSeek, fat_type: FatType, total_c } impl FatTrait for Fat12 { - fn get_raw(fat: &mut ReadSeek, cluster: u32) -> io::Result { + fn get_raw(fat: &mut T, cluster: u32) -> io::Result { let fat_offset = cluster + (cluster / 2); fat.seek(io::SeekFrom::Start(fat_offset as u64))?; let packed_val = fat.read_u16::()?; @@ -125,7 +124,7 @@ impl FatTrait for Fat12 { } as u32) } - fn get(fat: &mut ReadSeek, cluster: u32) -> io::Result { + fn get(fat: &mut T, cluster: u32) -> io::Result { let val = Self::get_raw(fat, cluster)?; Ok(match val { 0 => FatValue::Free, @@ -135,7 +134,7 @@ impl FatTrait for Fat12 { }) } - fn set(fat: &mut DiskSlice, cluster: u32, value: FatValue) -> io::Result<()> { + fn set(fat: &mut T, cluster: u32, value: FatValue) -> io::Result<()> { let raw_val = match value { FatValue::Free => 0, FatValue::Bad => 0xFF7, @@ -154,7 +153,7 @@ impl FatTrait for Fat12 { Ok(()) } - fn find_free(fat: &mut ReadSeek, start_cluster: u32, end_cluster: u32) -> io::Result { + fn find_free(fat: &mut T, start_cluster: u32, end_cluster: u32) -> io::Result { let mut cluster = start_cluster; let fat_offset = cluster + (cluster / 2); fat.seek(io::SeekFrom::Start(fat_offset as u64))?; @@ -181,7 +180,7 @@ impl FatTrait for Fat12 { } } - fn count_free(fat: &mut ReadSeek, end_cluster: u32) -> io::Result { + fn count_free(fat: &mut T, end_cluster: u32) -> io::Result { let mut count = 0; let mut cluster = RESERVED_FAT_ENTRIES; fat.seek(io::SeekFrom::Start((cluster*3/2) as u64))?; @@ -211,12 +210,12 @@ impl FatTrait for Fat12 { } impl FatTrait for Fat16 { - fn get_raw(fat: &mut ReadSeek, cluster: u32) -> io::Result { + fn get_raw(fat: &mut T, cluster: u32) -> io::Result { fat.seek(io::SeekFrom::Start((cluster*2) as u64))?; Ok(fat.read_u16::()? as u32) } - fn get(fat: &mut ReadSeek, cluster: u32) -> io::Result { + fn get(fat: &mut T, cluster: u32) -> io::Result { let val = Self::get_raw(fat, cluster)?; Ok(match val { 0 => FatValue::Free, @@ -226,7 +225,7 @@ impl FatTrait for Fat16 { }) } - fn set(fat: &mut DiskSlice, cluster: u32, value: FatValue) -> io::Result<()> { + fn set(fat: &mut T, cluster: u32, value: FatValue) -> io::Result<()> { fat.seek(io::SeekFrom::Start((cluster*2) as u64))?; let raw_val = match value { FatValue::Free => 0, @@ -238,7 +237,7 @@ impl FatTrait for Fat16 { Ok(()) } - fn find_free(fat: &mut ReadSeek, start_cluster: u32, end_cluster: u32) -> io::Result { + fn find_free(fat: &mut T, start_cluster: u32, end_cluster: u32) -> io::Result { let mut cluster = start_cluster; fat.seek(io::SeekFrom::Start((cluster*2) as u64))?; while cluster < end_cluster { @@ -251,7 +250,7 @@ impl FatTrait for Fat16 { Err(io::Error::new(io::ErrorKind::Other, "end of FAT reached")) } - fn count_free(fat: &mut ReadSeek, end_cluster: u32) -> io::Result { + fn count_free(fat: &mut T, end_cluster: u32) -> io::Result { let mut count = 0; let mut cluster = RESERVED_FAT_ENTRIES; fat.seek(io::SeekFrom::Start((cluster*2) as u64))?; @@ -269,12 +268,12 @@ impl FatTrait for Fat16 { } impl FatTrait for Fat32 { - fn get_raw(fat: &mut ReadSeek, cluster: u32) -> io::Result { + fn get_raw(fat: &mut T, cluster: u32) -> io::Result { fat.seek(io::SeekFrom::Start((cluster*4) as u64))?; Ok(fat.read_u32::()? & 0x0FFFFFFF) } - fn get(fat: &mut ReadSeek, cluster: u32) -> io::Result { + fn get(fat: &mut T, cluster: u32) -> io::Result { let val = Self::get_raw(fat, cluster)?; Ok(match val { 0 => FatValue::Free, @@ -284,7 +283,7 @@ impl FatTrait for Fat32 { }) } - fn set(fat: &mut DiskSlice, cluster: u32, value: FatValue) -> io::Result<()> { + fn set(fat: &mut T, cluster: u32, value: FatValue) -> io::Result<()> { fat.seek(io::SeekFrom::Start((cluster*4) as u64))?; let raw_val = match value { FatValue::Free => 0, @@ -296,7 +295,7 @@ impl FatTrait for Fat32 { Ok(()) } - fn find_free(fat: &mut ReadSeek, start_cluster: u32, end_cluster: u32) -> io::Result { + fn find_free(fat: &mut T, start_cluster: u32, end_cluster: u32) -> io::Result { let mut cluster = start_cluster; fat.seek(io::SeekFrom::Start((cluster*4) as u64))?; while cluster < end_cluster { @@ -309,7 +308,7 @@ impl FatTrait for Fat32 { Err(io::Error::new(io::ErrorKind::Other, "end of FAT reached")) } - fn count_free(fat: &mut ReadSeek, end_cluster: u32) -> io::Result { + fn count_free(fat: &mut T, end_cluster: u32) -> io::Result { let mut count = 0; let mut cluster = RESERVED_FAT_ENTRIES; fat.seek(io::SeekFrom::Start((cluster*4) as u64))?; @@ -326,15 +325,15 @@ impl FatTrait for Fat32 { } } -pub(crate) struct ClusterIterator<'a, 'b: 'a> { - fat: DiskSlice<'a, 'b>, +pub(crate) struct ClusterIterator { + fat: T, fat_type: FatType, cluster: Option, err: bool, } -impl <'a, 'b> ClusterIterator<'a, 'b> { - pub(crate) fn new(fat: DiskSlice<'a, 'b>, fat_type: FatType, cluster: u32) -> Self { +impl ClusterIterator { + pub(crate) fn new(fat: T, fat_type: FatType, cluster: u32) -> Self { ClusterIterator { fat, fat_type, @@ -368,7 +367,7 @@ impl <'a, 'b> ClusterIterator<'a, 'b> { } } -impl <'a, 'b> Iterator for ClusterIterator<'a, 'b> { +impl Iterator for ClusterIterator { type Item = io::Result; fn next(&mut self) -> Option { diff --git a/tests/read.rs b/tests/read.rs index e770f9c..2c37257 100644 --- a/tests/read.rs +++ b/tests/read.rs @@ -6,24 +6,26 @@ use std::io::SeekFrom; use std::io::prelude::*; use std::str; -use fatfs::{FileSystem, FsOptions, FatType, DirEntry, BufStream}; +use fatfs::{FsOptions, FatType, BufStream}; const TEST_TEXT: &str = "Rust is cool!\n"; const FAT12_IMG: &str = "resources/fat12.img"; const FAT16_IMG: &str = "resources/fat16.img"; const FAT32_IMG: &str = "resources/fat32.img"; +type FileSystem = fatfs::FileSystem>; + fn call_with_fs(f: &Fn(FileSystem) -> (), filename: &str) { let _ = env_logger::try_init(); let file = fs::File::open(filename).unwrap(); - let mut buf_file = BufStream::new(file); - let fs = FileSystem::new(&mut buf_file, FsOptions::new()).unwrap(); + let buf_file = BufStream::new(file); + let fs = FileSystem::new(buf_file, FsOptions::new()).unwrap(); f(fs); } fn test_root_dir(fs: FileSystem) { let root_dir = fs.root_dir(); - let entries = root_dir.iter().map(|r| r.unwrap()).collect::>(); + let entries = root_dir.iter().map(|r| r.unwrap()).collect::>(); let short_names = entries.iter().map(|e| e.short_file_name()).collect::>(); assert_eq!(short_names, ["LONG.TXT", "SHORT.TXT", "VERY", "VERY-L~1"]); let names = entries.iter().map(|e| e.file_name()).collect::>(); diff --git a/tests/write.rs b/tests/write.rs index 4817523..0ec0651 100644 --- a/tests/write.rs +++ b/tests/write.rs @@ -6,7 +6,7 @@ use std::io::prelude::*; use std::io; use std::str; -use fatfs::{FileSystem, FsOptions, BufStream}; +use fatfs::{FsOptions, BufStream}; const FAT12_IMG: &str = "fat12.img"; const FAT16_IMG: &str = "fat16.img"; @@ -16,6 +16,8 @@ const TMP_DIR: &str = "tmp"; const TEST_STR: &str = "Hi there Rust programmer!\n"; const TEST_STR2: &str = "Rust is cool!\n"; +type FileSystem = fatfs::FileSystem>; + fn call_with_fs(f: &Fn(FileSystem) -> (), filename: &str, test_seq: u32) { let _ = env_logger::try_init(); let img_path = format!("{}/{}", IMG_DIR, filename); @@ -24,9 +26,9 @@ fn call_with_fs(f: &Fn(FileSystem) -> (), filename: &str, test_seq: u32) { fs::copy(&img_path, &tmp_path).unwrap(); { let file = fs::OpenOptions::new().read(true).write(true).open(&tmp_path).unwrap(); - let mut buf_file = BufStream::new(file); - let options = FsOptions::new().update_accessed_date(true).update_fs_info(true); - let fs = FileSystem::new(&mut buf_file, options).unwrap(); + let buf_file = BufStream::new(file); + let options = FsOptions::new().update_accessed_date(true); + let fs = FileSystem::new(buf_file, options).unwrap(); f(fs); } fs::remove_file(tmp_path).unwrap();