diff --git a/crates/wasi-c2/cap-std-sync/src/dir.rs b/crates/wasi-c2/cap-std-sync/src/dir.rs index 42c2b111cc..d4e357e6a7 100644 --- a/crates/wasi-c2/cap-std-sync/src/dir.rs +++ b/crates/wasi-c2/cap-std-sync/src/dir.rs @@ -6,7 +6,7 @@ use std::path::{Path, PathBuf}; use wasi_c2::{ dir::{ReaddirCursor, ReaddirEntity, WasiDir}, file::{FdFlags, FileCaps, FileType, Filestat, OFlags, WasiFile}, - Error, + Error, ErrorExt, }; pub struct Dir(cap_std::fs::Dir); @@ -118,7 +118,10 @@ impl WasiDir for Dir { let meta = entry.metadata()?; let inode = meta.ino(); let filetype = filetype_from(&meta.file_type()); - let name = entry.file_name().into_string().map_err(|_| Error::Ilseq)?; + let name = entry + .file_name() + .into_string() + .map_err(|_| Error::illegal_byte_sequence().context("filename"))?; let namelen = name.as_bytes().len().try_into()?; Ok((filetype, inode, namelen, name)) }), @@ -189,7 +192,7 @@ impl WasiDir for Dir { let dest_dir = dest_dir .as_any() .downcast_ref::() - .ok_or(Error::NotCapable)?; + .ok_or(Error::badf().context("failed downcast to cap-std Dir"))?; self.0 .rename(Path::new(src_path), &dest_dir.0, Path::new(dest_path))?; Ok(()) @@ -204,7 +207,7 @@ impl WasiDir for Dir { let target_dir = target_dir .as_any() .downcast_ref::() - .ok_or(Error::NotCapable)?; + .ok_or(Error::badf().context("failed downcast to cap-std Dir"))?; let src_path = Path::new(src_path); let target_path = Path::new(target_path); self.0.hard_link(src_path, &target_dir.0, target_path)?; diff --git a/crates/wasi-c2/cap-std-sync/src/file.rs b/crates/wasi-c2/cap-std-sync/src/file.rs index 00a43dd3eb..0089af7779 100644 --- a/crates/wasi-c2/cap-std-sync/src/file.rs +++ b/crates/wasi-c2/cap-std-sync/src/file.rs @@ -77,26 +77,26 @@ impl WasiFile for File { } fn read_vectored(&self, bufs: &mut [io::IoSliceMut]) -> Result { let n = self.0.read_vectored(bufs)?; - Ok(n.try_into().map_err(|_| Error::Overflow)?) + Ok(n.try_into()?) } fn read_vectored_at(&self, bufs: &mut [io::IoSliceMut], offset: u64) -> Result { let n = self.0.read_vectored_at(bufs, offset)?; - Ok(n.try_into().map_err(|_| Error::Overflow)?) + Ok(n.try_into()?) } fn write_vectored(&self, bufs: &[io::IoSlice]) -> Result { let n = self.0.write_vectored(bufs)?; - Ok(n.try_into().map_err(|_| Error::Overflow)?) + Ok(n.try_into()?) } fn write_vectored_at(&self, bufs: &[io::IoSlice], offset: u64) -> Result { let n = self.0.write_vectored_at(bufs, offset)?; - Ok(n.try_into().map_err(|_| Error::Overflow)?) + Ok(n.try_into()?) } fn seek(&self, pos: std::io::SeekFrom) -> Result { Ok(self.0.seek(pos)?) } fn peek(&self, buf: &mut [u8]) -> Result { let n = self.0.peek(buf)?; - Ok(n.try_into().map_err(|_| Error::Overflow)?) + Ok(n.try_into()?) } fn num_ready_bytes(&self) -> Result { Ok(self.0.num_ready_bytes()?) diff --git a/crates/wasi-c2/cap-std-sync/src/sched/unix.rs b/crates/wasi-c2/cap-std-sync/src/sched/unix.rs index 20c4c61ce7..24ce8b251f 100644 --- a/crates/wasi-c2/cap-std-sync/src/sched/unix.rs +++ b/crates/wasi-c2/cap-std-sync/src/sched/unix.rs @@ -8,7 +8,7 @@ use wasi_c2::{ subscription::{RwEventFlags, Subscription}, Poll, WasiSched, }, - Error, + Error, ErrorExt, }; use poll::{PollFd, PollFlags}; @@ -25,12 +25,16 @@ impl WasiSched for SyncSched { for s in poll.rw_subscriptions() { match s { Subscription::Read(f) => { - let raw_fd = wasi_file_raw_fd(f.file.deref()).ok_or(Error::Inval)?; + let raw_fd = wasi_file_raw_fd(f.file.deref()).ok_or( + Error::invalid_argument().context("read subscription fd downcast failed"), + )?; pollfds.push(unsafe { PollFd::new(raw_fd, PollFlags::POLLIN) }); } Subscription::Write(f) => { - let raw_fd = wasi_file_raw_fd(f.file.deref()).ok_or(Error::Inval)?; + let raw_fd = wasi_file_raw_fd(f.file.deref()).ok_or( + Error::invalid_argument().context("write subscription fd downcast failed"), + )?; pollfds.push(unsafe { PollFd::new(raw_fd, PollFlags::POLLOUT) }); } Subscription::MonotonicClock { .. } => unreachable!(), @@ -45,7 +49,7 @@ impl WasiSched for SyncSched { .unwrap_or(Duration::from_secs(0)); (duration.as_millis() + 1) // XXX try always rounding up? .try_into() - .map_err(|_| Error::Overflow)? + .map_err(|_| Error::overflow().context("poll timeout"))? } else { libc::c_int::max_value() }; @@ -78,9 +82,9 @@ impl WasiSched for SyncSched { _ => unreachable!(), }; if revents.contains(PollFlags::POLLNVAL) { - rwsub.error(Error::Badf); + rwsub.error(Error::badf()); } else if revents.contains(PollFlags::POLLERR) { - rwsub.error(Error::Io); + rwsub.error(Error::io()); } else if revents.contains(PollFlags::POLLHUP) { rwsub.complete(nbytes, RwEventFlags::HANGUP); } else { diff --git a/crates/wasi-c2/cap-std-sync/src/stdio.rs b/crates/wasi-c2/cap-std-sync/src/stdio.rs index 13026e5b70..935f37a4da 100644 --- a/crates/wasi-c2/cap-std-sync/src/stdio.rs +++ b/crates/wasi-c2/cap-std-sync/src/stdio.rs @@ -13,7 +13,7 @@ use std::os::windows::io::{AsRawHandle, RawHandle}; use unsafe_io::AsUnsafeFile; use wasi_c2::{ file::{FdFlags, FileType, Filestat, WasiFile}, - Error, + Error, ErrorExt, }; pub struct Stdin(std::io::Stdin); @@ -40,7 +40,7 @@ impl WasiFile for Stdin { Ok(FdFlags::empty()) } unsafe fn reopen_with_fdflags(&self, _fdflags: FdFlags) -> Result, Error> { - Err(Error::Badf) + Err(Error::badf()) } fn get_filestat(&self) -> Result { let meta = self.0.as_file_view().metadata()?; @@ -56,32 +56,32 @@ impl WasiFile for Stdin { }) } fn set_filestat_size(&self, _size: u64) -> Result<(), Error> { - Err(Error::Badf) + Err(Error::badf()) } fn advise(&self, _offset: u64, _len: u64, _advice: Advice) -> Result<(), Error> { - Err(Error::Badf) + Err(Error::badf()) } fn allocate(&self, _offset: u64, _len: u64) -> Result<(), Error> { - Err(Error::Badf) + Err(Error::badf()) } fn read_vectored(&self, bufs: &mut [io::IoSliceMut]) -> Result { let n = self.0.as_file_view().read_vectored(bufs)?; - Ok(n.try_into().map_err(|_| Error::Overflow)?) + Ok(n.try_into().map_err(|_| Error::range())?) } fn read_vectored_at(&self, _bufs: &mut [io::IoSliceMut], _offset: u64) -> Result { - Err(Error::Spipe) + Err(Error::seek_pipe()) } fn write_vectored(&self, _bufs: &[io::IoSlice]) -> Result { - Err(Error::Badf) + Err(Error::badf()) } fn write_vectored_at(&self, _bufs: &[io::IoSlice], _offset: u64) -> Result { - Err(Error::Badf) + Err(Error::badf()) } fn seek(&self, _pos: std::io::SeekFrom) -> Result { - Err(Error::Spipe) + Err(Error::seek_pipe()) } fn peek(&self, _buf: &mut [u8]) -> Result { - Err(Error::Spipe) + Err(Error::seek_pipe()) } fn set_times( &self, @@ -132,7 +132,7 @@ macro_rules! wasi_file_write_impl { &self, _fdflags: FdFlags, ) -> Result, Error> { - Err(Error::Badf) + Err(Error::badf()) } fn get_filestat(&self) -> Result { let meta = self.0.as_file_view().metadata()?; @@ -148,36 +148,36 @@ macro_rules! wasi_file_write_impl { }) } fn set_filestat_size(&self, _size: u64) -> Result<(), Error> { - Err(Error::Badf) + Err(Error::badf()) } fn advise(&self, _offset: u64, _len: u64, _advice: Advice) -> Result<(), Error> { - Err(Error::Badf) + Err(Error::badf()) } fn allocate(&self, _offset: u64, _len: u64) -> Result<(), Error> { - Err(Error::Badf) + Err(Error::badf()) } fn read_vectored(&self, _bufs: &mut [io::IoSliceMut]) -> Result { - Err(Error::Badf) + Err(Error::badf()) } fn read_vectored_at( &self, _bufs: &mut [io::IoSliceMut], _offset: u64, ) -> Result { - Err(Error::Badf) + Err(Error::badf()) } fn write_vectored(&self, bufs: &[io::IoSlice]) -> Result { let n = self.0.as_file_view().write_vectored(bufs)?; - Ok(n.try_into().map_err(|_| Error::Overflow)?) + Ok(n.try_into().map_err(|c| Error::range().context(c))?) } fn write_vectored_at(&self, _bufs: &[io::IoSlice], _offset: u64) -> Result { - Err(Error::Spipe) + Err(Error::seek_pipe()) } fn seek(&self, _pos: std::io::SeekFrom) -> Result { - Err(Error::Spipe) + Err(Error::seek_pipe()) } fn peek(&self, _buf: &mut [u8]) -> Result { - Err(Error::Badf) + Err(Error::badf()) } fn set_times( &self, diff --git a/crates/wasi-c2/src/error.rs b/crates/wasi-c2/src/error.rs index 9ff237ce6c..44bcab1795 100644 --- a/crates/wasi-c2/src/error.rs +++ b/crates/wasi-c2/src/error.rs @@ -21,6 +21,9 @@ pub enum ErrorKind { /// Errno::Inval: Invalid argument #[error("Inval: Invalid argument")] Inval, + /// Errno::Io: I/O error + #[error("Io: I/O error")] + Io, /// Errno::Nametoolong: Filename too long #[error("Nametoolong: Filename too long")] Nametoolong, @@ -50,6 +53,7 @@ pub trait ErrorExt { fn exist() -> Self; fn illegal_byte_sequence() -> Self; fn invalid_argument() -> Self; + fn io() -> Self; fn name_too_long() -> Self; fn not_dir() -> Self; fn not_supported() -> Self; @@ -75,6 +79,9 @@ impl ErrorExt for Error { fn invalid_argument() -> Self { ErrorKind::Inval.into() } + fn io() -> Self { + ErrorKind::Io.into() + } fn name_too_long() -> Self { ErrorKind::Nametoolong.into() } diff --git a/crates/wasi-c2/src/snapshots/preview_1.rs b/crates/wasi-c2/src/snapshots/preview_1.rs index 73f539de9a..ac698ff3b4 100644 --- a/crates/wasi-c2/src/snapshots/preview_1.rs +++ b/crates/wasi-c2/src/snapshots/preview_1.rs @@ -79,6 +79,7 @@ impl From for types::Errno { ErrorKind::Exist => Errno::Exist, ErrorKind::Ilseq => Errno::Ilseq, ErrorKind::Inval => Errno::Inval, + ErrorKind::Io => Errno::Io, ErrorKind::Nametoolong => Errno::Nametoolong, ErrorKind::Notdir => Errno::Notdir, ErrorKind::Notsup => Errno::Notsup, @@ -141,9 +142,15 @@ impl TryFrom for types::Errno { libc::EOVERFLOW => Ok(types::Errno::Overflow), libc::EILSEQ => Ok(types::Errno::Ilseq), libc::ENOTSUP => Ok(types::Errno::Notsup), - _ => Err(anyhow!(err).context("Unknown raw OS error")), + code => Err(anyhow!(err).context(format!("Unknown raw OS error: {}", code))), + }, + None => match err.kind() { + std::io::ErrorKind::NotFound => Ok(types::Errno::Noent), + std::io::ErrorKind::PermissionDenied => Ok(types::Errno::Perm), + std::io::ErrorKind::AlreadyExists => Ok(types::Errno::Exist), + std::io::ErrorKind::InvalidInput => Ok(types::Errno::Ilseq), + k => Err(anyhow!(err).context(format!("No raw OS error. Unhandled kind: {:?}", k))), }, - None => Err(anyhow!(err).context("No raw OS error")), } } }