diff --git a/CHANGELOG.md b/CHANGELOG.md index 774a3ef4e2a..cb9552b6242 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ All PRs to the Wasmer repository must add to this file. Blocks of changes will separated by version increments. ## **[Unreleased]** +- [#554](https://github.com/wasmerio/wasmer/pull/554) Finish implementation of `wasi::fd_seek`, fix bug in filestat ## 0.5.5 - [#541](https://github.com/wasmerio/wasmer/pull/541) Fix dependency graph by making separate test crates; ABI implementations should not depend on compilers. Add Cranelift fork as git submodule of clif-backend diff --git a/lib/wasi-tests/build/wasitests.rs b/lib/wasi-tests/build/wasitests.rs index c305ee44e99..fc4380a6149 100644 --- a/lib/wasi-tests/build/wasitests.rs +++ b/lib/wasi-tests/build/wasitests.rs @@ -32,7 +32,6 @@ pub fn compile(file: &str, ignores: &HashSet) -> Option { }; Command::new("rustc") - .arg("+nightly") .arg(file) .arg("-o") .arg(&normalized_name) @@ -85,7 +84,7 @@ pub fn compile(file: &str, ignores: &HashSet) -> Option { out_str.push_str("vec!["); for (alias, real_dir) in args.mapdir { out_str.push_str(&format!( - "(\"{}\".to_string(), \"{}\".to_string()),", + "(\"{}\".to_string(), ::std::path::PathBuf::from(\"{}\")),", alias, real_dir )); } diff --git a/lib/wasi-tests/tests/wasitests/fseek.rs b/lib/wasi-tests/tests/wasitests/fseek.rs new file mode 100644 index 00000000000..e48dd5814d9 --- /dev/null +++ b/lib/wasi-tests/tests/wasitests/fseek.rs @@ -0,0 +1,13 @@ +#[test] +fn test_fseek() { + assert_wasi_output!( + "../../wasitests/fseek.wasm", + "fseek", + vec![( + ".".to_string(), + ::std::path::PathBuf::from("wasitests/test_fs/hamlet") + ),], + vec![], + "../../wasitests/fseek.out" + ); +} diff --git a/lib/wasi-tests/tests/wasitests/mapdir.rs b/lib/wasi-tests/tests/wasitests/mapdir.rs index beddf10c813..efb99c7a4d6 100644 --- a/lib/wasi-tests/tests/wasitests/mapdir.rs +++ b/lib/wasi-tests/tests/wasitests/mapdir.rs @@ -3,7 +3,10 @@ fn test_mapdir() { assert_wasi_output!( "../../wasitests/mapdir.wasm", "mapdir", - vec![], + vec![( + ".".to_string(), + ::std::path::PathBuf::from("wasitests/test_fs/hamlet") + ),], vec![], "../../wasitests/mapdir.out" ); diff --git a/lib/wasi-tests/tests/wasitests/mod.rs b/lib/wasi-tests/tests/wasitests/mod.rs index 362573068f9..7331b309895 100644 --- a/lib/wasi-tests/tests/wasitests/mod.rs +++ b/lib/wasi-tests/tests/wasitests/mod.rs @@ -9,6 +9,7 @@ mod create_dir; mod envvar; mod file_metadata; mod fs_sandbox_test; +mod fseek; mod hello; mod mapdir; mod quine; diff --git a/lib/wasi-tests/wasitests/create_dir.wasm b/lib/wasi-tests/wasitests/create_dir.wasm index adfb1c2d323..107c7fd37e2 100755 Binary files a/lib/wasi-tests/wasitests/create_dir.wasm and b/lib/wasi-tests/wasitests/create_dir.wasm differ diff --git a/lib/wasi-tests/wasitests/envvar.wasm b/lib/wasi-tests/wasitests/envvar.wasm index 2fb521f3c70..41b18fe0aec 100755 Binary files a/lib/wasi-tests/wasitests/envvar.wasm and b/lib/wasi-tests/wasitests/envvar.wasm differ diff --git a/lib/wasi-tests/wasitests/file_metadata.wasm b/lib/wasi-tests/wasitests/file_metadata.wasm index a51bcdf7db6..daf95fbed16 100755 Binary files a/lib/wasi-tests/wasitests/file_metadata.wasm and b/lib/wasi-tests/wasitests/file_metadata.wasm differ diff --git a/lib/wasi-tests/wasitests/fs_sandbox_test.wasm b/lib/wasi-tests/wasitests/fs_sandbox_test.wasm index f41bc5a170a..175cea24341 100755 Binary files a/lib/wasi-tests/wasitests/fs_sandbox_test.wasm and b/lib/wasi-tests/wasitests/fs_sandbox_test.wasm differ diff --git a/lib/wasi-tests/wasitests/fseek.out b/lib/wasi-tests/wasitests/fseek.out new file mode 100644 index 00000000000..c9f09be6e17 --- /dev/null +++ b/lib/wasi-tests/wasitests/fseek.out @@ -0,0 +1,11 @@ +SCENE III. A room in Polonius' h +ouse. + + Enter LAERTES and OPH + And, sister, as the winds gi +r talk with the Lord Hamlet. + +uits, + Breathing like sanctif +is is for all: + I would not, diff --git a/lib/wasi-tests/wasitests/fseek.rs b/lib/wasi-tests/wasitests/fseek.rs new file mode 100644 index 00000000000..9b9e9f65e1c --- /dev/null +++ b/lib/wasi-tests/wasitests/fseek.rs @@ -0,0 +1,47 @@ +// Args: +// mapdir: .:wasitests/test_fs/hamlet + +use std::fs; +use std::io::{Read, Seek, SeekFrom}; +use std::path::PathBuf; + +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("act1/scene3.txt"); + + let mut file = fs::File::open(&base).expect("Could not open file"); + + let mut buffer = [0u8; 32]; + + assert_eq!(file.read(&mut buffer).unwrap(), 32); + let str_val = std::str::from_utf8(&buffer[..]).unwrap(); + println!("{}", str_val); + + assert_eq!(file.read(&mut buffer).unwrap(), 32); + let str_val = std::str::from_utf8(&buffer[..]).unwrap(); + println!("{}", str_val); + + assert_eq!(file.seek(SeekFrom::Start(123)).unwrap(), 123); + assert_eq!(file.read(&mut buffer).unwrap(), 32); + let str_val = std::str::from_utf8(&buffer[..]).unwrap(); + println!("{}", str_val); + + assert_eq!(file.seek(SeekFrom::End(-123)).unwrap(), 6617); + assert_eq!(file.read(&mut buffer).unwrap(), 32); + let str_val = std::str::from_utf8(&buffer[..]).unwrap(); + println!("{}", str_val); + + assert_eq!(file.seek(SeekFrom::Current(-250)).unwrap(), 6399); + assert_eq!(file.read(&mut buffer).unwrap(), 32); + let str_val = std::str::from_utf8(&buffer[..]).unwrap(); + println!("{}", str_val); + + assert_eq!(file.seek(SeekFrom::Current(50)).unwrap(), 6481); + assert_eq!(file.read(&mut buffer).unwrap(), 32); + let str_val = std::str::from_utf8(&buffer[..]).unwrap(); + println!("{}", str_val); +} diff --git a/lib/wasi-tests/wasitests/fseek.wasm b/lib/wasi-tests/wasitests/fseek.wasm new file mode 100755 index 00000000000..381f768e15a Binary files /dev/null and b/lib/wasi-tests/wasitests/fseek.wasm differ diff --git a/lib/wasi-tests/wasitests/hello.wasm b/lib/wasi-tests/wasitests/hello.wasm index 958d5e36da4..2703be2d1f9 100755 Binary files a/lib/wasi-tests/wasitests/hello.wasm and b/lib/wasi-tests/wasitests/hello.wasm differ diff --git a/lib/wasi-tests/wasitests/mapdir.out b/lib/wasi-tests/wasitests/mapdir.out index baa3809d212..a40625b2412 100644 --- a/lib/wasi-tests/wasitests/mapdir.out +++ b/lib/wasi-tests/wasitests/mapdir.out @@ -1,6 +1,6 @@ -"wasitests/test_fs/hamlet/README.md" -"wasitests/test_fs/hamlet/act1" -"wasitests/test_fs/hamlet/act2" -"wasitests/test_fs/hamlet/act3" -"wasitests/test_fs/hamlet/act4" -"wasitests/test_fs/hamlet/act5" +"./README.md" +"./act1" +"./act2" +"./act3" +"./act4" +"./act5" diff --git a/lib/wasi-tests/wasitests/mapdir.rs b/lib/wasi-tests/wasitests/mapdir.rs index 915e0249c36..d13cf25934d 100644 --- a/lib/wasi-tests/wasitests/mapdir.rs +++ b/lib/wasi-tests/wasitests/mapdir.rs @@ -4,9 +4,9 @@ use std::fs; fn main() { - #[cfg(not(target = "wasi"))] - let read_dir = fs::read_dir("wasitests/test_fs/hamlet").unwrap(); - #[cfg(target = "wasi")] + // #[cfg(not(target_os = "wasi"))] + // let read_dir = fs::read_dir("wasitests/test_fs/hamlet").unwrap(); + // #[cfg(target_os = "wasi")] let read_dir = fs::read_dir(".").unwrap(); let mut out = vec![]; for entry in read_dir { diff --git a/lib/wasi-tests/wasitests/mapdir.wasm b/lib/wasi-tests/wasitests/mapdir.wasm index 32e34888c98..ff940d0e619 100755 Binary files a/lib/wasi-tests/wasitests/mapdir.wasm and b/lib/wasi-tests/wasitests/mapdir.wasm differ diff --git a/lib/wasi-tests/wasitests/quine.wasm b/lib/wasi-tests/wasitests/quine.wasm index 3b195bb0886..fa5e1427070 100755 Binary files a/lib/wasi-tests/wasitests/quine.wasm and b/lib/wasi-tests/wasitests/quine.wasm differ diff --git a/lib/wasi/src/syscalls/mod.rs b/lib/wasi/src/syscalls/mod.rs index 45253262782..440103a99f8 100644 --- a/lib/wasi/src/syscalls/mod.rs +++ b/lib/wasi/src/syscalls/mod.rs @@ -903,7 +903,28 @@ pub fn fd_seek( // TODO: handle case if fd is a dir? match whence { __WASI_WHENCE_CUR => fd_entry.offset = (fd_entry.offset as i64 + offset) as u64, - __WASI_WHENCE_END => unimplemented!("__WASI__WHENCE_END in wasi::fd_seek"), + __WASI_WHENCE_END => { + use std::io::SeekFrom; + match state.fs.inodes[fd_entry.inode].kind { + Kind::File { ref mut handle } => { + let end = wasi_try!(handle.seek(SeekFrom::End(0)).ok().ok_or(__WASI_EIO)); + // TODO: handle case if fd_entry.offset uses 64 bits of a u64 + fd_entry.offset = (end as i64 + offset) as u64; + } + Kind::Symlink { .. } => { + unimplemented!("wasi::fd_seek not implemented for symlinks") + } + Kind::Dir { .. } => { + // TODO: check this + return __WASI_EINVAL; + } + Kind::Buffer { .. } => { + // seeking buffers probably makes sense + // TODO: implement this + return __WASI_EINVAL; + } + } + } __WASI_WHENCE_SET => fd_entry.offset = offset as u64, _ => return __WASI_EINVAL, } @@ -1235,6 +1256,7 @@ pub fn path_filestat_get( let last_segment = path_vec.last().unwrap(); cumulative_path.push(last_segment); + // read it from wasi FS cache first, otherwise check host system if entries.contains_key(last_segment) { state.fs.inodes[entries[last_segment]].stat } else { @@ -1244,7 +1266,25 @@ pub fn path_filestat_get( } let final_path_metadata = wasi_try!(cumulative_path.metadata().map_err(|_| __WASI_EIO)); - wasi_try!(get_stat_for_kind(&state.fs.inodes[inode].kind).ok_or(__WASI_EIO)) + let kind = if final_path_metadata.is_file() { + let file = + wasi_try!(std::fs::File::open(&cumulative_path).ok().ok_or(__WASI_EIO)); + Kind::File { + handle: WasiFile::HostFile(file), + } + } else if final_path_metadata.is_dir() { + Kind::Dir { + parent: Some(inode), + // TODO: verify that this doesn't cause issues with relative paths + path: cumulative_path.clone(), + entries: Default::default(), + } + } else { + // TODO: check this + return __WASI_EINVAL; + }; + + wasi_try!(get_stat_for_kind(&kind).ok_or(__WASI_EIO)) } } _ => {