Skip to content

Commit ae73f2f

Browse files
committed
Support directory deletion
1 parent 2851be4 commit ae73f2f

File tree

2 files changed

+51
-10
lines changed

2 files changed

+51
-10
lines changed

src/lib.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -189,8 +189,10 @@ where
189189
OpenedDirAsFile,
190190
/// You can't open a file as a directory
191191
OpenedFileAsDir,
192-
/// You can't delete a directory as a file
192+
/// You can't delete a directory as a file [no longer being emitted]
193193
DeleteDirAsFile,
194+
/// You can't delete a non-empty directory
195+
DeleteNonEmptyDir,
194196
/// You can't close a volume with open files or directories
195197
VolumeStillInUse,
196198
/// You can't open a volume twice
@@ -253,6 +255,7 @@ impl<E: Debug> embedded_io::Error for Error<E> {
253255
Error::OpenedDirAsFile
254256
| Error::OpenedFileAsDir
255257
| Error::DeleteDirAsFile
258+
| Error::DeleteNonEmptyDir
256259
| Error::BadCluster
257260
| Error::ConversionError
258261
| Error::UnterminatedFatChain => ErrorKind::InvalidData,

src/volume_mgr.rs

Lines changed: 47 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -665,26 +665,64 @@ where
665665
let data = data.deref_mut();
666666

667667
let dir_idx = data.get_dir_by_id(directory)?;
668-
let dir_info = &data.open_dirs[dir_idx];
669-
let volume_idx = data.get_volume_by_id(dir_info.raw_volume)?;
668+
let parent_dir_info = data.open_dirs[dir_idx].clone();
669+
let volume_idx = data.get_volume_by_id(parent_dir_info.raw_volume)?;
670670
let sfn = name.to_short_filename().map_err(Error::FilenameError)?;
671671

672672
let dir_entry = match &data.open_volumes[volume_idx].volume_type {
673-
VolumeType::Fat(fat) => fat.find_directory_entry(&mut data.block_cache, dir_info, &sfn),
673+
VolumeType::Fat(fat) => {
674+
fat.find_directory_entry(&mut data.block_cache, &parent_dir_info, &sfn)
675+
}
674676
}?;
675677

676678
if dir_entry.attributes.is_directory() {
677-
return Err(Error::DeleteDirAsFile);
678-
}
679-
680-
if data.file_is_open(dir_info.raw_volume, &dir_entry) {
679+
// Find the directory to be deleted, so that we can check its contents.
680+
let dir_info = if let Some(dir_info) = data
681+
.open_dirs
682+
.iter()
683+
.find(|dir_info| {
684+
// Subdirectory is already open.
685+
dir_info.cluster == dir_entry.cluster
686+
})
687+
.cloned()
688+
{
689+
dir_info
690+
} else {
691+
// The subdirectory isn't yet open. Open it in order to be able to list it.
692+
let raw_directory = RawDirectory(data.id_generator.generate());
693+
DirectoryInfo {
694+
raw_directory,
695+
raw_volume: data.open_volumes[volume_idx].raw_volume,
696+
cluster: dir_entry.cluster,
697+
}
698+
};
699+
// Can only delete directories that are already empty.
700+
let mut count = 0;
701+
// Equivalent to `self.iterate_dir(raw_dir, |_| count += 1)?;`, without locking again.
702+
match &data.open_volumes[volume_idx].volume_type {
703+
VolumeType::Fat(fat) => {
704+
fat.iterate_dir(&mut data.block_cache, &dir_info, |de| {
705+
// Hide all the LFN directory entries
706+
if !de.attributes.is_lfn()
707+
&& de.name != ShortFileName::this_dir()
708+
&& de.name != ShortFileName::parent_dir()
709+
{
710+
count += 1;
711+
}
712+
})?;
713+
}
714+
}
715+
if count != 0 {
716+
return Err(Error::DeleteNonEmptyDir);
717+
}
718+
} else if data.file_is_open(parent_dir_info.raw_volume, &dir_entry) {
681719
return Err(Error::FileAlreadyOpen);
682720
}
683721

684-
let volume_idx = data.get_volume_by_id(dir_info.raw_volume)?;
722+
let volume_idx = data.get_volume_by_id(parent_dir_info.raw_volume)?;
685723
match &data.open_volumes[volume_idx].volume_type {
686724
VolumeType::Fat(fat) => {
687-
fat.delete_directory_entry(&mut data.block_cache, dir_info, &sfn)?
725+
fat.delete_directory_entry(&mut data.block_cache, &parent_dir_info, &sfn)?
688726
}
689727
}
690728

0 commit comments

Comments
 (0)