@@ -21,9 +21,13 @@ pub struct FileAttr {
2121 created : Option < SystemTime > ,
2222}
2323
24- pub struct ReadDir ( ! ) ;
24+ pub struct ReadDir ( uefi_fs :: File ) ;
2525
26- pub struct DirEntry ( !) ;
26+ pub struct DirEntry {
27+ attr : FileAttr ,
28+ file_name : OsString ,
29+ path : PathBuf ,
30+ }
2731
2832#[ derive( Clone , Debug ) ]
2933pub struct OpenOptions {
@@ -143,34 +147,46 @@ impl FileType {
143147}
144148
145149impl fmt:: Debug for ReadDir {
146- fn fmt ( & self , _f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
147- self . 0
150+ fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
151+ let mut b = f. debug_struct ( "ReadDir" ) ;
152+ b. field ( "path" , & self . 0 . path ( ) ) ;
153+ b. finish ( )
148154 }
149155}
150156
151157impl Iterator for ReadDir {
152158 type Item = io:: Result < DirEntry > ;
153159
154160 fn next ( & mut self ) -> Option < io:: Result < DirEntry > > {
155- self . 0
161+ match self . 0 . read_dir_entry ( ) {
162+ Ok ( None ) => None ,
163+ Ok ( Some ( x) ) => Some ( Ok ( DirEntry :: from_uefi ( x, self . 0 . path ( ) ) ) ) ,
164+ Err ( e) => Some ( Err ( e) ) ,
165+ }
156166 }
157167}
158168
159169impl DirEntry {
160170 pub fn path ( & self ) -> PathBuf {
161- self . 0
171+ self . path . clone ( )
162172 }
163173
164174 pub fn file_name ( & self ) -> OsString {
165- self . 0
175+ self . file_name . clone ( )
166176 }
167177
168178 pub fn metadata ( & self ) -> io:: Result < FileAttr > {
169- self . 0
179+ Ok ( self . attr . clone ( ) )
170180 }
171181
172182 pub fn file_type ( & self ) -> io:: Result < FileType > {
173- self . 0
183+ Ok ( self . attr . file_type ( ) )
184+ }
185+
186+ fn from_uefi ( info : helpers:: UefiBox < file:: Info > , parent : & Path ) -> Self {
187+ let file_name = uefi_fs:: file_name_from_uefi ( & info) ;
188+ let path = parent. join ( & file_name) ;
189+ Self { file_name, path, attr : FileAttr :: from_uefi ( info) }
174190 }
175191}
176192
@@ -344,8 +360,17 @@ impl fmt::Debug for File {
344360 }
345361}
346362
347- pub fn readdir ( _p : & Path ) -> io:: Result < ReadDir > {
348- unsupported ( )
363+ pub fn readdir ( p : & Path ) -> io:: Result < ReadDir > {
364+ let path = crate :: path:: absolute ( p) ?;
365+ let f = uefi_fs:: File :: from_path ( & path, file:: MODE_READ , 0 ) ?;
366+ let file_info = f. file_info ( ) ?;
367+ let file_attr = FileAttr :: from_uefi ( file_info) ;
368+
369+ if file_attr. file_type ( ) . is_dir ( ) {
370+ Ok ( ReadDir ( f) )
371+ } else {
372+ Err ( io:: const_error!( io:: ErrorKind :: NotADirectory , "expected a directory but got a file" ) )
373+ }
349374}
350375
351376pub fn unlink ( p : & Path ) -> io:: Result < ( ) > {
@@ -459,13 +484,18 @@ mod uefi_fs {
459484 use r_efi:: protocols:: { device_path, file, simple_file_system} ;
460485
461486 use crate :: boxed:: Box ;
487+ use crate :: ffi:: OsString ;
462488 use crate :: io;
489+ use crate :: os:: uefi:: ffi:: OsStringExt ;
463490 use crate :: path:: Path ;
464491 use crate :: ptr:: NonNull ;
465492 use crate :: sys:: helpers:: { self , UefiBox } ;
466493 use crate :: sys:: time:: { self , SystemTime } ;
467494
468- pub ( crate ) struct File ( NonNull < file:: Protocol > ) ;
495+ pub ( crate ) struct File {
496+ protocol : NonNull < file:: Protocol > ,
497+ path : crate :: path:: PathBuf ,
498+ }
469499
470500 impl File {
471501 pub ( crate ) fn from_path ( path : & Path , open_mode : u64 , attr : u64 ) -> io:: Result < Self > {
@@ -474,7 +504,8 @@ mod uefi_fs {
474504 let p = helpers:: OwnedDevicePath :: from_text ( absolute. as_os_str ( ) ) ?;
475505 let ( vol, mut path_remaining) = Self :: open_volume_from_device_path ( p. borrow ( ) ) ?;
476506
477- vol. open ( & mut path_remaining, open_mode, attr)
507+ let protocol = Self :: open ( vol, & mut path_remaining, open_mode, attr) ?;
508+ Ok ( Self { protocol, path : absolute } )
478509 }
479510
480511 /// Open Filesystem volume given a devicepath to the volume, or a file/directory in the
@@ -490,7 +521,7 @@ mod uefi_fs {
490521 /// and return the remaining file path "\abc\run.efi".
491522 fn open_volume_from_device_path (
492523 path : helpers:: BorrowedDevicePath < ' _ > ,
493- ) -> io:: Result < ( Self , Box < [ u16 ] > ) > {
524+ ) -> io:: Result < ( NonNull < file :: Protocol > , Box < [ u16 ] > ) > {
494525 let handles = match helpers:: locate_handles ( simple_file_system:: PROTOCOL_GUID ) {
495526 Ok ( x) => x,
496527 Err ( e) => return Err ( e) ,
@@ -512,7 +543,9 @@ mod uefi_fs {
512543 }
513544
514545 // Open volume on device_handle using SIMPLE_FILE_SYSTEM_PROTOCOL
515- fn open_volume ( device_handle : NonNull < crate :: ffi:: c_void > ) -> io:: Result < Self > {
546+ fn open_volume (
547+ device_handle : NonNull < crate :: ffi:: c_void > ,
548+ ) -> io:: Result < NonNull < file:: Protocol > > {
516549 let simple_file_system_protocol = helpers:: open_protocol :: < simple_file_system:: Protocol > (
517550 device_handle,
518551 simple_file_system:: PROTOCOL_GUID ,
@@ -531,11 +564,16 @@ mod uefi_fs {
531564
532565 // Since no error was returned, file protocol should be non-NULL.
533566 let p = NonNull :: new ( file_protocol) . unwrap ( ) ;
534- Ok ( Self ( p ) )
567+ Ok ( p )
535568 }
536569
537- fn open ( & self , path : & mut [ u16 ] , open_mode : u64 , attr : u64 ) -> io:: Result < Self > {
538- let file_ptr = self . 0 . as_ptr ( ) ;
570+ fn open (
571+ protocol : NonNull < file:: Protocol > ,
572+ path : & mut [ u16 ] ,
573+ open_mode : u64 ,
574+ attr : u64 ,
575+ ) -> io:: Result < NonNull < file:: Protocol > > {
576+ let file_ptr = protocol. as_ptr ( ) ;
539577 let mut file_opened = crate :: ptr:: null_mut ( ) ;
540578
541579 let r = unsafe {
@@ -548,11 +586,37 @@ mod uefi_fs {
548586
549587 // Since no error was returned, file protocol should be non-NULL.
550588 let p = NonNull :: new ( file_opened) . unwrap ( ) ;
551- Ok ( File ( p) )
589+ Ok ( p)
590+ }
591+
592+ pub ( crate ) fn read_dir_entry ( & self ) -> io:: Result < Option < UefiBox < file:: Info > > > {
593+ let file_ptr = self . protocol . as_ptr ( ) ;
594+ let mut buf_size = 0 ;
595+
596+ let r = unsafe { ( ( * file_ptr) . read ) ( file_ptr, & mut buf_size, crate :: ptr:: null_mut ( ) ) } ;
597+
598+ if buf_size == 0 {
599+ return Ok ( None ) ;
600+ }
601+
602+ assert ! ( r. is_error( ) ) ;
603+ if r != r_efi:: efi:: Status :: BUFFER_TOO_SMALL {
604+ return Err ( io:: Error :: from_raw_os_error ( r. as_usize ( ) ) ) ;
605+ }
606+
607+ let mut info: UefiBox < file:: Info > = UefiBox :: new ( buf_size) ?;
608+ let r =
609+ unsafe { ( ( * file_ptr) . read ) ( file_ptr, & mut buf_size, info. as_mut_ptr ( ) . cast ( ) ) } ;
610+
611+ if r. is_error ( ) {
612+ Err ( io:: Error :: from_raw_os_error ( r. as_usize ( ) ) )
613+ } else {
614+ Ok ( Some ( info) )
615+ }
552616 }
553617
554618 pub ( crate ) fn file_info ( & self ) -> io:: Result < UefiBox < file:: Info > > {
555- let file_ptr = self . 0 . as_ptr ( ) ;
619+ let file_ptr = self . protocol . as_ptr ( ) ;
556620 let mut info_id = file:: INFO_ID ;
557621 let mut buf_size = 0 ;
558622
@@ -583,7 +647,7 @@ mod uefi_fs {
583647 }
584648
585649 pub ( crate ) fn set_file_info ( & self , mut info : UefiBox < file:: Info > ) -> io:: Result < ( ) > {
586- let file_ptr = self . 0 . as_ptr ( ) ;
650+ let file_ptr = self . protocol . as_ptr ( ) ;
587651 let mut info_id = file:: INFO_ID ;
588652
589653 let r = unsafe {
@@ -594,20 +658,24 @@ mod uefi_fs {
594658 }
595659
596660 pub ( crate ) fn delete ( self ) -> io:: Result < ( ) > {
597- let file_ptr = self . 0 . as_ptr ( ) ;
661+ let file_ptr = self . protocol . as_ptr ( ) ;
598662 let r = unsafe { ( ( * file_ptr) . delete ) ( file_ptr) } ;
599663
600664 // Spec states that even in case of failure, the file handle will be closed.
601665 crate :: mem:: forget ( self ) ;
602666
603667 if r. is_error ( ) { Err ( io:: Error :: from_raw_os_error ( r. as_usize ( ) ) ) } else { Ok ( ( ) ) }
604668 }
669+
670+ pub ( crate ) fn path ( & self ) -> & Path {
671+ & self . path
672+ }
605673 }
606674
607675 impl Drop for File {
608676 fn drop ( & mut self ) {
609- let file_ptr = self . 0 . as_ptr ( ) ;
610- let _ = unsafe { ( ( * self . 0 . as_ptr ( ) ) . close ) ( file_ptr) } ;
677+ let file_ptr = self . protocol . as_ptr ( ) ;
678+ let _ = unsafe { ( ( * file_ptr ) . close ) ( file_ptr) } ;
611679 }
612680 }
613681
@@ -647,15 +715,16 @@ mod uefi_fs {
647715 let ( vol, mut path_remaining) = File :: open_volume_from_device_path ( p. borrow ( ) ) ?;
648716
649717 // Check if file exists
650- match vol . open ( & mut path_remaining, file:: MODE_READ , 0 ) {
718+ match File :: open ( vol , & mut path_remaining, file:: MODE_READ , 0 ) {
651719 Ok ( _) => {
652720 return Err ( io:: Error :: new ( io:: ErrorKind :: AlreadyExists , "Path already exists" ) ) ;
653721 }
654722 Err ( e) if e. kind ( ) == io:: ErrorKind :: NotFound => { }
655723 Err ( e) => return Err ( e) ,
656724 }
657725
658- let _ = vol. open (
726+ let _ = File :: open (
727+ vol,
659728 & mut path_remaining,
660729 file:: MODE_READ | file:: MODE_WRITE | file:: MODE_CREATE ,
661730 file:: DIRECTORY ,
@@ -680,4 +749,14 @@ mod uefi_fs {
680749 let now = time:: system_time_internal:: now ( ) ;
681750 time. to_uefi_loose ( now. timezone , now. daylight )
682751 }
752+
753+ pub ( crate ) fn file_name_from_uefi ( info : & UefiBox < file:: Info > ) -> OsString {
754+ let file_name = {
755+ let size = unsafe { ( * info. as_ptr ( ) ) . size } ;
756+ let strlen = ( size as usize - crate :: mem:: size_of :: < file:: Info < 0 > > ( ) - 1 ) / 2 ;
757+ unsafe { crate :: slice:: from_raw_parts ( ( * info. as_ptr ( ) ) . file_name . as_ptr ( ) , strlen) }
758+ } ;
759+
760+ OsString :: from_wide ( file_name)
761+ }
683762}
0 commit comments