Update the `wasi` crate for `wasm32-wasi`

This commit updates the `wasi` crate used by the standard library which
is used to implement most of the functionality of libstd on the
`wasm32-wasi` target. This update comes with a brand new crate structure
in the `wasi` crate which caused quite a few changes for the wasi target
here, but it also comes with a significant change to where the
functionality is coming from.

The WASI specification is organized into "snapshots" and a new snapshot
happened recently, so the WASI APIs themselves have changed since the
previous revision. This had only minor impact on the public facing
surface area of libstd, only changing on `u32` to a `u64` in an unstable
API. The actual source for all of these types and such, however, is now
coming from the `wasi_preview_snapshot1` module instead of the
`wasi_unstable` module like before. This means that any implementors
generating binaries will need to ensure that their embedding environment
handles the `wasi_preview_snapshot1` module.
This commit is contained in:
Alex Crichton 2019-11-25 09:27:25 -08:00
parent 7d808659cd
commit f3fb1c5e95
12 changed files with 304 additions and 364 deletions

View File

@ -1294,7 +1294,7 @@ checksum = "473a1265acc8ff1e808cd0a1af8cee3c2ee5200916058a2ca113c29f2d903571"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
"libc", "libc",
"wasi", "wasi 0.7.0",
] ]
[[package]] [[package]]
@ -4301,7 +4301,7 @@ dependencies = [
"rustc_msan", "rustc_msan",
"rustc_tsan", "rustc_tsan",
"unwind", "unwind",
"wasi", "wasi 0.9.0+wasi-snapshot-preview1",
] ]
[[package]] [[package]]
@ -5172,6 +5172,12 @@ name = "wasi"
version = "0.7.0" version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b89c3ce4ce14bdc6fb6beaf9ec7928ca331de5df7e5ea278375642a2f478570d" checksum = "b89c3ce4ce14bdc6fb6beaf9ec7928ca331de5df7e5ea278375642a2f478570d"
[[package]]
name = "wasi"
version = "0.9.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
dependencies = [ dependencies = [
"compiler_builtins", "compiler_builtins",
"rustc-std-workspace-alloc", "rustc-std-workspace-alloc",

View File

@ -54,7 +54,7 @@ fortanix-sgx-abi = { version = "0.3.2", features = ['rustc-dep-of-std'] }
hermit-abi = { version = "0.1", features = ['rustc-dep-of-std'] } hermit-abi = { version = "0.1", features = ['rustc-dep-of-std'] }
[target.wasm32-wasi.dependencies] [target.wasm32-wasi.dependencies]
wasi = { version = "0.7.0", features = ['rustc-dep-of-std', 'alloc'] } wasi = { version = "0.9.0", features = ['rustc-dep-of-std'], default-features = false }
[features] [features]
default = ["std_detect_file_io", "std_detect_dlsym_getauxval"] default = ["std_detect_file_io", "std_detect_dlsym_getauxval"]

View File

@ -1,15 +1,11 @@
use crate::ffi::OsString; use crate::ffi::{CStr, OsStr, OsString};
use crate::marker::PhantomData; use crate::marker::PhantomData;
use crate::os::wasi::ffi::OsStringExt; use crate::os::wasi::ffi::OsStrExt;
use crate::vec; use crate::vec;
use ::wasi::wasi_unstable as wasi; pub unsafe fn init(_argc: isize, _argv: *const *const u8) {}
pub unsafe fn init(_argc: isize, _argv: *const *const u8) { pub unsafe fn cleanup() {}
}
pub unsafe fn cleanup() {
}
pub struct Args { pub struct Args {
iter: vec::IntoIter<OsString>, iter: vec::IntoIter<OsString>,
@ -18,17 +14,24 @@ pub struct Args {
/// Returns the command line arguments /// Returns the command line arguments
pub fn args() -> Args { pub fn args() -> Args {
let buf = wasi::args_sizes_get().and_then(|args_sizes| {
let mut buf = Vec::with_capacity(args_sizes.get_count());
wasi::args_get(args_sizes, |arg| {
let arg = OsString::from_vec(arg.to_vec());
buf.push(arg);
})?;
Ok(buf)
}).unwrap_or(vec![]);
Args { Args {
iter: buf.into_iter(), iter: maybe_args().unwrap_or(Vec::new()).into_iter(),
_dont_send_or_sync_me: PhantomData _dont_send_or_sync_me: PhantomData,
}
}
fn maybe_args() -> Option<Vec<OsString>> {
unsafe {
let (argc, buf_size) = wasi::args_sizes_get().ok()?;
let mut argv = Vec::with_capacity(argc);
let mut buf = Vec::with_capacity(buf_size);
wasi::args_get(argv.as_mut_ptr(), buf.as_mut_ptr()).ok()?;
let mut ret = Vec::with_capacity(argc);
for ptr in argv {
let s = CStr::from_ptr(ptr.cast());
ret.push(OsStr::from_bytes(s.to_bytes()).to_owned());
}
Some(ret)
} }
} }

View File

@ -4,12 +4,10 @@
use crate::fs::{self, File, Metadata, OpenOptions}; use crate::fs::{self, File, Metadata, OpenOptions};
use crate::io::{self, IoSlice, IoSliceMut}; use crate::io::{self, IoSlice, IoSliceMut};
use crate::os::wasi::ffi::OsStrExt;
use crate::path::{Path, PathBuf}; use crate::path::{Path, PathBuf};
use crate::sys::fs::osstr2str;
use crate::sys_common::{AsInner, AsInnerMut, FromInner}; use crate::sys_common::{AsInner, AsInnerMut, FromInner};
use ::wasi::wasi_unstable as wasi;
/// WASI-specific extensions to [`File`]. /// WASI-specific extensions to [`File`].
/// ///
/// [`File`]: ../../../../std/fs/struct.File.html /// [`File`]: ../../../../std/fs/struct.File.html
@ -49,62 +47,62 @@ pub trait FileExt {
/// Returns the current position within the file. /// Returns the current position within the file.
/// ///
/// This corresponds to the `__wasi_fd_tell` syscall and is similar to /// This corresponds to the `fd_tell` syscall and is similar to
/// `seek` where you offset 0 bytes from the current position. /// `seek` where you offset 0 bytes from the current position.
fn tell(&self) -> io::Result<u64>; fn tell(&self) -> io::Result<u64>;
/// Adjust the flags associated with this file. /// Adjust the flags associated with this file.
/// ///
/// This corresponds to the `__wasi_fd_fdstat_set_flags` syscall. /// This corresponds to the `fd_fdstat_set_flags` syscall.
fn fdstat_set_flags(&self, flags: u16) -> io::Result<()>; fn fdstat_set_flags(&self, flags: u16) -> io::Result<()>;
/// Adjust the rights associated with this file. /// Adjust the rights associated with this file.
/// ///
/// This corresponds to the `__wasi_fd_fdstat_set_rights` syscall. /// This corresponds to the `fd_fdstat_set_rights` syscall.
fn fdstat_set_rights(&self, rights: u64, inheriting: u64) -> io::Result<()>; fn fdstat_set_rights(&self, rights: u64, inheriting: u64) -> io::Result<()>;
/// Provide file advisory information on a file descriptor. /// Provide file advisory information on a file descriptor.
/// ///
/// This corresponds to the `__wasi_fd_advise` syscall. /// This corresponds to the `fd_advise` syscall.
fn advise(&self, offset: u64, len: u64, advice: u8) -> io::Result<()>; fn advise(&self, offset: u64, len: u64, advice: u8) -> io::Result<()>;
/// Force the allocation of space in a file. /// Force the allocation of space in a file.
/// ///
/// This corresponds to the `__wasi_fd_allocate` syscall. /// This corresponds to the `fd_allocate` syscall.
fn allocate(&self, offset: u64, len: u64) -> io::Result<()>; fn allocate(&self, offset: u64, len: u64) -> io::Result<()>;
/// Create a directory. /// Create a directory.
/// ///
/// This corresponds to the `__wasi_path_create_directory` syscall. /// This corresponds to the `path_create_directory` syscall.
fn create_directory<P: AsRef<Path>>(&self, dir: P) -> io::Result<()>; fn create_directory<P: AsRef<Path>>(&self, dir: P) -> io::Result<()>;
/// Read the contents of a symbolic link. /// Read the contents of a symbolic link.
/// ///
/// This corresponds to the `__wasi_path_readlink` syscall. /// This corresponds to the `path_readlink` syscall.
fn read_link<P: AsRef<Path>>(&self, path: P) -> io::Result<PathBuf>; fn read_link<P: AsRef<Path>>(&self, path: P) -> io::Result<PathBuf>;
/// Return the attributes of a file or directory. /// Return the attributes of a file or directory.
/// ///
/// This corresponds to the `__wasi_path_filestat_get` syscall. /// This corresponds to the `path_filestat_get` syscall.
fn metadata_at<P: AsRef<Path>>(&self, lookup_flags: u32, path: P) -> io::Result<Metadata>; fn metadata_at<P: AsRef<Path>>(&self, lookup_flags: u32, path: P) -> io::Result<Metadata>;
/// Unlink a file. /// Unlink a file.
/// ///
/// This corresponds to the `__wasi_path_unlink_file` syscall. /// This corresponds to the `path_unlink_file` syscall.
fn remove_file<P: AsRef<Path>>(&self, path: P) -> io::Result<()>; fn remove_file<P: AsRef<Path>>(&self, path: P) -> io::Result<()>;
/// Remove a directory. /// Remove a directory.
/// ///
/// This corresponds to the `__wasi_path_remove_directory` syscall. /// This corresponds to the `path_remove_directory` syscall.
fn remove_directory<P: AsRef<Path>>(&self, path: P) -> io::Result<()>; fn remove_directory<P: AsRef<Path>>(&self, path: P) -> io::Result<()>;
} }
// FIXME: bind __wasi_fd_fdstat_get - need to define a custom return type // FIXME: bind fd_fdstat_get - need to define a custom return type
// FIXME: bind __wasi_fd_readdir - can't return `ReadDir` since we only have entry name // FIXME: bind fd_readdir - can't return `ReadDir` since we only have entry name
// FIXME: bind __wasi_fd_filestat_set_times maybe? - on crates.io for unix // FIXME: bind fd_filestat_set_times maybe? - on crates.io for unix
// FIXME: bind __wasi_path_filestat_set_times maybe? - on crates.io for unix // FIXME: bind path_filestat_set_times maybe? - on crates.io for unix
// FIXME: bind __wasi_poll_oneoff maybe? - probably should wait for I/O to settle // FIXME: bind poll_oneoff maybe? - probably should wait for I/O to settle
// FIXME: bind __wasi_random_get maybe? - on crates.io for unix // FIXME: bind random_get maybe? - on crates.io for unix
impl FileExt for fs::File { impl FileExt for fs::File {
fn read_at(&self, bufs: &mut [IoSliceMut<'_>], offset: u64) -> io::Result<usize> { fn read_at(&self, bufs: &mut [IoSliceMut<'_>], offset: u64) -> io::Result<usize> {
@ -136,9 +134,7 @@ impl FileExt for fs::File {
} }
fn create_directory<P: AsRef<Path>>(&self, dir: P) -> io::Result<()> { fn create_directory<P: AsRef<Path>>(&self, dir: P) -> io::Result<()> {
self.as_inner() self.as_inner().fd().create_directory(osstr2str(dir.as_ref().as_ref())?)
.fd()
.create_directory(dir.as_ref().as_os_str().as_bytes())
} }
fn read_link<P: AsRef<Path>>(&self, path: P) -> io::Result<PathBuf> { fn read_link<P: AsRef<Path>>(&self, path: P) -> io::Result<PathBuf> {
@ -151,15 +147,11 @@ impl FileExt for fs::File {
} }
fn remove_file<P: AsRef<Path>>(&self, path: P) -> io::Result<()> { fn remove_file<P: AsRef<Path>>(&self, path: P) -> io::Result<()> {
self.as_inner() self.as_inner().fd().unlink_file(osstr2str(path.as_ref().as_ref())?)
.fd()
.unlink_file(path.as_ref().as_os_str().as_bytes())
} }
fn remove_directory<P: AsRef<Path>>(&self, path: P) -> io::Result<()> { fn remove_directory<P: AsRef<Path>>(&self, path: P) -> io::Result<()> {
self.as_inner() self.as_inner().fd().remove_directory(osstr2str(path.as_ref().as_ref())?)
.fd()
.remove_directory(path.as_ref().as_os_str().as_bytes())
} }
} }
@ -167,10 +159,10 @@ impl FileExt for fs::File {
/// ///
/// [`fs::OpenOptions`]: ../../../../std/fs/struct.OpenOptions.html /// [`fs::OpenOptions`]: ../../../../std/fs/struct.OpenOptions.html
pub trait OpenOptionsExt { pub trait OpenOptionsExt {
/// Pass custom `dirflags` argument to `__wasi_path_open`. /// Pass custom `dirflags` argument to `path_open`.
/// ///
/// This option configures the `dirflags` argument to the /// This option configures the `dirflags` argument to the
/// `__wasi_path_open` syscall which `OpenOptions` will eventually call. The /// `path_open` syscall which `OpenOptions` will eventually call. The
/// `dirflags` argument configures how the file is looked up, currently /// `dirflags` argument configures how the file is looked up, currently
/// primarily affecting whether symlinks are followed or not. /// primarily affecting whether symlinks are followed or not.
/// ///
@ -188,31 +180,31 @@ pub trait OpenOptionsExt {
fn directory(&mut self, dir: bool) -> &mut Self; fn directory(&mut self, dir: bool) -> &mut Self;
/// Indicates whether `__WASI_FDFLAG_DSYNC` is passed in the `fs_flags` /// Indicates whether `__WASI_FDFLAG_DSYNC` is passed in the `fs_flags`
/// field of `__wasi_path_open`. /// field of `path_open`.
/// ///
/// This option is by default `false` /// This option is by default `false`
fn dsync(&mut self, dsync: bool) -> &mut Self; fn dsync(&mut self, dsync: bool) -> &mut Self;
/// Indicates whether `__WASI_FDFLAG_NONBLOCK` is passed in the `fs_flags` /// Indicates whether `__WASI_FDFLAG_NONBLOCK` is passed in the `fs_flags`
/// field of `__wasi_path_open`. /// field of `path_open`.
/// ///
/// This option is by default `false` /// This option is by default `false`
fn nonblock(&mut self, nonblock: bool) -> &mut Self; fn nonblock(&mut self, nonblock: bool) -> &mut Self;
/// Indicates whether `__WASI_FDFLAG_RSYNC` is passed in the `fs_flags` /// Indicates whether `__WASI_FDFLAG_RSYNC` is passed in the `fs_flags`
/// field of `__wasi_path_open`. /// field of `path_open`.
/// ///
/// This option is by default `false` /// This option is by default `false`
fn rsync(&mut self, rsync: bool) -> &mut Self; fn rsync(&mut self, rsync: bool) -> &mut Self;
/// Indicates whether `__WASI_FDFLAG_SYNC` is passed in the `fs_flags` /// Indicates whether `__WASI_FDFLAG_SYNC` is passed in the `fs_flags`
/// field of `__wasi_path_open`. /// field of `path_open`.
/// ///
/// This option is by default `false` /// This option is by default `false`
fn sync(&mut self, sync: bool) -> &mut Self; fn sync(&mut self, sync: bool) -> &mut Self;
/// Indicates the value that should be passed in for the `fs_rights_base` /// Indicates the value that should be passed in for the `fs_rights_base`
/// parameter of `__wasi_path_open`. /// parameter of `path_open`.
/// ///
/// This option defaults based on the `read` and `write` configuration of /// This option defaults based on the `read` and `write` configuration of
/// this `OpenOptions` builder. If this method is called, however, the /// this `OpenOptions` builder. If this method is called, however, the
@ -220,7 +212,7 @@ pub trait OpenOptionsExt {
fn fs_rights_base(&mut self, rights: u64) -> &mut Self; fn fs_rights_base(&mut self, rights: u64) -> &mut Self;
/// Indicates the value that should be passed in for the /// Indicates the value that should be passed in for the
/// `fs_rights_inheriting` parameter of `__wasi_path_open`. /// `fs_rights_inheriting` parameter of `path_open`.
/// ///
/// The default for this option is the same value as what will be passed /// The default for this option is the same value as what will be passed
/// for the `fs_rights_base` parameter but if this method is called then /// for the `fs_rights_base` parameter but if this method is called then
@ -229,7 +221,7 @@ pub trait OpenOptionsExt {
/// Open a file or directory. /// Open a file or directory.
/// ///
/// This corresponds to the `__wasi_path_open` syscall. /// This corresponds to the `path_open` syscall.
fn open_at<P: AsRef<Path>>(&self, file: &File, path: P) -> io::Result<File>; fn open_at<P: AsRef<Path>>(&self, file: &File, path: P) -> io::Result<File>;
} }
@ -284,38 +276,38 @@ impl OpenOptionsExt for OpenOptions {
/// ///
/// [`fs::Metadata`]: ../../../../std/fs/struct.Metadata.html /// [`fs::Metadata`]: ../../../../std/fs/struct.Metadata.html
pub trait MetadataExt { pub trait MetadataExt {
/// Returns the `st_dev` field of the internal `__wasi_filestat_t` /// Returns the `st_dev` field of the internal `filestat_t`
fn dev(&self) -> u64; fn dev(&self) -> u64;
/// Returns the `st_ino` field of the internal `__wasi_filestat_t` /// Returns the `st_ino` field of the internal `filestat_t`
fn ino(&self) -> u64; fn ino(&self) -> u64;
/// Returns the `st_nlink` field of the internal `__wasi_filestat_t` /// Returns the `st_nlink` field of the internal `filestat_t`
fn nlink(&self) -> u32; fn nlink(&self) -> u64;
/// Returns the `st_atim` field of the internal `__wasi_filestat_t` /// Returns the `st_atim` field of the internal `filestat_t`
fn atim(&self) -> u64; fn atim(&self) -> u64;
/// Returns the `st_mtim` field of the internal `__wasi_filestat_t` /// Returns the `st_mtim` field of the internal `filestat_t`
fn mtim(&self) -> u64; fn mtim(&self) -> u64;
/// Returns the `st_ctim` field of the internal `__wasi_filestat_t` /// Returns the `st_ctim` field of the internal `filestat_t`
fn ctim(&self) -> u64; fn ctim(&self) -> u64;
} }
impl MetadataExt for fs::Metadata { impl MetadataExt for fs::Metadata {
fn dev(&self) -> u64 { fn dev(&self) -> u64 {
self.as_inner().as_wasi().st_dev self.as_inner().as_wasi().dev
} }
fn ino(&self) -> u64 { fn ino(&self) -> u64 {
self.as_inner().as_wasi().st_ino self.as_inner().as_wasi().ino
} }
fn nlink(&self) -> u32 { fn nlink(&self) -> u64 {
self.as_inner().as_wasi().st_nlink self.as_inner().as_wasi().nlink
} }
fn atim(&self) -> u64 { fn atim(&self) -> u64 {
self.as_inner().as_wasi().st_atim self.as_inner().as_wasi().atim
} }
fn mtim(&self) -> u64 { fn mtim(&self) -> u64 {
self.as_inner().as_wasi().st_mtim self.as_inner().as_wasi().mtim
} }
fn ctim(&self) -> u64 { fn ctim(&self) -> u64 {
self.as_inner().as_wasi().st_ctim self.as_inner().as_wasi().ctim
} }
} }
@ -355,7 +347,7 @@ impl FileTypeExt for fs::FileType {
/// ///
/// [`fs::DirEntry`]: ../../../../std/fs/struct.DirEntry.html /// [`fs::DirEntry`]: ../../../../std/fs/struct.DirEntry.html
pub trait DirEntryExt { pub trait DirEntryExt {
/// Returns the underlying `d_ino` field of the `__wasi_dirent_t` /// Returns the underlying `d_ino` field of the `dirent_t`
fn ino(&self) -> u64; fn ino(&self) -> u64;
} }
@ -367,7 +359,7 @@ impl DirEntryExt for fs::DirEntry {
/// Create a hard link. /// Create a hard link.
/// ///
/// This corresponds to the `__wasi_path_link` syscall. /// This corresponds to the `path_link` syscall.
pub fn link<P: AsRef<Path>, U: AsRef<Path>>( pub fn link<P: AsRef<Path>, U: AsRef<Path>>(
old_fd: &File, old_fd: &File,
old_flags: u32, old_flags: u32,
@ -377,15 +369,15 @@ pub fn link<P: AsRef<Path>, U: AsRef<Path>>(
) -> io::Result<()> { ) -> io::Result<()> {
old_fd.as_inner().fd().link( old_fd.as_inner().fd().link(
old_flags, old_flags,
old_path.as_ref().as_os_str().as_bytes(), osstr2str(old_path.as_ref().as_ref())?,
new_fd.as_inner().fd(), new_fd.as_inner().fd(),
new_path.as_ref().as_os_str().as_bytes(), osstr2str(new_path.as_ref().as_ref())?,
) )
} }
/// Rename a file or directory. /// Rename a file or directory.
/// ///
/// This corresponds to the `__wasi_path_rename` syscall. /// This corresponds to the `path_rename` syscall.
pub fn rename<P: AsRef<Path>, U: AsRef<Path>>( pub fn rename<P: AsRef<Path>, U: AsRef<Path>>(
old_fd: &File, old_fd: &File,
old_path: P, old_path: P,
@ -393,22 +385,21 @@ pub fn rename<P: AsRef<Path>, U: AsRef<Path>>(
new_path: U, new_path: U,
) -> io::Result<()> { ) -> io::Result<()> {
old_fd.as_inner().fd().rename( old_fd.as_inner().fd().rename(
old_path.as_ref().as_os_str().as_bytes(), osstr2str(old_path.as_ref().as_ref())?,
new_fd.as_inner().fd(), new_fd.as_inner().fd(),
new_path.as_ref().as_os_str().as_bytes(), osstr2str(new_path.as_ref().as_ref())?,
) )
} }
/// Create a symbolic link. /// Create a symbolic link.
/// ///
/// This corresponds to the `__wasi_path_symlink` syscall. /// This corresponds to the `path_symlink` syscall.
pub fn symlink<P: AsRef<Path>, U: AsRef<Path>>( pub fn symlink<P: AsRef<Path>, U: AsRef<Path>>(
old_path: P, old_path: P,
fd: &File, fd: &File,
new_path: U, new_path: U,
) -> io::Result<()> { ) -> io::Result<()> {
fd.as_inner().fd().symlink( fd.as_inner()
old_path.as_ref().as_os_str().as_bytes(), .fd()
new_path.as_ref().as_os_str().as_bytes(), .symlink(osstr2str(old_path.as_ref().as_ref())?, osstr2str(new_path.as_ref().as_ref())?)
)
} }

View File

@ -8,8 +8,6 @@ use crate::sys;
use crate::net; use crate::net;
use crate::sys_common::{AsInner, FromInner, IntoInner}; use crate::sys_common::{AsInner, FromInner, IntoInner};
use ::wasi::wasi_unstable as wasi;
/// Raw file descriptors. /// Raw file descriptors.
pub type RawFd = u32; pub type RawFd = u32;
@ -127,18 +125,18 @@ impl IntoRawFd for fs::File {
impl AsRawFd for io::Stdin { impl AsRawFd for io::Stdin {
fn as_raw_fd(&self) -> RawFd { fn as_raw_fd(&self) -> RawFd {
wasi::STDIN_FD sys::stdio::Stdin.as_raw_fd()
} }
} }
impl AsRawFd for io::Stdout { impl AsRawFd for io::Stdout {
fn as_raw_fd(&self) -> RawFd { fn as_raw_fd(&self) -> RawFd {
wasi::STDOUT_FD sys::stdio::Stdout.as_raw_fd()
} }
} }
impl AsRawFd for io::Stderr { impl AsRawFd for io::Stderr {
fn as_raw_fd(&self) -> RawFd { fn as_raw_fd(&self) -> RawFd {
wasi::STDERR_FD sys::stdio::Stderr.as_raw_fd()
} }
} }

View File

@ -1,40 +1,31 @@
#![allow(dead_code)] #![allow(dead_code)]
use super::err2io;
use crate::io::{self, IoSlice, IoSliceMut, SeekFrom}; use crate::io::{self, IoSlice, IoSliceMut, SeekFrom};
use crate::mem; use crate::mem;
use crate::net::Shutdown; use crate::net::Shutdown;
use super::err2io;
use ::wasi::wasi_unstable as wasi;
#[derive(Debug)] #[derive(Debug)]
pub struct WasiFd { pub struct WasiFd {
fd: wasi::Fd, fd: wasi::Fd,
} }
fn iovec<'a>(a: &'a mut [IoSliceMut<'_>]) -> &'a [wasi::IoVec] { fn iovec<'a>(a: &'a mut [IoSliceMut<'_>]) -> &'a [wasi::Iovec] {
assert_eq!( assert_eq!(mem::size_of::<IoSliceMut<'_>>(), mem::size_of::<wasi::Iovec>());
mem::size_of::<IoSliceMut<'_>>(), assert_eq!(mem::align_of::<IoSliceMut<'_>>(), mem::align_of::<wasi::Iovec>());
mem::size_of::<wasi::IoVec>()
);
assert_eq!(
mem::align_of::<IoSliceMut<'_>>(),
mem::align_of::<wasi::IoVec>()
);
/// SAFETY: `IoSliceMut` and `IoVec` have exactly the same memory layout /// SAFETY: `IoSliceMut` and `IoVec` have exactly the same memory layout
unsafe { mem::transmute(a) } unsafe {
mem::transmute(a)
}
} }
fn ciovec<'a>(a: &'a [IoSlice<'_>]) -> &'a [wasi::CIoVec] { fn ciovec<'a>(a: &'a [IoSlice<'_>]) -> &'a [wasi::Ciovec] {
assert_eq!( assert_eq!(mem::size_of::<IoSlice<'_>>(), mem::size_of::<wasi::Ciovec>());
mem::size_of::<IoSlice<'_>>(), assert_eq!(mem::align_of::<IoSlice<'_>>(), mem::align_of::<wasi::Ciovec>());
mem::size_of::<wasi::CIoVec>()
);
assert_eq!(
mem::align_of::<IoSlice<'_>>(),
mem::align_of::<wasi::CIoVec>()
);
/// SAFETY: `IoSlice` and `CIoVec` have exactly the same memory layout /// SAFETY: `IoSlice` and `CIoVec` have exactly the same memory layout
unsafe { mem::transmute(a) } unsafe {
mem::transmute(a)
}
} }
impl WasiFd { impl WasiFd {
@ -87,7 +78,7 @@ impl WasiFd {
// FIXME: __wasi_fd_fdstat_get // FIXME: __wasi_fd_fdstat_get
pub fn set_flags(&self, flags: wasi::FdFlags) -> io::Result<()> { pub fn set_flags(&self, flags: wasi::Fdflags) -> io::Result<()> {
unsafe { wasi::fd_fdstat_set_flags(self.fd, flags).map_err(err2io) } unsafe { wasi::fd_fdstat_set_flags(self.fd, flags).map_err(err2io) }
} }
@ -107,31 +98,30 @@ impl WasiFd {
unsafe { wasi::fd_allocate(self.fd, offset, len).map_err(err2io) } unsafe { wasi::fd_allocate(self.fd, offset, len).map_err(err2io) }
} }
pub fn create_directory(&self, path: &[u8]) -> io::Result<()> { pub fn create_directory(&self, path: &str) -> io::Result<()> {
unsafe { wasi::path_create_directory(self.fd, path).map_err(err2io) } unsafe { wasi::path_create_directory(self.fd, path).map_err(err2io) }
} }
pub fn link( pub fn link(
&self, &self,
old_flags: wasi::LookupFlags, old_flags: wasi::Lookupflags,
old_path: &[u8], old_path: &str,
new_fd: &WasiFd, new_fd: &WasiFd,
new_path: &[u8], new_path: &str,
) -> io::Result<()> { ) -> io::Result<()> {
unsafe { unsafe {
wasi::path_link(self.fd, old_flags, old_path, new_fd.fd, new_path) wasi::path_link(self.fd, old_flags, old_path, new_fd.fd, new_path).map_err(err2io)
.map_err(err2io)
} }
} }
pub fn open( pub fn open(
&self, &self,
dirflags: wasi::LookupFlags, dirflags: wasi::Lookupflags,
path: &[u8], path: &str,
oflags: wasi::OFlags, oflags: wasi::Oflags,
fs_rights_base: wasi::Rights, fs_rights_base: wasi::Rights,
fs_rights_inheriting: wasi::Rights, fs_rights_inheriting: wasi::Rights,
fs_flags: wasi::FdFlags, fs_flags: wasi::Fdflags,
) -> io::Result<WasiFd> { ) -> io::Result<WasiFd> {
unsafe { unsafe {
wasi::path_open( wasi::path_open(
@ -142,25 +132,25 @@ impl WasiFd {
fs_rights_base, fs_rights_base,
fs_rights_inheriting, fs_rights_inheriting,
fs_flags, fs_flags,
).map(|fd| WasiFd::from_raw(fd)).map_err(err2io) )
.map(|fd| WasiFd::from_raw(fd))
.map_err(err2io)
} }
} }
pub fn readdir(&self, buf: &mut [u8], cookie: wasi::DirCookie) -> io::Result<usize> { pub fn readdir(&self, buf: &mut [u8], cookie: wasi::Dircookie) -> io::Result<usize> {
unsafe { wasi::fd_readdir(self.fd, buf, cookie).map_err(err2io) } unsafe { wasi::fd_readdir(self.fd, buf.as_mut_ptr(), buf.len(), cookie).map_err(err2io) }
} }
pub fn readlink(&self, path: &[u8], buf: &mut [u8]) -> io::Result<usize> { pub fn readlink(&self, path: &str, buf: &mut [u8]) -> io::Result<usize> {
unsafe { wasi::path_readlink(self.fd, path, buf).map_err(err2io) } unsafe { wasi::path_readlink(self.fd, path, buf.as_mut_ptr(), buf.len()).map_err(err2io) }
} }
pub fn rename(&self, old_path: &[u8], new_fd: &WasiFd, new_path: &[u8]) -> io::Result<()> { pub fn rename(&self, old_path: &str, new_fd: &WasiFd, new_path: &str) -> io::Result<()> {
unsafe { unsafe { wasi::path_rename(self.fd, old_path, new_fd.fd, new_path).map_err(err2io) }
wasi::path_rename(self.fd, old_path, new_fd.fd, new_path).map_err(err2io)
}
} }
pub fn filestat_get(&self) -> io::Result<wasi::FileStat> { pub fn filestat_get(&self) -> io::Result<wasi::Filestat> {
unsafe { wasi::fd_filestat_get(self.fd).map_err(err2io) } unsafe { wasi::fd_filestat_get(self.fd).map_err(err2io) }
} }
@ -168,11 +158,9 @@ impl WasiFd {
&self, &self,
atim: wasi::Timestamp, atim: wasi::Timestamp,
mtim: wasi::Timestamp, mtim: wasi::Timestamp,
fstflags: wasi::FstFlags, fstflags: wasi::Fstflags,
) -> io::Result<()> { ) -> io::Result<()> {
unsafe { unsafe { wasi::fd_filestat_set_times(self.fd, atim, mtim, fstflags).map_err(err2io) }
wasi::fd_filestat_set_times(self.fd, atim, mtim, fstflags).map_err(err2io)
}
} }
pub fn filestat_set_size(&self, size: u64) -> io::Result<()> { pub fn filestat_set_size(&self, size: u64) -> io::Result<()> {
@ -181,61 +169,55 @@ impl WasiFd {
pub fn path_filestat_get( pub fn path_filestat_get(
&self, &self,
flags: wasi::LookupFlags, flags: wasi::Lookupflags,
path: &[u8], path: &str,
) -> io::Result<wasi::FileStat> { ) -> io::Result<wasi::Filestat> {
unsafe { wasi::path_filestat_get(self.fd, flags, path).map_err(err2io) } unsafe { wasi::path_filestat_get(self.fd, flags, path).map_err(err2io) }
} }
pub fn path_filestat_set_times( pub fn path_filestat_set_times(
&self, &self,
flags: wasi::LookupFlags, flags: wasi::Lookupflags,
path: &[u8], path: &str,
atim: wasi::Timestamp, atim: wasi::Timestamp,
mtim: wasi::Timestamp, mtim: wasi::Timestamp,
fstflags: wasi::FstFlags, fstflags: wasi::Fstflags,
) -> io::Result<()> { ) -> io::Result<()> {
unsafe { unsafe {
wasi::path_filestat_set_times( wasi::path_filestat_set_times(self.fd, flags, path, atim, mtim, fstflags)
self.fd, .map_err(err2io)
flags,
path,
atim,
mtim,
fstflags,
).map_err(err2io)
} }
} }
pub fn symlink(&self, old_path: &[u8], new_path: &[u8]) -> io::Result<()> { pub fn symlink(&self, old_path: &str, new_path: &str) -> io::Result<()> {
unsafe { wasi::path_symlink(old_path, self.fd, new_path).map_err(err2io) } unsafe { wasi::path_symlink(old_path, self.fd, new_path).map_err(err2io) }
} }
pub fn unlink_file(&self, path: &[u8]) -> io::Result<()> { pub fn unlink_file(&self, path: &str) -> io::Result<()> {
unsafe { wasi::path_unlink_file(self.fd, path).map_err(err2io) } unsafe { wasi::path_unlink_file(self.fd, path).map_err(err2io) }
} }
pub fn remove_directory(&self, path: &[u8]) -> io::Result<()> { pub fn remove_directory(&self, path: &str) -> io::Result<()> {
unsafe { wasi::path_remove_directory(self.fd, path).map_err(err2io) } unsafe { wasi::path_remove_directory(self.fd, path).map_err(err2io) }
} }
pub fn sock_recv( pub fn sock_recv(
&self, &self,
ri_data: &mut [IoSliceMut<'_>], ri_data: &mut [IoSliceMut<'_>],
ri_flags: wasi::RiFlags, ri_flags: wasi::Riflags,
) -> io::Result<(usize, wasi::RoFlags)> { ) -> io::Result<(usize, wasi::Roflags)> {
unsafe { wasi::sock_recv(self.fd, iovec(ri_data), ri_flags).map_err(err2io) } unsafe { wasi::sock_recv(self.fd, iovec(ri_data), ri_flags).map_err(err2io) }
} }
pub fn sock_send(&self, si_data: &[IoSlice<'_>], si_flags: wasi::SiFlags) -> io::Result<usize> { pub fn sock_send(&self, si_data: &[IoSlice<'_>], si_flags: wasi::Siflags) -> io::Result<usize> {
unsafe { wasi::sock_send(self.fd, ciovec(si_data), si_flags).map_err(err2io) } unsafe { wasi::sock_send(self.fd, ciovec(si_data), si_flags).map_err(err2io) }
} }
pub fn sock_shutdown(&self, how: Shutdown) -> io::Result<()> { pub fn sock_shutdown(&self, how: Shutdown) -> io::Result<()> {
let how = match how { let how = match how {
Shutdown::Read => wasi::SHUT_RD, Shutdown::Read => wasi::SDFLAGS_RD,
Shutdown::Write => wasi::SHUT_WR, Shutdown::Write => wasi::SDFLAGS_WR,
Shutdown::Both => wasi::SHUT_WR | wasi::SHUT_RD, Shutdown::Both => wasi::SDFLAGS_WR | wasi::SDFLAGS_RD,
}; };
unsafe { wasi::sock_shutdown(self.fd, how).map_err(err2io) } unsafe { wasi::sock_shutdown(self.fd, how).map_err(err2io) }
} }

View File

@ -15,20 +15,18 @@ use crate::sys_common::FromInner;
pub use crate::sys_common::fs::copy; pub use crate::sys_common::fs::copy;
pub use crate::sys_common::fs::remove_dir_all; pub use crate::sys_common::fs::remove_dir_all;
use ::wasi::wasi_unstable as wasi;
pub struct File { pub struct File {
fd: WasiFd, fd: WasiFd,
} }
#[derive(Clone)] #[derive(Clone)]
pub struct FileAttr { pub struct FileAttr {
meta: wasi::FileStat, meta: wasi::Filestat,
} }
pub struct ReadDir { pub struct ReadDir {
inner: Arc<ReadDirInner>, inner: Arc<ReadDirInner>,
cookie: Option<wasi::DirCookie>, cookie: Option<wasi::Dircookie>,
buf: Vec<u8>, buf: Vec<u8>,
offset: usize, offset: usize,
cap: usize, cap: usize,
@ -49,9 +47,9 @@ pub struct DirEntry {
pub struct OpenOptions { pub struct OpenOptions {
read: bool, read: bool,
write: bool, write: bool,
dirflags: wasi::LookupFlags, dirflags: wasi::Lookupflags,
fdflags: wasi::FdFlags, fdflags: wasi::Fdflags,
oflags: wasi::OFlags, oflags: wasi::Oflags,
rights_base: Option<wasi::Rights>, rights_base: Option<wasi::Rights>,
rights_inheriting: Option<wasi::Rights>, rights_inheriting: Option<wasi::Rights>,
} }
@ -63,7 +61,7 @@ pub struct FilePermissions {
#[derive(PartialEq, Eq, Hash, Debug, Copy, Clone)] #[derive(PartialEq, Eq, Hash, Debug, Copy, Clone)]
pub struct FileType { pub struct FileType {
bits: wasi::FileType, bits: wasi::Filetype,
} }
#[derive(Debug)] #[derive(Debug)]
@ -71,7 +69,7 @@ pub struct DirBuilder {}
impl FileAttr { impl FileAttr {
pub fn size(&self) -> u64 { pub fn size(&self) -> u64 {
self.meta.st_size self.meta.size
} }
pub fn perm(&self) -> FilePermissions { pub fn perm(&self) -> FilePermissions {
@ -80,24 +78,22 @@ impl FileAttr {
} }
pub fn file_type(&self) -> FileType { pub fn file_type(&self) -> FileType {
FileType { FileType { bits: self.meta.filetype }
bits: self.meta.st_filetype,
}
} }
pub fn modified(&self) -> io::Result<SystemTime> { pub fn modified(&self) -> io::Result<SystemTime> {
Ok(SystemTime::from_wasi_timestamp(self.meta.st_mtim)) Ok(SystemTime::from_wasi_timestamp(self.meta.mtim))
} }
pub fn accessed(&self) -> io::Result<SystemTime> { pub fn accessed(&self) -> io::Result<SystemTime> {
Ok(SystemTime::from_wasi_timestamp(self.meta.st_atim)) Ok(SystemTime::from_wasi_timestamp(self.meta.atim))
} }
pub fn created(&self) -> io::Result<SystemTime> { pub fn created(&self) -> io::Result<SystemTime> {
Ok(SystemTime::from_wasi_timestamp(self.meta.st_ctim)) Ok(SystemTime::from_wasi_timestamp(self.meta.ctim))
} }
pub fn as_wasi(&self) -> &wasi::FileStat { pub fn as_wasi(&self) -> &wasi::Filestat {
&self.meta &self.meta
} }
} }
@ -125,7 +121,7 @@ impl FileType {
self.bits == wasi::FILETYPE_SYMBOLIC_LINK self.bits == wasi::FILETYPE_SYMBOLIC_LINK
} }
pub fn bits(&self) -> wasi::FileType { pub fn bits(&self) -> wasi::Filetype {
self.bits self.bits
} }
} }
@ -177,8 +173,7 @@ impl Iterator for ReadDir {
continue; continue;
} }
let (dirent, data) = data.split_at(dirent_size); let (dirent, data) = data.split_at(dirent_size);
let dirent = let dirent = unsafe { ptr::read_unaligned(dirent.as_ptr() as *const wasi::Dirent) };
unsafe { ptr::read_unaligned(dirent.as_ptr() as *const wasi::Dirent) };
// If the file name was truncated, then we need to reinvoke // If the file name was truncated, then we need to reinvoke
// `readdir` so we truncate our buffer to start over and reread this // `readdir` so we truncate our buffer to start over and reread this
@ -224,17 +219,11 @@ impl DirEntry {
} }
pub fn metadata(&self) -> io::Result<FileAttr> { pub fn metadata(&self) -> io::Result<FileAttr> {
metadata_at( metadata_at(&self.inner.dir.fd, 0, OsStr::from_bytes(&self.name).as_ref())
&self.inner.dir.fd,
0,
OsStr::from_bytes(&self.name).as_ref(),
)
} }
pub fn file_type(&self) -> io::Result<FileType> { pub fn file_type(&self) -> io::Result<FileType> {
Ok(FileType { Ok(FileType { bits: self.meta.d_type })
bits: self.meta.d_type,
})
} }
pub fn ino(&self) -> wasi::Inode { pub fn ino(&self) -> wasi::Inode {
@ -245,7 +234,7 @@ impl DirEntry {
impl OpenOptions { impl OpenOptions {
pub fn new() -> OpenOptions { pub fn new() -> OpenOptions {
let mut base = OpenOptions::default(); let mut base = OpenOptions::default();
base.dirflags = wasi::LOOKUP_SYMLINK_FOLLOW; base.dirflags = wasi::LOOKUPFLAGS_SYMLINK_FOLLOW;
return base; return base;
} }
@ -258,23 +247,23 @@ impl OpenOptions {
} }
pub fn truncate(&mut self, truncate: bool) { pub fn truncate(&mut self, truncate: bool) {
self.oflag(wasi::O_TRUNC, truncate); self.oflag(wasi::OFLAGS_TRUNC, truncate);
} }
pub fn create(&mut self, create: bool) { pub fn create(&mut self, create: bool) {
self.oflag(wasi::O_CREAT, create); self.oflag(wasi::OFLAGS_CREAT, create);
} }
pub fn create_new(&mut self, create_new: bool) { pub fn create_new(&mut self, create_new: bool) {
self.oflag(wasi::O_EXCL, create_new); self.oflag(wasi::OFLAGS_EXCL, create_new);
self.oflag(wasi::O_CREAT, create_new); self.oflag(wasi::OFLAGS_CREAT, create_new);
} }
pub fn directory(&mut self, directory: bool) { pub fn directory(&mut self, directory: bool) {
self.oflag(wasi::O_DIRECTORY, directory); self.oflag(wasi::OFLAGS_DIRECTORY, directory);
} }
fn oflag(&mut self, bit: wasi::OFlags, set: bool) { fn oflag(&mut self, bit: wasi::Oflags, set: bool) {
if set { if set {
self.oflags |= bit; self.oflags |= bit;
} else { } else {
@ -283,26 +272,26 @@ impl OpenOptions {
} }
pub fn append(&mut self, set: bool) { pub fn append(&mut self, set: bool) {
self.fdflag(wasi::FDFLAG_APPEND, set); self.fdflag(wasi::FDFLAGS_APPEND, set);
} }
pub fn dsync(&mut self, set: bool) { pub fn dsync(&mut self, set: bool) {
self.fdflag(wasi::FDFLAG_DSYNC, set); self.fdflag(wasi::FDFLAGS_DSYNC, set);
} }
pub fn nonblock(&mut self, set: bool) { pub fn nonblock(&mut self, set: bool) {
self.fdflag(wasi::FDFLAG_NONBLOCK, set); self.fdflag(wasi::FDFLAGS_NONBLOCK, set);
} }
pub fn rsync(&mut self, set: bool) { pub fn rsync(&mut self, set: bool) {
self.fdflag(wasi::FDFLAG_RSYNC, set); self.fdflag(wasi::FDFLAGS_RSYNC, set);
} }
pub fn sync(&mut self, set: bool) { pub fn sync(&mut self, set: bool) {
self.fdflag(wasi::FDFLAG_SYNC, set); self.fdflag(wasi::FDFLAGS_SYNC, set);
} }
fn fdflag(&mut self, bit: wasi::FdFlags, set: bool) { fn fdflag(&mut self, bit: wasi::Fdflags, set: bool) {
if set { if set {
self.fdflags |= bit; self.fdflags |= bit;
} else { } else {
@ -330,36 +319,36 @@ impl OpenOptions {
// based on that. // based on that.
let mut base = 0; let mut base = 0;
if self.read { if self.read {
base |= wasi::RIGHT_FD_READ; base |= wasi::RIGHTS_FD_READ;
base |= wasi::RIGHT_FD_READDIR; base |= wasi::RIGHTS_FD_READDIR;
} }
if self.write { if self.write {
base |= wasi::RIGHT_FD_WRITE; base |= wasi::RIGHTS_FD_WRITE;
base |= wasi::RIGHT_FD_DATASYNC; base |= wasi::RIGHTS_FD_DATASYNC;
base |= wasi::RIGHT_FD_ALLOCATE; base |= wasi::RIGHTS_FD_ALLOCATE;
base |= wasi::RIGHT_FD_FILESTAT_SET_SIZE; base |= wasi::RIGHTS_FD_FILESTAT_SET_SIZE;
} }
// FIXME: some of these should probably be read-only or write-only... // FIXME: some of these should probably be read-only or write-only...
base |= wasi::RIGHT_FD_ADVISE; base |= wasi::RIGHTS_FD_ADVISE;
base |= wasi::RIGHT_FD_FDSTAT_SET_FLAGS; base |= wasi::RIGHTS_FD_FDSTAT_SET_FLAGS;
base |= wasi::RIGHT_FD_FILESTAT_SET_TIMES; base |= wasi::RIGHTS_FD_FILESTAT_SET_TIMES;
base |= wasi::RIGHT_FD_SEEK; base |= wasi::RIGHTS_FD_SEEK;
base |= wasi::RIGHT_FD_SYNC; base |= wasi::RIGHTS_FD_SYNC;
base |= wasi::RIGHT_FD_TELL; base |= wasi::RIGHTS_FD_TELL;
base |= wasi::RIGHT_PATH_CREATE_DIRECTORY; base |= wasi::RIGHTS_PATH_CREATE_DIRECTORY;
base |= wasi::RIGHT_PATH_CREATE_FILE; base |= wasi::RIGHTS_PATH_CREATE_FILE;
base |= wasi::RIGHT_PATH_FILESTAT_GET; base |= wasi::RIGHTS_PATH_FILESTAT_GET;
base |= wasi::RIGHT_PATH_LINK_SOURCE; base |= wasi::RIGHTS_PATH_LINK_SOURCE;
base |= wasi::RIGHT_PATH_LINK_TARGET; base |= wasi::RIGHTS_PATH_LINK_TARGET;
base |= wasi::RIGHT_PATH_OPEN; base |= wasi::RIGHTS_PATH_OPEN;
base |= wasi::RIGHT_PATH_READLINK; base |= wasi::RIGHTS_PATH_READLINK;
base |= wasi::RIGHT_PATH_REMOVE_DIRECTORY; base |= wasi::RIGHTS_PATH_REMOVE_DIRECTORY;
base |= wasi::RIGHT_PATH_RENAME_SOURCE; base |= wasi::RIGHTS_PATH_RENAME_SOURCE;
base |= wasi::RIGHT_PATH_RENAME_TARGET; base |= wasi::RIGHTS_PATH_RENAME_TARGET;
base |= wasi::RIGHT_PATH_SYMLINK; base |= wasi::RIGHTS_PATH_SYMLINK;
base |= wasi::RIGHT_PATH_UNLINK_FILE; base |= wasi::RIGHTS_PATH_UNLINK_FILE;
base |= wasi::RIGHT_POLL_FD_READWRITE; base |= wasi::RIGHTS_POLL_FD_READWRITE;
return base; return base;
} }
@ -368,14 +357,14 @@ impl OpenOptions {
self.rights_inheriting.unwrap_or_else(|| self.rights_base()) self.rights_inheriting.unwrap_or_else(|| self.rights_base())
} }
pub fn lookup_flags(&mut self, flags: wasi::LookupFlags) { pub fn lookup_flags(&mut self, flags: wasi::Lookupflags) {
self.dirflags = flags; self.dirflags = flags;
} }
} }
impl File { impl File {
pub fn open(path: &Path, opts: &OpenOptions) -> io::Result<File> { pub fn open(path: &Path, opts: &OpenOptions) -> io::Result<File> {
let (dir, file) = open_parent(path, wasi::RIGHT_PATH_OPEN)?; let (dir, file) = open_parent(path, wasi::RIGHTS_PATH_OPEN)?;
open_at(&dir, &file, opts) open_at(&dir, &file, opts)
} }
@ -387,11 +376,7 @@ impl File {
self.fd.filestat_get().map(|meta| FileAttr { meta }) self.fd.filestat_get().map(|meta| FileAttr { meta })
} }
pub fn metadata_at( pub fn metadata_at(&self, flags: wasi::Lookupflags, path: &Path) -> io::Result<FileAttr> {
&self,
flags: wasi::LookupFlags,
path: &Path,
) -> io::Result<FileAttr> {
metadata_at(&self.fd, flags, path) metadata_at(&self.fd, flags, path)
} }
@ -457,11 +442,7 @@ impl File {
impl FromInner<u32> for File { impl FromInner<u32> for File {
fn from_inner(fd: u32) -> File { fn from_inner(fd: u32) -> File {
unsafe { unsafe { File { fd: WasiFd::from_raw(fd) } }
File {
fd: WasiFd::from_raw(fd),
}
}
} }
} }
@ -471,16 +452,14 @@ impl DirBuilder {
} }
pub fn mkdir(&self, p: &Path) -> io::Result<()> { pub fn mkdir(&self, p: &Path) -> io::Result<()> {
let (dir, file) = open_parent(p, wasi::RIGHT_PATH_CREATE_DIRECTORY)?; let (dir, file) = open_parent(p, wasi::RIGHTS_PATH_CREATE_DIRECTORY)?;
dir.create_directory(file.as_os_str().as_bytes()) dir.create_directory(osstr2str(file.as_ref())?)
} }
} }
impl fmt::Debug for File { impl fmt::Debug for File {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("File") f.debug_struct("File").field("fd", &self.fd.as_raw()).finish()
.field("fd", &self.fd.as_raw())
.finish()
} }
} }
@ -494,26 +473,19 @@ pub fn readdir(p: &Path) -> io::Result<ReadDir> {
buf: vec![0; 128], buf: vec![0; 128],
offset: 0, offset: 0,
cap: 0, cap: 0,
inner: Arc::new(ReadDirInner { inner: Arc::new(ReadDirInner { dir, root: p.to_path_buf() }),
dir,
root: p.to_path_buf(),
}),
}) })
} }
pub fn unlink(p: &Path) -> io::Result<()> { pub fn unlink(p: &Path) -> io::Result<()> {
let (dir, file) = open_parent(p, wasi::RIGHT_PATH_UNLINK_FILE)?; let (dir, file) = open_parent(p, wasi::RIGHTS_PATH_UNLINK_FILE)?;
dir.unlink_file(file.as_os_str().as_bytes()) dir.unlink_file(osstr2str(file.as_ref())?)
} }
pub fn rename(old: &Path, new: &Path) -> io::Result<()> { pub fn rename(old: &Path, new: &Path) -> io::Result<()> {
let (old, old_file) = open_parent(old, wasi::RIGHT_PATH_RENAME_SOURCE)?; let (old, old_file) = open_parent(old, wasi::RIGHTS_PATH_RENAME_SOURCE)?;
let (new, new_file) = open_parent(new, wasi::RIGHT_PATH_RENAME_TARGET)?; let (new, new_file) = open_parent(new, wasi::RIGHTS_PATH_RENAME_TARGET)?;
old.rename( old.rename(osstr2str(old_file.as_ref())?, &new, osstr2str(new_file.as_ref())?)
old_file.as_os_str().as_bytes(),
&new,
new_file.as_os_str().as_bytes(),
)
} }
pub fn set_perm(_p: &Path, _perm: FilePermissions) -> io::Result<()> { pub fn set_perm(_p: &Path, _perm: FilePermissions) -> io::Result<()> {
@ -523,12 +495,12 @@ pub fn set_perm(_p: &Path, _perm: FilePermissions) -> io::Result<()> {
} }
pub fn rmdir(p: &Path) -> io::Result<()> { pub fn rmdir(p: &Path) -> io::Result<()> {
let (dir, file) = open_parent(p, wasi::RIGHT_PATH_REMOVE_DIRECTORY)?; let (dir, file) = open_parent(p, wasi::RIGHTS_PATH_REMOVE_DIRECTORY)?;
dir.remove_directory(file.as_os_str().as_bytes()) dir.remove_directory(osstr2str(file.as_ref())?)
} }
pub fn readlink(p: &Path) -> io::Result<PathBuf> { pub fn readlink(p: &Path) -> io::Result<PathBuf> {
let (dir, file) = open_parent(p, wasi::RIGHT_PATH_READLINK)?; let (dir, file) = open_parent(p, wasi::RIGHTS_PATH_READLINK)?;
read_link(&dir, &file) read_link(&dir, &file)
} }
@ -549,7 +521,7 @@ fn read_link(fd: &WasiFd, file: &Path) -> io::Result<PathBuf> {
// Now that we have an initial guess of how big to make our buffer, call // Now that we have an initial guess of how big to make our buffer, call
// `readlink` in a loop until it fails or reports it filled fewer bytes than // `readlink` in a loop until it fails or reports it filled fewer bytes than
// we asked for, indicating we got everything. // we asked for, indicating we got everything.
let file = file.as_os_str().as_bytes(); let file = osstr2str(file.as_ref())?;
let mut destination = vec![0u8; initial_size]; let mut destination = vec![0u8; initial_size];
loop { loop {
let len = fd.readlink(file, &mut destination)?; let len = fd.readlink(file, &mut destination)?;
@ -564,38 +536,34 @@ fn read_link(fd: &WasiFd, file: &Path) -> io::Result<PathBuf> {
} }
pub fn symlink(src: &Path, dst: &Path) -> io::Result<()> { pub fn symlink(src: &Path, dst: &Path) -> io::Result<()> {
let (dst, dst_file) = open_parent(dst, wasi::RIGHT_PATH_SYMLINK)?; let (dst, dst_file) = open_parent(dst, wasi::RIGHTS_PATH_SYMLINK)?;
dst.symlink(src.as_os_str().as_bytes(), dst_file.as_os_str().as_bytes()) dst.symlink(osstr2str(src.as_ref())?, osstr2str(dst_file.as_ref())?)
} }
pub fn link(src: &Path, dst: &Path) -> io::Result<()> { pub fn link(src: &Path, dst: &Path) -> io::Result<()> {
let (src, src_file) = open_parent(src, wasi::RIGHT_PATH_LINK_SOURCE)?; let (src, src_file) = open_parent(src, wasi::RIGHTS_PATH_LINK_SOURCE)?;
let (dst, dst_file) = open_parent(dst, wasi::RIGHT_PATH_LINK_TARGET)?; let (dst, dst_file) = open_parent(dst, wasi::RIGHTS_PATH_LINK_TARGET)?;
src.link( src.link(
wasi::LOOKUP_SYMLINK_FOLLOW, wasi::LOOKUPFLAGS_SYMLINK_FOLLOW,
src_file.as_os_str().as_bytes(), osstr2str(src_file.as_ref())?,
&dst, &dst,
dst_file.as_os_str().as_bytes(), osstr2str(dst_file.as_ref())?,
) )
} }
pub fn stat(p: &Path) -> io::Result<FileAttr> { pub fn stat(p: &Path) -> io::Result<FileAttr> {
let (dir, file) = open_parent(p, wasi::RIGHT_PATH_FILESTAT_GET)?; let (dir, file) = open_parent(p, wasi::RIGHTS_PATH_FILESTAT_GET)?;
metadata_at(&dir, wasi::LOOKUP_SYMLINK_FOLLOW, &file) metadata_at(&dir, wasi::LOOKUPFLAGS_SYMLINK_FOLLOW, &file)
} }
pub fn lstat(p: &Path) -> io::Result<FileAttr> { pub fn lstat(p: &Path) -> io::Result<FileAttr> {
let (dir, file) = open_parent(p, wasi::RIGHT_PATH_FILESTAT_GET)?; let (dir, file) = open_parent(p, wasi::RIGHTS_PATH_FILESTAT_GET)?;
metadata_at(&dir, 0, &file) metadata_at(&dir, 0, &file)
} }
fn metadata_at( fn metadata_at(fd: &WasiFd, flags: wasi::Lookupflags, path: &Path) -> io::Result<FileAttr> {
fd: &WasiFd, let meta = fd.path_filestat_get(flags, osstr2str(path.as_ref())?)?;
flags: wasi::LookupFlags, Ok(FileAttr { meta })
path: &Path,
) -> io::Result<FileAttr> {
fd.path_filestat_get(flags, path.as_os_str().as_bytes())
.map(|meta| FileAttr { meta })
} }
pub fn canonicalize(_p: &Path) -> io::Result<PathBuf> { pub fn canonicalize(_p: &Path) -> io::Result<PathBuf> {
@ -607,7 +575,7 @@ pub fn canonicalize(_p: &Path) -> io::Result<PathBuf> {
fn open_at(fd: &WasiFd, path: &Path, opts: &OpenOptions) -> io::Result<File> { fn open_at(fd: &WasiFd, path: &Path, opts: &OpenOptions) -> io::Result<File> {
let fd = fd.open( let fd = fd.open(
opts.dirflags, opts.dirflags,
path.as_os_str().as_bytes(), osstr2str(path.as_ref())?,
opts.oflags, opts.oflags,
opts.rights_base(), opts.rights_base(),
opts.rights_inheriting(), opts.rights_inheriting(),
@ -643,10 +611,7 @@ fn open_at(fd: &WasiFd, path: &Path, opts: &OpenOptions) -> io::Result<File> {
/// ///
/// Note that this can fail if `p` doesn't look like it can be opened relative /// Note that this can fail if `p` doesn't look like it can be opened relative
/// to any preopened file descriptor. /// to any preopened file descriptor.
fn open_parent( fn open_parent(p: &Path, rights: wasi::Rights) -> io::Result<(ManuallyDrop<WasiFd>, PathBuf)> {
p: &Path,
rights: wasi::Rights,
) -> io::Result<(ManuallyDrop<WasiFd>, PathBuf)> {
let p = CString::new(p.as_os_str().as_bytes())?; let p = CString::new(p.as_os_str().as_bytes())?;
unsafe { unsafe {
let mut ret = ptr::null(); let mut ret = ptr::null();
@ -671,3 +636,7 @@ fn open_parent(
return Ok((ManuallyDrop::new(WasiFd::from_raw(fd as u32)), path)); return Ok((ManuallyDrop::new(WasiFd::from_raw(fd as u32)), path));
} }
} }
pub fn osstr2str(f: &OsStr) -> io::Result<&str> {
f.to_str().ok_or_else(|| io::Error::new(io::ErrorKind::Other, "input must be utf-8"))
}

View File

@ -1,12 +1,9 @@
use crate::marker::PhantomData; use crate::marker::PhantomData;
use crate::slice; use crate::slice;
use ::wasi::wasi_unstable as wasi;
use core::ffi::c_void;
#[repr(transparent)] #[repr(transparent)]
pub struct IoSlice<'a> { pub struct IoSlice<'a> {
vec: wasi::CIoVec, vec: wasi::Ciovec,
_p: PhantomData<&'a [u8]>, _p: PhantomData<&'a [u8]>,
} }
@ -14,8 +11,8 @@ impl<'a> IoSlice<'a> {
#[inline] #[inline]
pub fn new(buf: &'a [u8]) -> IoSlice<'a> { pub fn new(buf: &'a [u8]) -> IoSlice<'a> {
IoSlice { IoSlice {
vec: wasi::CIoVec { vec: wasi::Ciovec {
buf: buf.as_ptr() as *const c_void, buf: buf.as_ptr(),
buf_len: buf.len(), buf_len: buf.len(),
}, },
_p: PhantomData, _p: PhantomData,
@ -44,7 +41,7 @@ impl<'a> IoSlice<'a> {
#[repr(transparent)] #[repr(transparent)]
pub struct IoSliceMut<'a> { pub struct IoSliceMut<'a> {
vec: wasi::IoVec, vec: wasi::Iovec,
_p: PhantomData<&'a mut [u8]>, _p: PhantomData<&'a mut [u8]>,
} }
@ -52,8 +49,8 @@ impl<'a> IoSliceMut<'a> {
#[inline] #[inline]
pub fn new(buf: &'a mut [u8]) -> IoSliceMut<'a> { pub fn new(buf: &'a mut [u8]) -> IoSliceMut<'a> {
IoSliceMut { IoSliceMut {
vec: wasi::IoVec { vec: wasi::Iovec {
buf: buf.as_mut_ptr() as *mut c_void, buf: buf.as_mut_ptr(),
buf_len: buf.len() buf_len: buf.len()
}, },
_p: PhantomData, _p: PhantomData,

View File

@ -17,7 +17,6 @@
use crate::io as std_io; use crate::io as std_io;
use crate::mem; use crate::mem;
use crate::os::raw::c_char; use crate::os::raw::c_char;
use ::wasi::wasi_unstable as wasi;
pub mod alloc; pub mod alloc;
pub mod args; pub mod args;
@ -72,25 +71,21 @@ pub fn decode_error_kind(errno: i32) -> std_io::ErrorKind {
if errno > u16::max_value() as i32 || errno < 0 { if errno > u16::max_value() as i32 || errno < 0 {
return Other; return Other;
} }
let code = match wasi::Error::new(errno as u16) { match errno as u16 {
Some(code) => code, wasi::ERRNO_CONNREFUSED => ConnectionRefused,
None => return Other, wasi::ERRNO_CONNRESET => ConnectionReset,
}; wasi::ERRNO_PERM | wasi::ERRNO_ACCES => PermissionDenied,
match code { wasi::ERRNO_PIPE => BrokenPipe,
wasi::ECONNREFUSED => ConnectionRefused, wasi::ERRNO_NOTCONN => NotConnected,
wasi::ECONNRESET => ConnectionReset, wasi::ERRNO_CONNABORTED => ConnectionAborted,
wasi::EPERM | wasi::EACCES => PermissionDenied, wasi::ERRNO_ADDRNOTAVAIL => AddrNotAvailable,
wasi::EPIPE => BrokenPipe, wasi::ERRNO_ADDRINUSE => AddrInUse,
wasi::ENOTCONN => NotConnected, wasi::ERRNO_NOENT => NotFound,
wasi::ECONNABORTED => ConnectionAborted, wasi::ERRNO_INTR => Interrupted,
wasi::EADDRNOTAVAIL => AddrNotAvailable, wasi::ERRNO_INVAL => InvalidInput,
wasi::EADDRINUSE => AddrInUse, wasi::ERRNO_TIMEDOUT => TimedOut,
wasi::ENOENT => NotFound, wasi::ERRNO_EXIST => AlreadyExists,
wasi::EINTR => Interrupted, wasi::ERRNO_AGAIN => WouldBlock,
wasi::EINVAL => InvalidInput,
wasi::ETIMEDOUT => TimedOut,
wasi::EEXIST => AlreadyExists,
wasi::EAGAIN => WouldBlock,
_ => Other, _ => Other,
} }
} }
@ -116,16 +111,13 @@ pub unsafe fn abort_internal() -> ! {
pub fn hashmap_random_keys() -> (u64, u64) { pub fn hashmap_random_keys() -> (u64, u64) {
let mut ret = (0u64, 0u64); let mut ret = (0u64, 0u64);
unsafe { unsafe {
let base = &mut ret as *mut (u64, u64) as *mut core::ffi::c_void; let base = &mut ret as *mut (u64, u64) as *mut u8;
let len = mem::size_of_val(&ret); let len = mem::size_of_val(&ret);
let ret = wasi::raw::__wasi_random_get(base, len); wasi::random_get(base, len).expect("random_get failure");
if ret != 0 {
panic!("__wasi_random_get failure")
}
} }
return ret return ret
} }
fn err2io(err: wasi::Error) -> std_io::Error { fn err2io(err: wasi::Error) -> std_io::Error {
std_io::Error::from_raw_os_error(err.get() as i32) std_io::Error::from_raw_os_error(err.raw_error().into())
} }

View File

@ -2,8 +2,6 @@ use crate::io::{self, IoSlice, IoSliceMut};
use crate::mem::ManuallyDrop; use crate::mem::ManuallyDrop;
use crate::sys::fd::WasiFd; use crate::sys::fd::WasiFd;
use ::wasi::wasi_unstable as wasi;
pub struct Stdin; pub struct Stdin;
pub struct Stdout; pub struct Stdout;
pub struct Stderr; pub struct Stderr;
@ -18,8 +16,11 @@ impl Stdin {
} }
pub fn read_vectored(&self, data: &mut [IoSliceMut<'_>]) -> io::Result<usize> { pub fn read_vectored(&self, data: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
ManuallyDrop::new(unsafe { WasiFd::from_raw(wasi::STDIN_FD) }) ManuallyDrop::new(unsafe { WasiFd::from_raw(self.as_raw_fd()) }).read(data)
.read(data) }
pub fn as_raw_fd(&self) -> u32 {
0
} }
} }
@ -33,13 +34,16 @@ impl Stdout {
} }
pub fn write_vectored(&self, data: &[IoSlice<'_>]) -> io::Result<usize> { pub fn write_vectored(&self, data: &[IoSlice<'_>]) -> io::Result<usize> {
ManuallyDrop::new(unsafe { WasiFd::from_raw(wasi::STDOUT_FD) }) ManuallyDrop::new(unsafe { WasiFd::from_raw(self.as_raw_fd()) }).write(data)
.write(data)
} }
pub fn flush(&self) -> io::Result<()> { pub fn flush(&self) -> io::Result<()> {
Ok(()) Ok(())
} }
pub fn as_raw_fd(&self) -> u32 {
1
}
} }
impl Stderr { impl Stderr {
@ -52,13 +56,16 @@ impl Stderr {
} }
pub fn write_vectored(&self, data: &[IoSlice<'_>]) -> io::Result<usize> { pub fn write_vectored(&self, data: &[IoSlice<'_>]) -> io::Result<usize> {
ManuallyDrop::new(unsafe { WasiFd::from_raw(wasi::STDERR_FD) }) ManuallyDrop::new(unsafe { WasiFd::from_raw(self.as_raw_fd()) }).write(data)
.write(data)
} }
pub fn flush(&self) -> io::Result<()> { pub fn flush(&self) -> io::Result<()> {
Ok(()) Ok(())
} }
pub fn as_raw_fd(&self) -> u32 {
2
}
} }
impl io::Write for Stderr { impl io::Write for Stderr {
@ -74,7 +81,7 @@ impl io::Write for Stderr {
pub const STDIN_BUF_SIZE: usize = crate::sys_common::io::DEFAULT_BUF_SIZE; pub const STDIN_BUF_SIZE: usize = crate::sys_common::io::DEFAULT_BUF_SIZE;
pub fn is_ebadf(err: &io::Error) -> bool { pub fn is_ebadf(err: &io::Error) -> bool {
err.raw_os_error() == Some(wasi::EBADF.get() as i32) err.raw_os_error() == Some(wasi::ERRNO_BADF.into())
} }
pub fn panic_output() -> Option<impl io::Write> { pub fn panic_output() -> Option<impl io::Write> {

View File

@ -4,22 +4,18 @@ use crate::mem;
use crate::sys::{unsupported, Void}; use crate::sys::{unsupported, Void};
use crate::time::Duration; use crate::time::Duration;
use ::wasi::wasi_unstable as wasi;
pub struct Thread(Void); pub struct Thread(Void);
pub const DEFAULT_MIN_STACK_SIZE: usize = 4096; pub const DEFAULT_MIN_STACK_SIZE: usize = 4096;
impl Thread { impl Thread {
// unsafe: see thread::Builder::spawn_unchecked for safety requirements // unsafe: see thread::Builder::spawn_unchecked for safety requirements
pub unsafe fn new(_stack: usize, _p: Box<dyn FnOnce()>) pub unsafe fn new(_stack: usize, _p: Box<dyn FnOnce()>) -> io::Result<Thread> {
-> io::Result<Thread>
{
unsupported() unsupported()
} }
pub fn yield_now() { pub fn yield_now() {
let ret = wasi::sched_yield(); let ret = unsafe { wasi::sched_yield() };
debug_assert_eq!(ret, Ok(())); debug_assert_eq!(ret, Ok(()));
} }
@ -33,32 +29,30 @@ impl Thread {
const USERDATA: wasi::Userdata = 0x0123_45678; const USERDATA: wasi::Userdata = 0x0123_45678;
let clock = wasi::raw::__wasi_subscription_u_clock_t { let clock = wasi::SubscriptionClock {
identifier: 0, id: wasi::CLOCKID_MONOTONIC,
clock_id: wasi::CLOCK_MONOTONIC,
timeout: nanos as u64, timeout: nanos as u64,
precision: 0, precision: 0,
flags: 0, flags: 0,
}; };
let in_ = [wasi::Subscription { let in_ = wasi::Subscription {
userdata: USERDATA, userdata: USERDATA,
type_: wasi::EVENTTYPE_CLOCK, r#type: wasi::EVENTTYPE_CLOCK,
u: wasi::raw::__wasi_subscription_u { clock: clock }, u: wasi::SubscriptionU { clock },
}];
let (res, event) = unsafe {
let mut out: [wasi::Event; 1] = mem::zeroed();
let res = wasi::poll_oneoff(&in_, &mut out);
(res, out[0])
}; };
match (res, event) { unsafe {
(Ok(1), wasi::Event { let mut event: wasi::Event = mem::zeroed();
userdata: USERDATA, let res = wasi::poll_oneoff(&in_, &mut event, 1);
error: 0, match (res, event) {
type_: wasi::EVENTTYPE_CLOCK, (
.. Ok(1),
}) => {} wasi::Event {
_ => panic!("thread::sleep(): unexpected result of poll_oneoff"), userdata: USERDATA, error: 0, r#type: wasi::EVENTTYPE_CLOCK, ..
},
) => {}
_ => panic!("thread::sleep(): unexpected result of poll_oneoff"),
}
} }
} }
@ -69,6 +63,10 @@ impl Thread {
pub mod guard { pub mod guard {
pub type Guard = !; pub type Guard = !;
pub unsafe fn current() -> Option<Guard> { None } pub unsafe fn current() -> Option<Guard> {
pub unsafe fn init() -> Option<Guard> { None } None
}
pub unsafe fn init() -> Option<Guard> {
None
}
} }

View File

@ -1,5 +1,4 @@
use crate::time::Duration; use crate::time::Duration;
use ::wasi::wasi_unstable as wasi;
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
pub struct Instant(Duration); pub struct Instant(Duration);
@ -10,19 +9,18 @@ pub struct SystemTime(Duration);
pub const UNIX_EPOCH: SystemTime = SystemTime(Duration::from_secs(0)); pub const UNIX_EPOCH: SystemTime = SystemTime(Duration::from_secs(0));
fn current_time(clock: u32) -> Duration { fn current_time(clock: u32) -> Duration {
let ts = wasi::clock_time_get( let ts = unsafe {
clock, wasi::clock_time_get(
1, // precision... seems ignored though? clock, 1, // precision... seems ignored though?
).unwrap(); )
Duration::new( .unwrap()
(ts / 1_000_000_000) as u64, };
(ts % 1_000_000_000) as u32, Duration::new((ts / 1_000_000_000) as u64, (ts % 1_000_000_000) as u32)
)
} }
impl Instant { impl Instant {
pub fn now() -> Instant { pub fn now() -> Instant {
Instant(current_time(wasi::CLOCK_MONOTONIC)) Instant(current_time(wasi::CLOCKID_MONOTONIC))
} }
pub const fn zero() -> Instant { pub const fn zero() -> Instant {
@ -48,15 +46,14 @@ impl Instant {
impl SystemTime { impl SystemTime {
pub fn now() -> SystemTime { pub fn now() -> SystemTime {
SystemTime(current_time(wasi::CLOCK_REALTIME)) SystemTime(current_time(wasi::CLOCKID_REALTIME))
} }
pub fn from_wasi_timestamp(ts: wasi::Timestamp) -> SystemTime { pub fn from_wasi_timestamp(ts: wasi::Timestamp) -> SystemTime {
SystemTime(Duration::from_nanos(ts)) SystemTime(Duration::from_nanos(ts))
} }
pub fn sub_time(&self, other: &SystemTime) pub fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> {
-> Result<Duration, Duration> {
self.0.checked_sub(other.0).ok_or_else(|| other.0 - self.0) self.0.checked_sub(other.0).ok_or_else(|| other.0 - self.0)
} }