// Copyright 2019 Intel Corporation. All Rights Reserved. // // Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. // // Portions Copyright 2017 The Chromium OS Authors. All rights reserved. // // SPDX-License-Identifier: BSD-3-Clause //! Structures, helpers, and type definitions for working with //! [`errno`](http://man7.org/linux/man-pages/man3/errno.3.html). use std::fmt::{Display, Formatter}; use std::io; use std::result; /// Wrapper over [`errno`](http://man7.org/linux/man-pages/man3/errno.3.html). /// /// The error number is an integer number set by system calls and some libc /// functions in case of error. #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub struct Error(i32); /// A specialized [Result](https://doc.rust-lang.org/std/result/enum.Result.html) type /// for operations that can return `errno`. /// /// This typedef is generally used to avoid writing out `errno::Error` directly and is /// otherwise a direct mapping to `Result`. pub type Result = result::Result; impl Error { /// Creates a new error from the given error number. /// /// # Arguments /// /// * `errno`: error number used for creating the `Error`. /// /// # Examples /// /// ``` /// # extern crate libc; /// extern crate vmm_sys_util; /// # /// # use libc; /// use vmm_sys_util::errno::Error; /// /// let err = Error::new(libc::EIO); /// ``` pub fn new(errno: i32) -> Error { Error(errno) } /// Returns the last occurred `errno` wrapped in an `Error`. /// /// Calling `Error::last()` is the equivalent of using /// [`errno`](http://man7.org/linux/man-pages/man3/errno.3.html) in C/C++. /// The result of this function only has meaning after a libc call or syscall /// where `errno` was set. /// /// # Examples /// /// ``` /// # extern crate libc; /// extern crate vmm_sys_util; /// # /// # use libc; /// # use std::fs::File; /// # use std::io::{self, Read}; /// # use std::env::temp_dir; /// use vmm_sys_util::errno::Error; /// # /// // Reading from a file without permissions returns an error. /// let mut path = temp_dir(); /// path.push("test"); /// let mut file = File::create(path).unwrap(); /// let mut buf: Vec = Vec::new(); /// assert!(file.read_to_end(&mut buf).is_err()); /// /// // Retrieve the error number of the previous operation using `Error::last()`: /// let read_err = Error::last(); /// #[cfg(unix)] /// assert_eq!(read_err, Error::new(libc::EBADF)); /// #[cfg(not(unix))] /// assert_eq!(read_err, Error::new(libc::EIO)); /// ``` pub fn last() -> Error { // It's safe to unwrap because this `Error` was constructed via `last_os_error`. Error(io::Error::last_os_error().raw_os_error().unwrap()) } /// Returns the raw integer value (`errno`) corresponding to this Error. /// /// # Examples /// ``` /// extern crate vmm_sys_util; /// use vmm_sys_util::errno::Error; /// /// let err = Error::new(13); /// assert_eq!(err.errno(), 13); /// ``` pub fn errno(self) -> i32 { self.0 } } impl Display for Error { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { io::Error::from_raw_os_error(self.0).fmt(f) } } impl std::error::Error for Error {} impl From for Error { fn from(e: io::Error) -> Self { Error::new(e.raw_os_error().unwrap_or_default()) } } impl From for io::Error { fn from(err: Error) -> io::Error { io::Error::from_raw_os_error(err.0) } } /// Returns the last `errno` as a [`Result`] that is always an error. /// /// [`Result`]: type.Result.html pub fn errno_result() -> Result { Err(Error::last()) } #[cfg(test)] mod tests { use super::*; use crate::tempfile::TempFile; use std::error::Error as _; use std::fs::OpenOptions; use std::io::{self, Read}; #[test] pub fn test_errno() { #[cfg(unix)] let expected_errno = libc::EBADF; #[cfg(not(unix))] let expected_errno = libc::EIO; // try to read from a file without read permissions let temp_file = TempFile::new().unwrap(); let path = temp_file.as_path().to_owned(); // Drop temp_file so we can cleanly reuse path below. std::mem::drop(temp_file); let mut file = OpenOptions::new() .read(false) .write(true) .create(true) .truncate(true) .open(&path) .unwrap(); let mut buf: Vec = Vec::new(); assert!(file.read_to_end(&mut buf).is_err()); // Test that errno_result returns Err and the error is the expected one. let last_err = errno_result::().unwrap_err(); assert_eq!(last_err, Error::new(expected_errno)); // Test that the inner value of `Error` corresponds to expected_errno. assert_eq!(last_err.errno(), expected_errno); assert!(last_err.source().is_none()); // Test creating an `Error` from a `std::io::Error`. assert_eq!(last_err, Error::from(io::Error::last_os_error())); // Test that calling `last()` returns the same error as `errno_result()`. assert_eq!(last_err, Error::last()); let last_err: io::Error = last_err.into(); // Test creating a `std::io::Error` from an `Error` assert_eq!(io::Error::last_os_error().kind(), last_err.kind()); assert!(std::fs::remove_file(&path).is_ok()); } #[test] pub fn test_display() { // Test the display implementation. #[cfg(target_os = "linux")] assert_eq!( format!("{}", Error::new(libc::EBADF)), "Bad file descriptor (os error 9)" ); #[cfg(not(unix))] assert_eq!( format!("{}", Error::new(libc::EIO)), "Access is denied. (os error 5)" ); } }