diff --git a/Cargo.toml b/Cargo.toml index 56b4a06..cd531f7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,6 +16,7 @@ libc = "0.2" rand = "0.6" cfg-if = "0.1.9" log = "0.4" +filetime = "0.2.7" [target.'cfg(unix)'.dependencies] nix = "0.13" diff --git a/build.rs b/build.rs index e0b7ef6..dda957c 100644 --- a/build.rs +++ b/build.rs @@ -136,7 +136,6 @@ cfg_if::cfg_if! { "symlink_loop" => true, "clock_time_get" => true, "truncation_rights" => true, - "fd_filestat_set" => true, _ => false, } } else { diff --git a/src/hostcalls_impl/fs.rs b/src/hostcalls_impl/fs.rs index f3eb683..4f9f83c 100644 --- a/src/hostcalls_impl/fs.rs +++ b/src/hostcalls_impl/fs.rs @@ -7,8 +7,10 @@ use crate::sys::fdentry_impl::determine_type_rights; use crate::sys::hostcalls_impl::fs_helpers::path_open_rights; use crate::sys::{errno_from_ioerror, host_impl, hostcalls_impl}; use crate::{host, wasm32, Result}; +use filetime::{set_file_handle_times, FileTime}; use log::trace; use std::io::{self, Read, Seek, SeekFrom, Write}; +use std::time::{Duration, SystemTime, UNIX_EPOCH}; pub(crate) fn fd_close(wasi_ctx: &mut WasiCtx, fd: wasm32::__wasi_fd_t) -> Result<()> { trace!("fd_close(fd={:?})", fd); @@ -764,7 +766,34 @@ pub(crate) fn fd_filestat_set_times( let st_mtim = dec_timestamp(st_mtim); let fst_flags = dec_fstflags(fst_flags); - hostcalls_impl::fd_filestat_set_times(fd, st_atim, st_mtim, fst_flags) + let set_atim = fst_flags & host::__WASI_FILESTAT_SET_ATIM != 0; + let set_atim_now = fst_flags & host::__WASI_FILESTAT_SET_ATIM_NOW != 0; + let set_mtim = fst_flags & host::__WASI_FILESTAT_SET_MTIM != 0; + let set_mtim_now = fst_flags & host::__WASI_FILESTAT_SET_MTIM_NOW != 0; + + if (set_atim && set_atim_now) || (set_mtim && set_mtim_now) { + return Err(host::__WASI_EINVAL); + } + let atim = if set_atim { + let time = UNIX_EPOCH + Duration::from_nanos(st_atim); + Some(FileTime::from_system_time(time)) + } else if set_atim_now { + let time = SystemTime::now(); + Some(FileTime::from_system_time(time)) + } else { + None + }; + + let mtim = if set_mtim { + let time = UNIX_EPOCH + Duration::from_nanos(st_mtim); + Some(FileTime::from_system_time(time)) + } else if set_mtim_now { + let time = SystemTime::now(); + Some(FileTime::from_system_time(time)) + } else { + None + }; + set_file_handle_times(fd, atim, mtim).map_err(errno_from_ioerror) } pub(crate) fn fd_filestat_set_size( diff --git a/src/sys/unix/hostcalls_impl/fs.rs b/src/sys/unix/hostcalls_impl/fs.rs index cec90c6..e9cbe05 100644 --- a/src/sys/unix/hostcalls_impl/fs.rs +++ b/src/sys/unix/hostcalls_impl/fs.rs @@ -6,7 +6,7 @@ use crate::hostcalls_impl::PathGet; use crate::sys::errno_from_ioerror; use crate::sys::host_impl; use crate::{host, wasm32, Result}; -use nix::libc::{self, c_long, c_void, off_t}; +use nix::libc::{self, c_long, c_void}; use std::convert::TryInto; use std::ffi::CString; use std::fs::{File, Metadata}; @@ -50,6 +50,8 @@ pub(crate) fn fd_advise( ) -> Result<()> { #[cfg(target_os = "linux")] { + use nix::libc::off_t; + let host_advice = match advice { host::__WASI_ADVICE_DONTNEED => libc::POSIX_FADV_DONTNEED, host::__WASI_ADVICE_SEQUENTIAL => libc::POSIX_FADV_SEQUENTIAL, @@ -363,49 +365,6 @@ fn filetype(metadata: &Metadata) -> host::__wasi_filetype_t { } } -pub(crate) fn fd_filestat_set_times( - fd: &File, - st_atim: host::__wasi_timestamp_t, - mut st_mtim: host::__wasi_timestamp_t, - fst_flags: host::__wasi_fstflags_t, -) -> Result<()> { - use nix::sys::time::{TimeSpec, TimeValLike}; - - if fst_flags & host::__WASI_FILESTAT_SET_MTIM_NOW != 0 { - let clock_id = libc::CLOCK_REALTIME; - let mut timespec = unsafe { std::mem::uninitialized::() }; - let res = unsafe { libc::clock_gettime(clock_id, &mut timespec as *mut libc::timespec) }; - if res != 0 { - return Err(host_impl::errno_from_nix(nix::errno::Errno::last())); - } - st_mtim = (timespec.tv_sec as host::__wasi_timestamp_t) - .checked_mul(1_000_000_000) - .and_then(|sec_ns| sec_ns.checked_add(timespec.tv_nsec as host::__wasi_timestamp_t)) - .ok_or(host::__WASI_EOVERFLOW)?; - } - let ts_atime = match fst_flags { - f if f & host::__WASI_FILESTAT_SET_ATIM_NOW != 0 => libc::timespec { - tv_sec: 0, - tv_nsec: utime_now(), - }, - f if f & host::__WASI_FILESTAT_SET_ATIM != 0 => { - *TimeSpec::nanoseconds(st_atim as i64).as_ref() - } - _ => libc::timespec { - tv_sec: 0, - tv_nsec: utime_omit(), - }, - }; - let ts_mtime = *TimeSpec::nanoseconds(st_mtim as i64).as_ref(); - let times = [ts_atime, ts_mtime]; - let res = unsafe { libc::futimens(fd.as_raw_fd(), times.as_ptr()) }; - if res != 0 { - Err(host_impl::errno_from_nix(nix::errno::Errno::last())) - } else { - Ok(()) - } -} - pub(crate) fn path_filestat_get( resolved: PathGet, dirflags: host::__wasi_lookupflags_t, diff --git a/src/sys/windows/hostcalls_impl/fs.rs b/src/sys/windows/hostcalls_impl/fs.rs index 2c84f17..db9e7c0 100644 --- a/src/sys/windows/hostcalls_impl/fs.rs +++ b/src/sys/windows/hostcalls_impl/fs.rs @@ -267,15 +267,6 @@ fn filetype(metadata: &Metadata) -> io::Result { Ok(ret) } -pub(crate) fn fd_filestat_set_times( - fd: &File, - st_atim: host::__wasi_timestamp_t, - mut st_mtim: host::__wasi_timestamp_t, - fst_flags: host::__wasi_fstflags_t, -) -> Result<()> { - unimplemented!("fd_filestat_set_times") -} - pub(crate) fn path_filestat_get( resolved: PathGet, dirflags: host::__wasi_lookupflags_t,