[wasi-common]: yanix now returns io::Error directly (#1242)

* Yanix now returns io::Error

This commit may seem somewhat controversial at first, but hear me
out first. Currently, Yanix would return a custom error that's a
wrapper around three other error types returned by various entities
inside Rust's `libstd`. In particular, Yanix's error type would wrap
`io::Error`, `num::TryFromIntError` and `ffi::NulError`. It turns
out that there is a natural conversion between the first and the last
and provided by the standard library, i.e., `From<ffi::NulError> for io::Error`
is provided. So at the surface it may seem that only the first two
wrapped error types are worth keeping.

Digging a little bit deeper into `libstd`, `num::TryFromIntError`
is essentially speaking only a marker that the integral conversion
went wrong. The struct implementing this error stores a unit type,
and nothing more. It therefore seems like a waste to wrap this
particular error when we could unify everything under `io::Error`.
And so, whenever we perform an int conversion, I suggest we simply
remap the error to `io::Error::from_raw_os_error(libc::EOVERFLOW)`
since this carries a comparable amount of information.

As a result of completely discarding `yanix::Error` custom error type,
we are invariably simplifying `yanix` itself, but also allowing
`wasi-common` to simplify in several places as well.

* Adapt wasi-common to changes in yanix

* Add Cargo.lock

* Unwrap try_into's where possible

* Remove unnecessary type annotation
This commit is contained in:
Jakub Konka
2020-03-06 23:20:54 +01:00
committed by GitHub
parent 55337abd3f
commit 42fae4e3b8
25 changed files with 368 additions and 398 deletions

View File

@@ -1,9 +1,10 @@
use crate::{Error, Result};
use crate::{from_result, from_success_code};
use bitflags::bitflags;
use cfg_if::cfg_if;
use std::{
convert::TryInto,
ffi::{CString, OsStr, OsString},
io::Result,
os::unix::prelude::*,
};
@@ -137,7 +138,7 @@ pub unsafe fn openat<P: AsRef<OsStr>>(
mode: Mode,
) -> Result<RawFd> {
let path = CString::new(path.as_ref().as_bytes())?;
Error::from_result(libc::openat(
from_result(libc::openat(
dirfd,
path.as_ptr(),
oflag.bits(),
@@ -148,21 +149,23 @@ pub unsafe fn openat<P: AsRef<OsStr>>(
pub unsafe fn readlinkat<P: AsRef<OsStr>>(dirfd: RawFd, path: P) -> Result<OsString> {
let path = CString::new(path.as_ref().as_bytes())?;
let buffer = &mut [0u8; libc::PATH_MAX as usize + 1];
Error::from_result(libc::readlinkat(
let nread = from_result(libc::readlinkat(
dirfd,
path.as_ptr(),
buffer.as_mut_ptr() as *mut _,
buffer.len(),
))
.and_then(|nread| {
let link = OsStr::from_bytes(&buffer[0..nread.try_into()?]);
Ok(link.into())
})
))?;
// We can just unwrap() this, because readlinkat returns an ssize_t which is either -1
// (handled above) or non-negative and will fit in a size_t/usize, which is what we're
// converting it to here.
let nread = nread.try_into().unwrap();
let link = OsStr::from_bytes(&buffer[0..nread]);
Ok(link.into())
}
pub unsafe fn mkdirat<P: AsRef<OsStr>>(dirfd: RawFd, path: P, mode: Mode) -> Result<()> {
let path = CString::new(path.as_ref().as_bytes())?;
Error::from_success_code(libc::mkdirat(dirfd, path.as_ptr(), mode.bits()))
from_success_code(libc::mkdirat(dirfd, path.as_ptr(), mode.bits()))
}
pub unsafe fn linkat<P: AsRef<OsStr>>(
@@ -174,7 +177,7 @@ pub unsafe fn linkat<P: AsRef<OsStr>>(
) -> Result<()> {
let old_path = CString::new(old_path.as_ref().as_bytes())?;
let new_path = CString::new(new_path.as_ref().as_bytes())?;
Error::from_success_code(libc::linkat(
from_success_code(libc::linkat(
old_dirfd,
old_path.as_ptr(),
new_dirfd,
@@ -185,7 +188,7 @@ pub unsafe fn linkat<P: AsRef<OsStr>>(
pub unsafe fn unlinkat<P: AsRef<OsStr>>(dirfd: RawFd, path: P, flags: AtFlag) -> Result<()> {
let path = CString::new(path.as_ref().as_bytes())?;
Error::from_success_code(libc::unlinkat(dirfd, path.as_ptr(), flags.bits()))
from_success_code(libc::unlinkat(dirfd, path.as_ptr(), flags.bits()))
}
pub unsafe fn renameat<P: AsRef<OsStr>>(
@@ -196,7 +199,7 @@ pub unsafe fn renameat<P: AsRef<OsStr>>(
) -> Result<()> {
let old_path = CString::new(old_path.as_ref().as_bytes())?;
let new_path = CString::new(new_path.as_ref().as_bytes())?;
Error::from_success_code(libc::renameat(
from_success_code(libc::renameat(
old_dirfd,
old_path.as_ptr(),
new_dirfd,
@@ -207,7 +210,7 @@ pub unsafe fn renameat<P: AsRef<OsStr>>(
pub unsafe fn symlinkat<P: AsRef<OsStr>>(old_path: P, new_dirfd: RawFd, new_path: P) -> Result<()> {
let old_path = CString::new(old_path.as_ref().as_bytes())?;
let new_path = CString::new(new_path.as_ref().as_bytes())?;
Error::from_success_code(libc::symlinkat(
from_success_code(libc::symlinkat(
old_path.as_ptr(),
new_dirfd,
new_path.as_ptr(),
@@ -218,7 +221,7 @@ pub unsafe fn fstatat<P: AsRef<OsStr>>(dirfd: RawFd, path: P, flags: AtFlag) ->
use std::mem::MaybeUninit;
let path = CString::new(path.as_ref().as_bytes())?;
let mut filestat = MaybeUninit::<libc::stat>::uninit();
Error::from_result(libc::fstatat(
from_result(libc::fstatat(
dirfd,
path.as_ptr(),
filestat.as_mut_ptr(),
@@ -230,20 +233,26 @@ pub unsafe fn fstatat<P: AsRef<OsStr>>(dirfd: RawFd, path: P, flags: AtFlag) ->
pub unsafe fn fstat(fd: RawFd) -> Result<libc::stat> {
use std::mem::MaybeUninit;
let mut filestat = MaybeUninit::<libc::stat>::uninit();
Error::from_result(libc::fstat(fd, filestat.as_mut_ptr()))?;
from_result(libc::fstat(fd, filestat.as_mut_ptr()))?;
Ok(filestat.assume_init())
}
/// `fionread()` function, equivalent to `ioctl(fd, FIONREAD, *bytes)`.
pub unsafe fn fionread(fd: RawFd) -> Result<u32> {
let mut nread: libc::c_int = 0;
Error::from_result(libc::ioctl(fd, libc::FIONREAD, &mut nread as *mut _))?;
Ok(nread.try_into()?)
from_result(libc::ioctl(fd, libc::FIONREAD, &mut nread as *mut _))?;
// FIONREAD returns a non-negative int if it doesn't fail, or it'll fit in a u32 if it does.
//
// For the future, if we want to be super cautious and avoid assuming int is 32-bit, we could
// widen fionread's return type here, since the one place that calls it wants a u64 anyway.
Ok(nread.try_into().unwrap())
}
/// This function is unsafe because it operates on a raw file descriptor.
/// It's provided, because std::io::Seek requires a mutable borrow.
pub unsafe fn tell(fd: RawFd) -> Result<u64> {
let offset: i64 = Error::from_result(libc::lseek(fd, 0, libc::SEEK_CUR))?;
Ok(offset.try_into()?)
let offset = from_result(libc::lseek(fd, 0, libc::SEEK_CUR))?;
// lseek returns an off_t, which we can assume is a non-negative i64 if it doesn't fail.
// So we can unwrap() this conversion.
Ok(offset.try_into().unwrap())
}