From 09099cc9a309050d1fe73663df141e25eb2b51d6 Mon Sep 17 00:00:00 2001 From: Tim Ledbetter Date: Tue, 26 Sep 2023 18:28:15 +0100 Subject: [PATCH] du: Prevent multiple counting of the same file Previously, the same file would be counted more than once if its containing directory was visited multiple times, or there were multiple hard links pointing to it. We now keep track of every visited inode to ensure that files aren't evaluated multiple times. This matches the behavior of `du` on FreeBSD and Linux. --- Userland/Utilities/du.cpp | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/Userland/Utilities/du.cpp b/Userland/Utilities/du.cpp index 829e98a3e4..737ac83dff 100644 --- a/Userland/Utilities/du.cpp +++ b/Userland/Utilities/du.cpp @@ -36,6 +36,26 @@ struct DuOption { size_t max_depth = SIZE_MAX; }; +struct VisitedFile { + dev_t device; + ino_t inode; +}; + +template<> +struct AK::Traits : public GenericTraits { + static unsigned hash(VisitedFile const& visited_file) + { + return pair_int_hash(u64_hash(visited_file.device), u64_hash(visited_file.inode)); + } + + static bool equals(VisitedFile const& a, VisitedFile const& b) + { + return a.device == b.device && a.inode == b.inode; + } +}; + +static HashTable s_visited_files; + static ErrorOr parse_args(Main::Arguments arguments, Vector& files, DuOption& du_option); static u64 print_space_usage(DeprecatedString const& path, DuOption const& du_option, size_t current_depth, bool inside_dir = false); @@ -144,6 +164,13 @@ u64 print_space_usage(DeprecatedString const& path, DuOption const& du_option, s } auto path_stat = path_stat_or_error.release_value(); + + VisitedFile visited_file { path_stat.st_dev, path_stat.st_ino }; + if (s_visited_files.contains(visited_file)) { + return 0; + } + s_visited_files.set(visited_file); + bool const is_directory = S_ISDIR(path_stat.st_mode); if (is_directory) { auto di = Core::DirIterator(path, Core::DirIterator::SkipParentAndBaseDir);