diff options
author | Xavier Defrang <xavier.defrang@gmail.com> | 2021-12-25 11:02:56 +0100 |
---|---|---|
committer | Brian Gianforcaro <b.gianfo@gmail.com> | 2022-01-01 17:33:43 +0000 |
commit | 005b0f73849e3f9b4d0a0c069bf70caaea102e84 (patch) | |
tree | 92997b4ef63941d4d5c8a790811fdf455457e07f /Userland/Utilities | |
parent | 8b95423b5027e3363a3d7fc5e796bc4bf8a0ea15 (diff) | |
download | serenity-005b0f73849e3f9b4d0a0c069bf70caaea102e84.zip |
chmod: Use FilePermissionsMask to handle mode argument
Diffstat (limited to 'Userland/Utilities')
-rw-r--r-- | Userland/Utilities/chmod.cpp | 218 |
1 files changed, 6 insertions, 212 deletions
diff --git a/Userland/Utilities/chmod.cpp b/Userland/Utilities/chmod.cpp index bed9f0d16d..f73f5caa7f 100644 --- a/Userland/Utilities/chmod.cpp +++ b/Userland/Utilities/chmod.cpp @@ -1,6 +1,7 @@ /* * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> * Copyright (c) 2021, Kenneth Myhra <kennethmyhra@gmail.com> + * Copyright (c) 2021, Xavier Defrang <xavier.defrang@gmail.com> * * SPDX-License-Identifier: BSD-2-Clause */ @@ -10,61 +11,16 @@ #include <AK/String.h> #include <AK/StringUtils.h> #include <AK/Vector.h> +#include <LibCore/FilePermissionsMask.h> #include <LibCore/System.h> #include <LibMain/Main.h> #include <stdio.h> #include <string.h> #include <sys/stat.h> -/* the new mode will be computed using the boolean function(for each bit): - - |current mode|removal mask|applying mask|result | - | 0 | 0 | 0 | 0 | - | 0 | 0 | 1 | 1 | - | 0 | 1 | 0 | 0 | - | 0 | 1 | 1 | 1 | ---> find the CNF --> find the minimal CNF - | 1 | 0 | 0 | 1 | - | 1 | 0 | 1 | 1 | - | 1 | 1 | 0 | 0 | - | 1 | 1 | 1 | 1 | -*/ - -class Mask { -private: - mode_t removal_mask; // the bits that will be removed - mode_t applying_mask; // the bits that will be set - -public: - Mask() - : removal_mask(0) - , applying_mask(0) - { - } - - Mask& operator|=(const Mask& other) - { - removal_mask |= other.removal_mask; - applying_mask |= other.applying_mask; - - return *this; - } - - mode_t& get_removal_mask() { return removal_mask; } - mode_t& get_applying_mask() { return applying_mask; } - - void set_mode(mode_t mode) - { - this->applying_mask = mode; - this->removal_mask = ~mode; - } -}; - -Optional<Mask> string_to_mode(char access_scope, StringView access_string); -Optional<Mask> apply_permission(char access_scope, char permission, char operation); - ErrorOr<int> serenity_main(Main::Arguments arguments) { - TRY(Core::System::pledge("stdio rpath fattr", nullptr)); + TRY(Core::System::pledge("stdio rpath fattr")); if (arguments.strings.size() < 3) { warnln("usage: chmod <octal-mode> <path...>"); @@ -72,174 +28,12 @@ ErrorOr<int> serenity_main(Main::Arguments arguments) return 1; } - Mask mask; + auto mask = TRY(Core::FilePermissionsMask::parse(arguments.strings[1])); - /* compute a mask */ - - auto mode_string = arguments.strings[1]; - if (mode_string[0] >= '0' && mode_string[0] <= '7') { - mode_t mode = AK::StringUtils::convert_to_uint_from_octal<u16>(mode_string).value_or(01000); - if (mode > 0777) { - warnln("chmod: invalid mode: {}", mode_string); - return 1; - } - mask.set_mode(mode); - } else { - auto access_strings = arguments.strings[1].split_view(','); - for (auto access_string : access_strings) { - Optional<Mask> tmp_mask; - switch (access_string[0]) { - case 'u': - tmp_mask = string_to_mode('u', access_string); - break; - case 'g': - tmp_mask = string_to_mode('g', access_string); - break; - case 'o': - tmp_mask = string_to_mode('o', access_string); - break; - case 'a': - tmp_mask = string_to_mode('a', access_string); - break; - case '=': - case '+': - case '-': - tmp_mask = string_to_mode('a', access_string); - break; - } - if (!tmp_mask.has_value()) { - warnln("chmod: invalid mode: {}", arguments.strings[1]); - return 1; - } - mask |= tmp_mask.value(); - } - } - - /* set the mask for each file's permissions */ - size_t i = 2; - while (i < arguments.strings.size()) { + for (size_t i = 2; i < arguments.strings.size(); ++i) { auto current_access = TRY(Core::System::stat(arguments.strings[i])); - /* found the minimal CNF by The Quine–McCluskey algorithm and use it */ - mode_t mode = mask.get_applying_mask() - | (current_access.st_mode & ~mask.get_removal_mask()); - TRY(Core::System::chmod(arguments.strings[i++], mode)); + TRY(Core::System::chmod(arguments.strings[i], mask.apply(current_access.st_mode))); } return 0; } - -Optional<Mask> string_to_mode(char access_scope, StringView access_string) -{ - auto get_operation = [](StringView s) { - for (auto c : s) { - if (c == '+' || c == '-' || c == '=') - return c; - } - return ' '; - }; - - auto operation = get_operation(access_string); - if (operation == ' ') { - return {}; - } - - Mask mask; - if (operation == '=') { - switch (access_scope) { - case 'u': - mask.get_removal_mask() = (S_IRUSR | S_IWUSR | S_IXUSR); - break; - case 'g': - mask.get_removal_mask() = (S_IRGRP | S_IWGRP | S_IXGRP); - break; - case 'o': - mask.get_removal_mask() = (S_IROTH | S_IWOTH | S_IXOTH); - break; - case 'a': - mask.get_removal_mask() = (S_IRUSR | S_IWUSR | S_IXUSR - | S_IRGRP | S_IWGRP | S_IXGRP - | S_IROTH | S_IWOTH | S_IXOTH); - break; - } - operation = '+'; - } - - for (size_t i = 1; i < access_string.length(); i++) { - char permission = access_string[i]; - if (permission == '+' || permission == '-' || permission == '=') - continue; - - Optional<Mask> tmp_mask; - tmp_mask = apply_permission(access_scope, permission, operation); - if (!tmp_mask.has_value()) { - return {}; - } - mask |= tmp_mask.value(); - } - - return mask; -} - -Optional<Mask> apply_permission(char access_scope, char permission, char operation) -{ - if (permission != 'r' && permission != 'w' && permission != 'x') { - return {}; - } - - Mask mask; - mode_t tmp_mask = 0; - switch (access_scope) { - case 'u': - switch (permission) { - case 'r': - tmp_mask = S_IRUSR; - break; - case 'w': - tmp_mask = S_IWUSR; - break; - case 'x': - tmp_mask = S_IXUSR; - break; - } - break; - case 'g': - switch (permission) { - case 'r': - tmp_mask = S_IRGRP; - break; - case 'w': - tmp_mask = S_IWGRP; - break; - case 'x': - tmp_mask = S_IXGRP; - break; - } - break; - case 'o': - switch (permission) { - case 'r': - tmp_mask = S_IROTH; - break; - case 'w': - tmp_mask = S_IWOTH; - break; - case 'x': - tmp_mask = S_IXOTH; - break; - } - break; - case 'a': - mask |= apply_permission('u', permission, operation).value(); - mask |= apply_permission('g', permission, operation).value(); - mask |= apply_permission('o', permission, operation).value(); - break; - } - - if (operation == '+') { - mask.get_applying_mask() |= tmp_mask; - } else { - mask.get_removal_mask() |= tmp_mask; - } - - return mask; -} |