Browse Source

LibCore: Expose file type from DirIterator

Our `find` utility makes use of the `dirent::d_type` field for filtering
results, which `Core::DirIterator` didn't expose. So, now it does. :^)

We now store the name and type of the entry as the "next" value instead
of just the name. The type is exposed as a `DirectoryEntry::Type`
instead of a `DT_FOO` constant, so that we're not tied to posixy
systems, and because proper enums are nice. :^)
Sam Atkins 2 năm trước cách đây
mục cha
commit
a98ae8f357

+ 1 - 0
Userland/Libraries/LibCore/CMakeLists.txt

@@ -6,6 +6,7 @@ set(SOURCES
     DateTime.cpp
     DeprecatedFile.cpp
     Directory.cpp
+    DirectoryEntry.cpp
     DirIterator.cpp
     ElapsedTimer.cpp
     Event.cpp

+ 22 - 13
Userland/Libraries/LibCore/DirIterator.cpp

@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
+ * Copyright (c) 2023, Sam Atkins <atkinssj@serenityos.org>
  *
  * SPDX-License-Identifier: BSD-2-Clause
  */
@@ -7,7 +8,6 @@
 #include <AK/Vector.h>
 #include <LibCore/DirIterator.h>
 #include <errno.h>
-#include <unistd.h>
 
 namespace Core {
 
@@ -49,40 +49,49 @@ bool DirIterator::advance_next()
         auto* de = readdir(m_dir);
         if (!de) {
             m_error = errno;
-            m_next = DeprecatedString();
+            m_next.clear();
             return false;
         }
 
-        m_next = de->d_name;
-        if (m_next.is_null())
+        m_next = DirectoryEntry::from_dirent(*de);
+
+        if (m_next->name.is_empty())
             return false;
 
-        if (m_flags & Flags::SkipDots && m_next.starts_with('.'))
+        if (m_flags & Flags::SkipDots && m_next->name.starts_with('.'))
             continue;
 
-        if (m_flags & Flags::SkipParentAndBaseDir && (m_next == "." || m_next == ".."))
+        if (m_flags & Flags::SkipParentAndBaseDir && (m_next->name == "." || m_next->name == ".."))
             continue;
 
-        return !m_next.is_empty();
+        return !m_next->name.is_empty();
     }
 }
 
 bool DirIterator::has_next()
 {
-    if (!m_next.is_null())
+    if (m_next.has_value())
         return true;
 
     return advance_next();
 }
 
-DeprecatedString DirIterator::next_path()
+Optional<DirectoryEntry> DirIterator::next()
 {
-    if (m_next.is_null())
+    if (!m_next.has_value())
         advance_next();
 
-    auto tmp = m_next;
-    m_next = DeprecatedString();
-    return tmp;
+    auto result = m_next;
+    m_next.clear();
+    return result;
+}
+
+DeprecatedString DirIterator::next_path()
+{
+    auto entry = next();
+    if (entry.has_value())
+        return entry->name;
+    return "";
 }
 
 DeprecatedString DirIterator::next_full_path()

+ 4 - 1
Userland/Libraries/LibCore/DirIterator.h

@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
+ * Copyright (c) 2023, Sam Atkins <atkinssj@serenityos.org>
  *
  * SPDX-License-Identifier: BSD-2-Clause
  */
@@ -7,6 +8,7 @@
 #pragma once
 
 #include <AK/DeprecatedString.h>
+#include <LibCore/DirectoryEntry.h>
 #include <dirent.h>
 #include <string.h>
 
@@ -30,6 +32,7 @@ public:
     int error() const { return m_error; }
     char const* error_string() const { return strerror(m_error); }
     bool has_next();
+    Optional<DirectoryEntry> next();
     DeprecatedString next_path();
     DeprecatedString next_full_path();
     int fd() const;
@@ -37,7 +40,7 @@ public:
 private:
     DIR* m_dir = nullptr;
     int m_error = 0;
-    DeprecatedString m_next;
+    Optional<DirectoryEntry> m_next;
     DeprecatedString m_path;
     int m_flags;
 

+ 45 - 0
Userland/Libraries/LibCore/DirectoryEntry.cpp

@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2023, Sam Atkins <atkinssj@serenityos.org>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include "DirectoryEntry.h"
+#include <dirent.h>
+
+namespace Core {
+
+static DirectoryEntry::Type directory_entry_type_from_posix(unsigned char dt_constant)
+{
+    switch (dt_constant) {
+    case DT_UNKNOWN:
+        return DirectoryEntry::Type::Unknown;
+    case DT_FIFO:
+        return DirectoryEntry::Type::NamedPipe;
+    case DT_CHR:
+        return DirectoryEntry::Type::CharacterDevice;
+    case DT_DIR:
+        return DirectoryEntry::Type::Directory;
+    case DT_BLK:
+        return DirectoryEntry::Type::BlockDevice;
+    case DT_REG:
+        return DirectoryEntry::Type::File;
+    case DT_LNK:
+        return DirectoryEntry::Type::SymbolicLink;
+    case DT_SOCK:
+        return DirectoryEntry::Type::Socket;
+    case DT_WHT:
+        return DirectoryEntry::Type::Whiteout;
+    }
+    VERIFY_NOT_REACHED();
+}
+
+DirectoryEntry DirectoryEntry::from_dirent(dirent const& de)
+{
+    return DirectoryEntry {
+        .type = directory_entry_type_from_posix(de.d_type),
+        .name = de.d_name,
+    };
+};
+
+}

+ 34 - 0
Userland/Libraries/LibCore/DirectoryEntry.h

@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2023, Sam Atkins <atkinssj@serenityos.org>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#pragma once
+
+#include <AK/DeprecatedString.h>
+
+struct dirent;
+
+namespace Core {
+
+struct DirectoryEntry {
+    enum class Type {
+        BlockDevice,
+        CharacterDevice,
+        Directory,
+        File,
+        NamedPipe,
+        Socket,
+        SymbolicLink,
+        Unknown,
+        Whiteout,
+    };
+    Type type;
+    // FIXME: Once we have a special Path string class, use that.
+    DeprecatedString name;
+
+    static DirectoryEntry from_dirent(dirent const&);
+};
+
+}