diff --git a/repertory/librepertory/src/drives/fuse/fuse_drive.cpp b/repertory/librepertory/src/drives/fuse/fuse_drive.cpp index a7ab2485..f297de8d 100644 --- a/repertory/librepertory/src/drives/fuse/fuse_drive.cpp +++ b/repertory/librepertory/src/drives/fuse/fuse_drive.cpp @@ -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(-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(-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; } diff --git a/repertory/librepertory/src/rpc/client/client.cpp b/repertory/librepertory/src/rpc/client/client.cpp index e9d6fd0e..e8fbcf2f 100644 --- a/repertory/librepertory/src/rpc/client/client.cpp +++ b/repertory/librepertory/src/rpc/client/client.cpp @@ -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 diff --git a/repertory/repertory/include/cli/display_config.hpp b/repertory/repertory/include/cli/display_config.hpp index 6fc00148..5ee2b1ef 100644 --- a/repertory/repertory/include/cli/display_config.hpp +++ b/repertory/repertory/include/cli/display_config.hpp @@ -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(response.response_type) << std::endl; std::cout << response.data.dump(2) << std::endl; } diff --git a/repertory/repertory/include/cli/drive_information.hpp b/repertory/repertory/include/cli/drive_information.hpp index 5b80272d..11bbc175 100644 --- a/repertory/repertory/include/cli/drive_information.hpp +++ b/repertory/repertory/include/cli/drive_information.hpp @@ -38,8 +38,11 @@ drive_information(std::vector /* 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(response.response_type) << std::endl; std::cout << response.data.dump(2) << std::endl; } else { diff --git a/repertory/repertory/include/cli/get.hpp b/repertory/repertory/include/cli/get.hpp index 7d50a8ec..106a381e 100644 --- a/repertory/repertory/include/cli/get.hpp +++ b/repertory/repertory/include/cli/get.hpp @@ -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(response.response_type) << std::endl; std::cout << response.data.dump(2) << std::endl; } diff --git a/repertory/repertory/include/cli/get_directory_items.hpp b/repertory/repertory/include/cli/get_directory_items.hpp index 58d48c20..7454eb00 100644 --- a/repertory/repertory/include/cli/get_directory_items.hpp +++ b/repertory/repertory/include/cli/get_directory_items.hpp @@ -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 { diff --git a/repertory/repertory/include/cli/get_pinned_files.hpp b/repertory/repertory/include/cli/get_pinned_files.hpp index d700274f..c7f2ebc3 100644 --- a/repertory/repertory/include/cli/get_pinned_files.hpp +++ b/repertory/repertory/include/cli/get_pinned_files.hpp @@ -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 { diff --git a/repertory/repertory/include/cli/open_files.hpp b/repertory/repertory/include/cli/open_files.hpp index d346c5ca..ed34902a 100644 --- a/repertory/repertory/include/cli/open_files.hpp +++ b/repertory/repertory/include/cli/open_files.hpp @@ -37,8 +37,11 @@ open_files(std::vector /* 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(response.response_type) << std::endl; std::cout << response.data.dump(2) << std::endl; } else { diff --git a/repertory/repertory/include/cli/pin_file.hpp b/repertory/repertory/include/cli/pin_file.hpp index c4053d00..f2bf54a4 100644 --- a/repertory/repertory/include/cli/pin_file.hpp +++ b/repertory/repertory/include/cli/pin_file.hpp @@ -36,8 +36,11 @@ pin_file(std::vector 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 { diff --git a/repertory/repertory/include/cli/pinned_status.hpp b/repertory/repertory/include/cli/pinned_status.hpp index 827f0347..ae5fc894 100644 --- a/repertory/repertory/include/cli/pinned_status.hpp +++ b/repertory/repertory/include/cli/pinned_status.hpp @@ -36,8 +36,11 @@ pinned_status(std::vector 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 { diff --git a/repertory/repertory/include/cli/set.hpp b/repertory/repertory/include/cli/set.hpp index b07e27ba..995c47aa 100644 --- a/repertory/repertory/include/cli/set.hpp +++ b/repertory/repertory/include/cli/set.hpp @@ -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(response.response_type) << std::endl; std::cout << response.data.dump(2) << std::endl; ret = response.response_type == rpc_response_type::config_value_not_found diff --git a/repertory/repertory/include/cli/unmount.hpp b/repertory/repertory/include/cli/unmount.hpp index ee696996..c8900dd7 100644 --- a/repertory/repertory/include/cli/unmount.hpp +++ b/repertory/repertory/include/cli/unmount.hpp @@ -27,16 +27,42 @@ namespace repertory::cli::actions { [[nodiscard]] inline auto unmount(std::vector /* 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(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(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; diff --git a/repertory/repertory/include/cli/unpin_file.hpp b/repertory/repertory/include/cli/unpin_file.hpp index 7a5e7bbe..36bd1257 100644 --- a/repertory/repertory/include/cli/unpin_file.hpp +++ b/repertory/repertory/include/cli/unpin_file.hpp @@ -36,8 +36,11 @@ unpin_file(std::vector 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 { diff --git a/repertory/repertory_test/include/fixtures/fuse_fixture.hpp b/repertory/repertory_test/include/fixtures/fuse_fixture.hpp index b48ab876..77ed5f52 100644 --- a/repertory/repertory_test/include/fixtures/fuse_fixture.hpp +++ b/repertory/repertory_test/include/fixtures/fuse_fixture.hpp @@ -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) { diff --git a/repertory/repertory_test/src/fuse_drive_create_and_open_test.cpp b/repertory/repertory_test/src/fuse_drive_create_and_open_test.cpp index 3c4405fa..56edec6b 100644 --- a/repertory/repertory_test/src/fuse_drive_create_and_open_test.cpp +++ b/repertory/repertory_test/src/fuse_drive_create_and_open_test.cpp @@ -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 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 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 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 diff --git a/support/src/utils/unix.cpp b/support/src/utils/unix.cpp index 5871db82..be53711e 100644 --- a/support/src/utils/unix.cpp +++ b/support/src/utils/unix.cpp @@ -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 { + REPERTORY_USES_FUNCTION_NAME(); + + std::vector 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(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(pass->pw_gid), + reinterpret_cast(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(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 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(group_count)); -#if defined(__APPLE__) - getgrouplist(pass->pw_name, pass->pw_gid, - reinterpret_cast(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 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