Add macOS support #34
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
|
@@ -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
|
||||
|
@@ -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;
|
||||
}
|
||||
|
@@ -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 {
|
||||
|
@@ -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;
|
||||
}
|
||||
|
@@ -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 {
|
||||
|
@@ -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 {
|
||||
|
@@ -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 {
|
||||
|
@@ -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 {
|
||||
|
@@ -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 {
|
||||
|
@@ -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
|
||||
|
@@ -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;
|
||||
|
@@ -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 {
|
||||
|
@@ -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) {
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
|
||||
|
Reference in New Issue
Block a user