From 23aec16e8b0186171b471b375d6fa172efd2ed1d Mon Sep 17 00:00:00 2001 From: Sam Atkins Date: Thu, 2 Mar 2023 17:01:08 +0000 Subject: [PATCH] LibCore: Introduce a new directory iteration API `Core::Directory::for_each_entry()` takes a callback which is passed the DirectoryEntry and the parent Directory. It returns any error from creating the iterator, iterating the entries, or returned from the callback. As a simple example, this: ```c++ Core::DirIterator piece_set_iterator { "/res/icons/chess/sets/", Core::DirIterator::SkipParentAndBaseDir }; while (piece_set_iterator.has_next()) m_piece_sets.append(piece_set_iterator.next_path()); ``` becomes this: ```c++ TRY(Core::Directory::for_each_entry("/res/icons/chess/sets/"sv, Core::DirIterator::SkipParentAndBaseDir, [&](auto const& entry, auto&) -> ErrorOr { TRY(m_piece_sets.try_append(entry.name)); return IterationDecision::Continue; })); ``` --- Userland/Libraries/LibCore/Directory.cpp | 28 ++++++++++++++++++++++++ Userland/Libraries/LibCore/Directory.h | 11 ++++++++-- 2 files changed, 37 insertions(+), 2 deletions(-) diff --git a/Userland/Libraries/LibCore/Directory.cpp b/Userland/Libraries/LibCore/Directory.cpp index e63207c7fe..cbfd048fc7 100644 --- a/Userland/Libraries/LibCore/Directory.cpp +++ b/Userland/Libraries/LibCore/Directory.cpp @@ -93,4 +93,32 @@ ErrorOr Directory::stat() const return System::fstat(m_directory_fd); } +ErrorOr Directory::for_each_entry(DirIterator::Flags flags, Core::Directory::ForEachEntryCallback callback) +{ + DirIterator iterator { path().string(), flags }; + if (iterator.has_error()) + return iterator.error(); + + while (iterator.has_next()) { + if (iterator.has_error()) + return iterator.error(); + + auto entry = iterator.next(); + if (!entry.has_value()) + break; + + auto decision = TRY(callback(entry.value(), *this)); + if (decision == IterationDecision::Break) + break; + } + + return {}; +} + +ErrorOr Directory::for_each_entry(AK::StringView path, DirIterator::Flags flags, Core::Directory::ForEachEntryCallback callback) +{ + auto directory = TRY(Directory::create(path, CreateDirectories::No)); + return directory.for_each_entry(flags, move(callback)); +} + } diff --git a/Userland/Libraries/LibCore/Directory.h b/Userland/Libraries/LibCore/Directory.h index ccc97e0714..ec04cc714a 100644 --- a/Userland/Libraries/LibCore/Directory.h +++ b/Userland/Libraries/LibCore/Directory.h @@ -1,5 +1,6 @@ /* * Copyright (c) 2022, kleines Filmröllchen + * Copyright (c) 2023, Sam Atkins * * SPDX-License-Identifier: BSD-2-Clause */ @@ -8,17 +9,19 @@ #include #include +#include +#include #include #include #include +#include +#include #include #include #include namespace Core { -class DirIterator; - // Deal with real system directories. Any Directory instance always refers to a valid existing directory. class Directory { AK_MAKE_NONCOPYABLE(Directory); @@ -43,6 +46,10 @@ public: LexicalPath const& path() const { return m_path; } + using ForEachEntryCallback = Function(DirectoryEntry const&, Directory const& parent)>; + static ErrorOr for_each_entry(StringView path, DirIterator::Flags, ForEachEntryCallback); + ErrorOr for_each_entry(DirIterator::Flags, ForEachEntryCallback); + ErrorOr chown(uid_t, gid_t); static ErrorOr is_valid_directory(int fd);