diff options
| author | bors <bors@rust-lang.org> | 2022-03-09 02:17:58 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2022-03-09 02:17:58 +0000 |
| commit | 163c207fc28cadff4de1808848a93e3e5f2d1941 (patch) | |
| tree | 85ba92c4bc888fefa3da555c462cd4f866458ce4 | |
| parent | 803a7593044457cc8436847196752405cf023fb5 (diff) | |
| parent | e8b9ba84be772b6888f17c940ecdab0fdcdcb3c5 (diff) | |
| download | rust-163c207fc28cadff4de1808848a93e3e5f2d1941.tar.gz rust-163c207fc28cadff4de1808848a93e3e5f2d1941.zip | |
Auto merge of #94750 - cuviper:dirent64_min, r=joshtriplett
unix: reduce the size of DirEntry On platforms where we call `readdir` instead of `readdir_r`, we store the name as an allocated `CString` for variable length. There's no point carrying around a full `dirent64` with its fixed-length `d_name` too.
| -rw-r--r-- | library/std/src/sys/unix/fs.rs | 57 |
1 files changed, 47 insertions, 10 deletions
diff --git a/library/std/src/sys/unix/fs.rs b/library/std/src/sys/unix/fs.rs index 4a48be5cda6..a3e6b081936 100644 --- a/library/std/src/sys/unix/fs.rs +++ b/library/std/src/sys/unix/fs.rs @@ -228,23 +228,54 @@ struct Dir(*mut libc::DIR); unsafe impl Send for Dir {} unsafe impl Sync for Dir {} +#[cfg(any( + target_os = "android", + target_os = "linux", + target_os = "solaris", + target_os = "illumos", + target_os = "fuchsia", + target_os = "redox" +))] pub struct DirEntry { - entry: dirent64, dir: Arc<InnerReadDir>, + entry: dirent64_min, // We need to store an owned copy of the entry name on platforms that use // readdir() (not readdir_r()), because a) struct dirent may use a flexible // array to store the name, b) it lives only until the next readdir() call. - #[cfg(any( - target_os = "android", - target_os = "linux", - target_os = "solaris", - target_os = "illumos", - target_os = "fuchsia", - target_os = "redox" - ))] name: CString, } +// Define a minimal subset of fields we need from `dirent64`, especially since +// we're not using the immediate `d_name` on these targets. Keeping this as an +// `entry` field in `DirEntry` helps reduce the `cfg` boilerplate elsewhere. +#[cfg(any( + target_os = "android", + target_os = "linux", + target_os = "solaris", + target_os = "illumos", + target_os = "fuchsia", + target_os = "redox" +))] +struct dirent64_min { + d_ino: u64, + #[cfg(not(any(target_os = "solaris", target_os = "illumos")))] + d_type: u8, +} + +#[cfg(not(any( + target_os = "android", + target_os = "linux", + target_os = "solaris", + target_os = "illumos", + target_os = "fuchsia", + target_os = "redox" +)))] +pub struct DirEntry { + dir: Arc<InnerReadDir>, + // The full entry includes a fixed-length `d_name`. + entry: dirent64, +} + #[derive(Clone, Debug)] pub struct OpenOptions { // generic @@ -501,8 +532,14 @@ impl Iterator for ReadDir { let entry_name = entry_bytes.add(name_offset); ptr::copy_nonoverlapping(entry_bytes, copy_bytes, name_offset); + let entry = dirent64_min { + d_ino: copy.d_ino as u64, + #[cfg(not(any(target_os = "solaris", target_os = "illumos")))] + d_type: copy.d_type as u8, + }; + let ret = DirEntry { - entry: copy, + entry, // d_name is guaranteed to be null-terminated. name: CStr::from_ptr(entry_name as *const _).to_owned(), dir: Arc::clone(&self.inner), |
