diff --git a/Base/usr/share/man/man1/du.md b/Base/usr/share/man/man1/du.md index b9b672a340..a1c0d510f0 100644 --- a/Base/usr/share/man/man1/du.md +++ b/Base/usr/share/man/man1/du.md @@ -23,6 +23,7 @@ $ du [files...] * `-t size`, `--threshold size`: Exclude entries smaller than size if positive, or entries greater than size if negative * `--time time-type`: Show time of time time-type of any file in the directory, or any of its subdirectories. Available choices: mtime, modification, ctime, status, use, atime, access * `--exclude pattern`: Exclude files that match pattern +* `-x`, `--one-file-system`: Don't traverse directories on different file systems * `-X file, --exclude-from`: Exclude files that match any pattern in file ## Arguments diff --git a/Userland/Utilities/du.cpp b/Userland/Utilities/du.cpp index 70fcea238f..38d2ddf14b 100644 --- a/Userland/Utilities/du.cpp +++ b/Userland/Utilities/du.cpp @@ -29,6 +29,7 @@ struct DuOption { bool human_readable_si = false; bool all = false; bool apparent_size = false; + bool one_file_system = false; i64 threshold = 0; TimeType time_type = TimeType::NotUsed; Vector excluded_patterns; @@ -57,7 +58,7 @@ struct AK::Traits : public GenericTraits { 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); +static u64 print_space_usage(DeprecatedString const& path, DuOption const& du_option, size_t current_depth, Optional root_device = {}); ErrorOr serenity_main(Main::Arguments arguments) { @@ -124,6 +125,7 @@ ErrorOr parse_args(Main::Arguments arguments, Vector& fi args_parser.add_option(move(time_option)); args_parser.add_option(pattern, "Exclude files that match pattern", "exclude", 0, "pattern"); args_parser.add_option(exclude_from, "Exclude files that match any pattern in file", "exclude-from", 'X', "file"); + args_parser.add_option(du_option.one_file_system, "Don't traverse directories on different file systems", "one-file-system", 'x'); args_parser.add_option(du_option.block_size, "Outputs file sizes as the required blocks with the given size (defaults to 1024)", "block-size", 'B', "size"); args_parser.add_option(move(block_size_1k_option)); args_parser.add_positional_argument(files_to_process, "File to process", "file", Core::ArgsParser::Required::No); @@ -154,7 +156,7 @@ ErrorOr parse_args(Main::Arguments arguments, Vector& fi return {}; } -u64 print_space_usage(DeprecatedString const& path, DuOption const& du_option, size_t current_depth) +u64 print_space_usage(DeprecatedString const& path, DuOption const& du_option, size_t current_depth, Optional root_device) { u64 size = 0; auto path_stat_or_error = Core::System::lstat(path); @@ -165,6 +167,14 @@ u64 print_space_usage(DeprecatedString const& path, DuOption const& du_option, s auto path_stat = path_stat_or_error.release_value(); + if (!root_device.has_value()) { + root_device = path_stat.st_dev; + } + + if (du_option.one_file_system && root_device.value() != path_stat.st_dev) { + return 0; + } + VisitedFile visited_file { path_stat.st_dev, path_stat.st_ino }; if (s_visited_files.contains(visited_file)) { return 0; @@ -182,7 +192,7 @@ u64 print_space_usage(DeprecatedString const& path, DuOption const& du_option, s while (di.has_next()) { auto const child_path = di.next_full_path(); - size += print_space_usage(child_path, du_option, current_depth + 1); + size += print_space_usage(child_path, du_option, current_depth + 1, root_device); } }