diff --git a/CHANGELOG.md b/CHANGELOG.md index 1d019ef0031..2480b2996a2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,12 @@ # Changelog ## **[Unreleased]** +- [#1566](https://github.com/wasmerio/wasmer/pull/1566) Add support for opening special Unix files to the WASI FS + +## TODO: 1.0.0-alpha1.0 +- Wasmer refactor lands + +## TODO: 17... - [#1554](https://github.com/wasmerio/wasmer/pull/1554) Update supported stable Rust version to 1.45.2. - [#1552](https://github.com/wasmerio/wasmer/pull/1552) Disable `sigint` handler by default. diff --git a/Cargo.lock b/Cargo.lock index e34200d2ce9..35c9a0cb907 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2456,7 +2456,7 @@ dependencies = [ "typetag", "wasmer", "wasmer-wasi", - "wast", + "wast 17.0.0", ] [[package]] @@ -2494,6 +2494,15 @@ version = "0.57.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32fddd575d477c6e9702484139cf9f23dcd554b06d185ed0f56c857dd3a47aa6" +[[package]] +name = "wast" +version = "17.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a0e1c36b928fca33dbaf96235188f5fad22ee87100e26cc606bd0fbabdf1932" +dependencies = [ + "leb128", +] + [[package]] name = "wast" version = "21.0.0" @@ -2509,7 +2518,7 @@ version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ce85d72b74242c340e9e3492cfb602652d7bb324c3172dd441b5577e39a2e18c" dependencies = [ - "wast", + "wast 21.0.0", ] [[package]] diff --git a/lib/wasi/src/state/mod.rs b/lib/wasi/src/state/mod.rs index 86c0994eac6..15dca18d118 100644 --- a/lib/wasi/src/state/mod.rs +++ b/lib/wasi/src/state/mod.rs @@ -819,6 +819,56 @@ impl WasiFs { relative_path: link_value, } } else { + #[cfg(unix)] + { + use std::os::unix::fs::FileTypeExt; + let file_type: __wasi_filetype_t = if file_type.is_char_device() + { + __WASI_FILETYPE_CHARACTER_DEVICE + } else if file_type.is_block_device() { + __WASI_FILETYPE_BLOCK_DEVICE + } else if file_type.is_fifo() { + // FIFO doesn't seem to fit any other type, so unknown + __WASI_FILETYPE_UNKNOWN + } else if file_type.is_socket() { + // TODO: how do we know if it's a `__WASI_FILETYPE_SOCKET_STREAM` or + // a `__WASI_FILETYPE_SOCKET_DGRAM`? + __WASI_FILETYPE_SOCKET_STREAM + } else { + unimplemented!("state::get_inode_at_path unknown file type: not file, directory, symlink, char device, block device, fifo, or socket"); + }; + + let kind = Kind::File { + handle: None, + path: file.clone(), + fd: None, + }; + let new_inode = self.create_inode_with_stat( + kind, + false, + file.to_string_lossy().to_string(), + __wasi_filestat_t { + st_filetype: file_type, + ..__wasi_filestat_t::default() + }, + ); + if let Kind::Dir { + ref mut entries, .. + } = &mut self.inodes[cur_inode].kind + { + entries.insert( + component.as_os_str().to_string_lossy().to_string(), + new_inode, + ); + } else { + unreachable!( + "Attempted to insert special device into non-directory" + ); + } + // perhaps just continue with symlink resolution and return at the end + return Ok(new_inode); + } + #[cfg(not(unix))] unimplemented!("state::get_inode_at_path unknown file type: not file, directory, or symlink"); }; @@ -1178,25 +1228,29 @@ impl WasiFs { is_preopened: bool, name: String, ) -> Result { - let mut stat = self.get_stat_for_kind(&kind).ok_or(__WASI_EIO)?; - stat.st_ino = self.get_next_inode_index(); - - Ok(self.inodes.insert(InodeVal { - stat, - is_preopened, - name, - kind, - })) + let stat = self.get_stat_for_kind(&kind).ok_or(__WASI_EIO)?; + Ok(self.create_inode_with_stat(kind, is_preopened, name, stat)) } - /// creates an inode and inserts it given a Kind, does not assume the file exists to + /// Creates an inode and inserts it given a Kind, does not assume the file exists. pub(crate) fn create_inode_with_default_stat( &mut self, kind: Kind, is_preopened: bool, name: String, ) -> Inode { - let mut stat = __wasi_filestat_t::default(); + let stat = __wasi_filestat_t::default(); + self.create_inode_with_stat(kind, is_preopened, name, stat) + } + + /// Creates an inode with the given filestat and inserts it. + pub(crate) fn create_inode_with_stat( + &mut self, + kind: Kind, + is_preopened: bool, + name: String, + mut stat: __wasi_filestat_t, + ) -> Inode { stat.st_ino = self.get_next_inode_index(); self.inodes.insert(InodeVal { diff --git a/tests/ignores.txt b/tests/ignores.txt index 7cf7bd43a7b..85b22ac4cfc 100644 --- a/tests/ignores.txt +++ b/tests/ignores.txt @@ -67,3 +67,7 @@ wasitests::unstable::file_metadata on windows wasitests::unstable::fseek on windows wasitests::unstable::path_link on windows wasitests::unstable::path_symlink on windows + +# This test is meant to only run on Unix +wasitests::unstable::unix_open_special_files on windows +wasitests::snapshot1::unix_open_special_files on windows diff --git a/tests/wasi-wast/README.md b/tests/wasi-wast/README.md index d71abed2984..42a05578a40 100644 --- a/tests/wasi-wast/README.md +++ b/tests/wasi-wast/README.md @@ -25,3 +25,8 @@ And here's an example of how to generate these tests: cargo run -- -as # set up the toolchains for all targets cargo run -- -ag # generate the WASI tests for all targets ``` + +## Updating in Wasmer + +Run +`git subtree pull --prefix tests/wasi-wast git@github.com:wasmerio/wasi-tests master --squash` diff --git a/tests/wasi-wast/wasi/snapshot1/unix_open_special_files.wasm b/tests/wasi-wast/wasi/snapshot1/unix_open_special_files.wasm new file mode 100755 index 00000000000..68382fe5ec6 Binary files /dev/null and b/tests/wasi-wast/wasi/snapshot1/unix_open_special_files.wasm differ diff --git a/tests/wasi-wast/wasi/snapshot1/unix_open_special_files.wast b/tests/wasi-wast/wasi/snapshot1/unix_open_special_files.wast new file mode 100644 index 00000000000..a26cb3bd70d --- /dev/null +++ b/tests/wasi-wast/wasi/snapshot1/unix_open_special_files.wast @@ -0,0 +1,5 @@ +(wasi_test "unix_open_special_files.wasm" + (map_dirs "/dev:/dev") + (assert_return (i64.const 0)) + (assert_stdout "13\n") +) \ No newline at end of file diff --git a/tests/wasi-wast/wasi/tests/unix_open_special_files.rs b/tests/wasi-wast/wasi/tests/unix_open_special_files.rs new file mode 100644 index 00000000000..d449cbea84b --- /dev/null +++ b/tests/wasi-wast/wasi/tests/unix_open_special_files.rs @@ -0,0 +1,14 @@ +// WASI: +// mapdir: /dev:/dev + +use std::fs; +use std::io::Write; + +fn main() { + let mut f = fs::OpenOptions::new() + .write(true) + .open("/dev/null") + .unwrap(); + let result = f.write(b"hello, world!").unwrap(); + println!("{}", result); +} diff --git a/tests/wasi-wast/wasi/unstable/unix_open_special_files.wasm b/tests/wasi-wast/wasi/unstable/unix_open_special_files.wasm new file mode 100755 index 00000000000..7b489106219 Binary files /dev/null and b/tests/wasi-wast/wasi/unstable/unix_open_special_files.wasm differ diff --git a/tests/wasi-wast/wasi/unstable/unix_open_special_files.wast b/tests/wasi-wast/wasi/unstable/unix_open_special_files.wast new file mode 100644 index 00000000000..a26cb3bd70d --- /dev/null +++ b/tests/wasi-wast/wasi/unstable/unix_open_special_files.wast @@ -0,0 +1,5 @@ +(wasi_test "unix_open_special_files.wasm" + (map_dirs "/dev:/dev") + (assert_return (i64.const 0)) + (assert_stdout "13\n") +) \ No newline at end of file