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