/******************************************************************************* * 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