瀏覽代碼

LibCore: Avoid running fstatat on skipped entries in DirIterator

Fixes #22630
implicitfield 1 年之前
父節點
當前提交
20aa56891a
共有 1 個文件被更改,包括 25 次插入17 次删除
  1. 25 17
      Userland/Libraries/LibCore/DirIterator.cpp

+ 25 - 17
Userland/Libraries/LibCore/DirIterator.cpp

@@ -41,6 +41,13 @@ DirIterator::DirIterator(DirIterator&& other)
     other.m_dir = nullptr;
     other.m_dir = nullptr;
 }
 }
 
 
+static constexpr bool dirent_has_d_type =
+#if defined(AK_OS_SOLARIS) || defined(AK_OS_HAIKU)
+    false;
+#else
+    true;
+#endif
+
 bool DirIterator::advance_next()
 bool DirIterator::advance_next()
 {
 {
     if (!m_dir)
     if (!m_dir)
@@ -58,23 +65,10 @@ bool DirIterator::advance_next()
             return false;
             return false;
         }
         }
 
 
-#if defined(AK_OS_SOLARIS) || defined(AK_OS_HAIKU)
-        m_next = DirectoryEntry::from_stat(m_dir, *de);
-#else
-        m_next = DirectoryEntry::from_dirent(*de);
-
-        // dirent structures from readdir aren't guaranteed to contain valid file types,
-        // as it is possible that the underlying filesystem doesn't keep track of those.
-        if (m_next->type == DirectoryEntry::Type::Unknown && !m_next->name.is_empty()) {
-            struct stat statbuf;
-            if (fstatat(dirfd(m_dir), de->d_name, &statbuf, AT_SYMLINK_NOFOLLOW) < 0) {
-                m_error = Error::from_errno(errno);
-                dbgln("DirIteration error: {}", m_error.value());
-                return false;
-            }
-            m_next->type = DirectoryEntry::directory_entry_type_from_stat(statbuf.st_mode);
-        }
-#endif
+        if constexpr (dirent_has_d_type)
+            m_next = DirectoryEntry::from_dirent(*de);
+        else
+            m_next = DirectoryEntry::from_stat(m_dir, *de);
 
 
         if (m_next->name.is_empty())
         if (m_next->name.is_empty())
             return false;
             return false;
@@ -85,6 +79,20 @@ bool DirIterator::advance_next()
         if (m_flags & Flags::SkipParentAndBaseDir && (m_next->name == "." || m_next->name == ".."))
         if (m_flags & Flags::SkipParentAndBaseDir && (m_next->name == "." || m_next->name == ".."))
             continue;
             continue;
 
 
+        if constexpr (dirent_has_d_type) {
+            // dirent structures from readdir aren't guaranteed to contain valid file types,
+            // as it is possible that the underlying filesystem doesn't keep track of those.
+            if (m_next->type == DirectoryEntry::Type::Unknown) {
+                struct stat statbuf;
+                if (fstatat(dirfd(m_dir), de->d_name, &statbuf, AT_SYMLINK_NOFOLLOW) < 0) {
+                    m_error = Error::from_errno(errno);
+                    dbgln("DirIteration error: {}", m_error.value());
+                    return false;
+                }
+                m_next->type = DirectoryEntry::directory_entry_type_from_stat(statbuf.st_mode);
+            }
+        }
+
         return !m_next->name.is_empty();
         return !m_next->name.is_empty();
     }
     }
 }
 }