1- use  super :: abi:: { self ,  O_APPEND ,  O_CREAT ,  O_EXCL ,  O_RDONLY ,  O_RDWR ,  O_TRUNC ,  O_WRONLY } ; 
1+ use  super :: abi:: { 
2+     self ,  dirent64,  stat as  stat_struct,  DT_DIR ,  DT_LNK ,  DT_REG ,  DT_UNKNOWN ,  O_APPEND ,  O_CREAT , 
3+     O_EXCL ,  O_RDONLY ,  O_RDWR ,  O_TRUNC ,  O_WRONLY ,  S_IFDIR ,  S_IFLNK ,  S_IFMT ,  S_IFREG , 
4+ } ; 
25use  super :: fd:: FileDesc ; 
3- use  crate :: ffi:: { CStr ,  OsString } ; 
6+ use  crate :: ffi:: { CStr ,  OsStr ,   OsString } ; 
47use  crate :: fmt; 
58use  crate :: io:: { self ,  Error ,  ErrorKind } ; 
69use  crate :: io:: { BorrowedCursor ,  IoSlice ,  IoSliceMut ,  SeekFrom } ; 
710use  crate :: mem; 
811use  crate :: os:: hermit:: ffi:: OsStringExt ; 
912use  crate :: os:: hermit:: io:: { AsFd ,  AsRawFd ,  BorrowedFd ,  FromRawFd ,  IntoRawFd ,  RawFd } ; 
1013use  crate :: path:: { Path ,  PathBuf } ; 
11- use  crate :: ptr; 
1214use  crate :: sync:: Arc ; 
1315use  crate :: sys:: common:: small_c_string:: run_path_with_cstr; 
1416use  crate :: sys:: cvt; 
@@ -17,7 +19,6 @@ use crate::sys::unsupported;
1719use  crate :: sys_common:: { AsInner ,  AsInnerMut ,  FromInner ,  IntoInner } ; 
1820
1921pub  use  crate :: sys_common:: fs:: { copy,  try_exists} ; 
20- //pub use crate::sys_common::fs::remove_dir_all; 
2122
2223#[ derive( Debug ) ]  
2324pub  struct  File ( FileDesc ) ; 
@@ -34,32 +35,38 @@ impl FileAttr {
3435
3536// all DirEntry's will have a reference to this struct 
3637struct  InnerReadDir  { 
37-     dirp :  FileDesc , 
3838    root :  PathBuf , 
39+     dir :  Vec < u8 > , 
40+ } 
41+ 
42+ impl  InnerReadDir  { 
43+     pub  fn  new ( root :  PathBuf ,  dir :  Vec < u8 > )  -> Self  { 
44+         Self  {  root,  dir } 
45+     } 
3946} 
4047
4148pub  struct  ReadDir  { 
4249    inner :  Arc < InnerReadDir > , 
43-     end_of_stream :   bool , 
50+     pos :   i64 , 
4451} 
4552
4653impl  ReadDir  { 
4754    fn  new ( inner :  InnerReadDir )  -> Self  { 
48-         Self  {  inner :  Arc :: new ( inner) ,  end_of_stream :   false  } 
55+         Self  {  inner :  Arc :: new ( inner) ,  pos :   0  } 
4956    } 
5057} 
5158
5259pub  struct  DirEntry  { 
53-     dir :  Arc < InnerReadDir > , 
54-     entry :  dirent_min , 
60+     /// path to the entry 
61+ root :  PathBuf , 
62+     /// 64-bit inode number 
63+ ino :  u64 , 
64+     /// File type 
65+ type_ :  u32 , 
66+     /// name of the entry 
5567name :  OsString , 
5668} 
5769
58- struct  dirent_min  { 
59-     d_ino :  u64 , 
60-     d_type :  u32 , 
61- } 
62- 
6370#[ derive( Clone ,  Debug ) ]  
6471pub  struct  OpenOptions  { 
6572    // generic 
@@ -105,15 +112,24 @@ pub struct DirBuilder {
105112
106113impl  FileAttr  { 
107114    pub  fn  modified ( & self )  -> io:: Result < SystemTime >  { 
108-         Ok ( SystemTime :: new ( self . stat_val . st_mtime ,  self . stat_val . st_mtime_nsec ) ) 
115+         Ok ( SystemTime :: new ( 
116+             self . stat_val . st_mtime . try_into ( ) . unwrap ( ) , 
117+             self . stat_val . st_mtime_nsec . try_into ( ) . unwrap ( ) , 
118+         ) ) 
109119    } 
110120
111121    pub  fn  accessed ( & self )  -> io:: Result < SystemTime >  { 
112-         Ok ( SystemTime :: new ( self . stat_val . st_atime ,  self . stat_val . st_atime_nsec ) ) 
122+         Ok ( SystemTime :: new ( 
123+             self . stat_val . st_atime . try_into ( ) . unwrap ( ) , 
124+             self . stat_val . st_atime_nsec . try_into ( ) . unwrap ( ) , 
125+         ) ) 
113126    } 
114127
115128    pub  fn  created ( & self )  -> io:: Result < SystemTime >  { 
116-         Ok ( SystemTime :: new ( self . stat_val . st_ctime ,  self . stat_val . st_ctime_nsec ) ) 
129+         Ok ( SystemTime :: new ( 
130+             self . stat_val . st_ctime . try_into ( ) . unwrap ( ) , 
131+             self . stat_val . st_ctime_nsec . try_into ( ) . unwrap ( ) , 
132+         ) ) 
117133    } 
118134
119135    pub  fn  size ( & self )  -> u64  { 
@@ -171,7 +187,7 @@ impl FileType {
171187impl  fmt:: Debug  for  ReadDir  { 
172188    fn  fmt ( & self ,  f :  & mut  fmt:: Formatter < ' _ > )  -> fmt:: Result  { 
173189        // This will only be called from std::fs::ReadDir, which will add a "ReadDir()" frame. 
174-         // Thus the result will be e g  'ReadDir("/home")' 
190+         // Thus the result will be e.g.  'ReadDir("/home")' 
175191        fmt:: Debug :: fmt ( & * self . inner . root ,  f) 
176192    } 
177193} 
@@ -180,101 +196,74 @@ impl Iterator for ReadDir {
180196    type  Item  = io:: Result < DirEntry > ; 
181197
182198    fn  next ( & mut  self )  -> Option < io:: Result < DirEntry > >  { 
183-         if  self . end_of_stream  { 
184-             return  None ; 
185-         } 
199+         let  mut  counter:  usize  = 0 ; 
200+         let  mut  offset:  i64  = 0 ; 
201+ 
202+         // loop over all directory entries and search the entry for the current position 
203+         loop  { 
204+             // leave function, if the loop reaches the of the buffer (with all entries) 
205+             if  offset >= self . inner . dir . len ( ) . try_into ( ) . unwrap ( )  { 
206+                 return  None ; 
207+             } 
186208
187-         unsafe  { 
188-             loop  { 
189-                 // As of POSIX.1-2017, readdir() is not required to be thread safe; only 
190-                 // readdir_r() is. However, readdir_r() cannot correctly handle platforms 
191-                 // with unlimited or variable NAME_MAX. Many modern platforms guarantee 
192-                 // thread safety for readdir() as long an individual DIR* is not accessed 
193-                 // concurrently, which is sufficient for Rust. 
194-                 let  entry_ptr = match  abi:: readdir ( self . inner . dirp . as_raw_fd ( ) )  { 
195-                     abi:: DirectoryEntry :: Invalid ( e)  => { 
196-                         // We either encountered an error, or reached the end. Either way, 
197-                         // the next call to next() should return None. 
198-                         self . end_of_stream  = true ; 
199- 
200-                         return  Some ( Err ( Error :: from_raw_os_error ( e) ) ) ; 
201-                     } 
202-                     abi:: DirectoryEntry :: Valid ( ptr)  => { 
203-                         if  ptr. is_null ( )  { 
204-                             return  None ; 
205-                         } 
206- 
207-                         ptr
208-                     } 
209+             let  dir = unsafe  { 
210+                 & * ( self . inner . dir . as_ptr ( ) . offset ( offset. try_into ( ) . unwrap ( ) )  as  * const  dirent64 ) 
211+             } ; 
212+ 
213+             if  counter == self . pos . try_into ( ) . unwrap ( )  { 
214+                 self . pos  += 1 ; 
215+ 
216+                 // After dirent64, the file name is stored. d_reclen represents the length of the dirent64 
217+                 // plus the length of the file name. Consequently, file name has a size of d_reclen minus 
218+                 // the size of dirent64. The file name is always a C string and terminated by `\0`. 
219+                 // Consequently, we are able to ignore the last byte. 
220+                 let  name_bytes = unsafe  { 
221+                     core:: slice:: from_raw_parts ( 
222+                         & dir. d_name  as  * const  _  as  * const  u8 , 
223+                         dir. d_reclen  as  usize  - core:: mem:: size_of :: < dirent64 > ( )  - 1 , 
224+                     ) 
225+                     . to_vec ( ) 
209226                } ; 
210- 
211-                 macro_rules!  offset_ptr { 
212-                     ( $entry_ptr: expr,  $field: ident)  => { { 
213-                         const  OFFSET :  isize  = { 
214-                             let  delusion = MaybeUninit :: <dirent>:: uninit( ) ; 
215-                             let  entry_ptr = delusion. as_ptr( ) ; 
216-                             unsafe  { 
217-                                 ptr:: addr_of!( ( * entry_ptr) . $field) 
218-                                     . cast:: <u8 >( ) 
219-                                     . offset_from( entry_ptr. cast:: <u8 >( ) ) 
220-                             } 
221-                         } ; 
222-                         if  true  { 
223-                             // Cast to the same type determined by the else branch. 
224-                             $entry_ptr. byte_offset( OFFSET ) . cast:: <_>( ) 
225-                         }  else { 
226-                             #[ allow( deref_nullptr) ] 
227-                             { 
228-                                 ptr:: addr_of!( ( * ptr:: null:: <dirent>( ) ) . $field) 
229-                             } 
230-                         } 
231-                     } } ; 
232-                 } 
233- 
234-                 // d_name is NOT guaranteed to be null-terminated. 
235-                 let  name_bytes = core:: slice:: from_raw_parts ( 
236-                     offset_ptr ! ( entry_ptr,  d_name)  as  * const  u8 , 
237-                     * offset_ptr ! ( entry_ptr,  d_namelen)  as  usize , 
238-                 ) 
239-                 . to_vec ( ) ; 
240- 
241-                 if  name_bytes == b"."  || name_bytes == b".."  { 
242-                     continue ; 
243-                 } 
244- 
245-                 let  name = OsString :: from_vec ( name_bytes) ; 
246- 
247-                 let  entry = dirent_min  { 
248-                     d_ino :  * offset_ptr ! ( entry_ptr,  d_ino) , 
249-                     d_type :  * offset_ptr ! ( entry_ptr,  d_type) , 
227+                 let  entry = DirEntry  { 
228+                     root :  self . inner . root . clone ( ) , 
229+                     ino :  dir. d_ino , 
230+                     type_ :  dir. d_type  as  u32 , 
231+                     name :  OsString :: from_vec ( name_bytes) , 
250232                } ; 
251233
252-                 return  Some ( Ok ( DirEntry   {   entry,   name :  name ,   dir :   Arc :: clone ( & self . inner )   } ) ) ; 
234+                 return  Some ( Ok ( entry) ) ; 
253235            } 
236+ 
237+             counter += 1 ; 
238+ 
239+             // move to the next dirent64, which is directly stored after the previous one 
240+             offset = offset + dir. d_off ; 
254241        } 
255242    } 
256243} 
257244
258245impl  DirEntry  { 
259246    pub  fn  path ( & self )  -> PathBuf  { 
260-         self . dir . root . join ( self . file_name_os_str ( ) ) 
247+         self . root . join ( self . file_name_os_str ( ) ) 
261248    } 
262249
263250    pub  fn  file_name ( & self )  -> OsString  { 
264251        self . file_name_os_str ( ) . to_os_string ( ) 
265252    } 
266253
267254    pub  fn  metadata ( & self )  -> io:: Result < FileAttr >  { 
268-         lstat ( & self . path ( ) ) 
255+         let  mut  path = self . path ( ) ; 
256+         path. set_file_name ( self . file_name_os_str ( ) ) ; 
257+         lstat ( & path) 
269258    } 
270259
271260    pub  fn  file_type ( & self )  -> io:: Result < FileType >  { 
272-         Ok ( FileType  {  mode :  self . entry . d_type  } ) 
261+         Ok ( FileType  {  mode :  self . type_   as   u32  } ) 
273262    } 
274263
275264    #[ allow( dead_code) ]  
276265    pub  fn  ino ( & self )  -> u64  { 
277-         self . entry . d_ino 
266+         self . ino 
278267    } 
279268
280269    pub  fn  file_name_os_str ( & self )  -> & OsStr  { 
@@ -456,7 +445,7 @@ impl DirBuilder {
456445    } 
457446
458447    pub  fn  mkdir ( & self ,  path :  & Path )  -> io:: Result < ( ) >  { 
459-         run_path_with_cstr ( path,  |path| { 
448+         run_path_with_cstr ( path,  & |path| { 
460449            cvt ( unsafe  {  abi:: mkdir ( path. as_ptr ( ) ,  self . mode )  } ) . map ( |_| ( ) ) 
461450        } ) 
462451    } 
@@ -519,11 +508,42 @@ impl FromRawFd for File {
519508} 
520509
521510pub  fn  readdir ( path :  & Path )  -> io:: Result < ReadDir >  { 
522-     let  fd_raw = run_path_with_cstr ( path,  |path| cvt ( unsafe  {  abi:: opendir ( path. as_ptr ( ) )  } ) ) ?; 
511+     let  fd_raw = run_path_with_cstr ( path,  & |path| cvt ( unsafe  {  abi:: opendir ( path. as_ptr ( ) )  } ) ) ?; 
523512    let  fd = unsafe  {  FileDesc :: from_raw_fd ( fd_raw as  i32 )  } ; 
524513    let  root = path. to_path_buf ( ) ; 
525-     let  inner = InnerReadDir  {  dirp :  fd,  root } ; 
526-     Ok ( ReadDir :: new ( inner) ) 
514+ 
515+     // read all director entries 
516+     let  mut  vec:  Vec < u8 >  = Vec :: new ( ) ; 
517+     let  mut  sz = 512 ; 
518+     loop  { 
519+         // reserve memory to receive all directory entries 
520+         vec. resize ( sz,  0 ) ; 
521+ 
522+         let  readlen =
523+             unsafe  {  abi:: getdents64 ( fd. as_raw_fd ( ) ,  vec. as_mut_ptr ( )  as  * mut  dirent64 ,  sz)  } ; 
524+         if  readlen > 0  { 
525+             // shrink down to the minimal size 
526+             vec. resize ( readlen. try_into ( ) . unwrap ( ) ,  0 ) ; 
527+             break ; 
528+         } 
529+ 
530+         // if the buffer is too small, getdents64 returns EINVAL 
531+         // otherwise, getdents64 returns an error number 
532+         if  readlen != ( -abi:: errno:: EINVAL ) . into ( )  { 
533+             return  Err ( Error :: from_raw_os_error ( readlen. try_into ( ) . unwrap ( ) ) ) ; 
534+         } 
535+ 
536+         // we don't have enough memory => try to increase the vector size 
537+         sz = sz *  2 ; 
538+ 
539+         // 1 MB for directory entries should be enough 
540+         // stop here to avoid an endless loop 
541+         if  sz > 0x100000  { 
542+             return  Err ( Error :: from ( ErrorKind :: Uncategorized ) ) ; 
543+         } 
544+     } 
545+ 
546+     Ok ( ReadDir :: new ( InnerReadDir :: new ( root,  vec) ) ) 
527547} 
528548
529549pub  fn  unlink ( path :  & Path )  -> io:: Result < ( ) >  { 
@@ -539,12 +559,11 @@ pub fn set_perm(_p: &Path, _perm: FilePermissions) -> io::Result<()> {
539559} 
540560
541561pub  fn  rmdir ( path :  & Path )  -> io:: Result < ( ) >  { 
542-     run_path_with_cstr ( path,  |path| cvt ( unsafe  {  abi:: rmdir ( path. as_ptr ( ) )  } ) . map ( |_| ( ) ) ) 
562+     run_path_with_cstr ( path,  & |path| cvt ( unsafe  {  abi:: rmdir ( path. as_ptr ( ) )  } ) . map ( |_| ( ) ) ) 
543563} 
544564
545565pub  fn  remove_dir_all ( _path :  & Path )  -> io:: Result < ( ) >  { 
546-     //unsupported() 
547-     Ok ( ( ) ) 
566+     unsupported ( ) 
548567} 
549568
550569pub  fn  readlink ( _p :  & Path )  -> io:: Result < PathBuf >  { 
@@ -560,15 +579,15 @@ pub fn link(_original: &Path, _link: &Path) -> io::Result<()> {
560579} 
561580
562581pub  fn  stat ( path :  & Path )  -> io:: Result < FileAttr >  { 
563-     run_path_with_cstr ( path,  |path| { 
582+     run_path_with_cstr ( path,  & |path| { 
564583        let  mut  stat_val:  stat_struct  = unsafe  {  mem:: zeroed ( )  } ; 
565584        cvt ( unsafe  {  abi:: stat ( path. as_ptr ( ) ,  & mut  stat_val)  } ) ?; 
566585        Ok ( FileAttr :: from_stat ( stat_val) ) 
567586    } ) 
568587} 
569588
570589pub  fn  lstat ( path :  & Path )  -> io:: Result < FileAttr >  { 
571-     run_path_with_cstr ( path,  |path| { 
590+     run_path_with_cstr ( path,  & |path| { 
572591        let  mut  stat_val:  stat_struct  = unsafe  {  mem:: zeroed ( )  } ; 
573592        cvt ( unsafe  {  abi:: lstat ( path. as_ptr ( ) ,  & mut  stat_val)  } ) ?; 
574593        Ok ( FileAttr :: from_stat ( stat_val) ) 
0 commit comments