@@ -57,7 +57,10 @@ struct InnerReadDir {
57
57
}
58
58
59
59
#[ derive( Clone ) ]
60
- pub struct ReadDir ( Arc < InnerReadDir > ) ;
60
+ pub struct ReadDir {
61
+ inner : Arc < InnerReadDir > ,
62
+ end_of_stream : bool ,
63
+ }
61
64
62
65
struct Dir ( * mut libc:: DIR ) ;
63
66
@@ -213,7 +216,7 @@ impl fmt::Debug for ReadDir {
213
216
fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
214
217
// This will only be called from std::fs::ReadDir, which will add a "ReadDir()" frame.
215
218
// 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)
217
220
}
218
221
}
219
222
@@ -229,7 +232,7 @@ impl Iterator for ReadDir {
229
232
// is safe to use in threaded applications and it is generally preferred
230
233
// over the readdir_r(3C) function.
231
234
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 ) ;
233
236
if entry_ptr. is_null ( ) {
234
237
// NULL can mean either the end is reached or an error occurred.
235
238
// So we had to clear errno beforehand to check for an error now.
@@ -257,14 +260,25 @@ impl Iterator for ReadDir {
257
260
258
261
#[ cfg( not( any( target_os = "solaris" , target_os = "fuchsia" ) ) ) ]
259
262
fn next ( & mut self ) -> Option < io:: Result < DirEntry > > {
263
+ if self . end_of_stream {
264
+ return None ;
265
+ }
266
+
260
267
unsafe {
261
268
let mut ret = DirEntry {
262
269
entry : mem:: zeroed ( ) ,
263
270
dir : self . clone ( ) ,
264
271
} ;
265
272
let mut entry_ptr = ptr:: null_mut ( ) ;
266
273
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
+ }
268
282
return Some ( Err ( Error :: last_os_error ( ) ) )
269
283
}
270
284
if entry_ptr. is_null ( ) {
@@ -287,7 +301,7 @@ impl Drop for Dir {
287
301
288
302
impl DirEntry {
289
303
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 ( ) ) )
291
305
}
292
306
293
307
pub fn file_name ( & self ) -> OsString {
@@ -296,7 +310,7 @@ impl DirEntry {
296
310
297
311
#[ cfg( any( target_os = "linux" , target_os = "emscripten" , target_os = "android" ) ) ]
298
312
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 ) } ) ?;
300
314
let mut stat: stat64 = unsafe { mem:: zeroed ( ) } ;
301
315
cvt ( unsafe {
302
316
fstatat ( fd,
@@ -692,7 +706,10 @@ pub fn readdir(p: &Path) -> io::Result<ReadDir> {
692
706
Err ( Error :: last_os_error ( ) )
693
707
} else {
694
708
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
+ } )
696
713
}
697
714
}
698
715
}
0 commit comments