1use thiserror::Error;
9
10#[derive(Debug, Clone, Copy, PartialEq, Eq)]
12pub enum CopyErrorKind {
13 SourceNotFound,
15 TargetNotFound,
17 Timeout,
19 Transient,
21 Permanent,
23 #[cfg(feature = "nfs-bypass")]
25 NfsTransient,
26 #[cfg(feature = "nfs-bypass")]
28 NfsBypassUnavailable,
29}
30
31#[derive(Error, Debug)]
33pub enum FxcpError {
34 #[error("Config: {0}")]
35 Config(String),
36 #[error("IO: {0}")]
37 Io(#[from] std::io::Error),
38 #[error("System: {0}")]
39 System(#[from] nix::Error),
40 #[error("Security: {0}")]
41 Security(String),
42 #[error("Encoding: {0}")]
43 Utf8(#[from] std::string::FromUtf8Error),
44 #[error("Join: {0}")]
45 Join(#[from] tokio::task::JoinError),
46 #[error("JSON: {0}")]
47 Json(#[from] serde_json::Error),
48 #[error("Versioning: {0}")]
49 Versioning(String),
50 #[error("CString Nul: {0}")]
51 Nul(#[from] std::ffi::NulError),
52 #[error("IOUring Push: {0}")]
53 IouPush(String),
54 #[error("Tracing Error ({correlation_id}): {message}")]
55 Traced {
56 correlation_id: u64,
57 message: String,
58 },
59 #[error("Memory Limit Exhausted: {0}")]
60 MemoryExhausted(String),
61 #[error("CAS Store: {0}")]
62 CasStoreError(String),
63 #[error("Manifest Corrupt: {0}")]
64 ManifestCorrupt(String),
65 #[error("Chunk Missing: {0}")]
66 ChunkMissing(String),
67 #[cfg(feature = "nfs-bypass")]
68 #[error("NFS: {0}")]
69 Nfs(#[from] crate::nfs::NfsError),
70}
71
72impl FxcpError {
73 pub fn copy_error_kind(&self) -> CopyErrorKind {
75 match self {
76 FxcpError::Io(io_err) => match io_err.kind() {
77 std::io::ErrorKind::NotFound => CopyErrorKind::TargetNotFound,
78 std::io::ErrorKind::PermissionDenied => CopyErrorKind::Permanent,
79 std::io::ErrorKind::TimedOut => CopyErrorKind::Timeout,
80 std::io::ErrorKind::WouldBlock | std::io::ErrorKind::Interrupted => CopyErrorKind::Transient,
81 _ => CopyErrorKind::Transient,
82 },
83 FxcpError::Security(_) => CopyErrorKind::Permanent,
84 FxcpError::ManifestCorrupt(_) => CopyErrorKind::Permanent,
85 #[cfg(feature = "nfs-bypass")]
86 FxcpError::Nfs(nfs_err) => match nfs_err {
87 crate::nfs::NfsError::StaleHandle { .. } => CopyErrorKind::NfsTransient,
88 crate::nfs::NfsError::Nfs4Error { code, .. } => {
89 use crate::nfs::rpc;
90 match *code {
91 rpc::NFS4ERR_STALE | rpc::NFS4ERR_DELAY | rpc::NFS4ERR_BADSESSION
92 | rpc::NFS4ERR_BADSEQ | rpc::NFS4ERR_SEQ_MISORDERED => CopyErrorKind::NfsTransient,
93 rpc::NFS4ERR_ACCESS => CopyErrorKind::Permanent,
94 _ => CopyErrorKind::Transient,
95 }
96 }
97 crate::nfs::NfsError::KerberosRequired => CopyErrorKind::NfsBypassUnavailable,
98 crate::nfs::NfsError::Timeout(_) => CopyErrorKind::Timeout,
99 _ => CopyErrorKind::Transient,
100 },
101 _ => CopyErrorKind::Transient,
102 }
103 }
104}
105
106impl From<io_uring::squeue::PushError> for FxcpError {
107 fn from(err: io_uring::squeue::PushError) -> Self {
108 FxcpError::IouPush(format!("{:?}", err))
109 }
110}
111
112pub type Result<T> = std::result::Result<T, FxcpError>;