summaryrefslogtreecommitdiffstats
path: root/third_party/rust/lucet-wasi-wasmsbx/src
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/rust/lucet-wasi-wasmsbx/src')
-rw-r--r--third_party/rust/lucet-wasi-wasmsbx/src/bindings.rs11
-rw-r--r--third_party/rust/lucet-wasi-wasmsbx/src/c_api.rs98
-rw-r--r--third_party/rust/lucet-wasi-wasmsbx/src/ctx.rs260
-rw-r--r--third_party/rust/lucet-wasi-wasmsbx/src/fdentry.rs169
-rw-r--r--third_party/rust/lucet-wasi-wasmsbx/src/host.rs346
-rw-r--r--third_party/rust/lucet-wasi-wasmsbx/src/hostcalls/fs.rs1358
-rw-r--r--third_party/rust/lucet-wasi-wasmsbx/src/hostcalls/fs_helpers.rs306
-rw-r--r--third_party/rust/lucet-wasi-wasmsbx/src/hostcalls/misc.rs457
-rw-r--r--third_party/rust/lucet-wasi-wasmsbx/src/hostcalls/mod.rs448
-rw-r--r--third_party/rust/lucet-wasi-wasmsbx/src/hostcalls/timers.rs113
-rw-r--r--third_party/rust/lucet-wasi-wasmsbx/src/lib.rs16
-rw-r--r--third_party/rust/lucet-wasi-wasmsbx/src/memory.rs620
-rw-r--r--third_party/rust/lucet-wasi-wasmsbx/src/wasi_host.rs1035
-rw-r--r--third_party/rust/lucet-wasi-wasmsbx/src/wasm32.rs1367
14 files changed, 6604 insertions, 0 deletions
diff --git a/third_party/rust/lucet-wasi-wasmsbx/src/bindings.rs b/third_party/rust/lucet-wasi-wasmsbx/src/bindings.rs
new file mode 100644
index 0000000000..0d454a1f04
--- /dev/null
+++ b/third_party/rust/lucet-wasi-wasmsbx/src/bindings.rs
@@ -0,0 +1,11 @@
+use lucet_module::bindings::Bindings;
+
+pub fn bindings() -> Bindings {
+ Bindings::from_str(include_str!("../bindings.json")).expect("lucet-wasi bindings.json is valid")
+}
+
+#[cfg(test)]
+#[test]
+fn test_bindings_parses() {
+ let _ = bindings();
+}
diff --git a/third_party/rust/lucet-wasi-wasmsbx/src/c_api.rs b/third_party/rust/lucet-wasi-wasmsbx/src/c_api.rs
new file mode 100644
index 0000000000..be8dc94169
--- /dev/null
+++ b/third_party/rust/lucet-wasi-wasmsbx/src/c_api.rs
@@ -0,0 +1,98 @@
+use crate::ctx::WasiCtxBuilder;
+use lucet_runtime::{DlModule, Module, Region};
+use lucet_runtime_internals::c_api::{lucet_dl_module, lucet_error, lucet_instance, lucet_region};
+use lucet_runtime_internals::instance::instance_handle_to_raw;
+use lucet_runtime_internals::{assert_nonnull, with_ffi_arcs};
+use std::ffi::CStr;
+use std::sync::Arc;
+
+#[repr(C)]
+pub struct lucet_wasi_ctx {
+ _unused: [u8; 0],
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn lucet_wasi_ctx_create() -> *mut lucet_wasi_ctx {
+ let b = WasiCtxBuilder::new();
+ Box::into_raw(Box::new(b)) as _
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn lucet_wasi_ctx_args(
+ wasi_ctx: *mut lucet_wasi_ctx,
+ argc: usize,
+ argv: *const *const libc::c_char,
+) -> lucet_error {
+ assert_nonnull!(wasi_ctx);
+ let mut b = Box::from_raw(wasi_ctx as *mut WasiCtxBuilder);
+ let args_raw = std::slice::from_raw_parts(argv, argc);
+ // TODO: error handling
+ let args = args_raw
+ .into_iter()
+ .map(|arg| CStr::from_ptr(*arg))
+ .collect::<Vec<&CStr>>();
+ *b = b.c_args(&args);
+ Box::into_raw(b);
+ lucet_error::Ok
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn lucet_wasi_ctx_inherit_env(wasi_ctx: *mut lucet_wasi_ctx) -> lucet_error {
+ assert_nonnull!(wasi_ctx);
+ let mut b = Box::from_raw(wasi_ctx as *mut WasiCtxBuilder);
+ *b = b.inherit_env();
+ Box::into_raw(b);
+ lucet_error::Ok
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn lucet_wasi_ctx_inherit_stdio(
+ wasi_ctx: *mut lucet_wasi_ctx,
+) -> lucet_error {
+ assert_nonnull!(wasi_ctx);
+ let mut b = Box::from_raw(wasi_ctx as *mut WasiCtxBuilder);
+ *b = b.inherit_stdio();
+ Box::into_raw(b);
+ lucet_error::Ok
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn lucet_wasi_ctx_destroy(wasi_ctx: *mut lucet_wasi_ctx) {
+ Box::from_raw(wasi_ctx as *mut WasiCtxBuilder);
+}
+
+/// Create a Lucet instance with the given WASI context.
+///
+/// After this call, the `wasi_ctx` pointer is no longer valid.
+#[no_mangle]
+pub unsafe extern "C" fn lucet_region_new_instance_with_wasi_ctx(
+ region: *const lucet_region,
+ module: *const lucet_dl_module,
+ wasi_ctx: *mut lucet_wasi_ctx,
+ inst_out: *mut *mut lucet_instance,
+) -> lucet_error {
+ assert_nonnull!(wasi_ctx);
+ assert_nonnull!(inst_out);
+ with_ffi_arcs!([region: dyn Region, module: DlModule], {
+ let wasi_ctx = *Box::from_raw(wasi_ctx as *mut WasiCtxBuilder);
+ region
+ .new_instance_builder(module.clone() as Arc<dyn Module>)
+ .with_embed_ctx(wasi_ctx.build())
+ .build()
+ .map(|i| {
+ inst_out.write(instance_handle_to_raw(i) as _);
+ lucet_error::Ok
+ })
+ .unwrap_or_else(|e| e.into())
+ })
+}
+
+/// Call this if you're having trouble with `__wasi_*` symbols not being exported.
+///
+/// This is pretty hackish; we will hopefully be able to avoid this altogether once [this
+/// issue](https://github.com/rust-lang/rust/issues/58037) is addressed.
+#[no_mangle]
+#[doc(hidden)]
+pub extern "C" fn lucet_wasi_internal_ensure_linked() {
+ crate::hostcalls::ensure_linked();
+}
diff --git a/third_party/rust/lucet-wasi-wasmsbx/src/ctx.rs b/third_party/rust/lucet-wasi-wasmsbx/src/ctx.rs
new file mode 100644
index 0000000000..49e96145b5
--- /dev/null
+++ b/third_party/rust/lucet-wasi-wasmsbx/src/ctx.rs
@@ -0,0 +1,260 @@
+use crate::fdentry::FdEntry;
+use crate::host;
+use failure::{bail, format_err, Error};
+use nix::unistd::dup;
+use std::collections::HashMap;
+use std::ffi::{CStr, CString};
+use std::fs::File;
+use std::io::{stderr, stdin, stdout};
+use std::os::unix::prelude::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
+use std::path::{Path, PathBuf};
+
+pub struct WasiCtxBuilder {
+ fds: HashMap<host::__wasi_fd_t, FdEntry>,
+ preopens: HashMap<PathBuf, File>,
+ args: Vec<CString>,
+ env: HashMap<CString, CString>,
+}
+
+lazy_static! {
+ static ref DEV_NULL_FILE: File = dev_null();
+}
+
+impl WasiCtxBuilder {
+ /// Builder for a new `WasiCtx`.
+ pub fn new() -> Self {
+ WasiCtxBuilder {
+ fds: HashMap::new(),
+ preopens: HashMap::new(),
+ args: vec![],
+ env: HashMap::new(),
+ }
+ }
+
+ pub fn args(mut self, args: &[&str]) -> Self {
+ self.args = args
+ .into_iter()
+ .map(|arg| CString::new(*arg).expect("argument can be converted to a CString"))
+ .collect();
+ self
+ }
+
+ pub fn arg(mut self, arg: &str) -> Self {
+ self.args
+ .push(CString::new(arg).expect("argument can be converted to a CString"));
+ self
+ }
+
+ pub fn c_args<S: AsRef<CStr>>(mut self, args: &[S]) -> Self {
+ self.args = args
+ .into_iter()
+ .map(|arg| arg.as_ref().to_owned())
+ .collect();
+ self
+ }
+
+ pub fn c_arg<S: AsRef<CStr>>(mut self, arg: S) -> Self {
+ self.args.push(arg.as_ref().to_owned());
+ self
+ }
+
+ pub fn inherit_stdio(self) -> Self {
+ self.fd_dup(0, &stdin())
+ .fd_dup(1, &stdout())
+ .fd_dup(2, &stderr())
+ }
+
+ pub fn inherit_stdio_no_syscall(self) -> Self {
+ self.fd_dup_for_io_desc(0, &stdin(), false /* writeable */)
+ .fd_dup_for_io_desc(1, &stdout(), true /* writeable */)
+ .fd_dup_for_io_desc(2, &stderr(), true /* writeable */)
+ }
+
+ pub fn inherit_env(mut self) -> Self {
+ self.env = std::env::vars()
+ .map(|(k, v)| {
+ // TODO: handle errors, and possibly assert that the key is valid per POSIX
+ (
+ CString::new(k).expect("environment key can be converted to a CString"),
+ CString::new(v).expect("environment value can be converted to a CString"),
+ )
+ })
+ .collect();
+ self
+ }
+
+ pub fn env(mut self, k: &str, v: &str) -> Self {
+ self.env.insert(
+ // TODO: handle errors, and possibly assert that the key is valid per POSIX
+ CString::new(k).expect("environment key can be converted to a CString"),
+ CString::new(v).expect("environment value can be converted to a CString"),
+ );
+ self
+ }
+
+ pub fn c_env<S, T>(mut self, k: S, v: T) -> Self
+ where
+ S: AsRef<CStr>,
+ T: AsRef<CStr>,
+ {
+ self.env
+ .insert(k.as_ref().to_owned(), v.as_ref().to_owned());
+ self
+ }
+
+ /// Add an existing file-like object as a file descriptor in the context.
+ ///
+ /// When the `WasiCtx` is dropped, all of its associated file descriptors are `close`d. If you
+ /// do not want this to close the existing object, use `WasiCtxBuilder::fd_dup()`.
+ pub fn fd<F: IntoRawFd>(self, wasm_fd: host::__wasi_fd_t, fd: F) -> Self {
+ // safe because we're getting a valid RawFd from the F directly
+ unsafe { self.raw_fd(wasm_fd, fd.into_raw_fd()) }
+ }
+
+ /// Add an existing file-like object as a duplicate file descriptor in the context.
+ ///
+ /// The underlying file descriptor of this object will be duplicated before being added to the
+ /// context, so it will not be closed when the `WasiCtx` is dropped.
+ ///
+ /// TODO: handle `dup` errors
+ pub fn fd_dup<F: AsRawFd>(self, wasm_fd: host::__wasi_fd_t, fd: &F) -> Self {
+ // safe because we're getting a valid RawFd from the F directly
+ unsafe { self.raw_fd(wasm_fd, dup(fd.as_raw_fd()).unwrap()) }
+ }
+
+ pub fn fd_dup_for_io_desc<F: AsRawFd>(self, wasm_fd: host::__wasi_fd_t, fd: &F, writable : bool) -> Self {
+ // safe because we're getting a valid RawFd from the F directly
+ unsafe { self.raw_fd_for_io_desc(wasm_fd, dup(fd.as_raw_fd()).unwrap(), writable) }
+ }
+
+ /// Add an existing file descriptor to the context.
+ ///
+ /// When the `WasiCtx` is dropped, this file descriptor will be `close`d. If you do not want to
+ /// close the existing descriptor, use `WasiCtxBuilder::raw_fd_dup()`.
+ pub unsafe fn raw_fd(mut self, wasm_fd: host::__wasi_fd_t, fd: RawFd) -> Self {
+ self.fds.insert(wasm_fd, FdEntry::from_raw_fd(fd));
+ self
+ }
+
+ pub unsafe fn raw_fd_for_io_desc(mut self, wasm_fd: host::__wasi_fd_t, fd: RawFd, writable : bool) -> Self {
+ self.fds.insert(wasm_fd, FdEntry::from_raw_fd_for_io_desc(fd, writable));
+ self
+ }
+
+ /// Add a duplicate of an existing file descriptor to the context.
+ ///
+ /// The file descriptor will be duplicated before being added to the context, so it will not be
+ /// closed when the `WasiCtx` is dropped.
+ ///
+ /// TODO: handle `dup` errors
+ pub unsafe fn raw_fd_dup(self, wasm_fd: host::__wasi_fd_t, fd: RawFd) -> Self {
+ self.raw_fd(wasm_fd, dup(fd).unwrap())
+ }
+
+ pub fn preopened_dir<P: AsRef<Path>>(mut self, dir: File, guest_path: P) -> Self {
+ self.preopens.insert(guest_path.as_ref().to_owned(), dir);
+ self
+ }
+
+ pub fn build(mut self) -> Result<WasiCtx, Error> {
+ // startup code starts looking at fd 3 for preopens
+ let mut preopen_fd = 3;
+ for (guest_path, dir) in self.preopens {
+ if !dir.metadata()?.is_dir() {
+ bail!("preopened file is not a directory");
+ }
+ while self.fds.contains_key(&preopen_fd) {
+ preopen_fd = preopen_fd
+ .checked_add(1)
+ .ok_or(format_err!("not enough file handles"))?;
+ }
+ let mut fe = FdEntry::from_file(dir);
+ fe.preopen_path = Some(guest_path);
+ self.fds.insert(preopen_fd, fe);
+ preopen_fd += 1;
+ }
+
+ let env = self
+ .env
+ .into_iter()
+ .map(|(k, v)| {
+ let mut pair = k.into_bytes();
+ pair.extend_from_slice(b"=");
+ pair.extend_from_slice(v.to_bytes_with_nul());
+ // constructing a new CString from existing CStrings is safe
+ unsafe { CString::from_vec_unchecked(pair) }
+ })
+ .collect();
+
+ Ok(WasiCtx {
+ fds: self.fds,
+ args: self.args,
+ env,
+ })
+ }
+}
+
+#[derive(Debug)]
+pub struct WasiCtx {
+ pub fds: HashMap<host::__wasi_fd_t, FdEntry>,
+ pub args: Vec<CString>,
+ pub 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(args: &[&str]) -> WasiCtx {
+ WasiCtxBuilder::new()
+ .args(args)
+ .inherit_stdio()
+ .inherit_env()
+ .build()
+ .expect("default options don't fail")
+ }
+
+ pub fn get_fd_entry(
+ &self,
+ fd: host::__wasi_fd_t,
+ rights_base: host::__wasi_rights_t,
+ rights_inheriting: host::__wasi_rights_t,
+ ) -> Result<&FdEntry, host::__wasi_errno_t> {
+ if let Some(fe) = self.fds.get(&fd) {
+ // validate rights
+ if !fe.rights_base & rights_base != 0 || !fe.rights_inheriting & rights_inheriting != 0
+ {
+ Err(host::__WASI_ENOTCAPABLE as host::__wasi_errno_t)
+ } else {
+ Ok(fe)
+ }
+ } else {
+ Err(host::__WASI_EBADF as host::__wasi_errno_t)
+ }
+ }
+
+ pub fn insert_fd_entry(
+ &mut self,
+ fe: FdEntry,
+ ) -> Result<host::__wasi_fd_t, host::__wasi_errno_t> {
+ // never insert where stdio handles usually are
+ 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(host::__WASI_EMFILE as host::__wasi_errno_t);
+ }
+ }
+ self.fds.insert(fd, fe);
+ Ok(fd)
+ }
+}
+
+fn dev_null() -> File {
+ File::open("/dev/null").expect("failed to open /dev/null")
+}
diff --git a/third_party/rust/lucet-wasi-wasmsbx/src/fdentry.rs b/third_party/rust/lucet-wasi-wasmsbx/src/fdentry.rs
new file mode 100644
index 0000000000..7c65a64705
--- /dev/null
+++ b/third_party/rust/lucet-wasi-wasmsbx/src/fdentry.rs
@@ -0,0 +1,169 @@
+use crate::host;
+use std::fs::File;
+use std::os::unix::prelude::{FileTypeExt, FromRawFd, IntoRawFd, RawFd};
+use std::path::PathBuf;
+
+#[derive(Debug)]
+pub struct FdEntry {
+ pub fd_object: FdObject,
+ pub rights_base: host::__wasi_rights_t,
+ pub rights_inheriting: host::__wasi_rights_t,
+ pub preopen_path: Option<PathBuf>,
+}
+
+impl FdEntry {
+ pub fn from_file(file: File) -> FdEntry {
+ unsafe { FdEntry::from_raw_fd(file.into_raw_fd()) }
+ }
+ pub unsafe fn from_raw_fd_for_io_desc(rawfd: RawFd, writable : bool) -> FdEntry {
+ let (ty, mut rights_base, rights_inheriting) =
+ (
+ host::__WASI_FILETYPE_CHARACTER_DEVICE,
+ host::RIGHTS_TTY_BASE,
+ host::RIGHTS_TTY_BASE,
+ );
+
+ if !writable {
+ rights_base &= !host::__WASI_RIGHT_FD_WRITE as host::__wasi_rights_t;
+ } else {
+ rights_base &= !host::__WASI_RIGHT_FD_READ as host::__wasi_rights_t;
+ }
+
+ FdEntry {
+ fd_object: FdObject {
+ ty: ty as u8,
+ rawfd,
+ needs_close: true,
+ },
+ rights_base,
+ rights_inheriting,
+ preopen_path: None,
+ }
+ }
+
+}
+
+impl FromRawFd for FdEntry {
+ // TODO: make this a different function with error handling, rather than using the trait method
+ unsafe fn from_raw_fd(rawfd: RawFd) -> FdEntry {
+ let (ty, mut rights_base, rights_inheriting) =
+ determine_type_rights(rawfd).expect("can determine file rights");
+
+ use nix::fcntl::{fcntl, OFlag, F_GETFL};
+ let flags_bits = fcntl(rawfd, F_GETFL).expect("fcntl succeeds");
+ let flags = OFlag::from_bits_truncate(flags_bits);
+ let accmode = flags & OFlag::O_ACCMODE;
+ if accmode == OFlag::O_RDONLY {
+ rights_base &= !host::__WASI_RIGHT_FD_WRITE as host::__wasi_rights_t;
+ } else if accmode == OFlag::O_WRONLY {
+ rights_base &= !host::__WASI_RIGHT_FD_READ as host::__wasi_rights_t;
+ }
+
+ FdEntry {
+ fd_object: FdObject {
+ ty: ty as u8,
+ rawfd,
+ needs_close: true,
+ },
+ rights_base,
+ rights_inheriting,
+ preopen_path: None,
+ }
+ }
+}
+
+// TODO: can probably make this safe by using fcntl directly rather than going through `File`
+pub unsafe fn determine_type_rights(
+ rawfd: RawFd,
+) -> Result<
+ (
+ host::__wasi_filetype_t,
+ host::__wasi_rights_t,
+ host::__wasi_rights_t,
+ ),
+ host::__wasi_errno_t,
+> {
+ let (ty, rights_base, rights_inheriting) = {
+ let file = File::from_raw_fd(rawfd);
+ let ft = file.metadata().unwrap().file_type();
+ // we just make a `File` here for convenience; we don't want it to close when it drops
+ std::mem::forget(file);
+ if ft.is_block_device() {
+ (
+ host::__WASI_FILETYPE_BLOCK_DEVICE,
+ host::RIGHTS_BLOCK_DEVICE_BASE,
+ host::RIGHTS_BLOCK_DEVICE_INHERITING,
+ )
+ } else if ft.is_char_device() {
+ if nix::unistd::isatty(rawfd).unwrap() {
+ (
+ host::__WASI_FILETYPE_CHARACTER_DEVICE,
+ host::RIGHTS_TTY_BASE,
+ host::RIGHTS_TTY_BASE,
+ )
+ } else {
+ (
+ host::__WASI_FILETYPE_CHARACTER_DEVICE,
+ host::RIGHTS_CHARACTER_DEVICE_BASE,
+ host::RIGHTS_CHARACTER_DEVICE_INHERITING,
+ )
+ }
+ } else if ft.is_dir() {
+ (
+ host::__WASI_FILETYPE_DIRECTORY,
+ host::RIGHTS_DIRECTORY_BASE,
+ host::RIGHTS_DIRECTORY_INHERITING,
+ )
+ } else if ft.is_file() {
+ (
+ host::__WASI_FILETYPE_REGULAR_FILE,
+ host::RIGHTS_REGULAR_FILE_BASE,
+ host::RIGHTS_REGULAR_FILE_INHERITING,
+ )
+ // } else if ft.is_socket() {
+ // use nix::sys::socket;
+ // match socket::getsockopt(rawfd, socket::sockopt::SockType).unwrap() {
+ // socket::SockType::Datagram => (
+ // host::__WASI_FILETYPE_SOCKET_DGRAM,
+ // host::RIGHTS_SOCKET_BASE,
+ // host::RIGHTS_SOCKET_INHERITING,
+ // ),
+ // socket::SockType::Stream => (
+ // host::__WASI_FILETYPE_SOCKET_STREAM,
+ // host::RIGHTS_SOCKET_BASE,
+ // host::RIGHTS_SOCKET_INHERITING,
+ // ),
+ // _ => return Err(host::__WASI_EINVAL as host::__wasi_errno_t),
+ // }
+ } else if ft.is_fifo() {
+ (
+ host::__WASI_FILETYPE_SOCKET_STREAM,
+ host::RIGHTS_SOCKET_BASE,
+ host::RIGHTS_SOCKET_INHERITING,
+ )
+ } else {
+ return Err(host::__WASI_EINVAL as host::__wasi_errno_t);
+ }
+ };
+ Ok((
+ ty as host::__wasi_filetype_t,
+ rights_base,
+ rights_inheriting,
+ ))
+}
+
+#[derive(Debug)]
+pub struct FdObject {
+ pub ty: host::__wasi_filetype_t,
+ pub rawfd: RawFd,
+ pub needs_close: bool,
+ // TODO: directories
+}
+
+impl Drop for FdObject {
+ fn drop(&mut self) {
+ if self.needs_close {
+ nix::unistd::close(self.rawfd).unwrap_or_else(|e| eprintln!("FdObject::drop(): {}", e));
+ }
+ }
+}
diff --git a/third_party/rust/lucet-wasi-wasmsbx/src/host.rs b/third_party/rust/lucet-wasi-wasmsbx/src/host.rs
new file mode 100644
index 0000000000..e1a6027d0c
--- /dev/null
+++ b/third_party/rust/lucet-wasi-wasmsbx/src/host.rs
@@ -0,0 +1,346 @@
+#![allow(non_camel_case_types)]
+#![allow(non_snake_case)]
+
+include!("wasi_host.rs");
+
+pub type void = ::std::os::raw::c_void;
+
+pub unsafe fn ciovec_to_nix<'a>(ciovec: &'a __wasi_ciovec_t) -> nix::sys::uio::IoVec<&'a [u8]> {
+ let slice = std::slice::from_raw_parts(ciovec.buf as *const u8, ciovec.buf_len);
+ nix::sys::uio::IoVec::from_slice(slice)
+}
+
+pub unsafe fn ciovec_to_nix_mut<'a>(
+ ciovec: &'a mut __wasi_ciovec_t,
+) -> nix::sys::uio::IoVec<&'a mut [u8]> {
+ let slice = std::slice::from_raw_parts_mut(ciovec.buf as *mut u8, ciovec.buf_len);
+ nix::sys::uio::IoVec::from_mut_slice(slice)
+}
+
+pub unsafe fn iovec_to_nix<'a>(iovec: &'a __wasi_iovec_t) -> nix::sys::uio::IoVec<&'a [u8]> {
+ let slice = std::slice::from_raw_parts(iovec.buf as *const u8, iovec.buf_len);
+ nix::sys::uio::IoVec::from_slice(slice)
+}
+
+pub unsafe fn iovec_to_nix_mut<'a>(
+ iovec: &'a mut __wasi_iovec_t,
+) -> nix::sys::uio::IoVec<&'a mut [u8]> {
+ let slice = std::slice::from_raw_parts_mut(iovec.buf as *mut u8, iovec.buf_len);
+ nix::sys::uio::IoVec::from_mut_slice(slice)
+}
+
+pub fn errno_from_nix(errno: nix::errno::Errno) -> __wasi_errno_t {
+ let e = match errno {
+ nix::errno::Errno::EPERM => __WASI_EPERM,
+ nix::errno::Errno::ENOENT => __WASI_ENOENT,
+ nix::errno::Errno::ESRCH => __WASI_ESRCH,
+ nix::errno::Errno::EINTR => __WASI_EINTR,
+ nix::errno::Errno::EIO => __WASI_EIO,
+ nix::errno::Errno::ENXIO => __WASI_ENXIO,
+ nix::errno::Errno::E2BIG => __WASI_E2BIG,
+ nix::errno::Errno::ENOEXEC => __WASI_ENOEXEC,
+ nix::errno::Errno::EBADF => __WASI_EBADF,
+ nix::errno::Errno::ECHILD => __WASI_ECHILD,
+ nix::errno::Errno::EAGAIN => __WASI_EAGAIN,
+ nix::errno::Errno::ENOMEM => __WASI_ENOMEM,
+ nix::errno::Errno::EACCES => __WASI_EACCES,
+ nix::errno::Errno::EFAULT => __WASI_EFAULT,
+ nix::errno::Errno::EBUSY => __WASI_EBUSY,
+ nix::errno::Errno::EEXIST => __WASI_EEXIST,
+ nix::errno::Errno::EXDEV => __WASI_EXDEV,
+ nix::errno::Errno::ENODEV => __WASI_ENODEV,
+ nix::errno::Errno::ENOTDIR => __WASI_ENOTDIR,
+ nix::errno::Errno::EISDIR => __WASI_EISDIR,
+ nix::errno::Errno::EINVAL => __WASI_EINVAL,
+ nix::errno::Errno::ENFILE => __WASI_ENFILE,
+ nix::errno::Errno::EMFILE => __WASI_EMFILE,
+ nix::errno::Errno::ENOTTY => __WASI_ENOTTY,
+ nix::errno::Errno::ETXTBSY => __WASI_ETXTBSY,
+ nix::errno::Errno::EFBIG => __WASI_EFBIG,
+ nix::errno::Errno::ENOSPC => __WASI_ENOSPC,
+ nix::errno::Errno::ESPIPE => __WASI_ESPIPE,
+ nix::errno::Errno::EROFS => __WASI_EROFS,
+ nix::errno::Errno::EMLINK => __WASI_EMLINK,
+ nix::errno::Errno::EPIPE => __WASI_EPIPE,
+ nix::errno::Errno::EDOM => __WASI_EDOM,
+ nix::errno::Errno::ERANGE => __WASI_ERANGE,
+ nix::errno::Errno::EDEADLK => __WASI_EDEADLK,
+ nix::errno::Errno::ENAMETOOLONG => __WASI_ENAMETOOLONG,
+ nix::errno::Errno::ENOLCK => __WASI_ENOLCK,
+ nix::errno::Errno::ENOSYS => __WASI_ENOSYS,
+ nix::errno::Errno::ENOTEMPTY => __WASI_ENOTEMPTY,
+ nix::errno::Errno::ELOOP => __WASI_ELOOP,
+ nix::errno::Errno::ENOMSG => __WASI_ENOMSG,
+ nix::errno::Errno::EIDRM => __WASI_EIDRM,
+ nix::errno::Errno::ENOLINK => __WASI_ENOLINK,
+ nix::errno::Errno::EPROTO => __WASI_EPROTO,
+ nix::errno::Errno::EMULTIHOP => __WASI_EMULTIHOP,
+ nix::errno::Errno::EBADMSG => __WASI_EBADMSG,
+ nix::errno::Errno::EOVERFLOW => __WASI_EOVERFLOW,
+ nix::errno::Errno::EILSEQ => __WASI_EILSEQ,
+ nix::errno::Errno::ENOTSOCK => __WASI_ENOTSOCK,
+ nix::errno::Errno::EDESTADDRREQ => __WASI_EDESTADDRREQ,
+ nix::errno::Errno::EMSGSIZE => __WASI_EMSGSIZE,
+ nix::errno::Errno::EPROTOTYPE => __WASI_EPROTOTYPE,
+ nix::errno::Errno::ENOPROTOOPT => __WASI_ENOPROTOOPT,
+ nix::errno::Errno::EPROTONOSUPPORT => __WASI_EPROTONOSUPPORT,
+ nix::errno::Errno::EAFNOSUPPORT => __WASI_EAFNOSUPPORT,
+ nix::errno::Errno::EADDRINUSE => __WASI_EADDRINUSE,
+ nix::errno::Errno::EADDRNOTAVAIL => __WASI_EADDRNOTAVAIL,
+ nix::errno::Errno::ENETDOWN => __WASI_ENETDOWN,
+ nix::errno::Errno::ENETUNREACH => __WASI_ENETUNREACH,
+ nix::errno::Errno::ENETRESET => __WASI_ENETRESET,
+ nix::errno::Errno::ECONNABORTED => __WASI_ECONNABORTED,
+ nix::errno::Errno::ECONNRESET => __WASI_ECONNRESET,
+ nix::errno::Errno::ENOBUFS => __WASI_ENOBUFS,
+ nix::errno::Errno::EISCONN => __WASI_EISCONN,
+ nix::errno::Errno::ENOTCONN => __WASI_ENOTCONN,
+ nix::errno::Errno::ETIMEDOUT => __WASI_ETIMEDOUT,
+ nix::errno::Errno::ECONNREFUSED => __WASI_ECONNREFUSED,
+ nix::errno::Errno::EHOSTUNREACH => __WASI_EHOSTUNREACH,
+ nix::errno::Errno::EALREADY => __WASI_EALREADY,
+ nix::errno::Errno::EINPROGRESS => __WASI_EINPROGRESS,
+ nix::errno::Errno::ESTALE => __WASI_ESTALE,
+ nix::errno::Errno::EDQUOT => __WASI_EDQUOT,
+ nix::errno::Errno::ECANCELED => __WASI_ECANCELED,
+ nix::errno::Errno::EOWNERDEAD => __WASI_EOWNERDEAD,
+ nix::errno::Errno::ENOTRECOVERABLE => __WASI_ENOTRECOVERABLE,
+ _ => __WASI_ENOSYS,
+ };
+ e as __wasi_errno_t
+}
+
+#[cfg(target_os = "linux")]
+const O_RSYNC: nix::fcntl::OFlag = nix::fcntl::OFlag::O_RSYNC;
+
+#[cfg(not(target_os = "linux"))]
+const O_RSYNC: nix::fcntl::OFlag = nix::fcntl::OFlag::O_SYNC;
+
+pub fn nix_from_fdflags(fdflags: __wasi_fdflags_t) -> nix::fcntl::OFlag {
+ use nix::fcntl::OFlag;
+ let mut nix_flags = OFlag::empty();
+ if fdflags & (__WASI_FDFLAG_APPEND as __wasi_fdflags_t) != 0 {
+ nix_flags.insert(OFlag::O_APPEND);
+ }
+ if fdflags & (__WASI_FDFLAG_DSYNC as __wasi_fdflags_t) != 0 {
+ nix_flags.insert(OFlag::O_DSYNC);
+ }
+ if fdflags & (__WASI_FDFLAG_NONBLOCK as __wasi_fdflags_t) != 0 {
+ nix_flags.insert(OFlag::O_NONBLOCK);
+ }
+ if fdflags & (__WASI_FDFLAG_RSYNC as __wasi_fdflags_t) != 0 {
+ nix_flags.insert(O_RSYNC);
+ }
+ if fdflags & (__WASI_FDFLAG_SYNC as __wasi_fdflags_t) != 0 {
+ nix_flags.insert(OFlag::O_SYNC);
+ }
+ nix_flags
+}
+
+pub fn fdflags_from_nix(oflags: nix::fcntl::OFlag) -> __wasi_fdflags_t {
+ use nix::fcntl::OFlag;
+ let mut fdflags = 0;
+ if oflags.contains(OFlag::O_APPEND) {
+ fdflags |= __WASI_FDFLAG_APPEND;
+ }
+ if oflags.contains(OFlag::O_DSYNC) {
+ fdflags |= __WASI_FDFLAG_DSYNC;
+ }
+ if oflags.contains(OFlag::O_NONBLOCK) {
+ fdflags |= __WASI_FDFLAG_NONBLOCK;
+ }
+ if oflags.contains(O_RSYNC) {
+ fdflags |= __WASI_FDFLAG_RSYNC;
+ }
+ if oflags.contains(OFlag::O_SYNC) {
+ fdflags |= __WASI_FDFLAG_SYNC;
+ }
+ fdflags as __wasi_fdflags_t
+}
+
+pub fn nix_from_oflags(oflags: __wasi_oflags_t) -> nix::fcntl::OFlag {
+ use nix::fcntl::OFlag;
+ let mut nix_flags = OFlag::empty();
+ if oflags & (__WASI_O_CREAT as __wasi_oflags_t) != 0 {
+ nix_flags.insert(OFlag::O_CREAT);
+ }
+ if oflags & (__WASI_O_DIRECTORY as __wasi_oflags_t) != 0 {
+ nix_flags.insert(OFlag::O_DIRECTORY);
+ }
+ if oflags & (__WASI_O_EXCL as __wasi_oflags_t) != 0 {
+ nix_flags.insert(OFlag::O_EXCL);
+ }
+ if oflags & (__WASI_O_TRUNC as __wasi_oflags_t) != 0 {
+ nix_flags.insert(OFlag::O_TRUNC);
+ }
+ nix_flags
+}
+
+pub fn filetype_from_nix(sflags: nix::sys::stat::SFlag) -> __wasi_filetype_t {
+ use nix::sys::stat::SFlag;
+ if sflags.contains(SFlag::S_IFCHR) {
+ __WASI_FILETYPE_CHARACTER_DEVICE as __wasi_filetype_t
+ } else if sflags.contains(SFlag::S_IFBLK) {
+ __WASI_FILETYPE_BLOCK_DEVICE as __wasi_filetype_t
+ } else if sflags.contains(SFlag::S_IFIFO) | sflags.contains(SFlag::S_IFSOCK) {
+ __WASI_FILETYPE_SOCKET_STREAM as __wasi_filetype_t
+ } else if sflags.contains(SFlag::S_IFDIR) {
+ __WASI_FILETYPE_DIRECTORY as __wasi_filetype_t
+ } else if sflags.contains(SFlag::S_IFREG) {
+ __WASI_FILETYPE_REGULAR_FILE as __wasi_filetype_t
+ } else if sflags.contains(SFlag::S_IFLNK) {
+ __WASI_FILETYPE_SYMBOLIC_LINK as __wasi_filetype_t
+ } else {
+ __WASI_FILETYPE_UNKNOWN as __wasi_filetype_t
+ }
+}
+
+pub fn nix_from_filetype(sflags: __wasi_filetype_t) -> nix::sys::stat::SFlag {
+ use nix::sys::stat::SFlag;
+ let mut nix_sflags = SFlag::empty();
+ if sflags & (__WASI_FILETYPE_CHARACTER_DEVICE as __wasi_filetype_t) != 0 {
+ nix_sflags.insert(SFlag::S_IFCHR);
+ }
+ if sflags & (__WASI_FILETYPE_BLOCK_DEVICE as __wasi_filetype_t) != 0 {
+ nix_sflags.insert(SFlag::S_IFBLK);
+ }
+ if sflags & (__WASI_FILETYPE_SOCKET_STREAM as __wasi_filetype_t) != 0 {
+ nix_sflags.insert(SFlag::S_IFIFO);
+ nix_sflags.insert(SFlag::S_IFSOCK);
+ }
+ if sflags & (__WASI_FILETYPE_DIRECTORY as __wasi_filetype_t) != 0 {
+ nix_sflags.insert(SFlag::S_IFDIR);
+ }
+ if sflags & (__WASI_FILETYPE_REGULAR_FILE as __wasi_filetype_t) != 0 {
+ nix_sflags.insert(SFlag::S_IFREG);
+ }
+ if sflags & (__WASI_FILETYPE_SYMBOLIC_LINK as __wasi_filetype_t) != 0 {
+ nix_sflags.insert(SFlag::S_IFLNK);
+ }
+ nix_sflags
+}
+
+pub fn filestat_from_nix(filestat: nix::sys::stat::FileStat) -> __wasi_filestat_t {
+ let filetype = nix::sys::stat::SFlag::from_bits_truncate(filestat.st_mode);
+ __wasi_filestat_t {
+ st_dev: filestat.st_dev as __wasi_device_t,
+ st_ino: filestat.st_ino as __wasi_inode_t,
+ st_nlink: filestat.st_nlink as __wasi_linkcount_t,
+ st_size: filestat.st_size as __wasi_filesize_t,
+ st_atim: filestat.st_atime as __wasi_timestamp_t * 1_000_000_000,
+ st_ctim: filestat.st_ctime as __wasi_timestamp_t * 1_000_000_000,
+ st_mtim: filestat.st_mtime as __wasi_timestamp_t * 1_000_000_000,
+ st_filetype: filetype_from_nix(filetype),
+ }
+}
+
+// Rights sets from wasmtime-wasi sandboxed system primitives. Transcribed because bindgen can't
+// parse the #defines.
+
+pub 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) as __wasi_rights_t;
+
+// Block and character device interaction is outside the scope of
+// CloudABI. Simply allow everything.
+pub const RIGHTS_BLOCK_DEVICE_BASE: __wasi_rights_t = RIGHTS_ALL;
+pub const RIGHTS_BLOCK_DEVICE_INHERITING: __wasi_rights_t = RIGHTS_ALL;
+pub const RIGHTS_CHARACTER_DEVICE_BASE: __wasi_rights_t = RIGHTS_ALL;
+pub 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 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)
+ as __wasi_rights_t;
+pub const RIGHTS_DIRECTORY_INHERITING: __wasi_rights_t =
+ (RIGHTS_DIRECTORY_BASE | RIGHTS_REGULAR_FILE_BASE);
+
+// Operations that apply to regular files.
+pub 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)
+ as __wasi_rights_t;
+pub const RIGHTS_REGULAR_FILE_INHERITING: __wasi_rights_t = 0;
+
+// Operations that apply to shared memory objects.
+pub const RIGHTS_SHARED_MEMORY_BASE: __wasi_rights_t = (__WASI_RIGHT_FD_READ
+ | __WASI_RIGHT_FD_WRITE
+ | __WASI_RIGHT_FD_FILESTAT_GET
+ | __WASI_RIGHT_FD_FILESTAT_SET_SIZE)
+ as __wasi_rights_t;
+pub const RIGHTS_SHARED_MEMORY_INHERITING: __wasi_rights_t = 0;
+
+// Operations that apply to sockets and socket pairs.
+pub 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)
+ as __wasi_rights_t;
+pub const RIGHTS_SOCKET_INHERITING: __wasi_rights_t = RIGHTS_ALL;
+
+// Operations that apply to TTYs.
+pub 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)
+ as __wasi_rights_t;
+pub const RIGHTS_TTY_INHERITING: __wasi_rights_t = 0;
diff --git a/third_party/rust/lucet-wasi-wasmsbx/src/hostcalls/fs.rs b/third_party/rust/lucet-wasi-wasmsbx/src/hostcalls/fs.rs
new file mode 100644
index 0000000000..db1a0c5d2d
--- /dev/null
+++ b/third_party/rust/lucet-wasi-wasmsbx/src/hostcalls/fs.rs
@@ -0,0 +1,1358 @@
+#![allow(non_camel_case_types)]
+#![allow(unused_unsafe)]
+
+use crate::ctx::WasiCtx;
+use crate::fdentry::{determine_type_rights, FdEntry};
+use crate::memory::*;
+use crate::{host, wasm32};
+
+use super::fs_helpers::*;
+use super::timers;
+use lucet_runtime::vmctx::Vmctx;
+
+use nix::libc::{self, c_long, c_void, off_t};
+use std::ffi::OsStr;
+use std::mem::MaybeUninit;
+use std::os::unix::prelude::{FromRawFd, OsStrExt};
+
+pub fn wasi_fd_close(vmctx: &mut Vmctx, fd: wasm32::__wasi_fd_t) -> wasm32::__wasi_errno_t {
+ let mut ctx = vmctx.get_embed_ctx_mut::<WasiCtx>();
+ let fd = dec_fd(fd);
+ if let Some(fdent) = ctx.fds.get(&fd) {
+ // can't close preopened files
+ if fdent.preopen_path.is_some() {
+ return wasm32::__WASI_ENOTSUP;
+ }
+ }
+ if let Some(mut fdent) = ctx.fds.remove(&fd) {
+ fdent.fd_object.needs_close = false;
+ match nix::unistd::close(fdent.fd_object.rawfd) {
+ Ok(_) => wasm32::__WASI_ESUCCESS,
+ Err(e) => wasm32::errno_from_nix(e.as_errno().unwrap()),
+ }
+ } else {
+ wasm32::__WASI_EBADF
+ }
+}
+
+pub fn wasi_fd_fdstat_get(
+ vmctx: &mut Vmctx,
+ fd: wasm32::__wasi_fd_t,
+ fdstat_ptr: wasm32::uintptr_t, // *mut wasm32::__wasi_fdstat_t
+) -> wasm32::__wasi_errno_t {
+ let host_fd = dec_fd(fd);
+ let mut host_fdstat = match dec_fdstat_byref(vmctx, fdstat_ptr) {
+ Ok(host_fdstat) => host_fdstat,
+ Err(e) => return enc_errno(e),
+ };
+
+ let ctx = vmctx.get_embed_ctx::<WasiCtx>();
+ let errno = if let Some(fe) = ctx.fds.get(&host_fd) {
+ host_fdstat.fs_filetype = fe.fd_object.ty;
+ host_fdstat.fs_rights_base = fe.rights_base;
+ host_fdstat.fs_rights_inheriting = fe.rights_inheriting;
+ use nix::fcntl::{fcntl, OFlag, F_GETFL};
+ match fcntl(fe.fd_object.rawfd, F_GETFL).map(OFlag::from_bits_truncate) {
+ Ok(flags) => {
+ host_fdstat.fs_flags = host::fdflags_from_nix(flags);
+ wasm32::__WASI_ESUCCESS
+ }
+ Err(e) => wasm32::errno_from_nix(e.as_errno().unwrap()),
+ }
+ } else {
+ wasm32::__WASI_EBADF
+ };
+ enc_fdstat_byref(vmctx, fdstat_ptr, host_fdstat)
+ .expect("can write back into the pointer we read from");
+ errno
+}
+
+pub fn wasi_fd_fdstat_set_flags(
+ vmctx: &mut Vmctx,
+ fd: wasm32::__wasi_fd_t,
+ fdflags: wasm32::__wasi_fdflags_t,
+) -> wasm32::__wasi_errno_t {
+ let host_fd = dec_fd(fd);
+ let host_fdflags = dec_fdflags(fdflags);
+ let nix_flags = host::nix_from_fdflags(host_fdflags);
+
+ let ctx = vmctx.get_embed_ctx::<WasiCtx>();
+ if let Some(fe) = ctx.fds.get(&host_fd) {
+ match nix::fcntl::fcntl(fe.fd_object.rawfd, nix::fcntl::F_SETFL(nix_flags)) {
+ Ok(_) => wasm32::__WASI_ESUCCESS,
+ Err(e) => wasm32::errno_from_nix(e.as_errno().unwrap()),
+ }
+ } else {
+ wasm32::__WASI_EBADF
+ }
+}
+
+pub fn wasi_fd_tell(
+ vmctx: &mut Vmctx,
+ fd: wasm32::__wasi_fd_t,
+ offset: wasm32::uintptr_t,
+) -> wasm32::__wasi_errno_t {
+ let ctx = vmctx.get_embed_ctx::<WasiCtx>();
+ let fd = dec_fd(fd);
+
+ let host_offset = {
+ use nix::unistd::{lseek, Whence};
+
+ let rights = host::__WASI_RIGHT_FD_TELL;
+ match ctx.get_fd_entry(fd, rights.into(), 0) {
+ Ok(fe) => match lseek(fe.fd_object.rawfd, 0, Whence::SeekCur) {
+ Ok(newoffset) => newoffset,
+ Err(e) => return wasm32::errno_from_nix(e.as_errno().unwrap()),
+ },
+ Err(e) => return enc_errno(e),
+ }
+ };
+ enc_filesize_byref(vmctx, offset, host_offset as u64)
+ .map(|_| wasm32::__WASI_ESUCCESS)
+ .unwrap_or_else(|e| e)
+}
+
+pub fn wasi_fd_seek(
+ vmctx: &mut Vmctx,
+ fd: wasm32::__wasi_fd_t,
+ offset: wasm32::__wasi_filedelta_t,
+ whence: wasm32::__wasi_whence_t,
+ newoffset: wasm32::uintptr_t,
+) -> wasm32::__wasi_errno_t {
+ let ctx = vmctx.get_embed_ctx::<WasiCtx>();
+ let fd = dec_fd(fd);
+ let offset = dec_filedelta(offset);
+ let whence = dec_whence(whence);
+
+ let host_newoffset = {
+ use nix::unistd::{lseek, Whence};
+ let nwhence = match u32::from(whence) {
+ host::__WASI_WHENCE_CUR => Whence::SeekCur,
+ host::__WASI_WHENCE_END => Whence::SeekEnd,
+ host::__WASI_WHENCE_SET => Whence::SeekSet,
+ _ => return wasm32::__WASI_EINVAL,
+ };
+
+ let rights = if offset == 0 && whence as u32 == host::__WASI_WHENCE_CUR {
+ host::__WASI_RIGHT_FD_TELL
+ } else {
+ host::__WASI_RIGHT_FD_SEEK | host::__WASI_RIGHT_FD_TELL
+ };
+ match ctx.get_fd_entry(fd, rights.into(), 0) {
+ Ok(fe) => match lseek(fe.fd_object.rawfd, offset, nwhence) {
+ Ok(newoffset) => newoffset,
+ Err(e) => return wasm32::errno_from_nix(e.as_errno().unwrap()),
+ },
+ Err(e) => return enc_errno(e),
+ }
+ };
+ enc_filesize_byref(vmctx, newoffset, host_newoffset as u64)
+ .map(|_| wasm32::__WASI_ESUCCESS)
+ .unwrap_or_else(|e| e)
+}
+
+pub fn wasi_fd_prestat_get(
+ vmctx: &mut Vmctx,
+ fd: wasm32::__wasi_fd_t,
+ prestat_ptr: wasm32::uintptr_t,
+) -> wasm32::__wasi_errno_t {
+ let ctx = vmctx.get_embed_ctx::<WasiCtx>();
+ let fd = dec_fd(fd);
+
+ let rights = host::__WASI_RIGHT_PATH_OPEN;
+ match ctx.get_fd_entry(fd, rights.into(), 0) {
+ Ok(fe) => {
+ if let Some(po_path) = &fe.preopen_path {
+ if fe.fd_object.ty != host::__WASI_FILETYPE_DIRECTORY as host::__wasi_filetype_t {
+ return wasm32::__WASI_ENOTDIR;
+ }
+ enc_prestat_byref(
+ vmctx,
+ prestat_ptr,
+ host::__wasi_prestat_t {
+ pr_type: host::__WASI_PREOPENTYPE_DIR as host::__wasi_preopentype_t,
+ u: host::__wasi_prestat_t___wasi_prestat_u {
+ dir: host::__wasi_prestat_t___wasi_prestat_u___wasi_prestat_u_dir_t {
+ pr_name_len: po_path.as_os_str().as_bytes().len(),
+ },
+ },
+ },
+ )
+ .map(|_| wasm32::__WASI_ESUCCESS)
+ .unwrap_or_else(|e| e)
+ } else {
+ wasm32::__WASI_ENOTSUP
+ }
+ }
+ Err(e) => enc_errno(e),
+ }
+}
+
+pub fn wasi_fd_prestat_dir_name(
+ vmctx: &mut Vmctx,
+ fd: wasm32::__wasi_fd_t,
+ path_ptr: wasm32::uintptr_t,
+ path_len: wasm32::size_t,
+) -> wasm32::__wasi_errno_t {
+ let ctx = vmctx.get_embed_ctx::<WasiCtx>();
+ let fd = dec_fd(fd);
+ let rights = host::__WASI_RIGHT_PATH_OPEN;
+ match ctx.get_fd_entry(fd, rights.into(), 0) {
+ Ok(fe) => {
+ if let Some(po_path) = &fe.preopen_path {
+ if fe.fd_object.ty != host::__WASI_FILETYPE_DIRECTORY as host::__wasi_filetype_t {
+ return wasm32::__WASI_ENOTDIR;
+ }
+ let path_bytes = po_path.as_os_str().as_bytes();
+ if path_bytes.len() > dec_usize(path_len) {
+ return wasm32::__WASI_ENAMETOOLONG;
+ }
+ enc_slice_of(vmctx, path_bytes, path_ptr)
+ .map(|_| wasm32::__WASI_ESUCCESS)
+ .unwrap_or_else(|e| e)
+ } else {
+ wasm32::__WASI_ENOTSUP
+ }
+ }
+ Err(e) => enc_errno(e),
+ }
+}
+
+pub fn wasi_fd_read(
+ vmctx: &mut Vmctx,
+ fd: wasm32::__wasi_fd_t,
+ iovs_ptr: wasm32::uintptr_t,
+ iovs_len: wasm32::size_t,
+ nread: wasm32::uintptr_t,
+) -> wasm32::__wasi_errno_t {
+ use nix::sys::uio::{readv, IoVec};
+
+ let fd = dec_fd(fd);
+ let mut iovs = match dec_iovec_slice(vmctx, iovs_ptr, iovs_len) {
+ Ok(iovs) => iovs,
+ Err(e) => return enc_errno(e),
+ };
+
+ let mut ctx = vmctx.get_embed_ctx_mut::<WasiCtx>();
+ let rights = host::__WASI_RIGHT_FD_READ;
+ let fe = match ctx.get_fd_entry(fd, rights.into(), 0) {
+ Ok(fe) => fe,
+ Err(e) => return enc_errno(e),
+ };
+
+ let mut iovs: Vec<IoVec<&mut [u8]>> = iovs
+ .iter_mut()
+ .map(|iov| unsafe { host::iovec_to_nix_mut(iov) })
+ .collect();
+
+ let host_nread = match readv(fe.fd_object.rawfd, &mut iovs) {
+ Ok(len) => len,
+ Err(e) => return wasm32::errno_from_nix(e.as_errno().unwrap()),
+ };
+
+ if host_nread == 0 {
+ // we hit eof, so remove the fdentry from the context
+ let mut fe = ctx.fds.remove(&fd).expect("file entry is still there");
+ fe.fd_object.needs_close = false;
+ }
+ enc_usize_byref(vmctx, nread, host_nread)
+ .map(|_| wasm32::__WASI_ESUCCESS)
+ .unwrap_or_else(|e| e)
+}
+
+pub fn wasi_fd_write(
+ vmctx: &mut Vmctx,
+ fd: wasm32::__wasi_fd_t,
+ iovs_ptr: wasm32::uintptr_t,
+ iovs_len: wasm32::size_t,
+ nwritten: wasm32::uintptr_t,
+) -> wasm32::__wasi_errno_t {
+ use nix::sys::uio::{writev, IoVec};
+
+ let fd = dec_fd(fd);
+ let iovs = match dec_ciovec_slice(vmctx, iovs_ptr, iovs_len) {
+ Ok(iovs) => iovs,
+ Err(e) => return enc_errno(e),
+ };
+
+ let ctx = vmctx.get_embed_ctx::<WasiCtx>();
+ let rights = host::__WASI_RIGHT_FD_WRITE;
+ let fe = match ctx.get_fd_entry(fd, rights.into(), 0) {
+ Ok(fe) => fe,
+ Err(e) => return enc_errno(e),
+ };
+
+ let iovs: Vec<IoVec<&[u8]>> = iovs
+ .iter()
+ .map(|iov| unsafe { host::ciovec_to_nix(iov) })
+ .collect();
+
+ let host_nwritten = match writev(fe.fd_object.rawfd, &iovs) {
+ Ok(len) => len,
+ Err(e) => return wasm32::errno_from_nix(e.as_errno().unwrap()),
+ };
+ enc_usize_byref(vmctx, nwritten, host_nwritten)
+ .map(|_| wasm32::__WASI_ESUCCESS)
+ .unwrap_or_else(|e| e)
+}
+
+pub fn wasi_path_open(
+ vmctx: &mut Vmctx,
+ dirfd: wasm32::__wasi_fd_t,
+ dirflags: wasm32::__wasi_lookupflags_t,
+ path_ptr: wasm32::uintptr_t,
+ path_len: wasm32::size_t,
+ oflags: wasm32::__wasi_oflags_t,
+ fs_rights_base: wasm32::__wasi_rights_t,
+ fs_rights_inheriting: wasm32::__wasi_rights_t,
+ fs_flags: wasm32::__wasi_fdflags_t,
+ fd_out_ptr: wasm32::uintptr_t,
+) -> wasm32::__wasi_errno_t {
+ use nix::errno::Errno;
+ use nix::fcntl::{openat, AtFlags, OFlag};
+ use nix::sys::stat::{fstatat, Mode, SFlag};
+
+ let dirfd = dec_fd(dirfd);
+ let dirflags = dec_lookupflags(dirflags);
+ let oflags = dec_oflags(oflags);
+ let fs_rights_base = dec_rights(fs_rights_base);
+ let fs_rights_inheriting = dec_rights(fs_rights_inheriting);
+ let fs_flags = dec_fdflags(fs_flags);
+
+ // which open mode do we need?
+ let read = fs_rights_base
+ & ((host::__WASI_RIGHT_FD_READ | host::__WASI_RIGHT_FD_READDIR) as host::__wasi_rights_t)
+ != 0;
+ let write = fs_rights_base
+ & ((host::__WASI_RIGHT_FD_DATASYNC
+ | host::__WASI_RIGHT_FD_WRITE
+ | host::__WASI_RIGHT_FD_ALLOCATE
+ | host::__WASI_RIGHT_FD_FILESTAT_SET_SIZE) as host::__wasi_rights_t)
+ != 0;
+
+ let mut nix_all_oflags = if read && write {
+ OFlag::O_RDWR
+ } else if read {
+ OFlag::O_RDONLY
+ } else {
+ OFlag::O_WRONLY
+ };
+
+ // on non-Capsicum systems, we always want nofollow
+ nix_all_oflags.insert(OFlag::O_NOFOLLOW);
+
+ // which rights are needed on the dirfd?
+ let mut needed_base = host::__WASI_RIGHT_PATH_OPEN as host::__wasi_rights_t;
+ let mut needed_inheriting = fs_rights_base | fs_rights_inheriting;
+
+ // convert open flags
+ let nix_oflags = host::nix_from_oflags(oflags);
+ nix_all_oflags.insert(nix_oflags);
+ if nix_all_oflags.contains(OFlag::O_CREAT) {
+ needed_base |= host::__WASI_RIGHT_PATH_CREATE_FILE as host::__wasi_rights_t;
+ }
+ if nix_all_oflags.contains(OFlag::O_TRUNC) {
+ needed_base |= host::__WASI_RIGHT_PATH_FILESTAT_SET_SIZE as host::__wasi_rights_t;
+ }
+
+ // convert file descriptor flags
+ nix_all_oflags.insert(host::nix_from_fdflags(fs_flags));
+ if nix_all_oflags.contains(OFlag::O_DSYNC) {
+ needed_inheriting |= host::__WASI_RIGHT_FD_DATASYNC as host::__wasi_rights_t;
+ }
+ if nix_all_oflags.intersects(O_RSYNC | OFlag::O_SYNC) {
+ needed_inheriting |= host::__WASI_RIGHT_FD_SYNC as host::__wasi_rights_t;
+ }
+ if nix_all_oflags.contains(OFlag::O_DIRECTORY) {
+ nix_all_oflags.remove(OFlag::O_RDWR);
+ nix_all_oflags.remove(OFlag::O_WRONLY);
+ nix_all_oflags.insert(OFlag::O_RDONLY);
+ }
+ let path = match dec_slice_of::<u8>(vmctx, path_ptr, path_len) {
+ Ok(path_bytes) => OsStr::from_bytes(path_bytes),
+ Err(e) => return enc_errno(e),
+ };
+
+ let (dir, path) = match path_get(
+ &vmctx,
+ dirfd,
+ dirflags,
+ path,
+ needed_base,
+ needed_inheriting,
+ nix_oflags.contains(OFlag::O_CREAT),
+ ) {
+ Ok((dir, path)) => (dir, path),
+ Err(e) => return enc_errno(e),
+ };
+
+ // 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.
+ let new_fd = match openat(
+ dir,
+ path.as_os_str(),
+ 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(dir, path.as_os_str(), AtFlags::AT_SYMLINK_NOFOLLOW) {
+ if SFlag::from_bits_truncate(stat.st_mode).contains(SFlag::S_IFSOCK) {
+ return wasm32::__WASI_ENOTSUP;
+ } else {
+ return wasm32::__WASI_ENXIO;
+ }
+ } else {
+ return wasm32::__WASI_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(dir, path.as_os_str(), AtFlags::AT_SYMLINK_NOFOLLOW) {
+ if SFlag::from_bits_truncate(stat.st_mode).contains(SFlag::S_IFLNK) {
+ return wasm32::__WASI_ELOOP;
+ }
+ }
+ return wasm32::__WASI_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 wasm32::__WASI_ELOOP;
+ }
+ Some(e) => return wasm32::errno_from_nix(e),
+ None => return wasm32::__WASI_ENOSYS,
+ }
+ }
+ };
+
+ // Determine the type of the new file descriptor and which rights contradict with this type
+ let guest_fd = match unsafe { determine_type_rights(new_fd) } {
+ Err(e) => {
+ // if `close` fails, note it but do not override the underlying errno
+ nix::unistd::close(new_fd).unwrap_or_else(|e| {
+ dbg!(e);
+ });
+ if let Err(e) = enc_fd_byref(vmctx, fd_out_ptr, wasm32::__wasi_fd_t::max_value()) {
+ return enc_errno(e);
+ }
+ return enc_errno(e);
+ }
+ Ok((_ty, max_base, max_inheriting)) => {
+ let mut fe = unsafe { FdEntry::from_raw_fd(new_fd) };
+ fe.rights_base &= max_base;
+ fe.rights_inheriting &= max_inheriting;
+ match vmctx.get_embed_ctx_mut::<WasiCtx>().insert_fd_entry(fe) {
+ Ok(fd) => fd,
+ Err(e) => return enc_errno(e),
+ }
+ }
+ };
+ enc_fd_byref(vmctx, fd_out_ptr, guest_fd)
+ .map(|_| wasm32::__WASI_ESUCCESS)
+ .unwrap_or_else(|e| e)
+}
+
+pub fn wasi_fd_filestat_get(
+ vmctx: &mut Vmctx,
+ fd: wasm32::__wasi_fd_t,
+ filestat_ptr: wasm32::uintptr_t,
+) -> wasm32::__wasi_errno_t {
+ use nix::sys::stat::fstat;
+
+ let host_fd = dec_fd(fd);
+ let ctx = vmctx.get_embed_ctx::<WasiCtx>();
+
+ let rights = host::__WASI_RIGHT_FD_FILESTAT_GET;
+ match ctx.get_fd_entry(host_fd, rights.into(), 0) {
+ Ok(fe) => match fstat(fe.fd_object.rawfd) {
+ Err(e) => return wasm32::errno_from_nix(e.as_errno().unwrap()),
+ Ok(filestat) => {
+ let host_filestat = host::filestat_from_nix(filestat);
+ enc_filestat_byref(vmctx, filestat_ptr, host_filestat)
+ .expect("can write into the pointer");
+ }
+ },
+ Err(e) => return enc_errno(e),
+ }
+ wasm32::__WASI_ESUCCESS
+}
+
+pub fn wasi_path_filestat_get(
+ vmctx: &mut Vmctx,
+ dirfd: wasm32::__wasi_fd_t,
+ dirflags: wasm32::__wasi_lookupflags_t,
+ path_ptr: wasm32::uintptr_t,
+ path_len: wasm32::size_t,
+ filestat_ptr: wasm32::uintptr_t,
+) -> wasm32::__wasi_errno_t {
+ use nix::fcntl::AtFlags;
+ use nix::sys::stat::fstatat;
+
+ let dirfd = dec_fd(dirfd);
+ let dirflags = dec_lookupflags(dirflags);
+ let path = match dec_slice_of::<u8>(vmctx, path_ptr, path_len) {
+ Ok(path_bytes) => OsStr::from_bytes(path_bytes),
+ Err(e) => return enc_errno(e),
+ };
+ let rights = host::__WASI_RIGHT_PATH_FILESTAT_GET;
+ let (dir, path) = match path_get(&vmctx, dirfd, dirflags, path, rights.into(), 0, false) {
+ Ok((dir, path)) => (dir, path),
+ Err(e) => return enc_errno(e),
+ };
+ let atflags = match dirflags {
+ wasm32::__WASI_LOOKUP_SYMLINK_FOLLOW => AtFlags::empty(),
+ _ => AtFlags::AT_SYMLINK_NOFOLLOW,
+ };
+ match fstatat(dir, path.as_os_str(), atflags) {
+ Err(e) => wasm32::errno_from_nix(e.as_errno().unwrap()),
+ Ok(filestat) => {
+ let host_filestat = host::filestat_from_nix(filestat);
+ enc_filestat_byref(vmctx, filestat_ptr, host_filestat)
+ .expect("can write into the pointer");
+ wasm32::__WASI_ESUCCESS
+ }
+ }
+}
+
+pub fn wasi_path_create_directory(
+ vmctx: &mut Vmctx,
+ dirfd: wasm32::__wasi_fd_t,
+ path_ptr: wasm32::uintptr_t,
+ path_len: wasm32::size_t,
+) -> wasm32::__wasi_errno_t {
+ use nix::errno;
+ use nix::libc::mkdirat;
+
+ let dirfd = dec_fd(dirfd);
+ let path = match dec_slice_of::<u8>(vmctx, path_ptr, path_len) {
+ Ok(path_bytes) => OsStr::from_bytes(path_bytes),
+ Err(e) => return enc_errno(e),
+ };
+ let rights = host::__WASI_RIGHT_PATH_CREATE_DIRECTORY;
+ let (dir, path) = match path_get(&vmctx, dirfd, 0, path, rights.into(), 0, false) {
+ Ok((dir, path)) => (dir, path),
+ Err(e) => return enc_errno(e),
+ };
+ let path_cstr = match std::ffi::CString::new(path.as_os_str().as_bytes()) {
+ Ok(path_cstr) => path_cstr,
+ Err(_) => return wasm32::__WASI_EINVAL,
+ };
+ // nix doesn't expose mkdirat() yet
+ match unsafe { mkdirat(dir, path_cstr.as_ptr(), 0o777) } {
+ 0 => wasm32::__WASI_ESUCCESS,
+ _ => wasm32::errno_from_nix(errno::Errno::last()),
+ }
+}
+
+pub fn wasi_path_unlink_file(
+ vmctx: &mut Vmctx,
+ dirfd: wasm32::__wasi_fd_t,
+ path_ptr: wasm32::uintptr_t,
+ path_len: wasm32::size_t,
+) -> wasm32::__wasi_errno_t {
+ use nix::errno;
+ use nix::libc::unlinkat;
+
+ let dirfd = dec_fd(dirfd);
+ let path = match dec_slice_of::<u8>(vmctx, path_ptr, path_len) {
+ Ok(path_bytes) => OsStr::from_bytes(path_bytes),
+ Err(e) => return enc_errno(e),
+ };
+ let rights = host::__WASI_RIGHT_PATH_UNLINK_FILE;
+ let (dir, path) = match path_get(&vmctx, dirfd, 0, path, rights.into(), 0, false) {
+ Ok((dir, path)) => (dir, path),
+ Err(e) => return enc_errno(e),
+ };
+ let path_cstr = match std::ffi::CString::new(path.as_os_str().as_bytes()) {
+ Ok(path_cstr) => path_cstr,
+ Err(_) => return wasm32::__WASI_EINVAL,
+ };
+ // nix doesn't expose unlinkat() yet
+ match unsafe { unlinkat(dir, path_cstr.as_ptr(), 0) } {
+ 0 => wasm32::__WASI_ESUCCESS,
+ _ => {
+ let mut e = errno::Errno::last();
+ // Non-Linux implementations may return EPERM when attempting to remove a
+ // directory without `REMOVEDIR`. For WASI, adjust this to `EISDIR`.
+ #[cfg(not(linux))]
+ {
+ use nix::fcntl::AtFlags;
+ use nix::sys::stat::{fstatat, SFlag};
+ if e == errno::Errno::EPERM {
+ if let Ok(stat) = fstatat(dir, path.as_os_str(), 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();
+ }
+ }
+ }
+ wasm32::errno_from_nix(e)
+ }
+ }
+}
+
+pub fn wasi_fd_allocate(
+ vmctx: &mut Vmctx,
+ fd: wasm32::__wasi_fd_t,
+ offset: wasm32::__wasi_filesize_t,
+ len: wasm32::__wasi_filesize_t,
+) -> wasm32::__wasi_errno_t {
+ let host_fd = dec_fd(fd);
+ let ctx = vmctx.get_embed_ctx::<WasiCtx>();
+ let rights = host::__WASI_RIGHT_FD_ALLOCATE;
+ let fe = match ctx.get_fd_entry(host_fd, rights.into(), 0) {
+ Ok(fe) => fe,
+ Err(e) => return enc_errno(e),
+ };
+ let offset = dec_filesize(offset);
+ let len = dec_filesize(len);
+
+ #[cfg(target_os = "linux")]
+ {
+ let res =
+ unsafe { libc::posix_fallocate(fe.fd_object.rawfd, offset as off_t, len as off_t) };
+ if res != 0 {
+ return wasm32::errno_from_nix(nix::errno::Errno::last());
+ }
+ }
+
+ #[cfg(not(target_os = "linux"))]
+ {
+ use nix::sys::stat::fstat;
+ use nix::unistd::ftruncate;
+
+ match fstat(fe.fd_object.rawfd) {
+ Err(e) => return wasm32::errno_from_nix(e.as_errno().unwrap()),
+ Ok(st) => {
+ let current_size = st.st_size as u64;
+ let wanted_size = match offset.checked_add(len) {
+ Some(wanted_size) => wanted_size,
+ None => return wasm32::__WASI_E2BIG,
+ };
+ if wanted_size > i64::max_value() as u64 {
+ return wasm32::__WASI_E2BIG;
+ }
+ if wanted_size > current_size {
+ if let Err(e) = ftruncate(fe.fd_object.rawfd, wanted_size as off_t) {
+ return wasm32::errno_from_nix(e.as_errno().unwrap());
+ }
+ }
+ }
+ }
+ }
+
+ wasm32::__WASI_ESUCCESS
+}
+
+pub fn wasi_fd_advise(
+ vmctx: &mut Vmctx,
+ fd: wasm32::__wasi_fd_t,
+ offset: wasm32::__wasi_filesize_t,
+ len: wasm32::__wasi_filesize_t,
+ advice: wasm32::__wasi_advice_t,
+) -> wasm32::__wasi_errno_t {
+ let host_fd = dec_fd(fd);
+ let ctx = vmctx.get_embed_ctx::<WasiCtx>();
+ let rights = host::__WASI_RIGHT_FD_ADVISE;
+ let fe = match ctx.get_fd_entry(host_fd, rights.into(), 0) {
+ Ok(fe) => fe,
+ Err(e) => return enc_errno(e),
+ };
+ let advice = dec_advice(advice);
+
+ #[cfg(target_os = "linux")]
+ {
+ let host_advice = match advice as u32 {
+ host::__WASI_ADVICE_DONTNEED => libc::POSIX_FADV_DONTNEED,
+ host::__WASI_ADVICE_SEQUENTIAL => libc::POSIX_FADV_SEQUENTIAL,
+ host::__WASI_ADVICE_WILLNEED => libc::POSIX_FADV_DONTNEED,
+ host::__WASI_ADVICE_NOREUSE => libc::POSIX_FADV_NOREUSE,
+ host::__WASI_ADVICE_RANDOM => libc::POSIX_FADV_RANDOM,
+ host::__WASI_ADVICE_NORMAL => libc::POSIX_FADV_NORMAL,
+ _ => return wasm32::__WASI_EINVAL,
+ };
+ let offset = dec_filesize(offset);
+ let len = dec_filesize(len);
+ let res = unsafe {
+ libc::posix_fadvise(
+ fe.fd_object.rawfd,
+ offset as off_t,
+ len as off_t,
+ host_advice,
+ )
+ };
+ if res != 0 {
+ return wasm32::errno_from_nix(nix::errno::Errno::last());
+ }
+ }
+
+ #[cfg(not(target_os = "linux"))]
+ {
+ let _ = (fe, offset, len);
+ match advice as u32 {
+ host::__WASI_ADVICE_DONTNEED
+ | host::__WASI_ADVICE_SEQUENTIAL
+ | host::__WASI_ADVICE_WILLNEED
+ | host::__WASI_ADVICE_NOREUSE
+ | host::__WASI_ADVICE_RANDOM
+ | host::__WASI_ADVICE_NORMAL => {}
+ _ => return wasm32::__WASI_EINVAL,
+ }
+ }
+
+ wasm32::__WASI_ESUCCESS
+}
+
+pub fn wasi_fd_datasync(vmctx: &mut Vmctx, fd: wasm32::__wasi_fd_t) -> wasm32::__wasi_errno_t {
+ let host_fd = dec_fd(fd);
+ let ctx = vmctx.get_embed_ctx::<WasiCtx>();
+ let rights = host::__WASI_RIGHT_FD_DATASYNC;
+ let fe = match ctx.get_fd_entry(host_fd, rights.into(), 0) {
+ Ok(fe) => fe,
+ Err(e) => return enc_errno(e),
+ };
+ let res;
+
+ #[cfg(target_os = "linux")]
+ {
+ res = nix::unistd::fdatasync(fe.fd_object.rawfd);
+ }
+
+ #[cfg(not(target_os = "linux"))]
+ {
+ res = nix::unistd::fsync(fe.fd_object.rawfd);
+ }
+
+ if let Err(e) = res {
+ return wasm32::errno_from_nix(e.as_errno().unwrap());
+ }
+ wasm32::__WASI_ESUCCESS
+}
+
+pub fn wasi_fd_sync(vmctx: &mut Vmctx, fd: wasm32::__wasi_fd_t) -> wasm32::__wasi_errno_t {
+ let host_fd = dec_fd(fd);
+ let ctx = vmctx.get_embed_ctx::<WasiCtx>();
+ let rights = host::__WASI_RIGHT_FD_SYNC;
+ let fe = match ctx.get_fd_entry(host_fd, rights.into(), 0) {
+ Ok(fe) => fe,
+ Err(e) => return enc_errno(e),
+ };
+ let res = nix::unistd::fsync(fe.fd_object.rawfd);
+ if let Err(e) = res {
+ return wasm32::errno_from_nix(e.as_errno().unwrap());
+ }
+ wasm32::__WASI_ESUCCESS
+}
+
+pub fn wasi_fd_fdstat_set_rights(
+ vmctx: &mut Vmctx,
+ fd: wasm32::__wasi_fd_t,
+ fs_rights_base: wasm32::__wasi_rights_t,
+ fs_rights_inheriting: wasm32::__wasi_rights_t,
+) -> wasm32::__wasi_errno_t {
+ let host_fd = dec_fd(fd);
+ let mut ctx = vmctx.get_embed_ctx_mut::<WasiCtx>();
+ let fe = match ctx.fds.get_mut(&host_fd) {
+ Some(fe) => fe,
+ None => return wasm32::__WASI_EBADF,
+ };
+ if fe.rights_base & fs_rights_base != fs_rights_base
+ || fe.rights_inheriting & fs_rights_inheriting != fs_rights_inheriting
+ {
+ return wasm32::__WASI_ENOTCAPABLE;
+ }
+ fe.rights_base = fs_rights_base;
+ fe.rights_inheriting = fs_rights_inheriting;
+ wasm32::__WASI_ESUCCESS
+}
+
+pub fn wasi_fd_filestat_set_size(
+ vmctx: &mut Vmctx,
+ fd: wasm32::__wasi_fd_t,
+ st_size: wasm32::__wasi_filesize_t,
+) -> wasm32::__wasi_errno_t {
+ use nix::unistd::ftruncate;
+
+ let host_fd = dec_fd(fd);
+ let ctx = vmctx.get_embed_ctx::<WasiCtx>();
+ let rights = host::__WASI_RIGHT_FD_FILESTAT_SET_SIZE;
+ let fe = match ctx.get_fd_entry(host_fd, rights.into(), 0) {
+ Ok(fe) => fe,
+ Err(e) => return enc_errno(e),
+ };
+ let st_size = dec_filesize(st_size);
+ if st_size > i64::max_value() as u64 {
+ return wasm32::__WASI_E2BIG;
+ }
+ if let Err(e) = ftruncate(fe.fd_object.rawfd, st_size as off_t) {
+ return wasm32::errno_from_nix(e.as_errno().unwrap());
+ }
+ wasm32::__WASI_ESUCCESS
+}
+
+pub fn wasi_fd_filestat_set_times(
+ vmctx: &mut Vmctx,
+ fd: wasm32::__wasi_fd_t,
+ st_atim: wasm32::__wasi_timestamp_t,
+ st_mtim: wasm32::__wasi_timestamp_t,
+ fst_flags: wasm32::__wasi_fstflags_t,
+) -> wasm32::__wasi_errno_t {
+ use nix::sys::time::{TimeSpec, TimeValLike};
+
+ let host_fd = dec_fd(fd);
+ let ctx = vmctx.get_embed_ctx::<WasiCtx>();
+ let rights = host::__WASI_RIGHT_FD_FILESTAT_SET_TIMES;
+ let fe = match ctx.get_fd_entry(host_fd, rights.into(), 0) {
+ Ok(fe) => fe,
+ Err(e) => return enc_errno(e),
+ };
+ let st_atim = dec_timestamp(st_atim);
+ let mut st_mtim = dec_timestamp(st_mtim);
+ let fst_flags = dec_fstflags(fst_flags);
+ if fst_flags & (host::__WASI_FILESTAT_SET_MTIM_NOW as host::__wasi_fstflags_t) != 0 {
+ let clock_id = libc::CLOCK_REALTIME;
+ let mut timespec = MaybeUninit::<libc::timespec>::uninit();
+ let res = unsafe { timers::clock_gettime_helper(clock_id, timespec.as_mut_ptr()) };
+ if res != 0 {
+ return wasm32::errno_from_nix(nix::errno::Errno::last());
+ }
+ let timespec = unsafe { timespec.assume_init() };
+ let time_ns = match (timespec.tv_sec as host::__wasi_timestamp_t)
+ .checked_mul(1_000_000_000)
+ .and_then(|sec_ns| sec_ns.checked_add(timespec.tv_nsec as host::__wasi_timestamp_t))
+ {
+ Some(time_ns) => time_ns,
+ None => return wasm32::__WASI_EOVERFLOW,
+ };
+ st_mtim = time_ns;
+ }
+ let ts_atime = match fst_flags as u32 {
+ f if f & host::__WASI_FILESTAT_SET_ATIM_NOW != 0 => libc::timespec {
+ tv_sec: 0,
+ tv_nsec: utime_now(),
+ },
+ f if f & host::__WASI_FILESTAT_SET_ATIM != 0 => {
+ *TimeSpec::nanoseconds(st_atim as i64).as_ref()
+ }
+ _ => libc::timespec {
+ tv_sec: 0,
+ tv_nsec: utime_omit(),
+ },
+ };
+ let ts_mtime = *TimeSpec::nanoseconds(st_mtim as i64).as_ref();
+ let times = [ts_atime, ts_mtime];
+ let res = unsafe { timers::futimens_helper(fe.fd_object.rawfd, times.as_ptr()) };
+ if res != 0 {
+ return wasm32::errno_from_nix(nix::errno::Errno::last());
+ }
+ wasm32::__WASI_ESUCCESS
+}
+
+pub fn wasi_path_filestat_set_times(
+ vmctx: &mut Vmctx,
+ dirfd: wasm32::__wasi_fd_t,
+ dirflags: wasm32::__wasi_lookupflags_t,
+ path_ptr: wasm32::uintptr_t,
+ path_len: wasm32::size_t,
+ st_atim: wasm32::__wasi_timestamp_t,
+ st_mtim: wasm32::__wasi_timestamp_t,
+ fst_flags: wasm32::__wasi_fstflags_t,
+) -> wasm32::__wasi_errno_t {
+ use nix::sys::time::{TimeSpec, TimeValLike};
+
+ let dirfd = dec_fd(dirfd);
+ let dirflags = dec_lookupflags(dirflags);
+ let path = match dec_slice_of::<u8>(vmctx, path_ptr, path_len) {
+ Ok(path_bytes) => OsStr::from_bytes(path_bytes),
+ Err(e) => return enc_errno(e),
+ };
+ let rights = host::__WASI_RIGHT_PATH_FILESTAT_SET_TIMES;
+ let (dir, path) = match path_get(&vmctx, dirfd, dirflags, path, rights.into(), 0, false) {
+ Ok((dir, path)) => (dir, path),
+ Err(e) => return enc_errno(e),
+ };
+ let atflags = match dirflags {
+ wasm32::__WASI_LOOKUP_SYMLINK_FOLLOW => 0,
+ _ => libc::AT_SYMLINK_NOFOLLOW,
+ };
+ let st_atim = dec_timestamp(st_atim);
+ let mut st_mtim = dec_timestamp(st_mtim);
+ let fst_flags = dec_fstflags(fst_flags);
+ if fst_flags & (host::__WASI_FILESTAT_SET_MTIM_NOW as host::__wasi_fstflags_t) != 0 {
+ let clock_id = libc::CLOCK_REALTIME;
+ let mut timespec = MaybeUninit::<libc::timespec>::uninit();
+ let res = unsafe { timers::clock_gettime_helper(clock_id, timespec.as_mut_ptr()) };
+ if res != 0 {
+ return wasm32::errno_from_nix(nix::errno::Errno::last());
+ }
+ let timespec = unsafe { timespec.assume_init() };
+ let time_ns = match (timespec.tv_sec as host::__wasi_timestamp_t)
+ .checked_mul(1_000_000_000)
+ .and_then(|sec_ns| sec_ns.checked_add(timespec.tv_nsec as host::__wasi_timestamp_t))
+ {
+ Some(time_ns) => time_ns,
+ None => return wasm32::__WASI_EOVERFLOW,
+ };
+ st_mtim = time_ns;
+ }
+ let ts_atime = match fst_flags as u32 {
+ f if f & host::__WASI_FILESTAT_SET_ATIM_NOW != 0 => libc::timespec {
+ tv_sec: 0,
+ tv_nsec: utime_now(),
+ },
+ f if f & host::__WASI_FILESTAT_SET_ATIM != 0 => {
+ *TimeSpec::nanoseconds(st_atim as i64).as_ref()
+ }
+ _ => libc::timespec {
+ tv_sec: 0,
+ tv_nsec: utime_omit(),
+ },
+ };
+ let ts_mtime = *TimeSpec::nanoseconds(st_mtim as i64).as_ref();
+ let times = [ts_atime, ts_mtime];
+ let path_cstr = match std::ffi::CString::new(path.as_os_str().as_bytes()) {
+ Ok(path_cstr) => path_cstr,
+ Err(_) => return wasm32::__WASI_EINVAL,
+ };
+ let res = unsafe { timers::utimensat_helper(dir, path_cstr.as_ptr(), times.as_ptr(), atflags) };
+ if res != 0 {
+ return wasm32::errno_from_nix(nix::errno::Errno::last());
+ }
+ wasm32::__WASI_ESUCCESS
+}
+
+pub fn wasi_fd_pread(
+ vmctx: &mut Vmctx,
+ fd: wasm32::__wasi_fd_t,
+ iovs_ptr: wasm32::uintptr_t,
+ iovs_len: wasm32::size_t,
+ offset: wasm32::__wasi_filesize_t,
+ nread: wasm32::uintptr_t,
+) -> wasm32::__wasi_errno_t {
+ use nix::sys::uio::pread;
+ use std::cmp;
+
+ let fd = dec_fd(fd);
+ let iovs = match dec_iovec_slice(vmctx, iovs_ptr, iovs_len) {
+ Ok(iovs) => iovs,
+ Err(e) => return enc_errno(e),
+ };
+ let ctx = vmctx.get_embed_ctx::<WasiCtx>();
+ let rights = host::__WASI_RIGHT_FD_READ;
+ let fe = match ctx.get_fd_entry(fd, rights.into(), 0) {
+ Ok(fe) => fe,
+ Err(e) => return enc_errno(e),
+ };
+ let offset = dec_filesize(offset);
+ if offset > i64::max_value() as u64 {
+ return wasm32::__WASI_EIO;
+ }
+ let buf_size = iovs.iter().map(|v| v.buf_len).sum();
+ let mut buf = vec![0; buf_size];
+ let host_nread = match pread(fe.fd_object.rawfd, &mut buf, offset as off_t) {
+ Ok(len) => len,
+ Err(e) => return wasm32::errno_from_nix(e.as_errno().unwrap()),
+ };
+ let mut buf_offset = 0;
+ let mut left = host_nread;
+ for iov in &iovs {
+ if left == 0 {
+ break;
+ }
+ let vec_len = cmp::min(iov.buf_len, left);
+ unsafe { std::slice::from_raw_parts_mut(iov.buf as *mut u8, vec_len) }
+ .copy_from_slice(&buf[buf_offset..buf_offset + vec_len]);
+ buf_offset += vec_len;
+ left -= vec_len;
+ }
+ enc_usize_byref(vmctx, nread, host_nread)
+ .map(|_| wasm32::__WASI_ESUCCESS)
+ .unwrap_or_else(|e| e)
+}
+
+pub fn wasi_fd_pwrite(
+ vmctx: &mut Vmctx,
+ fd: wasm32::__wasi_fd_t,
+ iovs_ptr: wasm32::uintptr_t,
+ iovs_len: wasm32::size_t,
+ offset: wasm32::__wasi_filesize_t,
+ nwritten: wasm32::uintptr_t,
+) -> wasm32::__wasi_errno_t {
+ use nix::sys::uio::pwrite;
+
+ let fd = dec_fd(fd);
+ let iovs = match dec_iovec_slice(vmctx, iovs_ptr, iovs_len) {
+ Ok(iovs) => iovs,
+ Err(e) => return enc_errno(e),
+ };
+ let ctx = vmctx.get_embed_ctx::<WasiCtx>();
+ let rights = host::__WASI_RIGHT_FD_READ;
+ let fe = match ctx.get_fd_entry(fd, rights.into(), 0) {
+ Ok(fe) => fe,
+ Err(e) => return enc_errno(e),
+ };
+ let offset = dec_filesize(offset);
+ if offset > i64::max_value() as u64 {
+ return wasm32::__WASI_EIO;
+ }
+ let buf_size = iovs.iter().map(|v| v.buf_len).sum();
+ let mut buf = Vec::with_capacity(buf_size);
+ for iov in &iovs {
+ buf.extend_from_slice(unsafe {
+ std::slice::from_raw_parts(iov.buf as *const u8, iov.buf_len)
+ });
+ }
+ let host_nwritten = match pwrite(fe.fd_object.rawfd, &buf, offset as off_t) {
+ Ok(len) => len,
+ Err(e) => return wasm32::errno_from_nix(e.as_errno().unwrap()),
+ };
+ enc_usize_byref(vmctx, nwritten, host_nwritten)
+ .map(|_| wasm32::__WASI_ESUCCESS)
+ .unwrap_or_else(|e| e)
+}
+
+pub fn wasi_fd_readdir(
+ vmctx: &mut Vmctx,
+ fd: wasm32::__wasi_fd_t,
+ buf: wasm32::uintptr_t,
+ buf_len: wasm32::size_t,
+ cookie: wasm32::__wasi_dircookie_t,
+ bufused: wasm32::uintptr_t,
+) -> wasm32::__wasi_errno_t {
+ use libc::{dirent, fdopendir, readdir_r, seekdir};
+
+ match enc_usize_byref(vmctx, bufused, 0) {
+ Ok(_) => {}
+ Err(e) => return enc_errno(e),
+ };
+ let fd = dec_fd(fd);
+ let ctx = vmctx.get_embed_ctx::<WasiCtx>();
+ let rights = host::__WASI_RIGHT_FD_READDIR;
+ let fe = match ctx.get_fd_entry(fd, rights.into(), 0) {
+ Ok(fe) => fe,
+ Err(e) => return enc_errno(e),
+ };
+ let host_buf = match dec_slice_of::<u8>(vmctx, buf, buf_len) {
+ Ok(host_buf) => host_buf,
+ Err(e) => return enc_errno(e),
+ };
+ let host_buf_ptr = host_buf.as_ptr();
+ let host_buf_len = host_buf.len();
+ let dir = unsafe { fdopendir(fe.fd_object.rawfd) };
+ if dir.is_null() {
+ return wasm32::errno_from_nix(nix::errno::Errno::last());
+ }
+ let cookie = dec_dircookie(cookie);
+ if cookie != wasm32::__WASI_DIRCOOKIE_START {
+ unsafe { seekdir(dir, cookie as c_long) };
+ }
+ let mut entry_buf = MaybeUninit::<dirent>::uninit();
+ let mut left = host_buf_len;
+ let mut host_buf_offset: usize = 0;
+ while left > 0 {
+ let mut host_entry: *mut dirent = std::ptr::null_mut();
+ let res = unsafe { readdir_r(dir, entry_buf.as_mut_ptr(), &mut host_entry) };
+ if res == -1 {
+ return wasm32::errno_from_nix(nix::errno::Errno::last());
+ }
+ if host_entry.is_null() {
+ break;
+ }
+ unsafe { entry_buf.assume_init() };
+ let entry: wasm32::__wasi_dirent_t = match dirent_from_host(&unsafe { *host_entry }) {
+ Ok(entry) => entry,
+ Err(e) => return enc_errno(e),
+ };
+ let name_len = entry.d_namlen as usize;
+ let required_space = std::mem::size_of_val(&entry) + name_len;
+ if required_space > left {
+ break;
+ }
+ unsafe {
+ let ptr = host_buf_ptr.offset(host_buf_offset as isize) as *mut c_void
+ as *mut wasm32::__wasi_dirent_t;
+ *ptr = entry;
+ }
+ host_buf_offset += std::mem::size_of_val(&entry);
+ let name_ptr = unsafe { *host_entry }.d_name.as_ptr();
+ unsafe {
+ std::ptr::copy_nonoverlapping(
+ name_ptr as *const _,
+ host_buf_ptr.offset(host_buf_offset as isize) as *mut _,
+ name_len,
+ )
+ };
+ host_buf_offset += name_len;
+ left -= required_space;
+ }
+ let host_bufused = host_buf_len - left;
+ enc_usize_byref(vmctx, bufused, host_bufused)
+ .map(|_| wasm32::__WASI_ESUCCESS)
+ .unwrap_or_else(|e| e)
+}
+
+pub fn wasi_fd_renumber(
+ vmctx: &mut Vmctx,
+ from: wasm32::__wasi_fd_t,
+ to: wasm32::__wasi_fd_t,
+) -> wasm32::__wasi_errno_t {
+ let from = dec_fd(from);
+ let to = dec_fd(to);
+ let mut ctx = vmctx.get_embed_ctx_mut::<WasiCtx>();
+ let fe_from = match ctx.fds.get(&from) {
+ Some(fe_from) => fe_from,
+ None => return wasm32::__WASI_EBADF,
+ };
+ let fe_to = match ctx.fds.get(&to) {
+ Some(fe_to) => fe_to,
+ None => return wasm32::__WASI_EBADF,
+ };
+ if let Err(e) = nix::unistd::dup2(fe_from.fd_object.rawfd, fe_to.fd_object.rawfd) {
+ return wasm32::errno_from_nix(e.as_errno().unwrap());
+ }
+ let fe_from_rawfd = fe_from.fd_object.rawfd;
+ ctx.fds.remove(&(fe_from_rawfd as host::__wasi_fd_t));
+
+ wasm32::__WASI_ESUCCESS
+}
+
+pub fn wasi_path_link(
+ vmctx: &mut Vmctx,
+ old_dirfd: wasm32::__wasi_fd_t,
+ _old_flags: wasm32::__wasi_lookupflags_t,
+ old_path_ptr: wasm32::uintptr_t,
+ old_path_len: wasm32::size_t,
+ new_dirfd: wasm32::__wasi_fd_t,
+ new_path_ptr: wasm32::uintptr_t,
+ new_path_len: wasm32::size_t,
+) -> wasm32::__wasi_errno_t {
+ use nix::libc::linkat;
+
+ let old_dirfd = dec_fd(old_dirfd);
+ let new_dirfd = dec_fd(new_dirfd);
+ let old_path = match dec_slice_of::<u8>(vmctx, old_path_ptr, old_path_len) {
+ Ok(old_path_bytes) => OsStr::from_bytes(old_path_bytes),
+ Err(e) => return enc_errno(e),
+ };
+ let new_path = match dec_slice_of::<u8>(vmctx, new_path_ptr, new_path_len) {
+ Ok(new_path_bytes) => OsStr::from_bytes(new_path_bytes),
+ Err(e) => return enc_errno(e),
+ };
+ let rights = host::__WASI_RIGHT_PATH_LINK_SOURCE;
+ let (old_dir, old_path) =
+ match path_get(&vmctx, old_dirfd, 0, old_path, rights.into(), 0, false) {
+ Ok((dir, path)) => (dir, path),
+ Err(e) => return enc_errno(e),
+ };
+ let rights = host::__WASI_RIGHT_PATH_LINK_TARGET;
+ let (new_dir, new_path) =
+ match path_get(&vmctx, new_dirfd, 0, new_path, rights.into(), 0, false) {
+ Ok((dir, path)) => (dir, path),
+ Err(e) => return enc_errno(e),
+ };
+ let old_path_cstr = match std::ffi::CString::new(old_path.as_bytes()) {
+ Ok(old_path_cstr) => old_path_cstr,
+ Err(_) => return wasm32::__WASI_EINVAL,
+ };
+ let new_path_cstr = match std::ffi::CString::new(new_path.as_bytes()) {
+ Ok(new_path_cstr) => new_path_cstr,
+ Err(_) => return wasm32::__WASI_EINVAL,
+ };
+
+ // Not setting AT_SYMLINK_FOLLOW fails on most filesystems
+ let atflags = libc::AT_SYMLINK_FOLLOW;
+ let res = unsafe {
+ linkat(
+ old_dir,
+ old_path_cstr.as_ptr(),
+ new_dir,
+ new_path_cstr.as_ptr(),
+ atflags,
+ )
+ };
+ if res != 0 {
+ return wasm32::errno_from_nix(nix::errno::Errno::last());
+ }
+ wasm32::__WASI_ESUCCESS
+}
+
+pub fn wasi_path_readlink(
+ vmctx: &mut Vmctx,
+ dirfd: wasm32::__wasi_fd_t,
+ path_ptr: wasm32::uintptr_t,
+ path_len: wasm32::size_t,
+ buf_ptr: wasm32::uintptr_t,
+ buf_len: wasm32::size_t,
+ bufused: wasm32::uintptr_t,
+) -> wasm32::__wasi_errno_t {
+ use nix::fcntl::readlinkat;
+ use std::cmp;
+
+ match enc_usize_byref(vmctx, bufused, 0) {
+ Ok(_) => {}
+ Err(e) => return enc_errno(e),
+ };
+ let dirfd = dec_fd(dirfd);
+ let path = match dec_slice_of::<u8>(vmctx, path_ptr, path_len) {
+ Ok(path_bytes) => OsStr::from_bytes(path_bytes),
+ Err(e) => return enc_errno(e),
+ };
+ let rights = host::__WASI_RIGHT_PATH_READLINK;
+ let (dir, path) = match path_get(&vmctx, dirfd, 0, path, rights.into(), 0, false) {
+ Ok((dir, path)) => (dir, path),
+ Err(e) => return enc_errno(e),
+ };
+ let dummy_buf = &mut [0u8];
+ let mut buf = if buf_len > 0 {
+ match dec_slice_of_mut::<u8>(vmctx, buf_ptr, buf_len) {
+ Ok(buf) => buf,
+ Err(e) => return enc_errno(e),
+ }
+ } else {
+ dummy_buf
+ };
+ let target_path = match readlinkat(dir, path.as_os_str(), &mut buf) {
+ Err(e) => return wasm32::errno_from_nix(e.as_errno().unwrap()),
+ Ok(target_path) => target_path,
+ };
+ let host_bufused = cmp::min(buf_len as usize, target_path.len());
+ match enc_usize_byref(vmctx, bufused, host_bufused) {
+ Ok(_) => {}
+ Err(e) => return enc_errno(e),
+ };
+ wasm32::__WASI_ESUCCESS
+}
+
+pub fn wasi_path_remove_directory(
+ vmctx: &mut Vmctx,
+ dirfd: wasm32::__wasi_fd_t,
+ path_ptr: wasm32::uintptr_t,
+ path_len: wasm32::size_t,
+) -> wasm32::__wasi_errno_t {
+ use nix::errno;
+ use nix::libc::{unlinkat, AT_REMOVEDIR};
+
+ let dirfd = dec_fd(dirfd);
+ let path = match dec_slice_of::<u8>(vmctx, path_ptr, path_len) {
+ Ok(path_bytes) => OsStr::from_bytes(path_bytes),
+ Err(e) => return enc_errno(e),
+ };
+ let rights = host::__WASI_RIGHT_PATH_REMOVE_DIRECTORY;
+ let (dir, path) = match path_get(&vmctx, dirfd, 0, path, rights.into(), 0, false) {
+ Ok((dir, path)) => (dir, path),
+ Err(e) => return enc_errno(e),
+ };
+ let path_cstr = match std::ffi::CString::new(path.as_os_str().as_bytes()) {
+ Ok(path_cstr) => path_cstr,
+ Err(_) => return wasm32::__WASI_EINVAL,
+ };
+ // nix doesn't expose unlinkat() yet
+ match unsafe { unlinkat(dir, path_cstr.as_ptr(), AT_REMOVEDIR) } {
+ 0 => wasm32::__WASI_ESUCCESS,
+ _ => wasm32::errno_from_nix(errno::Errno::last()),
+ }
+}
+
+pub fn wasi_path_rename(
+ vmctx: &mut Vmctx,
+ old_dirfd: wasm32::__wasi_fd_t,
+ old_path_ptr: wasm32::uintptr_t,
+ old_path_len: wasm32::size_t,
+ new_dirfd: wasm32::__wasi_fd_t,
+ new_path_ptr: wasm32::uintptr_t,
+ new_path_len: wasm32::size_t,
+) -> wasm32::__wasi_errno_t {
+ use nix::libc::renameat;
+
+ let old_dirfd = dec_fd(old_dirfd);
+ let new_dirfd = dec_fd(new_dirfd);
+ let old_path = match dec_slice_of::<u8>(vmctx, old_path_ptr, old_path_len) {
+ Ok(old_path_bytes) => OsStr::from_bytes(old_path_bytes),
+ Err(e) => return enc_errno(e),
+ };
+ let new_path = match dec_slice_of::<u8>(vmctx, new_path_ptr, new_path_len) {
+ Ok(new_path_bytes) => OsStr::from_bytes(new_path_bytes),
+ Err(e) => return enc_errno(e),
+ };
+ let rights = host::__WASI_RIGHT_PATH_RENAME_SOURCE;
+ let (old_dir, old_path) =
+ match path_get(&vmctx, old_dirfd, 0, old_path, rights.into(), 0, false) {
+ Ok((dir, path)) => (dir, path),
+ Err(e) => return enc_errno(e),
+ };
+ let rights = host::__WASI_RIGHT_PATH_RENAME_TARGET;
+ let (new_dir, new_path) =
+ match path_get(&vmctx, new_dirfd, 0, new_path, rights.into(), 0, false) {
+ Ok((dir, path)) => (dir, path),
+ Err(e) => return enc_errno(e),
+ };
+ let old_path_cstr = match std::ffi::CString::new(old_path.as_bytes()) {
+ Ok(old_path_cstr) => old_path_cstr,
+ Err(_) => return wasm32::__WASI_EINVAL,
+ };
+ let new_path_cstr = match std::ffi::CString::new(new_path.as_bytes()) {
+ Ok(new_path_cstr) => new_path_cstr,
+ Err(_) => return wasm32::__WASI_EINVAL,
+ };
+ let res = unsafe {
+ renameat(
+ old_dir,
+ old_path_cstr.as_ptr(),
+ new_dir,
+ new_path_cstr.as_ptr(),
+ )
+ };
+ if res != 0 {
+ return wasm32::errno_from_nix(nix::errno::Errno::last());
+ }
+ wasm32::__WASI_ESUCCESS
+}
+
+pub fn wasi_path_symlink(
+ vmctx: &mut Vmctx,
+ old_path_ptr: wasm32::uintptr_t,
+ old_path_len: wasm32::size_t,
+ dirfd: wasm32::__wasi_fd_t,
+ new_path_ptr: wasm32::uintptr_t,
+ new_path_len: wasm32::size_t,
+) -> wasm32::__wasi_errno_t {
+ use nix::libc::symlinkat;
+
+ let dirfd = dec_fd(dirfd);
+ let old_path = match dec_slice_of::<u8>(vmctx, old_path_ptr, old_path_len) {
+ Ok(old_path_bytes) => OsStr::from_bytes(old_path_bytes),
+ Err(e) => return enc_errno(e),
+ };
+ let new_path = match dec_slice_of::<u8>(vmctx, new_path_ptr, new_path_len) {
+ Ok(new_path_bytes) => OsStr::from_bytes(new_path_bytes),
+ Err(e) => return enc_errno(e),
+ };
+ let rights = host::__WASI_RIGHT_PATH_SYMLINK;
+ let (dir, new_path) = match path_get(&vmctx, dirfd, 0, new_path, rights.into(), 0, false) {
+ Ok((dir, path)) => (dir, path),
+ Err(e) => return enc_errno(e),
+ };
+ let old_path_cstr = match std::ffi::CString::new(old_path.as_bytes()) {
+ Ok(old_path_cstr) => old_path_cstr,
+ Err(_) => return wasm32::__WASI_EINVAL,
+ };
+ let new_path_cstr = match std::ffi::CString::new(new_path.as_bytes()) {
+ Ok(new_path_cstr) => new_path_cstr,
+ Err(_) => return wasm32::__WASI_EINVAL,
+ };
+ let res = unsafe { symlinkat(old_path_cstr.as_ptr(), dir, new_path_cstr.as_ptr()) };
+ if res != 0 {
+ return wasm32::errno_from_nix(nix::errno::Errno::last());
+ }
+ wasm32::__WASI_ESUCCESS
+}
diff --git a/third_party/rust/lucet-wasi-wasmsbx/src/hostcalls/fs_helpers.rs b/third_party/rust/lucet-wasi-wasmsbx/src/hostcalls/fs_helpers.rs
new file mode 100644
index 0000000000..a82924e481
--- /dev/null
+++ b/third_party/rust/lucet-wasi-wasmsbx/src/hostcalls/fs_helpers.rs
@@ -0,0 +1,306 @@
+#![allow(non_camel_case_types)]
+#![allow(unused_unsafe)]
+use crate::ctx::WasiCtx;
+use crate::host;
+
+use lucet_runtime::vmctx::Vmctx;
+
+use nix::libc::{self, c_long};
+use std::ffi::{OsStr, OsString};
+use std::os::unix::prelude::{OsStrExt, OsStringExt, RawFd};
+
+#[cfg(target_os = "linux")]
+pub const O_RSYNC: nix::fcntl::OFlag = nix::fcntl::OFlag::O_RSYNC;
+
+#[cfg(not(target_os = "linux"))]
+pub const O_RSYNC: nix::fcntl::OFlag = nix::fcntl::OFlag::O_SYNC;
+
+/// 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 fn path_get<P: AsRef<OsStr>>(
+ vmctx: &Vmctx,
+ dirfd: host::__wasi_fd_t,
+ dirflags: host::__wasi_lookupflags_t,
+ path: P,
+ needed_base: host::__wasi_rights_t,
+ needed_inheriting: host::__wasi_rights_t,
+ needs_final_component: bool,
+) -> Result<(RawFd, OsString), host::__wasi_errno_t> {
+ use nix::errno::Errno;
+ use nix::fcntl::{openat, readlinkat, OFlag};
+ use nix::sys::stat::Mode;
+
+ const MAX_SYMLINK_EXPANSIONS: usize = 128;
+
+ /// close all the intermediate file descriptors, but make sure not to drop either the original
+ /// dirfd or the one we return (which may be the same dirfd)
+ fn ret_dir_success(dir_stack: &mut Vec<RawFd>) -> RawFd {
+ let ret_dir = dir_stack.pop().expect("there is always a dirfd to return");
+ if let Some(dirfds) = dir_stack.get(1..) {
+ for dirfd in dirfds {
+ nix::unistd::close(*dirfd).unwrap_or_else(|e| {
+ dbg!(e);
+ });
+ }
+ }
+ ret_dir
+ }
+
+ /// close all file descriptors other than the base directory, and return the errno for
+ /// convenience with `return`
+ fn ret_error(
+ dir_stack: &mut Vec<RawFd>,
+ errno: host::__wasi_errno_t,
+ ) -> Result<(RawFd, OsString), host::__wasi_errno_t> {
+ if let Some(dirfds) = dir_stack.get(1..) {
+ for dirfd in dirfds {
+ nix::unistd::close(*dirfd).unwrap_or_else(|e| {
+ dbg!(e);
+ });
+ }
+ }
+ Err(errno)
+ }
+
+ let ctx = vmctx.get_embed_ctx::<WasiCtx>();
+
+ let dirfe = ctx.get_fd_entry(dirfd, needed_base, needed_inheriting)?;
+
+ // 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![dirfe.fd_object.rawfd];
+
+ // 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.as_ref().to_owned().into_vec()];
+
+ // Track the number of symlinks we've expanded, so we can return `ELOOP` after too many.
+ let mut symlink_expansions = 0;
+
+ // Buffer to read links into; defined outside of the loop so we don't reallocate it constantly.
+ let mut readlink_buf = vec![0u8; libc::PATH_MAX as usize + 1];
+
+ // 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 {
+ let component = if let Some(cur_path) = path_stack.pop() {
+ // eprintln!(
+ // "cur_path = {:?}",
+ // std::str::from_utf8(cur_path.as_slice()).unwrap()
+ // );
+ let mut split = cur_path.splitn(2, |&c| c == b'/');
+ let head = split.next();
+ let tail = split.next();
+ match (head, tail) {
+ (None, _) => {
+ // split always returns at least a singleton iterator with an empty slice
+ panic!("unreachable");
+ }
+ // path is empty
+ (Some([]), None) => {
+ return ret_error(&mut dir_stack, host::__WASI_ENOENT as host::__wasi_errno_t);
+ }
+ // path starts with `/`, is absolute
+ (Some([]), Some(_)) => {
+ return ret_error(
+ &mut dir_stack,
+ host::__WASI_ENOTCAPABLE as host::__wasi_errno_t,
+ );
+ }
+ // the final component of the path with no trailing slash
+ (Some(component), None) => component.to_vec(),
+ (Some(component), Some(rest)) => {
+ if rest.iter().all(|&c| c == b'/') {
+ // the final component of the path with trailing slashes; put one trailing
+ // slash back on
+ let mut component = component.to_vec();
+ component.push('/' as u8);
+ component
+ } else {
+ // non-final component; push the rest back on the stack
+ path_stack.push(rest.to_vec());
+ component.to_vec()
+ }
+ }
+ }
+ } else {
+ // if the path stack is ever empty, we return rather than going through the loop again
+ panic!("unreachable");
+ };
+
+ // eprintln!(
+ // "component = {:?}",
+ // std::str::from_utf8(component.as_slice()).unwrap()
+ // );
+
+ match component.as_slice() {
+ b"." => {
+ // skip component
+ }
+ b".." => {
+ // pop a directory
+ let dirfd = dir_stack.pop().expect("dir_stack is never empty");
+
+ // we're not allowed to pop past the original directory
+ if dir_stack.is_empty() {
+ return ret_error(
+ &mut dir_stack,
+ host::__WASI_ENOTCAPABLE as host::__wasi_errno_t,
+ );
+ } else {
+ nix::unistd::close(dirfd).unwrap_or_else(|e| {
+ dbg!(e);
+ });
+ }
+ }
+ // should the component be a directory? it should if there is more path left to process, or
+ // if it has a trailing slash and `needs_final_component` is not set
+ component
+ if !path_stack.is_empty()
+ || (component.ends_with(b"/") && !needs_final_component) =>
+ {
+ match openat(
+ *dir_stack.last().expect("dir_stack is never empty"),
+ component,
+ OFlag::O_RDONLY | OFlag::O_DIRECTORY | OFlag::O_NOFOLLOW,
+ Mode::empty(),
+ ) {
+ Ok(new_dir) => {
+ dir_stack.push(new_dir);
+ continue;
+ }
+ Err(e)
+ // Check to see if it was a symlink. Linux indicates
+ // this with ENOTDIR because of the O_DIRECTORY flag.
+ if e.as_errno() == Some(Errno::ELOOP)
+ || e.as_errno() == Some(Errno::EMLINK)
+ || e.as_errno() == Some(Errno::ENOTDIR) =>
+ {
+ // attempt symlink expansion
+ match readlinkat(
+ *dir_stack.last().expect("dir_stack is never empty"),
+ component,
+ readlink_buf.as_mut_slice(),
+ ) {
+ Ok(link_path) => {
+ symlink_expansions += 1;
+ if symlink_expansions > MAX_SYMLINK_EXPANSIONS {
+ return ret_error(
+ &mut dir_stack,
+ host::__WASI_ELOOP as host::__wasi_errno_t,
+ );
+ }
+
+ let mut link_path = link_path.as_bytes().to_vec();
+
+ // append a trailing slash if the component leading to it has one, so
+ // that we preserve any ENOTDIR that might come from trying to open a
+ // non-directory
+ if component.ends_with(b"/") {
+ link_path.push(b'/');
+ }
+
+ path_stack.push(link_path);
+ continue;
+ }
+ Err(e) => {
+ return ret_error(
+ &mut dir_stack,
+ host::errno_from_nix(e.as_errno().unwrap()),
+ );
+ }
+ }
+ }
+ Err(e) => {
+ return ret_error(
+ &mut dir_stack,
+ host::errno_from_nix(e.as_errno().unwrap()),
+ );
+ }
+ }
+ }
+ // the final component
+ component => {
+ // if there's a trailing slash, or if `LOOKUP_SYMLINK_FOLLOW` is set, attempt
+ // symlink expansion
+ if component.ends_with(b"/") || (dirflags & host::__WASI_LOOKUP_SYMLINK_FOLLOW) != 0
+ {
+ match readlinkat(
+ *dir_stack.last().expect("dir_stack is never empty"),
+ component,
+ readlink_buf.as_mut_slice(),
+ ) {
+ Ok(link_path) => {
+ symlink_expansions += 1;
+ if symlink_expansions > MAX_SYMLINK_EXPANSIONS {
+ return ret_error(
+ &mut dir_stack,
+ host::__WASI_ELOOP as host::__wasi_errno_t,
+ );
+ }
+
+ let mut link_path = link_path.as_bytes().to_vec();
+
+ // append a trailing slash if the component leading to it has one, so
+ // that we preserve any ENOTDIR that might come from trying to open a
+ // non-directory
+ if component.ends_with(b"/") {
+ link_path.push(b'/');
+ }
+
+ path_stack.push(link_path);
+ continue;
+ }
+ Err(e) => {
+ let errno = e.as_errno().unwrap();
+ if errno != Errno::EINVAL && errno != Errno::ENOENT {
+ // only return an error if this path is not actually a symlink
+ return ret_error(&mut dir_stack, host::errno_from_nix(errno));
+ }
+ }
+ }
+ }
+
+ // not a symlink, so we're done;
+ return Ok((
+ ret_dir_success(&mut dir_stack),
+ OsStr::from_bytes(component).to_os_string(),
+ ));
+ }
+ }
+
+ if path_stack.is_empty() {
+ // 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((
+ ret_dir_success(&mut dir_stack),
+ OsStr::new(".").to_os_string(),
+ ));
+ } else {
+ continue;
+ }
+ }
+}
+
+#[cfg(not(target_os = "macos"))]
+pub fn utime_now() -> c_long {
+ libc::UTIME_NOW
+}
+
+#[cfg(target_os = "macos")]
+pub fn utime_now() -> c_long {
+ -1
+}
+
+#[cfg(not(target_os = "macos"))]
+pub fn utime_omit() -> c_long {
+ libc::UTIME_OMIT
+}
+
+#[cfg(target_os = "macos")]
+pub fn utime_omit() -> c_long {
+ -2
+}
diff --git a/third_party/rust/lucet-wasi-wasmsbx/src/hostcalls/misc.rs b/third_party/rust/lucet-wasi-wasmsbx/src/hostcalls/misc.rs
new file mode 100644
index 0000000000..39ab5109c1
--- /dev/null
+++ b/third_party/rust/lucet-wasi-wasmsbx/src/hostcalls/misc.rs
@@ -0,0 +1,457 @@
+#![allow(non_camel_case_types)]
+#![allow(unused_unsafe)]
+
+use crate::ctx::WasiCtx;
+use crate::memory::*;
+use crate::{host, wasm32};
+
+use super::timers;
+
+use cast::From as _0;
+use lucet_runtime::lucet_hostcall_terminate;
+use lucet_runtime::vmctx::Vmctx;
+
+use nix::convert_ioctl_res;
+use nix::libc::{self, c_int};
+use std::cmp;
+use std::mem::MaybeUninit;
+use std::time::SystemTime;
+
+// define the `fionread()` function, equivalent to `ioctl(fd, FIONREAD, *bytes)`
+nix::ioctl_read_bad!(fionread, nix::libc::FIONREAD, c_int);
+
+fn wasi_clock_to_relative_ns_delay(
+ wasi_clock: host::__wasi_subscription_t___wasi_subscription_u___wasi_subscription_u_clock_t,
+) -> u128 {
+ if wasi_clock.flags != wasm32::__WASI_SUBSCRIPTION_CLOCK_ABSTIME {
+ return wasi_clock.timeout as u128;
+ }
+ let now: u128 = SystemTime::now()
+ .duration_since(SystemTime::UNIX_EPOCH)
+ .expect("Current date is before the epoch")
+ .as_nanos();
+ let deadline = wasi_clock.timeout as u128;
+ deadline.saturating_sub(now)
+}
+
+#[derive(Debug, Copy, Clone)]
+struct ClockEventData {
+ delay: u128,
+ userdata: host::__wasi_userdata_t,
+}
+#[derive(Debug, Copy, Clone)]
+struct FdEventData {
+ fd: c_int,
+ type_: host::__wasi_eventtype_t,
+ userdata: host::__wasi_userdata_t,
+}
+
+pub fn wasi_proc_exit(_vmctx: &mut Vmctx, rval: wasm32::__wasi_exitcode_t) -> ! {
+ lucet_hostcall_terminate!(dec_exitcode(rval));
+}
+
+pub fn wasi_args_get(
+ vmctx: &mut Vmctx,
+ argv_ptr: wasm32::uintptr_t,
+ argv_buf: wasm32::uintptr_t,
+) -> wasm32::__wasi_errno_t {
+ let ctx = vmctx.get_embed_ctx::<WasiCtx>();
+
+ let mut argv_buf_offset = 0;
+ let mut argv = vec![];
+
+ for arg in ctx.args.iter() {
+ let arg_bytes = arg.as_bytes_with_nul();
+ let arg_ptr = argv_buf + argv_buf_offset;
+
+ if let Err(e) = enc_slice_of(vmctx, arg_bytes, arg_ptr) {
+ return enc_errno(e);
+ }
+
+ argv.push(arg_ptr);
+
+ argv_buf_offset = if let Some(new_offset) = argv_buf_offset.checked_add(
+ wasm32::uintptr_t::cast(arg_bytes.len())
+ .expect("cast overflow would have been caught by `enc_slice_of` above"),
+ ) {
+ new_offset
+ } else {
+ return wasm32::__WASI_EOVERFLOW;
+ }
+ }
+ enc_slice_of(vmctx, argv.as_slice(), argv_ptr)
+ .map(|_| wasm32::__WASI_ESUCCESS)
+ .unwrap_or_else(|e| e)
+}
+
+pub fn wasi_args_sizes_get(
+ vmctx: &mut Vmctx,
+ argc_ptr: wasm32::uintptr_t,
+ argv_buf_size_ptr: wasm32::uintptr_t,
+) -> wasm32::__wasi_errno_t {
+ let ctx = vmctx.get_embed_ctx::<WasiCtx>();
+
+ let argc = ctx.args.len();
+ let argv_size = ctx
+ .args
+ .iter()
+ .map(|arg| arg.as_bytes_with_nul().len())
+ .sum();
+ if let Err(e) = enc_usize_byref(vmctx, argc_ptr, argc) {
+ return enc_errno(e);
+ }
+ if let Err(e) = enc_usize_byref(vmctx, argv_buf_size_ptr, argv_size) {
+ return enc_errno(e);
+ }
+ wasm32::__WASI_ESUCCESS
+}
+
+pub fn wasi_sched_yield(_vmctx: &mut Vmctx) -> wasm32::__wasi_errno_t {
+ unsafe { libc::sched_yield() };
+ wasm32::__WASI_ESUCCESS
+}
+
+pub fn wasi_clock_res_get(
+ vmctx: &mut Vmctx,
+ clock_id: wasm32::__wasi_clockid_t,
+ resolution_ptr: wasm32::uintptr_t,
+) -> wasm32::__wasi_errno_t {
+ // convert the supported clocks to the libc types, or return EINVAL
+ let clock_id = match dec_clockid(clock_id) {
+ host::__WASI_CLOCK_REALTIME => libc::CLOCK_REALTIME,
+ host::__WASI_CLOCK_MONOTONIC => libc::CLOCK_MONOTONIC,
+ host::__WASI_CLOCK_PROCESS_CPUTIME_ID => libc::CLOCK_PROCESS_CPUTIME_ID,
+ host::__WASI_CLOCK_THREAD_CPUTIME_ID => libc::CLOCK_THREAD_CPUTIME_ID,
+ _ => return wasm32::__WASI_EINVAL,
+ };
+
+ // no `nix` wrapper for clock_getres, so we do it ourselves
+ let mut timespec = MaybeUninit::<libc::timespec>::uninit();
+ let res = unsafe { timers::clock_getres_helper(clock_id, timespec.as_mut_ptr()) };
+ if res != 0 {
+ return wasm32::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 host::__wasi_timestamp_t)
+ .checked_mul(1_000_000_000)
+ .and_then(|sec_ns| sec_ns.checked_add(timespec.tv_nsec as host::__wasi_timestamp_t))
+ .map(|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 {
+ wasm32::__WASI_EINVAL
+ } else {
+ enc_timestamp_byref(vmctx, resolution_ptr, resolution)
+ .map(|_| wasm32::__WASI_ESUCCESS)
+ .unwrap_or_else(|e| e)
+ }
+ })
+ .unwrap_or(wasm32::__WASI_EOVERFLOW)
+}
+
+pub fn wasi_clock_time_get(
+ vmctx: &mut Vmctx,
+ clock_id: wasm32::__wasi_clockid_t,
+ // ignored for now, but will be useful once we put optional limits on precision to reduce side
+ // channels
+ _precision: wasm32::__wasi_timestamp_t,
+ time_ptr: wasm32::uintptr_t,
+) -> wasm32::__wasi_errno_t {
+ // convert the supported clocks to the libc types, or return EINVAL
+ let clock_id = match dec_clockid(clock_id) {
+ host::__WASI_CLOCK_REALTIME => libc::CLOCK_REALTIME,
+ host::__WASI_CLOCK_MONOTONIC => libc::CLOCK_MONOTONIC,
+ host::__WASI_CLOCK_PROCESS_CPUTIME_ID => libc::CLOCK_PROCESS_CPUTIME_ID,
+ host::__WASI_CLOCK_THREAD_CPUTIME_ID => libc::CLOCK_THREAD_CPUTIME_ID,
+ _ => return wasm32::__WASI_EINVAL,
+ };
+
+ // no `nix` wrapper for clock_getres, so we do it ourselves
+ let mut timespec = MaybeUninit::<libc::timespec>::uninit();
+ let res = unsafe { timers::clock_gettime_helper(clock_id, timespec.as_mut_ptr()) };
+ if res != 0 {
+ return wasm32::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 host::__wasi_timestamp_t)
+ .checked_mul(1_000_000_000)
+ .and_then(|sec_ns| sec_ns.checked_add(timespec.tv_nsec as host::__wasi_timestamp_t))
+ .map(|time| {
+ enc_timestamp_byref(vmctx, time_ptr, time)
+ .map(|_| wasm32::__WASI_ESUCCESS)
+ .unwrap_or_else(|e| e)
+ })
+ .unwrap_or(wasm32::__WASI_EOVERFLOW)
+}
+
+pub fn wasi_environ_get(
+ vmctx: &mut Vmctx,
+ environ_ptr: wasm32::uintptr_t,
+ environ_buf: wasm32::uintptr_t,
+) -> wasm32::__wasi_errno_t {
+ let ctx = vmctx.get_embed_ctx::<WasiCtx>();
+
+ let mut environ_buf_offset = 0;
+ let mut environ = vec![];
+
+ for pair in ctx.env.iter() {
+ let env_bytes = pair.as_bytes_with_nul();
+ let env_ptr = environ_buf + environ_buf_offset;
+
+ if let Err(e) = enc_slice_of(vmctx, env_bytes, env_ptr) {
+ return enc_errno(e);
+ }
+
+ environ.push(env_ptr);
+
+ environ_buf_offset = if let Some(new_offset) = environ_buf_offset.checked_add(
+ wasm32::uintptr_t::cast(env_bytes.len())
+ .expect("cast overflow would have been caught by `enc_slice_of` above"),
+ ) {
+ new_offset
+ } else {
+ return wasm32::__WASI_EOVERFLOW;
+ }
+ }
+ enc_slice_of(vmctx, environ.as_slice(), environ_ptr)
+ .map(|_| wasm32::__WASI_ESUCCESS)
+ .unwrap_or_else(|e| e)
+}
+
+pub fn wasi_environ_sizes_get(
+ vmctx: &mut Vmctx,
+ environ_count_ptr: wasm32::uintptr_t,
+ environ_size_ptr: wasm32::uintptr_t,
+) -> wasm32::__wasi_errno_t {
+ let ctx = vmctx.get_embed_ctx::<WasiCtx>();
+
+ let environ_count = ctx.env.len();
+ if let Some(environ_size) = ctx.env.iter().try_fold(0, |acc: u32, pair| {
+ acc.checked_add(pair.as_bytes_with_nul().len() as u32)
+ }) {
+ if let Err(e) = enc_usize_byref(vmctx, environ_count_ptr, environ_count) {
+ return enc_errno(e);
+ }
+ if let Err(e) = enc_usize_byref(vmctx, environ_size_ptr, environ_size as usize) {
+ return enc_errno(e);
+ }
+ wasm32::__WASI_ESUCCESS
+ } else {
+ wasm32::__WASI_EOVERFLOW
+ }
+}
+
+pub fn wasi_random_get(
+ vmctx: &mut Vmctx,
+ buf_ptr: wasm32::uintptr_t,
+ buf_len: wasm32::size_t,
+) -> wasm32::__wasi_errno_t {
+ use rand::{thread_rng, RngCore};
+
+ let buf = match dec_slice_of_mut::<u8>(vmctx, buf_ptr, buf_len) {
+ Ok(buf) => buf,
+ Err(e) => return enc_errno(e),
+ };
+ thread_rng().fill_bytes(buf);
+
+ return wasm32::__WASI_ESUCCESS;
+}
+
+fn _wasi_poll_oneoff_handle_timeout_event(
+ output_slice: &mut [wasm32::__wasi_event_t],
+ timeout: Option<ClockEventData>,
+) -> wasm32::size_t {
+ if let Some(ClockEventData { userdata, .. }) = timeout {
+ let output_event = host::__wasi_event_t {
+ userdata,
+ type_: wasm32::__WASI_EVENTTYPE_CLOCK,
+ error: wasm32::__WASI_ESUCCESS,
+ u: host::__wasi_event_t___wasi_event_u {
+ fd_readwrite: host::__wasi_event_t___wasi_event_u___wasi_event_u_fd_readwrite_t {
+ nbytes: 0,
+ flags: 0,
+ },
+ },
+ };
+ output_slice[0] = enc_event(output_event);
+ 1
+ } else {
+ // shouldn't happen
+ 0
+ }
+}
+
+fn _wasi_poll_oneoff_handle_fd_event<'t>(
+ output_slice: &mut [wasm32::__wasi_event_t],
+ events: impl Iterator<Item = (&'t FdEventData, &'t nix::poll::PollFd)>,
+) -> wasm32::size_t {
+ let mut output_slice_cur = output_slice.iter_mut();
+ let mut revents_count = 0;
+ for (fd_event, poll_fd) in events {
+ let revents = match poll_fd.revents() {
+ Some(revents) => revents,
+ None => continue,
+ };
+ let mut nbytes = 0;
+ if fd_event.type_ == wasm32::__WASI_EVENTTYPE_FD_READ {
+ let _ = unsafe { fionread(fd_event.fd, &mut nbytes) };
+ }
+ let output_event = if revents.contains(nix::poll::EventFlags::POLLNVAL) {
+ host::__wasi_event_t {
+ userdata: fd_event.userdata,
+ type_: fd_event.type_,
+ error: wasm32::__WASI_EBADF,
+ u: host::__wasi_event_t___wasi_event_u {
+ fd_readwrite:
+ host::__wasi_event_t___wasi_event_u___wasi_event_u_fd_readwrite_t {
+ nbytes: 0,
+ flags: wasm32::__WASI_EVENT_FD_READWRITE_HANGUP,
+ },
+ },
+ }
+ } else if revents.contains(nix::poll::EventFlags::POLLERR) {
+ host::__wasi_event_t {
+ userdata: fd_event.userdata,
+ type_: fd_event.type_,
+ error: wasm32::__WASI_EIO,
+ u: host::__wasi_event_t___wasi_event_u {
+ fd_readwrite:
+ host::__wasi_event_t___wasi_event_u___wasi_event_u_fd_readwrite_t {
+ nbytes: 0,
+ flags: wasm32::__WASI_EVENT_FD_READWRITE_HANGUP,
+ },
+ },
+ }
+ } else if revents.contains(nix::poll::EventFlags::POLLHUP) {
+ host::__wasi_event_t {
+ userdata: fd_event.userdata,
+ type_: fd_event.type_,
+ error: wasm32::__WASI_ESUCCESS,
+ u: host::__wasi_event_t___wasi_event_u {
+ fd_readwrite:
+ host::__wasi_event_t___wasi_event_u___wasi_event_u_fd_readwrite_t {
+ nbytes: 0,
+ flags: wasm32::__WASI_EVENT_FD_READWRITE_HANGUP,
+ },
+ },
+ }
+ } else if revents.contains(nix::poll::EventFlags::POLLIN)
+ | revents.contains(nix::poll::EventFlags::POLLOUT)
+ {
+ host::__wasi_event_t {
+ userdata: fd_event.userdata,
+ type_: fd_event.type_,
+ error: wasm32::__WASI_ESUCCESS,
+ u: host::__wasi_event_t___wasi_event_u {
+ fd_readwrite:
+ host::__wasi_event_t___wasi_event_u___wasi_event_u_fd_readwrite_t {
+ nbytes: nbytes as host::__wasi_filesize_t,
+ flags: 0,
+ },
+ },
+ }
+ } else {
+ continue;
+ };
+ *output_slice_cur.next().unwrap() = enc_event(output_event);
+ revents_count += 1;
+ }
+ revents_count
+}
+
+pub fn wasi_poll_oneoff(
+ vmctx: &mut Vmctx,
+ input: wasm32::uintptr_t,
+ output: wasm32::uintptr_t,
+ nsubscriptions: wasm32::size_t,
+ nevents: wasm32::uintptr_t,
+) -> wasm32::__wasi_errno_t {
+ if nsubscriptions as u64 > wasm32::__wasi_filesize_t::max_value() {
+ return wasm32::__WASI_EINVAL;
+ }
+ enc_pointee(vmctx, nevents, 0).unwrap();
+
+ let input_slice =
+ dec_slice_of::<wasm32::__wasi_subscription_t>(vmctx, input, nsubscriptions).unwrap();
+
+ let output_slice =
+ dec_slice_of_mut::<wasm32::__wasi_event_t>(vmctx, output, nsubscriptions).unwrap();
+
+ let input: Vec<_> = input_slice.iter().map(|x| dec_subscription(x)).collect();
+
+ let timeout = input
+ .iter()
+ .filter_map(|event| match event {
+ Ok(event) if event.type_ == wasm32::__WASI_EVENTTYPE_CLOCK => Some(ClockEventData {
+ delay: wasi_clock_to_relative_ns_delay(unsafe { event.u.clock }) / 1_000_000,
+ userdata: event.userdata,
+ }),
+ _ => None,
+ })
+ .min_by_key(|event| event.delay);
+ let fd_events: Vec<_> = input
+ .iter()
+ .filter_map(|event| match event {
+ Ok(event)
+ if event.type_ == wasm32::__WASI_EVENTTYPE_FD_READ
+ || event.type_ == wasm32::__WASI_EVENTTYPE_FD_WRITE =>
+ {
+ Some(FdEventData {
+ fd: unsafe { event.u.fd_readwrite.fd } as c_int,
+ type_: event.type_,
+ userdata: event.userdata,
+ })
+ }
+ _ => None,
+ })
+ .collect();
+ if fd_events.is_empty() && timeout.is_none() {
+ return wasm32::__WASI_ESUCCESS;
+ }
+ let mut poll_fds: Vec<_> = fd_events
+ .iter()
+ .map(|event| {
+ let mut flags = nix::poll::EventFlags::empty();
+ match event.type_ {
+ wasm32::__WASI_EVENTTYPE_FD_READ => flags.insert(nix::poll::EventFlags::POLLIN),
+ wasm32::__WASI_EVENTTYPE_FD_WRITE => flags.insert(nix::poll::EventFlags::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!(),
+ };
+ nix::poll::PollFd::new(event.fd, flags)
+ })
+ .collect();
+ let timeout = timeout.map(|ClockEventData { delay, userdata }| ClockEventData {
+ delay: cmp::min(delay, c_int::max_value() as u128),
+ userdata,
+ });
+ let poll_timeout = timeout.map(|timeout| timeout.delay as c_int).unwrap_or(-1);
+ let ready = loop {
+ match nix::poll::poll(&mut poll_fds, poll_timeout) {
+ Err(_) => {
+ if nix::errno::Errno::last() == nix::errno::Errno::EINTR {
+ continue;
+ }
+ return wasm32::errno_from_nix(nix::errno::Errno::last());
+ }
+ Ok(ready) => break ready as usize,
+ }
+ };
+ let events_count = if ready == 0 {
+ _wasi_poll_oneoff_handle_timeout_event(output_slice, timeout)
+ } else {
+ let events = fd_events.iter().zip(poll_fds.iter()).take(ready);
+ _wasi_poll_oneoff_handle_fd_event(output_slice, events)
+ };
+ if let Err(e) = enc_pointee(vmctx, nevents, events_count) {
+ return enc_errno(e);
+ }
+ wasm32::__WASI_ESUCCESS
+}
diff --git a/third_party/rust/lucet-wasi-wasmsbx/src/hostcalls/mod.rs b/third_party/rust/lucet-wasi-wasmsbx/src/hostcalls/mod.rs
new file mode 100644
index 0000000000..ed9b5e038d
--- /dev/null
+++ b/third_party/rust/lucet-wasi-wasmsbx/src/hostcalls/mod.rs
@@ -0,0 +1,448 @@
+//! Hostcalls that implement
+//! [WASI](https://github.com/CraneStation/wasmtime-wasi/blob/wasi/docs/WASI-overview.md).
+//!
+//! This code borrows heavily from [wasmtime-wasi](https://github.com/CraneStation/wasmtime-wasi),
+//! which in turn borrows from cloudabi-utils. See `LICENSE.wasmtime-wasi` for license information.
+
+#![allow(non_camel_case_types)]
+#![allow(unused_unsafe)]
+
+mod fs;
+mod fs_helpers;
+mod misc;
+mod timers;
+
+use crate::wasm32;
+
+use fs::*;
+use lucet_runtime::lucet_hostcalls;
+use misc::*;
+
+lucet_hostcalls! {
+ #[no_mangle] pub unsafe extern "C"
+ fn __wasi_proc_exit(&mut vmctx, rval: wasm32::__wasi_exitcode_t,) -> ! {
+ wasi_proc_exit(vmctx, rval)
+ }
+
+ #[no_mangle] pub unsafe extern "C"
+ fn __wasi_args_get(
+ &mut vmctx,
+ argv_ptr: wasm32::uintptr_t,
+ argv_buf: wasm32::uintptr_t,
+ ) -> wasm32::__wasi_errno_t {
+ wasi_args_get(vmctx, argv_ptr, argv_buf)
+ }
+
+ #[no_mangle] pub unsafe extern "C"
+ fn __wasi_args_sizes_get(&mut vmctx,
+ argc_ptr: wasm32::uintptr_t,
+ argv_buf_size_ptr: wasm32::uintptr_t,
+ ) -> wasm32::__wasi_errno_t {
+ wasi_args_sizes_get(vmctx, argc_ptr, argv_buf_size_ptr)
+ }
+
+ #[no_mangle] pub unsafe extern "C"
+ fn __wasi_sched_yield(&mut vmctx,) -> wasm32::__wasi_errno_t {
+ wasi_sched_yield(vmctx)
+ }
+
+ #[no_mangle] pub unsafe extern "C"
+ fn __wasi_clock_res_get(
+ &mut vmctx,
+ clock_id: wasm32::__wasi_clockid_t,
+ resolution_ptr: wasm32::uintptr_t,
+ ) -> wasm32::__wasi_errno_t {
+ wasi_clock_res_get(vmctx, clock_id, resolution_ptr)
+ }
+
+ #[no_mangle] pub unsafe extern "C"
+ fn __wasi_clock_time_get(
+ &mut vmctx,
+ clock_id: wasm32::__wasi_clockid_t,
+ precision: wasm32::__wasi_timestamp_t,
+ time_ptr: wasm32::uintptr_t,
+ ) -> wasm32::__wasi_errno_t {
+ wasi_clock_time_get(vmctx, clock_id, precision, time_ptr)
+ }
+
+ #[no_mangle] pub unsafe extern "C"
+ fn __wasi_environ_get(
+ &mut vmctx,
+ environ_ptr: wasm32::uintptr_t,
+ environ_buf: wasm32::uintptr_t,
+ ) -> wasm32::__wasi_errno_t {
+ wasi_environ_get(vmctx, environ_ptr, environ_buf)
+ }
+
+ #[no_mangle] pub unsafe extern "C"
+ fn __wasi_environ_sizes_get(
+ &mut vmctx,
+ environ_count_ptr: wasm32::uintptr_t,
+ environ_size_ptr: wasm32::uintptr_t,
+ ) -> wasm32::__wasi_errno_t {
+ wasi_environ_sizes_get(vmctx, environ_count_ptr, environ_size_ptr)
+ }
+
+ #[no_mangle] pub unsafe extern "C"
+ fn __wasi_fd_close(
+ &mut vmctx,
+ fd: wasm32::__wasi_fd_t,
+ ) -> wasm32::__wasi_errno_t {
+ wasi_fd_close(vmctx, fd)
+ }
+
+ #[no_mangle] pub unsafe extern "C"
+ fn __wasi_fd_fdstat_get(
+ &mut vmctx,
+ fd: wasm32::__wasi_fd_t,
+ fdstat_ptr: wasm32::uintptr_t,
+ ) -> wasm32::__wasi_errno_t {
+ wasi_fd_fdstat_get(vmctx, fd, fdstat_ptr)
+ }
+
+ #[no_mangle] pub unsafe extern "C"
+ fn __wasi_fd_fdstat_set_flags(
+ &mut vmctx,
+ fd: wasm32::__wasi_fd_t,
+ fdflags: wasm32::__wasi_fdflags_t,
+ ) -> wasm32::__wasi_errno_t {
+ wasi_fd_fdstat_set_flags(vmctx, fd, fdflags)
+ }
+
+ #[no_mangle] pub unsafe extern "C"
+ fn __wasi_fd_tell(&mut vmctx,
+ fd: wasm32::__wasi_fd_t,
+ offset: wasm32::uintptr_t,
+ ) -> wasm32::__wasi_errno_t {
+ wasi_fd_tell(vmctx, fd, offset)
+ }
+
+ #[no_mangle] pub unsafe extern "C"
+ fn __wasi_fd_seek(&mut vmctx,
+ fd: wasm32::__wasi_fd_t,
+ offset: wasm32::__wasi_filedelta_t,
+ whence: wasm32::__wasi_whence_t,
+ newoffset: wasm32::uintptr_t,
+ ) -> wasm32::__wasi_errno_t {
+ wasi_fd_seek(vmctx, fd, offset, whence, newoffset)
+ }
+
+ #[no_mangle] pub unsafe extern "C"
+ fn __wasi_fd_prestat_get(
+ &mut vmctx,
+ fd: wasm32::__wasi_fd_t,
+ prestat_ptr: wasm32::uintptr_t,
+ ) -> wasm32::__wasi_errno_t {
+ wasi_fd_prestat_get(vmctx, fd, prestat_ptr)
+ }
+
+ #[no_mangle] pub unsafe extern "C"
+ fn __wasi_fd_prestat_dir_name(
+ &mut vmctx,
+ fd: wasm32::__wasi_fd_t,
+ path_ptr: wasm32::uintptr_t,
+ path_len: wasm32::size_t,
+ ) -> wasm32::__wasi_errno_t {
+ wasi_fd_prestat_dir_name(vmctx, fd, path_ptr, path_len)
+ }
+
+ #[no_mangle] pub unsafe extern "C"
+ fn __wasi_fd_read(
+ &mut vmctx,
+ fd: wasm32::__wasi_fd_t,
+ iovs_ptr: wasm32::uintptr_t,
+ iovs_len: wasm32::size_t,
+ nread: wasm32::uintptr_t,
+ ) -> wasm32::__wasi_errno_t {
+ wasi_fd_read(vmctx, fd, iovs_ptr, iovs_len, nread)
+ }
+
+ #[no_mangle] pub unsafe extern "C"
+ fn __wasi_fd_write(
+ &mut vmctx,
+ fd: wasm32::__wasi_fd_t,
+ iovs_ptr: wasm32::uintptr_t,
+ iovs_len: wasm32::size_t,
+ nwritten: wasm32::uintptr_t,
+ ) -> wasm32::__wasi_errno_t {
+ wasi_fd_write(vmctx, fd, iovs_ptr, iovs_len, nwritten)
+ }
+
+ #[no_mangle] pub unsafe extern "C"
+ fn __wasi_path_open(
+ &mut vmctx,
+ dirfd: wasm32::__wasi_fd_t,
+ dirflags: wasm32::__wasi_lookupflags_t,
+ path_ptr: wasm32::uintptr_t,
+ path_len: wasm32::size_t,
+ oflags: wasm32::__wasi_oflags_t,
+ fs_rights_base: wasm32::__wasi_rights_t,
+ fs_rights_inheriting: wasm32::__wasi_rights_t,
+ fs_flags: wasm32::__wasi_fdflags_t,
+ fd_out_ptr: wasm32::uintptr_t,
+ ) -> wasm32::__wasi_errno_t {
+ wasi_path_open(vmctx, dirfd, dirflags, path_ptr, path_len,
+ oflags, fs_rights_base, fs_rights_inheriting, fs_flags,
+ fd_out_ptr)
+ }
+
+ #[no_mangle] pub unsafe extern "C"
+ fn __wasi_random_get(
+ &mut vmctx,
+ buf_ptr: wasm32::uintptr_t,
+ buf_len: wasm32::size_t,
+ ) -> wasm32::__wasi_errno_t {
+ wasi_random_get(vmctx, buf_ptr, buf_len)
+ }
+
+ #[no_mangle] pub unsafe extern "C"
+ fn __wasi_poll_oneoff(
+ &mut vmctx,
+ input: wasm32::uintptr_t,
+ output: wasm32::uintptr_t,
+ nsubscriptions: wasm32::size_t,
+ nevents: wasm32::uintptr_t,
+ ) -> wasm32::__wasi_errno_t {
+ wasi_poll_oneoff(vmctx, input, output, nsubscriptions, nevents)
+ }
+
+ #[no_mangle] pub unsafe extern "C"
+ fn __wasi_fd_filestat_get(
+ &mut vmctx,
+ fd: wasm32::__wasi_fd_t,
+ filestat_ptr: wasm32::uintptr_t,
+ ) -> wasm32::__wasi_errno_t {
+ wasi_fd_filestat_get(vmctx, fd, filestat_ptr)
+ }
+
+ #[no_mangle] pub unsafe extern "C"
+ fn __wasi_path_filestat_get(
+ &mut vmctx,
+ dirfd: wasm32::__wasi_fd_t,
+ dirflags: wasm32::__wasi_lookupflags_t,
+ path_ptr: wasm32::uintptr_t,
+ path_len: wasm32::size_t,
+ filestat_ptr: wasm32::uintptr_t,
+ ) -> wasm32::__wasi_errno_t {
+ wasi_path_filestat_get(vmctx, dirfd, dirflags, path_ptr,
+ path_len, filestat_ptr)
+ }
+
+ #[no_mangle] pub unsafe extern "C"
+ fn __wasi_path_create_directory(
+ &mut vmctx,
+ dirfd: wasm32::__wasi_fd_t,
+ path_ptr: wasm32::uintptr_t,
+ path_len: wasm32::size_t,
+ ) -> wasm32::__wasi_errno_t {
+ wasi_path_create_directory(vmctx, dirfd, path_ptr, path_len)
+ }
+
+ #[no_mangle] pub unsafe extern "C"
+ fn __wasi_path_unlink_file(
+ &mut vmctx,
+ dirfd: wasm32::__wasi_fd_t,
+ path_ptr: wasm32::uintptr_t,
+ path_len: wasm32::size_t,
+ ) -> wasm32::__wasi_errno_t {
+ wasi_path_unlink_file(vmctx, dirfd, path_ptr, path_len)
+ }
+
+ #[no_mangle] pub unsafe extern "C"
+ fn __wasi_fd_allocate(
+ &mut vmctx,
+ fd: wasm32::__wasi_fd_t,
+ offset: wasm32::__wasi_filesize_t,
+ len: wasm32::__wasi_filesize_t,
+ ) -> wasm32::__wasi_errno_t {
+ wasi_fd_allocate(vmctx, fd, offset, len)
+ }
+
+ #[no_mangle] pub unsafe extern "C"
+ fn __wasi_fd_advise(
+ &mut vmctx,
+ fd: wasm32::__wasi_fd_t,
+ offset: wasm32::__wasi_filesize_t,
+ len: wasm32::__wasi_filesize_t,
+ advice: wasm32::__wasi_advice_t,
+ ) -> wasm32::__wasi_errno_t {
+ wasi_fd_advise(vmctx, fd, offset, len, advice)
+ }
+
+ #[no_mangle] pub unsafe extern "C"
+ fn __wasi_fd_datasync(
+ &mut vmctx,
+ fd: wasm32::__wasi_fd_t,
+ ) -> wasm32::__wasi_errno_t {
+ wasi_fd_datasync(vmctx, fd)
+ }
+
+ #[no_mangle] pub unsafe extern "C"
+ fn __wasi_fd_sync(
+ &mut vmctx,
+ fd: wasm32::__wasi_fd_t,
+ ) -> wasm32::__wasi_errno_t {
+ wasi_fd_sync(vmctx, fd)
+ }
+
+ #[no_mangle] pub unsafe extern "C"
+ fn __wasi_fd_fdstat_set_rights(
+ &mut vmctx,
+ fd: wasm32::__wasi_fd_t,
+ fs_rights_base: wasm32::__wasi_rights_t,
+ fs_rights_inheriting: wasm32::__wasi_rights_t,
+ ) -> wasm32::__wasi_errno_t {
+ wasi_fd_fdstat_set_rights(vmctx, fd, fs_rights_base, fs_rights_inheriting)
+ }
+
+ #[no_mangle] pub unsafe extern "C"
+ fn __wasi_fd_filestat_set_size(
+ &mut vmctx,
+ fd: wasm32::__wasi_fd_t,
+ st_size: wasm32::__wasi_filesize_t,
+ ) -> wasm32::__wasi_errno_t {
+ wasi_fd_filestat_set_size(vmctx, fd, st_size)
+ }
+
+ #[no_mangle] pub unsafe extern "C"
+ fn __wasi_fd_filestat_set_times(
+ &mut vmctx,
+ fd: wasm32::__wasi_fd_t,
+ st_atim: wasm32::__wasi_timestamp_t,
+ st_mtim: wasm32::__wasi_timestamp_t,
+ fst_flags: wasm32::__wasi_fstflags_t,
+ ) -> wasm32::__wasi_errno_t {
+ wasi_fd_filestat_set_times(vmctx, fd, st_atim, st_mtim, fst_flags)
+ }
+
+ #[no_mangle] pub unsafe extern "C"
+ fn __wasi_fd_pread(
+ &mut vmctx,
+ fd: wasm32::__wasi_fd_t,
+ iovs_ptr: wasm32::uintptr_t,
+ iovs_len: wasm32::size_t,
+ offset: wasm32::__wasi_filesize_t,
+ nread: wasm32::uintptr_t,
+ ) -> wasm32::__wasi_errno_t {
+ wasi_fd_pread(vmctx, fd, iovs_ptr, iovs_len, offset, nread)
+ }
+
+ #[no_mangle] pub unsafe extern "C"
+ fn __wasi_fd_pwrite(
+ &mut vmctx,
+ fd: wasm32::__wasi_fd_t,
+ iovs_ptr: wasm32::uintptr_t,
+ iovs_len: wasm32::size_t,
+ offset: wasm32::__wasi_filesize_t,
+ nwritten: wasm32::uintptr_t,
+ ) -> wasm32::__wasi_errno_t {
+ wasi_fd_pwrite(vmctx, fd, iovs_ptr, iovs_len, offset, nwritten)
+ }
+
+ #[no_mangle] pub unsafe extern "C"
+ fn __wasi_fd_readdir(
+ &mut vmctx,
+ fd: wasm32::__wasi_fd_t,
+ buf: wasm32::uintptr_t,
+ buf_len: wasm32::size_t,
+ cookie: wasm32::__wasi_dircookie_t,
+ bufused: wasm32::uintptr_t,
+ ) -> wasm32::__wasi_errno_t {
+ wasi_fd_readdir(vmctx, fd, buf, buf_len, cookie, bufused)
+ }
+
+ #[no_mangle] pub unsafe extern "C"
+ fn __wasi_fd_renumber(
+ &mut vmctx,
+ from: wasm32::__wasi_fd_t,
+ to: wasm32::__wasi_fd_t,
+ ) -> wasm32::__wasi_errno_t {
+ wasi_fd_renumber(vmctx, from, to)
+ }
+
+ #[no_mangle] pub unsafe extern "C"
+ fn __wasi_path_filestat_set_times(
+ &mut vmctx,
+ dirfd: wasm32::__wasi_fd_t,
+ dirflags: wasm32::__wasi_lookupflags_t,
+ path_ptr: wasm32::uintptr_t,
+ path_len: wasm32::size_t,
+ st_atim: wasm32::__wasi_timestamp_t,
+ st_mtim: wasm32::__wasi_timestamp_t,
+ fst_flags: wasm32::__wasi_fstflags_t,
+ ) -> wasm32::__wasi_errno_t {
+ wasi_path_filestat_set_times(vmctx, dirfd, dirflags, path_ptr, path_len, st_atim, st_mtim, fst_flags)
+ }
+
+ #[no_mangle] pub unsafe extern "C"
+ fn __wasi_path_link(
+ &mut vmctx,
+ old_fd: wasm32::__wasi_fd_t,
+ old_flags: wasm32::__wasi_lookupflags_t,
+ old_path_ptr: wasm32::uintptr_t,
+ old_path_len: wasm32::size_t,
+ new_fd: wasm32::__wasi_fd_t,
+ new_path_ptr: wasm32::uintptr_t,
+ new_path_len: wasm32::size_t,
+ ) -> wasm32::__wasi_errno_t {
+ wasi_path_link(vmctx, old_fd, old_flags, old_path_ptr, old_path_len,
+ new_fd, new_path_ptr, new_path_len)
+ }
+
+ #[no_mangle] pub unsafe extern "C"
+ fn __wasi_path_readlink(
+ &mut vmctx,
+ dirfd: wasm32::__wasi_fd_t,
+ path_ptr: wasm32::uintptr_t,
+ path_len: wasm32::size_t,
+ buf_ptr: wasm32::uintptr_t,
+ buf_len: wasm32::size_t,
+ bufused: wasm32::uintptr_t,
+ ) -> wasm32::__wasi_errno_t {
+ wasi_path_readlink(vmctx, dirfd, path_ptr, path_len, buf_ptr, buf_len, bufused)
+ }
+
+ #[no_mangle] pub unsafe extern "C"
+ fn __wasi_path_remove_directory(
+ &mut vmctx,
+ dirfd: wasm32::__wasi_fd_t,
+ path_ptr: wasm32::uintptr_t,
+ path_len: wasm32::size_t,
+ ) -> wasm32::__wasi_errno_t {
+ wasi_path_remove_directory(vmctx, dirfd, path_ptr, path_len)
+ }
+
+ #[no_mangle] pub unsafe extern "C"
+ fn __wasi_path_rename(
+ &mut vmctx,
+ old_dirfd: wasm32::__wasi_fd_t,
+ old_path_ptr: wasm32::uintptr_t,
+ old_path_len: wasm32::size_t,
+ new_dirfd: wasm32::__wasi_fd_t,
+ new_path_ptr: wasm32::uintptr_t,
+ new_path_len: wasm32::size_t,
+ ) -> wasm32::__wasi_errno_t {
+ wasi_path_rename(vmctx, old_dirfd, old_path_ptr, old_path_len,
+ new_dirfd, new_path_ptr, new_path_len)
+ }
+
+ #[no_mangle] pub unsafe extern "C"
+ fn __wasi_path_symlink(
+ &mut vmctx,
+ old_path_ptr: wasm32::uintptr_t,
+ old_path_len: wasm32::size_t,
+ dir_fd: wasm32::__wasi_fd_t,
+ new_path_ptr: wasm32::uintptr_t,
+ new_path_len: wasm32::size_t,
+ ) -> wasm32::__wasi_errno_t {
+ wasi_path_symlink(vmctx, old_path_ptr, old_path_len,
+ dir_fd, new_path_ptr, new_path_len)
+ }
+}
+
+#[doc(hidden)]
+pub fn ensure_linked() {
+ unsafe {
+ std::ptr::read_volatile(__wasi_proc_exit as *const extern "C" fn());
+ }
+}
diff --git a/third_party/rust/lucet-wasi-wasmsbx/src/hostcalls/timers.rs b/third_party/rust/lucet-wasi-wasmsbx/src/hostcalls/timers.rs
new file mode 100644
index 0000000000..926a998445
--- /dev/null
+++ b/third_party/rust/lucet-wasi-wasmsbx/src/hostcalls/timers.rs
@@ -0,0 +1,113 @@
+use nix::libc::{self, c_int, c_char};
+
+#[cfg(not(target_os = "macos"))]
+mod notmac
+{
+ use super::*;
+
+ pub unsafe fn clock_gettime_helper(clock_id: libc::clockid_t, tp: *mut libc::timespec) -> c_int {
+ libc::clock_gettime(clock_id, tp)
+ }
+
+ pub unsafe fn clock_getres_helper(clock_id: libc::clockid_t, res: *mut libc::timespec) -> c_int {
+ libc::clock_getres(clock_id, res)
+ }
+
+ pub unsafe fn futimens_helper(fd: c_int, times: *const libc::timespec) -> c_int {
+ libc::futimens(fd, times)
+ }
+
+ pub unsafe fn utimensat_helper(dirfd: c_int, path: *const c_char, times: *const libc::timespec, flag: c_int) -> c_int {
+ libc::utimensat(dirfd, path, times, flag)
+ }
+}
+
+#[cfg(target_os = "macos")]
+mod mac
+{
+ use super::*;
+ use std::mem::MaybeUninit;
+ use std::sync::Once;
+
+ use mach::mach_time::*;
+
+ // Referring these 3 sources
+ //https://stackoverflow.com/questions/5167269/clock-gettime-alternative-in-mac-os-x
+ //https://stackoverflow.com/questions/11680461/monotonic-clock-on-osx
+ //https://gist.github.com/lifthrasiir/393ffb3e9900709fa2e3ae2a540b635f
+
+ static mut CONVERSION_FACTOR : f64 = 0.0;
+ static INIT : Once = Once::new();
+
+ unsafe fn get_cached_conversion_factor() -> f64 {
+ unsafe {
+ INIT.call_once(|| {
+ let mut timebase = MaybeUninit::<mach_timebase_info_data_t>::uninit();
+ mach_timebase_info(timebase.as_mut_ptr());
+ let timebase = unsafe { timebase.assume_init() };
+
+ let numer_d : f64 = timebase.numer as f64;
+ let denom_d : f64 = timebase.denom as f64;
+
+ CONVERSION_FACTOR = numer_d / denom_d;
+ });
+ }
+ CONVERSION_FACTOR
+ }
+
+ pub unsafe fn clock_gettime_helper(clock_id: libc::clockid_t, tp: *mut libc::timespec) -> c_int {
+ if !(clock_id == libc::CLOCK_REALTIME || clock_id == libc::CLOCK_MONOTONIC) {
+ (*libc::__error()) = libc::EINVAL;
+ return -1;
+ }
+
+ if clock_id == libc::CLOCK_REALTIME {
+ let mut micro = MaybeUninit::<libc::timeval>::uninit();
+ libc::gettimeofday(micro.as_mut_ptr(), core::ptr::null_mut());
+ let micro = unsafe { micro.assume_init() };
+
+ (*tp).tv_sec = micro.tv_sec;
+ (*tp).tv_nsec = i64::from(micro.tv_usec) * 1000;
+ return 0;
+ } else {
+ let time : u64 = mach_absolute_time();
+ let time_d : f64 = time as f64;
+ let conv : f64 = get_cached_conversion_factor();
+ let nseconds : f64 = time_d * conv;
+ let seconds : f64 = nseconds / 1e9;
+ (*tp).tv_sec = seconds as i64;
+ (*tp).tv_nsec = nseconds as i64;
+ return 0;
+ }
+ }
+
+ pub unsafe fn clock_getres_helper(clock_id: libc::clockid_t, res: *mut libc::timespec) -> c_int {
+ if !(clock_id == libc::CLOCK_REALTIME || clock_id == libc::CLOCK_MONOTONIC) {
+ (*libc::__error()) = libc::EINVAL;
+ return -1;
+ }
+
+ (*res).tv_sec = 0 as i64;
+ (*res).tv_nsec =
+ if clock_id == libc::CLOCK_REALTIME {
+ 1000 as i64
+ } else {
+ 1 as i64
+ };
+ return 0;
+ }
+
+ pub unsafe fn futimens_helper(_fd: c_int, _times: *const libc::timespec) -> c_int {
+ panic!("futimens not implemented");
+ }
+
+ pub unsafe fn utimensat_helper(_dirfd: c_int, _path: *const c_char, _times: *const libc::timespec, _flag: c_int) -> c_int {
+ panic!("utimensat not implemented");
+ }
+}
+
+#[cfg(not(target_os = "macos"))]
+pub use notmac::*;
+
+#[cfg(target_os = "macos")]
+pub use mac::*; \ No newline at end of file
diff --git a/third_party/rust/lucet-wasi-wasmsbx/src/lib.rs b/third_party/rust/lucet-wasi-wasmsbx/src/lib.rs
new file mode 100644
index 0000000000..2c3a5f0675
--- /dev/null
+++ b/third_party/rust/lucet-wasi-wasmsbx/src/lib.rs
@@ -0,0 +1,16 @@
+#![deny(bare_trait_objects)]
+
+mod bindings;
+pub mod c_api;
+pub mod ctx;
+pub mod fdentry;
+pub mod host;
+pub mod hostcalls;
+pub mod memory;
+pub mod wasm32;
+
+pub use bindings::bindings;
+pub use ctx::{WasiCtx, WasiCtxBuilder};
+
+#[macro_use]
+extern crate lazy_static; \ No newline at end of file
diff --git a/third_party/rust/lucet-wasi-wasmsbx/src/memory.rs b/third_party/rust/lucet-wasi-wasmsbx/src/memory.rs
new file mode 100644
index 0000000000..3ecfd51b11
--- /dev/null
+++ b/third_party/rust/lucet-wasi-wasmsbx/src/memory.rs
@@ -0,0 +1,620 @@
+//! Functions to go back and forth between WASI types in host and wasm32 representations.
+//!
+//! This module is an adaptation of the `wasmtime-wasi` module
+//! [`translate.rs`](https://github.com/CraneStation/wasmtime-wasi/blob/1a6ecf3a0378d71f3fc1ba25ce76a2b43e4166b8/lib/wasi/src/translate.rs);
+//! its license file `LICENSE.wasmtime-wasi` is included in this project.
+//!
+//! Any of these functions that take a `Vmctx` argument are only meant to be called from within a
+//! hostcall.
+//!
+//! This sort of manual encoding will hopefully be obsolete once the IDL is developed.
+
+use crate::{host, wasm32};
+use cast;
+use cast::From as _0;
+use lucet_runtime::vmctx::Vmctx;
+use std::mem::{align_of, size_of};
+use std::slice;
+
+macro_rules! bail_errno {
+ ( $errno:ident ) => {
+ return Err(host::$errno as host::__wasi_errno_t);
+ };
+}
+
+pub fn dec_ptr(
+ vmctx: &Vmctx,
+ ptr: wasm32::uintptr_t,
+ len: usize,
+) -> Result<*const u8, host::__wasi_errno_t> {
+ let heap = vmctx.heap();
+
+ // check for overflow
+ let checked_len = (ptr as usize)
+ .checked_add(len)
+ .ok_or(host::__WASI_EFAULT as host::__wasi_errno_t)?;
+ if checked_len > heap.len() {
+ bail_errno!(__WASI_EFAULT);
+ }
+ // translate the pointer
+ Ok(unsafe { heap.as_ptr().offset(ptr as isize) })
+}
+
+pub fn dec_ptr_mut(
+ vmctx: &Vmctx,
+ ptr: wasm32::uintptr_t,
+ len: usize,
+) -> Result<*mut u8, host::__wasi_errno_t> {
+ let mut heap = vmctx.heap_mut();
+
+ // check for overflow
+ let checked_len = (ptr as usize)
+ .checked_add(len)
+ .ok_or(host::__WASI_EFAULT as host::__wasi_errno_t)?;
+ if checked_len > heap.len() {
+ bail_errno!(__WASI_EFAULT);
+ }
+ // translate the pointer
+ Ok(unsafe { heap.as_mut_ptr().offset(ptr as isize) })
+}
+
+pub fn dec_ptr_to<T>(
+ vmctx: &Vmctx,
+ ptr: wasm32::uintptr_t,
+) -> Result<*const T, host::__wasi_errno_t> {
+ // check that the ptr is aligned
+ if ptr as usize % align_of::<T>() != 0 {
+ bail_errno!(__WASI_EINVAL);
+ }
+ dec_ptr(vmctx, ptr, size_of::<T>()).map(|p| p as *const T)
+}
+
+pub fn dec_ptr_to_mut<T>(
+ vmctx: &Vmctx,
+ ptr: wasm32::uintptr_t,
+) -> Result<*mut T, host::__wasi_errno_t> {
+ // check that the ptr is aligned
+ if ptr as usize % align_of::<T>() != 0 {
+ bail_errno!(__WASI_EINVAL);
+ }
+ dec_ptr_mut(vmctx, ptr, size_of::<T>()).map(|p| p as *mut T)
+}
+
+pub fn dec_pointee<T>(vmctx: &Vmctx, ptr: wasm32::uintptr_t) -> Result<T, host::__wasi_errno_t> {
+ dec_ptr_to::<T>(vmctx, ptr).map(|p| unsafe { p.read() })
+}
+
+pub fn enc_pointee<T>(
+ vmctx: &Vmctx,
+ ptr: wasm32::uintptr_t,
+ t: T,
+) -> Result<(), host::__wasi_errno_t> {
+ dec_ptr_to_mut::<T>(vmctx, ptr).map(|p| unsafe { p.write(t) })
+}
+
+fn check_slice_of<T>(
+ ptr: wasm32::uintptr_t,
+ len: wasm32::size_t,
+) -> Result<(usize, usize), host::__wasi_errno_t> {
+ // check alignment, and that length doesn't overflow
+ if ptr as usize % align_of::<T>() != 0 {
+ bail_errno!(__WASI_EINVAL);
+ }
+ let len = dec_usize(len);
+ let len_bytes = if let Some(len) = size_of::<T>().checked_mul(len) {
+ len
+ } else {
+ bail_errno!(__WASI_EOVERFLOW);
+ };
+ Ok((len, len_bytes))
+}
+
+pub fn dec_slice_of<'vmctx, T>(
+ vmctx: &'vmctx Vmctx,
+ ptr: wasm32::uintptr_t,
+ len: wasm32::size_t,
+) -> Result<&'vmctx [T], host::__wasi_errno_t> {
+ let (len, len_bytes) = check_slice_of::<T>(ptr, len)?;
+ let ptr = dec_ptr(vmctx, ptr, len_bytes)? as *const T;
+ Ok(unsafe { slice::from_raw_parts(ptr, len) })
+}
+
+pub fn dec_slice_of_mut<'vmctx, T>(
+ vmctx: &'vmctx Vmctx,
+ ptr: wasm32::uintptr_t,
+ len: wasm32::size_t,
+) -> Result<&'vmctx mut [T], host::__wasi_errno_t> {
+ let (len, len_bytes) = check_slice_of::<T>(ptr, len)?;
+ let ptr = dec_ptr_mut(vmctx, ptr, len_bytes)? as *mut T;
+ Ok(unsafe { slice::from_raw_parts_mut(ptr, len) })
+}
+
+pub fn enc_slice_of<T>(
+ vmctx: &Vmctx,
+ slice: &[T],
+ ptr: wasm32::uintptr_t,
+) -> Result<(), host::__wasi_errno_t> {
+ // check alignment
+ if ptr as usize % align_of::<T>() != 0 {
+ return Err(host::__WASI_EINVAL as host::__wasi_errno_t);
+ }
+ // check that length doesn't overflow
+ let len_bytes = if let Some(len) = size_of::<T>().checked_mul(slice.len()) {
+ len
+ } else {
+ return Err(host::__WASI_EOVERFLOW as host::__wasi_errno_t);
+ };
+
+ // get the pointer into guest memory, and copy the bytes
+ let ptr = dec_ptr(vmctx, ptr, len_bytes)? as *mut libc::c_void;
+ unsafe { std::ptr::copy_nonoverlapping(slice.as_ptr() as *const libc::c_void, ptr, len_bytes) };
+
+ Ok(())
+}
+
+macro_rules! dec_enc_scalar {
+ ( $ty:ident, $dec:ident, $dec_byref:ident, $enc:ident, $enc_byref:ident) => {
+ pub fn $dec(x: wasm32::$ty) -> host::$ty {
+ host::$ty::from_le(x)
+ }
+
+ pub fn $dec_byref(
+ vmctx: &Vmctx,
+ ptr: wasm32::uintptr_t,
+ ) -> Result<host::$ty, host::__wasi_errno_t> {
+ dec_pointee::<wasm32::$ty>(vmctx, ptr).map($dec)
+ }
+
+ pub fn $enc(x: host::$ty) -> wasm32::$ty {
+ x.to_le()
+ }
+
+ pub fn $enc_byref(
+ vmctx: &Vmctx,
+ ptr: wasm32::uintptr_t,
+ x: host::$ty,
+ ) -> Result<(), host::__wasi_errno_t> {
+ enc_pointee::<wasm32::$ty>(vmctx, ptr, $enc(x))
+ }
+ };
+}
+
+pub fn dec_ciovec(
+ vmctx: &Vmctx,
+ ciovec: &wasm32::__wasi_ciovec_t,
+) -> Result<host::__wasi_ciovec_t, host::__wasi_errno_t> {
+ let len = dec_usize(ciovec.buf_len);
+ Ok(host::__wasi_ciovec_t {
+ buf: dec_ptr(vmctx, ciovec.buf, len)? as *const host::void,
+ buf_len: len,
+ })
+}
+
+pub fn dec_ciovec_slice(
+ vmctx: &Vmctx,
+ ptr: wasm32::uintptr_t,
+ len: wasm32::size_t,
+) -> Result<Vec<host::__wasi_ciovec_t>, host::__wasi_errno_t> {
+ let slice = dec_slice_of::<wasm32::__wasi_ciovec_t>(vmctx, ptr, len)?;
+ slice.iter().map(|iov| dec_ciovec(vmctx, iov)).collect()
+}
+
+pub fn dec_iovec(
+ vmctx: &Vmctx,
+ iovec: &wasm32::__wasi_iovec_t,
+) -> Result<host::__wasi_iovec_t, host::__wasi_errno_t> {
+ let len = dec_usize(iovec.buf_len);
+ Ok(host::__wasi_iovec_t {
+ buf: dec_ptr(vmctx, iovec.buf, len)? as *mut host::void,
+ buf_len: len,
+ })
+}
+
+pub fn dec_iovec_slice(
+ vmctx: &Vmctx,
+ ptr: wasm32::uintptr_t,
+ len: wasm32::size_t,
+) -> Result<Vec<host::__wasi_iovec_t>, host::__wasi_errno_t> {
+ let slice = dec_slice_of::<wasm32::__wasi_iovec_t>(vmctx, ptr, len)?;
+ slice.iter().map(|iov| dec_iovec(vmctx, iov)).collect()
+}
+
+dec_enc_scalar!(
+ __wasi_clockid_t,
+ dec_clockid,
+ dec_clockid_byref,
+ enc_clockid,
+ enc_clockid_byref
+);
+dec_enc_scalar!(
+ __wasi_errno_t,
+ dec_errno,
+ dec_errno_byref,
+ enc_errno,
+ enc_errno_byref
+);
+dec_enc_scalar!(
+ __wasi_exitcode_t,
+ dec_exitcode,
+ dec_exitcode_byref,
+ enc_exitcode,
+ enc_exitcode_byref
+);
+dec_enc_scalar!(__wasi_fd_t, dec_fd, dec_fd_byref, enc_fd, enc_fd_byref);
+dec_enc_scalar!(
+ __wasi_fdflags_t,
+ dec_fdflags,
+ dec_fdflags_byref,
+ enc_fdflags,
+ enc_fdflags_byref
+);
+dec_enc_scalar!(
+ __wasi_device_t,
+ dec_device,
+ dev_device_byref,
+ enc_device,
+ enc_device_byref
+);
+dec_enc_scalar!(
+ __wasi_inode_t,
+ dec_inode,
+ dev_inode_byref,
+ enc_inode,
+ enc_inode_byref
+);
+dec_enc_scalar!(
+ __wasi_linkcount_t,
+ dec_linkcount,
+ dev_linkcount_byref,
+ enc_linkcount,
+ enc_linkcount_byref
+);
+
+pub fn dec_filestat(filestat: wasm32::__wasi_filestat_t) -> host::__wasi_filestat_t {
+ host::__wasi_filestat_t {
+ st_dev: dec_device(filestat.st_dev),
+ st_ino: dec_inode(filestat.st_ino),
+ st_filetype: dec_filetype(filestat.st_filetype),
+ st_nlink: dec_linkcount(filestat.st_nlink),
+ st_size: dec_filesize(filestat.st_size),
+ st_atim: dec_timestamp(filestat.st_atim),
+ st_mtim: dec_timestamp(filestat.st_mtim),
+ st_ctim: dec_timestamp(filestat.st_ctim),
+ }
+}
+
+pub fn dec_filestat_byref(
+ vmctx: &Vmctx,
+ filestat_ptr: wasm32::uintptr_t,
+) -> Result<host::__wasi_filestat_t, host::__wasi_errno_t> {
+ dec_pointee::<wasm32::__wasi_filestat_t>(vmctx, filestat_ptr).map(dec_filestat)
+}
+
+pub fn enc_filestat(filestat: host::__wasi_filestat_t) -> wasm32::__wasi_filestat_t {
+ wasm32::__wasi_filestat_t {
+ st_dev: enc_device(filestat.st_dev),
+ st_ino: enc_inode(filestat.st_ino),
+ st_filetype: enc_filetype(filestat.st_filetype),
+ st_nlink: enc_linkcount(filestat.st_nlink),
+ st_size: enc_filesize(filestat.st_size),
+ st_atim: enc_timestamp(filestat.st_atim),
+ st_mtim: enc_timestamp(filestat.st_mtim),
+ st_ctim: enc_timestamp(filestat.st_ctim),
+ }
+}
+
+pub fn enc_filestat_byref(
+ vmctx: &Vmctx,
+ filestat_ptr: wasm32::uintptr_t,
+ host_filestat: host::__wasi_filestat_t,
+) -> Result<(), host::__wasi_errno_t> {
+ let filestat = enc_filestat(host_filestat);
+ enc_pointee::<wasm32::__wasi_filestat_t>(vmctx, filestat_ptr, filestat)
+}
+
+pub fn dec_fdstat(fdstat: wasm32::__wasi_fdstat_t) -> host::__wasi_fdstat_t {
+ host::__wasi_fdstat_t {
+ fs_filetype: dec_filetype(fdstat.fs_filetype),
+ fs_flags: dec_fdflags(fdstat.fs_flags),
+ fs_rights_base: dec_rights(fdstat.fs_rights_base),
+ fs_rights_inheriting: dec_rights(fdstat.fs_rights_inheriting),
+ }
+}
+
+pub fn dec_fdstat_byref(
+ vmctx: &Vmctx,
+ fdstat_ptr: wasm32::uintptr_t,
+) -> Result<host::__wasi_fdstat_t, host::__wasi_errno_t> {
+ dec_pointee::<wasm32::__wasi_fdstat_t>(vmctx, fdstat_ptr).map(dec_fdstat)
+}
+
+pub fn enc_fdstat(fdstat: host::__wasi_fdstat_t) -> wasm32::__wasi_fdstat_t {
+ wasm32::__wasi_fdstat_t {
+ fs_filetype: enc_filetype(fdstat.fs_filetype),
+ fs_flags: enc_fdflags(fdstat.fs_flags),
+ __bindgen_padding_0: 0,
+ fs_rights_base: enc_rights(fdstat.fs_rights_base),
+ fs_rights_inheriting: enc_rights(fdstat.fs_rights_inheriting),
+ }
+}
+
+pub fn enc_fdstat_byref(
+ vmctx: &Vmctx,
+ fdstat_ptr: wasm32::uintptr_t,
+ host_fdstat: host::__wasi_fdstat_t,
+) -> Result<(), host::__wasi_errno_t> {
+ let fdstat = enc_fdstat(host_fdstat);
+ enc_pointee::<wasm32::__wasi_fdstat_t>(vmctx, fdstat_ptr, fdstat)
+}
+
+dec_enc_scalar!(
+ __wasi_filedelta_t,
+ dec_filedelta,
+ dec_filedelta_byref,
+ enc_filedelta,
+ enc_filedelta_byref
+);
+dec_enc_scalar!(
+ __wasi_filesize_t,
+ dec_filesize,
+ dec_filesize_byref,
+ enc_filesize,
+ enc_filesize_byref
+);
+
+dec_enc_scalar!(
+ __wasi_filetype_t,
+ dec_filetype,
+ dec_filetype_byref,
+ enc_filetype,
+ enc_filetype_byref
+);
+
+dec_enc_scalar!(
+ __wasi_lookupflags_t,
+ dec_lookupflags,
+ dec_lookupflags_byref,
+ enc_lookupflags,
+ enc_lookupflags_byref
+);
+
+dec_enc_scalar!(
+ __wasi_oflags_t,
+ dec_oflags,
+ dec_oflags_byref,
+ enc_oflags,
+ enc_oflags_byref
+);
+
+pub fn dec_prestat(
+ prestat: wasm32::__wasi_prestat_t,
+) -> Result<host::__wasi_prestat_t, host::__wasi_errno_t> {
+ match prestat.pr_type {
+ wasm32::__WASI_PREOPENTYPE_DIR => {
+ let u = host::__wasi_prestat_t___wasi_prestat_u {
+ dir: host::__wasi_prestat_t___wasi_prestat_u___wasi_prestat_u_dir_t {
+ pr_name_len: dec_usize(unsafe { prestat.u.dir.pr_name_len }),
+ },
+ };
+ Ok(host::__wasi_prestat_t {
+ pr_type: host::__WASI_PREOPENTYPE_DIR as host::__wasi_preopentype_t,
+ u,
+ })
+ }
+ _ => Err(host::__WASI_EINVAL as host::__wasi_errno_t),
+ }
+}
+
+pub fn dec_prestat_byref(
+ vmctx: &Vmctx,
+ prestat_ptr: wasm32::uintptr_t,
+) -> Result<host::__wasi_prestat_t, host::__wasi_errno_t> {
+ dec_pointee::<wasm32::__wasi_prestat_t>(vmctx, prestat_ptr).and_then(dec_prestat)
+}
+
+pub fn enc_prestat(
+ prestat: host::__wasi_prestat_t,
+) -> Result<wasm32::__wasi_prestat_t, host::__wasi_errno_t> {
+ match u32::from(prestat.pr_type) {
+ host::__WASI_PREOPENTYPE_DIR => {
+ let u = wasm32::__wasi_prestat_t___wasi_prestat_u {
+ dir: wasm32::__wasi_prestat_t___wasi_prestat_u___wasi_prestat_u_dir_t {
+ pr_name_len: enc_usize(unsafe { prestat.u.dir.pr_name_len }),
+ },
+ };
+ Ok(wasm32::__wasi_prestat_t {
+ pr_type: wasm32::__WASI_PREOPENTYPE_DIR as wasm32::__wasi_preopentype_t,
+ u,
+ })
+ }
+ _ => Err(host::__WASI_EINVAL as host::__wasi_errno_t),
+ }
+}
+
+pub fn enc_prestat_byref(
+ vmctx: &Vmctx,
+ prestat_ptr: wasm32::uintptr_t,
+ host_prestat: host::__wasi_prestat_t,
+) -> Result<(), host::__wasi_errno_t> {
+ let prestat = enc_prestat(host_prestat)?;
+ enc_pointee::<wasm32::__wasi_prestat_t>(vmctx, prestat_ptr, prestat)
+}
+
+dec_enc_scalar!(
+ __wasi_rights_t,
+ dec_rights,
+ dec_rights_byref,
+ enc_rights,
+ enc_rights_byref
+);
+
+dec_enc_scalar!(
+ __wasi_timestamp_t,
+ dec_timestamp,
+ dec_timestamp_byref,
+ enc_timestamp,
+ enc_timestamp_byref
+);
+
+pub fn dec_u32(x: u32) -> u32 {
+ u32::from_le(x)
+}
+
+pub fn enc_u32(x: u32) -> u32 {
+ x.to_le()
+}
+
+pub fn dec_usize(size: wasm32::size_t) -> usize {
+ cast::usize(u32::from_le(size))
+}
+
+pub fn enc_usize(size: usize) -> wasm32::size_t {
+ wasm32::size_t::cast(size).unwrap()
+}
+
+pub fn enc_usize_byref(
+ vmctx: &Vmctx,
+ usize_ptr: wasm32::uintptr_t,
+ host_usize: usize,
+) -> Result<(), host::__wasi_errno_t> {
+ enc_pointee::<wasm32::size_t>(vmctx, usize_ptr, enc_usize(host_usize))
+}
+
+dec_enc_scalar!(
+ __wasi_whence_t,
+ dec_whence,
+ dec_whence_byref,
+ enc_whence,
+ enc_whence_byref
+);
+
+dec_enc_scalar!(
+ __wasi_subclockflags_t,
+ dec_subclockflags,
+ dec_subclockflags_byref,
+ enc_subclockflags,
+ enc_subclockflags_byref
+);
+
+dec_enc_scalar!(
+ __wasi_eventrwflags_t,
+ dec_eventrwflags,
+ dec_eventrwflags_byref,
+ enc_eventrwflags,
+ enc_eventrwflags_byref
+);
+
+dec_enc_scalar!(
+ __wasi_eventtype_t,
+ dec_eventtype,
+ dec_eventtype_byref,
+ enc_eventtype,
+ enc_eventtype_byref
+);
+
+dec_enc_scalar!(
+ __wasi_userdata_t,
+ dec_userdata,
+ dec_userdata_byref,
+ enc_userdata,
+ enc_userdata_byref
+);
+
+pub fn dec_subscription(
+ subscription: &wasm32::__wasi_subscription_t,
+) -> Result<host::__wasi_subscription_t, host::__wasi_errno_t> {
+ let userdata = dec_userdata(subscription.userdata);
+ let type_ = dec_eventtype(subscription.type_);
+ let u_orig = subscription.__bindgen_anon_1;
+ let u = match type_ {
+ wasm32::__WASI_EVENTTYPE_CLOCK => host::__wasi_subscription_t___wasi_subscription_u {
+ clock: unsafe {
+ host::__wasi_subscription_t___wasi_subscription_u___wasi_subscription_u_clock_t {
+ identifier: dec_userdata(u_orig.clock.identifier),
+ clock_id: dec_clockid(u_orig.clock.clock_id),
+ timeout: dec_timestamp(u_orig.clock.timeout),
+ precision: dec_timestamp(u_orig.clock.precision),
+ flags: dec_subclockflags(u_orig.clock.flags),
+ }
+ },
+ },
+ wasm32::__WASI_EVENTTYPE_FD_READ | wasm32::__WASI_EVENTTYPE_FD_WRITE => host::__wasi_subscription_t___wasi_subscription_u {
+ fd_readwrite: host::__wasi_subscription_t___wasi_subscription_u___wasi_subscription_u_fd_readwrite_t {
+ fd: dec_fd(unsafe{u_orig.fd_readwrite.fd})
+ }
+ },
+ _ => return Err(wasm32::__WASI_EINVAL)
+ };
+ Ok(host::__wasi_subscription_t { userdata, type_, u })
+}
+
+pub fn enc_event(event: host::__wasi_event_t) -> wasm32::__wasi_event_t {
+ let fd_readwrite = unsafe { event.u.fd_readwrite };
+ wasm32::__wasi_event_t {
+ userdata: enc_userdata(event.userdata),
+ type_: enc_eventtype(event.type_),
+ error: enc_errno(event.error),
+ __bindgen_anon_1: wasm32::__wasi_event_t__bindgen_ty_1 {
+ fd_readwrite: wasm32::__wasi_event_t__bindgen_ty_1__bindgen_ty_1 {
+ nbytes: enc_filesize(fd_readwrite.nbytes),
+ flags: enc_eventrwflags(fd_readwrite.flags),
+ __bindgen_padding_0: [0; 3],
+ },
+ },
+ __bindgen_padding_0: 0,
+ }
+}
+
+dec_enc_scalar!(
+ __wasi_advice_t,
+ dec_advice,
+ dec_advice_byref,
+ enc_advice,
+ enc_advice_byref
+);
+
+dec_enc_scalar!(
+ __wasi_fstflags_t,
+ dec_fstflags,
+ dec_fstflags_byref,
+ enc_fstflags,
+ enc_fstflags_byref
+);
+
+dec_enc_scalar!(
+ __wasi_dircookie_t,
+ dec_dircookie,
+ dec_dircookie_byref,
+ enc_dircookie,
+ enc_dircookie_byref
+);
+
+#[cfg(target_os = "linux")]
+pub fn dirent_from_host(
+ host_entry: &nix::libc::dirent,
+) -> Result<wasm32::__wasi_dirent_t, host::__wasi_errno_t> {
+ let mut entry = unsafe { std::mem::zeroed::<wasm32::__wasi_dirent_t>() };
+ let d_namlen = unsafe { std::ffi::CStr::from_ptr(host_entry.d_name.as_ptr()) }
+ .to_bytes()
+ .len();
+ if d_namlen > u32::max_value() as usize {
+ return Err(host::__WASI_EIO as host::__wasi_errno_t);
+ }
+ entry.d_ino = enc_inode(host_entry.d_ino);
+ entry.d_next = enc_dircookie(host_entry.d_off as u64);
+ entry.d_namlen = enc_u32(d_namlen as u32);
+ entry.d_type = enc_filetype(host_entry.d_type);
+ Ok(entry)
+}
+
+#[cfg(not(target_os = "linux"))]
+pub fn dirent_from_host(
+ host_entry: &nix::libc::dirent,
+) -> Result<wasm32::__wasi_dirent_t, host::__wasi_errno_t> {
+ let mut entry = unsafe { std::mem::zeroed::<wasm32::__wasi_dirent_t>() };
+ entry.d_ino = enc_inode(host_entry.d_ino);
+ entry.d_next = enc_dircookie(host_entry.d_seekoff);
+ entry.d_namlen = enc_u32(u32::from(host_entry.d_namlen));
+ entry.d_type = enc_filetype(host_entry.d_type);
+ Ok(entry)
+}
diff --git a/third_party/rust/lucet-wasi-wasmsbx/src/wasi_host.rs b/third_party/rust/lucet-wasi-wasmsbx/src/wasi_host.rs
new file mode 100644
index 0000000000..08ae163634
--- /dev/null
+++ b/third_party/rust/lucet-wasi-wasmsbx/src/wasi_host.rs
@@ -0,0 +1,1035 @@
+/* automatically generated by rust-bindgen */
+
+pub const __WASI_ADVICE_NORMAL: u32 = 0;
+pub const __WASI_ADVICE_SEQUENTIAL: u32 = 1;
+pub const __WASI_ADVICE_RANDOM: u32 = 2;
+pub const __WASI_ADVICE_WILLNEED: u32 = 3;
+pub const __WASI_ADVICE_DONTNEED: u32 = 4;
+pub const __WASI_ADVICE_NOREUSE: u32 = 5;
+pub const __WASI_CLOCK_REALTIME: u32 = 0;
+pub const __WASI_CLOCK_MONOTONIC: u32 = 1;
+pub const __WASI_CLOCK_PROCESS_CPUTIME_ID: u32 = 2;
+pub const __WASI_CLOCK_THREAD_CPUTIME_ID: u32 = 3;
+pub const __WASI_DIRCOOKIE_START: u32 = 0;
+pub const __WASI_ESUCCESS: u32 = 0;
+pub const __WASI_E2BIG: u32 = 1;
+pub const __WASI_EACCES: u32 = 2;
+pub const __WASI_EADDRINUSE: u32 = 3;
+pub const __WASI_EADDRNOTAVAIL: u32 = 4;
+pub const __WASI_EAFNOSUPPORT: u32 = 5;
+pub const __WASI_EAGAIN: u32 = 6;
+pub const __WASI_EALREADY: u32 = 7;
+pub const __WASI_EBADF: u32 = 8;
+pub const __WASI_EBADMSG: u32 = 9;
+pub const __WASI_EBUSY: u32 = 10;
+pub const __WASI_ECANCELED: u32 = 11;
+pub const __WASI_ECHILD: u32 = 12;
+pub const __WASI_ECONNABORTED: u32 = 13;
+pub const __WASI_ECONNREFUSED: u32 = 14;
+pub const __WASI_ECONNRESET: u32 = 15;
+pub const __WASI_EDEADLK: u32 = 16;
+pub const __WASI_EDESTADDRREQ: u32 = 17;
+pub const __WASI_EDOM: u32 = 18;
+pub const __WASI_EDQUOT: u32 = 19;
+pub const __WASI_EEXIST: u32 = 20;
+pub const __WASI_EFAULT: u32 = 21;
+pub const __WASI_EFBIG: u32 = 22;
+pub const __WASI_EHOSTUNREACH: u32 = 23;
+pub const __WASI_EIDRM: u32 = 24;
+pub const __WASI_EILSEQ: u32 = 25;
+pub const __WASI_EINPROGRESS: u32 = 26;
+pub const __WASI_EINTR: u32 = 27;
+pub const __WASI_EINVAL: u32 = 28;
+pub const __WASI_EIO: u32 = 29;
+pub const __WASI_EISCONN: u32 = 30;
+pub const __WASI_EISDIR: u32 = 31;
+pub const __WASI_ELOOP: u32 = 32;
+pub const __WASI_EMFILE: u32 = 33;
+pub const __WASI_EMLINK: u32 = 34;
+pub const __WASI_EMSGSIZE: u32 = 35;
+pub const __WASI_EMULTIHOP: u32 = 36;
+pub const __WASI_ENAMETOOLONG: u32 = 37;
+pub const __WASI_ENETDOWN: u32 = 38;
+pub const __WASI_ENETRESET: u32 = 39;
+pub const __WASI_ENETUNREACH: u32 = 40;
+pub const __WASI_ENFILE: u32 = 41;
+pub const __WASI_ENOBUFS: u32 = 42;
+pub const __WASI_ENODEV: u32 = 43;
+pub const __WASI_ENOENT: u32 = 44;
+pub const __WASI_ENOEXEC: u32 = 45;
+pub const __WASI_ENOLCK: u32 = 46;
+pub const __WASI_ENOLINK: u32 = 47;
+pub const __WASI_ENOMEM: u32 = 48;
+pub const __WASI_ENOMSG: u32 = 49;
+pub const __WASI_ENOPROTOOPT: u32 = 50;
+pub const __WASI_ENOSPC: u32 = 51;
+pub const __WASI_ENOSYS: u32 = 52;
+pub const __WASI_ENOTCONN: u32 = 53;
+pub const __WASI_ENOTDIR: u32 = 54;
+pub const __WASI_ENOTEMPTY: u32 = 55;
+pub const __WASI_ENOTRECOVERABLE: u32 = 56;
+pub const __WASI_ENOTSOCK: u32 = 57;
+pub const __WASI_ENOTSUP: u32 = 58;
+pub const __WASI_ENOTTY: u32 = 59;
+pub const __WASI_ENXIO: u32 = 60;
+pub const __WASI_EOVERFLOW: u32 = 61;
+pub const __WASI_EOWNERDEAD: u32 = 62;
+pub const __WASI_EPERM: u32 = 63;
+pub const __WASI_EPIPE: u32 = 64;
+pub const __WASI_EPROTO: u32 = 65;
+pub const __WASI_EPROTONOSUPPORT: u32 = 66;
+pub const __WASI_EPROTOTYPE: u32 = 67;
+pub const __WASI_ERANGE: u32 = 68;
+pub const __WASI_EROFS: u32 = 69;
+pub const __WASI_ESPIPE: u32 = 70;
+pub const __WASI_ESRCH: u32 = 71;
+pub const __WASI_ESTALE: u32 = 72;
+pub const __WASI_ETIMEDOUT: u32 = 73;
+pub const __WASI_ETXTBSY: u32 = 74;
+pub const __WASI_EXDEV: u32 = 75;
+pub const __WASI_ENOTCAPABLE: u32 = 76;
+pub const __WASI_EVENT_FD_READWRITE_HANGUP: u32 = 1;
+pub const __WASI_EVENTTYPE_CLOCK: u32 = 0;
+pub const __WASI_EVENTTYPE_FD_READ: u32 = 1;
+pub const __WASI_EVENTTYPE_FD_WRITE: u32 = 2;
+pub const __WASI_FDFLAG_APPEND: u32 = 1;
+pub const __WASI_FDFLAG_DSYNC: u32 = 2;
+pub const __WASI_FDFLAG_NONBLOCK: u32 = 4;
+pub const __WASI_FDFLAG_RSYNC: u32 = 8;
+pub const __WASI_FDFLAG_SYNC: u32 = 16;
+pub const __WASI_FILETYPE_UNKNOWN: u32 = 0;
+pub const __WASI_FILETYPE_BLOCK_DEVICE: u32 = 1;
+pub const __WASI_FILETYPE_CHARACTER_DEVICE: u32 = 2;
+pub const __WASI_FILETYPE_DIRECTORY: u32 = 3;
+pub const __WASI_FILETYPE_REGULAR_FILE: u32 = 4;
+pub const __WASI_FILETYPE_SOCKET_DGRAM: u32 = 5;
+pub const __WASI_FILETYPE_SOCKET_STREAM: u32 = 6;
+pub const __WASI_FILETYPE_SYMBOLIC_LINK: u32 = 7;
+pub const __WASI_FILESTAT_SET_ATIM: u32 = 1;
+pub const __WASI_FILESTAT_SET_ATIM_NOW: u32 = 2;
+pub const __WASI_FILESTAT_SET_MTIM: u32 = 4;
+pub const __WASI_FILESTAT_SET_MTIM_NOW: u32 = 8;
+pub const __WASI_LOOKUP_SYMLINK_FOLLOW: u32 = 1;
+pub const __WASI_O_CREAT: u32 = 1;
+pub const __WASI_O_DIRECTORY: u32 = 2;
+pub const __WASI_O_EXCL: u32 = 4;
+pub const __WASI_O_TRUNC: u32 = 8;
+pub const __WASI_SOCK_RECV_PEEK: u32 = 1;
+pub const __WASI_SOCK_RECV_WAITALL: u32 = 2;
+pub const __WASI_RIGHT_FD_DATASYNC: u32 = 1;
+pub const __WASI_RIGHT_FD_READ: u32 = 2;
+pub const __WASI_RIGHT_FD_SEEK: u32 = 4;
+pub const __WASI_RIGHT_FD_FDSTAT_SET_FLAGS: u32 = 8;
+pub const __WASI_RIGHT_FD_SYNC: u32 = 16;
+pub const __WASI_RIGHT_FD_TELL: u32 = 32;
+pub const __WASI_RIGHT_FD_WRITE: u32 = 64;
+pub const __WASI_RIGHT_FD_ADVISE: u32 = 128;
+pub const __WASI_RIGHT_FD_ALLOCATE: u32 = 256;
+pub const __WASI_RIGHT_PATH_CREATE_DIRECTORY: u32 = 512;
+pub const __WASI_RIGHT_PATH_CREATE_FILE: u32 = 1024;
+pub const __WASI_RIGHT_PATH_LINK_SOURCE: u32 = 2048;
+pub const __WASI_RIGHT_PATH_LINK_TARGET: u32 = 4096;
+pub const __WASI_RIGHT_PATH_OPEN: u32 = 8192;
+pub const __WASI_RIGHT_FD_READDIR: u32 = 16384;
+pub const __WASI_RIGHT_PATH_READLINK: u32 = 32768;
+pub const __WASI_RIGHT_PATH_RENAME_SOURCE: u32 = 65536;
+pub const __WASI_RIGHT_PATH_RENAME_TARGET: u32 = 131072;
+pub const __WASI_RIGHT_PATH_FILESTAT_GET: u32 = 262144;
+pub const __WASI_RIGHT_PATH_FILESTAT_SET_SIZE: u32 = 524288;
+pub const __WASI_RIGHT_PATH_FILESTAT_SET_TIMES: u32 = 1048576;
+pub const __WASI_RIGHT_FD_FILESTAT_GET: u32 = 2097152;
+pub const __WASI_RIGHT_FD_FILESTAT_SET_SIZE: u32 = 4194304;
+pub const __WASI_RIGHT_FD_FILESTAT_SET_TIMES: u32 = 8388608;
+pub const __WASI_RIGHT_PATH_SYMLINK: u32 = 16777216;
+pub const __WASI_RIGHT_PATH_REMOVE_DIRECTORY: u32 = 33554432;
+pub const __WASI_RIGHT_PATH_UNLINK_FILE: u32 = 67108864;
+pub const __WASI_RIGHT_POLL_FD_READWRITE: u32 = 134217728;
+pub const __WASI_RIGHT_SOCK_SHUTDOWN: u32 = 268435456;
+pub const __WASI_SOCK_RECV_DATA_TRUNCATED: u32 = 1;
+pub const __WASI_SHUT_RD: u32 = 1;
+pub const __WASI_SHUT_WR: u32 = 2;
+pub const __WASI_SIGHUP: u32 = 1;
+pub const __WASI_SIGINT: u32 = 2;
+pub const __WASI_SIGQUIT: u32 = 3;
+pub const __WASI_SIGILL: u32 = 4;
+pub const __WASI_SIGTRAP: u32 = 5;
+pub const __WASI_SIGABRT: u32 = 6;
+pub const __WASI_SIGBUS: u32 = 7;
+pub const __WASI_SIGFPE: u32 = 8;
+pub const __WASI_SIGKILL: u32 = 9;
+pub const __WASI_SIGUSR1: u32 = 10;
+pub const __WASI_SIGSEGV: u32 = 11;
+pub const __WASI_SIGUSR2: u32 = 12;
+pub const __WASI_SIGPIPE: u32 = 13;
+pub const __WASI_SIGALRM: u32 = 14;
+pub const __WASI_SIGTERM: u32 = 15;
+pub const __WASI_SIGCHLD: u32 = 16;
+pub const __WASI_SIGCONT: u32 = 17;
+pub const __WASI_SIGSTOP: u32 = 18;
+pub const __WASI_SIGTSTP: u32 = 19;
+pub const __WASI_SIGTTIN: u32 = 20;
+pub const __WASI_SIGTTOU: u32 = 21;
+pub const __WASI_SIGURG: u32 = 22;
+pub const __WASI_SIGXCPU: u32 = 23;
+pub const __WASI_SIGXFSZ: u32 = 24;
+pub const __WASI_SIGVTALRM: u32 = 25;
+pub const __WASI_SIGPROF: u32 = 26;
+pub const __WASI_SIGWINCH: u32 = 27;
+pub const __WASI_SIGPOLL: u32 = 28;
+pub const __WASI_SIGPWR: u32 = 29;
+pub const __WASI_SIGSYS: u32 = 30;
+pub const __WASI_SUBSCRIPTION_CLOCK_ABSTIME: u32 = 1;
+pub const __WASI_WHENCE_CUR: u32 = 0;
+pub const __WASI_WHENCE_END: u32 = 1;
+pub const __WASI_WHENCE_SET: u32 = 2;
+pub const __WASI_PREOPENTYPE_DIR: u32 = 0;
+pub type __wasi_advice_t = u8;
+pub type __wasi_clockid_t = u32;
+pub type __wasi_device_t = u64;
+pub type __wasi_dircookie_t = u64;
+pub type __wasi_errno_t = u16;
+pub type __wasi_eventrwflags_t = u16;
+pub type __wasi_eventtype_t = u8;
+pub type __wasi_exitcode_t = u32;
+pub type __wasi_fd_t = u32;
+pub type __wasi_fdflags_t = u16;
+pub type __wasi_filedelta_t = i64;
+pub type __wasi_filesize_t = u64;
+pub type __wasi_filetype_t = u8;
+pub type __wasi_fstflags_t = u16;
+pub type __wasi_inode_t = u64;
+pub type __wasi_linkcount_t = u32;
+pub type __wasi_lookupflags_t = u32;
+pub type __wasi_oflags_t = u16;
+pub type __wasi_riflags_t = u16;
+pub type __wasi_rights_t = u64;
+pub type __wasi_roflags_t = u16;
+pub type __wasi_sdflags_t = u8;
+pub type __wasi_siflags_t = u16;
+pub type __wasi_signal_t = u8;
+pub type __wasi_subclockflags_t = u16;
+pub type __wasi_timestamp_t = u64;
+pub type __wasi_userdata_t = u64;
+pub type __wasi_whence_t = u8;
+pub type __wasi_preopentype_t = u8;
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct __wasi_dirent_t {
+ pub d_next: __wasi_dircookie_t,
+ pub d_ino: __wasi_inode_t,
+ pub d_namlen: u32,
+ pub d_type: __wasi_filetype_t,
+}
+#[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)
+ )
+ );
+}
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub struct __wasi_event_t {
+ pub userdata: __wasi_userdata_t,
+ pub error: __wasi_errno_t,
+ pub type_: __wasi_eventtype_t,
+ pub u: __wasi_event_t___wasi_event_u,
+}
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub union __wasi_event_t___wasi_event_u {
+ pub fd_readwrite: __wasi_event_t___wasi_event_u___wasi_event_u_fd_readwrite_t,
+ _bindgen_union_align: [u64; 2usize],
+}
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct __wasi_event_t___wasi_event_u___wasi_event_u_fd_readwrite_t {
+ pub nbytes: __wasi_filesize_t,
+ pub flags: __wasi_eventrwflags_t,
+}
+#[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_t___wasi_event_u___wasi_event_u_fd_readwrite_t>(),
+ 16usize,
+ concat!(
+ "Size of: ",
+ stringify!(__wasi_event_t___wasi_event_u___wasi_event_u_fd_readwrite_t)
+ )
+ );
+ assert_eq!(
+ ::std::mem::align_of::<__wasi_event_t___wasi_event_u___wasi_event_u_fd_readwrite_t>(),
+ 8usize,
+ concat!(
+ "Alignment of ",
+ stringify!(__wasi_event_t___wasi_event_u___wasi_event_u_fd_readwrite_t)
+ )
+ );
+ assert_eq!(
+ unsafe {
+ &(*(::std::ptr::null::<__wasi_event_t___wasi_event_u___wasi_event_u_fd_readwrite_t>()))
+ .nbytes as *const _ as usize
+ },
+ 0usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(__wasi_event_t___wasi_event_u___wasi_event_u_fd_readwrite_t),
+ "::",
+ stringify!(nbytes)
+ )
+ );
+ assert_eq!(
+ unsafe {
+ &(*(::std::ptr::null::<__wasi_event_t___wasi_event_u___wasi_event_u_fd_readwrite_t>()))
+ .flags as *const _ as usize
+ },
+ 8usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(__wasi_event_t___wasi_event_u___wasi_event_u_fd_readwrite_t),
+ "::",
+ stringify!(flags)
+ )
+ );
+}
+#[test]
+fn bindgen_test_layout___wasi_event_t___wasi_event_u() {
+ assert_eq!(
+ ::std::mem::size_of::<__wasi_event_t___wasi_event_u>(),
+ 16usize,
+ concat!("Size of: ", stringify!(__wasi_event_t___wasi_event_u))
+ );
+ assert_eq!(
+ ::std::mem::align_of::<__wasi_event_t___wasi_event_u>(),
+ 8usize,
+ concat!("Alignment of ", stringify!(__wasi_event_t___wasi_event_u))
+ );
+ assert_eq!(
+ unsafe {
+ &(*(::std::ptr::null::<__wasi_event_t___wasi_event_u>())).fd_readwrite as *const _
+ as usize
+ },
+ 0usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(__wasi_event_t___wasi_event_u),
+ "::",
+ 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>())).type_ as *const _ as usize },
+ 10usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(__wasi_event_t),
+ "::",
+ stringify!(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)
+ )
+ );
+}
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub struct __wasi_prestat_t {
+ pub pr_type: __wasi_preopentype_t,
+ pub u: __wasi_prestat_t___wasi_prestat_u,
+}
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub union __wasi_prestat_t___wasi_prestat_u {
+ pub dir: __wasi_prestat_t___wasi_prestat_u___wasi_prestat_u_dir_t,
+ _bindgen_union_align: u64,
+}
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct __wasi_prestat_t___wasi_prestat_u___wasi_prestat_u_dir_t {
+ pub pr_name_len: usize,
+}
+#[test]
+fn bindgen_test_layout___wasi_prestat_t___wasi_prestat_u___wasi_prestat_u_dir_t() {
+ assert_eq!(
+ ::std::mem::size_of::<__wasi_prestat_t___wasi_prestat_u___wasi_prestat_u_dir_t>(),
+ 8usize,
+ concat!(
+ "Size of: ",
+ stringify!(__wasi_prestat_t___wasi_prestat_u___wasi_prestat_u_dir_t)
+ )
+ );
+ assert_eq!(
+ ::std::mem::align_of::<__wasi_prestat_t___wasi_prestat_u___wasi_prestat_u_dir_t>(),
+ 8usize,
+ concat!(
+ "Alignment of ",
+ stringify!(__wasi_prestat_t___wasi_prestat_u___wasi_prestat_u_dir_t)
+ )
+ );
+ assert_eq!(
+ unsafe {
+ &(*(::std::ptr::null::<__wasi_prestat_t___wasi_prestat_u___wasi_prestat_u_dir_t>()))
+ .pr_name_len as *const _ as usize
+ },
+ 0usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(__wasi_prestat_t___wasi_prestat_u___wasi_prestat_u_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_t___wasi_prestat_u>(),
+ 8usize,
+ concat!("Size of: ", stringify!(__wasi_prestat_t___wasi_prestat_u))
+ );
+ assert_eq!(
+ ::std::mem::align_of::<__wasi_prestat_t___wasi_prestat_u>(),
+ 8usize,
+ concat!(
+ "Alignment of ",
+ stringify!(__wasi_prestat_t___wasi_prestat_u)
+ )
+ );
+ assert_eq!(
+ unsafe {
+ &(*(::std::ptr::null::<__wasi_prestat_t___wasi_prestat_u>())).dir as *const _ as usize
+ },
+ 0usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(__wasi_prestat_t___wasi_prestat_u),
+ "::",
+ stringify!(dir)
+ )
+ );
+}
+#[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)
+ )
+ );
+}
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct __wasi_fdstat_t {
+ pub fs_filetype: __wasi_filetype_t,
+ pub fs_flags: __wasi_fdflags_t,
+ pub fs_rights_base: __wasi_rights_t,
+ pub fs_rights_inheriting: __wasi_rights_t,
+}
+#[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)
+ )
+ );
+}
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct __wasi_filestat_t {
+ pub st_dev: __wasi_device_t,
+ pub st_ino: __wasi_inode_t,
+ pub st_filetype: __wasi_filetype_t,
+ pub st_nlink: __wasi_linkcount_t,
+ pub st_size: __wasi_filesize_t,
+ pub st_atim: __wasi_timestamp_t,
+ pub st_mtim: __wasi_timestamp_t,
+ pub st_ctim: __wasi_timestamp_t,
+}
+#[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>())).st_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>())).st_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>())).st_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>())).st_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>())).st_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>())).st_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>())).st_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>())).st_ctim as *const _ as usize },
+ 48usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(__wasi_filestat_t),
+ "::",
+ stringify!(st_ctim)
+ )
+ );
+}
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct __wasi_ciovec_t {
+ pub buf: *const ::std::os::raw::c_void,
+ pub buf_len: usize,
+}
+#[test]
+fn bindgen_test_layout___wasi_ciovec_t() {
+ assert_eq!(
+ ::std::mem::size_of::<__wasi_ciovec_t>(),
+ 16usize,
+ concat!("Size of: ", stringify!(__wasi_ciovec_t))
+ );
+ assert_eq!(
+ ::std::mem::align_of::<__wasi_ciovec_t>(),
+ 8usize,
+ 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 },
+ 8usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(__wasi_ciovec_t),
+ "::",
+ stringify!(buf_len)
+ )
+ );
+}
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct __wasi_iovec_t {
+ pub buf: *mut ::std::os::raw::c_void,
+ pub buf_len: usize,
+}
+#[test]
+fn bindgen_test_layout___wasi_iovec_t() {
+ assert_eq!(
+ ::std::mem::size_of::<__wasi_iovec_t>(),
+ 16usize,
+ concat!("Size of: ", stringify!(__wasi_iovec_t))
+ );
+ assert_eq!(
+ ::std::mem::align_of::<__wasi_iovec_t>(),
+ 8usize,
+ 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 },
+ 8usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(__wasi_iovec_t),
+ "::",
+ stringify!(buf_len)
+ )
+ );
+}
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub struct __wasi_subscription_t {
+ pub userdata: __wasi_userdata_t,
+ pub type_: __wasi_eventtype_t,
+ pub u: __wasi_subscription_t___wasi_subscription_u,
+}
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub union __wasi_subscription_t___wasi_subscription_u {
+ pub clock: __wasi_subscription_t___wasi_subscription_u___wasi_subscription_u_clock_t,
+ pub fd_readwrite:
+ __wasi_subscription_t___wasi_subscription_u___wasi_subscription_u_fd_readwrite_t,
+ _bindgen_union_align: [u64; 5usize],
+}
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct __wasi_subscription_t___wasi_subscription_u___wasi_subscription_u_clock_t {
+ pub identifier: __wasi_userdata_t,
+ pub clock_id: __wasi_clockid_t,
+ pub timeout: __wasi_timestamp_t,
+ pub precision: __wasi_timestamp_t,
+ pub flags: __wasi_subclockflags_t,
+}
+#[test]
+fn bindgen_test_layout___wasi_subscription_t___wasi_subscription_u___wasi_subscription_u_clock_t() {
+ assert_eq!(
+ ::std::mem::size_of::<
+ __wasi_subscription_t___wasi_subscription_u___wasi_subscription_u_clock_t,
+ >(),
+ 40usize,
+ concat!(
+ "Size of: ",
+ stringify!(__wasi_subscription_t___wasi_subscription_u___wasi_subscription_u_clock_t)
+ )
+ );
+ assert_eq!(
+ ::std::mem::align_of::<
+ __wasi_subscription_t___wasi_subscription_u___wasi_subscription_u_clock_t,
+ >(),
+ 8usize,
+ concat!(
+ "Alignment of ",
+ stringify!(__wasi_subscription_t___wasi_subscription_u___wasi_subscription_u_clock_t)
+ )
+ );
+ assert_eq!(
+ unsafe {
+ &(*(::std::ptr::null::<
+ __wasi_subscription_t___wasi_subscription_u___wasi_subscription_u_clock_t,
+ >()))
+ .identifier as *const _ as usize
+ },
+ 0usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(__wasi_subscription_t___wasi_subscription_u___wasi_subscription_u_clock_t),
+ "::",
+ stringify!(identifier)
+ )
+ );
+ assert_eq!(
+ unsafe {
+ &(*(::std::ptr::null::<
+ __wasi_subscription_t___wasi_subscription_u___wasi_subscription_u_clock_t,
+ >()))
+ .clock_id as *const _ as usize
+ },
+ 8usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(__wasi_subscription_t___wasi_subscription_u___wasi_subscription_u_clock_t),
+ "::",
+ stringify!(clock_id)
+ )
+ );
+ assert_eq!(
+ unsafe {
+ &(*(::std::ptr::null::<
+ __wasi_subscription_t___wasi_subscription_u___wasi_subscription_u_clock_t,
+ >()))
+ .timeout as *const _ as usize
+ },
+ 16usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(__wasi_subscription_t___wasi_subscription_u___wasi_subscription_u_clock_t),
+ "::",
+ stringify!(timeout)
+ )
+ );
+ assert_eq!(
+ unsafe {
+ &(*(::std::ptr::null::<
+ __wasi_subscription_t___wasi_subscription_u___wasi_subscription_u_clock_t,
+ >()))
+ .precision as *const _ as usize
+ },
+ 24usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(__wasi_subscription_t___wasi_subscription_u___wasi_subscription_u_clock_t),
+ "::",
+ stringify!(precision)
+ )
+ );
+ assert_eq!(
+ unsafe {
+ &(*(::std::ptr::null::<
+ __wasi_subscription_t___wasi_subscription_u___wasi_subscription_u_clock_t,
+ >()))
+ .flags as *const _ as usize
+ },
+ 32usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(__wasi_subscription_t___wasi_subscription_u___wasi_subscription_u_clock_t),
+ "::",
+ stringify!(flags)
+ )
+ );
+}
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct __wasi_subscription_t___wasi_subscription_u___wasi_subscription_u_fd_readwrite_t {
+ pub fd: __wasi_fd_t,
+}
+#[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_t___wasi_subscription_u___wasi_subscription_u_fd_readwrite_t,
+ >(),
+ 4usize,
+ concat!(
+ "Size of: ",
+ stringify!(
+ __wasi_subscription_t___wasi_subscription_u___wasi_subscription_u_fd_readwrite_t
+ )
+ )
+ );
+ assert_eq!(
+ ::std::mem::align_of::<
+ __wasi_subscription_t___wasi_subscription_u___wasi_subscription_u_fd_readwrite_t,
+ >(),
+ 4usize,
+ concat!(
+ "Alignment of ",
+ stringify!(
+ __wasi_subscription_t___wasi_subscription_u___wasi_subscription_u_fd_readwrite_t
+ )
+ )
+ );
+ assert_eq!(
+ unsafe {
+ &(*(::std::ptr::null::<
+ __wasi_subscription_t___wasi_subscription_u___wasi_subscription_u_fd_readwrite_t,
+ >()))
+ .fd as *const _ as usize
+ },
+ 0usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(
+ __wasi_subscription_t___wasi_subscription_u___wasi_subscription_u_fd_readwrite_t
+ ),
+ "::",
+ stringify!(fd)
+ )
+ );
+}
+#[test]
+fn bindgen_test_layout___wasi_subscription_t___wasi_subscription_u() {
+ assert_eq!(
+ ::std::mem::size_of::<__wasi_subscription_t___wasi_subscription_u>(),
+ 40usize,
+ concat!(
+ "Size of: ",
+ stringify!(__wasi_subscription_t___wasi_subscription_u)
+ )
+ );
+ assert_eq!(
+ ::std::mem::align_of::<__wasi_subscription_t___wasi_subscription_u>(),
+ 8usize,
+ concat!(
+ "Alignment of ",
+ stringify!(__wasi_subscription_t___wasi_subscription_u)
+ )
+ );
+ assert_eq!(
+ unsafe {
+ &(*(::std::ptr::null::<__wasi_subscription_t___wasi_subscription_u>())).clock
+ as *const _ as usize
+ },
+ 0usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(__wasi_subscription_t___wasi_subscription_u),
+ "::",
+ stringify!(clock)
+ )
+ );
+ assert_eq!(
+ unsafe {
+ &(*(::std::ptr::null::<__wasi_subscription_t___wasi_subscription_u>())).fd_readwrite
+ as *const _ as usize
+ },
+ 0usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(__wasi_subscription_t___wasi_subscription_u),
+ "::",
+ 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>())).type_ as *const _ as usize },
+ 8usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(__wasi_subscription_t),
+ "::",
+ stringify!(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)
+ )
+ );
+}
diff --git a/third_party/rust/lucet-wasi-wasmsbx/src/wasm32.rs b/third_party/rust/lucet-wasi-wasmsbx/src/wasm32.rs
new file mode 100644
index 0000000000..9983b37907
--- /dev/null
+++ b/third_party/rust/lucet-wasi-wasmsbx/src/wasm32.rs
@@ -0,0 +1,1367 @@
+//! WASI types as defined in wasm32. This file was originally generated
+//! by running bindgen over wasi/core.h with a wasm32 target, and the content
+//! still largely reflects that, however it's been heavily modified, to
+//! be host-independent, to avoid exposing libc implementation details,
+//! to clean up cases where the headers use complex preprocessor macros,
+//! and to
+
+#![allow(non_camel_case_types)]
+#![allow(non_snake_case)]
+#![allow(dead_code)]
+
+// C types
+pub type char = i8;
+pub type schar = i8;
+pub type uchar = u8;
+pub type short = i16;
+pub type ushort = u16;
+pub type int = i32;
+pub type uint = u32;
+pub type long = i32;
+pub type ulong = u32;
+pub type longlong = i64;
+pub type ulonglong = u64;
+
+// libc stdint types
+pub type int8_t = i8;
+pub type uint8_t = u8;
+pub type int16_t = i16;
+pub type uint16_t = u16;
+pub type int32_t = i32;
+pub type uint32_t = u32;
+pub type int64_t = i64;
+pub type uint64_t = u64;
+pub type intmax_t = i64;
+pub type uintmax_t = u64;
+pub type int_least8_t = i8;
+pub type int_least16_t = i16;
+pub type int_least32_t = i32;
+pub type int_least64_t = i64;
+pub type uint_least8_t = u8;
+pub type uint_least16_t = u16;
+pub type uint_least32_t = u32;
+pub type uint_least64_t = u64;
+pub type int_fast8_t = i8;
+pub type int_fast16_t = i32;
+pub type int_fast32_t = i32;
+pub type int_fast64_t = i64;
+pub type uint_fast8_t = u8;
+pub type uint_fast16_t = u32;
+pub type uint_fast32_t = u32;
+pub type uint_fast64_t = u64;
+pub type size_t = ulong;
+pub type intptr_t = long;
+pub type uintptr_t = ulong;
+pub type wchar_t = i32;
+
+// libc types
+pub type dev_t = u64;
+pub type uid_t = u32;
+pub type gid_t = u32;
+pub type ino_t = u64;
+pub type ino64_t = u64;
+pub type mode_t = u32;
+pub type nlink_t = u64;
+pub type off_t = i64;
+pub type off64_t = i64;
+pub type pid_t = i32;
+pub type clock_t = i64;
+pub type rlim_t = u64;
+pub type rlim64_t = u64;
+pub type id_t = u32;
+pub type time_t = i64;
+pub type useconds_t = u32;
+pub type suseconds_t = i64;
+pub type daddr_t = i32;
+pub type key_t = i32;
+pub type clockid_t = i32;
+pub type timer_t = uintptr_t; // *mut ::std::os::raw::c_void
+pub type blksize_t = i64;
+pub type blkcnt_t = i64;
+pub type blkcnt64_t = i64;
+pub type fsblkcnt_t = u64;
+pub type fsblkcnt64_t = u64;
+pub type fsfilcnt_t = u64;
+pub type fsfilcnt64_t = u64;
+pub type fsword_t = i64;
+pub type ssize_t = i32;
+pub type loff_t = off64_t;
+pub type caddr_t = uintptr_t; // *mut i8
+pub type socklen_t = u32;
+pub type sig_atomic_t = i32;
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct fsid_t {
+ pub __val: [i32; 2usize],
+}
+#[allow(non_snake_case)]
+#[test]
+fn bindgen_test_layout_fsid_t() {
+ assert_eq!(
+ ::std::mem::size_of::<fsid_t>(),
+ 8usize,
+ concat!("Size of: ", stringify!(fsid_t))
+ );
+ assert_eq!(
+ ::std::mem::align_of::<fsid_t>(),
+ 4usize,
+ concat!("Alignment of ", stringify!(fsid_t))
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<fsid_t>())).__val as *const _ as usize },
+ 0usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(fsid_t),
+ "::",
+ stringify!(__val)
+ )
+ );
+}
+
+// WASI types
+pub type __wasi_advice_t = u8;
+pub type __wasi_clockid_t = u32;
+pub type __wasi_device_t = u64;
+pub type __wasi_dircookie_t = u64;
+pub type __wasi_errno_t = u16;
+pub type __wasi_eventrwflags_t = u16;
+pub type __wasi_eventtype_t = u8;
+pub type __wasi_exitcode_t = u32;
+pub type __wasi_fd_t = u32;
+pub type __wasi_fdflags_t = u16;
+pub type __wasi_fdsflags_t = u16;
+pub type __wasi_filedelta_t = i64;
+pub type __wasi_filesize_t = u64;
+pub type __wasi_filetype_t = u8;
+pub type __wasi_preopentype_t = u8;
+pub type __wasi_fstflags_t = u16;
+pub type __wasi_inode_t = u64;
+pub type __wasi_linkcount_t = u32;
+pub type __wasi_lookupflags_t = u32;
+pub type __wasi_oflags_t = u16;
+pub type __wasi_riflags_t = u16;
+pub type __wasi_rights_t = u64;
+pub type __wasi_roflags_t = u16;
+pub type __wasi_sdflags_t = u8;
+pub type __wasi_siflags_t = u16;
+pub type __wasi_signal_t = u8;
+pub type __wasi_subclockflags_t = u16;
+pub type __wasi_timestamp_t = u64;
+pub type __wasi_userdata_t = u64;
+pub type __wasi_whence_t = u8;
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct __wasi_dirent_t {
+ pub d_next: __wasi_dircookie_t,
+ pub d_ino: __wasi_inode_t,
+ pub d_namlen: u32,
+ pub d_type: __wasi_filetype_t,
+ pub __bindgen_padding_0: [u8; 3usize],
+}
+#[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)
+ )
+ );
+}
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub struct __wasi_event_t {
+ pub userdata: __wasi_userdata_t,
+ pub error: __wasi_errno_t,
+ pub type_: __wasi_eventtype_t,
+ pub __bindgen_padding_0: u32,
+ pub __bindgen_anon_1: __wasi_event_t__bindgen_ty_1,
+}
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub struct __wasi_prestat_t {
+ pub pr_type: __wasi_preopentype_t,
+ pub u: __wasi_prestat_t___wasi_prestat_u,
+}
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub union __wasi_prestat_t___wasi_prestat_u {
+ pub dir: __wasi_prestat_t___wasi_prestat_u___wasi_prestat_u_dir_t,
+}
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct __wasi_prestat_t___wasi_prestat_u___wasi_prestat_u_dir_t {
+ pub pr_name_len: size_t,
+}
+#[test]
+fn bindgen_test_layout___wasi_prestat_t___wasi_prestat_u___wasi_prestat_u_dir_t() {
+ assert_eq!(
+ ::std::mem::size_of::<__wasi_prestat_t___wasi_prestat_u___wasi_prestat_u_dir_t>(),
+ 4usize,
+ concat!(
+ "Size of: ",
+ stringify!(__wasi_prestat_t___wasi_prestat_u___wasi_prestat_u_dir_t)
+ )
+ );
+ assert_eq!(
+ ::std::mem::align_of::<__wasi_prestat_t___wasi_prestat_u___wasi_prestat_u_dir_t>(),
+ 4usize,
+ concat!(
+ "Alignment of ",
+ stringify!(__wasi_prestat_t___wasi_prestat_u___wasi_prestat_u_dir_t)
+ )
+ );
+ assert_eq!(
+ unsafe {
+ &(*(::std::ptr::null::<__wasi_prestat_t___wasi_prestat_u___wasi_prestat_u_dir_t>()))
+ .pr_name_len as *const _ as usize
+ },
+ 0usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(__wasi_prestat_t___wasi_prestat_u___wasi_prestat_u_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_t___wasi_prestat_u>(),
+ 4usize,
+ concat!("Size of: ", stringify!(__wasi_prestat_t___wasi_prestat_u))
+ );
+ assert_eq!(
+ ::std::mem::align_of::<__wasi_prestat_t___wasi_prestat_u>(),
+ 4usize,
+ concat!(
+ "Alignment of ",
+ stringify!(__wasi_prestat_t___wasi_prestat_u)
+ )
+ );
+ assert_eq!(
+ unsafe {
+ &(*(::std::ptr::null::<__wasi_prestat_t___wasi_prestat_u>())).dir as *const _ as usize
+ },
+ 0usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(__wasi_prestat_t___wasi_prestat_u),
+ "::",
+ 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)
+ )
+ );
+}
+#[allow(non_snake_case)]
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub union __wasi_event_t__bindgen_ty_1 {
+ pub fd_readwrite: __wasi_event_t__bindgen_ty_1__bindgen_ty_1,
+ _bindgen_union_align: [u64; 2usize],
+}
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct __wasi_event_t__bindgen_ty_1__bindgen_ty_1 {
+ pub nbytes: __wasi_filesize_t,
+ pub flags: __wasi_eventrwflags_t,
+ pub __bindgen_padding_0: [u16; 3usize],
+}
+#[allow(non_snake_case)]
+#[test]
+fn bindgen_test_layout_wasi_event_t__bindgen_ty_1__bindgen_ty_1() {
+ assert_eq!(
+ ::std::mem::size_of::<__wasi_event_t__bindgen_ty_1__bindgen_ty_1>(),
+ 16usize,
+ concat!(
+ "Size of: ",
+ stringify!(__wasi_event_t__bindgen_ty_1__bindgen_ty_1)
+ )
+ );
+ assert_eq!(
+ unsafe {
+ &(*(::std::ptr::null::<__wasi_event_t__bindgen_ty_1__bindgen_ty_1>())).nbytes
+ as *const _ as usize
+ },
+ 0usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(__wasi_event_t__bindgen_ty_1__bindgen_ty_1),
+ "::",
+ stringify!(nbytes)
+ )
+ );
+ assert_eq!(
+ unsafe {
+ &(*(::std::ptr::null::<__wasi_event_t__bindgen_ty_1__bindgen_ty_1>())).flags as *const _
+ as usize
+ },
+ 8usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(__wasi_event_t__bindgen_ty_1__bindgen_ty_1),
+ "::",
+ stringify!(flags)
+ )
+ );
+}
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct __wasi_event_t__bindgen_ty_1__bindgen_ty_2 {
+ pub signal: __wasi_signal_t,
+ pub exitcode: __wasi_exitcode_t,
+}
+#[allow(non_snake_case)]
+#[test]
+fn bindgen_test_layout_wasi_event_t__bindgen_ty_1__bindgen_ty_2() {
+ assert_eq!(
+ ::std::mem::size_of::<__wasi_event_t__bindgen_ty_1__bindgen_ty_2>(),
+ 8usize,
+ concat!(
+ "Size of: ",
+ stringify!(__wasi_event_t__bindgen_ty_1__bindgen_ty_2)
+ )
+ );
+ assert_eq!(
+ ::std::mem::align_of::<__wasi_event_t__bindgen_ty_1__bindgen_ty_2>(),
+ 4usize,
+ concat!(
+ "Alignment of ",
+ stringify!(__wasi_event_t__bindgen_ty_1__bindgen_ty_2)
+ )
+ );
+ assert_eq!(
+ unsafe {
+ &(*(::std::ptr::null::<__wasi_event_t__bindgen_ty_1__bindgen_ty_2>())).signal
+ as *const _ as usize
+ },
+ 0usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(__wasi_event_t__bindgen_ty_1__bindgen_ty_2),
+ "::",
+ stringify!(signal)
+ )
+ );
+ assert_eq!(
+ unsafe {
+ &(*(::std::ptr::null::<__wasi_event_t__bindgen_ty_1__bindgen_ty_2>())).exitcode
+ as *const _ as usize
+ },
+ 4usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(__wasi_event_t__bindgen_ty_1__bindgen_ty_2),
+ "::",
+ stringify!(exitcode)
+ )
+ );
+}
+#[allow(non_snake_case)]
+#[test]
+fn bindgen_test_layout_wasi_event_t__bindgen_ty_1() {
+ assert_eq!(
+ ::std::mem::size_of::<__wasi_event_t__bindgen_ty_1>(),
+ 16usize,
+ concat!("Size of: ", stringify!(__wasi_event_t__bindgen_ty_1))
+ );
+ assert_eq!(
+ unsafe {
+ &(*(::std::ptr::null::<__wasi_event_t__bindgen_ty_1>())).fd_readwrite as *const _
+ as usize
+ },
+ 0usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(__wasi_event_t__bindgen_ty_1),
+ "::",
+ 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!(
+ 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>())).type_ as *const _ as usize },
+ 10usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(__wasi_event_t),
+ "::",
+ stringify!(type_)
+ )
+ );
+}
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct __wasi_fdstat_t {
+ pub fs_filetype: __wasi_filetype_t,
+ pub fs_flags: __wasi_fdflags_t,
+ pub __bindgen_padding_0: u32,
+ pub fs_rights_base: __wasi_rights_t,
+ pub fs_rights_inheriting: __wasi_rights_t,
+}
+#[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)
+ )
+ );
+}
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct __wasi_filestat_t {
+ pub st_dev: __wasi_device_t,
+ pub st_ino: __wasi_inode_t,
+ pub st_filetype: __wasi_filetype_t,
+ pub st_nlink: __wasi_linkcount_t,
+ pub st_size: __wasi_filesize_t,
+ pub st_atim: __wasi_timestamp_t,
+ pub st_mtim: __wasi_timestamp_t,
+ pub st_ctim: __wasi_timestamp_t,
+}
+#[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>())).st_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>())).st_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>())).st_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>())).st_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>())).st_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>())).st_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>())).st_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>())).st_ctim as *const _ as usize },
+ 48usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(__wasi_filestat_t),
+ "::",
+ stringify!(st_ctim)
+ )
+ );
+}
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct __wasi_ciovec_t {
+ pub buf: uintptr_t, // *const ::std::os::raw::c_void
+ pub buf_len: size_t,
+}
+#[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)
+ )
+ );
+}
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct __wasi_iovec_t {
+ pub buf: uintptr_t, // *mut ::std::os::raw::c_void
+ pub buf_len: size_t,
+}
+#[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)
+ )
+ );
+}
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub struct __wasi_subscription_t {
+ pub userdata: __wasi_userdata_t,
+ pub type_: __wasi_eventtype_t,
+ pub __bindgen_padding_0: u32,
+ pub __bindgen_anon_1: __wasi_subscription_t__bindgen_ty_1,
+}
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub union __wasi_subscription_t__bindgen_ty_1 {
+ pub clock: __wasi_subscription_t__bindgen_ty_1__bindgen_ty_1,
+ pub fd_readwrite: __wasi_subscription_t__bindgen_ty_1__bindgen_ty_3,
+ _bindgen_union_align: [u64; 5usize],
+}
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct __wasi_subscription_t__bindgen_ty_1__bindgen_ty_1 {
+ pub identifier: __wasi_userdata_t,
+ pub clock_id: __wasi_clockid_t,
+ pub __bindgen_padding_0: u32,
+ pub timeout: __wasi_timestamp_t,
+ pub precision: __wasi_timestamp_t,
+ pub flags: __wasi_subclockflags_t,
+ pub __bindgen_padding_1: [u16; 3usize],
+}
+#[allow(non_snake_case)]
+#[test]
+fn bindgen_test_layout_wasi_subscription_t__bindgen_ty_1__bindgen_ty_1() {
+ assert_eq!(
+ ::std::mem::size_of::<__wasi_subscription_t__bindgen_ty_1__bindgen_ty_1>(),
+ 40usize,
+ concat!(
+ "Size of: ",
+ stringify!(__wasi_subscription_t__bindgen_ty_1__bindgen_ty_1)
+ )
+ );
+ assert_eq!(
+ unsafe {
+ &(*(::std::ptr::null::<__wasi_subscription_t__bindgen_ty_1__bindgen_ty_1>())).identifier
+ as *const _ as usize
+ },
+ 0usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(__wasi_subscription_t__bindgen_ty_1__bindgen_ty_1),
+ "::",
+ stringify!(identifier)
+ )
+ );
+ assert_eq!(
+ unsafe {
+ &(*(::std::ptr::null::<__wasi_subscription_t__bindgen_ty_1__bindgen_ty_1>())).clock_id
+ as *const _ as usize
+ },
+ 8usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(__wasi_subscription_t__bindgen_ty_1__bindgen_ty_1),
+ "::",
+ stringify!(clock_id)
+ )
+ );
+ assert_eq!(
+ unsafe {
+ &(*(::std::ptr::null::<__wasi_subscription_t__bindgen_ty_1__bindgen_ty_1>())).timeout
+ as *const _ as usize
+ },
+ 16usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(__wasi_subscription_t__bindgen_ty_1__bindgen_ty_1),
+ "::",
+ stringify!(timeout)
+ )
+ );
+ assert_eq!(
+ unsafe {
+ &(*(::std::ptr::null::<__wasi_subscription_t__bindgen_ty_1__bindgen_ty_1>())).precision
+ as *const _ as usize
+ },
+ 24usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(__wasi_subscription_t__bindgen_ty_1__bindgen_ty_1),
+ "::",
+ stringify!(precision)
+ )
+ );
+ assert_eq!(
+ unsafe {
+ &(*(::std::ptr::null::<__wasi_subscription_t__bindgen_ty_1__bindgen_ty_1>())).flags
+ as *const _ as usize
+ },
+ 32usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(__wasi_subscription_t__bindgen_ty_1__bindgen_ty_1),
+ "::",
+ stringify!(flags)
+ )
+ );
+}
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct __wasi_subscription_t__bindgen_ty_1__bindgen_ty_3 {
+ pub fd: __wasi_fd_t,
+}
+#[allow(non_snake_case)]
+#[test]
+fn bindgen_test_layout_wasi_subscription_t__bindgen_ty_1__bindgen_ty_3() {
+ assert_eq!(
+ ::std::mem::size_of::<__wasi_subscription_t__bindgen_ty_1__bindgen_ty_3>(),
+ 4usize,
+ concat!(
+ "Size of: ",
+ stringify!(__wasi_subscription_t__bindgen_ty_1__bindgen_ty_3)
+ )
+ );
+ assert_eq!(
+ ::std::mem::align_of::<__wasi_subscription_t__bindgen_ty_1__bindgen_ty_3>(),
+ 4usize,
+ concat!(
+ "Alignment of ",
+ stringify!(__wasi_subscription_t__bindgen_ty_1__bindgen_ty_3)
+ )
+ );
+ assert_eq!(
+ unsafe {
+ &(*(::std::ptr::null::<__wasi_subscription_t__bindgen_ty_1__bindgen_ty_3>())).fd
+ as *const _ as usize
+ },
+ 0usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(__wasi_subscription_t__bindgen_ty_1__bindgen_ty_3),
+ "::",
+ stringify!(fd)
+ )
+ );
+}
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct __wasi_subscription_t__bindgen_ty_1__bindgen_ty_5 {
+ pub fd: __wasi_fd_t,
+}
+#[allow(non_snake_case)]
+#[test]
+fn bindgen_test_layout_wasi_subscription_t__bindgen_ty_1__bindgen_ty_5() {
+ assert_eq!(
+ ::std::mem::size_of::<__wasi_subscription_t__bindgen_ty_1__bindgen_ty_5>(),
+ 4usize,
+ concat!(
+ "Size of: ",
+ stringify!(__wasi_subscription_t__bindgen_ty_1__bindgen_ty_5)
+ )
+ );
+ assert_eq!(
+ ::std::mem::align_of::<__wasi_subscription_t__bindgen_ty_1__bindgen_ty_5>(),
+ 4usize,
+ concat!(
+ "Alignment of ",
+ stringify!(__wasi_subscription_t__bindgen_ty_1__bindgen_ty_5)
+ )
+ );
+ assert_eq!(
+ unsafe {
+ &(*(::std::ptr::null::<__wasi_subscription_t__bindgen_ty_1__bindgen_ty_5>())).fd
+ as *const _ as usize
+ },
+ 0usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(__wasi_subscription_t__bindgen_ty_1__bindgen_ty_5),
+ "::",
+ stringify!(fd)
+ )
+ );
+}
+#[allow(non_snake_case)]
+#[test]
+fn bindgen_test_layout_wasi_subscription_t__bindgen_ty_1() {
+ assert_eq!(
+ ::std::mem::size_of::<__wasi_subscription_t__bindgen_ty_1>(),
+ 40usize,
+ concat!("Size of: ", stringify!(__wasi_subscription_t__bindgen_ty_1))
+ );
+ assert_eq!(
+ unsafe {
+ &(*(::std::ptr::null::<__wasi_subscription_t__bindgen_ty_1>())).clock as *const _
+ as usize
+ },
+ 0usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(__wasi_subscription_t__bindgen_ty_1),
+ "::",
+ stringify!(clock)
+ )
+ );
+ assert_eq!(
+ unsafe {
+ &(*(::std::ptr::null::<__wasi_subscription_t__bindgen_ty_1>())).fd_readwrite as *const _
+ as usize
+ },
+ 0usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(__wasi_subscription_t__bindgen_ty_1),
+ "::",
+ stringify!(fd_readwrite)
+ )
+ );
+}
+#[allow(non_snake_case)]
+#[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!(
+ 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>())).type_ as *const _ as usize },
+ 8usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(__wasi_subscription_t),
+ "::",
+ stringify!(type_)
+ )
+ );
+}
+
+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",
+ 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),
+ }
+}
+
+// libc constants
+pub const INT8_MIN: i32 = -128;
+pub const INT16_MIN: i32 = -32768;
+pub const INT32_MIN: i32 = -2147483648;
+pub const INT8_MAX: u32 = 127;
+pub const INT16_MAX: u32 = 32767;
+pub const INT32_MAX: u32 = 2147483647;
+pub const UINT8_MAX: u32 = 255;
+pub const UINT16_MAX: u32 = 65535;
+pub const UINT32_MAX: u32 = 4294967295;
+pub const INT_LEAST8_MIN: i32 = -128;
+pub const INT_LEAST16_MIN: i32 = -32768;
+pub const INT_LEAST32_MIN: i32 = -2147483648;
+pub const INT_LEAST8_MAX: u32 = 127;
+pub const INT_LEAST16_MAX: u32 = 32767;
+pub const INT_LEAST32_MAX: u32 = 2147483647;
+pub const UINT_LEAST8_MAX: u32 = 255;
+pub const UINT_LEAST16_MAX: u32 = 65535;
+pub const UINT_LEAST32_MAX: u32 = 4294967295;
+pub const INT_FAST8_MIN: i32 = -128;
+pub const INT_FAST16_MIN: i32 = -2147483648;
+pub const INT_FAST32_MIN: i32 = -2147483648;
+pub const INT_FAST8_MAX: u32 = 127;
+pub const INT_FAST16_MAX: u32 = 2147483647;
+pub const INT_FAST32_MAX: u32 = 2147483647;
+pub const UINT_FAST8_MAX: u32 = 255;
+pub const UINT_FAST16_MAX: u32 = 4294967295;
+pub const UINT_FAST32_MAX: u32 = 4294967295;
+pub const INTPTR_MIN: i32 = -2147483648;
+pub const INTPTR_MAX: u32 = 2147483647;
+pub const UINTPTR_MAX: u32 = 4294967295;
+pub const PTRDIFF_MIN: i32 = -2147483648;
+pub const PTRDIFF_MAX: u32 = 2147483647;
+pub const SIG_ATOMIC_MIN: i32 = -2147483648;
+pub const SIG_ATOMIC_MAX: u32 = 2147483647;
+pub const SIZE_MAX: u32 = 4294967295;
+pub const WINT_MIN: i32 = -2147483648;
+pub const WINT_MAX: i32 = 2147483647;
+
+// WASI constants
+pub const __WASI_ADVICE_NORMAL: __wasi_advice_t = 0;
+pub const __WASI_ADVICE_SEQUENTIAL: __wasi_advice_t = 1;
+pub const __WASI_ADVICE_RANDOM: __wasi_advice_t = 2;
+pub const __WASI_ADVICE_WILLNEED: __wasi_advice_t = 3;
+pub const __WASI_ADVICE_DONTNEED: __wasi_advice_t = 4;
+pub const __WASI_ADVICE_NOREUSE: __wasi_advice_t = 5;
+pub const __WASI_CLOCK_REALTIME: __wasi_clockid_t = 0;
+pub const __WASI_CLOCK_MONOTONIC: __wasi_clockid_t = 1;
+pub const __WASI_CLOCK_PROCESS_CPUTIME_ID: __wasi_clockid_t = 2;
+pub const __WASI_CLOCK_THREAD_CPUTIME_ID: __wasi_clockid_t = 3;
+pub const __WASI_DIRCOOKIE_START: __wasi_dircookie_t = 0;
+pub const __WASI_ESUCCESS: __wasi_errno_t = 0;
+pub const __WASI_E2BIG: __wasi_errno_t = 1;
+pub const __WASI_EACCES: __wasi_errno_t = 2;
+pub const __WASI_EADDRINUSE: __wasi_errno_t = 3;
+pub const __WASI_EADDRNOTAVAIL: __wasi_errno_t = 4;
+pub const __WASI_EAFNOSUPPORT: __wasi_errno_t = 5;
+pub const __WASI_EAGAIN: __wasi_errno_t = 6;
+pub const __WASI_EALREADY: __wasi_errno_t = 7;
+pub const __WASI_EBADF: __wasi_errno_t = 8;
+pub const __WASI_EBADMSG: __wasi_errno_t = 9;
+pub const __WASI_EBUSY: __wasi_errno_t = 10;
+pub const __WASI_ECANCELED: __wasi_errno_t = 11;
+pub const __WASI_ECHILD: __wasi_errno_t = 12;
+pub const __WASI_ECONNABORTED: __wasi_errno_t = 13;
+pub const __WASI_ECONNREFUSED: __wasi_errno_t = 14;
+pub const __WASI_ECONNRESET: __wasi_errno_t = 15;
+pub const __WASI_EDEADLK: __wasi_errno_t = 16;
+pub const __WASI_EDESTADDRREQ: __wasi_errno_t = 17;
+pub const __WASI_EDOM: __wasi_errno_t = 18;
+pub const __WASI_EDQUOT: __wasi_errno_t = 19;
+pub const __WASI_EEXIST: __wasi_errno_t = 20;
+pub const __WASI_EFAULT: __wasi_errno_t = 21;
+pub const __WASI_EFBIG: __wasi_errno_t = 22;
+pub const __WASI_EHOSTUNREACH: __wasi_errno_t = 23;
+pub const __WASI_EIDRM: __wasi_errno_t = 24;
+pub const __WASI_EILSEQ: __wasi_errno_t = 25;
+pub const __WASI_EINPROGRESS: __wasi_errno_t = 26;
+pub const __WASI_EINTR: __wasi_errno_t = 27;
+pub const __WASI_EINVAL: __wasi_errno_t = 28;
+pub const __WASI_EIO: __wasi_errno_t = 29;
+pub const __WASI_EISCONN: __wasi_errno_t = 30;
+pub const __WASI_EISDIR: __wasi_errno_t = 31;
+pub const __WASI_ELOOP: __wasi_errno_t = 32;
+pub const __WASI_EMFILE: __wasi_errno_t = 33;
+pub const __WASI_EMLINK: __wasi_errno_t = 34;
+pub const __WASI_EMSGSIZE: __wasi_errno_t = 35;
+pub const __WASI_EMULTIHOP: __wasi_errno_t = 36;
+pub const __WASI_ENAMETOOLONG: __wasi_errno_t = 37;
+pub const __WASI_ENETDOWN: __wasi_errno_t = 38;
+pub const __WASI_ENETRESET: __wasi_errno_t = 39;
+pub const __WASI_ENETUNREACH: __wasi_errno_t = 40;
+pub const __WASI_ENFILE: __wasi_errno_t = 41;
+pub const __WASI_ENOBUFS: __wasi_errno_t = 42;
+pub const __WASI_ENODEV: __wasi_errno_t = 43;
+pub const __WASI_ENOENT: __wasi_errno_t = 44;
+pub const __WASI_ENOEXEC: __wasi_errno_t = 45;
+pub const __WASI_ENOLCK: __wasi_errno_t = 46;
+pub const __WASI_ENOLINK: __wasi_errno_t = 47;
+pub const __WASI_ENOMEM: __wasi_errno_t = 48;
+pub const __WASI_ENOMSG: __wasi_errno_t = 49;
+pub const __WASI_ENOPROTOOPT: __wasi_errno_t = 50;
+pub const __WASI_ENOSPC: __wasi_errno_t = 51;
+pub const __WASI_ENOSYS: __wasi_errno_t = 52;
+pub const __WASI_ENOTCONN: __wasi_errno_t = 53;
+pub const __WASI_ENOTDIR: __wasi_errno_t = 54;
+pub const __WASI_ENOTEMPTY: __wasi_errno_t = 55;
+pub const __WASI_ENOTRECOVERABLE: __wasi_errno_t = 56;
+pub const __WASI_ENOTSOCK: __wasi_errno_t = 57;
+pub const __WASI_ENOTSUP: __wasi_errno_t = 58;
+pub const __WASI_ENOTTY: __wasi_errno_t = 59;
+pub const __WASI_ENXIO: __wasi_errno_t = 60;
+pub const __WASI_EOVERFLOW: __wasi_errno_t = 61;
+pub const __WASI_EOWNERDEAD: __wasi_errno_t = 62;
+pub const __WASI_EPERM: __wasi_errno_t = 63;
+pub const __WASI_EPIPE: __wasi_errno_t = 64;
+pub const __WASI_EPROTO: __wasi_errno_t = 65;
+pub const __WASI_EPROTONOSUPPORT: __wasi_errno_t = 66;
+pub const __WASI_EPROTOTYPE: __wasi_errno_t = 67;
+pub const __WASI_ERANGE: __wasi_errno_t = 68;
+pub const __WASI_EROFS: __wasi_errno_t = 69;
+pub const __WASI_ESPIPE: __wasi_errno_t = 70;
+pub const __WASI_ESRCH: __wasi_errno_t = 71;
+pub const __WASI_ESTALE: __wasi_errno_t = 72;
+pub const __WASI_ETIMEDOUT: __wasi_errno_t = 73;
+pub const __WASI_ETXTBSY: __wasi_errno_t = 74;
+pub const __WASI_EXDEV: __wasi_errno_t = 75;
+pub const __WASI_ENOTCAPABLE: __wasi_errno_t = 76;
+pub const __WASI_EVENT_FD_READWRITE_HANGUP: __wasi_eventrwflags_t = 1;
+pub const __WASI_EVENTTYPE_CLOCK: __wasi_eventtype_t = 0;
+pub const __WASI_EVENTTYPE_FD_READ: __wasi_eventtype_t = 1;
+pub const __WASI_EVENTTYPE_FD_WRITE: __wasi_eventtype_t = 2;
+pub const __WASI_FDFLAG_APPEND: __wasi_fdflags_t = 1;
+pub const __WASI_FDFLAG_DSYNC: __wasi_fdflags_t = 2;
+pub const __WASI_FDFLAG_NONBLOCK: __wasi_fdflags_t = 4;
+pub const __WASI_FDFLAG_RSYNC: __wasi_fdflags_t = 8;
+pub const __WASI_FDFLAG_SYNC: __wasi_fdflags_t = 16;
+pub const __WASI_PREOPENTYPE_DIR: __wasi_preopentype_t = 0;
+pub const __WASI_FILETYPE_UNKNOWN: __wasi_filetype_t = 0;
+pub const __WASI_FILETYPE_BLOCK_DEVICE: __wasi_filetype_t = 1;
+pub const __WASI_FILETYPE_CHARACTER_DEVICE: __wasi_filetype_t = 2;
+pub const __WASI_FILETYPE_DIRECTORY: __wasi_filetype_t = 3;
+pub const __WASI_FILETYPE_REGULAR_FILE: __wasi_filetype_t = 4;
+pub const __WASI_FILETYPE_SOCKET_DGRAM: __wasi_filetype_t = 5;
+pub const __WASI_FILETYPE_SOCKET_STREAM: __wasi_filetype_t = 6;
+pub const __WASI_FILETYPE_SYMBOLIC_LINK: __wasi_filetype_t = 7;
+pub const __WASI_FILESTAT_SET_ATIM: __wasi_fstflags_t = 1;
+pub const __WASI_FILESTAT_SET_ATIM_NOW: __wasi_fstflags_t = 2;
+pub const __WASI_FILESTAT_SET_MTIM: __wasi_fstflags_t = 4;
+pub const __WASI_FILESTAT_SET_MTIM_NOW: __wasi_fstflags_t = 8;
+pub const __WASI_LOOKUP_SYMLINK_FOLLOW: __wasi_lookupflags_t = 1;
+pub const __WASI_O_CREAT: __wasi_oflags_t = 1;
+pub const __WASI_O_DIRECTORY: __wasi_oflags_t = 2;
+pub const __WASI_O_EXCL: __wasi_oflags_t = 4;
+pub const __WASI_O_TRUNC: __wasi_oflags_t = 8;
+pub const __WASI_SOCK_RECV_PEEK: __wasi_riflags_t = 1;
+pub const __WASI_SOCK_RECV_WAITALL: __wasi_riflags_t = 2;
+pub const __WASI_RIGHT_FD_DATASYNC: __wasi_rights_t = 1;
+pub const __WASI_RIGHT_FD_READ: __wasi_rights_t = 2;
+pub const __WASI_RIGHT_FD_SEEK: __wasi_rights_t = 4;
+pub const __WASI_RIGHT_FD_FDSTAT_SET_FLAGS: __wasi_rights_t = 8;
+pub const __WASI_RIGHT_FD_SYNC: __wasi_rights_t = 16;
+pub const __WASI_RIGHT_FD_TELL: __wasi_rights_t = 32;
+pub const __WASI_RIGHT_FD_WRITE: __wasi_rights_t = 64;
+pub const __WASI_RIGHT_FD_ADVISE: __wasi_rights_t = 128;
+pub const __WASI_RIGHT_FD_ALLOCATE: __wasi_rights_t = 256;
+pub const __WASI_RIGHT_PATH_CREATE_DIRECTORY: __wasi_rights_t = 512;
+pub const __WASI_RIGHT_PATH_CREATE_FILE: __wasi_rights_t = 1024;
+pub const __WASI_RIGHT_PATH_LINK_SOURCE: __wasi_rights_t = 2048;
+pub const __WASI_RIGHT_PATH_LINK_TARGET: __wasi_rights_t = 4096;
+pub const __WASI_RIGHT_PATH_OPEN: __wasi_rights_t = 8192;
+pub const __WASI_RIGHT_FD_READDIR: __wasi_rights_t = 16384;
+pub const __WASI_RIGHT_PATH_READLINK: __wasi_rights_t = 32768;
+pub const __WASI_RIGHT_PATH_RENAME_SOURCE: __wasi_rights_t = 65536;
+pub const __WASI_RIGHT_PATH_RENAME_TARGET: __wasi_rights_t = 131072;
+pub const __WASI_RIGHT_PATH_FILESTAT_GET: __wasi_rights_t = 262144;
+pub const __WASI_RIGHT_PATH_FILESTAT_SET_SIZE: __wasi_rights_t = 524288;
+pub const __WASI_RIGHT_PATH_FILESTAT_SET_TIMES: __wasi_rights_t = 1048576;
+pub const __WASI_RIGHT_FD_FILESTAT_GET: __wasi_rights_t = 2097152;
+pub const __WASI_RIGHT_FD_FILESTAT_SET_SIZE: __wasi_rights_t = 4194304;
+pub const __WASI_RIGHT_FD_FILESTAT_SET_TIMES: __wasi_rights_t = 8388608;
+pub const __WASI_RIGHT_PATH_SYMLINK: __wasi_rights_t = 16777216;
+pub const __WASI_RIGHT_PATH_REMOVE_DIRECTORY: __wasi_rights_t = 33554432;
+pub const __WASI_RIGHT_PATH_UNLINK_FILE: __wasi_rights_t = 67108864;
+pub const __WASI_RIGHT_POLL_FD_READWRITE: __wasi_rights_t = 134217728;
+pub const __WASI_RIGHT_SOCK_SHUTDOWN: __wasi_rights_t = 268435456;
+pub const __WASI_SOCK_RECV_DATA_TRUNCATED: __wasi_roflags_t = 1;
+pub const __WASI_SHUT_RD: __wasi_sdflags_t = 1;
+pub const __WASI_SHUT_WR: __wasi_sdflags_t = 2;
+pub const __WASI_SIGHUP: __wasi_signal_t = 1;
+pub const __WASI_SIGINT: __wasi_signal_t = 2;
+pub const __WASI_SIGQUIT: __wasi_signal_t = 3;
+pub const __WASI_SIGILL: __wasi_signal_t = 4;
+pub const __WASI_SIGTRAP: __wasi_signal_t = 5;
+pub const __WASI_SIGABRT: __wasi_signal_t = 6;
+pub const __WASI_SIGBUS: __wasi_signal_t = 7;
+pub const __WASI_SIGFPE: __wasi_signal_t = 8;
+pub const __WASI_SIGKILL: __wasi_signal_t = 9;
+pub const __WASI_SIGUSR1: __wasi_signal_t = 10;
+pub const __WASI_SIGSEGV: __wasi_signal_t = 11;
+pub const __WASI_SIGUSR2: __wasi_signal_t = 12;
+pub const __WASI_SIGPIPE: __wasi_signal_t = 13;
+pub const __WASI_SIGALRM: __wasi_signal_t = 14;
+pub const __WASI_SIGTERM: __wasi_signal_t = 15;
+pub const __WASI_SIGCHLD: __wasi_signal_t = 16;
+pub const __WASI_SIGCONT: __wasi_signal_t = 17;
+pub const __WASI_SIGSTOP: __wasi_signal_t = 18;
+pub const __WASI_SIGTSTP: __wasi_signal_t = 19;
+pub const __WASI_SIGTTIN: __wasi_signal_t = 20;
+pub const __WASI_SIGTTOU: __wasi_signal_t = 21;
+pub const __WASI_SIGURG: __wasi_signal_t = 22;
+pub const __WASI_SIGXCPU: __wasi_signal_t = 23;
+pub const __WASI_SIGXFSZ: __wasi_signal_t = 24;
+pub const __WASI_SIGVTALRM: __wasi_signal_t = 25;
+pub const __WASI_SIGPROF: __wasi_signal_t = 26;
+pub const __WASI_SIGWINCH: __wasi_signal_t = 27;
+pub const __WASI_SIGPOLL: __wasi_signal_t = 28;
+pub const __WASI_SIGPWR: __wasi_signal_t = 29;
+pub const __WASI_SIGSYS: __wasi_signal_t = 30;
+pub const __WASI_SUBSCRIPTION_CLOCK_ABSTIME: __wasi_subclockflags_t = 1;
+pub const __WASI_WHENCE_CUR: __wasi_whence_t = 0;
+pub const __WASI_WHENCE_END: __wasi_whence_t = 1;
+pub const __WASI_WHENCE_SET: __wasi_whence_t = 2;
+
+pub fn errno_from_nix(errno: nix::errno::Errno) -> __wasi_errno_t {
+ match errno {
+ nix::errno::Errno::EPERM => __WASI_EPERM,
+ nix::errno::Errno::ENOENT => __WASI_ENOENT,
+ nix::errno::Errno::ESRCH => __WASI_ESRCH,
+ nix::errno::Errno::EINTR => __WASI_EINTR,
+ nix::errno::Errno::EIO => __WASI_EIO,
+ nix::errno::Errno::ENXIO => __WASI_ENXIO,
+ nix::errno::Errno::E2BIG => __WASI_E2BIG,
+ nix::errno::Errno::ENOEXEC => __WASI_ENOEXEC,
+ nix::errno::Errno::EBADF => __WASI_EBADF,
+ nix::errno::Errno::ECHILD => __WASI_ECHILD,
+ nix::errno::Errno::EAGAIN => __WASI_EAGAIN,
+ nix::errno::Errno::ENOMEM => __WASI_ENOMEM,
+ nix::errno::Errno::EACCES => __WASI_EACCES,
+ nix::errno::Errno::EFAULT => __WASI_EFAULT,
+ nix::errno::Errno::EBUSY => __WASI_EBUSY,
+ nix::errno::Errno::EEXIST => __WASI_EEXIST,
+ nix::errno::Errno::EXDEV => __WASI_EXDEV,
+ nix::errno::Errno::ENODEV => __WASI_ENODEV,
+ nix::errno::Errno::ENOTDIR => __WASI_ENOTDIR,
+ nix::errno::Errno::EISDIR => __WASI_EISDIR,
+ nix::errno::Errno::EINVAL => __WASI_EINVAL,
+ nix::errno::Errno::ENFILE => __WASI_ENFILE,
+ nix::errno::Errno::EMFILE => __WASI_EMFILE,
+ nix::errno::Errno::ENOTTY => __WASI_ENOTTY,
+ nix::errno::Errno::ETXTBSY => __WASI_ETXTBSY,
+ nix::errno::Errno::EFBIG => __WASI_EFBIG,
+ nix::errno::Errno::ENOSPC => __WASI_ENOSPC,
+ nix::errno::Errno::ESPIPE => __WASI_ESPIPE,
+ nix::errno::Errno::EROFS => __WASI_EROFS,
+ nix::errno::Errno::EMLINK => __WASI_EMLINK,
+ nix::errno::Errno::EPIPE => __WASI_EPIPE,
+ nix::errno::Errno::EDOM => __WASI_EDOM,
+ nix::errno::Errno::ERANGE => __WASI_ERANGE,
+ nix::errno::Errno::EDEADLK => __WASI_EDEADLK,
+ nix::errno::Errno::ENAMETOOLONG => __WASI_ENAMETOOLONG,
+ nix::errno::Errno::ENOLCK => __WASI_ENOLCK,
+ nix::errno::Errno::ENOSYS => __WASI_ENOSYS,
+ nix::errno::Errno::ENOTEMPTY => __WASI_ENOTEMPTY,
+ nix::errno::Errno::ELOOP => __WASI_ELOOP,
+ nix::errno::Errno::ENOMSG => __WASI_ENOMSG,
+ nix::errno::Errno::EIDRM => __WASI_EIDRM,
+ nix::errno::Errno::ENOLINK => __WASI_ENOLINK,
+ nix::errno::Errno::EPROTO => __WASI_EPROTO,
+ nix::errno::Errno::EMULTIHOP => __WASI_EMULTIHOP,
+ nix::errno::Errno::EBADMSG => __WASI_EBADMSG,
+ nix::errno::Errno::EOVERFLOW => __WASI_EOVERFLOW,
+ nix::errno::Errno::EILSEQ => __WASI_EILSEQ,
+ nix::errno::Errno::ENOTSOCK => __WASI_ENOTSOCK,
+ nix::errno::Errno::EDESTADDRREQ => __WASI_EDESTADDRREQ,
+ nix::errno::Errno::EMSGSIZE => __WASI_EMSGSIZE,
+ nix::errno::Errno::EPROTOTYPE => __WASI_EPROTOTYPE,
+ nix::errno::Errno::ENOPROTOOPT => __WASI_ENOPROTOOPT,
+ nix::errno::Errno::EPROTONOSUPPORT => __WASI_EPROTONOSUPPORT,
+ nix::errno::Errno::EAFNOSUPPORT => __WASI_EAFNOSUPPORT,
+ nix::errno::Errno::EADDRINUSE => __WASI_EADDRINUSE,
+ nix::errno::Errno::EADDRNOTAVAIL => __WASI_EADDRNOTAVAIL,
+ nix::errno::Errno::ENETDOWN => __WASI_ENETDOWN,
+ nix::errno::Errno::ENETUNREACH => __WASI_ENETUNREACH,
+ nix::errno::Errno::ENETRESET => __WASI_ENETRESET,
+ nix::errno::Errno::ECONNABORTED => __WASI_ECONNABORTED,
+ nix::errno::Errno::ECONNRESET => __WASI_ECONNRESET,
+ nix::errno::Errno::ENOBUFS => __WASI_ENOBUFS,
+ nix::errno::Errno::EISCONN => __WASI_EISCONN,
+ nix::errno::Errno::ENOTCONN => __WASI_ENOTCONN,
+ nix::errno::Errno::ETIMEDOUT => __WASI_ETIMEDOUT,
+ nix::errno::Errno::ECONNREFUSED => __WASI_ECONNREFUSED,
+ nix::errno::Errno::EHOSTUNREACH => __WASI_EHOSTUNREACH,
+ nix::errno::Errno::EALREADY => __WASI_EALREADY,
+ nix::errno::Errno::EINPROGRESS => __WASI_EINPROGRESS,
+ nix::errno::Errno::ESTALE => __WASI_ESTALE,
+ nix::errno::Errno::EDQUOT => __WASI_EDQUOT,
+ nix::errno::Errno::ECANCELED => __WASI_ECANCELED,
+ nix::errno::Errno::EOWNERDEAD => __WASI_EOWNERDEAD,
+ nix::errno::Errno::ENOTRECOVERABLE => __WASI_ENOTRECOVERABLE,
+ _ => __WASI_ENOSYS,
+ }
+}