@@ -34,7 +34,20 @@ use libc::c_char;
3434use libc:: dirfd;
3535#[ cfg( any( target_os = "linux" , target_os = "emscripten" ) ) ]
3636use 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;
3749#[ cfg( not( any(
50+ target_os = "android" ,
3851 target_os = "linux" ,
3952 target_os = "emscripten" ,
4053 target_os = "solaris" ,
@@ -60,9 +73,7 @@ use libc::{
6073 lstat as lstat64, off_t as off64_t, open as open64, stat as stat64,
6174} ;
6275#[ 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} ;
6677
6778pub use crate :: sys_common:: fs:: try_exists;
6879
@@ -202,6 +213,8 @@ struct InnerReadDir {
202213pub struct ReadDir {
203214 inner : Arc < InnerReadDir > ,
204215 #[ cfg( not( any(
216+ target_os = "android" ,
217+ target_os = "linux" ,
205218 target_os = "solaris" ,
206219 target_os = "illumos" ,
207220 target_os = "fuchsia" ,
@@ -218,11 +231,12 @@ unsafe impl Sync for Dir {}
218231pub struct DirEntry {
219232 entry : dirent64 ,
220233 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.
225237 #[ cfg( any(
238+ target_os = "android" ,
239+ target_os = "linux" ,
226240 target_os = "solaris" ,
227241 target_os = "illumos" ,
228242 target_os = "fuchsia" ,
@@ -449,6 +463,8 @@ impl Iterator for ReadDir {
449463 type Item = io:: Result < DirEntry > ;
450464
451465 #[ cfg( any(
466+ target_os = "android" ,
467+ target_os = "linux" ,
452468 target_os = "solaris" ,
453469 target_os = "fuchsia" ,
454470 target_os = "redox" ,
@@ -457,12 +473,13 @@ impl Iterator for ReadDir {
457473 fn next ( & mut self ) -> Option < io:: Result < DirEntry > > {
458474 unsafe {
459475 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.
464481 super :: os:: set_errno ( 0 ) ;
465- let entry_ptr = libc :: readdir ( self . inner . dirp . 0 ) ;
482+ let entry_ptr = readdir64 ( self . inner . dirp . 0 ) ;
466483 if entry_ptr. is_null ( ) {
467484 // null can mean either the end is reached or an error occurred.
468485 // So we had to clear errno beforehand to check for an error now.
@@ -486,6 +503,8 @@ impl Iterator for ReadDir {
486503 }
487504
488505 #[ cfg( not( any(
506+ target_os = "android" ,
507+ target_os = "linux" ,
489508 target_os = "solaris" ,
490509 target_os = "fuchsia" ,
491510 target_os = "redox" ,
@@ -531,17 +550,17 @@ impl Drop for Dir {
531550
532551impl DirEntry {
533552 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 ( ) )
535554 }
536555
537556 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 ( )
539558 }
540559
541560 #[ cfg( any( target_os = "linux" , target_os = "emscripten" , target_os = "android" ) ) ]
542561 pub fn metadata ( & self ) -> io:: Result < FileAttr > {
543562 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 ( ) ;
545564
546565 cfg_has_statx ! {
547566 if let Some ( ret) = unsafe { try_statx(
@@ -639,29 +658,21 @@ impl DirEntry {
639658 )
640659 }
641660 }
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+ ) ) ) ]
660669 fn name_bytes ( & self ) -> & [ u8 ] {
661- self . name . as_bytes ( )
670+ self . name_cstr ( ) . to_bytes ( )
662671 }
663672
664673 #[ cfg( not( any(
674+ target_os = "android" ,
675+ target_os = "linux" ,
665676 target_os = "solaris" ,
666677 target_os = "illumos" ,
667678 target_os = "fuchsia" ,
@@ -670,7 +681,14 @@ impl DirEntry {
670681 fn name_cstr ( & self ) -> & CStr {
671682 unsafe { CStr :: from_ptr ( self . entry . d_name . as_ptr ( ) ) }
672683 }
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+ ) ) ]
674692 fn name_cstr ( & self ) -> & CStr {
675693 & self . name
676694 }
@@ -1076,6 +1094,8 @@ pub fn readdir(p: &Path) -> io::Result<ReadDir> {
10761094 Ok ( ReadDir {
10771095 inner : Arc :: new ( inner) ,
10781096 #[ cfg( not( any(
1097+ target_os = "android" ,
1098+ target_os = "linux" ,
10791099 target_os = "solaris" ,
10801100 target_os = "illumos" ,
10811101 target_os = "fuchsia" ,
@@ -1615,6 +1635,8 @@ mod remove_dir_impl {
16151635 ReadDir {
16161636 inner : Arc :: new ( InnerReadDir { dirp, root : dummy_root } ) ,
16171637 #[ cfg( not( any(
1638+ target_os = "android" ,
1639+ target_os = "linux" ,
16181640 target_os = "solaris" ,
16191641 target_os = "illumos" ,
16201642 target_os = "fuchsia" ,
0 commit comments