diff --git a/crates/c-api/include/wasi.h b/crates/c-api/include/wasi.h index 869f99ff6800..80e617e907f9 100644 --- a/crates/c-api/include/wasi.h +++ b/crates/c-api/include/wasi.h @@ -55,8 +55,11 @@ WASI_API_EXTERN own wasi_config_t *wasi_config_new(); * * The arguments are copied into the `config` object as part of this function * call, so the `argv` pointer only needs to stay alive for this function call. + * + * This function returns `true` if all arguments were registered successfully, + * or `false` if an argument was not valid UTF-8. */ -WASI_API_EXTERN void wasi_config_set_argv(wasi_config_t *config, int argc, +WASI_API_EXTERN bool wasi_config_set_argv(wasi_config_t *config, size_t argc, const char *argv[]); /** @@ -76,8 +79,12 @@ WASI_API_EXTERN void wasi_config_inherit_argv(wasi_config_t *config); * The env vars are copied into the `config` object as part of this function * call, so the `names` and `values` pointers only need to stay alive for this * function call. + * + * This function returns `true` if all environment variables were successfully + * registered. This returns `false` if environment variables are not valid + * UTF-8. */ -WASI_API_EXTERN void wasi_config_set_env(wasi_config_t *config, int envc, +WASI_API_EXTERN bool wasi_config_set_env(wasi_config_t *config, size_t envc, const char *names[], const char *values[]); diff --git a/crates/c-api/src/wasi.rs b/crates/c-api/src/wasi.rs index 08ce94cf972c..3f638cd5bfe1 100644 --- a/crates/c-api/src/wasi.rs +++ b/crates/c-api/src/wasi.rs @@ -2,10 +2,9 @@ use crate::wasm_byte_vec_t; use anyhow::Result; -use std::ffi::CStr; +use std::ffi::{c_char, CStr}; use std::fs::File; -use std::os::raw::{c_char, c_int}; -use std::path::{Path, PathBuf}; +use std::path::Path; use std::slice; use wasmtime_wasi::{preview1::WasiP1Ctx, WasiCtxBuilder}; @@ -26,163 +25,73 @@ unsafe fn create_file(path: *const c_char) -> Option { } #[repr(C)] -#[derive(Default)] pub struct wasi_config_t { - args: Vec>, - env: Vec<(Vec, Vec)>, - stdin: WasiConfigReadPipe, - stdout: WasiConfigWritePipe, - stderr: WasiConfigWritePipe, - preopen_dirs: Vec<(PathBuf, String)>, - inherit_args: bool, - inherit_env: bool, -} - -#[repr(C)] -#[derive(Default)] -pub enum WasiConfigReadPipe { - #[default] - None, - Inherit, - File(File), - Bytes(Vec), -} - -#[repr(C)] -#[derive(Default)] -pub enum WasiConfigWritePipe { - #[default] - None, - Inherit, - File(File), + builder: WasiCtxBuilder, } wasmtime_c_api_macros::declare_own!(wasi_config_t); impl wasi_config_t { - pub fn into_wasi_ctx(self) -> Result { - let mut builder = WasiCtxBuilder::new(); - if self.inherit_args { - builder.inherit_args(); - } else if !self.args.is_empty() { - let args = self - .args - .into_iter() - .map(|bytes| Ok(String::from_utf8(bytes)?)) - .collect::>>()?; - builder.args(&args); - } - if self.inherit_env { - builder.inherit_env(); - } else if !self.env.is_empty() { - let env = self - .env - .into_iter() - .map(|(kbytes, vbytes)| { - let k = String::from_utf8(kbytes)?; - let v = String::from_utf8(vbytes)?; - Ok((k, v)) - }) - .collect::>>()?; - builder.envs(&env); - } - match self.stdin { - WasiConfigReadPipe::None => {} - WasiConfigReadPipe::Inherit => { - builder.inherit_stdin(); - } - WasiConfigReadPipe::File(file) => { - let file = tokio::fs::File::from_std(file); - let stdin_stream = wasmtime_wasi::AsyncStdinStream::new( - wasmtime_wasi::pipe::AsyncReadStream::new(file), - ); - builder.stdin(stdin_stream); - } - WasiConfigReadPipe::Bytes(binary) => { - let binary = wasmtime_wasi::pipe::MemoryInputPipe::new(binary); - builder.stdin(binary); - } - }; - match self.stdout { - WasiConfigWritePipe::None => {} - WasiConfigWritePipe::Inherit => { - builder.inherit_stdout(); - } - WasiConfigWritePipe::File(file) => { - builder.stdout(wasmtime_wasi::OutputFile::new(file)); - } - }; - match self.stderr { - WasiConfigWritePipe::None => {} - WasiConfigWritePipe::Inherit => { - builder.inherit_stderr(); - } - WasiConfigWritePipe::File(file) => { - builder.stderr(wasmtime_wasi::OutputFile::new(file)); - } - }; - for (host_path, guest_path) in self.preopen_dirs { - builder.preopened_dir( - host_path, - guest_path, - wasmtime_wasi::DirPerms::all(), - wasmtime_wasi::FilePerms::all(), - )?; - } - Ok(builder.build_p1()) + pub fn into_wasi_ctx(mut self) -> Result { + Ok(self.builder.build_p1()) } } #[no_mangle] pub extern "C" fn wasi_config_new() -> Box { - Box::new(wasi_config_t::default()) + Box::new(wasi_config_t { + builder: WasiCtxBuilder::new(), + }) } #[no_mangle] pub unsafe extern "C" fn wasi_config_set_argv( config: &mut wasi_config_t, - argc: c_int, + argc: usize, argv: *const *const c_char, -) { - config.args = slice::from_raw_parts(argv, argc as usize) - .iter() - .map(|p| CStr::from_ptr(*p).to_bytes().to_owned()) - .collect(); - config.inherit_args = false; +) -> bool { + for arg in slice::from_raw_parts(argv, argc) { + let arg = match CStr::from_ptr(*arg).to_str() { + Ok(s) => s, + Err(_) => return false, + }; + config.builder.arg(arg); + } + true } #[no_mangle] pub extern "C" fn wasi_config_inherit_argv(config: &mut wasi_config_t) { - config.args.clear(); - config.inherit_args = true; + config.builder.inherit_args(); } #[no_mangle] pub unsafe extern "C" fn wasi_config_set_env( config: &mut wasi_config_t, - envc: c_int, + envc: usize, names: *const *const c_char, values: *const *const c_char, -) { - let names = slice::from_raw_parts(names, envc as usize); - let values = slice::from_raw_parts(values, envc as usize); +) -> bool { + let names = slice::from_raw_parts(names, envc); + let values = slice::from_raw_parts(values, envc); - config.env = names - .iter() - .map(|p| CStr::from_ptr(*p).to_bytes().to_owned()) - .zip( - values - .iter() - .map(|p| CStr::from_ptr(*p).to_bytes().to_owned()), - ) - .collect(); - config.inherit_env = false; + for (k, v) in names.iter().zip(values) { + let k = match cstr_to_str(*k) { + Some(s) => s, + None => return false, + }; + let v = match cstr_to_str(*v) { + Some(s) => s, + None => return false, + }; + config.builder.env(k, v); + } + true } #[no_mangle] pub extern "C" fn wasi_config_inherit_env(config: &mut wasi_config_t) { - config.env.clear(); - config.inherit_env = true; + config.builder.inherit_env(); } #[no_mangle] @@ -195,7 +104,10 @@ pub unsafe extern "C" fn wasi_config_set_stdin_file( None => return false, }; - config.stdin = WasiConfigReadPipe::File(file); + let file = tokio::fs::File::from_std(file); + let stdin_stream = + wasmtime_wasi::AsyncStdinStream::new(wasmtime_wasi::pipe::AsyncReadStream::new(file)); + config.builder.stdin(stdin_stream); true } @@ -206,13 +118,13 @@ pub unsafe extern "C" fn wasi_config_set_stdin_bytes( binary: &mut wasm_byte_vec_t, ) { let binary = binary.take(); - - config.stdin = WasiConfigReadPipe::Bytes(binary); + let binary = wasmtime_wasi::pipe::MemoryInputPipe::new(binary); + config.builder.stdin(binary); } #[no_mangle] pub extern "C" fn wasi_config_inherit_stdin(config: &mut wasi_config_t) { - config.stdin = WasiConfigReadPipe::Inherit; + config.builder.inherit_stdin(); } #[no_mangle] @@ -225,14 +137,14 @@ pub unsafe extern "C" fn wasi_config_set_stdout_file( None => return false, }; - config.stdout = WasiConfigWritePipe::File(file); + config.builder.stdout(wasmtime_wasi::OutputFile::new(file)); true } #[no_mangle] pub extern "C" fn wasi_config_inherit_stdout(config: &mut wasi_config_t) { - config.stdout = WasiConfigWritePipe::Inherit; + config.builder.inherit_stdout(); } #[no_mangle] @@ -245,14 +157,14 @@ pub unsafe extern "C" fn wasi_config_set_stderr_file( None => return false, }; - config.stderr = WasiConfigWritePipe::File(file); + config.builder.stderr(wasmtime_wasi::OutputFile::new(file)); true } #[no_mangle] pub extern "C" fn wasi_config_inherit_stderr(config: &mut wasi_config_t) { - config.stderr = WasiConfigWritePipe::Inherit; + config.builder.inherit_stderr(); } #[no_mangle] @@ -271,9 +183,13 @@ pub unsafe extern "C" fn wasi_config_preopen_dir( None => return false, }; - (*config) - .preopen_dirs - .push((host_path.to_owned(), guest_path.to_owned())); - - true + config + .builder + .preopened_dir( + host_path, + guest_path, + wasmtime_wasi::DirPerms::all(), + wasmtime_wasi::FilePerms::all(), + ) + .is_ok() }