[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,12 +1,12 @@
use crate::{wasi, Result};
use crate::wasi::{self, WasiResult};
use std::convert::TryFrom;
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)
}
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)
}

View File

@@ -1,8 +1,8 @@
use crate::hostcalls_impl::PathGet;
use crate::{Error, Result};
use crate::wasi::{WasiError, WasiResult};
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};
match unsafe {
unlinkat(
@@ -32,7 +32,7 @@ pub(crate) fn path_unlink_file(resolved: PathGet) -> Result<()> {
} {
Ok(stat) => {
if FileType::from_stat_st_mode(stat.st_mode) == FileType::Directory {
return Err(Error::EISDIR);
return Err(WasiError::EISDIR);
}
}
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};
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,
)
} {
Ok(_) => return Err(Error::EEXIST),
Ok(_) => return Err(WasiError::EEXIST),
Err(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};
match unsafe {
renameat(
@@ -113,9 +113,9 @@ pub(crate) fn path_rename(resolved_old: PathGet, resolved_new: PathGet) -> Resul
Ok(_) => {
// check if destination contains a trailing slash
if resolved_new.path().contains('/') {
return Err(Error::ENOTDIR);
return Err(WasiError::ENOTDIR);
} else {
return Err(Error::ENOENT);
return Err(WasiError::ENOENT);
}
}
Err(err) => {
@@ -132,13 +132,13 @@ pub(crate) fn path_rename(resolved_old: PathGet, resolved_new: PathGet) -> Resul
pub(crate) mod fd_readdir_impl {
use crate::sys::fdentry_impl::OsHandle;
use crate::Result;
use crate::wasi::WasiResult;
use std::sync::{Mutex, MutexGuard};
use yanix::dir::Dir;
pub(crate) fn get_dir_from_os_handle<'a>(
os_handle: &'a mut OsHandle,
) -> Result<MutexGuard<'a, Dir>> {
) -> WasiResult<MutexGuard<'a, Dir>> {
let dir = match os_handle.dir {
Some(ref mut dir) => dir,
None => {

View File

@@ -1,5 +1,5 @@
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::io;
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.
pub(crate) unsafe fn determine_type_and_access_rights<Fd: AsRawFd>(
fd: &Fd,
) -> Result<(
) -> io::Result<(
wasi::__wasi_filetype_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.
pub(crate) unsafe fn determine_type_rights<Fd: AsRawFd>(
fd: &Fd,
) -> Result<(
) -> io::Result<(
wasi::__wasi_filetype_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_INHERITING,
),
_ => return Err(Error::EINVAL),
_ => return Err(io::Error::from_raw_os_error(libc::EINVAL)),
}
} else if ft.is_fifo() {
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 {
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(dead_code)]
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::io;
use std::os::unix::prelude::OsStrExt;
use yanix::file::OFlag;
pub(crate) use sys_impl::host_impl::*;
impl FromRawOsError for Error {
fn from_raw_os_error(code: i32) -> Self {
match code {
libc::EPERM => Self::EPERM,
libc::ENOENT => Self::ENOENT,
libc::ESRCH => Self::ESRCH,
libc::EINTR => Self::EINTR,
libc::EIO => Self::EIO,
libc::ENXIO => Self::ENXIO,
libc::E2BIG => Self::E2BIG,
libc::ENOEXEC => Self::ENOEXEC,
libc::EBADF => Self::EBADF,
libc::ECHILD => Self::ECHILD,
libc::EAGAIN => Self::EAGAIN,
libc::ENOMEM => Self::ENOMEM,
libc::EACCES => Self::EACCES,
libc::EFAULT => Self::EFAULT,
libc::EBUSY => Self::EBUSY,
libc::EEXIST => Self::EEXIST,
libc::EXDEV => Self::EXDEV,
libc::ENODEV => Self::ENODEV,
libc::ENOTDIR => Self::ENOTDIR,
libc::EISDIR => Self::EISDIR,
libc::EINVAL => Self::EINVAL,
libc::ENFILE => Self::ENFILE,
libc::EMFILE => Self::EMFILE,
libc::ENOTTY => Self::ENOTTY,
libc::ETXTBSY => Self::ETXTBSY,
libc::EFBIG => Self::EFBIG,
libc::ENOSPC => Self::ENOSPC,
libc::ESPIPE => Self::ESPIPE,
libc::EROFS => Self::EROFS,
libc::EMLINK => Self::EMLINK,
libc::EPIPE => Self::EPIPE,
libc::EDOM => Self::EDOM,
libc::ERANGE => Self::ERANGE,
libc::EDEADLK => Self::EDEADLK,
libc::ENAMETOOLONG => Self::ENAMETOOLONG,
libc::ENOLCK => Self::ENOLCK,
libc::ENOSYS => Self::ENOSYS,
libc::ENOTEMPTY => Self::ENOTEMPTY,
libc::ELOOP => Self::ELOOP,
libc::ENOMSG => Self::ENOMSG,
libc::EIDRM => Self::EIDRM,
libc::ENOLINK => Self::ENOLINK,
libc::EPROTO => Self::EPROTO,
libc::EMULTIHOP => Self::EMULTIHOP,
libc::EBADMSG => Self::EBADMSG,
libc::EOVERFLOW => Self::EOVERFLOW,
libc::EILSEQ => Self::EILSEQ,
libc::ENOTSOCK => Self::ENOTSOCK,
libc::EDESTADDRREQ => Self::EDESTADDRREQ,
libc::EMSGSIZE => Self::EMSGSIZE,
libc::EPROTOTYPE => Self::EPROTOTYPE,
libc::ENOPROTOOPT => Self::ENOPROTOOPT,
libc::EPROTONOSUPPORT => Self::EPROTONOSUPPORT,
libc::EAFNOSUPPORT => Self::EAFNOSUPPORT,
libc::EADDRINUSE => Self::EADDRINUSE,
libc::EADDRNOTAVAIL => Self::EADDRNOTAVAIL,
libc::ENETDOWN => Self::ENETDOWN,
libc::ENETUNREACH => Self::ENETUNREACH,
libc::ENETRESET => Self::ENETRESET,
libc::ECONNABORTED => Self::ECONNABORTED,
libc::ECONNRESET => Self::ECONNRESET,
libc::ENOBUFS => Self::ENOBUFS,
libc::EISCONN => Self::EISCONN,
libc::ENOTCONN => Self::ENOTCONN,
libc::ETIMEDOUT => Self::ETIMEDOUT,
libc::ECONNREFUSED => Self::ECONNREFUSED,
libc::EHOSTUNREACH => Self::EHOSTUNREACH,
libc::EALREADY => Self::EALREADY,
libc::EINPROGRESS => Self::EINPROGRESS,
libc::ESTALE => Self::ESTALE,
libc::EDQUOT => Self::EDQUOT,
libc::ECANCELED => Self::ECANCELED,
libc::EOWNERDEAD => Self::EOWNERDEAD,
libc::ENOTRECOVERABLE => Self::ENOTRECOVERABLE,
x => {
log::debug!("Unknown errno value: {}", x);
impl From<io::Error> for WasiError {
fn from(err: io::Error) -> Self {
match err.raw_os_error() {
Some(code) => match code {
libc::EPERM => Self::EPERM,
libc::ENOENT => Self::ENOENT,
libc::ESRCH => Self::ESRCH,
libc::EINTR => Self::EINTR,
libc::EIO => Self::EIO,
libc::ENXIO => Self::ENXIO,
libc::E2BIG => Self::E2BIG,
libc::ENOEXEC => Self::ENOEXEC,
libc::EBADF => Self::EBADF,
libc::ECHILD => Self::ECHILD,
libc::EAGAIN => Self::EAGAIN,
libc::ENOMEM => Self::ENOMEM,
libc::EACCES => Self::EACCES,
libc::EFAULT => Self::EFAULT,
libc::EBUSY => Self::EBUSY,
libc::EEXIST => Self::EEXIST,
libc::EXDEV => Self::EXDEV,
libc::ENODEV => Self::ENODEV,
libc::ENOTDIR => Self::ENOTDIR,
libc::EISDIR => Self::EISDIR,
libc::EINVAL => Self::EINVAL,
libc::ENFILE => Self::ENFILE,
libc::EMFILE => Self::EMFILE,
libc::ENOTTY => Self::ENOTTY,
libc::ETXTBSY => Self::ETXTBSY,
libc::EFBIG => Self::EFBIG,
libc::ENOSPC => Self::ENOSPC,
libc::ESPIPE => Self::ESPIPE,
libc::EROFS => Self::EROFS,
libc::EMLINK => Self::EMLINK,
libc::EPIPE => Self::EPIPE,
libc::EDOM => Self::EDOM,
libc::ERANGE => Self::ERANGE,
libc::EDEADLK => Self::EDEADLK,
libc::ENAMETOOLONG => Self::ENAMETOOLONG,
libc::ENOLCK => Self::ENOLCK,
libc::ENOSYS => Self::ENOSYS,
libc::ENOTEMPTY => Self::ENOTEMPTY,
libc::ELOOP => Self::ELOOP,
libc::ENOMSG => Self::ENOMSG,
libc::EIDRM => Self::EIDRM,
libc::ENOLINK => Self::ENOLINK,
libc::EPROTO => Self::EPROTO,
libc::EMULTIHOP => Self::EMULTIHOP,
libc::EBADMSG => Self::EBADMSG,
libc::EOVERFLOW => Self::EOVERFLOW,
libc::EILSEQ => Self::EILSEQ,
libc::ENOTSOCK => Self::ENOTSOCK,
libc::EDESTADDRREQ => Self::EDESTADDRREQ,
libc::EMSGSIZE => Self::EMSGSIZE,
libc::EPROTOTYPE => Self::EPROTOTYPE,
libc::ENOPROTOOPT => Self::ENOPROTOOPT,
libc::EPROTONOSUPPORT => Self::EPROTONOSUPPORT,
libc::EAFNOSUPPORT => Self::EAFNOSUPPORT,
libc::EADDRINUSE => Self::EADDRINUSE,
libc::EADDRNOTAVAIL => Self::EADDRNOTAVAIL,
libc::ENETDOWN => Self::ENETDOWN,
libc::ENETUNREACH => Self::ENETUNREACH,
libc::ENETRESET => Self::ENETRESET,
libc::ECONNABORTED => Self::ECONNABORTED,
libc::ECONNRESET => Self::ECONNRESET,
libc::ENOBUFS => Self::ENOBUFS,
libc::EISCONN => Self::EISCONN,
libc::ENOTCONN => Self::ENOTCONN,
libc::ETIMEDOUT => Self::ETIMEDOUT,
libc::ECONNREFUSED => Self::ECONNREFUSED,
libc::EHOSTUNREACH => Self::EHOSTUNREACH,
libc::EALREADY => Self::EALREADY,
libc::EINPROGRESS => Self::EINPROGRESS,
libc::ESTALE => Self::ESTALE,
libc::EDQUOT => Self::EDQUOT,
libc::ECANCELED => Self::ECANCELED,
libc::EOWNERDEAD => Self::EOWNERDEAD,
libc::ENOTRECOVERABLE => Self::ENOTRECOVERABLE,
libc::ENOTSUP => Self::ENOTSUP,
x => {
log::debug!("Unknown errno value: {}", x);
Self::EIO
}
},
None => {
log::debug!("Other I/O error: {}", err);
Self::EIO
}
}
@@ -152,13 +161,13 @@ pub(crate) fn nix_from_oflags(oflags: wasi::__wasi_oflags_t) -> OFlag {
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;
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)
.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);
@@ -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,
/// `__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)
}

View File

@@ -3,8 +3,9 @@
use crate::fdentry::Descriptor;
use crate::host::Dirent;
use crate::hostcalls_impl::PathGet;
use crate::sys::{fdentry_impl::OsHandle, host_impl, unix::sys_impl};
use crate::{wasi, Error, Result};
use crate::sys::fdentry_impl::OsHandle;
use crate::sys::{host_impl, unix::sys_impl};
use crate::wasi::{self, WasiError, WasiResult};
use std::convert::TryInto;
use std::fs::File;
use std::os::unix::fs::FileExt;
@@ -16,15 +17,19 @@ pub(crate) fn fd_pread(
file: &File,
buf: &mut [u8],
offset: wasi::__wasi_filesize_t,
) -> Result<usize> {
) -> WasiResult<usize> {
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)
}
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()) }
.map(host_impl::fdflags_from_nix)
.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(
fd: &File,
fdflags: wasi::__wasi_fdflags_t,
) -> Result<Option<OsHandle>> {
) -> WasiResult<Option<OsHandle>> {
let nix_flags = host_impl::nix_from_fdflags(fdflags);
unsafe { yanix::fcntl::set_status_flags(fd.as_raw_fd(), nix_flags) }
.map(|_| None)
@@ -45,7 +50,7 @@ pub(crate) fn fd_advise(
advice: wasi::__wasi_advice_t,
offset: wasi::__wasi_filesize_t,
len: wasi::__wasi_filesize_t,
) -> Result<()> {
) -> WasiResult<()> {
use yanix::fadvise::{posix_fadvise, PosixFadviseAdvice};
let offset = offset.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_RANDOM => PosixFadviseAdvice::Random,
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)
}
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};
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};
unsafe {
linkat(
@@ -86,7 +91,7 @@ pub(crate) fn path_open(
write: bool,
oflags: wasi::__wasi_oflags_t,
fs_flags: wasi::__wasi_fdflags_t,
) -> Result<Descriptor> {
) -> WasiResult<Descriptor> {
use yanix::file::{fstatat, openat, AtFlag, FileType, Mode, OFlag};
let mut nix_all_oflags = if read && write {
@@ -136,7 +141,7 @@ pub(crate) fn path_open(
} {
Ok(stat) => {
if FileType::from_stat_st_mode(stat.st_mode) == FileType::Socket {
return Err(Error::ENOTSUP);
return Err(WasiError::ENOTSUP);
}
}
Err(err) => {
@@ -158,7 +163,7 @@ pub(crate) fn path_open(
} {
Ok(stat) => {
if FileType::from_stat_st_mode(stat.st_mode) == FileType::Symlink {
return Err(Error::ELOOP);
return Err(WasiError::ELOOP);
}
}
Err(err) => {
@@ -169,7 +174,7 @@ pub(crate) fn path_open(
// FreeBSD returns EMLINK instead of ELOOP when using O_NOFOLLOW on
// a symlink.
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())
}
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 yanix::file::readlinkat;
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)
}
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;
unsafe { fstat(file.as_raw_fd()) }
.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(
resolved: PathGet,
dirflags: wasi::__wasi_lookupflags_t,
) -> Result<wasi::__wasi_filestat_t> {
) -> WasiResult<wasi::__wasi_filestat_t> {
use yanix::file::{fstatat, AtFlag};
let atflags = match dirflags {
0 => AtFlag::empty(),
@@ -224,7 +229,7 @@ pub(crate) fn path_filestat_set_times(
st_atim: wasi::__wasi_timestamp_t,
st_mtim: wasi::__wasi_timestamp_t,
fst_flags: wasi::__wasi_fstflags_t,
) -> Result<()> {
) -> WasiResult<()> {
use std::time::{Duration, UNIX_EPOCH};
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;
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;
@@ -265,7 +270,7 @@ pub(crate) fn path_filestat_set_times(
.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};
unsafe {
@@ -281,7 +286,7 @@ pub(crate) fn path_remove_directory(resolved: PathGet) -> Result<()> {
pub(crate) fn fd_readdir<'a>(
os_handle: &'a mut OsHandle,
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};
// Get an instance of `Dir`; this is host-specific due to intricasies

View File

@@ -1,7 +1,7 @@
#![allow(non_camel_case_types)]
#![allow(unused_unsafe)]
use crate::sys::host_impl;
use crate::{wasi, Result};
use crate::wasi::{self, WasiResult};
use std::fs::File;
use yanix::file::OFlag;
@@ -36,7 +36,7 @@ pub(crate) fn path_open_rights(
(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 yanix::file::{openat, Mode};
@@ -54,7 +54,7 @@ pub(crate) fn openat(dirfd: &File, path: &str) -> Result<File> {
.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 yanix::file::readlinkat;

View File

@@ -1,22 +1,24 @@
#![allow(non_camel_case_types)]
#![allow(unused_unsafe)]
use crate::hostcalls_impl::{ClockEventData, FdEventData};
use crate::{wasi, Error, Result};
use crate::wasi::{self, WasiError, WasiResult};
use std::io;
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
match clock_id {
wasi::__WASI_CLOCKID_REALTIME => Ok(ClockId::Realtime),
wasi::__WASI_CLOCKID_MONOTONIC => Ok(ClockId::Monotonic),
wasi::__WASI_CLOCKID_PROCESS_CPUTIME_ID => Ok(ClockId::ProcessCPUTime),
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 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)
.checked_mul(1_000_000_000)
.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
// make sure we follow the spec
if resolution == 0 {
Err(Error::EINVAL)
Err(WasiError::EINVAL)
} else {
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 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)
.checked_mul(1_000_000_000)
.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(
timeout: Option<ClockEventData>,
fd_events: Vec<FdEventData>,
events: &mut Vec<wasi::__wasi_event_t>,
) -> Result<()> {
) -> WasiResult<()> {
use std::{convert::TryInto, os::unix::prelude::AsRawFd};
use yanix::poll::{poll, PollFd, PollFlags};
@@ -122,12 +126,12 @@ fn poll_oneoff_handle_timeout_event(
fn poll_oneoff_handle_fd_event<'a>(
ready_events: impl Iterator<Item = (FdEventData<'a>, yanix::poll::PollFd)>,
events: &mut Vec<wasi::__wasi_event_t>,
) -> Result<()> {
) -> WasiResult<()> {
use crate::fdentry::Descriptor;
use std::{convert::TryInto, os::unix::prelude::AsRawFd};
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.
if let Descriptor::OsHandle(os_handle) = fd {
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) 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))
}
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))
}

View File

@@ -1,9 +1,9 @@
use crate::fdentry::Descriptor;
use crate::hostcalls_impl::PathGet;
use crate::Result;
use crate::wasi::WasiResult;
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};
unsafe {
unlinkat(
@@ -15,7 +15,7 @@ pub(crate) fn path_unlink_file(resolved: PathGet) -> Result<()> {
.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;
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)
}
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;
match (resolved_old.dirfd(), resolved_new.dirfd()) {
(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 {
use crate::sys::fdentry_impl::OsHandle;
use crate::Result;
use crate::wasi::WasiResult;
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)`:
// After a successful call to fdopendir(), fd is used internally by the implementation,
// 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::io::Result;
use std::path::Path;
pub(crate) fn dev_null() -> Result<File> {
OpenOptions::new()
.read(true)
.write(true)
.open("/dev/null")
.map_err(Into::into)
OpenOptions::new().read(true).write(true).open("/dev/null")
}
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::{wasi, Error, Result};
use crate::wasi;
use std::fs::File;
use std::io;
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.
pub(crate) unsafe fn determine_type_and_access_rights<Handle: AsRawHandle>(
handle: &Handle,
) -> Result<(
) -> io::Result<(
wasi::__wasi_filetype_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.
pub(crate) unsafe fn determine_type_rights<Handle: AsRawHandle>(
handle: &Handle,
) -> Result<(
) -> io::Result<(
wasi::__wasi_filetype_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() {
// disk file: file, dir or disk device
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() {
(
wasi::__WASI_FILETYPE_DIRECTORY,
@@ -128,7 +128,7 @@ pub(crate) unsafe fn determine_type_rights<Handle: AsRawHandle>(
wasi::RIGHTS_REGULAR_FILE_INHERITING,
)
} else {
return Err(Error::EINVAL);
return Err(io::Error::from_raw_os_error(libc::EINVAL));
}
} else if file_type.is_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,
)
} else {
return Err(Error::EINVAL);
return Err(io::Error::from_raw_os_error(libc::EINVAL));
}
};
Ok((file_type, rights_base, rights_inheriting))

View File

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

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::host_impl::{self, path_from_host};
use crate::sys::hostcalls_impl::fs_helpers::PathGetExt;
use crate::{wasi, Error, Result};
use crate::wasi::{self, WasiError, WasiResult};
use log::{debug, trace};
use std::convert::TryInto;
use std::fs::{File, Metadata, OpenOptions};
@@ -44,16 +44,20 @@ pub(crate) fn fd_pread(
file: &File,
buf: &mut [u8],
offset: wasi::__wasi_filesize_t,
) -> Result<usize> {
) -> WasiResult<usize> {
read_at(file, buf, offset).map_err(Into::into)
}
// 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)
}
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 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(
fd: &File,
fdflags: wasi::__wasi_fdflags_t,
) -> Result<Option<OsHandle>> {
) -> WasiResult<Option<OsHandle>> {
let handle = unsafe { fd.as_raw_handle() };
let access_mode = winx::file::query_access_information(handle)?;
@@ -106,7 +110,7 @@ pub(crate) fn fd_advise(
advice: wasi::__wasi_advice_t,
_offset: wasi::__wasi_filesize_t,
_len: wasi::__wasi_filesize_t,
) -> Result<()> {
) -> WasiResult<()> {
match advice {
wasi::__WASI_ADVICE_DONTNEED
| wasi::__WASI_ADVICE_SEQUENTIAL
@@ -114,18 +118,18 @@ pub(crate) fn fd_advise(
| wasi::__WASI_ADVICE_NOREUSE
| wasi::__WASI_ADVICE_RANDOM
| wasi::__WASI_ADVICE_NORMAL => {}
_ => return Err(Error::EINVAL),
_ => return Err(WasiError::EINVAL),
}
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)?;
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")
}
@@ -135,7 +139,7 @@ pub(crate) fn path_open(
write: bool,
oflags: wasi::__wasi_oflags_t,
fdflags: wasi::__wasi_fdflags_t,
) -> Result<Descriptor> {
) -> WasiResult<Descriptor> {
use winx::file::{AccessMode, CreationDisposition, Flags};
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
// of the `FILE_WRITE_DATA` permission.
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) => {
// check if we are trying to open a 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
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() {
@@ -191,7 +195,7 @@ pub(crate) fn path_open(
}
None => {
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,
name: &str,
cookie: wasi::__wasi_dircookie_t,
) -> Result<Dirent> {
) -> WasiResult<Dirent> {
let path = path.as_ref();
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(
fd: &File,
cookie: wasi::__wasi_dircookie_t,
) -> Result<impl Iterator<Item = Result<Dirent>>> {
) -> WasiResult<impl Iterator<Item = WasiResult<Dirent>>> {
use winx::file::get_file_path;
let cookie = cookie.try_into()?;
@@ -361,7 +365,7 @@ pub(crate) fn fd_readdir(
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;
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 target_path = target_path
.strip_prefix(dir_path)
.map_err(|_| Error::ENOTCAPABLE)
.and_then(|path| path.to_str().map(String::from).ok_or(Error::EILSEQ))?;
.map_err(|_| WasiError::ENOTCAPABLE)
.and_then(|path| path.to_str().map(String::from).ok_or(WasiError::EILSEQ))?;
if buf.len() > 0 {
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('/') {
let suffix = resolved.path().trim_end_matches('/');
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;
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
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
// ending in a trailing slash.
if old_path.is_file() && resolved_new.path().ends_with('/') {
return Err(Error::ENOTDIR);
return Err(WasiError::ENOTDIR);
}
// 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.
// Eliminate case old_path == file first.
if old_path.is_file() {
return Err(Error::EISDIR);
return Err(WasiError::EISDIR);
} else {
// Ok, let's try removing an empty dir at new_path if it exists
// 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.
if let Some(path) = strip_trailing_slashes_and_concatenate(&resolved_old)? {
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 => {
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)
}
pub(crate) fn path_filestat_get(
resolved: PathGet,
dirflags: wasi::__wasi_lookupflags_t,
) -> Result<wasi::__wasi_filestat_t> {
) -> WasiResult<wasi::__wasi_filestat_t> {
let path = resolved.concatenate()?;
let file = File::open(path)?;
host_impl::filestat_from_win(&file)
@@ -488,7 +492,7 @@ pub(crate) fn path_filestat_set_times(
st_atim: wasi::__wasi_timestamp_t,
mut st_mtim: wasi::__wasi_timestamp_t,
fst_flags: wasi::__wasi_fstflags_t,
) -> Result<()> {
) -> WasiResult<()> {
use winx::file::AccessMode;
let path = resolved.concatenate()?;
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)
}
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};
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 => {
// does the target exist?
if new_path.exists() {
return Err(Error::EEXIST);
return Err(WasiError::EEXIST);
}
}
winerror::ERROR_INVALID_NAME => {
// does the target without trailing slashes exist?
if let Some(path) = strip_trailing_slashes_and_concatenate(&resolved)? {
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 => {
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;
let path = resolved.concatenate()?;
@@ -573,19 +577,19 @@ pub(crate) fn path_unlink_file(resolved: PathGet) -> Result<()> {
}
None => {
log::debug!("Inconvertible OS error: {}", err);
Err(Error::EIO)
Err(WasiError::EIO)
}
}
} else if file_type.is_dir() {
Err(Error::EISDIR)
Err(WasiError::EISDIR)
} else if file_type.is_file() {
fs::remove_file(path).map_err(Into::into)
} 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()?;
std::fs::remove_dir(&path).map_err(Into::into)
}

View File

@@ -1,7 +1,7 @@
#![allow(non_camel_case_types)]
use crate::fdentry::Descriptor;
use crate::hostcalls_impl::PathGet;
use crate::{wasi, Error, Result};
use crate::wasi::{self, WasiError, WasiResult};
use std::ffi::{OsStr, OsString};
use std::fs::File;
use std::os::windows::ffi::{OsStrExt, OsStringExt};
@@ -9,11 +9,11 @@ use std::path::{Path, PathBuf};
use winapi::shared::winerror;
pub(crate) trait PathGetExt {
fn concatenate(&self) -> Result<PathBuf>;
fn concatenate(&self) -> WasiResult<PathBuf>;
}
impl PathGetExt for PathGet {
fn concatenate(&self) -> Result<PathBuf> {
fn concatenate(&self) -> WasiResult<PathBuf> {
match self.dirfd() {
Descriptor::OsHandle(file) => concatenate(file, Path::new(self.path())),
Descriptor::VirtualFile(_virt) => {
@@ -55,7 +55,7 @@ pub(crate) fn path_open_rights(
(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::os::windows::fs::OpenOptionsExt;
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() {
log::debug!("openat error={:?}", code);
if code as u32 == winerror::ERROR_INVALID_NAME {
return Err(Error::ENOTDIR);
return Err(WasiError::ENOTDIR);
}
}
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;
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 target_path = target_path
.strip_prefix(dir_path)
.map_err(|_| Error::ENOTCAPABLE)?;
let target_path = target_path.to_str().ok_or(Error::EILSEQ)?;
.map_err(|_| WasiError::ENOTCAPABLE)?;
let target_path = target_path.to_str().ok_or(WasiError::EILSEQ)?;
return Ok(target_path.to_owned());
}
Err(e) => e,
@@ -105,7 +105,7 @@ pub(crate) fn readlinkat(dirfd: &File, s_path: &str) -> Result<String> {
// strip "/" and check if exists
let path = concatenate(dirfd, Path::new(s_path.trim_end_matches('/')))?;
if path.exists() && !path.is_dir() {
return Err(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;
// WASI is not able to deal with absolute paths
// so error out if absolute
if path.as_ref().is_absolute() {
return Err(Error::ENOTCAPABLE);
return Err(WasiError::ENOTCAPABLE);
}
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::memory::*;
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 lazy_static::lazy_static;
use log::{debug, error, trace, warn};
@@ -24,9 +25,9 @@ struct StdinPoll {
enum PollState {
Ready,
NotReady, // it's not ready, but we didn't wait
TimedOut, // it's not ready and a timeout has occurred
Error(WasiError), // not using the top-lever Error because it's not Clone
NotReady, // it's not ready, but we didn't wait
TimedOut, // it's not ready and a timeout has occurred
Error(WasiError),
}
enum WaitMode {
@@ -82,7 +83,7 @@ impl StdinPoll {
// Linux returns `POLLIN` in both cases, and we imitate this behavior.
let resp = match std::io::stdin().lock().fill_buf() {
Ok(_) => PollState::Ready,
Err(e) => PollState::Error(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,
@@ -108,7 +109,9 @@ lazy_static! {
// Timer resolution on Windows is really hard. We may consider exposing the resolution of the respective
// 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 {
// This is the best that we can do with std::time::SystemTime.
// 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.
// https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-getthreadtimes
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 {
wasi::__WASI_CLOCKID_REALTIME => get_monotonic_time(),
wasi::__WASI_CLOCKID_MONOTONIC => get_realtime_time()?,
wasi::__WASI_CLOCKID_PROCESS_CPUTIME_ID => get_proc_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)
}
fn make_rw_event(event: &FdEventData, nbytes: Result<u64>) -> wasi::__wasi_event_t {
use crate::error::AsWasiError;
let error = nbytes.as_wasi_error();
let nbytes = nbytes.unwrap_or_default();
fn make_rw_event(event: &FdEventData, nbytes: WasiResult<u64>) -> wasi::__wasi_event_t {
let (nbytes, error) = match nbytes {
Ok(nbytes) => (nbytes, WasiError::ESUCCESS),
Err(e) => (u64::default(), e),
};
wasi::__wasi_event_t {
userdata: event.userdata,
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(
event: FdEventData,
error: Error,
error: WasiError,
out_events: &mut Vec<wasi::__wasi_event_t>,
) {
let new_event = make_rw_event(&event, Err(error));
@@ -244,7 +250,7 @@ pub(crate) fn poll_oneoff(
timeout: Option<ClockEventData>,
fd_events: Vec<FdEventData>,
events: &mut Vec<wasi::__wasi_event_t>,
) -> Result<()> {
) -> WasiResult<()> {
use std::fs::Metadata;
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()) }?;
if ftype.is_unknown() || ftype.is_char() {
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() {
immediate_events.push(event);
} else if ftype.is_pipe() {
@@ -349,7 +355,7 @@ pub(crate) fn poll_oneoff(
PollState::Ready => handle_rw_event(event, events),
PollState::NotReady => {} // not immediately available, so just ignore
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 => {
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()
}
fn get_realtime_time() -> Result<Duration> {
fn get_realtime_time() -> WasiResult<Duration> {
SystemTime::now()
.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())
}
fn get_thread_cputime() -> Result<Duration> {
fn get_thread_cputime() -> WasiResult<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 hostcalls_impl;
use crate::Result;
use std::fs::{File, OpenOptions};
use std::io::Result;
use std::path::Path;
pub(crate) fn dev_null() -> Result<File> {
OpenOptions::new()
.read(true)
.write(true)
.open("NUL")
.map_err(Into::into)
OpenOptions::new().read(true).write(true).open("NUL")
}
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)
.attributes(FILE_FLAG_BACKUP_SEMANTICS)
.open(path)
.map_err(Into::into)
}