From 6e8dc9114fb261176a4c03639c02e7d748e08cb7 Mon Sep 17 00:00:00 2001 From: Koichi Imai Date: Fri, 4 Jul 2025 19:03:35 +0900 Subject: [PATCH 1/3] add Debug for fatfs Signed-off-by: Koichi Imai --- awkernel_lib/src/file/fatfs/dir.rs | 44 +++++++++++++-------- awkernel_lib/src/file/fatfs/dir_entry.rs | 10 ++--- awkernel_lib/src/file/fatfs/file.rs | 22 ++++++----- awkernel_lib/src/file/fatfs/fs.rs | 50 ++++++++++++++++++------ awkernel_lib/src/file/memfs.rs | 8 ++++ 5 files changed, 91 insertions(+), 43 deletions(-) diff --git a/awkernel_lib/src/file/fatfs/dir.rs b/awkernel_lib/src/file/fatfs/dir.rs index 5559f3d54..a197c3f77 100644 --- a/awkernel_lib/src/file/fatfs/dir.rs +++ b/awkernel_lib/src/file/fatfs/dir.rs @@ -23,12 +23,12 @@ use super::time::TimeProvider; #[cfg(feature = "lfn")] const LFN_PADDING: u16 = 0xFFFF; -pub(crate) enum DirRawStream { +pub(crate) enum DirRawStream { File(File), Root(DiskSlice, FsIoAdapter>), } -impl DirRawStream { +impl DirRawStream { fn abs_pos(&self) -> Option { match self { DirRawStream::File(file) => file.abs_pos(), @@ -52,7 +52,7 @@ impl DirRawStream { } // Note: derive cannot be used because of invalid bounds. See: https://github.com/rust-lang/rust/issues/26925 -impl Clone for DirRawStream { +impl Clone for DirRawStream { fn clone(&self) -> Self { match self { DirRawStream::File(file) => DirRawStream::File(file.clone()), @@ -61,11 +61,13 @@ impl Clone for DirRawStream { } } -impl IoBase for DirRawStream { +impl IoBase for DirRawStream { type Error = Error; } -impl Read for DirRawStream { +impl Read + for DirRawStream +{ fn read(&mut self, buf: &mut [u8]) -> Result { match self { DirRawStream::File(file) => file.read(buf), @@ -74,7 +76,9 @@ impl Read for DirRawStream Write for DirRawStream { +impl Write + for DirRawStream +{ fn write(&mut self, buf: &[u8]) -> Result { match self { DirRawStream::File(file) => file.write(buf), @@ -89,7 +93,7 @@ impl Write for DirRawStream Seek for DirRawStream { +impl Seek for DirRawStream { fn seek(&mut self, pos: SeekFrom) -> Result { match self { DirRawStream::File(file) => file.seek(pos), @@ -105,7 +109,7 @@ fn split_path(path: &str) -> (&str, Option<&str>) { }) } -enum DirEntryOrShortName { +enum DirEntryOrShortName { DirEntry(DirEntry), ShortName([u8; SFN_SIZE]), } @@ -114,12 +118,12 @@ enum DirEntryOrShortName { /// /// 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 { +pub struct Dir { stream: DirRawStream, fs: Arc>, } -impl Dir { +impl Dir { pub(crate) fn new(stream: DirRawStream, fs: Arc>) -> Self { Dir { stream, fs } } @@ -132,7 +136,9 @@ impl Dir { } } -impl Dir { +impl + Dir +{ pub fn find_entry( &self, name: &str, @@ -619,7 +625,9 @@ impl Dir Clone for Dir { +impl Clone + for Dir +{ fn clone(&self) -> Self { Self { stream: self.stream.clone(), @@ -631,14 +639,14 @@ impl Clone for /// An iterator over the directory entries. /// /// This struct is created by the `iter` method on `Dir`. -pub struct DirIter { +pub struct DirIter { stream: DirRawStream, fs: Arc>, skip_volume: bool, err: bool, } -impl DirIter { +impl DirIter { fn new( stream: DirRawStream, fs: Arc>, @@ -653,7 +661,7 @@ impl DirIter { } } -impl DirIter { +impl DirIter { fn should_skip_entry(&self, raw_entry: &DirEntryData) -> bool { if raw_entry.is_deleted() { return true; @@ -720,7 +728,7 @@ impl DirIter { } // Note: derive cannot be used because of invalid bounds. See: https://github.com/rust-lang/rust/issues/26925 -impl Clone for DirIter { +impl Clone for DirIter { fn clone(&self) -> Self { Self { stream: self.stream.clone(), @@ -731,7 +739,9 @@ impl Clone for DirIter { } } -impl Iterator for DirIter { +impl Iterator + for DirIter +{ type Item = Result, Error>; fn next(&mut self) -> Option { diff --git a/awkernel_lib/src/file/fatfs/dir_entry.rs b/awkernel_lib/src/file/fatfs/dir_entry.rs index a6e8a6fe0..876ef51ef 100644 --- a/awkernel_lib/src/file/fatfs/dir_entry.rs +++ b/awkernel_lib/src/file/fatfs/dir_entry.rs @@ -523,7 +523,7 @@ impl DirEntryEditor { } } - pub(crate) fn flush( + pub(crate) fn flush( &mut self, fs: &FileSystem, ) -> Result<(), IO::Error> { @@ -534,7 +534,7 @@ impl DirEntryEditor { Ok(()) } - fn write( + fn write( &self, fs: &FileSystem, ) -> Result<(), IO::Error> { @@ -549,7 +549,7 @@ impl DirEntryEditor { /// /// `DirEntry` is returned by `DirIter` when reading a directory. #[derive(Clone)] -pub struct DirEntry { +pub struct DirEntry { pub(crate) data: DirFileEntryData, pub(crate) short_name: ShortName, #[cfg(feature = "lfn")] @@ -560,7 +560,7 @@ pub struct DirEntry { } #[allow(clippy::len_without_is_empty)] -impl DirEntry { +impl DirEntry { /// Returns short file name. /// /// Non-ASCII characters are replaced by the replacement character (U+FFFD). @@ -735,7 +735,7 @@ impl DirEntry { } } -impl fmt::Debug for DirEntry { +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 3369869af..13e0d6818 100644 --- a/awkernel_lib/src/file/fatfs/file.rs +++ b/awkernel_lib/src/file/fatfs/file.rs @@ -14,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 { +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 @@ -38,7 +38,7 @@ pub struct Extent { pub size: u32, } -impl File { +impl File { pub(crate) fn new( first_cluster: Option, entry: Option, @@ -221,7 +221,7 @@ impl File { } } -impl File { +impl File { fn update_dir_entry_after_write(&mut self) { let offset = self.offset; if let Some(ref mut e) = self.entry { @@ -234,7 +234,7 @@ impl File { } } -impl Drop for File { +impl Drop for File { fn drop(&mut self) { if let Err(err) = self.flush() { log::error!("flush failed {err:?}"); @@ -243,7 +243,7 @@ impl Drop for File { } // Note: derive cannot be used because of invalid bounds. See: https://github.com/rust-lang/rust/issues/26925 -impl Clone for File { +impl Clone for File { fn clone(&self) -> Self { File { first_cluster: self.first_cluster, @@ -255,11 +255,13 @@ impl Clone for File { } } -impl IoBase for File { +impl IoBase for File { type Error = Error; } -impl Read for File { +impl Read + for File +{ fn read(&mut self, buf: &mut [u8]) -> Result { log::trace!("File::read"); let cluster_size = self.fs.cluster_size(); @@ -314,7 +316,9 @@ impl Read for File } } -impl Write for File { +impl Write + for File +{ fn write(&mut self, buf: &[u8]) -> Result { log::trace!("File::write"); let cluster_size = self.fs.cluster_size(); @@ -388,7 +392,7 @@ impl Write for File Seek for File { +impl Seek for File { fn seek(&mut self, pos: SeekFrom) -> Result { log::trace!("File::seek"); let size_opt = self.size(); diff --git a/awkernel_lib/src/file/fatfs/fs.rs b/awkernel_lib/src/file/fatfs/fs.rs index 031769b87..7ec65f942 100644 --- a/awkernel_lib/src/file/fatfs/fs.rs +++ b/awkernel_lib/src/file/fatfs/fs.rs @@ -328,8 +328,11 @@ impl FileSystemStats { /// A FAT filesystem object. /// /// `FileSystem` struct is representing a state of a mounted FAT volume. -pub struct FileSystem -{ +pub struct FileSystem< + IO: ReadWriteSeek + Send + Debug, + TP = DefaultTimeProvider, + OCC = LossyOemCpConverter, +> { pub(crate) disk: Mutex, pub(crate) options: FsOptions, fat_type: FatType, @@ -341,6 +344,27 @@ pub struct FileSystem, } +impl Debug for FileSystem +where + IO: ReadWriteSeek + Send + Debug, + TP: Debug, + OCC: Debug, +{ + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + f.debug_struct("FileSystem") + .field("disk", &" disk") + .field("options", &self.options) + .field("fat_type", &self.fat_type) + .field("bpb", &self.bpb) + .field("first_data_sector", &self.first_data_sector) + .field("root_dir_sectors", &self.root_dir_sectors) + .field("total_clusters", &self.total_clusters) + .field("fs_info", &" fs_info") + .field("current_status_flags", &" status flags") + .finish() + } +} + pub trait IntoStorage { fn into_storage(self) -> T; } @@ -351,7 +375,7 @@ impl IntoStorage for T { } } -impl FileSystem { +impl FileSystem { /// Creates a new filesystem object instance. /// /// Supplied `storage` parameter cannot be seeked. If there is a need to read a fragment of disk @@ -686,7 +710,7 @@ impl FileSystem { } } -impl FileSystem { +impl FileSystem { /// Returns a volume label from BPB in the Boot Sector as `String`. /// /// Non-ASCII characters are replaced by the replacement character (U+FFFD). @@ -701,7 +725,9 @@ impl FileSystem } } -impl FileSystem { +impl + FileSystem +{ /// Returns a volume label from root directory as `String`. /// /// It finds file with `VOLUME_ID` attribute and returns its short name. @@ -747,7 +773,7 @@ impl FileSystem } /// `Drop` implementation tries to unmount the filesystem when dropping. -impl Drop for FileSystem { +impl Drop for FileSystem { fn drop(&mut self) { if let Err(err) = self.unmount_internal() { log::error!("unmount failed {err:?}"); @@ -755,15 +781,15 @@ impl Drop for FileSystem { } } -pub(crate) struct FsIoAdapter { +pub(crate) struct FsIoAdapter { fs: Arc>, } -impl IoBase for FsIoAdapter { +impl IoBase for FsIoAdapter { type Error = IO::Error; } -impl Read for FsIoAdapter { +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); @@ -771,7 +797,7 @@ impl Read for FsIoAdapter { } } -impl Write for FsIoAdapter { +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); @@ -790,7 +816,7 @@ impl Write for FsIoAdapter { } } -impl Seek for FsIoAdapter { +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); @@ -799,7 +825,7 @@ impl Seek for FsIoAdapter { } // Note: derive cannot be used because of invalid bounds. See: https://github.com/rust-lang/rust/issues/26925 -impl Clone for FsIoAdapter { +impl Clone for FsIoAdapter { fn clone(&self) -> Self { FsIoAdapter { fs: self.fs.clone(), diff --git a/awkernel_lib/src/file/memfs.rs b/awkernel_lib/src/file/memfs.rs index 3636faf30..a441c728c 100644 --- a/awkernel_lib/src/file/memfs.rs +++ b/awkernel_lib/src/file/memfs.rs @@ -2,9 +2,11 @@ extern crate alloc; use super::error::IoError; use super::io::{IoBase, Read, Seek, SeekFrom, Write}; +use super::vfs::error::VfsIoError; use alloc::{string::String, vec::Vec}; use core::fmt::{self, Debug}; +#[derive(Debug)] pub struct InMemoryDisk { data: Vec, position: u64, @@ -104,3 +106,9 @@ impl IoError for InMemoryDiskError { InMemoryDiskError::WriteZero } } + +impl From for VfsIoError { + fn from(_err: InMemoryDiskError) -> Self { + VfsIoError::OutOfBounds + } +} From 2f9f13bce89b7e0c4f4cf27b126a2fdb34ba8a13 Mon Sep 17 00:00:00 2001 From: Koichi Imai Date: Fri, 4 Jul 2025 19:11:38 +0900 Subject: [PATCH 2/3] fix error Signed-off-by: Koichi Imai --- awkernel_lib/src/file/memfs.rs | 10 ++++++++-- awkernel_lib/src/file/vfs/error.rs | 4 ++++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/awkernel_lib/src/file/memfs.rs b/awkernel_lib/src/file/memfs.rs index a441c728c..7870e5ac2 100644 --- a/awkernel_lib/src/file/memfs.rs +++ b/awkernel_lib/src/file/memfs.rs @@ -108,7 +108,13 @@ impl IoError for InMemoryDiskError { } impl From for VfsIoError { - fn from(_err: InMemoryDiskError) -> Self { - VfsIoError::OutOfBounds + fn from(err: InMemoryDiskError) -> Self { + match err { + InMemoryDiskError::OutOfBounds => VfsIoError::OutOfBounds, + InMemoryDiskError::WriteZero => VfsIoError::WriteZero, + InMemoryDiskError::UnexpectedEof => VfsIoError::UnexpectedEof, + InMemoryDiskError::Interrupted => VfsIoError::Interrupted, + InMemoryDiskError::Other(msg) => VfsIoError::Other(msg), + } } } diff --git a/awkernel_lib/src/file/vfs/error.rs b/awkernel_lib/src/file/vfs/error.rs index c1c31b565..377110b7f 100644 --- a/awkernel_lib/src/file/vfs/error.rs +++ b/awkernel_lib/src/file/vfs/error.rs @@ -143,6 +143,7 @@ pub enum VfsIoError { WriteZero, UnexpectedEof, Interrupted, + Other(String), } impl fmt::Display for VfsIoError { @@ -160,6 +161,9 @@ impl fmt::Display for VfsIoError { VfsIoError::Interrupted => { write!(f, "Operation interrupted") } + VfsIoError::Other(msg) => { + write!(f, "An error occured: {msg}") + } } } } From 537b9fd444ac250d2d9591f1777e333e1a6c7e1a Mon Sep 17 00:00:00 2001 From: Koichi Date: Mon, 7 Jul 2025 12:35:54 +0900 Subject: [PATCH 3/3] fix Signed-off-by: Koichi --- awkernel_lib/src/file/fatfs/dir.rs | 43 ++++++++++-------------- awkernel_lib/src/file/fatfs/dir_entry.rs | 12 +++---- awkernel_lib/src/file/fatfs/file.rs | 23 ++++++------- 3 files changed, 34 insertions(+), 44 deletions(-) diff --git a/awkernel_lib/src/file/fatfs/dir.rs b/awkernel_lib/src/file/fatfs/dir.rs index a197c3f77..16312f182 100644 --- a/awkernel_lib/src/file/fatfs/dir.rs +++ b/awkernel_lib/src/file/fatfs/dir.rs @@ -1,6 +1,7 @@ use alloc::sync::Arc; #[cfg(feature = "lfn")] use alloc::vec::Vec; +use core::fmt::Debug; use core::num; use core::str; #[cfg(feature = "lfn")] @@ -23,12 +24,12 @@ use super::time::TimeProvider; #[cfg(feature = "lfn")] const LFN_PADDING: u16 = 0xFFFF; -pub(crate) enum DirRawStream { +pub(crate) enum DirRawStream { File(File), Root(DiskSlice, FsIoAdapter>), } -impl DirRawStream { +impl DirRawStream { fn abs_pos(&self) -> Option { match self { DirRawStream::File(file) => file.abs_pos(), @@ -52,7 +53,7 @@ impl DirRawStream Clone for DirRawStream { +impl Clone for DirRawStream { fn clone(&self) -> Self { match self { DirRawStream::File(file) => DirRawStream::File(file.clone()), @@ -61,13 +62,11 @@ impl Clone for DirRawStrea } } -impl IoBase for DirRawStream { +impl IoBase for DirRawStream { type Error = Error; } -impl Read - for DirRawStream -{ +impl Read for DirRawStream { fn read(&mut self, buf: &mut [u8]) -> Result { match self { DirRawStream::File(file) => file.read(buf), @@ -76,9 +75,7 @@ impl Read } } -impl Write - for DirRawStream -{ +impl Write for DirRawStream { fn write(&mut self, buf: &[u8]) -> Result { match self { DirRawStream::File(file) => file.write(buf), @@ -93,7 +90,7 @@ impl Write } } -impl Seek for DirRawStream { +impl Seek for DirRawStream { fn seek(&mut self, pos: SeekFrom) -> Result { match self { DirRawStream::File(file) => file.seek(pos), @@ -109,7 +106,7 @@ fn split_path(path: &str) -> (&str, Option<&str>) { }) } -enum DirEntryOrShortName { +enum DirEntryOrShortName { DirEntry(DirEntry), ShortName([u8; SFN_SIZE]), } @@ -118,12 +115,12 @@ enum DirEntryOrShortName { /// /// 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 { +pub struct Dir { stream: DirRawStream, fs: Arc>, } -impl Dir { +impl Dir { pub(crate) fn new(stream: DirRawStream, fs: Arc>) -> Self { Dir { stream, fs } } @@ -136,9 +133,7 @@ impl Dir { } } -impl - Dir -{ +impl Dir { pub fn find_entry( &self, name: &str, @@ -625,7 +620,7 @@ impl Clone +impl Clone for Dir { fn clone(&self) -> Self { @@ -639,14 +634,14 @@ impl { +pub struct DirIter { stream: DirRawStream, fs: Arc>, skip_volume: bool, err: bool, } -impl DirIter { +impl DirIter { fn new( stream: DirRawStream, fs: Arc>, @@ -661,7 +656,7 @@ impl DirIter } } -impl DirIter { +impl DirIter { fn should_skip_entry(&self, raw_entry: &DirEntryData) -> bool { if raw_entry.is_deleted() { return true; @@ -728,7 +723,7 @@ impl DirIter } // Note: derive cannot be used because of invalid bounds. See: https://github.com/rust-lang/rust/issues/26925 -impl Clone for DirIter { +impl Clone for DirIter { fn clone(&self) -> Self { Self { stream: self.stream.clone(), @@ -739,9 +734,7 @@ impl Clone for DirIter Iterator - for DirIter -{ +impl Iterator for DirIter { type Item = Result, Error>; fn next(&mut self) -> Option { diff --git a/awkernel_lib/src/file/fatfs/dir_entry.rs b/awkernel_lib/src/file/fatfs/dir_entry.rs index 876ef51ef..c3047d1f0 100644 --- a/awkernel_lib/src/file/fatfs/dir_entry.rs +++ b/awkernel_lib/src/file/fatfs/dir_entry.rs @@ -3,7 +3,7 @@ use alloc::sync::Arc; use bitflags::bitflags; use core::char; use core::convert::TryInto; -use core::fmt; +use core::fmt::{self, Debug}; #[cfg(not(feature = "unicode"))] use core::iter; @@ -523,7 +523,7 @@ impl DirEntryEditor { } } - pub(crate) fn flush( + pub(crate) fn flush( &mut self, fs: &FileSystem, ) -> Result<(), IO::Error> { @@ -534,7 +534,7 @@ impl DirEntryEditor { Ok(()) } - fn write( + fn write( &self, fs: &FileSystem, ) -> Result<(), IO::Error> { @@ -549,7 +549,7 @@ impl DirEntryEditor { /// /// `DirEntry` is returned by `DirIter` when reading a directory. #[derive(Clone)] -pub struct DirEntry { +pub struct DirEntry { pub(crate) data: DirFileEntryData, pub(crate) short_name: ShortName, #[cfg(feature = "lfn")] @@ -560,7 +560,7 @@ pub struct DirEntry { } #[allow(clippy::len_without_is_empty)] -impl DirEntry { +impl DirEntry { /// Returns short file name. /// /// Non-ASCII characters are replaced by the replacement character (U+FFFD). @@ -735,7 +735,7 @@ impl DirEn } } -impl fmt::Debug for DirEntry { +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 13e0d6818..22f9b8396 100644 --- a/awkernel_lib/src/file/fatfs/file.rs +++ b/awkernel_lib/src/file/fatfs/file.rs @@ -1,5 +1,6 @@ use alloc::sync::Arc; use core::convert::TryFrom; +use core::fmt::Debug; use super::super::io::{IoBase, Read, Seek, SeekFrom, Write}; use super::dir_entry::DirEntryEditor; @@ -14,7 +15,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 { +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 @@ -38,7 +39,7 @@ pub struct Extent { pub size: u32, } -impl File { +impl File { pub(crate) fn new( first_cluster: Option, entry: Option, @@ -221,7 +222,7 @@ impl File { } } -impl File { +impl File { fn update_dir_entry_after_write(&mut self) { let offset = self.offset; if let Some(ref mut e) = self.entry { @@ -234,7 +235,7 @@ impl File Drop for File { +impl Drop for File { fn drop(&mut self) { if let Err(err) = self.flush() { log::error!("flush failed {err:?}"); @@ -243,7 +244,7 @@ impl Drop for File Clone for File { +impl Clone for File { fn clone(&self) -> Self { File { first_cluster: self.first_cluster, @@ -255,13 +256,11 @@ impl Clone for File IoBase for File { +impl IoBase for File { type Error = Error; } -impl Read - for File -{ +impl Read for File { fn read(&mut self, buf: &mut [u8]) -> Result { log::trace!("File::read"); let cluster_size = self.fs.cluster_size(); @@ -316,9 +315,7 @@ impl Read } } -impl Write - for File -{ +impl Write for File { fn write(&mut self, buf: &[u8]) -> Result { log::trace!("File::write"); let cluster_size = self.fs.cluster_size(); @@ -392,7 +389,7 @@ impl Write } } -impl Seek for File { +impl Seek for File { fn seek(&mut self, pos: SeekFrom) -> Result { log::trace!("File::seek"); let size_opt = self.size();