@@ -59,7 +59,10 @@ struct InnerReadDir {
59
59
}
60
60
61
61
#[ derive( Clone ) ]
62
- pub struct ReadDir ( Arc < InnerReadDir > ) ;
62
+ pub struct ReadDir {
63
+ inner : Arc < InnerReadDir > ,
64
+ end_of_stream : bool ,
65
+ }
63
66
64
67
struct Dir ( * mut libc:: DIR ) ;
65
68
@@ -215,7 +218,7 @@ impl fmt::Debug for ReadDir {
215
218
fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
216
219
// This will only be called from std::fs::ReadDir, which will add a "ReadDir()" frame.
217
220
// Thus the result will be e g 'ReadDir("/home")'
218
- fmt:: Debug :: fmt ( & * self . 0 . root , f)
221
+ fmt:: Debug :: fmt ( & * self . inner . root , f)
219
222
}
220
223
}
221
224
@@ -231,7 +234,7 @@ impl Iterator for ReadDir {
231
234
// is safe to use in threaded applications and it is generally preferred
232
235
// over the readdir_r(3C) function.
233
236
super :: os:: set_errno ( 0 ) ;
234
- let entry_ptr = libc:: readdir ( self . 0 . dirp . 0 ) ;
237
+ let entry_ptr = libc:: readdir ( self . inner . dirp . 0 ) ;
235
238
if entry_ptr. is_null ( ) {
236
239
// NULL can mean either the end is reached or an error occurred.
237
240
// So we had to clear errno beforehand to check for an error now.
@@ -259,14 +262,25 @@ impl Iterator for ReadDir {
259
262
260
263
#[ cfg( not( any( target_os = "solaris" , target_os = "fuchsia" ) ) ) ]
261
264
fn next ( & mut self ) -> Option < io:: Result < DirEntry > > {
265
+ if self . end_of_stream {
266
+ return None ;
267
+ }
268
+
262
269
unsafe {
263
270
let mut ret = DirEntry {
264
271
entry : mem:: zeroed ( ) ,
265
272
dir : self . clone ( ) ,
266
273
} ;
267
274
let mut entry_ptr = ptr:: null_mut ( ) ;
268
275
loop {
269
- if readdir64_r ( self . 0 . dirp . 0 , & mut ret. entry , & mut entry_ptr) != 0 {
276
+ if readdir64_r ( self . inner . dirp . 0 , & mut ret. entry , & mut entry_ptr) != 0 {
277
+ if entry_ptr. is_null ( ) {
278
+ // We encountered an error (which will be returned in this iteration), but
279
+ // we also reached the end of the directory stream. The `end_of_stream`
280
+ // flag is enabled to make sure that we return `None` in the next iteration
281
+ // (instead of looping forever)
282
+ self . end_of_stream = true ;
283
+ }
270
284
return Some ( Err ( Error :: last_os_error ( ) ) )
271
285
}
272
286
if entry_ptr. is_null ( ) {
@@ -289,7 +303,7 @@ impl Drop for Dir {
289
303
290
304
impl DirEntry {
291
305
pub fn path ( & self ) -> PathBuf {
292
- self . dir . 0 . root . join ( OsStr :: from_bytes ( self . name_bytes ( ) ) )
306
+ self . dir . inner . root . join ( OsStr :: from_bytes ( self . name_bytes ( ) ) )
293
307
}
294
308
295
309
pub fn file_name ( & self ) -> OsString {
@@ -298,7 +312,7 @@ impl DirEntry {
298
312
299
313
#[ cfg( any( target_os = "linux" , target_os = "emscripten" , target_os = "android" ) ) ]
300
314
pub fn metadata ( & self ) -> io:: Result < FileAttr > {
301
- let fd = cvt ( unsafe { dirfd ( self . dir . 0 . dirp . 0 ) } ) ?;
315
+ let fd = cvt ( unsafe { dirfd ( self . dir . inner . dirp . 0 ) } ) ?;
302
316
let mut stat: stat64 = unsafe { mem:: zeroed ( ) } ;
303
317
cvt ( unsafe {
304
318
fstatat64 ( fd, self . entry . d_name . as_ptr ( ) , & mut stat, libc:: AT_SYMLINK_NOFOLLOW )
@@ -691,7 +705,10 @@ pub fn readdir(p: &Path) -> io::Result<ReadDir> {
691
705
Err ( Error :: last_os_error ( ) )
692
706
} else {
693
707
let inner = InnerReadDir { dirp : Dir ( ptr) , root } ;
694
- Ok ( ReadDir ( Arc :: new ( inner) ) )
708
+ Ok ( ReadDir {
709
+ inner : Arc :: new ( inner) ,
710
+ end_of_stream : false ,
711
+ } )
695
712
}
696
713
}
697
714
}
0 commit comments