diff --git a/examples/append_file.rs b/examples/append_file.rs index f5a3bc4..fcd80d8 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 b355c3c..2f21315 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 81263ce..3829389 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 743b2d5..a0df0f8 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 18c121d..fca8526 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 1a958c1..314731a 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 ed4b146..2a929cd 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/examples/shell.rs b/examples/shell.rs index 0e41ce1..030e008 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/fat/fat_table.rs b/src/fat/fat_table.rs new file mode 100644 index 0000000..dc98f74 --- /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 35641cb..4c0cf90 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 8f44c6d..0c5c461 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 1bcd429..bad9175 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)?; @@ -75,6 +75,7 @@ pub mod filesystem; pub mod sdcard; use filesystem::SearchId; +pub use volume_mgr::VolumeOpenMode; #[doc(inline)] pub use crate::blockdevice::{Block, BlockCount, BlockDevice, BlockIdx}; @@ -175,6 +176,8 @@ where VolumeStillInUse, /// You can't open a volume twice VolumeAlreadyOpen, + /// Volume is opened in read only mode + VolumeReadOnly, /// We can't do that yet Unsupported, /// Tried to read beyond end of file @@ -344,6 +347,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! + 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 15e4f42..2284151 100644 --- a/src/volume_mgr.rs +++ b/src/volume_mgr.rs @@ -12,12 +12,22 @@ 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; +/// 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 + ReadOnly, + /// Opening volume for reading and writing. + ReadWrite, +} + /// A `VolumeManager` wraps a block device and gives access to the FAT-formatted /// volumes within it. #[derive(Debug)] @@ -99,11 +109,13 @@ 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. + /// Opening and closing a read only volume is faster than a writable volume. pub fn open_volume( &mut self, volume_idx: VolumeIdx, + open_mode: VolumeOpenMode, ) -> Result, Error> { - let v = self.open_raw_volume(volume_idx)?; + let v = self.open_raw_volume(volume_idx, open_mode)?; Ok(v.to_volume(self)) } @@ -114,7 +126,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, + open_mode: VolumeOpenMode, + ) -> 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,9 +208,13 @@ where volume_id: id, idx: volume_idx, volume_type: volume, + open_mode: open_mode, }; // 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")), @@ -319,13 +339,61 @@ where return Err(Error::VolumeStillInUse); } } - let volume_idx = self.get_volume_by_id(volume)?; + if self.open_volumes[volume_idx].open_mode != VolumeOpenMode::ReadOnly { + self.set_volume_status_dirty(volume, 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: 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")?; + 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)?; + 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)?; + // 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: 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")?; + 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( &mut self, @@ -479,6 +547,10 @@ where let volume_info = &self.open_volumes[volume_idx]; let sfn = name.to_short_filename().map_err(Error::FilenameError)?; + if volume_info.open_mode == VolumeOpenMode::ReadOnly && 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) @@ -1126,8 +1198,12 @@ mod tests { use super::*; use crate::filesystem::SearchId; use crate::Timestamp; + use crate::VolumeType; + use std::cell::RefCell; - struct DummyBlockDevice; + struct DummyBlockDevice { + blocks: RefCell<[Block; 9]>, + } struct Clock; @@ -1150,6 +1226,524 @@ mod tests { } } + 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 + ], + }; + + // 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!( + "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 + ], + }; + + // 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 + ], + }; + + 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, + ]), + } + } + + 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, + ]), + } + } + + // 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 PartialEq for Block { + fn eq(&self, other: &Self) -> bool { + self.contents == other.contents + } + } + impl BlockDevice for DummyBlockDevice { type Error = Error; @@ -1160,181 +1754,6 @@ 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; 3] = [ - 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 { - contents: [ - 0xeb, 0x58, 0x90, 0x6d, 0x6b, 0x66, 0x73, 0x2e, 0x66, 0x61, 0x74, 0x00, - 0x02, 0x08, 0x20, 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 - ], - }, - 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" - ), - }, - ]; println!( "Reading block {} to {}", start_block_idx.0, @@ -1342,8 +1761,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); } @@ -1353,7 +1772,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. @@ -1365,9 +1787,11 @@ mod tests { #[test] fn partition0() { let mut c: VolumeManager = - VolumeManager::new_with_limits(DummyBlockDevice, Clock, 0xAA00_0000); + VolumeManager::new_with_limits(DummyBlockDevice::new_not_dirty(), Clock, 0xAA00_0000); - let v = c.open_raw_volume(VolumeIdx(0)).unwrap(); + let v = c + .open_raw_volume(VolumeIdx(0), VolumeOpenMode::ReadOnly) + .unwrap(); let expected_id = RawVolume(SearchId(0xAA00_0000)); assert_eq!(v, expected_id); assert_eq!( @@ -1375,16 +1799,19 @@ mod tests { &VolumeInfo { volume_id: expected_id, idx: VolumeIdx(0), + open_mode: VolumeOpenMode::ReadOnly, 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), @@ -1392,6 +1819,121 @@ mod tests { }) } ); + let volume = c.open_volumes[0].volume_id; + assert_eq!(c.volume_status_dirty(volume).unwrap(), false); + } + + #[test] + fn partition0_dirty() { + let mut c: VolumeManager = + VolumeManager::new_with_limits(DummyBlockDevice::new_dirty(), Clock, 0xAA00_0000); + + 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!( + &c.open_volumes[0], + &VolumeInfo { + volume_id: expected_id, + idx: VolumeIdx(0), + open_mode: VolumeOpenMode::ReadWrite, + 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 volume = c.open_volumes[0].volume_id; + assert_eq!(c.volume_status_dirty(volume).unwrap(), true); + } + + #[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), VolumeOpenMode::ReadOnly) + .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), + open_mode: VolumeOpenMode::ReadOnly, + 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 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], + 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(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(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], + 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); } } diff --git a/tests/directories.rs b/tests/directories.rs index df9154f..363d18a 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 10e2181..f532316 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"); @@ -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) diff --git a/tests/read_file.rs b/tests/read_file.rs index b7c80c9..0db9a1d 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] = @@ -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) @@ -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 diff --git a/tests/volume.rs b/tests/volume.rs index 633a8d2..b3ec0cc 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 97e7bcd..682cce7 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");