diff --git a/CHANGELOG.md b/CHANGELOG.md index b2dfbd5bf..ffd058c89 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,8 @@ - Added `CStr16::as_bytes` - Added `AsRef<[u8]>` and `Borrow<[u8]>` for `Cstr8` and `CStr16`. - Added `LoadedImageDevicePath` protocol. +- Added `FileAttribute::is_directory(&self)` and + `FileAttribute::is_regular_file(&self)` ### Changed 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..09ba03a52 100644 --- a/uefi/src/fs/dir_entry_iter.rs +++ b/uefi/src/fs/dir_entry_iter.rs @@ -1,16 +1,24 @@ //! Module for directory iteration. See [`UefiDirectoryIter`]. use super::*; -use crate::Result; +use crate::{CStr16, Result}; use alloc::boxed::Box; +use uefi_macros::cstr16; + +/// Common skip dirs in UEFI/FAT-style file systems. +pub const COMMON_SKIP_DIRS: &[&CStr16] = &[cstr16!("."), cstr16!("..")]; /// 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); impl UefiDirectoryIter { /// Constructor. + #[must_use] pub fn new(handle: UefiDirectoryHandle) -> Self { Self(handle) } diff --git a/uefi/src/fs/file_system/error.rs b/uefi/src/fs/file_system/error.rs index f25086539..3a6409632 100644 --- a/uefi/src/fs/file_system/error.rs +++ b/uefi/src/fs/file_system/error.rs @@ -28,8 +28,7 @@ pub struct IoError { pub uefi_error: crate::Error, } -/// Enum that further specifies the context in that a [`Error`] -/// occurred. +/// Enum that further specifies the context in that an [`Error`] occurred. #[derive(Debug, Clone, Display, PartialEq, Eq)] pub enum FileSystemIOErrorContext { /// Can't delete the directory. diff --git a/uefi/src/fs/file_system/fs.rs b/uefi/src/fs/file_system/fs.rs index c729fd725..79b66a0ca 100644 --- a/uefi/src/fs/file_system/fs.rs +++ b/uefi/src/fs/file_system/fs.rs @@ -181,11 +181,34 @@ 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<()> { let path = path.as_ref(); - }*/ + for file_info in self + .read_dir(path)? + .filter_map(|file_info_result| file_info_result.ok()) + { + if COMMON_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 +305,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() diff --git a/uefi/src/fs/mod.rs b/uefi/src/fs/mod.rs index a896e0d5e..aa2b2968d 100644 --- a/uefi/src/fs/mod.rs +++ b/uefi/src/fs/mod.rs @@ -21,11 +21,9 @@ //! [`Path`] and [`PathBuf`]. //! //! # API Hints -//! There are no `File` and `Path` abstractions similar to those from `std` that -//! are publicly exported. Instead, paths to files are provided as `&str`, and -//! will be validated and transformed internally to the correct type. -//! Furthermore, there are no `File` objects that are exposed to users. Instead, -//! it is intended to work with the file system as in `std::fs`. +//! There is no `File` abstraction as in the Rust `std` library. Instead, it is +//! intended to work with the file system via dedicated functions, similar to +//! the public functions of the `std::fs` module. //! //! There is no automatic synchronization of the file system for concurrent //! accesses. This is in the responsibility of the user. @@ -35,8 +33,8 @@ mod file_system; mod path; mod uefi_types; +pub use dir_entry_iter::*; pub use file_system::*; pub use path::*; -use dir_entry_iter::*; use uefi_types::*; diff --git a/uefi/src/fs/path/mod.rs b/uefi/src/fs/path/mod.rs index 35293e0ae..ce943d35a 100644 --- a/uefi/src/fs/path/mod.rs +++ b/uefi/src/fs/path/mod.rs @@ -33,7 +33,7 @@ pub const SEPARATOR_STR: &CStr16 = uefi_macros::cstr16!("\\"); /// Deny list of characters for path components. UEFI supports FAT-like file /// systems. According to , -/// paths should not contain the following symbols. +/// paths should not contain these symbols. pub const CHARACTER_DENY_LIST: [Char16; 10] = unsafe { [ NUL_16, diff --git a/uefi/src/proto/media/file/info.rs b/uefi/src/proto/media/file/info.rs index cd923218b..4bb7b8d7f 100644 --- a/uefi/src/proto/media/file/info.rs +++ b/uefi/src/proto/media/file/info.rs @@ -229,6 +229,18 @@ impl FileInfo { pub fn file_name(&self) -> &CStr16 { unsafe { CStr16::from_ptr(self.file_name.as_ptr()) } } + + /// Returns if the file is a directory. + #[must_use] + pub fn is_directory(&self) -> bool { + self.attribute.contains(FileAttribute::DIRECTORY) + } + + /// Returns if the file is a regular file. + #[must_use] + pub fn is_regular_file(&self) -> bool { + !self.is_directory() + } } impl Align for FileInfo {