diff --git a/src/ctx.rs b/src/ctx.rs index 019239955f..6d7645fcdf 100644 --- a/src/ctx.rs +++ b/src/ctx.rs @@ -1,7 +1,7 @@ use crate::host; use crate::sys::dev_null; -use crate::sys::fdmap::{FdEntry, FdMap}; +use crate::sys::fdentry::FdEntry; use failure::{bail, format_err, Error}; use std::collections::HashMap; @@ -11,7 +11,7 @@ use std::io::{stderr, stdin, stdout}; use std::path::{Path, PathBuf}; pub struct WasiCtxBuilder { - fds: FdMap, + fds: HashMap, preopens: HashMap, args: Vec, env: HashMap, @@ -21,15 +21,15 @@ impl WasiCtxBuilder { /// Builder for a new `WasiCtx`. pub fn new() -> Self { let mut builder = Self { - fds: FdMap::new(), + fds: HashMap::new(), preopens: HashMap::new(), args: vec![], env: HashMap::new(), }; - builder.fds.insert_fd_entry_at(0, FdEntry::from_file(dev_null())); - builder.fds.insert_fd_entry_at(1, FdEntry::from_file(dev_null())); - builder.fds.insert_fd_entry_at(2, FdEntry::from_file(dev_null())); + builder.fds.insert(0, FdEntry::from_file(dev_null())); + builder.fds.insert(1, FdEntry::from_file(dev_null())); + builder.fds.insert(2, FdEntry::from_file(dev_null())); builder } @@ -62,9 +62,9 @@ impl WasiCtxBuilder { } pub fn inherit_stdio(mut self) -> Self { - self.fds.insert_fd_entry_at(0, FdEntry::duplicate(&stdin())); - self.fds.insert_fd_entry_at(1, FdEntry::duplicate(&stdout())); - self.fds.insert_fd_entry_at(2, FdEntry::duplicate(&stderr())); + self.fds.insert(0, FdEntry::duplicate(&stdin())); + self.fds.insert(1, FdEntry::duplicate(&stdout())); + self.fds.insert(2, FdEntry::duplicate(&stderr())); self } @@ -106,15 +106,22 @@ impl WasiCtxBuilder { } pub fn build(mut self) -> Result { + // 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_fd_entry(fe) - .map_err(|_| format_err!("not enough file handles"))?; + self.fds.insert(preopen_fd, fe); + preopen_fd += 1; } let env = self @@ -139,7 +146,7 @@ impl WasiCtxBuilder { #[derive(Debug)] pub struct WasiCtx { - pub fds: FdMap, + pub fds: HashMap, pub args: Vec, pub env: Vec, } @@ -167,13 +174,33 @@ impl WasiCtx { rights_base: host::__wasi_rights_t, rights_inheriting: host::__wasi_rights_t, ) -> Result<&FdEntry, host::__wasi_errno_t> { - self.fds.get_fd_entry(fd, rights_base, rights_inheriting) + 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) + } else { + Ok(fe) + } + } else { + Err(host::__WASI_EBADF) + } } pub fn insert_fd_entry( &mut self, fe: FdEntry, ) -> Result { - self.fds.insert_fd_entry(fe) + // 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); + } + } + self.fds.insert(fd, fe); + Ok(fd) } } diff --git a/src/hostcalls/misc.rs b/src/hostcalls.rs similarity index 81% rename from src/hostcalls/misc.rs rename to src/hostcalls.rs index e24350253d..deb30fe0f6 100644 --- a/src/hostcalls/misc.rs +++ b/src/hostcalls.rs @@ -3,12 +3,13 @@ use crate::ctx::WasiCtx; use crate::memory::*; use crate::wasm32; -use crate::sys::hostcalls as hostcalls_impl; - +// NOTE avoid shadowing `std::convert::From` - cf. rust-lang/rfcs#1311 use cast::From as _0; use wasi_common_cbindgen::wasi_common_cbindgen; +pub use crate::sys::hostcalls::*; + #[wasi_common_cbindgen] pub fn args_get( wasi_ctx: &WasiCtx, @@ -67,25 +68,6 @@ pub fn args_sizes_get( wasm32::__WASI_ESUCCESS } -#[wasi_common_cbindgen] -pub fn clock_res_get( - memory: &mut [u8], - clock_id: wasm32::__wasi_clockid_t, - resolution_ptr: wasm32::uintptr_t, -) -> wasm32::__wasi_errno_t { - hostcalls_impl::clock_res_get(memory, clock_id, resolution_ptr) -} - -#[wasi_common_cbindgen] -pub fn clock_time_get( - memory: &mut [u8], - clock_id: wasm32::__wasi_clockid_t, - precision: wasm32::__wasi_timestamp_t, - time_ptr: wasm32::uintptr_t, -) -> wasm32::__wasi_errno_t { - hostcalls_impl::clock_time_get(memory, clock_id, precision, time_ptr) -} - #[wasi_common_cbindgen] pub fn environ_get( wasi_ctx: &WasiCtx, @@ -144,17 +126,6 @@ pub fn environ_sizes_get( } } -#[wasi_common_cbindgen] -pub fn poll_oneoff( - memory: &mut [u8], - input: wasm32::uintptr_t, - output: wasm32::uintptr_t, - nsubscriptions: wasm32::size_t, - nevents: wasm32::uintptr_t, -) -> wasm32::__wasi_errno_t { - hostcalls_impl::poll_oneoff(memory, input, output, nsubscriptions, nevents) -} - #[wasi_common_cbindgen] pub fn proc_exit(rval: wasm32::__wasi_exitcode_t) -> () { // TODO: Rather than call std::process::exit here, we should trigger a @@ -171,11 +142,6 @@ pub fn proc_raise( unimplemented!("proc_raise") } -#[wasi_common_cbindgen] -pub fn sched_yield() -> wasm32::__wasi_errno_t { - hostcalls_impl::sched_yield() -} - #[wasi_common_cbindgen] pub fn random_get( memory: &mut [u8], diff --git a/src/hostcalls/mod.rs b/src/hostcalls/mod.rs deleted file mode 100644 index 5832ce7dba..0000000000 --- a/src/hostcalls/mod.rs +++ /dev/null @@ -1,7 +0,0 @@ -mod fs; -mod misc; -mod sock; - -pub use self::fs::*; -pub use self::misc::*; -pub use self::sock::*; diff --git a/src/lib.rs b/src/lib.rs index f58e918c24..8543a54ab2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -23,9 +23,9 @@ mod ctx; mod sys; -pub mod memory; pub mod host; pub mod hostcalls; +pub mod memory; pub mod wasm32; pub use ctx::{WasiCtx, WasiCtxBuilder}; diff --git a/src/memory.rs b/src/memory.rs index 98085b780a..c45d77aa20 100644 --- a/src/memory.rs +++ b/src/memory.rs @@ -1,9 +1,11 @@ //! Functions to go back and forth between WASI types in host and wasm32 representations. +#![allow(unused)] use crate::{host, wasm32}; -pub use crate::sys::memory::*; + +// NOTE avoid shadowing `std::convert::From` - cf. rust-lang/rfcs#1311 +use cast::From as _0; use cast; -use cast::From as _0; use std::mem::{align_of, size_of}; use std::ptr; use std::slice; diff --git a/src/sys/unix/fdmap.rs b/src/sys/unix/fdentry.rs similarity index 71% rename from src/sys/unix/fdmap.rs rename to src/sys/unix/fdentry.rs index b1aa321486..a2237161a8 100644 --- a/src/sys/unix/fdmap.rs +++ b/src/sys/unix/fdentry.rs @@ -1,9 +1,8 @@ use crate::host; use std::fs::File; -use std::os::unix::prelude::{FileTypeExt, FromRawFd, IntoRawFd, RawFd, AsRawFd}; +use std::os::unix::prelude::{AsRawFd, FileTypeExt, FromRawFd, IntoRawFd, RawFd}; use std::path::PathBuf; -use std::collections::HashMap; #[derive(Clone, Debug)] pub struct FdObject { @@ -21,11 +20,6 @@ pub struct FdEntry { pub preopen_path: Option, } -#[derive(Debug)] -pub struct FdMap { - entries: HashMap, -} - impl Drop for FdObject { fn drop(&mut self) { if self.needs_close { @@ -148,63 +142,3 @@ pub unsafe fn determine_type_rights( }; Ok((ty, rights_base, rights_inheriting)) } - -impl FdMap { - pub fn new() -> Self { - Self { - entries: HashMap::new() - } - } - - pub(crate) fn insert_fd_entry_at(&mut self, fd: host::__wasi_fd_t, fe: FdEntry) { - self.entries.insert(fd, fe); - } - - pub(crate) fn get(&self, fd: &host::__wasi_fd_t) -> Option<&FdEntry> { - self.entries.get(fd) - } - - pub(crate) fn get_mut(&mut self, fd: &host::__wasi_fd_t) -> Option<&mut FdEntry> { - self.entries.get_mut(fd) - } - - pub(crate) fn remove(&mut self, fd: &host::__wasi_fd_t) -> Option { - self.entries.remove(fd) - } - - 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.entries.get(&fd) { - // validate rights - if !fe.rights_base & rights_base != 0 || !fe.rights_inheriting & rights_inheriting != 0 - { - Err(host::__WASI_ENOTCAPABLE) - } else { - Ok(fe) - } - } else { - Err(host::__WASI_EBADF) - } - } - - pub fn insert_fd_entry( - &mut self, - fe: FdEntry, - ) -> Result { - // never insert where stdio handles usually are - let mut fd = 3; - while self.entries.contains_key(&fd) { - if let Some(next_fd) = fd.checked_add(1) { - fd = next_fd; - } else { - return Err(host::__WASI_EMFILE); - } - } - self.entries.insert(fd, fe); - Ok(fd) - } -} \ No newline at end of file diff --git a/src/sys/unix/host.rs b/src/sys/unix/host_impl.rs similarity index 62% rename from src/sys/unix/host.rs rename to src/sys/unix/host_impl.rs index 6f6914e90d..7e3a1d2a9a 100644 --- a/src/sys/unix/host.rs +++ b/src/sys/unix/host_impl.rs @@ -3,26 +3,28 @@ #![allow(non_snake_case)] #![allow(dead_code)] use crate::host; +use crate::memory; +use crate::wasm32; pub fn errno_from_nix(errno: nix::errno::Errno) -> host::__wasi_errno_t { match errno { - nix::errno::Errno::EPERM => host::__WASI_EPERM, + nix::errno::Errno::EPERM => host::__WASI_EPERM, nix::errno::Errno::ENOENT => host::__WASI_ENOENT, - nix::errno::Errno::ESRCH => host::__WASI_ESRCH, - nix::errno::Errno::EINTR => host::__WASI_EINTR, - nix::errno::Errno::EIO => host::__WASI_EIO, - nix::errno::Errno::ENXIO => host::__WASI_ENXIO, - nix::errno::Errno::E2BIG => host::__WASI_E2BIG, + nix::errno::Errno::ESRCH => host::__WASI_ESRCH, + nix::errno::Errno::EINTR => host::__WASI_EINTR, + nix::errno::Errno::EIO => host::__WASI_EIO, + nix::errno::Errno::ENXIO => host::__WASI_ENXIO, + nix::errno::Errno::E2BIG => host::__WASI_E2BIG, nix::errno::Errno::ENOEXEC => host::__WASI_ENOEXEC, - nix::errno::Errno::EBADF => host::__WASI_EBADF, + nix::errno::Errno::EBADF => host::__WASI_EBADF, nix::errno::Errno::ECHILD => host::__WASI_ECHILD, nix::errno::Errno::EAGAIN => host::__WASI_EAGAIN, nix::errno::Errno::ENOMEM => host::__WASI_ENOMEM, nix::errno::Errno::EACCES => host::__WASI_EACCES, nix::errno::Errno::EFAULT => host::__WASI_EFAULT, - nix::errno::Errno::EBUSY => host::__WASI_EBUSY, + nix::errno::Errno::EBUSY => host::__WASI_EBUSY, nix::errno::Errno::EEXIST => host::__WASI_EEXIST, - nix::errno::Errno::EXDEV => host::__WASI_EXDEV, + nix::errno::Errno::EXDEV => host::__WASI_EXDEV, nix::errno::Errno::ENODEV => host::__WASI_ENODEV, nix::errno::Errno::ENOTDIR => host::__WASI_ENOTDIR, nix::errno::Errno::EISDIR => host::__WASI_EISDIR, @@ -31,60 +33,62 @@ pub fn errno_from_nix(errno: nix::errno::Errno) -> host::__wasi_errno_t { nix::errno::Errno::EMFILE => host::__WASI_EMFILE, nix::errno::Errno::ENOTTY => host::__WASI_ENOTTY, nix::errno::Errno::ETXTBSY => host::__WASI_ETXTBSY, - nix::errno::Errno::EFBIG => host::__WASI_EFBIG, + nix::errno::Errno::EFBIG => host::__WASI_EFBIG, nix::errno::Errno::ENOSPC => host::__WASI_ENOSPC, nix::errno::Errno::ESPIPE => host::__WASI_ESPIPE, - nix::errno::Errno::EROFS => host::__WASI_EROFS, + nix::errno::Errno::EROFS => host::__WASI_EROFS, nix::errno::Errno::EMLINK => host::__WASI_EMLINK, - nix::errno::Errno::EPIPE => host::__WASI_EPIPE, - nix::errno::Errno::EDOM => host::__WASI_EDOM, + nix::errno::Errno::EPIPE => host::__WASI_EPIPE, + nix::errno::Errno::EDOM => host::__WASI_EDOM, nix::errno::Errno::ERANGE => host::__WASI_ERANGE, - nix::errno::Errno::EDEADLK => host::__WASI_EDEADLK, + nix::errno::Errno::EDEADLK => host::__WASI_EDEADLK, nix::errno::Errno::ENAMETOOLONG => host::__WASI_ENAMETOOLONG, - nix::errno::Errno::ENOLCK => host::__WASI_ENOLCK, - nix::errno::Errno::ENOSYS => host::__WASI_ENOSYS, - nix::errno::Errno::ENOTEMPTY => host::__WASI_ENOTEMPTY, - nix::errno::Errno::ELOOP => host::__WASI_ELOOP, - nix::errno::Errno::ENOMSG => host::__WASI_ENOMSG, - nix::errno::Errno::EIDRM => host::__WASI_EIDRM, - nix::errno::Errno::ENOLINK => host::__WASI_ENOLINK, - nix::errno::Errno::EPROTO => host::__WASI_EPROTO, - nix::errno::Errno::EMULTIHOP => host::__WASI_EMULTIHOP, - nix::errno::Errno::EBADMSG => host::__WASI_EBADMSG, - nix::errno::Errno::EOVERFLOW => host::__WASI_EOVERFLOW, - nix::errno::Errno::EILSEQ => host::__WASI_EILSEQ, - nix::errno::Errno::ENOTSOCK => host::__WASI_ENOTSOCK, + nix::errno::Errno::ENOLCK => host::__WASI_ENOLCK, + nix::errno::Errno::ENOSYS => host::__WASI_ENOSYS, + nix::errno::Errno::ENOTEMPTY => host::__WASI_ENOTEMPTY, + nix::errno::Errno::ELOOP => host::__WASI_ELOOP, + nix::errno::Errno::ENOMSG => host::__WASI_ENOMSG, + nix::errno::Errno::EIDRM => host::__WASI_EIDRM, + nix::errno::Errno::ENOLINK => host::__WASI_ENOLINK, + nix::errno::Errno::EPROTO => host::__WASI_EPROTO, + nix::errno::Errno::EMULTIHOP => host::__WASI_EMULTIHOP, + nix::errno::Errno::EBADMSG => host::__WASI_EBADMSG, + nix::errno::Errno::EOVERFLOW => host::__WASI_EOVERFLOW, + nix::errno::Errno::EILSEQ => host::__WASI_EILSEQ, + nix::errno::Errno::ENOTSOCK => host::__WASI_ENOTSOCK, nix::errno::Errno::EDESTADDRREQ => host::__WASI_EDESTADDRREQ, - nix::errno::Errno::EMSGSIZE => host::__WASI_EMSGSIZE, - nix::errno::Errno::EPROTOTYPE => host::__WASI_EPROTOTYPE, - nix::errno::Errno::ENOPROTOOPT => host::__WASI_ENOPROTOOPT, + nix::errno::Errno::EMSGSIZE => host::__WASI_EMSGSIZE, + nix::errno::Errno::EPROTOTYPE => host::__WASI_EPROTOTYPE, + nix::errno::Errno::ENOPROTOOPT => host::__WASI_ENOPROTOOPT, nix::errno::Errno::EPROTONOSUPPORT => host::__WASI_EPROTONOSUPPORT, - nix::errno::Errno::EAFNOSUPPORT => host::__WASI_EAFNOSUPPORT, - nix::errno::Errno::EADDRINUSE => host::__WASI_EADDRINUSE, + nix::errno::Errno::EAFNOSUPPORT => host::__WASI_EAFNOSUPPORT, + nix::errno::Errno::EADDRINUSE => host::__WASI_EADDRINUSE, nix::errno::Errno::EADDRNOTAVAIL => host::__WASI_EADDRNOTAVAIL, - nix::errno::Errno::ENETDOWN => host::__WASI_ENETDOWN, - nix::errno::Errno::ENETUNREACH => host::__WASI_ENETUNREACH, - nix::errno::Errno::ENETRESET => host::__WASI_ENETRESET, - nix::errno::Errno::ECONNABORTED => host::__WASI_ECONNABORTED, - nix::errno::Errno::ECONNRESET => host::__WASI_ECONNRESET, - nix::errno::Errno::ENOBUFS => host::__WASI_ENOBUFS, - nix::errno::Errno::EISCONN => host::__WASI_EISCONN, - nix::errno::Errno::ENOTCONN => host::__WASI_ENOTCONN, - nix::errno::Errno::ETIMEDOUT => host::__WASI_ETIMEDOUT, - nix::errno::Errno::ECONNREFUSED => host::__WASI_ECONNREFUSED, - nix::errno::Errno::EHOSTUNREACH => host::__WASI_EHOSTUNREACH, - nix::errno::Errno::EALREADY => host::__WASI_EALREADY, - nix::errno::Errno::EINPROGRESS => host::__WASI_EINPROGRESS, - nix::errno::Errno::ESTALE => host::__WASI_ESTALE, - nix::errno::Errno::EDQUOT => host::__WASI_EDQUOT, - nix::errno::Errno::ECANCELED => host::__WASI_ECANCELED, - nix::errno::Errno::EOWNERDEAD => host::__WASI_EOWNERDEAD, + nix::errno::Errno::ENETDOWN => host::__WASI_ENETDOWN, + nix::errno::Errno::ENETUNREACH => host::__WASI_ENETUNREACH, + nix::errno::Errno::ENETRESET => host::__WASI_ENETRESET, + nix::errno::Errno::ECONNABORTED => host::__WASI_ECONNABORTED, + nix::errno::Errno::ECONNRESET => host::__WASI_ECONNRESET, + nix::errno::Errno::ENOBUFS => host::__WASI_ENOBUFS, + nix::errno::Errno::EISCONN => host::__WASI_EISCONN, + nix::errno::Errno::ENOTCONN => host::__WASI_ENOTCONN, + nix::errno::Errno::ETIMEDOUT => host::__WASI_ETIMEDOUT, + nix::errno::Errno::ECONNREFUSED => host::__WASI_ECONNREFUSED, + nix::errno::Errno::EHOSTUNREACH => host::__WASI_EHOSTUNREACH, + nix::errno::Errno::EALREADY => host::__WASI_EALREADY, + nix::errno::Errno::EINPROGRESS => host::__WASI_EINPROGRESS, + nix::errno::Errno::ESTALE => host::__WASI_ESTALE, + nix::errno::Errno::EDQUOT => host::__WASI_EDQUOT, + nix::errno::Errno::ECANCELED => host::__WASI_ECANCELED, + nix::errno::Errno::EOWNERDEAD => host::__WASI_EOWNERDEAD, nix::errno::Errno::ENOTRECOVERABLE => host::__WASI_ENOTRECOVERABLE, _ => host::__WASI_ENOSYS, } } -pub unsafe fn ciovec_to_nix<'a>(ciovec: &'a host::__wasi_ciovec_t) -> nix::sys::uio::IoVec<&'a [u8]> { +pub unsafe fn ciovec_to_nix<'a>( + ciovec: &'a host::__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) } @@ -231,10 +235,40 @@ pub fn filestat_from_nix(filestat: nix::sys::stat::FileStat) -> host::__wasi_fil st_dev: dev, st_ino: ino, st_nlink: filestat.st_nlink as host::__wasi_linkcount_t, - st_size: filestat.st_size as host::__wasi_filesize_t, + st_size: filestat.st_size as host::__wasi_filesize_t, st_atim: filestat.st_atime as host::__wasi_timestamp_t, st_ctim: filestat.st_ctime as host::__wasi_timestamp_t, st_mtim: filestat.st_mtime as host::__wasi_timestamp_t, st_filetype: filetype_from_nix(filetype), } } + +#[cfg(target_os = "linux")] +pub fn dirent_from_host( + host_entry: &nix::libc::dirent, +) -> Result { + let mut entry = unsafe { std::mem::zeroed::() }; + 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); + } + entry.d_ino = memory::enc_inode(host_entry.d_ino); + entry.d_next = memory::enc_dircookie(host_entry.d_off as u64); + entry.d_namlen = memory::enc_u32(d_namlen as u32); + entry.d_type = memory::enc_filetype(host_entry.d_type); + Ok(entry) +} + +#[cfg(not(target_os = "linux"))] +pub fn dirent_from_host( + host_entry: &nix::libc::dirent, +) -> Result { + let mut entry = unsafe { std::mem::zeroed::() }; + entry.d_ino = memory::enc_inode(host_entry.d_ino); + entry.d_next = memory::enc_dircookie(host_entry.d_seekoff); + entry.d_namlen = memory::enc_u32(u32::from(host_entry.d_namlen)); + entry.d_type = memory::enc_filetype(host_entry.d_type); + Ok(entry) +} diff --git a/src/sys/unix/hostcalls/fs.rs b/src/sys/unix/hostcalls/fs.rs index a922061914..af3b3c1ae7 100644 --- a/src/sys/unix/hostcalls/fs.rs +++ b/src/sys/unix/hostcalls/fs.rs @@ -1,18 +1,19 @@ #![allow(non_camel_case_types)] #![allow(unused_unsafe)] -use crate::sys::fdmap::{determine_type_rights, FdEntry}; -use crate::sys::host as host_impl; +use super::fdentry::{determine_type_rights, FdEntry}; +use super::fs_helpers::*; +use super::host_impl; use crate::ctx::WasiCtx; use crate::memory::*; use crate::{host, wasm32}; -use super::fs_helpers::*; - use nix::libc::{self, c_long, c_void, off_t}; use std::ffi::OsStr; use std::os::unix::prelude::{FromRawFd, OsStrExt}; +use wasi_common_cbindgen::wasi_common_cbindgen; +#[wasi_common_cbindgen] pub fn fd_close(wasi_ctx: &mut WasiCtx, fd: wasm32::__wasi_fd_t) -> wasm32::__wasi_errno_t { let fd = dec_fd(fd); if let Some(fdent) = wasi_ctx.fds.get(&fd) { @@ -32,6 +33,7 @@ pub fn fd_close(wasi_ctx: &mut WasiCtx, fd: wasm32::__wasi_fd_t) -> wasm32::__wa } } +#[wasi_common_cbindgen] pub fn fd_datasync(wasi_ctx: &WasiCtx, fd: wasm32::__wasi_fd_t) -> wasm32::__wasi_errno_t { let host_fd = dec_fd(fd); let rights = host::__WASI_RIGHT_FD_DATASYNC; @@ -57,6 +59,7 @@ pub fn fd_datasync(wasi_ctx: &WasiCtx, fd: wasm32::__wasi_fd_t) -> wasm32::__was wasm32::__WASI_ESUCCESS } +#[wasi_common_cbindgen] pub fn fd_pread( wasi_ctx: &WasiCtx, memory: &mut [u8], @@ -106,6 +109,7 @@ pub fn fd_pread( .unwrap_or_else(|e| e) } +#[wasi_common_cbindgen] pub fn fd_pwrite( wasi_ctx: &WasiCtx, memory: &mut [u8], @@ -147,6 +151,7 @@ pub fn fd_pwrite( .unwrap_or_else(|e| e) } +#[wasi_common_cbindgen] pub fn fd_read( wasi_ctx: &mut WasiCtx, memory: &mut [u8], @@ -189,6 +194,7 @@ pub fn fd_read( .unwrap_or_else(|e| e) } +#[wasi_common_cbindgen] pub fn fd_renumber( wasi_ctx: &mut WasiCtx, from: wasm32::__wasi_fd_t, @@ -213,6 +219,7 @@ pub fn fd_renumber( wasm32::__WASI_ESUCCESS } +#[wasi_common_cbindgen] pub fn fd_seek( wasi_ctx: &WasiCtx, memory: &mut [u8], @@ -253,6 +260,7 @@ pub fn fd_seek( .unwrap_or_else(|e| e) } +#[wasi_common_cbindgen] pub fn fd_tell( wasi_ctx: &WasiCtx, memory: &mut [u8], @@ -279,6 +287,7 @@ pub fn fd_tell( .unwrap_or_else(|e| e) } +#[wasi_common_cbindgen] pub fn fd_fdstat_get( wasi_ctx: &WasiCtx, memory: &mut [u8], @@ -313,6 +322,7 @@ pub fn fd_fdstat_get( errno } +#[wasi_common_cbindgen] pub fn fd_fdstat_set_flags( wasi_ctx: &WasiCtx, fd: wasm32::__wasi_fd_t, @@ -332,6 +342,7 @@ pub fn fd_fdstat_set_flags( } } +#[wasi_common_cbindgen] pub fn fd_fdstat_set_rights( wasi_ctx: &mut WasiCtx, fd: wasm32::__wasi_fd_t, @@ -354,6 +365,7 @@ pub fn fd_fdstat_set_rights( wasm32::__WASI_ESUCCESS } +#[wasi_common_cbindgen] pub fn fd_sync(wasi_ctx: &WasiCtx, fd: wasm32::__wasi_fd_t) -> wasm32::__wasi_errno_t { let host_fd = dec_fd(fd); let rights = host::__WASI_RIGHT_FD_SYNC; @@ -368,6 +380,7 @@ pub fn fd_sync(wasi_ctx: &WasiCtx, fd: wasm32::__wasi_fd_t) -> wasm32::__wasi_er wasm32::__WASI_ESUCCESS } +#[wasi_common_cbindgen] pub fn fd_write( wasi_ctx: &WasiCtx, memory: &mut [u8], @@ -404,6 +417,7 @@ pub fn fd_write( .unwrap_or_else(|e| e) } +#[wasi_common_cbindgen] pub fn fd_advise( wasi_ctx: &WasiCtx, fd: wasm32::__wasi_fd_t, @@ -462,6 +476,7 @@ pub fn fd_advise( wasm32::__WASI_ESUCCESS } +#[wasi_common_cbindgen] pub fn fd_allocate( wasi_ctx: &WasiCtx, fd: wasm32::__wasi_fd_t, @@ -514,6 +529,7 @@ pub fn fd_allocate( wasm32::__WASI_ESUCCESS } +#[wasi_common_cbindgen] pub fn path_create_directory( wasi_ctx: &WasiCtx, memory: &mut [u8], @@ -552,6 +568,7 @@ pub fn path_create_directory( } } +#[wasi_common_cbindgen] pub fn path_link( wasi_ctx: &WasiCtx, memory: &mut [u8], @@ -613,6 +630,7 @@ pub fn path_link( wasm32::__WASI_ESUCCESS } +#[wasi_common_cbindgen] pub fn path_open( wasi_ctx: &mut WasiCtx, memory: &mut [u8], @@ -770,6 +788,7 @@ pub fn path_open( .unwrap_or_else(|e| e) } +#[wasi_common_cbindgen] pub fn fd_readdir( wasi_ctx: &WasiCtx, memory: &mut [u8], @@ -817,10 +836,11 @@ pub fn fd_readdir( if host_entry.is_null() { break; } - let entry: wasm32::__wasi_dirent_t = match dirent_from_host(&unsafe { *host_entry }) { - Ok(entry) => entry, - Err(e) => return enc_errno(e), - }; + let entry: wasm32::__wasi_dirent_t = + match host_impl::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 { @@ -849,6 +869,7 @@ pub fn fd_readdir( .unwrap_or_else(|e| e) } +#[wasi_common_cbindgen] pub fn path_readlink( wasi_ctx: &WasiCtx, memory: &mut [u8], @@ -892,6 +913,7 @@ pub fn path_readlink( wasm32::__WASI_ESUCCESS } +#[wasi_common_cbindgen] pub fn path_rename( wasi_ctx: &WasiCtx, memory: &mut [u8], @@ -948,6 +970,7 @@ pub fn path_rename( wasm32::__WASI_ESUCCESS } +#[wasi_common_cbindgen] pub fn fd_filestat_get( wasi_ctx: &WasiCtx, memory: &mut [u8], @@ -974,6 +997,7 @@ pub fn fd_filestat_get( errno } +#[wasi_common_cbindgen] pub fn fd_filestat_set_times( wasi_ctx: &WasiCtx, fd: wasm32::__wasi_fd_t, @@ -1030,6 +1054,7 @@ pub fn fd_filestat_set_times( wasm32::__WASI_ESUCCESS } +#[wasi_common_cbindgen] pub fn fd_filestat_set_size( wasi_ctx: &WasiCtx, fd: wasm32::__wasi_fd_t, @@ -1053,6 +1078,7 @@ pub fn fd_filestat_set_size( wasm32::__WASI_ESUCCESS } +#[wasi_common_cbindgen] pub fn path_filestat_get( wasi_ctx: &WasiCtx, memory: &mut [u8], @@ -1098,6 +1124,7 @@ pub fn path_filestat_get( } } +#[wasi_common_cbindgen] pub fn path_filestat_set_times( wasi_ctx: &WasiCtx, memory: &mut [u8], @@ -1171,6 +1198,7 @@ pub fn path_filestat_set_times( wasm32::__WASI_ESUCCESS } +#[wasi_common_cbindgen] pub fn path_symlink( wasi_ctx: &WasiCtx, memory: &mut [u8], @@ -1211,6 +1239,7 @@ pub fn path_symlink( wasm32::__WASI_ESUCCESS } +#[wasi_common_cbindgen] pub fn path_unlink_file( wasi_ctx: &WasiCtx, memory: &mut [u8], @@ -1249,6 +1278,7 @@ pub fn path_unlink_file( } } +#[wasi_common_cbindgen] pub fn path_remove_directory( wasi_ctx: &WasiCtx, memory: &mut [u8], @@ -1280,6 +1310,7 @@ pub fn path_remove_directory( } } +#[wasi_common_cbindgen] pub fn fd_prestat_get( wasi_ctx: &WasiCtx, memory: &mut [u8], @@ -1316,6 +1347,7 @@ pub fn fd_prestat_get( } } +#[wasi_common_cbindgen] pub fn fd_prestat_dir_name( wasi_ctx: &WasiCtx, memory: &mut [u8], diff --git a/src/sys/unix/hostcalls/fs_helpers.rs b/src/sys/unix/hostcalls/fs_helpers.rs index 10f5b43e68..5d1c70bd88 100644 --- a/src/sys/unix/hostcalls/fs_helpers.rs +++ b/src/sys/unix/hostcalls/fs_helpers.rs @@ -1,9 +1,9 @@ #![allow(non_camel_case_types)] #![allow(unused_unsafe)] +use super::host_impl; use crate::ctx::WasiCtx; use crate::host; -use crate::sys::host as host_impl; use nix::libc::{self, c_long}; use std::ffi::{OsStr, OsString}; diff --git a/src/sys/unix/hostcalls/misc.rs b/src/sys/unix/hostcalls/misc.rs index bad79caca1..3c3982bab3 100644 --- a/src/sys/unix/hostcalls/misc.rs +++ b/src/sys/unix/hostcalls/misc.rs @@ -1,15 +1,17 @@ #![allow(non_camel_case_types)] #![allow(unused_unsafe)] +use super::host_impl; use crate::memory::*; use crate::{host, wasm32}; -use crate::sys::host as host_impl; use nix::convert_ioctl_res; use nix::libc::{self, c_int}; use std::cmp; use std::time::SystemTime; +use wasi_common_cbindgen::wasi_common_cbindgen; +#[wasi_common_cbindgen] pub fn clock_res_get( memory: &mut [u8], clock_id: wasm32::__wasi_clockid_t, @@ -49,6 +51,7 @@ pub fn clock_res_get( }) } +#[wasi_common_cbindgen] pub fn clock_time_get( memory: &mut [u8], clock_id: wasm32::__wasi_clockid_t, @@ -85,6 +88,7 @@ pub fn clock_time_get( }) } +#[wasi_common_cbindgen] pub fn poll_oneoff( memory: &mut [u8], input: wasm32::uintptr_t, @@ -176,6 +180,7 @@ pub fn poll_oneoff( wasm32::__WASI_ESUCCESS } +#[wasi_common_cbindgen] pub fn sched_yield() -> wasm32::__wasi_errno_t { unsafe { libc::sched_yield() }; wasm32::__WASI_ESUCCESS diff --git a/src/sys/unix/hostcalls/mod.rs b/src/sys/unix/hostcalls/mod.rs index a0ce8f8ecc..481e90dee9 100644 --- a/src/sys/unix/hostcalls/mod.rs +++ b/src/sys/unix/hostcalls/mod.rs @@ -1,10 +1,13 @@ -//! Hostcalls that implement +//! Unix-specific hostcalls that implement //! [WASI](https://github.com/CraneStation/wasmtime-wasi/blob/wasi/docs/WASI-overview.md). mod fs; mod fs_helpers; mod misc; mod sock; +use super::fdentry; +use super::host_impl; + pub use self::fs::*; pub use self::misc::*; pub use self::sock::*; diff --git a/src/sys/unix/hostcalls/sock.rs b/src/sys/unix/hostcalls/sock.rs index 2dbef5a69f..0d38a3f611 100644 --- a/src/sys/unix/hostcalls/sock.rs +++ b/src/sys/unix/hostcalls/sock.rs @@ -6,6 +6,7 @@ use crate::ctx::WasiCtx; use crate::wasm32; use wasi_common_cbindgen::wasi_common_cbindgen; +#[wasi_common_cbindgen] pub fn sock_recv( wasi_ctx: &WasiCtx, memory: &mut [u8], @@ -19,6 +20,7 @@ pub fn sock_recv( unimplemented!("sock_recv") } +#[wasi_common_cbindgen] pub fn sock_send( wasi_ctx: &WasiCtx, memory: &mut [u8], @@ -31,6 +33,7 @@ pub fn sock_send( unimplemented!("sock_send") } +#[wasi_common_cbindgen] pub fn sock_shutdown( wasi_ctx: &WasiCtx, memory: &mut [u8], @@ -38,4 +41,4 @@ pub fn sock_shutdown( how: wasm32::__wasi_sdflags_t, ) -> wasm32::__wasi_errno_t { unimplemented!("sock_shutdown") -} \ No newline at end of file +} diff --git a/src/sys/unix/mod.rs b/src/sys/unix/mod.rs index 5b200f9fc4..8d9f70ad3c 100644 --- a/src/sys/unix/mod.rs +++ b/src/sys/unix/mod.rs @@ -1,41 +1,6 @@ -pub mod host; +pub mod fdentry; +mod host_impl; pub mod hostcalls; -pub mod fdmap; - -pub mod memory { - use crate::{host, wasm32}; - use crate::memory::*; - - #[cfg(target_os = "linux")] - pub fn dirent_from_host( - host_entry: &nix::libc::dirent, - ) -> Result { - let mut entry = unsafe { std::mem::zeroed::() }; - 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); - } - 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 { - let mut entry = unsafe { std::mem::zeroed::() }; - 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) - } -} pub fn dev_null() -> std::fs::File { std::fs::File::open("/dev/null").expect("failed to open /dev/null") diff --git a/src/sys/windows/fdentry.rs b/src/sys/windows/fdentry.rs new file mode 100644 index 0000000000..c662cf2898 --- /dev/null +++ b/src/sys/windows/fdentry.rs @@ -0,0 +1,89 @@ +use crate::host; + +use std::fs::File; +use std::os::windows::prelude::{AsRawHandle, FromRawHandle, IntoRawHandle, RawHandle}; +use std::path::PathBuf; +use winapi::shared::minwindef::FALSE; +use winapi::um::handleapi::DuplicateHandle; +use winapi::um::processthreadsapi::GetCurrentProcess; +use winapi::um::winnt::DUPLICATE_SAME_ACCESS; + +#[derive(Clone, Debug)] +pub struct FdObject { + pub ty: host::__wasi_filetype_t, + pub raw_handle: RawHandle, + pub needs_close: bool, + // TODO: directories +} + +#[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, +} + +impl Drop for FdObject { + fn drop(&mut self) { + if self.needs_close { + unsafe { + if winapi::um::handleapi::CloseHandle(self.raw_handle) == 0 { + // TODO: use DWORD WINAPI GetLastError(void) to get error + eprintln!("FdObject::drop(): couldn't close raw Handle"); + } + } + } + } +} + +impl FdEntry { + pub fn from_file(file: File) -> Self { + unsafe { Self::from_raw_handle(file.into_raw_handle()) } + } + + pub fn duplicate(fd: &F) -> Self { + unsafe { + let source = fd.as_raw_handle(); + let mut dest = 0 as RawHandle; + + let cur_proc = GetCurrentProcess(); + if DuplicateHandle( + cur_proc, + source, + cur_proc, + &mut dest, + 0, // dwDesiredAccess; this flag is ignored if DUPLICATE_SAME_ACCESS is specified + FALSE, + DUPLICATE_SAME_ACCESS, + ) == FALSE + { + panic!("Couldn't duplicate handle"); + } + + Self::from_raw_handle(dest) + } + } +} + +impl FromRawHandle for FdEntry { + // TODO: implement + unsafe fn from_raw_handle(raw_handle: RawHandle) -> Self { + let (ty, rights_base, rights_inheriting) = ( + host::__WASI_FILETYPE_REGULAR_FILE, + host::RIGHTS_REGULAR_FILE_BASE, + host::RIGHTS_REGULAR_FILE_INHERITING, + ); + + Self { + fd_object: FdObject { + ty, + raw_handle, + needs_close: true, + }, + rights_base, + rights_inheriting, + preopen_path: None, + } + } +} diff --git a/src/sys/windows/host_impl.rs b/src/sys/windows/host_impl.rs new file mode 100644 index 0000000000..63f34166ab --- /dev/null +++ b/src/sys/windows/host_impl.rs @@ -0,0 +1,84 @@ +//! WASI host types specific to Windows host. +#![allow(non_camel_case_types)] +#![allow(non_snake_case)] +#![allow(unused)] +use crate::host; + +use std::marker::PhantomData; +use std::slice; +use winapi::shared::{ntdef, ws2def}; + +// these will be obsolete once https://github.com/rust-lang/rust/pull/60334 +// lands in stable +pub struct IoVec<'a> { + vec: ws2def::WSABUF, + _p: PhantomData<&'a [u8]>, +} + +pub struct IoVecMut<'a> { + vec: ws2def::WSABUF, + _p: PhantomData<&'a mut [u8]>, +} + +impl<'a> IoVec<'a> { + #[inline] + pub fn new(buf: &'a [u8]) -> Self { + assert!(buf.len() <= ntdef::ULONG::max_value() as usize); + Self { + vec: ws2def::WSABUF { + len: buf.len() as ntdef::ULONG, + buf: buf.as_ptr() as *mut u8 as *mut ntdef::CHAR, + }, + _p: PhantomData, + } + } + + #[inline] + pub fn as_slice(&self) -> &[u8] { + unsafe { slice::from_raw_parts(self.vec.buf as *mut u8, self.vec.len as usize) } + } +} + +impl<'a> IoVecMut<'a> { + #[inline] + pub fn new(buf: &'a mut [u8]) -> Self { + assert!(buf.len() <= ntdef::ULONG::max_value() as usize); + Self { + vec: ws2def::WSABUF { + len: buf.len() as ntdef::ULONG, + buf: buf.as_mut_ptr() as *mut u8 as *mut ntdef::CHAR, + }, + _p: PhantomData, + } + } + + #[inline] + pub fn as_slice(&self) -> &[u8] { + unsafe { slice::from_raw_parts(self.vec.buf as *mut u8, self.vec.len as usize) } + } + + #[inline] + pub fn as_mut_slice(&mut self) -> &mut [u8] { + unsafe { slice::from_raw_parts_mut(self.vec.buf as *mut u8, self.vec.len as usize) } + } +} + +pub unsafe fn ciovec_to_win<'a>(ciovec: &'a host::__wasi_ciovec_t) -> IoVec<'a> { + let slice = slice::from_raw_parts(ciovec.buf as *const u8, ciovec.buf_len); + IoVec::new(slice) +} + +pub unsafe fn ciovec_to_win_mut<'a>(ciovec: &'a mut host::__wasi_ciovec_t) -> IoVecMut<'a> { + let slice = slice::from_raw_parts_mut(ciovec.buf as *mut u8, ciovec.buf_len); + IoVecMut::new(slice) +} + +pub unsafe fn iovec_to_win<'a>(iovec: &'a host::__wasi_iovec_t) -> IoVec<'a> { + let slice = slice::from_raw_parts(iovec.buf as *const u8, iovec.buf_len); + IoVec::new(slice) +} + +pub unsafe fn iovec_to_win_mut<'a>(iovec: &'a mut host::__wasi_iovec_t) -> IoVecMut<'a> { + let slice = slice::from_raw_parts_mut(iovec.buf as *mut u8, iovec.buf_len); + IoVecMut::new(slice) +} diff --git a/src/hostcalls/fs.rs b/src/sys/windows/hostcalls/fs.rs similarity index 61% rename from src/hostcalls/fs.rs rename to src/sys/windows/hostcalls/fs.rs index 9aa3c55660..75437fa82d 100644 --- a/src/hostcalls/fs.rs +++ b/src/sys/windows/hostcalls/fs.rs @@ -1,19 +1,25 @@ #![allow(non_camel_case_types)] +#![allow(unused_unsafe)] +#![allow(unused)] +use super::host_impl; +use super::host_impl::IoVec; + use crate::ctx::WasiCtx; -use crate::wasm32; - -use crate::sys::hostcalls as hostcalls_impl; +use crate::memory::*; +use crate::{host, wasm32}; +use std::cmp; +use std::os::windows::prelude::OsStrExt; use wasi_common_cbindgen::wasi_common_cbindgen; #[wasi_common_cbindgen] pub fn fd_close(wasi_ctx: &mut WasiCtx, fd: wasm32::__wasi_fd_t) -> wasm32::__wasi_errno_t { - hostcalls_impl::fd_close(wasi_ctx, fd) + unimplemented!("fd_close") } #[wasi_common_cbindgen] pub fn fd_datasync(wasi_ctx: &WasiCtx, fd: wasm32::__wasi_fd_t) -> wasm32::__wasi_errno_t { - hostcalls_impl::fd_datasync(wasi_ctx, fd) + unimplemented!("fd_datasync") } #[wasi_common_cbindgen] @@ -26,7 +32,7 @@ pub fn fd_pread( offset: wasm32::__wasi_filesize_t, nread: wasm32::uintptr_t, ) -> wasm32::__wasi_errno_t { - hostcalls_impl::fd_pread(wasi_ctx, memory, fd, iovs_ptr, iovs_len, offset, nread) + unimplemented!("fd_pread") } #[wasi_common_cbindgen] @@ -39,7 +45,7 @@ pub fn fd_pwrite( offset: wasm32::__wasi_filesize_t, nwritten: wasm32::uintptr_t, ) -> wasm32::__wasi_errno_t { - hostcalls_impl::fd_pwrite(wasi_ctx, memory, fd, iovs_ptr, iovs_len, offset, nwritten) + unimplemented!("fd_pwrite") } #[wasi_common_cbindgen] @@ -51,7 +57,7 @@ pub fn fd_read( iovs_len: wasm32::size_t, nread: wasm32::uintptr_t, ) -> wasm32::__wasi_errno_t { - hostcalls_impl::fd_read(wasi_ctx, memory, fd, iovs_ptr, iovs_len, nread) + unimplemented!("fd_read") } #[wasi_common_cbindgen] @@ -60,7 +66,7 @@ pub fn fd_renumber( from: wasm32::__wasi_fd_t, to: wasm32::__wasi_fd_t, ) -> wasm32::__wasi_errno_t { - hostcalls_impl::fd_renumber(wasi_ctx, from, to) + unimplemented!("fd_renumber") } #[wasi_common_cbindgen] @@ -72,7 +78,7 @@ pub fn fd_seek( whence: wasm32::__wasi_whence_t, newoffset: wasm32::uintptr_t, ) -> wasm32::__wasi_errno_t { - hostcalls_impl::fd_seek(wasi_ctx, memory, fd, offset, whence, newoffset) + unimplemented!("fd_seek") } #[wasi_common_cbindgen] @@ -82,7 +88,7 @@ pub fn fd_tell( fd: wasm32::__wasi_fd_t, newoffset: wasm32::uintptr_t, ) -> wasm32::__wasi_errno_t { - hostcalls_impl::fd_tell(wasi_ctx, memory, fd, newoffset) + unimplemented!("fd_tell") } #[wasi_common_cbindgen] @@ -90,9 +96,9 @@ pub fn fd_fdstat_get( wasi_ctx: &WasiCtx, memory: &mut [u8], fd: wasm32::__wasi_fd_t, - fdstat_ptr: wasm32::uintptr_t, + fdstat_ptr: wasm32::uintptr_t, // *mut wasm32::__wasi_fdstat_t ) -> wasm32::__wasi_errno_t { - hostcalls_impl::fd_fdstat_get(wasi_ctx, memory, fd, fdstat_ptr) + unimplemented!("fd_fdstat_get") } #[wasi_common_cbindgen] @@ -101,7 +107,7 @@ pub fn fd_fdstat_set_flags( fd: wasm32::__wasi_fd_t, fdflags: wasm32::__wasi_fdflags_t, ) -> wasm32::__wasi_errno_t { - hostcalls_impl::fd_fdstat_set_flags(wasi_ctx, fd, fdflags) + unimplemented!("fd_fdstat_set_flags") } #[wasi_common_cbindgen] @@ -111,12 +117,12 @@ pub fn fd_fdstat_set_rights( fs_rights_base: wasm32::__wasi_rights_t, fs_rights_inheriting: wasm32::__wasi_rights_t, ) -> wasm32::__wasi_errno_t { - hostcalls_impl::fd_fdstat_set_rights(wasi_ctx, fd, fs_rights_base, fs_rights_inheriting) + unimplemented!("fd_fdstat_set_rights") } #[wasi_common_cbindgen] pub fn fd_sync(wasi_ctx: &WasiCtx, fd: wasm32::__wasi_fd_t) -> wasm32::__wasi_errno_t { - hostcalls_impl::fd_sync(wasi_ctx, fd) + unimplemented!("fd_sync") } #[wasi_common_cbindgen] @@ -128,7 +134,46 @@ pub fn fd_write( iovs_len: wasm32::size_t, nwritten: wasm32::uintptr_t, ) -> wasm32::__wasi_errno_t { - hostcalls_impl::fd_write(wasi_ctx, memory, fd, iovs_ptr, iovs_len, nwritten) + use winapi::shared::minwindef::{DWORD, LPVOID}; + use winapi::shared::ws2def::WSABUF; + use winapi::um::fileapi::WriteFile; + + let fd = dec_fd(fd); + let mut iovs = match dec_iovec_slice(memory, iovs_ptr, iovs_len) { + Ok(iovs) => iovs, + Err(e) => return enc_errno(e), + }; + + let fe = match wasi_ctx.get_fd_entry(fd, host::__WASI_RIGHT_FD_WRITE.into(), 0) { + Ok(fe) => fe, + Err(e) => return enc_errno(e), + }; + + let iovs: Vec = iovs + .iter() + .map(|iov| unsafe { host_impl::iovec_to_win(iov) }) + .collect(); + + let buf = iovs + .iter() + .find(|b| !b.as_slice().is_empty()) + .map_or(&[][..], |b| b.as_slice()); + + let mut host_nwritten = 0; + let len = cmp::min(buf.len(), ::max_value() as usize) as DWORD; + unsafe { + WriteFile( + fe.fd_object.raw_handle, + buf.as_ptr() as LPVOID, + len, + &mut host_nwritten, + std::ptr::null_mut(), + ) + }; + + enc_usize_byref(memory, nwritten, host_nwritten as usize) + .map(|_| wasm32::__WASI_ESUCCESS) + .unwrap_or_else(|e| e) } #[wasi_common_cbindgen] @@ -139,7 +184,7 @@ pub fn fd_advise( len: wasm32::__wasi_filesize_t, advice: wasm32::__wasi_advice_t, ) -> wasm32::__wasi_errno_t { - hostcalls_impl::fd_advise(wasi_ctx, fd, offset, len, advice) + unimplemented!("fd_advise") } #[wasi_common_cbindgen] @@ -149,7 +194,7 @@ pub fn fd_allocate( offset: wasm32::__wasi_filesize_t, len: wasm32::__wasi_filesize_t, ) -> wasm32::__wasi_errno_t { - hostcalls_impl::fd_allocate(wasi_ctx, fd, offset, len) + unimplemented!("fd_allocate") } #[wasi_common_cbindgen] @@ -160,7 +205,7 @@ pub fn path_create_directory( path_ptr: wasm32::uintptr_t, path_len: wasm32::size_t, ) -> wasm32::__wasi_errno_t { - hostcalls_impl::path_create_directory(wasi_ctx, memory, dirfd, path_ptr, path_len) + unimplemented!("path_create_directory") } #[wasi_common_cbindgen] @@ -168,24 +213,14 @@ pub fn path_link( wasi_ctx: &WasiCtx, memory: &mut [u8], old_dirfd: wasm32::__wasi_fd_t, - old_flags: wasm32::__wasi_lookupflags_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 { - hostcalls_impl::path_link( - wasi_ctx, - memory, - old_dirfd, - old_flags, - old_path_ptr, - old_path_len, - new_dirfd, - new_path_ptr, - new_path_len, - ) + unimplemented!("path_link") } #[wasi_common_cbindgen] @@ -202,19 +237,7 @@ pub fn path_open( fs_flags: wasm32::__wasi_fdflags_t, fd_out_ptr: wasm32::uintptr_t, ) -> wasm32::__wasi_errno_t { - hostcalls_impl::path_open( - wasi_ctx, - memory, - dirfd, - dirflags, - path_ptr, - path_len, - oflags, - fs_rights_base, - fs_rights_inheriting, - fs_flags, - fd_out_ptr, - ) + unimplemented!("path_open") } #[wasi_common_cbindgen] @@ -227,7 +250,7 @@ pub fn fd_readdir( cookie: wasm32::__wasi_dircookie_t, buf_used: wasm32::uintptr_t, ) -> wasm32::__wasi_errno_t { - hostcalls_impl::fd_readdir(wasi_ctx, memory, fd, buf, buf_len, cookie, buf_used) + unimplemented!("fd_readdir") } #[wasi_common_cbindgen] @@ -241,9 +264,7 @@ pub fn path_readlink( buf_len: wasm32::size_t, buf_used: wasm32::uintptr_t, ) -> wasm32::__wasi_errno_t { - hostcalls_impl::path_readlink( - wasi_ctx, memory, dirfd, path_ptr, path_len, buf_ptr, buf_len, buf_used, - ) + unimplemented!("path_readlink") } #[wasi_common_cbindgen] @@ -257,16 +278,7 @@ pub fn path_rename( new_path_ptr: wasm32::uintptr_t, new_path_len: wasm32::size_t, ) -> wasm32::__wasi_errno_t { - hostcalls_impl::path_rename( - wasi_ctx, - memory, - old_dirfd, - old_path_ptr, - old_path_len, - new_dirfd, - new_path_ptr, - new_path_len, - ) + unimplemented!("path_rename") } #[wasi_common_cbindgen] @@ -276,7 +288,7 @@ pub fn fd_filestat_get( fd: wasm32::__wasi_fd_t, filestat_ptr: wasm32::uintptr_t, ) -> wasm32::__wasi_errno_t { - hostcalls_impl::fd_filestat_get(wasi_ctx, memory, fd, filestat_ptr) + unimplemented!("fd_filestat_get") } #[wasi_common_cbindgen] @@ -287,7 +299,7 @@ pub fn fd_filestat_set_times( st_mtim: wasm32::__wasi_timestamp_t, fst_flags: wasm32::__wasi_fstflags_t, ) -> wasm32::__wasi_errno_t { - hostcalls_impl::fd_filestat_set_times(wasi_ctx, fd, st_atim, st_mtim, fst_flags) + unimplemented!("fd_filestat_set_times") } #[wasi_common_cbindgen] @@ -296,7 +308,7 @@ pub fn fd_filestat_set_size( fd: wasm32::__wasi_fd_t, st_size: wasm32::__wasi_filesize_t, ) -> wasm32::__wasi_errno_t { - hostcalls_impl::fd_filestat_set_size(wasi_ctx, fd, st_size) + unimplemented!("fd_filestat_set_size") } #[wasi_common_cbindgen] @@ -309,15 +321,7 @@ pub fn path_filestat_get( path_len: wasm32::size_t, filestat_ptr: wasm32::uintptr_t, ) -> wasm32::__wasi_errno_t { - hostcalls_impl::path_filestat_get( - wasi_ctx, - memory, - dirfd, - dirflags, - path_ptr, - path_len, - filestat_ptr, - ) + unimplemented!("path_filestat_get") } #[wasi_common_cbindgen] @@ -332,9 +336,7 @@ pub fn path_filestat_set_times( st_mtim: wasm32::__wasi_timestamp_t, fst_flags: wasm32::__wasi_fstflags_t, ) -> wasm32::__wasi_errno_t { - hostcalls_impl::path_filestat_set_times( - wasi_ctx, memory, dirfd, dirflags, path_ptr, path_len, st_atim, st_mtim, fst_flags, - ) + unimplemented!("path_filestat_set_times") } #[wasi_common_cbindgen] @@ -347,15 +349,7 @@ pub fn path_symlink( new_path_ptr: wasm32::uintptr_t, new_path_len: wasm32::size_t, ) -> wasm32::__wasi_errno_t { - hostcalls_impl::path_symlink( - wasi_ctx, - memory, - old_path_ptr, - old_path_len, - dirfd, - new_path_ptr, - new_path_len, - ) + unimplemented!("path_symlink") } #[wasi_common_cbindgen] @@ -366,7 +360,7 @@ pub fn path_unlink_file( path_ptr: wasm32::uintptr_t, path_len: wasm32::size_t, ) -> wasm32::__wasi_errno_t { - hostcalls_impl::path_unlink_file(wasi_ctx, memory, dirfd, path_ptr, path_len) + unimplemented!("path_unlink_file") } #[wasi_common_cbindgen] @@ -377,7 +371,7 @@ pub fn path_remove_directory( path_ptr: wasm32::uintptr_t, path_len: wasm32::size_t, ) -> wasm32::__wasi_errno_t { - hostcalls_impl::path_remove_directory(wasi_ctx, memory, dirfd, path_ptr, path_len) + unimplemented!("path_remove_directory") } #[wasi_common_cbindgen] @@ -387,7 +381,35 @@ pub fn fd_prestat_get( fd: wasm32::__wasi_fd_t, prestat_ptr: wasm32::uintptr_t, ) -> wasm32::__wasi_errno_t { - hostcalls_impl::fd_prestat_get(wasi_ctx, memory, fd, prestat_ptr) + let fd = dec_fd(fd); + // TODO: is this the correct right for this? + match wasi_ctx.get_fd_entry(fd, host::__WASI_RIGHT_PATH_OPEN.into(), 0) { + Ok(fe) => { + if let Some(po_path) = &fe.preopen_path { + if fe.fd_object.ty != host::__WASI_FILETYPE_DIRECTORY { + return wasm32::__WASI_ENOTDIR; + } + enc_prestat_byref( + memory, + prestat_ptr, + host::__wasi_prestat_t { + pr_type: host::__WASI_PREOPENTYPE_DIR, + u: host::__wasi_prestat_t___wasi_prestat_u { + dir: host::__wasi_prestat_t___wasi_prestat_u___wasi_prestat_u_dir_t { + // TODO: clean up + pr_name_len: po_path.as_os_str().encode_wide().count() * 2, + }, + }, + }, + ) + .map(|_| wasm32::__WASI_ESUCCESS) + .unwrap_or_else(|e| e) + } else { + wasm32::__WASI_ENOTSUP + } + } + Err(e) => enc_errno(e), + } } #[wasi_common_cbindgen] @@ -398,5 +420,33 @@ pub fn fd_prestat_dir_name( path_ptr: wasm32::uintptr_t, path_len: wasm32::size_t, ) -> wasm32::__wasi_errno_t { - hostcalls_impl::fd_prestat_dir_name(wasi_ctx, memory, fd, path_ptr, path_len) + let fd = dec_fd(fd); + + match wasi_ctx.get_fd_entry(fd, host::__WASI_RIGHT_PATH_OPEN.into(), 0) { + Ok(fe) => { + if let Some(po_path) = &fe.preopen_path { + if fe.fd_object.ty != host::__WASI_FILETYPE_DIRECTORY { + return wasm32::__WASI_ENOTDIR; + } + // TODO: clean up + let path_bytes = &po_path + .as_os_str() + .encode_wide() + .map(u16::to_le_bytes) + .fold(Vec::new(), |mut acc, bytes| { + acc.extend_from_slice(&bytes); + acc + }); + if path_bytes.len() > dec_usize(path_len) { + return wasm32::__WASI_ENAMETOOLONG; + } + enc_slice_of(memory, path_bytes, path_ptr) + .map(|_| wasm32::__WASI_ESUCCESS) + .unwrap_or_else(|e| e) + } else { + wasm32::__WASI_ENOTSUP + } + } + Err(e) => enc_errno(e), + } } diff --git a/src/sys/windows/hostcalls/misc.rs b/src/sys/windows/hostcalls/misc.rs new file mode 100644 index 0000000000..8bdc8969ef --- /dev/null +++ b/src/sys/windows/hostcalls/misc.rs @@ -0,0 +1,46 @@ +#![allow(non_camel_case_types)] +#![allow(unused_unsafe)] +#![allow(unused)] +use super::host_impl; + +use crate::memory::*; +use crate::{host, wasm32}; + +use std::cmp; +use std::time::SystemTime; +use wasi_common_cbindgen::wasi_common_cbindgen; + +#[wasi_common_cbindgen] +pub fn clock_res_get( + memory: &mut [u8], + clock_id: wasm32::__wasi_clockid_t, + resolution_ptr: wasm32::uintptr_t, +) -> wasm32::__wasi_errno_t { + unimplemented!("clock_res_get") +} + +#[wasi_common_cbindgen] +pub fn clock_time_get( + memory: &mut [u8], + clock_id: wasm32::__wasi_clockid_t, + precision: wasm32::__wasi_timestamp_t, + time_ptr: wasm32::uintptr_t, +) -> wasm32::__wasi_errno_t { + unimplemented!("clock_time_get") +} + +#[wasi_common_cbindgen] +pub fn poll_oneoff( + memory: &mut [u8], + input: wasm32::uintptr_t, + output: wasm32::uintptr_t, + nsubscriptions: wasm32::size_t, + nevents: wasm32::uintptr_t, +) -> wasm32::__wasi_errno_t { + unimplemented!("poll_oneoff") +} + +#[wasi_common_cbindgen] +pub fn sched_yield() -> wasm32::__wasi_errno_t { + unimplemented!("sched_yield") +} diff --git a/src/sys/windows/hostcalls/mod.rs b/src/sys/windows/hostcalls/mod.rs new file mode 100644 index 0000000000..58c6f13021 --- /dev/null +++ b/src/sys/windows/hostcalls/mod.rs @@ -0,0 +1,11 @@ +//! Windows-specific hostcalls that implement +//! [WASI](https://github.com/CraneStation/wasmtime-wasi/blob/wasi/docs/WASI-overview.md). +mod fs; +mod misc; +mod sock; + +use super::host_impl; + +pub use self::fs::*; +pub use self::misc::*; +pub use self::sock::*; diff --git a/src/hostcalls/sock.rs b/src/sys/windows/hostcalls/sock.rs similarity index 67% rename from src/hostcalls/sock.rs rename to src/sys/windows/hostcalls/sock.rs index e3bd80a9c3..0d38a3f611 100644 --- a/src/hostcalls/sock.rs +++ b/src/sys/windows/hostcalls/sock.rs @@ -1,9 +1,9 @@ #![allow(non_camel_case_types)] +#![allow(unused_unsafe)] +#![allow(unused)] + use crate::ctx::WasiCtx; use crate::wasm32; - -use crate::sys::hostcalls as hostcalls_impl; - use wasi_common_cbindgen::wasi_common_cbindgen; #[wasi_common_cbindgen] @@ -17,16 +17,7 @@ pub fn sock_recv( ro_datalen: wasm32::uintptr_t, ro_flags: wasm32::uintptr_t, ) -> wasm32::__wasi_errno_t { - hostcalls_impl::sock_recv( - wasi_ctx, - memory, - sock, - ri_data, - ri_data_len, - ri_flags, - ro_datalen, - ro_flags, - ) + unimplemented!("sock_recv") } #[wasi_common_cbindgen] @@ -39,15 +30,7 @@ pub fn sock_send( si_flags: wasm32::__wasi_siflags_t, so_datalen: wasm32::uintptr_t, ) -> wasm32::__wasi_errno_t { - hostcalls_impl::sock_send( - wasi_ctx, - memory, - sock, - si_data, - si_data_len, - si_flags, - so_datalen, - ) + unimplemented!("sock_send") } #[wasi_common_cbindgen] @@ -57,5 +40,5 @@ pub fn sock_shutdown( sock: wasm32::__wasi_fd_t, how: wasm32::__wasi_sdflags_t, ) -> wasm32::__wasi_errno_t { - hostcalls_impl::sock_shutdown(wasi_ctx, memory, sock, how) + unimplemented!("sock_shutdown") } diff --git a/src/sys/windows/mod.rs b/src/sys/windows/mod.rs index e69de29bb2..fe2c757617 100644 --- a/src/sys/windows/mod.rs +++ b/src/sys/windows/mod.rs @@ -0,0 +1,9 @@ +pub mod fdentry; +mod host_impl; +pub mod hostcalls; + +use std::fs::File; + +pub fn dev_null() -> File { + File::open("NUL").expect("failed to open NUL") +}