From 2cdb2cac44a07fa5db72408f62427a64f32c1d90 Mon Sep 17 00:00:00 2001 From: Dominick Allen Date: Wed, 2 Oct 2024 08:30:08 -0500 Subject: Add permissions model for files. --- CMakeLists.txt | 1 + include/fud_c_file.hpp | 44 +++++++++- include/fud_permissions.hpp | 191 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 235 insertions(+), 1 deletion(-) create mode 100644 include/fud_permissions.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 7c44675..d17a027 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -98,6 +98,7 @@ set(FUD_HEADERS "include/fud_utf8_iterator.hpp" "include/fud_sqlite.hpp" "include/fud_directory.hpp" + "include/fud_permissions.hpp" ) set_target_properties(fud PROPERTIES PUBLIC_HEADER "${FUD_HEADERS}") diff --git a/include/fud_c_file.hpp b/include/fud_c_file.hpp index 45a8b54..f451292 100644 --- a/include/fud_c_file.hpp +++ b/include/fud_c_file.hpp @@ -21,9 +21,13 @@ #include "fud_result.hpp" #include "fud_status.hpp" #include "fud_string.hpp" +#include "fud_permissions.hpp" #include #include +#include +#include +#include namespace fud { @@ -109,6 +113,27 @@ class CFile { return self.m_file != nullptr ? FudStatus::Success : FudStatus::Failure; } + FudStatus create(Permissions permissions) + { + auto& self = static_cast(*this); + if (self.m_modeFlags == CFileMode::ReadOnly || self.m_modeFlags == CFileMode::ReadWrite) { + return FudStatus::OperationInvalid; + } + + if (!self.m_filename.valid()) { + return FudStatus::ObjectInvalid; + } + + auto fdResult = ::open(self.m_filename.c_str(), O_CREAT, permissions.mode()); + if (fdResult == -1) { + return FudStatus::Failure; + } + ::close(fdResult); + + self.m_file = fopen(self.m_filename.c_str(), self.m_mode.c_str()); + return self.m_file != nullptr ? FudStatus::Success : FudStatus::Failure; + } + void close() { auto& self = static_cast(*this); @@ -130,6 +155,22 @@ class CFile { return self.m_file; } + FudStatus setPermissions(Permissions permissions) { + auto& self = static_cast(*this); + if (!self.isOpen()) { + return FudStatus::OperationInvalid; + } + auto descriptor = fileno(self.file()); + if (descriptor == -1) { + return FudStatus::ObjectInvalid; + } + auto result = fchmod(descriptor, permissions()); + if (result != 0) { + return FudStatus::Failure; + } + return FudStatus::Success; + } + [[nodiscard]] Result size() const { const auto& self = static_cast(*this); @@ -311,7 +352,8 @@ class CFile { auto& self = static_cast(*this); return self.write(static_cast(&source), sourceSize, length, offset); } -private: + + private: FudStatus reset() const { const auto& self = static_cast(*this); diff --git a/include/fud_permissions.hpp b/include/fud_permissions.hpp new file mode 100644 index 0000000..66eec0c --- /dev/null +++ b/include/fud_permissions.hpp @@ -0,0 +1,191 @@ +/* + * libfud + * Copyright 2024 Dominick Allen + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FUD_PERMISSIONS_HPP +#define FUD_PERMISSIONS_HPP + +#include +#include +#include +#include + +namespace fud { + +static_assert(CHAR_BIT == 8, "Assume that uint8_t has 8 bits"); +static_assert(sizeof(uint8_t) == 1, "Assume that uint8_t is 1 byte"); + +enum class PermissionType : uint8_t +{ + None = 0x00, + Exec = 0x01, + Write = 0x02, + Read = 0x04 +}; + +struct PermissionField { + explicit constexpr PermissionField(PermissionType permissionType) : + m_permissions{static_cast(permissionType)} + { + } + + constexpr PermissionField(PermissionType lhs, PermissionType rhs) + { + m_permissions = static_cast(lhs) | static_cast(rhs); + } + + constexpr PermissionField(PermissionType lhs, PermissionField rhs) + { + m_permissions = static_cast(lhs) | rhs.m_permissions; + } + + constexpr PermissionField(PermissionField lhs, PermissionType rhs) + { + m_permissions = lhs.m_permissions | static_cast(rhs); + } + + constexpr PermissionField(PermissionField lhs, PermissionField rhs) + { + m_permissions = lhs.m_permissions | rhs.m_permissions; + } + + constexpr uint16_t operator()() + { + return m_permissions; + } + + uint8_t m_permissions{}; +}; + +enum class PermissionSpecialType : uint8_t +{ + None = 0x00, + Sticky = 0x01, + SetGroupId = 0x02, + SetUserId = 0x04 +}; + +struct PermissionSpecial { + explicit constexpr PermissionSpecial(PermissionSpecialType permissionType) : + m_permissions{static_cast(permissionType)} + { + } + + constexpr PermissionSpecial(PermissionSpecialType lhs, PermissionSpecialType rhs) + { + m_permissions = static_cast(lhs) | static_cast(rhs); + } + + constexpr PermissionSpecial(PermissionSpecialType lhs, PermissionSpecial rhs) + { + m_permissions = static_cast(lhs) | rhs.m_permissions; + } + + constexpr PermissionSpecial(PermissionSpecial lhs, PermissionSpecialType rhs) + { + m_permissions = lhs.m_permissions | static_cast(rhs); + } + + constexpr PermissionSpecial(PermissionSpecial lhs, PermissionSpecial rhs) + { + m_permissions = lhs.m_permissions | rhs.m_permissions; + } + + constexpr uint16_t operator()() + { + return m_permissions; + } + + uint8_t m_permissions{0}; +}; + +class Permissions { + public: + static constexpr uint8_t GroupShift = 3; + static constexpr uint8_t UserShift = GroupShift + 3; + static constexpr uint8_t SpecialShift = UserShift + 3; + + constexpr Permissions(PermissionField user, PermissionField group, PermissionField others) + { + m_permissions = user() << UserShift | group() << GroupShift | others(); + } + + template + constexpr Permissions(U user, G group, O others) + { + m_permissions = PermissionField{user}() << UserShift | PermissionField{group}() << GroupShift | + PermissionField{others}(); + } + + constexpr Permissions( + PermissionField user, + PermissionField group, + PermissionField others, + PermissionSpecial special) + { + m_permissions = special() << SpecialShift | user() << UserShift | group() << GroupShift | others(); + } + + template + constexpr Permissions( + PermissionField user, + PermissionField group, + PermissionField others, + PermissionSpecial special) + { + m_permissions = special() << SpecialShift | PermissionField{user}() << UserShift | + PermissionField{group}() << GroupShift | PermissionField{others}(); + } + + constexpr int32_t operator()() + { + return m_permissions; + } + + constexpr mode_t mode() + { + return static_cast(m_permissions); + } + + private: + int32_t m_permissions{0}; +}; + +constexpr PermissionField operator|(PermissionType lhs, PermissionType rhs) +{ + return PermissionField{lhs, rhs}; +} + +constexpr PermissionField operator|(PermissionType lhs, PermissionField rhs) +{ + return PermissionField{lhs, rhs}; +} + +constexpr PermissionField operator|(PermissionField lhs, PermissionType rhs) +{ + return PermissionField{lhs, rhs}; +} + +constexpr PermissionField operator|(PermissionField lhs, PermissionField rhs) +{ + return PermissionField{lhs, rhs}; +} + +constexpr PermissionField PermReadWrite = PermissionType::Read | PermissionType::Write; + +} // namespace fud + +#endif -- cgit v1.2.3