diff --git a/examples/big_dir.rs b/examples/big_dir.rs new file mode 100644 index 0000000..b355c3c --- /dev/null +++ b/examples/big_dir.rs @@ -0,0 +1,39 @@ +extern crate embedded_sdmmc; + +mod linux; +use linux::*; + +use embedded_sdmmc::{Error, VolumeManager}; + +fn main() -> Result<(), embedded_sdmmc::Error> { + env_logger::init(); + let mut args = std::env::args().skip(1); + let filename = args.next().unwrap_or_else(|| "/dev/mmcblk0".into()); + let print_blocks = args.find(|x| x == "-v").map(|_| true).unwrap_or(false); + 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(embedded_sdmmc::VolumeIdx(1)) + .unwrap(); + println!("Volume: {:?}", volume); + let mut root_dir = volume.open_root_dir().unwrap(); + + let mut file_num = 0; + loop { + file_num += 1; + let file_name = format!("{}.da", file_num); + println!("opening file {file_name} for writing"); + let mut file = root_dir + .open_file_in_dir( + file_name.as_str(), + embedded_sdmmc::Mode::ReadWriteCreateOrTruncate, + ) + .unwrap(); + let buf = b"hello world, from rust"; + println!("writing to file"); + file.write(&buf[..]).unwrap(); + println!("closing file"); + drop(file); + } +} diff --git a/src/fat/volume.rs b/src/fat/volume.rs index c946ec8..b6dd510 100644 --- a/src/fat/volume.rs +++ b/src/fat/volume.rs @@ -179,6 +179,9 @@ impl FatVolume { where D: BlockDevice, { + if cluster.0 > (u32::MAX / 4) { + panic!("next_cluster called on invalid cluster {:x?}", cluster); + } match &self.fat_specific_info { FatSpecificInfo::Fat16(_fat16_info) => { let fat_offset = cluster.0 * 2; @@ -360,19 +363,24 @@ impl FatVolume { FatSpecificInfo::Fat32(fat32_info) => { // All directories on FAT32 have a cluster chain but the root // dir starts in a specified cluster. - let mut first_dir_block_num = match dir.cluster { - ClusterId::ROOT_DIR => self.cluster_to_block(fat32_info.first_root_dir_cluster), - _ => self.cluster_to_block(dir.cluster), + let mut current_cluster = match dir.cluster { + ClusterId::ROOT_DIR => Some(fat32_info.first_root_dir_cluster), + _ => Some(dir.cluster), }; - let mut current_cluster = Some(dir.cluster); + let mut first_dir_block_num = self.cluster_to_block(dir.cluster); let mut blocks = [Block::new()]; let dir_size = BlockCount(u32::from(self.blocks_per_cluster)); + // Walk the cluster chain until we run out of clusters while let Some(cluster) = current_cluster { + // Loop through the blocks in the cluster for block in first_dir_block_num.range(dir_size) { + // Read a block of directory entries block_device .read(&mut blocks, block, "read_dir") .map_err(Error::DeviceError)?; + // Are any entries in the block we just loaded blank? If so + // we can use them. for entry in 0..Block::LEN / OnDiskDirEntry::LEN { let start = entry * OnDiskDirEntry::LEN; let end = (entry + 1) * OnDiskDirEntry::LEN; @@ -397,6 +405,8 @@ impl FatVolume { } } } + // Well none of the blocks in that cluster had any space in + // them, let's fetch another one. let mut block_cache = BlockCache::empty(); current_cluster = match self.next_cluster(block_device, cluster, &mut block_cache) { @@ -412,6 +422,8 @@ impl FatVolume { _ => None, }; } + // We ran out of clusters in the chain, and apparently we weren't + // able to make the chain longer, so the disk must be full. Err(Error::NotEnoughSpace) } }