From ad28fa5b0c1384fe70397fb2eaa83e2a6e62699d Mon Sep 17 00:00:00 2001 From: Neil Fortner Date: Wed, 15 Oct 2008 22:52:16 -0500 Subject: [svn-r15886] Purpose: Close bug 1332 Description: Improved external link traversal of h5dump. h5dump will now properly avoid all cycles, even those spanning multiple files. Improvement to the output of committed datatypes. Committed datatypes are now checked for uniqueness (like other objects). Tests added for these cases. Tested: kagiso, linew, smirom (h5committest) --- MANIFEST | 3 + release_docs/RELEASE.txt | 4 + tools/h5dump/h5dump.c | 394 +++++++++++++++++++++++++------ tools/h5dump/h5dumpgentest.c | 31 ++- tools/h5dump/testh5dump.sh.in | 4 + tools/h5ls/h5ls.c | 2 +- tools/lib/h5tools_utils.c | 28 +-- tools/testfiles/textlinkfar.ddl | 69 ++++++ tools/testfiles/textlinkfar.h5 | Bin 0 -> 888 bytes tools/testfiles/textlinksrc-1.ls | 2 + tools/testfiles/textlinksrc-3.ls | 2 + tools/testfiles/textlinksrc.ddl | 60 +++++ tools/testfiles/textlinktar.h5 | Bin 5664 -> 6752 bytes tools/testfiles/thlink.h5.xml | 4 +- tools/testfiles/tmany.h5.xml | 4 +- tools/testfiles/tnamed_dtype_attr.ddl | 4 +- tools/testfiles/tnamed_dtype_attr.h5 | Bin 2304 -> 2304 bytes tools/testfiles/tnamed_dtype_attr.h5.xml | 15 +- tools/testfiles/torderattr1.ddl | 4 +- tools/testfiles/torderattr2.ddl | 4 +- tools/testfiles/torderattr3.ddl | 4 +- tools/testfiles/torderattr4.ddl | 4 +- tools/testfiles/tvlstr.ddl | 2 +- windows/tools/h5dump/testh5dump.bat | 4 + 24 files changed, 541 insertions(+), 107 deletions(-) create mode 100644 tools/testfiles/textlinkfar.ddl create mode 100644 tools/testfiles/textlinkfar.h5 create mode 100644 tools/testfiles/textlinksrc.ddl diff --git a/MANIFEST b/MANIFEST index 9d2e2af..4fe181e 100644 --- a/MANIFEST +++ b/MANIFEST @@ -1154,6 +1154,9 @@ ./tools/testfiles/textlink.h5 ./tools/testfiles/textlink.h5.xml ./tools/testfiles/textlink-1.ls +./tools/testfiles/textlinkfar.ddl +./tools/testfiles/textlinkfar.h5 +./tools/testfiles/textlinksrc.ddl ./tools/testfiles/textlinksrc.h5 ./tools/testfiles/textlinksrc-1.ls ./tools/testfiles/textlinksrc-2.ls diff --git a/release_docs/RELEASE.txt b/release_docs/RELEASE.txt index a1711d1..80a57c7 100644 --- a/release_docs/RELEASE.txt +++ b/release_docs/RELEASE.txt @@ -175,6 +175,10 @@ Bug Fixes since HDF5-1.8.0 release Tools ----- + - h5dump now checks for uniqueness of committed datatypes. + (NAF - 2008/10/15) + - Fixed unnecessary indentation of committed datatypes in h5dump. + (NAF - 2008/10/15) - Fixed bugs in h5stat:segmemtation fault when printing groups and print warning message when traversal of objects is unsuccessful. (see bug #1253) (VC- 2008/10/13) diff --git a/tools/h5dump/h5dump.c b/tools/h5dump/h5dump.c index 8ace682..979c2ff 100644 --- a/tools/h5dump/h5dump.c +++ b/tools/h5dump/h5dump.c @@ -55,9 +55,24 @@ const char *progname = "h5dump"; #define H5_SZIP_MSB_OPTION_MASK 16 #define H5_SZIP_RAW_OPTION_MASK 128 +/* List of table structures. There is one table structure for each file */ +typedef struct h5dump_table_list_t { + size_t nalloc; + size_t nused; + struct { + unsigned long fileno; /* File number that these tables refer to */ + hid_t oid; /* ID of an object in this file, held open so fileno is consistent */ + table_t *group_table; /* Table of groups */ + table_t *dset_table; /* Table of datasets */ + table_t *type_table; /* Table of datatypes */ + } *tables; +} h5dump_table_list_t; + int d_status = EXIT_SUCCESS; static int unamedtype = 0; /* shared datatype with no name */ +static h5dump_table_list_t table_list = {0, 0, NULL}; static table_t *group_table = NULL, *dset_table = NULL, *type_table = NULL; +static hbool_t hit_elink = FALSE; /* whether we have traversed an external link */ static size_t prefix_len = 1024; static char *prefix; static const char *driver = NULL; /* The driver to open the file with. */ @@ -106,7 +121,7 @@ static void init_prefix(char **prfx, size_t prfx_len); static void add_prefix(char **prfx, size_t *prfx_len, const char *name); /* callback function used by H5Literate() */ static herr_t dump_all_cb(hid_t group, const char *name, const H5L_info_t *linfo, void *op_data); -static int dump_extlink(const char *filename, const char *targname); +static int dump_extlink(hid_t group, const char *linkname, const char *objname); static h5tool_format_t dataformat = { @@ -359,7 +374,7 @@ static char *xml_escape_the_name(const char *); /* a structure for handling the order command-line parameters come in */ struct handler_t { - void (*func)(hid_t, const char *, void *, int); + void (*func)(hid_t, const char *, void *, int, const char *); char *obj; struct subset_t *subset_info; }; @@ -690,6 +705,126 @@ usage(const char *prog) fprintf(stdout, "\n"); } + +/*------------------------------------------------------------------------- + * Function: table_list_add + * + * Purpose: Add a new set of tables + * + * Return: index of added table on success, -1 on failure + * + * Programmer: Neil Fortner, nfortne2@hdfgroup.org + * Adapted from trav_addr_add in h5trav.c by Quincey Koziol + * + * Date: October 13, 2008 + * + *------------------------------------------------------------------------- + */ +static ssize_t +table_list_add(hid_t oid, unsigned long file_no) +{ + size_t idx; /* Index of table to use */ + find_objs_t info; + void *tmp_ptr; + + /* Allocate space if necessary */ + if(table_list.nused == table_list.nalloc) { + table_list.nalloc = MAX(1, table_list.nalloc * 2); + if(NULL == (tmp_ptr = HDrealloc(table_list.tables, table_list.nalloc * sizeof(table_list.tables[0])))) + return -1; + table_list.tables = tmp_ptr; + } /* end if */ + + /* Append it */ + idx = table_list.nused++; + table_list.tables[idx].fileno = file_no; + table_list.tables[idx].oid = oid; + if(H5Iinc_ref(oid) < 0) { + table_list.nused--; + return -1; + } + if(init_objs(oid, &info, &table_list.tables[idx].group_table, + &table_list.tables[idx].dset_table, &table_list.tables[idx].type_table) < 0) { + H5Idec_ref(oid); + table_list.nused--; + return -1; + } + +#ifdef H5DUMP_DEBUG + dump_tables(&info); +#endif /* H5DUMP_DEBUG */ + + return((ssize_t) idx); +} /* end table_list_add() */ + + +/*------------------------------------------------------------------------- + * Function: table_list_visited + * + * Purpose: Check if a table already exists for the specified fileno + * + * Return: The index of the matching table, or -1 if no matches found + * + * Programmer: Neil Fortner, nfortne2@hdfgroup.org + * Adapted from trav_addr_visited in h5trav.c by Quincey Koziol + * + * Date: October 13, 2008 + * + *------------------------------------------------------------------------- + */ +static ssize_t +table_list_visited(unsigned long file_no) +{ + size_t u; /* Local index variable */ + + /* Look for table */ + for(u = 0; u < table_list.nused; u++) + /* Check for fileno value already in array */ + if(table_list.tables[u].fileno == file_no) + return((ssize_t) u); + + /* Didn't find table */ + return(-1); +} /* end table_list_visited() */ + + +/*------------------------------------------------------------------------- + * Function: table_list_free + * + * Purpose: Frees the table list + * + * Return: void + * + * Programmer: Neil Fortner, nfortne2@hdfgroup.org + * + * Date: October 13, 2008 + * + *------------------------------------------------------------------------- + */ +static void +table_list_free(void) +{ + size_t u; /* Local index variable */ + + /* Iterate over tables */ + for(u = 0; u < table_list.nused; u++) { + /* Release object id */ + if(H5Idec_ref(table_list.tables[u].oid) < 0) + d_status = EXIT_FAILURE; + + /* Free each table */ + free_table(table_list.tables[u].group_table); + free_table(table_list.tables[u].dset_table); + free_table(table_list.tables[u].type_table); + } + + /* Free the table list */ + HDfree(table_list.tables); + table_list.tables = NULL; + table_list.nalloc = table_list.nused = 0; +} /* end table_list_free() */ + + /*------------------------------------------------------------------------- * Function: print_datatype * @@ -1443,7 +1578,7 @@ dump_all_cb(hid_t group, const char *name, const H5L_info_t *linfo, void UNUSED case H5O_TYPE_DATASET: if((obj = H5Dopen2(group, name, H5P_DEFAULT)) >= 0) { - if(oinfo.rc > 1) { + if(oinfo.rc > 1 || hit_elink) { obj_t *found_obj; /* Found object */ found_obj = search_obj(dset_table, oinfo.addr); @@ -1479,6 +1614,7 @@ dump_all_cb(hid_t group, const char *name, const H5L_info_t *linfo, void UNUSED char *t_obj_path = xml_escape_the_name(obj_path); char *t_prefix = xml_escape_the_name(HDstrcmp(prefix,"") ? prefix : "/"); char *t_name = xml_escape_the_name(name); + char *t_objname = xml_escape_the_name(found_obj->objname); char dsetxid[100]; char parentxid[100]; char pointerxid[100]; @@ -1501,13 +1637,14 @@ dump_all_cb(hid_t group, const char *name, const H5L_info_t *linfo, void UNUSED xml_name_to_XID(found_obj->objname, pointerxid, sizeof(pointerxid), 1); printf("<%sDatasetPtr OBJ-XID=\"%s\" H5Path=\"%s\"/>\n", xmlnsprefix, - pointerxid,t_obj_path); + pointerxid,t_objname); indentation(indent); printf("\n", xmlnsprefix); HDfree(t_name); HDfree(t_obj_path); HDfree(t_prefix); + HDfree(t_objname); } H5Dclose(obj); @@ -1672,7 +1809,7 @@ dump_all_cb(hid_t group, const char *name, const H5L_info_t *linfo, void UNUSED /* dump the external link */ - dump_extlink(filename,targname); + dump_extlink(group, name, targname); } /* end if */ @@ -1786,7 +1923,7 @@ done: static void dump_named_datatype(hid_t tid, const char *name) { - + H5O_info_t oinfo; unsigned attr_crt_order_flags; hid_t tcpl_id; /* datatype creation property list ID */ @@ -1814,13 +1951,33 @@ dump_named_datatype(hid_t tid, const char *name) printf("%s \"%s\" %s", dump_header_format->datatypebegin, name, dump_header_format->datatypeblockbegin); - if(H5Tget_class(tid) == H5T_COMPOUND) - print_datatype(tid, 1); - else { - indentation(indent + COL); - print_datatype(tid, 1); + H5Oget_info(tid, &oinfo); + + /* Must check for uniqueness of all objects if we've traversed an elink, + * otherwise only check if the reference count > 1. + */ + if(oinfo.rc > 1 || hit_elink) { + obj_t *found_obj; /* Found object */ + + found_obj = search_obj(type_table, oinfo.addr); + + if (found_obj == NULL) { + error_msg(progname, "internal error (file %s:line %d)\n", + __FILE__, __LINE__); + d_status = EXIT_FAILURE; + goto done; + } + else if (found_obj->displayed) { + printf("%s \"%s\"\n", HARDLINK, found_obj->objname); + goto done; + } + else + found_obj->displayed = TRUE; + } /* end if */ + + print_datatype(tid, 1); + if(H5Tget_class(tid) != H5T_COMPOUND) printf(";\n"); - } /* end else */ /* print attributes */ indent += COL; @@ -1834,6 +1991,8 @@ dump_named_datatype(hid_t tid, const char *name) H5Aiterate2(tid, H5_INDEX_NAME, sort_order, NULL, dump_attr_cb, NULL); indent -= COL; + +done: end_obj(dump_header_format->datatypeend, dump_header_format->datatypeblockend); } @@ -1921,7 +2080,10 @@ dump_group(hid_t gid, const char *name) H5Oget_info(gid, &oinfo); - if(oinfo.rc > 1) { + /* Must check for uniqueness of all objects if we've traversed an elink, + * otherwise only check if the reference count > 1. + */ + if(oinfo.rc > 1 || hit_elink) { obj_t *found_obj; /* Found object */ found_obj = search_obj(group_table, oinfo.addr); @@ -3149,7 +3311,7 @@ set_sort_order(const char *form) *------------------------------------------------------------------------- */ static void -handle_attributes(hid_t fid, const char *attr, void UNUSED * data, int pe) +handle_attributes(hid_t fid, const char *attr, void UNUSED * data, int UNUSED pe, const char UNUSED *display_name) { dump_selected_attr(fid, attr); } @@ -3301,20 +3463,21 @@ parse_subset_params(char *dset) *------------------------------------------------------------------------- */ static void -handle_datasets(hid_t fid, const char *dset, void *data, int pe) +handle_datasets(hid_t fid, const char *dset, void *data, int pe, const char *display_name) { H5O_info_t oinfo; hid_t dsetid; struct subset_t *sset = (struct subset_t *)data; + const char *real_name = display_name ? display_name : dset; if((dsetid = H5Dopen2(fid, dset, H5P_DEFAULT)) < 0) { if (pe) { - begin_obj(dump_header_format->datasetbegin, dset, + begin_obj(dump_header_format->datasetbegin, real_name, dump_header_format->datasetblockbegin); indentation(COL); - error_msg(progname, "unable to open dataset \"%s\"\n", dset); + error_msg(progname, "unable to open dataset \"%s\"\n", real_name); end_obj(dump_header_format->datasetend, dump_header_format->datasetblockend); d_status = EXIT_FAILURE; @@ -3407,14 +3570,15 @@ handle_datasets(hid_t fid, const char *dset, void *data, int pe) } H5Oget_info(dsetid, &oinfo); - if(oinfo.rc > 1) { + if(oinfo.rc > 1 || hit_elink) { obj_t *found_obj; /* Found object */ found_obj = search_obj(dset_table, oinfo.addr); if(found_obj) { if (found_obj->displayed) { - begin_obj(dump_header_format->datasetbegin, dset, + indentation(indent); + begin_obj(dump_header_format->datasetbegin, real_name, dump_header_format->datasetblockbegin); indentation(indent + COL); printf("%s \"%s\"\n", HARDLINK, found_obj->objname); @@ -3423,14 +3587,14 @@ handle_datasets(hid_t fid, const char *dset, void *data, int pe) dump_header_format->datasetblockend); } else { found_obj->displayed = TRUE; - dump_dataset(dsetid, dset, sset); + dump_dataset(dsetid, real_name, sset); } } else d_status = EXIT_FAILURE; } else - dump_dataset(dsetid, dset, sset); + dump_dataset(dsetid, real_name, sset); if(H5Dclose(dsetid) < 0) d_status = EXIT_FAILURE; @@ -3459,18 +3623,19 @@ handle_datasets(hid_t fid, const char *dset, void *data, int pe) *------------------------------------------------------------------------- */ static void -handle_groups(hid_t fid, const char *group, void UNUSED * data, int pe) +handle_groups(hid_t fid, const char *group, void UNUSED * data, int pe, const char * display_name) { - hid_t gid; + hid_t gid; + const char *real_name = display_name ? display_name : group; if((gid = H5Gopen2(fid, group, H5P_DEFAULT)) < 0) { if ( pe ) { - begin_obj(dump_header_format->groupbegin, group, dump_header_format->groupblockbegin); + begin_obj(dump_header_format->groupbegin, real_name, dump_header_format->groupblockbegin); indentation(COL); - error_msg(progname, "unable to open group \"%s\"\n", group); + error_msg(progname, "unable to open group \"%s\"\n", real_name); end_obj(dump_header_format->groupend, dump_header_format->groupblockend); d_status = EXIT_FAILURE; } @@ -3488,7 +3653,7 @@ handle_groups(hid_t fid, const char *group, void UNUSED * data, int pe) HDstrcpy(prefix, group); - dump_group(gid, group); + dump_group(gid, real_name); if(H5Gclose(gid) < 0) d_status = EXIT_FAILURE; @@ -3510,7 +3675,7 @@ handle_groups(hid_t fid, const char *group, void UNUSED * data, int pe) *------------------------------------------------------------------------- */ static void -handle_links(hid_t fid, const char *links, void UNUSED * data, int pe) +handle_links(hid_t fid, const char *links, void UNUSED * data, int UNUSED pe, const char UNUSED *display_name) { H5L_info_t linfo; @@ -3602,9 +3767,10 @@ handle_links(hid_t fid, const char *links, void UNUSED * data, int pe) *------------------------------------------------------------------------- */ static void -handle_datatypes(hid_t fid, const char *type, void UNUSED * data, int pe) +handle_datatypes(hid_t fid, const char *type, void UNUSED * data, int pe, const char *display_name) { hid_t type_id; + const char *real_name = display_name ? display_name : type; if((type_id = H5Topen2(fid, type, H5P_DEFAULT)) < 0) { @@ -3619,7 +3785,7 @@ handle_datatypes(hid_t fid, const char *type, void UNUSED * data, int pe) /* unamed datatype */ sprintf(name, "/#"H5_PRINTF_HADDR_FMT, type_table->objs[idx].objno); - if(!HDstrcmp(name, type)) + if(!HDstrcmp(name, real_name)) break; } /* end if */ @@ -3631,10 +3797,10 @@ handle_datatypes(hid_t fid, const char *type, void UNUSED * data, int pe) if ( pe ) { /* unknown type */ - begin_obj(dump_header_format->datatypebegin, type, + begin_obj(dump_header_format->datatypebegin, real_name, dump_header_format->datatypeblockbegin); indentation(COL); - error_msg(progname, "unable to open datatype \"%s\"\n", type); + error_msg(progname, "unable to open datatype \"%s\"\n", real_name); end_obj(dump_header_format->datatypeend, dump_header_format->datatypeblockend); d_status = EXIT_FAILURE; @@ -3645,14 +3811,14 @@ handle_datatypes(hid_t fid, const char *type, void UNUSED * data, int pe) { hid_t dsetid = H5Dopen2(fid, type_table->objs[idx].objname, H5P_DEFAULT); type_id = H5Dget_type(dsetid); - dump_named_datatype(type_id, type); + dump_named_datatype(type_id, real_name); H5Tclose(type_id); H5Dclose(dsetid); } } else { - dump_named_datatype(type_id, type); + dump_named_datatype(type_id, real_name); if(H5Tclose(type_id) < 0) d_status = EXIT_FAILURE; @@ -4073,7 +4239,7 @@ main(int argc, const char *argv[]) char *fname = NULL; void *edata; H5E_auto2_t func; - find_objs_t info; + H5O_info_t oi; struct handler_t *hand; int i; unsigned u; @@ -4162,12 +4328,22 @@ main(int argc, const char *argv[]) } - /* find all shared objects */ - if(init_objs(fid, &info, &group_table, &dset_table, &type_table) < 0) { + /* Get object info for root group */ + if(H5Oget_info_by_name(fid, "/", &oi, H5P_DEFAULT) < 0) { error_msg(progname, "internal error (file %s:line %d)\n", __FILE__, __LINE__); d_status = EXIT_FAILURE; goto done; } + + /* Initialize object tables */ + if(table_list_add(fid, oi.fileno) < 0) { + error_msg(progname, "internal error (file %s:line %d)\n", __FILE__, __LINE__); + d_status = EXIT_FAILURE; + goto done; + } + group_table = table_list.tables[0].group_table; + dset_table = table_list.tables[0].dset_table; + type_table = table_list.tables[0].type_table; /* does there exist unamed committed datatype */ for (u = 0; u < type_table->nobjs; u++) @@ -4176,10 +4352,6 @@ main(int argc, const char *argv[]) break; } /* end if */ -#ifdef H5DUMP_DEBUG - dump_tables(&info); -#endif /* H5DUMP_DEBUG */ - /* start to dump - display file header information */ if (!doxml) { begin_obj(dump_header_format->filebegin, fname, @@ -4257,7 +4429,7 @@ main(int argc, const char *argv[]) for(i = 0; i < argc; i++) if(hand[i].func) - hand[i].func(fid, hand[i].obj, hand[i].subset_info, 1); + hand[i].func(fid, hand[i].obj, hand[i].subset_info, 1, NULL); } if (!doxml) { @@ -4267,16 +4439,14 @@ main(int argc, const char *argv[]) } done: + /* Free tables for objects */ + table_list_free(); + if (H5Fclose(fid) < 0) d_status = EXIT_FAILURE; free_handler(hand, argc); - /* Free tables for objects */ - free_table(group_table); - free_table(dset_table); - free_table(type_table); - HDfree(prefix); HDfree(fname); @@ -5435,20 +5605,49 @@ xml_dump_named_datatype(hid_t type, const char *name) "Parents=\"%s\" H5ParentPaths=\"%s\">\n", xmlnsprefix, name, dtxid, - parentxid,(HDstrcmp(prefix, "") ? t_prefix : "/")); + parentxid, HDstrcmp(prefix,"") ? t_prefix : "/"); } else { + H5O_info_t oinfo; /* Object info */ + printf("<%sNamedDataType Name=\"%s\" OBJ-XID=\"%s\" " "H5Path=\"%s\" Parents=\"%s\" H5ParentPaths=\"%s\">\n", xmlnsprefix, t_name, dtxid, t_tmp, parentxid, (HDstrcmp(prefix, "") ? t_prefix : "/")); + + /* Check uniqueness of named datatype */ + H5Oget_info(type, &oinfo); + if(oinfo.rc > 1) { + obj_t *found_obj; /* Found object */ + + /* Group with more than one link to it... */ + found_obj = search_obj(type_table, oinfo.addr); + + if (found_obj == NULL) { + indentation(indent); + error_msg(progname, "internal error (file %s:line %d)\n", + __FILE__, __LINE__); + d_status = EXIT_FAILURE; + goto done; + } else if(found_obj->displayed) { + /* We have already printed this named datatype, print it as a + * NamedDatatypePtr + */ + char pointerxid[100]; + char *t_objname = xml_escape_the_name(found_obj->objname); + + indentation(indent + COL); + xml_name_to_XID(found_obj->objname, pointerxid, sizeof(pointerxid), 1); + printf("<%sNamedDatatypePtr OBJ-XID=\"%s\" H5Path=\"%s\"/>\n", + xmlnsprefix, pointerxid, t_objname); + indentation(indent); + printf("\n", xmlnsprefix); + HDfree(t_objname); + goto done; + } else + found_obj->displayed = TRUE; + } } - HDfree(dtxid); - HDfree(parentxid); - HDfree(t_tmp); - HDfree(t_prefix); - HDfree(t_name); - HDfree(tmp); indent += COL; indentation(indent); @@ -5464,6 +5663,14 @@ xml_dump_named_datatype(hid_t type, const char *name) indent -= COL; indentation(indent); printf("\n",xmlnsprefix); + +done: + HDfree(dtxid); + HDfree(parentxid); + HDfree(t_tmp); + HDfree(t_prefix); + HDfree(t_name); + HDfree(tmp); } /*------------------------------------------------------------------------- @@ -5581,7 +5788,7 @@ xml_dump_group(hid_t gid, const char *name) indentation(indent + COL); ptrstr = malloc(100); - t_objname = xml_escape_the_name(found_obj->objname); + t_objname = xml_escape_the_name(found_obj->objname);/* point to the NDT by name */ par_name = xml_escape_the_name(par); xml_name_to_XID(found_obj->objname, ptrstr, 100, 1); xml_name_to_XID(par, parentxid, 100, 1); @@ -6704,32 +6911,87 @@ add_prefix(char **prfx, size_t *prfx_len, const char *name) * basis, attempting to dump as a dataset, as a group and as a named datatype * Error messages are supressed * + * Modifications: + * Neil Fortner + * 13 October 2008 + * Function basically rewritten. No longer directly opens the target file, + * now initializes a new set of tables for the external file. No longer + * dumps on a trial and error basis, but errors are still suppressed. + * *------------------------------------------------------------------------- */ -static int dump_extlink(const char *filename, const char *targname) +static int dump_extlink(hid_t group, const char *linkname, const char *objname) { - hid_t fid; + hid_t oid; + H5O_info_t oi; + table_t *old_group_table = group_table; + table_t *old_dset_table = dset_table; + table_t *old_type_table = type_table; + hbool_t old_hit_elink; + ssize_t idx; - fid = h5tools_fopen(filename, H5F_ACC_RDONLY, H5P_DEFAULT, driver, NULL, 0); + /* Open target object */ + if ((oid = H5Oopen(group, linkname, H5P_DEFAULT)) < 0) + goto fail; - if (fid < 0) - { + /* Get object info */ + if (H5Oget_info(oid, &oi) < 0) { + H5Oclose(oid); goto fail; } - /* add some indentation to distinguish that these objects are external */ - indent += 2*COL; + /* Check if we have visited this file already */ + if ((idx = table_list_visited(oi.fileno)) < 0) { + /* We have not visited this file, build object tables */ + if ((idx = table_list_add(oid, oi.fileno)) < 0) { + H5Oclose(oid); + goto fail; + } + } - handle_datasets(fid, targname, NULL, 0); - handle_groups(fid, targname, NULL, 0); - handle_datatypes(fid, targname, NULL, 0); + /* Do not recurse through an external link into the original file (idx=0) */ + if (idx) { + /* Update table pointers */ + group_table = table_list.tables[idx].group_table; + dset_table = table_list.tables[idx].dset_table; + type_table = table_list.tables[idx].type_table; - indent -= 2*COL; + /* We will now traverse the external link, set this global to indicate this */ + old_hit_elink = hit_elink; + hit_elink = TRUE; + /* add some indentation to distinguish that these objects are external */ + indent += 2*COL; - if (H5Fclose(fid) < 0) + /* Recurse into the external file */ + switch (oi.type) { + case H5O_TYPE_GROUP: + handle_groups(group, linkname, NULL, 0, objname); + break; + case H5O_TYPE_DATASET: + handle_datasets(group, linkname, NULL, 0, objname); + break; + case H5O_TYPE_NAMED_DATATYPE: + handle_datatypes(group, linkname, NULL, 0, objname); + break; + default: + d_status = EXIT_FAILURE; + } + + indent -= 2*COL; + + /* Reset table pointers */ + group_table = old_group_table; + dset_table = old_dset_table; + type_table = old_type_table; + + /* Reset hit_elink */ + hit_elink = old_hit_elink; + } /* end if */ + + if (H5Idec_ref(oid) < 0) d_status = EXIT_FAILURE; diff --git a/tools/h5dump/h5dumpgentest.c b/tools/h5dump/h5dumpgentest.c index bd3c4de..05efda8 100644 --- a/tools/h5dump/h5dumpgentest.c +++ b/tools/h5dump/h5dumpgentest.c @@ -90,6 +90,7 @@ #define FILE60 "tfpformat.h5" #define FILE61 "textlinksrc.h5" #define FILE62 "textlinktar.h5" +#define FILE63 "textlinkfar.h5" @@ -225,6 +226,7 @@ typedef struct s1_t { #define F42_DSETNAME "Dataset" #define F42_TYPENAME "Datatype" #define F42_ATTRNAME "Attribute" +#define F42_LINKNAME "Link_to_Datatype" /* "File 43" macros */ /* Name of dataset to create in datafile */ @@ -4417,6 +4419,10 @@ static void gent_named_dtype_attr(void) ret = H5Tcommit2(fid, F42_TYPENAME, tid, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); assert(ret >= 0); + /* Create a hard link to the datatype */ + ret = H5Lcreate_hard(fid, F42_TYPENAME, fid, F42_LINKNAME, H5P_DEFAULT, H5P_DEFAULT); + assert(ret >= 0); + /* Create a scalar dataspace used for all objects */ sid = H5Screate(H5S_SCALAR); assert(sid > 0); @@ -6179,27 +6185,28 @@ gent_fpformat(void) /*------------------------------------------------------------------------- * Function: gent_extlinks * - * Purpose: Generate 2 files to be used in the external links test - * External links point from one HDF5 file to an object (Group, Dataset, or - * committed Datatype) in another file. + * Purpose: Generate 3 files to be used in the external links test + * External links point from one HDF5 file to an object (Group, Dataset, + * or committed Datatype) in another file. Try to create cycles. * *------------------------------------------------------------------------- */ static void gent_extlinks(void) { - hid_t source_fid, target_fid, sid, did, gid, tid; + hid_t source_fid, target_fid, far_fid, sid, did, gid, gid2, tid; hsize_t dims[1] = {6}; int buf[6] = {1, 2, 3, 4, 5, 6}; /* create two files, a source and a target */ source_fid = H5Fcreate(FILE61, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); target_fid = H5Fcreate(FILE62, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + far_fid = H5Fcreate(FILE63, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); /*------------------------------------------------------------------------- - * create Groups, a Dataset, a committed Datatype, and external links in - * the target + * create Groups, a Dataset, a committed Datatype, external links, and a + * cycle in the target *------------------------------------------------------------------------- */ @@ -6210,8 +6217,13 @@ gent_extlinks(void) H5Dwrite(did, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, buf); H5Lcreate_external(FILE61, "/", gid, "elink_t1", H5P_DEFAULT, H5P_DEFAULT); H5Lcreate_external(FILE61, "/ext_link4", gid, "elink_t2", H5P_DEFAULT, H5P_DEFAULT); + + gid2 = H5Gcreate2(gid, "subgroup", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + H5Lcreate_hard(target_fid, "/group", gid2, "link_to_group", H5P_DEFAULT, H5P_DEFAULT); + H5Dclose(did); H5Sclose(sid); + H5Gclose(gid2); H5Gclose(gid); @@ -6236,9 +6248,16 @@ gent_extlinks(void) H5Lcreate_external(FILE62, "group/elink_t2", source_fid, "ext_link4", H5P_DEFAULT, H5P_DEFAULT); H5Lcreate_external(FILE62, "empty_group", source_fid, "ext_link5", H5P_DEFAULT, H5P_DEFAULT); +/*------------------------------------------------------------------------- + * create external link in the "far" file pointing to the source file + *------------------------------------------------------------------------- + */ + H5Lcreate_external(FILE61, "/", far_fid, "src_file", H5P_DEFAULT, H5P_DEFAULT); + /* close */ H5Fclose(source_fid); H5Fclose(target_fid); + H5Fclose(far_fid); } diff --git a/tools/h5dump/testh5dump.sh.in b/tools/h5dump/testh5dump.sh.in index 034c456..c1458a1 100644 --- a/tools/h5dump/testh5dump.sh.in +++ b/tools/h5dump/testh5dump.sh.in @@ -499,6 +499,10 @@ TOOLTEST torderattr4.ddl -H --sort_by=creation_order --sort_order=descending tor # tests for floating point user defined printf format TOOLTEST tfpformat.ddl -m %.7f tfpformat.h5 +# tests for traversal of external links +TOOLTEST textlinksrc.ddl textlinksrc.h5 +TOOLTEST textlinkfar.ddl textlinkfar.h5 + if test $nerrors -eq 0 ; then diff --git a/tools/h5ls/h5ls.c b/tools/h5ls/h5ls.c index c5ff96e..eec1fcd 100644 --- a/tools/h5ls/h5ls.c +++ b/tools/h5ls/h5ls.c @@ -1845,8 +1845,8 @@ elink_trav_visited(elink_trav_t *visited, const char *file, const char *path) /* Didn't find elink */ return(FALSE); } /* end elink_trav_visited() */ - + /*------------------------------------------------------------------------- * Function: list_lnk * diff --git a/tools/lib/h5tools_utils.c b/tools/lib/h5tools_utils.c index 0be3a91..a221465 100644 --- a/tools/lib/h5tools_utils.c +++ b/tools/lib/h5tools_utils.c @@ -485,21 +485,21 @@ find_objs_cb(const char *name, const H5O_info_t *oinfo, const char *already_seen break; case H5O_TYPE_NAMED_DATATYPE: - { - obj_t *found_obj; - - if((found_obj = search_obj(info->type_table, oinfo->addr)) == NULL) - add_obj(info->type_table, oinfo->addr, name, TRUE); - else { - /* Use latest version of name */ - HDfree(found_obj->objname); - found_obj->objname = HDstrdup(name); - - /* Mark named datatype as having valid name */ - found_obj->recorded = TRUE; - } /* end else */ + if(NULL == already_seen) { + obj_t *found_obj; + + if((found_obj = search_obj(info->type_table, oinfo->addr)) == NULL) + add_obj(info->type_table, oinfo->addr, name, TRUE); + else { + /* Use latest version of name */ + HDfree(found_obj->objname); + found_obj->objname = HDstrdup(name); + + /* Mark named datatype as having valid name */ + found_obj->recorded = TRUE; + } /* end else */ + } /* end if */ break; - } default: break; diff --git a/tools/testfiles/textlinkfar.ddl b/tools/testfiles/textlinkfar.ddl new file mode 100644 index 0000000..4151710 --- /dev/null +++ b/tools/testfiles/textlinkfar.ddl @@ -0,0 +1,69 @@ +############################# +Expected output for 'h5dump textlinkfar.h5' +############################# +HDF5 "textlinkfar.h5" { +GROUP "/" { + EXTERNAL_LINK "src_file" { + TARGETFILE "textlinksrc.h5" + TARGETPATH "/" + GROUP "/" { + EXTERNAL_LINK "ext_link1" { + TARGETFILE "textlinktar.h5" + TARGETPATH "group" + GROUP "group" { + DATASET "dset" { + DATATYPE H5T_STD_I32LE + DATASPACE SIMPLE { ( 6 ) / ( 6 ) } + DATA { + (0): 1, 2, 3, 4, 5, 6 + } + } + EXTERNAL_LINK "elink_t1" { + TARGETFILE "textlinksrc.h5" + TARGETPATH "/" + GROUP "/" { + HARDLINK "/" + } + } + EXTERNAL_LINK "elink_t2" { + TARGETFILE "textlinksrc.h5" + TARGETPATH "/ext_link4" + } + GROUP "subgroup" { + GROUP "link_to_group" { + HARDLINK "/group" + } + } + } + } + EXTERNAL_LINK "ext_link2" { + TARGETFILE "textlinktar.h5" + TARGETPATH "dset" + DATASET "dset" { + DATATYPE H5T_STD_I32LE + DATASPACE SIMPLE { ( 6 ) / ( 6 ) } + DATA { + (0): 1, 2, 3, 4, 5, 6 + } + } + } + EXTERNAL_LINK "ext_link3" { + TARGETFILE "textlinktar.h5" + TARGETPATH "type" + DATATYPE "type" H5T_STD_I32LE; + + } + EXTERNAL_LINK "ext_link4" { + TARGETFILE "textlinktar.h5" + TARGETPATH "group/elink_t2" + } + EXTERNAL_LINK "ext_link5" { + TARGETFILE "textlinktar.h5" + TARGETPATH "empty_group" + GROUP "empty_group" { + } + } + } + } +} +} diff --git a/tools/testfiles/textlinkfar.h5 b/tools/testfiles/textlinkfar.h5 new file mode 100644 index 0000000..6fb3130 Binary files /dev/null and b/tools/testfiles/textlinkfar.h5 differ diff --git a/tools/testfiles/textlinksrc-1.ls b/tools/testfiles/textlinksrc-1.ls index 3b0da0b..5e81dec 100644 --- a/tools/testfiles/textlinksrc-1.ls +++ b/tools/testfiles/textlinksrc-1.ls @@ -11,6 +11,8 @@ /ext_link1/elink_t1/ext_link4 External Link {textlinktar.h5//group/elink_t2} {**NOT FOUND**} /ext_link1/elink_t1/ext_link5 External Link {textlinktar.h5//empty_group} {Group} /ext_link1/elink_t2 External Link {textlinksrc.h5//ext_link4} {**NOT FOUND**} +/ext_link1/subgroup Group +/ext_link1/subgroup/link_to_group Group, same as /ext_link1 /ext_link2 External Link {textlinktar.h5//dset} {Already Visited} /ext_link3 External Link {textlinktar.h5//type} {Already Visited} /ext_link4 External Link {textlinktar.h5//group/elink_t2} {Already Visited} diff --git a/tools/testfiles/textlinksrc-3.ls b/tools/testfiles/textlinksrc-3.ls index dd9d1b1..a86ca32 100644 --- a/tools/testfiles/textlinksrc-3.ls +++ b/tools/testfiles/textlinksrc-3.ls @@ -10,3 +10,5 @@ ext_link1 External Link {textlinktar.h5//group} {Group} /elink_t1/ext_link4 External Link {textlinktar.h5//group/elink_t2} {**NOT FOUND**} /elink_t1/ext_link5 External Link {textlinktar.h5//empty_group} {Group} /elink_t2 External Link {textlinksrc.h5//ext_link4} {**NOT FOUND**} +/subgroup Group +/subgroup/link_to_group Group, same as /ext_link1 diff --git a/tools/testfiles/textlinksrc.ddl b/tools/testfiles/textlinksrc.ddl new file mode 100644 index 0000000..b806c56 --- /dev/null +++ b/tools/testfiles/textlinksrc.ddl @@ -0,0 +1,60 @@ +############################# +Expected output for 'h5dump textlinksrc.h5' +############################# +HDF5 "textlinksrc.h5" { +GROUP "/" { + EXTERNAL_LINK "ext_link1" { + TARGETFILE "textlinktar.h5" + TARGETPATH "group" + GROUP "group" { + DATASET "dset" { + DATATYPE H5T_STD_I32LE + DATASPACE SIMPLE { ( 6 ) / ( 6 ) } + DATA { + (0): 1, 2, 3, 4, 5, 6 + } + } + EXTERNAL_LINK "elink_t1" { + TARGETFILE "textlinksrc.h5" + TARGETPATH "/" + } + EXTERNAL_LINK "elink_t2" { + TARGETFILE "textlinksrc.h5" + TARGETPATH "/ext_link4" + } + GROUP "subgroup" { + GROUP "link_to_group" { + HARDLINK "/group" + } + } + } + } + EXTERNAL_LINK "ext_link2" { + TARGETFILE "textlinktar.h5" + TARGETPATH "dset" + DATASET "dset" { + DATATYPE H5T_STD_I32LE + DATASPACE SIMPLE { ( 6 ) / ( 6 ) } + DATA { + (0): 1, 2, 3, 4, 5, 6 + } + } + } + EXTERNAL_LINK "ext_link3" { + TARGETFILE "textlinktar.h5" + TARGETPATH "type" + DATATYPE "type" H5T_STD_I32LE; + + } + EXTERNAL_LINK "ext_link4" { + TARGETFILE "textlinktar.h5" + TARGETPATH "group/elink_t2" + } + EXTERNAL_LINK "ext_link5" { + TARGETFILE "textlinktar.h5" + TARGETPATH "empty_group" + GROUP "empty_group" { + } + } +} +} diff --git a/tools/testfiles/textlinktar.h5 b/tools/testfiles/textlinktar.h5 index bf009eb..fe33e10 100644 Binary files a/tools/testfiles/textlinktar.h5 and b/tools/testfiles/textlinktar.h5 differ diff --git a/tools/testfiles/thlink.h5.xml b/tools/testfiles/thlink.h5.xml index 72b7b31..c2737b9 100644 --- a/tools/testfiles/thlink.h5.xml +++ b/tools/testfiles/thlink.h5.xml @@ -31,11 +31,11 @@ Expected output for 'h5dump --xml thlink.h5' - + - + diff --git a/tools/testfiles/tmany.h5.xml b/tools/testfiles/tmany.h5.xml index 49efc51..93a0610 100644 --- a/tools/testfiles/tmany.h5.xml +++ b/tools/testfiles/tmany.h5.xml @@ -267,7 +267,7 @@ Expected output for 'h5dump --xml tmany.h5' - + @@ -313,7 +313,7 @@ Expected output for 'h5dump --xml tmany.h5' - + diff --git a/tools/testfiles/tnamed_dtype_attr.ddl b/tools/testfiles/tnamed_dtype_attr.ddl index 391abf8..4ef3158 100644 --- a/tools/testfiles/tnamed_dtype_attr.ddl +++ b/tools/testfiles/tnamed_dtype_attr.ddl @@ -17,7 +17,7 @@ GROUP "/" { } } } - DATATYPE "Datatype" H5T_STD_I32LE; + DATATYPE "Datatype" H5T_STD_I32LE; ATTRIBUTE "Attribute" { DATATYPE H5T_STD_I32LE DATASPACE SCALAR @@ -26,6 +26,8 @@ GROUP "/" { } } + DATATYPE "Link_to_Datatype" HARDLINK "/Datatype" + GROUP "g1" { ATTRIBUTE "Attribute" { DATATYPE "/Datatype" diff --git a/tools/testfiles/tnamed_dtype_attr.h5 b/tools/testfiles/tnamed_dtype_attr.h5 index 9be537c..e7bf23d 100644 Binary files a/tools/testfiles/tnamed_dtype_attr.h5 and b/tools/testfiles/tnamed_dtype_attr.h5 differ diff --git a/tools/testfiles/tnamed_dtype_attr.h5.xml b/tools/testfiles/tnamed_dtype_attr.h5.xml index 0b9ceae..2e3cfa3 100644 --- a/tools/testfiles/tnamed_dtype_attr.h5.xml +++ b/tools/testfiles/tnamed_dtype_attr.h5.xml @@ -4,7 +4,7 @@ Expected output for 'h5dump --xml tnamed_dtype_attr.h5' - + @@ -16,12 +16,12 @@ Expected output for 'h5dump --xml tnamed_dtype_attr.h5' - + - + 8 @@ -32,19 +32,22 @@ Expected output for 'h5dump --xml tnamed_dtype_attr.h5' - + - + + + + - + 8 diff --git a/tools/testfiles/torderattr1.ddl b/tools/testfiles/torderattr1.ddl index 3c4bd6b..de3b72b 100644 --- a/tools/testfiles/torderattr1.ddl +++ b/tools/testfiles/torderattr1.ddl @@ -75,7 +75,7 @@ GROUP "/" { DATASPACE SCALAR } } - DATATYPE "t" H5T_STD_I32LE; + DATATYPE "t" H5T_STD_I32LE; ATTRIBUTE "a" { DATATYPE H5T_STD_U8LE DATASPACE SCALAR @@ -89,7 +89,7 @@ GROUP "/" { DATASPACE SCALAR } - DATATYPE "tt" H5T_STD_I32LE; + DATATYPE "tt" H5T_STD_I32LE; ATTRIBUTE "a" { DATATYPE H5T_STD_U8LE DATASPACE SCALAR diff --git a/tools/testfiles/torderattr2.ddl b/tools/testfiles/torderattr2.ddl index 89799d3..3686984 100644 --- a/tools/testfiles/torderattr2.ddl +++ b/tools/testfiles/torderattr2.ddl @@ -15,7 +15,7 @@ GROUP "/" { DATATYPE H5T_STD_U8LE DATASPACE SCALAR } - DATATYPE "tt" H5T_STD_I32LE; + DATATYPE "tt" H5T_STD_I32LE; ATTRIBUTE "c" { DATATYPE H5T_STD_U8LE DATASPACE SCALAR @@ -29,7 +29,7 @@ GROUP "/" { DATASPACE SCALAR } - DATATYPE "t" H5T_STD_I32LE; + DATATYPE "t" H5T_STD_I32LE; ATTRIBUTE "c" { DATATYPE H5T_STD_U8LE DATASPACE SCALAR diff --git a/tools/testfiles/torderattr3.ddl b/tools/testfiles/torderattr3.ddl index 5dba83e..9dc027a 100644 --- a/tools/testfiles/torderattr3.ddl +++ b/tools/testfiles/torderattr3.ddl @@ -75,7 +75,7 @@ GROUP "/" { DATASPACE SCALAR } } - DATATYPE "t" H5T_STD_I32LE; + DATATYPE "t" H5T_STD_I32LE; ATTRIBUTE "a" { DATATYPE H5T_STD_U8LE DATASPACE SCALAR @@ -89,7 +89,7 @@ GROUP "/" { DATASPACE SCALAR } - DATATYPE "tt" H5T_STD_I32LE; + DATATYPE "tt" H5T_STD_I32LE; ATTRIBUTE "c" { DATATYPE H5T_STD_U8LE DATASPACE SCALAR diff --git a/tools/testfiles/torderattr4.ddl b/tools/testfiles/torderattr4.ddl index fc59f6a..38af25d 100644 --- a/tools/testfiles/torderattr4.ddl +++ b/tools/testfiles/torderattr4.ddl @@ -15,7 +15,7 @@ GROUP "/" { DATATYPE H5T_STD_U8LE DATASPACE SCALAR } - DATATYPE "tt" H5T_STD_I32LE; + DATATYPE "tt" H5T_STD_I32LE; ATTRIBUTE "a" { DATATYPE H5T_STD_U8LE DATASPACE SCALAR @@ -29,7 +29,7 @@ GROUP "/" { DATASPACE SCALAR } - DATATYPE "t" H5T_STD_I32LE; + DATATYPE "t" H5T_STD_I32LE; ATTRIBUTE "c" { DATATYPE H5T_STD_U8LE DATASPACE SCALAR diff --git a/tools/testfiles/tvlstr.ddl b/tools/testfiles/tvlstr.ddl index 3b67af6..eda8e000 100644 --- a/tools/testfiles/tvlstr.ddl +++ b/tools/testfiles/tvlstr.ddl @@ -24,7 +24,7 @@ GROUP "/" { (2): "", NULL } } - DATATYPE "vl_string_type" H5T_STRING { + DATATYPE "vl_string_type" H5T_STRING { STRSIZE H5T_VARIABLE; STRPAD H5T_STR_NULLPAD; CSET H5T_CSET_ASCII; diff --git a/windows/tools/h5dump/testh5dump.bat b/windows/tools/h5dump/testh5dump.bat index 0b75d06..6920df8 100644 --- a/windows/tools/h5dump/testh5dump.bat +++ b/windows/tools/h5dump/testh5dump.bat @@ -594,6 +594,10 @@ rem ############################################################################ rem Note: Make sure to use PERCENT rather than "%", because Windows needs rem to handle it specially. --SJW 5/12/08 call :tooltest tfpformat.ddl -m PERCENT.7f tfpformat.h5 + + rem tests for traversal of external links + call :tooltest textlinksrc.ddl textlinksrc.h5 + call :tooltest textlinkfar.ddl textlinkfar.h5 -- cgit v0.12