diff --git a/CMakeLists.txt b/CMakeLists.txt index 5cf540d..969d358 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,6 +10,16 @@ include (nc) include_directories(.) +############################################################################### +add_library(emory + acl.cpp + acl.hpp +) + + +target_link_libraries(emory cruft acl) + + ############################################################################### option (TESTS "enable unit testing" ON) if (TESTS) @@ -25,5 +35,5 @@ add_subdirectory(cruft/crypto) ############################################################################### foreach (t analyse compare stat) add_executable ("${t}" "tools/${t}.cpp") - target_link_libraries("${t}" cruft-crypto cruft-util) + target_link_libraries("${t}" emory cruft-crypto cruft) endforeach() diff --git a/acl.cpp b/acl.cpp new file mode 100644 index 0000000..46501b3 --- /dev/null +++ b/acl.cpp @@ -0,0 +1,227 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Copyright 2019, Danny Robson + */ + +#include "acl.hpp" + +#include + +#include +#include +#include + + +using cruft::acl; +using cruft::entry; +using cruft::permset; + + +/////////////////////////////////////////////////////////////////////////////// +acl::acl (int count) + : acl (acl_init (count)) +{ ; } + + +//----------------------------------------------------------------------------- +acl::acl (std::filesystem::path const &path, acl_type_t type) + : acl (acl_get_file (path.u8string ().c_str (), type)) +{ ; } + + +//----------------------------------------------------------------------------- +acl::acl (acl_t &&_native) + : m_native (_native) +{ + if (!m_native) + cruft::posix::error::throw_code (); +} + + +/////////////////////////////////////////////////////////////////////////////// +acl::~acl () +{ + if (m_native) + acl_free (m_native); +} + + +/////////////////////////////////////////////////////////////////////////////// +acl acl::dup (void) const +{ + return acl { + acl_dup (m_native) + }; +} + + +/////////////////////////////////////////////////////////////////////////////// +acl::iterator::iterator (acl const &_parent) + : m_parent (&_parent) +{ + fetch (ACL_FIRST_ENTRY); +} + + +//----------------------------------------------------------------------------- +acl::iterator::iterator () + : m_parent (nullptr) +{ ; } + + +//----------------------------------------------------------------------------- +acl::iterator::value_type +acl::iterator::operator* (void) +{ + return entry { m_value }; +} + + +//----------------------------------------------------------------------------- +acl::iterator& +acl::iterator::operator++ () +{ + fetch (ACL_NEXT_ENTRY); + return *this; +} + + +//----------------------------------------------------------------------------- +bool +acl::iterator::operator== (iterator const &rhs) const +{ + return m_parent == rhs.m_parent; +} + + +//----------------------------------------------------------------------------- +bool +acl::iterator::operator!= (iterator const &rhs) const +{ + return m_parent != rhs.m_parent; +} + + +//----------------------------------------------------------------------------- +void +acl::iterator::fetch (int pos) +{ + auto const res = acl_get_entry (m_parent->native (), pos, &m_value); + + switch (res) { + case 0: m_parent = nullptr; return; + case 1: return; + default: + cruft::posix::error::throw_code (); + } +} + + + +/////////////////////////////////////////////////////////////////////////////// +acl::const_iterator +acl::begin (void) const +{ + return const_iterator { *this }; +} + + +//----------------------------------------------------------------------------- +acl::const_iterator +acl::end (void) const +{ + return iterator {}; +} + + +/////////////////////////////////////////////////////////////////////////////// +int acl::size (void) const +{ + return cruft::posix::error::try_call (acl_entries, m_native); +} + + +/////////////////////////////////////////////////////////////////////////////// +entry::entry (acl_entry_t _native) + : m_native (_native) +{ ; } + + +//----------------------------------------------------------------------------- +acl_tag_t +entry::tag (void) const +{ + acl_tag_t res; + cruft::posix::error::try_call (acl_get_tag_type, m_native, &res); + return res; +} + + +//----------------------------------------------------------------------------- +class cruft::permset +entry::permset (void) const +{ + acl_permset_t res; + cruft::posix::error::try_call (acl_get_permset, m_native, &res); + return res; +} + + +/////////////////////////////////////////////////////////////////////////////// +permset::permset (acl_permset_t _native) + : m_native (_native) +{ ; } + + +//----------------------------------------------------------------------------- +bool permset::operator& (acl_perm_t val) const +{ + return cruft::posix::error::try_call (acl_get_perm, m_native, val); +} + + +/////////////////////////////////////////////////////////////////////////////// +std::ostream& +cruft::operator<< (std::ostream &os, cruft::acl const &val) +{ + return os << "[ " << cruft::iterator::make_infix (val) << " ]"; +} + + +//----------------------------------------------------------------------------- +std::ostream& +cruft::operator<< (std::ostream &os, cruft::entry const &val) +{ + os << "{ "; + + auto t = val.tag (); + + switch (t) { + case ACL_USER: os << "uid: " << +val.qualifier (); break; + case ACL_GROUP: os << "gid: " << +val.qualifier (); break; + + case ACL_USER_OBJ: os << "owner: null"; break; + case ACL_GROUP_OBJ: os << "group: null"; break; + case ACL_MASK: os << "mask: null"; break; + case ACL_OTHER: os << "other: null"; break; + default: + unhandled (t); + } + + os << ", permset: " << val.permset () << " }"; + + return os; +} + + +//----------------------------------------------------------------------------- +std::ostream& +cruft::operator<< (std::ostream &os, cruft::permset const &val) +{ + return os << ((val & ACL_READ ) ? 'r' : '_') + << ((val & ACL_WRITE ) ? 'w' : '_') + << ((val & ACL_EXECUTE) ? 'x' : '_'); +} diff --git a/acl.hpp b/acl.hpp new file mode 100644 index 0000000..53526fe --- /dev/null +++ b/acl.hpp @@ -0,0 +1,139 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Copyright 2019, Danny Robson + */ + +#pragma once + +#include + +#include +#include +#include +#include + +#include + + +namespace cruft { + /// A combination of read, write, and/or execute flags. + class permset { + public: + permset (acl_permset_t _native); + + bool operator& (acl_perm_t) const; + + private: + acl_permset_t m_native; + }; + + + /// One single entry in an ACL. Contains a tag, qualifier, and permset. + class entry { + public: + explicit entry (acl_entry_t); + + acl_tag_t tag (void) const; + + // It would be nice to use a tagged union, but uid_t and gid_t would + // clash if we used something like std::variant. And we can't just + // return an int because some systems have larger objects (eg, MacOS + // with ACL_EXTENDED_ALLOW returns a guid_t). + template + ValueT qualifier (void) const + { + static_assert (std::is_pod_v); + + auto data = acl_get_qualifier (m_native); + + union { + u08 raw[sizeof (ValueT)]; + ValueT res; + }; + + memcpy (raw, data, sizeof (ValueT)); + acl_free (data); + return res; + + } + + class permset permset (void) const; + + acl_entry_t& native (void) &; + acl_entry_t const& native (void) const&; + + private: + acl_entry_t m_native; + }; + + + /// A context for a ACL operations. + class acl { + public: + using value_type = entry; + + explicit acl (int count); + explicit acl (acl_t &&); + acl (std::filesystem::path const&, acl_type_t); + + acl (acl&&); + acl& operator= (acl&&); + + acl (acl const&) = delete; + acl& operator= (acl const&) = delete; + + ~acl (); + + acl dup (void) const; + + class iterator { + public: + using iterator_category = std::input_iterator_tag; + using difference_type = int; + using value_type = entry; + using pointer = value_type*; + using reference = value_type&; + + explicit iterator (); + explicit iterator (acl const &parent); + + iterator& operator++ (); + value_type operator* (); + + bool operator== (iterator const&) const; + bool operator!= (iterator const&) const; + + private: + void fetch (int pos); + + acl const *m_parent; + acl_entry_t m_value; + }; + + using const_iterator = iterator; + + //iterator begin (void); + //iterator end (void); + + const_iterator begin (void) const; + const_iterator end (void) const; + + const_iterator cbegin (void) const; + const_iterator cend (void) const; + + int size (void) const; + + acl_t& native (void)& { return m_native; } + acl_t const& native (void) const& { return m_native; } + + private: + acl_t m_native; + }; + + std::ostream& operator<< (std::ostream&, acl const&); + std::ostream& operator<< (std::ostream&, entry const&); + std::ostream& operator<< (std::ostream&, permset const&); +} diff --git a/tools/stat.cpp b/tools/stat.cpp index b16eef0..0743b30 100644 --- a/tools/stat.cpp +++ b/tools/stat.cpp @@ -1,3 +1,8 @@ + +#include +#include +#include "../acl.hpp" + #include #include #include @@ -145,6 +150,13 @@ void do_xattr (char const *path) } +//----------------------------------------------------------------------------- +void do_acl (char const *path) +{ + std::cout << cruft::acl (path, ACL_TYPE_ACCESS) << '\n'; +} + + /////////////////////////////////////////////////////////////////////////////// int main (int argc, char **argv) { @@ -159,6 +171,7 @@ int main (int argc, char **argv) char const *path = argv[i]; do_stat (path); do_xattr (path); + do_acl (path); std::cout << '\n'; }