diff options
author | Dana Robinson <derobins@hdfgroup.org> | 2016-02-22 21:40:03 (GMT) |
---|---|---|
committer | Dana Robinson <derobins@hdfgroup.org> | 2016-02-22 21:40:03 (GMT) |
commit | 19a8216bd52b6a495c4bc989b7d01e9a7ecd46bf (patch) | |
tree | bf07b7366747d1519b628ea1c399bb5e8b654753 /src | |
parent | 7511d8b4691770a15f1ba9f7fcc242f038c79669 (diff) | |
download | hdf5-19a8216bd52b6a495c4bc989b7d01e9a7ecd46bf.zip hdf5-19a8216bd52b6a495c4bc989b7d01e9a7ecd46bf.tar.gz hdf5-19a8216bd52b6a495c4bc989b7d01e9a7ecd46bf.tar.bz2 |
[svn-r29182] Re-commit of HDFFV-8740 fix, which adds the ability to configure
external dataset storage path behavior.
This check-in fixes a bug in the original check-in where the
external path stored in the file struct was not copied on reopen
causing subsequent dataset operations to fail.
Tested on: 64-bit Ubuntu 15.10 (Linux 4.2.0 x86_64) gcc 5.2.1
autotools serial w/ fortran and C++
autotools parallel (MPICH 3.1.4) w/ fortran
Diffstat (limited to 'src')
-rw-r--r-- | src/H5.c | 3 | ||||
-rw-r--r-- | src/H5Defl.c | 172 | ||||
-rw-r--r-- | src/H5Dint.c | 113 | ||||
-rw-r--r-- | src/H5Dpkg.h | 2 | ||||
-rw-r--r-- | src/H5Dprivate.h | 1 | ||||
-rw-r--r-- | src/H5F.c | 15 | ||||
-rw-r--r-- | src/H5Fquery.c | 2 | ||||
-rw-r--r-- | src/H5MM.c | 44 | ||||
-rw-r--r-- | src/H5Pdapl.c | 384 | ||||
-rw-r--r-- | src/H5Plapl.c | 3 | ||||
-rw-r--r-- | src/H5Ppublic.h | 2 | ||||
-rw-r--r-- | src/H5private.h | 6 | ||||
-rw-r--r-- | src/H5system.c | 129 | ||||
-rw-r--r-- | src/H5win32defs.h | 23 |
14 files changed, 763 insertions, 136 deletions
@@ -193,7 +193,8 @@ H5_init_library(void) /* Normal library termination code */ (void)HDatexit(H5_term_library); - H5_dont_atexit_g = TRUE; + + H5_dont_atexit_g = TRUE; } /* end if */ /* diff --git a/src/H5Defl.c b/src/H5Defl.c index ec96ae7..cf1b36c 100644 --- a/src/H5Defl.c +++ b/src/H5Defl.c @@ -28,12 +28,13 @@ /***********/ /* Headers */ /***********/ -#include "H5private.h" /* Generic Functions */ -#include "H5Dpkg.h" /* Datasets */ -#include "H5Eprivate.h" /* Error handling */ -#include "H5Fprivate.h" /* Files */ -#include "H5HLprivate.h" /* Local Heaps */ -#include "H5VMprivate.h" /* Vector and array functions */ +#include "H5private.h" /* Generic Functions */ +#include "H5Dpkg.h" /* Datasets */ +#include "H5Eprivate.h" /* Error handling */ +#include "H5Fprivate.h" /* Files */ +#include "H5HLprivate.h" /* Local Heaps */ +#include "H5MMprivate.h" /* Memory management */ +#include "H5VMprivate.h" /* Vector and array functions */ /****************/ @@ -48,12 +49,14 @@ /* Callback info for readvv operation */ typedef struct H5D_efl_readvv_ud_t { const H5O_efl_t *efl; /* Pointer to efl info */ + const H5D_t *dset; /* The dataset */ unsigned char *rbuf; /* Read buffer */ } H5D_efl_readvv_ud_t; /* Callback info for writevv operation */ typedef struct H5D_efl_writevv_ud_t { const H5O_efl_t *efl; /* Pointer to efl info */ + const H5D_t *dset; /* The dataset */ const unsigned char *wbuf; /* Write buffer */ } H5D_efl_writevv_ud_t; @@ -75,9 +78,9 @@ static ssize_t H5D__efl_writevv(const H5D_io_info_t *io_info, size_t mem_max_nseq, size_t *mem_curr_seq, size_t mem_len_arr[], hsize_t mem_offset_arr[]); /* Helper routines */ -static herr_t H5D__efl_read(const H5O_efl_t *efl, haddr_t addr, size_t size, +static herr_t H5D__efl_read(const H5O_efl_t *efl, const H5D_t *dset, haddr_t addr, size_t size, uint8_t *buf); -static herr_t H5D__efl_write(const H5O_efl_t *efl, haddr_t addr, size_t size, +static herr_t H5D__efl_write(const H5O_efl_t *efl, const H5D_t *dset, haddr_t addr, size_t size, const uint8_t *buf); @@ -232,25 +235,22 @@ H5D__efl_io_init(const H5D_io_info_t *io_info, const H5D_type_info_t H5_ATTR_UNU /*------------------------------------------------------------------------- - * Function: H5D__efl_read + * Function: H5D__efl_read * - * Purpose: Reads data from an external file list. It is an error to - * read past the logical end of file, but reading past the end - * of any particular member of the external file list results in - * zeros. + * Purpose: Reads data from an external file list. It is an error to + * read past the logical end of file, but reading past the end + * of any particular member of the external file list results in + * zeros. * - * Return: Non-negative on success/Negative on failure + * Return: SUCCEED/FAIL * - * Programmer: Robb Matzke + * Programmer: Robb Matzke * Wednesday, March 4, 1998 * - * Modifications: - * Robb Matzke, 1999-07-28 - * The ADDR argument is passed by value. *------------------------------------------------------------------------- */ static herr_t -H5D__efl_read(const H5O_efl_t *efl, haddr_t addr, size_t size, uint8_t *buf) +H5D__efl_read(const H5O_efl_t *efl, const H5D_t *dset, haddr_t addr, size_t size, uint8_t *buf) { int fd = -1; size_t to_read; @@ -261,6 +261,7 @@ H5D__efl_read(const H5O_efl_t *efl, haddr_t addr, size_t size, uint8_t *buf) haddr_t cur; ssize_t n; size_t u; /* Local index variable */ + char *full_name = NULL; /* File name with prefix */ herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_STATIC @@ -273,44 +274,49 @@ H5D__efl_read(const H5O_efl_t *efl, haddr_t addr, size_t size, uint8_t *buf) /* Find the first efl member from which to read */ for (u=0, cur=0; u<efl->nused; u++) { - if(H5O_EFL_UNLIMITED == efl->slot[u].size || addr < cur + efl->slot[u].size) { - skip = addr - cur; - break; - } /* end if */ - cur += efl->slot[u].size; + if(H5O_EFL_UNLIMITED == efl->slot[u].size || addr < cur + efl->slot[u].size) { + skip = addr - cur; + break; + } /* end if */ + cur += efl->slot[u].size; } /* end for */ /* Read the data */ while(size) { HDassert(buf); - if(u >= efl->nused) - HGOTO_ERROR(H5E_EFL, H5E_OVERFLOW, FAIL, "read past logical end of file") - if(H5F_OVERFLOW_HSIZET2OFFT(efl->slot[u].offset + skip)) - HGOTO_ERROR(H5E_EFL, H5E_OVERFLOW, FAIL, "external file address overflowed") - if((fd = HDopen(efl->slot[u].name, O_RDONLY, 0)) < 0) - HGOTO_ERROR(H5E_EFL, H5E_CANTOPENFILE, FAIL, "unable to open external raw data file") - if(HDlseek(fd, (HDoff_t)(efl->slot[u].offset + skip), SEEK_SET) < 0) - HGOTO_ERROR(H5E_EFL, H5E_SEEKERROR, FAIL, "unable to seek in external raw data file") + if(u >= efl->nused) + HGOTO_ERROR(H5E_EFL, H5E_OVERFLOW, FAIL, "read past logical end of file") + if(H5F_OVERFLOW_HSIZET2OFFT(efl->slot[u].offset + skip)) + HGOTO_ERROR(H5E_EFL, H5E_OVERFLOW, FAIL, "external file address overflowed") + if(H5_combine_path(dset->shared->extfile_prefix, efl->slot[u].name, &full_name) < 0) + HGOTO_ERROR(H5E_EFL, H5E_NOSPACE, FAIL, "can't build external file name") + if((fd = HDopen(full_name, O_RDONLY, 0)) < 0) + HGOTO_ERROR(H5E_EFL, H5E_CANTOPENFILE, FAIL, "unable to open external raw data file") + if(HDlseek(fd, (HDoff_t)(efl->slot[u].offset + skip), SEEK_SET) < 0) + HGOTO_ERROR(H5E_EFL, H5E_SEEKERROR, FAIL, "unable to seek in external raw data file") #ifndef NDEBUG - tempto_read = MIN(efl->slot[u].size-skip, (hsize_t)size); + tempto_read = MIN((size_t)(efl->slot[u].size-skip), (hsize_t)size); H5_CHECK_OVERFLOW(tempto_read, hsize_t, size_t); - to_read = (size_t)tempto_read; + to_read = (size_t)tempto_read; #else /* NDEBUG */ - to_read = MIN((size_t)(efl->slot[u].size - skip), size); + to_read = MIN((size_t)(efl->slot[u].size - skip), (hsize_t)size); #endif /* NDEBUG */ - if((n = HDread(fd, buf, to_read)) < 0) - HGOTO_ERROR(H5E_EFL, H5E_READERROR, FAIL, "read error in external raw data file") - else if((size_t)n < to_read) - HDmemset(buf + n, 0, to_read - (size_t)n); - HDclose(fd); - fd = -1; - size -= to_read; - buf += to_read; - skip = 0; - u++; + if((n = HDread(fd, buf, to_read)) < 0) + HGOTO_ERROR(H5E_EFL, H5E_READERROR, FAIL, "read error in external raw data file") + else if((size_t)n < to_read) + HDmemset(buf + n, 0, to_read - (size_t)n); + full_name = (char *)H5MM_xfree(full_name); + HDclose(fd); + fd = -1; + size -= to_read; + buf += to_read; + skip = 0; + u++; } /* end while */ done: + if(full_name) + full_name = (char *)H5MM_xfree(full_name); if(fd >= 0) HDclose(fd); @@ -337,7 +343,7 @@ done: *------------------------------------------------------------------------- */ static herr_t -H5D__efl_write(const H5O_efl_t *efl, haddr_t addr, size_t size, const uint8_t *buf) +H5D__efl_write(const H5O_efl_t *efl, const H5D_t *dset, haddr_t addr, size_t size, const uint8_t *buf) { int fd = -1; size_t to_write; @@ -346,7 +352,8 @@ H5D__efl_write(const H5O_efl_t *efl, haddr_t addr, size_t size, const uint8_t *b #endif /* NDEBUG */ haddr_t cur; hsize_t skip = 0; - size_t u; /* Local index variable */ + size_t u; /* Local index variable */ + char *full_name = NULL; /* File name with prefix */ herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_STATIC @@ -359,46 +366,51 @@ H5D__efl_write(const H5O_efl_t *efl, haddr_t addr, size_t size, const uint8_t *b /* Find the first efl member in which to write */ for(u = 0, cur = 0; u < efl->nused; u++) { - if(H5O_EFL_UNLIMITED == efl->slot[u].size || addr < cur + efl->slot[u].size) { - skip = addr - cur; - break; - } /* end if */ - cur += efl->slot[u].size; + if(H5O_EFL_UNLIMITED == efl->slot[u].size || addr < cur + efl->slot[u].size) { + skip = addr - cur; + break; + } /* end if */ + cur += efl->slot[u].size; } /* end for */ /* Write the data */ while(size) { HDassert(buf); - if(u >= efl->nused) - HGOTO_ERROR(H5E_EFL, H5E_OVERFLOW, FAIL, "write past logical end of file") - if(H5F_OVERFLOW_HSIZET2OFFT(efl->slot[u].offset + skip)) - HGOTO_ERROR(H5E_EFL, H5E_OVERFLOW, FAIL, "external file address overflowed") - if((fd = HDopen(efl->slot[u].name, O_CREAT | O_RDWR, 0666)) < 0) { - if(HDaccess(efl->slot[u].name, F_OK) < 0) - HGOTO_ERROR(H5E_EFL, H5E_CANTOPENFILE, FAIL, "external raw data file does not exist") - else - HGOTO_ERROR(H5E_EFL, H5E_CANTOPENFILE, FAIL, "unable to open external raw data file") - } /* end if */ - if(HDlseek(fd, (HDoff_t)(efl->slot[u].offset + skip), SEEK_SET) < 0) - HGOTO_ERROR(H5E_EFL, H5E_SEEKERROR, FAIL, "unable to seek in external raw data file") + if(u >= efl->nused) + HGOTO_ERROR(H5E_EFL, H5E_OVERFLOW, FAIL, "write past logical end of file") + if(H5F_OVERFLOW_HSIZET2OFFT(efl->slot[u].offset + skip)) + HGOTO_ERROR(H5E_EFL, H5E_OVERFLOW, FAIL, "external file address overflowed") + if(H5_combine_path(dset->shared->extfile_prefix, efl->slot[u].name, &full_name) < 0) + HGOTO_ERROR(H5E_EFL, H5E_NOSPACE, FAIL, "can't build external file name") + if((fd = HDopen(full_name, O_CREAT | O_RDWR, 0666)) < 0) { + if(HDaccess(full_name, F_OK) < 0) + HGOTO_ERROR(H5E_EFL, H5E_CANTOPENFILE, FAIL, "external raw data file does not exist") + else + HGOTO_ERROR(H5E_EFL, H5E_CANTOPENFILE, FAIL, "unable to open external raw data file") + } /* end if */ + if(HDlseek(fd, (HDoff_t)(efl->slot[u].offset + skip), SEEK_SET) < 0) + HGOTO_ERROR(H5E_EFL, H5E_SEEKERROR, FAIL, "unable to seek in external raw data file") #ifndef NDEBUG - tempto_write = MIN(efl->slot[u].size - skip, (hsize_t)size); + tempto_write = MIN(efl->slot[u].size - skip, (hsize_t)size); H5_CHECK_OVERFLOW(tempto_write, hsize_t, size_t); to_write = (size_t)tempto_write; #else /* NDEBUG */ - to_write = MIN((size_t)(efl->slot[u].size - skip), size); + to_write = MIN((size_t)(efl->slot[u].size - skip), size); #endif /* NDEBUG */ - if((size_t)HDwrite(fd, buf, to_write) != to_write) - HGOTO_ERROR(H5E_EFL, H5E_READERROR, FAIL, "write error in external raw data file") - HDclose (fd); - fd = -1; - size -= to_write; - buf += to_write; - skip = 0; - u++; + if((size_t)HDwrite(fd, buf, to_write) != to_write) + HGOTO_ERROR(H5E_EFL, H5E_READERROR, FAIL, "write error in external raw data file") + full_name = (char *)H5MM_xfree(full_name); + HDclose (fd); + fd = -1; + size -= to_write; + buf += to_write; + skip = 0; + u++; } /* end while */ done: + if(full_name) + full_name = (char *)H5MM_xfree(full_name); if(fd >= 0) HDclose(fd); @@ -427,7 +439,7 @@ H5D__efl_readvv_cb(hsize_t dst_off, hsize_t src_off, size_t len, void *_udata) FUNC_ENTER_STATIC /* Read data */ - if(H5D__efl_read(udata->efl, dst_off, len, (udata->rbuf + src_off)) < 0) + if(H5D__efl_read(udata->efl, udata->dset, dst_off, len, (udata->rbuf + src_off)) < 0) HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "EFL read failed") done: @@ -464,6 +476,9 @@ H5D__efl_readvv(const H5D_io_info_t *io_info, HDassert(io_info); HDassert(io_info->store->efl.nused > 0); HDassert(io_info->u.rbuf); + HDassert(io_info->dset); + HDassert(io_info->dset->shared); + HDassert(io_info->dset->shared->extfile_prefix); HDassert(dset_curr_seq); HDassert(dset_len_arr); HDassert(dset_off_arr); @@ -473,6 +488,7 @@ H5D__efl_readvv(const H5D_io_info_t *io_info, /* Set up user data for H5VM_opvv() */ udata.efl = &(io_info->store->efl); + udata.dset = io_info->dset; udata.rbuf = (unsigned char *)io_info->u.rbuf; /* Call generic sequence operation routine */ @@ -507,7 +523,7 @@ H5D__efl_writevv_cb(hsize_t dst_off, hsize_t src_off, size_t len, void *_udata) FUNC_ENTER_STATIC /* Write data */ - if(H5D__efl_write(udata->efl, dst_off, len, (udata->wbuf + src_off)) < 0) + if(H5D__efl_write(udata->efl, udata->dset, dst_off, len, (udata->wbuf + src_off)) < 0) HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "EFL write failed") done: @@ -544,6 +560,9 @@ H5D__efl_writevv(const H5D_io_info_t *io_info, HDassert(io_info); HDassert(io_info->store->efl.nused > 0); HDassert(io_info->u.wbuf); + HDassert(io_info->dset); + HDassert(io_info->dset->shared); + HDassert(io_info->dset->shared->extfile_prefix); HDassert(dset_curr_seq); HDassert(dset_len_arr); HDassert(dset_off_arr); @@ -553,6 +572,7 @@ H5D__efl_writevv(const H5D_io_info_t *io_info, /* Set up user data for H5VM_opvv() */ udata.efl = &(io_info->store->efl); + udata.dset = io_info->dset; udata.wbuf = (const unsigned char *)io_info->u.wbuf; /* Call generic sequence operation routine */ diff --git a/src/H5Dint.c b/src/H5Dint.c index 3e2d212..fe34718 100644 --- a/src/H5Dint.c +++ b/src/H5Dint.c @@ -63,6 +63,8 @@ static herr_t H5D__cache_dataspace_info(const H5D_t *dset); static herr_t H5D__init_space(H5F_t *file, const H5D_t *dset, const H5S_t *space); static herr_t H5D__update_oh_info(H5F_t *file, hid_t dxpl_id, H5D_t *dset, hid_t dapl_id); +static herr_t H5D_build_extfile_prefix(const H5D_t *dset, hid_t dapl_id, + char **extfile_prefix); static herr_t H5D__open_oid(H5D_t *dataset, hid_t dapl_id, hid_t dxpl_id); static herr_t H5D__init_storage(const H5D_io_info_t *io_info, hbool_t full_overwrite, hsize_t old_dim[]); @@ -982,6 +984,84 @@ done: } /* end H5D__update_oh_info() */ +/*-------------------------------------------------------------------------- + * Function: H5D_build_extfile_prefix + * + * Purpose: Determine the external file prefix to be used and store + * it in extfile_prefix. Stores an empty string if no prefix + * should be used. + * + * Return: SUCCEED/FAIL + * + * Programmer: Steffen Kiess + * October 16, 2015 + *-------------------------------------------------------------------------- + */ +static herr_t +H5D_build_extfile_prefix(const H5D_t *dset, hid_t dapl_id, char **extfile_prefix /*out*/) +{ + char *prefix = NULL; /* prefix used to look for the file */ + char *extpath = NULL; /* absolute path of directory the HDF5 file is in */ + size_t extpath_len; /* length of extpath */ + size_t prefix_len; /* length of prefix */ + size_t extfile_prefix_len; /* length of expanded prefix */ + H5P_genplist_t *plist = NULL; /* Property list pointer */ + herr_t ret_value = SUCCEED; /* Return value */ + + + FUNC_ENTER_NOAPI_NOINIT + + HDassert(dset); + HDassert(dset->oloc.file); + + extpath = H5F_EXTPATH(dset->oloc.file); + HDassert(extpath); + + /* XXX: Future thread-safety note - getenv is not required + * to be reentrant. + */ + prefix = HDgetenv("HDF5_EXTFILE_PREFIX"); + + if(prefix == NULL || *prefix == '\0') { + /* Set prefix to value of H5D_ACS_EFILE_PREFIX_NAME property */ + if(NULL == (plist = H5P_object_verify(dapl_id, H5P_DATASET_ACCESS))) + HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID") + if(H5P_peek(plist, H5D_ACS_EFILE_PREFIX_NAME, &prefix) < 0) + HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get external file prefix") + } /* end if */ + + /* Prefix has to be checked for NULL / empty string again because the + * code above might have updated it. + */ + if(prefix == NULL || *prefix == '\0' || HDstrcmp(prefix, ".") == 0) { + /* filename is interpreted as relative to the current directory, + * does not need to be expanded + */ + if(NULL == (*extfile_prefix = (char *)H5MM_strdup(""))) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed") + } /* end if */ + else { + if (HDstrncmp(prefix, "${ORIGIN}", HDstrlen("${ORIGIN}")) == 0) { + /* Replace ${ORIGIN} at beginning of prefix by directory of HDF5 file */ + extpath_len = HDstrlen(extpath); + prefix_len = HDstrlen(prefix); + extfile_prefix_len = extpath_len + prefix_len - HDstrlen("${ORIGIN}") + 1; + + if(NULL == (*extfile_prefix = (char *)H5MM_malloc(extfile_prefix_len))) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "unable to allocate buffer") + HDsnprintf(*extfile_prefix, extfile_prefix_len, "%s%s", extpath, prefix + HDstrlen("${ORIGIN}")); + } /* end if */ + else { + if(NULL == (*extfile_prefix = (char *)H5MM_strdup(prefix))) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed") + } /* end else */ + } /* end else */ + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* H5D_build_extfile_prefix() */ + + /*------------------------------------------------------------------------- * Function: H5D__create * @@ -1151,6 +1231,10 @@ H5D__create(H5F_t *file, hid_t type_id, const H5S_t *space, hid_t dcpl_id, /* Indicate that the layout information was initialized */ layout_init = TRUE; + /* Set the external file prefix */ + if(H5D_build_extfile_prefix(new_dset, dapl_id, &new_dset->shared->extfile_prefix) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, NULL, "unable to initialize external file prefix") + /* Add the dataset to the list of opened objects in the file */ if(H5FO_top_incr(new_dset->oloc.file, new_dset->oloc.addr) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTINC, NULL, "can't incr object ref. count") @@ -1195,6 +1279,7 @@ done: } /* end if */ if(new_dset->shared->dcpl_id != 0 && H5I_dec_ref(new_dset->shared->dcpl_id) < 0) HDONE_ERROR(H5E_DATASET, H5E_CANTDEC, NULL, "unable to decrement ref count on property list") + new_dset->shared->extfile_prefix = (char *)H5MM_xfree(new_dset->shared->extfile_prefix); new_dset->shared = H5FL_FREE(H5D_shared_t, new_dset->shared); } /* end if */ new_dset->oloc.file = NULL; @@ -1288,7 +1373,8 @@ H5D_open(const H5G_loc_t *loc, hid_t dapl_id, hid_t dxpl_id) { H5D_shared_t *shared_fo = NULL; H5D_t *dataset = NULL; - H5D_t *ret_value = NULL; /* Return value */ + char *extfile_prefix = NULL; /* Expanded external file prefix */ + H5D_t *ret_value = NULL; /* Return value */ FUNC_ENTER_NOAPI(NULL) @@ -1307,6 +1393,10 @@ H5D_open(const H5G_loc_t *loc, hid_t dapl_id, hid_t dxpl_id) if(H5G_name_copy(&(dataset->path), loc->path, H5_COPY_SHALLOW) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTCOPY, NULL, "can't copy path") + /* Get the external file prefix */ + if(H5D_build_extfile_prefix(dataset, dapl_id, &extfile_prefix) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, NULL, "unable to initialize external file prefix") + /* Check if dataset was already open */ if(NULL == (shared_fo = (H5D_shared_t *)H5FO_opened(dataset->oloc.file, dataset->oloc.addr))) { /* Clear any errors from H5FO_opened() */ @@ -1326,6 +1416,12 @@ H5D_open(const H5G_loc_t *loc, hid_t dapl_id, hid_t dxpl_id) /* We're the first dataset to use the the shared info */ dataset->shared->fo_count = 1; + + /* Set the external file prefix */ + dataset->shared->extfile_prefix = extfile_prefix; + /* Prevent string from being freed during done: */ + extfile_prefix = NULL; + } /* end if */ else { /* Point to shared info */ @@ -1334,6 +1430,12 @@ H5D_open(const H5G_loc_t *loc, hid_t dapl_id, hid_t dxpl_id) /* Increment # of datasets using shared information */ shared_fo->fo_count++; + /* Check whether the external file prefix of the already open dataset + * matches the new external file prefix + */ + if(HDstrcmp(extfile_prefix, dataset->shared->extfile_prefix) != 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTOPENOBJ, NULL, "new external file prefix does not match external file prefix of already open dataset") + /* Check if the object has been opened through the top file yet */ if(H5FO_top_count(dataset->oloc.file, dataset->oloc.addr) == 0) { /* Open the object through this top file */ @@ -1350,11 +1452,15 @@ H5D_open(const H5G_loc_t *loc, hid_t dapl_id, hid_t dxpl_id) ret_value = dataset; done: + extfile_prefix = (char *)H5MM_xfree(extfile_prefix); + if(ret_value == NULL) { /* Free the location--casting away const*/ if(dataset) { - if(shared_fo == NULL) /* Need to free shared fo */ + if(shared_fo == NULL && dataset->shared) { /* Need to free shared fo */ + dataset->shared->extfile_prefix = (char *)H5MM_xfree(dataset->shared->extfile_prefix); dataset->shared = H5FL_FREE(H5D_shared_t, dataset->shared); + } H5O_loc_free(&(dataset->oloc)); H5G_name_free(&(dataset->path)); @@ -1658,6 +1764,9 @@ H5D_close(H5D_t *dataset) if(dataset->shared->layout.ops->dest && (dataset->shared->layout.ops->dest)(dataset, H5AC_ind_read_dxpl_id) < 0) HDONE_ERROR(H5E_DATASET, H5E_CANTRELEASE, FAIL, "unable to destroy layout info") + /* Free the external file prefix */ + dataset->shared->extfile_prefix = (char *)H5MM_xfree(dataset->shared->extfile_prefix); + /* Release layout, fill-value, efl & pipeline messages */ if(dataset->shared->dcpl_id != H5P_DATASET_CREATE_DEFAULT) free_failed |= (H5O_msg_reset(H5O_PLINE_ID, &dataset->shared->dcpl_cache.pline) < 0) || diff --git a/src/H5Dpkg.h b/src/H5Dpkg.h index 5972d9e..bc04300 100644 --- a/src/H5Dpkg.h +++ b/src/H5Dpkg.h @@ -441,6 +441,8 @@ typedef struct H5D_shared_t { */ H5D_rdcc_t chunk; /* Information about chunked data */ } cache; + + char *extfile_prefix; /* expanded external file prefix */ } H5D_shared_t; struct H5D_t { diff --git a/src/H5Dprivate.h b/src/H5Dprivate.h index 3b43aaf..ab60a50 100644 --- a/src/H5Dprivate.h +++ b/src/H5Dprivate.h @@ -54,6 +54,7 @@ #define H5D_ACS_PREEMPT_READ_CHUNKS_NAME "rdcc_w0" /* Preemption read chunks first */ #define H5D_ACS_VDS_VIEW_NAME "vds_view" /* VDS view option */ #define H5D_ACS_VDS_PRINTF_GAP_NAME "vds_printf_gap" /* VDS printf gap size */ +#define H5D_ACS_EFILE_PREFIX_NAME "external file prefix" /* External file prefix */ /* ======== Data transfer properties ======== */ #define H5D_XFER_MAX_TEMP_BUF_NAME "max_temp_buf" /* Maximum temp buffer size */ @@ -785,10 +785,6 @@ done: * Programmer: Robb Matzke * Friday, October 16, 1998 * - * Modifications: - * Quincey Koziol, May 14, 2002 - * Keep old file's read/write intent in reopened file. - * *------------------------------------------------------------------------- */ hid_t @@ -803,26 +799,27 @@ H5Freopen(hid_t file_id) /* Check arguments */ if(NULL == (old_file = (H5F_t *)H5I_object_verify(file_id, H5I_FILE))) - HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a file") + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a file") /* Get a new "top level" file struct, sharing the same "low level" file struct */ if(NULL == (new_file = H5F_new(old_file->shared, 0, H5P_FILE_CREATE_DEFAULT, H5P_FILE_ACCESS_DEFAULT, NULL))) - HGOTO_ERROR(H5E_FILE, H5E_CANTINIT, FAIL, "unable to reopen file") + HGOTO_ERROR(H5E_FILE, H5E_CANTINIT, FAIL, "unable to reopen file") /* Duplicate old file's names */ new_file->open_name = H5MM_xstrdup(old_file->open_name); new_file->actual_name = H5MM_xstrdup(old_file->actual_name); + new_file->extpath = H5MM_xstrdup(old_file->extpath); if((ret_value = H5I_register(H5I_FILE, new_file, TRUE)) < 0) - HGOTO_ERROR(H5E_ATOM, H5E_CANTREGISTER, FAIL, "unable to atomize file handle") + HGOTO_ERROR(H5E_ATOM, H5E_CANTREGISTER, FAIL, "unable to atomize file handle") /* Keep this ID in file object structure */ new_file->file_id = ret_value; done: if(ret_value < 0 && new_file) - if(H5F_dest(new_file, H5AC_ind_read_dxpl_id, FALSE) < 0) - HDONE_ERROR(H5E_FILE, H5E_CANTCLOSEFILE, FAIL, "can't close file") + if(H5F_dest(new_file, H5AC_ind_read_dxpl_id, FALSE) < 0) + HDONE_ERROR(H5E_FILE, H5E_CANTCLOSEFILE, FAIL, "can't close file") FUNC_LEAVE_API(ret_value) } /* end H5Freopen() */ diff --git a/src/H5Fquery.c b/src/H5Fquery.c index 66f002c..e9af300 100644 --- a/src/H5Fquery.c +++ b/src/H5Fquery.c @@ -158,7 +158,7 @@ H5F_get_actual_name(const H5F_t *f) * Function: H5F_get_extpath * * Purpose: Retrieve the file's 'extpath' flags - * This is used by H5L_extern_traverse() to retrieve the main file's location + * This is used by H5L_extern_traverse() and H5D_build_extfile_prefix() to retrieve the main file's location * when searching the target file. * * Return: 'extpath' on success/abort on failure (shouldn't fail) @@ -125,10 +125,10 @@ static size_t H5MM_peak_alloc_blocks_count_s = 0; * Function: H5MM__is_our_block * * Purpose: Try to determine if a memory buffer has been allocated through - * the H5MM* interface, instead of the system's malloc() routines. + * the H5MM* interface, instead of the system's malloc() routines. * - * Return: Success: TRUE/FALSE - * Failure: (Can't fail) + * Return: Success: TRUE/FALSE + * Failure: (Can't fail) * * Programmer: Quincey Koziol * Dec 30 2015 @@ -149,7 +149,7 @@ H5MM__is_our_block(void *mem) * * Purpose: Check a block wrapper around a buffer to validate it. * - * Return: N/A (void) + * Return: N/A (void) * * Programmer: Quincey Koziol * Dec 30 2015 @@ -173,9 +173,9 @@ H5MM__sanity_check_block(const H5MM_block_t *block) * Function: H5MM__sanity_check * * Purpose: Check a buffer to validate it (just calls - * H5MM__sanity_check_block after finding block for buffer) + * H5MM__sanity_check_block after finding block for buffer) * - * Return: N/A (void) + * Return: N/A (void) * * Programmer: Quincey Koziol * Dec 30 2015 @@ -196,7 +196,7 @@ H5MM__sanity_check(void *mem) * * Purpose: Sanity check all current memory allocations. * - * Return: N/A (void) + * Return: N/A (void) * * Programmer: Quincey Koziol * Jan 5 2016 @@ -206,7 +206,7 @@ H5MM__sanity_check(void *mem) void H5MM_sanity_check_all(void) { - H5MM_block_t *curr; + H5MM_block_t *curr = NULL; curr = H5MM_block_head_s.next; while(curr != &H5MM_block_head_s) { @@ -221,7 +221,7 @@ H5MM_sanity_check_all(void) * * Purpose: Final sanity checks on memory allocation. * - * Return: N/A (void) + * Return: N/A (void) * * Programmer: Quincey Koziol * Jan 1 2016 @@ -257,8 +257,8 @@ H5MM_final_sanity_check(void) * considered an error condition since allocations of zero * bytes usually indicate problems. * - * Return: Success: Pointer new memory - * Failure: NULL + * Return: Success: Pointer to new memory + * Failure: NULL * * Programmer: Quincey Koziol * Nov 8 2003 @@ -268,7 +268,7 @@ H5MM_final_sanity_check(void) void * H5MM_malloc(size_t size) { - void *ret_value; + void *ret_value = NULL; HDassert(size); @@ -346,8 +346,8 @@ H5MM_malloc(size_t size) * bytes usually indicate problems. * * - * Return: Success: Pointer new memory - * Failure: NULL + * Return: Success: Pointer to new memory + * Failure: NULL * * Programmer: Quincey Koziol * Nov 8 2003 @@ -357,7 +357,7 @@ H5MM_malloc(size_t size) void * H5MM_calloc(size_t size) { - void *ret_value; + void *ret_value = NULL; HDassert(size); @@ -392,8 +392,9 @@ H5MM_calloc(size_t size) * Note that the (NULL, 0) combination is undefined behavior * in the C standard. * - * Return: Success: Ptr to new memory if size > 0, NULL if size is zero - * Failure: NULL (input buffer is unchanged on failure) + * Return: Success: Ptr to new memory if size > 0 + * NULL if size is zero + * Failure: NULL (input buffer is unchanged on failure) * * Programmer: Robb Matzke * Jul 10 1997 @@ -403,7 +404,7 @@ H5MM_calloc(size_t size) void * H5MM_realloc(void *mem, size_t size) { - void *ret_value; + void *ret_value = NULL; /* Use FUNC_ENTER_NOAPI_NOINIT_NOERR here to avoid performance issues */ FUNC_ENTER_NOAPI_NOINIT_NOERR @@ -458,7 +459,6 @@ H5MM_realloc(void *mem, size_t size) * Failure: abort() * * Programmer: Robb Matzke - * matzke@llnl.gov * Jul 10 1997 *------------------------------------------------------------------------- */ @@ -490,17 +490,16 @@ done: * an error will be raised. * * Return: Success: Pointer to a new string - * Failure: abort() + * Failure: NULL * * Programmer: Robb Matzke - * matzke@llnl.gov * Jul 10 1997 *------------------------------------------------------------------------- */ char * H5MM_strdup(const char *s) { - char *ret_value; + char *ret_value = NULL; FUNC_ENTER_NOAPI(NULL) @@ -528,7 +527,6 @@ done: * Failure: never fails * * Programmer: Robb Matzke - * matzke@llnl.gov * Jul 10 1997 * *------------------------------------------------------------------------- diff --git a/src/H5Pdapl.c b/src/H5Pdapl.c index eab9337..6407d4c 100644 --- a/src/H5Pdapl.c +++ b/src/H5Pdapl.c @@ -16,8 +16,8 @@ /*------------------------------------------------------------------------- * * Created: H5Pdapl.c - * October 27, 2008 - * Neil Fortner <nfortne2@hdfgroup.org> + * October 27, 2008 + * Neil Fortner <nfortne2@hdfgroup.org> * * Purpose: Dataset access property list class routines * @@ -39,7 +39,8 @@ #include "H5Eprivate.h" /* Error handling */ #include "H5Fprivate.h" /* Files */ #include "H5Iprivate.h" /* IDs */ -#include "H5Ppkg.h" /* Property lists */ +#include "H5Ppkg.h" /* Property lists */ +#include "H5MMprivate.h" /* Memory management */ /****************/ @@ -72,6 +73,17 @@ #define H5D_ACS_VDS_PRINTF_GAP_DEF (hsize_t)0 #define H5D_ACS_VDS_PRINTF_GAP_ENC H5P__encode_hsize_t #define H5D_ACS_VDS_PRINTF_GAP_DEC H5P__decode_hsize_t +/* Definitions for external file prefix */ +#define H5D_ACS_EFILE_PREFIX_SIZE sizeof(char *) +#define H5D_ACS_EFILE_PREFIX_DEF NULL /*default is no prefix */ +#define H5D_ACS_EFILE_PREFIX_SET H5P__dapl_efile_pref_set +#define H5D_ACS_EFILE_PREFIX_GET H5P__dapl_efile_pref_get +#define H5D_ACS_EFILE_PREFIX_ENC H5P__dapl_efile_pref_enc +#define H5D_ACS_EFILE_PREFIX_DEC H5P__dapl_efile_pref_dec +#define H5D_ACS_EFILE_PREFIX_DEL H5P__dapl_efile_pref_del +#define H5D_ACS_EFILE_PREFIX_COPY H5P__dapl_efile_pref_copy +#define H5D_ACS_EFILE_PREFIX_CMP H5P__dapl_efile_pref_cmp +#define H5D_ACS_EFILE_PREFIX_CLOSE H5P__dapl_efile_pref_close /******************/ /* Local Typedefs */ @@ -100,6 +112,16 @@ static herr_t H5P__decode_chunk_cache_nbytes(const void **_pp, void *_value); static herr_t H5P__dacc_vds_view_enc(const void *value, void **pp, size_t *size); static herr_t H5P__dacc_vds_view_dec(const void **pp, void *value); +/* Property list callbacks */ +static herr_t H5P__dapl_efile_pref_set(hid_t prop_id, const char* name, size_t size, void* value); +static herr_t H5P__dapl_efile_pref_get(hid_t prop_id, const char* name, size_t size, void* value); +static herr_t H5P__dapl_efile_pref_enc(const void *value, void **_pp, size_t *size); +static herr_t H5P__dapl_efile_pref_dec(const void **_pp, void *value); +static herr_t H5P__dapl_efile_pref_del(hid_t prop_id, const char* name, size_t size, void* value); +static herr_t H5P__dapl_efile_pref_copy(const char* name, size_t size, void* value); +static int H5P__dapl_efile_pref_cmp(const void *value1, const void *value2, size_t size); +static herr_t H5P__dapl_efile_pref_close(const char* name, size_t size, void* value); + /*********************/ /* Package Variables */ @@ -134,6 +156,9 @@ const H5P_libclass_t H5P_CLS_DACC[1] = {{ /* Local Variables */ /*******************/ +/* Property value defaults */ +static const char *H5D_def_efile_prefix_g = H5D_ACS_EFILE_PREFIX_DEF; /* Default external file prefix string */ + /*------------------------------------------------------------------------- @@ -187,12 +212,274 @@ H5P__dacc_reg_prop(H5P_genclass_t *pclass) NULL, NULL, NULL, NULL) < 0) HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "can't insert property into class") + /* Register property for external file prefix */ + if(H5P_register_real(pclass, H5D_ACS_EFILE_PREFIX_NAME, H5D_ACS_EFILE_PREFIX_SIZE, &H5D_def_efile_prefix_g, + NULL, H5D_ACS_EFILE_PREFIX_SET, H5D_ACS_EFILE_PREFIX_GET, H5D_ACS_EFILE_PREFIX_ENC, H5D_ACS_EFILE_PREFIX_DEC, + H5D_ACS_EFILE_PREFIX_DEL, H5D_ACS_EFILE_PREFIX_COPY, H5D_ACS_EFILE_PREFIX_CMP, H5D_ACS_EFILE_PREFIX_CLOSE) < 0) + HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "can't insert property into class") + done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5P__dacc_reg_prop() */ /*------------------------------------------------------------------------- + * Function: H5P__dapl_efile_pref_set + * + * Purpose: Copies an external file prefix property when it's set + * for a property list + * + * Return: SUCCEED/FAIL + * + *------------------------------------------------------------------------- + */ +static herr_t +H5P__dapl_efile_pref_set(hid_t H5_ATTR_UNUSED prop_id, const char H5_ATTR_UNUSED *name, + size_t H5_ATTR_UNUSED size, void *value) +{ + FUNC_ENTER_STATIC_NOERR + + /* Sanity check */ + HDassert(value); + + /* Copy the prefix */ + *(char **)value = H5MM_xstrdup(*(const char **)value); + + FUNC_LEAVE_NOAPI(SUCCEED) +} /* end H5P__dapl_efile_pref_set() */ + + +/*------------------------------------------------------------------------- + * Function: H5P__dapl_efile_pref_get + * + * Purpose: Copies an external file prefix property when it's retrieved + * from a property list + * + * Return: SUCCEED/FAIL + * + *------------------------------------------------------------------------- + */ +static herr_t +H5P__dapl_efile_pref_get(hid_t H5_ATTR_UNUSED prop_id, const char H5_ATTR_UNUSED *name, + size_t H5_ATTR_UNUSED size, void *value) +{ + FUNC_ENTER_STATIC_NOERR + + /* Sanity check */ + HDassert(value); + + /* Copy the prefix */ + *(char **)value = H5MM_xstrdup(*(const char **)value); + + FUNC_LEAVE_NOAPI(SUCCEED) +} /* end H5P__dapl_efile_pref_get() */ + + +/*------------------------------------------------------------------------- + * Function: H5P__dapl_efile_pref_enc + * + * Purpose: Callback routine which is called whenever the efile flags + * property in the dataset access property list is + * encoded. + * + * Return: SUCCEED/FAIL + * + *------------------------------------------------------------------------- + */ +static herr_t +H5P__dapl_efile_pref_enc(const void *value, void **_pp, size_t *size) +{ + const char *efile_pref = *(const char * const *)value; + uint8_t **pp = (uint8_t **)_pp; + size_t len = 0; + uint64_t enc_value; + unsigned enc_size; + + FUNC_ENTER_NOAPI_NOINIT_NOERR + + HDcompile_assert(sizeof(size_t) <= sizeof(uint64_t)); + + /* calculate prefix length */ + if(NULL != efile_pref) + len = HDstrlen(efile_pref); + + enc_value = (uint64_t)len; + enc_size = H5VM_limit_enc_size(enc_value); + HDassert(enc_size < 256); + + if(NULL != *pp) { + /* encode the length of the prefix */ + *(*pp)++ = (uint8_t)enc_size; + UINT64ENCODE_VAR(*pp, enc_value, enc_size); + + /* encode the prefix */ + if(NULL != efile_pref) { + HDmemcpy(*(char **)pp, efile_pref, len); + *pp += len; + } /* end if */ + } /* end if */ + + *size += (1 + enc_size); + if(NULL != efile_pref) + *size += len; + + FUNC_LEAVE_NOAPI(SUCCEED) +} /* end H5P__dapl_efile_pref_enc() */ + + +/*------------------------------------------------------------------------- + * Function: H5P__dapl_efile_pref_dec + * + * Purpose: Callback routine which is called whenever the efile prefix + * property in the dataset access property list is + * decoded. + * + * Return: SUCCEED/FAIL + * + *------------------------------------------------------------------------- + */ +static herr_t +H5P__dapl_efile_pref_dec(const void **_pp, void *_value) +{ + char **efile_pref = (char **)_value; + const uint8_t **pp = (const uint8_t **)_pp; + size_t len; + uint64_t enc_value; /* Decoded property value */ + unsigned enc_size; /* Size of encoded property */ + herr_t ret_value = SUCCEED; + + FUNC_ENTER_NOAPI_NOINIT + + HDassert(pp); + HDassert(*pp); + HDassert(efile_pref); + HDcompile_assert(sizeof(size_t) <= sizeof(uint64_t)); + + /* Decode the size */ + enc_size = *(*pp)++; + HDassert(enc_size < 256); + + /* Decode the value */ + UINT64DECODE_VAR(*pp, enc_value, enc_size); + len = (size_t)enc_value; + + if(0 != len) { + /* Make a copy of the user's prefix string */ + if(NULL == (*efile_pref = (char *)H5MM_malloc(len + 1))) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINIT, FAIL, "memory allocation failed for prefix") + HDstrncpy(*efile_pref, *(const char **)pp, len); + (*efile_pref)[len] = '\0'; + + *pp += len; + } /* end if */ + else + *efile_pref = NULL; + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5P__dapl_efile_pref_dec() */ + + +/*------------------------------------------------------------------------- + * Function: H5P__dapl_efile_pref_del + * + * Purpose: Frees memory used to store the external file prefix string + * + * Return: SUCCEED (Can't fail) + * + *------------------------------------------------------------------------- + */ +static herr_t +H5P__dapl_efile_pref_del(hid_t H5_ATTR_UNUSED prop_id, const char H5_ATTR_UNUSED *name, + size_t H5_ATTR_UNUSED size, void *value) +{ + FUNC_ENTER_NOAPI_NOINIT_NOERR + + HDassert(value); + + H5MM_xfree(*(void **)value); + + FUNC_LEAVE_NOAPI(SUCCEED) +} /* end H5P__dapl_efile_pref_del() */ + + +/*------------------------------------------------------------------------- + * Function: H5P__dapl_efile_pref_copy + * + * Purpose: Creates a copy of the external file prefix string + * + * Return: SUCCEED/FAIL + * + *------------------------------------------------------------------------- + */ +static herr_t +H5P__dapl_efile_pref_copy(const char H5_ATTR_UNUSED *name, size_t H5_ATTR_UNUSED size, void *value) +{ + FUNC_ENTER_NOAPI_NOINIT_NOERR + + HDassert(value); + + *(char **)value = H5MM_xstrdup(*(const char **)value); + + FUNC_LEAVE_NOAPI(SUCCEED) +} /* end H5P__dapl_efile_pref_copy() */ + + +/*------------------------------------------------------------------------- + * Function: H5P__dapl_efile_pref_cmp + * + * Purpose: Callback routine which is called whenever the efile prefix + * property in the dataset creation property list is + * compared. + * + * Return: zero if VALUE1 and VALUE2 are equal, non zero otherwise. + * + *------------------------------------------------------------------------- + */ +static int +H5P__dapl_efile_pref_cmp(const void *value1, const void *value2, size_t H5_ATTR_UNUSED size) +{ + const char *pref1 = *(const char * const *)value1; + const char *pref2 = *(const char * const *)value2; + int ret_value = 0; + + FUNC_ENTER_NOAPI_NOINIT_NOERR + + if(NULL == pref1 && NULL != pref2) + HGOTO_DONE(1); + if(NULL != pref1 && NULL == pref2) + HGOTO_DONE(-1); + if(NULL != pref1 && NULL != pref2) + ret_value = HDstrcmp(pref1, pref2); + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5P__dapl_efile_pref_cmp() */ + + +/*------------------------------------------------------------------------- + * Function: H5P__dapl_efile_pref_close + * + * Purpose: Frees memory used to store the external file prefix string + * + * Return: SUCCEED/FAIL + * + *------------------------------------------------------------------------- + */ +static herr_t +H5P__dapl_efile_pref_close(const char H5_ATTR_UNUSED *name, size_t H5_ATTR_UNUSED size, void *value) +{ + FUNC_ENTER_NOAPI_NOINIT_NOERR + + HDassert(value); + + H5MM_xfree(*(void **)value); + + FUNC_LEAVE_NOAPI(SUCCEED) +} /* end H5P__dapl_efile_pref_close() */ + + +/*------------------------------------------------------------------------- * Function: H5Pset_chunk_cache * * Purpose: Set the number of objects in the meta data cache and the @@ -787,3 +1074,94 @@ done: FUNC_LEAVE_API(ret_value) } /* end H5Pget_virtual_printf_gap() */ + +/*------------------------------------------------------------------------- + * Function: H5Pset_efile_prefix + * + * Purpose: Set a prefix to be used for any external files. + * + * If the prefix starts with ${ORIGIN}, this will be replaced by + * the absolute path of the directory of the HDF5 file containing + * the dataset. + * + * If the prefix is ".", no prefix will be applied. + * + * This property can be overwritten by the environment variable + * HDF5_EXTFILE_PREFIX. + * + * Return: Non-negative on success/Negative on failure + * + *------------------------------------------------------------------------- + */ +herr_t +H5Pset_efile_prefix(hid_t plist_id, const char *prefix) +{ + H5P_genplist_t *plist; /* Property list pointer */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_API(FAIL) + H5TRACE2("e", "i*s", plist_id, prefix); + + /* Get the plist structure */ + if(NULL == (plist = H5P_object_verify(plist_id, H5P_DATASET_ACCESS))) + HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID") + + /* Set prefix */ + if(H5P_set(plist, H5D_ACS_EFILE_PREFIX_NAME, &prefix) < 0) + HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set prefix info") + +done: + FUNC_LEAVE_API(ret_value) +} /* end H5Pset_efile_prefix() */ + + +/*------------------------------------------------------------------------- + * Function: H5Pget_efile_prefix + * + * Purpose: Gets the prefix to be used for any external files. + * + * If the pointer is not NULL, it points to a user-allocated + * buffer. + * + * Return: Non-negative on success/Negative on failure + * + *------------------------------------------------------------------------- + */ +ssize_t +H5Pget_efile_prefix(hid_t plist_id, char *prefix, size_t size) +{ + H5P_genplist_t *plist; /* Property list pointer */ + char *my_prefix; /* Library's copy of the prefix */ + size_t len; /* Length of prefix string */ + ssize_t ret_value; /* Return value */ + + FUNC_ENTER_API(FAIL) + H5TRACE3("Zs", "i*sz", plist_id, prefix, size); + + /* Get the plist structure */ + if(NULL == (plist = H5P_object_verify(plist_id, H5P_DATASET_ACCESS))) + HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID") + + /* Get the current prefix */ + if(H5P_peek(plist, H5D_ACS_EFILE_PREFIX_NAME, &my_prefix) < 0) + HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get external file prefix") + + /* Check for prefix being set */ + if(my_prefix) { + /* Copy to user's buffer, if given */ + len = HDstrlen(my_prefix); + if(prefix) { + HDstrncpy(prefix, my_prefix, MIN(len + 1, size)); + if(len >= size) + prefix[size - 1] = '\0'; + } /* end if */ + } /* end if */ + else + len = 0; + + /* Set return value */ + ret_value = (ssize_t)len; + +done: + FUNC_LEAVE_API(ret_value) +} /* end H5Pget_efile_prefix() */ diff --git a/src/H5Plapl.c b/src/H5Plapl.c index f725435..266dc63 100644 --- a/src/H5Plapl.c +++ b/src/H5Plapl.c @@ -800,7 +800,8 @@ done: *------------------------------------------------------------------------- */ static herr_t -H5P__lacc_elink_pref_del(hid_t H5_ATTR_UNUSED prop_id, const char H5_ATTR_UNUSED *name, size_t H5_ATTR_UNUSED size, void *value) +H5P__lacc_elink_pref_del(hid_t H5_ATTR_UNUSED prop_id, const char H5_ATTR_UNUSED *name, + size_t H5_ATTR_UNUSED size, void *value) { FUNC_ENTER_STATIC_NOERR diff --git a/src/H5Ppublic.h b/src/H5Ppublic.h index 589bcdc..894fc2c 100644 --- a/src/H5Ppublic.h +++ b/src/H5Ppublic.h @@ -406,6 +406,8 @@ H5_DLL herr_t H5Pset_virtual_view(hid_t plist_id, H5D_vds_view_t view); H5_DLL herr_t H5Pget_virtual_view(hid_t plist_id, H5D_vds_view_t *view); H5_DLL herr_t H5Pset_virtual_printf_gap(hid_t plist_id, hsize_t gap_size); H5_DLL herr_t H5Pget_virtual_printf_gap(hid_t plist_id, hsize_t *gap_size); +H5_DLL herr_t H5Pset_efile_prefix(hid_t dapl_id, const char* prefix); +H5_DLL ssize_t H5Pget_efile_prefix(hid_t dapl_id, char* prefix /*out*/, size_t size); /* Dataset xfer property list (DXPL) routines */ H5_DLL herr_t H5Pset_data_transform(hid_t plist_id, const char* expression); diff --git a/src/H5private.h b/src/H5private.h index 8d5f4c9..fa5a114 100644 --- a/src/H5private.h +++ b/src/H5private.h @@ -1189,6 +1189,9 @@ typedef off_t h5_stat_size_t; #ifndef HDsetbuf #define HDsetbuf(F,S) setbuf(F,S) #endif /* HDsetbuf */ +#ifndef HDsetenv + #define HDsetenv(N,V,O) setenv(N,V,O) +#endif /* HDsetenv */ #ifndef HDsetgid #define HDsetgid(G) setgid(G) #endif /* HDsetgid */ @@ -2560,7 +2563,8 @@ H5_DLL uint32_t H5_hash_string(const char *str); H5_DLL time_t H5_make_time(struct tm *tm); /* Functions for building paths, etc. */ -H5_DLL herr_t H5_build_extpath(const char *, char ** /*out*/ ); +H5_DLL herr_t H5_build_extpath(const char *name, char **extpath /*out*/); +H5_DLL herr_t H5_combine_path(const char *path1, const char *path2, char **full_name /*out*/); /* Functions for debugging */ H5_DLL herr_t H5_buffer_dump(FILE *stream, int indent, const uint8_t *buf, diff --git a/src/H5system.c b/src/H5system.c index 4baebc5..eb09b15 100644 --- a/src/H5system.c +++ b/src/H5system.c @@ -757,7 +757,7 @@ done: */ int Wgettimeofday(struct timeval *tv, struct timezone *tz) - { +{ union { unsigned long long ns100; /*time since 1 Jan 1601 in 100ns units */ FILETIME ft; @@ -783,7 +783,42 @@ Wgettimeofday(struct timeval *tv, struct timezone *tz) /* Always return 0 as per Open Group Base Specifications Issue 6. Do not set errno on error. */ return 0; -} +} /* end Wgettimeofday() */ + + +/*------------------------------------------------------------------------- + * Function: Wsetenv + * + * Purpose: Wrapper function for setenv on Windows systems. + * Interestingly, getenv *is* available in the Windows + * POSIX layer, just not setenv. + * + * Return: Success: 0 + * Failure: non-zero error code + * + * Programmer: Dana Robinson + * February 2016 + * + *------------------------------------------------------------------------- + */ +int +Wsetenv(const char *name, const char *value, int overwrite) +{ + size_t bufsize; + errno_t err; + + /* If we're not overwriting, check if the environment variable exists. + * If it does (i.e.: the required buffer size to store the variable's + * value is non-zero), then return an error code. + */ + if(!overwrite) { + err = getenv_s(&bufsize, NULL, 0, name); + if (err || bufsize) + return (int)err; + } /* end if */ + + return (int)_putenv_s(name, value); +} /* end Wsetenv() */ #ifdef H5_HAVE_WINSOCK2_H #pragma comment(lib, "advapi32.lib") @@ -881,26 +916,25 @@ Wflock(int fd, int operation) { /*------------------------------------------------------------------------- - * Function: H5_build_extpath + * Function: H5_build_extpath * - * Purpose: To build the path for later searching of target file for external - * link. This path can be either: + * Purpose: To build the path for later searching of target file for external + * links and external files. This path can be either: * 1. The absolute path of NAME * or * 2. The current working directory + relative path of NAME * - * Return: Success: 0 - * Failure: -1 + * Return: SUCCEED/FAIL * * Programmer: Vailin Choi - * April 2, 2008 + * April 2, 2008 * *------------------------------------------------------------------------- */ #define MAX_PATH_LEN 1024 herr_t -H5_build_extpath(const char *name, char **extpath/*out*/) +H5_build_extpath(const char *name, char **extpath /*out*/) { char *full_path = NULL; /* Pointer to the full path, as built or passed in */ char *cwdpath = NULL; /* Pointer to the current working directory path */ @@ -998,5 +1032,80 @@ done: H5MM_xfree(new_name); FUNC_LEAVE_NOAPI(ret_value) -} /* H5_build_extpath() */ +} /* end H5_build_extpath() */ + + +/*-------------------------------------------------------------------------- + * Function: H5_combine_path + * + * Purpose: If path2 is relative, interpret path2 as relative to path1 + * and store the result in full_name. Otherwise store path2 + * in full_name. + * + * Return: SUCCEED/FAIL + * + * Programmer: Steffen Kiess + * June 22, 2015 + *-------------------------------------------------------------------------- + */ +herr_t +H5_combine_path(const char* path1, const char* path2, char **full_name /*out*/) +{ + size_t path1_len; /* length of path1 */ + size_t path2_len; /* length of path2 */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT + + HDassert(path1); + HDassert(path2); + + path1_len = HDstrlen(path1); + path2_len = HDstrlen(path2); + + if(*path1 == '\0' || H5_CHECK_ABSOLUTE(path2)) { + + /* If path1 is empty or path2 is absolute, simply use path2 */ + if(NULL == (*full_name = (char *)H5MM_strdup(path2))) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed") + + } /* end if */ + else if(H5_CHECK_ABS_PATH(path2)) { + + /* On windows path2 is a path absolute name */ + if (H5_CHECK_ABSOLUTE(path1) || H5_CHECK_ABS_DRIVE(path1)) { + /* path1 is absolute or drive absolute and path2 is path absolute. + * Use the drive letter of path1 + path2 + */ + if(NULL == (*full_name = (char *)H5MM_malloc(path2_len + 3))) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "unable to allocate path2 buffer") + HDsnprintf(*full_name, (path2_len + 3), "%c:%s", path1[0], path2); + } /* end if */ + else { + /* On windows path2 is path absolute name ("\foo\bar"), + * path1 does not have a drive letter (i.e. is "a\b" or "\a\b"). + * Use path2. + */ + if(NULL == (*full_name = (char *)H5MM_strdup(path2))) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed") + } /* end else */ + + } /* end else if */ + else { + + /* Relative path2: + * Allocate a buffer to hold path1 + path2 + possibly the delimiter + * + terminating null byte + */ + if(NULL == (*full_name = (char *)H5MM_malloc(path1_len + path2_len + 2))) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "unable to allocate filename buffer") + + /* Compose the full file name */ + HDsnprintf(*full_name, (path1_len + path2_len + 2), "%s%s%s", path1, + (H5_CHECK_DELIMITER(path1[path1_len - 1]) ? "" : H5_DIR_SEPS), path2); + } /* end else */ + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5_combine_name() */ diff --git a/src/H5win32defs.h b/src/H5win32defs.h index e84def9..2a0f22d 100644 --- a/src/H5win32defs.h +++ b/src/H5win32defs.h @@ -71,21 +71,24 @@ struct timezone { }; #ifdef __cplusplus - extern "C" { +extern "C" { #endif /* __cplusplus */ - H5_DLL int Wgettimeofday(struct timeval *tv, struct timezone *tz); - H5_DLL int Wflock(int fd, int operation); - H5_DLL char* Wgetlogin(void); - H5_DLL int c99_snprintf(char* str, size_t size, const char* format, ...); - H5_DLL int c99_vsnprintf(char* str, size_t size, const char* format, va_list ap); + H5_DLL int Wgettimeofday(struct timeval *tv, struct timezone *tz); + H5_DLL int Wsetenv(const char *name, const char *value, int overwrite); + H5_DLL int Wflock(int fd, int operation); + H5_DLL char* Wgetlogin(void); + H5_DLL int c99_snprintf(char* str, size_t size, const char* format, ...); + H5_DLL int c99_vsnprintf(char* str, size_t size, const char* format, va_list ap); #ifdef __cplusplus - } +} #endif /* __cplusplus */ + #define HDgettimeofday(V,Z) Wgettimeofday(V,Z) +#define HDsetenv(N,V,O) Wsetenv(N,V,O) #define HDflock(F,L) Wflock(F,L) #define HDgetlogin() Wgetlogin() #define HDsnprintf c99_snprintf /*varargs*/ -#define HDvsnprintf c99_vsnprintf +#define HDvsnprintf c99_vsnprintf /*varargs*/ #endif /* H5_HAVE_VISUAL_STUDIO */ @@ -98,5 +101,7 @@ struct timezone { #ifndef H5_HAVE_MINGW #define HDftruncate(F,L) _chsize_s(F,L) #define HDfseek(F,O,W) _fseeki64(F,O,W) -#endif +#endif /* H5_HAVE_MINGW */ + #endif /* H5_HAVE_WIN32_API */ + |