Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 8f56999

Browse files
committed
fs: add method read_entry_boxed to Directory + test
1 parent 3fe3639 commit 8f56999

File tree

2 files changed

+126
-13
lines changed

2 files changed

+126
-13
lines changed

‎src/proto/media/file/dir.rs‎

Lines changed: 72 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,19 @@ use crate::data_types::Align;
33
use crate::Result;
44
use core::ffi::c_void;
55

6+
#[cfg(feature = "alloc")]
7+
use crate::{ResultExt, Status};
8+
#[cfg(feature = "alloc")]
9+
use alloc_api::alloc;
10+
#[cfg(feature = "alloc")]
11+
use alloc_api::boxed::Box;
12+
#[cfg(feature = "alloc")]
13+
use core::alloc::Layout;
14+
#[cfg(feature = "alloc")]
15+
use core::ptr::NonNull;
16+
#[cfg(feature = "alloc")]
17+
use core::slice;
18+
619
/// A `FileHandle` that is also a directory.
720
///
821
/// Use `File::into_type` or `Directory::new` to create a `Directory`. In
@@ -20,7 +33,7 @@ impl Directory {
2033
Self(RegularFile::new(handle))
2134
}
2235

23-
/// Read the next directory entry
36+
/// Read the next directory entry.
2437
///
2538
/// Try to read the next directory entry into `buffer`. If the buffer is too small, report the
2639
/// required buffer size as part of the error. If there are no more directory entries, return
@@ -56,6 +69,64 @@ impl Directory {
5669
})
5770
}
5871

72+
/// Wrapper around [`Self::read_entry`] that returns an owned copy of the data. It has the same
73+
/// implications and requirements. On failure, the payload of `Err` is `() ́.
74+
#[cfg(feature = "alloc")]
75+
pub fn read_entry_boxed(&mut self) -> Result<Option<Box<FileInfo>>> {
76+
let read_entry_res = self.read_entry(&mut []);
77+
78+
// If no more entries are available, return early.
79+
if let Ok(None) = read_entry_res {
80+
return Ok(None);
81+
}
82+
83+
let required_size = match read_entry_res
84+
.expect_err("zero sized read unexpectedly succeeded")
85+
.split()
86+
{
87+
// Early return if something has failed.
88+
(s, None) => return Err(s.into()),
89+
(_, Some(required_size)) => required_size,
90+
};
91+
92+
// We add trailing padding because the size of a rust structure must
93+
// always be a multiple of alignment.
94+
let layout = Layout::from_size_align(required_size, FileInfo::alignment())
95+
.unwrap()
96+
.pad_to_align();
97+
98+
// Allocate the buffer.
99+
let heap_buf: NonNull<u8> = unsafe {
100+
let ptr = alloc::alloc(layout);
101+
match NonNull::new(ptr) {
102+
None => return Err(Status::OUT_OF_RESOURCES.into()),
103+
Some(ptr) => ptr,
104+
}
105+
};
106+
107+
// Get the file info using the allocated buffer for storage.
108+
let info = {
109+
let buffer = unsafe { slice::from_raw_parts_mut(heap_buf.as_ptr(), layout.size()) };
110+
self.read_entry(buffer).discard_errdata()
111+
};
112+
113+
// If an error occurred, deallocate the memory before returning.
114+
let info = match info {
115+
Ok(info) => info,
116+
Err(err) => {
117+
unsafe { alloc::dealloc(heap_buf.as_ptr(), layout) };
118+
return Err(err);
119+
}
120+
};
121+
122+
// Wrap the file info in a box so that it will be deallocated on
123+
// drop. This is valid because the memory was allocated with the
124+
// global allocator.
125+
let info = info.map(|info| unsafe { Box::from_raw(info) });
126+
127+
Ok(info)
128+
}
129+
59130
/// Start over the process of enumerating directory entries
60131
pub fn reset_entry_readout(&mut self) -> Result {
61132
self.0.set_position(0)

‎uefi-test-runner/src/proto/media/known_disk.rs‎

Lines changed: 54 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use alloc::string::ToString;
2+
use core::cell::RefCell;
23
use core::ptr::NonNull;
34
use uefi::prelude::*;
45
use uefi::proto::media::block::BlockIO;
@@ -21,20 +22,61 @@ fn test_existing_dir(directory: &mut Directory) {
2122

2223
assert!(dir.is_directory().unwrap());
2324

24-
let mut dir = dir.into_directory().expect("not a directory");
25-
26-
// Collect and validate the directory entries.
27-
let mut entry_names = vec![];
28-
let mut buf = vec![0; 200];
29-
loop {
30-
let entry = dir.read_entry(&mut buf).expect("failed to read directory");
31-
if let Some(entry) = entry {
32-
entry_names.push(entry.file_name().to_string());
33-
} else {
34-
break;
25+
let dir = dir.into_directory().expect("Should be a directory");
26+
27+
let dir = RefCell::new(dir);
28+
29+
// Backing memory to read the file info data into.
30+
let mut stack_buf = [0; 200];
31+
32+
// The file names that the test read from the directory.
33+
let entry_names = RefCell::new(vec![]);
34+
35+
// Expected file names in the directory.
36+
const EXPECTED: &[&str] = &[".", "..", "test_input.txt"];
37+
38+
// Reads the whole directory with provided backing memory.
39+
let mut test_read_dir_stack_mem = || {
40+
let mut dir = dir.borrow_mut();
41+
let mut entry_names = entry_names.borrow_mut();
42+
loop {
43+
let entry = dir
44+
.read_entry(&mut stack_buf)
45+
.expect("failed to read directory");
46+
if let Some(entry) = entry {
47+
entry_names.push(entry.file_name().to_string());
48+
} else {
49+
break;
50+
}
3551
}
52+
assert_eq!(&*entry_names, EXPECTED);
53+
};
54+
55+
// Reads the whole directory but returns owned memory on the heap.
56+
let test_read_dir_heap_mem = || {
57+
let mut dir = dir.borrow_mut();
58+
let mut entry_names = entry_names.borrow_mut();
59+
loop {
60+
let entry = dir.read_entry_boxed().expect("failed to read directory");
61+
if let Some(entry) = entry {
62+
entry_names.push(entry.file_name().to_string());
63+
} else {
64+
break;
65+
}
66+
}
67+
assert_eq!(&*entry_names, EXPECTED);
68+
};
69+
70+
// Tests all read dir test functions three times.
71+
for _ in 0..3 {
72+
entry_names.borrow_mut().clear();
73+
dir.borrow_mut().reset_entry_readout().unwrap();
74+
test_read_dir_stack_mem();
75+
76+
entry_names.borrow_mut().clear();
77+
dir.borrow_mut().reset_entry_readout().unwrap();
78+
test_read_dir_heap_mem();
3679
}
37-
assert_eq!(entry_names, [".", "..", "test_input.txt"]);
3880
}
3981

4082
/// Test that deleting a file opened in read-only mode fails with a

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /