@@ -34,7 +34,20 @@ use libc::c_char;
34
34
use libc:: dirfd;
35
35
#[ cfg( any( target_os = "linux" , target_os = "emscripten" ) ) ]
36
36
use libc:: fstatat64;
37
+ #[ cfg( any(
38
+ target_os = "android" ,
39
+ target_os = "solaris" ,
40
+ target_os = "fuchsia" ,
41
+ target_os = "redox" ,
42
+ target_os = "illumos"
43
+ ) ) ]
44
+ use libc:: readdir as readdir64;
45
+ #[ cfg( target_os = "linux" ) ]
46
+ use libc:: readdir64;
47
+ #[ cfg( any( target_os = "emscripten" , target_os = "l4re" ) ) ]
48
+ use libc:: readdir64_r;
37
49
#[ cfg( not( any(
50
+ target_os = "android" ,
38
51
target_os = "linux" ,
39
52
target_os = "emscripten" ,
40
53
target_os = "solaris" ,
@@ -60,9 +73,7 @@ use libc::{
60
73
lstat as lstat64, off_t as off64_t, open as open64, stat as stat64,
61
74
} ;
62
75
#[ cfg( any( target_os = "linux" , target_os = "emscripten" , target_os = "l4re" ) ) ]
63
- use libc:: {
64
- dirent64, fstat64, ftruncate64, lseek64, lstat64, off64_t, open64, readdir64_r, stat64,
65
- } ;
76
+ use libc:: { dirent64, fstat64, ftruncate64, lseek64, lstat64, off64_t, open64, stat64} ;
66
77
67
78
pub use crate :: sys_common:: fs:: try_exists;
68
79
@@ -202,6 +213,8 @@ struct InnerReadDir {
202
213
pub struct ReadDir {
203
214
inner : Arc < InnerReadDir > ,
204
215
#[ cfg( not( any(
216
+ target_os = "android" ,
217
+ target_os = "linux" ,
205
218
target_os = "solaris" ,
206
219
target_os = "illumos" ,
207
220
target_os = "fuchsia" ,
@@ -218,11 +231,12 @@ unsafe impl Sync for Dir {}
218
231
pub struct DirEntry {
219
232
entry : dirent64 ,
220
233
dir : Arc < InnerReadDir > ,
221
- // We need to store an owned copy of the entry name
222
- // on Solaris and Fuchsia because a) it uses a zero-length
223
- // array to store the name, b) its lifetime between readdir
224
- // calls is not guaranteed.
234
+ // We need to store an owned copy of the entry name on platforms that use
235
+ // readdir() (not readdir_r()), because a) struct dirent may use a flexible
236
+ // array to store the name, b) it lives only until the next readdir() call.
225
237
#[ cfg( any(
238
+ target_os = "android" ,
239
+ target_os = "linux" ,
226
240
target_os = "solaris" ,
227
241
target_os = "illumos" ,
228
242
target_os = "fuchsia" ,
@@ -449,6 +463,8 @@ impl Iterator for ReadDir {
449
463
type Item = io:: Result < DirEntry > ;
450
464
451
465
#[ cfg( any(
466
+ target_os = "android" ,
467
+ target_os = "linux" ,
452
468
target_os = "solaris" ,
453
469
target_os = "fuchsia" ,
454
470
target_os = "redox" ,
@@ -457,12 +473,13 @@ impl Iterator for ReadDir {
457
473
fn next ( & mut self ) -> Option < io:: Result < DirEntry > > {
458
474
unsafe {
459
475
loop {
460
- // Although readdir_r(3) would be a correct function to use here because
461
- // of the thread safety, on Illumos and Fuchsia the readdir(3C) function
462
- // is safe to use in threaded applications and it is generally preferred
463
- // over the readdir_r(3C) function.
476
+ // As of POSIX.1-2017, readdir() is not required to be thread safe; only
477
+ // readdir_r() is. However, readdir_r() cannot correctly handle platforms
478
+ // with unlimited or variable NAME_MAX. Many modern platforms guarantee
479
+ // thread safety for readdir() as long an individual DIR* is not accessed
480
+ // concurrently, which is sufficient for Rust.
464
481
super :: os:: set_errno ( 0 ) ;
465
- let entry_ptr = libc :: readdir ( self . inner . dirp . 0 ) ;
482
+ let entry_ptr = readdir64 ( self . inner . dirp . 0 ) ;
466
483
if entry_ptr. is_null ( ) {
467
484
// null can mean either the end is reached or an error occurred.
468
485
// So we had to clear errno beforehand to check for an error now.
@@ -486,6 +503,8 @@ impl Iterator for ReadDir {
486
503
}
487
504
488
505
#[ cfg( not( any(
506
+ target_os = "android" ,
507
+ target_os = "linux" ,
489
508
target_os = "solaris" ,
490
509
target_os = "fuchsia" ,
491
510
target_os = "redox" ,
@@ -531,17 +550,17 @@ impl Drop for Dir {
531
550
532
551
impl DirEntry {
533
552
pub fn path ( & self ) -> PathBuf {
534
- self . dir . root . join ( OsStr :: from_bytes ( self . name_bytes ( ) ) )
553
+ self . dir . root . join ( self . file_name_os_str ( ) )
535
554
}
536
555
537
556
pub fn file_name ( & self ) -> OsString {
538
- OsStr :: from_bytes ( self . name_bytes ( ) ) . to_os_string ( )
557
+ self . file_name_os_str ( ) . to_os_string ( )
539
558
}
540
559
541
560
#[ cfg( any( target_os = "linux" , target_os = "emscripten" , target_os = "android" ) ) ]
542
561
pub fn metadata ( & self ) -> io:: Result < FileAttr > {
543
562
let fd = cvt ( unsafe { dirfd ( self . dir . dirp . 0 ) } ) ?;
544
- let name = self . entry . d_name . as_ptr ( ) ;
563
+ let name = self . name_cstr ( ) . as_ptr ( ) ;
545
564
546
565
cfg_has_statx ! {
547
566
if let Some ( ret) = unsafe { try_statx(
@@ -639,29 +658,21 @@ impl DirEntry {
639
658
)
640
659
}
641
660
}
642
- #[ cfg( any(
643
- target_os = "android" ,
644
- target_os = "linux" ,
645
- target_os = "emscripten" ,
646
- target_os = "l4re" ,
647
- target_os = "haiku" ,
648
- target_os = "vxworks" ,
649
- target_os = "espidf"
650
- ) ) ]
651
- fn name_bytes ( & self ) -> & [ u8 ] {
652
- unsafe { CStr :: from_ptr ( self . entry . d_name . as_ptr ( ) ) . to_bytes ( ) }
653
- }
654
- #[ cfg( any(
655
- target_os = "solaris" ,
656
- target_os = "illumos" ,
657
- target_os = "fuchsia" ,
658
- target_os = "redox"
659
- ) ) ]
661
+ #[ cfg( not( any(
662
+ target_os = "macos" ,
663
+ target_os = "ios" ,
664
+ target_os = "netbsd" ,
665
+ target_os = "openbsd" ,
666
+ target_os = "freebsd" ,
667
+ target_os = "dragonfly"
668
+ ) ) ) ]
660
669
fn name_bytes ( & self ) -> & [ u8 ] {
661
- self . name . as_bytes ( )
670
+ self . name_cstr ( ) . to_bytes ( )
662
671
}
663
672
664
673
#[ cfg( not( any(
674
+ target_os = "android" ,
675
+ target_os = "linux" ,
665
676
target_os = "solaris" ,
666
677
target_os = "illumos" ,
667
678
target_os = "fuchsia" ,
@@ -670,7 +681,14 @@ impl DirEntry {
670
681
fn name_cstr ( & self ) -> & CStr {
671
682
unsafe { CStr :: from_ptr ( self . entry . d_name . as_ptr ( ) ) }
672
683
}
673
- #[ cfg( any( target_os = "solaris" , target_os = "illumos" , target_os = "fuchsia" ) ) ]
684
+ #[ cfg( any(
685
+ target_os = "android" ,
686
+ target_os = "linux" ,
687
+ target_os = "solaris" ,
688
+ target_os = "illumos" ,
689
+ target_os = "fuchsia" ,
690
+ target_os = "redox"
691
+ ) ) ]
674
692
fn name_cstr ( & self ) -> & CStr {
675
693
& self . name
676
694
}
@@ -1076,6 +1094,8 @@ pub fn readdir(p: &Path) -> io::Result<ReadDir> {
1076
1094
Ok ( ReadDir {
1077
1095
inner : Arc :: new ( inner) ,
1078
1096
#[ cfg( not( any(
1097
+ target_os = "android" ,
1098
+ target_os = "linux" ,
1079
1099
target_os = "solaris" ,
1080
1100
target_os = "illumos" ,
1081
1101
target_os = "fuchsia" ,
@@ -1615,6 +1635,8 @@ mod remove_dir_impl {
1615
1635
ReadDir {
1616
1636
inner : Arc :: new ( InnerReadDir { dirp, root : dummy_root } ) ,
1617
1637
#[ cfg( not( any(
1638
+ target_os = "android" ,
1639
+ target_os = "linux" ,
1618
1640
target_os = "solaris" ,
1619
1641
target_os = "illumos" ,
1620
1642
target_os = "fuchsia" ,
0 commit comments