summaryrefslogtreecommitdiffstats
path: root/src/H5Oattr.c
diff options
context:
space:
mode:
authorQuincey Koziol <koziol@hdfgroup.org>2006-12-06 22:19:52 (GMT)
committerQuincey Koziol <koziol@hdfgroup.org>2006-12-06 22:19:52 (GMT)
commit7b368f006eea17a8b08cac9e6e79e58977edf864 (patch)
tree99e0f328dab0a6c3e602684d94aad309f339498d /src/H5Oattr.c
parent1fa6d7cbf7062f12bdd85f896d40004f562cc439 (diff)
downloadhdf5-7b368f006eea17a8b08cac9e6e79e58977edf864.zip
hdf5-7b368f006eea17a8b08cac9e6e79e58977edf864.tar.gz
hdf5-7b368f006eea17a8b08cac9e6e79e58977edf864.tar.bz2
[svn-r13028] Description:
Add first pass of "dense" attribute storage to objects. Lots of parts of this are stubbed out, but all the tests are passing and I'll work on the corner cases soon. Eliminated several unused parameters from object header message callback routines. Other, miscellaneous code cleanups, etc. (and probably some things I've forgotten about... :-) Tested on: FreeBSD/32 4.11 (sleipnir) Linux/32 2.4 (heping) AIX/32 5.? (copper)
Diffstat (limited to 'src/H5Oattr.c')
-rw-r--r--src/H5Oattr.c525
1 files changed, 519 insertions, 6 deletions
diff --git a/src/H5Oattr.c b/src/H5Oattr.c
index fa104a9..617614e 100644
--- a/src/H5Oattr.c
+++ b/src/H5Oattr.c
@@ -29,10 +29,47 @@
#include "H5Spkg.h" /* Dataspaces */
#include "H5SMprivate.h" /* Shared Object Header Messages */
+/* User data for iteration when updating an attribute */
+typedef struct {
+ /* down */
+ H5F_t *f; /* Pointer to file attribute is in */
+ hid_t dxpl_id; /* DXPL for operation */
+ H5A_t *attr; /* Attribute data to update object header with */
+
+ /* up */
+ hbool_t found; /* Whether the attribute was found */
+} H5O_iter_wrt_t;
+
+/* User data for iteration when renaming an attribute */
+typedef struct {
+ /* down */
+ H5F_t *f; /* Pointer to file attribute is in */
+ hid_t dxpl_id; /* DXPL for operation */
+ const char *old_name; /* Old name of attribute */
+ const char *new_name; /* New name of attribute */
+
+ /* up */
+ hbool_t found; /* Whether the attribute was found */
+} H5O_iter_ren_t;
+
+/* User data for iteration when iterating over attributes */
+typedef struct {
+ /* down */
+ H5F_t *f; /* Pointer to file attribute is in */
+ hid_t dxpl_id; /* DXPL for operation */
+ hid_t loc_id; /* ID of object being iterated over */
+ unsigned skip; /* # of attributes to skip over */
+ H5A_operator_t op; /* Callback routine for each attribute */
+ void *op_data; /* User data for callback */
+
+ /* up */
+ unsigned count; /* Count of attributes examined */
+} H5O_iter_itr_t;
+
/* PRIVATE PROTOTYPES */
static herr_t H5O_attr_encode(H5F_t *f, uint8_t *p, const void *mesg);
static void *H5O_attr_decode(H5F_t *f, hid_t dxpl_id, const uint8_t *p);
-static void *H5O_attr_copy(const void *_mesg, void *_dest, unsigned update_flags);
+static void *H5O_attr_copy(const void *_mesg, void *_dest);
static size_t H5O_attr_size(const H5F_t *f, const void *_mesg);
static herr_t H5O_attr_reset(void *_mesg);
static herr_t H5O_attr_free(void *mesg);
@@ -470,18 +507,17 @@ done:
allocating the destination structure if necessary.
--------------------------------------------------------------------------*/
static void *
-H5O_attr_copy(const void *_src, void *_dst, unsigned update_flags)
+H5O_attr_copy(const void *_src, void *_dst)
{
- const H5A_t *src = (const H5A_t *) _src;
- void *ret_value; /* Return value */
+ void *ret_value; /* Return value */
FUNC_ENTER_NOAPI_NOINIT(H5O_attr_copy)
/* check args */
- HDassert(src);
+ HDassert(_src);
/* copy */
- if(NULL == (ret_value = H5A_copy(_dst, src, update_flags)))
+ if(NULL == (ret_value = H5A_copy(_dst, _src)))
HGOTO_ERROR(H5E_ATTR, H5E_CANTINIT, NULL, "can't copy attribute")
done:
@@ -1229,3 +1265,480 @@ done:
FUNC_LEAVE_NOAPI(ret_value)
} /* end H5O_attr_debug() */
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_attr_write_cb
+ *
+ * Purpose: Object header iterator callback routine to update an
+ * attribute stored compactly.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Dec 4 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O_attr_write_cb(H5O_t *oh, H5O_mesg_t *mesg/*in,out*/,
+ unsigned UNUSED sequence, unsigned *oh_flags_ptr, void *_udata/*in,out*/)
+{
+ H5O_iter_wrt_t *udata = (H5O_iter_wrt_t *)_udata; /* Operator user data */
+ herr_t ret_value = H5_ITER_CONT; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT(H5O_attr_write_cb)
+
+ /* check args */
+ HDassert(oh);
+ HDassert(mesg);
+ HDassert(!udata->found);
+
+ /* Check for shared message */
+ if(mesg->flags & H5O_MSG_FLAG_SHARED) {
+ H5A_t shared_attr; /* Copy of shared attribute */
+
+ /*
+ * If the message is shared then then the native pointer points to an
+ * H5O_MSG_SHARED message. We use that information to look up the real
+ * message in the global heap or some other object header.
+ */
+ if(NULL == H5O_shared_read(udata->f, udata->dxpl_id, mesg->native, H5O_MSG_ATTR, &shared_attr))
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTINIT, H5_ITER_ERROR, "unable to read shared attribute")
+
+ /* Check for correct attribute message to modify */
+ if(HDstrcmp(shared_attr.name, udata->attr->name) == 0) {
+ htri_t shared_mesg; /* Whether the message should be shared */
+
+ /* Store new version of message as a SOHM */
+ /* (should always work, since we're not changing the size of the attribute) */
+ if((shared_mesg = H5SM_try_share(udata->f, udata->dxpl_id, H5O_ATTR_ID, udata->attr)) == 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_BADMESG, H5_ITER_ERROR, "attribute changed sharing status")
+ else if(shared_mesg < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_BADMESG, H5_ITER_ERROR, "can't share attribute")
+
+ /* Remove the old attribut from the SOHM index */
+ if(H5SM_try_delete(udata->f, udata->dxpl_id, H5O_ATTR_ID, mesg->native) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTFREE, H5_ITER_ERROR, "unable to delete shared attribute in shared storage")
+
+ /* Extract shared message info from current attribute */
+ if(H5O_attr_get_share(udata->attr, mesg->native) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_BADMESG, H5_ITER_ERROR, "can't get shared info")
+
+ /* Indicate that we found the correct attribute */
+ udata->found = TRUE;
+ } /* end if */
+
+ /* Release copy of shared attribute */
+ H5O_attr_reset(&shared_attr);
+ } /* end if */
+ else {
+ /* Check for correct attribute message to modify */
+ if(HDstrcmp(((H5A_t *)mesg->native)->name, udata->attr->name) == 0) {
+ /* Allocate storage for the message's data, if necessary */
+ if(((H5A_t *)mesg->native)->data == NULL)
+ if(NULL == (((H5A_t *)mesg->native)->data = H5FL_BLK_MALLOC(attr_buf, udata->attr->data_size)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, H5_ITER_ERROR, "memory allocation failed")
+
+ /* Copy the data */
+ HDmemcpy(((H5A_t *)mesg->native)->data, udata->attr->data, udata->attr->data_size);
+
+ /* Indicate that we found the correct attribute */
+ udata->found = TRUE;
+ } /* end if */
+ } /* end else */
+
+ /* Set common info, if we found the correct attribute */
+ if(udata->found) {
+ /* Mark message as dirty */
+ mesg->dirty = TRUE;
+
+ /* Stop iterating */
+ ret_value = H5_ITER_STOP;
+
+ /* Indicate that the object header was modified */
+ *oh_flags_ptr |= H5AC__DIRTIED_FLAG;
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_attr_write_cb() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_attr_write
+ *
+ * Purpose: Write a new value to an attribute.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Monday, December 4, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5O_attr_write(const H5O_loc_t *loc, hid_t dxpl_id, H5A_t *attr)
+{
+ H5O_t *oh = NULL; /* Pointer to actual object header */
+ unsigned oh_flags = H5AC__NO_FLAGS_SET; /* Metadata cache flags for object header */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT(H5O_attr_write)
+
+ /* Check arguments */
+ HDassert(loc);
+ HDassert(attr);
+
+ /* Protect the object header to iterate over */
+ if(NULL == (oh = H5AC_protect(loc->file, dxpl_id, H5AC_OHDR, loc->addr, NULL, NULL, H5AC_WRITE)))
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTLOAD, FAIL, "unable to load object header")
+
+ /* Check for attributes stored densely */
+ if(H5F_addr_defined(oh->attr_fheap_addr)) {
+ /* Modify the attribute data in dense storage */
+ if(H5A_dense_write(loc->file, dxpl_id, oh, attr) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTUPDATE, FAIL, "error updating attribute")
+ } /* end if */
+ else {
+ H5O_iter_wrt_t udata; /* User data for callback */
+ H5O_mesg_operator_t op; /* Wrapper for operator */
+
+ /* Set up user data for callback */
+ udata.f = loc->file;
+ udata.dxpl_id = dxpl_id;
+ udata.attr = attr;
+ udata.found = FALSE;
+
+ /* Iterate over attributes, to locate correct one to update */
+ op.lib_op = H5O_attr_write_cb;
+ if(H5O_msg_iterate_real(loc->file, oh, H5O_MSG_ATTR, TRUE, op, &udata, dxpl_id, &oh_flags) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTUPDATE, FAIL, "error updating attribute")
+
+ /* Check that we found the attribute */
+ if(!udata.found)
+ HGOTO_ERROR(H5E_ATTR, H5E_NOTFOUND, FAIL, "can't locate open attribute?")
+ } /* end else */
+
+ /* Update the modification time, if any */
+ if(H5O_touch_oh(loc->file, dxpl_id, oh, FALSE, &oh_flags) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTUPDATE, FAIL, "unable to update time on object")
+
+done:
+ if(oh && H5AC_unprotect(loc->file, dxpl_id, H5AC_OHDR, loc->addr, oh, oh_flags) < 0)
+ HDONE_ERROR(H5E_ATTR, H5E_PROTECT, FAIL, "unable to release object header")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_attr_write */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_attr_rename_dup_cb
+ *
+ * Purpose: Object header iterator callback routine to check for
+ * duplicate name during rename
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Dec 5 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O_attr_rename_dup_cb(H5O_t *oh, H5O_mesg_t *mesg/*in,out*/,
+ unsigned UNUSED sequence, unsigned UNUSED *oh_flags_ptr, void *_udata/*in,out*/)
+{
+ H5O_iter_ren_t *udata = (H5O_iter_ren_t *)_udata; /* Operator user data */
+ herr_t ret_value = H5_ITER_CONT; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT(H5O_attr_rename_dup_cb)
+
+ /* check args */
+ HDassert(oh);
+ HDassert(mesg);
+ HDassert(!udata->found);
+
+ /* Check for shared message */
+ if(mesg->flags & H5O_MSG_FLAG_SHARED) {
+ H5A_t shared_attr; /* Copy of shared attribute */
+
+ /*
+ * If the message is shared then then the native pointer points to an
+ * H5O_MSG_SHARED message. We use that information to look up the real
+ * message in the global heap or some other object header.
+ */
+ if(NULL == H5O_shared_read(udata->f, udata->dxpl_id, mesg->native, H5O_MSG_ATTR, &shared_attr))
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTINIT, H5_ITER_ERROR, "unable to read shared attribute")
+
+ /* Check for existing attribute with new name */
+ if(HDstrcmp(shared_attr.name, udata->new_name) == 0) {
+ /* Indicate that we found an existing attribute with the new name*/
+ udata->found = TRUE;
+
+ /* Stop iterating */
+ ret_value = H5_ITER_STOP;
+ } /* end if */
+
+ /* Release copy of shared attribute */
+ H5O_attr_reset(&shared_attr);
+ } /* end if */
+ else {
+ /* Check for existing attribute with new name */
+ if(HDstrcmp(((H5A_t *)mesg->native)->name, udata->new_name) == 0) {
+ /* Indicate that we found an existing attribute with the new name*/
+ udata->found = TRUE;
+
+ /* Stop iterating */
+ ret_value = H5_ITER_STOP;
+ } /* end if */
+ } /* end else */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_attr_rename_dup_cb() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_attr_rename_mod_cb
+ *
+ * Purpose: Object header iterator callback routine to change name of
+ * attribute during rename
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Dec 5 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O_attr_rename_mod_cb(H5O_t *oh, H5O_mesg_t *mesg/*in,out*/,
+ unsigned UNUSED sequence, unsigned *oh_flags_ptr, void *_udata/*in,out*/)
+{
+ H5O_iter_ren_t *udata = (H5O_iter_ren_t *)_udata; /* Operator user data */
+ herr_t ret_value = H5_ITER_CONT; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT(H5O_attr_rename_mod_cb)
+
+ /* check args */
+ HDassert(oh);
+ HDassert(mesg);
+ HDassert(!udata->found);
+
+ /* Check for shared message */
+ if(mesg->flags & H5O_MSG_FLAG_SHARED) {
+ H5A_t shared_attr; /* Copy of shared attribute */
+
+ /*
+ * If the message is shared then then the native pointer points to an
+ * H5O_MSG_SHARED message. We use that information to look up the real
+ * message in the global heap or some other object header.
+ */
+ if(NULL == H5O_shared_read(udata->f, udata->dxpl_id, mesg->native, H5O_MSG_ATTR, &shared_attr))
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTINIT, H5_ITER_ERROR, "unable to read shared attribute")
+
+ /* Check for correct attribute message to modify */
+ if(HDstrcmp(shared_attr.name, udata->old_name) == 0) {
+/* XXX: fix me */
+HDfprintf(stderr, "%s: renaming a shared attribute not supported yet!\n", FUNC);
+HGOTO_ERROR(H5E_ATTR, H5E_UNSUPPORTED, H5_ITER_ERROR, "renaming a shared attribute not supported yet")
+ } /* end if */
+
+ /* Release copy of shared attribute */
+ H5O_attr_reset(&shared_attr);
+ } /* end if */
+ else {
+ /* Find correct attribute message to rename */
+ if(HDstrcmp(((H5A_t *)mesg->native)->name, udata->old_name) == 0) {
+ /* Change the name for the attribute */
+ H5MM_xfree(((H5A_t *)mesg->native)->name);
+ ((H5A_t *)mesg->native)->name = H5MM_xstrdup(udata->new_name);
+
+ /* Indicate that we found an existing attribute with the old name*/
+ udata->found = TRUE;
+
+ /* Mark message as dirty */
+ mesg->dirty = TRUE;
+
+ /* Stop iterating */
+ ret_value = H5_ITER_STOP;
+
+ /* Indicate that the object header was modified */
+ *oh_flags_ptr |= H5AC__DIRTIED_FLAG;
+ } /* end if */
+ } /* end else */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_attr_rename_mod_cb() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_attr_rename
+ *
+ * Purpose: Rename an attribute.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, December 5, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5O_attr_rename(const H5O_loc_t *loc, hid_t dxpl_id, const char *old_name, const char *new_name)
+{
+ H5O_t *oh = NULL; /* Pointer to actual object header */
+ unsigned oh_flags = H5AC__NO_FLAGS_SET; /* Metadata cache flags for object header */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT(H5O_attr_rename)
+
+ /* Check arguments */
+ HDassert(loc);
+ HDassert(old_name);
+ HDassert(new_name);
+
+ /* Protect the object header to iterate over */
+ if(NULL == (oh = H5AC_protect(loc->file, dxpl_id, H5AC_OHDR, loc->addr, NULL, NULL, H5AC_WRITE)))
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTLOAD, FAIL, "unable to load object header")
+
+ /* Check for attributes stored densely */
+ if(H5F_addr_defined(oh->attr_fheap_addr)) {
+/* XXX: fix me */
+HDfprintf(stderr, "%s: renaming attributes in dense storage not supported yet!\n", FUNC);
+HGOTO_ERROR(H5E_ATTR, H5E_UNSUPPORTED, FAIL, "renaming attributes in dense storage not supported yet")
+ } /* end if */
+ else {
+ H5O_iter_ren_t udata; /* User data for callback */
+ H5O_mesg_operator_t op; /* Wrapper for operator */
+
+ /* Set up user data for callback */
+ udata.f = loc->file;
+ udata.dxpl_id = dxpl_id;
+ udata.old_name = old_name;
+ udata.new_name = new_name;
+ udata.found = FALSE;
+
+ /* Iterate over attributes, to check if "new name" exists already */
+ op.lib_op = H5O_attr_rename_dup_cb;
+ if(H5O_msg_iterate_real(loc->file, oh, H5O_MSG_ATTR, TRUE, op, &udata, dxpl_id, &oh_flags) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTUPDATE, FAIL, "error updating attribute")
+
+ /* If the new name was found, indicate an error */
+ if(udata.found)
+ HGOTO_ERROR(H5E_ATTR, H5E_EXISTS, FAIL, "attribute with new name already exists")
+
+ /* Iterate over attributes again, to actually rename attribute with old name */
+ op.lib_op = H5O_attr_rename_mod_cb;
+ if(H5O_msg_iterate_real(loc->file, oh, H5O_MSG_ATTR, TRUE, op, &udata, dxpl_id, &oh_flags) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTUPDATE, FAIL, "error updating attribute")
+ } /* end else */
+
+ /* Update the modification time, if any */
+ if(H5O_touch_oh(loc->file, dxpl_id, oh, FALSE, &oh_flags) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTUPDATE, FAIL, "unable to update time on object")
+
+done:
+ if(oh && H5AC_unprotect(loc->file, dxpl_id, H5AC_OHDR, loc->addr, oh, oh_flags) < 0)
+ HDONE_ERROR(H5E_ATTR, H5E_PROTECT, FAIL, "unable to release object header")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_attr_rename */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_attr_iterate
+ *
+ * Purpose: Iterate over attributes for an object.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, December 5, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5O_attr_iterate(hid_t loc_id, const H5O_loc_t *loc, hid_t dxpl_id,
+ unsigned skip, unsigned *last_attr, H5A_operator_t op, void *op_data)
+{
+ H5O_t *oh = NULL; /* Pointer to actual object header */
+ haddr_t attr_fheap_addr; /* Address of fractal heap for dense attribute storage */
+ haddr_t name_bt2_addr; /* Address of v2 B-tree for name index on dense attribute storage */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT(H5O_attr_iterate)
+
+ /* Check arguments */
+ HDassert(loc);
+ HDassert(op);
+
+ /* Protect the object header to iterate over */
+ if(NULL == (oh = H5AC_protect(loc->file, dxpl_id, H5AC_OHDR, loc->addr, NULL, NULL, H5AC_READ)))
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTLOAD, FAIL, "unable to load object header")
+
+ /* Retrieve the information about dense attribute storage */
+ if(oh->version > H5O_VERSION_1 && H5F_addr_defined(oh->attr_fheap_addr)) {
+ attr_fheap_addr = oh->attr_fheap_addr;
+ name_bt2_addr = oh->name_bt2_addr;
+ } /* end if */
+ else
+ attr_fheap_addr = name_bt2_addr = HADDR_UNDEF;
+
+ /* Release the object header */
+ if(H5AC_unprotect(loc->file, dxpl_id, H5AC_OHDR, loc->addr, oh, H5AC__NO_FLAGS_SET) < 0)
+ HDONE_ERROR(H5E_ATTR, H5E_PROTECT, FAIL, "unable to release object header")
+ oh = NULL;
+
+ /* Check for attributes stored densely */
+ if(H5F_addr_defined(attr_fheap_addr)) {
+ if((ret_value = H5A_dense_iterate(loc->file, dxpl_id, loc_id, attr_fheap_addr,
+ name_bt2_addr, skip, last_attr, op, op_data)) < 0)
+ HERROR(H5E_ATTR, H5E_BADITER, "error iterating over attributes");
+ } /* end if */
+ else {
+ unsigned idx; /* Current attribute to operate on */
+
+ /* Check for skipping over too many attributes */
+ if((int)skip < H5O_msg_count(loc, H5O_ATTR_ID, dxpl_id)) {
+ H5A_t found_attr; /* Copy of attribute for callback */
+
+ /* Read each attribute and call application's callback */
+ /* (this could be made more efficient by iterating over the
+ * attribute header messages with H5O_msg_iterate, but then
+ * the object header would be locked during the callback into
+ * the application code, causing problems if they attempt to
+ * do anything with the object the attribute is on - QAK)
+ */
+ idx = skip;
+ while(H5O_msg_read(loc, H5O_ATTR_ID, (int)idx, &found_attr, dxpl_id) != NULL) {
+ /* Call application's callback */
+ idx++;
+ if((ret_value = (op)(loc_id, found_attr.name, op_data)) != 0) {
+ H5A_free(&found_attr);
+ break;
+ } /* end if */
+ H5A_free(&found_attr);
+ } /* end while */
+
+ /* Clear error stack from running off end of attributes */
+ if(ret_value == 0)
+ H5E_clear_stack(NULL);
+ } /* end if */
+ else
+ if(skip > 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid index specified")
+
+ /* Update last attribute looked at */
+ if(last_attr)
+ *last_attr = idx;
+ } /* end else */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_attr_iterate */
+