Skip to content

Commit b208763

Browse files
committed
std: sys: fs: uefi: Implement readdir
- Tested on OVMF. Signed-off-by: Ayush Singh <ayush@beagleboard.org>
1 parent 9b82a4f commit b208763

File tree

1 file changed

+77
-11
lines changed

1 file changed

+77
-11
lines changed

library/std/src/sys/fs/uefi.rs

Lines changed: 77 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,16 @@ pub struct FileAttr {
2323
created: SystemTime,
2424
}
2525

26-
pub struct ReadDir(!);
26+
pub struct ReadDir {
27+
file: uefi_fs::File,
28+
path: PathBuf,
29+
}
2730

28-
pub struct DirEntry(!);
31+
pub struct DirEntry {
32+
attr: FileAttr,
33+
file_name: OsString,
34+
path: PathBuf,
35+
}
2936

3037
#[derive(Clone, Debug)]
3138
pub struct OpenOptions {
@@ -139,34 +146,46 @@ impl FileType {
139146
}
140147

141148
impl fmt::Debug for ReadDir {
142-
fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
143-
self.0
149+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
150+
let mut b = f.debug_struct("ReadDir");
151+
b.field("path", &self.path);
152+
b.finish()
144153
}
145154
}
146155

147156
impl Iterator for ReadDir {
148157
type Item = io::Result<DirEntry>;
149158

150159
fn next(&mut self) -> Option<io::Result<DirEntry>> {
151-
self.0
160+
match self.file.read_dir_entry() {
161+
Ok(None) => None,
162+
Ok(Some(x)) => Some(Ok(DirEntry::from_uefi(x, &self.path))),
163+
Err(e) => Some(Err(e)),
164+
}
152165
}
153166
}
154167

155168
impl DirEntry {
156169
pub fn path(&self) -> PathBuf {
157-
self.0
170+
self.path.clone()
158171
}
159172

160173
pub fn file_name(&self) -> OsString {
161-
self.0
174+
self.file_name.clone()
162175
}
163176

164177
pub fn metadata(&self) -> io::Result<FileAttr> {
165-
self.0
178+
Ok(self.attr.clone())
166179
}
167180

168181
pub fn file_type(&self) -> io::Result<FileType> {
169-
self.0
182+
Ok(self.attr.file_type())
183+
}
184+
185+
fn from_uefi(info: helpers::UefiBox<file::Info>, parent: &Path) -> Self {
186+
let file_name = uefi_fs::file_name_from_uefi(&info);
187+
let path = parent.join(&file_name);
188+
Self { file_name, path, attr: FileAttr::from_uefi(info) }
170189
}
171190
}
172191

@@ -340,8 +359,17 @@ impl fmt::Debug for File {
340359
}
341360
}
342361

343-
pub fn readdir(_p: &Path) -> io::Result<ReadDir> {
344-
unsupported()
362+
pub fn readdir(p: &Path) -> io::Result<ReadDir> {
363+
let path = crate::path::absolute(p)?;
364+
let f = uefi_fs::File::from_path(&path, file::MODE_READ, 0)?;
365+
let file_info = f.file_info()?;
366+
let file_attr = FileAttr::from_uefi(file_info);
367+
368+
if file_attr.file_type().is_dir() {
369+
Ok(ReadDir { path, file: f })
370+
} else {
371+
Err(io::const_error!(io::ErrorKind::NotADirectory, "expected a directory but got a file"))
372+
}
345373
}
346374

347375
pub fn unlink(p: &Path) -> io::Result<()> {
@@ -431,7 +459,9 @@ mod uefi_fs {
431459
use r_efi::protocols::{device_path, file, simple_file_system};
432460

433461
use crate::boxed::Box;
462+
use crate::ffi::OsString;
434463
use crate::io;
464+
use crate::os::uefi::ffi::OsStringExt;
435465
use crate::path::Path;
436466
use crate::ptr::NonNull;
437467
use crate::sys::helpers::{self, UefiBox};
@@ -523,6 +553,32 @@ mod uefi_fs {
523553
Ok(File(p))
524554
}
525555

556+
pub(crate) fn read_dir_entry(&self) -> io::Result<Option<UefiBox<file::Info>>> {
557+
let file_ptr = self.0.as_ptr();
558+
let mut buf_size = 0;
559+
560+
let r = unsafe { ((*file_ptr).read)(file_ptr, &mut buf_size, crate::ptr::null_mut()) };
561+
562+
if buf_size == 0 {
563+
return Ok(None);
564+
}
565+
566+
assert!(r.is_error());
567+
if r != r_efi::efi::Status::BUFFER_TOO_SMALL {
568+
return Err(io::Error::from_raw_os_error(r.as_usize()));
569+
}
570+
571+
let mut info: UefiBox<file::Info> = UefiBox::new(buf_size)?;
572+
let r =
573+
unsafe { ((*file_ptr).read)(file_ptr, &mut buf_size, info.as_mut_ptr().cast()) };
574+
575+
if r.is_error() {
576+
Err(io::Error::from_raw_os_error(r.as_usize()))
577+
} else {
578+
Ok(Some(info))
579+
}
580+
}
581+
526582
pub(crate) fn file_info(&self) -> io::Result<UefiBox<file::Info>> {
527583
let file_ptr = self.0.as_ptr();
528584
let mut info_id = file::INFO_ID;
@@ -642,4 +698,14 @@ mod uefi_fs {
642698
let now = time::system_time_internal::now().unwrap();
643699
time.to_uefi_loose(now.timezone, now.daylight)
644700
}
701+
702+
pub(crate) fn file_name_from_uefi(info: &UefiBox<file::Info>) -> OsString {
703+
let file_name = {
704+
let size = unsafe { (*info.as_ptr()).size };
705+
let strlen = (size as usize - crate::mem::size_of::<file::Info<0>>() - 1) / 2;
706+
unsafe { crate::slice::from_raw_parts((*info.as_ptr()).file_name.as_ptr(), strlen) }
707+
};
708+
709+
OsString::from_wide(file_name)
710+
}
645711
}

0 commit comments

Comments
 (0)