diff --git a/Cargo.lock b/Cargo.lock index d015e15345..c4d5ae3b3a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2516,18 +2516,14 @@ version = "0.22.0" dependencies = [ "anyhow", "bitflags", - "cap-fs-ext", "cap-rand", "cap-std", - "cap-time-ext", "cfg-if 1.0.0", - "fs-set-times", "libc", "system-interface", "thiserror", "tracing", "wiggle", - "yanix 0.22.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] diff --git a/crates/wasi-c2/Cargo.toml b/crates/wasi-c2/Cargo.toml index 848e69051d..de412a5954 100644 --- a/crates/wasi-c2/Cargo.toml +++ b/crates/wasi-c2/Cargo.toml @@ -26,13 +26,9 @@ wiggle = { path = "../wiggle", default-features = false, version = "0.22.0" } tracing = "0.1.19" system-interface = { version = "0.5", features = ["cap_std_impls"] } cap-std = "0.9" -cap-fs-ext = "0.9" -cap-time-ext = "0.9" cap-rand = "0.9" -fs-set-times = "0.2.2" cfg-if = "1" bitflags = "1.2" -yanix = "0.22" [badges] maintenance = { status = "actively-developed" } diff --git a/crates/wasi-c2/cap-std-sync/src/clocks.rs b/crates/wasi-c2/cap-std-sync/src/clocks.rs new file mode 100644 index 0000000000..3d81929534 --- /dev/null +++ b/crates/wasi-c2/cap-std-sync/src/clocks.rs @@ -0,0 +1,46 @@ +use cap_std::time::{Duration, Instant, SystemTime}; +use cap_time_ext::{MonotonicClockExt, SystemClockExt}; +use wasi_c2::clocks::{WasiClocks, WasiMonotonicClock, WasiSystemClock}; + +pub struct SystemClock(cap_std::time::SystemClock); + +impl SystemClock { + pub unsafe fn new() -> Self { + SystemClock(cap_std::time::SystemClock::new()) + } +} +impl WasiSystemClock for SystemClock { + fn resolution(&self) -> Duration { + self.0.resolution() + } + fn now(&self, precision: Duration) -> SystemTime { + self.0.now_with(precision) + } +} + +pub struct MonotonicClock(cap_std::time::MonotonicClock); +impl MonotonicClock { + pub unsafe fn new() -> Self { + MonotonicClock(cap_std::time::MonotonicClock::new()) + } +} +impl WasiMonotonicClock for MonotonicClock { + fn resolution(&self) -> Duration { + self.0.resolution() + } + fn now(&self, precision: Duration) -> Instant { + self.0.now_with(precision) + } +} + +pub fn clocks() -> WasiClocks { + let system = Box::new(unsafe { SystemClock::new() }); + let monotonic = unsafe { cap_std::time::MonotonicClock::new() }; + let creation_time = monotonic.now(); + let monotonic = Box::new(MonotonicClock(monotonic)); + WasiClocks { + system, + monotonic, + creation_time, + } +} diff --git a/crates/wasi-c2/cap-std-sync/src/dir.rs b/crates/wasi-c2/cap-std-sync/src/dir.rs index 50d61fe1e9..42c2b111cc 100644 --- a/crates/wasi-c2/cap-std-sync/src/dir.rs +++ b/crates/wasi-c2/cap-std-sync/src/dir.rs @@ -197,7 +197,7 @@ impl WasiDir for Dir { fn hard_link( &self, src_path: &str, - symlink_follow: bool, + symlink_follow: bool, // XXX not in cap-std yet target_dir: &dyn WasiDir, target_path: &str, ) -> Result<(), Error> { @@ -213,10 +213,22 @@ impl WasiDir for Dir { fn set_times( &self, path: &str, - atime: Option, - mtime: Option, + atime: Option, + mtime: Option, ) -> Result<(), Error> { - self.0.set_times(Path::new(path), atime, mtime)?; + self.0.set_times( + Path::new(path), + convert_systimespec(atime), + convert_systimespec(mtime), + )?; Ok(()) } } + +fn convert_systimespec(t: Option) -> Option { + match t { + Some(wasi_c2::SystemTimeSpec::Absolute(t)) => Some(SystemTimeSpec::Absolute(t)), + Some(wasi_c2::SystemTimeSpec::SymbolicNow) => Some(SystemTimeSpec::SymbolicNow), + None => None, + } +} diff --git a/crates/wasi-c2/cap-std-sync/src/file.rs b/crates/wasi-c2/cap-std-sync/src/file.rs index 3fb8c90f3b..5502335ba1 100644 --- a/crates/wasi-c2/cap-std-sync/src/file.rs +++ b/crates/wasi-c2/cap-std-sync/src/file.rs @@ -68,10 +68,11 @@ impl WasiFile for File { } fn set_times( &self, - atime: Option, - mtime: Option, + atime: Option, + mtime: Option, ) -> Result<(), Error> { - self.0.set_times(atime, mtime)?; + self.0 + .set_times(convert_systimespec(atime), convert_systimespec(mtime))?; Ok(()) } fn read_vectored(&self, bufs: &mut [io::IoSliceMut]) -> Result { @@ -93,9 +94,6 @@ impl WasiFile for File { fn seek(&self, pos: std::io::SeekFrom) -> Result { Ok(self.0.seek(pos)?) } - fn stream_position(&self) -> Result { - Ok(self.0.stream_position()?) - } fn peek(&self, buf: &mut [u8]) -> Result { let n = self.0.peek(buf)?; Ok(n.try_into().map_err(|_| Error::Overflow)?) @@ -145,3 +143,10 @@ impl AsRawFd for File { self.0.as_raw_fd() } } +pub fn convert_systimespec(t: Option) -> Option { + match t { + Some(wasi_c2::SystemTimeSpec::Absolute(t)) => Some(SystemTimeSpec::Absolute(t.into_std())), + Some(wasi_c2::SystemTimeSpec::SymbolicNow) => Some(SystemTimeSpec::SymbolicNow), + None => None, + } +} diff --git a/crates/wasi-c2/cap-std-sync/src/lib.rs b/crates/wasi-c2/cap-std-sync/src/lib.rs index 75e5ed4e71..0d4063f08a 100644 --- a/crates/wasi-c2/cap-std-sync/src/lib.rs +++ b/crates/wasi-c2/cap-std-sync/src/lib.rs @@ -1,3 +1,4 @@ +pub mod clocks; pub mod dir; pub mod file; pub mod sched; @@ -7,7 +8,7 @@ use cap_rand::RngCore; use std::cell::RefCell; use std::path::Path; use std::rc::Rc; -use wasi_c2::{clocks::WasiClocks, table::Table, Error, WasiCtx, WasiFile}; +use wasi_c2::{table::Table, Error, WasiCtx, WasiFile}; pub struct WasiCtxBuilder(wasi_c2::WasiCtxBuilder); @@ -15,7 +16,7 @@ impl WasiCtxBuilder { pub fn new() -> Self { WasiCtxBuilder(WasiCtx::builder( random(), - clocks(), + clocks::clocks(), Box::new(sched::SyncSched), Rc::new(RefCell::new(Table::new())), )) @@ -51,18 +52,6 @@ impl WasiCtxBuilder { } } -pub fn clocks() -> WasiClocks { - let system = Box::new(unsafe { cap_std::time::SystemClock::new() }); - let monotonic = unsafe { cap_std::time::MonotonicClock::new() }; - let creation_time = monotonic.now(); - let monotonic = Box::new(monotonic); - WasiClocks { - system, - monotonic, - creation_time, - } -} - pub fn random() -> RefCell> { RefCell::new(Box::new(unsafe { cap_rand::rngs::OsRng::default() })) } diff --git a/crates/wasi-c2/cap-std-sync/src/stdio.rs b/crates/wasi-c2/cap-std-sync/src/stdio.rs index ad6e61cb03..40c9616003 100644 --- a/crates/wasi-c2/cap-std-sync/src/stdio.rs +++ b/crates/wasi-c2/cap-std-sync/src/stdio.rs @@ -1,3 +1,4 @@ +use crate::file::convert_systimespec; use fs_set_times::SetTimes; use std::any::Any; use std::convert::TryInto; @@ -87,19 +88,16 @@ macro_rules! wasi_file_impl { fn seek(&self, pos: std::io::SeekFrom) -> Result { Ok(self.0.seek(pos)?) } - fn stream_position(&self) -> Result { - Ok(self.0.stream_position()?) - } fn peek(&self, buf: &mut [u8]) -> Result { let n = self.0.peek(buf)?; Ok(n.try_into().map_err(|_| Error::Overflow)?) } fn set_times( &self, - atime: Option, - mtime: Option, + atime: Option, + mtime: Option, ) -> Result<(), Error> { - self.0.set_times(atime, mtime)?; + self.0.set_times(convert_systimespec(atime), convert_systimespec(mtime))?; Ok(()) } $additional diff --git a/crates/wasi-c2/src/clocks.rs b/crates/wasi-c2/src/clocks.rs index 729ced1dd5..babf0acff4 100644 --- a/crates/wasi-c2/src/clocks.rs +++ b/crates/wasi-c2/src/clocks.rs @@ -1,34 +1,20 @@ -use cap_std::time::{Duration, Instant, MonotonicClock, SystemClock, SystemTime}; -use cap_time_ext::{MonotonicClockExt, SystemClockExt}; +use cap_std::time::{Duration, Instant, SystemTime}; + +pub enum SystemTimeSpec { + SymbolicNow, + Absolute(SystemTime), +} pub trait WasiSystemClock { fn resolution(&self) -> Duration; fn now(&self, precision: Duration) -> SystemTime; } -impl WasiSystemClock for SystemClock { - fn resolution(&self) -> Duration { - SystemClockExt::resolution(self) - } - fn now(&self, precision: Duration) -> SystemTime { - self.now_with(precision) - } -} - pub trait WasiMonotonicClock { fn resolution(&self) -> Duration; fn now(&self, precision: Duration) -> Instant; } -impl WasiMonotonicClock for MonotonicClock { - fn resolution(&self) -> Duration { - MonotonicClockExt::resolution(self) - } - fn now(&self, precision: Duration) -> Instant { - self.now_with(precision) - } -} - pub struct WasiClocks { pub system: Box, pub monotonic: Box, diff --git a/crates/wasi-c2/src/dir.rs b/crates/wasi-c2/src/dir.rs index cb46c916e5..bdc0811865 100644 --- a/crates/wasi-c2/src/dir.rs +++ b/crates/wasi-c2/src/dir.rs @@ -1,7 +1,6 @@ -use crate::error::Error; use crate::file::{FdFlags, FileCaps, FileType, Filestat, OFlags, WasiFile}; +use crate::{Error, SystemTimeSpec}; use bitflags::bitflags; -use cap_fs_ext::SystemTimeSpec; use std::any::Any; use std::cell::Ref; use std::ops::Deref; diff --git a/crates/wasi-c2/src/file.rs b/crates/wasi-c2/src/file.rs index 3521d21b53..97bb939eb7 100644 --- a/crates/wasi-c2/src/file.rs +++ b/crates/wasi-c2/src/file.rs @@ -1,42 +1,43 @@ -use crate::Error; +use crate::{Error, SystemTimeSpec}; use bitflags::bitflags; -use fs_set_times::SystemTimeSpec; use std::any::Any; use std::cell::Ref; use std::ops::Deref; pub trait WasiFile { fn as_any(&self) -> &dyn Any; - fn datasync(&self) -> Result<(), Error>; - fn sync(&self) -> Result<(), Error>; - fn get_filetype(&self) -> Result; - fn get_fdflags(&self) -> Result; + fn datasync(&self) -> Result<(), Error>; // write op + fn sync(&self) -> Result<(), Error>; // file op + fn get_filetype(&self) -> Result; // file op + fn get_fdflags(&self) -> Result; // file op fn set_fdflags(&self, _flags: FdFlags) -> Result<(), Error>; - fn get_filestat(&self) -> Result; - fn set_filestat_size(&self, _size: u64) -> Result<(), Error>; + fn get_filestat(&self) -> Result; // split out get_length as a read & write op, rest is a file op + fn set_filestat_size(&self, _size: u64) -> Result<(), Error>; // write op fn advise( &self, offset: u64, len: u64, advice: system_interface::fs::Advice, - ) -> Result<(), Error>; - fn allocate(&self, offset: u64, len: u64) -> Result<(), Error>; + ) -> Result<(), Error>; // file op + fn allocate(&self, offset: u64, len: u64) -> Result<(), Error>; // write op fn set_times( &self, atime: Option, mtime: Option, ) -> Result<(), Error>; - fn read_vectored(&self, bufs: &mut [std::io::IoSliceMut]) -> Result; + fn read_vectored(&self, bufs: &mut [std::io::IoSliceMut]) -> Result; // read op fn read_vectored_at(&self, bufs: &mut [std::io::IoSliceMut], offset: u64) - -> Result; - fn write_vectored(&self, bufs: &[std::io::IoSlice]) -> Result; - fn write_vectored_at(&self, bufs: &[std::io::IoSlice], offset: u64) -> Result; - fn seek(&self, pos: std::io::SeekFrom) -> Result; - fn stream_position(&self) -> Result; - fn peek(&self, buf: &mut [u8]) -> Result; - fn num_ready_bytes(&self) -> Result; + -> Result; // file op + fn write_vectored(&self, bufs: &[std::io::IoSlice]) -> Result; // write op + fn write_vectored_at(&self, bufs: &[std::io::IoSlice], offset: u64) -> Result; // file op + fn seek(&self, pos: std::io::SeekFrom) -> Result; // file op that generates a new stream from a file will supercede this + fn peek(&self, buf: &mut [u8]) -> Result; // read op + fn num_ready_bytes(&self) -> Result; // read op } +// XXX we will add pipes to wasi - lets add it to this internal enum and present them as +// Unknown to old wasis +// XXX put the enum variants in same order as WASI so conversion funcs are no-op #[derive(Debug, Copy, Clone)] pub enum FileType { Directory, @@ -74,7 +75,7 @@ pub struct Filestat { pub inode: u64, pub filetype: FileType, pub nlink: u64, - pub size: u64, + pub size: u64, // this is a read field, the rest are file fields pub atim: Option, pub mtim: Option, pub ctim: Option, diff --git a/crates/wasi-c2/src/lib.rs b/crates/wasi-c2/src/lib.rs index 6fbb269df1..7cd5c8325f 100644 --- a/crates/wasi-c2/src/lib.rs +++ b/crates/wasi-c2/src/lib.rs @@ -12,7 +12,7 @@ pub mod snapshots; mod string_array; pub mod table; -pub use cap_fs_ext::SystemTimeSpec; +pub use clocks::SystemTimeSpec; pub use ctx::{WasiCtx, WasiCtxBuilder}; pub use dir::{DirCaps, ReaddirCursor, ReaddirEntity, WasiDir}; pub use error::Error; diff --git a/crates/wasi-c2/src/pipe.rs b/crates/wasi-c2/src/pipe.rs index 55c6c6ce08..a65acd8f1e 100644 --- a/crates/wasi-c2/src/pipe.rs +++ b/crates/wasi-c2/src/pipe.rs @@ -9,8 +9,10 @@ //! Some convenience constructors are included for common backing types like `Vec` and `String`, //! but the virtual pipes can be instantiated with any `Read` or `Write` type. //! -use crate::file::{FdFlags, FileType, Filestat, WasiFile}; -use crate::Error; +use crate::{ + file::{FdFlags, FileType, Filestat, WasiFile}, + Error, SystemTimeSpec, +}; use std::any::Any; use std::convert::TryInto; use std::io::{self, Read, Write}; @@ -152,16 +154,13 @@ impl WasiFile for ReadPipe { fn seek(&self, pos: std::io::SeekFrom) -> Result { Err(Error::Badf) } - fn stream_position(&self) -> Result { - Err(Error::Badf) - } fn peek(&self, buf: &mut [u8]) -> Result { Err(Error::Badf) } fn set_times( &self, - atime: Option, - mtime: Option, + atime: Option, + mtime: Option, ) -> Result<(), Error> { Err(Error::Badf) } @@ -291,16 +290,13 @@ impl WasiFile for WritePipe { fn seek(&self, pos: std::io::SeekFrom) -> Result { Err(Error::Badf) } - fn stream_position(&self) -> Result { - Err(Error::Badf) - } fn peek(&self, buf: &mut [u8]) -> Result { Err(Error::Badf) } fn set_times( &self, - atime: Option, - mtime: Option, + atime: Option, + mtime: Option, ) -> Result<(), Error> { Err(Error::Badf) } diff --git a/crates/wasi-c2/src/snapshots/preview_1.rs b/crates/wasi-c2/src/snapshots/preview_1.rs index 53d973a834..68cab65da9 100644 --- a/crates/wasi-c2/src/snapshots/preview_1.rs +++ b/crates/wasi-c2/src/snapshots/preview_1.rs @@ -1,14 +1,17 @@ #![allow(unused_variables)] -use crate::dir::{ - DirCaps, DirEntry, DirEntryExt, DirFdStat, ReaddirCursor, ReaddirEntity, TableDirExt, +use crate::{ + dir::{DirCaps, DirEntry, DirEntryExt, DirFdStat, ReaddirCursor, ReaddirEntity, TableDirExt}, + file::{ + FdFlags, FdStat, FileCaps, FileEntry, FileEntryExt, FileType, Filestat, OFlags, + TableFileExt, + }, + sched::{ + subscription::{RwEventFlags, SubscriptionResult}, + Poll, + }, + Error, SystemTimeSpec, WasiCtx, }; -use crate::file::{ - FdFlags, FdStat, FileCaps, FileEntry, FileEntryExt, FileType, Filestat, OFlags, TableFileExt, -}; -use crate::sched::subscription::{RwEventFlags, SubscriptionResult}; -use crate::sched::Poll; -use crate::{Error, WasiCtx}; -use fs_set_times::SystemTimeSpec; +use cap_std::time::{Duration, SystemClock}; use std::cell::{Ref, RefMut}; use std::convert::{TryFrom, TryInto}; use std::io::{IoSlice, IoSliceMut}; @@ -172,7 +175,6 @@ impl<'a> wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiCtx { id: types::Clockid, precision: types::Timestamp, ) -> Result { - use cap_std::time::Duration; let precision = Duration::from_nanos(precision); match id { types::Clockid::Realtime => { @@ -344,55 +346,31 @@ impl<'a> wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiCtx { if (set_atim && set_atim_now) || (set_mtim && set_mtim_now) { return Err(Error::Inval); } + let atim = if set_atim { + Some(SystemTimeSpec::Absolute( + SystemClock::UNIX_EPOCH + Duration::from_nanos(atim), + )) + } else if set_atim_now { + Some(SystemTimeSpec::SymbolicNow) + } else { + None + }; + let mtim = if set_mtim { + Some(SystemTimeSpec::Absolute( + SystemClock::UNIX_EPOCH + Duration::from_nanos(mtim), + )) + } else if set_mtim_now { + Some(SystemTimeSpec::SymbolicNow) + } else { + None + }; if table.is::(fd) { - use std::time::{Duration, UNIX_EPOCH}; - let atim = if set_atim { - Some(SystemTimeSpec::Absolute( - UNIX_EPOCH + Duration::from_nanos(atim), - )) - } else if set_atim_now { - Some(SystemTimeSpec::SymbolicNow) - } else { - None - }; - let mtim = if set_mtim { - Some(SystemTimeSpec::Absolute( - UNIX_EPOCH + Duration::from_nanos(mtim), - )) - } else if set_mtim_now { - Some(SystemTimeSpec::SymbolicNow) - } else { - None - }; - table .get_file(fd) .expect("checked that entry is file") .get_cap(FileCaps::FILESTAT_SET_TIMES)? .set_times(atim, mtim) } else if table.is::(fd) { - use cap_std::time::{Duration, SystemClock}; - - use cap_fs_ext::SystemTimeSpec; - let atim = if set_atim { - Some(SystemTimeSpec::Absolute( - SystemClock::UNIX_EPOCH + Duration::from_nanos(atim), - )) - } else if set_atim_now { - Some(SystemTimeSpec::SymbolicNow) - } else { - None - }; - let mtim = if set_mtim { - Some(SystemTimeSpec::Absolute( - SystemClock::UNIX_EPOCH + Duration::from_nanos(mtim), - )) - } else if set_mtim_now { - Some(SystemTimeSpec::SymbolicNow) - } else { - None - }; - table .get_dir(fd) .expect("checked that entry is dir") @@ -599,6 +577,7 @@ impl<'a> wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiCtx { } fn fd_tell(&self, fd: types::Fd) -> Result { + // XXX should this be stream_position? let offset = self .table() .get_file(u32::from(fd))? @@ -694,7 +673,6 @@ impl<'a> wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiCtx { mtim: types::Timestamp, fst_flags: types::Fstflags, ) -> Result<(), Error> { - // XXX DRY these are in fd_filestat_set_times twice! let set_atim = fst_flags.contains(types::Fstflags::ATIM); let set_atim_now = fst_flags.contains(types::Fstflags::ATIM_NOW); let set_mtim = fst_flags.contains(types::Fstflags::MTIM); @@ -702,27 +680,19 @@ impl<'a> wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiCtx { if (set_atim && set_atim_now) || (set_mtim && set_mtim_now) { return Err(Error::Inval); } - use cap_fs_ext::SystemTimeSpec; - use cap_std::time::{Duration, SystemClock}; - let atim = if set_atim { - Some(SystemTimeSpec::Absolute( - SystemClock::UNIX_EPOCH + Duration::from_nanos(atim), - )) - } else if set_atim_now { - Some(SystemTimeSpec::SymbolicNow) - } else { - None - }; - let mtim = if set_mtim { - Some(SystemTimeSpec::Absolute( - SystemClock::UNIX_EPOCH + Duration::from_nanos(mtim), - )) - } else if set_mtim_now { - Some(SystemTimeSpec::SymbolicNow) - } else { - None - }; - + fn systimespec(set: bool, ts: types::Timestamp, now: bool) -> Option { + if set { + Some(SystemTimeSpec::Absolute( + SystemClock::UNIX_EPOCH + Duration::from_nanos(ts), + )) + } else if now { + Some(SystemTimeSpec::SymbolicNow) + } else { + None + } + } + let atim = systimespec(set_atim, atim, set_atim_now); + let mtim = systimespec(set_mtim, mtim, set_mtim_now); self.table() .get_dir(u32::from(dirfd))? .get_cap(DirCaps::PATH_FILESTAT_SET_TIMES)? @@ -893,7 +863,6 @@ impl<'a> wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiCtx { return Err(Error::Inval); } - use cap_std::time::Duration; let table = self.table(); let mut poll = Poll::new();