From a031b7a17432632a77f878cc193ccade181e78c9 Mon Sep 17 00:00:00 2001 From: Tim Schumacher Date: Sun, 24 Jul 2022 18:59:14 +0200 Subject: [PATCH] chmod: Implement the `--recursive` flag --- Userland/Utilities/chmod.cpp | 31 +++++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/Userland/Utilities/chmod.cpp b/Userland/Utilities/chmod.cpp index 95019b49e9..5edb749970 100644 --- a/Userland/Utilities/chmod.cpp +++ b/Userland/Utilities/chmod.cpp @@ -8,6 +8,7 @@ #include #include +#include #include #include #include @@ -18,17 +19,43 @@ ErrorOr serenity_main(Main::Arguments arguments) StringView mode; Vector paths; + bool recursive = false; Core::ArgsParser args_parser; + args_parser.add_option(recursive, "Change file modes recursively", "recursive", 'R'); args_parser.add_positional_argument(mode, "File mode in octal or symbolic notation", "mode"); args_parser.add_positional_argument(paths, "Paths to file", "paths"); args_parser.parse(arguments); auto mask = TRY(Core::FilePermissionsMask::parse(mode)); + Function(StringView const&)> update_path_permissions = [&](StringView const& path) -> ErrorOr { + auto stat = TRY(Core::System::lstat(path)); + + if (S_ISLNK(stat.st_mode)) { + // Symlinks don't get processed unless they are explicitly listed on the command line. + if (!paths.contains_slow(path)) + return {}; + + // The chmod syscall changes the file that a link points to, so we will have to get + // the correct mode to base our modifications on. + stat = TRY(Core::System::stat(path)); + } + + TRY(Core::System::chmod(path, mask.apply(stat.st_mode))); + + if (recursive && S_ISDIR(stat.st_mode)) { + Core::DirIterator it(path, Core::DirIterator::Flags::SkipParentAndBaseDir); + + while (it.has_next()) + TRY(update_path_permissions(it.next_full_path())); + } + + return {}; + }; + for (auto const& path : paths) { - auto current_access = TRY(Core::System::stat(path)); - TRY(Core::System::chmod(path, mask.apply(current_access.st_mode))); + TRY(update_path_permissions(path)); } return 0;