[wasi-common]: clean up error handling (#1253)

* Introduce WasiCtxBuilderError error type

`WasiCtxBuilderError` is the `wasi-common` client-facing error type
which is exclusively thrown when building a new `WasiCtx` instance.
As such, building such an instance should not require the client to
understand different WASI errno values as was assumed until now.

This commit is a first step at streamlining error handling in
`wasi-common` and makes way for the `wiggle` crate.

When adding the `WasiCtxBuilderError`, I've had to do two things of
notable importance:
1. I've removed a couple of `ok_or` calls in `WasiCtxBuilder::build`
   and replaced them with `unwrap`s, following the same pattern in
   different builder methods above. This is fine since we _always_
   operate on non-empty `Option`s in `WasiCtxBuilder` thus `unwrap`ing
   will never fail. On the other hand, this might be a good opportunity
   to rethink the structure of our builder, and how we good remove
   the said `Option`s especially since we always populate them with
   empty containers to begin with. I understand this is to make
   chaining of builder methods easier which take and return `&mut self`
   and the same applies to `WasiCtxBuilder::build(&mut self)` method,
   but perhaps it would more cleanly signal the intentions if we simply
   moved `WasiCtxBuilder` instance around. Food for thought!
2. Methods specific to determining rights of passed around `std::fs::File`
   objects when populating `WasiCtx` `FdEntry` entities now return
   `io::Error` directly so that we can reuse them in `WasiCtxBuilder` methods
   (returning `WasiCtxBuilderError` error type), and in syscalls
   (returning WASI errno).

* Return WasiError directly in syscalls

Also, removes `error::Error` type altogether. Now, `io::Error` and
related are automatically converted to their corresponding WASI
errno value encapsulated as `WasiError`.

While here, it made sense to me to move `WasiError` to `wasi` module
which will align itself well with the upcoming changes introduced
by `wiggle`. To different standard `Result` from WASI specific, I've
created a helper alias `WasiResult` also residing in `wasi` module.

* Update wig

* Add from ffi::NulError and pass context to NotADirectory

* Add dummy commit to test CI
This commit is contained in:
Jakub Konka
2020-03-09 22:58:55 +01:00
committed by GitHub
parent 963bf0e255
commit 773915b4bf
59 changed files with 1465 additions and 1552 deletions

View File

@@ -1,16 +1,44 @@
use crate::fdentry::{Descriptor, FdEntry}; use crate::fdentry::{Descriptor, FdEntry};
use crate::sys::fdentry_impl::OsHandle; use crate::sys::fdentry_impl::OsHandle;
use crate::virtfs::{VirtualDir, VirtualDirEntry}; use crate::virtfs::{VirtualDir, VirtualDirEntry};
use crate::{wasi, Error, Result}; use crate::wasi::{self, WasiError, WasiResult};
use std::borrow::Borrow; use std::borrow::Borrow;
use std::collections::HashMap; use std::collections::HashMap;
use std::env; use std::ffi::{self, CString, OsString};
use std::ffi::{CString, OsString};
use std::fs::File; use std::fs::File;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use std::{env, io, string};
/// Possible errors when `WasiCtxBuilder` fails building
/// `WasiCtx`.
#[derive(Debug, thiserror::Error)]
pub enum WasiCtxBuilderError {
/// General I/O error was encountered.
#[error("general I/O error encountered: {0}")]
Io(#[from] io::Error),
/// Provided sequence of bytes was not a valid UTF-8.
#[error("provided sequence is not valid UTF-8: {0}")]
InvalidUtf8(#[from] string::FromUtf8Error),
/// Provided sequence of bytes was not a valid UTF-16.
///
/// This error is expected to only occur on Windows hosts.
#[error("provided sequence is not valid UTF-16: {0}")]
InvalidUtf16(#[from] string::FromUtf16Error),
/// Provided sequence of bytes contained an unexpected NUL byte.
#[error("provided sequence contained an unexpected NUL byte")]
UnexpectedNul(#[from] ffi::NulError),
/// Provided `File` is not a directory.
#[error("preopened directory path {} is not a directory", .0.display())]
NotADirectory(PathBuf),
/// `WasiCtx` has too many opened files.
#[error("context object has too many opened files")]
TooManyFilesOpen,
}
type WasiCtxBuilderResult<T> = std::result::Result<T, WasiCtxBuilderError>;
enum PendingFdEntry { enum PendingFdEntry {
Thunk(fn() -> Result<FdEntry>), Thunk(fn() -> io::Result<FdEntry>),
File(File), File(File),
} }
@@ -20,7 +48,7 @@ impl std::fmt::Debug for PendingFdEntry {
Self::Thunk(f) => write!( Self::Thunk(f) => write!(
fmt, fmt,
"PendingFdEntry::Thunk({:p})", "PendingFdEntry::Thunk({:p})",
f as *const fn() -> Result<FdEntry> f as *const fn() -> io::Result<FdEntry>
), ),
Self::File(f) => write!(fmt, "PendingFdEntry::File({:?})", f), Self::File(f) => write!(fmt, "PendingFdEntry::File({:?})", f),
} }
@@ -46,17 +74,29 @@ impl From<OsString> for PendingCString {
} }
impl PendingCString { impl PendingCString {
fn into_string(self) -> Result<String> { fn into_string(self) -> WasiCtxBuilderResult<String> {
match self { let res = match self {
Self::Bytes(v) => String::from_utf8(v).map_err(|_| Error::EILSEQ), Self::Bytes(v) => String::from_utf8(v)?,
Self::OsString(s) => s.into_string().map_err(|_| Error::EILSEQ), #[cfg(unix)]
} Self::OsString(s) => {
use std::os::unix::ffi::OsStringExt;
String::from_utf8(s.into_vec())?
}
#[cfg(windows)]
Self::OsString(s) => {
use std::os::windows::ffi::OsStrExt;
let bytes: Vec<u16> = s.encode_wide().collect();
String::from_utf16(&bytes)?
}
};
Ok(res)
} }
/// Create a `CString` containing valid UTF-8, or fail with `Error::EILSEQ`. /// Create a `CString` containing valid UTF-8.
fn into_utf8_cstring(self) -> Result<CString> { fn into_utf8_cstring(self) -> WasiCtxBuilderResult<CString> {
self.into_string() let s = self.into_string()?;
.and_then(|s| CString::new(s).map_err(|_| Error::EILSEQ)) let s = CString::new(s)?;
Ok(s)
} }
} }
@@ -87,8 +127,7 @@ impl WasiCtxBuilder {
/// Add arguments to the command-line arguments list. /// Add arguments to the command-line arguments list.
/// ///
/// Arguments must be valid UTF-8 with no NUL bytes, or else `WasiCtxBuilder::build()` will fail /// Arguments must be valid UTF-8 with no NUL bytes, or else `WasiCtxBuilder::build()` will fail.
/// with `Error::EILSEQ`.
pub fn args<S: AsRef<[u8]>>(&mut self, args: impl IntoIterator<Item = S>) -> &mut Self { pub fn args<S: AsRef<[u8]>>(&mut self, args: impl IntoIterator<Item = S>) -> &mut Self {
self.args self.args
.as_mut() .as_mut()
@@ -99,8 +138,7 @@ impl WasiCtxBuilder {
/// Add an argument to the command-line arguments list. /// Add an argument to the command-line arguments list.
/// ///
/// Arguments must be valid UTF-8 with no NUL bytes, or else `WasiCtxBuilder::build()` will fail /// Arguments must be valid UTF-8 with no NUL bytes, or else `WasiCtxBuilder::build()` will fail.
/// with `Error::EILSEQ`.
pub fn arg<S: AsRef<[u8]>>(&mut self, arg: S) -> &mut Self { pub fn arg<S: AsRef<[u8]>>(&mut self, arg: S) -> &mut Self {
self.args self.args
.as_mut() .as_mut()
@@ -112,7 +150,7 @@ impl WasiCtxBuilder {
/// Inherit the command-line arguments from the host process. /// Inherit the command-line arguments from the host process.
/// ///
/// If any arguments from the host process contain invalid UTF-8, `WasiCtxBuilder::build()` will /// If any arguments from the host process contain invalid UTF-8, `WasiCtxBuilder::build()` will
/// fail with `Error::EILSEQ`. /// fail.
pub fn inherit_args(&mut self) -> &mut Self { pub fn inherit_args(&mut self) -> &mut Self {
let args = self.args.as_mut().unwrap(); let args = self.args.as_mut().unwrap();
args.clear(); args.clear();
@@ -159,8 +197,7 @@ impl WasiCtxBuilder {
/// Inherit the environment variables from the host process. /// Inherit the environment variables from the host process.
/// ///
/// If any environment variables from the host process contain invalid Unicode (UTF-16 for /// If any environment variables from the host process contain invalid Unicode (UTF-16 for
/// Windows, UTF-8 for other platforms), `WasiCtxBuilder::build()` will fail with /// Windows, UTF-8 for other platforms), `WasiCtxBuilder::build()` will fail.
/// `Error::EILSEQ`.
pub fn inherit_env(&mut self) -> &mut Self { pub fn inherit_env(&mut self) -> &mut Self {
let env = self.env.as_mut().unwrap(); let env = self.env.as_mut().unwrap();
env.clear(); env.clear();
@@ -171,7 +208,7 @@ impl WasiCtxBuilder {
/// Add an entry to the environment. /// Add an entry to the environment.
/// ///
/// Environment variable keys and values must be valid UTF-8 with no NUL bytes, or else /// Environment variable keys and values must be valid UTF-8 with no NUL bytes, or else
/// `WasiCtxBuilder::build()` will fail with `Error::EILSEQ`. /// `WasiCtxBuilder::build()` will fail.
pub fn env<S: AsRef<[u8]>>(&mut self, k: S, v: S) -> &mut Self { pub fn env<S: AsRef<[u8]>>(&mut self, k: S, v: S) -> &mut Self {
self.env self.env
.as_mut() .as_mut()
@@ -183,7 +220,7 @@ impl WasiCtxBuilder {
/// Add entries to the environment. /// Add entries to the environment.
/// ///
/// Environment variable keys and values must be valid UTF-8 with no NUL bytes, or else /// Environment variable keys and values must be valid UTF-8 with no NUL bytes, or else
/// `WasiCtxBuilder::build()` will fail with `Error::EILSEQ`. /// `WasiCtxBuilder::build()` will fail.
pub fn envs<S: AsRef<[u8]>, T: Borrow<(S, S)>>( pub fn envs<S: AsRef<[u8]>, T: Borrow<(S, S)>>(
&mut self, &mut self,
envs: impl IntoIterator<Item = T>, envs: impl IntoIterator<Item = T>,
@@ -270,22 +307,22 @@ impl WasiCtxBuilder {
/// Build a `WasiCtx`, consuming this `WasiCtxBuilder`. /// Build a `WasiCtx`, consuming this `WasiCtxBuilder`.
/// ///
/// If any of the arguments or environment variables in this builder cannot be converted into /// If any of the arguments or environment variables in this builder cannot be converted into
/// `CString`s, either due to NUL bytes or Unicode conversions, this returns `Error::EILSEQ`. /// `CString`s, either due to NUL bytes or Unicode conversions, this will fail.
pub fn build(&mut self) -> Result<WasiCtx> { pub fn build(&mut self) -> WasiCtxBuilderResult<WasiCtx> {
// Process arguments and environment variables into `CString`s, failing quickly if they // Process arguments and environment variables into `CString`s, failing quickly if they
// contain any NUL bytes, or if conversion from `OsString` fails. // contain any NUL bytes, or if conversion from `OsString` fails.
let args = self let args = self
.args .args
.take() .take()
.ok_or(Error::EINVAL)? .unwrap()
.into_iter() .into_iter()
.map(|arg| arg.into_utf8_cstring()) .map(|arg| arg.into_utf8_cstring())
.collect::<Result<Vec<CString>>>()?; .collect::<WasiCtxBuilderResult<Vec<CString>>>()?;
let env = self let env = self
.env .env
.take() .take()
.ok_or(Error::EINVAL)? .unwrap()
.into_iter() .into_iter()
.map(|(k, v)| { .map(|(k, v)| {
k.into_string().and_then(|mut pair| { k.into_string().and_then(|mut pair| {
@@ -294,15 +331,16 @@ impl WasiCtxBuilder {
pair.push_str(v.as_str()); pair.push_str(v.as_str());
// We have valid UTF-8, but the keys and values have not yet been checked // We have valid UTF-8, but the keys and values have not yet been checked
// for NULs, so we do a final check here. // for NULs, so we do a final check here.
CString::new(pair).map_err(|_| Error::EILSEQ) let s = CString::new(pair)?;
Ok(s)
}) })
}) })
}) })
.collect::<Result<Vec<CString>>>()?; .collect::<WasiCtxBuilderResult<Vec<CString>>>()?;
let mut fds: HashMap<wasi::__wasi_fd_t, FdEntry> = HashMap::new(); let mut fds: HashMap<wasi::__wasi_fd_t, FdEntry> = HashMap::new();
// Populate the non-preopen fds. // Populate the non-preopen fds.
for (fd, pending) in self.fds.take().ok_or(Error::EINVAL)? { for (fd, pending) in self.fds.take().unwrap() {
log::debug!("WasiCtx inserting ({:?}, {:?})", fd, pending); log::debug!("WasiCtx inserting ({:?}, {:?})", fd, pending);
match pending { match pending {
PendingFdEntry::Thunk(f) => { PendingFdEntry::Thunk(f) => {
@@ -317,20 +355,22 @@ impl WasiCtxBuilder {
// so we start from there. This variable is initially 2, though, because the loop // so we start from there. This variable is initially 2, though, because the loop
// immediately does the increment and check for overflow. // immediately does the increment and check for overflow.
let mut preopen_fd: wasi::__wasi_fd_t = 2; let mut preopen_fd: wasi::__wasi_fd_t = 2;
for (guest_path, dir) in self.preopens.take().ok_or(Error::EINVAL)? { for (guest_path, dir) in self.preopens.take().unwrap() {
// We do the increment at the beginning of the loop body, so that we don't overflow // We do the increment at the beginning of the loop body, so that we don't overflow
// unnecessarily if we have exactly the maximum number of file descriptors. // unnecessarily if we have exactly the maximum number of file descriptors.
preopen_fd = preopen_fd.checked_add(1).ok_or(Error::ENFILE)?; preopen_fd = preopen_fd
.checked_add(1)
.ok_or(WasiCtxBuilderError::TooManyFilesOpen)?;
match &dir { match &dir {
Descriptor::OsHandle(handle) => { Descriptor::OsHandle(handle) => {
if !handle.metadata()?.is_dir() { if !handle.metadata()?.is_dir() {
return Err(Error::EBADF); return Err(WasiCtxBuilderError::NotADirectory(guest_path));
} }
} }
Descriptor::VirtualFile(virt) => { Descriptor::VirtualFile(virt) => {
if virt.get_file_type() != wasi::__WASI_FILETYPE_DIRECTORY { if virt.get_file_type() != wasi::__WASI_FILETYPE_DIRECTORY {
return Err(Error::EBADF); return Err(WasiCtxBuilderError::NotADirectory(guest_path));
} }
} }
Descriptor::Stdin | Descriptor::Stdout | Descriptor::Stderr => { Descriptor::Stdin | Descriptor::Stdout | Descriptor::Stderr => {
@@ -341,7 +381,9 @@ impl WasiCtxBuilder {
// We don't currently allow setting file descriptors other than 0-2, but this will avoid // We don't currently allow setting file descriptors other than 0-2, but this will avoid
// collisions if we restore that functionality in the future. // collisions if we restore that functionality in the future.
while fds.contains_key(&preopen_fd) { while fds.contains_key(&preopen_fd) {
preopen_fd = preopen_fd.checked_add(1).ok_or(Error::ENFILE)?; preopen_fd = preopen_fd
.checked_add(1)
.ok_or(WasiCtxBuilderError::TooManyFilesOpen)?;
} }
let mut fe = FdEntry::from(dir)?; let mut fe = FdEntry::from(dir)?;
fe.preopen_path = Some(guest_path); fe.preopen_path = Some(guest_path);
@@ -369,7 +411,7 @@ impl WasiCtx {
/// - Environment variables are inherited from the host process. /// - Environment variables are inherited from the host process.
/// ///
/// To override these behaviors, use `WasiCtxBuilder`. /// To override these behaviors, use `WasiCtxBuilder`.
pub fn new<S: AsRef<[u8]>>(args: impl IntoIterator<Item = S>) -> Result<Self> { pub fn new<S: AsRef<[u8]>>(args: impl IntoIterator<Item = S>) -> WasiCtxBuilderResult<Self> {
WasiCtxBuilder::new() WasiCtxBuilder::new()
.args(args) .args(args)
.inherit_stdio() .inherit_stdio()
@@ -383,30 +425,30 @@ impl WasiCtx {
} }
/// Get an immutable `FdEntry` corresponding to the specified raw WASI `fd`. /// Get an immutable `FdEntry` corresponding to the specified raw WASI `fd`.
pub(crate) unsafe fn get_fd_entry(&self, fd: wasi::__wasi_fd_t) -> Result<&FdEntry> { pub(crate) unsafe fn get_fd_entry(&self, fd: wasi::__wasi_fd_t) -> WasiResult<&FdEntry> {
self.fds.get(&fd).ok_or(Error::EBADF) self.fds.get(&fd).ok_or(WasiError::EBADF)
} }
/// Get a mutable `FdEntry` corresponding to the specified raw WASI `fd`. /// Get a mutable `FdEntry` corresponding to the specified raw WASI `fd`.
pub(crate) unsafe fn get_fd_entry_mut( pub(crate) unsafe fn get_fd_entry_mut(
&mut self, &mut self,
fd: wasi::__wasi_fd_t, fd: wasi::__wasi_fd_t,
) -> Result<&mut FdEntry> { ) -> WasiResult<&mut FdEntry> {
self.fds.get_mut(&fd).ok_or(Error::EBADF) self.fds.get_mut(&fd).ok_or(WasiError::EBADF)
} }
/// Insert the specified `FdEntry` into the `WasiCtx` object. /// Insert the specified `FdEntry` into the `WasiCtx` object.
/// ///
/// The `FdEntry` will automatically get another free raw WASI `fd` assigned. Note that /// The `FdEntry` 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. /// the two subsequent free raw WASI `fd`s do not have to be stored contiguously.
pub(crate) fn insert_fd_entry(&mut self, fe: FdEntry) -> Result<wasi::__wasi_fd_t> { pub(crate) fn insert_fd_entry(&mut self, fe: FdEntry) -> WasiResult<wasi::__wasi_fd_t> {
// Never insert where stdio handles are expected to be. // Never insert where stdio handles are expected to be.
let mut fd = 3; let mut fd = 3;
while self.fds.contains_key(&fd) { while self.fds.contains_key(&fd) {
if let Some(next_fd) = fd.checked_add(1) { if let Some(next_fd) = fd.checked_add(1) {
fd = next_fd; fd = next_fd;
} else { } else {
return Err(Error::EMFILE); return Err(WasiError::EMFILE);
} }
} }
self.fds.insert(fd, fe); self.fds.insert(fd, fe);
@@ -424,7 +466,7 @@ impl WasiCtx {
} }
/// Remove `FdEntry` corresponding to the specified raw WASI `fd` from the `WasiCtx` object. /// Remove `FdEntry` corresponding to the specified raw WASI `fd` from the `WasiCtx` object.
pub(crate) fn remove_fd_entry(&mut self, fd: wasi::__wasi_fd_t) -> Result<FdEntry> { pub(crate) fn remove_fd_entry(&mut self, fd: wasi::__wasi_fd_t) -> WasiResult<FdEntry> {
self.fds.remove(&fd).ok_or(Error::EBADF) self.fds.remove(&fd).ok_or(WasiError::EBADF)
} }
} }

View File

@@ -1,249 +0,0 @@
// Due to https://github.com/rust-lang/rust/issues/64247
#![allow(clippy::use_self)]
use crate::wasi;
use std::convert::Infallible;
use std::num::TryFromIntError;
use std::{ffi, str};
use thiserror::Error;
#[derive(Clone, Copy, Debug, Error, Eq, PartialEq)]
#[repr(u16)]
#[error("{:?} ({})", self, wasi::strerror(*self as wasi::__wasi_errno_t))]
pub enum WasiError {
ESUCCESS = wasi::__WASI_ERRNO_SUCCESS,
E2BIG = wasi::__WASI_ERRNO_2BIG,
EACCES = wasi::__WASI_ERRNO_ACCES,
EADDRINUSE = wasi::__WASI_ERRNO_ADDRINUSE,
EADDRNOTAVAIL = wasi::__WASI_ERRNO_ADDRNOTAVAIL,
EAFNOSUPPORT = wasi::__WASI_ERRNO_AFNOSUPPORT,
EAGAIN = wasi::__WASI_ERRNO_AGAIN,
EALREADY = wasi::__WASI_ERRNO_ALREADY,
EBADF = wasi::__WASI_ERRNO_BADF,
EBADMSG = wasi::__WASI_ERRNO_BADMSG,
EBUSY = wasi::__WASI_ERRNO_BUSY,
ECANCELED = wasi::__WASI_ERRNO_CANCELED,
ECHILD = wasi::__WASI_ERRNO_CHILD,
ECONNABORTED = wasi::__WASI_ERRNO_CONNABORTED,
ECONNREFUSED = wasi::__WASI_ERRNO_CONNREFUSED,
ECONNRESET = wasi::__WASI_ERRNO_CONNRESET,
EDEADLK = wasi::__WASI_ERRNO_DEADLK,
EDESTADDRREQ = wasi::__WASI_ERRNO_DESTADDRREQ,
EDOM = wasi::__WASI_ERRNO_DOM,
EDQUOT = wasi::__WASI_ERRNO_DQUOT,
EEXIST = wasi::__WASI_ERRNO_EXIST,
EFAULT = wasi::__WASI_ERRNO_FAULT,
EFBIG = wasi::__WASI_ERRNO_FBIG,
EHOSTUNREACH = wasi::__WASI_ERRNO_HOSTUNREACH,
EIDRM = wasi::__WASI_ERRNO_IDRM,
EILSEQ = wasi::__WASI_ERRNO_ILSEQ,
EINPROGRESS = wasi::__WASI_ERRNO_INPROGRESS,
EINTR = wasi::__WASI_ERRNO_INTR,
EINVAL = wasi::__WASI_ERRNO_INVAL,
EIO = wasi::__WASI_ERRNO_IO,
EISCONN = wasi::__WASI_ERRNO_ISCONN,
EISDIR = wasi::__WASI_ERRNO_ISDIR,
ELOOP = wasi::__WASI_ERRNO_LOOP,
EMFILE = wasi::__WASI_ERRNO_MFILE,
EMLINK = wasi::__WASI_ERRNO_MLINK,
EMSGSIZE = wasi::__WASI_ERRNO_MSGSIZE,
EMULTIHOP = wasi::__WASI_ERRNO_MULTIHOP,
ENAMETOOLONG = wasi::__WASI_ERRNO_NAMETOOLONG,
ENETDOWN = wasi::__WASI_ERRNO_NETDOWN,
ENETRESET = wasi::__WASI_ERRNO_NETRESET,
ENETUNREACH = wasi::__WASI_ERRNO_NETUNREACH,
ENFILE = wasi::__WASI_ERRNO_NFILE,
ENOBUFS = wasi::__WASI_ERRNO_NOBUFS,
ENODEV = wasi::__WASI_ERRNO_NODEV,
ENOENT = wasi::__WASI_ERRNO_NOENT,
ENOEXEC = wasi::__WASI_ERRNO_NOEXEC,
ENOLCK = wasi::__WASI_ERRNO_NOLCK,
ENOLINK = wasi::__WASI_ERRNO_NOLINK,
ENOMEM = wasi::__WASI_ERRNO_NOMEM,
ENOMSG = wasi::__WASI_ERRNO_NOMSG,
ENOPROTOOPT = wasi::__WASI_ERRNO_NOPROTOOPT,
ENOSPC = wasi::__WASI_ERRNO_NOSPC,
ENOSYS = wasi::__WASI_ERRNO_NOSYS,
ENOTCONN = wasi::__WASI_ERRNO_NOTCONN,
ENOTDIR = wasi::__WASI_ERRNO_NOTDIR,
ENOTEMPTY = wasi::__WASI_ERRNO_NOTEMPTY,
ENOTRECOVERABLE = wasi::__WASI_ERRNO_NOTRECOVERABLE,
ENOTSOCK = wasi::__WASI_ERRNO_NOTSOCK,
ENOTSUP = wasi::__WASI_ERRNO_NOTSUP,
ENOTTY = wasi::__WASI_ERRNO_NOTTY,
ENXIO = wasi::__WASI_ERRNO_NXIO,
EOVERFLOW = wasi::__WASI_ERRNO_OVERFLOW,
EOWNERDEAD = wasi::__WASI_ERRNO_OWNERDEAD,
EPERM = wasi::__WASI_ERRNO_PERM,
EPIPE = wasi::__WASI_ERRNO_PIPE,
EPROTO = wasi::__WASI_ERRNO_PROTO,
EPROTONOSUPPORT = wasi::__WASI_ERRNO_PROTONOSUPPORT,
EPROTOTYPE = wasi::__WASI_ERRNO_PROTOTYPE,
ERANGE = wasi::__WASI_ERRNO_RANGE,
EROFS = wasi::__WASI_ERRNO_ROFS,
ESPIPE = wasi::__WASI_ERRNO_SPIPE,
ESRCH = wasi::__WASI_ERRNO_SRCH,
ESTALE = wasi::__WASI_ERRNO_STALE,
ETIMEDOUT = wasi::__WASI_ERRNO_TIMEDOUT,
ETXTBSY = wasi::__WASI_ERRNO_TXTBSY,
EXDEV = wasi::__WASI_ERRNO_XDEV,
ENOTCAPABLE = wasi::__WASI_ERRNO_NOTCAPABLE,
}
impl WasiError {
pub fn as_raw_errno(self) -> wasi::__wasi_errno_t {
self as wasi::__wasi_errno_t
}
}
#[derive(Debug, Error)]
pub enum Error {
#[error("WASI error code: {0}")]
Wasi(#[from] WasiError),
#[error("IO error: {0}")]
Io(#[from] std::io::Error),
}
impl From<TryFromIntError> for Error {
fn from(_: TryFromIntError) -> Self {
Self::EOVERFLOW
}
}
impl From<Infallible> for Error {
fn from(_: Infallible) -> Self {
unreachable!()
}
}
impl From<str::Utf8Error> for Error {
fn from(_: str::Utf8Error) -> Self {
Self::EILSEQ
}
}
impl From<ffi::NulError> for Error {
fn from(_: ffi::NulError) -> Self {
Self::EILSEQ
}
}
impl From<&ffi::NulError> for Error {
fn from(_: &ffi::NulError) -> Self {
Self::EILSEQ
}
}
impl Error {
pub(crate) fn as_wasi_error(&self) -> WasiError {
match self {
Self::Wasi(err) => *err,
Self::Io(err) => {
let err = match err.raw_os_error() {
Some(code) => Self::from_raw_os_error(code),
None => {
log::debug!("Inconvertible OS error: {}", err);
Self::EIO
}
};
err.as_wasi_error()
}
}
}
pub const ESUCCESS: Self = Error::Wasi(WasiError::ESUCCESS);
pub const E2BIG: Self = Error::Wasi(WasiError::E2BIG);
pub const EACCES: Self = Error::Wasi(WasiError::EACCES);
pub const EADDRINUSE: Self = Error::Wasi(WasiError::EADDRINUSE);
pub const EADDRNOTAVAIL: Self = Error::Wasi(WasiError::EADDRNOTAVAIL);
pub const EAFNOSUPPORT: Self = Error::Wasi(WasiError::EAFNOSUPPORT);
pub const EAGAIN: Self = Error::Wasi(WasiError::EAGAIN);
pub const EALREADY: Self = Error::Wasi(WasiError::EALREADY);
pub const EBADF: Self = Error::Wasi(WasiError::EBADF);
pub const EBADMSG: Self = Error::Wasi(WasiError::EBADMSG);
pub const EBUSY: Self = Error::Wasi(WasiError::EBUSY);
pub const ECANCELED: Self = Error::Wasi(WasiError::ECANCELED);
pub const ECHILD: Self = Error::Wasi(WasiError::ECHILD);
pub const ECONNABORTED: Self = Error::Wasi(WasiError::ECONNABORTED);
pub const ECONNREFUSED: Self = Error::Wasi(WasiError::ECONNREFUSED);
pub const ECONNRESET: Self = Error::Wasi(WasiError::ECONNRESET);
pub const EDEADLK: Self = Error::Wasi(WasiError::EDEADLK);
pub const EDESTADDRREQ: Self = Error::Wasi(WasiError::EDESTADDRREQ);
pub const EDOM: Self = Error::Wasi(WasiError::EDOM);
pub const EDQUOT: Self = Error::Wasi(WasiError::EDQUOT);
pub const EEXIST: Self = Error::Wasi(WasiError::EEXIST);
pub const EFAULT: Self = Error::Wasi(WasiError::EFAULT);
pub const EFBIG: Self = Error::Wasi(WasiError::EFBIG);
pub const EHOSTUNREACH: Self = Error::Wasi(WasiError::EHOSTUNREACH);
pub const EIDRM: Self = Error::Wasi(WasiError::EIDRM);
pub const EILSEQ: Self = Error::Wasi(WasiError::EILSEQ);
pub const EINPROGRESS: Self = Error::Wasi(WasiError::EINPROGRESS);
pub const EINTR: Self = Error::Wasi(WasiError::EINTR);
pub const EINVAL: Self = Error::Wasi(WasiError::EINVAL);
pub const EIO: Self = Error::Wasi(WasiError::EIO);
pub const EISCONN: Self = Error::Wasi(WasiError::EISCONN);
pub const EISDIR: Self = Error::Wasi(WasiError::EISDIR);
pub const ELOOP: Self = Error::Wasi(WasiError::ELOOP);
pub const EMFILE: Self = Error::Wasi(WasiError::EMFILE);
pub const EMLINK: Self = Error::Wasi(WasiError::EMLINK);
pub const EMSGSIZE: Self = Error::Wasi(WasiError::EMSGSIZE);
pub const EMULTIHOP: Self = Error::Wasi(WasiError::EMULTIHOP);
pub const ENAMETOOLONG: Self = Error::Wasi(WasiError::ENAMETOOLONG);
pub const ENETDOWN: Self = Error::Wasi(WasiError::ENETDOWN);
pub const ENETRESET: Self = Error::Wasi(WasiError::ENETRESET);
pub const ENETUNREACH: Self = Error::Wasi(WasiError::ENETUNREACH);
pub const ENFILE: Self = Error::Wasi(WasiError::ENFILE);
pub const ENOBUFS: Self = Error::Wasi(WasiError::ENOBUFS);
pub const ENODEV: Self = Error::Wasi(WasiError::ENODEV);
pub const ENOENT: Self = Error::Wasi(WasiError::ENOENT);
pub const ENOEXEC: Self = Error::Wasi(WasiError::ENOEXEC);
pub const ENOLCK: Self = Error::Wasi(WasiError::ENOLCK);
pub const ENOLINK: Self = Error::Wasi(WasiError::ENOLINK);
pub const ENOMEM: Self = Error::Wasi(WasiError::ENOMEM);
pub const ENOMSG: Self = Error::Wasi(WasiError::ENOMSG);
pub const ENOPROTOOPT: Self = Error::Wasi(WasiError::ENOPROTOOPT);
pub const ENOSPC: Self = Error::Wasi(WasiError::ENOSPC);
pub const ENOSYS: Self = Error::Wasi(WasiError::ENOSYS);
pub const ENOTCONN: Self = Error::Wasi(WasiError::ENOTCONN);
pub const ENOTDIR: Self = Error::Wasi(WasiError::ENOTDIR);
pub const ENOTEMPTY: Self = Error::Wasi(WasiError::ENOTEMPTY);
pub const ENOTRECOVERABLE: Self = Error::Wasi(WasiError::ENOTRECOVERABLE);
pub const ENOTSOCK: Self = Error::Wasi(WasiError::ENOTSOCK);
pub const ENOTSUP: Self = Error::Wasi(WasiError::ENOTSUP);
pub const ENOTTY: Self = Error::Wasi(WasiError::ENOTTY);
pub const ENXIO: Self = Error::Wasi(WasiError::ENXIO);
pub const EOVERFLOW: Self = Error::Wasi(WasiError::EOVERFLOW);
pub const EOWNERDEAD: Self = Error::Wasi(WasiError::EOWNERDEAD);
pub const EPERM: Self = Error::Wasi(WasiError::EPERM);
pub const EPIPE: Self = Error::Wasi(WasiError::EPIPE);
pub const EPROTO: Self = Error::Wasi(WasiError::EPROTO);
pub const EPROTONOSUPPORT: Self = Error::Wasi(WasiError::EPROTONOSUPPORT);
pub const EPROTOTYPE: Self = Error::Wasi(WasiError::EPROTOTYPE);
pub const ERANGE: Self = Error::Wasi(WasiError::ERANGE);
pub const EROFS: Self = Error::Wasi(WasiError::EROFS);
pub const ESPIPE: Self = Error::Wasi(WasiError::ESPIPE);
pub const ESRCH: Self = Error::Wasi(WasiError::ESRCH);
pub const ESTALE: Self = Error::Wasi(WasiError::ESTALE);
pub const ETIMEDOUT: Self = Error::Wasi(WasiError::ETIMEDOUT);
pub const ETXTBSY: Self = Error::Wasi(WasiError::ETXTBSY);
pub const EXDEV: Self = Error::Wasi(WasiError::EXDEV);
pub const ENOTCAPABLE: Self = Error::Wasi(WasiError::ENOTCAPABLE);
}
pub(crate) trait FromRawOsError {
fn from_raw_os_error(code: i32) -> Self;
}
pub(crate) type Result<T> = std::result::Result<T, Error>;
pub(crate) trait AsWasiError {
fn as_wasi_error(&self) -> WasiError;
}
impl<T> AsWasiError for Result<T> {
fn as_wasi_error(&self) -> WasiError {
self.as_ref()
.err()
.unwrap_or(&Error::ESUCCESS)
.as_wasi_error()
}
}

View File

@@ -3,7 +3,7 @@ use crate::sys::fdentry_impl::{
descriptor_as_oshandle, determine_type_and_access_rights, OsHandle, descriptor_as_oshandle, determine_type_and_access_rights, OsHandle,
}; };
use crate::virtfs::VirtualFile; use crate::virtfs::VirtualFile;
use crate::{wasi, Error, Result}; use crate::wasi::{self, WasiError, WasiResult};
use std::marker::PhantomData; use std::marker::PhantomData;
use std::mem::ManuallyDrop; use std::mem::ManuallyDrop;
use std::ops::{Deref, DerefMut}; use std::ops::{Deref, DerefMut};
@@ -56,22 +56,22 @@ impl Descriptor {
/// Return a reference to the `OsHandle` or `VirtualFile` treating it as an /// Return a reference to the `OsHandle` or `VirtualFile` treating it as an
/// actual file/dir, and allowing operations which require an actual file and /// actual file/dir, and allowing operations which require an actual file and
/// not just a stream or socket file descriptor. /// not just a stream or socket file descriptor.
pub(crate) fn as_file<'descriptor>(&'descriptor self) -> Result<&'descriptor Descriptor> { pub(crate) fn as_file<'descriptor>(&'descriptor self) -> WasiResult<&'descriptor Descriptor> {
match self { match self {
Self::OsHandle(_) => Ok(self), Self::OsHandle(_) => Ok(self),
Self::VirtualFile(_) => Ok(self), Self::VirtualFile(_) => Ok(self),
_ => Err(Error::EBADF), _ => Err(WasiError::EBADF),
} }
} }
/// Like `as_file`, but return a mutable reference. /// Like `as_file`, but return a mutable reference.
pub(crate) fn as_file_mut<'descriptor>( pub(crate) fn as_file_mut<'descriptor>(
&'descriptor mut self, &'descriptor mut self,
) -> Result<&'descriptor mut Descriptor> { ) -> WasiResult<&'descriptor mut Descriptor> {
match self { match self {
Self::OsHandle(_) => Ok(self), Self::OsHandle(_) => Ok(self),
Self::VirtualFile(_) => Ok(self), Self::VirtualFile(_) => Ok(self),
_ => Err(Error::EBADF), _ => Err(WasiError::EBADF),
} }
} }
@@ -100,7 +100,7 @@ pub(crate) struct FdEntry {
} }
impl FdEntry { impl FdEntry {
pub(crate) fn from(file: Descriptor) -> Result<Self> { pub(crate) fn from(file: Descriptor) -> io::Result<Self> {
match file { match file {
Descriptor::OsHandle(handle) => unsafe { determine_type_and_access_rights(&handle) } Descriptor::OsHandle(handle) => unsafe { determine_type_and_access_rights(&handle) }
.map(|(file_type, rights_base, rights_inheriting)| Self { .map(|(file_type, rights_base, rights_inheriting)| Self {
@@ -129,7 +129,7 @@ impl FdEntry {
} }
} }
pub(crate) fn duplicate_stdin() -> Result<Self> { pub(crate) fn duplicate_stdin() -> io::Result<Self> {
unsafe { determine_type_and_access_rights(&io::stdin()) }.map( unsafe { determine_type_and_access_rights(&io::stdin()) }.map(
|(file_type, rights_base, rights_inheriting)| Self { |(file_type, rights_base, rights_inheriting)| Self {
file_type, file_type,
@@ -141,7 +141,7 @@ impl FdEntry {
) )
} }
pub(crate) fn duplicate_stdout() -> Result<Self> { pub(crate) fn duplicate_stdout() -> io::Result<Self> {
unsafe { determine_type_and_access_rights(&io::stdout()) }.map( unsafe { determine_type_and_access_rights(&io::stdout()) }.map(
|(file_type, rights_base, rights_inheriting)| Self { |(file_type, rights_base, rights_inheriting)| Self {
file_type, file_type,
@@ -153,7 +153,7 @@ impl FdEntry {
) )
} }
pub(crate) fn duplicate_stderr() -> Result<Self> { pub(crate) fn duplicate_stderr() -> io::Result<Self> {
unsafe { determine_type_and_access_rights(&io::stderr()) }.map( unsafe { determine_type_and_access_rights(&io::stderr()) }.map(
|(file_type, rights_base, rights_inheriting)| Self { |(file_type, rights_base, rights_inheriting)| Self {
file_type, file_type,
@@ -165,7 +165,7 @@ impl FdEntry {
) )
} }
pub(crate) fn null() -> Result<Self> { pub(crate) fn null() -> io::Result<Self> {
Self::from(OsHandle::from(dev_null()?).into()) Self::from(OsHandle::from(dev_null()?).into())
} }
@@ -175,12 +175,12 @@ impl FdEntry {
/// The `FdEntry` can only be converted into a valid `Descriptor` object if /// The `FdEntry` can only be converted into a valid `Descriptor` object if
/// the specified set of base rights `rights_base`, and inheriting rights `rights_inheriting` /// the specified set of base rights `rights_base`, and inheriting rights `rights_inheriting`
/// is a subset of rights attached to this `FdEntry`. The check is performed using /// is a subset of rights attached to this `FdEntry`. The check is performed using
/// `FdEntry::validate_rights` method. If the check fails, `Error::ENOTCAPABLE` is returned. /// `FdEntry::validate_rights` method. If the check fails, `WasiError::ENOTCAPABLE` is returned.
pub(crate) fn as_descriptor( pub(crate) fn as_descriptor(
&self, &self,
rights_base: wasi::__wasi_rights_t, rights_base: wasi::__wasi_rights_t,
rights_inheriting: wasi::__wasi_rights_t, rights_inheriting: wasi::__wasi_rights_t,
) -> Result<&Descriptor> { ) -> WasiResult<&Descriptor> {
self.validate_rights(rights_base, rights_inheriting)?; self.validate_rights(rights_base, rights_inheriting)?;
Ok(&self.descriptor) Ok(&self.descriptor)
} }
@@ -191,12 +191,12 @@ impl FdEntry {
/// The `FdEntry` can only be converted into a valid `Descriptor` object if /// The `FdEntry` can only be converted into a valid `Descriptor` object if
/// the specified set of base rights `rights_base`, and inheriting rights `rights_inheriting` /// the specified set of base rights `rights_base`, and inheriting rights `rights_inheriting`
/// is a subset of rights attached to this `FdEntry`. The check is performed using /// is a subset of rights attached to this `FdEntry`. The check is performed using
/// `FdEntry::validate_rights` method. If the check fails, `Error::ENOTCAPABLE` is returned. /// `FdEntry::validate_rights` method. If the check fails, `WasiError::ENOTCAPABLE` is returned.
pub(crate) fn as_descriptor_mut( pub(crate) fn as_descriptor_mut(
&mut self, &mut self,
rights_base: wasi::__wasi_rights_t, rights_base: wasi::__wasi_rights_t,
rights_inheriting: wasi::__wasi_rights_t, rights_inheriting: wasi::__wasi_rights_t,
) -> Result<&mut Descriptor> { ) -> WasiResult<&mut Descriptor> {
self.validate_rights(rights_base, rights_inheriting)?; self.validate_rights(rights_base, rights_inheriting)?;
Ok(&mut self.descriptor) Ok(&mut self.descriptor)
} }
@@ -205,12 +205,12 @@ impl FdEntry {
/// inheriting rights `rights_inheriting`; i.e., if rights attached to this `FdEntry` object /// inheriting rights `rights_inheriting`; i.e., if rights attached to this `FdEntry` object
/// are a superset. /// are a superset.
/// ///
/// Upon unsuccessful check, `Error::ENOTCAPABLE` is returned. /// Upon unsuccessful check, `WasiError::ENOTCAPABLE` is returned.
fn validate_rights( fn validate_rights(
&self, &self,
rights_base: wasi::__wasi_rights_t, rights_base: wasi::__wasi_rights_t,
rights_inheriting: wasi::__wasi_rights_t, rights_inheriting: wasi::__wasi_rights_t,
) -> Result<()> { ) -> WasiResult<()> {
let missing_base = !self.rights_base & rights_base; let missing_base = !self.rights_base & rights_base;
let missing_inheriting = !self.rights_inheriting & rights_inheriting; let missing_inheriting = !self.rights_inheriting & rights_inheriting;
if missing_base != 0 || missing_inheriting != 0 { if missing_base != 0 || missing_inheriting != 0 {
@@ -226,7 +226,7 @@ impl FdEntry {
missing_base, missing_base,
missing_inheriting missing_inheriting
); );
Err(Error::ENOTCAPABLE) Err(WasiError::ENOTCAPABLE)
} else { } else {
Ok(()) Ok(())
} }

View File

@@ -1,5 +1,6 @@
use crate::fs::Metadata; use crate::fs::Metadata;
use crate::{host, hostcalls, hostcalls_impl, wasi, Result, WasiCtx}; use crate::wasi::{self, WasiResult};
use crate::{host, hostcalls, hostcalls_impl, WasiCtx};
use std::io; use std::io;
/// A reference to an open file on the filesystem. /// A reference to an open file on the filesystem.
@@ -34,7 +35,7 @@ impl<'ctx> File<'ctx> {
/// This corresponds to [`std::fs::File::sync_all`]. /// This corresponds to [`std::fs::File::sync_all`].
/// ///
/// [`std::fs::File::sync_all`]: https://doc.rust-lang.org/std/fs/struct.File.html#method.sync_all /// [`std::fs::File::sync_all`]: https://doc.rust-lang.org/std/fs/struct.File.html#method.sync_all
pub fn sync_all(&self) -> Result<()> { pub fn sync_all(&self) -> WasiResult<()> {
unsafe { unsafe {
hostcalls_impl::fd_sync(self.ctx, &mut [], self.fd)?; hostcalls_impl::fd_sync(self.ctx, &mut [], self.fd)?;
} }
@@ -47,7 +48,7 @@ impl<'ctx> File<'ctx> {
/// This corresponds to [`std::fs::File::sync_data`]. /// This corresponds to [`std::fs::File::sync_data`].
/// ///
/// [`std::fs::File::sync_data`]: https://doc.rust-lang.org/std/fs/struct.File.html#method.sync_data /// [`std::fs::File::sync_data`]: https://doc.rust-lang.org/std/fs/struct.File.html#method.sync_data
pub fn sync_data(&self) -> Result<()> { pub fn sync_data(&self) -> WasiResult<()> {
unsafe { unsafe {
hostcalls_impl::fd_datasync(self.ctx, &mut [], self.fd)?; hostcalls_impl::fd_datasync(self.ctx, &mut [], self.fd)?;
} }
@@ -60,7 +61,7 @@ impl<'ctx> File<'ctx> {
/// This corresponds to [`std::fs::File::set_len`]. /// This corresponds to [`std::fs::File::set_len`].
/// ///
/// [`std::fs::File::set_len`]: https://doc.rust-lang.org/std/fs/struct.File.html#method.set_len /// [`std::fs::File::set_len`]: https://doc.rust-lang.org/std/fs/struct.File.html#method.set_len
pub fn set_len(&self, size: u64) -> Result<()> { pub fn set_len(&self, size: u64) -> WasiResult<()> {
unsafe { unsafe {
hostcalls_impl::fd_filestat_set_size(self.ctx, &mut [], self.fd, size)?; hostcalls_impl::fd_filestat_set_size(self.ctx, &mut [], self.fd, size)?;
} }
@@ -72,7 +73,7 @@ impl<'ctx> File<'ctx> {
/// This corresponds to [`std::fs::File::metadata`]. /// This corresponds to [`std::fs::File::metadata`].
/// ///
/// [`std::fs::File::metadata`]: https://doc.rust-lang.org/std/fs/struct.File.html#method.metadata /// [`std::fs::File::metadata`]: https://doc.rust-lang.org/std/fs/struct.File.html#method.metadata
pub fn metadata(&self) -> Result<Metadata> { pub fn metadata(&self) -> WasiResult<Metadata> {
Ok(Metadata {}) Ok(Metadata {})
} }
} }

View File

@@ -1,10 +1,11 @@
use crate::{Error, Result}; use crate::wasi::WasiResult;
use std::str; use std::str;
/// Creates not-owned WASI path from byte slice. /// Creates not-owned WASI path from byte slice.
/// ///
/// NB WASI spec requires bytes to be valid UTF-8. Otherwise, /// NB WASI spec requires bytes to be valid UTF-8. Otherwise,
/// `__WASI_ERRNO_ILSEQ` error is returned. /// `__WASI_ERRNO_ILSEQ` error is returned.
pub(crate) fn path_from_slice<'a>(s: &'a [u8]) -> Result<&'a str> { pub(crate) fn path_from_slice<'a>(s: &'a [u8]) -> WasiResult<&'a str> {
str::from_utf8(s).map_err(|_| Error::EILSEQ) let s = str::from_utf8(s)?;
Ok(s)
} }

View File

@@ -5,7 +5,6 @@
#![allow(non_snake_case)] #![allow(non_snake_case)]
use crate::wasi::*; use crate::wasi::*;
use crate::{Error, Result};
use std::{convert::TryInto, io, mem, slice}; use std::{convert::TryInto, io, mem, slice};
use wig::witx_host_types; use wig::witx_host_types;
@@ -67,11 +66,13 @@ pub struct Dirent {
impl Dirent { impl Dirent {
/// Serialize the directory entry to the format define by `__wasi_fd_readdir`, /// Serialize the directory entry to the format define by `__wasi_fd_readdir`,
/// so that the serialized entries can be concatenated by the implementation. /// so that the serialized entries can be concatenated by the implementation.
pub fn to_wasi_raw(&self) -> Result<Vec<u8>> { pub fn to_wasi_raw(&self) -> WasiResult<Vec<u8>> {
let name = self.name.as_bytes(); let name = self.name.as_bytes();
let namlen = name.len(); let namlen = name.len();
let dirent_size = mem::size_of::<__wasi_dirent_t>(); let dirent_size = mem::size_of::<__wasi_dirent_t>();
let offset = dirent_size.checked_add(namlen).ok_or(Error::EOVERFLOW)?; let offset = dirent_size
.checked_add(namlen)
.ok_or(WasiError::EOVERFLOW)?;
let mut raw = Vec::<u8>::with_capacity(offset); let mut raw = Vec::<u8>::with_capacity(offset);
raw.resize(offset, 0); raw.resize(offset, 0);

View File

@@ -8,7 +8,8 @@ use crate::memory::*;
use crate::sandboxed_tty_writer::SandboxedTTYWriter; use crate::sandboxed_tty_writer::SandboxedTTYWriter;
use crate::sys::hostcalls_impl::fs_helpers::path_open_rights; use crate::sys::hostcalls_impl::fs_helpers::path_open_rights;
use crate::sys::{host_impl, hostcalls_impl}; use crate::sys::{host_impl, hostcalls_impl};
use crate::{helpers, host, wasi, wasi32, Error, Result}; use crate::wasi::{self, WasiError, WasiResult};
use crate::{helpers, host, wasi32};
use filetime::{set_file_handle_times, FileTime}; use filetime::{set_file_handle_times, FileTime};
use log::trace; use log::trace;
use std::convert::TryInto; use std::convert::TryInto;
@@ -20,13 +21,13 @@ pub(crate) unsafe fn fd_close(
wasi_ctx: &mut WasiCtx, wasi_ctx: &mut WasiCtx,
_memory: &mut [u8], _memory: &mut [u8],
fd: wasi::__wasi_fd_t, fd: wasi::__wasi_fd_t,
) -> Result<()> { ) -> WasiResult<()> {
trace!("fd_close(fd={:?})", fd); trace!("fd_close(fd={:?})", fd);
if let Ok(fe) = wasi_ctx.get_fd_entry(fd) { if let Ok(fe) = wasi_ctx.get_fd_entry(fd) {
// can't close preopened files // can't close preopened files
if fe.preopen_path.is_some() { if fe.preopen_path.is_some() {
return Err(Error::ENOTSUP); return Err(WasiError::ENOTSUP);
} }
} }
@@ -38,7 +39,7 @@ pub(crate) unsafe fn fd_datasync(
wasi_ctx: &WasiCtx, wasi_ctx: &WasiCtx,
_memory: &mut [u8], _memory: &mut [u8],
fd: wasi::__wasi_fd_t, fd: wasi::__wasi_fd_t,
) -> Result<()> { ) -> WasiResult<()> {
trace!("fd_datasync(fd={:?})", fd); trace!("fd_datasync(fd={:?})", fd);
let file = wasi_ctx let file = wasi_ctx
@@ -60,7 +61,7 @@ pub(crate) unsafe fn fd_pread(
iovs_len: wasi32::size_t, iovs_len: wasi32::size_t,
offset: wasi::__wasi_filesize_t, offset: wasi::__wasi_filesize_t,
nread: wasi32::uintptr_t, nread: wasi32::uintptr_t,
) -> Result<()> { ) -> WasiResult<()> {
trace!( trace!(
"fd_pread(fd={:?}, iovs_ptr={:#x?}, iovs_len={:?}, offset={}, nread={:#x?})", "fd_pread(fd={:?}, iovs_ptr={:#x?}, iovs_len={:?}, offset={}, nread={:#x?})",
fd, fd,
@@ -78,7 +79,7 @@ pub(crate) unsafe fn fd_pread(
let iovs = dec_iovec_slice(memory, iovs_ptr, iovs_len)?; let iovs = dec_iovec_slice(memory, iovs_ptr, iovs_len)?;
if offset > i64::max_value() as u64 { if offset > i64::max_value() as u64 {
return Err(Error::EIO); return Err(WasiError::EIO);
} }
let buf_size = iovs let buf_size = iovs
.iter() .iter()
@@ -90,7 +91,7 @@ pub(crate) unsafe fn fd_pread(
cast_iovlen cast_iovlen
}) })
.fold(Some(0u32), |len, iov| len.and_then(|x| x.checked_add(iov))) .fold(Some(0u32), |len, iov| len.and_then(|x| x.checked_add(iov)))
.ok_or(Error::EINVAL)?; .ok_or(WasiError::EINVAL)?;
let mut buf = vec![0; buf_size as usize]; let mut buf = vec![0; buf_size as usize];
let host_nread = match file { let host_nread = match file {
Descriptor::OsHandle(fd) => hostcalls_impl::fd_pread(&fd, &mut buf, offset)?, Descriptor::OsHandle(fd) => hostcalls_impl::fd_pread(&fd, &mut buf, offset)?,
@@ -128,7 +129,7 @@ pub(crate) unsafe fn fd_pwrite(
iovs_len: wasi32::size_t, iovs_len: wasi32::size_t,
offset: wasi::__wasi_filesize_t, offset: wasi::__wasi_filesize_t,
nwritten: wasi32::uintptr_t, nwritten: wasi32::uintptr_t,
) -> Result<()> { ) -> WasiResult<()> {
trace!( trace!(
"fd_pwrite(fd={:?}, iovs_ptr={:#x?}, iovs_len={:?}, offset={}, nwritten={:#x?})", "fd_pwrite(fd={:?}, iovs_ptr={:#x?}, iovs_len={:?}, offset={}, nwritten={:#x?})",
fd, fd,
@@ -148,7 +149,7 @@ pub(crate) unsafe fn fd_pwrite(
let iovs = dec_ciovec_slice(memory, iovs_ptr, iovs_len)?; let iovs = dec_ciovec_slice(memory, iovs_ptr, iovs_len)?;
if offset > i64::max_value() as u64 { if offset > i64::max_value() as u64 {
return Err(Error::EIO); return Err(WasiError::EIO);
} }
let buf_size = iovs let buf_size = iovs
.iter() .iter()
@@ -160,7 +161,7 @@ pub(crate) unsafe fn fd_pwrite(
cast_iovlen cast_iovlen
}) })
.fold(Some(0u32), |len, iov| len.and_then(|x| x.checked_add(iov))) .fold(Some(0u32), |len, iov| len.and_then(|x| x.checked_add(iov)))
.ok_or(Error::EINVAL)?; .ok_or(WasiError::EINVAL)?;
let mut buf = Vec::with_capacity(buf_size as usize); let mut buf = Vec::with_capacity(buf_size as usize);
for iov in &iovs { for iov in &iovs {
buf.extend_from_slice(std::slice::from_raw_parts( buf.extend_from_slice(std::slice::from_raw_parts(
@@ -190,7 +191,7 @@ pub(crate) unsafe fn fd_read(
iovs_ptr: wasi32::uintptr_t, iovs_ptr: wasi32::uintptr_t,
iovs_len: wasi32::size_t, iovs_len: wasi32::size_t,
nread: wasi32::uintptr_t, nread: wasi32::uintptr_t,
) -> Result<()> { ) -> WasiResult<()> {
trace!( trace!(
"fd_read(fd={:?}, iovs_ptr={:#x?}, iovs_len={:?}, nread={:#x?})", "fd_read(fd={:?}, iovs_ptr={:#x?}, iovs_len={:?}, nread={:#x?})",
fd, fd,
@@ -212,7 +213,7 @@ pub(crate) unsafe fn fd_read(
Descriptor::OsHandle(file) => file.read_vectored(&mut iovs).map_err(Into::into), Descriptor::OsHandle(file) => file.read_vectored(&mut iovs).map_err(Into::into),
Descriptor::VirtualFile(virt) => virt.read_vectored(&mut iovs), Descriptor::VirtualFile(virt) => virt.read_vectored(&mut iovs),
Descriptor::Stdin => io::stdin().read_vectored(&mut iovs).map_err(Into::into), Descriptor::Stdin => io::stdin().read_vectored(&mut iovs).map_err(Into::into),
_ => return Err(Error::EBADF), _ => return Err(WasiError::EBADF),
}; };
let host_nread = maybe_host_nread?; let host_nread = maybe_host_nread?;
@@ -227,11 +228,11 @@ pub(crate) unsafe fn fd_renumber(
_memory: &mut [u8], _memory: &mut [u8],
from: wasi::__wasi_fd_t, from: wasi::__wasi_fd_t,
to: wasi::__wasi_fd_t, to: wasi::__wasi_fd_t,
) -> Result<()> { ) -> WasiResult<()> {
trace!("fd_renumber(from={:?}, to={:?})", from, to); trace!("fd_renumber(from={:?}, to={:?})", from, to);
if !wasi_ctx.contains_fd_entry(from) { if !wasi_ctx.contains_fd_entry(from) {
return Err(Error::EBADF); return Err(WasiError::EBADF);
} }
// Don't allow renumbering over a pre-opened resource. // Don't allow renumbering over a pre-opened resource.
@@ -239,11 +240,11 @@ pub(crate) unsafe fn fd_renumber(
// userspace is capable of removing entries from its tables as well. // userspace is capable of removing entries from its tables as well.
let from_fe = wasi_ctx.get_fd_entry(from)?; let from_fe = wasi_ctx.get_fd_entry(from)?;
if from_fe.preopen_path.is_some() { if from_fe.preopen_path.is_some() {
return Err(Error::ENOTSUP); return Err(WasiError::ENOTSUP);
} }
if let Ok(to_fe) = wasi_ctx.get_fd_entry(to) { if let Ok(to_fe) = wasi_ctx.get_fd_entry(to) {
if to_fe.preopen_path.is_some() { if to_fe.preopen_path.is_some() {
return Err(Error::ENOTSUP); return Err(WasiError::ENOTSUP);
} }
} }
@@ -260,7 +261,7 @@ pub(crate) unsafe fn fd_seek(
offset: wasi::__wasi_filedelta_t, offset: wasi::__wasi_filedelta_t,
whence: wasi::__wasi_whence_t, whence: wasi::__wasi_whence_t,
newoffset: wasi32::uintptr_t, newoffset: wasi32::uintptr_t,
) -> Result<()> { ) -> WasiResult<()> {
trace!( trace!(
"fd_seek(fd={:?}, offset={:?}, whence={}, newoffset={:#x?})", "fd_seek(fd={:?}, offset={:?}, whence={}, newoffset={:#x?})",
fd, fd,
@@ -283,7 +284,7 @@ pub(crate) unsafe fn fd_seek(
wasi::__WASI_WHENCE_CUR => SeekFrom::Current(offset), wasi::__WASI_WHENCE_CUR => SeekFrom::Current(offset),
wasi::__WASI_WHENCE_END => SeekFrom::End(offset), wasi::__WASI_WHENCE_END => SeekFrom::End(offset),
wasi::__WASI_WHENCE_SET => SeekFrom::Start(offset as u64), wasi::__WASI_WHENCE_SET => SeekFrom::Start(offset as u64),
_ => return Err(Error::EINVAL), _ => return Err(WasiError::EINVAL),
}; };
let host_newoffset = match file { let host_newoffset = match file {
Descriptor::OsHandle(fd) => fd.seek(pos)?, Descriptor::OsHandle(fd) => fd.seek(pos)?,
@@ -305,7 +306,7 @@ pub(crate) unsafe fn fd_tell(
memory: &mut [u8], memory: &mut [u8],
fd: wasi::__wasi_fd_t, fd: wasi::__wasi_fd_t,
newoffset: wasi32::uintptr_t, newoffset: wasi32::uintptr_t,
) -> Result<()> { ) -> WasiResult<()> {
trace!("fd_tell(fd={:?}, newoffset={:#x?})", fd, newoffset); trace!("fd_tell(fd={:?}, newoffset={:#x?})", fd, newoffset);
let file = wasi_ctx let file = wasi_ctx
@@ -333,7 +334,7 @@ pub(crate) unsafe fn fd_fdstat_get(
memory: &mut [u8], memory: &mut [u8],
fd: wasi::__wasi_fd_t, fd: wasi::__wasi_fd_t,
fdstat_ptr: wasi32::uintptr_t, // *mut wasi::__wasi_fdstat_t fdstat_ptr: wasi32::uintptr_t, // *mut wasi::__wasi_fdstat_t
) -> Result<()> { ) -> WasiResult<()> {
trace!("fd_fdstat_get(fd={:?}, fdstat_ptr={:#x?})", fd, fdstat_ptr); trace!("fd_fdstat_get(fd={:?}, fdstat_ptr={:#x?})", fd, fdstat_ptr);
let mut fdstat = dec_fdstat_byref(memory, fdstat_ptr)?; let mut fdstat = dec_fdstat_byref(memory, fdstat_ptr)?;
@@ -361,7 +362,7 @@ pub(crate) unsafe fn fd_fdstat_set_flags(
_memory: &mut [u8], _memory: &mut [u8],
fd: wasi::__wasi_fd_t, fd: wasi::__wasi_fd_t,
fdflags: wasi::__wasi_fdflags_t, fdflags: wasi::__wasi_fdflags_t,
) -> Result<()> { ) -> WasiResult<()> {
trace!("fd_fdstat_set_flags(fd={:?}, fdflags={:#x?})", fd, fdflags); trace!("fd_fdstat_set_flags(fd={:?}, fdflags={:#x?})", fd, fdflags);
let descriptor = wasi_ctx let descriptor = wasi_ctx
@@ -400,7 +401,7 @@ pub(crate) unsafe fn fd_fdstat_set_rights(
fd: wasi::__wasi_fd_t, fd: wasi::__wasi_fd_t,
fs_rights_base: wasi::__wasi_rights_t, fs_rights_base: wasi::__wasi_rights_t,
fs_rights_inheriting: wasi::__wasi_rights_t, fs_rights_inheriting: wasi::__wasi_rights_t,
) -> Result<()> { ) -> WasiResult<()> {
trace!( trace!(
"fd_fdstat_set_rights(fd={:?}, fs_rights_base={:#x?}, fs_rights_inheriting={:#x?})", "fd_fdstat_set_rights(fd={:?}, fs_rights_base={:#x?}, fs_rights_inheriting={:#x?})",
fd, fd,
@@ -412,7 +413,7 @@ pub(crate) unsafe fn fd_fdstat_set_rights(
if fe.rights_base & fs_rights_base != fs_rights_base if fe.rights_base & fs_rights_base != fs_rights_base
|| fe.rights_inheriting & fs_rights_inheriting != fs_rights_inheriting || fe.rights_inheriting & fs_rights_inheriting != fs_rights_inheriting
{ {
return Err(Error::ENOTCAPABLE); return Err(WasiError::ENOTCAPABLE);
} }
fe.rights_base = fs_rights_base; fe.rights_base = fs_rights_base;
fe.rights_inheriting = fs_rights_inheriting; fe.rights_inheriting = fs_rights_inheriting;
@@ -424,7 +425,7 @@ pub(crate) unsafe fn fd_sync(
wasi_ctx: &WasiCtx, wasi_ctx: &WasiCtx,
_memory: &mut [u8], _memory: &mut [u8],
fd: wasi::__wasi_fd_t, fd: wasi::__wasi_fd_t,
) -> Result<()> { ) -> WasiResult<()> {
trace!("fd_sync(fd={:?})", fd); trace!("fd_sync(fd={:?})", fd);
let file = wasi_ctx let file = wasi_ctx
@@ -449,7 +450,7 @@ pub(crate) unsafe fn fd_write(
iovs_ptr: wasi32::uintptr_t, iovs_ptr: wasi32::uintptr_t,
iovs_len: wasi32::size_t, iovs_len: wasi32::size_t,
nwritten: wasi32::uintptr_t, nwritten: wasi32::uintptr_t,
) -> Result<()> { ) -> WasiResult<()> {
trace!( trace!(
"fd_write(fd={:?}, iovs_ptr={:#x?}, iovs_len={:?}, nwritten={:#x?})", "fd_write(fd={:?}, iovs_ptr={:#x?}, iovs_len={:?}, nwritten={:#x?})",
fd, fd,
@@ -480,7 +481,7 @@ pub(crate) unsafe fn fd_write(
virt.write_vectored(&iovs)? virt.write_vectored(&iovs)?
} }
} }
Descriptor::Stdin => return Err(Error::EBADF), Descriptor::Stdin => return Err(WasiError::EBADF),
Descriptor::Stdout => { Descriptor::Stdout => {
// lock for the duration of the scope // lock for the duration of the scope
let stdout = io::stdout(); let stdout = io::stdout();
@@ -512,7 +513,7 @@ pub(crate) unsafe fn fd_advise(
offset: wasi::__wasi_filesize_t, offset: wasi::__wasi_filesize_t,
len: wasi::__wasi_filesize_t, len: wasi::__wasi_filesize_t,
advice: wasi::__wasi_advice_t, advice: wasi::__wasi_advice_t,
) -> Result<()> { ) -> WasiResult<()> {
trace!( trace!(
"fd_advise(fd={:?}, offset={}, len={}, advice={:?})", "fd_advise(fd={:?}, offset={}, len={}, advice={:?})",
fd, fd,
@@ -543,7 +544,7 @@ pub(crate) unsafe fn fd_allocate(
fd: wasi::__wasi_fd_t, fd: wasi::__wasi_fd_t,
offset: wasi::__wasi_filesize_t, offset: wasi::__wasi_filesize_t,
len: wasi::__wasi_filesize_t, len: wasi::__wasi_filesize_t,
) -> Result<()> { ) -> WasiResult<()> {
trace!("fd_allocate(fd={:?}, offset={}, len={})", fd, offset, len); trace!("fd_allocate(fd={:?}, offset={}, len={})", fd, offset, len);
let file = wasi_ctx let file = wasi_ctx
@@ -556,10 +557,10 @@ pub(crate) unsafe fn fd_allocate(
let metadata = fd.metadata()?; let metadata = fd.metadata()?;
let current_size = metadata.len(); let current_size = metadata.len();
let wanted_size = offset.checked_add(len).ok_or(Error::E2BIG)?; let wanted_size = offset.checked_add(len).ok_or(WasiError::E2BIG)?;
// This check will be unnecessary when rust-lang/rust#63326 is fixed // This check will be unnecessary when rust-lang/rust#63326 is fixed
if wanted_size > i64::max_value() as u64 { if wanted_size > i64::max_value() as u64 {
return Err(Error::E2BIG); return Err(WasiError::E2BIG);
} }
if wanted_size > current_size { if wanted_size > current_size {
@@ -583,7 +584,7 @@ pub(crate) unsafe fn path_create_directory(
dirfd: wasi::__wasi_fd_t, dirfd: wasi::__wasi_fd_t,
path_ptr: wasi32::uintptr_t, path_ptr: wasi32::uintptr_t,
path_len: wasi32::size_t, path_len: wasi32::size_t,
) -> Result<()> { ) -> WasiResult<()> {
trace!( trace!(
"path_create_directory(dirfd={:?}, path_ptr={:#x?}, path_len={})", "path_create_directory(dirfd={:?}, path_ptr={:#x?}, path_len={})",
dirfd, dirfd,
@@ -612,7 +613,7 @@ pub(crate) unsafe fn path_link(
new_dirfd: wasi::__wasi_fd_t, new_dirfd: wasi::__wasi_fd_t,
new_path_ptr: wasi32::uintptr_t, new_path_ptr: wasi32::uintptr_t,
new_path_len: wasi32::size_t, new_path_len: wasi32::size_t,
) -> Result<()> { ) -> WasiResult<()> {
trace!( trace!(
"path_link(old_dirfd={:?}, old_flags={:?}, old_path_ptr={:#x?}, old_path_len={}, new_dirfd={:?}, new_path_ptr={:#x?}, new_path_len={})", "path_link(old_dirfd={:?}, old_flags={:?}, old_path_ptr={:#x?}, old_path_len={}, new_dirfd={:?}, new_path_ptr={:#x?}, new_path_len={})",
old_dirfd, old_dirfd,
@@ -664,7 +665,7 @@ pub(crate) unsafe fn path_open(
fs_rights_inheriting: wasi::__wasi_rights_t, fs_rights_inheriting: wasi::__wasi_rights_t,
fs_flags: wasi::__wasi_fdflags_t, fs_flags: wasi::__wasi_fdflags_t,
fd_out_ptr: wasi32::uintptr_t, fd_out_ptr: wasi32::uintptr_t,
) -> Result<()> { ) -> WasiResult<()> {
trace!( trace!(
"path_open(dirfd={:?}, dirflags={:?}, path_ptr={:#x?}, path_len={:?}, oflags={:#x?}, fs_rights_base={:#x?}, fs_rights_inheriting={:#x?}, fs_flags={:#x?}, fd_out_ptr={:#x?})", "path_open(dirfd={:?}, dirflags={:?}, path_ptr={:#x?}, path_len={:?}, oflags={:#x?}, fs_rights_base={:#x?}, fs_rights_inheriting={:#x?}, fs_flags={:#x?}, fd_out_ptr={:#x?})",
dirfd, dirfd,
@@ -739,7 +740,7 @@ pub(crate) unsafe fn path_readlink(
buf_ptr: wasi32::uintptr_t, buf_ptr: wasi32::uintptr_t,
buf_len: wasi32::size_t, buf_len: wasi32::size_t,
buf_used: wasi32::uintptr_t, buf_used: wasi32::uintptr_t,
) -> Result<()> { ) -> WasiResult<()> {
trace!( trace!(
"path_readlink(dirfd={:?}, path_ptr={:#x?}, path_len={:?}, buf_ptr={:#x?}, buf_len={}, buf_used={:#x?})", "path_readlink(dirfd={:?}, path_ptr={:#x?}, path_len={:?}, buf_ptr={:#x?}, buf_len={}, buf_used={:#x?})",
dirfd, dirfd,
@@ -783,7 +784,7 @@ pub(crate) unsafe fn path_rename(
new_dirfd: wasi::__wasi_fd_t, new_dirfd: wasi::__wasi_fd_t,
new_path_ptr: wasi32::uintptr_t, new_path_ptr: wasi32::uintptr_t,
new_path_len: wasi32::size_t, new_path_len: wasi32::size_t,
) -> Result<()> { ) -> WasiResult<()> {
trace!( trace!(
"path_rename(old_dirfd={:?}, old_path_ptr={:#x?}, old_path_len={:?}, new_dirfd={:?}, new_path_ptr={:#x?}, new_path_len={:?})", "path_rename(old_dirfd={:?}, old_path_ptr={:#x?}, old_path_len={:?}, new_dirfd={:?}, new_path_ptr={:#x?}, new_path_len={:?})",
old_dirfd, old_dirfd,
@@ -838,7 +839,7 @@ pub(crate) unsafe fn fd_filestat_get(
memory: &mut [u8], memory: &mut [u8],
fd: wasi::__wasi_fd_t, fd: wasi::__wasi_fd_t,
filestat_ptr: wasi32::uintptr_t, filestat_ptr: wasi32::uintptr_t,
) -> Result<()> { ) -> WasiResult<()> {
trace!( trace!(
"fd_filestat_get(fd={:?}, filestat_ptr={:#x?})", "fd_filestat_get(fd={:?}, filestat_ptr={:#x?})",
fd, fd,
@@ -871,7 +872,7 @@ pub(crate) unsafe fn fd_filestat_set_times(
st_atim: wasi::__wasi_timestamp_t, st_atim: wasi::__wasi_timestamp_t,
st_mtim: wasi::__wasi_timestamp_t, st_mtim: wasi::__wasi_timestamp_t,
fst_flags: wasi::__wasi_fstflags_t, fst_flags: wasi::__wasi_fstflags_t,
) -> Result<()> { ) -> WasiResult<()> {
trace!( trace!(
"fd_filestat_set_times(fd={:?}, st_atim={}, st_mtim={}, fst_flags={:#x?})", "fd_filestat_set_times(fd={:?}, st_atim={}, st_mtim={}, fst_flags={:#x?})",
fd, fd,
@@ -893,14 +894,14 @@ pub(crate) fn fd_filestat_set_times_impl(
st_atim: wasi::__wasi_timestamp_t, st_atim: wasi::__wasi_timestamp_t,
st_mtim: wasi::__wasi_timestamp_t, st_mtim: wasi::__wasi_timestamp_t,
fst_flags: wasi::__wasi_fstflags_t, fst_flags: wasi::__wasi_fstflags_t,
) -> Result<()> { ) -> WasiResult<()> {
let set_atim = fst_flags & wasi::__WASI_FSTFLAGS_ATIM != 0; let set_atim = fst_flags & wasi::__WASI_FSTFLAGS_ATIM != 0;
let set_atim_now = fst_flags & wasi::__WASI_FSTFLAGS_ATIM_NOW != 0; let set_atim_now = fst_flags & wasi::__WASI_FSTFLAGS_ATIM_NOW != 0;
let set_mtim = fst_flags & wasi::__WASI_FSTFLAGS_MTIM != 0; let set_mtim = fst_flags & wasi::__WASI_FSTFLAGS_MTIM != 0;
let set_mtim_now = fst_flags & wasi::__WASI_FSTFLAGS_MTIM_NOW != 0; let set_mtim_now = fst_flags & wasi::__WASI_FSTFLAGS_MTIM_NOW != 0;
if (set_atim && set_atim_now) || (set_mtim && set_mtim_now) { if (set_atim && set_atim_now) || (set_mtim && set_mtim_now) {
return Err(Error::EINVAL); return Err(WasiError::EINVAL);
} }
let atim = if set_atim { let atim = if set_atim {
let time = UNIX_EPOCH + Duration::from_nanos(st_atim); let time = UNIX_EPOCH + Duration::from_nanos(st_atim);
@@ -937,7 +938,7 @@ pub(crate) unsafe fn fd_filestat_set_size(
_memory: &mut [u8], _memory: &mut [u8],
fd: wasi::__wasi_fd_t, fd: wasi::__wasi_fd_t,
st_size: wasi::__wasi_filesize_t, st_size: wasi::__wasi_filesize_t,
) -> Result<()> { ) -> WasiResult<()> {
trace!("fd_filestat_set_size(fd={:?}, st_size={})", fd, st_size); trace!("fd_filestat_set_size(fd={:?}, st_size={})", fd, st_size);
let file = wasi_ctx let file = wasi_ctx
@@ -947,7 +948,7 @@ pub(crate) unsafe fn fd_filestat_set_size(
// This check will be unnecessary when rust-lang/rust#63326 is fixed // This check will be unnecessary when rust-lang/rust#63326 is fixed
if st_size > i64::max_value() as u64 { if st_size > i64::max_value() as u64 {
return Err(Error::E2BIG); return Err(WasiError::E2BIG);
} }
match file { match file {
Descriptor::OsHandle(fd) => fd.set_len(st_size).map_err(Into::into), Descriptor::OsHandle(fd) => fd.set_len(st_size).map_err(Into::into),
@@ -968,7 +969,7 @@ pub(crate) unsafe fn path_filestat_get(
path_ptr: wasi32::uintptr_t, path_ptr: wasi32::uintptr_t,
path_len: wasi32::size_t, path_len: wasi32::size_t,
filestat_ptr: wasi32::uintptr_t, filestat_ptr: wasi32::uintptr_t,
) -> Result<()> { ) -> WasiResult<()> {
trace!( trace!(
"path_filestat_get(dirfd={:?}, dirflags={:?}, path_ptr={:#x?}, path_len={}, filestat_ptr={:#x?})", "path_filestat_get(dirfd={:?}, dirflags={:?}, path_ptr={:#x?}, path_len={}, filestat_ptr={:#x?})",
dirfd, dirfd,
@@ -1013,7 +1014,7 @@ pub(crate) unsafe fn path_filestat_set_times(
st_atim: wasi::__wasi_timestamp_t, st_atim: wasi::__wasi_timestamp_t,
st_mtim: wasi::__wasi_timestamp_t, st_mtim: wasi::__wasi_timestamp_t,
fst_flags: wasi::__wasi_fstflags_t, fst_flags: wasi::__wasi_fstflags_t,
) -> Result<()> { ) -> WasiResult<()> {
trace!( trace!(
"path_filestat_set_times(dirfd={:?}, dirflags={:?}, path_ptr={:#x?}, path_len={}, st_atim={}, st_mtim={}, fst_flags={:#x?})", "path_filestat_set_times(dirfd={:?}, dirflags={:?}, path_ptr={:#x?}, path_len={}, st_atim={}, st_mtim={}, fst_flags={:#x?})",
dirfd, dirfd,
@@ -1056,7 +1057,7 @@ pub(crate) unsafe fn path_symlink(
dirfd: wasi::__wasi_fd_t, dirfd: wasi::__wasi_fd_t,
new_path_ptr: wasi32::uintptr_t, new_path_ptr: wasi32::uintptr_t,
new_path_len: wasi32::size_t, new_path_len: wasi32::size_t,
) -> Result<()> { ) -> WasiResult<()> {
trace!( trace!(
"path_symlink(old_path_ptr={:#x?}, old_path_len={}, dirfd={:?}, new_path_ptr={:#x?}, new_path_len={})", "path_symlink(old_path_ptr={:#x?}, old_path_len={}, dirfd={:?}, new_path_ptr={:#x?}, new_path_len={})",
old_path_ptr, old_path_ptr,
@@ -1089,7 +1090,7 @@ pub(crate) unsafe fn path_unlink_file(
dirfd: wasi::__wasi_fd_t, dirfd: wasi::__wasi_fd_t,
path_ptr: wasi32::uintptr_t, path_ptr: wasi32::uintptr_t,
path_len: wasi32::size_t, path_len: wasi32::size_t,
) -> Result<()> { ) -> WasiResult<()> {
trace!( trace!(
"path_unlink_file(dirfd={:?}, path_ptr={:#x?}, path_len={})", "path_unlink_file(dirfd={:?}, path_ptr={:#x?}, path_len={})",
dirfd, dirfd,
@@ -1116,7 +1117,7 @@ pub(crate) unsafe fn path_remove_directory(
dirfd: wasi::__wasi_fd_t, dirfd: wasi::__wasi_fd_t,
path_ptr: wasi32::uintptr_t, path_ptr: wasi32::uintptr_t,
path_len: wasi32::size_t, path_len: wasi32::size_t,
) -> Result<()> { ) -> WasiResult<()> {
trace!( trace!(
"path_remove_directory(dirfd={:?}, path_ptr={:#x?}, path_len={})", "path_remove_directory(dirfd={:?}, path_ptr={:#x?}, path_len={})",
dirfd, dirfd,
@@ -1151,7 +1152,7 @@ pub(crate) unsafe fn fd_prestat_get(
memory: &mut [u8], memory: &mut [u8],
fd: wasi::__wasi_fd_t, fd: wasi::__wasi_fd_t,
prestat_ptr: wasi32::uintptr_t, prestat_ptr: wasi32::uintptr_t,
) -> Result<()> { ) -> WasiResult<()> {
trace!( trace!(
"fd_prestat_get(fd={:?}, prestat_ptr={:#x?})", "fd_prestat_get(fd={:?}, prestat_ptr={:#x?})",
fd, fd,
@@ -1160,9 +1161,9 @@ pub(crate) unsafe fn fd_prestat_get(
// TODO: should we validate any rights here? // TODO: should we validate any rights here?
let fe = wasi_ctx.get_fd_entry(fd)?; let fe = wasi_ctx.get_fd_entry(fd)?;
let po_path = fe.preopen_path.as_ref().ok_or(Error::ENOTSUP)?; let po_path = fe.preopen_path.as_ref().ok_or(WasiError::ENOTSUP)?;
if fe.file_type != wasi::__WASI_FILETYPE_DIRECTORY { if fe.file_type != wasi::__WASI_FILETYPE_DIRECTORY {
return Err(Error::ENOTDIR); return Err(WasiError::ENOTDIR);
} }
let path = host_impl::path_from_host(po_path.as_os_str())?; let path = host_impl::path_from_host(po_path.as_os_str())?;
@@ -1187,7 +1188,7 @@ pub(crate) unsafe fn fd_prestat_dir_name(
fd: wasi::__wasi_fd_t, fd: wasi::__wasi_fd_t,
path_ptr: wasi32::uintptr_t, path_ptr: wasi32::uintptr_t,
path_len: wasi32::size_t, path_len: wasi32::size_t,
) -> Result<()> { ) -> WasiResult<()> {
trace!( trace!(
"fd_prestat_dir_name(fd={:?}, path_ptr={:#x?}, path_len={})", "fd_prestat_dir_name(fd={:?}, path_ptr={:#x?}, path_len={})",
fd, fd,
@@ -1197,15 +1198,15 @@ pub(crate) unsafe fn fd_prestat_dir_name(
// TODO: should we validate any rights here? // TODO: should we validate any rights here?
let fe = wasi_ctx.get_fd_entry(fd)?; let fe = wasi_ctx.get_fd_entry(fd)?;
let po_path = fe.preopen_path.as_ref().ok_or(Error::ENOTSUP)?; let po_path = fe.preopen_path.as_ref().ok_or(WasiError::ENOTSUP)?;
if fe.file_type != wasi::__WASI_FILETYPE_DIRECTORY { if fe.file_type != wasi::__WASI_FILETYPE_DIRECTORY {
return Err(Error::ENOTDIR); return Err(WasiError::ENOTDIR);
} }
let path = host_impl::path_from_host(po_path.as_os_str())?; let path = host_impl::path_from_host(po_path.as_os_str())?;
if path.len() > dec_usize(path_len) { if path.len() > dec_usize(path_len) {
return Err(Error::ENAMETOOLONG); return Err(WasiError::ENAMETOOLONG);
} }
trace!(" | (path_ptr,path_len)='{}'", path); trace!(" | (path_ptr,path_len)='{}'", path);
@@ -1221,7 +1222,7 @@ pub(crate) unsafe fn fd_readdir(
buf_len: wasi32::size_t, buf_len: wasi32::size_t,
cookie: wasi::__wasi_dircookie_t, cookie: wasi::__wasi_dircookie_t,
buf_used: wasi32::uintptr_t, buf_used: wasi32::uintptr_t,
) -> Result<()> { ) -> WasiResult<()> {
trace!( trace!(
"fd_readdir(fd={:?}, buf={:#x?}, buf_len={}, cookie={:#x?}, buf_used={:#x?})", "fd_readdir(fd={:?}, buf={:#x?}, buf_len={}, cookie={:#x?}, buf_used={:#x?})",
fd, fd,
@@ -1241,10 +1242,10 @@ pub(crate) unsafe fn fd_readdir(
trace!(" | (buf,buf_len)={:?}", host_buf); trace!(" | (buf,buf_len)={:?}", host_buf);
fn copy_entities<T: Iterator<Item = Result<Dirent>>>( fn copy_entities<T: Iterator<Item = WasiResult<Dirent>>>(
iter: T, iter: T,
mut host_buf: &mut [u8], mut host_buf: &mut [u8],
) -> Result<usize> { ) -> WasiResult<usize> {
let mut host_bufused = 0; let mut host_bufused = 0;
for dirent in iter { for dirent in iter {
let dirent_raw = dirent?.to_wasi_raw()?; let dirent_raw = dirent?.to_wasi_raw()?;

View File

@@ -2,7 +2,8 @@
use crate::sys::fdentry_impl::OsHandle; use crate::sys::fdentry_impl::OsHandle;
use crate::sys::host_impl; use crate::sys::host_impl;
use crate::sys::hostcalls_impl::fs_helpers::*; use crate::sys::hostcalls_impl::fs_helpers::*;
use crate::{error::WasiError, fdentry::Descriptor, fdentry::FdEntry, wasi, Error, Result}; use crate::wasi::{self, WasiError, WasiResult};
use crate::{fdentry::Descriptor, fdentry::FdEntry};
use std::path::{Component, Path}; use std::path::{Component, Path};
#[derive(Debug)] #[derive(Debug)]
@@ -20,7 +21,7 @@ impl PathGet {
&self.path &self.path
} }
pub(crate) fn path_create_directory(self) -> Result<()> { pub(crate) fn path_create_directory(self) -> WasiResult<()> {
match &self.dirfd { match &self.dirfd {
Descriptor::OsHandle(file) => { Descriptor::OsHandle(file) => {
crate::sys::hostcalls_impl::path_create_directory(&file, &self.path) crate::sys::hostcalls_impl::path_create_directory(&file, &self.path)
@@ -38,7 +39,7 @@ impl PathGet {
write: bool, write: bool,
oflags: u16, oflags: u16,
fs_flags: u16, fs_flags: u16,
) -> Result<Descriptor> { ) -> WasiResult<Descriptor> {
match &self.dirfd { match &self.dirfd {
Descriptor::OsHandle(_) => { Descriptor::OsHandle(_) => {
crate::sys::hostcalls_impl::path_open(self, read, write, oflags, fs_flags) crate::sys::hostcalls_impl::path_open(self, read, write, oflags, fs_flags)
@@ -64,7 +65,7 @@ impl<'a, 'b> PathRef<'a, 'b> {
PathRef { dirfd, path } PathRef { dirfd, path }
} }
fn open(&self) -> Result<Descriptor> { fn open(&self) -> WasiResult<Descriptor> {
match self.dirfd { match self.dirfd {
Descriptor::OsHandle(file) => Ok(Descriptor::OsHandle(OsHandle::from(openat( Descriptor::OsHandle(file) => Ok(Descriptor::OsHandle(OsHandle::from(openat(
&file, &self.path, &file, &self.path,
@@ -84,7 +85,7 @@ impl<'a, 'b> PathRef<'a, 'b> {
} }
} }
fn readlink(&self) -> Result<String> { fn readlink(&self) -> WasiResult<String> {
match self.dirfd { match self.dirfd {
Descriptor::OsHandle(file) => readlinkat(file, self.path), Descriptor::OsHandle(file) => readlinkat(file, self.path),
Descriptor::VirtualFile(virt) => { Descriptor::VirtualFile(virt) => {
@@ -107,17 +108,17 @@ pub(crate) fn path_get(
dirflags: wasi::__wasi_lookupflags_t, dirflags: wasi::__wasi_lookupflags_t,
path: &str, path: &str,
needs_final_component: bool, needs_final_component: bool,
) -> Result<PathGet> { ) -> WasiResult<PathGet> {
const MAX_SYMLINK_EXPANSIONS: usize = 128; const MAX_SYMLINK_EXPANSIONS: usize = 128;
if path.contains('\0') { if path.contains('\0') {
// if contains NUL, return EILSEQ // if contains NUL, return EILSEQ
return Err(Error::EILSEQ); return Err(WasiError::EILSEQ);
} }
if fe.file_type != wasi::__WASI_FILETYPE_DIRECTORY { if fe.file_type != wasi::__WASI_FILETYPE_DIRECTORY {
// if `dirfd` doesn't refer to a directory, return `ENOTDIR`. // if `dirfd` doesn't refer to a directory, return `ENOTDIR`.
return Err(Error::ENOTDIR); return Err(WasiError::ENOTDIR);
} }
let dirfd = fe let dirfd = fe
@@ -148,7 +149,7 @@ pub(crate) fn path_get(
let ends_with_slash = cur_path.ends_with('/'); let ends_with_slash = cur_path.ends_with('/');
let mut components = Path::new(&cur_path).components(); let mut components = Path::new(&cur_path).components();
let head = match components.next() { let head = match components.next() {
None => return Err(Error::ENOENT), None => return Err(WasiError::ENOENT),
Some(p) => p, Some(p) => p,
}; };
let tail = components.as_path(); let tail = components.as_path();
@@ -166,18 +167,18 @@ pub(crate) fn path_get(
match head { match head {
Component::Prefix(_) | Component::RootDir => { Component::Prefix(_) | Component::RootDir => {
// path is absolute! // path is absolute!
return Err(Error::ENOTCAPABLE); return Err(WasiError::ENOTCAPABLE);
} }
Component::CurDir => { Component::CurDir => {
// "." so skip // "." so skip
} }
Component::ParentDir => { Component::ParentDir => {
// ".." so pop a dir // ".." so pop a dir
let _ = dir_stack.pop().ok_or(Error::ENOTCAPABLE)?; let _ = dir_stack.pop().ok_or(WasiError::ENOTCAPABLE)?;
// we're not allowed to pop past the original directory // we're not allowed to pop past the original directory
if dir_stack.is_empty() { if dir_stack.is_empty() {
return Err(Error::ENOTCAPABLE); return Err(WasiError::ENOTCAPABLE);
} }
} }
Component::Normal(head) => { Component::Normal(head) => {
@@ -188,14 +189,17 @@ pub(crate) fn path_get(
} }
if !path_stack.is_empty() || (ends_with_slash && !needs_final_component) { if !path_stack.is_empty() || (ends_with_slash && !needs_final_component) {
match PathRef::new(dir_stack.last().ok_or(Error::ENOTCAPABLE)?, &head) match PathRef::new(
.open() dir_stack.last().ok_or(WasiError::ENOTCAPABLE)?,
&head,
)
.open()
{ {
Ok(new_dir) => { Ok(new_dir) => {
dir_stack.push(new_dir); dir_stack.push(new_dir);
} }
Err(e) => { Err(e) => {
match e.as_wasi_error() { match e {
WasiError::ELOOP WasiError::ELOOP
| WasiError::EMLINK | WasiError::EMLINK
| WasiError::ENOTDIR => | WasiError::ENOTDIR =>
@@ -204,14 +208,14 @@ pub(crate) fn path_get(
{ {
// attempt symlink expansion // attempt symlink expansion
let mut link_path = PathRef::new( let mut link_path = PathRef::new(
dir_stack.last().ok_or(Error::ENOTCAPABLE)?, dir_stack.last().ok_or(WasiError::ENOTCAPABLE)?,
&head, &head,
) )
.readlink()?; .readlink()?;
symlink_expansions += 1; symlink_expansions += 1;
if symlink_expansions > MAX_SYMLINK_EXPANSIONS { if symlink_expansions > MAX_SYMLINK_EXPANSIONS {
return Err(Error::ELOOP); return Err(WasiError::ELOOP);
} }
if head.ends_with('/') { if head.ends_with('/') {
@@ -238,13 +242,16 @@ pub(crate) fn path_get(
{ {
// if there's a trailing slash, or if `LOOKUP_SYMLINK_FOLLOW` is set, attempt // if there's a trailing slash, or if `LOOKUP_SYMLINK_FOLLOW` is set, attempt
// symlink expansion // symlink expansion
match PathRef::new(dir_stack.last().ok_or(Error::ENOTCAPABLE)?, &head) match PathRef::new(
.readlink() dir_stack.last().ok_or(WasiError::ENOTCAPABLE)?,
&head,
)
.readlink()
{ {
Ok(mut link_path) => { Ok(mut link_path) => {
symlink_expansions += 1; symlink_expansions += 1;
if symlink_expansions > MAX_SYMLINK_EXPANSIONS { if symlink_expansions > MAX_SYMLINK_EXPANSIONS {
return Err(Error::ELOOP); return Err(WasiError::ELOOP);
} }
if head.ends_with('/') { if head.ends_with('/') {
@@ -260,12 +267,12 @@ pub(crate) fn path_get(
continue; continue;
} }
Err(e) => { Err(e) => {
if e.as_wasi_error() != WasiError::EINVAL if e != WasiError::EINVAL
&& e.as_wasi_error() != WasiError::ENOENT && e != WasiError::ENOENT
// this handles the cases when trying to link to // this handles the cases when trying to link to
// a destination that already exists, and the target // a destination that already exists, and the target
// path contains a slash // path contains a slash
&& e.as_wasi_error() != WasiError::ENOTDIR && e != WasiError::ENOTDIR
{ {
return Err(e); return Err(e);
} }
@@ -275,7 +282,7 @@ pub(crate) fn path_get(
// not a symlink, so we're done; // not a symlink, so we're done;
return Ok(PathGet { return Ok(PathGet {
dirfd: dir_stack.pop().ok_or(Error::ENOTCAPABLE)?, dirfd: dir_stack.pop().ok_or(WasiError::ENOTCAPABLE)?,
path: head, path: head,
}); });
} }
@@ -285,7 +292,7 @@ pub(crate) fn path_get(
// no further components to process. means we've hit a case like "." or "a/..", or if the // 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 // input path has trailing slashes and `needs_final_component` is not set
return Ok(PathGet { return Ok(PathGet {
dirfd: dir_stack.pop().ok_or(Error::ENOTCAPABLE)?, dirfd: dir_stack.pop().ok_or(WasiError::ENOTCAPABLE)?,
path: String::from("."), path: String::from("."),
}); });
} }

View File

@@ -3,7 +3,8 @@ use crate::ctx::WasiCtx;
use crate::fdentry::Descriptor; use crate::fdentry::Descriptor;
use crate::memory::*; use crate::memory::*;
use crate::sys::hostcalls_impl; use crate::sys::hostcalls_impl;
use crate::{wasi, wasi32, Error, Result}; use crate::wasi::{self, WasiError, WasiResult};
use crate::wasi32;
use log::{error, trace}; use log::{error, trace};
use std::convert::TryFrom; use std::convert::TryFrom;
@@ -12,7 +13,7 @@ pub(crate) fn args_get(
memory: &mut [u8], memory: &mut [u8],
argv_ptr: wasi32::uintptr_t, argv_ptr: wasi32::uintptr_t,
argv_buf: wasi32::uintptr_t, argv_buf: wasi32::uintptr_t,
) -> Result<()> { ) -> WasiResult<()> {
trace!( trace!(
"args_get(argv_ptr={:#x?}, argv_buf={:#x?})", "args_get(argv_ptr={:#x?}, argv_buf={:#x?})",
argv_ptr, argv_ptr,
@@ -31,7 +32,9 @@ pub(crate) fn args_get(
argv.push(arg_ptr); argv.push(arg_ptr);
let len = wasi32::uintptr_t::try_from(arg_bytes.len())?; let len = wasi32::uintptr_t::try_from(arg_bytes.len())?;
argv_buf_offset = argv_buf_offset.checked_add(len).ok_or(Error::EOVERFLOW)?; argv_buf_offset = argv_buf_offset
.checked_add(len)
.ok_or(WasiError::EOVERFLOW)?;
} }
enc_slice_of_wasi32_uintptr(memory, argv.as_slice(), argv_ptr) enc_slice_of_wasi32_uintptr(memory, argv.as_slice(), argv_ptr)
@@ -42,7 +45,7 @@ pub(crate) fn args_sizes_get(
memory: &mut [u8], memory: &mut [u8],
argc_ptr: wasi32::uintptr_t, argc_ptr: wasi32::uintptr_t,
argv_buf_size_ptr: wasi32::uintptr_t, argv_buf_size_ptr: wasi32::uintptr_t,
) -> Result<()> { ) -> WasiResult<()> {
trace!( trace!(
"args_sizes_get(argc_ptr={:#x?}, argv_buf_size_ptr={:#x?})", "args_sizes_get(argc_ptr={:#x?}, argv_buf_size_ptr={:#x?})",
argc_ptr, argc_ptr,
@@ -70,7 +73,7 @@ pub(crate) fn environ_get(
memory: &mut [u8], memory: &mut [u8],
environ_ptr: wasi32::uintptr_t, environ_ptr: wasi32::uintptr_t,
environ_buf: wasi32::uintptr_t, environ_buf: wasi32::uintptr_t,
) -> Result<()> { ) -> WasiResult<()> {
trace!( trace!(
"environ_get(environ_ptr={:#x?}, environ_buf={:#x?})", "environ_get(environ_ptr={:#x?}, environ_buf={:#x?})",
environ_ptr, environ_ptr,
@@ -91,7 +94,7 @@ pub(crate) fn environ_get(
let len = wasi32::uintptr_t::try_from(env_bytes.len())?; let len = wasi32::uintptr_t::try_from(env_bytes.len())?;
environ_buf_offset = environ_buf_offset environ_buf_offset = environ_buf_offset
.checked_add(len) .checked_add(len)
.ok_or(Error::EOVERFLOW)?; .ok_or(WasiError::EOVERFLOW)?;
} }
enc_slice_of_wasi32_uintptr(memory, environ.as_slice(), environ_ptr) enc_slice_of_wasi32_uintptr(memory, environ.as_slice(), environ_ptr)
@@ -102,7 +105,7 @@ pub(crate) fn environ_sizes_get(
memory: &mut [u8], memory: &mut [u8],
environ_count_ptr: wasi32::uintptr_t, environ_count_ptr: wasi32::uintptr_t,
environ_size_ptr: wasi32::uintptr_t, environ_size_ptr: wasi32::uintptr_t,
) -> Result<()> { ) -> WasiResult<()> {
trace!( trace!(
"environ_sizes_get(environ_count_ptr={:#x?}, environ_size_ptr={:#x?})", "environ_sizes_get(environ_count_ptr={:#x?}, environ_size_ptr={:#x?})",
environ_count_ptr, environ_count_ptr,
@@ -116,7 +119,7 @@ pub(crate) fn environ_sizes_get(
.try_fold(0, |acc: u32, pair| { .try_fold(0, |acc: u32, pair| {
acc.checked_add(pair.as_bytes_with_nul().len() as u32) acc.checked_add(pair.as_bytes_with_nul().len() as u32)
}) })
.ok_or(Error::EOVERFLOW)?; .ok_or(WasiError::EOVERFLOW)?;
trace!(" | *environ_count_ptr={:?}", environ_count); trace!(" | *environ_count_ptr={:?}", environ_count);
@@ -132,14 +135,14 @@ pub(crate) fn random_get(
memory: &mut [u8], memory: &mut [u8],
buf_ptr: wasi32::uintptr_t, buf_ptr: wasi32::uintptr_t,
buf_len: wasi32::size_t, buf_len: wasi32::size_t,
) -> Result<()> { ) -> WasiResult<()> {
trace!("random_get(buf_ptr={:#x?}, buf_len={:?})", buf_ptr, buf_len); trace!("random_get(buf_ptr={:#x?}, buf_len={:?})", buf_ptr, buf_len);
let buf = dec_slice_of_mut_u8(memory, buf_ptr, buf_len)?; let buf = dec_slice_of_mut_u8(memory, buf_ptr, buf_len)?;
getrandom::getrandom(buf).map_err(|err| { getrandom::getrandom(buf).map_err(|err| {
error!("getrandom failure: {:?}", err); error!("getrandom failure: {:?}", err);
Error::EIO WasiError::EIO
}) })
} }
@@ -148,7 +151,7 @@ pub(crate) fn clock_res_get(
memory: &mut [u8], memory: &mut [u8],
clock_id: wasi::__wasi_clockid_t, clock_id: wasi::__wasi_clockid_t,
resolution_ptr: wasi32::uintptr_t, resolution_ptr: wasi32::uintptr_t,
) -> Result<()> { ) -> WasiResult<()> {
trace!( trace!(
"clock_res_get(clock_id={:?}, resolution_ptr={:#x?})", "clock_res_get(clock_id={:?}, resolution_ptr={:#x?})",
clock_id, clock_id,
@@ -168,7 +171,7 @@ pub(crate) fn clock_time_get(
clock_id: wasi::__wasi_clockid_t, clock_id: wasi::__wasi_clockid_t,
precision: wasi::__wasi_timestamp_t, precision: wasi::__wasi_timestamp_t,
time_ptr: wasi32::uintptr_t, time_ptr: wasi32::uintptr_t,
) -> Result<()> { ) -> WasiResult<()> {
trace!( trace!(
"clock_time_get(clock_id={:?}, precision={:?}, time_ptr={:#x?})", "clock_time_get(clock_id={:?}, precision={:?}, time_ptr={:#x?})",
clock_id, clock_id,
@@ -183,7 +186,7 @@ pub(crate) fn clock_time_get(
enc_timestamp_byref(memory, time_ptr, time) enc_timestamp_byref(memory, time_ptr, time)
} }
pub(crate) fn sched_yield(_wasi_ctx: &WasiCtx, _memory: &mut [u8]) -> Result<()> { pub(crate) fn sched_yield(_wasi_ctx: &WasiCtx, _memory: &mut [u8]) -> WasiResult<()> {
trace!("sched_yield()"); trace!("sched_yield()");
std::thread::yield_now(); std::thread::yield_now();
@@ -198,7 +201,7 @@ pub(crate) fn poll_oneoff(
output: wasi32::uintptr_t, output: wasi32::uintptr_t,
nsubscriptions: wasi32::size_t, nsubscriptions: wasi32::size_t,
nevents: wasi32::uintptr_t, nevents: wasi32::uintptr_t,
) -> Result<()> { ) -> WasiResult<()> {
trace!( trace!(
"poll_oneoff(input={:#x?}, output={:#x?}, nsubscriptions={}, nevents={:#x?})", "poll_oneoff(input={:#x?}, output={:#x?}, nsubscriptions={}, nevents={:#x?})",
input, input,
@@ -208,7 +211,7 @@ pub(crate) fn poll_oneoff(
); );
if u64::from(nsubscriptions) > wasi::__wasi_filesize_t::max_value() { if u64::from(nsubscriptions) > wasi::__wasi_filesize_t::max_value() {
return Err(Error::EINVAL); return Err(WasiError::EINVAL);
} }
enc_int_byref(memory, nevents, 0)?; enc_int_byref(memory, nevents, 0)?;
@@ -222,7 +225,7 @@ pub(crate) fn poll_oneoff(
// As mandated by the WASI spec: // As mandated by the WASI spec:
// > If `nsubscriptions` is 0, returns `errno::inval`. // > If `nsubscriptions` is 0, returns `errno::inval`.
if subscriptions.is_empty() { if subscriptions.is_empty() {
return Err(Error::EINVAL); return Err(WasiError::EINVAL);
} }
for subscription in subscriptions { for subscription in subscriptions {
match subscription.u.tag { match subscription.u.tag {
@@ -258,7 +261,7 @@ pub(crate) fn poll_oneoff(
Err(err) => { Err(err) => {
let event = wasi::__wasi_event_t { let event = wasi::__wasi_event_t {
userdata: subscription.userdata, userdata: subscription.userdata,
error: err.as_wasi_error().as_raw_errno(), error: err.as_raw_errno(),
r#type: wasi::__WASI_EVENTTYPE_FD_READ, r#type: wasi::__WASI_EVENTTYPE_FD_READ,
fd_readwrite: wasi::__wasi_event_fd_readwrite_t { fd_readwrite: wasi::__wasi_event_fd_readwrite_t {
nbytes: 0, nbytes: 0,
@@ -286,7 +289,7 @@ pub(crate) fn poll_oneoff(
Err(err) => { Err(err) => {
let event = wasi::__wasi_event_t { let event = wasi::__wasi_event_t {
userdata: subscription.userdata, userdata: subscription.userdata,
error: err.as_wasi_error().as_raw_errno(), error: err.as_raw_errno(),
r#type: wasi::__WASI_EVENTTYPE_FD_WRITE, r#type: wasi::__WASI_EVENTTYPE_FD_WRITE,
fd_readwrite: wasi::__wasi_event_fd_readwrite_t { fd_readwrite: wasi::__wasi_event_fd_readwrite_t {
nbytes: 0, nbytes: 0,
@@ -310,7 +313,7 @@ pub(crate) fn poll_oneoff(
// events have been filtered out as errors in the code above. // events have been filtered out as errors in the code above.
hostcalls_impl::poll_oneoff(timeout, fd_events, &mut events)?; hostcalls_impl::poll_oneoff(timeout, fd_events, &mut events)?;
let events_count = u32::try_from(events.len()).map_err(|_| Error::EOVERFLOW)?; let events_count = u32::try_from(events.len()).map_err(|_| WasiError::EOVERFLOW)?;
enc_events(memory, output, nsubscriptions, events)?; enc_events(memory, output, nsubscriptions, events)?;
@@ -319,7 +322,9 @@ pub(crate) fn poll_oneoff(
enc_int_byref(memory, nevents, events_count) enc_int_byref(memory, nevents, events_count)
} }
fn wasi_clock_to_relative_ns_delay(wasi_clock: wasi::__wasi_subscription_clock_t) -> Result<u128> { fn wasi_clock_to_relative_ns_delay(
wasi_clock: wasi::__wasi_subscription_clock_t,
) -> WasiResult<u128> {
use std::time::SystemTime; use std::time::SystemTime;
if wasi_clock.flags != wasi::__WASI_SUBCLOCKFLAGS_SUBSCRIPTION_CLOCK_ABSTIME { if wasi_clock.flags != wasi::__WASI_SUBCLOCKFLAGS_SUBSCRIPTION_CLOCK_ABSTIME {
@@ -327,7 +332,7 @@ fn wasi_clock_to_relative_ns_delay(wasi_clock: wasi::__wasi_subscription_clock_t
} }
let now: u128 = SystemTime::now() let now: u128 = SystemTime::now()
.duration_since(SystemTime::UNIX_EPOCH) .duration_since(SystemTime::UNIX_EPOCH)
.map_err(|_| Error::ENOTCAPABLE)? .map_err(|_| WasiError::ENOTCAPABLE)?
.as_nanos(); .as_nanos();
let deadline = u128::from(wasi_clock.timeout); let deadline = u128::from(wasi_clock.timeout);
Ok(deadline.saturating_sub(now)) Ok(deadline.saturating_sub(now))
@@ -357,6 +362,6 @@ pub(crate) fn proc_raise(
_wasi_ctx: &WasiCtx, _wasi_ctx: &WasiCtx,
_memory: &mut [u8], _memory: &mut [u8],
_sig: wasi::__wasi_signal_t, _sig: wasi::__wasi_signal_t,
) -> Result<()> { ) -> WasiResult<()> {
unimplemented!("proc_raise") unimplemented!("proc_raise")
} }

View File

@@ -1,5 +1,6 @@
use crate::ctx::WasiCtx; use crate::ctx::WasiCtx;
use crate::{wasi, wasi32, Result}; use crate::wasi::{self, WasiResult};
use crate::wasi32;
pub fn sock_recv( pub fn sock_recv(
_wasi_ctx: &WasiCtx, _wasi_ctx: &WasiCtx,
@@ -10,7 +11,7 @@ pub fn sock_recv(
_ri_flags: wasi::__wasi_riflags_t, _ri_flags: wasi::__wasi_riflags_t,
_ro_datalen: wasi32::uintptr_t, _ro_datalen: wasi32::uintptr_t,
_ro_flags: wasi32::uintptr_t, _ro_flags: wasi32::uintptr_t,
) -> Result<()> { ) -> WasiResult<()> {
unimplemented!("sock_recv") unimplemented!("sock_recv")
} }
@@ -22,7 +23,7 @@ pub fn sock_send(
_si_data_len: wasi32::size_t, _si_data_len: wasi32::size_t,
_si_flags: wasi::__wasi_siflags_t, _si_flags: wasi::__wasi_siflags_t,
_so_datalen: wasi32::uintptr_t, _so_datalen: wasi32::uintptr_t,
) -> Result<()> { ) -> WasiResult<()> {
unimplemented!("sock_send") unimplemented!("sock_send")
} }
@@ -31,6 +32,6 @@ pub fn sock_shutdown(
_memory: &mut [u8], _memory: &mut [u8],
_sock: wasi::__wasi_fd_t, _sock: wasi::__wasi_fd_t,
_how: wasi::__wasi_sdflags_t, _how: wasi::__wasi_sdflags_t,
) -> Result<()> { ) -> WasiResult<()> {
unimplemented!("sock_shutdown") unimplemented!("sock_shutdown")
} }

View File

@@ -22,7 +22,6 @@
)] )]
mod ctx; mod ctx;
mod error;
mod fdentry; mod fdentry;
pub mod fs; pub mod fs;
mod helpers; mod helpers;
@@ -43,6 +42,3 @@ pub mod hostcalls {
pub use ctx::{WasiCtx, WasiCtxBuilder}; pub use ctx::{WasiCtx, WasiCtxBuilder};
pub use sys::preopen_dir; pub use sys::preopen_dir;
pub use error::Error;
pub(crate) use error::Result;

View File

@@ -8,38 +8,39 @@
//! are not held for long durations. //! are not held for long durations.
#![allow(unused)] #![allow(unused)]
use crate::{host, wasi, wasi32, Error, Result}; use crate::wasi::{self, WasiError, WasiResult};
use crate::{host, wasi32};
use num::PrimInt; use num::PrimInt;
use std::convert::TryFrom; use std::convert::TryFrom;
use std::mem::{align_of, size_of}; use std::mem::{align_of, size_of};
use std::{ptr, slice}; use std::{ptr, slice};
fn dec_ptr(memory: &[u8], ptr: wasi32::uintptr_t, len: usize) -> Result<*const u8> { fn dec_ptr(memory: &[u8], ptr: wasi32::uintptr_t, len: usize) -> WasiResult<*const u8> {
// check for overflow // check for overflow
let checked_len = (ptr as usize).checked_add(len).ok_or(Error::EFAULT)?; let checked_len = (ptr as usize).checked_add(len).ok_or(WasiError::EFAULT)?;
// translate the pointer // translate the pointer
memory memory
.get(ptr as usize..checked_len) .get(ptr as usize..checked_len)
.ok_or(Error::EFAULT) .ok_or(WasiError::EFAULT)
.map(|mem| mem.as_ptr()) .map(|mem| mem.as_ptr())
} }
fn dec_ptr_mut(memory: &mut [u8], ptr: wasi32::uintptr_t, len: usize) -> Result<*mut u8> { fn dec_ptr_mut(memory: &mut [u8], ptr: wasi32::uintptr_t, len: usize) -> WasiResult<*mut u8> {
// check for overflow // check for overflow
let checked_len = (ptr as usize).checked_add(len).ok_or(Error::EFAULT)?; let checked_len = (ptr as usize).checked_add(len).ok_or(WasiError::EFAULT)?;
// translate the pointer // translate the pointer
memory memory
.get_mut(ptr as usize..checked_len) .get_mut(ptr as usize..checked_len)
.ok_or(Error::EFAULT) .ok_or(WasiError::EFAULT)
.map(|mem| mem.as_mut_ptr()) .map(|mem| mem.as_mut_ptr())
} }
fn dec_ptr_to<'memory, T>(memory: &'memory [u8], ptr: wasi32::uintptr_t) -> Result<&'memory T> { fn dec_ptr_to<'memory, T>(memory: &'memory [u8], ptr: wasi32::uintptr_t) -> WasiResult<&'memory T> {
// check that the ptr is aligned // check that the ptr is aligned
if ptr as usize % align_of::<T>() != 0 { if ptr as usize % align_of::<T>() != 0 {
return Err(Error::EINVAL); return Err(WasiError::EINVAL);
} }
dec_ptr(memory, ptr, size_of::<T>()).map(|p| unsafe { &*(p as *const T) }) dec_ptr(memory, ptr, size_of::<T>()).map(|p| unsafe { &*(p as *const T) })
@@ -48,49 +49,49 @@ fn dec_ptr_to<'memory, T>(memory: &'memory [u8], ptr: wasi32::uintptr_t) -> Resu
fn dec_ptr_to_mut<'memory, T>( fn dec_ptr_to_mut<'memory, T>(
memory: &'memory mut [u8], memory: &'memory mut [u8],
ptr: wasi32::uintptr_t, ptr: wasi32::uintptr_t,
) -> Result<&'memory mut T> { ) -> WasiResult<&'memory mut T> {
// check that the ptr is aligned // check that the ptr is aligned
if ptr as usize % align_of::<T>() != 0 { if ptr as usize % align_of::<T>() != 0 {
return Err(Error::EINVAL); return Err(WasiError::EINVAL);
} }
dec_ptr_mut(memory, ptr, size_of::<T>()).map(|p| unsafe { &mut *(p as *mut T) }) dec_ptr_mut(memory, ptr, size_of::<T>()).map(|p| unsafe { &mut *(p as *mut T) })
} }
/// This function does not perform endianness conversions! /// This function does not perform endianness conversions!
fn dec_raw_byref<T>(memory: &[u8], ptr: wasi32::uintptr_t) -> Result<T> { fn dec_raw_byref<T>(memory: &[u8], ptr: wasi32::uintptr_t) -> WasiResult<T> {
dec_ptr_to::<T>(memory, ptr).map(|p| unsafe { ptr::read(p) }) dec_ptr_to::<T>(memory, ptr).map(|p| unsafe { ptr::read(p) })
} }
/// This function does not perform endianness conversions! /// This function does not perform endianness conversions!
fn enc_raw_byref<T>(memory: &mut [u8], ptr: wasi32::uintptr_t, t: T) -> Result<()> { fn enc_raw_byref<T>(memory: &mut [u8], ptr: wasi32::uintptr_t, t: T) -> WasiResult<()> {
dec_ptr_to_mut::<T>(memory, ptr).map(|p| unsafe { ptr::write(p, t) }) dec_ptr_to_mut::<T>(memory, ptr).map(|p| unsafe { ptr::write(p, t) })
} }
pub(crate) fn dec_int_byref<T>(memory: &[u8], ptr: wasi32::uintptr_t) -> Result<T> pub(crate) fn dec_int_byref<T>(memory: &[u8], ptr: wasi32::uintptr_t) -> WasiResult<T>
where where
T: PrimInt, T: PrimInt,
{ {
dec_raw_byref::<T>(memory, ptr).map(|i| PrimInt::from_le(i)) dec_raw_byref::<T>(memory, ptr).map(|i| PrimInt::from_le(i))
} }
pub(crate) fn enc_int_byref<T>(memory: &mut [u8], ptr: wasi32::uintptr_t, t: T) -> Result<()> pub(crate) fn enc_int_byref<T>(memory: &mut [u8], ptr: wasi32::uintptr_t, t: T) -> WasiResult<()>
where where
T: PrimInt, T: PrimInt,
{ {
enc_raw_byref::<T>(memory, ptr, PrimInt::to_le(t)) enc_raw_byref::<T>(memory, ptr, PrimInt::to_le(t))
} }
fn check_slice_of<T>(ptr: wasi32::uintptr_t, len: wasi32::size_t) -> Result<(usize, usize)> { fn check_slice_of<T>(ptr: wasi32::uintptr_t, len: wasi32::size_t) -> WasiResult<(usize, usize)> {
// check alignment, and that length doesn't overflow // check alignment, and that length doesn't overflow
if ptr as usize % align_of::<T>() != 0 { if ptr as usize % align_of::<T>() != 0 {
return Err(Error::EINVAL); return Err(WasiError::EINVAL);
} }
let len = dec_usize(len); let len = dec_usize(len);
let len_bytes = if let Some(len) = size_of::<T>().checked_mul(len) { let len_bytes = if let Some(len) = size_of::<T>().checked_mul(len) {
len len
} else { } else {
return Err(Error::EOVERFLOW); return Err(WasiError::EOVERFLOW);
}; };
Ok((len, len_bytes)) Ok((len, len_bytes))
@@ -100,7 +101,7 @@ fn dec_raw_slice_of<'memory, T>(
memory: &'memory [u8], memory: &'memory [u8],
ptr: wasi32::uintptr_t, ptr: wasi32::uintptr_t,
len: wasi32::size_t, len: wasi32::size_t,
) -> Result<&'memory [T]> { ) -> WasiResult<&'memory [T]> {
let (len, len_bytes) = check_slice_of::<T>(ptr, len)?; let (len, len_bytes) = check_slice_of::<T>(ptr, len)?;
let ptr = dec_ptr(memory, ptr, len_bytes)? as *const T; let ptr = dec_ptr(memory, ptr, len_bytes)? as *const T;
Ok(unsafe { slice::from_raw_parts(ptr, len) }) Ok(unsafe { slice::from_raw_parts(ptr, len) })
@@ -110,7 +111,7 @@ fn dec_raw_slice_of_mut<'memory, T>(
memory: &'memory mut [u8], memory: &'memory mut [u8],
ptr: wasi32::uintptr_t, ptr: wasi32::uintptr_t,
len: wasi32::size_t, len: wasi32::size_t,
) -> Result<&'memory mut [T]> { ) -> WasiResult<&'memory mut [T]> {
let (len, len_bytes) = check_slice_of::<T>(ptr, len)?; let (len, len_bytes) = check_slice_of::<T>(ptr, len)?;
let ptr = dec_ptr_mut(memory, ptr, len_bytes)? as *mut T; let ptr = dec_ptr_mut(memory, ptr, len_bytes)? as *mut T;
Ok(unsafe { slice::from_raw_parts_mut(ptr, len) }) Ok(unsafe { slice::from_raw_parts_mut(ptr, len) })
@@ -120,16 +121,16 @@ fn raw_slice_for_enc<'memory, T>(
memory: &'memory mut [u8], memory: &'memory mut [u8],
slice: &[T], slice: &[T],
ptr: wasi32::uintptr_t, ptr: wasi32::uintptr_t,
) -> Result<&'memory mut [T]> { ) -> WasiResult<&'memory mut [T]> {
// check alignment // check alignment
if ptr as usize % align_of::<T>() != 0 { if ptr as usize % align_of::<T>() != 0 {
return Err(Error::EINVAL); return Err(WasiError::EINVAL);
} }
// check that length doesn't overflow // check that length doesn't overflow
let len_bytes = if let Some(len) = size_of::<T>().checked_mul(slice.len()) { let len_bytes = if let Some(len) = size_of::<T>().checked_mul(slice.len()) {
len len
} else { } else {
return Err(Error::EOVERFLOW); return Err(WasiError::EOVERFLOW);
}; };
// get the pointer into guest memory // get the pointer into guest memory
@@ -142,7 +143,7 @@ pub(crate) fn dec_slice_of_u8<'memory>(
memory: &'memory [u8], memory: &'memory [u8],
ptr: wasi32::uintptr_t, ptr: wasi32::uintptr_t,
len: wasi32::size_t, len: wasi32::size_t,
) -> Result<&'memory [u8]> { ) -> WasiResult<&'memory [u8]> {
dec_raw_slice_of::<u8>(memory, ptr, len) dec_raw_slice_of::<u8>(memory, ptr, len)
} }
@@ -150,7 +151,7 @@ pub(crate) fn dec_slice_of_mut_u8<'memory>(
memory: &'memory mut [u8], memory: &'memory mut [u8],
ptr: wasi32::uintptr_t, ptr: wasi32::uintptr_t,
len: wasi32::size_t, len: wasi32::size_t,
) -> Result<&'memory mut [u8]> { ) -> WasiResult<&'memory mut [u8]> {
dec_raw_slice_of_mut::<u8>(memory, ptr, len) dec_raw_slice_of_mut::<u8>(memory, ptr, len)
} }
@@ -158,7 +159,7 @@ pub(crate) fn enc_slice_of_u8(
memory: &mut [u8], memory: &mut [u8],
slice: &[u8], slice: &[u8],
ptr: wasi32::uintptr_t, ptr: wasi32::uintptr_t,
) -> Result<()> { ) -> WasiResult<()> {
let output = raw_slice_for_enc::<u8>(memory, slice, ptr)?; let output = raw_slice_for_enc::<u8>(memory, slice, ptr)?;
output.copy_from_slice(slice); output.copy_from_slice(slice);
@@ -170,7 +171,7 @@ pub(crate) fn enc_slice_of_wasi32_uintptr(
memory: &mut [u8], memory: &mut [u8],
slice: &[wasi32::uintptr_t], slice: &[wasi32::uintptr_t],
ptr: wasi32::uintptr_t, ptr: wasi32::uintptr_t,
) -> Result<()> { ) -> WasiResult<()> {
let mut output_iter = raw_slice_for_enc::<wasi32::uintptr_t>(memory, slice, ptr)?.into_iter(); let mut output_iter = raw_slice_for_enc::<wasi32::uintptr_t>(memory, slice, ptr)?.into_iter();
for p in slice { for p in slice {
@@ -182,7 +183,10 @@ pub(crate) fn enc_slice_of_wasi32_uintptr(
macro_rules! dec_enc_scalar { macro_rules! dec_enc_scalar {
($ty:ident, $dec_byref:ident, $enc_byref:ident) => { ($ty:ident, $dec_byref:ident, $enc_byref:ident) => {
pub(crate) fn $dec_byref(memory: &mut [u8], ptr: wasi32::uintptr_t) -> Result<wasi::$ty> { pub(crate) fn $dec_byref(
memory: &mut [u8],
ptr: wasi32::uintptr_t,
) -> WasiResult<wasi::$ty> {
dec_int_byref::<wasi::$ty>(memory, ptr) dec_int_byref::<wasi::$ty>(memory, ptr)
} }
@@ -190,7 +194,7 @@ macro_rules! dec_enc_scalar {
memory: &mut [u8], memory: &mut [u8],
ptr: wasi32::uintptr_t, ptr: wasi32::uintptr_t,
x: wasi::$ty, x: wasi::$ty,
) -> Result<()> { ) -> WasiResult<()> {
enc_int_byref::<wasi::$ty>(memory, ptr, x) enc_int_byref::<wasi::$ty>(memory, ptr, x)
} }
}; };
@@ -200,7 +204,7 @@ pub(crate) fn dec_ciovec_slice(
memory: &[u8], memory: &[u8],
ptr: wasi32::uintptr_t, ptr: wasi32::uintptr_t,
len: wasi32::size_t, len: wasi32::size_t,
) -> Result<Vec<host::__wasi_ciovec_t>> { ) -> WasiResult<Vec<host::__wasi_ciovec_t>> {
let raw_slice = dec_raw_slice_of::<wasi32::__wasi_ciovec_t>(memory, ptr, len)?; let raw_slice = dec_raw_slice_of::<wasi32::__wasi_ciovec_t>(memory, ptr, len)?;
raw_slice raw_slice
@@ -220,7 +224,7 @@ pub(crate) fn dec_iovec_slice(
memory: &[u8], memory: &[u8],
ptr: wasi32::uintptr_t, ptr: wasi32::uintptr_t,
len: wasi32::size_t, len: wasi32::size_t,
) -> Result<Vec<host::__wasi_iovec_t>> { ) -> WasiResult<Vec<host::__wasi_iovec_t>> {
let raw_slice = dec_raw_slice_of::<wasi32::__wasi_iovec_t>(memory, ptr, len)?; let raw_slice = dec_raw_slice_of::<wasi32::__wasi_iovec_t>(memory, ptr, len)?;
raw_slice raw_slice
@@ -248,7 +252,7 @@ dec_enc_scalar!(__wasi_linkcount_t, dev_linkcount_byref, enc_linkcount_byref);
pub(crate) fn dec_filestat_byref( pub(crate) fn dec_filestat_byref(
memory: &mut [u8], memory: &mut [u8],
filestat_ptr: wasi32::uintptr_t, filestat_ptr: wasi32::uintptr_t,
) -> Result<wasi::__wasi_filestat_t> { ) -> WasiResult<wasi::__wasi_filestat_t> {
let raw = dec_raw_byref::<wasi::__wasi_filestat_t>(memory, filestat_ptr)?; let raw = dec_raw_byref::<wasi::__wasi_filestat_t>(memory, filestat_ptr)?;
Ok(wasi::__wasi_filestat_t { Ok(wasi::__wasi_filestat_t {
@@ -267,7 +271,7 @@ pub(crate) fn enc_filestat_byref(
memory: &mut [u8], memory: &mut [u8],
filestat_ptr: wasi32::uintptr_t, filestat_ptr: wasi32::uintptr_t,
filestat: wasi::__wasi_filestat_t, filestat: wasi::__wasi_filestat_t,
) -> Result<()> { ) -> WasiResult<()> {
let raw = wasi::__wasi_filestat_t { let raw = wasi::__wasi_filestat_t {
dev: PrimInt::to_le(filestat.dev), dev: PrimInt::to_le(filestat.dev),
ino: PrimInt::to_le(filestat.ino), ino: PrimInt::to_le(filestat.ino),
@@ -285,7 +289,7 @@ pub(crate) fn enc_filestat_byref(
pub(crate) fn dec_fdstat_byref( pub(crate) fn dec_fdstat_byref(
memory: &mut [u8], memory: &mut [u8],
fdstat_ptr: wasi32::uintptr_t, fdstat_ptr: wasi32::uintptr_t,
) -> Result<wasi::__wasi_fdstat_t> { ) -> WasiResult<wasi::__wasi_fdstat_t> {
let raw = dec_raw_byref::<wasi::__wasi_fdstat_t>(memory, fdstat_ptr)?; let raw = dec_raw_byref::<wasi::__wasi_fdstat_t>(memory, fdstat_ptr)?;
Ok(wasi::__wasi_fdstat_t { Ok(wasi::__wasi_fdstat_t {
@@ -300,7 +304,7 @@ pub(crate) fn enc_fdstat_byref(
memory: &mut [u8], memory: &mut [u8],
fdstat_ptr: wasi32::uintptr_t, fdstat_ptr: wasi32::uintptr_t,
fdstat: wasi::__wasi_fdstat_t, fdstat: wasi::__wasi_fdstat_t,
) -> Result<()> { ) -> WasiResult<()> {
let raw = wasi::__wasi_fdstat_t { let raw = wasi::__wasi_fdstat_t {
fs_filetype: PrimInt::to_le(fdstat.fs_filetype), fs_filetype: PrimInt::to_le(fdstat.fs_filetype),
fs_flags: PrimInt::to_le(fdstat.fs_flags), fs_flags: PrimInt::to_le(fdstat.fs_flags),
@@ -326,7 +330,7 @@ dec_enc_scalar!(__wasi_oflags_t, dec_oflags_byref, enc_oflags_byref);
pub(crate) fn dec_prestat_byref( pub(crate) fn dec_prestat_byref(
memory: &mut [u8], memory: &mut [u8],
prestat_ptr: wasi32::uintptr_t, prestat_ptr: wasi32::uintptr_t,
) -> Result<host::__wasi_prestat_t> { ) -> WasiResult<host::__wasi_prestat_t> {
let raw = dec_raw_byref::<wasi32::__wasi_prestat_t>(memory, prestat_ptr)?; let raw = dec_raw_byref::<wasi32::__wasi_prestat_t>(memory, prestat_ptr)?;
match PrimInt::from_le(raw.tag) { match PrimInt::from_le(raw.tag) {
@@ -338,7 +342,7 @@ pub(crate) fn dec_prestat_byref(
}, },
}, },
}), }),
_ => Err(Error::EINVAL), _ => Err(WasiError::EINVAL),
} }
} }
@@ -346,7 +350,7 @@ pub(crate) fn enc_prestat_byref(
memory: &mut [u8], memory: &mut [u8],
prestat_ptr: wasi32::uintptr_t, prestat_ptr: wasi32::uintptr_t,
prestat: host::__wasi_prestat_t, prestat: host::__wasi_prestat_t,
) -> Result<()> { ) -> WasiResult<()> {
let raw = match prestat.tag { let raw = match prestat.tag {
wasi::__WASI_PREOPENTYPE_DIR => Ok(wasi32::__wasi_prestat_t { wasi::__WASI_PREOPENTYPE_DIR => Ok(wasi32::__wasi_prestat_t {
tag: PrimInt::to_le(wasi::__WASI_PREOPENTYPE_DIR), tag: PrimInt::to_le(wasi::__WASI_PREOPENTYPE_DIR),
@@ -356,7 +360,7 @@ pub(crate) fn enc_prestat_byref(
}, },
}, },
}), }),
_ => Err(Error::EINVAL), _ => Err(WasiError::EINVAL),
}?; }?;
enc_raw_byref::<wasi32::__wasi_prestat_t>(memory, prestat_ptr, raw) enc_raw_byref::<wasi32::__wasi_prestat_t>(memory, prestat_ptr, raw)
@@ -377,7 +381,7 @@ pub(crate) fn enc_usize_byref(
memory: &mut [u8], memory: &mut [u8],
usize_ptr: wasi32::uintptr_t, usize_ptr: wasi32::uintptr_t,
host_usize: usize, host_usize: usize,
) -> Result<()> { ) -> WasiResult<()> {
enc_int_byref::<wasi32::size_t>(memory, usize_ptr, enc_usize(host_usize)) enc_int_byref::<wasi32::size_t>(memory, usize_ptr, enc_usize(host_usize))
} }
@@ -402,7 +406,7 @@ pub(crate) fn dec_subscriptions(
memory: &mut [u8], memory: &mut [u8],
input: wasi32::uintptr_t, input: wasi32::uintptr_t,
nsubscriptions: wasi32::size_t, nsubscriptions: wasi32::size_t,
) -> Result<Vec<wasi::__wasi_subscription_t>> { ) -> WasiResult<Vec<wasi::__wasi_subscription_t>> {
let raw_input_slice = let raw_input_slice =
dec_raw_slice_of::<wasi::__wasi_subscription_t>(memory, input, nsubscriptions)?; dec_raw_slice_of::<wasi::__wasi_subscription_t>(memory, input, nsubscriptions)?;
@@ -435,14 +439,14 @@ pub(crate) fn dec_subscriptions(
}), }),
}, },
}, },
_ => return Err(Error::EINVAL), _ => return Err(WasiError::EINVAL),
}; };
Ok(wasi::__wasi_subscription_t { Ok(wasi::__wasi_subscription_t {
userdata, userdata,
u: wasi::__wasi_subscription_u_t { tag, u }, u: wasi::__wasi_subscription_u_t { tag, u },
}) })
}) })
.collect::<Result<Vec<_>>>() .collect::<WasiResult<Vec<_>>>()
} }
pub(crate) fn enc_events( pub(crate) fn enc_events(
@@ -450,7 +454,7 @@ pub(crate) fn enc_events(
output: wasi32::uintptr_t, output: wasi32::uintptr_t,
nsubscriptions: wasi32::size_t, nsubscriptions: wasi32::size_t,
events: Vec<wasi::__wasi_event_t>, events: Vec<wasi::__wasi_event_t>,
) -> Result<()> { ) -> WasiResult<()> {
let mut raw_output_iter = let mut raw_output_iter =
dec_raw_slice_of_mut::<wasi::__wasi_event_t>(memory, output, nsubscriptions)?.into_iter(); dec_raw_slice_of_mut::<wasi::__wasi_event_t>(memory, output, nsubscriptions)?.into_iter();

View File

@@ -1,14 +1,42 @@
use crate::old::snapshot_0::fdentry::FdEntry; use crate::old::snapshot_0::fdentry::FdEntry;
use crate::old::snapshot_0::{wasi, Error, Result}; use crate::old::snapshot_0::wasi::{self, WasiError, WasiResult};
use std::borrow::Borrow; use std::borrow::Borrow;
use std::collections::HashMap; use std::collections::HashMap;
use std::env; use std::ffi::{self, CString, OsString};
use std::ffi::{CString, OsString};
use std::fs::File; use std::fs::File;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use std::{env, io, string};
/// Possible errors when `WasiCtxBuilder` fails building
/// `WasiCtx`.
#[derive(Debug, thiserror::Error)]
pub enum WasiCtxBuilderError {
/// General I/O error was encountered.
#[error("general I/O error encountered: {0}")]
Io(#[from] io::Error),
/// Provided sequence of bytes was not a valid UTF-8.
#[error("provided sequence is not valid UTF-8: {0}")]
InvalidUtf8(#[from] string::FromUtf8Error),
/// Provided sequence of bytes was not a valid UTF-16.
///
/// This error is expected to only occur on Windows hosts.
#[error("provided sequence is not valid UTF-16: {0}")]
InvalidUtf16(#[from] string::FromUtf16Error),
/// Provided sequence of bytes contained an unexpected NUL byte.
#[error("provided sequence contained an unexpected NUL byte")]
UnexpectedNul(#[from] ffi::NulError),
/// Provided `File` is not a directory.
#[error("preopened directory path {} is not a directory", .0.display())]
NotADirectory(PathBuf),
/// `WasiCtx` has too many opened files.
#[error("context object has too many opened files")]
TooManyFilesOpen,
}
type WasiCtxBuilderResult<T> = std::result::Result<T, WasiCtxBuilderError>;
enum PendingFdEntry { enum PendingFdEntry {
Thunk(fn() -> Result<FdEntry>), Thunk(fn() -> io::Result<FdEntry>),
File(File), File(File),
} }
@@ -18,7 +46,7 @@ impl std::fmt::Debug for PendingFdEntry {
Self::Thunk(f) => write!( Self::Thunk(f) => write!(
fmt, fmt,
"PendingFdEntry::Thunk({:p})", "PendingFdEntry::Thunk({:p})",
f as *const fn() -> Result<FdEntry> f as *const fn() -> io::Result<FdEntry>
), ),
Self::File(f) => write!(fmt, "PendingFdEntry::File({:?})", f), Self::File(f) => write!(fmt, "PendingFdEntry::File({:?})", f),
} }
@@ -44,17 +72,29 @@ impl From<OsString> for PendingCString {
} }
impl PendingCString { impl PendingCString {
fn into_string(self) -> Result<String> { fn into_string(self) -> WasiCtxBuilderResult<String> {
match self { let res = match self {
Self::Bytes(v) => String::from_utf8(v).map_err(|_| Error::EILSEQ), Self::Bytes(v) => String::from_utf8(v)?,
Self::OsString(s) => s.into_string().map_err(|_| Error::EILSEQ), #[cfg(unix)]
} Self::OsString(s) => {
use std::os::unix::ffi::OsStringExt;
String::from_utf8(s.into_vec())?
}
#[cfg(windows)]
Self::OsString(s) => {
use std::os::windows::ffi::OsStrExt;
let bytes: Vec<u16> = s.encode_wide().collect();
String::from_utf16(&bytes)?
}
};
Ok(res)
} }
/// Create a `CString` containing valid UTF-8, or fail with `Error::EILSEQ`. /// Create a `CString` containing valid UTF-8, or fail.
fn into_utf8_cstring(self) -> Result<CString> { fn into_utf8_cstring(self) -> WasiCtxBuilderResult<CString> {
self.into_string() let s = self.into_string()?;
.and_then(|s| CString::new(s).map_err(|_| Error::EILSEQ)) let s = CString::new(s)?;
Ok(s)
} }
} }
@@ -85,8 +125,7 @@ impl WasiCtxBuilder {
/// Add arguments to the command-line arguments list. /// Add arguments to the command-line arguments list.
/// ///
/// Arguments must be valid UTF-8 with no NUL bytes, or else `WasiCtxBuilder::build()` will fail /// Arguments must be valid UTF-8 with no NUL bytes, or else `WasiCtxBuilder::build()` will fail.
/// with `Error::EILSEQ`.
pub fn args<S: AsRef<[u8]>>(mut self, args: impl IntoIterator<Item = S>) -> Self { pub fn args<S: AsRef<[u8]>>(mut self, args: impl IntoIterator<Item = S>) -> Self {
self.args = args self.args = args
.into_iter() .into_iter()
@@ -97,8 +136,7 @@ impl WasiCtxBuilder {
/// Add an argument to the command-line arguments list. /// Add an argument to the command-line arguments list.
/// ///
/// Arguments must be valid UTF-8 with no NUL bytes, or else `WasiCtxBuilder::build()` will fail /// Arguments must be valid UTF-8 with no NUL bytes, or else `WasiCtxBuilder::build()` will fail.
/// with `Error::EILSEQ`.
pub fn arg<S: AsRef<[u8]>>(mut self, arg: S) -> Self { pub fn arg<S: AsRef<[u8]>>(mut self, arg: S) -> Self {
self.args.push(arg.as_ref().to_vec().into()); self.args.push(arg.as_ref().to_vec().into());
self self
@@ -107,7 +145,7 @@ impl WasiCtxBuilder {
/// Inherit the command-line arguments from the host process. /// Inherit the command-line arguments from the host process.
/// ///
/// If any arguments from the host process contain invalid UTF-8, `WasiCtxBuilder::build()` will /// If any arguments from the host process contain invalid UTF-8, `WasiCtxBuilder::build()` will
/// fail with `Error::EILSEQ`. /// fail.
pub fn inherit_args(mut self) -> Self { pub fn inherit_args(mut self) -> Self {
self.args = env::args_os().map(PendingCString::OsString).collect(); self.args = env::args_os().map(PendingCString::OsString).collect();
self self
@@ -127,8 +165,7 @@ impl WasiCtxBuilder {
/// Inherit the environment variables from the host process. /// Inherit the environment variables from the host process.
/// ///
/// If any environment variables from the host process contain invalid Unicode (UTF-16 for /// If any environment variables from the host process contain invalid Unicode (UTF-16 for
/// Windows, UTF-8 for other platforms), `WasiCtxBuilder::build()` will fail with /// Windows, UTF-8 for other platforms), `WasiCtxBuilder::build()` will fail.
/// `Error::EILSEQ`.
pub fn inherit_env(mut self) -> Self { pub fn inherit_env(mut self) -> Self {
self.env = std::env::vars_os() self.env = std::env::vars_os()
.map(|(k, v)| (k.into(), v.into())) .map(|(k, v)| (k.into(), v.into()))
@@ -139,7 +176,7 @@ impl WasiCtxBuilder {
/// Add an entry to the environment. /// Add an entry to the environment.
/// ///
/// Environment variable keys and values must be valid UTF-8 with no NUL bytes, or else /// Environment variable keys and values must be valid UTF-8 with no NUL bytes, or else
/// `WasiCtxBuilder::build()` will fail with `Error::EILSEQ`. /// `WasiCtxBuilder::build()` will fail.
pub fn env<S: AsRef<[u8]>>(mut self, k: S, v: S) -> Self { pub fn env<S: AsRef<[u8]>>(mut self, k: S, v: S) -> Self {
self.env self.env
.insert(k.as_ref().to_vec().into(), v.as_ref().to_vec().into()); .insert(k.as_ref().to_vec().into(), v.as_ref().to_vec().into());
@@ -149,7 +186,7 @@ impl WasiCtxBuilder {
/// Add entries to the environment. /// Add entries to the environment.
/// ///
/// Environment variable keys and values must be valid UTF-8 with no NUL bytes, or else /// Environment variable keys and values must be valid UTF-8 with no NUL bytes, or else
/// `WasiCtxBuilder::build()` will fail with `Error::EILSEQ`. /// `WasiCtxBuilder::build()` will fail.
pub fn envs<S: AsRef<[u8]>, T: Borrow<(S, S)>>( pub fn envs<S: AsRef<[u8]>, T: Borrow<(S, S)>>(
mut self, mut self,
envs: impl IntoIterator<Item = T>, envs: impl IntoIterator<Item = T>,
@@ -191,15 +228,15 @@ impl WasiCtxBuilder {
/// Build a `WasiCtx`, consuming this `WasiCtxBuilder`. /// Build a `WasiCtx`, consuming this `WasiCtxBuilder`.
/// ///
/// If any of the arguments or environment variables in this builder cannot be converted into /// If any of the arguments or environment variables in this builder cannot be converted into
/// `CString`s, either due to NUL bytes or Unicode conversions, this returns `Error::EILSEQ`. /// `CString`s, either due to NUL bytes or Unicode conversions, this returns an error.
pub fn build(self) -> Result<WasiCtx> { pub fn build(self) -> WasiCtxBuilderResult<WasiCtx> {
// Process arguments and environment variables into `CString`s, failing quickly if they // Process arguments and environment variables into `CString`s, failing quickly if they
// contain any NUL bytes, or if conversion from `OsString` fails. // contain any NUL bytes, or if conversion from `OsString` fails.
let args = self let args = self
.args .args
.into_iter() .into_iter()
.map(|arg| arg.into_utf8_cstring()) .map(|arg| arg.into_utf8_cstring())
.collect::<Result<Vec<CString>>>()?; .collect::<WasiCtxBuilderResult<Vec<CString>>>()?;
let env = self let env = self
.env .env
@@ -211,11 +248,12 @@ impl WasiCtxBuilder {
pair.push_str(v.as_str()); pair.push_str(v.as_str());
// We have valid UTF-8, but the keys and values have not yet been checked // We have valid UTF-8, but the keys and values have not yet been checked
// for NULs, so we do a final check here. // for NULs, so we do a final check here.
CString::new(pair).map_err(|_| Error::EILSEQ) let s = CString::new(pair)?;
Ok(s)
}) })
}) })
}) })
.collect::<Result<Vec<CString>>>()?; .collect::<WasiCtxBuilderResult<Vec<CString>>>()?;
let mut fds: HashMap<wasi::__wasi_fd_t, FdEntry> = HashMap::new(); let mut fds: HashMap<wasi::__wasi_fd_t, FdEntry> = HashMap::new();
// Populate the non-preopen fds. // Populate the non-preopen fds.
@@ -237,16 +275,20 @@ impl WasiCtxBuilder {
for (guest_path, dir) in self.preopens { for (guest_path, dir) in self.preopens {
// We do the increment at the beginning of the loop body, so that we don't overflow // We do the increment at the beginning of the loop body, so that we don't overflow
// unnecessarily if we have exactly the maximum number of file descriptors. // unnecessarily if we have exactly the maximum number of file descriptors.
preopen_fd = preopen_fd.checked_add(1).ok_or(Error::ENFILE)?; preopen_fd = preopen_fd
.checked_add(1)
.ok_or(WasiCtxBuilderError::TooManyFilesOpen)?;
if !dir.metadata()?.is_dir() { if !dir.metadata()?.is_dir() {
return Err(Error::EBADF); return Err(WasiCtxBuilderError::NotADirectory(guest_path));
} }
// We don't currently allow setting file descriptors other than 0-2, but this will avoid // We don't currently allow setting file descriptors other than 0-2, but this will avoid
// collisions if we restore that functionality in the future. // collisions if we restore that functionality in the future.
while fds.contains_key(&preopen_fd) { while fds.contains_key(&preopen_fd) {
preopen_fd = preopen_fd.checked_add(1).ok_or(Error::ENFILE)?; preopen_fd = preopen_fd
.checked_add(1)
.ok_or(WasiCtxBuilderError::TooManyFilesOpen)?;
} }
let mut fe = FdEntry::from(dir)?; let mut fe = FdEntry::from(dir)?;
fe.preopen_path = Some(guest_path); fe.preopen_path = Some(guest_path);
@@ -274,7 +316,7 @@ impl WasiCtx {
/// - Environment variables are inherited from the host process. /// - Environment variables are inherited from the host process.
/// ///
/// To override these behaviors, use `WasiCtxBuilder`. /// To override these behaviors, use `WasiCtxBuilder`.
pub fn new<S: AsRef<[u8]>>(args: impl IntoIterator<Item = S>) -> Result<Self> { pub fn new<S: AsRef<[u8]>>(args: impl IntoIterator<Item = S>) -> WasiCtxBuilderResult<Self> {
WasiCtxBuilder::new() WasiCtxBuilder::new()
.args(args) .args(args)
.inherit_stdio() .inherit_stdio()
@@ -288,30 +330,30 @@ impl WasiCtx {
} }
/// Get an immutable `FdEntry` corresponding to the specified raw WASI `fd`. /// Get an immutable `FdEntry` corresponding to the specified raw WASI `fd`.
pub(crate) unsafe fn get_fd_entry(&self, fd: wasi::__wasi_fd_t) -> Result<&FdEntry> { pub(crate) unsafe fn get_fd_entry(&self, fd: wasi::__wasi_fd_t) -> WasiResult<&FdEntry> {
self.fds.get(&fd).ok_or(Error::EBADF) self.fds.get(&fd).ok_or(WasiError::EBADF)
} }
/// Get a mutable `FdEntry` corresponding to the specified raw WASI `fd`. /// Get a mutable `FdEntry` corresponding to the specified raw WASI `fd`.
pub(crate) unsafe fn get_fd_entry_mut( pub(crate) unsafe fn get_fd_entry_mut(
&mut self, &mut self,
fd: wasi::__wasi_fd_t, fd: wasi::__wasi_fd_t,
) -> Result<&mut FdEntry> { ) -> WasiResult<&mut FdEntry> {
self.fds.get_mut(&fd).ok_or(Error::EBADF) self.fds.get_mut(&fd).ok_or(WasiError::EBADF)
} }
/// Insert the specified `FdEntry` into the `WasiCtx` object. /// Insert the specified `FdEntry` into the `WasiCtx` object.
/// ///
/// The `FdEntry` will automatically get another free raw WASI `fd` assigned. Note that /// The `FdEntry` 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. /// the two subsequent free raw WASI `fd`s do not have to be stored contiguously.
pub(crate) fn insert_fd_entry(&mut self, fe: FdEntry) -> Result<wasi::__wasi_fd_t> { pub(crate) fn insert_fd_entry(&mut self, fe: FdEntry) -> WasiResult<wasi::__wasi_fd_t> {
// Never insert where stdio handles are expected to be. // Never insert where stdio handles are expected to be.
let mut fd = 3; let mut fd = 3;
while self.fds.contains_key(&fd) { while self.fds.contains_key(&fd) {
if let Some(next_fd) = fd.checked_add(1) { if let Some(next_fd) = fd.checked_add(1) {
fd = next_fd; fd = next_fd;
} else { } else {
return Err(Error::EMFILE); return Err(WasiError::EMFILE);
} }
} }
self.fds.insert(fd, fe); self.fds.insert(fd, fe);
@@ -329,7 +371,7 @@ impl WasiCtx {
} }
/// Remove `FdEntry` corresponding to the specified raw WASI `fd` from the `WasiCtx` object. /// Remove `FdEntry` corresponding to the specified raw WASI `fd` from the `WasiCtx` object.
pub(crate) fn remove_fd_entry(&mut self, fd: wasi::__wasi_fd_t) -> Result<FdEntry> { pub(crate) fn remove_fd_entry(&mut self, fd: wasi::__wasi_fd_t) -> WasiResult<FdEntry> {
self.fds.remove(&fd).ok_or(Error::EBADF) self.fds.remove(&fd).ok_or(WasiError::EBADF)
} }
} }

View File

@@ -1,234 +0,0 @@
// Due to https://github.com/rust-lang/rust/issues/64247
#![allow(clippy::use_self)]
use crate::old::snapshot_0::wasi;
use std::convert::Infallible;
use std::num::TryFromIntError;
use std::{ffi, str};
use thiserror::Error;
#[derive(Clone, Copy, Debug, Error, Eq, PartialEq)]
#[repr(u16)]
#[error("{:?} ({})", self, wasi::strerror(*self as wasi::__wasi_errno_t))]
pub enum WasiError {
ESUCCESS = wasi::__WASI_ERRNO_SUCCESS,
E2BIG = wasi::__WASI_ERRNO_2BIG,
EACCES = wasi::__WASI_ERRNO_ACCES,
EADDRINUSE = wasi::__WASI_ERRNO_ADDRINUSE,
EADDRNOTAVAIL = wasi::__WASI_ERRNO_ADDRNOTAVAIL,
EAFNOSUPPORT = wasi::__WASI_ERRNO_AFNOSUPPORT,
EAGAIN = wasi::__WASI_ERRNO_AGAIN,
EALREADY = wasi::__WASI_ERRNO_ALREADY,
EBADF = wasi::__WASI_ERRNO_BADF,
EBADMSG = wasi::__WASI_ERRNO_BADMSG,
EBUSY = wasi::__WASI_ERRNO_BUSY,
ECANCELED = wasi::__WASI_ERRNO_CANCELED,
ECHILD = wasi::__WASI_ERRNO_CHILD,
ECONNABORTED = wasi::__WASI_ERRNO_CONNABORTED,
ECONNREFUSED = wasi::__WASI_ERRNO_CONNREFUSED,
ECONNRESET = wasi::__WASI_ERRNO_CONNRESET,
EDEADLK = wasi::__WASI_ERRNO_DEADLK,
EDESTADDRREQ = wasi::__WASI_ERRNO_DESTADDRREQ,
EDOM = wasi::__WASI_ERRNO_DOM,
EDQUOT = wasi::__WASI_ERRNO_DQUOT,
EEXIST = wasi::__WASI_ERRNO_EXIST,
EFAULT = wasi::__WASI_ERRNO_FAULT,
EFBIG = wasi::__WASI_ERRNO_FBIG,
EHOSTUNREACH = wasi::__WASI_ERRNO_HOSTUNREACH,
EIDRM = wasi::__WASI_ERRNO_IDRM,
EILSEQ = wasi::__WASI_ERRNO_ILSEQ,
EINPROGRESS = wasi::__WASI_ERRNO_INPROGRESS,
EINTR = wasi::__WASI_ERRNO_INTR,
EINVAL = wasi::__WASI_ERRNO_INVAL,
EIO = wasi::__WASI_ERRNO_IO,
EISCONN = wasi::__WASI_ERRNO_ISCONN,
EISDIR = wasi::__WASI_ERRNO_ISDIR,
ELOOP = wasi::__WASI_ERRNO_LOOP,
EMFILE = wasi::__WASI_ERRNO_MFILE,
EMLINK = wasi::__WASI_ERRNO_MLINK,
EMSGSIZE = wasi::__WASI_ERRNO_MSGSIZE,
EMULTIHOP = wasi::__WASI_ERRNO_MULTIHOP,
ENAMETOOLONG = wasi::__WASI_ERRNO_NAMETOOLONG,
ENETDOWN = wasi::__WASI_ERRNO_NETDOWN,
ENETRESET = wasi::__WASI_ERRNO_NETRESET,
ENETUNREACH = wasi::__WASI_ERRNO_NETUNREACH,
ENFILE = wasi::__WASI_ERRNO_NFILE,
ENOBUFS = wasi::__WASI_ERRNO_NOBUFS,
ENODEV = wasi::__WASI_ERRNO_NODEV,
ENOENT = wasi::__WASI_ERRNO_NOENT,
ENOEXEC = wasi::__WASI_ERRNO_NOEXEC,
ENOLCK = wasi::__WASI_ERRNO_NOLCK,
ENOLINK = wasi::__WASI_ERRNO_NOLINK,
ENOMEM = wasi::__WASI_ERRNO_NOMEM,
ENOMSG = wasi::__WASI_ERRNO_NOMSG,
ENOPROTOOPT = wasi::__WASI_ERRNO_NOPROTOOPT,
ENOSPC = wasi::__WASI_ERRNO_NOSPC,
ENOSYS = wasi::__WASI_ERRNO_NOSYS,
ENOTCONN = wasi::__WASI_ERRNO_NOTCONN,
ENOTDIR = wasi::__WASI_ERRNO_NOTDIR,
ENOTEMPTY = wasi::__WASI_ERRNO_NOTEMPTY,
ENOTRECOVERABLE = wasi::__WASI_ERRNO_NOTRECOVERABLE,
ENOTSOCK = wasi::__WASI_ERRNO_NOTSOCK,
ENOTSUP = wasi::__WASI_ERRNO_NOTSUP,
ENOTTY = wasi::__WASI_ERRNO_NOTTY,
ENXIO = wasi::__WASI_ERRNO_NXIO,
EOVERFLOW = wasi::__WASI_ERRNO_OVERFLOW,
EOWNERDEAD = wasi::__WASI_ERRNO_OWNERDEAD,
EPERM = wasi::__WASI_ERRNO_PERM,
EPIPE = wasi::__WASI_ERRNO_PIPE,
EPROTO = wasi::__WASI_ERRNO_PROTO,
EPROTONOSUPPORT = wasi::__WASI_ERRNO_PROTONOSUPPORT,
EPROTOTYPE = wasi::__WASI_ERRNO_PROTOTYPE,
ERANGE = wasi::__WASI_ERRNO_RANGE,
EROFS = wasi::__WASI_ERRNO_ROFS,
ESPIPE = wasi::__WASI_ERRNO_SPIPE,
ESRCH = wasi::__WASI_ERRNO_SRCH,
ESTALE = wasi::__WASI_ERRNO_STALE,
ETIMEDOUT = wasi::__WASI_ERRNO_TIMEDOUT,
ETXTBSY = wasi::__WASI_ERRNO_TXTBSY,
EXDEV = wasi::__WASI_ERRNO_XDEV,
ENOTCAPABLE = wasi::__WASI_ERRNO_NOTCAPABLE,
}
impl WasiError {
pub fn as_raw_errno(self) -> wasi::__wasi_errno_t {
self as wasi::__wasi_errno_t
}
}
#[derive(Debug, Error)]
pub enum Error {
#[error("WASI error code: {0}")]
Wasi(#[from] WasiError),
#[error("IO error: {0}")]
Io(#[from] std::io::Error),
}
impl From<TryFromIntError> for Error {
fn from(_: TryFromIntError) -> Self {
Self::EOVERFLOW
}
}
impl From<Infallible> for Error {
fn from(_: Infallible) -> Self {
unreachable!()
}
}
impl From<str::Utf8Error> for Error {
fn from(_: str::Utf8Error) -> Self {
Self::EILSEQ
}
}
impl From<ffi::NulError> for Error {
fn from(_: ffi::NulError) -> Self {
Self::EILSEQ
}
}
impl From<&ffi::NulError> for Error {
fn from(_: &ffi::NulError) -> Self {
Self::EILSEQ
}
}
impl Error {
pub(crate) fn as_wasi_error(&self) -> WasiError {
match self {
Self::Wasi(err) => *err,
Self::Io(err) => {
let err = match err.raw_os_error() {
Some(code) => Self::from_raw_os_error(code),
None => {
log::debug!("Inconvertible OS error: {}", err);
Self::EIO
}
};
err.as_wasi_error()
}
}
}
pub const ESUCCESS: Self = Error::Wasi(WasiError::ESUCCESS);
pub const E2BIG: Self = Error::Wasi(WasiError::E2BIG);
pub const EACCES: Self = Error::Wasi(WasiError::EACCES);
pub const EADDRINUSE: Self = Error::Wasi(WasiError::EADDRINUSE);
pub const EADDRNOTAVAIL: Self = Error::Wasi(WasiError::EADDRNOTAVAIL);
pub const EAFNOSUPPORT: Self = Error::Wasi(WasiError::EAFNOSUPPORT);
pub const EAGAIN: Self = Error::Wasi(WasiError::EAGAIN);
pub const EALREADY: Self = Error::Wasi(WasiError::EALREADY);
pub const EBADF: Self = Error::Wasi(WasiError::EBADF);
pub const EBADMSG: Self = Error::Wasi(WasiError::EBADMSG);
pub const EBUSY: Self = Error::Wasi(WasiError::EBUSY);
pub const ECANCELED: Self = Error::Wasi(WasiError::ECANCELED);
pub const ECHILD: Self = Error::Wasi(WasiError::ECHILD);
pub const ECONNABORTED: Self = Error::Wasi(WasiError::ECONNABORTED);
pub const ECONNREFUSED: Self = Error::Wasi(WasiError::ECONNREFUSED);
pub const ECONNRESET: Self = Error::Wasi(WasiError::ECONNRESET);
pub const EDEADLK: Self = Error::Wasi(WasiError::EDEADLK);
pub const EDESTADDRREQ: Self = Error::Wasi(WasiError::EDESTADDRREQ);
pub const EDOM: Self = Error::Wasi(WasiError::EDOM);
pub const EDQUOT: Self = Error::Wasi(WasiError::EDQUOT);
pub const EEXIST: Self = Error::Wasi(WasiError::EEXIST);
pub const EFAULT: Self = Error::Wasi(WasiError::EFAULT);
pub const EFBIG: Self = Error::Wasi(WasiError::EFBIG);
pub const EHOSTUNREACH: Self = Error::Wasi(WasiError::EHOSTUNREACH);
pub const EIDRM: Self = Error::Wasi(WasiError::EIDRM);
pub const EILSEQ: Self = Error::Wasi(WasiError::EILSEQ);
pub const EINPROGRESS: Self = Error::Wasi(WasiError::EINPROGRESS);
pub const EINTR: Self = Error::Wasi(WasiError::EINTR);
pub const EINVAL: Self = Error::Wasi(WasiError::EINVAL);
pub const EIO: Self = Error::Wasi(WasiError::EIO);
pub const EISCONN: Self = Error::Wasi(WasiError::EISCONN);
pub const EISDIR: Self = Error::Wasi(WasiError::EISDIR);
pub const ELOOP: Self = Error::Wasi(WasiError::ELOOP);
pub const EMFILE: Self = Error::Wasi(WasiError::EMFILE);
pub const EMLINK: Self = Error::Wasi(WasiError::EMLINK);
pub const EMSGSIZE: Self = Error::Wasi(WasiError::EMSGSIZE);
pub const EMULTIHOP: Self = Error::Wasi(WasiError::EMULTIHOP);
pub const ENAMETOOLONG: Self = Error::Wasi(WasiError::ENAMETOOLONG);
pub const ENETDOWN: Self = Error::Wasi(WasiError::ENETDOWN);
pub const ENETRESET: Self = Error::Wasi(WasiError::ENETRESET);
pub const ENETUNREACH: Self = Error::Wasi(WasiError::ENETUNREACH);
pub const ENFILE: Self = Error::Wasi(WasiError::ENFILE);
pub const ENOBUFS: Self = Error::Wasi(WasiError::ENOBUFS);
pub const ENODEV: Self = Error::Wasi(WasiError::ENODEV);
pub const ENOENT: Self = Error::Wasi(WasiError::ENOENT);
pub const ENOEXEC: Self = Error::Wasi(WasiError::ENOEXEC);
pub const ENOLCK: Self = Error::Wasi(WasiError::ENOLCK);
pub const ENOLINK: Self = Error::Wasi(WasiError::ENOLINK);
pub const ENOMEM: Self = Error::Wasi(WasiError::ENOMEM);
pub const ENOMSG: Self = Error::Wasi(WasiError::ENOMSG);
pub const ENOPROTOOPT: Self = Error::Wasi(WasiError::ENOPROTOOPT);
pub const ENOSPC: Self = Error::Wasi(WasiError::ENOSPC);
pub const ENOSYS: Self = Error::Wasi(WasiError::ENOSYS);
pub const ENOTCONN: Self = Error::Wasi(WasiError::ENOTCONN);
pub const ENOTDIR: Self = Error::Wasi(WasiError::ENOTDIR);
pub const ENOTEMPTY: Self = Error::Wasi(WasiError::ENOTEMPTY);
pub const ENOTRECOVERABLE: Self = Error::Wasi(WasiError::ENOTRECOVERABLE);
pub const ENOTSOCK: Self = Error::Wasi(WasiError::ENOTSOCK);
pub const ENOTSUP: Self = Error::Wasi(WasiError::ENOTSUP);
pub const ENOTTY: Self = Error::Wasi(WasiError::ENOTTY);
pub const ENXIO: Self = Error::Wasi(WasiError::ENXIO);
pub const EOVERFLOW: Self = Error::Wasi(WasiError::EOVERFLOW);
pub const EOWNERDEAD: Self = Error::Wasi(WasiError::EOWNERDEAD);
pub const EPERM: Self = Error::Wasi(WasiError::EPERM);
pub const EPIPE: Self = Error::Wasi(WasiError::EPIPE);
pub const EPROTO: Self = Error::Wasi(WasiError::EPROTO);
pub const EPROTONOSUPPORT: Self = Error::Wasi(WasiError::EPROTONOSUPPORT);
pub const EPROTOTYPE: Self = Error::Wasi(WasiError::EPROTOTYPE);
pub const ERANGE: Self = Error::Wasi(WasiError::ERANGE);
pub const EROFS: Self = Error::Wasi(WasiError::EROFS);
pub const ESPIPE: Self = Error::Wasi(WasiError::ESPIPE);
pub const ESRCH: Self = Error::Wasi(WasiError::ESRCH);
pub const ESTALE: Self = Error::Wasi(WasiError::ESTALE);
pub const ETIMEDOUT: Self = Error::Wasi(WasiError::ETIMEDOUT);
pub const ETXTBSY: Self = Error::Wasi(WasiError::ETXTBSY);
pub const EXDEV: Self = Error::Wasi(WasiError::EXDEV);
pub const ENOTCAPABLE: Self = Error::Wasi(WasiError::ENOTCAPABLE);
}
pub(crate) trait FromRawOsError {
fn from_raw_os_error(code: i32) -> Self;
}

View File

@@ -2,7 +2,7 @@ use crate::old::snapshot_0::sys::dev_null;
use crate::old::snapshot_0::sys::fdentry_impl::{ use crate::old::snapshot_0::sys::fdentry_impl::{
descriptor_as_oshandle, determine_type_and_access_rights, OsHandle, descriptor_as_oshandle, determine_type_and_access_rights, OsHandle,
}; };
use crate::old::snapshot_0::{wasi, Error, Result}; use crate::old::snapshot_0::wasi::{self, WasiError, WasiResult};
use std::marker::PhantomData; use std::marker::PhantomData;
use std::mem::ManuallyDrop; use std::mem::ManuallyDrop;
use std::ops::{Deref, DerefMut}; use std::ops::{Deref, DerefMut};
@@ -21,18 +21,18 @@ impl Descriptor {
/// Return a reference to the `OsHandle` treating it as an actual file/dir, and /// Return a reference to the `OsHandle` treating it as an actual file/dir, and
/// allowing operations which require an actual file and not just a stream or /// allowing operations which require an actual file and not just a stream or
/// socket file descriptor. /// socket file descriptor.
pub(crate) fn as_file(&self) -> Result<&OsHandle> { pub(crate) fn as_file(&self) -> WasiResult<&OsHandle> {
match self { match self {
Self::OsHandle(file) => Ok(file), Self::OsHandle(file) => Ok(file),
_ => Err(Error::EBADF), _ => Err(WasiError::EBADF),
} }
} }
/// Like `as_file`, but return a mutable reference. /// Like `as_file`, but return a mutable reference.
pub(crate) fn as_file_mut(&mut self) -> Result<&mut OsHandle> { pub(crate) fn as_file_mut(&mut self) -> WasiResult<&mut OsHandle> {
match self { match self {
Self::OsHandle(file) => Ok(file), Self::OsHandle(file) => Ok(file),
_ => Err(Error::EBADF), _ => Err(WasiError::EBADF),
} }
} }
@@ -64,7 +64,7 @@ impl FdEntry {
/// Create an FdEntry with *maximal* possible rights from a given `File`. /// Create an FdEntry with *maximal* possible rights from a given `File`.
/// If this is not desired, the rights of the resulting `FdEntry` should /// If this is not desired, the rights of the resulting `FdEntry` should
/// be manually restricted. /// be manually restricted.
pub(crate) fn from(file: fs::File) -> Result<Self> { pub(crate) fn from(file: fs::File) -> io::Result<Self> {
unsafe { determine_type_and_access_rights(&file) }.map( unsafe { determine_type_and_access_rights(&file) }.map(
|(file_type, rights_base, rights_inheriting)| Self { |(file_type, rights_base, rights_inheriting)| Self {
file_type, file_type,
@@ -76,7 +76,7 @@ impl FdEntry {
) )
} }
pub(crate) fn duplicate_stdin() -> Result<Self> { pub(crate) fn duplicate_stdin() -> io::Result<Self> {
unsafe { determine_type_and_access_rights(&io::stdin()) }.map( unsafe { determine_type_and_access_rights(&io::stdin()) }.map(
|(file_type, rights_base, rights_inheriting)| Self { |(file_type, rights_base, rights_inheriting)| Self {
file_type, file_type,
@@ -88,7 +88,7 @@ impl FdEntry {
) )
} }
pub(crate) fn duplicate_stdout() -> Result<Self> { pub(crate) fn duplicate_stdout() -> io::Result<Self> {
unsafe { determine_type_and_access_rights(&io::stdout()) }.map( unsafe { determine_type_and_access_rights(&io::stdout()) }.map(
|(file_type, rights_base, rights_inheriting)| Self { |(file_type, rights_base, rights_inheriting)| Self {
file_type, file_type,
@@ -100,7 +100,7 @@ impl FdEntry {
) )
} }
pub(crate) fn duplicate_stderr() -> Result<Self> { pub(crate) fn duplicate_stderr() -> io::Result<Self> {
unsafe { determine_type_and_access_rights(&io::stderr()) }.map( unsafe { determine_type_and_access_rights(&io::stderr()) }.map(
|(file_type, rights_base, rights_inheriting)| Self { |(file_type, rights_base, rights_inheriting)| Self {
file_type, file_type,
@@ -112,7 +112,7 @@ impl FdEntry {
) )
} }
pub(crate) fn null() -> Result<Self> { pub(crate) fn null() -> io::Result<Self> {
Self::from(dev_null()?) Self::from(dev_null()?)
} }
@@ -127,7 +127,7 @@ impl FdEntry {
&self, &self,
rights_base: wasi::__wasi_rights_t, rights_base: wasi::__wasi_rights_t,
rights_inheriting: wasi::__wasi_rights_t, rights_inheriting: wasi::__wasi_rights_t,
) -> Result<&Descriptor> { ) -> WasiResult<&Descriptor> {
self.validate_rights(rights_base, rights_inheriting)?; self.validate_rights(rights_base, rights_inheriting)?;
Ok(&self.descriptor) Ok(&self.descriptor)
} }
@@ -143,7 +143,7 @@ impl FdEntry {
&mut self, &mut self,
rights_base: wasi::__wasi_rights_t, rights_base: wasi::__wasi_rights_t,
rights_inheriting: wasi::__wasi_rights_t, rights_inheriting: wasi::__wasi_rights_t,
) -> Result<&mut Descriptor> { ) -> WasiResult<&mut Descriptor> {
self.validate_rights(rights_base, rights_inheriting)?; self.validate_rights(rights_base, rights_inheriting)?;
Ok(&mut self.descriptor) Ok(&mut self.descriptor)
} }
@@ -157,10 +157,10 @@ impl FdEntry {
&self, &self,
rights_base: wasi::__wasi_rights_t, rights_base: wasi::__wasi_rights_t,
rights_inheriting: wasi::__wasi_rights_t, rights_inheriting: wasi::__wasi_rights_t,
) -> Result<()> { ) -> WasiResult<()> {
if !self.rights_base & rights_base != 0 || !self.rights_inheriting & rights_inheriting != 0 if !self.rights_base & rights_base != 0 || !self.rights_inheriting & rights_inheriting != 0
{ {
Err(Error::ENOTCAPABLE) Err(WasiError::ENOTCAPABLE)
} else { } else {
Ok(()) Ok(())
} }

View File

@@ -1,10 +1,11 @@
use crate::old::snapshot_0::{Error, Result}; use crate::old::snapshot_0::wasi::WasiResult;
use std::str; use std::str;
/// Creates not-owned WASI path from byte slice. /// Creates not-owned WASI path from byte slice.
/// ///
/// NB WASI spec requires bytes to be valid UTF-8. Otherwise, /// NB WASI spec requires bytes to be valid UTF-8. Otherwise,
/// `__WASI_ERRNO_ILSEQ` error is returned. /// `__WASI_ERRNO_ILSEQ` error is returned.
pub(crate) fn path_from_slice<'a>(s: &'a [u8]) -> Result<&'a str> { pub(crate) fn path_from_slice<'a>(s: &'a [u8]) -> WasiResult<&'a str> {
str::from_utf8(s).map_err(|_| Error::EILSEQ) let s = str::from_utf8(s)?;
Ok(s)
} }

View File

@@ -5,7 +5,6 @@
#![allow(non_snake_case)] #![allow(non_snake_case)]
use crate::old::snapshot_0::wasi::*; use crate::old::snapshot_0::wasi::*;
use crate::old::snapshot_0::{Error, Result};
use std::{convert::TryInto, io, mem, slice}; use std::{convert::TryInto, io, mem, slice};
use wig::witx_host_types; use wig::witx_host_types;
@@ -52,11 +51,13 @@ pub(crate) struct Dirent {
impl Dirent { impl Dirent {
/// Serialize the directory entry to the format define by `__wasi_fd_readdir`, /// Serialize the directory entry to the format define by `__wasi_fd_readdir`,
/// so that the serialized entries can be concatenated by the implementation. /// so that the serialized entries can be concatenated by the implementation.
pub fn to_wasi_raw(&self) -> Result<Vec<u8>> { pub fn to_wasi_raw(&self) -> WasiResult<Vec<u8>> {
let name = self.name.as_bytes(); let name = self.name.as_bytes();
let namlen = name.len(); let namlen = name.len();
let dirent_size = mem::size_of::<__wasi_dirent_t>(); let dirent_size = mem::size_of::<__wasi_dirent_t>();
let offset = dirent_size.checked_add(namlen).ok_or(Error::EOVERFLOW)?; let offset = dirent_size
.checked_add(namlen)
.ok_or(WasiError::EOVERFLOW)?;
let mut raw = Vec::<u8>::with_capacity(offset); let mut raw = Vec::<u8>::with_capacity(offset);
raw.resize(offset, 0); raw.resize(offset, 0);

View File

@@ -7,7 +7,8 @@ use crate::old::snapshot_0::memory::*;
use crate::old::snapshot_0::sys::fdentry_impl::determine_type_rights; use crate::old::snapshot_0::sys::fdentry_impl::determine_type_rights;
use crate::old::snapshot_0::sys::hostcalls_impl::fs_helpers::path_open_rights; use crate::old::snapshot_0::sys::hostcalls_impl::fs_helpers::path_open_rights;
use crate::old::snapshot_0::sys::{host_impl, hostcalls_impl}; use crate::old::snapshot_0::sys::{host_impl, hostcalls_impl};
use crate::old::snapshot_0::{helpers, host, wasi, wasi32, Error, Result}; use crate::old::snapshot_0::wasi::{self, WasiError, WasiResult};
use crate::old::snapshot_0::{helpers, host, wasi32};
use crate::sandboxed_tty_writer::SandboxedTTYWriter; use crate::sandboxed_tty_writer::SandboxedTTYWriter;
use filetime::{set_file_handle_times, FileTime}; use filetime::{set_file_handle_times, FileTime};
use log::trace; use log::trace;
@@ -20,13 +21,13 @@ pub(crate) unsafe fn fd_close(
wasi_ctx: &mut WasiCtx, wasi_ctx: &mut WasiCtx,
_mem: &mut [u8], _mem: &mut [u8],
fd: wasi::__wasi_fd_t, fd: wasi::__wasi_fd_t,
) -> Result<()> { ) -> WasiResult<()> {
trace!("fd_close(fd={:?})", fd); trace!("fd_close(fd={:?})", fd);
if let Ok(fe) = wasi_ctx.get_fd_entry(fd) { if let Ok(fe) = wasi_ctx.get_fd_entry(fd) {
// can't close preopened files // can't close preopened files
if fe.preopen_path.is_some() { if fe.preopen_path.is_some() {
return Err(Error::ENOTSUP); return Err(WasiError::ENOTSUP);
} }
} }
@@ -38,7 +39,7 @@ pub(crate) unsafe fn fd_datasync(
wasi_ctx: &WasiCtx, wasi_ctx: &WasiCtx,
_mem: &mut [u8], _mem: &mut [u8],
fd: wasi::__wasi_fd_t, fd: wasi::__wasi_fd_t,
) -> Result<()> { ) -> WasiResult<()> {
trace!("fd_datasync(fd={:?})", fd); trace!("fd_datasync(fd={:?})", fd);
let fd = wasi_ctx let fd = wasi_ctx
@@ -57,7 +58,7 @@ pub(crate) unsafe fn fd_pread(
iovs_len: wasi32::size_t, iovs_len: wasi32::size_t,
offset: wasi::__wasi_filesize_t, offset: wasi::__wasi_filesize_t,
nread: wasi32::uintptr_t, nread: wasi32::uintptr_t,
) -> Result<()> { ) -> WasiResult<()> {
trace!( trace!(
"fd_pread(fd={:?}, iovs_ptr={:#x?}, iovs_len={:?}, offset={}, nread={:#x?})", "fd_pread(fd={:?}, iovs_ptr={:#x?}, iovs_len={:?}, offset={}, nread={:#x?})",
fd, fd,
@@ -75,7 +76,7 @@ pub(crate) unsafe fn fd_pread(
let iovs = dec_iovec_slice(memory, iovs_ptr, iovs_len)?; let iovs = dec_iovec_slice(memory, iovs_ptr, iovs_len)?;
if offset > i64::max_value() as u64 { if offset > i64::max_value() as u64 {
return Err(Error::EIO); return Err(WasiError::EIO);
} }
let buf_size = iovs.iter().map(|v| v.buf_len).sum(); let buf_size = iovs.iter().map(|v| v.buf_len).sum();
let mut buf = vec![0; buf_size]; let mut buf = vec![0; buf_size];
@@ -106,7 +107,7 @@ pub(crate) unsafe fn fd_pwrite(
iovs_len: wasi32::size_t, iovs_len: wasi32::size_t,
offset: wasi::__wasi_filesize_t, offset: wasi::__wasi_filesize_t,
nwritten: wasi32::uintptr_t, nwritten: wasi32::uintptr_t,
) -> Result<()> { ) -> WasiResult<()> {
trace!( trace!(
"fd_pwrite(fd={:?}, iovs_ptr={:#x?}, iovs_len={:?}, offset={}, nwritten={:#x?})", "fd_pwrite(fd={:?}, iovs_ptr={:#x?}, iovs_len={:?}, offset={}, nwritten={:#x?})",
fd, fd,
@@ -126,7 +127,7 @@ pub(crate) unsafe fn fd_pwrite(
let iovs = dec_ciovec_slice(memory, iovs_ptr, iovs_len)?; let iovs = dec_ciovec_slice(memory, iovs_ptr, iovs_len)?;
if offset > i64::max_value() as u64 { if offset > i64::max_value() as u64 {
return Err(Error::EIO); return Err(WasiError::EIO);
} }
let buf_size = iovs.iter().map(|v| v.buf_len).sum(); let buf_size = iovs.iter().map(|v| v.buf_len).sum();
let mut buf = Vec::with_capacity(buf_size); let mut buf = Vec::with_capacity(buf_size);
@@ -150,7 +151,7 @@ pub(crate) unsafe fn fd_read(
iovs_ptr: wasi32::uintptr_t, iovs_ptr: wasi32::uintptr_t,
iovs_len: wasi32::size_t, iovs_len: wasi32::size_t,
nread: wasi32::uintptr_t, nread: wasi32::uintptr_t,
) -> Result<()> { ) -> WasiResult<()> {
trace!( trace!(
"fd_read(fd={:?}, iovs_ptr={:#x?}, iovs_len={:?}, nread={:#x?})", "fd_read(fd={:?}, iovs_ptr={:#x?}, iovs_len={:?}, nread={:#x?})",
fd, fd,
@@ -171,7 +172,7 @@ pub(crate) unsafe fn fd_read(
{ {
Descriptor::OsHandle(file) => file.read_vectored(&mut iovs), Descriptor::OsHandle(file) => file.read_vectored(&mut iovs),
Descriptor::Stdin => io::stdin().read_vectored(&mut iovs), Descriptor::Stdin => io::stdin().read_vectored(&mut iovs),
_ => return Err(Error::EBADF), _ => return Err(WasiError::EBADF),
}; };
let host_nread = maybe_host_nread?; let host_nread = maybe_host_nread?;
@@ -186,11 +187,11 @@ pub(crate) unsafe fn fd_renumber(
_mem: &mut [u8], _mem: &mut [u8],
from: wasi::__wasi_fd_t, from: wasi::__wasi_fd_t,
to: wasi::__wasi_fd_t, to: wasi::__wasi_fd_t,
) -> Result<()> { ) -> WasiResult<()> {
trace!("fd_renumber(from={:?}, to={:?})", from, to); trace!("fd_renumber(from={:?}, to={:?})", from, to);
if !wasi_ctx.contains_fd_entry(from) { if !wasi_ctx.contains_fd_entry(from) {
return Err(Error::EBADF); return Err(WasiError::EBADF);
} }
// Don't allow renumbering over a pre-opened resource. // Don't allow renumbering over a pre-opened resource.
@@ -198,11 +199,11 @@ pub(crate) unsafe fn fd_renumber(
// userspace is capable of removing entries from its tables as well. // userspace is capable of removing entries from its tables as well.
let from_fe = wasi_ctx.get_fd_entry(from)?; let from_fe = wasi_ctx.get_fd_entry(from)?;
if from_fe.preopen_path.is_some() { if from_fe.preopen_path.is_some() {
return Err(Error::ENOTSUP); return Err(WasiError::ENOTSUP);
} }
if let Ok(to_fe) = wasi_ctx.get_fd_entry(to) { if let Ok(to_fe) = wasi_ctx.get_fd_entry(to) {
if to_fe.preopen_path.is_some() { if to_fe.preopen_path.is_some() {
return Err(Error::ENOTSUP); return Err(WasiError::ENOTSUP);
} }
} }
@@ -219,7 +220,7 @@ pub(crate) unsafe fn fd_seek(
offset: wasi::__wasi_filedelta_t, offset: wasi::__wasi_filedelta_t,
whence: wasi::__wasi_whence_t, whence: wasi::__wasi_whence_t,
newoffset: wasi32::uintptr_t, newoffset: wasi32::uintptr_t,
) -> Result<()> { ) -> WasiResult<()> {
trace!( trace!(
"fd_seek(fd={:?}, offset={:?}, whence={}, newoffset={:#x?})", "fd_seek(fd={:?}, offset={:?}, whence={}, newoffset={:#x?})",
fd, fd,
@@ -242,7 +243,7 @@ pub(crate) unsafe fn fd_seek(
wasi::__WASI_WHENCE_CUR => SeekFrom::Current(offset), wasi::__WASI_WHENCE_CUR => SeekFrom::Current(offset),
wasi::__WASI_WHENCE_END => SeekFrom::End(offset), wasi::__WASI_WHENCE_END => SeekFrom::End(offset),
wasi::__WASI_WHENCE_SET => SeekFrom::Start(offset as u64), wasi::__WASI_WHENCE_SET => SeekFrom::Start(offset as u64),
_ => return Err(Error::EINVAL), _ => return Err(WasiError::EINVAL),
}; };
let host_newoffset = fd.seek(pos)?; let host_newoffset = fd.seek(pos)?;
@@ -256,7 +257,7 @@ pub(crate) unsafe fn fd_tell(
memory: &mut [u8], memory: &mut [u8],
fd: wasi::__wasi_fd_t, fd: wasi::__wasi_fd_t,
newoffset: wasi32::uintptr_t, newoffset: wasi32::uintptr_t,
) -> Result<()> { ) -> WasiResult<()> {
trace!("fd_tell(fd={:?}, newoffset={:#x?})", fd, newoffset); trace!("fd_tell(fd={:?}, newoffset={:#x?})", fd, newoffset);
let fd = wasi_ctx let fd = wasi_ctx
@@ -276,7 +277,7 @@ pub(crate) unsafe fn fd_fdstat_get(
memory: &mut [u8], memory: &mut [u8],
fd: wasi::__wasi_fd_t, fd: wasi::__wasi_fd_t,
fdstat_ptr: wasi32::uintptr_t, // *mut wasi::__wasi_fdstat_t fdstat_ptr: wasi32::uintptr_t, // *mut wasi::__wasi_fdstat_t
) -> Result<()> { ) -> WasiResult<()> {
trace!("fd_fdstat_get(fd={:?}, fdstat_ptr={:#x?})", fd, fdstat_ptr); trace!("fd_fdstat_get(fd={:?}, fdstat_ptr={:#x?})", fd, fdstat_ptr);
let mut fdstat = dec_fdstat_byref(memory, fdstat_ptr)?; let mut fdstat = dec_fdstat_byref(memory, fdstat_ptr)?;
@@ -303,7 +304,7 @@ pub(crate) unsafe fn fd_fdstat_set_flags(
_mem: &mut [u8], _mem: &mut [u8],
fd: wasi::__wasi_fd_t, fd: wasi::__wasi_fd_t,
fdflags: wasi::__wasi_fdflags_t, fdflags: wasi::__wasi_fdflags_t,
) -> Result<()> { ) -> WasiResult<()> {
trace!("fd_fdstat_set_flags(fd={:?}, fdflags={:#x?})", fd, fdflags); trace!("fd_fdstat_set_flags(fd={:?}, fdflags={:#x?})", fd, fdflags);
let fd = wasi_ctx let fd = wasi_ctx
@@ -320,7 +321,7 @@ pub(crate) unsafe fn fd_fdstat_set_rights(
fd: wasi::__wasi_fd_t, fd: wasi::__wasi_fd_t,
fs_rights_base: wasi::__wasi_rights_t, fs_rights_base: wasi::__wasi_rights_t,
fs_rights_inheriting: wasi::__wasi_rights_t, fs_rights_inheriting: wasi::__wasi_rights_t,
) -> Result<()> { ) -> WasiResult<()> {
trace!( trace!(
"fd_fdstat_set_rights(fd={:?}, fs_rights_base={:#x?}, fs_rights_inheriting={:#x?})", "fd_fdstat_set_rights(fd={:?}, fs_rights_base={:#x?}, fs_rights_inheriting={:#x?})",
fd, fd,
@@ -332,7 +333,7 @@ pub(crate) unsafe fn fd_fdstat_set_rights(
if fe.rights_base & fs_rights_base != fs_rights_base if fe.rights_base & fs_rights_base != fs_rights_base
|| fe.rights_inheriting & fs_rights_inheriting != fs_rights_inheriting || fe.rights_inheriting & fs_rights_inheriting != fs_rights_inheriting
{ {
return Err(Error::ENOTCAPABLE); return Err(WasiError::ENOTCAPABLE);
} }
fe.rights_base = fs_rights_base; fe.rights_base = fs_rights_base;
fe.rights_inheriting = fs_rights_inheriting; fe.rights_inheriting = fs_rights_inheriting;
@@ -344,7 +345,7 @@ pub(crate) unsafe fn fd_sync(
wasi_ctx: &WasiCtx, wasi_ctx: &WasiCtx,
_mem: &mut [u8], _mem: &mut [u8],
fd: wasi::__wasi_fd_t, fd: wasi::__wasi_fd_t,
) -> Result<()> { ) -> WasiResult<()> {
trace!("fd_sync(fd={:?})", fd); trace!("fd_sync(fd={:?})", fd);
let fd = wasi_ctx let fd = wasi_ctx
@@ -361,7 +362,7 @@ pub(crate) unsafe fn fd_write(
iovs_ptr: wasi32::uintptr_t, iovs_ptr: wasi32::uintptr_t,
iovs_len: wasi32::size_t, iovs_len: wasi32::size_t,
nwritten: wasi32::uintptr_t, nwritten: wasi32::uintptr_t,
) -> Result<()> { ) -> WasiResult<()> {
trace!( trace!(
"fd_write(fd={:?}, iovs_ptr={:#x?}, iovs_len={:?}, nwritten={:#x?})", "fd_write(fd={:?}, iovs_ptr={:#x?}, iovs_len={:?}, nwritten={:#x?})",
fd, fd,
@@ -385,7 +386,7 @@ pub(crate) unsafe fn fd_write(
file.write_vectored(&iovs)? file.write_vectored(&iovs)?
} }
} }
Descriptor::Stdin => return Err(Error::EBADF), Descriptor::Stdin => return Err(WasiError::EBADF),
Descriptor::Stdout => { Descriptor::Stdout => {
// lock for the duration of the scope // lock for the duration of the scope
let stdout = io::stdout(); let stdout = io::stdout();
@@ -417,7 +418,7 @@ pub(crate) unsafe fn fd_advise(
offset: wasi::__wasi_filesize_t, offset: wasi::__wasi_filesize_t,
len: wasi::__wasi_filesize_t, len: wasi::__wasi_filesize_t,
advice: wasi::__wasi_advice_t, advice: wasi::__wasi_advice_t,
) -> Result<()> { ) -> WasiResult<()> {
trace!( trace!(
"fd_advise(fd={:?}, offset={}, len={}, advice={:?})", "fd_advise(fd={:?}, offset={}, len={}, advice={:?})",
fd, fd,
@@ -440,7 +441,7 @@ pub(crate) unsafe fn fd_allocate(
fd: wasi::__wasi_fd_t, fd: wasi::__wasi_fd_t,
offset: wasi::__wasi_filesize_t, offset: wasi::__wasi_filesize_t,
len: wasi::__wasi_filesize_t, len: wasi::__wasi_filesize_t,
) -> Result<()> { ) -> WasiResult<()> {
trace!("fd_allocate(fd={:?}, offset={}, len={})", fd, offset, len); trace!("fd_allocate(fd={:?}, offset={}, len={})", fd, offset, len);
let fd = wasi_ctx let fd = wasi_ctx
@@ -451,10 +452,10 @@ pub(crate) unsafe fn fd_allocate(
let metadata = fd.metadata()?; let metadata = fd.metadata()?;
let current_size = metadata.len(); let current_size = metadata.len();
let wanted_size = offset.checked_add(len).ok_or(Error::E2BIG)?; let wanted_size = offset.checked_add(len).ok_or(WasiError::E2BIG)?;
// This check will be unnecessary when rust-lang/rust#63326 is fixed // This check will be unnecessary when rust-lang/rust#63326 is fixed
if wanted_size > i64::max_value() as u64 { if wanted_size > i64::max_value() as u64 {
return Err(Error::E2BIG); return Err(WasiError::E2BIG);
} }
if wanted_size > current_size { if wanted_size > current_size {
@@ -470,7 +471,7 @@ pub(crate) unsafe fn path_create_directory(
dirfd: wasi::__wasi_fd_t, dirfd: wasi::__wasi_fd_t,
path_ptr: wasi32::uintptr_t, path_ptr: wasi32::uintptr_t,
path_len: wasi32::size_t, path_len: wasi32::size_t,
) -> Result<()> { ) -> WasiResult<()> {
trace!( trace!(
"path_create_directory(dirfd={:?}, path_ptr={:#x?}, path_len={})", "path_create_directory(dirfd={:?}, path_ptr={:#x?}, path_len={})",
dirfd, dirfd,
@@ -499,7 +500,7 @@ pub(crate) unsafe fn path_link(
new_dirfd: wasi::__wasi_fd_t, new_dirfd: wasi::__wasi_fd_t,
new_path_ptr: wasi32::uintptr_t, new_path_ptr: wasi32::uintptr_t,
new_path_len: wasi32::size_t, new_path_len: wasi32::size_t,
) -> Result<()> { ) -> WasiResult<()> {
trace!( trace!(
"path_link(old_dirfd={:?}, old_flags={:?}, old_path_ptr={:#x?}, old_path_len={}, new_dirfd={:?}, new_path_ptr={:#x?}, new_path_len={})", "path_link(old_dirfd={:?}, old_flags={:?}, old_path_ptr={:#x?}, old_path_len={}, new_dirfd={:?}, new_path_ptr={:#x?}, new_path_len={})",
old_dirfd, old_dirfd,
@@ -551,7 +552,7 @@ pub(crate) unsafe fn path_open(
fs_rights_inheriting: wasi::__wasi_rights_t, fs_rights_inheriting: wasi::__wasi_rights_t,
fs_flags: wasi::__wasi_fdflags_t, fs_flags: wasi::__wasi_fdflags_t,
fd_out_ptr: wasi32::uintptr_t, fd_out_ptr: wasi32::uintptr_t,
) -> Result<()> { ) -> WasiResult<()> {
trace!( trace!(
"path_open(dirfd={:?}, dirflags={:?}, path_ptr={:#x?}, path_len={:?}, oflags={:#x?}, fs_rights_base={:#x?}, fs_rights_inheriting={:#x?}, fs_flags={:#x?}, fd_out_ptr={:#x?})", "path_open(dirfd={:?}, dirflags={:?}, path_ptr={:#x?}, path_len={:?}, oflags={:#x?}, fs_rights_base={:#x?}, fs_rights_inheriting={:#x?}, fs_flags={:#x?}, fd_out_ptr={:#x?})",
dirfd, dirfd,
@@ -616,7 +617,7 @@ pub(crate) unsafe fn path_readlink(
buf_ptr: wasi32::uintptr_t, buf_ptr: wasi32::uintptr_t,
buf_len: wasi32::size_t, buf_len: wasi32::size_t,
buf_used: wasi32::uintptr_t, buf_used: wasi32::uintptr_t,
) -> Result<()> { ) -> WasiResult<()> {
trace!( trace!(
"path_readlink(dirfd={:?}, path_ptr={:#x?}, path_len={:?}, buf_ptr={:#x?}, buf_len={}, buf_used={:#x?})", "path_readlink(dirfd={:?}, path_ptr={:#x?}, path_len={:?}, buf_ptr={:#x?}, buf_len={}, buf_used={:#x?})",
dirfd, dirfd,
@@ -655,7 +656,7 @@ pub(crate) unsafe fn path_rename(
new_dirfd: wasi::__wasi_fd_t, new_dirfd: wasi::__wasi_fd_t,
new_path_ptr: wasi32::uintptr_t, new_path_ptr: wasi32::uintptr_t,
new_path_len: wasi32::size_t, new_path_len: wasi32::size_t,
) -> Result<()> { ) -> WasiResult<()> {
trace!( trace!(
"path_rename(old_dirfd={:?}, old_path_ptr={:#x?}, old_path_len={:?}, new_dirfd={:?}, new_path_ptr={:#x?}, new_path_len={:?})", "path_rename(old_dirfd={:?}, old_path_ptr={:#x?}, old_path_len={:?}, new_dirfd={:?}, new_path_ptr={:#x?}, new_path_len={:?})",
old_dirfd, old_dirfd,
@@ -702,7 +703,7 @@ pub(crate) unsafe fn fd_filestat_get(
memory: &mut [u8], memory: &mut [u8],
fd: wasi::__wasi_fd_t, fd: wasi::__wasi_fd_t,
filestat_ptr: wasi32::uintptr_t, filestat_ptr: wasi32::uintptr_t,
) -> Result<()> { ) -> WasiResult<()> {
trace!( trace!(
"fd_filestat_get(fd={:?}, filestat_ptr={:#x?})", "fd_filestat_get(fd={:?}, filestat_ptr={:#x?})",
fd, fd,
@@ -724,7 +725,7 @@ pub(crate) unsafe fn fd_filestat_set_times(
st_atim: wasi::__wasi_timestamp_t, st_atim: wasi::__wasi_timestamp_t,
st_mtim: wasi::__wasi_timestamp_t, st_mtim: wasi::__wasi_timestamp_t,
fst_flags: wasi::__wasi_fstflags_t, fst_flags: wasi::__wasi_fstflags_t,
) -> Result<()> { ) -> WasiResult<()> {
trace!( trace!(
"fd_filestat_set_times(fd={:?}, st_atim={}, st_mtim={}, fst_flags={:#x?})", "fd_filestat_set_times(fd={:?}, st_atim={}, st_mtim={}, fst_flags={:#x?})",
fd, fd,
@@ -746,14 +747,14 @@ pub(crate) fn fd_filestat_set_times_impl(
st_atim: wasi::__wasi_timestamp_t, st_atim: wasi::__wasi_timestamp_t,
st_mtim: wasi::__wasi_timestamp_t, st_mtim: wasi::__wasi_timestamp_t,
fst_flags: wasi::__wasi_fstflags_t, fst_flags: wasi::__wasi_fstflags_t,
) -> Result<()> { ) -> WasiResult<()> {
let set_atim = fst_flags & wasi::__WASI_FSTFLAGS_ATIM != 0; let set_atim = fst_flags & wasi::__WASI_FSTFLAGS_ATIM != 0;
let set_atim_now = fst_flags & wasi::__WASI_FSTFLAGS_ATIM_NOW != 0; let set_atim_now = fst_flags & wasi::__WASI_FSTFLAGS_ATIM_NOW != 0;
let set_mtim = fst_flags & wasi::__WASI_FSTFLAGS_MTIM != 0; let set_mtim = fst_flags & wasi::__WASI_FSTFLAGS_MTIM != 0;
let set_mtim_now = fst_flags & wasi::__WASI_FSTFLAGS_MTIM_NOW != 0; let set_mtim_now = fst_flags & wasi::__WASI_FSTFLAGS_MTIM_NOW != 0;
if (set_atim && set_atim_now) || (set_mtim && set_mtim_now) { if (set_atim && set_atim_now) || (set_mtim && set_mtim_now) {
return Err(Error::EINVAL); return Err(WasiError::EINVAL);
} }
let atim = if set_atim { let atim = if set_atim {
let time = UNIX_EPOCH + Duration::from_nanos(st_atim); let time = UNIX_EPOCH + Duration::from_nanos(st_atim);
@@ -782,7 +783,7 @@ pub(crate) unsafe fn fd_filestat_set_size(
_mem: &mut [u8], _mem: &mut [u8],
fd: wasi::__wasi_fd_t, fd: wasi::__wasi_fd_t,
st_size: wasi::__wasi_filesize_t, st_size: wasi::__wasi_filesize_t,
) -> Result<()> { ) -> WasiResult<()> {
trace!("fd_filestat_set_size(fd={:?}, st_size={})", fd, st_size); trace!("fd_filestat_set_size(fd={:?}, st_size={})", fd, st_size);
let fd = wasi_ctx let fd = wasi_ctx
@@ -792,7 +793,7 @@ pub(crate) unsafe fn fd_filestat_set_size(
// This check will be unnecessary when rust-lang/rust#63326 is fixed // This check will be unnecessary when rust-lang/rust#63326 is fixed
if st_size > i64::max_value() as u64 { if st_size > i64::max_value() as u64 {
return Err(Error::E2BIG); return Err(WasiError::E2BIG);
} }
fd.set_len(st_size).map_err(Into::into) fd.set_len(st_size).map_err(Into::into)
} }
@@ -805,7 +806,7 @@ pub(crate) unsafe fn path_filestat_get(
path_ptr: wasi32::uintptr_t, path_ptr: wasi32::uintptr_t,
path_len: wasi32::size_t, path_len: wasi32::size_t,
filestat_ptr: wasi32::uintptr_t, filestat_ptr: wasi32::uintptr_t,
) -> Result<()> { ) -> WasiResult<()> {
trace!( trace!(
"path_filestat_get(dirfd={:?}, dirflags={:?}, path_ptr={:#x?}, path_len={}, filestat_ptr={:#x?})", "path_filestat_get(dirfd={:?}, dirflags={:?}, path_ptr={:#x?}, path_len={}, filestat_ptr={:#x?})",
dirfd, dirfd,
@@ -845,7 +846,7 @@ pub(crate) unsafe fn path_filestat_set_times(
st_atim: wasi::__wasi_timestamp_t, st_atim: wasi::__wasi_timestamp_t,
st_mtim: wasi::__wasi_timestamp_t, st_mtim: wasi::__wasi_timestamp_t,
fst_flags: wasi::__wasi_fstflags_t, fst_flags: wasi::__wasi_fstflags_t,
) -> Result<()> { ) -> WasiResult<()> {
trace!( trace!(
"path_filestat_set_times(dirfd={:?}, dirflags={:?}, path_ptr={:#x?}, path_len={}, st_atim={}, st_mtim={}, fst_flags={:#x?})", "path_filestat_set_times(dirfd={:?}, dirflags={:?}, path_ptr={:#x?}, path_len={}, st_atim={}, st_mtim={}, fst_flags={:#x?})",
dirfd, dirfd,
@@ -881,7 +882,7 @@ pub(crate) unsafe fn path_symlink(
dirfd: wasi::__wasi_fd_t, dirfd: wasi::__wasi_fd_t,
new_path_ptr: wasi32::uintptr_t, new_path_ptr: wasi32::uintptr_t,
new_path_len: wasi32::size_t, new_path_len: wasi32::size_t,
) -> Result<()> { ) -> WasiResult<()> {
trace!( trace!(
"path_symlink(old_path_ptr={:#x?}, old_path_len={}, dirfd={:?}, new_path_ptr={:#x?}, new_path_len={})", "path_symlink(old_path_ptr={:#x?}, old_path_len={}, dirfd={:?}, new_path_ptr={:#x?}, new_path_len={})",
old_path_ptr, old_path_ptr,
@@ -909,7 +910,7 @@ pub(crate) unsafe fn path_unlink_file(
dirfd: wasi::__wasi_fd_t, dirfd: wasi::__wasi_fd_t,
path_ptr: wasi32::uintptr_t, path_ptr: wasi32::uintptr_t,
path_len: wasi32::size_t, path_len: wasi32::size_t,
) -> Result<()> { ) -> WasiResult<()> {
trace!( trace!(
"path_unlink_file(dirfd={:?}, path_ptr={:#x?}, path_len={})", "path_unlink_file(dirfd={:?}, path_ptr={:#x?}, path_len={})",
dirfd, dirfd,
@@ -933,7 +934,7 @@ pub(crate) unsafe fn path_remove_directory(
dirfd: wasi::__wasi_fd_t, dirfd: wasi::__wasi_fd_t,
path_ptr: wasi32::uintptr_t, path_ptr: wasi32::uintptr_t,
path_len: wasi32::size_t, path_len: wasi32::size_t,
) -> Result<()> { ) -> WasiResult<()> {
trace!( trace!(
"path_remove_directory(dirfd={:?}, path_ptr={:#x?}, path_len={})", "path_remove_directory(dirfd={:?}, path_ptr={:#x?}, path_len={})",
dirfd, dirfd,
@@ -965,7 +966,7 @@ pub(crate) unsafe fn fd_prestat_get(
memory: &mut [u8], memory: &mut [u8],
fd: wasi::__wasi_fd_t, fd: wasi::__wasi_fd_t,
prestat_ptr: wasi32::uintptr_t, prestat_ptr: wasi32::uintptr_t,
) -> Result<()> { ) -> WasiResult<()> {
trace!( trace!(
"fd_prestat_get(fd={:?}, prestat_ptr={:#x?})", "fd_prestat_get(fd={:?}, prestat_ptr={:#x?})",
fd, fd,
@@ -974,9 +975,9 @@ pub(crate) unsafe fn fd_prestat_get(
// TODO: should we validate any rights here? // TODO: should we validate any rights here?
let fe = wasi_ctx.get_fd_entry(fd)?; let fe = wasi_ctx.get_fd_entry(fd)?;
let po_path = fe.preopen_path.as_ref().ok_or(Error::ENOTSUP)?; let po_path = fe.preopen_path.as_ref().ok_or(WasiError::ENOTSUP)?;
if fe.file_type != wasi::__WASI_FILETYPE_DIRECTORY { if fe.file_type != wasi::__WASI_FILETYPE_DIRECTORY {
return Err(Error::ENOTDIR); return Err(WasiError::ENOTDIR);
} }
let path = host_impl::path_from_host(po_path.as_os_str())?; let path = host_impl::path_from_host(po_path.as_os_str())?;
@@ -1001,7 +1002,7 @@ pub(crate) unsafe fn fd_prestat_dir_name(
fd: wasi::__wasi_fd_t, fd: wasi::__wasi_fd_t,
path_ptr: wasi32::uintptr_t, path_ptr: wasi32::uintptr_t,
path_len: wasi32::size_t, path_len: wasi32::size_t,
) -> Result<()> { ) -> WasiResult<()> {
trace!( trace!(
"fd_prestat_dir_name(fd={:?}, path_ptr={:#x?}, path_len={})", "fd_prestat_dir_name(fd={:?}, path_ptr={:#x?}, path_len={})",
fd, fd,
@@ -1011,15 +1012,15 @@ pub(crate) unsafe fn fd_prestat_dir_name(
// TODO: should we validate any rights here? // TODO: should we validate any rights here?
let fe = wasi_ctx.get_fd_entry(fd)?; let fe = wasi_ctx.get_fd_entry(fd)?;
let po_path = fe.preopen_path.as_ref().ok_or(Error::ENOTSUP)?; let po_path = fe.preopen_path.as_ref().ok_or(WasiError::ENOTSUP)?;
if fe.file_type != wasi::__WASI_FILETYPE_DIRECTORY { if fe.file_type != wasi::__WASI_FILETYPE_DIRECTORY {
return Err(Error::ENOTDIR); return Err(WasiError::ENOTDIR);
} }
let path = host_impl::path_from_host(po_path.as_os_str())?; let path = host_impl::path_from_host(po_path.as_os_str())?;
if path.len() > dec_usize(path_len) { if path.len() > dec_usize(path_len) {
return Err(Error::ENAMETOOLONG); return Err(WasiError::ENAMETOOLONG);
} }
trace!(" | (path_ptr,path_len)='{}'", path); trace!(" | (path_ptr,path_len)='{}'", path);
@@ -1035,7 +1036,7 @@ pub(crate) unsafe fn fd_readdir(
buf_len: wasi32::size_t, buf_len: wasi32::size_t,
cookie: wasi::__wasi_dircookie_t, cookie: wasi::__wasi_dircookie_t,
buf_used: wasi32::uintptr_t, buf_used: wasi32::uintptr_t,
) -> Result<()> { ) -> WasiResult<()> {
trace!( trace!(
"fd_readdir(fd={:?}, buf={:#x?}, buf_len={}, cookie={:#x?}, buf_used={:#x?})", "fd_readdir(fd={:?}, buf={:#x?}, buf_len={}, cookie={:#x?}, buf_used={:#x?})",
fd, fd,

View File

@@ -1,7 +1,8 @@
#![allow(non_camel_case_types)] #![allow(non_camel_case_types)]
use crate::old::snapshot_0::fdentry::FdEntry;
use crate::old::snapshot_0::sys::host_impl; use crate::old::snapshot_0::sys::host_impl;
use crate::old::snapshot_0::sys::hostcalls_impl::fs_helpers::*; use crate::old::snapshot_0::sys::hostcalls_impl::fs_helpers::*;
use crate::old::snapshot_0::{error::WasiError, fdentry::FdEntry, wasi, Error, Result}; use crate::old::snapshot_0::wasi::{self, WasiError, WasiResult};
use std::fs::File; use std::fs::File;
use std::path::{Component, Path}; use std::path::{Component, Path};
@@ -31,17 +32,17 @@ pub(crate) fn path_get(
dirflags: wasi::__wasi_lookupflags_t, dirflags: wasi::__wasi_lookupflags_t,
path: &str, path: &str,
needs_final_component: bool, needs_final_component: bool,
) -> Result<PathGet> { ) -> WasiResult<PathGet> {
const MAX_SYMLINK_EXPANSIONS: usize = 128; const MAX_SYMLINK_EXPANSIONS: usize = 128;
if path.contains('\0') { if path.contains('\0') {
// if contains NUL, return EILSEQ // if contains NUL, return EILSEQ
return Err(Error::EILSEQ); return Err(WasiError::EILSEQ);
} }
if fe.file_type != wasi::__WASI_FILETYPE_DIRECTORY { if fe.file_type != wasi::__WASI_FILETYPE_DIRECTORY {
// if `dirfd` doesn't refer to a directory, return `ENOTDIR`. // if `dirfd` doesn't refer to a directory, return `ENOTDIR`.
return Err(Error::ENOTDIR); return Err(WasiError::ENOTDIR);
} }
let dirfd = fe let dirfd = fe
@@ -72,7 +73,7 @@ pub(crate) fn path_get(
let ends_with_slash = cur_path.ends_with('/'); let ends_with_slash = cur_path.ends_with('/');
let mut components = Path::new(&cur_path).components(); let mut components = Path::new(&cur_path).components();
let head = match components.next() { let head = match components.next() {
None => return Err(Error::ENOENT), None => return Err(WasiError::ENOENT),
Some(p) => p, Some(p) => p,
}; };
let tail = components.as_path(); let tail = components.as_path();
@@ -90,18 +91,18 @@ pub(crate) fn path_get(
match head { match head {
Component::Prefix(_) | Component::RootDir => { Component::Prefix(_) | Component::RootDir => {
// path is absolute! // path is absolute!
return Err(Error::ENOTCAPABLE); return Err(WasiError::ENOTCAPABLE);
} }
Component::CurDir => { Component::CurDir => {
// "." so skip // "." so skip
} }
Component::ParentDir => { Component::ParentDir => {
// ".." so pop a dir // ".." so pop a dir
let _ = dir_stack.pop().ok_or(Error::ENOTCAPABLE)?; let _ = dir_stack.pop().ok_or(WasiError::ENOTCAPABLE)?;
// we're not allowed to pop past the original directory // we're not allowed to pop past the original directory
if dir_stack.is_empty() { if dir_stack.is_empty() {
return Err(Error::ENOTCAPABLE); return Err(WasiError::ENOTCAPABLE);
} }
} }
Component::Normal(head) => { Component::Normal(head) => {
@@ -112,12 +113,12 @@ pub(crate) fn path_get(
} }
if !path_stack.is_empty() || (ends_with_slash && !needs_final_component) { if !path_stack.is_empty() || (ends_with_slash && !needs_final_component) {
match openat(dir_stack.last().ok_or(Error::ENOTCAPABLE)?, &head) { match openat(dir_stack.last().ok_or(WasiError::ENOTCAPABLE)?, &head) {
Ok(new_dir) => { Ok(new_dir) => {
dir_stack.push(new_dir); dir_stack.push(new_dir);
} }
Err(e) => { Err(e) => {
match e.as_wasi_error() { match e {
WasiError::ELOOP WasiError::ELOOP
| WasiError::EMLINK | WasiError::EMLINK
| WasiError::ENOTDIR => | WasiError::ENOTDIR =>
@@ -126,13 +127,13 @@ pub(crate) fn path_get(
{ {
// attempt symlink expansion // attempt symlink expansion
let mut link_path = readlinkat( let mut link_path = readlinkat(
dir_stack.last().ok_or(Error::ENOTCAPABLE)?, dir_stack.last().ok_or(WasiError::ENOTCAPABLE)?,
&head, &head,
)?; )?;
symlink_expansions += 1; symlink_expansions += 1;
if symlink_expansions > MAX_SYMLINK_EXPANSIONS { if symlink_expansions > MAX_SYMLINK_EXPANSIONS {
return Err(Error::ELOOP); return Err(WasiError::ELOOP);
} }
if head.ends_with('/') { if head.ends_with('/') {
@@ -159,11 +160,12 @@ pub(crate) fn path_get(
{ {
// if there's a trailing slash, or if `LOOKUP_SYMLINK_FOLLOW` is set, attempt // if there's a trailing slash, or if `LOOKUP_SYMLINK_FOLLOW` is set, attempt
// symlink expansion // symlink expansion
match readlinkat(dir_stack.last().ok_or(Error::ENOTCAPABLE)?, &head) { match readlinkat(dir_stack.last().ok_or(WasiError::ENOTCAPABLE)?, &head)
{
Ok(mut link_path) => { Ok(mut link_path) => {
symlink_expansions += 1; symlink_expansions += 1;
if symlink_expansions > MAX_SYMLINK_EXPANSIONS { if symlink_expansions > MAX_SYMLINK_EXPANSIONS {
return Err(Error::ELOOP); return Err(WasiError::ELOOP);
} }
if head.ends_with('/') { if head.ends_with('/') {
@@ -179,12 +181,12 @@ pub(crate) fn path_get(
continue; continue;
} }
Err(e) => { Err(e) => {
if e.as_wasi_error() != WasiError::EINVAL if e != WasiError::EINVAL
&& e.as_wasi_error() != WasiError::ENOENT && e != WasiError::ENOENT
// this handles the cases when trying to link to // this handles the cases when trying to link to
// a destination that already exists, and the target // a destination that already exists, and the target
// path contains a slash // path contains a slash
&& e.as_wasi_error() != WasiError::ENOTDIR && e != WasiError::ENOTDIR
{ {
return Err(e); return Err(e);
} }
@@ -194,7 +196,7 @@ pub(crate) fn path_get(
// not a symlink, so we're done; // not a symlink, so we're done;
return Ok(PathGet { return Ok(PathGet {
dirfd: dir_stack.pop().ok_or(Error::ENOTCAPABLE)?, dirfd: dir_stack.pop().ok_or(WasiError::ENOTCAPABLE)?,
path: head, path: head,
}); });
} }
@@ -204,7 +206,7 @@ pub(crate) fn path_get(
// no further components to process. means we've hit a case like "." or "a/..", or if the // 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 // input path has trailing slashes and `needs_final_component` is not set
return Ok(PathGet { return Ok(PathGet {
dirfd: dir_stack.pop().ok_or(Error::ENOTCAPABLE)?, dirfd: dir_stack.pop().ok_or(WasiError::ENOTCAPABLE)?,
path: String::from("."), path: String::from("."),
}); });
} }

View File

@@ -3,7 +3,8 @@ use crate::old::snapshot_0::ctx::WasiCtx;
use crate::old::snapshot_0::fdentry::Descriptor; use crate::old::snapshot_0::fdentry::Descriptor;
use crate::old::snapshot_0::memory::*; use crate::old::snapshot_0::memory::*;
use crate::old::snapshot_0::sys::hostcalls_impl; use crate::old::snapshot_0::sys::hostcalls_impl;
use crate::old::snapshot_0::{wasi, wasi32, Error, Result}; use crate::old::snapshot_0::wasi::{self, WasiError, WasiResult};
use crate::old::snapshot_0::wasi32;
use log::{error, trace}; use log::{error, trace};
use std::convert::TryFrom; use std::convert::TryFrom;
@@ -12,7 +13,7 @@ pub(crate) fn args_get(
memory: &mut [u8], memory: &mut [u8],
argv_ptr: wasi32::uintptr_t, argv_ptr: wasi32::uintptr_t,
argv_buf: wasi32::uintptr_t, argv_buf: wasi32::uintptr_t,
) -> Result<()> { ) -> WasiResult<()> {
trace!( trace!(
"args_get(argv_ptr={:#x?}, argv_buf={:#x?})", "args_get(argv_ptr={:#x?}, argv_buf={:#x?})",
argv_ptr, argv_ptr,
@@ -31,7 +32,9 @@ pub(crate) fn args_get(
argv.push(arg_ptr); argv.push(arg_ptr);
let len = wasi32::uintptr_t::try_from(arg_bytes.len())?; let len = wasi32::uintptr_t::try_from(arg_bytes.len())?;
argv_buf_offset = argv_buf_offset.checked_add(len).ok_or(Error::EOVERFLOW)?; argv_buf_offset = argv_buf_offset
.checked_add(len)
.ok_or(WasiError::EOVERFLOW)?;
} }
enc_slice_of_wasi32_uintptr(memory, argv.as_slice(), argv_ptr) enc_slice_of_wasi32_uintptr(memory, argv.as_slice(), argv_ptr)
@@ -42,7 +45,7 @@ pub(crate) fn args_sizes_get(
memory: &mut [u8], memory: &mut [u8],
argc_ptr: wasi32::uintptr_t, argc_ptr: wasi32::uintptr_t,
argv_buf_size_ptr: wasi32::uintptr_t, argv_buf_size_ptr: wasi32::uintptr_t,
) -> Result<()> { ) -> WasiResult<()> {
trace!( trace!(
"args_sizes_get(argc_ptr={:#x?}, argv_buf_size_ptr={:#x?})", "args_sizes_get(argc_ptr={:#x?}, argv_buf_size_ptr={:#x?})",
argc_ptr, argc_ptr,
@@ -70,7 +73,7 @@ pub(crate) fn environ_get(
memory: &mut [u8], memory: &mut [u8],
environ_ptr: wasi32::uintptr_t, environ_ptr: wasi32::uintptr_t,
environ_buf: wasi32::uintptr_t, environ_buf: wasi32::uintptr_t,
) -> Result<()> { ) -> WasiResult<()> {
trace!( trace!(
"environ_get(environ_ptr={:#x?}, environ_buf={:#x?})", "environ_get(environ_ptr={:#x?}, environ_buf={:#x?})",
environ_ptr, environ_ptr,
@@ -91,7 +94,7 @@ pub(crate) fn environ_get(
let len = wasi32::uintptr_t::try_from(env_bytes.len())?; let len = wasi32::uintptr_t::try_from(env_bytes.len())?;
environ_buf_offset = environ_buf_offset environ_buf_offset = environ_buf_offset
.checked_add(len) .checked_add(len)
.ok_or(Error::EOVERFLOW)?; .ok_or(WasiError::EOVERFLOW)?;
} }
enc_slice_of_wasi32_uintptr(memory, environ.as_slice(), environ_ptr) enc_slice_of_wasi32_uintptr(memory, environ.as_slice(), environ_ptr)
@@ -102,7 +105,7 @@ pub(crate) fn environ_sizes_get(
memory: &mut [u8], memory: &mut [u8],
environ_count_ptr: wasi32::uintptr_t, environ_count_ptr: wasi32::uintptr_t,
environ_size_ptr: wasi32::uintptr_t, environ_size_ptr: wasi32::uintptr_t,
) -> Result<()> { ) -> WasiResult<()> {
trace!( trace!(
"environ_sizes_get(environ_count_ptr={:#x?}, environ_size_ptr={:#x?})", "environ_sizes_get(environ_count_ptr={:#x?}, environ_size_ptr={:#x?})",
environ_count_ptr, environ_count_ptr,
@@ -116,7 +119,7 @@ pub(crate) fn environ_sizes_get(
.try_fold(0, |acc: u32, pair| { .try_fold(0, |acc: u32, pair| {
acc.checked_add(pair.as_bytes_with_nul().len() as u32) acc.checked_add(pair.as_bytes_with_nul().len() as u32)
}) })
.ok_or(Error::EOVERFLOW)?; .ok_or(WasiError::EOVERFLOW)?;
trace!(" | *environ_count_ptr={:?}", environ_count); trace!(" | *environ_count_ptr={:?}", environ_count);
@@ -132,14 +135,14 @@ pub(crate) fn random_get(
memory: &mut [u8], memory: &mut [u8],
buf_ptr: wasi32::uintptr_t, buf_ptr: wasi32::uintptr_t,
buf_len: wasi32::size_t, buf_len: wasi32::size_t,
) -> Result<()> { ) -> WasiResult<()> {
trace!("random_get(buf_ptr={:#x?}, buf_len={:?})", buf_ptr, buf_len); trace!("random_get(buf_ptr={:#x?}, buf_len={:?})", buf_ptr, buf_len);
let buf = dec_slice_of_mut_u8(memory, buf_ptr, buf_len)?; let buf = dec_slice_of_mut_u8(memory, buf_ptr, buf_len)?;
getrandom::getrandom(buf).map_err(|err| { getrandom::getrandom(buf).map_err(|err| {
error!("getrandom failure: {:?}", err); error!("getrandom failure: {:?}", err);
Error::EIO WasiError::EIO
}) })
} }
@@ -148,7 +151,7 @@ pub(crate) fn clock_res_get(
memory: &mut [u8], memory: &mut [u8],
clock_id: wasi::__wasi_clockid_t, clock_id: wasi::__wasi_clockid_t,
resolution_ptr: wasi32::uintptr_t, resolution_ptr: wasi32::uintptr_t,
) -> Result<()> { ) -> WasiResult<()> {
trace!( trace!(
"clock_res_get(clock_id={:?}, resolution_ptr={:#x?})", "clock_res_get(clock_id={:?}, resolution_ptr={:#x?})",
clock_id, clock_id,
@@ -168,7 +171,7 @@ pub(crate) fn clock_time_get(
clock_id: wasi::__wasi_clockid_t, clock_id: wasi::__wasi_clockid_t,
precision: wasi::__wasi_timestamp_t, precision: wasi::__wasi_timestamp_t,
time_ptr: wasi32::uintptr_t, time_ptr: wasi32::uintptr_t,
) -> Result<()> { ) -> WasiResult<()> {
trace!( trace!(
"clock_time_get(clock_id={:?}, precision={:?}, time_ptr={:#x?})", "clock_time_get(clock_id={:?}, precision={:?}, time_ptr={:#x?})",
clock_id, clock_id,
@@ -183,7 +186,7 @@ pub(crate) fn clock_time_get(
enc_timestamp_byref(memory, time_ptr, time) enc_timestamp_byref(memory, time_ptr, time)
} }
pub(crate) fn sched_yield(_wasi_ctx: &WasiCtx, _memory: &mut [u8]) -> Result<()> { pub(crate) fn sched_yield(_wasi_ctx: &WasiCtx, _memory: &mut [u8]) -> WasiResult<()> {
trace!("sched_yield()"); trace!("sched_yield()");
std::thread::yield_now(); std::thread::yield_now();
@@ -198,7 +201,7 @@ pub(crate) fn poll_oneoff(
output: wasi32::uintptr_t, output: wasi32::uintptr_t,
nsubscriptions: wasi32::size_t, nsubscriptions: wasi32::size_t,
nevents: wasi32::uintptr_t, nevents: wasi32::uintptr_t,
) -> Result<()> { ) -> WasiResult<()> {
trace!( trace!(
"poll_oneoff(input={:#x?}, output={:#x?}, nsubscriptions={}, nevents={:#x?})", "poll_oneoff(input={:#x?}, output={:#x?}, nsubscriptions={}, nevents={:#x?})",
input, input,
@@ -208,7 +211,7 @@ pub(crate) fn poll_oneoff(
); );
if u64::from(nsubscriptions) > wasi::__wasi_filesize_t::max_value() { if u64::from(nsubscriptions) > wasi::__wasi_filesize_t::max_value() {
return Err(Error::EINVAL); return Err(WasiError::EINVAL);
} }
enc_int_byref(memory, nevents, 0)?; enc_int_byref(memory, nevents, 0)?;
@@ -253,7 +256,7 @@ pub(crate) fn poll_oneoff(
Err(err) => { Err(err) => {
let event = wasi::__wasi_event_t { let event = wasi::__wasi_event_t {
userdata: subscription.userdata, userdata: subscription.userdata,
error: err.as_wasi_error().as_raw_errno(), error: err.as_raw_errno(),
r#type: wasi::__WASI_EVENTTYPE_FD_READ, r#type: wasi::__WASI_EVENTTYPE_FD_READ,
fd_readwrite: wasi::__wasi_event_fd_readwrite_t { fd_readwrite: wasi::__wasi_event_fd_readwrite_t {
nbytes: 0, nbytes: 0,
@@ -281,7 +284,7 @@ pub(crate) fn poll_oneoff(
Err(err) => { Err(err) => {
let event = wasi::__wasi_event_t { let event = wasi::__wasi_event_t {
userdata: subscription.userdata, userdata: subscription.userdata,
error: err.as_wasi_error().as_raw_errno(), error: err.as_raw_errno(),
r#type: wasi::__WASI_EVENTTYPE_FD_WRITE, r#type: wasi::__WASI_EVENTTYPE_FD_WRITE,
fd_readwrite: wasi::__wasi_event_fd_readwrite_t { fd_readwrite: wasi::__wasi_event_fd_readwrite_t {
nbytes: 0, nbytes: 0,
@@ -301,7 +304,7 @@ pub(crate) fn poll_oneoff(
hostcalls_impl::poll_oneoff(timeout, fd_events, &mut events)?; hostcalls_impl::poll_oneoff(timeout, fd_events, &mut events)?;
let events_count = u32::try_from(events.len()).map_err(|_| Error::EOVERFLOW)?; let events_count = u32::try_from(events.len()).map_err(|_| WasiError::EOVERFLOW)?;
enc_events(memory, output, nsubscriptions, events)?; enc_events(memory, output, nsubscriptions, events)?;
@@ -310,7 +313,9 @@ pub(crate) fn poll_oneoff(
enc_int_byref(memory, nevents, events_count) enc_int_byref(memory, nevents, events_count)
} }
fn wasi_clock_to_relative_ns_delay(wasi_clock: wasi::__wasi_subscription_clock_t) -> Result<u128> { fn wasi_clock_to_relative_ns_delay(
wasi_clock: wasi::__wasi_subscription_clock_t,
) -> WasiResult<u128> {
use std::time::SystemTime; use std::time::SystemTime;
if wasi_clock.flags != wasi::__WASI_SUBCLOCKFLAGS_SUBSCRIPTION_CLOCK_ABSTIME { if wasi_clock.flags != wasi::__WASI_SUBCLOCKFLAGS_SUBSCRIPTION_CLOCK_ABSTIME {
@@ -318,7 +323,7 @@ fn wasi_clock_to_relative_ns_delay(wasi_clock: wasi::__wasi_subscription_clock_t
} }
let now: u128 = SystemTime::now() let now: u128 = SystemTime::now()
.duration_since(SystemTime::UNIX_EPOCH) .duration_since(SystemTime::UNIX_EPOCH)
.map_err(|_| Error::ENOTCAPABLE)? .map_err(|_| WasiError::ENOTCAPABLE)?
.as_nanos(); .as_nanos();
let deadline = u128::from(wasi_clock.timeout); let deadline = u128::from(wasi_clock.timeout);
Ok(deadline.saturating_sub(now)) Ok(deadline.saturating_sub(now))
@@ -348,6 +353,6 @@ pub(crate) fn proc_raise(
_wasi_ctx: &WasiCtx, _wasi_ctx: &WasiCtx,
_memory: &mut [u8], _memory: &mut [u8],
_sig: wasi::__wasi_signal_t, _sig: wasi::__wasi_signal_t,
) -> Result<()> { ) -> WasiResult<()> {
unimplemented!("proc_raise") unimplemented!("proc_raise")
} }

View File

@@ -1,4 +1,5 @@
use crate::old::snapshot_0::{wasi, wasi32, Result, WasiCtx}; use crate::old::snapshot_0::wasi::{self, WasiResult};
use crate::old::snapshot_0::{wasi32, WasiCtx};
pub fn sock_recv( pub fn sock_recv(
_wasi_ctx: &WasiCtx, _wasi_ctx: &WasiCtx,
@@ -9,7 +10,7 @@ pub fn sock_recv(
_ri_flags: wasi::__wasi_riflags_t, _ri_flags: wasi::__wasi_riflags_t,
_ro_datalen: wasi32::uintptr_t, _ro_datalen: wasi32::uintptr_t,
_ro_flags: wasi32::uintptr_t, _ro_flags: wasi32::uintptr_t,
) -> Result<()> { ) -> WasiResult<()> {
unimplemented!("sock_recv") unimplemented!("sock_recv")
} }
@@ -21,7 +22,7 @@ pub fn sock_send(
_si_data_len: wasi32::size_t, _si_data_len: wasi32::size_t,
_si_flags: wasi::__wasi_siflags_t, _si_flags: wasi::__wasi_siflags_t,
_so_datalen: wasi32::uintptr_t, _so_datalen: wasi32::uintptr_t,
) -> Result<()> { ) -> WasiResult<()> {
unimplemented!("sock_send") unimplemented!("sock_send")
} }
@@ -30,6 +31,6 @@ pub fn sock_shutdown(
_memory: &mut [u8], _memory: &mut [u8],
_sock: wasi::__wasi_fd_t, _sock: wasi::__wasi_fd_t,
_how: wasi::__wasi_sdflags_t, _how: wasi::__wasi_sdflags_t,
) -> Result<()> { ) -> WasiResult<()> {
unimplemented!("sock_shutdown") unimplemented!("sock_shutdown")
} }

View File

@@ -8,38 +8,39 @@
//! are not held for long durations. //! are not held for long durations.
#![allow(unused)] #![allow(unused)]
use crate::old::snapshot_0::{host, wasi, wasi32, Error, Result}; use crate::old::snapshot_0::wasi::{self, WasiError, WasiResult};
use crate::old::snapshot_0::{host, wasi32};
use num::PrimInt; use num::PrimInt;
use std::convert::TryFrom; use std::convert::TryFrom;
use std::mem::{align_of, size_of}; use std::mem::{align_of, size_of};
use std::{ptr, slice}; use std::{ptr, slice};
fn dec_ptr(memory: &[u8], ptr: wasi32::uintptr_t, len: usize) -> Result<*const u8> { fn dec_ptr(memory: &[u8], ptr: wasi32::uintptr_t, len: usize) -> WasiResult<*const u8> {
// check for overflow // check for overflow
let checked_len = (ptr as usize).checked_add(len).ok_or(Error::EFAULT)?; let checked_len = (ptr as usize).checked_add(len).ok_or(WasiError::EFAULT)?;
// translate the pointer // translate the pointer
memory memory
.get(ptr as usize..checked_len) .get(ptr as usize..checked_len)
.ok_or(Error::EFAULT) .ok_or(WasiError::EFAULT)
.map(|mem| mem.as_ptr()) .map(|mem| mem.as_ptr())
} }
fn dec_ptr_mut(memory: &mut [u8], ptr: wasi32::uintptr_t, len: usize) -> Result<*mut u8> { fn dec_ptr_mut(memory: &mut [u8], ptr: wasi32::uintptr_t, len: usize) -> WasiResult<*mut u8> {
// check for overflow // check for overflow
let checked_len = (ptr as usize).checked_add(len).ok_or(Error::EFAULT)?; let checked_len = (ptr as usize).checked_add(len).ok_or(WasiError::EFAULT)?;
// translate the pointer // translate the pointer
memory memory
.get_mut(ptr as usize..checked_len) .get_mut(ptr as usize..checked_len)
.ok_or(Error::EFAULT) .ok_or(WasiError::EFAULT)
.map(|mem| mem.as_mut_ptr()) .map(|mem| mem.as_mut_ptr())
} }
fn dec_ptr_to<'memory, T>(memory: &'memory [u8], ptr: wasi32::uintptr_t) -> Result<&'memory T> { fn dec_ptr_to<'memory, T>(memory: &'memory [u8], ptr: wasi32::uintptr_t) -> WasiResult<&'memory T> {
// check that the ptr is aligned // check that the ptr is aligned
if ptr as usize % align_of::<T>() != 0 { if ptr as usize % align_of::<T>() != 0 {
return Err(Error::EINVAL); return Err(WasiError::EINVAL);
} }
dec_ptr(memory, ptr, size_of::<T>()).map(|p| unsafe { &*(p as *const T) }) dec_ptr(memory, ptr, size_of::<T>()).map(|p| unsafe { &*(p as *const T) })
@@ -48,49 +49,49 @@ fn dec_ptr_to<'memory, T>(memory: &'memory [u8], ptr: wasi32::uintptr_t) -> Resu
fn dec_ptr_to_mut<'memory, T>( fn dec_ptr_to_mut<'memory, T>(
memory: &'memory mut [u8], memory: &'memory mut [u8],
ptr: wasi32::uintptr_t, ptr: wasi32::uintptr_t,
) -> Result<&'memory mut T> { ) -> WasiResult<&'memory mut T> {
// check that the ptr is aligned // check that the ptr is aligned
if ptr as usize % align_of::<T>() != 0 { if ptr as usize % align_of::<T>() != 0 {
return Err(Error::EINVAL); return Err(WasiError::EINVAL);
} }
dec_ptr_mut(memory, ptr, size_of::<T>()).map(|p| unsafe { &mut *(p as *mut T) }) dec_ptr_mut(memory, ptr, size_of::<T>()).map(|p| unsafe { &mut *(p as *mut T) })
} }
/// This function does not perform endianness conversions! /// This function does not perform endianness conversions!
fn dec_raw_byref<T>(memory: &[u8], ptr: wasi32::uintptr_t) -> Result<T> { fn dec_raw_byref<T>(memory: &[u8], ptr: wasi32::uintptr_t) -> WasiResult<T> {
dec_ptr_to::<T>(memory, ptr).map(|p| unsafe { ptr::read(p) }) dec_ptr_to::<T>(memory, ptr).map(|p| unsafe { ptr::read(p) })
} }
/// This function does not perform endianness conversions! /// This function does not perform endianness conversions!
fn enc_raw_byref<T>(memory: &mut [u8], ptr: wasi32::uintptr_t, t: T) -> Result<()> { fn enc_raw_byref<T>(memory: &mut [u8], ptr: wasi32::uintptr_t, t: T) -> WasiResult<()> {
dec_ptr_to_mut::<T>(memory, ptr).map(|p| unsafe { ptr::write(p, t) }) dec_ptr_to_mut::<T>(memory, ptr).map(|p| unsafe { ptr::write(p, t) })
} }
pub(crate) fn dec_int_byref<T>(memory: &[u8], ptr: wasi32::uintptr_t) -> Result<T> pub(crate) fn dec_int_byref<T>(memory: &[u8], ptr: wasi32::uintptr_t) -> WasiResult<T>
where where
T: PrimInt, T: PrimInt,
{ {
dec_raw_byref::<T>(memory, ptr).map(|i| PrimInt::from_le(i)) dec_raw_byref::<T>(memory, ptr).map(|i| PrimInt::from_le(i))
} }
pub(crate) fn enc_int_byref<T>(memory: &mut [u8], ptr: wasi32::uintptr_t, t: T) -> Result<()> pub(crate) fn enc_int_byref<T>(memory: &mut [u8], ptr: wasi32::uintptr_t, t: T) -> WasiResult<()>
where where
T: PrimInt, T: PrimInt,
{ {
enc_raw_byref::<T>(memory, ptr, PrimInt::to_le(t)) enc_raw_byref::<T>(memory, ptr, PrimInt::to_le(t))
} }
fn check_slice_of<T>(ptr: wasi32::uintptr_t, len: wasi32::size_t) -> Result<(usize, usize)> { fn check_slice_of<T>(ptr: wasi32::uintptr_t, len: wasi32::size_t) -> WasiResult<(usize, usize)> {
// check alignment, and that length doesn't overflow // check alignment, and that length doesn't overflow
if ptr as usize % align_of::<T>() != 0 { if ptr as usize % align_of::<T>() != 0 {
return Err(Error::EINVAL); return Err(WasiError::EINVAL);
} }
let len = dec_usize(len); let len = dec_usize(len);
let len_bytes = if let Some(len) = size_of::<T>().checked_mul(len) { let len_bytes = if let Some(len) = size_of::<T>().checked_mul(len) {
len len
} else { } else {
return Err(Error::EOVERFLOW); return Err(WasiError::EOVERFLOW);
}; };
Ok((len, len_bytes)) Ok((len, len_bytes))
@@ -100,7 +101,7 @@ fn dec_raw_slice_of<'memory, T>(
memory: &'memory [u8], memory: &'memory [u8],
ptr: wasi32::uintptr_t, ptr: wasi32::uintptr_t,
len: wasi32::size_t, len: wasi32::size_t,
) -> Result<&'memory [T]> { ) -> WasiResult<&'memory [T]> {
let (len, len_bytes) = check_slice_of::<T>(ptr, len)?; let (len, len_bytes) = check_slice_of::<T>(ptr, len)?;
let ptr = dec_ptr(memory, ptr, len_bytes)? as *const T; let ptr = dec_ptr(memory, ptr, len_bytes)? as *const T;
Ok(unsafe { slice::from_raw_parts(ptr, len) }) Ok(unsafe { slice::from_raw_parts(ptr, len) })
@@ -110,7 +111,7 @@ fn dec_raw_slice_of_mut<'memory, T>(
memory: &'memory mut [u8], memory: &'memory mut [u8],
ptr: wasi32::uintptr_t, ptr: wasi32::uintptr_t,
len: wasi32::size_t, len: wasi32::size_t,
) -> Result<&'memory mut [T]> { ) -> WasiResult<&'memory mut [T]> {
let (len, len_bytes) = check_slice_of::<T>(ptr, len)?; let (len, len_bytes) = check_slice_of::<T>(ptr, len)?;
let ptr = dec_ptr_mut(memory, ptr, len_bytes)? as *mut T; let ptr = dec_ptr_mut(memory, ptr, len_bytes)? as *mut T;
Ok(unsafe { slice::from_raw_parts_mut(ptr, len) }) Ok(unsafe { slice::from_raw_parts_mut(ptr, len) })
@@ -120,16 +121,16 @@ fn raw_slice_for_enc<'memory, T>(
memory: &'memory mut [u8], memory: &'memory mut [u8],
slice: &[T], slice: &[T],
ptr: wasi32::uintptr_t, ptr: wasi32::uintptr_t,
) -> Result<&'memory mut [T]> { ) -> WasiResult<&'memory mut [T]> {
// check alignment // check alignment
if ptr as usize % align_of::<T>() != 0 { if ptr as usize % align_of::<T>() != 0 {
return Err(Error::EINVAL); return Err(WasiError::EINVAL);
} }
// check that length doesn't overflow // check that length doesn't overflow
let len_bytes = if let Some(len) = size_of::<T>().checked_mul(slice.len()) { let len_bytes = if let Some(len) = size_of::<T>().checked_mul(slice.len()) {
len len
} else { } else {
return Err(Error::EOVERFLOW); return Err(WasiError::EOVERFLOW);
}; };
// get the pointer into guest memory // get the pointer into guest memory
@@ -142,7 +143,7 @@ pub(crate) fn dec_slice_of_u8<'memory>(
memory: &'memory [u8], memory: &'memory [u8],
ptr: wasi32::uintptr_t, ptr: wasi32::uintptr_t,
len: wasi32::size_t, len: wasi32::size_t,
) -> Result<&'memory [u8]> { ) -> WasiResult<&'memory [u8]> {
dec_raw_slice_of::<u8>(memory, ptr, len) dec_raw_slice_of::<u8>(memory, ptr, len)
} }
@@ -150,7 +151,7 @@ pub(crate) fn dec_slice_of_mut_u8<'memory>(
memory: &'memory mut [u8], memory: &'memory mut [u8],
ptr: wasi32::uintptr_t, ptr: wasi32::uintptr_t,
len: wasi32::size_t, len: wasi32::size_t,
) -> Result<&'memory mut [u8]> { ) -> WasiResult<&'memory mut [u8]> {
dec_raw_slice_of_mut::<u8>(memory, ptr, len) dec_raw_slice_of_mut::<u8>(memory, ptr, len)
} }
@@ -158,7 +159,7 @@ pub(crate) fn enc_slice_of_u8(
memory: &mut [u8], memory: &mut [u8],
slice: &[u8], slice: &[u8],
ptr: wasi32::uintptr_t, ptr: wasi32::uintptr_t,
) -> Result<()> { ) -> WasiResult<()> {
let output = raw_slice_for_enc::<u8>(memory, slice, ptr)?; let output = raw_slice_for_enc::<u8>(memory, slice, ptr)?;
output.copy_from_slice(slice); output.copy_from_slice(slice);
@@ -170,7 +171,7 @@ pub(crate) fn enc_slice_of_wasi32_uintptr(
memory: &mut [u8], memory: &mut [u8],
slice: &[wasi32::uintptr_t], slice: &[wasi32::uintptr_t],
ptr: wasi32::uintptr_t, ptr: wasi32::uintptr_t,
) -> Result<()> { ) -> WasiResult<()> {
let mut output_iter = raw_slice_for_enc::<wasi32::uintptr_t>(memory, slice, ptr)?.into_iter(); let mut output_iter = raw_slice_for_enc::<wasi32::uintptr_t>(memory, slice, ptr)?.into_iter();
for p in slice { for p in slice {
@@ -182,7 +183,10 @@ pub(crate) fn enc_slice_of_wasi32_uintptr(
macro_rules! dec_enc_scalar { macro_rules! dec_enc_scalar {
($ty:ident, $dec_byref:ident, $enc_byref:ident) => { ($ty:ident, $dec_byref:ident, $enc_byref:ident) => {
pub(crate) fn $dec_byref(memory: &mut [u8], ptr: wasi32::uintptr_t) -> Result<wasi::$ty> { pub(crate) fn $dec_byref(
memory: &mut [u8],
ptr: wasi32::uintptr_t,
) -> WasiResult<wasi::$ty> {
dec_int_byref::<wasi::$ty>(memory, ptr) dec_int_byref::<wasi::$ty>(memory, ptr)
} }
@@ -190,7 +194,7 @@ macro_rules! dec_enc_scalar {
memory: &mut [u8], memory: &mut [u8],
ptr: wasi32::uintptr_t, ptr: wasi32::uintptr_t,
x: wasi::$ty, x: wasi::$ty,
) -> Result<()> { ) -> WasiResult<()> {
enc_int_byref::<wasi::$ty>(memory, ptr, x) enc_int_byref::<wasi::$ty>(memory, ptr, x)
} }
}; };
@@ -200,7 +204,7 @@ pub(crate) fn dec_ciovec_slice(
memory: &[u8], memory: &[u8],
ptr: wasi32::uintptr_t, ptr: wasi32::uintptr_t,
len: wasi32::size_t, len: wasi32::size_t,
) -> Result<Vec<host::__wasi_ciovec_t>> { ) -> WasiResult<Vec<host::__wasi_ciovec_t>> {
let raw_slice = dec_raw_slice_of::<wasi32::__wasi_ciovec_t>(memory, ptr, len)?; let raw_slice = dec_raw_slice_of::<wasi32::__wasi_ciovec_t>(memory, ptr, len)?;
raw_slice raw_slice
@@ -220,7 +224,7 @@ pub(crate) fn dec_iovec_slice(
memory: &[u8], memory: &[u8],
ptr: wasi32::uintptr_t, ptr: wasi32::uintptr_t,
len: wasi32::size_t, len: wasi32::size_t,
) -> Result<Vec<host::__wasi_iovec_t>> { ) -> WasiResult<Vec<host::__wasi_iovec_t>> {
let raw_slice = dec_raw_slice_of::<wasi32::__wasi_iovec_t>(memory, ptr, len)?; let raw_slice = dec_raw_slice_of::<wasi32::__wasi_iovec_t>(memory, ptr, len)?;
raw_slice raw_slice
@@ -248,7 +252,7 @@ dec_enc_scalar!(__wasi_linkcount_t, dev_linkcount_byref, enc_linkcount_byref);
pub(crate) fn dec_filestat_byref( pub(crate) fn dec_filestat_byref(
memory: &mut [u8], memory: &mut [u8],
filestat_ptr: wasi32::uintptr_t, filestat_ptr: wasi32::uintptr_t,
) -> Result<wasi::__wasi_filestat_t> { ) -> WasiResult<wasi::__wasi_filestat_t> {
let raw = dec_raw_byref::<wasi::__wasi_filestat_t>(memory, filestat_ptr)?; let raw = dec_raw_byref::<wasi::__wasi_filestat_t>(memory, filestat_ptr)?;
Ok(wasi::__wasi_filestat_t { Ok(wasi::__wasi_filestat_t {
@@ -267,7 +271,7 @@ pub(crate) fn enc_filestat_byref(
memory: &mut [u8], memory: &mut [u8],
filestat_ptr: wasi32::uintptr_t, filestat_ptr: wasi32::uintptr_t,
filestat: wasi::__wasi_filestat_t, filestat: wasi::__wasi_filestat_t,
) -> Result<()> { ) -> WasiResult<()> {
let raw = wasi::__wasi_filestat_t { let raw = wasi::__wasi_filestat_t {
dev: PrimInt::to_le(filestat.dev), dev: PrimInt::to_le(filestat.dev),
ino: PrimInt::to_le(filestat.ino), ino: PrimInt::to_le(filestat.ino),
@@ -285,7 +289,7 @@ pub(crate) fn enc_filestat_byref(
pub(crate) fn dec_fdstat_byref( pub(crate) fn dec_fdstat_byref(
memory: &mut [u8], memory: &mut [u8],
fdstat_ptr: wasi32::uintptr_t, fdstat_ptr: wasi32::uintptr_t,
) -> Result<wasi::__wasi_fdstat_t> { ) -> WasiResult<wasi::__wasi_fdstat_t> {
let raw = dec_raw_byref::<wasi::__wasi_fdstat_t>(memory, fdstat_ptr)?; let raw = dec_raw_byref::<wasi::__wasi_fdstat_t>(memory, fdstat_ptr)?;
Ok(wasi::__wasi_fdstat_t { Ok(wasi::__wasi_fdstat_t {
@@ -300,7 +304,7 @@ pub(crate) fn enc_fdstat_byref(
memory: &mut [u8], memory: &mut [u8],
fdstat_ptr: wasi32::uintptr_t, fdstat_ptr: wasi32::uintptr_t,
fdstat: wasi::__wasi_fdstat_t, fdstat: wasi::__wasi_fdstat_t,
) -> Result<()> { ) -> WasiResult<()> {
let raw = wasi::__wasi_fdstat_t { let raw = wasi::__wasi_fdstat_t {
fs_filetype: PrimInt::to_le(fdstat.fs_filetype), fs_filetype: PrimInt::to_le(fdstat.fs_filetype),
fs_flags: PrimInt::to_le(fdstat.fs_flags), fs_flags: PrimInt::to_le(fdstat.fs_flags),
@@ -326,7 +330,7 @@ dec_enc_scalar!(__wasi_oflags_t, dec_oflags_byref, enc_oflags_byref);
pub(crate) fn dec_prestat_byref( pub(crate) fn dec_prestat_byref(
memory: &mut [u8], memory: &mut [u8],
prestat_ptr: wasi32::uintptr_t, prestat_ptr: wasi32::uintptr_t,
) -> Result<host::__wasi_prestat_t> { ) -> WasiResult<host::__wasi_prestat_t> {
let raw = dec_raw_byref::<wasi32::__wasi_prestat_t>(memory, prestat_ptr)?; let raw = dec_raw_byref::<wasi32::__wasi_prestat_t>(memory, prestat_ptr)?;
match PrimInt::from_le(raw.tag) { match PrimInt::from_le(raw.tag) {
@@ -338,7 +342,7 @@ pub(crate) fn dec_prestat_byref(
}, },
}, },
}), }),
_ => Err(Error::EINVAL), _ => Err(WasiError::EINVAL),
} }
} }
@@ -346,7 +350,7 @@ pub(crate) fn enc_prestat_byref(
memory: &mut [u8], memory: &mut [u8],
prestat_ptr: wasi32::uintptr_t, prestat_ptr: wasi32::uintptr_t,
prestat: host::__wasi_prestat_t, prestat: host::__wasi_prestat_t,
) -> Result<()> { ) -> WasiResult<()> {
let raw = match prestat.tag { let raw = match prestat.tag {
wasi::__WASI_PREOPENTYPE_DIR => Ok(wasi32::__wasi_prestat_t { wasi::__WASI_PREOPENTYPE_DIR => Ok(wasi32::__wasi_prestat_t {
tag: PrimInt::to_le(wasi::__WASI_PREOPENTYPE_DIR), tag: PrimInt::to_le(wasi::__WASI_PREOPENTYPE_DIR),
@@ -356,7 +360,7 @@ pub(crate) fn enc_prestat_byref(
}, },
}, },
}), }),
_ => Err(Error::EINVAL), _ => Err(WasiError::EINVAL),
}?; }?;
enc_raw_byref::<wasi32::__wasi_prestat_t>(memory, prestat_ptr, raw) enc_raw_byref::<wasi32::__wasi_prestat_t>(memory, prestat_ptr, raw)
@@ -377,7 +381,7 @@ pub(crate) fn enc_usize_byref(
memory: &mut [u8], memory: &mut [u8],
usize_ptr: wasi32::uintptr_t, usize_ptr: wasi32::uintptr_t,
host_usize: usize, host_usize: usize,
) -> Result<()> { ) -> WasiResult<()> {
enc_int_byref::<wasi32::size_t>(memory, usize_ptr, enc_usize(host_usize)) enc_int_byref::<wasi32::size_t>(memory, usize_ptr, enc_usize(host_usize))
} }
@@ -402,7 +406,7 @@ pub(crate) fn dec_subscriptions(
memory: &mut [u8], memory: &mut [u8],
input: wasi32::uintptr_t, input: wasi32::uintptr_t,
nsubscriptions: wasi32::size_t, nsubscriptions: wasi32::size_t,
) -> Result<Vec<wasi::__wasi_subscription_t>> { ) -> WasiResult<Vec<wasi::__wasi_subscription_t>> {
let raw_input_slice = let raw_input_slice =
dec_raw_slice_of::<wasi::__wasi_subscription_t>(memory, input, nsubscriptions)?; dec_raw_slice_of::<wasi::__wasi_subscription_t>(memory, input, nsubscriptions)?;
@@ -436,14 +440,14 @@ pub(crate) fn dec_subscriptions(
}), }),
}, },
}, },
_ => return Err(Error::EINVAL), _ => return Err(WasiError::EINVAL),
}; };
Ok(wasi::__wasi_subscription_t { Ok(wasi::__wasi_subscription_t {
userdata, userdata,
u: wasi::__wasi_subscription_u_t { tag, u }, u: wasi::__wasi_subscription_u_t { tag, u },
}) })
}) })
.collect::<Result<Vec<_>>>() .collect::<WasiResult<Vec<_>>>()
} }
pub(crate) fn enc_events( pub(crate) fn enc_events(
@@ -451,7 +455,7 @@ pub(crate) fn enc_events(
output: wasi32::uintptr_t, output: wasi32::uintptr_t,
nsubscriptions: wasi32::size_t, nsubscriptions: wasi32::size_t,
events: Vec<wasi::__wasi_event_t>, events: Vec<wasi::__wasi_event_t>,
) -> Result<()> { ) -> WasiResult<()> {
let mut raw_output_iter = let mut raw_output_iter =
dec_raw_slice_of_mut::<wasi::__wasi_event_t>(memory, output, nsubscriptions)?.into_iter(); dec_raw_slice_of_mut::<wasi::__wasi_event_t>(memory, output, nsubscriptions)?.into_iter();

View File

@@ -1,5 +1,4 @@
mod ctx; mod ctx;
mod error;
mod fdentry; mod fdentry;
mod helpers; mod helpers;
mod host; mod host;
@@ -14,6 +13,3 @@ pub mod hostcalls {
} }
pub use ctx::{WasiCtx, WasiCtxBuilder}; pub use ctx::{WasiCtx, WasiCtxBuilder};
pub type Error = error::Error;
pub type Result<T> = std::result::Result<T, Error>;

View File

@@ -1,16 +1,16 @@
use crate::old::snapshot_0::{wasi, Result}; use crate::old::snapshot_0::wasi::{self, WasiResult};
use std::convert::TryFrom; use std::convert::TryFrom;
pub(crate) const O_RSYNC: yanix::file::OFlag = yanix::file::OFlag::SYNC; pub(crate) const O_RSYNC: yanix::file::OFlag = yanix::file::OFlag::SYNC;
pub(crate) fn stdev_from_nix(dev: libc::dev_t) -> Result<wasi::__wasi_device_t> { pub(crate) fn stdev_from_nix(dev: libc::dev_t) -> WasiResult<wasi::__wasi_device_t> {
wasi::__wasi_device_t::try_from(dev).map_err(Into::into) wasi::__wasi_device_t::try_from(dev).map_err(Into::into)
} }
pub(crate) fn stino_from_nix(ino: libc::ino_t) -> Result<wasi::__wasi_inode_t> { pub(crate) fn stino_from_nix(ino: libc::ino_t) -> WasiResult<wasi::__wasi_inode_t> {
wasi::__wasi_device_t::try_from(ino).map_err(Into::into) wasi::__wasi_device_t::try_from(ino).map_err(Into::into)
} }
pub(crate) fn stnlink_from_nix(nlink: libc::nlink_t) -> Result<wasi::__wasi_linkcount_t> { pub(crate) fn stnlink_from_nix(nlink: libc::nlink_t) -> WasiResult<wasi::__wasi_linkcount_t> {
Ok(nlink.into()) Ok(nlink.into())
} }

View File

@@ -1,8 +1,8 @@
use crate::old::snapshot_0::hostcalls_impl::PathGet; use crate::old::snapshot_0::hostcalls_impl::PathGet;
use crate::old::snapshot_0::{Error, Result}; use crate::old::snapshot_0::wasi::{WasiError, WasiResult};
use std::os::unix::prelude::AsRawFd; use std::os::unix::prelude::AsRawFd;
pub(crate) fn path_unlink_file(resolved: PathGet) -> Result<()> { pub(crate) fn path_unlink_file(resolved: PathGet) -> WasiResult<()> {
use yanix::file::{unlinkat, AtFlag}; use yanix::file::{unlinkat, AtFlag};
match unsafe { match unsafe {
unlinkat( unlinkat(
@@ -32,7 +32,7 @@ pub(crate) fn path_unlink_file(resolved: PathGet) -> Result<()> {
} { } {
Ok(stat) => { Ok(stat) => {
if FileType::from_stat_st_mode(stat.st_mode) == FileType::Directory { if FileType::from_stat_st_mode(stat.st_mode) == FileType::Directory {
return Err(Error::EISDIR); return Err(WasiError::EISDIR);
} }
} }
Err(err) => { Err(err) => {
@@ -47,7 +47,7 @@ pub(crate) fn path_unlink_file(resolved: PathGet) -> Result<()> {
} }
} }
pub(crate) fn path_symlink(old_path: &str, resolved: PathGet) -> Result<()> { pub(crate) fn path_symlink(old_path: &str, resolved: PathGet) -> WasiResult<()> {
use yanix::file::{fstatat, symlinkat, AtFlag}; use yanix::file::{fstatat, symlinkat, AtFlag};
log::debug!("path_symlink old_path = {:?}", old_path); log::debug!("path_symlink old_path = {:?}", old_path);
@@ -69,7 +69,7 @@ pub(crate) fn path_symlink(old_path: &str, resolved: PathGet) -> Result<()> {
AtFlag::SYMLINK_NOFOLLOW, AtFlag::SYMLINK_NOFOLLOW,
) )
} { } {
Ok(_) => return Err(Error::EEXIST), Ok(_) => return Err(WasiError::EEXIST),
Err(err) => { Err(err) => {
log::debug!("path_symlink fstatat error: {:?}", err); log::debug!("path_symlink fstatat error: {:?}", err);
} }
@@ -81,7 +81,7 @@ pub(crate) fn path_symlink(old_path: &str, resolved: PathGet) -> Result<()> {
} }
} }
pub(crate) fn path_rename(resolved_old: PathGet, resolved_new: PathGet) -> Result<()> { pub(crate) fn path_rename(resolved_old: PathGet, resolved_new: PathGet) -> WasiResult<()> {
use yanix::file::{fstatat, renameat, AtFlag}; use yanix::file::{fstatat, renameat, AtFlag};
match unsafe { match unsafe {
renameat( renameat(
@@ -113,9 +113,9 @@ pub(crate) fn path_rename(resolved_old: PathGet, resolved_new: PathGet) -> Resul
Ok(_) => { Ok(_) => {
// check if destination contains a trailing slash // check if destination contains a trailing slash
if resolved_new.path().contains('/') { if resolved_new.path().contains('/') {
return Err(Error::ENOTDIR); return Err(WasiError::ENOTDIR);
} else { } else {
return Err(Error::ENOENT); return Err(WasiError::ENOENT);
} }
} }
Err(err) => { Err(err) => {
@@ -132,13 +132,13 @@ pub(crate) fn path_rename(resolved_old: PathGet, resolved_new: PathGet) -> Resul
pub(crate) mod fd_readdir_impl { pub(crate) mod fd_readdir_impl {
use crate::old::snapshot_0::sys::fdentry_impl::OsHandle; use crate::old::snapshot_0::sys::fdentry_impl::OsHandle;
use crate::old::snapshot_0::Result; use crate::old::snapshot_0::wasi::WasiResult;
use std::sync::{Mutex, MutexGuard}; use std::sync::{Mutex, MutexGuard};
use yanix::dir::Dir; use yanix::dir::Dir;
pub(crate) fn get_dir_from_os_handle<'a>( pub(crate) fn get_dir_from_os_handle<'a>(
os_handle: &'a mut OsHandle, os_handle: &'a mut OsHandle,
) -> Result<MutexGuard<'a, Dir>> { ) -> WasiResult<MutexGuard<'a, Dir>> {
let dir = match os_handle.dir { let dir = match os_handle.dir {
Some(ref mut dir) => dir, Some(ref mut dir) => dir,
None => { None => {

View File

@@ -1,5 +1,5 @@
use crate::old::snapshot_0::fdentry::{Descriptor, OsHandleRef}; use crate::old::snapshot_0::fdentry::{Descriptor, OsHandleRef};
use crate::old::snapshot_0::{sys::unix::sys_impl, wasi, Error, Result}; use crate::old::snapshot_0::{sys::unix::sys_impl, wasi};
use std::fs::File; use std::fs::File;
use std::io; use std::io;
use std::mem::ManuallyDrop; use std::mem::ManuallyDrop;
@@ -29,7 +29,7 @@ pub(crate) fn descriptor_as_oshandle<'lifetime>(
/// This function is unsafe because it operates on a raw file descriptor. /// This function is unsafe because it operates on a raw file descriptor.
pub(crate) unsafe fn determine_type_and_access_rights<Fd: AsRawFd>( pub(crate) unsafe fn determine_type_and_access_rights<Fd: AsRawFd>(
fd: &Fd, fd: &Fd,
) -> Result<( ) -> io::Result<(
wasi::__wasi_filetype_t, wasi::__wasi_filetype_t,
wasi::__wasi_rights_t, wasi::__wasi_rights_t,
wasi::__wasi_rights_t, wasi::__wasi_rights_t,
@@ -51,7 +51,7 @@ pub(crate) unsafe fn determine_type_and_access_rights<Fd: AsRawFd>(
/// This function is unsafe because it operates on a raw file descriptor. /// This function is unsafe because it operates on a raw file descriptor.
pub(crate) unsafe fn determine_type_rights<Fd: AsRawFd>( pub(crate) unsafe fn determine_type_rights<Fd: AsRawFd>(
fd: &Fd, fd: &Fd,
) -> Result<( ) -> io::Result<(
wasi::__wasi_filetype_t, wasi::__wasi_filetype_t,
wasi::__wasi_rights_t, wasi::__wasi_rights_t,
wasi::__wasi_rights_t, wasi::__wasi_rights_t,
@@ -111,7 +111,7 @@ pub(crate) unsafe fn determine_type_rights<Fd: AsRawFd>(
wasi::RIGHTS_SOCKET_BASE, wasi::RIGHTS_SOCKET_BASE,
wasi::RIGHTS_SOCKET_INHERITING, wasi::RIGHTS_SOCKET_INHERITING,
), ),
_ => return Err(Error::EINVAL), _ => return Err(io::Error::from_raw_os_error(libc::EINVAL)),
} }
} else if ft.is_fifo() { } else if ft.is_fifo() {
log::debug!("Host fd {:?} is a fifo", fd.as_raw_fd()); log::debug!("Host fd {:?} is a fifo", fd.as_raw_fd());
@@ -122,7 +122,7 @@ pub(crate) unsafe fn determine_type_rights<Fd: AsRawFd>(
) )
} else { } else {
log::debug!("Host fd {:?} is unknown", fd.as_raw_fd()); log::debug!("Host fd {:?} is unknown", fd.as_raw_fd());
return Err(Error::EINVAL); return Err(io::Error::from_raw_os_error(libc::EINVAL));
} }
}; };

View File

@@ -3,94 +3,101 @@
#![allow(non_snake_case)] #![allow(non_snake_case)]
#![allow(dead_code)] #![allow(dead_code)]
use crate::old::snapshot_0::host::FileType; use crate::old::snapshot_0::host::FileType;
use crate::old::snapshot_0::{ use crate::old::snapshot_0::wasi::{self, WasiError, WasiResult};
error::FromRawOsError, helpers, sys::unix::sys_impl, wasi, Error, Result, use crate::old::snapshot_0::{helpers, sys::unix::sys_impl};
};
use std::ffi::OsStr; use std::ffi::OsStr;
use std::io;
use std::os::unix::prelude::OsStrExt; use std::os::unix::prelude::OsStrExt;
use yanix::file::OFlag; use yanix::file::OFlag;
pub(crate) use sys_impl::host_impl::*; pub(crate) use sys_impl::host_impl::*;
impl FromRawOsError for Error { impl From<io::Error> for WasiError {
fn from_raw_os_error(code: i32) -> Self { fn from(err: io::Error) -> Self {
match code { match err.raw_os_error() {
libc::EPERM => Self::EPERM, Some(code) => match code {
libc::ENOENT => Self::ENOENT, libc::EPERM => Self::EPERM,
libc::ESRCH => Self::ESRCH, libc::ENOENT => Self::ENOENT,
libc::EINTR => Self::EINTR, libc::ESRCH => Self::ESRCH,
libc::EIO => Self::EIO, libc::EINTR => Self::EINTR,
libc::ENXIO => Self::ENXIO, libc::EIO => Self::EIO,
libc::E2BIG => Self::E2BIG, libc::ENXIO => Self::ENXIO,
libc::ENOEXEC => Self::ENOEXEC, libc::E2BIG => Self::E2BIG,
libc::EBADF => Self::EBADF, libc::ENOEXEC => Self::ENOEXEC,
libc::ECHILD => Self::ECHILD, libc::EBADF => Self::EBADF,
libc::EAGAIN => Self::EAGAIN, libc::ECHILD => Self::ECHILD,
libc::ENOMEM => Self::ENOMEM, libc::EAGAIN => Self::EAGAIN,
libc::EACCES => Self::EACCES, libc::ENOMEM => Self::ENOMEM,
libc::EFAULT => Self::EFAULT, libc::EACCES => Self::EACCES,
libc::EBUSY => Self::EBUSY, libc::EFAULT => Self::EFAULT,
libc::EEXIST => Self::EEXIST, libc::EBUSY => Self::EBUSY,
libc::EXDEV => Self::EXDEV, libc::EEXIST => Self::EEXIST,
libc::ENODEV => Self::ENODEV, libc::EXDEV => Self::EXDEV,
libc::ENOTDIR => Self::ENOTDIR, libc::ENODEV => Self::ENODEV,
libc::EISDIR => Self::EISDIR, libc::ENOTDIR => Self::ENOTDIR,
libc::EINVAL => Self::EINVAL, libc::EISDIR => Self::EISDIR,
libc::ENFILE => Self::ENFILE, libc::EINVAL => Self::EINVAL,
libc::EMFILE => Self::EMFILE, libc::ENFILE => Self::ENFILE,
libc::ENOTTY => Self::ENOTTY, libc::EMFILE => Self::EMFILE,
libc::ETXTBSY => Self::ETXTBSY, libc::ENOTTY => Self::ENOTTY,
libc::EFBIG => Self::EFBIG, libc::ETXTBSY => Self::ETXTBSY,
libc::ENOSPC => Self::ENOSPC, libc::EFBIG => Self::EFBIG,
libc::ESPIPE => Self::ESPIPE, libc::ENOSPC => Self::ENOSPC,
libc::EROFS => Self::EROFS, libc::ESPIPE => Self::ESPIPE,
libc::EMLINK => Self::EMLINK, libc::EROFS => Self::EROFS,
libc::EPIPE => Self::EPIPE, libc::EMLINK => Self::EMLINK,
libc::EDOM => Self::EDOM, libc::EPIPE => Self::EPIPE,
libc::ERANGE => Self::ERANGE, libc::EDOM => Self::EDOM,
libc::EDEADLK => Self::EDEADLK, libc::ERANGE => Self::ERANGE,
libc::ENAMETOOLONG => Self::ENAMETOOLONG, libc::EDEADLK => Self::EDEADLK,
libc::ENOLCK => Self::ENOLCK, libc::ENAMETOOLONG => Self::ENAMETOOLONG,
libc::ENOSYS => Self::ENOSYS, libc::ENOLCK => Self::ENOLCK,
libc::ENOTEMPTY => Self::ENOTEMPTY, libc::ENOSYS => Self::ENOSYS,
libc::ELOOP => Self::ELOOP, libc::ENOTEMPTY => Self::ENOTEMPTY,
libc::ENOMSG => Self::ENOMSG, libc::ELOOP => Self::ELOOP,
libc::EIDRM => Self::EIDRM, libc::ENOMSG => Self::ENOMSG,
libc::ENOLINK => Self::ENOLINK, libc::EIDRM => Self::EIDRM,
libc::EPROTO => Self::EPROTO, libc::ENOLINK => Self::ENOLINK,
libc::EMULTIHOP => Self::EMULTIHOP, libc::EPROTO => Self::EPROTO,
libc::EBADMSG => Self::EBADMSG, libc::EMULTIHOP => Self::EMULTIHOP,
libc::EOVERFLOW => Self::EOVERFLOW, libc::EBADMSG => Self::EBADMSG,
libc::EILSEQ => Self::EILSEQ, libc::EOVERFLOW => Self::EOVERFLOW,
libc::ENOTSOCK => Self::ENOTSOCK, libc::EILSEQ => Self::EILSEQ,
libc::EDESTADDRREQ => Self::EDESTADDRREQ, libc::ENOTSOCK => Self::ENOTSOCK,
libc::EMSGSIZE => Self::EMSGSIZE, libc::EDESTADDRREQ => Self::EDESTADDRREQ,
libc::EPROTOTYPE => Self::EPROTOTYPE, libc::EMSGSIZE => Self::EMSGSIZE,
libc::ENOPROTOOPT => Self::ENOPROTOOPT, libc::EPROTOTYPE => Self::EPROTOTYPE,
libc::EPROTONOSUPPORT => Self::EPROTONOSUPPORT, libc::ENOPROTOOPT => Self::ENOPROTOOPT,
libc::EAFNOSUPPORT => Self::EAFNOSUPPORT, libc::EPROTONOSUPPORT => Self::EPROTONOSUPPORT,
libc::EADDRINUSE => Self::EADDRINUSE, libc::EAFNOSUPPORT => Self::EAFNOSUPPORT,
libc::EADDRNOTAVAIL => Self::EADDRNOTAVAIL, libc::EADDRINUSE => Self::EADDRINUSE,
libc::ENETDOWN => Self::ENETDOWN, libc::EADDRNOTAVAIL => Self::EADDRNOTAVAIL,
libc::ENETUNREACH => Self::ENETUNREACH, libc::ENETDOWN => Self::ENETDOWN,
libc::ENETRESET => Self::ENETRESET, libc::ENETUNREACH => Self::ENETUNREACH,
libc::ECONNABORTED => Self::ECONNABORTED, libc::ENETRESET => Self::ENETRESET,
libc::ECONNRESET => Self::ECONNRESET, libc::ECONNABORTED => Self::ECONNABORTED,
libc::ENOBUFS => Self::ENOBUFS, libc::ECONNRESET => Self::ECONNRESET,
libc::EISCONN => Self::EISCONN, libc::ENOBUFS => Self::ENOBUFS,
libc::ENOTCONN => Self::ENOTCONN, libc::EISCONN => Self::EISCONN,
libc::ETIMEDOUT => Self::ETIMEDOUT, libc::ENOTCONN => Self::ENOTCONN,
libc::ECONNREFUSED => Self::ECONNREFUSED, libc::ETIMEDOUT => Self::ETIMEDOUT,
libc::EHOSTUNREACH => Self::EHOSTUNREACH, libc::ECONNREFUSED => Self::ECONNREFUSED,
libc::EALREADY => Self::EALREADY, libc::EHOSTUNREACH => Self::EHOSTUNREACH,
libc::EINPROGRESS => Self::EINPROGRESS, libc::EALREADY => Self::EALREADY,
libc::ESTALE => Self::ESTALE, libc::EINPROGRESS => Self::EINPROGRESS,
libc::EDQUOT => Self::EDQUOT, libc::ESTALE => Self::ESTALE,
libc::ECANCELED => Self::ECANCELED, libc::EDQUOT => Self::EDQUOT,
libc::EOWNERDEAD => Self::EOWNERDEAD, libc::ECANCELED => Self::ECANCELED,
libc::ENOTRECOVERABLE => Self::ENOTRECOVERABLE, libc::EOWNERDEAD => Self::EOWNERDEAD,
x => { libc::ENOTRECOVERABLE => Self::ENOTRECOVERABLE,
log::debug!("Unknown errno value: {}", x); libc::ENOTSUP => Self::ENOTSUP,
x => {
log::debug!("Unknown errno value: {}", x);
Self::EIO
}
},
None => {
log::debug!("Other I/O error: {}", err);
Self::EIO Self::EIO
} }
} }
@@ -154,13 +161,13 @@ pub(crate) fn nix_from_oflags(oflags: wasi::__wasi_oflags_t) -> OFlag {
nix_flags nix_flags
} }
pub(crate) fn filestat_from_nix(filestat: libc::stat) -> Result<wasi::__wasi_filestat_t> { pub(crate) fn filestat_from_nix(filestat: libc::stat) -> WasiResult<wasi::__wasi_filestat_t> {
use std::convert::TryInto; use std::convert::TryInto;
fn filestat_to_timestamp(secs: u64, nsecs: u64) -> Result<wasi::__wasi_timestamp_t> { fn filestat_to_timestamp(secs: u64, nsecs: u64) -> WasiResult<wasi::__wasi_timestamp_t> {
secs.checked_mul(1_000_000_000) secs.checked_mul(1_000_000_000)
.and_then(|sec_nsec| sec_nsec.checked_add(nsecs)) .and_then(|sec_nsec| sec_nsec.checked_add(nsecs))
.ok_or(Error::EOVERFLOW) .ok_or(WasiError::EOVERFLOW)
} }
let filetype = yanix::file::FileType::from_stat_st_mode(filestat.st_mode); let filetype = yanix::file::FileType::from_stat_st_mode(filestat.st_mode);
@@ -195,7 +202,7 @@ pub(crate) fn filestat_from_nix(filestat: libc::stat) -> Result<wasi::__wasi_fil
/// ///
/// NB WASI spec requires OS string to be valid UTF-8. Otherwise, /// NB WASI spec requires OS string to be valid UTF-8. Otherwise,
/// `__WASI_ERRNO_ILSEQ` error is returned. /// `__WASI_ERRNO_ILSEQ` error is returned.
pub(crate) fn path_from_host<S: AsRef<OsStr>>(s: S) -> Result<String> { pub(crate) fn path_from_host<S: AsRef<OsStr>>(s: S) -> WasiResult<String> {
helpers::path_from_slice(s.as_ref().as_bytes()).map(String::from) helpers::path_from_slice(s.as_ref().as_bytes()).map(String::from)
} }

View File

@@ -3,7 +3,7 @@
use crate::old::snapshot_0::host::Dirent; use crate::old::snapshot_0::host::Dirent;
use crate::old::snapshot_0::hostcalls_impl::PathGet; use crate::old::snapshot_0::hostcalls_impl::PathGet;
use crate::old::snapshot_0::sys::{fdentry_impl::OsHandle, host_impl, unix::sys_impl}; use crate::old::snapshot_0::sys::{fdentry_impl::OsHandle, host_impl, unix::sys_impl};
use crate::old::snapshot_0::{wasi, Error, Result}; use crate::old::snapshot_0::wasi::{self, WasiError, WasiResult};
use std::convert::TryInto; use std::convert::TryInto;
use std::fs::File; use std::fs::File;
use std::os::unix::fs::FileExt; use std::os::unix::fs::FileExt;
@@ -15,21 +15,25 @@ pub(crate) fn fd_pread(
file: &File, file: &File,
buf: &mut [u8], buf: &mut [u8],
offset: wasi::__wasi_filesize_t, offset: wasi::__wasi_filesize_t,
) -> Result<usize> { ) -> WasiResult<usize> {
file.read_at(buf, offset).map_err(Into::into) file.read_at(buf, offset).map_err(Into::into)
} }
pub(crate) fn fd_pwrite(file: &File, buf: &[u8], offset: wasi::__wasi_filesize_t) -> Result<usize> { pub(crate) fn fd_pwrite(
file: &File,
buf: &[u8],
offset: wasi::__wasi_filesize_t,
) -> WasiResult<usize> {
file.write_at(buf, offset).map_err(Into::into) file.write_at(buf, offset).map_err(Into::into)
} }
pub(crate) fn fd_fdstat_get(fd: &File) -> Result<wasi::__wasi_fdflags_t> { pub(crate) fn fd_fdstat_get(fd: &File) -> WasiResult<wasi::__wasi_fdflags_t> {
unsafe { yanix::fcntl::get_status_flags(fd.as_raw_fd()) } unsafe { yanix::fcntl::get_status_flags(fd.as_raw_fd()) }
.map(host_impl::fdflags_from_nix) .map(host_impl::fdflags_from_nix)
.map_err(Into::into) .map_err(Into::into)
} }
pub(crate) fn fd_fdstat_set_flags(fd: &File, fdflags: wasi::__wasi_fdflags_t) -> Result<()> { pub(crate) fn fd_fdstat_set_flags(fd: &File, fdflags: wasi::__wasi_fdflags_t) -> WasiResult<()> {
let nix_flags = host_impl::nix_from_fdflags(fdflags); let nix_flags = host_impl::nix_from_fdflags(fdflags);
unsafe { yanix::fcntl::set_status_flags(fd.as_raw_fd(), nix_flags) }.map_err(Into::into) unsafe { yanix::fcntl::set_status_flags(fd.as_raw_fd(), nix_flags) }.map_err(Into::into)
} }
@@ -39,7 +43,7 @@ pub(crate) fn fd_advise(
advice: wasi::__wasi_advice_t, advice: wasi::__wasi_advice_t,
offset: wasi::__wasi_filesize_t, offset: wasi::__wasi_filesize_t,
len: wasi::__wasi_filesize_t, len: wasi::__wasi_filesize_t,
) -> Result<()> { ) -> WasiResult<()> {
use yanix::fadvise::{posix_fadvise, PosixFadviseAdvice}; use yanix::fadvise::{posix_fadvise, PosixFadviseAdvice};
let offset = offset.try_into()?; let offset = offset.try_into()?;
let len = len.try_into()?; let len = len.try_into()?;
@@ -50,12 +54,12 @@ pub(crate) fn fd_advise(
wasi::__WASI_ADVICE_NOREUSE => PosixFadviseAdvice::NoReuse, wasi::__WASI_ADVICE_NOREUSE => PosixFadviseAdvice::NoReuse,
wasi::__WASI_ADVICE_RANDOM => PosixFadviseAdvice::Random, wasi::__WASI_ADVICE_RANDOM => PosixFadviseAdvice::Random,
wasi::__WASI_ADVICE_NORMAL => PosixFadviseAdvice::Normal, wasi::__WASI_ADVICE_NORMAL => PosixFadviseAdvice::Normal,
_ => return Err(Error::EINVAL), _ => return Err(WasiError::EINVAL),
}; };
unsafe { posix_fadvise(file.as_raw_fd(), offset, len, host_advice) }.map_err(Into::into) unsafe { posix_fadvise(file.as_raw_fd(), offset, len, host_advice) }.map_err(Into::into)
} }
pub(crate) fn path_create_directory(resolved: PathGet) -> Result<()> { pub(crate) fn path_create_directory(resolved: PathGet) -> WasiResult<()> {
use yanix::file::{mkdirat, Mode}; use yanix::file::{mkdirat, Mode};
unsafe { unsafe {
mkdirat( mkdirat(
@@ -67,7 +71,7 @@ pub(crate) fn path_create_directory(resolved: PathGet) -> Result<()> {
.map_err(Into::into) .map_err(Into::into)
} }
pub(crate) fn path_link(resolved_old: PathGet, resolved_new: PathGet) -> Result<()> { pub(crate) fn path_link(resolved_old: PathGet, resolved_new: PathGet) -> WasiResult<()> {
use yanix::file::{linkat, AtFlag}; use yanix::file::{linkat, AtFlag};
unsafe { unsafe {
linkat( linkat(
@@ -87,7 +91,7 @@ pub(crate) fn path_open(
write: bool, write: bool,
oflags: wasi::__wasi_oflags_t, oflags: wasi::__wasi_oflags_t,
fs_flags: wasi::__wasi_fdflags_t, fs_flags: wasi::__wasi_fdflags_t,
) -> Result<File> { ) -> WasiResult<File> {
use yanix::file::{fstatat, openat, AtFlag, FileType, Mode, OFlag}; use yanix::file::{fstatat, openat, AtFlag, FileType, Mode, OFlag};
let mut nix_all_oflags = if read && write { let mut nix_all_oflags = if read && write {
@@ -136,7 +140,7 @@ pub(crate) fn path_open(
} { } {
Ok(stat) => { Ok(stat) => {
if FileType::from_stat_st_mode(stat.st_mode) == FileType::Socket { if FileType::from_stat_st_mode(stat.st_mode) == FileType::Socket {
return Err(Error::ENOTSUP); return Err(WasiError::ENOTSUP);
} }
} }
Err(err) => { Err(err) => {
@@ -158,7 +162,7 @@ pub(crate) fn path_open(
} { } {
Ok(stat) => { Ok(stat) => {
if FileType::from_stat_st_mode(stat.st_mode) == FileType::Symlink { if FileType::from_stat_st_mode(stat.st_mode) == FileType::Symlink {
return Err(Error::ELOOP); return Err(WasiError::ELOOP);
} }
} }
Err(err) => { Err(err) => {
@@ -169,7 +173,7 @@ pub(crate) fn path_open(
// FreeBSD returns EMLINK instead of ELOOP when using O_NOFOLLOW on // FreeBSD returns EMLINK instead of ELOOP when using O_NOFOLLOW on
// a symlink. // a symlink.
libc::EMLINK if !(nix_all_oflags & OFlag::NOFOLLOW).is_empty() => { libc::EMLINK if !(nix_all_oflags & OFlag::NOFOLLOW).is_empty() => {
return Err(Error::ELOOP); return Err(WasiError::ELOOP);
} }
_ => {} _ => {}
} }
@@ -184,7 +188,7 @@ pub(crate) fn path_open(
Ok(unsafe { File::from_raw_fd(new_fd) }) Ok(unsafe { File::from_raw_fd(new_fd) })
} }
pub(crate) fn path_readlink(resolved: PathGet, buf: &mut [u8]) -> Result<usize> { pub(crate) fn path_readlink(resolved: PathGet, buf: &mut [u8]) -> WasiResult<usize> {
use std::cmp::min; use std::cmp::min;
use yanix::file::readlinkat; use yanix::file::readlinkat;
let read_link = unsafe { readlinkat(resolved.dirfd().as_raw_fd(), resolved.path()) } let read_link = unsafe { readlinkat(resolved.dirfd().as_raw_fd(), resolved.path()) }
@@ -197,7 +201,7 @@ pub(crate) fn path_readlink(resolved: PathGet, buf: &mut [u8]) -> Result<usize>
Ok(copy_len) Ok(copy_len)
} }
pub(crate) fn fd_filestat_get(file: &std::fs::File) -> Result<wasi::__wasi_filestat_t> { pub(crate) fn fd_filestat_get(file: &std::fs::File) -> WasiResult<wasi::__wasi_filestat_t> {
use yanix::file::fstat; use yanix::file::fstat;
unsafe { fstat(file.as_raw_fd()) } unsafe { fstat(file.as_raw_fd()) }
.map_err(Into::into) .map_err(Into::into)
@@ -207,7 +211,7 @@ pub(crate) fn fd_filestat_get(file: &std::fs::File) -> Result<wasi::__wasi_files
pub(crate) fn path_filestat_get( pub(crate) fn path_filestat_get(
resolved: PathGet, resolved: PathGet,
dirflags: wasi::__wasi_lookupflags_t, dirflags: wasi::__wasi_lookupflags_t,
) -> Result<wasi::__wasi_filestat_t> { ) -> WasiResult<wasi::__wasi_filestat_t> {
use yanix::file::{fstatat, AtFlag}; use yanix::file::{fstatat, AtFlag};
let atflags = match dirflags { let atflags = match dirflags {
0 => AtFlag::empty(), 0 => AtFlag::empty(),
@@ -224,7 +228,7 @@ pub(crate) fn path_filestat_set_times(
st_atim: wasi::__wasi_timestamp_t, st_atim: wasi::__wasi_timestamp_t,
st_mtim: wasi::__wasi_timestamp_t, st_mtim: wasi::__wasi_timestamp_t,
fst_flags: wasi::__wasi_fstflags_t, fst_flags: wasi::__wasi_fstflags_t,
) -> Result<()> { ) -> WasiResult<()> {
use std::time::{Duration, UNIX_EPOCH}; use std::time::{Duration, UNIX_EPOCH};
use yanix::filetime::*; use yanix::filetime::*;
@@ -234,7 +238,7 @@ pub(crate) fn path_filestat_set_times(
let set_mtim_now = fst_flags & wasi::__WASI_FSTFLAGS_MTIM_NOW != 0; let set_mtim_now = fst_flags & wasi::__WASI_FSTFLAGS_MTIM_NOW != 0;
if (set_atim && set_atim_now) || (set_mtim && set_mtim_now) { if (set_atim && set_atim_now) || (set_mtim && set_mtim_now) {
return Err(Error::EINVAL); return Err(WasiError::EINVAL);
} }
let symlink_nofollow = wasi::__WASI_LOOKUPFLAGS_SYMLINK_FOLLOW != dirflags; let symlink_nofollow = wasi::__WASI_LOOKUPFLAGS_SYMLINK_FOLLOW != dirflags;
@@ -265,7 +269,7 @@ pub(crate) fn path_filestat_set_times(
.map_err(Into::into) .map_err(Into::into)
} }
pub(crate) fn path_remove_directory(resolved: PathGet) -> Result<()> { pub(crate) fn path_remove_directory(resolved: PathGet) -> WasiResult<()> {
use yanix::file::{unlinkat, AtFlag}; use yanix::file::{unlinkat, AtFlag};
unsafe { unsafe {
unlinkat( unlinkat(
@@ -280,7 +284,7 @@ pub(crate) fn path_remove_directory(resolved: PathGet) -> Result<()> {
pub(crate) fn fd_readdir<'a>( pub(crate) fn fd_readdir<'a>(
os_handle: &'a mut OsHandle, os_handle: &'a mut OsHandle,
cookie: wasi::__wasi_dircookie_t, cookie: wasi::__wasi_dircookie_t,
) -> Result<impl Iterator<Item = Result<Dirent>> + 'a> { ) -> WasiResult<impl Iterator<Item = WasiResult<Dirent>> + 'a> {
use yanix::dir::{DirIter, Entry, EntryExt, SeekLoc}; use yanix::dir::{DirIter, Entry, EntryExt, SeekLoc};
// Get an instance of `Dir`; this is host-specific due to intricasies // Get an instance of `Dir`; this is host-specific due to intricasies

View File

@@ -1,7 +1,7 @@
#![allow(non_camel_case_types)] #![allow(non_camel_case_types)]
#![allow(unused_unsafe)] #![allow(unused_unsafe)]
use crate::old::snapshot_0::sys::host_impl; use crate::old::snapshot_0::sys::host_impl;
use crate::old::snapshot_0::{wasi, Result}; use crate::old::snapshot_0::wasi::{self, WasiResult};
use std::fs::File; use std::fs::File;
use yanix::file::OFlag; use yanix::file::OFlag;
@@ -36,7 +36,7 @@ pub(crate) fn path_open_rights(
(needed_base, needed_inheriting) (needed_base, needed_inheriting)
} }
pub(crate) fn openat(dirfd: &File, path: &str) -> Result<File> { pub(crate) fn openat(dirfd: &File, path: &str) -> WasiResult<File> {
use std::os::unix::prelude::{AsRawFd, FromRawFd}; use std::os::unix::prelude::{AsRawFd, FromRawFd};
use yanix::file::{openat, Mode}; use yanix::file::{openat, Mode};
@@ -54,7 +54,7 @@ pub(crate) fn openat(dirfd: &File, path: &str) -> Result<File> {
.map_err(Into::into) .map_err(Into::into)
} }
pub(crate) fn readlinkat(dirfd: &File, path: &str) -> Result<String> { pub(crate) fn readlinkat(dirfd: &File, path: &str) -> WasiResult<String> {
use std::os::unix::prelude::AsRawFd; use std::os::unix::prelude::AsRawFd;
use yanix::file::readlinkat; use yanix::file::readlinkat;

View File

@@ -1,22 +1,24 @@
#![allow(non_camel_case_types)] #![allow(non_camel_case_types)]
#![allow(unused_unsafe)] #![allow(unused_unsafe)]
use crate::old::snapshot_0::hostcalls_impl::{ClockEventData, FdEventData}; use crate::old::snapshot_0::hostcalls_impl::{ClockEventData, FdEventData};
use crate::old::snapshot_0::{wasi, Error, Result}; use crate::old::snapshot_0::wasi::{self, WasiError, WasiResult};
use std::io; use std::io;
use yanix::clock::{clock_getres, clock_gettime, ClockId}; use yanix::clock::{clock_getres, clock_gettime, ClockId};
fn wasi_clock_id_to_unix(clock_id: wasi::__wasi_clockid_t) -> Result<ClockId> { fn wasi_clock_id_to_unix(clock_id: wasi::__wasi_clockid_t) -> WasiResult<ClockId> {
// convert the supported clocks to libc types, or return EINVAL // convert the supported clocks to libc types, or return EINVAL
match clock_id { match clock_id {
wasi::__WASI_CLOCKID_REALTIME => Ok(ClockId::Realtime), wasi::__WASI_CLOCKID_REALTIME => Ok(ClockId::Realtime),
wasi::__WASI_CLOCKID_MONOTONIC => Ok(ClockId::Monotonic), wasi::__WASI_CLOCKID_MONOTONIC => Ok(ClockId::Monotonic),
wasi::__WASI_CLOCKID_PROCESS_CPUTIME_ID => Ok(ClockId::ProcessCPUTime), wasi::__WASI_CLOCKID_PROCESS_CPUTIME_ID => Ok(ClockId::ProcessCPUTime),
wasi::__WASI_CLOCKID_THREAD_CPUTIME_ID => Ok(ClockId::ThreadCPUTime), wasi::__WASI_CLOCKID_THREAD_CPUTIME_ID => Ok(ClockId::ThreadCPUTime),
_ => Err(Error::EINVAL), _ => Err(WasiError::EINVAL),
} }
} }
pub(crate) fn clock_res_get(clock_id: wasi::__wasi_clockid_t) -> Result<wasi::__wasi_timestamp_t> { pub(crate) fn clock_res_get(
clock_id: wasi::__wasi_clockid_t,
) -> WasiResult<wasi::__wasi_timestamp_t> {
let clock_id = wasi_clock_id_to_unix(clock_id)?; let clock_id = wasi_clock_id_to_unix(clock_id)?;
let timespec = clock_getres(clock_id)?; let timespec = clock_getres(clock_id)?;
@@ -26,18 +28,20 @@ pub(crate) fn clock_res_get(clock_id: wasi::__wasi_clockid_t) -> Result<wasi::__
(timespec.tv_sec as wasi::__wasi_timestamp_t) (timespec.tv_sec as wasi::__wasi_timestamp_t)
.checked_mul(1_000_000_000) .checked_mul(1_000_000_000)
.and_then(|sec_ns| sec_ns.checked_add(timespec.tv_nsec as wasi::__wasi_timestamp_t)) .and_then(|sec_ns| sec_ns.checked_add(timespec.tv_nsec as wasi::__wasi_timestamp_t))
.map_or(Err(Error::EOVERFLOW), |resolution| { .map_or(Err(WasiError::EOVERFLOW), |resolution| {
// a supported clock can never return zero; this case will probably never get hit, but // a supported clock can never return zero; this case will probably never get hit, but
// make sure we follow the spec // make sure we follow the spec
if resolution == 0 { if resolution == 0 {
Err(Error::EINVAL) Err(WasiError::EINVAL)
} else { } else {
Ok(resolution) Ok(resolution)
} }
}) })
} }
pub(crate) fn clock_time_get(clock_id: wasi::__wasi_clockid_t) -> Result<wasi::__wasi_timestamp_t> { pub(crate) fn clock_time_get(
clock_id: wasi::__wasi_clockid_t,
) -> WasiResult<wasi::__wasi_timestamp_t> {
let clock_id = wasi_clock_id_to_unix(clock_id)?; let clock_id = wasi_clock_id_to_unix(clock_id)?;
let timespec = clock_gettime(clock_id)?; let timespec = clock_gettime(clock_id)?;
@@ -46,14 +50,14 @@ pub(crate) fn clock_time_get(clock_id: wasi::__wasi_clockid_t) -> Result<wasi::_
(timespec.tv_sec as wasi::__wasi_timestamp_t) (timespec.tv_sec as wasi::__wasi_timestamp_t)
.checked_mul(1_000_000_000) .checked_mul(1_000_000_000)
.and_then(|sec_ns| sec_ns.checked_add(timespec.tv_nsec as wasi::__wasi_timestamp_t)) .and_then(|sec_ns| sec_ns.checked_add(timespec.tv_nsec as wasi::__wasi_timestamp_t))
.map_or(Err(Error::EOVERFLOW), Ok) .map_or(Err(WasiError::EOVERFLOW), Ok)
} }
pub(crate) fn poll_oneoff( pub(crate) fn poll_oneoff(
timeout: Option<ClockEventData>, timeout: Option<ClockEventData>,
fd_events: Vec<FdEventData>, fd_events: Vec<FdEventData>,
events: &mut Vec<wasi::__wasi_event_t>, events: &mut Vec<wasi::__wasi_event_t>,
) -> Result<()> { ) -> WasiResult<()> {
use std::{convert::TryInto, os::unix::prelude::AsRawFd}; use std::{convert::TryInto, os::unix::prelude::AsRawFd};
use yanix::poll::{poll, PollFd, PollFlags}; use yanix::poll::{poll, PollFd, PollFlags};
@@ -122,7 +126,7 @@ fn poll_oneoff_handle_timeout_event(
fn poll_oneoff_handle_fd_event<'a>( fn poll_oneoff_handle_fd_event<'a>(
ready_events: impl Iterator<Item = (FdEventData<'a>, yanix::poll::PollFd)>, ready_events: impl Iterator<Item = (FdEventData<'a>, yanix::poll::PollFd)>,
events: &mut Vec<wasi::__wasi_event_t>, events: &mut Vec<wasi::__wasi_event_t>,
) -> Result<()> { ) -> WasiResult<()> {
use std::{convert::TryInto, os::unix::prelude::AsRawFd}; use std::{convert::TryInto, os::unix::prelude::AsRawFd};
use yanix::{file::fionread, poll::PollFlags}; use yanix::{file::fionread, poll::PollFlags};

View File

@@ -1,16 +1,16 @@
use crate::old::snapshot_0::{wasi, Result}; use crate::old::snapshot_0::wasi::{self, WasiResult};
use std::convert::TryInto; use std::convert::TryInto;
pub(crate) const O_RSYNC: yanix::file::OFlag = yanix::file::OFlag::RSYNC; pub(crate) const O_RSYNC: yanix::file::OFlag = yanix::file::OFlag::RSYNC;
pub(crate) fn stdev_from_nix(dev: libc::dev_t) -> Result<wasi::__wasi_device_t> { pub(crate) fn stdev_from_nix(dev: libc::dev_t) -> WasiResult<wasi::__wasi_device_t> {
Ok(wasi::__wasi_device_t::from(dev)) Ok(wasi::__wasi_device_t::from(dev))
} }
pub(crate) fn stino_from_nix(ino: libc::ino_t) -> Result<wasi::__wasi_inode_t> { pub(crate) fn stino_from_nix(ino: libc::ino_t) -> WasiResult<wasi::__wasi_inode_t> {
Ok(wasi::__wasi_device_t::from(ino)) Ok(wasi::__wasi_device_t::from(ino))
} }
pub(crate) fn stnlink_from_nix(nlink: libc::nlink_t) -> Result<wasi::__wasi_linkcount_t> { pub(crate) fn stnlink_from_nix(nlink: libc::nlink_t) -> WasiResult<wasi::__wasi_linkcount_t> {
nlink.try_into().map_err(Into::into) nlink.try_into().map_err(Into::into)
} }

View File

@@ -1,8 +1,8 @@
use crate::old::snapshot_0::hostcalls_impl::PathGet; use crate::old::snapshot_0::hostcalls_impl::PathGet;
use crate::old::snapshot_0::Result; use crate::old::snapshot_0::wasi::WasiResult;
use std::os::unix::prelude::AsRawFd; use std::os::unix::prelude::AsRawFd;
pub(crate) fn path_unlink_file(resolved: PathGet) -> Result<()> { pub(crate) fn path_unlink_file(resolved: PathGet) -> WasiResult<()> {
use yanix::file::{unlinkat, AtFlag}; use yanix::file::{unlinkat, AtFlag};
unsafe { unsafe {
unlinkat( unlinkat(
@@ -14,7 +14,7 @@ pub(crate) fn path_unlink_file(resolved: PathGet) -> Result<()> {
.map_err(Into::into) .map_err(Into::into)
} }
pub(crate) fn path_symlink(old_path: &str, resolved: PathGet) -> Result<()> { pub(crate) fn path_symlink(old_path: &str, resolved: PathGet) -> WasiResult<()> {
use yanix::file::symlinkat; use yanix::file::symlinkat;
log::debug!("path_symlink old_path = {:?}", old_path); log::debug!("path_symlink old_path = {:?}", old_path);
@@ -24,7 +24,7 @@ pub(crate) fn path_symlink(old_path: &str, resolved: PathGet) -> Result<()> {
.map_err(Into::into) .map_err(Into::into)
} }
pub(crate) fn path_rename(resolved_old: PathGet, resolved_new: PathGet) -> Result<()> { pub(crate) fn path_rename(resolved_old: PathGet, resolved_new: PathGet) -> WasiResult<()> {
use yanix::file::renameat; use yanix::file::renameat;
unsafe { unsafe {
renameat( renameat(
@@ -39,10 +39,10 @@ pub(crate) fn path_rename(resolved_old: PathGet, resolved_new: PathGet) -> Resul
pub(crate) mod fd_readdir_impl { pub(crate) mod fd_readdir_impl {
use crate::old::snapshot_0::sys::fdentry_impl::OsHandle; use crate::old::snapshot_0::sys::fdentry_impl::OsHandle;
use crate::old::snapshot_0::Result; use crate::old::snapshot_0::wasi::WasiResult;
use yanix::dir::Dir; use yanix::dir::Dir;
pub(crate) fn get_dir_from_os_handle(os_handle: &mut OsHandle) -> Result<Box<Dir>> { pub(crate) fn get_dir_from_os_handle(os_handle: &mut OsHandle) -> WasiResult<Box<Dir>> {
// We need to duplicate the fd, because `opendir(3)`: // We need to duplicate the fd, because `opendir(3)`:
// After a successful call to fdopendir(), fd is used internally by the implementation, // After a successful call to fdopendir(), fd is used internally by the implementation,
// and should not otherwise be used by the application. // and should not otherwise be used by the application.

View File

@@ -20,13 +20,9 @@ cfg_if::cfg_if! {
} }
} }
use crate::old::snapshot_0::Result;
use std::fs::{File, OpenOptions}; use std::fs::{File, OpenOptions};
use std::io::Result;
pub(crate) fn dev_null() -> Result<File> { pub(crate) fn dev_null() -> Result<File> {
OpenOptions::new() OpenOptions::new().read(true).write(true).open("/dev/null")
.read(true)
.write(true)
.open("/dev/null")
.map_err(Into::into)
} }

View File

@@ -1,5 +1,5 @@
use crate::old::snapshot_0::fdentry::{Descriptor, OsHandleRef}; use crate::old::snapshot_0::fdentry::{Descriptor, OsHandleRef};
use crate::old::snapshot_0::{wasi, Error, Result}; use crate::old::snapshot_0::wasi;
use std::fs::File; use std::fs::File;
use std::io; use std::io;
use std::mem::ManuallyDrop; use std::mem::ManuallyDrop;
@@ -57,7 +57,7 @@ pub(crate) fn descriptor_as_oshandle<'lifetime>(
/// This function is unsafe because it operates on a raw file handle. /// This function is unsafe because it operates on a raw file handle.
pub(crate) unsafe fn determine_type_and_access_rights<Handle: AsRawHandle>( pub(crate) unsafe fn determine_type_and_access_rights<Handle: AsRawHandle>(
handle: &Handle, handle: &Handle,
) -> Result<( ) -> io::Result<(
wasi::__wasi_filetype_t, wasi::__wasi_filetype_t,
wasi::__wasi_rights_t, wasi::__wasi_rights_t,
wasi::__wasi_rights_t, wasi::__wasi_rights_t,
@@ -88,7 +88,7 @@ pub(crate) unsafe fn determine_type_and_access_rights<Handle: AsRawHandle>(
/// This function is unsafe because it operates on a raw file handle. /// This function is unsafe because it operates on a raw file handle.
pub(crate) unsafe fn determine_type_rights<Handle: AsRawHandle>( pub(crate) unsafe fn determine_type_rights<Handle: AsRawHandle>(
handle: &Handle, handle: &Handle,
) -> Result<( ) -> io::Result<(
wasi::__wasi_filetype_t, wasi::__wasi_filetype_t,
wasi::__wasi_rights_t, wasi::__wasi_rights_t,
wasi::__wasi_rights_t, wasi::__wasi_rights_t,
@@ -106,7 +106,7 @@ pub(crate) unsafe fn determine_type_rights<Handle: AsRawHandle>(
} else if file_type.is_disk() { } else if file_type.is_disk() {
// disk file: file, dir or disk device // disk file: file, dir or disk device
let file = std::mem::ManuallyDrop::new(File::from_raw_handle(handle.as_raw_handle())); let file = std::mem::ManuallyDrop::new(File::from_raw_handle(handle.as_raw_handle()));
let meta = file.metadata().map_err(|_| Error::EINVAL)?; let meta = file.metadata()?;
if meta.is_dir() { if meta.is_dir() {
( (
wasi::__WASI_FILETYPE_DIRECTORY, wasi::__WASI_FILETYPE_DIRECTORY,
@@ -120,7 +120,7 @@ pub(crate) unsafe fn determine_type_rights<Handle: AsRawHandle>(
wasi::RIGHTS_REGULAR_FILE_INHERITING, wasi::RIGHTS_REGULAR_FILE_INHERITING,
) )
} else { } else {
return Err(Error::EINVAL); return Err(io::Error::from_raw_os_error(libc::EINVAL));
} }
} else if file_type.is_pipe() { } else if file_type.is_pipe() {
// pipe object: socket, named pipe or anonymous pipe // pipe object: socket, named pipe or anonymous pipe
@@ -131,7 +131,7 @@ pub(crate) unsafe fn determine_type_rights<Handle: AsRawHandle>(
wasi::RIGHTS_SOCKET_INHERITING, wasi::RIGHTS_SOCKET_INHERITING,
) )
} else { } else {
return Err(Error::EINVAL); return Err(io::Error::from_raw_os_error(libc::EINVAL));
} }
}; };
Ok((file_type, rights_base, rights_inheriting)) Ok((file_type, rights_base, rights_inheriting))

View File

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

View File

@@ -8,7 +8,7 @@ use crate::old::snapshot_0::hostcalls_impl::{fd_filestat_set_times_impl, PathGet
use crate::old::snapshot_0::sys::fdentry_impl::determine_type_rights; use crate::old::snapshot_0::sys::fdentry_impl::determine_type_rights;
use crate::old::snapshot_0::sys::host_impl::{self, path_from_host}; use crate::old::snapshot_0::sys::host_impl::{self, path_from_host};
use crate::old::snapshot_0::sys::hostcalls_impl::fs_helpers::PathGetExt; use crate::old::snapshot_0::sys::hostcalls_impl::fs_helpers::PathGetExt;
use crate::old::snapshot_0::{wasi, Error, Result}; use crate::old::snapshot_0::wasi::{self, WasiError, WasiResult};
use log::{debug, trace}; use log::{debug, trace};
use std::convert::TryInto; use std::convert::TryInto;
use std::fs::{File, Metadata, OpenOptions}; use std::fs::{File, Metadata, OpenOptions};
@@ -44,16 +44,20 @@ pub(crate) fn fd_pread(
file: &File, file: &File,
buf: &mut [u8], buf: &mut [u8],
offset: wasi::__wasi_filesize_t, offset: wasi::__wasi_filesize_t,
) -> Result<usize> { ) -> WasiResult<usize> {
read_at(file, buf, offset).map_err(Into::into) read_at(file, buf, offset).map_err(Into::into)
} }
// TODO refactor common code with unix // TODO refactor common code with unix
pub(crate) fn fd_pwrite(file: &File, buf: &[u8], offset: wasi::__wasi_filesize_t) -> Result<usize> { pub(crate) fn fd_pwrite(
file: &File,
buf: &[u8],
offset: wasi::__wasi_filesize_t,
) -> WasiResult<usize> {
write_at(file, buf, offset).map_err(Into::into) write_at(file, buf, offset).map_err(Into::into)
} }
pub(crate) fn fd_fdstat_get(fd: &File) -> Result<wasi::__wasi_fdflags_t> { pub(crate) fn fd_fdstat_get(fd: &File) -> WasiResult<wasi::__wasi_fdflags_t> {
let mut fdflags = 0; let mut fdflags = 0;
let handle = unsafe { fd.as_raw_handle() }; let handle = unsafe { fd.as_raw_handle() };
@@ -79,7 +83,7 @@ pub(crate) fn fd_fdstat_get(fd: &File) -> Result<wasi::__wasi_fdflags_t> {
Ok(fdflags) Ok(fdflags)
} }
pub(crate) fn fd_fdstat_set_flags(fd: &File, fdflags: wasi::__wasi_fdflags_t) -> Result<()> { pub(crate) fn fd_fdstat_set_flags(fd: &File, fdflags: wasi::__wasi_fdflags_t) -> WasiResult<()> {
unimplemented!("fd_fdstat_set_flags") unimplemented!("fd_fdstat_set_flags")
} }
@@ -88,7 +92,7 @@ pub(crate) fn fd_advise(
advice: wasi::__wasi_advice_t, advice: wasi::__wasi_advice_t,
_offset: wasi::__wasi_filesize_t, _offset: wasi::__wasi_filesize_t,
_len: wasi::__wasi_filesize_t, _len: wasi::__wasi_filesize_t,
) -> Result<()> { ) -> WasiResult<()> {
match advice { match advice {
wasi::__WASI_ADVICE_DONTNEED wasi::__WASI_ADVICE_DONTNEED
| wasi::__WASI_ADVICE_SEQUENTIAL | wasi::__WASI_ADVICE_SEQUENTIAL
@@ -96,18 +100,18 @@ pub(crate) fn fd_advise(
| wasi::__WASI_ADVICE_NOREUSE | wasi::__WASI_ADVICE_NOREUSE
| wasi::__WASI_ADVICE_RANDOM | wasi::__WASI_ADVICE_RANDOM
| wasi::__WASI_ADVICE_NORMAL => {} | wasi::__WASI_ADVICE_NORMAL => {}
_ => return Err(Error::EINVAL), _ => return Err(WasiError::EINVAL),
} }
Ok(()) Ok(())
} }
pub(crate) fn path_create_directory(resolved: PathGet) -> Result<()> { pub(crate) fn path_create_directory(resolved: PathGet) -> WasiResult<()> {
let path = resolved.concatenate()?; let path = resolved.concatenate()?;
std::fs::create_dir(&path).map_err(Into::into) std::fs::create_dir(&path).map_err(Into::into)
} }
pub(crate) fn path_link(resolved_old: PathGet, resolved_new: PathGet) -> Result<()> { pub(crate) fn path_link(resolved_old: PathGet, resolved_new: PathGet) -> WasiResult<()> {
unimplemented!("path_link") unimplemented!("path_link")
} }
@@ -117,7 +121,7 @@ pub(crate) fn path_open(
write: bool, write: bool,
oflags: wasi::__wasi_oflags_t, oflags: wasi::__wasi_oflags_t,
fdflags: wasi::__wasi_fdflags_t, fdflags: wasi::__wasi_fdflags_t,
) -> Result<File> { ) -> WasiResult<File> {
use winx::file::{AccessMode, CreationDisposition, Flags}; use winx::file::{AccessMode, CreationDisposition, Flags};
// convert open flags // convert open flags
@@ -143,11 +147,11 @@ pub(crate) fn path_open(
Ok(file_type) => { Ok(file_type) => {
// check if we are trying to open a symlink // check if we are trying to open a symlink
if file_type.is_symlink() { if file_type.is_symlink() {
return Err(Error::ELOOP); return Err(WasiError::ELOOP);
} }
// check if we are trying to open a file as a dir // check if we are trying to open a file as a dir
if file_type.is_file() && oflags & wasi::__WASI_OFLAGS_DIRECTORY != 0 { if file_type.is_file() && oflags & wasi::__WASI_OFLAGS_DIRECTORY != 0 {
return Err(Error::ENOTDIR); return Err(WasiError::ENOTDIR);
} }
} }
Err(err) => match err.raw_os_error() { Err(err) => match err.raw_os_error() {
@@ -162,7 +166,7 @@ pub(crate) fn path_open(
} }
None => { None => {
log::debug!("Inconvertible OS error: {}", err); log::debug!("Inconvertible OS error: {}", err);
return Err(Error::EIO); return Err(WasiError::EIO);
} }
}, },
} }
@@ -236,7 +240,7 @@ fn dirent_from_path<P: AsRef<Path>>(
path: P, path: P,
name: &str, name: &str,
cookie: wasi::__wasi_dircookie_t, cookie: wasi::__wasi_dircookie_t,
) -> Result<Dirent> { ) -> WasiResult<Dirent> {
let path = path.as_ref(); let path = path.as_ref();
trace!("dirent_from_path: opening {}", path.to_string_lossy()); trace!("dirent_from_path: opening {}", path.to_string_lossy());
@@ -285,7 +289,7 @@ fn dirent_from_path<P: AsRef<Path>>(
pub(crate) fn fd_readdir( pub(crate) fn fd_readdir(
fd: &File, fd: &File,
cookie: wasi::__wasi_dircookie_t, cookie: wasi::__wasi_dircookie_t,
) -> Result<impl Iterator<Item = Result<Dirent>>> { ) -> WasiResult<impl Iterator<Item = WasiResult<Dirent>>> {
use winx::file::get_file_path; use winx::file::get_file_path;
let cookie = cookie.try_into()?; let cookie = cookie.try_into()?;
@@ -321,7 +325,7 @@ pub(crate) fn fd_readdir(
Ok(iter.skip(cookie)) Ok(iter.skip(cookie))
} }
pub(crate) fn path_readlink(resolved: PathGet, buf: &mut [u8]) -> Result<usize> { pub(crate) fn path_readlink(resolved: PathGet, buf: &mut [u8]) -> WasiResult<usize> {
use winx::file::get_file_path; use winx::file::get_file_path;
let path = resolved.concatenate()?; let path = resolved.concatenate()?;
@@ -335,8 +339,8 @@ pub(crate) fn path_readlink(resolved: PathGet, buf: &mut [u8]) -> Result<usize>
let dir_path = PathBuf::from(strip_extended_prefix(dir_path)); let dir_path = PathBuf::from(strip_extended_prefix(dir_path));
let target_path = target_path let target_path = target_path
.strip_prefix(dir_path) .strip_prefix(dir_path)
.map_err(|_| Error::ENOTCAPABLE) .map_err(|_| WasiError::ENOTCAPABLE)
.and_then(|path| path.to_str().map(String::from).ok_or(Error::EILSEQ))?; .and_then(|path| path.to_str().map(String::from).ok_or(WasiError::EILSEQ))?;
if buf.len() > 0 { if buf.len() > 0 {
let mut chars = target_path.chars(); let mut chars = target_path.chars();
@@ -358,7 +362,7 @@ pub(crate) fn path_readlink(resolved: PathGet, buf: &mut [u8]) -> Result<usize>
} }
} }
fn strip_trailing_slashes_and_concatenate(resolved: &PathGet) -> Result<Option<PathBuf>> { fn strip_trailing_slashes_and_concatenate(resolved: &PathGet) -> WasiResult<Option<PathBuf>> {
if resolved.path().ends_with('/') { if resolved.path().ends_with('/') {
let suffix = resolved.path().trim_end_matches('/'); let suffix = resolved.path().trim_end_matches('/');
concatenate(resolved.dirfd(), Path::new(suffix)).map(Some) concatenate(resolved.dirfd(), Path::new(suffix)).map(Some)
@@ -367,7 +371,7 @@ fn strip_trailing_slashes_and_concatenate(resolved: &PathGet) -> Result<Option<P
} }
} }
pub(crate) fn path_rename(resolved_old: PathGet, resolved_new: PathGet) -> Result<()> { pub(crate) fn path_rename(resolved_old: PathGet, resolved_new: PathGet) -> WasiResult<()> {
use std::fs; use std::fs;
let old_path = resolved_old.concatenate()?; let old_path = resolved_old.concatenate()?;
@@ -378,12 +382,12 @@ pub(crate) fn path_rename(resolved_old: PathGet, resolved_new: PathGet) -> Resul
// //
// [std::fs::rename]: https://doc.rust-lang.org/std/fs/fn.rename.html // [std::fs::rename]: https://doc.rust-lang.org/std/fs/fn.rename.html
if old_path.is_dir() && new_path.is_file() { if old_path.is_dir() && new_path.is_file() {
return Err(Error::ENOTDIR); return Err(WasiError::ENOTDIR);
} }
// Second sanity check: check we're not trying to rename a file into a path // Second sanity check: check we're not trying to rename a file into a path
// ending in a trailing slash. // ending in a trailing slash.
if old_path.is_file() && resolved_new.path().ends_with('/') { if old_path.is_file() && resolved_new.path().ends_with('/') {
return Err(Error::ENOTDIR); return Err(WasiError::ENOTDIR);
} }
// TODO handle symlinks // TODO handle symlinks
@@ -399,7 +403,7 @@ pub(crate) fn path_rename(resolved_old: PathGet, resolved_new: PathGet) -> Resul
// So most likely dealing with new_path == dir. // So most likely dealing with new_path == dir.
// Eliminate case old_path == file first. // Eliminate case old_path == file first.
if old_path.is_file() { if old_path.is_file() {
return Err(Error::EISDIR); return Err(WasiError::EISDIR);
} else { } else {
// Ok, let's try removing an empty dir at new_path if it exists // Ok, let's try removing an empty dir at new_path if it exists
// and is a nonempty dir. // and is a nonempty dir.
@@ -413,7 +417,7 @@ pub(crate) fn path_rename(resolved_old: PathGet, resolved_new: PathGet) -> Resul
// a file instead of a dir, and if so, throw ENOTDIR. // a file instead of a dir, and if so, throw ENOTDIR.
if let Some(path) = strip_trailing_slashes_and_concatenate(&resolved_old)? { if let Some(path) = strip_trailing_slashes_and_concatenate(&resolved_old)? {
if path.is_file() { if path.is_file() {
return Err(Error::ENOTDIR); return Err(WasiError::ENOTDIR);
} }
} }
} }
@@ -424,19 +428,19 @@ pub(crate) fn path_rename(resolved_old: PathGet, resolved_new: PathGet) -> Resul
} }
None => { None => {
log::debug!("Inconvertible OS error: {}", err); log::debug!("Inconvertible OS error: {}", err);
Err(Error::EIO) Err(WasiError::EIO)
} }
} }
} }
pub(crate) fn fd_filestat_get(file: &std::fs::File) -> Result<wasi::__wasi_filestat_t> { pub(crate) fn fd_filestat_get(file: &std::fs::File) -> WasiResult<wasi::__wasi_filestat_t> {
host_impl::filestat_from_win(file) host_impl::filestat_from_win(file)
} }
pub(crate) fn path_filestat_get( pub(crate) fn path_filestat_get(
resolved: PathGet, resolved: PathGet,
dirflags: wasi::__wasi_lookupflags_t, dirflags: wasi::__wasi_lookupflags_t,
) -> Result<wasi::__wasi_filestat_t> { ) -> WasiResult<wasi::__wasi_filestat_t> {
let path = resolved.concatenate()?; let path = resolved.concatenate()?;
let file = File::open(path)?; let file = File::open(path)?;
host_impl::filestat_from_win(&file) host_impl::filestat_from_win(&file)
@@ -448,7 +452,7 @@ pub(crate) fn path_filestat_set_times(
st_atim: wasi::__wasi_timestamp_t, st_atim: wasi::__wasi_timestamp_t,
mut st_mtim: wasi::__wasi_timestamp_t, mut st_mtim: wasi::__wasi_timestamp_t,
fst_flags: wasi::__wasi_fstflags_t, fst_flags: wasi::__wasi_fstflags_t,
) -> Result<()> { ) -> WasiResult<()> {
use winx::file::AccessMode; use winx::file::AccessMode;
let path = resolved.concatenate()?; let path = resolved.concatenate()?;
let file = OpenOptions::new() let file = OpenOptions::new()
@@ -457,7 +461,7 @@ pub(crate) fn path_filestat_set_times(
fd_filestat_set_times_impl(&file, st_atim, st_mtim, fst_flags) fd_filestat_set_times_impl(&file, st_atim, st_mtim, fst_flags)
} }
pub(crate) fn path_symlink(old_path: &str, resolved: PathGet) -> Result<()> { pub(crate) fn path_symlink(old_path: &str, resolved: PathGet) -> WasiResult<()> {
use std::os::windows::fs::{symlink_dir, symlink_file}; use std::os::windows::fs::{symlink_dir, symlink_file};
let old_path = concatenate(resolved.dirfd(), Path::new(old_path))?; let old_path = concatenate(resolved.dirfd(), Path::new(old_path))?;
@@ -479,14 +483,14 @@ pub(crate) fn path_symlink(old_path: &str, resolved: PathGet) -> Result<()> {
winerror::ERROR_ACCESS_DENIED => { winerror::ERROR_ACCESS_DENIED => {
// does the target exist? // does the target exist?
if new_path.exists() { if new_path.exists() {
return Err(Error::EEXIST); return Err(WasiError::EEXIST);
} }
} }
winerror::ERROR_INVALID_NAME => { winerror::ERROR_INVALID_NAME => {
// does the target without trailing slashes exist? // does the target without trailing slashes exist?
if let Some(path) = strip_trailing_slashes_and_concatenate(&resolved)? { if let Some(path) = strip_trailing_slashes_and_concatenate(&resolved)? {
if path.exists() { if path.exists() {
return Err(Error::EEXIST); return Err(WasiError::EEXIST);
} }
} }
} }
@@ -497,12 +501,12 @@ pub(crate) fn path_symlink(old_path: &str, resolved: PathGet) -> Result<()> {
} }
None => { None => {
log::debug!("Inconvertible OS error: {}", err); log::debug!("Inconvertible OS error: {}", err);
Err(Error::EIO) Err(WasiError::EIO)
} }
} }
} }
pub(crate) fn path_unlink_file(resolved: PathGet) -> Result<()> { pub(crate) fn path_unlink_file(resolved: PathGet) -> WasiResult<()> {
use std::fs; use std::fs;
let path = resolved.concatenate()?; let path = resolved.concatenate()?;
@@ -532,19 +536,19 @@ pub(crate) fn path_unlink_file(resolved: PathGet) -> Result<()> {
} }
None => { None => {
log::debug!("Inconvertible OS error: {}", err); log::debug!("Inconvertible OS error: {}", err);
Err(Error::EIO) Err(WasiError::EIO)
} }
} }
} else if file_type.is_dir() { } else if file_type.is_dir() {
Err(Error::EISDIR) Err(WasiError::EISDIR)
} else if file_type.is_file() { } else if file_type.is_file() {
fs::remove_file(path).map_err(Into::into) fs::remove_file(path).map_err(Into::into)
} else { } else {
Err(Error::EINVAL) Err(WasiError::EINVAL)
} }
} }
pub(crate) fn path_remove_directory(resolved: PathGet) -> Result<()> { pub(crate) fn path_remove_directory(resolved: PathGet) -> WasiResult<()> {
let path = resolved.concatenate()?; let path = resolved.concatenate()?;
std::fs::remove_dir(&path).map_err(Into::into) std::fs::remove_dir(&path).map_err(Into::into)
} }

View File

@@ -1,6 +1,6 @@
#![allow(non_camel_case_types)] #![allow(non_camel_case_types)]
use crate::old::snapshot_0::hostcalls_impl::PathGet; use crate::old::snapshot_0::hostcalls_impl::PathGet;
use crate::old::snapshot_0::{wasi, Error, Result}; use crate::old::snapshot_0::wasi::{self, WasiError, WasiResult};
use std::ffi::{OsStr, OsString}; use std::ffi::{OsStr, OsString};
use std::fs::File; use std::fs::File;
use std::os::windows::ffi::{OsStrExt, OsStringExt}; use std::os::windows::ffi::{OsStrExt, OsStringExt};
@@ -8,11 +8,11 @@ use std::path::{Path, PathBuf};
use winapi::shared::winerror; use winapi::shared::winerror;
pub(crate) trait PathGetExt { pub(crate) trait PathGetExt {
fn concatenate(&self) -> Result<PathBuf>; fn concatenate(&self) -> WasiResult<PathBuf>;
} }
impl PathGetExt for PathGet { impl PathGetExt for PathGet {
fn concatenate(&self) -> Result<PathBuf> { fn concatenate(&self) -> WasiResult<PathBuf> {
concatenate(self.dirfd(), Path::new(self.path())) concatenate(self.dirfd(), Path::new(self.path()))
} }
} }
@@ -46,7 +46,7 @@ pub(crate) fn path_open_rights(
(needed_base, needed_inheriting) (needed_base, needed_inheriting)
} }
pub(crate) fn openat(dirfd: &File, path: &str) -> Result<File> { pub(crate) fn openat(dirfd: &File, path: &str) -> WasiResult<File> {
use std::fs::OpenOptions; use std::fs::OpenOptions;
use std::os::windows::fs::OpenOptionsExt; use std::os::windows::fs::OpenOptionsExt;
use winx::file::Flags; use winx::file::Flags;
@@ -63,13 +63,13 @@ pub(crate) fn openat(dirfd: &File, path: &str) -> Result<File> {
if let Some(code) = err.raw_os_error() { if let Some(code) = err.raw_os_error() {
log::debug!("openat error={:?}", code); log::debug!("openat error={:?}", code);
if code as u32 == winerror::ERROR_INVALID_NAME { if code as u32 == winerror::ERROR_INVALID_NAME {
return Err(Error::ENOTDIR); return Err(WasiError::ENOTDIR);
} }
} }
Err(err.into()) Err(err.into())
} }
pub(crate) fn readlinkat(dirfd: &File, s_path: &str) -> Result<String> { pub(crate) fn readlinkat(dirfd: &File, s_path: &str) -> WasiResult<String> {
use winx::file::get_file_path; use winx::file::get_file_path;
let path = concatenate(dirfd, Path::new(s_path))?; let path = concatenate(dirfd, Path::new(s_path))?;
@@ -83,8 +83,8 @@ pub(crate) fn readlinkat(dirfd: &File, s_path: &str) -> Result<String> {
let dir_path = PathBuf::from(strip_extended_prefix(dir_path)); let dir_path = PathBuf::from(strip_extended_prefix(dir_path));
let target_path = target_path let target_path = target_path
.strip_prefix(dir_path) .strip_prefix(dir_path)
.map_err(|_| Error::ENOTCAPABLE)?; .map_err(|_| WasiError::ENOTCAPABLE)?;
let target_path = target_path.to_str().ok_or(Error::EILSEQ)?; let target_path = target_path.to_str().ok_or(WasiError::EILSEQ)?;
return Ok(target_path.to_owned()); return Ok(target_path.to_owned());
} }
Err(e) => e, Err(e) => e,
@@ -96,7 +96,7 @@ pub(crate) fn readlinkat(dirfd: &File, s_path: &str) -> Result<String> {
// strip "/" and check if exists // strip "/" and check if exists
let path = concatenate(dirfd, Path::new(s_path.trim_end_matches('/')))?; let path = concatenate(dirfd, Path::new(s_path.trim_end_matches('/')))?;
if path.exists() && !path.is_dir() { if path.exists() && !path.is_dir() {
return Err(Error::ENOTDIR); return Err(WasiError::ENOTDIR);
} }
} }
} }
@@ -113,13 +113,13 @@ pub(crate) fn strip_extended_prefix<P: AsRef<OsStr>>(path: P) -> OsString {
} }
} }
pub(crate) fn concatenate<P: AsRef<Path>>(dirfd: &File, path: P) -> Result<PathBuf> { pub(crate) fn concatenate<P: AsRef<Path>>(dirfd: &File, path: P) -> WasiResult<PathBuf> {
use winx::file::get_file_path; use winx::file::get_file_path;
// WASI is not able to deal with absolute paths // WASI is not able to deal with absolute paths
// so error out if absolute // so error out if absolute
if path.as_ref().is_absolute() { if path.as_ref().is_absolute() {
return Err(Error::ENOTCAPABLE); return Err(WasiError::ENOTCAPABLE);
} }
let dir_path = get_file_path(dirfd)?; let dir_path = get_file_path(dirfd)?;

View File

@@ -4,7 +4,8 @@
use crate::old::snapshot_0::hostcalls_impl::{ClockEventData, FdEventData}; use crate::old::snapshot_0::hostcalls_impl::{ClockEventData, FdEventData};
use crate::old::snapshot_0::memory::*; use crate::old::snapshot_0::memory::*;
use crate::old::snapshot_0::sys::host_impl; use crate::old::snapshot_0::sys::host_impl;
use crate::old::snapshot_0::{wasi, wasi32, Error, Result}; use crate::old::snapshot_0::wasi::{self, WasiError, WasiResult};
use crate::old::snapshot_0::wasi32;
use cpu_time::{ProcessTime, ThreadTime}; use cpu_time::{ProcessTime, ThreadTime};
use lazy_static::lazy_static; use lazy_static::lazy_static;
use std::convert::TryInto; use std::convert::TryInto;
@@ -17,7 +18,9 @@ lazy_static! {
// Timer resolution on Windows is really hard. We may consider exposing the resolution of the respective // Timer resolution on Windows is really hard. We may consider exposing the resolution of the respective
// timers as an associated function in the future. // timers as an associated function in the future.
pub(crate) fn clock_res_get(clock_id: wasi::__wasi_clockid_t) -> Result<wasi::__wasi_timestamp_t> { pub(crate) fn clock_res_get(
clock_id: wasi::__wasi_clockid_t,
) -> WasiResult<wasi::__wasi_timestamp_t> {
Ok(match clock_id { Ok(match clock_id {
// This is the best that we can do with std::time::SystemTime. // This is the best that we can do with std::time::SystemTime.
// Rust uses GetSystemTimeAsFileTime, which is said to have the resolution of // Rust uses GetSystemTimeAsFileTime, which is said to have the resolution of
@@ -61,17 +64,19 @@ pub(crate) fn clock_res_get(clock_id: wasi::__wasi_clockid_t) -> Result<wasi::__
// The best we can do is to hardcode the value from the docs. // The best we can do is to hardcode the value from the docs.
// https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-getthreadtimes // https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-getthreadtimes
wasi::__WASI_CLOCKID_THREAD_CPUTIME_ID => 100, wasi::__WASI_CLOCKID_THREAD_CPUTIME_ID => 100,
_ => return Err(Error::EINVAL), _ => return Err(WasiError::EINVAL),
}) })
} }
pub(crate) fn clock_time_get(clock_id: wasi::__wasi_clockid_t) -> Result<wasi::__wasi_timestamp_t> { pub(crate) fn clock_time_get(
clock_id: wasi::__wasi_clockid_t,
) -> WasiResult<wasi::__wasi_timestamp_t> {
let duration = match clock_id { let duration = match clock_id {
wasi::__WASI_CLOCKID_REALTIME => get_monotonic_time(), wasi::__WASI_CLOCKID_REALTIME => get_monotonic_time(),
wasi::__WASI_CLOCKID_MONOTONIC => get_realtime_time()?, wasi::__WASI_CLOCKID_MONOTONIC => get_realtime_time()?,
wasi::__WASI_CLOCKID_PROCESS_CPUTIME_ID => get_proc_cputime()?, wasi::__WASI_CLOCKID_PROCESS_CPUTIME_ID => get_proc_cputime()?,
wasi::__WASI_CLOCKID_THREAD_CPUTIME_ID => get_thread_cputime()?, wasi::__WASI_CLOCKID_THREAD_CPUTIME_ID => get_thread_cputime()?,
_ => return Err(Error::EINVAL), _ => return Err(WasiError::EINVAL),
}; };
duration.as_nanos().try_into().map_err(Into::into) duration.as_nanos().try_into().map_err(Into::into)
} }
@@ -80,7 +85,7 @@ pub(crate) fn poll_oneoff(
timeout: Option<ClockEventData>, timeout: Option<ClockEventData>,
fd_events: Vec<FdEventData>, fd_events: Vec<FdEventData>,
events: &mut Vec<wasi::__wasi_event_t>, events: &mut Vec<wasi::__wasi_event_t>,
) -> Result<Vec<wasi::__wasi_event_t>> { ) -> WasiResult<Vec<wasi::__wasi_event_t>> {
unimplemented!("poll_oneoff") unimplemented!("poll_oneoff")
} }
@@ -94,17 +99,17 @@ fn get_monotonic_time() -> Duration {
START_MONOTONIC.elapsed() START_MONOTONIC.elapsed()
} }
fn get_realtime_time() -> Result<Duration> { fn get_realtime_time() -> WasiResult<Duration> {
SystemTime::now() SystemTime::now()
.duration_since(UNIX_EPOCH) .duration_since(UNIX_EPOCH)
.map_err(|_| Error::EFAULT) .map_err(|_| WasiError::EFAULT)
} }
fn get_proc_cputime() -> Result<Duration> { fn get_proc_cputime() -> WasiResult<Duration> {
Ok(ProcessTime::try_now()?.as_duration()) Ok(ProcessTime::try_now()?.as_duration())
} }
fn get_thread_cputime() -> Result<Duration> { fn get_thread_cputime() -> WasiResult<Duration> {
Ok(ThreadTime::try_now()?.as_duration()) Ok(ThreadTime::try_now()?.as_duration())
} }

View File

@@ -2,13 +2,9 @@ pub(crate) mod fdentry_impl;
pub(crate) mod host_impl; pub(crate) mod host_impl;
pub(crate) mod hostcalls_impl; pub(crate) mod hostcalls_impl;
use crate::old::snapshot_0::Result;
use std::fs::{File, OpenOptions}; use std::fs::{File, OpenOptions};
use std::io::Result;
pub(crate) fn dev_null() -> Result<File> { pub(crate) fn dev_null() -> Result<File> {
OpenOptions::new() OpenOptions::new().read(true).write(true).open("NUL")
.read(true)
.write(true)
.open("NUL")
.map_err(Into::into)
} }

View File

@@ -10,6 +10,115 @@ use wig::witx_wasi_types;
witx_wasi_types!("old/snapshot_0" "wasi_unstable"); witx_wasi_types!("old/snapshot_0" "wasi_unstable");
pub type WasiResult<T> = Result<T, WasiError>;
#[derive(Clone, Copy, Debug, thiserror::Error, Eq, PartialEq)]
#[repr(u16)]
#[error("{:?} ({})", self, strerror(*self as __wasi_errno_t))]
pub enum WasiError {
ESUCCESS = __WASI_ERRNO_SUCCESS,
E2BIG = __WASI_ERRNO_2BIG,
EACCES = __WASI_ERRNO_ACCES,
EADDRINUSE = __WASI_ERRNO_ADDRINUSE,
EADDRNOTAVAIL = __WASI_ERRNO_ADDRNOTAVAIL,
EAFNOSUPPORT = __WASI_ERRNO_AFNOSUPPORT,
EAGAIN = __WASI_ERRNO_AGAIN,
EALREADY = __WASI_ERRNO_ALREADY,
EBADF = __WASI_ERRNO_BADF,
EBADMSG = __WASI_ERRNO_BADMSG,
EBUSY = __WASI_ERRNO_BUSY,
ECANCELED = __WASI_ERRNO_CANCELED,
ECHILD = __WASI_ERRNO_CHILD,
ECONNABORTED = __WASI_ERRNO_CONNABORTED,
ECONNREFUSED = __WASI_ERRNO_CONNREFUSED,
ECONNRESET = __WASI_ERRNO_CONNRESET,
EDEADLK = __WASI_ERRNO_DEADLK,
EDESTADDRREQ = __WASI_ERRNO_DESTADDRREQ,
EDOM = __WASI_ERRNO_DOM,
EDQUOT = __WASI_ERRNO_DQUOT,
EEXIST = __WASI_ERRNO_EXIST,
EFAULT = __WASI_ERRNO_FAULT,
EFBIG = __WASI_ERRNO_FBIG,
EHOSTUNREACH = __WASI_ERRNO_HOSTUNREACH,
EIDRM = __WASI_ERRNO_IDRM,
EILSEQ = __WASI_ERRNO_ILSEQ,
EINPROGRESS = __WASI_ERRNO_INPROGRESS,
EINTR = __WASI_ERRNO_INTR,
EINVAL = __WASI_ERRNO_INVAL,
EIO = __WASI_ERRNO_IO,
EISCONN = __WASI_ERRNO_ISCONN,
EISDIR = __WASI_ERRNO_ISDIR,
ELOOP = __WASI_ERRNO_LOOP,
EMFILE = __WASI_ERRNO_MFILE,
EMLINK = __WASI_ERRNO_MLINK,
EMSGSIZE = __WASI_ERRNO_MSGSIZE,
EMULTIHOP = __WASI_ERRNO_MULTIHOP,
ENAMETOOLONG = __WASI_ERRNO_NAMETOOLONG,
ENETDOWN = __WASI_ERRNO_NETDOWN,
ENETRESET = __WASI_ERRNO_NETRESET,
ENETUNREACH = __WASI_ERRNO_NETUNREACH,
ENFILE = __WASI_ERRNO_NFILE,
ENOBUFS = __WASI_ERRNO_NOBUFS,
ENODEV = __WASI_ERRNO_NODEV,
ENOENT = __WASI_ERRNO_NOENT,
ENOEXEC = __WASI_ERRNO_NOEXEC,
ENOLCK = __WASI_ERRNO_NOLCK,
ENOLINK = __WASI_ERRNO_NOLINK,
ENOMEM = __WASI_ERRNO_NOMEM,
ENOMSG = __WASI_ERRNO_NOMSG,
ENOPROTOOPT = __WASI_ERRNO_NOPROTOOPT,
ENOSPC = __WASI_ERRNO_NOSPC,
ENOSYS = __WASI_ERRNO_NOSYS,
ENOTCONN = __WASI_ERRNO_NOTCONN,
ENOTDIR = __WASI_ERRNO_NOTDIR,
ENOTEMPTY = __WASI_ERRNO_NOTEMPTY,
ENOTRECOVERABLE = __WASI_ERRNO_NOTRECOVERABLE,
ENOTSOCK = __WASI_ERRNO_NOTSOCK,
ENOTSUP = __WASI_ERRNO_NOTSUP,
ENOTTY = __WASI_ERRNO_NOTTY,
ENXIO = __WASI_ERRNO_NXIO,
EOVERFLOW = __WASI_ERRNO_OVERFLOW,
EOWNERDEAD = __WASI_ERRNO_OWNERDEAD,
EPERM = __WASI_ERRNO_PERM,
EPIPE = __WASI_ERRNO_PIPE,
EPROTO = __WASI_ERRNO_PROTO,
EPROTONOSUPPORT = __WASI_ERRNO_PROTONOSUPPORT,
EPROTOTYPE = __WASI_ERRNO_PROTOTYPE,
ERANGE = __WASI_ERRNO_RANGE,
EROFS = __WASI_ERRNO_ROFS,
ESPIPE = __WASI_ERRNO_SPIPE,
ESRCH = __WASI_ERRNO_SRCH,
ESTALE = __WASI_ERRNO_STALE,
ETIMEDOUT = __WASI_ERRNO_TIMEDOUT,
ETXTBSY = __WASI_ERRNO_TXTBSY,
EXDEV = __WASI_ERRNO_XDEV,
ENOTCAPABLE = __WASI_ERRNO_NOTCAPABLE,
}
impl WasiError {
pub fn as_raw_errno(self) -> __wasi_errno_t {
self as __wasi_errno_t
}
}
impl From<std::convert::Infallible> for WasiError {
fn from(_err: std::convert::Infallible) -> Self {
unreachable!()
}
}
impl From<std::num::TryFromIntError> for WasiError {
fn from(_err: std::num::TryFromIntError) -> Self {
Self::EOVERFLOW
}
}
impl From<std::str::Utf8Error> for WasiError {
fn from(_err: std::str::Utf8Error) -> Self {
Self::EILSEQ
}
}
pub(crate) const RIGHTS_ALL: __wasi_rights_t = __WASI_RIGHTS_FD_DATASYNC pub(crate) const RIGHTS_ALL: __wasi_rights_t = __WASI_RIGHTS_FD_DATASYNC
| __WASI_RIGHTS_FD_READ | __WASI_RIGHTS_FD_READ
| __WASI_RIGHTS_FD_SEEK | __WASI_RIGHTS_FD_SEEK

View File

@@ -1,12 +1,12 @@
use crate::{wasi, Result}; use crate::wasi::{self, WasiResult};
use std::convert::TryFrom; use std::convert::TryFrom;
pub(crate) const O_RSYNC: yanix::file::OFlag = yanix::file::OFlag::SYNC; pub(crate) const O_RSYNC: yanix::file::OFlag = yanix::file::OFlag::SYNC;
pub(crate) fn stdev_from_nix(dev: libc::dev_t) -> Result<wasi::__wasi_device_t> { pub(crate) fn stdev_from_nix(dev: libc::dev_t) -> WasiResult<wasi::__wasi_device_t> {
wasi::__wasi_device_t::try_from(dev).map_err(Into::into) wasi::__wasi_device_t::try_from(dev).map_err(Into::into)
} }
pub(crate) fn stino_from_nix(ino: libc::ino_t) -> Result<wasi::__wasi_inode_t> { pub(crate) fn stino_from_nix(ino: libc::ino_t) -> WasiResult<wasi::__wasi_inode_t> {
wasi::__wasi_device_t::try_from(ino).map_err(Into::into) wasi::__wasi_device_t::try_from(ino).map_err(Into::into)
} }

View File

@@ -1,8 +1,8 @@
use crate::hostcalls_impl::PathGet; use crate::hostcalls_impl::PathGet;
use crate::{Error, Result}; use crate::wasi::{WasiError, WasiResult};
use std::os::unix::prelude::AsRawFd; use std::os::unix::prelude::AsRawFd;
pub(crate) fn path_unlink_file(resolved: PathGet) -> Result<()> { pub(crate) fn path_unlink_file(resolved: PathGet) -> WasiResult<()> {
use yanix::file::{unlinkat, AtFlag}; use yanix::file::{unlinkat, AtFlag};
match unsafe { match unsafe {
unlinkat( unlinkat(
@@ -32,7 +32,7 @@ pub(crate) fn path_unlink_file(resolved: PathGet) -> Result<()> {
} { } {
Ok(stat) => { Ok(stat) => {
if FileType::from_stat_st_mode(stat.st_mode) == FileType::Directory { if FileType::from_stat_st_mode(stat.st_mode) == FileType::Directory {
return Err(Error::EISDIR); return Err(WasiError::EISDIR);
} }
} }
Err(err) => { Err(err) => {
@@ -47,7 +47,7 @@ pub(crate) fn path_unlink_file(resolved: PathGet) -> Result<()> {
} }
} }
pub(crate) fn path_symlink(old_path: &str, resolved: PathGet) -> Result<()> { pub(crate) fn path_symlink(old_path: &str, resolved: PathGet) -> WasiResult<()> {
use yanix::file::{fstatat, symlinkat, AtFlag}; use yanix::file::{fstatat, symlinkat, AtFlag};
log::debug!("path_symlink old_path = {:?}", old_path); log::debug!("path_symlink old_path = {:?}", old_path);
@@ -69,7 +69,7 @@ pub(crate) fn path_symlink(old_path: &str, resolved: PathGet) -> Result<()> {
AtFlag::SYMLINK_NOFOLLOW, AtFlag::SYMLINK_NOFOLLOW,
) )
} { } {
Ok(_) => return Err(Error::EEXIST), Ok(_) => return Err(WasiError::EEXIST),
Err(err) => { Err(err) => {
log::debug!("path_symlink fstatat error: {:?}", err); log::debug!("path_symlink fstatat error: {:?}", err);
} }
@@ -81,7 +81,7 @@ pub(crate) fn path_symlink(old_path: &str, resolved: PathGet) -> Result<()> {
} }
} }
pub(crate) fn path_rename(resolved_old: PathGet, resolved_new: PathGet) -> Result<()> { pub(crate) fn path_rename(resolved_old: PathGet, resolved_new: PathGet) -> WasiResult<()> {
use yanix::file::{fstatat, renameat, AtFlag}; use yanix::file::{fstatat, renameat, AtFlag};
match unsafe { match unsafe {
renameat( renameat(
@@ -113,9 +113,9 @@ pub(crate) fn path_rename(resolved_old: PathGet, resolved_new: PathGet) -> Resul
Ok(_) => { Ok(_) => {
// check if destination contains a trailing slash // check if destination contains a trailing slash
if resolved_new.path().contains('/') { if resolved_new.path().contains('/') {
return Err(Error::ENOTDIR); return Err(WasiError::ENOTDIR);
} else { } else {
return Err(Error::ENOENT); return Err(WasiError::ENOENT);
} }
} }
Err(err) => { Err(err) => {
@@ -132,13 +132,13 @@ pub(crate) fn path_rename(resolved_old: PathGet, resolved_new: PathGet) -> Resul
pub(crate) mod fd_readdir_impl { pub(crate) mod fd_readdir_impl {
use crate::sys::fdentry_impl::OsHandle; use crate::sys::fdentry_impl::OsHandle;
use crate::Result; use crate::wasi::WasiResult;
use std::sync::{Mutex, MutexGuard}; use std::sync::{Mutex, MutexGuard};
use yanix::dir::Dir; use yanix::dir::Dir;
pub(crate) fn get_dir_from_os_handle<'a>( pub(crate) fn get_dir_from_os_handle<'a>(
os_handle: &'a mut OsHandle, os_handle: &'a mut OsHandle,
) -> Result<MutexGuard<'a, Dir>> { ) -> WasiResult<MutexGuard<'a, Dir>> {
let dir = match os_handle.dir { let dir = match os_handle.dir {
Some(ref mut dir) => dir, Some(ref mut dir) => dir,
None => { None => {

View File

@@ -1,5 +1,5 @@
use crate::fdentry::{Descriptor, OsHandleRef}; use crate::fdentry::{Descriptor, OsHandleRef};
use crate::{sys::unix::sys_impl, wasi, Error, Result}; use crate::{sys::unix::sys_impl, wasi};
use std::fs::File; use std::fs::File;
use std::io; use std::io;
use std::mem::ManuallyDrop; use std::mem::ManuallyDrop;
@@ -33,7 +33,7 @@ pub(crate) fn descriptor_as_oshandle<'lifetime>(
/// This function is unsafe because it operates on a raw file descriptor. /// This function is unsafe because it operates on a raw file descriptor.
pub(crate) unsafe fn determine_type_and_access_rights<Fd: AsRawFd>( pub(crate) unsafe fn determine_type_and_access_rights<Fd: AsRawFd>(
fd: &Fd, fd: &Fd,
) -> Result<( ) -> io::Result<(
wasi::__wasi_filetype_t, wasi::__wasi_filetype_t,
wasi::__wasi_rights_t, wasi::__wasi_rights_t,
wasi::__wasi_rights_t, wasi::__wasi_rights_t,
@@ -57,7 +57,7 @@ pub(crate) unsafe fn determine_type_and_access_rights<Fd: AsRawFd>(
/// This function is unsafe because it operates on a raw file descriptor. /// This function is unsafe because it operates on a raw file descriptor.
pub(crate) unsafe fn determine_type_rights<Fd: AsRawFd>( pub(crate) unsafe fn determine_type_rights<Fd: AsRawFd>(
fd: &Fd, fd: &Fd,
) -> Result<( ) -> io::Result<(
wasi::__wasi_filetype_t, wasi::__wasi_filetype_t,
wasi::__wasi_rights_t, wasi::__wasi_rights_t,
wasi::__wasi_rights_t, wasi::__wasi_rights_t,
@@ -117,7 +117,7 @@ pub(crate) unsafe fn determine_type_rights<Fd: AsRawFd>(
wasi::RIGHTS_SOCKET_BASE, wasi::RIGHTS_SOCKET_BASE,
wasi::RIGHTS_SOCKET_INHERITING, wasi::RIGHTS_SOCKET_INHERITING,
), ),
_ => return Err(Error::EINVAL), _ => return Err(io::Error::from_raw_os_error(libc::EINVAL)),
} }
} else if ft.is_fifo() { } else if ft.is_fifo() {
log::debug!("Host fd {:?} is a fifo", fd.as_raw_fd()); log::debug!("Host fd {:?} is a fifo", fd.as_raw_fd());
@@ -128,7 +128,7 @@ pub(crate) unsafe fn determine_type_rights<Fd: AsRawFd>(
) )
} else { } else {
log::debug!("Host fd {:?} is unknown", fd.as_raw_fd()); log::debug!("Host fd {:?} is unknown", fd.as_raw_fd());
return Err(Error::EINVAL); return Err(io::Error::from_raw_os_error(libc::EINVAL));
} }
}; };

View File

@@ -3,92 +3,101 @@
#![allow(non_snake_case)] #![allow(non_snake_case)]
#![allow(dead_code)] #![allow(dead_code)]
use crate::host::FileType; use crate::host::FileType;
use crate::{error::FromRawOsError, helpers, sys::unix::sys_impl, wasi, Error, Result}; use crate::wasi::{self, WasiError, WasiResult};
use crate::{helpers, sys::unix::sys_impl};
use std::ffi::OsStr; use std::ffi::OsStr;
use std::io;
use std::os::unix::prelude::OsStrExt; use std::os::unix::prelude::OsStrExt;
use yanix::file::OFlag; use yanix::file::OFlag;
pub(crate) use sys_impl::host_impl::*; pub(crate) use sys_impl::host_impl::*;
impl FromRawOsError for Error { impl From<io::Error> for WasiError {
fn from_raw_os_error(code: i32) -> Self { fn from(err: io::Error) -> Self {
match code { match err.raw_os_error() {
libc::EPERM => Self::EPERM, Some(code) => match code {
libc::ENOENT => Self::ENOENT, libc::EPERM => Self::EPERM,
libc::ESRCH => Self::ESRCH, libc::ENOENT => Self::ENOENT,
libc::EINTR => Self::EINTR, libc::ESRCH => Self::ESRCH,
libc::EIO => Self::EIO, libc::EINTR => Self::EINTR,
libc::ENXIO => Self::ENXIO, libc::EIO => Self::EIO,
libc::E2BIG => Self::E2BIG, libc::ENXIO => Self::ENXIO,
libc::ENOEXEC => Self::ENOEXEC, libc::E2BIG => Self::E2BIG,
libc::EBADF => Self::EBADF, libc::ENOEXEC => Self::ENOEXEC,
libc::ECHILD => Self::ECHILD, libc::EBADF => Self::EBADF,
libc::EAGAIN => Self::EAGAIN, libc::ECHILD => Self::ECHILD,
libc::ENOMEM => Self::ENOMEM, libc::EAGAIN => Self::EAGAIN,
libc::EACCES => Self::EACCES, libc::ENOMEM => Self::ENOMEM,
libc::EFAULT => Self::EFAULT, libc::EACCES => Self::EACCES,
libc::EBUSY => Self::EBUSY, libc::EFAULT => Self::EFAULT,
libc::EEXIST => Self::EEXIST, libc::EBUSY => Self::EBUSY,
libc::EXDEV => Self::EXDEV, libc::EEXIST => Self::EEXIST,
libc::ENODEV => Self::ENODEV, libc::EXDEV => Self::EXDEV,
libc::ENOTDIR => Self::ENOTDIR, libc::ENODEV => Self::ENODEV,
libc::EISDIR => Self::EISDIR, libc::ENOTDIR => Self::ENOTDIR,
libc::EINVAL => Self::EINVAL, libc::EISDIR => Self::EISDIR,
libc::ENFILE => Self::ENFILE, libc::EINVAL => Self::EINVAL,
libc::EMFILE => Self::EMFILE, libc::ENFILE => Self::ENFILE,
libc::ENOTTY => Self::ENOTTY, libc::EMFILE => Self::EMFILE,
libc::ETXTBSY => Self::ETXTBSY, libc::ENOTTY => Self::ENOTTY,
libc::EFBIG => Self::EFBIG, libc::ETXTBSY => Self::ETXTBSY,
libc::ENOSPC => Self::ENOSPC, libc::EFBIG => Self::EFBIG,
libc::ESPIPE => Self::ESPIPE, libc::ENOSPC => Self::ENOSPC,
libc::EROFS => Self::EROFS, libc::ESPIPE => Self::ESPIPE,
libc::EMLINK => Self::EMLINK, libc::EROFS => Self::EROFS,
libc::EPIPE => Self::EPIPE, libc::EMLINK => Self::EMLINK,
libc::EDOM => Self::EDOM, libc::EPIPE => Self::EPIPE,
libc::ERANGE => Self::ERANGE, libc::EDOM => Self::EDOM,
libc::EDEADLK => Self::EDEADLK, libc::ERANGE => Self::ERANGE,
libc::ENAMETOOLONG => Self::ENAMETOOLONG, libc::EDEADLK => Self::EDEADLK,
libc::ENOLCK => Self::ENOLCK, libc::ENAMETOOLONG => Self::ENAMETOOLONG,
libc::ENOSYS => Self::ENOSYS, libc::ENOLCK => Self::ENOLCK,
libc::ENOTEMPTY => Self::ENOTEMPTY, libc::ENOSYS => Self::ENOSYS,
libc::ELOOP => Self::ELOOP, libc::ENOTEMPTY => Self::ENOTEMPTY,
libc::ENOMSG => Self::ENOMSG, libc::ELOOP => Self::ELOOP,
libc::EIDRM => Self::EIDRM, libc::ENOMSG => Self::ENOMSG,
libc::ENOLINK => Self::ENOLINK, libc::EIDRM => Self::EIDRM,
libc::EPROTO => Self::EPROTO, libc::ENOLINK => Self::ENOLINK,
libc::EMULTIHOP => Self::EMULTIHOP, libc::EPROTO => Self::EPROTO,
libc::EBADMSG => Self::EBADMSG, libc::EMULTIHOP => Self::EMULTIHOP,
libc::EOVERFLOW => Self::EOVERFLOW, libc::EBADMSG => Self::EBADMSG,
libc::EILSEQ => Self::EILSEQ, libc::EOVERFLOW => Self::EOVERFLOW,
libc::ENOTSOCK => Self::ENOTSOCK, libc::EILSEQ => Self::EILSEQ,
libc::EDESTADDRREQ => Self::EDESTADDRREQ, libc::ENOTSOCK => Self::ENOTSOCK,
libc::EMSGSIZE => Self::EMSGSIZE, libc::EDESTADDRREQ => Self::EDESTADDRREQ,
libc::EPROTOTYPE => Self::EPROTOTYPE, libc::EMSGSIZE => Self::EMSGSIZE,
libc::ENOPROTOOPT => Self::ENOPROTOOPT, libc::EPROTOTYPE => Self::EPROTOTYPE,
libc::EPROTONOSUPPORT => Self::EPROTONOSUPPORT, libc::ENOPROTOOPT => Self::ENOPROTOOPT,
libc::EAFNOSUPPORT => Self::EAFNOSUPPORT, libc::EPROTONOSUPPORT => Self::EPROTONOSUPPORT,
libc::EADDRINUSE => Self::EADDRINUSE, libc::EAFNOSUPPORT => Self::EAFNOSUPPORT,
libc::EADDRNOTAVAIL => Self::EADDRNOTAVAIL, libc::EADDRINUSE => Self::EADDRINUSE,
libc::ENETDOWN => Self::ENETDOWN, libc::EADDRNOTAVAIL => Self::EADDRNOTAVAIL,
libc::ENETUNREACH => Self::ENETUNREACH, libc::ENETDOWN => Self::ENETDOWN,
libc::ENETRESET => Self::ENETRESET, libc::ENETUNREACH => Self::ENETUNREACH,
libc::ECONNABORTED => Self::ECONNABORTED, libc::ENETRESET => Self::ENETRESET,
libc::ECONNRESET => Self::ECONNRESET, libc::ECONNABORTED => Self::ECONNABORTED,
libc::ENOBUFS => Self::ENOBUFS, libc::ECONNRESET => Self::ECONNRESET,
libc::EISCONN => Self::EISCONN, libc::ENOBUFS => Self::ENOBUFS,
libc::ENOTCONN => Self::ENOTCONN, libc::EISCONN => Self::EISCONN,
libc::ETIMEDOUT => Self::ETIMEDOUT, libc::ENOTCONN => Self::ENOTCONN,
libc::ECONNREFUSED => Self::ECONNREFUSED, libc::ETIMEDOUT => Self::ETIMEDOUT,
libc::EHOSTUNREACH => Self::EHOSTUNREACH, libc::ECONNREFUSED => Self::ECONNREFUSED,
libc::EALREADY => Self::EALREADY, libc::EHOSTUNREACH => Self::EHOSTUNREACH,
libc::EINPROGRESS => Self::EINPROGRESS, libc::EALREADY => Self::EALREADY,
libc::ESTALE => Self::ESTALE, libc::EINPROGRESS => Self::EINPROGRESS,
libc::EDQUOT => Self::EDQUOT, libc::ESTALE => Self::ESTALE,
libc::ECANCELED => Self::ECANCELED, libc::EDQUOT => Self::EDQUOT,
libc::EOWNERDEAD => Self::EOWNERDEAD, libc::ECANCELED => Self::ECANCELED,
libc::ENOTRECOVERABLE => Self::ENOTRECOVERABLE, libc::EOWNERDEAD => Self::EOWNERDEAD,
x => { libc::ENOTRECOVERABLE => Self::ENOTRECOVERABLE,
log::debug!("Unknown errno value: {}", x); libc::ENOTSUP => Self::ENOTSUP,
x => {
log::debug!("Unknown errno value: {}", x);
Self::EIO
}
},
None => {
log::debug!("Other I/O error: {}", err);
Self::EIO Self::EIO
} }
} }
@@ -152,13 +161,13 @@ pub(crate) fn nix_from_oflags(oflags: wasi::__wasi_oflags_t) -> OFlag {
nix_flags nix_flags
} }
pub(crate) fn filestat_from_nix(filestat: libc::stat) -> Result<wasi::__wasi_filestat_t> { pub(crate) fn filestat_from_nix(filestat: libc::stat) -> WasiResult<wasi::__wasi_filestat_t> {
use std::convert::TryInto; use std::convert::TryInto;
fn filestat_to_timestamp(secs: u64, nsecs: u64) -> Result<wasi::__wasi_timestamp_t> { fn filestat_to_timestamp(secs: u64, nsecs: u64) -> WasiResult<wasi::__wasi_timestamp_t> {
secs.checked_mul(1_000_000_000) secs.checked_mul(1_000_000_000)
.and_then(|sec_nsec| sec_nsec.checked_add(nsecs)) .and_then(|sec_nsec| sec_nsec.checked_add(nsecs))
.ok_or(Error::EOVERFLOW) .ok_or(WasiError::EOVERFLOW)
} }
let filetype = yanix::file::FileType::from_stat_st_mode(filestat.st_mode); let filetype = yanix::file::FileType::from_stat_st_mode(filestat.st_mode);
@@ -193,7 +202,7 @@ pub(crate) fn filestat_from_nix(filestat: libc::stat) -> Result<wasi::__wasi_fil
/// ///
/// NB WASI spec requires OS string to be valid UTF-8. Otherwise, /// NB WASI spec requires OS string to be valid UTF-8. Otherwise,
/// `__WASI_ERRNO_ILSEQ` error is returned. /// `__WASI_ERRNO_ILSEQ` error is returned.
pub(crate) fn path_from_host<S: AsRef<OsStr>>(s: S) -> Result<String> { pub(crate) fn path_from_host<S: AsRef<OsStr>>(s: S) -> WasiResult<String> {
helpers::path_from_slice(s.as_ref().as_bytes()).map(String::from) helpers::path_from_slice(s.as_ref().as_bytes()).map(String::from)
} }

View File

@@ -3,8 +3,9 @@
use crate::fdentry::Descriptor; use crate::fdentry::Descriptor;
use crate::host::Dirent; use crate::host::Dirent;
use crate::hostcalls_impl::PathGet; use crate::hostcalls_impl::PathGet;
use crate::sys::{fdentry_impl::OsHandle, host_impl, unix::sys_impl}; use crate::sys::fdentry_impl::OsHandle;
use crate::{wasi, Error, Result}; use crate::sys::{host_impl, unix::sys_impl};
use crate::wasi::{self, WasiError, WasiResult};
use std::convert::TryInto; use std::convert::TryInto;
use std::fs::File; use std::fs::File;
use std::os::unix::fs::FileExt; use std::os::unix::fs::FileExt;
@@ -16,15 +17,19 @@ pub(crate) fn fd_pread(
file: &File, file: &File,
buf: &mut [u8], buf: &mut [u8],
offset: wasi::__wasi_filesize_t, offset: wasi::__wasi_filesize_t,
) -> Result<usize> { ) -> WasiResult<usize> {
file.read_at(buf, offset).map_err(Into::into) file.read_at(buf, offset).map_err(Into::into)
} }
pub(crate) fn fd_pwrite(file: &File, buf: &[u8], offset: wasi::__wasi_filesize_t) -> Result<usize> { pub(crate) fn fd_pwrite(
file: &File,
buf: &[u8],
offset: wasi::__wasi_filesize_t,
) -> WasiResult<usize> {
file.write_at(buf, offset).map_err(Into::into) file.write_at(buf, offset).map_err(Into::into)
} }
pub(crate) fn fd_fdstat_get(fd: &File) -> Result<wasi::__wasi_fdflags_t> { pub(crate) fn fd_fdstat_get(fd: &File) -> WasiResult<wasi::__wasi_fdflags_t> {
unsafe { yanix::fcntl::get_status_flags(fd.as_raw_fd()) } unsafe { yanix::fcntl::get_status_flags(fd.as_raw_fd()) }
.map(host_impl::fdflags_from_nix) .map(host_impl::fdflags_from_nix)
.map_err(Into::into) .map_err(Into::into)
@@ -33,7 +38,7 @@ pub(crate) fn fd_fdstat_get(fd: &File) -> Result<wasi::__wasi_fdflags_t> {
pub(crate) fn fd_fdstat_set_flags( pub(crate) fn fd_fdstat_set_flags(
fd: &File, fd: &File,
fdflags: wasi::__wasi_fdflags_t, fdflags: wasi::__wasi_fdflags_t,
) -> Result<Option<OsHandle>> { ) -> WasiResult<Option<OsHandle>> {
let nix_flags = host_impl::nix_from_fdflags(fdflags); let nix_flags = host_impl::nix_from_fdflags(fdflags);
unsafe { yanix::fcntl::set_status_flags(fd.as_raw_fd(), nix_flags) } unsafe { yanix::fcntl::set_status_flags(fd.as_raw_fd(), nix_flags) }
.map(|_| None) .map(|_| None)
@@ -45,7 +50,7 @@ pub(crate) fn fd_advise(
advice: wasi::__wasi_advice_t, advice: wasi::__wasi_advice_t,
offset: wasi::__wasi_filesize_t, offset: wasi::__wasi_filesize_t,
len: wasi::__wasi_filesize_t, len: wasi::__wasi_filesize_t,
) -> Result<()> { ) -> WasiResult<()> {
use yanix::fadvise::{posix_fadvise, PosixFadviseAdvice}; use yanix::fadvise::{posix_fadvise, PosixFadviseAdvice};
let offset = offset.try_into()?; let offset = offset.try_into()?;
let len = len.try_into()?; let len = len.try_into()?;
@@ -56,17 +61,17 @@ pub(crate) fn fd_advise(
wasi::__WASI_ADVICE_NOREUSE => PosixFadviseAdvice::NoReuse, wasi::__WASI_ADVICE_NOREUSE => PosixFadviseAdvice::NoReuse,
wasi::__WASI_ADVICE_RANDOM => PosixFadviseAdvice::Random, wasi::__WASI_ADVICE_RANDOM => PosixFadviseAdvice::Random,
wasi::__WASI_ADVICE_NORMAL => PosixFadviseAdvice::Normal, wasi::__WASI_ADVICE_NORMAL => PosixFadviseAdvice::Normal,
_ => return Err(Error::EINVAL), _ => return Err(WasiError::EINVAL),
}; };
unsafe { posix_fadvise(file.as_raw_fd(), offset, len, host_advice) }.map_err(Into::into) unsafe { posix_fadvise(file.as_raw_fd(), offset, len, host_advice) }.map_err(Into::into)
} }
pub(crate) fn path_create_directory(base: &File, path: &str) -> Result<()> { pub(crate) fn path_create_directory(base: &File, path: &str) -> WasiResult<()> {
use yanix::file::{mkdirat, Mode}; use yanix::file::{mkdirat, Mode};
unsafe { mkdirat(base.as_raw_fd(), path, Mode::from_bits_truncate(0o777)) }.map_err(Into::into) unsafe { mkdirat(base.as_raw_fd(), path, Mode::from_bits_truncate(0o777)) }.map_err(Into::into)
} }
pub(crate) fn path_link(resolved_old: PathGet, resolved_new: PathGet) -> Result<()> { pub(crate) fn path_link(resolved_old: PathGet, resolved_new: PathGet) -> WasiResult<()> {
use yanix::file::{linkat, AtFlag}; use yanix::file::{linkat, AtFlag};
unsafe { unsafe {
linkat( linkat(
@@ -86,7 +91,7 @@ pub(crate) fn path_open(
write: bool, write: bool,
oflags: wasi::__wasi_oflags_t, oflags: wasi::__wasi_oflags_t,
fs_flags: wasi::__wasi_fdflags_t, fs_flags: wasi::__wasi_fdflags_t,
) -> Result<Descriptor> { ) -> WasiResult<Descriptor> {
use yanix::file::{fstatat, openat, AtFlag, FileType, Mode, OFlag}; use yanix::file::{fstatat, openat, AtFlag, FileType, Mode, OFlag};
let mut nix_all_oflags = if read && write { let mut nix_all_oflags = if read && write {
@@ -136,7 +141,7 @@ pub(crate) fn path_open(
} { } {
Ok(stat) => { Ok(stat) => {
if FileType::from_stat_st_mode(stat.st_mode) == FileType::Socket { if FileType::from_stat_st_mode(stat.st_mode) == FileType::Socket {
return Err(Error::ENOTSUP); return Err(WasiError::ENOTSUP);
} }
} }
Err(err) => { Err(err) => {
@@ -158,7 +163,7 @@ pub(crate) fn path_open(
} { } {
Ok(stat) => { Ok(stat) => {
if FileType::from_stat_st_mode(stat.st_mode) == FileType::Symlink { if FileType::from_stat_st_mode(stat.st_mode) == FileType::Symlink {
return Err(Error::ELOOP); return Err(WasiError::ELOOP);
} }
} }
Err(err) => { Err(err) => {
@@ -169,7 +174,7 @@ pub(crate) fn path_open(
// FreeBSD returns EMLINK instead of ELOOP when using O_NOFOLLOW on // FreeBSD returns EMLINK instead of ELOOP when using O_NOFOLLOW on
// a symlink. // a symlink.
libc::EMLINK if !(nix_all_oflags & OFlag::NOFOLLOW).is_empty() => { libc::EMLINK if !(nix_all_oflags & OFlag::NOFOLLOW).is_empty() => {
return Err(Error::ELOOP); return Err(WasiError::ELOOP);
} }
_ => {} _ => {}
} }
@@ -184,7 +189,7 @@ pub(crate) fn path_open(
Ok(OsHandle::from(unsafe { File::from_raw_fd(new_fd) }).into()) Ok(OsHandle::from(unsafe { File::from_raw_fd(new_fd) }).into())
} }
pub(crate) fn path_readlink(resolved: PathGet, buf: &mut [u8]) -> Result<usize> { pub(crate) fn path_readlink(resolved: PathGet, buf: &mut [u8]) -> WasiResult<usize> {
use std::cmp::min; use std::cmp::min;
use yanix::file::readlinkat; use yanix::file::readlinkat;
let read_link = unsafe { readlinkat(resolved.dirfd().as_raw_fd(), resolved.path()) } let read_link = unsafe { readlinkat(resolved.dirfd().as_raw_fd(), resolved.path()) }
@@ -197,7 +202,7 @@ pub(crate) fn path_readlink(resolved: PathGet, buf: &mut [u8]) -> Result<usize>
Ok(copy_len) Ok(copy_len)
} }
pub(crate) fn fd_filestat_get(file: &std::fs::File) -> Result<wasi::__wasi_filestat_t> { pub(crate) fn fd_filestat_get(file: &std::fs::File) -> WasiResult<wasi::__wasi_filestat_t> {
use yanix::file::fstat; use yanix::file::fstat;
unsafe { fstat(file.as_raw_fd()) } unsafe { fstat(file.as_raw_fd()) }
.map_err(Into::into) .map_err(Into::into)
@@ -207,7 +212,7 @@ pub(crate) fn fd_filestat_get(file: &std::fs::File) -> Result<wasi::__wasi_files
pub(crate) fn path_filestat_get( pub(crate) fn path_filestat_get(
resolved: PathGet, resolved: PathGet,
dirflags: wasi::__wasi_lookupflags_t, dirflags: wasi::__wasi_lookupflags_t,
) -> Result<wasi::__wasi_filestat_t> { ) -> WasiResult<wasi::__wasi_filestat_t> {
use yanix::file::{fstatat, AtFlag}; use yanix::file::{fstatat, AtFlag};
let atflags = match dirflags { let atflags = match dirflags {
0 => AtFlag::empty(), 0 => AtFlag::empty(),
@@ -224,7 +229,7 @@ pub(crate) fn path_filestat_set_times(
st_atim: wasi::__wasi_timestamp_t, st_atim: wasi::__wasi_timestamp_t,
st_mtim: wasi::__wasi_timestamp_t, st_mtim: wasi::__wasi_timestamp_t,
fst_flags: wasi::__wasi_fstflags_t, fst_flags: wasi::__wasi_fstflags_t,
) -> Result<()> { ) -> WasiResult<()> {
use std::time::{Duration, UNIX_EPOCH}; use std::time::{Duration, UNIX_EPOCH};
use yanix::filetime::*; use yanix::filetime::*;
@@ -234,7 +239,7 @@ pub(crate) fn path_filestat_set_times(
let set_mtim_now = fst_flags & wasi::__WASI_FSTFLAGS_MTIM_NOW != 0; let set_mtim_now = fst_flags & wasi::__WASI_FSTFLAGS_MTIM_NOW != 0;
if (set_atim && set_atim_now) || (set_mtim && set_mtim_now) { if (set_atim && set_atim_now) || (set_mtim && set_mtim_now) {
return Err(Error::EINVAL); return Err(WasiError::EINVAL);
} }
let symlink_nofollow = wasi::__WASI_LOOKUPFLAGS_SYMLINK_FOLLOW != dirflags; let symlink_nofollow = wasi::__WASI_LOOKUPFLAGS_SYMLINK_FOLLOW != dirflags;
@@ -265,7 +270,7 @@ pub(crate) fn path_filestat_set_times(
.map_err(Into::into) .map_err(Into::into)
} }
pub(crate) fn path_remove_directory(resolved: PathGet) -> Result<()> { pub(crate) fn path_remove_directory(resolved: PathGet) -> WasiResult<()> {
use yanix::file::{unlinkat, AtFlag}; use yanix::file::{unlinkat, AtFlag};
unsafe { unsafe {
@@ -281,7 +286,7 @@ pub(crate) fn path_remove_directory(resolved: PathGet) -> Result<()> {
pub(crate) fn fd_readdir<'a>( pub(crate) fn fd_readdir<'a>(
os_handle: &'a mut OsHandle, os_handle: &'a mut OsHandle,
cookie: wasi::__wasi_dircookie_t, cookie: wasi::__wasi_dircookie_t,
) -> Result<impl Iterator<Item = Result<Dirent>> + 'a> { ) -> WasiResult<impl Iterator<Item = WasiResult<Dirent>> + 'a> {
use yanix::dir::{DirIter, Entry, EntryExt, SeekLoc}; use yanix::dir::{DirIter, Entry, EntryExt, SeekLoc};
// Get an instance of `Dir`; this is host-specific due to intricasies // Get an instance of `Dir`; this is host-specific due to intricasies

View File

@@ -1,7 +1,7 @@
#![allow(non_camel_case_types)] #![allow(non_camel_case_types)]
#![allow(unused_unsafe)] #![allow(unused_unsafe)]
use crate::sys::host_impl; use crate::sys::host_impl;
use crate::{wasi, Result}; use crate::wasi::{self, WasiResult};
use std::fs::File; use std::fs::File;
use yanix::file::OFlag; use yanix::file::OFlag;
@@ -36,7 +36,7 @@ pub(crate) fn path_open_rights(
(needed_base, needed_inheriting) (needed_base, needed_inheriting)
} }
pub(crate) fn openat(dirfd: &File, path: &str) -> Result<File> { pub(crate) fn openat(dirfd: &File, path: &str) -> WasiResult<File> {
use std::os::unix::prelude::{AsRawFd, FromRawFd}; use std::os::unix::prelude::{AsRawFd, FromRawFd};
use yanix::file::{openat, Mode}; use yanix::file::{openat, Mode};
@@ -54,7 +54,7 @@ pub(crate) fn openat(dirfd: &File, path: &str) -> Result<File> {
.map_err(Into::into) .map_err(Into::into)
} }
pub(crate) fn readlinkat(dirfd: &File, path: &str) -> Result<String> { pub(crate) fn readlinkat(dirfd: &File, path: &str) -> WasiResult<String> {
use std::os::unix::prelude::AsRawFd; use std::os::unix::prelude::AsRawFd;
use yanix::file::readlinkat; use yanix::file::readlinkat;

View File

@@ -1,22 +1,24 @@
#![allow(non_camel_case_types)] #![allow(non_camel_case_types)]
#![allow(unused_unsafe)] #![allow(unused_unsafe)]
use crate::hostcalls_impl::{ClockEventData, FdEventData}; use crate::hostcalls_impl::{ClockEventData, FdEventData};
use crate::{wasi, Error, Result}; use crate::wasi::{self, WasiError, WasiResult};
use std::io; use std::io;
use yanix::clock::{clock_getres, clock_gettime, ClockId}; use yanix::clock::{clock_getres, clock_gettime, ClockId};
fn wasi_clock_id_to_unix(clock_id: wasi::__wasi_clockid_t) -> Result<ClockId> { fn wasi_clock_id_to_unix(clock_id: wasi::__wasi_clockid_t) -> WasiResult<ClockId> {
// convert the supported clocks to libc types, or return EINVAL // convert the supported clocks to libc types, or return EINVAL
match clock_id { match clock_id {
wasi::__WASI_CLOCKID_REALTIME => Ok(ClockId::Realtime), wasi::__WASI_CLOCKID_REALTIME => Ok(ClockId::Realtime),
wasi::__WASI_CLOCKID_MONOTONIC => Ok(ClockId::Monotonic), wasi::__WASI_CLOCKID_MONOTONIC => Ok(ClockId::Monotonic),
wasi::__WASI_CLOCKID_PROCESS_CPUTIME_ID => Ok(ClockId::ProcessCPUTime), wasi::__WASI_CLOCKID_PROCESS_CPUTIME_ID => Ok(ClockId::ProcessCPUTime),
wasi::__WASI_CLOCKID_THREAD_CPUTIME_ID => Ok(ClockId::ThreadCPUTime), wasi::__WASI_CLOCKID_THREAD_CPUTIME_ID => Ok(ClockId::ThreadCPUTime),
_ => Err(Error::EINVAL), _ => Err(WasiError::EINVAL),
} }
} }
pub(crate) fn clock_res_get(clock_id: wasi::__wasi_clockid_t) -> Result<wasi::__wasi_timestamp_t> { pub(crate) fn clock_res_get(
clock_id: wasi::__wasi_clockid_t,
) -> WasiResult<wasi::__wasi_timestamp_t> {
let clock_id = wasi_clock_id_to_unix(clock_id)?; let clock_id = wasi_clock_id_to_unix(clock_id)?;
let timespec = clock_getres(clock_id)?; let timespec = clock_getres(clock_id)?;
@@ -26,18 +28,20 @@ pub(crate) fn clock_res_get(clock_id: wasi::__wasi_clockid_t) -> Result<wasi::__
(timespec.tv_sec as wasi::__wasi_timestamp_t) (timespec.tv_sec as wasi::__wasi_timestamp_t)
.checked_mul(1_000_000_000) .checked_mul(1_000_000_000)
.and_then(|sec_ns| sec_ns.checked_add(timespec.tv_nsec as wasi::__wasi_timestamp_t)) .and_then(|sec_ns| sec_ns.checked_add(timespec.tv_nsec as wasi::__wasi_timestamp_t))
.map_or(Err(Error::EOVERFLOW), |resolution| { .map_or(Err(WasiError::EOVERFLOW), |resolution| {
// a supported clock can never return zero; this case will probably never get hit, but // a supported clock can never return zero; this case will probably never get hit, but
// make sure we follow the spec // make sure we follow the spec
if resolution == 0 { if resolution == 0 {
Err(Error::EINVAL) Err(WasiError::EINVAL)
} else { } else {
Ok(resolution) Ok(resolution)
} }
}) })
} }
pub(crate) fn clock_time_get(clock_id: wasi::__wasi_clockid_t) -> Result<wasi::__wasi_timestamp_t> { pub(crate) fn clock_time_get(
clock_id: wasi::__wasi_clockid_t,
) -> WasiResult<wasi::__wasi_timestamp_t> {
let clock_id = wasi_clock_id_to_unix(clock_id)?; let clock_id = wasi_clock_id_to_unix(clock_id)?;
let timespec = clock_gettime(clock_id)?; let timespec = clock_gettime(clock_id)?;
@@ -46,14 +50,14 @@ pub(crate) fn clock_time_get(clock_id: wasi::__wasi_clockid_t) -> Result<wasi::_
(timespec.tv_sec as wasi::__wasi_timestamp_t) (timespec.tv_sec as wasi::__wasi_timestamp_t)
.checked_mul(1_000_000_000) .checked_mul(1_000_000_000)
.and_then(|sec_ns| sec_ns.checked_add(timespec.tv_nsec as wasi::__wasi_timestamp_t)) .and_then(|sec_ns| sec_ns.checked_add(timespec.tv_nsec as wasi::__wasi_timestamp_t))
.map_or(Err(Error::EOVERFLOW), Ok) .map_or(Err(WasiError::EOVERFLOW), Ok)
} }
pub(crate) fn poll_oneoff( pub(crate) fn poll_oneoff(
timeout: Option<ClockEventData>, timeout: Option<ClockEventData>,
fd_events: Vec<FdEventData>, fd_events: Vec<FdEventData>,
events: &mut Vec<wasi::__wasi_event_t>, events: &mut Vec<wasi::__wasi_event_t>,
) -> Result<()> { ) -> WasiResult<()> {
use std::{convert::TryInto, os::unix::prelude::AsRawFd}; use std::{convert::TryInto, os::unix::prelude::AsRawFd};
use yanix::poll::{poll, PollFd, PollFlags}; use yanix::poll::{poll, PollFd, PollFlags};
@@ -122,12 +126,12 @@ fn poll_oneoff_handle_timeout_event(
fn poll_oneoff_handle_fd_event<'a>( fn poll_oneoff_handle_fd_event<'a>(
ready_events: impl Iterator<Item = (FdEventData<'a>, yanix::poll::PollFd)>, ready_events: impl Iterator<Item = (FdEventData<'a>, yanix::poll::PollFd)>,
events: &mut Vec<wasi::__wasi_event_t>, events: &mut Vec<wasi::__wasi_event_t>,
) -> Result<()> { ) -> WasiResult<()> {
use crate::fdentry::Descriptor; use crate::fdentry::Descriptor;
use std::{convert::TryInto, os::unix::prelude::AsRawFd}; use std::{convert::TryInto, os::unix::prelude::AsRawFd};
use yanix::{file::fionread, poll::PollFlags}; use yanix::{file::fionread, poll::PollFlags};
fn query_nbytes(fd: &Descriptor) -> Result<u64> { fn query_nbytes(fd: &Descriptor) -> WasiResult<u64> {
// fionread may overflow for large files, so use another way for regular files. // fionread may overflow for large files, so use another way for regular files.
if let Descriptor::OsHandle(os_handle) = fd { if let Descriptor::OsHandle(os_handle) = fd {
let meta = os_handle.metadata()?; let meta = os_handle.metadata()?;

View File

@@ -1,11 +1,11 @@
use crate::{wasi, Result}; use crate::wasi::{self, WasiResult};
pub(crate) const O_RSYNC: yanix::file::OFlag = yanix::file::OFlag::RSYNC; pub(crate) const O_RSYNC: yanix::file::OFlag = yanix::file::OFlag::RSYNC;
pub(crate) fn stdev_from_nix(dev: libc::dev_t) -> Result<wasi::__wasi_device_t> { pub(crate) fn stdev_from_nix(dev: libc::dev_t) -> WasiResult<wasi::__wasi_device_t> {
Ok(wasi::__wasi_device_t::from(dev)) Ok(wasi::__wasi_device_t::from(dev))
} }
pub(crate) fn stino_from_nix(ino: libc::ino_t) -> Result<wasi::__wasi_inode_t> { pub(crate) fn stino_from_nix(ino: libc::ino_t) -> WasiResult<wasi::__wasi_inode_t> {
Ok(wasi::__wasi_device_t::from(ino)) Ok(wasi::__wasi_device_t::from(ino))
} }

View File

@@ -1,9 +1,9 @@
use crate::fdentry::Descriptor; use crate::fdentry::Descriptor;
use crate::hostcalls_impl::PathGet; use crate::hostcalls_impl::PathGet;
use crate::Result; use crate::wasi::WasiResult;
use std::os::unix::prelude::AsRawFd; use std::os::unix::prelude::AsRawFd;
pub(crate) fn path_unlink_file(resolved: PathGet) -> Result<()> { pub(crate) fn path_unlink_file(resolved: PathGet) -> WasiResult<()> {
use yanix::file::{unlinkat, AtFlag}; use yanix::file::{unlinkat, AtFlag};
unsafe { unsafe {
unlinkat( unlinkat(
@@ -15,7 +15,7 @@ pub(crate) fn path_unlink_file(resolved: PathGet) -> Result<()> {
.map_err(Into::into) .map_err(Into::into)
} }
pub(crate) fn path_symlink(old_path: &str, resolved: PathGet) -> Result<()> { pub(crate) fn path_symlink(old_path: &str, resolved: PathGet) -> WasiResult<()> {
use yanix::file::symlinkat; use yanix::file::symlinkat;
log::debug!("path_symlink old_path = {:?}", old_path); log::debug!("path_symlink old_path = {:?}", old_path);
@@ -25,7 +25,7 @@ pub(crate) fn path_symlink(old_path: &str, resolved: PathGet) -> Result<()> {
.map_err(Into::into) .map_err(Into::into)
} }
pub(crate) fn path_rename(resolved_old: PathGet, resolved_new: PathGet) -> Result<()> { pub(crate) fn path_rename(resolved_old: PathGet, resolved_new: PathGet) -> WasiResult<()> {
use yanix::file::renameat; use yanix::file::renameat;
match (resolved_old.dirfd(), resolved_new.dirfd()) { match (resolved_old.dirfd(), resolved_new.dirfd()) {
(Descriptor::OsHandle(resolved_old_file), Descriptor::OsHandle(resolved_new_file)) => { (Descriptor::OsHandle(resolved_old_file), Descriptor::OsHandle(resolved_new_file)) => {
@@ -47,10 +47,10 @@ pub(crate) fn path_rename(resolved_old: PathGet, resolved_new: PathGet) -> Resul
pub(crate) mod fd_readdir_impl { pub(crate) mod fd_readdir_impl {
use crate::sys::fdentry_impl::OsHandle; use crate::sys::fdentry_impl::OsHandle;
use crate::Result; use crate::wasi::WasiResult;
use yanix::dir::Dir; use yanix::dir::Dir;
pub(crate) fn get_dir_from_os_handle(os_handle: &mut OsHandle) -> Result<Box<Dir>> { pub(crate) fn get_dir_from_os_handle(os_handle: &mut OsHandle) -> WasiResult<Box<Dir>> {
// We need to duplicate the fd, because `opendir(3)`: // We need to duplicate the fd, because `opendir(3)`:
// After a successful call to fdopendir(), fd is used internally by the implementation, // After a successful call to fdopendir(), fd is used internally by the implementation,
// and should not otherwise be used by the application. // and should not otherwise be used by the application.

View File

@@ -20,18 +20,14 @@ cfg_if::cfg_if! {
} }
} }
use crate::Result;
use std::fs::{File, OpenOptions}; use std::fs::{File, OpenOptions};
use std::io::Result;
use std::path::Path; use std::path::Path;
pub(crate) fn dev_null() -> Result<File> { pub(crate) fn dev_null() -> Result<File> {
OpenOptions::new() OpenOptions::new().read(true).write(true).open("/dev/null")
.read(true)
.write(true)
.open("/dev/null")
.map_err(Into::into)
} }
pub fn preopen_dir<P: AsRef<Path>>(path: P) -> Result<File> { pub fn preopen_dir<P: AsRef<Path>>(path: P) -> Result<File> {
File::open(path).map_err(Into::into) File::open(path)
} }

View File

@@ -1,5 +1,5 @@
use crate::fdentry::{Descriptor, OsHandleRef}; use crate::fdentry::{Descriptor, OsHandleRef};
use crate::{wasi, Error, Result}; use crate::wasi;
use std::fs::File; use std::fs::File;
use std::io; use std::io;
use std::mem::ManuallyDrop; use std::mem::ManuallyDrop;
@@ -63,7 +63,7 @@ pub(crate) fn descriptor_as_oshandle<'lifetime>(
/// This function is unsafe because it operates on a raw file descriptor. /// This function is unsafe because it operates on a raw file descriptor.
pub(crate) unsafe fn determine_type_and_access_rights<Handle: AsRawHandle>( pub(crate) unsafe fn determine_type_and_access_rights<Handle: AsRawHandle>(
handle: &Handle, handle: &Handle,
) -> Result<( ) -> io::Result<(
wasi::__wasi_filetype_t, wasi::__wasi_filetype_t,
wasi::__wasi_rights_t, wasi::__wasi_rights_t,
wasi::__wasi_rights_t, wasi::__wasi_rights_t,
@@ -96,7 +96,7 @@ pub(crate) unsafe fn determine_type_and_access_rights<Handle: AsRawHandle>(
/// This function is unsafe because it operates on a raw file descriptor. /// This function is unsafe because it operates on a raw file descriptor.
pub(crate) unsafe fn determine_type_rights<Handle: AsRawHandle>( pub(crate) unsafe fn determine_type_rights<Handle: AsRawHandle>(
handle: &Handle, handle: &Handle,
) -> Result<( ) -> io::Result<(
wasi::__wasi_filetype_t, wasi::__wasi_filetype_t,
wasi::__wasi_rights_t, wasi::__wasi_rights_t,
wasi::__wasi_rights_t, wasi::__wasi_rights_t,
@@ -114,7 +114,7 @@ pub(crate) unsafe fn determine_type_rights<Handle: AsRawHandle>(
} else if file_type.is_disk() { } else if file_type.is_disk() {
// disk file: file, dir or disk device // disk file: file, dir or disk device
let file = std::mem::ManuallyDrop::new(File::from_raw_handle(handle.as_raw_handle())); let file = std::mem::ManuallyDrop::new(File::from_raw_handle(handle.as_raw_handle()));
let meta = file.metadata().map_err(|_| Error::EINVAL)?; let meta = file.metadata()?;
if meta.is_dir() { if meta.is_dir() {
( (
wasi::__WASI_FILETYPE_DIRECTORY, wasi::__WASI_FILETYPE_DIRECTORY,
@@ -128,7 +128,7 @@ pub(crate) unsafe fn determine_type_rights<Handle: AsRawHandle>(
wasi::RIGHTS_REGULAR_FILE_INHERITING, wasi::RIGHTS_REGULAR_FILE_INHERITING,
) )
} else { } else {
return Err(Error::EINVAL); return Err(io::Error::from_raw_os_error(libc::EINVAL));
} }
} else if file_type.is_pipe() { } else if file_type.is_pipe() {
// pipe object: socket, named pipe or anonymous pipe // pipe object: socket, named pipe or anonymous pipe
@@ -139,7 +139,7 @@ pub(crate) unsafe fn determine_type_rights<Handle: AsRawHandle>(
wasi::RIGHTS_SOCKET_INHERITING, wasi::RIGHTS_SOCKET_INHERITING,
) )
} else { } else {
return Err(Error::EINVAL); return Err(io::Error::from_raw_os_error(libc::EINVAL));
} }
}; };
Ok((file_type, rights_base, rights_inheriting)) Ok((file_type, rights_base, rights_inheriting))

View File

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

View File

@@ -8,7 +8,7 @@ use crate::hostcalls_impl::{fd_filestat_set_times_impl, PathGet};
use crate::sys::fdentry_impl::{determine_type_rights, OsHandle}; use crate::sys::fdentry_impl::{determine_type_rights, OsHandle};
use crate::sys::host_impl::{self, path_from_host}; use crate::sys::host_impl::{self, path_from_host};
use crate::sys::hostcalls_impl::fs_helpers::PathGetExt; use crate::sys::hostcalls_impl::fs_helpers::PathGetExt;
use crate::{wasi, Error, Result}; use crate::wasi::{self, WasiError, WasiResult};
use log::{debug, trace}; use log::{debug, trace};
use std::convert::TryInto; use std::convert::TryInto;
use std::fs::{File, Metadata, OpenOptions}; use std::fs::{File, Metadata, OpenOptions};
@@ -44,16 +44,20 @@ pub(crate) fn fd_pread(
file: &File, file: &File,
buf: &mut [u8], buf: &mut [u8],
offset: wasi::__wasi_filesize_t, offset: wasi::__wasi_filesize_t,
) -> Result<usize> { ) -> WasiResult<usize> {
read_at(file, buf, offset).map_err(Into::into) read_at(file, buf, offset).map_err(Into::into)
} }
// TODO refactor common code with unix // TODO refactor common code with unix
pub(crate) fn fd_pwrite(file: &File, buf: &[u8], offset: wasi::__wasi_filesize_t) -> Result<usize> { pub(crate) fn fd_pwrite(
file: &File,
buf: &[u8],
offset: wasi::__wasi_filesize_t,
) -> WasiResult<usize> {
write_at(file, buf, offset).map_err(Into::into) write_at(file, buf, offset).map_err(Into::into)
} }
pub(crate) fn fd_fdstat_get(fd: &File) -> Result<wasi::__wasi_fdflags_t> { pub(crate) fn fd_fdstat_get(fd: &File) -> WasiResult<wasi::__wasi_fdflags_t> {
let mut fdflags = 0; let mut fdflags = 0;
let handle = unsafe { fd.as_raw_handle() }; let handle = unsafe { fd.as_raw_handle() };
@@ -82,7 +86,7 @@ pub(crate) fn fd_fdstat_get(fd: &File) -> Result<wasi::__wasi_fdflags_t> {
pub(crate) fn fd_fdstat_set_flags( pub(crate) fn fd_fdstat_set_flags(
fd: &File, fd: &File,
fdflags: wasi::__wasi_fdflags_t, fdflags: wasi::__wasi_fdflags_t,
) -> Result<Option<OsHandle>> { ) -> WasiResult<Option<OsHandle>> {
let handle = unsafe { fd.as_raw_handle() }; let handle = unsafe { fd.as_raw_handle() };
let access_mode = winx::file::query_access_information(handle)?; let access_mode = winx::file::query_access_information(handle)?;
@@ -106,7 +110,7 @@ pub(crate) fn fd_advise(
advice: wasi::__wasi_advice_t, advice: wasi::__wasi_advice_t,
_offset: wasi::__wasi_filesize_t, _offset: wasi::__wasi_filesize_t,
_len: wasi::__wasi_filesize_t, _len: wasi::__wasi_filesize_t,
) -> Result<()> { ) -> WasiResult<()> {
match advice { match advice {
wasi::__WASI_ADVICE_DONTNEED wasi::__WASI_ADVICE_DONTNEED
| wasi::__WASI_ADVICE_SEQUENTIAL | wasi::__WASI_ADVICE_SEQUENTIAL
@@ -114,18 +118,18 @@ pub(crate) fn fd_advise(
| wasi::__WASI_ADVICE_NOREUSE | wasi::__WASI_ADVICE_NOREUSE
| wasi::__WASI_ADVICE_RANDOM | wasi::__WASI_ADVICE_RANDOM
| wasi::__WASI_ADVICE_NORMAL => {} | wasi::__WASI_ADVICE_NORMAL => {}
_ => return Err(Error::EINVAL), _ => return Err(WasiError::EINVAL),
} }
Ok(()) Ok(())
} }
pub(crate) fn path_create_directory(file: &File, path: &str) -> Result<()> { pub(crate) fn path_create_directory(file: &File, path: &str) -> WasiResult<()> {
let path = concatenate(file, path)?; let path = concatenate(file, path)?;
std::fs::create_dir(&path).map_err(Into::into) std::fs::create_dir(&path).map_err(Into::into)
} }
pub(crate) fn path_link(resolved_old: PathGet, resolved_new: PathGet) -> Result<()> { pub(crate) fn path_link(resolved_old: PathGet, resolved_new: PathGet) -> WasiResult<()> {
unimplemented!("path_link") unimplemented!("path_link")
} }
@@ -135,7 +139,7 @@ pub(crate) fn path_open(
write: bool, write: bool,
oflags: wasi::__wasi_oflags_t, oflags: wasi::__wasi_oflags_t,
fdflags: wasi::__wasi_fdflags_t, fdflags: wasi::__wasi_fdflags_t,
) -> Result<Descriptor> { ) -> WasiResult<Descriptor> {
use winx::file::{AccessMode, CreationDisposition, Flags}; use winx::file::{AccessMode, CreationDisposition, Flags};
let is_trunc = oflags & wasi::__WASI_OFLAGS_TRUNC != 0; let is_trunc = oflags & wasi::__WASI_OFLAGS_TRUNC != 0;
@@ -145,7 +149,7 @@ pub(crate) fn path_open(
// This is because truncation requires `GENERIC_WRITE` access, which will override the removal // This is because truncation requires `GENERIC_WRITE` access, which will override the removal
// of the `FILE_WRITE_DATA` permission. // of the `FILE_WRITE_DATA` permission.
if fdflags & wasi::__WASI_FDFLAGS_APPEND != 0 { if fdflags & wasi::__WASI_FDFLAGS_APPEND != 0 {
return Err(Error::ENOTSUP); return Err(WasiError::ENOTSUP);
} }
} }
@@ -172,11 +176,11 @@ pub(crate) fn path_open(
Ok(file_type) => { Ok(file_type) => {
// check if we are trying to open a symlink // check if we are trying to open a symlink
if file_type.is_symlink() { if file_type.is_symlink() {
return Err(Error::ELOOP); return Err(WasiError::ELOOP);
} }
// check if we are trying to open a file as a dir // check if we are trying to open a file as a dir
if file_type.is_file() && oflags & wasi::__WASI_OFLAGS_DIRECTORY != 0 { if file_type.is_file() && oflags & wasi::__WASI_OFLAGS_DIRECTORY != 0 {
return Err(Error::ENOTDIR); return Err(WasiError::ENOTDIR);
} }
} }
Err(err) => match err.raw_os_error() { Err(err) => match err.raw_os_error() {
@@ -191,7 +195,7 @@ pub(crate) fn path_open(
} }
None => { None => {
log::debug!("Inconvertible OS error: {}", err); log::debug!("Inconvertible OS error: {}", err);
return Err(Error::EIO); return Err(WasiError::EIO);
} }
}, },
} }
@@ -276,7 +280,7 @@ fn dirent_from_path<P: AsRef<Path>>(
path: P, path: P,
name: &str, name: &str,
cookie: wasi::__wasi_dircookie_t, cookie: wasi::__wasi_dircookie_t,
) -> Result<Dirent> { ) -> WasiResult<Dirent> {
let path = path.as_ref(); let path = path.as_ref();
trace!("dirent_from_path: opening {}", path.to_string_lossy()); trace!("dirent_from_path: opening {}", path.to_string_lossy());
@@ -325,7 +329,7 @@ fn dirent_from_path<P: AsRef<Path>>(
pub(crate) fn fd_readdir( pub(crate) fn fd_readdir(
fd: &File, fd: &File,
cookie: wasi::__wasi_dircookie_t, cookie: wasi::__wasi_dircookie_t,
) -> Result<impl Iterator<Item = Result<Dirent>>> { ) -> WasiResult<impl Iterator<Item = WasiResult<Dirent>>> {
use winx::file::get_file_path; use winx::file::get_file_path;
let cookie = cookie.try_into()?; let cookie = cookie.try_into()?;
@@ -361,7 +365,7 @@ pub(crate) fn fd_readdir(
Ok(iter.skip(cookie)) Ok(iter.skip(cookie))
} }
pub(crate) fn path_readlink(resolved: PathGet, buf: &mut [u8]) -> Result<usize> { pub(crate) fn path_readlink(resolved: PathGet, buf: &mut [u8]) -> WasiResult<usize> {
use winx::file::get_file_path; use winx::file::get_file_path;
let path = resolved.concatenate()?; let path = resolved.concatenate()?;
@@ -375,8 +379,8 @@ pub(crate) fn path_readlink(resolved: PathGet, buf: &mut [u8]) -> Result<usize>
let dir_path = PathBuf::from(strip_extended_prefix(dir_path)); let dir_path = PathBuf::from(strip_extended_prefix(dir_path));
let target_path = target_path let target_path = target_path
.strip_prefix(dir_path) .strip_prefix(dir_path)
.map_err(|_| Error::ENOTCAPABLE) .map_err(|_| WasiError::ENOTCAPABLE)
.and_then(|path| path.to_str().map(String::from).ok_or(Error::EILSEQ))?; .and_then(|path| path.to_str().map(String::from).ok_or(WasiError::EILSEQ))?;
if buf.len() > 0 { if buf.len() > 0 {
let mut chars = target_path.chars(); let mut chars = target_path.chars();
@@ -398,7 +402,7 @@ pub(crate) fn path_readlink(resolved: PathGet, buf: &mut [u8]) -> Result<usize>
} }
} }
fn strip_trailing_slashes_and_concatenate(resolved: &PathGet) -> Result<Option<PathBuf>> { fn strip_trailing_slashes_and_concatenate(resolved: &PathGet) -> WasiResult<Option<PathBuf>> {
if resolved.path().ends_with('/') { if resolved.path().ends_with('/') {
let suffix = resolved.path().trim_end_matches('/'); let suffix = resolved.path().trim_end_matches('/');
concatenate(&resolved.dirfd().as_os_handle(), Path::new(suffix)).map(Some) concatenate(&resolved.dirfd().as_os_handle(), Path::new(suffix)).map(Some)
@@ -407,7 +411,7 @@ fn strip_trailing_slashes_and_concatenate(resolved: &PathGet) -> Result<Option<P
} }
} }
pub(crate) fn path_rename(resolved_old: PathGet, resolved_new: PathGet) -> Result<()> { pub(crate) fn path_rename(resolved_old: PathGet, resolved_new: PathGet) -> WasiResult<()> {
use std::fs; use std::fs;
let old_path = resolved_old.concatenate()?; let old_path = resolved_old.concatenate()?;
@@ -418,12 +422,12 @@ pub(crate) fn path_rename(resolved_old: PathGet, resolved_new: PathGet) -> Resul
// //
// [std::fs::rename]: https://doc.rust-lang.org/std/fs/fn.rename.html // [std::fs::rename]: https://doc.rust-lang.org/std/fs/fn.rename.html
if old_path.is_dir() && new_path.is_file() { if old_path.is_dir() && new_path.is_file() {
return Err(Error::ENOTDIR); return Err(WasiError::ENOTDIR);
} }
// Second sanity check: check we're not trying to rename a file into a path // Second sanity check: check we're not trying to rename a file into a path
// ending in a trailing slash. // ending in a trailing slash.
if old_path.is_file() && resolved_new.path().ends_with('/') { if old_path.is_file() && resolved_new.path().ends_with('/') {
return Err(Error::ENOTDIR); return Err(WasiError::ENOTDIR);
} }
// TODO handle symlinks // TODO handle symlinks
@@ -439,7 +443,7 @@ pub(crate) fn path_rename(resolved_old: PathGet, resolved_new: PathGet) -> Resul
// So most likely dealing with new_path == dir. // So most likely dealing with new_path == dir.
// Eliminate case old_path == file first. // Eliminate case old_path == file first.
if old_path.is_file() { if old_path.is_file() {
return Err(Error::EISDIR); return Err(WasiError::EISDIR);
} else { } else {
// Ok, let's try removing an empty dir at new_path if it exists // Ok, let's try removing an empty dir at new_path if it exists
// and is a nonempty dir. // and is a nonempty dir.
@@ -453,7 +457,7 @@ pub(crate) fn path_rename(resolved_old: PathGet, resolved_new: PathGet) -> Resul
// a file instead of a dir, and if so, throw ENOTDIR. // a file instead of a dir, and if so, throw ENOTDIR.
if let Some(path) = strip_trailing_slashes_and_concatenate(&resolved_old)? { if let Some(path) = strip_trailing_slashes_and_concatenate(&resolved_old)? {
if path.is_file() { if path.is_file() {
return Err(Error::ENOTDIR); return Err(WasiError::ENOTDIR);
} }
} }
} }
@@ -464,19 +468,19 @@ pub(crate) fn path_rename(resolved_old: PathGet, resolved_new: PathGet) -> Resul
} }
None => { None => {
log::debug!("Inconvertible OS error: {}", err); log::debug!("Inconvertible OS error: {}", err);
Err(Error::EIO) Err(WasiError::EIO)
} }
} }
} }
pub(crate) fn fd_filestat_get(file: &std::fs::File) -> Result<wasi::__wasi_filestat_t> { pub(crate) fn fd_filestat_get(file: &std::fs::File) -> WasiResult<wasi::__wasi_filestat_t> {
host_impl::filestat_from_win(file) host_impl::filestat_from_win(file)
} }
pub(crate) fn path_filestat_get( pub(crate) fn path_filestat_get(
resolved: PathGet, resolved: PathGet,
dirflags: wasi::__wasi_lookupflags_t, dirflags: wasi::__wasi_lookupflags_t,
) -> Result<wasi::__wasi_filestat_t> { ) -> WasiResult<wasi::__wasi_filestat_t> {
let path = resolved.concatenate()?; let path = resolved.concatenate()?;
let file = File::open(path)?; let file = File::open(path)?;
host_impl::filestat_from_win(&file) host_impl::filestat_from_win(&file)
@@ -488,7 +492,7 @@ pub(crate) fn path_filestat_set_times(
st_atim: wasi::__wasi_timestamp_t, st_atim: wasi::__wasi_timestamp_t,
mut st_mtim: wasi::__wasi_timestamp_t, mut st_mtim: wasi::__wasi_timestamp_t,
fst_flags: wasi::__wasi_fstflags_t, fst_flags: wasi::__wasi_fstflags_t,
) -> Result<()> { ) -> WasiResult<()> {
use winx::file::AccessMode; use winx::file::AccessMode;
let path = resolved.concatenate()?; let path = resolved.concatenate()?;
let file = OpenOptions::new() let file = OpenOptions::new()
@@ -498,7 +502,7 @@ pub(crate) fn path_filestat_set_times(
fd_filestat_set_times_impl(&modifiable_fd, st_atim, st_mtim, fst_flags) fd_filestat_set_times_impl(&modifiable_fd, st_atim, st_mtim, fst_flags)
} }
pub(crate) fn path_symlink(old_path: &str, resolved: PathGet) -> Result<()> { pub(crate) fn path_symlink(old_path: &str, resolved: PathGet) -> WasiResult<()> {
use std::os::windows::fs::{symlink_dir, symlink_file}; use std::os::windows::fs::{symlink_dir, symlink_file};
let old_path = concatenate(&resolved.dirfd().as_os_handle(), Path::new(old_path))?; let old_path = concatenate(&resolved.dirfd().as_os_handle(), Path::new(old_path))?;
@@ -520,14 +524,14 @@ pub(crate) fn path_symlink(old_path: &str, resolved: PathGet) -> Result<()> {
winerror::ERROR_ACCESS_DENIED => { winerror::ERROR_ACCESS_DENIED => {
// does the target exist? // does the target exist?
if new_path.exists() { if new_path.exists() {
return Err(Error::EEXIST); return Err(WasiError::EEXIST);
} }
} }
winerror::ERROR_INVALID_NAME => { winerror::ERROR_INVALID_NAME => {
// does the target without trailing slashes exist? // does the target without trailing slashes exist?
if let Some(path) = strip_trailing_slashes_and_concatenate(&resolved)? { if let Some(path) = strip_trailing_slashes_and_concatenate(&resolved)? {
if path.exists() { if path.exists() {
return Err(Error::EEXIST); return Err(WasiError::EEXIST);
} }
} }
} }
@@ -538,12 +542,12 @@ pub(crate) fn path_symlink(old_path: &str, resolved: PathGet) -> Result<()> {
} }
None => { None => {
log::debug!("Inconvertible OS error: {}", err); log::debug!("Inconvertible OS error: {}", err);
Err(Error::EIO) Err(WasiError::EIO)
} }
} }
} }
pub(crate) fn path_unlink_file(resolved: PathGet) -> Result<()> { pub(crate) fn path_unlink_file(resolved: PathGet) -> WasiResult<()> {
use std::fs; use std::fs;
let path = resolved.concatenate()?; let path = resolved.concatenate()?;
@@ -573,19 +577,19 @@ pub(crate) fn path_unlink_file(resolved: PathGet) -> Result<()> {
} }
None => { None => {
log::debug!("Inconvertible OS error: {}", err); log::debug!("Inconvertible OS error: {}", err);
Err(Error::EIO) Err(WasiError::EIO)
} }
} }
} else if file_type.is_dir() { } else if file_type.is_dir() {
Err(Error::EISDIR) Err(WasiError::EISDIR)
} else if file_type.is_file() { } else if file_type.is_file() {
fs::remove_file(path).map_err(Into::into) fs::remove_file(path).map_err(Into::into)
} else { } else {
Err(Error::EINVAL) Err(WasiError::EINVAL)
} }
} }
pub(crate) fn path_remove_directory(resolved: PathGet) -> Result<()> { pub(crate) fn path_remove_directory(resolved: PathGet) -> WasiResult<()> {
let path = resolved.concatenate()?; let path = resolved.concatenate()?;
std::fs::remove_dir(&path).map_err(Into::into) std::fs::remove_dir(&path).map_err(Into::into)
} }

View File

@@ -1,7 +1,7 @@
#![allow(non_camel_case_types)] #![allow(non_camel_case_types)]
use crate::fdentry::Descriptor; use crate::fdentry::Descriptor;
use crate::hostcalls_impl::PathGet; use crate::hostcalls_impl::PathGet;
use crate::{wasi, Error, Result}; use crate::wasi::{self, WasiError, WasiResult};
use std::ffi::{OsStr, OsString}; use std::ffi::{OsStr, OsString};
use std::fs::File; use std::fs::File;
use std::os::windows::ffi::{OsStrExt, OsStringExt}; use std::os::windows::ffi::{OsStrExt, OsStringExt};
@@ -9,11 +9,11 @@ use std::path::{Path, PathBuf};
use winapi::shared::winerror; use winapi::shared::winerror;
pub(crate) trait PathGetExt { pub(crate) trait PathGetExt {
fn concatenate(&self) -> Result<PathBuf>; fn concatenate(&self) -> WasiResult<PathBuf>;
} }
impl PathGetExt for PathGet { impl PathGetExt for PathGet {
fn concatenate(&self) -> Result<PathBuf> { fn concatenate(&self) -> WasiResult<PathBuf> {
match self.dirfd() { match self.dirfd() {
Descriptor::OsHandle(file) => concatenate(file, Path::new(self.path())), Descriptor::OsHandle(file) => concatenate(file, Path::new(self.path())),
Descriptor::VirtualFile(_virt) => { Descriptor::VirtualFile(_virt) => {
@@ -55,7 +55,7 @@ pub(crate) fn path_open_rights(
(needed_base, needed_inheriting) (needed_base, needed_inheriting)
} }
pub(crate) fn openat(dirfd: &File, path: &str) -> Result<File> { pub(crate) fn openat(dirfd: &File, path: &str) -> WasiResult<File> {
use std::fs::OpenOptions; use std::fs::OpenOptions;
use std::os::windows::fs::OpenOptionsExt; use std::os::windows::fs::OpenOptionsExt;
use winx::file::Flags; use winx::file::Flags;
@@ -72,13 +72,13 @@ pub(crate) fn openat(dirfd: &File, path: &str) -> Result<File> {
if let Some(code) = err.raw_os_error() { if let Some(code) = err.raw_os_error() {
log::debug!("openat error={:?}", code); log::debug!("openat error={:?}", code);
if code as u32 == winerror::ERROR_INVALID_NAME { if code as u32 == winerror::ERROR_INVALID_NAME {
return Err(Error::ENOTDIR); return Err(WasiError::ENOTDIR);
} }
} }
Err(err.into()) Err(err.into())
} }
pub(crate) fn readlinkat(dirfd: &File, s_path: &str) -> Result<String> { pub(crate) fn readlinkat(dirfd: &File, s_path: &str) -> WasiResult<String> {
use winx::file::get_file_path; use winx::file::get_file_path;
let path = concatenate(dirfd, Path::new(s_path))?; let path = concatenate(dirfd, Path::new(s_path))?;
@@ -92,8 +92,8 @@ pub(crate) fn readlinkat(dirfd: &File, s_path: &str) -> Result<String> {
let dir_path = PathBuf::from(strip_extended_prefix(dir_path)); let dir_path = PathBuf::from(strip_extended_prefix(dir_path));
let target_path = target_path let target_path = target_path
.strip_prefix(dir_path) .strip_prefix(dir_path)
.map_err(|_| Error::ENOTCAPABLE)?; .map_err(|_| WasiError::ENOTCAPABLE)?;
let target_path = target_path.to_str().ok_or(Error::EILSEQ)?; let target_path = target_path.to_str().ok_or(WasiError::EILSEQ)?;
return Ok(target_path.to_owned()); return Ok(target_path.to_owned());
} }
Err(e) => e, Err(e) => e,
@@ -105,7 +105,7 @@ pub(crate) fn readlinkat(dirfd: &File, s_path: &str) -> Result<String> {
// strip "/" and check if exists // strip "/" and check if exists
let path = concatenate(dirfd, Path::new(s_path.trim_end_matches('/')))?; let path = concatenate(dirfd, Path::new(s_path.trim_end_matches('/')))?;
if path.exists() && !path.is_dir() { if path.exists() && !path.is_dir() {
return Err(Error::ENOTDIR); return Err(WasiError::ENOTDIR);
} }
} }
} }
@@ -122,13 +122,13 @@ pub(crate) fn strip_extended_prefix<P: AsRef<OsStr>>(path: P) -> OsString {
} }
} }
pub(crate) fn concatenate<P: AsRef<Path>>(file: &File, path: P) -> Result<PathBuf> { pub(crate) fn concatenate<P: AsRef<Path>>(file: &File, path: P) -> WasiResult<PathBuf> {
use winx::file::get_file_path; use winx::file::get_file_path;
// WASI is not able to deal with absolute paths // WASI is not able to deal with absolute paths
// so error out if absolute // so error out if absolute
if path.as_ref().is_absolute() { if path.as_ref().is_absolute() {
return Err(Error::ENOTCAPABLE); return Err(WasiError::ENOTCAPABLE);
} }
let dir_path = get_file_path(file)?; let dir_path = get_file_path(file)?;

View File

@@ -5,7 +5,8 @@ use crate::fdentry::Descriptor;
use crate::hostcalls_impl::{ClockEventData, FdEventData}; use crate::hostcalls_impl::{ClockEventData, FdEventData};
use crate::memory::*; use crate::memory::*;
use crate::sys::host_impl; use crate::sys::host_impl;
use crate::{error::WasiError, wasi, wasi32, Error, Result}; use crate::wasi::{self, WasiError, WasiResult};
use crate::wasi32;
use cpu_time::{ProcessTime, ThreadTime}; use cpu_time::{ProcessTime, ThreadTime};
use lazy_static::lazy_static; use lazy_static::lazy_static;
use log::{debug, error, trace, warn}; use log::{debug, error, trace, warn};
@@ -24,9 +25,9 @@ struct StdinPoll {
enum PollState { enum PollState {
Ready, Ready,
NotReady, // it's not ready, but we didn't wait NotReady, // it's not ready, but we didn't wait
TimedOut, // it's not ready and a timeout has occurred TimedOut, // it's not ready and a timeout has occurred
Error(WasiError), // not using the top-lever Error because it's not Clone Error(WasiError),
} }
enum WaitMode { enum WaitMode {
@@ -82,7 +83,7 @@ impl StdinPoll {
// Linux returns `POLLIN` in both cases, and we imitate this behavior. // Linux returns `POLLIN` in both cases, and we imitate this behavior.
let resp = match std::io::stdin().lock().fill_buf() { let resp = match std::io::stdin().lock().fill_buf() {
Ok(_) => PollState::Ready, Ok(_) => PollState::Ready,
Err(e) => PollState::Error(Error::from(e).as_wasi_error()), Err(e) => PollState::Error(WasiError::from(e)),
}; };
// Notify the requestor about data in stdin. They may have already timed out, // Notify the requestor about data in stdin. They may have already timed out,
@@ -108,7 +109,9 @@ lazy_static! {
// Timer resolution on Windows is really hard. We may consider exposing the resolution of the respective // Timer resolution on Windows is really hard. We may consider exposing the resolution of the respective
// timers as an associated function in the future. // timers as an associated function in the future.
pub(crate) fn clock_res_get(clock_id: wasi::__wasi_clockid_t) -> Result<wasi::__wasi_timestamp_t> { pub(crate) fn clock_res_get(
clock_id: wasi::__wasi_clockid_t,
) -> WasiResult<wasi::__wasi_timestamp_t> {
Ok(match clock_id { Ok(match clock_id {
// This is the best that we can do with std::time::SystemTime. // This is the best that we can do with std::time::SystemTime.
// Rust uses GetSystemTimeAsFileTime, which is said to have the resolution of // Rust uses GetSystemTimeAsFileTime, which is said to have the resolution of
@@ -152,25 +155,28 @@ pub(crate) fn clock_res_get(clock_id: wasi::__wasi_clockid_t) -> Result<wasi::__
// The best we can do is to hardcode the value from the docs. // The best we can do is to hardcode the value from the docs.
// https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-getthreadtimes // https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-getthreadtimes
wasi::__WASI_CLOCKID_THREAD_CPUTIME_ID => 100, wasi::__WASI_CLOCKID_THREAD_CPUTIME_ID => 100,
_ => return Err(Error::EINVAL), _ => return Err(WasiError::EINVAL),
}) })
} }
pub(crate) fn clock_time_get(clock_id: wasi::__wasi_clockid_t) -> Result<wasi::__wasi_timestamp_t> { pub(crate) fn clock_time_get(
clock_id: wasi::__wasi_clockid_t,
) -> WasiResult<wasi::__wasi_timestamp_t> {
let duration = match clock_id { let duration = match clock_id {
wasi::__WASI_CLOCKID_REALTIME => get_monotonic_time(), wasi::__WASI_CLOCKID_REALTIME => get_monotonic_time(),
wasi::__WASI_CLOCKID_MONOTONIC => get_realtime_time()?, wasi::__WASI_CLOCKID_MONOTONIC => get_realtime_time()?,
wasi::__WASI_CLOCKID_PROCESS_CPUTIME_ID => get_proc_cputime()?, wasi::__WASI_CLOCKID_PROCESS_CPUTIME_ID => get_proc_cputime()?,
wasi::__WASI_CLOCKID_THREAD_CPUTIME_ID => get_thread_cputime()?, wasi::__WASI_CLOCKID_THREAD_CPUTIME_ID => get_thread_cputime()?,
_ => return Err(Error::EINVAL), _ => return Err(WasiError::EINVAL),
}; };
duration.as_nanos().try_into().map_err(Into::into) duration.as_nanos().try_into().map_err(Into::into)
} }
fn make_rw_event(event: &FdEventData, nbytes: Result<u64>) -> wasi::__wasi_event_t { fn make_rw_event(event: &FdEventData, nbytes: WasiResult<u64>) -> wasi::__wasi_event_t {
use crate::error::AsWasiError; let (nbytes, error) = match nbytes {
let error = nbytes.as_wasi_error(); Ok(nbytes) => (nbytes, WasiError::ESUCCESS),
let nbytes = nbytes.unwrap_or_default(); Err(e) => (u64::default(), e),
};
wasi::__wasi_event_t { wasi::__wasi_event_t {
userdata: event.userdata, userdata: event.userdata,
r#type: event.r#type, r#type: event.r#type,
@@ -233,7 +239,7 @@ fn handle_rw_event(event: FdEventData, out_events: &mut Vec<wasi::__wasi_event_t
fn handle_error_event( fn handle_error_event(
event: FdEventData, event: FdEventData,
error: Error, error: WasiError,
out_events: &mut Vec<wasi::__wasi_event_t>, out_events: &mut Vec<wasi::__wasi_event_t>,
) { ) {
let new_event = make_rw_event(&event, Err(error)); let new_event = make_rw_event(&event, Err(error));
@@ -244,7 +250,7 @@ pub(crate) fn poll_oneoff(
timeout: Option<ClockEventData>, timeout: Option<ClockEventData>,
fd_events: Vec<FdEventData>, fd_events: Vec<FdEventData>,
events: &mut Vec<wasi::__wasi_event_t>, events: &mut Vec<wasi::__wasi_event_t>,
) -> Result<()> { ) -> WasiResult<()> {
use std::fs::Metadata; use std::fs::Metadata;
use std::thread; use std::thread;
@@ -289,7 +295,7 @@ pub(crate) fn poll_oneoff(
let ftype = unsafe { winx::file::get_file_type(os_handle.as_raw_handle()) }?; let ftype = unsafe { winx::file::get_file_type(os_handle.as_raw_handle()) }?;
if ftype.is_unknown() || ftype.is_char() { if ftype.is_unknown() || ftype.is_char() {
debug!("poll_oneoff: unsupported file type: {:?}", ftype); debug!("poll_oneoff: unsupported file type: {:?}", ftype);
handle_error_event(event, Error::ENOTSUP, events); handle_error_event(event, WasiError::ENOTSUP, events);
} else if ftype.is_disk() { } else if ftype.is_disk() {
immediate_events.push(event); immediate_events.push(event);
} else if ftype.is_pipe() { } else if ftype.is_pipe() {
@@ -349,7 +355,7 @@ pub(crate) fn poll_oneoff(
PollState::Ready => handle_rw_event(event, events), PollState::Ready => handle_rw_event(event, events),
PollState::NotReady => {} // not immediately available, so just ignore PollState::NotReady => {} // not immediately available, so just ignore
PollState::TimedOut => handle_timeout_event(timeout.unwrap().0, events), PollState::TimedOut => handle_timeout_event(timeout.unwrap().0, events),
PollState::Error(e) => handle_error_event(event, Error::Wasi(e), events), PollState::Error(e) => handle_error_event(event, e, events),
} }
} }
} }
@@ -365,7 +371,7 @@ pub(crate) fn poll_oneoff(
} }
None => { None => {
error!("Polling only pipes with no timeout not supported on Windows."); error!("Polling only pipes with no timeout not supported on Windows.");
return Err(Error::ENOTSUP); return Err(WasiError::ENOTSUP);
} }
} }
} }
@@ -383,17 +389,17 @@ fn get_monotonic_time() -> Duration {
START_MONOTONIC.elapsed() START_MONOTONIC.elapsed()
} }
fn get_realtime_time() -> Result<Duration> { fn get_realtime_time() -> WasiResult<Duration> {
SystemTime::now() SystemTime::now()
.duration_since(UNIX_EPOCH) .duration_since(UNIX_EPOCH)
.map_err(|_| Error::EFAULT) .map_err(|_| WasiError::EFAULT)
} }
fn get_proc_cputime() -> Result<Duration> { fn get_proc_cputime() -> WasiResult<Duration> {
Ok(ProcessTime::try_now()?.as_duration()) Ok(ProcessTime::try_now()?.as_duration())
} }
fn get_thread_cputime() -> Result<Duration> { fn get_thread_cputime() -> WasiResult<Duration> {
Ok(ThreadTime::try_now()?.as_duration()) Ok(ThreadTime::try_now()?.as_duration())
} }

View File

@@ -2,16 +2,12 @@ pub(crate) mod fdentry_impl;
pub(crate) mod host_impl; pub(crate) mod host_impl;
pub(crate) mod hostcalls_impl; pub(crate) mod hostcalls_impl;
use crate::Result;
use std::fs::{File, OpenOptions}; use std::fs::{File, OpenOptions};
use std::io::Result;
use std::path::Path; use std::path::Path;
pub(crate) fn dev_null() -> Result<File> { pub(crate) fn dev_null() -> Result<File> {
OpenOptions::new() OpenOptions::new().read(true).write(true).open("NUL")
.read(true)
.write(true)
.open("NUL")
.map_err(Into::into)
} }
pub fn preopen_dir<P: AsRef<Path>>(path: P) -> Result<File> { pub fn preopen_dir<P: AsRef<Path>>(path: P) -> Result<File> {
@@ -28,5 +24,4 @@ pub fn preopen_dir<P: AsRef<Path>>(path: P) -> Result<File> {
.read(true) .read(true)
.attributes(FILE_FLAG_BACKUP_SEMANTICS) .attributes(FILE_FLAG_BACKUP_SEMANTICS)
.open(path) .open(path)
.map_err(Into::into)
} }

View File

@@ -1,6 +1,7 @@
use crate::host::Dirent; use crate::host::Dirent;
use crate::host::FileType; use crate::host::FileType;
use crate::{wasi, wasi32, Error, Result}; use crate::wasi::{self, WasiError, WasiResult};
use crate::wasi32;
use filetime::FileTime; use filetime::FileTime;
use log::trace; use log::trace;
use std::cell::RefCell; use std::cell::RefCell;
@@ -44,8 +45,8 @@ pub(crate) trait VirtualFile: MovableFile {
fn try_clone(&self) -> io::Result<Box<dyn VirtualFile>>; fn try_clone(&self) -> io::Result<Box<dyn VirtualFile>>;
fn readlinkat(&self, _path: &Path) -> Result<String> { fn readlinkat(&self, _path: &Path) -> WasiResult<String> {
Err(Error::EACCES) Err(WasiError::EACCES)
} }
fn openat( fn openat(
@@ -55,51 +56,51 @@ pub(crate) trait VirtualFile: MovableFile {
_write: bool, _write: bool,
_oflags: wasi::__wasi_oflags_t, _oflags: wasi::__wasi_oflags_t,
_fd_flags: wasi::__wasi_fdflags_t, _fd_flags: wasi::__wasi_fdflags_t,
) -> Result<Box<dyn VirtualFile>> { ) -> WasiResult<Box<dyn VirtualFile>> {
Err(Error::EACCES) Err(WasiError::EACCES)
} }
fn remove_directory(&self, _path: &str) -> Result<()> { fn remove_directory(&self, _path: &str) -> WasiResult<()> {
Err(Error::EACCES) Err(WasiError::EACCES)
} }
fn unlink_file(&self, _path: &str) -> Result<()> { fn unlink_file(&self, _path: &str) -> WasiResult<()> {
Err(Error::EACCES) Err(WasiError::EACCES)
} }
fn datasync(&self) -> Result<()> { fn datasync(&self) -> WasiResult<()> {
Err(Error::EINVAL) Err(WasiError::EINVAL)
} }
fn sync(&self) -> Result<()> { fn sync(&self) -> WasiResult<()> {
Ok(()) Ok(())
} }
fn create_directory(&self, _path: &Path) -> Result<()> { fn create_directory(&self, _path: &Path) -> WasiResult<()> {
Err(Error::EACCES) Err(WasiError::EACCES)
} }
fn readdir( fn readdir(
&self, &self,
_cookie: wasi::__wasi_dircookie_t, _cookie: wasi::__wasi_dircookie_t,
) -> Result<Box<dyn Iterator<Item = Result<Dirent>>>> { ) -> WasiResult<Box<dyn Iterator<Item = WasiResult<Dirent>>>> {
Err(Error::EBADF) Err(WasiError::EBADF)
} }
fn write_vectored(&mut self, _iovs: &[io::IoSlice]) -> Result<usize> { fn write_vectored(&mut self, _iovs: &[io::IoSlice]) -> WasiResult<usize> {
Err(Error::EBADF) Err(WasiError::EBADF)
} }
fn pread(&self, _buf: &mut [u8], _offset: u64) -> Result<usize> { fn pread(&self, _buf: &mut [u8], _offset: u64) -> WasiResult<usize> {
Err(Error::EBADF) Err(WasiError::EBADF)
} }
fn pwrite(&self, _buf: &mut [u8], _offset: u64) -> Result<usize> { fn pwrite(&self, _buf: &mut [u8], _offset: u64) -> WasiResult<usize> {
Err(Error::EBADF) Err(WasiError::EBADF)
} }
fn seek(&mut self, _offset: SeekFrom) -> Result<u64> { fn seek(&mut self, _offset: SeekFrom) -> WasiResult<u64> {
Err(Error::EBADF) Err(WasiError::EBADF)
} }
fn advise( fn advise(
@@ -107,36 +108,40 @@ pub(crate) trait VirtualFile: MovableFile {
_advice: wasi::__wasi_advice_t, _advice: wasi::__wasi_advice_t,
_offset: wasi::__wasi_filesize_t, _offset: wasi::__wasi_filesize_t,
_len: wasi::__wasi_filesize_t, _len: wasi::__wasi_filesize_t,
) -> Result<()> { ) -> WasiResult<()> {
Err(Error::EBADF) Err(WasiError::EBADF)
} }
fn allocate( fn allocate(
&self, &self,
_offset: wasi::__wasi_filesize_t, _offset: wasi::__wasi_filesize_t,
_len: wasi::__wasi_filesize_t, _len: wasi::__wasi_filesize_t,
) -> Result<()> { ) -> WasiResult<()> {
Err(Error::EBADF) Err(WasiError::EBADF)
} }
fn filestat_get(&self) -> Result<wasi::__wasi_filestat_t> { fn filestat_get(&self) -> WasiResult<wasi::__wasi_filestat_t> {
Err(Error::EBADF) Err(WasiError::EBADF)
} }
fn filestat_set_times(&self, _atim: Option<FileTime>, _mtim: Option<FileTime>) -> Result<()> { fn filestat_set_times(
Err(Error::EBADF) &self,
_atim: Option<FileTime>,
_mtim: Option<FileTime>,
) -> WasiResult<()> {
Err(WasiError::EBADF)
} }
fn filestat_set_size(&self, _st_size: wasi::__wasi_filesize_t) -> Result<()> { fn filestat_set_size(&self, _st_size: wasi::__wasi_filesize_t) -> WasiResult<()> {
Err(Error::EBADF) Err(WasiError::EBADF)
} }
fn fdstat_set_flags(&mut self, _fdflags: wasi::__wasi_fdflags_t) -> Result<()> { fn fdstat_set_flags(&mut self, _fdflags: wasi::__wasi_fdflags_t) -> WasiResult<()> {
Err(Error::EBADF) Err(WasiError::EBADF)
} }
fn read_vectored(&mut self, _iovs: &mut [io::IoSliceMut]) -> Result<usize> { fn read_vectored(&mut self, _iovs: &mut [io::IoSliceMut]) -> WasiResult<usize> {
Err(Error::EBADF) Err(WasiError::EBADF)
} }
fn get_file_type(&self) -> wasi::__wasi_filetype_t; fn get_file_type(&self) -> wasi::__wasi_filetype_t;
@@ -157,23 +162,30 @@ pub trait FileContents {
/// The current number of bytes this `FileContents` describes. /// The current number of bytes this `FileContents` describes.
fn size(&self) -> wasi::__wasi_filesize_t; fn size(&self) -> wasi::__wasi_filesize_t;
/// Resize to hold `new_size` number of bytes, or error if this is not possible. /// Resize to hold `new_size` number of bytes, or error if this is not possible.
fn resize(&mut self, new_size: wasi::__wasi_filesize_t) -> Result<()>; fn resize(&mut self, new_size: wasi::__wasi_filesize_t) -> WasiResult<()>;
/// Write a list of `IoSlice` starting at `offset`. `offset` plus the total size of all `iovs` /// Write a list of `IoSlice` starting at `offset`. `offset` plus the total size of all `iovs`
/// is guaranteed to not exceed `max_size`. Implementations must not indicate more bytes have /// is guaranteed to not exceed `max_size`. Implementations must not indicate more bytes have
/// been written than can be held by `iovs`. /// been written than can be held by `iovs`.
fn pwritev(&mut self, iovs: &[io::IoSlice], offset: wasi::__wasi_filesize_t) -> Result<usize>; fn pwritev(
&mut self,
iovs: &[io::IoSlice],
offset: wasi::__wasi_filesize_t,
) -> WasiResult<usize>;
/// Read from the file from `offset`, filling a list of `IoSlice`. The returend size must not /// Read from the file from `offset`, filling a list of `IoSlice`. The returend size must not
/// be more than the capactiy of `iovs`, and must not exceed the limit reported by /// be more than the capactiy of `iovs`, and must not exceed the limit reported by
/// `self.max_size()`. /// `self.max_size()`.
fn preadv(&self, iovs: &mut [io::IoSliceMut], offset: wasi::__wasi_filesize_t) fn preadv(
-> Result<usize>; &self,
iovs: &mut [io::IoSliceMut],
offset: wasi::__wasi_filesize_t,
) -> WasiResult<usize>;
/// Write contents from `buf` to this file starting at `offset`. `offset` plus the length of /// Write contents from `buf` to this file starting at `offset`. `offset` plus the length of
/// `buf` is guaranteed to not exceed `max_size`. Implementations must not indicate more bytes /// `buf` is guaranteed to not exceed `max_size`. Implementations must not indicate more bytes
/// have been written than the size of `buf`. /// have been written than the size of `buf`.
fn pwrite(&mut self, buf: &[u8], offset: wasi::__wasi_filesize_t) -> Result<usize>; fn pwrite(&mut self, buf: &[u8], offset: wasi::__wasi_filesize_t) -> WasiResult<usize>;
/// Read from the file at `offset`, filling `buf`. The returned size must not be more than the /// Read from the file at `offset`, filling `buf`. The returned size must not be more than the
/// capacity of `buf`, and `offset` plus the returned size must not exceed `self.max_size()`. /// capacity of `buf`, and `offset` plus the returned size must not exceed `self.max_size()`.
fn pread(&self, buf: &mut [u8], offset: wasi::__wasi_filesize_t) -> Result<usize>; fn pread(&self, buf: &mut [u8], offset: wasi::__wasi_filesize_t) -> WasiResult<usize>;
} }
impl FileContents for VecFileContents { impl FileContents for VecFileContents {
@@ -185,8 +197,8 @@ impl FileContents for VecFileContents {
self.content.len() as wasi::__wasi_filesize_t self.content.len() as wasi::__wasi_filesize_t
} }
fn resize(&mut self, new_size: wasi::__wasi_filesize_t) -> Result<()> { fn resize(&mut self, new_size: wasi::__wasi_filesize_t) -> WasiResult<()> {
let new_size: usize = new_size.try_into().map_err(|_| Error::EINVAL)?; let new_size: usize = new_size.try_into().map_err(|_| WasiError::EINVAL)?;
self.content.resize(new_size, 0); self.content.resize(new_size, 0);
Ok(()) Ok(())
} }
@@ -195,7 +207,7 @@ impl FileContents for VecFileContents {
&self, &self,
iovs: &mut [io::IoSliceMut], iovs: &mut [io::IoSliceMut],
offset: wasi::__wasi_filesize_t, offset: wasi::__wasi_filesize_t,
) -> Result<usize> { ) -> WasiResult<usize> {
let mut read_total = 0usize; let mut read_total = 0usize;
for iov in iovs.iter_mut() { for iov in iovs.iter_mut() {
let read = self.pread(iov, offset)?; let read = self.pread(iov, offset)?;
@@ -204,7 +216,11 @@ impl FileContents for VecFileContents {
Ok(read_total) Ok(read_total)
} }
fn pwritev(&mut self, iovs: &[io::IoSlice], offset: wasi::__wasi_filesize_t) -> Result<usize> { fn pwritev(
&mut self,
iovs: &[io::IoSlice],
offset: wasi::__wasi_filesize_t,
) -> WasiResult<usize> {
let mut write_total = 0usize; let mut write_total = 0usize;
for iov in iovs.iter() { for iov in iovs.iter() {
let written = self.pwrite(iov, offset)?; let written = self.pwrite(iov, offset)?;
@@ -213,9 +229,9 @@ impl FileContents for VecFileContents {
Ok(write_total) Ok(write_total)
} }
fn pread(&self, buf: &mut [u8], offset: wasi::__wasi_filesize_t) -> Result<usize> { fn pread(&self, buf: &mut [u8], offset: wasi::__wasi_filesize_t) -> WasiResult<usize> {
trace!(" | pread(buf.len={}, offset={})", buf.len(), offset); trace!(" | pread(buf.len={}, offset={})", buf.len(), offset);
let offset: usize = offset.try_into().map_err(|_| Error::EINVAL)?; let offset: usize = offset.try_into().map_err(|_| WasiError::EINVAL)?;
let data_remaining = self.content.len().saturating_sub(offset); let data_remaining = self.content.len().saturating_sub(offset);
@@ -228,10 +244,10 @@ impl FileContents for VecFileContents {
res res
} }
fn pwrite(&mut self, buf: &[u8], offset: wasi::__wasi_filesize_t) -> Result<usize> { fn pwrite(&mut self, buf: &[u8], offset: wasi::__wasi_filesize_t) -> WasiResult<usize> {
let offset: usize = offset.try_into().map_err(|_| Error::EINVAL)?; let offset: usize = offset.try_into().map_err(|_| WasiError::EINVAL)?;
let write_end = offset.checked_add(buf.len()).ok_or(Error::EFBIG)?; let write_end = offset.checked_add(buf.len()).ok_or(WasiError::EFBIG)?;
if write_end > self.content.len() { if write_end > self.content.len() {
self.content.resize(write_end, 0); self.content.resize(write_end, 0);
@@ -305,9 +321,9 @@ impl VirtualFile for InMemoryFile {
})) }))
} }
fn readlinkat(&self, _path: &Path) -> Result<String> { fn readlinkat(&self, _path: &Path) -> WasiResult<String> {
// no symlink support, so always say it's invalid. // no symlink support, so always say it's invalid.
Err(Error::ENOTDIR) Err(WasiError::ENOTDIR)
} }
fn openat( fn openat(
@@ -317,7 +333,7 @@ impl VirtualFile for InMemoryFile {
write: bool, write: bool,
oflags: wasi::__wasi_oflags_t, oflags: wasi::__wasi_oflags_t,
fd_flags: wasi::__wasi_fdflags_t, fd_flags: wasi::__wasi_fdflags_t,
) -> Result<Box<dyn VirtualFile>> { ) -> WasiResult<Box<dyn VirtualFile>> {
log::trace!( log::trace!(
"InMemoryFile::openat(path={:?}, read={:?}, write={:?}, oflags={:?}, fd_flags={:?}", "InMemoryFile::openat(path={:?}, read={:?}, write={:?}, oflags={:?}, fd_flags={:?}",
path, path,
@@ -333,7 +349,7 @@ impl VirtualFile for InMemoryFile {
path path
); );
log::trace!(" return ENOTDIR"); log::trace!(" return ENOTDIR");
return Err(Error::ENOTDIR); return Err(WasiError::ENOTDIR);
} }
if path == Path::new(".") { if path == Path::new(".") {
@@ -344,24 +360,24 @@ impl VirtualFile for InMemoryFile {
None => self.try_clone().map_err(Into::into), None => self.try_clone().map_err(Into::into),
} }
} else { } else {
Err(Error::EACCES) Err(WasiError::EACCES)
} }
} }
fn remove_directory(&self, _path: &str) -> Result<()> { fn remove_directory(&self, _path: &str) -> WasiResult<()> {
Err(Error::ENOTDIR) Err(WasiError::ENOTDIR)
} }
fn unlink_file(&self, _path: &str) -> Result<()> { fn unlink_file(&self, _path: &str) -> WasiResult<()> {
Err(Error::ENOTDIR) Err(WasiError::ENOTDIR)
} }
fn fdstat_set_flags(&mut self, fdflags: wasi::__wasi_fdflags_t) -> Result<()> { fn fdstat_set_flags(&mut self, fdflags: wasi::__wasi_fdflags_t) -> WasiResult<()> {
self.fd_flags = fdflags; self.fd_flags = fdflags;
Ok(()) Ok(())
} }
fn write_vectored(&mut self, iovs: &[io::IoSlice]) -> Result<usize> { fn write_vectored(&mut self, iovs: &[io::IoSlice]) -> WasiResult<usize> {
trace!("write_vectored(iovs={:?})", iovs); trace!("write_vectored(iovs={:?})", iovs);
let mut data = self.data.borrow_mut(); let mut data = self.data.borrow_mut();
@@ -389,10 +405,10 @@ impl VirtualFile for InMemoryFile {
if let Some(end) = write_start.checked_add(max_size as wasi::__wasi_filesize_t) { if let Some(end) = write_start.checked_add(max_size as wasi::__wasi_filesize_t) {
if end > data.max_size() { if end > data.max_size() {
return Err(Error::EFBIG); return Err(WasiError::EFBIG);
} }
} else { } else {
return Err(Error::EFBIG); return Err(WasiError::EFBIG);
} }
trace!(" | *write_start={:?}", write_start); trace!(" | *write_start={:?}", write_start);
@@ -407,43 +423,43 @@ impl VirtualFile for InMemoryFile {
Ok(written) Ok(written)
} }
fn read_vectored(&mut self, iovs: &mut [io::IoSliceMut]) -> Result<usize> { fn read_vectored(&mut self, iovs: &mut [io::IoSliceMut]) -> WasiResult<usize> {
trace!("read_vectored(iovs={:?})", iovs); trace!("read_vectored(iovs={:?})", iovs);
trace!(" | *read_start={:?}", self.cursor); trace!(" | *read_start={:?}", self.cursor);
self.data.borrow_mut().preadv(iovs, self.cursor) self.data.borrow_mut().preadv(iovs, self.cursor)
} }
fn pread(&self, buf: &mut [u8], offset: wasi::__wasi_filesize_t) -> Result<usize> { fn pread(&self, buf: &mut [u8], offset: wasi::__wasi_filesize_t) -> WasiResult<usize> {
self.data.borrow_mut().pread(buf, offset) self.data.borrow_mut().pread(buf, offset)
} }
fn pwrite(&self, buf: &mut [u8], offset: wasi::__wasi_filesize_t) -> Result<usize> { fn pwrite(&self, buf: &mut [u8], offset: wasi::__wasi_filesize_t) -> WasiResult<usize> {
self.data.borrow_mut().pwrite(buf, offset) self.data.borrow_mut().pwrite(buf, offset)
} }
fn seek(&mut self, offset: SeekFrom) -> Result<wasi::__wasi_filesize_t> { fn seek(&mut self, offset: SeekFrom) -> WasiResult<wasi::__wasi_filesize_t> {
let content_len = self.data.borrow().size(); let content_len = self.data.borrow().size();
match offset { match offset {
SeekFrom::Current(offset) => { SeekFrom::Current(offset) => {
let new_cursor = if offset < 0 { let new_cursor = if offset < 0 {
self.cursor self.cursor
.checked_sub(offset.wrapping_neg() as u64) .checked_sub(offset.wrapping_neg() as u64)
.ok_or(Error::EINVAL)? .ok_or(WasiError::EINVAL)?
} else { } else {
self.cursor self.cursor
.checked_add(offset as u64) .checked_add(offset as u64)
.ok_or(Error::EINVAL)? .ok_or(WasiError::EINVAL)?
}; };
self.cursor = std::cmp::min(content_len, new_cursor); self.cursor = std::cmp::min(content_len, new_cursor);
} }
SeekFrom::End(offset) => { SeekFrom::End(offset) => {
// A negative offset from the end would be past the end of the file, // A negative offset from the end would be past the end of the file,
let offset: u64 = offset.try_into().map_err(|_| Error::EINVAL)?; let offset: u64 = offset.try_into().map_err(|_| WasiError::EINVAL)?;
self.cursor = content_len.saturating_sub(offset); self.cursor = content_len.saturating_sub(offset);
} }
SeekFrom::Start(offset) => { SeekFrom::Start(offset) => {
// A negative offset from the end would be before the start of the file. // A negative offset from the end would be before the start of the file.
let offset: u64 = offset.try_into().map_err(|_| Error::EINVAL)?; let offset: u64 = offset.try_into().map_err(|_| WasiError::EINVAL)?;
self.cursor = std::cmp::min(content_len, offset); self.cursor = std::cmp::min(content_len, offset);
} }
} }
@@ -456,7 +472,7 @@ impl VirtualFile for InMemoryFile {
advice: wasi::__wasi_advice_t, advice: wasi::__wasi_advice_t,
_offset: wasi::__wasi_filesize_t, _offset: wasi::__wasi_filesize_t,
_len: wasi::__wasi_filesize_t, _len: wasi::__wasi_filesize_t,
) -> Result<()> { ) -> WasiResult<()> {
// we'll just ignore advice for now, unless it's totally invalid // we'll just ignore advice for now, unless it's totally invalid
match advice { match advice {
wasi::__WASI_ADVICE_DONTNEED wasi::__WASI_ADVICE_DONTNEED
@@ -465,7 +481,7 @@ impl VirtualFile for InMemoryFile {
| wasi::__WASI_ADVICE_NOREUSE | wasi::__WASI_ADVICE_NOREUSE
| wasi::__WASI_ADVICE_RANDOM | wasi::__WASI_ADVICE_RANDOM
| wasi::__WASI_ADVICE_NORMAL => Ok(()), | wasi::__WASI_ADVICE_NORMAL => Ok(()),
_ => Err(Error::EINVAL), _ => Err(WasiError::EINVAL),
} }
} }
@@ -473,12 +489,12 @@ impl VirtualFile for InMemoryFile {
&self, &self,
offset: wasi::__wasi_filesize_t, offset: wasi::__wasi_filesize_t,
len: wasi::__wasi_filesize_t, len: wasi::__wasi_filesize_t,
) -> Result<()> { ) -> WasiResult<()> {
let new_limit = offset.checked_add(len).ok_or(Error::EFBIG)?; let new_limit = offset.checked_add(len).ok_or(WasiError::EFBIG)?;
let mut data = self.data.borrow_mut(); let mut data = self.data.borrow_mut();
if new_limit > data.max_size() { if new_limit > data.max_size() {
return Err(Error::EFBIG); return Err(WasiError::EFBIG);
} }
if new_limit > data.size() { if new_limit > data.size() {
@@ -488,15 +504,15 @@ impl VirtualFile for InMemoryFile {
Ok(()) Ok(())
} }
fn filestat_set_size(&self, st_size: wasi::__wasi_filesize_t) -> Result<()> { fn filestat_set_size(&self, st_size: wasi::__wasi_filesize_t) -> WasiResult<()> {
let mut data = self.data.borrow_mut(); let mut data = self.data.borrow_mut();
if st_size > data.max_size() { if st_size > data.max_size() {
return Err(Error::EFBIG); return Err(WasiError::EFBIG);
} }
data.resize(st_size) data.resize(st_size)
} }
fn filestat_get(&self) -> Result<wasi::__wasi_filestat_t> { fn filestat_get(&self) -> WasiResult<wasi::__wasi_filestat_t> {
let stat = wasi::__wasi_filestat_t { let stat = wasi::__wasi_filestat_t {
dev: 0, dev: 0,
ino: 0, ino: 0,
@@ -594,9 +610,9 @@ impl VirtualFile for VirtualDir {
})) }))
} }
fn readlinkat(&self, _path: &Path) -> Result<String> { fn readlinkat(&self, _path: &Path) -> WasiResult<String> {
// Files are not symbolic links or directories, faithfully report ENOTDIR. // Files are not symbolic links or directories, faithfully report ENOTDIR.
Err(Error::ENOTDIR) Err(WasiError::ENOTDIR)
} }
fn openat( fn openat(
@@ -606,7 +622,7 @@ impl VirtualFile for VirtualDir {
write: bool, write: bool,
oflags: wasi::__wasi_oflags_t, oflags: wasi::__wasi_oflags_t,
fd_flags: wasi::__wasi_fdflags_t, fd_flags: wasi::__wasi_fdflags_t,
) -> Result<Box<dyn VirtualFile>> { ) -> WasiResult<Box<dyn VirtualFile>> {
log::trace!( log::trace!(
"VirtualDir::openat(path={:?}, read={:?}, write={:?}, oflags={:?}, fd_flags={:?}", "VirtualDir::openat(path={:?}, read={:?}, write={:?}, oflags={:?}, fd_flags={:?}",
path, path,
@@ -631,7 +647,7 @@ impl VirtualFile for VirtualDir {
// openat may have been passed a path with a trailing slash, but files are mapped to paths // openat may have been passed a path with a trailing slash, but files are mapped to paths
// with trailing slashes normalized out. // with trailing slashes normalized out.
let file_name = path.file_name().ok_or(Error::EINVAL)?; let file_name = path.file_name().ok_or(WasiError::EINVAL)?;
let mut entries = self.entries.borrow_mut(); let mut entries = self.entries.borrow_mut();
let entry_count = entries.len(); let entry_count = entries.len();
match entries.entry(Path::new(file_name).to_path_buf()) { match entries.entry(Path::new(file_name).to_path_buf()) {
@@ -640,7 +656,7 @@ impl VirtualFile for VirtualDir {
if (oflags & creat_excl_mask) == creat_excl_mask { if (oflags & creat_excl_mask) == creat_excl_mask {
log::trace!("VirtualDir::openat was passed oflags CREAT|EXCL, but the file {:?} exists.", file_name); log::trace!("VirtualDir::openat was passed oflags CREAT|EXCL, but the file {:?} exists.", file_name);
log::trace!(" return EEXIST"); log::trace!(" return EEXIST");
return Err(Error::EEXIST); return Err(WasiError::EEXIST);
} }
if (oflags & wasi::__WASI_OFLAGS_DIRECTORY) != 0 if (oflags & wasi::__WASI_OFLAGS_DIRECTORY) != 0
@@ -651,7 +667,7 @@ impl VirtualFile for VirtualDir {
file_name file_name
); );
log::trace!(" return ENOTDIR"); log::trace!(" return ENOTDIR");
return Err(Error::ENOTDIR); return Err(WasiError::ENOTDIR);
} }
e.get().try_clone().map_err(Into::into) e.get().try_clone().map_err(Into::into)
@@ -663,7 +679,7 @@ impl VirtualFile for VirtualDir {
// would have with `usize`. The limit is the full `u32` range minus two so we // would have with `usize`. The limit is the full `u32` range minus two so we
// can reserve "self" and "parent" cookie values. // can reserve "self" and "parent" cookie values.
if entry_count >= (std::u32::MAX - RESERVED_ENTRY_COUNT) as usize { if entry_count >= (std::u32::MAX - RESERVED_ENTRY_COUNT) as usize {
return Err(Error::ENOSPC); return Err(WasiError::ENOSPC);
} }
log::trace!( log::trace!(
@@ -676,26 +692,26 @@ impl VirtualFile for VirtualDir {
file.set_parent(Some(self.try_clone().expect("can clone self"))); file.set_parent(Some(self.try_clone().expect("can clone self")));
v.insert(file).try_clone().map_err(Into::into) v.insert(file).try_clone().map_err(Into::into)
} else { } else {
Err(Error::EACCES) Err(WasiError::EACCES)
} }
} }
} }
} }
fn remove_directory(&self, path: &str) -> Result<()> { fn remove_directory(&self, path: &str) -> WasiResult<()> {
let trimmed_path = path.trim_end_matches('/'); let trimmed_path = path.trim_end_matches('/');
let mut entries = self.entries.borrow_mut(); let mut entries = self.entries.borrow_mut();
match entries.entry(Path::new(trimmed_path).to_path_buf()) { match entries.entry(Path::new(trimmed_path).to_path_buf()) {
Entry::Occupied(e) => { Entry::Occupied(e) => {
// first, does this name a directory? // first, does this name a directory?
if e.get().get_file_type() != wasi::__WASI_FILETYPE_DIRECTORY { if e.get().get_file_type() != wasi::__WASI_FILETYPE_DIRECTORY {
return Err(Error::ENOTDIR); return Err(WasiError::ENOTDIR);
} }
// Okay, but is the directory empty? // Okay, but is the directory empty?
let iter = e.get().readdir(wasi::__WASI_DIRCOOKIE_START)?; let iter = e.get().readdir(wasi::__WASI_DIRCOOKIE_START)?;
if iter.skip(RESERVED_ENTRY_COUNT as usize).next().is_some() { if iter.skip(RESERVED_ENTRY_COUNT as usize).next().is_some() {
return Err(Error::ENOTEMPTY); return Err(WasiError::ENOTEMPTY);
} }
// Alright, it's an empty directory. We can remove it. // Alright, it's an empty directory. We can remove it.
@@ -711,19 +727,19 @@ impl VirtualFile for VirtualDir {
"VirtualDir::remove_directory failed to remove {}, no such entry", "VirtualDir::remove_directory failed to remove {}, no such entry",
trimmed_path trimmed_path
); );
Err(Error::ENOENT) Err(WasiError::ENOENT)
} }
} }
} }
fn unlink_file(&self, path: &str) -> Result<()> { fn unlink_file(&self, path: &str) -> WasiResult<()> {
let trimmed_path = path.trim_end_matches('/'); let trimmed_path = path.trim_end_matches('/');
// Special case: we may be unlinking this directory itself if path is `"."`. In that case, // Special case: we may be unlinking this directory itself if path is `"."`. In that case,
// fail with EISDIR, since this is a directory. Alternatively, we may be unlinking `".."`, // fail with EISDIR, 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. // which is bound the same way, as this is by definition contained in a directory.
if trimmed_path == "." || trimmed_path == ".." { if trimmed_path == "." || trimmed_path == ".." {
return Err(Error::EISDIR); return Err(WasiError::EISDIR);
} }
let mut entries = self.entries.borrow_mut(); let mut entries = self.entries.borrow_mut();
@@ -731,7 +747,7 @@ impl VirtualFile for VirtualDir {
Entry::Occupied(e) => { Entry::Occupied(e) => {
// Directories must be removed through `remove_directory`, not `unlink_file`. // Directories must be removed through `remove_directory`, not `unlink_file`.
if e.get().get_file_type() == wasi::__WASI_FILETYPE_DIRECTORY { if e.get().get_file_type() == wasi::__WASI_FILETYPE_DIRECTORY {
return Err(Error::EISDIR); return Err(WasiError::EISDIR);
} }
let removed = e.remove_entry(); let removed = e.remove_entry();
@@ -746,15 +762,15 @@ impl VirtualFile for VirtualDir {
"VirtualDir::unlink_file failed to remove {}, no such entry", "VirtualDir::unlink_file failed to remove {}, no such entry",
trimmed_path trimmed_path
); );
Err(Error::ENOENT) Err(WasiError::ENOENT)
} }
} }
} }
fn create_directory(&self, path: &Path) -> Result<()> { fn create_directory(&self, path: &Path) -> WasiResult<()> {
let mut entries = self.entries.borrow_mut(); let mut entries = self.entries.borrow_mut();
match entries.entry(path.to_owned()) { match entries.entry(path.to_owned()) {
Entry::Occupied(_) => Err(Error::EEXIST), Entry::Occupied(_) => Err(WasiError::EEXIST),
Entry::Vacant(v) => { Entry::Vacant(v) => {
if self.writable { if self.writable {
let new_dir = Box::new(VirtualDir::new(true)); let new_dir = Box::new(VirtualDir::new(true));
@@ -762,26 +778,26 @@ impl VirtualFile for VirtualDir {
v.insert(new_dir); v.insert(new_dir);
Ok(()) Ok(())
} else { } else {
Err(Error::EACCES) Err(WasiError::EACCES)
} }
} }
} }
} }
fn write_vectored(&mut self, _iovs: &[io::IoSlice]) -> Result<usize> { fn write_vectored(&mut self, _iovs: &[io::IoSlice]) -> WasiResult<usize> {
Err(Error::EBADF) Err(WasiError::EBADF)
} }
fn readdir( fn readdir(
&self, &self,
cookie: wasi::__wasi_dircookie_t, cookie: wasi::__wasi_dircookie_t,
) -> Result<Box<dyn Iterator<Item = Result<Dirent>>>> { ) -> WasiResult<Box<dyn Iterator<Item = WasiResult<Dirent>>>> {
struct VirtualDirIter { struct VirtualDirIter {
start: u32, start: u32,
entries: Rc<RefCell<HashMap<PathBuf, Box<dyn VirtualFile>>>>, entries: Rc<RefCell<HashMap<PathBuf, Box<dyn VirtualFile>>>>,
} }
impl Iterator for VirtualDirIter { impl Iterator for VirtualDirIter {
type Item = Result<Dirent>; type Item = WasiResult<Dirent>;
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
log::trace!("VirtualDirIter::next continuing from {}", self.start); log::trace!("VirtualDirIter::next continuing from {}", self.start);
@@ -850,7 +866,7 @@ impl VirtualFile for VirtualDir {
})) }))
} }
fn filestat_get(&self) -> Result<wasi::__wasi_filestat_t> { fn filestat_get(&self) -> WasiResult<wasi::__wasi_filestat_t> {
let stat = wasi::__wasi_filestat_t { let stat = wasi::__wasi_filestat_t {
dev: 0, dev: 0,
ino: 0, ino: 0,

View File

@@ -10,6 +10,115 @@ use wig::witx_wasi_types;
witx_wasi_types!("snapshot" "wasi_snapshot_preview1"); witx_wasi_types!("snapshot" "wasi_snapshot_preview1");
pub type WasiResult<T> = Result<T, WasiError>;
#[derive(Clone, Copy, Debug, thiserror::Error, Eq, PartialEq)]
#[repr(u16)]
#[error("{:?} ({})", self, strerror(*self as __wasi_errno_t))]
pub enum WasiError {
ESUCCESS = __WASI_ERRNO_SUCCESS,
E2BIG = __WASI_ERRNO_2BIG,
EACCES = __WASI_ERRNO_ACCES,
EADDRINUSE = __WASI_ERRNO_ADDRINUSE,
EADDRNOTAVAIL = __WASI_ERRNO_ADDRNOTAVAIL,
EAFNOSUPPORT = __WASI_ERRNO_AFNOSUPPORT,
EAGAIN = __WASI_ERRNO_AGAIN,
EALREADY = __WASI_ERRNO_ALREADY,
EBADF = __WASI_ERRNO_BADF,
EBADMSG = __WASI_ERRNO_BADMSG,
EBUSY = __WASI_ERRNO_BUSY,
ECANCELED = __WASI_ERRNO_CANCELED,
ECHILD = __WASI_ERRNO_CHILD,
ECONNABORTED = __WASI_ERRNO_CONNABORTED,
ECONNREFUSED = __WASI_ERRNO_CONNREFUSED,
ECONNRESET = __WASI_ERRNO_CONNRESET,
EDEADLK = __WASI_ERRNO_DEADLK,
EDESTADDRREQ = __WASI_ERRNO_DESTADDRREQ,
EDOM = __WASI_ERRNO_DOM,
EDQUOT = __WASI_ERRNO_DQUOT,
EEXIST = __WASI_ERRNO_EXIST,
EFAULT = __WASI_ERRNO_FAULT,
EFBIG = __WASI_ERRNO_FBIG,
EHOSTUNREACH = __WASI_ERRNO_HOSTUNREACH,
EIDRM = __WASI_ERRNO_IDRM,
EILSEQ = __WASI_ERRNO_ILSEQ,
EINPROGRESS = __WASI_ERRNO_INPROGRESS,
EINTR = __WASI_ERRNO_INTR,
EINVAL = __WASI_ERRNO_INVAL,
EIO = __WASI_ERRNO_IO,
EISCONN = __WASI_ERRNO_ISCONN,
EISDIR = __WASI_ERRNO_ISDIR,
ELOOP = __WASI_ERRNO_LOOP,
EMFILE = __WASI_ERRNO_MFILE,
EMLINK = __WASI_ERRNO_MLINK,
EMSGSIZE = __WASI_ERRNO_MSGSIZE,
EMULTIHOP = __WASI_ERRNO_MULTIHOP,
ENAMETOOLONG = __WASI_ERRNO_NAMETOOLONG,
ENETDOWN = __WASI_ERRNO_NETDOWN,
ENETRESET = __WASI_ERRNO_NETRESET,
ENETUNREACH = __WASI_ERRNO_NETUNREACH,
ENFILE = __WASI_ERRNO_NFILE,
ENOBUFS = __WASI_ERRNO_NOBUFS,
ENODEV = __WASI_ERRNO_NODEV,
ENOENT = __WASI_ERRNO_NOENT,
ENOEXEC = __WASI_ERRNO_NOEXEC,
ENOLCK = __WASI_ERRNO_NOLCK,
ENOLINK = __WASI_ERRNO_NOLINK,
ENOMEM = __WASI_ERRNO_NOMEM,
ENOMSG = __WASI_ERRNO_NOMSG,
ENOPROTOOPT = __WASI_ERRNO_NOPROTOOPT,
ENOSPC = __WASI_ERRNO_NOSPC,
ENOSYS = __WASI_ERRNO_NOSYS,
ENOTCONN = __WASI_ERRNO_NOTCONN,
ENOTDIR = __WASI_ERRNO_NOTDIR,
ENOTEMPTY = __WASI_ERRNO_NOTEMPTY,
ENOTRECOVERABLE = __WASI_ERRNO_NOTRECOVERABLE,
ENOTSOCK = __WASI_ERRNO_NOTSOCK,
ENOTSUP = __WASI_ERRNO_NOTSUP,
ENOTTY = __WASI_ERRNO_NOTTY,
ENXIO = __WASI_ERRNO_NXIO,
EOVERFLOW = __WASI_ERRNO_OVERFLOW,
EOWNERDEAD = __WASI_ERRNO_OWNERDEAD,
EPERM = __WASI_ERRNO_PERM,
EPIPE = __WASI_ERRNO_PIPE,
EPROTO = __WASI_ERRNO_PROTO,
EPROTONOSUPPORT = __WASI_ERRNO_PROTONOSUPPORT,
EPROTOTYPE = __WASI_ERRNO_PROTOTYPE,
ERANGE = __WASI_ERRNO_RANGE,
EROFS = __WASI_ERRNO_ROFS,
ESPIPE = __WASI_ERRNO_SPIPE,
ESRCH = __WASI_ERRNO_SRCH,
ESTALE = __WASI_ERRNO_STALE,
ETIMEDOUT = __WASI_ERRNO_TIMEDOUT,
ETXTBSY = __WASI_ERRNO_TXTBSY,
EXDEV = __WASI_ERRNO_XDEV,
ENOTCAPABLE = __WASI_ERRNO_NOTCAPABLE,
}
impl WasiError {
pub fn as_raw_errno(self) -> __wasi_errno_t {
self as __wasi_errno_t
}
}
impl From<std::convert::Infallible> for WasiError {
fn from(_err: std::convert::Infallible) -> Self {
unreachable!()
}
}
impl From<std::num::TryFromIntError> for WasiError {
fn from(_err: std::num::TryFromIntError) -> Self {
Self::EOVERFLOW
}
}
impl From<std::str::Utf8Error> for WasiError {
fn from(_err: std::str::Utf8Error) -> Self {
Self::EILSEQ
}
}
pub(crate) const RIGHTS_ALL: __wasi_rights_t = __WASI_RIGHTS_FD_DATASYNC pub(crate) const RIGHTS_ALL: __wasi_rights_t = __WASI_RIGHTS_FD_DATASYNC
| __WASI_RIGHTS_FD_READ | __WASI_RIGHTS_FD_READ
| __WASI_RIGHTS_FD_SEEK | __WASI_RIGHTS_FD_SEEK

View File

@@ -92,8 +92,7 @@ fn generate_wrappers(func: &witx::InterfaceFunc, old: bool) -> TokenStream {
quote! { quote! {
let ret = #call let ret = #call
.err() .err()
.unwrap_or(super::Error::ESUCCESS) .unwrap_or(super::wasi::WasiError::ESUCCESS);
.as_wasi_error();
log::trace!(" | errno={}", ret); log::trace!(" | errno={}", ret);
ret.as_raw_errno() ret.as_raw_errno()
} }