diff --git a/awkernel_lib/src/file/fatfs/dir.rs b/awkernel_lib/src/file/fatfs/dir.rs index 88d207297..a71d3d22e 100644 --- a/awkernel_lib/src/file/fatfs/dir.rs +++ b/awkernel_lib/src/file/fatfs/dir.rs @@ -1,3 +1,4 @@ +use alloc::sync::Arc; #[cfg(all(not(feature = "std"), feature = "alloc", feature = "lfn"))] use alloc::vec::Vec; use core::num; @@ -21,12 +22,12 @@ use super::time::TimeProvider; #[cfg(feature = "lfn")] const LFN_PADDING: u16 = 0xFFFF; -pub(crate) enum DirRawStream<'a, IO: ReadWriteSeek + Send + Sync, TP, OCC> { - File(File<'a, IO, TP, OCC>), - Root(DiskSlice, FsIoAdapter<'a, IO, TP, OCC>>), +pub(crate) enum DirRawStream { + File(File), + Root(DiskSlice, FsIoAdapter>), } -impl DirRawStream<'_, IO, TP, OCC> { +impl DirRawStream { fn abs_pos(&self) -> Option { match self { DirRawStream::File(file) => file.abs_pos(), @@ -50,7 +51,7 @@ impl DirRawStream<'_, IO, TP, OCC> { } // Note: derive cannot be used because of invalid bounds. See: https://github.com/rust-lang/rust/issues/26925 -impl Clone for DirRawStream<'_, IO, TP, OCC> { +impl Clone for DirRawStream { fn clone(&self) -> Self { match self { DirRawStream::File(file) => DirRawStream::File(file.clone()), @@ -59,13 +60,11 @@ impl Clone for DirRawStream<'_, IO, TP } } -impl IoBase for DirRawStream<'_, IO, TP, OCC> { +impl IoBase for DirRawStream { type Error = Error; } -impl Read - for DirRawStream<'_, IO, TP, OCC> -{ +impl Read for DirRawStream { fn read(&mut self, buf: &mut [u8]) -> Result { match self { DirRawStream::File(file) => file.read(buf), @@ -74,9 +73,7 @@ impl Read } } -impl Write - for DirRawStream<'_, IO, TP, OCC> -{ +impl Write for DirRawStream { fn write(&mut self, buf: &[u8]) -> Result { match self { DirRawStream::File(file) => file.write(buf), @@ -91,7 +88,7 @@ impl Write } } -impl Seek for DirRawStream<'_, IO, TP, OCC> { +impl Seek for DirRawStream { fn seek(&mut self, pos: SeekFrom) -> Result { match self { DirRawStream::File(file) => file.seek(pos), @@ -107,8 +104,8 @@ fn split_path(path: &str) -> (&str, Option<&str>) { }) } -enum DirEntryOrShortName<'a, IO: ReadWriteSeek + Send + Sync, TP, OCC> { - DirEntry(DirEntry<'a, IO, TP, OCC>), +enum DirEntryOrShortName { + DirEntry(DirEntry), ShortName([u8; SFN_SIZE]), } @@ -116,36 +113,31 @@ enum DirEntryOrShortName<'a, IO: ReadWriteSeek + Send + Sync, TP, OCC> { /// /// This struct is created by the `open_dir` or `create_dir` methods on `Dir`. /// The root directory is returned by the `root_dir` method on `FileSystem`. -pub struct Dir<'a, IO: ReadWriteSeek + Send + Sync, TP, OCC> { - stream: DirRawStream<'a, IO, TP, OCC>, - fs: &'a FileSystem, +pub struct Dir { + stream: DirRawStream, + fs: Arc>, } -impl<'a, IO: ReadWriteSeek + Send + Sync, TP, OCC> Dir<'a, IO, TP, OCC> { - pub(crate) fn new( - stream: DirRawStream<'a, IO, TP, OCC>, - fs: &'a FileSystem, - ) -> Self { +impl Dir { + pub(crate) fn new(stream: DirRawStream, fs: Arc>) -> Self { Dir { stream, fs } } /// Creates directory entries iterator. #[must_use] #[allow(clippy::iter_not_returning_iterator)] - pub fn iter(&self) -> DirIter<'a, IO, TP, OCC> { - DirIter::new(self.stream.clone(), self.fs, true) + pub fn iter(&self) -> DirIter { + DirIter::new(self.stream.clone(), self.fs.clone(), true) } } -impl<'a, IO: ReadWriteSeek + Send + Sync, TP: TimeProvider, OCC: OemCpConverter> - Dir<'a, IO, TP, OCC> -{ +impl Dir { fn find_entry( &self, name: &str, is_dir: Option, mut short_name_gen: Option<&mut ShortNameGenerator>, - ) -> Result, Error> { + ) -> Result, Error> { for r in self.iter() { let e = r?; // compare name ignoring case @@ -172,8 +164,8 @@ impl<'a, IO: ReadWriteSeek + Send + Sync, TP: TimeProvider, OCC: OemCpConverter> #[allow(clippy::type_complexity)] pub(crate) fn find_volume_entry( &self, - ) -> Result>, Error> { - for r in DirIter::new(self.stream.clone(), self.fs, false) { + ) -> Result>, Error> { + for r in DirIter::new(self.stream.clone(), self.fs.clone(), false) { let e = r?; if e.data.is_volume() { return Ok(Some(e)); @@ -186,7 +178,7 @@ impl<'a, IO: ReadWriteSeek + Send + Sync, TP: TimeProvider, OCC: OemCpConverter> &self, name: &str, is_dir: Option, - ) -> Result, Error> { + ) -> Result, Error> { let mut short_name_gen = ShortNameGenerator::new(name); loop { // find matching entry @@ -241,7 +233,7 @@ impl<'a, IO: ReadWriteSeek + Send + Sync, TP: TimeProvider, OCC: OemCpConverter> /// * `Error::NotFound` will be returned if `path` points to a non-existing directory entry. /// * `Error::InvalidInput` will be returned if `path` points to a file that is a directory. /// * `Error::Io` will be returned if the underlying storage object returned an I/O error. - pub fn open_file(&self, path: &str) -> Result, Error> { + pub fn open_file(&self, path: &str) -> Result, Error> { log::trace!("Dir::open_file {path}"); // traverse path let (name, rest_opt) = split_path(path); @@ -268,7 +260,7 @@ impl<'a, IO: ReadWriteSeek + Send + Sync, TP: TimeProvider, OCC: OemCpConverter> /// * `Error::UnsupportedFileNameCharacter` will be returned if the file name contains an invalid character. /// * `Error::NotEnoughSpace` will be returned if there is not enough free space to create a new file. /// * `Error::Io` will be returned if the underlying storage object returned an I/O error. - pub fn create_file(&self, path: &str) -> Result, Error> { + pub fn create_file(&self, path: &str) -> Result, Error> { log::trace!("Dir::create_file {path}"); // traverse path let (name, rest_opt) = split_path(path); @@ -321,7 +313,7 @@ impl<'a, IO: ReadWriteSeek + Send + Sync, TP: TimeProvider, OCC: OemCpConverter> // directory does not exist - create it DirEntryOrShortName::ShortName(short_name) => { // alloc cluster for directory data - let cluster = self.fs.alloc_cluster(None, true)?; + let cluster = FileSystem::alloc_cluster(&self.fs, None, true)?; // create entry in parent directory let sfn_entry = self.create_sfn_entry(short_name, FileAttributes::DIRECTORY, Some(cluster)); @@ -395,7 +387,7 @@ impl<'a, IO: ReadWriteSeek + Send + Sync, TP: TimeProvider, OCC: OemCpConverter> } // free data if let Some(n) = e.first_cluster() { - self.fs.free_cluster_chain(n)?; + FileSystem::free_cluster_chain(&self.fs, n)?; } // free long and short name entries let mut stream = self.stream.clone(); @@ -495,7 +487,7 @@ impl<'a, IO: ReadWriteSeek + Send + Sync, TP: TimeProvider, OCC: OemCpConverter> fn find_free_entries( &self, num_entries: u32, - ) -> Result, Error> { + ) -> Result, Error> { let mut stream = self.stream.clone(); let mut first_free: u32 = 0; let mut num_free: u32 = 0; @@ -559,7 +551,7 @@ impl<'a, IO: ReadWriteSeek + Send + Sync, TP: TimeProvider, OCC: OemCpConverter> &self, lfn_utf16: &LfnBuffer, short_name: &[u8; SFN_SIZE], - ) -> Result<(DirRawStream<'a, IO, TP, OCC>, u64), Error> { + ) -> Result<(DirRawStream, u64), Error> { // get short name checksum let lfn_chsum = lfn_checksum(short_name); // create LFN entries generator @@ -576,7 +568,7 @@ impl<'a, IO: ReadWriteSeek + Send + Sync, TP: TimeProvider, OCC: OemCpConverter> } #[allow(clippy::type_complexity)] - fn alloc_sfn_entry(&self) -> Result<(DirRawStream<'a, IO, TP, OCC>, u64), Error> { + fn alloc_sfn_entry(&self) -> Result<(DirRawStream, u64), Error> { let mut stream = self.find_free_entries(1)?; let start_pos = stream.seek(super::super::io::SeekFrom::Current(0))?; Ok((stream, start_pos)) @@ -586,7 +578,7 @@ impl<'a, IO: ReadWriteSeek + Send + Sync, TP: TimeProvider, OCC: OemCpConverter> &self, name: &str, raw_entry: DirFileEntryData, - ) -> Result, Error> { + ) -> Result, Error> { log::trace!("Dir::write_entry {name}"); // check if name doesn't contain unsupported characters validate_long_name(name)?; @@ -618,7 +610,7 @@ impl<'a, IO: ReadWriteSeek + Send + Sync, TP: TimeProvider, OCC: OemCpConverter> short_name, #[cfg(feature = "lfn")] lfn_utf16, - fs: self.fs, + fs: self.fs.clone(), entry_pos: start_abs_pos, offset_range: (start_pos, end_pos), }) @@ -627,12 +619,12 @@ impl<'a, IO: ReadWriteSeek + Send + Sync, TP: TimeProvider, OCC: OemCpConverter> // Note: derive cannot be used because of invalid bounds. See: https://github.com/rust-lang/rust/issues/26925 impl Clone - for Dir<'_, IO, TP, OCC> + for Dir { fn clone(&self) -> Self { Self { stream: self.stream.clone(), - fs: self.fs, + fs: self.fs.clone(), } } } @@ -640,17 +632,17 @@ impl Clo /// An iterator over the directory entries. /// /// This struct is created by the `iter` method on `Dir`. -pub struct DirIter<'a, IO: ReadWriteSeek + Send + Sync, TP, OCC> { - stream: DirRawStream<'a, IO, TP, OCC>, - fs: &'a FileSystem, +pub struct DirIter { + stream: DirRawStream, + fs: Arc>, skip_volume: bool, err: bool, } -impl<'a, IO: ReadWriteSeek + Send + Sync, TP, OCC> DirIter<'a, IO, TP, OCC> { +impl DirIter { fn new( - stream: DirRawStream<'a, IO, TP, OCC>, - fs: &'a FileSystem, + stream: DirRawStream, + fs: Arc>, skip_volume: bool, ) -> Self { DirIter { @@ -662,7 +654,7 @@ impl<'a, IO: ReadWriteSeek + Send + Sync, TP, OCC> DirIter<'a, IO, TP, OCC> { } } -impl<'a, IO: ReadWriteSeek + Send + Sync, TP: TimeProvider, OCC> DirIter<'a, IO, TP, OCC> { +impl DirIter { fn should_skip_entry(&self, raw_entry: &DirEntryData) -> bool { if raw_entry.is_deleted() { return true; @@ -674,7 +666,7 @@ impl<'a, IO: ReadWriteSeek + Send + Sync, TP: TimeProvider, OCC> DirIter<'a, IO, } #[allow(clippy::type_complexity)] - fn read_dir_entry(&mut self) -> Result>, Error> { + fn read_dir_entry(&mut self) -> Result>, Error> { log::trace!("DirIter::read_dir_entry"); let mut lfn_builder = LongNameBuilder::new(); let mut offset = self.stream.seek(SeekFrom::Current(0))?; @@ -713,7 +705,7 @@ impl<'a, IO: ReadWriteSeek + Send + Sync, TP: TimeProvider, OCC> DirIter<'a, IO, short_name, #[cfg(feature = "lfn")] lfn_utf16: lfn_builder.into_buf(), - fs: self.fs, + fs: self.fs.clone(), entry_pos: abs_pos, offset_range: (begin_offset, offset), })); @@ -729,21 +721,19 @@ impl<'a, IO: ReadWriteSeek + Send + Sync, TP: TimeProvider, OCC> DirIter<'a, IO, } // Note: derive cannot be used because of invalid bounds. See: https://github.com/rust-lang/rust/issues/26925 -impl Clone for DirIter<'_, IO, TP, OCC> { +impl Clone for DirIter { fn clone(&self) -> Self { Self { stream: self.stream.clone(), - fs: self.fs, + fs: self.fs.clone(), err: self.err, skip_volume: self.skip_volume, } } } -impl<'a, IO: ReadWriteSeek + Send + Sync, TP: TimeProvider, OCC> Iterator - for DirIter<'a, IO, TP, OCC> -{ - type Item = Result, Error>; +impl Iterator for DirIter { + type Item = Result, Error>; fn next(&mut self) -> Option { if self.err { diff --git a/awkernel_lib/src/file/fatfs/dir_entry.rs b/awkernel_lib/src/file/fatfs/dir_entry.rs index 99faacdc5..845fa2d5a 100644 --- a/awkernel_lib/src/file/fatfs/dir_entry.rs +++ b/awkernel_lib/src/file/fatfs/dir_entry.rs @@ -1,5 +1,6 @@ #[cfg(all(not(feature = "std"), feature = "alloc"))] use alloc::string::String; +use alloc::sync::Arc; use bitflags::bitflags; use core::char; use core::convert::TryInto; @@ -552,18 +553,18 @@ impl DirEntryEditor { /// /// `DirEntry` is returned by `DirIter` when reading a directory. #[derive(Clone)] -pub struct DirEntry<'a, IO: ReadWriteSeek + Send + Sync, TP, OCC> { +pub struct DirEntry { pub(crate) data: DirFileEntryData, pub(crate) short_name: ShortName, #[cfg(feature = "lfn")] pub(crate) lfn_utf16: LfnBuffer, pub(crate) entry_pos: u64, pub(crate) offset_range: (u64, u64), - pub(crate) fs: &'a FileSystem, + pub(crate) fs: Arc>, } #[allow(clippy::len_without_is_empty)] -impl<'a, IO: ReadWriteSeek + Send + Sync, TP, OCC: OemCpConverter> DirEntry<'a, IO, TP, OCC> { +impl DirEntry { /// Returns short file name. /// /// Non-ASCII characters are replaced by the replacement character (U+FFFD). @@ -647,9 +648,9 @@ impl<'a, IO: ReadWriteSeek + Send + Sync, TP, OCC: OemCpConverter> DirEntry<'a, /// /// Will panic if this is not a file. #[must_use] - pub fn to_file(&self) -> File<'a, IO, TP, OCC> { + pub fn to_file(&self) -> File { assert!(!self.is_dir(), "Not a file entry"); - File::new(self.first_cluster(), Some(self.editor()), self.fs) + File::new(self.first_cluster(), Some(self.editor()), self.fs.clone()) } /// Returns `Dir` struct for this entry. @@ -658,14 +659,14 @@ impl<'a, IO: ReadWriteSeek + Send + Sync, TP, OCC: OemCpConverter> DirEntry<'a, /// /// Will panic if this is not a directory. #[must_use] - pub fn to_dir(&self) -> Dir<'a, IO, TP, OCC> { + pub fn to_dir(&self) -> Dir { assert!(self.is_dir(), "Not a directory entry"); match self.first_cluster() { Some(n) => { - let file = File::new(Some(n), Some(self.editor()), self.fs); - Dir::new(DirRawStream::File(file), self.fs) + let file = File::new(Some(n), Some(self.editor()), self.fs.clone()); + Dir::new(DirRawStream::File(file), self.fs.clone()) } - None => self.fs.root_dir(), + None => FileSystem::root_dir(&self.fs), } } @@ -740,7 +741,7 @@ impl<'a, IO: ReadWriteSeek + Send + Sync, TP, OCC: OemCpConverter> DirEntry<'a, } } -impl fmt::Debug for DirEntry<'_, IO, TP, OCC> { +impl fmt::Debug for DirEntry { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { self.data.fmt(f) } diff --git a/awkernel_lib/src/file/fatfs/file.rs b/awkernel_lib/src/file/fatfs/file.rs index 1f1560a9d..61f6127ff 100644 --- a/awkernel_lib/src/file/fatfs/file.rs +++ b/awkernel_lib/src/file/fatfs/file.rs @@ -1,3 +1,4 @@ +use alloc::sync::Arc; use core::convert::TryFrom; use super::super::error::Error; @@ -13,7 +14,7 @@ const MAX_FILE_SIZE: u32 = u32::MAX; /// A FAT filesystem file object used for reading and writing data. /// /// This struct is created by the `open_file` or `create_file` methods on `Dir`. -pub struct File<'a, IO: ReadWriteSeek + Send + Sync, TP, OCC> { +pub struct File { // Note first_cluster is None if file is empty first_cluster: Option, // Note: if offset points between clusters current_cluster is the previous cluster @@ -23,7 +24,7 @@ pub struct File<'a, IO: ReadWriteSeek + Send + Sync, TP, OCC> { // file dir entry editor - None for root dir entry: Option, // file-system reference - fs: &'a FileSystem, + fs: Arc>, } /// An extent containing a file's data on disk. @@ -37,11 +38,11 @@ pub struct Extent { pub size: u32, } -impl<'a, IO: ReadWriteSeek + Send + Sync, TP, OCC> File<'a, IO, TP, OCC> { +impl File { pub(crate) fn new( first_cluster: Option, entry: Option, - fs: &'a FileSystem, + fs: Arc>, ) -> Self { File { first_cluster, @@ -75,11 +76,11 @@ impl<'a, IO: ReadWriteSeek + Send + Sync, TP, OCC> File<'a, IO, TP, OCC> { if let Some(current_cluster) = self.current_cluster { // current cluster is none only if offset is 0 debug_assert!(self.offset > 0); - self.fs.truncate_cluster_chain(current_cluster) + FileSystem::truncate_cluster_chain(&self.fs, current_cluster) } else { debug_assert!(self.offset == 0); if let Some(n) = self.first_cluster { - self.fs.free_cluster_chain(n)?; + FileSystem::free_cluster_chain(&self.fs, n)?; self.first_cluster = None; } Ok(()) @@ -90,8 +91,8 @@ impl<'a, IO: ReadWriteSeek + Send + Sync, TP, OCC> File<'a, IO, TP, OCC> { /// /// This returns an iterator over the byte ranges on-disk occupied by /// this file. - pub fn extents(&mut self) -> impl Iterator>> + 'a { - let fs = self.fs; + pub fn extents(&mut self) -> impl Iterator>> + '_ { + let fs = &self.fs; let cluster_size = fs.cluster_size(); let Some(mut bytes_left) = self.size() else { return None.into_iter().flatten(); @@ -102,7 +103,7 @@ impl<'a, IO: ReadWriteSeek + Send + Sync, TP, OCC> File<'a, IO, TP, OCC> { Some( core::iter::once(Ok(first)) - .chain(fs.cluster_iter(first)) + .chain(FileSystem::cluster_iter(fs, first)) .map(move |cluster_err| match cluster_err { Ok(cluster) => { let size = cluster_size.min(bytes_left); @@ -142,7 +143,7 @@ impl<'a, IO: ReadWriteSeek + Send + Sync, TP, OCC> File<'a, IO, TP, OCC> { fn flush_dir_entry(&mut self) -> Result<(), Error> { if let Some(ref mut e) = self.entry { - e.flush(self.fs)?; + e.flush(&self.fs)?; } Ok(()) } @@ -220,7 +221,7 @@ impl<'a, IO: ReadWriteSeek + Send + Sync, TP, OCC> File<'a, IO, TP, OCC> { } } -impl File<'_, IO, TP, OCC> { +impl File { fn update_dir_entry_after_write(&mut self) { let offset = self.offset; if let Some(ref mut e) = self.entry { @@ -233,7 +234,7 @@ impl File<'_, IO, TP, OC } } -impl Drop for File<'_, IO, TP, OCC> { +impl Drop for File { fn drop(&mut self) { if let Err(err) = self.flush() { log::error!("flush failed {err:?}"); @@ -242,23 +243,23 @@ impl Drop for File<'_, IO, TP, OCC> { } // Note: derive cannot be used because of invalid bounds. See: https://github.com/rust-lang/rust/issues/26925 -impl Clone for File<'_, IO, TP, OCC> { +impl Clone for File { 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, + fs: Arc::clone(&self.fs), } } } -impl IoBase for File<'_, IO, TP, OCC> { +impl IoBase for File { type Error = Error; } -impl Read for File<'_, IO, TP, OCC> { +impl Read for File { fn read(&mut self, buf: &mut [u8]) -> Result { log::trace!("File::read"); let cluster_size = self.fs.cluster_size(); @@ -267,7 +268,7 @@ impl Read for File<'_, I match self.current_cluster { None => self.first_cluster, Some(n) => { - let r = self.fs.cluster_iter(n).next(); + let r = FileSystem::cluster_iter(&self.fs, n).next(); match r { Some(Err(err)) => return Err(err), Some(Ok(n)) => Some(n), @@ -314,7 +315,7 @@ impl Read for File<'_, I } #[cfg(feature = "std")] -impl std::io::Read for File<'_, IO, TP, OCC> +impl std::io::Read for File where std::io::Error: From>, { @@ -323,7 +324,7 @@ where } } -impl Write for File<'_, IO, TP, OCC> { +impl Write for File { fn write(&mut self, buf: &[u8]) -> Result { log::trace!("File::write"); let cluster_size = self.fs.cluster_size(); @@ -346,7 +347,7 @@ impl Write for File<'_, let next_cluster = match self.current_cluster { None => self.first_cluster, Some(n) => { - let r = self.fs.cluster_iter(n).next(); + let r = FileSystem::cluster_iter(&self.fs, n).next(); match r { Some(Err(err)) => return Err(err), Some(Ok(n)) => Some(n), @@ -358,7 +359,8 @@ impl Write for File<'_, n } else { // end of chain reached - allocate new cluster - let new_cluster = self.fs.alloc_cluster(self.current_cluster, self.is_dir())?; + let new_cluster = + FileSystem::alloc_cluster(&self.fs, self.current_cluster, self.is_dir())?; log::trace!("allocated cluster {new_cluster}"); if self.first_cluster.is_none() { self.set_first_cluster(new_cluster); @@ -397,8 +399,7 @@ impl Write for File<'_, } #[cfg(feature = "std")] -impl std::io::Write - for File<'_, IO, TP, OCC> +impl std::io::Write for File where std::io::Error: From>, { @@ -415,7 +416,7 @@ where } } -impl Seek for File<'_, IO, TP, OCC> { +impl Seek for File { fn seek(&mut self, pos: SeekFrom) -> Result { log::trace!("File::seek"); let size_opt = self.size(); @@ -461,7 +462,7 @@ impl Seek for File<'_, IO, TP, OCC> { debug_assert!(new_offset_in_clusters > 0); let clusters_to_skip = new_offset_in_clusters - 1; let mut cluster = first_cluster; - let mut iter = self.fs.cluster_iter(first_cluster); + let mut iter = FileSystem::cluster_iter(&self.fs, first_cluster); for i in 0..clusters_to_skip { cluster = if let Some(r) = iter.next() { r? @@ -484,7 +485,7 @@ impl Seek for File<'_, IO, TP, OCC> { } #[cfg(feature = "std")] -impl std::io::Seek for File<'_, IO, TP, OCC> +impl std::io::Seek for File where std::io::Error: From>, { diff --git a/awkernel_lib/src/file/fatfs/fs.rs b/awkernel_lib/src/file/fatfs/fs.rs index 29d8bf017..2a82abe27 100644 --- a/awkernel_lib/src/file/fatfs/fs.rs +++ b/awkernel_lib/src/file/fatfs/fs.rs @@ -1,5 +1,6 @@ #[cfg(all(not(feature = "std"), feature = "alloc"))] use alloc::string::String; +use alloc::sync::Arc; use core::borrow::BorrowMut; use core::convert::TryFrom; use core::fmt::Debug; @@ -489,39 +490,42 @@ impl FileSystem { self.bpb.clusters_from_bytes(bytes) } - fn fat_slice(&self) -> impl ReadWriteSeek> + '_ { - let io = FsIoAdapter { fs: self }; - fat_slice(io, &self.bpb) + fn fat_slice(fs: &Arc) -> impl ReadWriteSeek> + '_ { + let io = FsIoAdapter { fs: Arc::clone(fs) }; + fat_slice(io, &fs.bpb) } pub(crate) fn cluster_iter( - &self, + fs: &Arc, cluster: u32, ) -> ClusterIterator> + '_, IO::Error> { - let disk_slice = self.fat_slice(); - ClusterIterator::new(disk_slice, self.fat_type, cluster) + let disk_slice = FileSystem::fat_slice(fs); + ClusterIterator::new(disk_slice, fs.fat_type, cluster) } - pub(crate) fn truncate_cluster_chain(&self, cluster: u32) -> Result<(), Error> { - let mut iter = self.cluster_iter(cluster); + pub(crate) fn truncate_cluster_chain( + fs: &Arc, + cluster: u32, + ) -> Result<(), Error> { + let mut iter = FileSystem::cluster_iter(fs, cluster); let num_free = iter.truncate()?; let mut node = MCSNode::new(); - let mut fs_info_guard = self.fs_info.lock(&mut node); + let mut fs_info_guard = fs.fs_info.lock(&mut node); fs_info_guard.map_free_clusters(|n| n + num_free); Ok(()) } - pub(crate) fn free_cluster_chain(&self, cluster: u32) -> Result<(), Error> { - let mut iter = self.cluster_iter(cluster); + pub(crate) fn free_cluster_chain(fs: &Arc, cluster: u32) -> Result<(), Error> { + let mut iter = FileSystem::cluster_iter(fs, cluster); let num_free = iter.free()?; let mut node = MCSNode::new(); - let mut fs_info_guard = self.fs_info.lock(&mut node); + let mut fs_info_guard = fs.fs_info.lock(&mut node); fs_info_guard.map_free_clusters(|n| n + num_free); Ok(()) } pub(crate) fn alloc_cluster( - &self, + fs: &Arc, prev_cluster: Option, zero: bool, ) -> Result> { @@ -529,27 +533,21 @@ impl FileSystem { let hint; { let mut node = MCSNode::new(); - let fs_info_guard = self.fs_info.lock(&mut node); + let fs_info_guard = fs.fs_info.lock(&mut node); hint = fs_info_guard.next_free_cluster; } let cluster = { - let mut fat = self.fat_slice(); - alloc_cluster( - &mut fat, - self.fat_type, - prev_cluster, - hint, - self.total_clusters, - )? + let mut fat = FileSystem::fat_slice(fs); + alloc_cluster(&mut fat, fs.fat_type, prev_cluster, hint, fs.total_clusters)? }; if zero { let mut node_disk = MCSNode::new(); - let mut disk_guard = self.disk.lock(&mut node_disk); - disk_guard.seek(SeekFrom::Start(self.offset_from_cluster(cluster)))?; - write_zeros(&mut *disk_guard, u64::from(self.cluster_size()))?; + let mut disk_guard = fs.disk.lock(&mut node_disk); + disk_guard.seek(SeekFrom::Start(fs.offset_from_cluster(cluster)))?; + write_zeros(&mut *disk_guard, u64::from(fs.cluster_size()))?; } let mut node = MCSNode::new(); - let mut fs_info_guard = self.fs_info.lock(&mut node); + let mut fs_info_guard = fs.fs_info.lock(&mut node); fs_info_guard.set_next_free_cluster(cluster + 1); fs_info_guard.map_free_clusters(|n| n - 1); Ok(cluster) @@ -560,9 +558,9 @@ impl FileSystem { /// # Errors /// /// `Error::Io` will be returned if the underlying storage object returned an I/O error. - pub fn read_status_flags(&self) -> Result> { - let bpb_status = self.bpb.status_flags(); - let fat_status = read_fat_flags(&mut self.fat_slice(), self.fat_type)?; + pub fn read_status_flags(fs: &Arc) -> Result> { + let bpb_status = fs.bpb.status_flags(); + let fat_status = read_fat_flags(&mut FileSystem::fat_slice(fs), fs.fat_type)?; Ok(FsStatusFlags { dirty: bpb_status.dirty || fat_status.dirty, io_error: bpb_status.io_error || fat_status.io_error, @@ -577,29 +575,29 @@ impl FileSystem { /// # Errors /// /// `Error::Io` will be returned if the underlying storage object returned an I/O error. - pub fn stats(&self) -> Result> { + pub fn stats(fs: &Arc) -> Result> { let mut node = MCSNode::new(); - let fs_info_guard = self.fs_info.lock(&mut node); + let fs_info_guard = fs.fs_info.lock(&mut node); let free_clusters_option = fs_info_guard.free_cluster_count; drop(fs_info_guard); let free_clusters = if let Some(n) = free_clusters_option { n } else { - self.recalc_free_clusters()? + Self::recalc_free_clusters(fs)? }; Ok(FileSystemStats { - cluster_size: self.cluster_size(), - total_clusters: self.total_clusters, + cluster_size: fs.cluster_size(), + total_clusters: fs.total_clusters, free_clusters, }) } /// Forces free clusters recalculation. - fn recalc_free_clusters(&self) -> Result> { - let mut fat = self.fat_slice(); - let free_cluster_count = count_free_clusters(&mut fat, self.fat_type, self.total_clusters)?; + fn recalc_free_clusters(fs: &Arc) -> Result> { + let mut fat = FileSystem::fat_slice(fs); + let free_cluster_count = count_free_clusters(&mut fat, fs.fat_type, fs.total_clusters)?; let mut node = MCSNode::new(); - let mut fs_info_guard = self.fs_info.lock(&mut node); + let mut fs_info_guard = fs.fs_info.lock(&mut node); fs_info_guard.set_free_cluster_count(free_cluster_count); Ok(free_cluster_count) } @@ -677,23 +675,25 @@ impl FileSystem { } /// Returns a root directory object allowing for futher penetration of a filesystem structure. - pub fn root_dir(&self) -> Dir { + pub fn root_dir(fs: &Arc) -> Dir { log::trace!("root_dir"); let root_rdr = { - match self.fat_type { + match fs.fat_type { FatType::Fat12 | FatType::Fat16 => DirRawStream::Root(DiskSlice::from_sectors( - self.first_data_sector - self.root_dir_sectors, - self.root_dir_sectors, + fs.first_data_sector - fs.root_dir_sectors, + fs.root_dir_sectors, 1, - &self.bpb, - FsIoAdapter { fs: self }, + &fs.bpb, + FsIoAdapter { fs: Arc::clone(fs) }, + )), + FatType::Fat32 => DirRawStream::File(File::new( + Some(fs.bpb.root_dir_first_cluster), + None, + Arc::clone(fs), )), - FatType::Fat32 => { - DirRawStream::File(File::new(Some(self.bpb.root_dir_first_cluster), None, self)) - } } }; - Dir::new(root_rdr, self) + Dir::new(root_rdr, Arc::clone(fs)) } } @@ -724,10 +724,12 @@ impl /// /// `Error::Io` will be returned if the underlying storage object returned an I/O error. #[cfg(feature = "alloc")] - pub fn read_volume_label_from_root_dir(&self) -> Result, Error> { + pub fn read_volume_label_from_root_dir( + fs: &Arc, + ) -> Result, Error> { // Note: DirEntry::file_short_name() cannot be used because it interprets name as 8.3 // (adds dot before an extension) - let volume_label_opt = self.read_volume_label_from_root_dir_as_bytes()?; + let volume_label_opt = FileSystem::read_volume_label_from_root_dir_as_bytes(fs)?; volume_label_opt.map_or(Ok(None), |volume_label| { // Strip label padding let len = volume_label @@ -737,7 +739,7 @@ impl let label_slice = &volume_label[..len]; // Decode volume label from OEM codepage let volume_label_iter = label_slice.iter().copied(); - let char_iter = volume_label_iter.map(|c| self.options.oem_cp_converter.decode(c)); + let char_iter = volume_label_iter.map(|c| fs.options.oem_cp_converter.decode(c)); // Build string from character iterator Ok(Some(char_iter.collect::())) }) @@ -752,9 +754,9 @@ impl /// /// `Error::Io` will be returned if the underlying storage object returned an I/O error. pub fn read_volume_label_from_root_dir_as_bytes( - &self, + fs: &Arc, ) -> Result, Error> { - let entry_opt = self.root_dir().find_volume_entry()?; + let entry_opt = Self::root_dir(fs).find_volume_entry()?; Ok(entry_opt.map(|e| *e.raw_short_name())) } } @@ -768,15 +770,15 @@ impl Drop for FileSystem } } -pub(crate) struct FsIoAdapter<'a, IO: ReadWriteSeek + Send + Sync, TP, OCC> { - fs: &'a FileSystem, +pub(crate) struct FsIoAdapter { + fs: Arc>, } -impl IoBase for FsIoAdapter<'_, IO, TP, OCC> { +impl IoBase for FsIoAdapter { type Error = IO::Error; } -impl Read for FsIoAdapter<'_, IO, TP, OCC> { +impl Read for FsIoAdapter { fn read(&mut self, buf: &mut [u8]) -> Result { let mut node = MCSNode::new(); let mut disk_guard = self.fs.disk.lock(&mut node); @@ -784,7 +786,7 @@ impl Read for FsIoAdapter<'_, IO, TP, } } -impl Write for FsIoAdapter<'_, IO, TP, OCC> { +impl Write for FsIoAdapter { fn write(&mut self, buf: &[u8]) -> Result { let mut node = MCSNode::new(); let mut disk_guard = self.fs.disk.lock(&mut node); @@ -803,7 +805,7 @@ impl Write for FsIoAdapter<'_, IO, TP, } } -impl Seek for FsIoAdapter<'_, IO, TP, OCC> { +impl Seek for FsIoAdapter { fn seek(&mut self, pos: SeekFrom) -> Result { let mut node = MCSNode::new(); let mut disk_guard = self.fs.disk.lock(&mut node); @@ -812,9 +814,11 @@ impl Seek for FsIoAdapter<'_, IO, TP, } // Note: derive cannot be used because of invalid bounds. See: https://github.com/rust-lang/rust/issues/26925 -impl Clone for FsIoAdapter<'_, IO, TP, OCC> { +impl Clone for FsIoAdapter { fn clone(&self) -> Self { - FsIoAdapter { fs: self.fs } + FsIoAdapter { + fs: self.fs.clone(), + } } }