1use objects::error::HeddleError;
9
10pub type Result<T> = std::result::Result<T, MountError>;
12
13#[derive(Debug, thiserror::Error)]
15pub enum MountError {
16 #[error("not found: {0}")]
18 NotFound(String),
19
20 #[error("stale node: {0}")]
23 Stale(String),
24
25 #[error("not a directory: {0}")]
27 NotADirectory(String),
28
29 #[error("thread {0} has no current state")]
31 UnknownThread(String),
32
33 #[error("read-only filesystem")]
35 ReadOnly,
36
37 #[error("already exists: {0}")]
43 AlreadyExists(String),
44
45 #[error("is a directory: {0}")]
49 IsADirectory(String),
50
51 #[error("directory not empty: {0}")]
55 NotEmpty(String),
56
57 #[error("invalid argument: {0}")]
60 InvalidArgument(String),
61
62 #[error("file too large: {0}")]
65 FileTooLarge(String),
66
67 #[error("mount session initialization failed: {0}")]
72 SessionInit(String),
73
74 #[error(transparent)]
76 Store(#[from] HeddleError),
77}
78
79impl MountError {
80 pub fn to_errno(&self) -> i32 {
90 match self {
91 MountError::NotFound(_) | MountError::UnknownThread(_) => libc::ENOENT,
92 MountError::Stale(_) => stale_errno(),
93 MountError::NotADirectory(_) => libc::ENOTDIR,
94 MountError::ReadOnly => libc::EROFS,
95 MountError::AlreadyExists(_) => libc::EEXIST,
96 MountError::IsADirectory(_) => libc::EISDIR,
97 MountError::NotEmpty(_) => libc::ENOTEMPTY,
98 MountError::InvalidArgument(_) => libc::EINVAL,
99 MountError::FileTooLarge(_) => libc::EFBIG,
100 MountError::SessionInit(_) => libc::EIO,
101 MountError::Store(HeddleError::NotFound(_))
102 | MountError::Store(HeddleError::StateNotFound(_))
103 | MountError::Store(HeddleError::MissingObject { .. }) => libc::ENOENT,
104 MountError::Store(HeddleError::Io(io)) => io.raw_os_error().unwrap_or(libc::EIO),
105 MountError::Store(_) => libc::EIO,
106 }
107 }
108}
109
110#[cfg(unix)]
111#[inline]
112fn stale_errno() -> i32 {
113 libc::ESTALE
114}
115
116#[cfg(windows)]
121#[inline]
122fn stale_errno() -> i32 {
123 116
124}
125
126#[cfg(any(
134 all(target_os = "linux", feature = "fuse"),
135 all(target_os = "macos", feature = "fskit"),
136 all(target_os = "windows", feature = "projfs"),
137))]
138pub(crate) fn panic_payload_str(payload: &Box<dyn std::any::Any + Send>) -> String {
139 if let Some(s) = payload.downcast_ref::<&'static str>() {
140 (*s).to_string()
141 } else if let Some(s) = payload.downcast_ref::<String>() {
142 s.clone()
143 } else {
144 "<non-string panic payload>".to_string()
145 }
146}
147
148#[cfg(test)]
149mod tests {
150 use std::io;
151
152 use objects::error::HeddleError;
153
154 use super::*;
155
156 #[test]
157 fn to_errno_maps_every_mount_error_variant() {
158 assert_eq!(MountError::NotFound("x".into()).to_errno(), libc::ENOENT);
159 assert_eq!(
160 MountError::UnknownThread("t".into()).to_errno(),
161 libc::ENOENT
162 );
163 assert_eq!(MountError::Stale("s".into()).to_errno(), stale_errno());
164 assert_eq!(
165 MountError::NotADirectory("d".into()).to_errno(),
166 libc::ENOTDIR
167 );
168 assert_eq!(MountError::ReadOnly.to_errno(), libc::EROFS);
169 assert_eq!(
170 MountError::AlreadyExists("e".into()).to_errno(),
171 libc::EEXIST
172 );
173 assert_eq!(
174 MountError::IsADirectory("d".into()).to_errno(),
175 libc::EISDIR
176 );
177 assert_eq!(MountError::NotEmpty("d".into()).to_errno(), libc::ENOTEMPTY);
178 assert_eq!(
179 MountError::InvalidArgument("a".into()).to_errno(),
180 libc::EINVAL
181 );
182 assert_eq!(MountError::FileTooLarge("f".into()).to_errno(), libc::EFBIG);
183 assert_eq!(MountError::SessionInit("s".into()).to_errno(), libc::EIO);
184 assert_eq!(
185 MountError::Store(HeddleError::NotFound("o".into())).to_errno(),
186 libc::ENOENT
187 );
188 assert_eq!(
189 MountError::Store(HeddleError::StateNotFound(
190 objects::object::StateId::from_bytes([0xab; 32])
191 ))
192 .to_errno(),
193 libc::ENOENT
194 );
195 assert_eq!(
196 MountError::Store(HeddleError::MissingObject {
197 object_type: "blob".into(),
198 id: "deadbeef".into(),
199 })
200 .to_errno(),
201 libc::ENOENT
202 );
203 let io_err = io::Error::from_raw_os_error(libc::EACCES);
204 assert_eq!(
205 MountError::Store(HeddleError::Io(io_err)).to_errno(),
206 libc::EACCES
207 );
208 assert_eq!(
210 MountError::Store(HeddleError::InvalidObject("c".into())).to_errno(),
211 libc::EIO
212 );
213 }
214}