diff --git a/uefi-test-runner/src/fs/mod.rs b/uefi-test-runner/src/fs/mod.rs index cb47146e8..9dae895e4 100644 --- a/uefi-test-runner/src/fs/mod.rs +++ b/uefi-test-runner/src/fs/mod.rs @@ -60,7 +60,10 @@ pub fn test(sfs: ScopedProtocol) -> Result<(), fs::Error> { assert_eq!(boxinfo.file_size(), data_to_write.len() as u64); // test remove dir all - // TODO + fs.remove_dir_all(cstr16!("foo_dir\\1"))?; + // file should not be available after remove all + let err = fs.try_exists(cstr16!("foo_dir\\1")); + assert!(err.is_err()); Ok(()) } diff --git a/uefi/src/fs/dir_entry_iter.rs b/uefi/src/fs/dir_entry_iter.rs index 7118e96d9..26a512c1e 100644 --- a/uefi/src/fs/dir_entry_iter.rs +++ b/uefi/src/fs/dir_entry_iter.rs @@ -6,6 +6,9 @@ use alloc::boxed::Box; /// Iterates over the entries of an UEFI directory. It returns boxed values of /// type [`UefiFileInfo`]. +/// +/// Note that on UEFI/FAT-style file systems, the root dir usually doesn't +/// return the entries `.` and `..`, whereas sub directories do. #[derive(Debug)] pub struct UefiDirectoryIter(UefiDirectoryHandle); diff --git a/uefi/src/fs/file_system/fs.rs b/uefi/src/fs/file_system/fs.rs index c729fd725..99161b90d 100644 --- a/uefi/src/fs/file_system/fs.rs +++ b/uefi/src/fs/file_system/fs.rs @@ -11,6 +11,8 @@ use core::fmt; use core::fmt::{Debug, Formatter}; use core::ops::Deref; use log::debug; +use uefi::CStr16; +use uefi_macros::cstr16; /// Return type for public [`FileSystem`] operations. pub type FileSystemResult = Result; @@ -181,11 +183,35 @@ impl<'a> FileSystem<'a> { } } - /*/// Removes a directory at this path, after removing all its contents. Use + /// Removes a directory at this path, after removing all its contents. Use /// carefully! pub fn remove_dir_all(&mut self, path: impl AsRef) -> FileSystemResult<()> { + const SKIP_DIRS: [&CStr16; 2] = [cstr16!("."), cstr16!("..")]; let path = path.as_ref(); - }*/ + for file_info in self + .read_dir(path)? + .filter_map(|file_info_result| file_info_result.ok()) + { + if SKIP_DIRS.contains(&file_info.file_name()) { + continue; + } + + let mut abs_entry_path = PathBuf::new(); + abs_entry_path.push(path); + abs_entry_path.push(file_info.file_name()); + if file_info.is_directory() { + // delete all inner files + // This recursion is fine as there are no links in UEFI/FAT file + // systems. No cycles possible. + self.remove_dir_all(&abs_entry_path)?; + } else { + self.remove_file(abs_entry_path)?; + } + } + // Now that the dir is empty, we delete it as final step. + self.remove_dir(path)?; + Ok(()) + } /// Removes a file from the filesystem. pub fn remove_file(&mut self, path: impl AsRef) -> FileSystemResult<()> { @@ -282,17 +308,17 @@ impl<'a> FileSystem<'a> { /// absolute path. /// /// May create a file if [`UefiFileMode::CreateReadWrite`] is set. May - /// create a directory if [`UefiFileMode::CreateReadWrite`] and `is_dir` - /// is set. + /// create a directory if [`UefiFileMode::CreateReadWrite`] and `create_dir` + /// is set. The parameter `create_dir` is ignored otherwise. fn open( &mut self, path: &Path, mode: UefiFileMode, - is_dir: bool, + create_dir: bool, ) -> FileSystemResult { validate_path(path)?; - let attr = if mode == UefiFileMode::CreateReadWrite && is_dir { + let attr = if mode == UefiFileMode::CreateReadWrite && create_dir { UefiFileAttribute::DIRECTORY } else { UefiFileAttribute::empty()