@@ -23,9 +23,16 @@ pub struct FileAttr {
2323 created : SystemTime ,
2424}
2525
26- pub struct ReadDir ( !) ;
26+ pub struct ReadDir {
27+ file : uefi_fs:: File ,
28+ path : PathBuf ,
29+ }
2730
28- pub struct DirEntry ( !) ;
31+ pub struct DirEntry {
32+ attr : FileAttr ,
33+ file_name : OsString ,
34+ path : PathBuf ,
35+ }
2936
3037#[ derive( Clone , Debug ) ]
3138pub struct OpenOptions {
@@ -139,34 +146,46 @@ impl FileType {
139146}
140147
141148impl fmt:: Debug for ReadDir {
142- fn fmt ( & self , _f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
143- self . 0
149+ fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
150+ let mut b = f. debug_struct ( "ReadDir" ) ;
151+ b. field ( "path" , & self . path ) ;
152+ b. finish ( )
144153 }
145154}
146155
147156impl Iterator for ReadDir {
148157 type Item = io:: Result < DirEntry > ;
149158
150159 fn next ( & mut self ) -> Option < io:: Result < DirEntry > > {
151- self . 0
160+ match self . file . read_dir_entry ( ) {
161+ Ok ( None ) => None ,
162+ Ok ( Some ( x) ) => Some ( Ok ( DirEntry :: from_uefi ( x, & self . path ) ) ) ,
163+ Err ( e) => Some ( Err ( e) ) ,
164+ }
152165 }
153166}
154167
155168impl DirEntry {
156169 pub fn path ( & self ) -> PathBuf {
157- self . 0
170+ self . path . clone ( )
158171 }
159172
160173 pub fn file_name ( & self ) -> OsString {
161- self . 0
174+ self . file_name . clone ( )
162175 }
163176
164177 pub fn metadata ( & self ) -> io:: Result < FileAttr > {
165- self . 0
178+ Ok ( self . attr . clone ( ) )
166179 }
167180
168181 pub fn file_type ( & self ) -> io:: Result < FileType > {
169- self . 0
182+ Ok ( self . attr . file_type ( ) )
183+ }
184+
185+ fn from_uefi ( info : helpers:: UefiBox < file:: Info > , parent : & Path ) -> Self {
186+ let file_name = uefi_fs:: file_name_from_uefi ( & info) ;
187+ let path = parent. join ( & file_name) ;
188+ Self { file_name, path, attr : FileAttr :: from_uefi ( info) }
170189 }
171190}
172191
@@ -340,8 +359,17 @@ impl fmt::Debug for File {
340359 }
341360}
342361
343- pub fn readdir ( _p : & Path ) -> io:: Result < ReadDir > {
344- unsupported ( )
362+ pub fn readdir ( p : & Path ) -> io:: Result < ReadDir > {
363+ let path = crate :: path:: absolute ( p) ?;
364+ let f = uefi_fs:: File :: from_path ( & path, file:: MODE_READ , 0 ) ?;
365+ let file_info = f. file_info ( ) ?;
366+ let file_attr = FileAttr :: from_uefi ( file_info) ;
367+
368+ if file_attr. file_type ( ) . is_dir ( ) {
369+ Ok ( ReadDir { path, file : f } )
370+ } else {
371+ Err ( io:: const_error!( io:: ErrorKind :: NotADirectory , "expected a directory but got a file" ) )
372+ }
345373}
346374
347375pub fn unlink ( p : & Path ) -> io:: Result < ( ) > {
@@ -431,7 +459,9 @@ mod uefi_fs {
431459 use r_efi:: protocols:: { device_path, file, simple_file_system} ;
432460
433461 use crate :: boxed:: Box ;
462+ use crate :: ffi:: OsString ;
434463 use crate :: io;
464+ use crate :: os:: uefi:: ffi:: OsStringExt ;
435465 use crate :: path:: Path ;
436466 use crate :: ptr:: NonNull ;
437467 use crate :: sys:: helpers:: { self , UefiBox } ;
@@ -523,6 +553,32 @@ mod uefi_fs {
523553 Ok ( File ( p) )
524554 }
525555
556+ pub ( crate ) fn read_dir_entry ( & self ) -> io:: Result < Option < UefiBox < file:: Info > > > {
557+ let file_ptr = self . 0 . as_ptr ( ) ;
558+ let mut buf_size = 0 ;
559+
560+ let r = unsafe { ( ( * file_ptr) . read ) ( file_ptr, & mut buf_size, crate :: ptr:: null_mut ( ) ) } ;
561+
562+ if buf_size == 0 {
563+ return Ok ( None ) ;
564+ }
565+
566+ assert ! ( r. is_error( ) ) ;
567+ if r != r_efi:: efi:: Status :: BUFFER_TOO_SMALL {
568+ return Err ( io:: Error :: from_raw_os_error ( r. as_usize ( ) ) ) ;
569+ }
570+
571+ let mut info: UefiBox < file:: Info > = UefiBox :: new ( buf_size) ?;
572+ let r =
573+ unsafe { ( ( * file_ptr) . read ) ( file_ptr, & mut buf_size, info. as_mut_ptr ( ) . cast ( ) ) } ;
574+
575+ if r. is_error ( ) {
576+ Err ( io:: Error :: from_raw_os_error ( r. as_usize ( ) ) )
577+ } else {
578+ Ok ( Some ( info) )
579+ }
580+ }
581+
526582 pub ( crate ) fn file_info ( & self ) -> io:: Result < UefiBox < file:: Info > > {
527583 let file_ptr = self . 0 . as_ptr ( ) ;
528584 let mut info_id = file:: INFO_ID ;
@@ -642,4 +698,14 @@ mod uefi_fs {
642698 let now = time:: system_time_internal:: now ( ) . unwrap ( ) ;
643699 time. to_uefi_loose ( now. timezone , now. daylight )
644700 }
701+
702+ pub ( crate ) fn file_name_from_uefi ( info : & UefiBox < file:: Info > ) -> OsString {
703+ let file_name = {
704+ let size = unsafe { ( * info. as_ptr ( ) ) . size } ;
705+ let strlen = ( size as usize - crate :: mem:: size_of :: < file:: Info < 0 > > ( ) - 1 ) / 2 ;
706+ unsafe { crate :: slice:: from_raw_parts ( ( * info. as_ptr ( ) ) . file_name . as_ptr ( ) , strlen) }
707+ } ;
708+
709+ OsString :: from_wide ( file_name)
710+ }
645711}
0 commit comments