Skip to content

Commit

Permalink
Added support for creating soft/hard/external links
Browse files Browse the repository at this point in the history
  • Loading branch information
DavidAce committed Oct 2, 2021
1 parent a52b38c commit 6d18873
Show file tree
Hide file tree
Showing 3 changed files with 142 additions and 27 deletions.
37 changes: 33 additions & 4 deletions include/h5pp/details/h5ppFile.h
Original file line number Diff line number Diff line change
Expand Up @@ -730,10 +730,6 @@ namespace h5pp {
return dsetInfo;
}

void writeSymbolicLink(std::string_view src_path, std::string_view tgt_path) {
h5pp::hdf5::writeSymbolicLink(openFileHandle(), src_path, tgt_path, std::nullopt, plists);
}

template<typename DataType, typename = std::enable_if_t<not std::is_const_v<DataType>>>
void readDataset(DataType &data, DataInfo &dataInfo, const DsetInfo &dsetInfo) const {
h5pp::hdf5::resizeData(data, dataInfo, dsetInfo);
Expand Down Expand Up @@ -1372,6 +1368,39 @@ namespace h5pp {
return data;
}

/*
*
*
* Functions for creating hard/soft/external links
*
*
*/

void createSoftLink(std::string_view targetLinkPath, std::string_view softLinkPath) {
h5pp::hdf5::createSoftLink(targetLinkPath, openFileHandle(), softLinkPath, plists);
}

void createHardLink(std::string_view targetLinkPath, std::string_view hardLinkPath) {
h5pp::hdf5::createHardLink(openFileHandle(), targetLinkPath, openFileHandle(), hardLinkPath, plists);
}

void createExternalLink(std::string_view targetFilePath, /*!< Path to an external hdf5 file with the desired link. If relative, it is relative to the current file */
std::string_view targetLinkPath, /*!< Full path to link within the external file */
std::string_view softLinkPath /*!< Full path to the new soft link created within this file */
) {
// The given targetFilePath is written as-is into the TARGETFILE property of the new esternal link.
// Therefore it is important that it is written either as:
// 1: a path relative to the current file, and not relative to the current process, or
// 2: a full path
if(fs::path(targetFilePath).is_relative()){
auto prox = fs::proximate(targetFilePath, filePath);
if(prox != targetFilePath) h5pp::logger::log->debug("External link [{}] is not relative to the current file [{}]."
"This can cause a dangling soft link");
}
h5pp::hdf5::createExternalLink(targetFilePath, targetLinkPath, openFileHandle(), softLinkPath, plists);
}


/*
*
*
Expand Down
101 changes: 78 additions & 23 deletions include/h5pp/details/h5ppHdf5.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#pragma once
#include "h5ppDebug.h"
#include "h5ppEigen.h"
#include "h5ppEnums.h"
#include "h5ppFilesystem.h"
Expand Down Expand Up @@ -28,7 +29,7 @@ namespace h5pp::hdf5 {
// [3]: this/is/a/long
// [4]: this/is/a/long/path

// It is very important to note that the resulting views are not null terminate. Therefore, these vector elements
// It is very important to note that the resulting views are not null terminated. Therefore, these vector elements
// **must not** be used as c-style arrays using their .data() member functions.
std::vector<std::string_view> output;
size_t currentPosition = 0;
Expand Down Expand Up @@ -970,25 +971,78 @@ namespace h5pp::hdf5 {
}

template<typename h5x>
inline void writeSymbolicLink(const h5x &loc,
std::string_view srcPath,
std::string_view tgtPath,
std::optional<bool> linkExists = std::nullopt,
const PropertyLists &plists = PropertyLists()) {
inline void createSoftLink(std::string_view targetLinkPath,
const h5x &loc,
std::string_view softLinkPath,
const PropertyLists &plists = PropertyLists()) {
static_assert(h5pp::type::sfinae::is_h5_loc_or_hid_v<h5x>,
"Template function [h5pp::hdf5::writeSymbolicLink(const h5x & loc, ...)] requires type h5x to be: "
"Template function [h5pp::hdf5::createSoftLink(const h5x & loc, ...)] requires type h5x to be: "
"[h5pp::hid::h5f], [h5pp::hid::h5g], [h5pp::hid::h5o] or [hid_t]");
if(not linkExists) linkExists = checkIfLinkExists(loc, srcPath, plists.linkAccess);
if(not linkExists.value()) {
h5pp::logger::log->trace("Creating symbolic link [{}] --> [{}]", srcPath, tgtPath);
herr_t retval =
H5Lcreate_soft(util::safe_str(srcPath).c_str(), loc, util::safe_str(tgtPath).c_str(), plists.linkCreate, plists.linkAccess);
if(retval < 0) {
H5Eprint(H5E_DEFAULT, stderr);
throw std::runtime_error(h5pp::format("Failed to write symbolic link [{}] ", srcPath));
}
} else {
throw std::runtime_error(h5pp::format("Tried to write soft link to non-existing path [{}]", srcPath));
if constexpr(not h5pp::ndebug) {
if(not checkIfLinkExists(loc, targetLinkPath, plists.linkAccess))
throw std::runtime_error(h5pp::format("Tried to create soft link to a path that does not exist [{}]", targetLinkPath));
}

h5pp::logger::log->trace("Creating soft link [{}] --> [{}]", targetLinkPath, softLinkPath);
herr_t retval = H5Lcreate_soft(util::safe_str(targetLinkPath).c_str(),
loc,
util::safe_str(softLinkPath).c_str(),
plists.linkCreate,
plists.linkAccess);
if(retval < 0) {
H5Eprint(H5E_DEFAULT, stderr);
throw std::runtime_error(h5pp::format("Failed to create soft link [{}] ", targetLinkPath));
}
}

template<typename h5x>
inline void createHardLink(
const h5x &targetLinkLoc,
std::string_view targetLinkPath,
const h5x &hardLinkLoc,
std::string_view hardLinkPath,
const PropertyLists &plists = PropertyLists()) {
static_assert(h5pp::type::sfinae::is_h5_loc_or_hid_v<h5x>,
"Template function [h5pp::hdf5::createHardLink(const h5x & loc, ...)] requires type h5x to be: "
"[h5pp::hid::h5f], [h5pp::hid::h5g], [h5pp::hid::h5o] or [hid_t]");
if constexpr(not h5pp::ndebug) {
if(not checkIfLinkExists(targetLinkLoc, targetLinkPath, plists.linkAccess))
throw std::runtime_error(h5pp::format("Tried to create a hard link to a path that does not exist [{}]", targetLinkPath));
}
h5pp::logger::log->trace("Creating hard link [{}] --> [{}]", targetLinkPath, hardLinkPath);
herr_t retval = H5Lcreate_hard(targetLinkLoc,
util::safe_str(targetLinkPath).c_str(),
hardLinkLoc,
util::safe_str(hardLinkPath).c_str(),
plists.linkCreate,
plists.linkAccess);
if(retval < 0) {
H5Eprint(H5E_DEFAULT, stderr);
throw std::runtime_error(h5pp::format("Failed to create hard link [{}] -> [{}] ", targetLinkPath, hardLinkPath));
}
}

template<typename h5x>
void createExternalLink(std::string_view targetFilePath,
std::string_view targetLinkPath,
const h5x &loc,
std::string_view softLinkPath,
const PropertyLists &plists = PropertyLists()) {
static_assert(h5pp::type::sfinae::is_h5_loc_or_hid_v<h5x>,
"Template function [h5pp::hdf5::createExternalLink(const h5x & loc, ...)] requires type h5x to be: "
"[h5pp::hid::h5f], [h5pp::hid::h5g], [h5pp::hid::h5o] or [hid_t]");
h5pp::logger::log->trace("Creating external link [{}] from file [{}] : [{}]", softLinkPath, targetFilePath, targetLinkPath);

herr_t retval = H5Lcreate_external(util::safe_str(targetFilePath).c_str(),
util::safe_str(targetLinkPath).c_str(),
loc,
util::safe_str(softLinkPath).c_str(),
plists.linkCreate,
plists.linkAccess);

if(retval < 0) {
H5Eprint(H5E_DEFAULT, stderr);
throw std::runtime_error(h5pp::format("Failed to create external link [{}] --> [{}]", targetLinkPath, softLinkPath));
}
}

Expand Down Expand Up @@ -1808,7 +1862,7 @@ namespace h5pp::hdf5 {
maxHits,
maxDepth);

if (not checkIfLinkExists(loc,searchRoot,linkAccess)){
if(not checkIfLinkExists(loc, searchRoot, linkAccess)) {
H5Eprint(H5E_DEFAULT, stderr);
throw std::runtime_error(h5pp::format("Cannot find links inside group [{}]: it does not exist", searchRoot));
}
Expand All @@ -1820,10 +1874,11 @@ namespace h5pp::hdf5 {
herr_t err = internal::visit_by_name<ObjType>(loc, searchRoot, matchList, linkAccess);
if(err < 0) {
H5Eprint(H5E_DEFAULT, stderr);
throw std::runtime_error(h5pp::format("Error occurred when trying to find links of type [{}] containing [{}] while iterating from root [{}]",
internal::getObjTypeName<ObjType>(),
searchKey,
searchRoot));
throw std::runtime_error(
h5pp::format("Error occurred when trying to find links of type [{}] containing [{}] while iterating from root [{}]",
internal::getObjTypeName<ObjType>(),
searchKey,
searchRoot));
}
return matchList;
}
Expand Down
31 changes: 31 additions & 0 deletions tests/test-externalLinks.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#define CATCH_CONFIG_RUNNER
#include "catch.hpp"
#include <h5pp/h5pp.h>

TEST_CASE("Test adding external links from other another file", "[External Link]") {
SECTION("Create an external file A"){
h5pp::File fileA("output/externalLink-A.h5", h5pp::FilePermission::REPLACE, 2);
fileA.writeDataset(42.0, "dsetA");
}
SECTION("Add external link to file B") {
h5pp::File fileB("output/externalLink-B.h5", h5pp::FilePermission::REPLACE, 2);
fileB.createExternalLink("externalLink-A.h5", "dsetA", "dsetA");
REQUIRE(fileB.readDataset<double>("dsetA") == 42.0);
}
}






int main(int argc, char *argv[]) {

Catch::Session session; // There must be exactly one instance
int returnCode = session.applyCommandLine(argc, argv);
if(returnCode != 0) // Indicates a command line error
return returnCode;
// session.configData().showSuccessfulTests = true;
// session.configData().reporterName = "compact";
return session.run();
}

0 comments on commit 6d18873

Please sign in to comment.