Use wiggle "trappable error" to implement wasi-common (#5279)
* convert wasi-common from defining its own error to using wiggle trappable error * wasi-common impl crates: switch error strategy * wasmtime-wasi: error is trappable, and no longer requires UserErrorConversion * docs * typo * readdir: windows fixes * fix windows scheduler errors fun fact! the Send and Recv errors here that just had a `.context` on them were previously not being captured in the downcasting either. They need to be traps, and would have ended up that way by ommission, but you'd never actually know that by reading the code!
This commit is contained in:
@@ -138,6 +138,19 @@ impl WasiDir for Dir {
|
||||
&self,
|
||||
cursor: ReaddirCursor,
|
||||
) -> Result<Box<dyn Iterator<Item = Result<ReaddirEntity, Error>> + Send>, Error> {
|
||||
// We need to keep a full-fidelity io Error around to check for a special failure mode
|
||||
// on windows, but also this function can fail due to an illegal byte sequence in a
|
||||
// filename, which we can't construct an io Error to represent.
|
||||
enum ReaddirError {
|
||||
Io(std::io::Error),
|
||||
IllegalSequence,
|
||||
}
|
||||
impl From<std::io::Error> for ReaddirError {
|
||||
fn from(e: std::io::Error) -> ReaddirError {
|
||||
ReaddirError::Io(e)
|
||||
}
|
||||
}
|
||||
|
||||
// cap_std's read_dir does not include . and .., we should prepend these.
|
||||
// Why does the Ok contain a tuple? We can't construct a cap_std::fs::DirEntry, and we don't
|
||||
// have enough info to make a ReaddirEntity yet.
|
||||
@@ -145,7 +158,7 @@ impl WasiDir for Dir {
|
||||
let rd = vec![
|
||||
{
|
||||
let name = ".".to_owned();
|
||||
Ok((FileType::Directory, dir_meta.ino(), name))
|
||||
Ok::<_, ReaddirError>((FileType::Directory, dir_meta.ino(), name))
|
||||
},
|
||||
{
|
||||
let name = "..".to_owned();
|
||||
@@ -163,24 +176,22 @@ impl WasiDir for Dir {
|
||||
let name = entry
|
||||
.file_name()
|
||||
.into_string()
|
||||
.map_err(|_| Error::illegal_byte_sequence().context("filename"))?;
|
||||
.map_err(|_| ReaddirError::IllegalSequence)?;
|
||||
Ok((filetype, inode, name))
|
||||
});
|
||||
|
||||
// On Windows, filter out files like `C:\DumpStack.log.tmp` which we
|
||||
// can't get a full metadata for.
|
||||
#[cfg(windows)]
|
||||
let entries = entries.filter(|entry: &Result<_, wasi_common::Error>| {
|
||||
let entries = entries.filter(|entry| {
|
||||
use windows_sys::Win32::Foundation::{
|
||||
ERROR_ACCESS_DENIED, ERROR_SHARING_VIOLATION,
|
||||
};
|
||||
if let Err(err) = entry {
|
||||
if let Some(err) = err.downcast_ref::<std::io::Error>() {
|
||||
if err.raw_os_error() == Some(ERROR_SHARING_VIOLATION as i32)
|
||||
|| err.raw_os_error() == Some(ERROR_ACCESS_DENIED as i32)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if let Err(ReaddirError::Io(err)) = entry {
|
||||
if err.raw_os_error() == Some(ERROR_SHARING_VIOLATION as i32)
|
||||
|| err.raw_os_error() == Some(ERROR_ACCESS_DENIED as i32)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
true
|
||||
@@ -197,7 +208,8 @@ impl WasiDir for Dir {
|
||||
inode,
|
||||
name,
|
||||
}),
|
||||
Err(e) => Err(e),
|
||||
Err(ReaddirError::Io(e)) => Err(e.into()),
|
||||
Err(ReaddirError::IllegalSequence) => Err(Error::illegal_byte_sequence()),
|
||||
})
|
||||
.skip(u64::from(cursor) as usize);
|
||||
|
||||
|
||||
@@ -47,7 +47,7 @@ pub async fn poll_oneoff<'a>(poll: &mut Poll<'a>) -> Result<(), Error> {
|
||||
match rustix::io::poll(&mut pollfds, poll_timeout) {
|
||||
Ok(ready) => break ready,
|
||||
Err(rustix::io::Errno::INTR) => continue,
|
||||
Err(err) => return Err(err.into()),
|
||||
Err(err) => return Err(std::io::Error::from(err).into()),
|
||||
}
|
||||
};
|
||||
if ready > 0 {
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
// We suspect there are bugs in this scheduler, however, we have not
|
||||
// taken the time to improve it. See bug #2880.
|
||||
|
||||
use anyhow::Context;
|
||||
use once_cell::sync::Lazy;
|
||||
use std::ops::Deref;
|
||||
use std::sync::mpsc::{self, Receiver, RecvTimeoutError, Sender, TryRecvError};
|
||||
@@ -73,7 +72,7 @@ pub async fn poll_oneoff_<'a>(
|
||||
if !stdin_read_subs.is_empty() {
|
||||
let state = STDIN_POLL
|
||||
.lock()
|
||||
.map_err(|_| Error::trap("failed to take lock of STDIN_POLL"))?
|
||||
.map_err(|_| Error::trap(anyhow::Error::msg("failed to take lock of STDIN_POLL")))?
|
||||
.poll(waitmode)?;
|
||||
for readsub in stdin_read_subs.into_iter() {
|
||||
match state {
|
||||
@@ -167,34 +166,36 @@ impl StdinPoll {
|
||||
// Clean up possibly unread result from previous poll.
|
||||
Ok(_) | Err(TryRecvError::Empty) => {}
|
||||
Err(TryRecvError::Disconnected) => {
|
||||
return Err(Error::trap("StdinPoll notify_rx channel closed"))
|
||||
return Err(Error::trap(anyhow::Error::msg(
|
||||
"StdinPoll notify_rx channel closed",
|
||||
)))
|
||||
}
|
||||
}
|
||||
|
||||
// Notify the worker thread to poll stdin
|
||||
self.request_tx
|
||||
.send(())
|
||||
.context("request_tx channel closed")?;
|
||||
.map_err(|_| Error::trap(anyhow::Error::msg("request_tx channel closed")))?;
|
||||
|
||||
// Wait for the worker thread to send a readiness notification
|
||||
match wait_mode {
|
||||
WaitMode::Timeout(timeout) => match self.notify_rx.recv_timeout(timeout) {
|
||||
Ok(r) => Ok(r),
|
||||
Err(RecvTimeoutError::Timeout) => Ok(PollState::TimedOut),
|
||||
Err(RecvTimeoutError::Disconnected) => {
|
||||
Err(Error::trap("StdinPoll notify_rx channel closed"))
|
||||
}
|
||||
Err(RecvTimeoutError::Disconnected) => Err(Error::trap(anyhow::Error::msg(
|
||||
"StdinPoll notify_rx channel closed",
|
||||
))),
|
||||
},
|
||||
WaitMode::Infinite => self
|
||||
.notify_rx
|
||||
.recv()
|
||||
.context("StdinPoll notify_rx channel closed"),
|
||||
.map_err(|_| Error::trap(anyhow::Error::msg("StdinPoll notify_rx channel closed"))),
|
||||
WaitMode::Immediate => match self.notify_rx.try_recv() {
|
||||
Ok(r) => Ok(r),
|
||||
Err(TryRecvError::Empty) => Ok(PollState::NotReady),
|
||||
Err(TryRecvError::Disconnected) => {
|
||||
Err(Error::trap("StdinPoll notify_rx channel closed"))
|
||||
}
|
||||
Err(TryRecvError::Disconnected) => Err(Error::trap(anyhow::Error::msg(
|
||||
"StdinPoll notify_rx channel closed",
|
||||
))),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -128,7 +128,9 @@ macro_rules! wasi_file_write_impl {
|
||||
}
|
||||
async fn write_vectored<'a>(&mut self, bufs: &[io::IoSlice<'a>]) -> Result<u64, Error> {
|
||||
let n = (&*self.0.as_filelike_view::<File>()).write_vectored(bufs)?;
|
||||
Ok(n.try_into().map_err(|c| Error::range().context(c))?)
|
||||
Ok(n.try_into().map_err(|_| {
|
||||
Error::range().context("converting write_vectored total length")
|
||||
})?)
|
||||
}
|
||||
async fn write_vectored_at<'a>(
|
||||
&mut self,
|
||||
|
||||
Reference in New Issue
Block a user