@@ -57,7 +57,10 @@ struct InnerReadDir {
5757}
5858
5959#[ derive( Clone ) ]
60- pub struct ReadDir ( Arc < InnerReadDir > ) ;
60+ pub struct ReadDir {
61+ inner : Arc < InnerReadDir > ,
62+ end_of_stream : bool ,
63+ }
6164
6265struct Dir ( * mut libc:: DIR ) ;
6366
@@ -213,7 +216,7 @@ impl fmt::Debug for ReadDir {
213216 fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
214217 // This will only be called from std::fs::ReadDir, which will add a "ReadDir()" frame.
215218 // Thus the result will be e g 'ReadDir("/home")'
216- fmt:: Debug :: fmt ( & * self . 0 . root , f)
219+ fmt:: Debug :: fmt ( & * self . inner . root , f)
217220 }
218221}
219222
@@ -229,7 +232,7 @@ impl Iterator for ReadDir {
229232 // is safe to use in threaded applications and it is generally preferred
230233 // over the readdir_r(3C) function.
231234 super :: os:: set_errno ( 0 ) ;
232- let entry_ptr = libc:: readdir ( self . 0 . dirp . 0 ) ;
235+ let entry_ptr = libc:: readdir ( self . inner . dirp . 0 ) ;
233236 if entry_ptr. is_null ( ) {
234237 // NULL can mean either the end is reached or an error occurred.
235238 // So we had to clear errno beforehand to check for an error now.
@@ -257,14 +260,25 @@ impl Iterator for ReadDir {
257260
258261 #[ cfg( not( any( target_os = "solaris" , target_os = "fuchsia" ) ) ) ]
259262 fn next ( & mut self ) -> Option < io:: Result < DirEntry > > {
263+ if self . end_of_stream {
264+ return None ;
265+ }
266+
260267 unsafe {
261268 let mut ret = DirEntry {
262269 entry : mem:: zeroed ( ) ,
263270 dir : self . clone ( ) ,
264271 } ;
265272 let mut entry_ptr = ptr:: null_mut ( ) ;
266273 loop {
267- if readdir64_r ( self . 0 . dirp . 0 , & mut ret. entry , & mut entry_ptr) != 0 {
274+ if readdir64_r ( self . inner . dirp . 0 , & mut ret. entry , & mut entry_ptr) != 0 {
275+ if entry_ptr. is_null ( ) {
276+ // We encountered an error (which will be returned in this iteration), but
277+ // we also reached the end of the directory stream. The `end_of_stream`
278+ // flag is enabled to make sure that we return `None` in the next iteration
279+ // (instead of looping forever)
280+ self . end_of_stream = true ;
281+ }
268282 return Some ( Err ( Error :: last_os_error ( ) ) )
269283 }
270284 if entry_ptr. is_null ( ) {
@@ -287,7 +301,7 @@ impl Drop for Dir {
287301
288302impl DirEntry {
289303 pub fn path ( & self ) -> PathBuf {
290- self . dir . 0 . root . join ( OsStr :: from_bytes ( self . name_bytes ( ) ) )
304+ self . dir . inner . root . join ( OsStr :: from_bytes ( self . name_bytes ( ) ) )
291305 }
292306
293307 pub fn file_name ( & self ) -> OsString {
@@ -296,7 +310,7 @@ impl DirEntry {
296310
297311 #[ cfg( any( target_os = "linux" , target_os = "emscripten" , target_os = "android" ) ) ]
298312 pub fn metadata ( & self ) -> io:: Result < FileAttr > {
299- let fd = cvt ( unsafe { dirfd ( self . dir . 0 . dirp . 0 ) } ) ?;
313+ let fd = cvt ( unsafe { dirfd ( self . dir . inner . dirp . 0 ) } ) ?;
300314 let mut stat: stat64 = unsafe { mem:: zeroed ( ) } ;
301315 cvt ( unsafe {
302316 fstatat ( fd,
@@ -692,7 +706,10 @@ pub fn readdir(p: &Path) -> io::Result<ReadDir> {
692706 Err ( Error :: last_os_error ( ) )
693707 } else {
694708 let inner = InnerReadDir { dirp : Dir ( ptr) , root } ;
695- Ok ( ReadDir ( Arc :: new ( inner) ) )
709+ Ok ( ReadDir {
710+ inner : Arc :: new ( inner) ,
711+ end_of_stream : false ,
712+ } )
696713 }
697714 }
698715}
0 commit comments