change the preopen strategy again, implement more calls
This commit is contained in:
@@ -1,24 +1,22 @@
|
|||||||
|
use crate::dir::{DirEntry, WasiDir};
|
||||||
use crate::file::{FileCaps, FileEntry, WasiFile};
|
use crate::file::{FileCaps, FileEntry, WasiFile};
|
||||||
use crate::table::Table;
|
use crate::table::Table;
|
||||||
use std::cell::{RefCell, RefMut};
|
use std::cell::{RefCell, RefMut};
|
||||||
use std::collections::HashMap;
|
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
pub struct WasiCtx {
|
pub struct WasiCtx {
|
||||||
table: Rc<RefCell<Table>>,
|
table: Rc<RefCell<Table>>,
|
||||||
preopen_paths: RefCell<HashMap<u32, Option<PathBuf>>>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WasiCtx {
|
impl WasiCtx {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
WasiCtx {
|
WasiCtx {
|
||||||
table: Rc::new(RefCell::new(Table::new())),
|
table: Rc::new(RefCell::new(Table::new())),
|
||||||
preopen_paths: RefCell::new(HashMap::new()),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn preopen_file(
|
pub fn insert_file(
|
||||||
&self,
|
&self,
|
||||||
fd: u32,
|
fd: u32,
|
||||||
file: Box<dyn WasiFile>,
|
file: Box<dyn WasiFile>,
|
||||||
@@ -32,27 +30,18 @@ impl WasiCtx {
|
|||||||
file,
|
file,
|
||||||
};
|
};
|
||||||
self.table().insert_at(fd, e);
|
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) {
|
pub fn insert_dir(&self, fd: u32, dir: Box<dyn WasiDir>, flags: u32, path: PathBuf) {
|
||||||
let e = DirEntry { flags, dir };
|
let e = DirEntry {
|
||||||
|
flags,
|
||||||
|
preopen_path: Some(path),
|
||||||
|
dir,
|
||||||
|
};
|
||||||
self.table().insert_at(fd, e);
|
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> {
|
pub fn table(&self) -> RefMut<Table> {
|
||||||
self.table.borrow_mut()
|
self.table.borrow_mut()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait WasiDir {}
|
|
||||||
|
|
||||||
pub(crate) struct DirEntry {
|
|
||||||
pub(crate) flags: u32,
|
|
||||||
pub(crate) dir: Box<dyn WasiDir>,
|
|
||||||
}
|
|
||||||
|
|||||||
24
crates/wasi-c2/src/dir.rs
Normal file
24
crates/wasi-c2/src/dir.rs
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
pub trait WasiDir {}
|
||||||
|
|
||||||
|
pub(crate) struct DirEntry {
|
||||||
|
pub(crate) flags: u32,
|
||||||
|
pub(crate) preopen_path: Option<PathBuf>, // precondition: PathBuf is valid unicode
|
||||||
|
pub(crate) dir: Box<dyn WasiDir>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait TableDirExt {
|
||||||
|
fn is_preopen(&self, fd: u32) -> bool;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TableDirExt for crate::table::Table {
|
||||||
|
fn is_preopen(&self, fd: u32) -> bool {
|
||||||
|
if self.is::<DirEntry>(fd) {
|
||||||
|
let dir_entry: std::cell::RefMut<DirEntry> = self.get(fd).unwrap();
|
||||||
|
dir_entry.preopen_path.is_some()
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -31,6 +31,9 @@ pub trait WasiFile: FileIoExt {
|
|||||||
fn filestat_set_size(&self, _size: u64) -> Result<(), Error> {
|
fn filestat_set_size(&self, _size: u64) -> Result<(), Error> {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
fn sync(&self) -> Result<(), Error> {
|
||||||
|
todo!("FileIoExt has no facilities for sync")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone)]
|
#[derive(Debug, Copy, Clone)]
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
mod ctx;
|
mod ctx;
|
||||||
|
mod dir;
|
||||||
mod error;
|
mod error;
|
||||||
mod file;
|
mod file;
|
||||||
pub mod snapshots;
|
pub mod snapshots;
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
#![allow(unused_variables)]
|
#![allow(unused_variables)]
|
||||||
|
use crate::dir::{DirEntry, TableDirExt};
|
||||||
use crate::file::{FileCaps, FileEntry, Filestat, FilestatSetTime, Filetype, OFlags};
|
use crate::file::{FileCaps, FileEntry, Filestat, FilestatSetTime, Filetype, OFlags};
|
||||||
use crate::{Error, WasiCtx};
|
use crate::{Error, WasiCtx};
|
||||||
use std::cell::RefMut;
|
use std::cell::RefMut;
|
||||||
@@ -162,15 +163,20 @@ impl<'a> wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiCtx {
|
|||||||
fn fd_close(&self, fd: types::Fd) -> Result<(), Error> {
|
fn fd_close(&self, fd: types::Fd) -> Result<(), Error> {
|
||||||
let mut table = self.table();
|
let mut table = self.table();
|
||||||
let fd = u32::from(fd);
|
let fd = u32::from(fd);
|
||||||
// Can't close preopens:
|
|
||||||
if self.is_preopen(fd) {
|
// fd_close must close either a File or a Dir handle
|
||||||
|
if table.is::<FileEntry>(fd) {
|
||||||
|
let _ = table.delete(fd);
|
||||||
|
} else if table.is::<DirEntry>(fd) {
|
||||||
|
// We cannot close preopened directories
|
||||||
|
let dir_entry: RefMut<DirEntry> = table.get(fd).unwrap();
|
||||||
|
if dir_entry.preopen_path.is_some() {
|
||||||
return Err(Error::Notsup);
|
return Err(Error::Notsup);
|
||||||
}
|
}
|
||||||
// Make sure file to close exists as a File:
|
drop(dir_entry);
|
||||||
let file_entry: RefMut<FileEntry> = table.get(fd)?;
|
|
||||||
drop(file_entry);
|
|
||||||
// Delete from table, Drop will close it
|
|
||||||
let _ = table.delete(fd);
|
let _ = table.delete(fd);
|
||||||
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -383,16 +389,38 @@ impl<'a> wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiCtx {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn fd_prestat_get(&self, fd: types::Fd) -> Result<types::Prestat, Error> {
|
fn fd_prestat_get(&self, fd: types::Fd) -> Result<types::Prestat, Error> {
|
||||||
unimplemented!()
|
let table = self.table();
|
||||||
|
let dir_entry: RefMut<DirEntry> = table.get(u32::from(fd)).map_err(|_| Error::Notdir)?;
|
||||||
|
if let Some(ref preopen) = dir_entry.preopen_path {
|
||||||
|
let path_str = preopen.to_str().ok_or(Error::Notsup)?;
|
||||||
|
let pr_name_len =
|
||||||
|
u32::try_from(path_str.as_bytes().len()).map_err(|_| Error::Overflow)?;
|
||||||
|
Ok(types::Prestat::Dir(types::PrestatDir { pr_name_len }))
|
||||||
|
} else {
|
||||||
|
Err(Error::Notsup)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fd_prestat_dir_name(
|
fn fd_prestat_dir_name(
|
||||||
&self,
|
&self,
|
||||||
fd: types::Fd,
|
fd: types::Fd,
|
||||||
path: &GuestPtr<u8>,
|
path: &GuestPtr<u8>,
|
||||||
path_len: types::Size,
|
path_max_len: types::Size,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
unimplemented!()
|
let table = self.table();
|
||||||
|
let dir_entry: RefMut<DirEntry> = table.get(u32::from(fd)).map_err(|_| Error::Notdir)?;
|
||||||
|
if let Some(ref preopen) = dir_entry.preopen_path {
|
||||||
|
let path_bytes = preopen.to_str().ok_or(Error::Notsup)?.as_bytes();
|
||||||
|
let path_len = path_bytes.len();
|
||||||
|
if path_len < path_max_len as usize {
|
||||||
|
return Err(Error::Nametoolong);
|
||||||
|
}
|
||||||
|
let mut p_memory = path.as_array(path_len as u32).as_slice_mut()?;
|
||||||
|
p_memory.copy_from_slice(path_bytes);
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(Error::Notsup)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fd_readdir(
|
fn fd_readdir(
|
||||||
@@ -402,7 +430,7 @@ impl<'a> wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiCtx {
|
|||||||
buf_len: types::Size,
|
buf_len: types::Size,
|
||||||
cookie: types::Dircookie,
|
cookie: types::Dircookie,
|
||||||
) -> Result<types::Size, Error> {
|
) -> Result<types::Size, Error> {
|
||||||
unimplemented!()
|
todo!("fd_readdir is very complicated")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fd_renumber(&self, from: types::Fd, to: types::Fd) -> Result<(), Error> {
|
fn fd_renumber(&self, from: types::Fd, to: types::Fd) -> Result<(), Error> {
|
||||||
@@ -412,10 +440,10 @@ impl<'a> wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiCtx {
|
|||||||
if !table.contains_key(from) {
|
if !table.contains_key(from) {
|
||||||
return Err(Error::Badf);
|
return Err(Error::Badf);
|
||||||
}
|
}
|
||||||
if self.is_preopen(from) {
|
if table.is_preopen(from) {
|
||||||
return Err(Error::Notsup);
|
return Err(Error::Notsup);
|
||||||
}
|
}
|
||||||
if self.is_preopen(to) {
|
if table.is_preopen(to) {
|
||||||
return Err(Error::Notsup);
|
return Err(Error::Notsup);
|
||||||
}
|
}
|
||||||
let from_entry = table
|
let from_entry = table
|
||||||
@@ -431,15 +459,39 @@ impl<'a> wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiCtx {
|
|||||||
offset: types::Filedelta,
|
offset: types::Filedelta,
|
||||||
whence: types::Whence,
|
whence: types::Whence,
|
||||||
) -> Result<types::Filesize, Error> {
|
) -> Result<types::Filesize, Error> {
|
||||||
unimplemented!()
|
use std::io::SeekFrom;
|
||||||
|
|
||||||
|
let required_caps = if offset == 0 && whence == types::Whence::Cur {
|
||||||
|
FileCaps::TELL
|
||||||
|
} else {
|
||||||
|
FileCaps::TELL | FileCaps::SEEK
|
||||||
|
};
|
||||||
|
|
||||||
|
let table = self.table();
|
||||||
|
let file_entry: RefMut<FileEntry> = table.get(u32::from(fd))?;
|
||||||
|
let f = file_entry.get_cap(required_caps)?;
|
||||||
|
let newoffset = f.seek(match whence {
|
||||||
|
types::Whence::Cur => SeekFrom::Current(offset),
|
||||||
|
types::Whence::End => SeekFrom::End(offset),
|
||||||
|
types::Whence::Set => SeekFrom::Start(offset as u64),
|
||||||
|
})?;
|
||||||
|
Ok(newoffset)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fd_sync(&self, fd: types::Fd) -> Result<(), Error> {
|
fn fd_sync(&self, fd: types::Fd) -> Result<(), Error> {
|
||||||
unimplemented!()
|
let table = self.table();
|
||||||
|
let file_entry: RefMut<FileEntry> = table.get(u32::from(fd))?;
|
||||||
|
let f = file_entry.get_cap(FileCaps::SYNC)?;
|
||||||
|
f.sync()?;
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fd_tell(&self, fd: types::Fd) -> Result<types::Filesize, Error> {
|
fn fd_tell(&self, fd: types::Fd) -> Result<types::Filesize, Error> {
|
||||||
unimplemented!()
|
let table = self.table();
|
||||||
|
let file_entry: RefMut<FileEntry> = table.get(u32::from(fd))?;
|
||||||
|
let f = file_entry.get_cap(FileCaps::TELL)?;
|
||||||
|
let offset = f.seek(std::io::SeekFrom::Current(0))?;
|
||||||
|
Ok(offset)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn path_create_directory(
|
fn path_create_directory(
|
||||||
|
|||||||
@@ -36,6 +36,17 @@ impl Table {
|
|||||||
self.map.contains_key(&key)
|
self.map.contains_key(&key)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn is<T: Any + Sized>(&self, key: u32) -> bool {
|
||||||
|
if let Some(refcell) = self.map.get(&key) {
|
||||||
|
if let Ok(refmut) = refcell.try_borrow_mut() {
|
||||||
|
refmut.is::<T>()
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
// Todo: we can refine these errors and translate them to Exist at abi
|
// Todo: we can refine these errors and translate them to Exist at abi
|
||||||
pub fn get<T: Any + Sized>(&self, key: u32) -> Result<RefMut<T>, Error> {
|
pub fn get<T: Any + Sized>(&self, key: u32) -> Result<RefMut<T>, Error> {
|
||||||
if let Some(refcell) = self.map.get(&key) {
|
if let Some(refcell) = self.map.get(&key) {
|
||||||
|
|||||||
Reference in New Issue
Block a user