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 = "write")]
117 StaleEntry,
118
119 #[cfg(feature = "write")]
125 WriterConflict,
126
127 #[cfg(feature = "cache")]
133 CacheDirtyEviction {
134 sector: u32,
136 },
137
138 #[cfg(feature = "write")]
140 VolumeTooSmall {
141 size: u64,
143 min_size: u64,
145 },
146
147 #[cfg(feature = "write")]
149 VolumeTooLarge {
150 size: u64,
152 max_size: u64,
154 },
155
156 #[cfg(feature = "write")]
158 InvalidFormatOption {
159 option: &'static str,
161 reason: &'static str,
163 },
164
165 #[cfg(feature = "unstable-exfat")]
168 ExFatInvalidSignature {
169 expected: [u8; 8],
171 found: [u8; 8],
173 },
174 #[cfg(feature = "unstable-exfat")]
176 ExFatInvalidBootSector {
177 reason: &'static str,
179 },
180 #[cfg(feature = "unstable-exfat")]
182 ExFatInvalidChecksum {
183 expected: u32,
185 found: u32,
187 },
188 #[cfg(feature = "unstable-exfat")]
190 ExFatInvalidEntry {
191 reason: &'static str,
193 },
194}
195
196impl fmt::Display for Error {
197 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
198 match self {
199 Self::InvalidBootSignature { found } => {
200 write!(
201 f,
202 "invalid boot signature: expected 0xAA55, found {found:#06x}"
203 )
204 }
205 Self::UnsupportedFatType(ty) => {
206 write!(f, "unsupported FAT type: {ty}")
207 }
208 Self::InvalidFsInfoSignature {
209 field,
210 expected,
211 found,
212 } => {
213 write!(
214 f,
215 "invalid FSInfo signature: {field} expected {expected:#010x}, found {found:#010x}"
216 )
217 }
218 Self::InvalidShortFilename => {
219 write!(f, "invalid short filename")
220 }
221 Self::ClusterOutOfBounds { cluster, max } => {
222 write!(f, "cluster {cluster} out of bounds (max: {max})")
223 }
224 Self::BadCluster { cluster } => {
225 write!(f, "bad cluster marker encountered at cluster {cluster}")
226 }
227 Self::UnexpectedEndOfChain { cluster } => {
228 write!(f, "unexpected end of cluster chain at cluster {cluster}")
229 }
230 Self::Io(e) => {
231 write!(f, "I/O error: {e:?}")
232 }
233 Self::IoContext { op, sector, source } => match sector {
234 Some(s) => write!(f, "I/O error reading {op} (sector {s}): {source:?}"),
235 None => write!(f, "I/O error reading {op}: {source:?}"),
236 },
237 Self::CorruptFilesystem { context } => {
238 write!(f, "corrupt filesystem: {context}")
239 }
240 Self::ClusterLoop { cluster } => {
241 write!(f, "cluster chain loop detected at cluster {cluster}")
242 }
243 Self::NotAFile => {
244 write!(f, "entry is not a file")
245 }
246 Self::NotADirectory => {
247 write!(f, "entry is not a directory")
248 }
249 Self::EntryNotFound => {
250 write!(f, "entry not found in directory")
251 }
252 Self::InvalidPath => {
253 write!(f, "path is invalid (empty or malformed)")
254 }
255 #[cfg(feature = "write")]
256 Self::NoFreeSpace => {
257 write!(f, "no free clusters available")
258 }
259 #[cfg(feature = "write")]
260 Self::DirectoryFull => {
261 write!(f, "directory is full (no free entry slots)")
262 }
263 #[cfg(feature = "write")]
264 Self::InvalidFilename => {
265 write!(f, "filename is invalid or too long")
266 }
267 #[cfg(feature = "write")]
268 Self::AlreadyExists => {
269 write!(f, "entry with this name already exists")
270 }
271 #[cfg(feature = "write")]
272 Self::DirectoryNotEmpty => {
273 write!(f, "cannot delete non-empty directory")
274 }
275 #[cfg(feature = "write")]
276 Self::InvalidAttributeChange { bit } => {
277 write!(f, "cannot change immutable attribute bit `{bit}` in place")
278 }
279 #[cfg(feature = "write")]
280 Self::StaleEntry => {
281 write!(
282 f,
283 "directory entry handle is stale (its on-disk slot was deleted or reused)"
284 )
285 }
286 #[cfg(feature = "write")]
287 Self::WriterConflict => {
288 write!(f, "a FileWriter is already open for this directory entry")
289 }
290 #[cfg(feature = "cache")]
291 Self::CacheDirtyEviction { sector } => {
292 write!(
293 f,
294 "FAT cache is full and every sector is dirty (sector {sector}); call flush() before continuing"
295 )
296 }
297 #[cfg(feature = "write")]
298 Self::VolumeTooSmall { size, min_size } => {
299 write!(
300 f,
301 "volume size {size} bytes is too small (minimum: {min_size} bytes)"
302 )
303 }
304 #[cfg(feature = "write")]
305 Self::VolumeTooLarge { size, max_size } => {
306 write!(
307 f,
308 "volume size {size} bytes is too large (maximum: {max_size} bytes)"
309 )
310 }
311 #[cfg(feature = "write")]
312 Self::InvalidFormatOption { option, reason } => {
313 write!(f, "invalid format option '{option}': {reason}")
314 }
315 #[cfg(feature = "unstable-exfat")]
316 Self::ExFatInvalidSignature { expected, found } => {
317 write!(
318 f,
319 "invalid exFAT signature: expected {:?}, found {:?}",
320 core::str::from_utf8(expected).unwrap_or("<invalid>"),
321 core::str::from_utf8(found).unwrap_or("<invalid>")
322 )
323 }
324 #[cfg(feature = "unstable-exfat")]
325 Self::ExFatInvalidBootSector { reason } => {
326 write!(f, "invalid exFAT boot sector: {reason}")
327 }
328 #[cfg(feature = "unstable-exfat")]
329 Self::ExFatInvalidChecksum { expected, found } => {
330 write!(
331 f,
332 "invalid exFAT checksum: expected {expected:#010x}, found {found:#010x}"
333 )
334 }
335 #[cfg(feature = "unstable-exfat")]
336 Self::ExFatInvalidEntry { reason } => {
337 write!(f, "invalid exFAT directory entry: {reason}")
338 }
339 }
340 }
341}
342
343#[cfg(feature = "std")]
344impl std::error::Error for Error {}
345
346impl<E: hadris_io::IoError> From<hadris_io::Error<E>> for Error {
347 fn from(e: hadris_io::Error<E>) -> Self {
348 Self::Io(e.erase())
349 }
350}
351
352#[cfg(feature = "defmt")]
356impl defmt::Format for Error {
357 fn format(&self, f: defmt::Formatter) {
358 match self {
359 Self::InvalidBootSignature { found } => {
360 defmt::write!(
361 f,
362 "invalid boot signature: expected 0xAA55, found {=u16:#06x}",
363 *found
364 )
365 }
366 Self::UnsupportedFatType(ty) => defmt::write!(f, "unsupported FAT type: {=str}", *ty),
367 Self::InvalidFsInfoSignature {
368 field,
369 expected,
370 found,
371 } => defmt::write!(
372 f,
373 "invalid FSInfo signature: {=str} expected {=u32:#010x}, found {=u32:#010x}",
374 *field,
375 *expected,
376 *found
377 ),
378 Self::InvalidShortFilename => defmt::write!(f, "invalid short filename"),
379 Self::ClusterOutOfBounds { cluster, max } => {
380 defmt::write!(
381 f,
382 "cluster {=u32} out of bounds (max: {=u32})",
383 *cluster,
384 *max
385 )
386 }
387 Self::BadCluster { cluster } => {
388 defmt::write!(f, "bad cluster marker at cluster {=u32}", *cluster)
389 }
390 Self::UnexpectedEndOfChain { cluster } => {
391 defmt::write!(f, "unexpected end of cluster chain at {=u32}", *cluster)
392 }
393 Self::Io(_) => defmt::write!(f, "I/O error"),
396 Self::IoContext { op, sector, .. } => match sector {
397 Some(s) => defmt::write!(f, "I/O error reading {=str} (sector {=u64})", *op, *s),
398 None => defmt::write!(f, "I/O error reading {=str}", *op),
399 },
400 Self::CorruptFilesystem { context } => {
401 defmt::write!(f, "corrupt filesystem: {=str}", *context)
402 }
403 Self::ClusterLoop { cluster } => {
404 defmt::write!(f, "cluster chain loop at {=u32}", *cluster)
405 }
406 Self::NotAFile => defmt::write!(f, "entry is not a file"),
407 Self::NotADirectory => defmt::write!(f, "entry is not a directory"),
408 Self::EntryNotFound => defmt::write!(f, "entry not found"),
409 Self::InvalidPath => defmt::write!(f, "path is invalid"),
410 #[cfg(feature = "write")]
411 Self::NoFreeSpace => defmt::write!(f, "no free clusters"),
412 #[cfg(feature = "write")]
413 Self::DirectoryFull => defmt::write!(f, "directory is full"),
414 #[cfg(feature = "write")]
415 Self::InvalidFilename => defmt::write!(f, "filename invalid or too long"),
416 #[cfg(feature = "write")]
417 Self::AlreadyExists => defmt::write!(f, "entry already exists"),
418 #[cfg(feature = "write")]
419 Self::DirectoryNotEmpty => defmt::write!(f, "directory not empty"),
420 #[cfg(feature = "write")]
421 Self::InvalidAttributeChange { bit } => {
422 defmt::write!(f, "cannot change immutable attribute bit `{=str}`", *bit)
423 }
424 #[cfg(feature = "write")]
425 Self::StaleEntry => {
426 defmt::write!(f, "directory entry handle is stale (deleted or reused)")
427 }
428 #[cfg(feature = "write")]
429 Self::WriterConflict => {
430 defmt::write!(f, "a FileWriter is already open for this directory entry")
431 }
432 #[cfg(feature = "cache")]
433 Self::CacheDirtyEviction { sector } => defmt::write!(
434 f,
435 "FAT cache full and every sector dirty (sector {=u32}); flush() needed",
436 *sector
437 ),
438 #[cfg(feature = "write")]
439 Self::VolumeTooSmall { size, min_size } => defmt::write!(
440 f,
441 "volume size {=u64} too small (min: {=u64})",
442 *size,
443 *min_size
444 ),
445 #[cfg(feature = "write")]
446 Self::VolumeTooLarge { size, max_size } => defmt::write!(
447 f,
448 "volume size {=u64} too large (max: {=u64})",
449 *size,
450 *max_size
451 ),
452 #[cfg(feature = "write")]
453 Self::InvalidFormatOption { option, reason } => {
454 defmt::write!(
455 f,
456 "invalid format option `{=str}`: {=str}",
457 *option,
458 *reason
459 )
460 }
461 #[cfg(feature = "unstable-exfat")]
462 Self::ExFatInvalidSignature { .. } => defmt::write!(f, "invalid exFAT signature"),
463 #[cfg(feature = "unstable-exfat")]
464 Self::ExFatInvalidBootSector { reason } => {
465 defmt::write!(f, "invalid exFAT boot sector: {=str}", *reason)
466 }
467 #[cfg(feature = "unstable-exfat")]
468 Self::ExFatInvalidChecksum { expected, found } => defmt::write!(
469 f,
470 "invalid exFAT checksum: expected {=u32:#010x}, found {=u32:#010x}",
471 *expected,
472 *found
473 ),
474 #[cfg(feature = "unstable-exfat")]
475 Self::ExFatInvalidEntry { reason } => {
476 defmt::write!(f, "invalid exFAT directory entry: {=str}", *reason)
477 }
478 }
479 }
480}
481
482pub type Result<T> = core::result::Result<T, Error>;