mirror of
https://github.com/fluencelabs/wasmer
synced 2025-06-20 20:26:32 +00:00
Add serialization for WASI state - wip
This commit is contained in:
3
Cargo.lock
generated
3
Cargo.lock
generated
@ -535,6 +535,7 @@ version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1651,11 +1652,13 @@ dependencies = [
|
||||
name = "wasmer-wasi"
|
||||
version = "0.6.0"
|
||||
dependencies = [
|
||||
"bincode 1.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"generational-arena 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"wasmer-runtime-core 0.6.0",
|
||||
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
@ -8,14 +8,16 @@ repository = "https://github.com/wasmerio/wasmer"
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
wasmer-runtime-core = { path = "../runtime-core", version = "0.6.0" }
|
||||
libc = "0.2.60"
|
||||
rand = "0.7.0"
|
||||
# wasmer-runtime-abi = { path = "../runtime-abi" }
|
||||
generational-arena = "0.2.2"
|
||||
log = "0.4.8"
|
||||
bincode = "1"
|
||||
byteorder = "1.3.2"
|
||||
generational-arena = { version = "0.2.2", features = ["serde"] }
|
||||
libc = "0.2.60"
|
||||
log = "0.4.8"
|
||||
rand = "0.7.0"
|
||||
time = "0.1.42"
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
# wasmer-runtime-abi = { path = "../runtime-abi" }
|
||||
wasmer-runtime-core = { path = "../runtime-core", version = "0.6.0" }
|
||||
|
||||
[target.'cfg(windows)'.dependencies]
|
||||
winapi = "0.3.7"
|
||||
|
@ -49,8 +49,8 @@ pub fn generate_import_object(
|
||||
|
||||
let state = Box::new(WasiState {
|
||||
fs: WasiFs::new(&preopened_files, &mapped_dirs).unwrap(),
|
||||
args: &args[..],
|
||||
envs: &envs[..],
|
||||
args,
|
||||
envs,
|
||||
});
|
||||
|
||||
(
|
||||
|
@ -8,6 +8,7 @@ pub use self::types::*;
|
||||
use crate::syscalls::types::*;
|
||||
use generational_arena::Arena;
|
||||
pub use generational_arena::Index as Inode;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::HashMap;
|
||||
use std::{
|
||||
borrow::Borrow,
|
||||
@ -35,7 +36,7 @@ pub unsafe fn get_wasi_state(ctx: &mut Ctx) -> &mut WasiState {
|
||||
pub const MAX_SYMLINKS: u32 = 128;
|
||||
|
||||
/// A file that Wasi knows about that may or may not be open
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct InodeVal {
|
||||
pub stat: __wasi_filestat_t,
|
||||
pub is_preopened: bool,
|
||||
@ -43,28 +44,10 @@ pub struct InodeVal {
|
||||
pub kind: Kind,
|
||||
}
|
||||
|
||||
/*impl WasiFdBacking for InodeVal {
|
||||
fn get_stat(&self) -> &__wasi_filestat_t {
|
||||
&self.stat
|
||||
}
|
||||
|
||||
fn get_stat_mut(&mut self) -> &mut __wasi_filestat_t {
|
||||
&mut self.stat
|
||||
}
|
||||
|
||||
fn is_preopened(&self) -> bool {
|
||||
self.is_preopened
|
||||
}
|
||||
|
||||
fn get_name(&self) -> &str {
|
||||
self.name.as_ref()
|
||||
}
|
||||
}*/
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub enum Kind {
|
||||
File {
|
||||
#[serde(skip)]
|
||||
/// the open file, if it's open
|
||||
handle: Option<Box<dyn WasiFile>>,
|
||||
/// The path on the host system where the file is located
|
||||
@ -106,15 +89,24 @@ pub enum Kind {
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct Fd {
|
||||
pub rights: __wasi_rights_t,
|
||||
pub rights_inheriting: __wasi_rights_t,
|
||||
pub flags: __wasi_fdflags_t,
|
||||
pub offset: u64,
|
||||
pub open_flags: u16,
|
||||
pub inode: Inode,
|
||||
}
|
||||
|
||||
impl Fd {
|
||||
pub const READ: u16 = 1;
|
||||
pub const WRITE: u16 = 2;
|
||||
pub const APPEND: u16 = 4;
|
||||
pub const TRUNCATE: u16 = 8;
|
||||
pub const CREATE: u16 = 16;
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
/// Warning, modifying these fields directly may cause invariants to break and
|
||||
/// should be considered unsafe. These fields may be made private in a future release
|
||||
@ -176,7 +168,7 @@ impl WasiFs {
|
||||
& (!__WASI_RIGHT_PATH_REMOVE_DIRECTORY)*/;
|
||||
let inode = wasi_fs.create_virtual_root();
|
||||
let fd = wasi_fs
|
||||
.create_fd(root_rights, root_rights, 0, inode)
|
||||
.create_fd(root_rights, root_rights, 0, Fd::READ, inode)
|
||||
.expect("Could not create root fd");
|
||||
wasi_fs.preopen_fds.push(fd);
|
||||
inode
|
||||
@ -211,7 +203,13 @@ impl WasiFs {
|
||||
)
|
||||
})?;
|
||||
let fd = wasi_fs
|
||||
.create_fd(default_rights, default_rights, 0, inode)
|
||||
.create_fd(
|
||||
default_rights,
|
||||
default_rights,
|
||||
0,
|
||||
Fd::READ | Fd::WRITE,
|
||||
inode,
|
||||
)
|
||||
.expect("Could not open fd");
|
||||
if let Kind::Root { entries } = &mut wasi_fs.inodes[root_inode].kind {
|
||||
// todo handle collisions
|
||||
@ -249,7 +247,13 @@ impl WasiFs {
|
||||
)
|
||||
})?;
|
||||
let fd = wasi_fs
|
||||
.create_fd(default_rights, default_rights, 0, inode)
|
||||
.create_fd(
|
||||
default_rights,
|
||||
default_rights,
|
||||
0,
|
||||
Fd::READ | Fd::WRITE,
|
||||
inode,
|
||||
)
|
||||
.expect("Could not open fd");
|
||||
if let Kind::Root { entries } = &mut wasi_fs.inodes[root_inode].kind {
|
||||
// todo handle collisions
|
||||
@ -276,6 +280,7 @@ impl WasiFs {
|
||||
&mut self,
|
||||
base: __wasi_fd_t,
|
||||
file: Box<dyn WasiFile>,
|
||||
open_flags: u16,
|
||||
name: String,
|
||||
rights: __wasi_rights_t,
|
||||
rights_inheriting: __wasi_rights_t,
|
||||
@ -312,7 +317,7 @@ impl WasiFs {
|
||||
_ => unreachable!("Dir or Root became not Dir or Root"),
|
||||
}
|
||||
|
||||
self.create_fd(rights, rights_inheriting, flags, inode)
|
||||
self.create_fd(rights, rights_inheriting, flags, open_flags, inode)
|
||||
.map_err(WasiFsError::from_wasi_err)
|
||||
}
|
||||
_ => Err(WasiFsError::BaseNotDirectory),
|
||||
@ -754,10 +759,13 @@ impl WasiFs {
|
||||
let inode = &mut self.inodes[fd.inode];
|
||||
|
||||
match &mut inode.kind {
|
||||
Kind::File {
|
||||
handle: Some(handle),
|
||||
..
|
||||
} => handle.flush().map_err(|_| __WASI_EIO)?,
|
||||
Kind::File { handle, .. } => {
|
||||
if let Some(file) = handle {
|
||||
file.flush().map_err(|_| __WASI_EIO)?
|
||||
} else {
|
||||
return Err(__WASI_EIO);
|
||||
}
|
||||
}
|
||||
// TODO: verify this behavior
|
||||
Kind::Dir { .. } => return Err(__WASI_EISDIR),
|
||||
Kind::Symlink { .. } => unimplemented!(),
|
||||
@ -810,6 +818,7 @@ impl WasiFs {
|
||||
rights: __wasi_rights_t,
|
||||
rights_inheriting: __wasi_rights_t,
|
||||
flags: __wasi_fdflags_t,
|
||||
open_flags: u16,
|
||||
inode: Inode,
|
||||
) -> Result<__wasi_fd_t, __wasi_errno_t> {
|
||||
let idx = self.next_fd.get();
|
||||
@ -821,6 +830,7 @@ impl WasiFs {
|
||||
rights_inheriting,
|
||||
flags,
|
||||
offset: 0,
|
||||
open_flags,
|
||||
inode,
|
||||
},
|
||||
);
|
||||
@ -922,13 +932,80 @@ impl WasiFs {
|
||||
..__wasi_filestat_t::default()
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn unfreeze(bytes: &[u8]) -> Option<(WasiFs, &[u8])> {
|
||||
unimplemented!()
|
||||
Some((Self {
|
||||
preopen_fds,
|
||||
name_map,
|
||||
inodes,
|
||||
fd_map,
|
||||
next_fd,
|
||||
inode_counter,
|
||||
orphan_fds,
|
||||
|
||||
stdout,
|
||||
stderr,
|
||||
stdin
|
||||
}, unimplemented!()))
|
||||
}
|
||||
|
||||
pub(crate) fn freeze(&self) -> Option<Vec<u8>> {
|
||||
let mut out = vec![];
|
||||
// store pointer to stdout, stderr, and stdin here I guess
|
||||
// hmmm
|
||||
out.append(&mut bincode::serialize(&self.preopen_fds).ok()?);
|
||||
out.append(&mut bincode::serialize(&self.name_map).ok()?);
|
||||
out.append(&mut bincode::serialize(&self.inodes).ok()?);
|
||||
out.append(&mut bincode::serialize(&self.fd_map).ok()?);
|
||||
out.append(&mut bincode::serialize(&self.next_fd).ok()?);
|
||||
out.append(&mut bincode::serialize(&self.inode_counter).ok()?);
|
||||
out.append(&mut bincode::serialize(&self.orphan_fds).ok()?);
|
||||
out.append(&mut self.stdout.to_bytes()?);
|
||||
out.append(&mut self.stderr.to_bytes()?);
|
||||
out.append(&mut self.stdin.to_bytes()?);
|
||||
|
||||
Some(out)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct WasiState<'a> {
|
||||
pub struct WasiState {
|
||||
pub fs: WasiFs,
|
||||
pub args: &'a [Vec<u8>],
|
||||
pub envs: &'a [Vec<u8>],
|
||||
pub args: Vec<Vec<u8>>,
|
||||
pub envs: Vec<Vec<u8>>,
|
||||
}
|
||||
|
||||
impl WasiState {
|
||||
/// Turn the WasiState into bytes
|
||||
pub fn freeze(&self) -> Option<Vec<u8>> {
|
||||
let wasi_fs = self.wasi_fs.freeze()?;
|
||||
let args = bincode::serialize(&self.args).ok()?;
|
||||
let envs = bincode::serialize(&self.envs).ok()?;
|
||||
|
||||
Some(
|
||||
wasi_fs
|
||||
.into_iter()
|
||||
.chain(args.into_iter())
|
||||
.chain(envs.into_iter())
|
||||
.collect(),
|
||||
)
|
||||
}
|
||||
|
||||
/// Get a WasiState from bytes
|
||||
pub fn unfreeze<F>(bytes: &[u8], deserialize_fns: Vec<Box<F>>) -> Option<Self>
|
||||
where
|
||||
F: Fn(&[u8]) -> Option<Box<dyn WasiFile>>,
|
||||
{
|
||||
let (wasi_fs, remaining_bytes) = WasiFs::unfreeze(bytes)?;
|
||||
let (args, envs): (Vec<Vec<u8>>, Vec<Vec<u8>>) =
|
||||
bincode::deserialize(remaining_bytes).ok()?;
|
||||
Some(Self {
|
||||
fs: wasi_fs,
|
||||
args,
|
||||
envs,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub fn host_file_type_to_wasi_file_type(file_type: fs::FileType) -> __wasi_filetype_t {
|
||||
|
@ -4,7 +4,7 @@ use crate::syscalls::types::*;
|
||||
use std::convert::TryInto;
|
||||
use std::{
|
||||
fs,
|
||||
io::{self, Read, Seek, Write},
|
||||
io::{self, Read, Seek, SeekFrom, Write},
|
||||
path::PathBuf,
|
||||
time::SystemTime,
|
||||
};
|
||||
@ -178,6 +178,29 @@ pub trait WasiFile: std::fmt::Debug + Write + Read + Seek {
|
||||
fn get_raw_fd(&self) -> Option<i32> {
|
||||
None
|
||||
}
|
||||
|
||||
/// Try to turn the file into bytes
|
||||
fn to_bytes(&self) -> Option<Vec<u8>>;
|
||||
}
|
||||
|
||||
/// Tries to read a WASI file out of bytes
|
||||
/// with default parsers for stdin/stdout/stderr and `HostFile`
|
||||
pub fn wasi_file_from_bytes(bytes: &[u8]) -> Option<Box<dyn WasiFile>> {
|
||||
Some(if b"stdout"[..] == bytes[.."stdout".len()] {
|
||||
Box::new(Stdout(std::io::stdout()))
|
||||
} else if b"stderr"[..] == bytes[.."stderr".len()] {
|
||||
Box::new(Stderr(std::io::stderr()))
|
||||
} else if b"stdin"[..] == bytes[.."stdin".len()] {
|
||||
Box::new(Stdin(std::io::stdin()))
|
||||
} else if b"host_file"[..] == bytes[.."host_file".len()] {
|
||||
unimplemented!();
|
||||
} else {
|
||||
return None;
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn serialize_file<E: Default>(file: Box<dyn WasiFile>) -> Result<Vec<u8>, E> {
|
||||
file.to_bytes().ok_or_else(|| Default::default())
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
@ -485,6 +508,23 @@ impl WasiFile for HostFile {
|
||||
"HostFile::get_raw_fd in WasiFile is not implemented for non-Unix-like targets yet"
|
||||
);
|
||||
}
|
||||
|
||||
fn to_bytes(&self) -> Option<Vec<u8>> {
|
||||
let mut out = vec![];
|
||||
for c in "host_file".chars() {
|
||||
out.push(c as u8);
|
||||
}
|
||||
let cursor = self.inner.seek(SeekFrom::Current(0)).ok()?;
|
||||
// store r/w/append info here? or is this handeled somewhere else?
|
||||
for b in cursor.to_le_bytes().into_iter() {
|
||||
out.push(*b);
|
||||
}
|
||||
for b in self.host_path.to_string_lossy().bytes() {
|
||||
out.push(b);
|
||||
}
|
||||
|
||||
Some(out)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<io::Error> for WasiFsError {
|
||||
@ -591,6 +631,10 @@ impl WasiFile for Stdout {
|
||||
"Stdout::get_raw_fd in WasiFile is not implemented for non-Unix-like targets yet"
|
||||
);
|
||||
}
|
||||
|
||||
fn to_bytes(&self) -> Option<Vec<u8>> {
|
||||
Some("stdout".chars().map(|c| c as u8).collect())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
@ -670,6 +714,10 @@ impl WasiFile for Stderr {
|
||||
"Stderr::get_raw_fd in WasiFile is not implemented for non-Unix-like targets yet"
|
||||
);
|
||||
}
|
||||
|
||||
fn to_bytes(&self) -> Option<Vec<u8>> {
|
||||
Some("stderr".chars().map(|c| c as u8).collect())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
@ -773,6 +821,10 @@ impl WasiFile for Stdin {
|
||||
"Stdin::get_raw_fd in WasiFile is not implemented for non-Unix-like targets yet"
|
||||
);
|
||||
}
|
||||
|
||||
fn to_bytes(&self) -> Option<Vec<u8>> {
|
||||
Some("stdin".chars().map(|c| c as u8).collect())
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -683,23 +683,11 @@ pub fn fd_pread(
|
||||
match &mut state.fs.inodes[inode].kind {
|
||||
Kind::File { handle, .. } => {
|
||||
if let Some(h) = handle {
|
||||
let current_pos =
|
||||
wasi_try!(h.seek(std::io::SeekFrom::Current(0)).ok(), __WASI_EIO);
|
||||
wasi_try!(
|
||||
h.seek(std::io::SeekFrom::Start(offset as u64)).ok(),
|
||||
__WASI_EIO
|
||||
);
|
||||
let bytes_read = wasi_try!(read_bytes(h, memory, iov_cells));
|
||||
// reborrow so we can seek it back (the &mut gets moved into `read_bytes`
|
||||
// and we can't use it after)
|
||||
// If you're in the future and there's a nicer way to do this, please
|
||||
// clean up this code
|
||||
if let Some(h) = handle {
|
||||
wasi_try!(
|
||||
h.seek(std::io::SeekFrom::Start(current_pos)).ok(),
|
||||
__WASI_EIO
|
||||
);
|
||||
}
|
||||
bytes_read
|
||||
} else {
|
||||
return __WASI_EINVAL;
|
||||
@ -1675,6 +1663,7 @@ pub fn path_open(
|
||||
if let Ok(m) = maybe_inode {
|
||||
&state.fs.inodes[m];
|
||||
}
|
||||
let mut open_flags = 0;
|
||||
|
||||
// TODO: traverse rights of dirs properly
|
||||
// COMMENTED OUT: WASI isn't giving appropriate rights here when opening
|
||||
@ -1702,7 +1691,16 @@ pub fn path_open(
|
||||
.write(adjusted_rights & __WASI_RIGHT_FD_WRITE != 0)
|
||||
.create(o_flags & __WASI_O_CREAT != 0)
|
||||
.truncate(o_flags & __WASI_O_TRUNC != 0);
|
||||
|
||||
open_flags |= Fd::READ;
|
||||
if adjusted_rights & __WASI_RIGHT_FD_WRITE != 0 {
|
||||
open_flags |= Fd::WRITE;
|
||||
}
|
||||
if o_flags & __WASI_O_CREAT != 0 {
|
||||
open_flags |= Fd::CREATE;
|
||||
}
|
||||
if o_flags & __WASI_O_TRUNC != 0 {
|
||||
open_flags |= Fd::TRUNCATE;
|
||||
}
|
||||
*handle = Some(Box::new(HostFile::new(
|
||||
wasi_try!(open_options.open(&path).map_err(|_| __WASI_EIO)),
|
||||
path.to_path_buf(),
|
||||
@ -1762,6 +1760,7 @@ pub fn path_open(
|
||||
// write access is required for creating a file
|
||||
.write(true)
|
||||
.create_new(true);
|
||||
open_flags |= Fd::READ | Fd::WRITE | Fd::CREATE | Fd::TRUNCATE;
|
||||
|
||||
Some(Box::new(HostFile::new(
|
||||
wasi_try!(open_options.open(&new_file_host_path).map_err(|e| {
|
||||
@ -1800,10 +1799,13 @@ pub fn path_open(
|
||||
|
||||
// TODO: check and reduce these
|
||||
// TODO: ensure a mutable fd to root can never be opened
|
||||
let out_fd =
|
||||
wasi_try!(state
|
||||
.fs
|
||||
.create_fd(adjusted_rights, fs_rights_inheriting, fs_flags, inode));
|
||||
let out_fd = wasi_try!(state.fs.create_fd(
|
||||
adjusted_rights,
|
||||
fs_rights_inheriting,
|
||||
fs_flags,
|
||||
open_flags,
|
||||
inode
|
||||
));
|
||||
|
||||
fd_cell.set(out_fd);
|
||||
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
use crate::ptr::{Array, WasmPtr};
|
||||
use byteorder::{ReadBytesExt, WriteBytesExt, LE};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt;
|
||||
use std::mem;
|
||||
use wasmer_runtime_core::types::ValueType;
|
||||
@ -316,7 +317,7 @@ pub type __wasi_filedelta_t = i64;
|
||||
|
||||
pub type __wasi_filesize_t = u64;
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq)]
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[repr(C)]
|
||||
pub struct __wasi_filestat_t {
|
||||
pub st_dev: __wasi_device_t,
|
||||
|
Reference in New Issue
Block a user