Skip to content

"is_regular_file" for file trait + integration test #475

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Sep 6, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@
### Fixed

- Corrected the name of `BlockIOMedia::is_media_preset` to `is_media_present`.
- The `File` trait now knows the methods `is_regular_file` and `is_directory`.
Developers profit from this on the struct `FileHandle`, for example.

### Changed

Expand Down
8 changes: 8 additions & 0 deletions src/proto/media/file/dir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,4 +67,12 @@ impl File for Directory {
fn handle(&mut self) -> &mut FileHandle {
self.0.handle()
}

fn is_regular_file(&self) -> Result<bool> {
Ok(false)
}

fn is_directory(&self) -> Result<bool> {
Ok(true)
}
}
47 changes: 38 additions & 9 deletions src/proto/media/file/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,18 @@ pub trait File: Sized {
// global allocator.
unsafe { Ok(Box::from_raw(info)) }
}

/// Returns if the underlying file is a regular file.
/// The result is an error if the underlying file was already closed or deleted.
///
/// UEFI file system protocol only knows "regular files" and "directories".
fn is_regular_file(&self) -> Result<bool>;

/// Returns if the underlying file is a directory.
/// The result is an error if the underlying file was already closed or deleted.
///
/// UEFI file system protocol only knows "regular files" and "directories".
fn is_directory(&self) -> Result<bool>;
}

// Internal File helper methods to access the funciton pointer table.
Expand Down Expand Up @@ -241,17 +253,17 @@ impl FileHandle {
}

/// Converts `File` into a more specific subtype based on if it is a
/// directory or not. It does this via a call to `get_position`.
pub fn into_type(mut self) -> Result<FileType> {
/// directory or not. Wrapper around [Self::is_regular_file].
pub fn into_type(self) -> Result<FileType> {
use FileType::*;

// get_position fails with EFI_UNSUPPORTED on directories
let mut pos = 0;
match (self.imp().get_position)(self.imp(), &mut pos) {
Status::SUCCESS => unsafe { Ok(Regular(RegularFile::new(self))) },
Status::UNSUPPORTED => unsafe { Ok(Dir(Directory::new(self))) },
s => Err(s.into()),
}
self.is_regular_file().map(|is_file| {
if is_file {
unsafe { Regular(RegularFile::new(self)) }
} else {
unsafe { Dir(Directory::new(self)) }
}
})
}

/// If the handle represents a directory, convert it into a
Expand Down Expand Up @@ -280,6 +292,23 @@ impl File for FileHandle {
fn handle(&mut self) -> &mut FileHandle {
self
}

fn is_regular_file(&self) -> Result<bool> {
let this = unsafe { self.0.as_mut().unwrap() };

// - get_position fails with EFI_UNSUPPORTED on directories
// - result is an error if the underlying file was already closed or deleted.
let mut pos = 0;
match (this.get_position)(this, &mut pos) {
Status::SUCCESS => Ok(true),
Status::UNSUPPORTED => Ok(false),
s => Err(s.into()),
}
}

fn is_directory(&self) -> Result<bool> {
self.is_regular_file().map(|b| !b)
}
}

impl Drop for FileHandle {
Expand Down
8 changes: 8 additions & 0 deletions src/proto/media/file/regular.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,4 +104,12 @@ impl File for RegularFile {
fn handle(&mut self) -> &mut FileHandle {
&mut self.0
}

fn is_regular_file(&self) -> Result<bool> {
Ok(true)
}

fn is_directory(&self) -> Result<bool> {
Ok(false)
}
}
2 changes: 1 addition & 1 deletion src/result/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use core::fmt::Debug;

/// Errors emitted from UEFI entry point must propagate erronerous UEFI statuses,
/// and may optionally propagate additional entry point-specific data.
#[derive(Debug)]
#[derive(Debug, PartialEq, Eq)]
pub struct Error<Data: Debug = ()> {
status: Status,
data: Data,
Expand Down
45 changes: 30 additions & 15 deletions uefi-test-runner/src/proto/media/known_disk.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,13 @@ fn test_existing_dir(directory: &mut Directory) {
info!("Testing existing directory");

let input_dir_path = cstr16!("test_dir");
let mut dir = directory
let dir = directory
.open(input_dir_path, FileMode::Read, FileAttribute::empty())
.expect("failed to open directory")
.into_directory()
.expect("not a directory");
.expect("failed to open directory");

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

let mut dir = dir.into_directory().expect("not a directory");

// Collect and validate the directory entries.
let mut entry_names = vec![];
Expand Down Expand Up @@ -129,15 +131,17 @@ fn test_create_file(directory: &mut Directory) {
info!("Testing file creation");

// Create a new file.
let mut file = directory
let file = directory
.open(
cstr16!("new_test_file.txt"),
FileMode::CreateReadWrite,
FileAttribute::empty(),
)
.expect("failed to create file")
.into_regular_file()
.expect("not a regular file");
.expect("failed to create file");

assert!(file.is_regular_file().unwrap());

let mut file = file.into_regular_file().expect("not a regular file");
file.write(b"test output data").unwrap();
}

Expand Down Expand Up @@ -261,10 +265,21 @@ pub fn test_known_disk(bt: &BootServices) {
let mut sfs = bt
.open_protocol_exclusive::<SimpleFileSystem>(handle)
.expect("Failed to get simple file system");
let mut directory = sfs.open_volume().unwrap();
let mut root_directory = sfs.open_volume().unwrap();

// test is_directory() and is_regular_file() from the File trait which is the
// base for into_type() used later in the test.
{
// because File is "Sized", we cannot cast it to &dyn
fn test_is_directory(file: &impl File) {
assert_eq!(Ok(true), file.is_directory());
assert_eq!(Ok(false), file.is_regular_file());
}
test_is_directory(&root_directory);
}

let mut fs_info_buf = vec![0; 128];
let fs_info = directory
let fs_info = root_directory
.get_info::<FileSystemInfo>(&mut fs_info_buf)
.unwrap();

Expand All @@ -281,13 +296,13 @@ pub fn test_known_disk(bt: &BootServices) {
assert_eq!(fs_info.block_size(), 512);

// Check that `get_boxed_info` returns the same info.
let boxed_fs_info = directory.get_boxed_info::<FileSystemInfo>().unwrap();
let boxed_fs_info = root_directory.get_boxed_info::<FileSystemInfo>().unwrap();
assert_eq!(*fs_info, *boxed_fs_info);

test_existing_dir(&mut directory);
test_delete_warning(&mut directory);
test_existing_file(&mut directory);
test_create_file(&mut directory);
test_existing_dir(&mut root_directory);
test_delete_warning(&mut root_directory);
test_existing_file(&mut root_directory);
test_create_file(&mut root_directory);
}

test_raw_disk_io(handle, bt);
Expand Down