[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:
@@ -1,6 +1,6 @@
|
||||
//! WASI host types specific to Windows host.
|
||||
use crate::host::FileType;
|
||||
use crate::{error::FromRawOsError, wasi, Error, Result};
|
||||
use crate::wasi::{self, WasiError, WasiResult};
|
||||
use std::convert::TryInto;
|
||||
use std::ffi::OsStr;
|
||||
use std::fs::{self, File};
|
||||
@@ -9,34 +9,42 @@ use std::os::windows::ffi::OsStrExt;
|
||||
use std::time::{SystemTime, UNIX_EPOCH};
|
||||
use winapi::shared::winerror;
|
||||
|
||||
impl FromRawOsError for Error {
|
||||
fn from_raw_os_error(code: i32) -> Self {
|
||||
// TODO: implement error mapping between Windows and WASI
|
||||
match code as u32 {
|
||||
winerror::ERROR_SUCCESS => Self::ESUCCESS,
|
||||
winerror::ERROR_BAD_ENVIRONMENT => Self::E2BIG,
|
||||
winerror::ERROR_FILE_NOT_FOUND => Self::ENOENT,
|
||||
winerror::ERROR_PATH_NOT_FOUND => Self::ENOENT,
|
||||
winerror::ERROR_TOO_MANY_OPEN_FILES => Self::ENFILE,
|
||||
winerror::ERROR_ACCESS_DENIED => Self::EACCES,
|
||||
winerror::ERROR_SHARING_VIOLATION => Self::EACCES,
|
||||
winerror::ERROR_PRIVILEGE_NOT_HELD => Self::ENOTCAPABLE, // TODO is this the correct mapping?
|
||||
winerror::ERROR_INVALID_HANDLE => Self::EBADF,
|
||||
winerror::ERROR_INVALID_NAME => Self::ENOENT,
|
||||
winerror::ERROR_NOT_ENOUGH_MEMORY => Self::ENOMEM,
|
||||
winerror::ERROR_OUTOFMEMORY => Self::ENOMEM,
|
||||
winerror::ERROR_DIR_NOT_EMPTY => Self::ENOTEMPTY,
|
||||
winerror::ERROR_NOT_READY => Self::EBUSY,
|
||||
winerror::ERROR_BUSY => Self::EBUSY,
|
||||
winerror::ERROR_NOT_SUPPORTED => Self::ENOTSUP,
|
||||
winerror::ERROR_FILE_EXISTS => Self::EEXIST,
|
||||
winerror::ERROR_BROKEN_PIPE => Self::EPIPE,
|
||||
winerror::ERROR_BUFFER_OVERFLOW => Self::ENAMETOOLONG,
|
||||
winerror::ERROR_NOT_A_REPARSE_POINT => Self::EINVAL,
|
||||
winerror::ERROR_NEGATIVE_SEEK => Self::EINVAL,
|
||||
winerror::ERROR_DIRECTORY => Self::ENOTDIR,
|
||||
winerror::ERROR_ALREADY_EXISTS => Self::EEXIST,
|
||||
_ => Self::ENOTSUP,
|
||||
impl From<io::Error> for WasiError {
|
||||
fn from(err: io::Error) -> Self {
|
||||
match err.raw_os_error() {
|
||||
Some(code) => match code as u32 {
|
||||
winerror::ERROR_SUCCESS => Self::ESUCCESS,
|
||||
winerror::ERROR_BAD_ENVIRONMENT => Self::E2BIG,
|
||||
winerror::ERROR_FILE_NOT_FOUND => Self::ENOENT,
|
||||
winerror::ERROR_PATH_NOT_FOUND => Self::ENOENT,
|
||||
winerror::ERROR_TOO_MANY_OPEN_FILES => Self::ENFILE,
|
||||
winerror::ERROR_ACCESS_DENIED => Self::EACCES,
|
||||
winerror::ERROR_SHARING_VIOLATION => Self::EACCES,
|
||||
winerror::ERROR_PRIVILEGE_NOT_HELD => Self::ENOTCAPABLE,
|
||||
winerror::ERROR_INVALID_HANDLE => Self::EBADF,
|
||||
winerror::ERROR_INVALID_NAME => Self::ENOENT,
|
||||
winerror::ERROR_NOT_ENOUGH_MEMORY => Self::ENOMEM,
|
||||
winerror::ERROR_OUTOFMEMORY => Self::ENOMEM,
|
||||
winerror::ERROR_DIR_NOT_EMPTY => Self::ENOTEMPTY,
|
||||
winerror::ERROR_NOT_READY => Self::EBUSY,
|
||||
winerror::ERROR_BUSY => Self::EBUSY,
|
||||
winerror::ERROR_NOT_SUPPORTED => Self::ENOTSUP,
|
||||
winerror::ERROR_FILE_EXISTS => Self::EEXIST,
|
||||
winerror::ERROR_BROKEN_PIPE => Self::EPIPE,
|
||||
winerror::ERROR_BUFFER_OVERFLOW => Self::ENAMETOOLONG,
|
||||
winerror::ERROR_NOT_A_REPARSE_POINT => Self::EINVAL,
|
||||
winerror::ERROR_NEGATIVE_SEEK => Self::EINVAL,
|
||||
winerror::ERROR_DIRECTORY => Self::ENOTDIR,
|
||||
winerror::ERROR_ALREADY_EXISTS => Self::EEXIST,
|
||||
x => {
|
||||
log::debug!("unknown error value: {}", x);
|
||||
Self::EIO
|
||||
}
|
||||
},
|
||||
None => {
|
||||
log::debug!("Other I/O error: {}", err);
|
||||
Self::EIO
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -73,15 +81,15 @@ fn change_time(file: &File) -> io::Result<i64> {
|
||||
winx::file::change_time(file)
|
||||
}
|
||||
|
||||
fn systemtime_to_timestamp(st: SystemTime) -> Result<u64> {
|
||||
fn systemtime_to_timestamp(st: SystemTime) -> WasiResult<u64> {
|
||||
st.duration_since(UNIX_EPOCH)
|
||||
.map_err(|_| Error::EINVAL)? // date earlier than UNIX_EPOCH
|
||||
.map_err(|_| WasiError::EINVAL)? // date earlier than UNIX_EPOCH
|
||||
.as_nanos()
|
||||
.try_into()
|
||||
.map_err(Into::into) // u128 doesn't fit into u64
|
||||
}
|
||||
|
||||
pub(crate) fn filestat_from_win(file: &File) -> Result<wasi::__wasi_filestat_t> {
|
||||
pub(crate) fn filestat_from_win(file: &File) -> WasiResult<wasi::__wasi_filestat_t> {
|
||||
let metadata = file.metadata()?;
|
||||
Ok(wasi::__wasi_filestat_t {
|
||||
dev: device_id(file)?,
|
||||
@@ -99,7 +107,7 @@ pub(crate) fn filestat_from_win(file: &File) -> Result<wasi::__wasi_filestat_t>
|
||||
///
|
||||
/// NB WASI spec requires OS string to be valid UTF-8. Otherwise,
|
||||
/// `__WASI_ERRNO_ILSEQ` error is returned.
|
||||
pub(crate) fn path_from_host<S: AsRef<OsStr>>(s: S) -> Result<String> {
|
||||
pub(crate) fn path_from_host<S: AsRef<OsStr>>(s: S) -> WasiResult<String> {
|
||||
let vec: Vec<u16> = s.as_ref().encode_wide().collect();
|
||||
String::from_utf16(&vec).map_err(|_| Error::EILSEQ)
|
||||
String::from_utf16(&vec).map_err(|_| WasiError::EILSEQ)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user