diff options
Diffstat (limited to 'test/h5test.c')
| -rw-r--r-- | test/h5test.c | 2123 |
1 files changed, 1618 insertions, 505 deletions
diff --git a/test/h5test.c b/test/h5test.c index 7faba81..0138c69 100644 --- a/test/h5test.c +++ b/test/h5test.c @@ -1,40 +1,37 @@ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Copyright by The HDF Group. * - * Copyright by the Board of Trustees of the University of Illinois. * * All rights reserved. * * * * This file is part of HDF5. The full HDF5 copyright notice, including * * terms governing use, modification, and redistribution, is contained in * - * the files COPYING and Copyright.html. COPYING can be found at the root * - * of the source code distribution tree; Copyright.html can be found at the * - * root level of an installed copy of the electronic HDF5 document set and * - * is linked from the top-level documents page. It can also be found at * - * http://hdfgroup.org/HDF5/doc/Copyright.html. If you do not have * - * access to either file, you may request a copy from help@hdfgroup.org. * + * the COPYING file, which can be found at the root of the source code * + * distribution tree, or in https://www.hdfgroup.org/licenses. * + * If you do not have access to either file, you may request a copy from * + * help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* - * Programmer: Robb Matzke <matzke@llnl.gov> + * Programmer: Robb Matzke * Thursday, November 19, 1998 * * Purpose: Provides support functions for most of the hdf5 tests cases. * */ -#undef NDEBUG /*override -DNDEBUG */ -#include <sys/types.h> -#include <sys/stat.h> +#undef NDEBUG /*override -DNDEBUG */ + #include "h5test.h" #include "H5srcdir.h" +#include "H5srcdir_str.h" /* Necessary for h5_verify_cached_stabs() */ -#define H5G_PACKAGE +#define H5G_FRIEND /*suppress error about including H5Gpkg */ #define H5G_TESTING #include "H5Gpkg.h" #ifdef H5_HAVE_WIN32_API #include <process.h> -#endif /* H5_HAVE_WIN32_API */ +#endif /* H5_HAVE_WIN32_API */ /* * Define these environment variables or constants to influence functions in @@ -42,10 +39,10 @@ * to the cpp constant. If neither is defined then use some default value. * * HDF5_DRIVER: This string describes what low level file driver to - * use for HDF5 file access. The first word in the - * value is the name of the driver and subsequent data - * is interpreted according to the driver. See - * h5_fileaccess() for details. + * use for HDF5 file access. + * + * HDF5_LIBVER_BOUNDS: This string describes what library version bounds to + * use for HDF5 file access. See h5_get_libver_fapl() for details. * * HDF5_PREFIX: A string to add to the beginning of all serial test * file names. This can be used to run tests in a @@ -70,13 +67,12 @@ #ifndef HDF5_PARAPREFIX #define HDF5_PARAPREFIX "" #endif -char *paraprefix = NULL; /* for command line option para-prefix */ +char *paraprefix = NULL; /* for command line option para-prefix */ #ifdef H5_HAVE_PARALLEL -MPI_Info h5_io_info_g=MPI_INFO_NULL;/* MPI INFO object for IO */ +MPI_Info h5_io_info_g = MPI_INFO_NULL; /* MPI INFO object for IO */ #endif -#define FILENAME_BUF_SIZE 1024 -#define READ_BUF_SIZE 4096 +#define READ_BUF_SIZE 65536 /* * These are the letters that are appended to the file name when generating @@ -92,9 +88,38 @@ MPI_Info h5_io_info_g=MPI_INFO_NULL;/* MPI INFO object for IO */ */ static const char *multi_letters = "msbrglo"; +/* Length of multi-file VFD filename buffers */ +#define H5TEST_MULTI_FILENAME_LEN 1024 + +/* Temporary file for sending signal messages */ +#define TMP_SIGNAL_FILE "tmp_signal_file" + +/* The # of seconds to wait for the message file--used by h5_wait_message() */ +#define MESSAGE_TIMEOUT 300 /* Timeout in seconds */ + +/* Buffer to construct path in and return pointer to */ +static char srcdir_path[1024]; + +/* Buffer to construct file in and return pointer to */ +static char srcdir_testpath[1024]; + +/* The strings that correspond to library version bounds H5F_libver_t in H5Fpublic.h */ +/* This is used by h5_get_version_string() */ +const char *LIBVER_NAMES[] = {"earliest", /* H5F_LIBVER_EARLIEST = 0 */ + "v18", /* H5F_LIBVER_V18 = 1 */ + "v110", /* H5F_LIBVER_V110 = 2 */ + "v112", /* H5F_LIBVER_V112 = 3 */ + "v114", /* H5F_LIBVER_V114 = 4 */ + "latest", /* H5F_LIBVER_V116 = 5 */ + NULL}; + +/* Previous error reporting function */ +static H5E_auto2_t err_func = NULL; + static herr_t h5_errors(hid_t estack, void *client_data); +static char *h5_fixname_real(const char *base_name, hid_t fapl, const char *_suffix, char *fullname, + size_t size, hbool_t nest_printf, hbool_t subst_for_superblock); - /*------------------------------------------------------------------------- * Function: h5_errors * @@ -112,13 +137,103 @@ static herr_t h5_errors(hid_t estack, void *client_data); *------------------------------------------------------------------------- */ static herr_t -h5_errors(hid_t estack, void UNUSED *client_data) +h5_errors(hid_t estack, void H5_ATTR_UNUSED *client_data) { H5_FAILED(); H5Eprint2(estack, stdout); return 0; } +/*------------------------------------------------------------------------- + * Function: h5_clean_files + * + * Purpose: Cleanup temporary test files (always). + * base_name contains the list of test file names. + * + * Return: void + * + * Programmer: Neil Fortner + * June 1, 2015 + * + *------------------------------------------------------------------------- + */ +void +h5_clean_files(const char *base_name[], hid_t fapl) +{ + int i; + + for (i = 0; base_name[i]; i++) { + h5_delete_test_file(base_name[i], fapl); + } + + /* Close the FAPL used to access the file */ + H5Pclose(fapl); +} /* end h5_clean_files() */ + +/*------------------------------------------------------------------------- + * Function: h5_delete_test_file + * + * Purpose Clean up temporary test files. + * + * When a test calls h5_fixname() to get a VFD-dependent + * test file name, this function can be used to clean it up. + * + * Return: void + * + * Since this is a cleanup file, we don't care if it fails. + * + * Programmer: Dana Robinson + * February 2016 + * + *------------------------------------------------------------------------- + */ +void +h5_delete_test_file(const char *base_name, hid_t fapl) +{ + char filename[1024]; /* VFD-dependent filename to delete */ + + /* Get the VFD-dependent filename */ + if (NULL == h5_fixname(base_name, fapl, filename, sizeof(filename))) + return; + + H5E_BEGIN_TRY + { + H5Fdelete(filename, fapl); + } + H5E_END_TRY; + +} /* end h5_delete_test_file() */ + +/*------------------------------------------------------------------------- + * Function: h5_delete_all_test_files + * + * Purpose Clean up temporary test files. + * + * When a test calls h5_fixname() get a VFD-dependent + * test file name, this function can be used to clean it up. + * + * This function takes an array of filenames that ends with + * a NULL string and cleans them all. + * + * Return: void + * + * Since this is a cleanup file, we don't care if it fails. + * + * Programmer: Dana Robinson + * February 2016 + * + *------------------------------------------------------------------------- + */ +void +h5_delete_all_test_files(const char *base_name[], hid_t fapl) +{ + int i; /* iterator */ + + for (i = 0; base_name[i]; i++) { + h5_delete_test_file(base_name[i], fapl); + } /* end for */ + +} /* end h5_delete_all_test_files() */ /*------------------------------------------------------------------------- * Function: h5_cleanup @@ -132,69 +247,73 @@ h5_errors(hid_t estack, void UNUSED *client_data) * Programmer: Albert Cheng * May 28, 1998 * - * Modifications: - * Albert Cheng, 2000-09-09 - * Added the explicite base_name argument to replace the - * global variable FILENAME. - * *------------------------------------------------------------------------- */ int h5_cleanup(const char *base_name[], hid_t fapl) { - char filename[1024]; - char temp[2048]; - int i, j; - int retval=0; - hid_t driver; - - if (GetTestCleanup()){ - for (i = 0; base_name[i]; i++) { - if (h5_fixname(base_name[i], fapl, filename, sizeof(filename)) == NULL) - continue; - - driver = H5Pget_driver(fapl); + int retval = 0; - if (driver == H5FD_FAMILY) { - for (j = 0; /*void*/; j++) { - HDsnprintf(temp, sizeof temp, filename, j); + if (GetTestCleanup()) { + /* Clean up files in base_name, and the FAPL */ + h5_clean_files(base_name, fapl); - if (HDaccess(temp, F_OK) < 0) - break; - - HDremove(temp); - } - } else if (driver == H5FD_CORE) { - hbool_t backing; /* Whether the core file has backing store */ - - H5Pget_fapl_core(fapl,NULL,&backing); + retval = 1; + } /* end if */ - /* If the file was stored to disk with bacing store, remove it */ - if(backing) - HDremove(filename); + /* Restore the original error reporting routine */ + h5_restore_err(); - } else if (driver == H5FD_MULTI) { - H5FD_mem_t mt; - assert(HDstrlen(multi_letters)==H5FD_MEM_NTYPES); + return retval; +} /* end h5_cleanup() */ - for (mt = H5FD_MEM_DEFAULT; mt < H5FD_MEM_NTYPES; H5_INC_ENUM(H5FD_mem_t,mt)) { - HDsnprintf(temp, sizeof temp, "%s-%c.h5", - filename, multi_letters[mt]); - HDremove(temp); /*don't care if it fails*/ - } - } else { - HDremove(filename); - } - } +/*------------------------------------------------------------------------- + * Function: h5_test_shutdown + * + * Purpose: Performs any special test cleanup required before the test + * ends. + * + * NOTE: This function should normally only be called once + * in a given test, usually just before leaving main(). It + * is intended for use in the single-file unit tests, not + * testhdf5. + * + * Return: void + * + * Programmer: Dana Robinson + * February 2016 + * + *------------------------------------------------------------------------- + */ +void +h5_test_shutdown(void) +{ - retval = 1; - } + /* Restore the original error reporting routine */ + h5_restore_err(); +} /* end h5_test_shutdown() */ - H5Pclose(fapl); - return retval; +/*------------------------------------------------------------------------- + * Function: h5_restore_err + * + * Purpose: Restore the default error handler. + * + * Return: N/A + * + * Programmer: Quincey Koziol + * Sept 10, 2015 + * + *------------------------------------------------------------------------- + */ +void +h5_restore_err(void) +{ + /* Restore the original error reporting routine */ + HDassert(err_func != NULL); + H5Eset_auto2(H5E_DEFAULT, err_func, NULL); + err_func = NULL; } - /*------------------------------------------------------------------------- * Function: h5_reset * @@ -205,8 +324,6 @@ h5_cleanup(const char *base_name[], hid_t fapl) * Programmer: Robb Matzke * Friday, November 20, 1998 * - * Modifications: - * *------------------------------------------------------------------------- */ void @@ -215,6 +332,10 @@ h5_reset(void) HDfflush(stdout); HDfflush(stderr); H5close(); + + /* Save current error stack reporting routine and redirect to our local one */ + HDassert(err_func == NULL); + H5Eget_auto2(H5E_DEFAULT, &err_func, NULL); H5Eset_auto2(H5E_DEFAULT, h5_errors, NULL); /* @@ -227,27 +348,57 @@ h5_reset(void) * appropriate configure flags/macros. QAK - 2007/12/20 */ #ifdef OLD_WAY -{ - char filename[1024]; - - /* - * Cause the library to emit some diagnostics early so they don't - * interfere with other formatted output. - */ - sprintf(filename, "/tmp/h5emit-%05d.h5", HDgetpid()); - H5E_BEGIN_TRY { - hid_t file = H5Fcreate(filename, H5F_ACC_TRUNC, H5P_DEFAULT, - H5P_DEFAULT); - hid_t grp = H5Gcreate2(file, "emit", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); - H5Gclose(grp); - H5Fclose(file); - HDunlink(filename); - } H5E_END_TRY; -} + { + char filename[1024]; + + /* + * Cause the library to emit some diagnostics early so they don't + * interfere with other formatted output. + */ + HDsnprintf(filename, sizeof(filename), "/tmp/h5emit-%05d.h5", HDgetpid()); + H5E_BEGIN_TRY + { + hid_t file = H5Fcreate(filename, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + hid_t grp = H5Gcreate2(file, "emit", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + H5Gclose(grp); + H5Fclose(file); + HDunlink(filename); + } + H5E_END_TRY; + } #endif /* OLD_WAY */ } - +/*------------------------------------------------------------------------- + * Function: h5_test_init + * + * Purpose: Performs any special actions before the test begins. + * + * NOTE: This function should normally only be called once + * in a given test, usually at the beginning of main(). It + * is intended for use in the single-file unit tests, not + * testhdf5. + * + * Return: void + * + * Programmer: Dana Robinson + * February 2016 + * + *------------------------------------------------------------------------- + */ +void +h5_test_init(void) +{ + HDfflush(stdout); + HDfflush(stderr); + H5close(); + + /* Save current error stack reporting routine and redirect to our local one */ + HDassert(err_func == NULL); + H5Eget_auto2(H5E_DEFAULT, &err_func, NULL); + H5Eset_auto2(H5E_DEFAULT, h5_errors, NULL); +} /* end h5_test_init() */ + /*------------------------------------------------------------------------- * Function: h5_fixname * @@ -268,62 +419,186 @@ h5_reset(void) * Programmer: Robb Matzke * Thursday, November 19, 1998 * - * Modifications: - * Robb Matzke, 1999-08-03 - * Modified to use the virtual file layer. + *------------------------------------------------------------------------- + */ +char * +h5_fixname(const char *base_name, hid_t fapl, char *fullname, size_t size) +{ + return (h5_fixname_real(base_name, fapl, ".h5", fullname, size, FALSE, FALSE)); +} + +/*------------------------------------------------------------------------- + * Function: h5_fixname_superblock + * + * Purpose: Like h5_fixname() but returns the name of the file you'd + * open to find the superblock. Useful for when you have to + * open a file with open(2) but the h5_fixname() string + * contains stuff like format strings. * - * Albert Cheng, 2000-01-25 - * Added prefix for parallel test files. + * Return: Success: The FULLNAME pointer. + * + * Failure: NULL if BASENAME or FULLNAME is the null + * pointer or if FULLNAME isn't large enough for + * the result. + * + * Programmer: Dana Robinson + * Spring 2019 * - * Albert Cheng, 2003-05-08 - * Changed the default parallel prefix back to NULL but added - * an explanation remark of $HDF5_PARAPREFIX. *------------------------------------------------------------------------- */ char * -h5_fixname(const char *base_name, hid_t fapl, char *fullname, size_t size) +h5_fixname_superblock(const char *base_name, hid_t fapl_id, char *fullname, size_t size) +{ + return (h5_fixname_real(base_name, fapl_id, ".h5", fullname, size, FALSE, TRUE)); +} + +/*------------------------------------------------------------------------- + * Function: h5_fixname_no_suffix + * + * Purpose: Same as h5_fixname but with no suffix appended + * + * Return: Success: The FULLNAME pointer. + * + * Failure: NULL if BASENAME or FULLNAME is the null + * pointer or if FULLNAME isn't large enough for + * the result. + * + *------------------------------------------------------------------------- + */ +char * +h5_fixname_no_suffix(const char *base_name, hid_t fapl, char *fullname, size_t size) +{ + return (h5_fixname_real(base_name, fapl, NULL, fullname, size, FALSE, FALSE)); +} + +/*------------------------------------------------------------------------- + * Function: h5_fixname_printf + * + * Purpose: Same as h5_fixname but returns a filename that can be passed + * through a printf-style function once before being passed to the file + * driver. Basically, replaces all % characters used by the file + * driver with %%. + * + * Return: Success: The FULLNAME pointer. + * + * Failure: NULL if BASENAME or FULLNAME is the null + * pointer or if FULLNAME isn't large enough for + * the result. + * + * Programmer: Neil Fortner + * Wednesday, July 15, 2015 + * + *------------------------------------------------------------------------- + */ +char * +h5_fixname_printf(const char *base_name, hid_t fapl, char *fullname, size_t size) +{ + return (h5_fixname_real(base_name, fapl, ".h5", fullname, size, TRUE, FALSE)); +} + +/*------------------------------------------------------------------------- + * Function: h5_fixname_real + * + * Purpose: Create a file name from a file base name like `test' and + * return it through the FULLNAME (at most SIZE characters + * counting the null terminator). The full name is created by + * prepending the contents of HDF5_PREFIX (separated from the + * base name by a slash) and appending a file extension based on + * the driver supplied, resulting in something like + * `ufs:/u/matzke/test.h5'. + * + * Return: Success: The FULLNAME pointer. + * + * Failure: NULL if BASENAME or FULLNAME is the null + * pointer or if FULLNAME isn't large enough for + * the result. + * + * Programmer: Robb Matzke + * Thursday, November 19, 1998 + * + *------------------------------------------------------------------------- + */ +static char * +h5_fixname_real(const char *base_name, hid_t fapl, const char *_suffix, char *fullname, size_t size, + hbool_t nest_printf, hbool_t subst_for_superblock) { - const char *prefix = NULL; - const char *suffix = ".h5"; /* suffix has default */ - char *ptr, last = '\0'; - size_t i, j; - hid_t driver = -1; - int isppdriver = 0; /* if the driver is MPI parallel */ + const char *prefix = NULL; + const char *driver_env_var = NULL; /* HDF5_DRIVER environment variable */ + char *ptr, last = '\0'; + const char *suffix = _suffix; + size_t i, j; + hid_t driver = -1; + int isppdriver = 0; /* if the driver is MPI parallel */ if (!base_name || !fullname || size < 1) return NULL; - memset(fullname, 0, size); + HDmemset(fullname, 0, size); + + /* Determine if driver is set by environment variable. If it is, + * only generate a suffix if fixing the filename for the superblock + * file. */ + driver_env_var = HDgetenv(HDF5_DRIVER); + if (driver_env_var && (H5P_DEFAULT == fapl) && subst_for_superblock) + fapl = H5P_FILE_ACCESS_DEFAULT; /* figure out the suffix */ if (H5P_DEFAULT != fapl) { - if ((driver = H5Pget_driver(fapl)) < 0) + if ((driver = H5Pget_driver(fapl)) < 0) return NULL; - if (H5FD_FAMILY == driver) - suffix = "%05d.h5"; - else if (H5FD_MULTI == driver) - suffix = NULL; + if (suffix) { + if (H5FD_FAMILY == driver) { + if (subst_for_superblock) + suffix = "-000000.h5"; + else + suffix = nest_printf ? "-%%06d.h5" : "-%06d.h5"; + } + else if (H5FD_MULTI == driver) { + + /* Check the HDF5_DRIVER environment variable in case + * we are using the split driver since both of those + * use the multi VFD under the hood. + */ +#ifdef HDF5_DRIVER + /* Use the environment variable, then the compile-time constant */ + if (!driver_env_var) + driver_env_var = HDF5_DRIVER; +#endif + if (driver_env_var && !HDstrcmp(driver_env_var, "split")) { + /* split VFD */ + if (subst_for_superblock) + suffix = ".h5.meta"; + } + else { + /* multi VFD */ + if (subst_for_superblock) + suffix = "-s.h5"; + else + suffix = NULL; + } + } + } } /* Must first check fapl is not H5P_DEFAULT (-1) because H5FD_XXX * could be of value -1 if it is not defined. */ - isppdriver = H5P_DEFAULT != fapl && - (H5FD_MPIO==driver || H5FD_MPIPOSIX==driver); + isppdriver = ((H5P_DEFAULT != fapl) || driver_env_var) && (H5FD_MPIO == driver); /* Check HDF5_NOCLEANUP environment setting. * (The #ifdef is needed to prevent compile failure in case MPI is not * configured.) */ - if (isppdriver){ + if (isppdriver) { #ifdef H5_HAVE_PARALLEL - if (getenv_all(MPI_COMM_WORLD, 0, "HDF5_NOCLEANUP")) - SetTestNoCleanup(); -#endif /* H5_HAVE_PARALLEL */ - }else{ - if (HDgetenv("HDF5_NOCLEANUP")) - SetTestNoCleanup(); + if (getenv_all(MPI_COMM_WORLD, 0, HDF5_NOCLEANUP)) + SetTestNoCleanup(); +#endif /* H5_HAVE_PARALLEL */ + } + else { + if (HDgetenv(HDF5_NOCLEANUP)) + SetTestNoCleanup(); } /* Check what prefix to use for test files. Process HDF5_PARAPREFIX and @@ -332,54 +607,55 @@ h5_fixname(const char *base_name, hid_t fapl, char *fullname, size_t size) * (The #ifdef is needed to prevent compile failure in case MPI is not * configured.) */ - if (isppdriver){ + if (isppdriver) { #ifdef H5_HAVE_PARALLEL - /* + /* * For parallel: * First use command line option, then the environment * variable, then try the constant - */ + */ static int explained = 0; - prefix = (paraprefix ? paraprefix : getenv_all(MPI_COMM_WORLD, 0, "HDF5_PARAPREFIX")); + prefix = (paraprefix ? paraprefix : getenv_all(MPI_COMM_WORLD, 0, "HDF5_PARAPREFIX")); - if (!prefix && !explained) { - /* print hint by process 0 once. */ - int mpi_rank; + if (!prefix && !explained) { + /* print hint by process 0 once. */ + int mpi_rank; - MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank); + MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank); - if (mpi_rank == 0) - printf("*** Hint ***\n" - "You can use environment variable HDF5_PARAPREFIX to " - "run parallel test files in a\n" - "different directory or to add file type prefix. E.g.,\n" - " HDF5_PARAPREFIX=pfs:/PFS/user/me\n" - " export HDF5_PARAPREFIX\n" - "*** End of Hint ***\n"); + if (mpi_rank == 0) + HDprintf("*** Hint ***\n" + "You can use environment variable HDF5_PARAPREFIX to " + "run parallel test files in a\n" + "different directory or to add file type prefix. e.g.,\n" + " HDF5_PARAPREFIX=pfs:/PFS/user/me\n" + " export HDF5_PARAPREFIX\n" + "*** End of Hint ***\n"); - explained = TRUE; + explained = TRUE; #ifdef HDF5_PARAPREFIX prefix = HDF5_PARAPREFIX; -#endif /* HDF5_PARAPREFIX */ - } -#endif /* H5_HAVE_PARALLEL */ - } else { - /* +#endif /* HDF5_PARAPREFIX */ + } +#endif /* H5_HAVE_PARALLEL */ + } + else { + /* * For serial: * First use the environment variable, then try the constant - */ - prefix = HDgetenv("HDF5_PREFIX"); + */ + prefix = HDgetenv("HDF5_PREFIX"); #ifdef HDF5_PREFIX - if (!prefix) + if (!prefix) prefix = HDF5_PREFIX; -#endif /* HDF5_PREFIX */ +#endif /* HDF5_PREFIX */ } /* Prepend the prefix value to the base name */ if (prefix && *prefix) { - if (isppdriver){ + if (isppdriver) { /* This is a parallel system */ char *subdir; @@ -391,8 +667,8 @@ h5_fixname(const char *base_name, hid_t fapl, char *fullname, size_t size) */ char *user, *login; - user = HDgetenv("USER"); - login = HDgetenv("LOGIN"); + user = HDgetenv("USER"); + login = HDgetenv("LOGIN"); subdir = (user ? user : login); if (subdir) { @@ -406,9 +682,11 @@ h5_fixname(const char *base_name, hid_t fapl, char *fullname, size_t size) } } - if (!fullname[0]) + if (!fullname[0]) { /* We didn't append the prefix yet */ - HDstrncpy(fullname, prefix, MIN(strlen(prefix), size)); + HDstrncpy(fullname, prefix, size); + fullname[size - 1] = '\0'; + } if (HDstrlen(fullname) + HDstrlen(base_name) + 1 < size) { /* @@ -429,28 +707,32 @@ h5_fixname(const char *base_name, hid_t fapl, char *fullname, size_t size) HDstrcat(fullname, "/"); HDstrcat(fullname, base_name); - } else { + } + else { /* Buffer is too small */ return NULL; } - } else { + } + else { if (HDsnprintf(fullname, size, "%s/%s", prefix, base_name) == (int)size) /* Buffer is too small */ return NULL; } - } else if (HDstrlen(base_name) >= size) { - /* Buffer is too small */ - return NULL; - } else { - HDstrcpy(fullname, base_name); - } + } + else if (HDstrlen(base_name) >= size) { + /* Buffer is too small */ + return NULL; + } + else { + HDstrcpy(fullname, base_name); + } /* Append a suffix */ if (suffix) { - if (HDstrlen(fullname) + HDstrlen(suffix) >= size) + if (HDstrlen(fullname) + HDstrlen(suffix) >= size) return NULL; - HDstrcat(fullname, suffix); + HDstrcat(fullname, suffix); } /* Remove any double slashes in the filename */ @@ -464,7 +746,6 @@ h5_fixname(const char *base_name, hid_t fapl, char *fullname, size_t size) return fullname; } - /*------------------------------------------------------------------------- * Function: h5_rmprefix * @@ -482,136 +763,151 @@ h5_fixname(const char *base_name, hid_t fapl, char *fullname, size_t size) * *------------------------------------------------------------------------- */ -const char * +H5_ATTR_PURE const char * h5_rmprefix(const char *filename) { const char *ret_ptr; if ((ret_ptr = HDstrstr(filename, ":")) == NULL) - ret_ptr = filename; + ret_ptr = filename; else - ret_ptr++; + ret_ptr++; - return(ret_ptr); + return (ret_ptr); } - /*------------------------------------------------------------------------- - * Function: h5_fileaccess + * Function: h5_fileaccess * - * Purpose: Returns a file access template which is the default template - * but with a file driver set according to the constant or - * environment variable HDF5_DRIVER + * Purpose: Returns a file access template which is the default template + * but with a file driver, VOL connector, or libver bound set + * according to a constant or environment variable * - * Return: Success: A file access property list - * - * Failure: -1 + * Return: Success: A file access property list + * Failure: H5I_INVALID_HID * * Programmer: Robb Matzke * Thursday, November 19, 1998 * - * Modifications: - * *------------------------------------------------------------------------- */ hid_t h5_fileaccess(void) { - const char *val = NULL; - const char *name; - char s[1024]; - hid_t fapl = -1; + hid_t fapl_id = H5I_INVALID_HID; - /* First use the environment variable, then the constant */ - val = HDgetenv("HDF5_DRIVER"); -#ifdef HDF5_DRIVER - if (!val) val = HDF5_DRIVER; -#endif + if ((fapl_id = H5Pcreate(H5P_FILE_ACCESS)) < 0) + goto error; - if ((fapl=H5Pcreate(H5P_FILE_ACCESS))<0) return -1; - if (!val || !*val) return fapl; /*use default*/ - - HDstrncpy(s, val, sizeof s); - s[sizeof(s)-1] = '\0'; - if (NULL==(name=HDstrtok(s, " \t\n\r"))) return fapl; - - if (!HDstrcmp(name, "sec2")) { - /* Unix read() and write() system calls */ - if (H5Pset_fapl_sec2(fapl)<0) return -1; - } else if (!HDstrcmp(name, "stdio")) { - /* Standard C fread() and fwrite() system calls */ - if (H5Pset_fapl_stdio(fapl)<0) return -1; - } else if (!HDstrcmp(name, "core")) { - /* In-core temporary file with 1MB increment */ - if (H5Pset_fapl_core(fapl, (size_t)1, TRUE)<0) return -1; - } else if (!HDstrcmp(name, "split")) { - /* Split meta data and raw data each using default driver */ - if (H5Pset_fapl_split(fapl, - "-m.h5", H5P_DEFAULT, - "-r.h5", H5P_DEFAULT)<0) - return -1; - } else if (!HDstrcmp(name, "multi")) { - /* Multi-file driver, general case of the split driver */ - H5FD_mem_t memb_map[H5FD_MEM_NTYPES]; - hid_t memb_fapl[H5FD_MEM_NTYPES]; - const char *memb_name[H5FD_MEM_NTYPES]; - char sv[H5FD_MEM_NTYPES][1024]; - haddr_t memb_addr[H5FD_MEM_NTYPES]; - H5FD_mem_t mt; - - HDmemset(memb_map, 0, sizeof memb_map); - HDmemset(memb_fapl, 0, sizeof memb_fapl); - HDmemset(memb_name, 0, sizeof memb_name); - HDmemset(memb_addr, 0, sizeof memb_addr); - - HDassert(HDstrlen(multi_letters)==H5FD_MEM_NTYPES); - for(mt = H5FD_MEM_DEFAULT; mt < H5FD_MEM_NTYPES; H5_INC_ENUM(H5FD_mem_t, mt)) { - memb_fapl[mt] = H5P_DEFAULT; - sprintf(sv[mt], "%%s-%c.h5", multi_letters[mt]); - memb_name[mt] = sv[mt]; - memb_addr[mt] = (haddr_t)MAX(mt - 1, 0) * (HADDR_MAX / 10); - } /* end for */ - - if (H5Pset_fapl_multi(fapl, memb_map, memb_fapl, memb_name, - memb_addr, FALSE)<0) { - return -1; - } - } else if (!HDstrcmp(name, "family")) { - hsize_t fam_size = 100*1024*1024; /*100 MB*/ - - /* Family of files, each 1MB and using the default driver */ - if ((val=HDstrtok(NULL, " \t\n\r"))) - fam_size = (hsize_t)(HDstrtod(val, NULL) * 1024*1024); - if (H5Pset_fapl_family(fapl, fam_size, H5P_DEFAULT)<0) - return -1; - } else if (!HDstrcmp(name, "log")) { - unsigned log_flags = H5FD_LOG_LOC_IO | H5FD_LOG_ALLOC; - - /* Log file access */ - if ((val = HDstrtok(NULL, " \t\n\r"))) - log_flags = (unsigned)HDstrtol(val, NULL, 0); - - if (H5Pset_fapl_log(fapl, NULL, log_flags, (size_t)0) < 0) - return -1; - } else if (!HDstrcmp(name, "direct")) { -#ifdef H5_HAVE_DIRECT - /* Linux direct read() and write() system calls. Set memory boundary, file block size, - * and copy buffer size to the default values. */ - if (H5Pset_fapl_direct(fapl, 1024, 4096, 8*4096)<0) return -1; + /* Check for libver bounds */ + if (h5_get_libver_fapl(fapl_id) < 0) + goto error; + + return fapl_id; + +error: + if (fapl_id != H5I_INVALID_HID) + H5Pclose(fapl_id); + return H5I_INVALID_HID; +} /* end h5_fileaccess() */ + +/*------------------------------------------------------------------------- + * Function: h5_fileaccess_flags + * + * Purpose: Returns a file access template which is the default template + * but with a file driver, VOL connector, or libver bound set + * according to a constant or environment variable + * + * Return: Success: A file access property list + * Failure: H5I_INVALID_HID + * + * Programmer: Robb Matzke + * Thursday, November 19, 1998 + * + *------------------------------------------------------------------------- + */ +hid_t +h5_fileaccess_flags(unsigned flags) +{ + hid_t fapl_id = H5I_INVALID_HID; + + if ((fapl_id = H5Pcreate(H5P_FILE_ACCESS)) < 0) + goto error; + + /* Check for libver bounds */ + if ((flags & H5_FILEACCESS_LIBVER) && h5_get_libver_fapl(fapl_id) < 0) + goto error; + + return fapl_id; + +error: + if (fapl_id != H5I_INVALID_HID) + H5Pclose(fapl_id); + return H5I_INVALID_HID; +} /* end h5_fileaccess_flags() */ + +/*------------------------------------------------------------------------- + * Function: h5_get_libver_fapl + * + * Purpose: Sets the library version bounds for a FAPL according to the + * value in the constant or environment variable "HDF5_LIBVER_BOUNDS". + * + * Return: Success: 0 + * Failure: -1 + * + * Programmer: Quincey Koziol + * November 2018 + * + *------------------------------------------------------------------------- + */ +herr_t +h5_get_libver_fapl(hid_t fapl) +{ + const char *env = NULL; /* HDF5_DRIVER environment variable */ + const char *tok = NULL; /* strtok pointer */ + char *lasts = NULL; /* Context pointer for strtok_r() call */ + char buf[1024]; /* buffer for tokenizing HDF5_DRIVER */ + + /* Get the environment variable, if it exists */ + env = HDgetenv("HDF5_LIBVER_BOUNDS"); +#ifdef HDF5_LIBVER_BOUNDS + /* Use the environment variable, then the compile-time constant */ + if (!env) + env = HDF5_LIBVER_BOUNDS; #endif - } else if(!HDstrcmp(name, "latest")) { - /* use the latest format */ - if(H5Pset_libver_bounds(fapl, H5F_LIBVER_LATEST, H5F_LIBVER_LATEST) < 0) - return -1; - } else { - /* Unknown driver */ - return -1; - } - return fapl; -} + /* If the environment variable was not set, just return + * without modifying the FAPL. + */ + if (!env || !*env) + goto done; + + /* Get the first 'word' of the environment variable. + * If it's nothing (environment variable was whitespace) + * just return the default fapl. + */ + HDstrncpy(buf, env, sizeof(buf)); + buf[sizeof(buf) - 1] = '\0'; + if (NULL == (tok = HDstrtok_r(buf, " \t\n\r", &lasts))) + goto done; + + if (!HDstrcmp(tok, "latest")) { + /* use the latest format */ + if (H5Pset_libver_bounds(fapl, H5F_LIBVER_LATEST, H5F_LIBVER_LATEST) < 0) + goto error; + } /* end if */ + else { + /* Unknown setting */ + goto error; + } /* end else */ + +done: + return 0; + +error: + return -1; +} /* end h5_get_libver_fapl() */ - /*------------------------------------------------------------------------- * Function: h5_no_hwconv * @@ -629,10 +925,9 @@ h5_fileaccess(void) void h5_no_hwconv(void) { - H5Tunregister(H5T_PERS_HARD, NULL, -1, -1, NULL); + H5Tunregister(H5T_PERS_HARD, NULL, (hid_t)-1, (hid_t)-1, NULL); } - /*------------------------------------------------------------------------- * Function: h5_show_hostname * @@ -650,65 +945,64 @@ h5_no_hwconv(void) void h5_show_hostname(void) { - char hostname[80]; + char hostname[80]; #ifdef H5_HAVE_WIN32_API - WSADATA wsaData; - int err; + WSADATA wsaData; + int err; #endif /* try show the process or thread id in multiple processes cases*/ #ifdef H5_HAVE_PARALLEL { - int mpi_rank, mpi_initialized; - - MPI_Initialized(&mpi_initialized); - if (mpi_initialized){ - MPI_Comm_rank(MPI_COMM_WORLD,&mpi_rank); - printf("MPI-process %d.", mpi_rank); - }else - printf("thread 0."); + int mpi_rank, mpi_initialized, mpi_finalized; + + MPI_Initialized(&mpi_initialized); + MPI_Finalized(&mpi_finalized); + + if (mpi_initialized && !mpi_finalized) { + MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank); + HDprintf("MPI-process %d.", mpi_rank); + } + else + HDprintf("thread 0."); } -#elif defined(H5_HAVE_THREADSAFE) - printf("thread %lu.", HDpthread_self_ulong()); #else - printf("thread 0."); + HDprintf("thread %" PRIu64 ".", H5TS_thread_id()); #endif #ifdef H5_HAVE_WIN32_API - err = WSAStartup( MAKEWORD(2,2), &wsaData ); - if ( err != 0 ) { - /* could not find a usable WinSock DLL */ - return; - } - -/* Confirm that the WinSock DLL supports 2.2.*/ -/* Note that if the DLL supports versions greater */ -/* than 2.2 in addition to 2.2, it will still return */ -/* 2.2 in wVersion since that is the version we */ -/* requested. */ - - if ( LOBYTE( wsaData.wVersion ) != 2 || - HIBYTE( wsaData.wVersion ) != 2 ) { - /* could not find a usable WinSock DLL */ - WSACleanup( ); - return; - } + err = WSAStartup(MAKEWORD(2, 2), &wsaData); + if (err != 0) { + /* could not find a usable WinSock DLL */ + return; + } + + /* Confirm that the WinSock DLL supports 2.2.*/ + /* Note that if the DLL supports versions greater */ + /* than 2.2 in addition to 2.2, it will still return */ + /* 2.2 in wVersion since that is the version we */ + /* requested. */ + + if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2) { + /* could not find a usable WinSock DLL */ + WSACleanup(); + return; + } #endif #ifdef H5_HAVE_GETHOSTNAME - if (gethostname(hostname, (size_t)80) < 0) - printf(" gethostname failed\n"); + if (HDgethostname(hostname, (size_t)80) < 0) + HDprintf(" gethostname failed\n"); else - printf(" hostname=%s\n", hostname); + HDprintf(" hostname=%s\n", hostname); #else - printf(" gethostname not supported\n"); + HDprintf(" gethostname not supported\n"); #endif #ifdef H5_HAVE_WIN32_API WSACleanup(); #endif } - #ifdef H5_HAVE_PARALLEL /* * Function: h5_set_info_object @@ -726,30 +1020,34 @@ h5_show_hostname(void) int h5_set_info_object(void) { - char *envp; /* environment pointer */ - int ret_value=0; + char *envp; /* environment pointer */ + int ret_value = 0; /* handle any MPI INFO hints via $HDF5_MPI_INFO */ - if ((envp = getenv("HDF5_MPI_INFO")) != NULL){ + if ((envp = HDgetenv("HDF5_MPI_INFO")) != NULL) { char *next, *valp; valp = envp = next = HDstrdup(envp); + if (!valp) + return 0; + /* create an INFO object if not created yet */ if (h5_io_info_g == MPI_INFO_NULL) MPI_Info_create(&h5_io_info_g); do { size_t len; - char *key_val, *endp, *namep; + char *key_val, *endp, *namep; if (*valp == ';') valp++; /* copy key/value pair into temporary buffer */ - len = strcspn(valp, ";"); + len = HDstrcspn(valp, ";"); next = &valp[len]; - key_val = calloc(1, len + 1); + if (NULL == (key_val = (char *)HDcalloc(1, len + 1))) + return -1; /* increment the next pointer past the terminating semicolon */ if (*next == ';') @@ -761,8 +1059,11 @@ h5_set_info_object(void) while (*namep && (*namep == ' ' || *namep == '\t')) namep++; + if (!*namep) + continue; /* was all white space, so move to next k/v pair */ + /* eat up any ending white spaces */ - endp = &namep[strlen(namep) - 1]; + endp = &namep[HDstrlen(namep) - 1]; while (endp && (*endp == ' ' || *endp == '\t')) *endp-- = '\0'; @@ -770,7 +1071,7 @@ h5_set_info_object(void) /* find the '=' */ valp = HDstrchr(namep, '='); - if (valp != NULL) { /* it's a valid key/value pairing */ + if (valp != NULL) { /* it's a valid key/value pairing */ char *tmp_val = valp + 1; /* change '=' to \0, move valp down one */ @@ -788,7 +1089,7 @@ h5_set_info_object(void) /* actually set the darned thing */ if (MPI_SUCCESS != MPI_Info_set(h5_io_info_g, namep, valp)) { - printf("MPI_Info_set failed\n"); + HDprintf("MPI_Info_set failed\n"); ret_value = -1; } } @@ -803,7 +1104,6 @@ h5_set_info_object(void) return ret_value; } - /* * Function: h5_dump_info_object * Purpose: Display content of an MPI Info object @@ -814,30 +1114,27 @@ h5_set_info_object(void) void h5_dump_info_object(MPI_Info info) { - char key[MPI_MAX_INFO_KEY+1]; - char value[MPI_MAX_INFO_VAL+1]; - int flag; - int i, nkeys; - - printf("Dumping MPI Info Object(%d) (up to %d bytes per item):\n", (int)info, - MPI_MAX_INFO_VAL); - if (info==MPI_INFO_NULL){ - printf("object is MPI_INFO_NULL\n"); + char key[MPI_MAX_INFO_KEY + 1]; + char value[MPI_MAX_INFO_VAL + 1]; + int flag; + int i, nkeys; + + HDprintf("Dumping MPI Info Object (up to %d bytes per item):\n", MPI_MAX_INFO_VAL); + if (info == MPI_INFO_NULL) { + HDprintf("object is MPI_INFO_NULL\n"); } else { - MPI_Info_get_nkeys(info, &nkeys); - printf("object has %d items\n", nkeys); - for (i=0; i<nkeys; i++){ - MPI_Info_get_nthkey(info, i, key); - MPI_Info_get(info, key, MPI_MAX_INFO_VAL, value, &flag); - printf("%s=%s\n", key, value); - } - + MPI_Info_get_nkeys(info, &nkeys); + HDprintf("object has %d items\n", nkeys); + for (i = 0; i < nkeys; i++) { + MPI_Info_get_nthkey(info, i, key); + MPI_Info_get(info, key, MPI_MAX_INFO_VAL, value, &flag); + HDprintf("%s=%s\n", key, value); + } } } -#endif /* H5_HAVE_PARALLEL */ +#endif /* H5_HAVE_PARALLEL */ - /*------------------------------------------------------------------------- * Function: h5_get_file_size * @@ -851,115 +1148,185 @@ h5_dump_info_object(MPI_Info info) * *------------------------------------------------------------------------- */ +/* Disable warning for "format not a string literal" here -QAK */ +/* + * This pragma only needs to surround the snprintf() calls with + * temp in the code below, but early (4.4.7, at least) gcc only + * allows diagnostic pragmas to be toggled outside of functions. + */ +H5_GCC_CLANG_DIAG_OFF("format-nonliteral") h5_stat_size_t h5_get_file_size(const char *filename, hid_t fapl) { - char temp[2048]; /* Temporary buffer for file names */ - h5_stat_t sb; /* Structure for querying file info */ - int j = 0; + char temp[2048]; /* Temporary buffer for file names */ + h5_stat_t sb; /* Structure for querying file info */ + int j = 0; - if(fapl == H5P_DEFAULT) { + if (fapl == H5P_DEFAULT) { /* Get the file's statistics */ - if(0 == HDstat(filename, &sb)) - return((h5_stat_size_t)sb.st_size); + if (0 == HDstat(filename, &sb)) + return ((h5_stat_size_t)sb.st_size); } /* end if */ else { - hid_t driver; /* VFD used for file */ + hid_t driver; /* VFD used for file */ /* Get the driver used when creating the file */ - if((driver = H5Pget_driver(fapl)) < 0) - return(-1); + if ((driver = H5Pget_driver(fapl)) < 0) + return (-1); /* Check for simple cases */ - if(driver == H5FD_SEC2 || driver == H5FD_STDIO || driver == H5FD_CORE || -#ifdef H5_HAVE_PARALLEL - driver == H5FD_MPIO || driver == H5FD_MPIPOSIX || -#endif /* H5_HAVE_PARALLEL */ + if (driver == H5FD_SEC2 || driver == H5FD_STDIO || driver == H5FD_CORE || #ifdef H5_HAVE_WINDOWS - driver == H5FD_WINDOWS || + driver == H5FD_WINDOWS || #endif /* H5_HAVE_WINDOWS */ #ifdef H5_HAVE_DIRECT - driver == H5FD_DIRECT || + driver == H5FD_DIRECT || #endif /* H5_HAVE_DIRECT */ - driver == H5FD_LOG) { + driver == H5FD_LOG || driver == H5FD_SPLITTER) { /* Get the file's statistics */ - if(0 == HDstat(filename, &sb)) - return((h5_stat_size_t)sb.st_size); + if (0 == HDstat(filename, &sb)) + return ((h5_stat_size_t)sb.st_size); } /* end if */ - else if(driver == H5FD_MULTI) { - H5FD_mem_t mt; - h5_stat_size_t tot_size = 0; - - HDassert(HDstrlen(multi_letters) == H5FD_MEM_NTYPES); - for(mt = H5FD_MEM_DEFAULT; mt < H5FD_MEM_NTYPES; H5_INC_ENUM(H5FD_mem_t, mt)) { - /* Create the filename to query */ - HDsnprintf(temp, sizeof temp, "%s-%c.h5", filename, multi_letters[mt]); - - /* Check for existence of file */ - if(0 == HDaccess(temp, F_OK)) { - /* Get the file's statistics */ - if(0 != HDstat(temp, &sb)) - return(-1); - - /* Add to total size */ - tot_size += (h5_stat_size_t)sb.st_size; - } /* end if */ - } /* end for */ + else if (driver == H5FD_MULTI) { + H5FD_mem_t mt; + h5_stat_size_t tot_size = 0; + char *driver_env_var = NULL; + + driver_env_var = HDgetenv(HDF5_DRIVER); + if (driver_env_var && !HDstrcmp(driver_env_var, "split")) { + for (mt = H5FD_MEM_DEFAULT; mt < H5FD_MEM_NTYPES; mt++) { + if (mt != H5FD_MEM_DRAW && mt != H5FD_MEM_SUPER) + continue; + + /* Create the filename to query */ + if (mt == H5FD_MEM_DRAW) { + HDsnprintf(temp, sizeof temp, "%s.raw", filename); + } + else { + HDsnprintf(temp, sizeof temp, "%s.meta", filename); + } + + /* Check for existence of file */ + if (0 == HDaccess(temp, F_OK)) { + /* Get the file's statistics */ + if (0 != HDstat(temp, &sb)) + return (-1); + + /* Add to total size */ + tot_size += (h5_stat_size_t)sb.st_size; + } /* end if */ + } /* end for */ + } + else { + HDassert(HDstrlen(multi_letters) == H5FD_MEM_NTYPES); + for (mt = H5FD_MEM_DEFAULT; mt < H5FD_MEM_NTYPES; mt++) { + /* Create the filename to query */ + HDsnprintf(temp, sizeof temp, "%s-%c.h5", filename, multi_letters[mt]); + + /* Check for existence of file */ + if (0 == HDaccess(temp, F_OK)) { + /* Get the file's statistics */ + if (0 != HDstat(temp, &sb)) + return (-1); + + /* Add to total size */ + tot_size += (h5_stat_size_t)sb.st_size; + } /* end if */ + } /* end for */ + } /* Return total size */ - return(tot_size); + return (tot_size); } /* end if */ - else if(driver == H5FD_FAMILY) { +#ifdef H5_HAVE_PARALLEL + else if (driver == H5FD_MPIO) { + MPI_File fh; /* MPI file handle used to open the file and verify its size */ + int mpi_ret; + MPI_Offset file_size; + + mpi_ret = MPI_File_open(MPI_COMM_WORLD, filename, MPI_MODE_RDONLY, MPI_INFO_NULL, &fh); + if (mpi_ret != MPI_SUCCESS) + return -1; + mpi_ret = MPI_File_get_size(fh, &file_size); + if (mpi_ret != MPI_SUCCESS) + return -1; + mpi_ret = MPI_File_close(&fh); + if (mpi_ret != MPI_SUCCESS) + return -1; + + return file_size; + } +#endif /* H5_HAVE_PARALLEL */ + else if (driver == H5FD_FAMILY) { h5_stat_size_t tot_size = 0; /* Try all filenames possible, until we find one that's missing */ - for(j = 0; /*void*/; j++) { + for (j = 0; /*void*/; j++) { /* Create the filename to query */ HDsnprintf(temp, sizeof temp, filename, j); /* Check for existence of file */ - if(HDaccess(temp, F_OK) < 0) + if (HDaccess(temp, F_OK) < 0) break; /* Get the file's statistics */ - if(0 != HDstat(temp, &sb)) - return(-1); + if (0 != HDstat(temp, &sb)) + return (-1); /* Add to total size */ tot_size += (h5_stat_size_t)sb.st_size; } /* end for */ /* Return total size */ - return(tot_size); + return (tot_size); } /* end if */ + else if (driver == H5FD_SUBFILING) { + hsize_t size; + hid_t fid = H5I_INVALID_HID; + + if ((fid = H5Fopen(filename, H5F_ACC_RDONLY, fapl)) < 0) + return -1; + if (H5Fget_filesize(fid, &size) < 0) { + H5Fclose(fid); + return -1; + } + + if (H5Fclose(fid) < 0) + return -1; + + return (h5_stat_size_t)size; + } else { - HDassert(0 && "Unknown VFD!"); + /* Get the file's statistics */ + if (0 == HDstat(filename, &sb)) + return ((h5_stat_size_t)sb.st_size); } /* end else */ - } /* end else */ + } /* end else */ - return(-1); + return (-1); } /* end get_file_size() */ +H5_GCC_CLANG_DIAG_ON("format-nonliteral") /* * This routine is designed to provide equivalent functionality to 'printf' * and allow easy replacement for environments which don't have stdin/stdout * available. (i.e. Windows & the Mac) */ +H5_ATTR_FORMAT(printf, 1, 2) int print_func(const char *format, ...) { - va_list arglist; - int ret_value; + va_list arglist; + int ret_value; - va_start(arglist, format); - ret_value = vprintf(format, arglist); - va_end(arglist); - return ret_value; + HDva_start(arglist, format); + ret_value = HDvprintf(format, arglist); + HDva_end(arglist); + return ret_value; } #ifdef H5_HAVE_FILTER_SZIP - /*------------------------------------------------------------------------- * Function: h5_szip_can_encode * @@ -976,31 +1343,31 @@ print_func(const char *format, ...) * *------------------------------------------------------------------------- */ -int h5_szip_can_encode(void ) +int +h5_szip_can_encode(void) { unsigned int filter_config_flags; H5Zget_filter_info(H5Z_FILTER_SZIP, &filter_config_flags); - if ((filter_config_flags & - (H5Z_FILTER_CONFIG_ENCODE_ENABLED|H5Z_FILTER_CONFIG_DECODE_ENABLED)) == 0) { + if ((filter_config_flags & (H5Z_FILTER_CONFIG_ENCODE_ENABLED | H5Z_FILTER_CONFIG_DECODE_ENABLED)) == 0) { /* filter present but neither encode nor decode is supported (???) */ return -1; - } else if ((filter_config_flags & - (H5Z_FILTER_CONFIG_ENCODE_ENABLED|H5Z_FILTER_CONFIG_DECODE_ENABLED)) == - H5Z_FILTER_CONFIG_DECODE_ENABLED) { + } + else if ((filter_config_flags & (H5Z_FILTER_CONFIG_ENCODE_ENABLED | H5Z_FILTER_CONFIG_DECODE_ENABLED)) == + H5Z_FILTER_CONFIG_DECODE_ENABLED) { /* decoder only: read but not write */ return 0; - } else if ((filter_config_flags & - (H5Z_FILTER_CONFIG_ENCODE_ENABLED|H5Z_FILTER_CONFIG_DECODE_ENABLED)) == - H5Z_FILTER_CONFIG_ENCODE_ENABLED) { + } + else if ((filter_config_flags & (H5Z_FILTER_CONFIG_ENCODE_ENABLED | H5Z_FILTER_CONFIG_DECODE_ENABLED)) == + H5Z_FILTER_CONFIG_ENCODE_ENABLED) { /* encoder only: write but not read (???) */ return -1; - } else if ((filter_config_flags & - (H5Z_FILTER_CONFIG_ENCODE_ENABLED|H5Z_FILTER_CONFIG_DECODE_ENABLED)) == - (H5Z_FILTER_CONFIG_ENCODE_ENABLED|H5Z_FILTER_CONFIG_DECODE_ENABLED)) { + } + else if ((filter_config_flags & (H5Z_FILTER_CONFIG_ENCODE_ENABLED | H5Z_FILTER_CONFIG_DECODE_ENABLED)) == + (H5Z_FILTER_CONFIG_ENCODE_ENABLED | H5Z_FILTER_CONFIG_DECODE_ENABLED)) { return 1; } - return(-1); + return (-1); } #endif /* H5_HAVE_FILTER_SZIP */ @@ -1019,7 +1386,7 @@ int h5_szip_can_encode(void ) * further calls to getenv_all take place. * * Return: pointer to a string containing the value of the environment variable - * NULL if the varialbe doesn't exist in task 'root's environment. + * NULL if the variable doesn't exist in task 'root's environment. * * Programmer: Leon Arber * 4/4/05 @@ -1032,63 +1399,64 @@ int h5_szip_can_encode(void ) *------------------------------------------------------------------------- */ char * -getenv_all(MPI_Comm comm, int root, const char* name) +getenv_all(MPI_Comm comm, int root, const char *name) { - int mpi_size, mpi_rank, mpi_initialized; - int len; - static char* env = NULL; + int mpi_size, mpi_rank, mpi_initialized, mpi_finalized; + int len; + static char *env = NULL; - assert(name); + HDassert(name); MPI_Initialized(&mpi_initialized); - if(!mpi_initialized) { - /* use original getenv */ - if(env) - HDfree(env); - env = HDgetenv(name); - } /* end if */ - else { - MPI_Comm_rank(comm, &mpi_rank); - MPI_Comm_size(comm, &mpi_size); - assert(root < mpi_size); - - /* The root task does the getenv call - * and sends the result to the other tasks */ - if(mpi_rank == root) { - env = HDgetenv(name); - if(env) { - len = HDstrlen(env); - MPI_Bcast(&len, 1, MPI_INT, root, comm); - MPI_Bcast(env, len, MPI_CHAR, root, comm); - } - else { - /* len -1 indicates that the variable was not in the environment */ - len = -1; - MPI_Bcast(&len, 1, MPI_INT, root, comm); - } - } - else { - MPI_Bcast(&len, 1, MPI_INT, root, comm); - if(len >= 0) { - if(env == NULL) - env = (char*) HDmalloc(len+1); - else if(strlen(env) < len) - env = (char*) HDrealloc(env, len+1); - - MPI_Bcast(env, len, MPI_CHAR, root, comm); - env[len] = '\0'; - } - else { - if(env) - HDfree(env); - env = NULL; - } - } - } - + MPI_Finalized(&mpi_finalized); + + if (mpi_initialized && !mpi_finalized) { + MPI_Comm_rank(comm, &mpi_rank); + MPI_Comm_size(comm, &mpi_size); + HDassert(root < mpi_size); + + /* The root task does the getenv call + * and sends the result to the other tasks */ + if (mpi_rank == root) { + env = HDgetenv(name); + if (env) { + len = (int)HDstrlen(env); + MPI_Bcast(&len, 1, MPI_INT, root, comm); + MPI_Bcast(env, len, MPI_CHAR, root, comm); + } + else { + /* len -1 indicates that the variable was not in the environment */ + len = -1; + MPI_Bcast(&len, 1, MPI_INT, root, comm); + } + } + else { + MPI_Bcast(&len, 1, MPI_INT, root, comm); + if (len >= 0) { + if (env == NULL) + env = (char *)HDmalloc((size_t)len + 1); + else if (HDstrlen(env) < (size_t)len) + env = (char *)HDrealloc(env, (size_t)len + 1); + + MPI_Bcast(env, len, MPI_CHAR, root, comm); + env[len] = '\0'; + } + else { + if (env) + HDfree(env); + env = NULL; + } + } #ifndef NDEBUG - MPI_Barrier(comm); + MPI_Barrier(comm); #endif + } + else { + /* use original getenv */ + if (env) + HDfree(env); + env = HDgetenv(name); + } /* end if */ return env; } @@ -1111,74 +1479,77 @@ getenv_all(MPI_Comm comm, int root, const char* name) * Programmer: Larry Knox * Monday, October 13, 2009 * - * Modifications: - * *------------------------------------------------------------------------- */ -hid_t +int h5_make_local_copy(const char *origfilename, const char *local_copy_name) { - int fd_old = (-1), fd_new = (-1); /* File descriptors for copying data */ - ssize_t nread; /* Number of bytes read in */ - char buf[READ_BUF_SIZE]; /* Buffer for copying data */ - char filename[FILENAME_BUF_SIZE] = ""; -#ifdef H5_VMS - HDstrcat(filename, origfilename); -#else - char * srcdir = HDgetenv("srcdir"); /* The source directory */ + int fd_old = (-1), fd_new = (-1); /* File descriptors for copying data */ + ssize_t nread; /* Number of bytes read in */ + void *buf = NULL; /* Buffer for copying data */ + const char *filename = H5_get_srcdir_filename(origfilename); /* Get the test file name to copy */ - if(srcdir && ((HDstrlen(srcdir) + - HDstrlen(origfilename) + 6) < FILENAME_BUF_SIZE)) { - HDstrcpy(filename, srcdir); - HDstrcat(filename, "/"); - } - HDstrcat(filename, origfilename); -#endif + if (!filename) + goto error; + + /* Allocate copy buffer */ + if (NULL == (buf = HDcalloc((size_t)1, (size_t)READ_BUF_SIZE))) + goto error; /* Copy old file into temporary file */ - if((fd_old = HDopen(filename, O_RDONLY, 0666)) < 0) return -1; - if((fd_new = HDopen(local_copy_name, O_RDWR|O_CREAT|O_TRUNC, 0666)) - < 0) return -1; + if ((fd_old = HDopen(filename, O_RDONLY)) < 0) + goto error; + if ((fd_new = HDopen(local_copy_name, O_RDWR | O_CREAT | O_TRUNC, H5_POSIX_CREATE_MODE_RW)) < 0) + goto error; /* Copy data */ - while((nread = HDread(fd_old, buf, (size_t)READ_BUF_SIZE)) > 0) - HDwrite(fd_new, buf, (size_t)nread); + while ((nread = HDread(fd_old, buf, (size_t)READ_BUF_SIZE)) > 0) + if (HDwrite(fd_new, buf, (size_t)nread) < 0) + goto error; /* Close files */ - if(HDclose(fd_old) < 0) return -1; - if(HDclose(fd_new) < 0) return -1; + if (HDclose(fd_old) < 0) + goto error; + if (HDclose(fd_new) < 0) + goto error; + + /* Release memory */ + HDfree(buf); return 0; -} - +error: + /* ignore return values since we're already noted the problem */ + if (fd_old > 0) + HDclose(fd_old); + if (fd_new > 0) + HDclose(fd_new); + HDfree(buf); + return -1; +} /* end h5_make_local_copy() */ + /*------------------------------------------------------------------------- * Function: h5_verify_cached_stabs_cb * * Purpose: Callback function for h5_verify_cached_stabs. * - * Return: Success: 0 - * - * Failure: -1 + * Return: SUCCEED/FAIL * * Programmer: Neil Fortner * Tuesday, April 12, 2011 * - * Modifications: - * *------------------------------------------------------------------------- */ static herr_t -h5_verify_cached_stabs_cb(hid_t oid, const char UNUSED *name, - const H5O_info_t *oinfo, void UNUSED *udata) +h5_verify_cached_stabs_cb(hid_t oid, const char H5_ATTR_UNUSED *name, const H5O_info2_t *oinfo, + void H5_ATTR_UNUSED *udata) { - if(oinfo->type == H5O_TYPE_GROUP) - return(H5G__verify_cached_stabs_test(oid)); + if (oinfo->type == H5O_TYPE_GROUP) + return H5G__verify_cached_stabs_test(oid); else - return(0); + return SUCCEED; } /* end h5_verify_cached_stabs_cb() */ - /*------------------------------------------------------------------------- * Function: h5_verify_cached_stabs * @@ -1202,27 +1573,29 @@ h5_verify_cached_stabs_cb(hid_t oid, const char UNUSED *name, herr_t h5_verify_cached_stabs(const char *base_name[], hid_t fapl) { - hid_t file = -1; - char filename[1024]; - int i = 0; + hid_t file = -1; + char filename[1024]; + int i = 0; - while(base_name[i]) { + while (base_name[i]) { if (h5_fixname(base_name[i], fapl, filename, sizeof(filename)) == NULL) continue; - H5E_BEGIN_TRY { + H5E_BEGIN_TRY + { file = H5Fopen(filename, H5F_ACC_RDONLY, fapl); - } H5E_END_TRY - if(file < 0) { + } + H5E_END_TRY + if (file < 0) { i++; continue; } /* end if */ - if(H5Ovisit(file, H5_INDEX_NAME, H5_ITER_NATIVE, - h5_verify_cached_stabs_cb, NULL) < 0) + if (H5Ovisit3(file, H5_INDEX_NAME, H5_ITER_NATIVE, h5_verify_cached_stabs_cb, NULL, H5O_INFO_BASIC) < + 0) goto error; - if(H5Fclose(file) < 0) + if (H5Fclose(file) < 0) goto error; file = -1; @@ -1232,10 +1605,750 @@ h5_verify_cached_stabs(const char *base_name[], hid_t fapl) return 0; error: - H5E_BEGIN_TRY { + H5E_BEGIN_TRY + { H5Fclose(file); - } H5E_END_TRY; + } + H5E_END_TRY; return -1; } +/*------------------------------------------------------------------------- + * Function: h5_send_message + * + * Purpose: Sends the specified signal. + * + * In terms of this test framework, a signal consists of a file + * on disk. Since there are multiple processes that need to + * communicate with each other, they do so by writing and + * reading signal files on disk, the names and contents of + * which are used to inform a process about when it can + * proceed and what it should do next. + * + * This function writes a signal file. The first argument is + * the name of the signal file, and the second and third + * arguments are the contents of the first two lines of the + * signal file. The last two arguments may be NULL. + * + * Return: void + * + * Programmer: Mike McGreevy + * August 18, 2010 + * + *------------------------------------------------------------------------- + */ +void +h5_send_message(const char *send, const char *arg1, const char *arg2) +{ + FILE *signalfile = NULL; + + /* Create signal file (which will send signal to some other process) */ + signalfile = HDfopen(TMP_SIGNAL_FILE, "w+"); + + /* Write messages to signal file, if provided */ + if (arg2 != NULL) { + HDassert(arg1); + HDfprintf(signalfile, "%s\n%s\n", arg1, arg2); + } /* end if */ + else if (arg1 != NULL) { + HDassert(arg2 == NULL); + HDfprintf(signalfile, "%s\n", arg1); + } /* end if */ + else { + HDassert(arg1 == NULL); + HDassert(arg2 == NULL); + } /* end else */ + + HDfclose(signalfile); + + HDrename(TMP_SIGNAL_FILE, send); +} /* h5_send_message() */ + +/*------------------------------------------------------------------------- + * Function: h5_wait_message + * + * Purpose: Waits for the specified signal. + * + * In terms of this test framework, a signal consists of a file + * on disk. Since there are multiple processes that need to + * communicate with each other, they do so by writing and + * reading signal files on disk, the names and contents of + * which are used to inform a process about when it can + * proceed and what it should do next. + * + * This function continuously attempts to read the specified + * signal file from disk, and only continues once it has + * successfully done so (i.e., only after another process has + * called the "h5_send_message" function to write the signal file). + * This function will then immediately remove the file (i.e., + * to indicate that it has been received and can be reused), + * and then exits, allowing the calling function to continue. + * + * Return: void + * + * Programmer: Mike McGreevy + * August 18, 2010 + * + *------------------------------------------------------------------------- + */ +herr_t +h5_wait_message(const char *waitfor) +{ + FILE *returnfile; + time_t t0, t1; + + /* Start timer. If this function runs for too long (i.e., + expected signal is never received), it will + return failure */ + HDtime(&t0); + + /* Wait for return signal from some other process */ + while ((returnfile = HDfopen(waitfor, "r")) == NULL) { + + /* make note of current time. */ + HDtime(&t1); + + /* If we've been waiting for a signal for too long, then + it was likely never sent and we should fail rather + than loop infinitely */ + if (HDdifftime(t1, t0) > MESSAGE_TIMEOUT) { + HDfprintf(stdout, "Error communicating between processes. Make sure test script is running.\n"); + TEST_ERROR; + } /* end if */ + } /* end while */ + + HDfclose(returnfile); + HDunlink(waitfor); + + return SUCCEED; + +error: + return FAIL; +} /* h5_wait_message() */ + +/* Functions for the dummy VFD class (see below). + * + * Useful for testing things like ID handling where we shouldn't mess with the + * real VFDs. + */ +static H5FD_t *dummy_vfd_open(const char *name, unsigned flags, hid_t fapl_id, haddr_t maxaddr); +static H5FD_t * +dummy_vfd_open(const char H5_ATTR_UNUSED *name, unsigned H5_ATTR_UNUSED flags, hid_t H5_ATTR_UNUSED fapl_id, + haddr_t H5_ATTR_UNUSED maxaddr) +{ + return NULL; +} + +static herr_t dummy_vfd_close(H5FD_t *_file); +static herr_t +dummy_vfd_close(H5FD_t H5_ATTR_UNUSED *_file) +{ + return FAIL; +} + +static haddr_t dummy_vfd_get_eoa(const H5FD_t *file, H5FD_mem_t type); +static haddr_t +dummy_vfd_get_eoa(const H5FD_t H5_ATTR_UNUSED *file, H5FD_mem_t H5_ATTR_UNUSED type) +{ + return HADDR_UNDEF; +} + +static herr_t dummy_vfd_set_eoa(H5FD_t *_file, H5FD_mem_t type, haddr_t addr); +static herr_t +dummy_vfd_set_eoa(H5FD_t H5_ATTR_UNUSED *_file, H5FD_mem_t H5_ATTR_UNUSED type, haddr_t H5_ATTR_UNUSED addr) +{ + return FAIL; +} + +static haddr_t dummy_vfd_get_eof(const H5FD_t *file, H5FD_mem_t type); +static haddr_t +dummy_vfd_get_eof(const H5FD_t H5_ATTR_UNUSED *file, H5FD_mem_t H5_ATTR_UNUSED type) +{ + return HADDR_UNDEF; +} + +static herr_t dummy_vfd_read(H5FD_t *_file, H5FD_mem_t type, hid_t fapl_id, haddr_t addr, size_t size, + void *buf); +static herr_t +dummy_vfd_read(H5FD_t H5_ATTR_UNUSED *_file, H5FD_mem_t H5_ATTR_UNUSED type, hid_t H5_ATTR_UNUSED fapl_id, + haddr_t H5_ATTR_UNUSED addr, size_t H5_ATTR_UNUSED size, void H5_ATTR_UNUSED *buf) +{ + return FAIL; +} + +static herr_t dummy_vfd_write(H5FD_t *_file, H5FD_mem_t type, hid_t fapl_id, haddr_t addr, size_t size, + const void *buf); +static herr_t +dummy_vfd_write(H5FD_t H5_ATTR_UNUSED *_file, H5FD_mem_t H5_ATTR_UNUSED type, hid_t H5_ATTR_UNUSED fapl_id, + haddr_t H5_ATTR_UNUSED addr, size_t H5_ATTR_UNUSED size, const void H5_ATTR_UNUSED *buf) +{ + return FAIL; +} + +/* Dummy VFD with the minimum parameters to make a VFD that can be registered */ +#define DUMMY_VFD_VALUE (H5FD_class_value_t)155 +static const H5FD_class_t H5FD_dummy_g = { + H5FD_CLASS_VERSION, /* struct version */ + DUMMY_VFD_VALUE, /* value */ + "dummy", /* name */ + 1, /* maxaddr */ + H5F_CLOSE_WEAK, /* fc_degree */ + NULL, /* terminate */ + NULL, /* sb_size */ + NULL, /* sb_encode */ + NULL, /* sb_decode */ + 0, /* fapl_size */ + NULL, /* fapl_get */ + NULL, /* fapl_copy */ + NULL, /* fapl_free */ + 0, /* dxpl_size */ + NULL, /* dxpl_copy */ + NULL, /* dxpl_free */ + dummy_vfd_open, /* open */ + dummy_vfd_close, /* close */ + NULL, /* cmp */ + NULL, /* query */ + NULL, /* get_type_map */ + NULL, /* alloc */ + NULL, /* free */ + dummy_vfd_get_eoa, /* get_eoa */ + dummy_vfd_set_eoa, /* set_eoa */ + dummy_vfd_get_eof, /* get_eof */ + NULL, /* get_handle */ + dummy_vfd_read, /* read */ + dummy_vfd_write, /* write */ + NULL, /* read_vector */ + NULL, /* write_vector */ + NULL, /* read_selection */ + NULL, /* write_selection */ + NULL, /* flush */ + NULL, /* truncate */ + NULL, /* lock */ + NULL, /* unlock */ + NULL, /* del */ + NULL, /* ctl */ + H5FD_FLMAP_DICHOTOMY /* fl_map */ +}; + +/*------------------------------------------------------------------------- + * Function: h5_get_dummy_vfd_class() + * + * Purpose: Returns a disposable, generally non-functional, + * VFD class struct. + * + * In some of the test code, we need a disposable VFD but + * we don't want to mess with the real VFDs and we also + * don't have access to the internals of the real VFDs (which + * use static globals and functions) to easily duplicate + * them (e.g.: for testing VFD ID handling). + * + * This API call will return a pointer to a VFD class that + * can be used to construct a test VFD using H5FDregister(). + * + * Return: Success: A pointer to a VFD class struct + * Failure: NULL + * + *------------------------------------------------------------------------- + */ +H5FD_class_t * +h5_get_dummy_vfd_class(void) +{ + H5FD_class_t *vfd_class = NULL; /* Dummy VFD that will be returned */ + + /* Create the class and initialize everything to zero/NULL */ + if (NULL == (vfd_class = (H5FD_class_t *)HDmalloc(sizeof(H5FD_class_t)))) + TEST_ERROR; + + /* Copy the dummy VFD */ + HDmemcpy(vfd_class, &H5FD_dummy_g, sizeof(H5FD_class_t)); + + return vfd_class; + +error: + if (vfd_class) + HDfree(vfd_class); + return NULL; +} /* h5_get_dummy_vfd_class */ + +/*------------------------------------------------------------------------- + * Function: h5_get_dummy_vol_class() + * + * Purpose: Returns a disposable, generally non-functional, + * VOL class struct. + * + * In some of the test code, we need a disposable VOL connector + * but we don't want to mess with the real VFDs and we also + * don't have access to the internals of the real VOL connectors + * (which use static globals and functions) to easily duplicate + * them (e.g.: for testing VOL connector ID handling). + * + * This API call will return a pointer to a VOL class that + * can be used to construct a test VOL using H5VLregister_connector(). + * + * Return: Success: A pointer to a VOL class struct + * Failure: NULL + * + *------------------------------------------------------------------------- + */ +H5VL_class_t * +h5_get_dummy_vol_class(void) +{ + H5VL_class_t *vol_class = NULL; /* Dummy VOL class that will be returned */ + + /* Create the class and initialize everything to zero/NULL */ + if (NULL == (vol_class = (H5VL_class_t *)HDcalloc((size_t)1, sizeof(H5VL_class_t)))) + TEST_ERROR; + + /* Fill in the minimum parameters to make a VOL connector class that + * can be registered. + */ + vol_class->version = H5VL_VERSION; + vol_class->name = "dummy"; + + return vol_class; + +error: + if (vol_class) + HDfree(vol_class); + return NULL; +} /* h5_get_dummy_vol_class */ + +/*------------------------------------------------------------------------- + * Function: h5_get_version_string + * + * Purpose: Get the string that corresponds to the libvery version bound. + * + * Return: The string + * + *------------------------------------------------------------------------- + */ +H5_ATTR_PURE const char * +h5_get_version_string(H5F_libver_t libver) +{ + return (LIBVER_NAMES[libver]); +} /* end of h5_get_version_string */ + +/*------------------------------------------------------------------------- + * Function: h5_compare_file_bytes() + * + * Purpose: Helper function to compare two files byte-for-byte. + * + * Return: Success: 0, if files are identical + * Failure: -1, if files differ + * + * Programmer: Binh-Minh Ribler + * October, 2018 + *------------------------------------------------------------------------- + */ +int +h5_compare_file_bytes(char *f1name, char *f2name) +{ + FILE *f1ptr = NULL; /* two file pointers */ + FILE *f2ptr = NULL; + off_t f1size = 0; /* size of the files */ + off_t f2size = 0; + char f1char = 0; /* one char from each file */ + char f2char = 0; + off_t ii = 0; + int ret_value = 0; /* for error handling */ + + /* Open files for reading */ + f1ptr = HDfopen(f1name, "rb"); + if (f1ptr == NULL) { + HDfprintf(stderr, "Unable to fopen() %s\n", f1name); + ret_value = -1; + goto done; + } + f2ptr = HDfopen(f2name, "rb"); + if (f2ptr == NULL) { + HDfprintf(stderr, "Unable to fopen() %s\n", f2name); + ret_value = -1; + goto done; + } + + /* Get the file sizes and verify that they equal */ + HDfseek(f1ptr, 0, SEEK_END); + f1size = HDftell(f1ptr); + + HDfseek(f2ptr, 0, SEEK_END); + f2size = HDftell(f2ptr); + + if (f1size != f2size) { + HDfprintf(stderr, "Files differ in size, %" PRIuHSIZE " vs. %" PRIuHSIZE "\n", (hsize_t)f1size, + (hsize_t)f2size); + ret_value = -1; + goto done; + } + + /* Compare each byte and fail if a difference is found */ + HDrewind(f1ptr); + HDrewind(f2ptr); + for (ii = 0; ii < f1size; ii++) { + if (HDfread(&f1char, 1, 1, f1ptr) != 1) { + ret_value = -1; + goto done; + } + if (HDfread(&f2char, 1, 1, f2ptr) != 1) { + ret_value = -1; + goto done; + } + if (f1char != f2char) { + HDfprintf(stderr, "Mismatch @ 0x%" PRIXHSIZE ": 0x%X != 0x%X\n", (hsize_t)ii, f1char, f2char); + ret_value = -1; + goto done; + } + } + +done: + if (f1ptr) + HDfclose(f1ptr); + if (f2ptr) + HDfclose(f2ptr); + return ret_value; +} /* end h5_compare_file_bytes() */ + +/*------------------------------------------------------------------------- + * Function: H5_get_srcdir_filename + * + * Purpose: Append the test file name to the srcdir path and return the whole string + * + * Return: The string or NULL (errors or not enough space) + * + *------------------------------------------------------------------------- + */ +const char * +H5_get_srcdir_filename(const char *filename) +{ + const char *srcdir = H5_get_srcdir(); + + /* Check for error */ + if (NULL == srcdir) + return NULL; + + /* Build path to test file. We're checking the length so suppress + * the gcc format-truncation warning. + */ + if ((HDstrlen(srcdir) + HDstrlen(filename) + 1) < sizeof(srcdir_testpath)) { + H5_GCC_DIAG_OFF("format-truncation") + HDsnprintf(srcdir_testpath, sizeof(srcdir_testpath), "%s%s", srcdir, filename); + H5_GCC_DIAG_ON("format-truncation") + return srcdir_testpath; + } + + /* If not enough space, just return NULL */ + return NULL; +} /* end H5_get_srcdir_filename() */ + +/*------------------------------------------------------------------------- + * Function: H5_get_srcdir + * + * Purpose: Just return the srcdir path + * + * Return: The string + * + *------------------------------------------------------------------------- + */ +const char * +H5_get_srcdir(void) +{ + const char *srcdir = HDgetenv("srcdir"); + + /* Check for using the srcdir from configure time */ + if (NULL == srcdir) + srcdir = config_srcdir; + + /* Build path to all test files */ + if ((HDstrlen(srcdir) + 2) < sizeof(srcdir_path)) { + HDsnprintf(srcdir_path, sizeof(srcdir_path), "%s/", srcdir); + return (srcdir_path); + } /* end if */ + else + return (NULL); +} /* end H5_get_srcdir() */ + +/*------------------------------------------------------------------------- + * Function: h5_duplicate_file_by_bytes + * + * Purpose: Duplicate a file byte-for-byte at filename/path 'orig' + * to a new (or replaced) file at 'dest'. + * + * Return: Success: 0, completed successfully + * Failure: -1 + * + * Programmer: Jake Smith + * 24 June 2020 + * + *------------------------------------------------------------------------- + */ +int +h5_duplicate_file_by_bytes(const char *orig, const char *dest) +{ + FILE *orig_ptr = NULL; + FILE *dest_ptr = NULL; + hsize_t fsize = 0; + hsize_t read_size = 0; + hsize_t max_buf = 0; + void *dup_buf = NULL; + int ret_value = 0; + + max_buf = 4096 * sizeof(char); + + orig_ptr = HDfopen(orig, "rb"); + if (NULL == orig_ptr) { + ret_value = -1; + goto done; + } + + HDfseek(orig_ptr, 0, SEEK_END); + fsize = (hsize_t)HDftell(orig_ptr); + HDrewind(orig_ptr); + + dest_ptr = HDfopen(dest, "wb"); + if (NULL == dest_ptr) { + ret_value = -1; + goto done; + } + + read_size = MIN(fsize, max_buf); + dup_buf = HDmalloc(read_size); + if (NULL == dup_buf) { + ret_value = -1; + goto done; + } + + while (read_size > 0) { + if (HDfread(dup_buf, read_size, 1, orig_ptr) != 1) { + ret_value = -1; + goto done; + } + HDfwrite(dup_buf, read_size, 1, dest_ptr); + fsize -= read_size; + read_size = MIN(fsize, max_buf); + } + +done: + if (orig_ptr != NULL) + HDfclose(orig_ptr); + if (dest_ptr != NULL) + HDfclose(dest_ptr); + if (dup_buf != NULL) + HDfree(dup_buf); + return ret_value; +} /* end h5_duplicate_file_by_bytes() */ + +/*------------------------------------------------------------------------- + * Function: h5_check_if_file_locking_enabled + * + * Purpose: Checks if file locking is enabled on this file system. + * + * Return: SUCCEED/FAIL + * are_enabled will be FALSE if file locking is disabled on + * the file system of if there were errors. + * + *------------------------------------------------------------------------- + */ +herr_t +h5_check_if_file_locking_enabled(hbool_t *is_enabled) +{ + const char *filename = "locking_test_file"; + int pmode = O_RDWR | O_CREAT | O_TRUNC; + int fd = -1; + + *is_enabled = TRUE; + + if ((fd = HDopen(filename, pmode, H5_POSIX_CREATE_MODE_RW)) < 0) + goto error; + + /* Test HDflock() to see if it works */ + if (HDflock(fd, LOCK_EX | LOCK_NB) < 0) { + if (ENOSYS == errno) { + /* When errno is set to ENOSYS, the file system does not support + * locking, so ignore it. This is most frequently used on + * Lustre. If we also want to check for disabled NFS locks + * we'll need to check for ENOLCK, too. That isn't done by + * default here since that could also represent an actual + * error condition. + */ + errno = 0; + *is_enabled = FALSE; + } + else + goto error; + } + if (HDflock(fd, LOCK_UN) < 0) + goto error; + + if (HDclose(fd) < 0) + goto error; + if (HDremove(filename) < 0) + goto error; + + return SUCCEED; + +error: + *is_enabled = FALSE; + if (fd > -1) { + HDclose(fd); + HDremove(filename); + } + return FAIL; +} /* end h5_check_if_file_locking_enabled() */ + +/*------------------------------------------------------------------------- + * Function: h5_using_default_driver + * + * Purpose: Checks if the specified VFD name matches the library's + * default VFD. If `drv_name` is NULL, the HDF5_DRIVER + * environment is checked instead (if it is set). + * + * Return: TRUE/FALSE + * + *------------------------------------------------------------------------- + */ +hbool_t +h5_using_default_driver(const char *drv_name) +{ + hbool_t ret_val = TRUE; + + HDassert(H5_DEFAULT_VFD == H5FD_SEC2); + + if (!drv_name) + drv_name = HDgetenv(HDF5_DRIVER); + + if (drv_name) + return (!HDstrcmp(drv_name, "sec2") || !HDstrcmp(drv_name, "nomatch")); + + return ret_val; +} + +/*------------------------------------------------------------------------- + * Function: h5_using_parallel_driver + * + * Purpose: Checks if the current VFD set on the given FAPL is a + * parallel-enabled VFD (The MPI I/O VFD, for example). + * + * This is mostly useful for avoiding tests that use features + * which are not currently supported for parallel HDF5, such + * as writing of VL or region reference datatypes. + * + * Return: TRUE/FALSE + * + *------------------------------------------------------------------------- + */ +herr_t +h5_using_parallel_driver(hid_t fapl_id, hbool_t *driver_is_parallel) +{ + unsigned long feat_flags = 0; + hid_t driver_id = H5I_INVALID_HID; + herr_t ret_value = SUCCEED; + + HDassert(fapl_id >= 0); + HDassert(driver_is_parallel); + + if (fapl_id == H5P_DEFAULT) + fapl_id = H5P_FILE_ACCESS_DEFAULT; + + if ((driver_id = H5Pget_driver(fapl_id)) < 0) + return FAIL; + + if (H5FDdriver_query(driver_id, &feat_flags) < 0) + return FAIL; + + *driver_is_parallel = (feat_flags & H5FD_FEAT_HAS_MPI); + + return ret_value; +} + +/*------------------------------------------------------------------------- + * Function: h5_driver_is_default_vfd_compatible + * + * Purpose: Checks if the current VFD set on the given FAPL creates a + * file that is compatible with the default VFD. Some examples + * are the core and MPI I/O drivers. Some counterexamples are + * the multi and family drivers, which split the HDF5 file + * into several different files. + * + * This routine is helpful for skipping tests that use + * pre-generated files. VFDs that create files which aren't + * compatible with the default VFD will generally not be able + * to open these pre-generated files and those particular + * tests will fail. + * + * Return: Non-negative on success/Negative on failure + * + *------------------------------------------------------------------------- + */ +herr_t +h5_driver_is_default_vfd_compatible(hid_t fapl_id, hbool_t *default_vfd_compatible) +{ + unsigned long feat_flags = 0; + hid_t driver_id = H5I_INVALID_HID; + herr_t ret_value = SUCCEED; + + HDassert(fapl_id >= 0); + HDassert(default_vfd_compatible); + + if (fapl_id == H5P_DEFAULT) + fapl_id = H5P_FILE_ACCESS_DEFAULT; + + if ((driver_id = H5Pget_driver(fapl_id)) < 0) + return FAIL; + + if (H5FDdriver_query(driver_id, &feat_flags) < 0) + return FAIL; + + *default_vfd_compatible = (feat_flags & H5FD_FEAT_DEFAULT_VFD_COMPATIBLE); + + return ret_value; +} /* end h5_driver_is_default_vfd_compatible() */ + +/*------------------------------------------------------------------------- + * Function: h5_driver_uses_multiple_files + * + * Purpose: Checks if the specified VFD name matches a driver that + * stores data using multiple files. + * + * The following flags can be used to control what types of + * drivers are checked for by this routine: + * + * H5_EXCLUDE_MULTIPART_DRIVERS - This flag excludes any + * drivers which store data using multiple files which, + * together, make up a single logical file. These are + * drivers like the split, multi and family drivers. + * + * H5_EXCLUDE_NON_MULTIPART_DRIVERS - This flag excludes any + * drivers which store data using multiple files which are + * separate logical files. The splitter driver is an example + * of this type of driver. + * + * Eventually, this should become a VFD feature flag so this + * check is less fragile. + * + * Return: TRUE/FALSE + * + *------------------------------------------------------------------------- + */ +hbool_t +h5_driver_uses_multiple_files(const char *drv_name, unsigned flags) +{ + hbool_t ret_val = FALSE; + + if (!drv_name) + drv_name = HDgetenv(HDF5_DRIVER); + + if (drv_name) { + if ((flags & H5_EXCLUDE_MULTIPART_DRIVERS) == 0) { + if (!HDstrcmp(drv_name, "split") || !HDstrcmp(drv_name, "multi") || + !HDstrcmp(drv_name, "family") || !HDstrcmp(drv_name, H5FD_SUBFILING_NAME)) + return TRUE; + } + + if ((flags & H5_EXCLUDE_NON_MULTIPART_DRIVERS) == 0) { + if (!HDstrcmp(drv_name, "splitter")) + return TRUE; + } + } + + return ret_val; +} |
