/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Copyright by The HDF Group. * * 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://www.hdfgroup.org/licenses. * * If you do not have access to either file, you may request a copy from * * help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #define H5G_FRIEND /*suppress error about including H5Gpkg */ /* Define this macro to indicate that the testing APIs should be available */ #define H5G_TESTING #include "h5test.h" #include "H5Gpkg.h" /* Groups */ static const char *FILENAME[] = {"stab", NULL}; #define NAME_BUF_SIZE 1024 /* Definitions for 'long' test */ #define LONG_NAME_LEN 40960 /* Definitions for 'large' test */ #define LARGE_NOBJS 5000 /* Definitions for 'lifecycle' test */ #define LIFECYCLE_TOP_GROUP "top" #define LIFECYCLE_BOTTOM_GROUP "bottom %u" #define LIFECYCLE_LOCAL_HEAP_SIZE_HINT 256 #define LIFECYCLE_MAX_COMPACT 4 #define LIFECYCLE_MIN_DENSE 3 #define LIFECYCLE_EST_NUM_ENTRIES 4 #define LIFECYCLE_EST_NAME_LEN 8 /* Definitions for 'long_compact' test */ #define LONG_COMPACT_LENGTH ((64 * 1024) + 1024) /* Definitions for 'read_old' test */ #define READ_OLD_NGROUPS 100 /* The group_old.h5 is generated from gen_old_fill.c in HDF5 'test' directory * for version 1.6. To get this data file, simply compile gen_old_group.c with * the HDF5 library in that branch and run it. */ #define FILE_OLD_GROUPS "group_old.h5" #define FILE_OLD_GROUPS_COPY "group_old_copy.h5" /* Definitions for 'no_compact' test */ #define NO_COMPACT_TOP_GROUP "top" #define NO_COMPACT_BOTTOM_GROUP "bottom %u" #define NO_COMPACT_MAX_COMPACT 0 #define NO_COMPACT_MIN_DENSE 0 /* Definitions for 'gcpl_on_root' test */ #define GCPL_ON_ROOT_MIDDLE_GROUP "/middle" #define GCPL_ON_ROOT_BOTTOM_GROUP "/middle/bottom" #define GCPL_ON_ROOT_MAX_COMPACT 4 #define GCPL_ON_ROOT_MIN_DENSE 2 #ifndef H5_NO_DEPRECATED_SYMBOLS /* Definitions for 'old_api' test */ #define OLD_API_GROUP "/old_api" #endif /* H5_NO_DEPRECATED_SYMBOLS */ /* Definitions for 'corrupt_stab_msg' test */ #define CORRUPT_STAB_FILE "corrupt_stab_msg.h5" #define CORRUPT_STAB_TMP_FILE "corrupt_stab_msg_tmp.h5" #define CORRUPT_STAB_DSET "DS1" /*------------------------------------------------------------------------- * Function: test_misc * * Purpose: Test miscellaneous group stuff. * * Return: Success: 0 * * Failure: number of errors * *------------------------------------------------------------------------- */ static int test_misc(hid_t fcpl, hid_t fapl, bool new_format) { hid_t fid = (H5I_INVALID_HID); /* File ID */ hid_t g1 = (H5I_INVALID_HID), g2 = (H5I_INVALID_HID), g3 = (H5I_INVALID_HID); char filename[NAME_BUF_SIZE]; char comment[64]; if (new_format) TESTING("miscellaneous group tests (w/new group format)"); else TESTING("miscellaneous group tests"); /* Create file */ h5_fixname(FILENAME[0], fapl, filename, sizeof(filename)); if ((fid = H5Fcreate(filename, H5F_ACC_TRUNC, fcpl, fapl)) < 0) TEST_ERROR; /* Create initial groups for testing, then close */ if ((g1 = H5Gcreate2(fid, "test_1a", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) TEST_ERROR; if ((g2 = H5Gcreate2(g1, "sub_1", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) TEST_ERROR; if ((g3 = H5Gcreate2(fid, "test_1b", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) TEST_ERROR; if (H5Oset_comment(g3, "hello world") < 0) TEST_ERROR; if (H5Gclose(g1) < 0) TEST_ERROR; if (H5Gclose(g2) < 0) TEST_ERROR; if (H5Gclose(g3) < 0) TEST_ERROR; /* Open all groups with absolute names to check for existence */ if ((g1 = H5Gopen2(fid, "/test_1a", H5P_DEFAULT)) < 0) TEST_ERROR; if ((g2 = H5Gopen2(fid, "/test_1a/sub_1", H5P_DEFAULT)) < 0) TEST_ERROR; if ((g3 = H5Gopen2(fid, "/test_1b", H5P_DEFAULT)) < 0) TEST_ERROR; if (H5Oget_comment_by_name(g3, "././.", comment, sizeof comment, H5P_DEFAULT) < 0) TEST_ERROR; if (strcmp(comment, "hello world") != 0) { H5_FAILED(); puts(" Read the wrong comment string from the group."); printf(" got: \"%s\"\n ans: \"hello world\"\n", comment); TEST_ERROR; } if (H5Gclose(g1) < 0) TEST_ERROR; if (H5Gclose(g2) < 0) TEST_ERROR; if (H5Gclose(g3) < 0) TEST_ERROR; /* Check that creating groups with no-op names isn't allowed */ H5E_BEGIN_TRY { g1 = H5Gcreate2(fid, "/", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); } H5E_END_TRY if (g1 >= 0) TEST_ERROR; H5E_BEGIN_TRY { g1 = H5Gcreate2(fid, "./././", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); } H5E_END_TRY if (g1 >= 0) TEST_ERROR; /* Close file */ if (H5Fclose(fid) < 0) TEST_ERROR; PASSED(); return 0; error: H5E_BEGIN_TRY { H5Gclose(g1); H5Gclose(g2); H5Gclose(g3); H5Fclose(fid); } H5E_END_TRY return 1; } /*------------------------------------------------------------------------- * Purpose: Creates a group with a very long name * * Return: Success: 0 * * Failure: number of errors * *------------------------------------------------------------------------- */ static int test_long(hid_t fcpl, hid_t fapl, bool new_format) { hid_t fid = (H5I_INVALID_HID); /* File ID */ hid_t g1 = (H5I_INVALID_HID), g2 = (H5I_INVALID_HID); size_t name2Len; char *name1 = NULL, *name2 = NULL; char filename[NAME_BUF_SIZE]; size_t i; if (new_format) TESTING("long names (w/new group format)"); else TESTING("long names"); /* Create file */ h5_fixname(FILENAME[0], fapl, filename, sizeof(filename)); if ((fid = H5Fcreate(filename, H5F_ACC_TRUNC, fcpl, fapl)) < 0) TEST_ERROR; /* Group names */ name1 = (char *)malloc((size_t)LONG_NAME_LEN); for (i = 0; i < LONG_NAME_LEN; i++) name1[i] = (char)('A' + i % 26); name1[LONG_NAME_LEN - 1] = '\0'; name2Len = (2 * LONG_NAME_LEN) + 2; name2 = (char *)malloc(name2Len); snprintf(name2, name2Len, "%s/%s", name1, name1); /* Create groups */ if ((g1 = H5Gcreate2(fid, name1, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) TEST_ERROR; if ((g2 = H5Gcreate2(g1, name1, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) TEST_ERROR; if (H5Gclose(g1) < 0) TEST_ERROR; if (H5Gclose(g2) < 0) TEST_ERROR; /* Open groups */ if ((g1 = H5Gopen2(fid, name1, H5P_DEFAULT)) < 0) TEST_ERROR; if ((g2 = H5Gopen2(fid, name2, H5P_DEFAULT)) < 0) TEST_ERROR; if (H5Gclose(g1) < 0) TEST_ERROR; if (H5Gclose(g2) < 0) TEST_ERROR; /* Close file */ if (H5Fclose(fid) < 0) TEST_ERROR; /* Release name buffers */ free(name2); free(name1); PASSED(); return 0; error: H5E_BEGIN_TRY { H5Gclose(g1); H5Gclose(g2); H5Fclose(fid); free(name2); free(name1); } H5E_END_TRY return 1; } /* end test_long() */ /*------------------------------------------------------------------------- * Function: test_large * * Purpose: Creates a really large directory. * * Return: Success: 0 * * Failure: number of errors * *------------------------------------------------------------------------- */ static int test_large(hid_t fcpl, hid_t fapl, bool new_format) { hid_t fid = (H5I_INVALID_HID); /* File ID */ hid_t cwg = (H5I_INVALID_HID), dir = (H5I_INVALID_HID); /* Group IDs */ char filename[NAME_BUF_SIZE]; char name[NAME_BUF_SIZE]; int i; if (new_format) TESTING("large directories (w/new group format)"); else TESTING("large directories"); /* Create file */ h5_fixname(FILENAME[0], fapl, filename, sizeof(filename)); if ((fid = H5Fcreate(filename, H5F_ACC_TRUNC, fcpl, fapl)) < 0) TEST_ERROR; /* * Create a directory that has so many entries that the root * of the B-tree ends up splitting. */ if ((cwg = H5Gcreate2(fid, "/big", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) TEST_ERROR; if (new_format) if (H5G__has_stab_test(cwg) != false) TEST_ERROR; for (i = 0; i < LARGE_NOBJS; i++) { snprintf(name, sizeof(name), "%05d%05d", (HDrandom() % 100000), i); if ((dir = H5Gcreate2(cwg, name, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) TEST_ERROR; if (H5Gclose(dir) < 0) TEST_ERROR; } if (new_format) if (H5G__is_new_dense_test(cwg) != true) TEST_ERROR; if (H5Gclose(cwg) < 0) TEST_ERROR; /* Close file */ if (H5Fclose(fid) < 0) TEST_ERROR; PASSED(); return 0; error: H5E_BEGIN_TRY { H5Gclose(dir); H5Gclose(cwg); H5Fclose(fid); } H5E_END_TRY return 1; } /* end test_large() */ /*------------------------------------------------------------------------- * Function: lifecycle * * Purpose: Test that adding links to a group follow proper "lifecycle" * of empty->compact->symbol table->compact->empty. (As group * is created, links are added, then links removed) * * Return: Success: 0 * * Failure: -1 * *------------------------------------------------------------------------- */ static int lifecycle(hid_t fcpl, hid_t fapl2) { hid_t fid = (H5I_INVALID_HID); /* File ID */ hid_t gid = (H5I_INVALID_HID); /* Group ID */ hid_t gid2 = (H5I_INVALID_HID); /* Datatype ID */ hid_t gcpl = (H5I_INVALID_HID); /* Group creation property list ID */ size_t lheap_size_hint; /* Local heap size hint */ unsigned max_compact; /* Maximum # of links to store in group compactly */ unsigned min_dense; /* Minimum # of links to store in group "densely" */ unsigned est_num_entries; /* Estimated # of entries in group */ unsigned est_name_len; /* Estimated length of entry name */ unsigned nmsgs; /* Number of messages in group's header */ H5O_native_info_t ninfo; /* Object info */ char objname[NAME_BUF_SIZE]; /* Object name */ char filename[NAME_BUF_SIZE]; h5_stat_size_t empty_size; /* Size of an empty file */ unsigned u; /* Local index variable */ h5_stat_size_t file_size; /* Size of each file created */ TESTING("group lifecycle"); /* Create file */ h5_fixname(FILENAME[0], fapl2, filename, sizeof(filename)); if ((fid = H5Fcreate(filename, H5F_ACC_TRUNC, fcpl, fapl2)) < 0) TEST_ERROR; /* Close file */ if (H5Fclose(fid) < 0) TEST_ERROR; /* Get size of file as empty */ if ((empty_size = h5_get_file_size(filename, fapl2)) < 0) TEST_ERROR; /* Re-open file */ if ((fid = H5Fopen(filename, H5F_ACC_RDWR, fapl2)) < 0) TEST_ERROR; /* Set up group creation property list */ if ((gcpl = H5Pcreate(H5P_GROUP_CREATE)) < 0) TEST_ERROR; /* Query default group creation property settings */ if (H5Pget_local_heap_size_hint(gcpl, &lheap_size_hint) < 0) TEST_ERROR; if (lheap_size_hint != H5G_CRT_GINFO_LHEAP_SIZE_HINT) TEST_ERROR; if (H5Pget_link_phase_change(gcpl, &max_compact, &min_dense) < 0) TEST_ERROR; if (max_compact != H5G_CRT_GINFO_MAX_COMPACT) TEST_ERROR; if (min_dense != H5G_CRT_GINFO_MIN_DENSE) TEST_ERROR; if (H5Pget_est_link_info(gcpl, &est_num_entries, &est_name_len) < 0) TEST_ERROR; if (est_num_entries != H5G_CRT_GINFO_EST_NUM_ENTRIES) TEST_ERROR; if (est_name_len != H5G_CRT_GINFO_EST_NAME_LEN) TEST_ERROR; /* Set GCPL parameters */ if (H5Pset_local_heap_size_hint(gcpl, (size_t)LIFECYCLE_LOCAL_HEAP_SIZE_HINT) < 0) TEST_ERROR; if (H5Pset_link_phase_change(gcpl, LIFECYCLE_MAX_COMPACT, LIFECYCLE_MIN_DENSE) < 0) TEST_ERROR; if (H5Pset_est_link_info(gcpl, LIFECYCLE_EST_NUM_ENTRIES, LIFECYCLE_EST_NAME_LEN) < 0) TEST_ERROR; /* Create group for testing lifecycle */ if ((gid = H5Gcreate2(fid, LIFECYCLE_TOP_GROUP, H5P_DEFAULT, gcpl, H5P_DEFAULT)) < 0) TEST_ERROR; /* Query group creation property settings */ if (H5Pget_local_heap_size_hint(gcpl, &lheap_size_hint) < 0) TEST_ERROR; if (lheap_size_hint != LIFECYCLE_LOCAL_HEAP_SIZE_HINT) TEST_ERROR; if (H5Pget_link_phase_change(gcpl, &max_compact, &min_dense) < 0) TEST_ERROR; if (max_compact != LIFECYCLE_MAX_COMPACT) TEST_ERROR; if (min_dense != LIFECYCLE_MIN_DENSE) TEST_ERROR; if (H5Pget_est_link_info(gcpl, &est_num_entries, &est_name_len) < 0) TEST_ERROR; if (est_num_entries != LIFECYCLE_EST_NUM_ENTRIES) TEST_ERROR; if (est_name_len != LIFECYCLE_EST_NAME_LEN) TEST_ERROR; /* Use internal testing routine to check that the group has no links or symbol table */ if (H5G__is_empty_test(gid) != true) TEST_ERROR; /* Create first "bottom" group */ snprintf(objname, sizeof(objname), LIFECYCLE_BOTTOM_GROUP, (unsigned)0); if ((gid2 = H5Gcreate2(gid, objname, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) TEST_ERROR; /* Check on bottom group's status */ if (H5G__is_empty_test(gid2) != true) TEST_ERROR; /* Close bottom group */ if (H5Gclose(gid2) < 0) TEST_ERROR; /* Check on top group's status */ if (H5G__is_empty_test(gid) == true) TEST_ERROR; if (H5G__has_links_test(gid, &nmsgs) != true) TEST_ERROR; if (nmsgs != 1) TEST_ERROR; /* Create several more bottom groups, to push the top group almost to a symbol table */ /* (Start counting at '1', since we've already created one bottom group */ for (u = 1; u < LIFECYCLE_MAX_COMPACT; u++) { snprintf(objname, sizeof(objname), LIFECYCLE_BOTTOM_GROUP, u); if ((gid2 = H5Gcreate2(gid, objname, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) TEST_ERROR; /* Check on bottom group's status */ if (H5G__is_empty_test(gid2) != true) TEST_ERROR; /* Close bottom group */ if (H5Gclose(gid2) < 0) TEST_ERROR; } /* end for */ /* Check on top group's status */ if (H5G__is_empty_test(gid) == true) TEST_ERROR; if (H5G__has_links_test(gid, &nmsgs) != true) TEST_ERROR; if (nmsgs != LIFECYCLE_MAX_COMPACT) TEST_ERROR; if (H5G__is_new_dense_test(gid) != false) TEST_ERROR; /* Check that the object header is only one chunk and the space has been allocated correctly */ if (H5Oget_native_info(gid, &ninfo, H5O_NATIVE_INFO_HDR) < 0) TEST_ERROR; if (ninfo.hdr.space.total != 151) TEST_ERROR; if (ninfo.hdr.space.free != 0) TEST_ERROR; if (ninfo.hdr.nmesgs != 6) TEST_ERROR; if (ninfo.hdr.nchunks != 1) TEST_ERROR; /* Create one more "bottom" group, which should push top group into using a symbol table */ snprintf(objname, sizeof(objname), LIFECYCLE_BOTTOM_GROUP, u); if ((gid2 = H5Gcreate2(gid, objname, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) TEST_ERROR; /* Check on bottom group's status */ if (H5G__is_empty_test(gid2) != true) TEST_ERROR; /* Close bottom group */ if (H5Gclose(gid2) < 0) TEST_ERROR; /* Check on top group's status */ if (H5G__is_empty_test(gid) == true) TEST_ERROR; if (H5G__has_links_test(gid, NULL) == true) TEST_ERROR; if (H5G__is_new_dense_test(gid) != true) TEST_ERROR; /* Check that the object header is still one chunk and the space has been allocated correctly */ if (H5Oget_native_info(gid, &ninfo, H5O_NATIVE_INFO_HDR) < 0) TEST_ERROR; if (ninfo.hdr.space.total != 151) TEST_ERROR; if (ninfo.hdr.space.free != 92) TEST_ERROR; if (ninfo.hdr.nmesgs != 3) TEST_ERROR; if (ninfo.hdr.nchunks != 1) TEST_ERROR; /* Unlink objects from top group */ while (u >= LIFECYCLE_MIN_DENSE) { snprintf(objname, sizeof(objname), LIFECYCLE_BOTTOM_GROUP, u); if (H5Ldelete(gid, objname, H5P_DEFAULT) < 0) FAIL_STACK_ERROR; u--; } /* end while */ /* Check on top group's status */ if (H5G__is_empty_test(gid) == true) TEST_ERROR; if (H5G__has_links_test(gid, NULL) == true) TEST_ERROR; if (H5G__is_new_dense_test(gid) != true) TEST_ERROR; /* Unlink one more object from the group, which should transform back to using links */ snprintf(objname, sizeof(objname), LIFECYCLE_BOTTOM_GROUP, u); if (H5Ldelete(gid, objname, H5P_DEFAULT) < 0) FAIL_STACK_ERROR; u--; /* Check on top group's status */ if (H5G__is_empty_test(gid) == true) TEST_ERROR; if (H5G__has_links_test(gid, &nmsgs) != true) TEST_ERROR; if (nmsgs != (LIFECYCLE_MIN_DENSE - 1)) TEST_ERROR; /* Unlink last two objects from top group */ snprintf(objname, sizeof(objname), LIFECYCLE_BOTTOM_GROUP, u); if (H5Ldelete(gid, objname, H5P_DEFAULT) < 0) FAIL_STACK_ERROR; u--; snprintf(objname, sizeof(objname), LIFECYCLE_BOTTOM_GROUP, u); if (H5Ldelete(gid, objname, H5P_DEFAULT) < 0) FAIL_STACK_ERROR; /* Check on top group's status */ if (H5G__is_empty_test(gid) != true) TEST_ERROR; /* Close top group */ if (H5Gclose(gid) < 0) TEST_ERROR; /* Unlink top group */ if (H5Ldelete(fid, LIFECYCLE_TOP_GROUP, H5P_DEFAULT) < 0) FAIL_STACK_ERROR; /* Close GCPL */ if (H5Pclose(gcpl) < 0) TEST_ERROR; /* Close file */ if (H5Fclose(fid) < 0) TEST_ERROR; /* Get size of file as empty */ if ((file_size = h5_get_file_size(filename, fapl2)) < 0) TEST_ERROR; /* Verify that file is correct size */ if (file_size != empty_size) TEST_ERROR; PASSED(); return 0; error: H5E_BEGIN_TRY { H5Gclose(gcpl); H5Gclose(gid2); H5Gclose(gid); H5Fclose(fid); } H5E_END_TRY return 1; } /* end lifecycle() */ /*------------------------------------------------------------------------- * Function: long_compact * * Purpose: Test that long links are correctly _not_ put into compact * form. * * Return: Success: 0 * * Failure: -1 * *------------------------------------------------------------------------- */ static int long_compact(hid_t fcpl, hid_t fapl2) { hid_t fid = (H5I_INVALID_HID); /* File ID */ hid_t gid = (H5I_INVALID_HID); /* Group ID */ hid_t gid2 = (H5I_INVALID_HID); /* Group ID */ char *objname = NULL; /* Object name */ char filename[NAME_BUF_SIZE]; h5_stat_size_t empty_size; /* Size of an empty file */ h5_stat_size_t file_size; /* Size of each file created */ TESTING("long link names in compact groups"); /* Create file */ h5_fixname(FILENAME[0], fapl2, filename, sizeof(filename)); if ((fid = H5Fcreate(filename, H5F_ACC_TRUNC, fcpl, fapl2)) < 0) TEST_ERROR; /* Close file */ if (H5Fclose(fid) < 0) TEST_ERROR; /* Get size of file as empty */ if ((empty_size = h5_get_file_size(filename, fapl2)) < 0) TEST_ERROR; /* Construct very long object name template */ if (NULL == (objname = (char *)malloc((size_t)(LONG_COMPACT_LENGTH + 1)))) TEST_ERROR; memset(objname, 'a', (size_t)LONG_COMPACT_LENGTH); objname[LONG_COMPACT_LENGTH] = '\0'; /* Re-open file */ if ((fid = H5Fopen(filename, H5F_ACC_RDWR, fapl2)) < 0) TEST_ERROR; /* Create top group */ if ((gid = H5Gcreate2(fid, "top", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) TEST_ERROR; /* Use internal testing routine to check that the group has no links or dense storage */ if (H5G__is_empty_test(gid) != true) TEST_ERROR; /* Create first group with "long" name */ if ((gid2 = H5Gcreate2(gid, objname, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) TEST_ERROR; /* Check on bottom group's status */ if (H5G__is_empty_test(gid2) != true) TEST_ERROR; /* Close bottom group */ if (H5Gclose(gid2) < 0) TEST_ERROR; /* Check on top group's status */ /* (Should have dense storage to hold links, since name is too long for object header message) */ if (H5G__is_empty_test(gid) == true) TEST_ERROR; if (H5G__has_links_test(gid, NULL) == true) TEST_ERROR; if (H5G__is_new_dense_test(gid) != true) TEST_ERROR; /* Create second group with "long" name */ objname[0] = 'b'; if ((gid2 = H5Gcreate2(gid, objname, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) TEST_ERROR; /* Check on bottom group's status */ if (H5G__is_empty_test(gid2) != true) TEST_ERROR; /* Close bottom group */ if (H5Gclose(gid2) < 0) TEST_ERROR; /* Check on top group's status */ /* (Should have dense storage to hold links, since name is too long for object header message) */ if (H5G__is_empty_test(gid) == true) TEST_ERROR; if (H5G__has_links_test(gid, NULL) == true) TEST_ERROR; if (H5G__is_new_dense_test(gid) != true) TEST_ERROR; /* Unlink second object from top group */ if (H5Ldelete(gid, objname, H5P_DEFAULT) < 0) FAIL_STACK_ERROR; /* Check on top group's status */ /* (Should still be dense storage to hold links, since name is too long for object header message) */ if (H5G__is_empty_test(gid) == true) TEST_ERROR; if (H5G__has_links_test(gid, NULL) == true) TEST_ERROR; if (H5G__is_new_dense_test(gid) != true) TEST_ERROR; /* Unlink first object from top group */ objname[0] = 'a'; if (H5Ldelete(gid, objname, H5P_DEFAULT) < 0) FAIL_STACK_ERROR; /* Check on top group's status */ /* (Should have deleted the dense storage now) */ if (H5G__is_empty_test(gid) != true) TEST_ERROR; /* Free object name */ free(objname); objname = NULL; /* Close top group */ if (H5Gclose(gid) < 0) TEST_ERROR; /* Unlink top group */ if (H5Ldelete(fid, "top", H5P_DEFAULT) < 0) FAIL_STACK_ERROR; /* Close file */ if (H5Fclose(fid) < 0) TEST_ERROR; /* Get size of file as empty */ if ((file_size = h5_get_file_size(filename, fapl2)) < 0) TEST_ERROR; /* Verify that file is correct size */ if (file_size != empty_size) TEST_ERROR; PASSED(); return 0; error: H5E_BEGIN_TRY { H5Gclose(gid2); H5Gclose(gid); H5Fclose(fid); } H5E_END_TRY if (objname) free(objname); return 1; } /* end long_compact() */ /*------------------------------------------------------------------------- * Function: read_old * * Purpose: Test reading a file with "old style" (symbol table) groups * * Return: Success: 0 * * Failure: -1 * *------------------------------------------------------------------------- */ static int read_old(void) { hid_t fid = (H5I_INVALID_HID); /* File ID */ hid_t gid = (H5I_INVALID_HID); /* Group ID */ hid_t gid2 = (H5I_INVALID_HID); /* Group ID */ char objname[NAME_BUF_SIZE]; /* Object name */ unsigned u; /* Local index variable */ TESTING("reading old groups"); /* Make a copy of the data file from svn. */ if (h5_make_local_copy(FILE_OLD_GROUPS, FILE_OLD_GROUPS_COPY) < 0) TEST_ERROR; /* Open copied file */ if ((fid = H5Fopen(FILE_OLD_GROUPS_COPY, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) TEST_ERROR; /* Attempt to open "old" group */ if ((gid = H5Gopen2(fid, "old", H5P_DEFAULT)) < 0) TEST_ERROR; /* Check on old group's status */ if (H5G__is_empty_test(gid) == false) TEST_ERROR; if (H5G__has_links_test(gid, NULL) == true) TEST_ERROR; if (H5G__has_stab_test(gid) != true) TEST_ERROR; /* Create a bunch of objects in the group */ for (u = 0; u < READ_OLD_NGROUPS; u++) { snprintf(objname, sizeof(objname), "Group %u", u); if ((gid2 = H5Gcreate2(gid, objname, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) TEST_ERROR; /* Check on bottom group's status */ if (H5G__is_empty_test(gid2) != true) TEST_ERROR; /* Close bottom group */ if (H5Gclose(gid2) < 0) TEST_ERROR; } /* end for */ /* Check on old group's status */ /* (Should stay in old "symbol table" form) */ if (H5G__is_empty_test(gid) == true) TEST_ERROR; if (H5G__has_links_test(gid, NULL) == true) TEST_ERROR; if (H5G__has_stab_test(gid) != true) TEST_ERROR; /* Delete new objects from old group */ for (u = 0; u < READ_OLD_NGROUPS; u++) { snprintf(objname, sizeof(objname), "Group %u", u); if (H5Ldelete(gid, objname, H5P_DEFAULT) < 0) FAIL_STACK_ERROR; } /* end for */ /* Check on old group's status */ /* (Should stay in old "symbol table" form, but have no links) */ if (H5G__is_empty_test(gid) == false) TEST_ERROR; if (H5G__has_links_test(gid, NULL) == true) TEST_ERROR; if (H5G__has_stab_test(gid) != true) TEST_ERROR; /* Close old group */ if (H5Gclose(gid) < 0) TEST_ERROR; /* Close first file */ if (H5Fclose(fid) < 0) TEST_ERROR; PASSED(); return 0; error: H5E_BEGIN_TRY { H5Gclose(gid); H5Fclose(fid); } H5E_END_TRY return 1; } /* end read_old() */ /*------------------------------------------------------------------------- * Function: no_compact * * Purpose: Test that its possible to create groups that don't use the * compact form directly (and don't use link messages). * * Return: Success: 0 * * Failure: -1 * *------------------------------------------------------------------------- */ static int no_compact(hid_t fcpl, hid_t fapl2) { hid_t fid = (H5I_INVALID_HID); /* File ID */ hid_t gid = (H5I_INVALID_HID); /* Group ID */ hid_t gid2 = (H5I_INVALID_HID); /* Datatype ID */ hid_t gcpl = (H5I_INVALID_HID); /* Group creation property list ID */ char objname[NAME_BUF_SIZE]; /* Object name */ char filename[NAME_BUF_SIZE]; h5_stat_size_t empty_size; /* Size of an empty file */ h5_stat_size_t file_size; /* Size of each file created */ unsigned est_num_entries; /* Estimated # of entries in group */ unsigned est_name_len; /* Estimated length of entry name */ TESTING("group without compact form"); /* Create file */ h5_fixname(FILENAME[0], fapl2, filename, sizeof(filename)); if ((fid = H5Fcreate(filename, H5F_ACC_TRUNC, fcpl, fapl2)) < 0) TEST_ERROR; /* Close file */ if (H5Fclose(fid) < 0) TEST_ERROR; /* Get size of file as empty */ if ((empty_size = h5_get_file_size(filename, fapl2)) < 0) TEST_ERROR; /* Re-open file */ if ((fid = H5Fopen(filename, H5F_ACC_RDWR, fapl2)) < 0) TEST_ERROR; /* Set up group creation property list */ if ((gcpl = H5Pcreate(H5P_GROUP_CREATE)) < 0) TEST_ERROR; /* Set GCPL parameters */ if (H5Pset_link_phase_change(gcpl, NO_COMPACT_MAX_COMPACT, NO_COMPACT_MIN_DENSE) < 0) TEST_ERROR; /* Check information for default group creation */ if (H5Pget_est_link_info(gcpl, &est_num_entries, &est_name_len) < 0) TEST_ERROR; if (est_num_entries != H5G_CRT_GINFO_EST_NUM_ENTRIES) TEST_ERROR; if (est_name_len != H5G_CRT_GINFO_EST_NAME_LEN) TEST_ERROR; /* Create group for testing no compact form */ if ((gid = H5Gcreate2(fid, NO_COMPACT_TOP_GROUP, H5P_DEFAULT, gcpl, H5P_DEFAULT)) < 0) TEST_ERROR; /* Close GCPL */ if (H5Pclose(gcpl) < 0) TEST_ERROR; /* Use internal testing routine to check that the group has no links or dense storage */ if (H5G__is_empty_test(gid) != true) TEST_ERROR; /* Create first "bottom" group */ snprintf(objname, sizeof(objname), NO_COMPACT_BOTTOM_GROUP, (unsigned)0); if ((gid2 = H5Gcreate2(gid, objname, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) TEST_ERROR; /* Check on bottom group's status */ if (H5G__is_empty_test(gid2) != true) TEST_ERROR; /* Close bottom group */ if (H5Gclose(gid2) < 0) TEST_ERROR; /* Check on top group's status */ if (H5G__is_empty_test(gid) == true) TEST_ERROR; if (H5G__has_links_test(gid, NULL) == true) TEST_ERROR; if (H5G__is_new_dense_test(gid) != true) TEST_ERROR; /* Unlink object from top group */ snprintf(objname, sizeof(objname), NO_COMPACT_BOTTOM_GROUP, (unsigned)0); if (H5Ldelete(gid, objname, H5P_DEFAULT) < 0) FAIL_STACK_ERROR; /* Check on top group's status */ if (H5G__is_empty_test(gid) != true) TEST_ERROR; /* Close top group */ if (H5Gclose(gid) < 0) TEST_ERROR; /* Unlink top group */ if (H5Ldelete(fid, NO_COMPACT_TOP_GROUP, H5P_DEFAULT) < 0) FAIL_STACK_ERROR; /* Close file */ if (H5Fclose(fid) < 0) TEST_ERROR; /* Get size of file as empty */ if ((file_size = h5_get_file_size(filename, fapl2)) < 0) TEST_ERROR; /* Verify that file is correct size */ if (file_size != empty_size) TEST_ERROR; PASSED(); return 0; error: H5E_BEGIN_TRY { H5Gclose(gcpl); H5Gclose(gid2); H5Gclose(gid); H5Fclose(fid); } H5E_END_TRY return 1; } /* end no_compact() */ /*------------------------------------------------------------------------- * Function: gcpl_on_root * * Purpose: Test setting group creation properties for root group. * * Return: Success: 0 * * Failure: -1 * *------------------------------------------------------------------------- */ static int gcpl_on_root(hid_t fapl2) { hid_t fid = (H5I_INVALID_HID); /* File ID */ hid_t gid = (H5I_INVALID_HID); /* Group ID */ hid_t gid2 = (H5I_INVALID_HID); /* Datatype ID */ hid_t fcpl = (H5I_INVALID_HID); /* File creation property list ID */ hid_t gcpl = (H5I_INVALID_HID); /* Group creation property list ID */ hid_t lcpl = (H5I_INVALID_HID); /* Link creation property list ID */ unsigned max_compact; /* Maximum # of links to store in group compactly */ unsigned min_dense; /* Minimum # of links to store in group "densely" */ char filename[NAME_BUF_SIZE]; TESTING("setting root group creation properties"); /* Create file */ h5_fixname(FILENAME[0], fapl2, filename, sizeof(filename)); /* Set up file creation property list */ if ((fcpl = H5Pcreate(H5P_FILE_CREATE)) < 0) TEST_ERROR; /* Set GCPL parameters */ if (H5Pset_link_phase_change(fcpl, GCPL_ON_ROOT_MAX_COMPACT, GCPL_ON_ROOT_MIN_DENSE) < 0) TEST_ERROR; /* Query the group creation properties from the FCPL */ if (H5Pget_link_phase_change(fcpl, &max_compact, &min_dense) < 0) TEST_ERROR; if (max_compact != GCPL_ON_ROOT_MAX_COMPACT) TEST_ERROR; if (min_dense != GCPL_ON_ROOT_MIN_DENSE) TEST_ERROR; /* Create file with modified root group creation properties */ if ((fid = H5Fcreate(filename, H5F_ACC_TRUNC, fcpl, fapl2)) < 0) TEST_ERROR; /* Close FCPL */ if (H5Pclose(fcpl) < 0) TEST_ERROR; /* Open the root group */ if ((gid = H5Gopen2(fid, "/", H5P_DEFAULT)) < 0) TEST_ERROR; /* Query the group creation properties */ if ((gcpl = H5Gget_create_plist(gid)) < 0) TEST_ERROR; if (H5Pget_link_phase_change(gcpl, &max_compact, &min_dense) < 0) TEST_ERROR; if (max_compact != GCPL_ON_ROOT_MAX_COMPACT) TEST_ERROR; if (min_dense != GCPL_ON_ROOT_MIN_DENSE) TEST_ERROR; /* Close GCPL */ if (H5Pclose(gcpl) < 0) TEST_ERROR; /* Create a link creation property list, with intermediate group creation set */ if ((lcpl = H5Pcreate(H5P_LINK_CREATE)) < 0) TEST_ERROR; if (H5Pset_create_intermediate_group(lcpl, true) < 0) TEST_ERROR; /* Create a group and intermediate groups, to check if root group settings are inherited */ if ((gid2 = H5Gcreate2(gid, GCPL_ON_ROOT_BOTTOM_GROUP, lcpl, H5P_DEFAULT, H5P_DEFAULT)) < 0) TEST_ERROR; /* Close LCPL */ if (H5Pclose(lcpl) < 0) TEST_ERROR; /* Query the group creation properties */ if ((gcpl = H5Gget_create_plist(gid2)) < 0) TEST_ERROR; if (H5Pget_link_phase_change(gcpl, &max_compact, &min_dense) < 0) TEST_ERROR; if (max_compact != H5G_CRT_GINFO_MAX_COMPACT) TEST_ERROR; if (min_dense != H5G_CRT_GINFO_MIN_DENSE) TEST_ERROR; /* Close GCPL */ if (H5Pclose(gcpl) < 0) TEST_ERROR; /* Close bottom group */ if (H5Gclose(gid2) < 0) TEST_ERROR; /* Open the middle group */ if ((gid2 = H5Gopen2(fid, GCPL_ON_ROOT_MIDDLE_GROUP, H5P_DEFAULT)) < 0) TEST_ERROR; /* Query the group creation properties */ if ((gcpl = H5Gget_create_plist(gid2)) < 0) TEST_ERROR; if (H5Pget_link_phase_change(gcpl, &max_compact, &min_dense) < 0) TEST_ERROR; if (max_compact != GCPL_ON_ROOT_MAX_COMPACT) TEST_ERROR; if (min_dense != GCPL_ON_ROOT_MIN_DENSE) TEST_ERROR; /* Close GCPL */ if (H5Pclose(gcpl) < 0) TEST_ERROR; /* Close bottom group */ if (H5Gclose(gid2) < 0) TEST_ERROR; /* Close root group */ if (H5Gclose(gid) < 0) TEST_ERROR; /* Close file */ if (H5Fclose(fid) < 0) TEST_ERROR; PASSED(); return 0; error: H5E_BEGIN_TRY { H5Gclose(lcpl); H5Gclose(gcpl); H5Gclose(gid2); H5Gclose(gid); H5Gclose(fcpl); H5Fclose(fid); } H5E_END_TRY return 1; } /* end gcpl_on_root() */ /*------------------------------------------------------------------------- * Function: old_api * * Purpose: Test old API routines * * Return: Success: 0 * Failure: -1 * *------------------------------------------------------------------------- */ static int old_api(hid_t fapl) { #ifndef H5_NO_DEPRECATED_SYMBOLS hid_t fid = (H5I_INVALID_HID); /* File ID */ hid_t gid = (H5I_INVALID_HID); /* Group ID */ h5_stat_size_t small_file_size; /* Size of small group file */ h5_stat_size_t large_file_size; /* Size of large group file */ char filename[NAME_BUF_SIZE]; #endif /* H5_NO_DEPRECATED_SYMBOLS */ TESTING("old API routines"); #ifndef H5_NO_DEPRECATED_SYMBOLS /* Create file */ h5_fixname(FILENAME[0], fapl, filename, sizeof(filename)); /* Create file */ if ((fid = H5Fcreate(filename, H5F_ACC_TRUNC, H5P_DEFAULT, fapl)) < 0) FAIL_STACK_ERROR; /* Create a group, with the old API routine and a "small" heap */ if ((gid = H5Gcreate1(fid, OLD_API_GROUP, (size_t)0)) < 0) FAIL_STACK_ERROR; /* Close group */ if (H5Gclose(gid) < 0) FAIL_STACK_ERROR; /* Close file */ if (H5Fclose(fid) < 0) FAIL_STACK_ERROR; /* Get the size of the file with a "small" heap for group */ if ((small_file_size = h5_get_file_size(filename, fapl)) < 0) TEST_ERROR; /* Create file */ if ((fid = H5Fcreate(filename, H5F_ACC_TRUNC, H5P_DEFAULT, fapl)) < 0) FAIL_STACK_ERROR; /* Create a group, with the old API routine and a "large" heap */ if ((gid = H5Gcreate1(fid, OLD_API_GROUP, (size_t)10000)) < 0) FAIL_STACK_ERROR; /* Close group */ if (H5Gclose(gid) < 0) FAIL_STACK_ERROR; /* Re-open group */ if ((gid = H5Gopen1(fid, OLD_API_GROUP)) < 0) FAIL_STACK_ERROR; /* Close group */ if (H5Gclose(gid) < 0) FAIL_STACK_ERROR; /* Close file */ if (H5Fclose(fid) < 0) FAIL_STACK_ERROR; /* Get the size of the file with a "large" heap for group */ if ((large_file_size = h5_get_file_size(filename, fapl)) < 0) TEST_ERROR; /* Check that the file with a "large" group heap is actually bigger */ if (large_file_size <= small_file_size) TEST_ERROR; PASSED(); #else /* H5_NO_DEPRECATED_SYMBOLS */ /* Shut compiler up */ (void)fapl; SKIPPED(); puts(" Deprecated API symbols not enabled"); #endif /* H5_NO_DEPRECATED_SYMBOLS */ return 0; #ifndef H5_NO_DEPRECATED_SYMBOLS error: H5E_BEGIN_TRY { H5Gclose(gid); H5Fclose(fid); } H5E_END_TRY return 1; #endif /* H5_NO_DEPRECATED_SYMBOLS */ } /* end old_api() */ /*------------------------------------------------------------------------- * Function: corrupt_stab_msg * * Purpose: Test that a corrupt symbol table message can be fixed * using the cached symbol table information. * * Return: Success: 0 * Failure: -1 * *------------------------------------------------------------------------- */ static int corrupt_stab_msg(void) { hid_t fid = (H5I_INVALID_HID); /* File ID */ hid_t did = (H5I_INVALID_HID); /* Dataset ID */ TESTING("corrupt symbol table message"); /* Make a copy of the data file from svn. */ if (h5_make_local_copy(CORRUPT_STAB_FILE, CORRUPT_STAB_TMP_FILE) < 0) TEST_ERROR; #ifndef H5_STRICT_FORMAT_CHECKS /* Open temp file through HDF5 library */ if ((fid = H5Fopen(CORRUPT_STAB_TMP_FILE, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) TEST_ERROR; /* Open dataset */ if ((did = H5Dopen2(fid, CORRUPT_STAB_DSET, H5P_DEFAULT)) < 0) TEST_ERROR; /* Close dataset and file */ if (H5Dclose(did) < 0) TEST_ERROR; if (H5Fclose(fid) < 0) TEST_ERROR; /* Now reopen with read only access. This verifies that the issue has been * corrected, as the symbol table message is not patched in read only mode. */ /* Open file */ if ((fid = H5Fopen(CORRUPT_STAB_TMP_FILE, H5F_ACC_RDONLY, H5P_DEFAULT)) < 0) TEST_ERROR; /* Open dataset */ if ((did = H5Dopen2(fid, CORRUPT_STAB_DSET, H5P_DEFAULT)) < 0) TEST_ERROR; /* Close dataset and file */ if (H5Dclose(did) < 0) TEST_ERROR; if (H5Fclose(fid) < 0) TEST_ERROR; #else /* H5_STRICT_FORMAT_CHECKS */ /* Open file */ if ((fid = H5Fopen(CORRUPT_STAB_TMP_FILE, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) TEST_ERROR; /* Verify that an error is thrown when we try to access the dataset */ H5E_BEGIN_TRY { did = H5Dopen2(fid, CORRUPT_STAB_DSET, H5P_DEFAULT); } H5E_END_TRY if (did >= 0) TEST_ERROR; /* Close file */ if (H5Fclose(fid) < 0) TEST_ERROR; #endif /* H5_STRICT_FORMAT_CHECKS */ PASSED(); return 0; error: H5E_BEGIN_TRY { H5Dclose(did); H5Fclose(fid); } H5E_END_TRY return 1; } /* end corrupt_stab_msg() */ /*------------------------------------------------------------------------- * Function: main * * Purpose: Test groups * * Return: Success: zero * * Failure: non-zero * *------------------------------------------------------------------------- */ int main(void) { hid_t fapl, fapl2; /* File access property list IDs */ hid_t fcpl, fcpl2; /* File creation property list ID */ unsigned new_format; /* Whether to use the new format or not */ const char *env_h5_drvr; /* File Driver value from environment */ bool contig_addr_vfd; /* Whether VFD used has a contiguous address space */ bool driver_is_default_compatible; int nerrors = 0; /* Get the VFD to use */ env_h5_drvr = getenv(HDF5_DRIVER); if (env_h5_drvr == NULL) env_h5_drvr = "nomatch"; /* VFD that does not support contiguous address space */ contig_addr_vfd = (bool)(strcmp(env_h5_drvr, "split") != 0 && strcmp(env_h5_drvr, "multi") != 0); /* Reset library */ h5_reset(); fapl = h5_fileaccess(); if (h5_driver_is_default_vfd_compatible(fapl, &driver_is_default_compatible) < 0) TEST_ERROR; /* 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; /* Set up file creation property list */ if ((fcpl = H5Pcreate(H5P_FILE_CREATE)) < 0) TEST_ERROR; if ((fcpl2 = H5Pcopy(fcpl)) < 0) TEST_ERROR; /* Set to use paged aggregation strategy and persisting free-space */ /* Skip testing for multi/split drivers */ if (H5Pset_file_space_strategy(fcpl2, H5F_FSPACE_STRATEGY_PAGE, 1, (hsize_t)1) < 0) TEST_ERROR; /* Loop over using new group format */ for (new_format = false; new_format <= true; new_format++) { hid_t my_fapl = fapl; hid_t my_fcpl = fcpl; if (!contig_addr_vfd) continue; if (new_format) { my_fapl = fapl2; my_fcpl = fcpl2; /* Set to use paged aggregation and persisting free-space */ } /* Perform basic tests, with old & new style groups */ nerrors += test_misc(my_fcpl, my_fapl, new_format); nerrors += test_long(my_fcpl, my_fapl, new_format); nerrors += test_large(my_fcpl, my_fapl, new_format); } /* end for */ /* New format group specific tests (require new format features) */ if (contig_addr_vfd) { nerrors += lifecycle(fcpl2, fapl2); nerrors += long_compact(fcpl2, fapl2); if (driver_is_default_compatible) { nerrors += read_old(); } nerrors += no_compact(fcpl2, fapl2); nerrors += gcpl_on_root(fapl2); } /* Old group API specific tests */ nerrors += old_api(fapl); if (driver_is_default_compatible) { nerrors += corrupt_stab_msg(); } /* Close 2nd FAPL */ H5Pclose(fapl2); H5Pclose(fcpl); H5Pclose(fcpl2); /* Verify symbol table messages are cached */ nerrors += (h5_verify_cached_stabs(FILENAME, fapl) < 0 ? 1 : 0); /* Check for test errors */ if (nerrors) goto error; puts("All symbol table tests passed."); /* Cleanup */ if (GetTestCleanup()) { HDremove(FILE_OLD_GROUPS_COPY); HDremove(CORRUPT_STAB_TMP_FILE); } h5_cleanup(FILENAME, fapl); return 0; error: puts("*** TESTS FAILED ***"); return 1; }