hdf5/test/objcopy_ref.c
2020-09-30 09:27:10 -05:00

2001 lines
68 KiB
C

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* 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 COPYING file, which can be found at the root of the source code *
* distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
* If you do not have access to either file, you may request a copy from *
* help@hdfgroup.org. *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/*
* Programmer: Peter X. Cao
* May 01, 2005
*
* Purpose: Test H5Ocopy() for references.
*/
#include "testhdf5.h"
#define H5F_FRIEND /*suppress error about including H5Fpkg */
#define H5F_TESTING
#include "H5Fpkg.h" /* File access */
const char *FILENAME[] = {"objcopy_ref_src",
"objcopy_ref_dst",
"objcopy_ref_ext",
"objcopy_ref_src2",
"verbound_ref_src",
"verbound_ref_dst",
NULL};
/* Configuration, really a series of bit flags. Maximum value is all three
* bit flags enabled.
*/
#define CONFIG_SHARE_SRC 1
#define CONFIG_SHARE_DST 2
#define CONFIG_SRC_NEW_FORMAT 4
#define CONFIG_DST_NEW_FORMAT 8
#define CONFIG_DENSE 16
#define MAX_CONFIGURATION 31
#define NAME_DATASET_SIMPLE "dataset_simple"
#define NAME_DATASET_SUB_SUB "/g0/g00/g000/dataset_simple"
#define NAME_GROUP_UNCOPIED "/uncopied"
#define NAME_GROUP_TOP "/g0"
#define NAME_GROUP_SUB "/g0/g00"
#define NAME_GROUP_SUB_SUB2 "g000"
#define NAME_GROUP_LINK "/g_links"
#define NAME_GROUP_LINK2 "/g_links2"
#define NAME_GROUP_REF "ref_grp"
#define NAME_LINK_SOFT "/g_links/soft_link_to_dataset_simple"
#define NAME_LINK_SOFT2 "/g_links2/soft_link_to_dataset_simple"
#define NAME_LINK_EXTERN "/g_links/external_link_to_dataset_simple"
#define NAME_LINK_EXTERN2 "/g_links2/external_link_to_dataset_simple"
#define NAME_LINK_SOFT_DANGLE "/g_links/soft_link_to_nowhere"
#define NAME_LINK_SOFT_DANGLE2 "/g_links2/soft_link_to_nowhere"
#define NAME_LINK_EXTERN_DANGLE "/g_links/external_link_to_nowhere"
#define NAME_LINK_EXTERN_DANGLE2 "/g_links2/external_link_to_nowhere"
#define NAME_BUF_SIZE 1024
#define ATTR_NAME_LEN 80
#define DIM_SIZE_1 12
#define DIM_SIZE_2 6
unsigned num_attributes_g; /* Number of attributes created */
/* Table containing object id and object name */
/* (Used for detecting duplicate objects when comparing groups */
static struct {
size_t nalloc; /* number of slots allocated */
size_t nobjs; /* number of objects */
H5O_token_t *obj; /* tokens for objects seen */
} idtab_g;
/* Local function prototypes */
static int compare_data(hid_t parent1, hid_t parent2, hid_t pid, hid_t tid, size_t nelmts, const void *buf1,
const void *buf2, hid_t obj_owner);
static int compare_datasets(hid_t did, hid_t did2, hid_t pid, const void *wbuf);
static int compare_groups(hid_t gid, hid_t gid2, hid_t pid, int depth, unsigned copy_flags);
/*-------------------------------------------------------------------------
* Function: token_insert
*
* Purpose: Add a token to the table.
*
* Return: void
*
* Programmer: Quincey Koziol
* Saturday, November 5, 2005
*
*-------------------------------------------------------------------------
*/
static void
token_insert(H5O_info2_t *oinfo)
{
size_t n;
/* Don't add it if the link count is 1 because such an object can only
* be encountered once. */
if (oinfo->rc < 2)
return;
/* Extend the table */
if (idtab_g.nobjs >= idtab_g.nalloc) {
idtab_g.nalloc = MAX(256, 2 * idtab_g.nalloc);
idtab_g.obj = (H5O_token_t *)HDrealloc(idtab_g.obj, idtab_g.nalloc * sizeof(idtab_g.obj[0]));
}
/* Insert the entry */
n = idtab_g.nobjs++;
idtab_g.obj[n] = oinfo->token;
} /* end token_insert() */
/*-------------------------------------------------------------------------
* Function: token_lookup
*
* Purpose: Check if a token has already been encountered
*
* Return: Success: TRUE/FALSE
* Failure: (can't fail)
*
* Programmer: Quincey Koziol
* Saturday, November 5, 2005
*
*-------------------------------------------------------------------------
*/
static H5_ATTR_PURE hbool_t
token_lookup(hid_t loc_id, H5O_info2_t *oinfo)
{
size_t n;
int token_cmp;
if (oinfo->rc < 2)
return FALSE; /*only one link possible*/
for (n = 0; n < idtab_g.nobjs; n++) {
if (H5Otoken_cmp(loc_id, &(idtab_g.obj[n]), &oinfo->token, &token_cmp) < 0)
return FALSE;
if (0 == token_cmp)
return TRUE;
}
return FALSE;
} /* end token_lookup() */
/*-------------------------------------------------------------------------
* Function: token_reset
*
* Purpose: Reset the token tracking data structures
*
* Return: void
*
* Programmer: Quincey Koziol
* Saturday, November 5, 2005
*
*-------------------------------------------------------------------------
*/
static void
token_reset(void)
{
if (idtab_g.obj)
HDfree(idtab_g.obj);
idtab_g.obj = NULL;
idtab_g.nalloc = idtab_g.nobjs = 0;
} /* end token_reset() */
/*-------------------------------------------------------------------------
* Function: attach_ref_attr
*
* Purpose: Create an attribute with object references
*
* Return: Non-negative on success/Negative on failure
*
*-------------------------------------------------------------------------
*/
static herr_t
attach_ref_attr(hid_t file_id, hid_t loc_id)
{
char dsetname1[] = "dataset1_pointed_by_ref_attr";
char dsetname2[] = "dataset2_pointed_by_ref_attr";
hid_t did1 = (-1), did2 = (-1), aid = (-1), sid = (-1), sid_ref = (-1);
hsize_t dims[2] = {2, 9};
hsize_t dims_ref[1] = {2};
H5R_ref_t ref[2];
int data1[2][9] = {{1, 1, 1, 1, 1, 1, 1, 1, 1}, {1, 1, 1, 1, 1, 1, 1, 1, 18}};
int data2[2][9] = {{2, 2, 2, 2, 2, 2, 2, 2, 2}, {2, 2, 2, 2, 2, 2, 2, 2, 18}};
/* creates two simple datasets */
if ((sid = H5Screate_simple(2, dims, NULL)) < 0)
TEST_ERROR
if ((sid_ref = H5Screate_simple(1, dims_ref, NULL)) < 0)
TEST_ERROR
if ((did1 = H5Dcreate2(file_id, dsetname1, H5T_NATIVE_INT, sid, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) <
0)
TEST_ERROR
if (H5Dwrite(did1, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, data1) < 0)
TEST_ERROR
if ((did2 = H5Dcreate2(file_id, dsetname2, H5T_NATIVE_INT, sid, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) <
0)
TEST_ERROR
if (H5Dwrite(did2, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, data2) < 0)
TEST_ERROR
/* create an attribute with two object references */
if (H5Rcreate_object(file_id, dsetname1, H5P_DEFAULT, &ref[0]) < 0)
TEST_ERROR
if (H5Rcreate_object(file_id, dsetname2, H5P_DEFAULT, &ref[1]) < 0)
TEST_ERROR
if ((aid = H5Acreate2(loc_id, "obj_ref_attr", H5T_STD_REF, sid_ref, H5P_DEFAULT, H5P_DEFAULT)) < 0)
TEST_ERROR
if (H5Awrite(aid, H5T_STD_REF, ref) < 0)
TEST_ERROR
if (H5Sclose(sid) < 0)
TEST_ERROR
if (H5Sclose(sid_ref) < 0)
TEST_ERROR
if (H5Dclose(did1) < 0)
TEST_ERROR
if (H5Dclose(did2) < 0)
TEST_ERROR
if (H5Aclose(aid) < 0)
TEST_ERROR
if (H5Rdestroy(&ref[0]) < 0)
TEST_ERROR
if (H5Rdestroy(&ref[1]) < 0)
TEST_ERROR
return 0;
error:
H5E_BEGIN_TRY
{
H5Sclose(sid);
H5Sclose(sid_ref);
H5Dclose(did1);
H5Dclose(did2);
H5Aclose(aid);
H5Rdestroy(&ref[0]);
H5Rdestroy(&ref[1]);
}
H5E_END_TRY;
return (-1);
}
/*-------------------------------------------------------------------------
* Function: attach_reg_ref_attr
*
* Purpose: Create an attribute with object references
*
* Return: Non-negative on success/Negative on failure
*
* Programmer: Peter Cao
* Monday, March 5, 2006
*
*-------------------------------------------------------------------------
*/
static herr_t
attach_reg_ref_attr(hid_t file_id, hid_t loc_id)
{
const char dsetnamev[] = "dataset_pointed_by_reg_ref_attr";
hid_t aid = (-1);
hid_t space_id = (-1); /* dataspace identifiers */
hid_t spacer_id = (-1); /* dataspace identifiers */
hid_t dsetv_id = (-1); /*dataset identifiers*/
hsize_t dims[2] = {2, 9};
hsize_t dimsr[1] = {2};
int rank = 2;
int rankr = 1;
H5R_ref_t ref[2];
int data[2][9] = {{1, 1, 2, 3, 3, 4, 5, 5, 999}, {1, 2, 2, 3, 4, 4, 5, 6, 999}};
hsize_t start[2] = {0, 3};
hsize_t count[2] = {2, 3};
hsize_t coord[3][2] = {{0, 0}, {1, 6}, {0, 8}};
size_t num_points = 3;
/* create a 2D dataset */
if ((space_id = H5Screate_simple(rank, dims, NULL)) < 0)
TEST_ERROR
if ((spacer_id = H5Screate_simple(rankr, dimsr, NULL)) < 0)
TEST_ERROR
if ((dsetv_id = H5Dcreate2(file_id, dsetnamev, H5T_NATIVE_INT, space_id, H5P_DEFAULT, H5P_DEFAULT,
H5P_DEFAULT)) < 0)
TEST_ERROR
if (H5Dwrite(dsetv_id, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, data) < 0)
TEST_ERROR
/* create reg_ref of block selection */
if (H5Sselect_hyperslab(space_id, H5S_SELECT_SET, start, NULL, count, NULL) < 0)
TEST_ERROR
if (H5Rcreate_region(file_id, dsetnamev, space_id, H5P_DEFAULT, &ref[0]) < 0)
TEST_ERROR
/* create reg_ref of point selection */
if (H5Sselect_none(space_id) < 0)
TEST_ERROR
if (H5Sselect_elements(space_id, H5S_SELECT_SET, num_points, (const hsize_t *)coord) < 0)
TEST_ERROR
if (H5Rcreate_region(file_id, dsetnamev, space_id, H5P_DEFAULT, &ref[1]) < 0)
TEST_ERROR
/* create reg_ref attribute */
if ((aid = H5Acreate2(loc_id, "reg_ref_attr", H5T_STD_REF, spacer_id, H5P_DEFAULT, H5P_DEFAULT)) < 0)
TEST_ERROR
if (H5Awrite(aid, H5T_STD_REF, ref) < 0)
TEST_ERROR
/* attach the reg_ref attribute to the dataset itself */
if (H5Aclose(aid) < 0)
TEST_ERROR
if ((aid = H5Acreate2(dsetv_id, "reg_ref_attr", H5T_STD_REF, spacer_id, H5P_DEFAULT, H5P_DEFAULT)) < 0)
TEST_ERROR
if (H5Awrite(aid, H5T_STD_REF, ref) < 0)
TEST_ERROR
if (H5Sclose(spacer_id) < 0)
TEST_ERROR
if (H5Sclose(space_id) < 0)
TEST_ERROR
if (H5Dclose(dsetv_id) < 0)
TEST_ERROR
if (H5Aclose(aid) < 0)
TEST_ERROR
if (H5Rdestroy(&ref[0]) < 0)
TEST_ERROR
if (H5Rdestroy(&ref[1]) < 0)
TEST_ERROR
return 0;
error:
H5E_BEGIN_TRY
{
H5Sclose(spacer_id);
H5Sclose(space_id);
H5Dclose(dsetv_id);
H5Aclose(aid);
H5Rdestroy(&ref[0]);
H5Rdestroy(&ref[1]);
}
H5E_END_TRY;
return (-1);
}
/*-------------------------------------------------------------------------
* Function: create_reg_ref_dataset
*
* Purpose: Create a dataset with region references
*
* Return: Non-negative on success/Negative on failure
*
* Programmer: Peter Cao
* Friday, August 4, 2006
*
*-------------------------------------------------------------------------
*/
static herr_t
create_reg_ref_dataset(hid_t file_id, hid_t loc_id)
{
const char dsetnamev[] = "dataset_pointed_by_ref_dset";
const char dsetnamer[] = "dataset_with_reg_ref";
const char dsetnamer1[] = "compact_dataset_with_reg_ref";
const char dsetnamer2[] = "compressed_dataset_with_reg_ref";
hid_t space_id = (-1); /* dataspace identifiers */
hid_t spacer_id = (-1);
hid_t dsetv_id = (-1); /*dataset identifiers*/
hid_t dsetr_id = (-1);
hsize_t dims[2] = {2, 9};
hsize_t dimsr[1] = {2};
int rank = 2;
int rankr = 1;
hsize_t chunk_size = 1;
H5R_ref_t ref[2];
int data[2][9] = {{1, 1, 2, 3, 3, 4, 5, 5, 6}, {1, 2, 2, 3, 4, 4, 5, 6, 6}};
hsize_t start[2];
hsize_t count[2];
hsize_t coord[3][2] = {{0, 0}, {1, 6}, {0, 8}};
size_t num_points = 3;
hid_t pid = (-1);
if ((space_id = H5Screate_simple(rank, dims, NULL)) < 0)
TEST_ERROR
if ((spacer_id = H5Screate_simple(rankr, dimsr, NULL)) < 0)
TEST_ERROR
if ((dsetv_id = H5Dcreate2(file_id, dsetnamev, H5T_NATIVE_INT, space_id, H5P_DEFAULT, H5P_DEFAULT,
H5P_DEFAULT)) < 0)
TEST_ERROR
if (H5Dwrite(dsetv_id, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, data) < 0)
TEST_ERROR
if ((dsetr_id = H5Dcreate2(loc_id, dsetnamer, H5T_STD_REF, spacer_id, H5P_DEFAULT, H5P_DEFAULT,
H5P_DEFAULT)) < 0)
TEST_ERROR
start[0] = 0;
start[1] = 3;
count[0] = 2;
count[1] = 3;
if (H5Sselect_hyperslab(space_id, H5S_SELECT_SET, start, NULL, count, NULL) < 0)
TEST_ERROR
if (H5Rcreate_region(file_id, dsetnamev, space_id, H5P_DEFAULT, &ref[0]) < 0)
TEST_ERROR
if (H5Sselect_none(space_id) < 0)
TEST_ERROR
if (H5Sselect_elements(space_id, H5S_SELECT_SET, num_points, (const hsize_t *)coord) < 0)
TEST_ERROR
if (H5Rcreate_region(file_id, dsetnamev, space_id, H5P_DEFAULT, &ref[1]) < 0)
TEST_ERROR
if (H5Dwrite(dsetr_id, H5T_STD_REF, H5S_ALL, H5S_ALL, H5P_DEFAULT, ref) < 0)
TEST_ERROR
if (H5Dclose(dsetr_id) < 0)
TEST_ERROR
/* create and set compact plist */
if ((pid = H5Pcreate(H5P_DATASET_CREATE)) < 0)
TEST_ERROR
if (H5Pset_layout(pid, H5D_COMPACT) < 0)
TEST_ERROR
if ((dsetr_id = H5Dcreate2(loc_id, dsetnamer1, H5T_STD_REF, spacer_id, H5P_DEFAULT, pid, H5P_DEFAULT)) <
0)
TEST_ERROR
if (H5Pclose(pid) < 0)
TEST_ERROR
if (H5Dwrite(dsetr_id, H5T_STD_REF, H5S_ALL, H5S_ALL, H5P_DEFAULT, ref) < 0)
TEST_ERROR
if (H5Dclose(dsetr_id) < 0)
TEST_ERROR
/* create and set comp & chunk plist */
if ((pid = H5Pcreate(H5P_DATASET_CREATE)) < 0)
TEST_ERROR
if (H5Pset_chunk(pid, 1, &chunk_size) < 0)
TEST_ERROR
if (H5Pset_deflate(pid, 9) < 0)
TEST_ERROR
if ((dsetr_id = H5Dcreate2(loc_id, dsetnamer2, H5T_STD_REF, spacer_id, H5P_DEFAULT, pid, H5P_DEFAULT)) <
0)
TEST_ERROR
if (H5Pclose(pid) < 0)
TEST_ERROR
if (H5Dwrite(dsetr_id, H5T_STD_REF, H5S_ALL, H5S_ALL, H5P_DEFAULT, ref) < 0)
TEST_ERROR
if (H5Dclose(dsetr_id) < 0)
TEST_ERROR
if (H5Sclose(space_id) < 0)
TEST_ERROR
if (H5Sclose(spacer_id) < 0)
TEST_ERROR
if (H5Dclose(dsetv_id) < 0)
TEST_ERROR
if (H5Rdestroy(&ref[0]) < 0)
TEST_ERROR
if (H5Rdestroy(&ref[1]) < 0)
TEST_ERROR
return 0;
error:
H5E_BEGIN_TRY
{
H5Sclose(space_id);
H5Sclose(spacer_id);
H5Dclose(dsetr_id);
H5Dclose(dsetv_id);
H5Pclose(pid);
H5Rdestroy(&ref[0]);
H5Rdestroy(&ref[1]);
}
H5E_END_TRY;
return (-1);
}
/*-------------------------------------------------------------------------
* Function: test_copy_attach_attributes
*
* Purpose: Attach NUM_ATTRIBUTES attributes to the object to be copied
*
* Return: Non-negative on success/Negative on failure
*
* Programmer: Peter Cao
* Friday, September 30, 2005
*
*-------------------------------------------------------------------------
*/
static int
test_copy_attach_attributes(hid_t loc_id, hid_t type_id)
{
hid_t aid = -1, sid = -1;
char attr_name[ATTR_NAME_LEN];
int attr_data[2];
hsize_t dim1 = 2;
hid_t acpl = -1;
unsigned u;
int ret_value = -1;
if ((sid = H5Screate_simple(1, &dim1, NULL)) < 0)
goto done;
/* Create attribute creation plist */
if ((acpl = H5Pcreate(H5P_ATTRIBUTE_CREATE)) < 0)
goto done;
for (u = 0; u < num_attributes_g; u++) {
HDsprintf(attr_name, "%u attr", u);
/* Set attribute data */
attr_data[0] = (int)(100 * u);
attr_data[1] = (int)(200 * u);
/* Set attribute character set (alternate) */
if (u % 2) {
if (H5Pset_char_encoding(acpl, H5T_CSET_ASCII) < 0)
goto done;
} /* end if */
else if (H5Pset_char_encoding(acpl, H5T_CSET_UTF8) < 0)
goto done;
if ((aid = H5Acreate2(loc_id, attr_name, type_id, sid, acpl, H5P_DEFAULT)) < 0)
goto done;
if (H5Awrite(aid, H5T_NATIVE_INT, attr_data) < 0)
goto done;
if (aid > 0)
H5Aclose(aid);
aid = -1;
}
ret_value = 0;
done:
if (sid > 0)
H5Sclose(sid);
if (aid > 0)
H5Aclose(aid);
if (acpl > 0)
H5Pclose(acpl);
return ret_value;
}
/*-------------------------------------------------------------------------
* Function: compare_attribute
*
* Purpose: Compare two attributes to check that they are equal
*
* Return: TRUE if attributes are equal/FALSE if they are different
*
* Programmer: Peter Cao
* Saturday, December 17, 2005
*
*-------------------------------------------------------------------------
*/
static int
compare_attribute(hid_t aid, hid_t aid2, hid_t pid, const void *wbuf, hid_t obj_owner)
{
hid_t sid = -1, sid2 = -1; /* Dataspace IDs */
hid_t tid = -1, tid2 = -1; /* Datatype IDs */
size_t elmt_size; /* Size of datatype */
htri_t is_committed; /* If the datatype is committed */
htri_t is_committed2; /* If the datatype is committed */
H5A_info_t ainfo; /* Attribute info */
H5A_info_t ainfo2; /* Attribute info */
hssize_t nelmts; /* # of elements in dataspace */
void * rbuf = NULL; /* Buffer for reading raw data */
void * rbuf2 = NULL; /* Buffer for reading raw data */
/* Check the character sets are equal */
if (H5Aget_info(aid, &ainfo) < 0)
TEST_ERROR
if (H5Aget_info(aid2, &ainfo2) < 0)
TEST_ERROR
if (ainfo.cset != ainfo2.cset)
TEST_ERROR
/* Check the creation orders are equal (if appropriate) */
if (ainfo.corder_valid != ainfo2.corder_valid)
TEST_ERROR
if (ainfo.corder_valid)
if (ainfo.corder != ainfo2.corder)
TEST_ERROR
/* Check the datatypes are equal */
/* Open the datatype for the source attribute */
if ((tid = H5Aget_type(aid)) < 0)
TEST_ERROR
/* Open the datatype for the destination attribute */
if ((tid2 = H5Aget_type(aid2)) < 0)
TEST_ERROR
/* Check that both datatypes are committed/not committed */
if ((is_committed = H5Tcommitted(tid)) < 0)
TEST_ERROR
if ((is_committed2 = H5Tcommitted(tid2)) < 0)
TEST_ERROR
if (is_committed != is_committed2)
TEST_ERROR
/* Compare the datatypes */
if (H5Tequal(tid, tid2) != TRUE)
TEST_ERROR
/* Determine the size of datatype (for later) */
if ((elmt_size = H5Tget_size(tid)) == 0)
TEST_ERROR
/* Check the dataspaces are equal */
/* Open the dataspace for the source attribute */
if ((sid = H5Aget_space(aid)) < 0)
TEST_ERROR
/* Open the dataspace for the destination attribute */
if ((sid2 = H5Aget_space(aid2)) < 0)
TEST_ERROR
/* Compare the dataspaces */
if (H5Sextent_equal(sid, sid2) != TRUE)
TEST_ERROR
/* Determine the number of elements in dataspace (for later) */
if ((nelmts = H5Sget_simple_extent_npoints(sid2)) < 0)
TEST_ERROR
/* Check the raw data is equal */
/* Allocate & initialize space for the raw data buffers */
if ((rbuf = HDcalloc(elmt_size, (size_t)nelmts)) == NULL)
TEST_ERROR
if ((rbuf2 = HDcalloc(elmt_size, (size_t)nelmts)) == NULL)
TEST_ERROR
/* Read data from the source attribute */
if (H5Aread(aid, tid, rbuf) < 0)
TEST_ERROR
/* Read data from the destination attribute */
if (H5Aread(aid2, tid2, rbuf2) < 0)
TEST_ERROR
/* Check raw data read in against data written out */
if (wbuf) {
if (!compare_data(aid, (hid_t)0, pid, tid, (size_t)nelmts, wbuf, rbuf, obj_owner))
TEST_ERROR
if (!compare_data(aid2, (hid_t)0, pid, tid2, (size_t)nelmts, wbuf, rbuf2, obj_owner))
TEST_ERROR
} /* end if */
/* Don't have written data, just compare data between the two attributes */
else if (!compare_data(aid, aid2, pid, tid, (size_t)nelmts, rbuf, rbuf2, obj_owner))
TEST_ERROR
/* Reclaim vlen data, if necessary */
if (H5Tdetect_class(tid, H5T_VLEN) == TRUE || H5Tdetect_class(tid, H5T_REFERENCE) == TRUE)
if (H5Treclaim(tid, sid, H5P_DEFAULT, rbuf) < 0)
TEST_ERROR
if (H5Tdetect_class(tid2, H5T_VLEN) == TRUE || H5Tdetect_class(tid2, H5T_REFERENCE) == TRUE)
if (H5Treclaim(tid2, sid2, H5P_DEFAULT, rbuf2) < 0)
TEST_ERROR
/* Release raw data buffers */
HDfree(rbuf);
rbuf = NULL;
HDfree(rbuf2);
rbuf2 = NULL;
/* close the source dataspace */
if (H5Sclose(sid) < 0)
TEST_ERROR
/* close the destination dataspace */
if (H5Sclose(sid2) < 0)
TEST_ERROR
/* close the source datatype */
if (H5Tclose(tid) < 0)
TEST_ERROR
/* close the destination datatype */
if (H5Tclose(tid2) < 0)
TEST_ERROR
return TRUE;
error:
if (rbuf)
HDfree(rbuf);
if (rbuf2)
HDfree(rbuf2);
H5E_BEGIN_TRY
{
H5Sclose(sid2);
H5Sclose(sid);
H5Tclose(tid2);
H5Tclose(tid);
}
H5E_END_TRY;
return FALSE;
} /* end compare_attribute() */
/*-------------------------------------------------------------------------
* Function: compare_std_attributes
*
* Purpose: Compare "standard" attributes on two objects to check that they are equal
*
* Return: TRUE if objects have same attributes/FALSE if they are different
*
* Programmer: Quincey Koziol
* Monday, October 31, 2005
*
* Note: This isn't very general, the attributes are assumed to be
* those written in test_copy_attach_attributes().
*
*-------------------------------------------------------------------------
*/
static int
compare_std_attributes(hid_t oid, hid_t oid2, hid_t pid)
{
hid_t aid = -1, aid2 = -1; /* Attribute IDs */
H5O_info2_t oinfo1, oinfo2; /* Object info */
unsigned cpy_flags; /* Object copy flags */
/* Retrieve the object copy flags from the property list, if it's non-DEFAULT */
if (pid != H5P_DEFAULT) {
if (H5Pget_copy_object(pid, &cpy_flags) < 0)
TEST_ERROR
} /* end if */
else
cpy_flags = 0;
/* Check the number of attributes on source dataset */
if (H5Oget_info3(oid, &oinfo1, H5O_INFO_NUM_ATTRS) < 0)
TEST_ERROR
/* Check the number of attributes on destination dataset */
if (H5Oget_info3(oid2, &oinfo2, H5O_INFO_NUM_ATTRS) < 0)
TEST_ERROR
if (cpy_flags & H5O_COPY_WITHOUT_ATTR_FLAG) {
/* Check that the destination has no attributes */
if (oinfo2.num_attrs != 0)
TEST_ERROR
} /* end if */
else {
char attr_name[ATTR_NAME_LEN]; /* Attribute name */
unsigned i; /* Local index variable */
/* Compare the number of attributes */
if (oinfo1.num_attrs != oinfo2.num_attrs)
TEST_ERROR
/* Check the attributes are equal */
for (i = 0; i < (unsigned)oinfo1.num_attrs; i++) {
if ((aid = H5Aopen_by_idx(oid, ".", H5_INDEX_CRT_ORDER, H5_ITER_INC, (hsize_t)i, H5P_DEFAULT,
H5P_DEFAULT)) < 0)
TEST_ERROR
if (H5Aget_name(aid, (size_t)ATTR_NAME_LEN, attr_name) < 0)
TEST_ERROR
if ((aid2 = H5Aopen(oid2, attr_name, H5P_DEFAULT)) < 0)
TEST_ERROR
/* Check the attributes are equal */
if (!compare_attribute(aid, aid2, pid, NULL, oid))
TEST_ERROR
/* Close the attributes */
if (H5Aclose(aid) < 0)
TEST_ERROR
if (H5Aclose(aid2) < 0)
TEST_ERROR
} /* end for */
} /* end if */
/* Objects should be the same. :-) */
return TRUE;
error:
H5E_BEGIN_TRY
{
H5Aclose(aid2);
H5Aclose(aid);
}
H5E_END_TRY;
return FALSE;
} /* end compare_std_attributes() */
/*-------------------------------------------------------------------------
* Function: compare_data
*
* Purpose: Compare two buffers of data to check that they are equal
*
* Return: TRUE if buffer are equal/FALSE if they are different
*
* Programmer: Quincey Koziol
* Monday, November 21, 2005
*
*-------------------------------------------------------------------------
*/
static int
compare_data(hid_t parent1, hid_t parent2, hid_t pid, hid_t tid, size_t nelmts, const void *buf1,
const void *buf2, hid_t obj_owner)
{
size_t elmt_size; /* Size of an element */
/* Check size of each element */
if ((elmt_size = H5Tget_size(tid)) == 0)
TEST_ERROR
/* If the type is a compound containing a vlen, loop over all elements for
* each compound member. Compounds containing reference are not supported
* yet. */
if ((H5Tget_class(tid) == H5T_COMPOUND) && (H5Tdetect_class(tid, H5T_VLEN) == TRUE)) {
hid_t memb_id; /* Member id */
const uint8_t *memb1; /* Pointer to current member */
const uint8_t *memb2; /* Pointer to current member */
int nmembs; /* Number of members */
size_t memb_off; /* Member offset */
size_t memb_size; /* Member size */
unsigned memb_idx; /* Member index */
size_t elmt; /* Current element */
/* Get number of members in compound */
if ((nmembs = H5Tget_nmembers(tid)) < 0)
TEST_ERROR
/* Loop over members */
for (memb_idx = 0; memb_idx < (unsigned)nmembs; memb_idx++) {
/* Get member offset. Note that we cannot check for an error here.
*/
memb_off = H5Tget_member_offset(tid, memb_idx);
/* Get member id */
if ((memb_id = H5Tget_member_type(tid, memb_idx)) < 0)
TEST_ERROR
/* Get member size */
if ((memb_size = H5Tget_size(memb_id)) == 0)
TEST_ERROR
/* Set up pointers to member in the first element */
memb1 = (const uint8_t *)buf1 + memb_off;
memb2 = (const uint8_t *)buf2 + memb_off;
/* Check if this member contains (or is) a vlen */
if (H5Tget_class(memb_id) == H5T_VLEN) {
hid_t base_id; /* vlen base type id */
/* Get base type of vlen datatype */
if ((base_id = H5Tget_super(memb_id)) < 0)
TEST_ERROR
/* Iterate over all elements, recursively calling this function
* for each */
for (elmt = 0; elmt < nelmts; elmt++) {
/* Check vlen lengths */
if (((const hvl_t *)((const void *)memb1))->len !=
((const hvl_t *)((const void *)memb2))->len)
TEST_ERROR
/* Check vlen data */
if (!compare_data(parent1, parent2, pid, base_id,
((const hvl_t *)((const void *)memb1))->len,
((const hvl_t *)((const void *)memb1))->p,
((const hvl_t *)((const void *)memb2))->p, obj_owner))
TEST_ERROR
/* Update member pointers */
memb1 += elmt_size;
memb2 += elmt_size;
} /* end for */
}
else {
/* vlens cannot currently be nested below the top layer of a
* compound */
HDassert(H5Tdetect_class(memb_id, H5T_VLEN) == FALSE);
/* Iterate over all elements, calling memcmp() for each */
for (elmt = 0; elmt < nelmts; elmt++) {
if (HDmemcmp(memb1, memb2, memb_size))
TEST_ERROR
/* Update member pointers */
memb1 += elmt_size;
memb2 += elmt_size;
} /* end for */
} /* end else */
} /* end for */
}
else if (H5Tdetect_class(tid, H5T_VLEN) == TRUE) {
const hvl_t *vl_buf1, *vl_buf2; /* Aliases for buffers to compare */
hid_t base_tid; /* Base type of vlen datatype */
size_t u; /* Local index variable */
/* Check for "simple" vlen datatype */
if (H5Tget_class(tid) != H5T_VLEN)
TEST_ERROR
/* Get base type of vlen datatype */
if ((base_tid = H5Tget_super(tid)) < 0)
TEST_ERROR
/* Loop over elements in buffers */
vl_buf1 = (const hvl_t *)buf1;
vl_buf2 = (const hvl_t *)buf2;
for (u = 0; u < nelmts; u++, vl_buf1++, vl_buf2++) {
/* Check vlen lengths */
if (vl_buf1->len != vl_buf2->len)
TEST_ERROR
/* Check vlen data */
if (!compare_data(parent1, parent2, pid, base_tid, vl_buf1->len, vl_buf1->p, vl_buf2->p,
obj_owner))
TEST_ERROR
} /* end for */
if (H5Tclose(base_tid) < 0)
TEST_ERROR
} /* end if */
else if (H5Tdetect_class(tid, H5T_REFERENCE) == TRUE) {
size_t u; /* Local index variable */
/* Check for "simple" reference datatype */
if (H5Tget_class(tid) != H5T_REFERENCE)
TEST_ERROR
/* Check for object or region reference */
if (H5Tequal(tid, H5T_STD_REF) > 0) {
H5R_ref_t *ref_buf1, *ref_buf2; /* Aliases for buffers to compare */
/* Loop over elements in buffers */
ref_buf1 = (H5R_ref_t *)buf1;
ref_buf2 = (H5R_ref_t *)buf2;
for (u = 0; u < nelmts; u++, ref_buf1++, ref_buf2++) {
hid_t obj1_id, obj2_id; /* IDs for objects referenced */
H5O_type_t obj1_type, obj2_type; /* Types of objects referenced */
/* Check for types of objects handled */
if (H5Rget_obj_type3(ref_buf1, H5P_DEFAULT, &obj1_type) < 0)
TEST_ERROR
if (H5Rget_obj_type3(ref_buf2, H5P_DEFAULT, &obj2_type) < 0)
TEST_ERROR
if (obj1_type != obj2_type)
TEST_ERROR
/* Open referenced objects */
if ((obj1_id = H5Ropen_object(ref_buf1, H5P_DEFAULT, H5P_DEFAULT)) < 0)
TEST_ERROR
if ((obj2_id = H5Ropen_object(ref_buf2, H5P_DEFAULT, H5P_DEFAULT)) < 0)
TEST_ERROR
/* break the infinite loop when the ref_object points to itself */
if (obj_owner > 0) {
H5O_info2_t oinfo1, oinfo2;
int token_cmp;
if (H5Oget_info3(obj_owner, &oinfo1, H5O_INFO_BASIC) < 0)
TEST_ERROR
if (H5Oget_info3(obj1_id, &oinfo2, H5O_INFO_BASIC) < 0)
TEST_ERROR
if (H5Otoken_cmp(obj1_id, &oinfo1.token, &oinfo2.token, &token_cmp) < 0)
TEST_ERROR
if (0 == token_cmp) {
if (H5Oclose(obj1_id) < 0)
TEST_ERROR
if (H5Oclose(obj2_id) < 0)
TEST_ERROR
return TRUE;
}
}
/* Check for types of objects handled */
switch (obj1_type) {
case H5O_TYPE_DATASET:
if (compare_datasets(obj1_id, obj2_id, pid, NULL) != TRUE)
TEST_ERROR
break;
case H5O_TYPE_GROUP:
if (compare_groups(obj1_id, obj2_id, pid, -1, 0) != TRUE)
TEST_ERROR
break;
case H5O_TYPE_NAMED_DATATYPE:
if (H5Tequal(obj1_id, obj2_id) != TRUE)
TEST_ERROR
break;
case H5O_TYPE_MAP:
/* Maps not supported in native VOL connector */
case H5O_TYPE_UNKNOWN:
case H5O_TYPE_NTYPES:
default:
TEST_ERROR
} /* end switch */
/* Close objects */
if (H5Oclose(obj1_id) < 0)
TEST_ERROR
if (H5Oclose(obj2_id) < 0)
TEST_ERROR
if (H5Rget_type(ref_buf1) == H5R_DATASET_REGION2) {
hid_t obj1_sid, obj2_sid; /* Dataspace IDs for objects referenced */
/* Get regions for referenced datasets */
if ((obj1_sid = H5Ropen_region(ref_buf1, H5P_DEFAULT, H5P_DEFAULT)) < 0)
TEST_ERROR
if ((obj2_sid = H5Ropen_region(ref_buf2, H5P_DEFAULT, H5P_DEFAULT)) < 0)
TEST_ERROR
/* Check if dataspaces are the same shape */
if (H5Sselect_shape_same(obj1_sid, obj2_sid) < 0)
TEST_ERROR
/* Close dataspaces */
if (H5Sclose(obj1_sid) < 0)
TEST_ERROR
if (H5Sclose(obj2_sid) < 0)
TEST_ERROR
} /* end if */
} /* end for */
} /* end if */
else
TEST_ERROR
} /* end else */
else if (HDmemcmp(buf1, buf2, (elmt_size * nelmts)))
TEST_ERROR
/* Data should be the same. :-) */
return TRUE;
error:
return FALSE;
} /* end compare_data() */
/*-------------------------------------------------------------------------
* Function: compare_datasets
*
* Purpose: Compare two datasets to check that they are equal
*
* Return: TRUE if datasets are equal/FALSE if they are different
*
* Programmer: Quincey Koziol
* Tuesday, October 25, 2005
*
*-------------------------------------------------------------------------
*/
static int
compare_datasets(hid_t did, hid_t did2, hid_t pid, const void *wbuf)
{
hid_t sid = -1, sid2 = -1; /* Dataspace IDs */
hid_t tid = -1, tid2 = -1; /* Datatype IDs */
hid_t dcpl = -1, dcpl2 = -1; /* Dataset creation property list IDs */
size_t elmt_size; /* Size of datatype */
htri_t is_committed; /* If the datatype is committed */
htri_t is_committed2; /* If the datatype is committed */
int nfilters; /* Number of filters applied to dataset */
hssize_t nelmts; /* # of elements in dataspace */
void * rbuf = NULL; /* Buffer for reading raw data */
void * rbuf2 = NULL; /* Buffer for reading raw data */
H5D_space_status_t space_status; /* Dataset's raw dataspace status */
H5D_space_status_t space_status2; /* Dataset's raw dataspace status */
/* Check the datatypes are equal */
/* Open the datatype for the source dataset */
if ((tid = H5Dget_type(did)) < 0)
TEST_ERROR
/* Open the datatype for the destination dataset */
if ((tid2 = H5Dget_type(did2)) < 0)
TEST_ERROR
/* Check that both datatypes are committed/not committed */
if ((is_committed = H5Tcommitted(tid)) < 0)
TEST_ERROR
if ((is_committed2 = H5Tcommitted(tid2)) < 0)
TEST_ERROR
if (is_committed != is_committed2)
TEST_ERROR
/* Compare the datatypes */
if (H5Tequal(tid, tid2) != TRUE)
TEST_ERROR
/* Determine the size of datatype (for later) */
if ((elmt_size = H5Tget_size(tid)) == 0)
TEST_ERROR
/* Check the dataspaces are equal */
/* Open the dataspace for the source dataset */
if ((sid = H5Dget_space(did)) < 0)
TEST_ERROR
/* Open the dataspace for the destination dataset */
if ((sid2 = H5Dget_space(did2)) < 0)
TEST_ERROR
/* Compare the dataspaces */
if (H5Sextent_equal(sid, sid2) != TRUE)
TEST_ERROR
/* Determine the number of elements in dataspace (for later) */
if ((nelmts = H5Sget_simple_extent_npoints(sid)) < 0)
TEST_ERROR
/* Check the dataset creation property lists are equal */
/* Open the dataset creation property list for the source dataset */
if ((dcpl = H5Dget_create_plist(did)) < 0)
TEST_ERROR
/* Open the dataset creation property list for the destination dataset */
if ((dcpl2 = H5Dget_create_plist(did2)) < 0)
TEST_ERROR
/* Compare the rest of the dataset creation property lists */
if (H5Pequal(dcpl, dcpl2) != TRUE)
TEST_ERROR
/* Get the number of filters on dataset (for later) */
if ((nfilters = H5Pget_nfilters(dcpl)) < 0)
TEST_ERROR
/* close the source dataset creation property list */
if (H5Pclose(dcpl) < 0)
TEST_ERROR
/* close the destination dataset creation property list */
if (H5Pclose(dcpl2) < 0)
TEST_ERROR
/* Check the allocated storage is the same */
/* Check that the space allocation status is the same */
if (H5Dget_space_status(did, &space_status) < 0)
TEST_ERROR
if (H5Dget_space_status(did2, &space_status2) < 0)
TEST_ERROR
if (space_status != space_status2)
TEST_ERROR
/* Check that the space used is the same */
/* (Don't check if the dataset is filtered (i.e. compressed, etc.) and
* the datatype is VLEN, since the addresses for the vlen
* data in each dataset will (probably) be different and the storage
* size will thus vary)
*/
if (!(nfilters > 0 && (H5Tdetect_class(tid, H5T_VLEN) ||
(H5Tdetect_class(tid, H5T_REFERENCE) && H5Tequal(tid, H5T_STD_REF))))) {
hsize_t storage_size = H5Dget_storage_size(did); /* Dataset's raw data storage size */
hsize_t storage_size2 = H5Dget_storage_size(did2); /* 2nd Dataset's raw data storage size */
if (storage_size != storage_size2)
TEST_ERROR
} /* end if */
/* Check the raw data is equal */
/* Allocate & initialize space for the raw data buffers */
if ((rbuf = HDcalloc(elmt_size, (size_t)nelmts)) == NULL)
TEST_ERROR
if ((rbuf2 = HDcalloc(elmt_size, (size_t)nelmts)) == NULL)
TEST_ERROR
/* Read data from datasets */
if (H5Dread(did, tid, H5S_ALL, H5S_ALL, H5P_DEFAULT, rbuf) < 0)
TEST_ERROR
if (H5Dread(did2, tid2, H5S_ALL, H5S_ALL, H5P_DEFAULT, rbuf2) < 0)
TEST_ERROR
/* Check raw data read in against data written out */
if (wbuf) {
if (!compare_data(did, (hid_t)0, pid, tid, (size_t)nelmts, wbuf, rbuf, did))
TEST_ERROR
if (!compare_data(did2, (hid_t)0, pid, tid2, (size_t)nelmts, wbuf, rbuf2, did2))
TEST_ERROR
} /* end if */
/* Don't have written data, just compare data between the two datasets */
else if (!compare_data(did, did2, pid, tid, (size_t)nelmts, rbuf, rbuf2, did))
TEST_ERROR
/* Reclaim vlen data, if necessary */
if (H5Tdetect_class(tid, H5T_VLEN) == TRUE || H5Tdetect_class(tid, H5T_REFERENCE) == TRUE)
if (H5Treclaim(tid, sid, H5P_DEFAULT, rbuf) < 0)
TEST_ERROR
if (H5Tdetect_class(tid2, H5T_VLEN) == TRUE || H5Tdetect_class(tid2, H5T_REFERENCE) == TRUE)
if (H5Treclaim(tid2, sid2, H5P_DEFAULT, rbuf2) < 0)
TEST_ERROR
/* Release raw data buffers */
HDfree(rbuf);
rbuf = NULL;
HDfree(rbuf2);
rbuf2 = NULL;
/* close the source dataspace */
if (H5Sclose(sid) < 0)
TEST_ERROR
/* close the destination dataspace */
if (H5Sclose(sid2) < 0)
TEST_ERROR
/* close the source datatype */
if (H5Tclose(tid) < 0)
TEST_ERROR
/* close the destination datatype */
if (H5Tclose(tid2) < 0)
TEST_ERROR
/* Check if the attributes are equal */
if (compare_std_attributes(did, did2, pid) != TRUE)
TEST_ERROR
/* Datasets should be the same. :-) */
return TRUE;
error:
H5E_BEGIN_TRY
{
if (rbuf)
HDfree(rbuf);
if (rbuf2)
HDfree(rbuf2);
H5Pclose(dcpl2);
H5Pclose(dcpl);
H5Sclose(sid2);
H5Sclose(sid);
H5Tclose(tid2);
H5Tclose(tid);
}
H5E_END_TRY;
return FALSE;
} /* end compare_datasets() */
/*-------------------------------------------------------------------------
* Function: compare_groups
*
* Purpose: Compare two groups to check that they are "equal"
*
* Return: TRUE if group are equal/FALSE if they are different
*
* Programmer: Quincey Koziol
* Monday, October 31, 2005
*
*-------------------------------------------------------------------------
*/
static int
compare_groups(hid_t gid, hid_t gid2, hid_t pid, int depth, unsigned copy_flags)
{
H5G_info_t ginfo; /* Group info struct */
H5G_info_t ginfo2; /* Group info struct */
hsize_t idx; /* Index over the objects in group */
unsigned cpy_flags; /* Object copy flags */
/* Retrieve the object copy flags from the property list, if it's non-DEFAULT */
if (pid != H5P_DEFAULT) {
if (H5Pget_copy_object(pid, &cpy_flags) < 0)
TEST_ERROR
} /* end if */
else
cpy_flags = 0;
/* Check if both groups have the same # of objects */
if (H5Gget_info(gid, &ginfo) < 0)
TEST_ERROR
if (H5Gget_info(gid2, &ginfo2) < 0)
TEST_ERROR
if ((cpy_flags & H5O_COPY_SHALLOW_HIERARCHY_FLAG) && depth == 0) {
if (ginfo2.nlinks != 0)
TEST_ERROR
} /* end if */
else {
if (ginfo.nlinks != ginfo2.nlinks)
TEST_ERROR
} /* end if */
/* Check contents of groups */
if (ginfo2.nlinks > 0) {
char objname[NAME_BUF_SIZE]; /* Name of object in group */
char objname2[NAME_BUF_SIZE]; /* Name of object in group */
H5L_info2_t linfo; /* Link information */
H5L_info2_t linfo2; /* Link information */
/* Loop over contents of groups */
for (idx = 0; idx < ginfo.nlinks; idx++) {
/* Check name of objects */
if (H5Lget_name_by_idx(gid, ".", H5_INDEX_NAME, H5_ITER_INC, idx, objname, (size_t)NAME_BUF_SIZE,
H5P_DEFAULT) < 0)
TEST_ERROR
if (H5Lget_name_by_idx(gid2, ".", H5_INDEX_NAME, H5_ITER_INC, idx, objname2,
(size_t)NAME_BUF_SIZE, H5P_DEFAULT) < 0)
TEST_ERROR
if (HDstrcmp(objname, objname2))
TEST_ERROR
/* Get link info */
if (H5Lget_info2(gid, objname, &linfo, H5P_DEFAULT) < 0)
TEST_ERROR
if (H5Lget_info2(gid2, objname2, &linfo2, H5P_DEFAULT) < 0)
TEST_ERROR
if (linfo.type != linfo2.type)
TEST_ERROR
/* Extra checks for "real" objects */
if (linfo.type == H5L_TYPE_HARD) {
hid_t oid, oid2; /* IDs of objects within group */
H5O_info2_t oinfo, oinfo2; /* Data model object info */
H5O_native_info_t ninfo, ninfo2; /* Native file format object info */
/* Compare some pieces of the object info */
/* Get data model object info */
if (H5Oget_info_by_name3(gid, objname, &oinfo, H5O_INFO_BASIC, H5P_DEFAULT) < 0)
TEST_ERROR
if (H5Oget_info_by_name3(gid2, objname2, &oinfo2, H5O_INFO_BASIC, H5P_DEFAULT) < 0)
TEST_ERROR
/* Get native object info */
if (H5Oget_native_info_by_name(gid, objname, &ninfo, H5O_NATIVE_INFO_HDR, H5P_DEFAULT) < 0)
TEST_ERROR
if (H5Oget_native_info_by_name(gid2, objname2, &ninfo2, H5O_NATIVE_INFO_HDR, H5P_DEFAULT) < 0)
TEST_ERROR
if (oinfo.type != oinfo2.type)
TEST_ERROR
if (oinfo.rc != oinfo2.rc)
TEST_ERROR
/* If NULL messages are preserved, the number of messages
* should be the same in the destination.
* Otherwise, it should simply be true that the number
* of messages hasn't increased.
*/
if (H5O_COPY_PRESERVE_NULL_FLAG & copy_flags) {
if (ninfo.hdr.nmesgs != ninfo2.hdr.nmesgs)
;
else if (ninfo.hdr.nmesgs < ninfo2.hdr.nmesgs)
TEST_ERROR
}
/* Check for object already having been compared */
if (token_lookup(gid, &oinfo))
continue;
else
token_insert(&oinfo);
/* Open objects */
if ((oid = H5Oopen(gid, objname, H5P_DEFAULT)) < 0)
FAIL_STACK_ERROR
if ((oid2 = H5Oopen(gid2, objname2, H5P_DEFAULT)) < 0)
FAIL_STACK_ERROR
/* Compare objects within group */
switch (oinfo.type) {
case H5O_TYPE_GROUP:
/* Compare groups */
if (compare_groups(oid, oid2, pid, depth - 1, copy_flags) != TRUE)
TEST_ERROR
break;
case H5O_TYPE_DATASET:
/* Compare datasets */
if (compare_datasets(oid, oid2, pid, NULL) != TRUE)
TEST_ERROR
break;
case H5O_TYPE_NAMED_DATATYPE:
/* Compare datatypes */
if (H5Tequal(oid, oid2) != TRUE)
TEST_ERROR
break;
case H5O_TYPE_MAP:
HDassert(0 && "maps not supported in native VOL connector");
case H5O_TYPE_UNKNOWN:
case H5O_TYPE_NTYPES:
default:
HDassert(0 && "Unknown type of object");
break;
} /* end switch */
/* Close objects */
if (H5Oclose(oid) < 0)
TEST_ERROR
if (H5Oclose(oid2) < 0)
TEST_ERROR
} /* end if */
else {
/* Check that both links are the same size */
if (linfo.u.val_size != linfo2.u.val_size)
TEST_ERROR
/* Compare link values */
if (linfo.type == H5L_TYPE_SOFT ||
(linfo.type >= H5L_TYPE_UD_MIN && linfo.type <= H5L_TYPE_MAX)) {
char linkval[NAME_BUF_SIZE]; /* Link value */
char linkval2[NAME_BUF_SIZE]; /* Link value */
/* Get link values */
HDassert(linfo.u.val_size <= NAME_BUF_SIZE);
if (H5Lget_val(gid, objname, linkval, (size_t)NAME_BUF_SIZE, H5P_DEFAULT) < 0)
TEST_ERROR
if (H5Lget_val(gid2, objname2, linkval2, (size_t)NAME_BUF_SIZE, H5P_DEFAULT) < 0)
TEST_ERROR
/* Compare link data */
if (HDmemcmp(linkval, linkval2, linfo.u.val_size))
TEST_ERROR
} /* end else-if */
else {
HDassert(0 && "Unknown type of link");
} /* end else */
} /* end else */
} /* end for */
} /* end if */
/* Check if the attributes are equal */
if (compare_std_attributes(gid, gid2, pid) != TRUE)
TEST_ERROR
/* Groups should be the same. :-) */
return TRUE;
error:
H5E_BEGIN_TRY {}
H5E_END_TRY;
return FALSE;
} /* end compare_groups() */
/*-------------------------------------------------------------------------
* Function: test_copy_option
*
* Purpose: Create a group in SRC file and copy it to DST file
*
* Return: Success: 0
* Failure: number of errors
*
* Programmer: Peter Cao
* March 11, 2006
*
*-------------------------------------------------------------------------
*/
static int
test_copy_option(hid_t fcpl_src, hid_t fcpl_dst, hid_t src_fapl, hid_t dst_fapl, unsigned flag,
hbool_t crt_intermediate_grp, const char *test_desciption)
{
hid_t fid_src = -1, fid_dst = -1, fid_ext = -1; /* File IDs */
hid_t sid = -1; /* Dataspace ID */
hid_t did = -1; /* Dataset ID */
hid_t gid = -1, gid2 = -1, gid_ref = -1; /* Group IDs */
hid_t gid_sub = -1, gid_sub_sub = -1; /* Sub-group ID */
hid_t pid = -1, lcpl_id = -1; /* Property IDs */
unsigned cpy_flags; /* Object copy flags */
int depth = -1; /* Copy depth */
hsize_t dim2d[2];
int buf[DIM_SIZE_1][DIM_SIZE_2];
int i, j;
char src_filename[NAME_BUF_SIZE];
char dst_filename[NAME_BUF_SIZE];
TESTING(test_desciption);
/* set initial data values */
for (i = 0; i < DIM_SIZE_1; i++)
for (j = 0; j < DIM_SIZE_2; j++)
buf[i][j] = 10000 + 100 * i + j;
/* Initialize the filenames */
h5_fixname(FILENAME[0], src_fapl, src_filename, sizeof src_filename);
h5_fixname(FILENAME[1], dst_fapl, dst_filename, sizeof dst_filename);
/* Reset file token checking info */
token_reset();
/* create source file */
if ((fid_src = H5Fcreate(src_filename, H5F_ACC_TRUNC, fcpl_src, src_fapl)) < 0)
TEST_ERROR
/* create group at the SRC file */
if ((gid = H5Gcreate2(fid_src, NAME_GROUP_TOP, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0)
TEST_ERROR
/* attach attributes to the group */
if (test_copy_attach_attributes(gid, H5T_NATIVE_INT) < 0)
TEST_ERROR
/* Set dataspace dimensions */
dim2d[0] = DIM_SIZE_1;
dim2d[1] = DIM_SIZE_2;
/* create dataspace */
if ((sid = H5Screate_simple(2, dim2d, NULL)) < 0)
TEST_ERROR
/* add a dataset to the top group */
if ((did = H5Dcreate2(gid, NAME_DATASET_SIMPLE, H5T_NATIVE_INT, sid, H5P_DEFAULT, H5P_DEFAULT,
H5P_DEFAULT)) < 0)
TEST_ERROR
if (H5Dwrite(did, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, buf) < 0)
TEST_ERROR
if (H5Dclose(did) < 0)
TEST_ERROR
/* create a sub-group */
if ((gid_sub = H5Gcreate2(fid_src, NAME_GROUP_SUB, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0)
TEST_ERROR
/* add a dataset to the sub group */
if ((did = H5Dcreate2(gid_sub, NAME_DATASET_SIMPLE, H5T_NATIVE_INT, sid, H5P_DEFAULT, H5P_DEFAULT,
H5P_DEFAULT)) < 0)
TEST_ERROR
if (H5Dwrite(did, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, buf) < 0)
TEST_ERROR
if (H5Dclose(did) < 0)
TEST_ERROR
/* create sub-sub-group */
if ((gid_sub_sub = H5Gcreate2(gid_sub, NAME_GROUP_SUB_SUB2, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0)
TEST_ERROR
/* add a dataset to the sub sub group */
if ((did = H5Dcreate2(gid_sub_sub, NAME_DATASET_SIMPLE, H5T_NATIVE_INT, sid, H5P_DEFAULT, H5P_DEFAULT,
H5P_DEFAULT)) < 0)
TEST_ERROR
if (H5Dwrite(did, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, buf) < 0)
TEST_ERROR
/* close dataset */
if (H5Dclose(did) < 0)
TEST_ERROR
/* close dataspace */
if (H5Sclose(sid) < 0)
TEST_ERROR
if (H5Gclose(gid_sub_sub) < 0)
TEST_ERROR
if (H5Gclose(gid_sub) < 0)
TEST_ERROR
/* close the group */
if (H5Gclose(gid) < 0)
FAIL_STACK_ERROR
if ((flag & H5O_COPY_EXPAND_SOFT_LINK_FLAG) > 0) {
/* Create group to copy */
if ((gid = H5Gcreate2(fid_src, NAME_GROUP_LINK, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0)
FAIL_STACK_ERROR
if (H5Lcreate_soft(NAME_DATASET_SUB_SUB, fid_src, NAME_LINK_SOFT, H5P_DEFAULT, H5P_DEFAULT) < 0)
FAIL_STACK_ERROR
if (H5Lcreate_soft("nowhere", fid_src, NAME_LINK_SOFT_DANGLE, H5P_DEFAULT, H5P_DEFAULT) < 0)
FAIL_STACK_ERROR
if (H5Gclose(gid) < 0)
FAIL_STACK_ERROR
/* Create group to compare with */
if ((gid = H5Gcreate2(fid_src, NAME_GROUP_LINK2, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0)
FAIL_STACK_ERROR
if (H5Lcreate_hard(fid_src, NAME_DATASET_SUB_SUB, H5L_SAME_LOC, NAME_LINK_SOFT2, H5P_DEFAULT,
H5P_DEFAULT) < 0)
FAIL_STACK_ERROR
if (H5Lcreate_soft("nowhere", fid_src, NAME_LINK_SOFT_DANGLE2, H5P_DEFAULT, H5P_DEFAULT) < 0)
FAIL_STACK_ERROR
if (H5Gclose(gid) < 0)
FAIL_STACK_ERROR
} /* end if */
if ((flag & H5O_COPY_EXPAND_EXT_LINK_FLAG) > 0) {
char ext_filename[NAME_BUF_SIZE];
h5_fixname(FILENAME[2], src_fapl, ext_filename, sizeof ext_filename);
/* Create the external file and dataset */
if ((fid_ext = H5Fcreate(ext_filename, H5F_ACC_TRUNC, fcpl_src, src_fapl)) < 0)
TEST_ERROR
if ((sid = H5Screate_simple(2, dim2d, NULL)) < 0)
TEST_ERROR
if ((did = H5Dcreate2(fid_ext, NAME_DATASET_SIMPLE, H5T_NATIVE_INT, sid, H5P_DEFAULT, H5P_DEFAULT,
H5P_DEFAULT)) < 0)
TEST_ERROR
if (H5Dwrite(did, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, buf) < 0)
TEST_ERROR
if (H5Dclose(did) < 0)
TEST_ERROR
if (H5Fclose(fid_ext) < 0)
TEST_ERROR
/* Create group to copy */
if (!(flag & H5O_COPY_EXPAND_SOFT_LINK_FLAG)) {
if ((gid = H5Gcreate2(fid_src, NAME_GROUP_LINK, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0)
TEST_ERROR
} /* end if */
else if ((gid = H5Gopen2(fid_src, NAME_GROUP_LINK, H5P_DEFAULT)) < 0)
TEST_ERROR
if (H5Lcreate_external(ext_filename, NAME_DATASET_SIMPLE, fid_src, NAME_LINK_EXTERN, H5P_DEFAULT,
H5P_DEFAULT) < 0)
TEST_ERROR
if (H5Lcreate_external("no_file", "no_object", fid_src, NAME_LINK_EXTERN_DANGLE, H5P_DEFAULT,
H5P_DEFAULT) < 0)
TEST_ERROR
if (H5Gclose(gid) < 0)
TEST_ERROR
/* Create group to compare with */
if (!(flag & H5O_COPY_EXPAND_SOFT_LINK_FLAG)) {
if ((gid = H5Gcreate2(fid_src, NAME_GROUP_LINK2, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0)
TEST_ERROR
} /* end if */
else if ((gid = H5Gopen2(fid_src, NAME_GROUP_LINK2, H5P_DEFAULT)) < 0)
TEST_ERROR
if ((did = H5Dcreate2(fid_src, NAME_LINK_EXTERN2, H5T_NATIVE_INT, sid, H5P_DEFAULT, H5P_DEFAULT,
H5P_DEFAULT)) < 0)
TEST_ERROR
if (H5Dwrite(did, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, buf) < 0)
TEST_ERROR
if (H5Lcreate_external("no_file", "no_object", fid_src, NAME_LINK_EXTERN_DANGLE2, H5P_DEFAULT,
H5P_DEFAULT) < 0)
TEST_ERROR
if (H5Dclose(did) < 0)
TEST_ERROR
if (H5Gclose(gid) < 0)
TEST_ERROR
/* Close dataspace */
if (H5Sclose(sid) < 0)
TEST_ERROR
} /* end if */
if ((flag & H5O_COPY_EXPAND_REFERENCE_FLAG) > 0) {
if ((gid_ref = H5Gcreate2(fid_src, NAME_GROUP_REF, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0)
TEST_ERROR
/* create an attribute of new object references */
if (attach_ref_attr(fid_src, gid_ref) < 0)
TEST_ERROR
/* create an attribute of region references */
if (attach_reg_ref_attr(fid_src, gid_ref) < 0)
TEST_ERROR
/* create a dataset of region references */
if (create_reg_ref_dataset(fid_src, gid_ref) < 0)
TEST_ERROR
/* Close group holding reference objects */
if (H5Gclose(gid_ref) < 0)
TEST_ERROR
} /* end if */
/* close the SRC file */
if (H5Fclose(fid_src) < 0)
TEST_ERROR
/* open the source file with read-only */
/* (except when expanding soft links */
if ((flag & H5O_COPY_EXPAND_SOFT_LINK_FLAG) > 0) {
if ((fid_src = H5Fopen(src_filename, H5F_ACC_RDWR, src_fapl)) < 0)
TEST_ERROR
} /* end if */
else if ((fid_src = H5Fopen(src_filename, H5F_ACC_RDONLY, src_fapl)) < 0)
TEST_ERROR
/* create destination file */
if ((fid_dst = H5Fcreate(dst_filename, H5F_ACC_TRUNC, fcpl_dst, dst_fapl)) < 0)
TEST_ERROR
/* Create an uncopied object in destination file so that tokens in source and destination
files aren't the same */
if (H5Gclose(H5Gcreate2(fid_dst, NAME_GROUP_UNCOPIED, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0)
TEST_ERROR
/* create property to pass copy options */
if ((pid = H5Pcreate(H5P_OBJECT_COPY)) < 0)
TEST_ERROR
/* set options for object copy */
if (H5Pset_copy_object(pid, flag) < 0)
TEST_ERROR
/* Verify object copy flags */
if (H5Pget_copy_object(pid, &cpy_flags) < 0)
TEST_ERROR
if (cpy_flags != flag)
TEST_ERROR
/* copy the group from SRC to DST */
if (crt_intermediate_grp) {
/* Create link creation plist to pass in intermediate group creation */
if ((lcpl_id = H5Pcreate(H5P_LINK_CREATE)) < 0)
TEST_ERROR
if (H5Pset_create_intermediate_group(lcpl_id, TRUE) < 0)
TEST_ERROR
if (H5Ocopy(fid_src, NAME_GROUP_TOP, fid_dst, "/new_g0/new_g00", pid, lcpl_id) < 0)
TEST_ERROR
if (H5Pclose(lcpl_id) < 0)
TEST_ERROR
/* open the group for copy */
if ((gid = H5Gopen2(fid_src, NAME_GROUP_TOP, H5P_DEFAULT)) < 0)
FAIL_STACK_ERROR
/* open the destination group */
if ((gid2 = H5Gopen2(fid_dst, "/new_g0/new_g00", H5P_DEFAULT)) < 0)
FAIL_STACK_ERROR
}
else if (((flag & H5O_COPY_EXPAND_SOFT_LINK_FLAG) > 0) || ((flag & H5O_COPY_EXPAND_EXT_LINK_FLAG) > 0)) {
if (H5Ocopy(fid_src, NAME_GROUP_LINK, fid_dst, NAME_GROUP_LINK, pid, H5P_DEFAULT) < 0)
TEST_ERROR
if ((flag & H5O_COPY_EXPAND_SOFT_LINK_FLAG) > 0)
/* Unlink dataset to copy from original location */
/* (So group comparison works properly) */
if (H5Ldelete(fid_src, NAME_DATASET_SUB_SUB, H5P_DEFAULT) < 0)
FAIL_STACK_ERROR
/* open the group for copy */
if ((gid = H5Gopen2(fid_src, NAME_GROUP_LINK2, H5P_DEFAULT)) < 0)
FAIL_STACK_ERROR
/* open the destination group */
if ((gid2 = H5Gopen2(fid_dst, NAME_GROUP_LINK, H5P_DEFAULT)) < 0)
FAIL_STACK_ERROR
}
else if (flag & (H5O_COPY_WITHOUT_ATTR_FLAG | H5O_COPY_PRESERVE_NULL_FLAG)) {
if (H5Ocopy(fid_src, NAME_GROUP_TOP, fid_dst, NAME_GROUP_TOP, pid, H5P_DEFAULT) < 0)
TEST_ERROR
/* open the group for copy */
if ((gid = H5Gopen2(fid_src, NAME_GROUP_TOP, H5P_DEFAULT)) < 0)
FAIL_STACK_ERROR
/* open the destination group */
if ((gid2 = H5Gopen2(fid_dst, NAME_GROUP_TOP, H5P_DEFAULT)) < 0)
FAIL_STACK_ERROR
}
else if (flag & H5O_COPY_SHALLOW_HIERARCHY_FLAG) {
if (H5Ocopy(fid_src, NAME_GROUP_TOP, fid_dst, NAME_GROUP_TOP, pid, H5P_DEFAULT) < 0)
TEST_ERROR
/* open the group for copy */
if ((gid = H5Gopen2(fid_src, NAME_GROUP_TOP, H5P_DEFAULT)) < 0)
FAIL_STACK_ERROR
/* open the destination group */
if ((gid2 = H5Gopen2(fid_dst, NAME_GROUP_TOP, H5P_DEFAULT)) < 0)
FAIL_STACK_ERROR
/* Set the copy depth */
depth = 1;
}
else if ((flag & H5O_COPY_EXPAND_REFERENCE_FLAG) > 0) {
if (H5Ocopy(fid_src, NAME_GROUP_REF, fid_dst, NAME_GROUP_REF, pid, H5P_DEFAULT) < 0)
TEST_ERROR
/* open the group for copy */
if ((gid = H5Gopen2(fid_src, NAME_GROUP_REF, H5P_DEFAULT)) < 0)
FAIL_STACK_ERROR
/* open the destination group */
if ((gid2 = H5Gopen2(fid_dst, NAME_GROUP_REF, H5P_DEFAULT)) < 0)
FAIL_STACK_ERROR
}
else {
/* Unknown flag */
TEST_ERROR
} /* end else */
/* Check if the groups are equal */
if (compare_groups(gid, gid2, pid, depth, flag) != TRUE)
TEST_ERROR
if (H5Gclose(gid2) < 0)
TEST_ERROR
if (H5Gclose(gid) < 0)
TEST_ERROR
/* close the SRC file */
if (H5Fclose(fid_src) < 0)
TEST_ERROR
/* close the DST file */
if (H5Fclose(fid_dst) < 0)
TEST_ERROR
/* close properties */
if (H5Pclose(pid) < 0)
TEST_ERROR
PASSED();
return 0;
error:
H5E_BEGIN_TRY
{
H5Pclose(lcpl_id);
H5Pclose(pid);
H5Sclose(sid);
H5Dclose(did);
H5Gclose(gid_ref);
H5Gclose(gid_sub);
H5Gclose(gid2);
H5Gclose(gid);
H5Fclose(fid_dst);
H5Fclose(fid_src);
H5Fclose(fid_ext);
}
H5E_END_TRY;
return 1;
} /* end test_copy_option */
/*-------------------------------------------------------------------------
* Function: main
*
* Purpose: Test H5Ocopy()
*
* Tests a number of cases: messages can be stored in the
* new or old format, messages can be shared in either,
* both, or neither of the source and destination files.
*
* Return: EXIT_SUCCESS/EXIT_FAILURE
*
* Programmer: Peter Cao
* Friday, September 30, 2005
*
*-------------------------------------------------------------------------
*/
int
main(void)
{
int nerrors = 0;
hid_t fapl, fapl2;
hid_t fcpl_shared, ocpl;
unsigned max_compact, min_dense;
int configuration; /* Configuration of tests. */
int ExpressMode;
/* Setup */
h5_reset();
fapl = h5_fileaccess();
ExpressMode = GetTestExpress();
if (ExpressMode > 1)
HDprintf("***Express test mode on. Some tests may be skipped\n");
/* Copy the file access property list */
if ((fapl2 = H5Pcopy(fapl)) < 0)
TEST_ERROR
/* Set the "use the latest version of the format" bounds for creating objects in the file */
if (H5Pset_libver_bounds(fapl2, H5F_LIBVER_LATEST, H5F_LIBVER_LATEST) < 0)
TEST_ERROR
/* Create an FCPL with sharing enabled */
if ((fcpl_shared = H5Pcreate(H5P_FILE_CREATE)) < 0)
TEST_ERROR
if (H5Pset_shared_mesg_nindexes(fcpl_shared, 1) < 0)
TEST_ERROR
if (H5Pset_shared_mesg_index(fcpl_shared, 0, H5O_SHMESG_ALL_FLAG, 10) < 0)
TEST_ERROR
/* Obtain the default attribute storage phase change values */
if ((ocpl = H5Pcreate(H5P_OBJECT_CREATE)) < 0)
TEST_ERROR
if (H5Pget_attr_phase_change(ocpl, &max_compact, &min_dense) < 0)
TEST_ERROR
if (H5Pclose(ocpl) < 0)
TEST_ERROR
/* Test in all configurations */
for (configuration = 0; configuration <= MAX_CONFIGURATION; configuration++) {
hid_t src_fapl;
hid_t dst_fapl;
hid_t fcpl_src;
hid_t fcpl_dst;
/* No need to test dense attributes with old format */
if (!(configuration & CONFIG_SRC_NEW_FORMAT) && (configuration & CONFIG_DENSE))
continue;
/* TODO Region references currently do not support copy from new format to old format
* (this may be fixed once H5Sencode/decode and H5CXis fixed) */
if ((configuration & CONFIG_SRC_NEW_FORMAT) && !(configuration & CONFIG_DST_NEW_FORMAT))
continue;
/* Test with and without shared messages */
if (configuration & CONFIG_SHARE_SRC) {
HDputs("\nTesting with shared src messages:");
fcpl_src = fcpl_shared;
}
else {
HDputs("\nTesting without shared src messages:");
fcpl_src = H5P_DEFAULT;
}
if (configuration & CONFIG_SHARE_DST) {
HDputs("Testing with shared dst messages:");
fcpl_dst = fcpl_shared;
}
else {
HDputs("Testing without shared dst messages:");
fcpl_dst = H5P_DEFAULT;
}
/* Set the FAPL for the source file's type of format */
if (configuration & CONFIG_SRC_NEW_FORMAT) {
HDputs("Testing with latest format for source file:");
src_fapl = fapl2;
/* Test with and without dense attributes */
if (configuration & CONFIG_DENSE) {
HDputs("Testing with dense attributes:");
num_attributes_g = max_compact + 1;
}
else {
HDputs("Testing without dense attributes:");
num_attributes_g = MAX(min_dense, 2) - 2;
}
} /* end if */
else {
HDputs("Testing with oldest file format for source file:");
src_fapl = fapl;
num_attributes_g = 4;
} /* end else */
/* Set the FAPL for the destination file's type of format */
if (configuration & CONFIG_DST_NEW_FORMAT) {
HDputs("Testing with latest format for destination file:");
dst_fapl = fapl2;
} /* end if */
else {
HDputs("Testing with oldest file format for destination file:");
dst_fapl = fapl;
} /* end else */
/* The tests... */
nerrors += test_copy_option(fcpl_src, fcpl_dst, src_fapl, dst_fapl, H5O_COPY_EXPAND_REFERENCE_FLAG,
FALSE, "H5Ocopy(): expand object reference");
} /* end for */
/* Reset file token checking info */
token_reset();
/* Verify symbol table messages are cached */
nerrors += (h5_verify_cached_stabs(FILENAME, fapl) < 0 ? 1 : 0);
/* Results */
if (nerrors) {
HDprintf("***** %d OBJECT COPY TEST%s FAILED! *****\n", nerrors, (1 == nerrors ? "" : "S"));
HDexit(EXIT_FAILURE);
} /* end if */
HDputs("All object copying tests passed.");
/* close property list.
* NOTE: if this property list is not closed and the test is
* run with the split or multi driver, an interesting
* problem is exposed in the property list shutdown code.
*
* Namely, since the split/multi driver copies property
* lists for internal use, there's a (high) chance that
* leaving the FAPL open and having the library's shutdown
* code close it will cause the underlying property lists
* to be cleaned up first, causing the actual property list
* close operation to fail (since it won't be able to close
* the already closed underlying property list).
*
* The could be addressed by converting the split/multi to
* use non-public API routines, or putting some way into the
* public H5I routines to indicate ordering at shutdown.
*
* For now, we just make certain to close the property list.
* (QAK - 2016/04/06)
*
*/
H5Pclose(fapl2);
h5_cleanup(FILENAME, fapl);
HDexit(EXIT_SUCCESS);
error:
HDexit(EXIT_FAILURE);
} /* main */