summaryrefslogtreecommitdiffstats
path: root/hl
diff options
context:
space:
mode:
authorQuincey Koziol <koziol@hdfgroup.org>2012-03-31 08:49:35 (GMT)
committerQuincey Koziol <koziol@hdfgroup.org>2012-03-31 08:49:35 (GMT)
commitc2a9dcb8977f81ff8e66bfd41c72f106993d3086 (patch)
treea73dacf5ae2aa108fce2d14dc731f9558baddfc8 /hl
parentb51ffb25fe610675a7470cf50efed5bcdf2bf79f (diff)
downloadhdf5-c2a9dcb8977f81ff8e66bfd41c72f106993d3086.zip
hdf5-c2a9dcb8977f81ff8e66bfd41c72f106993d3086.tar.gz
hdf5-c2a9dcb8977f81ff8e66bfd41c72f106993d3086.tar.bz2
[svn-r22219] Description:
Merge "file image" changes from feature branch back to trunk. Tested on: Mac OSX/64 10.7.3 (amazon) w/debug (h5committest upcoming)
Diffstat (limited to 'hl')
-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
6 files changed, 1129 insertions, 15 deletions
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;
+}
+