blob: f2060d1cb1ac017cc94d4307baa6de4cbad0abfd [file] [log] [blame]
// Copyright (c) 2017 Baidu, Inc. All Rights Reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in
// the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Baidu, Inc., nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
use sgx_types::sgx_status_t;
use error;
use sys;
use core::fmt;
use core::result;
use core::convert::From;
use alloc::str;
use alloc::boxed::Box;
/// A specialized [`Result`](../result/enum.Result.html) type for I/O
/// operations.
///
/// This type is broadly used across `std::io` for any operation which may
/// produce an error.
///
/// This typedef is generally used to avoid writing out `io::Error` directly and
/// is otherwise a direct mapping to `Result`.
///
/// While usual Rust style is to import types directly, aliases of `Result`
/// often are not, to make it easier to distinguish between them. `Result` is
/// generally assumed to be `std::result::Result`, and so users of this alias
/// will generally use `io::Result` instead of shadowing the prelude's import
/// of `std::result::Result`.
///
pub type Result<T> = result::Result<T, Error>;
/// The error type for I/O operations of the `Read`, `Write`, `Seek`, and
/// associated traits.
///
/// Errors mostly originate from the underlying OS, but custom instances of
/// `Error` can be created with crafted error messages and a particular value of
/// [`ErrorKind`].
///
/// [`ErrorKind`]: enum.ErrorKind.html
#[derive(Debug)]
pub struct Error {
repr: Repr,
}
enum Repr {
Os(i32),
Simple(ErrorKind),
Custom(Box<Custom>),
SgxStatus(sgx_status_t),
}
#[derive(Debug)]
struct Custom {
kind: ErrorKind,
error: Box<error::Error+Send+Sync>,
}
/// A list specifying general categories of I/O error.
///
/// This list is intended to grow over time and it is not recommended to
/// exhaustively match against it.
///
/// It is used with the [`io::Error`] type.
///
/// [`io::Error`]: struct.Error.html
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[allow(deprecated)]
pub enum ErrorKind {
/// An entity was not found, often a file.
NotFound,
/// The operation lacked the necessary privileges to complete.
PermissionDenied,
/// The connection was refused by the remote server.
ConnectionRefused,
/// The connection was reset by the remote server.
ConnectionReset,
/// The connection was aborted (terminated) by the remote server.
ConnectionAborted,
/// The network operation failed because it was not connected yet.
NotConnected,
/// A socket address could not be bound because the address is already in
/// use elsewhere.
AddrInUse,
/// A nonexistent interface was requested or the requested address was not
/// local.
AddrNotAvailable,
/// The operation failed because a pipe was closed.
BrokenPipe,
/// An entity already exists, often a file.
AlreadyExists,
/// The operation needs to block to complete, but the blocking operation was
/// requested to not occur.
WouldBlock,
/// A parameter was incorrect.
InvalidInput,
/// Data not valid for the operation were encountered.
///
/// Unlike [`InvalidInput`], this typically means that the operation
/// parameters were valid, however the error was caused by malformed
/// input data.
///
/// For example, a function that reads a file into a string will error with
/// `InvalidData` if the file's contents are not valid UTF-8.
///
/// [`InvalidInput`]: #variant.InvalidInput
InvalidData,
/// The I/O operation's timeout expired, causing it to be canceled.
TimedOut,
/// An error returned when an operation could not be completed because a
/// call to [`write`] returned [`Ok(0)`].
///
/// This typically means that an operation could only succeed if it wrote a
/// particular number of bytes but only a smaller number of bytes could be
/// written.
///
/// [`write`]: ../../std/io/trait.Write.html#tymethod.write
/// [`Ok(0)`]: ../../std/io/type.Result.html
WriteZero,
/// This operation was interrupted.
///
/// Interrupted operations can typically be retried.
Interrupted,
/// Any I/O error not part of this list.
Other,
/// An error returned when an operation could not be completed because an
/// "end of file" was reached prematurely.
///
/// This typically means that an operation could only succeed if it read a
/// particular number of bytes but only a smaller number of bytes could be
/// read.
UnexpectedEof,
///
/// SGX error status
SgxError,
/// A marker variant that tells the compiler that users of this enum cannot
/// match it exhaustively.
#[doc(hidden)]
__Nonexhaustive,
}
impl ErrorKind {
fn as_str(&self) -> &'static str {
match *self {
ErrorKind::NotFound => "entity not found",
ErrorKind::PermissionDenied => "permission denied",
ErrorKind::ConnectionRefused => "connection refused",
ErrorKind::ConnectionReset => "connection reset",
ErrorKind::ConnectionAborted => "connection aborted",
ErrorKind::NotConnected => "not connected",
ErrorKind::AddrInUse => "address in use",
ErrorKind::AddrNotAvailable => "address not available",
ErrorKind::BrokenPipe => "broken pipe",
ErrorKind::AlreadyExists => "entity already exists",
ErrorKind::WouldBlock => "operation would block",
ErrorKind::InvalidInput => "invalid input parameter",
ErrorKind::InvalidData => "invalid data",
ErrorKind::TimedOut => "timed out",
ErrorKind::WriteZero => "write zero",
ErrorKind::Interrupted => "operation interrupted",
ErrorKind::Other => "other os error",
ErrorKind::UnexpectedEof => "unexpected end of file",
ErrorKind::SgxError => "Sgx error status",
ErrorKind::__Nonexhaustive => unreachable!()
}
}
}
/// Intended for use for errors not exposed to the user, where allocating onto
/// the heap (for normal construction via Error::new) is too costly.
impl From<ErrorKind> for Error {
#[inline]
fn from(kind: ErrorKind) -> Error {
Error {
repr: Repr::Simple(kind)
}
}
}
impl From<sgx_status_t> for Error {
#[inline]
fn from(status: sgx_status_t) -> Error {
Error {
repr: Repr::SgxStatus(status)
}
}
}
impl Error {
/// Creates a new I/O error from a known kind of error as well as an
/// arbitrary error payload.
///
/// This function is used to generically create I/O errors which do not
/// originate from the OS itself. The `error` argument is an arbitrary
/// payload which will be contained in this `Error`.
///
pub fn new<E>(kind: ErrorKind, error: E) -> Error
where E: Into<Box<error::Error+Send+Sync>>
{
Self::_new(kind, error.into())
}
fn _new(kind: ErrorKind, error: Box<error::Error+Send+Sync>) -> Error {
Error {
repr: Repr::Custom(Box::new(Custom {
kind: kind,
error: error,
}))
}
}
/// Returns an error representing the last OS error which occurred.
///
/// This function reads the value of `errno` for the target platform (e.g.
/// `GetLastError` on Windows) and will return a corresponding instance of
/// `Error` for the error code.
///
pub fn last_os_error() -> Error {
Error::from_raw_os_error(sys::os::errno() as i32)
}
/// Creates a new instance of an `Error` from a particular OS error code.
///
pub fn from_raw_os_error(code: i32) -> Error {
Error { repr: Repr::Os(code) }
}
/// Returns the OS error that this error represents (if any).
///
/// If this `Error` was constructed via `last_os_error` or
/// `from_raw_os_error`, then this function will return `Some`, otherwise
/// it will return `None`.
///
pub fn raw_os_error(&self) -> Option<i32> {
match self.repr {
Repr::Os(i) => Some(i),
Repr::Custom(..) => None,
Repr::Simple(..) => None,
Repr::SgxStatus(..) => None,
}
}
/// Creates a new instance of an `Error` from a particular SGX error status.
///
pub fn from_sgx_error(status: sgx_status_t) -> Error {
Error { repr: Repr::SgxStatus(status) }
}
/// Returns the SGX error that this error represents (if any).
///
/// If this `Error` was constructed via `from_sgx_error` or
/// then this function will return `Some`, otherwise
/// it will return `None`.
///
pub fn raw_sgx_error(&self) -> Option<sgx_status_t> {
match self.repr {
Repr::Os(..) => None,
Repr::Custom(..) => None,
Repr::Simple(..) => None,
Repr::SgxStatus(status) => Some(status),
}
}
/// Returns a reference to the inner error wrapped by this error (if any).
///
/// If this `Error` was constructed via `new` then this function will
/// return `Some`, otherwise it will return `None`.
///
pub fn get_ref(&self) -> Option<&(error::Error+Send+Sync+'static)> {
match self.repr {
Repr::Os(..) => None,
Repr::Simple(..) => None,
Repr::Custom(ref c) => Some(&*c.error),
Repr::SgxStatus(ref s) => Some(s),
}
}
/// Returns a mutable reference to the inner error wrapped by this error
/// (if any).
///
/// If this `Error` was constructed via `new` then this function will
/// return `Some`, otherwise it will return `None`.
///
pub fn get_mut(&mut self) -> Option<&mut (error::Error+Send+Sync+'static)> {
match self.repr {
Repr::Os(..) => None,
Repr::Simple(..) => None,
Repr::Custom(ref mut c) => Some(&mut *c.error),
Repr::SgxStatus(ref mut s) => Some(s),
}
}
/// Consumes the `Error`, returning its inner error (if any).
///
/// If this `Error` was constructed via `new` then this function will
/// return `Some`, otherwise it will return `None`.
///
pub fn into_inner(self) -> Option<Box<error::Error+Send+Sync>> {
match self.repr {
Repr::Os(..) => None,
Repr::Simple(..) => None,
Repr::Custom(c) => Some(c.error),
Repr::SgxStatus(s) => Some(Box::new(s)),
}
}
/// Returns the corresponding `ErrorKind` for this error.
///
pub fn kind(&self) -> ErrorKind {
match self.repr {
Repr::Os(code) => sys::decode_error_kind(code),
Repr::Custom(ref c) => c.kind,
Repr::Simple(kind) => kind,
Repr::SgxStatus(..) => ErrorKind::SgxError,
}
}
}
impl fmt::Debug for Repr {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
match *self {
Repr::Os(ref code) =>
fmt.debug_struct("Os").field("code", code)
.field("message", &sys::os::error_string(*code)).finish(),
Repr::Custom(ref c) => fmt.debug_tuple("Custom").field(c).finish(),
Repr::Simple(kind) => fmt.debug_tuple("Kind").field(&kind).finish(),
Repr::SgxStatus(status) => fmt.debug_tuple("Sgx").field(&status).finish(),
}
}
}
impl fmt::Display for Error {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
match self.repr {
Repr::Os(code) => {
let detail = sys::os::error_string(code);
write!(fmt, "{} (os error {})", detail, code)
}
Repr::Custom(ref c) => c.error.fmt(fmt),
Repr::Simple(kind) => write!(fmt, "{}", kind.as_str()),
Repr::SgxStatus(status) => write!(fmt, "{}", status.as_str()),
}
}
}
impl error::Error for Error {
fn description(&self) -> &str {
match self.repr {
Repr::Os(..) | Repr::Simple(..) => self.kind().as_str(),
Repr::Custom(ref c) => c.error.description(),
Repr::SgxStatus(ref s) => s.description(),
}
}
fn cause(&self) -> Option<&error::Error> {
match self.repr {
Repr::Os(..) => None,
Repr::Simple(..) => None,
Repr::Custom(ref c) => c.error.cause(),
Repr::SgxStatus(ref s) => Some(s),
}
}
}
fn _assert_error_is_sync_send() {
fn _is_sync_send<T: Sync+Send>() {}
_is_sync_send::<Error>();
}
impl error::Error for sgx_status_t {
fn description(&self) -> &str {
self.__description()
}
}