Initial error refactor

This commit is contained in:
Marcin Mielniczuk
2019-09-07 19:36:29 +02:00
committed by Jakub Konka
parent 85a41d449c
commit 14aaffd46f
22 changed files with 560 additions and 383 deletions

View File

@@ -5,8 +5,8 @@ use crate::fdentry::{Descriptor, FdEntry};
use crate::memory::*;
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 crate::sys::{host_impl, hostcalls_impl};
use crate::{host, wasm32, Error, Result};
use filetime::{set_file_handle_times, FileTime};
use log::trace;
use std::fs::File;
@@ -20,11 +20,11 @@ pub(crate) fn fd_close(wasi_ctx: &mut WasiCtx, fd: wasm32::__wasi_fd_t) -> Resul
if let Some(fdent) = wasi_ctx.fds.get(&fd) {
// can't close preopened files
if fdent.preopen_path.is_some() {
return Err(host::__WASI_ENOTSUP);
return Err(Error::ENOTSUP);
}
}
let mut fe = wasi_ctx.fds.remove(&fd).ok_or(host::__WASI_EBADF)?;
let mut fe = wasi_ctx.fds.remove(&fd).ok_or(Error::EBADF)?;
fe.fd_object.needs_close = true;
Ok(())
@@ -38,7 +38,7 @@ pub(crate) fn fd_datasync(wasi_ctx: &WasiCtx, fd: wasm32::__wasi_fd_t) -> Result
.get_fd_entry(fd, host::__WASI_RIGHT_FD_DATASYNC, 0)
.and_then(|fe| fe.fd_object.descriptor.as_file())?;
fd.sync_data().map_err(errno_from_ioerror)
fd.sync_data().map_err(Into::into)
}
pub(crate) fn fd_pread(
@@ -68,7 +68,7 @@ pub(crate) fn fd_pread(
let offset = dec_filesize(offset);
if offset > i64::max_value() as u64 {
return Err(host::__WASI_EIO);
return Err(Error::EIO);
}
let buf_size = iovs.iter().map(|v| v.buf_len).sum();
let mut buf = vec![0; buf_size];
@@ -117,7 +117,7 @@ pub(crate) fn fd_pwrite(
let offset = dec_filesize(offset);
if offset > i64::max_value() as u64 {
return Err(host::__WASI_EIO);
return Err(Error::EIO);
}
let buf_size = iovs.iter().map(|v| v.buf_len).sum();
let mut buf = Vec::with_capacity(buf_size);
@@ -160,10 +160,10 @@ pub(crate) fn fd_read(
let maybe_host_nread = match &mut *fe.fd_object.descriptor {
Descriptor::File(f) => f.read_vectored(&mut iovs),
Descriptor::Stdin => io::stdin().lock().read_vectored(&mut iovs),
_ => return Err(host::__WASI_EBADF),
_ => return Err(Error::EBADF),
};
let host_nread = maybe_host_nread.map_err(errno_from_ioerror)?;
let host_nread = maybe_host_nread?;
trace!(" | *nread={:?}", host_nread);
@@ -181,14 +181,14 @@ pub(crate) fn fd_renumber(
let to = dec_fd(to);
if !wasi_ctx.contains_fd_entry(from) || !wasi_ctx.contains_fd_entry(to) {
return Err(host::__WASI_EBADF);
return Err(Error::EBADF);
}
// Don't allow renumbering over a pre-opened resource.
// TODO: Eventually, we do want to permit this, once libpreopen in
// userspace is capable of removing entries from its tables as well.
if wasi_ctx.fds[&from].preopen_path.is_some() || wasi_ctx.fds[&to].preopen_path.is_some() {
return Err(host::__WASI_ENOTSUP);
return Err(Error::ENOTSUP);
}
// check if stdio fds
@@ -196,7 +196,7 @@ pub(crate) fn fd_renumber(
if !wasi_ctx.fds[&from].fd_object.descriptor.is_file()
|| !wasi_ctx.fds[&to].fd_object.descriptor.is_file()
{
return Err(host::__WASI_EBADF);
return Err(Error::EBADF);
}
let fe_from_dup = wasi_ctx.fds[&from]
@@ -244,9 +244,9 @@ pub(crate) fn fd_seek(
host::__WASI_WHENCE_CUR => SeekFrom::Current(offset),
host::__WASI_WHENCE_END => SeekFrom::End(offset),
host::__WASI_WHENCE_SET => SeekFrom::Start(offset as u64),
_ => return Err(host::__WASI_EINVAL),
_ => return Err(Error::EINVAL),
};
let host_newoffset = fd.seek(pos).map_err(errno_from_ioerror)?;
let host_newoffset = fd.seek(pos)?;
trace!(" | *newoffset={:?}", host_newoffset);
@@ -266,7 +266,7 @@ pub(crate) fn fd_tell(
.get_fd_entry(fd, host::__WASI_RIGHT_FD_TELL, 0)
.and_then(|fe| fe.fd_object.descriptor.as_file())?;
let host_offset = fd.seek(SeekFrom::Current(0)).map_err(errno_from_ioerror)?;
let host_offset = fd.seek(SeekFrom::Current(0))?;
trace!(" | *newoffset={:?}", host_offset);
@@ -328,12 +328,12 @@ pub(crate) fn fd_fdstat_set_rights(
);
let fd = dec_fd(fd);
let fe = wasi_ctx.fds.get_mut(&fd).ok_or(host::__WASI_EBADF)?;
let fe = wasi_ctx.fds.get_mut(&fd).ok_or(Error::EBADF)?;
if fe.rights_base & fs_rights_base != fs_rights_base
|| fe.rights_inheriting & fs_rights_inheriting != fs_rights_inheriting
{
return Err(host::__WASI_ENOTCAPABLE);
return Err(Error::ENOTCAPABLE);
}
fe.rights_base = fs_rights_base;
fe.rights_inheriting = fs_rights_inheriting;
@@ -348,7 +348,7 @@ pub(crate) fn fd_sync(wasi_ctx: &WasiCtx, fd: wasm32::__wasi_fd_t) -> Result<()>
let fd = wasi_ctx
.get_fd_entry(fd, host::__WASI_RIGHT_FD_SYNC, 0)
.and_then(|fe| fe.fd_object.descriptor.as_file())?;
fd.sync_all().map_err(errno_from_ioerror)
fd.sync_all().map_err(Into::into)
}
pub(crate) fn fd_write(
@@ -377,20 +377,17 @@ pub(crate) fn fd_write(
// perform unbuffered writes
let host_nwritten = match &mut *fe.fd_object.descriptor {
Descriptor::File(f) => f.write_vectored(&iovs).map_err(errno_from_ioerror)?,
Descriptor::Stdin => return Err(host::__WASI_EBADF),
Descriptor::File(f) => f.write_vectored(&iovs)?,
Descriptor::Stdin => return Err(Error::EBADF),
Descriptor::Stdout => {
// lock for the duration of the scope
let stdout = io::stdout();
let mut stdout = stdout.lock();
let nwritten = stdout.write_vectored(&iovs).map_err(errno_from_ioerror)?;
stdout.flush().map_err(errno_from_ioerror)?;
let nwritten = stdout.write_vectored(&iovs)?;
stdout.flush()?;
nwritten
}
Descriptor::Stderr => io::stderr()
.lock()
.write_vectored(&iovs)
.map_err(errno_from_ioerror)?,
Descriptor::Stderr => io::stderr().lock().write_vectored(&iovs)?,
};
trace!(" | *nwritten={:?}", host_nwritten);
@@ -439,17 +436,17 @@ pub(crate) fn fd_allocate(
.get_fd_entry(fd, host::__WASI_RIGHT_FD_ALLOCATE, 0)
.and_then(|fe| fe.fd_object.descriptor.as_file())?;
let metadata = fd.metadata().map_err(errno_from_ioerror)?;
let metadata = fd.metadata()?;
let current_size = metadata.len();
let wanted_size = offset.checked_add(len).ok_or(host::__WASI_E2BIG)?;
let wanted_size = offset.checked_add(len).ok_or(Error::E2BIG)?;
// This check will be unnecessary when rust-lang/rust#63326 is fixed
if wanted_size > i64::max_value() as u64 {
return Err(host::__WASI_E2BIG);
return Err(Error::E2BIG);
}
if wanted_size > current_size {
fd.set_len(wanted_size).map_err(errno_from_ioerror)
fd.set_len(wanted_size).map_err(Into::into)
} else {
Ok(())
}
@@ -782,7 +779,7 @@ pub(crate) fn fd_filestat_set_times_impl(
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);
return Err(Error::EINVAL);
}
let atim = if set_atim {
let time = UNIX_EPOCH + Duration::from_nanos(st_atim);
@@ -803,7 +800,7 @@ pub(crate) fn fd_filestat_set_times_impl(
} else {
None
};
set_file_handle_times(fd, atim, mtim).map_err(errno_from_ioerror)
set_file_handle_times(fd, atim, mtim).map_err(Into::into)
}
pub(crate) fn fd_filestat_set_size(
@@ -821,9 +818,9 @@ pub(crate) fn fd_filestat_set_size(
let st_size = dec_filesize(st_size);
// This check will be unnecessary when rust-lang/rust#63326 is fixed
if st_size > i64::max_value() as u64 {
return Err(host::__WASI_E2BIG);
return Err(Error::E2BIG);
}
fd.set_len(st_size).map_err(errno_from_ioerror)
fd.set_len(st_size).map_err(Into::into)
}
pub(crate) fn path_filestat_get(
@@ -1006,9 +1003,9 @@ pub(crate) fn fd_prestat_get(
wasi_ctx
.get_fd_entry(fd, host::__WASI_RIGHT_PATH_OPEN, 0)
.and_then(|fe| {
let po_path = fe.preopen_path.as_ref().ok_or(host::__WASI_ENOTSUP)?;
let po_path = fe.preopen_path.as_ref().ok_or(Error::ENOTSUP)?;
if fe.fd_object.file_type != host::__WASI_FILETYPE_DIRECTORY {
return Err(host::__WASI_ENOTDIR);
return Err(Error::ENOTDIR);
}
let path = host_impl::path_from_host(po_path.as_os_str())?;
@@ -1047,15 +1044,15 @@ pub(crate) fn fd_prestat_dir_name(
wasi_ctx
.get_fd_entry(fd, host::__WASI_RIGHT_PATH_OPEN, 0)
.and_then(|fe| {
let po_path = fe.preopen_path.as_ref().ok_or(host::__WASI_ENOTSUP)?;
let po_path = fe.preopen_path.as_ref().ok_or(Error::ENOTSUP)?;
if fe.fd_object.file_type != host::__WASI_FILETYPE_DIRECTORY {
return Err(host::__WASI_ENOTDIR);
return Err(Error::ENOTDIR);
}
let path = host_impl::path_from_host(po_path.as_os_str())?;
if path.len() > dec_usize(path_len) {
return Err(host::__WASI_ENAMETOOLONG);
return Err(Error::ENAMETOOLONG);
}
trace!(" | (path_ptr,path_len)='{}'", path);

View File

@@ -1,7 +1,7 @@
#![allow(non_camel_case_types)]
use crate::sys::host_impl;
use crate::sys::hostcalls_impl::fs_helpers::*;
use crate::sys::{errno_from_host, host_impl};
use crate::{host, Result};
use crate::{host, Error, Result};
use std::fs::File;
use std::path::{Component, Path};
@@ -33,13 +33,10 @@ pub(crate) fn path_get(
if path.contains('\0') {
// if contains NUL, return EILSEQ
return Err(host::__WASI_EILSEQ);
return Err(Error::EILSEQ);
}
let dirfd = dirfd.try_clone().map_err(|err| {
err.raw_os_error()
.map_or(host::__WASI_EBADF, errno_from_host)
})?;
let dirfd = dirfd.try_clone()?;
// Stack of directory file descriptors. Index 0 always corresponds with the directory provided
// to this function. Entering a directory causes a file descriptor to be pushed, while handling
@@ -64,7 +61,7 @@ pub(crate) fn path_get(
let ends_with_slash = cur_path.ends_with('/');
let mut components = Path::new(&cur_path).components();
let head = match components.next() {
None => return Err(host::__WASI_ENOENT),
None => return Err(Error::ENOENT),
Some(p) => p,
};
let tail = components.as_path();
@@ -80,18 +77,18 @@ pub(crate) fn path_get(
match head {
Component::Prefix(_) | Component::RootDir => {
// path is absolute!
return Err(host::__WASI_ENOTCAPABLE);
return Err(Error::ENOTCAPABLE);
}
Component::CurDir => {
// "." so skip
}
Component::ParentDir => {
// ".." so pop a dir
let _ = dir_stack.pop().ok_or(host::__WASI_ENOTCAPABLE)?;
let _ = dir_stack.pop().ok_or(Error::ENOTCAPABLE)?;
// we're not allowed to pop past the original directory
if dir_stack.is_empty() {
return Err(host::__WASI_ENOTCAPABLE);
return Err(Error::ENOTCAPABLE);
}
}
Component::Normal(head) => {
@@ -102,41 +99,44 @@ pub(crate) fn path_get(
}
if !path_stack.is_empty() || (ends_with_slash && !needs_final_component) {
match openat(dir_stack.last().ok_or(host::__WASI_ENOTCAPABLE)?, &head) {
match openat(dir_stack.last().ok_or(Error::ENOTCAPABLE)?, &head) {
Ok(new_dir) => {
dir_stack.push(new_dir);
}
Err(e)
if e == host::__WASI_ELOOP
|| e == host::__WASI_EMLINK
|| e == host::__WASI_ENOTDIR =>
// Check to see if it was a symlink. Linux indicates
// this with ENOTDIR because of the O_DIRECTORY flag.
{
// attempt symlink expansion
let mut link_path = readlinkat(
dir_stack.last().ok_or(host::__WASI_ENOTCAPABLE)?,
&head,
)?;
symlink_expansions += 1;
if symlink_expansions > MAX_SYMLINK_EXPANSIONS {
return Err(host::__WASI_ELOOP);
}
if head.ends_with('/') {
link_path.push('/');
}
log::debug!(
"attempted symlink expansion link_path={:?}",
link_path
);
path_stack.push(link_path);
}
Err(e) => {
return Err(e);
match e.as_wasi_errno() {
host::__WASI_ELOOP
| host::__WASI_EMLINK
| host::__WASI_ENOTDIR =>
// Check to see if it was a symlink. Linux indicates
// this with ENOTDIR because of the O_DIRECTORY flag.
{
// attempt symlink expansion
let mut link_path = readlinkat(
dir_stack.last().ok_or(Error::ENOTCAPABLE)?,
&head,
)?;
symlink_expansions += 1;
if symlink_expansions > MAX_SYMLINK_EXPANSIONS {
return Err(Error::ELOOP);
}
if head.ends_with('/') {
link_path.push('/');
}
log::debug!(
"attempted symlink expansion link_path={:?}",
link_path
);
path_stack.push(link_path);
}
_ => {
return Err(e);
}
}
}
}
@@ -146,14 +146,11 @@ pub(crate) fn path_get(
{
// if there's a trailing slash, or if `LOOKUP_SYMLINK_FOLLOW` is set, attempt
// symlink expansion
match readlinkat(
dir_stack.last().ok_or(host::__WASI_ENOTCAPABLE)?,
&head,
) {
match readlinkat(dir_stack.last().ok_or(Error::ENOTCAPABLE)?, &head) {
Ok(mut link_path) => {
symlink_expansions += 1;
if symlink_expansions > MAX_SYMLINK_EXPANSIONS {
return Err(host::__WASI_ELOOP);
return Err(Error::ELOOP);
}
if head.ends_with('/') {
@@ -169,7 +166,9 @@ pub(crate) fn path_get(
continue;
}
Err(e) => {
if e != host::__WASI_EINVAL && e != host::__WASI_ENOENT {
if e.as_wasi_errno() != host::__WASI_EINVAL
&& e.as_wasi_errno() != host::__WASI_ENOENT
{
return Err(e);
}
}
@@ -178,7 +177,7 @@ pub(crate) fn path_get(
// not a symlink, so we're done;
return Ok(PathGet {
dirfd: dir_stack.pop().ok_or(host::__WASI_ENOTCAPABLE)?,
dirfd: dir_stack.pop().ok_or(Error::ENOTCAPABLE)?,
path: head,
});
}
@@ -188,7 +187,7 @@ pub(crate) fn path_get(
// no further components to process. means we've hit a case like "." or "a/..", or if the
// input path has trailing slashes and `needs_final_component` is not set
return Ok(PathGet {
dirfd: dir_stack.pop().ok_or(host::__WASI_ENOTCAPABLE)?,
dirfd: dir_stack.pop().ok_or(Error::ENOTCAPABLE)?,
path: String::from("."),
});
}

View File

@@ -2,7 +2,7 @@
use crate::ctx::WasiCtx;
use crate::memory::*;
use crate::sys::hostcalls_impl;
use crate::{host, wasm32, Result};
use crate::{wasm32, Error, Result};
use log::trace;
use std::convert::TryFrom;
@@ -29,11 +29,8 @@ pub(crate) fn args_get(
argv.push(arg_ptr);
let len =
wasm32::uintptr_t::try_from(arg_bytes.len()).map_err(|_| host::__WASI_EOVERFLOW)?;
argv_buf_offset = argv_buf_offset
.checked_add(len)
.ok_or(host::__WASI_EOVERFLOW)?;
let len = wasm32::uintptr_t::try_from(arg_bytes.len()).map_err(|_| Error::EOVERFLOW)?;
argv_buf_offset = argv_buf_offset.checked_add(len).ok_or(Error::EOVERFLOW)?;
}
enc_slice_of(memory, argv.as_slice(), argv_ptr)
@@ -90,11 +87,10 @@ pub(crate) fn environ_get(
environ.push(env_ptr);
let len =
wasm32::uintptr_t::try_from(env_bytes.len()).map_err(|_| host::__WASI_EOVERFLOW)?;
let len = wasm32::uintptr_t::try_from(env_bytes.len()).map_err(|_| Error::EOVERFLOW)?;
environ_buf_offset = environ_buf_offset
.checked_add(len)
.ok_or(host::__WASI_EOVERFLOW)?;
.ok_or(Error::EOVERFLOW)?;
}
enc_slice_of(memory, environ.as_slice(), environ_ptr)
@@ -119,7 +115,7 @@ pub(crate) fn environ_sizes_get(
.try_fold(0, |acc: u32, pair| {
acc.checked_add(pair.as_bytes_with_nul().len() as u32)
})
.ok_or(host::__WASI_EOVERFLOW)?;
.ok_or(Error::EOVERFLOW)?;
trace!(" | *environ_count_ptr={:?}", environ_count);
@@ -202,7 +198,7 @@ pub(crate) fn poll_oneoff(
);
if nsubscriptions as u64 > wasm32::__wasi_filesize_t::max_value() {
return Err(host::__WASI_EINVAL);
return Err(Error::EINVAL);
}
enc_pointee(memory, nevents, 0)?;