Skip to content

Commit dd94198

Browse files
authored
Merge pull request #799 from phip1611/fs-delete-dir-all
fs: implement remove_dir_all
2 parents 12e2da2 + bc8d8db commit dd94198

File tree

8 files changed

+62
-17
lines changed

8 files changed

+62
-17
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@
2525
- Added `CStr16::as_bytes`
2626
- Added `AsRef<[u8]>` and `Borrow<[u8]>` for `Cstr8` and `CStr16`.
2727
- Added `LoadedImageDevicePath` protocol.
28+
- Added `FileAttribute::is_directory(&self)` and
29+
`FileAttribute::is_regular_file(&self)`
2830

2931
### Changed
3032

uefi-test-runner/src/fs/mod.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,10 @@ pub fn test(sfs: ScopedProtocol<SimpleFileSystem>) -> Result<(), fs::Error> {
6060
assert_eq!(boxinfo.file_size(), data_to_write.len() as u64);
6161

6262
// test remove dir all
63-
// TODO
63+
fs.remove_dir_all(cstr16!("foo_dir\\1"))?;
64+
// file should not be available after remove all
65+
let err = fs.try_exists(cstr16!("foo_dir\\1"));
66+
assert!(err.is_err());
6467

6568
Ok(())
6669
}

uefi/src/fs/dir_entry_iter.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,24 @@
11
//! Module for directory iteration. See [`UefiDirectoryIter`].
22
33
use super::*;
4-
use crate::Result;
4+
use crate::{CStr16, Result};
55
use alloc::boxed::Box;
6+
use uefi_macros::cstr16;
7+
8+
/// Common skip dirs in UEFI/FAT-style file systems.
9+
pub const COMMON_SKIP_DIRS: &[&CStr16] = &[cstr16!("."), cstr16!("..")];
610

711
/// Iterates over the entries of an UEFI directory. It returns boxed values of
812
/// type [`UefiFileInfo`].
13+
///
14+
/// Note that on UEFI/FAT-style file systems, the root dir usually doesn't
15+
/// return the entries `.` and `..`, whereas sub directories do.
916
#[derive(Debug)]
1017
pub struct UefiDirectoryIter(UefiDirectoryHandle);
1118

1219
impl UefiDirectoryIter {
1320
/// Constructor.
21+
#[must_use]
1422
pub fn new(handle: UefiDirectoryHandle) -> Self {
1523
Self(handle)
1624
}

uefi/src/fs/file_system/error.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,7 @@ pub struct IoError {
2828
pub uefi_error: crate::Error,
2929
}
3030

31-
/// Enum that further specifies the context in that a [`Error`]
32-
/// occurred.
31+
/// Enum that further specifies the context in that an [`Error`] occurred.
3332
#[derive(Debug, Clone, Display, PartialEq, Eq)]
3433
pub enum FileSystemIOErrorContext {
3534
/// Can't delete the directory.

uefi/src/fs/file_system/fs.rs

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -181,11 +181,34 @@ impl<'a> FileSystem<'a> {
181181
}
182182
}
183183

184-
/*/// Removes a directory at this path, after removing all its contents. Use
184+
/// Removes a directory at this path, after removing all its contents. Use
185185
/// carefully!
186186
pub fn remove_dir_all(&mut self, path: impl AsRef<Path>) -> FileSystemResult<()> {
187187
let path = path.as_ref();
188-
}*/
188+
for file_info in self
189+
.read_dir(path)?
190+
.filter_map(|file_info_result| file_info_result.ok())
191+
{
192+
if COMMON_SKIP_DIRS.contains(&file_info.file_name()) {
193+
continue;
194+
}
195+
196+
let mut abs_entry_path = PathBuf::new();
197+
abs_entry_path.push(path);
198+
abs_entry_path.push(file_info.file_name());
199+
if file_info.is_directory() {
200+
// delete all inner files
201+
// This recursion is fine as there are no links in UEFI/FAT file
202+
// systems. No cycles possible.
203+
self.remove_dir_all(&abs_entry_path)?;
204+
} else {
205+
self.remove_file(abs_entry_path)?;
206+
}
207+
}
208+
// Now that the dir is empty, we delete it as final step.
209+
self.remove_dir(path)?;
210+
Ok(())
211+
}
189212

190213
/// Removes a file from the filesystem.
191214
pub fn remove_file(&mut self, path: impl AsRef<Path>) -> FileSystemResult<()> {
@@ -282,17 +305,17 @@ impl<'a> FileSystem<'a> {
282305
/// absolute path.
283306
///
284307
/// May create a file if [`UefiFileMode::CreateReadWrite`] is set. May
285-
/// create a directory if [`UefiFileMode::CreateReadWrite`] and `is_dir`
286-
/// is set.
308+
/// create a directory if [`UefiFileMode::CreateReadWrite`] and `create_dir`
309+
/// is set. The parameter `create_dir` is ignored otherwise.
287310
fn open(
288311
&mut self,
289312
path: &Path,
290313
mode: UefiFileMode,
291-
is_dir: bool,
314+
create_dir: bool,
292315
) -> FileSystemResult<UefiFileHandle> {
293316
validate_path(path)?;
294317

295-
let attr = if mode == UefiFileMode::CreateReadWrite && is_dir {
318+
let attr = if mode == UefiFileMode::CreateReadWrite && create_dir {
296319
UefiFileAttribute::DIRECTORY
297320
} else {
298321
UefiFileAttribute::empty()

uefi/src/fs/mod.rs

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,9 @@
2121
//! [`Path`] and [`PathBuf`].
2222
//!
2323
//! # API Hints
24-
//! There are no `File` and `Path` abstractions similar to those from `std` that
25-
//! are publicly exported. Instead, paths to files are provided as `&str`, and
26-
//! will be validated and transformed internally to the correct type.
27-
//! Furthermore, there are no `File` objects that are exposed to users. Instead,
28-
//! it is intended to work with the file system as in `std::fs`.
24+
//! There is no `File` abstraction as in the Rust `std` library. Instead, it is
25+
//! intended to work with the file system via dedicated functions, similar to
26+
//! the public functions of the `std::fs` module.
2927
//!
3028
//! There is no automatic synchronization of the file system for concurrent
3129
//! accesses. This is in the responsibility of the user.
@@ -35,8 +33,8 @@ mod file_system;
3533
mod path;
3634
mod uefi_types;
3735

36+
pub use dir_entry_iter::*;
3837
pub use file_system::*;
3938
pub use path::*;
4039

41-
use dir_entry_iter::*;
4240
use uefi_types::*;

uefi/src/fs/path/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ pub const SEPARATOR_STR: &CStr16 = uefi_macros::cstr16!("\\");
3333

3434
/// Deny list of characters for path components. UEFI supports FAT-like file
3535
/// systems. According to <https://en.wikipedia.org/wiki/Comparison_of_file_systems>,
36-
/// paths should not contain the following symbols.
36+
/// paths should not contain these symbols.
3737
pub const CHARACTER_DENY_LIST: [Char16; 10] = unsafe {
3838
[
3939
NUL_16,

uefi/src/proto/media/file/info.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,18 @@ impl FileInfo {
229229
pub fn file_name(&self) -> &CStr16 {
230230
unsafe { CStr16::from_ptr(self.file_name.as_ptr()) }
231231
}
232+
233+
/// Returns if the file is a directory.
234+
#[must_use]
235+
pub fn is_directory(&self) -> bool {
236+
self.attribute.contains(FileAttribute::DIRECTORY)
237+
}
238+
239+
/// Returns if the file is a regular file.
240+
#[must_use]
241+
pub fn is_regular_file(&self) -> bool {
242+
!self.is_directory()
243+
}
232244
}
233245

234246
impl Align for FileInfo {

0 commit comments

Comments
 (0)