Implement fd_filestat_get for all platforms (#42)
* Implement fd_filestat_get for all platforms * Remove an old comment * Remove panics from the syscall wrappers * Return WASI error type * Reuse Metadata if possible to save syscalls. * Refactor the change for two separate fd_filestat_get_impl * Refactor error handling
This commit is contained in:
committed by
Jakub Konka
parent
e759e3c2a4
commit
89fbde2c3f
10
src/helpers.rs
Normal file
10
src/helpers.rs
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
use crate::{host, Result};
|
||||||
|
use std::convert::TryInto;
|
||||||
|
use std::time::{SystemTime, UNIX_EPOCH};
|
||||||
|
pub(crate) fn systemtime_to_timestamp(st: SystemTime) -> Result<u64> {
|
||||||
|
st.duration_since(UNIX_EPOCH)
|
||||||
|
.map_err(|_| host::__WASI_EINVAL)? // date earlier than UNIX_EPOCH
|
||||||
|
.as_nanos()
|
||||||
|
.try_into()
|
||||||
|
.map_err(|_| host::__WASI_EOVERFLOW) // u128 doesn't fit into u64
|
||||||
|
}
|
||||||
@@ -730,7 +730,7 @@ pub(crate) fn fd_filestat_get(
|
|||||||
.get_fd_entry(fd, 0, 0)
|
.get_fd_entry(fd, 0, 0)
|
||||||
.and_then(|fe| fe.fd_object.descriptor.as_file())?;
|
.and_then(|fe| fe.fd_object.descriptor.as_file())?;
|
||||||
|
|
||||||
let host_filestat = hostcalls_impl::fd_filestat_get(fd)?;
|
let host_filestat = hostcalls_impl::fd_filestat_get_impl(fd)?;
|
||||||
|
|
||||||
trace!(" | *filestat_ptr={:?}", host_filestat);
|
trace!(" | *filestat_ptr={:?}", host_filestat);
|
||||||
|
|
||||||
|
|||||||
@@ -22,6 +22,7 @@
|
|||||||
|
|
||||||
mod ctx;
|
mod ctx;
|
||||||
mod fdentry;
|
mod fdentry;
|
||||||
|
mod helpers;
|
||||||
mod hostcalls_impl;
|
mod hostcalls_impl;
|
||||||
mod sys;
|
mod sys;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
|
|||||||
@@ -6,17 +6,27 @@ cfg_if! {
|
|||||||
mod unix;
|
mod unix;
|
||||||
pub use self::unix::*;
|
pub use self::unix::*;
|
||||||
|
|
||||||
pub fn errno_from_host(err: i32) -> host::__wasi_errno_t {
|
pub(crate) fn errno_from_host(err: i32) -> host::__wasi_errno_t {
|
||||||
host_impl::errno_from_nix(nix::errno::from_i32(err))
|
host_impl::errno_from_nix(nix::errno::from_i32(err))
|
||||||
}
|
}
|
||||||
} else if #[cfg(windows)] {
|
} else if #[cfg(windows)] {
|
||||||
mod windows;
|
mod windows;
|
||||||
pub use self::windows::*;
|
pub use self::windows::*;
|
||||||
|
|
||||||
pub fn errno_from_host(err: i32) -> host::__wasi_errno_t {
|
pub(crate) fn errno_from_host(err: i32) -> host::__wasi_errno_t {
|
||||||
host_impl::errno_from_win(winx::winerror::WinError::from_u32(err as u32))
|
host_impl::errno_from_win(winx::winerror::WinError::from_u32(err as u32))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
compile_error!("wasi-common doesn't compile for this platform yet");
|
compile_error!("wasi-common doesn't compile for this platform yet");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn errno_from_ioerror(e: std::io::Error) -> host::__wasi_errno_t {
|
||||||
|
match e.raw_os_error() {
|
||||||
|
Some(code) => errno_from_host(code),
|
||||||
|
None => {
|
||||||
|
log::debug!("Inconvertible OS error: {}", e);
|
||||||
|
host::__WASI_EIO
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -3,13 +3,15 @@
|
|||||||
use super::fs_helpers::*;
|
use super::fs_helpers::*;
|
||||||
use crate::ctx::WasiCtx;
|
use crate::ctx::WasiCtx;
|
||||||
use crate::fdentry::FdEntry;
|
use crate::fdentry::FdEntry;
|
||||||
use crate::sys::errno_from_host;
|
use crate::helpers::systemtime_to_timestamp;
|
||||||
use crate::sys::fdentry_impl::determine_type_rights;
|
use crate::sys::fdentry_impl::determine_type_rights;
|
||||||
use crate::sys::host_impl;
|
use crate::sys::host_impl;
|
||||||
|
use crate::sys::{errno_from_host, errno_from_ioerror};
|
||||||
use crate::{host, wasm32, Result};
|
use crate::{host, wasm32, Result};
|
||||||
use nix::libc::{self, c_long, c_void, off_t};
|
use nix::libc::{self, c_long, c_void, off_t};
|
||||||
|
use std::convert::TryInto;
|
||||||
use std::ffi::CString;
|
use std::ffi::CString;
|
||||||
use std::fs::File;
|
use std::fs::{File, Metadata};
|
||||||
use std::os::unix::fs::FileExt;
|
use std::os::unix::fs::FileExt;
|
||||||
use std::os::unix::prelude::{AsRawFd, FromRawFd};
|
use std::os::unix::prelude::{AsRawFd, FromRawFd};
|
||||||
|
|
||||||
@@ -356,11 +358,54 @@ pub(crate) fn path_rename(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn fd_filestat_get(fd: &File) -> Result<host::__wasi_filestat_t> {
|
pub(crate) fn fd_filestat_get_impl(file: &std::fs::File) -> Result<host::__wasi_filestat_t> {
|
||||||
use nix::sys::stat::fstat;
|
use std::os::unix::fs::MetadataExt;
|
||||||
let filestat =
|
|
||||||
fstat(fd.as_raw_fd()).map_err(|err| host_impl::errno_from_nix(err.as_errno().unwrap()))?;
|
let metadata = file.metadata().map_err(errno_from_ioerror)?;
|
||||||
host_impl::filestat_from_nix(filestat)
|
Ok(host::__wasi_filestat_t {
|
||||||
|
st_dev: metadata.dev(),
|
||||||
|
st_ino: metadata.ino(),
|
||||||
|
st_nlink: metadata
|
||||||
|
.nlink()
|
||||||
|
.try_into()
|
||||||
|
.map_err(|_| host::__WASI_EOVERFLOW)?, // u64 doesn't fit into u32
|
||||||
|
st_size: metadata.len(),
|
||||||
|
st_atim: metadata
|
||||||
|
.accessed()
|
||||||
|
.map_err(errno_from_ioerror)
|
||||||
|
.and_then(systemtime_to_timestamp)?,
|
||||||
|
st_ctim: metadata
|
||||||
|
.ctime()
|
||||||
|
.try_into()
|
||||||
|
.map_err(|_| host::__WASI_EOVERFLOW)?, // i64 doesn't fit into u64
|
||||||
|
st_mtim: metadata
|
||||||
|
.modified()
|
||||||
|
.map_err(errno_from_ioerror)
|
||||||
|
.and_then(systemtime_to_timestamp)?,
|
||||||
|
st_filetype: filetype(&metadata),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn filetype(metadata: &Metadata) -> host::__wasi_filetype_t {
|
||||||
|
use std::os::unix::fs::FileTypeExt;
|
||||||
|
let ftype = metadata.file_type();
|
||||||
|
if ftype.is_file() {
|
||||||
|
host::__WASI_FILETYPE_REGULAR_FILE
|
||||||
|
} else if ftype.is_dir() {
|
||||||
|
host::__WASI_FILETYPE_DIRECTORY
|
||||||
|
} else if ftype.is_symlink() {
|
||||||
|
host::__WASI_FILETYPE_SYMBOLIC_LINK
|
||||||
|
} else if ftype.is_char_device() {
|
||||||
|
host::__WASI_FILETYPE_CHARACTER_DEVICE
|
||||||
|
} else if ftype.is_block_device() {
|
||||||
|
host::__WASI_FILETYPE_BLOCK_DEVICE
|
||||||
|
} else if ftype.is_socket() || ftype.is_fifo() {
|
||||||
|
// TODO we should use getsockopt to find out if it's
|
||||||
|
// SOCKET_STREAM or SOCKET_DGRAM
|
||||||
|
host::__WASI_FILETYPE_SOCKET_STREAM
|
||||||
|
} else {
|
||||||
|
host::__WASI_FILETYPE_UNKNOWN
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn fd_filestat_set_times(
|
pub(crate) fn fd_filestat_set_times(
|
||||||
|
|||||||
@@ -3,11 +3,13 @@
|
|||||||
use super::fs_helpers::*;
|
use super::fs_helpers::*;
|
||||||
use crate::ctx::WasiCtx;
|
use crate::ctx::WasiCtx;
|
||||||
use crate::fdentry::FdEntry;
|
use crate::fdentry::FdEntry;
|
||||||
use crate::sys::errno_from_host;
|
use crate::helpers::systemtime_to_timestamp;
|
||||||
|
use crate::sys::{errno_from_ioerror, errno_from_host};
|
||||||
use crate::sys::fdentry_impl::determine_type_rights;
|
use crate::sys::fdentry_impl::determine_type_rights;
|
||||||
use crate::sys::host_impl;
|
use crate::sys::host_impl;
|
||||||
use crate::{host, Result};
|
use crate::{host, Result};
|
||||||
use std::fs::File;
|
use std::convert::TryInto;
|
||||||
|
use std::fs::{File, Metadata};
|
||||||
use std::io::{self, Seek, SeekFrom};
|
use std::io::{self, Seek, SeekFrom};
|
||||||
use std::os::windows::fs::FileExt;
|
use std::os::windows::fs::FileExt;
|
||||||
use std::os::windows::prelude::{AsRawHandle, FromRawHandle};
|
use std::os::windows::prelude::{AsRawHandle, FromRawHandle};
|
||||||
@@ -173,8 +175,65 @@ pub(crate) fn path_rename(
|
|||||||
unimplemented!("path_rename")
|
unimplemented!("path_rename")
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn fd_filestat_get(fd: &File) -> Result<host::__wasi_filestat_t> {
|
pub(crate) fn num_hardlinks(file: &File, _metadata: &Metadata) -> io::Result<u64> {
|
||||||
unimplemented!("fd_filestat_get")
|
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, _metadata: &Metadata) -> 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<host::__wasi_filestat_t> {
|
||||||
|
let metadata = file.metadata().map_err(errno_from_ioerror)?;
|
||||||
|
Ok(host::__wasi_filestat_t {
|
||||||
|
st_dev: device_id(file, &metadata).map_err(errno_from_ioerror)?,
|
||||||
|
st_ino: file_serial_no(file, &metadata).map_err(errno_from_ioerror)?,
|
||||||
|
st_nlink: num_hardlinks(file, &metadata)
|
||||||
|
.map_err(errno_from_ioerror)?
|
||||||
|
.try_into()
|
||||||
|
.map_err(|_| host::__WASI_EOVERFLOW)?, // u64 doesn't fit into u32
|
||||||
|
st_size: metadata.len(),
|
||||||
|
st_atim: metadata
|
||||||
|
.accessed()
|
||||||
|
.map_err(errno_from_ioerror)
|
||||||
|
.and_then(systemtime_to_timestamp)?,
|
||||||
|
st_ctim: change_time(file, &metadata)
|
||||||
|
.map_err(errno_from_ioerror)?
|
||||||
|
.try_into()
|
||||||
|
.map_err(|_| host::__WASI_EOVERFLOW)?, // i64 doesn't fit into u64
|
||||||
|
st_mtim: metadata
|
||||||
|
.modified()
|
||||||
|
.map_err(errno_from_ioerror)
|
||||||
|
.and_then(systemtime_to_timestamp)?,
|
||||||
|
st_filetype: filetype(&metadata).map_err(errno_from_ioerror)?,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn filetype(metadata: &Metadata) -> io::Result<host::__wasi_filetype_t> {
|
||||||
|
let ftype = metadata.file_type();
|
||||||
|
let ret = if ftype.is_file() {
|
||||||
|
host::__WASI_FILETYPE_REGULAR_FILE
|
||||||
|
} else if ftype.is_dir() {
|
||||||
|
host::__WASI_FILETYPE_DIRECTORY
|
||||||
|
} else if ftype.is_symlink() {
|
||||||
|
host::__WASI_FILETYPE_SYMBOLIC_LINK
|
||||||
|
} else {
|
||||||
|
host::__WASI_FILETYPE_UNKNOWN
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(ret)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn fd_filestat_set_times(
|
pub(crate) fn fd_filestat_set_times(
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
#![allow(non_camel_case_types)]
|
#![allow(non_camel_case_types)]
|
||||||
use crate::{winerror, Result};
|
use crate::{winerror, Result};
|
||||||
use std::ffi::{OsStr, OsString};
|
use std::ffi::{c_void, OsStr, OsString};
|
||||||
use std::os::windows::prelude::{OsStrExt, OsStringExt, RawHandle};
|
use std::fs::File;
|
||||||
|
use std::io;
|
||||||
|
use std::os::windows::prelude::{AsRawHandle, OsStrExt, OsStringExt, RawHandle};
|
||||||
use winapi::shared::minwindef::{self, DWORD};
|
use winapi::shared::minwindef::{self, DWORD};
|
||||||
use winapi::um::{fileapi, fileapi::GetFileType, winbase, winnt};
|
use winapi::um::{fileapi, fileapi::GetFileType, minwinbase, winbase, winnt};
|
||||||
|
|
||||||
/// Maximum total path length for Unicode in Windows.
|
/// Maximum total path length for Unicode in Windows.
|
||||||
/// [Maximum path length limitation]: https://docs.microsoft.com/en-us/windows/desktop/FileIO/naming-a-file#maximum-path-length-limitation
|
/// [Maximum path length limitation]: https://docs.microsoft.com/en-us/windows/desktop/FileIO/naming-a-file#maximum-path-length-limitation
|
||||||
@@ -457,3 +459,48 @@ pub fn openat<S: AsRef<OsStr>>(
|
|||||||
Ok(handle)
|
Ok(handle)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Taken from Rust libstd, file libstd/sys/windows/fs.rs
|
||||||
|
fn cvt(i: winapi::shared::minwindef::BOOL) -> io::Result<()> {
|
||||||
|
if i == 0 {
|
||||||
|
Err(io::Error::last_os_error())
|
||||||
|
} else {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_fileinfo(file: &File) -> io::Result<fileapi::BY_HANDLE_FILE_INFORMATION> {
|
||||||
|
use fileapi::{GetFileInformationByHandle, BY_HANDLE_FILE_INFORMATION};
|
||||||
|
use std::mem;
|
||||||
|
|
||||||
|
let handle = file.as_raw_handle();
|
||||||
|
let info = unsafe {
|
||||||
|
let mut info: BY_HANDLE_FILE_INFORMATION = mem::zeroed();
|
||||||
|
cvt(GetFileInformationByHandle(handle, &mut info))?;
|
||||||
|
info
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(info)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn change_time(file: &File) -> io::Result<i64> {
|
||||||
|
use fileapi::FILE_BASIC_INFO;
|
||||||
|
use minwinbase::FileBasicInfo;
|
||||||
|
use std::mem;
|
||||||
|
use winbase::GetFileInformationByHandleEx;
|
||||||
|
|
||||||
|
let handle = file.as_raw_handle();
|
||||||
|
let tm = unsafe {
|
||||||
|
let mut info: FILE_BASIC_INFO = mem::zeroed();
|
||||||
|
let infosize = mem::size_of_val(&info);
|
||||||
|
cvt(GetFileInformationByHandleEx(
|
||||||
|
handle,
|
||||||
|
FileBasicInfo,
|
||||||
|
&mut info as *mut FILE_BASIC_INFO as *mut c_void,
|
||||||
|
infosize as u32,
|
||||||
|
))?;
|
||||||
|
*info.ChangeTime.QuadPart()
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(tm)
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user