use failure::Error;
use nix::errno::Errno;
use std::io;
use std::path::PathBuf;
#[derive(Debug, Fail)]
#[fail(display = "errno={}", errno)]
pub struct KernelError {
errno: Errno,
}
impl KernelError {
pub fn from_errno(errno: Errno) -> KernelError {
KernelError { errno }
}
pub fn errno_as_i32(&self) -> i32 {
self.errno as i32
}
}
impl From<io::Error> for KernelError {
fn from(e: io::Error) -> Self {
match e.raw_os_error() {
Some(errno) => KernelError::from_errno(Errno::from_i32(errno)),
None => {
warn!("Got io::Error without an errno; propagating as EIO: {}", e);
KernelError::from_errno(Errno::EIO)
},
}
}
}
impl From<nix::Error> for KernelError {
fn from(e: nix::Error) -> Self {
match e {
nix::Error::Sys(errno) => KernelError::from_errno(errno),
_ => {
warn!("Got nix::Error without an errno; propagating as EIO: {}", e);
KernelError::from_errno(Errno::EIO)
}
}
}
}
#[derive(Debug, Eq, Fail, PartialEq)]
pub enum MappingError {
#[fail(display = "path {:?} is not absolute", path)]
PathNotAbsolute {
path: PathBuf,
},
#[fail(display = "path {:?} is not normalized", path)]
PathNotNormalized {
path: PathBuf,
},
}
pub fn flatten_causes(err: &Error) -> String {
err.iter_chain().fold(String::new(), |flattened, cause| {
let flattened = if flattened.is_empty() {
flattened
} else {
flattened + ": "
};
flattened + &format!("{}", cause)
})
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn flatten_causes_one() {
let err = Error::from(format_err!("root cause"));
assert_eq!("root cause", flatten_causes(&err));
}
#[test]
fn flatten_causes_multiple() {
let err = Error::from(format_err!("root cause"));
let err = Error::from(err.context("intermediate"));
let err = Error::from(err.context("top"));
assert_eq!("top: intermediate: root cause", flatten_causes(&err));
}
}