summaryrefslogtreecommitdiffstats
path: root/src/H5Gobj.c
diff options
context:
space:
mode:
authorQuincey Koziol <koziol@hdfgroup.org>2005-11-15 02:55:39 (GMT)
committerQuincey Koziol <koziol@hdfgroup.org>2005-11-15 02:55:39 (GMT)
commita1708eb023f2c8f8ac6c2c17bf1e598c8dff956e (patch)
tree34c87a3753b36c4c8d689d58bf456eaf261cd235 /src/H5Gobj.c
parentbea1e576c5ef5500678f7ce913d835341b625e8f (diff)
downloadhdf5-a1708eb023f2c8f8ac6c2c17bf1e598c8dff956e.zip
hdf5-a1708eb023f2c8f8ac6c2c17bf1e598c8dff956e.tar.gz
hdf5-a1708eb023f2c8f8ac6c2c17bf1e598c8dff956e.tar.bz2
[svn-r11712] Purpose:
New feature Description: Check in baseline for compact group revisions, which radically revises the source code for managing groups and object headers. WARNING!!!! WARNING!!!! WARNING!!!! WARNING!!!! WARNING!!!! WARNING!!!! WARNING!!!! WARNING!!!! WARNING!!!! WARNING!!!! WARNING!!!! WARNING!!!! This initiates the "unstable" phase of the 1.7.x branch, leading up to the 1.8.0 release. Please test this code, but do _NOT_ keep files created with it - the format will change again before the release and you will not be able to read your old files!!! WARNING!!!! WARNING!!!! WARNING!!!! WARNING!!!! WARNING!!!! WARNING!!!! WARNING!!!! WARNING!!!! WARNING!!!! WARNING!!!! WARNING!!!! WARNING!!!! Solution: There's too many changes to really describe them all, but some of them include: - Stop abusing the H5G_entry_t structure and split it into two separate structures for non-symbol table node use within the library: H5O_loc_t for object locations in a file and H5G_name_t to store the path to an opened object. H5G_entry_t is now only used for storing symbol table entries on disk. - Retire H5G_namei() in favor of a more general mechanism for traversing group paths and issuing callbacks on objects located. This gets us out of the business of hacking H5G_namei() for new features, generally. - Revised H5O* routines to take a H5O_loc_t instead of H5G_entry_t - Lots more... Platforms tested: h5committested and maybe another dozen configurations.... :-)
Diffstat (limited to 'src/H5Gobj.c')
-rw-r--r--src/H5Gobj.c884
1 files changed, 884 insertions, 0 deletions
diff --git a/src/H5Gobj.c b/src/H5Gobj.c
new file mode 100644
index 0000000..a178e93
--- /dev/null
+++ b/src/H5Gobj.c
@@ -0,0 +1,884 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * 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 files COPYING and Copyright.html. COPYING can be found at the root *
+ * of the source code distribution tree; Copyright.html can be found at the *
+ * root level of an installed copy of the electronic HDF5 document set and *
+ * is linked from the top-level documents page. It can also be found at *
+ * http://hdf.ncsa.uiuc.edu/HDF5/doc/Copyright.html. If you do not have *
+ * access to either file, you may request a copy from hdfhelp@ncsa.uiuc.edu. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5Gobj.c
+ * Sep 5 2005
+ * Quincey Koziol <koziol@ncsa.uiuc.edu>
+ *
+ * Purpose: Functions for abstract handling of objects in groups.
+ *
+ *-------------------------------------------------------------------------
+ */
+#define H5F_PACKAGE /*suppress error about including H5Fpkg */
+#define H5G_PACKAGE /*suppress error about including H5Gpkg */
+
+
+/* Packages needed by this file... */
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5Fpkg.h" /* File access */
+#include "H5Gpkg.h" /* Groups */
+#include "H5HLprivate.h" /* Local Heaps */
+#include "H5Iprivate.h" /* IDs */
+#include "H5MMprivate.h" /* Memory management */
+
+/* Private typedefs */
+
+/* User data for converting link messages to symbol table */
+typedef struct {
+ H5F_t *f; /* Pointer to file for insertion */
+ haddr_t btree_addr; /* Address of symbol table B-tree */
+ haddr_t heap_addr; /* Address of symbol table local heap */
+ hid_t dxpl_id; /* DXPL during insertion */
+} H5G_obj_ud1_t;
+
+/* User data for looking up an object in a group */
+typedef struct {
+ H5O_loc_t *oloc; /* Object location to set */
+} H5G_obj_ud2_t;
+
+/* Private macros */
+
+/* PRIVATE PROTOTYPES */
+static herr_t
+H5G_obj_link_to_stab_cb(const void *_mesg, unsigned idx, void *_udata);
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G_obj_create
+ *
+ * Purpose: Create an object header for a group and update object location info
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Sep 29 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5G_obj_create(H5F_t *f, hid_t dxpl_id, H5O_ginfo_t *ginfo, H5O_loc_t *oloc/*out*/)
+{
+ H5O_linfo_t linfo; /* Link information */
+ H5O_link_t lnk; /* Temporary link message info for computing message size */
+ char null_char = '\0'; /* Character for creating null string */
+ size_t ginfo_size; /* Size of the group info message */
+ size_t linfo_size; /* Size of the link info message */
+ size_t link_size; /* Size of a link message */
+ size_t hdr_size; /* Size of object header to request */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(H5G_obj_create, FAIL)
+
+ /*
+ * Check arguments.
+ */
+ HDassert(f);
+ HDassert(ginfo);
+ HDassert(oloc);
+
+ /* Initialize message information */
+ linfo.nlinks = 0;
+
+ /* Calculate message size infomation, for creating group's object header */
+ linfo_size = H5O_mesg_size(H5O_LINFO_ID, f, &linfo);
+ HDassert(linfo_size);
+
+ ginfo_size = H5O_mesg_size(H5O_GINFO_ID, f, ginfo);
+ HDassert(ginfo_size);
+
+ lnk.type = H5G_LINK_HARD;
+ lnk.name = &null_char;
+ link_size = H5O_mesg_size(H5O_LINK_ID, f, &lnk);
+ HDassert(link_size);
+
+ /* Compute size of header to use for creation */
+ hdr_size = linfo_size +
+ ginfo_size +
+ (ginfo->est_num_entries * (link_size + ginfo->est_name_len));
+
+ /*
+ * Create symbol table object header. It has a zero link count
+ * since nothing refers to it yet. The link count will be
+ * incremented if the object is added to the group directed graph.
+ */
+ if(H5O_create(f, dxpl_id, hdr_size, oloc/*out*/) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "can't create header")
+
+ /* Insert link info message */
+ if(H5O_modify(oloc, H5O_LINFO_ID, H5O_NEW_MESG, 0, 0, &linfo, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "can't create message")
+
+ /* Insert group info message */
+ if(H5O_modify(oloc, H5O_GINFO_ID, H5O_NEW_MESG, H5O_FLAG_CONSTANT, H5O_UPDATE_TIME, ginfo, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "can't create message")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5G_obj_create() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G_obj_ent_decode
+ *
+ * Purpose: Decodes a symbol table entry into a object location
+ *
+ * Return: Success: Non-negative with *pp pointing to the first byte
+ * following the symbol table entry.
+ *
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Sep 26 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5G_obj_ent_decode(H5F_t *f, const uint8_t **pp, H5O_loc_t *oloc)
+{
+ const uint8_t *p_ret = *pp;
+
+ FUNC_ENTER_NOAPI_NOFUNC(H5G_obj_ent_decode)
+
+ /* check arguments */
+ HDassert(f);
+ HDassert(pp);
+ HDassert(oloc);
+
+ /* Set file pointer for root object location */
+ oloc->file = f;
+
+ /* decode header */
+ *pp += H5F_SIZEOF_SIZE(f); /* Skip over local heap address */
+ H5F_addr_decode(f, pp, &(oloc->addr));
+ *pp += 4; /* Skip over "cache type" */
+ *pp += 4; /* Reserved */
+
+ /* Set decode pointer */
+ *pp = p_ret + H5G_SIZEOF_ENTRY(f);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5G_obj_ent_decode() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G_obj_ent_encode
+ *
+ * Purpose: Encodes the specified object location into a symbol table
+ * entry in the buffer pointed to by *pp.
+ *
+ * Return: Success: Non-negative, with *pp pointing to the first byte
+ * after the symbol table entry.
+ *
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Sep 26 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5G_obj_ent_encode(H5F_t *f, uint8_t **pp, const H5O_loc_t *oloc)
+{
+ uint8_t *p_ret = *pp + H5G_SIZEOF_ENTRY(f);
+
+ FUNC_ENTER_NOAPI_NOFUNC(H5G_obj_ent_encode)
+
+ /* check arguments */
+ HDassert(f);
+ HDassert(pp);
+
+ /* encode header */
+ H5F_ENCODE_LENGTH(f, *pp, 0); /* No name for root group */
+ if(oloc)
+ H5F_addr_encode(f, pp, oloc->addr);
+ else
+ H5F_addr_encode(f, pp, HADDR_UNDEF);
+ UINT32ENCODE(*pp, H5G_NOTHING_CACHED);
+ UINT32ENCODE(*pp, 0); /*reserved*/
+
+ /* fill with zero */
+ while(*pp < p_ret)
+ *(*pp)++ = 0;
+ *pp = p_ret;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5G_obj_ent_encode() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G_obj_link_to_stab_cb
+ *
+ * Purpose: Callback routine for converting 'link' messages to symbol table
+ * form.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Aug 30 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5G_obj_link_to_stab_cb(const void *_mesg, unsigned UNUSED idx, void *_udata)
+{
+ const H5O_link_t *lnk = (const H5O_link_t *)_mesg; /* Pointer to link */
+ H5G_obj_ud1_t *udata = (H5G_obj_ud1_t *)_udata; /* 'User data' passed in */
+ H5G_bt_ud1_t bt_udata; /* Data to pass through B-tree */
+ herr_t ret_value = H5O_ITER_CONT; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT(H5G_obj_link_to_stab_cb)
+
+ /* check arguments */
+ HDassert(lnk);
+ HDassert(udata);
+
+ /* Construct user data to pass through B-tree routines */
+ bt_udata.common.name = lnk->name;
+ bt_udata.common.heap_addr = udata->heap_addr;
+ bt_udata.lnk = lnk;
+
+ /* Insert entry into symbol table */
+ if(H5B_insert(udata->f, udata->dxpl_id, H5B_SNODE, udata->btree_addr, &bt_udata) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTINSERT, FAIL, "unable to insert entry")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5G_obj_link_to_stab_cb() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G_obj_insert
+ *
+ * Purpose: Insert a new symbol into the group described by GRP_OLOC.
+ * file F. The name of the new symbol is NAME and its symbol
+ * table entry is OBJ_LNK. Optionally, increment the reference
+ * count for the object the link points to with INC_LINK.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Sep 6 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5G_obj_insert(H5O_loc_t *grp_oloc, const char *name, H5O_link_t *obj_lnk,
+ hbool_t inc_link, hid_t dxpl_id)
+{
+ H5O_linfo_t linfo; /* Link info message */
+ htri_t linfo_exists; /* Whether the link info is present */
+ hbool_t use_stab; /* Whether to use symbol table for insertions or not */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(H5G_obj_insert, FAIL)
+
+ /* check arguments */
+ HDassert(grp_oloc && grp_oloc->file);
+ HDassert(name && *name);
+ HDassert(obj_lnk);
+
+ /* Check if we have information about the number of objects in this group */
+ if((linfo_exists = H5O_exists(grp_oloc, H5O_LINFO_ID, 0, dxpl_id)) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "unable to check for link info")
+ if(linfo_exists) {
+ htri_t stab_exists; /* Whether the symbol table info is present */
+
+ /* Get the number of objects in this group */
+ if(NULL == H5O_read(grp_oloc, H5O_LINFO_ID, 0, &linfo, dxpl_id))
+ HGOTO_ERROR(H5E_SYM, H5E_BADMESG, FAIL, "can't get link info")
+
+ /* Check if there is already a 'stab' message */
+ if((stab_exists = H5O_exists(grp_oloc, H5O_STAB_ID, 0, dxpl_id)) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "unable to check for symbol table")
+ if(stab_exists)
+ use_stab = TRUE;
+ else {
+ H5O_ginfo_t ginfo; /* Group info message */
+ size_t link_msg_size; /* Size of link message in the file */
+
+ /* Get the link message size */
+ if((link_msg_size = H5O_raw_size(H5O_LINK_ID, grp_oloc->file, obj_lnk)) == 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTGETSIZE, FAIL, "can't get link size")
+
+ /* Get the group info */
+ if(NULL == H5O_read(grp_oloc, H5O_GINFO_ID, 0, &ginfo, dxpl_id))
+ HGOTO_ERROR(H5E_SYM, H5E_BADMESG, FAIL, "can't get group info")
+
+ /* If there's still a small enough number of links, use the 'link' message */
+ /* (If the encoded form of the link is too large to fit into an object
+ * header message, convert to using symbol table instead of link messages)
+ */
+ if(linfo.nlinks < ginfo.max_compact && link_msg_size < H5O_MAX_SIZE)
+ use_stab = FALSE;
+ else {
+ H5G_obj_ud1_t udata; /* User data for iteration */
+ H5O_stab_t stab; /* Symbol table message */
+
+ /* The group doesn't currently have a 'stab' message, go create one */
+ if(H5G_stab_create(grp_oloc, &stab, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "unable to create symbol table")
+
+ /* Set up user data for object header message iteration */
+ udata.f = grp_oloc->file;
+ udata.btree_addr = stab.btree_addr;
+ udata.heap_addr = stab.heap_addr;
+ udata.dxpl_id = dxpl_id;
+
+ /* Iterate over the 'link' messages, inserting them into the symbol table */
+ if(H5O_iterate(grp_oloc, H5O_LINK_ID, H5G_obj_link_to_stab_cb, &udata, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "error iterating over links")
+
+ /* Remove all the 'link' messages */
+ if(H5O_remove(grp_oloc, H5O_LINK_ID, H5O_ALL, FALSE, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTDELETE, FAIL, "unable to delete link messages")
+
+ use_stab = TRUE;
+ } /* end else */
+ } /* end else */
+ } /* end if */
+ else
+ use_stab = TRUE;
+
+ /* Insert into symbol table or create link object */
+ if(use_stab) {
+ /* Insert into symbol table */
+ if(H5G_stab_insert(grp_oloc, name, obj_lnk, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTINSERT, FAIL, "unable to insert entry")
+ } /* end if */
+ else {
+ /* Insert with link message */
+ if(H5G_link_insert(grp_oloc, obj_lnk, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTINSERT, FAIL, "unable to insert entry")
+ } /* end else */
+
+ /* Increment the number of objects in this group */
+ if(linfo_exists) {
+ linfo.nlinks++;
+ if(H5O_modify(grp_oloc, H5O_LINFO_ID, 0, 0, H5O_UPDATE_TIME, &linfo, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, FAIL, "can't update link info message")
+ } /* end if */
+
+ /* Increment link count on object, if appropriate */
+ if(inc_link) {
+ H5O_loc_t obj_oloc; /* Object location */
+
+ /* Convert to object location */
+ obj_oloc.file = grp_oloc->file;
+ obj_oloc.addr = obj_lnk->u.hard.addr;
+
+ /* Increment reference count for object */
+ if(H5O_link(&obj_oloc, 1, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_LINK, FAIL, "unable to increment hard link count")
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5G_obj_insert() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G_obj_iterate
+ *
+ * Purpose: Private function for H5Giterate.
+ * Iterates over objects in a group
+ *
+ * Return: Success: Non-negative
+ *
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Oct 3, 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5G_obj_iterate(hid_t loc_id, const char *name, int skip, int *last_obj,
+ H5G_iterate_t op, void *op_data, hid_t dxpl_id)
+{
+ htri_t stab_exists; /* Whether the symbol table info is present */
+ hid_t gid = -1; /* ID of group to iterate over */
+ H5G_t *grp; /* Pointer to group data structure to iterate over */
+ herr_t ret_value; /* Return value */
+
+ FUNC_ENTER_NOAPI(H5G_obj_iterate, FAIL)
+
+ /* Sanity check */
+ HDassert(name);
+ HDassert(last_obj);
+ HDassert(op);
+
+ /*
+ * Open the group on which to operate. We also create a group ID which
+ * we can pass to the application-defined operator.
+ */
+ if((gid = H5Gopen (loc_id, name)) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTOPENOBJ, FAIL, "unable to open group")
+ if((grp = H5I_object(gid)) == NULL)
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "bad group ID")
+
+ /* Check if we have information about the number of objects in this group */
+ if((stab_exists = H5O_exists(&(grp->oloc), H5O_STAB_ID, 0, dxpl_id)) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "unable to check for symbol table")
+
+ /* If the symbol table doesn't exist, iterate over link messages */
+ if(!stab_exists) {
+ /* Get the object's name from the link messages */
+ if((ret_value = H5G_link_iterate(&(grp->oloc), gid, skip, last_obj, op, op_data, dxpl_id)) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_BADITER, FAIL, "can't iterate over links")
+ } /* end if */
+ else {
+ /* Iterate over symbol table */
+ if((ret_value = H5G_stab_iterate(&(grp->oloc), gid, skip, last_obj, op, op_data, dxpl_id)) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_BADITER, FAIL, "can't iterate over symbol table")
+ } /* end else */
+
+done:
+ if(gid > 0)
+ H5I_dec_ref(gid); /*also closes 'grp'*/
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5G_obj_iterate() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G_obj_count
+ *
+ * Purpose: Check the number of objects in a group
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Sep 6 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5G_obj_count(H5O_loc_t *oloc, hsize_t *num_objs, hid_t dxpl_id)
+{
+ htri_t linfo_exists; /* Whether the link info is present */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(H5G_obj_count, FAIL)
+
+ /* Sanity check */
+ HDassert(oloc);
+ HDassert(num_objs);
+
+ /* Check if we have information about the number of objects in this group */
+ if((linfo_exists = H5O_exists(oloc, H5O_LINFO_ID, 0, dxpl_id)) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "unable to check for link info")
+
+ /* If the link info exists, then it has the number of objects in the group */
+ if(linfo_exists > 0) {
+ H5O_linfo_t linfo; /* Link info message */
+
+ /* Get the link info for this group */
+ if(NULL == H5O_read(oloc, H5O_LINFO_ID, 0, &linfo, dxpl_id))
+ HGOTO_ERROR(H5E_SYM, H5E_BADMESG, FAIL, "can't get link info")
+
+ /* Set the number of objects */
+ *num_objs = linfo.nlinks;
+ } /* end if */
+ else {
+ /* Get the number of objects in this group by iterating over symbol table */
+ if(H5G_stab_count(oloc, num_objs, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTCOUNT, FAIL, "can't count objects")
+ } /* end else */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5G_obj_count() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G_obj_get_name_by_idx
+ *
+ * Purpose: Private function for H5Gget_objname_by_idx.
+ * Returns the name of objects in the group by giving index.
+ *
+ * Return: Success: Non-negative
+ *
+ * Failure: Negative
+ *
+ * Programmer: Raymond Lu
+ * Nov 20, 2002
+ *
+ *-------------------------------------------------------------------------
+ */
+ssize_t
+H5G_obj_get_name_by_idx(H5O_loc_t *oloc, hsize_t idx, char* name, size_t size, hid_t dxpl_id)
+{
+ htri_t stab_exists; /* Whether the symbol table info is present */
+ ssize_t ret_value; /* Return value */
+
+ FUNC_ENTER_NOAPI(H5G_obj_get_name_by_idx, FAIL)
+
+ /* Sanity check */
+ HDassert(oloc);
+
+ /* Check if we have information about the number of objects in this group */
+ if((stab_exists = H5O_exists(oloc, H5O_STAB_ID, 0, dxpl_id)) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "unable to check for symbol table")
+
+ /* If the symbol table doesn't exist, search link messages */
+ if(!stab_exists) {
+ /* Get the object's name from the link messages */
+ if((ret_value = H5G_link_get_name_by_idx(oloc, idx, name, size, dxpl_id)) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "can't locate name")
+ } /* end if */
+ else {
+ /* Get the object's name from the symbol table */
+ if((ret_value = H5G_stab_get_name_by_idx(oloc, idx, name, size, dxpl_id)) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "can't locate name")
+ } /* end else */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5G_obj_get_name_by_idx() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G_obj_get_type_by_idx
+ *
+ * Purpose: Private function for H5Gget_objtype_by_idx.
+ * Returns the type of objects in the group by giving index.
+ *
+ * Return: Success: H5G_GROUP(1), H5G_DATASET(2), H5G_TYPE(3)
+ *
+ * Failure: Negative
+ *
+ * Programmer: Raymond Lu
+ * Nov 20, 2002
+ *
+ *-------------------------------------------------------------------------
+ */
+H5G_obj_t
+H5G_obj_get_type_by_idx(H5O_loc_t *oloc, hsize_t idx, hid_t dxpl_id)
+{
+ htri_t stab_exists; /* Whether the symbol table info is present */
+ H5G_obj_t ret_value; /* Return value */
+
+ FUNC_ENTER_NOAPI(H5G_obj_get_type_by_idx, H5G_UNKNOWN)
+
+ /* Sanity check */
+ HDassert(oloc);
+
+ /* Check if we have information about the number of objects in this group */
+ if((stab_exists = H5O_exists(oloc, H5O_STAB_ID, 0, dxpl_id)) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, H5G_UNKNOWN, "unable to check for symbol table")
+
+ /* If the symbol table doesn't exist, search link messages */
+ if(!stab_exists) {
+ /* Get the object's type from the link messages */
+ if((ret_value = H5G_link_get_type_by_idx(oloc, idx, dxpl_id)) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, H5G_UNKNOWN, "can't locate type")
+ } /* end if */
+ else {
+ /* Get the object's type from the symbol table */
+ if((ret_value = H5G_stab_get_type_by_idx(oloc, idx, dxpl_id)) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, H5G_UNKNOWN, "can't locate type")
+ } /* end else */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5G_obj_get_type_by_idx() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G_obj_remove
+ *
+ * Purpose: Remove an object from a group.
+ * (Needs to hand up the type of the object removed)
+ *
+ * Return: Success: Non-negative
+ *
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Sep 19, 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5G_obj_remove(H5O_loc_t *oloc, const char *name, H5G_obj_t *obj_type, hid_t dxpl_id)
+{
+ htri_t linfo_exists; /* Whether the link info is present */
+ H5O_linfo_t linfo; /* Link info message */
+ htri_t stab_exists; /* Whether the symbol table info is present */
+ hbool_t use_stab; /* Whether to use symbol table for deletions or not */
+ H5G_obj_t ret_value; /* Return value */
+
+ FUNC_ENTER_NOAPI(H5G_obj_remove, FAIL)
+
+ /* Sanity check */
+ HDassert(oloc);
+ HDassert(obj_type);
+
+ /* Check if we have information about the number of objects in this group */
+ if((stab_exists = H5O_exists(oloc, H5O_STAB_ID, 0, dxpl_id)) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "unable to check for symbol table")
+
+ /* Check if we have information about the number of objects in this group */
+ if((linfo_exists = H5O_exists(oloc, H5O_LINFO_ID, 0, dxpl_id)) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "unable to check for link info message")
+ if(linfo_exists) {
+ H5O_ginfo_t ginfo; /* Group info message */
+
+ /* Get the number of objects in this group */
+ if(NULL == H5O_read(oloc, H5O_LINFO_ID, 0, &linfo, dxpl_id))
+ HGOTO_ERROR(H5E_SYM, H5E_BADMESG, FAIL, "can't get link info")
+
+ /* Check for deleting enough links from group to go back to link messages */
+ if(stab_exists) {
+ /* Get the group info */
+ if(NULL == H5O_read(oloc, H5O_GINFO_ID, 0, &ginfo, dxpl_id))
+ HGOTO_ERROR(H5E_SYM, H5E_BADMESG, FAIL, "can't get group info")
+
+ /* Switch from symbol table back to link messages */
+ if(linfo.nlinks <= ginfo.min_dense) {
+ H5G_bt_it_ud4_t udata;
+ H5O_stab_t stab; /* Info about local heap & B-tree */
+ H5O_link_t *lnk_table; /* Array of links to convert */
+ hbool_t can_convert = TRUE; /* Whether converting to link messages is possible */
+ size_t u; /* Local index */
+
+ /* Get the B-tree & local heap info */
+ if(NULL == H5O_read(oloc, H5O_STAB_ID, 0, &stab, dxpl_id))
+ HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "unable to determine local heap address")
+
+ /* Allocate space for the link table */
+ H5_CHECK_OVERFLOW(linfo.nlinks, /* From: */ hsize_t, /* To: */size_t);
+ if(NULL == (lnk_table = H5MM_malloc(sizeof(H5O_link_t) * (size_t)linfo.nlinks)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed for link table")
+
+ /* Build udata to pass through H5B_iterate() */
+ udata.heap_addr = stab.heap_addr;
+ udata.lnk_table = lnk_table;
+ udata.nlinks = 0;
+ udata.max_links = linfo.nlinks;
+
+ /* Iterate over the group members, building a table of equivalent link messages */
+ if((ret_value = H5B_iterate(oloc->file, dxpl_id, H5B_SNODE,
+ H5G_node_stab_convert, stab.btree_addr, &udata)) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTNEXT, FAIL, "error iterating over entries")
+
+ /* Inspect links in table for ones that can't be converted back
+ * into link message form (currently only links which can't fit
+ * into an object header message)
+ */
+ for(u = 0; u < linfo.nlinks; u++)
+ if(H5O_mesg_size(H5O_LINK_ID, oloc->file, &(lnk_table[u])) >= H5O_MAX_SIZE) {
+ can_convert = FALSE;
+ break;
+ } /* end if */
+
+ /* If ok, insert links as link messages */
+ if(can_convert) {
+ for(u = 0; u < linfo.nlinks; u++) {
+ /* Insert link message into group */
+ if(H5O_modify(oloc, H5O_LINK_ID, H5O_NEW_MESG, 0, H5O_UPDATE_TIME, &(lnk_table[u]), dxpl_id) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "can't create message")
+ } /* end for */
+
+ /* Remove the 'stab' message */
+ if(H5O_remove(oloc, H5O_STAB_ID, H5O_ALL, FALSE, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTDELETE, FAIL, "unable to delete symbol table message")
+
+ use_stab = FALSE;
+ } /* end if */
+ else
+ use_stab = TRUE;
+
+ /* Release memory for link names (and memory for soft link values) */
+ for(u = 0; u < linfo.nlinks; u++) {
+ H5MM_xfree(lnk_table[u].name);
+ if(lnk_table[u].type == H5G_LINK_SOFT)
+ H5MM_xfree(lnk_table[u].u.soft.name);
+ } /* end for */
+
+ /* Release memory for link table */
+ H5MM_xfree(lnk_table);
+ } /* end if */
+ else
+ use_stab = TRUE;
+ } /* end if */
+ else
+ use_stab = FALSE;
+ } /* end if */
+ else
+ use_stab = TRUE;
+
+ /* If the symbol table doesn't exist, search link messages */
+ if(!use_stab) {
+ /* Remove object from the link messages */
+ if((ret_value = H5G_link_remove(oloc, name, obj_type, dxpl_id)) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "can't remove object")
+ } /* end if */
+ else {
+ /* Remove object from the symbol table */
+ if((ret_value = H5G_stab_remove(oloc, name, obj_type, dxpl_id)) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "can't remove object")
+ } /* end else */
+
+ /* Decrement the number of objects in this group */
+ if(linfo_exists) {
+ linfo.nlinks--;
+ if(H5O_modify(oloc, H5O_LINFO_ID, 0, 0, H5O_UPDATE_TIME, &linfo, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, FAIL, "can't update link info message")
+
+ /* Remove the symbol table, if we are using one and the number of links drops to zero */
+ if(linfo.nlinks == 0 && use_stab) {
+ if(H5O_remove(oloc, H5O_STAB_ID, H5O_ALL, FALSE, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTDELETE, FAIL, "unable to delete symbol table message")
+ } /* end if */
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5G_obj_remove() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G_obj_lookup
+ *
+ * Purpose: Look up a link in a group.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Sep 26 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5G_obj_lookup(H5O_loc_t *grp_oloc, const char *name, H5O_link_t *lnk,
+ hid_t dxpl_id)
+{
+ htri_t stab_exists; /* Whether the symbol table info is present */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(H5G_obj_lookup, FAIL)
+
+ /* check arguments */
+ HDassert(grp_oloc && grp_oloc->file);
+ HDassert(name && *name);
+
+ /* Check if we have information about the number of objects in this group */
+ if((stab_exists = H5O_exists(grp_oloc, H5O_STAB_ID, 0, dxpl_id)) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "unable to check for symbol table")
+
+ /* If the symbol table doesn't exist, search link messages */
+ if(!stab_exists) {
+ /* Get the object's info from the link messages */
+ if(H5G_link_lookup(grp_oloc, name, lnk, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "can't locate object")
+ } /* end if */
+ else {
+ /* Get the object's info from the symbol table */
+ if(H5G_stab_lookup(grp_oloc, name, lnk, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "can't locate object")
+ } /* end else */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5G_obj_lookup() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G_obj_find_cb
+ *
+ * Purpose: Callback for retrieving object location for an object in a group
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, September 20, 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5G_obj_find_cb(H5G_loc_t UNUSED *grp_loc/*in*/, const char UNUSED *name, const H5O_link_t UNUSED *lnk,
+ H5G_loc_t *obj_loc, void *_udata/*in,out*/)
+{
+ H5G_obj_ud2_t *udata = (H5G_obj_ud2_t *)_udata; /* User data passed in */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT(H5G_obj_find_cb)
+
+ /* Check if the name in this group resolved to a valid link */
+ if(obj_loc == NULL)
+ HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "name doesn't exist")
+
+ /* Copy object location for object */
+ H5O_loc_copy(udata->oloc, obj_loc->oloc, H5O_COPY_DEEP);
+
+ /* Release the group location for the object */
+ /* (Group traversal callbacks are responsible for either taking ownership
+ * of the group location for the object, or freeing it. - QAK)
+ */
+ H5G_loc_free(obj_loc);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5G_obj_find_cb() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G_obj_find
+ *
+ * Purpose: Look up an object relative to a group.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Sep 20 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5G_obj_find(H5G_loc_t *loc, const char *name, unsigned traverse_flags,
+ H5O_loc_t *obj_oloc, hid_t dxpl_id)
+{
+ H5G_obj_ud2_t udata; /* User data for traversal callback */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(H5G_obj_find, FAIL)
+
+ /* check arguments */
+ HDassert(loc && loc->oloc->file);
+ HDassert(name && *name);
+ HDassert(obj_oloc);
+
+ /* Set up user data for locating object */
+ udata.oloc = obj_oloc;
+
+ /* Traverse group hierarchy to locate object */
+ if(H5G_traverse(loc, name, traverse_flags, H5G_obj_find_cb, &udata, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "can't find object")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5G_obj_find() */
+