[wasi-common] Clean up fd_filestat_get implementation (#757)
* Clean up fd_filestat_get implementation
This commit does 4 things:
* Adds `yanix::file::fstat`, a wrapper around `libc::fstat`.
* It essentially reverts 89fbde2 for Unix hosts -- in other words,
it brings back the use of `fstat` to obtain `libc::stat` from a
file descriptor, rather than relying on `std::fs::Metadata`. This
way, we reuse `host_impl::filestat_from_nix` in
`hostcalls_impl::fd_filestat_get` implementation rather than
unnecessarily duplicate code for converting filestats into
`__wasi_filestat_t`.
* Moves `crate::helpers::systemtime_to_timestamp` to Windows `host_impl`
module. It does the same thing with helpers which assist in converting
`std::fs::Metadata` into `__wasi_filestat_t`. This should retain symmetry
between *nix and Windows impls.
* Makes timestamp conversions in `host_impl::filestat_from_nix` fallible.
* Backport changes to snapshot0
* Signal no overflow with `from` rather than `as` cast
This commit is contained in:
@@ -1,7 +1,12 @@
|
||||
//! WASI host types specific to Windows host.
|
||||
use crate::host::FileType;
|
||||
use crate::{wasi, Error, Result};
|
||||
use std::convert::TryInto;
|
||||
use std::ffi::OsStr;
|
||||
use std::fs::{self, File};
|
||||
use std::io;
|
||||
use std::os::windows::ffi::OsStrExt;
|
||||
use std::time::{SystemTime, UNIX_EPOCH};
|
||||
|
||||
pub(crate) fn errno_from_win(error: winx::winerror::WinError) -> wasi::__wasi_errno_t {
|
||||
// TODO: implement error mapping between Windows and WASI
|
||||
@@ -34,6 +39,60 @@ pub(crate) fn errno_from_win(error: winx::winerror::WinError) -> wasi::__wasi_er
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn filetype_from_std(ftype: &fs::FileType) -> FileType {
|
||||
if ftype.is_file() {
|
||||
FileType::RegularFile
|
||||
} else if ftype.is_dir() {
|
||||
FileType::Directory
|
||||
} else if ftype.is_symlink() {
|
||||
FileType::Symlink
|
||||
} else {
|
||||
FileType::Unknown
|
||||
}
|
||||
}
|
||||
|
||||
fn num_hardlinks(file: &File) -> io::Result<u64> {
|
||||
Ok(winx::file::get_fileinfo(file)?.nNumberOfLinks.into())
|
||||
}
|
||||
|
||||
fn device_id(file: &File) -> io::Result<u64> {
|
||||
Ok(winx::file::get_fileinfo(file)?.dwVolumeSerialNumber.into())
|
||||
}
|
||||
|
||||
pub(crate) fn file_serial_no(file: &File) -> io::Result<u64> {
|
||||
let info = winx::file::get_fileinfo(file)?;
|
||||
let high = info.nFileIndexHigh;
|
||||
let low = info.nFileIndexLow;
|
||||
let no = (u64::from(high) << 32) | u64::from(low);
|
||||
Ok(no)
|
||||
}
|
||||
|
||||
fn change_time(file: &File) -> io::Result<i64> {
|
||||
winx::file::change_time(file)
|
||||
}
|
||||
|
||||
fn systemtime_to_timestamp(st: SystemTime) -> Result<u64> {
|
||||
st.duration_since(UNIX_EPOCH)
|
||||
.map_err(|_| Error::EINVAL)? // date earlier than UNIX_EPOCH
|
||||
.as_nanos()
|
||||
.try_into()
|
||||
.map_err(Into::into) // u128 doesn't fit into u64
|
||||
}
|
||||
|
||||
pub(crate) fn filestat_from_win(file: &File) -> Result<wasi::__wasi_filestat_t> {
|
||||
let metadata = file.metadata()?;
|
||||
Ok(wasi::__wasi_filestat_t {
|
||||
dev: device_id(file)?,
|
||||
ino: file_serial_no(file)?,
|
||||
nlink: num_hardlinks(file)?.try_into()?, // u64 doesn't fit into u32
|
||||
size: metadata.len(),
|
||||
atim: systemtime_to_timestamp(metadata.accessed()?)?,
|
||||
ctim: change_time(file)?.try_into()?, // i64 doesn't fit into u64
|
||||
mtim: systemtime_to_timestamp(metadata.modified()?)?,
|
||||
filetype: filetype_from_std(&metadata.file_type()).to_wasi(),
|
||||
})
|
||||
}
|
||||
|
||||
/// Creates owned WASI path from OS string.
|
||||
///
|
||||
/// NB WASI spec requires OS string to be valid UTF-8. Otherwise,
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
use super::fs_helpers::*;
|
||||
use crate::ctx::WasiCtx;
|
||||
use crate::fdentry::FdEntry;
|
||||
use crate::helpers::systemtime_to_timestamp;
|
||||
use crate::host::{Dirent, FileType};
|
||||
use crate::hostcalls_impl::{fd_filestat_set_times_impl, PathGet};
|
||||
use crate::sys::fdentry_impl::determine_type_rights;
|
||||
@@ -249,10 +248,10 @@ fn dirent_from_path<P: AsRef<Path>>(
|
||||
.open(path)?;
|
||||
let ty = file.metadata()?.file_type();
|
||||
Ok(Dirent {
|
||||
ftype: filetype_from_std(&ty),
|
||||
ftype: host_impl::filetype_from_std(&ty),
|
||||
name: name.to_owned(),
|
||||
cookie,
|
||||
ino: file_serial_no(&file)?,
|
||||
ino: host_impl::file_serial_no(&file)?,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -305,8 +304,8 @@ pub(crate) fn fd_readdir(
|
||||
|
||||
Ok(Dirent {
|
||||
name: path_from_host(dir.file_name())?,
|
||||
ftype: filetype_from_std(&dir.file_type()?),
|
||||
ino: File::open(dir.path()).and_then(|f| file_serial_no(&f))?,
|
||||
ftype: host_impl::filetype_from_std(&dir.file_type()?),
|
||||
ino: File::open(dir.path()).and_then(|f| host_impl::file_serial_no(&f))?,
|
||||
cookie: no,
|
||||
})
|
||||
});
|
||||
@@ -429,50 +428,8 @@ pub(crate) fn path_rename(resolved_old: PathGet, resolved_new: PathGet) -> Resul
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn num_hardlinks(file: &File, _metadata: &Metadata) -> io::Result<u64> {
|
||||
Ok(winx::file::get_fileinfo(file)?.nNumberOfLinks.into())
|
||||
}
|
||||
|
||||
pub(crate) fn device_id(file: &File, _metadata: &Metadata) -> io::Result<u64> {
|
||||
Ok(winx::file::get_fileinfo(file)?.dwVolumeSerialNumber.into())
|
||||
}
|
||||
|
||||
pub(crate) fn file_serial_no(file: &File) -> io::Result<u64> {
|
||||
let info = winx::file::get_fileinfo(file)?;
|
||||
let high = info.nFileIndexHigh;
|
||||
let low = info.nFileIndexLow;
|
||||
let no = ((high as u64) << 32) | (low as u64);
|
||||
Ok(no)
|
||||
}
|
||||
|
||||
pub(crate) fn change_time(file: &File, _metadata: &Metadata) -> io::Result<i64> {
|
||||
winx::file::change_time(file)
|
||||
}
|
||||
|
||||
pub(crate) fn fd_filestat_get_impl(file: &std::fs::File) -> Result<wasi::__wasi_filestat_t> {
|
||||
let metadata = file.metadata()?;
|
||||
Ok(wasi::__wasi_filestat_t {
|
||||
dev: device_id(file, &metadata)?,
|
||||
ino: file_serial_no(file)?,
|
||||
nlink: num_hardlinks(file, &metadata)?.try_into()?, // u64 doesn't fit into u32
|
||||
size: metadata.len(),
|
||||
atim: systemtime_to_timestamp(metadata.accessed()?)?,
|
||||
ctim: change_time(file, &metadata)?.try_into()?, // i64 doesn't fit into u64
|
||||
mtim: systemtime_to_timestamp(metadata.modified()?)?,
|
||||
filetype: filetype_from_std(&metadata.file_type()).to_wasi(),
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn filetype_from_std(ftype: &std::fs::FileType) -> FileType {
|
||||
if ftype.is_file() {
|
||||
FileType::RegularFile
|
||||
} else if ftype.is_dir() {
|
||||
FileType::Directory
|
||||
} else if ftype.is_symlink() {
|
||||
FileType::Symlink
|
||||
} else {
|
||||
FileType::Unknown
|
||||
}
|
||||
pub(crate) fn fd_filestat_get(file: &std::fs::File) -> Result<wasi::__wasi_filestat_t> {
|
||||
host_impl::filestat_from_win(file)
|
||||
}
|
||||
|
||||
pub(crate) fn path_filestat_get(
|
||||
@@ -481,7 +438,7 @@ pub(crate) fn path_filestat_get(
|
||||
) -> Result<wasi::__wasi_filestat_t> {
|
||||
let path = resolved.concatenate()?;
|
||||
let file = File::open(path)?;
|
||||
fd_filestat_get_impl(&file)
|
||||
host_impl::filestat_from_win(&file)
|
||||
}
|
||||
|
||||
pub(crate) fn path_filestat_set_times(
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
#![allow(non_camel_case_types)]
|
||||
#![allow(unused_unsafe)]
|
||||
#![allow(unused)]
|
||||
use crate::helpers::systemtime_to_timestamp;
|
||||
use crate::hostcalls_impl::{ClockEventData, FdEventData};
|
||||
use crate::memory::*;
|
||||
use crate::sys::host_impl;
|
||||
|
||||
Reference in New Issue
Block a user