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 6b269e9

Browse files
committed
fs: add method read_entry_boxed to Directory + test
1 parent f1ebb9b commit 6b269e9

File tree

2 files changed

+123
-13
lines changed

2 files changed

+123
-13
lines changed

‎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

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

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

6+
#[cfg(feature = "alloc")]
7+
use {
8+
crate::{ResultExt, Status},
9+
::alloc::boxed::Box,
10+
alloc::alloc,
11+
core::alloc::Layout,
12+
core::ptr::NonNull,
13+
core::slice,
14+
};
15+
616
/// A `FileHandle` that is also a directory.
717
///
818
/// Use `File::into_type` or `Directory::new` to create a `Directory`. In
@@ -20,7 +30,7 @@ impl Directory {
2030
Self(RegularFile::new(handle))
2131
}
2232

23-
/// Read the next directory entry
33+
/// Read the next directory entry.
2434
///
2535
/// Try to read the next directory entry into `buffer`. If the buffer is too small, report the
2636
/// required buffer size as part of the error. If there are no more directory entries, return
@@ -56,6 +66,64 @@ impl Directory {
5666
})
5767
}
5868

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

0 commit comments

Comments
(0)

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