From 6e8dc9114fb261176a4c03639c02e7d748e08cb7 Mon Sep 17 00:00:00 2001 From: Koichi Imai Date: Fri, 4 Jul 2025 19:03:35 +0900 Subject: [PATCH 1/5] 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/5] 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 bdd1a3a19e588808b717ec882a18b664f72402c5 Mon Sep 17 00:00:00 2001 From: Koichi Imai Date: Fri, 4 Jul 2025 19:29:41 +0900 Subject: [PATCH 3/5] add init in memory fatfs Signed-off-by: Koichi Imai --- awkernel_lib/src/allocator.rs | 5 +++ awkernel_lib/src/file/fatfs.rs | 76 ++++++++++++++++++++++++++++++++++ awkernel_lib/src/lib.rs | 1 + 3 files changed, 82 insertions(+) create mode 100644 awkernel_lib/src/allocator.rs diff --git a/awkernel_lib/src/allocator.rs b/awkernel_lib/src/allocator.rs new file mode 100644 index 000000000..545fd998e --- /dev/null +++ b/awkernel_lib/src/allocator.rs @@ -0,0 +1,5 @@ +#[cfg(feature = "std")] +pub use std::alloc::System; + +#[cfg(not(feature = "std"))] +pub use super::heap::TALLOC as System; diff --git a/awkernel_lib/src/file/fatfs.rs b/awkernel_lib/src/file/fatfs.rs index 99a01124c..8980b399f 100644 --- a/awkernel_lib/src/file/fatfs.rs +++ b/awkernel_lib/src/file/fatfs.rs @@ -6,3 +6,79 @@ pub mod file; pub mod fs; pub mod table; pub mod time; + +use crate::{ + allocator::System, + file::{ + fatfs::{ + fs::{format_volume, FileSystem, FormatVolumeOptions, FsOptions, LossyOemCpConverter}, + time::NullTimeProvider, + }, + memfs::InMemoryDisk, + }, + paging::PAGESIZE, + sync::rwlock::RwLock, +}; + +use alloc::{sync::Arc, vec::Vec}; +use core::alloc::{GlobalAlloc, Layout}; + +pub const MEMORY_FILESYSTEM_SIZE: usize = 1024 * 1024; + +static FAT_FS_INSTANCE: RwLock< + Option>>, +> = RwLock::new(None); + +pub fn init_memory_fatfs() -> Result<(), &'static str> { + let mut fs_guard = FAT_FS_INSTANCE.write(); + if fs_guard.is_some() { + return Err("FAT filesystem has already been initialized."); + } + + let disk_layout = Layout::from_size_align(MEMORY_FILESYSTEM_SIZE, PAGESIZE) + .map_err(|_| "Invalid layout for memory filesystem allocation.")?; + + let raw_disk_memory = unsafe { System.alloc(disk_layout) }; + if raw_disk_memory.is_null() { + return Err("Failed to allocate memory for the in-memory disk."); + } + + let disk_data = unsafe { + Vec::from_raw_parts( + raw_disk_memory, + MEMORY_FILESYSTEM_SIZE, + MEMORY_FILESYSTEM_SIZE, + ) + }; + + let mut in_memory_disk = InMemoryDisk::new(disk_data, 0); + + log::info!("Attempting to format FAT filesystem in memory..."); + match format_volume(&mut in_memory_disk, FormatVolumeOptions::new()) { + Ok(_) => log::info!("FAT filesystem formatted successfully in memory!"), + Err(e) => { + log::error!("Error formatting FAT filesystem: {e:?}"); + return Err("Failed to format FAT volume."); + } + } + + let file_system = match FileSystem::new(in_memory_disk, FsOptions::new()) { + Ok(fs) => fs, + Err(e) => { + log::error!("Error creating new FileSystem instance: {e:?}"); + return Err("Failed to create FileSystem instance."); + } + }; + + *fs_guard = Some(Arc::new(file_system)); + + Ok(()) +} + +pub fn get_memory_fatfs() -> Arc> { + let fs_guard = FAT_FS_INSTANCE.read(); + + (*fs_guard) + .clone() + .expect("FAT filesystem has not been initialized. Call init_fatfs() first.") +} diff --git a/awkernel_lib/src/lib.rs b/awkernel_lib/src/lib.rs index 3c879cdee..d012e3b5e 100644 --- a/awkernel_lib/src/lib.rs +++ b/awkernel_lib/src/lib.rs @@ -8,6 +8,7 @@ use core::{cell::Cell, marker::PhantomData}; use alloc::rc::Rc; pub mod addr; +pub mod allocator; pub mod arch; pub mod config; pub mod console; From 2b15e1bbfee226f30b5d9b94a02ddc6564426f74 Mon Sep 17 00:00:00 2001 From: Koichi Date: Mon, 7 Jul 2025 22:17:50 +0900 Subject: [PATCH 4/5] fix Signed-off-by: Koichi --- awkernel_lib/src/file/fatfs.rs | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/awkernel_lib/src/file/fatfs.rs b/awkernel_lib/src/file/fatfs.rs index 8980b399f..506525cca 100644 --- a/awkernel_lib/src/file/fatfs.rs +++ b/awkernel_lib/src/file/fatfs.rs @@ -53,13 +53,9 @@ pub fn init_memory_fatfs() -> Result<(), &'static str> { let mut in_memory_disk = InMemoryDisk::new(disk_data, 0); - log::info!("Attempting to format FAT filesystem in memory..."); - match format_volume(&mut in_memory_disk, FormatVolumeOptions::new()) { - Ok(_) => log::info!("FAT filesystem formatted successfully in memory!"), - Err(e) => { - log::error!("Error formatting FAT filesystem: {e:?}"); - return Err("Failed to format FAT volume."); - } + if let Err(e) = format_volume(&mut in_memory_disk, FormatVolumeOptions::new()) { + log::error!("Error formatting FAT filesystem: {e:?}"); + return Err("Failed to format FAT volume."); } let file_system = match FileSystem::new(in_memory_disk, FsOptions::new()) { From 052643f7499032e5fef94c2cee4cac016ab946db Mon Sep 17 00:00:00 2001 From: Koichi Imai Date: Tue, 8 Jul 2025 11:35:29 +0900 Subject: [PATCH 5/5] fix Signed-off-by: Koichi Imai --- awkernel_lib/src/file/fatfs.rs | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/awkernel_lib/src/file/fatfs.rs b/awkernel_lib/src/file/fatfs.rs index 506525cca..b2869814d 100644 --- a/awkernel_lib/src/file/fatfs.rs +++ b/awkernel_lib/src/file/fatfs.rs @@ -20,7 +20,7 @@ use crate::{ sync::rwlock::RwLock, }; -use alloc::{sync::Arc, vec::Vec}; +use alloc::{format, string::String, sync::Arc, vec::Vec}; use core::alloc::{GlobalAlloc, Layout}; pub const MEMORY_FILESYSTEM_SIZE: usize = 1024 * 1024; @@ -29,10 +29,10 @@ static FAT_FS_INSTANCE: RwLock< Option>>, > = RwLock::new(None); -pub fn init_memory_fatfs() -> Result<(), &'static str> { +pub fn init_memory_fatfs() -> Result<(), String> { let mut fs_guard = FAT_FS_INSTANCE.write(); if fs_guard.is_some() { - return Err("FAT filesystem has already been initialized."); + return Err("FAT filesystem has already been initialized.".into()); } let disk_layout = Layout::from_size_align(MEMORY_FILESYSTEM_SIZE, PAGESIZE) @@ -40,7 +40,7 @@ pub fn init_memory_fatfs() -> Result<(), &'static str> { let raw_disk_memory = unsafe { System.alloc(disk_layout) }; if raw_disk_memory.is_null() { - return Err("Failed to allocate memory for the in-memory disk."); + return Err("Failed to allocate memory for the in-memory disk.".into()); } let disk_data = unsafe { @@ -54,15 +54,13 @@ pub fn init_memory_fatfs() -> Result<(), &'static str> { let mut in_memory_disk = InMemoryDisk::new(disk_data, 0); if let Err(e) = format_volume(&mut in_memory_disk, FormatVolumeOptions::new()) { - log::error!("Error formatting FAT filesystem: {e:?}"); - return Err("Failed to format FAT volume."); + return Err(format!("Failed to format FAT volume: {e:?}")); } let file_system = match FileSystem::new(in_memory_disk, FsOptions::new()) { Ok(fs) => fs, Err(e) => { - log::error!("Error creating new FileSystem instance: {e:?}"); - return Err("Failed to create FileSystem instance."); + return Err(format!("Failed to create FileSystem instance: {e:?}")); } };