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 ed466e2 commit afa9b14
Showing 1 changed file with 55 additions and 7 deletions.
62 changes: 55 additions & 7 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,13 +217,43 @@ namespace
return ec;
} // close_destination_data_obj

auto throw_if_force_overwrite_to_new_resource(RsComm& _comm, const DataObjInp& _inp) -> void
{
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});

const auto hier_match = [&destination_resource, &replicas = doi.replicas()] {
return std::any_of(replicas.cbegin(), replicas.cend(), [&destination_resource](const auto& r) {
return irods::hierarchy_parser{r.hierarchy().data()}.first_resc() == destination_resource.value();
});
}();

if (!hier_match) {
THROW(
HIERARCHY_ERROR,
fmt::format(
"cannot force put [{}] to a different resource [{}]", _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 {
Expand All @@ -227,14 +262,27 @@ namespace
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.
if (fs::server::is_data_object(*rsComm, destDataObjInp->objPath)) {
if (!getValByKey(&destDataObjInp->condInput, FORCE_FLAG_KW)) {
THROW(OVERWRITE_WITHOUT_FORCE_FLAG,
fmt::format("Object-level overwrite of [{}] requires use of the force flag keyword [{}]",
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 afa9b14

Please sign in to comment.