Add support for wasi_snapshot_preview1. (#592)
* Add support for wasi_snapshot_preview1. This adds support for the new ABI, while preserving compatibility support for the old ABI. * Fix compilation on platforms where nlink_t isn't 64-bit. * rustfmt * Fix Windows build errors.
This commit is contained in:
@@ -33,7 +33,7 @@ pub fn instantiate(data: &[u8], bin_name: &str, workspace: Option<&Path>) -> any
|
||||
|
||||
// Create our wasi context with pretty standard arguments/inheritance/etc.
|
||||
// Additionally register andy preopened directories if we have them.
|
||||
let mut builder = wasi_common::WasiCtxBuilder::new()
|
||||
let mut builder = wasi_common::old::snapshot_0::WasiCtxBuilder::new()
|
||||
.arg(bin_name)
|
||||
.arg(".")
|
||||
.inherit_stdio();
|
||||
@@ -48,11 +48,13 @@ pub fn instantiate(data: &[u8], bin_name: &str, workspace: Option<&Path>) -> any
|
||||
let (reader, _writer) = os_pipe::pipe()?;
|
||||
builder = builder.stdin(reader_to_file(reader));
|
||||
|
||||
// The current stable Rust toolchain uses the old `wasi_unstable` ABI,
|
||||
// aka `snapshot_0`.
|
||||
module_registry.insert(
|
||||
"wasi_unstable".to_owned(),
|
||||
Instance::from_handle(
|
||||
&store,
|
||||
wasmtime_wasi::instantiate_wasi_with_context(
|
||||
wasmtime_wasi::old::snapshot_0::instantiate_wasi_with_context(
|
||||
global_exports.clone(),
|
||||
builder.build().context("failed to build wasi context")?,
|
||||
)
|
||||
|
||||
Submodule crates/wasi-common/WASI updated: 8a968f2667...9b298d7911
@@ -9,83 +9,83 @@ use thiserror::Error;
|
||||
#[derive(Clone, Copy, Debug, Error, Eq, PartialEq)]
|
||||
#[repr(u16)]
|
||||
pub enum WasiError {
|
||||
ESUCCESS = wasi::__WASI_ESUCCESS,
|
||||
E2BIG = wasi::__WASI_E2BIG,
|
||||
EACCES = wasi::__WASI_EACCES,
|
||||
EADDRINUSE = wasi::__WASI_EADDRINUSE,
|
||||
EADDRNOTAVAIL = wasi::__WASI_EADDRNOTAVAIL,
|
||||
EAFNOSUPPORT = wasi::__WASI_EAFNOSUPPORT,
|
||||
EAGAIN = wasi::__WASI_EAGAIN,
|
||||
EALREADY = wasi::__WASI_EALREADY,
|
||||
EBADF = wasi::__WASI_EBADF,
|
||||
EBADMSG = wasi::__WASI_EBADMSG,
|
||||
EBUSY = wasi::__WASI_EBUSY,
|
||||
ECANCELED = wasi::__WASI_ECANCELED,
|
||||
ECHILD = wasi::__WASI_ECHILD,
|
||||
ECONNABORTED = wasi::__WASI_ECONNABORTED,
|
||||
ECONNREFUSED = wasi::__WASI_ECONNREFUSED,
|
||||
ECONNRESET = wasi::__WASI_ECONNRESET,
|
||||
EDEADLK = wasi::__WASI_EDEADLK,
|
||||
EDESTADDRREQ = wasi::__WASI_EDESTADDRREQ,
|
||||
EDOM = wasi::__WASI_EDOM,
|
||||
EDQUOT = wasi::__WASI_EDQUOT,
|
||||
EEXIST = wasi::__WASI_EEXIST,
|
||||
EFAULT = wasi::__WASI_EFAULT,
|
||||
EFBIG = wasi::__WASI_EFBIG,
|
||||
EHOSTUNREACH = wasi::__WASI_EHOSTUNREACH,
|
||||
EIDRM = wasi::__WASI_EIDRM,
|
||||
EILSEQ = wasi::__WASI_EILSEQ,
|
||||
EINPROGRESS = wasi::__WASI_EINPROGRESS,
|
||||
EINTR = wasi::__WASI_EINTR,
|
||||
EINVAL = wasi::__WASI_EINVAL,
|
||||
EIO = wasi::__WASI_EIO,
|
||||
EISCONN = wasi::__WASI_EISCONN,
|
||||
EISDIR = wasi::__WASI_EISDIR,
|
||||
ELOOP = wasi::__WASI_ELOOP,
|
||||
EMFILE = wasi::__WASI_EMFILE,
|
||||
EMLINK = wasi::__WASI_EMLINK,
|
||||
EMSGSIZE = wasi::__WASI_EMSGSIZE,
|
||||
EMULTIHOP = wasi::__WASI_EMULTIHOP,
|
||||
ENAMETOOLONG = wasi::__WASI_ENAMETOOLONG,
|
||||
ENETDOWN = wasi::__WASI_ENETDOWN,
|
||||
ENETRESET = wasi::__WASI_ENETRESET,
|
||||
ENETUNREACH = wasi::__WASI_ENETUNREACH,
|
||||
ENFILE = wasi::__WASI_ENFILE,
|
||||
ENOBUFS = wasi::__WASI_ENOBUFS,
|
||||
ENODEV = wasi::__WASI_ENODEV,
|
||||
ENOENT = wasi::__WASI_ENOENT,
|
||||
ENOEXEC = wasi::__WASI_ENOEXEC,
|
||||
ENOLCK = wasi::__WASI_ENOLCK,
|
||||
ENOLINK = wasi::__WASI_ENOLINK,
|
||||
ENOMEM = wasi::__WASI_ENOMEM,
|
||||
ENOMSG = wasi::__WASI_ENOMSG,
|
||||
ENOPROTOOPT = wasi::__WASI_ENOPROTOOPT,
|
||||
ENOSPC = wasi::__WASI_ENOSPC,
|
||||
ENOSYS = wasi::__WASI_ENOSYS,
|
||||
ENOTCONN = wasi::__WASI_ENOTCONN,
|
||||
ENOTDIR = wasi::__WASI_ENOTDIR,
|
||||
ENOTEMPTY = wasi::__WASI_ENOTEMPTY,
|
||||
ENOTRECOVERABLE = wasi::__WASI_ENOTRECOVERABLE,
|
||||
ENOTSOCK = wasi::__WASI_ENOTSOCK,
|
||||
ENOTSUP = wasi::__WASI_ENOTSUP,
|
||||
ENOTTY = wasi::__WASI_ENOTTY,
|
||||
ENXIO = wasi::__WASI_ENXIO,
|
||||
EOVERFLOW = wasi::__WASI_EOVERFLOW,
|
||||
EOWNERDEAD = wasi::__WASI_EOWNERDEAD,
|
||||
EPERM = wasi::__WASI_EPERM,
|
||||
EPIPE = wasi::__WASI_EPIPE,
|
||||
EPROTO = wasi::__WASI_EPROTO,
|
||||
EPROTONOSUPPORT = wasi::__WASI_EPROTONOSUPPORT,
|
||||
EPROTOTYPE = wasi::__WASI_EPROTOTYPE,
|
||||
ERANGE = wasi::__WASI_ERANGE,
|
||||
EROFS = wasi::__WASI_EROFS,
|
||||
ESPIPE = wasi::__WASI_ESPIPE,
|
||||
ESRCH = wasi::__WASI_ESRCH,
|
||||
ESTALE = wasi::__WASI_ESTALE,
|
||||
ETIMEDOUT = wasi::__WASI_ETIMEDOUT,
|
||||
ETXTBSY = wasi::__WASI_ETXTBSY,
|
||||
EXDEV = wasi::__WASI_EXDEV,
|
||||
ENOTCAPABLE = wasi::__WASI_ENOTCAPABLE,
|
||||
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 {
|
||||
@@ -273,7 +273,7 @@ fn errno_from_ioerror(e: &std::io::Error) -> wasi::__wasi_errno_t {
|
||||
Some(code) => crate::sys::errno_from_host(code),
|
||||
None => {
|
||||
log::debug!("Inconvertible OS error: {}", e);
|
||||
wasi::__WASI_EIO
|
||||
wasi::__WASI_ERRNO_IO
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,7 +52,7 @@ impl<'ctx> Dir<'ctx> {
|
||||
wasi_errno_to_io_error(hostcalls::path_open(
|
||||
self.ctx,
|
||||
self.fd,
|
||||
wasi::__WASI_LOOKUP_SYMLINK_FOLLOW,
|
||||
wasi::__WASI_LOOKUPFLAGS_SYMLINK_FOLLOW,
|
||||
path.as_os_str().as_bytes(),
|
||||
path.as_os_str().len(),
|
||||
0,
|
||||
@@ -98,9 +98,9 @@ impl<'ctx> Dir<'ctx> {
|
||||
wasi_errno_to_io_error(hostcalls::path_open(
|
||||
self.ctx,
|
||||
self.fd,
|
||||
wasi::__WASI_LOOKUP_SYMLINK_FOLLOW,
|
||||
wasi::__WASI_LOOKUPFLAGS_SYMLINK_FOLLOW,
|
||||
path.as_os_str().as_bytes(),
|
||||
wasi::__WASI_O_DIRECTORY,
|
||||
wasi::__WASI_OFLAGS_DIRECTORY,
|
||||
!0,
|
||||
!0,
|
||||
0,
|
||||
@@ -132,10 +132,10 @@ impl<'ctx> Dir<'ctx> {
|
||||
wasi_errno_to_io_error(hostcalls::path_open(
|
||||
self.ctx,
|
||||
self.fd,
|
||||
wasi::__WASI_LOOKUP_SYMLINK_FOLLOW,
|
||||
wasi::__WASI_LOOKUPFLAGS_SYMLINK_FOLLOW,
|
||||
path.as_os_str().as_bytes(),
|
||||
path.as_os_str().len(),
|
||||
wasi::__WASI_O_CREAT | wasi::__WASI_O_TRUNC,
|
||||
wasi::__WASI_OFLAGS_CREAT | wasi::__WASI_OFLAGS_TRUNC,
|
||||
!0,
|
||||
!0,
|
||||
0,
|
||||
|
||||
@@ -9,86 +9,86 @@ use std::io;
|
||||
pub(crate) fn wasi_errno_to_io_error(errno: wasi::__wasi_errno_t) -> io::Result<()> {
|
||||
#[cfg(unix)]
|
||||
let raw_os_error = match errno {
|
||||
wasi::__WASI_ESUCCESS => return Ok(()),
|
||||
wasi::__WASI_EIO => libc::EIO,
|
||||
wasi::__WASI_EPERM => libc::EPERM,
|
||||
wasi::__WASI_EINVAL => libc::EINVAL,
|
||||
wasi::__WASI_EPIPE => libc::EPIPE,
|
||||
wasi::__WASI_ENOTCONN => libc::ENOTCONN,
|
||||
wasi::__WASI_E2BIG => libc::E2BIG,
|
||||
wasi::__WASI_EACCES => libc::EACCES,
|
||||
wasi::__WASI_EADDRINUSE => libc::EADDRINUSE,
|
||||
wasi::__WASI_EADDRNOTAVAIL => libc::EADDRNOTAVAIL,
|
||||
wasi::__WASI_EAFNOSUPPORT => libc::EAFNOSUPPORT,
|
||||
wasi::__WASI_EAGAIN => libc::EAGAIN,
|
||||
wasi::__WASI_EALREADY => libc::EALREADY,
|
||||
wasi::__WASI_EBADF => libc::EBADF,
|
||||
wasi::__WASI_EBADMSG => libc::EBADMSG,
|
||||
wasi::__WASI_EBUSY => libc::EBUSY,
|
||||
wasi::__WASI_ECANCELED => libc::ECANCELED,
|
||||
wasi::__WASI_ECHILD => libc::ECHILD,
|
||||
wasi::__WASI_ECONNABORTED => libc::ECONNABORTED,
|
||||
wasi::__WASI_ECONNREFUSED => libc::ECONNREFUSED,
|
||||
wasi::__WASI_ECONNRESET => libc::ECONNRESET,
|
||||
wasi::__WASI_EDEADLK => libc::EDEADLK,
|
||||
wasi::__WASI_EDESTADDRREQ => libc::EDESTADDRREQ,
|
||||
wasi::__WASI_EDOM => libc::EDOM,
|
||||
wasi::__WASI_EDQUOT => libc::EDQUOT,
|
||||
wasi::__WASI_EEXIST => libc::EEXIST,
|
||||
wasi::__WASI_EFAULT => libc::EFAULT,
|
||||
wasi::__WASI_EFBIG => libc::EFBIG,
|
||||
wasi::__WASI_EHOSTUNREACH => libc::EHOSTUNREACH,
|
||||
wasi::__WASI_EIDRM => libc::EIDRM,
|
||||
wasi::__WASI_EILSEQ => libc::EILSEQ,
|
||||
wasi::__WASI_EINPROGRESS => libc::EINPROGRESS,
|
||||
wasi::__WASI_EINTR => libc::EINTR,
|
||||
wasi::__WASI_EISCONN => libc::EISCONN,
|
||||
wasi::__WASI_EISDIR => libc::EISDIR,
|
||||
wasi::__WASI_ELOOP => libc::ELOOP,
|
||||
wasi::__WASI_EMFILE => libc::EMFILE,
|
||||
wasi::__WASI_EMLINK => libc::EMLINK,
|
||||
wasi::__WASI_EMSGSIZE => libc::EMSGSIZE,
|
||||
wasi::__WASI_EMULTIHOP => libc::EMULTIHOP,
|
||||
wasi::__WASI_ENAMETOOLONG => libc::ENAMETOOLONG,
|
||||
wasi::__WASI_ENETDOWN => libc::ENETDOWN,
|
||||
wasi::__WASI_ENETRESET => libc::ENETRESET,
|
||||
wasi::__WASI_ENETUNREACH => libc::ENETUNREACH,
|
||||
wasi::__WASI_ENFILE => libc::ENFILE,
|
||||
wasi::__WASI_ENOBUFS => libc::ENOBUFS,
|
||||
wasi::__WASI_ENODEV => libc::ENODEV,
|
||||
wasi::__WASI_ENOENT => libc::ENOENT,
|
||||
wasi::__WASI_ENOEXEC => libc::ENOEXEC,
|
||||
wasi::__WASI_ENOLCK => libc::ENOLCK,
|
||||
wasi::__WASI_ENOLINK => libc::ENOLINK,
|
||||
wasi::__WASI_ENOMEM => libc::ENOMEM,
|
||||
wasi::__WASI_ENOMSG => libc::ENOMSG,
|
||||
wasi::__WASI_ENOPROTOOPT => libc::ENOPROTOOPT,
|
||||
wasi::__WASI_ENOSPC => libc::ENOSPC,
|
||||
wasi::__WASI_ENOSYS => libc::ENOSYS,
|
||||
wasi::__WASI_ENOTDIR => libc::ENOTDIR,
|
||||
wasi::__WASI_ENOTEMPTY => libc::ENOTEMPTY,
|
||||
wasi::__WASI_ENOTRECOVERABLE => libc::ENOTRECOVERABLE,
|
||||
wasi::__WASI_ENOTSOCK => libc::ENOTSOCK,
|
||||
wasi::__WASI_ENOTSUP => libc::ENOTSUP,
|
||||
wasi::__WASI_ENOTTY => libc::ENOTTY,
|
||||
wasi::__WASI_ENXIO => libc::ENXIO,
|
||||
wasi::__WASI_EOVERFLOW => libc::EOVERFLOW,
|
||||
wasi::__WASI_EOWNERDEAD => libc::EOWNERDEAD,
|
||||
wasi::__WASI_EPROTO => libc::EPROTO,
|
||||
wasi::__WASI_EPROTONOSUPPORT => libc::EPROTONOSUPPORT,
|
||||
wasi::__WASI_EPROTOTYPE => libc::EPROTOTYPE,
|
||||
wasi::__WASI_ERANGE => libc::ERANGE,
|
||||
wasi::__WASI_EROFS => libc::EROFS,
|
||||
wasi::__WASI_ESPIPE => libc::ESPIPE,
|
||||
wasi::__WASI_ESRCH => libc::ESRCH,
|
||||
wasi::__WASI_ESTALE => libc::ESTALE,
|
||||
wasi::__WASI_ETIMEDOUT => libc::ETIMEDOUT,
|
||||
wasi::__WASI_ETXTBSY => libc::ETXTBSY,
|
||||
wasi::__WASI_EXDEV => libc::EXDEV,
|
||||
wasi::__WASI_ERRNO_SUCCESS => return Ok(()),
|
||||
wasi::__WASI_ERRNO_IO => libc::EIO,
|
||||
wasi::__WASI_ERRNO_PERM => libc::EPERM,
|
||||
wasi::__WASI_ERRNO_INVAL => libc::EINVAL,
|
||||
wasi::__WASI_ERRNO_PIPE => libc::EPIPE,
|
||||
wasi::__WASI_ERRNO_NOTCONN => libc::ENOTCONN,
|
||||
wasi::__WASI_ERRNO_2BIG => libc::E2BIG,
|
||||
wasi::__WASI_ERRNO_ACCES => libc::EACCES,
|
||||
wasi::__WASI_ERRNO_ADDRINUSE => libc::EADDRINUSE,
|
||||
wasi::__WASI_ERRNO_ADDRNOTAVAIL => libc::EADDRNOTAVAIL,
|
||||
wasi::__WASI_ERRNO_AFNOSUPPORT => libc::EAFNOSUPPORT,
|
||||
wasi::__WASI_ERRNO_AGAIN => libc::EAGAIN,
|
||||
wasi::__WASI_ERRNO_ALREADY => libc::EALREADY,
|
||||
wasi::__WASI_ERRNO_BADF => libc::EBADF,
|
||||
wasi::__WASI_ERRNO_BADMSG => libc::EBADMSG,
|
||||
wasi::__WASI_ERRNO_BUSY => libc::EBUSY,
|
||||
wasi::__WASI_ERRNO_CANCELED => libc::ECANCELED,
|
||||
wasi::__WASI_ERRNO_CHILD => libc::ECHILD,
|
||||
wasi::__WASI_ERRNO_CONNABORTED => libc::ECONNABORTED,
|
||||
wasi::__WASI_ERRNO_CONNREFUSED => libc::ECONNREFUSED,
|
||||
wasi::__WASI_ERRNO_CONNRESET => libc::ECONNRESET,
|
||||
wasi::__WASI_ERRNO_DEADLK => libc::EDEADLK,
|
||||
wasi::__WASI_ERRNO_DESTADDRREQ => libc::EDESTADDRREQ,
|
||||
wasi::__WASI_ERRNO_DOM => libc::EDOM,
|
||||
wasi::__WASI_ERRNO_DQUOT => libc::EDQUOT,
|
||||
wasi::__WASI_ERRNO_EXIST => libc::EEXIST,
|
||||
wasi::__WASI_ERRNO_FAULT => libc::EFAULT,
|
||||
wasi::__WASI_ERRNO_FBIG => libc::EFBIG,
|
||||
wasi::__WASI_ERRNO_HOSTUNREACH => libc::EHOSTUNREACH,
|
||||
wasi::__WASI_ERRNO_IDRM => libc::EIDRM,
|
||||
wasi::__WASI_ERRNO_ILSEQ => libc::EILSEQ,
|
||||
wasi::__WASI_ERRNO_INPROGRESS => libc::EINPROGRESS,
|
||||
wasi::__WASI_ERRNO_INTR => libc::EINTR,
|
||||
wasi::__WASI_ERRNO_ISCONN => libc::EISCONN,
|
||||
wasi::__WASI_ERRNO_ISDIR => libc::EISDIR,
|
||||
wasi::__WASI_ERRNO_LOOP => libc::ELOOP,
|
||||
wasi::__WASI_ERRNO_MFILE => libc::EMFILE,
|
||||
wasi::__WASI_ERRNO_MLINK => libc::EMLINK,
|
||||
wasi::__WASI_ERRNO_MSGSIZE => libc::EMSGSIZE,
|
||||
wasi::__WASI_ERRNO_MULTIHOP => libc::EMULTIHOP,
|
||||
wasi::__WASI_ERRNO_NAMETOOLONG => libc::ENAMETOOLONG,
|
||||
wasi::__WASI_ERRNO_NETDOWN => libc::ENETDOWN,
|
||||
wasi::__WASI_ERRNO_NETRESET => libc::ENETRESET,
|
||||
wasi::__WASI_ERRNO_NETUNREACH => libc::ENETUNREACH,
|
||||
wasi::__WASI_ERRNO_NFILE => libc::ENFILE,
|
||||
wasi::__WASI_ERRNO_NOBUFS => libc::ENOBUFS,
|
||||
wasi::__WASI_ERRNO_NODEV => libc::ENODEV,
|
||||
wasi::__WASI_ERRNO_NOENT => libc::ENOENT,
|
||||
wasi::__WASI_ERRNO_NOEXEC => libc::ENOEXEC,
|
||||
wasi::__WASI_ERRNO_NOLCK => libc::ENOLCK,
|
||||
wasi::__WASI_ERRNO_NOLINK => libc::ENOLINK,
|
||||
wasi::__WASI_ERRNO_NOMEM => libc::ENOMEM,
|
||||
wasi::__WASI_ERRNO_NOMSG => libc::ENOMSG,
|
||||
wasi::__WASI_ERRNO_NOPROTOOPT => libc::ENOPROTOOPT,
|
||||
wasi::__WASI_ERRNO_NOSPC => libc::ENOSPC,
|
||||
wasi::__WASI_ERRNO_NOSYS => libc::ENOSYS,
|
||||
wasi::__WASI_ERRNO_NOTDIR => libc::ENOTDIR,
|
||||
wasi::__WASI_ERRNO_NOTEMPTY => libc::ENOTEMPTY,
|
||||
wasi::__WASI_ERRNO_NOTRECOVERABLE => libc::ENOTRECOVERABLE,
|
||||
wasi::__WASI_ERRNO_NOTSOCK => libc::ENOTSOCK,
|
||||
wasi::__WASI_ERRNO_NOTSUP => libc::ENOTSUP,
|
||||
wasi::__WASI_ERRNO_NOTTY => libc::ENOTTY,
|
||||
wasi::__WASI_ERRNO_NXIO => libc::ENXIO,
|
||||
wasi::__WASI_ERRNO_OVERFLOW => libc::EOVERFLOW,
|
||||
wasi::__WASI_ERRNO_OWNERDEAD => libc::EOWNERDEAD,
|
||||
wasi::__WASI_ERRNO_PROTO => libc::EPROTO,
|
||||
wasi::__WASI_ERRNO_PROTONOSUPPORT => libc::EPROTONOSUPPORT,
|
||||
wasi::__WASI_ERRNO_PROTOTYPE => libc::EPROTOTYPE,
|
||||
wasi::__WASI_ERRNO_RANGE => libc::ERANGE,
|
||||
wasi::__WASI_ERRNO_ROFS => libc::EROFS,
|
||||
wasi::__WASI_ERRNO_SPIPE => libc::ESPIPE,
|
||||
wasi::__WASI_ERRNO_SRCH => libc::ESRCH,
|
||||
wasi::__WASI_ERRNO_STALE => libc::ESTALE,
|
||||
wasi::__WASI_ERRNO_TIMEDOUT => libc::ETIMEDOUT,
|
||||
wasi::__WASI_ERRNO_TXTBSY => libc::ETXTBSY,
|
||||
wasi::__WASI_ERRNO_XDEV => libc::EXDEV,
|
||||
#[cfg(target_os = "wasi")]
|
||||
wasi::__WASI_ENOTCAPABLE => libc::ENOTCAPABLE,
|
||||
wasi::__WASI_ERRNO_NOTCAPABLE => libc::ENOTCAPABLE,
|
||||
#[cfg(not(target_os = "wasi"))]
|
||||
wasi::__WASI_ENOTCAPABLE => libc::EIO,
|
||||
wasi::__WASI_ERRNO_NOTCAPABLE => libc::EIO,
|
||||
_ => panic!("unexpected wasi errno value"),
|
||||
};
|
||||
|
||||
@@ -97,82 +97,82 @@ pub(crate) fn wasi_errno_to_io_error(errno: wasi::__wasi_errno_t) -> io::Result<
|
||||
|
||||
#[cfg(windows)]
|
||||
let raw_os_error = match errno {
|
||||
wasi::__WASI_ESUCCESS => return Ok(()),
|
||||
wasi::__WASI_EINVAL => WSAEINVAL,
|
||||
wasi::__WASI_EPIPE => ERROR_BROKEN_PIPE,
|
||||
wasi::__WASI_ENOTCONN => WSAENOTCONN,
|
||||
wasi::__WASI_EPERM | wasi::__WASI_EACCES => ERROR_ACCESS_DENIED,
|
||||
wasi::__WASI_EADDRINUSE => WSAEADDRINUSE,
|
||||
wasi::__WASI_EADDRNOTAVAIL => WSAEADDRNOTAVAIL,
|
||||
wasi::__WASI_EAGAIN => WSAEWOULDBLOCK,
|
||||
wasi::__WASI_ECONNABORTED => WSAECONNABORTED,
|
||||
wasi::__WASI_ECONNREFUSED => WSAECONNREFUSED,
|
||||
wasi::__WASI_ECONNRESET => WSAECONNRESET,
|
||||
wasi::__WASI_EEXIST => ERROR_ALREADY_EXISTS,
|
||||
wasi::__WASI_ENOENT => ERROR_FILE_NOT_FOUND,
|
||||
wasi::__WASI_ETIMEDOUT => WSAETIMEDOUT,
|
||||
wasi::__WASI_EAFNOSUPPORT => WSAEAFNOSUPPORT,
|
||||
wasi::__WASI_EALREADY => WSAEALREADY,
|
||||
wasi::__WASI_EBADF => WSAEBADF,
|
||||
wasi::__WASI_EDESTADDRREQ => WSAEDESTADDRREQ,
|
||||
wasi::__WASI_EDQUOT => WSAEDQUOT,
|
||||
wasi::__WASI_EFAULT => WSAEFAULT,
|
||||
wasi::__WASI_EHOSTUNREACH => WSAEHOSTUNREACH,
|
||||
wasi::__WASI_EINPROGRESS => WSAEINPROGRESS,
|
||||
wasi::__WASI_EINTR => WSAEINTR,
|
||||
wasi::__WASI_EISCONN => WSAEISCONN,
|
||||
wasi::__WASI_ELOOP => WSAELOOP,
|
||||
wasi::__WASI_EMFILE => WSAEMFILE,
|
||||
wasi::__WASI_EMSGSIZE => WSAEMSGSIZE,
|
||||
wasi::__WASI_ENAMETOOLONG => WSAENAMETOOLONG,
|
||||
wasi::__WASI_ENETDOWN => WSAENETDOWN,
|
||||
wasi::__WASI_ENETRESET => WSAENETRESET,
|
||||
wasi::__WASI_ENETUNREACH => WSAENETUNREACH,
|
||||
wasi::__WASI_ENOBUFS => WSAENOBUFS,
|
||||
wasi::__WASI_ENOPROTOOPT => WSAENOPROTOOPT,
|
||||
wasi::__WASI_ENOTEMPTY => WSAENOTEMPTY,
|
||||
wasi::__WASI_ENOTSOCK => WSAENOTSOCK,
|
||||
wasi::__WASI_EPROTONOSUPPORT => WSAEPROTONOSUPPORT,
|
||||
wasi::__WASI_EPROTOTYPE => WSAEPROTOTYPE,
|
||||
wasi::__WASI_ESTALE => WSAESTALE,
|
||||
wasi::__WASI_EIO
|
||||
| wasi::__WASI_EISDIR
|
||||
| wasi::__WASI_E2BIG
|
||||
| wasi::__WASI_EBADMSG
|
||||
| wasi::__WASI_EBUSY
|
||||
| wasi::__WASI_ECANCELED
|
||||
| wasi::__WASI_ECHILD
|
||||
| wasi::__WASI_EDEADLK
|
||||
| wasi::__WASI_EDOM
|
||||
| wasi::__WASI_EFBIG
|
||||
| wasi::__WASI_EIDRM
|
||||
| wasi::__WASI_EILSEQ
|
||||
| wasi::__WASI_EMLINK
|
||||
| wasi::__WASI_EMULTIHOP
|
||||
| wasi::__WASI_ENFILE
|
||||
| wasi::__WASI_ENODEV
|
||||
| wasi::__WASI_ENOEXEC
|
||||
| wasi::__WASI_ENOLCK
|
||||
| wasi::__WASI_ENOLINK
|
||||
| wasi::__WASI_ENOMEM
|
||||
| wasi::__WASI_ENOMSG
|
||||
| wasi::__WASI_ENOSPC
|
||||
| wasi::__WASI_ENOSYS
|
||||
| wasi::__WASI_ENOTDIR
|
||||
| wasi::__WASI_ENOTRECOVERABLE
|
||||
| wasi::__WASI_ENOTSUP
|
||||
| wasi::__WASI_ENOTTY
|
||||
| wasi::__WASI_ENXIO
|
||||
| wasi::__WASI_EOVERFLOW
|
||||
| wasi::__WASI_EOWNERDEAD
|
||||
| wasi::__WASI_EPROTO
|
||||
| wasi::__WASI_ERANGE
|
||||
| wasi::__WASI_EROFS
|
||||
| wasi::__WASI_ESPIPE
|
||||
| wasi::__WASI_ESRCH
|
||||
| wasi::__WASI_ETXTBSY
|
||||
| wasi::__WASI_EXDEV
|
||||
| wasi::__WASI_ENOTCAPABLE => {
|
||||
wasi::__WASI_ERRNO_SUCCESS => return Ok(()),
|
||||
wasi::__WASI_ERRNO_INVAL => WSAEINVAL,
|
||||
wasi::__WASI_ERRNO_PIPE => ERROR_BROKEN_PIPE,
|
||||
wasi::__WASI_ERRNO_NOTCONN => WSAENOTCONN,
|
||||
wasi::__WASI_ERRNO_PERM | wasi::__WASI_ERRNO_ACCES => ERROR_ACCESS_DENIED,
|
||||
wasi::__WASI_ERRNO_ADDRINUSE => WSAEADDRINUSE,
|
||||
wasi::__WASI_ERRNO_ADDRNOTAVAIL => WSAEADDRNOTAVAIL,
|
||||
wasi::__WASI_ERRNO_AGAIN => WSAEWOULDBLOCK,
|
||||
wasi::__WASI_ERRNO_CONNABORTED => WSAECONNABORTED,
|
||||
wasi::__WASI_ERRNO_CONNREFUSED => WSAECONNREFUSED,
|
||||
wasi::__WASI_ERRNO_CONNRESET => WSAECONNRESET,
|
||||
wasi::__WASI_ERRNO_EXIST => ERROR_ALREADY_EXISTS,
|
||||
wasi::__WASI_ERRNO_NOENT => ERROR_FILE_NOT_FOUND,
|
||||
wasi::__WASI_ERRNO_TIMEDOUT => WSAETIMEDOUT,
|
||||
wasi::__WASI_ERRNO_AFNOSUPPORT => WSAEAFNOSUPPORT,
|
||||
wasi::__WASI_ERRNO_ALREADY => WSAEALREADY,
|
||||
wasi::__WASI_ERRNO_BADF => WSAEBADF,
|
||||
wasi::__WASI_ERRNO_DESTADDRREQ => WSAEDESTADDRREQ,
|
||||
wasi::__WASI_ERRNO_DQUOT => WSAEDQUOT,
|
||||
wasi::__WASI_ERRNO_FAULT => WSAEFAULT,
|
||||
wasi::__WASI_ERRNO_HOSTUNREACH => WSAEHOSTUNREACH,
|
||||
wasi::__WASI_ERRNO_INPROGRESS => WSAEINPROGRESS,
|
||||
wasi::__WASI_ERRNO_INTR => WSAEINTR,
|
||||
wasi::__WASI_ERRNO_ISCONN => WSAEISCONN,
|
||||
wasi::__WASI_ERRNO_LOOP => WSAELOOP,
|
||||
wasi::__WASI_ERRNO_MFILE => WSAEMFILE,
|
||||
wasi::__WASI_ERRNO_MSGSIZE => WSAEMSGSIZE,
|
||||
wasi::__WASI_ERRNO_NAMETOOLONG => WSAENAMETOOLONG,
|
||||
wasi::__WASI_ERRNO_NETDOWN => WSAENETDOWN,
|
||||
wasi::__WASI_ERRNO_NETRESET => WSAENETRESET,
|
||||
wasi::__WASI_ERRNO_NETUNREACH => WSAENETUNREACH,
|
||||
wasi::__WASI_ERRNO_NOBUFS => WSAENOBUFS,
|
||||
wasi::__WASI_ERRNO_NOPROTOOPT => WSAENOPROTOOPT,
|
||||
wasi::__WASI_ERRNO_NOTEMPTY => WSAENOTEMPTY,
|
||||
wasi::__WASI_ERRNO_NOTSOCK => WSAENOTSOCK,
|
||||
wasi::__WASI_ERRNO_PROTONOSUPPORT => WSAEPROTONOSUPPORT,
|
||||
wasi::__WASI_ERRNO_PROTOTYPE => WSAEPROTOTYPE,
|
||||
wasi::__WASI_ERRNO_STALE => WSAESTALE,
|
||||
wasi::__WASI_ERRNO_IO
|
||||
| wasi::__WASI_ERRNO_ISDIR
|
||||
| wasi::__WASI_ERRNO_2BIG
|
||||
| wasi::__WASI_ERRNO_BADMSG
|
||||
| wasi::__WASI_ERRNO_BUSY
|
||||
| wasi::__WASI_ERRNO_CANCELED
|
||||
| wasi::__WASI_ERRNO_CHILD
|
||||
| wasi::__WASI_ERRNO_DEADLK
|
||||
| wasi::__WASI_ERRNO_DOM
|
||||
| wasi::__WASI_ERRNO_FBIG
|
||||
| wasi::__WASI_ERRNO_IDRM
|
||||
| wasi::__WASI_ERRNO_ILSEQ
|
||||
| wasi::__WASI_ERRNO_MLINK
|
||||
| wasi::__WASI_ERRNO_MULTIHOP
|
||||
| wasi::__WASI_ERRNO_NFILE
|
||||
| wasi::__WASI_ERRNO_NODEV
|
||||
| wasi::__WASI_ERRNO_NOEXEC
|
||||
| wasi::__WASI_ERRNO_NOLCK
|
||||
| wasi::__WASI_ERRNO_NOLINK
|
||||
| wasi::__WASI_ERRNO_NOMEM
|
||||
| wasi::__WASI_ERRNO_NOMSG
|
||||
| wasi::__WASI_ERRNO_NOSPC
|
||||
| wasi::__WASI_ERRNO_NOSYS
|
||||
| wasi::__WASI_ERRNO_NOTDIR
|
||||
| wasi::__WASI_ERRNO_NOTRECOVERABLE
|
||||
| wasi::__WASI_ERRNO_NOTSUP
|
||||
| wasi::__WASI_ERRNO_NOTTY
|
||||
| wasi::__WASI_ERRNO_NXIO
|
||||
| wasi::__WASI_ERRNO_OVERFLOW
|
||||
| wasi::__WASI_ERRNO_OWNERDEAD
|
||||
| wasi::__WASI_ERRNO_PROTO
|
||||
| wasi::__WASI_ERRNO_RANGE
|
||||
| wasi::__WASI_ERRNO_ROFS
|
||||
| wasi::__WASI_ERRNO_SPIPE
|
||||
| wasi::__WASI_ERRNO_SRCH
|
||||
| wasi::__WASI_ERRNO_TXTBSY
|
||||
| wasi::__WASI_ERRNO_XDEV
|
||||
| wasi::__WASI_ERRNO_NOTCAPABLE => {
|
||||
return Err(io::Error::new(io::ErrorKind::Other, error_str(errno)))
|
||||
}
|
||||
_ => panic!("unrecognized WASI errno value"),
|
||||
@@ -184,82 +184,82 @@ pub(crate) fn wasi_errno_to_io_error(errno: wasi::__wasi_errno_t) -> io::Result<
|
||||
#[cfg(windows)]
|
||||
fn error_str(errno: wasi::__wasi_errno_t) -> &'static str {
|
||||
match errno {
|
||||
wasi::__WASI_E2BIG => "Argument list too long",
|
||||
wasi::__WASI_EACCES => "Permission denied",
|
||||
wasi::__WASI_EADDRINUSE => "Address in use",
|
||||
wasi::__WASI_EADDRNOTAVAIL => "Address not available",
|
||||
wasi::__WASI_EAFNOSUPPORT => "Address family not supported by protocol",
|
||||
wasi::__WASI_EAGAIN => "Resource temporarily unavailable",
|
||||
wasi::__WASI_EALREADY => "Operation already in progress",
|
||||
wasi::__WASI_EBADF => "Bad file descriptor",
|
||||
wasi::__WASI_EBADMSG => "Bad message",
|
||||
wasi::__WASI_EBUSY => "Resource busy",
|
||||
wasi::__WASI_ECANCELED => "Operation canceled",
|
||||
wasi::__WASI_ECHILD => "No child process",
|
||||
wasi::__WASI_ECONNABORTED => "Connection aborted",
|
||||
wasi::__WASI_ECONNREFUSED => "Connection refused",
|
||||
wasi::__WASI_ECONNRESET => "Connection reset by peer",
|
||||
wasi::__WASI_EDEADLK => "Resource deadlock would occur",
|
||||
wasi::__WASI_EDESTADDRREQ => "Destination address required",
|
||||
wasi::__WASI_EDOM => "Domain error",
|
||||
wasi::__WASI_EDQUOT => "Quota exceeded",
|
||||
wasi::__WASI_EEXIST => "File exists",
|
||||
wasi::__WASI_EFAULT => "Bad address",
|
||||
wasi::__WASI_EFBIG => "File too large",
|
||||
wasi::__WASI_EHOSTUNREACH => "Host is unreachable",
|
||||
wasi::__WASI_EIDRM => "Identifier removed",
|
||||
wasi::__WASI_EILSEQ => "Illegal byte sequence",
|
||||
wasi::__WASI_EINPROGRESS => "Operation in progress",
|
||||
wasi::__WASI_EINTR => "Interrupted system call",
|
||||
wasi::__WASI_EINVAL => "Invalid argument",
|
||||
wasi::__WASI_EIO => "Remote I/O error",
|
||||
wasi::__WASI_EISCONN => "Socket is connected",
|
||||
wasi::__WASI_EISDIR => "Is a directory",
|
||||
wasi::__WASI_ELOOP => "Symbolic link loop",
|
||||
wasi::__WASI_EMFILE => "No file descriptors available",
|
||||
wasi::__WASI_EMLINK => "Too many links",
|
||||
wasi::__WASI_EMSGSIZE => "Message too large",
|
||||
wasi::__WASI_EMULTIHOP => "Multihop attempted",
|
||||
wasi::__WASI_ENAMETOOLONG => "Filename too long",
|
||||
wasi::__WASI_ENETDOWN => "Network is down",
|
||||
wasi::__WASI_ENETRESET => "Connection reset by network",
|
||||
wasi::__WASI_ENETUNREACH => "Network unreachable",
|
||||
wasi::__WASI_ENFILE => "Too many open files in system",
|
||||
wasi::__WASI_ENOBUFS => "No buffer space available",
|
||||
wasi::__WASI_ENODEV => "No such device",
|
||||
wasi::__WASI_ENOENT => "No such file or directory",
|
||||
wasi::__WASI_ENOEXEC => "Exec format error",
|
||||
wasi::__WASI_ENOLCK => "No locks available",
|
||||
wasi::__WASI_ENOLINK => "Link has been severed",
|
||||
wasi::__WASI_ENOMEM => "Out of memory",
|
||||
wasi::__WASI_ENOMSG => "No message of desired type",
|
||||
wasi::__WASI_ENOPROTOOPT => "Protocol not available",
|
||||
wasi::__WASI_ENOSPC => "No space left on device",
|
||||
wasi::__WASI_ENOSYS => "Function not implemented",
|
||||
wasi::__WASI_ENOTCONN => "Socket not connected",
|
||||
wasi::__WASI_ENOTDIR => "Not a directory",
|
||||
wasi::__WASI_ENOTEMPTY => "Directory not empty",
|
||||
wasi::__WASI_ENOTRECOVERABLE => "State not recoverable",
|
||||
wasi::__WASI_ENOTSOCK => "Not a socket",
|
||||
wasi::__WASI_ENOTSUP => "Not supported",
|
||||
wasi::__WASI_ENOTTY => "Not a tty",
|
||||
wasi::__WASI_ENXIO => "No such device or address",
|
||||
wasi::__WASI_EOVERFLOW => "Value too large for data type",
|
||||
wasi::__WASI_EOWNERDEAD => "Previous owner died",
|
||||
wasi::__WASI_EPERM => "Operation not permitted",
|
||||
wasi::__WASI_EPIPE => "Broken pipe",
|
||||
wasi::__WASI_EPROTO => "Protocol error",
|
||||
wasi::__WASI_EPROTONOSUPPORT => "Protocol not supported",
|
||||
wasi::__WASI_EPROTOTYPE => "Protocol wrong type for socket",
|
||||
wasi::__WASI_ERANGE => "Result not representable",
|
||||
wasi::__WASI_EROFS => "Read-only file system",
|
||||
wasi::__WASI_ESPIPE => "Invalid seek",
|
||||
wasi::__WASI_ESRCH => "No such process",
|
||||
wasi::__WASI_ESTALE => "Stale file handle",
|
||||
wasi::__WASI_ETIMEDOUT => "Operation timed out",
|
||||
wasi::__WASI_ETXTBSY => "Text file busy",
|
||||
wasi::__WASI_EXDEV => "Cross-device link",
|
||||
wasi::__WASI_ENOTCAPABLE => "Capabilities insufficient",
|
||||
wasi::__WASI_ERRNO_2BIG => "Argument list too long",
|
||||
wasi::__WASI_ERRNO_ACCES => "Permission denied",
|
||||
wasi::__WASI_ERRNO_ADDRINUSE => "Address in use",
|
||||
wasi::__WASI_ERRNO_ADDRNOTAVAIL => "Address not available",
|
||||
wasi::__WASI_ERRNO_AFNOSUPPORT => "Address family not supported by protocol",
|
||||
wasi::__WASI_ERRNO_AGAIN => "Resource temporarily unavailable",
|
||||
wasi::__WASI_ERRNO_ALREADY => "Operation already in progress",
|
||||
wasi::__WASI_ERRNO_BADF => "Bad file descriptor",
|
||||
wasi::__WASI_ERRNO_BADMSG => "Bad message",
|
||||
wasi::__WASI_ERRNO_BUSY => "Resource busy",
|
||||
wasi::__WASI_ERRNO_CANCELED => "Operation canceled",
|
||||
wasi::__WASI_ERRNO_CHILD => "No child process",
|
||||
wasi::__WASI_ERRNO_CONNABORTED => "Connection aborted",
|
||||
wasi::__WASI_ERRNO_CONNREFUSED => "Connection refused",
|
||||
wasi::__WASI_ERRNO_CONNRESET => "Connection reset by peer",
|
||||
wasi::__WASI_ERRNO_DEADLK => "Resource deadlock would occur",
|
||||
wasi::__WASI_ERRNO_DESTADDRREQ => "Destination address required",
|
||||
wasi::__WASI_ERRNO_DOM => "Domain error",
|
||||
wasi::__WASI_ERRNO_DQUOT => "Quota exceeded",
|
||||
wasi::__WASI_ERRNO_EXIST => "File exists",
|
||||
wasi::__WASI_ERRNO_FAULT => "Bad address",
|
||||
wasi::__WASI_ERRNO_FBIG => "File too large",
|
||||
wasi::__WASI_ERRNO_HOSTUNREACH => "Host is unreachable",
|
||||
wasi::__WASI_ERRNO_IDRM => "Identifier removed",
|
||||
wasi::__WASI_ERRNO_ILSEQ => "Illegal byte sequence",
|
||||
wasi::__WASI_ERRNO_INPROGRESS => "Operation in progress",
|
||||
wasi::__WASI_ERRNO_INTR => "Interrupted system call",
|
||||
wasi::__WASI_ERRNO_INVAL => "Invalid argument",
|
||||
wasi::__WASI_ERRNO_IO => "Remote I/O error",
|
||||
wasi::__WASI_ERRNO_ISCONN => "Socket is connected",
|
||||
wasi::__WASI_ERRNO_ISDIR => "Is a directory",
|
||||
wasi::__WASI_ERRNO_LOOP => "Symbolic link loop",
|
||||
wasi::__WASI_ERRNO_MFILE => "No file descriptors available",
|
||||
wasi::__WASI_ERRNO_MLINK => "Too many links",
|
||||
wasi::__WASI_ERRNO_MSGSIZE => "Message too large",
|
||||
wasi::__WASI_ERRNO_MULTIHOP => "Multihop attempted",
|
||||
wasi::__WASI_ERRNO_NAMETOOLONG => "Filename too long",
|
||||
wasi::__WASI_ERRNO_NETDOWN => "Network is down",
|
||||
wasi::__WASI_ERRNO_NETRESET => "Connection reset by network",
|
||||
wasi::__WASI_ERRNO_NETUNREACH => "Network unreachable",
|
||||
wasi::__WASI_ERRNO_NFILE => "Too many open files in system",
|
||||
wasi::__WASI_ERRNO_NOBUFS => "No buffer space available",
|
||||
wasi::__WASI_ERRNO_NODEV => "No such device",
|
||||
wasi::__WASI_ERRNO_NOENT => "No such file or directory",
|
||||
wasi::__WASI_ERRNO_NOEXEC => "Exec format error",
|
||||
wasi::__WASI_ERRNO_NOLCK => "No locks available",
|
||||
wasi::__WASI_ERRNO_NOLINK => "Link has been severed",
|
||||
wasi::__WASI_ERRNO_NOMEM => "Out of memory",
|
||||
wasi::__WASI_ERRNO_NOMSG => "No message of desired type",
|
||||
wasi::__WASI_ERRNO_NOPROTOOPT => "Protocol not available",
|
||||
wasi::__WASI_ERRNO_NOSPC => "No space left on device",
|
||||
wasi::__WASI_ERRNO_NOSYS => "Function not implemented",
|
||||
wasi::__WASI_ERRNO_NOTCONN => "Socket not connected",
|
||||
wasi::__WASI_ERRNO_NOTDIR => "Not a directory",
|
||||
wasi::__WASI_ERRNO_NOTEMPTY => "Directory not empty",
|
||||
wasi::__WASI_ERRNO_NOTRECOVERABLE => "State not recoverable",
|
||||
wasi::__WASI_ERRNO_NOTSOCK => "Not a socket",
|
||||
wasi::__WASI_ERRNO_NOTSUP => "Not supported",
|
||||
wasi::__WASI_ERRNO_NOTTY => "Not a tty",
|
||||
wasi::__WASI_ERRNO_NXIO => "No such device or address",
|
||||
wasi::__WASI_ERRNO_OVERFLOW => "Value too large for data type",
|
||||
wasi::__WASI_ERRNO_OWNERDEAD => "Previous owner died",
|
||||
wasi::__WASI_ERRNO_PERM => "Operation not permitted",
|
||||
wasi::__WASI_ERRNO_PIPE => "Broken pipe",
|
||||
wasi::__WASI_ERRNO_PROTO => "Protocol error",
|
||||
wasi::__WASI_ERRNO_PROTONOSUPPORT => "Protocol not supported",
|
||||
wasi::__WASI_ERRNO_PROTOTYPE => "Protocol wrong type for socket",
|
||||
wasi::__WASI_ERRNO_RANGE => "Result not representable",
|
||||
wasi::__WASI_ERRNO_ROFS => "Read-only file system",
|
||||
wasi::__WASI_ERRNO_SPIPE => "Invalid seek",
|
||||
wasi::__WASI_ERRNO_SRCH => "No such process",
|
||||
wasi::__WASI_ERRNO_STALE => "Stale file handle",
|
||||
wasi::__WASI_ERRNO_TIMEDOUT => "Operation timed out",
|
||||
wasi::__WASI_ERRNO_TXTBSY => "Text file busy",
|
||||
wasi::__WASI_ERRNO_XDEV => "Cross-device link",
|
||||
wasi::__WASI_ERRNO_NOTCAPABLE => "Capabilities insufficient",
|
||||
_ => panic!("unrecognized WASI errno value"),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ pub(crate) fn systemtime_to_timestamp(st: SystemTime) -> Result<u64> {
|
||||
/// Creates not-owned WASI path from byte slice.
|
||||
///
|
||||
/// NB WASI spec requires bytes to be valid UTF-8. Otherwise,
|
||||
/// `__WASI_EILSEQ` error is returned.
|
||||
/// `__WASI_ERRNO_ILSEQ` error is returned.
|
||||
pub(crate) fn path_from_slice<'a>(s: &'a [u8]) -> Result<&'a str> {
|
||||
str::from_utf8(s).map_err(|_| Error::EILSEQ)
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ use crate::wasi::*;
|
||||
use std::{io, slice};
|
||||
use wig::witx_host_types;
|
||||
|
||||
witx_host_types!("unstable" "wasi_unstable_preview0");
|
||||
witx_host_types!("snapshot" "wasi_snapshot_preview1");
|
||||
|
||||
pub(crate) unsafe fn ciovec_to_host(ciovec: &__wasi_ciovec_t) -> io::IoSlice {
|
||||
let slice = slice::from_raw_parts(ciovec.buf as *const u8, ciovec.buf_len);
|
||||
@@ -60,23 +60,23 @@ mod test {
|
||||
#[test]
|
||||
fn bindgen_test_layout___wasi_prestat_t___wasi_prestat_u___wasi_prestat_u_dir_t() {
|
||||
assert_eq!(
|
||||
::std::mem::size_of::<__wasi_prestat_dir>(),
|
||||
::std::mem::size_of::<__wasi_prestat_dir_t>(),
|
||||
8usize,
|
||||
concat!("Size of: ", stringify!(__wasi_prestat_dir))
|
||||
concat!("Size of: ", stringify!(__wasi_prestat_dir_t))
|
||||
);
|
||||
assert_eq!(
|
||||
::std::mem::align_of::<__wasi_prestat_dir>(),
|
||||
::std::mem::align_of::<__wasi_prestat_dir_t>(),
|
||||
8usize,
|
||||
concat!("Alignment of ", stringify!(__wasi_prestat_dir))
|
||||
concat!("Alignment of ", stringify!(__wasi_prestat_dir_t))
|
||||
);
|
||||
assert_eq!(
|
||||
unsafe {
|
||||
&(*(::std::ptr::null::<__wasi_prestat_dir>())).pr_name_len as *const _ as usize
|
||||
&(*(::std::ptr::null::<__wasi_prestat_dir_t>())).pr_name_len as *const _ as usize
|
||||
},
|
||||
0usize,
|
||||
concat!(
|
||||
"Offset of field: ",
|
||||
stringify!(__wasi_prestat_dir),
|
||||
stringify!(__wasi_prestat_dir_t),
|
||||
"::",
|
||||
stringify!(pr_name_len)
|
||||
)
|
||||
@@ -86,21 +86,21 @@ mod test {
|
||||
#[test]
|
||||
fn bindgen_test_layout___wasi_prestat_t___wasi_prestat_u() {
|
||||
assert_eq!(
|
||||
::std::mem::size_of::<__wasi_prestat_u>(),
|
||||
::std::mem::size_of::<__wasi_prestat_u_t>(),
|
||||
8usize,
|
||||
concat!("Size of: ", stringify!(__wasi_prestat_u))
|
||||
);
|
||||
assert_eq!(
|
||||
::std::mem::align_of::<__wasi_prestat_u>(),
|
||||
::std::mem::align_of::<__wasi_prestat_u_t>(),
|
||||
8usize,
|
||||
concat!("Alignment of ", stringify!(__wasi_prestat_u))
|
||||
);
|
||||
assert_eq!(
|
||||
unsafe { &(*(::std::ptr::null::<__wasi_prestat_u>())).dir as *const _ as usize },
|
||||
unsafe { &(*(::std::ptr::null::<__wasi_prestat_u_t>())).dir as *const _ as usize },
|
||||
0usize,
|
||||
concat!(
|
||||
"Offset of field: ",
|
||||
stringify!(__wasi_prestat_u),
|
||||
stringify!(__wasi_prestat_u_t),
|
||||
"::",
|
||||
stringify!(dir)
|
||||
)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#![allow(non_camel_case_types)]
|
||||
use crate::ctx::WasiCtx;
|
||||
use crate::{wasi, wasi32};
|
||||
use crate::{hostcalls_impl, wasi, wasi32};
|
||||
|
||||
hostcalls! {
|
||||
pub unsafe fn fd_close(wasi_ctx: &mut WasiCtx, fd: wasi::__wasi_fd_t,) -> wasi::__wasi_errno_t;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#![allow(non_camel_case_types)]
|
||||
use crate::ctx::WasiCtx;
|
||||
use crate::{wasi, wasi32};
|
||||
use crate::{hostcalls_impl, wasi, wasi32};
|
||||
use log::trace;
|
||||
use wasi_common_cbindgen::wasi_common_cbindgen;
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@ pub(crate) unsafe fn fd_datasync(wasi_ctx: &WasiCtx, fd: wasi::__wasi_fd_t) -> R
|
||||
|
||||
let fd = wasi_ctx
|
||||
.get_fd_entry(fd)?
|
||||
.as_descriptor(wasi::__WASI_RIGHT_FD_DATASYNC, 0)?
|
||||
.as_descriptor(wasi::__WASI_RIGHTS_FD_DATASYNC, 0)?
|
||||
.as_file()?;
|
||||
|
||||
fd.sync_data().map_err(Into::into)
|
||||
@@ -61,7 +61,7 @@ pub(crate) unsafe fn fd_pread(
|
||||
|
||||
let fd = wasi_ctx
|
||||
.get_fd_entry(fd)?
|
||||
.as_descriptor(wasi::__WASI_RIGHT_FD_READ | wasi::__WASI_RIGHT_FD_SEEK, 0)?
|
||||
.as_descriptor(wasi::__WASI_RIGHTS_FD_READ | wasi::__WASI_RIGHTS_FD_SEEK, 0)?
|
||||
.as_file()?;
|
||||
|
||||
let iovs = dec_iovec_slice(memory, iovs_ptr, iovs_len)?;
|
||||
@@ -110,7 +110,10 @@ pub(crate) unsafe fn fd_pwrite(
|
||||
|
||||
let fd = wasi_ctx
|
||||
.get_fd_entry(fd)?
|
||||
.as_descriptor(wasi::__WASI_RIGHT_FD_WRITE | wasi::__WASI_RIGHT_FD_SEEK, 0)?
|
||||
.as_descriptor(
|
||||
wasi::__WASI_RIGHTS_FD_WRITE | wasi::__WASI_RIGHTS_FD_SEEK,
|
||||
0,
|
||||
)?
|
||||
.as_file()?;
|
||||
let iovs = dec_ciovec_slice(memory, iovs_ptr, iovs_len)?;
|
||||
|
||||
@@ -156,7 +159,7 @@ pub(crate) unsafe fn fd_read(
|
||||
|
||||
let maybe_host_nread = match wasi_ctx
|
||||
.get_fd_entry_mut(fd)?
|
||||
.as_descriptor_mut(wasi::__WASI_RIGHT_FD_READ, 0)?
|
||||
.as_descriptor_mut(wasi::__WASI_RIGHTS_FD_READ, 0)?
|
||||
{
|
||||
Descriptor::OsFile(file) => file.read_vectored(&mut iovs),
|
||||
Descriptor::Stdin => io::stdin().lock().read_vectored(&mut iovs),
|
||||
@@ -225,9 +228,9 @@ pub(crate) unsafe fn fd_seek(
|
||||
);
|
||||
|
||||
let rights = if offset == 0 && whence == wasi::__WASI_WHENCE_CUR {
|
||||
wasi::__WASI_RIGHT_FD_TELL
|
||||
wasi::__WASI_RIGHTS_FD_TELL
|
||||
} else {
|
||||
wasi::__WASI_RIGHT_FD_SEEK | wasi::__WASI_RIGHT_FD_TELL
|
||||
wasi::__WASI_RIGHTS_FD_SEEK | wasi::__WASI_RIGHTS_FD_TELL
|
||||
};
|
||||
let fd = wasi_ctx
|
||||
.get_fd_entry_mut(fd)?
|
||||
@@ -257,7 +260,7 @@ pub(crate) unsafe fn fd_tell(
|
||||
|
||||
let fd = wasi_ctx
|
||||
.get_fd_entry_mut(fd)?
|
||||
.as_descriptor_mut(wasi::__WASI_RIGHT_FD_TELL, 0)?
|
||||
.as_descriptor_mut(wasi::__WASI_RIGHTS_FD_TELL, 0)?
|
||||
.as_file_mut()?;
|
||||
|
||||
let host_offset = fd.seek(SeekFrom::Current(0))?;
|
||||
@@ -333,7 +336,7 @@ pub(crate) unsafe fn fd_sync(wasi_ctx: &WasiCtx, fd: wasi::__wasi_fd_t) -> Resul
|
||||
|
||||
let fd = wasi_ctx
|
||||
.get_fd_entry(fd)?
|
||||
.as_descriptor(wasi::__WASI_RIGHT_FD_SYNC, 0)?
|
||||
.as_descriptor(wasi::__WASI_RIGHTS_FD_SYNC, 0)?
|
||||
.as_file()?;
|
||||
fd.sync_all().map_err(Into::into)
|
||||
}
|
||||
@@ -360,7 +363,7 @@ pub(crate) unsafe fn fd_write(
|
||||
// perform unbuffered writes
|
||||
let host_nwritten = match wasi_ctx
|
||||
.get_fd_entry_mut(fd)?
|
||||
.as_descriptor_mut(wasi::__WASI_RIGHT_FD_WRITE, 0)?
|
||||
.as_descriptor_mut(wasi::__WASI_RIGHTS_FD_WRITE, 0)?
|
||||
{
|
||||
Descriptor::OsFile(file) => file.write_vectored(&iovs)?,
|
||||
Descriptor::Stdin => return Err(Error::EBADF),
|
||||
@@ -397,7 +400,7 @@ pub(crate) unsafe fn fd_advise(
|
||||
|
||||
let fd = wasi_ctx
|
||||
.get_fd_entry(fd)?
|
||||
.as_descriptor(wasi::__WASI_RIGHT_FD_ADVISE, 0)?
|
||||
.as_descriptor(wasi::__WASI_RIGHTS_FD_ADVISE, 0)?
|
||||
.as_file()?;
|
||||
|
||||
hostcalls_impl::fd_advise(fd, advice, offset, len)
|
||||
@@ -413,7 +416,7 @@ pub(crate) unsafe fn fd_allocate(
|
||||
|
||||
let fd = wasi_ctx
|
||||
.get_fd_entry(fd)?
|
||||
.as_descriptor(wasi::__WASI_RIGHT_FD_ALLOCATE, 0)?
|
||||
.as_descriptor(wasi::__WASI_RIGHTS_FD_ALLOCATE, 0)?
|
||||
.as_file()?;
|
||||
|
||||
let metadata = fd.metadata()?;
|
||||
@@ -450,7 +453,7 @@ pub(crate) unsafe fn path_create_directory(
|
||||
|
||||
trace!(" | (path_ptr,path_len)='{}'", path);
|
||||
|
||||
let rights = wasi::__WASI_RIGHT_PATH_OPEN | wasi::__WASI_RIGHT_PATH_CREATE_DIRECTORY;
|
||||
let rights = wasi::__WASI_RIGHTS_PATH_OPEN | wasi::__WASI_RIGHTS_PATH_CREATE_DIRECTORY;
|
||||
let fe = wasi_ctx.get_fd_entry(dirfd)?;
|
||||
let resolved = path_get(fe, rights, 0, 0, path, false)?;
|
||||
|
||||
@@ -489,7 +492,7 @@ pub(crate) unsafe fn path_link(
|
||||
let new_fe = wasi_ctx.get_fd_entry(new_dirfd)?;
|
||||
let resolved_old = path_get(
|
||||
old_fe,
|
||||
wasi::__WASI_RIGHT_PATH_LINK_SOURCE,
|
||||
wasi::__WASI_RIGHTS_PATH_LINK_SOURCE,
|
||||
0,
|
||||
0,
|
||||
old_path,
|
||||
@@ -497,7 +500,7 @@ pub(crate) unsafe fn path_link(
|
||||
)?;
|
||||
let resolved_new = path_get(
|
||||
new_fe,
|
||||
wasi::__WASI_RIGHT_PATH_LINK_TARGET,
|
||||
wasi::__WASI_RIGHTS_PATH_LINK_TARGET,
|
||||
0,
|
||||
0,
|
||||
new_path,
|
||||
@@ -549,16 +552,16 @@ pub(crate) unsafe fn path_open(
|
||||
needed_inheriting,
|
||||
dirflags,
|
||||
path,
|
||||
oflags & wasi::__WASI_O_CREAT != 0,
|
||||
oflags & wasi::__WASI_OFLAGS_CREAT != 0,
|
||||
)?;
|
||||
|
||||
// which open mode do we need?
|
||||
let read = fs_rights_base & (wasi::__WASI_RIGHT_FD_READ | wasi::__WASI_RIGHT_FD_READDIR) != 0;
|
||||
let read = fs_rights_base & (wasi::__WASI_RIGHTS_FD_READ | wasi::__WASI_RIGHTS_FD_READDIR) != 0;
|
||||
let write = fs_rights_base
|
||||
& (wasi::__WASI_RIGHT_FD_DATASYNC
|
||||
| wasi::__WASI_RIGHT_FD_WRITE
|
||||
| wasi::__WASI_RIGHT_FD_ALLOCATE
|
||||
| wasi::__WASI_RIGHT_FD_FILESTAT_SET_SIZE)
|
||||
& (wasi::__WASI_RIGHTS_FD_DATASYNC
|
||||
| wasi::__WASI_RIGHTS_FD_WRITE
|
||||
| wasi::__WASI_RIGHTS_FD_ALLOCATE
|
||||
| wasi::__WASI_RIGHTS_FD_FILESTAT_SET_SIZE)
|
||||
!= 0;
|
||||
|
||||
let fd = hostcalls_impl::path_open(resolved, read, write, oflags, fs_flags)?;
|
||||
@@ -597,7 +600,7 @@ pub(crate) unsafe fn fd_readdir(
|
||||
|
||||
let file = wasi_ctx
|
||||
.get_fd_entry_mut(fd)?
|
||||
.as_descriptor_mut(wasi::__WASI_RIGHT_FD_READDIR, 0)?
|
||||
.as_descriptor_mut(wasi::__WASI_RIGHTS_FD_READDIR, 0)?
|
||||
.as_file_mut()?;
|
||||
let host_buf = dec_slice_of_mut_u8(memory, buf, buf_len)?;
|
||||
|
||||
@@ -637,7 +640,7 @@ pub(crate) unsafe fn path_readlink(
|
||||
trace!(" | (path_ptr,path_len)='{}'", &path);
|
||||
|
||||
let fe = wasi_ctx.get_fd_entry(dirfd)?;
|
||||
let resolved = path_get(fe, wasi::__WASI_RIGHT_PATH_READLINK, 0, 0, &path, false)?;
|
||||
let resolved = path_get(fe, wasi::__WASI_RIGHTS_PATH_READLINK, 0, 0, &path, false)?;
|
||||
|
||||
let mut buf = dec_slice_of_mut_u8(memory, buf_ptr, buf_len)?;
|
||||
|
||||
@@ -679,7 +682,7 @@ pub(crate) unsafe fn path_rename(
|
||||
let new_fe = wasi_ctx.get_fd_entry(new_dirfd)?;
|
||||
let resolved_old = path_get(
|
||||
old_fe,
|
||||
wasi::__WASI_RIGHT_PATH_RENAME_SOURCE,
|
||||
wasi::__WASI_RIGHTS_PATH_RENAME_SOURCE,
|
||||
0,
|
||||
0,
|
||||
old_path,
|
||||
@@ -687,7 +690,7 @@ pub(crate) unsafe fn path_rename(
|
||||
)?;
|
||||
let resolved_new = path_get(
|
||||
new_fe,
|
||||
wasi::__WASI_RIGHT_PATH_RENAME_TARGET,
|
||||
wasi::__WASI_RIGHTS_PATH_RENAME_TARGET,
|
||||
0,
|
||||
0,
|
||||
new_path,
|
||||
@@ -738,7 +741,7 @@ pub(crate) unsafe fn fd_filestat_set_times(
|
||||
|
||||
let fd = wasi_ctx
|
||||
.get_fd_entry(fd)?
|
||||
.as_descriptor(wasi::__WASI_RIGHT_FD_FILESTAT_SET_TIMES, 0)?
|
||||
.as_descriptor(wasi::__WASI_RIGHTS_FD_FILESTAT_SET_TIMES, 0)?
|
||||
.as_file()?;
|
||||
|
||||
fd_filestat_set_times_impl(fd, st_atim, st_mtim, fst_flags)
|
||||
@@ -750,10 +753,10 @@ pub(crate) fn fd_filestat_set_times_impl(
|
||||
st_mtim: wasi::__wasi_timestamp_t,
|
||||
fst_flags: wasi::__wasi_fstflags_t,
|
||||
) -> Result<()> {
|
||||
let set_atim = fst_flags & wasi::__WASI_FILESTAT_SET_ATIM != 0;
|
||||
let set_atim_now = fst_flags & wasi::__WASI_FILESTAT_SET_ATIM_NOW != 0;
|
||||
let set_mtim = fst_flags & wasi::__WASI_FILESTAT_SET_MTIM != 0;
|
||||
let set_mtim_now = fst_flags & wasi::__WASI_FILESTAT_SET_MTIM_NOW != 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_mtim = fst_flags & wasi::__WASI_FSTFLAGS_MTIM != 0;
|
||||
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);
|
||||
@@ -789,7 +792,7 @@ pub(crate) unsafe fn fd_filestat_set_size(
|
||||
|
||||
let fd = wasi_ctx
|
||||
.get_fd_entry(fd)?
|
||||
.as_descriptor(wasi::__WASI_RIGHT_FD_FILESTAT_SET_SIZE, 0)?
|
||||
.as_descriptor(wasi::__WASI_RIGHTS_FD_FILESTAT_SET_SIZE, 0)?
|
||||
.as_file()?;
|
||||
|
||||
// This check will be unnecessary when rust-lang/rust#63326 is fixed
|
||||
@@ -824,7 +827,7 @@ pub(crate) unsafe fn path_filestat_get(
|
||||
let fe = wasi_ctx.get_fd_entry(dirfd)?;
|
||||
let resolved = path_get(
|
||||
fe,
|
||||
wasi::__WASI_RIGHT_PATH_FILESTAT_GET,
|
||||
wasi::__WASI_RIGHTS_PATH_FILESTAT_GET,
|
||||
0,
|
||||
dirflags,
|
||||
path,
|
||||
@@ -865,7 +868,7 @@ pub(crate) unsafe fn path_filestat_set_times(
|
||||
let fe = wasi_ctx.get_fd_entry(dirfd)?;
|
||||
let resolved = path_get(
|
||||
fe,
|
||||
wasi::__WASI_RIGHT_PATH_FILESTAT_SET_TIMES,
|
||||
wasi::__WASI_RIGHTS_PATH_FILESTAT_SET_TIMES,
|
||||
0,
|
||||
dirflags,
|
||||
path,
|
||||
@@ -900,7 +903,7 @@ pub(crate) unsafe fn path_symlink(
|
||||
trace!(" | (new_path_ptr,new_path_len)='{}'", new_path);
|
||||
|
||||
let fe = wasi_ctx.get_fd_entry(dirfd)?;
|
||||
let resolved_new = path_get(fe, wasi::__WASI_RIGHT_PATH_SYMLINK, 0, 0, new_path, true)?;
|
||||
let resolved_new = path_get(fe, wasi::__WASI_RIGHTS_PATH_SYMLINK, 0, 0, new_path, true)?;
|
||||
|
||||
hostcalls_impl::path_symlink(old_path, resolved_new)
|
||||
}
|
||||
@@ -924,7 +927,7 @@ pub(crate) unsafe fn path_unlink_file(
|
||||
trace!(" | (path_ptr,path_len)='{}'", path);
|
||||
|
||||
let fe = wasi_ctx.get_fd_entry(dirfd)?;
|
||||
let resolved = path_get(fe, wasi::__WASI_RIGHT_PATH_UNLINK_FILE, 0, 0, path, false)?;
|
||||
let resolved = path_get(fe, wasi::__WASI_RIGHTS_PATH_UNLINK_FILE, 0, 0, path, false)?;
|
||||
|
||||
hostcalls_impl::path_unlink_file(resolved)
|
||||
}
|
||||
@@ -950,7 +953,7 @@ pub(crate) unsafe fn path_remove_directory(
|
||||
let fe = wasi_ctx.get_fd_entry(dirfd)?;
|
||||
let resolved = path_get(
|
||||
fe,
|
||||
wasi::__WASI_RIGHT_PATH_REMOVE_DIRECTORY,
|
||||
wasi::__WASI_RIGHTS_PATH_REMOVE_DIRECTORY,
|
||||
0,
|
||||
0,
|
||||
path,
|
||||
@@ -988,8 +991,8 @@ pub(crate) unsafe fn fd_prestat_get(
|
||||
prestat_ptr,
|
||||
host::__wasi_prestat_t {
|
||||
pr_type: wasi::__WASI_PREOPENTYPE_DIR,
|
||||
u: host::__wasi_prestat_u {
|
||||
dir: host::__wasi_prestat_dir {
|
||||
u: host::__wasi_prestat_u_t {
|
||||
dir: host::__wasi_prestat_dir_t {
|
||||
pr_name_len: path.len(),
|
||||
},
|
||||
},
|
||||
|
||||
@@ -118,9 +118,9 @@ pub(crate) fn path_get(
|
||||
}
|
||||
Err(e) => {
|
||||
match e.as_wasi_errno() {
|
||||
wasi::__WASI_ELOOP
|
||||
| wasi::__WASI_EMLINK
|
||||
| wasi::__WASI_ENOTDIR =>
|
||||
wasi::__WASI_ERRNO_LOOP
|
||||
| wasi::__WASI_ERRNO_MLINK
|
||||
| wasi::__WASI_ERRNO_NOTDIR =>
|
||||
// Check to see if it was a symlink. Linux indicates
|
||||
// this with ENOTDIR because of the O_DIRECTORY flag.
|
||||
{
|
||||
@@ -155,7 +155,7 @@ pub(crate) fn path_get(
|
||||
|
||||
continue;
|
||||
} else if ends_with_slash
|
||||
|| (dirflags & wasi::__WASI_LOOKUP_SYMLINK_FOLLOW) != 0
|
||||
|| (dirflags & wasi::__WASI_LOOKUPFLAGS_SYMLINK_FOLLOW) != 0
|
||||
{
|
||||
// if there's a trailing slash, or if `LOOKUP_SYMLINK_FOLLOW` is set, attempt
|
||||
// symlink expansion
|
||||
@@ -179,12 +179,12 @@ pub(crate) fn path_get(
|
||||
continue;
|
||||
}
|
||||
Err(e) => {
|
||||
if e.as_wasi_errno() != wasi::__WASI_EINVAL
|
||||
&& e.as_wasi_errno() != wasi::__WASI_ENOENT
|
||||
if e.as_wasi_errno() != wasi::__WASI_ERRNO_INVAL
|
||||
&& e.as_wasi_errno() != wasi::__WASI_ERRNO_NOENT
|
||||
// this handles the cases when trying to link to
|
||||
// a destination that already exists, and the target
|
||||
// path contains a slash
|
||||
&& e.as_wasi_errno() != wasi::__WASI_ENOTDIR
|
||||
&& e.as_wasi_errno() != wasi::__WASI_ERRNO_NOTDIR
|
||||
{
|
||||
return Err(e);
|
||||
}
|
||||
|
||||
@@ -240,9 +240,9 @@ pub(crate) fn poll_oneoff(
|
||||
{
|
||||
let wasi_fd = unsafe { subscription.u.fd_readwrite.file_descriptor };
|
||||
let rights = if r#type == wasi::__WASI_EVENTTYPE_FD_READ {
|
||||
wasi::__WASI_RIGHT_FD_READ
|
||||
wasi::__WASI_RIGHTS_FD_READ
|
||||
} else {
|
||||
wasi::__WASI_RIGHT_FD_WRITE
|
||||
wasi::__WASI_RIGHTS_FD_WRITE
|
||||
};
|
||||
|
||||
match unsafe {
|
||||
@@ -260,7 +260,7 @@ pub(crate) fn poll_oneoff(
|
||||
userdata: subscription.userdata,
|
||||
r#type,
|
||||
error: err.as_wasi_errno(),
|
||||
u: wasi::__wasi_event_u {
|
||||
u: wasi::__wasi_event_u_t {
|
||||
fd_readwrite: wasi::__wasi_event_fd_readwrite_t {
|
||||
nbytes: 0,
|
||||
flags: 0,
|
||||
@@ -292,7 +292,7 @@ pub(crate) fn poll_oneoff(
|
||||
fn wasi_clock_to_relative_ns_delay(wasi_clock: wasi::__wasi_subscription_clock_t) -> Result<u128> {
|
||||
use std::time::SystemTime;
|
||||
|
||||
if wasi_clock.flags != wasi::__WASI_SUBSCRIPTION_CLOCK_ABSTIME {
|
||||
if wasi_clock.flags != wasi::__WASI_SUBCLOCKFLAGS_SUBSCRIPTION_CLOCK_ABSTIME {
|
||||
return Ok(u128::from(wasi_clock.timeout));
|
||||
}
|
||||
let now: u128 = SystemTime::now()
|
||||
|
||||
@@ -33,6 +33,7 @@ pub mod fs;
|
||||
mod host;
|
||||
pub mod hostcalls;
|
||||
mod memory;
|
||||
pub mod old;
|
||||
pub mod wasi;
|
||||
pub mod wasi32;
|
||||
|
||||
|
||||
@@ -2,8 +2,24 @@ macro_rules! hostcalls {
|
||||
($(pub unsafe fn $name:ident($($arg:ident: $ty:ty,)*) -> $ret:ty;)*) => ($(
|
||||
#[wasi_common_cbindgen::wasi_common_cbindgen]
|
||||
pub unsafe fn $name($($arg: $ty,)*) -> $ret {
|
||||
let ret = match crate::hostcalls_impl::$name($($arg,)*) {
|
||||
Ok(()) => crate::wasi::__WASI_ESUCCESS,
|
||||
let ret = match hostcalls_impl::$name($($arg,)*) {
|
||||
Ok(()) => wasi::__WASI_ERRNO_SUCCESS,
|
||||
Err(e) => e.as_wasi_errno(),
|
||||
};
|
||||
|
||||
ret
|
||||
}
|
||||
)*)
|
||||
}
|
||||
|
||||
// Like `hostcalls`, but uses `wasi_common_cbindgen_old`, which means
|
||||
// it doesn't declare a non-mangled function name.
|
||||
macro_rules! hostcalls_old {
|
||||
($(pub unsafe fn $name:ident($($arg:ident: $ty:ty,)*) -> $ret:ty;)*) => ($(
|
||||
#[wasi_common_cbindgen::wasi_common_cbindgen_old]
|
||||
pub unsafe fn $name($($arg: $ty,)*) -> $ret {
|
||||
let ret = match hostcalls_impl::$name($($arg,)*) {
|
||||
Ok(()) => wasi::__WASI_ERRNO_SUCCESS,
|
||||
Err(e) => e.as_wasi_errno(),
|
||||
};
|
||||
|
||||
|
||||
@@ -252,14 +252,14 @@ pub(crate) fn dec_filestat_byref(
|
||||
let raw = dec_raw_byref::<wasi::__wasi_filestat_t>(memory, filestat_ptr)?;
|
||||
|
||||
Ok(wasi::__wasi_filestat_t {
|
||||
st_dev: PrimInt::from_le(raw.st_dev),
|
||||
st_ino: PrimInt::from_le(raw.st_ino),
|
||||
st_filetype: PrimInt::from_le(raw.st_filetype),
|
||||
st_nlink: PrimInt::from_le(raw.st_nlink),
|
||||
st_size: PrimInt::from_le(raw.st_size),
|
||||
st_atim: PrimInt::from_le(raw.st_atim),
|
||||
st_mtim: PrimInt::from_le(raw.st_mtim),
|
||||
st_ctim: PrimInt::from_le(raw.st_ctim),
|
||||
dev: PrimInt::from_le(raw.dev),
|
||||
ino: PrimInt::from_le(raw.ino),
|
||||
filetype: PrimInt::from_le(raw.filetype),
|
||||
nlink: PrimInt::from_le(raw.nlink),
|
||||
size: PrimInt::from_le(raw.size),
|
||||
atim: PrimInt::from_le(raw.atim),
|
||||
mtim: PrimInt::from_le(raw.mtim),
|
||||
ctim: PrimInt::from_le(raw.ctim),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -269,14 +269,14 @@ pub(crate) fn enc_filestat_byref(
|
||||
filestat: wasi::__wasi_filestat_t,
|
||||
) -> Result<()> {
|
||||
let raw = wasi::__wasi_filestat_t {
|
||||
st_dev: PrimInt::to_le(filestat.st_dev),
|
||||
st_ino: PrimInt::to_le(filestat.st_ino),
|
||||
st_filetype: PrimInt::to_le(filestat.st_filetype),
|
||||
st_nlink: PrimInt::to_le(filestat.st_nlink),
|
||||
st_size: PrimInt::to_le(filestat.st_size),
|
||||
st_atim: PrimInt::to_le(filestat.st_atim),
|
||||
st_mtim: PrimInt::to_le(filestat.st_mtim),
|
||||
st_ctim: PrimInt::to_le(filestat.st_ctim),
|
||||
dev: PrimInt::to_le(filestat.dev),
|
||||
ino: PrimInt::to_le(filestat.ino),
|
||||
filetype: PrimInt::to_le(filestat.filetype),
|
||||
nlink: PrimInt::to_le(filestat.nlink),
|
||||
size: PrimInt::to_le(filestat.size),
|
||||
atim: PrimInt::to_le(filestat.atim),
|
||||
mtim: PrimInt::to_le(filestat.mtim),
|
||||
ctim: PrimInt::to_le(filestat.ctim),
|
||||
};
|
||||
|
||||
enc_raw_byref::<wasi::__wasi_filestat_t>(memory, filestat_ptr, raw)
|
||||
@@ -332,8 +332,8 @@ pub(crate) fn dec_prestat_byref(
|
||||
match PrimInt::from_le(raw.pr_type) {
|
||||
wasi::__WASI_PREOPENTYPE_DIR => Ok(host::__wasi_prestat_t {
|
||||
pr_type: wasi::__WASI_PREOPENTYPE_DIR,
|
||||
u: host::__wasi_prestat_u {
|
||||
dir: host::__wasi_prestat_dir {
|
||||
u: host::__wasi_prestat_u_t {
|
||||
dir: host::__wasi_prestat_dir_t {
|
||||
pr_name_len: dec_usize(PrimInt::from_le(unsafe { raw.u.dir.pr_name_len })),
|
||||
},
|
||||
},
|
||||
@@ -350,8 +350,8 @@ pub(crate) fn enc_prestat_byref(
|
||||
let raw = match prestat.pr_type {
|
||||
wasi::__WASI_PREOPENTYPE_DIR => Ok(wasi32::__wasi_prestat_t {
|
||||
pr_type: PrimInt::to_le(wasi::__WASI_PREOPENTYPE_DIR),
|
||||
u: wasi32::__wasi_prestat_u {
|
||||
dir: wasi32::__wasi_prestat_dir {
|
||||
u: wasi32::__wasi_prestat_u_t {
|
||||
dir: wasi32::__wasi_prestat_dir_t {
|
||||
pr_name_len: enc_usize(unsafe { prestat.u.dir.pr_name_len }),
|
||||
},
|
||||
},
|
||||
@@ -413,11 +413,10 @@ pub(crate) fn dec_subscriptions(
|
||||
let r#type = PrimInt::from_le(raw_subscription.r#type);
|
||||
let raw_u = raw_subscription.u;
|
||||
let u = match r#type {
|
||||
wasi::__WASI_EVENTTYPE_CLOCK => wasi::__wasi_subscription_u {
|
||||
wasi::__WASI_EVENTTYPE_CLOCK => wasi::__wasi_subscription_u_t {
|
||||
clock: unsafe {
|
||||
wasi::__wasi_subscription_clock_t {
|
||||
identifier: PrimInt::from_le(raw_u.clock.identifier),
|
||||
clock_id: PrimInt::from_le(raw_u.clock.clock_id),
|
||||
id: PrimInt::from_le(raw_u.clock.id),
|
||||
timeout: PrimInt::from_le(raw_u.clock.timeout),
|
||||
precision: PrimInt::from_le(raw_u.clock.precision),
|
||||
flags: PrimInt::from_le(raw_u.clock.flags),
|
||||
@@ -425,7 +424,7 @@ pub(crate) fn dec_subscriptions(
|
||||
},
|
||||
},
|
||||
wasi::__WASI_EVENTTYPE_FD_READ | wasi::__WASI_EVENTTYPE_FD_WRITE => {
|
||||
wasi::__wasi_subscription_u {
|
||||
wasi::__wasi_subscription_u_t {
|
||||
fd_readwrite: wasi::__wasi_subscription_fd_readwrite_t {
|
||||
file_descriptor: PrimInt::from_le(unsafe {
|
||||
raw_u.fd_readwrite.file_descriptor
|
||||
@@ -462,7 +461,7 @@ pub(crate) fn enc_events(
|
||||
userdata: PrimInt::to_le(event.userdata),
|
||||
r#type: PrimInt::to_le(event.r#type),
|
||||
error: PrimInt::to_le(event.error),
|
||||
u: wasi::__wasi_event_u {
|
||||
u: wasi::__wasi_event_u_t {
|
||||
fd_readwrite: wasi::__wasi_event_fd_readwrite_t {
|
||||
nbytes: PrimInt::to_le(fd_readwrite.nbytes),
|
||||
flags: PrimInt::to_le(fd_readwrite.flags),
|
||||
|
||||
1
crates/wasi-common/src/old/mod.rs
Normal file
1
crates/wasi-common/src/old/mod.rs
Normal file
@@ -0,0 +1 @@
|
||||
pub mod snapshot_0;
|
||||
335
crates/wasi-common/src/old/snapshot_0/ctx.rs
Normal file
335
crates/wasi-common/src/old/snapshot_0/ctx.rs
Normal file
@@ -0,0 +1,335 @@
|
||||
use crate::old::snapshot_0::fdentry::FdEntry;
|
||||
use crate::old::snapshot_0::{wasi, Error, Result};
|
||||
use std::borrow::Borrow;
|
||||
use std::collections::HashMap;
|
||||
use std::env;
|
||||
use std::ffi::{CString, OsString};
|
||||
use std::fs::File;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
enum PendingFdEntry {
|
||||
Thunk(fn() -> Result<FdEntry>),
|
||||
File(File),
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for PendingFdEntry {
|
||||
fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Self::Thunk(f) => write!(
|
||||
fmt,
|
||||
"PendingFdEntry::Thunk({:p})",
|
||||
f as *const fn() -> Result<FdEntry>
|
||||
),
|
||||
Self::File(f) => write!(fmt, "PendingFdEntry::File({:?})", f),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, Hash, PartialEq)]
|
||||
enum PendingCString {
|
||||
Bytes(Vec<u8>),
|
||||
OsString(OsString),
|
||||
}
|
||||
|
||||
impl From<Vec<u8>> for PendingCString {
|
||||
fn from(bytes: Vec<u8>) -> Self {
|
||||
Self::Bytes(bytes)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<OsString> for PendingCString {
|
||||
fn from(s: OsString) -> Self {
|
||||
Self::OsString(s)
|
||||
}
|
||||
}
|
||||
|
||||
impl PendingCString {
|
||||
fn into_string(self) -> Result<String> {
|
||||
match self {
|
||||
Self::Bytes(v) => String::from_utf8(v).map_err(|_| Error::EILSEQ),
|
||||
Self::OsString(s) => s.into_string().map_err(|_| Error::EILSEQ),
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a `CString` containing valid UTF-8, or fail with `Error::EILSEQ`.
|
||||
fn into_utf8_cstring(self) -> Result<CString> {
|
||||
self.into_string()
|
||||
.and_then(|s| CString::new(s).map_err(|_| Error::EILSEQ))
|
||||
}
|
||||
}
|
||||
|
||||
/// A builder allowing customizable construction of `WasiCtx` instances.
|
||||
pub struct WasiCtxBuilder {
|
||||
fds: HashMap<wasi::__wasi_fd_t, PendingFdEntry>,
|
||||
preopens: Vec<(PathBuf, File)>,
|
||||
args: Vec<PendingCString>,
|
||||
env: HashMap<PendingCString, PendingCString>,
|
||||
}
|
||||
|
||||
impl WasiCtxBuilder {
|
||||
/// Builder for a new `WasiCtx`.
|
||||
pub fn new() -> Self {
|
||||
let mut builder = Self {
|
||||
fds: HashMap::new(),
|
||||
preopens: Vec::new(),
|
||||
args: vec![],
|
||||
env: HashMap::new(),
|
||||
};
|
||||
|
||||
builder.fds.insert(0, PendingFdEntry::Thunk(FdEntry::null));
|
||||
builder.fds.insert(1, PendingFdEntry::Thunk(FdEntry::null));
|
||||
builder.fds.insert(2, PendingFdEntry::Thunk(FdEntry::null));
|
||||
|
||||
builder
|
||||
}
|
||||
|
||||
/// Add arguments to the command-line arguments list.
|
||||
///
|
||||
/// 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 {
|
||||
self.args = args
|
||||
.into_iter()
|
||||
.map(|arg| arg.as_ref().to_vec().into())
|
||||
.collect();
|
||||
self
|
||||
}
|
||||
|
||||
/// 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
|
||||
/// with `Error::EILSEQ`.
|
||||
pub fn arg<S: AsRef<[u8]>>(mut self, arg: S) -> Self {
|
||||
self.args.push(arg.as_ref().to_vec().into());
|
||||
self
|
||||
}
|
||||
|
||||
/// Inherit the command-line arguments from the host process.
|
||||
///
|
||||
/// If any arguments from the host process contain invalid UTF-8, `WasiCtxBuilder::build()` will
|
||||
/// fail with `Error::EILSEQ`.
|
||||
pub fn inherit_args(mut self) -> Self {
|
||||
self.args = env::args_os().map(PendingCString::OsString).collect();
|
||||
self
|
||||
}
|
||||
|
||||
/// Inherit the stdin, stdout, and stderr streams from the host process.
|
||||
pub fn inherit_stdio(mut self) -> Self {
|
||||
self.fds
|
||||
.insert(0, PendingFdEntry::Thunk(FdEntry::duplicate_stdin));
|
||||
self.fds
|
||||
.insert(1, PendingFdEntry::Thunk(FdEntry::duplicate_stdout));
|
||||
self.fds
|
||||
.insert(2, PendingFdEntry::Thunk(FdEntry::duplicate_stderr));
|
||||
self
|
||||
}
|
||||
|
||||
/// Inherit the environment variables from the host process.
|
||||
///
|
||||
/// 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
|
||||
/// `Error::EILSEQ`.
|
||||
pub fn inherit_env(mut self) -> Self {
|
||||
self.env = std::env::vars_os()
|
||||
.map(|(k, v)| (k.into(), v.into()))
|
||||
.collect();
|
||||
self
|
||||
}
|
||||
|
||||
/// Add an entry to the environment.
|
||||
///
|
||||
/// Environment variable keys and values must be valid UTF-8 with no NUL bytes, or else
|
||||
/// `WasiCtxBuilder::build()` will fail with `Error::EILSEQ`.
|
||||
pub fn env<S: AsRef<[u8]>>(mut self, k: S, v: S) -> Self {
|
||||
self.env
|
||||
.insert(k.as_ref().to_vec().into(), v.as_ref().to_vec().into());
|
||||
self
|
||||
}
|
||||
|
||||
/// Add entries to the environment.
|
||||
///
|
||||
/// Environment variable keys and values must be valid UTF-8 with no NUL bytes, or else
|
||||
/// `WasiCtxBuilder::build()` will fail with `Error::EILSEQ`.
|
||||
pub fn envs<S: AsRef<[u8]>, T: Borrow<(S, S)>>(
|
||||
mut self,
|
||||
envs: impl IntoIterator<Item = T>,
|
||||
) -> Self {
|
||||
self.env = envs
|
||||
.into_iter()
|
||||
.map(|t| {
|
||||
let (k, v) = t.borrow();
|
||||
(k.as_ref().to_vec().into(), v.as_ref().to_vec().into())
|
||||
})
|
||||
.collect();
|
||||
self
|
||||
}
|
||||
|
||||
/// Provide a File to use as stdin
|
||||
pub fn stdin(mut self, file: File) -> Self {
|
||||
self.fds.insert(0, PendingFdEntry::File(file));
|
||||
self
|
||||
}
|
||||
|
||||
/// Provide a File to use as stdout
|
||||
pub fn stdout(mut self, file: File) -> Self {
|
||||
self.fds.insert(1, PendingFdEntry::File(file));
|
||||
self
|
||||
}
|
||||
|
||||
/// Provide a File to use as stderr
|
||||
pub fn stderr(mut self, file: File) -> Self {
|
||||
self.fds.insert(2, PendingFdEntry::File(file));
|
||||
self
|
||||
}
|
||||
|
||||
/// Add a preopened directory.
|
||||
pub fn preopened_dir<P: AsRef<Path>>(mut self, dir: File, guest_path: P) -> Self {
|
||||
self.preopens.push((guest_path.as_ref().to_owned(), dir));
|
||||
self
|
||||
}
|
||||
|
||||
/// Build a `WasiCtx`, consuming this `WasiCtxBuilder`.
|
||||
///
|
||||
/// 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`.
|
||||
pub fn build(self) -> Result<WasiCtx> {
|
||||
// Process arguments and environment variables into `CString`s, failing quickly if they
|
||||
// contain any NUL bytes, or if conversion from `OsString` fails.
|
||||
let args = self
|
||||
.args
|
||||
.into_iter()
|
||||
.map(|arg| arg.into_utf8_cstring())
|
||||
.collect::<Result<Vec<CString>>>()?;
|
||||
|
||||
let env = self
|
||||
.env
|
||||
.into_iter()
|
||||
.map(|(k, v)| {
|
||||
k.into_string().and_then(|mut pair| {
|
||||
v.into_string().and_then(|v| {
|
||||
pair.push('=');
|
||||
pair.push_str(v.as_str());
|
||||
// We have valid UTF-8, but the keys and values have not yet been checked
|
||||
// for NULs, so we do a final check here.
|
||||
CString::new(pair).map_err(|_| Error::EILSEQ)
|
||||
})
|
||||
})
|
||||
})
|
||||
.collect::<Result<Vec<CString>>>()?;
|
||||
|
||||
let mut fds: HashMap<wasi::__wasi_fd_t, FdEntry> = HashMap::new();
|
||||
// Populate the non-preopen fds.
|
||||
for (fd, pending) in self.fds {
|
||||
log::debug!("WasiCtx inserting ({:?}, {:?})", fd, pending);
|
||||
match pending {
|
||||
PendingFdEntry::Thunk(f) => {
|
||||
fds.insert(fd, f()?);
|
||||
}
|
||||
PendingFdEntry::File(f) => {
|
||||
fds.insert(fd, FdEntry::from(f)?);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Then add the preopen fds. Startup code in the guest starts looking at fd 3 for preopens,
|
||||
// so we start from there. This variable is initially 2, though, because the loop
|
||||
// immediately does the increment and check for overflow.
|
||||
let mut preopen_fd: wasi::__wasi_fd_t = 2;
|
||||
for (guest_path, dir) in self.preopens {
|
||||
// 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.
|
||||
preopen_fd = preopen_fd.checked_add(1).ok_or(Error::ENFILE)?;
|
||||
|
||||
if !dir.metadata()?.is_dir() {
|
||||
return Err(Error::EBADF);
|
||||
}
|
||||
|
||||
// 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.
|
||||
while fds.contains_key(&preopen_fd) {
|
||||
preopen_fd = preopen_fd.checked_add(1).ok_or(Error::ENFILE)?;
|
||||
}
|
||||
let mut fe = FdEntry::from(dir)?;
|
||||
fe.preopen_path = Some(guest_path);
|
||||
log::debug!("WasiCtx inserting ({:?}, {:?})", preopen_fd, fe);
|
||||
fds.insert(preopen_fd, fe);
|
||||
log::debug!("WasiCtx fds = {:?}", fds);
|
||||
}
|
||||
|
||||
Ok(WasiCtx { args, env, fds })
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct WasiCtx {
|
||||
fds: HashMap<wasi::__wasi_fd_t, FdEntry>,
|
||||
pub(crate) args: Vec<CString>,
|
||||
pub(crate) env: Vec<CString>,
|
||||
}
|
||||
|
||||
impl WasiCtx {
|
||||
/// Make a new `WasiCtx` with some default settings.
|
||||
///
|
||||
/// - File descriptors 0, 1, and 2 inherit stdin, stdout, and stderr from the host process.
|
||||
///
|
||||
/// - Environment variables are inherited from the host process.
|
||||
///
|
||||
/// To override these behaviors, use `WasiCtxBuilder`.
|
||||
pub fn new<S: AsRef<[u8]>>(args: impl IntoIterator<Item = S>) -> Result<Self> {
|
||||
WasiCtxBuilder::new()
|
||||
.args(args)
|
||||
.inherit_stdio()
|
||||
.inherit_env()
|
||||
.build()
|
||||
}
|
||||
|
||||
/// Check if `WasiCtx` contains the specified raw WASI `fd`.
|
||||
pub(crate) unsafe fn contains_fd_entry(&self, fd: wasi::__wasi_fd_t) -> bool {
|
||||
self.fds.contains_key(&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> {
|
||||
self.fds.get(&fd).ok_or(Error::EBADF)
|
||||
}
|
||||
|
||||
/// Get a mutable `FdEntry` corresponding to the specified raw WASI `fd`.
|
||||
pub(crate) unsafe fn get_fd_entry_mut(
|
||||
&mut self,
|
||||
fd: wasi::__wasi_fd_t,
|
||||
) -> Result<&mut FdEntry> {
|
||||
self.fds.get_mut(&fd).ok_or(Error::EBADF)
|
||||
}
|
||||
|
||||
/// Insert the specified `FdEntry` into the `WasiCtx` object.
|
||||
///
|
||||
/// 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.
|
||||
pub(crate) fn insert_fd_entry(&mut self, fe: FdEntry) -> Result<wasi::__wasi_fd_t> {
|
||||
// Never insert where stdio handles are expected to be.
|
||||
let mut fd = 3;
|
||||
while self.fds.contains_key(&fd) {
|
||||
if let Some(next_fd) = fd.checked_add(1) {
|
||||
fd = next_fd;
|
||||
} else {
|
||||
return Err(Error::EMFILE);
|
||||
}
|
||||
}
|
||||
self.fds.insert(fd, fe);
|
||||
Ok(fd)
|
||||
}
|
||||
|
||||
/// Insert the specified `FdEntry` with the specified raw WASI `fd` key into the `WasiCtx`
|
||||
/// object.
|
||||
pub(crate) fn insert_fd_entry_at(
|
||||
&mut self,
|
||||
fd: wasi::__wasi_fd_t,
|
||||
fe: FdEntry,
|
||||
) -> Option<FdEntry> {
|
||||
self.fds.insert(fd, fe)
|
||||
}
|
||||
|
||||
/// 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> {
|
||||
self.fds.remove(&fd).ok_or(Error::EBADF)
|
||||
}
|
||||
}
|
||||
279
crates/wasi-common/src/old/snapshot_0/error.rs
Normal file
279
crates/wasi-common/src/old/snapshot_0/error.rs
Normal file
@@ -0,0 +1,279 @@
|
||||
// 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::{fmt, str};
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Clone, Copy, Debug, Error, Eq, PartialEq)]
|
||||
#[repr(u16)]
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for WasiError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match *self {
|
||||
_ => write!(f, "{:?}", self),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum Error {
|
||||
Wasi(WasiError),
|
||||
Io(std::io::Error),
|
||||
#[cfg(unix)]
|
||||
Nix(nix::Error),
|
||||
#[cfg(windows)]
|
||||
Win(winx::winerror::WinError),
|
||||
}
|
||||
|
||||
impl From<WasiError> for Error {
|
||||
fn from(err: WasiError) -> Self {
|
||||
Self::Wasi(err)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
impl From<nix::Error> for Error {
|
||||
fn from(err: nix::Error) -> Self {
|
||||
Self::Nix(err)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<std::io::Error> for Error {
|
||||
fn from(err: std::io::Error) -> Self {
|
||||
Self::Io(err)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<TryFromIntError> for Error {
|
||||
fn from(_: TryFromIntError) -> Self {
|
||||
Self::Wasi(WasiError::EOVERFLOW)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Infallible> for Error {
|
||||
fn from(_: Infallible) -> Self {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<str::Utf8Error> for Error {
|
||||
fn from(_: str::Utf8Error) -> Self {
|
||||
Self::Wasi(WasiError::EILSEQ)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
impl From<winx::winerror::WinError> for Error {
|
||||
fn from(err: winx::winerror::WinError) -> Self {
|
||||
Self::Win(err)
|
||||
}
|
||||
}
|
||||
|
||||
impl Error {
|
||||
pub(crate) fn as_wasi_errno(&self) -> wasi::__wasi_errno_t {
|
||||
match self {
|
||||
Self::Wasi(no) => no.as_raw_errno(),
|
||||
Self::Io(e) => errno_from_ioerror(e.to_owned()),
|
||||
#[cfg(unix)]
|
||||
Self::Nix(err) => err
|
||||
.as_errno()
|
||||
.map_or_else(
|
||||
|| {
|
||||
log::debug!("Unknown nix errno: {}", err);
|
||||
Self::ENOSYS
|
||||
},
|
||||
crate::old::snapshot_0::sys::host_impl::errno_from_nix,
|
||||
)
|
||||
.as_wasi_errno(),
|
||||
#[cfg(windows)]
|
||||
Self::Win(err) => crate::old::snapshot_0::sys::host_impl::errno_from_win(*err),
|
||||
}
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
impl fmt::Display for Error {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
Self::Io(e) => e.fmt(f),
|
||||
Self::Wasi(e) => e.fmt(f),
|
||||
#[cfg(unix)]
|
||||
Self::Nix(e) => e.fmt(f),
|
||||
#[cfg(windows)]
|
||||
Self::Win(e) => e.fmt(f),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn errno_from_ioerror(e: &std::io::Error) -> wasi::__wasi_errno_t {
|
||||
match e.raw_os_error() {
|
||||
Some(code) => crate::old::snapshot_0::sys::errno_from_host(code),
|
||||
None => {
|
||||
log::debug!("Inconvertible OS error: {}", e);
|
||||
wasi::__WASI_ERRNO_IO
|
||||
}
|
||||
}
|
||||
}
|
||||
186
crates/wasi-common/src/old/snapshot_0/fdentry.rs
Normal file
186
crates/wasi-common/src/old/snapshot_0/fdentry.rs
Normal file
@@ -0,0 +1,186 @@
|
||||
use crate::old::snapshot_0::sys::dev_null;
|
||||
use crate::old::snapshot_0::sys::fdentry_impl::{determine_type_and_access_rights, OsFile};
|
||||
use crate::old::snapshot_0::{wasi, Error, Result};
|
||||
use std::path::PathBuf;
|
||||
use std::{fs, io};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) enum Descriptor {
|
||||
OsFile(OsFile),
|
||||
Stdin,
|
||||
Stdout,
|
||||
Stderr,
|
||||
}
|
||||
|
||||
impl Descriptor {
|
||||
pub(crate) fn as_file(&self) -> Result<&OsFile> {
|
||||
match self {
|
||||
Self::OsFile(file) => Ok(file),
|
||||
_ => Err(Error::EBADF),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn as_file_mut(&mut self) -> Result<&mut OsFile> {
|
||||
match self {
|
||||
Self::OsFile(file) => Ok(file),
|
||||
_ => Err(Error::EBADF),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn is_file(&self) -> bool {
|
||||
match self {
|
||||
Self::OsFile(_) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
pub(crate) fn is_stdin(&self) -> bool {
|
||||
match self {
|
||||
Self::Stdin => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
pub(crate) fn is_stdout(&self) -> bool {
|
||||
match self {
|
||||
Self::Stdout => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
pub(crate) fn is_stderr(&self) -> bool {
|
||||
match self {
|
||||
Self::Stderr => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// An abstraction struct serving as a wrapper for a host `Descriptor` object which requires
|
||||
/// certain base rights `rights_base` and inheriting rights `rights_inheriting` in order to be
|
||||
/// accessed correctly.
|
||||
///
|
||||
/// Here, the `descriptor` field stores the host `Descriptor` object (such as a file descriptor, or
|
||||
/// stdin handle), and accessing it can only be done via the provided `FdEntry::as_descriptor` and
|
||||
/// `FdEntry::as_descriptor_mut` methods which require a set of base and inheriting rights to be
|
||||
/// specified, verifying whether the stored `Descriptor` object is valid for the rights specified.
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct FdEntry {
|
||||
pub(crate) file_type: wasi::__wasi_filetype_t,
|
||||
descriptor: Descriptor,
|
||||
pub(crate) rights_base: wasi::__wasi_rights_t,
|
||||
pub(crate) rights_inheriting: wasi::__wasi_rights_t,
|
||||
pub(crate) preopen_path: Option<PathBuf>,
|
||||
// TODO: directories
|
||||
}
|
||||
|
||||
impl FdEntry {
|
||||
pub(crate) fn from(file: fs::File) -> Result<Self> {
|
||||
unsafe { determine_type_and_access_rights(&file) }.map(
|
||||
|(file_type, rights_base, rights_inheriting)| Self {
|
||||
file_type,
|
||||
descriptor: Descriptor::OsFile(OsFile::from(file)),
|
||||
rights_base,
|
||||
rights_inheriting,
|
||||
preopen_path: None,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
pub(crate) fn duplicate(file: &fs::File) -> Result<Self> {
|
||||
Self::from(file.try_clone()?)
|
||||
}
|
||||
|
||||
pub(crate) fn duplicate_stdin() -> Result<Self> {
|
||||
unsafe { determine_type_and_access_rights(&io::stdin()) }.map(
|
||||
|(file_type, rights_base, rights_inheriting)| Self {
|
||||
file_type,
|
||||
descriptor: Descriptor::Stdin,
|
||||
rights_base,
|
||||
rights_inheriting,
|
||||
preopen_path: None,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
pub(crate) fn duplicate_stdout() -> Result<Self> {
|
||||
unsafe { determine_type_and_access_rights(&io::stdout()) }.map(
|
||||
|(file_type, rights_base, rights_inheriting)| Self {
|
||||
file_type,
|
||||
descriptor: Descriptor::Stdout,
|
||||
rights_base,
|
||||
rights_inheriting,
|
||||
preopen_path: None,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
pub(crate) fn duplicate_stderr() -> Result<Self> {
|
||||
unsafe { determine_type_and_access_rights(&io::stderr()) }.map(
|
||||
|(file_type, rights_base, rights_inheriting)| Self {
|
||||
file_type,
|
||||
descriptor: Descriptor::Stderr,
|
||||
rights_base,
|
||||
rights_inheriting,
|
||||
preopen_path: None,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
pub(crate) fn null() -> Result<Self> {
|
||||
Self::from(dev_null()?)
|
||||
}
|
||||
|
||||
/// Convert this `FdEntry` into a host `Descriptor` object provided the specified
|
||||
/// `rights_base` and `rights_inheriting` rights are set on this `FdEntry` object.
|
||||
///
|
||||
/// 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`
|
||||
/// 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.
|
||||
pub(crate) fn as_descriptor(
|
||||
&self,
|
||||
rights_base: wasi::__wasi_rights_t,
|
||||
rights_inheriting: wasi::__wasi_rights_t,
|
||||
) -> Result<&Descriptor> {
|
||||
self.validate_rights(rights_base, rights_inheriting)?;
|
||||
Ok(&self.descriptor)
|
||||
}
|
||||
|
||||
/// Convert this `FdEntry` into a mutable host `Descriptor` object provided the specified
|
||||
/// `rights_base` and `rights_inheriting` rights are set on this `FdEntry` object.
|
||||
///
|
||||
/// 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`
|
||||
/// 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.
|
||||
pub(crate) fn as_descriptor_mut(
|
||||
&mut self,
|
||||
rights_base: wasi::__wasi_rights_t,
|
||||
rights_inheriting: wasi::__wasi_rights_t,
|
||||
) -> Result<&mut Descriptor> {
|
||||
self.validate_rights(rights_base, rights_inheriting)?;
|
||||
Ok(&mut self.descriptor)
|
||||
}
|
||||
|
||||
/// Check if this `FdEntry` object satisfies the specified base rights `rights_base`, and
|
||||
/// inheriting rights `rights_inheriting`; i.e., if rights attached to this `FdEntry` object
|
||||
/// are a superset.
|
||||
///
|
||||
/// Upon unsuccessful check, `Error::ENOTCAPABLE` is returned.
|
||||
fn validate_rights(
|
||||
&self,
|
||||
rights_base: wasi::__wasi_rights_t,
|
||||
rights_inheriting: wasi::__wasi_rights_t,
|
||||
) -> Result<()> {
|
||||
if !self.rights_base & rights_base != 0 || !self.rights_inheriting & rights_inheriting != 0
|
||||
{
|
||||
Err(Error::ENOTCAPABLE)
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
20
crates/wasi-common/src/old/snapshot_0/helpers.rs
Normal file
20
crates/wasi-common/src/old/snapshot_0/helpers.rs
Normal file
@@ -0,0 +1,20 @@
|
||||
use crate::old::snapshot_0::{Error, Result};
|
||||
use std::convert::TryInto;
|
||||
use std::str;
|
||||
use std::time::{SystemTime, UNIX_EPOCH};
|
||||
|
||||
pub(crate) fn systemtime_to_timestamp(st: SystemTime) -> Result<u64> {
|
||||
st.duration_since(UNIX_EPOCH)
|
||||
.map_err(|_| Error::EINVAL)? // date earlier than UNIX_EPOCH
|
||||
.as_nanos()
|
||||
.try_into()
|
||||
.map_err(Into::into) // u128 doesn't fit into u64
|
||||
}
|
||||
|
||||
/// Creates not-owned WASI path from byte slice.
|
||||
///
|
||||
/// NB WASI spec requires bytes to be valid UTF-8. Otherwise,
|
||||
/// `__WASI_ERRNO_ILSEQ` error is returned.
|
||||
pub(crate) fn path_from_slice<'a>(s: &'a [u8]) -> Result<&'a str> {
|
||||
str::from_utf8(s).map_err(|_| Error::EILSEQ)
|
||||
}
|
||||
109
crates/wasi-common/src/old/snapshot_0/host.rs
Normal file
109
crates/wasi-common/src/old/snapshot_0/host.rs
Normal file
@@ -0,0 +1,109 @@
|
||||
//! WASI host types. These are types that contain raw pointers and `usize`
|
||||
//! values, and so are platform-specific.
|
||||
|
||||
#![allow(non_camel_case_types)]
|
||||
#![allow(non_snake_case)]
|
||||
|
||||
use crate::old::snapshot_0::wasi::*;
|
||||
use std::{io, slice};
|
||||
use wig::witx_host_types;
|
||||
|
||||
witx_host_types!("old/snapshot_0" "wasi_unstable");
|
||||
|
||||
pub(crate) unsafe fn ciovec_to_host(ciovec: &__wasi_ciovec_t) -> io::IoSlice {
|
||||
let slice = slice::from_raw_parts(ciovec.buf as *const u8, ciovec.buf_len);
|
||||
io::IoSlice::new(slice)
|
||||
}
|
||||
|
||||
pub(crate) unsafe fn iovec_to_host_mut(iovec: &mut __wasi_iovec_t) -> io::IoSliceMut {
|
||||
let slice = slice::from_raw_parts_mut(iovec.buf as *mut u8, iovec.buf_len);
|
||||
io::IoSliceMut::new(slice)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
#[test]
|
||||
fn bindgen_test_layout___wasi_prestat_t() {
|
||||
assert_eq!(
|
||||
::std::mem::size_of::<__wasi_prestat_t>(),
|
||||
16usize,
|
||||
concat!("Size of: ", stringify!(__wasi_prestat_t))
|
||||
);
|
||||
assert_eq!(
|
||||
::std::mem::align_of::<__wasi_prestat_t>(),
|
||||
8usize,
|
||||
concat!("Alignment of ", stringify!(__wasi_prestat_t))
|
||||
);
|
||||
assert_eq!(
|
||||
unsafe { &(*(::std::ptr::null::<__wasi_prestat_t>())).pr_type as *const _ as usize },
|
||||
0usize,
|
||||
concat!(
|
||||
"Offset of field: ",
|
||||
stringify!(__wasi_prestat_t),
|
||||
"::",
|
||||
stringify!(pr_type)
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
unsafe { &(*(::std::ptr::null::<__wasi_prestat_t>())).u as *const _ as usize },
|
||||
8usize,
|
||||
concat!(
|
||||
"Offset of field: ",
|
||||
stringify!(__wasi_prestat_t),
|
||||
"::",
|
||||
stringify!(u)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn bindgen_test_layout___wasi_prestat_t___wasi_prestat_u___wasi_prestat_u_dir_t() {
|
||||
assert_eq!(
|
||||
::std::mem::size_of::<__wasi_prestat_dir_t>(),
|
||||
8usize,
|
||||
concat!("Size of: ", stringify!(__wasi_prestat_dir_t))
|
||||
);
|
||||
assert_eq!(
|
||||
::std::mem::align_of::<__wasi_prestat_dir_t>(),
|
||||
8usize,
|
||||
concat!("Alignment of ", stringify!(__wasi_prestat_dir_t))
|
||||
);
|
||||
assert_eq!(
|
||||
unsafe {
|
||||
&(*(::std::ptr::null::<__wasi_prestat_dir_t>())).pr_name_len as *const _ as usize
|
||||
},
|
||||
0usize,
|
||||
concat!(
|
||||
"Offset of field: ",
|
||||
stringify!(__wasi_prestat_dir_t),
|
||||
"::",
|
||||
stringify!(pr_name_len)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn bindgen_test_layout___wasi_prestat_t___wasi_prestat_u() {
|
||||
assert_eq!(
|
||||
::std::mem::size_of::<__wasi_prestat_u_t>(),
|
||||
8usize,
|
||||
concat!("Size of: ", stringify!(__wasi_prestat_u_t))
|
||||
);
|
||||
assert_eq!(
|
||||
::std::mem::align_of::<__wasi_prestat_u_t>(),
|
||||
8usize,
|
||||
concat!("Alignment of ", stringify!(__wasi_prestat_u_t))
|
||||
);
|
||||
assert_eq!(
|
||||
unsafe { &(*(::std::ptr::null::<__wasi_prestat_u_t>())).dir as *const _ as usize },
|
||||
0usize,
|
||||
concat!(
|
||||
"Offset of field: ",
|
||||
stringify!(__wasi_prestat_u_t),
|
||||
"::",
|
||||
stringify!(dir)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
256
crates/wasi-common/src/old/snapshot_0/hostcalls/fs.rs
Normal file
256
crates/wasi-common/src/old/snapshot_0/hostcalls/fs.rs
Normal file
@@ -0,0 +1,256 @@
|
||||
#![allow(non_camel_case_types)]
|
||||
use crate::old::snapshot_0::ctx::WasiCtx;
|
||||
use crate::old::snapshot_0::{hostcalls_impl, wasi, wasi32};
|
||||
|
||||
hostcalls_old! {
|
||||
pub unsafe fn fd_close(wasi_ctx: &mut WasiCtx, fd: wasi::__wasi_fd_t,) -> wasi::__wasi_errno_t;
|
||||
|
||||
pub unsafe fn fd_datasync(wasi_ctx: &WasiCtx, fd: wasi::__wasi_fd_t,) -> wasi::__wasi_errno_t;
|
||||
|
||||
pub unsafe fn fd_pread(
|
||||
wasi_ctx: &WasiCtx,
|
||||
memory: &mut [u8],
|
||||
fd: wasi::__wasi_fd_t,
|
||||
iovs_ptr: wasi32::uintptr_t,
|
||||
iovs_len: wasi32::size_t,
|
||||
offset: wasi::__wasi_filesize_t,
|
||||
nread: wasi32::uintptr_t,
|
||||
) -> wasi::__wasi_errno_t;
|
||||
|
||||
pub unsafe fn fd_pwrite(
|
||||
wasi_ctx: &WasiCtx,
|
||||
memory: &mut [u8],
|
||||
fd: wasi::__wasi_fd_t,
|
||||
iovs_ptr: wasi32::uintptr_t,
|
||||
iovs_len: wasi32::size_t,
|
||||
offset: wasi::__wasi_filesize_t,
|
||||
nwritten: wasi32::uintptr_t,
|
||||
) -> wasi::__wasi_errno_t;
|
||||
|
||||
pub unsafe fn fd_read(
|
||||
wasi_ctx: &mut WasiCtx,
|
||||
memory: &mut [u8],
|
||||
fd: wasi::__wasi_fd_t,
|
||||
iovs_ptr: wasi32::uintptr_t,
|
||||
iovs_len: wasi32::size_t,
|
||||
nread: wasi32::uintptr_t,
|
||||
) -> wasi::__wasi_errno_t;
|
||||
|
||||
pub unsafe fn fd_renumber(
|
||||
wasi_ctx: &mut WasiCtx,
|
||||
from: wasi::__wasi_fd_t,
|
||||
to: wasi::__wasi_fd_t,
|
||||
) -> wasi::__wasi_errno_t;
|
||||
|
||||
pub unsafe fn fd_seek(
|
||||
wasi_ctx: &mut WasiCtx,
|
||||
memory: &mut [u8],
|
||||
fd: wasi::__wasi_fd_t,
|
||||
offset: wasi::__wasi_filedelta_t,
|
||||
whence: wasi::__wasi_whence_t,
|
||||
newoffset: wasi32::uintptr_t,
|
||||
) -> wasi::__wasi_errno_t;
|
||||
|
||||
pub unsafe fn fd_tell(
|
||||
wasi_ctx: &mut WasiCtx,
|
||||
memory: &mut [u8],
|
||||
fd: wasi::__wasi_fd_t,
|
||||
newoffset: wasi32::uintptr_t,
|
||||
) -> wasi::__wasi_errno_t;
|
||||
|
||||
pub unsafe fn fd_fdstat_get(
|
||||
wasi_ctx: &WasiCtx,
|
||||
memory: &mut [u8],
|
||||
fd: wasi::__wasi_fd_t,
|
||||
fdstat_ptr: wasi32::uintptr_t,
|
||||
) -> wasi::__wasi_errno_t;
|
||||
|
||||
pub unsafe fn fd_fdstat_set_flags(
|
||||
wasi_ctx: &WasiCtx,
|
||||
fd: wasi::__wasi_fd_t,
|
||||
fdflags: wasi::__wasi_fdflags_t,
|
||||
) -> wasi::__wasi_errno_t;
|
||||
|
||||
pub unsafe fn fd_fdstat_set_rights(
|
||||
wasi_ctx: &mut WasiCtx,
|
||||
fd: wasi::__wasi_fd_t,
|
||||
fs_rights_base: wasi::__wasi_rights_t,
|
||||
fs_rights_inheriting: wasi::__wasi_rights_t,
|
||||
) -> wasi::__wasi_errno_t;
|
||||
|
||||
pub unsafe fn fd_sync(wasi_ctx: &WasiCtx, fd: wasi::__wasi_fd_t,) -> wasi::__wasi_errno_t;
|
||||
|
||||
pub unsafe fn fd_write(
|
||||
wasi_ctx: &mut WasiCtx,
|
||||
memory: &mut [u8],
|
||||
fd: wasi::__wasi_fd_t,
|
||||
iovs_ptr: wasi32::uintptr_t,
|
||||
iovs_len: wasi32::size_t,
|
||||
nwritten: wasi32::uintptr_t,
|
||||
) -> wasi::__wasi_errno_t;
|
||||
|
||||
pub unsafe fn fd_advise(
|
||||
wasi_ctx: &WasiCtx,
|
||||
fd: wasi::__wasi_fd_t,
|
||||
offset: wasi::__wasi_filesize_t,
|
||||
len: wasi::__wasi_filesize_t,
|
||||
advice: wasi::__wasi_advice_t,
|
||||
) -> wasi::__wasi_errno_t;
|
||||
|
||||
pub unsafe fn fd_allocate(
|
||||
wasi_ctx: &WasiCtx,
|
||||
fd: wasi::__wasi_fd_t,
|
||||
offset: wasi::__wasi_filesize_t,
|
||||
len: wasi::__wasi_filesize_t,
|
||||
) -> wasi::__wasi_errno_t;
|
||||
|
||||
pub unsafe fn path_create_directory(
|
||||
wasi_ctx: &WasiCtx,
|
||||
memory: &mut [u8],
|
||||
dirfd: wasi::__wasi_fd_t,
|
||||
path_ptr: wasi32::uintptr_t,
|
||||
path_len: wasi32::size_t,
|
||||
) -> wasi::__wasi_errno_t;
|
||||
|
||||
pub unsafe fn path_link(
|
||||
wasi_ctx: &WasiCtx,
|
||||
memory: &mut [u8],
|
||||
old_dirfd: wasi::__wasi_fd_t,
|
||||
old_flags: wasi::__wasi_lookupflags_t,
|
||||
old_path_ptr: wasi32::uintptr_t,
|
||||
old_path_len: wasi32::size_t,
|
||||
new_dirfd: wasi::__wasi_fd_t,
|
||||
new_path_ptr: wasi32::uintptr_t,
|
||||
new_path_len: wasi32::size_t,
|
||||
) -> wasi::__wasi_errno_t;
|
||||
|
||||
pub unsafe fn path_open(
|
||||
wasi_ctx: &mut WasiCtx,
|
||||
memory: &mut [u8],
|
||||
dirfd: wasi::__wasi_fd_t,
|
||||
dirflags: wasi::__wasi_lookupflags_t,
|
||||
path_ptr: wasi32::uintptr_t,
|
||||
path_len: wasi32::size_t,
|
||||
oflags: wasi::__wasi_oflags_t,
|
||||
fs_rights_base: wasi::__wasi_rights_t,
|
||||
fs_rights_inheriting: wasi::__wasi_rights_t,
|
||||
fs_flags: wasi::__wasi_fdflags_t,
|
||||
fd_out_ptr: wasi32::uintptr_t,
|
||||
) -> wasi::__wasi_errno_t;
|
||||
|
||||
pub unsafe fn fd_readdir(
|
||||
wasi_ctx: &mut WasiCtx,
|
||||
memory: &mut [u8],
|
||||
fd: wasi::__wasi_fd_t,
|
||||
buf: wasi32::uintptr_t,
|
||||
buf_len: wasi32::size_t,
|
||||
cookie: wasi::__wasi_dircookie_t,
|
||||
buf_used: wasi32::uintptr_t,
|
||||
) -> wasi::__wasi_errno_t;
|
||||
|
||||
pub unsafe fn path_readlink(
|
||||
wasi_ctx: &WasiCtx,
|
||||
memory: &mut [u8],
|
||||
dirfd: wasi::__wasi_fd_t,
|
||||
path_ptr: wasi32::uintptr_t,
|
||||
path_len: wasi32::size_t,
|
||||
buf_ptr: wasi32::uintptr_t,
|
||||
buf_len: wasi32::size_t,
|
||||
buf_used: wasi32::uintptr_t,
|
||||
) -> wasi::__wasi_errno_t;
|
||||
|
||||
pub unsafe fn path_rename(
|
||||
wasi_ctx: &WasiCtx,
|
||||
memory: &mut [u8],
|
||||
old_dirfd: wasi::__wasi_fd_t,
|
||||
old_path_ptr: wasi32::uintptr_t,
|
||||
old_path_len: wasi32::size_t,
|
||||
new_dirfd: wasi::__wasi_fd_t,
|
||||
new_path_ptr: wasi32::uintptr_t,
|
||||
new_path_len: wasi32::size_t,
|
||||
) -> wasi::__wasi_errno_t;
|
||||
|
||||
pub unsafe fn fd_filestat_get(
|
||||
wasi_ctx: &WasiCtx,
|
||||
memory: &mut [u8],
|
||||
fd: wasi::__wasi_fd_t,
|
||||
filestat_ptr: wasi32::uintptr_t,
|
||||
) -> wasi::__wasi_errno_t;
|
||||
|
||||
pub unsafe fn fd_filestat_set_times(
|
||||
wasi_ctx: &WasiCtx,
|
||||
fd: wasi::__wasi_fd_t,
|
||||
st_atim: wasi::__wasi_timestamp_t,
|
||||
st_mtim: wasi::__wasi_timestamp_t,
|
||||
fst_flags: wasi::__wasi_fstflags_t,
|
||||
) -> wasi::__wasi_errno_t;
|
||||
|
||||
pub unsafe fn fd_filestat_set_size(
|
||||
wasi_ctx: &WasiCtx,
|
||||
fd: wasi::__wasi_fd_t,
|
||||
st_size: wasi::__wasi_filesize_t,
|
||||
) -> wasi::__wasi_errno_t;
|
||||
|
||||
pub unsafe fn path_filestat_get(
|
||||
wasi_ctx: &WasiCtx,
|
||||
memory: &mut [u8],
|
||||
dirfd: wasi::__wasi_fd_t,
|
||||
dirflags: wasi::__wasi_lookupflags_t,
|
||||
path_ptr: wasi32::uintptr_t,
|
||||
path_len: wasi32::size_t,
|
||||
filestat_ptr: wasi32::uintptr_t,
|
||||
) -> wasi::__wasi_errno_t;
|
||||
|
||||
pub unsafe fn path_filestat_set_times(
|
||||
wasi_ctx: &WasiCtx,
|
||||
memory: &mut [u8],
|
||||
dirfd: wasi::__wasi_fd_t,
|
||||
dirflags: wasi::__wasi_lookupflags_t,
|
||||
path_ptr: wasi32::uintptr_t,
|
||||
path_len: wasi32::size_t,
|
||||
st_atim: wasi::__wasi_timestamp_t,
|
||||
st_mtim: wasi::__wasi_timestamp_t,
|
||||
fst_flags: wasi::__wasi_fstflags_t,
|
||||
) -> wasi::__wasi_errno_t;
|
||||
|
||||
pub unsafe fn path_symlink(
|
||||
wasi_ctx: &WasiCtx,
|
||||
memory: &mut [u8],
|
||||
old_path_ptr: wasi32::uintptr_t,
|
||||
old_path_len: wasi32::size_t,
|
||||
dirfd: wasi::__wasi_fd_t,
|
||||
new_path_ptr: wasi32::uintptr_t,
|
||||
new_path_len: wasi32::size_t,
|
||||
) -> wasi::__wasi_errno_t;
|
||||
|
||||
pub unsafe fn path_unlink_file(
|
||||
wasi_ctx: &WasiCtx,
|
||||
memory: &mut [u8],
|
||||
dirfd: wasi::__wasi_fd_t,
|
||||
path_ptr: wasi32::uintptr_t,
|
||||
path_len: wasi32::size_t,
|
||||
) -> wasi::__wasi_errno_t;
|
||||
|
||||
pub unsafe fn path_remove_directory(
|
||||
wasi_ctx: &WasiCtx,
|
||||
memory: &mut [u8],
|
||||
dirfd: wasi::__wasi_fd_t,
|
||||
path_ptr: wasi32::uintptr_t,
|
||||
path_len: wasi32::size_t,
|
||||
) -> wasi::__wasi_errno_t;
|
||||
|
||||
pub unsafe fn fd_prestat_get(
|
||||
wasi_ctx: &WasiCtx,
|
||||
memory: &mut [u8],
|
||||
fd: wasi::__wasi_fd_t,
|
||||
prestat_ptr: wasi32::uintptr_t,
|
||||
) -> wasi::__wasi_errno_t;
|
||||
|
||||
pub unsafe fn fd_prestat_dir_name(
|
||||
wasi_ctx: &WasiCtx,
|
||||
memory: &mut [u8],
|
||||
fd: wasi::__wasi_fd_t,
|
||||
path_ptr: wasi32::uintptr_t,
|
||||
path_len: wasi32::size_t,
|
||||
) -> wasi::__wasi_errno_t;
|
||||
}
|
||||
82
crates/wasi-common/src/old/snapshot_0/hostcalls/misc.rs
Normal file
82
crates/wasi-common/src/old/snapshot_0/hostcalls/misc.rs
Normal file
@@ -0,0 +1,82 @@
|
||||
#![allow(non_camel_case_types)]
|
||||
use crate::old::snapshot_0::ctx::WasiCtx;
|
||||
use crate::old::snapshot_0::{hostcalls_impl, wasi, wasi32};
|
||||
use log::trace;
|
||||
use wasi_common_cbindgen::wasi_common_cbindgen_old;
|
||||
|
||||
#[wasi_common_cbindgen_old]
|
||||
pub unsafe fn proc_exit(rval: wasi::__wasi_exitcode_t) {
|
||||
trace!("proc_exit(rval={:?})", rval);
|
||||
// TODO: Rather than call std::process::exit here, we should trigger a
|
||||
// stack unwind similar to a trap.
|
||||
std::process::exit(rval as i32);
|
||||
}
|
||||
|
||||
#[wasi_common_cbindgen_old]
|
||||
pub unsafe fn proc_raise(
|
||||
_wasi_ctx: &WasiCtx,
|
||||
_memory: &mut [u8],
|
||||
_sig: wasi::__wasi_signal_t,
|
||||
) -> wasi::__wasi_errno_t {
|
||||
unimplemented!("proc_raise")
|
||||
}
|
||||
|
||||
hostcalls_old! {
|
||||
pub unsafe fn args_get(
|
||||
wasi_ctx: &WasiCtx,
|
||||
memory: &mut [u8],
|
||||
argv_ptr: wasi32::uintptr_t,
|
||||
argv_buf: wasi32::uintptr_t,
|
||||
) -> wasi::__wasi_errno_t;
|
||||
|
||||
pub unsafe fn args_sizes_get(
|
||||
wasi_ctx: &WasiCtx,
|
||||
memory: &mut [u8],
|
||||
argc_ptr: wasi32::uintptr_t,
|
||||
argv_buf_size_ptr: wasi32::uintptr_t,
|
||||
) -> wasi::__wasi_errno_t;
|
||||
|
||||
pub unsafe fn environ_get(
|
||||
wasi_ctx: &WasiCtx,
|
||||
memory: &mut [u8],
|
||||
environ_ptr: wasi32::uintptr_t,
|
||||
environ_buf: wasi32::uintptr_t,
|
||||
) -> wasi::__wasi_errno_t;
|
||||
|
||||
pub unsafe fn environ_sizes_get(
|
||||
wasi_ctx: &WasiCtx,
|
||||
memory: &mut [u8],
|
||||
environ_count_ptr: wasi32::uintptr_t,
|
||||
environ_size_ptr: wasi32::uintptr_t,
|
||||
) -> wasi::__wasi_errno_t;
|
||||
|
||||
pub unsafe fn random_get(
|
||||
memory: &mut [u8],
|
||||
buf_ptr: wasi32::uintptr_t,
|
||||
buf_len: wasi32::size_t,
|
||||
) -> wasi::__wasi_errno_t;
|
||||
|
||||
pub unsafe fn clock_res_get(
|
||||
memory: &mut [u8],
|
||||
clock_id: wasi::__wasi_clockid_t,
|
||||
resolution_ptr: wasi32::uintptr_t,
|
||||
) -> wasi::__wasi_errno_t;
|
||||
|
||||
pub unsafe fn clock_time_get(
|
||||
memory: &mut [u8],
|
||||
clock_id: wasi::__wasi_clockid_t,
|
||||
precision: wasi::__wasi_timestamp_t,
|
||||
time_ptr: wasi32::uintptr_t,
|
||||
) -> wasi::__wasi_errno_t;
|
||||
|
||||
pub unsafe fn poll_oneoff(
|
||||
wasi_ctx: &WasiCtx,
|
||||
memory: &mut [u8],
|
||||
input: wasi32::uintptr_t,
|
||||
output: wasi32::uintptr_t,
|
||||
nsubscriptions: wasi32::size_t,
|
||||
nevents: wasi32::uintptr_t,
|
||||
) -> wasi::__wasi_errno_t;
|
||||
|
||||
pub unsafe fn sched_yield() -> wasi::__wasi_errno_t;
|
||||
}
|
||||
7
crates/wasi-common/src/old/snapshot_0/hostcalls/mod.rs
Normal file
7
crates/wasi-common/src/old/snapshot_0/hostcalls/mod.rs
Normal file
@@ -0,0 +1,7 @@
|
||||
mod fs;
|
||||
mod misc;
|
||||
mod sock;
|
||||
|
||||
pub use self::fs::*;
|
||||
pub use self::misc::*;
|
||||
pub use self::sock::*;
|
||||
43
crates/wasi-common/src/old/snapshot_0/hostcalls/sock.rs
Normal file
43
crates/wasi-common/src/old/snapshot_0/hostcalls/sock.rs
Normal file
@@ -0,0 +1,43 @@
|
||||
#![allow(non_camel_case_types)]
|
||||
#![allow(unused_unsafe)]
|
||||
#![allow(unused)]
|
||||
use crate::old::snapshot_0::ctx::WasiCtx;
|
||||
use crate::old::snapshot_0::{wasi, wasi32};
|
||||
use wasi_common_cbindgen::wasi_common_cbindgen_old;
|
||||
|
||||
#[wasi_common_cbindgen_old]
|
||||
pub unsafe fn sock_recv(
|
||||
wasi_ctx: &WasiCtx,
|
||||
memory: &mut [u8],
|
||||
sock: wasi::__wasi_fd_t,
|
||||
ri_data: wasi32::uintptr_t,
|
||||
ri_data_len: wasi32::size_t,
|
||||
ri_flags: wasi::__wasi_riflags_t,
|
||||
ro_datalen: wasi32::uintptr_t,
|
||||
ro_flags: wasi32::uintptr_t,
|
||||
) -> wasi::__wasi_errno_t {
|
||||
unimplemented!("sock_recv")
|
||||
}
|
||||
|
||||
#[wasi_common_cbindgen_old]
|
||||
pub unsafe fn sock_send(
|
||||
wasi_ctx: &WasiCtx,
|
||||
memory: &mut [u8],
|
||||
sock: wasi::__wasi_fd_t,
|
||||
si_data: wasi32::uintptr_t,
|
||||
si_data_len: wasi32::size_t,
|
||||
si_flags: wasi::__wasi_siflags_t,
|
||||
so_datalen: wasi32::uintptr_t,
|
||||
) -> wasi::__wasi_errno_t {
|
||||
unimplemented!("sock_send")
|
||||
}
|
||||
|
||||
#[wasi_common_cbindgen_old]
|
||||
pub unsafe fn sock_shutdown(
|
||||
wasi_ctx: &WasiCtx,
|
||||
memory: &mut [u8],
|
||||
sock: wasi::__wasi_fd_t,
|
||||
how: wasi::__wasi_sdflags_t,
|
||||
) -> wasi::__wasi_errno_t {
|
||||
unimplemented!("sock_shutdown")
|
||||
}
|
||||
1094
crates/wasi-common/src/old/snapshot_0/hostcalls_impl/fs.rs
Normal file
1094
crates/wasi-common/src/old/snapshot_0/hostcalls_impl/fs.rs
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,213 @@
|
||||
#![allow(non_camel_case_types)]
|
||||
use crate::old::snapshot_0::sys::host_impl;
|
||||
use crate::old::snapshot_0::sys::hostcalls_impl::fs_helpers::*;
|
||||
use crate::old::snapshot_0::{fdentry::FdEntry, wasi, Error, Result};
|
||||
use std::fs::File;
|
||||
use std::path::{Component, Path};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct PathGet {
|
||||
dirfd: File,
|
||||
path: String,
|
||||
}
|
||||
|
||||
impl PathGet {
|
||||
pub(crate) fn dirfd(&self) -> &File {
|
||||
&self.dirfd
|
||||
}
|
||||
|
||||
pub(crate) fn path(&self) -> &str {
|
||||
&self.path
|
||||
}
|
||||
}
|
||||
|
||||
/// Normalizes a path to ensure that the target path is located under the directory provided.
|
||||
///
|
||||
/// This is a workaround for not having Capsicum support in the OS.
|
||||
pub(crate) fn path_get(
|
||||
fe: &FdEntry,
|
||||
rights_base: wasi::__wasi_rights_t,
|
||||
rights_inheriting: wasi::__wasi_rights_t,
|
||||
dirflags: wasi::__wasi_lookupflags_t,
|
||||
path: &str,
|
||||
needs_final_component: bool,
|
||||
) -> Result<PathGet> {
|
||||
const MAX_SYMLINK_EXPANSIONS: usize = 128;
|
||||
|
||||
if path.contains('\0') {
|
||||
// if contains NUL, return EILSEQ
|
||||
return Err(Error::EILSEQ);
|
||||
}
|
||||
|
||||
if fe.file_type != wasi::__WASI_FILETYPE_DIRECTORY {
|
||||
// if `dirfd` doesn't refer to a directory, return `ENOTDIR`.
|
||||
return Err(Error::ENOTDIR);
|
||||
}
|
||||
|
||||
let dirfd = fe
|
||||
.as_descriptor(rights_base, rights_inheriting)?
|
||||
.as_file()?
|
||||
.try_clone()?;
|
||||
|
||||
// Stack of directory file descriptors. Index 0 always corresponds with the directory provided
|
||||
// to this function. Entering a directory causes a file descriptor to be pushed, while handling
|
||||
// ".." entries causes an entry to be popped. Index 0 cannot be popped, as this would imply
|
||||
// escaping the base directory.
|
||||
let mut dir_stack = vec![dirfd];
|
||||
|
||||
// Stack of paths left to process. This is initially the `path` argument to this function, but
|
||||
// any symlinks we encounter are processed by pushing them on the stack.
|
||||
let mut path_stack = vec![path.to_owned()];
|
||||
|
||||
// Track the number of symlinks we've expanded, so we can return `ELOOP` after too many.
|
||||
let mut symlink_expansions = 0;
|
||||
|
||||
// TODO: rewrite this using a custom posix path type, with a component iterator that respects
|
||||
// trailing slashes. This version does way too much allocation, and is way too fiddly.
|
||||
loop {
|
||||
match path_stack.pop() {
|
||||
Some(cur_path) => {
|
||||
log::debug!("path_get cur_path = {:?}", cur_path);
|
||||
|
||||
let ends_with_slash = cur_path.ends_with('/');
|
||||
let mut components = Path::new(&cur_path).components();
|
||||
let head = match components.next() {
|
||||
None => return Err(Error::ENOENT),
|
||||
Some(p) => p,
|
||||
};
|
||||
let tail = components.as_path();
|
||||
|
||||
if tail.components().next().is_some() {
|
||||
let mut tail = host_impl::path_from_host(tail.as_os_str())?;
|
||||
if ends_with_slash {
|
||||
tail.push('/');
|
||||
}
|
||||
path_stack.push(tail);
|
||||
}
|
||||
|
||||
log::debug!("path_get path_stack = {:?}", path_stack);
|
||||
|
||||
match head {
|
||||
Component::Prefix(_) | Component::RootDir => {
|
||||
// path is absolute!
|
||||
return Err(Error::ENOTCAPABLE);
|
||||
}
|
||||
Component::CurDir => {
|
||||
// "." so skip
|
||||
}
|
||||
Component::ParentDir => {
|
||||
// ".." so pop a dir
|
||||
let _ = dir_stack.pop().ok_or(Error::ENOTCAPABLE)?;
|
||||
|
||||
// we're not allowed to pop past the original directory
|
||||
if dir_stack.is_empty() {
|
||||
return Err(Error::ENOTCAPABLE);
|
||||
}
|
||||
}
|
||||
Component::Normal(head) => {
|
||||
let mut head = host_impl::path_from_host(head)?;
|
||||
if ends_with_slash {
|
||||
// preserve trailing slash
|
||||
head.push('/');
|
||||
}
|
||||
|
||||
if !path_stack.is_empty() || (ends_with_slash && !needs_final_component) {
|
||||
match openat(dir_stack.last().ok_or(Error::ENOTCAPABLE)?, &head) {
|
||||
Ok(new_dir) => {
|
||||
dir_stack.push(new_dir);
|
||||
}
|
||||
Err(e) => {
|
||||
match e.as_wasi_errno() {
|
||||
wasi::__WASI_ERRNO_LOOP
|
||||
| wasi::__WASI_ERRNO_MLINK
|
||||
| wasi::__WASI_ERRNO_NOTDIR =>
|
||||
// Check to see if it was a symlink. Linux indicates
|
||||
// this with ENOTDIR because of the O_DIRECTORY flag.
|
||||
{
|
||||
// attempt symlink expansion
|
||||
let mut link_path = readlinkat(
|
||||
dir_stack.last().ok_or(Error::ENOTCAPABLE)?,
|
||||
&head,
|
||||
)?;
|
||||
|
||||
symlink_expansions += 1;
|
||||
if symlink_expansions > MAX_SYMLINK_EXPANSIONS {
|
||||
return Err(Error::ELOOP);
|
||||
}
|
||||
|
||||
if head.ends_with('/') {
|
||||
link_path.push('/');
|
||||
}
|
||||
|
||||
log::debug!(
|
||||
"attempted symlink expansion link_path={:?}",
|
||||
link_path
|
||||
);
|
||||
|
||||
path_stack.push(link_path);
|
||||
}
|
||||
_ => {
|
||||
return Err(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
continue;
|
||||
} else if ends_with_slash
|
||||
|| (dirflags & wasi::__WASI_LOOKUPFLAGS_SYMLINK_FOLLOW) != 0
|
||||
{
|
||||
// if there's a trailing slash, or if `LOOKUP_SYMLINK_FOLLOW` is set, attempt
|
||||
// symlink expansion
|
||||
match readlinkat(dir_stack.last().ok_or(Error::ENOTCAPABLE)?, &head) {
|
||||
Ok(mut link_path) => {
|
||||
symlink_expansions += 1;
|
||||
if symlink_expansions > MAX_SYMLINK_EXPANSIONS {
|
||||
return Err(Error::ELOOP);
|
||||
}
|
||||
|
||||
if head.ends_with('/') {
|
||||
link_path.push('/');
|
||||
}
|
||||
|
||||
log::debug!(
|
||||
"attempted symlink expansion link_path={:?}",
|
||||
link_path
|
||||
);
|
||||
|
||||
path_stack.push(link_path);
|
||||
continue;
|
||||
}
|
||||
Err(e) => {
|
||||
if e.as_wasi_errno() != wasi::__WASI_ERRNO_INVAL
|
||||
&& e.as_wasi_errno() != wasi::__WASI_ERRNO_NOENT
|
||||
// this handles the cases when trying to link to
|
||||
// a destination that already exists, and the target
|
||||
// path contains a slash
|
||||
&& e.as_wasi_errno() != wasi::__WASI_ERRNO_NOTDIR
|
||||
{
|
||||
return Err(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// not a symlink, so we're done;
|
||||
return Ok(PathGet {
|
||||
dirfd: dir_stack.pop().ok_or(Error::ENOTCAPABLE)?,
|
||||
path: head,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
None => {
|
||||
// no further components to process. means we've hit a case like "." or "a/..", or if the
|
||||
// input path has trailing slashes and `needs_final_component` is not set
|
||||
return Ok(PathGet {
|
||||
dirfd: dir_stack.pop().ok_or(Error::ENOTCAPABLE)?,
|
||||
path: String::from("."),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
317
crates/wasi-common/src/old/snapshot_0/hostcalls_impl/misc.rs
Normal file
317
crates/wasi-common/src/old/snapshot_0/hostcalls_impl/misc.rs
Normal file
@@ -0,0 +1,317 @@
|
||||
#![allow(non_camel_case_types)]
|
||||
use crate::old::snapshot_0::ctx::WasiCtx;
|
||||
use crate::old::snapshot_0::fdentry::Descriptor;
|
||||
use crate::old::snapshot_0::memory::*;
|
||||
use crate::old::snapshot_0::sys::hostcalls_impl;
|
||||
use crate::old::snapshot_0::{wasi, wasi32, Error, Result};
|
||||
use log::trace;
|
||||
use std::convert::TryFrom;
|
||||
|
||||
pub(crate) fn args_get(
|
||||
wasi_ctx: &WasiCtx,
|
||||
memory: &mut [u8],
|
||||
argv_ptr: wasi32::uintptr_t,
|
||||
argv_buf: wasi32::uintptr_t,
|
||||
) -> Result<()> {
|
||||
trace!(
|
||||
"args_get(argv_ptr={:#x?}, argv_buf={:#x?})",
|
||||
argv_ptr,
|
||||
argv_buf,
|
||||
);
|
||||
|
||||
let mut argv_buf_offset = 0;
|
||||
let mut argv = vec![];
|
||||
|
||||
for arg in &wasi_ctx.args {
|
||||
let arg_bytes = arg.as_bytes_with_nul();
|
||||
let arg_ptr = argv_buf + argv_buf_offset;
|
||||
|
||||
enc_slice_of_u8(memory, arg_bytes, arg_ptr)?;
|
||||
|
||||
argv.push(arg_ptr);
|
||||
|
||||
let len = wasi32::uintptr_t::try_from(arg_bytes.len())?;
|
||||
argv_buf_offset = argv_buf_offset.checked_add(len).ok_or(Error::EOVERFLOW)?;
|
||||
}
|
||||
|
||||
enc_slice_of_wasi32_uintptr(memory, argv.as_slice(), argv_ptr)
|
||||
}
|
||||
|
||||
pub(crate) fn args_sizes_get(
|
||||
wasi_ctx: &WasiCtx,
|
||||
memory: &mut [u8],
|
||||
argc_ptr: wasi32::uintptr_t,
|
||||
argv_buf_size_ptr: wasi32::uintptr_t,
|
||||
) -> Result<()> {
|
||||
trace!(
|
||||
"args_sizes_get(argc_ptr={:#x?}, argv_buf_size_ptr={:#x?})",
|
||||
argc_ptr,
|
||||
argv_buf_size_ptr,
|
||||
);
|
||||
|
||||
let argc = wasi_ctx.args.len();
|
||||
let argv_size = wasi_ctx
|
||||
.args
|
||||
.iter()
|
||||
.map(|arg| arg.as_bytes_with_nul().len())
|
||||
.sum();
|
||||
|
||||
trace!(" | *argc_ptr={:?}", argc);
|
||||
|
||||
enc_usize_byref(memory, argc_ptr, argc)?;
|
||||
|
||||
trace!(" | *argv_buf_size_ptr={:?}", argv_size);
|
||||
|
||||
enc_usize_byref(memory, argv_buf_size_ptr, argv_size)
|
||||
}
|
||||
|
||||
pub(crate) fn environ_get(
|
||||
wasi_ctx: &WasiCtx,
|
||||
memory: &mut [u8],
|
||||
environ_ptr: wasi32::uintptr_t,
|
||||
environ_buf: wasi32::uintptr_t,
|
||||
) -> Result<()> {
|
||||
trace!(
|
||||
"environ_get(environ_ptr={:#x?}, environ_buf={:#x?})",
|
||||
environ_ptr,
|
||||
environ_buf,
|
||||
);
|
||||
|
||||
let mut environ_buf_offset = 0;
|
||||
let mut environ = vec![];
|
||||
|
||||
for pair in &wasi_ctx.env {
|
||||
let env_bytes = pair.as_bytes_with_nul();
|
||||
let env_ptr = environ_buf + environ_buf_offset;
|
||||
|
||||
enc_slice_of_u8(memory, env_bytes, env_ptr)?;
|
||||
|
||||
environ.push(env_ptr);
|
||||
|
||||
let len = wasi32::uintptr_t::try_from(env_bytes.len())?;
|
||||
environ_buf_offset = environ_buf_offset
|
||||
.checked_add(len)
|
||||
.ok_or(Error::EOVERFLOW)?;
|
||||
}
|
||||
|
||||
enc_slice_of_wasi32_uintptr(memory, environ.as_slice(), environ_ptr)
|
||||
}
|
||||
|
||||
pub(crate) fn environ_sizes_get(
|
||||
wasi_ctx: &WasiCtx,
|
||||
memory: &mut [u8],
|
||||
environ_count_ptr: wasi32::uintptr_t,
|
||||
environ_size_ptr: wasi32::uintptr_t,
|
||||
) -> Result<()> {
|
||||
trace!(
|
||||
"environ_sizes_get(environ_count_ptr={:#x?}, environ_size_ptr={:#x?})",
|
||||
environ_count_ptr,
|
||||
environ_size_ptr,
|
||||
);
|
||||
|
||||
let environ_count = wasi_ctx.env.len();
|
||||
let environ_size = wasi_ctx
|
||||
.env
|
||||
.iter()
|
||||
.try_fold(0, |acc: u32, pair| {
|
||||
acc.checked_add(pair.as_bytes_with_nul().len() as u32)
|
||||
})
|
||||
.ok_or(Error::EOVERFLOW)?;
|
||||
|
||||
trace!(" | *environ_count_ptr={:?}", environ_count);
|
||||
|
||||
enc_usize_byref(memory, environ_count_ptr, environ_count)?;
|
||||
|
||||
trace!(" | *environ_size_ptr={:?}", environ_size);
|
||||
|
||||
enc_usize_byref(memory, environ_size_ptr, environ_size as usize)
|
||||
}
|
||||
|
||||
pub(crate) fn random_get(
|
||||
memory: &mut [u8],
|
||||
buf_ptr: wasi32::uintptr_t,
|
||||
buf_len: wasi32::size_t,
|
||||
) -> Result<()> {
|
||||
use rand::{thread_rng, RngCore};
|
||||
|
||||
trace!("random_get(buf_ptr={:#x?}, buf_len={:?})", buf_ptr, buf_len);
|
||||
|
||||
let buf = dec_slice_of_mut_u8(memory, buf_ptr, buf_len)?;
|
||||
|
||||
thread_rng().fill_bytes(buf);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn clock_res_get(
|
||||
memory: &mut [u8],
|
||||
clock_id: wasi::__wasi_clockid_t,
|
||||
resolution_ptr: wasi32::uintptr_t,
|
||||
) -> Result<()> {
|
||||
trace!(
|
||||
"clock_res_get(clock_id={:?}, resolution_ptr={:#x?})",
|
||||
clock_id,
|
||||
resolution_ptr,
|
||||
);
|
||||
|
||||
let resolution = hostcalls_impl::clock_res_get(clock_id)?;
|
||||
|
||||
trace!(" | *resolution_ptr={:?}", resolution);
|
||||
|
||||
enc_timestamp_byref(memory, resolution_ptr, resolution)
|
||||
}
|
||||
|
||||
pub(crate) fn clock_time_get(
|
||||
memory: &mut [u8],
|
||||
clock_id: wasi::__wasi_clockid_t,
|
||||
precision: wasi::__wasi_timestamp_t,
|
||||
time_ptr: wasi32::uintptr_t,
|
||||
) -> Result<()> {
|
||||
trace!(
|
||||
"clock_time_get(clock_id={:?}, precision={:?}, time_ptr={:#x?})",
|
||||
clock_id,
|
||||
precision,
|
||||
time_ptr,
|
||||
);
|
||||
|
||||
let time = hostcalls_impl::clock_time_get(clock_id)?;
|
||||
|
||||
trace!(" | *time_ptr={:?}", time);
|
||||
|
||||
enc_timestamp_byref(memory, time_ptr, time)
|
||||
}
|
||||
|
||||
pub(crate) fn sched_yield() -> Result<()> {
|
||||
trace!("sched_yield()");
|
||||
|
||||
std::thread::yield_now();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn poll_oneoff(
|
||||
wasi_ctx: &WasiCtx,
|
||||
memory: &mut [u8],
|
||||
input: wasi32::uintptr_t,
|
||||
output: wasi32::uintptr_t,
|
||||
nsubscriptions: wasi32::size_t,
|
||||
nevents: wasi32::uintptr_t,
|
||||
) -> Result<()> {
|
||||
trace!(
|
||||
"poll_oneoff(input={:#x?}, output={:#x?}, nsubscriptions={}, nevents={:#x?})",
|
||||
input,
|
||||
output,
|
||||
nsubscriptions,
|
||||
nevents,
|
||||
);
|
||||
|
||||
if u64::from(nsubscriptions) > wasi::__wasi_filesize_t::max_value() {
|
||||
return Err(Error::EINVAL);
|
||||
}
|
||||
|
||||
enc_int_byref(memory, nevents, 0)?;
|
||||
|
||||
let subscriptions = dec_subscriptions(memory, input, nsubscriptions)?;
|
||||
let mut events = Vec::new();
|
||||
|
||||
let mut timeout: Option<ClockEventData> = None;
|
||||
let mut fd_events = Vec::new();
|
||||
for subscription in subscriptions {
|
||||
match subscription.r#type {
|
||||
wasi::__WASI_EVENTTYPE_CLOCK => {
|
||||
let clock = unsafe { subscription.u.clock };
|
||||
let delay = wasi_clock_to_relative_ns_delay(clock)?;
|
||||
|
||||
log::debug!("poll_oneoff event.u.clock = {:?}", clock);
|
||||
log::debug!("poll_oneoff delay = {:?}ns", delay);
|
||||
|
||||
let current = ClockEventData {
|
||||
delay,
|
||||
userdata: subscription.userdata,
|
||||
};
|
||||
let timeout = timeout.get_or_insert(current);
|
||||
if current.delay < timeout.delay {
|
||||
*timeout = current;
|
||||
}
|
||||
}
|
||||
r#type
|
||||
if r#type == wasi::__WASI_EVENTTYPE_FD_READ
|
||||
|| r#type == wasi::__WASI_EVENTTYPE_FD_WRITE =>
|
||||
{
|
||||
let wasi_fd = unsafe { subscription.u.fd_readwrite.file_descriptor };
|
||||
let rights = if r#type == wasi::__WASI_EVENTTYPE_FD_READ {
|
||||
wasi::__WASI_RIGHTS_FD_READ
|
||||
} else {
|
||||
wasi::__WASI_RIGHTS_FD_WRITE
|
||||
};
|
||||
|
||||
match unsafe {
|
||||
wasi_ctx
|
||||
.get_fd_entry(wasi_fd)
|
||||
.and_then(|fe| fe.as_descriptor(rights, 0))
|
||||
} {
|
||||
Ok(descriptor) => fd_events.push(FdEventData {
|
||||
descriptor,
|
||||
r#type: subscription.r#type,
|
||||
userdata: subscription.userdata,
|
||||
}),
|
||||
Err(err) => {
|
||||
let event = wasi::__wasi_event_t {
|
||||
userdata: subscription.userdata,
|
||||
r#type,
|
||||
error: err.as_wasi_errno(),
|
||||
u: wasi::__wasi_event_u_t {
|
||||
fd_readwrite: wasi::__wasi_event_fd_readwrite_t {
|
||||
nbytes: 0,
|
||||
flags: 0,
|
||||
},
|
||||
},
|
||||
};
|
||||
events.push(event);
|
||||
}
|
||||
};
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
log::debug!("poll_oneoff timeout = {:?}", timeout);
|
||||
log::debug!("poll_oneoff fd_events = {:?}", fd_events);
|
||||
|
||||
hostcalls_impl::poll_oneoff(timeout, fd_events, &mut events)?;
|
||||
|
||||
let events_count = u32::try_from(events.len()).map_err(|_| Error::EOVERFLOW)?;
|
||||
|
||||
enc_events(memory, output, nsubscriptions, events)?;
|
||||
|
||||
trace!(" | *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> {
|
||||
use std::time::SystemTime;
|
||||
|
||||
if wasi_clock.flags != wasi::__WASI_SUBCLOCKFLAGS_SUBSCRIPTION_CLOCK_ABSTIME {
|
||||
return Ok(u128::from(wasi_clock.timeout));
|
||||
}
|
||||
let now: u128 = SystemTime::now()
|
||||
.duration_since(SystemTime::UNIX_EPOCH)
|
||||
.map_err(|_| Error::ENOTCAPABLE)?
|
||||
.as_nanos();
|
||||
let deadline = u128::from(wasi_clock.timeout);
|
||||
Ok(deadline.saturating_sub(now))
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub(crate) struct ClockEventData {
|
||||
pub(crate) delay: u128, // delay is expressed in nanoseconds
|
||||
pub(crate) userdata: wasi::__wasi_userdata_t,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct FdEventData<'a> {
|
||||
pub(crate) descriptor: &'a Descriptor,
|
||||
pub(crate) r#type: wasi::__wasi_eventtype_t,
|
||||
pub(crate) userdata: wasi::__wasi_userdata_t,
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
mod fs;
|
||||
mod fs_helpers;
|
||||
mod misc;
|
||||
|
||||
pub(crate) use self::fs::*;
|
||||
pub(crate) use self::fs_helpers::PathGet;
|
||||
pub(crate) use self::misc::*;
|
||||
480
crates/wasi-common/src/old/snapshot_0/memory.rs
Normal file
480
crates/wasi-common/src/old/snapshot_0/memory.rs
Normal file
@@ -0,0 +1,480 @@
|
||||
//! Functions to store and load data to and from wasm linear memory,
|
||||
//! transforming them from and to host data types.
|
||||
//!
|
||||
//! Endianness concerns are completely encapsulated in this file, so
|
||||
//! that users outside this file holding a `wasi::*` value never need
|
||||
//! to consider what endianness it's in. Inside this file,
|
||||
//! wasm linear-memory-ordered values are called "raw" values, and
|
||||
//! are not held for long durations.
|
||||
|
||||
#![allow(unused)]
|
||||
use crate::old::snapshot_0::{host, wasi, wasi32, Error, Result};
|
||||
use num::PrimInt;
|
||||
use std::convert::TryFrom;
|
||||
use std::mem::{align_of, size_of};
|
||||
use std::{ptr, slice};
|
||||
|
||||
fn dec_ptr(memory: &[u8], ptr: wasi32::uintptr_t, len: usize) -> Result<*const u8> {
|
||||
// check for overflow
|
||||
let checked_len = (ptr as usize).checked_add(len).ok_or(Error::EFAULT)?;
|
||||
|
||||
// translate the pointer
|
||||
memory
|
||||
.get(ptr as usize..checked_len)
|
||||
.ok_or(Error::EFAULT)
|
||||
.map(|mem| mem.as_ptr())
|
||||
}
|
||||
|
||||
fn dec_ptr_mut(memory: &mut [u8], ptr: wasi32::uintptr_t, len: usize) -> Result<*mut u8> {
|
||||
// check for overflow
|
||||
let checked_len = (ptr as usize).checked_add(len).ok_or(Error::EFAULT)?;
|
||||
|
||||
// translate the pointer
|
||||
memory
|
||||
.get_mut(ptr as usize..checked_len)
|
||||
.ok_or(Error::EFAULT)
|
||||
.map(|mem| mem.as_mut_ptr())
|
||||
}
|
||||
|
||||
fn dec_ptr_to<'memory, T>(memory: &'memory [u8], ptr: wasi32::uintptr_t) -> Result<&'memory T> {
|
||||
// check that the ptr is aligned
|
||||
if ptr as usize % align_of::<T>() != 0 {
|
||||
return Err(Error::EINVAL);
|
||||
}
|
||||
|
||||
dec_ptr(memory, ptr, size_of::<T>()).map(|p| unsafe { &*(p as *const T) })
|
||||
}
|
||||
|
||||
fn dec_ptr_to_mut<'memory, T>(
|
||||
memory: &'memory mut [u8],
|
||||
ptr: wasi32::uintptr_t,
|
||||
) -> Result<&'memory mut T> {
|
||||
// check that the ptr is aligned
|
||||
if ptr as usize % align_of::<T>() != 0 {
|
||||
return Err(Error::EINVAL);
|
||||
}
|
||||
|
||||
dec_ptr_mut(memory, ptr, size_of::<T>()).map(|p| unsafe { &mut *(p as *mut T) })
|
||||
}
|
||||
|
||||
/// This function does not perform endianness conversions!
|
||||
fn dec_raw_byref<T>(memory: &[u8], ptr: wasi32::uintptr_t) -> Result<T> {
|
||||
dec_ptr_to::<T>(memory, ptr).map(|p| unsafe { ptr::read(p) })
|
||||
}
|
||||
|
||||
/// This function does not perform endianness conversions!
|
||||
fn enc_raw_byref<T>(memory: &mut [u8], ptr: wasi32::uintptr_t, t: T) -> Result<()> {
|
||||
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>
|
||||
where
|
||||
T: PrimInt,
|
||||
{
|
||||
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<()>
|
||||
where
|
||||
T: PrimInt,
|
||||
{
|
||||
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)> {
|
||||
// check alignment, and that length doesn't overflow
|
||||
if ptr as usize % align_of::<T>() != 0 {
|
||||
return Err(Error::EINVAL);
|
||||
}
|
||||
let len = dec_usize(len);
|
||||
let len_bytes = if let Some(len) = size_of::<T>().checked_mul(len) {
|
||||
len
|
||||
} else {
|
||||
return Err(Error::EOVERFLOW);
|
||||
};
|
||||
|
||||
Ok((len, len_bytes))
|
||||
}
|
||||
|
||||
fn dec_raw_slice_of<'memory, T>(
|
||||
memory: &'memory [u8],
|
||||
ptr: wasi32::uintptr_t,
|
||||
len: wasi32::size_t,
|
||||
) -> Result<&'memory [T]> {
|
||||
let (len, len_bytes) = check_slice_of::<T>(ptr, len)?;
|
||||
let ptr = dec_ptr(memory, ptr, len_bytes)? as *const T;
|
||||
Ok(unsafe { slice::from_raw_parts(ptr, len) })
|
||||
}
|
||||
|
||||
fn dec_raw_slice_of_mut<'memory, T>(
|
||||
memory: &'memory mut [u8],
|
||||
ptr: wasi32::uintptr_t,
|
||||
len: wasi32::size_t,
|
||||
) -> Result<&'memory mut [T]> {
|
||||
let (len, len_bytes) = check_slice_of::<T>(ptr, len)?;
|
||||
let ptr = dec_ptr_mut(memory, ptr, len_bytes)? as *mut T;
|
||||
Ok(unsafe { slice::from_raw_parts_mut(ptr, len) })
|
||||
}
|
||||
|
||||
fn raw_slice_for_enc<'memory, T>(
|
||||
memory: &'memory mut [u8],
|
||||
slice: &[T],
|
||||
ptr: wasi32::uintptr_t,
|
||||
) -> Result<&'memory mut [T]> {
|
||||
// check alignment
|
||||
if ptr as usize % align_of::<T>() != 0 {
|
||||
return Err(Error::EINVAL);
|
||||
}
|
||||
// check that length doesn't overflow
|
||||
let len_bytes = if let Some(len) = size_of::<T>().checked_mul(slice.len()) {
|
||||
len
|
||||
} else {
|
||||
return Err(Error::EOVERFLOW);
|
||||
};
|
||||
|
||||
// get the pointer into guest memory
|
||||
let ptr = dec_ptr_mut(memory, ptr, len_bytes)? as *mut T;
|
||||
|
||||
Ok(unsafe { slice::from_raw_parts_mut(ptr, slice.len()) })
|
||||
}
|
||||
|
||||
pub(crate) fn dec_slice_of_u8<'memory>(
|
||||
memory: &'memory [u8],
|
||||
ptr: wasi32::uintptr_t,
|
||||
len: wasi32::size_t,
|
||||
) -> Result<&'memory [u8]> {
|
||||
dec_raw_slice_of::<u8>(memory, ptr, len)
|
||||
}
|
||||
|
||||
pub(crate) fn dec_slice_of_mut_u8<'memory>(
|
||||
memory: &'memory mut [u8],
|
||||
ptr: wasi32::uintptr_t,
|
||||
len: wasi32::size_t,
|
||||
) -> Result<&'memory mut [u8]> {
|
||||
dec_raw_slice_of_mut::<u8>(memory, ptr, len)
|
||||
}
|
||||
|
||||
pub(crate) fn enc_slice_of_u8(
|
||||
memory: &mut [u8],
|
||||
slice: &[u8],
|
||||
ptr: wasi32::uintptr_t,
|
||||
) -> Result<()> {
|
||||
let output = raw_slice_for_enc::<u8>(memory, slice, ptr)?;
|
||||
|
||||
output.copy_from_slice(slice);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn enc_slice_of_wasi32_uintptr(
|
||||
memory: &mut [u8],
|
||||
slice: &[wasi32::uintptr_t],
|
||||
ptr: wasi32::uintptr_t,
|
||||
) -> Result<()> {
|
||||
let mut output_iter = raw_slice_for_enc::<wasi32::uintptr_t>(memory, slice, ptr)?.into_iter();
|
||||
|
||||
for p in slice {
|
||||
*output_iter.next().unwrap() = PrimInt::to_le(*p);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
macro_rules! dec_enc_scalar {
|
||||
($ty:ident, $dec_byref:ident, $enc_byref:ident) => {
|
||||
pub(crate) fn $dec_byref(memory: &mut [u8], ptr: wasi32::uintptr_t) -> Result<wasi::$ty> {
|
||||
dec_int_byref::<wasi::$ty>(memory, ptr)
|
||||
}
|
||||
|
||||
pub(crate) fn $enc_byref(
|
||||
memory: &mut [u8],
|
||||
ptr: wasi32::uintptr_t,
|
||||
x: wasi::$ty,
|
||||
) -> Result<()> {
|
||||
enc_int_byref::<wasi::$ty>(memory, ptr, x)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
pub(crate) fn dec_ciovec_slice(
|
||||
memory: &[u8],
|
||||
ptr: wasi32::uintptr_t,
|
||||
len: wasi32::size_t,
|
||||
) -> Result<Vec<host::__wasi_ciovec_t>> {
|
||||
let raw_slice = dec_raw_slice_of::<wasi32::__wasi_ciovec_t>(memory, ptr, len)?;
|
||||
|
||||
raw_slice
|
||||
.iter()
|
||||
.map(|raw_iov| {
|
||||
let len = dec_usize(PrimInt::from_le(raw_iov.buf_len));
|
||||
let buf = PrimInt::from_le(raw_iov.buf);
|
||||
Ok(host::__wasi_ciovec_t {
|
||||
buf: dec_ptr(memory, buf, len)? as *const u8,
|
||||
buf_len: len,
|
||||
})
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub(crate) fn dec_iovec_slice(
|
||||
memory: &[u8],
|
||||
ptr: wasi32::uintptr_t,
|
||||
len: wasi32::size_t,
|
||||
) -> Result<Vec<host::__wasi_iovec_t>> {
|
||||
let raw_slice = dec_raw_slice_of::<wasi32::__wasi_iovec_t>(memory, ptr, len)?;
|
||||
|
||||
raw_slice
|
||||
.iter()
|
||||
.map(|raw_iov| {
|
||||
let len = dec_usize(PrimInt::from_le(raw_iov.buf_len));
|
||||
let buf = PrimInt::from_le(raw_iov.buf);
|
||||
Ok(host::__wasi_iovec_t {
|
||||
buf: dec_ptr(memory, buf, len)? as *mut u8,
|
||||
buf_len: len,
|
||||
})
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
dec_enc_scalar!(__wasi_clockid_t, dec_clockid_byref, enc_clockid_byref);
|
||||
dec_enc_scalar!(__wasi_errno_t, dec_errno_byref, enc_errno_byref);
|
||||
dec_enc_scalar!(__wasi_exitcode_t, dec_exitcode_byref, enc_exitcode_byref);
|
||||
dec_enc_scalar!(__wasi_fd_t, dec_fd_byref, enc_fd_byref);
|
||||
dec_enc_scalar!(__wasi_fdflags_t, dec_fdflags_byref, enc_fdflags_byref);
|
||||
dec_enc_scalar!(__wasi_device_t, dev_device_byref, enc_device_byref);
|
||||
dec_enc_scalar!(__wasi_inode_t, dev_inode_byref, enc_inode_byref);
|
||||
dec_enc_scalar!(__wasi_linkcount_t, dev_linkcount_byref, enc_linkcount_byref);
|
||||
|
||||
pub(crate) fn dec_filestat_byref(
|
||||
memory: &mut [u8],
|
||||
filestat_ptr: wasi32::uintptr_t,
|
||||
) -> Result<wasi::__wasi_filestat_t> {
|
||||
let raw = dec_raw_byref::<wasi::__wasi_filestat_t>(memory, filestat_ptr)?;
|
||||
|
||||
Ok(wasi::__wasi_filestat_t {
|
||||
dev: PrimInt::from_le(raw.dev),
|
||||
ino: PrimInt::from_le(raw.ino),
|
||||
filetype: PrimInt::from_le(raw.filetype),
|
||||
nlink: PrimInt::from_le(raw.nlink),
|
||||
size: PrimInt::from_le(raw.size),
|
||||
atim: PrimInt::from_le(raw.atim),
|
||||
mtim: PrimInt::from_le(raw.mtim),
|
||||
ctim: PrimInt::from_le(raw.ctim),
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn enc_filestat_byref(
|
||||
memory: &mut [u8],
|
||||
filestat_ptr: wasi32::uintptr_t,
|
||||
filestat: wasi::__wasi_filestat_t,
|
||||
) -> Result<()> {
|
||||
let raw = wasi::__wasi_filestat_t {
|
||||
dev: PrimInt::to_le(filestat.dev),
|
||||
ino: PrimInt::to_le(filestat.ino),
|
||||
filetype: PrimInt::to_le(filestat.filetype),
|
||||
nlink: PrimInt::to_le(filestat.nlink),
|
||||
size: PrimInt::to_le(filestat.size),
|
||||
atim: PrimInt::to_le(filestat.atim),
|
||||
mtim: PrimInt::to_le(filestat.mtim),
|
||||
ctim: PrimInt::to_le(filestat.ctim),
|
||||
};
|
||||
|
||||
enc_raw_byref::<wasi::__wasi_filestat_t>(memory, filestat_ptr, raw)
|
||||
}
|
||||
|
||||
pub(crate) fn dec_fdstat_byref(
|
||||
memory: &mut [u8],
|
||||
fdstat_ptr: wasi32::uintptr_t,
|
||||
) -> Result<wasi::__wasi_fdstat_t> {
|
||||
let raw = dec_raw_byref::<wasi::__wasi_fdstat_t>(memory, fdstat_ptr)?;
|
||||
|
||||
Ok(wasi::__wasi_fdstat_t {
|
||||
fs_filetype: PrimInt::from_le(raw.fs_filetype),
|
||||
fs_flags: PrimInt::from_le(raw.fs_flags),
|
||||
fs_rights_base: PrimInt::from_le(raw.fs_rights_base),
|
||||
fs_rights_inheriting: PrimInt::from_le(raw.fs_rights_inheriting),
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn enc_fdstat_byref(
|
||||
memory: &mut [u8],
|
||||
fdstat_ptr: wasi32::uintptr_t,
|
||||
fdstat: wasi::__wasi_fdstat_t,
|
||||
) -> Result<()> {
|
||||
let raw = wasi::__wasi_fdstat_t {
|
||||
fs_filetype: PrimInt::to_le(fdstat.fs_filetype),
|
||||
fs_flags: PrimInt::to_le(fdstat.fs_flags),
|
||||
fs_rights_base: PrimInt::to_le(fdstat.fs_rights_base),
|
||||
fs_rights_inheriting: PrimInt::to_le(fdstat.fs_rights_inheriting),
|
||||
};
|
||||
|
||||
enc_raw_byref::<wasi::__wasi_fdstat_t>(memory, fdstat_ptr, raw)
|
||||
}
|
||||
|
||||
dec_enc_scalar!(__wasi_filedelta_t, dec_filedelta_byref, enc_filedelta_byref);
|
||||
dec_enc_scalar!(__wasi_filesize_t, dec_filesize_byref, enc_filesize_byref);
|
||||
dec_enc_scalar!(__wasi_filetype_t, dec_filetype_byref, enc_filetype_byref);
|
||||
|
||||
dec_enc_scalar!(
|
||||
__wasi_lookupflags_t,
|
||||
dec_lookupflags_byref,
|
||||
enc_lookupflags_byref
|
||||
);
|
||||
|
||||
dec_enc_scalar!(__wasi_oflags_t, dec_oflags_byref, enc_oflags_byref);
|
||||
|
||||
pub(crate) fn dec_prestat_byref(
|
||||
memory: &mut [u8],
|
||||
prestat_ptr: wasi32::uintptr_t,
|
||||
) -> Result<host::__wasi_prestat_t> {
|
||||
let raw = dec_raw_byref::<wasi32::__wasi_prestat_t>(memory, prestat_ptr)?;
|
||||
|
||||
match PrimInt::from_le(raw.pr_type) {
|
||||
wasi::__WASI_PREOPENTYPE_DIR => Ok(host::__wasi_prestat_t {
|
||||
pr_type: wasi::__WASI_PREOPENTYPE_DIR,
|
||||
u: host::__wasi_prestat_u_t {
|
||||
dir: host::__wasi_prestat_dir_t {
|
||||
pr_name_len: dec_usize(PrimInt::from_le(unsafe { raw.u.dir.pr_name_len })),
|
||||
},
|
||||
},
|
||||
}),
|
||||
_ => Err(Error::EINVAL),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn enc_prestat_byref(
|
||||
memory: &mut [u8],
|
||||
prestat_ptr: wasi32::uintptr_t,
|
||||
prestat: host::__wasi_prestat_t,
|
||||
) -> Result<()> {
|
||||
let raw = match prestat.pr_type {
|
||||
wasi::__WASI_PREOPENTYPE_DIR => Ok(wasi32::__wasi_prestat_t {
|
||||
pr_type: PrimInt::to_le(wasi::__WASI_PREOPENTYPE_DIR),
|
||||
u: wasi32::__wasi_prestat_u_t {
|
||||
dir: wasi32::__wasi_prestat_dir_t {
|
||||
pr_name_len: enc_usize(unsafe { prestat.u.dir.pr_name_len }),
|
||||
},
|
||||
},
|
||||
}),
|
||||
_ => Err(Error::EINVAL),
|
||||
}?;
|
||||
|
||||
enc_raw_byref::<wasi32::__wasi_prestat_t>(memory, prestat_ptr, raw)
|
||||
}
|
||||
|
||||
dec_enc_scalar!(__wasi_rights_t, dec_rights_byref, enc_rights_byref);
|
||||
dec_enc_scalar!(__wasi_timestamp_t, dec_timestamp_byref, enc_timestamp_byref);
|
||||
|
||||
pub(crate) fn dec_usize(size: wasi32::size_t) -> usize {
|
||||
usize::try_from(size).unwrap()
|
||||
}
|
||||
|
||||
pub(crate) fn enc_usize(size: usize) -> wasi32::size_t {
|
||||
wasi32::size_t::try_from(size).unwrap()
|
||||
}
|
||||
|
||||
pub(crate) fn enc_usize_byref(
|
||||
memory: &mut [u8],
|
||||
usize_ptr: wasi32::uintptr_t,
|
||||
host_usize: usize,
|
||||
) -> Result<()> {
|
||||
enc_int_byref::<wasi32::size_t>(memory, usize_ptr, enc_usize(host_usize))
|
||||
}
|
||||
|
||||
dec_enc_scalar!(__wasi_whence_t, dec_whence_byref, enc_whence_byref);
|
||||
|
||||
dec_enc_scalar!(
|
||||
__wasi_subclockflags_t,
|
||||
dec_subclockflags_byref,
|
||||
enc_subclockflags_byref
|
||||
);
|
||||
|
||||
dec_enc_scalar!(
|
||||
__wasi_eventrwflags_t,
|
||||
dec_eventrwflags_byref,
|
||||
enc_eventrwflags_byref
|
||||
);
|
||||
|
||||
dec_enc_scalar!(__wasi_eventtype_t, dec_eventtype_byref, enc_eventtype_byref);
|
||||
dec_enc_scalar!(__wasi_userdata_t, dec_userdata_byref, enc_userdata_byref);
|
||||
|
||||
pub(crate) fn dec_subscriptions(
|
||||
memory: &mut [u8],
|
||||
input: wasi32::uintptr_t,
|
||||
nsubscriptions: wasi32::size_t,
|
||||
) -> Result<Vec<wasi::__wasi_subscription_t>> {
|
||||
let raw_input_slice =
|
||||
dec_raw_slice_of::<wasi::__wasi_subscription_t>(memory, input, nsubscriptions)?;
|
||||
|
||||
raw_input_slice
|
||||
.into_iter()
|
||||
.map(|raw_subscription| {
|
||||
let userdata = PrimInt::from_le(raw_subscription.userdata);
|
||||
let r#type = PrimInt::from_le(raw_subscription.r#type);
|
||||
let raw_u = raw_subscription.u;
|
||||
let u = match r#type {
|
||||
wasi::__WASI_EVENTTYPE_CLOCK => wasi::__wasi_subscription_u_t {
|
||||
clock: unsafe {
|
||||
wasi::__wasi_subscription_clock_t {
|
||||
identifier: PrimInt::from_le(raw_u.clock.identifier),
|
||||
id: PrimInt::from_le(raw_u.clock.id),
|
||||
timeout: PrimInt::from_le(raw_u.clock.timeout),
|
||||
precision: PrimInt::from_le(raw_u.clock.precision),
|
||||
flags: PrimInt::from_le(raw_u.clock.flags),
|
||||
}
|
||||
},
|
||||
},
|
||||
wasi::__WASI_EVENTTYPE_FD_READ | wasi::__WASI_EVENTTYPE_FD_WRITE => {
|
||||
wasi::__wasi_subscription_u_t {
|
||||
fd_readwrite: wasi::__wasi_subscription_fd_readwrite_t {
|
||||
file_descriptor: PrimInt::from_le(unsafe {
|
||||
raw_u.fd_readwrite.file_descriptor
|
||||
}),
|
||||
},
|
||||
}
|
||||
}
|
||||
_ => return Err(Error::EINVAL),
|
||||
};
|
||||
Ok(wasi::__wasi_subscription_t {
|
||||
userdata,
|
||||
r#type,
|
||||
u,
|
||||
})
|
||||
})
|
||||
.collect::<Result<Vec<_>>>()
|
||||
}
|
||||
|
||||
pub(crate) fn enc_events(
|
||||
memory: &mut [u8],
|
||||
output: wasi32::uintptr_t,
|
||||
nsubscriptions: wasi32::size_t,
|
||||
events: Vec<wasi::__wasi_event_t>,
|
||||
) -> Result<()> {
|
||||
let mut raw_output_iter =
|
||||
dec_raw_slice_of_mut::<wasi::__wasi_event_t>(memory, output, nsubscriptions)?.into_iter();
|
||||
|
||||
for event in events.iter() {
|
||||
*raw_output_iter
|
||||
.next()
|
||||
.expect("the number of events cannot exceed the number of subscriptions") = {
|
||||
let fd_readwrite = unsafe { event.u.fd_readwrite };
|
||||
wasi::__wasi_event_t {
|
||||
userdata: PrimInt::to_le(event.userdata),
|
||||
r#type: PrimInt::to_le(event.r#type),
|
||||
error: PrimInt::to_le(event.error),
|
||||
u: wasi::__wasi_event_u_t {
|
||||
fd_readwrite: wasi::__wasi_event_fd_readwrite_t {
|
||||
nbytes: PrimInt::to_le(fd_readwrite.nbytes),
|
||||
flags: PrimInt::to_le(fd_readwrite.flags),
|
||||
},
|
||||
},
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
dec_enc_scalar!(__wasi_advice_t, dec_advice_byref, enc_advice_byref);
|
||||
dec_enc_scalar!(__wasi_fstflags_t, dec_fstflags_byref, enc_fstflags_byref);
|
||||
dec_enc_scalar!(__wasi_dircookie_t, dec_dircookie_byref, enc_dircookie_byref);
|
||||
16
crates/wasi-common/src/old/snapshot_0/mod.rs
Normal file
16
crates/wasi-common/src/old/snapshot_0/mod.rs
Normal file
@@ -0,0 +1,16 @@
|
||||
mod ctx;
|
||||
mod error;
|
||||
mod fdentry;
|
||||
mod helpers;
|
||||
mod host;
|
||||
pub mod hostcalls;
|
||||
mod hostcalls_impl;
|
||||
mod memory;
|
||||
mod sys;
|
||||
pub mod wasi;
|
||||
pub mod wasi32;
|
||||
|
||||
pub use ctx::{WasiCtx, WasiCtxBuilder};
|
||||
|
||||
pub type Error = error::Error;
|
||||
pub type Result<T> = std::result::Result<T, Error>;
|
||||
23
crates/wasi-common/src/old/snapshot_0/sys/mod.rs
Normal file
23
crates/wasi-common/src/old/snapshot_0/sys/mod.rs
Normal file
@@ -0,0 +1,23 @@
|
||||
use crate::old::snapshot_0::wasi;
|
||||
use cfg_if::cfg_if;
|
||||
|
||||
cfg_if! {
|
||||
if #[cfg(unix)] {
|
||||
mod unix;
|
||||
pub(crate) use self::unix::*;
|
||||
|
||||
pub(crate) fn errno_from_host(err: i32) -> wasi::__wasi_errno_t {
|
||||
host_impl::errno_from_nix(nix::errno::from_i32(err)).as_wasi_errno()
|
||||
}
|
||||
} else if #[cfg(windows)] {
|
||||
mod windows;
|
||||
pub(crate) use self::windows::*;
|
||||
pub use self::windows::preopen_dir;
|
||||
|
||||
pub(crate) fn errno_from_host(err: i32) -> wasi::__wasi_errno_t {
|
||||
host_impl::errno_from_win(winx::winerror::WinError::from_u32(err as u32))
|
||||
}
|
||||
} else {
|
||||
compile_error!("wasi-common doesn't compile for this platform yet");
|
||||
}
|
||||
}
|
||||
103
crates/wasi-common/src/old/snapshot_0/sys/unix/bsd/filetime.rs
Normal file
103
crates/wasi-common/src/old/snapshot_0/sys/unix/bsd/filetime.rs
Normal file
@@ -0,0 +1,103 @@
|
||||
//! This internal module consists of helper types and functions for dealing
|
||||
//! with setting the file times specific to BSD-style *nixes.
|
||||
use super::super::filetime::FileTime;
|
||||
use cfg_if::cfg_if;
|
||||
use std::ffi::CStr;
|
||||
use std::fs::File;
|
||||
use std::io;
|
||||
use std::sync::atomic::{AtomicUsize, Ordering::SeqCst};
|
||||
|
||||
cfg_if! {
|
||||
if #[cfg(any(
|
||||
target_os = "macos",
|
||||
target_os = "freebsd",
|
||||
target_os = "ios",
|
||||
target_os = "dragonfly"
|
||||
))] {
|
||||
pub(crate) const UTIME_NOW: i64 = -1;
|
||||
pub(crate) const UTIME_OMIT: i64 = -2;
|
||||
} else if #[cfg(target_os = "openbsd")] {
|
||||
// These are swapped compared to macos, freebsd, ios, and dragonfly.
|
||||
// https://github.com/openbsd/src/blob/master/sys/sys/stat.h#L187
|
||||
pub(crate) const UTIME_NOW: i64 = -2;
|
||||
pub(crate) const UTIME_OMIT: i64 = -1;
|
||||
} else if #[cfg(target_os = "netbsd" )] {
|
||||
// These are the same as for Linux.
|
||||
// http://cvsweb.netbsd.org/bsdweb.cgi/src/sys/sys/stat.h?rev=1.69&content-type=text/x-cvsweb-markup&only_with_tag=MAIN
|
||||
pub(crate) const UTIME_NOW: i64 = 1_073_741_823;
|
||||
pub(crate) const UTIME_OMIT: i64 = 1_073_741_822;
|
||||
}
|
||||
}
|
||||
|
||||
/// Wrapper for `utimensat` syscall, however, with an added twist such that `utimensat` symbol
|
||||
/// is firstly resolved (i.e., we check whether it exists on the host), and only used if that is
|
||||
/// the case. Otherwise, the syscall resorts to a less accurate `utimesat` emulated syscall.
|
||||
/// The original implementation can be found here: [filetime::unix::macos::set_times]
|
||||
///
|
||||
/// [filetime::unix::macos::set_times]: https://github.com/alexcrichton/filetime/blob/master/src/unix/macos.rs#L49
|
||||
pub(crate) fn utimensat(
|
||||
dirfd: &File,
|
||||
path: &str,
|
||||
atime: FileTime,
|
||||
mtime: FileTime,
|
||||
symlink_nofollow: bool,
|
||||
) -> io::Result<()> {
|
||||
use super::super::filetime::{to_timespec, utimesat};
|
||||
use std::ffi::CString;
|
||||
use std::os::unix::prelude::*;
|
||||
|
||||
// Attempt to use the `utimensat` syscall, but if it's not supported by the
|
||||
// current kernel then fall back to an older syscall.
|
||||
if let Some(func) = fetch_utimensat() {
|
||||
let flags = if symlink_nofollow {
|
||||
libc::AT_SYMLINK_NOFOLLOW
|
||||
} else {
|
||||
0
|
||||
};
|
||||
|
||||
let p = CString::new(path.as_bytes())?;
|
||||
let times = [to_timespec(&atime), to_timespec(&mtime)];
|
||||
let rc = unsafe { func(dirfd.as_raw_fd(), p.as_ptr(), times.as_ptr(), flags) };
|
||||
if rc == 0 {
|
||||
return Ok(());
|
||||
} else {
|
||||
return Err(io::Error::last_os_error());
|
||||
}
|
||||
}
|
||||
|
||||
utimesat(dirfd, path, atime, mtime, symlink_nofollow)
|
||||
}
|
||||
|
||||
/// Wraps `fetch` specifically targetting `utimensat` symbol. If the symbol exists
|
||||
/// on the host, then returns an `Some(unsafe fn)`.
|
||||
fn fetch_utimensat() -> Option<
|
||||
unsafe extern "C" fn(
|
||||
libc::c_int,
|
||||
*const libc::c_char,
|
||||
*const libc::timespec,
|
||||
libc::c_int,
|
||||
) -> libc::c_int,
|
||||
> {
|
||||
static ADDR: AtomicUsize = AtomicUsize::new(0);
|
||||
unsafe {
|
||||
fetch(&ADDR, CStr::from_bytes_with_nul_unchecked(b"utimensat\0"))
|
||||
.map(|sym| std::mem::transmute(sym))
|
||||
}
|
||||
}
|
||||
|
||||
/// Fetches a symbol by `name` and stores it in `cache`.
|
||||
fn fetch(cache: &AtomicUsize, name: &CStr) -> Option<usize> {
|
||||
match cache.load(SeqCst) {
|
||||
0 => {}
|
||||
1 => return None,
|
||||
n => return Some(n),
|
||||
}
|
||||
let sym = unsafe { libc::dlsym(libc::RTLD_DEFAULT, name.as_ptr() as *const _) };
|
||||
let (val, ret) = if sym.is_null() {
|
||||
(1, None)
|
||||
} else {
|
||||
(sym as usize, Some(sym as usize))
|
||||
};
|
||||
cache.store(val, SeqCst);
|
||||
return ret;
|
||||
}
|
||||
@@ -0,0 +1,298 @@
|
||||
use super::osfile::OsFile;
|
||||
use crate::old::snapshot_0::hostcalls_impl::PathGet;
|
||||
use crate::old::snapshot_0::sys::host_impl;
|
||||
use crate::old::snapshot_0::sys::unix::str_to_cstring;
|
||||
use crate::old::snapshot_0::{wasi, Error, Result};
|
||||
use nix::libc::{self, c_long, c_void};
|
||||
use std::convert::TryInto;
|
||||
use std::fs::File;
|
||||
use std::os::unix::prelude::AsRawFd;
|
||||
|
||||
pub(crate) fn path_unlink_file(resolved: PathGet) -> Result<()> {
|
||||
use nix::errno;
|
||||
use nix::libc::unlinkat;
|
||||
|
||||
let path_cstr = str_to_cstring(resolved.path())?;
|
||||
|
||||
// nix doesn't expose unlinkat() yet
|
||||
match unsafe { unlinkat(resolved.dirfd().as_raw_fd(), path_cstr.as_ptr(), 0) } {
|
||||
0 => Ok(()),
|
||||
_ => {
|
||||
let mut e = errno::Errno::last();
|
||||
|
||||
// Non-Linux implementations may return EPERM when attempting to remove a
|
||||
// directory without REMOVEDIR. While that's what POSIX specifies, it's
|
||||
// less useful. Adjust this to EISDIR. It doesn't matter that this is not
|
||||
// atomic with the unlinkat, because if the file is removed and a directory
|
||||
// is created before fstatat sees it, we're racing with that change anyway
|
||||
// and unlinkat could have legitimately seen the directory if the race had
|
||||
// turned out differently.
|
||||
use nix::fcntl::AtFlags;
|
||||
use nix::sys::stat::{fstatat, SFlag};
|
||||
|
||||
if e == errno::Errno::EPERM {
|
||||
if let Ok(stat) = fstatat(
|
||||
resolved.dirfd().as_raw_fd(),
|
||||
resolved.path(),
|
||||
AtFlags::AT_SYMLINK_NOFOLLOW,
|
||||
) {
|
||||
if SFlag::from_bits_truncate(stat.st_mode).contains(SFlag::S_IFDIR) {
|
||||
e = errno::Errno::EISDIR;
|
||||
}
|
||||
} else {
|
||||
e = errno::Errno::last();
|
||||
}
|
||||
}
|
||||
|
||||
Err(host_impl::errno_from_nix(e))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn path_symlink(old_path: &str, resolved: PathGet) -> Result<()> {
|
||||
use nix::{errno::Errno, fcntl::AtFlags, libc::symlinkat, sys::stat::fstatat};
|
||||
|
||||
let old_path_cstr = str_to_cstring(old_path)?;
|
||||
let new_path_cstr = str_to_cstring(resolved.path())?;
|
||||
|
||||
log::debug!("path_symlink old_path = {:?}", old_path);
|
||||
log::debug!("path_symlink resolved = {:?}", resolved);
|
||||
|
||||
let res = unsafe {
|
||||
symlinkat(
|
||||
old_path_cstr.as_ptr(),
|
||||
resolved.dirfd().as_raw_fd(),
|
||||
new_path_cstr.as_ptr(),
|
||||
)
|
||||
};
|
||||
if res != 0 {
|
||||
match Errno::last() {
|
||||
Errno::ENOTDIR => {
|
||||
// On BSD, symlinkat returns ENOTDIR when it should in fact
|
||||
// return a EEXIST. It seems that it gets confused with by
|
||||
// the trailing slash in the target path. Thus, we strip
|
||||
// the trailing slash and check if the path exists, and
|
||||
// adjust the error code appropriately.
|
||||
let new_path = resolved.path().trim_end_matches('/');
|
||||
if let Ok(_) = fstatat(
|
||||
resolved.dirfd().as_raw_fd(),
|
||||
new_path,
|
||||
AtFlags::AT_SYMLINK_NOFOLLOW,
|
||||
) {
|
||||
Err(Error::EEXIST)
|
||||
} else {
|
||||
Err(Error::ENOTDIR)
|
||||
}
|
||||
}
|
||||
x => Err(host_impl::errno_from_nix(x)),
|
||||
}
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn path_rename(resolved_old: PathGet, resolved_new: PathGet) -> Result<()> {
|
||||
use nix::{errno::Errno, fcntl::AtFlags, libc::renameat, sys::stat::fstatat};
|
||||
let old_path_cstr = str_to_cstring(resolved_old.path())?;
|
||||
let new_path_cstr = str_to_cstring(resolved_new.path())?;
|
||||
|
||||
let res = unsafe {
|
||||
renameat(
|
||||
resolved_old.dirfd().as_raw_fd(),
|
||||
old_path_cstr.as_ptr(),
|
||||
resolved_new.dirfd().as_raw_fd(),
|
||||
new_path_cstr.as_ptr(),
|
||||
)
|
||||
};
|
||||
if res != 0 {
|
||||
// Currently, this is verified to be correct on macOS, where
|
||||
// ENOENT can be returned in case when we try to rename a file
|
||||
// into a name with a trailing slash. On macOS, if the latter does
|
||||
// not exist, an ENOENT is thrown, whereas on Linux we observe the
|
||||
// correct behaviour of throwing an ENOTDIR since the destination is
|
||||
// indeed not a directory.
|
||||
//
|
||||
// TODO
|
||||
// Verify on other BSD-based OSes.
|
||||
match Errno::last() {
|
||||
Errno::ENOENT => {
|
||||
// check if the source path exists
|
||||
if let Ok(_) = fstatat(
|
||||
resolved_old.dirfd().as_raw_fd(),
|
||||
resolved_old.path(),
|
||||
AtFlags::AT_SYMLINK_NOFOLLOW,
|
||||
) {
|
||||
// check if destination contains a trailing slash
|
||||
if resolved_new.path().contains('/') {
|
||||
Err(Error::ENOTDIR)
|
||||
} else {
|
||||
Err(Error::ENOENT)
|
||||
}
|
||||
} else {
|
||||
Err(Error::ENOENT)
|
||||
}
|
||||
}
|
||||
x => Err(host_impl::errno_from_nix(x)),
|
||||
}
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn fd_readdir(
|
||||
os_file: &mut OsFile,
|
||||
host_buf: &mut [u8],
|
||||
cookie: wasi::__wasi_dircookie_t,
|
||||
) -> Result<usize> {
|
||||
use crate::old::snapshot_0::sys::unix::bsd::osfile::DirStream;
|
||||
use libc::{fdopendir, readdir, rewinddir, seekdir, telldir};
|
||||
use nix::errno::Errno;
|
||||
use std::ffi::CStr;
|
||||
use std::mem::ManuallyDrop;
|
||||
use std::sync::Mutex;
|
||||
|
||||
let dir_stream = match os_file.dir_stream {
|
||||
Some(ref mut dir_stream) => dir_stream,
|
||||
None => {
|
||||
let file = os_file.file.try_clone()?;
|
||||
let dir_ptr = unsafe { fdopendir(file.as_raw_fd()) };
|
||||
os_file.dir_stream.get_or_insert(Mutex::new(DirStream {
|
||||
file: ManuallyDrop::new(file),
|
||||
dir_ptr,
|
||||
}))
|
||||
}
|
||||
};
|
||||
let dir_stream = dir_stream.lock().unwrap();
|
||||
|
||||
let host_buf_ptr = host_buf.as_mut_ptr();
|
||||
let host_buf_len = host_buf.len();
|
||||
|
||||
if cookie != wasi::__WASI_DIRCOOKIE_START {
|
||||
unsafe { seekdir(dir_stream.dir_ptr, cookie as c_long) };
|
||||
} else {
|
||||
unsafe { rewinddir(dir_stream.dir_ptr) };
|
||||
}
|
||||
|
||||
let mut left = host_buf_len;
|
||||
let mut host_buf_offset: usize = 0;
|
||||
|
||||
loop {
|
||||
let errno = Errno::last();
|
||||
let host_entry_ptr = unsafe { readdir(dir_stream.dir_ptr) };
|
||||
if host_entry_ptr.is_null() {
|
||||
if errno != Errno::last() {
|
||||
// TODO Is this correct?
|
||||
// According to POSIX man (for Linux though!), there was an error
|
||||
// if the errno value has changed at some point during the sequence
|
||||
// of readdir calls
|
||||
return Err(host_impl::errno_from_nix(Errno::last()));
|
||||
} else {
|
||||
// Not an error
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
let host_entry = unsafe { *host_entry_ptr };
|
||||
let mut wasi_entry: wasi::__wasi_dirent_t = host_impl::dirent_from_host(&host_entry)?;
|
||||
// Set d_next manually:
|
||||
// * on macOS d_seekoff is not set for some reason
|
||||
// * on FreeBSD d_seekoff doesn't exist; there is d_off but it is
|
||||
// not equivalent to the value read from telldir call
|
||||
wasi_entry.d_next = unsafe { telldir(dir_stream.dir_ptr) } as wasi::__wasi_dircookie_t;
|
||||
|
||||
log::debug!("fd_readdir host_entry = {:?}", host_entry);
|
||||
log::debug!("fd_readdir wasi_entry = {:?}", wasi_entry);
|
||||
|
||||
let name_len = host_entry.d_namlen.try_into()?;
|
||||
let required_space = std::mem::size_of_val(&wasi_entry) + name_len;
|
||||
|
||||
if required_space > left {
|
||||
break;
|
||||
}
|
||||
|
||||
let name = unsafe { CStr::from_ptr(host_entry.d_name.as_ptr()) }.to_str()?;
|
||||
log::debug!("fd_readdir entry name = {}", name);
|
||||
|
||||
unsafe {
|
||||
let ptr = host_buf_ptr.offset(host_buf_offset.try_into()?) as *mut c_void
|
||||
as *mut wasi::__wasi_dirent_t;
|
||||
*ptr = wasi_entry;
|
||||
}
|
||||
host_buf_offset += std::mem::size_of_val(&wasi_entry);
|
||||
|
||||
unsafe {
|
||||
std::ptr::copy_nonoverlapping(
|
||||
name.as_ptr(),
|
||||
host_buf_ptr.offset(host_buf_offset.try_into()?),
|
||||
name_len,
|
||||
)
|
||||
};
|
||||
host_buf_offset += name_len;
|
||||
left -= required_space;
|
||||
}
|
||||
|
||||
Ok(host_buf_len - left)
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "macos", target_os = "ios"))]
|
||||
pub(crate) fn fd_advise(
|
||||
file: &File,
|
||||
advice: wasi::__wasi_advice_t,
|
||||
offset: wasi::__wasi_filesize_t,
|
||||
len: wasi::__wasi_filesize_t,
|
||||
) -> Result<()> {
|
||||
use nix::errno::Errno;
|
||||
|
||||
match advice {
|
||||
wasi::__WASI_ADVICE_DONTNEED => return Ok(()),
|
||||
// unfortunately, the advisory syscall in macOS doesn't take any flags of this
|
||||
// sort (unlike on Linux), hence, they are left here as a noop
|
||||
wasi::__WASI_ADVICE_SEQUENTIAL
|
||||
| wasi::__WASI_ADVICE_WILLNEED
|
||||
| wasi::__WASI_ADVICE_NOREUSE
|
||||
| wasi::__WASI_ADVICE_RANDOM
|
||||
| wasi::__WASI_ADVICE_NORMAL => {}
|
||||
_ => return Err(Error::EINVAL),
|
||||
}
|
||||
|
||||
// From macOS man pages:
|
||||
// F_RDADVISE Issue an advisory read async with no copy to user.
|
||||
//
|
||||
// The F_RDADVISE command operates on the following structure which holds information passed from
|
||||
// the user to the system:
|
||||
//
|
||||
// struct radvisory {
|
||||
// off_t ra_offset; /* offset into the file */
|
||||
// int ra_count; /* size of the read */
|
||||
// };
|
||||
let advisory = libc::radvisory {
|
||||
ra_offset: offset.try_into()?,
|
||||
ra_count: len.try_into()?,
|
||||
};
|
||||
|
||||
let res = unsafe { libc::fcntl(file.as_raw_fd(), libc::F_RDADVISE, &advisory) };
|
||||
Errno::result(res).map(|_| ()).map_err(Error::from)
|
||||
}
|
||||
|
||||
// TODO
|
||||
// It seems that at least some BSDs do support `posix_fadvise`,
|
||||
// so we should investigate further.
|
||||
#[cfg(not(any(target_os = "macos", target_os = "ios")))]
|
||||
pub(crate) fn fd_advise(
|
||||
_file: &File,
|
||||
advice: wasi::__wasi_advice_t,
|
||||
_offset: wasi::__wasi_filesize_t,
|
||||
_len: wasi::__wasi_filesize_t,
|
||||
) -> Result<()> {
|
||||
match advice {
|
||||
wasi::__WASI_ADVICE_DONTNEED
|
||||
| wasi::__WASI_ADVICE_SEQUENTIAL
|
||||
| wasi::__WASI_ADVICE_WILLNEED
|
||||
| wasi::__WASI_ADVICE_NOREUSE
|
||||
| wasi::__WASI_ADVICE_RANDOM
|
||||
| wasi::__WASI_ADVICE_NORMAL => {}
|
||||
_ => return Err(Error::EINVAL),
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
41
crates/wasi-common/src/old/snapshot_0/sys/unix/bsd/mod.rs
Normal file
41
crates/wasi-common/src/old/snapshot_0/sys/unix/bsd/mod.rs
Normal file
@@ -0,0 +1,41 @@
|
||||
pub(crate) mod filetime;
|
||||
pub(crate) mod hostcalls_impl;
|
||||
pub(crate) mod osfile;
|
||||
|
||||
pub(crate) mod fdentry_impl {
|
||||
use crate::old::snapshot_0::{sys::host_impl, Result};
|
||||
use std::os::unix::prelude::AsRawFd;
|
||||
|
||||
pub(crate) unsafe fn isatty(fd: &impl AsRawFd) -> Result<bool> {
|
||||
let res = libc::isatty(fd.as_raw_fd());
|
||||
if res == 1 {
|
||||
// isatty() returns 1 if fd is an open file descriptor referring to a terminal...
|
||||
Ok(true)
|
||||
} else {
|
||||
// ... otherwise 0 is returned, and errno is set to indicate the error.
|
||||
match nix::errno::Errno::last() {
|
||||
nix::errno::Errno::ENOTTY => Ok(false),
|
||||
x => Err(host_impl::errno_from_nix(x)),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) mod host_impl {
|
||||
use super::super::host_impl::dirent_filetype_from_host;
|
||||
use crate::old::snapshot_0::{wasi, Result};
|
||||
|
||||
pub(crate) const O_RSYNC: nix::fcntl::OFlag = nix::fcntl::OFlag::O_SYNC;
|
||||
|
||||
pub(crate) fn dirent_from_host(
|
||||
host_entry: &nix::libc::dirent,
|
||||
) -> Result<wasi::__wasi_dirent_t> {
|
||||
let mut entry = unsafe { std::mem::zeroed::<wasi::__wasi_dirent_t>() };
|
||||
let d_type = dirent_filetype_from_host(host_entry)?;
|
||||
entry.d_ino = host_entry.d_ino;
|
||||
entry.d_next = host_entry.d_seekoff;
|
||||
entry.d_namlen = u32::from(host_entry.d_namlen);
|
||||
entry.d_type = d_type;
|
||||
Ok(entry)
|
||||
}
|
||||
}
|
||||
52
crates/wasi-common/src/old/snapshot_0/sys/unix/bsd/osfile.rs
Normal file
52
crates/wasi-common/src/old/snapshot_0/sys/unix/bsd/osfile.rs
Normal file
@@ -0,0 +1,52 @@
|
||||
use std::fs;
|
||||
use std::mem::ManuallyDrop;
|
||||
use std::ops::{Deref, DerefMut};
|
||||
use std::os::unix::prelude::{AsRawFd, RawFd};
|
||||
use std::sync::Mutex;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct DirStream {
|
||||
pub(crate) file: ManuallyDrop<fs::File>,
|
||||
pub(crate) dir_ptr: *mut libc::DIR,
|
||||
}
|
||||
|
||||
impl Drop for DirStream {
|
||||
fn drop(&mut self) {
|
||||
unsafe { libc::closedir(self.dir_ptr) };
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct OsFile {
|
||||
pub(crate) file: fs::File,
|
||||
pub(crate) dir_stream: Option<Mutex<DirStream>>,
|
||||
}
|
||||
|
||||
impl From<fs::File> for OsFile {
|
||||
fn from(file: fs::File) -> Self {
|
||||
Self {
|
||||
file,
|
||||
dir_stream: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRawFd for OsFile {
|
||||
fn as_raw_fd(&self) -> RawFd {
|
||||
self.file.as_raw_fd()
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for OsFile {
|
||||
type Target = fs::File;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.file
|
||||
}
|
||||
}
|
||||
|
||||
impl DerefMut for OsFile {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
&mut self.file
|
||||
}
|
||||
}
|
||||
216
crates/wasi-common/src/old/snapshot_0/sys/unix/dir.rs
Normal file
216
crates/wasi-common/src/old/snapshot_0/sys/unix/dir.rs
Normal file
@@ -0,0 +1,216 @@
|
||||
// Based on src/dir.rs from nix
|
||||
#![allow(unused)] // temporarily, until BSD catches up with this change
|
||||
use crate::old::snapshot_0::hostcalls_impl::FileType;
|
||||
use libc;
|
||||
use nix::{errno::Errno, Error, Result};
|
||||
use std::os::unix::io::{AsRawFd, IntoRawFd, RawFd};
|
||||
use std::{ffi, ptr};
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
use libc::{dirent64 as dirent, readdir64_r as readdir_r};
|
||||
|
||||
#[cfg(not(target_os = "linux"))]
|
||||
use libc::{dirent, readdir_r};
|
||||
|
||||
/// An open directory.
|
||||
///
|
||||
/// This is a lower-level interface than `std::fs::ReadDir`. Notable differences:
|
||||
/// * can be opened from a file descriptor (as returned by `openat`, perhaps before knowing
|
||||
/// if the path represents a file or directory).
|
||||
/// * implements `AsRawFd`, so it can be passed to `fstat`, `openat`, etc.
|
||||
/// The file descriptor continues to be owned by the `Dir`, so callers must not keep a `RawFd`
|
||||
/// after the `Dir` is dropped.
|
||||
/// * can be iterated through multiple times without closing and reopening the file
|
||||
/// descriptor. Each iteration rewinds when finished.
|
||||
/// * returns entries for `.` (current directory) and `..` (parent directory).
|
||||
/// * returns entries' names as a `CStr` (no allocation or conversion beyond whatever libc
|
||||
/// does).
|
||||
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
|
||||
pub(crate) struct Dir(ptr::NonNull<libc::DIR>);
|
||||
|
||||
impl Dir {
|
||||
/// Converts from a descriptor-based object, closing the descriptor on success or failure.
|
||||
#[inline]
|
||||
pub(crate) fn from<F: IntoRawFd>(fd: F) -> Result<Self> {
|
||||
unsafe { Self::from_fd(fd.into_raw_fd()) }
|
||||
}
|
||||
|
||||
/// Converts from a file descriptor, closing it on success or failure.
|
||||
unsafe fn from_fd(fd: RawFd) -> Result<Self> {
|
||||
let d = libc::fdopendir(fd);
|
||||
if d.is_null() {
|
||||
let e = Error::last();
|
||||
libc::close(fd);
|
||||
return Err(e);
|
||||
};
|
||||
// Always guaranteed to be non-null by the previous check
|
||||
Ok(Self(ptr::NonNull::new(d).unwrap()))
|
||||
}
|
||||
|
||||
/// Set the position of the directory stream, see `seekdir(3)`.
|
||||
#[cfg(not(target_os = "android"))]
|
||||
pub(crate) fn seek(&mut self, loc: SeekLoc) {
|
||||
unsafe { libc::seekdir(self.0.as_ptr(), loc.0) }
|
||||
}
|
||||
|
||||
/// Reset directory stream, see `rewinddir(3)`.
|
||||
pub(crate) fn rewind(&mut self) {
|
||||
unsafe { libc::rewinddir(self.0.as_ptr()) }
|
||||
}
|
||||
|
||||
/// Get the current position in the directory stream.
|
||||
///
|
||||
/// If this location is given to `Dir::seek`, the entries up to the previously returned
|
||||
/// will be omitted and the iteration will start from the currently pending directory entry.
|
||||
#[cfg(not(target_os = "android"))]
|
||||
#[allow(dead_code)]
|
||||
pub(crate) fn tell(&self) -> SeekLoc {
|
||||
let loc = unsafe { libc::telldir(self.0.as_ptr()) };
|
||||
SeekLoc(loc)
|
||||
}
|
||||
}
|
||||
|
||||
// `Dir` is not `Sync`. With the current implementation, it could be, but according to
|
||||
// https://www.gnu.org/software/libc/manual/html_node/Reading_002fClosing-Directory.html,
|
||||
// future versions of POSIX are likely to obsolete `readdir_r` and specify that it's unsafe to
|
||||
// call `readdir` simultaneously from multiple threads.
|
||||
//
|
||||
// `Dir` is safe to pass from one thread to another, as it's not reference-counted.
|
||||
unsafe impl Send for Dir {}
|
||||
|
||||
impl AsRawFd for Dir {
|
||||
fn as_raw_fd(&self) -> RawFd {
|
||||
unsafe { libc::dirfd(self.0.as_ptr()) }
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for Dir {
|
||||
fn drop(&mut self) {
|
||||
unsafe { libc::closedir(self.0.as_ptr()) };
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct IntoIter(Dir);
|
||||
impl Iterator for IntoIter {
|
||||
type Item = Result<Entry>;
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
unsafe {
|
||||
// Note: POSIX specifies that portable applications should dynamically allocate a
|
||||
// buffer with room for a `d_name` field of size `pathconf(..., _PC_NAME_MAX)` plus 1
|
||||
// for the NUL byte. It doesn't look like the std library does this; it just uses
|
||||
// fixed-sized buffers (and libc's dirent seems to be sized so this is appropriate).
|
||||
// Probably fine here too then.
|
||||
//
|
||||
// See `impl Iterator for ReadDir` [1] for more details.
|
||||
// [1] https://github.com/rust-lang/rust/blob/master/src/libstd/sys/unix/fs.rs
|
||||
let mut ent = std::mem::MaybeUninit::<dirent>::uninit();
|
||||
let mut result = ptr::null_mut();
|
||||
if let Err(e) = Errno::result(readdir_r(
|
||||
(self.0).0.as_ptr(),
|
||||
ent.as_mut_ptr(),
|
||||
&mut result,
|
||||
)) {
|
||||
return Some(Err(e));
|
||||
}
|
||||
if result.is_null() {
|
||||
None
|
||||
} else {
|
||||
assert_eq!(result, ent.as_mut_ptr(), "readdir_r specification violated");
|
||||
Some(Ok(Entry(ent.assume_init())))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoIterator for Dir {
|
||||
type IntoIter = IntoIter;
|
||||
type Item = Result<Entry>;
|
||||
|
||||
fn into_iter(self) -> IntoIter {
|
||||
IntoIter(self)
|
||||
}
|
||||
}
|
||||
|
||||
/// A directory entry, similar to `std::fs::DirEntry`.
|
||||
///
|
||||
/// Note that unlike the std version, this may represent the `.` or `..` entries.
|
||||
#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
|
||||
#[repr(transparent)]
|
||||
pub(crate) struct Entry(dirent);
|
||||
|
||||
pub(crate) type Type = FileType;
|
||||
|
||||
impl Entry {
|
||||
/// Returns the inode number (`d_ino`) of the underlying `dirent`.
|
||||
#[cfg(any(
|
||||
target_os = "android",
|
||||
target_os = "emscripten",
|
||||
target_os = "fuchsia",
|
||||
target_os = "haiku",
|
||||
target_os = "ios",
|
||||
target_os = "l4re",
|
||||
target_os = "linux",
|
||||
target_os = "macos",
|
||||
target_os = "solaris"
|
||||
))]
|
||||
pub(crate) fn ino(&self) -> u64 {
|
||||
self.0.d_ino.into()
|
||||
}
|
||||
|
||||
/// Returns the inode number (`d_fileno`) of the underlying `dirent`.
|
||||
#[cfg(not(any(
|
||||
target_os = "android",
|
||||
target_os = "emscripten",
|
||||
target_os = "fuchsia",
|
||||
target_os = "haiku",
|
||||
target_os = "ios",
|
||||
target_os = "l4re",
|
||||
target_os = "linux",
|
||||
target_os = "macos",
|
||||
target_os = "solaris"
|
||||
)))]
|
||||
pub(crate) fn ino(&self) -> u64 {
|
||||
u64::from(self.0.d_fileno)
|
||||
}
|
||||
|
||||
/// Returns the bare file name of this directory entry without any other leading path component.
|
||||
pub(crate) fn file_name(&self) -> &ffi::CStr {
|
||||
unsafe { ::std::ffi::CStr::from_ptr(self.0.d_name.as_ptr()) }
|
||||
}
|
||||
|
||||
/// Returns the type of this directory entry, if known.
|
||||
///
|
||||
/// See platform `readdir(3)` or `dirent(5)` manpage for when the file type is known;
|
||||
/// notably, some Linux filesystems don't implement this. The caller should use `stat` or
|
||||
/// `fstat` if this returns `None`.
|
||||
pub(crate) fn file_type(&self) -> FileType {
|
||||
match self.0.d_type {
|
||||
libc::DT_CHR => Type::CharacterDevice,
|
||||
libc::DT_DIR => Type::Directory,
|
||||
libc::DT_BLK => Type::BlockDevice,
|
||||
libc::DT_REG => Type::RegularFile,
|
||||
libc::DT_LNK => Type::Symlink,
|
||||
/* libc::DT_UNKNOWN | libc::DT_SOCK | libc::DT_FIFO */ _ => Type::Unknown,
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
pub(crate) fn seek_loc(&self) -> SeekLoc {
|
||||
unsafe { SeekLoc::from_raw(self.0.d_off) }
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "android"))]
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub(crate) struct SeekLoc(libc::c_long);
|
||||
|
||||
#[cfg(not(target_os = "android"))]
|
||||
impl SeekLoc {
|
||||
pub(crate) unsafe fn from_raw(loc: i64) -> Self {
|
||||
Self(loc.into())
|
||||
}
|
||||
|
||||
pub(crate) fn to_raw(&self) -> i64 {
|
||||
self.0.into()
|
||||
}
|
||||
}
|
||||
135
crates/wasi-common/src/old/snapshot_0/sys/unix/fdentry_impl.rs
Normal file
135
crates/wasi-common/src/old/snapshot_0/sys/unix/fdentry_impl.rs
Normal file
@@ -0,0 +1,135 @@
|
||||
use crate::old::snapshot_0::fdentry::Descriptor;
|
||||
use crate::old::snapshot_0::{wasi, Error, Result};
|
||||
use std::io;
|
||||
use std::os::unix::prelude::{AsRawFd, FileTypeExt, FromRawFd, RawFd};
|
||||
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(target_os = "linux")] {
|
||||
pub(crate) use super::linux::osfile::*;
|
||||
pub(crate) use super::linux::fdentry_impl::*;
|
||||
} else if #[cfg(any(
|
||||
target_os = "macos",
|
||||
target_os = "netbsd",
|
||||
target_os = "freebsd",
|
||||
target_os = "openbsd",
|
||||
target_os = "ios",
|
||||
target_os = "dragonfly"
|
||||
))] {
|
||||
pub(crate) use super::bsd::osfile::*;
|
||||
pub(crate) use super::bsd::fdentry_impl::*;
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRawFd for Descriptor {
|
||||
fn as_raw_fd(&self) -> RawFd {
|
||||
match self {
|
||||
Self::OsFile(file) => file.as_raw_fd(),
|
||||
Self::Stdin => io::stdin().as_raw_fd(),
|
||||
Self::Stdout => io::stdout().as_raw_fd(),
|
||||
Self::Stderr => io::stderr().as_raw_fd(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 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<(
|
||||
wasi::__wasi_filetype_t,
|
||||
wasi::__wasi_rights_t,
|
||||
wasi::__wasi_rights_t,
|
||||
)> {
|
||||
let (file_type, mut rights_base, rights_inheriting) = determine_type_rights(fd)?;
|
||||
|
||||
use nix::fcntl::{fcntl, OFlag, F_GETFL};
|
||||
let flags_bits = fcntl(fd.as_raw_fd(), F_GETFL)?;
|
||||
let flags = OFlag::from_bits_truncate(flags_bits);
|
||||
let accmode = flags & OFlag::O_ACCMODE;
|
||||
if accmode == OFlag::O_RDONLY {
|
||||
rights_base &= !wasi::__WASI_RIGHTS_FD_WRITE;
|
||||
} else if accmode == OFlag::O_WRONLY {
|
||||
rights_base &= !wasi::__WASI_RIGHTS_FD_READ;
|
||||
}
|
||||
|
||||
Ok((file_type, rights_base, rights_inheriting))
|
||||
}
|
||||
|
||||
/// This function is unsafe because it operates on a raw file descriptor.
|
||||
pub(crate) unsafe fn determine_type_rights<Fd: AsRawFd>(
|
||||
fd: &Fd,
|
||||
) -> Result<(
|
||||
wasi::__wasi_filetype_t,
|
||||
wasi::__wasi_rights_t,
|
||||
wasi::__wasi_rights_t,
|
||||
)> {
|
||||
let (file_type, rights_base, rights_inheriting) = {
|
||||
// we just make a `File` here for convenience; we don't want it to close when it drops
|
||||
let file = std::mem::ManuallyDrop::new(std::fs::File::from_raw_fd(fd.as_raw_fd()));
|
||||
let ft = file.metadata()?.file_type();
|
||||
if ft.is_block_device() {
|
||||
log::debug!("Host fd {:?} is a block device", fd.as_raw_fd());
|
||||
(
|
||||
wasi::__WASI_FILETYPE_BLOCK_DEVICE,
|
||||
wasi::RIGHTS_BLOCK_DEVICE_BASE,
|
||||
wasi::RIGHTS_BLOCK_DEVICE_INHERITING,
|
||||
)
|
||||
} else if ft.is_char_device() {
|
||||
log::debug!("Host fd {:?} is a char device", fd.as_raw_fd());
|
||||
if isatty(fd)? {
|
||||
(
|
||||
wasi::__WASI_FILETYPE_CHARACTER_DEVICE,
|
||||
wasi::RIGHTS_TTY_BASE,
|
||||
wasi::RIGHTS_TTY_BASE,
|
||||
)
|
||||
} else {
|
||||
(
|
||||
wasi::__WASI_FILETYPE_CHARACTER_DEVICE,
|
||||
wasi::RIGHTS_CHARACTER_DEVICE_BASE,
|
||||
wasi::RIGHTS_CHARACTER_DEVICE_INHERITING,
|
||||
)
|
||||
}
|
||||
} else if ft.is_dir() {
|
||||
log::debug!("Host fd {:?} is a directory", fd.as_raw_fd());
|
||||
(
|
||||
wasi::__WASI_FILETYPE_DIRECTORY,
|
||||
wasi::RIGHTS_DIRECTORY_BASE,
|
||||
wasi::RIGHTS_DIRECTORY_INHERITING,
|
||||
)
|
||||
} else if ft.is_file() {
|
||||
log::debug!("Host fd {:?} is a file", fd.as_raw_fd());
|
||||
(
|
||||
wasi::__WASI_FILETYPE_REGULAR_FILE,
|
||||
wasi::RIGHTS_REGULAR_FILE_BASE,
|
||||
wasi::RIGHTS_REGULAR_FILE_INHERITING,
|
||||
)
|
||||
} else if ft.is_socket() {
|
||||
log::debug!("Host fd {:?} is a socket", fd.as_raw_fd());
|
||||
use nix::sys::socket;
|
||||
match socket::getsockopt(fd.as_raw_fd(), socket::sockopt::SockType)? {
|
||||
socket::SockType::Datagram => (
|
||||
wasi::__WASI_FILETYPE_SOCKET_DGRAM,
|
||||
wasi::RIGHTS_SOCKET_BASE,
|
||||
wasi::RIGHTS_SOCKET_INHERITING,
|
||||
),
|
||||
socket::SockType::Stream => (
|
||||
wasi::__WASI_FILETYPE_SOCKET_STREAM,
|
||||
wasi::RIGHTS_SOCKET_BASE,
|
||||
wasi::RIGHTS_SOCKET_INHERITING,
|
||||
),
|
||||
_ => return Err(Error::EINVAL),
|
||||
}
|
||||
} else if ft.is_fifo() {
|
||||
log::debug!("Host fd {:?} is a fifo", fd.as_raw_fd());
|
||||
(
|
||||
wasi::__WASI_FILETYPE_UNKNOWN,
|
||||
wasi::RIGHTS_REGULAR_FILE_BASE,
|
||||
wasi::RIGHTS_REGULAR_FILE_INHERITING,
|
||||
)
|
||||
} else {
|
||||
log::debug!("Host fd {:?} is unknown", fd.as_raw_fd());
|
||||
return Err(Error::EINVAL);
|
||||
}
|
||||
};
|
||||
|
||||
Ok((file_type, rights_base, rights_inheriting))
|
||||
}
|
||||
149
crates/wasi-common/src/old/snapshot_0/sys/unix/filetime.rs
Normal file
149
crates/wasi-common/src/old/snapshot_0/sys/unix/filetime.rs
Normal file
@@ -0,0 +1,149 @@
|
||||
//! This internal module consists of helper types and functions for dealing
|
||||
//! with setting the file times (mainly in `path_filestat_set_times` syscall for now).
|
||||
//!
|
||||
//! The vast majority of the code contained within and in platform-specific implementations
|
||||
//! (`super::linux::filetime` and `super::bsd::filetime`) is based on the [filetime] crate.
|
||||
//! Kudos @alexcrichton!
|
||||
//!
|
||||
//! [filetime]: https://github.com/alexcrichton/filetime
|
||||
use std::fs::{self, File};
|
||||
use std::io;
|
||||
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(target_os = "linux")] {
|
||||
pub(crate) use super::linux::filetime::*;
|
||||
} else if #[cfg(any(
|
||||
target_os = "macos",
|
||||
target_os = "netbsd",
|
||||
target_os = "freebsd",
|
||||
target_os = "openbsd",
|
||||
target_os = "ios",
|
||||
target_os = "dragonfly"
|
||||
))] {
|
||||
pub(crate) use super::bsd::filetime::*;
|
||||
}
|
||||
}
|
||||
|
||||
/// A wrapper `enum` around `filetime::FileTime` struct, but unlike the original, this
|
||||
/// type allows the possibility of specifying `FileTime::Now` as a valid enumeration which,
|
||||
/// in turn, if `utimensat` is available on the host, will use a special const setting
|
||||
/// `UTIME_NOW`.
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub(crate) enum FileTime {
|
||||
Now,
|
||||
Omit,
|
||||
FileTime(filetime::FileTime),
|
||||
}
|
||||
|
||||
/// For a provided pair of access and modified `FileTime`s, converts the input to
|
||||
/// `filetime::FileTime` used later in `utimensat` function. For variants `FileTime::Now`
|
||||
/// and `FileTime::Omit`, this function will make two syscalls: either accessing current
|
||||
/// system time, or accessing the file's metadata.
|
||||
///
|
||||
/// The original implementation can be found here: [filetime::unix::get_times].
|
||||
///
|
||||
/// [filetime::unix::get_times]: https://github.com/alexcrichton/filetime/blob/master/src/unix/utimes.rs#L42
|
||||
fn get_times(
|
||||
atime: FileTime,
|
||||
mtime: FileTime,
|
||||
current: impl Fn() -> io::Result<fs::Metadata>,
|
||||
) -> io::Result<(filetime::FileTime, filetime::FileTime)> {
|
||||
use std::time::SystemTime;
|
||||
|
||||
let atime = match atime {
|
||||
FileTime::Now => {
|
||||
let time = SystemTime::now();
|
||||
filetime::FileTime::from_system_time(time)
|
||||
}
|
||||
FileTime::Omit => {
|
||||
let meta = current()?;
|
||||
filetime::FileTime::from_last_access_time(&meta)
|
||||
}
|
||||
FileTime::FileTime(ft) => ft,
|
||||
};
|
||||
|
||||
let mtime = match mtime {
|
||||
FileTime::Now => {
|
||||
let time = SystemTime::now();
|
||||
filetime::FileTime::from_system_time(time)
|
||||
}
|
||||
FileTime::Omit => {
|
||||
let meta = current()?;
|
||||
filetime::FileTime::from_last_modification_time(&meta)
|
||||
}
|
||||
FileTime::FileTime(ft) => ft,
|
||||
};
|
||||
|
||||
Ok((atime, mtime))
|
||||
}
|
||||
|
||||
/// Combines `openat` with `utimes` to emulate `utimensat` on platforms where it is
|
||||
/// not available. The logic for setting file times is based on [filetime::unix::set_file_handles_times].
|
||||
///
|
||||
/// [filetime::unix::set_file_handles_times]: https://github.com/alexcrichton/filetime/blob/master/src/unix/utimes.rs#L24
|
||||
pub(crate) fn utimesat(
|
||||
dirfd: &File,
|
||||
path: &str,
|
||||
atime: FileTime,
|
||||
mtime: FileTime,
|
||||
symlink_nofollow: bool,
|
||||
) -> io::Result<()> {
|
||||
use std::ffi::CString;
|
||||
use std::os::unix::prelude::*;
|
||||
// emulate *at syscall by reading the path from a combination of
|
||||
// (fd, path)
|
||||
let p = CString::new(path.as_bytes())?;
|
||||
let mut flags = libc::O_RDWR;
|
||||
if symlink_nofollow {
|
||||
flags |= libc::O_NOFOLLOW;
|
||||
}
|
||||
let fd = unsafe { libc::openat(dirfd.as_raw_fd(), p.as_ptr(), flags) };
|
||||
let f = unsafe { File::from_raw_fd(fd) };
|
||||
let (atime, mtime) = get_times(atime, mtime, || f.metadata())?;
|
||||
let times = [to_timeval(atime), to_timeval(mtime)];
|
||||
let rc = unsafe { libc::futimes(f.as_raw_fd(), times.as_ptr()) };
|
||||
return if rc == 0 {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(io::Error::last_os_error())
|
||||
};
|
||||
}
|
||||
|
||||
/// Converts `filetime::FileTime` to `libc::timeval`. This function was taken directly from
|
||||
/// [filetime] crate.
|
||||
///
|
||||
/// [filetime]: https://github.com/alexcrichton/filetime/blob/master/src/unix/utimes.rs#L93
|
||||
fn to_timeval(ft: filetime::FileTime) -> libc::timeval {
|
||||
libc::timeval {
|
||||
tv_sec: ft.seconds(),
|
||||
tv_usec: (ft.nanoseconds() / 1000) as libc::suseconds_t,
|
||||
}
|
||||
}
|
||||
|
||||
/// Converts `FileTime` to `libc::timespec`. If `FileTime::Now` variant is specified, this
|
||||
/// resolves to `UTIME_NOW` special const, `FileTime::Omit` variant resolves to `UTIME_OMIT`, and
|
||||
/// `FileTime::FileTime(ft)` where `ft := filetime::FileTime` uses [filetime] crate's original
|
||||
/// implementation which can be found here: [filetime::unix::to_timespec].
|
||||
///
|
||||
/// [filetime]: https://github.com/alexcrichton/filetime
|
||||
/// [filetime::unix::to_timespec]: https://github.com/alexcrichton/filetime/blob/master/src/unix/mod.rs#L30
|
||||
pub(crate) fn to_timespec(ft: &FileTime) -> libc::timespec {
|
||||
match ft {
|
||||
FileTime::Now => libc::timespec {
|
||||
tv_sec: 0,
|
||||
tv_nsec: UTIME_NOW,
|
||||
},
|
||||
FileTime::Omit => libc::timespec {
|
||||
tv_sec: 0,
|
||||
tv_nsec: UTIME_OMIT,
|
||||
},
|
||||
// `filetime::FileTime`'s fields are normalised by definition. `ft.seconds()` return the number
|
||||
// of whole seconds, while `ft.nanoseconds()` returns only fractional part expressed in
|
||||
// nanoseconds, as underneath it uses `std::time::Duration::subsec_nanos` to populate the
|
||||
// `filetime::FileTime::nanoseconds` field. It is, therefore, OK to do an `as` cast here.
|
||||
FileTime::FileTime(ft) => libc::timespec {
|
||||
tv_sec: ft.seconds(),
|
||||
tv_nsec: ft.nanoseconds() as _,
|
||||
},
|
||||
}
|
||||
}
|
||||
246
crates/wasi-common/src/old/snapshot_0/sys/unix/host_impl.rs
Normal file
246
crates/wasi-common/src/old/snapshot_0/sys/unix/host_impl.rs
Normal file
@@ -0,0 +1,246 @@
|
||||
//! WASI host types specific to *nix host.
|
||||
#![allow(non_camel_case_types)]
|
||||
#![allow(non_snake_case)]
|
||||
#![allow(dead_code)]
|
||||
use crate::old::snapshot_0::hostcalls_impl::FileType;
|
||||
use crate::old::snapshot_0::{helpers, wasi, Error, Result};
|
||||
use log::warn;
|
||||
use std::ffi::OsStr;
|
||||
use std::os::unix::prelude::OsStrExt;
|
||||
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(target_os = "linux")] {
|
||||
pub(crate) use super::linux::host_impl::*;
|
||||
} else if #[cfg(any(
|
||||
target_os = "macos",
|
||||
target_os = "netbsd",
|
||||
target_os = "freebsd",
|
||||
target_os = "openbsd",
|
||||
target_os = "ios",
|
||||
target_os = "dragonfly"
|
||||
))] {
|
||||
pub(crate) use super::bsd::host_impl::*;
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn errno_from_nix(errno: nix::errno::Errno) -> Error {
|
||||
match errno {
|
||||
nix::errno::Errno::EPERM => Error::EPERM,
|
||||
nix::errno::Errno::ENOENT => Error::ENOENT,
|
||||
nix::errno::Errno::ESRCH => Error::ESRCH,
|
||||
nix::errno::Errno::EINTR => Error::EINTR,
|
||||
nix::errno::Errno::EIO => Error::EIO,
|
||||
nix::errno::Errno::ENXIO => Error::ENXIO,
|
||||
nix::errno::Errno::E2BIG => Error::E2BIG,
|
||||
nix::errno::Errno::ENOEXEC => Error::ENOEXEC,
|
||||
nix::errno::Errno::EBADF => Error::EBADF,
|
||||
nix::errno::Errno::ECHILD => Error::ECHILD,
|
||||
nix::errno::Errno::EAGAIN => Error::EAGAIN,
|
||||
nix::errno::Errno::ENOMEM => Error::ENOMEM,
|
||||
nix::errno::Errno::EACCES => Error::EACCES,
|
||||
nix::errno::Errno::EFAULT => Error::EFAULT,
|
||||
nix::errno::Errno::EBUSY => Error::EBUSY,
|
||||
nix::errno::Errno::EEXIST => Error::EEXIST,
|
||||
nix::errno::Errno::EXDEV => Error::EXDEV,
|
||||
nix::errno::Errno::ENODEV => Error::ENODEV,
|
||||
nix::errno::Errno::ENOTDIR => Error::ENOTDIR,
|
||||
nix::errno::Errno::EISDIR => Error::EISDIR,
|
||||
nix::errno::Errno::EINVAL => Error::EINVAL,
|
||||
nix::errno::Errno::ENFILE => Error::ENFILE,
|
||||
nix::errno::Errno::EMFILE => Error::EMFILE,
|
||||
nix::errno::Errno::ENOTTY => Error::ENOTTY,
|
||||
nix::errno::Errno::ETXTBSY => Error::ETXTBSY,
|
||||
nix::errno::Errno::EFBIG => Error::EFBIG,
|
||||
nix::errno::Errno::ENOSPC => Error::ENOSPC,
|
||||
nix::errno::Errno::ESPIPE => Error::ESPIPE,
|
||||
nix::errno::Errno::EROFS => Error::EROFS,
|
||||
nix::errno::Errno::EMLINK => Error::EMLINK,
|
||||
nix::errno::Errno::EPIPE => Error::EPIPE,
|
||||
nix::errno::Errno::EDOM => Error::EDOM,
|
||||
nix::errno::Errno::ERANGE => Error::ERANGE,
|
||||
nix::errno::Errno::EDEADLK => Error::EDEADLK,
|
||||
nix::errno::Errno::ENAMETOOLONG => Error::ENAMETOOLONG,
|
||||
nix::errno::Errno::ENOLCK => Error::ENOLCK,
|
||||
nix::errno::Errno::ENOSYS => Error::ENOSYS,
|
||||
nix::errno::Errno::ENOTEMPTY => Error::ENOTEMPTY,
|
||||
nix::errno::Errno::ELOOP => Error::ELOOP,
|
||||
nix::errno::Errno::ENOMSG => Error::ENOMSG,
|
||||
nix::errno::Errno::EIDRM => Error::EIDRM,
|
||||
nix::errno::Errno::ENOLINK => Error::ENOLINK,
|
||||
nix::errno::Errno::EPROTO => Error::EPROTO,
|
||||
nix::errno::Errno::EMULTIHOP => Error::EMULTIHOP,
|
||||
nix::errno::Errno::EBADMSG => Error::EBADMSG,
|
||||
nix::errno::Errno::EOVERFLOW => Error::EOVERFLOW,
|
||||
nix::errno::Errno::EILSEQ => Error::EILSEQ,
|
||||
nix::errno::Errno::ENOTSOCK => Error::ENOTSOCK,
|
||||
nix::errno::Errno::EDESTADDRREQ => Error::EDESTADDRREQ,
|
||||
nix::errno::Errno::EMSGSIZE => Error::EMSGSIZE,
|
||||
nix::errno::Errno::EPROTOTYPE => Error::EPROTOTYPE,
|
||||
nix::errno::Errno::ENOPROTOOPT => Error::ENOPROTOOPT,
|
||||
nix::errno::Errno::EPROTONOSUPPORT => Error::EPROTONOSUPPORT,
|
||||
nix::errno::Errno::EAFNOSUPPORT => Error::EAFNOSUPPORT,
|
||||
nix::errno::Errno::EADDRINUSE => Error::EADDRINUSE,
|
||||
nix::errno::Errno::EADDRNOTAVAIL => Error::EADDRNOTAVAIL,
|
||||
nix::errno::Errno::ENETDOWN => Error::ENETDOWN,
|
||||
nix::errno::Errno::ENETUNREACH => Error::ENETUNREACH,
|
||||
nix::errno::Errno::ENETRESET => Error::ENETRESET,
|
||||
nix::errno::Errno::ECONNABORTED => Error::ECONNABORTED,
|
||||
nix::errno::Errno::ECONNRESET => Error::ECONNRESET,
|
||||
nix::errno::Errno::ENOBUFS => Error::ENOBUFS,
|
||||
nix::errno::Errno::EISCONN => Error::EISCONN,
|
||||
nix::errno::Errno::ENOTCONN => Error::ENOTCONN,
|
||||
nix::errno::Errno::ETIMEDOUT => Error::ETIMEDOUT,
|
||||
nix::errno::Errno::ECONNREFUSED => Error::ECONNREFUSED,
|
||||
nix::errno::Errno::EHOSTUNREACH => Error::EHOSTUNREACH,
|
||||
nix::errno::Errno::EALREADY => Error::EALREADY,
|
||||
nix::errno::Errno::EINPROGRESS => Error::EINPROGRESS,
|
||||
nix::errno::Errno::ESTALE => Error::ESTALE,
|
||||
nix::errno::Errno::EDQUOT => Error::EDQUOT,
|
||||
nix::errno::Errno::ECANCELED => Error::ECANCELED,
|
||||
nix::errno::Errno::EOWNERDEAD => Error::EOWNERDEAD,
|
||||
nix::errno::Errno::ENOTRECOVERABLE => Error::ENOTRECOVERABLE,
|
||||
other => {
|
||||
warn!("Unknown error from nix: {}", other);
|
||||
Error::ENOSYS
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn nix_from_fdflags(fdflags: wasi::__wasi_fdflags_t) -> nix::fcntl::OFlag {
|
||||
use nix::fcntl::OFlag;
|
||||
let mut nix_flags = OFlag::empty();
|
||||
if fdflags & wasi::__WASI_FDFLAGS_APPEND != 0 {
|
||||
nix_flags.insert(OFlag::O_APPEND);
|
||||
}
|
||||
if fdflags & wasi::__WASI_FDFLAGS_DSYNC != 0 {
|
||||
nix_flags.insert(OFlag::O_DSYNC);
|
||||
}
|
||||
if fdflags & wasi::__WASI_FDFLAGS_NONBLOCK != 0 {
|
||||
nix_flags.insert(OFlag::O_NONBLOCK);
|
||||
}
|
||||
if fdflags & wasi::__WASI_FDFLAGS_RSYNC != 0 {
|
||||
nix_flags.insert(O_RSYNC);
|
||||
}
|
||||
if fdflags & wasi::__WASI_FDFLAGS_SYNC != 0 {
|
||||
nix_flags.insert(OFlag::O_SYNC);
|
||||
}
|
||||
nix_flags
|
||||
}
|
||||
|
||||
pub(crate) fn fdflags_from_nix(oflags: nix::fcntl::OFlag) -> wasi::__wasi_fdflags_t {
|
||||
use nix::fcntl::OFlag;
|
||||
let mut fdflags = 0;
|
||||
if oflags.contains(OFlag::O_APPEND) {
|
||||
fdflags |= wasi::__WASI_FDFLAGS_APPEND;
|
||||
}
|
||||
if oflags.contains(OFlag::O_DSYNC) {
|
||||
fdflags |= wasi::__WASI_FDFLAGS_DSYNC;
|
||||
}
|
||||
if oflags.contains(OFlag::O_NONBLOCK) {
|
||||
fdflags |= wasi::__WASI_FDFLAGS_NONBLOCK;
|
||||
}
|
||||
if oflags.contains(O_RSYNC) {
|
||||
fdflags |= wasi::__WASI_FDFLAGS_RSYNC;
|
||||
}
|
||||
if oflags.contains(OFlag::O_SYNC) {
|
||||
fdflags |= wasi::__WASI_FDFLAGS_SYNC;
|
||||
}
|
||||
fdflags
|
||||
}
|
||||
|
||||
pub(crate) fn nix_from_oflags(oflags: wasi::__wasi_oflags_t) -> nix::fcntl::OFlag {
|
||||
use nix::fcntl::OFlag;
|
||||
let mut nix_flags = OFlag::empty();
|
||||
if oflags & wasi::__WASI_OFLAGS_CREAT != 0 {
|
||||
nix_flags.insert(OFlag::O_CREAT);
|
||||
}
|
||||
if oflags & wasi::__WASI_OFLAGS_DIRECTORY != 0 {
|
||||
nix_flags.insert(OFlag::O_DIRECTORY);
|
||||
}
|
||||
if oflags & wasi::__WASI_OFLAGS_EXCL != 0 {
|
||||
nix_flags.insert(OFlag::O_EXCL);
|
||||
}
|
||||
if oflags & wasi::__WASI_OFLAGS_TRUNC != 0 {
|
||||
nix_flags.insert(OFlag::O_TRUNC);
|
||||
}
|
||||
nix_flags
|
||||
}
|
||||
|
||||
pub(crate) fn filetype_from_nix(sflags: nix::sys::stat::SFlag) -> FileType {
|
||||
use nix::sys::stat::SFlag;
|
||||
if sflags.contains(SFlag::S_IFCHR) {
|
||||
FileType::CharacterDevice
|
||||
} else if sflags.contains(SFlag::S_IFBLK) {
|
||||
FileType::BlockDevice
|
||||
} else if sflags.contains(SFlag::S_IFSOCK) {
|
||||
FileType::SocketStream
|
||||
} else if sflags.contains(SFlag::S_IFDIR) {
|
||||
FileType::Directory
|
||||
} else if sflags.contains(SFlag::S_IFREG) {
|
||||
FileType::RegularFile
|
||||
} else if sflags.contains(SFlag::S_IFLNK) {
|
||||
FileType::Symlink
|
||||
} else {
|
||||
FileType::Unknown
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn filestat_from_nix(
|
||||
filestat: nix::sys::stat::FileStat,
|
||||
) -> Result<wasi::__wasi_filestat_t> {
|
||||
use std::convert::TryFrom;
|
||||
fn filestat_to_timestamp(secs: u64, nsecs: u64) -> Result<wasi::__wasi_timestamp_t> {
|
||||
secs.checked_mul(1_000_000_000)
|
||||
.and_then(|sec_nsec| sec_nsec.checked_add(nsecs))
|
||||
.ok_or(Error::EOVERFLOW)
|
||||
}
|
||||
|
||||
let filetype = nix::sys::stat::SFlag::from_bits_truncate(filestat.st_mode);
|
||||
let dev = wasi::__wasi_device_t::try_from(filestat.st_dev)?;
|
||||
let ino = wasi::__wasi_inode_t::try_from(filestat.st_ino)?;
|
||||
let atim = filestat_to_timestamp(filestat.st_atime as u64, filestat.st_atime_nsec as u64)?;
|
||||
let ctim = filestat_to_timestamp(filestat.st_ctime as u64, filestat.st_ctime_nsec as u64)?;
|
||||
let mtim = filestat_to_timestamp(filestat.st_mtime as u64, filestat.st_mtime_nsec as u64)?;
|
||||
|
||||
Ok(wasi::__wasi_filestat_t {
|
||||
dev,
|
||||
ino,
|
||||
nlink: filestat.st_nlink as wasi::__wasi_linkcount_t,
|
||||
size: filestat.st_size as wasi::__wasi_filesize_t,
|
||||
atim,
|
||||
ctim,
|
||||
mtim,
|
||||
filetype: filetype_from_nix(filetype).to_wasi(),
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn dirent_filetype_from_host(
|
||||
host_entry: &nix::libc::dirent,
|
||||
) -> Result<wasi::__wasi_filetype_t> {
|
||||
match host_entry.d_type {
|
||||
libc::DT_FIFO => Ok(wasi::__WASI_FILETYPE_UNKNOWN),
|
||||
libc::DT_CHR => Ok(wasi::__WASI_FILETYPE_CHARACTER_DEVICE),
|
||||
libc::DT_DIR => Ok(wasi::__WASI_FILETYPE_DIRECTORY),
|
||||
libc::DT_BLK => Ok(wasi::__WASI_FILETYPE_BLOCK_DEVICE),
|
||||
libc::DT_REG => Ok(wasi::__WASI_FILETYPE_REGULAR_FILE),
|
||||
libc::DT_LNK => Ok(wasi::__WASI_FILETYPE_SYMBOLIC_LINK),
|
||||
libc::DT_SOCK => {
|
||||
// TODO how to discriminate between STREAM and DGRAM?
|
||||
// Perhaps, we should create a more general WASI filetype
|
||||
// such as __WASI_FILETYPE_SOCKET, and then it would be
|
||||
// up to the client to check whether it's actually
|
||||
// STREAM or DGRAM?
|
||||
Ok(wasi::__WASI_FILETYPE_UNKNOWN)
|
||||
}
|
||||
libc::DT_UNKNOWN => Ok(wasi::__WASI_FILETYPE_UNKNOWN),
|
||||
_ => Err(Error::EINVAL),
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates owned WASI path from OS string.
|
||||
///
|
||||
/// 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> {
|
||||
helpers::path_from_slice(s.as_ref().as_bytes()).map(String::from)
|
||||
}
|
||||
@@ -0,0 +1,340 @@
|
||||
#![allow(non_camel_case_types)]
|
||||
#![allow(unused_unsafe)]
|
||||
use crate::old::snapshot_0::helpers::systemtime_to_timestamp;
|
||||
use crate::old::snapshot_0::hostcalls_impl::{FileType, PathGet};
|
||||
use crate::old::snapshot_0::sys::host_impl;
|
||||
use crate::old::snapshot_0::sys::unix::str_to_cstring;
|
||||
use crate::old::snapshot_0::{wasi, Error, Result};
|
||||
use nix::libc;
|
||||
use std::convert::TryInto;
|
||||
use std::fs::{File, Metadata};
|
||||
use std::os::unix::fs::FileExt;
|
||||
use std::os::unix::prelude::{AsRawFd, FromRawFd};
|
||||
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(target_os = "linux")] {
|
||||
pub(crate) use super::super::linux::hostcalls_impl::*;
|
||||
} else if #[cfg(any(
|
||||
target_os = "macos",
|
||||
target_os = "netbsd",
|
||||
target_os = "freebsd",
|
||||
target_os = "openbsd",
|
||||
target_os = "ios",
|
||||
target_os = "dragonfly"
|
||||
))] {
|
||||
pub(crate) use super::super::bsd::hostcalls_impl::*;
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn fd_pread(
|
||||
file: &File,
|
||||
buf: &mut [u8],
|
||||
offset: wasi::__wasi_filesize_t,
|
||||
) -> Result<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> {
|
||||
file.write_at(buf, offset).map_err(Into::into)
|
||||
}
|
||||
|
||||
pub(crate) fn fd_fdstat_get(fd: &File) -> Result<wasi::__wasi_fdflags_t> {
|
||||
use nix::fcntl::{fcntl, OFlag, F_GETFL};
|
||||
match fcntl(fd.as_raw_fd(), F_GETFL).map(OFlag::from_bits_truncate) {
|
||||
Ok(flags) => Ok(host_impl::fdflags_from_nix(flags)),
|
||||
Err(e) => Err(host_impl::errno_from_nix(e.as_errno().unwrap())),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn fd_fdstat_set_flags(fd: &File, fdflags: wasi::__wasi_fdflags_t) -> Result<()> {
|
||||
use nix::fcntl::{fcntl, F_SETFL};
|
||||
let nix_flags = host_impl::nix_from_fdflags(fdflags);
|
||||
match fcntl(fd.as_raw_fd(), F_SETFL(nix_flags)) {
|
||||
Ok(_) => Ok(()),
|
||||
Err(e) => Err(host_impl::errno_from_nix(e.as_errno().unwrap())),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn path_create_directory(resolved: PathGet) -> Result<()> {
|
||||
use nix::libc::mkdirat;
|
||||
let path_cstr = str_to_cstring(resolved.path())?;
|
||||
// nix doesn't expose mkdirat() yet
|
||||
match unsafe { mkdirat(resolved.dirfd().as_raw_fd(), path_cstr.as_ptr(), 0o777) } {
|
||||
0 => Ok(()),
|
||||
_ => Err(host_impl::errno_from_nix(nix::errno::Errno::last())),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn path_link(resolved_old: PathGet, resolved_new: PathGet) -> Result<()> {
|
||||
use nix::libc::linkat;
|
||||
let old_path_cstr = str_to_cstring(resolved_old.path())?;
|
||||
let new_path_cstr = str_to_cstring(resolved_new.path())?;
|
||||
|
||||
// Not setting AT_SYMLINK_FOLLOW fails on most filesystems
|
||||
let atflags = libc::AT_SYMLINK_FOLLOW;
|
||||
let res = unsafe {
|
||||
linkat(
|
||||
resolved_old.dirfd().as_raw_fd(),
|
||||
old_path_cstr.as_ptr(),
|
||||
resolved_new.dirfd().as_raw_fd(),
|
||||
new_path_cstr.as_ptr(),
|
||||
atflags,
|
||||
)
|
||||
};
|
||||
if res != 0 {
|
||||
Err(host_impl::errno_from_nix(nix::errno::Errno::last()))
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn path_open(
|
||||
resolved: PathGet,
|
||||
read: bool,
|
||||
write: bool,
|
||||
oflags: wasi::__wasi_oflags_t,
|
||||
fs_flags: wasi::__wasi_fdflags_t,
|
||||
) -> Result<File> {
|
||||
use nix::errno::Errno;
|
||||
use nix::fcntl::{openat, AtFlags, OFlag};
|
||||
use nix::sys::stat::{fstatat, Mode, SFlag};
|
||||
|
||||
let mut nix_all_oflags = if read && write {
|
||||
OFlag::O_RDWR
|
||||
} else if write {
|
||||
OFlag::O_WRONLY
|
||||
} else {
|
||||
OFlag::O_RDONLY
|
||||
};
|
||||
|
||||
// on non-Capsicum systems, we always want nofollow
|
||||
nix_all_oflags.insert(OFlag::O_NOFOLLOW);
|
||||
|
||||
// convert open flags
|
||||
nix_all_oflags.insert(host_impl::nix_from_oflags(oflags));
|
||||
|
||||
// convert file descriptor flags
|
||||
nix_all_oflags.insert(host_impl::nix_from_fdflags(fs_flags));
|
||||
|
||||
// Call openat. Use mode 0o666 so that we follow whatever the user's
|
||||
// umask is, but don't set the executable flag, because it isn't yet
|
||||
// meaningful for WASI programs to create executable files.
|
||||
|
||||
log::debug!("path_open resolved = {:?}", resolved);
|
||||
log::debug!("path_open oflags = {:?}", nix_all_oflags);
|
||||
|
||||
let new_fd = match openat(
|
||||
resolved.dirfd().as_raw_fd(),
|
||||
resolved.path(),
|
||||
nix_all_oflags,
|
||||
Mode::from_bits_truncate(0o666),
|
||||
) {
|
||||
Ok(fd) => fd,
|
||||
Err(e) => {
|
||||
match e.as_errno() {
|
||||
// Linux returns ENXIO instead of EOPNOTSUPP when opening a socket
|
||||
Some(Errno::ENXIO) => {
|
||||
if let Ok(stat) = fstatat(
|
||||
resolved.dirfd().as_raw_fd(),
|
||||
resolved.path(),
|
||||
AtFlags::AT_SYMLINK_NOFOLLOW,
|
||||
) {
|
||||
if SFlag::from_bits_truncate(stat.st_mode).contains(SFlag::S_IFSOCK) {
|
||||
return Err(Error::ENOTSUP);
|
||||
} else {
|
||||
return Err(Error::ENXIO);
|
||||
}
|
||||
} else {
|
||||
return Err(Error::ENXIO);
|
||||
}
|
||||
}
|
||||
// Linux returns ENOTDIR instead of ELOOP when using O_NOFOLLOW|O_DIRECTORY
|
||||
// on a symlink.
|
||||
Some(Errno::ENOTDIR)
|
||||
if !(nix_all_oflags & (OFlag::O_NOFOLLOW | OFlag::O_DIRECTORY)).is_empty() =>
|
||||
{
|
||||
if let Ok(stat) = fstatat(
|
||||
resolved.dirfd().as_raw_fd(),
|
||||
resolved.path(),
|
||||
AtFlags::AT_SYMLINK_NOFOLLOW,
|
||||
) {
|
||||
if SFlag::from_bits_truncate(stat.st_mode).contains(SFlag::S_IFLNK) {
|
||||
return Err(Error::ELOOP);
|
||||
}
|
||||
}
|
||||
return Err(Error::ENOTDIR);
|
||||
}
|
||||
// FreeBSD returns EMLINK instead of ELOOP when using O_NOFOLLOW on
|
||||
// a symlink.
|
||||
Some(Errno::EMLINK) if !(nix_all_oflags & OFlag::O_NOFOLLOW).is_empty() => {
|
||||
return Err(Error::ELOOP);
|
||||
}
|
||||
Some(e) => return Err(host_impl::errno_from_nix(e)),
|
||||
None => return Err(Error::ENOSYS),
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
log::debug!("path_open (host) new_fd = {:?}", new_fd);
|
||||
|
||||
// Determine the type of the new file descriptor and which rights contradict with this type
|
||||
Ok(unsafe { File::from_raw_fd(new_fd) })
|
||||
}
|
||||
|
||||
pub(crate) fn path_readlink(resolved: PathGet, buf: &mut [u8]) -> Result<usize> {
|
||||
use nix::errno::Errno;
|
||||
let path_cstr = str_to_cstring(resolved.path())?;
|
||||
|
||||
// Linux requires that the buffer size is positive, whereas POSIX does not.
|
||||
// Use a fake buffer to store the results if the size is zero.
|
||||
// TODO: instead of using raw libc::readlinkat call here, this should really
|
||||
// be fixed in `nix` crate
|
||||
let fakebuf: &mut [u8] = &mut [0];
|
||||
let buf_len = buf.len();
|
||||
let len = unsafe {
|
||||
libc::readlinkat(
|
||||
resolved.dirfd().as_raw_fd(),
|
||||
path_cstr.as_ptr() as *const libc::c_char,
|
||||
if buf_len == 0 {
|
||||
fakebuf.as_mut_ptr()
|
||||
} else {
|
||||
buf.as_mut_ptr()
|
||||
} as *mut libc::c_char,
|
||||
if buf_len == 0 { fakebuf.len() } else { buf_len },
|
||||
)
|
||||
};
|
||||
|
||||
if len < 0 {
|
||||
Err(host_impl::errno_from_nix(Errno::last()))
|
||||
} else {
|
||||
let len = len as usize;
|
||||
Ok(if len < buf_len { len } else { buf_len })
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn fd_filestat_get_impl(file: &std::fs::File) -> Result<wasi::__wasi_filestat_t> {
|
||||
use std::os::unix::fs::MetadataExt;
|
||||
|
||||
let metadata = file.metadata()?;
|
||||
Ok(wasi::__wasi_filestat_t {
|
||||
dev: metadata.dev(),
|
||||
ino: metadata.ino(),
|
||||
nlink: metadata.nlink().try_into()?, // u64 doesn't fit into u32
|
||||
size: metadata.len(),
|
||||
atim: systemtime_to_timestamp(metadata.accessed()?)?,
|
||||
ctim: metadata.ctime().try_into()?, // i64 doesn't fit into u64
|
||||
mtim: systemtime_to_timestamp(metadata.modified()?)?,
|
||||
filetype: filetype(file, &metadata)?.to_wasi(),
|
||||
})
|
||||
}
|
||||
|
||||
fn filetype(file: &File, metadata: &Metadata) -> Result<FileType> {
|
||||
use nix::sys::socket::{self, SockType};
|
||||
use std::os::unix::fs::FileTypeExt;
|
||||
let ftype = metadata.file_type();
|
||||
if ftype.is_file() {
|
||||
Ok(FileType::RegularFile)
|
||||
} else if ftype.is_dir() {
|
||||
Ok(FileType::Directory)
|
||||
} else if ftype.is_symlink() {
|
||||
Ok(FileType::Symlink)
|
||||
} else if ftype.is_char_device() {
|
||||
Ok(FileType::CharacterDevice)
|
||||
} else if ftype.is_block_device() {
|
||||
Ok(FileType::BlockDevice)
|
||||
} else if ftype.is_socket() {
|
||||
match socket::getsockopt(file.as_raw_fd(), socket::sockopt::SockType)
|
||||
.map_err(|err| err.as_errno().unwrap())
|
||||
.map_err(host_impl::errno_from_nix)?
|
||||
{
|
||||
SockType::Datagram => Ok(FileType::SocketDgram),
|
||||
SockType::Stream => Ok(FileType::SocketStream),
|
||||
_ => Ok(FileType::Unknown),
|
||||
}
|
||||
} else {
|
||||
Ok(FileType::Unknown)
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn path_filestat_get(
|
||||
resolved: PathGet,
|
||||
dirflags: wasi::__wasi_lookupflags_t,
|
||||
) -> Result<wasi::__wasi_filestat_t> {
|
||||
use nix::fcntl::AtFlags;
|
||||
use nix::sys::stat::fstatat;
|
||||
|
||||
let atflags = match dirflags {
|
||||
0 => AtFlags::empty(),
|
||||
_ => AtFlags::AT_SYMLINK_NOFOLLOW,
|
||||
};
|
||||
|
||||
let filestat = fstatat(resolved.dirfd().as_raw_fd(), resolved.path(), atflags)
|
||||
.map_err(|err| host_impl::errno_from_nix(err.as_errno().unwrap()))?;
|
||||
host_impl::filestat_from_nix(filestat)
|
||||
}
|
||||
|
||||
pub(crate) fn path_filestat_set_times(
|
||||
resolved: PathGet,
|
||||
dirflags: wasi::__wasi_lookupflags_t,
|
||||
st_atim: wasi::__wasi_timestamp_t,
|
||||
st_mtim: wasi::__wasi_timestamp_t,
|
||||
fst_flags: wasi::__wasi_fstflags_t,
|
||||
) -> Result<()> {
|
||||
use super::super::filetime::*;
|
||||
use std::time::{Duration, UNIX_EPOCH};
|
||||
|
||||
let set_atim = fst_flags & wasi::__WASI_FSTFLAGS_ATIM != 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_now = fst_flags & wasi::__WASI_FSTFLAGS_MTIM_NOW != 0;
|
||||
|
||||
if (set_atim && set_atim_now) || (set_mtim && set_mtim_now) {
|
||||
return Err(Error::EINVAL);
|
||||
}
|
||||
|
||||
let symlink_nofollow = wasi::__WASI_LOOKUPFLAGS_SYMLINK_FOLLOW != dirflags;
|
||||
let atim = if set_atim {
|
||||
let time = UNIX_EPOCH + Duration::from_nanos(st_atim);
|
||||
FileTime::FileTime(filetime::FileTime::from_system_time(time))
|
||||
} else if set_atim_now {
|
||||
FileTime::Now
|
||||
} else {
|
||||
FileTime::Omit
|
||||
};
|
||||
let mtim = if set_mtim {
|
||||
let time = UNIX_EPOCH + Duration::from_nanos(st_mtim);
|
||||
FileTime::FileTime(filetime::FileTime::from_system_time(time))
|
||||
} else if set_mtim_now {
|
||||
FileTime::Now
|
||||
} else {
|
||||
FileTime::Omit
|
||||
};
|
||||
|
||||
utimensat(
|
||||
resolved.dirfd(),
|
||||
resolved.path(),
|
||||
atim,
|
||||
mtim,
|
||||
symlink_nofollow,
|
||||
)
|
||||
.map_err(Into::into)
|
||||
}
|
||||
|
||||
pub(crate) fn path_remove_directory(resolved: PathGet) -> Result<()> {
|
||||
use nix::errno;
|
||||
use nix::libc::{unlinkat, AT_REMOVEDIR};
|
||||
|
||||
let path_cstr = str_to_cstring(resolved.path())?;
|
||||
|
||||
// nix doesn't expose unlinkat() yet
|
||||
match unsafe {
|
||||
unlinkat(
|
||||
resolved.dirfd().as_raw_fd(),
|
||||
path_cstr.as_ptr(),
|
||||
AT_REMOVEDIR,
|
||||
)
|
||||
} {
|
||||
0 => Ok(()),
|
||||
_ => Err(host_impl::errno_from_nix(errno::Errno::last())),
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
#![allow(non_camel_case_types)]
|
||||
#![allow(unused_unsafe)]
|
||||
use crate::old::snapshot_0::sys::host_impl;
|
||||
use crate::old::snapshot_0::{wasi, Result};
|
||||
use std::fs::File;
|
||||
|
||||
pub(crate) fn path_open_rights(
|
||||
rights_base: wasi::__wasi_rights_t,
|
||||
rights_inheriting: wasi::__wasi_rights_t,
|
||||
oflags: wasi::__wasi_oflags_t,
|
||||
fs_flags: wasi::__wasi_fdflags_t,
|
||||
) -> (wasi::__wasi_rights_t, wasi::__wasi_rights_t) {
|
||||
use nix::fcntl::OFlag;
|
||||
|
||||
// which rights are needed on the dirfd?
|
||||
let mut needed_base = wasi::__WASI_RIGHTS_PATH_OPEN;
|
||||
let mut needed_inheriting = rights_base | rights_inheriting;
|
||||
|
||||
// convert open flags
|
||||
let oflags = host_impl::nix_from_oflags(oflags);
|
||||
if oflags.contains(OFlag::O_CREAT) {
|
||||
needed_base |= wasi::__WASI_RIGHTS_PATH_CREATE_FILE;
|
||||
}
|
||||
if oflags.contains(OFlag::O_TRUNC) {
|
||||
needed_base |= wasi::__WASI_RIGHTS_PATH_FILESTAT_SET_SIZE;
|
||||
}
|
||||
|
||||
// convert file descriptor flags
|
||||
let fdflags = host_impl::nix_from_fdflags(fs_flags);
|
||||
if fdflags.contains(OFlag::O_DSYNC) {
|
||||
needed_inheriting |= wasi::__WASI_RIGHTS_FD_DATASYNC;
|
||||
}
|
||||
if fdflags.intersects(host_impl::O_RSYNC | OFlag::O_SYNC) {
|
||||
needed_inheriting |= wasi::__WASI_RIGHTS_FD_SYNC;
|
||||
}
|
||||
|
||||
(needed_base, needed_inheriting)
|
||||
}
|
||||
|
||||
pub(crate) fn openat(dirfd: &File, path: &str) -> Result<File> {
|
||||
use nix::fcntl::{self, OFlag};
|
||||
use nix::sys::stat::Mode;
|
||||
use std::os::unix::prelude::{AsRawFd, FromRawFd};
|
||||
|
||||
log::debug!("path_get openat path = {:?}", path);
|
||||
|
||||
fcntl::openat(
|
||||
dirfd.as_raw_fd(),
|
||||
path,
|
||||
OFlag::O_RDONLY | OFlag::O_DIRECTORY | OFlag::O_NOFOLLOW,
|
||||
Mode::empty(),
|
||||
)
|
||||
.map(|new_fd| unsafe { File::from_raw_fd(new_fd) })
|
||||
.map_err(Into::into)
|
||||
}
|
||||
|
||||
pub(crate) fn readlinkat(dirfd: &File, path: &str) -> Result<String> {
|
||||
use nix::fcntl;
|
||||
use std::os::unix::prelude::AsRawFd;
|
||||
|
||||
log::debug!("path_get readlinkat path = {:?}", path);
|
||||
|
||||
let readlink_buf = &mut [0u8; libc::PATH_MAX as usize + 1];
|
||||
|
||||
fcntl::readlinkat(dirfd.as_raw_fd(), path, readlink_buf)
|
||||
.map_err(Into::into)
|
||||
.and_then(host_impl::path_from_host)
|
||||
}
|
||||
@@ -0,0 +1,221 @@
|
||||
#![allow(non_camel_case_types)]
|
||||
#![allow(unused_unsafe)]
|
||||
use crate::old::snapshot_0::hostcalls_impl::{ClockEventData, FdEventData};
|
||||
use crate::old::snapshot_0::sys::host_impl;
|
||||
use crate::old::snapshot_0::{wasi, Error, Result};
|
||||
use nix::libc::{self, c_int};
|
||||
use std::mem::MaybeUninit;
|
||||
|
||||
fn wasi_clock_id_to_unix(clock_id: wasi::__wasi_clockid_t) -> Result<libc::clockid_t> {
|
||||
// convert the supported clocks to the libc types, or return EINVAL
|
||||
match clock_id {
|
||||
wasi::__WASI_CLOCKID_REALTIME => Ok(libc::CLOCK_REALTIME),
|
||||
wasi::__WASI_CLOCKID_MONOTONIC => Ok(libc::CLOCK_MONOTONIC),
|
||||
wasi::__WASI_CLOCKID_PROCESS_CPUTIME_ID => Ok(libc::CLOCK_PROCESS_CPUTIME_ID),
|
||||
wasi::__WASI_CLOCKID_THREAD_CPUTIME_ID => Ok(libc::CLOCK_THREAD_CPUTIME_ID),
|
||||
_ => Err(Error::EINVAL),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn clock_res_get(clock_id: wasi::__wasi_clockid_t) -> Result<wasi::__wasi_timestamp_t> {
|
||||
let clock_id = wasi_clock_id_to_unix(clock_id)?;
|
||||
// no `nix` wrapper for clock_getres, so we do it ourselves
|
||||
let mut timespec = MaybeUninit::<libc::timespec>::uninit();
|
||||
let res = unsafe { libc::clock_getres(clock_id, timespec.as_mut_ptr()) };
|
||||
if res != 0 {
|
||||
return Err(host_impl::errno_from_nix(nix::errno::Errno::last()));
|
||||
}
|
||||
let timespec = unsafe { timespec.assume_init() };
|
||||
|
||||
// convert to nanoseconds, returning EOVERFLOW in case of overflow;
|
||||
// this is freelancing a bit from the spec but seems like it'll
|
||||
// be an unusual situation to hit
|
||||
(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| {
|
||||
// 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)
|
||||
} else {
|
||||
Ok(resolution)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn clock_time_get(clock_id: wasi::__wasi_clockid_t) -> Result<wasi::__wasi_timestamp_t> {
|
||||
let clock_id = wasi_clock_id_to_unix(clock_id)?;
|
||||
// no `nix` wrapper for clock_getres, so we do it ourselves
|
||||
let mut timespec = MaybeUninit::<libc::timespec>::uninit();
|
||||
let res = unsafe { libc::clock_gettime(clock_id, timespec.as_mut_ptr()) };
|
||||
if res != 0 {
|
||||
return Err(host_impl::errno_from_nix(nix::errno::Errno::last()));
|
||||
}
|
||||
let timespec = unsafe { timespec.assume_init() };
|
||||
|
||||
// convert to nanoseconds, returning EOVERFLOW in case of overflow; this is freelancing a bit
|
||||
// from the spec but seems like it'll be an unusual situation to hit
|
||||
(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)
|
||||
}
|
||||
|
||||
pub(crate) fn poll_oneoff(
|
||||
timeout: Option<ClockEventData>,
|
||||
fd_events: Vec<FdEventData>,
|
||||
events: &mut Vec<wasi::__wasi_event_t>,
|
||||
) -> Result<()> {
|
||||
use nix::{
|
||||
errno::Errno,
|
||||
poll::{poll, PollFd, PollFlags},
|
||||
};
|
||||
use std::{convert::TryInto, os::unix::prelude::AsRawFd};
|
||||
|
||||
if fd_events.is_empty() && timeout.is_none() {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let mut poll_fds: Vec<_> = fd_events
|
||||
.iter()
|
||||
.map(|event| {
|
||||
let mut flags = PollFlags::empty();
|
||||
match event.r#type {
|
||||
wasi::__WASI_EVENTTYPE_FD_READ => flags.insert(PollFlags::POLLIN),
|
||||
wasi::__WASI_EVENTTYPE_FD_WRITE => flags.insert(PollFlags::POLLOUT),
|
||||
// An event on a file descriptor can currently only be of type FD_READ or FD_WRITE
|
||||
// Nothing else has been defined in the specification, and these are also the only two
|
||||
// events we filtered before. If we get something else here, the code has a serious bug.
|
||||
_ => unreachable!(),
|
||||
};
|
||||
PollFd::new(event.descriptor.as_raw_fd(), flags)
|
||||
})
|
||||
.collect();
|
||||
|
||||
let poll_timeout = timeout.map_or(-1, |timeout| {
|
||||
let delay = timeout.delay / 1_000_000; // poll syscall requires delay to expressed in milliseconds
|
||||
delay.try_into().unwrap_or(c_int::max_value())
|
||||
});
|
||||
log::debug!("poll_oneoff poll_timeout = {:?}", poll_timeout);
|
||||
|
||||
let ready = loop {
|
||||
match poll(&mut poll_fds, poll_timeout) {
|
||||
Err(_) => {
|
||||
if Errno::last() == Errno::EINTR {
|
||||
continue;
|
||||
}
|
||||
return Err(host_impl::errno_from_nix(Errno::last()));
|
||||
}
|
||||
Ok(ready) => break ready as usize,
|
||||
}
|
||||
};
|
||||
|
||||
Ok(if ready == 0 {
|
||||
poll_oneoff_handle_timeout_event(timeout.expect("timeout should not be None"), events)
|
||||
} else {
|
||||
let ready_events = fd_events.into_iter().zip(poll_fds.into_iter()).take(ready);
|
||||
poll_oneoff_handle_fd_event(ready_events, events)?
|
||||
})
|
||||
}
|
||||
|
||||
// define the `fionread()` function, equivalent to `ioctl(fd, FIONREAD, *bytes)`
|
||||
nix::ioctl_read_bad!(fionread, nix::libc::FIONREAD, c_int);
|
||||
|
||||
fn poll_oneoff_handle_timeout_event(
|
||||
timeout: ClockEventData,
|
||||
events: &mut Vec<wasi::__wasi_event_t>,
|
||||
) {
|
||||
events.push(wasi::__wasi_event_t {
|
||||
userdata: timeout.userdata,
|
||||
r#type: wasi::__WASI_EVENTTYPE_CLOCK,
|
||||
error: wasi::__WASI_ERRNO_SUCCESS,
|
||||
u: wasi::__wasi_event_u_t {
|
||||
fd_readwrite: wasi::__wasi_event_fd_readwrite_t {
|
||||
nbytes: 0,
|
||||
flags: 0,
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
fn poll_oneoff_handle_fd_event<'a>(
|
||||
ready_events: impl Iterator<Item = (FdEventData<'a>, nix::poll::PollFd)>,
|
||||
events: &mut Vec<wasi::__wasi_event_t>,
|
||||
) -> Result<()> {
|
||||
use nix::poll::PollFlags;
|
||||
use std::{convert::TryInto, os::unix::prelude::AsRawFd};
|
||||
|
||||
for (fd_event, poll_fd) in ready_events {
|
||||
log::debug!("poll_oneoff_handle_fd_event fd_event = {:?}", fd_event);
|
||||
log::debug!("poll_oneoff_handle_fd_event poll_fd = {:?}", poll_fd);
|
||||
|
||||
let revents = match poll_fd.revents() {
|
||||
Some(revents) => revents,
|
||||
None => continue,
|
||||
};
|
||||
|
||||
log::debug!("poll_oneoff_handle_fd_event revents = {:?}", revents);
|
||||
|
||||
let mut nbytes = 0;
|
||||
if fd_event.r#type == wasi::__WASI_EVENTTYPE_FD_READ {
|
||||
let _ = unsafe { fionread(fd_event.descriptor.as_raw_fd(), &mut nbytes) };
|
||||
}
|
||||
|
||||
let output_event = if revents.contains(PollFlags::POLLNVAL) {
|
||||
wasi::__wasi_event_t {
|
||||
userdata: fd_event.userdata,
|
||||
r#type: fd_event.r#type,
|
||||
error: wasi::__WASI_ERRNO_BADF,
|
||||
u: wasi::__wasi_event_u_t {
|
||||
fd_readwrite: wasi::__wasi_event_fd_readwrite_t {
|
||||
nbytes: 0,
|
||||
flags: wasi::__WASI_EVENTRWFLAGS_FD_READWRITE_HANGUP,
|
||||
},
|
||||
},
|
||||
}
|
||||
} else if revents.contains(PollFlags::POLLERR) {
|
||||
wasi::__wasi_event_t {
|
||||
userdata: fd_event.userdata,
|
||||
r#type: fd_event.r#type,
|
||||
error: wasi::__WASI_ERRNO_IO,
|
||||
u: wasi::__wasi_event_u_t {
|
||||
fd_readwrite: wasi::__wasi_event_fd_readwrite_t {
|
||||
nbytes: 0,
|
||||
flags: wasi::__WASI_EVENTRWFLAGS_FD_READWRITE_HANGUP,
|
||||
},
|
||||
},
|
||||
}
|
||||
} else if revents.contains(PollFlags::POLLHUP) {
|
||||
wasi::__wasi_event_t {
|
||||
userdata: fd_event.userdata,
|
||||
r#type: fd_event.r#type,
|
||||
error: wasi::__WASI_ERRNO_SUCCESS,
|
||||
u: wasi::__wasi_event_u_t {
|
||||
fd_readwrite: wasi::__wasi_event_fd_readwrite_t {
|
||||
nbytes: 0,
|
||||
flags: wasi::__WASI_EVENTRWFLAGS_FD_READWRITE_HANGUP,
|
||||
},
|
||||
},
|
||||
}
|
||||
} else if revents.contains(PollFlags::POLLIN) | revents.contains(PollFlags::POLLOUT) {
|
||||
wasi::__wasi_event_t {
|
||||
userdata: fd_event.userdata,
|
||||
r#type: fd_event.r#type,
|
||||
error: wasi::__WASI_ERRNO_SUCCESS,
|
||||
u: wasi::__wasi_event_u_t {
|
||||
fd_readwrite: wasi::__wasi_event_fd_readwrite_t {
|
||||
nbytes: nbytes.try_into()?,
|
||||
flags: 0,
|
||||
},
|
||||
},
|
||||
}
|
||||
} else {
|
||||
continue;
|
||||
};
|
||||
|
||||
events.push(output_event);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
//! Unix-specific hostcalls that implement
|
||||
//! [WASI](https://github.com/bytecodealliance/wasmtime-wasi/blob/wasi/docs/WASI-overview.md).
|
||||
mod fs;
|
||||
pub(crate) mod fs_helpers;
|
||||
mod misc;
|
||||
|
||||
pub(crate) use self::fs::*;
|
||||
pub(crate) use self::misc::*;
|
||||
@@ -0,0 +1,61 @@
|
||||
//! This internal module consists of helper types and functions for dealing
|
||||
//! with setting the file times specific to Linux.
|
||||
use super::super::filetime::FileTime;
|
||||
use std::fs::File;
|
||||
use std::io;
|
||||
use std::sync::atomic::{AtomicBool, Ordering::Relaxed};
|
||||
|
||||
pub(crate) const UTIME_NOW: i64 = 1_073_741_823;
|
||||
pub(crate) const UTIME_OMIT: i64 = 1_073_741_822;
|
||||
|
||||
/// Wrapper for `utimensat` syscall, however, with an added twist such that `utimensat` symbol
|
||||
/// is firstly resolved (i.e., we check whether it exists on the host), and only used if that is
|
||||
/// the case. Otherwise, the syscall resorts to a less accurate `utimesat` emulated syscall.
|
||||
/// The original implementation can be found here: [filetime::unix::linux::set_times]
|
||||
///
|
||||
/// [filetime::unix::linux::set_times]: https://github.com/alexcrichton/filetime/blob/master/src/unix/linux.rs#L64
|
||||
pub(crate) fn utimensat(
|
||||
dirfd: &File,
|
||||
path: &str,
|
||||
atime: FileTime,
|
||||
mtime: FileTime,
|
||||
symlink_nofollow: bool,
|
||||
) -> io::Result<()> {
|
||||
use super::super::filetime::{to_timespec, utimesat};
|
||||
use std::ffi::CString;
|
||||
use std::os::unix::prelude::*;
|
||||
|
||||
let flags = if symlink_nofollow {
|
||||
libc::AT_SYMLINK_NOFOLLOW
|
||||
} else {
|
||||
0
|
||||
};
|
||||
|
||||
// Attempt to use the `utimensat` syscall, but if it's not supported by the
|
||||
// current kernel then fall back to an older syscall.
|
||||
static INVALID: AtomicBool = AtomicBool::new(false);
|
||||
if !INVALID.load(Relaxed) {
|
||||
let p = CString::new(path.as_bytes())?;
|
||||
let times = [to_timespec(&atime), to_timespec(&mtime)];
|
||||
let rc = unsafe {
|
||||
libc::syscall(
|
||||
libc::SYS_utimensat,
|
||||
dirfd.as_raw_fd(),
|
||||
p.as_ptr(),
|
||||
times.as_ptr(),
|
||||
flags,
|
||||
)
|
||||
};
|
||||
if rc == 0 {
|
||||
return Ok(());
|
||||
}
|
||||
let err = io::Error::last_os_error();
|
||||
if err.raw_os_error() == Some(libc::ENOSYS) {
|
||||
INVALID.store(true, Relaxed);
|
||||
} else {
|
||||
return Err(err);
|
||||
}
|
||||
}
|
||||
|
||||
utimesat(dirfd, path, atime, mtime, symlink_nofollow)
|
||||
}
|
||||
@@ -0,0 +1,165 @@
|
||||
use super::super::dir::{Dir, Entry, SeekLoc};
|
||||
use super::osfile::OsFile;
|
||||
use crate::old::snapshot_0::hostcalls_impl::{Dirent, PathGet};
|
||||
use crate::old::snapshot_0::sys::host_impl;
|
||||
use crate::old::snapshot_0::sys::unix::str_to_cstring;
|
||||
use crate::old::snapshot_0::{wasi, Error, Result};
|
||||
use log::trace;
|
||||
use std::convert::TryInto;
|
||||
use std::fs::File;
|
||||
use std::os::unix::prelude::AsRawFd;
|
||||
|
||||
pub(crate) fn path_unlink_file(resolved: PathGet) -> Result<()> {
|
||||
use nix::errno;
|
||||
use nix::libc::unlinkat;
|
||||
|
||||
let path_cstr = str_to_cstring(resolved.path())?;
|
||||
|
||||
// nix doesn't expose unlinkat() yet
|
||||
let res = unsafe { unlinkat(resolved.dirfd().as_raw_fd(), path_cstr.as_ptr(), 0) };
|
||||
if res == 0 {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(host_impl::errno_from_nix(errno::Errno::last()))
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn path_symlink(old_path: &str, resolved: PathGet) -> Result<()> {
|
||||
use nix::{errno::Errno, libc::symlinkat};
|
||||
|
||||
let old_path_cstr = str_to_cstring(old_path)?;
|
||||
let new_path_cstr = str_to_cstring(resolved.path())?;
|
||||
|
||||
log::debug!("path_symlink old_path = {:?}", old_path);
|
||||
log::debug!("path_symlink resolved = {:?}", resolved);
|
||||
|
||||
let res = unsafe {
|
||||
symlinkat(
|
||||
old_path_cstr.as_ptr(),
|
||||
resolved.dirfd().as_raw_fd(),
|
||||
new_path_cstr.as_ptr(),
|
||||
)
|
||||
};
|
||||
if res != 0 {
|
||||
Err(host_impl::errno_from_nix(Errno::last()))
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn path_rename(resolved_old: PathGet, resolved_new: PathGet) -> Result<()> {
|
||||
use nix::libc::renameat;
|
||||
let old_path_cstr = str_to_cstring(resolved_old.path())?;
|
||||
let new_path_cstr = str_to_cstring(resolved_new.path())?;
|
||||
|
||||
let res = unsafe {
|
||||
renameat(
|
||||
resolved_old.dirfd().as_raw_fd(),
|
||||
old_path_cstr.as_ptr(),
|
||||
resolved_new.dirfd().as_raw_fd(),
|
||||
new_path_cstr.as_ptr(),
|
||||
)
|
||||
};
|
||||
if res != 0 {
|
||||
Err(host_impl::errno_from_nix(nix::errno::Errno::last()))
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn fd_readdir_impl(
|
||||
fd: &File,
|
||||
cookie: wasi::__wasi_dircookie_t,
|
||||
) -> Result<impl Iterator<Item = Result<Dirent>>> {
|
||||
// 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.
|
||||
// `opendir(3p)` also says that it's undefined behavior to
|
||||
// modify the state of the fd in a different way than by accessing DIR*.
|
||||
//
|
||||
// Still, rewinddir will be needed because the two file descriptors
|
||||
// share progress. But we can safely execute closedir now.
|
||||
let fd = fd.try_clone()?;
|
||||
let mut dir = Dir::from(fd)?;
|
||||
|
||||
// Seek if needed. Unless cookie is wasi::__WASI_DIRCOOKIE_START,
|
||||
// new items may not be returned to the caller.
|
||||
//
|
||||
// According to `opendir(3p)`:
|
||||
// If a file is removed from or added to the directory after the most recent call
|
||||
// to opendir() or rewinddir(), whether a subsequent call to readdir() returns an entry
|
||||
// for that file is unspecified.
|
||||
if cookie == wasi::__WASI_DIRCOOKIE_START {
|
||||
trace!(" | fd_readdir: doing rewinddir");
|
||||
dir.rewind();
|
||||
} else {
|
||||
trace!(" | fd_readdir: doing seekdir to {}", cookie);
|
||||
let loc = unsafe { SeekLoc::from_raw(cookie as i64) };
|
||||
dir.seek(loc);
|
||||
}
|
||||
|
||||
Ok(dir.into_iter().map(|entry| {
|
||||
let entry: Entry = entry?;
|
||||
Ok(Dirent {
|
||||
name: entry // TODO can we reuse path_from_host for CStr?
|
||||
.file_name()
|
||||
.to_str()?
|
||||
.to_owned(),
|
||||
ino: entry.ino(),
|
||||
ftype: entry.file_type().into(),
|
||||
cookie: entry.seek_loc().to_raw().try_into()?,
|
||||
})
|
||||
}))
|
||||
}
|
||||
|
||||
// This should actually be common code with Windows,
|
||||
// but there's BSD stuff remaining
|
||||
pub(crate) fn fd_readdir(
|
||||
os_file: &mut OsFile,
|
||||
mut host_buf: &mut [u8],
|
||||
cookie: wasi::__wasi_dircookie_t,
|
||||
) -> Result<usize> {
|
||||
let iter = fd_readdir_impl(os_file, cookie)?;
|
||||
let mut used = 0;
|
||||
for dirent in iter {
|
||||
let dirent_raw = dirent?.to_wasi_raw()?;
|
||||
let offset = dirent_raw.len();
|
||||
if host_buf.len() < offset {
|
||||
break;
|
||||
} else {
|
||||
host_buf[0..offset].copy_from_slice(&dirent_raw);
|
||||
used += offset;
|
||||
host_buf = &mut host_buf[offset..];
|
||||
}
|
||||
}
|
||||
|
||||
trace!(" | *buf_used={:?}", used);
|
||||
Ok(used)
|
||||
}
|
||||
|
||||
pub(crate) fn fd_advise(
|
||||
file: &File,
|
||||
advice: wasi::__wasi_advice_t,
|
||||
offset: wasi::__wasi_filesize_t,
|
||||
len: wasi::__wasi_filesize_t,
|
||||
) -> Result<()> {
|
||||
{
|
||||
use nix::fcntl::{posix_fadvise, PosixFadviseAdvice};
|
||||
|
||||
let offset = offset.try_into()?;
|
||||
let len = len.try_into()?;
|
||||
let host_advice = match advice {
|
||||
wasi::__WASI_ADVICE_DONTNEED => PosixFadviseAdvice::POSIX_FADV_DONTNEED,
|
||||
wasi::__WASI_ADVICE_SEQUENTIAL => PosixFadviseAdvice::POSIX_FADV_SEQUENTIAL,
|
||||
wasi::__WASI_ADVICE_WILLNEED => PosixFadviseAdvice::POSIX_FADV_WILLNEED,
|
||||
wasi::__WASI_ADVICE_NOREUSE => PosixFadviseAdvice::POSIX_FADV_NOREUSE,
|
||||
wasi::__WASI_ADVICE_RANDOM => PosixFadviseAdvice::POSIX_FADV_RANDOM,
|
||||
wasi::__WASI_ADVICE_NORMAL => PosixFadviseAdvice::POSIX_FADV_NORMAL,
|
||||
_ => return Err(Error::EINVAL),
|
||||
};
|
||||
|
||||
posix_fadvise(file.as_raw_fd(), offset, len, host_advice)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
33
crates/wasi-common/src/old/snapshot_0/sys/unix/linux/mod.rs
Normal file
33
crates/wasi-common/src/old/snapshot_0/sys/unix/linux/mod.rs
Normal file
@@ -0,0 +1,33 @@
|
||||
pub(crate) mod filetime;
|
||||
pub(crate) mod hostcalls_impl;
|
||||
pub(crate) mod osfile;
|
||||
|
||||
pub(crate) mod fdentry_impl {
|
||||
use crate::old::snapshot_0::{sys::host_impl, Result};
|
||||
use std::os::unix::prelude::AsRawFd;
|
||||
|
||||
pub(crate) unsafe fn isatty(fd: &impl AsRawFd) -> Result<bool> {
|
||||
use nix::errno::Errno;
|
||||
|
||||
let res = libc::isatty(fd.as_raw_fd());
|
||||
if res == 1 {
|
||||
// isatty() returns 1 if fd is an open file descriptor referring to a terminal...
|
||||
Ok(true)
|
||||
} else {
|
||||
// ... otherwise 0 is returned, and errno is set to indicate the error.
|
||||
match Errno::last() {
|
||||
// While POSIX specifies ENOTTY if the passed
|
||||
// fd is *not* a tty, on Linux, some implementations
|
||||
// may return EINVAL instead.
|
||||
//
|
||||
// https://linux.die.net/man/3/isatty
|
||||
Errno::ENOTTY | Errno::EINVAL => Ok(false),
|
||||
x => Err(host_impl::errno_from_nix(x)),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) mod host_impl {
|
||||
pub(crate) const O_RSYNC: nix::fcntl::OFlag = nix::fcntl::OFlag::O_RSYNC;
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
use std::fs;
|
||||
use std::ops::{Deref, DerefMut};
|
||||
use std::os::unix::prelude::{AsRawFd, RawFd};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct OsFile(fs::File);
|
||||
|
||||
impl From<fs::File> for OsFile {
|
||||
fn from(file: fs::File) -> Self {
|
||||
Self(file)
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRawFd for OsFile {
|
||||
fn as_raw_fd(&self) -> RawFd {
|
||||
self.0.as_raw_fd()
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for OsFile {
|
||||
type Target = fs::File;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl DerefMut for OsFile {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
&mut self.0
|
||||
}
|
||||
}
|
||||
34
crates/wasi-common/src/old/snapshot_0/sys/unix/mod.rs
Normal file
34
crates/wasi-common/src/old/snapshot_0/sys/unix/mod.rs
Normal file
@@ -0,0 +1,34 @@
|
||||
pub(crate) mod fdentry_impl;
|
||||
pub(crate) mod host_impl;
|
||||
pub(crate) mod hostcalls_impl;
|
||||
|
||||
mod dir;
|
||||
mod filetime;
|
||||
|
||||
#[cfg(any(
|
||||
target_os = "macos",
|
||||
target_os = "netbsd",
|
||||
target_os = "freebsd",
|
||||
target_os = "openbsd",
|
||||
target_os = "ios",
|
||||
target_os = "dragonfly"
|
||||
))]
|
||||
mod bsd;
|
||||
#[cfg(target_os = "linux")]
|
||||
mod linux;
|
||||
|
||||
use crate::old::snapshot_0::{Error, Result};
|
||||
use std::ffi::CString;
|
||||
use std::fs::{File, OpenOptions};
|
||||
|
||||
pub(crate) fn dev_null() -> Result<File> {
|
||||
OpenOptions::new()
|
||||
.read(true)
|
||||
.write(true)
|
||||
.open("/dev/null")
|
||||
.map_err(Into::into)
|
||||
}
|
||||
|
||||
pub(crate) fn str_to_cstring(s: &str) -> Result<CString> {
|
||||
CString::new(s.as_bytes()).map_err(|_| Error::EILSEQ)
|
||||
}
|
||||
@@ -0,0 +1,129 @@
|
||||
use crate::old::snapshot_0::fdentry::Descriptor;
|
||||
use crate::old::snapshot_0::{wasi, Error, Result};
|
||||
use std::fs::File;
|
||||
use std::io;
|
||||
use std::ops::{Deref, DerefMut};
|
||||
use std::os::windows::prelude::{AsRawHandle, FromRawHandle, RawHandle};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct OsFile(File);
|
||||
|
||||
impl From<File> for OsFile {
|
||||
fn from(file: File) -> Self {
|
||||
Self(file)
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRawHandle for OsFile {
|
||||
fn as_raw_handle(&self) -> RawHandle {
|
||||
self.0.as_raw_handle()
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for OsFile {
|
||||
type Target = File;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl DerefMut for OsFile {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
&mut self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRawHandle for Descriptor {
|
||||
fn as_raw_handle(&self) -> RawHandle {
|
||||
match self {
|
||||
Self::OsFile(file) => file.as_raw_handle(),
|
||||
Self::Stdin => io::stdin().as_raw_handle(),
|
||||
Self::Stdout => io::stdout().as_raw_handle(),
|
||||
Self::Stderr => io::stderr().as_raw_handle(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// This function is unsafe because it operates on a raw file handle.
|
||||
pub(crate) unsafe fn determine_type_and_access_rights<Handle: AsRawHandle>(
|
||||
handle: &Handle,
|
||||
) -> Result<(
|
||||
wasi::__wasi_filetype_t,
|
||||
wasi::__wasi_rights_t,
|
||||
wasi::__wasi_rights_t,
|
||||
)> {
|
||||
use winx::file::{get_file_access_mode, AccessMode};
|
||||
|
||||
let (file_type, mut rights_base, rights_inheriting) = determine_type_rights(handle)?;
|
||||
|
||||
match file_type {
|
||||
wasi::__WASI_FILETYPE_DIRECTORY | wasi::__WASI_FILETYPE_REGULAR_FILE => {
|
||||
let mode = get_file_access_mode(handle.as_raw_handle())?;
|
||||
if mode.contains(AccessMode::FILE_GENERIC_READ) {
|
||||
rights_base |= wasi::__WASI_RIGHTS_FD_READ;
|
||||
}
|
||||
if mode.contains(AccessMode::FILE_GENERIC_WRITE) {
|
||||
rights_base |= wasi::__WASI_RIGHTS_FD_WRITE;
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
// TODO: is there a way around this? On windows, it seems
|
||||
// we cannot check access rights for anything but dirs and regular files
|
||||
}
|
||||
}
|
||||
|
||||
Ok((file_type, rights_base, rights_inheriting))
|
||||
}
|
||||
|
||||
/// This function is unsafe because it operates on a raw file handle.
|
||||
pub(crate) unsafe fn determine_type_rights<Handle: AsRawHandle>(
|
||||
handle: &Handle,
|
||||
) -> Result<(
|
||||
wasi::__wasi_filetype_t,
|
||||
wasi::__wasi_rights_t,
|
||||
wasi::__wasi_rights_t,
|
||||
)> {
|
||||
let (file_type, rights_base, rights_inheriting) = {
|
||||
let file_type = winx::file::get_file_type(handle.as_raw_handle())?;
|
||||
if file_type.is_char() {
|
||||
// character file: LPT device or console
|
||||
// TODO: rule out LPT device
|
||||
(
|
||||
wasi::__WASI_FILETYPE_CHARACTER_DEVICE,
|
||||
wasi::RIGHTS_TTY_BASE,
|
||||
wasi::RIGHTS_TTY_BASE,
|
||||
)
|
||||
} 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)?;
|
||||
if meta.is_dir() {
|
||||
(
|
||||
wasi::__WASI_FILETYPE_DIRECTORY,
|
||||
wasi::RIGHTS_DIRECTORY_BASE,
|
||||
wasi::RIGHTS_DIRECTORY_INHERITING,
|
||||
)
|
||||
} else if meta.is_file() {
|
||||
(
|
||||
wasi::__WASI_FILETYPE_REGULAR_FILE,
|
||||
wasi::RIGHTS_REGULAR_FILE_BASE,
|
||||
wasi::RIGHTS_REGULAR_FILE_INHERITING,
|
||||
)
|
||||
} else {
|
||||
return Err(Error::EINVAL);
|
||||
}
|
||||
} else if file_type.is_pipe() {
|
||||
// pipe object: socket, named pipe or anonymous pipe
|
||||
// TODO: what about pipes, etc?
|
||||
(
|
||||
wasi::__WASI_FILETYPE_SOCKET_STREAM,
|
||||
wasi::RIGHTS_SOCKET_BASE,
|
||||
wasi::RIGHTS_SOCKET_INHERITING,
|
||||
)
|
||||
} else {
|
||||
return Err(Error::EINVAL);
|
||||
}
|
||||
};
|
||||
Ok((file_type, rights_base, rights_inheriting))
|
||||
}
|
||||
108
crates/wasi-common/src/old/snapshot_0/sys/windows/host_impl.rs
Normal file
108
crates/wasi-common/src/old/snapshot_0/sys/windows/host_impl.rs
Normal file
@@ -0,0 +1,108 @@
|
||||
//! WASI host types specific to Windows host.
|
||||
#![allow(non_camel_case_types)]
|
||||
#![allow(non_snake_case)]
|
||||
#![allow(unused)]
|
||||
use crate::old::snapshot_0::{wasi, Error, Result};
|
||||
use std::ffi::OsStr;
|
||||
use std::fs::OpenOptions;
|
||||
use std::os::windows::ffi::OsStrExt;
|
||||
use std::os::windows::fs::OpenOptionsExt;
|
||||
use winx::file::{AccessMode, Attributes, CreationDisposition, Flags};
|
||||
|
||||
pub(crate) fn errno_from_win(error: winx::winerror::WinError) -> wasi::__wasi_errno_t {
|
||||
// TODO: implement error mapping between Windows and WASI
|
||||
use winx::winerror::WinError::*;
|
||||
match error {
|
||||
ERROR_SUCCESS => wasi::__WASI_ERRNO_SUCCESS,
|
||||
ERROR_BAD_ENVIRONMENT => wasi::__WASI_ERRNO_2BIG,
|
||||
ERROR_FILE_NOT_FOUND => wasi::__WASI_ERRNO_NOENT,
|
||||
ERROR_PATH_NOT_FOUND => wasi::__WASI_ERRNO_NOENT,
|
||||
ERROR_TOO_MANY_OPEN_FILES => wasi::__WASI_ERRNO_NFILE,
|
||||
ERROR_ACCESS_DENIED => wasi::__WASI_ERRNO_ACCES,
|
||||
ERROR_SHARING_VIOLATION => wasi::__WASI_ERRNO_ACCES,
|
||||
ERROR_PRIVILEGE_NOT_HELD => wasi::__WASI_ERRNO_NOTCAPABLE, // TODO is this the correct mapping?
|
||||
ERROR_INVALID_HANDLE => wasi::__WASI_ERRNO_BADF,
|
||||
ERROR_INVALID_NAME => wasi::__WASI_ERRNO_NOENT,
|
||||
ERROR_NOT_ENOUGH_MEMORY => wasi::__WASI_ERRNO_NOMEM,
|
||||
ERROR_OUTOFMEMORY => wasi::__WASI_ERRNO_NOMEM,
|
||||
ERROR_DIR_NOT_EMPTY => wasi::__WASI_ERRNO_NOTEMPTY,
|
||||
ERROR_NOT_READY => wasi::__WASI_ERRNO_BUSY,
|
||||
ERROR_BUSY => wasi::__WASI_ERRNO_BUSY,
|
||||
ERROR_NOT_SUPPORTED => wasi::__WASI_ERRNO_NOTSUP,
|
||||
ERROR_FILE_EXISTS => wasi::__WASI_ERRNO_EXIST,
|
||||
ERROR_BROKEN_PIPE => wasi::__WASI_ERRNO_PIPE,
|
||||
ERROR_BUFFER_OVERFLOW => wasi::__WASI_ERRNO_NAMETOOLONG,
|
||||
ERROR_NOT_A_REPARSE_POINT => wasi::__WASI_ERRNO_INVAL,
|
||||
ERROR_NEGATIVE_SEEK => wasi::__WASI_ERRNO_INVAL,
|
||||
ERROR_DIRECTORY => wasi::__WASI_ERRNO_NOTDIR,
|
||||
ERROR_ALREADY_EXISTS => wasi::__WASI_ERRNO_EXIST,
|
||||
_ => wasi::__WASI_ERRNO_NOTSUP,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn fdflags_from_win(mode: AccessMode) -> wasi::__wasi_fdflags_t {
|
||||
let mut fdflags = 0;
|
||||
// TODO verify this!
|
||||
if mode.contains(AccessMode::FILE_APPEND_DATA) {
|
||||
fdflags |= wasi::__WASI_FDFLAGS_APPEND;
|
||||
}
|
||||
if mode.contains(AccessMode::SYNCHRONIZE) {
|
||||
fdflags |= wasi::__WASI_FDFLAGS_DSYNC;
|
||||
fdflags |= wasi::__WASI_FDFLAGS_RSYNC;
|
||||
fdflags |= wasi::__WASI_FDFLAGS_SYNC;
|
||||
}
|
||||
// The NONBLOCK equivalent is FILE_FLAG_OVERLAPPED
|
||||
// but it seems winapi doesn't provide a mechanism
|
||||
// for checking whether the handle supports async IO.
|
||||
// On the contrary, I've found some dicsussion online
|
||||
// which suggests that on Windows all handles should
|
||||
// generally be assumed to be opened with async support
|
||||
// and then the program should fallback should that **not**
|
||||
// be the case at the time of the operation.
|
||||
// TODO: this requires further investigation
|
||||
fdflags
|
||||
}
|
||||
|
||||
pub(crate) fn win_from_fdflags(fdflags: wasi::__wasi_fdflags_t) -> (AccessMode, Flags) {
|
||||
let mut access_mode = AccessMode::empty();
|
||||
let mut flags = Flags::empty();
|
||||
|
||||
// TODO verify this!
|
||||
if fdflags & wasi::__WASI_FDFLAGS_NONBLOCK != 0 {
|
||||
flags.insert(Flags::FILE_FLAG_OVERLAPPED);
|
||||
}
|
||||
if fdflags & wasi::__WASI_FDFLAGS_APPEND != 0 {
|
||||
access_mode.insert(AccessMode::FILE_APPEND_DATA);
|
||||
}
|
||||
if fdflags & wasi::__WASI_FDFLAGS_DSYNC != 0
|
||||
|| fdflags & wasi::__WASI_FDFLAGS_RSYNC != 0
|
||||
|| fdflags & wasi::__WASI_FDFLAGS_SYNC != 0
|
||||
{
|
||||
access_mode.insert(AccessMode::SYNCHRONIZE);
|
||||
}
|
||||
|
||||
(access_mode, flags)
|
||||
}
|
||||
|
||||
pub(crate) fn win_from_oflags(oflags: wasi::__wasi_oflags_t) -> CreationDisposition {
|
||||
if oflags & wasi::__WASI_OFLAGS_CREAT != 0 {
|
||||
if oflags & wasi::__WASI_OFLAGS_EXCL != 0 {
|
||||
CreationDisposition::CREATE_NEW
|
||||
} else {
|
||||
CreationDisposition::CREATE_ALWAYS
|
||||
}
|
||||
} else if oflags & wasi::__WASI_OFLAGS_TRUNC != 0 {
|
||||
CreationDisposition::TRUNCATE_EXISTING
|
||||
} else {
|
||||
CreationDisposition::OPEN_EXISTING
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates owned WASI path from OS string.
|
||||
///
|
||||
/// 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> {
|
||||
let vec: Vec<u16> = s.as_ref().encode_wide().collect();
|
||||
String::from_utf16(&vec).map_err(|_| Error::EILSEQ)
|
||||
}
|
||||
@@ -0,0 +1,552 @@
|
||||
#![allow(non_camel_case_types)]
|
||||
#![allow(unused)]
|
||||
use super::fs_helpers::*;
|
||||
use crate::old::snapshot_0::ctx::WasiCtx;
|
||||
use crate::old::snapshot_0::fdentry::FdEntry;
|
||||
use crate::old::snapshot_0::helpers::systemtime_to_timestamp;
|
||||
use crate::old::snapshot_0::hostcalls_impl::{
|
||||
fd_filestat_set_times_impl, Dirent, FileType, PathGet,
|
||||
};
|
||||
use crate::old::snapshot_0::sys::fdentry_impl::{determine_type_rights, OsFile};
|
||||
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::{wasi, Error, Result};
|
||||
use log::{debug, trace};
|
||||
use std::convert::TryInto;
|
||||
use std::fs::{File, Metadata, OpenOptions};
|
||||
use std::io::{self, Seek, SeekFrom};
|
||||
use std::os::windows::fs::{FileExt, OpenOptionsExt};
|
||||
use std::os::windows::prelude::{AsRawHandle, FromRawHandle};
|
||||
use std::path::{Path, PathBuf};
|
||||
use winx::file::{AccessMode, Flags};
|
||||
|
||||
fn read_at(mut file: &File, buf: &mut [u8], offset: u64) -> io::Result<usize> {
|
||||
// get current cursor position
|
||||
let cur_pos = file.seek(SeekFrom::Current(0))?;
|
||||
// perform a seek read by a specified offset
|
||||
let nread = file.seek_read(buf, offset)?;
|
||||
// rewind the cursor back to the original position
|
||||
file.seek(SeekFrom::Start(cur_pos))?;
|
||||
Ok(nread)
|
||||
}
|
||||
|
||||
fn write_at(mut file: &File, buf: &[u8], offset: u64) -> io::Result<usize> {
|
||||
// get current cursor position
|
||||
let cur_pos = file.seek(SeekFrom::Current(0))?;
|
||||
// perform a seek write by a specified offset
|
||||
let nwritten = file.seek_write(buf, offset)?;
|
||||
// rewind the cursor back to the original position
|
||||
file.seek(SeekFrom::Start(cur_pos))?;
|
||||
Ok(nwritten)
|
||||
}
|
||||
|
||||
// TODO refactor common code with unix
|
||||
pub(crate) fn fd_pread(
|
||||
file: &File,
|
||||
buf: &mut [u8],
|
||||
offset: wasi::__wasi_filesize_t,
|
||||
) -> Result<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> {
|
||||
write_at(file, buf, offset).map_err(Into::into)
|
||||
}
|
||||
|
||||
pub(crate) fn fd_fdstat_get(fd: &File) -> Result<wasi::__wasi_fdflags_t> {
|
||||
use winx::file::AccessMode;
|
||||
unsafe { winx::file::get_file_access_mode(fd.as_raw_handle()) }
|
||||
.map(host_impl::fdflags_from_win)
|
||||
.map_err(Into::into)
|
||||
}
|
||||
|
||||
pub(crate) fn fd_fdstat_set_flags(fd: &File, fdflags: wasi::__wasi_fdflags_t) -> Result<()> {
|
||||
unimplemented!("fd_fdstat_set_flags")
|
||||
}
|
||||
|
||||
pub(crate) fn fd_advise(
|
||||
_file: &File,
|
||||
advice: wasi::__wasi_advice_t,
|
||||
_offset: wasi::__wasi_filesize_t,
|
||||
_len: wasi::__wasi_filesize_t,
|
||||
) -> Result<()> {
|
||||
match advice {
|
||||
wasi::__WASI_ADVICE_DONTNEED
|
||||
| wasi::__WASI_ADVICE_SEQUENTIAL
|
||||
| wasi::__WASI_ADVICE_WILLNEED
|
||||
| wasi::__WASI_ADVICE_NOREUSE
|
||||
| wasi::__WASI_ADVICE_RANDOM
|
||||
| wasi::__WASI_ADVICE_NORMAL => {}
|
||||
_ => return Err(Error::EINVAL),
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn path_create_directory(resolved: PathGet) -> Result<()> {
|
||||
let path = resolved.concatenate()?;
|
||||
std::fs::create_dir(&path).map_err(Into::into)
|
||||
}
|
||||
|
||||
pub(crate) fn path_link(resolved_old: PathGet, resolved_new: PathGet) -> Result<()> {
|
||||
unimplemented!("path_link")
|
||||
}
|
||||
|
||||
pub(crate) fn path_open(
|
||||
resolved: PathGet,
|
||||
read: bool,
|
||||
write: bool,
|
||||
oflags: wasi::__wasi_oflags_t,
|
||||
fdflags: wasi::__wasi_fdflags_t,
|
||||
) -> Result<File> {
|
||||
use winx::file::{AccessMode, CreationDisposition, Flags};
|
||||
|
||||
let mut access_mode = AccessMode::READ_CONTROL;
|
||||
if read {
|
||||
access_mode.insert(AccessMode::FILE_GENERIC_READ);
|
||||
}
|
||||
if write {
|
||||
access_mode.insert(AccessMode::FILE_GENERIC_WRITE);
|
||||
}
|
||||
|
||||
let mut flags = Flags::FILE_FLAG_BACKUP_SEMANTICS;
|
||||
|
||||
// convert open flags
|
||||
let mut opts = OpenOptions::new();
|
||||
match host_impl::win_from_oflags(oflags) {
|
||||
CreationDisposition::CREATE_ALWAYS => {
|
||||
opts.create(true).append(true);
|
||||
}
|
||||
CreationDisposition::CREATE_NEW => {
|
||||
opts.create_new(true).write(true);
|
||||
}
|
||||
CreationDisposition::TRUNCATE_EXISTING => {
|
||||
opts.truncate(true);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
// convert file descriptor flags
|
||||
let (add_access_mode, add_flags) = host_impl::win_from_fdflags(fdflags);
|
||||
access_mode.insert(add_access_mode);
|
||||
flags.insert(add_flags);
|
||||
|
||||
let path = resolved.concatenate()?;
|
||||
|
||||
match path.symlink_metadata().map(|metadata| metadata.file_type()) {
|
||||
Ok(file_type) => {
|
||||
// check if we are trying to open a symlink
|
||||
if file_type.is_symlink() {
|
||||
return Err(Error::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);
|
||||
}
|
||||
}
|
||||
Err(e) => match e.raw_os_error() {
|
||||
Some(e) => {
|
||||
use winx::winerror::WinError;
|
||||
log::debug!("path_open at symlink_metadata error code={:?}", e);
|
||||
let e = WinError::from_u32(e as u32);
|
||||
|
||||
if e != WinError::ERROR_FILE_NOT_FOUND {
|
||||
return Err(e.into());
|
||||
}
|
||||
// file not found, let it proceed to actually
|
||||
// trying to open it
|
||||
}
|
||||
None => {
|
||||
log::debug!("Inconvertible OS error: {}", e);
|
||||
return Err(Error::EIO);
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
opts.access_mode(access_mode.bits())
|
||||
.custom_flags(flags.bits())
|
||||
.open(&path)
|
||||
.map_err(Into::into)
|
||||
}
|
||||
|
||||
fn dirent_from_path<P: AsRef<Path>>(
|
||||
path: P,
|
||||
name: &str,
|
||||
cookie: wasi::__wasi_dircookie_t,
|
||||
) -> Result<Dirent> {
|
||||
let path = path.as_ref();
|
||||
trace!("dirent_from_path: opening {}", path.to_string_lossy());
|
||||
|
||||
// To open a directory on Windows, FILE_FLAG_BACKUP_SEMANTICS flag must be used
|
||||
let file = OpenOptions::new()
|
||||
.custom_flags(Flags::FILE_FLAG_BACKUP_SEMANTICS.bits())
|
||||
.read(true)
|
||||
.open(path)?;
|
||||
let ty = file.metadata()?.file_type();
|
||||
Ok(Dirent {
|
||||
ftype: filetype_from_std(&ty),
|
||||
name: name.to_owned(),
|
||||
cookie,
|
||||
ino: file_serial_no(&file)?,
|
||||
})
|
||||
}
|
||||
|
||||
// On Windows there is apparently no support for seeking the directory stream in the OS.
|
||||
// cf. https://github.com/WebAssembly/WASI/issues/61
|
||||
//
|
||||
// The implementation here may perform in O(n^2) if the host buffer is O(1)
|
||||
// and the number of directory entries is O(n).
|
||||
// TODO: Add a heuristic optimization to achieve O(n) time in the most common case
|
||||
// where fd_readdir is resumed where it previously finished
|
||||
//
|
||||
// Correctness of this approach relies upon one assumption: that the order of entries
|
||||
// returned by `FindNextFileW` is stable, i.e. doesn't change if the directory
|
||||
// contents stay the same. This invariant is crucial to be able to implement
|
||||
// any kind of seeking whatsoever without having to read the whole directory at once
|
||||
// and then return the data from cache. (which leaks memory)
|
||||
//
|
||||
// The MSDN documentation explicitly says that the order in which the search returns the files
|
||||
// is not guaranteed, and is dependent on the file system.
|
||||
// cf. https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-findnextfilew
|
||||
//
|
||||
// This stackoverflow post suggests that `FindNextFileW` is indeed stable and that
|
||||
// the order of directory entries depends **only** on the filesystem used, but the
|
||||
// MSDN documentation is not clear about this.
|
||||
// cf. https://stackoverflow.com/questions/47380739/is-findfirstfile-and-findnextfile-order-random-even-for-dvd
|
||||
//
|
||||
// Implementation details:
|
||||
// Cookies for the directory entries start from 1. (0 is reserved by wasi::__WASI_DIRCOOKIE_START)
|
||||
// . gets cookie = 1
|
||||
// .. gets cookie = 2
|
||||
// other entries, in order they were returned by FindNextFileW get subsequent integers as their cookies
|
||||
pub(crate) fn fd_readdir_impl(
|
||||
fd: &File,
|
||||
cookie: wasi::__wasi_dircookie_t,
|
||||
) -> Result<impl Iterator<Item = Result<Dirent>>> {
|
||||
use winx::file::get_file_path;
|
||||
|
||||
let cookie = cookie.try_into()?;
|
||||
let path = get_file_path(fd)?;
|
||||
// std::fs::ReadDir doesn't return . and .., so we need to emulate it
|
||||
let path = Path::new(&path);
|
||||
// The directory /.. is the same as / on Unix (at least on ext4), so emulate this behavior too
|
||||
let parent = path.parent().unwrap_or(path);
|
||||
let dot = dirent_from_path(path, ".", 1)?;
|
||||
let dotdot = dirent_from_path(parent, "..", 2)?;
|
||||
|
||||
trace!(" | fd_readdir impl: executing std::fs::ReadDir");
|
||||
let iter = path.read_dir()?.zip(3..).map(|(dir, no)| {
|
||||
let dir: std::fs::DirEntry = dir?;
|
||||
|
||||
Ok(Dirent {
|
||||
name: path_from_host(dir.file_name())?,
|
||||
ftype: filetype_from_std(&dir.file_type()?),
|
||||
ino: File::open(dir.path()).and_then(|f| file_serial_no(&f))?,
|
||||
cookie: no,
|
||||
})
|
||||
});
|
||||
|
||||
// into_iter for arrays is broken and returns references instead of values,
|
||||
// so we need to use vec![...] and do heap allocation
|
||||
// See https://github.com/rust-lang/rust/issues/25725
|
||||
let iter = vec![dot, dotdot].into_iter().map(Ok).chain(iter);
|
||||
|
||||
// Emulate seekdir(). This may give O(n^2) complexity if used with a
|
||||
// small host_buf, but this is difficult to implement efficiently.
|
||||
//
|
||||
// See https://github.com/WebAssembly/WASI/issues/61 for more details.
|
||||
Ok(iter.skip(cookie))
|
||||
}
|
||||
|
||||
// This should actually be common code with Linux
|
||||
pub(crate) fn fd_readdir(
|
||||
os_file: &mut OsFile,
|
||||
mut host_buf: &mut [u8],
|
||||
cookie: wasi::__wasi_dircookie_t,
|
||||
) -> Result<usize> {
|
||||
let iter = fd_readdir_impl(os_file, cookie)?;
|
||||
let mut used = 0;
|
||||
for dirent in iter {
|
||||
let dirent_raw = dirent?.to_wasi_raw()?;
|
||||
let offset = dirent_raw.len();
|
||||
if host_buf.len() < offset {
|
||||
break;
|
||||
} else {
|
||||
host_buf[0..offset].copy_from_slice(&dirent_raw);
|
||||
used += offset;
|
||||
host_buf = &mut host_buf[offset..];
|
||||
}
|
||||
}
|
||||
|
||||
trace!(" | *buf_used={:?}", used);
|
||||
Ok(used)
|
||||
}
|
||||
|
||||
pub(crate) fn path_readlink(resolved: PathGet, buf: &mut [u8]) -> Result<usize> {
|
||||
use winx::file::get_file_path;
|
||||
|
||||
let path = resolved.concatenate()?;
|
||||
let target_path = path.read_link()?;
|
||||
|
||||
// since on Windows we are effectively emulating 'at' syscalls
|
||||
// we need to strip the prefix from the absolute path
|
||||
// as otherwise we will error out since WASI is not capable
|
||||
// of dealing with absolute paths
|
||||
let dir_path = get_file_path(resolved.dirfd())?;
|
||||
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))?;
|
||||
|
||||
if buf.len() > 0 {
|
||||
let mut chars = target_path.chars();
|
||||
let mut nread = 0usize;
|
||||
|
||||
for i in 0..buf.len() {
|
||||
match chars.next() {
|
||||
Some(ch) => {
|
||||
buf[i] = ch as u8;
|
||||
nread += 1;
|
||||
}
|
||||
None => break,
|
||||
}
|
||||
}
|
||||
|
||||
Ok(nread)
|
||||
} else {
|
||||
Ok(0)
|
||||
}
|
||||
}
|
||||
|
||||
fn strip_trailing_slashes_and_concatenate(resolved: &PathGet) -> Result<Option<PathBuf>> {
|
||||
if resolved.path().ends_with('/') {
|
||||
let suffix = resolved.path().trim_end_matches('/');
|
||||
concatenate(resolved.dirfd(), Path::new(suffix)).map(Some)
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn path_rename(resolved_old: PathGet, resolved_new: PathGet) -> Result<()> {
|
||||
use std::fs;
|
||||
|
||||
let old_path = resolved_old.concatenate()?;
|
||||
let new_path = resolved_new.concatenate()?;
|
||||
|
||||
// First sanity check: check we're not trying to rename dir to file or vice versa.
|
||||
// NB on Windows, the former is actually permitted [std::fs::rename].
|
||||
//
|
||||
// [std::fs::rename]: https://doc.rust-lang.org/std/fs/fn.rename.html
|
||||
if old_path.is_dir() && new_path.is_file() {
|
||||
return Err(Error::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);
|
||||
}
|
||||
|
||||
// TODO handle symlinks
|
||||
|
||||
fs::rename(&old_path, &new_path).or_else(|e| match e.raw_os_error() {
|
||||
Some(e) => {
|
||||
use winx::winerror::WinError;
|
||||
|
||||
log::debug!("path_rename at rename error code={:?}", e);
|
||||
match WinError::from_u32(e as u32) {
|
||||
WinError::ERROR_ACCESS_DENIED => {
|
||||
// So most likely dealing with new_path == dir.
|
||||
// Eliminate case old_path == file first.
|
||||
if old_path.is_file() {
|
||||
Err(Error::EISDIR)
|
||||
} else {
|
||||
// Ok, let's try removing an empty dir at new_path if it exists
|
||||
// and is a nonempty dir.
|
||||
fs::remove_dir(&new_path)
|
||||
.and_then(|()| fs::rename(old_path, new_path))
|
||||
.map_err(Into::into)
|
||||
}
|
||||
}
|
||||
WinError::ERROR_INVALID_NAME => {
|
||||
// If source contains trailing slashes, check if we are dealing with
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
Err(WinError::ERROR_INVALID_NAME.into())
|
||||
}
|
||||
e => Err(e.into()),
|
||||
}
|
||||
}
|
||||
None => {
|
||||
log::debug!("Inconvertible OS error: {}", e);
|
||||
Err(Error::EIO)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn num_hardlinks(file: &File, _metadata: &Metadata) -> io::Result<u64> {
|
||||
Ok(winx::file::get_fileinfo(file)?.nNumberOfLinks.into())
|
||||
}
|
||||
|
||||
pub(crate) fn device_id(file: &File, _metadata: &Metadata) -> io::Result<u64> {
|
||||
Ok(winx::file::get_fileinfo(file)?.dwVolumeSerialNumber.into())
|
||||
}
|
||||
|
||||
pub(crate) fn file_serial_no(file: &File) -> io::Result<u64> {
|
||||
let info = winx::file::get_fileinfo(file)?;
|
||||
let high = info.nFileIndexHigh;
|
||||
let low = info.nFileIndexLow;
|
||||
let no = ((high as u64) << 32) | (low as u64);
|
||||
Ok(no)
|
||||
}
|
||||
|
||||
pub(crate) fn change_time(file: &File, _metadata: &Metadata) -> io::Result<i64> {
|
||||
winx::file::change_time(file)
|
||||
}
|
||||
|
||||
pub(crate) fn fd_filestat_get_impl(file: &std::fs::File) -> Result<wasi::__wasi_filestat_t> {
|
||||
let metadata = file.metadata()?;
|
||||
Ok(wasi::__wasi_filestat_t {
|
||||
dev: device_id(file, &metadata)?,
|
||||
ino: file_serial_no(file)?,
|
||||
nlink: num_hardlinks(file, &metadata)?.try_into()?, // u64 doesn't fit into u32
|
||||
size: metadata.len(),
|
||||
atim: systemtime_to_timestamp(metadata.accessed()?)?,
|
||||
ctim: change_time(file, &metadata)?.try_into()?, // i64 doesn't fit into u64
|
||||
mtim: systemtime_to_timestamp(metadata.modified()?)?,
|
||||
filetype: filetype_from_std(&metadata.file_type()).to_wasi(),
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn filetype_from_std(ftype: &std::fs::FileType) -> FileType {
|
||||
if ftype.is_file() {
|
||||
FileType::RegularFile
|
||||
} else if ftype.is_dir() {
|
||||
FileType::Directory
|
||||
} else if ftype.is_symlink() {
|
||||
FileType::Symlink
|
||||
} else {
|
||||
FileType::Unknown
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn path_filestat_get(
|
||||
resolved: PathGet,
|
||||
dirflags: wasi::__wasi_lookupflags_t,
|
||||
) -> Result<wasi::__wasi_filestat_t> {
|
||||
let path = resolved.concatenate()?;
|
||||
let file = File::open(path)?;
|
||||
fd_filestat_get_impl(&file)
|
||||
}
|
||||
|
||||
pub(crate) fn path_filestat_set_times(
|
||||
resolved: PathGet,
|
||||
dirflags: wasi::__wasi_lookupflags_t,
|
||||
st_atim: wasi::__wasi_timestamp_t,
|
||||
mut st_mtim: wasi::__wasi_timestamp_t,
|
||||
fst_flags: wasi::__wasi_fstflags_t,
|
||||
) -> Result<()> {
|
||||
use winx::file::AccessMode;
|
||||
let path = resolved.concatenate()?;
|
||||
let file = OpenOptions::new()
|
||||
.access_mode(AccessMode::FILE_WRITE_ATTRIBUTES.bits())
|
||||
.open(path)?;
|
||||
fd_filestat_set_times_impl(&file, st_atim, st_mtim, fst_flags)
|
||||
}
|
||||
|
||||
pub(crate) fn path_symlink(old_path: &str, resolved: PathGet) -> Result<()> {
|
||||
use std::os::windows::fs::{symlink_dir, symlink_file};
|
||||
use winx::winerror::WinError;
|
||||
|
||||
let old_path = concatenate(resolved.dirfd(), Path::new(old_path))?;
|
||||
let new_path = resolved.concatenate()?;
|
||||
|
||||
// try creating a file symlink
|
||||
symlink_file(&old_path, &new_path).or_else(|e| {
|
||||
match e.raw_os_error() {
|
||||
Some(e) => {
|
||||
log::debug!("path_symlink at symlink_file error code={:?}", e);
|
||||
match WinError::from_u32(e as u32) {
|
||||
WinError::ERROR_NOT_A_REPARSE_POINT => {
|
||||
// try creating a dir symlink instead
|
||||
symlink_dir(old_path, new_path).map_err(Into::into)
|
||||
}
|
||||
WinError::ERROR_ACCESS_DENIED => {
|
||||
// does the target exist?
|
||||
if new_path.exists() {
|
||||
Err(Error::EEXIST)
|
||||
} else {
|
||||
Err(WinError::ERROR_ACCESS_DENIED.into())
|
||||
}
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
Err(WinError::ERROR_INVALID_NAME.into())
|
||||
}
|
||||
e => Err(e.into()),
|
||||
}
|
||||
}
|
||||
None => {
|
||||
log::debug!("Inconvertible OS error: {}", e);
|
||||
Err(Error::EIO)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn path_unlink_file(resolved: PathGet) -> Result<()> {
|
||||
use std::fs;
|
||||
use winx::winerror::WinError;
|
||||
|
||||
let path = resolved.concatenate()?;
|
||||
let file_type = path
|
||||
.symlink_metadata()
|
||||
.map(|metadata| metadata.file_type())?;
|
||||
|
||||
// check if we're unlinking a symlink
|
||||
// NB this will get cleaned up a lot when [std::os::windows::fs::FileTypeExt]
|
||||
// stabilises
|
||||
//
|
||||
// [std::os::windows::fs::FileTypeExt]: https://doc.rust-lang.org/std/os/windows/fs/trait.FileTypeExt.html
|
||||
if file_type.is_symlink() {
|
||||
fs::remove_file(&path).or_else(|e| {
|
||||
match e.raw_os_error() {
|
||||
Some(e) => {
|
||||
log::debug!("path_unlink_file at symlink_file error code={:?}", e);
|
||||
match WinError::from_u32(e as u32) {
|
||||
WinError::ERROR_ACCESS_DENIED => {
|
||||
// try unlinking a dir symlink instead
|
||||
fs::remove_dir(path).map_err(Into::into)
|
||||
}
|
||||
e => Err(e.into()),
|
||||
}
|
||||
}
|
||||
None => {
|
||||
log::debug!("Inconvertible OS error: {}", e);
|
||||
Err(Error::EIO)
|
||||
}
|
||||
}
|
||||
})
|
||||
} else if file_type.is_dir() {
|
||||
Err(Error::EISDIR)
|
||||
} else if file_type.is_file() {
|
||||
fs::remove_file(path).map_err(Into::into)
|
||||
} else {
|
||||
Err(Error::EINVAL)
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn path_remove_directory(resolved: PathGet) -> Result<()> {
|
||||
let path = resolved.concatenate()?;
|
||||
std::fs::remove_dir(&path).map_err(Into::into)
|
||||
}
|
||||
@@ -0,0 +1,149 @@
|
||||
#![allow(non_camel_case_types)]
|
||||
use crate::old::snapshot_0::hostcalls_impl::PathGet;
|
||||
use crate::old::snapshot_0::{wasi, Error, Result};
|
||||
use std::ffi::{OsStr, OsString};
|
||||
use std::fs::File;
|
||||
use std::os::windows::ffi::{OsStrExt, OsStringExt};
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
pub(crate) trait PathGetExt {
|
||||
fn concatenate(&self) -> Result<PathBuf>;
|
||||
}
|
||||
|
||||
impl PathGetExt for PathGet {
|
||||
fn concatenate(&self) -> Result<PathBuf> {
|
||||
concatenate(self.dirfd(), Path::new(self.path()))
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn path_open_rights(
|
||||
rights_base: wasi::__wasi_rights_t,
|
||||
rights_inheriting: wasi::__wasi_rights_t,
|
||||
oflags: wasi::__wasi_oflags_t,
|
||||
fdflags: wasi::__wasi_fdflags_t,
|
||||
) -> (wasi::__wasi_rights_t, wasi::__wasi_rights_t) {
|
||||
// which rights are needed on the dirfd?
|
||||
let mut needed_base = wasi::__WASI_RIGHTS_PATH_OPEN;
|
||||
let mut needed_inheriting = rights_base | rights_inheriting;
|
||||
|
||||
// convert open flags
|
||||
if oflags & wasi::__WASI_OFLAGS_CREAT != 0 {
|
||||
needed_base |= wasi::__WASI_RIGHTS_PATH_CREATE_FILE;
|
||||
} else if oflags & wasi::__WASI_OFLAGS_TRUNC != 0 {
|
||||
needed_base |= wasi::__WASI_RIGHTS_PATH_FILESTAT_SET_SIZE;
|
||||
}
|
||||
|
||||
// convert file descriptor flags
|
||||
if fdflags & wasi::__WASI_FDFLAGS_DSYNC != 0
|
||||
|| fdflags & wasi::__WASI_FDFLAGS_RSYNC != 0
|
||||
|| fdflags & wasi::__WASI_FDFLAGS_SYNC != 0
|
||||
{
|
||||
needed_inheriting |= wasi::__WASI_RIGHTS_FD_DATASYNC;
|
||||
needed_inheriting |= wasi::__WASI_RIGHTS_FD_SYNC;
|
||||
}
|
||||
|
||||
(needed_base, needed_inheriting)
|
||||
}
|
||||
|
||||
pub(crate) fn openat(dirfd: &File, path: &str) -> Result<File> {
|
||||
use std::fs::OpenOptions;
|
||||
use std::os::windows::fs::OpenOptionsExt;
|
||||
use winx::file::Flags;
|
||||
use winx::winerror::WinError;
|
||||
|
||||
let path = concatenate(dirfd, Path::new(path))?;
|
||||
OpenOptions::new()
|
||||
.read(true)
|
||||
.custom_flags(Flags::FILE_FLAG_BACKUP_SEMANTICS.bits())
|
||||
.open(&path)
|
||||
.map_err(|e| match e.raw_os_error() {
|
||||
Some(e) => {
|
||||
log::debug!("openat error={:?}", e);
|
||||
match WinError::from_u32(e as u32) {
|
||||
WinError::ERROR_INVALID_NAME => Error::ENOTDIR,
|
||||
e => e.into(),
|
||||
}
|
||||
}
|
||||
None => {
|
||||
log::debug!("Inconvertible OS error: {}", e);
|
||||
Error::EIO
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn readlinkat(dirfd: &File, s_path: &str) -> Result<String> {
|
||||
use winx::file::get_file_path;
|
||||
use winx::winerror::WinError;
|
||||
|
||||
let path = concatenate(dirfd, Path::new(s_path))?;
|
||||
match path.read_link() {
|
||||
Ok(target_path) => {
|
||||
// since on Windows we are effectively emulating 'at' syscalls
|
||||
// we need to strip the prefix from the absolute path
|
||||
// as otherwise we will error out since WASI is not capable
|
||||
// of dealing with absolute paths
|
||||
let dir_path = get_file_path(dirfd)?;
|
||||
let dir_path = PathBuf::from(strip_extended_prefix(dir_path));
|
||||
target_path
|
||||
.strip_prefix(dir_path)
|
||||
.map_err(|_| Error::ENOTCAPABLE)
|
||||
.and_then(|path| path.to_str().map(String::from).ok_or(Error::EILSEQ))
|
||||
}
|
||||
Err(e) => match e.raw_os_error() {
|
||||
Some(e) => {
|
||||
log::debug!("readlinkat error={:?}", e);
|
||||
match WinError::from_u32(e as u32) {
|
||||
WinError::ERROR_INVALID_NAME => {
|
||||
if s_path.ends_with('/') {
|
||||
// strip "/" and check if exists
|
||||
let path = concatenate(dirfd, Path::new(s_path.trim_end_matches('/')))?;
|
||||
if path.exists() && !path.is_dir() {
|
||||
Err(Error::ENOTDIR)
|
||||
} else {
|
||||
Err(Error::ENOENT)
|
||||
}
|
||||
} else {
|
||||
Err(Error::ENOENT)
|
||||
}
|
||||
}
|
||||
e => Err(e.into()),
|
||||
}
|
||||
}
|
||||
None => {
|
||||
log::debug!("Inconvertible OS error: {}", e);
|
||||
Err(Error::EIO)
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn strip_extended_prefix<P: AsRef<OsStr>>(path: P) -> OsString {
|
||||
let path: Vec<u16> = path.as_ref().encode_wide().collect();
|
||||
if &[92, 92, 63, 92] == &path[0..4] {
|
||||
OsString::from_wide(&path[4..])
|
||||
} else {
|
||||
OsString::from_wide(&path)
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn concatenate<P: AsRef<Path>>(dirfd: &File, path: P) -> Result<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);
|
||||
}
|
||||
|
||||
let dir_path = get_file_path(dirfd)?;
|
||||
// concatenate paths
|
||||
let mut out_path = PathBuf::from(dir_path);
|
||||
out_path.push(path.as_ref());
|
||||
// strip extended prefix; otherwise we will error out on any relative
|
||||
// components with `out_path`
|
||||
let out_path = PathBuf::from(strip_extended_prefix(out_path));
|
||||
|
||||
log::debug!("out_path={:?}", out_path);
|
||||
|
||||
Ok(out_path)
|
||||
}
|
||||
@@ -0,0 +1,119 @@
|
||||
#![allow(non_camel_case_types)]
|
||||
#![allow(unused_unsafe)]
|
||||
#![allow(unused)]
|
||||
use crate::old::snapshot_0::helpers::systemtime_to_timestamp;
|
||||
use crate::old::snapshot_0::hostcalls_impl::{ClockEventData, FdEventData};
|
||||
use crate::old::snapshot_0::memory::*;
|
||||
use crate::old::snapshot_0::sys::host_impl;
|
||||
use crate::old::snapshot_0::{wasi, wasi32, Error, Result};
|
||||
use cpu_time::{ProcessTime, ThreadTime};
|
||||
use lazy_static::lazy_static;
|
||||
use std::convert::TryInto;
|
||||
use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH};
|
||||
|
||||
lazy_static! {
|
||||
static ref START_MONOTONIC: Instant = Instant::now();
|
||||
static ref PERF_COUNTER_RES: u64 = get_perf_counter_resolution_ns();
|
||||
}
|
||||
|
||||
// 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> {
|
||||
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
|
||||
// 10ms or 55ms, [1] but MSDN doesn't confirm this in any way.
|
||||
// Even the MSDN article on high resolution timestamps doesn't even mention the precision
|
||||
// for this method. [3]
|
||||
//
|
||||
// The timer resolution can be queried using one of the functions: [2, 5]
|
||||
// * NtQueryTimerResolution, which is undocumented and thus not exposed by the winapi crate
|
||||
// * timeGetDevCaps, which returns the upper and lower bound for the precision, in ms.
|
||||
// While the upper bound seems like something we could use, it's typically too high to be meaningful.
|
||||
// For instance, the intervals return by the syscall are:
|
||||
// * [1, 65536] on Wine
|
||||
// * [1, 1000000] on Windows 10, which is up to (sic) 1000 seconds.
|
||||
//
|
||||
// It's possible to manually set the timer resolution, but this sounds like something which should
|
||||
// only be done temporarily. [5]
|
||||
//
|
||||
// Alternatively, we could possibly use GetSystemTimePreciseAsFileTime in clock_time_get, but
|
||||
// this syscall is only available starting from Windows 8.
|
||||
// (we could possibly emulate it on earlier versions of Windows, see [4])
|
||||
// The MSDN are not clear on the resolution of GetSystemTimePreciseAsFileTime either, but a
|
||||
// Microsoft devblog entry [1] suggests that it kind of combines GetSystemTimeAsFileTime with
|
||||
// QueryPeformanceCounter, which probably means that those two should have the same resolution.
|
||||
//
|
||||
// See also this discussion about the use of GetSystemTimePreciseAsFileTime in Python stdlib,
|
||||
// which in particular contains some resolution benchmarks.
|
||||
//
|
||||
// [1] https://devblogs.microsoft.com/oldnewthing/20170921-00/?p=97057
|
||||
// [2] http://www.windowstimestamp.com/description
|
||||
// [3] https://docs.microsoft.com/en-us/windows/win32/sysinfo/acquiring-high-resolution-time-stamps?redirectedfrom=MSDN
|
||||
// [4] https://www.codeproject.com/Tips/1011902/High-Resolution-Time-For-Windows
|
||||
// [5] https://stackoverflow.com/questions/7685762/windows-7-timing-functions-how-to-use-getsystemtimeadjustment-correctly
|
||||
// [6] https://bugs.python.org/issue19007
|
||||
wasi::__WASI_CLOCKID_REALTIME => 55_000_000,
|
||||
// std::time::Instant uses QueryPerformanceCounter & QueryPerformanceFrequency internally
|
||||
wasi::__WASI_CLOCKID_MONOTONIC => *PERF_COUNTER_RES,
|
||||
// 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-getprocesstimes
|
||||
wasi::__WASI_CLOCKID_PROCESS_CPUTIME_ID => 100,
|
||||
// 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),
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn clock_time_get(clock_id: wasi::__wasi_clockid_t) -> Result<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),
|
||||
};
|
||||
duration.as_nanos().try_into().map_err(Into::into)
|
||||
}
|
||||
|
||||
pub(crate) fn poll_oneoff(
|
||||
timeout: Option<ClockEventData>,
|
||||
fd_events: Vec<FdEventData>,
|
||||
events: &mut Vec<wasi::__wasi_event_t>,
|
||||
) -> Result<Vec<wasi::__wasi_event_t>> {
|
||||
unimplemented!("poll_oneoff")
|
||||
}
|
||||
|
||||
fn get_monotonic_time() -> Duration {
|
||||
// We're circumventing the fact that we can't get a Duration from an Instant
|
||||
// The epoch of __WASI_CLOCKID_MONOTONIC is undefined, so we fix a time point once
|
||||
// and count relative to this time point.
|
||||
//
|
||||
// The alternative would be to copy over the implementation of std::time::Instant
|
||||
// to our source tree and add a conversion to std::time::Duration
|
||||
START_MONOTONIC.elapsed()
|
||||
}
|
||||
|
||||
fn get_realtime_time() -> Result<Duration> {
|
||||
SystemTime::now()
|
||||
.duration_since(UNIX_EPOCH)
|
||||
.map_err(|_| Error::EFAULT)
|
||||
}
|
||||
|
||||
fn get_proc_cputime() -> Result<Duration> {
|
||||
Ok(ProcessTime::try_now()?.as_duration())
|
||||
}
|
||||
|
||||
fn get_thread_cputime() -> Result<Duration> {
|
||||
Ok(ThreadTime::try_now()?.as_duration())
|
||||
}
|
||||
|
||||
fn get_perf_counter_resolution_ns() -> u64 {
|
||||
use winx::time::perf_counter_frequency;
|
||||
const NANOS_PER_SEC: u64 = 1_000_000_000;
|
||||
// This should always succeed starting from Windows XP, so it's fine to panic in case of an error.
|
||||
let freq = perf_counter_frequency().expect("QueryPerformanceFrequency returned an error");
|
||||
let epsilon = NANOS_PER_SEC / freq;
|
||||
epsilon
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
//! Windows-specific hostcalls that implement
|
||||
//! [WASI](https://github.com/bytecodealliance/wasmtime-wasi/blob/wasi/docs/WASI-overview.md).
|
||||
mod fs;
|
||||
pub(crate) mod fs_helpers;
|
||||
mod misc;
|
||||
|
||||
pub(crate) use self::fs::*;
|
||||
pub(crate) use self::misc::*;
|
||||
32
crates/wasi-common/src/old/snapshot_0/sys/windows/mod.rs
Normal file
32
crates/wasi-common/src/old/snapshot_0/sys/windows/mod.rs
Normal file
@@ -0,0 +1,32 @@
|
||||
pub(crate) mod fdentry_impl;
|
||||
pub(crate) mod host_impl;
|
||||
pub(crate) mod hostcalls_impl;
|
||||
|
||||
use crate::old::snapshot_0::Result;
|
||||
use std::fs::{File, OpenOptions};
|
||||
use std::path::Path;
|
||||
|
||||
pub(crate) fn dev_null() -> Result<File> {
|
||||
OpenOptions::new()
|
||||
.read(true)
|
||||
.write(true)
|
||||
.open("NUL")
|
||||
.map_err(Into::into)
|
||||
}
|
||||
|
||||
pub fn preopen_dir<P: AsRef<Path>>(path: P) -> Result<File> {
|
||||
use std::fs::OpenOptions;
|
||||
use std::os::windows::fs::OpenOptionsExt;
|
||||
use winapi::um::winbase::FILE_FLAG_BACKUP_SEMANTICS;
|
||||
|
||||
// To open a directory using CreateFile, specify the
|
||||
// FILE_FLAG_BACKUP_SEMANTICS flag as part of dwFileFlags...
|
||||
// cf. https://docs.microsoft.com/en-us/windows/desktop/api/fileapi/nf-fileapi-createfile2
|
||||
OpenOptions::new()
|
||||
.create(false)
|
||||
.write(true)
|
||||
.read(true)
|
||||
.attributes(FILE_FLAG_BACKUP_SEMANTICS)
|
||||
.open(path)
|
||||
.map_err(Into::into)
|
||||
}
|
||||
957
crates/wasi-common/src/old/snapshot_0/wasi.rs
Normal file
957
crates/wasi-common/src/old/snapshot_0/wasi.rs
Normal file
@@ -0,0 +1,957 @@
|
||||
//! Types and constants shared between 32-bit and 64-bit wasi. Types involving
|
||||
//! pointer or `usize`-sized data are excluded here, so this file only contains
|
||||
//! fixed-size types, so it's host/target independent.
|
||||
|
||||
#![allow(non_camel_case_types)]
|
||||
#![allow(non_snake_case)]
|
||||
#![allow(dead_code)]
|
||||
|
||||
use wig::witx_wasi_types;
|
||||
|
||||
witx_wasi_types!("old/snapshot_0" "wasi_unstable");
|
||||
|
||||
pub(crate) const RIGHTS_ALL: __wasi_rights_t = __WASI_RIGHTS_FD_DATASYNC
|
||||
| __WASI_RIGHTS_FD_READ
|
||||
| __WASI_RIGHTS_FD_SEEK
|
||||
| __WASI_RIGHTS_FD_FDSTAT_SET_FLAGS
|
||||
| __WASI_RIGHTS_FD_SYNC
|
||||
| __WASI_RIGHTS_FD_TELL
|
||||
| __WASI_RIGHTS_FD_WRITE
|
||||
| __WASI_RIGHTS_FD_ADVISE
|
||||
| __WASI_RIGHTS_FD_ALLOCATE
|
||||
| __WASI_RIGHTS_PATH_CREATE_DIRECTORY
|
||||
| __WASI_RIGHTS_PATH_CREATE_FILE
|
||||
| __WASI_RIGHTS_PATH_LINK_SOURCE
|
||||
| __WASI_RIGHTS_PATH_LINK_TARGET
|
||||
| __WASI_RIGHTS_PATH_OPEN
|
||||
| __WASI_RIGHTS_FD_READDIR
|
||||
| __WASI_RIGHTS_PATH_READLINK
|
||||
| __WASI_RIGHTS_PATH_RENAME_SOURCE
|
||||
| __WASI_RIGHTS_PATH_RENAME_TARGET
|
||||
| __WASI_RIGHTS_PATH_FILESTAT_GET
|
||||
| __WASI_RIGHTS_PATH_FILESTAT_SET_SIZE
|
||||
| __WASI_RIGHTS_PATH_FILESTAT_SET_TIMES
|
||||
| __WASI_RIGHTS_FD_FILESTAT_GET
|
||||
| __WASI_RIGHTS_FD_FILESTAT_SET_SIZE
|
||||
| __WASI_RIGHTS_FD_FILESTAT_SET_TIMES
|
||||
| __WASI_RIGHTS_PATH_SYMLINK
|
||||
| __WASI_RIGHTS_PATH_UNLINK_FILE
|
||||
| __WASI_RIGHTS_PATH_REMOVE_DIRECTORY
|
||||
| __WASI_RIGHTS_POLL_FD_READWRITE
|
||||
| __WASI_RIGHTS_SOCK_SHUTDOWN;
|
||||
|
||||
// Block and character device interaction is outside the scope of
|
||||
// WASI. Simply allow everything.
|
||||
pub(crate) const RIGHTS_BLOCK_DEVICE_BASE: __wasi_rights_t = RIGHTS_ALL;
|
||||
pub(crate) const RIGHTS_BLOCK_DEVICE_INHERITING: __wasi_rights_t = RIGHTS_ALL;
|
||||
pub(crate) const RIGHTS_CHARACTER_DEVICE_BASE: __wasi_rights_t = RIGHTS_ALL;
|
||||
pub(crate) const RIGHTS_CHARACTER_DEVICE_INHERITING: __wasi_rights_t = RIGHTS_ALL;
|
||||
|
||||
// Only allow directory operations on directories. Directories can only
|
||||
// yield file descriptors to other directories and files.
|
||||
pub(crate) const RIGHTS_DIRECTORY_BASE: __wasi_rights_t = __WASI_RIGHTS_FD_FDSTAT_SET_FLAGS
|
||||
| __WASI_RIGHTS_FD_SYNC
|
||||
| __WASI_RIGHTS_FD_ADVISE
|
||||
| __WASI_RIGHTS_PATH_CREATE_DIRECTORY
|
||||
| __WASI_RIGHTS_PATH_CREATE_FILE
|
||||
| __WASI_RIGHTS_PATH_LINK_SOURCE
|
||||
| __WASI_RIGHTS_PATH_LINK_TARGET
|
||||
| __WASI_RIGHTS_PATH_OPEN
|
||||
| __WASI_RIGHTS_FD_READDIR
|
||||
| __WASI_RIGHTS_PATH_READLINK
|
||||
| __WASI_RIGHTS_PATH_RENAME_SOURCE
|
||||
| __WASI_RIGHTS_PATH_RENAME_TARGET
|
||||
| __WASI_RIGHTS_PATH_FILESTAT_GET
|
||||
| __WASI_RIGHTS_PATH_FILESTAT_SET_SIZE
|
||||
| __WASI_RIGHTS_PATH_FILESTAT_SET_TIMES
|
||||
| __WASI_RIGHTS_FD_FILESTAT_GET
|
||||
| __WASI_RIGHTS_FD_FILESTAT_SET_TIMES
|
||||
| __WASI_RIGHTS_PATH_SYMLINK
|
||||
| __WASI_RIGHTS_PATH_UNLINK_FILE
|
||||
| __WASI_RIGHTS_PATH_REMOVE_DIRECTORY
|
||||
| __WASI_RIGHTS_POLL_FD_READWRITE;
|
||||
pub(crate) const RIGHTS_DIRECTORY_INHERITING: __wasi_rights_t =
|
||||
RIGHTS_DIRECTORY_BASE | RIGHTS_REGULAR_FILE_BASE;
|
||||
|
||||
// Operations that apply to regular files.
|
||||
pub(crate) const RIGHTS_REGULAR_FILE_BASE: __wasi_rights_t = __WASI_RIGHTS_FD_DATASYNC
|
||||
| __WASI_RIGHTS_FD_READ
|
||||
| __WASI_RIGHTS_FD_SEEK
|
||||
| __WASI_RIGHTS_FD_FDSTAT_SET_FLAGS
|
||||
| __WASI_RIGHTS_FD_SYNC
|
||||
| __WASI_RIGHTS_FD_TELL
|
||||
| __WASI_RIGHTS_FD_WRITE
|
||||
| __WASI_RIGHTS_FD_ADVISE
|
||||
| __WASI_RIGHTS_FD_ALLOCATE
|
||||
| __WASI_RIGHTS_FD_FILESTAT_GET
|
||||
| __WASI_RIGHTS_FD_FILESTAT_SET_SIZE
|
||||
| __WASI_RIGHTS_FD_FILESTAT_SET_TIMES
|
||||
| __WASI_RIGHTS_POLL_FD_READWRITE;
|
||||
pub(crate) const RIGHTS_REGULAR_FILE_INHERITING: __wasi_rights_t = 0;
|
||||
|
||||
// Operations that apply to sockets and socket pairs.
|
||||
pub(crate) const RIGHTS_SOCKET_BASE: __wasi_rights_t = __WASI_RIGHTS_FD_READ
|
||||
| __WASI_RIGHTS_FD_FDSTAT_SET_FLAGS
|
||||
| __WASI_RIGHTS_FD_WRITE
|
||||
| __WASI_RIGHTS_FD_FILESTAT_GET
|
||||
| __WASI_RIGHTS_POLL_FD_READWRITE
|
||||
| __WASI_RIGHTS_SOCK_SHUTDOWN;
|
||||
pub(crate) const RIGHTS_SOCKET_INHERITING: __wasi_rights_t = RIGHTS_ALL;
|
||||
|
||||
// Operations that apply to TTYs.
|
||||
pub(crate) const RIGHTS_TTY_BASE: __wasi_rights_t = __WASI_RIGHTS_FD_READ
|
||||
| __WASI_RIGHTS_FD_FDSTAT_SET_FLAGS
|
||||
| __WASI_RIGHTS_FD_WRITE
|
||||
| __WASI_RIGHTS_FD_FILESTAT_GET
|
||||
| __WASI_RIGHTS_POLL_FD_READWRITE;
|
||||
#[allow(unused)]
|
||||
pub(crate) const RIGHTS_TTY_INHERITING: __wasi_rights_t = 0;
|
||||
|
||||
pub fn strerror(errno: __wasi_errno_t) -> &'static str {
|
||||
match errno {
|
||||
__WASI_ERRNO_SUCCESS => "__WASI_ERRNO_SUCCESS",
|
||||
__WASI_ERRNO_2BIG => "__WASI_ERRNO_2BIG",
|
||||
__WASI_ERRNO_ACCES => "__WASI_ERRNO_ACCES",
|
||||
__WASI_ERRNO_ADDRINUSE => "__WASI_ERRNO_ADDRINUSE",
|
||||
__WASI_ERRNO_ADDRNOTAVAIL => "__WASI_ERRNO_ADDRNOTAVAIL",
|
||||
__WASI_ERRNO_AFNOSUPPORT => "__WASI_ERRNO_AFNOSUPPORT",
|
||||
__WASI_ERRNO_AGAIN => "__WASI_ERRNO_AGAIN",
|
||||
__WASI_ERRNO_ALREADY => "__WASI_ERRNO_ALREADY",
|
||||
__WASI_ERRNO_BADF => "__WASI_ERRNO_BADF",
|
||||
__WASI_ERRNO_BADMSG => "__WASI_ERRNO_BADMSG",
|
||||
__WASI_ERRNO_BUSY => "__WASI_ERRNO_BUSY",
|
||||
__WASI_ERRNO_CANCELED => "__WASI_ERRNO_CANCELED",
|
||||
__WASI_ERRNO_CHILD => "__WASI_ERRNO_CHILD",
|
||||
__WASI_ERRNO_CONNABORTED => "__WASI_ERRNO_CONNABORTED",
|
||||
__WASI_ERRNO_CONNREFUSED => "__WASI_ERRNO_CONNREFUSED",
|
||||
__WASI_ERRNO_CONNRESET => "__WASI_ERRNO_CONNRESET",
|
||||
__WASI_ERRNO_DEADLK => "__WASI_ERRNO_DEADLK",
|
||||
__WASI_ERRNO_DESTADDRREQ => "__WASI_ERRNO_DESTADDRREQ",
|
||||
__WASI_ERRNO_DOM => "__WASI_ERRNO_DOM",
|
||||
__WASI_ERRNO_DQUOT => "__WASI_ERRNO_DQUOT",
|
||||
__WASI_ERRNO_EXIST => "__WASI_ERRNO_EXIST",
|
||||
__WASI_ERRNO_FAULT => "__WASI_ERRNO_FAULT",
|
||||
__WASI_ERRNO_FBIG => "__WASI_ERRNO_FBIG",
|
||||
__WASI_ERRNO_HOSTUNREACH => "__WASI_ERRNO_HOSTUNREACH",
|
||||
__WASI_ERRNO_IDRM => "__WASI_ERRNO_IDRM",
|
||||
__WASI_ERRNO_ILSEQ => "__WASI_ERRNO_ILSEQ",
|
||||
__WASI_ERRNO_INPROGRESS => "__WASI_ERRNO_INPROGRESS",
|
||||
__WASI_ERRNO_INTR => "__WASI_ERRNO_INTR",
|
||||
__WASI_ERRNO_INVAL => "__WASI_ERRNO_INVAL",
|
||||
__WASI_ERRNO_IO => "__WASI_ERRNO_IO",
|
||||
__WASI_ERRNO_ISCONN => "__WASI_ERRNO_ISCONN",
|
||||
__WASI_ERRNO_ISDIR => "__WASI_ERRNO_ISDIR",
|
||||
__WASI_ERRNO_LOOP => "__WASI_ERRNO_LOOP",
|
||||
__WASI_ERRNO_MFILE => "__WASI_ERRNO_MFILE",
|
||||
__WASI_ERRNO_MLINK => "__WASI_ERRNO_MLINK",
|
||||
__WASI_ERRNO_MSGSIZE => "__WASI_ERRNO_MSGSIZE",
|
||||
__WASI_ERRNO_MULTIHOP => "__WASI_ERRNO_MULTIHOP",
|
||||
__WASI_ERRNO_NAMETOOLONG => "__WASI_ERRNO_NAMETOOLONG",
|
||||
__WASI_ERRNO_NETDOWN => "__WASI_ERRNO_NETDOWN",
|
||||
__WASI_ERRNO_NETRESET => "__WASI_ERRNO_NETRESET",
|
||||
__WASI_ERRNO_NETUNREACH => "__WASI_ERRNO_NETUNREACH",
|
||||
__WASI_ERRNO_NFILE => "__WASI_ERRNO_NFILE",
|
||||
__WASI_ERRNO_NOBUFS => "__WASI_ERRNO_NOBUFS",
|
||||
__WASI_ERRNO_NODEV => "__WASI_ERRNO_NODEV",
|
||||
__WASI_ERRNO_NOENT => "__WASI_ERRNO_NOENT",
|
||||
__WASI_ERRNO_NOEXEC => "__WASI_ERRNO_NOEXEC",
|
||||
__WASI_ERRNO_NOLCK => "__WASI_ERRNO_NOLCK",
|
||||
__WASI_ERRNO_NOLINK => "__WASI_ERRNO_NOLINK",
|
||||
__WASI_ERRNO_NOMEM => "__WASI_ERRNO_NOMEM",
|
||||
__WASI_ERRNO_NOMSG => "__WASI_ERRNO_NOMSG",
|
||||
__WASI_ERRNO_NOPROTOOPT => "__WASI_ERRNO_NOPROTOOPT",
|
||||
__WASI_ERRNO_NOSPC => "__WASI_ERRNO_NOSPC",
|
||||
__WASI_ERRNO_NOSYS => "__WASI_ERRNO_NOSYS",
|
||||
__WASI_ERRNO_NOTCONN => "__WASI_ERRNO_NOTCONN",
|
||||
__WASI_ERRNO_NOTDIR => "__WASI_ERRNO_NOTDIR",
|
||||
__WASI_ERRNO_NOTEMPTY => "__WASI_ERRNO_NOTEMPTY",
|
||||
__WASI_ERRNO_NOTRECOVERABLE => "__WASI_ERRNO_NOTRECOVERABLE",
|
||||
__WASI_ERRNO_NOTSOCK => "__WASI_ERRNO_NOTSOCK",
|
||||
__WASI_ERRNO_NOTSUP => "__WASI_ERRNO_NOTSUP",
|
||||
__WASI_ERRNO_NOTTY => "__WASI_ERRNO_NOTTY",
|
||||
__WASI_ERRNO_NXIO => "__WASI_ERRNO_NXIO",
|
||||
__WASI_ERRNO_OVERFLOW => "__WASI_ERRNO_OVERFLOW",
|
||||
__WASI_ERRNO_OWNERDEAD => "__WASI_ERRNO_OWNERDEAD",
|
||||
__WASI_ERRNO_PERM => "__WASI_ERRNO_PERM",
|
||||
__WASI_ERRNO_PIPE => "__WASI_ERRNO_PIPE",
|
||||
__WASI_ERRNO_PROTO => "__WASI_ERRNO_PROTO",
|
||||
__WASI_ERRNO_PROTONOSUPPORT => "__WASI_ERRNO_PROTONOSUPPORT",
|
||||
__WASI_ERRNO_PROTOTYPE => "__WASI_ERRNO_PROTOTYPE",
|
||||
__WASI_ERRNO_RANGE => "__WASI_ERRNO_RANGE",
|
||||
__WASI_ERRNO_ROFS => "__WASI_ERRNO_ROFS",
|
||||
__WASI_ERRNO_SPIPE => "__WASI_ERRNO_SPIPE",
|
||||
__WASI_ERRNO_SRCH => "__WASI_ERRNO_SRCH",
|
||||
__WASI_ERRNO_STALE => "__WASI_ERRNO_STALE",
|
||||
__WASI_ERRNO_TIMEDOUT => "__WASI_ERRNO_TIMEDOUT",
|
||||
__WASI_ERRNO_TXTBSY => "__WASI_ERRNO_TXTBSY",
|
||||
__WASI_ERRNO_XDEV => "__WASI_ERRNO_XDEV",
|
||||
__WASI_ERRNO_NOTCAPABLE => "__WASI_ERRNO_NOTCAPABLE",
|
||||
other => panic!("Undefined errno value {:?}", other),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn whence_to_str(whence: __wasi_whence_t) -> &'static str {
|
||||
match whence {
|
||||
__WASI_WHENCE_CUR => "__WASI_WHENCE_CUR",
|
||||
__WASI_WHENCE_END => "__WASI_WHENCE_END",
|
||||
__WASI_WHENCE_SET => "__WASI_WHENCE_SET",
|
||||
other => panic!("Undefined whence value {:?}", other),
|
||||
}
|
||||
}
|
||||
|
||||
pub const __WASI_DIRCOOKIE_START: __wasi_dircookie_t = 0;
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn bindgen_test_layout_wasi_dirent_t() {
|
||||
assert_eq!(
|
||||
::std::mem::size_of::<__wasi_dirent_t>(),
|
||||
24usize,
|
||||
concat!("Size of: ", stringify!(__wasi_dirent_t))
|
||||
);
|
||||
assert_eq!(
|
||||
unsafe { &(*(::std::ptr::null::<__wasi_dirent_t>())).d_next as *const _ as usize },
|
||||
0usize,
|
||||
concat!(
|
||||
"Offset of field: ",
|
||||
stringify!(__wasi_dirent_t),
|
||||
"::",
|
||||
stringify!(d_next)
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
unsafe { &(*(::std::ptr::null::<__wasi_dirent_t>())).d_ino as *const _ as usize },
|
||||
8usize,
|
||||
concat!(
|
||||
"Offset of field: ",
|
||||
stringify!(__wasi_dirent_t),
|
||||
"::",
|
||||
stringify!(d_ino)
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
unsafe { &(*(::std::ptr::null::<__wasi_dirent_t>())).d_namlen as *const _ as usize },
|
||||
16usize,
|
||||
concat!(
|
||||
"Offset of field: ",
|
||||
stringify!(__wasi_dirent_t),
|
||||
"::",
|
||||
stringify!(d_namlen)
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
unsafe { &(*(::std::ptr::null::<__wasi_dirent_t>())).d_type as *const _ as usize },
|
||||
20usize,
|
||||
concat!(
|
||||
"Offset of field: ",
|
||||
stringify!(__wasi_dirent_t),
|
||||
"::",
|
||||
stringify!(d_type)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn bindgen_test_layout___wasi_event_t___wasi_event_u___wasi_event_u_fd_readwrite_t() {
|
||||
assert_eq!(
|
||||
::std::mem::size_of::<__wasi_event_fd_readwrite_t>(),
|
||||
16usize,
|
||||
concat!("Size of: ", stringify!(__wasi_event_fd_readwrite_t))
|
||||
);
|
||||
assert_eq!(
|
||||
::std::mem::align_of::<__wasi_event_fd_readwrite_t>(),
|
||||
8usize,
|
||||
concat!("Alignment of ", stringify!(__wasi_event_fd_readwrite_t))
|
||||
);
|
||||
assert_eq!(
|
||||
unsafe {
|
||||
&(*(::std::ptr::null::<__wasi_event_fd_readwrite_t>())).nbytes as *const _ as usize
|
||||
},
|
||||
0usize,
|
||||
concat!(
|
||||
"Offset of field: ",
|
||||
stringify!(__wasi_event_fd_readwrite_t),
|
||||
"::",
|
||||
stringify!(nbytes)
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
unsafe {
|
||||
&(*(::std::ptr::null::<__wasi_event_fd_readwrite_t>())).flags as *const _ as usize
|
||||
},
|
||||
8usize,
|
||||
concat!(
|
||||
"Offset of field: ",
|
||||
stringify!(__wasi_event_fd_readwrite_t),
|
||||
"::",
|
||||
stringify!(flags)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn bindgen_test_layout___wasi_event_t___wasi_event_u() {
|
||||
assert_eq!(
|
||||
::std::mem::size_of::<__wasi_event_u_t>(),
|
||||
16usize,
|
||||
concat!("Size of: ", stringify!(__wasi_event_u_t))
|
||||
);
|
||||
assert_eq!(
|
||||
::std::mem::align_of::<__wasi_event_u_t>(),
|
||||
8usize,
|
||||
concat!("Alignment of ", stringify!(__wasi_event_u_t))
|
||||
);
|
||||
assert_eq!(
|
||||
unsafe {
|
||||
&(*(::std::ptr::null::<__wasi_event_u_t>())).fd_readwrite as *const _ as usize
|
||||
},
|
||||
0usize,
|
||||
concat!(
|
||||
"Offset of field: ",
|
||||
stringify!(__wasi_event_u_t),
|
||||
"::",
|
||||
stringify!(fd_readwrite)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn bindgen_test_layout___wasi_event_t() {
|
||||
assert_eq!(
|
||||
::std::mem::size_of::<__wasi_event_t>(),
|
||||
32usize,
|
||||
concat!("Size of: ", stringify!(__wasi_event_t))
|
||||
);
|
||||
assert_eq!(
|
||||
::std::mem::align_of::<__wasi_event_t>(),
|
||||
8usize,
|
||||
concat!("Alignment of ", stringify!(__wasi_event_t))
|
||||
);
|
||||
assert_eq!(
|
||||
unsafe { &(*(::std::ptr::null::<__wasi_event_t>())).userdata as *const _ as usize },
|
||||
0usize,
|
||||
concat!(
|
||||
"Offset of field: ",
|
||||
stringify!(__wasi_event_t),
|
||||
"::",
|
||||
stringify!(userdata)
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
unsafe { &(*(::std::ptr::null::<__wasi_event_t>())).error as *const _ as usize },
|
||||
8usize,
|
||||
concat!(
|
||||
"Offset of field: ",
|
||||
stringify!(__wasi_event_t),
|
||||
"::",
|
||||
stringify!(error)
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
unsafe { &(*(::std::ptr::null::<__wasi_event_t>())).r#type as *const _ as usize },
|
||||
10usize,
|
||||
concat!(
|
||||
"Offset of field: ",
|
||||
stringify!(__wasi_event_t),
|
||||
"::",
|
||||
stringify!(r#type)
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
unsafe { &(*(::std::ptr::null::<__wasi_event_t>())).u as *const _ as usize },
|
||||
16usize,
|
||||
concat!(
|
||||
"Offset of field: ",
|
||||
stringify!(__wasi_event_t),
|
||||
"::",
|
||||
stringify!(u)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn bindgen_test_layout_wasi_event_t() {
|
||||
assert_eq!(
|
||||
::std::mem::size_of::<__wasi_event_t>(),
|
||||
32usize,
|
||||
concat!("Size of: ", stringify!(__wasi_event_t))
|
||||
);
|
||||
assert_eq!(
|
||||
unsafe { &(*(::std::ptr::null::<__wasi_event_t>())).userdata as *const _ as usize },
|
||||
0usize,
|
||||
concat!(
|
||||
"Offset of field: ",
|
||||
stringify!(__wasi_event_t),
|
||||
"::",
|
||||
stringify!(userdata)
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
unsafe { &(*(::std::ptr::null::<__wasi_event_t>())).error as *const _ as usize },
|
||||
8usize,
|
||||
concat!(
|
||||
"Offset of field: ",
|
||||
stringify!(__wasi_event_t),
|
||||
"::",
|
||||
stringify!(error)
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
unsafe { &(*(::std::ptr::null::<__wasi_event_t>())).r#type as *const _ as usize },
|
||||
10usize,
|
||||
concat!(
|
||||
"Offset of field: ",
|
||||
stringify!(__wasi_event_t),
|
||||
"::",
|
||||
stringify!(r#type)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn bindgen_test_layout_wasi_fdstat_t() {
|
||||
assert_eq!(
|
||||
::std::mem::size_of::<__wasi_fdstat_t>(),
|
||||
24usize,
|
||||
concat!("Size of: ", stringify!(__wasi_fdstat_t))
|
||||
);
|
||||
assert_eq!(
|
||||
unsafe { &(*(::std::ptr::null::<__wasi_fdstat_t>())).fs_filetype as *const _ as usize },
|
||||
0usize,
|
||||
concat!(
|
||||
"Offset of field: ",
|
||||
stringify!(__wasi_fdstat_t),
|
||||
"::",
|
||||
stringify!(fs_filetype)
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
unsafe { &(*(::std::ptr::null::<__wasi_fdstat_t>())).fs_flags as *const _ as usize },
|
||||
2usize,
|
||||
concat!(
|
||||
"Offset of field: ",
|
||||
stringify!(__wasi_fdstat_t),
|
||||
"::",
|
||||
stringify!(fs_flags)
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
unsafe {
|
||||
&(*(::std::ptr::null::<__wasi_fdstat_t>())).fs_rights_base as *const _ as usize
|
||||
},
|
||||
8usize,
|
||||
concat!(
|
||||
"Offset of field: ",
|
||||
stringify!(__wasi_fdstat_t),
|
||||
"::",
|
||||
stringify!(fs_rights_base)
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
unsafe {
|
||||
&(*(::std::ptr::null::<__wasi_fdstat_t>())).fs_rights_inheriting as *const _
|
||||
as usize
|
||||
},
|
||||
16usize,
|
||||
concat!(
|
||||
"Offset of field: ",
|
||||
stringify!(__wasi_fdstat_t),
|
||||
"::",
|
||||
stringify!(fs_rights_inheriting)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn bindgen_test_layout_wasi_filestat_t() {
|
||||
assert_eq!(
|
||||
::std::mem::size_of::<__wasi_filestat_t>(),
|
||||
56usize,
|
||||
concat!("Size of: ", stringify!(__wasi_filestat_t))
|
||||
);
|
||||
assert_eq!(
|
||||
unsafe { &(*(::std::ptr::null::<__wasi_filestat_t>())).dev as *const _ as usize },
|
||||
0usize,
|
||||
concat!(
|
||||
"Offset of field: ",
|
||||
stringify!(__wasi_filestat_t),
|
||||
"::",
|
||||
stringify!(st_dev)
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
unsafe { &(*(::std::ptr::null::<__wasi_filestat_t>())).ino as *const _ as usize },
|
||||
8usize,
|
||||
concat!(
|
||||
"Offset of field: ",
|
||||
stringify!(__wasi_filestat_t),
|
||||
"::",
|
||||
stringify!(st_ino)
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
unsafe { &(*(::std::ptr::null::<__wasi_filestat_t>())).filetype as *const _ as usize },
|
||||
16usize,
|
||||
concat!(
|
||||
"Offset of field: ",
|
||||
stringify!(__wasi_filestat_t),
|
||||
"::",
|
||||
stringify!(st_filetype)
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
unsafe { &(*(::std::ptr::null::<__wasi_filestat_t>())).nlink as *const _ as usize },
|
||||
20usize,
|
||||
concat!(
|
||||
"Offset of field: ",
|
||||
stringify!(__wasi_filestat_t),
|
||||
"::",
|
||||
stringify!(st_nlink)
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
unsafe { &(*(::std::ptr::null::<__wasi_filestat_t>())).size as *const _ as usize },
|
||||
24usize,
|
||||
concat!(
|
||||
"Offset of field: ",
|
||||
stringify!(__wasi_filestat_t),
|
||||
"::",
|
||||
stringify!(st_size)
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
unsafe { &(*(::std::ptr::null::<__wasi_filestat_t>())).atim as *const _ as usize },
|
||||
32usize,
|
||||
concat!(
|
||||
"Offset of field: ",
|
||||
stringify!(__wasi_filestat_t),
|
||||
"::",
|
||||
stringify!(st_atim)
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
unsafe { &(*(::std::ptr::null::<__wasi_filestat_t>())).mtim as *const _ as usize },
|
||||
40usize,
|
||||
concat!(
|
||||
"Offset of field: ",
|
||||
stringify!(__wasi_filestat_t),
|
||||
"::",
|
||||
stringify!(st_mtim)
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
unsafe { &(*(::std::ptr::null::<__wasi_filestat_t>())).ctim as *const _ as usize },
|
||||
48usize,
|
||||
concat!(
|
||||
"Offset of field: ",
|
||||
stringify!(__wasi_filestat_t),
|
||||
"::",
|
||||
stringify!(st_ctim)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn bindgen_test_layout___wasi_subscription_clock_t() {
|
||||
assert_eq!(
|
||||
::std::mem::size_of::<__wasi_subscription_clock_t>(),
|
||||
40usize,
|
||||
concat!("Size of: ", stringify!(__wasi_subscription_clock_t))
|
||||
);
|
||||
assert_eq!(
|
||||
::std::mem::align_of::<__wasi_subscription_clock_t>(),
|
||||
8usize,
|
||||
concat!("Alignment of ", stringify!(__wasi_subscription_clock_t))
|
||||
);
|
||||
assert_eq!(
|
||||
unsafe {
|
||||
&(*(::std::ptr::null::<__wasi_subscription_clock_t>())).identifier as *const _
|
||||
as usize
|
||||
},
|
||||
0usize,
|
||||
concat!(
|
||||
"Offset of field: ",
|
||||
stringify!(__wasi_subscription_clock_t),
|
||||
"::",
|
||||
stringify!(identifier)
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
unsafe {
|
||||
&(*(::std::ptr::null::<__wasi_subscription_clock_t>())).id as *const _ as usize
|
||||
},
|
||||
8usize,
|
||||
concat!(
|
||||
"Offset of field: ",
|
||||
stringify!(__wasi_subscription_clock_t),
|
||||
"::",
|
||||
stringify!(clock_id)
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
unsafe {
|
||||
&(*(::std::ptr::null::<__wasi_subscription_clock_t>())).timeout as *const _ as usize
|
||||
},
|
||||
16usize,
|
||||
concat!(
|
||||
"Offset of field: ",
|
||||
stringify!(__wasi_subscription_clock_t),
|
||||
"::",
|
||||
stringify!(timeout)
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
unsafe {
|
||||
&(*(::std::ptr::null::<__wasi_subscription_clock_t>())).precision as *const _
|
||||
as usize
|
||||
},
|
||||
24usize,
|
||||
concat!(
|
||||
"Offset of field: ",
|
||||
stringify!(__wasi_subscription_clock_t),
|
||||
"::",
|
||||
stringify!(precision)
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
unsafe {
|
||||
&(*(::std::ptr::null::<__wasi_subscription_clock_t>())).flags as *const _ as usize
|
||||
},
|
||||
32usize,
|
||||
concat!(
|
||||
"Offset of field: ",
|
||||
stringify!(__wasi_subscription_clock_t),
|
||||
"::",
|
||||
stringify!(flags)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn bindgen_test_layout___wasi_subscription_t___wasi_subscription_u___wasi_subscription_u_fd_readwrite_t(
|
||||
) {
|
||||
assert_eq!(
|
||||
::std::mem::size_of::<__wasi_subscription_fd_readwrite_t>(),
|
||||
4usize,
|
||||
concat!("Size of: ", stringify!(__wasi_subscription_fd_readwrite_t))
|
||||
);
|
||||
assert_eq!(
|
||||
::std::mem::align_of::<__wasi_subscription_fd_readwrite_t>(),
|
||||
4usize,
|
||||
concat!(
|
||||
"Alignment of ",
|
||||
stringify!(__wasi_subscription_fd_readwrite_t)
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
unsafe {
|
||||
&(*(::std::ptr::null::<__wasi_subscription_fd_readwrite_t>())).file_descriptor
|
||||
as *const _ as usize
|
||||
},
|
||||
0usize,
|
||||
concat!(
|
||||
"Offset of field: ",
|
||||
stringify!(__wasi_subscription_fd_readwrite_t),
|
||||
"::",
|
||||
stringify!(fd)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn bindgen_test_layout___wasi_subscription_t___wasi_subscription_u() {
|
||||
assert_eq!(
|
||||
::std::mem::size_of::<__wasi_subscription_u_t>(),
|
||||
40usize,
|
||||
concat!("Size of: ", stringify!(__wasi_subscription_u_t))
|
||||
);
|
||||
assert_eq!(
|
||||
::std::mem::align_of::<__wasi_subscription_u_t>(),
|
||||
8usize,
|
||||
concat!("Alignment of ", stringify!(__wasi_subscription_u_t))
|
||||
);
|
||||
assert_eq!(
|
||||
unsafe {
|
||||
&(*(::std::ptr::null::<__wasi_subscription_u_t>())).clock as *const _ as usize
|
||||
},
|
||||
0usize,
|
||||
concat!(
|
||||
"Offset of field: ",
|
||||
stringify!(__wasi_subscription_u_t),
|
||||
"::",
|
||||
stringify!(clock)
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
unsafe {
|
||||
&(*(::std::ptr::null::<__wasi_subscription_u_t>())).fd_readwrite as *const _
|
||||
as usize
|
||||
},
|
||||
0usize,
|
||||
concat!(
|
||||
"Offset of field: ",
|
||||
stringify!(__wasi_subscription_u_t),
|
||||
"::",
|
||||
stringify!(fd_readwrite)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn bindgen_test_layout___wasi_subscription_t() {
|
||||
assert_eq!(
|
||||
::std::mem::size_of::<__wasi_subscription_t>(),
|
||||
56usize,
|
||||
concat!("Size of: ", stringify!(__wasi_subscription_t))
|
||||
);
|
||||
assert_eq!(
|
||||
::std::mem::align_of::<__wasi_subscription_t>(),
|
||||
8usize,
|
||||
concat!("Alignment of ", stringify!(__wasi_subscription_t))
|
||||
);
|
||||
assert_eq!(
|
||||
unsafe {
|
||||
&(*(::std::ptr::null::<__wasi_subscription_t>())).userdata as *const _ as usize
|
||||
},
|
||||
0usize,
|
||||
concat!(
|
||||
"Offset of field: ",
|
||||
stringify!(__wasi_subscription_t),
|
||||
"::",
|
||||
stringify!(userdata)
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
unsafe {
|
||||
&(*(::std::ptr::null::<__wasi_subscription_t>())).r#type as *const _ as usize
|
||||
},
|
||||
8usize,
|
||||
concat!(
|
||||
"Offset of field: ",
|
||||
stringify!(__wasi_subscription_t),
|
||||
"::",
|
||||
stringify!(r#type)
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
unsafe { &(*(::std::ptr::null::<__wasi_subscription_t>())).u as *const _ as usize },
|
||||
16usize,
|
||||
concat!(
|
||||
"Offset of field: ",
|
||||
stringify!(__wasi_subscription_t),
|
||||
"::",
|
||||
stringify!(u)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn bindgen_test_layout___wasi_filestat_t() {
|
||||
assert_eq!(
|
||||
::std::mem::size_of::<__wasi_filestat_t>(),
|
||||
56usize,
|
||||
concat!("Size of: ", stringify!(__wasi_filestat_t))
|
||||
);
|
||||
assert_eq!(
|
||||
::std::mem::align_of::<__wasi_filestat_t>(),
|
||||
8usize,
|
||||
concat!("Alignment of ", stringify!(__wasi_filestat_t))
|
||||
);
|
||||
assert_eq!(
|
||||
unsafe { &(*(::std::ptr::null::<__wasi_filestat_t>())).dev as *const _ as usize },
|
||||
0usize,
|
||||
concat!(
|
||||
"Offset of field: ",
|
||||
stringify!(__wasi_filestat_t),
|
||||
"::",
|
||||
stringify!(st_dev)
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
unsafe { &(*(::std::ptr::null::<__wasi_filestat_t>())).ino as *const _ as usize },
|
||||
8usize,
|
||||
concat!(
|
||||
"Offset of field: ",
|
||||
stringify!(__wasi_filestat_t),
|
||||
"::",
|
||||
stringify!(st_ino)
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
unsafe { &(*(::std::ptr::null::<__wasi_filestat_t>())).filetype as *const _ as usize },
|
||||
16usize,
|
||||
concat!(
|
||||
"Offset of field: ",
|
||||
stringify!(__wasi_filestat_t),
|
||||
"::",
|
||||
stringify!(st_filetype)
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
unsafe { &(*(::std::ptr::null::<__wasi_filestat_t>())).nlink as *const _ as usize },
|
||||
20usize,
|
||||
concat!(
|
||||
"Offset of field: ",
|
||||
stringify!(__wasi_filestat_t),
|
||||
"::",
|
||||
stringify!(st_nlink)
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
unsafe { &(*(::std::ptr::null::<__wasi_filestat_t>())).size as *const _ as usize },
|
||||
24usize,
|
||||
concat!(
|
||||
"Offset of field: ",
|
||||
stringify!(__wasi_filestat_t),
|
||||
"::",
|
||||
stringify!(st_size)
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
unsafe { &(*(::std::ptr::null::<__wasi_filestat_t>())).atim as *const _ as usize },
|
||||
32usize,
|
||||
concat!(
|
||||
"Offset of field: ",
|
||||
stringify!(__wasi_filestat_t),
|
||||
"::",
|
||||
stringify!(st_atim)
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
unsafe { &(*(::std::ptr::null::<__wasi_filestat_t>())).mtim as *const _ as usize },
|
||||
40usize,
|
||||
concat!(
|
||||
"Offset of field: ",
|
||||
stringify!(__wasi_filestat_t),
|
||||
"::",
|
||||
stringify!(st_mtim)
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
unsafe { &(*(::std::ptr::null::<__wasi_filestat_t>())).ctim as *const _ as usize },
|
||||
48usize,
|
||||
concat!(
|
||||
"Offset of field: ",
|
||||
stringify!(__wasi_filestat_t),
|
||||
"::",
|
||||
stringify!(st_ctim)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn bindgen_test_layout___wasi_fdstat_t() {
|
||||
assert_eq!(
|
||||
::std::mem::size_of::<__wasi_fdstat_t>(),
|
||||
24usize,
|
||||
concat!("Size of: ", stringify!(__wasi_fdstat_t))
|
||||
);
|
||||
assert_eq!(
|
||||
::std::mem::align_of::<__wasi_fdstat_t>(),
|
||||
8usize,
|
||||
concat!("Alignment of ", stringify!(__wasi_fdstat_t))
|
||||
);
|
||||
assert_eq!(
|
||||
unsafe { &(*(::std::ptr::null::<__wasi_fdstat_t>())).fs_filetype as *const _ as usize },
|
||||
0usize,
|
||||
concat!(
|
||||
"Offset of field: ",
|
||||
stringify!(__wasi_fdstat_t),
|
||||
"::",
|
||||
stringify!(fs_filetype)
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
unsafe { &(*(::std::ptr::null::<__wasi_fdstat_t>())).fs_flags as *const _ as usize },
|
||||
2usize,
|
||||
concat!(
|
||||
"Offset of field: ",
|
||||
stringify!(__wasi_fdstat_t),
|
||||
"::",
|
||||
stringify!(fs_flags)
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
unsafe {
|
||||
&(*(::std::ptr::null::<__wasi_fdstat_t>())).fs_rights_base as *const _ as usize
|
||||
},
|
||||
8usize,
|
||||
concat!(
|
||||
"Offset of field: ",
|
||||
stringify!(__wasi_fdstat_t),
|
||||
"::",
|
||||
stringify!(fs_rights_base)
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
unsafe {
|
||||
&(*(::std::ptr::null::<__wasi_fdstat_t>())).fs_rights_inheriting as *const _
|
||||
as usize
|
||||
},
|
||||
16usize,
|
||||
concat!(
|
||||
"Offset of field: ",
|
||||
stringify!(__wasi_fdstat_t),
|
||||
"::",
|
||||
stringify!(fs_rights_inheriting)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn bindgen_test_layout___wasi_dirent_t() {
|
||||
assert_eq!(
|
||||
::std::mem::size_of::<__wasi_dirent_t>(),
|
||||
24usize,
|
||||
concat!("Size of: ", stringify!(__wasi_dirent_t))
|
||||
);
|
||||
assert_eq!(
|
||||
::std::mem::align_of::<__wasi_dirent_t>(),
|
||||
8usize,
|
||||
concat!("Alignment of ", stringify!(__wasi_dirent_t))
|
||||
);
|
||||
assert_eq!(
|
||||
unsafe { &(*(::std::ptr::null::<__wasi_dirent_t>())).d_next as *const _ as usize },
|
||||
0usize,
|
||||
concat!(
|
||||
"Offset of field: ",
|
||||
stringify!(__wasi_dirent_t),
|
||||
"::",
|
||||
stringify!(d_next)
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
unsafe { &(*(::std::ptr::null::<__wasi_dirent_t>())).d_ino as *const _ as usize },
|
||||
8usize,
|
||||
concat!(
|
||||
"Offset of field: ",
|
||||
stringify!(__wasi_dirent_t),
|
||||
"::",
|
||||
stringify!(d_ino)
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
unsafe { &(*(::std::ptr::null::<__wasi_dirent_t>())).d_namlen as *const _ as usize },
|
||||
16usize,
|
||||
concat!(
|
||||
"Offset of field: ",
|
||||
stringify!(__wasi_dirent_t),
|
||||
"::",
|
||||
stringify!(d_namlen)
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
unsafe { &(*(::std::ptr::null::<__wasi_dirent_t>())).d_type as *const _ as usize },
|
||||
20usize,
|
||||
concat!(
|
||||
"Offset of field: ",
|
||||
stringify!(__wasi_dirent_t),
|
||||
"::",
|
||||
stringify!(d_type)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
172
crates/wasi-common/src/old/snapshot_0/wasi32.rs
Normal file
172
crates/wasi-common/src/old/snapshot_0/wasi32.rs
Normal file
@@ -0,0 +1,172 @@
|
||||
//! Types and constants specific to 32-bit wasi. These are similar to the types
|
||||
//! in the `host` module, but pointers and `usize` values are replaced with
|
||||
//! `u32`-sized types.
|
||||
|
||||
#![allow(non_camel_case_types)]
|
||||
#![allow(non_snake_case)]
|
||||
#![allow(dead_code)]
|
||||
|
||||
use crate::old::snapshot_0::wasi::*;
|
||||
use wig::witx_wasi32_types;
|
||||
|
||||
pub type uintptr_t = u32;
|
||||
pub type size_t = u32;
|
||||
|
||||
witx_wasi32_types!("old/snapshot_0" "wasi_unstable");
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn bindgen_test_layout_wasi_ciovec_t() {
|
||||
assert_eq!(
|
||||
::std::mem::size_of::<__wasi_ciovec_t>(),
|
||||
8usize,
|
||||
concat!("Size of: ", stringify!(__wasi_ciovec_t))
|
||||
);
|
||||
assert_eq!(
|
||||
::std::mem::align_of::<__wasi_ciovec_t>(),
|
||||
4usize,
|
||||
concat!("Alignment of ", stringify!(__wasi_ciovec_t))
|
||||
);
|
||||
assert_eq!(
|
||||
unsafe { &(*(::std::ptr::null::<__wasi_ciovec_t>())).buf as *const _ as usize },
|
||||
0usize,
|
||||
concat!(
|
||||
"Offset of field: ",
|
||||
stringify!(__wasi_ciovec_t),
|
||||
"::",
|
||||
stringify!(buf)
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
unsafe { &(*(::std::ptr::null::<__wasi_ciovec_t>())).buf_len as *const _ as usize },
|
||||
4usize,
|
||||
concat!(
|
||||
"Offset of field: ",
|
||||
stringify!(__wasi_ciovec_t),
|
||||
"::",
|
||||
stringify!(buf_len)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn bindgen_test_layout_wasi_iovec_t() {
|
||||
assert_eq!(
|
||||
::std::mem::size_of::<__wasi_iovec_t>(),
|
||||
8usize,
|
||||
concat!("Size of: ", stringify!(__wasi_iovec_t))
|
||||
);
|
||||
assert_eq!(
|
||||
::std::mem::align_of::<__wasi_iovec_t>(),
|
||||
4usize,
|
||||
concat!("Alignment of ", stringify!(__wasi_iovec_t))
|
||||
);
|
||||
assert_eq!(
|
||||
unsafe { &(*(::std::ptr::null::<__wasi_iovec_t>())).buf as *const _ as usize },
|
||||
0usize,
|
||||
concat!(
|
||||
"Offset of field: ",
|
||||
stringify!(__wasi_iovec_t),
|
||||
"::",
|
||||
stringify!(buf)
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
unsafe { &(*(::std::ptr::null::<__wasi_iovec_t>())).buf_len as *const _ as usize },
|
||||
4usize,
|
||||
concat!(
|
||||
"Offset of field: ",
|
||||
stringify!(__wasi_iovec_t),
|
||||
"::",
|
||||
stringify!(buf_len)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn bindgen_test_layout___wasi_prestat_t___wasi_prestat_u___wasi_prestat_u_dir_t() {
|
||||
assert_eq!(
|
||||
::std::mem::size_of::<__wasi_prestat_dir_t>(),
|
||||
4usize,
|
||||
concat!("Size of: ", stringify!(__wasi_prestat_dir_t))
|
||||
);
|
||||
assert_eq!(
|
||||
::std::mem::align_of::<__wasi_prestat_dir_t>(),
|
||||
4usize,
|
||||
concat!("Alignment of ", stringify!(__wasi_prestat_dir_t))
|
||||
);
|
||||
assert_eq!(
|
||||
unsafe {
|
||||
&(*(::std::ptr::null::<__wasi_prestat_dir_t>())).pr_name_len as *const _ as usize
|
||||
},
|
||||
0usize,
|
||||
concat!(
|
||||
"Offset of field: ",
|
||||
stringify!(__wasi_prestat_dir_t),
|
||||
"::",
|
||||
stringify!(pr_name_len)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn bindgen_test_layout___wasi_prestat_t___wasi_prestat_u() {
|
||||
assert_eq!(
|
||||
::std::mem::size_of::<__wasi_prestat_u_t>(),
|
||||
4usize,
|
||||
concat!("Size of: ", stringify!(__wasi_prestat_u_t))
|
||||
);
|
||||
assert_eq!(
|
||||
::std::mem::align_of::<__wasi_prestat_u_t>(),
|
||||
4usize,
|
||||
concat!("Alignment of ", stringify!(__wasi_prestat_u_t))
|
||||
);
|
||||
assert_eq!(
|
||||
unsafe { &(*(::std::ptr::null::<__wasi_prestat_u_t>())).dir as *const _ as usize },
|
||||
0usize,
|
||||
concat!(
|
||||
"Offset of field: ",
|
||||
stringify!(__wasi_prestat_u_t),
|
||||
"::",
|
||||
stringify!(dir)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn bindgen_test_layout___wasi_prestat_t() {
|
||||
assert_eq!(
|
||||
::std::mem::size_of::<__wasi_prestat_t>(),
|
||||
8usize,
|
||||
concat!("Size of: ", stringify!(__wasi_prestat_t))
|
||||
);
|
||||
assert_eq!(
|
||||
::std::mem::align_of::<__wasi_prestat_t>(),
|
||||
4usize,
|
||||
concat!("Alignment of ", stringify!(__wasi_prestat_t))
|
||||
);
|
||||
assert_eq!(
|
||||
unsafe { &(*(::std::ptr::null::<__wasi_prestat_t>())).pr_type as *const _ as usize },
|
||||
0usize,
|
||||
concat!(
|
||||
"Offset of field: ",
|
||||
stringify!(__wasi_prestat_t),
|
||||
"::",
|
||||
stringify!(pr_type)
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
unsafe { &(*(::std::ptr::null::<__wasi_prestat_t>())).u as *const _ as usize },
|
||||
4usize,
|
||||
concat!(
|
||||
"Offset of field: ",
|
||||
stringify!(__wasi_prestat_t),
|
||||
"::",
|
||||
stringify!(u)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -46,9 +46,9 @@ pub(crate) unsafe fn determine_type_and_access_rights<Fd: AsRawFd>(
|
||||
let flags = OFlag::from_bits_truncate(flags_bits);
|
||||
let accmode = flags & OFlag::O_ACCMODE;
|
||||
if accmode == OFlag::O_RDONLY {
|
||||
rights_base &= !wasi::__WASI_RIGHT_FD_WRITE;
|
||||
rights_base &= !wasi::__WASI_RIGHTS_FD_WRITE;
|
||||
} else if accmode == OFlag::O_WRONLY {
|
||||
rights_base &= !wasi::__WASI_RIGHT_FD_READ;
|
||||
rights_base &= !wasi::__WASI_RIGHTS_FD_READ;
|
||||
}
|
||||
|
||||
Ok((file_type, rights_base, rights_inheriting))
|
||||
|
||||
@@ -109,19 +109,19 @@ pub(crate) fn errno_from_nix(errno: nix::errno::Errno) -> Error {
|
||||
pub(crate) fn nix_from_fdflags(fdflags: wasi::__wasi_fdflags_t) -> nix::fcntl::OFlag {
|
||||
use nix::fcntl::OFlag;
|
||||
let mut nix_flags = OFlag::empty();
|
||||
if fdflags & wasi::__WASI_FDFLAG_APPEND != 0 {
|
||||
if fdflags & wasi::__WASI_FDFLAGS_APPEND != 0 {
|
||||
nix_flags.insert(OFlag::O_APPEND);
|
||||
}
|
||||
if fdflags & wasi::__WASI_FDFLAG_DSYNC != 0 {
|
||||
if fdflags & wasi::__WASI_FDFLAGS_DSYNC != 0 {
|
||||
nix_flags.insert(OFlag::O_DSYNC);
|
||||
}
|
||||
if fdflags & wasi::__WASI_FDFLAG_NONBLOCK != 0 {
|
||||
if fdflags & wasi::__WASI_FDFLAGS_NONBLOCK != 0 {
|
||||
nix_flags.insert(OFlag::O_NONBLOCK);
|
||||
}
|
||||
if fdflags & wasi::__WASI_FDFLAG_RSYNC != 0 {
|
||||
if fdflags & wasi::__WASI_FDFLAGS_RSYNC != 0 {
|
||||
nix_flags.insert(O_RSYNC);
|
||||
}
|
||||
if fdflags & wasi::__WASI_FDFLAG_SYNC != 0 {
|
||||
if fdflags & wasi::__WASI_FDFLAGS_SYNC != 0 {
|
||||
nix_flags.insert(OFlag::O_SYNC);
|
||||
}
|
||||
nix_flags
|
||||
@@ -131,19 +131,19 @@ pub(crate) fn fdflags_from_nix(oflags: nix::fcntl::OFlag) -> wasi::__wasi_fdflag
|
||||
use nix::fcntl::OFlag;
|
||||
let mut fdflags = 0;
|
||||
if oflags.contains(OFlag::O_APPEND) {
|
||||
fdflags |= wasi::__WASI_FDFLAG_APPEND;
|
||||
fdflags |= wasi::__WASI_FDFLAGS_APPEND;
|
||||
}
|
||||
if oflags.contains(OFlag::O_DSYNC) {
|
||||
fdflags |= wasi::__WASI_FDFLAG_DSYNC;
|
||||
fdflags |= wasi::__WASI_FDFLAGS_DSYNC;
|
||||
}
|
||||
if oflags.contains(OFlag::O_NONBLOCK) {
|
||||
fdflags |= wasi::__WASI_FDFLAG_NONBLOCK;
|
||||
fdflags |= wasi::__WASI_FDFLAGS_NONBLOCK;
|
||||
}
|
||||
if oflags.contains(O_RSYNC) {
|
||||
fdflags |= wasi::__WASI_FDFLAG_RSYNC;
|
||||
fdflags |= wasi::__WASI_FDFLAGS_RSYNC;
|
||||
}
|
||||
if oflags.contains(OFlag::O_SYNC) {
|
||||
fdflags |= wasi::__WASI_FDFLAG_SYNC;
|
||||
fdflags |= wasi::__WASI_FDFLAGS_SYNC;
|
||||
}
|
||||
fdflags
|
||||
}
|
||||
@@ -151,16 +151,16 @@ pub(crate) fn fdflags_from_nix(oflags: nix::fcntl::OFlag) -> wasi::__wasi_fdflag
|
||||
pub(crate) fn nix_from_oflags(oflags: wasi::__wasi_oflags_t) -> nix::fcntl::OFlag {
|
||||
use nix::fcntl::OFlag;
|
||||
let mut nix_flags = OFlag::empty();
|
||||
if oflags & wasi::__WASI_O_CREAT != 0 {
|
||||
if oflags & wasi::__WASI_OFLAGS_CREAT != 0 {
|
||||
nix_flags.insert(OFlag::O_CREAT);
|
||||
}
|
||||
if oflags & wasi::__WASI_O_DIRECTORY != 0 {
|
||||
if oflags & wasi::__WASI_OFLAGS_DIRECTORY != 0 {
|
||||
nix_flags.insert(OFlag::O_DIRECTORY);
|
||||
}
|
||||
if oflags & wasi::__WASI_O_EXCL != 0 {
|
||||
if oflags & wasi::__WASI_OFLAGS_EXCL != 0 {
|
||||
nix_flags.insert(OFlag::O_EXCL);
|
||||
}
|
||||
if oflags & wasi::__WASI_O_TRUNC != 0 {
|
||||
if oflags & wasi::__WASI_OFLAGS_TRUNC != 0 {
|
||||
nix_flags.insert(OFlag::O_TRUNC);
|
||||
}
|
||||
nix_flags
|
||||
@@ -198,19 +198,19 @@ pub(crate) fn filestat_from_nix(
|
||||
let filetype = nix::sys::stat::SFlag::from_bits_truncate(filestat.st_mode);
|
||||
let dev = wasi::__wasi_device_t::try_from(filestat.st_dev)?;
|
||||
let ino = wasi::__wasi_inode_t::try_from(filestat.st_ino)?;
|
||||
let st_atim = filestat_to_timestamp(filestat.st_atime as u64, filestat.st_atime_nsec as u64)?;
|
||||
let st_ctim = filestat_to_timestamp(filestat.st_ctime as u64, filestat.st_ctime_nsec as u64)?;
|
||||
let st_mtim = filestat_to_timestamp(filestat.st_mtime as u64, filestat.st_mtime_nsec as u64)?;
|
||||
let atim = filestat_to_timestamp(filestat.st_atime as u64, filestat.st_atime_nsec as u64)?;
|
||||
let ctim = filestat_to_timestamp(filestat.st_ctime as u64, filestat.st_ctime_nsec as u64)?;
|
||||
let mtim = filestat_to_timestamp(filestat.st_mtime as u64, filestat.st_mtime_nsec as u64)?;
|
||||
|
||||
Ok(wasi::__wasi_filestat_t {
|
||||
st_dev: dev,
|
||||
st_ino: ino,
|
||||
st_nlink: filestat.st_nlink as wasi::__wasi_linkcount_t,
|
||||
st_size: filestat.st_size as wasi::__wasi_filesize_t,
|
||||
st_atim,
|
||||
st_ctim,
|
||||
st_mtim,
|
||||
st_filetype: filetype_from_nix(filetype).to_wasi(),
|
||||
dev,
|
||||
ino,
|
||||
nlink: wasi::__wasi_linkcount_t::from(filestat.st_nlink),
|
||||
size: filestat.st_size as wasi::__wasi_filesize_t,
|
||||
atim,
|
||||
ctim,
|
||||
mtim,
|
||||
filetype: filetype_from_nix(filetype).to_wasi(),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -240,7 +240,7 @@ pub(crate) fn dirent_filetype_from_host(
|
||||
/// Creates owned WASI path from OS string.
|
||||
///
|
||||
/// NB WASI spec requires OS string to be valid UTF-8. Otherwise,
|
||||
/// `__WASI_EILSEQ` error is returned.
|
||||
/// `__WASI_ERRNO_ILSEQ` error is returned.
|
||||
pub(crate) fn path_from_host<S: AsRef<OsStr>>(s: S) -> Result<String> {
|
||||
helpers::path_from_slice(s.as_ref().as_bytes()).map(String::from)
|
||||
}
|
||||
|
||||
@@ -217,14 +217,14 @@ pub(crate) fn fd_filestat_get_impl(file: &std::fs::File) -> Result<wasi::__wasi_
|
||||
|
||||
let metadata = file.metadata()?;
|
||||
Ok(wasi::__wasi_filestat_t {
|
||||
st_dev: metadata.dev(),
|
||||
st_ino: metadata.ino(),
|
||||
st_nlink: metadata.nlink().try_into()?, // u64 doesn't fit into u32
|
||||
st_size: metadata.len(),
|
||||
st_atim: systemtime_to_timestamp(metadata.accessed()?)?,
|
||||
st_ctim: metadata.ctime().try_into()?, // i64 doesn't fit into u64
|
||||
st_mtim: systemtime_to_timestamp(metadata.modified()?)?,
|
||||
st_filetype: filetype(file, &metadata)?.to_wasi(),
|
||||
dev: metadata.dev(),
|
||||
ino: metadata.ino(),
|
||||
nlink: metadata.nlink().try_into()?, // u64 doesn't fit into u32
|
||||
size: metadata.len(),
|
||||
atim: systemtime_to_timestamp(metadata.accessed()?)?,
|
||||
ctim: metadata.ctime().try_into()?, // i64 doesn't fit into u64
|
||||
mtim: systemtime_to_timestamp(metadata.modified()?)?,
|
||||
filetype: filetype(file, &metadata)?.to_wasi(),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -283,16 +283,16 @@ pub(crate) fn path_filestat_set_times(
|
||||
use super::super::filetime::*;
|
||||
use std::time::{Duration, UNIX_EPOCH};
|
||||
|
||||
let set_atim = fst_flags & wasi::__WASI_FILESTAT_SET_ATIM != 0;
|
||||
let set_atim_now = fst_flags & wasi::__WASI_FILESTAT_SET_ATIM_NOW != 0;
|
||||
let set_mtim = fst_flags & wasi::__WASI_FILESTAT_SET_MTIM != 0;
|
||||
let set_mtim_now = fst_flags & wasi::__WASI_FILESTAT_SET_MTIM_NOW != 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_mtim = fst_flags & wasi::__WASI_FSTFLAGS_MTIM != 0;
|
||||
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);
|
||||
}
|
||||
|
||||
let symlink_nofollow = wasi::__WASI_LOOKUP_SYMLINK_FOLLOW != dirflags;
|
||||
let symlink_nofollow = wasi::__WASI_LOOKUPFLAGS_SYMLINK_FOLLOW != dirflags;
|
||||
let atim = if set_atim {
|
||||
let time = UNIX_EPOCH + Duration::from_nanos(st_atim);
|
||||
FileTime::FileTime(filetime::FileTime::from_system_time(time))
|
||||
|
||||
@@ -13,25 +13,25 @@ pub(crate) fn path_open_rights(
|
||||
use nix::fcntl::OFlag;
|
||||
|
||||
// which rights are needed on the dirfd?
|
||||
let mut needed_base = wasi::__WASI_RIGHT_PATH_OPEN;
|
||||
let mut needed_base = wasi::__WASI_RIGHTS_PATH_OPEN;
|
||||
let mut needed_inheriting = rights_base | rights_inheriting;
|
||||
|
||||
// convert open flags
|
||||
let oflags = host_impl::nix_from_oflags(oflags);
|
||||
if oflags.contains(OFlag::O_CREAT) {
|
||||
needed_base |= wasi::__WASI_RIGHT_PATH_CREATE_FILE;
|
||||
needed_base |= wasi::__WASI_RIGHTS_PATH_CREATE_FILE;
|
||||
}
|
||||
if oflags.contains(OFlag::O_TRUNC) {
|
||||
needed_base |= wasi::__WASI_RIGHT_PATH_FILESTAT_SET_SIZE;
|
||||
needed_base |= wasi::__WASI_RIGHTS_PATH_FILESTAT_SET_SIZE;
|
||||
}
|
||||
|
||||
// convert file descriptor flags
|
||||
let fdflags = host_impl::nix_from_fdflags(fs_flags);
|
||||
if fdflags.contains(OFlag::O_DSYNC) {
|
||||
needed_inheriting |= wasi::__WASI_RIGHT_FD_DATASYNC;
|
||||
needed_inheriting |= wasi::__WASI_RIGHTS_FD_DATASYNC;
|
||||
}
|
||||
if fdflags.intersects(host_impl::O_RSYNC | OFlag::O_SYNC) {
|
||||
needed_inheriting |= wasi::__WASI_RIGHT_FD_SYNC;
|
||||
needed_inheriting |= wasi::__WASI_RIGHTS_FD_SYNC;
|
||||
}
|
||||
|
||||
(needed_base, needed_inheriting)
|
||||
|
||||
@@ -9,10 +9,10 @@ use std::mem::MaybeUninit;
|
||||
fn wasi_clock_id_to_unix(clock_id: wasi::__wasi_clockid_t) -> Result<libc::clockid_t> {
|
||||
// convert the supported clocks to the libc types, or return EINVAL
|
||||
match clock_id {
|
||||
wasi::__WASI_CLOCK_REALTIME => Ok(libc::CLOCK_REALTIME),
|
||||
wasi::__WASI_CLOCK_MONOTONIC => Ok(libc::CLOCK_MONOTONIC),
|
||||
wasi::__WASI_CLOCK_PROCESS_CPUTIME_ID => Ok(libc::CLOCK_PROCESS_CPUTIME_ID),
|
||||
wasi::__WASI_CLOCK_THREAD_CPUTIME_ID => Ok(libc::CLOCK_THREAD_CPUTIME_ID),
|
||||
wasi::__WASI_CLOCKID_REALTIME => Ok(libc::CLOCK_REALTIME),
|
||||
wasi::__WASI_CLOCKID_MONOTONIC => Ok(libc::CLOCK_MONOTONIC),
|
||||
wasi::__WASI_CLOCKID_PROCESS_CPUTIME_ID => Ok(libc::CLOCK_PROCESS_CPUTIME_ID),
|
||||
wasi::__WASI_CLOCKID_THREAD_CPUTIME_ID => Ok(libc::CLOCK_THREAD_CPUTIME_ID),
|
||||
_ => Err(Error::EINVAL),
|
||||
}
|
||||
}
|
||||
@@ -129,8 +129,8 @@ fn poll_oneoff_handle_timeout_event(
|
||||
events.push(wasi::__wasi_event_t {
|
||||
userdata: timeout.userdata,
|
||||
r#type: wasi::__WASI_EVENTTYPE_CLOCK,
|
||||
error: wasi::__WASI_ESUCCESS,
|
||||
u: wasi::__wasi_event_u {
|
||||
error: wasi::__WASI_ERRNO_SUCCESS,
|
||||
u: wasi::__wasi_event_u_t {
|
||||
fd_readwrite: wasi::__wasi_event_fd_readwrite_t {
|
||||
nbytes: 0,
|
||||
flags: 0,
|
||||
@@ -166,11 +166,11 @@ fn poll_oneoff_handle_fd_event<'a>(
|
||||
wasi::__wasi_event_t {
|
||||
userdata: fd_event.userdata,
|
||||
r#type: fd_event.r#type,
|
||||
error: wasi::__WASI_EBADF,
|
||||
u: wasi::__wasi_event_u {
|
||||
error: wasi::__WASI_ERRNO_BADF,
|
||||
u: wasi::__wasi_event_u_t {
|
||||
fd_readwrite: wasi::__wasi_event_fd_readwrite_t {
|
||||
nbytes: 0,
|
||||
flags: wasi::__WASI_EVENT_FD_READWRITE_HANGUP,
|
||||
flags: wasi::__WASI_EVENTRWFLAGS_FD_READWRITE_HANGUP,
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -178,11 +178,11 @@ fn poll_oneoff_handle_fd_event<'a>(
|
||||
wasi::__wasi_event_t {
|
||||
userdata: fd_event.userdata,
|
||||
r#type: fd_event.r#type,
|
||||
error: wasi::__WASI_EIO,
|
||||
u: wasi::__wasi_event_u {
|
||||
error: wasi::__WASI_ERRNO_IO,
|
||||
u: wasi::__wasi_event_u_t {
|
||||
fd_readwrite: wasi::__wasi_event_fd_readwrite_t {
|
||||
nbytes: 0,
|
||||
flags: wasi::__WASI_EVENT_FD_READWRITE_HANGUP,
|
||||
flags: wasi::__WASI_EVENTRWFLAGS_FD_READWRITE_HANGUP,
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -190,11 +190,11 @@ fn poll_oneoff_handle_fd_event<'a>(
|
||||
wasi::__wasi_event_t {
|
||||
userdata: fd_event.userdata,
|
||||
r#type: fd_event.r#type,
|
||||
error: wasi::__WASI_ESUCCESS,
|
||||
u: wasi::__wasi_event_u {
|
||||
error: wasi::__WASI_ERRNO_SUCCESS,
|
||||
u: wasi::__wasi_event_u_t {
|
||||
fd_readwrite: wasi::__wasi_event_fd_readwrite_t {
|
||||
nbytes: 0,
|
||||
flags: wasi::__WASI_EVENT_FD_READWRITE_HANGUP,
|
||||
flags: wasi::__WASI_EVENTRWFLAGS_FD_READWRITE_HANGUP,
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -202,8 +202,8 @@ fn poll_oneoff_handle_fd_event<'a>(
|
||||
wasi::__wasi_event_t {
|
||||
userdata: fd_event.userdata,
|
||||
r#type: fd_event.r#type,
|
||||
error: wasi::__WASI_ESUCCESS,
|
||||
u: wasi::__wasi_event_u {
|
||||
error: wasi::__WASI_ERRNO_SUCCESS,
|
||||
u: wasi::__wasi_event_u_t {
|
||||
fd_readwrite: wasi::__wasi_event_fd_readwrite_t {
|
||||
nbytes: nbytes.try_into()?,
|
||||
flags: 0,
|
||||
|
||||
@@ -61,10 +61,10 @@ pub(crate) unsafe fn determine_type_and_access_rights<Handle: AsRawHandle>(
|
||||
wasi::__WASI_FILETYPE_DIRECTORY | wasi::__WASI_FILETYPE_REGULAR_FILE => {
|
||||
let mode = get_file_access_mode(handle.as_raw_handle())?;
|
||||
if mode.contains(AccessMode::FILE_GENERIC_READ) {
|
||||
rights_base |= wasi::__WASI_RIGHT_FD_READ;
|
||||
rights_base |= wasi::__WASI_RIGHTS_FD_READ;
|
||||
}
|
||||
if mode.contains(AccessMode::FILE_GENERIC_WRITE) {
|
||||
rights_base |= wasi::__WASI_RIGHT_FD_WRITE;
|
||||
rights_base |= wasi::__WASI_RIGHTS_FD_WRITE;
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
|
||||
@@ -13,30 +13,30 @@ pub(crate) fn errno_from_win(error: winx::winerror::WinError) -> wasi::__wasi_er
|
||||
// TODO: implement error mapping between Windows and WASI
|
||||
use winx::winerror::WinError::*;
|
||||
match error {
|
||||
ERROR_SUCCESS => wasi::__WASI_ESUCCESS,
|
||||
ERROR_BAD_ENVIRONMENT => wasi::__WASI_E2BIG,
|
||||
ERROR_FILE_NOT_FOUND => wasi::__WASI_ENOENT,
|
||||
ERROR_PATH_NOT_FOUND => wasi::__WASI_ENOENT,
|
||||
ERROR_TOO_MANY_OPEN_FILES => wasi::__WASI_ENFILE,
|
||||
ERROR_ACCESS_DENIED => wasi::__WASI_EACCES,
|
||||
ERROR_SHARING_VIOLATION => wasi::__WASI_EACCES,
|
||||
ERROR_PRIVILEGE_NOT_HELD => wasi::__WASI_ENOTCAPABLE, // TODO is this the correct mapping?
|
||||
ERROR_INVALID_HANDLE => wasi::__WASI_EBADF,
|
||||
ERROR_INVALID_NAME => wasi::__WASI_ENOENT,
|
||||
ERROR_NOT_ENOUGH_MEMORY => wasi::__WASI_ENOMEM,
|
||||
ERROR_OUTOFMEMORY => wasi::__WASI_ENOMEM,
|
||||
ERROR_DIR_NOT_EMPTY => wasi::__WASI_ENOTEMPTY,
|
||||
ERROR_NOT_READY => wasi::__WASI_EBUSY,
|
||||
ERROR_BUSY => wasi::__WASI_EBUSY,
|
||||
ERROR_NOT_SUPPORTED => wasi::__WASI_ENOTSUP,
|
||||
ERROR_FILE_EXISTS => wasi::__WASI_EEXIST,
|
||||
ERROR_BROKEN_PIPE => wasi::__WASI_EPIPE,
|
||||
ERROR_BUFFER_OVERFLOW => wasi::__WASI_ENAMETOOLONG,
|
||||
ERROR_NOT_A_REPARSE_POINT => wasi::__WASI_EINVAL,
|
||||
ERROR_NEGATIVE_SEEK => wasi::__WASI_EINVAL,
|
||||
ERROR_DIRECTORY => wasi::__WASI_ENOTDIR,
|
||||
ERROR_ALREADY_EXISTS => wasi::__WASI_EEXIST,
|
||||
_ => wasi::__WASI_ENOTSUP,
|
||||
ERROR_SUCCESS => wasi::__WASI_ERRNO_SUCCESS,
|
||||
ERROR_BAD_ENVIRONMENT => wasi::__WASI_ERRNO_2BIG,
|
||||
ERROR_FILE_NOT_FOUND => wasi::__WASI_ERRNO_NOENT,
|
||||
ERROR_PATH_NOT_FOUND => wasi::__WASI_ERRNO_NOENT,
|
||||
ERROR_TOO_MANY_OPEN_FILES => wasi::__WASI_ERRNO_NFILE,
|
||||
ERROR_ACCESS_DENIED => wasi::__WASI_ERRNO_ACCES,
|
||||
ERROR_SHARING_VIOLATION => wasi::__WASI_ERRNO_ACCES,
|
||||
ERROR_PRIVILEGE_NOT_HELD => wasi::__WASI_ERRNO_NOTCAPABLE, // TODO is this the correct mapping?
|
||||
ERROR_INVALID_HANDLE => wasi::__WASI_ERRNO_BADF,
|
||||
ERROR_INVALID_NAME => wasi::__WASI_ERRNO_NOENT,
|
||||
ERROR_NOT_ENOUGH_MEMORY => wasi::__WASI_ERRNO_NOMEM,
|
||||
ERROR_OUTOFMEMORY => wasi::__WASI_ERRNO_NOMEM,
|
||||
ERROR_DIR_NOT_EMPTY => wasi::__WASI_ERRNO_NOTEMPTY,
|
||||
ERROR_NOT_READY => wasi::__WASI_ERRNO_BUSY,
|
||||
ERROR_BUSY => wasi::__WASI_ERRNO_BUSY,
|
||||
ERROR_NOT_SUPPORTED => wasi::__WASI_ERRNO_NOTSUP,
|
||||
ERROR_FILE_EXISTS => wasi::__WASI_ERRNO_EXIST,
|
||||
ERROR_BROKEN_PIPE => wasi::__WASI_ERRNO_PIPE,
|
||||
ERROR_BUFFER_OVERFLOW => wasi::__WASI_ERRNO_NAMETOOLONG,
|
||||
ERROR_NOT_A_REPARSE_POINT => wasi::__WASI_ERRNO_INVAL,
|
||||
ERROR_NEGATIVE_SEEK => wasi::__WASI_ERRNO_INVAL,
|
||||
ERROR_DIRECTORY => wasi::__WASI_ERRNO_NOTDIR,
|
||||
ERROR_ALREADY_EXISTS => wasi::__WASI_ERRNO_EXIST,
|
||||
_ => wasi::__WASI_ERRNO_NOTSUP,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,12 +44,12 @@ pub(crate) fn fdflags_from_win(mode: AccessMode) -> wasi::__wasi_fdflags_t {
|
||||
let mut fdflags = 0;
|
||||
// TODO verify this!
|
||||
if mode.contains(AccessMode::FILE_APPEND_DATA) {
|
||||
fdflags |= wasi::__WASI_FDFLAG_APPEND;
|
||||
fdflags |= wasi::__WASI_FDFLAGS_APPEND;
|
||||
}
|
||||
if mode.contains(AccessMode::SYNCHRONIZE) {
|
||||
fdflags |= wasi::__WASI_FDFLAG_DSYNC;
|
||||
fdflags |= wasi::__WASI_FDFLAG_RSYNC;
|
||||
fdflags |= wasi::__WASI_FDFLAG_SYNC;
|
||||
fdflags |= wasi::__WASI_FDFLAGS_DSYNC;
|
||||
fdflags |= wasi::__WASI_FDFLAGS_RSYNC;
|
||||
fdflags |= wasi::__WASI_FDFLAGS_SYNC;
|
||||
}
|
||||
// The NONBLOCK equivalent is FILE_FLAG_OVERLAPPED
|
||||
// but it seems winapi doesn't provide a mechanism
|
||||
@@ -68,15 +68,15 @@ pub(crate) fn win_from_fdflags(fdflags: wasi::__wasi_fdflags_t) -> (AccessMode,
|
||||
let mut flags = Flags::empty();
|
||||
|
||||
// TODO verify this!
|
||||
if fdflags & wasi::__WASI_FDFLAG_NONBLOCK != 0 {
|
||||
if fdflags & wasi::__WASI_FDFLAGS_NONBLOCK != 0 {
|
||||
flags.insert(Flags::FILE_FLAG_OVERLAPPED);
|
||||
}
|
||||
if fdflags & wasi::__WASI_FDFLAG_APPEND != 0 {
|
||||
if fdflags & wasi::__WASI_FDFLAGS_APPEND != 0 {
|
||||
access_mode.insert(AccessMode::FILE_APPEND_DATA);
|
||||
}
|
||||
if fdflags & wasi::__WASI_FDFLAG_DSYNC != 0
|
||||
|| fdflags & wasi::__WASI_FDFLAG_RSYNC != 0
|
||||
|| fdflags & wasi::__WASI_FDFLAG_SYNC != 0
|
||||
if fdflags & wasi::__WASI_FDFLAGS_DSYNC != 0
|
||||
|| fdflags & wasi::__WASI_FDFLAGS_RSYNC != 0
|
||||
|| fdflags & wasi::__WASI_FDFLAGS_SYNC != 0
|
||||
{
|
||||
access_mode.insert(AccessMode::SYNCHRONIZE);
|
||||
}
|
||||
@@ -85,13 +85,13 @@ pub(crate) fn win_from_fdflags(fdflags: wasi::__wasi_fdflags_t) -> (AccessMode,
|
||||
}
|
||||
|
||||
pub(crate) fn win_from_oflags(oflags: wasi::__wasi_oflags_t) -> CreationDisposition {
|
||||
if oflags & wasi::__WASI_O_CREAT != 0 {
|
||||
if oflags & wasi::__WASI_O_EXCL != 0 {
|
||||
if oflags & wasi::__WASI_OFLAGS_CREAT != 0 {
|
||||
if oflags & wasi::__WASI_OFLAGS_EXCL != 0 {
|
||||
CreationDisposition::CREATE_NEW
|
||||
} else {
|
||||
CreationDisposition::CREATE_ALWAYS
|
||||
}
|
||||
} else if oflags & wasi::__WASI_O_TRUNC != 0 {
|
||||
} else if oflags & wasi::__WASI_OFLAGS_TRUNC != 0 {
|
||||
CreationDisposition::TRUNCATE_EXISTING
|
||||
} else {
|
||||
CreationDisposition::OPEN_EXISTING
|
||||
@@ -101,7 +101,7 @@ pub(crate) fn win_from_oflags(oflags: wasi::__wasi_oflags_t) -> CreationDisposit
|
||||
/// Creates owned WASI path from OS string.
|
||||
///
|
||||
/// NB WASI spec requires OS string to be valid UTF-8. Otherwise,
|
||||
/// `__WASI_EILSEQ` error is returned.
|
||||
/// `__WASI_ERRNO_ILSEQ` error is returned.
|
||||
pub(crate) fn path_from_host<S: AsRef<OsStr>>(s: S) -> Result<String> {
|
||||
let vec: Vec<u16> = s.as_ref().encode_wide().collect();
|
||||
String::from_utf16(&vec).map_err(|_| Error::EILSEQ)
|
||||
|
||||
@@ -139,7 +139,7 @@ pub(crate) fn path_open(
|
||||
return Err(Error::ELOOP);
|
||||
}
|
||||
// check if we are trying to open a file as a dir
|
||||
if file_type.is_file() && oflags & wasi::__WASI_O_DIRECTORY != 0 {
|
||||
if file_type.is_file() && oflags & wasi::__WASI_OFLAGS_DIRECTORY != 0 {
|
||||
return Err(Error::ENOTDIR);
|
||||
}
|
||||
}
|
||||
@@ -410,14 +410,14 @@ pub(crate) fn change_time(file: &File, _metadata: &Metadata) -> io::Result<i64>
|
||||
pub(crate) fn fd_filestat_get_impl(file: &std::fs::File) -> Result<wasi::__wasi_filestat_t> {
|
||||
let metadata = file.metadata()?;
|
||||
Ok(wasi::__wasi_filestat_t {
|
||||
st_dev: device_id(file, &metadata)?,
|
||||
st_ino: file_serial_no(file)?,
|
||||
st_nlink: num_hardlinks(file, &metadata)?.try_into()?, // u64 doesn't fit into u32
|
||||
st_size: metadata.len(),
|
||||
st_atim: systemtime_to_timestamp(metadata.accessed()?)?,
|
||||
st_ctim: change_time(file, &metadata)?.try_into()?, // i64 doesn't fit into u64
|
||||
st_mtim: systemtime_to_timestamp(metadata.modified()?)?,
|
||||
st_filetype: filetype_from_std(&metadata.file_type()).to_wasi(),
|
||||
dev: device_id(file, &metadata)?,
|
||||
ino: file_serial_no(file)?,
|
||||
nlink: num_hardlinks(file, &metadata)?.try_into()?, // u64 doesn't fit into u32
|
||||
size: metadata.len(),
|
||||
atim: systemtime_to_timestamp(metadata.accessed()?)?,
|
||||
ctim: change_time(file, &metadata)?.try_into()?, // i64 doesn't fit into u64
|
||||
mtim: systemtime_to_timestamp(metadata.modified()?)?,
|
||||
filetype: filetype_from_std(&metadata.file_type()).to_wasi(),
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -23,23 +23,23 @@ pub(crate) fn path_open_rights(
|
||||
fdflags: wasi::__wasi_fdflags_t,
|
||||
) -> (wasi::__wasi_rights_t, wasi::__wasi_rights_t) {
|
||||
// which rights are needed on the dirfd?
|
||||
let mut needed_base = wasi::__WASI_RIGHT_PATH_OPEN;
|
||||
let mut needed_base = wasi::__WASI_RIGHTS_PATH_OPEN;
|
||||
let mut needed_inheriting = rights_base | rights_inheriting;
|
||||
|
||||
// convert open flags
|
||||
if oflags & wasi::__WASI_O_CREAT != 0 {
|
||||
needed_base |= wasi::__WASI_RIGHT_PATH_CREATE_FILE;
|
||||
} else if oflags & wasi::__WASI_O_TRUNC != 0 {
|
||||
needed_base |= wasi::__WASI_RIGHT_PATH_FILESTAT_SET_SIZE;
|
||||
if oflags & wasi::__WASI_OFLAGS_CREAT != 0 {
|
||||
needed_base |= wasi::__WASI_RIGHTS_PATH_CREATE_FILE;
|
||||
} else if oflags & wasi::__WASI_OFLAGS_TRUNC != 0 {
|
||||
needed_base |= wasi::__WASI_RIGHTS_PATH_FILESTAT_SET_SIZE;
|
||||
}
|
||||
|
||||
// convert file descriptor flags
|
||||
if fdflags & wasi::__WASI_FDFLAG_DSYNC != 0
|
||||
|| fdflags & wasi::__WASI_FDFLAG_RSYNC != 0
|
||||
|| fdflags & wasi::__WASI_FDFLAG_SYNC != 0
|
||||
if fdflags & wasi::__WASI_FDFLAGS_DSYNC != 0
|
||||
|| fdflags & wasi::__WASI_FDFLAGS_RSYNC != 0
|
||||
|| fdflags & wasi::__WASI_FDFLAGS_SYNC != 0
|
||||
{
|
||||
needed_inheriting |= wasi::__WASI_RIGHT_FD_DATASYNC;
|
||||
needed_inheriting |= wasi::__WASI_RIGHT_FD_SYNC;
|
||||
needed_inheriting |= wasi::__WASI_RIGHTS_FD_DATASYNC;
|
||||
needed_inheriting |= wasi::__WASI_RIGHTS_FD_SYNC;
|
||||
}
|
||||
|
||||
(needed_base, needed_inheriting)
|
||||
|
||||
@@ -53,25 +53,25 @@ pub(crate) fn clock_res_get(clock_id: wasi::__wasi_clockid_t) -> Result<wasi::__
|
||||
// [4] https://www.codeproject.com/Tips/1011902/High-Resolution-Time-For-Windows
|
||||
// [5] https://stackoverflow.com/questions/7685762/windows-7-timing-functions-how-to-use-getsystemtimeadjustment-correctly
|
||||
// [6] https://bugs.python.org/issue19007
|
||||
wasi::__WASI_CLOCK_REALTIME => 55_000_000,
|
||||
wasi::__WASI_CLOCKID_REALTIME => 55_000_000,
|
||||
// std::time::Instant uses QueryPerformanceCounter & QueryPerformanceFrequency internally
|
||||
wasi::__WASI_CLOCK_MONOTONIC => *PERF_COUNTER_RES,
|
||||
wasi::__WASI_CLOCKID_MONOTONIC => *PERF_COUNTER_RES,
|
||||
// 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-getprocesstimes
|
||||
wasi::__WASI_CLOCK_PROCESS_CPUTIME_ID => 100,
|
||||
wasi::__WASI_CLOCKID_PROCESS_CPUTIME_ID => 100,
|
||||
// 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_CLOCK_THREAD_CPUTIME_ID => 100,
|
||||
wasi::__WASI_CLOCKID_THREAD_CPUTIME_ID => 100,
|
||||
_ => return Err(Error::EINVAL),
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn clock_time_get(clock_id: wasi::__wasi_clockid_t) -> Result<wasi::__wasi_timestamp_t> {
|
||||
let duration = match clock_id {
|
||||
wasi::__WASI_CLOCK_REALTIME => get_monotonic_time(),
|
||||
wasi::__WASI_CLOCK_MONOTONIC => get_realtime_time()?,
|
||||
wasi::__WASI_CLOCK_PROCESS_CPUTIME_ID => get_proc_cputime()?,
|
||||
wasi::__WASI_CLOCK_THREAD_CPUTIME_ID => get_thread_cputime()?,
|
||||
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),
|
||||
};
|
||||
duration.as_nanos().try_into().map_err(Into::into)
|
||||
@@ -87,7 +87,7 @@ pub(crate) fn poll_oneoff(
|
||||
|
||||
fn get_monotonic_time() -> Duration {
|
||||
// We're circumventing the fact that we can't get a Duration from an Instant
|
||||
// The epoch of __WASI_CLOCK_MONOTONIC is undefined, so we fix a time point once
|
||||
// The epoch of __WASI_CLOCKID_MONOTONIC is undefined, so we fix a time point once
|
||||
// and count relative to this time point.
|
||||
//
|
||||
// The alternative would be to copy over the implementation of std::time::Instant
|
||||
|
||||
@@ -8,37 +8,37 @@
|
||||
|
||||
use wig::witx_wasi_types;
|
||||
|
||||
witx_wasi_types!("unstable" "wasi_unstable_preview0");
|
||||
witx_wasi_types!("snapshot" "wasi_snapshot_preview1");
|
||||
|
||||
pub(crate) const RIGHTS_ALL: __wasi_rights_t = __WASI_RIGHT_FD_DATASYNC
|
||||
| __WASI_RIGHT_FD_READ
|
||||
| __WASI_RIGHT_FD_SEEK
|
||||
| __WASI_RIGHT_FD_FDSTAT_SET_FLAGS
|
||||
| __WASI_RIGHT_FD_SYNC
|
||||
| __WASI_RIGHT_FD_TELL
|
||||
| __WASI_RIGHT_FD_WRITE
|
||||
| __WASI_RIGHT_FD_ADVISE
|
||||
| __WASI_RIGHT_FD_ALLOCATE
|
||||
| __WASI_RIGHT_PATH_CREATE_DIRECTORY
|
||||
| __WASI_RIGHT_PATH_CREATE_FILE
|
||||
| __WASI_RIGHT_PATH_LINK_SOURCE
|
||||
| __WASI_RIGHT_PATH_LINK_TARGET
|
||||
| __WASI_RIGHT_PATH_OPEN
|
||||
| __WASI_RIGHT_FD_READDIR
|
||||
| __WASI_RIGHT_PATH_READLINK
|
||||
| __WASI_RIGHT_PATH_RENAME_SOURCE
|
||||
| __WASI_RIGHT_PATH_RENAME_TARGET
|
||||
| __WASI_RIGHT_PATH_FILESTAT_GET
|
||||
| __WASI_RIGHT_PATH_FILESTAT_SET_SIZE
|
||||
| __WASI_RIGHT_PATH_FILESTAT_SET_TIMES
|
||||
| __WASI_RIGHT_FD_FILESTAT_GET
|
||||
| __WASI_RIGHT_FD_FILESTAT_SET_SIZE
|
||||
| __WASI_RIGHT_FD_FILESTAT_SET_TIMES
|
||||
| __WASI_RIGHT_PATH_SYMLINK
|
||||
| __WASI_RIGHT_PATH_UNLINK_FILE
|
||||
| __WASI_RIGHT_PATH_REMOVE_DIRECTORY
|
||||
| __WASI_RIGHT_POLL_FD_READWRITE
|
||||
| __WASI_RIGHT_SOCK_SHUTDOWN;
|
||||
pub(crate) const RIGHTS_ALL: __wasi_rights_t = __WASI_RIGHTS_FD_DATASYNC
|
||||
| __WASI_RIGHTS_FD_READ
|
||||
| __WASI_RIGHTS_FD_SEEK
|
||||
| __WASI_RIGHTS_FD_FDSTAT_SET_FLAGS
|
||||
| __WASI_RIGHTS_FD_SYNC
|
||||
| __WASI_RIGHTS_FD_TELL
|
||||
| __WASI_RIGHTS_FD_WRITE
|
||||
| __WASI_RIGHTS_FD_ADVISE
|
||||
| __WASI_RIGHTS_FD_ALLOCATE
|
||||
| __WASI_RIGHTS_PATH_CREATE_DIRECTORY
|
||||
| __WASI_RIGHTS_PATH_CREATE_FILE
|
||||
| __WASI_RIGHTS_PATH_LINK_SOURCE
|
||||
| __WASI_RIGHTS_PATH_LINK_TARGET
|
||||
| __WASI_RIGHTS_PATH_OPEN
|
||||
| __WASI_RIGHTS_FD_READDIR
|
||||
| __WASI_RIGHTS_PATH_READLINK
|
||||
| __WASI_RIGHTS_PATH_RENAME_SOURCE
|
||||
| __WASI_RIGHTS_PATH_RENAME_TARGET
|
||||
| __WASI_RIGHTS_PATH_FILESTAT_GET
|
||||
| __WASI_RIGHTS_PATH_FILESTAT_SET_SIZE
|
||||
| __WASI_RIGHTS_PATH_FILESTAT_SET_TIMES
|
||||
| __WASI_RIGHTS_FD_FILESTAT_GET
|
||||
| __WASI_RIGHTS_FD_FILESTAT_SET_SIZE
|
||||
| __WASI_RIGHTS_FD_FILESTAT_SET_TIMES
|
||||
| __WASI_RIGHTS_PATH_SYMLINK
|
||||
| __WASI_RIGHTS_PATH_UNLINK_FILE
|
||||
| __WASI_RIGHTS_PATH_REMOVE_DIRECTORY
|
||||
| __WASI_RIGHTS_POLL_FD_READWRITE
|
||||
| __WASI_RIGHTS_SOCK_SHUTDOWN;
|
||||
|
||||
// Block and character device interaction is outside the scope of
|
||||
// WASI. Simply allow everything.
|
||||
@@ -49,143 +49,143 @@ pub(crate) const RIGHTS_CHARACTER_DEVICE_INHERITING: __wasi_rights_t = RIGHTS_AL
|
||||
|
||||
// Only allow directory operations on directories. Directories can only
|
||||
// yield file descriptors to other directories and files.
|
||||
pub(crate) const RIGHTS_DIRECTORY_BASE: __wasi_rights_t = __WASI_RIGHT_FD_FDSTAT_SET_FLAGS
|
||||
| __WASI_RIGHT_FD_SYNC
|
||||
| __WASI_RIGHT_FD_ADVISE
|
||||
| __WASI_RIGHT_PATH_CREATE_DIRECTORY
|
||||
| __WASI_RIGHT_PATH_CREATE_FILE
|
||||
| __WASI_RIGHT_PATH_LINK_SOURCE
|
||||
| __WASI_RIGHT_PATH_LINK_TARGET
|
||||
| __WASI_RIGHT_PATH_OPEN
|
||||
| __WASI_RIGHT_FD_READDIR
|
||||
| __WASI_RIGHT_PATH_READLINK
|
||||
| __WASI_RIGHT_PATH_RENAME_SOURCE
|
||||
| __WASI_RIGHT_PATH_RENAME_TARGET
|
||||
| __WASI_RIGHT_PATH_FILESTAT_GET
|
||||
| __WASI_RIGHT_PATH_FILESTAT_SET_SIZE
|
||||
| __WASI_RIGHT_PATH_FILESTAT_SET_TIMES
|
||||
| __WASI_RIGHT_FD_FILESTAT_GET
|
||||
| __WASI_RIGHT_FD_FILESTAT_SET_TIMES
|
||||
| __WASI_RIGHT_PATH_SYMLINK
|
||||
| __WASI_RIGHT_PATH_UNLINK_FILE
|
||||
| __WASI_RIGHT_PATH_REMOVE_DIRECTORY
|
||||
| __WASI_RIGHT_POLL_FD_READWRITE;
|
||||
pub(crate) const RIGHTS_DIRECTORY_BASE: __wasi_rights_t = __WASI_RIGHTS_FD_FDSTAT_SET_FLAGS
|
||||
| __WASI_RIGHTS_FD_SYNC
|
||||
| __WASI_RIGHTS_FD_ADVISE
|
||||
| __WASI_RIGHTS_PATH_CREATE_DIRECTORY
|
||||
| __WASI_RIGHTS_PATH_CREATE_FILE
|
||||
| __WASI_RIGHTS_PATH_LINK_SOURCE
|
||||
| __WASI_RIGHTS_PATH_LINK_TARGET
|
||||
| __WASI_RIGHTS_PATH_OPEN
|
||||
| __WASI_RIGHTS_FD_READDIR
|
||||
| __WASI_RIGHTS_PATH_READLINK
|
||||
| __WASI_RIGHTS_PATH_RENAME_SOURCE
|
||||
| __WASI_RIGHTS_PATH_RENAME_TARGET
|
||||
| __WASI_RIGHTS_PATH_FILESTAT_GET
|
||||
| __WASI_RIGHTS_PATH_FILESTAT_SET_SIZE
|
||||
| __WASI_RIGHTS_PATH_FILESTAT_SET_TIMES
|
||||
| __WASI_RIGHTS_FD_FILESTAT_GET
|
||||
| __WASI_RIGHTS_FD_FILESTAT_SET_TIMES
|
||||
| __WASI_RIGHTS_PATH_SYMLINK
|
||||
| __WASI_RIGHTS_PATH_UNLINK_FILE
|
||||
| __WASI_RIGHTS_PATH_REMOVE_DIRECTORY
|
||||
| __WASI_RIGHTS_POLL_FD_READWRITE;
|
||||
pub(crate) const RIGHTS_DIRECTORY_INHERITING: __wasi_rights_t =
|
||||
RIGHTS_DIRECTORY_BASE | RIGHTS_REGULAR_FILE_BASE;
|
||||
|
||||
// Operations that apply to regular files.
|
||||
pub(crate) const RIGHTS_REGULAR_FILE_BASE: __wasi_rights_t = __WASI_RIGHT_FD_DATASYNC
|
||||
| __WASI_RIGHT_FD_READ
|
||||
| __WASI_RIGHT_FD_SEEK
|
||||
| __WASI_RIGHT_FD_FDSTAT_SET_FLAGS
|
||||
| __WASI_RIGHT_FD_SYNC
|
||||
| __WASI_RIGHT_FD_TELL
|
||||
| __WASI_RIGHT_FD_WRITE
|
||||
| __WASI_RIGHT_FD_ADVISE
|
||||
| __WASI_RIGHT_FD_ALLOCATE
|
||||
| __WASI_RIGHT_FD_FILESTAT_GET
|
||||
| __WASI_RIGHT_FD_FILESTAT_SET_SIZE
|
||||
| __WASI_RIGHT_FD_FILESTAT_SET_TIMES
|
||||
| __WASI_RIGHT_POLL_FD_READWRITE;
|
||||
pub(crate) const RIGHTS_REGULAR_FILE_BASE: __wasi_rights_t = __WASI_RIGHTS_FD_DATASYNC
|
||||
| __WASI_RIGHTS_FD_READ
|
||||
| __WASI_RIGHTS_FD_SEEK
|
||||
| __WASI_RIGHTS_FD_FDSTAT_SET_FLAGS
|
||||
| __WASI_RIGHTS_FD_SYNC
|
||||
| __WASI_RIGHTS_FD_TELL
|
||||
| __WASI_RIGHTS_FD_WRITE
|
||||
| __WASI_RIGHTS_FD_ADVISE
|
||||
| __WASI_RIGHTS_FD_ALLOCATE
|
||||
| __WASI_RIGHTS_FD_FILESTAT_GET
|
||||
| __WASI_RIGHTS_FD_FILESTAT_SET_SIZE
|
||||
| __WASI_RIGHTS_FD_FILESTAT_SET_TIMES
|
||||
| __WASI_RIGHTS_POLL_FD_READWRITE;
|
||||
pub(crate) const RIGHTS_REGULAR_FILE_INHERITING: __wasi_rights_t = 0;
|
||||
|
||||
// Operations that apply to sockets and socket pairs.
|
||||
pub(crate) const RIGHTS_SOCKET_BASE: __wasi_rights_t = __WASI_RIGHT_FD_READ
|
||||
| __WASI_RIGHT_FD_FDSTAT_SET_FLAGS
|
||||
| __WASI_RIGHT_FD_WRITE
|
||||
| __WASI_RIGHT_FD_FILESTAT_GET
|
||||
| __WASI_RIGHT_POLL_FD_READWRITE
|
||||
| __WASI_RIGHT_SOCK_SHUTDOWN;
|
||||
pub(crate) const RIGHTS_SOCKET_BASE: __wasi_rights_t = __WASI_RIGHTS_FD_READ
|
||||
| __WASI_RIGHTS_FD_FDSTAT_SET_FLAGS
|
||||
| __WASI_RIGHTS_FD_WRITE
|
||||
| __WASI_RIGHTS_FD_FILESTAT_GET
|
||||
| __WASI_RIGHTS_POLL_FD_READWRITE
|
||||
| __WASI_RIGHTS_SOCK_SHUTDOWN;
|
||||
pub(crate) const RIGHTS_SOCKET_INHERITING: __wasi_rights_t = RIGHTS_ALL;
|
||||
|
||||
// Operations that apply to TTYs.
|
||||
pub(crate) const RIGHTS_TTY_BASE: __wasi_rights_t = __WASI_RIGHT_FD_READ
|
||||
| __WASI_RIGHT_FD_FDSTAT_SET_FLAGS
|
||||
| __WASI_RIGHT_FD_WRITE
|
||||
| __WASI_RIGHT_FD_FILESTAT_GET
|
||||
| __WASI_RIGHT_POLL_FD_READWRITE;
|
||||
pub(crate) const RIGHTS_TTY_BASE: __wasi_rights_t = __WASI_RIGHTS_FD_READ
|
||||
| __WASI_RIGHTS_FD_FDSTAT_SET_FLAGS
|
||||
| __WASI_RIGHTS_FD_WRITE
|
||||
| __WASI_RIGHTS_FD_FILESTAT_GET
|
||||
| __WASI_RIGHTS_POLL_FD_READWRITE;
|
||||
#[allow(unused)]
|
||||
pub(crate) const RIGHTS_TTY_INHERITING: __wasi_rights_t = 0;
|
||||
|
||||
pub fn strerror(errno: __wasi_errno_t) -> &'static str {
|
||||
match errno {
|
||||
__WASI_ESUCCESS => "__WASI_ESUCCESS",
|
||||
__WASI_E2BIG => "__WASI_E2BIG",
|
||||
__WASI_EACCES => "__WASI_EACCES",
|
||||
__WASI_EADDRINUSE => "__WASI_EADDRINUSE",
|
||||
__WASI_EADDRNOTAVAIL => "__WASI_EADDRNOTAVAIL",
|
||||
__WASI_EAFNOSUPPORT => "__WASI_EAFNOSUPPORT",
|
||||
__WASI_EAGAIN => "__WASI_EAGAIN",
|
||||
__WASI_EALREADY => "__WASI_EALREADY",
|
||||
__WASI_EBADF => "__WASI_EBADF",
|
||||
__WASI_EBADMSG => "__WASI_EBADMSG",
|
||||
__WASI_EBUSY => "__WASI_EBUSY",
|
||||
__WASI_ECANCELED => "__WASI_ECANCELED",
|
||||
__WASI_ECHILD => "__WASI_ECHILD",
|
||||
__WASI_ECONNABORTED => "__WASI_ECONNABORTED",
|
||||
__WASI_ECONNREFUSED => "__WASI_ECONNREFUSED",
|
||||
__WASI_ECONNRESET => "__WASI_ECONNRESET",
|
||||
__WASI_EDEADLK => "__WASI_EDEADLK",
|
||||
__WASI_EDESTADDRREQ => "__WASI_EDESTADDRREQ",
|
||||
__WASI_EDOM => "__WASI_EDOM",
|
||||
__WASI_EDQUOT => "__WASI_EDQUOT",
|
||||
__WASI_EEXIST => "__WASI_EEXIST",
|
||||
__WASI_EFAULT => "__WASI_EFAULT",
|
||||
__WASI_EFBIG => "__WASI_EFBIG",
|
||||
__WASI_EHOSTUNREACH => "__WASI_EHOSTUNREACH",
|
||||
__WASI_EIDRM => "__WASI_EIDRM",
|
||||
__WASI_EILSEQ => "__WASI_EILSEQ",
|
||||
__WASI_EINPROGRESS => "__WASI_EINPROGRESS",
|
||||
__WASI_EINTR => "__WASI_EINTR",
|
||||
__WASI_EINVAL => "__WASI_EINVAL",
|
||||
__WASI_EIO => "__WASI_EIO",
|
||||
__WASI_EISCONN => "__WASI_EISCONN",
|
||||
__WASI_EISDIR => "__WASI_EISDIR",
|
||||
__WASI_ELOOP => "__WASI_ELOOP",
|
||||
__WASI_EMFILE => "__WASI_EMFILE",
|
||||
__WASI_EMLINK => "__WASI_EMLINK",
|
||||
__WASI_EMSGSIZE => "__WASI_EMSGSIZE",
|
||||
__WASI_EMULTIHOP => "__WASI_EMULTIHOP",
|
||||
__WASI_ENAMETOOLONG => "__WASI_ENAMETOOLONG",
|
||||
__WASI_ENETDOWN => "__WASI_ENETDOWN",
|
||||
__WASI_ENETRESET => "__WASI_ENETRESET",
|
||||
__WASI_ENETUNREACH => "__WASI_ENETUNREACH",
|
||||
__WASI_ENFILE => "__WASI_ENFILE",
|
||||
__WASI_ENOBUFS => "__WASI_ENOBUFS",
|
||||
__WASI_ENODEV => "__WASI_ENODEV",
|
||||
__WASI_ENOENT => "__WASI_ENOENT",
|
||||
__WASI_ENOEXEC => "__WASI_ENOEXEC",
|
||||
__WASI_ENOLCK => "__WASI_ENOLCK",
|
||||
__WASI_ENOLINK => "__WASI_ENOLINK",
|
||||
__WASI_ENOMEM => "__WASI_ENOMEM",
|
||||
__WASI_ENOMSG => "__WASI_ENOMSG",
|
||||
__WASI_ENOPROTOOPT => "__WASI_ENOPROTOOPT",
|
||||
__WASI_ENOSPC => "__WASI_ENOSPC",
|
||||
__WASI_ENOSYS => "__WASI_ENOSYS",
|
||||
__WASI_ENOTCONN => "__WASI_ENOTCONN",
|
||||
__WASI_ENOTDIR => "__WASI_ENOTDIR",
|
||||
__WASI_ENOTEMPTY => "__WASI_ENOTEMPTY",
|
||||
__WASI_ENOTRECOVERABLE => "__WASI_ENOTRECOVERABLE",
|
||||
__WASI_ENOTSOCK => "__WASI_ENOTSOCK",
|
||||
__WASI_ENOTSUP => "__WASI_ENOTSUP",
|
||||
__WASI_ENOTTY => "__WASI_ENOTTY",
|
||||
__WASI_ENXIO => "__WASI_ENXIO",
|
||||
__WASI_EOVERFLOW => "__WASI_EOVERFLOW",
|
||||
__WASI_EOWNERDEAD => "__WASI_EOWNERDEAD",
|
||||
__WASI_EPERM => "__WASI_EPERM",
|
||||
__WASI_EPIPE => "__WASI_EPIPE",
|
||||
__WASI_EPROTO => "__WASI_EPROTO",
|
||||
__WASI_EPROTONOSUPPORT => "__WASI_EPROTONOSUPPORT",
|
||||
__WASI_EPROTOTYPE => "__WASI_EPROTOTYPE",
|
||||
__WASI_ERANGE => "__WASI_ERANGE",
|
||||
__WASI_EROFS => "__WASI_EROFS",
|
||||
__WASI_ESPIPE => "__WASI_ESPIPE",
|
||||
__WASI_ESRCH => "__WASI_ESRCH",
|
||||
__WASI_ESTALE => "__WASI_ESTALE",
|
||||
__WASI_ETIMEDOUT => "__WASI_ETIMEDOUT",
|
||||
__WASI_ETXTBSY => "__WASI_ETXTBSY",
|
||||
__WASI_EXDEV => "__WASI_EXDEV",
|
||||
__WASI_ENOTCAPABLE => "__WASI_ENOTCAPABLE",
|
||||
__WASI_ERRNO_SUCCESS => "__WASI_ERRNO_SUCCESS",
|
||||
__WASI_ERRNO_2BIG => "__WASI_ERRNO_2BIG",
|
||||
__WASI_ERRNO_ACCES => "__WASI_ERRNO_ACCES",
|
||||
__WASI_ERRNO_ADDRINUSE => "__WASI_ERRNO_ADDRINUSE",
|
||||
__WASI_ERRNO_ADDRNOTAVAIL => "__WASI_ERRNO_ADDRNOTAVAIL",
|
||||
__WASI_ERRNO_AFNOSUPPORT => "__WASI_ERRNO_AFNOSUPPORT",
|
||||
__WASI_ERRNO_AGAIN => "__WASI_ERRNO_AGAIN",
|
||||
__WASI_ERRNO_ALREADY => "__WASI_ERRNO_ALREADY",
|
||||
__WASI_ERRNO_BADF => "__WASI_ERRNO_BADF",
|
||||
__WASI_ERRNO_BADMSG => "__WASI_ERRNO_BADMSG",
|
||||
__WASI_ERRNO_BUSY => "__WASI_ERRNO_BUSY",
|
||||
__WASI_ERRNO_CANCELED => "__WASI_ERRNO_CANCELED",
|
||||
__WASI_ERRNO_CHILD => "__WASI_ERRNO_CHILD",
|
||||
__WASI_ERRNO_CONNABORTED => "__WASI_ERRNO_CONNABORTED",
|
||||
__WASI_ERRNO_CONNREFUSED => "__WASI_ERRNO_CONNREFUSED",
|
||||
__WASI_ERRNO_CONNRESET => "__WASI_ERRNO_CONNRESET",
|
||||
__WASI_ERRNO_DEADLK => "__WASI_ERRNO_DEADLK",
|
||||
__WASI_ERRNO_DESTADDRREQ => "__WASI_ERRNO_DESTADDRREQ",
|
||||
__WASI_ERRNO_DOM => "__WASI_ERRNO_DOM",
|
||||
__WASI_ERRNO_DQUOT => "__WASI_ERRNO_DQUOT",
|
||||
__WASI_ERRNO_EXIST => "__WASI_ERRNO_EXIST",
|
||||
__WASI_ERRNO_FAULT => "__WASI_ERRNO_FAULT",
|
||||
__WASI_ERRNO_FBIG => "__WASI_ERRNO_FBIG",
|
||||
__WASI_ERRNO_HOSTUNREACH => "__WASI_ERRNO_HOSTUNREACH",
|
||||
__WASI_ERRNO_IDRM => "__WASI_ERRNO_IDRM",
|
||||
__WASI_ERRNO_ILSEQ => "__WASI_ERRNO_ILSEQ",
|
||||
__WASI_ERRNO_INPROGRESS => "__WASI_ERRNO_INPROGRESS",
|
||||
__WASI_ERRNO_INTR => "__WASI_ERRNO_INTR",
|
||||
__WASI_ERRNO_INVAL => "__WASI_ERRNO_INVAL",
|
||||
__WASI_ERRNO_IO => "__WASI_ERRNO_IO",
|
||||
__WASI_ERRNO_ISCONN => "__WASI_ERRNO_ISCONN",
|
||||
__WASI_ERRNO_ISDIR => "__WASI_ERRNO_ISDIR",
|
||||
__WASI_ERRNO_LOOP => "__WASI_ERRNO_LOOP",
|
||||
__WASI_ERRNO_MFILE => "__WASI_ERRNO_MFILE",
|
||||
__WASI_ERRNO_MLINK => "__WASI_ERRNO_MLINK",
|
||||
__WASI_ERRNO_MSGSIZE => "__WASI_ERRNO_MSGSIZE",
|
||||
__WASI_ERRNO_MULTIHOP => "__WASI_ERRNO_MULTIHOP",
|
||||
__WASI_ERRNO_NAMETOOLONG => "__WASI_ERRNO_NAMETOOLONG",
|
||||
__WASI_ERRNO_NETDOWN => "__WASI_ERRNO_NETDOWN",
|
||||
__WASI_ERRNO_NETRESET => "__WASI_ERRNO_NETRESET",
|
||||
__WASI_ERRNO_NETUNREACH => "__WASI_ERRNO_NETUNREACH",
|
||||
__WASI_ERRNO_NFILE => "__WASI_ERRNO_NFILE",
|
||||
__WASI_ERRNO_NOBUFS => "__WASI_ERRNO_NOBUFS",
|
||||
__WASI_ERRNO_NODEV => "__WASI_ERRNO_NODEV",
|
||||
__WASI_ERRNO_NOENT => "__WASI_ERRNO_NOENT",
|
||||
__WASI_ERRNO_NOEXEC => "__WASI_ERRNO_NOEXEC",
|
||||
__WASI_ERRNO_NOLCK => "__WASI_ERRNO_NOLCK",
|
||||
__WASI_ERRNO_NOLINK => "__WASI_ERRNO_NOLINK",
|
||||
__WASI_ERRNO_NOMEM => "__WASI_ERRNO_NOMEM",
|
||||
__WASI_ERRNO_NOMSG => "__WASI_ERRNO_NOMSG",
|
||||
__WASI_ERRNO_NOPROTOOPT => "__WASI_ERRNO_NOPROTOOPT",
|
||||
__WASI_ERRNO_NOSPC => "__WASI_ERRNO_NOSPC",
|
||||
__WASI_ERRNO_NOSYS => "__WASI_ERRNO_NOSYS",
|
||||
__WASI_ERRNO_NOTCONN => "__WASI_ERRNO_NOTCONN",
|
||||
__WASI_ERRNO_NOTDIR => "__WASI_ERRNO_NOTDIR",
|
||||
__WASI_ERRNO_NOTEMPTY => "__WASI_ERRNO_NOTEMPTY",
|
||||
__WASI_ERRNO_NOTRECOVERABLE => "__WASI_ERRNO_NOTRECOVERABLE",
|
||||
__WASI_ERRNO_NOTSOCK => "__WASI_ERRNO_NOTSOCK",
|
||||
__WASI_ERRNO_NOTSUP => "__WASI_ERRNO_NOTSUP",
|
||||
__WASI_ERRNO_NOTTY => "__WASI_ERRNO_NOTTY",
|
||||
__WASI_ERRNO_NXIO => "__WASI_ERRNO_NXIO",
|
||||
__WASI_ERRNO_OVERFLOW => "__WASI_ERRNO_OVERFLOW",
|
||||
__WASI_ERRNO_OWNERDEAD => "__WASI_ERRNO_OWNERDEAD",
|
||||
__WASI_ERRNO_PERM => "__WASI_ERRNO_PERM",
|
||||
__WASI_ERRNO_PIPE => "__WASI_ERRNO_PIPE",
|
||||
__WASI_ERRNO_PROTO => "__WASI_ERRNO_PROTO",
|
||||
__WASI_ERRNO_PROTONOSUPPORT => "__WASI_ERRNO_PROTONOSUPPORT",
|
||||
__WASI_ERRNO_PROTOTYPE => "__WASI_ERRNO_PROTOTYPE",
|
||||
__WASI_ERRNO_RANGE => "__WASI_ERRNO_RANGE",
|
||||
__WASI_ERRNO_ROFS => "__WASI_ERRNO_ROFS",
|
||||
__WASI_ERRNO_SPIPE => "__WASI_ERRNO_SPIPE",
|
||||
__WASI_ERRNO_SRCH => "__WASI_ERRNO_SRCH",
|
||||
__WASI_ERRNO_STALE => "__WASI_ERRNO_STALE",
|
||||
__WASI_ERRNO_TIMEDOUT => "__WASI_ERRNO_TIMEDOUT",
|
||||
__WASI_ERRNO_TXTBSY => "__WASI_ERRNO_TXTBSY",
|
||||
__WASI_ERRNO_XDEV => "__WASI_ERRNO_XDEV",
|
||||
__WASI_ERRNO_NOTCAPABLE => "__WASI_ERRNO_NOTCAPABLE",
|
||||
other => panic!("Undefined errno value {:?}", other),
|
||||
}
|
||||
}
|
||||
@@ -295,21 +295,23 @@ mod test {
|
||||
#[test]
|
||||
fn bindgen_test_layout___wasi_event_t___wasi_event_u() {
|
||||
assert_eq!(
|
||||
::std::mem::size_of::<__wasi_event_u>(),
|
||||
::std::mem::size_of::<__wasi_event_u_t>(),
|
||||
16usize,
|
||||
concat!("Size of: ", stringify!(__wasi_event_u))
|
||||
concat!("Size of: ", stringify!(__wasi_event_u_t))
|
||||
);
|
||||
assert_eq!(
|
||||
::std::mem::align_of::<__wasi_event_u>(),
|
||||
::std::mem::align_of::<__wasi_event_u_t>(),
|
||||
8usize,
|
||||
concat!("Alignment of ", stringify!(__wasi_event_u))
|
||||
concat!("Alignment of ", stringify!(__wasi_event_u_t))
|
||||
);
|
||||
assert_eq!(
|
||||
unsafe { &(*(::std::ptr::null::<__wasi_event_u>())).fd_readwrite as *const _ as usize },
|
||||
unsafe {
|
||||
&(*(::std::ptr::null::<__wasi_event_u_t>())).fd_readwrite as *const _ as usize
|
||||
},
|
||||
0usize,
|
||||
concat!(
|
||||
"Offset of field: ",
|
||||
stringify!(__wasi_event_u),
|
||||
stringify!(__wasi_event_u_t),
|
||||
"::",
|
||||
stringify!(fd_readwrite)
|
||||
)
|
||||
@@ -467,11 +469,11 @@ mod test {
|
||||
fn bindgen_test_layout_wasi_filestat_t() {
|
||||
assert_eq!(
|
||||
::std::mem::size_of::<__wasi_filestat_t>(),
|
||||
56usize,
|
||||
64usize,
|
||||
concat!("Size of: ", stringify!(__wasi_filestat_t))
|
||||
);
|
||||
assert_eq!(
|
||||
unsafe { &(*(::std::ptr::null::<__wasi_filestat_t>())).st_dev as *const _ as usize },
|
||||
unsafe { &(*(::std::ptr::null::<__wasi_filestat_t>())).dev as *const _ as usize },
|
||||
0usize,
|
||||
concat!(
|
||||
"Offset of field: ",
|
||||
@@ -481,7 +483,7 @@ mod test {
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
unsafe { &(*(::std::ptr::null::<__wasi_filestat_t>())).st_ino as *const _ as usize },
|
||||
unsafe { &(*(::std::ptr::null::<__wasi_filestat_t>())).ino as *const _ as usize },
|
||||
8usize,
|
||||
concat!(
|
||||
"Offset of field: ",
|
||||
@@ -491,9 +493,7 @@ mod test {
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
unsafe {
|
||||
&(*(::std::ptr::null::<__wasi_filestat_t>())).st_filetype as *const _ as usize
|
||||
},
|
||||
unsafe { &(*(::std::ptr::null::<__wasi_filestat_t>())).filetype as *const _ as usize },
|
||||
16usize,
|
||||
concat!(
|
||||
"Offset of field: ",
|
||||
@@ -503,8 +503,8 @@ mod test {
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
unsafe { &(*(::std::ptr::null::<__wasi_filestat_t>())).st_nlink as *const _ as usize },
|
||||
20usize,
|
||||
unsafe { &(*(::std::ptr::null::<__wasi_filestat_t>())).nlink as *const _ as usize },
|
||||
24usize,
|
||||
concat!(
|
||||
"Offset of field: ",
|
||||
stringify!(__wasi_filestat_t),
|
||||
@@ -513,8 +513,8 @@ mod test {
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
unsafe { &(*(::std::ptr::null::<__wasi_filestat_t>())).st_size as *const _ as usize },
|
||||
24usize,
|
||||
unsafe { &(*(::std::ptr::null::<__wasi_filestat_t>())).size as *const _ as usize },
|
||||
32usize,
|
||||
concat!(
|
||||
"Offset of field: ",
|
||||
stringify!(__wasi_filestat_t),
|
||||
@@ -523,8 +523,8 @@ mod test {
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
unsafe { &(*(::std::ptr::null::<__wasi_filestat_t>())).st_atim as *const _ as usize },
|
||||
32usize,
|
||||
unsafe { &(*(::std::ptr::null::<__wasi_filestat_t>())).atim as *const _ as usize },
|
||||
40usize,
|
||||
concat!(
|
||||
"Offset of field: ",
|
||||
stringify!(__wasi_filestat_t),
|
||||
@@ -533,8 +533,8 @@ mod test {
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
unsafe { &(*(::std::ptr::null::<__wasi_filestat_t>())).st_mtim as *const _ as usize },
|
||||
40usize,
|
||||
unsafe { &(*(::std::ptr::null::<__wasi_filestat_t>())).mtim as *const _ as usize },
|
||||
48usize,
|
||||
concat!(
|
||||
"Offset of field: ",
|
||||
stringify!(__wasi_filestat_t),
|
||||
@@ -543,8 +543,8 @@ mod test {
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
unsafe { &(*(::std::ptr::null::<__wasi_filestat_t>())).st_ctim as *const _ as usize },
|
||||
48usize,
|
||||
unsafe { &(*(::std::ptr::null::<__wasi_filestat_t>())).ctim as *const _ as usize },
|
||||
56usize,
|
||||
concat!(
|
||||
"Offset of field: ",
|
||||
stringify!(__wasi_filestat_t),
|
||||
@@ -558,7 +558,7 @@ mod test {
|
||||
fn bindgen_test_layout___wasi_subscription_clock_t() {
|
||||
assert_eq!(
|
||||
::std::mem::size_of::<__wasi_subscription_clock_t>(),
|
||||
40usize,
|
||||
32usize,
|
||||
concat!("Size of: ", stringify!(__wasi_subscription_clock_t))
|
||||
);
|
||||
assert_eq!(
|
||||
@@ -568,23 +568,9 @@ mod test {
|
||||
);
|
||||
assert_eq!(
|
||||
unsafe {
|
||||
&(*(::std::ptr::null::<__wasi_subscription_clock_t>())).identifier as *const _
|
||||
as usize
|
||||
&(*(::std::ptr::null::<__wasi_subscription_clock_t>())).id as *const _ as usize
|
||||
},
|
||||
0usize,
|
||||
concat!(
|
||||
"Offset of field: ",
|
||||
stringify!(__wasi_subscription_clock_t),
|
||||
"::",
|
||||
stringify!(identifier)
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
unsafe {
|
||||
&(*(::std::ptr::null::<__wasi_subscription_clock_t>())).clock_id as *const _
|
||||
as usize
|
||||
},
|
||||
8usize,
|
||||
concat!(
|
||||
"Offset of field: ",
|
||||
stringify!(__wasi_subscription_clock_t),
|
||||
@@ -596,7 +582,7 @@ mod test {
|
||||
unsafe {
|
||||
&(*(::std::ptr::null::<__wasi_subscription_clock_t>())).timeout as *const _ as usize
|
||||
},
|
||||
16usize,
|
||||
8usize,
|
||||
concat!(
|
||||
"Offset of field: ",
|
||||
stringify!(__wasi_subscription_clock_t),
|
||||
@@ -609,7 +595,7 @@ mod test {
|
||||
&(*(::std::ptr::null::<__wasi_subscription_clock_t>())).precision as *const _
|
||||
as usize
|
||||
},
|
||||
24usize,
|
||||
16usize,
|
||||
concat!(
|
||||
"Offset of field: ",
|
||||
stringify!(__wasi_subscription_clock_t),
|
||||
@@ -621,7 +607,7 @@ mod test {
|
||||
unsafe {
|
||||
&(*(::std::ptr::null::<__wasi_subscription_clock_t>())).flags as *const _ as usize
|
||||
},
|
||||
32usize,
|
||||
24usize,
|
||||
concat!(
|
||||
"Offset of field: ",
|
||||
stringify!(__wasi_subscription_clock_t),
|
||||
@@ -665,33 +651,36 @@ mod test {
|
||||
#[test]
|
||||
fn bindgen_test_layout___wasi_subscription_t___wasi_subscription_u() {
|
||||
assert_eq!(
|
||||
::std::mem::size_of::<__wasi_subscription_u>(),
|
||||
40usize,
|
||||
concat!("Size of: ", stringify!(__wasi_subscription_u))
|
||||
::std::mem::size_of::<__wasi_subscription_u_t>(),
|
||||
32usize,
|
||||
concat!("Size of: ", stringify!(__wasi_subscription_u_t))
|
||||
);
|
||||
assert_eq!(
|
||||
::std::mem::align_of::<__wasi_subscription_u>(),
|
||||
::std::mem::align_of::<__wasi_subscription_u_t>(),
|
||||
8usize,
|
||||
concat!("Alignment of ", stringify!(__wasi_subscription_u))
|
||||
concat!("Alignment of ", stringify!(__wasi_subscription_u_t))
|
||||
);
|
||||
assert_eq!(
|
||||
unsafe { &(*(::std::ptr::null::<__wasi_subscription_u>())).clock as *const _ as usize },
|
||||
unsafe {
|
||||
&(*(::std::ptr::null::<__wasi_subscription_u_t>())).clock as *const _ as usize
|
||||
},
|
||||
0usize,
|
||||
concat!(
|
||||
"Offset of field: ",
|
||||
stringify!(__wasi_subscription_u),
|
||||
stringify!(__wasi_subscription_u_t),
|
||||
"::",
|
||||
stringify!(clock)
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
unsafe {
|
||||
&(*(::std::ptr::null::<__wasi_subscription_u>())).fd_readwrite as *const _ as usize
|
||||
&(*(::std::ptr::null::<__wasi_subscription_u_t>())).fd_readwrite as *const _
|
||||
as usize
|
||||
},
|
||||
0usize,
|
||||
concat!(
|
||||
"Offset of field: ",
|
||||
stringify!(__wasi_subscription_u),
|
||||
stringify!(__wasi_subscription_u_t),
|
||||
"::",
|
||||
stringify!(fd_readwrite)
|
||||
)
|
||||
@@ -702,7 +691,7 @@ mod test {
|
||||
fn bindgen_test_layout___wasi_subscription_t() {
|
||||
assert_eq!(
|
||||
::std::mem::size_of::<__wasi_subscription_t>(),
|
||||
56usize,
|
||||
48usize,
|
||||
concat!("Size of: ", stringify!(__wasi_subscription_t))
|
||||
);
|
||||
assert_eq!(
|
||||
@@ -750,7 +739,7 @@ mod test {
|
||||
fn bindgen_test_layout___wasi_filestat_t() {
|
||||
assert_eq!(
|
||||
::std::mem::size_of::<__wasi_filestat_t>(),
|
||||
56usize,
|
||||
64usize,
|
||||
concat!("Size of: ", stringify!(__wasi_filestat_t))
|
||||
);
|
||||
assert_eq!(
|
||||
@@ -759,7 +748,7 @@ mod test {
|
||||
concat!("Alignment of ", stringify!(__wasi_filestat_t))
|
||||
);
|
||||
assert_eq!(
|
||||
unsafe { &(*(::std::ptr::null::<__wasi_filestat_t>())).st_dev as *const _ as usize },
|
||||
unsafe { &(*(::std::ptr::null::<__wasi_filestat_t>())).dev as *const _ as usize },
|
||||
0usize,
|
||||
concat!(
|
||||
"Offset of field: ",
|
||||
@@ -769,7 +758,7 @@ mod test {
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
unsafe { &(*(::std::ptr::null::<__wasi_filestat_t>())).st_ino as *const _ as usize },
|
||||
unsafe { &(*(::std::ptr::null::<__wasi_filestat_t>())).ino as *const _ as usize },
|
||||
8usize,
|
||||
concat!(
|
||||
"Offset of field: ",
|
||||
@@ -779,9 +768,7 @@ mod test {
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
unsafe {
|
||||
&(*(::std::ptr::null::<__wasi_filestat_t>())).st_filetype as *const _ as usize
|
||||
},
|
||||
unsafe { &(*(::std::ptr::null::<__wasi_filestat_t>())).filetype as *const _ as usize },
|
||||
16usize,
|
||||
concat!(
|
||||
"Offset of field: ",
|
||||
@@ -791,8 +778,8 @@ mod test {
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
unsafe { &(*(::std::ptr::null::<__wasi_filestat_t>())).st_nlink as *const _ as usize },
|
||||
20usize,
|
||||
unsafe { &(*(::std::ptr::null::<__wasi_filestat_t>())).nlink as *const _ as usize },
|
||||
24usize,
|
||||
concat!(
|
||||
"Offset of field: ",
|
||||
stringify!(__wasi_filestat_t),
|
||||
@@ -801,8 +788,8 @@ mod test {
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
unsafe { &(*(::std::ptr::null::<__wasi_filestat_t>())).st_size as *const _ as usize },
|
||||
24usize,
|
||||
unsafe { &(*(::std::ptr::null::<__wasi_filestat_t>())).size as *const _ as usize },
|
||||
32usize,
|
||||
concat!(
|
||||
"Offset of field: ",
|
||||
stringify!(__wasi_filestat_t),
|
||||
@@ -811,8 +798,8 @@ mod test {
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
unsafe { &(*(::std::ptr::null::<__wasi_filestat_t>())).st_atim as *const _ as usize },
|
||||
32usize,
|
||||
unsafe { &(*(::std::ptr::null::<__wasi_filestat_t>())).atim as *const _ as usize },
|
||||
40usize,
|
||||
concat!(
|
||||
"Offset of field: ",
|
||||
stringify!(__wasi_filestat_t),
|
||||
@@ -821,8 +808,8 @@ mod test {
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
unsafe { &(*(::std::ptr::null::<__wasi_filestat_t>())).st_mtim as *const _ as usize },
|
||||
40usize,
|
||||
unsafe { &(*(::std::ptr::null::<__wasi_filestat_t>())).mtim as *const _ as usize },
|
||||
48usize,
|
||||
concat!(
|
||||
"Offset of field: ",
|
||||
stringify!(__wasi_filestat_t),
|
||||
@@ -831,8 +818,8 @@ mod test {
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
unsafe { &(*(::std::ptr::null::<__wasi_filestat_t>())).st_ctim as *const _ as usize },
|
||||
48usize,
|
||||
unsafe { &(*(::std::ptr::null::<__wasi_filestat_t>())).ctim as *const _ as usize },
|
||||
56usize,
|
||||
concat!(
|
||||
"Offset of field: ",
|
||||
stringify!(__wasi_filestat_t),
|
||||
|
||||
@@ -12,7 +12,7 @@ use wig::witx_wasi32_types;
|
||||
pub type uintptr_t = u32;
|
||||
pub type size_t = u32;
|
||||
|
||||
witx_wasi32_types!("unstable" "wasi_unstable_preview0");
|
||||
witx_wasi32_types!("snapshot" "wasi_snapshot_preview1");
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
@@ -89,23 +89,23 @@ mod test {
|
||||
#[test]
|
||||
fn bindgen_test_layout___wasi_prestat_t___wasi_prestat_u___wasi_prestat_u_dir_t() {
|
||||
assert_eq!(
|
||||
::std::mem::size_of::<__wasi_prestat_dir>(),
|
||||
::std::mem::size_of::<__wasi_prestat_dir_t>(),
|
||||
4usize,
|
||||
concat!("Size of: ", stringify!(__wasi_prestat_dir))
|
||||
concat!("Size of: ", stringify!(__wasi_prestat_dir_t))
|
||||
);
|
||||
assert_eq!(
|
||||
::std::mem::align_of::<__wasi_prestat_dir>(),
|
||||
::std::mem::align_of::<__wasi_prestat_dir_t>(),
|
||||
4usize,
|
||||
concat!("Alignment of ", stringify!(__wasi_prestat_dir))
|
||||
concat!("Alignment of ", stringify!(__wasi_prestat_dir_t))
|
||||
);
|
||||
assert_eq!(
|
||||
unsafe {
|
||||
&(*(::std::ptr::null::<__wasi_prestat_dir>())).pr_name_len as *const _ as usize
|
||||
&(*(::std::ptr::null::<__wasi_prestat_dir_t>())).pr_name_len as *const _ as usize
|
||||
},
|
||||
0usize,
|
||||
concat!(
|
||||
"Offset of field: ",
|
||||
stringify!(__wasi_prestat_dir),
|
||||
stringify!(__wasi_prestat_dir_t),
|
||||
"::",
|
||||
stringify!(pr_name_len)
|
||||
)
|
||||
@@ -115,21 +115,21 @@ mod test {
|
||||
#[test]
|
||||
fn bindgen_test_layout___wasi_prestat_t___wasi_prestat_u() {
|
||||
assert_eq!(
|
||||
::std::mem::size_of::<__wasi_prestat_u>(),
|
||||
::std::mem::size_of::<__wasi_prestat_u_t>(),
|
||||
4usize,
|
||||
concat!("Size of: ", stringify!(__wasi_prestat_u))
|
||||
concat!("Size of: ", stringify!(__wasi_prestat_u_t))
|
||||
);
|
||||
assert_eq!(
|
||||
::std::mem::align_of::<__wasi_prestat_u>(),
|
||||
::std::mem::align_of::<__wasi_prestat_u_t>(),
|
||||
4usize,
|
||||
concat!("Alignment of ", stringify!(__wasi_prestat_u))
|
||||
concat!("Alignment of ", stringify!(__wasi_prestat_u_t))
|
||||
);
|
||||
assert_eq!(
|
||||
unsafe { &(*(::std::ptr::null::<__wasi_prestat_u>())).dir as *const _ as usize },
|
||||
unsafe { &(*(::std::ptr::null::<__wasi_prestat_u_t>())).dir as *const _ as usize },
|
||||
0usize,
|
||||
concat!(
|
||||
"Offset of field: ",
|
||||
stringify!(__wasi_prestat_u),
|
||||
stringify!(__wasi_prestat_u_t),
|
||||
"::",
|
||||
stringify!(dir)
|
||||
)
|
||||
|
||||
@@ -13,6 +13,7 @@ proc-macro = true
|
||||
[dependencies]
|
||||
syn = { version = "1.0.5", features = ["full"] }
|
||||
quote = "1.0.2"
|
||||
proc-macro2 = "1.0.6"
|
||||
|
||||
[dev-dependencies]
|
||||
trybuild = "1.0.4"
|
||||
|
||||
@@ -4,21 +4,13 @@ use proc_macro::TokenStream;
|
||||
use quote::quote;
|
||||
use syn::{FnArg, Pat, PatType, Type, TypeReference, TypeSlice};
|
||||
|
||||
#[proc_macro_attribute]
|
||||
pub fn wasi_common_cbindgen(attr: TokenStream, function: TokenStream) -> TokenStream {
|
||||
assert!(attr.is_empty());
|
||||
|
||||
let function = syn::parse_macro_input!(function as syn::ItemFn);
|
||||
|
||||
// capture visibility
|
||||
let vis = &function.vis;
|
||||
|
||||
// generate C fn name prefixed with __wasi_
|
||||
let fn_ident = &function.sig.ident;
|
||||
let concatenated = format!("wasi_common_{}", fn_ident);
|
||||
let c_fn_ident = syn::Ident::new(&concatenated, fn_ident.span());
|
||||
|
||||
// capture input args
|
||||
fn capture_input_args(
|
||||
function: &syn::ItemFn,
|
||||
) -> (
|
||||
Vec<proc_macro2::TokenStream>,
|
||||
Vec<proc_macro2::TokenStream>,
|
||||
Vec<proc_macro2::TokenStream>,
|
||||
) {
|
||||
let mut arg_ident = Vec::new();
|
||||
let mut arg_type = Vec::new();
|
||||
let mut call_arg_ident = Vec::new();
|
||||
@@ -85,6 +77,26 @@ pub fn wasi_common_cbindgen(attr: TokenStream, function: TokenStream) -> TokenSt
|
||||
}
|
||||
}
|
||||
|
||||
(arg_ident, arg_type, call_arg_ident)
|
||||
}
|
||||
|
||||
#[proc_macro_attribute]
|
||||
pub fn wasi_common_cbindgen(attr: TokenStream, function: TokenStream) -> TokenStream {
|
||||
assert!(attr.is_empty());
|
||||
|
||||
let function = syn::parse_macro_input!(function as syn::ItemFn);
|
||||
|
||||
// capture visibility
|
||||
let vis = &function.vis;
|
||||
|
||||
// generate C fn name prefixed with wasi_common_
|
||||
let fn_ident = &function.sig.ident;
|
||||
let concatenated = format!("wasi_common_{}", fn_ident);
|
||||
let c_fn_ident = syn::Ident::new(&concatenated, fn_ident.span());
|
||||
|
||||
// capture input args
|
||||
let (arg_ident, arg_type, call_arg_ident) = capture_input_args(&function);
|
||||
|
||||
// capture output arg
|
||||
let output = &function.sig.output;
|
||||
|
||||
@@ -105,3 +117,40 @@ pub fn wasi_common_cbindgen(attr: TokenStream, function: TokenStream) -> TokenSt
|
||||
|
||||
result.into()
|
||||
}
|
||||
|
||||
#[proc_macro_attribute]
|
||||
pub fn wasi_common_cbindgen_old(attr: TokenStream, function: TokenStream) -> TokenStream {
|
||||
assert!(attr.is_empty());
|
||||
|
||||
let function = syn::parse_macro_input!(function as syn::ItemFn);
|
||||
|
||||
// capture visibility
|
||||
let vis = &function.vis;
|
||||
|
||||
// generate C fn name prefixed with old_wasi_common_
|
||||
let fn_ident = &function.sig.ident;
|
||||
let concatenated = format!("old_wasi_common_{}", fn_ident);
|
||||
let c_fn_ident = syn::Ident::new(&concatenated, fn_ident.span());
|
||||
|
||||
// capture input args
|
||||
let (arg_ident, arg_type, call_arg_ident) = capture_input_args(&function);
|
||||
|
||||
// capture output arg
|
||||
let output = &function.sig.output;
|
||||
|
||||
let result = quote! {
|
||||
#function
|
||||
|
||||
#vis unsafe extern "C" fn #c_fn_ident(
|
||||
#(
|
||||
#arg_ident: #arg_type,
|
||||
)*
|
||||
) #output {
|
||||
#fn_ident(#(
|
||||
#call_arg_ident,
|
||||
)*)
|
||||
}
|
||||
};
|
||||
|
||||
result.into()
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ proc-macro = true
|
||||
[dependencies]
|
||||
quote = "1.0.2"
|
||||
proc-macro2 = "1.0.6"
|
||||
heck = "0.3.1"
|
||||
# We include the WASI repo primarily for the witx files, but it's also useful
|
||||
# to use the witx parser it contains, rather than the witx crate from
|
||||
# crates.io, so that it always matches the version of the witx files.
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
//! Translate witx types to Rust.
|
||||
|
||||
use crate::utils;
|
||||
use heck::ShoutySnakeCase;
|
||||
use proc_macro2::{Delimiter, Group, Literal, TokenStream, TokenTree};
|
||||
use quote::{format_ident, quote};
|
||||
use std::convert::TryFrom;
|
||||
@@ -25,7 +26,7 @@ pub fn gen(args: TokenStream, mode: Mode) -> TokenStream {
|
||||
let mut output = TokenStream::new();
|
||||
|
||||
let (path, _phase) = utils::witx_path_from_args(args);
|
||||
let doc = match witx::load(&path) {
|
||||
let doc = match witx::load(&[&path]) {
|
||||
Ok(doc) => doc,
|
||||
Err(e) => {
|
||||
panic!("error opening file {}: {}", path, e);
|
||||
@@ -55,35 +56,43 @@ fn gen_datatype(
|
||||
) {
|
||||
match &datatype.variant {
|
||||
witx::DatatypeVariant::Alias(a) => {
|
||||
if a.name.as_str() == "size_t" {
|
||||
let wasi_name = format_ident!("__wasi_{}", a.name.as_str());
|
||||
if a.name.as_str() == "size" {
|
||||
let wasi_name = format_ident!("__wasi_{}_t", a.name.as_str());
|
||||
match mode {
|
||||
Mode::Host => output.extend(quote!(pub type #wasi_name = usize;)),
|
||||
Mode::Wasi => panic!("size_t has target-specific size"),
|
||||
Mode::Wasi => panic!("size has target-specific size"),
|
||||
Mode::Wasi32 => output.extend(quote!(pub type #wasi_name = u32;)),
|
||||
}
|
||||
} else {
|
||||
let wasi_name = format_ident!("__wasi_{}", a.name.as_str());
|
||||
let wasi_name = format_ident!("__wasi_{}_t", a.name.as_str());
|
||||
let to = ident_tokens(mode, &a.to);
|
||||
output.extend(quote!(pub type #wasi_name = #to;));
|
||||
}
|
||||
}
|
||||
witx::DatatypeVariant::Enum(e) => {
|
||||
let wasi_name = format_ident!("__wasi_{}", e.name.as_str());
|
||||
let wasi_name = format_ident!("__wasi_{}_t", e.name.as_str());
|
||||
let repr = int_repr_tokens(e.repr);
|
||||
output.extend(quote!(pub type #wasi_name = #repr;));
|
||||
for (index, variant) in e.variants.iter().enumerate() {
|
||||
let value_name = format_ident!("__WASI_{}", variant.as_str());
|
||||
let value_name = format_ident!(
|
||||
"__WASI_{}_{}",
|
||||
e.name.as_str().to_shouty_snake_case(),
|
||||
variant.name.as_str().to_shouty_snake_case()
|
||||
);
|
||||
let index_name = Literal::usize_unsuffixed(index);
|
||||
output.extend(quote!(pub const #value_name: #wasi_name = #index_name;));
|
||||
}
|
||||
}
|
||||
witx::DatatypeVariant::Flags(f) => {
|
||||
let wasi_name = format_ident!("__wasi_{}", f.name.as_str());
|
||||
let wasi_name = format_ident!("__wasi_{}_t", f.name.as_str());
|
||||
let repr = int_repr_tokens(f.repr);
|
||||
output.extend(quote!(pub type #wasi_name = #repr;));
|
||||
for (index, flag) in f.flags.iter().enumerate() {
|
||||
let value_name = format_ident!("__WASI_{}", flag.as_str());
|
||||
let value_name = format_ident!(
|
||||
"__WASI_{}_{}",
|
||||
f.name.as_str().to_shouty_snake_case(),
|
||||
flag.name.as_str().to_shouty_snake_case()
|
||||
);
|
||||
let flag_value = Literal::u128_unsuffixed(
|
||||
1u128
|
||||
.checked_shl(u32::try_from(index).expect("flag value overflow"))
|
||||
@@ -105,7 +114,7 @@ fn gen_datatype(
|
||||
output.extend(quote!(#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]));
|
||||
}
|
||||
|
||||
let wasi_name = format_ident!("__wasi_{}", s.name.as_str());
|
||||
let wasi_name = format_ident!("__wasi_{}_t", s.name.as_str());
|
||||
output.extend(quote!(pub struct #wasi_name));
|
||||
|
||||
let mut inner = TokenStream::new();
|
||||
@@ -122,7 +131,7 @@ fn gen_datatype(
|
||||
output.extend(quote!(#[derive(Copy, Clone)]));
|
||||
output.extend(quote!(#[allow(missing_debug_implementations)]));
|
||||
|
||||
let wasi_name = format_ident!("__wasi_{}", u.name.as_str());
|
||||
let wasi_name = format_ident!("__wasi_{}_t", u.name.as_str());
|
||||
output.extend(quote!(pub union #wasi_name));
|
||||
|
||||
let mut inner = TokenStream::new();
|
||||
@@ -134,6 +143,10 @@ fn gen_datatype(
|
||||
let braced = Group::new(Delimiter::Brace, inner);
|
||||
output.extend(TokenStream::from(TokenTree::Group(braced)));
|
||||
}
|
||||
witx::DatatypeVariant::Handle(a) => {
|
||||
let wasi_name = format_ident!("__wasi_{}_t", a.name.as_str());
|
||||
output.extend(quote!(pub type #wasi_name = u32;));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -170,7 +183,7 @@ fn ident_tokens(mode: Mode, ident: &witx::DatatypeIdent) -> TokenStream {
|
||||
match ident {
|
||||
witx::DatatypeIdent::Builtin(builtin) => builtin_tokens(mode, *builtin),
|
||||
witx::DatatypeIdent::Ident(ident) => TokenStream::from(TokenTree::Ident(format_ident!(
|
||||
"__wasi_{}",
|
||||
"__wasi_{}_t",
|
||||
ident.name.as_str()
|
||||
))),
|
||||
witx::DatatypeIdent::Pointer(pointee) => {
|
||||
@@ -216,7 +229,7 @@ fn struct_has_union(doc: &witx::Document, s: &witx::StructDatatype) -> bool {
|
||||
fn type_has_target_size(doc: &witx::Document, type_: &witx::Datatype) -> bool {
|
||||
match &type_.variant {
|
||||
witx::DatatypeVariant::Alias(a) => {
|
||||
a.name.as_str() == "size_t" || ident_has_target_size(doc, &a.to)
|
||||
a.name.as_str() == "size" || ident_has_target_size(doc, &a.to)
|
||||
}
|
||||
witx::DatatypeVariant::Enum(_) => false,
|
||||
witx::DatatypeVariant::Flags(_) => false,
|
||||
@@ -228,6 +241,7 @@ fn type_has_target_size(doc: &witx::Document, type_: &witx::Datatype) -> bool {
|
||||
.variants
|
||||
.iter()
|
||||
.any(|v| ident_has_target_size(doc, &v.type_)),
|
||||
witx::DatatypeVariant::Handle(_) => false,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
For the current polyfill sources, please checkout this same directory in
|
||||
[the polyfill branch](https://github.com/bytecodealliance/wasmtime/tree/polyfill/).
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 21 KiB |
@@ -1,6 +1,7 @@
|
||||
#![allow(improper_ctypes)]
|
||||
|
||||
mod instantiate;
|
||||
pub mod old;
|
||||
mod syscalls;
|
||||
|
||||
pub use instantiate::{create_wasi_instance, instantiate_wasi, instantiate_wasi_with_context};
|
||||
|
||||
1
crates/wasi/src/old/mod.rs
Normal file
1
crates/wasi/src/old/mod.rs
Normal file
@@ -0,0 +1 @@
|
||||
pub mod snapshot_0;
|
||||
156
crates/wasi/src/old/snapshot_0/instantiate.rs
Normal file
156
crates/wasi/src/old/snapshot_0/instantiate.rs
Normal file
@@ -0,0 +1,156 @@
|
||||
use super::syscalls;
|
||||
use alloc::rc::Rc;
|
||||
use core::cell::RefCell;
|
||||
use cranelift_codegen::ir::types;
|
||||
use cranelift_codegen::{ir, isa};
|
||||
use cranelift_entity::PrimaryMap;
|
||||
use cranelift_wasm::DefinedFuncIndex;
|
||||
use std::collections::HashMap;
|
||||
use std::fs::File;
|
||||
use target_lexicon::HOST;
|
||||
use wasi_common::old::snapshot_0::{WasiCtx, WasiCtxBuilder};
|
||||
use wasmtime_api as api;
|
||||
use wasmtime_environ::{translate_signature, Export, Module};
|
||||
use wasmtime_runtime::{Imports, InstanceHandle, InstantiationError, VMFunctionBody};
|
||||
|
||||
/// Creates `api::Instance` object implementing the "wasi" interface.
|
||||
pub fn create_wasi_instance(
|
||||
store: &api::HostRef<api::Store>,
|
||||
preopened_dirs: &[(String, File)],
|
||||
argv: &[String],
|
||||
environ: &[(String, String)],
|
||||
) -> Result<api::Instance, InstantiationError> {
|
||||
let global_exports = store.borrow().global_exports().clone();
|
||||
let wasi = instantiate_wasi(global_exports, preopened_dirs, argv, environ)?;
|
||||
let instance = api::Instance::from_handle(&store, wasi);
|
||||
Ok(instance)
|
||||
}
|
||||
|
||||
/// Return an instance implementing the "wasi" interface.
|
||||
pub fn instantiate_wasi(
|
||||
global_exports: Rc<RefCell<HashMap<String, Option<wasmtime_runtime::Export>>>>,
|
||||
preopened_dirs: &[(String, File)],
|
||||
argv: &[String],
|
||||
environ: &[(String, String)],
|
||||
) -> Result<InstanceHandle, InstantiationError> {
|
||||
let mut wasi_ctx_builder = WasiCtxBuilder::new()
|
||||
.inherit_stdio()
|
||||
.args(argv)
|
||||
.envs(environ);
|
||||
|
||||
for (dir, f) in preopened_dirs {
|
||||
wasi_ctx_builder = wasi_ctx_builder.preopened_dir(
|
||||
f.try_clone().map_err(|err| {
|
||||
InstantiationError::Resource(format!(
|
||||
"couldn't clone an instance handle to pre-opened dir: {}",
|
||||
err
|
||||
))
|
||||
})?,
|
||||
dir,
|
||||
);
|
||||
}
|
||||
|
||||
let wasi_ctx = wasi_ctx_builder.build().map_err(|err| {
|
||||
InstantiationError::Resource(format!("couldn't assemble WASI context object: {}", err))
|
||||
})?;
|
||||
instantiate_wasi_with_context(global_exports, wasi_ctx)
|
||||
}
|
||||
|
||||
/// Return an instance implementing the "wasi" interface.
|
||||
///
|
||||
/// The wasi context is configured by
|
||||
pub fn instantiate_wasi_with_context(
|
||||
global_exports: Rc<RefCell<HashMap<String, Option<wasmtime_runtime::Export>>>>,
|
||||
wasi_ctx: WasiCtx,
|
||||
) -> Result<InstanceHandle, InstantiationError> {
|
||||
let pointer_type = types::Type::triple_pointer_type(&HOST);
|
||||
let mut module = Module::new();
|
||||
let mut finished_functions: PrimaryMap<DefinedFuncIndex, *const VMFunctionBody> =
|
||||
PrimaryMap::new();
|
||||
let call_conv = isa::CallConv::triple_default(&HOST);
|
||||
|
||||
macro_rules! signature {
|
||||
($name:ident) => {{
|
||||
let sig = module.signatures.push(translate_signature(
|
||||
ir::Signature {
|
||||
params: syscalls::$name::params()
|
||||
.into_iter()
|
||||
.map(ir::AbiParam::new)
|
||||
.collect(),
|
||||
returns: syscalls::$name::results()
|
||||
.into_iter()
|
||||
.map(ir::AbiParam::new)
|
||||
.collect(),
|
||||
call_conv,
|
||||
},
|
||||
pointer_type,
|
||||
));
|
||||
let func = module.functions.push(sig);
|
||||
module
|
||||
.exports
|
||||
.insert(stringify!($name).to_owned(), Export::Function(func));
|
||||
finished_functions.push(syscalls::$name::SHIM as *const VMFunctionBody);
|
||||
}};
|
||||
}
|
||||
|
||||
signature!(args_get);
|
||||
signature!(args_sizes_get);
|
||||
signature!(clock_res_get);
|
||||
signature!(clock_time_get);
|
||||
signature!(environ_get);
|
||||
signature!(environ_sizes_get);
|
||||
signature!(fd_prestat_get);
|
||||
signature!(fd_prestat_dir_name);
|
||||
signature!(fd_close);
|
||||
signature!(fd_datasync);
|
||||
signature!(fd_pread);
|
||||
signature!(fd_pwrite);
|
||||
signature!(fd_read);
|
||||
signature!(fd_renumber);
|
||||
signature!(fd_seek);
|
||||
signature!(fd_tell);
|
||||
signature!(fd_fdstat_get);
|
||||
signature!(fd_fdstat_set_flags);
|
||||
signature!(fd_fdstat_set_rights);
|
||||
signature!(fd_sync);
|
||||
signature!(fd_write);
|
||||
signature!(fd_advise);
|
||||
signature!(fd_allocate);
|
||||
signature!(path_create_directory);
|
||||
signature!(path_link);
|
||||
signature!(path_open);
|
||||
signature!(fd_readdir);
|
||||
signature!(path_readlink);
|
||||
signature!(path_rename);
|
||||
signature!(fd_filestat_get);
|
||||
signature!(fd_filestat_set_times);
|
||||
signature!(fd_filestat_set_size);
|
||||
signature!(path_filestat_get);
|
||||
signature!(path_filestat_set_times);
|
||||
signature!(path_symlink);
|
||||
signature!(path_unlink_file);
|
||||
signature!(path_remove_directory);
|
||||
signature!(poll_oneoff);
|
||||
signature!(proc_exit);
|
||||
signature!(proc_raise);
|
||||
signature!(random_get);
|
||||
signature!(sched_yield);
|
||||
signature!(sock_recv);
|
||||
signature!(sock_send);
|
||||
signature!(sock_shutdown);
|
||||
|
||||
let imports = Imports::none();
|
||||
let data_initializers = Vec::new();
|
||||
let signatures = PrimaryMap::new();
|
||||
|
||||
InstanceHandle::new(
|
||||
Rc::new(module),
|
||||
global_exports,
|
||||
finished_functions.into_boxed_slice(),
|
||||
imports,
|
||||
&data_initializers,
|
||||
signatures.into_boxed_slice(),
|
||||
None,
|
||||
Box::new(wasi_ctx),
|
||||
)
|
||||
}
|
||||
15
crates/wasi/src/old/snapshot_0/mod.rs
Normal file
15
crates/wasi/src/old/snapshot_0/mod.rs
Normal file
@@ -0,0 +1,15 @@
|
||||
#![allow(improper_ctypes)]
|
||||
|
||||
extern crate alloc;
|
||||
|
||||
mod instantiate;
|
||||
mod syscalls;
|
||||
|
||||
pub use instantiate::{create_wasi_instance, instantiate_wasi, instantiate_wasi_with_context};
|
||||
|
||||
pub fn is_wasi_module(name: &str) -> bool {
|
||||
// FIXME: this should be more conservative, but while WASI is in flux and
|
||||
// we're figuring out how to support multiple revisions, this should do the
|
||||
// trick.
|
||||
name.starts_with("wasi")
|
||||
}
|
||||
977
crates/wasi/src/old/snapshot_0/syscalls.rs
Normal file
977
crates/wasi/src/old/snapshot_0/syscalls.rs
Normal file
@@ -0,0 +1,977 @@
|
||||
use cranelift_codegen::ir::types::{Type, I32, I64};
|
||||
use log::{error, trace};
|
||||
use wasi_common::old::snapshot_0::{hostcalls, wasi, wasi32, WasiCtx};
|
||||
use wasmtime_runtime::{Export, VMContext};
|
||||
|
||||
pub trait AbiRet {
|
||||
type Abi;
|
||||
fn convert(self) -> Self::Abi;
|
||||
fn codegen_tys() -> Vec<Type>;
|
||||
}
|
||||
|
||||
pub trait AbiParam {
|
||||
type Abi;
|
||||
fn convert(arg: Self::Abi) -> Self;
|
||||
fn codegen_ty() -> Type;
|
||||
}
|
||||
|
||||
macro_rules! cast32 {
|
||||
($($i:ident)*) => ($(
|
||||
impl AbiRet for $i {
|
||||
type Abi = i32;
|
||||
|
||||
fn convert(self) -> Self::Abi {
|
||||
self as i32
|
||||
}
|
||||
|
||||
fn codegen_tys() -> Vec<Type> { vec![I32] }
|
||||
}
|
||||
|
||||
impl AbiParam for $i {
|
||||
type Abi = i32;
|
||||
|
||||
fn convert(param: i32) -> Self {
|
||||
param as $i
|
||||
}
|
||||
|
||||
fn codegen_ty() -> Type { I32 }
|
||||
}
|
||||
)*)
|
||||
}
|
||||
|
||||
macro_rules! cast64 {
|
||||
($($i:ident)*) => ($(
|
||||
impl AbiRet for $i {
|
||||
type Abi = i64;
|
||||
|
||||
fn convert(self) -> Self::Abi {
|
||||
self as i64
|
||||
}
|
||||
|
||||
fn codegen_tys() -> Vec<Type> { vec![I64] }
|
||||
}
|
||||
|
||||
impl AbiParam for $i {
|
||||
type Abi = i64;
|
||||
|
||||
fn convert(param: i64) -> Self {
|
||||
param as $i
|
||||
}
|
||||
|
||||
fn codegen_ty() -> Type { I64 }
|
||||
}
|
||||
)*)
|
||||
}
|
||||
|
||||
cast32!(i8 i16 i32 u8 u16 u32);
|
||||
cast64!(i64 u64);
|
||||
|
||||
impl AbiRet for () {
|
||||
type Abi = ();
|
||||
fn convert(self) {}
|
||||
fn codegen_tys() -> Vec<Type> {
|
||||
Vec::new()
|
||||
}
|
||||
}
|
||||
|
||||
fn get_wasi_ctx(vmctx: &mut VMContext) -> Result<&mut WasiCtx, wasi::__wasi_errno_t> {
|
||||
unsafe {
|
||||
vmctx
|
||||
.host_state()
|
||||
.downcast_mut::<WasiCtx>()
|
||||
.ok_or_else(|| panic!("no host state named WasiCtx available"))
|
||||
}
|
||||
}
|
||||
|
||||
fn get_memory(vmctx: &mut VMContext) -> Result<&mut [u8], wasi::__wasi_errno_t> {
|
||||
unsafe {
|
||||
match vmctx.lookup_global_export("memory") {
|
||||
Some(Export::Memory {
|
||||
definition,
|
||||
vmctx: _,
|
||||
memory: _,
|
||||
}) => Ok(std::slice::from_raw_parts_mut(
|
||||
(*definition).base,
|
||||
(*definition).current_length,
|
||||
)),
|
||||
x => {
|
||||
error!(
|
||||
"no export named \"memory\", or the export isn't a mem: {:?}",
|
||||
x
|
||||
);
|
||||
Err(wasi::__WASI_ERRNO_INVAL)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! ok_or_errno {
|
||||
($expr:expr) => {
|
||||
match $expr {
|
||||
Ok(v) => v,
|
||||
Err(e) => {
|
||||
trace!(" -> errno={}", wasi::strerror(e));
|
||||
return e;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! syscalls {
|
||||
($(pub unsafe extern "C" fn $name:ident($ctx:ident: *mut VMContext $(, $arg:ident: $ty:ty)*,) -> $ret:ty {
|
||||
$($body:tt)*
|
||||
})*) => ($(
|
||||
pub mod $name {
|
||||
use super::*;
|
||||
|
||||
/// Returns the codegen types of all the parameters to the shim
|
||||
/// generated
|
||||
pub fn params() -> Vec<Type> {
|
||||
vec![$(<$ty as AbiParam>::codegen_ty()),*]
|
||||
}
|
||||
|
||||
/// Returns the codegen types of all the results of the shim
|
||||
/// generated
|
||||
pub fn results() -> Vec<Type> {
|
||||
<$ret as AbiRet>::codegen_tys()
|
||||
}
|
||||
|
||||
/// The actual function pointer to the shim for a syscall.
|
||||
///
|
||||
/// NB: ideally we'd expose `shim` below, but it seems like there's
|
||||
/// a compiler bug which prvents that from being cast to a `usize`.
|
||||
pub static SHIM: unsafe extern "C" fn(
|
||||
*mut VMContext,
|
||||
$(<$ty as AbiParam>::Abi),*
|
||||
) -> <$ret as AbiRet>::Abi = shim;
|
||||
|
||||
unsafe extern "C" fn shim(
|
||||
$ctx: *mut VMContext,
|
||||
$($arg: <$ty as AbiParam>::Abi,)*
|
||||
) -> <$ret as AbiRet>::Abi {
|
||||
let r = super::$name($ctx, $(<$ty as AbiParam>::convert($arg),)*);
|
||||
<$ret as AbiRet>::convert(r)
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe extern "C" fn $name($ctx: *mut VMContext, $($arg: $ty,)*) -> $ret {
|
||||
$($body)*
|
||||
}
|
||||
)*)
|
||||
}
|
||||
|
||||
syscalls! {
|
||||
pub unsafe extern "C" fn args_get(
|
||||
vmctx: *mut VMContext,
|
||||
argv: wasi32::uintptr_t,
|
||||
argv_buf: wasi32::uintptr_t,
|
||||
) -> wasi::__wasi_errno_t {
|
||||
trace!(
|
||||
"args_get(argv={:#x?}, argv_buf={:#x?})",
|
||||
argv,
|
||||
argv_buf,
|
||||
);
|
||||
let wasi_ctx = ok_or_errno!(get_wasi_ctx(&mut *vmctx));
|
||||
let memory = ok_or_errno!(get_memory(&mut *vmctx));
|
||||
hostcalls::args_get(wasi_ctx, memory, argv, argv_buf)
|
||||
}
|
||||
|
||||
pub unsafe extern "C" fn args_sizes_get(
|
||||
vmctx: *mut VMContext,
|
||||
argc: wasi32::uintptr_t,
|
||||
argv_buf_size: wasi32::uintptr_t,
|
||||
) -> wasi::__wasi_errno_t {
|
||||
trace!(
|
||||
"args_sizes_get(argc={:#x?}, argv_buf_size={:#x?})",
|
||||
argc,
|
||||
argv_buf_size,
|
||||
);
|
||||
let wasi_ctx = ok_or_errno!(get_wasi_ctx(&mut *vmctx));
|
||||
let memory = ok_or_errno!(get_memory(&mut *vmctx));
|
||||
hostcalls::args_sizes_get(wasi_ctx, memory, argc, argv_buf_size)
|
||||
}
|
||||
|
||||
pub unsafe extern "C" fn clock_res_get(
|
||||
vmctx: *mut VMContext,
|
||||
clock_id: wasi::__wasi_clockid_t,
|
||||
resolution: wasi32::uintptr_t,
|
||||
) -> wasi::__wasi_errno_t {
|
||||
trace!(
|
||||
"clock_res_get(clock_id={:?}, resolution={:#x?})",
|
||||
clock_id,
|
||||
resolution,
|
||||
);
|
||||
let memory = ok_or_errno!(get_memory(&mut *vmctx));
|
||||
hostcalls::clock_res_get(memory, clock_id, resolution)
|
||||
}
|
||||
|
||||
pub unsafe extern "C" fn clock_time_get(
|
||||
vmctx: *mut VMContext,
|
||||
clock_id: wasi::__wasi_clockid_t,
|
||||
precision: wasi::__wasi_timestamp_t,
|
||||
time: wasi32::uintptr_t,
|
||||
) -> wasi::__wasi_errno_t {
|
||||
trace!(
|
||||
"clock_time_get(clock_id={:?}, precision={:?}, time={:#x?})",
|
||||
clock_id,
|
||||
precision,
|
||||
time,
|
||||
);
|
||||
let memory = ok_or_errno!(get_memory(&mut *vmctx));
|
||||
hostcalls::clock_time_get(memory, clock_id, precision, time)
|
||||
}
|
||||
|
||||
pub unsafe extern "C" fn environ_get(
|
||||
vmctx: *mut VMContext,
|
||||
environ: wasi32::uintptr_t,
|
||||
environ_buf: wasi32::uintptr_t,
|
||||
) -> wasi::__wasi_errno_t {
|
||||
trace!(
|
||||
"environ_get(environ={:#x?}, environ_buf={:#x?})",
|
||||
environ,
|
||||
environ_buf,
|
||||
);
|
||||
let wasi_ctx = ok_or_errno!(get_wasi_ctx(&mut *vmctx));
|
||||
let memory = ok_or_errno!(get_memory(&mut *vmctx));
|
||||
hostcalls::environ_get(wasi_ctx, memory, environ, environ_buf)
|
||||
}
|
||||
|
||||
pub unsafe extern "C" fn environ_sizes_get(
|
||||
vmctx: *mut VMContext,
|
||||
environ_count: wasi32::uintptr_t,
|
||||
environ_buf_size: wasi32::uintptr_t,
|
||||
) -> wasi::__wasi_errno_t {
|
||||
trace!(
|
||||
"environ_sizes_get(environ_count={:#x?}, environ_buf_size={:#x?})",
|
||||
environ_count,
|
||||
environ_buf_size,
|
||||
);
|
||||
let wasi_ctx = ok_or_errno!(get_wasi_ctx(&mut *vmctx));
|
||||
let memory = ok_or_errno!(get_memory(&mut *vmctx));
|
||||
hostcalls::environ_sizes_get(wasi_ctx, memory, environ_count, environ_buf_size)
|
||||
}
|
||||
|
||||
pub unsafe extern "C" fn fd_prestat_get(
|
||||
vmctx: *mut VMContext,
|
||||
fd: wasi::__wasi_fd_t,
|
||||
buf: wasi32::uintptr_t,
|
||||
) -> wasi::__wasi_errno_t {
|
||||
trace!("fd_prestat_get(fd={:?}, buf={:#x?})", fd, buf);
|
||||
let wasi_ctx = ok_or_errno!(get_wasi_ctx(&mut *vmctx));
|
||||
let memory = ok_or_errno!(get_memory(&mut *vmctx));
|
||||
hostcalls::fd_prestat_get(wasi_ctx, memory, fd, buf)
|
||||
}
|
||||
|
||||
pub unsafe extern "C" fn fd_prestat_dir_name(
|
||||
vmctx: *mut VMContext,
|
||||
fd: wasi::__wasi_fd_t,
|
||||
path: wasi32::uintptr_t,
|
||||
path_len: wasi32::size_t,
|
||||
) -> wasi::__wasi_errno_t {
|
||||
trace!("fd_prestat_dir_name(fd={:?}, path={:#x?}, path_len={})", fd, path, path_len);
|
||||
let wasi_ctx = ok_or_errno!(get_wasi_ctx(&mut *vmctx));
|
||||
let memory = ok_or_errno!(get_memory(&mut *vmctx));
|
||||
hostcalls::fd_prestat_dir_name(wasi_ctx, memory, fd, path, path_len)
|
||||
}
|
||||
|
||||
pub unsafe extern "C" fn fd_close(
|
||||
vmctx: *mut VMContext,
|
||||
fd: wasi::__wasi_fd_t,
|
||||
) -> wasi::__wasi_errno_t {
|
||||
trace!("fd_close(fd={:?})", fd);
|
||||
let wasi_ctx = ok_or_errno!(get_wasi_ctx(&mut *vmctx));
|
||||
hostcalls::fd_close(wasi_ctx, fd)
|
||||
}
|
||||
|
||||
pub unsafe extern "C" fn fd_datasync(
|
||||
vmctx: *mut VMContext,
|
||||
fd: wasi::__wasi_fd_t,
|
||||
) -> wasi::__wasi_errno_t {
|
||||
trace!("fd_datasync(fd={:?})", fd);
|
||||
let wasi_ctx = ok_or_errno!(get_wasi_ctx(&mut *vmctx));
|
||||
hostcalls::fd_datasync(wasi_ctx, fd)
|
||||
}
|
||||
|
||||
pub unsafe extern "C" fn fd_pread(
|
||||
vmctx: *mut VMContext,
|
||||
fd: wasi::__wasi_fd_t,
|
||||
iovs: wasi32::uintptr_t,
|
||||
iovs_len: wasi32::size_t,
|
||||
offset: wasi::__wasi_filesize_t,
|
||||
nread: wasi32::uintptr_t,
|
||||
) -> wasi::__wasi_errno_t {
|
||||
trace!(
|
||||
"fd_pread(fd={:?}, iovs={:#x?}, iovs_len={:?}, offset={}, nread={:#x?})",
|
||||
fd,
|
||||
iovs,
|
||||
iovs_len,
|
||||
offset,
|
||||
nread
|
||||
);
|
||||
let wasi_ctx = ok_or_errno!(get_wasi_ctx(&mut *vmctx));
|
||||
let memory = ok_or_errno!(get_memory(&mut *vmctx));
|
||||
hostcalls::fd_pread(
|
||||
wasi_ctx,
|
||||
memory,
|
||||
fd,
|
||||
iovs,
|
||||
iovs_len,
|
||||
offset,
|
||||
nread
|
||||
)
|
||||
}
|
||||
|
||||
pub unsafe extern "C" fn fd_pwrite(
|
||||
vmctx: *mut VMContext,
|
||||
fd: wasi::__wasi_fd_t,
|
||||
iovs: wasi32::uintptr_t,
|
||||
iovs_len: wasi32::size_t,
|
||||
offset: wasi::__wasi_filesize_t,
|
||||
nwritten: wasi32::uintptr_t,
|
||||
) -> wasi::__wasi_errno_t {
|
||||
trace!(
|
||||
"fd_pwrite(fd={:?}, iovs={:#x?}, iovs_len={:?}, offset={}, nwritten={:#x?})",
|
||||
fd,
|
||||
iovs,
|
||||
iovs_len,
|
||||
offset,
|
||||
nwritten
|
||||
);
|
||||
let wasi_ctx = ok_or_errno!(get_wasi_ctx(&mut *vmctx));
|
||||
let memory = ok_or_errno!(get_memory(&mut *vmctx));
|
||||
hostcalls::fd_pwrite(
|
||||
wasi_ctx,
|
||||
memory,
|
||||
fd,
|
||||
iovs,
|
||||
iovs_len,
|
||||
offset,
|
||||
nwritten
|
||||
)
|
||||
}
|
||||
|
||||
pub unsafe extern "C" fn fd_read(
|
||||
vmctx: *mut VMContext,
|
||||
fd: wasi::__wasi_fd_t,
|
||||
iovs: wasi32::uintptr_t,
|
||||
iovs_len: wasi32::size_t,
|
||||
nread: wasi32::uintptr_t,
|
||||
) -> wasi::__wasi_errno_t {
|
||||
trace!(
|
||||
"fd_read(fd={:?}, iovs={:#x?}, iovs_len={:?}, nread={:#x?})",
|
||||
fd,
|
||||
iovs,
|
||||
iovs_len,
|
||||
nread
|
||||
);
|
||||
let wasi_ctx = ok_or_errno!(get_wasi_ctx(&mut *vmctx));
|
||||
let memory = ok_or_errno!(get_memory(&mut *vmctx));
|
||||
hostcalls::fd_read(wasi_ctx, memory, fd, iovs, iovs_len, nread)
|
||||
}
|
||||
|
||||
pub unsafe extern "C" fn fd_renumber(
|
||||
vmctx: *mut VMContext,
|
||||
from: wasi::__wasi_fd_t,
|
||||
to: wasi::__wasi_fd_t,
|
||||
) -> wasi::__wasi_errno_t {
|
||||
trace!("fd_renumber(from={:?}, to={:?})", from, to);
|
||||
let wasi_ctx = ok_or_errno!(get_wasi_ctx(&mut *vmctx));
|
||||
hostcalls::fd_renumber(wasi_ctx, from, to)
|
||||
}
|
||||
|
||||
pub unsafe extern "C" fn fd_seek(
|
||||
vmctx: *mut VMContext,
|
||||
fd: wasi::__wasi_fd_t,
|
||||
offset: wasi::__wasi_filedelta_t,
|
||||
whence: wasi::__wasi_whence_t,
|
||||
newoffset: wasi32::uintptr_t,
|
||||
) -> wasi::__wasi_errno_t {
|
||||
trace!(
|
||||
"fd_seek(fd={:?}, offset={:?}, whence={}, newoffset={:#x?})",
|
||||
fd,
|
||||
offset,
|
||||
wasi::whence_to_str(whence),
|
||||
newoffset
|
||||
);
|
||||
let wasi_ctx = ok_or_errno!(get_wasi_ctx(&mut *vmctx));
|
||||
let memory = ok_or_errno!(get_memory(&mut *vmctx));
|
||||
hostcalls::fd_seek(wasi_ctx, memory, fd, offset, whence, newoffset)
|
||||
}
|
||||
|
||||
pub unsafe extern "C" fn fd_tell(
|
||||
vmctx: *mut VMContext,
|
||||
fd: wasi::__wasi_fd_t,
|
||||
newoffset: wasi32::uintptr_t,
|
||||
) -> wasi::__wasi_errno_t {
|
||||
trace!("fd_tell(fd={:?}, newoffset={:#x?})", fd, newoffset);
|
||||
let wasi_ctx = ok_or_errno!(get_wasi_ctx(&mut *vmctx));
|
||||
let memory = ok_or_errno!(get_memory(&mut *vmctx));
|
||||
hostcalls::fd_tell(wasi_ctx, memory, fd, newoffset)
|
||||
}
|
||||
|
||||
pub unsafe extern "C" fn fd_fdstat_get(
|
||||
vmctx: *mut VMContext,
|
||||
fd: wasi::__wasi_fd_t,
|
||||
buf: wasi32::uintptr_t,
|
||||
) -> wasi::__wasi_errno_t {
|
||||
trace!("fd_fdstat_get(fd={:?}, buf={:#x?})", fd, buf);
|
||||
let wasi_ctx = ok_or_errno!(get_wasi_ctx(&mut *vmctx));
|
||||
let memory = ok_or_errno!(get_memory(&mut *vmctx));
|
||||
hostcalls::fd_fdstat_get(wasi_ctx, memory, fd, buf)
|
||||
}
|
||||
|
||||
pub unsafe extern "C" fn fd_fdstat_set_flags(
|
||||
vmctx: *mut VMContext,
|
||||
fd: wasi::__wasi_fd_t,
|
||||
flags: wasi::__wasi_fdflags_t,
|
||||
) -> wasi::__wasi_errno_t {
|
||||
trace!(
|
||||
"fd_fdstat_set_flags(fd={:?}, flags={:#x?})",
|
||||
fd,
|
||||
flags
|
||||
);
|
||||
let wasi_ctx = ok_or_errno!(get_wasi_ctx(&mut *vmctx));
|
||||
hostcalls::fd_fdstat_set_flags(wasi_ctx, fd, flags)
|
||||
}
|
||||
|
||||
pub unsafe extern "C" fn fd_fdstat_set_rights(
|
||||
vmctx: *mut VMContext,
|
||||
fd: wasi::__wasi_fd_t,
|
||||
fs_rights_base: wasi::__wasi_rights_t,
|
||||
fs_rights_inheriting: wasi::__wasi_rights_t,
|
||||
) -> wasi::__wasi_errno_t {
|
||||
trace!(
|
||||
"fd_fdstat_set_rights(fd={:?}, fs_rights_base={:#x?}, fs_rights_inheriting={:#x?})",
|
||||
fd,
|
||||
fs_rights_base,
|
||||
fs_rights_inheriting
|
||||
);
|
||||
let wasi_ctx = ok_or_errno!(get_wasi_ctx(&mut *vmctx));
|
||||
hostcalls::fd_fdstat_set_rights(
|
||||
wasi_ctx,
|
||||
fd,
|
||||
fs_rights_base,
|
||||
fs_rights_inheriting
|
||||
)
|
||||
}
|
||||
|
||||
pub unsafe extern "C" fn fd_sync(
|
||||
vmctx: *mut VMContext,
|
||||
fd: wasi::__wasi_fd_t,
|
||||
) -> wasi::__wasi_errno_t {
|
||||
trace!("fd_sync(fd={:?})", fd);
|
||||
let wasi_ctx = ok_or_errno!(get_wasi_ctx(&mut *vmctx));
|
||||
hostcalls::fd_sync(wasi_ctx, fd)
|
||||
}
|
||||
|
||||
pub unsafe extern "C" fn fd_write(
|
||||
vmctx: *mut VMContext,
|
||||
fd: wasi::__wasi_fd_t,
|
||||
iovs: wasi32::uintptr_t,
|
||||
iovs_len: wasi32::size_t,
|
||||
nwritten: wasi32::uintptr_t,
|
||||
) -> wasi::__wasi_errno_t {
|
||||
trace!(
|
||||
"fd_write(fd={:?}, iovs={:#x?}, iovs_len={:?}, nwritten={:#x?})",
|
||||
fd,
|
||||
iovs,
|
||||
iovs_len,
|
||||
nwritten
|
||||
);
|
||||
let wasi_ctx = ok_or_errno!(get_wasi_ctx(&mut *vmctx));
|
||||
let memory = ok_or_errno!(get_memory(&mut *vmctx));
|
||||
hostcalls::fd_write(wasi_ctx, memory, fd, iovs, iovs_len, nwritten)
|
||||
}
|
||||
|
||||
pub unsafe extern "C" fn fd_advise(
|
||||
vmctx: *mut VMContext,
|
||||
fd: wasi::__wasi_fd_t,
|
||||
offset: wasi::__wasi_filesize_t,
|
||||
len: wasi::__wasi_filesize_t,
|
||||
advice: wasi::__wasi_advice_t,
|
||||
) -> wasi::__wasi_errno_t {
|
||||
trace!(
|
||||
"fd_advise(fd={:?}, offset={}, len={}, advice={:?})",
|
||||
fd,
|
||||
offset,
|
||||
len,
|
||||
advice
|
||||
);
|
||||
let wasi_ctx = ok_or_errno!(get_wasi_ctx(&mut *vmctx));
|
||||
hostcalls::fd_advise(wasi_ctx, fd, offset, len, advice)
|
||||
}
|
||||
|
||||
pub unsafe extern "C" fn fd_allocate(
|
||||
vmctx: *mut VMContext,
|
||||
fd: wasi::__wasi_fd_t,
|
||||
offset: wasi::__wasi_filesize_t,
|
||||
len: wasi::__wasi_filesize_t,
|
||||
) -> wasi::__wasi_errno_t {
|
||||
trace!("fd_allocate(fd={:?}, offset={}, len={})", fd, offset, len);
|
||||
let wasi_ctx = ok_or_errno!(get_wasi_ctx(&mut *vmctx));
|
||||
hostcalls::fd_allocate(wasi_ctx, fd, offset, len)
|
||||
}
|
||||
|
||||
pub unsafe extern "C" fn path_create_directory(
|
||||
vmctx: *mut VMContext,
|
||||
fd: wasi::__wasi_fd_t,
|
||||
path: wasi32::uintptr_t,
|
||||
path_len: wasi32::size_t,
|
||||
) -> wasi::__wasi_errno_t {
|
||||
trace!(
|
||||
"path_create_directory(fd={:?}, path={:#x?}, path_len={})",
|
||||
fd,
|
||||
path,
|
||||
path_len,
|
||||
);
|
||||
let wasi_ctx = ok_or_errno!(get_wasi_ctx(&mut *vmctx));
|
||||
let memory = ok_or_errno!(get_memory(&mut *vmctx));
|
||||
hostcalls::path_create_directory(wasi_ctx, memory, fd, path, path_len)
|
||||
}
|
||||
|
||||
pub unsafe extern "C" fn path_link(
|
||||
vmctx: *mut VMContext,
|
||||
fd0: wasi::__wasi_fd_t,
|
||||
flags0: wasi::__wasi_lookupflags_t,
|
||||
path0: wasi32::uintptr_t,
|
||||
path_len0: wasi32::size_t,
|
||||
fd1: wasi::__wasi_fd_t,
|
||||
path1: wasi32::uintptr_t,
|
||||
path_len1: wasi32::size_t,
|
||||
) -> wasi::__wasi_errno_t {
|
||||
trace!(
|
||||
"path_link(fd0={:?}, flags0={:?}, path0={:#x?}, path_len0={}, fd1={:?}, path1={:#x?}, path_len1={})",
|
||||
fd0,
|
||||
flags0,
|
||||
path0,
|
||||
path_len0,
|
||||
fd1,
|
||||
path1,
|
||||
path_len1
|
||||
);
|
||||
let wasi_ctx = ok_or_errno!(get_wasi_ctx(&mut *vmctx));
|
||||
let memory = ok_or_errno!(get_memory(&mut *vmctx));
|
||||
hostcalls::path_link(
|
||||
wasi_ctx,
|
||||
memory,
|
||||
fd0,
|
||||
flags0,
|
||||
path0,
|
||||
path_len0,
|
||||
fd1,
|
||||
path1,
|
||||
path_len1
|
||||
)
|
||||
}
|
||||
|
||||
// TODO: When multi-value happens, switch to that instead of passing
|
||||
// the `fd` by reference?
|
||||
pub unsafe extern "C" fn path_open(
|
||||
vmctx: *mut VMContext,
|
||||
dirfd: wasi::__wasi_fd_t,
|
||||
dirflags: wasi::__wasi_lookupflags_t,
|
||||
path: wasi32::uintptr_t,
|
||||
path_len: wasi32::size_t,
|
||||
oflags: wasi::__wasi_oflags_t,
|
||||
fs_rights_base: wasi::__wasi_rights_t,
|
||||
fs_rights_inheriting: wasi::__wasi_rights_t,
|
||||
fs_flags: wasi::__wasi_fdflags_t,
|
||||
fd: wasi32::uintptr_t,
|
||||
) -> wasi::__wasi_errno_t {
|
||||
trace!(
|
||||
"path_open(dirfd={:?}, dirflags={:?}, path={:#x?}, path_len={:?}, oflags={:#x?}, fs_rights_base={:#x?}, fs_rights_inheriting={:#x?}, fs_flags={:#x?}, fd={:#x?})",
|
||||
dirfd,
|
||||
dirflags,
|
||||
path,
|
||||
path_len,
|
||||
oflags,
|
||||
fs_rights_base,
|
||||
fs_rights_inheriting,
|
||||
fs_flags,
|
||||
fd
|
||||
);
|
||||
let wasi_ctx = ok_or_errno!(get_wasi_ctx(&mut *vmctx));
|
||||
let memory = ok_or_errno!(get_memory(&mut *vmctx));
|
||||
hostcalls::path_open(
|
||||
wasi_ctx,
|
||||
memory,
|
||||
dirfd,
|
||||
dirflags,
|
||||
path,
|
||||
path_len,
|
||||
oflags,
|
||||
fs_rights_base,
|
||||
fs_rights_inheriting,
|
||||
fs_flags,
|
||||
fd
|
||||
)
|
||||
}
|
||||
|
||||
pub unsafe extern "C" fn fd_readdir(
|
||||
vmctx: *mut VMContext,
|
||||
fd: wasi::__wasi_fd_t,
|
||||
buf: wasi32::uintptr_t,
|
||||
buf_len: wasi32::size_t,
|
||||
cookie: wasi::__wasi_dircookie_t,
|
||||
buf_used: wasi32::uintptr_t,
|
||||
) -> wasi::__wasi_errno_t {
|
||||
trace!(
|
||||
"fd_readdir(fd={:?}, buf={:#x?}, buf_len={}, cookie={:#x?}, buf_used={:#x?})",
|
||||
fd,
|
||||
buf,
|
||||
buf_len,
|
||||
cookie,
|
||||
buf_used,
|
||||
);
|
||||
let wasi_ctx = ok_or_errno!(get_wasi_ctx(&mut *vmctx));
|
||||
let memory = ok_or_errno!(get_memory(&mut *vmctx));
|
||||
hostcalls::fd_readdir(
|
||||
wasi_ctx,
|
||||
memory,
|
||||
fd,
|
||||
buf,
|
||||
buf_len,
|
||||
cookie,
|
||||
buf_used
|
||||
)
|
||||
}
|
||||
|
||||
pub unsafe extern "C" fn path_readlink(
|
||||
vmctx: *mut VMContext,
|
||||
fd: wasi::__wasi_fd_t,
|
||||
path: wasi32::uintptr_t,
|
||||
path_len: wasi32::size_t,
|
||||
buf: wasi32::uintptr_t,
|
||||
buf_len: wasi32::size_t,
|
||||
buf_used: wasi32::uintptr_t,
|
||||
) -> wasi::__wasi_errno_t {
|
||||
trace!(
|
||||
"path_readlink(fd={:?}, path={:#x?}, path_len={:?}, buf={:#x?}, buf_len={}, buf_used={:#x?})",
|
||||
fd,
|
||||
path,
|
||||
path_len,
|
||||
buf,
|
||||
buf_len,
|
||||
buf_used,
|
||||
);
|
||||
let wasi_ctx = ok_or_errno!(get_wasi_ctx(&mut *vmctx));
|
||||
let memory = ok_or_errno!(get_memory(&mut *vmctx));
|
||||
hostcalls::path_readlink(
|
||||
wasi_ctx,
|
||||
memory,
|
||||
fd,
|
||||
path,
|
||||
path_len,
|
||||
buf,
|
||||
buf_len,
|
||||
buf_used
|
||||
)
|
||||
}
|
||||
|
||||
pub unsafe extern "C" fn path_rename(
|
||||
vmctx: *mut VMContext,
|
||||
fd0: wasi::__wasi_fd_t,
|
||||
path0: wasi32::uintptr_t,
|
||||
path_len0: wasi32::size_t,
|
||||
fd1: wasi::__wasi_fd_t,
|
||||
path1: wasi32::uintptr_t,
|
||||
path_len1: wasi32::size_t,
|
||||
) -> wasi::__wasi_errno_t {
|
||||
trace!(
|
||||
"path_rename(fd0={:?}, path0={:#x?}, path_len0={:?}, fd1={:?}, path1={:#x?}, path_len1={:?})",
|
||||
fd0,
|
||||
path0,
|
||||
path_len0,
|
||||
fd1,
|
||||
path1,
|
||||
path_len1,
|
||||
);
|
||||
let wasi_ctx = ok_or_errno!(get_wasi_ctx(&mut *vmctx));
|
||||
let memory = ok_or_errno!(get_memory(&mut *vmctx));
|
||||
hostcalls::path_rename(
|
||||
wasi_ctx,
|
||||
memory,
|
||||
fd0,
|
||||
path0,
|
||||
path_len0,
|
||||
fd1,
|
||||
path1,
|
||||
path_len1
|
||||
)
|
||||
}
|
||||
|
||||
pub unsafe extern "C" fn fd_filestat_get(
|
||||
vmctx: *mut VMContext,
|
||||
fd: wasi::__wasi_fd_t,
|
||||
buf: wasi32::uintptr_t,
|
||||
) -> wasi::__wasi_errno_t {
|
||||
trace!("fd_filestat_get(fd={:?}, buf={:#x?})", fd, buf);
|
||||
let wasi_ctx = ok_or_errno!(get_wasi_ctx(&mut *vmctx));
|
||||
let memory = ok_or_errno!(get_memory(&mut *vmctx));
|
||||
hostcalls::fd_filestat_get(wasi_ctx, memory, fd, buf)
|
||||
}
|
||||
|
||||
pub unsafe extern "C" fn fd_filestat_set_times(
|
||||
vmctx: *mut VMContext,
|
||||
fd: wasi::__wasi_fd_t,
|
||||
st_atim: wasi::__wasi_timestamp_t,
|
||||
st_mtim: wasi::__wasi_timestamp_t,
|
||||
fstflags: wasi::__wasi_fstflags_t,
|
||||
) -> wasi::__wasi_errno_t {
|
||||
trace!(
|
||||
"fd_filestat_set_times(fd={:?}, st_atim={}, st_mtim={}, fstflags={:#x?})",
|
||||
fd,
|
||||
st_atim, st_mtim,
|
||||
fstflags
|
||||
);
|
||||
let wasi_ctx = ok_or_errno!(get_wasi_ctx(&mut *vmctx));
|
||||
hostcalls::fd_filestat_set_times(wasi_ctx, fd, st_atim, st_mtim, fstflags)
|
||||
}
|
||||
|
||||
pub unsafe extern "C" fn fd_filestat_set_size(
|
||||
vmctx: *mut VMContext,
|
||||
fd: wasi::__wasi_fd_t,
|
||||
size: wasi::__wasi_filesize_t,
|
||||
) -> wasi::__wasi_errno_t {
|
||||
trace!(
|
||||
"fd_filestat_set_size(fd={:?}, size={})",
|
||||
fd,
|
||||
size
|
||||
);
|
||||
let wasi_ctx = ok_or_errno!(get_wasi_ctx(&mut *vmctx));
|
||||
hostcalls::fd_filestat_set_size(wasi_ctx, fd, size)
|
||||
}
|
||||
|
||||
pub unsafe extern "C" fn path_filestat_get(
|
||||
vmctx: *mut VMContext,
|
||||
fd: wasi::__wasi_fd_t,
|
||||
flags: wasi::__wasi_lookupflags_t,
|
||||
path: wasi32::uintptr_t,
|
||||
path_len: wasi32::size_t,
|
||||
buf: wasi32::uintptr_t,
|
||||
) -> wasi::__wasi_errno_t {
|
||||
trace!(
|
||||
"path_filestat_get(fd={:?}, flags={:?}, path={:#x?}, path_len={}, buf={:#x?})",
|
||||
fd,
|
||||
flags,
|
||||
path,
|
||||
path_len,
|
||||
buf
|
||||
);
|
||||
let wasi_ctx = ok_or_errno!(get_wasi_ctx(&mut *vmctx));
|
||||
let memory = ok_or_errno!(get_memory(&mut *vmctx));
|
||||
hostcalls::path_filestat_get(wasi_ctx, memory, fd, flags, path, path_len, buf)
|
||||
}
|
||||
|
||||
pub unsafe extern "C" fn path_filestat_set_times(
|
||||
vmctx: *mut VMContext,
|
||||
fd: wasi::__wasi_fd_t,
|
||||
flags: wasi::__wasi_lookupflags_t,
|
||||
path: wasi32::uintptr_t,
|
||||
path_len: wasi32::size_t,
|
||||
st_atim: wasi::__wasi_timestamp_t,
|
||||
st_mtim: wasi::__wasi_timestamp_t,
|
||||
fstflags: wasi::__wasi_fstflags_t,
|
||||
) -> wasi::__wasi_errno_t {
|
||||
trace!(
|
||||
"path_filestat_set_times(fd={:?}, flags={:?}, path={:#x?}, path_len={}, st_atim={}, st_mtim={}, fstflags={:#x?})",
|
||||
fd,
|
||||
flags,
|
||||
path,
|
||||
path_len,
|
||||
st_atim, st_mtim,
|
||||
fstflags
|
||||
);
|
||||
let wasi_ctx = ok_or_errno!(get_wasi_ctx(&mut *vmctx));
|
||||
let memory = ok_or_errno!(get_memory(&mut *vmctx));
|
||||
hostcalls::path_filestat_set_times(
|
||||
wasi_ctx,
|
||||
memory,
|
||||
fd,
|
||||
flags,
|
||||
path,
|
||||
path_len,
|
||||
st_atim,
|
||||
st_mtim,
|
||||
fstflags
|
||||
)
|
||||
}
|
||||
|
||||
pub unsafe extern "C" fn path_symlink(
|
||||
vmctx: *mut VMContext,
|
||||
path0: wasi32::uintptr_t,
|
||||
path_len0: wasi32::size_t,
|
||||
fd: wasi::__wasi_fd_t,
|
||||
path1: wasi32::uintptr_t,
|
||||
path_len1: wasi32::size_t,
|
||||
) -> wasi::__wasi_errno_t {
|
||||
trace!(
|
||||
"path_symlink(path0={:#x?}, path_len0={}, fd={:?}, path1={:#x?}, path_len1={})",
|
||||
path0,
|
||||
path_len0,
|
||||
fd,
|
||||
path1,
|
||||
path_len1
|
||||
);
|
||||
let wasi_ctx = ok_or_errno!(get_wasi_ctx(&mut *vmctx));
|
||||
let memory = ok_or_errno!(get_memory(&mut *vmctx));
|
||||
hostcalls::path_symlink(
|
||||
wasi_ctx,
|
||||
memory,
|
||||
path0,
|
||||
path_len0,
|
||||
fd,
|
||||
path1,
|
||||
path_len1
|
||||
)
|
||||
}
|
||||
|
||||
pub unsafe extern "C" fn path_unlink_file(
|
||||
vmctx: *mut VMContext,
|
||||
fd: wasi::__wasi_fd_t,
|
||||
path: wasi32::uintptr_t,
|
||||
path_len: wasi32::size_t,
|
||||
) -> wasi::__wasi_errno_t {
|
||||
trace!(
|
||||
"path_unlink_file(fd={:?}, path={:#x?}, path_len={})",
|
||||
fd,
|
||||
path,
|
||||
path_len
|
||||
);
|
||||
let wasi_ctx = ok_or_errno!(get_wasi_ctx(&mut *vmctx));
|
||||
let memory = ok_or_errno!(get_memory(&mut *vmctx));
|
||||
hostcalls::path_unlink_file(wasi_ctx, memory, fd, path, path_len)
|
||||
}
|
||||
|
||||
pub unsafe extern "C" fn path_remove_directory(
|
||||
vmctx: *mut VMContext,
|
||||
fd: wasi::__wasi_fd_t,
|
||||
path: wasi32::uintptr_t,
|
||||
path_len: wasi32::size_t,
|
||||
) -> wasi::__wasi_errno_t {
|
||||
trace!(
|
||||
"path_remove_directory(fd={:?}, path={:#x?}, path_len={})",
|
||||
fd,
|
||||
path,
|
||||
path_len
|
||||
);
|
||||
let wasi_ctx = ok_or_errno!(get_wasi_ctx(&mut *vmctx));
|
||||
let memory = ok_or_errno!(get_memory(&mut *vmctx));
|
||||
hostcalls::path_remove_directory(wasi_ctx, memory, fd, path, path_len)
|
||||
}
|
||||
|
||||
pub unsafe extern "C" fn poll_oneoff(
|
||||
vmctx: *mut VMContext,
|
||||
in_: wasi32::uintptr_t,
|
||||
out: wasi32::uintptr_t,
|
||||
nsubscriptions: wasi32::size_t,
|
||||
nevents: wasi32::uintptr_t,
|
||||
) -> wasi::__wasi_errno_t {
|
||||
trace!(
|
||||
"poll_oneoff(in={:#x?}, out={:#x?}, nsubscriptions={}, nevents={:#x?})",
|
||||
in_,
|
||||
out,
|
||||
nsubscriptions,
|
||||
nevents,
|
||||
);
|
||||
let wasi_ctx = ok_or_errno!(get_wasi_ctx(&mut *vmctx));
|
||||
let memory = ok_or_errno!(get_memory(&mut *vmctx));
|
||||
hostcalls::poll_oneoff(wasi_ctx, memory, in_, out, nsubscriptions, nevents)
|
||||
}
|
||||
|
||||
pub unsafe extern "C" fn proc_exit(_vmctx: *mut VMContext, rval: u32,) -> () {
|
||||
trace!("proc_exit(rval={:?})", rval);
|
||||
hostcalls::proc_exit(rval)
|
||||
}
|
||||
|
||||
pub unsafe extern "C" fn proc_raise(
|
||||
vmctx: *mut VMContext,
|
||||
sig: wasi::__wasi_signal_t,
|
||||
) -> wasi::__wasi_errno_t {
|
||||
trace!("proc_raise(sig={:?})", sig);
|
||||
let wasi_ctx = ok_or_errno!(get_wasi_ctx(&mut *vmctx));
|
||||
let memory = ok_or_errno!(get_memory(&mut *vmctx));
|
||||
hostcalls::proc_raise(wasi_ctx, memory, sig)
|
||||
}
|
||||
|
||||
pub unsafe extern "C" fn random_get(
|
||||
vmctx: *mut VMContext,
|
||||
buf: wasi32::uintptr_t,
|
||||
buf_len: wasi32::size_t,
|
||||
) -> wasi::__wasi_errno_t {
|
||||
trace!("random_get(buf={:#x?}, buf_len={:?})", buf, buf_len);
|
||||
let memory = ok_or_errno!(get_memory(&mut *vmctx));
|
||||
hostcalls::random_get(memory, buf, buf_len)
|
||||
}
|
||||
|
||||
pub unsafe extern "C" fn sched_yield(_vmctx: *mut VMContext,) -> wasi::__wasi_errno_t {
|
||||
trace!("sched_yield(void)");
|
||||
hostcalls::sched_yield()
|
||||
}
|
||||
|
||||
pub unsafe extern "C" fn sock_recv(
|
||||
vmctx: *mut VMContext,
|
||||
sock: wasi::__wasi_fd_t,
|
||||
ri_data: wasi32::uintptr_t,
|
||||
ri_data_len: wasi32::size_t,
|
||||
ri_flags: wasi::__wasi_riflags_t,
|
||||
ro_datalen: wasi32::uintptr_t,
|
||||
ro_flags: wasi32::uintptr_t,
|
||||
) -> wasi::__wasi_errno_t {
|
||||
trace!(
|
||||
"sock_recv(sock={:?}, ri_data={:#x?}, ri_data_len={}, ri_flags={:#x?}, ro_datalen={:#x?}, ro_flags={:#x?})",
|
||||
sock,
|
||||
ri_data, ri_data_len, ri_flags,
|
||||
ro_datalen, ro_flags
|
||||
);
|
||||
let wasi_ctx = ok_or_errno!(get_wasi_ctx(&mut *vmctx));
|
||||
let memory = ok_or_errno!(get_memory(&mut *vmctx));
|
||||
hostcalls::sock_recv(
|
||||
wasi_ctx,
|
||||
memory,
|
||||
sock,
|
||||
ri_data,
|
||||
ri_data_len,
|
||||
ri_flags,
|
||||
ro_datalen,
|
||||
ro_flags
|
||||
)
|
||||
}
|
||||
|
||||
pub unsafe extern "C" fn sock_send(
|
||||
vmctx: *mut VMContext,
|
||||
sock: wasi::__wasi_fd_t,
|
||||
si_data: wasi32::uintptr_t,
|
||||
si_data_len: wasi32::size_t,
|
||||
si_flags: wasi::__wasi_siflags_t,
|
||||
so_datalen: wasi32::uintptr_t,
|
||||
) -> wasi::__wasi_errno_t {
|
||||
trace!(
|
||||
"sock_send(sock={:?}, si_data={:#x?}, si_data_len={}, si_flags={:#x?}, so_datalen={:#x?})",
|
||||
sock,
|
||||
si_data, si_data_len, si_flags, so_datalen,
|
||||
);
|
||||
let wasi_ctx = ok_or_errno!(get_wasi_ctx(&mut *vmctx));
|
||||
let memory = ok_or_errno!(get_memory(&mut *vmctx));
|
||||
hostcalls::sock_send(
|
||||
wasi_ctx,
|
||||
memory,
|
||||
sock,
|
||||
si_data,
|
||||
si_data_len,
|
||||
si_flags,
|
||||
so_datalen
|
||||
)
|
||||
}
|
||||
|
||||
pub unsafe extern "C" fn sock_shutdown(
|
||||
vmctx: *mut VMContext,
|
||||
sock: wasi::__wasi_fd_t,
|
||||
how: wasi::__wasi_sdflags_t,
|
||||
) -> wasi::__wasi_errno_t {
|
||||
trace!("sock_shutdown(sock={:?}, how={:?})", sock, how);
|
||||
let wasi_ctx = ok_or_errno!(get_wasi_ctx(&mut *vmctx));
|
||||
let memory = ok_or_errno!(get_memory(&mut *vmctx));
|
||||
hostcalls::sock_shutdown(wasi_ctx, memory, sock, how)
|
||||
}
|
||||
}
|
||||
@@ -99,7 +99,7 @@ fn get_memory(vmctx: &mut VMContext) -> Result<&mut [u8], wasi::__wasi_errno_t>
|
||||
"no export named \"memory\", or the export isn't a mem: {:?}",
|
||||
x
|
||||
);
|
||||
Err(wasi::__WASI_EINVAL)
|
||||
Err(wasi::__WASI_ERRNO_INVAL)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,6 +43,7 @@ use wasmtime_environ::{cache_create_new_config, cache_init};
|
||||
use wasmtime_interface_types::ModuleData;
|
||||
use wasmtime_jit::Features;
|
||||
use wasmtime_wasi::create_wasi_instance;
|
||||
use wasmtime_wasi::old::snapshot_0::create_wasi_instance as create_wasi_instance_snapshot_0;
|
||||
#[cfg(feature = "wasi-c")]
|
||||
use wasmtime_wasi_c::instantiate_wasi_c;
|
||||
use wasmtime_wast::instantiate_spectest;
|
||||
@@ -80,7 +81,7 @@ Options:
|
||||
--lightbeam use Lightbeam for all compilation
|
||||
--cranelift use Cranelift for all compilation
|
||||
--enable-simd enable proposed SIMD instructions
|
||||
--wasi-c enable the wasi-c implementation of WASI
|
||||
--wasi-c enable the wasi-c implementation of `wasi_unstable`
|
||||
--preload=<wasm> load an additional wasm module before loading the main module
|
||||
--env=<env> pass an environment variable (\"key=value\") to the program
|
||||
--dir=<dir> grant access to the given host directory
|
||||
@@ -285,7 +286,7 @@ fn main() -> Result<()> {
|
||||
let argv = compute_argv(&args.arg_file, &args.arg_arg);
|
||||
let environ = compute_environ(&args.flag_env);
|
||||
|
||||
let wasi = HostRef::new(if args.flag_wasi_c {
|
||||
let wasi_unstable = HostRef::new(if args.flag_wasi_c {
|
||||
#[cfg(feature = "wasi-c")]
|
||||
{
|
||||
let global_exports = store.borrow().global_exports().clone();
|
||||
@@ -297,11 +298,18 @@ fn main() -> Result<()> {
|
||||
bail!("wasi-c feature not enabled at build time")
|
||||
}
|
||||
} else {
|
||||
create_wasi_instance(&store, &preopen_dirs, &argv, &environ)?
|
||||
create_wasi_instance_snapshot_0(&store, &preopen_dirs, &argv, &environ)?
|
||||
});
|
||||
|
||||
module_registry.insert("wasi_unstable".to_owned(), wasi.clone());
|
||||
module_registry.insert("wasi_unstable_preview0".to_owned(), wasi);
|
||||
let wasi_snapshot_preview1 = HostRef::new(create_wasi_instance(
|
||||
&store,
|
||||
&preopen_dirs,
|
||||
&argv,
|
||||
&environ,
|
||||
)?);
|
||||
|
||||
module_registry.insert("wasi_unstable".to_owned(), wasi_unstable);
|
||||
module_registry.insert("wasi_snapshot_preview1".to_owned(), wasi_snapshot_preview1);
|
||||
|
||||
// Load the preload wasm modules.
|
||||
for filename in &args.flag_preload {
|
||||
|
||||
Reference in New Issue
Block a user