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 support for WASI opening Unix special files #1566

Merged
merged 7 commits into from
Aug 31, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -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.
Expand Down
13 changes: 11 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

76 changes: 65 additions & 11 deletions lib/wasi/src/state/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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!(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a comment, I'm not sure whether this is reachable or not? If the place in the wasi-fs where the host path is being injected is controlled by the user then it seems like it should be a full Err? Otherwise, if this is part of mirroring the host paths then this is fine as is.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It shouldn't be reachable without unsafe I believe: it's not possible to put files in the virtual root right now, they have to come from a preopened directory and that directory will be mounted at /.

"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");
};

Expand Down Expand Up @@ -1178,25 +1228,29 @@ impl WasiFs {
is_preopened: bool,
name: String,
) -> Result<Inode, __wasi_errno_t> {
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 {
Expand Down
4 changes: 4 additions & 0 deletions tests/ignores.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
5 changes: 5 additions & 0 deletions tests/wasi-wast/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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`
Binary file not shown.
5 changes: 5 additions & 0 deletions tests/wasi-wast/wasi/snapshot1/unix_open_special_files.wast
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
(wasi_test "unix_open_special_files.wasm"
(map_dirs "/dev:/dev")
(assert_return (i64.const 0))
(assert_stdout "13\n")
)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

newline please!

14 changes: 14 additions & 0 deletions tests/wasi-wast/wasi/tests/unix_open_special_files.rs
Original file line number Diff line number Diff line change
@@ -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);
}
Binary file not shown.
5 changes: 5 additions & 0 deletions tests/wasi-wast/wasi/unstable/unix_open_special_files.wast
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
(wasi_test "unix_open_special_files.wasm"
(map_dirs "/dev:/dev")
(assert_return (i64.const 0))
(assert_stdout "13\n")
)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

newline please

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

these are generated files, I can regenerate them all but it'd probably be best to do that separately