@@ -38,7 +38,10 @@ struct Bpb {
3838
3939impl Bpb {
4040 fn parse < D : Read + Seek > ( disk : & mut D ) -> Self {
41- let mut raw = [ 0u8 ; 512 ] ;
41+ let mut raw = {
42+ let buffer = unsafe { & mut BUFFER [ ..] } ;
43+ & mut buffer[ ..512 ]
44+ } ;
4245 disk. read_exact ( & mut raw) ;
4346
4447 let bytes_per_sector = u16:: from_le_bytes ( raw[ 11 ..13 ] . try_into ( ) . unwrap ( ) ) ;
@@ -142,27 +145,50 @@ impl<D: Read + Seek> FileSystem<D> {
142145 }
143146 }
144147
145- pub fn lookup_file ( & mut self , path : & str ) -> Option < File > {
146- let root = self . read_root_dir ( ) ;
147- for entry in root {
148- write ! ( screen:: Writer , "entry: " ) . unwrap ( ) ;
149- match entry {
150- Ok ( RawDirectoryEntry :: Normal ( entry) ) => {
151- writeln ! ( screen:: Writer , "{}" , entry. short_filename_main) . unwrap ( ) ;
152- }
153- Ok ( RawDirectoryEntry :: LongName ( entry) ) => {
154- for c in entry. name ( ) {
155- match c {
156- Ok ( c) => write ! ( screen:: Writer , "{c}" ) . unwrap ( ) ,
157- Err ( _) => write ! ( screen:: Writer , "X" ) . unwrap ( ) ,
158- }
159- }
160- writeln ! ( screen:: Writer ) . unwrap ( ) ;
148+ pub fn find_file_in_root_dir ( & mut self , name : & str ) -> Option < File > {
149+ let mut root_entries = self . read_root_dir ( ) . filter_map ( |e| e. ok ( ) ) ;
150+ let raw_entry = root_entries. find ( |e| e. eq_name ( name) ) ?;
151+
152+ let entry = match raw_entry {
153+ RawDirectoryEntry :: Normal ( entry) => DirectoryEntry {
154+ short_name : entry. short_filename_main ,
155+ short_name_extension : entry. short_filename_extension ,
156+ long_name_1 : & [ ] ,
157+ long_name_2 : & [ ] ,
158+ long_name_3 : & [ ] ,
159+ file_size : entry. file_size ,
160+ first_cluster : entry. first_cluster ,
161+ attributes : entry. attributes ,
162+ } ,
163+ RawDirectoryEntry :: LongName ( long_name) => match root_entries. next ( ) {
164+ Some ( RawDirectoryEntry :: LongName ( _) ) => unimplemented ! ( ) ,
165+ Some ( RawDirectoryEntry :: Normal ( entry) ) => DirectoryEntry {
166+ short_name : entry. short_filename_main ,
167+ short_name_extension : entry. short_filename_extension ,
168+ long_name_1 : long_name. name_1 ,
169+ long_name_2 : long_name. name_2 ,
170+ long_name_3 : long_name. name_3 ,
171+ file_size : entry. file_size ,
172+ first_cluster : entry. first_cluster ,
173+ attributes : entry. attributes ,
174+ } ,
175+ None => {
176+ panic ! ( "next none" ) ;
177+ return None ;
161178 }
162- Err ( ( ) ) => writeln ! ( screen:: Writer , "<failed to read>" ) . unwrap ( ) ,
163- }
179+ } ,
180+ } ;
181+
182+ writeln ! ( screen:: Writer , "entry: {entry:?}" ) . unwrap ( ) ;
183+
184+ if entry. is_directory ( ) {
185+ None
186+ } else {
187+ Some ( File {
188+ first_cluster : entry. first_cluster ,
189+ file_size : entry. file_size ,
190+ } )
164191 }
165- todo ! ( ) ;
166192 }
167193
168194 fn read_root_dir < ' a > ( & ' a mut self ) -> impl Iterator < Item = Result < RawDirectoryEntry , ( ) > > + ' a {
@@ -197,6 +223,76 @@ enum FatType {
197223 Fat32 ,
198224}
199225
226+ #[ derive( Clone ) ]
227+ pub struct DirectoryEntry < ' a > {
228+ short_name : & ' a str ,
229+ short_name_extension : & ' a str ,
230+ long_name_1 : & ' a [ u8 ] ,
231+ long_name_2 : & ' a [ u8 ] ,
232+ long_name_3 : & ' a [ u8 ] ,
233+ file_size : u32 ,
234+ first_cluster : u32 ,
235+ attributes : u8 ,
236+ }
237+
238+ impl < ' a > DirectoryEntry < ' a > {
239+ pub fn name ( & self ) -> impl Iterator < Item = Result < char , DecodeUtf16Error > > + ' a {
240+ let mut long_name = {
241+ let iter = self
242+ . long_name_1
243+ . chunks ( 2 )
244+ . chain ( self . long_name_2 . chunks ( 2 ) )
245+ . chain ( self . long_name_3 . chunks ( 2 ) )
246+ . map ( |c| u16:: from_le_bytes ( c. try_into ( ) . unwrap ( ) ) )
247+ . take_while ( |& c| c != 0 ) ;
248+ char:: decode_utf16 ( iter) . peekable ( )
249+ } ;
250+ let short_name = {
251+ let iter = self . short_name . chars ( ) ;
252+ let extension_iter = {
253+ let raw = "." . chars ( ) . chain ( self . short_name_extension . chars ( ) ) ;
254+ raw. take ( if self . short_name_extension . is_empty ( ) {
255+ 0
256+ } else {
257+ self . short_name_extension . len ( ) + 1
258+ } )
259+ } ;
260+ iter. chain ( extension_iter) . map ( Ok )
261+ } ;
262+
263+ if long_name. peek ( ) . is_some ( ) {
264+ long_name. chain ( short_name. take ( 0 ) )
265+ } else {
266+ long_name. chain ( short_name. take ( usize:: MAX ) )
267+ }
268+ }
269+
270+ pub fn is_directory ( & self ) -> bool {
271+ self . attributes & directory_attributes:: DIRECTORY != 0
272+ }
273+ }
274+
275+ impl core:: fmt:: Debug for DirectoryEntry < ' _ > {
276+ fn fmt ( & self , f : & mut core:: fmt:: Formatter < ' _ > ) -> core:: fmt:: Result {
277+ struct NamePrinter < ' a > ( & ' a DirectoryEntry < ' a > ) ;
278+ impl core:: fmt:: Debug for NamePrinter < ' _ > {
279+ fn fmt ( & self , f : & mut core:: fmt:: Formatter < ' _ > ) -> core:: fmt:: Result {
280+ for char in self . 0 . name ( ) . filter_map ( |e| e. ok ( ) ) {
281+ write ! ( f, "{char}" ) ?;
282+ }
283+ Ok ( ( ) )
284+ }
285+ }
286+
287+ f. debug_struct ( "DirectoryEntry" )
288+ . field ( "name" , & NamePrinter ( self ) )
289+ . field ( "file_size" , & self . file_size )
290+ . field ( "first_cluster" , & self . first_cluster )
291+ . field ( "attributes" , & self . attributes )
292+ . finish ( )
293+ }
294+ }
295+
200296#[ derive( Debug ) ]
201297struct RawDirectoryEntryNormal < ' a > {
202298 short_filename_main : & ' a str ,
@@ -257,10 +353,14 @@ impl<'a> RawDirectoryEntry<'a> {
257353 fn slice_to_string ( slice : & [ u8 ] ) -> Result < & str , ( ) > {
258354 const SKIP_SPACE : u8 = 0x20 ;
259355 let mut iter = slice. into_iter ( ) . copied ( ) ;
260- let start_idx = iter. position ( |c| c != SKIP_SPACE ) . ok_or ( ( ) ) ?;
261- let end_idx = start_idx + iter. position ( |c| c == SKIP_SPACE ) . unwrap_or ( slice. len ( ) ) ;
262-
263- core:: str:: from_utf8 ( & slice[ start_idx..end_idx] ) . map_err ( |_| ( ) )
356+ match iter. position ( |c| c != SKIP_SPACE ) {
357+ Some ( start_idx) => {
358+ let end_idx =
359+ start_idx + iter. position ( |c| c == SKIP_SPACE ) . unwrap_or ( slice. len ( ) ) ;
360+ core:: str:: from_utf8 ( & slice[ start_idx..end_idx] ) . map_err ( |_| ( ) )
361+ }
362+ None => Ok ( "" ) ,
363+ }
264364 }
265365 let short_filename_main = slice_to_string ( & raw [ 0 ..8 ] ) ?;
266366 let short_filename_extension = slice_to_string ( & raw [ 8 ..11 ] ) ?;
@@ -277,6 +377,17 @@ impl<'a> RawDirectoryEntry<'a> {
277377 } ) )
278378 }
279379 }
380+
381+ pub fn eq_name ( & self , name : & str ) -> bool {
382+ match self {
383+ RawDirectoryEntry :: Normal ( entry) => entry
384+ . short_filename_main
385+ . chars ( )
386+ . chain ( entry. short_filename_extension . chars ( ) )
387+ . eq ( name. chars ( ) ) ,
388+ RawDirectoryEntry :: LongName ( entry) => entry. name ( ) . eq ( name. chars ( ) . map ( Ok ) ) ,
389+ }
390+ }
280391}
281392
282393mod directory_attributes {
0 commit comments