diff --git a/Cargo.lock b/Cargo.lock index ed0eeb7211..b2acc2ea90 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2117,9 +2117,9 @@ dependencies = [ [[package]] name = "tracing" -version = "0.1.16" +version = "0.1.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2e2a2de6b0d5cbb13fc21193a2296888eaab62b6044479aafb3c54c01c29fcd" +checksum = "6d79ca061b032d6ce30c660fded31189ca0b9922bf483cd70759f13a2d86786c" dependencies = [ "cfg-if", "log", @@ -2129,9 +2129,9 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.9" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0693bf8d6f2bf22c690fc61a9d21ac69efdbb894a17ed596b9af0f01e64b84b" +checksum = "1fe233f4227389ab7df5b32649239da7ebe0b281824b4e84b342d04d3fd8c25e" dependencies = [ "proc-macro2", "quote", @@ -2140,9 +2140,9 @@ dependencies = [ [[package]] name = "tracing-core" -version = "0.1.11" +version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94ae75f0d28ae10786f3b1895c55fe72e79928fd5ccdebb5438c75e93fec178f" +checksum = "db63662723c316b43ca36d833707cc93dff82a02ba3d7e354f342682cc8b3545" dependencies = [ "lazy_static", ] diff --git a/crates/wasi-common/Cargo.toml b/crates/wasi-common/Cargo.toml index 6a26b7129c..f0a2d2c6d3 100644 --- a/crates/wasi-common/Cargo.toml +++ b/crates/wasi-common/Cargo.toml @@ -20,13 +20,13 @@ links = "wasi-common-19" anyhow = "1.0" thiserror = "1.0" libc = "0.2" -getrandom = "0.1" +getrandom = { version = "0.1.14", features = ["std"] } cfg-if = "0.1.9" filetime = "0.2.7" lazy_static = "1.4.0" wig = { path = "wig", version = "0.19.0" } wiggle = { path = "../wiggle", default-features = false, version = "0.19.0" } -tracing = "0.1.15" +tracing = "0.1.19" [target.'cfg(unix)'.dependencies] yanix = { path = "yanix", version = "0.19.0" } diff --git a/crates/wasi-common/src/ctx.rs b/crates/wasi-common/src/ctx.rs index 9d2ffd54f1..08584dbaf5 100644 --- a/crates/wasi-common/src/ctx.rs +++ b/crates/wasi-common/src/ctx.rs @@ -6,7 +6,7 @@ use crate::sys::stdio::NullDevice; use crate::sys::stdio::{Stderr, StderrExt, Stdin, StdinExt, Stdout, StdoutExt}; use crate::virtfs::{VirtualDir, VirtualDirEntry}; use crate::wasi::types; -use crate::wasi::{Errno, Result}; +use crate::{Error, Result}; use std::borrow::Borrow; use std::cell::RefCell; use std::collections::HashMap; @@ -469,7 +469,7 @@ impl WasiCtx { pub(crate) fn get_entry(&self, fd: types::Fd) -> Result> { match self.entries.borrow().get(&fd) { Some(entry) => Ok(entry), - None => Err(Errno::Badf), + None => Err(Error::Badf), } } @@ -478,7 +478,7 @@ impl WasiCtx { /// The `Entry` will automatically get another free raw WASI `fd` assigned. Note that /// the two subsequent free raw WASI `fd`s do not have to be stored contiguously. pub(crate) fn insert_entry(&self, entry: Entry) -> Result { - self.entries.borrow_mut().insert(entry).ok_or(Errno::Mfile) + self.entries.borrow_mut().insert(entry).ok_or(Error::Mfile) } /// Insert the specified `Entry` with the specified raw WASI `fd` key into the `WasiCtx` @@ -489,6 +489,6 @@ impl WasiCtx { /// Remove `Entry` corresponding to the specified raw WASI `fd` from the `WasiCtx` object. pub(crate) fn remove_entry(&self, fd: types::Fd) -> Result> { - self.entries.borrow_mut().remove(fd).ok_or(Errno::Badf) + self.entries.borrow_mut().remove(fd).ok_or(Error::Badf) } } diff --git a/crates/wasi-common/src/entry.rs b/crates/wasi-common/src/entry.rs index 73923e6902..8e65f4ec5a 100644 --- a/crates/wasi-common/src/entry.rs +++ b/crates/wasi-common/src/entry.rs @@ -1,6 +1,6 @@ use crate::handle::{Handle, HandleRights}; use crate::wasi::types::Filetype; -use crate::wasi::{Errno, Result}; +use crate::{Error, Result}; use std::ops::Deref; use std::path::PathBuf; use std::rc::Rc; @@ -77,7 +77,7 @@ impl Entry { /// The `Entry` can only be converted into a valid `Handle` object if /// the specified set of base rights, and inheriting rights encapsulated within `rights` /// `HandleRights` structure is a subset of rights attached to this `Entry`. The check is - /// performed using `Entry::validate_rights` method. If the check fails, `Errno::Notcapable` + /// performed using `Entry::validate_rights` method. If the check fails, `Error::Notcapable` /// is returned. pub(crate) fn as_handle(&self, rights: &HandleRights) -> Result { self.validate_rights(rights)?; @@ -87,7 +87,7 @@ impl Entry { /// Check if this `Entry` object satisfies the specified `HandleRights`; i.e., if /// rights attached to this `Entry` object are a superset. /// - /// Upon unsuccessful check, `Errno::Notcapable` is returned. + /// Upon unsuccessful check, `Error::Notcapable` is returned. pub(crate) fn validate_rights(&self, rights: &HandleRights) -> Result<()> { let this_rights = self.handle.get_rights(); if this_rights.contains(rights) { @@ -98,7 +98,7 @@ impl Entry { actual = tracing::field::display(this_rights), "validate_rights failed", ); - Err(Errno::Notcapable) + Err(Error::Notcapable) } } } diff --git a/crates/wasi-common/src/error.rs b/crates/wasi-common/src/error.rs new file mode 100644 index 0000000000..282a46734f --- /dev/null +++ b/crates/wasi-common/src/error.rs @@ -0,0 +1,195 @@ +use cfg_if::cfg_if; +use thiserror::Error; + +pub type Result = std::result::Result; + +/// Internal error type for the `wasi-common` crate. +/// Contains variants of the WASI `$errno` type are added according to what is actually used internally by +/// the crate. Not all values are represented presently. +#[derive(Debug, Error)] +pub enum Error { + #[error("Wiggle GuestError: {0}")] + Guest(#[from] wiggle::GuestError), + #[error("TryFromIntError: {0}")] + TryFromInt(#[from] std::num::TryFromIntError), + #[error("Utf8Error: {0}")] + Utf8(#[from] std::str::Utf8Error), + #[error("GetRandom: {0}")] + GetRandom(#[from] getrandom::Error), + + /// The host OS may return an io error that doesn't match one of the + /// wasi errno variants we expect. We do not expose the details of this + /// error to the user. + #[error("Unexpected IoError: {0}")] + UnexpectedIo(#[source] std::io::Error), + + // Below this, all variants are from the `$errno` type: + /// Errno::TooBig: Argument list too long + #[error("TooBig: Argument list too long")] + TooBig, + /// Errno::Acces: Permission denied + #[error("Acces: Permission denied")] + Acces, + /// Errno::Badf: Bad file descriptor + #[error("Badf: Bad file descriptor")] + Badf, + /// Errno::Busy: Device or resource busy + #[error("Busy: Device or resource busy")] + Busy, + /// Errno::Exist: File exists + #[error("Exist: File exists")] + Exist, + /// Errno::Fault: Bad address + #[error("Fault: Bad address")] + Fault, + /// Errno::Fbig: File too large + #[error("Fbig: File too large")] + Fbig, + /// Errno::Ilseq: Illegal byte sequence + #[error("Ilseq: Illegal byte sequence")] + Ilseq, + /// Errno::Inval: Invalid argument + #[error("Inval: Invalid argument")] + Inval, + /// Errno::Io: I/O error + #[error("Io: I/o error")] + Io, + /// Errno::Isdir: Is a directory + #[error("Isdir: Is a directory")] + Isdir, + /// Errno::Loop: Too many levels of symbolic links + #[error("Loop: Too many levels of symbolic links")] + Loop, + /// Errno::Mfile: File descriptor value too large + #[error("Mfile: File descriptor value too large")] + Mfile, + /// Errno::Mlink: Too many links + #[error("Mlink: Too many links")] + Mlink, + /// Errno::Nametoolong: Filename too long + #[error("Nametoolong: Filename too long")] + Nametoolong, + /// Errno::Nfile: Too many files open in system + #[error("Nfile: Too many files open in system")] + Nfile, + /// Errno::Noent: No such file or directory + #[error("Noent: No such file or directory")] + Noent, + /// Errno::Nomem: Not enough space + #[error("Nomem: Not enough space")] + Nomem, + /// Errno::Nospc: No space left on device + #[error("Nospc: No space left on device")] + Nospc, + /// Errno::Notdir: Not a directory or a symbolic link to a directory. + #[error("Notdir: Not a directory or a symbolic link to a directory")] + Notdir, + /// Errno::Notempty: Directory not empty. + #[error("Notempty: Directory not empty")] + Notempty, + /// Errno::Notsup: Not supported, or operation not supported on socket. + #[error("Notsup: Not supported, or operation not supported on socket")] + Notsup, + /// Errno::Overflow: Value too large to be stored in data type. + #[error("Overflow: Value too large to be stored in data type")] + Overflow, + /// Errno::Pipe: Broken pipe + #[error("Pipe: Broken pipe")] + Pipe, + /// Errno::Perm: Operation not permitted + #[error("Perm: Operation not permitted")] + Perm, + /// Errno::Spipe: Invalid seek + #[error("Spipe: Invalid seek")] + Spipe, + /// Errno::Notcapable: Extension: Capabilities insufficient + #[error("Notcapable: cabailities insufficient")] + Notcapable, +} + +impl From for Error { + fn from(_err: std::convert::Infallible) -> Self { + unreachable!("should be impossible: From") + } +} + +// Turning an io::Error into an Error has platform-specific behavior +cfg_if! { + if #[cfg(windows)] { +use winapi::shared::winerror; +use std::io; +impl From for Error { + fn from(err: io::Error) -> Self { + match err.raw_os_error() { + Some(code) => match code as u32 { + winerror::ERROR_BAD_ENVIRONMENT => Self::TooBig, + winerror::ERROR_FILE_NOT_FOUND => Self::Noent, + winerror::ERROR_PATH_NOT_FOUND => Self::Noent, + winerror::ERROR_TOO_MANY_OPEN_FILES => Self::Nfile, + winerror::ERROR_ACCESS_DENIED => Self::Acces, + winerror::ERROR_SHARING_VIOLATION => Self::Acces, + winerror::ERROR_PRIVILEGE_NOT_HELD => Self::Notcapable, + winerror::ERROR_INVALID_HANDLE => Self::Badf, + winerror::ERROR_INVALID_NAME => Self::Noent, + winerror::ERROR_NOT_ENOUGH_MEMORY => Self::Nomem, + winerror::ERROR_OUTOFMEMORY => Self::Nomem, + winerror::ERROR_DIR_NOT_EMPTY => Self::Notempty, + winerror::ERROR_NOT_READY => Self::Busy, + winerror::ERROR_BUSY => Self::Busy, + winerror::ERROR_NOT_SUPPORTED => Self::Notsup, + winerror::ERROR_FILE_EXISTS => Self::Exist, + winerror::ERROR_BROKEN_PIPE => Self::Pipe, + winerror::ERROR_BUFFER_OVERFLOW => Self::Nametoolong, + winerror::ERROR_NOT_A_REPARSE_POINT => Self::Inval, + winerror::ERROR_NEGATIVE_SEEK => Self::Inval, + winerror::ERROR_DIRECTORY => Self::Notdir, + winerror::ERROR_ALREADY_EXISTS => Self::Exist, + _ => Self::UnexpectedIo(err), + }, + None => Self::UnexpectedIo(err), + } + } +} + + } else { +use std::io; +impl From for Error { + fn from(err: io::Error) -> Self { + match err.raw_os_error() { + Some(code) => match code { + libc::EPIPE => Self::Pipe, + libc::EPERM => Self::Perm, + libc::ENOENT => Self::Noent, + libc::ENOMEM => Self::Nomem, + libc::E2BIG => Self::TooBig, + libc::EIO => Self::Io, + libc::EBADF => Self::Badf, + libc::EBUSY => Self::Busy, + libc::EACCES => Self::Acces, + libc::EFAULT => Self::Fault, + libc::ENOTDIR => Self::Notdir, + libc::EISDIR => Self::Isdir, + libc::EINVAL => Self::Inval, + libc::EEXIST => Self::Exist, + libc::EFBIG => Self::Fbig, + libc::ENOSPC => Self::Nospc, + libc::ESPIPE => Self::Spipe, + libc::EMFILE => Self::Mfile, + libc::EMLINK => Self::Mlink, + libc::ENAMETOOLONG => Self::Nametoolong, + libc::ENFILE => Self::Nfile, + libc::ENOTEMPTY => Self::Notempty, + libc::ELOOP => Self::Loop, + libc::EOVERFLOW => Self::Overflow, + libc::EILSEQ => Self::Ilseq, + libc::ENOTSUP => Self::Notsup, + _ => Self::UnexpectedIo(err), + }, + None => { + Self::UnexpectedIo(err) + } + } + } +} + } +} diff --git a/crates/wasi-common/src/fs/file.rs b/crates/wasi-common/src/fs/file.rs index 9382804052..39a3b5a274 100644 --- a/crates/wasi-common/src/fs/file.rs +++ b/crates/wasi-common/src/fs/file.rs @@ -1,6 +1,7 @@ use crate::fs::Metadata; +use crate::wasi::types; use crate::wasi::wasi_snapshot_preview1::WasiSnapshotPreview1; -use crate::wasi::{types, Result}; +use crate::Result; use crate::WasiCtx; use std::io; diff --git a/crates/wasi-common/src/handle.rs b/crates/wasi-common/src/handle.rs index 8cdf6a4c57..72f0a7db1b 100644 --- a/crates/wasi-common/src/handle.rs +++ b/crates/wasi-common/src/handle.rs @@ -1,5 +1,5 @@ use crate::wasi::types::{self, Rights}; -use crate::wasi::{Errno, Result}; +use crate::{Error, Result}; use std::any::Any; use std::fmt; use std::io::{self, SeekFrom}; @@ -107,25 +107,25 @@ pub trait Handle { _offset: types::Filesize, _len: types::Filesize, ) -> Result<()> { - Err(Errno::Badf) + Err(Error::Badf) } fn allocate(&self, _offset: types::Filesize, _len: types::Filesize) -> Result<()> { - Err(Errno::Badf) + Err(Error::Badf) } fn datasync(&self) -> Result<()> { - Err(Errno::Inval) + Err(Error::Inval) } fn fdstat_get(&self) -> Result { Ok(types::Fdflags::empty()) } fn fdstat_set_flags(&self, _fdflags: types::Fdflags) -> Result<()> { - Err(Errno::Badf) + Err(Error::Badf) } fn filestat_get(&self) -> Result { - Err(Errno::Badf) + Err(Error::Badf) } fn filestat_set_size(&self, _st_size: types::Filesize) -> Result<()> { - Err(Errno::Badf) + Err(Error::Badf) } fn filestat_set_times( &self, @@ -133,39 +133,39 @@ pub trait Handle { _mtim: types::Timestamp, _fst_flags: types::Fstflags, ) -> Result<()> { - Err(Errno::Badf) + Err(Error::Badf) } fn preadv(&self, _buf: &mut [io::IoSliceMut], _offset: u64) -> Result { - Err(Errno::Badf) + Err(Error::Badf) } fn pwritev(&self, _buf: &[io::IoSlice], _offset: u64) -> Result { - Err(Errno::Badf) + Err(Error::Badf) } fn read_vectored(&self, _iovs: &mut [io::IoSliceMut]) -> Result { - Err(Errno::Badf) + Err(Error::Badf) } fn readdir<'a>( &'a self, _cookie: types::Dircookie, ) -> Result> + 'a>> { - Err(Errno::Badf) + Err(Error::Badf) } fn seek(&self, _offset: SeekFrom) -> Result { - Err(Errno::Badf) + Err(Error::Badf) } fn sync(&self) -> Result<()> { Ok(()) } fn write_vectored(&self, _iovs: &[io::IoSlice]) -> Result { - Err(Errno::Badf) + Err(Error::Badf) } // TODO perhaps should be a separate trait? // PathOps fn create_directory(&self, _path: &str) -> Result<()> { - Err(Errno::Acces) + Err(Error::Acces) } fn filestat_get_at(&self, _path: &str, _follow: bool) -> Result { - Err(Errno::Acces) + Err(Error::Acces) } fn filestat_set_times_at( &self, @@ -175,7 +175,7 @@ pub trait Handle { _fst_flags: types::Fstflags, _follow: bool, ) -> Result<()> { - Err(Errno::Acces) + Err(Error::Acces) } fn openat( &self, @@ -185,7 +185,7 @@ pub trait Handle { _oflags: types::Oflags, _fd_flags: types::Fdflags, ) -> Result> { - Err(Errno::Acces) + Err(Error::Acces) } fn link( &self, @@ -194,24 +194,24 @@ pub trait Handle { _new_path: &str, _follow: bool, ) -> Result<()> { - Err(Errno::Acces) + Err(Error::Acces) } fn readlink(&self, _path: &str, _buf: &mut [u8]) -> Result { - Err(Errno::Acces) + Err(Error::Acces) } fn readlinkat(&self, _path: &str) -> Result { - Err(Errno::Acces) + Err(Error::Acces) } fn remove_directory(&self, _path: &str) -> Result<()> { - Err(Errno::Acces) + Err(Error::Acces) } fn rename(&self, _old_path: &str, _new_handle: Box, _new_path: &str) -> Result<()> { - Err(Errno::Acces) + Err(Error::Acces) } fn symlink(&self, _old_path: &str, _new_path: &str) -> Result<()> { - Err(Errno::Acces) + Err(Error::Acces) } fn unlink_file(&self, _path: &str) -> Result<()> { - Err(Errno::Acces) + Err(Error::Acces) } } diff --git a/crates/wasi-common/src/lib.rs b/crates/wasi-common/src/lib.rs index 65b5ea047d..76e64bb3c0 100644 --- a/crates/wasi-common/src/lib.rs +++ b/crates/wasi-common/src/lib.rs @@ -23,6 +23,7 @@ mod ctx; mod entry; +mod error; mod fdpool; pub mod fs; mod handle; @@ -36,6 +37,7 @@ pub mod virtfs; pub mod wasi; pub use ctx::{WasiCtx, WasiCtxBuilder, WasiCtxBuilderError}; +pub use error::{Error, Result}; pub use handle::{Handle, HandleRights}; pub use sys::osdir::OsDir; pub use sys::osfile::OsFile; diff --git a/crates/wasi-common/src/path.rs b/crates/wasi-common/src/path.rs index 99452a7b17..a5b7304186 100644 --- a/crates/wasi-common/src/path.rs +++ b/crates/wasi-common/src/path.rs @@ -1,6 +1,7 @@ use crate::entry::Entry; use crate::handle::{Handle, HandleRights}; -use crate::wasi::{types, Errno, Result}; +use crate::wasi::types; +use crate::{Error, Result}; use std::path::{Component, Path}; use std::str; use wiggle::GuestPtr; @@ -26,12 +27,12 @@ pub(crate) fn get( if path.contains('\0') { // if contains NUL, return Ilseq - return Err(Errno::Ilseq); + return Err(Error::Ilseq); } if entry.get_file_type() != types::Filetype::Directory { // if `dirfd` doesn't refer to a directory, return `Notdir`. - return Err(Errno::Notdir); + return Err(Error::Notdir); } let handle = entry.as_handle(required_rights)?; @@ -60,7 +61,7 @@ pub(crate) fn get( let ends_with_slash = cur_path.ends_with('/'); let mut components = Path::new(&cur_path).components(); let head = match components.next() { - None => return Err(Errno::Noent), + None => return Err(Error::Noent), Some(p) => p, }; let tail = components.as_path(); @@ -78,18 +79,18 @@ pub(crate) fn get( match head { Component::Prefix(_) | Component::RootDir => { // path is absolute! - return Err(Errno::Notcapable); + return Err(Error::Notcapable); } Component::CurDir => { // "." so skip } Component::ParentDir => { // ".." so pop a dir - let _ = dir_stack.pop().ok_or(Errno::Notcapable)?; + let _ = dir_stack.pop().ok_or(Error::Notcapable)?; // we're not allowed to pop past the original directory if dir_stack.is_empty() { - return Err(Errno::Notcapable); + return Err(Error::Notcapable); } } Component::Normal(head) => { @@ -100,7 +101,7 @@ pub(crate) fn get( } if !path_stack.is_empty() || (ends_with_slash && !needs_final_component) { - let fd = dir_stack.last().ok_or(Errno::Notcapable)?; + let fd = dir_stack.last().ok_or(Error::Notcapable)?; match fd.openat( &head, false, @@ -113,16 +114,16 @@ pub(crate) fn get( } Err(e) => { match e { - Errno::Loop | Errno::Mlink | Errno::Notdir => + Error::Loop | Error::Mlink | Error::Notdir => // Check to see if it was a symlink. Linux indicates // this with ENOTDIR because of the O_DIRECTORY flag. { // attempt symlink expansion - let fd = dir_stack.last().ok_or(Errno::Notcapable)?; + let fd = dir_stack.last().ok_or(Error::Notcapable)?; let mut link_path = fd.readlinkat(&head)?; symlink_expansions += 1; if symlink_expansions > MAX_SYMLINK_EXPANSIONS { - return Err(Errno::Loop); + return Err(Error::Loop); } if head.ends_with('/') { @@ -149,12 +150,12 @@ pub(crate) fn get( { // if there's a trailing slash, or if `LOOKUP_SYMLINK_FOLLOW` is set, attempt // symlink expansion - let fd = dir_stack.last().ok_or(Errno::Notcapable)?; + let fd = dir_stack.last().ok_or(Error::Notcapable)?; match fd.readlinkat(&head) { Ok(mut link_path) => { symlink_expansions += 1; if symlink_expansions > MAX_SYMLINK_EXPANSIONS { - return Err(Errno::Loop); + return Err(Error::Loop); } if head.ends_with('/') { @@ -169,29 +170,26 @@ pub(crate) fn get( path_stack.push(link_path); continue; } + Err(Error::Inval) | Err(Error::Noent) | Err(Error::Notdir) => { + // this handles the cases when trying to link to + // a destination that already exists, and the target + // path contains a slash + } Err(e) => { - if e != Errno::Inval - && e != Errno::Noent - // this handles the cases when trying to link to - // a destination that already exists, and the target - // path contains a slash - && e != Errno::Notdir - { - return Err(e); - } + return Err(e); } } } // not a symlink, so we're done; - return Ok((dir_stack.pop().ok_or(Errno::Notcapable)?, head)); + return Ok((dir_stack.pop().ok_or(Error::Notcapable)?, head)); } } } None => { // no further components to process. means we've hit a case like "." or "a/..", or if the // input path has trailing slashes and `needs_final_component` is not set - return Ok((dir_stack.pop().ok_or(Errno::Notcapable)?, String::from("."))); + return Ok((dir_stack.pop().ok_or(Error::Notcapable)?, String::from("."))); } } } diff --git a/crates/wasi-common/src/snapshots/wasi_snapshot_preview1.rs b/crates/wasi-common/src/snapshots/wasi_snapshot_preview1.rs index ee5cd0cd80..e2d6c0eef0 100644 --- a/crates/wasi-common/src/snapshots/wasi_snapshot_preview1.rs +++ b/crates/wasi-common/src/snapshots/wasi_snapshot_preview1.rs @@ -2,12 +2,11 @@ use crate::entry::{Entry, EntryHandle}; use crate::handle::HandleRights; use crate::sys::clock; use crate::wasi::wasi_snapshot_preview1::WasiSnapshotPreview1; -use crate::wasi::{types, AsBytes, Errno, Result}; -use crate::WasiCtx; -use crate::{path, poll}; +use crate::wasi::{types, AsBytes}; +use crate::{path, poll, Error, Result, WasiCtx}; use std::convert::TryInto; use std::io::{self, SeekFrom}; -use tracing::{debug, error, trace}; +use tracing::{debug, trace}; use wiggle::{GuestPtr, GuestSlice}; impl<'a> WasiSnapshotPreview1 for WasiCtx { @@ -36,7 +35,7 @@ impl<'a> WasiSnapshotPreview1 for WasiCtx { let mut argv_size: types::Size = 0; for arg in &self.args { let arg_len = arg.as_bytes_with_nul().len().try_into()?; - argv_size = argv_size.checked_add(arg_len).ok_or(Errno::Overflow)?; + argv_size = argv_size.checked_add(arg_len).ok_or(Error::Overflow)?; } Ok((argc, argv_size)) } @@ -66,7 +65,7 @@ impl<'a> WasiSnapshotPreview1 for WasiCtx { let mut environ_size: types::Size = 0; for environ in &self.env { let env_len = environ.as_bytes_with_nul().len().try_into()?; - environ_size = environ_size.checked_add(env_len).ok_or(Errno::Overflow)?; + environ_size = environ_size.checked_add(env_len).ok_or(Error::Overflow)?; } Ok((environ_count, environ_size)) } @@ -114,7 +113,7 @@ impl<'a> WasiSnapshotPreview1 for WasiCtx { if let Ok(fe) = self.get_entry(fd) { // can't close preopened files if fe.preopen_path.is_some() { - return Err(Errno::Notsup); + return Err(Error::Notsup); } } self.remove_entry(fd)?; @@ -156,7 +155,7 @@ impl<'a> WasiSnapshotPreview1 for WasiCtx { let rights = HandleRights::new(fs_rights_base, fs_rights_inheriting); let entry = self.get_entry(fd)?; if !entry.get_rights().contains(&rights) { - return Err(Errno::Notcapable); + return Err(Error::Notcapable); } entry.set_rights(rights); Ok(()) @@ -206,7 +205,7 @@ impl<'a> WasiSnapshotPreview1 for WasiCtx { HandleRights::from_base(types::Rights::FD_READ | types::Rights::FD_SEEK); let entry = self.get_entry(fd)?; if offset > i64::max_value() as u64 { - return Err(Errno::Io); + return Err(Error::Io); } let host_nread = { @@ -225,9 +224,9 @@ impl<'a> WasiSnapshotPreview1 for WasiCtx { fn fd_prestat_get(&self, fd: types::Fd) -> Result { // TODO: should we validate any rights here? let entry = self.get_entry(fd)?; - let po_path = entry.preopen_path.as_ref().ok_or(Errno::Notsup)?; + let po_path = entry.preopen_path.as_ref().ok_or(Error::Notsup)?; if entry.get_file_type() != types::Filetype::Directory { - return Err(Errno::Notdir); + return Err(Error::Notdir); } let path = path::from_host(po_path.as_os_str())?; @@ -245,16 +244,16 @@ impl<'a> WasiSnapshotPreview1 for WasiCtx { ) -> Result<()> { // TODO: should we validate any rights here? let entry = self.get_entry(fd)?; - let po_path = entry.preopen_path.as_ref().ok_or(Errno::Notsup)?; + let po_path = entry.preopen_path.as_ref().ok_or(Error::Notsup)?; if entry.get_file_type() != types::Filetype::Directory { - return Err(Errno::Notdir); + return Err(Error::Notdir); } let host_path = path::from_host(po_path.as_os_str())?; let host_path_len = host_path.len().try_into()?; if host_path_len > path_len { - return Err(Errno::Nametoolong); + return Err(Error::Nametoolong); } trace!(" | path='{}'", host_path); @@ -283,7 +282,7 @@ impl<'a> WasiSnapshotPreview1 for WasiCtx { let entry = self.get_entry(fd)?; if offset > i64::max_value() as u64 { - return Err(Errno::Io); + return Err(Error::Io); } let host_nwritten = { @@ -339,7 +338,7 @@ impl<'a> WasiSnapshotPreview1 for WasiCtx { let dirent_len: types::Size = dirent_raw.len().try_into()?; let name_raw = name.as_bytes(); let name_len = name_raw.len().try_into()?; - let offset = dirent_len.checked_add(name_len).ok_or(Errno::Overflow)?; + let offset = dirent_len.checked_add(name_len).ok_or(Error::Overflow)?; if (buf_len - bufused) < offset { break; } else { @@ -356,7 +355,7 @@ impl<'a> WasiSnapshotPreview1 for WasiCtx { fn fd_renumber(&self, from: types::Fd, to: types::Fd) -> Result<()> { if !self.contains_entry(from) { - return Err(Errno::Badf); + return Err(Error::Badf); } // Don't allow renumbering over a pre-opened resource. @@ -364,12 +363,12 @@ impl<'a> WasiSnapshotPreview1 for WasiCtx { // userspace is capable of removing entries from its tables as well. if let Ok(from_fe) = self.get_entry(from) { if from_fe.preopen_path.is_some() { - return Err(Errno::Notsup); + return Err(Error::Notsup); } } if let Ok(to_fe) = self.get_entry(to) { if to_fe.preopen_path.is_some() { - return Err(Errno::Notsup); + return Err(Error::Notsup); } } let fe = self.remove_entry(from)?; @@ -672,7 +671,7 @@ impl<'a> WasiSnapshotPreview1 for WasiCtx { nsubscriptions: types::Size, ) -> Result { if u64::from(nsubscriptions) > types::Filesize::max_value() { - return Err(Errno::Inval); + return Err(Error::Inval); } let mut subscriptions = Vec::new(); @@ -690,7 +689,7 @@ impl<'a> WasiSnapshotPreview1 for WasiCtx { // As mandated by the WASI spec: // > If `nsubscriptions` is 0, returns `errno::inval`. if subscriptions.is_empty() { - return Err(Errno::Inval); + return Err(Error::Inval); } for subscription in subscriptions { @@ -721,7 +720,7 @@ impl<'a> WasiSnapshotPreview1 for WasiCtx { Err(error) => { events.push(types::Event { userdata: subscription.userdata, - error, + error: error.into(), type_: types::Eventtype::FdRead, fd_readwrite: types::EventFdReadwrite { nbytes: 0, @@ -747,7 +746,7 @@ impl<'a> WasiSnapshotPreview1 for WasiCtx { Err(error) => { events.push(types::Event { userdata: subscription.userdata, - error, + error: error.into(), type_: types::Eventtype::FdWrite, fd_readwrite: types::EventFdReadwrite { nbytes: 0, @@ -804,10 +803,8 @@ impl<'a> WasiSnapshotPreview1 for WasiCtx { fn random_get(&self, buf: &GuestPtr, buf_len: types::Size) -> Result<()> { let mut slice = buf.as_array(buf_len).as_slice()?; - getrandom::getrandom(&mut *slice).map_err(|err| { - error!(error = tracing::field::display(err), "getrandom failure"); - Errno::Io - }) + getrandom::getrandom(&mut *slice)?; + Ok(()) } fn sock_recv( diff --git a/crates/wasi-common/src/sys/clock.rs b/crates/wasi-common/src/sys/clock.rs index 28a04f597b..a31bb1b131 100644 --- a/crates/wasi-common/src/sys/clock.rs +++ b/crates/wasi-common/src/sys/clock.rs @@ -1,5 +1,5 @@ use crate::wasi::types::{Subclockflags, SubscriptionClock}; -use crate::wasi::{Errno, Result}; +use crate::{Error, Result}; use std::time::SystemTime; pub(crate) use super::sys_impl::clock::*; @@ -10,7 +10,7 @@ pub(crate) fn to_relative_ns_delay(clock: &SubscriptionClock) -> Result { } let now: u128 = SystemTime::now() .duration_since(SystemTime::UNIX_EPOCH) - .map_err(|_| Errno::Notcapable)? + .map_err(|_| Error::Notcapable)? .as_nanos(); let deadline = u128::from(clock.timeout); Ok(deadline.saturating_sub(now)) diff --git a/crates/wasi-common/src/sys/fd.rs b/crates/wasi-common/src/sys/fd.rs index 2fa59ee95c..ed6cd36b99 100644 --- a/crates/wasi-common/src/sys/fd.rs +++ b/crates/wasi-common/src/sys/fd.rs @@ -1,4 +1,5 @@ -use crate::wasi::{types, Errno, Result}; +use crate::wasi::types; +use crate::{Error, Result}; use filetime::{set_file_handle_times, FileTime}; use std::fs::File; use std::time::{Duration, SystemTime, UNIX_EPOCH}; @@ -17,7 +18,7 @@ pub(crate) fn filestat_set_times( let set_mtim_now = fst_flags.contains(&types::Fstflags::MTIM_NOW); if (set_atim && set_atim_now) || (set_mtim && set_mtim_now) { - return Err(Errno::Inval); + return Err(Error::Inval); } let atim = if set_atim { let time = UNIX_EPOCH + Duration::from_nanos(st_atim); diff --git a/crates/wasi-common/src/sys/osdir.rs b/crates/wasi-common/src/sys/osdir.rs index bf8bb0c280..3461149e8b 100644 --- a/crates/wasi-common/src/sys/osdir.rs +++ b/crates/wasi-common/src/sys/osdir.rs @@ -1,7 +1,8 @@ use super::sys_impl::oshandle::RawOsHandle; use super::{fd, path, AsFile}; use crate::handle::{Handle, HandleRights}; -use crate::wasi::{types, Errno, Result}; +use crate::wasi::types; +use crate::{Error, Result}; use std::any::Any; use std::io; use std::ops::Deref; @@ -102,7 +103,7 @@ impl Handle for OsDir { let new_handle = match new_handle.as_any().downcast_ref::() { None => { error!("Tried to link with handle that's not an OsDir"); - return Err(Errno::Badf); + return Err(Error::Badf); } Some(handle) => handle, }; @@ -121,7 +122,7 @@ impl Handle for OsDir { let new_handle = match new_handle.as_any().downcast_ref::() { None => { error!("Tried to rename with handle that's not an OsDir"); - return Err(Errno::Badf); + return Err(Error::Badf); } Some(handle) => handle, }; diff --git a/crates/wasi-common/src/sys/osfile.rs b/crates/wasi-common/src/sys/osfile.rs index f07ddf6240..31a2ccbf0e 100644 --- a/crates/wasi-common/src/sys/osfile.rs +++ b/crates/wasi-common/src/sys/osfile.rs @@ -1,7 +1,8 @@ use super::sys_impl::oshandle::RawOsHandle; use super::{fd, AsFile}; use crate::handle::{Handle, HandleRights}; -use crate::wasi::{types, Errno, Result}; +use crate::wasi::types; +use crate::{Error, Result}; use std::any::Any; use std::cell::Cell; use std::fs::File; @@ -77,10 +78,10 @@ impl Handle for OsFile { let fd = self.as_file()?; let metadata = fd.metadata()?; let current_size = metadata.len(); - let wanted_size = offset.checked_add(len).ok_or(Errno::TooBig)?; + let wanted_size = offset.checked_add(len).ok_or(Error::TooBig)?; // This check will be unnecessary when rust-lang/rust#63326 is fixed if wanted_size > i64::max_value() as u64 { - return Err(Errno::TooBig); + return Err(Error::TooBig); } if wanted_size > current_size { fd.set_len(wanted_size)?; diff --git a/crates/wasi-common/src/sys/osother.rs b/crates/wasi-common/src/sys/osother.rs index 4e5c90192d..73c359493e 100644 --- a/crates/wasi-common/src/sys/osother.rs +++ b/crates/wasi-common/src/sys/osother.rs @@ -3,7 +3,7 @@ use super::{fd, AsFile}; use crate::handle::{Handle, HandleRights}; use crate::sandboxed_tty_writer::SandboxedTTYWriter; use crate::wasi::types::{self, Filetype}; -use crate::wasi::Result; +use crate::Result; use std::any::Any; use std::cell::Cell; use std::fs::File; diff --git a/crates/wasi-common/src/sys/stdio.rs b/crates/wasi-common/src/sys/stdio.rs index 786643b559..ef5535c7ee 100644 --- a/crates/wasi-common/src/sys/stdio.rs +++ b/crates/wasi-common/src/sys/stdio.rs @@ -20,7 +20,8 @@ use super::{fd, AsFile}; use crate::handle::{Handle, HandleRights}; use crate::sandboxed_tty_writer::SandboxedTTYWriter; use crate::wasi::types::{self, Filetype}; -use crate::wasi::{Errno, Result, RightsExt}; +use crate::wasi::RightsExt; +use crate::{Error, Result}; use std::any::Any; use std::cell::Cell; use std::convert::TryInto; @@ -226,7 +227,7 @@ impl Handle for NullDevice { let mut total_len = 0u32; for iov in iovs { let len: types::Size = iov.len().try_into()?; - total_len = total_len.checked_add(len).ok_or(Errno::Overflow)?; + total_len = total_len.checked_add(len).ok_or(Error::Overflow)?; } Ok(total_len as usize) } diff --git a/crates/wasi-common/src/sys/unix/bsd/osdir.rs b/crates/wasi-common/src/sys/unix/bsd/osdir.rs index ed665329d6..b375254baa 100644 --- a/crates/wasi-common/src/sys/unix/bsd/osdir.rs +++ b/crates/wasi-common/src/sys/unix/bsd/osdir.rs @@ -1,6 +1,6 @@ use crate::handle::HandleRights; use crate::sys::sys_impl::oshandle::RawOsHandle; -use crate::wasi::Result; +use crate::Result; use std::cell::{Cell, RefCell, RefMut}; use std::io; use yanix::dir::Dir; diff --git a/crates/wasi-common/src/sys/unix/bsd/path.rs b/crates/wasi-common/src/sys/unix/bsd/path.rs index ca93b437c5..7d4b619c52 100644 --- a/crates/wasi-common/src/sys/unix/bsd/path.rs +++ b/crates/wasi-common/src/sys/unix/bsd/path.rs @@ -1,5 +1,5 @@ use crate::sys::osdir::OsDir; -use crate::wasi::{Errno, Result}; +use crate::{Error, Result}; use std::os::unix::prelude::AsRawFd; pub(crate) fn unlink_file(dirfd: &OsDir, path: &str) -> Result<()> { @@ -20,7 +20,7 @@ pub(crate) fn unlink_file(dirfd: &OsDir, path: &str) -> Result<()> { match unsafe { fstatat(dirfd.as_raw_fd(), path, AtFlags::SYMLINK_NOFOLLOW) } { Ok(stat) => { if FileType::from_stat_st_mode(stat.st_mode) == FileType::Directory { - return Err(Errno::Isdir); + return Err(Error::Isdir); } } Err(err) => { @@ -56,7 +56,7 @@ pub(crate) fn symlink(old_path: &str, new_dirfd: &OsDir, new_path: &str) -> Resu let new_path = new_path.trim_end_matches('/'); match unsafe { fstatat(new_dirfd.as_raw_fd(), new_path, AtFlags::SYMLINK_NOFOLLOW) } { - Ok(_) => return Err(Errno::Exist), + Ok(_) => return Err(Error::Exist), Err(err) => { tracing::debug!("path_symlink fstatat error: {:?}", err); } @@ -100,9 +100,9 @@ pub(crate) fn rename( Ok(_) => { // check if destination contains a trailing slash if new_path.contains('/') { - return Err(Errno::Notdir); + return Err(Error::Notdir); } else { - return Err(Errno::Noent); + return Err(Error::Noent); } } Err(err) => { diff --git a/crates/wasi-common/src/sys/unix/clock.rs b/crates/wasi-common/src/sys/unix/clock.rs index d043283462..e24c725807 100644 --- a/crates/wasi-common/src/sys/unix/clock.rs +++ b/crates/wasi-common/src/sys/unix/clock.rs @@ -1,4 +1,5 @@ -use crate::wasi::{types, Errno, Result}; +use crate::wasi::types; +use crate::{Error, Result}; use yanix::clock::{clock_getres, clock_gettime, ClockId}; pub(crate) fn res_get(clock_id: types::Clockid) -> Result { @@ -11,11 +12,11 @@ pub(crate) fn res_get(clock_id: types::Clockid) -> Result { (timespec.tv_sec as types::Timestamp) .checked_mul(1_000_000_000) .and_then(|sec_ns| sec_ns.checked_add(timespec.tv_nsec as types::Timestamp)) - .map_or(Err(Errno::Overflow), |resolution| { + .map_or(Err(Error::Overflow), |resolution| { // a supported clock can never return zero; this case will probably never get hit, but // make sure we follow the spec if resolution == 0 { - Err(Errno::Inval) + Err(Error::Inval) } else { Ok(resolution) } @@ -31,5 +32,5 @@ pub(crate) fn time_get(clock_id: types::Clockid) -> Result { (timespec.tv_sec as types::Timestamp) .checked_mul(1_000_000_000) .and_then(|sec_ns| sec_ns.checked_add(timespec.tv_nsec as types::Timestamp)) - .map_or(Err(Errno::Overflow), Ok) + .map_or(Err(Error::Overflow), Ok) } diff --git a/crates/wasi-common/src/sys/unix/fd.rs b/crates/wasi-common/src/sys/unix/fd.rs index 5a84e51d5e..6e6d2f7064 100644 --- a/crates/wasi-common/src/sys/unix/fd.rs +++ b/crates/wasi-common/src/sys/unix/fd.rs @@ -1,7 +1,8 @@ use super::oshandle::RawOsHandle; use crate::sys::osdir::OsDir; use crate::sys::osfile::OsFile; -use crate::wasi::{self, types, Result}; +use crate::wasi::{self, types}; +use crate::Result; use std::convert::TryInto; use std::fs::File; use std::os::unix::prelude::AsRawFd; diff --git a/crates/wasi-common/src/sys/unix/linux/osdir.rs b/crates/wasi-common/src/sys/unix/linux/osdir.rs index c803178c6a..57350afbaa 100644 --- a/crates/wasi-common/src/sys/unix/linux/osdir.rs +++ b/crates/wasi-common/src/sys/unix/linux/osdir.rs @@ -1,6 +1,6 @@ use crate::handle::HandleRights; use crate::sys::sys_impl::oshandle::RawOsHandle; -use crate::wasi::Result; +use crate::Result; use std::cell::Cell; use std::io; use yanix::dir::Dir; diff --git a/crates/wasi-common/src/sys/unix/linux/path.rs b/crates/wasi-common/src/sys/unix/linux/path.rs index 1d441a3fa9..fb2249dc53 100644 --- a/crates/wasi-common/src/sys/unix/linux/path.rs +++ b/crates/wasi-common/src/sys/unix/linux/path.rs @@ -1,5 +1,5 @@ use crate::sys::osdir::OsDir; -use crate::wasi::Result; +use crate::Result; use std::os::unix::prelude::AsRawFd; pub(crate) fn unlink_file(dirfd: &OsDir, path: &str) -> Result<()> { diff --git a/crates/wasi-common/src/sys/unix/mod.rs b/crates/wasi-common/src/sys/unix/mod.rs index 9cf2129a23..d765faa95c 100644 --- a/crates/wasi-common/src/sys/unix/mod.rs +++ b/crates/wasi-common/src/sys/unix/mod.rs @@ -28,7 +28,8 @@ cfg_if::cfg_if! { use crate::handle::HandleRights; use crate::sys::AsFile; -use crate::wasi::{types, Errno, Result, RightsExt}; +use crate::wasi::{types, RightsExt}; +use crate::{Error, Result}; use std::convert::{TryFrom, TryInto}; use std::fs::File; use std::io; @@ -144,98 +145,6 @@ impl From for ClockId { } } -impl From for Errno { - fn from(err: io::Error) -> Self { - match err.raw_os_error() { - Some(code) => match code { - libc::EPERM => Self::Perm, - libc::ENOENT => Self::Noent, - libc::ESRCH => Self::Srch, - libc::EINTR => Self::Intr, - libc::EIO => Self::Io, - libc::ENXIO => Self::Nxio, - libc::E2BIG => Self::TooBig, - libc::ENOEXEC => Self::Noexec, - libc::EBADF => Self::Badf, - libc::ECHILD => Self::Child, - libc::EAGAIN => Self::Again, - libc::ENOMEM => Self::Nomem, - libc::EACCES => Self::Acces, - libc::EFAULT => Self::Fault, - libc::EBUSY => Self::Busy, - libc::EEXIST => Self::Exist, - libc::EXDEV => Self::Xdev, - libc::ENODEV => Self::Nodev, - libc::ENOTDIR => Self::Notdir, - libc::EISDIR => Self::Isdir, - libc::EINVAL => Self::Inval, - libc::ENFILE => Self::Nfile, - libc::EMFILE => Self::Mfile, - libc::ENOTTY => Self::Notty, - libc::ETXTBSY => Self::Txtbsy, - libc::EFBIG => Self::Fbig, - libc::ENOSPC => Self::Nospc, - libc::ESPIPE => Self::Spipe, - libc::EROFS => Self::Rofs, - libc::EMLINK => Self::Mlink, - libc::EPIPE => Self::Pipe, - libc::EDOM => Self::Dom, - libc::ERANGE => Self::Range, - libc::EDEADLK => Self::Deadlk, - libc::ENAMETOOLONG => Self::Nametoolong, - libc::ENOLCK => Self::Nolck, - libc::ENOSYS => Self::Nosys, - libc::ENOTEMPTY => Self::Notempty, - libc::ELOOP => Self::Loop, - libc::ENOMSG => Self::Nomsg, - libc::EIDRM => Self::Idrm, - libc::ENOLINK => Self::Nolink, - libc::EPROTO => Self::Proto, - libc::EMULTIHOP => Self::Multihop, - libc::EBADMSG => Self::Badmsg, - libc::EOVERFLOW => Self::Overflow, - libc::EILSEQ => Self::Ilseq, - libc::ENOTSOCK => Self::Notsock, - libc::EDESTADDRREQ => Self::Destaddrreq, - libc::EMSGSIZE => Self::Msgsize, - libc::EPROTOTYPE => Self::Prototype, - libc::ENOPROTOOPT => Self::Noprotoopt, - libc::EPROTONOSUPPORT => Self::Protonosupport, - libc::EAFNOSUPPORT => Self::Afnosupport, - libc::EADDRINUSE => Self::Addrinuse, - libc::EADDRNOTAVAIL => Self::Addrnotavail, - libc::ENETDOWN => Self::Netdown, - libc::ENETUNREACH => Self::Netunreach, - libc::ENETRESET => Self::Netreset, - libc::ECONNABORTED => Self::Connaborted, - libc::ECONNRESET => Self::Connreset, - libc::ENOBUFS => Self::Nobufs, - libc::EISCONN => Self::Isconn, - libc::ENOTCONN => Self::Notconn, - libc::ETIMEDOUT => Self::Timedout, - libc::ECONNREFUSED => Self::Connrefused, - libc::EHOSTUNREACH => Self::Hostunreach, - libc::EALREADY => Self::Already, - libc::EINPROGRESS => Self::Inprogress, - libc::ESTALE => Self::Stale, - libc::EDQUOT => Self::Dquot, - libc::ECANCELED => Self::Canceled, - libc::EOWNERDEAD => Self::Ownerdead, - libc::ENOTRECOVERABLE => Self::Notrecoverable, - libc::ENOTSUP => Self::Notsup, - x => { - tracing::debug!("Unknown errno value: {}", x); - Self::Io - } - }, - None => { - tracing::debug!("Other I/O error: {}", err); - Self::Io - } - } - } -} - impl From for OFlags { fn from(fdflags: types::Fdflags) -> Self { let mut nix_flags = Self::empty(); @@ -300,13 +209,13 @@ impl From for OFlags { } impl TryFrom for types::Filestat { - type Error = Errno; + type Error = Error; fn try_from(filestat: libc::stat) -> Result { fn filestat_to_timestamp(secs: u64, nsecs: u64) -> Result { secs.checked_mul(1_000_000_000) .and_then(|sec_nsec| sec_nsec.checked_add(nsecs)) - .ok_or(Errno::Overflow) + .ok_or(Error::Overflow) } let filetype = yanix::file::FileType::from_stat_st_mode(filestat.st_mode); diff --git a/crates/wasi-common/src/sys/unix/path.rs b/crates/wasi-common/src/sys/unix/path.rs index d109fe96f5..c2607447f9 100644 --- a/crates/wasi-common/src/sys/unix/path.rs +++ b/crates/wasi-common/src/sys/unix/path.rs @@ -1,7 +1,8 @@ use crate::handle::{Handle, HandleRights}; use crate::sys::osdir::OsDir; use crate::sys::AsFile; -use crate::wasi::{types, Errno, Result}; +use crate::wasi::types; +use crate::{Error, Result}; use std::convert::{TryFrom, TryInto}; use std::ffi::OsStr; use std::fs::File; @@ -147,7 +148,7 @@ pub(crate) fn open( match unsafe { fstatat(dirfd.as_raw_fd(), path, AtFlags::SYMLINK_NOFOLLOW) } { Ok(stat) => { if FileType::from_stat_st_mode(stat.st_mode) == FileType::Socket { - return Err(Errno::Notsup); + return Err(Error::Notsup); } } Err(err) => { @@ -166,7 +167,7 @@ pub(crate) fn open( match unsafe { fstatat(dirfd.as_raw_fd(), path, AtFlags::SYMLINK_NOFOLLOW) } { Ok(stat) => { if FileType::from_stat_st_mode(stat.st_mode) == FileType::Symlink { - return Err(Errno::Loop); + return Err(Error::Loop); } } Err(err) => { @@ -180,7 +181,7 @@ pub(crate) fn open( // FreeBSD returns EMLINK instead of ELOOP when using O_NOFOLLOW on // a symlink. libc::EMLINK if !(nix_all_oflags & OFlags::NOFOLLOW).is_empty() => { - return Err(Errno::Loop); + return Err(Error::Loop); } _ => {} } @@ -244,7 +245,7 @@ pub(crate) fn filestat_set_times_at( let set_mtim_now = fst_flags.contains(&types::Fstflags::MTIM_NOW); if (set_atim && set_atim_now) || (set_mtim && set_mtim_now) { - return Err(Errno::Inval); + return Err(Error::Inval); } let atim = if set_atim { diff --git a/crates/wasi-common/src/sys/unix/poll.rs b/crates/wasi-common/src/sys/unix/poll.rs index 022a2ba644..25f54405c4 100644 --- a/crates/wasi-common/src/sys/unix/poll.rs +++ b/crates/wasi-common/src/sys/unix/poll.rs @@ -1,7 +1,8 @@ use crate::entry::EntryHandle; use crate::poll::{ClockEventData, FdEventData}; use crate::sys::AsFile; -use crate::wasi::{types, Errno, Result}; +use crate::wasi::types; +use crate::{Error, Result}; use std::io; use std::{convert::TryInto, os::unix::prelude::AsRawFd}; use yanix::file::fionread; @@ -67,7 +68,7 @@ pub(crate) fn oneoff( fn handle_timeout_event(timeout: ClockEventData, events: &mut Vec) { events.push(types::Event { userdata: timeout.userdata, - error: Errno::Success, + error: types::Errno::Success, type_: types::Eventtype::Clock, fd_readwrite: types::EventFdReadwrite { flags: types::Eventrwflags::empty(), @@ -114,7 +115,7 @@ fn handle_fd_event( let output_event = if revents.contains(PollFlags::POLLNVAL) { types::Event { userdata: fd_event.userdata, - error: Errno::Badf, + error: Error::Badf.into(), type_: fd_event.r#type, fd_readwrite: types::EventFdReadwrite { nbytes: 0, @@ -124,7 +125,7 @@ fn handle_fd_event( } else if revents.contains(PollFlags::POLLERR) { types::Event { userdata: fd_event.userdata, - error: Errno::Io, + error: Error::Io.into(), type_: fd_event.r#type, fd_readwrite: types::EventFdReadwrite { nbytes: 0, @@ -134,7 +135,7 @@ fn handle_fd_event( } else if revents.contains(PollFlags::POLLHUP) { types::Event { userdata: fd_event.userdata, - error: Errno::Success, + error: types::Errno::Success, type_: fd_event.r#type, fd_readwrite: types::EventFdReadwrite { nbytes: 0, @@ -144,7 +145,7 @@ fn handle_fd_event( } else if revents.contains(PollFlags::POLLIN) | revents.contains(PollFlags::POLLOUT) { types::Event { userdata: fd_event.userdata, - error: Errno::Success, + error: types::Errno::Success, type_: fd_event.r#type, fd_readwrite: types::EventFdReadwrite { nbytes: nbytes.try_into()?, diff --git a/crates/wasi-common/src/sys/windows/clock.rs b/crates/wasi-common/src/sys/windows/clock.rs index e72820ad6d..28025247b0 100644 --- a/crates/wasi-common/src/sys/windows/clock.rs +++ b/crates/wasi-common/src/sys/windows/clock.rs @@ -1,4 +1,5 @@ -use crate::wasi::{types, Errno, Result}; +use crate::wasi::types; +use crate::{Error, Result}; use cpu_time::{ProcessTime, ThreadTime}; use lazy_static::lazy_static; use std::convert::TryInto; @@ -83,7 +84,7 @@ fn get_monotonic_time() -> Duration { fn get_realtime_time() -> Result { SystemTime::now() .duration_since(UNIX_EPOCH) - .map_err(|_| Errno::Fault) + .map_err(|_| Error::Fault) } fn get_proc_cputime() -> Result { diff --git a/crates/wasi-common/src/sys/windows/fd.rs b/crates/wasi-common/src/sys/windows/fd.rs index 15ccb3f5cd..5adfb74e30 100644 --- a/crates/wasi-common/src/sys/windows/fd.rs +++ b/crates/wasi-common/src/sys/windows/fd.rs @@ -4,7 +4,8 @@ use crate::path; use crate::sys::osdir::OsDir; use crate::sys::osfile::OsFile; use crate::sys::AsFile; -use crate::wasi::{types, Result}; +use crate::wasi::types; +use crate::Result; use std::convert::TryInto; use std::fs::{File, OpenOptions}; use std::os::windows::fs::OpenOptionsExt; diff --git a/crates/wasi-common/src/sys/windows/mod.rs b/crates/wasi-common/src/sys/windows/mod.rs index c3aa913a59..9d0e7ae9e3 100644 --- a/crates/wasi-common/src/sys/windows/mod.rs +++ b/crates/wasi-common/src/sys/windows/mod.rs @@ -10,7 +10,8 @@ pub(crate) mod stdio; use crate::handle::HandleRights; use crate::sys::AsFile; -use crate::wasi::{types, Errno, Result, RightsExt}; +use crate::wasi::{types, RightsExt}; +use crate::{Error, Result}; use std::convert::{TryFrom, TryInto}; use std::fs::File; use std::mem::ManuallyDrop; @@ -18,7 +19,6 @@ use std::os::windows::prelude::{AsRawHandle, FromRawHandle}; use std::path::Path; use std::time::{SystemTime, UNIX_EPOCH}; use std::{io, string}; -use winapi::shared::winerror; use winx::file::{CreationDisposition, Flags}; impl AsFile for T { @@ -106,47 +106,7 @@ pub(crate) fn file_serial_no(file: &File) -> io::Result { Ok(no) } -impl From for Errno { - fn from(err: io::Error) -> Self { - match err.raw_os_error() { - Some(code) => match code as u32 { - winerror::ERROR_SUCCESS => Self::Success, - winerror::ERROR_BAD_ENVIRONMENT => Self::TooBig, - winerror::ERROR_FILE_NOT_FOUND => Self::Noent, - winerror::ERROR_PATH_NOT_FOUND => Self::Noent, - winerror::ERROR_TOO_MANY_OPEN_FILES => Self::Nfile, - winerror::ERROR_ACCESS_DENIED => Self::Acces, - winerror::ERROR_SHARING_VIOLATION => Self::Acces, - winerror::ERROR_PRIVILEGE_NOT_HELD => Self::Notcapable, - winerror::ERROR_INVALID_HANDLE => Self::Badf, - winerror::ERROR_INVALID_NAME => Self::Noent, - winerror::ERROR_NOT_ENOUGH_MEMORY => Self::Nomem, - winerror::ERROR_OUTOFMEMORY => Self::Nomem, - winerror::ERROR_DIR_NOT_EMPTY => Self::Notempty, - winerror::ERROR_NOT_READY => Self::Busy, - winerror::ERROR_BUSY => Self::Busy, - winerror::ERROR_NOT_SUPPORTED => Self::Notsup, - winerror::ERROR_FILE_EXISTS => Self::Exist, - winerror::ERROR_BROKEN_PIPE => Self::Pipe, - winerror::ERROR_BUFFER_OVERFLOW => Self::Nametoolong, - winerror::ERROR_NOT_A_REPARSE_POINT => Self::Inval, - winerror::ERROR_NEGATIVE_SEEK => Self::Inval, - winerror::ERROR_DIRECTORY => Self::Notdir, - winerror::ERROR_ALREADY_EXISTS => Self::Exist, - x => { - tracing::debug!("winerror: unknown error value: {}", x); - Self::Io - } - }, - None => { - tracing::debug!("Other I/O error: {}", err); - Self::Io - } - } - } -} - -impl From for Errno { +impl From for Error { fn from(_err: string::FromUtf16Error) -> Self { Self::Ilseq } @@ -166,14 +126,14 @@ fn change_time(file: &File) -> io::Result { fn systemtime_to_timestamp(st: SystemTime) -> Result { st.duration_since(UNIX_EPOCH) - .map_err(|_| Errno::Inval)? // date earlier than UNIX_EPOCH + .map_err(|_| Error::Inval)? // date earlier than UNIX_EPOCH .as_nanos() .try_into() .map_err(Into::into) // u128 doesn't fit into u64 } impl TryFrom<&File> for types::Filestat { - type Error = Errno; + type Error = Error; fn try_from(file: &File) -> Result { let metadata = file.metadata()?; diff --git a/crates/wasi-common/src/sys/windows/path.rs b/crates/wasi-common/src/sys/windows/path.rs index 89252d3d00..815b5f32d5 100644 --- a/crates/wasi-common/src/sys/windows/path.rs +++ b/crates/wasi-common/src/sys/windows/path.rs @@ -1,7 +1,8 @@ use crate::handle::{Handle, HandleRights}; use crate::sys::osdir::OsDir; use crate::sys::{fd, AsFile}; -use crate::wasi::{types, Errno, Result}; +use crate::wasi::types; +use crate::{Error, Result}; use std::convert::TryFrom; use std::ffi::{OsStr, OsString}; use std::fs::{self, Metadata, OpenOptions}; @@ -35,7 +36,7 @@ fn concatenate>(file: &OsDir, path: P) -> Result { // WASI is not able to deal with absolute paths // so error out if absolute if path.as_ref().is_absolute() { - return Err(Errno::Notcapable); + return Err(Error::Notcapable); } let dir_path = get_file_path(&*file.as_file()?)?; @@ -131,8 +132,8 @@ pub(crate) fn readlinkat(dirfd: &OsDir, s_path: &str) -> Result { let dir_path = PathBuf::from(strip_extended_prefix(dir_path)); let target_path = target_path .strip_prefix(dir_path) - .map_err(|_| Errno::Notcapable)?; - let target_path = target_path.to_str().ok_or(Errno::Ilseq)?; + .map_err(|_| Error::Notcapable)?; + let target_path = target_path.to_str().ok_or(Error::Ilseq)?; return Ok(target_path.to_owned()); } Err(e) => e, @@ -144,7 +145,7 @@ pub(crate) fn readlinkat(dirfd: &OsDir, s_path: &str) -> Result { // strip "/" and check if exists let path = concatenate(dirfd, Path::new(s_path.trim_end_matches('/')))?; if path.exists() && !path.is_dir() { - return Err(Errno::Notdir); + return Err(Error::Notdir); } } } @@ -178,7 +179,7 @@ pub(crate) fn link( // fs::canonicalize under Windows will return: // * ERROR_FILE_NOT_FOUND, if it encounters a dangling symlink // * ERROR_CANT_RESOLVE_FILENAME, if it encounters a symlink loop - Some(code) if code as u32 == winerror::ERROR_CANT_RESOLVE_FILENAME => Errno::Loop, + Some(code) if code as u32 == winerror::ERROR_CANT_RESOLVE_FILENAME => Error::Loop, _ => e.into(), })?; } @@ -193,7 +194,7 @@ pub(crate) fn link( // implementations of link return `EPERM`, but `ERROR_ACCESS_DENIED` is converted // to `EACCES`. We detect and correct this case here. if fs::metadata(&old_path).map(|m| m.is_dir()).unwrap_or(false) { - return Err(Errno::Perm); + return Err(Error::Perm); } } } @@ -217,7 +218,7 @@ pub(crate) fn open( // This is because truncation requires `GENERIC_WRITE` access, which will override the removal // of the `FILE_WRITE_DATA` permission. if fdflags.contains(&types::Fdflags::APPEND) { - return Err(Errno::Notsup); + return Err(Error::Notsup); } } @@ -242,11 +243,11 @@ pub(crate) fn open( Ok(file_type) => { // check if we are trying to open a symlink if file_type.is_symlink() { - return Err(Errno::Loop); + return Err(Error::Loop); } // check if we are trying to open a file as a dir if file_type.is_file() && oflags.contains(&types::Oflags::DIRECTORY) { - return Err(Errno::Notdir); + return Err(Error::Notdir); } } Err(err) => match err.raw_os_error() { @@ -260,14 +261,14 @@ pub(crate) fn open( winerror::ERROR_INVALID_NAME => { // TODO rethink this. For now, migrate how we handled // it in `path::openat` on Windows. - return Err(Errno::Notdir); + return Err(Error::Notdir); } _ => return Err(err.into()), }; } None => { tracing::debug!("Inconvertible OS error: {}", err); - return Err(Errno::Io); + return Err(Error::Io); } }, } @@ -302,8 +303,8 @@ pub(crate) fn readlink(dirfd: &OsDir, path: &str, buf: &mut [u8]) -> Result 0 { let mut chars = target_path.chars(); @@ -341,12 +342,12 @@ pub(crate) fn rename( // // [std::fs::rename]: https://doc.rust-lang.org/std/fs/fn.rename.html if old_path.is_dir() && new_path.is_file() { - return Err(Errno::Notdir); + return Err(Error::Notdir); } // Second sanity check: check we're not trying to rename a file into a path // ending in a trailing slash. if old_path.is_file() && new_path_.ends_with('/') { - return Err(Errno::Notdir); + return Err(Error::Notdir); } // TODO handle symlinks @@ -362,7 +363,7 @@ pub(crate) fn rename( // So most likely dealing with new_path == dir. // Eliminate case old_path == file first. if old_path.is_file() { - return Err(Errno::Isdir); + return Err(Error::Isdir); } else { // Ok, let's try removing an empty dir at new_path if it exists // and is a nonempty dir. @@ -378,7 +379,7 @@ pub(crate) fn rename( strip_trailing_slashes_and_concatenate(old_dirfd, old_path_)? { if path.is_file() { - return Err(Errno::Notdir); + return Err(Error::Notdir); } } } @@ -389,7 +390,7 @@ pub(crate) fn rename( } None => { tracing::debug!("Inconvertible OS error: {}", err); - Err(Errno::Io) + Err(Error::Io) } } } @@ -435,7 +436,7 @@ pub(crate) fn symlink(old_path: &str, new_dirfd: &OsDir, new_path_: &str) -> Res strip_trailing_slashes_and_concatenate(new_dirfd, new_path_)? { if path.exists() { - return Err(Errno::Exist); + return Err(Error::Exist); } } } @@ -446,7 +447,7 @@ pub(crate) fn symlink(old_path: &str, new_dirfd: &OsDir, new_path_: &str) -> Res } None => { tracing::debug!("Inconvertible OS error: {}", err); - Err(Errno::Io) + Err(Error::Io) } } } @@ -481,15 +482,15 @@ pub(crate) fn unlink_file(dirfd: &OsDir, path: &str) -> Result<()> { } None => { tracing::debug!("Inconvertible OS error: {}", err); - Err(Errno::Io) + Err(Error::Io) } } } else if file_type.is_dir() { - Err(Errno::Isdir) + Err(Error::Isdir) } else if file_type.is_file() { fs::remove_file(path).map_err(Into::into) } else { - Err(Errno::Inval) + Err(Error::Inval) } } diff --git a/crates/wasi-common/src/sys/windows/poll.rs b/crates/wasi-common/src/sys/windows/poll.rs index f467059b11..da48b15908 100644 --- a/crates/wasi-common/src/sys/windows/poll.rs +++ b/crates/wasi-common/src/sys/windows/poll.rs @@ -5,7 +5,8 @@ use crate::sys::osfile::OsFile; use crate::sys::osother::OsOther; use crate::sys::stdio::{Stderr, Stdin, Stdout}; use crate::sys::AsFile; -use crate::wasi::{types, Errno, Result}; +use crate::wasi::types; +use crate::{Error, Result}; use lazy_static::lazy_static; use std::convert::TryInto; use std::sync::mpsc::{self, Receiver, RecvTimeoutError, Sender, TryRecvError}; @@ -23,7 +24,7 @@ enum PollState { Ready, NotReady, // it's not ready, but we didn't wait TimedOut, // it's not ready and a timeout has occurred - Error(Errno), + Error(types::Errno), } enum WaitMode { @@ -79,7 +80,7 @@ impl StdinPoll { // Linux returns `POLLIN` in both cases, and we imitate this behavior. let resp = match std::io::stdin().lock().fill_buf() { Ok(_) => PollState::Ready, - Err(e) => PollState::Error(Errno::from(e)), + Err(e) => PollState::Error(types::Errno::from(Error::from(e))), }; // Notify the requestor about data in stdin. They may have already timed out, @@ -101,9 +102,12 @@ lazy_static! { }; } -fn make_rw_event(event: &FdEventData, nbytes: Result) -> types::Event { +fn make_rw_event( + event: &FdEventData, + nbytes: std::result::Result, +) -> types::Event { let (nbytes, error) = match nbytes { - Ok(nbytes) => (nbytes, Errno::Success), + Ok(nbytes) => (nbytes, types::Errno::Success), Err(e) => (u64::default(), e), }; types::Event { @@ -121,7 +125,7 @@ fn make_timeout_event(timeout: &ClockEventData) -> types::Event { types::Event { userdata: timeout.userdata, type_: types::Eventtype::Clock, - error: Errno::Success, + error: types::Errno::Success, fd_readwrite: types::EventFdReadwrite { nbytes: 0, flags: types::Eventrwflags::empty(), @@ -160,7 +164,7 @@ fn handle_rw_event(event: FdEventData, out_events: &mut Vec) { .as_file() .and_then(|f| f.metadata()) .map(|m| m.len()) - .map_err(Into::into) + .map_err(|ioerror| types::Errno::from(Error::from(ioerror))) } else { // The spec is unclear what nbytes should actually be for __WASI_EVENTTYPE_FD_WRITE and // the implementation on Unix just returns 0 here, so it's probably fine @@ -173,7 +177,7 @@ fn handle_rw_event(event: FdEventData, out_events: &mut Vec) { out_events.push(new_event); } -fn handle_error_event(event: FdEventData, error: Errno, out_events: &mut Vec) { +fn handle_error_event(event: FdEventData, error: types::Errno, out_events: &mut Vec) { let new_event = make_rw_event(&event, Err(error)); out_events.push(new_event); } @@ -238,11 +242,11 @@ pub(crate) fn oneoff( "poll_oneoff: unsupported file type: {}", other.get_file_type() ); - handle_error_event(event, Errno::Notsup, events); + handle_error_event(event, types::Errno::Notsup, events); } } else { tracing::error!("can poll FdEvent for OS resources only"); - return Err(Errno::Badf); + return Err(Error::Badf); } } @@ -306,7 +310,7 @@ pub(crate) fn oneoff( } None => { error!("Polling only pipes with no timeout not supported on Windows."); - return Err(Errno::Notsup); + return Err(Error::Notsup); } } } diff --git a/crates/wasi-common/src/virtfs.rs b/crates/wasi-common/src/virtfs.rs index 9e543a3d24..520bab6ad6 100644 --- a/crates/wasi-common/src/virtfs.rs +++ b/crates/wasi-common/src/virtfs.rs @@ -1,5 +1,6 @@ use crate::handle::{Handle, HandleRights}; -use crate::wasi::{self, types, Errno, Result, RightsExt}; +use crate::wasi::{self, types, RightsExt}; +use crate::{Error, Result}; use std::any::Any; use std::cell::{Cell, RefCell}; use std::collections::hash_map::Entry; @@ -70,7 +71,7 @@ impl FileContents for VecFileContents { } fn resize(&mut self, new_size: types::Filesize) -> Result<()> { - let new_size: usize = new_size.try_into().map_err(|_| Errno::Inval)?; + let new_size: usize = new_size.try_into().map_err(|_| Error::Inval)?; self.content.resize(new_size, 0); Ok(()) } @@ -78,7 +79,7 @@ impl FileContents for VecFileContents { fn preadv(&self, iovs: &mut [io::IoSliceMut], offset: types::Filesize) -> Result { let mut read_total = 0usize; for iov in iovs.iter_mut() { - let skip: u64 = read_total.try_into().map_err(|_| Errno::Inval)?; + let skip: u64 = read_total.try_into().map_err(|_| Error::Inval)?; let read = self.pread(iov, offset + skip)?; read_total = read_total.checked_add(read).expect("FileContents::preadv must not be called when reads could total to more bytes than the return value can hold"); } @@ -88,7 +89,7 @@ impl FileContents for VecFileContents { fn pwritev(&mut self, iovs: &[io::IoSlice], offset: types::Filesize) -> Result { let mut write_total = 0usize; for iov in iovs.iter() { - let skip: u64 = write_total.try_into().map_err(|_| Errno::Inval)?; + let skip: u64 = write_total.try_into().map_err(|_| Error::Inval)?; let written = self.pwrite(iov, offset + skip)?; write_total = write_total.checked_add(written).expect("FileContents::pwritev must not be called when writes could total to more bytes than the return value can hold"); } @@ -97,7 +98,7 @@ impl FileContents for VecFileContents { fn pread(&self, buf: &mut [u8], offset: types::Filesize) -> Result { trace!(buffer_length = buf.len(), offset = offset, "pread"); - let offset: usize = offset.try_into().map_err(|_| Errno::Inval)?; + let offset: usize = offset.try_into().map_err(|_| Error::Inval)?; let data_remaining = self.content.len().saturating_sub(offset); @@ -109,9 +110,9 @@ impl FileContents for VecFileContents { } fn pwrite(&mut self, buf: &[u8], offset: types::Filesize) -> Result { - let offset: usize = offset.try_into().map_err(|_| Errno::Inval)?; + let offset: usize = offset.try_into().map_err(|_| Error::Inval)?; - let write_end = offset.checked_add(buf.len()).ok_or(Errno::Fbig)?; + let write_end = offset.checked_add(buf.len()).ok_or(Error::Fbig)?; if write_end > self.content.len() { self.content.resize(write_end, 0); @@ -206,11 +207,11 @@ impl Handle for InMemoryFile { Ok(()) } fn allocate(&self, offset: types::Filesize, len: types::Filesize) -> Result<()> { - let new_limit = offset.checked_add(len).ok_or(Errno::Fbig)?; + let new_limit = offset.checked_add(len).ok_or(Error::Fbig)?; let mut data = self.data.borrow_mut(); if new_limit > data.max_size() { - return Err(Errno::Fbig); + return Err(Error::Fbig); } if new_limit > data.size() { @@ -242,7 +243,7 @@ impl Handle for InMemoryFile { fn filestat_set_size(&self, st_size: types::Filesize) -> Result<()> { let mut data = self.data.borrow_mut(); if st_size > data.max_size() { - return Err(Errno::Fbig); + return Err(Error::Fbig); } data.resize(st_size) } @@ -256,8 +257,8 @@ impl Handle for InMemoryFile { trace!("read_vectored(iovs={:?})", iovs); trace!(" | *read_start={:?}", self.cursor.get()); let read = self.data.borrow_mut().preadv(iovs, self.cursor.get())?; - let offset: u64 = read.try_into().map_err(|_| Errno::Inval)?; - let update = self.cursor.get().checked_add(offset).ok_or(Errno::Inval)?; + let offset: u64 = read.try_into().map_err(|_| Error::Inval)?; + let update = self.cursor.get().checked_add(offset).ok_or(Error::Inval)?; self.cursor.set(update); Ok(read) } @@ -269,23 +270,23 @@ impl Handle for InMemoryFile { self.cursor .get() .checked_sub(offset.wrapping_neg() as u64) - .ok_or(Errno::Inval)? + .ok_or(Error::Inval)? } else { self.cursor .get() .checked_add(offset as u64) - .ok_or(Errno::Inval)? + .ok_or(Error::Inval)? }; self.cursor.set(std::cmp::min(content_len, new_cursor)); } SeekFrom::End(offset) => { // A negative offset from the end would be past the end of the file, - let offset: u64 = offset.try_into().map_err(|_| Errno::Inval)?; + let offset: u64 = offset.try_into().map_err(|_| Error::Inval)?; self.cursor.set(content_len.saturating_sub(offset)); } SeekFrom::Start(offset) => { // A negative offset from the end would be before the start of the file. - let offset: u64 = offset.try_into().map_err(|_| Errno::Inval)?; + let offset: u64 = offset.try_into().map_err(|_| Error::Inval)?; self.cursor.set(std::cmp::min(content_len, offset)); } } @@ -320,10 +321,10 @@ impl Handle for InMemoryFile { if let Some(end) = write_start.checked_add(max_size as types::Filesize) { if end > data.max_size() { - return Err(Errno::Fbig); + return Err(Error::Fbig); } } else { - return Err(Errno::Fbig); + return Err(Error::Fbig); } trace!(" | *write_start={:?}", write_start); @@ -340,7 +341,7 @@ impl Handle for InMemoryFile { } // PathOps fn create_directory(&self, _path: &str) -> Result<()> { - Err(Errno::Notdir) + Err(Error::Notdir) } fn openat( &self, @@ -355,7 +356,7 @@ impl Handle for InMemoryFile { "InMemoryFile::openat was passed oflags DIRECTORY, but {:?} is a file.", path ); - return Err(Errno::Notdir); + return Err(Error::Notdir); } if path == "." { @@ -366,7 +367,7 @@ impl Handle for InMemoryFile { None => self.try_clone().map_err(Into::into), } } else { - Err(Errno::Acces) + Err(Error::Acces) } } fn link( @@ -376,25 +377,25 @@ impl Handle for InMemoryFile { _new_path: &str, _follow: bool, ) -> Result<()> { - Err(Errno::Notdir) + Err(Error::Notdir) } fn readlink(&self, _path: &str, _buf: &mut [u8]) -> Result { - Err(Errno::Notdir) + Err(Error::Notdir) } fn readlinkat(&self, _path: &str) -> Result { - Err(Errno::Notdir) + Err(Error::Notdir) } fn rename(&self, _old_path: &str, _new_handle: Box, _new_path: &str) -> Result<()> { - Err(Errno::Notdir) + Err(Error::Notdir) } fn remove_directory(&self, _path: &str) -> Result<()> { - Err(Errno::Notdir) + Err(Error::Notdir) } fn symlink(&self, _old_path: &str, _new_path: &str) -> Result<()> { - Err(Errno::Notdir) + Err(Error::Notdir) } fn unlink_file(&self, _path: &str) -> Result<()> { - Err(Errno::Notdir) + Err(Error::Notdir) } } @@ -587,7 +588,7 @@ impl Handle for VirtualDir { fn create_directory(&self, path: &str) -> Result<()> { let mut entries = self.entries.borrow_mut(); match entries.entry(PathBuf::from(path)) { - Entry::Occupied(_) => Err(Errno::Exist), + Entry::Occupied(_) => Err(Error::Exist), Entry::Vacant(v) => { if self.writable { let new_dir = Box::new(Self::new(true)); @@ -595,7 +596,7 @@ impl Handle for VirtualDir { v.insert(new_dir); Ok(()) } else { - Err(Errno::Acces) + Err(Error::Acces) } } } @@ -653,7 +654,7 @@ impl Handle for VirtualDir { // openat may have been passed a path with a trailing slash, but files are mapped to paths // with trailing slashes normalized out. - let file_name = Path::new(path).file_name().ok_or(Errno::Inval)?; + let file_name = Path::new(path).file_name().ok_or(Error::Inval)?; let mut entries = self.entries.borrow_mut(); let entry_count = entries.len(); match entries.entry(Path::new(file_name).to_path_buf()) { @@ -661,7 +662,7 @@ impl Handle for VirtualDir { let creat_excl_mask = types::Oflags::CREAT | types::Oflags::EXCL; if (oflags & creat_excl_mask) == creat_excl_mask { tracing::trace!("VirtualDir::openat was passed oflags CREAT|EXCL, but the file {:?} exists.", file_name); - return Err(Errno::Exist); + return Err(Error::Exist); } if oflags.contains(&types::Oflags::DIRECTORY) @@ -671,7 +672,7 @@ impl Handle for VirtualDir { "VirtualDir::openat was passed oflags DIRECTORY, but {:?} is a file.", file_name ); - return Err(Errno::Notdir); + return Err(Error::Notdir); } e.get().try_clone().map_err(Into::into) @@ -683,7 +684,7 @@ impl Handle for VirtualDir { // would have with `usize`. The limit is the full `u32` range minus two so we // can reserve "self" and "parent" cookie values. if entry_count >= (std::u32::MAX - RESERVED_ENTRY_COUNT) as usize { - return Err(Errno::Nospc); + return Err(Error::Nospc); } tracing::trace!("VirtualDir::openat creating an InMemoryFile named {}", path); @@ -693,14 +694,14 @@ impl Handle for VirtualDir { file.set_parent(Some(self.try_clone().expect("can clone self"))); v.insert(file).try_clone().map_err(Into::into) } else { - Err(Errno::Acces) + Err(Error::Acces) } } } } fn readlinkat(&self, _path: &str) -> Result { // Files are not symbolic links or directories, faithfully report Notdir. - Err(Errno::Notdir) + Err(Error::Notdir) } fn remove_directory(&self, path: &str) -> Result<()> { let trimmed_path = path.trim_end_matches('/'); @@ -709,13 +710,13 @@ impl Handle for VirtualDir { Entry::Occupied(e) => { // first, does this name a directory? if e.get().get_file_type() != types::Filetype::Directory { - return Err(Errno::Notdir); + return Err(Error::Notdir); } // Okay, but is the directory empty? let iter = e.get().readdir(wasi::DIRCOOKIE_START)?; if iter.skip(RESERVED_ENTRY_COUNT as usize).next().is_some() { - return Err(Errno::Notempty); + return Err(Error::Notempty); } // Alright, it's an empty directory. We can remove it. @@ -738,7 +739,7 @@ impl Handle for VirtualDir { "VirtualDir::remove_directory failed to remove {}, no such entry", trimmed_path ); - Err(Errno::Noent) + Err(Error::Noent) } } } @@ -749,7 +750,7 @@ impl Handle for VirtualDir { // fail with Isdir, since this is a directory. Alternatively, we may be unlinking `".."`, // which is bound the same way, as this is by definition contained in a directory. if trimmed_path == "." || trimmed_path == ".." { - return Err(Errno::Isdir); + return Err(Error::Isdir); } let mut entries = self.entries.borrow_mut(); @@ -757,7 +758,7 @@ impl Handle for VirtualDir { Entry::Occupied(e) => { // Directories must be removed through `remove_directory`, not `unlink_file`. if e.get().get_file_type() == types::Filetype::Directory { - return Err(Errno::Isdir); + return Err(Error::Isdir); } let removed = e.remove_entry(); @@ -779,7 +780,7 @@ impl Handle for VirtualDir { "VirtualDir::unlink_file failed to remove {}, no such entry", trimmed_path ); - Err(Errno::Noent) + Err(Error::Noent) } } } diff --git a/crates/wasi-common/src/virtfs/pipe.rs b/crates/wasi-common/src/virtfs/pipe.rs index ef253b72ae..87551e37f5 100644 --- a/crates/wasi-common/src/virtfs/pipe.rs +++ b/crates/wasi-common/src/virtfs/pipe.rs @@ -10,7 +10,8 @@ //! Note that `poll_oneoff` is not supported for these types, so they do not match the behavior of //! real pipes exactly. use crate::handle::{Handle, HandleRights}; -use crate::wasi::{types, Errno, Result}; +use crate::wasi::types; +use crate::{Error, Result}; use std::any::Any; use std::io::{self, Read, Write}; use std::sync::{Arc, RwLock}; @@ -132,11 +133,11 @@ impl Handle for ReadPipe { _offset: types::Filesize, _len: types::Filesize, ) -> Result<()> { - Err(Errno::Spipe) + Err(Error::Spipe) } fn allocate(&self, _offset: types::Filesize, _len: types::Filesize) -> Result<()> { - Err(Errno::Spipe) + Err(Error::Spipe) } fn fdstat_set_flags(&self, _fdflags: types::Fdflags) -> Result<()> { @@ -159,18 +160,18 @@ impl Handle for ReadPipe { } fn filestat_set_size(&self, _st_size: types::Filesize) -> Result<()> { - Err(Errno::Spipe) + Err(Error::Spipe) } fn preadv(&self, buf: &mut [io::IoSliceMut], offset: types::Filesize) -> Result { if offset != 0 { - return Err(Errno::Spipe); + return Err(Error::Spipe); } Ok(self.reader.write().unwrap().read_vectored(buf)?) } fn seek(&self, _offset: io::SeekFrom) -> Result { - Err(Errno::Spipe) + Err(Error::Spipe) } fn read_vectored(&self, iovs: &mut [io::IoSliceMut]) -> Result { @@ -178,7 +179,7 @@ impl Handle for ReadPipe { } fn create_directory(&self, _path: &str) -> Result<()> { - Err(Errno::Notdir) + Err(Error::Notdir) } fn openat( @@ -189,7 +190,7 @@ impl Handle for ReadPipe { _oflags: types::Oflags, _fd_flags: types::Fdflags, ) -> Result> { - Err(Errno::Notdir) + Err(Error::Notdir) } fn link( @@ -199,31 +200,31 @@ impl Handle for ReadPipe { _new_path: &str, _follow: bool, ) -> Result<()> { - Err(Errno::Notdir) + Err(Error::Notdir) } fn readlink(&self, _path: &str, _buf: &mut [u8]) -> Result { - Err(Errno::Notdir) + Err(Error::Notdir) } fn readlinkat(&self, _path: &str) -> Result { - Err(Errno::Notdir) + Err(Error::Notdir) } fn rename(&self, _old_path: &str, _new_handle: Box, _new_path: &str) -> Result<()> { - Err(Errno::Notdir) + Err(Error::Notdir) } fn remove_directory(&self, _path: &str) -> Result<()> { - Err(Errno::Notdir) + Err(Error::Notdir) } fn symlink(&self, _old_path: &str, _new_path: &str) -> Result<()> { - Err(Errno::Notdir) + Err(Error::Notdir) } fn unlink_file(&self, _path: &str) -> Result<()> { - Err(Errno::Notdir) + Err(Error::Notdir) } } @@ -317,11 +318,11 @@ impl Handle for WritePipe { _offset: types::Filesize, _len: types::Filesize, ) -> Result<()> { - Err(Errno::Spipe) + Err(Error::Spipe) } fn allocate(&self, _offset: types::Filesize, _len: types::Filesize) -> Result<()> { - Err(Errno::Spipe) + Err(Error::Spipe) } fn fdstat_set_flags(&self, _fdflags: types::Fdflags) -> Result<()> { @@ -344,18 +345,18 @@ impl Handle for WritePipe { } fn filestat_set_size(&self, _st_size: types::Filesize) -> Result<()> { - Err(Errno::Spipe) + Err(Error::Spipe) } fn pwritev(&self, buf: &[io::IoSlice], offset: types::Filesize) -> Result { if offset != 0 { - return Err(Errno::Spipe); + return Err(Error::Spipe); } Ok(self.writer.write().unwrap().write_vectored(buf)?) } fn seek(&self, _offset: io::SeekFrom) -> Result { - Err(Errno::Spipe) + Err(Error::Spipe) } fn write_vectored(&self, iovs: &[io::IoSlice]) -> Result { @@ -363,7 +364,7 @@ impl Handle for WritePipe { } fn create_directory(&self, _path: &str) -> Result<()> { - Err(Errno::Notdir) + Err(Error::Notdir) } fn openat( @@ -374,7 +375,7 @@ impl Handle for WritePipe { _oflags: types::Oflags, _fd_flags: types::Fdflags, ) -> Result> { - Err(Errno::Notdir) + Err(Error::Notdir) } fn link( @@ -384,30 +385,30 @@ impl Handle for WritePipe { _new_path: &str, _follow: bool, ) -> Result<()> { - Err(Errno::Notdir) + Err(Error::Notdir) } fn readlink(&self, _path: &str, _buf: &mut [u8]) -> Result { - Err(Errno::Notdir) + Err(Error::Notdir) } fn readlinkat(&self, _path: &str) -> Result { - Err(Errno::Notdir) + Err(Error::Notdir) } fn rename(&self, _old_path: &str, _new_handle: Box, _new_path: &str) -> Result<()> { - Err(Errno::Notdir) + Err(Error::Notdir) } fn remove_directory(&self, _path: &str) -> Result<()> { - Err(Errno::Notdir) + Err(Error::Notdir) } fn symlink(&self, _old_path: &str, _new_path: &str) -> Result<()> { - Err(Errno::Notdir) + Err(Error::Notdir) } fn unlink_file(&self, _path: &str) -> Result<()> { - Err(Errno::Notdir) + Err(Error::Notdir) } } diff --git a/crates/wasi-common/src/wasi.rs b/crates/wasi-common/src/wasi.rs index f8b4aab780..e87ac2fec9 100644 --- a/crates/wasi-common/src/wasi.rs +++ b/crates/wasi-common/src/wasi.rs @@ -1,15 +1,13 @@ -//! Types and constants shared between 32-bit and 64-bit wasi. Types involving -//! pointer or `usize`-sized data are excluded here, so this file only contains -//! fixed-size types, so it's host/target independent. -use crate::WasiCtx; +use crate::{Error, Result, WasiCtx}; +use tracing::debug; wiggle::from_witx!({ witx: ["$WASI_ROOT/phases/snapshot/witx/wasi_snapshot_preview1.witx"], ctx: WasiCtx, + errors: { errno => Error }, }); -pub use types::Errno; -pub type Result = std::result::Result; +use types::Errno; impl wiggle::GuestErrorType for Errno { fn success() -> Self { @@ -19,9 +17,54 @@ impl wiggle::GuestErrorType for Errno { impl types::GuestErrorConversion for WasiCtx { fn into_errno(&self, e: wiggle::GuestError) -> Errno { - eprintln!("Guest error: {:?}", e); - // TODO proper error mapping - Errno::Inval + debug!("Guest error: {:?}", e); + e.into() + } +} + +impl types::UserErrorConversion for WasiCtx { + fn errno_from_error(&self, e: Error) -> Errno { + debug!("Error: {:?}", e); + e.into() + } +} + +impl From for Errno { + fn from(e: Error) -> Errno { + match e { + Error::Guest(e) => e.into(), + Error::TryFromInt(_) => Errno::Overflow, + Error::Utf8(_) => Errno::Ilseq, + Error::UnexpectedIo(_) => Errno::Io, + Error::GetRandom(_) => Errno::Io, + Error::TooBig => Errno::TooBig, + Error::Acces => Errno::Acces, + Error::Badf => Errno::Badf, + Error::Busy => Errno::Busy, + Error::Exist => Errno::Exist, + Error::Fault => Errno::Fault, + Error::Fbig => Errno::Fbig, + Error::Ilseq => Errno::Ilseq, + Error::Inval => Errno::Inval, + Error::Io => Errno::Io, + Error::Isdir => Errno::Isdir, + Error::Loop => Errno::Loop, + Error::Mfile => Errno::Mfile, + Error::Mlink => Errno::Mlink, + Error::Nametoolong => Errno::Nametoolong, + Error::Nfile => Errno::Nfile, + Error::Noent => Errno::Noent, + Error::Nomem => Errno::Nomem, + Error::Nospc => Errno::Nospc, + Error::Notdir => Errno::Notdir, + Error::Notempty => Errno::Notempty, + Error::Notsup => Errno::Notsup, + Error::Overflow => Errno::Overflow, + Error::Pipe => Errno::Pipe, + Error::Perm => Errno::Perm, + Error::Spipe => Errno::Spipe, + Error::Notcapable => Errno::Notcapable, + } } } @@ -45,24 +88,6 @@ impl From for Errno { } } -impl From for Errno { - fn from(_err: std::convert::Infallible) -> Self { - unreachable!() - } -} - -impl From for Errno { - fn from(_err: std::num::TryFromIntError) -> Self { - Self::Overflow - } -} - -impl From for Errno { - fn from(_err: std::str::Utf8Error) -> Self { - Self::Ilseq - } -} - impl From for types::Filetype { fn from(ftype: std::fs::FileType) -> Self { if ftype.is_file() { diff --git a/crates/wasi/src/lib.rs b/crates/wasi/src/lib.rs index 1e812ba033..fc6c924313 100644 --- a/crates/wasi/src/lib.rs +++ b/crates/wasi/src/lib.rs @@ -33,7 +33,7 @@ resolution.", }, }, // Error to return when caller module is missing memory export: - missing_memory: { wasi_common::wasi::Errno::Inval }, + missing_memory: { wasi_common::wasi::types::Errno::Inval }, }); pub fn is_wasi_module(name: &str) -> bool {