From afd94614e0e6b527df8899470b33d2f667bb531f Mon Sep 17 00:00:00 2001 From: Quincey Koziol Date: Sun, 25 Nov 2007 17:10:35 -0500 Subject: [svn-r14286] Description: Add H5Ovisit() and H5Ovisit_by_name() API routines. Tested on: FreeBSD/32 6.2 (duty) in debug mode FreeBSD/64 6.2 (liberty) w/C++ & FORTRAN, in debug mode Linux/32 2.6 (kagiso) w/PGI compilers, w/C++ & FORTRAN, w/threadsafe, in debug mode Linux/64-amd64 2.6 (smirom) w/default API=1.6.x, w/C++ & FORTRAN, in production mode Linux/64-ia64 2.6 (cobalt) w/Intel compilers, w/C++ & FORTRAN, in production mode Solaris/32 2.10 (linew) w/deprecated symbols disabled, w/C++ & FORTRAN, w/szip filter, in production mode Mac OS X/32 10.4.10 (amazon) in debug mode Linux/64-ia64 2.4 (tg-login3) w/parallel, w/FORTRAN, in production mode --- src/H5G.c | 4 +- src/H5Gpkg.h | 3 - src/H5Gprivate.h | 3 + src/H5O.c | 392 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- src/H5Opublic.h | 9 ++ test/links.c | 265 ++++++++++++++++++++++++++++++++++++- 6 files changed, 667 insertions(+), 9 deletions(-) diff --git a/src/H5G.c b/src/H5G.c index 675b166..0fa2c1c 100644 --- a/src/H5G.c +++ b/src/H5G.c @@ -135,7 +135,7 @@ H5FL_DEFINE(H5G_t); H5FL_DEFINE(H5G_shared_t); /* Declare the free list to manage H5_obj_t's */ -H5FL_DEFINE_STATIC(H5_obj_t); +H5FL_DEFINE(H5_obj_t); /* Private prototypes */ @@ -1933,7 +1933,7 @@ H5G_visit(hid_t loc_id, const char *group_name, H5_index_t idx_type, udata.path_buf_size = 1; udata.curr_path_len = 0; - /* Create skip list to store reference path information */ + /* Create skip list to store visited object information */ if((udata.visited = H5SL_create(H5SL_TYPE_OBJ, 0.5, (size_t)16)) == NULL) HGOTO_ERROR(H5E_SYM, H5E_CANTCREATE, FAIL, "can't create skip list for visited objects") diff --git a/src/H5Gpkg.h b/src/H5Gpkg.h index 2d936a9..b2cef28 100644 --- a/src/H5Gpkg.h +++ b/src/H5Gpkg.h @@ -342,9 +342,6 @@ H5_DLL H5G_t *H5G_open_name(const H5G_loc_t *loc, const char *name, H5_DLL herr_t H5G_iterate(hid_t loc_id, const char *group_name, H5_index_t idx_type, H5_iter_order_t order, hsize_t skip, hsize_t *last_lnk, const H5G_link_iterate_t *lnk_op, void *op_data, hid_t lapl_id, hid_t dxpl_id); -H5_DLL herr_t H5G_visit(hid_t loc_id, const char *group_name, - H5_index_t idx_type, H5_iter_order_t order, H5L_iterate_t op, void *op_data, - hid_t lapl_id, hid_t dxpl_id); /* * Group hierarchy traversal routines diff --git a/src/H5Gprivate.h b/src/H5Gprivate.h index 0ddb3e9..c54f11d 100644 --- a/src/H5Gprivate.h +++ b/src/H5Gprivate.h @@ -162,6 +162,9 @@ H5_DLL herr_t H5G_unmount(H5G_t *grp); #ifndef H5_NO_DEPRECATED_SYMBOLS H5_DLL H5G_obj_t H5G_map_obj_type(H5O_type_t obj_type); #endif /* H5_NO_DEPRECATED_SYMBOLS */ +H5_DLL herr_t H5G_visit(hid_t loc_id, const char *group_name, + H5_index_t idx_type, H5_iter_order_t order, H5L_iterate_t op, void *op_data, + hid_t lapl_id, hid_t dxpl_id); /* * These functions operate on symbol table nodes. diff --git a/src/H5O.c b/src/H5O.c index 67aa960..70b6efe 100644 --- a/src/H5O.c +++ b/src/H5O.c @@ -57,6 +57,17 @@ /* Local Typedefs */ /******************/ +/* User data for recursive traversal over objects from a group */ +typedef struct { + hid_t obj_id; /* The ID for the starting group */ + H5G_loc_t *start_loc; /* Location of starting group */ + hid_t lapl_id; /* LAPL for walking across links */ + hid_t dxpl_id; /* DXPL for operations */ + H5SL_t *visited; /* Skip list for tracking visited nodes */ + H5O_iterate_t op; /* Application callback */ + void *op_data; /* Application's op data */ +} H5O_iter_visit_ud_t; + /********************/ /* Package Typedefs */ @@ -70,6 +81,9 @@ static herr_t H5O_delete_oh(H5F_t *f, hid_t dxpl_id, H5O_t *oh); static const H5O_obj_class_t *H5O_obj_class(const H5O_loc_t *loc, hid_t dxpl_id); static herr_t H5O_obj_type_real(H5O_t *oh, H5O_type_t *obj_type); +static herr_t H5O_visit(hid_t loc_id, const char *obj_name, H5_index_t idx_type, + H5_iter_order_t order, H5O_iterate_t op, void *op_data, hid_t lapl_id, + hid_t dxpl_id); /*********************/ @@ -140,6 +154,9 @@ H5FL_BLK_DEFINE(chunk_image); /* Declare external the free list for time_t's */ H5FL_EXTERN(time_t); +/* Declare external the free list for H5_obj_t's */ +H5FL_EXTERN(H5_obj_t); + /*******************/ /* Local Variables */ @@ -827,6 +844,127 @@ done: /*------------------------------------------------------------------------- + * Function: H5Ovisit + * + * Purpose: Recursively visit an object and all the objects reachable + * from it. If the starting object is a group, all the objects + * linked to from that group will be visited. Links within + * each group are visited according to the order within the + * specified index (unless the specified index does not exist for + * a particular group, then the "name" index is used). + * + * NOTE: Soft links and user-defined links are ignored during + * this operation. + * + * NOTE: Each _object_ reachable from the initial group will only + * be visited once. If multiple hard links point to the same + * object, the first link to the object's path (according to the + * iteration index and iteration order given) will be used to in + * the callback about the object. + * + * Return: Success: The return value of the first operator that + * returns non-zero, or zero if all members were + * processed with no operator returning non-zero. + * + * Failure: Negative if something goes wrong within the + * library, or the negative value returned by one + * of the operators. + * + * Programmer: Quincey Koziol + * November 25 2007 + * + *------------------------------------------------------------------------- + */ +herr_t +H5Ovisit(hid_t obj_id, H5_index_t idx_type, H5_iter_order_t order, + H5O_iterate_t op, void *op_data) +{ + herr_t ret_value; /* Return value */ + + FUNC_ENTER_API(H5Ovisit, FAIL) + + /* Check args */ + if(idx_type <= H5_INDEX_UNKNOWN || idx_type >= H5_INDEX_N) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid index type specified") + if(order <= H5_ITER_UNKNOWN || order >= H5_ITER_N) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid iteration order specified") + if(!op) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no callback operator specified") + + /* Call internal object visitation routine */ + if((ret_value = H5O_visit(obj_id, ".", idx_type, order, op, op_data, H5P_LINK_ACCESS_DEFAULT, H5AC_ind_dxpl_id)) < 0) + HGOTO_ERROR(H5E_SYM, H5E_BADITER, FAIL, "object visitation failed") + +done: + FUNC_LEAVE_API(ret_value) +} /* end H5Ovisit() */ + + +/*------------------------------------------------------------------------- + * Function: H5Ovisit_by_name + * + * Purpose: Recursively visit an object and all the objects reachable + * from it. If the starting object is a group, all the objects + * linked to from that group will be visited. Links within + * each group are visited according to the order within the + * specified index (unless the specified index does not exist for + * a particular group, then the "name" index is used). + * + * NOTE: Soft links and user-defined links are ignored during + * this operation. + * + * NOTE: Each _object_ reachable from the initial group will only + * be visited once. If multiple hard links point to the same + * object, the first link to the object's path (according to the + * iteration index and iteration order given) will be used to in + * the callback about the object. + * + * Return: Success: The return value of the first operator that + * returns non-zero, or zero if all members were + * processed with no operator returning non-zero. + * + * Failure: Negative if something goes wrong within the + * library, or the negative value returned by one + * of the operators. + * + * Programmer: Quincey Koziol + * November 24 2007 + * + *------------------------------------------------------------------------- + */ +herr_t +H5Ovisit_by_name(hid_t loc_id, const char *obj_name, H5_index_t idx_type, + H5_iter_order_t order, H5O_iterate_t op, void *op_data, hid_t lapl_id) +{ + herr_t ret_value; /* Return value */ + + FUNC_ENTER_API(H5Ovisit_by_name, FAIL) + + /* Check args */ + if(!obj_name || !*obj_name) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no name") + if(idx_type <= H5_INDEX_UNKNOWN || idx_type >= H5_INDEX_N) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid index type specified") + if(order <= H5_ITER_UNKNOWN || order >= H5_ITER_N) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid iteration order specified") + if(!op) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no callback operator specified") + if(H5P_DEFAULT == lapl_id) + lapl_id = H5P_LINK_ACCESS_DEFAULT; + else + if(TRUE != H5P_isa_class(lapl_id, H5P_LINK_ACCESS)) + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not link access property list ID") + + /* Call internal object visitation routine */ + if((ret_value = H5O_visit(loc_id, obj_name, idx_type, order, op, op_data, lapl_id, H5AC_ind_dxpl_id)) < 0) + HGOTO_ERROR(H5E_SYM, H5E_BADITER, FAIL, "object visitation failed") + +done: + FUNC_LEAVE_API(ret_value) +} /* end H5Ovisit_by_name() */ + + +/*------------------------------------------------------------------------- * Function: H5Oclose * * Purpose: Close an open file object. @@ -1124,7 +1262,7 @@ H5O_open_name(H5G_loc_t *loc, const char *name, hid_t lapl_id) loc_found = TRUE; /* Open the object */ - if((ret_value = H5O_open_by_loc(&obj_loc, H5AC_dxpl_id)) < 0) + if((ret_value = H5O_open_by_loc(&obj_loc, H5AC_ind_dxpl_id)) < 0) HGOTO_ERROR(H5E_SYM, H5E_CANTOPENOBJ, FAIL, "unable to open object") done: @@ -2456,3 +2594,255 @@ done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5O_get_rc_and_type() */ + +/*------------------------------------------------------------------------- + * Function: H5O_free_visit_visited + * + * Purpose: Free the key for an object visited during a group traversal + * + * Return: Non-negative on success, negative on failure + * + * Programmer: Quincey Koziol + * Nov 25, 2007 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5O_free_visit_visited(void *item, void UNUSED *key, void UNUSED *operator_data/*in,out*/) +{ + FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5O_free_visit_visited) + + H5FL_FREE(H5_obj_t, item); + + FUNC_LEAVE_NOAPI(SUCCEED) +} /* end H5O_free_visit_visited() */ + + +/*------------------------------------------------------------------------- + * Function: H5O_visit_cb + * + * Purpose: Callback function for recursively visiting objects from a group + * + * Return: Success: Non-negative + * Failure: Negative + * + * Programmer: Quincey Koziol + * Nov 25, 2007 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5O_visit_cb(hid_t UNUSED group, const char *name, const H5L_info_t *linfo, + void *_udata) +{ + H5O_iter_visit_ud_t *udata = (H5O_iter_visit_ud_t *)_udata; /* User data for callback */ + H5G_loc_t obj_loc; /* Location of object */ + H5G_name_t obj_path; /* Object's group hier. path */ + H5O_loc_t obj_oloc; /* Object's object location */ + hbool_t obj_found = FALSE; /* Object at 'name' found */ + herr_t ret_value = H5_ITER_CONT; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT(H5O_visit_cb) + + /* Sanity check */ + HDassert(name); + HDassert(linfo); + HDassert(udata); + + /* Check if this is a hard link */ + if(linfo->type == H5L_TYPE_HARD) { + H5_obj_t obj_pos; /* Object "position" for this object */ + + /* Set up opened group location to fill in */ + obj_loc.oloc = &obj_oloc; + obj_loc.path = &obj_path; + H5G_loc_reset(&obj_loc); + + /* Find the object using the LAPL passed in */ + /* (Correctly handles mounted files) */ + if(H5G_loc_find(udata->start_loc, name, &obj_loc/*out*/, udata->lapl_id, udata->dxpl_id) < 0) + HGOTO_ERROR(H5E_OHDR, H5E_NOTFOUND, H5_ITER_ERROR, "object not found") + obj_found = TRUE; + + /* Construct unique "position" for this object */ + H5F_GET_FILENO(obj_oloc.file, obj_pos.fileno); + obj_pos.addr = obj_oloc.addr; + + /* Check if we've seen the object the link references before */ + if(NULL == H5SL_search(udata->visited, &obj_pos)) { + H5O_info_t oinfo; /* Object info */ + + /* Get the object's info */ + if(H5O_get_info(&obj_oloc, udata->dxpl_id, TRUE, &oinfo) < 0) + HGOTO_ERROR(H5E_OHDR, H5E_CANTGET, H5_ITER_ERROR, "unable to get object info") + + /* Make the application callback */ + ret_value = (udata->op)(udata->obj_id, name, &oinfo, udata->op_data); + + /* Check for continuing to visit objects */ + if(ret_value == H5_ITER_CONT) { + /* If its ref count is > 1, we add it to the list of visited objects */ + /* (because it could come up again during traversal) */ + if(oinfo.rc > 1) { + H5_obj_t *new_node; /* New object node for visited list */ + + /* Allocate new object "position" node */ + if((new_node = H5FL_MALLOC(H5_obj_t)) == NULL) + HGOTO_ERROR(H5E_OHDR, H5E_NOSPACE, H5_ITER_ERROR, "can't allocate object node") + + /* Set node information */ + *new_node = obj_pos; + + /* Add to list of visited objects */ + if(H5SL_insert(udata->visited, new_node, new_node) < 0) + HGOTO_ERROR(H5E_OHDR, H5E_CANTINSERT, H5_ITER_ERROR, "can't insert object node into visited list") + } /* end if */ + } /* end if */ + } /* end if */ + } /* end if */ + +done: + /* Release resources */ + if(obj_found && H5G_loc_free(&obj_loc) < 0) + HDONE_ERROR(H5E_OHDR, H5E_CANTRELEASE, H5_ITER_ERROR, "can't free location") + + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5O_visit_cb() */ + + +/*------------------------------------------------------------------------- + * Function: H5O_visit + * + * Purpose: Recursively visit an object and all the objects reachable + * from it. If the starting object is a group, all the objects + * linked to from that group will be visited. Links within + * each group are visited according to the order within the + * specified index (unless the specified index does not exist for + * a particular group, then the "name" index is used). + * + * NOTE: Soft links and user-defined links are ignored during + * this operation. + * + * NOTE: Each _object_ reachable from the initial group will only + * be visited once. If multiple hard links point to the same + * object, the first link to the object's path (according to the + * iteration index and iteration order given) will be used to in + * the callback about the object. + * + * Return: Success: The return value of the first operator that + * returns non-zero, or zero if all members were + * processed with no operator returning non-zero. + * + * Failure: Negative if something goes wrong within the + * library, or the negative value returned by one + * of the operators. + * + * Programmer: Quincey Koziol + * November 24 2007 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5O_visit(hid_t loc_id, const char *obj_name, H5_index_t idx_type, + H5_iter_order_t order, H5O_iterate_t op, void *op_data, hid_t lapl_id, + hid_t dxpl_id) +{ + H5O_iter_visit_ud_t udata; /* User data for callback */ + H5G_loc_t loc; /* Location of reference object */ + H5G_loc_t obj_loc; /* Location used to open object */ + H5G_name_t obj_path; /* Opened object group hier. path */ + H5O_loc_t obj_oloc; /* Opened object object location */ + hbool_t loc_found = FALSE; /* Entry at 'name' found */ + H5O_info_t oinfo; /* Object info struct */ + hid_t obj_id = (-1); /* ID of object */ + herr_t ret_value; /* Return value */ + + FUNC_ENTER_NOAPI(H5O_visit, FAIL) + + /* Portably initialize user data struct to zeros */ + HDmemset(&udata, 0, sizeof(udata)); + + /* Check args */ + if(H5G_loc(loc_id, &loc) < 0) + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a location") + + /* Set up opened group location to fill in */ + obj_loc.oloc = &obj_oloc; + obj_loc.path = &obj_path; + H5G_loc_reset(&obj_loc); + + /* Find the object's location */ + if(H5G_loc_find(&loc, obj_name, &obj_loc/*out*/, lapl_id, dxpl_id) < 0) + HGOTO_ERROR(H5E_OHDR, H5E_NOTFOUND, FAIL, "object not found") + loc_found = TRUE; + + /* Get the object's info */ + if(H5O_get_info(&obj_oloc, dxpl_id, TRUE, &oinfo) < 0) + HGOTO_ERROR(H5E_OHDR, H5E_CANTGET, FAIL, "unable to get object info") + + /* Open the object */ + /* (Takes ownership of the obj_loc information) */ + if((obj_id = H5O_open_by_loc(&obj_loc, dxpl_id)) < 0) + HGOTO_ERROR(H5E_OHDR, H5E_CANTOPENOBJ, FAIL, "unable to open object") + + /* Make callback for starting object */ + if((ret_value = op(obj_id, ".", &oinfo, op_data)) < 0) + HGOTO_ERROR(H5E_OHDR, H5E_BADITER, FAIL, "can't visit objects") + + /* Check for object being a group */ + if(oinfo.type == H5O_TYPE_GROUP) { + H5G_loc_t start_loc; /* Location of starting group */ + + /* Get the location of the starting group */ + if(H5G_loc(obj_id, &start_loc) < 0) + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a location") + + /* Set up user data for visiting links */ + udata.obj_id = obj_id; + udata.start_loc = &start_loc; + udata.lapl_id = lapl_id; + udata.dxpl_id = dxpl_id; + udata.op = op; + udata.op_data = op_data; + + /* Create skip list to store visited object information */ + if((udata.visited = H5SL_create(H5SL_TYPE_OBJ, 0.5, (size_t)16)) == NULL) + HGOTO_ERROR(H5E_OHDR, H5E_CANTCREATE, FAIL, "can't create skip list for visited objects") + + /* If its ref count is > 1, we add it to the list of visited objects */ + /* (because it could come up again during traversal) */ + if(oinfo.rc > 1) { + H5_obj_t *obj_pos; /* New object node for visited list */ + + /* Allocate new object "position" node */ + if((obj_pos = H5FL_MALLOC(H5_obj_t)) == NULL) + HGOTO_ERROR(H5E_OHDR, H5E_NOSPACE, FAIL, "can't allocate object node") + + /* Construct unique "position" for this object */ + obj_pos->fileno = oinfo.fileno; + obj_pos->addr = oinfo.addr; + + /* Add to list of visited objects */ + if(H5SL_insert(udata.visited, obj_pos, obj_pos) < 0) + HGOTO_ERROR(H5E_OHDR, H5E_CANTINSERT, FAIL, "can't insert object node into visited list") + } /* end if */ + + /* Call internal group visitation routine */ + if((ret_value = H5G_visit(obj_id, ".", idx_type, order, H5O_visit_cb, &udata, lapl_id, dxpl_id)) < 0) + HGOTO_ERROR(H5E_OHDR, H5E_BADITER, FAIL, "object visitation failed") + } /* end if */ + +done: + if(obj_id > 0) { + if(H5I_dec_ref(obj_id) < 0) + HDONE_ERROR(H5E_OHDR, H5E_CANTRELEASE, FAIL, "unable to close object") + } /* end if */ + else if(loc_found && H5G_loc_free(&obj_loc) < 0) + HDONE_ERROR(H5E_OHDR, H5E_CANTRELEASE, FAIL, "can't free location") + if(udata.visited) + H5SL_destroy(udata.visited, H5O_free_visit_visited, NULL); + + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5O_visit() */ + + diff --git a/src/H5Opublic.h b/src/H5Opublic.h index 6ddd565..64fdd07 100644 --- a/src/H5Opublic.h +++ b/src/H5Opublic.h @@ -124,6 +124,10 @@ typedef struct H5O_info_t { /* Typedef for message creation indexes */ typedef uint32_t H5O_msg_crt_idx_t; +/* Prototype for H5Ovisit/H5Ovisit_by_name() operator */ +typedef herr_t (*H5O_iterate_t)(hid_t obj, const char *name, const H5O_info_t *info, + void *op_data); + /********************/ /* Public Variables */ @@ -159,6 +163,11 @@ H5_DLL herr_t H5Oset_comment_by_name(hid_t loc_id, const char *name, H5_DLL ssize_t H5Oget_comment(hid_t obj_id, char *comment, size_t bufsize); H5_DLL ssize_t H5Oget_comment_by_name(hid_t loc_id, const char *name, char *comment, size_t bufsize, hid_t lapl_id); +H5_DLL herr_t H5Ovisit(hid_t obj_id, H5_index_t idx_type, H5_iter_order_t order, + H5O_iterate_t op, void *op_data); +H5_DLL herr_t H5Ovisit_by_name(hid_t loc_id, const char *obj_name, + H5_index_t idx_type, H5_iter_order_t order, H5O_iterate_t op, + void *op_data, hid_t lapl_id); H5_DLL herr_t H5Oclose(hid_t object_id); /* Symbols defined for compatibility with previous versions of the HDF5 API. diff --git a/test/links.c b/test/links.c index 8208b2c..cef354d 100644 --- a/test/links.c +++ b/test/links.c @@ -165,12 +165,90 @@ static const link_visit_t lvisit2[] = { {"hard_zero/soft_two", 1} }; - typedef struct { - unsigned idx; /* Index in visit structure */ - const link_visit_t *info; /* Pointer to the visit structure to use */ + unsigned idx; /* Index in link visit structure */ + const link_visit_t *info; /* Pointer to the link visit structure to use */ } lvisit_ud_t; + +/* Object visit structs */ +typedef struct { + const char *path; /* Path to object */ + H5O_type_t type; /* Type of object */ +} obj_visit_t; +static const obj_visit_t ovisit0_old[] = { + {".", 0}, + {"Dataset_zero", 1}, + {"Group1", 0}, + {"Group1/Dataset_one", 1}, + {"Group1/Group2", 0}, + {"Group1/Group2/Dataset_two", 1}, + {"Group1/Group2/Type_two", 2}, + {"Group1/Type_one", 2}, + {"Type_zero", 2} +}; +static const obj_visit_t ovisit0_new[] = { + {".", 0}, + {"Dataset_zero", 1}, + {"Group1", 0}, + {"Group1/Dataset_one", 1}, + {"Group1/Group2", 0}, + {"Group1/Group2/Dataset_two", 1}, + {"Group1/Group2/Type_two", 2}, + {"Group1/Type_one", 2}, + {"Type_zero", 2} +}; +static const obj_visit_t ovisit1_old[] = { + {".", 0}, + {"Dataset_one", 1}, + {"Group2", 0}, + {"Group2/Dataset_two", 1}, + {"Group2/Type_two", 2}, + {"Group2/hard_zero", 0}, + {"Group2/hard_zero/Dataset_zero", 1}, + {"Group2/hard_zero/Type_zero", 2}, + {"Type_one", 2} +}; +static const obj_visit_t ovisit1_new[] = { + {".", 0}, + {"Dataset_one", 1}, + {"Group2", 0}, + {"Group2/Dataset_two", 1}, + {"Group2/Type_two", 2}, + {"Group2/hard_zero", 0}, + {"Group2/hard_zero/Dataset_zero", 1}, + {"Group2/hard_zero/Type_zero", 2}, + {"Type_one", 2} +}; +static const obj_visit_t ovisit2_old[] = { + {".", 0}, + {"Dataset_two", 1}, + {"Type_two", 2}, + {"hard_zero", 0}, + {"hard_zero/Dataset_zero", 1}, + {"hard_zero/Group1", 0}, + {"hard_zero/Group1/Dataset_one", 1}, + {"hard_zero/Group1/Type_one", 2}, + {"hard_zero/Type_zero", 2} +}; +static const obj_visit_t ovisit2_new[] = { + {".", 0}, + {"Dataset_two", 1}, + {"Type_two", 2}, + {"hard_zero", 0}, + {"hard_zero/Dataset_zero", 1}, + {"hard_zero/Group1", 0}, + {"hard_zero/Group1/Dataset_one", 1}, + {"hard_zero/Group1/Type_one", 2}, + {"hard_zero/Type_zero", 2} +}; + +typedef struct { + unsigned idx; /* Index in object visit structure */ + const obj_visit_t *info; /* Pointer to the object visit structure to use */ +} ovisit_ud_t; + + /*------------------------------------------------------------------------- * Function: mklinks @@ -5530,6 +5608,185 @@ error: /*------------------------------------------------------------------------- + * Function: visit_obj_cb + * + * Purpose: Callback routine for visiting objects in a file + * + * Return: Success: 0 + * Failure: -1 + * + * Programmer: Quincey Koziol + * Sunday, November 25, 2007 + * + *------------------------------------------------------------------------- + */ +static int +visit_obj_cb(hid_t UNUSED group_id, const char *name, const H5O_info_t *oinfo, + void *_op_data) +{ + ovisit_ud_t *op_data = (ovisit_ud_t *)_op_data; + + /* Check for correct object information */ + if(HDstrcmp(op_data->info[op_data->idx].path, name)) return(H5_ITER_ERROR); + if(op_data->info[op_data->idx].type != oinfo->type) return(H5_ITER_ERROR); + + /* Advance to next location in expected output */ + op_data->idx++; + + return(H5_ITER_CONT); +} /* end visit_link_cb() */ + + +/*------------------------------------------------------------------------- + * Function: obj_visit + * + * Purpose: Test the object visiting routine + * + * Return: Success: 0 + * Failure: -1 + * + * Programmer: Quincey Koziol + * Sunday, November 25, 2007 + * + *------------------------------------------------------------------------- + */ +static int +obj_visit(hid_t fapl, hbool_t new_format) +{ + ovisit_ud_t udata; /* User-data for visiting */ + hid_t fid = -1; + hid_t gid = -1; /* Group ID */ + + if(new_format) + TESTING("object visiting (w/new group format)") + else + TESTING("object visiting") + + /* Construct "interesting" file to visit */ + if((fid = build_visit_file(fapl)) < 0) TEST_ERROR + + /* Visit all the objects reachable from the root group (with file ID) */ + udata.idx = 0; + udata.info = new_format ? ovisit0_new : ovisit0_old; + if(H5Ovisit(fid, H5_INDEX_NAME, H5_ITER_INC, visit_obj_cb, &udata) < 0) FAIL_STACK_ERROR + + /* Visit all the objects reachable from the root group (with group ID) */ + if((gid = H5Gopen2(fid, "/", H5P_DEFAULT)) < 0) FAIL_STACK_ERROR + udata.idx = 0; + udata.info = new_format ? ovisit0_new : ovisit0_old; + if(H5Ovisit(gid, H5_INDEX_NAME, H5_ITER_INC, visit_obj_cb, &udata) < 0) FAIL_STACK_ERROR + if(H5Gclose(gid) < 0) FAIL_STACK_ERROR + + + /* Visit all the objects reachable from each internal group */ + if((gid = H5Gopen2(fid, "/Group1", H5P_DEFAULT)) < 0) FAIL_STACK_ERROR + udata.idx = 0; + udata.info = new_format ? ovisit1_new : ovisit1_old; + if(H5Ovisit(gid, H5_INDEX_NAME, H5_ITER_INC, visit_obj_cb, &udata) < 0) FAIL_STACK_ERROR + if(H5Gclose(gid) < 0) FAIL_STACK_ERROR + + if((gid = H5Gopen2(fid, "/Group1/Group2", H5P_DEFAULT)) < 0) FAIL_STACK_ERROR + udata.idx = 0; + udata.info = new_format ? ovisit2_new : ovisit2_old; + if(H5Ovisit(gid, H5_INDEX_NAME, H5_ITER_INC, visit_obj_cb, &udata) < 0) FAIL_STACK_ERROR + if(H5Gclose(gid) < 0) FAIL_STACK_ERROR + + + /* Close file created */ + if(H5Fclose(fid) < 0) TEST_ERROR + + PASSED(); + return 0; + +error: + H5E_BEGIN_TRY { + H5Fclose(gid); + H5Fclose(fid); + } H5E_END_TRY; + return -1; +} /* end obj_visit() */ + + +/*------------------------------------------------------------------------- + * Function: obj_visit_by_name + * + * Purpose: Test the object visiting "by name" routine + * + * Return: Success: 0 + * Failure: -1 + * + * Programmer: Quincey Koziol + * Sunday, November 25, 2007 + * + *------------------------------------------------------------------------- + */ +static int +obj_visit_by_name(hid_t fapl, hbool_t new_format) +{ + ovisit_ud_t udata; /* User-data for visiting */ + hid_t fid = -1; + hid_t gid = -1; /* Group ID */ + + if(new_format) + TESTING("object visiting by name (w/new group format)") + else + TESTING("object visiting by name") + + /* Construct "interesting" file to visit */ + if((fid = build_visit_file(fapl)) < 0) TEST_ERROR + + /* Visit all the objects reachable from the root group (with file ID) */ + udata.idx = 0; + udata.info = new_format ? ovisit0_new : ovisit0_old; + if(H5Ovisit_by_name(fid, "/", H5_INDEX_NAME, H5_ITER_INC, visit_obj_cb, &udata, H5P_DEFAULT) < 0) FAIL_STACK_ERROR + + /* Visit all the objects reachable from the root group (with group ID) */ + if((gid = H5Gopen2(fid, "/", H5P_DEFAULT)) < 0) FAIL_STACK_ERROR + udata.idx = 0; + udata.info = new_format ? ovisit0_new : ovisit0_old; + if(H5Ovisit_by_name(gid, ".", H5_INDEX_NAME, H5_ITER_INC, visit_obj_cb, &udata, H5P_DEFAULT) < 0) FAIL_STACK_ERROR + if(H5Gclose(gid) < 0) FAIL_STACK_ERROR + + + /* Visit all the objects reachable from each internal group */ + udata.idx = 0; + udata.info = new_format ? ovisit1_new : ovisit1_old; + if(H5Ovisit_by_name(fid, "/Group1", H5_INDEX_NAME, H5_ITER_INC, visit_obj_cb, &udata, H5P_DEFAULT) < 0) FAIL_STACK_ERROR + + if((gid = H5Gopen2(fid, "/Group1", H5P_DEFAULT)) < 0) FAIL_STACK_ERROR + udata.idx = 0; + udata.info = new_format ? ovisit1_new : ovisit1_old; + if(H5Ovisit_by_name(gid, ".", H5_INDEX_NAME, H5_ITER_INC, visit_obj_cb, &udata, H5P_DEFAULT) < 0) FAIL_STACK_ERROR + if(H5Gclose(gid) < 0) FAIL_STACK_ERROR + + + udata.idx = 0; + udata.info = new_format ? ovisit2_new : ovisit2_old; + if(H5Ovisit_by_name(fid, "/Group1/Group2", H5_INDEX_NAME, H5_ITER_INC, visit_obj_cb, &udata, H5P_DEFAULT) < 0) FAIL_STACK_ERROR + + if((gid = H5Gopen2(fid, "/Group1/Group2", H5P_DEFAULT)) < 0) FAIL_STACK_ERROR + udata.idx = 0; + udata.info = new_format ? ovisit2_new : ovisit2_old; + if(H5Ovisit_by_name(gid, ".", H5_INDEX_NAME, H5_ITER_INC, visit_obj_cb, &udata, H5P_DEFAULT) < 0) FAIL_STACK_ERROR + if(H5Gclose(gid) < 0) FAIL_STACK_ERROR + + + /* Close file created */ + if(H5Fclose(fid) < 0) TEST_ERROR + + PASSED(); + return 0; + +error: + H5E_BEGIN_TRY { + H5Fclose(gid); + H5Fclose(fid); + } H5E_END_TRY; + return -1; +} /* end obj_visit_by_name() */ + + +/*------------------------------------------------------------------------- * Function: corder_create_empty * * Purpose: Create an empty group with creation order indices @@ -10023,6 +10280,8 @@ main(void) /* Misc. extra tests, useful for both new & old format files */ nerrors += link_visit(my_fapl, new_format) < 0 ? 1 : 0; nerrors += link_visit_by_name(my_fapl, new_format) < 0 ? 1 : 0; + nerrors += obj_visit(my_fapl, new_format) < 0 ? 1 : 0; + nerrors += obj_visit_by_name(my_fapl, new_format) < 0 ? 1 : 0; /* Keep this test last, it's testing files that are used above */ nerrors += check_all_closed(my_fapl, new_format) < 0 ? 1 : 0; -- cgit v0.12