Merge pull request #2140 from bytecodealliance/pch/wasi_error_handling

wasi-common: refactor error types
This commit is contained in:
Pat Hickey
2020-09-01 13:01:26 -07:00
committed by GitHub
34 changed files with 511 additions and 407 deletions

View File

@@ -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" }

View File

@@ -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<Rc<Entry>> {
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<types::Fd> {
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<Rc<Entry>> {
self.entries.borrow_mut().remove(fd).ok_or(Errno::Badf)
self.entries.borrow_mut().remove(fd).ok_or(Error::Badf)
}
}

View File

@@ -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<EntryHandle> {
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)
}
}
}

View File

@@ -0,0 +1,195 @@
use cfg_if::cfg_if;
use thiserror::Error;
pub type Result<T> = std::result::Result<T, Error>;
/// 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<std::convert::Infallible> for Error {
fn from(_err: std::convert::Infallible) -> Self {
unreachable!("should be impossible: From<Infallible>")
}
}
// 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<io::Error> 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<io::Error> 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)
}
}
}
}
}
}

View File

@@ -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;

View File

@@ -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<types::Fdflags> {
Ok(types::Fdflags::empty())
}
fn fdstat_set_flags(&self, _fdflags: types::Fdflags) -> Result<()> {
Err(Errno::Badf)
Err(Error::Badf)
}
fn filestat_get(&self) -> Result<types::Filestat> {
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<usize> {
Err(Errno::Badf)
Err(Error::Badf)
}
fn pwritev(&self, _buf: &[io::IoSlice], _offset: u64) -> Result<usize> {
Err(Errno::Badf)
Err(Error::Badf)
}
fn read_vectored(&self, _iovs: &mut [io::IoSliceMut]) -> Result<usize> {
Err(Errno::Badf)
Err(Error::Badf)
}
fn readdir<'a>(
&'a self,
_cookie: types::Dircookie,
) -> Result<Box<dyn Iterator<Item = Result<(types::Dirent, String)>> + 'a>> {
Err(Errno::Badf)
Err(Error::Badf)
}
fn seek(&self, _offset: SeekFrom) -> Result<u64> {
Err(Errno::Badf)
Err(Error::Badf)
}
fn sync(&self) -> Result<()> {
Ok(())
}
fn write_vectored(&self, _iovs: &[io::IoSlice]) -> Result<usize> {
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<types::Filestat> {
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<Box<dyn Handle>> {
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<usize> {
Err(Errno::Acces)
Err(Error::Acces)
}
fn readlinkat(&self, _path: &str) -> Result<String> {
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<dyn Handle>, _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)
}
}

View File

@@ -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;

View File

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

View File

@@ -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<types::Prestat> {
// 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<types::Size> {
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<u8>, 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(

View File

@@ -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<u128> {
}
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))

View File

@@ -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);

View File

@@ -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::<Self>() {
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::<Self>() {
None => {
error!("Tried to rename with handle that's not an OsDir");
return Err(Errno::Badf);
return Err(Error::Badf);
}
Some(handle) => handle,
};

View File

@@ -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)?;

View File

@@ -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;

View File

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

View File

@@ -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;

View File

@@ -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) => {

View File

@@ -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<types::Timestamp> {
@@ -11,11 +12,11 @@ pub(crate) fn res_get(clock_id: types::Clockid) -> Result<types::Timestamp> {
(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<types::Timestamp> {
(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)
}

View File

@@ -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;

View File

@@ -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;

View File

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

View File

@@ -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<types::Clockid> for ClockId {
}
}
impl From<io::Error> 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<types::Fdflags> for OFlags {
fn from(fdflags: types::Fdflags) -> Self {
let mut nix_flags = Self::empty();
@@ -300,13 +209,13 @@ impl From<types::Oflags> for OFlags {
}
impl TryFrom<libc::stat> for types::Filestat {
type Error = Errno;
type Error = Error;
fn try_from(filestat: libc::stat) -> Result<Self> {
fn filestat_to_timestamp(secs: u64, nsecs: u64) -> Result<types::Timestamp> {
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);

View File

@@ -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 {

View File

@@ -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<types::Event>) {
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()?,

View File

@@ -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<Duration> {
SystemTime::now()
.duration_since(UNIX_EPOCH)
.map_err(|_| Errno::Fault)
.map_err(|_| Error::Fault)
}
fn get_proc_cputime() -> Result<Duration> {

View File

@@ -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;

View File

@@ -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<T: AsRawHandle> AsFile for T {
@@ -106,47 +106,7 @@ pub(crate) fn file_serial_no(file: &File) -> io::Result<u64> {
Ok(no)
}
impl From<io::Error> 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<string::FromUtf16Error> for Errno {
impl From<string::FromUtf16Error> for Error {
fn from(_err: string::FromUtf16Error) -> Self {
Self::Ilseq
}
@@ -166,14 +126,14 @@ fn change_time(file: &File) -> io::Result<i64> {
fn systemtime_to_timestamp(st: SystemTime) -> Result<u64> {
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<Self> {
let metadata = file.metadata()?;

View File

@@ -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<P: AsRef<Path>>(file: &OsDir, path: P) -> Result<PathBuf> {
// 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<String> {
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<String> {
// 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<usiz
let dir_path = PathBuf::from(strip_extended_prefix(dir_path));
let target_path = target_path
.strip_prefix(dir_path)
.map_err(|_| Errno::Notcapable)
.and_then(|path| path.to_str().map(String::from).ok_or(Errno::Ilseq))?;
.map_err(|_| Error::Notcapable)
.and_then(|path| path.to_str().map(String::from).ok_or(Error::Ilseq))?;
if buf.len() > 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)
}
}

View File

@@ -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<u64>) -> types::Event {
fn make_rw_event(
event: &FdEventData,
nbytes: std::result::Result<u64, types::Errno>,
) -> 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<types::Event>) {
.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<types::Event>) {
out_events.push(new_event);
}
fn handle_error_event(event: FdEventData, error: Errno, out_events: &mut Vec<types::Event>) {
fn handle_error_event(event: FdEventData, error: types::Errno, out_events: &mut Vec<types::Event>) {
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);
}
}
}

View File

@@ -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<usize> {
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<usize> {
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<usize> {
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<usize> {
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<usize> {
Err(Errno::Notdir)
Err(Error::Notdir)
}
fn readlinkat(&self, _path: &str) -> Result<String> {
Err(Errno::Notdir)
Err(Error::Notdir)
}
fn rename(&self, _old_path: &str, _new_handle: Box<dyn Handle>, _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<String> {
// 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)
}
}
}

View File

@@ -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<R: Read + Any> Handle for ReadPipe<R> {
_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<R: Read + Any> Handle for ReadPipe<R> {
}
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<usize> {
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<types::Filesize> {
Err(Errno::Spipe)
Err(Error::Spipe)
}
fn read_vectored(&self, iovs: &mut [io::IoSliceMut]) -> Result<usize> {
@@ -178,7 +179,7 @@ impl<R: Read + Any> Handle for ReadPipe<R> {
}
fn create_directory(&self, _path: &str) -> Result<()> {
Err(Errno::Notdir)
Err(Error::Notdir)
}
fn openat(
@@ -189,7 +190,7 @@ impl<R: Read + Any> Handle for ReadPipe<R> {
_oflags: types::Oflags,
_fd_flags: types::Fdflags,
) -> Result<Box<dyn Handle>> {
Err(Errno::Notdir)
Err(Error::Notdir)
}
fn link(
@@ -199,31 +200,31 @@ impl<R: Read + Any> Handle for ReadPipe<R> {
_new_path: &str,
_follow: bool,
) -> Result<()> {
Err(Errno::Notdir)
Err(Error::Notdir)
}
fn readlink(&self, _path: &str, _buf: &mut [u8]) -> Result<usize> {
Err(Errno::Notdir)
Err(Error::Notdir)
}
fn readlinkat(&self, _path: &str) -> Result<String> {
Err(Errno::Notdir)
Err(Error::Notdir)
}
fn rename(&self, _old_path: &str, _new_handle: Box<dyn Handle>, _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<W: Write + Any> Handle for WritePipe<W> {
_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<W: Write + Any> Handle for WritePipe<W> {
}
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<usize> {
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<types::Filesize> {
Err(Errno::Spipe)
Err(Error::Spipe)
}
fn write_vectored(&self, iovs: &[io::IoSlice]) -> Result<usize> {
@@ -363,7 +364,7 @@ impl<W: Write + Any> Handle for WritePipe<W> {
}
fn create_directory(&self, _path: &str) -> Result<()> {
Err(Errno::Notdir)
Err(Error::Notdir)
}
fn openat(
@@ -374,7 +375,7 @@ impl<W: Write + Any> Handle for WritePipe<W> {
_oflags: types::Oflags,
_fd_flags: types::Fdflags,
) -> Result<Box<dyn Handle>> {
Err(Errno::Notdir)
Err(Error::Notdir)
}
fn link(
@@ -384,30 +385,30 @@ impl<W: Write + Any> Handle for WritePipe<W> {
_new_path: &str,
_follow: bool,
) -> Result<()> {
Err(Errno::Notdir)
Err(Error::Notdir)
}
fn readlink(&self, _path: &str, _buf: &mut [u8]) -> Result<usize> {
Err(Errno::Notdir)
Err(Error::Notdir)
}
fn readlinkat(&self, _path: &str) -> Result<String> {
Err(Errno::Notdir)
Err(Error::Notdir)
}
fn rename(&self, _old_path: &str, _new_handle: Box<dyn Handle>, _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)
}
}

View File

@@ -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<T> = std::result::Result<T, Errno>;
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<Error> 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<wiggle::GuestError> for Errno {
}
}
impl From<std::convert::Infallible> for Errno {
fn from(_err: std::convert::Infallible) -> Self {
unreachable!()
}
}
impl From<std::num::TryFromIntError> for Errno {
fn from(_err: std::num::TryFromIntError) -> Self {
Self::Overflow
}
}
impl From<std::str::Utf8Error> for Errno {
fn from(_err: std::str::Utf8Error) -> Self {
Self::Ilseq
}
}
impl From<std::fs::FileType> for types::Filetype {
fn from(ftype: std::fs::FileType) -> Self {
if ftype.is_file() {