Skip to content

Commit

Permalink
[ 6497] Require icp -f -R to target resource with replica
Browse files Browse the repository at this point in the history
When overwriting a data object via icp -f, any explicitly specified target
resource ought to have a replica to overwrite. icp will not create new
replicas for existing data objects (apart from policy, of course). This
change fixes the historical behavior of selecting an existing replica to
overwrite in the absence of the target resource.
  • Loading branch information
alanking committed Nov 2, 2023
1 parent 6c2d9eb commit c4e9bee
Showing 1 changed file with 56 additions and 9 deletions.
65 changes: 56 additions & 9 deletions server/api/src/rsDataObjCopy.cpp
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
#include "irods/rsDataObjCopy.hpp"

#include "irods/collection.hpp"
#include "irods/dataObjClose.h"
#include "irods/dataObjCopy.h"
Expand All @@ -6,12 +8,12 @@
#include "irods/dataObjRepl.h"
#include "irods/getRemoteZoneResc.h"
#include "irods/irods_logger.hpp"
#include "irods/key_value_proxy.hpp"
#include "irods/objMetaOpr.hpp"
#include "irods/rcGlobalExtern.h"
#include "irods/regDataObj.h"
#include "irods/rodsLog.h"
#include "irods/rsDataObjClose.hpp"
#include "irods/rsDataObjCopy.hpp"
#include "irods/rsDataObjCreate.hpp"
#include "irods/rsDataObjOpen.hpp"
#include "irods/rsDataObjRepl.hpp"
Expand All @@ -24,7 +26,8 @@
#define IRODS_FILESYSTEM_ENABLE_SERVER_SIDE_API
#include "irods/filesystem.hpp"

#include "irods/key_value_proxy.hpp"
#define IRODS_REPLICA_ENABLE_SERVER_SIDE_API
#include "irods/data_object_proxy.hpp"

// =-=-=-=-=-=-=-
#include "irods/irods_resource_redirect.hpp"
Expand All @@ -35,6 +38,8 @@

namespace
{
namespace fs = irods::experimental::filesystem;

using log_api = irods::experimental::log::api;

int connect_to_remote_zone(
Expand Down Expand Up @@ -212,29 +217,71 @@ namespace
return ec;
} // close_destination_data_obj

auto throw_if_force_overwrite_to_new_resource(RsComm& _comm, const DataObjInp& _inp) -> void
{
namespace id = irods::experimental::data_object;

const auto cond_input = irods::experimental::make_key_value_proxy(_inp.condInput);

if (!cond_input.contains(FORCE_FLAG_KW)) {
return;
}

const auto destination_resource_itr = cond_input.find(DEST_RESC_NAME_KW);

if (destination_resource_itr == std::end(cond_input)) {
return;
}

const auto destination_resource = *destination_resource_itr;

auto [doi, lm] = irods::experimental::data_object::make_data_object_proxy(_comm, fs::path{_inp.objPath});

if (!id::root_resource_has_replica(doi, destination_resource.value())) {
THROW(
HIERARCHY_ERROR,
fmt::format(
"[{}]: Cannot overwrite [{}] on resource [{}] because resource does not hold a replica.", __func__, _inp.objPath, destination_resource.value()));
}
} // throw_if_force_overwrite_to_new_resource

int rsDataObjCopy_impl(
rsComm_t *rsComm,
dataObjCopyInp_t *dataObjCopyInp,
transferStat_t **transStat)
{
namespace fs = irods::experimental::filesystem;

dataObjInp_t* srcDataObjInp = &dataObjCopyInp->srcDataObjInp;
dataObjInp_t* destDataObjInp = &dataObjCopyInp->destDataObjInp;
try {
if (!fs::server::is_data_object(*rsComm, srcDataObjInp->objPath) ||
fs::path{destDataObjInp->objPath}.is_relative()) {
const auto source_exists_and_is_data_object = fs::server::is_data_object(*rsComm, srcDataObjInp->objPath);
if (!source_exists_and_is_data_object || fs::path{destDataObjInp->objPath}.is_relative()) {
return USER_INPUT_PATH_ERR;
}

if (irods::is_force_flag_required(*rsComm, *destDataObjInp)) {
return OVERWRITE_WITHOUT_FORCE_FLAG;
// These checks should only be done when the destination data object exists. If not, it does not matter if
// the force flag was provided or not, or which resource is being targeted for the copy.
const auto destination_exists_and_is_data_object =
fs::server::is_data_object(*rsComm, destDataObjInp->objPath);
if (destination_exists_and_is_data_object) {
if (!getValByKey(&destDataObjInp->condInput, FORCE_FLAG_KW)) {
THROW(OVERWRITE_WITHOUT_FORCE_FLAG,
fmt::format("[{}]: Overwrite of [{}] requires use of the force flag keyword [{}].",
__func__,
destDataObjInp->objPath,
FORCE_FLAG_KW));
}

throw_if_force_overwrite_to_new_resource(*rsComm, *destDataObjInp);
}
}
catch (const fs::filesystem_error& e) {
irods::experimental::log::api::error(e.what());
log_api::error(e.what());
return e.code().value();
}
catch (const irods::exception& e) {
log_api::error(e.client_display_what());
return e.code();
}

specCollCache_t *specCollCache{};
resolveLinkedPath(rsComm, srcDataObjInp->objPath, &specCollCache, &srcDataObjInp->condInput);
Expand Down

0 comments on commit c4e9bee

Please sign in to comment.