diff --git a/src/providers/s3/s3_provider.cpp b/src/providers/s3/s3_provider.cpp index 0de96583..5e3116fb 100644 --- a/src/providers/s3/s3_provider.cpp +++ b/src/providers/s3/s3_provider.cpp @@ -1072,11 +1072,156 @@ void s3_provider::remove_deleted_files() { } auto s3_provider::remove_directory(const std::string &api_path) -> api_error { - return api_error::not_implemented; + const auto notify_end = [&api_path](api_error error) -> api_error { + if (error == api_error::success) { + event_system::instance().raise(api_path); + } else { + event_system::instance().raise( + api_path, api_error_to_string(error)); + } + return error; + }; + + bool exists{}; + auto res = is_directory(api_path, exists); + if (res != api_error::success) { + return res; + } + if (not exists) { + return notify_end(api_error::item_not_found); + } + + const auto cfg = config_.get_s3_config(); + const auto is_encrypted = not cfg.encryption_token.empty(); + + std::string key; + if (is_encrypted) { + res = get_item_meta(api_path, META_KEY, key); + if (res != api_error::success) { + return notify_end(res); + } + } + + const auto object_name = + utils::path::create_api_path(is_encrypted ? key : api_path); + + curl::requests::http_delete del{}; + del.allow_timeout = true; + del.aws_service = "aws:amz:" + cfg.region + ":s3"; + del.path = object_name + '/'; + + long response_code{}; + stop_type stop_requested{}; + if (not comm_.make_request(del, response_code, stop_requested)) { + utils::error::raise_api_path_error(__FUNCTION__, api_path, + api_error::comm_error, + "failed to remove directory"); + return notify_end(api_error::comm_error); + } + + if ((response_code < http_error_codes::ok || + response_code >= http_error_codes::multiple_choices) && + response_code != http_error_codes::not_found) { + utils::error::raise_api_path_error(__FUNCTION__, api_path, response_code, + "failed to remove directory"); + return notify_end(api_error::comm_error); + } + + auto status = db_->Delete(rocksdb::WriteOptions(), api_path); + if (not status.ok()) { + utils::error::raise_api_path_error(__FUNCTION__, api_path, status.code(), + "failed to remove directory"); + return notify_end(api_error::error); + } + + return notify_end(api_error::success); } auto s3_provider::remove_file(const std::string &api_path) -> api_error { - return api_error::not_implemented; + const auto notify_end = [&api_path](api_error error) -> api_error { + if (error == api_error::success) { + event_system::instance().raise(api_path); + } else { + event_system::instance().raise( + api_path, api_error_to_string(error)); + } + + return error; + }; + + const auto *const function_name = __FUNCTION__; + + const auto remove_file_meta = [this, &api_path, &function_name, + ¬ify_end]() -> api_error { + api_meta_map meta{}; + auto res = get_item_meta(api_path, meta); + + auto res2 = db_->Delete(rocksdb::WriteOptions(), api_path); + if (not res2.ok()) { + utils::error::raise_api_path_error(function_name, api_path, res2.code(), + "failed to remove file"); + return notify_end(api_error::error); + } + + return notify_end(res); + }; + + bool exists{}; + auto res = is_directory(api_path, exists); + if (res != api_error::success) { + return notify_end(res); + } + if (exists) { + exists = false; + return notify_end(api_error::directory_exists); + } + + res = is_file(api_path, exists); + if (res != api_error::success) { + return notify_end(res); + } + if (not exists) { + event_system::instance().raise( + api_path, api_error_to_string(api_error::item_not_found)); + return remove_file_meta(); + } + + const auto cfg = config_.get_s3_config(); + const auto is_encrypted = not cfg.encryption_token.empty(); + + std::string key; + if (is_encrypted) { + res = get_item_meta(api_path, META_KEY, key); + if (res != api_error::success) { + return notify_end(res); + } + } + + const auto object_name = + utils::path::create_api_path(is_encrypted ? key : api_path); + + curl::requests::http_delete del{}; + del.allow_timeout = true; + del.aws_service = "aws:amz:" + cfg.region + ":s3"; + del.path = object_name; + + long response_code{}; + stop_type stop_requested{}; + if (not comm_.make_request(del, response_code, stop_requested)) { + utils::error::raise_api_path_error( + __FUNCTION__, api_path, api_error::comm_error, "failed to remove file"); + return notify_end(api_error::comm_error); + } + + if ((response_code < http_error_codes::ok || + response_code >= http_error_codes::multiple_choices) && + response_code != http_error_codes::not_found) { + utils::error::raise_api_path_error(__FUNCTION__, api_path, response_code, + "failed to remove file"); + return notify_end(api_error::comm_error); + } + + return remove_file_meta(); } auto s3_provider::remove_item_meta(const std::string &api_path,