[wasi-common]: move filetime module to yanix (#1255)
* Move filetime module to yanix I've noticed that we could replace every occurrence of `crate::Result` in `filetime` mods with `io::Result`, so I thought why not move it to `yanix` and get rid off a lot of unnecessary code duplication within `wasi-common`. Now, ideally I'd have our `filetime` modifications backported to Alex's [`filetime`] crate, but one step at a time (apologies Alex, I was meant to backport this ages ago, just didn't find the time yet... :-(). Anyway, this commit does just that; i.e., moves the `filetime` modules into `yanix` which seems a better fit for this type of code. [`filetime`]: https://github.com/alexcrichton/filetime There is one caveat here. On Emscripten, converting between `filetime::Filetime` and `libc::timespec` appears to be lossy, at least as far as the types are concerned. Now, `filetime::Filetime`'s seconds field is `i64` while nanoseconds field is `u32`, while Emscripten's `libc::timespec` requires both to be `i32` width. This might actually not be a problem since I don't think it's possible to fill `filetime::Filetime` struct with values of width wider than `i32` since Emscripten is 32bit but just to be on the safe side, we do a `TryInto` conversion, log the error (if any), and return `libc::EOVERFLOW`. * Run cargo fmt * Use i64::from instead of as cast
This commit is contained in:
81
crates/wasi-common/yanix/src/filetime.rs
Normal file
81
crates/wasi-common/yanix/src/filetime.rs
Normal file
@@ -0,0 +1,81 @@
|
||||
//! This module consists of helper types and functions for dealing
|
||||
//! with setting the file times (mainly in `path_filestat_set_times` syscall for now).
|
||||
//!
|
||||
//! The vast majority of the code contained within and in platform-specific implementations
|
||||
//! (`super::linux::filetime` and `super::bsd::filetime`) is based on the [filetime] crate.
|
||||
//! Kudos @alexcrichton!
|
||||
//!
|
||||
//! [filetime]: https://github.com/alexcrichton/filetime
|
||||
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<libc::timespec> {
|
||||
Ok(
|
||||
libc::timespec {
|
||||
tv_sec: ft.seconds(),
|
||||
tv_nsec: i64::from(ft.nanoseconds()),
|
||||
}
|
||||
)
|
||||
}
|
||||
} else {
|
||||
fn filetime_to_timespec(ft: &filetime::FileTime) -> Result<libc::timespec> {
|
||||
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 })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A wrapper `enum` around `filetime::FileTime` struct, but unlike the original, this
|
||||
/// type allows the possibility of specifying `FileTime::Now` as a valid enumeration which,
|
||||
/// in turn, if `utimensat` is available on the host, will use a special const setting
|
||||
/// `UTIME_NOW`.
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub enum FileTime {
|
||||
Now,
|
||||
Omit,
|
||||
FileTime(filetime::FileTime),
|
||||
}
|
||||
|
||||
/// Converts `FileTime` to `libc::timespec`. If `FileTime::Now` variant is specified, this
|
||||
/// resolves to `UTIME_NOW` special const, `FileTime::Omit` variant resolves to `UTIME_OMIT`, and
|
||||
/// `FileTime::FileTime(ft)` where `ft := filetime::FileTime` uses [filetime] crate's original
|
||||
/// implementation which can be found here: [filetime::unix::to_timespec].
|
||||
///
|
||||
/// [filetime]: https://github.com/alexcrichton/filetime
|
||||
/// [filetime::unix::to_timespec]: https://github.com/alexcrichton/filetime/blob/master/src/unix/mod.rs#L30
|
||||
pub(crate) fn to_timespec(ft: &FileTime) -> Result<libc::timespec> {
|
||||
let ts = match ft {
|
||||
FileTime::Now => libc::timespec {
|
||||
tv_sec: 0,
|
||||
tv_nsec: UTIME_NOW,
|
||||
},
|
||||
FileTime::Omit => libc::timespec {
|
||||
tv_sec: 0,
|
||||
tv_nsec: UTIME_OMIT,
|
||||
},
|
||||
FileTime::FileTime(ft) => filetime_to_timespec(ft)?,
|
||||
};
|
||||
Ok(ts)
|
||||
}
|
||||
Reference in New Issue
Block a user