1use core::fmt;
4
5#[derive(Debug)]
7pub enum Error {
8 InvalidBootSignature {
10 found: u16,
12 },
13 UnsupportedFatType(&'static str),
15 InvalidFsInfoSignature {
17 field: &'static str,
19 expected: u32,
21 found: u32,
23 },
24 InvalidShortFilename,
26 ClusterOutOfBounds {
28 cluster: u32,
30 max: u32,
32 },
33 BadCluster {
35 cluster: u32,
37 },
38 UnexpectedEndOfChain {
40 cluster: u32,
42 },
43 Io(hadris_io::Error),
45 IoContext {
51 op: &'static str,
53 sector: Option<u64>,
55 source: hadris_io::Error,
57 },
58 CorruptFilesystem {
66 context: &'static str,
68 },
69 ClusterLoop {
73 cluster: u32,
75 },
76 NotAFile,
78 NotADirectory,
80 EntryNotFound,
82 InvalidPath,
84 #[cfg(feature = "write")]
86 NoFreeSpace,
87 #[cfg(feature = "write")]
89 DirectoryFull,
90 #[cfg(feature = "write")]
92 InvalidFilename,
93 #[cfg(feature = "write")]
95 AlreadyExists,
96 #[cfg(feature = "write")]
98 DirectoryNotEmpty,
99
100 #[cfg(feature = "write")]
105 InvalidAttributeChange {
106 bit: &'static str,
108 },
109
110 #[cfg(feature = "cache")]
116 CacheDirtyEviction {
117 sector: u32,
119 },
120
121 #[cfg(feature = "write")]
123 VolumeTooSmall {
124 size: u64,
126 min_size: u64,
128 },
129
130 #[cfg(feature = "write")]
132 VolumeTooLarge {
133 size: u64,
135 max_size: u64,
137 },
138
139 #[cfg(feature = "write")]
141 InvalidFormatOption {
142 option: &'static str,
144 reason: &'static str,
146 },
147
148 #[cfg(feature = "unstable-exfat")]
151 ExFatInvalidSignature {
152 expected: [u8; 8],
154 found: [u8; 8],
156 },
157 #[cfg(feature = "unstable-exfat")]
159 ExFatInvalidBootSector {
160 reason: &'static str,
162 },
163 #[cfg(feature = "unstable-exfat")]
165 ExFatInvalidChecksum {
166 expected: u32,
168 found: u32,
170 },
171 #[cfg(feature = "unstable-exfat")]
173 ExFatInvalidEntry {
174 reason: &'static str,
176 },
177}
178
179impl fmt::Display for Error {
180 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
181 match self {
182 Self::InvalidBootSignature { found } => {
183 write!(
184 f,
185 "invalid boot signature: expected 0xAA55, found {found:#06x}"
186 )
187 }
188 Self::UnsupportedFatType(ty) => {
189 write!(f, "unsupported FAT type: {ty}")
190 }
191 Self::InvalidFsInfoSignature {
192 field,
193 expected,
194 found,
195 } => {
196 write!(
197 f,
198 "invalid FSInfo signature: {field} expected {expected:#010x}, found {found:#010x}"
199 )
200 }
201 Self::InvalidShortFilename => {
202 write!(f, "invalid short filename")
203 }
204 Self::ClusterOutOfBounds { cluster, max } => {
205 write!(f, "cluster {cluster} out of bounds (max: {max})")
206 }
207 Self::BadCluster { cluster } => {
208 write!(f, "bad cluster marker encountered at cluster {cluster}")
209 }
210 Self::UnexpectedEndOfChain { cluster } => {
211 write!(f, "unexpected end of cluster chain at cluster {cluster}")
212 }
213 Self::Io(e) => {
214 write!(f, "I/O error: {e:?}")
215 }
216 Self::IoContext { op, sector, source } => match sector {
217 Some(s) => write!(f, "I/O error reading {op} (sector {s}): {source:?}"),
218 None => write!(f, "I/O error reading {op}: {source:?}"),
219 },
220 Self::CorruptFilesystem { context } => {
221 write!(f, "corrupt filesystem: {context}")
222 }
223 Self::ClusterLoop { cluster } => {
224 write!(f, "cluster chain loop detected at cluster {cluster}")
225 }
226 Self::NotAFile => {
227 write!(f, "entry is not a file")
228 }
229 Self::NotADirectory => {
230 write!(f, "entry is not a directory")
231 }
232 Self::EntryNotFound => {
233 write!(f, "entry not found in directory")
234 }
235 Self::InvalidPath => {
236 write!(f, "path is invalid (empty or malformed)")
237 }
238 #[cfg(feature = "write")]
239 Self::NoFreeSpace => {
240 write!(f, "no free clusters available")
241 }
242 #[cfg(feature = "write")]
243 Self::DirectoryFull => {
244 write!(f, "directory is full (no free entry slots)")
245 }
246 #[cfg(feature = "write")]
247 Self::InvalidFilename => {
248 write!(f, "filename is invalid or too long")
249 }
250 #[cfg(feature = "write")]
251 Self::AlreadyExists => {
252 write!(f, "entry with this name already exists")
253 }
254 #[cfg(feature = "write")]
255 Self::DirectoryNotEmpty => {
256 write!(f, "cannot delete non-empty directory")
257 }
258 #[cfg(feature = "write")]
259 Self::InvalidAttributeChange { bit } => {
260 write!(f, "cannot change immutable attribute bit `{bit}` in place")
261 }
262 #[cfg(feature = "cache")]
263 Self::CacheDirtyEviction { sector } => {
264 write!(
265 f,
266 "FAT cache is full and every sector is dirty (sector {sector}); call flush() before continuing"
267 )
268 }
269 #[cfg(feature = "write")]
270 Self::VolumeTooSmall { size, min_size } => {
271 write!(
272 f,
273 "volume size {size} bytes is too small (minimum: {min_size} bytes)"
274 )
275 }
276 #[cfg(feature = "write")]
277 Self::VolumeTooLarge { size, max_size } => {
278 write!(
279 f,
280 "volume size {size} bytes is too large (maximum: {max_size} bytes)"
281 )
282 }
283 #[cfg(feature = "write")]
284 Self::InvalidFormatOption { option, reason } => {
285 write!(f, "invalid format option '{option}': {reason}")
286 }
287 #[cfg(feature = "unstable-exfat")]
288 Self::ExFatInvalidSignature { expected, found } => {
289 write!(
290 f,
291 "invalid exFAT signature: expected {:?}, found {:?}",
292 core::str::from_utf8(expected).unwrap_or("<invalid>"),
293 core::str::from_utf8(found).unwrap_or("<invalid>")
294 )
295 }
296 #[cfg(feature = "unstable-exfat")]
297 Self::ExFatInvalidBootSector { reason } => {
298 write!(f, "invalid exFAT boot sector: {reason}")
299 }
300 #[cfg(feature = "unstable-exfat")]
301 Self::ExFatInvalidChecksum { expected, found } => {
302 write!(
303 f,
304 "invalid exFAT checksum: expected {expected:#010x}, found {found:#010x}"
305 )
306 }
307 #[cfg(feature = "unstable-exfat")]
308 Self::ExFatInvalidEntry { reason } => {
309 write!(f, "invalid exFAT directory entry: {reason}")
310 }
311 }
312 }
313}
314
315#[cfg(feature = "std")]
316impl std::error::Error for Error {}
317
318impl<E: hadris_io::IoError> From<hadris_io::Error<E>> for Error {
319 fn from(e: hadris_io::Error<E>) -> Self {
320 Self::Io(e.erase())
321 }
322}
323
324#[cfg(feature = "defmt")]
328impl defmt::Format for Error {
329 fn format(&self, f: defmt::Formatter) {
330 match self {
331 Self::InvalidBootSignature { found } => {
332 defmt::write!(
333 f,
334 "invalid boot signature: expected 0xAA55, found {=u16:#06x}",
335 *found
336 )
337 }
338 Self::UnsupportedFatType(ty) => defmt::write!(f, "unsupported FAT type: {=str}", *ty),
339 Self::InvalidFsInfoSignature {
340 field,
341 expected,
342 found,
343 } => defmt::write!(
344 f,
345 "invalid FSInfo signature: {=str} expected {=u32:#010x}, found {=u32:#010x}",
346 *field,
347 *expected,
348 *found
349 ),
350 Self::InvalidShortFilename => defmt::write!(f, "invalid short filename"),
351 Self::ClusterOutOfBounds { cluster, max } => {
352 defmt::write!(
353 f,
354 "cluster {=u32} out of bounds (max: {=u32})",
355 *cluster,
356 *max
357 )
358 }
359 Self::BadCluster { cluster } => {
360 defmt::write!(f, "bad cluster marker at cluster {=u32}", *cluster)
361 }
362 Self::UnexpectedEndOfChain { cluster } => {
363 defmt::write!(f, "unexpected end of cluster chain at {=u32}", *cluster)
364 }
365 Self::Io(_) => defmt::write!(f, "I/O error"),
368 Self::IoContext { op, sector, .. } => match sector {
369 Some(s) => defmt::write!(f, "I/O error reading {=str} (sector {=u64})", *op, *s),
370 None => defmt::write!(f, "I/O error reading {=str}", *op),
371 },
372 Self::CorruptFilesystem { context } => {
373 defmt::write!(f, "corrupt filesystem: {=str}", *context)
374 }
375 Self::ClusterLoop { cluster } => {
376 defmt::write!(f, "cluster chain loop at {=u32}", *cluster)
377 }
378 Self::NotAFile => defmt::write!(f, "entry is not a file"),
379 Self::NotADirectory => defmt::write!(f, "entry is not a directory"),
380 Self::EntryNotFound => defmt::write!(f, "entry not found"),
381 Self::InvalidPath => defmt::write!(f, "path is invalid"),
382 #[cfg(feature = "write")]
383 Self::NoFreeSpace => defmt::write!(f, "no free clusters"),
384 #[cfg(feature = "write")]
385 Self::DirectoryFull => defmt::write!(f, "directory is full"),
386 #[cfg(feature = "write")]
387 Self::InvalidFilename => defmt::write!(f, "filename invalid or too long"),
388 #[cfg(feature = "write")]
389 Self::AlreadyExists => defmt::write!(f, "entry already exists"),
390 #[cfg(feature = "write")]
391 Self::DirectoryNotEmpty => defmt::write!(f, "directory not empty"),
392 #[cfg(feature = "write")]
393 Self::InvalidAttributeChange { bit } => {
394 defmt::write!(f, "cannot change immutable attribute bit `{=str}`", *bit)
395 }
396 #[cfg(feature = "cache")]
397 Self::CacheDirtyEviction { sector } => defmt::write!(
398 f,
399 "FAT cache full and every sector dirty (sector {=u32}); flush() needed",
400 *sector
401 ),
402 #[cfg(feature = "write")]
403 Self::VolumeTooSmall { size, min_size } => defmt::write!(
404 f,
405 "volume size {=u64} too small (min: {=u64})",
406 *size,
407 *min_size
408 ),
409 #[cfg(feature = "write")]
410 Self::VolumeTooLarge { size, max_size } => defmt::write!(
411 f,
412 "volume size {=u64} too large (max: {=u64})",
413 *size,
414 *max_size
415 ),
416 #[cfg(feature = "write")]
417 Self::InvalidFormatOption { option, reason } => {
418 defmt::write!(
419 f,
420 "invalid format option `{=str}`: {=str}",
421 *option,
422 *reason
423 )
424 }
425 #[cfg(feature = "unstable-exfat")]
426 Self::ExFatInvalidSignature { .. } => defmt::write!(f, "invalid exFAT signature"),
427 #[cfg(feature = "unstable-exfat")]
428 Self::ExFatInvalidBootSector { reason } => {
429 defmt::write!(f, "invalid exFAT boot sector: {=str}", *reason)
430 }
431 #[cfg(feature = "unstable-exfat")]
432 Self::ExFatInvalidChecksum { expected, found } => defmt::write!(
433 f,
434 "invalid exFAT checksum: expected {=u32:#010x}, found {=u32:#010x}",
435 *expected,
436 *found
437 ),
438 #[cfg(feature = "unstable-exfat")]
439 Self::ExFatInvalidEntry { reason } => {
440 defmt::write!(f, "invalid exFAT directory entry: {=str}", *reason)
441 }
442 }
443 }
444}
445
446pub type Result<T> = core::result::Result<T, Error>;