diff --git a/crates/c-api/src/wasi.rs b/crates/c-api/src/wasi.rs index a3b3ef8e8444..39e133d7748f 100644 --- a/crates/c-api/src/wasi.rs +++ b/crates/c-api/src/wasi.rs @@ -200,62 +200,85 @@ enum WasiInstance { Snapshot0(WasiSnapshot0), } -macro_rules! config_to_builder { - ($builder:ident, $config:ident) => {{ - let mut builder = $builder::new(); - - if $config.inherit_args { - builder.inherit_args(); - } else if !$config.args.is_empty() { - builder.args($config.args); - } - - if $config.inherit_env { - builder.inherit_env(); - } else if !$config.env.is_empty() { - builder.envs($config.env); - } - - if $config.inherit_stdin { - builder.inherit_stdin(); - } else if let Some(file) = $config.stdin { - builder.stdin(file); - } - - if $config.inherit_stdout { - builder.inherit_stdout(); - } else if let Some(file) = $config.stdout { - builder.stdout(file); - } - - if $config.inherit_stderr { - builder.inherit_stderr(); - } else if let Some(file) = $config.stderr { - builder.stderr(file); - } - - for preopen in $config.preopens { - builder.preopened_dir(preopen.0, preopen.1); - } - - builder - }}; -} - fn create_snapshot0_instance(store: &Store, config: wasi_config_t) -> Result { + let mut builder = WasiSnapshot0CtxBuilder::new(); + if config.inherit_args { + builder.inherit_args(); + } else if !config.args.is_empty() { + builder.args(config.args); + } + if config.inherit_env { + builder.inherit_env(); + } else if !config.env.is_empty() { + builder.envs(config.env); + } + if config.inherit_stdin { + builder.inherit_stdin(); + } else if let Some(file) = config.stdin { + builder.stdin(file); + } + if config.inherit_stdout { + builder.inherit_stdout(); + } else if let Some(file) = config.stdout { + builder.stdout(file); + } + if config.inherit_stderr { + builder.inherit_stderr(); + } else if let Some(file) = config.stderr { + builder.stderr(file); + } + for preopen in config.preopens { + builder.preopened_dir(preopen.0, preopen.1); + } Ok(WasiInstance::Snapshot0(WasiSnapshot0::new( store, - config_to_builder!(WasiSnapshot0CtxBuilder, config) - .build() - .map_err(|e| e.to_string())?, + builder.build().map_err(|e| e.to_string())?, ))) } +fn wasi_preview_builder(config: wasi_config_t) -> Result { + use std::convert::TryFrom; + use wasi_common::OsOther; + let mut builder = WasiPreview1CtxBuilder::new(); + if config.inherit_args { + builder.inherit_args(); + } else if !config.args.is_empty() { + builder.args(config.args); + } + if config.inherit_env { + builder.inherit_env(); + } else if !config.env.is_empty() { + builder.envs(config.env); + } + if config.inherit_stdin { + builder.inherit_stdin(); + } else if let Some(file) = config.stdin { + builder.stdin(OsOther::try_from(file)?); + } + if config.inherit_stdout { + builder.inherit_stdout(); + } else if let Some(file) = config.stdout { + builder.stdout(OsOther::try_from(file)?); + } + if config.inherit_stderr { + builder.inherit_stderr(); + } else if let Some(file) = config.stderr { + builder.stderr(OsOther::try_from(file)?); + } + for preopen in config.preopens { + builder.preopened_dir(preopen.0, preopen.1); + } + Ok(builder) +} + fn create_preview1_instance(store: &Store, config: wasi_config_t) -> Result { Ok(WasiInstance::Preview1(WasiPreview1::new( store, - config_to_builder!(WasiPreview1CtxBuilder, config) - .build() + wasi_preview_builder(config) + .and_then(|mut b| { + let b = b.build()?; + Ok(b) + }) .map_err(|e| e.to_string())?, ))) } diff --git a/crates/test-programs/tests/wasm_tests/runtime.rs b/crates/test-programs/tests/wasm_tests/runtime.rs index 0157a9c61400..a2c4a8f6bdd7 100644 --- a/crates/test-programs/tests/wasm_tests/runtime.rs +++ b/crates/test-programs/tests/wasm_tests/runtime.rs @@ -1,7 +1,8 @@ use anyhow::{bail, Context}; +use std::convert::TryFrom; use std::fs::File; use std::path::Path; -use wasi_common::VirtualDirEntry; +use wasi_common::{OsOther, VirtualDirEntry}; use wasmtime::{Instance, Module, Store}; #[derive(Clone, Copy, Debug)] @@ -46,7 +47,9 @@ pub fn instantiate( // where `stdin` is never ready to be read. In some CI systems, however, // stdin is closed which causes tests to fail. let (reader, _writer) = os_pipe::pipe()?; - builder.stdin(reader_to_file(reader)); + let file = reader_to_file(reader); + let handle = OsOther::try_from(file).context("failed to create OsOther from PipeReader")?; + builder.stdin(handle); let snapshot1 = wasmtime_wasi::Wasi::new(&store, builder.build()?); let module = Module::new(&store, &data).context("failed to create wasm module")?; let imports = module diff --git a/crates/wasi-common/src/ctx.rs b/crates/wasi-common/src/ctx.rs index 895c96ad6f17..3121cb14623c 100644 --- a/crates/wasi-common/src/ctx.rs +++ b/crates/wasi-common/src/ctx.rs @@ -47,7 +47,7 @@ type WasiCtxBuilderResult = std::result::Result; enum PendingEntry { Thunk(fn() -> io::Result>), - OsHandle(File), + Handle(Box), } impl std::fmt::Debug for PendingEntry { @@ -58,7 +58,7 @@ impl std::fmt::Debug for PendingEntry { "PendingEntry::Thunk({:p})", f as *const fn() -> io::Result> ), - Self::OsHandle(f) => write!(fmt, "PendingEntry::OsHandle({:?})", f), + Self::Handle(handle) => write!(fmt, "PendingEntry::Handle({:p})", handle), } } } @@ -247,21 +247,21 @@ impl WasiCtxBuilder { self } - /// Provide a File to use as stdin - pub fn stdin(&mut self, file: File) -> &mut Self { - self.stdin = Some(PendingEntry::OsHandle(file)); + /// Provide a `Handle` to use as stdin + pub fn stdin(&mut self, handle: T) -> &mut Self { + self.stdin = Some(PendingEntry::Handle(Box::new(handle))); self } - /// Provide a File to use as stdout - pub fn stdout(&mut self, file: File) -> &mut Self { - self.stdout = Some(PendingEntry::OsHandle(file)); + /// Provide a `Handle` to use as stdout + pub fn stdout(&mut self, handle: T) -> &mut Self { + self.stdout = Some(PendingEntry::Handle(Box::new(handle))); self } - /// Provide a File to use as stderr - pub fn stderr(&mut self, file: File) -> &mut Self { - self.stderr = Some(PendingEntry::OsHandle(file)); + /// Provide a `Handle` to use as stderr + pub fn stderr(&mut self, handle: T) -> &mut Self { + self.stderr = Some(PendingEntry::Handle(Box::new(handle))); self } @@ -368,9 +368,8 @@ impl WasiCtxBuilder { .insert(entry) .ok_or(WasiCtxBuilderError::TooManyFilesOpen)? } - PendingEntry::OsHandle(f) => { - let handle = OsOther::try_from(f)?; - let handle = EntryHandle::new(handle); + PendingEntry::Handle(handle) => { + let handle = EntryHandle::from(handle); let entry = Entry::new(handle); entries .insert(entry) diff --git a/crates/wasi-common/src/entry.rs b/crates/wasi-common/src/entry.rs index eb311a7b10b2..ba9e90c16089 100644 --- a/crates/wasi-common/src/entry.rs +++ b/crates/wasi-common/src/entry.rs @@ -8,6 +8,7 @@ use std::rc::Rc; pub(crate) struct EntryHandle(Rc); impl EntryHandle { + #[allow(dead_code)] pub(crate) fn new(handle: T) -> Self { Self(Rc::new(handle)) } diff --git a/crates/wasi-common/src/handle.rs b/crates/wasi-common/src/handle.rs index 21a0ab4f2c3e..97a841dfac69 100644 --- a/crates/wasi-common/src/handle.rs +++ b/crates/wasi-common/src/handle.rs @@ -6,38 +6,49 @@ use std::io::{self, SeekFrom}; /// Represents rights of a `Handle`, either already held or required. #[derive(Debug, Copy, Clone)] -pub(crate) struct HandleRights { +pub struct HandleRights { pub(crate) base: Rights, pub(crate) inheriting: Rights, } impl HandleRights { - pub(crate) fn new(base: Rights, inheriting: Rights) -> Self { + /// Creates new `HandleRights` instance from `base` and `inheriting` rights. + pub fn new(base: Rights, inheriting: Rights) -> Self { Self { base, inheriting } } - /// Create new `HandleRights` instance from `base` rights only, keeping + /// Creates new `HandleRights` instance from `base` rights only, keeping /// `inheriting` set to none. - pub(crate) fn from_base(base: Rights) -> Self { + pub fn from_base(base: Rights) -> Self { Self { base, inheriting: Rights::empty(), } } - /// Create new `HandleRights` instance with both `base` and `inheriting` + /// Creates new `HandleRights` instance with both `base` and `inheriting` /// rights set to none. - pub(crate) fn empty() -> Self { + pub fn empty() -> Self { Self { base: Rights::empty(), inheriting: Rights::empty(), } } - /// Check if `other` is a subset of those rights. - pub(crate) fn contains(&self, other: &Self) -> bool { + /// Checks if `other` is a subset of those rights. + pub fn contains(&self, other: &Self) -> bool { self.base.contains(&other.base) && self.inheriting.contains(&other.inheriting) } + + /// Returns base rights. + pub fn base(&self) -> Rights { + self.base + } + + /// Returns inheriting rights. + pub fn inheriting(&self) -> Rights { + self.inheriting + } } impl fmt::Display for HandleRights { @@ -50,7 +61,8 @@ impl fmt::Display for HandleRights { } } -pub(crate) trait Handle { +// TODO docs +pub trait Handle { fn as_any(&self) -> &dyn Any; fn try_clone(&self) -> io::Result>; fn get_file_type(&self) -> types::Filetype; diff --git a/crates/wasi-common/src/lib.rs b/crates/wasi-common/src/lib.rs index 4c0ccf7b4e0a..f9c17841a97a 100644 --- a/crates/wasi-common/src/lib.rs +++ b/crates/wasi-common/src/lib.rs @@ -36,5 +36,9 @@ mod virtfs; pub mod wasi; pub use ctx::{WasiCtx, WasiCtxBuilder, WasiCtxBuilderError}; +pub use handle::{Handle, HandleRights}; +pub use sys::osdir::OsDir; +pub use sys::osfile::OsFile; +pub use sys::osother::{OsOther, OsOtherExt}; pub use sys::preopen_dir; pub use virtfs::{FileContents, VirtualDirEntry}; diff --git a/crates/wasi-common/src/sys/osdir.rs b/crates/wasi-common/src/sys/osdir.rs index 29a69e0c106c..9f16b0f2f116 100644 --- a/crates/wasi-common/src/sys/osdir.rs +++ b/crates/wasi-common/src/sys/osdir.rs @@ -10,7 +10,7 @@ use std::ops::Deref; // TODO could this be cleaned up? // The actual `OsDir` struct is OS-dependent, therefore we delegate // its definition to OS-specific modules. -pub(crate) use super::sys_impl::osdir::OsDir; +pub use super::sys_impl::osdir::OsDir; impl Deref for OsDir { type Target = RawOsHandle; diff --git a/crates/wasi-common/src/sys/osfile.rs b/crates/wasi-common/src/sys/osfile.rs index a3491f5432d9..e9ced03fc673 100644 --- a/crates/wasi-common/src/sys/osfile.rs +++ b/crates/wasi-common/src/sys/osfile.rs @@ -9,7 +9,7 @@ use std::io::{self, Read, Seek, SeekFrom, Write}; use std::ops::Deref; #[derive(Debug)] -pub(crate) struct OsFile { +pub struct OsFile { rights: Cell, handle: RawOsHandle, } diff --git a/crates/wasi-common/src/sys/osother.rs b/crates/wasi-common/src/sys/osother.rs index de30a4f2dd0a..42f15c579b09 100644 --- a/crates/wasi-common/src/sys/osother.rs +++ b/crates/wasi-common/src/sys/osother.rs @@ -10,7 +10,7 @@ use std::fs::File; use std::io::{self, Read, Write}; use std::ops::Deref; -pub(crate) trait OsOtherExt { +pub trait OsOtherExt { /// Create `OsOther` as `dyn Handle` from null device. fn from_null() -> io::Result>; } @@ -21,7 +21,7 @@ pub(crate) trait OsOtherExt { /// pipe should be encapsulated within this instance _and not_ `OsFile` which represents a regular /// OS file. #[derive(Debug)] -pub(crate) struct OsOther { +pub struct OsOther { file_type: Filetype, rights: Cell, handle: RawOsHandle, diff --git a/crates/wasi-common/src/sys/unix/bsd/osdir.rs b/crates/wasi-common/src/sys/unix/bsd/osdir.rs index 0726ad2ef6ed..7baa1939ed02 100644 --- a/crates/wasi-common/src/sys/unix/bsd/osdir.rs +++ b/crates/wasi-common/src/sys/unix/bsd/osdir.rs @@ -6,7 +6,7 @@ use std::io; use yanix::dir::Dir; #[derive(Debug)] -pub(crate) struct OsDir { +pub struct OsDir { pub(crate) rights: Cell, pub(crate) handle: RawOsHandle, // When the client makes a `fd_readdir` syscall on this descriptor, diff --git a/crates/wasi-common/src/sys/unix/linux/osdir.rs b/crates/wasi-common/src/sys/unix/linux/osdir.rs index 2fff99ec7bbf..f15d89a4c5f6 100644 --- a/crates/wasi-common/src/sys/unix/linux/osdir.rs +++ b/crates/wasi-common/src/sys/unix/linux/osdir.rs @@ -6,7 +6,7 @@ use std::io; use yanix::dir::Dir; #[derive(Debug)] -pub(crate) struct OsDir { +pub struct OsDir { pub(crate) rights: Cell, pub(crate) handle: RawOsHandle, } diff --git a/crates/wasi-common/src/sys/unix/osdir.rs b/crates/wasi-common/src/sys/unix/osdir.rs index 47b264208fa5..6c4ba35655fe 100644 --- a/crates/wasi-common/src/sys/unix/osdir.rs +++ b/crates/wasi-common/src/sys/unix/osdir.rs @@ -6,7 +6,7 @@ use std::fs::File; use std::io; use std::os::unix::prelude::{AsRawFd, FromRawFd, IntoRawFd}; -pub(crate) use super::sys_impl::osdir::OsDir; +pub use super::sys_impl::osdir::OsDir; impl TryFrom for OsDir { type Error = io::Error; diff --git a/crates/wasi-common/src/sys/unix/oshandle.rs b/crates/wasi-common/src/sys/unix/oshandle.rs index 513e4b7787ae..b706a5bb0f11 100644 --- a/crates/wasi-common/src/sys/unix/oshandle.rs +++ b/crates/wasi-common/src/sys/unix/oshandle.rs @@ -3,7 +3,7 @@ use std::io; use std::os::unix::prelude::{AsRawFd, FromRawFd, IntoRawFd, RawFd}; #[derive(Debug)] -pub(crate) struct RawOsHandle(File); +pub struct RawOsHandle(File); impl RawOsHandle { /// Tries clone `self`. diff --git a/crates/wasi-common/src/sys/windows/osdir.rs b/crates/wasi-common/src/sys/windows/osdir.rs index 80cee50bce55..132bdceee433 100644 --- a/crates/wasi-common/src/sys/windows/osdir.rs +++ b/crates/wasi-common/src/sys/windows/osdir.rs @@ -8,7 +8,7 @@ use std::io; use std::os::windows::prelude::{AsRawHandle, FromRawHandle, IntoRawHandle}; #[derive(Debug)] -pub(crate) struct OsDir { +pub struct OsDir { pub(crate) rights: Cell, pub(crate) handle: RawOsHandle, } diff --git a/crates/wasi-common/src/sys/windows/oshandle.rs b/crates/wasi-common/src/sys/windows/oshandle.rs index 89884d03a8d9..74aacb80192b 100644 --- a/crates/wasi-common/src/sys/windows/oshandle.rs +++ b/crates/wasi-common/src/sys/windows/oshandle.rs @@ -6,7 +6,7 @@ use std::mem::ManuallyDrop; use std::os::windows::prelude::{AsRawHandle, FromRawHandle, IntoRawHandle, RawHandle}; #[derive(Debug)] -pub(crate) struct RawOsHandle(Cell); +pub struct RawOsHandle(Cell); impl RawOsHandle { /// Tries cloning `self`.