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 ceefb6c

Browse files
committed
add memory util make_boxed
1 parent 8f56999 commit ceefb6c

File tree

4 files changed

+137
-107
lines changed

4 files changed

+137
-107
lines changed

‎src/lib.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,3 +64,6 @@ pub mod alloc;
6464

6565
#[cfg(feature = "logger")]
6666
pub mod logger;
67+
68+
#[cfg(feature = "exts")]
69+
pub(crate) mod mem;

‎src/mem.rs

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
//! This is a utility module with helper methods for allocations/memory.
2+
3+
use crate::ResultExt;
4+
use crate::{Result, Status};
5+
use alloc_api::alloc;
6+
use alloc_api::boxed::Box;
7+
use core::alloc::Layout;
8+
use core::fmt::Debug;
9+
use core::ptr::NonNull;
10+
use core::slice;
11+
use uefi::data_types::Align;
12+
13+
/// Wraps a UEFI function that provides some data in a provided buffer. This function returns the
14+
/// data as owned copy on the heap in a Box.
15+
pub fn make_boxed<'a, Data: Align + ?Sized + Debug + 'a>(
16+
mut fetch_data_fn: impl FnMut(&'a mut [u8]) -> Result<&'a mut Data, Option<usize>>,
17+
) -> Result<Box<Data>> {
18+
let required_size = match fetch_data_fn(&mut [])
19+
.expect_err("succeeded unexpectedly")
20+
.split()
21+
{
22+
(s, None) => Err::<usize, crate::result::Error>(s.into()),
23+
(_, Some(required_size)) => Ok(required_size),
24+
}
25+
.unwrap();
26+
27+
// We add trailing padding because the size of a rust structure must
28+
// always be a multiple of alignment.
29+
let layout = Layout::from_size_align(required_size, Data::alignment())
30+
.unwrap()
31+
.pad_to_align();
32+
33+
// Allocate the buffer.
34+
let heap_buf: NonNull<u8> = unsafe {
35+
let ptr = alloc::alloc(layout);
36+
match NonNull::new(ptr) {
37+
None => return Err(Status::OUT_OF_RESOURCES.into()),
38+
Some(ptr) => ptr,
39+
}
40+
};
41+
42+
// Get the file info using the allocated buffer for storage.
43+
let data: Result<&mut Data> = {
44+
let buffer = unsafe { slice::from_raw_parts_mut(heap_buf.as_ptr(), layout.size()) };
45+
fetch_data_fn(buffer).discard_errdata()
46+
};
47+
48+
// If an error occurred, deallocate the memory before returning.
49+
let data: &mut Data = match data {
50+
Ok(data) => data,
51+
Err(err) => {
52+
unsafe { alloc::dealloc(heap_buf.as_ptr(), layout) };
53+
return Err(err);
54+
}
55+
};
56+
57+
let data = unsafe { Box::from_raw(data) };
58+
59+
Ok(data)
60+
}
61+
62+
#[cfg(test)]
63+
mod tests {
64+
use super::*;
65+
use crate::ResultExt;
66+
67+
#[derive(Debug)]
68+
#[repr(C)]
69+
struct SomeData([u8; 4]);
70+
71+
impl Align for SomeData {
72+
fn alignment() -> usize {
73+
4
74+
}
75+
}
76+
77+
/// Function that behaves like the other UEFI functions. It takes a
78+
/// mutable reference to a buffer memory that represents a [`SomeData`]
79+
/// instance.
80+
fn uefi_function_stub_read(buf: &mut [u8]) -> crate::Result<&mut SomeData, Option<usize>> {
81+
if buf.len() < 4 {
82+
return Status::BUFFER_TOO_SMALL.into_with(|| panic!(), |_| Some(4));
83+
};
84+
85+
buf[0] = 1;
86+
buf[1] = 2;
87+
buf[2] = 3;
88+
buf[3] = 4;
89+
90+
let data = unsafe { buf.as_ptr().cast::<SomeData>().cast_mut().as_mut().unwrap() };
91+
92+
Ok(data)
93+
}
94+
95+
#[test]
96+
fn test_basic() {
97+
assert_eq!(
98+
uefi_function_stub_read(&mut []).status(),
99+
Status::BUFFER_TOO_SMALL
100+
);
101+
assert_eq!(
102+
*uefi_function_stub_read(&mut []).unwrap_err().data(),
103+
Some(4)
104+
);
105+
106+
let mut buf: [u8; 4] = [0; 4];
107+
let data = uefi_function_stub_read(&mut buf).unwrap();
108+
109+
assert_eq!(&data.0, &[1, 2, 3, 4])
110+
}
111+
112+
#[test]
113+
fn test_utility() {
114+
let fetch_data_fn = |buf| uefi_function_stub_read(buf);
115+
let data: Box<SomeData> = make_boxed(fetch_data_fn).unwrap();
116+
117+
assert_eq!(&data.0, &[1, 2, 3, 4])
118+
}
119+
}

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

Lines changed: 11 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,8 @@ 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;
6+
#[cfg(feature = "exts")]
7+
use {crate::mem::make_boxed, alloc_api::boxed::Box};
188

199
/// A `FileHandle` that is also a directory.
2010
///
@@ -71,7 +61,7 @@ impl Directory {
7161

7262
/// Wrapper around [`Self::read_entry`] that returns an owned copy of the data. It has the same
7363
/// implications and requirements. On failure, the payload of `Err` is `() ́.
74-
#[cfg(feature = "alloc")]
64+
#[cfg(feature = "exts")]
7565
pub fn read_entry_boxed(&mut self) -> Result<Option<Box<FileInfo>>> {
7666
let read_entry_res = self.read_entry(&mut []);
7767

@@ -80,51 +70,15 @@ impl Directory {
8070
return Ok(None);
8171
}
8272

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,
73+
let fetch_data_fn = |buf| {
74+
self.read_entry(buf)
75+
// this is safe, as above, we checked that there are more entries
76+
.map(|maybe_info: Option<&mut FileInfo>| {
77+
maybe_info.expect("Should have more entries")
78+
})
9079
};
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)
80+
let file_info = make_boxed::<FileInfo>(fetch_data_fn)?;
81+
Ok(Some(file_info))
12882
}
12983

13084
/// Start over the process of enumerating directory entries

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

Lines changed: 4 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,7 @@ use core::fmt::Debug;
1717
use core::mem;
1818
use core::ptr;
1919
#[cfg(feature = "exts")]
20-
use {
21-
crate::ResultExt,
22-
alloc_api::{alloc, alloc::Layout, boxed::Box},
23-
core::slice,
24-
};
20+
use {alloc_api::boxed::Box, uefi::mem::make_boxed};
2521

2622
pub use self::info::{FileInfo, FileProtocolInfo, FileSystemInfo, FileSystemVolumeLabel, FromUefi};
2723
pub use self::{dir::Directory, regular::RegularFile};
@@ -168,51 +164,9 @@ pub trait File: Sized {
168164
#[cfg(feature = "exts")]
169165
/// Get the dynamically allocated info for a file
170166
fn get_boxed_info<Info: FileProtocolInfo + ?Sized + Debug>(&mut self) -> Result<Box<Info>> {
171-
// Initially try get_info with an empty array, this should always fail
172-
// as all Info types at least need room for a null-terminator.
173-
let size = match self
174-
.get_info::<Info>(&mut [])
175-
.expect_err("zero sized get_info unexpectedly succeeded")
176-
.split()
177-
{
178-
(s, None) => return Err(s.into()),
179-
(_, Some(size)) => size,
180-
};
181-
182-
// We add trailing padding because the size of a rust structure must
183-
// always be a multiple of alignment.
184-
let layout = Layout::from_size_align(size, Info::alignment())
185-
.unwrap()
186-
.pad_to_align();
187-
188-
// Allocate the buffer.
189-
let data: *mut u8 = unsafe {
190-
let data = alloc::alloc(layout);
191-
if data.is_null() {
192-
return Err(Status::OUT_OF_RESOURCES.into());
193-
}
194-
data
195-
};
196-
197-
// Get the file info using the allocated buffer for storage.
198-
let info = {
199-
let buffer = unsafe { slice::from_raw_parts_mut(data, layout.size()) };
200-
self.get_info::<Info>(buffer).discard_errdata()
201-
};
202-
203-
// If an error occurred, deallocate the memory before returning.
204-
let info = match info {
205-
Ok(info) => info,
206-
Err(err) => {
207-
unsafe { alloc::dealloc(data, layout) };
208-
return Err(err);
209-
}
210-
};
211-
212-
// Wrap the file info in a box so that it will be deallocated on
213-
// drop. This is valid because the memory was allocated with the
214-
// global allocator.
215-
unsafe { Ok(Box::from_raw(info)) }
167+
let fetch_data_fn = |buf| self.get_info::<Info>(buf);
168+
let file_info = make_boxed::<Info>(fetch_data_fn)?;
169+
Ok(file_info)
216170
}
217171

218172
/// Returns if the underlying file is a regular file.

0 commit comments

Comments
(0)

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