Skip to main content

hadris_fat/
error.rs

1//! Error types for the hadris-fat crate.
2
3use core::fmt;
4
5/// Errors that can occur when working with FAT file systems.
6#[derive(Debug)]
7pub enum FatError {
8    /// Invalid boot signature (expected 0xAA55)
9    InvalidBootSignature {
10        /// The signature that was found
11        found: u16,
12    },
13    /// Unsupported FAT type (FAT12/16 when FAT32 expected, or vice versa)
14    UnsupportedFatType(&'static str),
15    /// Invalid FSInfo signature
16    InvalidFsInfoSignature {
17        /// Which signature field failed validation
18        field: &'static str,
19        /// The expected signature value
20        expected: u32,
21        /// The actual signature value found
22        found: u32,
23    },
24    /// Invalid short filename (contains disallowed characters)
25    InvalidShortFilename,
26    /// Cluster number out of bounds
27    ClusterOutOfBounds {
28        /// The cluster number that was accessed
29        cluster: u32,
30        /// The maximum valid cluster number
31        max: u32,
32    },
33    /// Bad cluster marker encountered
34    BadCluster {
35        /// The cluster marked as bad
36        cluster: u32,
37    },
38    /// End of cluster chain reached unexpectedly
39    UnexpectedEndOfChain {
40        /// The last cluster in the chain
41        cluster: u32,
42    },
43    /// I/O error from the underlying storage
44    Io(hadris_io::Error),
45    /// File is not a regular file (e.g., is a directory)
46    NotAFile,
47    /// Entry is not a directory
48    NotADirectory,
49    /// Entry not found in directory
50    EntryNotFound,
51    /// Path is invalid (empty, malformed)
52    InvalidPath,
53    /// No free clusters available
54    #[cfg(feature = "write")]
55    NoFreeSpace,
56    /// Directory is full (no free entry slots)
57    #[cfg(feature = "write")]
58    DirectoryFull,
59    /// Filename is invalid or too long
60    #[cfg(feature = "write")]
61    InvalidFilename,
62    /// Entry with this name already exists
63    #[cfg(feature = "write")]
64    AlreadyExists,
65    /// Cannot delete non-empty directory
66    #[cfg(feature = "write")]
67    DirectoryNotEmpty,
68
69    /// Volume is too small for the requested format
70    #[cfg(feature = "write")]
71    VolumeTooSmall {
72        /// Requested volume size
73        size: u64,
74        /// Minimum required size
75        min_size: u64,
76    },
77
78    /// Volume is too large for the requested FAT type
79    #[cfg(feature = "write")]
80    VolumeTooLarge {
81        /// Requested volume size
82        size: u64,
83        /// Maximum supported size
84        max_size: u64,
85    },
86
87    /// Invalid format option
88    #[cfg(feature = "write")]
89    InvalidFormatOption {
90        /// The option that was invalid
91        option: &'static str,
92        /// The reason it was invalid
93        reason: &'static str,
94    },
95
96    // exFAT-specific errors
97    /// Invalid exFAT filesystem signature
98    #[cfg(feature = "exfat")]
99    ExFatInvalidSignature {
100        /// Expected signature
101        expected: [u8; 8],
102        /// Found signature
103        found: [u8; 8],
104    },
105    /// Invalid exFAT boot sector
106    #[cfg(feature = "exfat")]
107    ExFatInvalidBootSector {
108        /// Reason for invalidity
109        reason: &'static str,
110    },
111    /// Invalid exFAT boot region checksum
112    #[cfg(feature = "exfat")]
113    ExFatInvalidChecksum {
114        /// Expected checksum
115        expected: u32,
116        /// Found checksum
117        found: u32,
118    },
119    /// Invalid exFAT directory entry
120    #[cfg(feature = "exfat")]
121    ExFatInvalidEntry {
122        /// Reason for invalidity
123        reason: &'static str,
124    },
125}
126
127impl fmt::Display for FatError {
128    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
129        match self {
130            Self::InvalidBootSignature { found } => {
131                write!(
132                    f,
133                    "invalid boot signature: expected 0xAA55, found {found:#06x}"
134                )
135            }
136            Self::UnsupportedFatType(ty) => {
137                write!(f, "unsupported FAT type: {ty}")
138            }
139            Self::InvalidFsInfoSignature {
140                field,
141                expected,
142                found,
143            } => {
144                write!(
145                    f,
146                    "invalid FSInfo signature: {field} expected {expected:#010x}, found {found:#010x}"
147                )
148            }
149            Self::InvalidShortFilename => {
150                write!(f, "invalid short filename")
151            }
152            Self::ClusterOutOfBounds { cluster, max } => {
153                write!(f, "cluster {cluster} out of bounds (max: {max})")
154            }
155            Self::BadCluster { cluster } => {
156                write!(f, "bad cluster marker encountered at cluster {cluster}")
157            }
158            Self::UnexpectedEndOfChain { cluster } => {
159                write!(f, "unexpected end of cluster chain at cluster {cluster}")
160            }
161            Self::Io(e) => {
162                write!(f, "I/O error: {e:?}")
163            }
164            Self::NotAFile => {
165                write!(f, "entry is not a file")
166            }
167            Self::NotADirectory => {
168                write!(f, "entry is not a directory")
169            }
170            Self::EntryNotFound => {
171                write!(f, "entry not found in directory")
172            }
173            Self::InvalidPath => {
174                write!(f, "path is invalid (empty or malformed)")
175            }
176            #[cfg(feature = "write")]
177            Self::NoFreeSpace => {
178                write!(f, "no free clusters available")
179            }
180            #[cfg(feature = "write")]
181            Self::DirectoryFull => {
182                write!(f, "directory is full (no free entry slots)")
183            }
184            #[cfg(feature = "write")]
185            Self::InvalidFilename => {
186                write!(f, "filename is invalid or too long")
187            }
188            #[cfg(feature = "write")]
189            Self::AlreadyExists => {
190                write!(f, "entry with this name already exists")
191            }
192            #[cfg(feature = "write")]
193            Self::DirectoryNotEmpty => {
194                write!(f, "cannot delete non-empty directory")
195            }
196            #[cfg(feature = "write")]
197            Self::VolumeTooSmall { size, min_size } => {
198                write!(
199                    f,
200                    "volume size {} bytes is too small (minimum: {} bytes)",
201                    size, min_size
202                )
203            }
204            #[cfg(feature = "write")]
205            Self::VolumeTooLarge { size, max_size } => {
206                write!(
207                    f,
208                    "volume size {} bytes is too large (maximum: {} bytes)",
209                    size, max_size
210                )
211            }
212            #[cfg(feature = "write")]
213            Self::InvalidFormatOption { option, reason } => {
214                write!(f, "invalid format option '{}': {}", option, reason)
215            }
216            #[cfg(feature = "exfat")]
217            Self::ExFatInvalidSignature { expected, found } => {
218                write!(
219                    f,
220                    "invalid exFAT signature: expected {:?}, found {:?}",
221                    core::str::from_utf8(expected).unwrap_or("<invalid>"),
222                    core::str::from_utf8(found).unwrap_or("<invalid>")
223                )
224            }
225            #[cfg(feature = "exfat")]
226            Self::ExFatInvalidBootSector { reason } => {
227                write!(f, "invalid exFAT boot sector: {reason}")
228            }
229            #[cfg(feature = "exfat")]
230            Self::ExFatInvalidChecksum { expected, found } => {
231                write!(
232                    f,
233                    "invalid exFAT checksum: expected {expected:#010x}, found {found:#010x}"
234                )
235            }
236            #[cfg(feature = "exfat")]
237            Self::ExFatInvalidEntry { reason } => {
238                write!(f, "invalid exFAT directory entry: {reason}")
239            }
240        }
241    }
242}
243
244#[cfg(feature = "std")]
245impl std::error::Error for FatError {}
246
247impl From<hadris_io::Error> for FatError {
248    fn from(e: hadris_io::Error) -> Self {
249        Self::Io(e)
250    }
251}
252
253/// Result type alias for FAT operations.
254pub type Result<T> = core::result::Result<T, FatError>;