@@ -38,7 +38,10 @@ struct Bpb {
38
38
39
39
impl Bpb {
40
40
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
+ } ;
42
45
disk. read_exact ( & mut raw) ;
43
46
44
47
let bytes_per_sector = u16:: from_le_bytes ( raw[ 11 ..13 ] . try_into ( ) . unwrap ( ) ) ;
@@ -142,27 +145,50 @@ impl<D: Read + Seek> FileSystem<D> {
142
145
}
143
146
}
144
147
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 ;
161
178
}
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
+ } )
164
191
}
165
- todo ! ( ) ;
166
192
}
167
193
168
194
fn read_root_dir < ' a > ( & ' a mut self ) -> impl Iterator < Item = Result < RawDirectoryEntry , ( ) > > + ' a {
@@ -197,6 +223,76 @@ enum FatType {
197
223
Fat32 ,
198
224
}
199
225
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
+
200
296
#[ derive( Debug ) ]
201
297
struct RawDirectoryEntryNormal < ' a > {
202
298
short_filename_main : & ' a str ,
@@ -257,10 +353,14 @@ impl<'a> RawDirectoryEntry<'a> {
257
353
fn slice_to_string ( slice : & [ u8 ] ) -> Result < & str , ( ) > {
258
354
const SKIP_SPACE : u8 = 0x20 ;
259
355
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
+ }
264
364
}
265
365
let short_filename_main = slice_to_string ( & raw [ 0 ..8 ] ) ?;
266
366
let short_filename_extension = slice_to_string ( & raw [ 8 ..11 ] ) ?;
@@ -277,6 +377,17 @@ impl<'a> RawDirectoryEntry<'a> {
277
377
} ) )
278
378
}
279
379
}
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
+ }
280
391
}
281
392
282
393
mod directory_attributes {
0 commit comments