use std::ffi::NulError;
use thiserror::Error;
#[derive(Debug, Error)]
pub enum Error {
#[error("I/O error: {0}")]
Io(#[from] std::io::Error),
#[error("not found: {0}")]
NotFound(String),
#[error("already exists: {0}")]
AlreadyExists(String),
#[error("not a directory: {0}")]
NotADirectory(String),
#[error("is a directory: {0}")]
IsADirectory(String),
#[error("directory not empty: {0}")]
NotEmpty(String),
#[error("permission denied")]
PermissionDenied,
#[error("no space left on device")]
NoSpace,
#[error("read-only filesystem")]
ReadOnly,
#[error("invalid argument: {0}")]
InvalidArgument(String),
#[error("path contains null byte")]
NulError(#[from] NulError),
#[error("filesystem error: {0}")]
Filesystem(i32),
#[error("device not found")]
DeviceNotFound,
#[error("mount point not found")]
MountPointNotFound,
#[error("name too long")]
NameTooLong,
#[error("too many open files")]
TooManyOpenFiles,
#[error("invalid filesystem")]
InvalidFilesystem,
}
pub type Result<T> = std::result::Result<T, Error>;
impl From<i32> for Error {
fn from(errno: i32) -> Self {
match errno {
0 => panic!("attempted to convert success (0) to error"),
libc::ENOENT => Error::NotFound(String::new()),
libc::EEXIST => Error::AlreadyExists(String::new()),
libc::ENOTDIR => Error::NotADirectory(String::new()),
libc::EISDIR => Error::IsADirectory(String::new()),
libc::ENOTEMPTY => Error::NotEmpty(String::new()),
libc::EACCES | libc::EPERM => Error::PermissionDenied,
libc::ENOSPC => Error::NoSpace,
libc::EROFS => Error::ReadOnly,
libc::EINVAL => Error::InvalidArgument(String::new()),
libc::ENXIO | libc::ENODEV => Error::DeviceNotFound,
libc::ENAMETOOLONG => Error::NameTooLong,
libc::EMFILE | libc::ENFILE => Error::TooManyOpenFiles,
_ => Error::Filesystem(errno),
}
}
}
pub(crate) fn check_errno(errno: i32) -> Result<()> {
if errno == 0 {
Ok(())
} else {
Err(Error::from(errno))
}
}
pub(crate) fn check_errno_with_path(errno: i32, path: &str) -> Result<()> {
if errno == 0 {
Ok(())
} else {
let err = match errno {
libc::ENOENT => Error::NotFound(path.to_string()),
libc::EEXIST => Error::AlreadyExists(path.to_string()),
libc::ENOTDIR => Error::NotADirectory(path.to_string()),
libc::EISDIR => Error::IsADirectory(path.to_string()),
libc::ENOTEMPTY => Error::NotEmpty(path.to_string()),
_ => Error::from(errno),
};
Err(err)
}
}