[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:
Jakub Konka
2020-03-09 22:58:55 +01:00
committed by GitHub
parent 963bf0e255
commit 773915b4bf
59 changed files with 1465 additions and 1552 deletions

View File

@@ -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(())
}