Add support for wasi_snapshot_preview1. (#592)

* Add support for wasi_snapshot_preview1.

This adds support for the new ABI, while preserving compatibility
support for the old ABI.

* Fix compilation on platforms where nlink_t isn't 64-bit.

* rustfmt

* Fix Windows build errors.
This commit is contained in:
Dan Gohman
2019-11-18 22:07:16 -08:00
committed by GitHub
parent 39e57e3e9a
commit d645902620
83 changed files with 9928 additions and 803 deletions

View File

@@ -61,10 +61,10 @@ pub(crate) unsafe fn determine_type_and_access_rights<Handle: AsRawHandle>(
wasi::__WASI_FILETYPE_DIRECTORY | wasi::__WASI_FILETYPE_REGULAR_FILE => {
let mode = get_file_access_mode(handle.as_raw_handle())?;
if mode.contains(AccessMode::FILE_GENERIC_READ) {
rights_base |= wasi::__WASI_RIGHT_FD_READ;
rights_base |= wasi::__WASI_RIGHTS_FD_READ;
}
if mode.contains(AccessMode::FILE_GENERIC_WRITE) {
rights_base |= wasi::__WASI_RIGHT_FD_WRITE;
rights_base |= wasi::__WASI_RIGHTS_FD_WRITE;
}
}
_ => {

View File

@@ -13,30 +13,30 @@ pub(crate) fn errno_from_win(error: winx::winerror::WinError) -> wasi::__wasi_er
// TODO: implement error mapping between Windows and WASI
use winx::winerror::WinError::*;
match error {
ERROR_SUCCESS => wasi::__WASI_ESUCCESS,
ERROR_BAD_ENVIRONMENT => wasi::__WASI_E2BIG,
ERROR_FILE_NOT_FOUND => wasi::__WASI_ENOENT,
ERROR_PATH_NOT_FOUND => wasi::__WASI_ENOENT,
ERROR_TOO_MANY_OPEN_FILES => wasi::__WASI_ENFILE,
ERROR_ACCESS_DENIED => wasi::__WASI_EACCES,
ERROR_SHARING_VIOLATION => wasi::__WASI_EACCES,
ERROR_PRIVILEGE_NOT_HELD => wasi::__WASI_ENOTCAPABLE, // TODO is this the correct mapping?
ERROR_INVALID_HANDLE => wasi::__WASI_EBADF,
ERROR_INVALID_NAME => wasi::__WASI_ENOENT,
ERROR_NOT_ENOUGH_MEMORY => wasi::__WASI_ENOMEM,
ERROR_OUTOFMEMORY => wasi::__WASI_ENOMEM,
ERROR_DIR_NOT_EMPTY => wasi::__WASI_ENOTEMPTY,
ERROR_NOT_READY => wasi::__WASI_EBUSY,
ERROR_BUSY => wasi::__WASI_EBUSY,
ERROR_NOT_SUPPORTED => wasi::__WASI_ENOTSUP,
ERROR_FILE_EXISTS => wasi::__WASI_EEXIST,
ERROR_BROKEN_PIPE => wasi::__WASI_EPIPE,
ERROR_BUFFER_OVERFLOW => wasi::__WASI_ENAMETOOLONG,
ERROR_NOT_A_REPARSE_POINT => wasi::__WASI_EINVAL,
ERROR_NEGATIVE_SEEK => wasi::__WASI_EINVAL,
ERROR_DIRECTORY => wasi::__WASI_ENOTDIR,
ERROR_ALREADY_EXISTS => wasi::__WASI_EEXIST,
_ => wasi::__WASI_ENOTSUP,
ERROR_SUCCESS => wasi::__WASI_ERRNO_SUCCESS,
ERROR_BAD_ENVIRONMENT => wasi::__WASI_ERRNO_2BIG,
ERROR_FILE_NOT_FOUND => wasi::__WASI_ERRNO_NOENT,
ERROR_PATH_NOT_FOUND => wasi::__WASI_ERRNO_NOENT,
ERROR_TOO_MANY_OPEN_FILES => wasi::__WASI_ERRNO_NFILE,
ERROR_ACCESS_DENIED => wasi::__WASI_ERRNO_ACCES,
ERROR_SHARING_VIOLATION => wasi::__WASI_ERRNO_ACCES,
ERROR_PRIVILEGE_NOT_HELD => wasi::__WASI_ERRNO_NOTCAPABLE, // TODO is this the correct mapping?
ERROR_INVALID_HANDLE => wasi::__WASI_ERRNO_BADF,
ERROR_INVALID_NAME => wasi::__WASI_ERRNO_NOENT,
ERROR_NOT_ENOUGH_MEMORY => wasi::__WASI_ERRNO_NOMEM,
ERROR_OUTOFMEMORY => wasi::__WASI_ERRNO_NOMEM,
ERROR_DIR_NOT_EMPTY => wasi::__WASI_ERRNO_NOTEMPTY,
ERROR_NOT_READY => wasi::__WASI_ERRNO_BUSY,
ERROR_BUSY => wasi::__WASI_ERRNO_BUSY,
ERROR_NOT_SUPPORTED => wasi::__WASI_ERRNO_NOTSUP,
ERROR_FILE_EXISTS => wasi::__WASI_ERRNO_EXIST,
ERROR_BROKEN_PIPE => wasi::__WASI_ERRNO_PIPE,
ERROR_BUFFER_OVERFLOW => wasi::__WASI_ERRNO_NAMETOOLONG,
ERROR_NOT_A_REPARSE_POINT => wasi::__WASI_ERRNO_INVAL,
ERROR_NEGATIVE_SEEK => wasi::__WASI_ERRNO_INVAL,
ERROR_DIRECTORY => wasi::__WASI_ERRNO_NOTDIR,
ERROR_ALREADY_EXISTS => wasi::__WASI_ERRNO_EXIST,
_ => wasi::__WASI_ERRNO_NOTSUP,
}
}
@@ -44,12 +44,12 @@ pub(crate) fn fdflags_from_win(mode: AccessMode) -> wasi::__wasi_fdflags_t {
let mut fdflags = 0;
// TODO verify this!
if mode.contains(AccessMode::FILE_APPEND_DATA) {
fdflags |= wasi::__WASI_FDFLAG_APPEND;
fdflags |= wasi::__WASI_FDFLAGS_APPEND;
}
if mode.contains(AccessMode::SYNCHRONIZE) {
fdflags |= wasi::__WASI_FDFLAG_DSYNC;
fdflags |= wasi::__WASI_FDFLAG_RSYNC;
fdflags |= wasi::__WASI_FDFLAG_SYNC;
fdflags |= wasi::__WASI_FDFLAGS_DSYNC;
fdflags |= wasi::__WASI_FDFLAGS_RSYNC;
fdflags |= wasi::__WASI_FDFLAGS_SYNC;
}
// The NONBLOCK equivalent is FILE_FLAG_OVERLAPPED
// but it seems winapi doesn't provide a mechanism
@@ -68,15 +68,15 @@ pub(crate) fn win_from_fdflags(fdflags: wasi::__wasi_fdflags_t) -> (AccessMode,
let mut flags = Flags::empty();
// TODO verify this!
if fdflags & wasi::__WASI_FDFLAG_NONBLOCK != 0 {
if fdflags & wasi::__WASI_FDFLAGS_NONBLOCK != 0 {
flags.insert(Flags::FILE_FLAG_OVERLAPPED);
}
if fdflags & wasi::__WASI_FDFLAG_APPEND != 0 {
if fdflags & wasi::__WASI_FDFLAGS_APPEND != 0 {
access_mode.insert(AccessMode::FILE_APPEND_DATA);
}
if fdflags & wasi::__WASI_FDFLAG_DSYNC != 0
|| fdflags & wasi::__WASI_FDFLAG_RSYNC != 0
|| fdflags & wasi::__WASI_FDFLAG_SYNC != 0
if fdflags & wasi::__WASI_FDFLAGS_DSYNC != 0
|| fdflags & wasi::__WASI_FDFLAGS_RSYNC != 0
|| fdflags & wasi::__WASI_FDFLAGS_SYNC != 0
{
access_mode.insert(AccessMode::SYNCHRONIZE);
}
@@ -85,13 +85,13 @@ pub(crate) fn win_from_fdflags(fdflags: wasi::__wasi_fdflags_t) -> (AccessMode,
}
pub(crate) fn win_from_oflags(oflags: wasi::__wasi_oflags_t) -> CreationDisposition {
if oflags & wasi::__WASI_O_CREAT != 0 {
if oflags & wasi::__WASI_O_EXCL != 0 {
if oflags & wasi::__WASI_OFLAGS_CREAT != 0 {
if oflags & wasi::__WASI_OFLAGS_EXCL != 0 {
CreationDisposition::CREATE_NEW
} else {
CreationDisposition::CREATE_ALWAYS
}
} else if oflags & wasi::__WASI_O_TRUNC != 0 {
} else if oflags & wasi::__WASI_OFLAGS_TRUNC != 0 {
CreationDisposition::TRUNCATE_EXISTING
} else {
CreationDisposition::OPEN_EXISTING
@@ -101,7 +101,7 @@ pub(crate) fn win_from_oflags(oflags: wasi::__wasi_oflags_t) -> CreationDisposit
/// Creates owned WASI path from OS string.
///
/// NB WASI spec requires OS string to be valid UTF-8. Otherwise,
/// `__WASI_EILSEQ` error is returned.
/// `__WASI_ERRNO_ILSEQ` error is returned.
pub(crate) fn path_from_host<S: AsRef<OsStr>>(s: S) -> Result<String> {
let vec: Vec<u16> = s.as_ref().encode_wide().collect();
String::from_utf16(&vec).map_err(|_| Error::EILSEQ)

View File

@@ -139,7 +139,7 @@ pub(crate) fn path_open(
return Err(Error::ELOOP);
}
// check if we are trying to open a file as a dir
if file_type.is_file() && oflags & wasi::__WASI_O_DIRECTORY != 0 {
if file_type.is_file() && oflags & wasi::__WASI_OFLAGS_DIRECTORY != 0 {
return Err(Error::ENOTDIR);
}
}
@@ -410,14 +410,14 @@ pub(crate) fn change_time(file: &File, _metadata: &Metadata) -> io::Result<i64>
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 {
st_dev: device_id(file, &metadata)?,
st_ino: file_serial_no(file)?,
st_nlink: num_hardlinks(file, &metadata)?.try_into()?, // u64 doesn't fit into u32
st_size: metadata.len(),
st_atim: systemtime_to_timestamp(metadata.accessed()?)?,
st_ctim: change_time(file, &metadata)?.try_into()?, // i64 doesn't fit into u64
st_mtim: systemtime_to_timestamp(metadata.modified()?)?,
st_filetype: filetype_from_std(&metadata.file_type()).to_wasi(),
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(),
})
}

View File

@@ -23,23 +23,23 @@ pub(crate) fn path_open_rights(
fdflags: wasi::__wasi_fdflags_t,
) -> (wasi::__wasi_rights_t, wasi::__wasi_rights_t) {
// which rights are needed on the dirfd?
let mut needed_base = wasi::__WASI_RIGHT_PATH_OPEN;
let mut needed_base = wasi::__WASI_RIGHTS_PATH_OPEN;
let mut needed_inheriting = rights_base | rights_inheriting;
// convert open flags
if oflags & wasi::__WASI_O_CREAT != 0 {
needed_base |= wasi::__WASI_RIGHT_PATH_CREATE_FILE;
} else if oflags & wasi::__WASI_O_TRUNC != 0 {
needed_base |= wasi::__WASI_RIGHT_PATH_FILESTAT_SET_SIZE;
if oflags & wasi::__WASI_OFLAGS_CREAT != 0 {
needed_base |= wasi::__WASI_RIGHTS_PATH_CREATE_FILE;
} else if oflags & wasi::__WASI_OFLAGS_TRUNC != 0 {
needed_base |= wasi::__WASI_RIGHTS_PATH_FILESTAT_SET_SIZE;
}
// convert file descriptor flags
if fdflags & wasi::__WASI_FDFLAG_DSYNC != 0
|| fdflags & wasi::__WASI_FDFLAG_RSYNC != 0
|| fdflags & wasi::__WASI_FDFLAG_SYNC != 0
if fdflags & wasi::__WASI_FDFLAGS_DSYNC != 0
|| fdflags & wasi::__WASI_FDFLAGS_RSYNC != 0
|| fdflags & wasi::__WASI_FDFLAGS_SYNC != 0
{
needed_inheriting |= wasi::__WASI_RIGHT_FD_DATASYNC;
needed_inheriting |= wasi::__WASI_RIGHT_FD_SYNC;
needed_inheriting |= wasi::__WASI_RIGHTS_FD_DATASYNC;
needed_inheriting |= wasi::__WASI_RIGHTS_FD_SYNC;
}
(needed_base, needed_inheriting)

View File

@@ -53,25 +53,25 @@ pub(crate) fn clock_res_get(clock_id: wasi::__wasi_clockid_t) -> Result<wasi::__
// [4] https://www.codeproject.com/Tips/1011902/High-Resolution-Time-For-Windows
// [5] https://stackoverflow.com/questions/7685762/windows-7-timing-functions-how-to-use-getsystemtimeadjustment-correctly
// [6] https://bugs.python.org/issue19007
wasi::__WASI_CLOCK_REALTIME => 55_000_000,
wasi::__WASI_CLOCKID_REALTIME => 55_000_000,
// std::time::Instant uses QueryPerformanceCounter & QueryPerformanceFrequency internally
wasi::__WASI_CLOCK_MONOTONIC => *PERF_COUNTER_RES,
wasi::__WASI_CLOCKID_MONOTONIC => *PERF_COUNTER_RES,
// The best we can do is to hardcode the value from the docs.
// https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-getprocesstimes
wasi::__WASI_CLOCK_PROCESS_CPUTIME_ID => 100,
wasi::__WASI_CLOCKID_PROCESS_CPUTIME_ID => 100,
// The best we can do is to hardcode the value from the docs.
// https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-getthreadtimes
wasi::__WASI_CLOCK_THREAD_CPUTIME_ID => 100,
wasi::__WASI_CLOCKID_THREAD_CPUTIME_ID => 100,
_ => return Err(Error::EINVAL),
})
}
pub(crate) fn clock_time_get(clock_id: wasi::__wasi_clockid_t) -> Result<wasi::__wasi_timestamp_t> {
let duration = match clock_id {
wasi::__WASI_CLOCK_REALTIME => get_monotonic_time(),
wasi::__WASI_CLOCK_MONOTONIC => get_realtime_time()?,
wasi::__WASI_CLOCK_PROCESS_CPUTIME_ID => get_proc_cputime()?,
wasi::__WASI_CLOCK_THREAD_CPUTIME_ID => get_thread_cputime()?,
wasi::__WASI_CLOCKID_REALTIME => get_monotonic_time(),
wasi::__WASI_CLOCKID_MONOTONIC => get_realtime_time()?,
wasi::__WASI_CLOCKID_PROCESS_CPUTIME_ID => get_proc_cputime()?,
wasi::__WASI_CLOCKID_THREAD_CPUTIME_ID => get_thread_cputime()?,
_ => return Err(Error::EINVAL),
};
duration.as_nanos().try_into().map_err(Into::into)
@@ -87,7 +87,7 @@ pub(crate) fn poll_oneoff(
fn get_monotonic_time() -> Duration {
// We're circumventing the fact that we can't get a Duration from an Instant
// The epoch of __WASI_CLOCK_MONOTONIC is undefined, so we fix a time point once
// The epoch of __WASI_CLOCKID_MONOTONIC is undefined, so we fix a time point once
// and count relative to this time point.
//
// The alternative would be to copy over the implementation of std::time::Instant