about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2022-03-09 02:17:58 +0000
committerbors <bors@rust-lang.org>2022-03-09 02:17:58 +0000
commit163c207fc28cadff4de1808848a93e3e5f2d1941 (patch)
tree85ba92c4bc888fefa3da555c462cd4f866458ce4
parent803a7593044457cc8436847196752405cf023fb5 (diff)
parente8b9ba84be772b6888f17c940ecdab0fdcdcb3c5 (diff)
downloadrust-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.rs57
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),