1- // based on https://crates.io/crates/mini_fat
1+ // based on https://crates.io/crates/mini_fat by https://github.com/gridbugs
22
33use crate :: {
44 disk:: { Read , Seek , SeekFrom } ,
@@ -10,8 +10,6 @@ const DIRECTORY_ENTRY_BYTES: usize = 32;
1010const UNUSED_ENTRY_PREFIX : u8 = 0xE5 ;
1111const END_OF_DIRECTORY_PREFIX : u8 = 0 ;
1212
13- static mut BUFFER : [ u8 ; 0x4000 ] = [ 0 ; 0x4000 ] ;
14-
1513pub struct File {
1614 first_cluster : u32 ,
1715 file_size : u32 ,
@@ -38,8 +36,9 @@ struct Bpb {
3836
3937impl Bpb {
4038 fn parse < D : Read + Seek > ( disk : & mut D ) -> Self {
39+ static mut BPB_BUFFER : [ u8 ; 512 ] = [ 0 ; 512 ] ;
4140 let mut raw = {
42- let buffer = unsafe { & mut BUFFER [ ..] } ;
41+ let buffer = unsafe { & mut BPB_BUFFER [ ..] } ;
4342 & mut buffer[ ..512 ]
4443 } ;
4544 disk. read_exact ( & mut raw) ;
@@ -130,6 +129,25 @@ impl Bpb {
130129 ( self . reserved_sector_count as u64 + ( self . num_fats as u64 * self . fat_size_16 as u64 ) )
131130 * self . bytes_per_sector as u64
132131 }
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+ }
133151}
134152
135153pub struct FileSystem < D > {
@@ -199,7 +217,8 @@ impl<D: Read + Seek> FileSystem<D> {
199217 }
200218 FatType :: Fat12 | FatType :: Fat16 => {
201219 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 [ ..] } ;
203222 assert ! ( root_directory_size <= buffer. len( ) ) ;
204223 let raw = & mut buffer[ ..root_directory_size] ;
205224
@@ -214,6 +233,68 @@ impl<D: Read + Seek> FileSystem<D> {
214233 }
215234 }
216235 }
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+ }
217298}
218299
219300#[ derive( Debug , Clone , Copy , PartialEq , Eq ) ]
@@ -223,6 +304,16 @@ enum FatType {
223304 Fat32 ,
224305}
225306
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+
226317#[ derive( Clone ) ]
227318pub struct DirectoryEntry < ' a > {
228319 short_name : & ' a str ,
@@ -399,3 +490,73 @@ mod directory_attributes {
399490
400491 pub const LONG_NAME : u8 = READ_ONLY | HIDDEN | SYSTEM | VOLUME_ID ;
401492}
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