diff --git a/src/fat/volume.rs b/src/fat/volume.rs index 25f67de..4f085ac 100644 --- a/src/fat/volume.rs +++ b/src/fat/volume.rs @@ -1242,6 +1242,87 @@ impl FatVolume { block_cache.write_back().map_err(Error::DeviceError)?; Ok(()) } + + /// Create a new directory. + /// + /// 1) Creates the directory entry in the parent + /// 2) Allocates a new cluster to hold the new directory + /// 3) Writes out the `.` and `..` entries in the new directory + pub(crate) fn make_dir( + &mut self, + block_cache: &mut BlockCache, + time_source: &T, + parent: ClusterId, + sfn: ShortFileName, + att: Attributes, + ) -> Result<(), Error> + where + D: BlockDevice, + T: TimeSource, + { + let mut new_dir_entry_in_parent = + self.write_new_directory_entry(block_cache, time_source, parent, sfn, att)?; + if new_dir_entry_in_parent.cluster == ClusterId::EMPTY { + new_dir_entry_in_parent.cluster = self.alloc_cluster(block_cache, None, false)?; + // update the parent dir with the cluster of the new dir + self.write_entry_to_disk(block_cache, &new_dir_entry_in_parent)?; + } + let new_dir_start_block = self.cluster_to_block(new_dir_entry_in_parent.cluster); + debug!("Made new dir entry {:?}", new_dir_entry_in_parent); + let now = time_source.get_timestamp(); + let fat_type = self.get_fat_type(); + // A blank block + let block = block_cache.blank_mut(new_dir_start_block); + // make the "." entry + let dot_entry_in_child = DirEntry { + name: crate::ShortFileName::this_dir(), + mtime: now, + ctime: now, + attributes: att, + // point at ourselves + cluster: new_dir_entry_in_parent.cluster, + size: 0, + entry_block: new_dir_start_block, + entry_offset: 0, + }; + debug!("New dir has {:?}", dot_entry_in_child); + let mut offset = 0; + block[offset..offset + OnDiskDirEntry::LEN] + .copy_from_slice(&dot_entry_in_child.serialize(fat_type)[..]); + offset += OnDiskDirEntry::LEN; + // make the ".." entry + let dot_dot_entry_in_child = DirEntry { + name: crate::ShortFileName::parent_dir(), + mtime: now, + ctime: now, + attributes: att, + // point at our parent + cluster: if parent == ClusterId::ROOT_DIR { + // indicate parent is root using Cluster(0) + ClusterId::EMPTY + } else { + parent + }, + size: 0, + entry_block: new_dir_start_block, + entry_offset: OnDiskDirEntry::LEN_U32, + }; + debug!("New dir has {:?}", dot_dot_entry_in_child); + block[offset..offset + OnDiskDirEntry::LEN] + .copy_from_slice(&dot_dot_entry_in_child.serialize(fat_type)[..]); + + block_cache.write_back()?; + + for block_idx in new_dir_start_block + .range(BlockCount(u32::from(self.blocks_per_cluster))) + .skip(1) + { + let _block = block_cache.blank_mut(block_idx); + block_cache.write_back()?; + } + + Ok(()) + } } /// Load the boot parameter block from the start of the given partition and diff --git a/src/volume_mgr.rs b/src/volume_mgr.rs index 42770ae..5cc69c9 100644 --- a/src/volume_mgr.rs +++ b/src/volume_mgr.rs @@ -1070,79 +1070,14 @@ where // Need mutable access for this match &mut data.open_volumes[volume_idx].volume_type { VolumeType::Fat(fat) => { - // TODO: Move this into the FAT volume code debug!("Making dir entry"); - let mut new_dir_entry_in_parent = fat.write_new_directory_entry( + fat.make_dir( &mut data.block_cache, &self.time_source, parent_directory_info.cluster, sfn, att, )?; - if new_dir_entry_in_parent.cluster == ClusterId::EMPTY { - new_dir_entry_in_parent.cluster = - fat.alloc_cluster(&mut data.block_cache, None, false)?; - // update the parent dir with the cluster of the new dir - fat.write_entry_to_disk(&mut data.block_cache, &new_dir_entry_in_parent)?; - } - let new_dir_start_block = fat.cluster_to_block(new_dir_entry_in_parent.cluster); - debug!("Made new dir entry {:?}", new_dir_entry_in_parent); - let now = self.time_source.get_timestamp(); - let fat_type = fat.get_fat_type(); - // A blank block - let block = data.block_cache.blank_mut(new_dir_start_block); - // make the "." entry - let dot_entry_in_child = DirEntry { - name: crate::ShortFileName::this_dir(), - mtime: now, - ctime: now, - attributes: att, - // point at ourselves - cluster: new_dir_entry_in_parent.cluster, - size: 0, - entry_block: new_dir_start_block, - entry_offset: 0, - }; - debug!("New dir has {:?}", dot_entry_in_child); - let mut offset = 0; - block[offset..offset + fat::OnDiskDirEntry::LEN] - .copy_from_slice(&dot_entry_in_child.serialize(fat_type)[..]); - offset += fat::OnDiskDirEntry::LEN; - // make the ".." entry - let dot_dot_entry_in_child = DirEntry { - name: crate::ShortFileName::parent_dir(), - mtime: now, - ctime: now, - attributes: att, - // point at our parent - cluster: match fat_type { - fat::FatType::Fat16 => { - // On FAT16, indicate parent is root using Cluster(0) - if parent_directory_info.cluster == ClusterId::ROOT_DIR { - ClusterId::EMPTY - } else { - parent_directory_info.cluster - } - } - fat::FatType::Fat32 => parent_directory_info.cluster, - }, - size: 0, - entry_block: new_dir_start_block, - entry_offset: fat::OnDiskDirEntry::LEN_U32, - }; - debug!("New dir has {:?}", dot_dot_entry_in_child); - block[offset..offset + fat::OnDiskDirEntry::LEN] - .copy_from_slice(&dot_dot_entry_in_child.serialize(fat_type)[..]); - - data.block_cache.write_back()?; - - for block_idx in new_dir_start_block - .range(BlockCount(u32::from(fat.blocks_per_cluster))) - .skip(1) - { - let _block = data.block_cache.blank_mut(block_idx); - data.block_cache.write_back()?; - } } }; diff --git a/tests/directories.rs b/tests/directories.rs index e2e20d2..e10a901 100644 --- a/tests/directories.rs +++ b/tests/directories.rs @@ -98,6 +98,16 @@ fn fat16_root_directory_listing() { }, Some(String::from(".fseventsd")), ), + ( + ExpectedDirEntry { + name: String::from("P-FAT16"), + mtime: String::from("2024-10-30 18:43:12"), + ctime: String::from("2024-10-30 18:43:12"), + size: 0, + is_dir: false, + }, + None, + ), ]; let mut listing = Vec::new(); @@ -266,6 +276,16 @@ fn fat32_root_directory_listing() { }, Some(String::from(".fseventsd")), ), + ( + ExpectedDirEntry { + name: String::from("P-FAT32"), + mtime: String::from("2024-10-30 18:43:16"), + ctime: String::from("2024-10-30 18:43:16"), + size: 0, + is_dir: false, + }, + None, + ), ( ExpectedDirEntry { name: String::from("THISIS~9"), diff --git a/tests/disk.img.gz b/tests/disk.img.gz index 1ba2bdf..507ec94 100644 Binary files a/tests/disk.img.gz and b/tests/disk.img.gz differ