summaryrefslogtreecommitdiff
path: root/src/H5Gtraverse.c
diff options
context:
space:
mode:
authorTae-Young Chung <ty83.chung@samsung.com>2018-03-13 17:04:17 +0900
committerTae-Young Chung <ty83.chung@samsung.com>2018-03-13 17:06:54 +0900
commit45032639c6c5ee11b79d2d3faaca6e9be6e4be3b (patch)
tree1d636d696c1f1ea6d79fb469758c465f27a3d37c /src/H5Gtraverse.c
parent125c0b85df1bf388ae210fc7a87872984f865769 (diff)
downloadhdf5-45032639c6c5ee11b79d2d3faaca6e9be6e4be3b.tar.gz
hdf5-45032639c6c5ee11b79d2d3faaca6e9be6e4be3b.tar.bz2
hdf5-45032639c6c5ee11b79d2d3faaca6e9be6e4be3b.zip
Import upstream hdf5-1.10.1HEADupstream/1.10.1upstreammaster
Upstream repository is https://support.hdfgroup.org/ftp/HDF5/releases/hdf5-1.10/hdf5-1.10.1/src/ Change-Id: I4ec4c291940b7bb75722ea16813fbe55736374a6 Signed-off-by: Tae-Young Chung <ty83.chung@samsung.com>
Diffstat (limited to 'src/H5Gtraverse.c')
-rw-r--r--src/H5Gtraverse.c875
1 files changed, 875 insertions, 0 deletions
diff --git a/src/H5Gtraverse.c b/src/H5Gtraverse.c
new file mode 100644
index 0000000..ff1206e
--- /dev/null
+++ b/src/H5Gtraverse.c
@@ -0,0 +1,875 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5Gtraverse.c
+ * Sep 13 2005
+ * Quincey Koziol <koziol@ncsa.uiuc.edu>
+ *
+ * Purpose: Functions for traversing group hierarchy
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5Gmodule.h" /* This source code file is part of the H5G module */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Dprivate.h" /* Datasets */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5Fprivate.h" /* File access */
+#include "H5Gpkg.h" /* Groups */
+#include "H5HLprivate.h" /* Local Heaps */
+#include "H5Iprivate.h" /* IDs */
+#include "H5Lprivate.h" /* Links */
+#include "H5MMprivate.h" /* Memory management */
+#include "H5Ppublic.h" /* Property Lists */
+#include "H5WBprivate.h" /* Wrapped Buffers */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+/* User data for path traversal routine */
+typedef struct {
+ /* down */
+ hbool_t chk_exists; /* Flag to indicate we are checking if object exists */
+
+ /* up */
+ H5G_loc_t *obj_loc; /* Object location */
+ hbool_t exists; /* Indicate if object exists */
+} H5G_trav_slink_t;
+
+
+/********************/
+/* Package Typedefs */
+/********************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+static herr_t H5G_traverse_slink_cb(H5G_loc_t *grp_loc, const char *name,
+ const H5O_link_t *lnk, H5G_loc_t *obj_loc, void *_udata/*in,out*/,
+ H5G_own_loc_t *own_loc/*out*/);
+static herr_t H5G_traverse_ud(const H5G_loc_t *grp_loc, const H5O_link_t *lnk,
+ H5G_loc_t *obj_loc/*in,out*/, unsigned target, size_t *nlinks/*in,out*/,
+ hbool_t *obj_exists, hid_t lapl_id, hid_t dxpl_id);
+static herr_t H5G_traverse_slink(const H5G_loc_t *grp_loc, const H5O_link_t *lnk,
+ H5G_loc_t *obj_loc/*in,out*/, unsigned target, size_t *nlinks/*in,out*/,
+ hbool_t *obj_exists, hid_t lapl_id, hid_t dxpl_id);
+static herr_t H5G_traverse_real(const H5G_loc_t *loc, const char *name,
+ unsigned target, size_t *nlinks, H5G_traverse_t op, void *op_data,
+ hid_t lapl_id, hid_t dxpl_id);
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G_traverse_slink_cb
+ *
+ * Purpose: Callback for soft link traversal. This routine sets the
+ * correct information for the object location.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, September 13, 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5G_traverse_slink_cb(H5G_loc_t H5_ATTR_UNUSED *grp_loc, const char H5_ATTR_UNUSED *name,
+ const H5O_link_t H5_ATTR_UNUSED *lnk, H5G_loc_t *obj_loc, void *_udata/*in,out*/,
+ H5G_own_loc_t *own_loc/*out*/)
+{
+ H5G_trav_slink_t *udata = (H5G_trav_slink_t *)_udata; /* User data passed in */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Check for dangling soft link */
+ if(obj_loc == NULL) {
+ if(udata->chk_exists)
+ udata->exists = FALSE;
+ else
+ HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "component not found")
+ } /* end if */
+ else {
+ /* Copy new location information for resolved object */
+ H5O_loc_copy(udata->obj_loc->oloc, obj_loc->oloc, H5_COPY_DEEP);
+
+ /* Indicate that the object exists */
+ udata->exists = TRUE;
+ } /* end else */
+
+done:
+ /* Indicate that this callback didn't take ownership of the group *
+ * location for the object */
+ *own_loc = H5G_OWN_NONE;
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5G_traverse_slink_cb() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G_traverse_link_ud
+ *
+ * Purpose: Callback for user-defined link traversal. Sets up a
+ * location ID and passes it to the user traversal callback.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, September 13, 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5G_traverse_ud(const H5G_loc_t *grp_loc/*in,out*/, const H5O_link_t *lnk,
+ H5G_loc_t *obj_loc/*in,out*/, unsigned target, size_t *nlinks/*in,out*/,
+ hbool_t *obj_exists, hid_t _lapl_id, hid_t dxpl_id)
+{
+ const H5L_class_t *link_class; /* User-defined link class */
+ hid_t cb_return = -1; /* The ID the user-defined callback returned */
+ H5G_loc_t grp_loc_copy;
+ H5G_name_t grp_path_copy;
+ H5O_loc_t grp_oloc_copy;
+ H5G_loc_t new_loc; /* Group location for newly opened external object */
+ H5G_t *grp;
+ hid_t lapl_id = (-1); /* LAPL local to this routine */
+ H5P_genplist_t *lapl; /* LAPL with nlinks set */
+ hid_t cur_grp = (-1);
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Sanity check */
+ HDassert(grp_loc);
+ HDassert(lnk);
+ HDassert(lnk->type >= H5L_TYPE_UD_MIN);
+ HDassert(obj_loc);
+ HDassert(nlinks);
+ HDassert(_lapl_id >= 0);
+
+ /* Get the link class for this type of link. */
+ if(NULL == (link_class = H5L_find_class(lnk->type)))
+ HGOTO_ERROR(H5E_SYM, H5E_NOTREGISTERED, FAIL, "unable to get UD link class")
+
+ /* Set up location for user-defined callback. Use a copy of our current
+ * grp_loc. */
+ grp_loc_copy.path = &grp_path_copy;
+ grp_loc_copy.oloc = &grp_oloc_copy;
+ H5G_loc_reset(&grp_loc_copy);
+ if(H5G_loc_copy(&grp_loc_copy, grp_loc, H5_COPY_DEEP) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTCOPY, FAIL, "unable to copy object location")
+
+ /* Create a group ID to pass to the user-defined callback */
+ if(NULL == (grp = H5G_open(&grp_loc_copy, dxpl_id)))
+ HGOTO_ERROR(H5E_SYM, H5E_CANTOPENOBJ, FAIL, "unable to open group")
+ if((cur_grp = H5I_register(H5I_GROUP, grp, FALSE)) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTREGISTER, FAIL, "unable to register group")
+
+ /* Check for generic default property list and use link access default if so */
+ if(_lapl_id == H5P_DEFAULT) {
+ HDassert(H5P_LINK_ACCESS_DEFAULT != -1);
+ if(NULL == (lapl = (H5P_genplist_t *)H5I_object(H5P_LINK_ACCESS_DEFAULT)))
+ HGOTO_ERROR(H5E_SYM, H5E_BADATOM, FAIL, "unable to get default property list")
+ } /* end if */
+ else {
+ /* Get the underlying property list passed in */
+ if(NULL == (lapl = (H5P_genplist_t *)H5I_object(_lapl_id)))
+ HGOTO_ERROR(H5E_SYM, H5E_BADATOM, FAIL, "unable to get property list from ID")
+ } /* end else */
+
+ /* Copy the property list passed in */
+ if((lapl_id = H5P_copy_plist(lapl, FALSE)) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTCOPY, FAIL, "unable to copy property list")
+
+ /* Get the underlying property list copy */
+ if(NULL == (lapl = (H5P_genplist_t *)H5I_object(lapl_id)))
+ HGOTO_ERROR(H5E_SYM, H5E_BADATOM, FAIL, "unable to get property list from ID")
+
+ /* Record number of soft links left to traverse in the property list. */
+ if(H5P_set(lapl, H5L_ACS_NLINKS_NAME, nlinks) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTSET, FAIL, "can't set nlink info")
+
+ /* User-defined callback function */
+ cb_return = (link_class->trav_func)(lnk->name, cur_grp, lnk->u.ud.udata, lnk->u.ud.size, lapl_id);
+
+ /* Check for failing to locate the object */
+ if(cb_return < 0) {
+ /* Check if we just needed to know if the object exists */
+ if(target & H5G_TARGET_EXISTS) {
+ /* Clear any errors from the stack */
+ H5E_clear_stack(NULL);
+
+ /* Indicate that the object doesn't exist */
+ *obj_exists = FALSE;
+
+ /* Get out now */
+ HGOTO_DONE(SUCCEED);
+ } /* end if */
+ /* else, we really needed to open the object */
+ else
+ HGOTO_ERROR(H5E_SYM, H5E_BADATOM, FAIL, "traversal callback returned invalid ID")
+ } /* end if */
+
+ /* Get the object location information from the ID the user callback returned */
+ if(H5G_loc(cb_return, &new_loc) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_BADVALUE, FAIL, "unable to get object location from ID")
+
+ /* Release any previous location information for the object */
+ H5G_loc_free(obj_loc);
+
+ /* Copy new object's location information */
+ H5G_loc_copy(obj_loc, &new_loc, H5_COPY_DEEP);
+
+ /* Hold the file open until we free this object header (otherwise the
+ * object location will be invalidated when the file closes).
+ */
+ if(H5O_loc_hold_file(obj_loc->oloc) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTOPENOBJ, FAIL, "unable to hold file open")
+
+ /* We have a copy of the location and we're holding the file open.
+ * Close the open ID the user passed back.
+ */
+ if(H5I_dec_ref(cb_return) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTRELEASE, FAIL, "unable to close atom from UD callback")
+ cb_return = (hid_t)(-1);
+
+done:
+ /* Close location given to callback. */
+ if(cur_grp > 0 && H5I_dec_ref(cur_grp) < 0)
+ HDONE_ERROR(H5E_SYM, H5E_CANTRELEASE, FAIL, "unable to close atom for current location")
+
+ if(ret_value < 0 && cb_return > 0 && H5I_dec_ref(cb_return) < 0)
+ HDONE_ERROR(H5E_SYM, H5E_CANTRELEASE, FAIL, "unable to close atom from UD callback")
+
+ /* Close the LAPL, if we copied one */
+ if(lapl_id > 0 && H5I_dec_ref(lapl_id) < 0)
+ HDONE_ERROR(H5E_SYM, H5E_CANTRELEASE, FAIL, "unable to close copied link access property list")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5G_traverse_ud() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G_traverse_slink
+ *
+ * Purpose: Traverses symbolic link. The link head appears in the group
+ * whose entry is GRP_LOC and the link tail entry is OBJ_LOC.
+ *
+ * Return: Success: Non-negative, OBJ_LOC will contain information
+ * about the object to which the link points
+ *
+ * Failure: Negative
+ *
+ * Programmer: Robb Matzke
+ * Friday, April 10, 1998
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5G_traverse_slink(const H5G_loc_t *grp_loc, const H5O_link_t *lnk,
+ H5G_loc_t *obj_loc/*in,out*/, unsigned target, size_t *nlinks/*in,out*/,
+ hbool_t *obj_exists, hid_t lapl_id, hid_t dxpl_id)
+{
+ H5G_trav_slink_t udata; /* User data to pass to link traversal callback */
+ H5G_name_t tmp_obj_path; /* Temporary copy of object's path */
+ hbool_t tmp_obj_path_set = FALSE; /* Flag to indicate that tmp object path is initialized */
+ H5O_loc_t tmp_grp_oloc; /* Temporary copy of group entry */
+ H5G_name_t tmp_grp_path; /* Temporary copy of group's path */
+ H5G_loc_t tmp_grp_loc; /* Temporary copy of group's location */
+ hbool_t tmp_grp_loc_set = FALSE; /* Flag to indicate that tmp group location is initialized */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Sanity check */
+ HDassert(grp_loc);
+ HDassert(lnk);
+ HDassert(lnk->type == H5L_TYPE_SOFT);
+ HDassert(nlinks);
+
+ /* Set up temporary location */
+ tmp_grp_loc.oloc = &tmp_grp_oloc;
+ tmp_grp_loc.path = &tmp_grp_path;
+
+ /* Portably initialize the temporary objects */
+ H5G_loc_reset(&tmp_grp_loc);
+ H5G_name_reset(&tmp_obj_path);
+
+ /* Clone the group location, so we can track the names properly */
+ /* ("tracking the names properly" means to ignore the effects of the
+ * link traversal on the object's & group's paths - QAK)
+ */
+ H5G_loc_copy(&tmp_grp_loc, grp_loc, H5_COPY_DEEP);
+ tmp_grp_loc_set = TRUE;
+
+ /* Hold the object's group hier. path to restore later */
+ /* (Part of "tracking the names properly") */
+ H5G_name_copy(&tmp_obj_path, obj_loc->path, H5_COPY_SHALLOW);
+ tmp_obj_path_set = TRUE;
+
+ /* Set up user data for traversal callback */
+ udata.chk_exists = (target & H5G_TARGET_EXISTS) ? TRUE : FALSE;
+ udata.exists = FALSE;
+ udata.obj_loc = obj_loc;
+
+ /* Traverse the link */
+ if(H5G_traverse_real(&tmp_grp_loc, lnk->u.soft.name, target, nlinks, H5G_traverse_slink_cb, &udata, lapl_id, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "unable to follow symbolic link")
+
+ /* Pass back information about whether the object exists */
+ *obj_exists = udata.exists;
+
+done:
+ /* Restore object's group hier. path */
+ if(tmp_obj_path_set) {
+ H5G_name_free(obj_loc->path);
+ H5G_name_copy(obj_loc->path, &tmp_obj_path, H5_COPY_SHALLOW);
+ } /* end if */
+
+ /* Release cloned copy of group location */
+ if(tmp_grp_loc_set)
+ H5G_loc_free(&tmp_grp_loc);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5G_traverse_slink() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G__traverse_special
+ *
+ * Purpose: Handle traversing special link situations
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Nov 20 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5G__traverse_special(const H5G_loc_t *grp_loc, const H5O_link_t *lnk,
+ unsigned target, size_t *nlinks, hbool_t last_comp,
+ H5G_loc_t *obj_loc, hbool_t *obj_exists, hid_t lapl_id, hid_t dxpl_id)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* Sanity check */
+ HDassert(grp_loc);
+ HDassert(lnk);
+ HDassert(obj_loc);
+ HDassert(nlinks);
+
+ /*
+ * If we found a symbolic link then we should follow it. But if this
+ * is the last component of the name and the H5G_TARGET_SLINK bit of
+ * TARGET is set then we don't follow it.
+ */
+ if(H5L_TYPE_SOFT == lnk->type &&
+ (0 == (target & H5G_TARGET_SLINK) || !last_comp)) {
+ if((*nlinks)-- <= 0)
+ HGOTO_ERROR(H5E_LINK, H5E_NLINKS, FAIL, "too many links")
+ if(H5G_traverse_slink(grp_loc, lnk, obj_loc, (target & H5G_TARGET_EXISTS), nlinks, obj_exists, lapl_id, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_LINK, H5E_TRAVERSE, FAIL, "symbolic link traversal failed")
+ } /* end if */
+
+ /*
+ * If we found a user-defined link then we should follow it. But if this
+ * is the last component of the name and the H5G_TARGET_UDLINK bit of
+ * TARGET is set then we don't follow it.
+ */
+ if(lnk->type >= H5L_TYPE_UD_MIN &&
+ (0 == (target & H5G_TARGET_UDLINK) || !last_comp) ) {
+ if((*nlinks)-- <= 0)
+ HGOTO_ERROR(H5E_LINK, H5E_NLINKS, FAIL, "too many links")
+ if(H5G_traverse_ud(grp_loc, lnk, obj_loc, (target & H5G_TARGET_EXISTS), nlinks, obj_exists, lapl_id, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_LINK, H5E_TRAVERSE, FAIL, "user-defined link traversal failed")
+ } /* end if */
+
+ /*
+ * Resolve mount points to the mounted group. Do not do this step if
+ * the H5G_TARGET_MOUNT bit of TARGET is set and this is the last
+ * component of the name.
+ *
+ * (If this link is a hard link, try to perform mount point traversal)
+ *
+ * (Note that the soft and external link traversal above can change
+ * the status of the object (into a hard link), so don't use an 'else'
+ * statement here. -QAK)
+ */
+ if(H5F_addr_defined(obj_loc->oloc->addr) &&
+ (0 == (target & H5G_TARGET_MOUNT) || !last_comp)) {
+ if(H5F_traverse_mount(obj_loc->oloc/*in,out*/) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "mount point traversal failed")
+ } /* end if */
+
+ /* If the grp_loc is the only thing holding an external file open
+ * and obj_loc is in the same file, obj_loc should also hold the
+ * file open so that closing the grp_loc doesn't close the file.
+ */
+ if(grp_loc->oloc->holding_file && grp_loc->oloc->file == obj_loc->oloc->file)
+ if(H5O_loc_hold_file(obj_loc->oloc) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTOPENOBJ, FAIL, "unable to hold file open")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5G__traverse_special() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G_traverse_real
+ *
+ * Purpose: Internal version of path traversal routine
+ *
+ * Return: Success: Non-negative if name can be fully resolved.
+ *
+ * Failure: Negative if the name could not be fully
+ * resolved.
+ *
+ * Programmer: Robb Matzke
+ * matzke@llnl.gov
+ * Aug 11 1997
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5G_traverse_real(const H5G_loc_t *_loc, const char *name, unsigned target,
+ size_t *nlinks, H5G_traverse_t op, void *op_data, hid_t lapl_id, hid_t dxpl_id)
+{
+ H5G_loc_t loc; /* Location of start object */
+ H5O_loc_t grp_oloc; /* Object loc. for current group */
+ H5G_name_t grp_path; /* Path for current group */
+ H5G_loc_t grp_loc; /* Location of group */
+ H5O_loc_t obj_oloc; /* Object found */
+ H5G_name_t obj_path; /* Path for object found */
+ H5G_loc_t obj_loc; /* Location of object */
+ size_t nchars; /* component name length */
+ H5O_link_t lnk; /* Link information for object */
+ hbool_t link_valid = FALSE; /* Flag to indicate that the link information is valid */
+ hbool_t obj_loc_valid = FALSE; /* Flag to indicate that the object location is valid */
+ H5G_own_loc_t own_loc = H5G_OWN_NONE; /* Enum to indicate whether callback took ownership of locations*/
+ hbool_t group_copy = FALSE; /* Flag to indicate that the group entry is copied */
+ char comp_buf[1024]; /* Temporary buffer for path components */
+ char *comp; /* Pointer to buffer for path components */
+ H5WB_t *wb = NULL; /* Wrapped buffer for temporary buffer */
+ hbool_t last_comp = FALSE; /* Flag to indicate that a component is the last component in the name */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Check parameters */
+ HDassert(_loc);
+ HDassert(name);
+ HDassert(nlinks);
+ HDassert(op);
+
+ /*
+ * Where does the searching start? For absolute names it starts at the
+ * root of the file; for relative names it starts at CWG.
+ */
+ /* Check if we need to get the root group's entry */
+ if('/' == *name) {
+ H5G_t *root_grp; /* Temporary pointer to root group of file */
+
+ /* Look up root group for starting location */
+ root_grp = H5G_rootof(_loc->oloc->file);
+ HDassert(root_grp);
+
+ /* Set the location entry to the root group's info */
+ loc.oloc = &(root_grp->oloc);
+ loc.path = &(root_grp->path);
+ } /* end if */
+ else {
+ loc.oloc = _loc->oloc;
+ loc.path = _loc->path;
+ } /* end else */
+
+ /* Set up group & object locations */
+ grp_loc.oloc = &grp_oloc;
+ grp_loc.path = &grp_path;
+ obj_loc.oloc = &obj_oloc;
+ obj_loc.path = &obj_path;
+
+#if defined(H5_USING_MEMCHECKER) || !defined(NDEBUG)
+ /* Clear group location */
+ if(H5G_loc_reset(&grp_loc) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTOPENOBJ, FAIL, "unable to reset location")
+#endif /* H5_USING_MEMCHECKER */
+
+ /* Deep copy of the starting location to group location */
+ if(H5G_loc_copy(&grp_loc, &loc, H5_COPY_DEEP) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTOPENOBJ, FAIL, "unable to copy location")
+ group_copy = TRUE;
+
+ /* Clear object location */
+ if(H5G_loc_reset(&obj_loc) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTOPENOBJ, FAIL, "unable to reset location")
+
+ /* Wrap the local buffer for serialized header info */
+ if(NULL == (wb = H5WB_wrap(comp_buf, sizeof(comp_buf))))
+ HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "can't wrap buffer")
+
+ /* Get a pointer to a buffer that's large enough */
+ if(NULL == (comp = (char *)H5WB_actual(wb, (HDstrlen(name) + 1))))
+ HGOTO_ERROR(H5E_SYM, H5E_NOSPACE, FAIL, "can't get actual buffer")
+
+ /* Traverse the path */
+ while((name = H5G__component(name, &nchars)) && *name) {
+ const char *s; /* Temporary string pointer */
+ htri_t lookup_status; /* Status from object lookup */
+ hbool_t obj_exists; /* Whether the object exists */
+
+ /*
+ * Copy the component name into a null-terminated buffer so
+ * we can pass it down to the other symbol table functions.
+ */
+ HDmemcpy(comp, name, nchars);
+ comp[nchars] = '\0';
+
+ /*
+ * The special name `.' is a no-op.
+ */
+ if('.' == comp[0] && !comp[1]) {
+ name += nchars;
+ continue;
+ } /* end if */
+
+ /* Check if this is the last component of the name */
+ if(!((s = H5G__component(name + nchars, NULL)) && *s))
+ last_comp = TRUE;
+
+ /* If there's valid information in the link, reset it */
+ if(link_valid) {
+ H5O_msg_reset(H5O_LINK_ID, &lnk);
+ link_valid = FALSE;
+ } /* end if */
+
+ /* Get information for object in current group */
+ if((lookup_status = H5G__obj_lookup(grp_loc.oloc, comp, &lnk/*out*/, dxpl_id)) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "can't look up component")
+ obj_exists = FALSE;
+
+ /* If the lookup was OK, build object location and traverse special links, etc. */
+ if(lookup_status) {
+ /* Sanity check link and indicate it's valid */
+ HDassert(lnk.type >= H5L_TYPE_HARD);
+ HDassert(!HDstrcmp(comp, lnk.name));
+ link_valid = TRUE;
+
+ /* Build object location from the link */
+ if(H5G__link_to_loc(&grp_loc, &lnk, &obj_loc) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "cannot initialize object location")
+ obj_loc_valid = TRUE;
+
+ /* Assume object exists */
+ obj_exists = TRUE;
+
+ /* Perform any special traversals that the link needs */
+ /* (soft links, user-defined links, file mounting, etc.) */
+ if(H5G__traverse_special(&grp_loc, &lnk, target, nlinks, last_comp, &obj_loc, &obj_exists, lapl_id, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_LINK, H5E_TRAVERSE, FAIL, "special link traversal failed")
+ } /* end if */
+
+ /* Check for last component in name provided */
+ if(last_comp) {
+ H5O_link_t *cb_lnk; /* Pointer to link info for callback */
+ H5G_loc_t *cb_loc; /* Pointer to object location for callback */
+
+ /* Set callback parameters appropriately, based on link being found */
+ if(lookup_status) {
+ cb_lnk = &lnk;
+ if(obj_exists)
+ cb_loc = &obj_loc;
+ else
+ cb_loc = NULL;
+ } /* end if */
+ else {
+ HDassert(!obj_loc_valid);
+ cb_lnk = NULL;
+ cb_loc = NULL;
+ } /* end else */
+
+ /* Call 'operator' routine */
+ if((op)(&grp_loc, comp, cb_lnk, cb_loc, op_data, &own_loc) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CALLBACK, FAIL, "traversal operator failed")
+
+ HGOTO_DONE(SUCCEED)
+ } /* end if */
+
+ /* Handle lookup failures now */
+ if(!lookup_status) {
+ /* If an intermediate group doesn't exist & flag is set, create the group */
+ if(target & H5G_CRT_INTMD_GROUP) {
+ const H5O_ginfo_t def_ginfo = H5G_CRT_GROUP_INFO_DEF; /* Default group info settings */
+ const H5O_linfo_t def_linfo = H5G_CRT_LINK_INFO_DEF; /* Default link info settings */
+ const H5O_pline_t def_pline = H5O_CRT_PIPELINE_DEF; /* Default filter pipeline settings */
+ H5O_ginfo_t par_ginfo; /* Group info settings for parent group */
+ H5O_linfo_t par_linfo; /* Link info settings for parent group */
+ H5O_pline_t par_pline; /* Filter pipeline settings for parent group */
+ H5O_linfo_t tmp_linfo; /* Temporary link info settings */
+ htri_t exists; /* Whether a group or link info message exists */
+ const H5O_ginfo_t *ginfo; /* Group info settings for new group */
+ const H5O_linfo_t *linfo; /* Link info settings for new group */
+ const H5O_pline_t *pline; /* Filter pipeline settings for new group */
+ H5G_obj_create_t gcrt_info; /* Group creation info */
+
+ /* Check for the parent group having a group info message */
+ /* (OK if not found) */
+ if((exists = H5O_msg_exists(grp_loc.oloc, H5O_GINFO_ID, dxpl_id)) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTGET, FAIL, "unable to read object header")
+ if(exists) {
+ /* Get the group info for parent group */
+ if(NULL == H5O_msg_read(grp_loc.oloc, H5O_GINFO_ID, &par_ginfo, dxpl_id))
+ HGOTO_ERROR(H5E_SYM, H5E_CANTGET, FAIL, "group info message not present")
+
+ /* Use parent group info settings */
+ ginfo = &par_ginfo;
+ } /* end if */
+ else
+ /* Use default group info settings */
+ ginfo = &def_ginfo;
+
+ /* Check for the parent group having a link info message */
+ /* (OK if not found) */
+ /* Get the link info for parent group */
+ if((exists = H5G__obj_get_linfo(grp_loc.oloc, &par_linfo, dxpl_id)) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTGET, FAIL, "unable to read object header")
+ if(exists) {
+ /* Only keep the creation order information from the parent
+ * group's link info
+ */
+ HDmemcpy(&tmp_linfo, &def_linfo, sizeof(H5O_linfo_t));
+ tmp_linfo.track_corder = par_linfo.track_corder;
+ tmp_linfo.index_corder = par_linfo.index_corder;
+ linfo = &tmp_linfo;
+ } /* end if */
+ else
+ /* Use default link info settings */
+ linfo = &def_linfo;
+
+ /* Check for the parent group having a filter pipeline message */
+ /* (OK if not found) */
+ if((exists = H5O_msg_exists(grp_loc.oloc, H5O_PLINE_ID, dxpl_id)) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTGET, FAIL, "unable to read object header")
+ if(exists) {
+ /* Get the filter pipeline for parent group */
+ if(NULL == H5O_msg_read(grp_loc.oloc, H5O_PLINE_ID, &par_pline, dxpl_id))
+ HGOTO_ERROR(H5E_SYM, H5E_CANTGET, FAIL, "filter pipeline message not present")
+
+ /* Use parent filter pipeline settings */
+ pline = &par_pline;
+ } /* end if */
+ else
+ /* Use default filter pipeline settings */
+ pline = &def_pline;
+
+ /* Create the intermediate group */
+/* XXX: Should we allow user to control the group creation params here? -QAK */
+ gcrt_info.gcpl_id = H5P_GROUP_CREATE_DEFAULT;
+ gcrt_info.cache_type = H5G_NOTHING_CACHED;
+ HDmemset(&gcrt_info.cache, 0, sizeof(gcrt_info.cache));
+ if(H5G__obj_create_real(grp_oloc.file, dxpl_id, ginfo, linfo, pline, &gcrt_info, obj_loc.oloc/*out*/) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "unable to create group entry")
+
+ /* Insert new group into current group's symbol table */
+ if(H5G__loc_insert(&grp_loc, comp, &obj_loc, H5O_TYPE_GROUP, &gcrt_info, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTINSERT, FAIL, "unable to insert intermediate group")
+
+ /* Decrement refcount on intermediate group's object header in memory */
+ if(H5O_dec_rc_by_loc(obj_loc.oloc, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTDEC, FAIL, "unable to decrement refcount on newly created object")
+
+ /* Close new group */
+ if(H5O_close(obj_loc.oloc, NULL) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "unable to close")
+
+ /* If the parent group was holding the file open, the
+ * newly-created group should, as well.
+ */
+ if(grp_loc.oloc->holding_file)
+ if(H5O_loc_hold_file(obj_loc.oloc) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTOPENOBJ, FAIL, "unable to hold file open")
+
+ /* Reset any non-default object header messages */
+ if(ginfo != &def_ginfo)
+ /* (Casting away const OK - QAK) */
+ if(H5O_msg_reset(H5O_GINFO_ID, (void *)ginfo) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTRELEASE, FAIL, "unable to reset group info message")
+ if(linfo != &def_linfo)
+ /* (Casting away const OK - QAK) */
+ if(H5O_msg_reset(H5O_LINFO_ID, (void *)linfo) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTRELEASE, FAIL, "unable to reset link info message")
+ if(pline != &def_pline)
+ /* (Casting away const OK - QAK) */
+ if(H5O_msg_reset(H5O_PLINE_ID, (void *)pline) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTRELEASE, FAIL, "unable to reset I/O pipeline message")
+ } /* end if */
+ else
+ HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "component not found")
+ } /* end if */
+
+ /*
+ * Advance to the next component of the path.
+ */
+
+ /* Transfer "ownership" of the object's information to the group object */
+ H5G_loc_free(&grp_loc);
+ H5G_loc_copy(&grp_loc, &obj_loc, H5_COPY_SHALLOW);
+ H5G_loc_reset(&obj_loc);
+ obj_loc_valid = FALSE;
+
+ /* Advance to next component in string */
+ name += nchars;
+ } /* end while */
+
+ /* Call 'operator' routine */
+ /* If we've fallen through to here, the name must be something like just '.'
+ * and we should issue the callback on that. -QAK
+ * Since we don't have a group location or a link to the object we pass in
+ * NULL.
+ */
+ HDassert(group_copy);
+ if((op)(NULL, ".", NULL, &grp_loc, op_data, &own_loc) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTNEXT, FAIL, "traversal operator failed")
+
+ /* If the callback took ownership of the object location, it actually has
+ * ownership of grp_loc. It shouldn't have tried to take ownership of
+ * the "group location", which was NULL. */
+ HDassert(!(own_loc & H5G_OWN_GRP_LOC));
+ if(own_loc & H5G_OWN_OBJ_LOC)
+ own_loc |= H5G_OWN_GRP_LOC;
+
+done:
+ /* If there's been an error, the callback doesn't really get ownership of
+ * any location and we should close them both */
+ if(ret_value < 0)
+ own_loc = H5G_OWN_NONE;
+
+ /* Free all open locations. This also closes any open external files. */
+ if(obj_loc_valid && !(own_loc & H5G_OWN_OBJ_LOC))
+ H5G_loc_free(&obj_loc);
+ if(group_copy && !(own_loc & H5G_OWN_GRP_LOC))
+ H5G_loc_free(&grp_loc);
+
+ /* If there's valid information in the link, reset it */
+ if(link_valid)
+ if(H5O_msg_reset(H5O_LINK_ID, &lnk) < 0)
+ HDONE_ERROR(H5E_SYM, H5E_CANTRELEASE, FAIL, "unable to reset link message")
+
+ /* Release temporary component buffer */
+ if(wb && H5WB_unwrap(wb) < 0)
+ HDONE_ERROR(H5E_SYM, H5E_CANTRELEASE, FAIL, "can't release wrapped buffer")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5G_traverse_real() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G_traverse
+ *
+ * Purpose: Traverse a path from a location & perform an operation when
+ * the last component of the name is reached.
+ *
+ * Return: Success: Non-negative if path can be fully traversed.
+ * Failure: Negative if the path could not be fully
+ * traversed.
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Sep 13 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5G_traverse(const H5G_loc_t *loc, const char *name, unsigned target, H5G_traverse_t op,
+ void *op_data, hid_t lapl_id, hid_t dxpl_id)
+{
+ size_t nlinks; /* Link countdown value */
+ H5P_genplist_t *lapl; /* Property list with value for nlinks */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Check args */
+ if(!name || !*name)
+ HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "no name given")
+ if(!loc)
+ HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "no starting location")
+ if(!op)
+ HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "no operation provided")
+ HDassert(lapl_id >= 0);
+
+ /* Set nlinks value from property list, if it exists */
+ if(lapl_id == H5P_DEFAULT)
+ nlinks = H5L_NUM_LINKS;
+ else {
+ if(NULL == (lapl = (H5P_genplist_t *)H5I_object(lapl_id)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+ if(H5P_get(lapl, H5L_ACS_NLINKS_NAME, &nlinks) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get number of links")
+ } /* end else */
+
+ /* Set up invalid tag. This is a precautionary step only. Setting an invalid
+ tag here will ensure that no metadata accessed while doing the traversal
+ is given an improper tag, unless another one is specifically set up
+ first. This will ensure we're not accidentally tagging something we
+ shouldn't be during the traversal. Note that for best tagging assertion
+ coverage, setting H5C_DO_TAGGING_SANITY_CHECKS is advised. */
+ H5_BEGIN_TAG(dxpl_id, H5AC__INVALID_TAG, FAIL);
+
+ /* Go perform "real" traversal */
+ if(H5G_traverse_real(loc, name, target, &nlinks, op, op_data, lapl_id, dxpl_id) < 0)
+ HGOTO_ERROR_TAG(H5E_SYM, H5E_NOTFOUND, FAIL, "internal path traversal failed")
+
+ /* Reset tag after traversal */
+ H5_END_TAG(FAIL);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5G_traverse() */
+