From 9f627d590d88bc15b6f55777ef90e76bd452c554 Mon Sep 17 00:00:00 2001 From: Martin Marmsoler Date: Thu, 30 May 2024 10:36:10 +0200 Subject: [PATCH 01/17] initial commit to implement FAT table write/read and setting the volume dirty status Description: The dirty flag will be set when opening the volume to indicate that the FAT table might be out of date. In case of an unexpected close without unmount in the next mount it is visible that the FAT table is outdated and can be reread by the operating system (https://en.wikipedia.org/wiki/Design_of_the_FAT_file_system). Without this, the file must always closed before removing the sd card because otherwise the FAT table is outdated and so the files are not visible when mounting the sd card on a computer. For embedded systems it is quite likely that unexpect end can happen and always closing the file after a single write operation is a performance issue. For readonly this dirty flag is not required and therefore it will not set and reset when opening/closing a volume. https://unix.stackexchange.com/questions/230181/why-does-linux-mark-fat-as-dirty-simply-due-to-mounting-it Linux kernel is doing it during mount, so there is no need to ckeck it every time during a new write --- src/fat/fat_table.rs | 62 +++++++++++++++++++++++++++++++++++++ src/fat/mod.rs | 2 ++ src/fat/volume.rs | 8 +++++ src/lib.rs | 6 ++++ src/volume_mgr.rs | 73 +++++++++++++++++++++++++++++++++++++++++--- 5 files changed, 146 insertions(+), 5 deletions(-) create mode 100644 src/fat/fat_table.rs diff --git a/src/fat/fat_table.rs b/src/fat/fat_table.rs new file mode 100644 index 00000000..dc98f747 --- /dev/null +++ b/src/fat/fat_table.rs @@ -0,0 +1,62 @@ +/// FAT table definition +/// +/// +use crate::fat::FatType; +use byteorder::{ByteOrder, LittleEndian}; + +/// Represents a single FAT table. It contains all information about which cluster is occupied +/// from a file +pub struct FatTable<'a> { + fat_type: FatType, + data: &'a mut [u8], +} + +impl<'a> FatTable<'a> { + /// Attempt to parse a FAT table from a multiple sectors. + pub fn create_from_bytes(data: &'a mut [u8], fat_type: FatType) -> Result { + Ok(Self { data, fat_type }) + } + + // FAT16 only + //define_field!(fat_id16, u16, 0); + + // FAT32 only + //define_field!(fat_id32, u32, 0); + + const FAT16_DIRTY_BIT: u16 = 15; + const FAT32_DIRTY_BIT: u32 = 27; + + pub(crate) fn dirty(&self) -> bool { + match self.fat_type { + FatType::Fat16 => { + (LittleEndian::read_u16(&self.data[2..2 + 2]) & (1 << Self::FAT16_DIRTY_BIT)) == 0 + } + FatType::Fat32 => { + (LittleEndian::read_u32(&self.data[4..4 + 4]) & (1 << Self::FAT32_DIRTY_BIT)) == 0 + } + } + } + + pub(crate) fn set_dirty(&mut self, dirty: bool) { + match self.fat_type { + FatType::Fat16 => { + let mut v = LittleEndian::read_u16(&self.data[2..2 + 2]); + if dirty { + v &= !(1 << Self::FAT16_DIRTY_BIT); + } else { + v |= 1 << Self::FAT16_DIRTY_BIT + } + LittleEndian::write_u16(&mut self.data[2..2 + 2], v); + } + FatType::Fat32 => { + let mut v = LittleEndian::read_u32(&self.data[4..4 + 4]); + if dirty { + v &= !(1 << Self::FAT32_DIRTY_BIT); + } else { + v |= 1 << Self::FAT32_DIRTY_BIT + } + LittleEndian::write_u32(&mut self.data[4..4 + 4], v); + } + } + } +} diff --git a/src/fat/mod.rs b/src/fat/mod.rs index 35641cb6..4c0cf908 100644 --- a/src/fat/mod.rs +++ b/src/fat/mod.rs @@ -45,11 +45,13 @@ impl BlockCache { } mod bpb; +mod fat_table; mod info; mod ondiskdirentry; mod volume; pub use bpb::Bpb; +pub use fat_table::FatTable; pub use info::{Fat16Info, Fat32Info, FatSpecificInfo, InfoSector}; pub use ondiskdirentry::OnDiskDirEntry; pub use volume::{parse_volume, FatVolume, VolumeName}; diff --git a/src/fat/volume.rs b/src/fat/volume.rs index 8f44c6d9..0c5c4610 100644 --- a/src/fat/volume.rs +++ b/src/fat/volume.rs @@ -55,6 +55,10 @@ pub struct FatVolume { /// The block the FAT starts in. Relative to start of partition (so add /// `self.lba_offset` before passing to volume manager) pub(crate) fat_start: BlockCount, + /// Size of the FAT table in blocks + pub(crate) fat_size: BlockCount, + /// Number of FAT tables (Normaly there are 2 which are always synchronized (backup)) + pub(crate) fat_nums: u8, /// Expected number of free clusters pub(crate) free_clusters_count: Option, /// Number of the next expected free cluster @@ -1098,6 +1102,8 @@ where blocks_per_cluster: bpb.blocks_per_cluster(), first_data_block: (first_data_block), fat_start: BlockCount(u32::from(bpb.reserved_block_count())), + fat_size: BlockCount(bpb.fat_size()), + fat_nums: bpb.num_fats(), free_clusters_count: None, next_free_cluster: None, cluster_count: bpb.total_clusters(), @@ -1135,6 +1141,8 @@ where blocks_per_cluster: bpb.blocks_per_cluster(), first_data_block: BlockCount(first_data_block), fat_start: BlockCount(u32::from(bpb.reserved_block_count())), + fat_size: BlockCount(bpb.fat_size()), + fat_nums: bpb.num_fats(), free_clusters_count: info_sector.free_clusters_count(), next_free_cluster: info_sector.next_free_cluster(), cluster_count: bpb.total_clusters(), diff --git a/src/lib.rs b/src/lib.rs index 1bcd4298..58aaedea 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -175,6 +175,10 @@ where VolumeStillInUse, /// You can't open a volume twice VolumeAlreadyOpen, + /// Volume is opened in read only mode + VolumeReadOnly, + /// Fat table is longer than supported + FatTableTooLarge, /// We can't do that yet Unsupported, /// Tried to read beyond end of file @@ -344,6 +348,8 @@ pub(crate) struct VolumeInfo { idx: VolumeIdx, /// What kind of volume this is volume_type: VolumeType, + /// Flag to indicate if the volume was opened as read only. If read only, files cannot be opened in write mode! + read_only: bool, } /// This enum holds the data for the various different types of filesystems we diff --git a/src/volume_mgr.rs b/src/volume_mgr.rs index 15e4f424..8bd2c349 100644 --- a/src/volume_mgr.rs +++ b/src/volume_mgr.rs @@ -12,8 +12,8 @@ use crate::filesystem::{ SearchIdGenerator, TimeSource, ToShortFileName, MAX_FILE_SIZE, }; use crate::{ - debug, Block, BlockCount, BlockDevice, BlockIdx, Error, RawVolume, ShortFileName, Volume, - VolumeIdx, VolumeInfo, VolumeType, PARTITION_ID_FAT16, PARTITION_ID_FAT16_LBA, + debug, Block, BlockCount, BlockDevice, BlockIdx, Error, FatVolume, RawVolume, ShortFileName, + Volume, VolumeIdx, VolumeInfo, VolumeType, PARTITION_ID_FAT16, PARTITION_ID_FAT16_LBA, PARTITION_ID_FAT32_CHS_LBA, PARTITION_ID_FAT32_LBA, }; use heapless::Vec; @@ -102,8 +102,26 @@ where pub fn open_volume( &mut self, volume_idx: VolumeIdx, + read_only: bool, ) -> Result, Error> { - let v = self.open_raw_volume(volume_idx)?; + return self._open_volume(volume_idx, false); + } + + /// Get a volume (or partition) based on entries in the Master Boot Record. + /// + /// We do not support GUID Partition Table disks. Nor do we support any + /// concept of drive letters - that is for a higher layer to handle. + fn _open_volume( + &mut self, + volume_idx: VolumeIdx, + read_only: bool, + ) -> Result, Error> { + let v = self.open_raw_volume(volume_idx, read_only)?; + if !read_only { + let idx = self.get_volume_by_id(v)?; + let VolumeType::Fat(volume_type) = &self.open_volumes[idx].volume_type; + self.set_volume_status_dirty(volume_type, true)?; + } Ok(v.to_volume(self)) } @@ -114,7 +132,11 @@ where /// /// This function gives you a `RawVolume` and you must close the volume by /// calling `VolumeManager::close_volume`. - pub fn open_raw_volume(&mut self, volume_idx: VolumeIdx) -> Result> { + pub fn open_raw_volume( + &mut self, + volume_idx: VolumeIdx, + read_only: bool, + ) -> Result> { const PARTITION1_START: usize = 446; const PARTITION2_START: usize = PARTITION1_START + PARTITION_INFO_LENGTH; const PARTITION3_START: usize = PARTITION2_START + PARTITION_INFO_LENGTH; @@ -192,6 +214,7 @@ where volume_id: id, idx: volume_idx, volume_type: volume, + read_only: read_only, }; // We already checked for space self.open_volumes.push(info).unwrap(); @@ -319,13 +342,49 @@ where return Err(Error::VolumeStillInUse); } } - let volume_idx = self.get_volume_by_id(volume)?; + if !self.open_volumes[volume_idx].read_only { + let VolumeType::Fat(volume_type) = &self.open_volumes[volume_idx].volume_type; + self.set_volume_status_dirty(volume_type, false)?; + } + self.open_volumes.swap_remove(volume_idx); Ok(()) } + /// Sets the volume status dirty to dirty if true, to not dirty if false + fn set_volume_status_dirty( + &self, + volume: &FatVolume, + dirty: bool, + ) -> Result<(), Error> { + if volume.fat_size > BlockCount(512) { + return Err(Error::FatTableTooLarge); + } + let mut blocks = [Block::new()]; + self.block_device.read( + &mut blocks, + volume.lba_start + volume.fat_start, + "reading fat table", + )?; + let block = &mut blocks[0]; + let mut fat_table = + fat::FatTable::create_from_bytes(&mut block.contents, volume.get_fat_type()) + .map_err(Error::FormatError)?; + fat_table.set_dirty(dirty); + let fat_table_start = volume.lba_start + volume.fat_start; + if volume.fat_nums == 1 || volume.fat_nums == 2 { + self.block_device.write(&blocks, fat_table_start)?; + // Synchronize also backup fat table + if volume.fat_nums == 2 { + self.block_device + .write(&blocks, fat_table_start + volume.fat_size)? + } + } + Ok(()) + } + /// Look in a directory for a named file. pub fn find_directory_entry( &mut self, @@ -479,6 +538,10 @@ where let volume_info = &self.open_volumes[volume_idx]; let sfn = name.to_short_filename().map_err(Error::FilenameError)?; + if volume_info.read_only && mode != Mode::ReadOnly { + return Err(Error::VolumeReadOnly); + } + let dir_entry = match &volume_info.volume_type { VolumeType::Fat(fat) => { fat.find_directory_entry(&self.block_device, directory_info, &sfn) From e7d4565cde8e07e0727fb6b842ebec4bc2180c48 Mon Sep 17 00:00:00 2001 From: Martin Marmsoler Date: Thu, 30 May 2024 11:15:40 +0200 Subject: [PATCH 02/17] FatTableTooLarge can be ignored, because the value flag is in the second block of the fat table --- src/lib.rs | 2 -- src/volume_mgr.rs | 3 --- 2 files changed, 5 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 58aaedea..3d32ddf8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -177,8 +177,6 @@ where VolumeAlreadyOpen, /// Volume is opened in read only mode VolumeReadOnly, - /// Fat table is longer than supported - FatTableTooLarge, /// We can't do that yet Unsupported, /// Tried to read beyond end of file diff --git a/src/volume_mgr.rs b/src/volume_mgr.rs index 8bd2c349..5225f4f7 100644 --- a/src/volume_mgr.rs +++ b/src/volume_mgr.rs @@ -359,9 +359,6 @@ where volume: &FatVolume, dirty: bool, ) -> Result<(), Error> { - if volume.fat_size > BlockCount(512) { - return Err(Error::FatTableTooLarge); - } let mut blocks = [Block::new()]; self.block_device.read( &mut blocks, From d2bc1d1945dbec43cfc737b6221c31da63d25808 Mon Sep 17 00:00:00 2001 From: Martin Marmsoler Date: Thu, 30 May 2024 17:38:57 +0200 Subject: [PATCH 03/17] Add FAT table to test --- src/fat/fat_table.rs | 1 + src/volume_mgr.rs | 115 +++++++++++++++++++++++++++++++++++++------ 2 files changed, 102 insertions(+), 14 deletions(-) diff --git a/src/fat/fat_table.rs b/src/fat/fat_table.rs index dc98f747..776cb2d3 100644 --- a/src/fat/fat_table.rs +++ b/src/fat/fat_table.rs @@ -26,6 +26,7 @@ impl<'a> FatTable<'a> { const FAT16_DIRTY_BIT: u16 = 15; const FAT32_DIRTY_BIT: u32 = 27; + #[cfg(test)] pub(crate) fn dirty(&self) -> bool { match self.fat_type { FatType::Fat16 => { diff --git a/src/volume_mgr.rs b/src/volume_mgr.rs index 5225f4f7..3c9ea38e 100644 --- a/src/volume_mgr.rs +++ b/src/volume_mgr.rs @@ -360,27 +360,36 @@ where dirty: bool, ) -> Result<(), Error> { let mut blocks = [Block::new()]; - self.block_device.read( - &mut blocks, - volume.lba_start + volume.fat_start, - "reading fat table", - )?; + let fat_table1_start = volume.lba_start + volume.fat_start; + self.block_device + .read(&mut blocks, fat_table1_start, "reading fat table")?; let block = &mut blocks[0]; let mut fat_table = fat::FatTable::create_from_bytes(&mut block.contents, volume.get_fat_type()) .map_err(Error::FormatError)?; fat_table.set_dirty(dirty); - let fat_table_start = volume.lba_start + volume.fat_start; if volume.fat_nums == 1 || volume.fat_nums == 2 { - self.block_device.write(&blocks, fat_table_start)?; + self.block_device.write(&blocks, fat_table1_start)?; // Synchronize also backup fat table if volume.fat_nums == 2 { self.block_device - .write(&blocks, fat_table_start + volume.fat_size)? + .write(&blocks, fat_table1_start + volume.fat_size)? } } Ok(()) } + #[cfg(test)] + fn volume_status_dirty(&self, volume: &FatVolume) -> Result> { + let mut blocks = [Block::new()]; + let fat_table1_start = volume.lba_start + volume.fat_start; + self.block_device + .read(&mut blocks, fat_table1_start, "reading fat table")?; + let block = &mut blocks[0]; + let fat_table = + fat::FatTable::create_from_bytes(&mut block.contents, volume.get_fat_type()) + .map_err(Error::FormatError)?; + Ok(fat_table.dirty()) + } /// Look in a directory for a named file. pub fn find_directory_entry( @@ -1186,6 +1195,7 @@ mod tests { use super::*; use crate::filesystem::SearchId; use crate::Timestamp; + use crate::VolumeType; struct DummyBlockDevice; @@ -1221,7 +1231,8 @@ mod tests { _reason: &str, ) -> Result<(), Self::Error> { // Actual blocks taken from an SD card, except I've changed the start and length of partition 0. - static BLOCKS: [Block; 3] = [ + static BLOCKS: [Block; 4] = [ + // Block 0: MBR Block { contents: [ 0xfa, 0xb8, 0x00, 0x10, 0x8e, 0xd0, 0xbc, 0x00, 0xb0, 0xb8, 0x00, 0x00, @@ -1290,10 +1301,11 @@ mod tests { 0x00, 0x00, 0x55, 0xaa, // 0x1F0 ], }, + // Block 1: Partition 0 Boot block Block { contents: [ 0xeb, 0x58, 0x90, 0x6d, 0x6b, 0x66, 0x73, 0x2e, 0x66, 0x61, 0x74, 0x00, - 0x02, 0x08, 0x20, 0x00, // 0x000 + 0x02, 0x08, 0x02, 0x00, // 0x000 0x02, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x00, 0x10, 0x00, 0x04, 0x00, 0x00, 0x08, 0x00, 0x00, // 0x010 0x00, 0x20, 0x76, 0x00, 0x80, 0x1d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -1358,6 +1370,7 @@ mod tests { 0x00, 0x00, 0x55, 0xaa, // 0x1F0 ], }, + // Partition 0 info sector (BPB_FSInfo) Block { contents: hex!( "52 52 61 41 00 00 00 00 00 00 00 00 00 00 00 00 @@ -1394,6 +1407,75 @@ mod tests { 00 00 00 00 00 00 00 00 00 00 00 00 00 00 55 AA" ), }, + // Partition 0 FAT table + Block { + contents: [ + 0xF0, 0xFF, 0xFF, 0x0F, 0xFF, 0xFF, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, // 0x000 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, // 0x010 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, // 0x020 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, // 0x030 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, // 0x040 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, // 0x050 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, // 0x060 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, // 0x070 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, // 0x080 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, // 0x090 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, // 0x0A0 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, // 0x0B0 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, // 0x0C0 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, // 0x0D0 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, // 0x0E0 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, // 0x0F0 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, // 0x100 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, // 0x110 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, // 0x120 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, // 0x130 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, // 0x140 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, // 0x150 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, // 0x160 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, // 0x170 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, // 0x180 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, // 0x190 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, // 0x1A0 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, // 0x1B0 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, // 0x1C0 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, // 0x1D0 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, // 0x1E0 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, // 0x1F0 + ], + }, ]; println!( "Reading block {} to {}", @@ -1427,7 +1509,7 @@ mod tests { let mut c: VolumeManager = VolumeManager::new_with_limits(DummyBlockDevice, Clock, 0xAA00_0000); - let v = c.open_raw_volume(VolumeIdx(0)).unwrap(); + let v = c.open_raw_volume(VolumeIdx(0), false).unwrap(); let expected_id = RawVolume(SearchId(0xAA00_0000)); assert_eq!(v, expected_id); assert_eq!( @@ -1435,16 +1517,19 @@ mod tests { &VolumeInfo { volume_id: expected_id, idx: VolumeIdx(0), + read_only: false, volume_type: VolumeType::Fat(crate::FatVolume { lba_start: BlockIdx(1), num_blocks: BlockCount(0x0011_2233), blocks_per_cluster: 8, - first_data_block: BlockCount(15136), - fat_start: BlockCount(32), + first_data_block: BlockCount(15106), + fat_start: BlockCount(2), + fat_size: BlockCount(7552), + fat_nums: 2, name: fat::VolumeName::new(*b"Pictures "), free_clusters_count: None, next_free_cluster: None, - cluster_count: 965_788, + cluster_count: 965_791, fat_specific_info: fat::FatSpecificInfo::Fat32(fat::Fat32Info { first_root_dir_cluster: ClusterId(2), info_location: BlockIdx(1) + BlockCount(1), @@ -1452,6 +1537,8 @@ mod tests { }) } ); + let VolumeType::Fat(fat_info) = &c.open_volumes[0].volume_type; + assert_eq!(c.volume_status_dirty(fat_info).unwrap(), false); } } From 8d87d1ad658850222b422824f131913c0bad88a5 Mon Sep 17 00:00:00 2001 From: Martin Marmsoler Date: Thu, 30 May 2024 18:00:10 +0200 Subject: [PATCH 04/17] check also if the bit is set that it is really dirty --- src/volume_mgr.rs | 667 +++++++++++++++++++++++++++++----------------- 1 file changed, 419 insertions(+), 248 deletions(-) diff --git a/src/volume_mgr.rs b/src/volume_mgr.rs index 3c9ea38e..aaaed125 100644 --- a/src/volume_mgr.rs +++ b/src/volume_mgr.rs @@ -1197,7 +1197,8 @@ mod tests { use crate::Timestamp; use crate::VolumeType; - struct DummyBlockDevice; + struct DummyBlockDeviceVolumeStatusNotDirty; + struct DummyBlockDeviceVolumeStatusDirty; struct Clock; @@ -1220,7 +1221,324 @@ mod tests { } } - impl BlockDevice for DummyBlockDevice { + const MBR_BLOCK: Block = Block { + contents: [ + 0xfa, 0xb8, 0x00, 0x10, 0x8e, 0xd0, 0xbc, 0x00, 0xb0, 0xb8, 0x00, 0x00, 0x8e, 0xd8, + 0x8e, 0xc0, // 0x000 + 0xfb, 0xbe, 0x00, 0x7c, 0xbf, 0x00, 0x06, 0xb9, 0x00, 0x02, 0xf3, 0xa4, 0xea, 0x21, + 0x06, 0x00, // 0x010 + 0x00, 0xbe, 0xbe, 0x07, 0x38, 0x04, 0x75, 0x0b, 0x83, 0xc6, 0x10, 0x81, 0xfe, 0xfe, + 0x07, 0x75, // 0x020 + 0xf3, 0xeb, 0x16, 0xb4, 0x02, 0xb0, 0x01, 0xbb, 0x00, 0x7c, 0xb2, 0x80, 0x8a, 0x74, + 0x01, 0x8b, // 0x030 + 0x4c, 0x02, 0xcd, 0x13, 0xea, 0x00, 0x7c, 0x00, 0x00, 0xeb, 0xfe, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x040 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x050 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x060 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x070 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x080 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x090 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x0A0 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x0B0 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x0C0 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x0D0 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x0E0 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x0F0 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x100 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x110 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x120 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x130 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x140 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x150 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x160 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x170 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x180 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x190 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x1A0 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4c, 0xca, 0xde, 0x06, 0x00, 0x00, + 0x00, 0x04, // 0x1B0 + 0x01, 0x04, 0x0c, 0xfe, 0xc2, 0xff, 0x01, 0x00, 0x00, 0x00, 0x33, 0x22, 0x11, 0x00, + 0x00, 0x00, // 0x1C0 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x1D0 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x1E0 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x55, 0xaa, // 0x1F0 + ], + }; + + // Partition 0 Boot block + const FAT32_PARTITION0_BOOT: Block = Block { + contents: [ + 0xeb, 0x58, 0x90, 0x6d, 0x6b, 0x66, 0x73, 0x2e, 0x66, 0x61, 0x74, 0x00, 0x02, 0x08, + 0x02, 0x00, // 0x000 + 0x02, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x00, 0x10, 0x00, 0x04, 0x00, 0x00, 0x08, + 0x00, 0x00, // 0x010 + 0x00, 0x20, 0x76, 0x00, 0x80, 0x1d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, + 0x00, 0x00, // 0x020 + 0x01, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x030 + 0x80, 0x01, 0x29, 0x0b, 0xa8, 0x89, 0x27, 0x50, 0x69, 0x63, 0x74, 0x75, 0x72, 0x65, + 0x73, 0x20, // 0x040 + 0x20, 0x20, 0x46, 0x41, 0x54, 0x33, 0x32, 0x20, 0x20, 0x20, 0x0e, 0x1f, 0xbe, 0x77, + 0x7c, 0xac, // 0x050 + 0x22, 0xc0, 0x74, 0x0b, 0x56, 0xb4, 0x0e, 0xbb, 0x07, 0x00, 0xcd, 0x10, 0x5e, 0xeb, + 0xf0, 0x32, // 0x060 + 0xe4, 0xcd, 0x16, 0xcd, 0x19, 0xeb, 0xfe, 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, + 0x20, 0x6e, // 0x070 + 0x6f, 0x74, 0x20, 0x61, 0x20, 0x62, 0x6f, 0x6f, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x20, + 0x64, 0x69, // 0x080 + 0x73, 0x6b, 0x2e, 0x20, 0x20, 0x50, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x20, 0x69, 0x6e, + 0x73, 0x65, // 0x090 + 0x72, 0x74, 0x20, 0x61, 0x20, 0x62, 0x6f, 0x6f, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x20, + 0x66, 0x6c, // 0x0A0 + 0x6f, 0x70, 0x70, 0x79, 0x20, 0x61, 0x6e, 0x64, 0x0d, 0x0a, 0x70, 0x72, 0x65, 0x73, + 0x73, 0x20, // 0x0B0 + 0x61, 0x6e, 0x79, 0x20, 0x6b, 0x65, 0x79, 0x20, 0x74, 0x6f, 0x20, 0x74, 0x72, 0x79, + 0x20, 0x61, // 0x0C0 + 0x67, 0x61, 0x69, 0x6e, 0x20, 0x2e, 0x2e, 0x2e, 0x20, 0x0d, 0x0a, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x0D0 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x0E0 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x0F0 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x100 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x110 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x120 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x130 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x140 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x150 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x160 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x170 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x180 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x190 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x1A0 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x1B0 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x1C0 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x1D0 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x1E0 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x55, 0xaa, // 0x1F0 + ], + }; + + const FAT32_PARTITION0_FSINFO: Block = // Partition 0 info sector (BPB_FSInfo) + Block { + contents: hex!( + "52 52 61 41 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 72 72 41 61 FF FF FF FF FF FF FF FF + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 55 AA" + ), + }; + + // FAT table with volume status NOT dirty + const FAT32_PARTITION0_FAT_TABLE: Block = Block { + contents: [ + 0xF0, 0xFF, 0xFF, 0x0F, 0xFF, 0xFF, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x000 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x010 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x020 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x030 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x040 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x050 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x060 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x070 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x080 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x090 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x0A0 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x0B0 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x0C0 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x0D0 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x0E0 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x0F0 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x100 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x110 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x120 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x130 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x140 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x150 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x160 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x170 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x180 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x190 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x1A0 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x1B0 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x1C0 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x1D0 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x1E0 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x1F0 + ], + }; + + // FAT table with volume status dirty + const FAT32_PARTITION0_FAT_TABLE_DIRTY: Block = Block { + contents: [ + 0xF0, 0xFF, 0xFF, 0x0F, 0xFF, 0xFF, 0xFF, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x000 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x010 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x020 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x030 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x040 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x050 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x060 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x070 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x080 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x090 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x0A0 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x0B0 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x0C0 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x0D0 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x0E0 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x0F0 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x100 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x110 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x120 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x130 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x140 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x150 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x160 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x170 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x180 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x190 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x1A0 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x1B0 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x1C0 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x1D0 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x1E0 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x1F0 + ], + }; + + impl BlockDevice for DummyBlockDeviceVolumeStatusNotDirty { type Error = Error; /// Read one or more blocks, starting at the given block index. @@ -1232,250 +1550,54 @@ mod tests { ) -> Result<(), Self::Error> { // Actual blocks taken from an SD card, except I've changed the start and length of partition 0. static BLOCKS: [Block; 4] = [ - // Block 0: MBR - Block { - contents: [ - 0xfa, 0xb8, 0x00, 0x10, 0x8e, 0xd0, 0xbc, 0x00, 0xb0, 0xb8, 0x00, 0x00, - 0x8e, 0xd8, 0x8e, 0xc0, // 0x000 - 0xfb, 0xbe, 0x00, 0x7c, 0xbf, 0x00, 0x06, 0xb9, 0x00, 0x02, 0xf3, 0xa4, - 0xea, 0x21, 0x06, 0x00, // 0x010 - 0x00, 0xbe, 0xbe, 0x07, 0x38, 0x04, 0x75, 0x0b, 0x83, 0xc6, 0x10, 0x81, - 0xfe, 0xfe, 0x07, 0x75, // 0x020 - 0xf3, 0xeb, 0x16, 0xb4, 0x02, 0xb0, 0x01, 0xbb, 0x00, 0x7c, 0xb2, 0x80, - 0x8a, 0x74, 0x01, 0x8b, // 0x030 - 0x4c, 0x02, 0xcd, 0x13, 0xea, 0x00, 0x7c, 0x00, 0x00, 0xeb, 0xfe, 0x00, - 0x00, 0x00, 0x00, 0x00, // 0x040 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, // 0x050 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, // 0x060 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, // 0x070 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, // 0x080 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, // 0x090 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, // 0x0A0 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, // 0x0B0 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, // 0x0C0 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, // 0x0D0 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, // 0x0E0 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, // 0x0F0 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, // 0x100 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, // 0x110 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, // 0x120 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, // 0x130 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, // 0x140 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, // 0x150 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, // 0x160 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, // 0x170 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, // 0x180 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, // 0x190 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, // 0x1A0 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4c, 0xca, 0xde, 0x06, - 0x00, 0x00, 0x00, 0x04, // 0x1B0 - 0x01, 0x04, 0x0c, 0xfe, 0xc2, 0xff, 0x01, 0x00, 0x00, 0x00, 0x33, 0x22, - 0x11, 0x00, 0x00, 0x00, // 0x1C0 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, // 0x1D0 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, // 0x1E0 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x55, 0xaa, // 0x1F0 - ], - }, - // Block 1: Partition 0 Boot block - Block { - contents: [ - 0xeb, 0x58, 0x90, 0x6d, 0x6b, 0x66, 0x73, 0x2e, 0x66, 0x61, 0x74, 0x00, - 0x02, 0x08, 0x02, 0x00, // 0x000 - 0x02, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x00, 0x10, 0x00, 0x04, 0x00, - 0x00, 0x08, 0x00, 0x00, // 0x010 - 0x00, 0x20, 0x76, 0x00, 0x80, 0x1d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x02, 0x00, 0x00, 0x00, // 0x020 - 0x01, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, // 0x030 - 0x80, 0x01, 0x29, 0x0b, 0xa8, 0x89, 0x27, 0x50, 0x69, 0x63, 0x74, 0x75, - 0x72, 0x65, 0x73, 0x20, // 0x040 - 0x20, 0x20, 0x46, 0x41, 0x54, 0x33, 0x32, 0x20, 0x20, 0x20, 0x0e, 0x1f, - 0xbe, 0x77, 0x7c, 0xac, // 0x050 - 0x22, 0xc0, 0x74, 0x0b, 0x56, 0xb4, 0x0e, 0xbb, 0x07, 0x00, 0xcd, 0x10, - 0x5e, 0xeb, 0xf0, 0x32, // 0x060 - 0xe4, 0xcd, 0x16, 0xcd, 0x19, 0xeb, 0xfe, 0x54, 0x68, 0x69, 0x73, 0x20, - 0x69, 0x73, 0x20, 0x6e, // 0x070 - 0x6f, 0x74, 0x20, 0x61, 0x20, 0x62, 0x6f, 0x6f, 0x74, 0x61, 0x62, 0x6c, - 0x65, 0x20, 0x64, 0x69, // 0x080 - 0x73, 0x6b, 0x2e, 0x20, 0x20, 0x50, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x20, - 0x69, 0x6e, 0x73, 0x65, // 0x090 - 0x72, 0x74, 0x20, 0x61, 0x20, 0x62, 0x6f, 0x6f, 0x74, 0x61, 0x62, 0x6c, - 0x65, 0x20, 0x66, 0x6c, // 0x0A0 - 0x6f, 0x70, 0x70, 0x79, 0x20, 0x61, 0x6e, 0x64, 0x0d, 0x0a, 0x70, 0x72, - 0x65, 0x73, 0x73, 0x20, // 0x0B0 - 0x61, 0x6e, 0x79, 0x20, 0x6b, 0x65, 0x79, 0x20, 0x74, 0x6f, 0x20, 0x74, - 0x72, 0x79, 0x20, 0x61, // 0x0C0 - 0x67, 0x61, 0x69, 0x6e, 0x20, 0x2e, 0x2e, 0x2e, 0x20, 0x0d, 0x0a, 0x00, - 0x00, 0x00, 0x00, 0x00, // 0x0D0 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, // 0x0E0 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, // 0x0F0 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, // 0x100 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, // 0x110 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, // 0x120 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, // 0x130 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, // 0x140 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, // 0x150 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, // 0x160 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, // 0x170 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, // 0x180 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, // 0x190 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, // 0x1A0 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, // 0x1B0 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, // 0x1C0 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, // 0x1D0 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, // 0x1E0 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x55, 0xaa, // 0x1F0 - ], - }, - // Partition 0 info sector (BPB_FSInfo) - Block { - contents: hex!( - "52 52 61 41 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 72 72 41 61 FF FF FF FF FF FF FF FF - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 55 AA" - ), - }, - // Partition 0 FAT table - Block { - contents: [ - 0xF0, 0xFF, 0xFF, 0x0F, 0xFF, 0xFF, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, // 0x000 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, // 0x010 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, // 0x020 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, // 0x030 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, // 0x040 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, // 0x050 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, // 0x060 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, // 0x070 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, // 0x080 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, // 0x090 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, // 0x0A0 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, // 0x0B0 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, // 0x0C0 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, // 0x0D0 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, // 0x0E0 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, // 0x0F0 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, // 0x100 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, // 0x110 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, // 0x120 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, // 0x130 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, // 0x140 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, // 0x150 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, // 0x160 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, // 0x170 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, // 0x180 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, // 0x190 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, // 0x1A0 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, // 0x1B0 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, // 0x1C0 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, // 0x1D0 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, // 0x1E0 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, // 0x1F0 - ], - }, + MBR_BLOCK, + FAT32_PARTITION0_BOOT, + FAT32_PARTITION0_FSINFO, + FAT32_PARTITION0_FAT_TABLE, + ]; + println!( + "Reading block {} to {}", + start_block_idx.0, + start_block_idx.0 as usize + blocks.len() + ); + for (idx, block) in blocks.iter_mut().enumerate() { + let block_idx = start_block_idx.0 as usize + idx; + if block_idx < BLOCKS.len() { + *block = BLOCKS[block_idx].clone(); + } else { + return Err(Error::Unknown); + } + } + Ok(()) + } + + /// Write one or more blocks, starting at the given block index. + fn write(&self, _blocks: &[Block], _start_block_idx: BlockIdx) -> Result<(), Self::Error> { + unimplemented!(); + } + + /// Determine how many blocks this device can hold. + fn num_blocks(&self) -> Result { + Ok(BlockCount(2)) + } + } + + impl BlockDevice for DummyBlockDeviceVolumeStatusDirty { + type Error = Error; + + /// Read one or more blocks, starting at the given block index. + fn read( + &self, + blocks: &mut [Block], + start_block_idx: BlockIdx, + _reason: &str, + ) -> Result<(), Self::Error> { + // Actual blocks taken from an SD card, except I've changed the start and length of partition 0. + static BLOCKS: [Block; 4] = [ + MBR_BLOCK, + FAT32_PARTITION0_BOOT, + FAT32_PARTITION0_FSINFO, + FAT32_PARTITION0_FAT_TABLE_DIRTY, ]; println!( "Reading block {} to {}", @@ -1506,8 +1628,12 @@ mod tests { #[test] fn partition0() { - let mut c: VolumeManager = - VolumeManager::new_with_limits(DummyBlockDevice, Clock, 0xAA00_0000); + let mut c: VolumeManager = + VolumeManager::new_with_limits( + DummyBlockDeviceVolumeStatusNotDirty, + Clock, + 0xAA00_0000, + ); let v = c.open_raw_volume(VolumeIdx(0), false).unwrap(); let expected_id = RawVolume(SearchId(0xAA00_0000)); @@ -1539,6 +1665,51 @@ mod tests { ); let VolumeType::Fat(fat_info) = &c.open_volumes[0].volume_type; assert_eq!(c.volume_status_dirty(fat_info).unwrap(), false); + //c.set_volume_status_dirty(fat_info, true).unwrap(); + + //assert_eq!(c.volume_status_dirty(fat_info).unwrap(), true); + // TODO: check that it was really set! + } + + #[test] + fn partition0_dirty() { + let mut c: VolumeManager = + VolumeManager::new_with_limits(DummyBlockDeviceVolumeStatusDirty, Clock, 0xAA00_0000); + + let v = c.open_raw_volume(VolumeIdx(0), false).unwrap(); + let expected_id = RawVolume(SearchId(0xAA00_0000)); + assert_eq!(v, expected_id); + assert_eq!( + &c.open_volumes[0], + &VolumeInfo { + volume_id: expected_id, + idx: VolumeIdx(0), + read_only: false, + volume_type: VolumeType::Fat(crate::FatVolume { + lba_start: BlockIdx(1), + num_blocks: BlockCount(0x0011_2233), + blocks_per_cluster: 8, + first_data_block: BlockCount(15106), + fat_start: BlockCount(2), + fat_size: BlockCount(7552), + fat_nums: 2, + name: fat::VolumeName::new(*b"Pictures "), + free_clusters_count: None, + next_free_cluster: None, + cluster_count: 965_791, + fat_specific_info: fat::FatSpecificInfo::Fat32(fat::Fat32Info { + first_root_dir_cluster: ClusterId(2), + info_location: BlockIdx(1) + BlockCount(1), + }) + }) + } + ); + let VolumeType::Fat(fat_info) = &c.open_volumes[0].volume_type; + assert_eq!(c.volume_status_dirty(fat_info).unwrap(), true); + //c.set_volume_status_dirty(fat_info, false).unwrap(); + + //assert_eq!(c.volume_status_dirty(fat_info).unwrap(), true); + // TODO: check that it was really set! } } From e7a8a77787bbe1fb75ad37eea50855f4f8376abe Mon Sep 17 00:00:00 2001 From: Martin Marmsoler Date: Thu, 30 May 2024 20:29:46 +0200 Subject: [PATCH 05/17] Add readonly volume open function --- src/volume_mgr.rs | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/volume_mgr.rs b/src/volume_mgr.rs index aaaed125..ecb1e1bc 100644 --- a/src/volume_mgr.rs +++ b/src/volume_mgr.rs @@ -102,11 +102,22 @@ where pub fn open_volume( &mut self, volume_idx: VolumeIdx, - read_only: bool, ) -> Result, Error> { return self._open_volume(volume_idx, false); } + /// Get a read only volume (or partition) based on entries in the Master Boot Record. + /// Opening and closing a read only volume is faster than a writable volume. + /// + /// We do not support GUID Partition Table disks. Nor do we support any + /// concept of drive letters - that is for a higher layer to handle. + pub fn open_volume_read_only( + &mut self, + volume_idx: VolumeIdx, + ) -> Result, Error> { + return self._open_volume(volume_idx, true); + } + /// Get a volume (or partition) based on entries in the Master Boot Record. /// /// We do not support GUID Partition Table disks. Nor do we support any From ba5771c075cafb84cc70483605334d11a8b906bf Mon Sep 17 00:00:00 2001 From: Martin Marmsoler Date: Mon, 3 Jun 2024 20:54:36 +0200 Subject: [PATCH 06/17] add test to check write as well --- src/volume_mgr.rs | 335 ++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 276 insertions(+), 59 deletions(-) diff --git a/src/volume_mgr.rs b/src/volume_mgr.rs index ecb1e1bc..694a5128 100644 --- a/src/volume_mgr.rs +++ b/src/volume_mgr.rs @@ -1207,9 +1207,11 @@ mod tests { use crate::filesystem::SearchId; use crate::Timestamp; use crate::VolumeType; + use std::cell::RefCell; - struct DummyBlockDeviceVolumeStatusNotDirty; - struct DummyBlockDeviceVolumeStatusDirty; + struct DummyBlockDevice { + blocks: RefCell<[Block; 9]>, + } struct Clock; @@ -1371,6 +1373,77 @@ mod tests { ], }; + // same as FAT32_PARTITION0_BOOT with the following changes: + // - fat table size reduced to 5 blocks (0x24..0x27) + const FAT32_PARTITION0_BOOT_FAT_TABLE_SIZE_5: Block = Block { + contents: [ + 0xeb, 0x58, 0x90, 0x6d, 0x6b, 0x66, 0x73, 0x2e, 0x66, 0x61, 0x74, 0x00, 0x02, 0x08, + 0x02, 0x00, // 0x000 + 0x02, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x00, 0x10, 0x00, 0x04, 0x00, 0x00, 0x08, + 0x00, 0x00, // 0x010 + 0x00, 0x20, 0x76, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, + 0x00, 0x00, // 0x020 + 0x01, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x030 + 0x80, 0x01, 0x29, 0x0b, 0xa8, 0x89, 0x27, 0x50, 0x69, 0x63, 0x74, 0x75, 0x72, 0x65, + 0x73, 0x20, // 0x040 + 0x20, 0x20, 0x46, 0x41, 0x54, 0x33, 0x32, 0x20, 0x20, 0x20, 0x0e, 0x1f, 0xbe, 0x77, + 0x7c, 0xac, // 0x050 + 0x22, 0xc0, 0x74, 0x0b, 0x56, 0xb4, 0x0e, 0xbb, 0x07, 0x00, 0xcd, 0x10, 0x5e, 0xeb, + 0xf0, 0x32, // 0x060 + 0xe4, 0xcd, 0x16, 0xcd, 0x19, 0xeb, 0xfe, 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, + 0x20, 0x6e, // 0x070 + 0x6f, 0x74, 0x20, 0x61, 0x20, 0x62, 0x6f, 0x6f, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x20, + 0x64, 0x69, // 0x080 + 0x73, 0x6b, 0x2e, 0x20, 0x20, 0x50, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x20, 0x69, 0x6e, + 0x73, 0x65, // 0x090 + 0x72, 0x74, 0x20, 0x61, 0x20, 0x62, 0x6f, 0x6f, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x20, + 0x66, 0x6c, // 0x0A0 + 0x6f, 0x70, 0x70, 0x79, 0x20, 0x61, 0x6e, 0x64, 0x0d, 0x0a, 0x70, 0x72, 0x65, 0x73, + 0x73, 0x20, // 0x0B0 + 0x61, 0x6e, 0x79, 0x20, 0x6b, 0x65, 0x79, 0x20, 0x74, 0x6f, 0x20, 0x74, 0x72, 0x79, + 0x20, 0x61, // 0x0C0 + 0x67, 0x61, 0x69, 0x6e, 0x20, 0x2e, 0x2e, 0x2e, 0x20, 0x0d, 0x0a, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x0D0 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x0E0 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x0F0 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x100 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x110 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x120 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x130 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x140 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x150 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x160 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x170 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x180 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x190 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x1A0 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x1B0 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x1C0 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x1D0 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x1E0 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x55, 0xaa, // 0x1F0 + ], + }; + const FAT32_PARTITION0_FSINFO: Block = // Partition 0 info sector (BPB_FSInfo) Block { contents: hex!( @@ -1549,51 +1622,137 @@ mod tests { ], }; - impl BlockDevice for DummyBlockDeviceVolumeStatusNotDirty { - type Error = Error; + // Dummy Block + const DUMMY: Block = Block { + contents: [ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x000 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x010 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x020 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x030 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x040 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x050 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x060 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x070 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x080 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x090 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x0A0 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x0B0 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x0C0 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x0D0 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x0E0 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x0F0 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x100 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x110 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x120 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x130 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x140 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x150 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x160 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x170 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x180 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x190 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x1A0 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x1B0 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x1C0 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x1D0 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x1E0 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // 0x1F0 + ], + }; - /// Read one or more blocks, starting at the given block index. - fn read( - &self, - blocks: &mut [Block], - start_block_idx: BlockIdx, - _reason: &str, - ) -> Result<(), Self::Error> { - // Actual blocks taken from an SD card, except I've changed the start and length of partition 0. - static BLOCKS: [Block; 4] = [ - MBR_BLOCK, - FAT32_PARTITION0_BOOT, - FAT32_PARTITION0_FSINFO, - FAT32_PARTITION0_FAT_TABLE, - ]; - println!( - "Reading block {} to {}", - start_block_idx.0, - start_block_idx.0 as usize + blocks.len() - ); - for (idx, block) in blocks.iter_mut().enumerate() { - let block_idx = start_block_idx.0 as usize + idx; - if block_idx < BLOCKS.len() { - *block = BLOCKS[block_idx].clone(); - } else { - return Err(Error::Unknown); - } + impl DummyBlockDevice { + // Actual blocks taken from an SD card, except + // - changed the start and length of partition 0. + // - FAT Table properties changed + fn new_not_dirty() -> Self { + Self { + blocks: RefCell::new([ + MBR_BLOCK, + FAT32_PARTITION0_BOOT, + FAT32_PARTITION0_FSINFO, + FAT32_PARTITION0_FAT_TABLE, + DUMMY, + DUMMY, + DUMMY, + DUMMY, + FAT32_PARTITION0_FAT_TABLE, + ]) } - Ok(()) } - /// Write one or more blocks, starting at the given block index. - fn write(&self, _blocks: &[Block], _start_block_idx: BlockIdx) -> Result<(), Self::Error> { - unimplemented!(); + fn new_dirty() -> Self { + Self { + blocks: RefCell::new([ + MBR_BLOCK, + FAT32_PARTITION0_BOOT, + FAT32_PARTITION0_FSINFO, + FAT32_PARTITION0_FAT_TABLE_DIRTY, + DUMMY, + DUMMY, + DUMMY, + DUMMY, + FAT32_PARTITION0_FAT_TABLE_DIRTY, + ]) + } } - /// Determine how many blocks this device can hold. - fn num_blocks(&self) -> Result { - Ok(BlockCount(2)) + // Size of the fat table set to 5 so both tables are accessible + fn new_not_dirty_fattable_size_5() -> Self { + Self { + blocks: RefCell::new([ + MBR_BLOCK, + FAT32_PARTITION0_BOOT_FAT_TABLE_SIZE_5, + FAT32_PARTITION0_FSINFO, + FAT32_PARTITION0_FAT_TABLE, + DUMMY, + DUMMY, + DUMMY, + DUMMY, + FAT32_PARTITION0_FAT_TABLE, + ]) + } } } - impl BlockDevice for DummyBlockDeviceVolumeStatusDirty { + impl PartialEq for Block { + fn eq(&self, other: &Self) -> bool { + self.contents == other.contents + } + } + + impl BlockDevice for DummyBlockDevice { type Error = Error; /// Read one or more blocks, starting at the given block index. @@ -1603,13 +1762,8 @@ mod tests { start_block_idx: BlockIdx, _reason: &str, ) -> Result<(), Self::Error> { - // Actual blocks taken from an SD card, except I've changed the start and length of partition 0. - static BLOCKS: [Block; 4] = [ - MBR_BLOCK, - FAT32_PARTITION0_BOOT, - FAT32_PARTITION0_FSINFO, - FAT32_PARTITION0_FAT_TABLE_DIRTY, - ]; + + println!( "Reading block {} to {}", start_block_idx.0, @@ -1617,8 +1771,8 @@ mod tests { ); for (idx, block) in blocks.iter_mut().enumerate() { let block_idx = start_block_idx.0 as usize + idx; - if block_idx < BLOCKS.len() { - *block = BLOCKS[block_idx].clone(); + if block_idx < self.blocks.borrow().len() { + *block = self.blocks.borrow()[block_idx].clone(); } else { return Err(Error::Unknown); } @@ -1628,7 +1782,10 @@ mod tests { /// Write one or more blocks, starting at the given block index. fn write(&self, _blocks: &[Block], _start_block_idx: BlockIdx) -> Result<(), Self::Error> { - unimplemented!(); + for idx in 0.._blocks.len() { + self.blocks.borrow_mut()[_start_block_idx.0 as usize + idx] = _blocks[idx].clone(); + } + Ok(()) } /// Determine how many blocks this device can hold. @@ -1639,9 +1796,9 @@ mod tests { #[test] fn partition0() { - let mut c: VolumeManager = + let mut c: VolumeManager = VolumeManager::new_with_limits( - DummyBlockDeviceVolumeStatusNotDirty, + DummyBlockDevice::new_not_dirty(), Clock, 0xAA00_0000, ); @@ -1676,16 +1833,13 @@ mod tests { ); let VolumeType::Fat(fat_info) = &c.open_volumes[0].volume_type; assert_eq!(c.volume_status_dirty(fat_info).unwrap(), false); - //c.set_volume_status_dirty(fat_info, true).unwrap(); - - //assert_eq!(c.volume_status_dirty(fat_info).unwrap(), true); - // TODO: check that it was really set! + c.set_volume_status_dirty(fat_info, true).unwrap(); } #[test] fn partition0_dirty() { - let mut c: VolumeManager = - VolumeManager::new_with_limits(DummyBlockDeviceVolumeStatusDirty, Clock, 0xAA00_0000); + let mut c: VolumeManager = + VolumeManager::new_with_limits(DummyBlockDevice::new_dirty(), Clock, 0xAA00_0000); let v = c.open_raw_volume(VolumeIdx(0), false).unwrap(); let expected_id = RawVolume(SearchId(0xAA00_0000)); @@ -1717,10 +1871,73 @@ mod tests { ); let VolumeType::Fat(fat_info) = &c.open_volumes[0].volume_type; assert_eq!(c.volume_status_dirty(fat_info).unwrap(), true); - //c.set_volume_status_dirty(fat_info, false).unwrap(); + } - //assert_eq!(c.volume_status_dirty(fat_info).unwrap(), true); - // TODO: check that it was really set! + #[test] + fn partition0_set_dirty() { + let mut c: VolumeManager = + VolumeManager::new_with_limits( + DummyBlockDevice::new_not_dirty_fattable_size_5(), + Clock, + 0xAA00_0000, + ); + + let v = c.open_raw_volume(VolumeIdx(0), false).unwrap(); + let expected_id = RawVolume(SearchId(0xAA00_0000)); + assert_eq!(v, expected_id); + assert_eq!( + &c.open_volumes[0], + &VolumeInfo { + volume_id: expected_id, + idx: VolumeIdx(0), + read_only: false, + volume_type: VolumeType::Fat(crate::FatVolume { + lba_start: BlockIdx(1), + num_blocks: BlockCount(0x0011_2233), + blocks_per_cluster: 8, + first_data_block: BlockCount(12), + fat_start: BlockCount(2), + fat_size: BlockCount(5), + fat_nums: 2, + name: fat::VolumeName::new(*b"Pictures "), + free_clusters_count: None, + next_free_cluster: None, + cluster_count: 967_678, + fat_specific_info: fat::FatSpecificInfo::Fat32(fat::Fat32Info { + first_root_dir_cluster: ClusterId(2), + info_location: BlockIdx(1) + BlockCount(1), + }) + }) + } + ); + let VolumeType::Fat(fat_info) = &c.open_volumes[0].volume_type; + assert_eq!(c.volume_status_dirty(fat_info).unwrap(), false); + assert_eq!(c.block_device.blocks.borrow()[0], MBR_BLOCK); + assert_eq!(c.block_device.blocks.borrow()[1], FAT32_PARTITION0_BOOT_FAT_TABLE_SIZE_5); + assert_eq!(c.block_device.blocks.borrow()[2], FAT32_PARTITION0_FSINFO); + assert_eq!(c.block_device.blocks.borrow()[3].contents[7] & (1 << 3), 8); + assert_eq!(c.block_device.blocks.borrow()[4], DUMMY); + assert_eq!(c.block_device.blocks.borrow()[5], DUMMY); + assert_eq!(c.block_device.blocks.borrow()[6], DUMMY); + assert_eq!(c.block_device.blocks.borrow()[7], DUMMY); + assert_eq!(c.block_device.blocks.borrow()[8].contents[7] & (1 << 3), 8); + + c.set_volume_status_dirty(fat_info, true).unwrap(); + assert_eq!(c.volume_status_dirty(fat_info).unwrap(), true); + assert_eq!(c.block_device.blocks.borrow()[3].contents[7] & (1 << 3), 0); + assert_eq!(c.block_device.blocks.borrow()[8].contents[7] & (1 << 3), 0); + + c.set_volume_status_dirty(fat_info, false).unwrap(); + assert_eq!(c.volume_status_dirty(fat_info).unwrap(), false); + assert_eq!(c.block_device.blocks.borrow()[0], MBR_BLOCK); + assert_eq!(c.block_device.blocks.borrow()[1], FAT32_PARTITION0_BOOT_FAT_TABLE_SIZE_5); + assert_eq!(c.block_device.blocks.borrow()[2], FAT32_PARTITION0_FSINFO); + assert_eq!(c.block_device.blocks.borrow()[3].contents[7] & (1 << 3), 8); + assert_eq!(c.block_device.blocks.borrow()[4], DUMMY); + assert_eq!(c.block_device.blocks.borrow()[5], DUMMY); + assert_eq!(c.block_device.blocks.borrow()[6], DUMMY); + assert_eq!(c.block_device.blocks.borrow()[7], DUMMY); + assert_eq!(c.block_device.blocks.borrow()[8].contents[7] & (1 << 3), 8); } } From f4bc21899263ef3d2c4a0f8d83a255af23d855f6 Mon Sep 17 00:00:00 2001 From: Martin Marmsoler Date: Mon, 3 Jun 2024 21:21:56 +0200 Subject: [PATCH 07/17] use enum instead of bool Reason: makes the funktionality more clear and less error prone --- src/lib.rs | 3 +- src/volume_mgr.rs | 79 ++++++++++++++++++++++++++--------------------- 2 files changed, 46 insertions(+), 36 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 3d32ddf8..aa98fb63 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -75,6 +75,7 @@ pub mod filesystem; pub mod sdcard; use filesystem::SearchId; +use volume_mgr::VolumeOpenMode; #[doc(inline)] pub use crate::blockdevice::{Block, BlockCount, BlockDevice, BlockIdx}; @@ -347,7 +348,7 @@ pub(crate) struct VolumeInfo { /// What kind of volume this is volume_type: VolumeType, /// Flag to indicate if the volume was opened as read only. If read only, files cannot be opened in write mode! - read_only: bool, + open_mode: VolumeOpenMode, } /// This enum holds the data for the various different types of filesystems we diff --git a/src/volume_mgr.rs b/src/volume_mgr.rs index 694a5128..0531538b 100644 --- a/src/volume_mgr.rs +++ b/src/volume_mgr.rs @@ -18,6 +18,12 @@ use crate::{ }; use heapless::Vec; +#[derive(Debug, PartialEq, Eq, Clone, Copy)] +pub enum VolumeOpenMode { + ReadOnly, + ReadWrite, +} + /// A `VolumeManager` wraps a block device and gives access to the FAT-formatted /// volumes within it. #[derive(Debug)] @@ -103,7 +109,7 @@ where &mut self, volume_idx: VolumeIdx, ) -> Result, Error> { - return self._open_volume(volume_idx, false); + return self._open_volume(volume_idx, VolumeOpenMode::ReadWrite); } /// Get a read only volume (or partition) based on entries in the Master Boot Record. @@ -115,9 +121,8 @@ where &mut self, volume_idx: VolumeIdx, ) -> Result, Error> { - return self._open_volume(volume_idx, true); + return self._open_volume(volume_idx, VolumeOpenMode::ReadOnly); } - /// Get a volume (or partition) based on entries in the Master Boot Record. /// /// We do not support GUID Partition Table disks. Nor do we support any @@ -125,10 +130,10 @@ where fn _open_volume( &mut self, volume_idx: VolumeIdx, - read_only: bool, + open_mode: VolumeOpenMode, ) -> Result, Error> { - let v = self.open_raw_volume(volume_idx, read_only)?; - if !read_only { + let v = self.open_raw_volume(volume_idx, open_mode)?; + if open_mode != VolumeOpenMode::ReadOnly { let idx = self.get_volume_by_id(v)?; let VolumeType::Fat(volume_type) = &self.open_volumes[idx].volume_type; self.set_volume_status_dirty(volume_type, true)?; @@ -146,7 +151,7 @@ where pub fn open_raw_volume( &mut self, volume_idx: VolumeIdx, - read_only: bool, + open_mode: VolumeOpenMode, ) -> Result> { const PARTITION1_START: usize = 446; const PARTITION2_START: usize = PARTITION1_START + PARTITION_INFO_LENGTH; @@ -225,7 +230,7 @@ where volume_id: id, idx: volume_idx, volume_type: volume, - read_only: read_only, + open_mode: open_mode, }; // We already checked for space self.open_volumes.push(info).unwrap(); @@ -354,7 +359,7 @@ where } } let volume_idx = self.get_volume_by_id(volume)?; - if !self.open_volumes[volume_idx].read_only { + if self.open_volumes[volume_idx].open_mode != VolumeOpenMode::ReadOnly { let VolumeType::Fat(volume_type) = &self.open_volumes[volume_idx].volume_type; self.set_volume_status_dirty(volume_type, false)?; } @@ -555,7 +560,7 @@ where let volume_info = &self.open_volumes[volume_idx]; let sfn = name.to_short_filename().map_err(Error::FilenameError)?; - if volume_info.read_only && mode != Mode::ReadOnly { + if volume_info.open_mode == VolumeOpenMode::ReadOnly && mode != Mode::ReadOnly { return Err(Error::VolumeReadOnly); } @@ -1708,7 +1713,7 @@ mod tests { DUMMY, DUMMY, FAT32_PARTITION0_FAT_TABLE, - ]) + ]), } } @@ -1724,7 +1729,7 @@ mod tests { DUMMY, DUMMY, FAT32_PARTITION0_FAT_TABLE_DIRTY, - ]) + ]), } } @@ -1741,7 +1746,7 @@ mod tests { DUMMY, DUMMY, FAT32_PARTITION0_FAT_TABLE, - ]) + ]), } } } @@ -1762,8 +1767,6 @@ mod tests { start_block_idx: BlockIdx, _reason: &str, ) -> Result<(), Self::Error> { - - println!( "Reading block {} to {}", start_block_idx.0, @@ -1797,13 +1800,11 @@ mod tests { #[test] fn partition0() { let mut c: VolumeManager = - VolumeManager::new_with_limits( - DummyBlockDevice::new_not_dirty(), - Clock, - 0xAA00_0000, - ); + VolumeManager::new_with_limits(DummyBlockDevice::new_not_dirty(), Clock, 0xAA00_0000); - let v = c.open_raw_volume(VolumeIdx(0), false).unwrap(); + let v = c + .open_raw_volume(VolumeIdx(0), VolumeOpenMode::ReadWrite) + .unwrap(); let expected_id = RawVolume(SearchId(0xAA00_0000)); assert_eq!(v, expected_id); assert_eq!( @@ -1811,7 +1812,7 @@ mod tests { &VolumeInfo { volume_id: expected_id, idx: VolumeIdx(0), - read_only: false, + open_mode: VolumeOpenMode::ReadWrite, volume_type: VolumeType::Fat(crate::FatVolume { lba_start: BlockIdx(1), num_blocks: BlockCount(0x0011_2233), @@ -1833,7 +1834,6 @@ mod tests { ); let VolumeType::Fat(fat_info) = &c.open_volumes[0].volume_type; assert_eq!(c.volume_status_dirty(fat_info).unwrap(), false); - c.set_volume_status_dirty(fat_info, true).unwrap(); } #[test] @@ -1841,7 +1841,9 @@ mod tests { let mut c: VolumeManager = VolumeManager::new_with_limits(DummyBlockDevice::new_dirty(), Clock, 0xAA00_0000); - let v = c.open_raw_volume(VolumeIdx(0), false).unwrap(); + let v = c + .open_raw_volume(VolumeIdx(0), VolumeOpenMode::ReadWrite) + .unwrap(); let expected_id = RawVolume(SearchId(0xAA00_0000)); assert_eq!(v, expected_id); assert_eq!( @@ -1849,7 +1851,7 @@ mod tests { &VolumeInfo { volume_id: expected_id, idx: VolumeIdx(0), - read_only: false, + open_mode: VolumeOpenMode::ReadWrite, volume_type: VolumeType::Fat(crate::FatVolume { lba_start: BlockIdx(1), num_blocks: BlockCount(0x0011_2233), @@ -1875,14 +1877,15 @@ mod tests { #[test] fn partition0_set_dirty() { - let mut c: VolumeManager = - VolumeManager::new_with_limits( - DummyBlockDevice::new_not_dirty_fattable_size_5(), - Clock, - 0xAA00_0000, - ); + let mut c: VolumeManager = VolumeManager::new_with_limits( + DummyBlockDevice::new_not_dirty_fattable_size_5(), + Clock, + 0xAA00_0000, + ); - let v = c.open_raw_volume(VolumeIdx(0), false).unwrap(); + let v = c + .open_raw_volume(VolumeIdx(0), VolumeOpenMode::ReadWrite) + .unwrap(); let expected_id = RawVolume(SearchId(0xAA00_0000)); assert_eq!(v, expected_id); assert_eq!( @@ -1890,7 +1893,7 @@ mod tests { &VolumeInfo { volume_id: expected_id, idx: VolumeIdx(0), - read_only: false, + open_mode: VolumeOpenMode::ReadWrite, volume_type: VolumeType::Fat(crate::FatVolume { lba_start: BlockIdx(1), num_blocks: BlockCount(0x0011_2233), @@ -1913,7 +1916,10 @@ mod tests { let VolumeType::Fat(fat_info) = &c.open_volumes[0].volume_type; assert_eq!(c.volume_status_dirty(fat_info).unwrap(), false); assert_eq!(c.block_device.blocks.borrow()[0], MBR_BLOCK); - assert_eq!(c.block_device.blocks.borrow()[1], FAT32_PARTITION0_BOOT_FAT_TABLE_SIZE_5); + assert_eq!( + c.block_device.blocks.borrow()[1], + FAT32_PARTITION0_BOOT_FAT_TABLE_SIZE_5 + ); assert_eq!(c.block_device.blocks.borrow()[2], FAT32_PARTITION0_FSINFO); assert_eq!(c.block_device.blocks.borrow()[3].contents[7] & (1 << 3), 8); assert_eq!(c.block_device.blocks.borrow()[4], DUMMY); @@ -1930,7 +1936,10 @@ mod tests { c.set_volume_status_dirty(fat_info, false).unwrap(); assert_eq!(c.volume_status_dirty(fat_info).unwrap(), false); assert_eq!(c.block_device.blocks.borrow()[0], MBR_BLOCK); - assert_eq!(c.block_device.blocks.borrow()[1], FAT32_PARTITION0_BOOT_FAT_TABLE_SIZE_5); + assert_eq!( + c.block_device.blocks.borrow()[1], + FAT32_PARTITION0_BOOT_FAT_TABLE_SIZE_5 + ); assert_eq!(c.block_device.blocks.borrow()[2], FAT32_PARTITION0_FSINFO); assert_eq!(c.block_device.blocks.borrow()[3].contents[7] & (1 << 3), 8); assert_eq!(c.block_device.blocks.borrow()[4], DUMMY); From fbf4d20f0b8bffd5314046c192677f85ea94eab0 Mon Sep 17 00:00:00 2001 From: Martin Marmsoler Date: Mon, 3 Jun 2024 22:07:11 +0200 Subject: [PATCH 08/17] make volume_status_dirty public so it can be also used outside of tests --- src/fat/fat_table.rs | 1 - src/volume_mgr.rs | 5 +++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/fat/fat_table.rs b/src/fat/fat_table.rs index 776cb2d3..dc98f747 100644 --- a/src/fat/fat_table.rs +++ b/src/fat/fat_table.rs @@ -26,7 +26,6 @@ impl<'a> FatTable<'a> { const FAT16_DIRTY_BIT: u16 = 15; const FAT32_DIRTY_BIT: u32 = 27; - #[cfg(test)] pub(crate) fn dirty(&self) -> bool { match self.fat_type { FatType::Fat16 => { diff --git a/src/volume_mgr.rs b/src/volume_mgr.rs index 0531538b..31da5565 100644 --- a/src/volume_mgr.rs +++ b/src/volume_mgr.rs @@ -394,8 +394,9 @@ where } Ok(()) } - #[cfg(test)] - fn volume_status_dirty(&self, volume: &FatVolume) -> Result> { + + /// Checking if the volume is dirty or was unmounted correctly in a previous usage + pub fn volume_status_dirty(&self, volume: &FatVolume) -> Result> { let mut blocks = [Block::new()]; let fat_table1_start = volume.lba_start + volume.fat_start; self.block_device From 87bf066e9a04d4d7dfd7398406df3a622ab17292 Mon Sep 17 00:00:00 2001 From: Martin Marmsoler Date: Mon, 3 Jun 2024 22:27:07 +0200 Subject: [PATCH 09/17] use directly raw volume instead of FatVolume. Do not set dirty if already set Reason: the function can determine it self. --- src/volume_mgr.rs | 51 +++++++++++++++++++++++++---------------------- 1 file changed, 27 insertions(+), 24 deletions(-) diff --git a/src/volume_mgr.rs b/src/volume_mgr.rs index 31da5565..9fd3d1e2 100644 --- a/src/volume_mgr.rs +++ b/src/volume_mgr.rs @@ -134,9 +134,7 @@ where ) -> Result, Error> { let v = self.open_raw_volume(volume_idx, open_mode)?; if open_mode != VolumeOpenMode::ReadOnly { - let idx = self.get_volume_by_id(v)?; - let VolumeType::Fat(volume_type) = &self.open_volumes[idx].volume_type; - self.set_volume_status_dirty(volume_type, true)?; + self.set_volume_status_dirty(v, true)?; } Ok(v.to_volume(self)) } @@ -360,8 +358,7 @@ where } let volume_idx = self.get_volume_by_id(volume)?; if self.open_volumes[volume_idx].open_mode != VolumeOpenMode::ReadOnly { - let VolumeType::Fat(volume_type) = &self.open_volumes[volume_idx].volume_type; - self.set_volume_status_dirty(volume_type, false)?; + self.set_volume_status_dirty(volume, false)?; } self.open_volumes.swap_remove(volume_idx); @@ -372,10 +369,12 @@ where /// Sets the volume status dirty to dirty if true, to not dirty if false fn set_volume_status_dirty( &self, - volume: &FatVolume, + volume: RawVolume, dirty: bool, ) -> Result<(), Error> { let mut blocks = [Block::new()]; + let idx = self.get_volume_by_id(volume)?; + let VolumeType::Fat(volume) = &self.open_volumes[idx].volume_type; let fat_table1_start = volume.lba_start + volume.fat_start; self.block_device .read(&mut blocks, fat_table1_start, "reading fat table")?; @@ -383,21 +382,25 @@ where let mut fat_table = fat::FatTable::create_from_bytes(&mut block.contents, volume.get_fat_type()) .map_err(Error::FormatError)?; - fat_table.set_dirty(dirty); - if volume.fat_nums == 1 || volume.fat_nums == 2 { - self.block_device.write(&blocks, fat_table1_start)?; - // Synchronize also backup fat table - if volume.fat_nums == 2 { - self.block_device - .write(&blocks, fat_table1_start + volume.fat_size)? + if !fat_table.dirty() { + fat_table.set_dirty(dirty); + if volume.fat_nums == 1 || volume.fat_nums == 2 { + self.block_device.write(&blocks, fat_table1_start)?; + // Synchronize also backup fat table + if volume.fat_nums == 2 { + self.block_device + .write(&blocks, fat_table1_start + volume.fat_size)? + } } } Ok(()) } /// Checking if the volume is dirty or was unmounted correctly in a previous usage - pub fn volume_status_dirty(&self, volume: &FatVolume) -> Result> { + pub fn volume_status_dirty(&self, volume: RawVolume) -> Result> { let mut blocks = [Block::new()]; + let volume_idx = self.get_volume_by_id(volume)?; + let VolumeType::Fat(volume) = &self.open_volumes[volume_idx].volume_type; let fat_table1_start = volume.lba_start + volume.fat_start; self.block_device .read(&mut blocks, fat_table1_start, "reading fat table")?; @@ -1833,8 +1836,8 @@ mod tests { }) } ); - let VolumeType::Fat(fat_info) = &c.open_volumes[0].volume_type; - assert_eq!(c.volume_status_dirty(fat_info).unwrap(), false); + let volume = c.open_volumes[0].volume_id; + assert_eq!(c.volume_status_dirty(volume).unwrap(), false); } #[test] @@ -1872,8 +1875,8 @@ mod tests { }) } ); - let VolumeType::Fat(fat_info) = &c.open_volumes[0].volume_type; - assert_eq!(c.volume_status_dirty(fat_info).unwrap(), true); + let volume = c.open_volumes[0].volume_id; + assert_eq!(c.volume_status_dirty(volume).unwrap(), true); } #[test] @@ -1914,8 +1917,8 @@ mod tests { }) } ); - let VolumeType::Fat(fat_info) = &c.open_volumes[0].volume_type; - assert_eq!(c.volume_status_dirty(fat_info).unwrap(), false); + let volume = c.open_volumes[0].volume_id; + assert_eq!(c.volume_status_dirty(volume).unwrap(), false); assert_eq!(c.block_device.blocks.borrow()[0], MBR_BLOCK); assert_eq!( c.block_device.blocks.borrow()[1], @@ -1929,13 +1932,13 @@ mod tests { assert_eq!(c.block_device.blocks.borrow()[7], DUMMY); assert_eq!(c.block_device.blocks.borrow()[8].contents[7] & (1 << 3), 8); - c.set_volume_status_dirty(fat_info, true).unwrap(); - assert_eq!(c.volume_status_dirty(fat_info).unwrap(), true); + c.set_volume_status_dirty(volume, true).unwrap(); + assert_eq!(c.volume_status_dirty(volume).unwrap(), true); assert_eq!(c.block_device.blocks.borrow()[3].contents[7] & (1 << 3), 0); assert_eq!(c.block_device.blocks.borrow()[8].contents[7] & (1 << 3), 0); - c.set_volume_status_dirty(fat_info, false).unwrap(); - assert_eq!(c.volume_status_dirty(fat_info).unwrap(), false); + c.set_volume_status_dirty(volume, false).unwrap(); + assert_eq!(c.volume_status_dirty(volume).unwrap(), false); assert_eq!(c.block_device.blocks.borrow()[0], MBR_BLOCK); assert_eq!( c.block_device.blocks.borrow()[1], From 8ab0ceaa06168709e81522d1fadc819f9882a6e5 Mon Sep 17 00:00:00 2001 From: Martin Marmsoler Date: Wed, 5 Jun 2024 20:06:44 +0200 Subject: [PATCH 10/17] fix ci --- examples/shell.rs | 6 ++++- src/lib.rs | 2 +- src/volume_mgr.rs | 3 +++ tests/directories.rs | 18 +++++++-------- tests/open_files.rs | 4 ++-- tests/read_file.rs | 8 +++---- tests/volume.rs | 54 ++++++++++++++++++++++++++++++++++++-------- tests/write_file.rs | 6 ++--- 8 files changed, 72 insertions(+), 29 deletions(-) diff --git a/examples/shell.rs b/examples/shell.rs index 0e41ce1c..030e0088 100644 --- a/examples/shell.rs +++ b/examples/shell.rs @@ -73,6 +73,7 @@ use std::io::prelude::*; use embedded_sdmmc::{ Error as EsError, RawDirectory, RawVolume, ShortFileName, VolumeIdx, VolumeManager, + VolumeOpenMode, }; use crate::linux::{Clock, LinuxBlockDevice}; @@ -531,7 +532,10 @@ fn main() -> Result<(), Error> { let mut current_volume = None; for volume_no in 0..4 { - match ctx.volume_mgr.open_raw_volume(VolumeIdx(volume_no)) { + match ctx + .volume_mgr + .open_raw_volume(VolumeIdx(volume_no), VolumeOpenMode::ReadWrite) + { Ok(volume) => { println!("Volume # {}: found", Context::volume_to_letter(volume_no)); match ctx.volume_mgr.open_root_dir(volume) { diff --git a/src/lib.rs b/src/lib.rs index aa98fb63..18b3ad14 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -75,7 +75,7 @@ pub mod filesystem; pub mod sdcard; use filesystem::SearchId; -use volume_mgr::VolumeOpenMode; +pub use volume_mgr::VolumeOpenMode; #[doc(inline)] pub use crate::blockdevice::{Block, BlockCount, BlockDevice, BlockIdx}; diff --git a/src/volume_mgr.rs b/src/volume_mgr.rs index 9fd3d1e2..4d10b906 100644 --- a/src/volume_mgr.rs +++ b/src/volume_mgr.rs @@ -18,9 +18,12 @@ use crate::{ }; use heapless::Vec; +/// Opening volume mode #[derive(Debug, PartialEq, Eq, Clone, Copy)] pub enum VolumeOpenMode { + /// Opening volume read only. This is faster than ReadWrite if only readings are done ReadOnly, + /// Opening volume for reading and writing. ReadWrite, } diff --git a/tests/directories.rs b/tests/directories.rs index df9154f4..363d18a7 100644 --- a/tests/directories.rs +++ b/tests/directories.rs @@ -1,6 +1,6 @@ //! Directory related tests -use embedded_sdmmc::{Mode, ShortFileName}; +use embedded_sdmmc::{Mode, ShortFileName, VolumeOpenMode}; mod utils; @@ -41,7 +41,7 @@ fn fat16_root_directory_listing() { let mut volume_mgr = embedded_sdmmc::VolumeManager::new(disk, time_source); let fat16_volume = volume_mgr - .open_raw_volume(embedded_sdmmc::VolumeIdx(0)) + .open_raw_volume(embedded_sdmmc::VolumeIdx(0), VolumeOpenMode::ReadWrite) .expect("open volume 0"); let root_dir = volume_mgr .open_root_dir(fat16_volume) @@ -103,7 +103,7 @@ fn fat16_sub_directory_listing() { let mut volume_mgr = embedded_sdmmc::VolumeManager::new(disk, time_source); let fat16_volume = volume_mgr - .open_raw_volume(embedded_sdmmc::VolumeIdx(0)) + .open_raw_volume(embedded_sdmmc::VolumeIdx(0), VolumeOpenMode::ReadWrite) .expect("open volume 0"); let root_dir = volume_mgr .open_root_dir(fat16_volume) @@ -168,7 +168,7 @@ fn fat32_root_directory_listing() { let mut volume_mgr = embedded_sdmmc::VolumeManager::new(disk, time_source); let fat32_volume = volume_mgr - .open_raw_volume(embedded_sdmmc::VolumeIdx(1)) + .open_raw_volume(embedded_sdmmc::VolumeIdx(1), VolumeOpenMode::ReadWrite) .expect("open volume 1"); let root_dir = volume_mgr .open_root_dir(fat32_volume) @@ -230,7 +230,7 @@ fn open_dir_twice() { let mut volume_mgr = embedded_sdmmc::VolumeManager::new(disk, time_source); let fat32_volume = volume_mgr - .open_raw_volume(embedded_sdmmc::VolumeIdx(1)) + .open_raw_volume(embedded_sdmmc::VolumeIdx(1), VolumeOpenMode::ReadWrite) .expect("open volume 1"); let root_dir = volume_mgr @@ -276,7 +276,7 @@ fn open_too_many_dirs() { > = embedded_sdmmc::VolumeManager::new_with_limits(disk, time_source, 0x1000_0000); let fat32_volume = volume_mgr - .open_raw_volume(embedded_sdmmc::VolumeIdx(1)) + .open_raw_volume(embedded_sdmmc::VolumeIdx(1), VolumeOpenMode::ReadWrite) .expect("open volume 1"); let root_dir = volume_mgr .open_root_dir(fat32_volume) @@ -295,7 +295,7 @@ fn find_dir_entry() { let mut volume_mgr = embedded_sdmmc::VolumeManager::new(disk, time_source); let fat32_volume = volume_mgr - .open_raw_volume(embedded_sdmmc::VolumeIdx(1)) + .open_raw_volume(embedded_sdmmc::VolumeIdx(1), VolumeOpenMode::ReadWrite) .expect("open volume 1"); let root_dir = volume_mgr @@ -325,7 +325,7 @@ fn delete_file() { let mut volume_mgr = embedded_sdmmc::VolumeManager::new(disk, time_source); let fat32_volume = volume_mgr - .open_raw_volume(embedded_sdmmc::VolumeIdx(1)) + .open_raw_volume(embedded_sdmmc::VolumeIdx(1), VolumeOpenMode::ReadWrite) .expect("open volume 1"); let root_dir = volume_mgr @@ -370,7 +370,7 @@ fn make_directory() { let mut volume_mgr = embedded_sdmmc::VolumeManager::new(disk, time_source); let fat32_volume = volume_mgr - .open_raw_volume(embedded_sdmmc::VolumeIdx(1)) + .open_raw_volume(embedded_sdmmc::VolumeIdx(1), VolumeOpenMode::ReadWrite) .expect("open volume 1"); let root_dir = volume_mgr diff --git a/tests/open_files.rs b/tests/open_files.rs index 10e21818..59a50ae4 100644 --- a/tests/open_files.rs +++ b/tests/open_files.rs @@ -1,6 +1,6 @@ //! File opening related tests -use embedded_sdmmc::{Error, Mode, VolumeIdx, VolumeManager}; +use embedded_sdmmc::{Error, Mode, VolumeIdx, VolumeManager, VolumeOpenMode}; mod utils; @@ -11,7 +11,7 @@ fn open_files() { let mut volume_mgr: VolumeManager>, utils::TestTimeSource, 4, 2, 1> = VolumeManager::new_with_limits(disk, time_source, 0xAA00_0000); let volume = volume_mgr - .open_raw_volume(VolumeIdx(0)) + .open_raw_volume(VolumeIdx(0), VolumeOpenMode::ReadWrite) .expect("open volume"); let root_dir = volume_mgr.open_root_dir(volume).expect("open root dir"); diff --git a/tests/read_file.rs b/tests/read_file.rs index b7c80c95..1bc059e9 100644 --- a/tests/read_file.rs +++ b/tests/read_file.rs @@ -14,7 +14,7 @@ fn read_file_512_blocks() { let mut volume_mgr = embedded_sdmmc::VolumeManager::new(disk, time_source); let fat16_volume = volume_mgr - .open_raw_volume(embedded_sdmmc::VolumeIdx(0)) + .open_raw_volume(embedded_sdmmc::VolumeIdx(0), VolumeOpenMode::ReadWrite) .expect("open volume 0"); let root_dir = volume_mgr .open_root_dir(fat16_volume) @@ -56,7 +56,7 @@ fn read_file_all() { let mut volume_mgr = embedded_sdmmc::VolumeManager::new(disk, time_source); let fat16_volume = volume_mgr - .open_raw_volume(embedded_sdmmc::VolumeIdx(0)) + .open_raw_volume(embedded_sdmmc::VolumeIdx(0), VolumeOpenMode::ReadWrite) .expect("open volume 0"); let root_dir = volume_mgr .open_root_dir(fat16_volume) @@ -90,7 +90,7 @@ fn read_file_prime_blocks() { let mut volume_mgr = embedded_sdmmc::VolumeManager::new(disk, time_source); let fat16_volume = volume_mgr - .open_raw_volume(embedded_sdmmc::VolumeIdx(0)) + .open_raw_volume(embedded_sdmmc::VolumeIdx(0), VolumeOpenMode::ReadWrite) .expect("open volume 0"); let root_dir = volume_mgr .open_root_dir(fat16_volume) @@ -133,7 +133,7 @@ fn read_file_backwards() { let mut volume_mgr = embedded_sdmmc::VolumeManager::new(disk, time_source); let fat16_volume = volume_mgr - .open_raw_volume(embedded_sdmmc::VolumeIdx(0)) + .open_raw_volume(embedded_sdmmc::VolumeIdx(0), VolumeOpenMode::ReadWrite) .expect("open volume 0"); let root_dir = volume_mgr .open_root_dir(fat16_volume) diff --git a/tests/volume.rs b/tests/volume.rs index 633a8d25..b3ec0ccb 100644 --- a/tests/volume.rs +++ b/tests/volume.rs @@ -1,5 +1,7 @@ //! Volume related tests +use embedded_sdmmc::VolumeOpenMode; + mod utils; #[test] @@ -16,12 +18,12 @@ fn open_all_volumes() { // Open Volume 0 let fat16_volume = volume_mgr - .open_raw_volume(embedded_sdmmc::VolumeIdx(0)) + .open_raw_volume(embedded_sdmmc::VolumeIdx(0), VolumeOpenMode::ReadWrite) .expect("open volume 0"); // Fail to Open Volume 0 again assert!(matches!( - volume_mgr.open_raw_volume(embedded_sdmmc::VolumeIdx(0)), + volume_mgr.open_raw_volume(embedded_sdmmc::VolumeIdx(0), VolumeOpenMode::ReadWrite), Err(embedded_sdmmc::Error::VolumeAlreadyOpen) )); @@ -29,23 +31,23 @@ fn open_all_volumes() { // Open Volume 1 let fat32_volume = volume_mgr - .open_raw_volume(embedded_sdmmc::VolumeIdx(1)) + .open_raw_volume(embedded_sdmmc::VolumeIdx(1), VolumeOpenMode::ReadWrite) .expect("open volume 1"); // Fail to Volume 1 again assert!(matches!( - volume_mgr.open_raw_volume(embedded_sdmmc::VolumeIdx(1)), + volume_mgr.open_raw_volume(embedded_sdmmc::VolumeIdx(1), VolumeOpenMode::ReadWrite), Err(embedded_sdmmc::Error::VolumeAlreadyOpen) )); // Open Volume 0 again let fat16_volume = volume_mgr - .open_raw_volume(embedded_sdmmc::VolumeIdx(0)) + .open_raw_volume(embedded_sdmmc::VolumeIdx(0), VolumeOpenMode::ReadWrite) .expect("open volume 0"); // Open any volume - too many volumes (0 and 1 are open) assert!(matches!( - volume_mgr.open_raw_volume(embedded_sdmmc::VolumeIdx(0)), + volume_mgr.open_raw_volume(embedded_sdmmc::VolumeIdx(0), VolumeOpenMode::ReadWrite), Err(embedded_sdmmc::Error::TooManyOpenVolumes) )); @@ -54,13 +56,13 @@ fn open_all_volumes() { // This isn't a valid volume assert!(matches!( - volume_mgr.open_raw_volume(embedded_sdmmc::VolumeIdx(2)), + volume_mgr.open_raw_volume(embedded_sdmmc::VolumeIdx(2), VolumeOpenMode::ReadWrite), Err(embedded_sdmmc::Error::FormatError(_e)) )); // This isn't a valid volume assert!(matches!( - volume_mgr.open_raw_volume(embedded_sdmmc::VolumeIdx(9)), + volume_mgr.open_raw_volume(embedded_sdmmc::VolumeIdx(9), VolumeOpenMode::ReadWrite), Err(embedded_sdmmc::Error::NoSuchVolume) )); @@ -79,7 +81,7 @@ fn close_volume_too_early() { let mut volume_mgr = embedded_sdmmc::VolumeManager::new(disk, time_source); let volume = volume_mgr - .open_raw_volume(embedded_sdmmc::VolumeIdx(0)) + .open_raw_volume(embedded_sdmmc::VolumeIdx(0), VolumeOpenMode::ReadWrite) .expect("open volume 0"); let root_dir = volume_mgr.open_root_dir(volume).expect("open root dir"); @@ -102,6 +104,40 @@ fn close_volume_too_early() { )); } +#[test] +fn volume_read_only_open_file_read_write() { + let time_source = utils::make_time_source(); + let disk = utils::make_block_device(utils::DISK_SOURCE).unwrap(); + let mut volume_mgr = embedded_sdmmc::VolumeManager::new(disk, time_source); + + let volume = volume_mgr + .open_raw_volume(embedded_sdmmc::VolumeIdx(0), VolumeOpenMode::ReadOnly) + .expect("open volume 0"); + let root_dir = volume_mgr.open_root_dir(volume).expect("open root dir"); + + // Dir open + assert!(matches!( + volume_mgr.open_file_in_dir(root_dir, "64MB.DAT", embedded_sdmmc::Mode::ReadWriteAppend), + Err(embedded_sdmmc::Error::VolumeReadOnly) + )); +} + +#[test] +fn volume_read_only_open_file_read_only() { + let time_source = utils::make_time_source(); + let disk = utils::make_block_device(utils::DISK_SOURCE).unwrap(); + let mut volume_mgr = embedded_sdmmc::VolumeManager::new(disk, time_source); + + let volume = volume_mgr + .open_raw_volume(embedded_sdmmc::VolumeIdx(0), VolumeOpenMode::ReadOnly) + .expect("open volume 0"); + let root_dir = volume_mgr.open_root_dir(volume).expect("open root dir"); + + volume_mgr + .open_file_in_dir(root_dir, "64MB.DAT", embedded_sdmmc::Mode::ReadOnly) + .unwrap(); +} + // **************************************************************************** // // End Of File diff --git a/tests/write_file.rs b/tests/write_file.rs index 97e7bcdc..682cce78 100644 --- a/tests/write_file.rs +++ b/tests/write_file.rs @@ -1,6 +1,6 @@ //! File opening related tests -use embedded_sdmmc::{Mode, VolumeIdx, VolumeManager}; +use embedded_sdmmc::{Mode, VolumeIdx, VolumeManager, VolumeOpenMode}; mod utils; @@ -11,7 +11,7 @@ fn append_file() { let mut volume_mgr: VolumeManager>, utils::TestTimeSource, 4, 2, 1> = VolumeManager::new_with_limits(disk, time_source, 0xAA00_0000); let volume = volume_mgr - .open_raw_volume(VolumeIdx(0)) + .open_raw_volume(VolumeIdx(0), VolumeOpenMode::ReadWrite) .expect("open volume"); let root_dir = volume_mgr.open_root_dir(volume).expect("open root dir"); @@ -62,7 +62,7 @@ fn flush_file() { let mut volume_mgr: VolumeManager>, utils::TestTimeSource, 4, 2, 1> = VolumeManager::new_with_limits(disk, time_source, 0xAA00_0000); let volume = volume_mgr - .open_raw_volume(VolumeIdx(0)) + .open_raw_volume(VolumeIdx(0), VolumeOpenMode::ReadWrite) .expect("open volume"); let root_dir = volume_mgr.open_root_dir(volume).expect("open root dir"); From 598e64ed0958ca87de10c70b6c06a7222e6cf8d3 Mon Sep 17 00:00:00 2001 From: Martin Marmsoler Date: Wed, 5 Jun 2024 20:18:51 +0200 Subject: [PATCH 11/17] derive defmt::Format --- src/volume_mgr.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/volume_mgr.rs b/src/volume_mgr.rs index 4d10b906..ebbf2b16 100644 --- a/src/volume_mgr.rs +++ b/src/volume_mgr.rs @@ -19,6 +19,7 @@ use crate::{ use heapless::Vec; /// Opening volume mode +#[cfg_attr(feature = "defmt-log", derive(defmt::Format))] #[derive(Debug, PartialEq, Eq, Clone, Copy)] pub enum VolumeOpenMode { /// Opening volume read only. This is faster than ReadWrite if only readings are done From d236739767d74cdb08a9b4727f42e2923451daba Mon Sep 17 00:00:00 2001 From: Martin Marmsoler Date: Wed, 5 Jun 2024 20:22:13 +0200 Subject: [PATCH 12/17] fix compilation --- tests/read_file.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/read_file.rs b/tests/read_file.rs index 1bc059e9..1cdce879 100644 --- a/tests/read_file.rs +++ b/tests/read_file.rs @@ -1,7 +1,7 @@ //! Reading related tests +use embedded_sdmmc::VolumeOpenMode; use sha2::Digest; - mod utils; static TEST_DAT_SHA256_SUM: &[u8] = From 0dcab1600d19381efffe0d8ed380cd2d97888641 Mon Sep 17 00:00:00 2001 From: Martin Marmsoler Date: Wed, 5 Jun 2024 20:25:05 +0200 Subject: [PATCH 13/17] fix test --- src/volume_mgr.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/volume_mgr.rs b/src/volume_mgr.rs index ebbf2b16..74bf2896 100644 --- a/src/volume_mgr.rs +++ b/src/volume_mgr.rs @@ -386,7 +386,7 @@ where let mut fat_table = fat::FatTable::create_from_bytes(&mut block.contents, volume.get_fat_type()) .map_err(Error::FormatError)?; - if !fat_table.dirty() { + if fat_table.dirty() != dirty { fat_table.set_dirty(dirty); if volume.fat_nums == 1 || volume.fat_nums == 2 { self.block_device.write(&blocks, fat_table1_start)?; From 06fb719213bf241e19b30e1070c2c0d4fcf0274e Mon Sep 17 00:00:00 2001 From: Martin Marmsoler Date: Thu, 6 Jun 2024 19:18:19 +0200 Subject: [PATCH 14/17] use open_volume with parameter instead of two different functions --- examples/append_file.rs | 4 ++-- examples/big_dir.rs | 4 ++-- examples/create_file.rs | 4 ++-- examples/delete_file.rs | 4 ++-- examples/list_dir.rs | 4 ++-- examples/read_file.rs | 4 ++-- examples/readme_test.rs | 5 +++-- src/lib.rs | 4 ++-- src/volume_mgr.rs | 23 +---------------------- tests/open_files.rs | 4 +++- 10 files changed, 21 insertions(+), 39 deletions(-) diff --git a/examples/append_file.rs b/examples/append_file.rs index f5a3bc43..fcd80d80 100644 --- a/examples/append_file.rs +++ b/examples/append_file.rs @@ -22,7 +22,7 @@ use linux::*; const FILE_TO_APPEND: &str = "README.TXT"; -use embedded_sdmmc::{Error, Mode, VolumeIdx, VolumeManager}; +use embedded_sdmmc::{Error, Mode, VolumeIdx, VolumeManager, VolumeOpenMode}; fn main() -> Result<(), embedded_sdmmc::Error> { env_logger::init(); @@ -32,7 +32,7 @@ fn main() -> Result<(), embedded_sdmmc::Error> { let lbd = LinuxBlockDevice::new(filename, print_blocks).map_err(Error::DeviceError)?; let mut volume_mgr: VolumeManager = VolumeManager::new_with_limits(lbd, Clock, 0xAA00_0000); - let mut volume = volume_mgr.open_volume(VolumeIdx(0))?; + let mut volume = volume_mgr.open_volume(VolumeIdx(0), VolumeOpenMode::ReadWrite)?; let mut root_dir = volume.open_root_dir()?; println!("\nCreating file {}...", FILE_TO_APPEND); let mut f = root_dir.open_file_in_dir(FILE_TO_APPEND, Mode::ReadWriteAppend)?; diff --git a/examples/big_dir.rs b/examples/big_dir.rs index b355c3c4..2f213156 100644 --- a/examples/big_dir.rs +++ b/examples/big_dir.rs @@ -3,7 +3,7 @@ extern crate embedded_sdmmc; mod linux; use linux::*; -use embedded_sdmmc::{Error, VolumeManager}; +use embedded_sdmmc::{Error, VolumeManager, VolumeOpenMode}; fn main() -> Result<(), embedded_sdmmc::Error> { env_logger::init(); @@ -14,7 +14,7 @@ fn main() -> Result<(), embedded_sdmmc::Error> { let mut volume_mgr: VolumeManager = VolumeManager::new_with_limits(lbd, Clock, 0xAA00_0000); let mut volume = volume_mgr - .open_volume(embedded_sdmmc::VolumeIdx(1)) + .open_volume(embedded_sdmmc::VolumeIdx(1), VolumeOpenMode::ReadWrite) .unwrap(); println!("Volume: {:?}", volume); let mut root_dir = volume.open_root_dir().unwrap(); diff --git a/examples/create_file.rs b/examples/create_file.rs index 81263ceb..38293891 100644 --- a/examples/create_file.rs +++ b/examples/create_file.rs @@ -22,7 +22,7 @@ use linux::*; const FILE_TO_CREATE: &str = "CREATE.TXT"; -use embedded_sdmmc::{Error, Mode, VolumeIdx, VolumeManager}; +use embedded_sdmmc::{Error, Mode, VolumeIdx, VolumeManager, VolumeOpenMode}; fn main() -> Result<(), embedded_sdmmc::Error> { env_logger::init(); @@ -32,7 +32,7 @@ fn main() -> Result<(), embedded_sdmmc::Error> { let lbd = LinuxBlockDevice::new(filename, print_blocks).map_err(Error::DeviceError)?; let mut volume_mgr: VolumeManager = VolumeManager::new_with_limits(lbd, Clock, 0xAA00_0000); - let mut volume = volume_mgr.open_volume(VolumeIdx(0))?; + let mut volume = volume_mgr.open_volume(VolumeIdx(0), VolumeOpenMode::ReadWrite)?; let mut root_dir = volume.open_root_dir()?; println!("\nCreating file {}...", FILE_TO_CREATE); // This will panic if the file already exists: use ReadWriteCreateOrAppend diff --git a/examples/delete_file.rs b/examples/delete_file.rs index 743b2d54..a0df0f8c 100644 --- a/examples/delete_file.rs +++ b/examples/delete_file.rs @@ -25,7 +25,7 @@ use linux::*; const FILE_TO_DELETE: &str = "README.TXT"; -use embedded_sdmmc::{Error, VolumeIdx, VolumeManager}; +use embedded_sdmmc::{Error, VolumeIdx, VolumeManager, VolumeOpenMode}; fn main() -> Result<(), embedded_sdmmc::Error> { env_logger::init(); @@ -35,7 +35,7 @@ fn main() -> Result<(), embedded_sdmmc::Error> { let lbd = LinuxBlockDevice::new(filename, print_blocks).map_err(Error::DeviceError)?; let mut volume_mgr: VolumeManager = VolumeManager::new_with_limits(lbd, Clock, 0xAA00_0000); - let mut volume = volume_mgr.open_volume(VolumeIdx(0))?; + let mut volume = volume_mgr.open_volume(VolumeIdx(0), VolumeOpenMode::ReadWrite)?; let mut root_dir = volume.open_root_dir()?; println!("Deleting file {}...", FILE_TO_DELETE); root_dir.delete_file_in_dir(FILE_TO_DELETE)?; diff --git a/examples/list_dir.rs b/examples/list_dir.rs index 18c121d4..fca8526d 100644 --- a/examples/list_dir.rs +++ b/examples/list_dir.rs @@ -37,7 +37,7 @@ extern crate embedded_sdmmc; mod linux; use linux::*; -use embedded_sdmmc::{Directory, VolumeIdx, VolumeManager}; +use embedded_sdmmc::{Directory, VolumeIdx, VolumeManager, VolumeOpenMode}; type Error = embedded_sdmmc::Error; @@ -49,7 +49,7 @@ fn main() -> Result<(), Error> { let lbd = LinuxBlockDevice::new(filename, print_blocks).map_err(Error::DeviceError)?; let mut volume_mgr: VolumeManager = VolumeManager::new_with_limits(lbd, Clock, 0xAA00_0000); - let mut volume = volume_mgr.open_volume(VolumeIdx(0))?; + let mut volume = volume_mgr.open_volume(VolumeIdx(0), VolumeOpenMode::ReadWrite)?; let root_dir = volume.open_root_dir()?; list_dir(root_dir, "/")?; Ok(()) diff --git a/examples/read_file.rs b/examples/read_file.rs index 1a958c1c..314731a8 100644 --- a/examples/read_file.rs +++ b/examples/read_file.rs @@ -39,7 +39,7 @@ use linux::*; const FILE_TO_READ: &str = "README.TXT"; -use embedded_sdmmc::{Error, Mode, VolumeIdx, VolumeManager}; +use embedded_sdmmc::{Error, Mode, VolumeIdx, VolumeManager, VolumeOpenMode}; fn main() -> Result<(), embedded_sdmmc::Error> { env_logger::init(); @@ -49,7 +49,7 @@ fn main() -> Result<(), embedded_sdmmc::Error> { let lbd = LinuxBlockDevice::new(filename, print_blocks).map_err(Error::DeviceError)?; let mut volume_mgr: VolumeManager = VolumeManager::new_with_limits(lbd, Clock, 0xAA00_0000); - let mut volume = volume_mgr.open_volume(VolumeIdx(0))?; + let mut volume = volume_mgr.open_volume(VolumeIdx(0), VolumeOpenMode::ReadWrite)?; let mut root_dir = volume.open_root_dir()?; println!("\nReading file {}...", FILE_TO_READ); let mut f = root_dir.open_file_in_dir(FILE_TO_READ, Mode::ReadOnly)?; diff --git a/examples/readme_test.rs b/examples/readme_test.rs index ed4b1468..2a929cd1 100644 --- a/examples/readme_test.rs +++ b/examples/readme_test.rs @@ -7,7 +7,7 @@ use core::cell::RefCell; -use embedded_sdmmc::sdcard::DummyCsPin; +use embedded_sdmmc::{sdcard::DummyCsPin, VolumeOpenMode}; struct FakeSpiBus(); @@ -113,7 +113,8 @@ fn main() -> Result<(), Error> { let mut volume_mgr = embedded_sdmmc::VolumeManager::new(sdcard, time_source); // Try and access Volume 0 (i.e. the first partition). // The volume object holds information about the filesystem on that volume. - let mut volume0 = volume_mgr.open_volume(embedded_sdmmc::VolumeIdx(0))?; + let mut volume0 = + volume_mgr.open_volume(embedded_sdmmc::VolumeIdx(0), VolumeOpenMode::ReadWrite)?; println!("Volume 0: {:?}", volume0); // Open the root directory (mutably borrows from the volume). let mut root_dir = volume0.open_root_dir()?; diff --git a/src/lib.rs b/src/lib.rs index 18b3ad14..bad9175b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -17,7 +17,7 @@ //! suitable for reading SD and SDHC cards over SPI. //! //! ```rust -//! use embedded_sdmmc::{Error, Mode, SdCard, SdCardError, TimeSource, VolumeIdx, VolumeManager}; +//! use embedded_sdmmc::{Error, Mode, SdCard, SdCardError, TimeSource, VolumeIdx, VolumeManager, VolumeOpenMode}; //! //! fn example(spi: S, cs: CS, delay: D, ts: T) -> Result<(), Error> //! where @@ -29,7 +29,7 @@ //! let sdcard = SdCard::new(spi, cs, delay); //! println!("Card size is {} bytes", sdcard.num_bytes()?); //! let mut volume_mgr = VolumeManager::new(sdcard, ts); -//! let mut volume0 = volume_mgr.open_volume(VolumeIdx(0))?; +//! let mut volume0 = volume_mgr.open_volume(VolumeIdx(0), VolumeOpenMode::ReadOnly)?; //! println!("Volume 0: {:?}", volume0); //! let mut root_dir = volume0.open_root_dir()?; //! let mut my_file = root_dir.open_file_in_dir("MY_FILE.TXT", Mode::ReadOnly)?; diff --git a/src/volume_mgr.rs b/src/volume_mgr.rs index 74bf2896..4e4f0201 100644 --- a/src/volume_mgr.rs +++ b/src/volume_mgr.rs @@ -109,29 +109,8 @@ where /// /// We do not support GUID Partition Table disks. Nor do we support any /// concept of drive letters - that is for a higher layer to handle. - pub fn open_volume( - &mut self, - volume_idx: VolumeIdx, - ) -> Result, Error> { - return self._open_volume(volume_idx, VolumeOpenMode::ReadWrite); - } - - /// Get a read only volume (or partition) based on entries in the Master Boot Record. /// Opening and closing a read only volume is faster than a writable volume. - /// - /// We do not support GUID Partition Table disks. Nor do we support any - /// concept of drive letters - that is for a higher layer to handle. - pub fn open_volume_read_only( - &mut self, - volume_idx: VolumeIdx, - ) -> Result, Error> { - return self._open_volume(volume_idx, VolumeOpenMode::ReadOnly); - } - /// Get a volume (or partition) based on entries in the Master Boot Record. - /// - /// We do not support GUID Partition Table disks. Nor do we support any - /// concept of drive letters - that is for a higher layer to handle. - fn _open_volume( + pub fn open_volume( &mut self, volume_idx: VolumeIdx, open_mode: VolumeOpenMode, diff --git a/tests/open_files.rs b/tests/open_files.rs index 59a50ae4..f5323166 100644 --- a/tests/open_files.rs +++ b/tests/open_files.rs @@ -97,7 +97,9 @@ fn open_non_raw() { let disk = utils::make_block_device(utils::DISK_SOURCE).unwrap(); let mut volume_mgr: VolumeManager>, utils::TestTimeSource, 4, 2, 1> = VolumeManager::new_with_limits(disk, time_source, 0xAA00_0000); - let mut volume = volume_mgr.open_volume(VolumeIdx(0)).expect("open volume"); + let mut volume = volume_mgr + .open_volume(VolumeIdx(0), VolumeOpenMode::ReadWrite) + .expect("open volume"); let mut root_dir = volume.open_root_dir().expect("open root dir"); let mut f = root_dir .open_file_in_dir("README.TXT", Mode::ReadOnly) From 330f807d06e18f119d8e61a4e9edd88089b05829 Mon Sep 17 00:00:00 2001 From: Martin Marmsoler Date: Thu, 6 Jun 2024 22:36:38 +0200 Subject: [PATCH 15/17] set volume dirty always also for raw volumes --- src/volume_mgr.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/volume_mgr.rs b/src/volume_mgr.rs index 4e4f0201..ad6f1098 100644 --- a/src/volume_mgr.rs +++ b/src/volume_mgr.rs @@ -116,9 +116,6 @@ where open_mode: VolumeOpenMode, ) -> Result, Error> { let v = self.open_raw_volume(volume_idx, open_mode)?; - if open_mode != VolumeOpenMode::ReadOnly { - self.set_volume_status_dirty(v, true)?; - } Ok(v.to_volume(self)) } @@ -215,6 +212,9 @@ where }; // We already checked for space self.open_volumes.push(info).unwrap(); + if open_mode != VolumeOpenMode::ReadOnly { + self.set_volume_status_dirty(id, true)?; + } Ok(id) } _ => Err(Error::FormatError("Partition type not supported")), From 35e086b8e2cef47f2eea38a7f9392a1749b84517 Mon Sep 17 00:00:00 2001 From: Martin Marmsoler Date: Sun, 7 Jul 2024 09:09:55 +0200 Subject: [PATCH 16/17] fix compilation --- tests/read_file.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/read_file.rs b/tests/read_file.rs index 1cdce879..0db9a1dd 100644 --- a/tests/read_file.rs +++ b/tests/read_file.rs @@ -191,7 +191,7 @@ fn read_file_with_odd_seek() { let mut volume_mgr = embedded_sdmmc::VolumeManager::new(disk, time_source); let mut volume = volume_mgr - .open_volume(embedded_sdmmc::VolumeIdx(0)) + .open_volume(embedded_sdmmc::VolumeIdx(0), VolumeOpenMode::ReadOnly) .unwrap(); let mut root_dir = volume.open_root_dir().unwrap(); let mut f = root_dir From e7eb7ba3e1f836aa86a780baac97eac39ffeae03 Mon Sep 17 00:00:00 2001 From: Martin Marmsoler Date: Sun, 7 Jul 2024 09:24:57 +0200 Subject: [PATCH 17/17] fix tests. If ReadWrite, the dirty flag will be set when opening the volume --- src/volume_mgr.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/volume_mgr.rs b/src/volume_mgr.rs index ad6f1098..22841516 100644 --- a/src/volume_mgr.rs +++ b/src/volume_mgr.rs @@ -1790,7 +1790,7 @@ mod tests { VolumeManager::new_with_limits(DummyBlockDevice::new_not_dirty(), Clock, 0xAA00_0000); let v = c - .open_raw_volume(VolumeIdx(0), VolumeOpenMode::ReadWrite) + .open_raw_volume(VolumeIdx(0), VolumeOpenMode::ReadOnly) .unwrap(); let expected_id = RawVolume(SearchId(0xAA00_0000)); assert_eq!(v, expected_id); @@ -1799,7 +1799,7 @@ mod tests { &VolumeInfo { volume_id: expected_id, idx: VolumeIdx(0), - open_mode: VolumeOpenMode::ReadWrite, + open_mode: VolumeOpenMode::ReadOnly, volume_type: VolumeType::Fat(crate::FatVolume { lba_start: BlockIdx(1), num_blocks: BlockCount(0x0011_2233), @@ -1871,7 +1871,7 @@ mod tests { ); let v = c - .open_raw_volume(VolumeIdx(0), VolumeOpenMode::ReadWrite) + .open_raw_volume(VolumeIdx(0), VolumeOpenMode::ReadOnly) .unwrap(); let expected_id = RawVolume(SearchId(0xAA00_0000)); assert_eq!(v, expected_id); @@ -1880,7 +1880,7 @@ mod tests { &VolumeInfo { volume_id: expected_id, idx: VolumeIdx(0), - open_mode: VolumeOpenMode::ReadWrite, + open_mode: VolumeOpenMode::ReadOnly, volume_type: VolumeType::Fat(crate::FatVolume { lba_start: BlockIdx(1), num_blocks: BlockCount(0x0011_2233),