summaryrefslogtreecommitdiffstats
path: root/src/H5Gobj.c
diff options
context:
space:
mode:
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() */
+