Add macOS support #34
Some checks failed
BlockStorage/repertory_mac/pipeline/head This commit looks good
BlockStorage/repertory/pipeline/head There was a failure building this commit

This commit is contained in:
2025-08-03 10:41:21 -05:00
parent eee832ce49
commit 29aaf625c7
16 changed files with 292 additions and 133 deletions

View File

@@ -88,11 +88,16 @@ auto fuse_drive::chown_impl(std::string api_path, uid_t uid, gid_t gid,
auto fuse_drive::chown_impl(std::string api_path, uid_t uid, gid_t gid)
-> api_error {
#endif
REPERTORY_USES_FUNCTION_NAME();
return check_and_perform(
api_path, X_OK, [&](api_meta_map &meta) -> api_error {
meta.clear();
if (uid != static_cast<uid_t>(-1)) {
if (get_effective_uid() != 0 && get_effective_uid() != uid) {
utils::error::raise_error(
function_name, fmt::format("failed user|{}|{}",
get_effective_uid(), getuid()));
return api_error::permission_denied;
}
@@ -102,6 +107,9 @@ auto fuse_drive::chown_impl(std::string api_path, uid_t uid, gid_t gid)
if (gid != static_cast<gid_t>(-1)) {
if (get_effective_uid() != 0 &&
not utils::is_uid_member_of_group(get_effective_uid(), gid)) {
utils::error::raise_error(
function_name, fmt::format("failed group|{}|{}",
get_effective_gid(), getgid()));
return api_error::permission_denied;
}

View File

@@ -36,20 +36,20 @@ auto client::get_drive_information() -> rpc_response {
auto resp = cli.Get("/api/v1/" + rpc_method::get_drive_information);
if (resp.error() != httplib::Error::Success) {
return rpc_response{
rpc_response_type::http_error,
{{"error", httplib::to_string(resp.error())}},
.response_type = rpc_response_type::http_error,
.data = {{"error", httplib::to_string(resp.error())}},
};
}
if (resp->status != http_error_codes::ok) {
return rpc_response{
rpc_response_type::http_error,
{{"error", std::to_string(resp->status)}},
.response_type = rpc_response_type::http_error,
.data = {{"error", std::to_string(resp->status)}},
};
}
return rpc_response{
rpc_response_type::success,
json::parse(resp->body),
.response_type = rpc_response_type::success,
.data = json::parse(resp->body),
};
}
@@ -63,20 +63,20 @@ auto client::get_config() -> rpc_response {
auto resp = cli.Get("/api/v1/" + rpc_method::get_config);
if (resp.error() != httplib::Error::Success) {
return rpc_response{
rpc_response_type::http_error,
{{"error", httplib::to_string(resp.error())}},
.response_type = rpc_response_type::http_error,
.data = {{"error", httplib::to_string(resp.error())}},
};
}
if (resp->status != http_error_codes::ok) {
return rpc_response{
rpc_response_type::http_error,
{{"error", std::to_string(resp->status)}},
.response_type = rpc_response_type::http_error,
.data = {{"error", std::to_string(resp->status)}},
};
}
return rpc_response{
rpc_response_type::success,
json::parse(resp->body),
.response_type = rpc_response_type::success,
.data = json::parse(resp->body),
};
}
@@ -92,20 +92,20 @@ auto client::get_config_value_by_name(const std::string &name) -> rpc_response {
cli.Get("/api/v1/" + rpc_method::get_config_value_by_name, params, {});
if (resp.error() != httplib::Error::Success) {
return rpc_response{
rpc_response_type::http_error,
{{"error", httplib::to_string(resp.error())}},
.response_type = rpc_response_type::http_error,
.data = {{"error", httplib::to_string(resp.error())}},
};
}
if (resp->status != http_error_codes::ok) {
return rpc_response{
rpc_response_type::http_error,
{{"error", std::to_string(resp->status)}},
.response_type = rpc_response_type::http_error,
.data = {{"error", std::to_string(resp->status)}},
};
}
return rpc_response{
rpc_response_type::success,
json::parse(resp->body),
.response_type = rpc_response_type::success,
.data = json::parse(resp->body),
};
}
@@ -120,20 +120,20 @@ auto client::get_directory_items(const std::string &api_path) -> rpc_response {
auto resp = cli.Get("/api/v1/" + rpc_method::get_directory_items, params, {});
if (resp.error() != httplib::Error::Success) {
return rpc_response{
rpc_response_type::http_error,
{{"error", httplib::to_string(resp.error())}},
.response_type = rpc_response_type::http_error,
.data = {{"error", httplib::to_string(resp.error())}},
};
}
if (resp->status != http_error_codes::ok) {
return rpc_response{
rpc_response_type::http_error,
{{"error", std::to_string(resp->status)}},
.response_type = rpc_response_type::http_error,
.data = {{"error", std::to_string(resp->status)}},
};
}
return rpc_response{
rpc_response_type::success,
json::parse(resp->body),
.response_type = rpc_response_type::success,
.data = json::parse(resp->body),
};
}
@@ -147,20 +147,20 @@ auto client::get_open_files() -> rpc_response {
auto resp = cli.Get("/api/v1/" + rpc_method::get_open_files);
if (resp.error() != httplib::Error::Success) {
return rpc_response{
rpc_response_type::http_error,
{{"error", httplib::to_string(resp.error())}},
.response_type = rpc_response_type::http_error,
.data = {{"error", httplib::to_string(resp.error())}},
};
}
if (resp->status != http_error_codes::ok) {
return rpc_response{
rpc_response_type::http_error,
{{"error", std::to_string(resp->status)}},
.response_type = rpc_response_type::http_error,
.data = {{"error", std::to_string(resp->status)}},
};
}
return rpc_response{
rpc_response_type::success,
json::parse(resp->body),
.response_type = rpc_response_type::success,
.data = json::parse(resp->body),
};
}
@@ -174,20 +174,20 @@ auto client::get_pinned_files() -> rpc_response {
auto resp = cli.Get("/api/v1/" + rpc_method::get_pinned_files);
if (resp.error() != httplib::Error::Success) {
return rpc_response{
rpc_response_type::http_error,
{{"error", httplib::to_string(resp.error())}},
.response_type = rpc_response_type::http_error,
.data = {{"error", httplib::to_string(resp.error())}},
};
}
if (resp->status != http_error_codes::ok) {
return rpc_response{
rpc_response_type::http_error,
{{"error", std::to_string(resp->status)}},
.response_type = rpc_response_type::http_error,
.data = {{"error", std::to_string(resp->status)}},
};
}
return rpc_response{
rpc_response_type::success,
json::parse(resp->body),
.response_type = rpc_response_type::success,
.data = json::parse(resp->body),
};
}
@@ -202,20 +202,20 @@ auto client::pin_file(const std::string &api_path) -> rpc_response {
auto resp = cli.Post("/api/v1/" + rpc_method::pin_file, params);
if (resp.error() != httplib::Error::Success) {
return rpc_response{
rpc_response_type::http_error,
{{"error", httplib::to_string(resp.error())}},
.response_type = rpc_response_type::http_error,
.data = {{"error", httplib::to_string(resp.error())}},
};
}
if (resp->status != http_error_codes::ok) {
return rpc_response{
rpc_response_type::http_error,
{{"error", std::to_string(resp->status)}},
.response_type = rpc_response_type::http_error,
.data = {{"error", std::to_string(resp->status)}},
};
}
return rpc_response{
rpc_response_type::success,
{},
.response_type = rpc_response_type::success,
.data = {},
};
}
@@ -230,20 +230,20 @@ auto client::pinned_status(const std::string &api_path) -> rpc_response {
auto resp = cli.Get("/api/v1/" + rpc_method::pinned_status, params, {});
if (resp.error() != httplib::Error::Success) {
return rpc_response{
rpc_response_type::http_error,
{{"error", httplib::to_string(resp.error())}},
.response_type = rpc_response_type::http_error,
.data = {{"error", httplib::to_string(resp.error())}},
};
}
if (resp->status != http_error_codes::ok) {
return rpc_response{
rpc_response_type::http_error,
{{"error", std::to_string(resp->status)}},
.response_type = rpc_response_type::http_error,
.data = {{"error", std::to_string(resp->status)}},
};
}
return rpc_response{
rpc_response_type::success,
json::parse(resp->body),
.response_type = rpc_response_type::success,
.data = json::parse(resp->body),
};
}
@@ -265,20 +265,20 @@ auto client::set_config_value_by_name(const std::string &name,
cli.Post("/api/v1/" + rpc_method::set_config_value_by_name, params);
if (resp.error() != httplib::Error::Success) {
return rpc_response{
rpc_response_type::http_error,
{{"error", httplib::to_string(resp.error())}},
.response_type = rpc_response_type::http_error,
.data = {{"error", httplib::to_string(resp.error())}},
};
}
if (resp->status != http_error_codes::ok) {
return rpc_response{
rpc_response_type::http_error,
{{"error", std::to_string(resp->status)}},
.response_type = rpc_response_type::http_error,
.data = {{"error", std::to_string(resp->status)}},
};
};
return rpc_response{
rpc_response_type::success,
nlohmann::json::parse(resp->body),
.response_type = rpc_response_type::success,
.data = nlohmann::json::parse(resp->body),
};
}
@@ -292,20 +292,20 @@ auto client::unmount() -> rpc_response {
auto resp = cli.Post("/api/v1/" + rpc_method::unmount);
if (resp.error() != httplib::Error::Success) {
return rpc_response{
rpc_response_type::http_error,
{{"error", httplib::to_string(resp.error())}},
.response_type = rpc_response_type::http_error,
.data = {{"error", httplib::to_string(resp.error())}},
};
}
if (resp->status != http_error_codes::ok) {
return rpc_response{
rpc_response_type::http_error,
{{"error", std::to_string(resp->status)}},
.response_type = rpc_response_type::http_error,
.data = {{"error", std::to_string(resp->status)}},
};
}
return rpc_response{
rpc_response_type::success,
{},
.response_type = rpc_response_type::success,
.data = {},
};
}
@@ -320,20 +320,20 @@ auto client::unpin_file(const std::string &api_path) -> rpc_response {
auto resp = cli.Post("/api/v1/" + rpc_method::unpin_file, params);
if (resp.error() != httplib::Error::Success) {
return rpc_response{
rpc_response_type::http_error,
{{"error", httplib::to_string(resp.error())}},
.response_type = rpc_response_type::http_error,
.data = {{"error", httplib::to_string(resp.error())}},
};
}
if (resp->status != http_error_codes::ok) {
return rpc_response{
rpc_response_type::http_error,
{{"error", std::to_string(resp->status)}},
.response_type = rpc_response_type::http_error,
.data = {{"error", std::to_string(resp->status)}},
};
}
return rpc_response{
rpc_response_type::success,
{},
.response_type = rpc_response_type::success,
.data = {},
};
}
} // namespace repertory

View File

@@ -29,8 +29,8 @@ namespace repertory::cli::actions {
const std::string &data_directory,
const provider_type &prov,
const std::string &unique_id,
std::string user,
std::string password) -> exit_code {
std::string user, std::string password)
-> exit_code {
lock_data lock(prov, unique_id);
const auto res = lock.grab_lock(1U);
if (res == lock_result::success) {
@@ -42,8 +42,11 @@ namespace repertory::cli::actions {
auto port = app_config::default_api_port(prov);
utils::cli::get_api_authentication_data(user, password, port, prov,
data_directory);
const auto response =
client({"localhost", password, port, user}).get_config();
auto response = client({.host = "localhost",
.password = password,
.port = port,
.user = user})
.get_config();
std::cout << static_cast<int>(response.response_type) << std::endl;
std::cout << response.data.dump(2) << std::endl;
}

View File

@@ -38,8 +38,11 @@ drive_information(std::vector<const char *> /* args */,
auto port = app_config::default_api_port(prov);
utils::cli::get_api_authentication_data(user, password, port, prov,
data_directory);
const auto response =
client({"localhost", password, port, user}).get_drive_information();
auto response = client({.host = "localhost",
.password = password,
.port = port,
.user = user})
.get_drive_information();
std::cout << static_cast<int>(response.response_type) << std::endl;
std::cout << response.data.dump(2) << std::endl;
} else {

View File

@@ -49,8 +49,11 @@ namespace repertory::cli::actions {
auto port = app_config::default_api_port(prov);
utils::cli::get_api_authentication_data(user, password, port, prov,
data_directory);
const auto response = client({"localhost", password, port, user})
.get_config_value_by_name(data);
auto response = client({.host = "localhost",
.password = password,
.port = port,
.user = user})
.get_config_value_by_name(data);
std::cout << static_cast<int>(response.response_type) << std::endl;
std::cout << response.data.dump(2) << std::endl;
}

View File

@@ -36,8 +36,11 @@ namespace repertory::cli::actions {
auto port = app_config::default_api_port(prov);
utils::cli::get_api_authentication_data(user, password, port, prov,
data_directory);
const auto response =
client({"localhost", password, port, user}).get_directory_items(data);
auto response = client({.host = "localhost",
.password = password,
.port = port,
.user = user})
.get_directory_items(data);
if (response.response_type == rpc_response_type::success) {
std::cout << response.data.dump(2) << std::endl;
} else {

View File

@@ -35,8 +35,11 @@ namespace repertory::cli::actions {
auto port = app_config::default_api_port(prov);
utils::cli::get_api_authentication_data(user, password, port, prov,
data_directory);
const auto response =
client({"localhost", password, port, user}).get_pinned_files();
auto response = client({.host = "localhost",
.password = password,
.port = port,
.user = user})
.get_pinned_files();
if (response.response_type == rpc_response_type::success) {
std::cout << response.data.dump(2) << std::endl;
} else {

View File

@@ -37,8 +37,11 @@ open_files(std::vector<const char *> /* args */,
auto port = app_config::default_api_port(prov);
utils::cli::get_api_authentication_data(user, password, port, prov,
data_directory);
const auto response =
client({"localhost", password, port, user}).get_open_files();
auto response = client({.host = "localhost",
.password = password,
.port = port,
.user = user})
.get_open_files();
std::cout << static_cast<int>(response.response_type) << std::endl;
std::cout << response.data.dump(2) << std::endl;
} else {

View File

@@ -36,8 +36,11 @@ pin_file(std::vector<const char *> args, const std::string &data_directory,
auto port = app_config::default_api_port(prov);
utils::cli::get_api_authentication_data(user, password, port, prov,
data_directory);
const auto response =
client({"localhost", password, port, user}).pin_file(data);
auto response = client({.host = "localhost",
.password = password,
.port = port,
.user = user})
.pin_file(data);
if (response.response_type == rpc_response_type::success) {
std::cout << response.data.dump(2) << std::endl;
} else {

View File

@@ -36,8 +36,11 @@ pinned_status(std::vector<const char *> args, const std::string &data_directory,
auto port = app_config::default_api_port(prov);
utils::cli::get_api_authentication_data(user, password, port, prov,
data_directory);
const auto response =
client({"localhost", password, port, user}).pinned_status(data);
auto response = client({.host = "localhost",
.password = password,
.port = port,
.user = user})
.pinned_status(data);
if (response.response_type == rpc_response_type::success) {
std::cout << response.data.dump(2) << std::endl;
} else {

View File

@@ -56,8 +56,11 @@ namespace repertory::cli::actions {
auto port = app_config::default_api_port(prov);
utils::cli::get_api_authentication_data(user, password, port, prov,
data_directory);
const auto response = client({"localhost", password, port, user})
.set_config_value_by_name(data[0U], data[1U]);
auto response = client({.host = "localhost",
.password = password,
.port = port,
.user = user})
.set_config_value_by_name(data[0U], data[1U]);
std::cout << static_cast<int>(response.response_type) << std::endl;
std::cout << response.data.dump(2) << std::endl;
ret = response.response_type == rpc_response_type::config_value_not_found

View File

@@ -27,16 +27,42 @@
namespace repertory::cli::actions {
[[nodiscard]] inline auto
unmount(std::vector<const char *> /* args */, const std::string &data_directory,
const provider_type &prov, const std::string & /*unique_id*/,
const provider_type &prov, const std::string & /* unique_id */,
std::string user, std::string password) -> exit_code {
auto ret = exit_code::success;
auto port = app_config::default_api_port(prov);
constexpr const std::uint8_t retry_count{30U};
auto ret{exit_code::success};
auto port{app_config::default_api_port(prov)};
utils::cli::get_api_authentication_data(user, password, port, prov,
data_directory);
const auto response = client({"localhost", password, port, user}).unmount();
std::cout << static_cast<int>(response.response_type) << std::endl;
auto response = client({.host = "localhost",
.password = password,
.port = port,
.user = user})
.unmount();
if (response.response_type == rpc_response_type::success) {
std::cout << response.data.dump(2) << std::endl;
std::cout << "waiting for unmount ..." << std::flush;
for (std::uint8_t retry{0U};
retry < retry_count &&
response.response_type == rpc_response_type::success;
++retry) {
std::this_thread::sleep_for(1s);
response = client({.host = "localhost",
.password = password,
.port = port,
.user = user})
.unmount();
std::cout << "." << std::flush;
}
if (response.response_type == rpc_response_type::success) {
std::cerr << " failed! mount still active" << std::endl;
ret = exit_code::mount_active;
} else {
std::cout << " done!" << std::endl;
std::cout << static_cast<int>(rpc_response_type::success) << std::endl;
std::cout << response.data.dump(2) << std::endl;
}
} else {
std::cerr << response.data.dump(2) << std::endl;
ret = exit_code::communication_error;

View File

@@ -36,8 +36,11 @@ unpin_file(std::vector<const char *> args, const std::string &data_directory,
auto port = app_config::default_api_port(prov);
utils::cli::get_api_authentication_data(user, password, port, prov,
data_directory);
const auto response =
client({"localhost", password, port, user}).unpin_file(data);
auto response = client({.host = "localhost",
.password = password,
.port = port,
.user = user})
.unpin_file(data);
if (response.response_type == rpc_response_type::success) {
std::cout << response.data.dump(2) << std::endl;
} else {

View File

@@ -360,22 +360,12 @@ public:
}
static void execute_unmount(auto args) {
auto unmounted{false};
args.emplace_back("-unmount");
auto unmount_cmd = "./repertory " + utils::string::join(args, ' ');
std::cout << "unmount command: " << unmount_cmd << std::endl;
for (int i = 0; not unmounted && (i < 50); i++) {
auto res = system(unmount_cmd.c_str());
unmounted = res == 0;
EXPECT_EQ(0, res);
if (not unmounted) {
std::this_thread::sleep_for(5s);
}
}
EXPECT_TRUE(unmounted);
auto res = system(unmount_cmd.c_str());
EXPECT_EQ(0, res);
}
static void rmdir_and_test(std::string_view dir_path) {

View File

@@ -379,8 +379,11 @@ TYPED_TEST(fuse_test, create_fails_with_excl_if_path_is_directory) {
for (const auto &flags : ops) {
auto handle = open(dir_path.c_str(), flags, ACCESSPERMS);
EXPECT_EQ(-1, handle);
EXPECT_EQ(EEXIST, errno);
if (handle != -1) {
close(handle);
}
}
this->rmdir_and_test(dir_path);
@@ -399,8 +402,11 @@ TYPED_TEST(fuse_test, create_fails_with_excl_if_file_exists) {
for (const auto &flags : ops) {
auto handle = open(file_path.c_str(), flags, ACCESSPERMS);
EXPECT_EQ(-1, handle);
EXPECT_EQ(EEXIST, errno);
if (handle != -1) {
close(handle);
}
}
this->unlink_file_and_test(file_path);
@@ -408,23 +414,40 @@ TYPED_TEST(fuse_test, create_fails_with_excl_if_file_exists) {
TYPED_TEST(fuse_test, create_fails_if_path_is_directory) {
std::array<int, 7U> ops{
O_CREAT,
O_CREAT | O_APPEND,
O_CREAT | O_RDWR,
O_CREAT | O_TRUNC | O_RDWR,
O_CREAT | O_TRUNC | O_WRONLY,
O_CREAT | O_TRUNC,
O_CREAT | O_WRONLY,
O_CREAT,
};
std::string dir_name{"create_test"};
auto dir_path = this->create_directory_and_test(dir_name);
for (const auto &flags : ops) {
for (std::size_t idx{0U}; idx < ops.size(); ++idx) {
auto flags = ops.at(idx);
auto handle = open(dir_path.c_str(), flags, ACCESSPERMS);
#if defined(__APPLE__)
if (handle == -1) {
EXPECT_EQ(EISDIR, errno);
} else {
if (idx > 1U) {
std::cerr << "create flags should return invalid handle|idx|" << idx
<< "|flags|" << std::hex << flags << std::endl;
EXPECT_EQ(-1, handle);
}
close(handle);
}
#else // !defined(__APPLE__)
EXPECT_EQ(-1, handle);
EXPECT_EQ(EISDIR, errno);
if (handle != -1) {
close(handle);
}
#endif //! defined(__APPLE__)
}
this->rmdir_and_test(dir_path);
@@ -450,11 +473,15 @@ TYPED_TEST(fuse_test, create_fails_if_parent_path_does_not_exist) {
for (const auto &flags : ops) {
auto handle = open(file_path.c_str(), flags, ACCESSPERMS);
EXPECT_EQ(-1, handle);
EXPECT_EQ(ENOENT, errno);
if (handle != -1) {
close(handle);
}
}
}
#if !defined(__APPLE__)
TYPED_TEST(fuse_test, create_fails_if_invalid) {
std::array<int, 1U> ops{
O_CREAT | O_TRUNC | O_APPEND,
@@ -466,10 +493,14 @@ TYPED_TEST(fuse_test, create_fails_if_invalid) {
for (const auto &flags : ops) {
auto handle = open(file_path.c_str(), flags, ACCESSPERMS);
EXPECT_EQ(-1, handle);
EXPECT_EQ(EINVAL, errno);
if (handle != -1) {
close(handle);
}
}
}
#endif // !defined(__APPLE__)
TYPED_TEST(fuse_test, create_open_fails_if_path_is_directory) {
std::array<int, 9U> ops{
@@ -481,13 +512,28 @@ TYPED_TEST(fuse_test, create_open_fails_if_path_is_directory) {
std::string dir_name{"create_test"};
auto dir_path = this->create_directory_and_test(dir_name);
for (const auto &flags : ops) {
for (std::size_t idx{0U}; idx < ops.size(); ++idx) {
auto flags = ops.at(idx);
auto handle = open(dir_path.c_str(), flags);
EXPECT_EQ(-1, handle);
#if defined(__APPLE__)
if (handle != -1) {
std::cout << std::oct << flags << std::endl;
if (idx != 0U) {
std::cerr << "open flags should return invalid handle|idx|" << idx
<< "|flags|" << std::hex << flags << std::endl;
EXPECT_EQ(-1, handle);
}
close(handle);
continue;
}
#endif // defined(__APPLE_)
EXPECT_EQ(-1, handle);
EXPECT_EQ(EISDIR, errno);
if (handle != -1) {
close(handle);
}
}
this->rmdir_and_test(dir_path);
@@ -514,6 +560,10 @@ TYPED_TEST(fuse_test, create_open_fails_if_path_does_not_exist) {
auto handle = open(file_path.c_str(), flags);
EXPECT_EQ(-1, handle);
EXPECT_EQ(ENOENT, errno);
if (handle != -1) {
close(handle);
}
}
}
} // namespace repertory

View File

@@ -23,6 +23,68 @@
#include "utils/unix.hpp"
#include "utils/collection.hpp"
#include "utils/error_utils.hpp"
namespace {
[[nodiscard]] auto get_group_list(auto *pass) -> std::vector<gid_t> {
REPERTORY_USES_FUNCTION_NAME();
std::vector<gid_t> groups{};
#if defined(__APPLE__)
constexpr const int buffer_count{8};
constexpr const int max_group_count{1024};
groups.resize(buffer_count);
std::size_t orig_count{0U};
while (true) {
auto group_count{static_cast<int>(groups.size())};
if (group_count > max_group_count) {
repertory::utils::error::raise_error(
function_name, "getgrouplist failed: too many groups");
break;
}
auto res{
getgrouplist(pass->pw_name, static_cast<int>(pass->pw_gid),
reinterpret_cast<int *>(groups.data()), &group_count),
};
if (res < 0) {
if (orig_count == 0U) {
repertory::utils::error::raise_error(
function_name,
fmt::format("failed to get group list|error|{}", errno));
}
break;
}
groups.resize(static_cast<std::size_t>(group_count));
if (groups.size() == orig_count) {
break;
}
orig_count = groups.size();
}
#else // !defined(__APPLE__)
int group_count{};
auto res = getgrouplist(pass->pw_name, pass->pw_gid, nullptr, &group_count);
if (res >= 0) {
repertory::utils::error::raise_error(
function_name, fmt::format("failed to get group list|error|{}", errno));
}
#endif // defined(__APPLE__)
#if !defined(__APPLE__)
res = getgrouplist(pass->pw_name, pass->pw_gid, groups.data(), &group_count);
if (res >= 0) {
repertory::utils::error::raise_error(
function_name, fmt::format("failed to get group list|error|{}", errno));
}
#endif // !defined(__APPLE__)
return groups;
}
} // namespace
namespace repertory::utils {
#if defined(__APPLE__)
@@ -42,20 +104,11 @@ auto get_thread_id() -> std::uint64_t {
}
auto is_uid_member_of_group(uid_t uid, gid_t gid) -> bool {
std::vector<gid_t> groups{};
auto res = use_getpwuid(uid, [&groups](struct passwd *pass) {
int group_count{};
if (getgrouplist(pass->pw_name, pass->pw_gid, nullptr, &group_count) < 0) {
groups.resize(static_cast<std::size_t>(group_count));
#if defined(__APPLE__)
getgrouplist(pass->pw_name, pass->pw_gid,
reinterpret_cast<int *>(groups.data()), &group_count);
#else // !defined(__APPLE__)
getgrouplist(pass->pw_name, pass->pw_gid, groups.data(), &group_count);
#endif // defined(__APPLE__)
}
});
REPERTORY_USES_FUNCTION_NAME();
std::vector<gid_t> groups{};
auto res = use_getpwuid(
uid, [&groups](struct passwd *pass) { groups = get_group_list(pass); });
if (not res) {
throw utils::error::create_exception(res.function_name,
{"use_getpwuid failed", res.reason});
@@ -73,14 +126,16 @@ auto use_getpwuid(uid_t uid, passwd_callback_t callback) -> result {
auto *temp_pw = getpwuid(uid);
if (temp_pw == nullptr) {
return {
std::string{function_name},
false,
"'getpwuid' returned nullptr",
.function_name = std::string{function_name},
.ok = false,
.reason = "'getpwuid' returned nullptr",
};
}
callback(temp_pw);
return {std::string{function_name}};
return {
.function_name = std::string{function_name},
};
}
} // namespace repertory::utils