/*******************************************************************************
* This file is part of SWIFT.
* Copyright (c) 2021 John Helly (j.c.helly@durham.ac.uk)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see .
*
******************************************************************************/
/* Config parameters. */
#include
/* Some standard headers. */
#include
#include
#include
/* Local headers */
#include "error.h"
/* This object's header */
#include "hdf5_object_to_blob.h"
#ifdef HAVE_HDF5
#include
#define MAX_FILENAME_LENGTH 500
/**
* @brief Generates a file name using the process ID and host name
*
* @param prefix Prefix to add to the file name
* @param name Buffer to write the file name to
* @param len Length of the buffer
*
*/
static void unique_filename(char *prefix, char *name, size_t len) {
/* Get our process ID */
long pid = (long)getpid();
/* Get our host name. May be truncated or empty. */
char hostname[MAX_FILENAME_LENGTH];
if (gethostname(hostname, MAX_FILENAME_LENGTH) != 0) {
/* gethostname() call failed. Make hostname an empty string. */
hostname[0] = (char)0;
} else {
/* gethostname() successful. Add null terminator in case of truncation . */
hostname[MAX_FILENAME_LENGTH - 1] = (char)0;
}
/* Try to create a unique name. If truncated, try to use it anyway. */
int ret = snprintf(name, len, "%s.%s.%ld.tmp", prefix, hostname, pid);
if (ret < 0) {
error("snprintf call failed generating filename");
} else if (((size_t)ret) >= len) {
/* Output has been truncated */
name[len - 1] = (char)0;
}
}
/**
* @brief Copy a HDF5 object and its members to a byte array
*
* @param group_id Group containing the object to copy
* @param name Name of the object
* @param len Returns the size of the output array
* @param data Returns a pointer to the output array
*
* This creates a HDF5 file image in memory, copies the required
* object to the file image, then returns a copy of the image as
* a newly allocated array.
*
*/
void hdf5_object_to_blob(hid_t group_id, char *name, size_t *len, void **data) {
/* Set up property list */
hid_t fapl_id = H5Pcreate(H5P_FILE_ACCESS);
const size_t increment = 1024 * 1024;
const hbool_t backing_store = 0;
if (H5Pset_fapl_core(fapl_id, increment, backing_store) < 0)
error("Unable to set core driver");
/* Generate a file name which (hopefully!) doesn't exist */
char filename[MAX_FILENAME_LENGTH];
unique_filename("/tmp/__SWIFT_HDF5_CORE_WRITE", filename,
MAX_FILENAME_LENGTH);
/* Create the file image in memory (file with this name must not exist) */
hid_t file_id = H5Fcreate(filename, H5F_ACC_TRUNC, H5P_DEFAULT, fapl_id);
H5Pclose(fapl_id);
if (file_id < 0) error("Failed to create HDF5 file in memory");
/* Copy the input object to the file image */
if (H5Ocopy(group_id, name, file_id, name, H5P_DEFAULT, H5P_DEFAULT) < 0)
error("Failed to copy HDF5 object %s", name);
H5Fflush(file_id, H5F_SCOPE_GLOBAL);
/* Store the size of the file image */
ssize_t size = H5Fget_file_image(file_id, NULL, 0);
if (size < 0) error("Failed to get HDF5 file image size");
*len = (size_t)size;
/* Copy the file image to a new data array */
*data = malloc(*len);
if (H5Fget_file_image(file_id, *data, *len) < 0)
error("Failed to copy HDF5 file image to array");
/* Close the file image */
H5Fclose(file_id);
}
/**
* @brief Copy a HDF5 object from a byte array to a HDF5 file
*
* @param len Size of the input byte array
* @param data Pointer to the input byte array
* @param dest_id HDF5 group in which to write the object
* @param name Name of the object
*
* This opens the HDF5 file image supplied in data and copies
* the named object to the HDF5 group specified by dest_id.
*
*/
void blob_to_hdf5_object(size_t len, void *data, hid_t dest_id, char *name) {
/* Set up property list */
hid_t fapl_id = H5Pcreate(H5P_FILE_ACCESS);
const size_t increment = 1024 * 1024;
const hbool_t backing_store = 0;
if (H5Pset_fapl_core(fapl_id, increment, backing_store) < 0)
error("Unable to set core driver");
if (H5Pset_file_image(fapl_id, data, len) < 0)
error("Unable to set file image");
/* Generate a file name which (hopefully!) doesn't exist */
char filename[MAX_FILENAME_LENGTH];
unique_filename("/tmp/__SWIFT_HDF5_CORE_READ", filename, MAX_FILENAME_LENGTH);
/* Open the file image (file with this name must not exist) */
hid_t file_id = H5Fopen(filename, H5F_ACC_RDONLY, fapl_id);
if (file_id < 0)
error(
"Opening HDF5 file image failed, possibly because file %s already "
"exists",
filename);
H5Pclose(fapl_id);
/* Copy the object from the file image to the destination */
if (H5Ocopy(file_id, name, dest_id, name, H5P_DEFAULT, H5P_DEFAULT) < 0)
error("Failed to copy HDF5 object %s", name);
/* Close the file image */
H5Fclose(file_id);
}
#endif