use crate::clocks::WasiClocks; use crate::dir::{DirCaps, DirEntry, WasiDir}; use crate::file::{FileCaps, FileEntry, WasiFile}; use crate::sched::WasiSched; use crate::string_array::{StringArray, StringArrayError}; use crate::table::Table; use crate::Error; use cap_rand::RngCore; use std::cell::{RefCell, RefMut}; use std::path::{Path, PathBuf}; use std::rc::Rc; pub struct WasiCtx { pub args: StringArray, pub env: StringArray, pub random: RefCell>, pub clocks: WasiClocks, pub sched: Box, pub table: Rc>, } impl WasiCtx { pub fn builder( random: RefCell>, clocks: WasiClocks, sched: Box, table: Rc>, ) -> WasiCtxBuilder { WasiCtxBuilder(WasiCtx { args: StringArray::new(), env: StringArray::new(), random, clocks, sched, table, }) } pub fn insert_file(&self, fd: u32, file: Box, caps: FileCaps) { self.table() .insert_at(fd, Box::new(FileEntry::new(caps, file))); } pub fn insert_dir( &self, fd: u32, dir: Box, caps: DirCaps, file_caps: FileCaps, path: PathBuf, ) { self.table().insert_at( fd, Box::new(DirEntry::new(caps, file_caps, Some(path), dir)), ); } pub fn table(&self) -> RefMut { self.table.borrow_mut() } } pub struct WasiCtxBuilder(WasiCtx); impl WasiCtxBuilder { pub fn build(self) -> Result { use crate::file::TableFileExt; let t = self.0.table(); for (fd, name) in ["stdin", "stdout", "stderr"].iter().enumerate() { if t.get_file(fd as u32).is_err() { return Err(anyhow::anyhow!( "Cannot build WasiCtx: Missing required file `{}`", name )); } } drop(t); Ok(self.0) } pub fn arg(mut self, arg: &str) -> Result { self.0.args.push(arg.to_owned())?; Ok(self) } pub fn env(mut self, var: &str, value: &str) -> Result { self.0.env.push(format!("{}={}", var, value))?; Ok(self) } pub fn stdin(self, f: Box) -> Self { self.0.insert_file( 0, f, FileCaps::READ | FileCaps::POLL_READWRITE, // XXX fixme: more rights are ok, but this is read-only ); self } pub fn stdout(self, f: Box) -> Self { self.0.insert_file( 1, f, FileCaps::WRITE | FileCaps::POLL_READWRITE, // XXX fixme: more rights are ok, but this is append only ); self } pub fn stderr(self, f: Box) -> Self { self.0.insert_file( 2, f, FileCaps::WRITE | FileCaps::POLL_READWRITE, // XXX fixme: more rights are ok, but this is append only ); self } pub fn preopened_dir( self, dir: Box, path: impl AsRef, ) -> Result { let caps = DirCaps::all(); let file_caps = FileCaps::all(); self.0.table().push(Box::new(DirEntry::new( caps, file_caps, Some(path.as_ref().to_owned()), dir, )))?; Ok(self) } }