diff options
Diffstat (limited to 'third_party/rust/lucet-wasi-wasmsbx/src')
-rw-r--r-- | third_party/rust/lucet-wasi-wasmsbx/src/bindings.rs | 11 | ||||
-rw-r--r-- | third_party/rust/lucet-wasi-wasmsbx/src/c_api.rs | 98 | ||||
-rw-r--r-- | third_party/rust/lucet-wasi-wasmsbx/src/ctx.rs | 260 | ||||
-rw-r--r-- | third_party/rust/lucet-wasi-wasmsbx/src/fdentry.rs | 169 | ||||
-rw-r--r-- | third_party/rust/lucet-wasi-wasmsbx/src/host.rs | 346 | ||||
-rw-r--r-- | third_party/rust/lucet-wasi-wasmsbx/src/hostcalls/fs.rs | 1358 | ||||
-rw-r--r-- | third_party/rust/lucet-wasi-wasmsbx/src/hostcalls/fs_helpers.rs | 306 | ||||
-rw-r--r-- | third_party/rust/lucet-wasi-wasmsbx/src/hostcalls/misc.rs | 457 | ||||
-rw-r--r-- | third_party/rust/lucet-wasi-wasmsbx/src/hostcalls/mod.rs | 448 | ||||
-rw-r--r-- | third_party/rust/lucet-wasi-wasmsbx/src/hostcalls/timers.rs | 113 | ||||
-rw-r--r-- | third_party/rust/lucet-wasi-wasmsbx/src/lib.rs | 16 | ||||
-rw-r--r-- | third_party/rust/lucet-wasi-wasmsbx/src/memory.rs | 620 | ||||
-rw-r--r-- | third_party/rust/lucet-wasi-wasmsbx/src/wasi_host.rs | 1035 | ||||
-rw-r--r-- | third_party/rust/lucet-wasi-wasmsbx/src/wasm32.rs | 1367 |
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, + } +} |