[wasi-common]: clean up error handling (#1253)
* Introduce WasiCtxBuilderError error type `WasiCtxBuilderError` is the `wasi-common` client-facing error type which is exclusively thrown when building a new `WasiCtx` instance. As such, building such an instance should not require the client to understand different WASI errno values as was assumed until now. This commit is a first step at streamlining error handling in `wasi-common` and makes way for the `wiggle` crate. When adding the `WasiCtxBuilderError`, I've had to do two things of notable importance: 1. I've removed a couple of `ok_or` calls in `WasiCtxBuilder::build` and replaced them with `unwrap`s, following the same pattern in different builder methods above. This is fine since we _always_ operate on non-empty `Option`s in `WasiCtxBuilder` thus `unwrap`ing will never fail. On the other hand, this might be a good opportunity to rethink the structure of our builder, and how we good remove the said `Option`s especially since we always populate them with empty containers to begin with. I understand this is to make chaining of builder methods easier which take and return `&mut self` and the same applies to `WasiCtxBuilder::build(&mut self)` method, but perhaps it would more cleanly signal the intentions if we simply moved `WasiCtxBuilder` instance around. Food for thought! 2. Methods specific to determining rights of passed around `std::fs::File` objects when populating `WasiCtx` `FdEntry` entities now return `io::Error` directly so that we can reuse them in `WasiCtxBuilder` methods (returning `WasiCtxBuilderError` error type), and in syscalls (returning WASI errno). * Return WasiError directly in syscalls Also, removes `error::Error` type altogether. Now, `io::Error` and related are automatically converted to their corresponding WASI errno value encapsulated as `WasiError`. While here, it made sense to me to move `WasiError` to `wasi` module which will align itself well with the upcoming changes introduced by `wiggle`. To different standard `Result` from WASI specific, I've created a helper alias `WasiResult` also residing in `wasi` module. * Update wig * Add from ffi::NulError and pass context to NotADirectory * Add dummy commit to test CI
This commit is contained in:
@@ -3,7 +3,7 @@ use crate::sys::fdentry_impl::{
|
||||
descriptor_as_oshandle, determine_type_and_access_rights, OsHandle,
|
||||
};
|
||||
use crate::virtfs::VirtualFile;
|
||||
use crate::{wasi, Error, Result};
|
||||
use crate::wasi::{self, WasiError, WasiResult};
|
||||
use std::marker::PhantomData;
|
||||
use std::mem::ManuallyDrop;
|
||||
use std::ops::{Deref, DerefMut};
|
||||
@@ -56,22 +56,22 @@ impl Descriptor {
|
||||
/// Return a reference to the `OsHandle` or `VirtualFile` treating it as an
|
||||
/// actual file/dir, and allowing operations which require an actual file and
|
||||
/// not just a stream or socket file descriptor.
|
||||
pub(crate) fn as_file<'descriptor>(&'descriptor self) -> Result<&'descriptor Descriptor> {
|
||||
pub(crate) fn as_file<'descriptor>(&'descriptor self) -> WasiResult<&'descriptor Descriptor> {
|
||||
match self {
|
||||
Self::OsHandle(_) => Ok(self),
|
||||
Self::VirtualFile(_) => Ok(self),
|
||||
_ => Err(Error::EBADF),
|
||||
_ => Err(WasiError::EBADF),
|
||||
}
|
||||
}
|
||||
|
||||
/// Like `as_file`, but return a mutable reference.
|
||||
pub(crate) fn as_file_mut<'descriptor>(
|
||||
&'descriptor mut self,
|
||||
) -> Result<&'descriptor mut Descriptor> {
|
||||
) -> WasiResult<&'descriptor mut Descriptor> {
|
||||
match self {
|
||||
Self::OsHandle(_) => Ok(self),
|
||||
Self::VirtualFile(_) => Ok(self),
|
||||
_ => Err(Error::EBADF),
|
||||
_ => Err(WasiError::EBADF),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -100,7 +100,7 @@ pub(crate) struct FdEntry {
|
||||
}
|
||||
|
||||
impl FdEntry {
|
||||
pub(crate) fn from(file: Descriptor) -> Result<Self> {
|
||||
pub(crate) fn from(file: Descriptor) -> io::Result<Self> {
|
||||
match file {
|
||||
Descriptor::OsHandle(handle) => unsafe { determine_type_and_access_rights(&handle) }
|
||||
.map(|(file_type, rights_base, rights_inheriting)| Self {
|
||||
@@ -129,7 +129,7 @@ impl FdEntry {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn duplicate_stdin() -> Result<Self> {
|
||||
pub(crate) fn duplicate_stdin() -> io::Result<Self> {
|
||||
unsafe { determine_type_and_access_rights(&io::stdin()) }.map(
|
||||
|(file_type, rights_base, rights_inheriting)| Self {
|
||||
file_type,
|
||||
@@ -141,7 +141,7 @@ impl FdEntry {
|
||||
)
|
||||
}
|
||||
|
||||
pub(crate) fn duplicate_stdout() -> Result<Self> {
|
||||
pub(crate) fn duplicate_stdout() -> io::Result<Self> {
|
||||
unsafe { determine_type_and_access_rights(&io::stdout()) }.map(
|
||||
|(file_type, rights_base, rights_inheriting)| Self {
|
||||
file_type,
|
||||
@@ -153,7 +153,7 @@ impl FdEntry {
|
||||
)
|
||||
}
|
||||
|
||||
pub(crate) fn duplicate_stderr() -> Result<Self> {
|
||||
pub(crate) fn duplicate_stderr() -> io::Result<Self> {
|
||||
unsafe { determine_type_and_access_rights(&io::stderr()) }.map(
|
||||
|(file_type, rights_base, rights_inheriting)| Self {
|
||||
file_type,
|
||||
@@ -165,7 +165,7 @@ impl FdEntry {
|
||||
)
|
||||
}
|
||||
|
||||
pub(crate) fn null() -> Result<Self> {
|
||||
pub(crate) fn null() -> io::Result<Self> {
|
||||
Self::from(OsHandle::from(dev_null()?).into())
|
||||
}
|
||||
|
||||
@@ -175,12 +175,12 @@ impl FdEntry {
|
||||
/// The `FdEntry` can only be converted into a valid `Descriptor` object if
|
||||
/// the specified set of base rights `rights_base`, and inheriting rights `rights_inheriting`
|
||||
/// is a subset of rights attached to this `FdEntry`. The check is performed using
|
||||
/// `FdEntry::validate_rights` method. If the check fails, `Error::ENOTCAPABLE` is returned.
|
||||
/// `FdEntry::validate_rights` method. If the check fails, `WasiError::ENOTCAPABLE` is returned.
|
||||
pub(crate) fn as_descriptor(
|
||||
&self,
|
||||
rights_base: wasi::__wasi_rights_t,
|
||||
rights_inheriting: wasi::__wasi_rights_t,
|
||||
) -> Result<&Descriptor> {
|
||||
) -> WasiResult<&Descriptor> {
|
||||
self.validate_rights(rights_base, rights_inheriting)?;
|
||||
Ok(&self.descriptor)
|
||||
}
|
||||
@@ -191,12 +191,12 @@ impl FdEntry {
|
||||
/// The `FdEntry` can only be converted into a valid `Descriptor` object if
|
||||
/// the specified set of base rights `rights_base`, and inheriting rights `rights_inheriting`
|
||||
/// is a subset of rights attached to this `FdEntry`. The check is performed using
|
||||
/// `FdEntry::validate_rights` method. If the check fails, `Error::ENOTCAPABLE` is returned.
|
||||
/// `FdEntry::validate_rights` method. If the check fails, `WasiError::ENOTCAPABLE` is returned.
|
||||
pub(crate) fn as_descriptor_mut(
|
||||
&mut self,
|
||||
rights_base: wasi::__wasi_rights_t,
|
||||
rights_inheriting: wasi::__wasi_rights_t,
|
||||
) -> Result<&mut Descriptor> {
|
||||
) -> WasiResult<&mut Descriptor> {
|
||||
self.validate_rights(rights_base, rights_inheriting)?;
|
||||
Ok(&mut self.descriptor)
|
||||
}
|
||||
@@ -205,12 +205,12 @@ impl FdEntry {
|
||||
/// inheriting rights `rights_inheriting`; i.e., if rights attached to this `FdEntry` object
|
||||
/// are a superset.
|
||||
///
|
||||
/// Upon unsuccessful check, `Error::ENOTCAPABLE` is returned.
|
||||
/// Upon unsuccessful check, `WasiError::ENOTCAPABLE` is returned.
|
||||
fn validate_rights(
|
||||
&self,
|
||||
rights_base: wasi::__wasi_rights_t,
|
||||
rights_inheriting: wasi::__wasi_rights_t,
|
||||
) -> Result<()> {
|
||||
) -> WasiResult<()> {
|
||||
let missing_base = !self.rights_base & rights_base;
|
||||
let missing_inheriting = !self.rights_inheriting & rights_inheriting;
|
||||
if missing_base != 0 || missing_inheriting != 0 {
|
||||
@@ -226,7 +226,7 @@ impl FdEntry {
|
||||
missing_base,
|
||||
missing_inheriting
|
||||
);
|
||||
Err(Error::ENOTCAPABLE)
|
||||
Err(WasiError::ENOTCAPABLE)
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user