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