fill in more implementations, support preopens
This commit is contained in:
@@ -1,18 +1,50 @@
|
||||
use crate::file::{FileCaps, FileEntry, WasiFile};
|
||||
use crate::table::Table;
|
||||
use std::cell::{RefCell, RefMut};
|
||||
use std::collections::HashMap;
|
||||
use std::path::PathBuf;
|
||||
use std::rc::Rc;
|
||||
|
||||
pub struct WasiCtx {
|
||||
table: Rc<RefCell<Table>>,
|
||||
preopen_paths: RefCell<HashMap<u32, Option<PathBuf>>>,
|
||||
}
|
||||
|
||||
impl WasiCtx {
|
||||
pub fn new() -> Self {
|
||||
WasiCtx {
|
||||
table: Rc::new(RefCell::new(Table::new())),
|
||||
preopen_paths: RefCell::new(HashMap::new()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn preopen_file(
|
||||
&self,
|
||||
fd: u32,
|
||||
file: Box<dyn WasiFile>,
|
||||
base_caps: FileCaps,
|
||||
inheriting_caps: FileCaps,
|
||||
path: Option<PathBuf>,
|
||||
) {
|
||||
let e = FileEntry {
|
||||
base_caps,
|
||||
inheriting_caps,
|
||||
file,
|
||||
};
|
||||
self.table().insert_at(fd, e);
|
||||
self.preopen_paths.borrow_mut().insert(fd, path);
|
||||
}
|
||||
|
||||
pub fn preopen_dir(&self, fd: u32, dir: Box<dyn WasiDir>, flags: u32, path: PathBuf) {
|
||||
let e = DirEntry { flags, dir };
|
||||
self.table().insert_at(fd, e);
|
||||
self.preopen_paths.borrow_mut().insert(fd, Some(path));
|
||||
}
|
||||
|
||||
pub fn is_preopen(&self, fd: u32) -> bool {
|
||||
self.preopen_paths.borrow().contains_key(&fd)
|
||||
}
|
||||
|
||||
pub fn table(&self) -> RefMut<Table> {
|
||||
self.table.borrow_mut()
|
||||
}
|
||||
|
||||
@@ -127,10 +127,15 @@ impl FileCaps {
|
||||
pub const FILESTAT_GET: Self = FileCaps { flags: 512 };
|
||||
pub const FILESTAT_SET_SIZE: Self = FileCaps { flags: 1024 };
|
||||
pub const FILESTAT_SET_TIMES: Self = FileCaps { flags: 2048 };
|
||||
// This isnt in wasi-common, but lets use a cap to check
|
||||
// if its valid to close a file, rather than depend on
|
||||
// preopen logic
|
||||
pub const CLOSE: Self = FileCaps { flags: 4096 };
|
||||
}
|
||||
|
||||
impl std::ops::BitOr for FileCaps {
|
||||
type Output = FileCaps;
|
||||
fn bitor(self, rhs: FileCaps) -> FileCaps {
|
||||
FileCaps {
|
||||
flags: self.flags | rhs.flags,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for FileCaps {
|
||||
|
||||
@@ -3,6 +3,7 @@ use crate::file::{FileCaps, FileEntry, Filestat, FilestatSetTime, Filetype, OFla
|
||||
use crate::{Error, WasiCtx};
|
||||
use std::cell::RefMut;
|
||||
use std::convert::TryFrom;
|
||||
use std::io::{IoSlice, IoSliceMut};
|
||||
use std::ops::Deref;
|
||||
use tracing::debug;
|
||||
use wiggle::GuestPtr;
|
||||
@@ -160,11 +161,16 @@ impl<'a> wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiCtx {
|
||||
|
||||
fn fd_close(&self, fd: types::Fd) -> Result<(), Error> {
|
||||
let mut table = self.table();
|
||||
let file_entry: RefMut<FileEntry> = table.get(u32::from(fd))?;
|
||||
let f = file_entry.get_cap(FileCaps::CLOSE)?;
|
||||
drop(f);
|
||||
let fd = u32::from(fd);
|
||||
// Can't close preopens:
|
||||
if self.is_preopen(fd) {
|
||||
return Err(Error::Notsup);
|
||||
}
|
||||
// Make sure file to close exists as a File:
|
||||
let file_entry: RefMut<FileEntry> = table.get(fd)?;
|
||||
drop(file_entry);
|
||||
let _ = table.delete(u32::from(fd));
|
||||
// Delete from table, Drop will close it
|
||||
let _ = table.delete(fd);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -271,7 +277,26 @@ impl<'a> wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiCtx {
|
||||
}
|
||||
|
||||
fn fd_read(&self, fd: types::Fd, iovs: &types::IovecArray<'_>) -> Result<types::Size, Error> {
|
||||
unimplemented!()
|
||||
let table = self.table();
|
||||
let file_entry: RefMut<FileEntry> = table.get(u32::from(fd))?;
|
||||
let f = file_entry.get_cap(FileCaps::READ)?;
|
||||
|
||||
let mut guest_slices: Vec<wiggle::GuestSliceMut<u8>> = iovs
|
||||
.iter()
|
||||
.map(|iov_ptr| {
|
||||
let iov_ptr = iov_ptr?;
|
||||
let iov: types::Iovec = iov_ptr.read()?;
|
||||
Ok(iov.buf.as_array(iov.buf_len).as_slice_mut()?)
|
||||
})
|
||||
.collect::<Result<_, Error>>()?;
|
||||
|
||||
let mut ioslices: Vec<IoSliceMut> = guest_slices
|
||||
.iter_mut()
|
||||
.map(|s| IoSliceMut::new(&mut *s))
|
||||
.collect();
|
||||
|
||||
let bytes_read = f.read_vectored(&mut ioslices)?;
|
||||
Ok(types::Size::try_from(bytes_read)?)
|
||||
}
|
||||
|
||||
fn fd_pread(
|
||||
@@ -280,7 +305,26 @@ impl<'a> wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiCtx {
|
||||
iovs: &types::IovecArray<'_>,
|
||||
offset: types::Filesize,
|
||||
) -> Result<types::Size, Error> {
|
||||
unimplemented!()
|
||||
let table = self.table();
|
||||
let file_entry: RefMut<FileEntry> = table.get(u32::from(fd))?;
|
||||
let f = file_entry.get_cap(FileCaps::READ | FileCaps::SEEK)?;
|
||||
|
||||
let mut guest_slices: Vec<wiggle::GuestSliceMut<u8>> = iovs
|
||||
.iter()
|
||||
.map(|iov_ptr| {
|
||||
let iov_ptr = iov_ptr?;
|
||||
let iov: types::Iovec = iov_ptr.read()?;
|
||||
Ok(iov.buf.as_array(iov.buf_len).as_slice_mut()?)
|
||||
})
|
||||
.collect::<Result<_, Error>>()?;
|
||||
|
||||
let mut ioslices: Vec<IoSliceMut> = guest_slices
|
||||
.iter_mut()
|
||||
.map(|s| IoSliceMut::new(&mut *s))
|
||||
.collect();
|
||||
|
||||
let bytes_read = f.read_vectored_at(&mut ioslices, offset)?;
|
||||
Ok(types::Size::try_from(bytes_read)?)
|
||||
}
|
||||
|
||||
fn fd_write(
|
||||
@@ -288,7 +332,26 @@ impl<'a> wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiCtx {
|
||||
fd: types::Fd,
|
||||
ciovs: &types::CiovecArray<'_>,
|
||||
) -> Result<types::Size, Error> {
|
||||
unimplemented!()
|
||||
let table = self.table();
|
||||
let file_entry: RefMut<FileEntry> = table.get(u32::from(fd))?;
|
||||
let f = file_entry.get_cap(FileCaps::WRITE)?;
|
||||
|
||||
let guest_slices: Vec<wiggle::GuestSlice<u8>> = ciovs
|
||||
.iter()
|
||||
.map(|iov_ptr| {
|
||||
let iov_ptr = iov_ptr?;
|
||||
let iov: types::Ciovec = iov_ptr.read()?;
|
||||
Ok(iov.buf.as_array(iov.buf_len).as_slice()?)
|
||||
})
|
||||
.collect::<Result<_, Error>>()?;
|
||||
|
||||
let ioslices: Vec<IoSlice> = guest_slices
|
||||
.iter()
|
||||
.map(|s| IoSlice::new(s.deref()))
|
||||
.collect();
|
||||
let bytes_written = f.write_vectored(&ioslices)?;
|
||||
|
||||
Ok(types::Size::try_from(bytes_written)?)
|
||||
}
|
||||
|
||||
fn fd_pwrite(
|
||||
@@ -297,7 +360,26 @@ impl<'a> wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiCtx {
|
||||
ciovs: &types::CiovecArray<'_>,
|
||||
offset: types::Filesize,
|
||||
) -> Result<types::Size, Error> {
|
||||
unimplemented!()
|
||||
let table = self.table();
|
||||
let file_entry: RefMut<FileEntry> = table.get(u32::from(fd))?;
|
||||
let f = file_entry.get_cap(FileCaps::WRITE | FileCaps::SEEK)?;
|
||||
|
||||
let guest_slices: Vec<wiggle::GuestSlice<u8>> = ciovs
|
||||
.iter()
|
||||
.map(|iov_ptr| {
|
||||
let iov_ptr = iov_ptr?;
|
||||
let iov: types::Ciovec = iov_ptr.read()?;
|
||||
Ok(iov.buf.as_array(iov.buf_len).as_slice()?)
|
||||
})
|
||||
.collect::<Result<_, Error>>()?;
|
||||
|
||||
let ioslices: Vec<IoSlice> = guest_slices
|
||||
.iter()
|
||||
.map(|s| IoSlice::new(s.deref()))
|
||||
.collect();
|
||||
let bytes_written = f.write_vectored_at(&ioslices, offset)?;
|
||||
|
||||
Ok(types::Size::try_from(bytes_written)?)
|
||||
}
|
||||
|
||||
fn fd_prestat_get(&self, fd: types::Fd) -> Result<types::Prestat, Error> {
|
||||
@@ -324,7 +406,23 @@ impl<'a> wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiCtx {
|
||||
}
|
||||
|
||||
fn fd_renumber(&self, from: types::Fd, to: types::Fd) -> Result<(), Error> {
|
||||
unimplemented!()
|
||||
let mut table = self.table();
|
||||
let from = u32::from(from);
|
||||
let to = u32::from(to);
|
||||
if !table.contains_key(from) {
|
||||
return Err(Error::Badf);
|
||||
}
|
||||
if self.is_preopen(from) {
|
||||
return Err(Error::Notsup);
|
||||
}
|
||||
if self.is_preopen(to) {
|
||||
return Err(Error::Notsup);
|
||||
}
|
||||
let from_entry = table
|
||||
.delete(from)
|
||||
.expect("we checked that table contains from");
|
||||
table.insert_at(to, from_entry);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn fd_seek(
|
||||
|
||||
@@ -16,11 +16,24 @@ impl Table {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn insert(&mut self, a: impl Any + Sized) -> u32 {
|
||||
let key = self.next_key;
|
||||
self.next_key += 1;
|
||||
pub fn insert_at(&mut self, key: u32, a: impl Any + Sized) {
|
||||
self.map.insert(key, RefCell::new(Box::new(a)));
|
||||
key
|
||||
}
|
||||
|
||||
pub fn push(&mut self, a: impl Any + Sized) -> u32 {
|
||||
loop {
|
||||
let key = self.next_key;
|
||||
self.next_key += 1;
|
||||
if self.map.contains_key(&key) {
|
||||
continue;
|
||||
}
|
||||
self.map.insert(key, RefCell::new(Box::new(a)));
|
||||
return key;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn contains_key(&self, key: u32) -> bool {
|
||||
self.map.contains_key(&key)
|
||||
}
|
||||
|
||||
// Todo: we can refine these errors and translate them to Exist at abi
|
||||
|
||||
Reference in New Issue
Block a user