use crate::error::ACLError::{IoError, ValidationError};
use acl_sys::{ACL_TYPE_ACCESS, ACL_TYPE_DEFAULT};
use std::error::Error;
use std::io::ErrorKind;
use std::{fmt, io};
pub(crate) const FLAG_WRITE: u32 = 0x4000_0000;
#[derive(Debug)]
#[allow(clippy::upper_case_acronyms)]
pub enum ACLError {
IoError(IoErrorDetail),
ValidationError(ValidationErrorDetail),
}
#[derive(Debug)]
pub struct IoErrorDetail {
err: io::Error,
flags: u32,
}
#[derive(Debug)]
pub struct ValidationErrorDetail {
_private: (),
}
impl Error for ACLError {
fn source(&self) -> Option<&(dyn Error + 'static)> {
match self {
ValidationError(..) => None,
IoError(IoErrorDetail { ref err, .. }) => Some(err),
}
}
}
impl fmt::Display for ACLError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
IoError(IoErrorDetail { flags, err }) => write!(
f,
"Error {} {}: {}",
op_display(*flags),
type_display(*flags),
err
),
ValidationError(_) => write!(f, "ACL failed validation"),
}
}
}
impl ACLError {
pub fn kind(&self) -> ErrorKind {
match self {
ValidationError(_) => ErrorKind::InvalidData,
IoError(IoErrorDetail { ref err, .. }) => err.kind(),
}
}
pub fn as_io_error(&self) -> Option<&io::Error> {
match self {
ValidationError(_) => None,
IoError(IoErrorDetail { ref err, .. }) => Some(err),
}
}
pub(crate) fn last_os_error(flags: u32) -> ACLError {
IoError(IoErrorDetail {
err: io::Error::last_os_error(),
flags,
})
}
pub(crate) fn validation_error() -> ACLError {
ValidationError(ValidationErrorDetail { _private: () })
}
}
pub(crate) fn op_display(flags: u32) -> &'static str {
if flags & FLAG_WRITE != 0 {
"writing"
} else {
"reading"
}
}
pub(crate) fn type_display(flags: u32) -> &'static str {
let flags = flags & !FLAG_WRITE;
match flags {
ACL_TYPE_ACCESS => "ACL",
ACL_TYPE_DEFAULT => "default ACL",
_ => panic!("Invalid flags"),
}
}