Skip to content

fs: add new error type #792

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
May 9, 2023
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
17 changes: 11 additions & 6 deletions uefi-test-runner/src/fs/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@

use alloc::string::{String, ToString};
use alloc::vec::Vec;
use uefi::cstr16;
use uefi::fs::{FileSystem, FileSystemError, PathBuf};
use uefi::fs::{FileSystem, FileSystemIOErrorContext, IoError, PathBuf};
use uefi::proto::media::fs::SimpleFileSystem;
use uefi::table::boot::ScopedProtocol;
use uefi::{cstr16, fs, Status};

/// Tests functionality from the `uefi::fs` module. This test relies on a
/// working File System Protocol, which is tested at a dedicated place.
pub fn test(sfs: ScopedProtocol<SimpleFileSystem>) -> Result<(), FileSystemError> {
pub fn test(sfs: ScopedProtocol<SimpleFileSystem>) -> Result<(), fs::Error> {
let mut fs = FileSystem::new(sfs);

// test create dir
Expand All @@ -24,9 +24,14 @@ pub fn test(sfs: ScopedProtocol<SimpleFileSystem>) -> Result<(), FileSystemError
let read = String::from_utf8(read).expect("Should be valid utf8");
assert_eq!(read.as_str(), data_to_write);

// test copy from non-existent file
// test copy from non-existent file: does the error type work as expected?
let err = fs.copy(cstr16!("not_found"), cstr16!("abc"));
assert!(matches!(err, Err(FileSystemError::OpenError { .. })));
let expected_err = fs::Error::Io(IoError {
path: PathBuf::from(cstr16!("not_found")),
context: FileSystemIOErrorContext::OpenError,
uefi_error: uefi::Error::new(Status::NOT_FOUND, ()),
});
assert_eq!(err, Err(expected_err));

// test rename file + path buf replaces / with \
fs.rename(
Expand All @@ -35,7 +40,7 @@ pub fn test(sfs: ScopedProtocol<SimpleFileSystem>) -> Result<(), FileSystemError
)?;
// file should not be available after rename
let err = fs.read(cstr16!("foo_dir\\foo_cpy"));
assert!(matches!(err, Err(FileSystemError::OpenError { .. })));
assert!(err.is_err());

// test read dir on a sub dir
let entries = fs
Expand Down
82 changes: 82 additions & 0 deletions uefi/src/fs/file_system/error.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
use crate::fs::{PathBuf, PathError};
use alloc::string::FromUtf8Error;
use core::fmt::Debug;
use derive_more::Display;

/// All errors that can happen when working with the [`FileSystem`].
///
/// [`FileSystem`]: super::FileSystem
#[derive(Debug, Clone, Display, PartialEq, Eq)]
pub enum Error {
/// IO (low-level UEFI-errors) errors. See [`IoError`].
Io(IoError),
/// Path-related errors. See [`PathError`].
Path(PathError),
/// Can't parse file content as UTF-8. See [`FromUtf8Error`].
Utf8Encoding(FromUtf8Error),
}

/// UEFI-error with context when working with the underlying UEFI file protocol.
#[derive(Debug, Clone, Display, PartialEq, Eq)]
#[display(fmt = "IoError({},{})", context, path)]
pub struct IoError {
/// The path that led to the error.
pub path: PathBuf,
/// The context in which the path was used.
pub context: FileSystemIOErrorContext,
/// The underlying UEFI error.
pub uefi_error: crate::Error,
}

/// Enum that further specifies the context in that a [`Error`]
/// occurred.
#[derive(Debug, Clone, Display, PartialEq, Eq)]
pub enum FileSystemIOErrorContext {
/// Can't delete the directory.
CantDeleteDirectory,
/// Can't delete the file.
CantDeleteFile,
/// Error flushing file.
FlushFailure,
/// Can't open the root directory of the underlying volume.
CantOpenVolume,
/// Error while reading the metadata of the file.
Metadata,
/// Could not open the given path. One possible reason is that the file does
/// not exist.
OpenError,
/// Error reading file.
ReadFailure,
/// Error writing bytes.
WriteFailure,
/// The path exists but does not correspond to a directory when a directory
/// was expected.
NotADirectory,
/// The path exists but does not correspond to a file when a file was
/// expected.
NotAFile,
}

impl From<PathError> for Error {
fn from(value: PathError) -> Self {
Self::Path(value)
}
}

#[cfg(feature = "unstable")]
impl core::error::Error for Error {
fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
match self {
Error::Io(err) => Some(err),
Error::Path(err) => Some(err),
Error::Utf8Encoding(err) => Some(err),
}
}
}

#[cfg(feature = "unstable")]
impl core::error::Error for IoError {
fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
Some(&self.uefi_error)
}
}
Loading