wasi_common/snapshots/preview_1/
error.rs

1pub use super::types::{Errno, Error};
2
3pub trait ErrorExt {
4    fn not_found() -> Self;
5    fn too_big() -> Self;
6    fn badf() -> Self;
7    fn exist() -> Self;
8    fn illegal_byte_sequence() -> Self;
9    fn invalid_argument() -> Self;
10    fn io() -> Self;
11    fn name_too_long() -> Self;
12    fn not_dir() -> Self;
13    fn not_supported() -> Self;
14    fn overflow() -> Self;
15    fn range() -> Self;
16    fn seek_pipe() -> Self;
17    fn perm() -> Self;
18}
19
20impl ErrorExt for Error {
21    fn not_found() -> Self {
22        Errno::Noent.into()
23    }
24    fn too_big() -> Self {
25        Errno::TooBig.into()
26    }
27    fn badf() -> Self {
28        Errno::Badf.into()
29    }
30    fn exist() -> Self {
31        Errno::Exist.into()
32    }
33    fn illegal_byte_sequence() -> Self {
34        Errno::Ilseq.into()
35    }
36    fn invalid_argument() -> Self {
37        Errno::Inval.into()
38    }
39    fn io() -> Self {
40        Errno::Io.into()
41    }
42    fn name_too_long() -> Self {
43        Errno::Nametoolong.into()
44    }
45    fn not_dir() -> Self {
46        Errno::Notdir.into()
47    }
48    fn not_supported() -> Self {
49        Errno::Notsup.into()
50    }
51    fn overflow() -> Self {
52        Errno::Overflow.into()
53    }
54    fn range() -> Self {
55        Errno::Range.into()
56    }
57    fn seek_pipe() -> Self {
58        Errno::Spipe.into()
59    }
60    fn perm() -> Self {
61        Errno::Perm.into()
62    }
63}
64
65#[cfg(unix)]
66fn from_raw_os_error(err: Option<i32>) -> Option<Error> {
67    use rustix::io::Errno as RustixErrno;
68    if err.is_none() {
69        return None;
70    }
71    Some(match RustixErrno::from_raw_os_error(err.unwrap()) {
72        RustixErrno::AGAIN => Errno::Again.into(),
73        RustixErrno::PIPE => Errno::Pipe.into(),
74        RustixErrno::PERM => Errno::Perm.into(),
75        RustixErrno::NOENT => Errno::Noent.into(),
76        RustixErrno::NOMEM => Errno::Nomem.into(),
77        RustixErrno::TOOBIG => Errno::TooBig.into(),
78        RustixErrno::IO => Errno::Io.into(),
79        RustixErrno::BADF => Errno::Badf.into(),
80        RustixErrno::BUSY => Errno::Busy.into(),
81        RustixErrno::ACCESS => Errno::Acces.into(),
82        RustixErrno::FAULT => Errno::Fault.into(),
83        RustixErrno::NOTDIR => Errno::Notdir.into(),
84        RustixErrno::ISDIR => Errno::Isdir.into(),
85        RustixErrno::INVAL => Errno::Inval.into(),
86        RustixErrno::EXIST => Errno::Exist.into(),
87        RustixErrno::FBIG => Errno::Fbig.into(),
88        RustixErrno::NOSPC => Errno::Nospc.into(),
89        RustixErrno::SPIPE => Errno::Spipe.into(),
90        RustixErrno::MFILE => Errno::Mfile.into(),
91        RustixErrno::MLINK => Errno::Mlink.into(),
92        RustixErrno::NAMETOOLONG => Errno::Nametoolong.into(),
93        RustixErrno::NFILE => Errno::Nfile.into(),
94        RustixErrno::NOTEMPTY => Errno::Notempty.into(),
95        RustixErrno::LOOP => Errno::Loop.into(),
96        RustixErrno::OVERFLOW => Errno::Overflow.into(),
97        RustixErrno::ILSEQ => Errno::Ilseq.into(),
98        RustixErrno::NOTSUP => Errno::Notsup.into(),
99        RustixErrno::ADDRINUSE => Errno::Addrinuse.into(),
100        RustixErrno::CANCELED => Errno::Canceled.into(),
101        RustixErrno::ADDRNOTAVAIL => Errno::Addrnotavail.into(),
102        RustixErrno::AFNOSUPPORT => Errno::Afnosupport.into(),
103        RustixErrno::ALREADY => Errno::Already.into(),
104        RustixErrno::CONNABORTED => Errno::Connaborted.into(),
105        RustixErrno::CONNREFUSED => Errno::Connrefused.into(),
106        RustixErrno::CONNRESET => Errno::Connreset.into(),
107        RustixErrno::DESTADDRREQ => Errno::Destaddrreq.into(),
108        RustixErrno::DQUOT => Errno::Dquot.into(),
109        RustixErrno::HOSTUNREACH => Errno::Hostunreach.into(),
110        RustixErrno::INPROGRESS => Errno::Inprogress.into(),
111        RustixErrno::INTR => Errno::Intr.into(),
112        RustixErrno::ISCONN => Errno::Isconn.into(),
113        RustixErrno::MSGSIZE => Errno::Msgsize.into(),
114        RustixErrno::NETDOWN => Errno::Netdown.into(),
115        RustixErrno::NETRESET => Errno::Netreset.into(),
116        RustixErrno::NETUNREACH => Errno::Netunreach.into(),
117        RustixErrno::NOBUFS => Errno::Nobufs.into(),
118        RustixErrno::NOPROTOOPT => Errno::Noprotoopt.into(),
119        RustixErrno::NOTCONN => Errno::Notconn.into(),
120        RustixErrno::NOTSOCK => Errno::Notsock.into(),
121        RustixErrno::PROTONOSUPPORT => Errno::Protonosupport.into(),
122        RustixErrno::PROTOTYPE => Errno::Prototype.into(),
123        RustixErrno::STALE => Errno::Stale.into(),
124        RustixErrno::TIMEDOUT => Errno::Timedout.into(),
125
126        // On some platforms.into(), these have the same value as other errno values.
127        #[allow(unreachable_patterns)]
128        RustixErrno::WOULDBLOCK => Errno::Again.into(),
129        #[allow(unreachable_patterns)]
130        RustixErrno::OPNOTSUPP => Errno::Notsup.into(),
131
132        _ => return None,
133    })
134}
135#[cfg(windows)]
136fn from_raw_os_error(raw_os_error: Option<i32>) -> Option<Error> {
137    use windows_sys::Win32::Foundation;
138    use windows_sys::Win32::Networking::WinSock;
139
140    match raw_os_error.map(|code| code as u32) {
141        Some(Foundation::ERROR_BAD_ENVIRONMENT) => return Some(Errno::TooBig.into()),
142        Some(Foundation::ERROR_FILE_NOT_FOUND) => return Some(Errno::Noent.into()),
143        Some(Foundation::ERROR_PATH_NOT_FOUND) => return Some(Errno::Noent.into()),
144        Some(Foundation::ERROR_TOO_MANY_OPEN_FILES) => return Some(Errno::Nfile.into()),
145        Some(Foundation::ERROR_ACCESS_DENIED) => return Some(Errno::Acces.into()),
146        Some(Foundation::ERROR_SHARING_VIOLATION) => return Some(Errno::Acces.into()),
147        Some(Foundation::ERROR_PRIVILEGE_NOT_HELD) => return Some(Errno::Perm.into()),
148        Some(Foundation::ERROR_INVALID_HANDLE) => return Some(Errno::Badf.into()),
149        Some(Foundation::ERROR_INVALID_NAME) => return Some(Errno::Noent.into()),
150        Some(Foundation::ERROR_NOT_ENOUGH_MEMORY) => return Some(Errno::Nomem.into()),
151        Some(Foundation::ERROR_OUTOFMEMORY) => return Some(Errno::Nomem.into()),
152        Some(Foundation::ERROR_DIR_NOT_EMPTY) => return Some(Errno::Notempty.into()),
153        Some(Foundation::ERROR_NOT_READY) => return Some(Errno::Busy.into()),
154        Some(Foundation::ERROR_BUSY) => return Some(Errno::Busy.into()),
155        Some(Foundation::ERROR_NOT_SUPPORTED) => return Some(Errno::Notsup.into()),
156        Some(Foundation::ERROR_FILE_EXISTS) => return Some(Errno::Exist.into()),
157        Some(Foundation::ERROR_BROKEN_PIPE) => return Some(Errno::Pipe.into()),
158        Some(Foundation::ERROR_BUFFER_OVERFLOW) => return Some(Errno::Nametoolong.into()),
159        Some(Foundation::ERROR_NOT_A_REPARSE_POINT) => return Some(Errno::Inval.into()),
160        Some(Foundation::ERROR_NEGATIVE_SEEK) => return Some(Errno::Inval.into()),
161        Some(Foundation::ERROR_DIRECTORY) => return Some(Errno::Notdir.into()),
162        Some(Foundation::ERROR_ALREADY_EXISTS) => return Some(Errno::Exist.into()),
163        Some(Foundation::ERROR_STOPPED_ON_SYMLINK) => return Some(Errno::Loop.into()),
164        Some(Foundation::ERROR_DIRECTORY_NOT_SUPPORTED) => return Some(Errno::Isdir.into()),
165        _ => {}
166    }
167
168    match raw_os_error {
169        Some(WinSock::WSAEWOULDBLOCK) => Some(Errno::Again.into()),
170        Some(WinSock::WSAECANCELLED) => Some(Errno::Canceled.into()),
171        Some(WinSock::WSA_E_CANCELLED) => Some(Errno::Canceled.into()),
172        Some(WinSock::WSAEBADF) => Some(Errno::Badf.into()),
173        Some(WinSock::WSAEFAULT) => Some(Errno::Fault.into()),
174        Some(WinSock::WSAEINVAL) => Some(Errno::Inval.into()),
175        Some(WinSock::WSAEMFILE) => Some(Errno::Mfile.into()),
176        Some(WinSock::WSAENAMETOOLONG) => Some(Errno::Nametoolong.into()),
177        Some(WinSock::WSAENOTEMPTY) => Some(Errno::Notempty.into()),
178        Some(WinSock::WSAELOOP) => Some(Errno::Loop.into()),
179        Some(WinSock::WSAEOPNOTSUPP) => Some(Errno::Notsup.into()),
180        Some(WinSock::WSAEADDRINUSE) => Some(Errno::Addrinuse.into()),
181        Some(WinSock::WSAEACCES) => Some(Errno::Acces.into()),
182        Some(WinSock::WSAEADDRNOTAVAIL) => Some(Errno::Addrnotavail.into()),
183        Some(WinSock::WSAEAFNOSUPPORT) => Some(Errno::Afnosupport.into()),
184        Some(WinSock::WSAEALREADY) => Some(Errno::Already.into()),
185        Some(WinSock::WSAECONNABORTED) => Some(Errno::Connaborted.into()),
186        Some(WinSock::WSAECONNREFUSED) => Some(Errno::Connrefused.into()),
187        Some(WinSock::WSAECONNRESET) => Some(Errno::Connreset.into()),
188        Some(WinSock::WSAEDESTADDRREQ) => Some(Errno::Destaddrreq.into()),
189        Some(WinSock::WSAEDQUOT) => Some(Errno::Dquot.into()),
190        Some(WinSock::WSAEHOSTUNREACH) => Some(Errno::Hostunreach.into()),
191        Some(WinSock::WSAEINPROGRESS) => Some(Errno::Inprogress.into()),
192        Some(WinSock::WSAEINTR) => Some(Errno::Intr.into()),
193        Some(WinSock::WSAEISCONN) => Some(Errno::Isconn.into()),
194        Some(WinSock::WSAEMSGSIZE) => Some(Errno::Msgsize.into()),
195        Some(WinSock::WSAENETDOWN) => Some(Errno::Netdown.into()),
196        Some(WinSock::WSAENETRESET) => Some(Errno::Netreset.into()),
197        Some(WinSock::WSAENETUNREACH) => Some(Errno::Netunreach.into()),
198        Some(WinSock::WSAENOBUFS) => Some(Errno::Nobufs.into()),
199        Some(WinSock::WSAENOPROTOOPT) => Some(Errno::Noprotoopt.into()),
200        Some(WinSock::WSAENOTCONN) => Some(Errno::Notconn.into()),
201        Some(WinSock::WSAENOTSOCK) => Some(Errno::Notsock.into()),
202        Some(WinSock::WSAEPROTONOSUPPORT) => Some(Errno::Protonosupport.into()),
203        Some(WinSock::WSAEPROTOTYPE) => Some(Errno::Prototype.into()),
204        Some(WinSock::WSAESTALE) => Some(Errno::Stale.into()),
205        Some(WinSock::WSAETIMEDOUT) => Some(Errno::Timedout.into()),
206        _ => None,
207    }
208}
209
210impl From<std::io::Error> for Error {
211    fn from(err: std::io::Error) -> Error {
212        match from_raw_os_error(err.raw_os_error()) {
213            Some(errno) => errno,
214            None => match err.kind() {
215                std::io::ErrorKind::NotFound => Errno::Noent.into(),
216                std::io::ErrorKind::PermissionDenied => Errno::Perm.into(),
217                std::io::ErrorKind::AlreadyExists => Errno::Exist.into(),
218                std::io::ErrorKind::InvalidInput => Errno::Inval.into(),
219                std::io::ErrorKind::WouldBlock => Errno::Again.into(),
220                _ => Error::trap(anyhow::anyhow!(err).context("Unknown OS error")),
221            },
222        }
223    }
224}
225
226impl From<cap_rand::Error> for Error {
227    fn from(err: cap_rand::Error) -> Error {
228        // I picked Error::Io as a 'reasonable default', FIXME dan is this ok?
229        from_raw_os_error(err.raw_os_error()).unwrap_or_else(|| Error::from(Errno::Io))
230    }
231}
232
233impl From<wiggle::GuestError> for Error {
234    fn from(err: wiggle::GuestError) -> Error {
235        use wiggle::GuestError::*;
236        match err {
237            InvalidFlagValue { .. } => Errno::Inval.into(),
238            InvalidEnumValue { .. } => Errno::Inval.into(),
239            // As per
240            // https://github.com/WebAssembly/wasi/blob/main/legacy/tools/witx-docs.md#pointers
241            //
242            // > If a misaligned pointer is passed to a function, the function
243            // > shall trap.
244            // >
245            // > If an out-of-bounds pointer is passed to a function and the
246            // > function needs to dereference it, the function shall trap.
247            //
248            // so this turns OOB and misalignment errors into traps.
249            PtrOverflow { .. } | PtrOutOfBounds { .. } | PtrNotAligned { .. } => {
250                Error::trap(err.into())
251            }
252            PtrBorrowed { .. } => Errno::Fault.into(),
253            InvalidUtf8 { .. } => Errno::Ilseq.into(),
254            TryFromIntError { .. } => Errno::Overflow.into(),
255            SliceLengthsDiffer { .. } => Errno::Fault.into(),
256            BorrowCheckerOutOfHandles { .. } => Errno::Fault.into(),
257            InFunc { err, .. } => Error::from(*err),
258        }
259    }
260}
261
262impl From<std::num::TryFromIntError> for Error {
263    fn from(_err: std::num::TryFromIntError) -> Error {
264        Errno::Overflow.into()
265    }
266}