mirror of
https://github.com/fluencelabs/wasmer
synced 2025-03-16 00:00:49 +00:00
Merge #726
726: Add serialization for WASI state r=MarkMcCaskey a=MarkMcCaskey part of #700 Due to the trait objects from #583 , we can't use `serde` derive for this or use serde traits directly, we have to do some custom serialization (edit: luckily there's a crate for this: `typetag`) Co-authored-by: Mark McCaskey <mark@wasmer.io> Co-authored-by: Mark McCaskey <markmccaskey@users.noreply.github.com> Co-authored-by: Syrus Akbary <me@syrusakbary.com>
This commit is contained in:
commit
15066555e7
83
Cargo.lock
generated
83
Cargo.lock
generated
@ -409,6 +409,15 @@ dependencies = [
|
||||
"memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ctor"
|
||||
version = "0.1.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "digest"
|
||||
version = "0.8.1"
|
||||
@ -467,6 +476,14 @@ dependencies = [
|
||||
"termcolor 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "erased-serde"
|
||||
version = "0.3.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"serde 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "errno"
|
||||
version = "0.2.4"
|
||||
@ -535,6 +552,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]]
|
||||
@ -555,6 +573,16 @@ dependencies = [
|
||||
"wasi 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ghost"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "glob"
|
||||
version = "0.2.11"
|
||||
@ -629,6 +657,26 @@ dependencies = [
|
||||
"syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "inventory"
|
||||
version = "0.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"ctor 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ghost 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"inventory-impl 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "inventory-impl"
|
||||
version = "0.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.8.0"
|
||||
@ -1344,6 +1392,28 @@ name = "typenum"
|
||||
version = "1.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "typetag"
|
||||
version = "0.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"erased-serde 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"inventory 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"typetag-impl 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "typetag-impl"
|
||||
version = "0.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-segmentation"
|
||||
version = "1.3.0"
|
||||
@ -1428,7 +1498,9 @@ dependencies = [
|
||||
"errno 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"glob 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"structopt 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"typetag 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"wabt 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"wasmer-clif-backend 0.6.0",
|
||||
"wasmer-dev-utils 0.6.0",
|
||||
@ -1661,12 +1733,15 @@ 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)",
|
||||
"typetag 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"wasmer-runtime-core 0.6.0",
|
||||
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
@ -1679,6 +1754,7 @@ dependencies = [
|
||||
"wasmer-clif-backend 0.6.0",
|
||||
"wasmer-dev-utils 0.6.0",
|
||||
"wasmer-llvm-backend 0.6.0",
|
||||
"wasmer-runtime 0.6.0",
|
||||
"wasmer-runtime-core 0.6.0",
|
||||
"wasmer-singlepass-backend 0.6.0",
|
||||
"wasmer-wasi 0.6.0",
|
||||
@ -1812,12 +1888,14 @@ dependencies = [
|
||||
"checksum crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)" = "04973fa96e96579258a5091af6003abde64af786b860f18622b82e026cca60e6"
|
||||
"checksum csv 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "37519ccdfd73a75821cac9319d4fce15a81b9fcf75f951df5b9988aa3a0af87d"
|
||||
"checksum csv-core 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "9b5cadb6b25c77aeff80ba701712494213f4a8418fcda2ee11b6560c3ad0bf4c"
|
||||
"checksum ctor 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "5b6b2f4752cc29efbfd03474c532ce8f916f2d44ec5bb8c21f93bc76e5365528"
|
||||
"checksum digest 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5"
|
||||
"checksum dynasm 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f36d49ab6f8ecc642d2c6ee10fda04ba68003ef0277300866745cdde160e6b40"
|
||||
"checksum dynasmrt 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a4c408a211e7f5762829f5e46bdff0c14bc3b1517a21a4bb781c716bf88b0c68"
|
||||
"checksum either 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5527cfe0d098f36e3f8839852688e63c8fff1c90b2b405aef730615f9a7bcf7b"
|
||||
"checksum enum-methods 0.0.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7798e7da2d4cb0d6d6fc467e8d6b5bf247e9e989f786dde1732d79899c32bb10"
|
||||
"checksum env_logger 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "aafcde04e90a5226a6443b7aabdb016ba2f8307c847d524724bd9b346dd1a2d3"
|
||||
"checksum erased-serde 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "3beee4bc16478a1b26f2e80ad819a52d24745e292f521a63c16eea5f74b7eb60"
|
||||
"checksum errno 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "c2a071601ed01b988f896ab14b95e67335d1eeb50190932a1320f7fe3cadc84e"
|
||||
"checksum errno-dragonfly 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "14ca354e36190500e1e1fb267c647932382b54053c50b14970856c0b00a35067"
|
||||
"checksum failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "795bd83d3abeb9220f257e597aa0080a508b27533824adf336529648f6abf7e2"
|
||||
@ -1829,6 +1907,7 @@ dependencies = [
|
||||
"checksum generational-arena 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4024f96ffa0ebaaf36aa589cd41f2fd69f3a5e6fd02c86e11e12cdf41d5b46a3"
|
||||
"checksum generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c68f0274ae0e023facc3c97b2e00f076be70e254bc851d972503b328db79b2ec"
|
||||
"checksum getrandom 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "6171a6cc63fbabbe27c2b5ee268e8b7fe5dc1eb0dd2dfad537c1dfed6f69117e"
|
||||
"checksum ghost 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2a36606a68532b5640dc86bb1f33c64b45c4682aad4c50f3937b317ea387f3d6"
|
||||
"checksum glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "8be18de09a56b60ed0edf84bc9df007e30040691af7acd1c41874faac5895bfb"
|
||||
"checksum glob 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574"
|
||||
"checksum goblin 0.0.24 (registry+https://github.com/rust-lang/crates.io-index)" = "e3fa261d919c1ae9d1e4533c4a2f99e10938603c4208d56c05bec7a872b661b0"
|
||||
@ -1838,6 +1917,8 @@ dependencies = [
|
||||
"checksum indexmap 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a4d6d89e0948bf10c08b9ecc8ac5b83f07f857ebe2c0cbe38de15b4e4f510356"
|
||||
"checksum inkwell 0.1.0 (git+https://github.com/wasmerio/inkwell?branch=llvm8-0)" = "<none>"
|
||||
"checksum inkwell_internal_macros 0.1.0 (git+https://github.com/wasmerio/inkwell?branch=llvm8-0)" = "<none>"
|
||||
"checksum inventory 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "f4cece20baea71d9f3435e7bbe9adf4765f091c5fe404975f844006964a71299"
|
||||
"checksum inventory-impl 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "c2869bf972e998977b1cb87e60df70341d48e48dca0823f534feb91ea44adaf9"
|
||||
"checksum itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5b8467d9c1cebe26feb08c640139247fac215782d35371ade9a2136ed6085358"
|
||||
"checksum itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "501266b7edd0174f8530248f87f99c88fbe60ca4ef3dd486835b8d8d53136f7f"
|
||||
"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
|
||||
@ -1925,6 +2006,8 @@ dependencies = [
|
||||
"checksum toml 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "758664fc71a3a69038656bee8b6be6477d2a6c315a6b81f7081f591bffa4111f"
|
||||
"checksum toml 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c7aabe75941d914b72bf3e5d3932ed92ce0664d49d8432305a8b547c37227724"
|
||||
"checksum typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "612d636f949607bdf9b123b4a6f6d966dedf3ff669f7f045890d3a4a73948169"
|
||||
"checksum typetag 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "6ebb2c484029d695fb68a06d80e1536c68d491b3e0cf874c66abed255e831cfe"
|
||||
"checksum typetag-impl 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b63fd4799e4d0ec5cf0b055ebb8e2c3a657bbf76a84f6edc77ca60780e000204"
|
||||
"checksum unicode-segmentation 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1967f4cdfc355b37fd76d2a954fb2ed3871034eb4f26d60537d88795cfc332a9"
|
||||
"checksum unicode-width 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7007dbd421b92cc6e28410fe7362e2e0a2503394908f417b68ec8d1c364c4e20"
|
||||
"checksum unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f860d7d29cf02cb2f3f359fd35991af3d30bac52c57d265a3c461074cb4dc"
|
||||
|
@ -66,6 +66,10 @@ wabt = "0.9.1"
|
||||
glob = "0.3.0"
|
||||
rustc_version = "0.2.3"
|
||||
|
||||
[dev-dependencies]
|
||||
serde = { version = "1", features = ["derive"] } # used by the plugin example
|
||||
typetag = "0.1" # used by the plugin example
|
||||
|
||||
[features]
|
||||
default = ["fast-tests", "wasi", "backend-cranelift"]
|
||||
"loader-kernel" = ["wasmer-kernel-loader"]
|
||||
|
5
Makefile
5
Makefile
@ -70,12 +70,13 @@ wasitests-singlepass: wasitests-setup
|
||||
cargo test --manifest-path lib/wasi-tests/Cargo.toml --release --features singlepass -- --test-threads=1
|
||||
|
||||
wasitests-cranelift: wasitests-setup
|
||||
cargo test --manifest-path lib/wasi-tests/Cargo.toml --release --features clif -- --test-threads=1
|
||||
cargo test --manifest-path lib/wasi-tests/Cargo.toml --release --features clif -- --test-threads=1 --nocapture
|
||||
|
||||
wasitests-llvm: wasitests-setup
|
||||
cargo test --manifest-path lib/wasi-tests/Cargo.toml --release --features llvm -- --test-threads=1
|
||||
|
||||
wasitests-unit:
|
||||
wasitests-unit: wasitests-setup
|
||||
cargo test --manifest-path lib/wasi-tests/Cargo.toml --release --features clif -- --test-threads=1 --nocapture
|
||||
cargo test --manifest-path lib/wasi/Cargo.toml --release
|
||||
|
||||
wasitests: wasitests-unit wasitests-singlepass wasitests-cranelift wasitests-llvm
|
||||
|
@ -1,3 +1,4 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
use wasmer_runtime::{func, imports, instantiate};
|
||||
use wasmer_runtime_core::vm::Ctx;
|
||||
use wasmer_wasi::{
|
||||
@ -13,7 +14,7 @@ fn it_works(_ctx: &mut Ctx) -> i32 {
|
||||
5
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct LoggingWrapper {
|
||||
pub wasm_module_name: String,
|
||||
}
|
||||
@ -86,6 +87,8 @@ impl std::io::Write for LoggingWrapper {
|
||||
}
|
||||
|
||||
// the WasiFile methods aren't relevant for a write-only Stdout-like implementation
|
||||
// we must use typetag and serde so that our trait objects can be safely Serialized and Deserialized
|
||||
#[typetag::serde]
|
||||
impl WasiFile for LoggingWrapper {
|
||||
fn last_accessed(&self) -> u64 {
|
||||
0
|
||||
|
@ -10,6 +10,7 @@ build = "build/mod.rs"
|
||||
|
||||
[dependencies]
|
||||
wasmer-runtime-core = { path = "../runtime-core", version = "0.6.0" }
|
||||
wasmer-runtime = { path = "../runtime", version = "0.6.0" }
|
||||
wasmer-wasi = { path = "../wasi", version = "0.6.0" }
|
||||
# hack to get tests to work
|
||||
wasmer-singlepass-backend = { path = "../singlepass-backend", version = "0.6.0", optional = true }
|
||||
|
@ -1 +1,60 @@
|
||||
// nothing to see here
|
||||
#![cfg(test)]
|
||||
use wasmer_runtime::{compile, Func};
|
||||
use wasmer_runtime_core::vm::Ctx;
|
||||
use wasmer_wasi::{state::*, *};
|
||||
|
||||
use std::ffi::c_void;
|
||||
|
||||
#[test]
|
||||
fn serializing_works() {
|
||||
let args = vec![
|
||||
b"program_name".into_iter().cloned().collect(),
|
||||
b"arg1".into_iter().cloned().collect(),
|
||||
];
|
||||
let envs = vec![
|
||||
b"PATH=/bin".into_iter().cloned().collect(),
|
||||
b"GOROOT=$HOME/.cargo/bin".into_iter().cloned().collect(),
|
||||
];
|
||||
let wasm_binary = include_bytes!("../wasitests/fd_read.wasm");
|
||||
let import_object = generate_import_object(
|
||||
args.clone(),
|
||||
envs.clone(),
|
||||
vec![],
|
||||
vec![(
|
||||
".".to_string(),
|
||||
std::path::PathBuf::from("wasitests/test_fs/hamlet"),
|
||||
)],
|
||||
);
|
||||
let module = compile(&wasm_binary[..])
|
||||
.map_err(|e| format!("Can't compile module: {:?}", e))
|
||||
.unwrap();
|
||||
|
||||
let state_bytes = {
|
||||
let instance = module.instantiate(&import_object).unwrap();
|
||||
|
||||
let start: Func<(), ()> = instance.func("_start").unwrap();
|
||||
start.call().unwrap();
|
||||
let state = get_wasi_state(instance.context());
|
||||
|
||||
assert_eq!(state.args, args);
|
||||
assert_eq!(state.envs, envs);
|
||||
let bytes = state.freeze().unwrap();
|
||||
|
||||
bytes
|
||||
};
|
||||
|
||||
let mut instance = module.instantiate(&import_object).unwrap();
|
||||
|
||||
let wasi_state = Box::new(WasiState::unfreeze(&state_bytes).unwrap());
|
||||
|
||||
instance.context_mut().data = Box::into_raw(wasi_state) as *mut c_void;
|
||||
|
||||
let second_entry: Func<(), i32> = instance.func("second_entry").unwrap();
|
||||
let result = second_entry.call().unwrap();
|
||||
assert_eq!(result, true as i32);
|
||||
}
|
||||
|
||||
#[allow(clippy::mut_from_ref)]
|
||||
pub(crate) fn get_wasi_state(ctx: &Ctx) -> &mut WasiState {
|
||||
unsafe { state::get_wasi_state(&mut *(ctx as *const Ctx as *mut Ctx)) }
|
||||
}
|
||||
|
14
lib/wasi-tests/tests/wasitests/fd_read.rs
Normal file
14
lib/wasi-tests/tests/wasitests/fd_read.rs
Normal file
@ -0,0 +1,14 @@
|
||||
#[test]
|
||||
fn test_fd_read() {
|
||||
assert_wasi_output!(
|
||||
"../../wasitests/fd_read.wasm",
|
||||
"fd_read",
|
||||
vec![],
|
||||
vec![(
|
||||
".".to_string(),
|
||||
::std::path::PathBuf::from("wasitests/test_fs/hamlet")
|
||||
),],
|
||||
vec![],
|
||||
"../../wasitests/fd_read.out"
|
||||
);
|
||||
}
|
@ -9,6 +9,7 @@ mod create_dir;
|
||||
mod envvar;
|
||||
mod fd_allocate;
|
||||
mod fd_pread;
|
||||
mod fd_read;
|
||||
mod fd_sync;
|
||||
mod file_metadata;
|
||||
mod fs_sandbox_test;
|
||||
|
3
lib/wasi-tests/wasitests/fd_read.out
Normal file
3
lib/wasi-tests/wasitests/fd_read.out
Normal file
@ -0,0 +1,3 @@
|
||||
SCENE IV. The Queen's closet.
|
||||
|
||||
Enter QUEEN GERTRUDE and POLO
|
86
lib/wasi-tests/wasitests/fd_read.rs
Normal file
86
lib/wasi-tests/wasitests/fd_read.rs
Normal file
@ -0,0 +1,86 @@
|
||||
// Args:
|
||||
// mapdir: .:wasitests/test_fs/hamlet
|
||||
|
||||
// this program is used in the pause/resume test
|
||||
|
||||
use std::fs;
|
||||
#[cfg(target_os = "wasi")]
|
||||
use std::os::wasi::prelude::AsRawFd;
|
||||
use std::path::PathBuf;
|
||||
|
||||
#[cfg(target_os = "wasi")]
|
||||
#[repr(C)]
|
||||
struct WasiIovec {
|
||||
pub buf: u32,
|
||||
pub buf_len: u32,
|
||||
}
|
||||
|
||||
#[cfg(target_os = "wasi")]
|
||||
#[link(wasm_import_module = "wasi_unstable")]
|
||||
extern "C" {
|
||||
fn fd_read(fd: u32, iovs: u32, iovs_len: u32, nread: u32) -> u16;
|
||||
}
|
||||
|
||||
#[cfg(target_os = "wasi")]
|
||||
fn read(fd: u32, iovs: &[&mut [u8]]) -> u32 {
|
||||
let mut nread = 0;
|
||||
let mut processed_iovs = vec![];
|
||||
|
||||
for iov in iovs {
|
||||
processed_iovs.push(WasiIovec {
|
||||
buf: iov.as_ptr() as usize as u32,
|
||||
buf_len: iov.len() as u32,
|
||||
})
|
||||
}
|
||||
|
||||
unsafe {
|
||||
fd_read(
|
||||
fd,
|
||||
processed_iovs.as_ptr() as usize as u32,
|
||||
processed_iovs.len() as u32,
|
||||
&mut nread as *mut u32 as usize as u32,
|
||||
);
|
||||
}
|
||||
nread
|
||||
}
|
||||
|
||||
fn main() {
|
||||
#[cfg(not(target_os = "wasi"))]
|
||||
let mut base = PathBuf::from("wasitests/test_fs/hamlet");
|
||||
#[cfg(target_os = "wasi")]
|
||||
let mut base = PathBuf::from(".");
|
||||
|
||||
base.push("act3/scene4.txt");
|
||||
let mut file = fs::File::open(&base).expect("Could not open file");
|
||||
let mut buffer = [0u8; 64];
|
||||
|
||||
#[cfg(target_os = "wasi")]
|
||||
{
|
||||
let raw_fd = file.as_raw_fd();
|
||||
assert_eq!(read(raw_fd, &[&mut buffer]), 64);
|
||||
let str_val = std::str::from_utf8(&buffer[..]).unwrap().to_string();
|
||||
println!("{}", &str_val);
|
||||
}
|
||||
// leak the file handle so that we can use it later
|
||||
std::mem::forget(file);
|
||||
|
||||
#[cfg(not(target_os = "wasi"))]
|
||||
{
|
||||
// eh, just print the output directly
|
||||
print!(
|
||||
"SCENE IV. The Queen's closet.
|
||||
|
||||
Enter QUEEN GERTRUDE and POLO"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "wasi")]
|
||||
#[no_mangle]
|
||||
fn second_entry() -> bool {
|
||||
let raw_fd = 5;
|
||||
let mut buffer = [0u8; 8];
|
||||
let result = read(raw_fd, &[&mut buffer]);
|
||||
|
||||
&buffer == b"NIUS \n\nL"
|
||||
}
|
BIN
lib/wasi-tests/wasitests/fd_read.wasm
Executable file
BIN
lib/wasi-tests/wasitests/fd_read.wasm
Executable file
Binary file not shown.
@ -8,14 +8,17 @@ 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"
|
||||
typetag = "0.1"
|
||||
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.8"
|
||||
|
@ -44,20 +44,23 @@ pub fn generate_import_object(
|
||||
mapped_dirs: Vec<(String, PathBuf)>,
|
||||
) -> ImportObject {
|
||||
let state_gen = move || {
|
||||
// TODO: look into removing all these unnecessary clones
|
||||
fn state_destructor(data: *mut c_void) {
|
||||
unsafe {
|
||||
drop(Box::from_raw(data as *mut WasiState));
|
||||
}
|
||||
}
|
||||
let preopened_files = preopened_files.clone();
|
||||
let mapped_dirs = mapped_dirs.clone();
|
||||
|
||||
let state = Box::new(WasiState {
|
||||
fs: WasiFs::new(&preopened_files, &mapped_dirs).unwrap(),
|
||||
args: &args[..],
|
||||
envs: &envs[..],
|
||||
fs: WasiFs::new(&preopened_files, &mapped_dirs).expect("Could not create WASI FS"),
|
||||
args: args.clone(),
|
||||
envs: envs.clone(),
|
||||
});
|
||||
|
||||
(
|
||||
Box::leak(state) as *mut WasiState as *mut c_void,
|
||||
Box::into_raw(state) as *mut c_void,
|
||||
state_destructor as fn(*mut c_void),
|
||||
)
|
||||
};
|
||||
|
@ -8,12 +8,13 @@ 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,
|
||||
cell::Cell,
|
||||
fs,
|
||||
io::{self, Write},
|
||||
io::Write,
|
||||
path::{Path, PathBuf},
|
||||
time::SystemTime,
|
||||
};
|
||||
@ -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,26 +44,7 @@ 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 {
|
||||
/// the open file, if it's open
|
||||
@ -106,16 +88,25 @@ 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,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
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, Serialize, Deserialize)]
|
||||
/// 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
|
||||
pub struct WasiFs {
|
||||
@ -150,9 +141,9 @@ impl WasiFs {
|
||||
inode_counter: Cell::new(1024),
|
||||
orphan_fds: HashMap::new(),
|
||||
|
||||
stdin: Box::new(Stdin(io::stdin())),
|
||||
stdout: Box::new(Stdout(io::stdout())),
|
||||
stderr: Box::new(Stderr(io::stderr())),
|
||||
stdin: Box::new(Stdin),
|
||||
stdout: Box::new(Stdout),
|
||||
stderr: Box::new(Stderr),
|
||||
};
|
||||
// create virtual root
|
||||
let root_inode = {
|
||||
@ -176,8 +167,8 @@ 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)
|
||||
.expect("Could not create root fd");
|
||||
.create_fd(root_rights, root_rights, 0, Fd::READ, inode)
|
||||
.map_err(|e| format!("Could not create root fd: {}", e))?;
|
||||
wasi_fs.preopen_fds.push(fd);
|
||||
inode
|
||||
};
|
||||
@ -188,7 +179,13 @@ impl WasiFs {
|
||||
// TODO: think about this
|
||||
let default_rights = 0x1FFFFFFF; // all rights
|
||||
let cur_dir = PathBuf::from(dir);
|
||||
let cur_dir_metadata = cur_dir.metadata().expect("Could not find directory");
|
||||
let cur_dir_metadata = cur_dir.metadata().map_err(|e| {
|
||||
format!(
|
||||
"Could not get metadata for file {:?}: {}",
|
||||
dir,
|
||||
e.to_string()
|
||||
)
|
||||
})?;
|
||||
let kind = if cur_dir_metadata.is_dir() {
|
||||
Kind::Dir {
|
||||
parent: Some(root_inode),
|
||||
@ -211,8 +208,14 @@ impl WasiFs {
|
||||
)
|
||||
})?;
|
||||
let fd = wasi_fs
|
||||
.create_fd(default_rights, default_rights, 0, inode)
|
||||
.expect("Could not open fd");
|
||||
.create_fd(
|
||||
default_rights,
|
||||
default_rights,
|
||||
0,
|
||||
Fd::READ | Fd::WRITE,
|
||||
inode,
|
||||
)
|
||||
.map_err(|e| format!("Could not open fd for file {:?}: {}", dir, e))?;
|
||||
if let Kind::Root { entries } = &mut wasi_fs.inodes[root_inode].kind {
|
||||
// todo handle collisions
|
||||
assert!(entries.insert(dir.to_string(), inode).is_none())
|
||||
@ -224,9 +227,13 @@ impl WasiFs {
|
||||
debug!("Attempting to open {:?} at {}", real_dir, alias);
|
||||
// TODO: think about this
|
||||
let default_rights = 0x1FFFFFFF; // all rights
|
||||
let cur_dir_metadata = real_dir
|
||||
.metadata()
|
||||
.expect("mapped dir not at previously verified location");
|
||||
let cur_dir_metadata = real_dir.metadata().map_err(|e| {
|
||||
format!(
|
||||
"Could not get metadata for file {:?}: {}",
|
||||
&real_dir,
|
||||
e.to_string()
|
||||
)
|
||||
})?;
|
||||
let kind = if cur_dir_metadata.is_dir() {
|
||||
Kind::Dir {
|
||||
parent: Some(root_inode),
|
||||
@ -249,8 +256,14 @@ impl WasiFs {
|
||||
)
|
||||
})?;
|
||||
let fd = wasi_fs
|
||||
.create_fd(default_rights, default_rights, 0, inode)
|
||||
.expect("Could not open fd");
|
||||
.create_fd(
|
||||
default_rights,
|
||||
default_rights,
|
||||
0,
|
||||
Fd::READ | Fd::WRITE,
|
||||
inode,
|
||||
)
|
||||
.map_err(|e| format!("Could not open fd for file {:?}: {}", &real_dir, e))?;
|
||||
if let Kind::Root { entries } = &mut wasi_fs.inodes[root_inode].kind {
|
||||
// todo handle collisions
|
||||
assert!(entries.insert(alias.clone(), inode).is_none());
|
||||
@ -276,6 +289,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 +326,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 +768,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 +827,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 +839,7 @@ impl WasiFs {
|
||||
rights_inheriting,
|
||||
flags,
|
||||
offset: 0,
|
||||
open_flags,
|
||||
inode,
|
||||
},
|
||||
);
|
||||
@ -924,11 +943,23 @@ impl WasiFs {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct WasiState<'a> {
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
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>> {
|
||||
bincode::serialize(self).ok()
|
||||
}
|
||||
|
||||
/// Get a WasiState from bytes
|
||||
pub fn unfreeze(bytes: &[u8]) -> Option<Self> {
|
||||
bincode::deserialize(bytes).ok()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn host_file_type_to_wasi_file_type(file_type: fs::FileType) -> __wasi_filetype_t {
|
||||
|
@ -1,5 +1,6 @@
|
||||
/// types for use in the WASI filesystem
|
||||
use crate::syscalls::types::*;
|
||||
use serde::{de, Deserialize, Serialize};
|
||||
#[cfg(unix)]
|
||||
use std::convert::TryInto;
|
||||
use std::{
|
||||
@ -117,6 +118,7 @@ impl WasiFsError {
|
||||
}
|
||||
|
||||
/// This trait relies on your file closing when it goes out of scope via `Drop`
|
||||
#[typetag::serde(tag = "type")]
|
||||
pub trait WasiFile: std::fmt::Debug + Write + Read + Seek {
|
||||
/// the last time the file was accessed in nanoseconds as a UNIX timestamp
|
||||
fn last_accessed(&self) -> __wasi_timestamp_t;
|
||||
@ -339,18 +341,122 @@ pub(crate) fn poll(
|
||||
pub trait WasiPath {}
|
||||
|
||||
/// A thin wrapper around `std::fs::File`
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Serialize)]
|
||||
pub struct HostFile {
|
||||
#[serde(skip_serializing)]
|
||||
pub inner: fs::File,
|
||||
pub host_path: PathBuf,
|
||||
flags: u16,
|
||||
}
|
||||
|
||||
impl<'de> Deserialize<'de> for HostFile {
|
||||
fn deserialize<D>(deserializer: D) -> Result<HostFile, D::Error>
|
||||
where
|
||||
D: serde::Deserializer<'de>,
|
||||
{
|
||||
#[derive(Deserialize)]
|
||||
#[serde(field_identifier, rename_all = "snake_case")]
|
||||
enum Field {
|
||||
HostPath,
|
||||
Flags,
|
||||
}
|
||||
|
||||
struct HostFileVisitor;
|
||||
|
||||
impl<'de> de::Visitor<'de> for HostFileVisitor {
|
||||
type Value = HostFile;
|
||||
|
||||
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
formatter.write_str("struct HostFile")
|
||||
}
|
||||
|
||||
fn visit_seq<V>(self, mut seq: V) -> Result<Self::Value, V::Error>
|
||||
where
|
||||
V: de::SeqAccess<'de>,
|
||||
{
|
||||
let host_path = seq
|
||||
.next_element()?
|
||||
.ok_or_else(|| de::Error::invalid_length(0, &self))?;
|
||||
let flags = seq
|
||||
.next_element()?
|
||||
.ok_or_else(|| de::Error::invalid_length(1, &self))?;
|
||||
let inner = std::fs::OpenOptions::new()
|
||||
.read(flags & HostFile::READ != 0)
|
||||
.write(flags & HostFile::WRITE != 0)
|
||||
.append(flags & HostFile::APPEND != 0)
|
||||
.open(&host_path)
|
||||
.map_err(|_| de::Error::custom("Could not open file on this system"))?;
|
||||
Ok(HostFile {
|
||||
inner,
|
||||
host_path,
|
||||
flags,
|
||||
})
|
||||
}
|
||||
|
||||
fn visit_map<V>(self, mut map: V) -> Result<Self::Value, V::Error>
|
||||
where
|
||||
V: de::MapAccess<'de>,
|
||||
{
|
||||
let mut host_path = None;
|
||||
let mut flags = None;
|
||||
while let Some(key) = map.next_key()? {
|
||||
match key {
|
||||
Field::HostPath => {
|
||||
if host_path.is_some() {
|
||||
return Err(de::Error::duplicate_field("host_path"));
|
||||
}
|
||||
host_path = Some(map.next_value()?);
|
||||
}
|
||||
Field::Flags => {
|
||||
if flags.is_some() {
|
||||
return Err(de::Error::duplicate_field("flags"));
|
||||
}
|
||||
flags = Some(map.next_value()?);
|
||||
}
|
||||
}
|
||||
}
|
||||
let host_path = host_path.ok_or_else(|| de::Error::missing_field("host_path"))?;
|
||||
let flags = flags.ok_or_else(|| de::Error::missing_field("flags"))?;
|
||||
let inner = std::fs::OpenOptions::new()
|
||||
.read(flags & HostFile::READ != 0)
|
||||
.write(flags & HostFile::WRITE != 0)
|
||||
.append(flags & HostFile::APPEND != 0)
|
||||
.open(&host_path)
|
||||
.map_err(|_| de::Error::custom("Could not open file on this system"))?;
|
||||
Ok(HostFile {
|
||||
inner,
|
||||
host_path,
|
||||
flags,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const FIELDS: &'static [&'static str] = &["host_path", "flags"];
|
||||
deserializer.deserialize_struct("HostFile", FIELDS, HostFileVisitor)
|
||||
}
|
||||
}
|
||||
|
||||
impl HostFile {
|
||||
const READ: u16 = 1;
|
||||
const WRITE: u16 = 2;
|
||||
const APPEND: u16 = 4;
|
||||
|
||||
/// creates a new host file from a `std::fs::File` and a path
|
||||
pub fn new(file: fs::File, host_path: PathBuf) -> Self {
|
||||
pub fn new(file: fs::File, host_path: PathBuf, read: bool, write: bool, append: bool) -> Self {
|
||||
let mut flags = 0;
|
||||
if read {
|
||||
flags |= Self::READ;
|
||||
}
|
||||
if write {
|
||||
flags |= Self::WRITE;
|
||||
}
|
||||
if append {
|
||||
flags |= Self::APPEND;
|
||||
}
|
||||
Self {
|
||||
inner: file,
|
||||
host_path,
|
||||
flags,
|
||||
}
|
||||
}
|
||||
|
||||
@ -393,6 +499,7 @@ impl Write for HostFile {
|
||||
}
|
||||
}
|
||||
|
||||
#[typetag::serde]
|
||||
impl WasiFile for HostFile {
|
||||
fn last_accessed(&self) -> u64 {
|
||||
self.metadata()
|
||||
@ -519,57 +626,55 @@ fn host_file_bytes_available(_raw_fd: i32) -> Result<usize, WasiFsError> {
|
||||
unimplemented!("host_file_bytes_available not yet implemented for non-Unix-like targets. This probably means the program tried to use wasi::poll_oneoff")
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Stdout(pub std::io::Stdout);
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct Stdout;
|
||||
impl Read for Stdout {
|
||||
fn read(&mut self, _buf: &mut [u8]) -> io::Result<usize> {
|
||||
Err(std::io::Error::new(
|
||||
std::io::ErrorKind::Other,
|
||||
Err(io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
"can not read from stdout",
|
||||
))
|
||||
}
|
||||
fn read_to_end(&mut self, _buf: &mut Vec<u8>) -> io::Result<usize> {
|
||||
Err(std::io::Error::new(
|
||||
std::io::ErrorKind::Other,
|
||||
Err(io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
"can not read from stdout",
|
||||
))
|
||||
}
|
||||
fn read_to_string(&mut self, _buf: &mut String) -> io::Result<usize> {
|
||||
Err(std::io::Error::new(
|
||||
std::io::ErrorKind::Other,
|
||||
Err(io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
"can not read from stdout",
|
||||
))
|
||||
}
|
||||
fn read_exact(&mut self, _buf: &mut [u8]) -> io::Result<()> {
|
||||
Err(std::io::Error::new(
|
||||
std::io::ErrorKind::Other,
|
||||
Err(io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
"can not read from stdout",
|
||||
))
|
||||
}
|
||||
}
|
||||
impl Seek for Stdout {
|
||||
fn seek(&mut self, _pos: io::SeekFrom) -> io::Result<u64> {
|
||||
Err(std::io::Error::new(
|
||||
std::io::ErrorKind::Other,
|
||||
"can not seek stdout",
|
||||
))
|
||||
Err(io::Error::new(io::ErrorKind::Other, "can not seek stdout"))
|
||||
}
|
||||
}
|
||||
impl Write for Stdout {
|
||||
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
||||
self.0.write(buf)
|
||||
io::stdout().write(buf)
|
||||
}
|
||||
fn flush(&mut self) -> io::Result<()> {
|
||||
self.0.flush()
|
||||
io::stdout().flush()
|
||||
}
|
||||
fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
|
||||
self.0.write_all(buf)
|
||||
io::stdout().write_all(buf)
|
||||
}
|
||||
fn write_fmt(&mut self, fmt: ::std::fmt::Arguments) -> io::Result<()> {
|
||||
self.0.write_fmt(fmt)
|
||||
io::stdout().write_fmt(fmt)
|
||||
}
|
||||
}
|
||||
|
||||
#[typetag::serde]
|
||||
impl WasiFile for Stdout {
|
||||
fn last_accessed(&self) -> u64 {
|
||||
0
|
||||
@ -594,7 +699,7 @@ impl WasiFile for Stdout {
|
||||
#[cfg(unix)]
|
||||
fn get_raw_fd(&self) -> Option<i32> {
|
||||
use std::os::unix::io::AsRawFd;
|
||||
Some(self.0.as_raw_fd())
|
||||
Some(io::stdout().as_raw_fd())
|
||||
}
|
||||
|
||||
#[cfg(not(unix))]
|
||||
@ -605,57 +710,55 @@ impl WasiFile for Stdout {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Stderr(pub std::io::Stderr);
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct Stderr;
|
||||
impl Read for Stderr {
|
||||
fn read(&mut self, _buf: &mut [u8]) -> io::Result<usize> {
|
||||
Err(std::io::Error::new(
|
||||
std::io::ErrorKind::Other,
|
||||
Err(io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
"can not read from stderr",
|
||||
))
|
||||
}
|
||||
fn read_to_end(&mut self, _buf: &mut Vec<u8>) -> io::Result<usize> {
|
||||
Err(std::io::Error::new(
|
||||
std::io::ErrorKind::Other,
|
||||
Err(io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
"can not read from stderr",
|
||||
))
|
||||
}
|
||||
fn read_to_string(&mut self, _buf: &mut String) -> io::Result<usize> {
|
||||
Err(std::io::Error::new(
|
||||
std::io::ErrorKind::Other,
|
||||
Err(io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
"can not read from stderr",
|
||||
))
|
||||
}
|
||||
fn read_exact(&mut self, _buf: &mut [u8]) -> io::Result<()> {
|
||||
Err(std::io::Error::new(
|
||||
std::io::ErrorKind::Other,
|
||||
Err(io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
"can not read from stderr",
|
||||
))
|
||||
}
|
||||
}
|
||||
impl Seek for Stderr {
|
||||
fn seek(&mut self, _pos: io::SeekFrom) -> io::Result<u64> {
|
||||
Err(std::io::Error::new(
|
||||
std::io::ErrorKind::Other,
|
||||
"can not seek stderr",
|
||||
))
|
||||
Err(io::Error::new(io::ErrorKind::Other, "can not seek stderr"))
|
||||
}
|
||||
}
|
||||
impl Write for Stderr {
|
||||
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
||||
self.0.write(buf)
|
||||
io::stderr().write(buf)
|
||||
}
|
||||
fn flush(&mut self) -> io::Result<()> {
|
||||
self.0.flush()
|
||||
io::stderr().flush()
|
||||
}
|
||||
fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
|
||||
self.0.write_all(buf)
|
||||
io::stderr().write_all(buf)
|
||||
}
|
||||
fn write_fmt(&mut self, fmt: ::std::fmt::Arguments) -> io::Result<()> {
|
||||
self.0.write_fmt(fmt)
|
||||
io::stderr().write_fmt(fmt)
|
||||
}
|
||||
}
|
||||
|
||||
#[typetag::serde]
|
||||
impl WasiFile for Stderr {
|
||||
fn last_accessed(&self) -> u64 {
|
||||
0
|
||||
@ -680,7 +783,7 @@ impl WasiFile for Stderr {
|
||||
#[cfg(unix)]
|
||||
fn get_raw_fd(&self) -> Option<i32> {
|
||||
use std::os::unix::io::AsRawFd;
|
||||
Some(self.0.as_raw_fd())
|
||||
Some(io::stderr().as_raw_fd())
|
||||
}
|
||||
|
||||
#[cfg(not(unix))]
|
||||
@ -691,57 +794,55 @@ impl WasiFile for Stderr {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Stdin(pub std::io::Stdin);
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct Stdin;
|
||||
impl Read for Stdin {
|
||||
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
||||
self.0.read(buf)
|
||||
io::stdin().read(buf)
|
||||
}
|
||||
fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
|
||||
self.0.read_to_end(buf)
|
||||
io::stdin().read_to_end(buf)
|
||||
}
|
||||
fn read_to_string(&mut self, buf: &mut String) -> io::Result<usize> {
|
||||
self.0.read_to_string(buf)
|
||||
io::stdin().read_to_string(buf)
|
||||
}
|
||||
fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> {
|
||||
self.0.read_exact(buf)
|
||||
io::stdin().read_exact(buf)
|
||||
}
|
||||
}
|
||||
impl Seek for Stdin {
|
||||
fn seek(&mut self, _pos: io::SeekFrom) -> io::Result<u64> {
|
||||
Err(std::io::Error::new(
|
||||
std::io::ErrorKind::Other,
|
||||
"can not seek stdin",
|
||||
))
|
||||
Err(io::Error::new(io::ErrorKind::Other, "can not seek stdin"))
|
||||
}
|
||||
}
|
||||
impl Write for Stdin {
|
||||
fn write(&mut self, _buf: &[u8]) -> io::Result<usize> {
|
||||
Err(std::io::Error::new(
|
||||
std::io::ErrorKind::Other,
|
||||
Err(io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
"can not write to stdin",
|
||||
))
|
||||
}
|
||||
fn flush(&mut self) -> io::Result<()> {
|
||||
Err(std::io::Error::new(
|
||||
std::io::ErrorKind::Other,
|
||||
Err(io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
"can not write to stdin",
|
||||
))
|
||||
}
|
||||
fn write_all(&mut self, _buf: &[u8]) -> io::Result<()> {
|
||||
Err(std::io::Error::new(
|
||||
std::io::ErrorKind::Other,
|
||||
Err(io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
"can not write to stdin",
|
||||
))
|
||||
}
|
||||
fn write_fmt(&mut self, _fmt: ::std::fmt::Arguments) -> io::Result<()> {
|
||||
Err(std::io::Error::new(
|
||||
std::io::ErrorKind::Other,
|
||||
Err(io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
"can not write to stdin",
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
#[typetag::serde]
|
||||
impl WasiFile for Stdin {
|
||||
fn last_accessed(&self) -> u64 {
|
||||
0
|
||||
@ -766,7 +867,7 @@ impl WasiFile for Stdin {
|
||||
#[cfg(unix)]
|
||||
fn get_raw_fd(&self) -> Option<i32> {
|
||||
use std::os::unix::io::AsRawFd;
|
||||
Some(self.0.as_raw_fd())
|
||||
Some(io::stdin().as_raw_fd())
|
||||
}
|
||||
|
||||
#[cfg(not(unix))]
|
||||
|
@ -689,23 +689,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;
|
||||
@ -1681,6 +1669,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
|
||||
@ -1708,10 +1697,22 @@ 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(),
|
||||
true,
|
||||
adjusted_rights & __WASI_RIGHT_FD_WRITE != 0,
|
||||
false,
|
||||
)));
|
||||
}
|
||||
Kind::Buffer { .. } => unimplemented!("wasi::path_open for Buffer type files"),
|
||||
@ -1768,6 +1769,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| {
|
||||
@ -1775,6 +1777,9 @@ pub fn path_open(
|
||||
__WASI_EIO
|
||||
})),
|
||||
new_file_host_path.clone(),
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
)) as Box<dyn WasiFile>)
|
||||
};
|
||||
|
||||
@ -1806,10 +1811,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,
|
||||
|
Loading…
x
Reference in New Issue
Block a user