use std::ffi::CStr;
use std::fmt;
pub type Result<T> = std::result::Result<T, Error>;
#[derive(Debug)]
pub enum Error {
Archive {
code: i32,
message: String,
errno: Option<i32>,
},
Utf8(std::str::Utf8Error),
Io(std::io::Error),
NullPointer,
InvalidArgument(String),
}
impl Error {
pub(crate) unsafe fn from_archive(archive: *mut libarchive2_sys::archive) -> Self {
unsafe {
let code = libarchive2_sys::archive_errno(archive);
let msg_ptr = libarchive2_sys::archive_error_string(archive);
let message = if msg_ptr.is_null() {
format!("Unknown error (code: {})", code)
} else {
CStr::from_ptr(msg_ptr).to_string_lossy().into_owned()
};
let errno = if code != 0 { Some(code) } else { None };
Error::Archive {
code,
message,
errno,
}
}
}
pub(crate) unsafe fn from_return_code(
ret: i32,
archive: *mut libarchive2_sys::archive,
) -> Result<i32> {
if ret < 0 {
Err(unsafe { Self::from_archive(archive) })
} else {
Ok(ret)
}
}
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Error::Archive {
code,
message,
errno,
} => {
write!(f, "libarchive error (code {}): {}", code, message)?;
if let Some(e) = errno {
write!(f, " [errno: {}]", e)?;
}
Ok(())
}
Error::Utf8(e) => write!(f, "UTF-8 conversion error: {}", e),
Error::Io(e) => write!(f, "I/O error: {}", e),
Error::NullPointer => write!(f, "Null pointer error"),
Error::InvalidArgument(msg) => write!(f, "Invalid argument: {}", msg),
}
}
}
impl std::error::Error for Error {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match self {
Error::Utf8(e) => Some(e),
Error::Io(e) => Some(e),
_ => None,
}
}
}
impl From<std::str::Utf8Error> for Error {
fn from(e: std::str::Utf8Error) -> Self {
Error::Utf8(e)
}
}
impl From<std::io::Error> for Error {
fn from(e: std::io::Error) -> Self {
Error::Io(e)
}
}