1 // SPDX-License-Identifier: GPL-2.0-or-later
2
3 //! Utility functions to convert `errno` to and from
4 //! [`io::Error`]/[`io::Result`]
5 //!
6 //! QEMU C functions often have a "positive success/negative `errno`" calling
7 //! convention. This module provides functions to portably convert an integer
8 //! into an [`io::Result`] and back.
9
10 use std::{convert::TryFrom, io, io::ErrorKind};
11
12 /// An `errno` value that can be converted into an [`io::Error`]
13 pub struct Errno(pub u16);
14
15 // On Unix, from_raw_os_error takes an errno value and OS errors
16 // are printed using strerror. On Windows however it takes a
17 // GetLastError() value; therefore we need to convert errno values
18 // into io::Error by hand. This is the same mapping that the
19 // standard library uses to retrieve the kind of OS errors
20 // (`std::sys::pal::unix::decode_error_kind`).
21 impl From<Errno> for ErrorKind {
from(value: Errno) -> ErrorKind22 fn from(value: Errno) -> ErrorKind {
23 use ErrorKind::*;
24 let Errno(errno) = value;
25 match i32::from(errno) {
26 libc::EPERM | libc::EACCES => PermissionDenied,
27 libc::ENOENT => NotFound,
28 libc::EINTR => Interrupted,
29 x if x == libc::EAGAIN || x == libc::EWOULDBLOCK => WouldBlock,
30 libc::ENOMEM => OutOfMemory,
31 libc::EEXIST => AlreadyExists,
32 libc::EINVAL => InvalidInput,
33 libc::EPIPE => BrokenPipe,
34 libc::EADDRINUSE => AddrInUse,
35 libc::EADDRNOTAVAIL => AddrNotAvailable,
36 libc::ECONNABORTED => ConnectionAborted,
37 libc::ECONNREFUSED => ConnectionRefused,
38 libc::ECONNRESET => ConnectionReset,
39 libc::ENOTCONN => NotConnected,
40 libc::ENOTSUP => Unsupported,
41 libc::ETIMEDOUT => TimedOut,
42 _ => Other,
43 }
44 }
45 }
46
47 // This is used on Windows for all io::Errors, but also on Unix if the
48 // io::Error does not have a raw OS error. This is the reversed
49 // mapping of the above; EIO is returned for unknown ErrorKinds.
50 impl From<io::ErrorKind> for Errno {
from(value: io::ErrorKind) -> Errno51 fn from(value: io::ErrorKind) -> Errno {
52 use ErrorKind::*;
53 let errno = match value {
54 // can be both EPERM or EACCES :( pick one
55 PermissionDenied => libc::EPERM,
56 NotFound => libc::ENOENT,
57 Interrupted => libc::EINTR,
58 WouldBlock => libc::EAGAIN,
59 OutOfMemory => libc::ENOMEM,
60 AlreadyExists => libc::EEXIST,
61 InvalidInput => libc::EINVAL,
62 BrokenPipe => libc::EPIPE,
63 AddrInUse => libc::EADDRINUSE,
64 AddrNotAvailable => libc::EADDRNOTAVAIL,
65 ConnectionAborted => libc::ECONNABORTED,
66 ConnectionRefused => libc::ECONNREFUSED,
67 ConnectionReset => libc::ECONNRESET,
68 NotConnected => libc::ENOTCONN,
69 Unsupported => libc::ENOTSUP,
70 TimedOut => libc::ETIMEDOUT,
71 _ => libc::EIO,
72 };
73 Errno(errno as u16)
74 }
75 }
76
77 impl From<Errno> for io::Error {
78 #[cfg(unix)]
from(value: Errno) -> io::Error79 fn from(value: Errno) -> io::Error {
80 let Errno(errno) = value;
81 io::Error::from_raw_os_error(errno.into())
82 }
83
84 #[cfg(windows)]
from(value: Errno) -> io::Error85 fn from(value: Errno) -> io::Error {
86 let error_kind: ErrorKind = value.into();
87 error_kind.into()
88 }
89 }
90
91 impl From<io::Error> for Errno {
from(value: io::Error) -> Errno92 fn from(value: io::Error) -> Errno {
93 if cfg!(unix) {
94 if let Some(errno) = value.raw_os_error() {
95 return Errno(u16::try_from(errno).unwrap());
96 }
97 }
98 value.kind().into()
99 }
100 }
101
102 /// Internal traits; used to enable [`into_io_result`] and [`into_neg_errno`]
103 /// for the "right" set of types.
104 mod traits {
105 use super::Errno;
106
107 /// A signed type that can be converted into an
108 /// [`io::Result`](std::io::Result)
109 pub trait GetErrno {
110 /// Unsigned variant of `Self`, used as the type for the `Ok` case.
111 type Out;
112
113 /// Return `Ok(self)` if positive, `Err(Errno(-self))` if negative
into_errno_result(self) -> Result<Self::Out, Errno>114 fn into_errno_result(self) -> Result<Self::Out, Errno>;
115 }
116
117 /// A type that can be taken out of an [`io::Result`](std::io::Result) and
118 /// converted into "positive success/negative `errno`" convention.
119 pub trait MergeErrno {
120 /// Signed variant of `Self`, used as the return type of
121 /// [`into_neg_errno`](super::into_neg_errno).
122 type Out: From<u16> + std::ops::Neg<Output = Self::Out>;
123
124 /// Return `self`, asserting that it is in range
map_ok(self) -> Self::Out125 fn map_ok(self) -> Self::Out;
126 }
127
128 macro_rules! get_errno {
129 ($t:ty, $out:ty) => {
130 impl GetErrno for $t {
131 type Out = $out;
132 fn into_errno_result(self) -> Result<Self::Out, Errno> {
133 match self {
134 0.. => Ok(self as $out),
135 -65535..=-1 => Err(Errno(-self as u16)),
136 _ => panic!("{self} is not a negative errno"),
137 }
138 }
139 }
140 };
141 }
142
143 get_errno!(i32, u32);
144 get_errno!(i64, u64);
145 get_errno!(isize, usize);
146
147 macro_rules! merge_errno {
148 ($t:ty, $out:ty) => {
149 impl MergeErrno for $t {
150 type Out = $out;
151 fn map_ok(self) -> Self::Out {
152 self.try_into().unwrap()
153 }
154 }
155 };
156 }
157
158 merge_errno!(u8, i32);
159 merge_errno!(u16, i32);
160 merge_errno!(u32, i32);
161 merge_errno!(u64, i64);
162
163 impl MergeErrno for () {
164 type Out = i32;
map_ok(self) -> i32165 fn map_ok(self) -> i32 {
166 0
167 }
168 }
169 }
170
171 use traits::{GetErrno, MergeErrno};
172
173 /// Convert an integer value into a [`io::Result`].
174 ///
175 /// Positive values are turned into an `Ok` result; negative values
176 /// are interpreted as negated `errno` and turned into an `Err`.
177 ///
178 /// ```
179 /// # use qemu_api::errno::into_io_result;
180 /// # use std::io::ErrorKind;
181 /// let ok = into_io_result(1i32).unwrap();
182 /// assert_eq!(ok, 1u32);
183 ///
184 /// let err = into_io_result(-1i32).unwrap_err(); // -EPERM
185 /// assert_eq!(err.kind(), ErrorKind::PermissionDenied);
186 /// ```
187 ///
188 /// # Panics
189 ///
190 /// Since the result is an unsigned integer, negative values must
191 /// be close to 0; values that are too far away are considered
192 /// likely overflows and will panic:
193 ///
194 /// ```should_panic
195 /// # use qemu_api::errno::into_io_result;
196 /// # #[allow(dead_code)]
197 /// let err = into_io_result(-0x1234_5678i32); // panic
198 /// ```
into_io_result<T: GetErrno>(value: T) -> io::Result<T::Out>199 pub fn into_io_result<T: GetErrno>(value: T) -> io::Result<T::Out> {
200 value.into_errno_result().map_err(Into::into)
201 }
202
203 /// Convert a [`Result`] into an integer value, using negative `errno`
204 /// values to report errors.
205 ///
206 /// ```
207 /// # use qemu_api::errno::into_neg_errno;
208 /// # use std::io::{self, ErrorKind};
209 /// let ok: io::Result<()> = Ok(());
210 /// assert_eq!(into_neg_errno(ok), 0);
211 ///
212 /// let err: io::Result<()> = Err(ErrorKind::InvalidInput.into());
213 /// assert_eq!(into_neg_errno(err), -22); // -EINVAL
214 /// ```
215 ///
216 /// Since this module also provides the ability to convert [`io::Error`]
217 /// to an `errno` value, [`io::Result`] is the most commonly used type
218 /// for the argument of this function:
219 ///
220 /// # Panics
221 ///
222 /// Since the result is a signed integer, integer `Ok` values must remain
223 /// positive:
224 ///
225 /// ```should_panic
226 /// # use qemu_api::errno::into_neg_errno;
227 /// # use std::io;
228 /// let err: io::Result<u32> = Ok(0x8899_AABB);
229 /// into_neg_errno(err) // panic
230 /// # ;
231 /// ```
into_neg_errno<T: MergeErrno, E: Into<Errno>>(value: Result<T, E>) -> T::Out232 pub fn into_neg_errno<T: MergeErrno, E: Into<Errno>>(value: Result<T, E>) -> T::Out {
233 match value {
234 Ok(x) => x.map_ok(),
235 Err(err) => -T::Out::from(err.into().0),
236 }
237 }
238
239 #[cfg(test)]
240 mod tests {
241 use std::io::ErrorKind;
242
243 use super::*;
244 use crate::assert_match;
245
246 #[test]
test_from_u8()247 pub fn test_from_u8() {
248 let ok: io::Result<_> = Ok(42u8);
249 assert_eq!(into_neg_errno(ok), 42);
250
251 let err: io::Result<u8> = Err(io::ErrorKind::PermissionDenied.into());
252 assert_eq!(into_neg_errno(err), -1);
253
254 if cfg!(unix) {
255 let os_err: io::Result<u8> = Err(io::Error::from_raw_os_error(10));
256 assert_eq!(into_neg_errno(os_err), -10);
257 }
258 }
259
260 #[test]
test_from_u16()261 pub fn test_from_u16() {
262 let ok: io::Result<_> = Ok(1234u16);
263 assert_eq!(into_neg_errno(ok), 1234);
264
265 let err: io::Result<u16> = Err(io::ErrorKind::PermissionDenied.into());
266 assert_eq!(into_neg_errno(err), -1);
267
268 if cfg!(unix) {
269 let os_err: io::Result<u16> = Err(io::Error::from_raw_os_error(10));
270 assert_eq!(into_neg_errno(os_err), -10);
271 }
272 }
273
274 #[test]
test_i32()275 pub fn test_i32() {
276 assert_match!(into_io_result(1234i32), Ok(1234));
277
278 let err = into_io_result(-1i32).unwrap_err();
279 #[cfg(unix)]
280 assert_match!(err.raw_os_error(), Some(1));
281 assert_match!(err.kind(), ErrorKind::PermissionDenied);
282 }
283
284 #[test]
test_from_u32()285 pub fn test_from_u32() {
286 let ok: io::Result<_> = Ok(1234u32);
287 assert_eq!(into_neg_errno(ok), 1234);
288
289 let err: io::Result<u32> = Err(io::ErrorKind::PermissionDenied.into());
290 assert_eq!(into_neg_errno(err), -1);
291
292 if cfg!(unix) {
293 let os_err: io::Result<u32> = Err(io::Error::from_raw_os_error(10));
294 assert_eq!(into_neg_errno(os_err), -10);
295 }
296 }
297
298 #[test]
test_i64()299 pub fn test_i64() {
300 assert_match!(into_io_result(1234i64), Ok(1234));
301
302 let err = into_io_result(-22i64).unwrap_err();
303 #[cfg(unix)]
304 assert_match!(err.raw_os_error(), Some(22));
305 assert_match!(err.kind(), ErrorKind::InvalidInput);
306 }
307
308 #[test]
test_from_u64()309 pub fn test_from_u64() {
310 let ok: io::Result<_> = Ok(1234u64);
311 assert_eq!(into_neg_errno(ok), 1234);
312
313 let err: io::Result<u64> = Err(io::ErrorKind::InvalidInput.into());
314 assert_eq!(into_neg_errno(err), -22);
315
316 if cfg!(unix) {
317 let os_err: io::Result<u64> = Err(io::Error::from_raw_os_error(6));
318 assert_eq!(into_neg_errno(os_err), -6);
319 }
320 }
321
322 #[test]
test_isize()323 pub fn test_isize() {
324 assert_match!(into_io_result(1234isize), Ok(1234));
325
326 let err = into_io_result(-4isize).unwrap_err();
327 #[cfg(unix)]
328 assert_match!(err.raw_os_error(), Some(4));
329 assert_match!(err.kind(), ErrorKind::Interrupted);
330 }
331
332 #[test]
test_from_unit()333 pub fn test_from_unit() {
334 let ok: io::Result<_> = Ok(());
335 assert_eq!(into_neg_errno(ok), 0);
336
337 let err: io::Result<()> = Err(io::ErrorKind::OutOfMemory.into());
338 assert_eq!(into_neg_errno(err), -12);
339
340 if cfg!(unix) {
341 let os_err: io::Result<()> = Err(io::Error::from_raw_os_error(2));
342 assert_eq!(into_neg_errno(os_err), -2);
343 }
344 }
345 }
346