wasi-c2: completely redo how errors work
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
use crate::file::{FdFlags, FileCaps, FileType, Filestat, OFlags, WasiFile};
|
use crate::file::{FdFlags, FileCaps, FileType, Filestat, OFlags, WasiFile};
|
||||||
use crate::{Error, SystemTimeSpec};
|
use crate::{Error, ErrorExt, SystemTimeSpec};
|
||||||
use bitflags::bitflags;
|
use bitflags::bitflags;
|
||||||
use std::any::Any;
|
use std::any::Any;
|
||||||
use std::cell::Ref;
|
use std::cell::Ref;
|
||||||
@@ -69,20 +69,15 @@ impl DirEntry {
|
|||||||
if self.caps.contains(caps) {
|
if self.caps.contains(caps) {
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
Err(Error::DirNotCapable {
|
Err(Error::not_capable().context(format!("desired {:?}, has {:?}", caps, self.caps,)))
|
||||||
desired: caps,
|
|
||||||
has: self.caps,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn capable_of_file(&self, caps: FileCaps) -> Result<(), Error> {
|
pub fn capable_of_file(&self, caps: FileCaps) -> Result<(), Error> {
|
||||||
if self.file_caps.contains(caps) {
|
if self.file_caps.contains(caps) {
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
Err(Error::FileNotCapable {
|
Err(Error::not_capable()
|
||||||
desired: caps,
|
.context(format!("desired {:?}, has {:?}", caps, self.file_caps)))
|
||||||
has: self.file_caps,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn drop_caps_to(&mut self, caps: DirCaps, file_caps: FileCaps) -> Result<(), Error> {
|
pub fn drop_caps_to(&mut self, caps: DirCaps, file_caps: FileCaps) -> Result<(), Error> {
|
||||||
|
|||||||
@@ -1,171 +1,99 @@
|
|||||||
use crate::dir::DirCaps;
|
pub use anyhow::Error;
|
||||||
use crate::file::FileCaps;
|
|
||||||
use thiserror::Error;
|
|
||||||
|
|
||||||
/// Internal error type for the `wasi-common` crate.
|
/// 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
|
/// 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.
|
/// 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("cap_rand Error: {0}")]
|
|
||||||
CapRand(#[from] cap_rand::Error),
|
|
||||||
|
|
||||||
/// Errno::Notcapable: Extension: Capabilities insufficient
|
#[derive(Debug, thiserror::Error)]
|
||||||
#[error("File not capable: desired {desired:?}, has {has:?}")]
|
pub enum ErrorKind {
|
||||||
FileNotCapable { desired: FileCaps, has: FileCaps },
|
|
||||||
|
|
||||||
/// Errno::Notcapable: Extension: Capabilities insufficient
|
|
||||||
#[error("Directory not capable: desired {desired:?}, has {has:?}")]
|
|
||||||
DirNotCapable { desired: DirCaps, has: DirCaps },
|
|
||||||
|
|
||||||
/// Idk what the deal with this guy is yet
|
|
||||||
#[error("Table overflow")]
|
|
||||||
TableOverflow,
|
|
||||||
|
|
||||||
/// 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),
|
|
||||||
|
|
||||||
/// An unsupported feature of Wasi was used. This error will trap.
|
|
||||||
#[error("Unsupported feature: {0}")]
|
|
||||||
Unsupported(&'static str),
|
|
||||||
|
|
||||||
// Below this, all variants are from the `$errno` type:
|
|
||||||
/// Errno::TooBig: Argument list too long
|
/// Errno::TooBig: Argument list too long
|
||||||
#[error("TooBig: Argument list too long")]
|
#[error("TooBig: Argument list too long")]
|
||||||
TooBig,
|
TooBig,
|
||||||
/// Errno::Acces: Permission denied
|
|
||||||
#[error("Acces: Permission denied")]
|
|
||||||
Acces,
|
|
||||||
/// Errno::Badf: Bad file descriptor
|
/// Errno::Badf: Bad file descriptor
|
||||||
#[error("Badf: Bad file descriptor")]
|
#[error("Badf: Bad file descriptor")]
|
||||||
Badf,
|
Badf,
|
||||||
/// Errno::Busy: Device or resource busy
|
|
||||||
#[error("Busy: Device or resource busy")]
|
|
||||||
Busy,
|
|
||||||
/// Errno::Exist: File exists
|
/// Errno::Exist: File exists
|
||||||
#[error("Exist: File exists")]
|
#[error("Exist: File exists")]
|
||||||
Exist,
|
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
|
/// Errno::Ilseq: Illegal byte sequence
|
||||||
#[error("Ilseq: Illegal byte sequence")]
|
#[error("Ilseq: Illegal byte sequence")]
|
||||||
Ilseq,
|
Ilseq,
|
||||||
/// Errno::Inval: Invalid argument
|
/// Errno::Inval: Invalid argument
|
||||||
#[error("Inval: Invalid argument")]
|
#[error("Inval: Invalid argument")]
|
||||||
Inval,
|
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
|
/// Errno::Nametoolong: Filename too long
|
||||||
#[error("Nametoolong: Filename too long")]
|
#[error("Nametoolong: Filename too long")]
|
||||||
Nametoolong,
|
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.
|
/// Errno::Notdir: Not a directory or a symbolic link to a directory.
|
||||||
#[error("Notdir: Not a directory or a symbolic link to a directory")]
|
#[error("Notdir: Not a directory or a symbolic link to a directory")]
|
||||||
Notdir,
|
Notdir,
|
||||||
/// Errno::Notempty: Directory not empty.
|
|
||||||
#[error("Notempty: Directory not empty")]
|
|
||||||
Notempty,
|
|
||||||
/// Errno::Notsup: Not supported, or operation not supported on socket.
|
/// Errno::Notsup: Not supported, or operation not supported on socket.
|
||||||
#[error("Notsup: Not supported, or operation not supported on socket")]
|
#[error("Notsup: Not supported, or operation not supported on socket")]
|
||||||
Notsup,
|
Notsup,
|
||||||
/// Errno::Overflow: Value too large to be stored in data type.
|
/// Errno::Overflow: Value too large to be stored in data type.
|
||||||
#[error("Overflow: Value too large to be stored in data type")]
|
#[error("Overflow: Value too large to be stored in data type")]
|
||||||
Overflow,
|
Overflow,
|
||||||
/// Errno::Pipe: Broken pipe
|
|
||||||
#[error("Pipe: Broken pipe")]
|
|
||||||
Pipe,
|
|
||||||
/// Errno::Perm: Operation not permitted
|
|
||||||
#[error("Perm: Operation not permitted")]
|
|
||||||
Perm,
|
|
||||||
/// Errno::Range: Result too large
|
/// Errno::Range: Result too large
|
||||||
#[error("Range: Result too large")]
|
#[error("Range: Result too large")]
|
||||||
Range,
|
Range,
|
||||||
/// Errno::Spipe: Invalid seek
|
/// Errno::Spipe: Invalid seek
|
||||||
#[error("Spipe: Invalid seek")]
|
#[error("Spipe: Invalid seek")]
|
||||||
Spipe,
|
Spipe,
|
||||||
|
|
||||||
/// Errno::NotCapable: Not capable
|
/// Errno::NotCapable: Not capable
|
||||||
#[error("Not capable")]
|
#[error("Not capable")]
|
||||||
NotCapable,
|
NotCapable,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<std::convert::Infallible> for Error {
|
pub trait ErrorExt {
|
||||||
fn from(_err: std::convert::Infallible) -> Self {
|
fn too_big() -> Self;
|
||||||
unreachable!("should be impossible: From<Infallible>")
|
fn badf() -> Self;
|
||||||
}
|
fn exist() -> Self;
|
||||||
|
fn illegal_byte_sequence() -> Self;
|
||||||
|
fn invalid_argument() -> Self;
|
||||||
|
fn name_too_long() -> Self;
|
||||||
|
fn not_dir() -> Self;
|
||||||
|
fn not_supported() -> Self;
|
||||||
|
fn overflow() -> Self;
|
||||||
|
fn range() -> Self;
|
||||||
|
fn seek_pipe() -> Self;
|
||||||
|
fn not_capable() -> Self;
|
||||||
}
|
}
|
||||||
|
|
||||||
use std::io;
|
impl ErrorExt for Error {
|
||||||
impl From<io::Error> for Error {
|
fn too_big() -> Self {
|
||||||
fn from(err: io::Error) -> Self {
|
ErrorKind::TooBig.into()
|
||||||
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),
|
|
||||||
}
|
}
|
||||||
|
fn badf() -> Self {
|
||||||
|
ErrorKind::Badf.into()
|
||||||
|
}
|
||||||
|
fn exist() -> Self {
|
||||||
|
ErrorKind::Exist.into()
|
||||||
|
}
|
||||||
|
fn illegal_byte_sequence() -> Self {
|
||||||
|
ErrorKind::Ilseq.into()
|
||||||
|
}
|
||||||
|
fn invalid_argument() -> Self {
|
||||||
|
ErrorKind::Inval.into()
|
||||||
|
}
|
||||||
|
fn name_too_long() -> Self {
|
||||||
|
ErrorKind::Nametoolong.into()
|
||||||
|
}
|
||||||
|
fn not_dir() -> Self {
|
||||||
|
ErrorKind::Notdir.into()
|
||||||
|
}
|
||||||
|
fn not_supported() -> Self {
|
||||||
|
ErrorKind::Notsup.into()
|
||||||
|
}
|
||||||
|
fn overflow() -> Self {
|
||||||
|
ErrorKind::Overflow.into()
|
||||||
|
}
|
||||||
|
fn range() -> Self {
|
||||||
|
ErrorKind::Range.into()
|
||||||
|
}
|
||||||
|
fn seek_pipe() -> Self {
|
||||||
|
ErrorKind::Spipe.into()
|
||||||
|
}
|
||||||
|
fn not_capable() -> Self {
|
||||||
|
ErrorKind::NotCapable.into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
use crate::{Error, SystemTimeSpec};
|
use crate::{Error, ErrorExt, SystemTimeSpec};
|
||||||
use bitflags::bitflags;
|
use bitflags::bitflags;
|
||||||
use std::any::Any;
|
use std::any::Any;
|
||||||
use std::cell::Ref;
|
use std::cell::Ref;
|
||||||
@@ -116,10 +116,7 @@ impl FileEntry {
|
|||||||
if self.caps.contains(caps) {
|
if self.caps.contains(caps) {
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
Err(Error::FileNotCapable {
|
Err(Error::not_capable().context(format!("desired {:?}, has {:?}", caps, self.caps,)))
|
||||||
desired: caps,
|
|
||||||
has: self.caps,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,6 @@ pub mod table;
|
|||||||
pub use clocks::SystemTimeSpec;
|
pub use clocks::SystemTimeSpec;
|
||||||
pub use ctx::{WasiCtx, WasiCtxBuilder};
|
pub use ctx::{WasiCtx, WasiCtxBuilder};
|
||||||
pub use dir::{DirCaps, ReaddirCursor, ReaddirEntity, WasiDir};
|
pub use dir::{DirCaps, ReaddirCursor, ReaddirEntity, WasiDir};
|
||||||
pub use error::Error;
|
pub use error::{Error, ErrorExt, ErrorKind};
|
||||||
pub use file::{FdFlags, FileCaps, Filestat, OFlags, WasiFile};
|
pub use file::{FdFlags, FileCaps, Filestat, OFlags, WasiFile};
|
||||||
pub use string_array::StringArrayError;
|
pub use string_array::StringArrayError;
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
//!
|
//!
|
||||||
use crate::{
|
use crate::{
|
||||||
file::{FdFlags, FileType, Filestat, WasiFile},
|
file::{FdFlags, FileType, Filestat, WasiFile},
|
||||||
Error, SystemTimeSpec,
|
Error, ErrorExt, SystemTimeSpec,
|
||||||
};
|
};
|
||||||
use std::any::Any;
|
use std::any::Any;
|
||||||
use std::convert::TryInto;
|
use std::convert::TryInto;
|
||||||
@@ -115,7 +115,7 @@ impl<R: Read + Any> WasiFile for ReadPipe<R> {
|
|||||||
Ok(FdFlags::empty())
|
Ok(FdFlags::empty())
|
||||||
}
|
}
|
||||||
unsafe fn reopen_with_fdflags(&self, _fdflags: FdFlags) -> Result<Box<dyn WasiFile>, Error> {
|
unsafe fn reopen_with_fdflags(&self, _fdflags: FdFlags) -> Result<Box<dyn WasiFile>, Error> {
|
||||||
Err(Error::Badf)
|
Err(Error::badf())
|
||||||
}
|
}
|
||||||
fn get_filestat(&self) -> Result<Filestat, Error> {
|
fn get_filestat(&self) -> Result<Filestat, Error> {
|
||||||
Ok(Filestat {
|
Ok(Filestat {
|
||||||
@@ -130,39 +130,39 @@ impl<R: Read + Any> WasiFile for ReadPipe<R> {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
fn set_filestat_size(&self, _size: u64) -> Result<(), Error> {
|
fn set_filestat_size(&self, _size: u64) -> Result<(), Error> {
|
||||||
Err(Error::Perm)
|
Err(Error::badf())
|
||||||
}
|
}
|
||||||
fn advise(&self, offset: u64, len: u64, advice: Advice) -> Result<(), Error> {
|
fn advise(&self, offset: u64, len: u64, advice: Advice) -> Result<(), Error> {
|
||||||
Err(Error::Badf)
|
Err(Error::badf())
|
||||||
}
|
}
|
||||||
fn allocate(&self, offset: u64, len: u64) -> Result<(), Error> {
|
fn allocate(&self, offset: u64, len: u64) -> Result<(), Error> {
|
||||||
Err(Error::Badf)
|
Err(Error::badf())
|
||||||
}
|
}
|
||||||
fn read_vectored(&self, bufs: &mut [io::IoSliceMut]) -> Result<u64, Error> {
|
fn read_vectored(&self, bufs: &mut [io::IoSliceMut]) -> Result<u64, Error> {
|
||||||
let n = self.borrow().read_vectored(bufs)?;
|
let n = self.borrow().read_vectored(bufs)?;
|
||||||
Ok(n.try_into().map_err(|_| Error::Overflow)?)
|
Ok(n.try_into()?)
|
||||||
}
|
}
|
||||||
fn read_vectored_at(&self, bufs: &mut [io::IoSliceMut], offset: u64) -> Result<u64, Error> {
|
fn read_vectored_at(&self, bufs: &mut [io::IoSliceMut], offset: u64) -> Result<u64, Error> {
|
||||||
Err(Error::Badf)
|
Err(Error::badf())
|
||||||
}
|
}
|
||||||
fn write_vectored(&self, bufs: &[io::IoSlice]) -> Result<u64, Error> {
|
fn write_vectored(&self, bufs: &[io::IoSlice]) -> Result<u64, Error> {
|
||||||
Err(Error::Badf)
|
Err(Error::badf())
|
||||||
}
|
}
|
||||||
fn write_vectored_at(&self, bufs: &[io::IoSlice], offset: u64) -> Result<u64, Error> {
|
fn write_vectored_at(&self, bufs: &[io::IoSlice], offset: u64) -> Result<u64, Error> {
|
||||||
Err(Error::Badf)
|
Err(Error::badf())
|
||||||
}
|
}
|
||||||
fn seek(&self, pos: std::io::SeekFrom) -> Result<u64, Error> {
|
fn seek(&self, pos: std::io::SeekFrom) -> Result<u64, Error> {
|
||||||
Err(Error::Badf)
|
Err(Error::badf())
|
||||||
}
|
}
|
||||||
fn peek(&self, buf: &mut [u8]) -> Result<u64, Error> {
|
fn peek(&self, buf: &mut [u8]) -> Result<u64, Error> {
|
||||||
Err(Error::Badf)
|
Err(Error::badf())
|
||||||
}
|
}
|
||||||
fn set_times(
|
fn set_times(
|
||||||
&self,
|
&self,
|
||||||
atime: Option<SystemTimeSpec>,
|
atime: Option<SystemTimeSpec>,
|
||||||
mtime: Option<SystemTimeSpec>,
|
mtime: Option<SystemTimeSpec>,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
Err(Error::Badf)
|
Err(Error::badf())
|
||||||
}
|
}
|
||||||
fn num_ready_bytes(&self) -> Result<u64, Error> {
|
fn num_ready_bytes(&self) -> Result<u64, Error> {
|
||||||
Ok(0)
|
Ok(0)
|
||||||
@@ -251,7 +251,7 @@ impl<W: Write + Any> WasiFile for WritePipe<W> {
|
|||||||
Ok(FdFlags::APPEND)
|
Ok(FdFlags::APPEND)
|
||||||
}
|
}
|
||||||
unsafe fn reopen_with_fdflags(&self, _fdflags: FdFlags) -> Result<Box<dyn WasiFile>, Error> {
|
unsafe fn reopen_with_fdflags(&self, _fdflags: FdFlags) -> Result<Box<dyn WasiFile>, Error> {
|
||||||
Err(Error::Badf)
|
Err(Error::badf())
|
||||||
}
|
}
|
||||||
fn get_filestat(&self) -> Result<Filestat, Error> {
|
fn get_filestat(&self) -> Result<Filestat, Error> {
|
||||||
Ok(Filestat {
|
Ok(Filestat {
|
||||||
@@ -266,39 +266,39 @@ impl<W: Write + Any> WasiFile for WritePipe<W> {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
fn set_filestat_size(&self, _size: u64) -> Result<(), Error> {
|
fn set_filestat_size(&self, _size: u64) -> Result<(), Error> {
|
||||||
Err(Error::Perm)
|
Err(Error::badf())
|
||||||
}
|
}
|
||||||
fn advise(&self, offset: u64, len: u64, advice: Advice) -> Result<(), Error> {
|
fn advise(&self, offset: u64, len: u64, advice: Advice) -> Result<(), Error> {
|
||||||
Err(Error::Badf)
|
Err(Error::badf())
|
||||||
}
|
}
|
||||||
fn allocate(&self, offset: u64, len: u64) -> Result<(), Error> {
|
fn allocate(&self, offset: u64, len: u64) -> Result<(), Error> {
|
||||||
Err(Error::Badf)
|
Err(Error::badf())
|
||||||
}
|
}
|
||||||
fn read_vectored(&self, bufs: &mut [io::IoSliceMut]) -> Result<u64, Error> {
|
fn read_vectored(&self, bufs: &mut [io::IoSliceMut]) -> Result<u64, Error> {
|
||||||
Err(Error::Badf)
|
Err(Error::badf())
|
||||||
}
|
}
|
||||||
fn read_vectored_at(&self, bufs: &mut [io::IoSliceMut], offset: u64) -> Result<u64, Error> {
|
fn read_vectored_at(&self, bufs: &mut [io::IoSliceMut], offset: u64) -> Result<u64, Error> {
|
||||||
Err(Error::Badf)
|
Err(Error::badf())
|
||||||
}
|
}
|
||||||
fn write_vectored(&self, bufs: &[io::IoSlice]) -> Result<u64, Error> {
|
fn write_vectored(&self, bufs: &[io::IoSlice]) -> Result<u64, Error> {
|
||||||
let n = self.borrow().write_vectored(bufs)?;
|
let n = self.borrow().write_vectored(bufs)?;
|
||||||
Ok(n.try_into().map_err(|_| Error::Overflow)?)
|
Ok(n.try_into()?)
|
||||||
}
|
}
|
||||||
fn write_vectored_at(&self, bufs: &[io::IoSlice], offset: u64) -> Result<u64, Error> {
|
fn write_vectored_at(&self, bufs: &[io::IoSlice], offset: u64) -> Result<u64, Error> {
|
||||||
Err(Error::Badf)
|
Err(Error::badf())
|
||||||
}
|
}
|
||||||
fn seek(&self, pos: std::io::SeekFrom) -> Result<u64, Error> {
|
fn seek(&self, pos: std::io::SeekFrom) -> Result<u64, Error> {
|
||||||
Err(Error::Badf)
|
Err(Error::badf())
|
||||||
}
|
}
|
||||||
fn peek(&self, buf: &mut [u8]) -> Result<u64, Error> {
|
fn peek(&self, buf: &mut [u8]) -> Result<u64, Error> {
|
||||||
Err(Error::Badf)
|
Err(Error::badf())
|
||||||
}
|
}
|
||||||
fn set_times(
|
fn set_times(
|
||||||
&self,
|
&self,
|
||||||
atime: Option<SystemTimeSpec>,
|
atime: Option<SystemTimeSpec>,
|
||||||
mtime: Option<SystemTimeSpec>,
|
mtime: Option<SystemTimeSpec>,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
Err(Error::Badf)
|
Err(Error::badf())
|
||||||
}
|
}
|
||||||
fn num_ready_bytes(&self) -> Result<u64, Error> {
|
fn num_ready_bytes(&self) -> Result<u64, Error> {
|
||||||
Ok(0)
|
Ok(0)
|
||||||
|
|||||||
@@ -9,8 +9,9 @@ use crate::{
|
|||||||
subscription::{RwEventFlags, SubscriptionResult},
|
subscription::{RwEventFlags, SubscriptionResult},
|
||||||
Poll,
|
Poll,
|
||||||
},
|
},
|
||||||
Error, SystemTimeSpec, WasiCtx,
|
Error, ErrorExt, ErrorKind, SystemTimeSpec, WasiCtx,
|
||||||
};
|
};
|
||||||
|
use anyhow::{anyhow, Context};
|
||||||
use cap_std::time::{Duration, SystemClock};
|
use cap_std::time::{Duration, SystemClock};
|
||||||
use std::cell::{Ref, RefMut};
|
use std::cell::{Ref, RefMut};
|
||||||
use std::convert::{TryFrom, TryInto};
|
use std::convert::{TryFrom, TryInto};
|
||||||
@@ -42,74 +43,49 @@ impl types::UserErrorConversion for WasiCtx {
|
|||||||
fn errno_from_error(&self, e: Error) -> Result<types::Errno, wiggle::Trap> {
|
fn errno_from_error(&self, e: Error) -> Result<types::Errno, wiggle::Trap> {
|
||||||
debug!("Error: {:?}", e);
|
debug!("Error: {:?}", e);
|
||||||
e.try_into()
|
e.try_into()
|
||||||
|
.map_err(|e| wiggle::Trap::String(format!("{:?}", e)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TryFrom<Error> for types::Errno {
|
impl TryFrom<Error> for types::Errno {
|
||||||
type Error = wiggle::Trap;
|
type Error = Error;
|
||||||
fn try_from(e: Error) -> Result<types::Errno, wiggle::Trap> {
|
fn try_from(e: Error) -> Result<types::Errno, Error> {
|
||||||
use std::io::ErrorKind;
|
use types::Errno;
|
||||||
|
if e.is::<ErrorKind>() {
|
||||||
|
let e = e.downcast::<ErrorKind>().unwrap();
|
||||||
|
Ok(e.into())
|
||||||
|
} else if e.is::<std::io::Error>() {
|
||||||
|
let e = e.downcast::<std::io::Error>().unwrap();
|
||||||
|
e.try_into()
|
||||||
|
} else if e.is::<wiggle::GuestError>() {
|
||||||
|
let e = e.downcast::<wiggle::GuestError>().unwrap();
|
||||||
|
Ok(e.into())
|
||||||
|
} else if e.is::<std::num::TryFromIntError>() {
|
||||||
|
Ok(Errno::Overflow)
|
||||||
|
} else if e.is::<std::str::Utf8Error>() {
|
||||||
|
Ok(Errno::Ilseq)
|
||||||
|
} else {
|
||||||
|
Err(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<ErrorKind> for types::Errno {
|
||||||
|
fn from(e: ErrorKind) -> types::Errno {
|
||||||
use types::Errno;
|
use types::Errno;
|
||||||
match e {
|
match e {
|
||||||
Error::Unsupported(feat) => {
|
ErrorKind::TooBig => Errno::TooBig,
|
||||||
Err(wiggle::Trap::String(format!("Unsupported: {0}", feat)))
|
ErrorKind::Badf => Errno::Badf,
|
||||||
}
|
ErrorKind::Exist => Errno::Exist,
|
||||||
Error::Guest(e) => Ok(e.into()),
|
ErrorKind::Ilseq => Errno::Ilseq,
|
||||||
Error::TryFromInt(_) => Ok(Errno::Overflow),
|
ErrorKind::Inval => Errno::Inval,
|
||||||
Error::Utf8(_) => Ok(Errno::Ilseq),
|
ErrorKind::Nametoolong => Errno::Nametoolong,
|
||||||
Error::UnexpectedIo(e) => match e.kind() {
|
ErrorKind::Notdir => Errno::Notdir,
|
||||||
ErrorKind::NotFound => Ok(Errno::Noent),
|
ErrorKind::Notsup => Errno::Notsup,
|
||||||
ErrorKind::PermissionDenied => Ok(Errno::Perm),
|
ErrorKind::Overflow => Errno::Overflow,
|
||||||
ErrorKind::AlreadyExists => Ok(Errno::Exist),
|
ErrorKind::Range => Errno::Range,
|
||||||
ErrorKind::InvalidInput => Ok(Errno::Ilseq),
|
ErrorKind::Spipe => Errno::Spipe,
|
||||||
ErrorKind::ConnectionRefused
|
ErrorKind::NotCapable => Errno::Notcapable,
|
||||||
| ErrorKind::ConnectionReset
|
|
||||||
| ErrorKind::ConnectionAborted
|
|
||||||
| ErrorKind::NotConnected
|
|
||||||
| ErrorKind::AddrInUse
|
|
||||||
| ErrorKind::AddrNotAvailable
|
|
||||||
| ErrorKind::BrokenPipe
|
|
||||||
| ErrorKind::WouldBlock
|
|
||||||
| ErrorKind::InvalidData
|
|
||||||
| ErrorKind::TimedOut
|
|
||||||
| ErrorKind::WriteZero
|
|
||||||
| ErrorKind::Interrupted
|
|
||||||
| ErrorKind::Other
|
|
||||||
| ErrorKind::UnexpectedEof
|
|
||||||
| _ => Ok(Errno::Io),
|
|
||||||
},
|
|
||||||
Error::CapRand(_) => Ok(Errno::Io),
|
|
||||||
Error::TooBig => Ok(Errno::TooBig),
|
|
||||||
Error::Acces => Ok(Errno::Acces),
|
|
||||||
Error::Badf => Ok(Errno::Badf),
|
|
||||||
Error::Busy => Ok(Errno::Busy),
|
|
||||||
Error::Exist => Ok(Errno::Exist),
|
|
||||||
Error::Fault => Ok(Errno::Fault),
|
|
||||||
Error::Fbig => Ok(Errno::Fbig),
|
|
||||||
Error::Ilseq => Ok(Errno::Ilseq),
|
|
||||||
Error::Inval => Ok(Errno::Inval),
|
|
||||||
Error::Io => Ok(Errno::Io),
|
|
||||||
Error::Isdir => Ok(Errno::Isdir),
|
|
||||||
Error::Loop => Ok(Errno::Loop),
|
|
||||||
Error::Mfile => Ok(Errno::Mfile),
|
|
||||||
Error::Mlink => Ok(Errno::Mlink),
|
|
||||||
Error::Nametoolong => Ok(Errno::Nametoolong),
|
|
||||||
Error::Nfile => Ok(Errno::Nfile),
|
|
||||||
Error::Noent => Ok(Errno::Noent),
|
|
||||||
Error::Nomem => Ok(Errno::Nomem),
|
|
||||||
Error::Nospc => Ok(Errno::Nospc),
|
|
||||||
Error::Notdir => Ok(Errno::Notdir),
|
|
||||||
Error::Notempty => Ok(Errno::Notempty),
|
|
||||||
Error::Notsup => Ok(Errno::Notsup),
|
|
||||||
Error::Overflow => Ok(Errno::Overflow),
|
|
||||||
Error::Pipe => Ok(Errno::Pipe),
|
|
||||||
Error::Perm => Ok(Errno::Perm),
|
|
||||||
Error::Range => Ok(Errno::Range),
|
|
||||||
Error::Spipe => Ok(Errno::Spipe),
|
|
||||||
Error::FileNotCapable { .. } => Ok(Errno::Notcapable),
|
|
||||||
Error::DirNotCapable { .. } => Ok(Errno::Notcapable),
|
|
||||||
Error::NotCapable => Ok(Errno::Notcapable),
|
|
||||||
Error::TableOverflow => Ok(Errno::Overflow),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -134,6 +110,44 @@ impl From<wiggle::GuestError> for types::Errno {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl TryFrom<std::io::Error> for types::Errno {
|
||||||
|
type Error = Error;
|
||||||
|
fn try_from(err: std::io::Error) -> Result<types::Errno, Error> {
|
||||||
|
match err.raw_os_error() {
|
||||||
|
Some(code) => match code {
|
||||||
|
libc::EPIPE => Ok(types::Errno::Pipe),
|
||||||
|
libc::EPERM => Ok(types::Errno::Perm),
|
||||||
|
libc::ENOENT => Ok(types::Errno::Noent),
|
||||||
|
libc::ENOMEM => Ok(types::Errno::Nomem),
|
||||||
|
libc::E2BIG => Ok(types::Errno::TooBig),
|
||||||
|
libc::EIO => Ok(types::Errno::Io),
|
||||||
|
libc::EBADF => Ok(types::Errno::Badf),
|
||||||
|
libc::EBUSY => Ok(types::Errno::Busy),
|
||||||
|
libc::EACCES => Ok(types::Errno::Acces),
|
||||||
|
libc::EFAULT => Ok(types::Errno::Fault),
|
||||||
|
libc::ENOTDIR => Ok(types::Errno::Notdir),
|
||||||
|
libc::EISDIR => Ok(types::Errno::Isdir),
|
||||||
|
libc::EINVAL => Ok(types::Errno::Inval),
|
||||||
|
libc::EEXIST => Ok(types::Errno::Exist),
|
||||||
|
libc::EFBIG => Ok(types::Errno::Fbig),
|
||||||
|
libc::ENOSPC => Ok(types::Errno::Nospc),
|
||||||
|
libc::ESPIPE => Ok(types::Errno::Spipe),
|
||||||
|
libc::EMFILE => Ok(types::Errno::Mfile),
|
||||||
|
libc::EMLINK => Ok(types::Errno::Mlink),
|
||||||
|
libc::ENAMETOOLONG => Ok(types::Errno::Nametoolong),
|
||||||
|
libc::ENFILE => Ok(types::Errno::Nfile),
|
||||||
|
libc::ENOTEMPTY => Ok(types::Errno::Notempty),
|
||||||
|
libc::ELOOP => Ok(types::Errno::Loop),
|
||||||
|
libc::EOVERFLOW => Ok(types::Errno::Overflow),
|
||||||
|
libc::EILSEQ => Ok(types::Errno::Ilseq),
|
||||||
|
libc::ENOTSUP => Ok(types::Errno::Notsup),
|
||||||
|
_ => Err(anyhow!(err).context("Unknown raw OS error")),
|
||||||
|
},
|
||||||
|
None => Err(anyhow!(err).context("No raw OS error")),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'a> wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiCtx {
|
impl<'a> wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiCtx {
|
||||||
fn args_get<'b>(
|
fn args_get<'b>(
|
||||||
&self,
|
&self,
|
||||||
@@ -164,7 +178,7 @@ impl<'a> wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiCtx {
|
|||||||
types::Clockid::Realtime => Ok(self.clocks.system.resolution()),
|
types::Clockid::Realtime => Ok(self.clocks.system.resolution()),
|
||||||
types::Clockid::Monotonic => Ok(self.clocks.monotonic.resolution()),
|
types::Clockid::Monotonic => Ok(self.clocks.monotonic.resolution()),
|
||||||
types::Clockid::ProcessCputimeId | types::Clockid::ThreadCputimeId => {
|
types::Clockid::ProcessCputimeId | types::Clockid::ThreadCputimeId => {
|
||||||
Err(Error::NotCapable)
|
Err(Error::badf().context("process and thread clocks are not supported"))
|
||||||
}
|
}
|
||||||
}?;
|
}?;
|
||||||
Ok(resolution.as_nanos().try_into()?)
|
Ok(resolution.as_nanos().try_into()?)
|
||||||
@@ -181,7 +195,7 @@ impl<'a> wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiCtx {
|
|||||||
let now = self.clocks.system.now(precision).into_std();
|
let now = self.clocks.system.now(precision).into_std();
|
||||||
let d = now
|
let d = now
|
||||||
.duration_since(std::time::SystemTime::UNIX_EPOCH)
|
.duration_since(std::time::SystemTime::UNIX_EPOCH)
|
||||||
.map_err(|_| Error::NotCapable)?; // XXX wrong
|
.map_err(|_| anyhow!("current time before unix epoch"))?;
|
||||||
Ok(d.as_nanos().try_into()?)
|
Ok(d.as_nanos().try_into()?)
|
||||||
}
|
}
|
||||||
types::Clockid::Monotonic => {
|
types::Clockid::Monotonic => {
|
||||||
@@ -189,7 +203,9 @@ impl<'a> wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiCtx {
|
|||||||
let d = now.duration_since(self.clocks.creation_time);
|
let d = now.duration_since(self.clocks.creation_time);
|
||||||
Ok(d.as_nanos().try_into()?)
|
Ok(d.as_nanos().try_into()?)
|
||||||
}
|
}
|
||||||
types::Clockid::ProcessCputimeId | types::Clockid::ThreadCputimeId => Err(Error::Badf),
|
types::Clockid::ProcessCputimeId | types::Clockid::ThreadCputimeId => {
|
||||||
|
Err(Error::badf().context("process and thread clocks are not supported"))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -226,7 +242,7 @@ impl<'a> wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiCtx {
|
|||||||
|
|
||||||
// Fail fast: If not present in table, Badf
|
// Fail fast: If not present in table, Badf
|
||||||
if !table.contains_key(fd) {
|
if !table.contains_key(fd) {
|
||||||
return Err(Error::Badf);
|
return Err(Error::badf().context("key not in table"));
|
||||||
}
|
}
|
||||||
// fd_close must close either a File or a Dir handle
|
// fd_close must close either a File or a Dir handle
|
||||||
if table.is::<FileEntry>(fd) {
|
if table.is::<FileEntry>(fd) {
|
||||||
@@ -235,13 +251,12 @@ impl<'a> wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiCtx {
|
|||||||
// We cannot close preopened directories
|
// We cannot close preopened directories
|
||||||
let dir_entry: Ref<DirEntry> = table.get(fd).unwrap();
|
let dir_entry: Ref<DirEntry> = table.get(fd).unwrap();
|
||||||
if dir_entry.preopen_path().is_some() {
|
if dir_entry.preopen_path().is_some() {
|
||||||
return Err(Error::Notsup);
|
return Err(Error::not_supported().context("cannot close propened directory"));
|
||||||
}
|
}
|
||||||
drop(dir_entry);
|
drop(dir_entry);
|
||||||
let _ = table.delete(fd);
|
let _ = table.delete(fd);
|
||||||
} else {
|
} else {
|
||||||
// XXX do we just table delete other entry types anyway?
|
return Err(Error::badf().context("key does not refer to file or directory"));
|
||||||
return Err(Error::Badf);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -267,7 +282,7 @@ impl<'a> wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiCtx {
|
|||||||
let dir_fdstat = dir_entry.get_dir_fdstat();
|
let dir_fdstat = dir_entry.get_dir_fdstat();
|
||||||
Ok(types::Fdstat::from(&dir_fdstat))
|
Ok(types::Fdstat::from(&dir_fdstat))
|
||||||
} else {
|
} else {
|
||||||
Err(Error::Badf)
|
Err(Error::badf())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -300,7 +315,7 @@ impl<'a> wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiCtx {
|
|||||||
let file_caps = FileCaps::from(&fs_rights_inheriting);
|
let file_caps = FileCaps::from(&fs_rights_inheriting);
|
||||||
dir_entry.drop_caps_to(dir_caps, file_caps)
|
dir_entry.drop_caps_to(dir_caps, file_caps)
|
||||||
} else {
|
} else {
|
||||||
Err(Error::Badf)
|
Err(Error::badf())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -320,7 +335,7 @@ impl<'a> wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiCtx {
|
|||||||
.get_filestat()?;
|
.get_filestat()?;
|
||||||
Ok(filestat.into())
|
Ok(filestat.into())
|
||||||
} else {
|
} else {
|
||||||
Err(Error::Badf)
|
Err(Error::badf())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -346,27 +361,10 @@ impl<'a> wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiCtx {
|
|||||||
let set_atim_now = fst_flags.contains(types::Fstflags::ATIM_NOW);
|
let set_atim_now = fst_flags.contains(types::Fstflags::ATIM_NOW);
|
||||||
let set_mtim = fst_flags.contains(types::Fstflags::MTIM);
|
let set_mtim = fst_flags.contains(types::Fstflags::MTIM);
|
||||||
let set_mtim_now = fst_flags.contains(types::Fstflags::MTIM_NOW);
|
let set_mtim_now = fst_flags.contains(types::Fstflags::MTIM_NOW);
|
||||||
if (set_atim && set_atim_now) || (set_mtim && set_mtim_now) {
|
|
||||||
return Err(Error::Inval);
|
let atim = systimespec(set_atim, atim, set_atim_now).context("atim")?;
|
||||||
}
|
let mtim = systimespec(set_mtim, mtim, set_mtim_now).context("mtim")?;
|
||||||
let atim = if set_atim {
|
|
||||||
Some(SystemTimeSpec::Absolute(
|
|
||||||
SystemClock::UNIX_EPOCH + Duration::from_nanos(atim),
|
|
||||||
))
|
|
||||||
} else if set_atim_now {
|
|
||||||
Some(SystemTimeSpec::SymbolicNow)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
let mtim = if set_mtim {
|
|
||||||
Some(SystemTimeSpec::Absolute(
|
|
||||||
SystemClock::UNIX_EPOCH + Duration::from_nanos(mtim),
|
|
||||||
))
|
|
||||||
} else if set_mtim_now {
|
|
||||||
Some(SystemTimeSpec::SymbolicNow)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
if table.is::<FileEntry>(fd) {
|
if table.is::<FileEntry>(fd) {
|
||||||
table
|
table
|
||||||
.get_file(fd)
|
.get_file(fd)
|
||||||
@@ -380,7 +378,7 @@ impl<'a> wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiCtx {
|
|||||||
.get_cap(DirCaps::FILESTAT_SET_TIMES)?
|
.get_cap(DirCaps::FILESTAT_SET_TIMES)?
|
||||||
.set_times(".", atim, mtim)
|
.set_times(".", atim, mtim)
|
||||||
} else {
|
} else {
|
||||||
Err(Error::Badf)
|
Err(Error::badf())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -492,14 +490,13 @@ impl<'a> wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiCtx {
|
|||||||
|
|
||||||
fn fd_prestat_get(&self, fd: types::Fd) -> Result<types::Prestat, Error> {
|
fn fd_prestat_get(&self, fd: types::Fd) -> Result<types::Prestat, Error> {
|
||||||
let table = self.table();
|
let table = self.table();
|
||||||
let dir_entry: Ref<DirEntry> = table.get(u32::from(fd)).map_err(|_| Error::Badf)?;
|
let dir_entry: Ref<DirEntry> = table.get(u32::from(fd)).map_err(|_| Error::badf())?;
|
||||||
if let Some(ref preopen) = dir_entry.preopen_path() {
|
if let Some(ref preopen) = dir_entry.preopen_path() {
|
||||||
let path_str = preopen.to_str().ok_or(Error::Notsup)?;
|
let path_str = preopen.to_str().ok_or_else(|| Error::not_supported())?;
|
||||||
let pr_name_len =
|
let pr_name_len = u32::try_from(path_str.as_bytes().len())?;
|
||||||
u32::try_from(path_str.as_bytes().len()).map_err(|_| Error::Overflow)?;
|
|
||||||
Ok(types::Prestat::Dir(types::PrestatDir { pr_name_len }))
|
Ok(types::Prestat::Dir(types::PrestatDir { pr_name_len }))
|
||||||
} else {
|
} else {
|
||||||
Err(Error::Notsup)
|
Err(Error::not_supported().context("file is not a preopen"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -510,18 +507,21 @@ impl<'a> wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiCtx {
|
|||||||
path_max_len: types::Size,
|
path_max_len: types::Size,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
let table = self.table();
|
let table = self.table();
|
||||||
let dir_entry: Ref<DirEntry> = table.get(u32::from(fd)).map_err(|_| Error::Notdir)?;
|
let dir_entry: Ref<DirEntry> = table.get(u32::from(fd)).map_err(|_| Error::not_dir())?;
|
||||||
if let Some(ref preopen) = dir_entry.preopen_path() {
|
if let Some(ref preopen) = dir_entry.preopen_path() {
|
||||||
let path_bytes = preopen.to_str().ok_or(Error::Notsup)?.as_bytes();
|
let path_bytes = preopen
|
||||||
|
.to_str()
|
||||||
|
.ok_or_else(|| Error::not_supported())?
|
||||||
|
.as_bytes();
|
||||||
let path_len = path_bytes.len();
|
let path_len = path_bytes.len();
|
||||||
if path_len < path_max_len as usize {
|
if path_len < path_max_len as usize {
|
||||||
return Err(Error::Nametoolong);
|
return Err(Error::name_too_long());
|
||||||
}
|
}
|
||||||
let mut p_memory = path.as_array(path_len as u32).as_slice_mut()?;
|
let mut p_memory = path.as_array(path_len as u32).as_slice_mut()?;
|
||||||
p_memory.copy_from_slice(path_bytes);
|
p_memory.copy_from_slice(path_bytes);
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
Err(Error::Notsup)
|
Err(Error::not_supported())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn fd_renumber(&self, from: types::Fd, to: types::Fd) -> Result<(), Error> {
|
fn fd_renumber(&self, from: types::Fd, to: types::Fd) -> Result<(), Error> {
|
||||||
@@ -529,13 +529,10 @@ impl<'a> wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiCtx {
|
|||||||
let from = u32::from(from);
|
let from = u32::from(from);
|
||||||
let to = u32::from(to);
|
let to = u32::from(to);
|
||||||
if !table.contains_key(from) {
|
if !table.contains_key(from) {
|
||||||
return Err(Error::Badf);
|
return Err(Error::badf());
|
||||||
}
|
}
|
||||||
if table.is_preopen(from) {
|
if table.is_preopen(from) || table.is_preopen(to) {
|
||||||
return Err(Error::Notsup);
|
return Err(Error::not_supported().context("cannot renumber a preopen"));
|
||||||
}
|
|
||||||
if table.is_preopen(to) {
|
|
||||||
return Err(Error::Notsup);
|
|
||||||
}
|
}
|
||||||
let from_entry = table
|
let from_entry = table
|
||||||
.delete(from)
|
.delete(from)
|
||||||
@@ -609,7 +606,9 @@ impl<'a> wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiCtx {
|
|||||||
let dirent_len: types::Size = dirent_raw.len().try_into()?;
|
let dirent_len: types::Size = dirent_raw.len().try_into()?;
|
||||||
let name_raw = name.as_bytes();
|
let name_raw = name.as_bytes();
|
||||||
let name_len: types::Size = name_raw.len().try_into()?;
|
let name_len: types::Size = name_raw.len().try_into()?;
|
||||||
let offset = dirent_len.checked_add(name_len).ok_or(Error::Overflow)?;
|
let offset = dirent_len
|
||||||
|
.checked_add(name_len)
|
||||||
|
.ok_or_else(|| Error::overflow())?;
|
||||||
|
|
||||||
// Copy as many bytes of the dirent as we can, up to the end of the buffer
|
// Copy as many bytes of the dirent as we can, up to the end of the buffer
|
||||||
let dirent_copy_len = std::cmp::min(dirent_len, buf_len - bufused);
|
let dirent_copy_len = std::cmp::min(dirent_len, buf_len - bufused);
|
||||||
@@ -680,22 +679,9 @@ impl<'a> wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiCtx {
|
|||||||
let set_atim_now = fst_flags.contains(types::Fstflags::ATIM_NOW);
|
let set_atim_now = fst_flags.contains(types::Fstflags::ATIM_NOW);
|
||||||
let set_mtim = fst_flags.contains(types::Fstflags::MTIM);
|
let set_mtim = fst_flags.contains(types::Fstflags::MTIM);
|
||||||
let set_mtim_now = fst_flags.contains(types::Fstflags::MTIM_NOW);
|
let set_mtim_now = fst_flags.contains(types::Fstflags::MTIM_NOW);
|
||||||
if (set_atim && set_atim_now) || (set_mtim && set_mtim_now) {
|
|
||||||
return Err(Error::Inval);
|
let atim = systimespec(set_atim, atim, set_atim_now).context("atim")?;
|
||||||
}
|
let mtim = systimespec(set_mtim, mtim, set_mtim_now).context("mtim")?;
|
||||||
fn systimespec(set: bool, ts: types::Timestamp, now: bool) -> Option<SystemTimeSpec> {
|
|
||||||
if set {
|
|
||||||
Some(SystemTimeSpec::Absolute(
|
|
||||||
SystemClock::UNIX_EPOCH + Duration::from_nanos(ts),
|
|
||||||
))
|
|
||||||
} else if now {
|
|
||||||
Some(SystemTimeSpec::SymbolicNow)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let atim = systimespec(set_atim, atim, set_atim_now);
|
|
||||||
let mtim = systimespec(set_mtim, mtim, set_mtim_now);
|
|
||||||
self.table()
|
self.table()
|
||||||
.get_dir(u32::from(dirfd))?
|
.get_dir(u32::from(dirfd))?
|
||||||
.get_cap(DirCaps::PATH_FILESTAT_SET_TIMES)?
|
.get_cap(DirCaps::PATH_FILESTAT_SET_TIMES)?
|
||||||
@@ -740,7 +726,7 @@ impl<'a> wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiCtx {
|
|||||||
let mut table = self.table();
|
let mut table = self.table();
|
||||||
let dirfd = u32::from(dirfd);
|
let dirfd = u32::from(dirfd);
|
||||||
if table.is::<FileEntry>(dirfd) {
|
if table.is::<FileEntry>(dirfd) {
|
||||||
return Err(Error::Notdir);
|
return Err(Error::not_dir());
|
||||||
}
|
}
|
||||||
let dir_entry = table.get_dir(dirfd)?;
|
let dir_entry = table.get_dir(dirfd)?;
|
||||||
|
|
||||||
@@ -754,7 +740,7 @@ impl<'a> wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiCtx {
|
|||||||
|| oflags.contains(OFlags::EXCLUSIVE)
|
|| oflags.contains(OFlags::EXCLUSIVE)
|
||||||
|| oflags.contains(OFlags::TRUNCATE)
|
|| oflags.contains(OFlags::TRUNCATE)
|
||||||
{
|
{
|
||||||
return Err(Error::Inval);
|
return Err(Error::invalid_argument().context("directory oflags"));
|
||||||
}
|
}
|
||||||
let dir_caps = dir_entry.child_dir_caps(DirCaps::from(&fs_rights_base));
|
let dir_caps = dir_entry.child_dir_caps(DirCaps::from(&fs_rights_base));
|
||||||
let file_caps = dir_entry.child_file_caps(FileCaps::from(&fs_rights_inheriting));
|
let file_caps = dir_entry.child_file_caps(FileCaps::from(&fs_rights_inheriting));
|
||||||
@@ -794,11 +780,11 @@ impl<'a> wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiCtx {
|
|||||||
.read_link(path.as_str()?.deref())?
|
.read_link(path.as_str()?.deref())?
|
||||||
.into_os_string()
|
.into_os_string()
|
||||||
.into_string()
|
.into_string()
|
||||||
.map_err(|_| Error::Ilseq)?;
|
.map_err(|_| Error::illegal_byte_sequence().context("link contents"))?;
|
||||||
let link_bytes = link.as_bytes();
|
let link_bytes = link.as_bytes();
|
||||||
let link_len = link_bytes.len();
|
let link_len = link_bytes.len();
|
||||||
if link_len > buf_len as usize {
|
if link_len > buf_len as usize {
|
||||||
return Err(Error::Range);
|
return Err(Error::range());
|
||||||
}
|
}
|
||||||
let mut buf = buf.as_array(link_len as u32).as_slice_mut()?;
|
let mut buf = buf.as_array(link_len as u32).as_slice_mut()?;
|
||||||
buf.copy_from_slice(link_bytes);
|
buf.copy_from_slice(link_bytes);
|
||||||
@@ -863,7 +849,7 @@ impl<'a> wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiCtx {
|
|||||||
nsubscriptions: types::Size,
|
nsubscriptions: types::Size,
|
||||||
) -> Result<types::Size, Error> {
|
) -> Result<types::Size, Error> {
|
||||||
if nsubscriptions == 0 {
|
if nsubscriptions == 0 {
|
||||||
return Err(Error::Inval);
|
return Err(Error::invalid_argument().context("nsubscriptions must be nonzero"));
|
||||||
}
|
}
|
||||||
|
|
||||||
let table = self.table();
|
let table = self.table();
|
||||||
@@ -886,12 +872,12 @@ impl<'a> wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiCtx {
|
|||||||
self.clocks
|
self.clocks
|
||||||
.creation_time
|
.creation_time
|
||||||
.checked_add(duration)
|
.checked_add(duration)
|
||||||
.ok_or(Error::Overflow)?
|
.ok_or_else(|| Error::overflow().context("deadline"))?
|
||||||
} else {
|
} else {
|
||||||
clock
|
clock
|
||||||
.now(precision)
|
.now(precision)
|
||||||
.checked_add(duration)
|
.checked_add(duration)
|
||||||
.ok_or(Error::Overflow)?
|
.ok_or_else(|| Error::overflow().context("deadline"))?
|
||||||
};
|
};
|
||||||
poll.subscribe_monotonic_clock(
|
poll.subscribe_monotonic_clock(
|
||||||
clock,
|
clock,
|
||||||
@@ -900,7 +886,8 @@ impl<'a> wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiCtx {
|
|||||||
sub.userdata.into(),
|
sub.userdata.into(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
_ => Err(Error::Inval)?,
|
_ => Err(Error::invalid_argument()
|
||||||
|
.context("timer subscriptions only support monotonic timer"))?,
|
||||||
},
|
},
|
||||||
types::SubscriptionU::FdRead(readsub) => {
|
types::SubscriptionU::FdRead(readsub) => {
|
||||||
let fd = readsub.file_descriptor;
|
let fd = readsub.file_descriptor;
|
||||||
@@ -970,7 +957,7 @@ impl<'a> wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiCtx {
|
|||||||
},
|
},
|
||||||
Err(e) => types::Event {
|
Err(e) => types::Event {
|
||||||
userdata,
|
userdata,
|
||||||
error: e.try_into().expect("non-trapping"),
|
error: e.try_into()?,
|
||||||
type_,
|
type_,
|
||||||
fd_readwrite: fd_readwrite_empty(),
|
fd_readwrite: fd_readwrite_empty(),
|
||||||
},
|
},
|
||||||
@@ -982,7 +969,7 @@ impl<'a> wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiCtx {
|
|||||||
userdata,
|
userdata,
|
||||||
error: match r {
|
error: match r {
|
||||||
Ok(()) => types::Errno::Success,
|
Ok(()) => types::Errno::Success,
|
||||||
Err(e) => e.try_into().expect("non-trapping"),
|
Err(e) => e.try_into()?,
|
||||||
},
|
},
|
||||||
type_,
|
type_,
|
||||||
fd_readwrite: fd_readwrite_empty(),
|
fd_readwrite: fd_readwrite_empty(),
|
||||||
@@ -1004,7 +991,7 @@ impl<'a> wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiCtx {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn proc_raise(&self, _sig: types::Signal) -> Result<(), Error> {
|
fn proc_raise(&self, _sig: types::Signal) -> Result<(), Error> {
|
||||||
Err(Error::Unsupported("proc_raise"))
|
Err(anyhow!("proc_raise unsupported"))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sched_yield(&self) -> Result<(), Error> {
|
fn sched_yield(&self) -> Result<(), Error> {
|
||||||
@@ -1023,7 +1010,7 @@ impl<'a> wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiCtx {
|
|||||||
_ri_data: &types::IovecArray<'_>,
|
_ri_data: &types::IovecArray<'_>,
|
||||||
_ri_flags: types::Riflags,
|
_ri_flags: types::Riflags,
|
||||||
) -> Result<(types::Size, types::Roflags), Error> {
|
) -> Result<(types::Size, types::Roflags), Error> {
|
||||||
Err(Error::Unsupported("sock_recv"))
|
Err(anyhow!("sock_recv unsupported"))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sock_send(
|
fn sock_send(
|
||||||
@@ -1032,11 +1019,11 @@ impl<'a> wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiCtx {
|
|||||||
_si_data: &types::CiovecArray<'_>,
|
_si_data: &types::CiovecArray<'_>,
|
||||||
_si_flags: types::Siflags,
|
_si_flags: types::Siflags,
|
||||||
) -> Result<types::Size, Error> {
|
) -> Result<types::Size, Error> {
|
||||||
Err(Error::Unsupported("sock_send"))
|
Err(anyhow!("sock_send unsupported"))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sock_shutdown(&self, _fd: types::Fd, _how: types::Sdflags) -> Result<(), Error> {
|
fn sock_shutdown(&self, _fd: types::Fd, _how: types::Sdflags) -> Result<(), Error> {
|
||||||
Err(Error::Unsupported("sock_shutdown"))
|
Err(anyhow!("sock_shutdown unsupported"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1447,3 +1434,21 @@ fn fd_readwrite_empty() -> types::EventFdReadwrite {
|
|||||||
flags: types::Eventrwflags::empty(),
|
flags: types::Eventrwflags::empty(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn systimespec(
|
||||||
|
set: bool,
|
||||||
|
ts: types::Timestamp,
|
||||||
|
now: bool,
|
||||||
|
) -> Result<Option<SystemTimeSpec>, Error> {
|
||||||
|
if set && now {
|
||||||
|
Err(Error::invalid_argument())
|
||||||
|
} else if set {
|
||||||
|
Ok(Some(SystemTimeSpec::Absolute(
|
||||||
|
SystemClock::UNIX_EPOCH + Duration::from_nanos(ts),
|
||||||
|
)))
|
||||||
|
} else if now {
|
||||||
|
Ok(Some(SystemTimeSpec::SymbolicNow))
|
||||||
|
} else {
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
use crate::Error;
|
use crate::{Error, ErrorExt};
|
||||||
use wiggle::GuestPtr;
|
use wiggle::GuestPtr;
|
||||||
|
|
||||||
pub struct StringArray {
|
pub struct StringArray {
|
||||||
@@ -59,10 +59,13 @@ impl StringArray {
|
|||||||
{
|
{
|
||||||
let elem_buffer = buffer
|
let elem_buffer = buffer
|
||||||
.get_range(cursor..(cursor + len))
|
.get_range(cursor..(cursor + len))
|
||||||
.ok_or(Error::Inval)?; // Elements don't fit in buffer provided
|
.ok_or(Error::invalid_argument())?; // Elements don't fit in buffer provided
|
||||||
elem_buffer.copy_from_slice(bytes)?;
|
elem_buffer.copy_from_slice(bytes)?;
|
||||||
}
|
}
|
||||||
buffer.get(cursor + len).ok_or(Error::Inval)?.write(0)?; // 0 terminate
|
buffer
|
||||||
|
.get(cursor + len)
|
||||||
|
.ok_or(Error::invalid_argument())?
|
||||||
|
.write(0)?; // 0 terminate
|
||||||
head?.write(buffer.get(cursor).expect("already validated"))?;
|
head?.write(buffer.get(cursor).expect("already validated"))?;
|
||||||
cursor += len + 1;
|
cursor += len + 1;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
use crate::Error;
|
use crate::{Error, ErrorExt};
|
||||||
|
use anyhow::anyhow;
|
||||||
use std::any::Any;
|
use std::any::Any;
|
||||||
use std::cell::{Ref, RefCell, RefMut};
|
use std::cell::{Ref, RefCell, RefMut};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
@@ -25,7 +26,10 @@ impl Table {
|
|||||||
let key = self.next_key;
|
let key = self.next_key;
|
||||||
// XXX this is not correct. The table may still have empty entries, but our
|
// XXX this is not correct. The table may still have empty entries, but our
|
||||||
// linear search strategy is quite bad
|
// linear search strategy is quite bad
|
||||||
self.next_key = self.next_key.checked_add(1).ok_or(Error::TableOverflow)?;
|
self.next_key = self
|
||||||
|
.next_key
|
||||||
|
.checked_add(1)
|
||||||
|
.ok_or_else(|| anyhow!("out of keys in table"))?;
|
||||||
if self.map.contains_key(&key) {
|
if self.map.contains_key(&key) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -56,13 +60,13 @@ impl Table {
|
|||||||
if r.is::<T>() {
|
if r.is::<T>() {
|
||||||
Ok(Ref::map(r, |r| r.downcast_ref::<T>().unwrap()))
|
Ok(Ref::map(r, |r| r.downcast_ref::<T>().unwrap()))
|
||||||
} else {
|
} else {
|
||||||
Err(Error::Exist) // Exists at another type
|
Err(Error::exist().context("element is a different type"))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Err(Error::Exist) // Does exist, but borrowed
|
Err(Error::exist().context("element in table, but mutably borrowed"))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Err(Error::Badf) // Does not exist
|
Err(Error::badf().context("key not in table"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -72,13 +76,13 @@ impl Table {
|
|||||||
if r.is::<T>() {
|
if r.is::<T>() {
|
||||||
Ok(RefMut::map(r, |r| r.downcast_mut::<T>().unwrap()))
|
Ok(RefMut::map(r, |r| r.downcast_mut::<T>().unwrap()))
|
||||||
} else {
|
} else {
|
||||||
Err(Error::Exist) // Exists at another type
|
Err(Error::exist().context("element is a different type"))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Err(Error::Exist) // Does exist, but borrowed
|
Err(Error::exist().context("element in table, but borrowed"))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Err(Error::Badf) // Does not exist
|
Err(Error::badf().context("key not in table"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -91,8 +95,10 @@ impl Table {
|
|||||||
T: Any + Sized,
|
T: Any + Sized,
|
||||||
F: FnOnce(T) -> Result<T, Error>,
|
F: FnOnce(T) -> Result<T, Error>,
|
||||||
{
|
{
|
||||||
let entry = self.delete(key).ok_or(Error::Badf)?;
|
let entry = self.delete(key).ok_or(Error::badf())?;
|
||||||
let downcast = entry.downcast::<T>().map_err(|_| Error::Exist)?;
|
let downcast = entry
|
||||||
|
.downcast::<T>()
|
||||||
|
.map_err(|_| Error::exist().context("element is a different type"))?;
|
||||||
let new = f(*downcast)?;
|
let new = f(*downcast)?;
|
||||||
self.insert_at(key, Box::new(new));
|
self.insert_at(key, Box::new(new));
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|||||||
Reference in New Issue
Block a user