diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 584e057bfc..fc5bd1c468 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -119,19 +119,22 @@ jobs: env: RUST_BACKTRACE: 1 - # Install wasm32-unknown-emscripten target, and ensure `crates/wasi-common` - # compiles to Emscripten. - # TODO enable once rust-lang/rust#66308 is fixed - # emscripten: - # name: Emscripten - # runs-on: ubuntu-latest - # steps: - # - uses: actions/checkout@v1 - # with: - # submodules: true - # - uses: ./.github/actions/install-rust - # - run: rustup target add wasm32-unknown-emscripten - # - run: cargo build --target wasm32-unknown-emscripten -p wasi-common + # Check whether `crates/wasi-common` cross-compiles to the following targets: + # * wasm32-unknown-emscripten + # * armv7-unknown-linux-gnueabihf + crosscompile: + name: Cross-platform checks + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v1 + with: + submodules: true + - uses: ./.github/actions/install-rust + - run: | + rustup target add wasm32-unknown-emscripten + cargo check --target wasm32-unknown-emscripten -p wasi-common + rustup target add armv7-unknown-linux-gnueabihf + cargo check --target armv7-unknown-linux-gnueabihf -p wasi-common # Perform all tests (debug mode) for `wasmtime`. This runs stable/beta/nightly # channels of Rust as well as macOS/Linux/Windows. diff --git a/crates/wasi-common/src/old/snapshot_0/sys/unix/emscripten/host_impl.rs b/crates/wasi-common/src/old/snapshot_0/sys/unix/emscripten/host_impl.rs index 412280a519..ac25f4a9d2 100644 --- a/crates/wasi-common/src/old/snapshot_0/sys/unix/emscripten/host_impl.rs +++ b/crates/wasi-common/src/old/snapshot_0/sys/unix/emscripten/host_impl.rs @@ -1,15 +1,15 @@ -use crate::old::snapshot_0::{wasi, Result}; +use crate::old::snapshot_0::wasi::{self, WasiResult}; pub(crate) const O_RSYNC: yanix::file::OFlag = yanix::file::OFlag::RSYNC; -pub(crate) fn stdev_from_nix(dev: libc::dev_t) -> Result { +pub(crate) fn stdev_from_nix(dev: libc::dev_t) -> WasiResult { Ok(wasi::__wasi_device_t::from(dev)) } -pub(crate) fn stino_from_nix(ino: libc::ino_t) -> Result { +pub(crate) fn stino_from_nix(ino: libc::ino_t) -> WasiResult { Ok(wasi::__wasi_device_t::from(ino)) } -pub(crate) fn stnlink_from_nix(nlink: libc::nlink_t) -> Result { +pub(crate) fn stnlink_from_nix(nlink: libc::nlink_t) -> WasiResult { Ok(nlink) } diff --git a/crates/wasi-common/yanix/src/dir.rs b/crates/wasi-common/yanix/src/dir.rs index 00b2b40898..12b05686a6 100644 --- a/crates/wasi-common/yanix/src/dir.rs +++ b/crates/wasi-common/yanix/src/dir.rs @@ -2,7 +2,8 @@ use crate::{ file::FileType, sys::dir::{iter_impl, EntryImpl}, }; -use std::io::Result; +use std::convert::TryInto; +use std::io::{Error, Result}; use std::os::unix::io::{AsRawFd, IntoRawFd, RawFd}; use std::{ffi::CStr, io, ops::Deref, ptr}; @@ -98,6 +99,18 @@ impl SeekLoc { pub fn to_raw(&self) -> i64 { self.0.into() } + + pub unsafe fn from_raw(loc: i64) -> Result { + // The cookie (or `loc`) is an opaque value, and applications aren't supposed to do + // arithmetic on them or pick their own values or have any awareness of the numeric + // range of the values. They're just supposed to pass back in the values that we + // give them. And any value we give them will be convertable back to `long`, + // because that's the type the OS gives them to us in. So return an `EINVAL`. + let loc = loc + .try_into() + .map_err(|_| Error::from_raw_os_error(libc::EINVAL))?; + Ok(Self(loc)) + } } #[derive(Debug)] diff --git a/crates/wasi-common/yanix/src/filetime.rs b/crates/wasi-common/yanix/src/filetime.rs index d712036c0e..fe95e1d950 100644 --- a/crates/wasi-common/yanix/src/filetime.rs +++ b/crates/wasi-common/yanix/src/filetime.rs @@ -10,40 +10,34 @@ use std::io::Result; pub use super::sys::filetime::*; -cfg_if::cfg_if! { - if #[cfg(not(target_os = "emscripten"))] { - fn filetime_to_timespec(ft: &filetime::FileTime) -> Result { - Ok( - libc::timespec { - tv_sec: ft.seconds(), - tv_nsec: i64::from(ft.nanoseconds()), - } - ) - } - } else { - fn filetime_to_timespec(ft: &filetime::FileTime) -> Result { - use std::convert::TryInto; - use std::io::Error; - // Emscripten expects both `tv_sec` and `tv_nsec` fields to be `i32`. - // Here however `ft.seconds() -> i64` and `ft.nanoseconds() -> u32` so - // a simple `as` cast may be insufficient. So, perform a checked conversion, - // log error if any, and convert to libc::EOVERFLOW. - let tv_sec = match ft.seconds().try_into() { - Ok(sec) => sec, - Err(_) => { - log::debug!("filetime_to_timespec failed converting seconds to required width"); - return Err(Error::from_raw_os_error(libc::EOVERFLOW)); - } - }; - let tv_nsec = match ft.nanoseconds().try_into() { - Ok(nsec) => nsec, - Err(_) => { - log::debug!("filetime_to_timespec failed converting nanoseconds to required width"); - return Err(Error::from_raw_os_error(libc::EOVERFLOW)); - } - }; - Ok(libc::timespec { tv_sec, tv_nsec }) - } +/// Internal trait which specialises `filetime::FileTime`'s +/// `seconds` and `nanoseconds` accessors for different +/// pointer widths (32 and 64bit currently). +pub(crate) trait FileTimeExt { + fn seconds_(&self) -> Result; + fn nanoseconds_(&self) -> libc::c_long; +} + +impl FileTimeExt for filetime::FileTime { + fn seconds_(&self) -> Result { + use std::convert::TryInto; + use std::io::Error; + let sec = match self.seconds().try_into() { + Ok(sec) => sec, + Err(_) => { + log::debug!("filetime_to_timespec failed converting seconds to required width"); + return Err(Error::from_raw_os_error(libc::EOVERFLOW)); + } + }; + Ok(sec) + } + fn nanoseconds_(&self) -> libc::c_long { + use std::convert::TryInto; + // According to [filetime] docs, since the nanoseconds value is always less than 1 billion, + // any value should be convertible to `libc::c_long`, hence we can `unwrap` outright. + // + // [filetime]: https://docs.rs/filetime/0.2.8/filetime/struct.FileTime.html#method.nanoseconds + self.nanoseconds().try_into().unwrap() } } @@ -69,13 +63,16 @@ pub(crate) fn to_timespec(ft: &FileTime) -> Result { let ts = match ft { FileTime::Now => libc::timespec { tv_sec: 0, - tv_nsec: UTIME_NOW, + tv_nsec: libc::UTIME_NOW, }, FileTime::Omit => libc::timespec { tv_sec: 0, - tv_nsec: UTIME_OMIT, + tv_nsec: libc::UTIME_OMIT, + }, + FileTime::FileTime(ft) => libc::timespec { + tv_sec: ft.seconds_()?, + tv_nsec: ft.nanoseconds_(), }, - FileTime::FileTime(ft) => filetime_to_timespec(ft)?, }; Ok(ts) } diff --git a/crates/wasi-common/yanix/src/sys/bsd/dir.rs b/crates/wasi-common/yanix/src/sys/bsd/dir.rs index 6d1b75cc29..8a253a05f6 100644 --- a/crates/wasi-common/yanix/src/sys/bsd/dir.rs +++ b/crates/wasi-common/yanix/src/sys/bsd/dir.rs @@ -57,10 +57,3 @@ impl EntryExt for Entry { Ok(self.0.loc) } } - -impl SeekLoc { - pub unsafe fn from_raw(loc: i64) -> Result { - let loc = loc.into(); - Ok(Self(loc)) - } -} diff --git a/crates/wasi-common/yanix/src/sys/bsd/filetime.rs b/crates/wasi-common/yanix/src/sys/bsd/filetime.rs index 8f71db0e4c..63a7f58830 100644 --- a/crates/wasi-common/yanix/src/sys/bsd/filetime.rs +++ b/crates/wasi-common/yanix/src/sys/bsd/filetime.rs @@ -2,34 +2,11 @@ //! with setting the file times specific to BSD-style *nixes. use crate::filetime::FileTime; use crate::from_success_code; -use cfg_if::cfg_if; use std::ffi::CStr; use std::fs::File; use std::io::Result; use std::sync::atomic::{AtomicUsize, Ordering::SeqCst}; -cfg_if! { - if #[cfg(any( - target_os = "macos", - target_os = "freebsd", - target_os = "ios", - target_os = "dragonfly" - ))] { - pub(crate) const UTIME_NOW: i64 = -1; - pub(crate) const UTIME_OMIT: i64 = -2; - } else if #[cfg(target_os = "openbsd")] { - // These are swapped compared to macos, freebsd, ios, and dragonfly. - // https://github.com/openbsd/src/blob/master/sys/sys/stat.h#L187 - pub(crate) const UTIME_NOW: i64 = -2; - pub(crate) const UTIME_OMIT: i64 = -1; - } else if #[cfg(target_os = "netbsd" )] { - // These are the same as for Linux. - // http://cvsweb.netbsd.org/bsdweb.cgi/src/sys/sys/stat.h?rev=1.69&content-type=text/x-cvsweb-markup&only_with_tag=MAIN - pub(crate) const UTIME_NOW: i64 = 1_073_741_823; - pub(crate) const UTIME_OMIT: i64 = 1_073_741_822; - } -} - /// Wrapper for `utimensat` syscall, however, with an added twist such that `utimensat` symbol /// is firstly resolved (i.e., we check whether it exists on the host), and only used if that is /// the case. Otherwise, the syscall resorts to a less accurate `utimesat` emulated syscall. diff --git a/crates/wasi-common/yanix/src/sys/emscripten/filetime.rs b/crates/wasi-common/yanix/src/sys/emscripten/filetime.rs index c8de04d399..0d7336b591 100644 --- a/crates/wasi-common/yanix/src/sys/emscripten/filetime.rs +++ b/crates/wasi-common/yanix/src/sys/emscripten/filetime.rs @@ -5,9 +5,6 @@ use crate::from_success_code; use std::fs::File; use std::io::Result; -pub(crate) const UTIME_NOW: i32 = 1_073_741_823; -pub(crate) const UTIME_OMIT: i32 = 1_073_741_822; - /// Wrapper for `utimensat` syscall. In Emscripten, there is no point in dynamically resolving /// if `utimensat` is available as it always was and will be. pub fn utimensat( diff --git a/crates/wasi-common/yanix/src/sys/emscripten/mod.rs b/crates/wasi-common/yanix/src/sys/emscripten/mod.rs index 8511b5d377..a79cf82b9f 100644 --- a/crates/wasi-common/yanix/src/sys/emscripten/mod.rs +++ b/crates/wasi-common/yanix/src/sys/emscripten/mod.rs @@ -5,21 +5,3 @@ pub(crate) mod fadvise; #[path = "../linux/file.rs"] pub(crate) mod file; pub(crate) mod filetime; - -use crate::dir::SeekLoc; -use std::convert::TryInto; -use std::io::{Error, Result}; - -impl SeekLoc { - pub unsafe fn from_raw(loc: i64) -> Result { - // The cookie (or `loc`) is an opaque value, and applications aren't supposed to do - // arithmetic on them or pick their own values or have any awareness of the numeric - // range of the values. They're just supposed to pass back in the values that we - // give them. And any value we give them will be convertable back to `long`, - // because that's the type the OS gives them to us in. So return an `EINVAL`. - let loc = loc - .try_into() - .map_err(|_| Error::from_raw_os_error(libc::EINVAL))?; - Ok(Self(loc)) - } -} diff --git a/crates/wasi-common/yanix/src/sys/linux/filetime.rs b/crates/wasi-common/yanix/src/sys/linux/filetime.rs index 36b7687386..243aa46eef 100644 --- a/crates/wasi-common/yanix/src/sys/linux/filetime.rs +++ b/crates/wasi-common/yanix/src/sys/linux/filetime.rs @@ -6,9 +6,6 @@ use std::fs::File; use std::io::Result; use std::sync::atomic::{AtomicBool, Ordering::Relaxed}; -pub(crate) const UTIME_NOW: i64 = 1_073_741_823; -pub(crate) const UTIME_OMIT: i64 = 1_073_741_822; - /// Wrapper for `utimensat` syscall, however, with an added twist such that `utimensat` symbol /// is firstly resolved (i.e., we check whether it exists on the host), and only used if that is /// the case. Otherwise, the syscall resorts to a less accurate `utimesat` emulated syscall. diff --git a/crates/wasi-common/yanix/src/sys/linux/mod.rs b/crates/wasi-common/yanix/src/sys/linux/mod.rs index 311155a6de..26432d36dd 100644 --- a/crates/wasi-common/yanix/src/sys/linux/mod.rs +++ b/crates/wasi-common/yanix/src/sys/linux/mod.rs @@ -3,13 +3,3 @@ pub(crate) mod fadvise; pub(crate) mod file; pub(crate) mod filetime; pub(crate) mod utimesat; - -use crate::dir::SeekLoc; -use std::io::Result; - -impl SeekLoc { - pub unsafe fn from_raw(loc: i64) -> Result { - let loc = loc.into(); - Ok(Self(loc)) - } -} diff --git a/crates/wasi-common/yanix/src/sys/linux/utimesat.rs b/crates/wasi-common/yanix/src/sys/linux/utimesat.rs index 26025e0772..396c19b359 100644 --- a/crates/wasi-common/yanix/src/sys/linux/utimesat.rs +++ b/crates/wasi-common/yanix/src/sys/linux/utimesat.rs @@ -1,4 +1,5 @@ use crate::filetime::FileTime; +use crate::filetime::FileTimeExt; use crate::from_success_code; use std::fs; use std::io::Result; @@ -26,19 +27,16 @@ pub fn utimesat( let fd = unsafe { libc::openat(dirfd.as_raw_fd(), p.as_ptr(), flags) }; let f = unsafe { fs::File::from_raw_fd(fd) }; let (atime, mtime) = get_times(atime, mtime, || f.metadata().map_err(Into::into))?; - let times = [to_timeval(atime), to_timeval(mtime)]; + let times = [to_timeval(atime)?, to_timeval(mtime)?]; from_success_code(unsafe { libc::futimes(f.as_raw_fd(), times.as_ptr()) }) } -/// Converts `filetime::FileTime` to `libc::timeval`. This function was taken directly from -/// [filetime] crate. -/// -/// [filetime]: https://github.com/alexcrichton/filetime/blob/master/src/unix/utimes.rs#L93 -fn to_timeval(ft: filetime::FileTime) -> libc::timeval { - libc::timeval { - tv_sec: ft.seconds(), - tv_usec: (ft.nanoseconds() / 1000) as libc::suseconds_t, - } +/// Converts `filetime::FileTime` to `libc::timeval`. +fn to_timeval(ft: filetime::FileTime) -> Result { + Ok(libc::timeval { + tv_sec: ft.seconds_()?, + tv_usec: (ft.nanoseconds_() / 1000) as libc::suseconds_t, + }) } /// For a provided pair of access and modified `FileTime`s, converts the input to