Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add preopened fd and fix/improve fs syscalls; fix wasi memory access #343

Merged
merged 11 commits into from
Apr 19, 2019
8 changes: 6 additions & 2 deletions lib/wasi/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,11 @@ pub use self::utils::is_wasi_module;

use wasmer_runtime_core::{func, import::ImportObject, imports};

pub fn generate_import_object(args: Vec<Vec<u8>>, envs: Vec<Vec<u8>>) -> ImportObject {
pub fn generate_import_object(
args: Vec<Vec<u8>>,
envs: Vec<Vec<u8>>,
preopened_files: Vec<String>,
) -> ImportObject {
let state_gen = move || {
fn state_destructor(data: *mut c_void) {
unsafe {
Expand All @@ -26,7 +30,7 @@ pub fn generate_import_object(args: Vec<Vec<u8>>, envs: Vec<Vec<u8>>) -> ImportO
}

let state = Box::new(WasiState {
fs: WasiFs::new().unwrap(),
fs: WasiFs::new(&preopened_files).unwrap(),
args: &args[..],
envs: &envs[..],
});
Expand Down
157 changes: 140 additions & 17 deletions lib/wasi/src/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,89 @@ use generational_arena::{Arena, Index as Inode};
use hashbrown::hash_map::{Entry, HashMap};
use std::{
cell::Cell,
io::{self, Write},
fs,
io::{self, Read, Seek, Write},
time::SystemTime,
};
use wasmer_runtime_core::debug;
use zbox::{init_env as zbox_init_env, File, FileType, OpenOptions, Repo, RepoOpener};
use zbox::{init_env as zbox_init_env, FileType, OpenOptions, Repo, RepoOpener};

pub const MAX_SYMLINKS: usize = 100;

pub enum WasiFile {
ZboxFile(zbox::File),
HostFile(fs::File),
}

impl Write for WasiFile {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
match self {
WasiFile::ZboxFile(zbf) => zbf.write(buf),
WasiFile::HostFile(hf) => hf.write(buf),
}
}

fn flush(&mut self) -> io::Result<()> {
match self {
WasiFile::ZboxFile(zbf) => zbf.flush(),
WasiFile::HostFile(hf) => hf.flush(),
}
}

fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
match self {
WasiFile::ZboxFile(zbf) => zbf.write_all(buf),
WasiFile::HostFile(hf) => hf.write_all(buf),
}
}

fn write_fmt(&mut self, fmt: ::std::fmt::Arguments) -> io::Result<()> {
match self {
WasiFile::ZboxFile(zbf) => zbf.write_fmt(fmt),
WasiFile::HostFile(hf) => hf.write_fmt(fmt),
}
}
}

impl Read for WasiFile {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
match self {
WasiFile::ZboxFile(zbf) => zbf.read(buf),
WasiFile::HostFile(hf) => hf.read(buf),
}
}

fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
match self {
WasiFile::ZboxFile(zbf) => zbf.read_to_end(buf),
WasiFile::HostFile(hf) => hf.read_to_end(buf),
}
}

fn read_to_string(&mut self, buf: &mut String) -> io::Result<usize> {
match self {
WasiFile::ZboxFile(zbf) => zbf.read_to_string(buf),
WasiFile::HostFile(hf) => hf.read_to_string(buf),
}
}

fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> {
match self {
WasiFile::ZboxFile(zbf) => zbf.read_exact(buf),
WasiFile::HostFile(hf) => hf.read_exact(buf),
}
}
}

impl Seek for WasiFile {
fn seek(&mut self, pos: io::SeekFrom) -> io::Result<u64> {
match self {
WasiFile::ZboxFile(zbf) => zbf.seek(pos),
WasiFile::HostFile(hf) => hf.seek(pos),
}
}
}

pub struct InodeVal {
pub stat: __wasi_filestat_t,
pub is_preopened: bool,
Expand All @@ -25,10 +100,10 @@ pub struct InodeVal {
#[allow(dead_code)]
pub enum Kind {
File {
handle: File,
handle: WasiFile,
},
Dir {
handle: File,
handle: WasiFile,
/// The entries of a directory are lazily filled.
entries: HashMap<String, Inode>,
},
Expand All @@ -40,7 +115,7 @@ pub enum Kind {
},
}

#[derive(Clone)]
#[derive(Clone, Debug)]
pub struct Fd {
pub rights: __wasi_rights_t,
pub rights_inheriting: __wasi_rights_t,
Expand All @@ -50,7 +125,7 @@ pub struct Fd {
}

pub struct WasiFs {
// pub repo: Repo,
pub repo: Repo,
pub name_map: HashMap<String, Inode>,
pub inodes: Arena<InodeVal>,
pub fd_map: HashMap<u32, Fd>,
Expand All @@ -59,26 +134,58 @@ pub struct WasiFs {
}

impl WasiFs {
pub fn new() -> Result<Self, String> {
pub fn new(preopened_files: &[String]) -> Result<Self, String> {
debug!("wasi::fs::init");
zbox_init_env();
debug!("wasi::fs::repo");
// let repo = RepoOpener::new()
// .create(true)
// .open("mem://wasmer-test-fs", "")
// .map_err(|e| e.to_string())?;
let repo = RepoOpener::new()
.create(true)
.open("mem://wasmer-test-fs", "")
.map_err(|e| e.to_string())?;
debug!("wasi::fs::inodes");
let inodes = Arena::new();
let res = Ok(Self {
// repo: repo,
let mut wasi_fs = Self {
repo: repo,
name_map: HashMap::new(),
inodes: inodes,
fd_map: HashMap::new(),
next_fd: Cell::new(3),
inode_counter: Cell::new(1000),
});
};
for file in preopened_files {
debug!("Attempting to preopen {}", &file);
// TODO: think about this
let default_rights = 0x1FFFFFFF;
let cur_file: fs::File = fs::File::open(file).expect("Could not find file");
let kind = if cur_file.metadata().unwrap().is_dir() {
// it seems bad to open every file recursively; can do it lazily though
Kind::Dir {
handle: WasiFile::HostFile(cur_file),
entries: Default::default(),
}
} else {
/*Kind::File {
handle: WasiFile::HostFile(cur_file),
}*/
return Err(format!(
"WASI only supports pre-opened directories right now; found \"{}\"",
file
));
};
let inode_val = InodeVal {
stat: __wasi_filestat_t::default(),
is_preopened: true,
// this is incorrect
name: file.clone(),
kind,
};
let inode = wasi_fs.inodes.insert(inode_val);
wasi_fs
.create_fd(default_rights, default_rights, 0, inode)
.expect("Could not open fd");
}
debug!("wasi::fs::end");
res
Ok(wasi_fs)
}

#[allow(dead_code)]
Expand Down Expand Up @@ -195,7 +302,9 @@ impl WasiFs {
pub fn fdstat(&self, fd: __wasi_fd_t) -> Result<__wasi_fdstat_t, __wasi_errno_t> {
let fd = self.fd_map.get(&fd).ok_or(__WASI_EBADF)?;

Ok(__wasi_fdstat_t {
debug!("fdstat: {:?}", fd);

dbg!(Ok(__wasi_fdstat_t {
fs_filetype: match self.inodes[fd.inode].kind {
Kind::File { .. } => __WASI_FILETYPE_REGULAR_FILE,
Kind::Dir { .. } => __WASI_FILETYPE_DIRECTORY,
Expand All @@ -205,12 +314,13 @@ impl WasiFs {
fs_flags: fd.flags,
fs_rights_base: fd.rights,
fs_rights_inheriting: fd.rights, // TODO(lachlan): Is this right?
})
}))
}

pub fn prestat_fd(&self, fd: __wasi_fd_t) -> Result<__wasi_prestat_t, __wasi_errno_t> {
let fd = self.fd_map.get(&fd).ok_or(__WASI_EBADF)?;

debug!("in prestat_fd {:?}", fd);
let inode_val = &self.inodes[fd.inode];

if inode_val.is_preopened {
Expand Down Expand Up @@ -272,6 +382,19 @@ impl WasiFs {
);
Ok(idx)
}

MarkMcCaskey marked this conversation as resolved.
Show resolved Hide resolved
/*pub fn create_file_at_fd(
&mut self,
parent: __wasi_fd_t,
path: String,
fs_rights_base: __wasi_rights_t,
fs_rights_inheriting: __wasi_rights_t,
fs_flags: fs_flags,
) -> Result<__wasi_fd_t, __wasi_errno_t> {

let fd = self.fd_map.get(&fd).ok_or(__WASI_EBADF)?;
Ok()
}*/
}

pub struct WasiState<'a> {
Expand Down
Loading