diff options
author | Xavier Defrang <xavier.defrang@gmail.com> | 2021-12-24 15:34:30 +0100 |
---|---|---|
committer | Brian Gianforcaro <b.gianfo@gmail.com> | 2022-01-01 17:33:43 +0000 |
commit | 8b95423b5027e3363a3d7fc5e796bc4bf8a0ea15 (patch) | |
tree | 0d6b95182dcebd9216c7d98b5a23768211e37dc0 /Userland/Libraries/LibCore/FilePermissionsMask.cpp | |
parent | 0f729cebf4ff08b8d625c300a00be32241dbe27a (diff) | |
download | serenity-8b95423b5027e3363a3d7fc5e796bc4bf8a0ea15.zip |
LibCore: Add FilePermissionsMask
This class parses UNIX file permissions definitions in numeric (octal)
or symbolic (ugoa+rwx) format and can apply them on a given file mode.
Diffstat (limited to 'Userland/Libraries/LibCore/FilePermissionsMask.cpp')
-rw-r--r-- | Userland/Libraries/LibCore/FilePermissionsMask.cpp | 151 |
1 files changed, 151 insertions, 0 deletions
diff --git a/Userland/Libraries/LibCore/FilePermissionsMask.cpp b/Userland/Libraries/LibCore/FilePermissionsMask.cpp new file mode 100644 index 0000000000..1b6cdfc164 --- /dev/null +++ b/Userland/Libraries/LibCore/FilePermissionsMask.cpp @@ -0,0 +1,151 @@ +/* + * Copyright (c) 2021, Xavier Defrang <xavier.defrang@gmail.com> + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include <AK/Assertions.h> +#include <AK/CharacterTypes.h> +#include <AK/StringUtils.h> + +#include <LibCore/FilePermissionsMask.h> + +namespace Core { + +enum State { + Reference, + Mode +}; + +enum ClassFlag { + Other = 1, + Group = 2, + User = 4 +}; + +enum Operation { + Add, + Remove, + Assign, +}; + +ErrorOr<FilePermissionsMask> FilePermissionsMask::parse(StringView string) +{ + return (!string.is_empty() && is_ascii_digit(string[0])) + ? from_numeric_notation(string) + : from_symbolic_notation(string); +} + +ErrorOr<FilePermissionsMask> FilePermissionsMask::from_numeric_notation(StringView string) +{ + mode_t mode = AK::StringUtils::convert_to_uint_from_octal<u16>(string).value_or(01000); + if (mode > 0777) + return Error::from_string_literal("invalid octal representation"sv); + return FilePermissionsMask().assign_permissions(mode); +} + +ErrorOr<FilePermissionsMask> FilePermissionsMask::from_symbolic_notation(StringView string) +{ + auto mask = FilePermissionsMask(); + + u8 state = State::Reference; + u8 classes = 0; + u8 operation = 0; + + for (auto ch : string) { + switch (state) { + case State::Reference: { + // one or more [ugoa] terminated by one operator [+-=] + if (ch == 'u') + classes |= ClassFlag::User; + else if (ch == 'g') + classes |= ClassFlag::Group; + else if (ch == 'o') + classes |= ClassFlag::Other; + else if (ch == 'a') + classes = ClassFlag::User | ClassFlag::Group | ClassFlag::Other; + else { + if (classes == 0) + return Error::from_string_literal("invalid access class: expected 'u', 'g', 'o' or 'a' "sv); + + if (ch == '+') + operation = Operation::Add; + else if (ch == '-') + operation = Operation::Remove; + else if (ch == '=') + operation = Operation::Assign; + else + return Error::from_string_literal("invalid operation: expected '+', '-' or '='"sv); + + state = State::Mode; + } + + break; + } + + case State::Mode: { + // one or more [rwx] terminated by a comma + + // End of mode part, expect reference next + if (ch == ',') { + state = State::Reference; + classes = operation = 0; + continue; + } + + mode_t write_bits = 0; + + if (ch == 'r') + write_bits = 4; + else if (ch == 'w') + write_bits = 2; + else if (ch == 'x') + write_bits = 1; + else + return Error::from_string_literal("invalid symbolic permission"sv); + + mode_t clear_bits = operation == Operation::Assign ? 7 : write_bits; + + // Update masks one class at a time in other, group, user order + for (auto cls = classes; cls != 0; cls >>= 1) { + if (cls & 1) { + if (operation == Operation::Add || operation == Operation::Assign) + mask.add_permissions(write_bits); + if (operation == Operation::Remove || operation == Operation::Assign) + mask.remove_permissions(clear_bits); + } + write_bits <<= 3; + clear_bits <<= 3; + } + + break; + } + + default: + VERIFY_NOT_REACHED(); + } + } + + return mask; +} + +FilePermissionsMask& FilePermissionsMask::assign_permissions(mode_t mode) +{ + m_write_mask = mode; + m_clear_mask = 0777; + return *this; +} + +FilePermissionsMask& FilePermissionsMask::add_permissions(mode_t mode) +{ + m_write_mask |= mode; + return *this; +} + +FilePermissionsMask& FilePermissionsMask::remove_permissions(mode_t mode) +{ + m_clear_mask |= mode; + return *this; +} + +} |