Skip to content

Commit efcc300

Browse files
authored
Rollup merge of rust-lang#92778 - tavianator:linux-readdir-no-r, r=joshtriplett
fs: Use readdir() instead of readdir_r() on Linux readdir() is preferred over readdir_r() on Linux and many other platforms because it more gracefully supports long file names. Both glibc and musl (and presumably all other Linux libc implementations) guarantee that readdir() is thread-safe as long as a single DIR* is not accessed concurrently, which is enough to make a readdir()-based implementation of ReadDir safe. This implementation is already used for some other OSes including Fuchsia, Redox, and Solaris. See rust-lang#40021 for more details. Fixes rust-lang#86649.
2 parents 18fa47c + ea9181b commit efcc300

File tree

2 files changed

+18
-6
lines changed

2 files changed

+18
-6
lines changed

library/std/src/sys/unix/fs.rs

+17-5
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,15 @@ use libc::c_char;
3434
use libc::dirfd;
3535
#[cfg(any(target_os = "linux", target_os = "emscripten"))]
3636
use libc::fstatat64;
37+
#[cfg(any(
38+
target_os = "solaris",
39+
target_os = "fuchsia",
40+
target_os = "redox",
41+
target_os = "illumos"
42+
))]
43+
use libc::readdir as readdir64;
44+
#[cfg(target_os = "linux")]
45+
use libc::readdir64;
3746
#[cfg(not(any(
3847
target_os = "linux",
3948
target_os = "emscripten",
@@ -60,9 +69,7 @@ use libc::{
6069
lstat as lstat64, off_t as off64_t, open as open64, stat as stat64,
6170
};
6271
#[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-
};
72+
use libc::{dirent64, fstat64, ftruncate64, lseek64, lstat64, off64_t, open64, stat64};
6673

6774
pub use crate::sys_common::fs::{remove_dir_all, try_exists};
6875

@@ -202,6 +209,7 @@ struct InnerReadDir {
202209
pub struct ReadDir {
203210
inner: Arc<InnerReadDir>,
204211
#[cfg(not(any(
212+
target_os = "linux",
205213
target_os = "solaris",
206214
target_os = "illumos",
207215
target_os = "fuchsia",
@@ -223,6 +231,7 @@ pub struct DirEntry {
223231
// array to store the name, b) its lifetime between readdir
224232
// calls is not guaranteed.
225233
#[cfg(any(
234+
target_os = "linux",
226235
target_os = "solaris",
227236
target_os = "illumos",
228237
target_os = "fuchsia",
@@ -449,6 +458,7 @@ impl Iterator for ReadDir {
449458
type Item = io::Result<DirEntry>;
450459

451460
#[cfg(any(
461+
target_os = "linux",
452462
target_os = "solaris",
453463
target_os = "fuchsia",
454464
target_os = "redox",
@@ -464,7 +474,7 @@ impl Iterator for ReadDir {
464474
// is safe to use in threaded applications and it is generally preferred
465475
// over the readdir_r(3C) function.
466476
super::os::set_errno(0);
467-
let entry_ptr = libc::readdir(self.inner.dirp.0);
477+
let entry_ptr = readdir64(self.inner.dirp.0);
468478
if entry_ptr.is_null() {
469479
// null can mean either the end is reached or an error occurred.
470480
// So we had to clear errno beforehand to check for an error now.
@@ -492,6 +502,7 @@ impl Iterator for ReadDir {
492502
}
493503

494504
#[cfg(not(any(
505+
target_os = "linux",
495506
target_os = "solaris",
496507
target_os = "fuchsia",
497508
target_os = "redox",
@@ -647,7 +658,6 @@ impl DirEntry {
647658
}
648659
#[cfg(any(
649660
target_os = "android",
650-
target_os = "linux",
651661
target_os = "emscripten",
652662
target_os = "l4re",
653663
target_os = "haiku",
@@ -658,6 +668,7 @@ impl DirEntry {
658668
unsafe { CStr::from_ptr(self.entry.d_name.as_ptr()).to_bytes() }
659669
}
660670
#[cfg(any(
671+
target_os = "linux",
661672
target_os = "solaris",
662673
target_os = "illumos",
663674
target_os = "fuchsia",
@@ -1068,6 +1079,7 @@ pub fn readdir(p: &Path) -> io::Result<ReadDir> {
10681079
Ok(ReadDir {
10691080
inner: Arc::new(inner),
10701081
#[cfg(not(any(
1082+
target_os = "linux",
10711083
target_os = "solaris",
10721084
target_os = "illumos",
10731085
target_os = "fuchsia",

library/std/src/sys/unix/os.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ pub fn errno() -> i32 {
7575
}
7676

7777
/// Sets the platform-specific value of errno
78-
#[cfg(all(not(target_os = "linux"), not(target_os = "dragonfly"), not(target_os = "vxworks")))] // needed for readdir and syscall!
78+
#[cfg(all(not(target_os = "dragonfly"), not(target_os = "vxworks")))] // needed for readdir and syscall!
7979
#[allow(dead_code)] // but not all target cfgs actually end up using it
8080
pub fn set_errno(e: i32) {
8181
unsafe { *errno_location() = e as c_int }

0 commit comments

Comments
 (0)