1
- // based on https://crates.io/crates/mini_fat
1
+ // based on https://crates.io/crates/mini_fat by https://github.com/gridbugs
2
2
3
3
use crate :: {
4
4
disk:: { Read , Seek , SeekFrom } ,
@@ -10,8 +10,6 @@ const DIRECTORY_ENTRY_BYTES: usize = 32;
10
10
const UNUSED_ENTRY_PREFIX : u8 = 0xE5 ;
11
11
const END_OF_DIRECTORY_PREFIX : u8 = 0 ;
12
12
13
- static mut BUFFER : [ u8 ; 0x4000 ] = [ 0 ; 0x4000 ] ;
14
-
15
13
pub struct File {
16
14
first_cluster : u32 ,
17
15
file_size : u32 ,
@@ -38,8 +36,9 @@ struct Bpb {
38
36
39
37
impl Bpb {
40
38
fn parse < D : Read + Seek > ( disk : & mut D ) -> Self {
39
+ static mut BPB_BUFFER : [ u8 ; 512 ] = [ 0 ; 512 ] ;
41
40
let mut raw = {
42
- let buffer = unsafe { & mut BUFFER [ ..] } ;
41
+ let buffer = unsafe { & mut BPB_BUFFER [ ..] } ;
43
42
& mut buffer[ ..512 ]
44
43
} ;
45
44
disk. read_exact ( & mut raw) ;
@@ -130,6 +129,25 @@ impl Bpb {
130
129
( self . reserved_sector_count as u64 + ( self . num_fats as u64 * self . fat_size_16 as u64 ) )
131
130
* self . bytes_per_sector as u64
132
131
}
132
+
133
+ fn maximum_valid_cluster ( & self ) -> u32 {
134
+ self . count_of_clusters ( ) + 1
135
+ }
136
+
137
+ fn fat_offset ( & self ) -> u64 {
138
+ self . reserved_sector_count as u64 * self . bytes_per_sector as u64
139
+ }
140
+
141
+ fn data_offset ( & self ) -> u64 {
142
+ self . root_directory_size ( ) as u64
143
+ + ( ( self . reserved_sector_count as u64
144
+ + self . fat_size_in_sectors ( ) as u64 * self . num_fats as u64 )
145
+ * self . bytes_per_sector as u64 )
146
+ }
147
+
148
+ pub fn bytes_per_cluster ( & self ) -> u32 {
149
+ self . bytes_per_sector as u32 * self . sectors_per_cluster as u32
150
+ }
133
151
}
134
152
135
153
pub struct FileSystem < D > {
@@ -199,7 +217,8 @@ impl<D: Read + Seek> FileSystem<D> {
199
217
}
200
218
FatType :: Fat12 | FatType :: Fat16 => {
201
219
let root_directory_size = self . bpb . root_directory_size ( ) ;
202
- let buffer = unsafe { & mut BUFFER [ ..] } ;
220
+ static mut ROOT_DIR_BUFFER : [ u8 ; 0x4000 ] = [ 0 ; 0x4000 ] ;
221
+ let buffer = unsafe { & mut ROOT_DIR_BUFFER [ ..] } ;
203
222
assert ! ( root_directory_size <= buffer. len( ) ) ;
204
223
let raw = & mut buffer[ ..root_directory_size] ;
205
224
@@ -214,6 +233,68 @@ impl<D: Read + Seek> FileSystem<D> {
214
233
}
215
234
}
216
235
}
236
+
237
+ pub fn file_clusters < ' a > (
238
+ & ' a mut self ,
239
+ file : & File ,
240
+ ) -> impl Iterator < Item = Result < u32 , ( ) > > + ' a {
241
+ Traverser {
242
+ current_entry : file. first_cluster ,
243
+ bpb : & self . bpb ,
244
+ disk : & mut self . disk ,
245
+ }
246
+ }
247
+ }
248
+
249
+ struct Traverser < ' a , D > {
250
+ disk : & ' a mut D ,
251
+ current_entry : u32 ,
252
+ bpb : & ' a Bpb ,
253
+ }
254
+
255
+ impl < D > Traverser < ' _ , D >
256
+ where
257
+ D : Read + Seek ,
258
+ {
259
+ fn next_cluster ( & mut self ) -> Result < Option < u32 > , ( ) > {
260
+ let entry = classify_fat_entry (
261
+ self . bpb . fat_type ( ) ,
262
+ self . current_entry ,
263
+ self . bpb . maximum_valid_cluster ( ) ,
264
+ )
265
+ . map_err ( |_| ( ) ) ?;
266
+ let entry = match entry {
267
+ FileFatEntry :: AllocatedCluster ( cluster) => cluster,
268
+ FileFatEntry :: EndOfFile => return Ok ( None ) ,
269
+ } ;
270
+ let cluster_start =
271
+ self . bpb . data_offset ( ) + ( u64:: from ( entry) - 2 ) * self . bpb . bytes_per_cluster ( ) as u64 ;
272
+ // handle_read(
273
+ // self.traverser.handle,
274
+ // cluster_start,
275
+ // self.traverser.bpb.bytes_per_cluster() as usize,
276
+ // &mut self.traverser.buf,
277
+ // )?;
278
+ // if let Some(t) = f(&self.traverser.buf) {
279
+ // break Ok(Some(t));
280
+ // }
281
+ let next_entry =
282
+ fat_entry_of_nth_cluster ( self . disk , self . bpb . fat_type ( ) , self . bpb . fat_offset ( ) , entry) ;
283
+ self . current_entry = next_entry;
284
+
285
+ Ok ( Some ( entry) )
286
+ }
287
+ }
288
+
289
+ impl < D > Iterator for Traverser < ' _ , D >
290
+ where
291
+ D : Read + Seek ,
292
+ {
293
+ type Item = Result < u32 , ( ) > ;
294
+
295
+ fn next ( & mut self ) -> Option < Self :: Item > {
296
+ self . next_cluster ( ) . transpose ( )
297
+ }
217
298
}
218
299
219
300
#[ derive( Debug , Clone , Copy , PartialEq , Eq ) ]
@@ -223,6 +304,16 @@ enum FatType {
223
304
Fat32 ,
224
305
}
225
306
307
+ impl FatType {
308
+ fn fat_entry_defective ( self ) -> u32 {
309
+ match self {
310
+ Self :: Fat12 => 0xFF7 ,
311
+ Self :: Fat16 => 0xFFF7 ,
312
+ Self :: Fat32 => 0x0FFFFFF7 ,
313
+ }
314
+ }
315
+ }
316
+
226
317
#[ derive( Clone ) ]
227
318
pub struct DirectoryEntry < ' a > {
228
319
short_name : & ' a str ,
@@ -399,3 +490,73 @@ mod directory_attributes {
399
490
400
491
pub const LONG_NAME : u8 = READ_ONLY | HIDDEN | SYSTEM | VOLUME_ID ;
401
492
}
493
+
494
+ fn classify_fat_entry (
495
+ fat_type : FatType ,
496
+ entry : u32 ,
497
+ maximum_valid_cluster : u32 ,
498
+ ) -> Result < FileFatEntry , FatLookupError > {
499
+ match entry {
500
+ 0 => Err ( FatLookupError :: FreeCluster ) ,
501
+ 1 => Err ( FatLookupError :: UnspecifiedEntryOne ) ,
502
+ entry => {
503
+ if entry <= maximum_valid_cluster {
504
+ Ok ( FileFatEntry :: AllocatedCluster ( entry) )
505
+ } else if entry < fat_type. fat_entry_defective ( ) {
506
+ Err ( FatLookupError :: ReservedEntry )
507
+ } else if entry == fat_type. fat_entry_defective ( ) {
508
+ Err ( FatLookupError :: DefectiveCluster )
509
+ } else {
510
+ Ok ( FileFatEntry :: EndOfFile )
511
+ }
512
+ }
513
+ }
514
+ }
515
+
516
+ #[ derive( Debug ) ]
517
+ pub enum FatLookupError {
518
+ FreeCluster ,
519
+ DefectiveCluster ,
520
+ UnspecifiedEntryOne ,
521
+ ReservedEntry ,
522
+ }
523
+
524
+ enum FileFatEntry {
525
+ AllocatedCluster ( u32 ) ,
526
+ EndOfFile ,
527
+ }
528
+
529
+ fn fat_entry_of_nth_cluster < D > ( disk : & mut D , fat_type : FatType , fat_start : u64 , n : u32 ) -> u32
530
+ where
531
+ D : Seek + Read ,
532
+ {
533
+ debug_assert ! ( n >= 2 ) ;
534
+ match fat_type {
535
+ FatType :: Fat32 => {
536
+ let base = n as u64 * 4 ;
537
+ disk. seek ( SeekFrom :: Start ( fat_start + base) ) ;
538
+ let mut buf = [ 0 ; 4 ] ;
539
+ disk. read_exact ( & mut buf) ;
540
+ u32:: from_le_bytes ( buf) & 0x0FFFFFFF
541
+ }
542
+ FatType :: Fat16 => {
543
+ let base = n as u64 * 2 ;
544
+ disk. seek ( SeekFrom :: Start ( fat_start + base) ) ;
545
+ let mut buf = [ 0 ; 2 ] ;
546
+ disk. read_exact ( & mut buf) ;
547
+ u16:: from_le_bytes ( buf) as u32
548
+ }
549
+ FatType :: Fat12 => {
550
+ let base = n as u64 + ( n as u64 / 2 ) ;
551
+ disk. seek ( SeekFrom :: Start ( fat_start + base) ) ;
552
+ let mut buf = [ 0 ; 2 ] ;
553
+ disk. read_exact ( & mut buf) ;
554
+ let entry16 = u16:: from_le_bytes ( buf) ;
555
+ if n & 1 == 0 {
556
+ ( entry16 & 0xFFF ) as u32
557
+ } else {
558
+ ( entry16 >> 4 ) as u32
559
+ }
560
+ }
561
+ }
562
+ }
0 commit comments