Extract common interface from lucet-wasi
This commit is contained in:
257
src/ctx.rs
Normal file
257
src/ctx.rs
Normal file
@@ -0,0 +1,257 @@
|
||||
use crate::fdentry::FdEntry;
|
||||
use crate::host;
|
||||
use crate::wasm32;
|
||||
|
||||
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 trait VmContext {
|
||||
fn as_wasi_ctx(&self) -> &WasiCtx;
|
||||
fn as_wasi_ctx_mut(&mut self) -> &mut WasiCtx;
|
||||
|
||||
unsafe fn dec_ptr(
|
||||
&mut self,
|
||||
ptr: wasm32::uintptr_t,
|
||||
len: usize,
|
||||
) -> Result<*mut u8, host::__wasi_errno_t>;
|
||||
}
|
||||
|
||||
pub struct WasiCtxBuilder {
|
||||
fds: HashMap<host::__wasi_fd_t, FdEntry>,
|
||||
preopens: HashMap<PathBuf, File>,
|
||||
args: Vec<CString>,
|
||||
env: HashMap<CString, CString>,
|
||||
}
|
||||
|
||||
impl WasiCtxBuilder {
|
||||
/// Builder for a new `WasiCtx`.
|
||||
pub fn new() -> Self {
|
||||
let null = dev_null();
|
||||
WasiCtxBuilder {
|
||||
fds: HashMap::new(),
|
||||
preopens: HashMap::new(),
|
||||
args: vec![],
|
||||
env: HashMap::new(),
|
||||
}
|
||||
.fd_dup(0, &null)
|
||||
.fd_dup(1, &null)
|
||||
.fd_dup(2, &null)
|
||||
}
|
||||
|
||||
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_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()) }
|
||||
}
|
||||
|
||||
/// 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
|
||||
}
|
||||
|
||||
/// 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")
|
||||
}
|
||||
143
src/fdentry.rs
Normal file
143
src/fdentry.rs
Normal file
@@ -0,0 +1,143 @@
|
||||
use crate::host;
|
||||
use std::fs::File;
|
||||
use std::os::unix::prelude::{FileTypeExt, FromRawFd, IntoRawFd, RawFd};
|
||||
use std::path::PathBuf;
|
||||
|
||||
#[derive(Clone, 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()) }
|
||||
}
|
||||
}
|
||||
|
||||
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(Clone, 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));
|
||||
}
|
||||
}
|
||||
}
|
||||
335
src/host.rs
Normal file
335
src/host.rs
Normal file
@@ -0,0 +1,335 @@
|
||||
#![allow(non_camel_case_types)]
|
||||
#![allow(non_snake_case)]
|
||||
|
||||
include!(concat!(env!("OUT_DIR"), "/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 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,
|
||||
st_ctim: filestat.st_ctime as __wasi_timestamp_t,
|
||||
st_mtim: filestat.st_mtime as __wasi_timestamp_t,
|
||||
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_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)
|
||||
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;
|
||||
1360
src/hostcalls.rs
Normal file
1360
src/hostcalls.rs
Normal file
File diff suppressed because it is too large
Load Diff
8
src/lib.rs
Normal file
8
src/lib.rs
Normal file
@@ -0,0 +1,8 @@
|
||||
pub mod ctx;
|
||||
pub mod fdentry;
|
||||
pub mod host;
|
||||
pub mod hostcalls;
|
||||
pub mod memory;
|
||||
pub mod wasm32;
|
||||
|
||||
pub use ctx::{WasiCtx, WasiCtxBuilder};
|
||||
479
src/memory.rs
Normal file
479
src/memory.rs
Normal file
@@ -0,0 +1,479 @@
|
||||
//! 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::ctx::VmContext;
|
||||
use crate::{host, wasm32};
|
||||
|
||||
use cast;
|
||||
use cast::From as _0;
|
||||
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 unsafe fn dec_ptr_to<T>(
|
||||
vmctx: *mut VmContext,
|
||||
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);
|
||||
}
|
||||
(*vmctx).dec_ptr(ptr, size_of::<T>()).map(|p| p as *mut T)
|
||||
}
|
||||
|
||||
pub unsafe fn dec_pointee<T>(
|
||||
vmctx: *mut VmContext,
|
||||
ptr: wasm32::uintptr_t,
|
||||
) -> Result<T, host::__wasi_errno_t> {
|
||||
dec_ptr_to::<T>(vmctx, ptr).map(|p| p.read())
|
||||
}
|
||||
|
||||
pub unsafe fn enc_pointee<T>(
|
||||
vmctx: *mut VmContext,
|
||||
ptr: wasm32::uintptr_t,
|
||||
t: T,
|
||||
) -> Result<(), host::__wasi_errno_t> {
|
||||
dec_ptr_to::<T>(vmctx, ptr).map(|p| p.write(t))
|
||||
}
|
||||
|
||||
pub unsafe fn dec_slice_of<T>(
|
||||
vmctx: *mut VmContext,
|
||||
ptr: wasm32::uintptr_t,
|
||||
len: wasm32::size_t,
|
||||
) -> Result<(*mut T, usize), host::__wasi_errno_t> {
|
||||
// check alignment, and that length doesn't overflow
|
||||
if ptr as usize % align_of::<T>() != 0 {
|
||||
return Err(host::__WASI_EINVAL as host::__wasi_errno_t);
|
||||
}
|
||||
let len = dec_usize(len);
|
||||
let len_bytes = if let Some(len) = size_of::<T>().checked_mul(len) {
|
||||
len
|
||||
} else {
|
||||
return Err(host::__WASI_EOVERFLOW as host::__wasi_errno_t);
|
||||
};
|
||||
|
||||
let ptr = (*vmctx).dec_ptr(ptr, len_bytes)? as *mut T;
|
||||
|
||||
Ok((ptr, len))
|
||||
}
|
||||
|
||||
pub unsafe fn enc_slice_of<T>(
|
||||
vmctx: *mut VmContext,
|
||||
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 = (*vmctx).dec_ptr(ptr, len_bytes)? as *mut libc::c_void;
|
||||
libc::memcpy(ptr, slice.as_ptr() as *const libc::c_void, 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 unsafe fn $dec_byref(
|
||||
vmctx: *mut VmContext,
|
||||
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 unsafe fn $enc_byref(
|
||||
vmctx: *mut VmContext,
|
||||
ptr: wasm32::uintptr_t,
|
||||
x: host::$ty,
|
||||
) -> Result<(), host::__wasi_errno_t> {
|
||||
enc_pointee::<wasm32::$ty>(vmctx, ptr, $enc(x))
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
pub unsafe fn dec_ciovec(
|
||||
vmctx: *mut VmContext,
|
||||
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: (*vmctx).dec_ptr(ciovec.buf, len)? as *const host::void,
|
||||
buf_len: len,
|
||||
})
|
||||
}
|
||||
|
||||
pub unsafe fn dec_ciovec_slice(
|
||||
vmctx: *mut VmContext,
|
||||
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)?;
|
||||
let slice = slice::from_raw_parts(slice.0, slice.1);
|
||||
slice.iter().map(|iov| dec_ciovec(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 unsafe fn dec_filestat_byref(
|
||||
vmctx: *mut VmContext,
|
||||
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 unsafe fn enc_filestat_byref(
|
||||
vmctx: *mut VmContext,
|
||||
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 unsafe fn dec_fdstat_byref(
|
||||
vmctx: *mut VmContext,
|
||||
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 unsafe fn enc_fdstat_byref(
|
||||
vmctx: *mut VmContext,
|
||||
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 unsafe fn dec_prestat_byref(
|
||||
vmctx: *mut VmContext,
|
||||
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 prestat.pr_type as u32 {
|
||||
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 unsafe fn enc_prestat_byref(
|
||||
vmctx: *mut VmContext,
|
||||
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_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 unsafe fn enc_usize_byref(
|
||||
vmctx: *mut VmContext,
|
||||
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,
|
||||
}
|
||||
}
|
||||
1367
src/wasm32.rs
Normal file
1367
src/wasm32.rs
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user