From 307dc00ee02e9f40b11d3888f4ccda6b03944f43 Mon Sep 17 00:00:00 2001 From: Tim Ledbetter Date: Mon, 19 Jun 2023 18:20:21 +0100 Subject: [PATCH] rmdir: Add `-p` option to remove all directories in each given path --- Base/usr/share/man/man1/rmdir.md | 7 +++++++ Userland/Utilities/rmdir.cpp | 36 +++++++++++++++++++++++++------- 2 files changed, 36 insertions(+), 7 deletions(-) diff --git a/Base/usr/share/man/man1/rmdir.md b/Base/usr/share/man/man1/rmdir.md index 6624724cf4..fd60ee808a 100644 --- a/Base/usr/share/man/man1/rmdir.md +++ b/Base/usr/share/man/man1/rmdir.md @@ -12,6 +12,10 @@ $ rmdir `[directory...]` Remove given `directory(ies)`, if they are empty +## Options + +* `-p`, `--parents`: Remove all directories in each given path + ## Arguments * `directory`: directory(ies) to remove @@ -31,4 +35,7 @@ $ ls -a example $ rmdir example $ ls -a example example: No such file or directory + +# Removes foo/bar/baz/, foo/bar/ and foo/ +$ rmdir -p foo/bar/baz/ ``` diff --git a/Userland/Utilities/rmdir.cpp b/Userland/Utilities/rmdir.cpp index 7cc1d6c895..e7c124e460 100644 --- a/Userland/Utilities/rmdir.cpp +++ b/Userland/Utilities/rmdir.cpp @@ -1,33 +1,55 @@ /* * Copyright (c) 2018-2020, Andreas Kling + * Copyright (c) 2023, Tim Ledbetter * * SPDX-License-Identifier: BSD-2-Clause */ +#include #include #include #include #include -#include -#include ErrorOr serenity_main(Main::Arguments arguments) { TRY(Core::System::pledge("stdio cpath")); - Vector paths; + bool remove_parents = false; + Vector paths; Core::ArgsParser args_parser; + args_parser.add_option(remove_parents, "Remove all directories in each given path", "parents", 'p'); args_parser.add_positional_argument(paths, "Directories to remove", "paths"); args_parser.parse(arguments); int status = 0; - for (auto path : paths) { - int rc = rmdir(path.characters()); - if (rc < 0) { - perror("rmdir"); + + auto remove_directory = [&](StringView path) { + auto maybe_error = Core::System::rmdir(path); + if (maybe_error.is_error()) { + warnln("Failed to remove '{}': {}", path, maybe_error.release_error()); status = 1; } + + return !maybe_error.is_error(); + }; + + for (auto path : paths) { + if (!remove_directory(path) || !remove_parents) + continue; + + LexicalPath lexical_path(path); + auto const& path_parts = lexical_path.parts_view(); + if (path_parts.size() < 2) + continue; + + for (size_t i = path_parts.size() - 1; i > 0; --i) { + auto current_path_parts = path_parts.span().slice(0, i); + LexicalPath current_path { DeprecatedString::join('/', current_path_parts) }; + if (!remove_directory(current_path.string())) + break; + } } return status; }