summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--MANIFEST47
-rwxr-xr-xbin/trace1
-rw-r--r--hl/src/H5LT.c571
-rw-r--r--hl/src/H5LTpublic.h18
-rw-r--r--hl/test/Makefile.am4
-rw-r--r--hl/test/Makefile.in27
-rw-r--r--hl/test/h5hltest.h6
-rw-r--r--hl/test/test_file_image.c518
-rw-r--r--src/H5Dint.c3
-rw-r--r--src/H5E.c12
-rw-r--r--src/H5Edefin.h1
-rw-r--r--src/H5Einit.h5
-rw-r--r--src/H5Epubgen.h2
-rw-r--r--src/H5Eterm.h3
-rw-r--r--src/H5F.c284
-rw-r--r--src/H5FD.c82
-rw-r--r--src/H5FDcore.c293
-rw-r--r--src/H5FDfamily.c2
-rw-r--r--src/H5FDlog.c2
-rw-r--r--src/H5FDprivate.h26
-rw-r--r--src/H5FDpublic.h40
-rw-r--r--src/H5FDsec2.c2
-rw-r--r--src/H5Fprivate.h5
-rw-r--r--src/H5Fpublic.h1
-rw-r--r--src/H5Gname.c11
-rw-r--r--src/H5I.c144
-rw-r--r--src/H5Iprivate.h2
-rw-r--r--src/H5Oattribute.c11
-rw-r--r--src/H5Pfapl.c497
-rw-r--r--src/H5Pint.c54
-rw-r--r--src/H5Ppublic.h6
-rw-r--r--src/H5T.c3
-rw-r--r--src/H5err.txt1
-rw-r--r--test/Makefile.am4
-rw-r--r--test/Makefile.in58
-rw-r--r--test/file_image.c1335
-rw-r--r--test/file_image_core_test.h5bin0 -> 18528 bytes
-rw-r--r--test/gen_file_image.c91
-rw-r--r--testpar/Makefile.am4
-rw-r--r--testpar/Makefile.in12
-rw-r--r--testpar/t_file_image.c395
-rw-r--r--testpar/testphdf5.c7
-rw-r--r--testpar/testphdf5.h1
43 files changed, 4260 insertions, 331 deletions
diff --git a/MANIFEST b/MANIFEST
index b1c207d..a163532 100644
--- a/MANIFEST
+++ b/MANIFEST
@@ -963,32 +963,35 @@
./test/filespace_1_8.h5
./test/filespace_1_6.h5
./test/freespace.c
+./test/file_image.c
+./test/file_image_core_test.h5
./test/fill_old.h5
./test/fillval.c
./test/filter_fail.c
./test/flush1.c
./test/flush2.c
-./test/gen_bad_ohdr.c _DO_NOT_DISTRIBUTE_
-./test/gen_bad_compound.c _DO_NOT_DISTRIBUTE_
-./test/gen_bogus.c _DO_NOT_DISTRIBUTE_
-./test/gen_cross.c _DO_NOT_DISTRIBUTE_
-./test/gen_deflate.c _DO_NOT_DISTRIBUTE_
-./test/gen_filespace.c _DO_NOT_DISTRIBUTE_
-./test/gen_mergemsg.c _DO_NOT_DISTRIBUTE_
-./test/gen_new_array.c _DO_NOT_DISTRIBUTE_
-./test/gen_new_fill.c _DO_NOT_DISTRIBUTE_
-./test/gen_new_group.c _DO_NOT_DISTRIBUTE_
-./test/gen_new_mtime.c _DO_NOT_DISTRIBUTE_
-./test/gen_new_super.c _DO_NOT_DISTRIBUTE_
-./test/gen_noencoder.c _DO_NOT_DISTRIBUTE_
-./test/gen_nullspace.c _DO_NOT_DISTRIBUTE_
-./test/gen_old_array.c _DO_NOT_DISTRIBUTE_
-./test/gen_old_group.c _DO_NOT_DISTRIBUTE_
-./test/gen_old_layout.c _DO_NOT_DISTRIBUTE_
-./test/gen_old_mtime.c _DO_NOT_DISTRIBUTE_
-./test/gen_sizes_lheap.c _DO_NOT_DISTRIBUTE_
-./test/gen_specmetaread.c _DO_NOT_DISTRIBUTE_
-./test/gen_udlinks.c _DO_NOT_DISTRIBUTE_
+./test/gen_bad_ohdr.c _DO_NOT_DISTRIBUTE_
+./test/gen_bad_compound.c _DO_NOT_DISTRIBUTE_
+./test/gen_bogus.c _DO_NOT_DISTRIBUTE_
+./test/gen_cross.c _DO_NOT_DISTRIBUTE_
+./test/gen_deflate.c _DO_NOT_DISTRIBUTE_
+./test/gen_file_image.c _DO_NOT_DISTRIBUTE_
+./test/gen_filespace.c _DO_NOT_DISTRIBUTE_
+./test/gen_mergemsg.c _DO_NOT_DISTRIBUTE_
+./test/gen_new_array.c _DO_NOT_DISTRIBUTE_
+./test/gen_new_fill.c _DO_NOT_DISTRIBUTE_
+./test/gen_new_group.c _DO_NOT_DISTRIBUTE_
+./test/gen_new_mtime.c _DO_NOT_DISTRIBUTE_
+./test/gen_new_super.c _DO_NOT_DISTRIBUTE_
+./test/gen_noencoder.c _DO_NOT_DISTRIBUTE_
+./test/gen_nullspace.c _DO_NOT_DISTRIBUTE_
+./test/gen_old_array.c _DO_NOT_DISTRIBUTE_
+./test/gen_old_group.c _DO_NOT_DISTRIBUTE_
+./test/gen_old_layout.c _DO_NOT_DISTRIBUTE_
+./test/gen_old_mtime.c _DO_NOT_DISTRIBUTE_
+./test/gen_sizes_lheap.c _DO_NOT_DISTRIBUTE_
+./test/gen_specmetaread.c _DO_NOT_DISTRIBUTE_
+./test/gen_udlinks.c _DO_NOT_DISTRIBUTE_
./test/getname.c
./test/gheap.c
./test/group_old.h5
@@ -1083,6 +1086,7 @@
./testpar/t_cache.c
./testpar/t_dset.c
./testpar/t_file.c
+./testpar/t_file_image.c
./testpar/t_mdset.c
./testpar/t_mpi.c
./testpar/t_ph5basic.c
@@ -2075,6 +2079,7 @@
./hl/test/sepia.pal
./hl/test/gen_test_ds.c
./hl/test/test_ds.c
+./hl/test/test_file_image.c
./hl/test/test_image.c
./hl/test/test_lite.c
./hl/test/test_packet.c
diff --git a/bin/trace b/bin/trace
index bfaae19..0235049 100755
--- a/bin/trace
+++ b/bin/trace
@@ -109,6 +109,7 @@ $Source = "";
"H5FD_t" => "x",
"H5FD_class_t" => "x",
"H5FD_stream_fapl_t" => "x",
+ "H5FD_file_image_callbacks_t" => "x",
"H5G_iterate_t" => "x",
"H5G_info_t" => "x",
"H5I_free_t" => "x",
diff --git a/hl/src/H5LT.c b/hl/src/H5LT.c
index eeaceeb..8136b11 100644
--- a/hl/src/H5LT.c
+++ b/hl/src/H5LT.c
@@ -17,6 +17,7 @@
#include <stdlib.h>
#include <assert.h>
#include <stdio.h>
+
#include "H5LTprivate.h"
#include "H5private.h"
@@ -31,7 +32,461 @@ char *myinput;
size_t indent = 0;
+/* File Image operations
+
+ A file image is a representation of an HDF5 file in a memory
+ buffer. In order to perform operations on an image in a similar way
+ to a file, the application buffer is copied to a FAPL buffer, which
+ in turn is copied to a VFD buffer. Buffer copying can decrease
+ performance, especially when using large file images. A solution to
+ this issue is to simulate the copying of the application buffer,
+ when actually the same buffer is used for the FAPL and the VFD.
+ This is implemented by using callbacks that simulate the standard
+ functions for memory management (additional callbacks are used for
+ the management of associated data structures). From the application
+ standpoint, a file handle can be obtained from a file image by using
+ the API routine H5LTopen_file_image(). This function takes a flag
+ argument that indicates the HDF5 library how to handle the given image;
+ several flag values can be combined by using the bitwise OR operator.
+ Valid flag values include:
+
+ H5LT_FILE_IMAGE_OPEN_RW indicates the HDF5 library to open the file
+ image in read/write mode. Default is read-only mode.
+
+ H5LT_FILE_IMAGE_DONT_COPY indicates the HDF5 library to not copy the
+ supplied user buffer; the same buffer will be handled by the FAPL and
+ the VFD driver. Default operation copies the user buffer to the FAPL and
+ VFD driver.
+
+ H5LT_FILE_IMAGE_DONT_RELEASE indicates the HDF5 library to not release
+ the buffer handled by the FAPL and the VFD upon closing. This flag value
+ is only applicable when the flag value H5LT_FILE_IMAGE_DONT_COPY is set as
+ well. The application is responsible to release the image buffer.
+*/
+
+/* Data structure to pass application data to callbacks. */
+typedef struct {
+ void *app_image_ptr; /* Pointer to application buffer */
+ size_t app_image_size; /* Size of application buffer */
+ void *fapl_image_ptr; /* Pointer to FAPL buffer */
+ size_t fapl_image_size; /* Size of FAPL buffer */
+ int fapl_ref_count; /* Reference counter for FAPL buffer */
+ void *vfd_image_ptr; /* Pointer to VFD buffer */
+ size_t vfd_image_size; /* Size of VFD buffer */
+ int vfd_ref_count; /* Reference counter for VFD buffer */
+ unsigned flags; /* Flags indicate how the file image will */
+ /* be open */
+ int ref_count; /* Reference counter on udata struct */
+} H5LT_file_image_ud_t;
+
+/* callbacks prototypes for file image ops */
+static void *image_malloc(size_t size, H5FD_file_image_op_t file_image_op, void *udata);
+static void *image_memcpy(void *dest, const void *src, size_t size, H5FD_file_image_op_t file_image_op, void *udata);
+static void *image_realloc(void *ptr, size_t size, H5FD_file_image_op_t file_image_op, void *udata);
+static herr_t image_free(void *ptr, H5FD_file_image_op_t file_image_op, void *udata);
+static void *udata_copy(void *udata);
+static herr_t udata_free(void *udata);
+
+/* Definition of callbacks for file image operations. */
+
+
+/*-------------------------------------------------------------------------
+* Function: image_malloc
+*
+* Purpose: Simulates malloc() function to avoid copying file images.
+* The application buffer is set to the buffer on only one FAPL.
+* Then the FAPL buffer can be copied to other FAPL buffers or
+* to only one VFD buffer.
+*
+* Return: Address of "allocated" buffer, if successful. Otherwise, it returns
+* NULL.
+*
+* Programmer: Christian Chilan
+*
+* Date: October 3, 2011
+*
+*-------------------------------------------------------------------------
+*/
+static void *
+image_malloc(size_t size, H5FD_file_image_op_t file_image_op, void *_udata)
+{
+ H5LT_file_image_ud_t *udata = (H5LT_file_image_ud_t *)_udata;
+ void * return_value = NULL;
+
+ /* callback is only used if the application buffer is not actually copied */
+ if (!(udata->flags & H5LT_FILE_IMAGE_DONT_COPY))
+ goto out;
+
+ switch ( file_image_op ) {
+ /* the app buffer is "copied" to only one FAPL. Afterwards, FAPLs can be "copied" */
+ case H5FD_FILE_IMAGE_OP_PROPERTY_LIST_SET:
+ if (udata->app_image_ptr == NULL)
+ goto out;
+ if (udata->app_image_size != size)
+ goto out;
+ if (udata->fapl_image_ptr != NULL)
+ goto out;
+ if (udata->fapl_image_size != 0)
+ goto out;
+ if (udata->fapl_ref_count != 0)
+ goto out;
+
+ udata->fapl_image_ptr = udata->app_image_ptr;
+ udata->fapl_image_size = udata->app_image_size;
+ return_value = udata->fapl_image_ptr;
+ udata->fapl_ref_count++;
+ break;
+
+ case H5FD_FILE_IMAGE_OP_PROPERTY_LIST_COPY:
+ if (udata->fapl_image_ptr == NULL)
+ goto out;
+ if (udata->fapl_image_size != size)
+ goto out;
+ if (udata->fapl_ref_count == 0)
+ goto out;
+ return_value = udata->fapl_image_ptr;
+ udata->fapl_ref_count++;
+ break;
+
+ case H5FD_FILE_IMAGE_OP_PROPERTY_LIST_GET:
+ goto out;
+
+ case H5FD_FILE_IMAGE_OP_FILE_OPEN:
+ /* FAPL buffer is "copied" to only one VFD buffer */
+ if (udata->vfd_image_ptr != NULL)
+ goto out;
+ if (udata->vfd_image_size != 0)
+ goto out;
+ if (udata->vfd_ref_count != 0)
+ goto out;
+ if (udata->fapl_image_ptr == NULL)
+ goto out;
+ if (udata->fapl_image_size != size)
+ goto out;
+ if (udata->fapl_ref_count == 0)
+ goto out;
+
+ udata->vfd_image_ptr = udata->fapl_image_ptr;
+ udata->vfd_image_size = size;
+ udata->vfd_ref_count++;
+ return_value = udata->vfd_image_ptr;
+ break;
+
+ /* added unused labels to shut the compiler up */
+ case H5FD_FILE_IMAGE_OP_NO_OP:
+ case H5FD_FILE_IMAGE_OP_PROPERTY_LIST_CLOSE:
+ case H5FD_FILE_IMAGE_OP_FILE_RESIZE:
+ case H5FD_FILE_IMAGE_OP_FILE_CLOSE:
+ default:
+ goto out;
+ } /* end switch */
+
+ return(return_value);
+
+out:
+ return NULL;
+} /* end image_malloc() */
+
+
+/*-------------------------------------------------------------------------
+* Function: image_memcpy
+*
+* Purpose: Simulates memcpy() function to avoid copying file images.
+* The image buffer can be set to only one FAPL buffer, and
+* "copied" to only one VFD buffer. The FAPL buffer can be
+* "copied" to other FAPLs buffers.
+*
+* Return: The address of the destination buffer, if successful. Otherwise, it
+* returns NULL.
+*
+* Programmer: Christian Chilan
+*
+* Date: October 3, 2011
+*
+*-------------------------------------------------------------------------
+*/
+static void *
+image_memcpy(void *dest, const void *src, size_t size, H5FD_file_image_op_t file_image_op,
+ void *_udata)
+{
+ H5LT_file_image_ud_t *udata = (H5LT_file_image_ud_t *)_udata;
+
+ /* callback is only used if the application buffer is not actually copied */
+ if (!(udata->flags & H5LT_FILE_IMAGE_DONT_COPY))
+ goto out;
+
+ switch(file_image_op) {
+ case H5FD_FILE_IMAGE_OP_PROPERTY_LIST_SET:
+ if (dest != udata->fapl_image_ptr)
+ goto out;
+ if (src != udata->app_image_ptr)
+ goto out;
+ if (size != udata->fapl_image_size)
+ goto out;
+ if (size != udata->app_image_size)
+ goto out;
+ if (udata->fapl_ref_count == 0)
+ goto out;
+ break;
+
+ case H5FD_FILE_IMAGE_OP_PROPERTY_LIST_COPY:
+ if (dest != udata->fapl_image_ptr)
+ goto out;
+ if (src != udata->fapl_image_ptr)
+ goto out;
+ if (size != udata->fapl_image_size)
+ goto out;
+ if (udata->fapl_ref_count < 2)
+ goto out;
+ break;
+
+ case H5FD_FILE_IMAGE_OP_PROPERTY_LIST_GET:
+ goto out;
+
+ case H5FD_FILE_IMAGE_OP_FILE_OPEN:
+ if (dest != udata->vfd_image_ptr)
+ goto out;
+ if (src != udata->fapl_image_ptr)
+ goto out;
+ if (size != udata->vfd_image_size)
+ goto out;
+ if (size != udata->fapl_image_size)
+ goto out;
+ if (udata->fapl_ref_count == 0)
+ goto out;
+ if (udata->vfd_ref_count != 1)
+ goto out;
+ break;
+
+ /* added unused labels to shut the compiler up */
+ case H5FD_FILE_IMAGE_OP_NO_OP:
+ case H5FD_FILE_IMAGE_OP_PROPERTY_LIST_CLOSE:
+ case H5FD_FILE_IMAGE_OP_FILE_RESIZE:
+ case H5FD_FILE_IMAGE_OP_FILE_CLOSE:
+ default:
+ goto out;
+ } /* end switch */
+
+ return(dest);
+
+out:
+ return NULL;
+} /* end image_memcpy() */
+
+
+/*-------------------------------------------------------------------------
+* Function: image_realloc
+*
+* Purpose: Reallocates the shared application image buffer and updates data
+* structures that manage buffer "copying".
+*
+* Return: Address of reallocated buffer, if successful. Otherwise, it returns
+* NULL.
+*
+* Programmer: Christian Chilan
+*
+* Date: October 3, 2011
+*
+*-------------------------------------------------------------------------
+*/
+static void *
+image_realloc(void *ptr, size_t size, H5FD_file_image_op_t file_image_op, void *_udata)
+{
+ H5LT_file_image_ud_t *udata = (H5LT_file_image_ud_t *)_udata;
+ void * return_value = NULL;
+
+ /* callback is only used if the application buffer is not actually copied */
+ if (!(udata->flags & H5LT_FILE_IMAGE_DONT_COPY))
+ goto out;
+
+ /* realloc() is not allowed when the HDF5 library won't release the image
+ buffer because reallocation may change the address of the buffer. The
+ new address cannot be communicated to the application to release it. */
+ if (udata->flags & H5LT_FILE_IMAGE_DONT_RELEASE)
+ goto out;
+
+ /* realloc() is not allowed if the image is open in read-only mode */
+ if (!(udata->flags & H5LT_FILE_IMAGE_OPEN_RW))
+ goto out;
+
+ if (file_image_op == H5FD_FILE_IMAGE_OP_FILE_RESIZE) {
+ if (udata->vfd_image_ptr != ptr)
+ goto out;
+
+ if (udata->vfd_ref_count != 1)
+ goto out;
+
+ if (NULL == (udata->vfd_image_ptr = HDrealloc(ptr, size)))
+ goto out;
+
+ udata->vfd_image_size = size;
+ return_value = udata->vfd_image_ptr;
+ } /* end if */
+ else
+ goto out;
+
+ return(return_value);
+
+out:
+ return NULL;
+} /* end image_realloc() */
+
+
+/*-------------------------------------------------------------------------
+* Function: image_free
+*
+* Purpose: Simulates deallocation of FAPL and VFD buffers by decreasing
+* reference counters. Shared application buffer is actually
+* deallocated if there are no outstanding references.
+*
+* Return: SUCCEED or FAIL
+*
+* Programmer: Christian Chilan
+*
+* Date: October 3, 2011
+*
+*-------------------------------------------------------------------------
+*/
+static herr_t
+image_free(void *ptr, H5FD_file_image_op_t file_image_op, void *_udata)
+{
+ H5LT_file_image_ud_t *udata = (H5LT_file_image_ud_t *)_udata;
+
+ /* callback is only used if the application buffer is not actually copied */
+ if (!(udata->flags & H5LT_FILE_IMAGE_DONT_COPY))
+ goto out;
+
+ switch(file_image_op) {
+ case H5FD_FILE_IMAGE_OP_PROPERTY_LIST_CLOSE:
+ if (udata->fapl_image_ptr != ptr)
+ goto out;
+ if (udata->fapl_ref_count == 0)
+ goto out;
+
+ udata->fapl_ref_count--;
+
+ /* release the shared buffer only if indicated by the respective flag and there are no outstanding references */
+ if (udata->fapl_ref_count == 0 && udata->vfd_ref_count == 0 &&
+ !(udata->flags & H5LT_FILE_IMAGE_DONT_RELEASE)) {
+ HDfree(udata->fapl_image_ptr);
+ udata->app_image_ptr = NULL;
+ udata->fapl_image_ptr = NULL;
+ udata->vfd_image_ptr = NULL;
+ } /* end if */
+ break;
+
+ case H5FD_FILE_IMAGE_OP_FILE_CLOSE:
+ if (udata->vfd_image_ptr != ptr)
+ goto out;
+ if (udata->vfd_ref_count != 1)
+ goto out;
+
+ udata->vfd_ref_count--;
+
+ /* release the shared buffer only if indicated by the respective flag and there are no outstanding references */
+ if (udata->fapl_ref_count == 0 && udata->vfd_ref_count == 0 &&
+ !(udata->flags & H5LT_FILE_IMAGE_DONT_RELEASE)) {
+ HDfree(udata->vfd_image_ptr);
+ udata->app_image_ptr = NULL;
+ udata->fapl_image_ptr = NULL;
+ udata->vfd_image_ptr = NULL;
+ } /* end if */
+ break;
+
+ /* added unused labels to keep the compiler quite */
+ case H5FD_FILE_IMAGE_OP_NO_OP:
+ case H5FD_FILE_IMAGE_OP_PROPERTY_LIST_SET:
+ case H5FD_FILE_IMAGE_OP_PROPERTY_LIST_COPY:
+ case H5FD_FILE_IMAGE_OP_PROPERTY_LIST_GET:
+ case H5FD_FILE_IMAGE_OP_FILE_OPEN:
+ case H5FD_FILE_IMAGE_OP_FILE_RESIZE:
+ default:
+ goto out;
+ } /* end switch */
+
+ return(SUCCEED);
+
+out:
+ return(FAIL);
+} /* end image_free() */
+
+
+/*-------------------------------------------------------------------------
+* Function: udata_copy
+*
+* Purpose: Simulates the copying of the user data structure utilized in the
+* management of the "copying" of file images.
+*
+* Return: Address of "newly allocated" structure, if successful. Otherwise, it
+* returns NULL.
+*
+* Programmer: Christian Chilan
+*
+* Date: October 3, 2011
+*
+*-------------------------------------------------------------------------
+*/
+static void *
+udata_copy(void *_udata)
+{
+ H5LT_file_image_ud_t *udata = (H5LT_file_image_ud_t *)_udata;
+
+ /* callback is only used if the application buffer is not actually copied */
+ if (!(udata->flags & H5LT_FILE_IMAGE_DONT_COPY))
+ goto out;
+ if (udata->ref_count == 0)
+ goto out;
+
+ udata->ref_count++;
+
+ return(udata);
+
+out:
+ return NULL;
+} /* end udata_copy */
+
+
+/*-------------------------------------------------------------------------
+* Function: udata_free
+*
+* Purpose: Simulates deallocation of the user data structure utilized in the
+* management of the "copying" of file images. The data structure is
+* actually deallocated when there are no outstanding references.
+*
+* Return: SUCCEED or FAIL
+*
+* Programmer: Christian Chilan
+*
+* Date: October 3, 2011
+*
+*-------------------------------------------------------------------------
+*/
+static herr_t
+udata_free(void *_udata)
+{
+ H5LT_file_image_ud_t *udata = (H5LT_file_image_ud_t *)_udata;
+
+ /* callback is only used if the application buffer is not actually copied */
+ if (!(udata->flags & H5LT_FILE_IMAGE_DONT_COPY))
+ goto out;
+ if (udata->ref_count == 0)
+ goto out;
+
+ udata->ref_count--;
+
+ /* checks that there are no references outstanding before deallocating udata */
+ if (udata->ref_count == 0 && udata->fapl_ref_count == 0 &&
+ udata->vfd_ref_count == 0)
+ HDfree(udata);
+
+ return(SUCCEED);
+
+out:
+ return(FAIL);
+} /* end udata_free */
+
+/* End of callbacks definitions for file image operations */
/*-------------------------------------------------------------------------
*
@@ -388,6 +843,120 @@ out:
return -1;
}
+
+/*-------------------------------------------------------------------------
+* Function: H5LTopen_file_image
+*
+* Purpose: Open a user supplied file image using the core file driver.
+*
+* Return: File identifier, Failure: -1
+*
+* Programmer: Christian Chilan
+*
+* Date: October 3, 2011
+*
+*-------------------------------------------------------------------------
+*/
+hid_t H5LTopen_file_image(void *buf_ptr, size_t buf_size, unsigned flags)
+{
+ hid_t fapl, file_id; /* HDF5 identifiers */
+ unsigned file_open_flags;/* Flags for image open */
+ char file_name[64]; /* Filename buffer */
+ size_t alloc_incr; /* Buffer allocation increment */
+ size_t min_incr = 65536; /* Minimum buffer increment */
+ double buf_prcnt = 0.1f; /* Percentage of buffer size to set
+ as increment */
+ static long file_name_counter;
+ H5FD_file_image_callbacks_t callbacks = {&image_malloc, &image_memcpy,
+ &image_realloc, &image_free,
+ &udata_copy, &udata_free,
+ (void *)NULL};
+
+ /* check arguments */
+ if (buf_ptr == NULL)
+ goto out;
+ if (buf_size == 0)
+ goto out;
+ if (flags & (unsigned)~(H5LT_FILE_IMAGE_ALL))
+ goto out;
+
+ /* Create FAPL to transmit file image */
+ if ((fapl = H5Pcreate(H5P_FILE_ACCESS)) < 0)
+ goto out;
+
+ /* set allocation increment to a percentage of the supplied buffer size, or
+ * a pre-defined minimum increment value, whichever is larger
+ */
+ if ((buf_prcnt * buf_size) > min_incr)
+ alloc_incr = (size_t)(buf_prcnt * buf_size);
+ else
+ alloc_incr = min_incr;
+
+ /* Configure FAPL to use the core file driver */
+ if (H5Pset_fapl_core(fapl, alloc_incr, FALSE) < 0)
+ goto out;
+
+ /* Set callbacks for file image ops ONLY if the file image is NOT copied */
+ if (flags & H5LT_FILE_IMAGE_DONT_COPY) {
+ H5LT_file_image_ud_t *udata; /* Pointer to udata structure */
+
+ /* Allocate buffer to communicate user data to callbacks */
+ if (NULL == (udata = (H5LT_file_image_ud_t *)HDmalloc(sizeof(H5LT_file_image_ud_t))))
+ goto out;
+
+ /* Initialize udata with info about app buffer containing file image and flags */
+ udata->app_image_ptr = buf_ptr;
+ udata->app_image_size = buf_size;
+ udata->fapl_image_ptr = NULL;
+ udata->fapl_image_size = 0;
+ udata->fapl_ref_count = 0;
+ udata->vfd_image_ptr = NULL;
+ udata->vfd_image_size = 0;
+ udata->vfd_ref_count = 0;
+ udata->flags = flags;
+ udata->ref_count = 1; /* corresponding to the first FAPL */
+
+ /* copy address of udata into callbacks */
+ callbacks.udata = (void *)udata;
+
+ /* Set file image callbacks */
+ if (H5Pset_file_image_callbacks(fapl, &callbacks) < 0) {
+ HDfree(udata);
+ goto out;
+ } /* end if */
+ } /* end if */
+
+ /* Assign file image in user buffer to FAPL */
+ if (H5Pset_file_image(fapl, buf_ptr, buf_size) < 0)
+ goto out;
+
+ /* set file open flags */
+ if (flags & H5LT_FILE_IMAGE_OPEN_RW)
+ file_open_flags = H5F_ACC_RDWR;
+ else
+ file_open_flags = H5F_ACC_RDONLY;
+
+ /* define a unique file name */
+ snprintf(file_name, (sizeof(file_name) - 1), "file_image_%ld", file_name_counter++);
+
+ /* Assign file image in FAPL to the core file driver */
+ if ((file_id = H5Fopen(file_name, file_open_flags, fapl)) < 0)
+ goto out;
+
+ /* Close FAPL */
+ if (H5Pclose(fapl) < 0)
+ goto out;
+
+ /* Return file identifier */
+ return file_id;
+
+out:
+ H5E_BEGIN_TRY {
+ H5Pclose(fapl);
+ } H5E_END_TRY;
+ return -1;
+} /* end H5LTopen_file_image() */
+
/*-------------------------------------------------------------------------
* Function: H5LT_read_dataset
@@ -1801,7 +2370,7 @@ print_enum(hid_t type, char* str, size_t *str_len, hbool_t no_ubuf, size_t indt)
out:
if(0 == nmembs) {
- HDsnprintf(tmp_str, TMP_LEN, "\n%*s <empty>", indt + 4, "");
+ HDsnprintf(tmp_str, TMP_LEN, "\n%*s <empty>", (int)(indt + 4), "");
str = realloc_and_append(no_ubuf, str_len, str, tmp_str);
} /* end if */
diff --git a/hl/src/H5LTpublic.h b/hl/src/H5LTpublic.h
index 6efae68..929c6bd 100644
--- a/hl/src/H5LTpublic.h
+++ b/hl/src/H5LTpublic.h
@@ -16,6 +16,15 @@
#ifndef _H5LTpublic_H
#define _H5LTpublic_H
+/* Flag definitions for H5LTopen_file_image() */
+#define H5LT_FILE_IMAGE_OPEN_RW 0x0001 /* Open image for read-write */
+#define H5LT_FILE_IMAGE_DONT_COPY 0x0002 /* The HDF5 lib won't copy */
+/* user supplied image buffer. The same image is open with the core driver. */
+#define H5LT_FILE_IMAGE_DONT_RELEASE 0x0004 /* The HDF5 lib won't */
+/* deallocate user supplied image buffer. The user application is reponsible */
+/* for doing so. */
+#define H5LT_FILE_IMAGE_ALL 0x0007
+
typedef enum H5LT_lang_t {
H5LT_LANG_ERR = -1, /*this is the first*/
H5LT_DDL = 0, /*for DDL*/
@@ -344,6 +353,15 @@ H5_HLDLL herr_t H5LTfind_attribute( hid_t loc_id, const char *name );
H5_HLDLL htri_t H5LTpath_valid(hid_t loc_id, const char *path, hbool_t check_object_valid);
+/*-------------------------------------------------------------------------
+ *
+ * File image operations functions
+ *
+ *-------------------------------------------------------------------------
+ */
+
+H5_HLDLL hid_t H5LTopen_file_image(void *buf_ptr, size_t buf_size, unsigned flags);
+
#ifdef __cplusplus
}
#endif
diff --git a/hl/test/Makefile.am b/hl/test/Makefile.am
index 86e3318..76c6f90 100644
--- a/hl/test/Makefile.am
+++ b/hl/test/Makefile.am
@@ -29,7 +29,7 @@ LDADD=$(LIBH5_HL) $(LIBH5TEST) $(LIBHDF5)
# Test programs. These are our main targets. They should be listed in the
# order to be executed, generally most specific tests to least specific tests.
-TEST_PROG=test_lite test_image test_table test_ds test_packet
+TEST_PROG=test_lite test_image test_file_image test_table test_ds test_packet
check_PROGRAMS=$(TEST_PROG)
# These programs generate test files for the tests. They don't need to be
@@ -45,7 +45,7 @@ endif
# Temporary files. These files are the ones created by running `make test'.
CHECK_CLEANFILES+=combine_tables[1-2].h5 test_ds[1-9].h5 test_image[1-3].h5 \
- test_lite[1-2].h5 test_table.h5 test_packet_table.h5 \
+ file_img[1-2].h5 test_lite[1-2].h5 test_table.h5 test_packet_table.h5 \
test_packet_compress.h5 test_detach.h5
include $(top_srcdir)/config/conclude.am
diff --git a/hl/test/Makefile.in b/hl/test/Makefile.in
index 6aa5a2a..b7548ec 100644
--- a/hl/test/Makefile.in
+++ b/hl/test/Makefile.in
@@ -69,7 +69,8 @@ CONFIG_HEADER = $(top_builddir)/src/H5config.h
CONFIG_CLEAN_FILES = H5srcdir_str.h
CONFIG_CLEAN_VPATH_FILES =
am__EXEEXT_1 = test_lite$(EXEEXT) test_image$(EXEEXT) \
- test_table$(EXEEXT) test_ds$(EXEEXT) test_packet$(EXEEXT)
+ test_file_image$(EXEEXT) test_table$(EXEEXT) test_ds$(EXEEXT) \
+ test_packet$(EXEEXT)
am__EXEEXT_2 = gen_test_ds$(EXEEXT)
PROGRAMS = $(noinst_PROGRAMS)
gen_test_ds_SOURCES = gen_test_ds.c
@@ -83,6 +84,10 @@ test_ds_SOURCES = test_ds.c
test_ds_OBJECTS = test_ds.$(OBJEXT)
test_ds_LDADD = $(LDADD)
test_ds_DEPENDENCIES = $(LIBH5_HL) $(LIBH5TEST) $(LIBHDF5)
+test_file_image_SOURCES = test_file_image.c
+test_file_image_OBJECTS = test_file_image.$(OBJEXT)
+test_file_image_LDADD = $(LDADD)
+test_file_image_DEPENDENCIES = $(LIBH5_HL) $(LIBH5TEST) $(LIBHDF5)
test_image_SOURCES = test_image.c
test_image_OBJECTS = test_image.$(OBJEXT)
test_image_LDADD = $(LDADD)
@@ -125,10 +130,10 @@ am__v_CCLD_0 = @echo " CCLD " $@;
AM_V_GEN = $(am__v_GEN_$(V))
am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY))
am__v_GEN_0 = @echo " GEN " $@;
-SOURCES = gen_test_ds.c test_ds.c test_image.c test_lite.c \
- test_packet.c test_table.c
-DIST_SOURCES = gen_test_ds.c test_ds.c test_image.c test_lite.c \
- test_packet.c test_table.c
+SOURCES = gen_test_ds.c test_ds.c test_file_image.c test_image.c \
+ test_lite.c test_packet.c test_table.c
+DIST_SOURCES = gen_test_ds.c test_ds.c test_file_image.c test_image.c \
+ test_lite.c test_packet.c test_table.c
ETAGS = etags
CTAGS = ctags
am__tty_colors = \
@@ -422,16 +427,16 @@ TRACE = perl $(top_srcdir)/bin/trace
# Temporary files. These files are the ones created by running `make test'.
CHECK_CLEANFILES = *.chkexe *.chklog *.clog combine_tables[1-2].h5 \
- test_ds[1-9].h5 test_image[1-3].h5 test_lite[1-2].h5 \
- test_table.h5 test_packet_table.h5 test_packet_compress.h5 \
- test_detach.h5
+ test_ds[1-9].h5 test_image[1-3].h5 file_img[1-2].h5 \
+ test_lite[1-2].h5 test_table.h5 test_packet_table.h5 \
+ test_packet_compress.h5 test_detach.h5
# The tests depend on the hdf5, hdf5 test, and hdf5_hl libraries
LDADD = $(LIBH5_HL) $(LIBH5TEST) $(LIBHDF5)
# Test programs. These are our main targets. They should be listed in the
# order to be executed, generally most specific tests to least specific tests.
-TEST_PROG = test_lite test_image test_table test_ds test_packet
+TEST_PROG = test_lite test_image test_file_image test_table test_ds test_packet
# These programs generate test files for the tests. They don't need to be
# compiled every time we want to test the library. However, putting
@@ -515,6 +520,9 @@ gen_test_ds$(EXEEXT): $(gen_test_ds_OBJECTS) $(gen_test_ds_DEPENDENCIES)
test_ds$(EXEEXT): $(test_ds_OBJECTS) $(test_ds_DEPENDENCIES)
@rm -f test_ds$(EXEEXT)
$(AM_V_CCLD)$(LINK) $(test_ds_OBJECTS) $(test_ds_LDADD) $(LIBS)
+test_file_image$(EXEEXT): $(test_file_image_OBJECTS) $(test_file_image_DEPENDENCIES)
+ @rm -f test_file_image$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(test_file_image_OBJECTS) $(test_file_image_LDADD) $(LIBS)
test_image$(EXEEXT): $(test_image_OBJECTS) $(test_image_DEPENDENCIES)
@rm -f test_image$(EXEEXT)
$(AM_V_CCLD)$(LINK) $(test_image_OBJECTS) $(test_image_LDADD) $(LIBS)
@@ -536,6 +544,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gen_test_ds.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_ds.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_file_image.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_image.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_lite.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_packet.Po@am__quote@
diff --git a/hl/test/h5hltest.h b/hl/test/h5hltest.h
index 466a0e1..809c4ec 100644
--- a/hl/test/h5hltest.h
+++ b/hl/test/h5hltest.h
@@ -23,9 +23,6 @@
#ifndef _H5HLTEST_H
#define _H5HLTEST_H
-/* Get the HDF5 public header */
-#include "hdf5.h"
-
/* Get the HDF5 test header */
#include "h5test.h"
@@ -36,5 +33,8 @@
#define TESTING2(WHAT) {printf("%-70s", "Testing " WHAT); fflush(stdout);}
#define TESTING3(WHAT) {printf("%-70s", "" WHAT); fflush(stdout);}
+/* Implrements verbose 'assert' with 'goto error' exit */
+#define VERIFY(condition, string) do { if (!(condition)) FAIL_PUTS_ERROR(string) } while(0)
+
#endif /* _H5HLTEST_H */
diff --git a/hl/test/test_file_image.c b/hl/test/test_file_image.c
new file mode 100644
index 0000000..9729421
--- /dev/null
+++ b/hl/test/test_file_image.c
@@ -0,0 +1,518 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+* 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. *
+* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+#include "h5hltest.h"
+#include "H5LTpublic.h"
+
+#define DSET_NAME "dset"
+
+#define RANK 2
+
+/* Test of file image operations.
+
+ The following code provides a means to thoroughly test the file image
+ operations. Main objectives are testing operations with multiple open
+ images and using all possible flag combinations, which are set in the
+ main calling routine. Since the number of open images and flag combinations
+ may differ, the flag combinations are assigned to the images in round-robin
+ fashion. In order to simulate a realistic operation environment, the code
+ operates on as many open objects as possible by using several for-loops
+ instead of using a single loop that opens image i, accesses it, and closes
+ it. The first loop creates the files and obtains images using the function
+ H5Fget_file_image(); two images are set incorrectly (one image is filled
+ with "wrong" data while the other image is not valid). The second loop opens
+ the images using the function H5LTopen_file_image(), and test whether the
+ images have been copied in accordance to the H5LT_FILE_IMAGE_DONT_COPY flag.
+ The third loop reads the open images and verifies that the contents are
+ correct. The fourth loop first perform writes in the images that do not
+ extend the image, and then performs writes that extend the images. The fifth
+ loop reads the extended images and verify that the content are correct. The
+ sixth and final loop closes the file images and deallocates the image
+ buffers if appropriate. */
+
+/*-------------------------------------------------------------------------
+* test file image operations
+*-------------------------------------------------------------------------
+*/
+static int
+test_file_image(size_t open_images, size_t nflags, unsigned *flags)
+{
+ hid_t *file_id, *dset_id, file_space, plist; /* HDF5 ids */
+ hsize_t dims1[RANK] = {2,3}; /* original dimension of datasets */
+ hsize_t max_dims[RANK] = {H5S_UNLIMITED, H5S_UNLIMITED};
+ int data1[6] = {1,2,3,4,5,6}; /* original contents of dataset */
+ int data2[6] = {7,8,9,10,11,12}; /* "wrong" contents of dataset */
+ hsize_t dims3[RANK]; /* array to read dataset dimensions */
+ int data3[15]; /* array to read dataset contents */
+ hsize_t dims4[RANK] = {3,5}; /* extended dimensions of datasets */
+ int data4[15] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
+ /* extended contents of dataset */
+ ssize_t *buf_size; /* pointer to array of buffer sizes */
+ void **buf_ptr; /* pointer to array of pointers to image buffers */
+ char **filename; /* pointer to array of pointers to filenames */
+ unsigned *input_flags; /* pointer to array of flag combinations */
+ size_t i, j, k, nrow, n_values;
+ herr_t status1;
+ void *handle_ptr = NULL; /* pointers to driver buffer */
+ unsigned char **core_buf_ptr_ptr = NULL;
+
+ VERIFY(open_images > 1 , "The number of open images must be greater than 1");
+
+ VERIFY(nflags > 0, "The number of flag combinations must be greater than 0");
+
+ /* allocate array of flags for open images */
+ if (NULL == (input_flags = (unsigned *)HDmalloc(sizeof(unsigned) * open_images)))
+ FAIL_PUTS_ERROR("malloc() failed");
+
+ /* allocate array of pointers for each of the open images */
+ if (NULL == (buf_ptr = (void **)malloc(sizeof(void *) * open_images)))
+ FAIL_PUTS_ERROR("malloc() failed");
+
+ /* allocate array to store the name of each of the open images */
+ if (NULL == (filename = (char **)malloc(sizeof(char *) * open_images)))
+ FAIL_PUTS_ERROR("malloc() failed");
+
+ /* allocate array to store the size of each of the open images */
+ if (NULL == (buf_size = (ssize_t *)malloc(sizeof(ssize_t) * open_images)))
+ FAIL_PUTS_ERROR("malloc() failed");
+
+ /* allocate array for each of the file identifiers */
+ if (NULL == (file_id = (hid_t *)malloc(sizeof(hid_t) * open_images)))
+ FAIL_PUTS_ERROR("malloc() failed");
+
+ /* allocate array for each of the dataset identifiers */
+ if (NULL == (dset_id = (hid_t *)malloc(sizeof(hid_t) * open_images)))
+ FAIL_PUTS_ERROR("malloc() failed");
+
+ TESTING("get file images");
+
+ /* create several file images */
+ for (i = 0; i < open_images; i++) {
+
+ /* populate array for flags combinations */
+ input_flags[i] = flags[(nflags + i) % nflags];
+
+ /* allocate name buffer for image i */
+ filename[i] = (char *)HDmalloc(sizeof(char) * 32);
+
+ /* create file name */
+ sprintf(filename[i], "image_file%d.h5", (int)i);
+
+ /* create file */
+ if ((file_id[i] = H5Fcreate(filename[i], H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT)) < 0)
+ FAIL_PUTS_ERROR("H5Fcreate() failed");
+
+ /* define dataspace for the dataset */
+ if ((file_space = H5Screate_simple(RANK, dims1, max_dims)) < 0)
+ FAIL_PUTS_ERROR("H5Screate_simple() failed");
+
+ /* create dataset property list */
+ if ((plist = H5Pcreate(H5P_DATASET_CREATE)) < 0)
+ FAIL_PUTS_ERROR("H5Pcreate() failed");
+
+ /* set property list to create chunked dataset */
+ if (H5Pset_chunk(plist, RANK, dims1) < 0)
+ FAIL_PUTS_ERROR("H5Pset_chunk() failed");
+
+ /* create and write an integer type dataset named "dset" */
+ if ((dset_id[i] = H5Dcreate2(file_id[i], DSET_NAME, H5T_NATIVE_INT, file_space, H5P_DEFAULT, plist, H5P_DEFAULT)) < 0)
+ FAIL_PUTS_ERROR("H5Dcreate() failed");
+
+ /* dataset in open image 1 is written with "wrong" data */
+ if (i == 1) {
+ if (H5Dwrite(dset_id[i], H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, data2) < 0)
+ FAIL_PUTS_ERROR("H5Dwrite() failed");
+ } /* end if*/
+ /* dataset in the rest of the open images is written with correct data */
+ else {
+ if (H5Dwrite(dset_id[i], H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, data1) < 0)
+ FAIL_PUTS_ERROR("H5Dwrite() failed");
+ } /* end else */
+
+ /* flush into the file */
+ if (H5Fflush(file_id[i], H5F_SCOPE_LOCAL) < 0)
+ FAIL_PUTS_ERROR("H5Fflush() failed");
+
+ /* close dataset property list */
+ if (H5Pclose(plist) < 0)
+ FAIL_PUTS_ERROR("H5Pclose() failed");
+
+ /* close dataspace */
+ if (H5Sclose(file_space) < 0)
+ FAIL_PUTS_ERROR("H5Sclose() failed");
+
+ /* close dataset */
+ if (H5Dclose(dset_id[i]) < 0)
+ FAIL_PUTS_ERROR("H5Dclose() failed");
+
+ /* get size of the file image i */
+ if ((buf_size[i] = H5Fget_file_image(file_id[i], NULL, 0)) < 0)
+ FAIL_PUTS_ERROR("H5Fget_file_image() failed");
+
+ /* allocate buffer for the file image i */
+ if (NULL == (buf_ptr[i] = (void *)HDmalloc((size_t)buf_size[i])))
+ FAIL_PUTS_ERROR("malloc() failed");
+
+ /* buffer for file image 2 is filled with counter data (non-valid image) */
+ if (i == 2) {
+ for (j = 0; j < (size_t)buf_size[i]; j++)
+ ((char*)(buf_ptr[i]))[j] = (char)j;
+ } /* end if */
+ /* buffers for the rest of the file images are filled with data from the respective files */
+ else {
+ if ((buf_size[i] = H5Fget_file_image(file_id[i], buf_ptr[i], (size_t)buf_size[i])) < 0)
+ FAIL_PUTS_ERROR("H5Fget_file_image() failed");
+ } /* end else */
+
+ /* file close */
+ if (H5Fclose (file_id[i]) < 0)
+ FAIL_PUTS_ERROR("H5Fclose() failed");
+ } /* end for */
+
+ PASSED();
+
+ TESTING("open file images and check image copies");
+
+ /* open the file images with the core driver for data access */
+ for (i = 0; i < open_images; i++) {
+ /* open file image 2 filled with counter data (non-valid image) */
+ if (i == 2) {
+ H5E_BEGIN_TRY {
+ /* attempt to set file image in the core driver */
+ file_id[i] = H5LTopen_file_image(buf_ptr[i], (size_t)buf_size[i], input_flags[i]);
+ } H5E_END_TRY
+
+ VERIFY(file_id[i] < 0, "H5LTopen_file_image() should have failed");
+ } /* end if */
+ /* open rest of valid file images */
+ else {
+ /* set file image in the core driver */
+ if ((file_id[i] = H5LTopen_file_image(buf_ptr[i], (size_t)buf_size[i], input_flags[i])) < 0)
+ FAIL_PUTS_ERROR("H5LTopen_file_image() failed");
+
+ /* get pointer to the image buffer of the core driver */
+ if (H5Fget_vfd_handle(file_id[i], H5P_DEFAULT, &handle_ptr) < 0)
+ FAIL_PUTS_ERROR("H5Fget_vfd_handle() failed");
+
+ core_buf_ptr_ptr = (unsigned char **)handle_ptr;
+
+ /* test whether the user buffer has been copied or not */
+ if (input_flags[i] & H5LT_FILE_IMAGE_DONT_COPY)
+ VERIFY(*core_buf_ptr_ptr == buf_ptr[i], "vfd buffer and user buffer should have been the same");
+ else
+ VERIFY(*core_buf_ptr_ptr != buf_ptr[i], "vfd buffer and user buffer should be different");
+
+ /* test whether the contents of the user buffer and driver buffer */
+ /* are equal. */
+ if (HDmemcmp(*core_buf_ptr_ptr, buf_ptr[i], (size_t)buf_size[i]) != 0)
+ FAIL_PUTS_ERROR("comparison of vfd and user buffer failed");
+ } /* end else */
+ } /* end for */
+
+ PASSED();
+
+ TESTING("read file images");
+
+ /* read open file images and verify data */
+ for (i = 0; i < open_images; i++) {
+ /* if opening the file image failed, continue next iteration */
+ if (file_id[i] < 0) {
+ HDassert(i == 2);
+ continue;
+ } /* end if */
+
+ /* open dataset in file image */
+ if ((dset_id[i] = H5Dopen2(file_id[i], DSET_NAME, H5P_DEFAULT)) < 0)
+ FAIL_PUTS_ERROR("H5Dopen() failed");
+
+ /* get dataspace for the dataset */
+ if ((file_space = H5Dget_space(dset_id[i])) < 0)
+ FAIL_PUTS_ERROR("H5Dget_space() failed");
+
+ /* get dimensions for the dataset */
+ if (H5Sget_simple_extent_dims(file_space, dims3, NULL) < 0)
+ FAIL_PUTS_ERROR("H5Sget_simple_extent_dims() failed");
+
+ /* read dataset */
+ if (H5Dread(dset_id[i], H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, data3) < 0)
+ FAIL_PUTS_ERROR("H5Dread() failed");
+
+ /* compute number of elements in dataset */
+ n_values = (size_t)(dims3[0] * dims3[1]);
+
+ /* determine the number of rows in dataset */
+ nrow = (size_t)dims3[1];
+
+ /* verify contents for file image 1 with "wrong" data */
+ if (i == 1) {
+ /* compare file image values with original data */
+ for (j = 0; j < n_values / nrow; j++)
+ for (k = 0; k < nrow; k++)
+ if (data3[j * nrow + k ] == data1[j * nrow + k ])
+ FAIL_PUTS_ERROR("comparison of image values with original data should have failed");
+ } /* end if */
+ /* verify contents for the rest of the file images */
+ else {
+ /* compare file image values with original data */
+ for (j = 0; j < n_values / nrow; j++)
+ for (k = 0; k < nrow; k++)
+ if (data3[j * nrow + k ] != data1[j * nrow + k ])
+ FAIL_PUTS_ERROR("comparison of image values with original data failed");
+ } /* end else */
+
+ /* close dataspace */
+ if (H5Sclose (file_space) < 0)
+ FAIL_PUTS_ERROR("H5Sclose() failed");
+ } /* end for */
+
+ PASSED();
+
+ TESTING("write and extend file images");
+
+ /* write open file images and verify data */
+ for (i = 0; i < open_images; i++) {
+ /* if opening the file image failed, continue next iteration */
+ if (file_id[i] < 0) {
+ HDassert(i == 2);
+ continue;
+ } /* end if */
+
+ /* test data write when file image access is read-only */
+ if (!(input_flags[i] & H5LT_FILE_IMAGE_OPEN_RW)) {
+ /* write dataset without extending it */
+ H5E_BEGIN_TRY {
+ status1 = H5Dwrite(dset_id[i], H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, data1);
+ } H5E_END_TRY;
+
+ VERIFY(status1 < 0, "H5Dwrite() should have failed");
+
+ /* extend dimensions of dataset */
+ H5E_BEGIN_TRY {
+ status1 = H5Dset_extent(dset_id[i], dims4);
+ } H5E_END_TRY;
+
+ VERIFY(status1 < 0, "H5Dset_extent() should have failed");
+
+ /* write extended dataset */
+ H5E_BEGIN_TRY {
+ status1 = H5Dwrite(dset_id[i], H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, data4);
+ } H5E_END_TRY;
+
+ VERIFY(status1 < 0, "H5Dwrite() should have failed");
+
+ /* close dataset */
+ if (H5Dclose(dset_id[i]) < 0)
+ FAIL_PUTS_ERROR("H5Dclose() failed");
+ } /* end if */
+ /* test data write where file image access is read-write */
+ else {
+ if ((input_flags[i] & H5LT_FILE_IMAGE_DONT_COPY) && (input_flags[i] & H5LT_FILE_IMAGE_DONT_RELEASE)) {
+/* This test is disabled currently, since the new attribute causes the file
+ * to increase in size, but the realloc call in H5FD_core_write() fails, causing
+ * the flush operation to fail and the file to fail to close, eventually
+ * triggering the "infinite loop shutting down the library" problem.
+ *
+ * In theory, we could address this through a variety of methods, ranging from
+ * ignoring failures in H5F_dest() (when called from H5F_try_close()), to
+ * allocating space more aggressively when creating the attribute, etc.
+ *
+ * For now, we will just leave the test commented out and assume that
+ * application developers who mark their file image as "don't copy" won't
+ * be likely candidates for modifying their data. - QAK - March 29, 2012
+ */
+#if 0
+ int attr_rank = 1;
+ hsize_t attr_dims[] = {4096};
+ int attr_data[4096];
+ hid_t attr_space_id = -1;
+ hid_t attr_id = -1;
+ herr_t status2;
+ size_t l;
+
+ if ((attr_space_id = H5Screate_simple(attr_rank, attr_dims, attr_dims)) < 0)
+ FAIL_PUTS_ERROR("attr_space H5Screate_simple() failed");
+
+ if((attr_id = H5Acreate_by_name(dset_id[i], ".", "int array_addr", H5T_NATIVE_INT, attr_space_id, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0)
+ FAIL_PUTS_ERROR("H5Acreate_by_name() failed");
+
+ for(l = 0; l < 4096; l++)
+ attr_data[l] = (int)l;
+
+ /* write data to the attribute and then flush the file. One or the other should
+ * should trigger an extension to the EOA, which in turn should cause the realloc
+ * callback to fail.
+ */
+ H5E_BEGIN_TRY {
+ status1 = status2 = -1;
+
+ status1 = H5Awrite(attr_id, H5T_NATIVE_INT, (const void *)attr_data);
+ if(status1 >= 0)
+ status2 = H5Fflush(file_id[i], H5F_SCOPE_GLOBAL);
+
+ VERIFY(status1 < 0 || status2 < 0, "writing and flushing attr should have failed");
+ } H5E_END_TRY;
+
+ /* close attr and attr_space -- expect errors on close */
+ H5E_BEGIN_TRY {
+ H5Sclose(attr_space_id);
+ H5Aclose(attr_id);
+ } H5E_END_TRY;
+#endif
+ file_id[i] = -1;
+ } /* end if */
+ else {
+ /* write dataset without extending it */
+ if (H5Dwrite(dset_id[i], H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, data1) < 0)
+ FAIL_PUTS_ERROR("H5Dwrite() failed");
+
+ /* extend dimensions of dataset */
+ if (H5Dset_extent(dset_id[i], dims4) < 0)
+ FAIL_PUTS_ERROR("H5Dset_extent() failed");
+
+ /* write extended dataset */
+ if (H5Dwrite(dset_id[i], H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, data4) < 0)
+ FAIL_PUTS_ERROR("H5Dwrite() failed");
+
+ /* close dataset */
+ if (H5Dclose(dset_id[i]) < 0)
+ FAIL_PUTS_ERROR("H5Dclose() failed");
+ } /* end else */
+ } /* end else */
+ } /* end for */
+
+ PASSED();
+
+ TESTING("read extended file images");
+
+ /* read open file images and verify data */
+ for (i = 0; i < open_images; i++) {
+ /* if opening the file image failed, continue next iteration */
+ if ((file_id[i] < 0) || (!(input_flags[i] & H5LT_FILE_IMAGE_OPEN_RW )))
+ continue;
+
+ /* open dataset in file image */
+ if ((dset_id[i] = H5Dopen2(file_id[i], DSET_NAME, H5P_DEFAULT)) < 0)
+ FAIL_PUTS_ERROR("H5Dopen() failed");
+
+ /* get dataspace for the dataset */
+ if ((file_space = H5Dget_space(dset_id[i])) < 0)
+ FAIL_PUTS_ERROR("H5Dget_space() failed");
+
+ /* get dimensions for the dataset */
+ if (H5Sget_simple_extent_dims(file_space, dims3, NULL) < 0)
+ FAIL_PUTS_ERROR("H5Sget_simple_extent_dims() failed");
+
+ /* read dataset */
+ if (H5Dread(dset_id[i], H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, data3) < 0)
+ FAIL_PUTS_ERROR("H5Dread() failed");
+
+ /* compute number of elements in dataset */
+ n_values = (size_t)(dims3[0] * dims3[1]);
+
+ /* determine the number of rows in dataset */
+ nrow = (size_t)dims3[1];
+
+ /* verify contents for the file images */
+ for (j = 0; j < n_values / nrow; j++)
+ for (k = 0; k < nrow; k++)
+ if (data3[j * nrow + k ] != data4[j * nrow + k ])
+ FAIL_PUTS_ERROR("comparison of image values with original data failed");
+
+ /* close dataspace */
+ if (H5Sclose (file_space) < 0)
+ FAIL_PUTS_ERROR("H5Sclose() failed");
+
+ /* close dataset */
+ if (H5Dclose(dset_id[i]) < 0)
+ FAIL_PUTS_ERROR("H5Dclose() failed");
+ } /* end for */
+
+ PASSED()
+
+ TESTING("close file images");
+
+ /* close file images and release buffer if appropriate */
+ for (i = 0; i < open_images; i++) {
+ /* close file is appropriate */
+ if (file_id[i] >= 0) {
+ /* close file image */
+ if (H5Fclose(file_id[i]) < 0)
+ FAIL_PUTS_ERROR("H5Fclose() failed");
+ } /* end if */
+
+ /* delete test data files */
+ if (HDremove(filename[i]) < 0)
+ FAIL_PUTS_ERROR("HDremove() failed");
+
+ /* free shared buffer if appropriate */
+ if (!(input_flags[i] & H5LT_FILE_IMAGE_DONT_COPY) || (input_flags[i] & H5LT_FILE_IMAGE_DONT_RELEASE)) {
+ VERIFY(buf_ptr[i] != NULL, "buffer pointer must be non NULL");
+ HDfree(buf_ptr[i]);
+ } /* end if */
+
+ } /* end for */
+
+ /* release temporary working buffers */
+ HDfree(filename);
+ HDfree(file_id);
+ HDfree(dset_id);
+ HDfree(buf_ptr);
+ HDfree(buf_size);
+ HDfree(input_flags);
+
+ PASSED();
+
+ H5close();
+
+ return 0;
+
+error:
+ H5_FAILED();
+ return -1;
+}
+
+/*-------------------------------------------------------------------------
+* the main program
+*-------------------------------------------------------------------------
+*/
+int main( void )
+{
+ int nerrors = 0;
+ size_t open_images = 10; /* number of open file images */
+ size_t nflags = 8; /* number of flag combinations */
+ unsigned flags[8]; /* array with flag combinations */
+
+ /* set flag combinations for testing */
+ flags[0] = 0;
+ flags[1] = H5LT_FILE_IMAGE_DONT_RELEASE;
+ flags[2] = H5LT_FILE_IMAGE_DONT_COPY;
+ flags[3] = H5LT_FILE_IMAGE_DONT_COPY | H5LT_FILE_IMAGE_DONT_RELEASE;
+ flags[4] = H5LT_FILE_IMAGE_OPEN_RW;
+ flags[5] = H5LT_FILE_IMAGE_OPEN_RW | H5LT_FILE_IMAGE_DONT_RELEASE;
+ flags[6] = H5LT_FILE_IMAGE_OPEN_RW | H5LT_FILE_IMAGE_DONT_COPY;
+ flags[7] = H5LT_FILE_IMAGE_OPEN_RW | H5LT_FILE_IMAGE_DONT_COPY | H5LT_FILE_IMAGE_DONT_RELEASE;
+
+ /* Test file image operations. The flag combinations are assigned to file images in round-robin fashion */
+ nerrors += test_file_image(open_images, nflags, flags) < 0? 1 : 0;
+
+ if (nerrors) goto error;
+ printf("File image tests passed.\n");
+ return 0;
+
+error:
+ printf("***** %d IMAGE TEST%s FAILED! *****\n",nerrors, 1 == nerrors ? "" : "S");
+ return 1;
+}
+
diff --git a/src/H5Dint.c b/src/H5Dint.c
index 5c905bb..28d5367 100644
--- a/src/H5Dint.c
+++ b/src/H5Dint.c
@@ -2436,7 +2436,8 @@ H5D_flush(const H5F_t *f, hid_t dxpl_id)
udata.dxpl_id = dxpl_id;
/* Iterate over all the open datasets */
- H5I_search(H5I_DATASET, H5D_flush_cb, &udata, FALSE);
+ if(H5I_iterate(H5I_DATASET, H5D_flush_cb, &udata, FALSE) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_BADITER, FAIL, "unable to flush cached dataset info")
done:
FUNC_LEAVE_NOAPI(ret_value)
diff --git a/src/H5E.c b/src/H5E.c
index 4e14887..e74211e 100644
--- a/src/H5E.c
+++ b/src/H5E.c
@@ -107,7 +107,7 @@ static H5E_cls_t *H5E_register_class(const char *cls_name, const char *lib_name,
const char *version);
static herr_t H5E_unregister_class(H5E_cls_t *cls);
static ssize_t H5E_get_class_name(const H5E_cls_t *cls, char *name, size_t size);
-static int H5E_close_msg_cb(void *obj_ptr, hid_t obj_id, void *key);
+static int H5E_close_msg_cb(void *obj_ptr, hid_t obj_id, void *udata);
static herr_t H5E_close_msg(H5E_msg_t *err);
static H5E_msg_t *H5E_create_msg(H5E_cls_t *cls, H5E_type_t msg_type, const char *msg);
static H5E_t *H5E_get_current_stack(void);
@@ -543,8 +543,8 @@ H5E_unregister_class(H5E_cls_t *cls)
HDassert(cls);
/* Iterate over all the messages and delete those in this error class */
- /* (Ignore return value, since callback isn't designed to return a particular object) */
- (void)H5I_search(H5I_ERROR_MSG, H5E_close_msg_cb, cls, FALSE);
+ if(H5I_iterate(H5I_ERROR_MSG, H5E_close_msg_cb, cls, FALSE) < 0)
+ HGOTO_ERROR(H5E_ERROR, H5E_BADITER, FAIL, "unable to free all messages in this error class")
/* Free error class structure */
if(H5E_free_class(cls) < 0)
@@ -631,7 +631,7 @@ H5E_get_class_name(const H5E_cls_t *cls, char *name, size_t size)
/*-------------------------------------------------------------------------
* Function: H5E_close_msg_cb
*
- * Purpose: H5I_search callback function to close error messages in the
+ * Purpose: H5I_iterate callback function to close error messages in the
* error class.
*
* Return: Non-negative value on success/Negative on failure
@@ -642,10 +642,10 @@ H5E_get_class_name(const H5E_cls_t *cls, char *name, size_t size)
*-------------------------------------------------------------------------
*/
static int
-H5E_close_msg_cb(void *obj_ptr, hid_t obj_id, void *key)
+H5E_close_msg_cb(void *obj_ptr, hid_t obj_id, void *udata)
{
H5E_msg_t *err_msg = (H5E_msg_t*)obj_ptr;
- H5E_cls_t *cls = (H5E_cls_t*)key;
+ H5E_cls_t *cls = (H5E_cls_t*)udata;
herr_t ret_value = SUCCEED; /* Return value */
FUNC_ENTER_NOAPI_NOINIT
diff --git a/src/H5Edefin.h b/src/H5Edefin.h
index 887c2bb..ee284c4 100644
--- a/src/H5Edefin.h
+++ b/src/H5Edefin.h
@@ -93,6 +93,7 @@ hid_t H5E_CANTRELEASE_g = FAIL; /* Unable to release object */
hid_t H5E_CANTGET_g = FAIL; /* Can't get value */
hid_t H5E_CANTSET_g = FAIL; /* Can't set value */
hid_t H5E_DUPCLASS_g = FAIL; /* Duplicate class name in parent class */
+hid_t H5E_SETDISALLOWED_g = FAIL; /* Disallowed operation */
/* Free space errors */
hid_t H5E_CANTMERGE_g = FAIL; /* Can't merge objects */
diff --git a/src/H5Einit.h b/src/H5Einit.h
index 802c94a..6881e48 100644
--- a/src/H5Einit.h
+++ b/src/H5Einit.h
@@ -339,6 +339,11 @@ if((msg = H5E_create_msg(cls, H5E_MINOR, "Duplicate class name in parent class")
HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
if((H5E_DUPCLASS_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
+assert(H5E_SETDISALLOWED_g==(-1));
+if((msg = H5E_create_msg(cls, H5E_MINOR, "Disallowed operation"))==NULL)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed")
+if((H5E_SETDISALLOWED_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0)
+ HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message")
/* Free space errors */
assert(H5E_CANTMERGE_g==(-1));
diff --git a/src/H5Epubgen.h b/src/H5Epubgen.h
index f6a20f2..967b248 100644
--- a/src/H5Epubgen.h
+++ b/src/H5Epubgen.h
@@ -155,9 +155,11 @@ H5_DLLVAR hid_t H5E_CANTRELEASE_g; /* Unable to release object */
#define H5E_CANTGET (H5OPEN H5E_CANTGET_g)
#define H5E_CANTSET (H5OPEN H5E_CANTSET_g)
#define H5E_DUPCLASS (H5OPEN H5E_DUPCLASS_g)
+#define H5E_SETDISALLOWED (H5OPEN H5E_SETDISALLOWED_g)
H5_DLLVAR hid_t H5E_CANTGET_g; /* Can't get value */
H5_DLLVAR hid_t H5E_CANTSET_g; /* Can't set value */
H5_DLLVAR hid_t H5E_DUPCLASS_g; /* Duplicate class name in parent class */
+H5_DLLVAR hid_t H5E_SETDISALLOWED_g; /* Disallowed operation */
/* Free space errors */
#define H5E_CANTMERGE (H5OPEN H5E_CANTMERGE_g)
diff --git a/src/H5Eterm.h b/src/H5Eterm.h
index 921b3b6..5edcd34 100644
--- a/src/H5Eterm.h
+++ b/src/H5Eterm.h
@@ -94,7 +94,8 @@ H5E_CANTRELEASE_g=
/* Property list errors */
H5E_CANTGET_g=
H5E_CANTSET_g=
-H5E_DUPCLASS_g=
+H5E_DUPCLASS_g=
+H5E_SETDISALLOWED_g=
/* Free space errors */
H5E_CANTMERGE_g=
diff --git a/src/H5F.c b/src/H5F.c
index b4f1191..cdf418b 100644
--- a/src/H5F.c
+++ b/src/H5F.c
@@ -52,7 +52,7 @@ typedef struct H5F_olist_t {
} H5F_olist_t;
/* PRIVATE PROTOTYPES */
-static size_t H5F_get_objects(const H5F_t *f, unsigned types, size_t max_objs, hid_t *obj_id_list, hbool_t app_ref);
+static herr_t H5F_get_objects(const H5F_t *f, unsigned types, size_t max_index, hid_t *obj_id_list, hbool_t app_ref, size_t *obj_id_count_ptr);
static int H5F_get_objects_cb(void *obj_ptr, hid_t obj_id, void *key);
static H5F_t *H5F_new(H5F_file_t *shared, hid_t fcpl_id, hid_t fapl_id,
H5FD_t *lf);
@@ -363,11 +363,6 @@ done:
*
* Programmer: Raymond Lu
* Wednesday, Dec 5, 2001
- * Modification:
- * Raymond Lu
- * 24 September 2008
- * Changed the return value to ssize_t to accommadate
- * potential large number of objects.
*
*-------------------------------------------------------------------------
*/
@@ -375,18 +370,24 @@ ssize_t
H5Fget_obj_count(hid_t file_id, unsigned types)
{
H5F_t *f = NULL; /* File to query */
- ssize_t ret_value; /* Return value */
+ size_t obj_count = 0; /* Number of opened objects */
+ ssize_t ret_value; /* Return value */
FUNC_ENTER_API(FAIL)
H5TRACE2("Zs", "iIu", file_id, types);
+ /* Check arguments */
if(file_id != (hid_t)H5F_OBJ_ALL && (NULL == (f = (H5F_t *)H5I_object_verify(file_id, H5I_FILE))))
HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "not a file id")
if(0 == (types & H5F_OBJ_ALL))
HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "not an object type")
- /* H5F_get_obj_count doesn't fail */
- ret_value = (ssize_t)H5F_get_obj_count(f, types, TRUE);
+ /* Perform the query */
+ if(H5F_get_obj_count(f, types, TRUE, &obj_count) < 0)
+ HGOTO_ERROR(H5E_INTERNAL, H5E_BADITER, FAIL, "H5F_get_obj_count failed")
+
+ /* Set the return value */
+ ret_value = (ssize_t)obj_count;
done:
FUNC_LEAVE_API(ret_value)
@@ -399,31 +400,30 @@ done:
* Purpose: Private function return the number of opened object IDs
* (files, datasets, groups, datatypes) in the same file.
*
- * Return: Non-negative on success; can't fail.
+ * Return: SUCCEED on success, FAIL on failure.
*
* Programmer: Raymond Lu
* Wednesday, Dec 5, 2001
*
- * Modification:
- * Raymond Lu
- * 24 September 2008
- * Changed the return value to size_t to accommadate
- * potential large number of objects.
- *
*-------------------------------------------------------------------------
*/
-size_t
-H5F_get_obj_count(const H5F_t *f, unsigned types, hbool_t app_ref)
+herr_t
+H5F_get_obj_count(const H5F_t *f, unsigned types, hbool_t app_ref, size_t *obj_id_count_ptr)
{
- size_t ret_value; /* Return value */
+ herr_t ret_value = SUCCEED;
- FUNC_ENTER_NOAPI_NOINIT_NOERR
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity check */
+ HDassert(obj_id_count_ptr);
- /* H5F_get_objects doesn't fail */
- ret_value = H5F_get_objects(f, types, 0, NULL, app_ref);
+ /* Perform the query */
+ if((ret_value = H5F_get_objects(f, types, 0, NULL, app_ref, obj_id_count_ptr)) < 0)
+ HGOTO_ERROR(H5E_INTERNAL, H5E_BADITER, FAIL, "H5F_get_objects failed")
+done:
FUNC_LEAVE_NOAPI(ret_value)
-}
+} /* end H5F_get_obj_count() */
/*-------------------------------------------------------------------------
@@ -448,19 +448,25 @@ ssize_t
H5Fget_obj_ids(hid_t file_id, unsigned types, size_t max_objs, hid_t *oid_list)
{
H5F_t *f = NULL; /* File to query */
- ssize_t ret_value; /* Return value */
+ size_t obj_id_count = 0; /* Number of open objects */
+ ssize_t ret_value; /* Return value */
FUNC_ENTER_API(FAIL)
H5TRACE4("Zs", "iIuz*i", file_id, types, max_objs, oid_list);
+ /* Check arguments */
if(file_id != (hid_t)H5F_OBJ_ALL && (NULL == (f = (H5F_t *)H5I_object_verify(file_id, H5I_FILE))))
HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "not a file id")
if(0 == (types & H5F_OBJ_ALL))
HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "not an object type")
HDassert(oid_list);
- /* H5F_get_objects doesn't fail */
- ret_value = (ssize_t)H5F_get_obj_ids(f, types, max_objs, oid_list, TRUE);
+ /* Perform the query */
+ if(H5F_get_obj_ids(f, types, max_objs, oid_list, TRUE, &obj_id_count) < 0)
+ HGOTO_ERROR(H5E_INTERNAL, H5E_BADITER, FAIL, "H5F_get_obj_ids failed")
+
+ /* Set the return value */
+ ret_value = (ssize_t)obj_id_count;
done:
FUNC_LEAVE_API(ret_value)
@@ -477,26 +483,25 @@ done:
* Programmer: Raymond Lu
* Wednesday, Dec 5, 2001
*
- * Modification:
- * Raymond Lu
- * 24 September 2008
- * Changed the return value and MAX_OBJTS to size_t to accommadate
- * potential large number of objects.
- *
*-------------------------------------------------------------------------
*/
-size_t
-H5F_get_obj_ids(const H5F_t *f, unsigned types, size_t max_objs, hid_t *oid_list, hbool_t app_ref)
+herr_t
+H5F_get_obj_ids(const H5F_t *f, unsigned types, size_t max_objs, hid_t *oid_list, hbool_t app_ref, size_t *obj_id_count_ptr)
{
- size_t ret_value; /* Return value */
+ herr_t ret_value = SUCCEED; /* Return value */
- FUNC_ENTER_NOAPI_NOINIT_NOERR
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity check */
+ HDassert(obj_id_count_ptr);
- /* H5F_get_objects doesn't fail */
- ret_value = H5F_get_objects(f, types, max_objs, oid_list, app_ref);
+ /* Perform the query */
+ if((ret_value = H5F_get_objects(f, types, max_objs, oid_list, app_ref, obj_id_count_ptr)) < 0)
+ HGOTO_ERROR(H5E_INTERNAL, H5E_BADITER, FAIL, "H5F_get_objects failed")
+done:
FUNC_LEAVE_NOAPI(ret_value)
-}
+} /* end H5F_get_obj_ids() */
/*---------------------------------------------------------------------------
@@ -512,14 +517,18 @@ H5F_get_obj_ids(const H5F_t *f, unsigned types, size_t max_objs, hid_t *oid_list
*
*---------------------------------------------------------------------------
*/
-static size_t
-H5F_get_objects(const H5F_t *f, unsigned types, size_t max_index, hid_t *obj_id_list, hbool_t app_ref)
+static herr_t
+H5F_get_objects(const H5F_t *f, unsigned types, size_t max_index, hid_t *obj_id_list, hbool_t app_ref, size_t *obj_id_count_ptr)
{
size_t obj_id_count=0; /* Number of open IDs */
H5F_olist_t olist; /* Structure to hold search results */
- size_t ret_value; /* Return value */
+ htri_t type_exists; /* Whether objects of a type are open */
+ herr_t ret_value = SUCCEED; /* Return value */
- FUNC_ENTER_NOAPI_NOINIT_NOERR
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Sanity check */
+ HDassert(obj_id_count_ptr);
/* Set up search information */
olist.obj_id_list = (max_index==0 ? NULL : obj_id_list);
@@ -537,45 +546,50 @@ H5F_get_objects(const H5F_t *f, unsigned types, size_t max_index, hid_t *obj_id_
olist.file_info.ptr.shared = f ? f->shared : NULL;
} /* end else */
- /* Search through file IDs to count the number, and put their
- * IDs on the object list. H5I_search returns NULL if no object
- * is found, so don't return failure in this function. */
+ /* Iterate through file IDs to count the number, and put their
+ * IDs on the object list. */
if(types & H5F_OBJ_FILE) {
olist.obj_type = H5I_FILE;
- (void)H5I_search(H5I_FILE, H5F_get_objects_cb, &olist, app_ref);
+ if(H5I_iterate(H5I_FILE, H5F_get_objects_cb, &olist, app_ref) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_BADITER, FAIL, "iteration failed(1)")
} /* end if */
/* Search through dataset IDs to count number of datasets, and put their
* IDs on the object list */
if(types & H5F_OBJ_DATASET) {
olist.obj_type = H5I_DATASET;
- (void)H5I_search(H5I_DATASET, H5F_get_objects_cb, &olist, app_ref);
- }
+ if(H5I_iterate(H5I_DATASET, H5F_get_objects_cb, &olist, app_ref) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_BADITER, FAIL, "iteration failed(2)")
+ } /* end if */
/* Search through group IDs to count number of groups, and put their
* IDs on the object list */
if(types & H5F_OBJ_GROUP) {
olist.obj_type = H5I_GROUP;
- (void)H5I_search(H5I_GROUP, H5F_get_objects_cb, &olist, app_ref);
- }
+ if(H5I_iterate(H5I_GROUP, H5F_get_objects_cb, &olist, app_ref) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_BADITER, FAIL, "iteration failed(3)")
+ } /* end if */
/* Search through datatype IDs to count number of named datatypes, and put their
* IDs on the object list */
if(types & H5F_OBJ_DATATYPE) {
olist.obj_type = H5I_DATATYPE;
- (void)H5I_search(H5I_DATATYPE, H5F_get_objects_cb, &olist, app_ref);
- }
+ if(H5I_iterate(H5I_DATATYPE, H5F_get_objects_cb, &olist, app_ref) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_BADITER, FAIL, "iteration failed(4)")
+ } /* end if */
/* Search through attribute IDs to count number of attributes, and put their
* IDs on the object list */
if(types & H5F_OBJ_ATTR) {
olist.obj_type = H5I_ATTR;
- (void)H5I_search(H5I_ATTR, H5F_get_objects_cb, &olist, app_ref);
- }
+ if(H5I_iterate(H5I_ATTR, H5F_get_objects_cb, &olist, app_ref) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_BADITER, FAIL, "iteration failed(5)")
+ } /* end if */
/* Set the number of objects currently open */
- ret_value = obj_id_count;
+ *obj_id_count_ptr = obj_id_count;
+done:
FUNC_LEAVE_NOAPI(ret_value)
} /* end H5F_get_objects() */
@@ -593,8 +607,6 @@ H5F_get_objects(const H5F_t *f, unsigned types, size_t max_index, hid_t *obj_id_
* Programmer: Raymond Lu
* Wednesday, Dec 5, 2001
*
- * Modification:
- *
*-------------------------------------------------------------------------
*/
static int
@@ -626,8 +638,8 @@ H5F_get_objects_cb(void *obj_ptr, hid_t obj_id, void *key)
/* Check if we've filled up the array. Return TRUE only if
* we have filled up the array. Otherwise return FALSE(RET_VALUE is
- * preset to FALSE) because H5I_search needs the return value of FALSE
- * to continue searching. */
+ * preset to FALSE) because H5I_iterate needs the return value of
+ * FALSE to continue the iteration. */
if(olist->max_index>0 && olist->list_index>=olist->max_index)
HGOTO_DONE(TRUE) /* Indicate that the iterator should stop */
}
@@ -691,8 +703,8 @@ H5F_get_objects_cb(void *obj_ptr, hid_t obj_id, void *key)
/* Check if we've filled up the array. Return TRUE only if
* we have filled up the array. Otherwise return FALSE(RET_VALUE is
- * preset to FALSE) because H5I_search needs the return value of FALSE
- * to continue searching. */
+ * preset to FALSE) because H5I_iterate needs the return value of
+ * FALSE to continue iterating. */
if(olist->max_index>0 && olist->list_index>=olist->max_index)
HGOTO_DONE(TRUE) /* Indicate that the iterator should stop */
} /* end if */
@@ -1785,8 +1797,6 @@ done:
* Programmer: Quincey Koziol
* Tuesday, July 19, 2005
*
- * Modifications:
- *
*-------------------------------------------------------------------------
*/
herr_t
@@ -1868,27 +1878,36 @@ H5F_try_close(H5F_t *f)
if(f->nopen_objs > 0) {
size_t obj_count; /* # of open objects */
hid_t objs[128]; /* Array of objects to close */
+ herr_t result; /* Local result from obj ID query */
size_t u; /* Local index variable */
/* Get the list of IDs of open dataset, group, & attribute objects */
- while((obj_count = H5F_get_obj_ids(f, H5F_OBJ_LOCAL|H5F_OBJ_DATASET|H5F_OBJ_GROUP|H5F_OBJ_ATTR, (int)(sizeof(objs)/sizeof(objs[0])), objs, FALSE)) != 0) {
+ while((result = H5F_get_obj_ids(f, H5F_OBJ_LOCAL | H5F_OBJ_DATASET | H5F_OBJ_GROUP | H5F_OBJ_ATTR, (int)(sizeof(objs) / sizeof(objs[0])), objs, FALSE, &obj_count)) <= 0
+ && obj_count != 0 ) {
+
/* Try to close all the open objects in this file */
for(u = 0; u < obj_count; u++)
if(H5I_dec_ref(objs[u]) < 0)
HGOTO_ERROR(H5E_ATOM, H5E_CLOSEERROR, FAIL, "can't close object")
} /* end while */
+ if(result < 0)
+ HGOTO_ERROR(H5E_INTERNAL, H5E_BADITER, FAIL, "H5F_get_obj_ids failed(1)")
/* Get the list of IDs of open named datatype objects */
/* (Do this separately from the dataset & attribute IDs, because
* they could be using one of the named datatypes and then the
* open named datatype ID will get closed twice)
*/
- while((obj_count = H5F_get_obj_ids(f, H5F_OBJ_LOCAL|H5F_OBJ_DATATYPE, (int)(sizeof(objs)/sizeof(objs[0])), objs, FALSE)) != 0) {
+ while((result = H5F_get_obj_ids(f, H5F_OBJ_LOCAL | H5F_OBJ_DATATYPE, (int)(sizeof(objs) / sizeof(objs[0])), objs, FALSE, &obj_count)) <= 0
+ && obj_count != 0) {
+
/* Try to close all the open objects in this file */
for(u = 0; u < obj_count; u++)
if(H5I_dec_ref(objs[u]) < 0)
HGOTO_ERROR(H5E_ATOM, H5E_CLOSEERROR, FAIL, "can't close object")
} /* end while */
+ if(result < 0)
+ HGOTO_ERROR(H5E_INTERNAL, H5E_BADITER, FAIL, "H5F_get_obj_ids failed(2)")
} /* end if */
} /* end if */
@@ -2551,6 +2570,139 @@ done:
/*-------------------------------------------------------------------------
+ * Function: H5Fget_file_image
+ *
+ * Purpose: If a buffer is provided (via the buf_ptr argument) and is
+ * big enough (size in buf_len argument), load *buf_ptr with
+ * an image of the open file whose ID is provided in the
+ * file_id parameter, and return the number of bytes copied
+ * to the buffer.
+ *
+ * If the buffer exists, but is too small to contain an image
+ * of the indicated file, return a negative number.
+ *
+ * Finally, if no buffer is provided, return the size of the
+ * buffer needed. This value is simply the eoa of the target
+ * file.
+ *
+ * Note that any user block is skipped.
+ *
+ * Also note that the function may not be used on files
+ * opened with either the split/multi file driver or the
+ * family file driver.
+ *
+ * In the former case, the sparse address space makes the
+ * get file image operation impractical, due to the size of
+ * the image typically required.
+ *
+ * In the case of the family file driver, the problem is
+ * the driver message in the super block, which will prevent
+ * the image being opened with any driver other than the
+ * family file driver -- which negates the purpose of the
+ * operation. This can be fixed, but no resources for
+ * this now.
+ *
+ * Return: Success: Bytes copied / number of bytes needed.
+ * Failure: negative value
+ *
+ * Programmer: John Mainzer
+ * 11/15/11
+ *
+ *-------------------------------------------------------------------------
+ */
+ssize_t
+H5Fget_file_image(hid_t file_id, void *buf_ptr, size_t buf_len)
+{
+ H5F_t *file; /* File object for file ID */
+ H5FD_t *fd_ptr; /* file driver */
+ haddr_t eoa; /* End of file address */
+ ssize_t ret_value; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE3("Zs", "i*xz", file_id, buf_ptr, buf_len);
+
+ /* Check args */
+ if(NULL == (file = (H5F_t *)H5I_object_verify(file_id, H5I_FILE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "not a file ID")
+ if(!file || !file->shared || !file->shared->lf)
+ HGOTO_ERROR(H5E_FILE, H5E_BADVALUE, FAIL, "file_id yields invalid file pointer")
+ fd_ptr = file->shared->lf;
+ if(!fd_ptr->cls)
+ HGOTO_ERROR(H5E_FILE, H5E_BADVALUE, FAIL, "fd_ptr yields invalid class pointer")
+
+ /* the address space used by the split and multi file drivers is not
+ * a good fit for this call. Since the plan is to depreciate these
+ * drivers anyway, don't bother to do a "force fit".
+ *
+ * The following clause tests for the multi file driver, and fails
+ * if the supplied file has the multi file driver as its top level
+ * file driver. However, this test will not work if there is some
+ * other file driver sitting on top of the multi file driver.
+ *
+ * I'm not sure if this is possible at present, but in all likelyhood,
+ * it will become possible in the future. On the other hand, we may
+ * remove the split/multi file drivers before then.
+ *
+ * I am leaving this solution in for now, but we should review it,
+ * and improve the solution if necessary.
+ *
+ * JRM -- 11/11/22
+ */
+ if(HDstrcmp(fd_ptr->cls->name, "multi") == 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "Not supported for multi file driver.")
+
+ /* While the family file driver is conceptually fully compatible
+ * with the get file image operation, it sets a file driver message
+ * in the super block that prevents the image being opened with any
+ * driver other than the family file driver. Needless to say, this
+ * rather defeats the purpose of the get file image operation.
+ *
+ * While this problem is quire solvable, the required time and
+ * resources are lacking at present. Hence, for now, we don't
+ * allow the get file image operation to be perfomed on files
+ * opened with the family file driver.
+ *
+ * Observe that the following test only looks at the top level
+ * driver, and fails if there is some other driver sitting on to
+ * of the family file driver.
+ *
+ * I don't think this can happen at present, but that may change
+ * in the future.
+ * JRM -- 12/21/11
+ */
+ if(HDstrcmp(fd_ptr->cls->name, "family") == 0)
+ HGOTO_ERROR(H5E_FILE, H5E_BADVALUE, FAIL, "Not supported for family file driver.")
+
+
+ /* Go get the actual file size */
+ if(HADDR_UNDEF == (eoa = H5FD_get_eoa(file->shared->lf, H5FD_MEM_DEFAULT)))
+ HGOTO_ERROR(H5E_FILE, H5E_CANTGET, FAIL, "unable to get file size")
+
+ /* set ret_value = to eoa -- will overwrite this if appropriate */
+ ret_value = (ssize_t)eoa;
+
+ /* test to see if a buffer was provided -- if not, we are done */
+ if(buf_ptr != NULL) {
+ size_t space_needed; /* size of file image */
+
+ /* Check for buffer too small */
+ if((haddr_t)buf_len < eoa)
+ HGOTO_ERROR(H5E_FILE, H5E_BADVALUE, FAIL, "supplied buffer too small")
+
+ space_needed = (size_t)eoa;
+
+ /* read in the file image */
+ /* (Note compensation for base address addition in internal routine) */
+ if(H5FD_read(fd_ptr, H5AC_ind_dxpl_id, H5FD_MEM_DEFAULT, 0, space_needed, buf_ptr) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_READERROR, FAIL, "file image read request failed")
+ } /* end if */
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* H5Fget_file_image() */
+
+
+/*-------------------------------------------------------------------------
* Function: H5Fget_mdc_config
*
* Purpose: Retrieves the current automatic cache resize configuration
diff --git a/src/H5FD.c b/src/H5FD.c
index 66fa3b9..18b0eb6 100644
--- a/src/H5FD.c
+++ b/src/H5FD.c
@@ -70,6 +70,10 @@ static herr_t H5FD_pl_copy(void *(*copy_func)(const void *), size_t pl_size,
static herr_t H5FD_pl_close(hid_t driver_id, herr_t (*free_func)(void *),
void *pl);
static herr_t H5FD_free_cls(H5FD_class_t *cls);
+static herr_t H5FD_fapl_copy(hid_t driver_id, const void *fapl, void **copied_fapl);
+static herr_t H5FD_dxpl_copy(hid_t driver_id, const void *dxpl, void **copied_dxpl);
+static int H5FD_query(const H5FD_t *f, unsigned long *flags/*out*/);
+static int H5FD_driver_query(const H5FD_class_t *driver, unsigned long *flags/*out*/);
/*********************/
/* Package Variables */
@@ -750,17 +754,15 @@ done:
* Programmer: Robb Matzke
* Tuesday, August 3, 1999
*
- * Modifications:
- *
*-------------------------------------------------------------------------
*/
-herr_t
+static herr_t
H5FD_fapl_copy(hid_t driver_id, const void *old_fapl, void **copied_fapl)
{
H5FD_class_t *driver;
herr_t ret_value = SUCCEED; /* Return value */
- FUNC_ENTER_NOAPI(FAIL)
+ FUNC_ENTER_NOAPI_NOINIT
/* Check args */
if(NULL == (driver = (H5FD_class_t *)H5I_object(driver_id)))
@@ -871,17 +873,15 @@ done:
* Programmer: Robb Matzke
* Tuesday, August 3, 1999
*
- * Modifications:
- *
*-------------------------------------------------------------------------
*/
-herr_t
+static herr_t
H5FD_dxpl_copy(hid_t driver_id, const void *old_dxpl, void **copied_dxpl)
{
H5FD_class_t *driver;
herr_t ret_value = SUCCEED; /* Return value */
- FUNC_ENTER_NOAPI(FAIL)
+ FUNC_ENTER_NOAPI_NOINIT
/* Check args */
if(NULL == (driver = (H5FD_class_t *)H5I_object(driver_id)))
@@ -1039,6 +1039,8 @@ H5FD_open(const char *name, unsigned flags, hid_t fapl_id, haddr_t maxaddr)
H5FD_t *file = NULL; /* VFD file struct */
hid_t driver_id = -1; /* VFD ID */
H5P_genplist_t *plist; /* Property list pointer */
+ unsigned long driver_flags = 0; /* File-inspecific driver feature flags */
+ H5FD_file_image_info_t file_image_info; /* Initial file image */
H5FD_t *ret_value; /* Return value */
FUNC_ENTER_NOAPI(NULL)
@@ -1061,6 +1063,19 @@ H5FD_open(const char *name, unsigned flags, hid_t fapl_id, haddr_t maxaddr)
if(NULL == driver->open)
HGOTO_ERROR(H5E_VFL, H5E_UNSUPPORTED, NULL, "file driver has no `open' method")
+ /* Query driver flag */
+ H5FD_driver_query(driver, &driver_flags);
+
+ /* Get initial file image info */
+ if(H5P_get(plist, H5F_ACS_FILE_IMAGE_INFO_NAME, &file_image_info) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, NULL, "can't get file image info")
+
+ /* If an image is provided, make sure the driver supports this feature */
+ HDassert(((file_image_info.buffer != NULL) && (file_image_info.size > 0)) ||
+ ((file_image_info.buffer == NULL) && (file_image_info.size == 0)));
+ if((file_image_info.buffer != NULL) && !(driver_flags & H5FD_FEAT_ALLOW_FILE_IMAGE))
+ HGOTO_ERROR(H5E_VFL, H5E_UNSUPPORTED, NULL, "file image set, but not supported.")
+
/* Dispatch to file driver */
if(HADDR_UNDEF == maxaddr)
maxaddr = driver->maxaddr;
@@ -1318,19 +1333,17 @@ done:
* Programmer: Quincey Koziol
* Friday, August 25, 2000
*
- * Modifications:
- *
*-------------------------------------------------------------------------
*/
-int
+static int
H5FD_query(const H5FD_t *f, unsigned long *flags/*out*/)
{
- int ret_value=0;
+ int ret_value = 0; /* Return value */
- FUNC_ENTER_NOAPI(FAIL)
+ FUNC_ENTER_NOAPI_NOINIT
- assert(f);
- assert(flags);
+ HDassert(f);
+ HDassert(flags);
/* Check for query driver and call it */
if(f->cls->query)
@@ -1340,7 +1353,44 @@ H5FD_query(const H5FD_t *f, unsigned long *flags/*out*/)
done:
FUNC_LEAVE_NOAPI(ret_value)
-}
+} /* end H5FD_query() */
+
+
+/*-------------------------------------------------------------------------
+* Function: H5FD_driver_query
+*
+* Purpose: Similar to H5FD_query(), but intended for cases when we don't
+* have a file available (e.g. before one is opened). Since we
+* can't use the file to get the driver, the driver is passed in
+* as a parameter.
+*
+* Return: Success: non-negative
+* Failure: negative
+*
+* Programmer: Jacob Gruber
+* Wednesday, August 17, 2011
+*
+*-------------------------------------------------------------------------
+*/
+static int
+H5FD_driver_query(const H5FD_class_t *driver, unsigned long *flags/*out*/)
+{
+ int ret_value = 0; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ HDassert(driver);
+ HDassert(flags);
+
+ /* Check for the driver to query and then query it */
+ if(driver->query)
+ ret_value = (driver->query)(NULL, flags);
+ else
+ *flags = 0;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FD_driver_query() */
/*-------------------------------------------------------------------------
diff --git a/src/H5FDcore.c b/src/H5FDcore.c
index ff99cab..1fef36c 100644
--- a/src/H5FDcore.c
+++ b/src/H5FDcore.c
@@ -101,6 +101,7 @@ typedef struct H5FD_core_t {
HANDLE hFile; /* Native windows file handle */
#endif /* H5_HAVE_WIN32_API */
hbool_t dirty; /*changes not saved? */
+ H5FD_file_image_callbacks_t fi_callbacks; /* file image callbacks */
} H5FD_core_t;
/* Driver-specific file access properties */
@@ -412,6 +413,7 @@ H5FD_core_open(const char *name, unsigned flags, hid_t fapl_id,
#endif
h5_stat_t sb;
int fd=-1;
+ H5FD_file_image_info_t file_image_info;
H5FD_t *ret_value;
FUNC_ENTER_NOAPI_NOINIT
@@ -434,10 +436,32 @@ H5FD_core_open(const char *name, unsigned flags, hid_t fapl_id,
if(H5F_ACC_CREAT & flags) o_flags |= O_CREAT;
if(H5F_ACC_EXCL & flags) o_flags |= O_EXCL;
+ /* Retrieve initial file image info */
+ if(H5P_get(plist, H5F_ACS_FILE_IMAGE_INFO_NAME, &file_image_info) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, NULL, "can't get initial file image info")
+
+ /* If the file image exists and this is an open, make sure the file doesn't exist */
+ HDassert(((file_image_info.buffer != NULL) && (file_image_info.size > 0)) ||
+ ((file_image_info.buffer == NULL) && (file_image_info.size == 0)));
+ if((file_image_info.buffer != NULL) && !(H5F_ACC_CREAT & flags)) {
+ if(HDopen(name, o_flags, 0666) >= 0)
+ HGOTO_ERROR(H5E_FILE, H5E_FILEEXISTS, NULL, "file already exists")
+
+ /* If backing store is requested, create and stat the file
+ * Note: We are forcing the O_CREAT flag here, even though this is
+ * technically an open.
+ */
+ if(fa->backing_store) {
+ if((fd = HDopen(name, o_flags | O_CREAT, 0666)) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTOPENFILE, NULL, "unable to create file")
+ if(HDfstat(fd, &sb) < 0)
+ HSYS_GOTO_ERROR(H5E_FILE, H5E_BADFILE, NULL, "unable to fstat file")
+ } /* end if */
+ } /* end if */
/* Open backing store, and get stat() from file. The only case that backing
* store is off is when the backing_store flag is off and H5F_ACC_CREAT is
* on. */
- if(fa->backing_store || !(H5F_ACC_CREAT & flags)) {
+ else if(fa->backing_store || !(H5F_ACC_CREAT & flags)) {
if(fa && (fd = HDopen(name, o_flags, 0666)) < 0)
HGOTO_ERROR(H5E_FILE, H5E_CANTOPENFILE, NULL, "unable to open file")
if(HDfstat(fd, &sb) < 0)
@@ -460,6 +484,9 @@ H5FD_core_open(const char *name, unsigned flags, hid_t fapl_id,
/* If save data in backing store. */
file->backing_store = fa->backing_store;
+ /* Save file image callbacks */
+ file->fi_callbacks = file_image_info.callbacks;
+
if(fd >= 0) {
/* Retrieve information for determining uniqueness of file */
#ifdef H5_HAVE_WIN32_API
@@ -491,51 +518,70 @@ H5FD_core_open(const char *name, unsigned flags, hid_t fapl_id,
size_t size;
/* Retrieve file size */
- size = (size_t)sb.st_size;
+ if(file_image_info.buffer && file_image_info.size > 0)
+ size = file_image_info.size;
+ else
+ size = (size_t)sb.st_size;
/* Check if we should allocate the memory buffer and read in existing data */
if(size) {
- /* Allocate memory for the file's data */
- if(NULL == (file->mem = (unsigned char*)H5MM_malloc(size)))
- HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "unable to allocate memory block")
+ /* Allocate memory for the file's data, using the file image callback if available. */
+ if(file->fi_callbacks.image_malloc) {
+ if(NULL == (file->mem = (unsigned char*)file->fi_callbacks.image_malloc(size, H5FD_FILE_IMAGE_OP_FILE_OPEN, file->fi_callbacks.udata)))
+ HGOTO_ERROR(H5E_FILE, H5E_CANTALLOC, NULL, "image malloc callback failed")
+ } /* end if */
+ else {
+ if(NULL == (file->mem = (unsigned char*)H5MM_malloc(size)))
+ HGOTO_ERROR(H5E_FILE, H5E_CANTALLOC, NULL, "unable to allocate memory block")
+ } /* end else */
/* Set up data structures */
file->eof = size;
- /* Read in existing data, being careful of interrupted system calls,
- * partial results, and the end of the file.
- */
- while(size > 0) {
-
- h5_core_io_t bytes_in = 0; /* # of bytes to read */
- h5_core_io_ret_t bytes_read = -1; /* # of bytes actually read */
-
- /* Trying to read more bytes than the return type can handle is
- * undefined behavior in POSIX.
- */
- if(size > H5_CORE_MAX_IO_BYTES_g)
- bytes_in = H5_CORE_MAX_IO_BYTES_g;
- else
- bytes_in = (h5_core_io_t)size;
-
- do {
- bytes_read = HDread(file->fd, file->mem, bytes_in);
- } while(-1 == bytes_read && EINTR == errno);
-
- if(-1 == bytes_read) { /* error */
- int myerrno = errno;
- time_t mytime = HDtime(NULL);
- HDoff_t myoffset = HDlseek(file->fd, (HDoff_t)0, SEEK_CUR);
-
- HGOTO_ERROR(H5E_IO, H5E_READERROR, NULL, "file read failed: time = %s, filename = '%s', file descriptor = %d, errno = %d, error message = '%s', file->mem = %p, size = %lu, offset = %llu", HDctime(&mytime), file->name, file->fd, myerrno, HDstrerror(myerrno), file->mem, (unsigned long)size, (unsigned long long)myoffset);
+ /* If there is an initial file image, copy it, using the callback if possible */
+ if(file_image_info.buffer && file_image_info.size > 0) {
+ if(file->fi_callbacks.image_memcpy) {
+ if(file->mem != file->fi_callbacks.image_memcpy(file->mem, file_image_info.buffer, size, H5FD_FILE_IMAGE_OP_FILE_OPEN, file->fi_callbacks.udata))
+ HGOTO_ERROR(H5E_FILE, H5E_CANTCOPY, NULL, "image_memcpy callback failed")
} /* end if */
-
- HDassert(bytes_read >= 0);
- HDassert((size_t)bytes_read <= size);
-
- size -= (size_t)bytes_read;
-
- } /* end while */
+ else
+ HDmemcpy(file->mem, file_image_info.buffer, size);
+ } /* end if */
+ /* Read in existing data from the file if there is no image */
+ else {
+ /* Read in existing data, being careful of interrupted system calls,
+ * partial results, and the end of the file.
+ */
+ while(size > 0) {
+ h5_core_io_t bytes_in = 0; /* # of bytes to read */
+ h5_core_io_ret_t bytes_read = -1; /* # of bytes actually read */
+
+ /* Trying to read more bytes than the return type can handle is
+ * undefined behavior in POSIX.
+ */
+ if(size > H5_CORE_MAX_IO_BYTES_g)
+ bytes_in = H5_CORE_MAX_IO_BYTES_g;
+ else
+ bytes_in = (h5_core_io_t)size;
+
+ do {
+ bytes_read = HDread(file->fd, file->mem, bytes_in);
+ } while(-1 == bytes_read && EINTR == errno);
+
+ if(-1 == bytes_read) { /* error */
+ int myerrno = errno;
+ time_t mytime = HDtime(NULL);
+ HDoff_t myoffset = HDlseek(file->fd, (HDoff_t)0, SEEK_CUR);
+
+ HGOTO_ERROR(H5E_IO, H5E_READERROR, NULL, "file read failed: time = %s, filename = '%s', file descriptor = %d, errno = %d, error message = '%s', file->mem = %p, size = %lu, offset = %llu", HDctime(&mytime), file->name, file->fd, myerrno, HDstrerror(myerrno), file->mem, (unsigned long)size, (unsigned long long)myoffset);
+ } /* end if */
+
+ HDassert(bytes_read >= 0);
+ HDassert((size_t)bytes_read <= size);
+
+ size -= (size_t)bytes_read;
+ } /* end while */
+ } /* end else */
} /* end if */
} /* end if */
@@ -578,8 +624,15 @@ H5FD_core_close(H5FD_t *_file)
HDclose(file->fd);
if(file->name)
H5MM_xfree(file->name);
- if(file->mem)
- H5MM_xfree(file->mem);
+ if(file->mem) {
+ /* Use image callback if available */
+ if(file->fi_callbacks.image_free) {
+ if(file->fi_callbacks.image_free(file->mem, H5FD_FILE_IMAGE_OP_FILE_CLOSE, file->fi_callbacks.udata) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTFREE, FAIL, "image_free callback failed")
+ } /* end if */
+ else
+ H5MM_xfree(file->mem);
+ } /* end if */
HDmemset(file, 0, sizeof(H5FD_core_t));
H5MM_xfree(file);
@@ -700,9 +753,11 @@ H5FD_core_query(const H5FD_t * _file, unsigned long *flags /* out */)
*flags |= H5FD_FEAT_ACCUMULATE_METADATA; /* OK to accumulate metadata for faster writes */
*flags |= H5FD_FEAT_DATA_SIEVE; /* OK to perform data sieving for faster raw data reads & writes */
*flags |= H5FD_FEAT_AGGREGATE_SMALLDATA; /* OK to aggregate "small" raw data allocations */
+ *flags |= H5FD_FEAT_ALLOW_FILE_IMAGE; /* OK to use file image feature with this VFD */
+ *flags |= H5FD_FEAT_CAN_USE_FILE_IMAGE_CALLBACKS; /* OK to use file image callbacks with this VFD */
/* If the backing store is open, a POSIX file handle is available */
- if(file->fd >= 0 && file->backing_store)
+ if(file && file->fd >= 0 && file->backing_store)
*flags |= H5FD_FEAT_POSIX_COMPAT_HANDLE; /* VFD handle is POSIX I/O call compatible */
} /* end if */
@@ -976,9 +1031,16 @@ H5FD_core_write(H5FD_t *_file, H5FD_mem_t UNUSED type, hid_t UNUSED dxpl_id, had
if((addr + size) % file->increment)
new_eof += file->increment;
- /* (Re)allocate memory for the file buffer */
- if(NULL == (x = (unsigned char *)H5MM_realloc(file->mem, new_eof)))
- HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "unable to allocate memory block of %llu bytes", (unsigned long long)new_eof)
+ /* (Re)allocate memory for the file buffer, using callbacks if available */
+ if(file->fi_callbacks.image_realloc) {
+ if(NULL == (x = (unsigned char *)file->fi_callbacks.image_realloc(file->mem, new_eof, H5FD_FILE_IMAGE_OP_FILE_RESIZE, file->fi_callbacks.udata)))
+ HGOTO_ERROR(H5E_FILE, H5E_CANTALLOC, FAIL, "unable to allocate memory block of %llu bytes with callback", (unsigned long long)new_eof)
+ } /* end if */
+ else {
+ if(NULL == (x = (unsigned char *)H5MM_realloc(file->mem, new_eof)))
+ HGOTO_ERROR(H5E_FILE, H5E_CANTALLOC, FAIL, "unable to allocate memory block of %llu bytes", (unsigned long long)new_eof)
+ } /* end else */
+
#ifdef H5_CLEAR_MEMORY
HDmemset(x + file->eof, 0, (size_t)(new_eof - file->eof));
#endif /* H5_CLEAR_MEMORY */
@@ -989,6 +1051,8 @@ HDmemset(x + file->eof, 0, (size_t)(new_eof - file->eof));
/* Write from BUF to memory */
HDmemcpy(file->mem + addr, buf, size);
+
+ /* Mark memory buffer as modified */
file->dirty = TRUE;
done:
@@ -1075,6 +1139,28 @@ done:
* Purpose: Makes sure that the true file size is the same (or larger)
* than the end-of-address.
*
+ * Addendum -- 12/2/11
+ * For file images opened with the core file driver, it is
+ * necessary that we avoid reallocating the core file driver's
+ * buffer uneccessarily.
+ *
+ * To this end, I have made the following functional changes
+ * to this function.
+ *
+ * If we are closing, and there is no backing store, this
+ * function becomes a no-op.
+ *
+ * If we are closing, and there is backing store, we set the
+ * eof to equal the eoa, and truncate the backing store to
+ * the new eof
+ *
+ * If we are not closing, we realloc the buffer to size equal
+ * to the smallest multiple of the allocation increment that
+ * equals or exceeds the eoa and set the eof accordingly.
+ * Note that we no longer truncate the backing store to the
+ * new eof if applicable.
+ * -- JRM
+ *
* Return: Success: Non-negative
* Failure: Negative
*
@@ -1085,7 +1171,7 @@ done:
*/
/* ARGSUSED */
static herr_t
-H5FD_core_truncate(H5FD_t *_file, hid_t UNUSED dxpl_id, hbool_t UNUSED closing)
+H5FD_core_truncate(H5FD_t *_file, hid_t UNUSED dxpl_id, hbool_t closing)
{
H5FD_core_t *file = (H5FD_core_t*)_file;
size_t new_eof; /* New size of memory buffer */
@@ -1095,68 +1181,83 @@ H5FD_core_truncate(H5FD_t *_file, hid_t UNUSED dxpl_id, hbool_t UNUSED closing)
HDassert(file);
- /* Determine new size of memory buffer */
- H5_ASSIGN_OVERFLOW(new_eof, file->increment * (file->eoa / file->increment), hsize_t, size_t);
- if(file->eoa % file->increment)
- new_eof += file->increment;
-
- /* Extend the file to make sure it's large enough */
- if(!H5F_addr_eq(file->eof, (haddr_t)new_eof)) {
- unsigned char *x; /* Pointer to new buffer for file data */
+ /* if we are closing and not using backing store, do nothing */
+ if(!closing || file->backing_store) {
+ if(closing) /* set eof to eoa */
+ new_eof = file->eoa;
+ else { /* set eof to smallest multiple of increment that exceeds eoa */
+ /* Determine new size of memory buffer */
+ H5_ASSIGN_OVERFLOW(new_eof, file->increment * (file->eoa / file->increment), hsize_t, size_t);
+ if(file->eoa % file->increment)
+ new_eof += file->increment;
+ } /* end else */
+
+ /* Extend the file to make sure it's large enough */
+ if(!H5F_addr_eq(file->eof, (haddr_t)new_eof)) {
+ unsigned char *x; /* Pointer to new buffer for file data */
+
+ /* (Re)allocate memory for the file buffer, using callback if available */
+ if(file->fi_callbacks.image_realloc) {
+ if(NULL == (x = (unsigned char *)file->fi_callbacks.image_realloc(file->mem, new_eof, H5FD_FILE_IMAGE_OP_FILE_RESIZE, file->fi_callbacks.udata)))
+ HGOTO_ERROR(H5E_FILE, H5E_CANTALLOC, FAIL, "unable to allocate memory block with callback")
+ } /* end if */
+ else {
+ if(NULL == (x = (unsigned char *)H5MM_realloc(file->mem, new_eof)))
+ HGOTO_ERROR(H5E_FILE, H5E_CANTALLOC, FAIL, "unable to allocate memory block")
+ } /* end else */
- /* (Re)allocate memory for the file buffer */
- if(NULL == (x = (unsigned char *)H5MM_realloc(file->mem, new_eof)))
- HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "unable to allocate memory block")
#ifdef H5_CLEAR_MEMORY
-if(file->eof < new_eof)
- HDmemset(x + file->eof, 0, (size_t)(new_eof - file->eof));
+ if(file->eof < new_eof)
+ HDmemset(x + file->eof, 0, (size_t)(new_eof - file->eof));
#endif /* H5_CLEAR_MEMORY */
- file->mem = x;
+ file->mem = x;
- /* Update backing store, if using it */
- if(file->fd >= 0 && file->backing_store) {
+ /* Update backing store, if using it and if closing */
+ if(closing && (file->fd >= 0) && file->backing_store) {
#ifdef H5_HAVE_WIN32_API
- LARGE_INTEGER li; /* 64-bit (union) integer for SetFilePointer() call */
- DWORD dwPtrLow; /* Low-order pointer bits from SetFilePointer()
- * Only used as an error code here.
- */
- DWORD dwError; /* DWORD error code from GetLastError() */
- BOOL bError; /* Boolean error flag */
-
- /* Windows uses this odd QuadPart union for 32/64-bit portability */
- li.QuadPart = (__int64)file->eoa;
-
- /* Extend the file to make sure it's large enough.
- *
- * Since INVALID_SET_FILE_POINTER can technically be a valid return value
- * from SetFilePointer(), we also need to check GetLastError().
- */
- dwPtrLow = SetFilePointer(file->hFile, li.LowPart, &li.HighPart, FILE_BEGIN);
- if(INVALID_SET_FILE_POINTER == dwPtrLow) {
- dwError = GetLastError();
- if(dwError != NO_ERROR )
- HGOTO_ERROR(H5E_FILE, H5E_FILEOPEN, FAIL, "unable to set file pointer")
- }
-
- bError = SetEndOfFile(file->hFile);
- if(0 == bError)
- HGOTO_ERROR(H5E_IO, H5E_SEEKERROR, FAIL, "unable to extend file properly")
+ LARGE_INTEGER li; /* 64-bit (union) integer for SetFilePointer() call */
+ DWORD dwPtrLow; /* Low-order pointer bits from SetFilePointer()
+ * Only used as an error code here.
+ */
+ DWORD dwError; /* DWORD error code from GetLastError() */
+ BOOL bError; /* Boolean error flag */
+
+ /* Windows uses this odd QuadPart union for 32/64-bit portability */
+ li.QuadPart = (__int64)file->eoa;
+
+ /* Extend the file to make sure it's large enough.
+ *
+ * Since INVALID_SET_FILE_POINTER can technically be a valid return value
+ * from SetFilePointer(), we also need to check GetLastError().
+ */
+ dwPtrLow = SetFilePointer(file->hFile, li.LowPart, &li.HighPart, FILE_BEGIN);
+ if(INVALID_SET_FILE_POINTER == dwPtrLow) {
+ dwError = GetLastError();
+ if(dwError != NO_ERROR )
+ HGOTO_ERROR(H5E_FILE, H5E_FILEOPEN, FAIL, "unable to set file pointer")
+ }
+
+ bError = SetEndOfFile(file->hFile);
+ if(0 == bError)
+ HGOTO_ERROR(H5E_IO, H5E_SEEKERROR, FAIL, "unable to extend file properly")
#else /* H5_HAVE_WIN32_API */
#ifdef H5_VMS
- /* Reset seek offset to the beginning of the file, so that the file isn't
- * re-extended later. This may happen on Open VMS. */
- if(-1 == HDlseek(file->fd, (HDoff_t)0, SEEK_SET))
- HSYS_GOTO_ERROR(H5E_IO, H5E_SEEKERROR, FAIL, "unable to seek to proper position")
+ /* Reset seek offset to the beginning of the file, so that the file isn't
+ * re-extended later. This may happen on Open VMS. */
+ if(-1 == HDlseek(file->fd, (HDoff_t)0, SEEK_SET))
+ HSYS_GOTO_ERROR(H5E_IO, H5E_SEEKERROR, FAIL, "unable to seek to proper position")
#endif /* H5_VMS */
- if(-1 == HDftruncate(file->fd, (HDoff_t)new_eof))
- HSYS_GOTO_ERROR(H5E_IO, H5E_SEEKERROR, FAIL, "unable to extend file properly")
+ if(-1 == HDftruncate(file->fd, (HDoff_t)new_eof))
+ HSYS_GOTO_ERROR(H5E_IO, H5E_SEEKERROR, FAIL, "unable to extend file properly")
#endif /* H5_HAVE_WIN32_API */
- } /* end if */
+ } /* end if */
- /* Update the eof value */
- file->eof = new_eof;
- } /* end if */
+ /* Update the eof value */
+ file->eof = new_eof;
+ } /* end if */
+ } /* end if(file->eof < file->eoa) */
done:
FUNC_LEAVE_NOAPI(ret_value)
} /* end H5FD_core_truncate() */
+
diff --git a/src/H5FDfamily.c b/src/H5FDfamily.c
index 17683ce..6f6d757 100644
--- a/src/H5FDfamily.c
+++ b/src/H5FDfamily.c
@@ -995,7 +995,7 @@ H5FD_family_query(const H5FD_t * _file, unsigned long *flags /* out */)
*flags |= H5FD_FEAT_AGGREGATE_SMALLDATA; /* OK to aggregate "small" raw data allocations */
/* Check for flags that are set by h5repart */
- if(file->repart_members)
+ if(file && file->repart_members)
*flags |= H5FD_FEAT_DIRTY_SBLK_LOAD; /* Mark the superblock dirty when it is loaded (so the family member sizes are rewritten) */
} /* end if */
diff --git a/src/H5FDlog.c b/src/H5FDlog.c
index cb5ce3c..0b5c677 100644
--- a/src/H5FDlog.c
+++ b/src/H5FDlog.c
@@ -918,7 +918,7 @@ H5FD_log_query(const H5FD_t *_file, unsigned long *flags /* out */)
*flags |= H5FD_FEAT_POSIX_COMPAT_HANDLE; /* VFD handle is POSIX I/O call compatible */
/* Check for flags that are set by h5repart */
- if(file->fam_to_sec2)
+ if(file && file->fam_to_sec2)
*flags |= H5FD_FEAT_IGNORE_DRVRINFO; /* Ignore the driver info when file is opened (which eliminates it) */
} /* end if */
diff --git a/src/H5FDprivate.h b/src/H5FDprivate.h
index 4f7d059..9c19562 100644
--- a/src/H5FDprivate.h
+++ b/src/H5FDprivate.h
@@ -52,6 +52,29 @@ typedef enum {
} H5FD_file_op_t;
+/* Define structure to hold initial file image and other relevant information */
+typedef struct {
+ void *buffer;
+ size_t size;
+ H5FD_file_image_callbacks_t callbacks;
+} H5FD_file_image_info_t;
+
+/* Define default file image info */
+#define H5FD_DEFAULT_FILE_IMAGE_INFO { \
+ /* file image buffer */ NULL, \
+ /* buffer size */ 0, \
+ { /* Callbacks */ \
+ /* image_malloc */ NULL, \
+ /* image_memcpy */ NULL, \
+ /* image_realloc */ NULL, \
+ /* image_free */ NULL, \
+ /* udata_copy */ NULL, \
+ /* udata_free */ NULL, \
+ /* udata */ NULL, \
+ } \
+}
+
+
/*****************************/
/* Library Private Variables */
/*****************************/
@@ -72,17 +95,14 @@ H5_DLL herr_t H5FD_sb_encode(H5FD_t *file, char *name/*out*/, uint8_t *buf);
H5_DLL herr_t H5FD_sb_decode(H5FD_t *file, const char *name, const uint8_t *buf);
H5_DLL void *H5FD_fapl_get(H5FD_t *file);
H5_DLL herr_t H5FD_fapl_open(struct H5P_genplist_t *plist, hid_t driver_id, const void *driver_info);
-H5_DLL herr_t H5FD_fapl_copy(hid_t driver_id, const void *fapl, void **copied_fapl);
H5_DLL herr_t H5FD_fapl_close(hid_t driver_id, void *fapl);
H5_DLL herr_t H5FD_dxpl_open(struct H5P_genplist_t *plist, hid_t driver_id, const void *driver_info);
-H5_DLL herr_t H5FD_dxpl_copy(hid_t driver_id, const void *dxpl, void **copied_dxpl);
H5_DLL herr_t H5FD_dxpl_close(hid_t driver_id, void *dxpl);
H5_DLL hid_t H5FD_register(const void *cls, size_t size, hbool_t app_ref);
H5_DLL H5FD_t *H5FD_open(const char *name, unsigned flags, hid_t fapl_id,
haddr_t maxaddr);
H5_DLL herr_t H5FD_close(H5FD_t *file);
H5_DLL int H5FD_cmp(const H5FD_t *f1, const H5FD_t *f2);
-H5_DLL int H5FD_query(const H5FD_t *f, unsigned long *flags/*out*/);
H5_DLL haddr_t H5FD_alloc(H5FD_t *file, hid_t dxpl_id, H5FD_mem_t type, struct H5F_t *f,
hsize_t size, haddr_t *align_addr, hsize_t *align_size);
H5_DLL herr_t H5FD_free(H5FD_t *file, hid_t dxpl_id, H5FD_mem_t type, struct H5F_t *f,
diff --git a/src/H5FDpublic.h b/src/H5FDpublic.h
index f495e2d..ab19c68 100644
--- a/src/H5FDpublic.h
+++ b/src/H5FDpublic.h
@@ -222,6 +222,19 @@ typedef enum H5F_mem_t H5FD_mem_t;
* instead of the default H5D_ALLOC_TIME_LATE
*/
#define H5FD_FEAT_ALLOCATE_EARLY 0x00000200
+ /*
+ * Defining the H5FD_FEAT_ALLOW_FILE_IMAGE for a VFL driver means that
+ * the driver is able to use a file image in the fapl as the initial
+ * contents of a file.
+ */
+#define H5FD_FEAT_ALLOW_FILE_IMAGE 0x00000400
+ /*
+ * Defining the H5FD_FEAT_CAN_USE_FILE_IMAGE_CALLBACKS for a VFL driver
+ * means that the driver is able to use callbacks to make a copy of the
+ * image to store in memory.
+ */
+#define H5FD_FEAT_CAN_USE_FILE_IMAGE_CALLBACKS 0x00000800
+
/* Forward declaration */
typedef struct H5FD_t H5FD_t;
@@ -291,6 +304,33 @@ struct H5FD_t {
hsize_t alignment; /* Allocation alignment */
};
+/* Define enum for the source of file image callbacks */
+typedef enum {
+ H5FD_FILE_IMAGE_OP_NO_OP,
+ H5FD_FILE_IMAGE_OP_PROPERTY_LIST_SET,
+ H5FD_FILE_IMAGE_OP_PROPERTY_LIST_COPY,
+ H5FD_FILE_IMAGE_OP_PROPERTY_LIST_GET,
+ H5FD_FILE_IMAGE_OP_PROPERTY_LIST_CLOSE,
+ H5FD_FILE_IMAGE_OP_FILE_OPEN,
+ H5FD_FILE_IMAGE_OP_FILE_RESIZE,
+ H5FD_FILE_IMAGE_OP_FILE_CLOSE,
+} H5FD_file_image_op_t;
+
+/* Define structure to hold file image callbacks */
+typedef struct {
+ void *(*image_malloc)(size_t size, H5FD_file_image_op_t file_image_op,
+ void *udata);
+ void *(*image_memcpy)(void *dest, const void *src, size_t size,
+ H5FD_file_image_op_t file_image_op, void *udata);
+ void *(*image_realloc)(void *ptr, size_t size,
+ H5FD_file_image_op_t file_image_op, void *udata);
+ herr_t (*image_free)(void *ptr, H5FD_file_image_op_t file_image_op,
+ void *udata);
+ void *(*udata_copy)(void *udata);
+ herr_t (*udata_free)(void *udata);
+ void *udata;
+} H5FD_file_image_callbacks_t;
+
#ifdef __cplusplus
extern "C" {
#endif
diff --git a/src/H5FDsec2.c b/src/H5FDsec2.c
index 6d4a76a..4201e07 100644
--- a/src/H5FDsec2.c
+++ b/src/H5FDsec2.c
@@ -560,7 +560,7 @@ H5FD_sec2_query(const H5FD_t *_file, unsigned long *flags /* out */)
*flags |= H5FD_FEAT_POSIX_COMPAT_HANDLE; /* VFD handle is POSIX I/O call compatible */
/* Check for flags that are set by h5repart */
- if(file->fam_to_sec2)
+ if(file && file->fam_to_sec2)
*flags |= H5FD_FEAT_IGNORE_DRVRINFO; /* Ignore the driver info when file is opened (which eliminates it) */
} /* end if */
diff --git a/src/H5Fprivate.h b/src/H5Fprivate.h
index 868674f..40e075b 100644
--- a/src/H5Fprivate.h
+++ b/src/H5Fprivate.h
@@ -417,6 +417,7 @@ typedef struct H5F_blk_aggr_t H5F_blk_aggr_t;
#define H5F_ACS_LATEST_FORMAT_NAME "latest_format" /* 'Use latest format version' flag */
#define H5F_ACS_WANT_POSIX_FD_NAME "want_posix_fd" /* Internal: query the file descriptor from the core VFD, instead of the memory address */
#define H5F_ACS_EFC_SIZE_NAME "efc_size" /* Size of external file cache */
+#define H5F_ACS_FILE_IMAGE_INFO_NAME "file_image_info" /* struct containing initial file image and callback info */
/* ======================== File Mount properties ====================*/
#define H5F_MNT_SYM_LOCAL_NAME "local" /* Whether absolute symlinks local to file. */
@@ -528,8 +529,8 @@ H5_DLL H5F_t *H5F_get_parent(const H5F_t *f);
H5_DLL unsigned H5F_get_nmounts(const H5F_t *f);
H5_DLL hid_t H5F_get_access_plist(H5F_t *f, hbool_t app_ref);
H5_DLL hid_t H5F_get_id(H5F_t *file, hbool_t app_ref);
-H5_DLL size_t H5F_get_obj_count(const H5F_t *f, unsigned types, hbool_t app_ref);
-H5_DLL size_t H5F_get_obj_ids(const H5F_t *f, unsigned types, size_t max_objs, hid_t *obj_id_list, hbool_t app_ref);
+H5_DLL herr_t H5F_get_obj_count(const H5F_t *f, unsigned types, hbool_t app_ref, size_t *obj_id_count_ptr);
+H5_DLL herr_t H5F_get_obj_ids(const H5F_t *f, unsigned types, size_t max_objs, hid_t *oid_list, hbool_t app_ref, size_t *obj_id_count_ptr);
/* Functions than retrieve values set/cached from the superblock/FCPL */
H5_DLL haddr_t H5F_get_base_addr(const H5F_t *f);
diff --git a/src/H5Fpublic.h b/src/H5Fpublic.h
index d88538b..f32b3e0 100644
--- a/src/H5Fpublic.h
+++ b/src/H5Fpublic.h
@@ -192,6 +192,7 @@ H5_DLL herr_t H5Fmount(hid_t loc, const char *name, hid_t child, hid_t plist);
H5_DLL herr_t H5Funmount(hid_t loc, const char *name);
H5_DLL hssize_t H5Fget_freespace(hid_t file_id);
H5_DLL herr_t H5Fget_filesize(hid_t file_id, hsize_t *size);
+H5_DLL ssize_t H5Fget_file_image(hid_t file_id, void * buf_ptr, size_t buf_len);
H5_DLL herr_t H5Fget_mdc_config(hid_t file_id,
H5AC_cache_config_t * config_ptr);
H5_DLL herr_t H5Fset_mdc_config(hid_t file_id,
diff --git a/src/H5Gname.c b/src/H5Gname.c
index 62875dc..576d866 100644
--- a/src/H5Gname.c
+++ b/src/H5Gname.c
@@ -782,7 +782,7 @@ done:
/*-------------------------------------------------------------------------
* Function: H5G_name_replace_cb
*
- * Purpose: H5I_search callback function to replace group entry names
+ * Purpose: H5I_iterate callback function to replace group entry names
*
* Return: Success: 0, Failure: -1
*
@@ -1166,15 +1166,18 @@ H5G_name_replace(const H5O_link_t *lnk, H5G_names_op_t op, H5F_t *src_file,
/* Search through group IDs */
if(search_group)
- H5I_search(H5I_GROUP, H5G_name_replace_cb, &names, FALSE);
+ if(H5I_iterate(H5I_GROUP, H5G_name_replace_cb, &names, FALSE) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_BADITER, FAIL, "can't iterate over groups")
/* Search through dataset IDs */
if(search_dataset)
- H5I_search(H5I_DATASET, H5G_name_replace_cb, &names, FALSE);
+ if(H5I_iterate(H5I_DATASET, H5G_name_replace_cb, &names, FALSE) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_BADITER, FAIL, "can't iterate over datasets")
/* Search through datatype IDs */
if(search_datatype)
- H5I_search(H5I_DATATYPE, H5G_name_replace_cb, &names, FALSE);
+ if(H5I_iterate(H5I_DATATYPE, H5G_name_replace_cb, &names, FALSE) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_BADITER, FAIL, "can't iterate over datatypes")
} /* end if */
} /* end if */
diff --git a/src/H5I.c b/src/H5I.c
index 09d5dde..0382e8e 100644
--- a/src/H5I.c
+++ b/src/H5I.c
@@ -108,6 +108,11 @@ typedef struct {
H5I_id_info_t **id_list; /*pointer to an array of ptrs to IDs */
} H5I_id_type_t;
+typedef struct {
+ H5I_search_func_t app_cb; /* Application's callback routine */
+ void *app_key; /* Application's "key" (user data) */
+ void *ret_obj; /* Object to return */
+} H5I_search_ud_t;
/*-------------------- Locally scoped variables -----------------------------*/
@@ -127,6 +132,7 @@ H5FL_DEFINE_STATIC(H5I_id_info_t);
/*--------------------- Local function prototypes ---------------------------*/
static H5I_id_info_t *H5I_find_id(hid_t id);
+static int H5I_search_cb(void *obj, hid_t id, void *udata);
#ifdef H5I_DEBUG_OUTPUT
static herr_t H5I_debug(H5I_type_t type);
#endif /* H5I_DEBUG_OUTPUT */
@@ -1905,6 +1911,40 @@ done:
/*-------------------------------------------------------------------------
+ * Function: H5I_search_cb
+ *
+ * Purpose: Callback routine for H5Isearch, when it calls H5I_iterate.
+ * Calls "user" callback search function, and then sets return
+ * value, based on the result of that callback.
+ *
+ * Return: Success: The first object in the type for which FUNC
+ * returns non-zero. NULL if FUNC returned zero
+ * for every object in the type.
+ * Failure: NULL
+ *
+ * Programmer: Quincey Koziol
+ * Friday, March 30, 2012
+ *
+ *-------------------------------------------------------------------------
+ */
+static int
+H5I_search_cb(void *obj, hid_t id, void *_udata)
+{
+ H5I_search_ud_t *udata = (H5I_search_ud_t *)_udata; /* User data for callback */
+ int ret_value; /* Callback return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ ret_value = (*udata->app_cb)(obj, id, udata->app_key);
+ if(ret_value > 0)
+ udata->ret_obj = obj;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5I_search_cb() */
+
+
+/*-------------------------------------------------------------------------
* Function: H5Isearch
*
* Purpose: Apply function FUNC to each member of type TYPE and return a
@@ -1931,14 +1971,27 @@ done:
void *
H5Isearch(H5I_type_t type, H5I_search_func_t func, void *key)
{
- void * ret_value; /* Return value */
+ H5I_search_ud_t udata; /* Context for iteration */
+ void *ret_value; /* Return value */
FUNC_ENTER_API(NULL)
+ /* Check arguments */
if(H5I_IS_LIB_TYPE(type))
HGOTO_ERROR(H5E_ATOM, H5E_BADGROUP, NULL, "cannot call public function on library type")
- ret_value = H5I_search(type, func, key, TRUE);
+ /* Set up udata struct */
+ udata.app_cb = func;
+ udata.app_key = key;
+ udata.ret_obj = NULL;
+
+ /* Note that H5I_iterate returns an error code. We ignore it
+ * here, as we can't do anything with it without revising the API.
+ */
+ H5I_iterate(type, H5I_search_cb, &udata, TRUE);
+
+ /* Set return value */
+ ret_value = udata.ret_obj;
done:
FUNC_LEAVE_API(ret_value)
@@ -1946,62 +1999,71 @@ done:
/*-------------------------------------------------------------------------
- * Function: H5I_search
+ * Function: H5I_iterate
*
- * Purpose: Apply function FUNC to each member of type TYPE and return a
- * pointer to the first object for which FUNC returns non-zero.
- * The FUNC should take a pointer to the object and the KEY as
- * arguments and return non-zero to terminate the search (zero
- * to continue).
+ * Purpose: Apply function FUNC to each member of type TYPE (with
+ * non-zero application reference count if app_ref is TRUE).
+ * Stop if FUNC returns a non zero value (i.e. anything
+ * other than H5_ITER_CONT).
*
- * Limitation: Currently there is no way to start searching from where a
- * previous search left off.
+ * If FUNC returns a positive value (i.e. H5_ITER_STOP),
+ * return SUCCEED.
*
- * Return: Success: The first object in the type for which FUNC
- * returns non-zero. NULL if FUNC returned zero
- * for every object in the type.
- * Failure: NULL
+ * If FUNC returns a negative value (i.e. H5_ITER_ERROR),
+ * return FAIL.
+ *
+ * The FUNC should take a pointer to the object and the
+ * udata as arguments and return non-zero to terminate
+ * siteration, and zero to continue.
*
- * Programmer: Robb Matzke
- * Friday, February 19, 1999
+ * Limitation: Currently there is no way to start the iteration from
+ * where a previous iteration left off.
+ *
+ * Return: Success: SUCCEED
+ * Failure: FAIL
*
- * Modifications: Neil Fortner
- * Wednesday, October 1, 2008
- * Added app_ref parameter. When set to TRUE, the function will only
- * operate on ids that have a nonzero application reference count.
+ * Programmer: John Mainzer
+ * Monday, December 6, 2011
*
*-------------------------------------------------------------------------
*/
-void *
-H5I_search(H5I_type_t type, H5I_search_func_t func, void *key, hbool_t app_ref)
+herr_t
+H5I_iterate(H5I_type_t type, H5I_search_func_t func, void *udata, hbool_t app_ref)
{
- H5I_id_type_t *type_ptr; /*ptr to the type */
- void *ret_value = NULL; /*return value */
+ H5I_id_type_t *type_ptr; /*ptr to the type */
+ herr_t ret_value = SUCCEED; /*return value */
- FUNC_ENTER_NOAPI(NULL)
+ FUNC_ENTER_NOAPI(FAIL)
/* Check arguments */
if(type <= H5I_BADID || type >= H5I_next_type)
- HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, NULL, "invalid type number")
+ HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, FAIL, "invalid type number")
type_ptr = H5I_id_type_list_g[type];
- if(type_ptr == NULL || type_ptr->count <= 0)
- HGOTO_ERROR(H5E_ATOM, H5E_BADGROUP, NULL, "invalid type")
- /* Only iterate through hash table if there are IDs in group */
- if(type_ptr->ids > 0) {
- H5I_id_info_t *id_ptr; /*ptr to the new ID */
- H5I_id_info_t *next_id; /*ptr to the next ID */
- unsigned i; /*counter */
+ /* Only iterate through hash table if it is initialized and there are IDs in group */
+ if(type_ptr && type_ptr->count > 0 && type_ptr->ids > 0) {
+ unsigned u; /* Counter */
/* Start at the beginning of the array */
- for(i = 0; i < type_ptr->hash_size; i++) {
- id_ptr = type_ptr->id_list[i];
+ for(u = 0; u < type_ptr->hash_size; u++) {
+ H5I_id_info_t *id_ptr; /* Ptr to the new ID */
+
+ id_ptr = type_ptr->id_list[u];
while(id_ptr) {
- next_id = id_ptr->next; /* Protect against ID being deleted in callback */
- /* (Casting away const OK -QAK) */
- if((!app_ref || id_ptr->app_count) && (*func)((void *)id_ptr->obj_ptr, id_ptr->id, key))
- /* (Casting away const OK -QAK) */
- HGOTO_DONE((void *)id_ptr->obj_ptr); /*found the item*/
+ H5I_id_info_t *next_id; /* Ptr to the next ID */
+
+ /* Protect against ID being deleted in callback */
+ next_id = id_ptr->next;
+ if((!app_ref) || (id_ptr->app_count > 0)) {
+ herr_t cb_ret_val; /* Callback return value */
+
+ /* (Casting away const OK) */
+ cb_ret_val = (*func)((void *)id_ptr->obj_ptr, id_ptr->id, udata);
+ if(cb_ret_val > 0)
+ HGOTO_DONE(SUCCEED) /* terminate iteration early */
+ else if(cb_ret_val < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, FAIL, "func failed")
+ } /* end if */
id_ptr = next_id;
} /* end while */
} /* end for */
@@ -2009,7 +2071,7 @@ H5I_search(H5I_type_t type, H5I_search_func_t func, void *key, hbool_t app_ref)
done:
FUNC_LEAVE_NOAPI(ret_value)
-} /* end H5I_search() */
+} /* end H5I_iterate() */
/*-------------------------------------------------------------------------
diff --git a/src/H5Iprivate.h b/src/H5Iprivate.h
index 98423df..bc0ef41 100644
--- a/src/H5Iprivate.h
+++ b/src/H5Iprivate.h
@@ -62,7 +62,7 @@ H5_DLL H5I_type_t H5I_get_type(hid_t id);
H5_DLL hid_t H5I_get_file_id(hid_t obj_id, hbool_t app_ref);
H5_DLL void *H5I_remove(hid_t id);
H5_DLL void *H5I_remove_verify(hid_t id, H5I_type_t id_type);
-H5_DLL void *H5I_search(H5I_type_t type, H5I_search_func_t func, void *key, hbool_t app_ref);
+H5_DLL herr_t H5I_iterate(H5I_type_t type, H5I_search_func_t func, void *udata, hbool_t app_ref);
H5_DLL int H5I_get_ref(hid_t id, hbool_t app_ref);
H5_DLL int H5I_inc_ref(hid_t id, hbool_t app_ref);
H5_DLL int H5I_dec_ref(hid_t id);
diff --git a/src/H5Oattribute.c b/src/H5Oattribute.c
index 055fb69..30ec732 100644
--- a/src/H5Oattribute.c
+++ b/src/H5Oattribute.c
@@ -703,18 +703,23 @@ H5O_attr_find_opened_attr(const H5O_loc_t *loc, H5A_t **attr, const char* name_t
HGOTO_ERROR(H5E_ATTR, H5E_BADVALUE, FAIL, "can't get file serial number")
/* Count all opened attributes */
- num_open_attr = H5F_get_obj_count(loc->file, H5F_OBJ_ATTR | H5F_OBJ_LOCAL, FALSE);
+ if(H5F_get_obj_count(loc->file, H5F_OBJ_ATTR | H5F_OBJ_LOCAL, FALSE, &num_open_attr) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTGET, FAIL, "can't count opened attributes")
/* Find out whether the attribute has been opened */
if(num_open_attr) {
+ size_t check_num_attr; /* Number of open attribute IDs */
size_t u; /* Local index variable */
/* Allocate space for the attribute ID list */
if(NULL == (attr_id_list = (hid_t *)H5MM_malloc(num_open_attr * sizeof(hid_t))))
- HGOTO_ERROR(H5E_ATTR, H5E_NOSPACE, FAIL, "unable to allocate memory for attribute ID list")
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTALLOC, FAIL, "unable to allocate memory for attribute ID list")
/* Retrieve the IDs of all opened attributes */
- H5F_get_obj_ids(loc->file, H5F_OBJ_ATTR | H5F_OBJ_LOCAL, num_open_attr, attr_id_list, FALSE);
+ if(H5F_get_obj_ids(loc->file, H5F_OBJ_ATTR | H5F_OBJ_LOCAL, num_open_attr, attr_id_list, FALSE, &check_num_attr) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTGET, FAIL, "can't get IDs of opened attributes")
+ if(check_num_attr != num_open_attr)
+ HGOTO_ERROR(H5E_INTERNAL, H5E_BADITER, FAIL, "open attribute count mismatch")
/* Iterate over the attributes */
for(u = 0; u < num_open_attr; u++) {
diff --git a/src/H5Pfapl.c b/src/H5Pfapl.c
index c3371c9..7f72c85 100644
--- a/src/H5Pfapl.c
+++ b/src/H5Pfapl.c
@@ -40,6 +40,7 @@
#include "H5Fprivate.h" /* Files */
#include "H5FDprivate.h" /* File drivers */
#include "H5Iprivate.h" /* IDs */
+#include "H5MMprivate.h" /* Memory Management */
#include "H5Ppkg.h" /* Property lists */
/* Includes needed to set as default file driver */
@@ -122,6 +123,12 @@
/* Definition for external file cache size */
#define H5F_ACS_EFC_SIZE_SIZE sizeof(unsigned)
#define H5F_ACS_EFC_SIZE_DEF 0
+/* Definition of pointer to initial file image info */
+#define H5F_ACS_FILE_IMAGE_INFO_SIZE sizeof(H5FD_file_image_info_t)
+#define H5F_ACS_FILE_IMAGE_INFO_DEF H5FD_DEFAULT_FILE_IMAGE_INFO
+#define H5F_ACS_FILE_IMAGE_INFO_DEL H5P_file_image_info_del
+#define H5F_ACS_FILE_IMAGE_INFO_COPY H5P_file_image_info_copy
+#define H5F_ACS_FILE_IMAGE_INFO_CLOSE H5P_file_image_info_close
/******************/
@@ -149,6 +156,10 @@ static herr_t H5P_facc_reg_prop(H5P_genclass_t *pclass);
static herr_t H5P_facc_create(hid_t fapl_id, void *copy_data);
static herr_t H5P_facc_copy(hid_t new_plist_t, hid_t old_plist_t, void *copy_data);
+/* File image info property callbacks */
+static herr_t H5P_file_image_info_del(hid_t prop_id, const char *name, size_t size, void *value);
+static herr_t H5P_file_image_info_copy(const char *name, size_t size, void *value);
+static herr_t H5P_file_image_info_close(const char *name, size_t size, void *value);
/*********************/
/* Package Variables */
@@ -215,6 +226,7 @@ H5P_facc_reg_prop(H5P_genclass_t *pclass)
hbool_t latest_format = H5F_ACS_LATEST_FORMAT_DEF; /* Default setting for "use the latest version of the format" flag */
hbool_t want_posix_fd = H5F_ACS_WANT_POSIX_FD_DEF; /* Default setting for retrieving 'handle' from core VFD */
unsigned efc_size = H5F_ACS_EFC_SIZE_DEF; /* Default external file cache size */
+ H5FD_file_image_info_t file_image_info = H5F_ACS_FILE_IMAGE_INFO_DEF; /* Default file image info and callbacks */
herr_t ret_value = SUCCEED; /* Return value */
FUNC_ENTER_NOAPI_NOINIT
@@ -300,6 +312,10 @@ H5P_facc_reg_prop(H5P_genclass_t *pclass)
if(H5P_register_real(pclass, H5F_ACS_EFC_SIZE_NAME, H5F_ACS_EFC_SIZE_SIZE, &efc_size, NULL, NULL, NULL, NULL, NULL, NULL, NULL) < 0)
HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "can't insert property into class")
+ /* Register the initial file image info */
+ if(H5P_register_real(pclass, H5F_ACS_FILE_IMAGE_INFO_NAME, H5F_ACS_FILE_IMAGE_INFO_SIZE, &file_image_info, NULL, NULL, NULL, H5F_ACS_FILE_IMAGE_INFO_DEL, H5F_ACS_FILE_IMAGE_INFO_COPY, NULL, H5F_ACS_FILE_IMAGE_INFO_CLOSE) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "can't insert property into class")
+
done:
FUNC_LEAVE_NOAPI(ret_value)
} /* end H5P_facc_reg_prop() */
@@ -2101,3 +2117,484 @@ done:
FUNC_LEAVE_API(ret_value)
} /* end H5Pget_elink_file_cache_size() */
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pset_file_image
+ *
+ * Purpose: Sets the initial file image. Some file drivers can initialize
+ * the starting data in a file from a buffer.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Jacob Gruber
+ * Thurday, August 11, 2011
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pset_file_image(hid_t fapl_id, void *buf_ptr, size_t buf_len)
+{
+ H5P_genplist_t *fapl; /* Property list pointer */
+ H5FD_file_image_info_t image_info; /* File image info */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE3("e", "i*xz", fapl_id, buf_ptr, buf_len);
+
+ /* validate parameters */
+ if(!(((buf_ptr == NULL) && (buf_len == 0)) || ((buf_ptr != NULL) && (buf_len > 0))))
+ HGOTO_ERROR (H5E_ARGS, H5E_BADVALUE, FAIL, "inconsistant buf_ptr and buf_len");
+
+ /* Get the plist structure */
+ if(NULL == (fapl = H5P_object_verify(fapl_id, H5P_FILE_ACCESS)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ /* Get old image info */
+ if(H5P_get(fapl, H5F_ACS_FILE_IMAGE_INFO_NAME, &image_info) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get old file image pointer")
+
+ /* Release previous buffer, if it exists */
+ if(image_info.buffer != NULL) {
+ if(image_info.callbacks.image_free) {
+ if(SUCCEED != image_info.callbacks.image_free(image_info.buffer, H5FD_FILE_IMAGE_OP_PROPERTY_LIST_SET, image_info.callbacks.udata))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTFREE, FAIL, "image_free callback failed")
+ } /* end if */
+ else
+ H5MM_xfree(image_info.buffer);
+ } /* end if */
+
+ /* Update struct */
+ if(buf_ptr) {
+ /* Allocate memory */
+ if(image_info.callbacks.image_malloc) {
+ if(NULL == (image_info.buffer = image_info.callbacks.image_malloc(buf_len,
+ H5FD_FILE_IMAGE_OP_PROPERTY_LIST_SET, image_info.callbacks.udata)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "image malloc callback failed")
+ } /* end if */
+ else
+ if(NULL == (image_info.buffer = H5MM_malloc(buf_len)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "unable to allocate memory block")
+
+ /* Copy data */
+ if(image_info.callbacks.image_memcpy) {
+ if(image_info.buffer != image_info.callbacks.image_memcpy(image_info.buffer,
+ buf_ptr, buf_len, H5FD_FILE_IMAGE_OP_PROPERTY_LIST_SET,
+ image_info.callbacks.udata))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTCOPY, FAIL, "image_memcpy callback failed")
+ } /* end if */
+ else
+ HDmemcpy(image_info.buffer, buf_ptr, buf_len);
+ } /* end if */
+ else
+ image_info.buffer = NULL;
+
+ image_info.size = buf_len;
+
+ /* Set values */
+ if(H5P_set(fapl, H5F_ACS_FILE_IMAGE_INFO_NAME, &image_info) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set file image info")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pset_file_image() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pget_file_image
+ *
+ * Purpose: If the file image exists and buf_ptr_ptr is not NULL,
+ * allocate a buffer of the correct size, copy the image into
+ * the new buffer, and return the buffer to the caller in
+ * *buf_ptr_ptr. Do this using the file image callbacks
+ * if defined.
+ *
+ * NB: It is the responsibility of the caller to free the
+ * buffer whose address is returned in *buf_ptr_ptr. Do
+ * this using free if the file image callbacks are not
+ * defined, or with whatever method is appropriate if
+ * the callbacks are defined.
+ *
+ * If buf_ptr_ptr is not NULL, and no image exists, set
+ * *buf_ptr_ptr to NULL.
+ *
+ * If buf_len_ptr is not NULL, set *buf_len_ptr equal
+ * to the length of the file image if it exists, and
+ * to 0 if it does not.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Jacob Gruber
+ * Thurday, August 11, 2011
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pget_file_image(hid_t fapl_id, void **buf_ptr_ptr, size_t *buf_len_ptr)
+{
+ H5P_genplist_t *fapl; /* Property list pointer */
+ H5FD_file_image_info_t image_info; /* File image info */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE3("e", "i**x*z", fapl_id, buf_ptr_ptr, buf_len_ptr);
+
+ /* Get the plist structure */
+ if(NULL == (fapl = H5P_object_verify(fapl_id, H5P_FILE_ACCESS)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ /* Get values */
+ if(H5P_get(fapl, H5F_ACS_FILE_IMAGE_INFO_NAME, &image_info) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get file image info")
+
+ /* verify file image field consistancy */
+ HDassert(((image_info.buffer != NULL) && (image_info.size > 0)) ||
+ ((image_info.buffer == NULL) && (image_info.size == 0)));
+
+ /* Set output size */
+ if(buf_len_ptr != NULL)
+ *buf_len_ptr = image_info.size;
+
+ /* Duplicate the image if desired, using callbacks if available */
+ if(buf_ptr_ptr != NULL) {
+ void * copy_ptr = NULL; /* Copy of memory image */
+
+ if(image_info.buffer != NULL) {
+ /* Allocate memory */
+ if(image_info.callbacks.image_malloc) {
+ if(NULL == (copy_ptr = image_info.callbacks.image_malloc(image_info.size,
+ H5FD_FILE_IMAGE_OP_PROPERTY_LIST_GET, image_info.callbacks.udata)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "image malloc callback failed")
+ } /* end if */
+ else
+ if(NULL == (copy_ptr = H5MM_malloc(image_info.size)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "unable to allocate copy")
+
+ /* Copy data */
+ if(image_info.callbacks.image_memcpy) {
+ if(copy_ptr != image_info.callbacks.image_memcpy(copy_ptr, image_info.buffer,
+ image_info.size, H5FD_FILE_IMAGE_OP_PROPERTY_LIST_GET,
+ image_info.callbacks.udata))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTCOPY, FAIL, "image_memcpy callback failed")
+ } /* end if */
+ else
+ HDmemcpy(copy_ptr, image_info.buffer, image_info.size);
+ } /* end if */
+
+ *buf_ptr_ptr = copy_ptr;
+ } /* end if */
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pget_file_image */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pset_file_image_callbacks
+ *
+ * Purpose: Sets the callbacks for file images. Some file drivers allow
+ * the use of user-defined callbacks for allocating, freeing and
+ * copying the drivers internal buffer, potentially allowing a
+ * clever user to do optimizations such as avoiding large mallocs
+ * and memcpys or to perform detailed logging.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Jacob Gruber
+ * Thurday, August 11, 2011
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pset_file_image_callbacks(hid_t fapl_id, H5FD_file_image_callbacks_t *callbacks_ptr)
+{
+ H5P_genplist_t *fapl; /* Property list pointer */
+ H5FD_file_image_info_t info; /* File image info */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("e", "i*x", fapl_id, callbacks_ptr);
+
+ /* Get the plist structure */
+ if(NULL == (fapl = H5P_object_verify(fapl_id, H5P_FILE_ACCESS)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ /* Get old info */
+ if(H5P_get(fapl, H5F_ACS_FILE_IMAGE_INFO_NAME, &info) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get old file image info")
+
+ /* verify file image field consistancy */
+ HDassert(((info.buffer != NULL) && (info.size > 0)) ||
+ ((info.buffer == NULL) && (info.size == 0)));
+
+ /* Make sure a file image hasn't already been set */
+ if(info.buffer != NULL || info.size > 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_SETDISALLOWED, FAIL, "setting callbacks when an image is already set is forbidden. It could cause memory leaks.")
+
+ /* verify that callbacks_ptr is not NULL */
+ if(NULL == callbacks_ptr)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "NULL callbacks_ptr")
+
+ /* Make sure udata callbacks are going to be set if udata is going to be set */
+ if(callbacks_ptr->udata)
+ if(callbacks_ptr->udata_copy == NULL || callbacks_ptr->udata_free == NULL)
+ HGOTO_ERROR(H5E_PLIST, H5E_SETDISALLOWED, FAIL, "udata callbacks must be set if udata is set")
+
+ /* Release old udata if it exists */
+ if(info.callbacks.udata != NULL) {
+ HDassert(info.callbacks.udata_free);
+ if(info.callbacks.udata_free(info.callbacks.udata) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTFREE, FAIL, "udata_free callback failed")
+ } /* end if */
+
+ /* Update struct */
+ info.callbacks = *callbacks_ptr;
+
+ if(callbacks_ptr->udata) {
+ HDassert(callbacks_ptr->udata_copy);
+ HDassert(callbacks_ptr->udata_free);
+ if((info.callbacks.udata = callbacks_ptr->udata_copy(callbacks_ptr->udata)) == NULL)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't copy the suppplied udata")
+ } /* end if */
+
+ /* Set values */
+ if(H5P_set(fapl, H5F_ACS_FILE_IMAGE_INFO_NAME, &info) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set file image info")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pset_file_image_callbacks() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pget_file_image_callbacks
+ *
+ * Purpose: Sets the callbacks for file images. Some file drivers allow
+ * the use of user-defined callbacks for allocating, freeing and
+ * copying the drivers internal buffer, potentially allowing a
+ * clever user to do optimizations such as avoiding large mallocs
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Jacob Gruber
+ * Thurday, August 11, 2011
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pget_file_image_callbacks(hid_t fapl_id, H5FD_file_image_callbacks_t *callbacks_ptr)
+{
+ H5P_genplist_t *fapl; /* Property list pointer */
+ H5FD_file_image_info_t info; /* File image info */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("e", "i*x", fapl_id, callbacks_ptr);
+
+ /* Get the plist structure */
+ if(NULL == (fapl = H5P_object_verify(fapl_id, H5P_FILE_ACCESS)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ /* Get old info */
+ if(H5P_get(fapl, H5F_ACS_FILE_IMAGE_INFO_NAME, &info) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get file image info")
+
+ /* verify file image field consistancy */
+ HDassert(((info.buffer != NULL) && (info.size > 0)) ||
+ ((info.buffer == NULL) && (info.size == 0)));
+
+ /* verify that callbacks_ptr is not NULL */
+ if(NULL == callbacks_ptr)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "NULL callbacks_ptr")
+
+ /* Transfer values to parameters */
+ *callbacks_ptr = info.callbacks;
+
+ /* Copy udata if it exists */
+ if(info.callbacks.udata != NULL) {
+ HDassert(info.callbacks.udata_copy);
+ if((callbacks_ptr->udata = info.callbacks.udata_copy(info.callbacks.udata)) == 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't copy udata")
+ } /* end if */
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pget_file_image_callbacks() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P_file_image_info_del
+ *
+ * Purpose: Delete callback for the file image info property, called
+ * when the property is deleted from the plist. The buffer
+ * and udata may need to be freed, possibly using their
+ * respective callbacks so the default free won't work.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Jacob Gruber
+ * Thurday, August 11, 2011
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5P_file_image_info_del(hid_t UNUSED prop_id, const char UNUSED *name, size_t UNUSED size, void *value)
+{
+ H5FD_file_image_info_t info; /* Image info struct */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ if(value) {
+ info = *(H5FD_file_image_info_t *)value;
+
+ /* verify file image field consistancy */
+ HDassert(((info.buffer != NULL) && (info.size > 0)) ||
+ ((info.buffer == NULL) && (info.size == 0)));
+
+ if(info.buffer && info.size > 0) {
+ /* Free buffer */
+ if(info.callbacks.image_free) {
+ if(info.callbacks.image_free(info.buffer, H5FD_FILE_IMAGE_OP_PROPERTY_LIST_CLOSE, info.callbacks.udata) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTFREE, FAIL, "image_free callback failed")
+ } /* end if */
+ else
+ free(info.buffer);
+ } /* end if */
+
+ /* Free udata if it exists */
+ if(info.callbacks.udata) {
+ if(NULL == info.callbacks.udata_free)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "udata_free not defined")
+
+ if(info.callbacks.udata_free(info.callbacks.udata) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTFREE, FAIL, "udata_free callback failed")
+ } /* end if */
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5P_file_image_info_del() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P_file_image_info_copy
+ *
+ * Purpose: Copy callback for the file image info property. The buffer
+ * and udata may need to be copied, possibly using their
+ * respective callbacks so the default copy won't work.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Jacob Gruber
+ * Thurday, August 11, 2011
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5P_file_image_info_copy(const char UNUSED *name, size_t UNUSED size, void *value)
+{
+ H5FD_file_image_info_t *info; /* Image info struct */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ if(value) {
+ info = (H5FD_file_image_info_t *)value;
+
+ /* verify file image field consistancy */
+ HDassert(((info->buffer != NULL) && (info->size > 0)) ||
+ ((info->buffer == NULL) && (info->size == 0)));
+
+ if(info->buffer && info->size > 0) {
+ void *old_buffer; /* Pointer to old image buffer */
+
+ /* Store the old buffer */
+ old_buffer = info->buffer;
+
+ /* Allocate new buffer */
+ if(info->callbacks.image_malloc) {
+ if(NULL == (info->buffer = info->callbacks.image_malloc(info->size,
+ H5FD_FILE_IMAGE_OP_PROPERTY_LIST_COPY, info->callbacks.udata)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "image malloc callback failed")
+ } /* end if */
+ else {
+ if(NULL == (info->buffer = H5MM_malloc(info->size)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "unable to allocate memory block")
+ } /* end else */
+
+ /* Copy data to new buffer */
+ if(info->callbacks.image_memcpy) {
+ if(info->buffer != info->callbacks.image_memcpy(info->buffer, old_buffer,
+ info->size, H5FD_FILE_IMAGE_OP_PROPERTY_LIST_COPY,
+ info->callbacks.udata))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTCOPY, FAIL, "image_memcpy callback failed")
+ } /* end if */
+ else
+ HDmemcpy(info->buffer, old_buffer, info->size);
+ } /* end if */
+ } /* end if */
+
+ /* Copy udata if it exists */
+ if(info->callbacks.udata) {
+ void *old_udata = info->callbacks.udata;
+
+ if(NULL == info->callbacks.udata_copy)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "udata_copy not defined")
+
+ info->callbacks.udata = info->callbacks.udata_copy(old_udata);
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5P_file_image_info_copy() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5P_file_image_info_close
+ *
+ * Purpose: Close callback for the file image info property. The buffer
+ * and udata may need to be freed, possibly using their
+ * respective callbacks so the standard free won't work.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Jacob Gruber
+ * Thurday, August 11, 2011
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5P_file_image_info_close(const char UNUSED *name, size_t UNUSED size, void *value)
+{
+ H5FD_file_image_info_t info; /* Image info struct */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ if(value) {
+ info = *(H5FD_file_image_info_t *)value;
+
+ if(info.buffer != NULL && info.size > 0) {
+ /* Free buffer */
+ if(info.callbacks.image_free) {
+ if(info.callbacks.image_free(info.buffer, H5FD_FILE_IMAGE_OP_PROPERTY_LIST_CLOSE,
+ info.callbacks.udata) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTFREE, FAIL, "image_free callback failed")
+ } /* end if */
+ else
+ H5MM_xfree(info.buffer);
+ } /* end if */
+ } /* end if */
+
+ /* Free udata if it exists */
+ if(info.callbacks.udata) {
+ if(NULL == info.callbacks.udata_free)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "udata_free not defined")
+ if(info.callbacks.udata_free(info.callbacks.udata) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTFREE, FAIL, "udata_free callback failed")
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5P_file_image_info_close() */
+
diff --git a/src/H5Pint.c b/src/H5Pint.c
index 08b8af6..46a06a0 100644
--- a/src/H5Pint.c
+++ b/src/H5Pint.c
@@ -51,6 +51,7 @@
typedef struct {
const H5P_genclass_t *parent; /* Pointer to parent class */
const char *name; /* Pointer to name to check */
+ H5P_genclass_t *new_class; /* Pointer to class during path traversal */
} H5P_check_class_t;
@@ -1358,11 +1359,11 @@ H5P_access_class(H5P_genclass_t *pclass, H5P_class_mod_t mod)
/*--------------------------------------------------------------------------
NAME
- H5P_check_class
+ H5P_open_class_path_cb
PURPOSE
Internal callback routine to check for duplicated names in parent class.
USAGE
- int H5P_check_class(obj, id, key)
+ int H5P_open_class_path_cb(obj, id, key)
H5P_genclass_t *obj; IN: Pointer to class
hid_t id; IN: ID of object being looked at
const void *key; IN: Pointer to information used to compare
@@ -1378,27 +1379,29 @@ H5P_access_class(H5P_genclass_t *pclass, H5P_class_mod_t mod)
REVISION LOG
--------------------------------------------------------------------------*/
static int
-H5P_check_class(void *_obj, hid_t UNUSED id, void *_key)
+H5P_open_class_path_cb(void *_obj, hid_t UNUSED id, void *_key)
{
- H5P_genclass_t *obj=(H5P_genclass_t *)_obj; /* Pointer to the class for this ID */
- const H5P_check_class_t *key=(const H5P_check_class_t *)_key; /* Pointer to key information for comparison */
- int ret_value=0; /* Return value */
+ H5P_genclass_t *obj = (H5P_genclass_t *)_obj; /* Pointer to the class for this ID */
+ H5P_check_class_t *key = (H5P_check_class_t *)_key; /* Pointer to key information for comparison */
+ int ret_value = 0; /* Return value */
FUNC_ENTER_NOAPI_NOINIT_NOERR
HDassert(obj);
- HDassert(H5I_GENPROP_CLS==H5I_get_type(id));
+ HDassert(H5I_GENPROP_CLS == H5I_get_type(id));
HDassert(key);
/* Check if the class object has the same parent as the new class */
- if(obj->parent==key->parent) {
+ if(obj->parent == key->parent) {
/* Check if they have the same name */
- if(HDstrcmp(obj->name,key->name)==0)
- ret_value=1; /* Indicate a match */
+ if(HDstrcmp(obj->name, key->name) == 0) {
+ key->new_class = obj;
+ ret_value = 1; /* Indicate a match */
+ } /* end if */
} /* end if */
FUNC_LEAVE_NOAPI(ret_value)
-} /* end H5P_check_class() */
+} /* end H5P_open_class_path_cb() */
/*--------------------------------------------------------------------------
@@ -4555,8 +4558,8 @@ H5P_open_class_path(const char *path)
char *curr_name; /* Pointer to current component of path name */
char *delimit; /* Pointer to path delimiter during traversal */
H5P_genclass_t *curr_class; /* Pointer to class during path traversal */
- H5P_genclass_t *ret_value; /* Return value */
H5P_check_class_t check_info; /* Structure to hold the information for checking duplicate names */
+ H5P_genclass_t *ret_value; /* Return value */
FUNC_ENTER_NOAPI_NOINIT
@@ -4569,20 +4572,24 @@ H5P_open_class_path(const char *path)
/* Find the generic property class with this full path */
curr_name = tmp_path;
curr_class = NULL;
- while((delimit=HDstrchr(curr_name,'/'))!=NULL) {
+ while(NULL != (delimit = HDstrchr(curr_name, '/'))) {
/* Change the delimiter to terminate the string */
- *delimit='\0';
+ *delimit = '\0';
/* Set up the search structure */
- check_info.parent=curr_class;
- check_info.name=curr_name;
+ check_info.parent = curr_class;
+ check_info.name = curr_name;
+ check_info.new_class = NULL;
/* Find the class with this name & parent by iterating over the open classes */
- if(NULL == (curr_class = (H5P_genclass_t *)H5I_search(H5I_GENPROP_CLS, H5P_check_class, &check_info, FALSE)))
- HGOTO_ERROR(H5E_PLIST, H5E_NOTFOUND, NULL, "can't locate class")
+ if(H5I_iterate(H5I_GENPROP_CLS, H5P_open_class_path_cb, &check_info, FALSE) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_BADITER, NULL, "can't iterate over classes")
+ else if(NULL == check_info.new_class)
+ HGOTO_ERROR(H5E_PLIST, H5E_NOTFOUND, NULL, "can't locate class")
/* Advance the pointer in the path to the start of the next component */
- curr_name=delimit+1;
+ curr_class = check_info.new_class;
+ curr_name = delimit + 1;
} /* end while */
/* Should be pointing to the last component in the path name now... */
@@ -4590,13 +4597,16 @@ H5P_open_class_path(const char *path)
/* Set up the search structure */
check_info.parent = curr_class;
check_info.name = curr_name;
+ check_info.new_class = NULL;
/* Find the class with this name & parent by iterating over the open classes */
- if(NULL == (curr_class = (H5P_genclass_t *)H5I_search(H5I_GENPROP_CLS, H5P_check_class, &check_info, FALSE)))
+ if(H5I_iterate(H5I_GENPROP_CLS, H5P_open_class_path_cb, &check_info, FALSE) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_BADITER, NULL, "can't iterate over classes")
+ else if(NULL == check_info.new_class)
HGOTO_ERROR(H5E_PLIST, H5E_NOTFOUND, NULL, "can't locate class")
/* Copy it */
- if(NULL == (ret_value = H5P_copy_pclass(curr_class)))
+ if(NULL == (ret_value = H5P_copy_pclass(check_info.new_class)))
HGOTO_ERROR(H5E_PLIST, H5E_CANTCOPY, NULL, "can't copy property class")
done:
@@ -4604,7 +4614,7 @@ done:
H5MM_xfree(tmp_path);
FUNC_LEAVE_NOAPI(ret_value)
-} /* H5P_open_class_path() */
+} /* H5P_open_class_path() */
/*--------------------------------------------------------------------------
diff --git a/src/H5Ppublic.h b/src/H5Ppublic.h
index 9015940..654772a 100644
--- a/src/H5Ppublic.h
+++ b/src/H5Ppublic.h
@@ -322,6 +322,12 @@ H5_DLL herr_t H5Pget_libver_bounds(hid_t plist_id, H5F_libver_t *low,
H5F_libver_t *high);
H5_DLL herr_t H5Pset_elink_file_cache_size(hid_t plist_id, unsigned efc_size);
H5_DLL herr_t H5Pget_elink_file_cache_size(hid_t plist_id, unsigned *efc_size);
+H5_DLL herr_t H5Pset_file_image(hid_t fapl_id, void *buf_ptr, size_t buf_len);
+H5_DLL herr_t H5Pget_file_image(hid_t fapl_id, void **buf_ptr_ptr, size_t *buf_len_ptr);
+H5_DLL herr_t H5Pset_file_image_callbacks(hid_t fapl_id,
+ H5FD_file_image_callbacks_t *callbacks_ptr);
+H5_DLL herr_t H5Pget_file_image_callbacks(hid_t fapl_id,
+ H5FD_file_image_callbacks_t *callbacks_ptr);
/* Dataset creation property list (DCPL) routines */
H5_DLL herr_t H5Pset_layout(hid_t plist_id, H5D_layout_t layout);
diff --git a/src/H5T.c b/src/H5T.c
index fcc4ab3..37d4b68 100644
--- a/src/H5T.c
+++ b/src/H5T.c
@@ -1449,7 +1449,8 @@ H5T_term_interface(void)
H5T_g.asoft = 0;
/* Unlock all datatypes, then free them */
- H5I_search(H5I_DATATYPE, H5T_unlock_cb, NULL, FALSE);
+ /* note that we are ignoring the return value from H5I_iterate() */
+ H5I_iterate(H5I_DATATYPE, H5T_unlock_cb, NULL, FALSE);
H5I_dec_type_ref(H5I_DATATYPE);
/* Reset all the datatype IDs */
diff --git a/src/H5err.txt b/src/H5err.txt
index 71d27a6..b4cb28b 100644
--- a/src/H5err.txt
+++ b/src/H5err.txt
@@ -220,6 +220,7 @@ MINOR, DSPACE, H5E_CANTCOMPARE, Can't compare objects
MINOR, PLIST, H5E_CANTGET, Can't get value
MINOR, PLIST, H5E_CANTSET, Can't set value
MINOR, PLIST, H5E_DUPCLASS, Duplicate class name in parent class
+MINOR, PLIST, H5E_SETDISALLOWED, Disallowed operation
# Link errors
MINOR, LINK, H5E_TRAVERSE, Link traversal failure
diff --git a/test/Makefile.am b/test/Makefile.am
index afc1b37..50ca89c 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -42,7 +42,7 @@ TEST_PROG= testhdf5 lheap ohdr stab gheap cache cache_api cache_tagging \
big mtime fillval mount flush1 flush2 app_ref enum \
set_extent ttsafe \
getname vfd ntypes dangle dtransform reserved cross_read \
- freespace mf farray earray btree2 fheap
+ freespace mf farray earray btree2 fheap file_image
# List programs to be built when testing here. error_test and err_compat are
# built at the same time as the other tests, but executed by testerror.sh.
@@ -63,7 +63,7 @@ check_PROGRAMS=$(TEST_PROG) error_test err_compat tcheck_version testmeta links_
BUILD_ALL_PROGS=gen_bad_ohdr gen_bogus gen_cross gen_deflate gen_filters gen_new_array \
gen_new_fill gen_new_group gen_new_mtime gen_new_super gen_noencoder \
gen_nullspace gen_udlinks space_overflow gen_filespace gen_specmetaread \
- gen_sizes_lheap
+ gen_sizes_lheap gen_file_image
if BUILD_ALL_CONDITIONAL
noinst_PROGRAMS=$(BUILD_ALL_PROGS)
diff --git a/test/Makefile.in b/test/Makefile.in
index 6e716bc..d468cd9 100644
--- a/test/Makefile.in
+++ b/test/Makefile.in
@@ -92,7 +92,8 @@ am__EXEEXT_1 = testhdf5$(EXEEXT) lheap$(EXEEXT) ohdr$(EXEEXT) \
ttsafe$(EXEEXT) getname$(EXEEXT) vfd$(EXEEXT) ntypes$(EXEEXT) \
dangle$(EXEEXT) dtransform$(EXEEXT) reserved$(EXEEXT) \
cross_read$(EXEEXT) freespace$(EXEEXT) mf$(EXEEXT) \
- farray$(EXEEXT) earray$(EXEEXT) btree2$(EXEEXT) fheap$(EXEEXT)
+ farray$(EXEEXT) earray$(EXEEXT) btree2$(EXEEXT) fheap$(EXEEXT) \
+ file_image$(EXEEXT)
am__EXEEXT_2 = gen_bad_ohdr$(EXEEXT) gen_bogus$(EXEEXT) \
gen_cross$(EXEEXT) gen_deflate$(EXEEXT) gen_filters$(EXEEXT) \
gen_new_array$(EXEEXT) gen_new_fill$(EXEEXT) \
@@ -100,7 +101,7 @@ am__EXEEXT_2 = gen_bad_ohdr$(EXEEXT) gen_bogus$(EXEEXT) \
gen_new_super$(EXEEXT) gen_noencoder$(EXEEXT) \
gen_nullspace$(EXEEXT) gen_udlinks$(EXEEXT) \
space_overflow$(EXEEXT) gen_filespace$(EXEEXT) \
- gen_specmetaread$(EXEEXT) gen_sizes_lheap$(EXEEXT)
+ gen_specmetaread$(EXEEXT) gen_sizes_lheap$(EXEEXT) gen_file_image$(EXEEXT)
PROGRAMS = $(noinst_PROGRAMS)
accum_SOURCES = accum.c
accum_OBJECTS = accum.$(OBJEXT)
@@ -198,6 +199,10 @@ fheap_SOURCES = fheap.c
fheap_OBJECTS = fheap.$(OBJEXT)
fheap_LDADD = $(LDADD)
fheap_DEPENDENCIES = libh5test.la $(LIBHDF5)
+file_image_SOURCES = file_image.c
+file_image_OBJECTS = file_image.$(OBJEXT)
+file_image_LDADD = $(LDADD)
+file_image_DEPENDENCIES = libh5test.la $(LIBHDF5)
fillval_SOURCES = fillval.c
fillval_OBJECTS = fillval.$(OBJEXT)
fillval_LDADD = $(LDADD)
@@ -282,6 +287,10 @@ gen_udlinks_SOURCES = gen_udlinks.c
gen_udlinks_OBJECTS = gen_udlinks.$(OBJEXT)
gen_udlinks_LDADD = $(LDADD)
gen_udlinks_DEPENDENCIES = libh5test.la $(LIBHDF5)
+gen_file_image_SOURCES = gen_file_image.c
+gen_file_image_OBJECTS = gen_file_image.$(OBJEXT)
+gen_file_image_LDADD = $(LDADD)
+gen_file_image_DEPENDENCIES = libh5test.la $(LIBHDF5)
getname_SOURCES = getname.c
getname_OBJECTS = getname.$(OBJEXT)
getname_LDADD = $(LDADD)
@@ -418,31 +427,32 @@ SOURCES = $(libh5test_la_SOURCES) accum.c app_ref.c big.c bittests.c \
btree2.c cache.c cache_api.c cache_tagging.c cmpd_dset.c \
cross_read.c dangle.c dsets.c dt_arith.c dtransform.c dtypes.c \
earray.c efc.c enum.c err_compat.c error_test.c extend.c \
- external.c farray.c fheap.c fillval.c filter_fail.c flush1.c \
- flush2.c freespace.c gen_bad_ohdr.c gen_bogus.c gen_cross.c \
- gen_deflate.c gen_filespace.c gen_filters.c gen_new_array.c \
- gen_new_fill.c gen_new_group.c gen_new_mtime.c gen_new_super.c \
- gen_noencoder.c gen_nullspace.c gen_sizes_lheap.c \
- gen_specmetaread.c gen_udlinks.c getname.c gheap.c hyperslab.c \
- istore.c lheap.c links.c links_env.c mf.c mount.c mtime.c \
- ntypes.c objcopy.c ohdr.c pool.c reserved.c set_extent.c \
- space_overflow.c stab.c tcheck_version.c $(testhdf5_SOURCES) \
- testmeta.c $(ttsafe_SOURCES) unlink.c vfd.c
-DIST_SOURCES = $(libh5test_la_SOURCES) accum.c app_ref.c big.c \
- bittests.c btree2.c cache.c cache_api.c cache_tagging.c \
- cmpd_dset.c cross_read.c dangle.c dsets.c dt_arith.c \
- dtransform.c dtypes.c earray.c efc.c enum.c err_compat.c \
- error_test.c extend.c external.c farray.c fheap.c fillval.c \
+ external.c farray.c fheap.c file_image.c fillval.c \
filter_fail.c flush1.c flush2.c freespace.c gen_bad_ohdr.c \
gen_bogus.c gen_cross.c gen_deflate.c gen_filespace.c \
gen_filters.c gen_new_array.c gen_new_fill.c gen_new_group.c \
gen_new_mtime.c gen_new_super.c gen_noencoder.c \
gen_nullspace.c gen_sizes_lheap.c gen_specmetaread.c \
- gen_udlinks.c getname.c gheap.c hyperslab.c istore.c lheap.c \
+ gen_udlinks.c gen_file_image.c getname.c gheap.c hyperslab.c istore.c lheap.c \
links.c links_env.c mf.c mount.c mtime.c ntypes.c objcopy.c \
ohdr.c pool.c reserved.c set_extent.c space_overflow.c stab.c \
tcheck_version.c $(testhdf5_SOURCES) testmeta.c \
$(ttsafe_SOURCES) unlink.c vfd.c
+DIST_SOURCES = $(libh5test_la_SOURCES) accum.c app_ref.c big.c \
+ bittests.c btree2.c cache.c cache_api.c cache_tagging.c \
+ cmpd_dset.c cross_read.c dangle.c dsets.c dt_arith.c \
+ dtransform.c dtypes.c earray.c efc.c enum.c err_compat.c \
+ error_test.c extend.c external.c farray.c fheap.c file_image.c \
+ fillval.c filter_fail.c flush1.c flush2.c freespace.c \
+ gen_bad_ohdr.c gen_bogus.c gen_cross.c gen_deflate.c \
+ gen_filespace.c gen_filters.c gen_new_array.c gen_new_fill.c \
+ gen_new_group.c gen_new_mtime.c gen_new_super.c \
+ gen_noencoder.c gen_nullspace.c gen_sizes_lheap.c \
+ gen_specmetaread.c gen_udlinks.c gen_file_image.c getname.c gheap.c hyperslab.c \
+ istore.c lheap.c links.c links_env.c mf.c mount.c mtime.c \
+ ntypes.c objcopy.c ohdr.c pool.c reserved.c set_extent.c \
+ space_overflow.c stab.c tcheck_version.c $(testhdf5_SOURCES) \
+ testmeta.c $(ttsafe_SOURCES) unlink.c vfd.c
ETAGS = etags
CTAGS = ctags
am__tty_colors = \
@@ -778,7 +788,7 @@ TEST_PROG = testhdf5 lheap ohdr stab gheap cache cache_api cache_tagging \
big mtime fillval mount flush1 flush2 app_ref enum \
set_extent ttsafe \
getname vfd ntypes dangle dtransform reserved cross_read \
- freespace mf farray earray btree2 fheap
+ freespace mf farray earray btree2 fheap file_image
# These programs generate test files for the tests. They don't need to be
@@ -791,7 +801,7 @@ TEST_PROG = testhdf5 lheap ohdr stab gheap cache cache_api cache_tagging \
BUILD_ALL_PROGS = gen_bad_ohdr gen_bogus gen_cross gen_deflate gen_filters gen_new_array \
gen_new_fill gen_new_group gen_new_mtime gen_new_super gen_noencoder \
gen_nullspace gen_udlinks space_overflow gen_filespace gen_specmetaread \
- gen_sizes_lheap
+ gen_sizes_lheap gen_file_image
# The libh5test library provides common support code for the tests.
@@ -978,6 +988,9 @@ farray$(EXEEXT): $(farray_OBJECTS) $(farray_DEPENDENCIES)
fheap$(EXEEXT): $(fheap_OBJECTS) $(fheap_DEPENDENCIES)
@rm -f fheap$(EXEEXT)
$(AM_V_CCLD)$(LINK) $(fheap_OBJECTS) $(fheap_LDADD) $(LIBS)
+file_image$(EXEEXT): $(file_image_OBJECTS) $(file_image_DEPENDENCIES)
+ @rm -f file_image$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(file_image_OBJECTS) $(file_image_LDADD) $(LIBS)
fillval$(EXEEXT): $(fillval_OBJECTS) $(fillval_DEPENDENCIES)
@rm -f fillval$(EXEEXT)
$(AM_V_CCLD)$(LINK) $(fillval_OBJECTS) $(fillval_LDADD) $(LIBS)
@@ -1041,6 +1054,9 @@ gen_specmetaread$(EXEEXT): $(gen_specmetaread_OBJECTS) $(gen_specmetaread_DEPEND
gen_udlinks$(EXEEXT): $(gen_udlinks_OBJECTS) $(gen_udlinks_DEPENDENCIES)
@rm -f gen_udlinks$(EXEEXT)
$(AM_V_CCLD)$(LINK) $(gen_udlinks_OBJECTS) $(gen_udlinks_LDADD) $(LIBS)
+gen_file_image$(EXEEXT): $(gen_file_image_OBJECTS) $(gen_file_image_DEPENDENCIES)
+ @rm -f gen_file_image$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(gen_file_image_OBJECTS) $(gen_file_image_LDADD) $(LIBS)
getname$(EXEEXT): $(getname_OBJECTS) $(getname_DEPENDENCIES)
@rm -f getname$(EXEEXT)
$(AM_V_CCLD)$(LINK) $(getname_OBJECTS) $(getname_LDADD) $(LIBS)
@@ -1145,6 +1161,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/external.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/farray.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fheap.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/file_image.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fillval.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/filter_fail.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/flush1.Po@am__quote@
@@ -1166,6 +1183,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gen_sizes_lheap.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gen_specmetaread.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gen_udlinks.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gen_file_image.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/getname.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gheap.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/h5test.Plo@am__quote@
diff --git a/test/file_image.c b/test/file_image.c
new file mode 100644
index 0000000..7c2c3ff
--- /dev/null
+++ b/test/file_image.c
@@ -0,0 +1,1335 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * 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. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/***********************************************************
+*
+* Test program: file_image
+*
+* Test setting file images
+*
+*************************************************************/
+
+#include "h5test.h"
+#include "H5srcdir.h"
+#include "H5Fprivate.h" /* required to test property removals */
+#define VERIFY(condition, string) do { if (!(condition)) FAIL_PUTS_ERROR(string) } while(0)
+
+/* Values for callback bit field */
+#define MALLOC 0x01
+#define MEMCPY 0x02
+#define REALLOC 0x04
+#define FREE 0x08
+#define UDATA_COPY 0x10
+#define UDATA_FREE 0x20
+
+#define RANK 2
+#define DIM0 1024
+#define DIM1 32
+#define DSET_NAME "test_dset"
+
+#define FAMILY_SIZE (2 * 1024)
+
+const char *FILENAME[] = {
+ "file_image_core_test",
+ NULL
+};
+
+/* need a second file name array, as the first file name array contains
+ * files we don't want to delete on cleanup.
+ */
+const char *FILENAME2[] = {
+ "sec2_get_file_image_test",
+ "stdio_get_file_image_test",
+ "core_get_file_image_test",
+ "family_get_file_image_test",
+ "multi_get_file_image_test",
+ "split_get_file_image_test",
+ "get_file_image_error_rejection_test",
+ NULL
+};
+
+typedef struct {
+ unsigned char used_callbacks; /* Bitfield for tracking callbacks */
+ H5FD_file_image_op_t malloc_src; /* Source of file image callbacks */
+ H5FD_file_image_op_t memcpy_src;
+ H5FD_file_image_op_t realloc_src;
+ H5FD_file_image_op_t free_src;
+} udata_t;
+
+
+/******************************************************************************
+ * Function: test_properties
+ *
+ * Purpose: Tests that the file image properties (buffer pointer and length)
+ * are set properly. Image callbacks are not set in this test.
+ *
+ * Returns: Success: 0
+ * Failure: 1
+ *
+ * Programmer: Jacob Gruber
+ * Monday, August 22, 2011
+ *
+ ******************************************************************************
+ */
+static int
+test_properties(void)
+{
+ hid_t fapl_1;
+ hid_t fapl_2;
+ char *buffer;
+ int count = 10;
+ void *temp;
+ char *temp2;
+ int i;
+ size_t size;
+ size_t temp_size;
+
+ TESTING("File image property list functions");
+
+ /* Initialize file image buffer
+ *
+ * Note: this image will not contain a valid HDF5 file, as it complicates testing
+ * property list functions. In the file driver tests further down, this will
+ * not be the case.
+ */
+ size = (size_t)count * sizeof(char);
+ buffer = (char *)HDmalloc(size);
+ for(i = 0; i < count - 1; i++)
+ buffer[i] = (char)(65 + i);
+ buffer[count] = '\0';
+
+ /* Create fapl */
+ if((fapl_1 = H5Pcreate(H5P_FILE_ACCESS)) < 0) FAIL_STACK_ERROR
+
+ /* Get file image stuff */
+ if(H5Pget_file_image(fapl_1, (void **)&temp, &temp_size) < 0) FAIL_STACK_ERROR
+
+ /* Check default values */
+ VERIFY(temp == NULL, "Default pointer is wrong");
+ VERIFY(temp_size == 0, "Default size is wrong");
+
+ /* Set file image stuff */
+ if(H5Pset_file_image(fapl_1, (void *)buffer, size) < 0) FAIL_STACK_ERROR
+
+ /* Get the same */
+ if(H5Pget_file_image(fapl_1, (void **)&temp, &temp_size) < 0) FAIL_STACK_ERROR
+
+ /* Check that sizes are the same, and that the buffers are identical but separate */
+ VERIFY(temp != NULL, "temp is null!");
+ VERIFY(temp_size == size, "Sizes of buffers don't match");
+ VERIFY(temp != buffer, "Retrieved buffer is the same as original");
+ VERIFY(0 == HDmemcmp(temp, buffer, size), "Buffers contain different data");
+
+ /* Copy the fapl */
+ if((fapl_2 = H5Pcopy(fapl_1)) < 0) FAIL_STACK_ERROR
+
+ /* Get values from the new fapl */
+ if(H5Pget_file_image(fapl_2, (void **)&temp2, &temp_size) < 0) FAIL_STACK_ERROR
+
+ /* Check that sizes are the same, and that the buffers are identical but separate */
+ VERIFY(temp_size == size,"Sizes of buffers don't match");
+ VERIFY(temp2 != NULL,"Recieved buffer not set");
+ VERIFY(temp2 != buffer, "Retrieved buffer is the same as original");
+ VERIFY(temp2 != temp, "Retrieved buffer is the same as previously retrieved buffer");
+ VERIFY(0 == HDmemcmp(temp2, buffer, size),"Buffers contain different data");
+
+ /* Close everything */
+ if(H5Pclose(fapl_1) < 0) FAIL_STACK_ERROR
+ if(H5Pclose(fapl_2) < 0) FAIL_STACK_ERROR
+ HDfree(buffer);
+ HDfree(temp);
+ HDfree(temp2);
+
+ PASSED();
+ return 0;
+
+error:
+ return 1;
+} /* end test_properties() */
+
+/******************************************************************************
+ * Function: malloc_cb
+ *
+ * Purpose: This function allows calls to the malloc callback to be tracked.
+ *
+ * Returns: The result of a standard malloc
+ *
+ * Programmer: Jacob Gruber
+ * Monday, August 22, 2011
+ *
+ ******************************************************************************
+ */
+static void *
+malloc_cb(size_t size, H5FD_file_image_op_t op, void *udata)
+{
+ udata_t *u = (udata_t *)udata;
+
+ u->used_callbacks |= MALLOC;
+ u->malloc_src = op;
+ return HDmalloc(size);
+}
+
+/******************************************************************************
+ * Function: memcpy_cb
+ *
+ * Purpose: This function allows calls to the memcpy callback to be tracked.
+ *
+ * Returns: The result of a standard memcpy
+ *
+ * Programmer: Jacob Gruber
+ * Monday, August 22, 2011
+ *
+ ******************************************************************************
+ */
+static void *
+memcpy_cb(void *dest, const void *src, size_t size, H5FD_file_image_op_t op, void *udata)
+{
+ udata_t *u = (udata_t *)udata;
+
+ u->used_callbacks |= MEMCPY;
+ u->memcpy_src = op;
+ return HDmemcpy(dest, src, size);
+}
+
+/******************************************************************************
+ * Function: realloc_cb
+ *
+ * Purpose: This function allows calls to the realloc callback to be tracked.
+ *
+ * Returns: The result of a standard realloc
+ *
+ * Programmer: Jacob Gruber
+ * Monday, August 22, 2011
+ *
+ ******************************************************************************
+ */
+static void *
+realloc_cb(void *ptr, size_t size, H5FD_file_image_op_t op, void *udata)
+{
+ udata_t *u = (udata_t *)udata;
+
+ u->used_callbacks |= REALLOC;
+ u->realloc_src = op;
+ return HDrealloc(ptr,size);
+}
+
+/******************************************************************************
+ * Function: free_cb
+ *
+ * Purpose: This function allows calls to the free callback to be tracked.
+ *
+ * Programmer: Jacob Gruber
+ * Monday, August 22, 2011
+ *
+ ******************************************************************************
+ */
+static herr_t
+free_cb(void *ptr, H5FD_file_image_op_t op, void *udata)
+{
+ udata_t *u = (udata_t *)udata;
+
+ u->used_callbacks |= FREE;
+ u->free_src = op;
+ HDfree(ptr);
+ return(SUCCEED);
+}
+
+/******************************************************************************
+ * Function: udata_copy_cb
+ *
+ * Purpose: This function allows calls to the udata_copy callback to be tracked.
+ * No copying actualy takes place; it is easier to deal with only one
+ * instance of the udata.
+ *
+ * Returns: A pointer to the same udata that was passed in.
+ *
+ * Programmer: Jacob Gruber
+ * Monday, August 22, 2011
+ *
+ ******************************************************************************
+ */
+static void *
+udata_copy_cb(void *udata)
+{
+ udata_t *u = (udata_t *)udata;
+
+ u->used_callbacks |= UDATA_COPY;
+ return udata;
+}
+
+/******************************************************************************
+ * Function: udata_free_cb
+ *
+ * Purpose: This function allows calls to the udata_free callback to be tracked.
+ *
+ * Note: this callback doesn't actually do anything. Since the
+ * udata_copy callback doesn't copy, only one instance of the udata
+ * is kept alive and such it must be freed explicitly at the end of the tests.
+ *
+ * Programmer: Jacob Gruber
+ * Monday, August 22, 2011
+ *
+ ******************************************************************************
+ */
+static herr_t
+udata_free_cb(void *udata)
+{
+ udata_t *u = (udata_t *)udata;
+
+ u->used_callbacks |= UDATA_FREE;
+ return(SUCCEED);
+}
+
+/******************************************************************************
+ * Function: reset_udata
+ *
+ * Purpose: Resets the udata to default values. This facilitates storing only
+ * the results of a single operation in the udata.
+ *
+ * Programmer: Jacob Gruber
+ * Monday, August 22, 2011
+ *
+ ******************************************************************************
+ */
+static void
+reset_udata(udata_t *u)
+{
+ u->used_callbacks = 0;
+ u->malloc_src = u->memcpy_src = u->realloc_src = u->free_src = H5FD_FILE_IMAGE_OP_NO_OP;
+}
+
+/******************************************************************************
+ * Function: test_callbacks
+ *
+ * Purpose: Tests that callbacks are called properly in property list functions.
+ *
+ * Programmer: Jacob Gruber
+ * Monday, August 22, 2011
+ *
+ ******************************************************************************
+ */
+static int
+test_callbacks(void)
+{
+ H5FD_file_image_callbacks_t real_callbacks = {&malloc_cb, &memcpy_cb, &realloc_cb,
+ &free_cb, &udata_copy_cb, &udata_free_cb, NULL};
+ H5FD_file_image_callbacks_t null_callbacks = {NULL, NULL, NULL, NULL, NULL, NULL, NULL};
+ H5FD_file_image_callbacks_t callbacks;
+ hid_t fapl_1;
+ hid_t fapl_2;
+ udata_t *udata;
+ char *file_image;
+ char *temp_file_image;
+ int count = 10;
+ int i;
+ size_t size;
+ size_t temp_size;
+
+ TESTING("Callback use in property list operations");
+
+ /* Allocate and initialize udata */
+ udata = (udata_t *)HDmalloc(sizeof(udata_t));
+ reset_udata(udata);
+
+ /* copy the address of the user data into read_callbacks */
+ real_callbacks.udata = (void *)udata;
+
+ /* Allocate and initialize file image buffer */
+ size = (size_t)count * sizeof(char);
+ file_image = (char *)HDmalloc(size);
+ for(i = 0; i < count - 1; i++)
+ file_image[i] = (char)(65 + i);
+ file_image[count] = '\0';
+
+ /* Create fapl */
+ if((fapl_1 = H5Pcreate(H5P_FILE_ACCESS)) < 0) FAIL_STACK_ERROR
+
+ /* Get file image stuff */
+ callbacks = real_callbacks;
+ if(H5Pget_file_image_callbacks(fapl_1, &callbacks) < 0) FAIL_STACK_ERROR
+
+ /* Check default values */
+ VERIFY(callbacks.image_malloc == NULL, "Default malloc callback is wrong");
+ VERIFY(callbacks.image_memcpy == NULL, "Default memcpy callback is wrong");
+ VERIFY(callbacks.image_realloc == NULL, "Default realloc callback is wrong");
+ VERIFY(callbacks.image_free == NULL, "Default free callback is wrong");
+ VERIFY(callbacks.udata_copy == NULL, "Default udata copy callback is wrong");
+ VERIFY(callbacks.udata_free == NULL, "Default udata free callback is wrong");
+ VERIFY(callbacks.udata == NULL, "Default udata is wrong");
+
+
+ /* Set file image callbacks */
+ callbacks = real_callbacks;
+ if(H5Pset_file_image_callbacks(fapl_1, &callbacks) < 0) FAIL_STACK_ERROR
+
+ /* Get file image callbacks */
+ callbacks = null_callbacks;
+ if(H5Pget_file_image_callbacks(fapl_1, &callbacks) < 0) FAIL_STACK_ERROR
+
+ /* Verify values */
+ VERIFY(callbacks.image_malloc == &malloc_cb, "malloc callback was not set or retrieved properly");
+ VERIFY(callbacks.image_memcpy == &memcpy_cb, "memcpy callback was not set or retrieved properly");
+ VERIFY(callbacks.image_realloc == &realloc_cb, "realloc callback was not set or retrieved properly");
+ VERIFY(callbacks.image_free == &free_cb, "free callback was not set or retrieved properly");
+ VERIFY(callbacks.udata_copy == &udata_copy_cb, "udata copy callback was not set or retrieved properly");
+ VERIFY(callbacks.udata_free == &udata_free_cb, "udata free callback was not set or retrieved properly");
+ VERIFY(callbacks.udata == udata, "udata was not set or retrieved properly");
+
+
+ /*
+ * Check callbacks in internal function without a previously set file image
+ */
+
+ /* Copy fapl */
+ reset_udata(udata);
+ if((fapl_2 = H5Pcopy(fapl_1)) < 0) FAIL_STACK_ERROR
+
+ /* Verify that the property's copy callback used the correct image callbacks */
+ VERIFY(udata->used_callbacks == (UDATA_COPY), "Copying a fapl with no image used incorrect callbacks");
+
+ /* Close fapl */
+ reset_udata(udata);
+ if(H5Pclose(fapl_2) < 0) FAIL_STACK_ERROR
+
+ /* Verify that the udata free callback was used */
+ VERIFY(udata->used_callbacks == (UDATA_FREE), "Closing a fapl with no image used incorrect callbacks");
+
+ /* Copy again */
+ if((fapl_2 = H5Pcopy(fapl_1)) < 0) FAIL_STACK_ERROR
+
+ /* Remove property from fapl */
+ reset_udata(udata);
+ if(H5Premove(fapl_2, H5F_ACS_FILE_IMAGE_INFO_NAME) < 0) FAIL_STACK_ERROR
+
+ /* Verify that the property's delete callback was called using the correct image callbacks */
+ VERIFY(udata->used_callbacks == (UDATA_FREE), "Removing a property from a fapl with no image used incorrect callbacks");
+
+ /* Close it again */
+ if(H5Pclose(fapl_2) < 0) FAIL_STACK_ERROR
+
+ /* Get file image */
+ reset_udata(udata);
+ if(H5Pget_file_image(fapl_1, (void **)&temp_file_image, &temp_size) < 0) FAIL_STACK_ERROR
+
+ /* Verify that the correct callbacks were used */
+ VERIFY(udata->used_callbacks == 0, "attempting to retrieve the image from a fapl without an image has an unexpected callback");
+
+ /* Set file image */
+ reset_udata(udata);
+ if(H5Pset_file_image(fapl_1, (void *)file_image, size) < 0) FAIL_STACK_ERROR
+
+ VERIFY(udata->used_callbacks == (MALLOC | MEMCPY), "Setting a file image (first time) used incorrect callbacks");
+
+ /*
+ * Check callbacks in internal functions with a previously set file image
+ */
+
+ /* Copy fapl */
+ reset_udata(udata);
+ if((fapl_2 = H5Pcopy(fapl_1)) < 0) FAIL_STACK_ERROR
+
+ /* Verify that the property's copy callback used the correct image callbacks */
+ VERIFY(udata->used_callbacks == (MALLOC | MEMCPY | UDATA_COPY), "Copying a fapl with an image used incorrect callbacks");
+ VERIFY(udata->malloc_src == H5FD_FILE_IMAGE_OP_PROPERTY_LIST_COPY, "malloc callback has wrong source");
+ VERIFY(udata->memcpy_src == H5FD_FILE_IMAGE_OP_PROPERTY_LIST_COPY, "memcpy callback has wrong source");
+
+ /* Close fapl */
+ reset_udata(udata);
+ if(H5Pclose(fapl_2) < 0) FAIL_STACK_ERROR
+
+ /* Verify that the udata free callback was used */
+ VERIFY(udata->used_callbacks == (FREE | UDATA_FREE), "Closing a fapl with an image used incorrect callbacks");
+ VERIFY(udata->free_src == H5FD_FILE_IMAGE_OP_PROPERTY_LIST_CLOSE, "free callback has wrong source");
+
+ /* Copy again */
+ if((fapl_2 = H5Pcopy(fapl_1)) < 0) FAIL_STACK_ERROR
+
+ /* Remove property from fapl */
+ reset_udata(udata);
+ if(H5Premove(fapl_2, H5F_ACS_FILE_IMAGE_INFO_NAME) < 0) FAIL_STACK_ERROR
+
+ /* Verify that the property's delete callback was called using the correct image callbacks */
+ VERIFY(udata->used_callbacks == (FREE | UDATA_FREE), "Removing a property from a fapl with an image used incorrect callbacks");
+ VERIFY(udata->free_src == H5FD_FILE_IMAGE_OP_PROPERTY_LIST_CLOSE, "free callback has wrong source");
+
+ /* Close it again */
+ if(H5Pclose(fapl_2) < 0) FAIL_STACK_ERROR
+
+ /* Get file image */
+ reset_udata(udata);
+ if(H5Pget_file_image(fapl_1, (void **)&temp_file_image, &temp_size) < 0) FAIL_STACK_ERROR
+
+ /* Verify that the correct callbacks were used */
+ VERIFY(udata->used_callbacks == (MALLOC | MEMCPY), "attempting to retrieve the image from a fapl with an image has an unexpected callback");
+ VERIFY(udata->malloc_src == H5FD_FILE_IMAGE_OP_PROPERTY_LIST_GET, "malloc callback has wrong source");
+ VERIFY(udata->memcpy_src == H5FD_FILE_IMAGE_OP_PROPERTY_LIST_GET, "memcpy callback has wrong source");
+
+ /* Set file image */
+ reset_udata(udata);
+ if(H5Pset_file_image(fapl_1, (void *)file_image, size) < 0) FAIL_STACK_ERROR
+
+ VERIFY(udata->used_callbacks == (FREE | MALLOC | MEMCPY), "Setting a file image (second time) used incorrect callbacks");
+ VERIFY(udata->malloc_src == H5FD_FILE_IMAGE_OP_PROPERTY_LIST_SET, "malloc callback has wrong source");
+ VERIFY(udata->memcpy_src == H5FD_FILE_IMAGE_OP_PROPERTY_LIST_SET, "memcpy callback has wrong source");
+ VERIFY(udata->free_src == H5FD_FILE_IMAGE_OP_PROPERTY_LIST_SET, "freec callback has wrong source");
+
+ /* Close stuff */
+ if(H5Pclose(fapl_1) < 0) FAIL_STACK_ERROR
+ HDfree(file_image);
+ HDfree(temp_file_image);
+ HDfree(udata);
+
+ PASSED();
+ return 0;
+
+error:
+ return 1;
+} /* test_callbacks() */
+
+/******************************************************************************
+ * Function: test_core
+ *
+ * Purpose: Tests that callbacks are called properly in the core VFD and
+ * that the initial file image works properly.
+ *
+ * Programmer: Jacob Gruber
+ * Monday, August 22, 2011
+ *
+ ******************************************************************************
+ */
+static int
+test_core(void)
+{
+ hid_t fapl;
+ hid_t file;
+ hid_t dset;
+ hid_t space;
+ udata_t *udata;
+ unsigned char *file_image;
+ char filename[1024];
+ char src_dir_filename[1024];
+ const char *tmp = NULL;
+ size_t size;
+ hsize_t dims[2];
+ int fd;
+ h5_stat_t sb;
+ herr_t ret;
+ H5FD_file_image_callbacks_t callbacks = {&malloc_cb, &memcpy_cb, &realloc_cb,
+ &free_cb, &udata_copy_cb, &udata_free_cb, NULL};
+
+ TESTING("Initial file image and callbacks in Core VFD");
+
+ /* Create fapl */
+ fapl = h5_fileaccess();
+ VERIFY(fapl >= 0, "fapl creation failed");
+
+ /* Set up the core VFD */
+ ret = H5Pset_fapl_core(fapl, 0, 0);
+ VERIFY(ret >= 0, "setting core driver in fapl failed");
+
+ tmp = h5_fixname(FILENAME[0], fapl, filename, sizeof(filename));
+ VERIFY(tmp != NULL, "h5_fixname failed");
+
+ /* convert file name to srcdir file name. Make a copy as
+ * H5_get_srcdir_filename() simply sets up the file name in its
+ * own buffer each time it is called -- overwriting the previous
+ * value.
+ */
+ tmp = H5_get_srcdir_filename(filename);
+ VERIFY(tmp != NULL, "H5_get_srcdir_filename failed");
+ VERIFY(strlen(tmp) < 1023, "srcdir file name too long.");
+ HDstrncpy(src_dir_filename, tmp, 1023);
+ src_dir_filename[1023] = '\0';
+
+ /* Allocate and initialize udata */
+ udata = (udata_t *)HDmalloc(sizeof(udata_t));
+ VERIFY(udata != NULL, "udata malloc failed");
+
+ /* copy the address of the udata into the callbacks structure */
+ callbacks.udata = (void *)udata;
+
+ /* Set file image callbacks */
+ ret = H5Pset_file_image_callbacks(fapl, &callbacks);
+ VERIFY(ret >= 0, "set image callbacks failed");
+
+ /* Test open (no file image) */
+ reset_udata(udata);
+ file = H5Fopen(src_dir_filename, H5F_ACC_RDWR, fapl);
+ VERIFY(file >= 0, "H5Fopen failed");
+ VERIFY(udata->used_callbacks == MALLOC, "opening a core file used the wrong callbacks");
+ VERIFY(udata->malloc_src == H5FD_FILE_IMAGE_OP_FILE_OPEN, "Malloc callback came from wrong sourc in core open");
+
+ /* Close file */
+ reset_udata(udata);
+ ret = H5Fclose(file);
+ VERIFY(ret >= 0, "H5Fclose failed");
+ VERIFY(udata->used_callbacks == FREE, "Closing a core file used the wrong callbacks");
+ VERIFY(udata->free_src == H5FD_FILE_IMAGE_OP_FILE_CLOSE, "Free callback came from wrong sourc in core close");
+
+ /* Reopen file */
+ file = H5Fopen(src_dir_filename, H5F_ACC_RDWR, fapl);
+ VERIFY(file >= 0, "H5Fopen failed");
+
+ /* Set up a new dset */
+ dims[0] = DIM0;
+ dims[1] = DIM1;
+ space = H5Screate_simple(RANK, dims, dims);
+ VERIFY(space >= 0, "H5Screate failed");
+
+ /* Create new dset, invoking H5FD_core_write */
+ reset_udata(udata);
+ dset = H5Dcreate2(file, DSET_NAME, H5T_NATIVE_INT, space, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
+ VERIFY(dset >=0, "H5Dcreate failed");
+
+ /* Flush the write and check the realloc callback */
+ ret = H5Fflush(file, H5F_SCOPE_LOCAL);
+ VERIFY(ret >= 0, "H5Fflush failed");
+ VERIFY(udata->used_callbacks == (REALLOC), "core write used the wrong callbacks");
+ VERIFY(udata->realloc_src == H5FD_FILE_IMAGE_OP_FILE_RESIZE, "Realloc callback came from wrong source in core write");
+
+ /* Close dset and space */
+ ret = H5Dclose(dset);
+ VERIFY(ret >= 0, "H5Dclose failed");
+ ret = H5Sclose(space);
+ VERIFY(ret >= 0, "H5Sclose failed");
+
+ /* Test file close */
+ reset_udata(udata);
+ ret = H5Fclose(file);
+ VERIFY(ret >= 0, "H5Fclose failed");
+ VERIFY(udata->used_callbacks == (FREE), "Closing a core file used the wrong callbacks");
+ VERIFY(udata->free_src == H5FD_FILE_IMAGE_OP_FILE_CLOSE, "Free callback came from wrong sourc in core close");
+
+ /* Create file image buffer */
+ fd = HDopen(src_dir_filename, O_RDONLY, 0666);
+ VERIFY(fd > 0, "open failed");
+ ret = HDfstat(fd, &sb);
+ VERIFY(ret == 0, "fstat failed");
+ size = (size_t)sb.st_size;
+ file_image = (unsigned char *)HDmalloc(size);
+ HDread(fd, file_image, size);
+ ret = HDclose(fd);
+ VERIFY(ret == 0, "close failed");
+
+ /* Set file image in plist */
+ if(H5Pset_file_image(fapl, file_image, size) < 0) FAIL_STACK_ERROR
+
+ /* Test open with file image */
+ if((file = H5Fopen("dne.h5", H5F_ACC_RDWR, fapl)) < 0) FAIL_STACK_ERROR
+ if(H5Fclose(file) < 0) FAIL_STACK_ERROR
+
+ /* Release resources */
+ h5_cleanup(FILENAME, fapl);
+ HDfree(udata);
+ HDfree(file_image);
+
+ PASSED();
+
+ return 0;
+
+error:
+ return 1;
+} /* end test_core() */
+
+/******************************************************************************
+ * Function: test_get_file_image
+ *
+ * Purpose: Test the H5Fget_file_image() call.
+ *
+ * Programmer: John Mainzer
+ * Tuesday, November 15, 2011
+ *
+ ******************************************************************************
+ */
+static int
+test_get_file_image(const char * test_banner,
+ const int file_name_num,
+ hid_t fapl)
+{
+ char file_name[1024] = "\0";
+ void * insertion_ptr = NULL;
+ void * image_ptr = NULL;
+ void * file_image_ptr = NULL;
+ hbool_t is_family_file = FALSE;
+ hbool_t identical;
+ int data[100];
+ int i;
+ int fd = -1;
+ int result;
+ hid_t driver = -1;
+ hid_t file_id = -1;
+ hid_t dset_id = -1;
+ hid_t space_id = -1;
+ hid_t core_fapl_id = -1;
+ hid_t core_file_id = -1;
+ herr_t err;
+ hsize_t dims[2];
+ ssize_t bytes_read;
+ ssize_t image_size;
+ ssize_t file_size;
+ h5_stat_t stat_buf;
+
+ TESTING(test_banner);
+
+ /* set flag if we are dealing with a family file */
+ driver = H5Pget_driver(fapl);
+ VERIFY(driver >= 0, "H5Pget_driver(fapl) failed");
+
+ if(driver == H5FD_FAMILY)
+ is_family_file = TRUE;
+
+ /* setup the file name */
+ h5_fixname(FILENAME2[file_name_num], fapl, file_name, sizeof(file_name));
+ VERIFY(HDstrlen(file_name)>0, "h5_fixname failed");
+
+ /* create the file */
+ file_id = H5Fcreate(file_name, 0, H5P_DEFAULT, fapl);
+ VERIFY(file_id >= 0, "H5Fcreate() failed.");
+
+ /* Set up data space for new new data set */
+ dims[0] = 10;
+ dims[1] = 10;
+ space_id = H5Screate_simple(2, dims, dims);
+ VERIFY(space_id >= 0, "H5Screate() failed");
+
+ /* Create a dataset */
+ dset_id = H5Dcreate2(file_id, "dset 0", H5T_NATIVE_INT, space_id,
+ H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
+ VERIFY(dset_id >=0, "H5Dcreate() failed");
+
+ /* write some data to the data set */
+ for (i = 0; i < 100; i++)
+ data[i] = i;
+ err = H5Dwrite(dset_id, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, (void *)data);
+ VERIFY(err >= 0, "H5Dwrite() failed.");
+
+ /* Flush the file */
+ err = H5Fflush(file_id, H5F_SCOPE_GLOBAL);
+ VERIFY(err >= 0, "H5Fflush failed");
+
+ /* get the size of the file */
+ image_size = H5Fget_file_image(file_id, NULL, (size_t)0);
+ VERIFY(image_size > 0, "H5Fget_file_image(1) failed.");
+
+ /* allocate a buffer of the appropriate size */
+ image_ptr = HDmalloc((size_t)image_size);
+ VERIFY(image_ptr != NULL, "HDmalloc(1) failed.");
+
+ /* load the image of the file into the buffer */
+ bytes_read = H5Fget_file_image(file_id, image_ptr, (size_t)image_size);
+ VERIFY(bytes_read == image_size, "H5Fget_file_image(2) failed.");
+
+ /* Close dset and space */
+ err = H5Dclose(dset_id);
+ VERIFY(err >= 0, "H5Dclose failed");
+ err = H5Sclose(space_id);
+ VERIFY(err >= 0, "H5Sclose failed");
+
+ /* close the test file */
+ err = H5Fclose(file_id);
+ VERIFY(err == SUCCEED, "H5Fclose(file_id) failed.");
+
+ if(is_family_file) {
+ char member_file_name[1024];
+ ssize_t bytes_to_read;
+ ssize_t member_size;
+ ssize_t size_remaining;
+
+ i = 0;
+ file_size = 0;
+
+ do {
+ HDsnprintf(member_file_name, 1024, file_name, i);
+
+ /* get the size of the member file */
+ result = HDstat(member_file_name, &stat_buf);
+ VERIFY(result == 0, "HDstat() failed.");
+
+ member_size = (ssize_t)stat_buf.st_size;
+
+ i++;
+ file_size += member_size;
+ } while(member_size > 0);
+
+ /* Since we use the eoa to calculate the image size, the file size
+ * may be larger. This is OK, as long as (in this specialized instance)
+ * the remainder of the file is all '\0's.
+ */
+ VERIFY(file_size >= image_size, "file size != image size.");
+
+ /* allocate a buffer for the test file image */
+ file_image_ptr = HDmalloc((size_t)file_size);
+ VERIFY(file_image_ptr != NULL, "HDmalloc(2f) failed.");
+
+ size_remaining = image_size;
+ insertion_ptr = file_image_ptr;
+ i = 0;
+
+ while(size_remaining > 0) {
+ /* construct the member file name */
+ HDsnprintf(member_file_name, 1024, file_name, i);
+
+ /* open the test file using standard I/O calls */
+ fd = HDopen(member_file_name, O_RDONLY, 0666);
+ VERIFY(fd >= 0, "HDopen() failed.");
+
+ if(size_remaining >= FAMILY_SIZE ){
+ bytes_to_read = FAMILY_SIZE;
+ size_remaining -= FAMILY_SIZE;
+ } else {
+ bytes_to_read = size_remaining;
+ size_remaining = 0;
+ }
+
+ /* read the member file from disk into the buffer */
+ bytes_read = HDread(fd, insertion_ptr, (size_t)bytes_to_read);
+ VERIFY(bytes_read == bytes_to_read, "HDread() failed.");
+
+ insertion_ptr = (void *)(((char *)insertion_ptr) + bytes_to_read);
+
+ i++;
+
+ /* close the test file */
+ result = HDclose(fd);
+ VERIFY(result == 0, "HDclose() failed.");
+ }
+ } else {
+ /* get the size of the test file */
+ result = HDstat(file_name, &stat_buf);
+ VERIFY(result == 0, "HDstat() failed.");
+
+ /* Since we use the eoa to calculate the image size, the file size
+ * may be larger. This is OK, as long as (in this specialized instance)
+ * the remainder of the file is all '\0's.
+ */
+ file_size = (ssize_t)stat_buf.st_size;
+
+ /* with latest mods to truncate call in core file drive,
+ * file size should match image size
+ */
+ VERIFY(file_size == image_size, "file size != image size.");
+
+ /* allocate a buffer for the test file image */
+ file_image_ptr = HDmalloc((size_t)file_size);
+ VERIFY(file_image_ptr != NULL, "HDmalloc(2) failed.");
+
+ /* open the test file using standard I/O calls */
+ fd = HDopen(file_name, O_RDONLY, 0666);
+ VERIFY(fd >= 0, "HDopen() failed.");
+
+ /* read the test file from disk into the buffer */
+ bytes_read = HDread(fd, file_image_ptr, (size_t)file_size);
+ VERIFY(bytes_read == file_size, "HDread() failed.");
+
+ /* close the test file */
+ result = HDclose(fd);
+ VERIFY(result == 0, "HDclose() failed.");
+ }
+
+ /* verify that the file and the image contain the same data */
+ identical = TRUE;
+ i = 0;
+ while((i < (int)image_size) && identical) {
+ if(((char *)image_ptr)[i] != ((char *)file_image_ptr)[i])
+ identical = FALSE;
+ i++;
+ }
+ VERIFY(identical, "file and image differ.");
+
+
+ /* finally, verify that we can use the core file driver to open the image */
+
+ /* create fapl for core file driver */
+ core_fapl_id = H5Pcreate(H5P_FILE_ACCESS);
+ VERIFY(core_fapl_id >=0, "H5Pcreate() failed");
+
+ /* setup core_fapl_id to use the core file driver */
+ err = H5Pset_fapl_core(core_fapl_id, (size_t)(64 * 1024), FALSE);
+ VERIFY(err == SUCCEED, "H5Pset_fapl_core() failed.");
+
+ /* Set file image in core fapl */
+ err = H5Pset_file_image(core_fapl_id, image_ptr, (size_t)image_size);
+ VERIFY(err == SUCCEED, "H5Pset_file_image() failed.");
+
+ /* open the file image with the core file driver */
+ core_file_id = H5Fopen("nonesuch", H5F_ACC_RDWR, core_fapl_id);
+ VERIFY(core_file_id >= 0, "H5Fopen() of file image failed.");
+
+ /* close the file image with the core file driver */
+ err = H5Fclose(core_file_id);
+ VERIFY(err == SUCCEED, "H5Fclose(core_file_id) failed.");
+
+ /* dicard core fapl */
+ err = H5Pclose(core_fapl_id);
+ VERIFY(err == SUCCEED, "H5Pclose(core_fapl_id) failed.");
+
+ /* tidy up */
+ result = h5_cleanup(FILENAME2, fapl);
+ VERIFY(result != 0, "h5_cleanup() failed.");
+
+ /* discard the image buffer if it exists */
+ if(image_ptr != NULL)
+ HDfree(image_ptr);
+
+ /* discard the image buffer if it exists */
+ if(file_image_ptr != NULL)
+ HDfree(file_image_ptr);
+
+ PASSED();
+
+ return 0;
+
+error:
+ return 1;
+} /* end test_get_file_image() */
+
+/******************************************************************************
+ * Function: test_get_file_image_error_rejection
+ *
+ * Purpose: Verify that H5Fget_file_image() rejects invalid input.
+ *
+ * Programmer: John Mainzer
+ * Tuesday, November 22, 2011
+ *
+ ******************************************************************************
+ */
+
+#define TYPE_SLICE ((haddr_t)0x10000LL)
+
+static int
+test_get_file_image_error_rejection(void)
+{
+ const char *memb_name[H5FD_MEM_NTYPES];
+ char file_name[1024] = "\0";
+ void * image_ptr = NULL;
+ int data[100];
+ int i;
+ int result;
+ hid_t fapl_id = -1;
+ hid_t file_id = -1;
+ hid_t dset_id = -1;
+ hid_t space_id = -1;
+ herr_t err;
+ hsize_t dims[2];
+ ssize_t bytes_read;
+ ssize_t image_size;
+ hid_t memb_fapl[H5FD_MEM_NTYPES];
+ haddr_t memb_addr[H5FD_MEM_NTYPES];
+ H5FD_mem_t mt;
+ H5FD_mem_t memb_map[H5FD_MEM_NTYPES];
+
+
+ TESTING("H5Fget_file_image() error rejection");
+
+ /************************ Sub-Test #1 ********************************/
+ /* set up a test file, and try to get its image with a buffer that is
+ * too small. Call to H5Fget_file_image() should fail.
+ *
+ * Since we have already done the necessary setup, verify that
+ * H5Fget_file_image() will fail with:
+ *
+ * bad file id, or
+ *
+ * good id, but not a file id
+ */
+
+
+ /* setup fapl -- driver type doesn't matter much, so make it stdio */
+ fapl_id = H5Pcreate(H5P_FILE_ACCESS);
+ VERIFY(fapl_id >= 0, "H5Pcreate(1) failed");
+
+ err = H5Pset_fapl_stdio(fapl_id);
+ VERIFY(err >= 0, "H5Pset_fapl_stdio() failed");
+
+ /* setup the file name */
+ h5_fixname(FILENAME2[6], fapl_id, file_name, sizeof(file_name));
+ VERIFY(HDstrlen(file_name)>0, "h5_fixname failed");
+
+ /* create the file */
+ file_id = H5Fcreate(file_name, 0, H5P_DEFAULT, fapl_id);
+ VERIFY(file_id >= 0, "H5Fcreate() failed.");
+
+ /* Set up data space for new new data set */
+ dims[0] = 10;
+ dims[1] = 10;
+ space_id = H5Screate_simple(2, dims, dims);
+ VERIFY(space_id >= 0, "H5Screate() failed");
+
+ /* Create a dataset */
+ dset_id = H5Dcreate2(file_id, "dset 0", H5T_NATIVE_INT, space_id,
+ H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
+ VERIFY(dset_id >=0, "H5Dcreate() failed");
+
+ /* write some data to the data set */
+ for (i = 0; i < 100; i++)
+ data[i] = i;
+ err = H5Dwrite(dset_id, H5T_NATIVE_INT, H5S_ALL, H5S_ALL,
+ H5P_DEFAULT, (void *)data);
+ VERIFY(err >= 0, "H5Dwrite() failed.");
+
+ /* Flush the file */
+ err = H5Fflush(file_id, H5F_SCOPE_GLOBAL);
+ VERIFY(err >= 0, "H5Fflush failed");
+
+ /* get the size of the file */
+ image_size = H5Fget_file_image(file_id, NULL, (size_t)0);
+ VERIFY(image_size > 0, "H5Fget_file_image(1 -- test 1) failed.");
+
+ /* allocate a buffer of the appropriate size */
+ image_ptr = HDmalloc((size_t)image_size);
+ VERIFY(image_ptr != NULL, "HDmalloc(1) failed.");
+
+ /* load the image of the file into the buffer */
+ H5E_BEGIN_TRY {
+ bytes_read = H5Fget_file_image(file_id, image_ptr, (size_t)(image_size - 1));
+ } H5E_END_TRY;
+ VERIFY(bytes_read < 0, "H5Fget_file_image(2 -- test 1) succeeded.");
+
+ /* Call H5Fget_file_image() with good buffer and buffer size,
+ * but non-existant file_id. Should fail.
+ */
+ H5E_BEGIN_TRY {
+ bytes_read = H5Fget_file_image((hid_t)0, image_ptr, (size_t)(image_size));
+ } H5E_END_TRY;
+ VERIFY(bytes_read < 0, "H5Fget_file_image(3 -- test 1) succeeded.");
+
+ /* Call H5Fget_file_image() with good buffer and buffer size,
+ * but a file_id of the wrong type. Should fail.
+ */
+ H5E_BEGIN_TRY {
+ bytes_read = H5Fget_file_image(dset_id, image_ptr, (size_t)(image_size));
+ } H5E_END_TRY;
+ VERIFY(bytes_read < 0, "H5Fget_file_image(4 -- test 1) succeeded.");
+
+ /* Close dset and space */
+ err = H5Dclose(dset_id);
+ VERIFY(err >= 0, "H5Dclose failed");
+ err = H5Sclose(space_id);
+ VERIFY(err >= 0, "H5Sclose failed");
+
+ /* close the test file */
+ err = H5Fclose(file_id);
+ VERIFY(err == SUCCEED, "H5Fclose(file_id) failed.");
+
+ /* tidy up */
+ result = h5_cleanup(FILENAME2, fapl_id);
+ VERIFY(result != 0, "h5_cleanup(1) failed.");
+
+ /* discard the image buffer if it exists */
+ if(image_ptr != NULL)
+ HDfree(image_ptr);
+
+ /************************** Test #2 **********************************/
+ /* set up a multi file driver test file, and try to get its image
+ * with H5Fget_file_image(). Attempt should fail.
+ */
+
+ /* setup parameters for multi file driver */
+ for(mt = (H5FD_mem_t)0; mt < H5FD_MEM_NTYPES; mt = (H5FD_mem_t)(mt + 1)) {
+ memb_addr[mt] = HADDR_UNDEF;
+ memb_fapl[mt] = H5P_DEFAULT;
+ memb_map[mt] = H5FD_MEM_DRAW;
+ memb_name[mt] = NULL;
+ }
+
+ memb_map[H5FD_MEM_SUPER] = H5FD_MEM_SUPER;
+ memb_fapl[H5FD_MEM_SUPER] = H5P_DEFAULT;
+ memb_name[H5FD_MEM_SUPER] = "%s-s.h5";
+ memb_addr[H5FD_MEM_SUPER] = 0;
+
+ memb_map[H5FD_MEM_BTREE] = H5FD_MEM_BTREE;
+ memb_fapl[H5FD_MEM_BTREE] = H5P_DEFAULT;
+ memb_name[H5FD_MEM_BTREE] = "%s-b.h5";
+ memb_addr[H5FD_MEM_BTREE] = memb_addr[H5FD_MEM_SUPER] + TYPE_SLICE;
+
+ memb_map[H5FD_MEM_DRAW] = H5FD_MEM_DRAW;
+ memb_fapl[H5FD_MEM_DRAW] = H5P_DEFAULT;
+ memb_name[H5FD_MEM_DRAW] = "%s-r.h5";
+ memb_addr[H5FD_MEM_DRAW] = memb_addr[H5FD_MEM_BTREE] + TYPE_SLICE;
+
+ memb_map[H5FD_MEM_GHEAP] = H5FD_MEM_GHEAP;
+ memb_fapl[H5FD_MEM_GHEAP] = H5P_DEFAULT;
+ memb_name[H5FD_MEM_GHEAP] = "%s-g.h5";
+ memb_addr[H5FD_MEM_GHEAP] = memb_addr[H5FD_MEM_DRAW] + TYPE_SLICE;
+
+ memb_map[H5FD_MEM_LHEAP] = H5FD_MEM_LHEAP;
+ memb_fapl[H5FD_MEM_LHEAP] = H5P_DEFAULT;
+ memb_name[H5FD_MEM_LHEAP] = "%s-l.h5";
+ memb_addr[H5FD_MEM_LHEAP] = memb_addr[H5FD_MEM_GHEAP] + TYPE_SLICE;
+
+ memb_map[H5FD_MEM_OHDR] = H5FD_MEM_OHDR;
+ memb_fapl[H5FD_MEM_OHDR] = H5P_DEFAULT;
+ memb_name[H5FD_MEM_OHDR] = "%s-o.h5";
+ memb_addr[H5FD_MEM_OHDR] = memb_addr[H5FD_MEM_LHEAP] + TYPE_SLICE;
+
+ /* setup fapl */
+ fapl_id = H5Pcreate(H5P_FILE_ACCESS);
+ VERIFY(fapl_id >= 0, "H5Pcreate(2) failed");
+
+ /* setup the fapl for the multi file driver */
+ err = H5Pset_fapl_multi(fapl_id, memb_map, memb_fapl, memb_name,
+ memb_addr, FALSE);
+ VERIFY(err >= 0, "H5Pset_fapl_multi failed");
+
+ /* setup the file name */
+ h5_fixname(FILENAME2[4], fapl_id, file_name, sizeof(file_name));
+ VERIFY(HDstrlen(file_name)>0, "h5_fixname failed");
+
+ /* create the file */
+ file_id = H5Fcreate(file_name, 0, H5P_DEFAULT, fapl_id);
+ VERIFY(file_id >= 0, "H5Fcreate() failed.");
+
+ /* Set up data space for new new data set */
+ dims[0] = 10;
+ dims[1] = 10;
+ space_id = H5Screate_simple(2, dims, dims);
+ VERIFY(space_id >= 0, "H5Screate() failed");
+
+ /* Create a dataset */
+ dset_id = H5Dcreate2(file_id, "dset 0", H5T_NATIVE_INT, space_id,
+ H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
+ VERIFY(dset_id >=0, "H5Dcreate() failed");
+
+ /* write some data to the data set */
+ for (i = 0; i < 100; i++)
+ data[i] = i;
+ err = H5Dwrite(dset_id, H5T_NATIVE_INT, H5S_ALL, H5S_ALL,
+ H5P_DEFAULT, (void *)data);
+ VERIFY(err >= 0, "H5Dwrite() failed.");
+
+ /* Flush the file */
+ err = H5Fflush(file_id, H5F_SCOPE_GLOBAL);
+ VERIFY(err >= 0, "H5Fflush failed");
+
+ /* attempt to get the size of the file -- should fail */
+ H5E_BEGIN_TRY {
+ image_size = H5Fget_file_image(file_id, NULL, (size_t)0);
+ } H5E_END_TRY;
+ VERIFY(image_size == -1, "H5Fget_file_image(5) succeeded.");
+
+ /* Close dset and space */
+ err = H5Dclose(dset_id);
+ VERIFY(err >= 0, "H5Dclose failed");
+ err = H5Sclose(space_id);
+ VERIFY(err >= 0, "H5Sclose failed");
+
+ /* close the test file */
+ err = H5Fclose(file_id);
+ VERIFY(err == SUCCEED, "H5Fclose(2) failed.");
+
+ /* tidy up */
+ result = h5_cleanup(FILENAME2, fapl_id);
+ VERIFY(result != 0, "h5_cleanup(2 failed.");
+
+ /************************** Test #3 **********************************/
+ /* set up a split file driver test file, and try to get its image
+ * with H5Fget_file_image(). Attempt should fail.
+ */
+
+ /* create fapl */
+ fapl_id = H5Pcreate(H5P_FILE_ACCESS);
+ VERIFY(fapl_id >= 0, "H5Pcreate(3) failed");
+
+ /* setup the fapl for the split file driver */
+ err = H5Pset_fapl_split(fapl_id, "-m.h5", H5P_DEFAULT, "-r.h5", H5P_DEFAULT);
+ VERIFY(err >= 0, "H5Pset_fapl_split failed");
+
+ /* setup the file name */
+ h5_fixname(FILENAME2[5], fapl_id, file_name, sizeof(file_name));
+ VERIFY(HDstrlen(file_name)>0, "h5_fixname failed");
+
+ /* create the file */
+ file_id = H5Fcreate(file_name, 0, H5P_DEFAULT, fapl_id);
+ VERIFY(file_id >= 0, "H5Fcreate() failed.");
+
+ /* Set up data space for new new data set */
+ dims[0] = 10;
+ dims[1] = 10;
+ space_id = H5Screate_simple(2, dims, dims);
+ VERIFY(space_id >= 0, "H5Screate() failed");
+
+ /* Create a dataset */
+ dset_id = H5Dcreate2(file_id, "dset 0", H5T_NATIVE_INT, space_id,
+ H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
+ VERIFY(dset_id >=0, "H5Dcreate() failed");
+
+ /* write some data to the data set */
+ for (i = 0; i < 100; i++)
+ data[i] = i;
+ err = H5Dwrite(dset_id, H5T_NATIVE_INT, H5S_ALL, H5S_ALL,
+ H5P_DEFAULT, (void *)data);
+ VERIFY(err >= 0, "H5Dwrite() failed.");
+
+ /* Flush the file */
+ err = H5Fflush(file_id, H5F_SCOPE_GLOBAL);
+ VERIFY(err >= 0, "H5Fflush failed");
+
+ /* attempt to get the size of the file -- should fail */
+ H5E_BEGIN_TRY {
+ image_size = H5Fget_file_image(file_id, NULL, (size_t)0);
+ } H5E_END_TRY;
+ VERIFY(image_size == -1, "H5Fget_file_image(6) succeeded.");
+
+ /* Close dset and space */
+ err = H5Dclose(dset_id);
+ VERIFY(err >= 0, "H5Dclose failed");
+ err = H5Sclose(space_id);
+ VERIFY(err >= 0, "H5Sclose failed");
+
+ /* close the test file */
+ err = H5Fclose(file_id);
+ VERIFY(err == SUCCEED, "H5Fclose(2) failed.");
+
+
+ /************************** Test #4 **********************************/
+ /* set up a family file driver test file, and try to get its image
+ * with H5Fget_file_image(). Attempt should fail.
+ */
+
+ /* create fapl */
+ fapl_id = H5Pcreate(H5P_FILE_ACCESS);
+ VERIFY(fapl_id >= 0, "H5Pcreate(3) failed");
+
+ err = H5Pset_fapl_family(fapl_id, (hsize_t)FAMILY_SIZE, H5P_DEFAULT);
+ VERIFY(err >= 0, "H5Pset_fapl_family failed");
+
+ h5_fixname(FILENAME2[3], fapl_id, file_name, sizeof(file_name));
+ VERIFY(HDstrlen(file_name)>0, "h5_fixname failed");
+
+ /* create the file */
+ file_id = H5Fcreate(file_name, 0, H5P_DEFAULT, fapl_id);
+ VERIFY(file_id >= 0, "H5Fcreate() failed.");
+
+ /* Set up data space for new new data set */
+ dims[0] = 10;
+ dims[1] = 10;
+ space_id = H5Screate_simple(2, dims, dims);
+ VERIFY(space_id >= 0, "H5Screate() failed");
+
+ /* Create a dataset */
+ dset_id = H5Dcreate2(file_id, "dset 0", H5T_NATIVE_INT, space_id,
+ H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
+ VERIFY(dset_id >=0, "H5Dcreate() failed");
+
+ /* write some data to the data set */
+ for (i = 0; i < 100; i++)
+ data[i] = i;
+ err = H5Dwrite(dset_id, H5T_NATIVE_INT, H5S_ALL, H5S_ALL,
+ H5P_DEFAULT, (void *)data);
+ VERIFY(err >= 0, "H5Dwrite() failed.");
+
+ /* Flush the file */
+ err = H5Fflush(file_id, H5F_SCOPE_GLOBAL);
+ VERIFY(err >= 0, "H5Fflush failed");
+
+ /* attempt to get the size of the file -- should fail */
+ H5E_BEGIN_TRY {
+ image_size = H5Fget_file_image(file_id, NULL, (size_t)0);
+ } H5E_END_TRY;
+ VERIFY(image_size == -1, "H5Fget_file_image(7) succeeded.");
+
+ /* Close dset and space */
+ err = H5Dclose(dset_id);
+ VERIFY(err >= 0, "H5Dclose failed");
+ err = H5Sclose(space_id);
+ VERIFY(err >= 0, "H5Sclose failed");
+
+ /* close the test file */
+ err = H5Fclose(file_id);
+ VERIFY(err == SUCCEED, "H5Fclose(2) failed.");
+
+ /* tidy up */
+ result = h5_cleanup(FILENAME2, fapl_id);
+ VERIFY(result != 0, "h5_cleanup(2 failed.");
+
+ PASSED();
+
+ return 0;
+
+error:
+ return 1;
+}
+
+int
+main(void)
+{
+ int errors = 0;
+ hid_t fapl;
+
+ h5_reset();
+
+ printf("Testing File Image Functionality.\n");
+
+ errors += test_properties();
+ errors += test_callbacks();
+ errors += test_core();
+
+ /* test H5Fget_file_image() with sec2 driver */
+ fapl = H5Pcreate(H5P_FILE_ACCESS);
+ if(0 > H5Pset_fapl_sec2(fapl))
+ errors++;
+ else
+ errors += test_get_file_image("H5Fget_file_image() with sec2 driver",
+ 0, fapl);
+
+ /* test H5Fget_file_image() with stdio driver */
+ fapl = H5Pcreate(H5P_FILE_ACCESS);
+ if(0 > H5Pset_fapl_stdio(fapl))
+ errors++;
+ else
+ errors += test_get_file_image("H5Fget_file_image() with stdio driver",
+ 1, fapl);
+
+ /* test H5Fget_file_image() with core driver */
+ fapl = H5Pcreate(H5P_FILE_ACCESS);
+ if(0 > H5Pset_fapl_core(fapl, (size_t)(64 *1024), TRUE))
+ errors++;
+ else
+ errors += test_get_file_image("H5Fget_file_image() with core driver",
+ 2, fapl);
+
+#if 0
+ /* at present, H5Fget_file_image() rejects files opened with the
+ * family file driver, due to the addition of a driver info message
+ * in the super block. This message prevents the image being opened
+ * with any driver other than the family file driver, which sort of
+ * defeats the purpose of the get file image operation.
+ *
+ * While this issues is quite fixable, we don't have time or resources
+ * for this right now. Once we do, the following code should be
+ * suitable for testing the fix.
+ */
+ /* test H5Fget_file_image() with family file driver */
+ fapl = H5Pcreate(H5P_FILE_ACCESS);
+ if(H5Pset_fapl_family(fapl, (hsize_t)FAMILY_SIZE, H5P_DEFAULT) < 0)
+ errors++;
+ else
+ errors += test_get_file_image("H5Fget_file_image() with family driver",
+ 3, fapl);
+#endif
+
+ errors += test_get_file_image_error_rejection();
+
+
+ if(errors) {
+ printf("***** %d File Image TEST%s FAILED! *****\n",
+ errors, errors > 1 ? "S" : "");
+ return 1;
+ }
+
+ printf("All File Image tests passed.\n");
+ return 0;
+}
+
diff --git a/test/file_image_core_test.h5 b/test/file_image_core_test.h5
new file mode 100644
index 0000000..1cc5130
--- /dev/null
+++ b/test/file_image_core_test.h5
Binary files differ
diff --git a/test/gen_file_image.c b/test/gen_file_image.c
new file mode 100644
index 0000000..bc9de29
--- /dev/null
+++ b/test/gen_file_image.c
@@ -0,0 +1,91 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * 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. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Programmer: Quincey Koziol <koziol@ncsa.uiuc.edu>
+ * Friday, March 30, 2012
+ *
+ * Purpose: Create a simple file for use with the file image tests.
+ *
+ */
+#include "hdf5.h"
+
+#define TESTFILE "file_image_core_test.h5"
+
+/* 2-D dataset with fixed dimensions */
+#define SPACE_RANK 2
+#define SPACE_DIM1 128
+#define SPACE_DIM2 32
+
+/* Dataset data */
+int data[SPACE_DIM1][SPACE_DIM2];
+
+
+/*-------------------------------------------------------------------------
+ * Function: main
+ *
+ * Purpose:
+ *
+ * Return: Success:
+ *
+ * Failure:
+ *
+ * Programmer: Quincey Koziol
+ * Friday, March 30, 2012
+ *
+ *-------------------------------------------------------------------------
+ */
+int
+main(void)
+{
+ hid_t file, space, dset;
+ hsize_t dims[SPACE_RANK] = {SPACE_DIM1, SPACE_DIM2};
+ size_t i, j; /* Local index variables */
+
+ /* Initialize the data */
+ for(i = 0; i < SPACE_DIM1; i++)
+ for(j = 0; j < SPACE_DIM2; j++)
+ data[i][j] = (int)(j % 5);
+
+ /* Create the file */
+ file = H5Fcreate(TESTFILE, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT);
+ if(file < 0)
+ printf("file < 0!\n");
+
+ /* Create the dataspace */
+ space = H5Screate_simple(SPACE_RANK, dims, NULL);
+ if(space < 0)
+ printf("space < 0!\n");
+
+ /* Create the compressed dataset */
+ dset = H5Dcreate2(file, "Dataset1", H5T_NATIVE_INT, space, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
+ if(dset < 0)
+ printf("dset < 0!\n");
+
+ /* Write the data to the dataset */
+ if(H5Dwrite(dset, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, data) < 0)
+ printf("H5Dwrite() failed!\n");
+
+ /* Close everything */
+ if(H5Dclose(dset) < 0)
+ printf("H5Dclose() failed!\n");
+ if(H5Sclose(space) < 0)
+ printf("H5Sclose() failed!\n");
+ if(H5Fclose(file) < 0)
+ printf("H5Fclose() failed!\n");
+
+ return 0;
+}
+
diff --git a/testpar/Makefile.am b/testpar/Makefile.am
index 5a7a3f3..b2fb97c 100644
--- a/testpar/Makefile.am
+++ b/testpar/Makefile.am
@@ -31,8 +31,8 @@ TEST_SCRIPT_PARA=testph5.sh
check_PROGRAMS = $(TEST_PROG_PARA)
check_SCRIPTS= $(TEST_SCRIPT)
-testphdf5_SOURCES=testphdf5.c t_dset.c t_file.c t_mdset.c t_ph5basic.c \
- t_coll_chunk.c t_span_tree.c t_chunk_alloc.c t_filter_read.c
+testphdf5_SOURCES=testphdf5.c t_dset.c t_file.c t_file_image.c t_mdset.c \
+ t_ph5basic.c t_coll_chunk.c t_span_tree.c t_chunk_alloc.c t_filter_read.c
# The tests all depend on the hdf5 library and the test library
LDADD = $(LIBH5TEST) $(LIBHDF5)
diff --git a/testpar/Makefile.in b/testpar/Makefile.in
index ae0c7d0..a9a4135 100644
--- a/testpar/Makefile.in
+++ b/testpar/Makefile.in
@@ -95,9 +95,10 @@ t_shapesame_OBJECTS = t_shapesame.$(OBJEXT)
t_shapesame_LDADD = $(LDADD)
t_shapesame_DEPENDENCIES = $(LIBH5TEST) $(LIBHDF5)
am_testphdf5_OBJECTS = testphdf5.$(OBJEXT) t_dset.$(OBJEXT) \
- t_file.$(OBJEXT) t_mdset.$(OBJEXT) t_ph5basic.$(OBJEXT) \
- t_coll_chunk.$(OBJEXT) t_span_tree.$(OBJEXT) \
- t_chunk_alloc.$(OBJEXT) t_filter_read.$(OBJEXT)
+ t_file.$(OBJEXT) t_file_image.$(OBJEXT) t_mdset.$(OBJEXT) \
+ t_ph5basic.$(OBJEXT) t_coll_chunk.$(OBJEXT) \
+ t_span_tree.$(OBJEXT) t_chunk_alloc.$(OBJEXT) \
+ t_filter_read.$(OBJEXT)
testphdf5_OBJECTS = $(am_testphdf5_OBJECTS)
testphdf5_LDADD = $(LDADD)
testphdf5_DEPENDENCIES = $(LIBH5TEST) $(LIBHDF5)
@@ -431,8 +432,8 @@ INCLUDES = -I$(top_srcdir)/src -I$(top_srcdir)/test
TEST_PROG_PARA = t_mpi t_posix_compliant testphdf5 t_cache t_pflush1 t_pflush2 t_shapesame
TEST_SCRIPT_PARA = testph5.sh
check_SCRIPTS = $(TEST_SCRIPT)
-testphdf5_SOURCES = testphdf5.c t_dset.c t_file.c t_mdset.c t_ph5basic.c \
- t_coll_chunk.c t_span_tree.c t_chunk_alloc.c t_filter_read.c
+testphdf5_SOURCES = testphdf5.c t_dset.c t_file.c t_file_image.c t_mdset.c \
+ t_ph5basic.c t_coll_chunk.c t_span_tree.c t_chunk_alloc.c t_filter_read.c
# The tests all depend on the hdf5 library and the test library
@@ -532,6 +533,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/t_coll_chunk.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/t_dset.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/t_file.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/t_file_image.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/t_filter_read.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/t_mdset.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/t_mpi.Po@am__quote@
diff --git a/testpar/t_file_image.c b/testpar/t_file_image.c
new file mode 100644
index 0000000..d265957
--- /dev/null
+++ b/testpar/t_file_image.c
@@ -0,0 +1,395 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * 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. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Parallel tests for file image operations
+ */
+
+#include "testphdf5.h"
+
+/* file_image_daisy_chain_test
+ *
+ * Process zero:
+ *
+ * 1) Creates a core file with an integer vector data set of
+ * length n (= mpi_size),
+ *
+ * 2) Initializes the vector to zero in * location 0, and to -1
+ * everywhere else.
+ *
+ * 3) Flushes the core file, and gets an image of it. Closes
+ * the core file.
+ *
+ * 4) Sends the image to process 1.
+ *
+ * 5) Awaits receipt on a file image from process n-1.
+ *
+ * 6) opens the image received from process n-1, verifies that
+ * it contains a vector of length equal to mpi_size, and
+ * that the vector contains (0, 1, 2, ... n-1)
+ *
+ * 7) closes the core file and exits.
+ *
+ * Process i (0 < i < n)
+ *
+ * 1) Await receipt of file image from process (i - 1).
+ *
+ * 2) Open the image with the core file driver, verify that i
+ * contains a vector v of length, and that v[j] = j for
+ * 0 <= j < i, and that v[j] == -1 for i <= j < n
+ *
+ * 3) Set v[i] = i in the core file.
+ *
+ * 4) Flush the core file and send it to process (i + 1) % n.
+ *
+ * 5) close the core file and exit.
+ *
+ * Test fails on a hang (if an image is not received), or on invalid data.
+ *
+ * JRM -- 11/28/11
+ */
+void
+file_image_daisy_chain_test(void)
+{
+ char file_name[1024] = "\0";
+ int mpi_size, mpi_rank;
+ int mpi_result;
+ int i;
+ int space_ndims;
+ MPI_Status rcvstat;
+ int * vector_ptr = NULL;
+ hid_t fapl_id = -1;
+ hid_t file_id; /* file IDs */
+ hid_t dset_id = -1;
+ hid_t dset_type_id = -1;
+ hid_t space_id = -1;
+ herr_t err;
+ hsize_t dims[1];
+ void * image_ptr = NULL;
+ ssize_t bytes_read;
+ ssize_t image_len;
+ hbool_t vector_ok = TRUE;
+ htri_t tri_result;
+
+
+ /* set up MPI parameters */
+ MPI_Comm_size(MPI_COMM_WORLD, &mpi_size);
+ MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank);
+
+ /* setup file name */
+ HDsnprintf(file_name, 1024, "file_image_daisy_chain_test_%05d.h5",
+ (int)mpi_rank);
+
+ if(mpi_rank == 0) {
+
+ /* 1) Creates a core file with an integer vector data set
+ * of length mpi_size,
+ */
+ fapl_id = H5Pcreate(H5P_FILE_ACCESS);
+ VRFY((fapl_id >= 0), "creating fapl");
+
+ err = H5Pset_fapl_core(fapl_id, (size_t)(64 *1024), FALSE);
+ VRFY((err >= 0), "setting core file driver in fapl.");
+
+ file_id = H5Fcreate(file_name, 0, H5P_DEFAULT, fapl_id);
+ VRFY((file_id >= 0), "created core file");
+
+ dims[0] = (hsize_t)mpi_size;
+ space_id = H5Screate_simple(1, dims, dims);
+ VRFY((space_id >= 0), "created data space");
+
+ dset_id = H5Dcreate2(file_id, "v", H5T_NATIVE_INT, space_id,
+ H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
+ VRFY((dset_id >= 0), "created data set");
+
+
+ /* 2) Initialize the vector to zero in location 0, and
+ * to -1 everywhere else.
+ */
+
+ vector_ptr = (int *)HDmalloc((size_t)(mpi_size) * sizeof(int));
+ VRFY((vector_ptr != NULL), "allocated in memory representation of vector");
+
+ vector_ptr[0] = 0;
+ for(i = 1; i < mpi_size; i++)
+ vector_ptr[i] = -1;
+
+ err = H5Dwrite(dset_id, H5T_NATIVE_INT, H5S_ALL, H5S_ALL,
+ H5P_DEFAULT, (void *)vector_ptr);
+ VRFY((err >= 0), "wrote initial data to vector.");
+
+ HDfree(vector_ptr);
+ vector_ptr = NULL;
+
+
+ /* 3) Flush the core file, and get an image of it. Close
+ * the core file.
+ */
+ err = H5Fflush(file_id, H5F_SCOPE_GLOBAL);
+ VRFY((err >= 0), "flushed core file.");
+
+ image_len = H5Fget_file_image(file_id, NULL, (size_t)0);
+ VRFY((image_len > 0), "got image file size");
+
+ image_ptr = (void *)HDmalloc((size_t)image_len);
+ VRFY(image_ptr != NULL, "allocated file image buffer.");
+
+ bytes_read = H5Fget_file_image(file_id, image_ptr, (size_t)image_len);
+ VRFY(bytes_read == image_len, "wrote file into image buffer");
+
+ err = H5Sclose(space_id);
+ VRFY((err >= 0), "closed data space.");
+
+ err = H5Dclose(dset_id);
+ VRFY((err >= 0), "closed data set.");
+
+ err = H5Fclose(file_id);
+ VRFY((err >= 0), "closed core file(1).");
+
+ err = H5Pclose(fapl_id);
+ VRFY((err >= 0), "closed fapl(1).");
+
+
+ /* 4) Send the image to process 1. */
+
+ mpi_result = MPI_Ssend((void *)(&image_len), (int)sizeof(ssize_t),
+ MPI_BYTE, 1, 0, MPI_COMM_WORLD);
+ VRFY((mpi_result == MPI_SUCCESS), "sent image size to process 1");
+
+ mpi_result = MPI_Ssend((void *)image_ptr, (int)image_len,
+ MPI_BYTE, 1, 0, MPI_COMM_WORLD);
+ VRFY((mpi_result == MPI_SUCCESS), "sent image to process 1");
+
+ HDfree(image_ptr);
+ image_ptr = NULL;
+ image_len = 0;
+
+
+ /* 5) Await receipt on a file image from process n-1. */
+
+ mpi_result = MPI_Recv((void *)(&image_len), (int)sizeof(ssize_t),
+ MPI_BYTE, mpi_size - 1, 0, MPI_COMM_WORLD,
+ &rcvstat);
+ VRFY((mpi_result == MPI_SUCCESS), "received image len from process n-1");
+
+ image_ptr = (void *)HDmalloc((size_t)image_len);
+ VRFY(image_ptr != NULL, "allocated file image receive buffer.");
+
+ mpi_result = MPI_Recv((void *)image_ptr, (int)image_len,
+ MPI_BYTE, mpi_size - 1, 0, MPI_COMM_WORLD,
+ &rcvstat);
+ VRFY((mpi_result == MPI_SUCCESS), \
+ "received file image from process n-1");
+
+ /* 6) open the image received from process n-1, verify that
+ * it contains a vector of length equal to mpi_size, and
+ * that the vector contains (0, 1, 2, ... n-1).
+ */
+ fapl_id = H5Pcreate(H5P_FILE_ACCESS);
+ VRFY((fapl_id >= 0), "creating fapl");
+
+ err = H5Pset_fapl_core(fapl_id, (size_t)(64 *1024), FALSE);
+ VRFY((err >= 0), "setting core file driver in fapl.");
+
+ err = H5Pset_file_image(fapl_id, image_ptr, (size_t)image_len);
+ VRFY((err >= 0), "set file image in fapl.");
+
+ file_id = H5Fopen(file_name, H5F_ACC_RDWR, fapl_id);
+ VRFY((file_id >= 0), "opened received file image file");
+
+ dset_id = H5Dopen1(file_id, "v");
+ VRFY((dset_id >= 0), "opened data set");
+
+ dset_type_id = H5Dget_type(dset_id);
+ VRFY((dset_type_id >= 0), "obtained data set type");
+
+ tri_result = H5Tequal(dset_type_id, H5T_NATIVE_INT);
+ VRFY((tri_result == TRUE), "verified data set type");
+
+ space_id = H5Dget_space(dset_id);
+ VRFY((space_id >= 0), "opened data space");
+
+ space_ndims = H5Sget_simple_extent_ndims(space_id);
+ VRFY((space_ndims == 1), "verified data space num dims(1)");
+
+ space_ndims = H5Sget_simple_extent_dims(space_id, dims, NULL);
+ VRFY((space_ndims == 1), "verified data space num dims(2)");
+ VRFY((dims[0] == (hsize_t)mpi_size), "verified data space dims");
+
+ vector_ptr = (int *)HDmalloc((size_t)(mpi_size) * sizeof(int));
+ VRFY((vector_ptr != NULL), "allocated in memory rep of vector");
+
+ err = H5Dread(dset_id, H5T_NATIVE_INT, H5S_ALL, H5S_ALL,
+ H5P_DEFAULT, (void *)vector_ptr);
+ VRFY((err >= 0), "read received vector.");
+
+ vector_ok = TRUE;
+ for(i = 0; i < mpi_size; i++)
+ if(vector_ptr[i] != i)
+ vector_ok = FALSE;
+ VRFY((vector_ok), "verified received vector.");
+
+ /* 7) closes the core file and exit. */
+
+ err = H5Sclose(space_id);
+ VRFY((err >= 0), "closed data space.");
+
+ err = H5Dclose(dset_id);
+ VRFY((err >= 0), "closed data set.");
+
+ err = H5Fclose(file_id);
+ VRFY((err >= 0), "closed core file(1).");
+
+ err = H5Pclose(fapl_id);
+ VRFY((err >= 0), "closed fapl(1).");
+
+ HDfree(image_ptr);
+ image_ptr = NULL;
+ image_len = 0;
+ } else {
+ /* 1) Await receipt of file image from process (i - 1). */
+
+ mpi_result = MPI_Recv((void *)(&image_len), (int)sizeof(ssize_t),
+ MPI_BYTE, mpi_rank - 1, 0, MPI_COMM_WORLD,
+ &rcvstat);
+ VRFY((mpi_result == MPI_SUCCESS), \
+ "received image size from process mpi_rank-1");
+
+ image_ptr = (void *)HDmalloc((size_t)image_len);
+ VRFY(image_ptr != NULL, "allocated file image receive buffer.");
+
+ mpi_result = MPI_Recv((void *)image_ptr, (int)image_len,
+ MPI_BYTE, mpi_rank - 1, 0, MPI_COMM_WORLD,
+ &rcvstat);
+ VRFY((mpi_result == MPI_SUCCESS), \
+ "received file image from process mpi_rank-1");
+
+ /* 2) Open the image with the core file driver, verify that it
+ * contains a vector v of length, and that v[j] = j for
+ * 0 <= j < i, and that v[j] == -1 for i <= j < n
+ */
+ fapl_id = H5Pcreate(H5P_FILE_ACCESS);
+ VRFY((fapl_id >= 0), "creating fapl");
+
+ err = H5Pset_fapl_core(fapl_id, (size_t)(64 * 1024), FALSE);
+ VRFY((err >= 0), "setting core file driver in fapl.");
+
+ err = H5Pset_file_image(fapl_id, image_ptr, (size_t)image_len);
+ VRFY((err >= 0), "set file image in fapl.");
+
+ file_id = H5Fopen(file_name, H5F_ACC_RDWR, fapl_id);
+ H5Eprint1(stderr);
+ VRFY((file_id >= 0), "opened received file image file");
+
+ dset_id = H5Dopen1(file_id, "v");
+ VRFY((dset_id >= 0), "opened data set");
+
+ dset_type_id = H5Dget_type(dset_id);
+ VRFY((dset_type_id >= 0), "obtained data set type");
+
+ tri_result = H5Tequal(dset_type_id, H5T_NATIVE_INT);
+ VRFY((tri_result == TRUE), "verified data set type");
+
+ space_id = H5Dget_space(dset_id);
+ VRFY((space_id >= 0), "opened data space");
+
+ space_ndims = H5Sget_simple_extent_ndims(space_id);
+ VRFY((space_ndims == 1), "verified data space num dims(1)");
+
+ space_ndims = H5Sget_simple_extent_dims(space_id, dims, NULL);
+ VRFY((space_ndims == 1), "verified data space num dims(2)");
+ VRFY((dims[0] == (hsize_t)mpi_size), "verified data space dims");
+
+ vector_ptr = (int *)HDmalloc((size_t)(mpi_size) * sizeof(int));
+ VRFY((vector_ptr != NULL), "allocated in memory rep of vector");
+
+ err = H5Dread(dset_id, H5T_NATIVE_INT, H5S_ALL, H5S_ALL,
+ H5P_DEFAULT, (void *)vector_ptr);
+ VRFY((err >= 0), "read received vector.");
+
+ vector_ok = TRUE;
+ for(i = 0; i < mpi_size; i++){
+ if(i < mpi_rank) {
+ if(vector_ptr[i] != i)
+ vector_ok = FALSE;
+ } else {
+ if(vector_ptr[i] != -1)
+ vector_ok = FALSE;
+ }
+ }
+ VRFY((vector_ok), "verified received vector.");
+
+
+ /* 3) Set v[i] = i in the core file. */
+
+ vector_ptr[mpi_rank] = mpi_rank;
+
+ err = H5Dwrite(dset_id, H5T_NATIVE_INT, H5S_ALL, H5S_ALL,
+ H5P_DEFAULT, (void *)vector_ptr);
+ VRFY((err >= 0), "wrote modified data to vector.");
+
+ HDfree(vector_ptr);
+ vector_ptr = NULL;
+
+
+ /* 4) Flush the core file and send it to process (mpi_rank + 1) % n. */
+
+ err = H5Fflush(file_id, H5F_SCOPE_GLOBAL);
+ VRFY((err >= 0), "flushed core file.");
+
+ image_len = H5Fget_file_image(file_id, NULL, (size_t)0);
+ VRFY((image_len > 0), "got (possibly modified) image file len");
+
+ image_ptr = (void *)HDrealloc((void *)image_ptr, (size_t)image_len);
+ VRFY(image_ptr != NULL, "re-allocated file image buffer.");
+
+ bytes_read = H5Fget_file_image(file_id, image_ptr, (size_t)image_len);
+ VRFY(bytes_read == image_len, "wrote file into image buffer");
+
+ mpi_result = MPI_Ssend((void *)(&image_len), (int)sizeof(ssize_t),
+ MPI_BYTE, (mpi_rank + 1) % mpi_size, 0,
+ MPI_COMM_WORLD);
+ VRFY((mpi_result == MPI_SUCCESS), \
+ "sent image size to process (mpi_rank + 1) % mpi_size");
+
+ mpi_result = MPI_Ssend((void *)image_ptr, (int)image_len,
+ MPI_BYTE, (mpi_rank + 1) % mpi_size, 0,
+ MPI_COMM_WORLD);
+ VRFY((mpi_result == MPI_SUCCESS), \
+ "sent image to process (mpi_rank + 1) % mpi_size");
+
+ HDfree(image_ptr);
+ image_ptr = NULL;
+ image_len = 0;
+
+ /* 5) close the core file and exit. */
+
+ err = H5Sclose(space_id);
+ VRFY((err >= 0), "closed data space.");
+
+ err = H5Dclose(dset_id);
+ VRFY((err >= 0), "closed data set.");
+
+ err = H5Fclose(file_id);
+ VRFY((err >= 0), "closed core file(1).");
+
+ err = H5Pclose(fapl_id);
+ VRFY((err >= 0), "closed fapl(1).");
+ }
+
+ return;
+
+} /* file_image_daisy_chain_test() */
+
diff --git a/testpar/testphdf5.c b/testpar/testphdf5.c
index 4ec05ca..3a86642 100644
--- a/testpar/testphdf5.c
+++ b/testpar/testphdf5.c
@@ -502,6 +502,13 @@ int main(int argc, char **argv)
"test actual io mode proprerty",
PARATESTFILE);
+ if((mpi_size < 2) && MAINPROCESS) {
+ printf("File Image Ops daisy chain test needs at least 2 processes.\n");
+ printf("File Image Ops daisy chain test will be skipped \n");
+ }
+ AddTest((mpi_size < 2)? "-fiodc" : "fiodc", file_image_daisy_chain_test, NULL,
+ "file image ops daisy chain", NULL);
+
/* Display testing information */
TestInfo(argv[0]);
diff --git a/testpar/testphdf5.h b/testpar/testphdf5.h
index 15ef75f..da11c62 100644
--- a/testpar/testphdf5.h
+++ b/testpar/testphdf5.h
@@ -269,6 +269,7 @@ void lower_dim_size_comp_test(void);
void link_chunk_collective_io_test(void);
void contig_hyperslab_dr_pio_test(ShapeSameTestMethods sstest_type);
void checker_board_hyperslab_dr_pio_test(ShapeSameTestMethods sstest_type);
+void file_image_daisy_chain_test(void);
#ifdef H5_HAVE_FILTER_DEFLATE
void compress_readAll(void);
#endif /* H5_HAVE_FILTER_DEFLATE */