fill in more implementations, support preopens

This commit is contained in:
Pat Hickey
2020-12-01 18:26:45 -08:00
parent beaad53dc0
commit 40f8f69e03
4 changed files with 165 additions and 17 deletions

View File

@@ -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()
}

View File

@@ -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 {

View File

@@ -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(

View File

@@ -16,11 +16,24 @@ impl Table {
}
}
pub fn insert(&mut self, a: impl Any + Sized) -> u32 {
pub fn insert_at(&mut self, key: u32, a: impl Any + Sized) {
self.map.insert(key, RefCell::new(Box::new(a)));
}
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)));
key
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