use objects::error::HeddleError;
pub type Result<T> = std::result::Result<T, MountError>;
#[derive(Debug, thiserror::Error)]
pub enum MountError {
#[error("not found: {0}")]
NotFound(String),
#[error("stale node: {0}")]
Stale(String),
#[error("not a directory: {0}")]
NotADirectory(String),
#[error("thread {0} has no current state")]
UnknownThread(String),
#[error("read-only filesystem")]
ReadOnly,
#[error("already exists: {0}")]
AlreadyExists(String),
#[error("is a directory: {0}")]
IsADirectory(String),
#[error("directory not empty: {0}")]
NotEmpty(String),
#[error("invalid argument: {0}")]
InvalidArgument(String),
#[error("file too large: {0}")]
FileTooLarge(String),
#[error("mount session initialization failed: {0}")]
SessionInit(String),
#[error(transparent)]
Store(#[from] HeddleError),
}
impl MountError {
pub fn to_errno(&self) -> i32 {
match self {
MountError::NotFound(_) | MountError::UnknownThread(_) => libc::ENOENT,
MountError::Stale(_) => stale_errno(),
MountError::NotADirectory(_) => libc::ENOTDIR,
MountError::ReadOnly => libc::EROFS,
MountError::AlreadyExists(_) => libc::EEXIST,
MountError::IsADirectory(_) => libc::EISDIR,
MountError::NotEmpty(_) => libc::ENOTEMPTY,
MountError::InvalidArgument(_) => libc::EINVAL,
MountError::FileTooLarge(_) => libc::EFBIG,
MountError::SessionInit(_) => libc::EIO,
MountError::Store(HeddleError::NotFound(_))
| MountError::Store(HeddleError::StateNotFound(_))
| MountError::Store(HeddleError::MissingObject { .. }) => libc::ENOENT,
MountError::Store(HeddleError::Io(io)) => io.raw_os_error().unwrap_or(libc::EIO),
MountError::Store(_) => libc::EIO,
}
}
}
#[cfg(unix)]
#[inline]
fn stale_errno() -> i32 {
libc::ESTALE
}
#[cfg(windows)]
#[inline]
fn stale_errno() -> i32 {
116
}
#[cfg(any(
all(target_os = "linux", feature = "fuse"),
all(target_os = "macos", feature = "fskit"),
all(target_os = "windows", feature = "projfs"),
))]
pub(crate) fn panic_payload_str(payload: &Box<dyn std::any::Any + Send>) -> String {
if let Some(s) = payload.downcast_ref::<&'static str>() {
(*s).to_string()
} else if let Some(s) = payload.downcast_ref::<String>() {
s.clone()
} else {
"<non-string panic payload>".to_string()
}
}
#[cfg(test)]
mod tests {
use std::io;
use objects::error::HeddleError;
use super::*;
#[test]
fn to_errno_maps_every_mount_error_variant() {
assert_eq!(MountError::NotFound("x".into()).to_errno(), libc::ENOENT);
assert_eq!(
MountError::UnknownThread("t".into()).to_errno(),
libc::ENOENT
);
assert_eq!(MountError::Stale("s".into()).to_errno(), stale_errno());
assert_eq!(
MountError::NotADirectory("d".into()).to_errno(),
libc::ENOTDIR
);
assert_eq!(MountError::ReadOnly.to_errno(), libc::EROFS);
assert_eq!(
MountError::AlreadyExists("e".into()).to_errno(),
libc::EEXIST
);
assert_eq!(
MountError::IsADirectory("d".into()).to_errno(),
libc::EISDIR
);
assert_eq!(MountError::NotEmpty("d".into()).to_errno(), libc::ENOTEMPTY);
assert_eq!(
MountError::InvalidArgument("a".into()).to_errno(),
libc::EINVAL
);
assert_eq!(MountError::FileTooLarge("f".into()).to_errno(), libc::EFBIG);
assert_eq!(MountError::SessionInit("s".into()).to_errno(), libc::EIO);
assert_eq!(
MountError::Store(HeddleError::NotFound("o".into())).to_errno(),
libc::ENOENT
);
assert_eq!(
MountError::Store(HeddleError::StateNotFound(
objects::object::StateId::from_bytes([0xab; 32])
))
.to_errno(),
libc::ENOENT
);
assert_eq!(
MountError::Store(HeddleError::MissingObject {
object_type: "blob".into(),
id: "deadbeef".into(),
})
.to_errno(),
libc::ENOENT
);
let io_err = io::Error::from_raw_os_error(libc::EACCES);
assert_eq!(
MountError::Store(HeddleError::Io(io_err)).to_errno(),
libc::EACCES
);
assert_eq!(
MountError::Store(HeddleError::InvalidObject("c".into())).to_errno(),
libc::EIO
);
}
}