mirror of
https://github.com/HDFGroup/hdf5.git
synced 2025-01-12 15:04:59 +08:00
03b6575b1b
* Update H5_IS_BUFFER_OVERFLOW to account for 'size' of 0 * Invert a few checks to avoid function call
1842 lines
76 KiB
C
1842 lines
76 KiB
C
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
|
* Copyright by The HDF Group. *
|
|
* 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://www.hdfgroup.org/licenses. *
|
|
* If you do not have access to either file, you may request a copy from *
|
|
* help@hdfgroup.org. *
|
|
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
|
|
|
/*-------------------------------------------------------------------------
|
|
*
|
|
* Created: H5Oattribute.c
|
|
*
|
|
* Purpose: Object header attribute routines.
|
|
*
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
|
|
/****************/
|
|
/* Module Setup */
|
|
/****************/
|
|
|
|
#define H5A_FRIEND /* Suppress error about including H5Apkg.h */
|
|
#include "H5Omodule.h" /* This source code file is part of the H5O module */
|
|
|
|
/***********/
|
|
/* Headers */
|
|
/***********/
|
|
#include "H5private.h" /* Generic Functions */
|
|
#include "H5Apkg.h" /* Attributes */
|
|
#include "H5Eprivate.h" /* Error handling */
|
|
#include "H5MMprivate.h" /* Memory management */
|
|
#include "H5Opkg.h" /* Object headers */
|
|
#include "H5SMprivate.h" /* Shared Object Header Messages */
|
|
#include "H5Iprivate.h" /* IDs */
|
|
#include "H5Fprivate.h" /* File */
|
|
|
|
/****************/
|
|
/* Local Macros */
|
|
/****************/
|
|
|
|
/******************/
|
|
/* Local Typedefs */
|
|
/******************/
|
|
|
|
/* User data for iteration when converting attributes to dense storage */
|
|
typedef struct {
|
|
H5F_t *f; /* Pointer to file for insertion */
|
|
H5O_ainfo_t *ainfo; /* Attribute info struct */
|
|
} H5O_iter_cvt_t;
|
|
|
|
/* User data for iteration when opening an attribute */
|
|
typedef struct {
|
|
/* down */
|
|
const char *name; /* Name of attribute to open */
|
|
|
|
/* up */
|
|
H5A_t *attr; /* Attribute data to update object header with */
|
|
} H5O_iter_opn_t;
|
|
|
|
/* User data for iteration when updating an attribute */
|
|
typedef struct {
|
|
/* down */
|
|
H5F_t *f; /* Pointer to file attribute is in */
|
|
H5A_t *attr; /* Attribute data to update object header with */
|
|
|
|
/* up */
|
|
bool 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 */
|
|
const char *old_name; /* Old name of attribute */
|
|
const char *new_name; /* New name of attribute */
|
|
|
|
/* up */
|
|
bool found; /* Whether the attribute was found */
|
|
} H5O_iter_ren_t;
|
|
|
|
/* User data for iteration when removing an attribute */
|
|
typedef struct {
|
|
/* down */
|
|
H5F_t *f; /* Pointer to file attribute is in */
|
|
const char *name; /* Name of attribute to open */
|
|
|
|
/* up */
|
|
bool found; /* Found attribute to delete */
|
|
} H5O_iter_rm_t;
|
|
|
|
/* User data for iteration when checking if an attribute exists */
|
|
typedef struct {
|
|
/* down */
|
|
const char *name; /* Name of attribute to open */
|
|
|
|
/* up */
|
|
bool *exists; /* Pointer to flag to indicate attribute exists */
|
|
} H5O_iter_xst_t;
|
|
|
|
/********************/
|
|
/* Package Typedefs */
|
|
/********************/
|
|
|
|
/********************/
|
|
/* Local Prototypes */
|
|
/********************/
|
|
static herr_t H5O__attr_to_dense_cb(H5O_t *oh, H5O_mesg_t *mesg, unsigned H5_ATTR_UNUSED sequence,
|
|
unsigned *oh_modified, void *_udata);
|
|
static htri_t H5O__attr_find_opened_attr(const H5O_loc_t *loc, H5A_t **attr, const char *name_to_open);
|
|
static herr_t H5O__attr_open_cb(H5O_t *oh, H5O_mesg_t *mesg, unsigned sequence,
|
|
unsigned H5_ATTR_UNUSED *oh_modified, void *_udata);
|
|
static herr_t H5O__attr_open_by_idx_cb(const H5A_t *attr, void *_ret_attr);
|
|
static herr_t H5O__attr_write_cb(H5O_t *oh, H5O_mesg_t *mesg, unsigned H5_ATTR_UNUSED sequence,
|
|
unsigned *oh_modified, void *_udata);
|
|
static herr_t H5O__attr_rename_chk_cb(H5O_t H5_ATTR_UNUSED *oh, H5O_mesg_t *mesg,
|
|
unsigned H5_ATTR_UNUSED sequence, unsigned H5_ATTR_UNUSED *oh_modified,
|
|
void *_udata);
|
|
static herr_t H5O__attr_rename_mod_cb(H5O_t *oh, H5O_mesg_t *mesg, unsigned H5_ATTR_UNUSED sequence,
|
|
unsigned *oh_modified, void *_udata);
|
|
static herr_t H5O__attr_remove_update(const H5O_loc_t *loc, H5O_t *oh, H5O_ainfo_t *ainfo);
|
|
static herr_t H5O__attr_remove_cb(H5O_t *oh, H5O_mesg_t *mesg, unsigned H5_ATTR_UNUSED sequence,
|
|
unsigned *oh_modified, void *_udata);
|
|
static herr_t H5O__attr_exists_cb(H5O_t H5_ATTR_UNUSED *oh, H5O_mesg_t *mesg,
|
|
unsigned H5_ATTR_UNUSED sequence, unsigned H5_ATTR_UNUSED *oh_modified,
|
|
void *_udata);
|
|
|
|
/*********************/
|
|
/* Package Variables */
|
|
/*********************/
|
|
|
|
/*****************************/
|
|
/* Library Private Variables */
|
|
/*****************************/
|
|
|
|
/*******************/
|
|
/* Local Variables */
|
|
/*******************/
|
|
|
|
/*-------------------------------------------------------------------------
|
|
* Function: H5O__attr_to_dense_cb
|
|
*
|
|
* Purpose: Object header iterator callback routine to convert compact
|
|
* attributes to dense attributes
|
|
*
|
|
* Return: SUCCEED/FAIL
|
|
*
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
static herr_t
|
|
H5O__attr_to_dense_cb(H5O_t *oh, H5O_mesg_t *mesg /*in,out*/, unsigned H5_ATTR_UNUSED sequence,
|
|
unsigned *oh_modified, void *_udata /*in,out*/)
|
|
{
|
|
H5O_iter_cvt_t *udata = (H5O_iter_cvt_t *)_udata; /* Operator user data */
|
|
H5A_t *attr = (H5A_t *)mesg->native; /* Pointer to attribute to insert */
|
|
herr_t ret_value = H5_ITER_CONT; /* Return value */
|
|
|
|
FUNC_ENTER_PACKAGE
|
|
|
|
/* check args */
|
|
assert(oh);
|
|
assert(mesg);
|
|
assert(udata);
|
|
assert(udata->f);
|
|
assert(udata->ainfo);
|
|
assert(attr);
|
|
|
|
/* Insert attribute into dense storage */
|
|
if (H5A__dense_insert(udata->f, udata->ainfo, attr) < 0)
|
|
HGOTO_ERROR(H5E_OHDR, H5E_CANTINSERT, H5_ITER_ERROR, "unable to add to dense storage");
|
|
|
|
/* Convert message into a null message in the header */
|
|
/* (don't delete attribute's space in the file though) */
|
|
if (H5O__release_mesg(udata->f, oh, mesg, false) < 0)
|
|
HGOTO_ERROR(H5E_OHDR, H5E_CANTDELETE, H5_ITER_ERROR, "unable to convert into null message");
|
|
|
|
/* Indicate that the object header was modified */
|
|
*oh_modified = H5O_MODIFY_CONDENSE;
|
|
|
|
done:
|
|
FUNC_LEAVE_NOAPI(ret_value)
|
|
} /* end H5O__attr_to_dense_cb() */
|
|
|
|
/*-------------------------------------------------------------------------
|
|
* Function: H5O__attr_create
|
|
*
|
|
* Purpose: Create a new attribute in the object header.
|
|
*
|
|
* Return: SUCCEED/FAIL
|
|
*
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
herr_t
|
|
H5O__attr_create(const H5O_loc_t *loc, H5A_t *attr)
|
|
{
|
|
H5O_t *oh = NULL; /* Pointer to actual object header */
|
|
H5O_ainfo_t ainfo; /* Attribute information for object */
|
|
htri_t shared_mesg; /* Should this message be stored in the Shared Message table? */
|
|
herr_t ret_value = SUCCEED; /* Return value */
|
|
|
|
FUNC_ENTER_NOAPI_NOINIT
|
|
|
|
/* Check arguments */
|
|
assert(loc);
|
|
assert(attr);
|
|
|
|
/* Pin the object header */
|
|
if (NULL == (oh = H5O_pin(loc)))
|
|
HGOTO_ERROR(H5E_ATTR, H5E_CANTPIN, FAIL, "unable to pin object header");
|
|
|
|
/* Check for creating attribute with unusual datatype */
|
|
if (!(H5O_has_chksum(oh) || (H5F_RFIC_FLAGS(loc->file) & H5F_RFIC_UNUSUAL_NUM_UNUSED_NUMERIC_BITS)) &&
|
|
H5T_is_numeric_with_unusual_unused_bits(attr->shared->dt))
|
|
HGOTO_ERROR(H5E_ATTR, H5E_CANTINIT, FAIL,
|
|
"creating attribute with unusual datatype, see documentation for "
|
|
"H5Pset_relax_file_integrity_checks for details.");
|
|
|
|
/* Check if this object already has attribute information */
|
|
if (oh->version > H5O_VERSION_1) {
|
|
bool new_ainfo = false; /* Flag to indicate that the attribute information is new */
|
|
htri_t ainfo_exists; /* Whether the attribute info was retrieved */
|
|
|
|
/* Check for (& retrieve if available) attribute info */
|
|
if ((ainfo_exists = H5A__get_ainfo(loc->file, oh, &ainfo)) < 0)
|
|
HGOTO_ERROR(H5E_ATTR, H5E_CANTGET, FAIL, "can't check for attribute info message");
|
|
if (!ainfo_exists) {
|
|
/* Initialize attribute information */
|
|
ainfo.track_corder = (bool)((oh->flags & H5O_HDR_ATTR_CRT_ORDER_TRACKED) ? true : false);
|
|
ainfo.index_corder = (bool)((oh->flags & H5O_HDR_ATTR_CRT_ORDER_INDEXED) ? true : false);
|
|
ainfo.max_crt_idx = 0;
|
|
ainfo.corder_bt2_addr = HADDR_UNDEF;
|
|
ainfo.nattrs = 0;
|
|
ainfo.fheap_addr = HADDR_UNDEF;
|
|
ainfo.name_bt2_addr = HADDR_UNDEF;
|
|
|
|
/* Set flag to add attribute information to object header */
|
|
new_ainfo = true;
|
|
} /* end if */
|
|
else {
|
|
/* Sanity check attribute info read in */
|
|
assert(ainfo.nattrs > 0);
|
|
assert(ainfo.track_corder == ((oh->flags & H5O_HDR_ATTR_CRT_ORDER_TRACKED) > 0));
|
|
assert(ainfo.index_corder == ((oh->flags & H5O_HDR_ATTR_CRT_ORDER_INDEXED) > 0));
|
|
} /* end else */
|
|
|
|
/* Check if switching to "dense" attribute storage is possible */
|
|
if (!H5_addr_defined(ainfo.fheap_addr)) {
|
|
htri_t shareable; /* Whether the attribute will be shared */
|
|
size_t raw_size = 0; /* Raw size of message */
|
|
|
|
/* Check for attribute being shareable */
|
|
if ((shareable = H5SM_can_share(loc->file, NULL, NULL, H5O_ATTR_ID, attr)) < 0)
|
|
HGOTO_ERROR(H5E_ATTR, H5E_BADMESG, FAIL, "can't determine attribute sharing status");
|
|
else if (shareable == false) {
|
|
/* Compute the size needed to encode the attribute */
|
|
raw_size = (H5O_MSG_ATTR->raw_size)(loc->file, false, attr);
|
|
} /* end if */
|
|
|
|
/* Check for condititions for switching to "dense" attribute storage are met */
|
|
if (ainfo.nattrs == oh->max_compact || (!shareable && raw_size >= H5O_MESG_MAX_SIZE)) {
|
|
H5O_iter_cvt_t udata; /* User data for callback */
|
|
H5O_mesg_operator_t op; /* Wrapper for operator */
|
|
|
|
/* Create dense storage for attributes */
|
|
if (H5A__dense_create(loc->file, &ainfo) < 0)
|
|
HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, FAIL,
|
|
"unable to create dense storage for attributes");
|
|
|
|
/* Set up user data for callback */
|
|
udata.f = loc->file;
|
|
udata.ainfo = &ainfo;
|
|
|
|
/* Iterate over existing attributes, moving them to dense storage */
|
|
op.op_type = H5O_MESG_OP_LIB;
|
|
op.u.lib_op = H5O__attr_to_dense_cb;
|
|
if (H5O__msg_iterate_real(loc->file, oh, H5O_MSG_ATTR, &op, &udata) < 0)
|
|
HGOTO_ERROR(H5E_ATTR, H5E_CANTCONVERT, FAIL,
|
|
"error converting attributes to dense storage");
|
|
} /* end if */
|
|
} /* end if */
|
|
|
|
/* Increment attribute count on object */
|
|
ainfo.nattrs++;
|
|
|
|
/* Check whether we're tracking the creation index on attributes */
|
|
if (ainfo.track_corder) {
|
|
/* Check for attribute creation order index on the object wrapping around */
|
|
if (ainfo.max_crt_idx == H5O_MAX_CRT_ORDER_IDX)
|
|
HGOTO_ERROR(H5E_ATTR, H5E_CANTINC, FAIL, "attribute creation index can't be incremented");
|
|
|
|
/* Set the creation order index on the attribute & incr. creation order index */
|
|
attr->shared->crt_idx = ainfo.max_crt_idx++;
|
|
} /* end if */
|
|
else
|
|
/* Set "bogus" creation index for attribute */
|
|
attr->shared->crt_idx = H5O_MAX_CRT_ORDER_IDX;
|
|
|
|
/* Add the attribute information message, if one is needed */
|
|
if (new_ainfo) {
|
|
if (H5O__msg_append_real(loc->file, oh, H5O_MSG_AINFO, H5O_MSG_FLAG_DONTSHARE, 0, &ainfo) < 0)
|
|
HGOTO_ERROR(H5E_ATTR, H5E_CANTINSERT, FAIL, "unable to create new attribute info message");
|
|
} /* end if */
|
|
/* Otherwise, update existing message */
|
|
else if (H5O__msg_write_real(loc->file, oh, H5O_MSG_AINFO, H5O_MSG_FLAG_DONTSHARE, 0, &ainfo) < 0)
|
|
HGOTO_ERROR(H5E_ATTR, H5E_CANTUPDATE, FAIL, "unable to update attribute info message");
|
|
} /* end if */
|
|
else {
|
|
/* Set "bogus" creation index for attribute */
|
|
attr->shared->crt_idx = H5O_MAX_CRT_ORDER_IDX;
|
|
|
|
/* Set attribute info value to get attribute into object header */
|
|
ainfo.fheap_addr = HADDR_UNDEF;
|
|
} /* end else */
|
|
|
|
/* Check for storing attribute with dense storage */
|
|
if (H5_addr_defined(ainfo.fheap_addr)) {
|
|
/* Insert attribute into dense storage */
|
|
if (H5A__dense_insert(loc->file, &ainfo, attr) < 0)
|
|
HGOTO_ERROR(H5E_ATTR, H5E_CANTINSERT, FAIL, "unable to add to dense storage");
|
|
} /* end if */
|
|
else
|
|
/* Append new message to object header */
|
|
if (H5O__msg_append_real(loc->file, oh, H5O_MSG_ATTR, 0, 0, attr) < 0)
|
|
HGOTO_ERROR(H5E_ATTR, H5E_CANTINSERT, FAIL, "unable to create new attribute in header");
|
|
|
|
/* Increment reference count for shared attribute object for the
|
|
* object handle created by the caller function H5A__create. The count
|
|
* for the cached object header has been incremented in the step above
|
|
* (in H5O__msg_append_real). The dense storage doesn't need a count.
|
|
*/
|
|
attr->shared->nrefs += 1;
|
|
|
|
/* Was new attribute shared? */
|
|
if ((shared_mesg = H5O_msg_is_shared(H5O_ATTR_ID, attr)) > 0) {
|
|
hsize_t attr_rc; /* Attribute's ref count in shared message storage */
|
|
|
|
/* Retrieve ref count for shared attribute */
|
|
if (H5SM_get_refcount(loc->file, H5O_ATTR_ID, &attr->sh_loc, &attr_rc) < 0)
|
|
HGOTO_ERROR(H5E_ATTR, H5E_CANTGET, FAIL, "can't retrieve shared message ref count");
|
|
|
|
/* If this is not the first copy of the attribute in the shared message
|
|
* storage, decrement the reference count on any shared components
|
|
* of the attribute. This is done because the shared message
|
|
* storage's "try delete" call doesn't call the message class's
|
|
* "delete" callback until the reference count drops to zero.
|
|
* However, attributes have already increased the reference
|
|
* count on shared components before passing the attribute
|
|
* to the shared message code to manage, causing an asymmetry
|
|
* in the reference counting for any shared components.
|
|
*
|
|
* The alternate solution is to have the shared message's "try
|
|
* delete" code always call the message class's "delete" callback,
|
|
* even when the reference count is positive. This can be done
|
|
* without an appreciable performance hit (by using H5HF_op() in
|
|
* the shared message comparison v2 B-tree callback), but it has
|
|
* the undesirable side-effect of leaving the reference count on
|
|
* the attribute's shared components artificially (and possibly
|
|
* misleadingly) high, because there's only one shared attribute
|
|
* referencing the shared components, not <refcount for the
|
|
* shared attribute> objects referencing the shared components.
|
|
*
|
|
* *ick* -QAK, 2007/01/08
|
|
*/
|
|
if (attr_rc > 1) {
|
|
if (H5O__attr_delete(loc->file, oh, attr) < 0)
|
|
HGOTO_ERROR(H5E_ATTR, H5E_CANTDELETE, FAIL, "unable to delete attribute");
|
|
} /* end if */
|
|
} /* end if */
|
|
else if (shared_mesg < 0)
|
|
HGOTO_ERROR(H5E_ATTR, H5E_WRITEERROR, FAIL, "error determining if message should be shared");
|
|
|
|
/* Update the modification time, if any */
|
|
if (H5O_touch_oh(loc->file, oh, false) < 0)
|
|
HGOTO_ERROR(H5E_ATTR, H5E_CANTUPDATE, FAIL, "unable to update time on object");
|
|
|
|
done:
|
|
if (oh && H5O_unpin(oh) < 0)
|
|
HDONE_ERROR(H5E_ATTR, H5E_CANTUNPIN, FAIL, "unable to unpin object header");
|
|
|
|
FUNC_LEAVE_NOAPI(ret_value)
|
|
} /* end H5O__attr_create() */
|
|
|
|
/*-------------------------------------------------------------------------
|
|
* Function: H5O__attr_open_cb
|
|
*
|
|
* Purpose: Object header iterator callback routine to open an
|
|
* attribute stored compactly.
|
|
*
|
|
* Return: SUCCEED/FAIL
|
|
*
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
static herr_t
|
|
H5O__attr_open_cb(H5O_t *oh, H5O_mesg_t *mesg /*in,out*/, unsigned sequence,
|
|
unsigned H5_ATTR_UNUSED *oh_modified, void *_udata /*in,out*/)
|
|
{
|
|
H5O_iter_opn_t *udata = (H5O_iter_opn_t *)_udata; /* Operator user data */
|
|
herr_t ret_value = H5_ITER_CONT; /* Return value */
|
|
|
|
FUNC_ENTER_PACKAGE
|
|
|
|
/* check args */
|
|
assert(oh);
|
|
assert(mesg);
|
|
assert(!udata->attr);
|
|
|
|
/* Check for correct attribute message to modify */
|
|
if (strcmp(((H5A_t *)mesg->native)->shared->name, udata->name) == 0) {
|
|
/* Make a copy of the attribute to return */
|
|
if (NULL == (udata->attr = H5A__copy(NULL, (H5A_t *)mesg->native)))
|
|
HGOTO_ERROR(H5E_ATTR, H5E_CANTCOPY, H5_ITER_ERROR, "unable to copy attribute");
|
|
|
|
/* Assign [somewhat arbitrary] creation order value, for older versions
|
|
* of the format or if creation order is not tracked */
|
|
if (oh->version == H5O_VERSION_1 || !(oh->flags & H5O_HDR_ATTR_CRT_ORDER_TRACKED))
|
|
udata->attr->shared->crt_idx = sequence;
|
|
|
|
/* Stop iterating */
|
|
ret_value = H5_ITER_STOP;
|
|
} /* end if */
|
|
|
|
done:
|
|
FUNC_LEAVE_NOAPI(ret_value)
|
|
} /* end H5O__attr_open_cb() */
|
|
|
|
/*-------------------------------------------------------------------------
|
|
* Function: H5O__attr_open_by_name
|
|
*
|
|
* Purpose: Open an existing attribute in an object header.
|
|
*
|
|
* Return: SUCCEED/FAIL
|
|
*
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
H5A_t *
|
|
H5O__attr_open_by_name(const H5O_loc_t *loc, const char *name)
|
|
{
|
|
H5O_t *oh = NULL; /* Pointer to actual object header */
|
|
H5O_ainfo_t ainfo; /* Attribute information for object */
|
|
H5A_t *exist_attr = NULL; /* Existing opened attribute object */
|
|
H5A_t *opened_attr = NULL; /* Newly opened attribute object */
|
|
htri_t found_open_attr = false; /* Whether opened object is found */
|
|
H5A_t *ret_value = NULL; /* Return value */
|
|
|
|
FUNC_ENTER_PACKAGE_TAG(loc->addr)
|
|
|
|
/* Check arguments */
|
|
assert(loc);
|
|
assert(name);
|
|
|
|
/* Protect the object header to iterate over */
|
|
if (NULL == (oh = H5O_protect(loc, H5AC__READ_ONLY_FLAG, false)))
|
|
HGOTO_ERROR(H5E_ATTR, H5E_CANTPROTECT, NULL, "unable to load object header");
|
|
|
|
/* Check for attribute info stored */
|
|
ainfo.fheap_addr = HADDR_UNDEF;
|
|
if (oh->version > H5O_VERSION_1) {
|
|
/* Check for (& retrieve if available) attribute info */
|
|
if (H5A__get_ainfo(loc->file, oh, &ainfo) < 0)
|
|
HGOTO_ERROR(H5E_ATTR, H5E_CANTGET, NULL, "can't check for attribute info message");
|
|
} /* end if */
|
|
|
|
/* If found the attribute is already opened, make a copy of it to share the
|
|
* object information. If not, open attribute as a new object
|
|
*/
|
|
if ((found_open_attr = H5O__attr_find_opened_attr(loc, &exist_attr, name)) < 0)
|
|
HGOTO_ERROR(H5E_ATTR, H5E_CANTGET, NULL, "failed in finding opened attribute");
|
|
else if (found_open_attr == true) {
|
|
if (NULL == (opened_attr = H5A__copy(NULL, exist_attr)))
|
|
HGOTO_ERROR(H5E_ATTR, H5E_CANTCOPY, NULL, "can't copy existing attribute");
|
|
} /* end else if */
|
|
else {
|
|
/* Check for attributes in dense storage */
|
|
if (H5_addr_defined(ainfo.fheap_addr)) {
|
|
/* Open attribute with dense storage */
|
|
if (NULL == (opened_attr = H5A__dense_open(loc->file, &ainfo, name)))
|
|
HGOTO_ERROR(H5E_ATTR, H5E_CANTOPENOBJ, NULL, "can't open attribute");
|
|
} /* end if */
|
|
else {
|
|
H5O_iter_opn_t udata; /* User data for callback */
|
|
H5O_mesg_operator_t op; /* Wrapper for operator */
|
|
|
|
/* Set up user data for callback */
|
|
udata.name = name;
|
|
udata.attr = NULL;
|
|
|
|
/* Iterate over attributes, to locate correct one to open */
|
|
op.op_type = H5O_MESG_OP_LIB;
|
|
op.u.lib_op = H5O__attr_open_cb;
|
|
if (H5O__msg_iterate_real(loc->file, oh, H5O_MSG_ATTR, &op, &udata) < 0)
|
|
HGOTO_ERROR(H5E_ATTR, H5E_CANTOPENOBJ, NULL, "error updating attribute");
|
|
|
|
/* Check that we found the attribute */
|
|
if (!udata.attr)
|
|
HGOTO_ERROR(H5E_ATTR, H5E_NOTFOUND, NULL, "can't locate attribute: '%s'", name);
|
|
|
|
/* Get attribute opened from object header */
|
|
assert(udata.attr);
|
|
opened_attr = udata.attr;
|
|
} /* end else */
|
|
|
|
/* Mark datatype as being on disk now */
|
|
if (H5T_set_loc(opened_attr->shared->dt, H5F_VOL_OBJ(loc->file), H5T_LOC_DISK) < 0)
|
|
HGOTO_ERROR(H5E_ATTR, H5E_CANTINIT, NULL, "invalid datatype location");
|
|
} /* end else */
|
|
|
|
/* Set return value */
|
|
ret_value = opened_attr;
|
|
|
|
done:
|
|
if (oh && H5O_unprotect(loc, oh, H5AC__NO_FLAGS_SET) < 0)
|
|
HDONE_ERROR(H5E_ATTR, H5E_CANTUNPROTECT, NULL, "unable to release object header");
|
|
|
|
/* Release any resources, on error */
|
|
if (NULL == ret_value && opened_attr)
|
|
if (H5A__close(opened_attr) < 0)
|
|
HDONE_ERROR(H5E_ATTR, H5E_CANTCLOSEOBJ, NULL, "can't close attribute");
|
|
|
|
FUNC_LEAVE_NOAPI_TAG(ret_value)
|
|
} /* end H5O__attr_open_by_name() */
|
|
|
|
/*-------------------------------------------------------------------------
|
|
* Function: H5O__attr_open_by_idx_cb
|
|
*
|
|
* Purpose: Callback routine opening an attribute by index
|
|
*
|
|
* Return: SUCCEED/FAIL
|
|
*
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
static herr_t
|
|
H5O__attr_open_by_idx_cb(const H5A_t *attr, void *_ret_attr)
|
|
{
|
|
H5A_t **ret_attr = (H5A_t **)_ret_attr; /* 'User data' passed in */
|
|
herr_t ret_value = H5_ITER_STOP; /* Return value */
|
|
|
|
FUNC_ENTER_PACKAGE
|
|
|
|
/* check arguments */
|
|
assert(attr);
|
|
assert(ret_attr);
|
|
|
|
/* Copy attribute information. Shared some attribute information. */
|
|
if (NULL == (*ret_attr = H5A__copy(NULL, attr)))
|
|
HGOTO_ERROR(H5E_ATTR, H5E_CANTCOPY, H5_ITER_ERROR, "can't copy attribute");
|
|
|
|
done:
|
|
FUNC_LEAVE_NOAPI(ret_value)
|
|
} /* end H5O__attr_open_by_idx_cb() */
|
|
|
|
/*-------------------------------------------------------------------------
|
|
* Function: H5O__attr_open_by_idx
|
|
*
|
|
* Purpose: Open an existing attribute in an object header according to
|
|
* an index.
|
|
*
|
|
* Return: SUCCEED/FAIL
|
|
*
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
H5A_t *
|
|
H5O__attr_open_by_idx(const H5O_loc_t *loc, H5_index_t idx_type, H5_iter_order_t order, hsize_t n)
|
|
{
|
|
H5A_attr_iter_op_t attr_op; /* Attribute operator */
|
|
H5A_t *exist_attr = NULL; /* Existing opened attribute object */
|
|
H5A_t *opened_attr = NULL; /* Newly opened attribute object */
|
|
htri_t found_open_attr = false; /* Whether opened object is found */
|
|
H5A_t *ret_value = NULL; /* Return value */
|
|
|
|
FUNC_ENTER_PACKAGE
|
|
|
|
/* Check arguments */
|
|
assert(loc);
|
|
|
|
/* Build attribute operator info */
|
|
attr_op.op_type = H5A_ATTR_OP_LIB;
|
|
attr_op.u.lib_op = H5O__attr_open_by_idx_cb;
|
|
|
|
/* Iterate over attributes to locate correct one */
|
|
if (H5O_attr_iterate_real((hid_t)-1, loc, idx_type, order, n, NULL, &attr_op, &opened_attr) < 0)
|
|
HGOTO_ERROR(H5E_ATTR, H5E_BADITER, NULL, "can't locate attribute");
|
|
|
|
/* Find out whether it has already been opened. If it has, close the object
|
|
* and make a copy of the already opened object to share the object info.
|
|
*/
|
|
if (opened_attr) {
|
|
if ((found_open_attr = H5O__attr_find_opened_attr(loc, &exist_attr, opened_attr->shared->name)) < 0)
|
|
HGOTO_ERROR(H5E_ATTR, H5E_CANTGET, NULL, "failed in finding opened attribute");
|
|
|
|
/* If found that the attribute is already opened, make a copy of it
|
|
* and close the object just opened.
|
|
*/
|
|
if (found_open_attr && exist_attr) {
|
|
if (H5A__close(opened_attr) < 0)
|
|
HGOTO_ERROR(H5E_ATTR, H5E_CANTCLOSEOBJ, NULL, "can't close attribute");
|
|
if (NULL == (opened_attr = H5A__copy(NULL, exist_attr)))
|
|
HGOTO_ERROR(H5E_ATTR, H5E_CANTCOPY, NULL, "can't copy existing attribute");
|
|
}
|
|
else {
|
|
/* Mark datatype as being on disk now */
|
|
if (H5T_set_loc(opened_attr->shared->dt, H5F_VOL_OBJ(loc->file), H5T_LOC_DISK) < 0)
|
|
HGOTO_ERROR(H5E_ATTR, H5E_CANTINIT, NULL, "invalid datatype location");
|
|
} /* end if */
|
|
} /* end if */
|
|
|
|
/* Set return value */
|
|
ret_value = opened_attr;
|
|
|
|
done:
|
|
/* Release any resources, on error */
|
|
if (NULL == ret_value && opened_attr)
|
|
if (H5A__close(opened_attr) < 0)
|
|
HDONE_ERROR(H5E_ATTR, H5E_CANTCLOSEOBJ, NULL, "can't close attribute");
|
|
|
|
FUNC_LEAVE_NOAPI(ret_value)
|
|
} /* end H5O__attr_open_by_idx() */
|
|
|
|
/*-------------------------------------------------------------------------
|
|
* Function: H5O__attr_find_opened_attr
|
|
*
|
|
* Purpose: Find out whether an attribute has been opened by giving
|
|
* the name. Return the pointer to the object if found.
|
|
*
|
|
* Return: true: found the already opened object
|
|
* false: didn't find the opened object
|
|
* FAIL: function failed.
|
|
*
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
static htri_t
|
|
H5O__attr_find_opened_attr(const H5O_loc_t *loc, H5A_t **attr, const char *name_to_open)
|
|
{
|
|
hid_t *attr_id_list = NULL; /* List of IDs for opened attributes */
|
|
unsigned long loc_fnum; /* File serial # for object */
|
|
size_t num_open_attr; /* Number of opened attributes */
|
|
htri_t ret_value = false; /* Return value */
|
|
|
|
FUNC_ENTER_PACKAGE
|
|
|
|
/* Get file serial number for the location of attribute */
|
|
if (H5F_get_fileno(loc->file, &loc_fnum) < 0)
|
|
HGOTO_ERROR(H5E_ATTR, H5E_BADVALUE, FAIL, "can't get file serial number");
|
|
|
|
/* Count all opened attributes */
|
|
if (H5F_get_obj_count(loc->file, H5F_OBJ_ATTR | H5F_OBJ_LOCAL, false, &num_open_attr) < 0)
|
|
HGOTO_ERROR(H5E_ATTR, H5E_CANTGET, FAIL, "can't count opened attributes");
|
|
|
|
/* Find out whether the attribute has been opened */
|
|
if (num_open_attr) {
|
|
size_t check_num_attr; /* Number of open attribute IDs */
|
|
size_t u; /* Local index variable */
|
|
|
|
/* Allocate space for the attribute ID list */
|
|
if (NULL == (attr_id_list = (hid_t *)H5MM_malloc(num_open_attr * sizeof(hid_t))))
|
|
HGOTO_ERROR(H5E_ATTR, H5E_CANTALLOC, FAIL, "unable to allocate memory for attribute ID list");
|
|
|
|
/* Retrieve the IDs of all opened attributes */
|
|
if (H5F_get_obj_ids(loc->file, H5F_OBJ_ATTR | H5F_OBJ_LOCAL, num_open_attr, attr_id_list, false,
|
|
&check_num_attr) < 0)
|
|
HGOTO_ERROR(H5E_ATTR, H5E_CANTGET, FAIL, "can't get IDs of opened attributes");
|
|
if (check_num_attr != num_open_attr)
|
|
HGOTO_ERROR(H5E_ATTR, H5E_BADITER, FAIL, "open attribute count mismatch");
|
|
|
|
/* Iterate over the attributes */
|
|
for (u = 0; u < num_open_attr; u++) {
|
|
unsigned long attr_fnum; /* Attributes file serial number */
|
|
|
|
/* Get pointer to attribute */
|
|
if (NULL == (*attr = (H5A_t *)H5VL_object_verify(attr_id_list[u], H5I_ATTR)))
|
|
HGOTO_ERROR(H5E_ATTR, H5E_BADTYPE, FAIL, "not an attribute");
|
|
|
|
/* Get file serial number for attribute */
|
|
if (H5F_get_fileno((*attr)->oloc.file, &attr_fnum) < 0)
|
|
HGOTO_ERROR(H5E_ATTR, H5E_BADVALUE, FAIL, "can't get file serial number");
|
|
|
|
/* Verify whether it's the right object. The attribute name, object
|
|
* address to which the attribute is attached, and file serial
|
|
* number should all match.
|
|
*/
|
|
if (!strcmp(name_to_open, (*attr)->shared->name) && loc->addr == (*attr)->oloc.addr &&
|
|
loc_fnum == attr_fnum) {
|
|
ret_value = true;
|
|
break;
|
|
} /* end if */
|
|
} /* end for */
|
|
} /* end if */
|
|
|
|
done:
|
|
if (attr_id_list)
|
|
H5MM_free(attr_id_list);
|
|
|
|
FUNC_LEAVE_NOAPI(ret_value)
|
|
} /* end H5O__attr_find_opened_attr() */
|
|
|
|
/*-------------------------------------------------------------------------
|
|
* Function: H5O__attr_update_shared
|
|
*
|
|
* Purpose: Update a shared attribute.
|
|
*
|
|
* Return: SUCCEED/FAIL
|
|
*
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
herr_t
|
|
H5O__attr_update_shared(H5F_t *f, H5O_t *oh, H5A_t *attr, H5O_shared_t *update_sh_mesg)
|
|
{
|
|
H5O_shared_t sh_mesg; /* Shared object header message */
|
|
hsize_t attr_rc; /* Attribute's ref count in shared message storage */
|
|
htri_t shared_mesg; /* Whether the message should be shared */
|
|
herr_t ret_value = SUCCEED; /* Return value */
|
|
|
|
FUNC_ENTER_PACKAGE
|
|
|
|
/* check args */
|
|
assert(f);
|
|
assert(attr);
|
|
|
|
/* Extract shared message info from current attribute (for later use) */
|
|
if (H5O_set_shared(&sh_mesg, &(attr->sh_loc)) < 0)
|
|
HGOTO_ERROR(H5E_ATTR, H5E_CANTCOPY, FAIL, "can't get shared message");
|
|
|
|
/* Reset existing sharing information */
|
|
if (H5O_msg_reset_share(H5O_ATTR_ID, attr) < 0)
|
|
HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, FAIL, "unable to reset attribute sharing");
|
|
|
|
/* 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(f, oh, 0, H5O_ATTR_ID, attr, NULL)) == 0)
|
|
HGOTO_ERROR(H5E_ATTR, H5E_BADMESG, FAIL, "attribute changed sharing status");
|
|
else if (shared_mesg < 0)
|
|
HGOTO_ERROR(H5E_ATTR, H5E_BADMESG, FAIL, "can't share attribute");
|
|
|
|
/* Retrieve shared message storage ref count for new shared attribute */
|
|
if (H5SM_get_refcount(f, H5O_ATTR_ID, &attr->sh_loc, &attr_rc) < 0)
|
|
HGOTO_ERROR(H5E_ATTR, H5E_CANTGET, FAIL, "can't retrieve shared message ref count");
|
|
|
|
/* If the newly shared attribute needs to share "ownership" of the shared
|
|
* components (ie. its reference count is 1), increment the reference
|
|
* count on any shared components of the attribute, so that they won't
|
|
* be removed from the file by the following "delete" operation on the
|
|
* original attribute shared message info. (Essentially a "copy on
|
|
* write" operation).
|
|
*
|
|
* *ick* -QAK, 2007/01/08
|
|
*/
|
|
if (attr_rc == 1)
|
|
/* Increment reference count on attribute components */
|
|
if (H5O__attr_link(f, oh, attr) < 0)
|
|
HGOTO_ERROR(H5E_ATTR, H5E_LINKCOUNT, FAIL, "unable to adjust attribute link count");
|
|
|
|
/* Remove the old attribute from the SOHM storage */
|
|
if (H5SM_delete(f, oh, &sh_mesg) < 0)
|
|
HGOTO_ERROR(H5E_ATTR, H5E_CANTFREE, FAIL, "unable to delete shared attribute in shared storage");
|
|
|
|
/* Extract updated shared message info from modified attribute, if requested */
|
|
if (update_sh_mesg)
|
|
if (H5O_set_shared(update_sh_mesg, &(attr->sh_loc)) < 0)
|
|
HGOTO_ERROR(H5E_ATTR, H5E_CANTCOPY, FAIL, "can't get shared message");
|
|
|
|
done:
|
|
FUNC_LEAVE_NOAPI(ret_value)
|
|
} /* end H5O__attr_update_shared() */
|
|
|
|
/*-------------------------------------------------------------------------
|
|
* Function: H5O__attr_write_cb
|
|
*
|
|
* Purpose: Object header iterator callback routine to update an
|
|
* attribute stored compactly.
|
|
*
|
|
* Return: SUCCEED/FAIL
|
|
*
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
static herr_t
|
|
H5O__attr_write_cb(H5O_t *oh, H5O_mesg_t *mesg /*in,out*/, unsigned H5_ATTR_UNUSED sequence,
|
|
unsigned *oh_modified, void *_udata /*in,out*/)
|
|
{
|
|
H5O_iter_wrt_t *udata = (H5O_iter_wrt_t *)_udata; /* Operator user data */
|
|
H5O_chunk_proxy_t *chk_proxy = NULL; /* Chunk that message is in */
|
|
bool chk_dirtied = false; /* Flag for unprotecting chunk */
|
|
herr_t ret_value = H5_ITER_CONT; /* Return value */
|
|
|
|
FUNC_ENTER_PACKAGE
|
|
|
|
/* check args */
|
|
assert(oh);
|
|
assert(mesg);
|
|
assert(!udata->found);
|
|
|
|
/* Check for correct attribute message to modify */
|
|
if (0 == strcmp(((H5A_t *)mesg->native)->shared->name, udata->attr->shared->name)) {
|
|
/* Protect chunk */
|
|
if (NULL == (chk_proxy = H5O__chunk_protect(udata->f, oh, mesg->chunkno)))
|
|
HGOTO_ERROR(H5E_ATTR, H5E_CANTPROTECT, H5_ITER_ERROR, "unable to load object header chunk");
|
|
|
|
/* Because the attribute structure is shared now. The only situation that requires
|
|
* copying the data is when the metadata cache evicts and reloads this attribute.
|
|
* The shared attribute structure will be different in that situation. SLU-2010/7/29 */
|
|
if (((H5A_t *)mesg->native)->shared != udata->attr->shared) {
|
|
/* Sanity check */
|
|
assert(((H5A_t *)mesg->native)->shared->data);
|
|
assert(udata->attr->shared->data);
|
|
assert(((H5A_t *)mesg->native)->shared->data != udata->attr->shared->data);
|
|
|
|
/* (Needs to occur before updating the shared message, or the hash
|
|
* value on the old & new messages will be the same) */
|
|
H5MM_memcpy(((H5A_t *)mesg->native)->shared->data, udata->attr->shared->data,
|
|
udata->attr->shared->data_size);
|
|
} /* end if */
|
|
|
|
/* Mark the message as modified */
|
|
mesg->dirty = true;
|
|
chk_dirtied = true;
|
|
|
|
/* Release chunk */
|
|
if (H5O__chunk_unprotect(udata->f, chk_proxy, chk_dirtied) < 0)
|
|
HGOTO_ERROR(H5E_ATTR, H5E_CANTUNPROTECT, H5_ITER_ERROR,
|
|
"unable to unprotect object header chunk");
|
|
chk_proxy = NULL;
|
|
|
|
/* Update the shared attribute in the SOHM storage */
|
|
if (mesg->flags & H5O_MSG_FLAG_SHARED)
|
|
if (H5O__attr_update_shared(udata->f, oh, udata->attr, (H5O_shared_t *)mesg->native) < 0)
|
|
HGOTO_ERROR(H5E_ATTR, H5E_CANTUPDATE, H5_ITER_ERROR,
|
|
"unable to update attribute in shared storage");
|
|
|
|
/* Indicate that the object header was modified */
|
|
*oh_modified = H5O_MODIFY;
|
|
|
|
/* Indicate that the attribute was found */
|
|
udata->found = true;
|
|
|
|
/* Stop iterating */
|
|
ret_value = H5_ITER_STOP;
|
|
} /* end if */
|
|
|
|
done:
|
|
/* Release chunk, if not already done */
|
|
if (chk_proxy && H5O__chunk_unprotect(udata->f, chk_proxy, chk_dirtied) < 0)
|
|
HDONE_ERROR(H5E_ATTR, H5E_CANTUNPROTECT, H5_ITER_ERROR, "unable to unprotect object header chunk");
|
|
|
|
FUNC_LEAVE_NOAPI(ret_value)
|
|
} /* end H5O__attr_write_cb() */
|
|
|
|
/*-------------------------------------------------------------------------
|
|
* Function: H5O__attr_write
|
|
*
|
|
* Purpose: Write a new value to an attribute.
|
|
*
|
|
* Return: SUCCEED/FAIL
|
|
*
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
herr_t
|
|
H5O__attr_write(const H5O_loc_t *loc, H5A_t *attr)
|
|
{
|
|
H5O_t *oh = NULL; /* Pointer to actual object header */
|
|
H5O_ainfo_t ainfo; /* Attribute information for object */
|
|
herr_t ret_value = SUCCEED; /* Return value */
|
|
|
|
FUNC_ENTER_PACKAGE
|
|
|
|
/* Check arguments */
|
|
assert(loc);
|
|
assert(attr);
|
|
|
|
/* Pin the object header */
|
|
if (NULL == (oh = H5O_pin(loc)))
|
|
HGOTO_ERROR(H5E_ATTR, H5E_CANTPIN, FAIL, "unable to pin object header");
|
|
|
|
/* Check for attribute info stored */
|
|
ainfo.fheap_addr = HADDR_UNDEF;
|
|
if (oh->version > H5O_VERSION_1) {
|
|
/* Check for (& retrieve if available) attribute info */
|
|
if (H5A__get_ainfo(loc->file, oh, &ainfo) < 0)
|
|
HGOTO_ERROR(H5E_ATTR, H5E_CANTGET, FAIL, "can't check for attribute info message");
|
|
} /* end if */
|
|
|
|
/* Check for attributes stored densely */
|
|
if (H5_addr_defined(ainfo.fheap_addr)) {
|
|
/* Modify the attribute data in dense storage */
|
|
if (H5A__dense_write(loc->file, &ainfo, 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.attr = attr;
|
|
udata.found = false;
|
|
|
|
/* Iterate over attributes, to locate correct one to update */
|
|
op.op_type = H5O_MESG_OP_LIB;
|
|
op.u.lib_op = H5O__attr_write_cb;
|
|
if (H5O__msg_iterate_real(loc->file, oh, H5O_MSG_ATTR, &op, &udata) < 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, oh, false) < 0)
|
|
HGOTO_ERROR(H5E_ATTR, H5E_CANTUPDATE, FAIL, "unable to update time on object");
|
|
|
|
done:
|
|
if (oh && H5O_unpin(oh) < 0)
|
|
HDONE_ERROR(H5E_ATTR, H5E_CANTUNPIN, FAIL, "unable to unpin object header");
|
|
|
|
FUNC_LEAVE_NOAPI(ret_value)
|
|
} /* end H5O__attr_write */
|
|
|
|
/*-------------------------------------------------------------------------
|
|
* Function: H5O__attr_rename_chk_cb
|
|
*
|
|
* Purpose: Object header iterator callback routine to check for
|
|
* duplicate name during rename
|
|
*
|
|
* Return: SUCCEED/FAIL
|
|
*
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
static herr_t
|
|
H5O__attr_rename_chk_cb(H5O_t H5_ATTR_UNUSED *oh, H5O_mesg_t *mesg /*in,out*/,
|
|
unsigned H5_ATTR_UNUSED sequence, unsigned H5_ATTR_UNUSED *oh_modified,
|
|
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_PACKAGE_NOERR
|
|
|
|
/* check args */
|
|
assert(oh);
|
|
assert(mesg);
|
|
assert(!udata->found);
|
|
|
|
/* Check for existing attribute with new name */
|
|
if (strcmp(((H5A_t *)mesg->native)->shared->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 */
|
|
|
|
FUNC_LEAVE_NOAPI(ret_value)
|
|
} /* end H5O__attr_rename_chk_cb() */
|
|
|
|
/*-------------------------------------------------------------------------
|
|
* Function: H5O__attr_rename_mod_cb
|
|
*
|
|
* Purpose: Object header iterator callback routine to change name of
|
|
* attribute during rename
|
|
*
|
|
* Note: This routine doesn't currently allow an attribute to change
|
|
* its "shared" status, if the name change would cause a size
|
|
* difference that would put it into a different category.
|
|
* Something for later...
|
|
*
|
|
* Return: SUCCEED/FAIL
|
|
*
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
static herr_t
|
|
H5O__attr_rename_mod_cb(H5O_t *oh, H5O_mesg_t *mesg /*in,out*/, unsigned H5_ATTR_UNUSED sequence,
|
|
unsigned *oh_modified, void *_udata /*in,out*/)
|
|
{
|
|
H5O_iter_ren_t *udata = (H5O_iter_ren_t *)_udata; /* Operator user data */
|
|
H5O_chunk_proxy_t *chk_proxy = NULL; /* Chunk that message is in */
|
|
bool chk_dirtied = false; /* Flag for unprotecting chunk */
|
|
herr_t ret_value = H5_ITER_CONT; /* Return value */
|
|
|
|
FUNC_ENTER_PACKAGE
|
|
|
|
/* check args */
|
|
assert(oh);
|
|
assert(mesg);
|
|
assert(!udata->found);
|
|
|
|
/* Find correct attribute message to rename */
|
|
if (strcmp(((H5A_t *)mesg->native)->shared->name, udata->old_name) == 0) {
|
|
unsigned old_version = ((H5A_t *)mesg->native)->shared->version; /* Old version of the attribute */
|
|
|
|
/* Protect chunk */
|
|
if (NULL == (chk_proxy = H5O__chunk_protect(udata->f, oh, mesg->chunkno)))
|
|
HGOTO_ERROR(H5E_ATTR, H5E_CANTPROTECT, H5_ITER_ERROR, "unable to load object header chunk");
|
|
|
|
/* Change the name for the attribute */
|
|
H5MM_xfree(((H5A_t *)mesg->native)->shared->name);
|
|
((H5A_t *)mesg->native)->shared->name = H5MM_xstrdup(udata->new_name);
|
|
|
|
/* Recompute the version to encode the attribute with */
|
|
if (H5A__set_version(udata->f, ((H5A_t *)mesg->native)) < 0)
|
|
HGOTO_ERROR(H5E_ATTR, H5E_CANTSET, H5_ITER_ERROR, "unable to update attribute version");
|
|
|
|
/* Mark the message as modified */
|
|
mesg->dirty = true;
|
|
chk_dirtied = true;
|
|
|
|
/* Release chunk */
|
|
if (H5O__chunk_unprotect(udata->f, chk_proxy, chk_dirtied) < 0)
|
|
HGOTO_ERROR(H5E_ATTR, H5E_CANTUNPROTECT, H5_ITER_ERROR,
|
|
"unable to unprotect object header chunk");
|
|
chk_proxy = NULL;
|
|
|
|
/* Check for shared message */
|
|
if (mesg->flags & H5O_MSG_FLAG_SHARED) {
|
|
/* Update the shared attribute in the SOHM storage */
|
|
if (H5O__attr_update_shared(udata->f, oh, (H5A_t *)mesg->native, NULL) < 0)
|
|
HGOTO_ERROR(H5E_ATTR, H5E_CANTUPDATE, H5_ITER_ERROR,
|
|
"unable to update attribute in shared storage");
|
|
} /* end if */
|
|
else {
|
|
/* Sanity check */
|
|
assert(H5O_msg_is_shared(H5O_ATTR_ID, (H5A_t *)mesg->native) == false);
|
|
|
|
/* Check for attribute message changing size */
|
|
if (strlen(udata->new_name) != strlen(udata->old_name) ||
|
|
old_version != ((H5A_t *)mesg->native)->shared->version) {
|
|
H5A_t *attr; /* Attribute to re-add */
|
|
|
|
/* Take ownership of the message's native info (the attribute)
|
|
* so any shared objects in the file aren't adjusted (and
|
|
* possibly deleted) when the message is released.
|
|
*/
|
|
/* (We do this more complicated sequence of actions because the
|
|
* simpler solution of adding the modified attribute first
|
|
* and then deleting the old message can re-allocate the
|
|
* list of messages during the "add the modified attribute"
|
|
* step, invalidating the message pointer we have here - QAK)
|
|
*/
|
|
attr = (H5A_t *)mesg->native;
|
|
mesg->native = NULL;
|
|
|
|
/* Delete old attribute */
|
|
/* (doesn't decrement the link count on shared components because
|
|
* the "native" pointer has been reset)
|
|
*/
|
|
if (H5O__release_mesg(udata->f, oh, mesg, false) < 0)
|
|
HGOTO_ERROR(H5E_ATTR, H5E_CANTDELETE, H5_ITER_ERROR,
|
|
"unable to release previous attribute");
|
|
|
|
*oh_modified = H5O_MODIFY_CONDENSE;
|
|
|
|
/* Append renamed attribute to object header */
|
|
/* (Don't let it become shared) */
|
|
if (H5O__msg_append_real(udata->f, oh, H5O_MSG_ATTR, (mesg->flags | H5O_MSG_FLAG_DONTSHARE),
|
|
0, attr) < 0)
|
|
HGOTO_ERROR(H5E_ATTR, H5E_CANTINSERT, H5_ITER_ERROR,
|
|
"unable to relocate renamed attribute in header");
|
|
|
|
/* Sanity check */
|
|
assert(H5O_msg_is_shared(H5O_ATTR_ID, attr) == false);
|
|
|
|
/* Close the local copy of the attribute */
|
|
H5A__close(attr);
|
|
} /* end if */
|
|
} /* end else */
|
|
|
|
/* Indicate that the object header was modified */
|
|
*oh_modified |= H5O_MODIFY;
|
|
|
|
/* Indicate that we found an existing attribute with the old name */
|
|
udata->found = true;
|
|
|
|
/* Stop iterating */
|
|
ret_value = H5_ITER_STOP;
|
|
} /* end if */
|
|
|
|
done:
|
|
/* Release chunk, if not already done */
|
|
if (chk_proxy && H5O__chunk_unprotect(udata->f, chk_proxy, chk_dirtied) < 0)
|
|
HDONE_ERROR(H5E_ATTR, H5E_CANTUNPROTECT, H5_ITER_ERROR, "unable to unprotect object header chunk");
|
|
|
|
FUNC_LEAVE_NOAPI(ret_value)
|
|
} /* end H5O__attr_rename_mod_cb() */
|
|
|
|
/*-------------------------------------------------------------------------
|
|
* Function: H5O__attr_rename
|
|
*
|
|
* Purpose: Rename an attribute.
|
|
*
|
|
* Return: SUCCEED/FAIL
|
|
*
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
herr_t
|
|
H5O__attr_rename(const H5O_loc_t *loc, const char *old_name, const char *new_name)
|
|
{
|
|
H5O_t *oh = NULL; /* Pointer to actual object header */
|
|
H5O_ainfo_t ainfo; /* Attribute information for object */
|
|
herr_t ret_value = SUCCEED; /* Return value */
|
|
|
|
FUNC_ENTER_PACKAGE_TAG(loc->addr)
|
|
|
|
/* Check arguments */
|
|
assert(loc);
|
|
assert(old_name);
|
|
assert(new_name);
|
|
|
|
/* Pin the object header */
|
|
if (NULL == (oh = H5O_pin(loc)))
|
|
HGOTO_ERROR(H5E_ATTR, H5E_CANTPIN, FAIL, "unable to pin object header");
|
|
|
|
/* Check for attribute info stored */
|
|
ainfo.fheap_addr = HADDR_UNDEF;
|
|
if (oh->version > H5O_VERSION_1) {
|
|
/* Check for (& retrieve if available) attribute info */
|
|
if (H5A__get_ainfo(loc->file, oh, &ainfo) < 0)
|
|
HGOTO_ERROR(H5E_ATTR, H5E_CANTGET, FAIL, "can't check for attribute info message");
|
|
} /* end if */
|
|
|
|
/* Check for attributes stored densely */
|
|
if (H5_addr_defined(ainfo.fheap_addr)) {
|
|
/* Rename the attribute data in dense storage */
|
|
if (H5A__dense_rename(loc->file, &ainfo, old_name, new_name) < 0)
|
|
HGOTO_ERROR(H5E_ATTR, H5E_CANTUPDATE, FAIL, "error updating attribute");
|
|
} /* 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.old_name = old_name;
|
|
udata.new_name = new_name;
|
|
udata.found = false;
|
|
|
|
/* Iterate over attributes, to check if "new name" exists already */
|
|
op.op_type = H5O_MESG_OP_LIB;
|
|
op.u.lib_op = H5O__attr_rename_chk_cb;
|
|
if (H5O__msg_iterate_real(loc->file, oh, H5O_MSG_ATTR, &op, &udata) < 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.op_type = H5O_MESG_OP_LIB;
|
|
op.u.lib_op = H5O__attr_rename_mod_cb;
|
|
if (H5O__msg_iterate_real(loc->file, oh, H5O_MSG_ATTR, &op, &udata) < 0)
|
|
HGOTO_ERROR(H5E_ATTR, H5E_CANTUPDATE, FAIL, "error updating attribute");
|
|
|
|
/* Check that we found the attribute to rename */
|
|
if (!udata.found)
|
|
HGOTO_ERROR(H5E_ATTR, H5E_NOTFOUND, FAIL, "can't locate attribute with old name");
|
|
} /* end else */
|
|
|
|
/* Update the modification time, if any */
|
|
if (H5O_touch_oh(loc->file, oh, false) < 0)
|
|
HGOTO_ERROR(H5E_ATTR, H5E_CANTUPDATE, FAIL, "unable to update time on object");
|
|
|
|
done:
|
|
if (oh && H5O_unpin(oh) < 0)
|
|
HDONE_ERROR(H5E_ATTR, H5E_CANTUNPIN, FAIL, "unable to unpin object header");
|
|
|
|
FUNC_LEAVE_NOAPI_TAG(ret_value)
|
|
} /* end H5O__attr_rename() */
|
|
|
|
/*-------------------------------------------------------------------------
|
|
* Function: H5O_attr_iterate_real
|
|
*
|
|
* Purpose: Internal routine to iterate over attributes for an object.
|
|
*
|
|
* Return: SUCCEED/FAIL
|
|
*
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
herr_t
|
|
H5O_attr_iterate_real(hid_t loc_id, const H5O_loc_t *loc, H5_index_t idx_type, H5_iter_order_t order,
|
|
hsize_t skip, hsize_t *last_attr, const H5A_attr_iter_op_t *attr_op, void *op_data)
|
|
{
|
|
H5O_t *oh = NULL; /* Pointer to actual object header */
|
|
H5O_ainfo_t ainfo; /* Attribute information for object */
|
|
H5A_attr_table_t atable = {0, 0, NULL}; /* Table of attributes */
|
|
herr_t ret_value = FAIL; /* Return value */
|
|
|
|
FUNC_ENTER_NOAPI_NOINIT_TAG(loc->addr)
|
|
|
|
/* Check arguments */
|
|
assert(loc);
|
|
assert(loc->file);
|
|
assert(H5_addr_defined(loc->addr));
|
|
assert(attr_op);
|
|
|
|
/* Protect the object header to iterate over */
|
|
if (NULL == (oh = H5O_protect(loc, H5AC__READ_ONLY_FLAG, false)))
|
|
HGOTO_ERROR(H5E_ATTR, H5E_CANTPROTECT, FAIL, "unable to load object header");
|
|
|
|
/* Check for attribute info stored */
|
|
ainfo.fheap_addr = HADDR_UNDEF;
|
|
if (oh->version > H5O_VERSION_1) {
|
|
/* Check for (& retrieve if available) attribute info */
|
|
if (H5A__get_ainfo(loc->file, oh, &ainfo) < 0)
|
|
HGOTO_ERROR(H5E_ATTR, H5E_CANTGET, FAIL, "can't check for attribute info message");
|
|
} /* end if */
|
|
|
|
/* Check for attributes stored densely */
|
|
if (H5_addr_defined(ainfo.fheap_addr)) {
|
|
/* Check for skipping too many attributes */
|
|
if (skip > 0 && skip >= ainfo.nattrs)
|
|
HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid index specified");
|
|
|
|
/* Release the object header */
|
|
if (H5O_unprotect(loc, oh, H5AC__NO_FLAGS_SET) < 0)
|
|
HGOTO_ERROR(H5E_ATTR, H5E_CANTUNPROTECT, FAIL, "unable to release object header");
|
|
oh = NULL;
|
|
|
|
/* Iterate over attributes in dense storage */
|
|
if ((ret_value = H5A__dense_iterate(loc->file, loc_id, &ainfo, idx_type, order, skip, last_attr,
|
|
attr_op, op_data)) < 0)
|
|
HERROR(H5E_ATTR, H5E_BADITER, "error iterating over attributes");
|
|
} /* end if */
|
|
else {
|
|
/* Build table of attributes for compact storage */
|
|
if (H5A__compact_build_table(loc->file, oh, idx_type, order, &atable) < 0)
|
|
HGOTO_ERROR(H5E_ATTR, H5E_CANTINIT, FAIL, "error building attribute table");
|
|
|
|
/* Release the object header */
|
|
if (H5O_unprotect(loc, oh, H5AC__NO_FLAGS_SET) < 0)
|
|
HGOTO_ERROR(H5E_ATTR, H5E_CANTUNPROTECT, FAIL, "unable to release object header");
|
|
oh = NULL;
|
|
|
|
/* Check for skipping too many attributes */
|
|
if (skip > 0 && skip >= atable.num_attrs)
|
|
HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid index specified");
|
|
|
|
/* Iterate over attributes in table */
|
|
if ((ret_value = H5A__attr_iterate_table(&atable, skip, last_attr, loc_id, attr_op, op_data)) < 0)
|
|
HERROR(H5E_ATTR, H5E_BADITER, "iteration operator failed");
|
|
} /* end else */
|
|
|
|
done:
|
|
/* Release resources */
|
|
if (oh && H5O_unprotect(loc, oh, H5AC__NO_FLAGS_SET) < 0)
|
|
HDONE_ERROR(H5E_ATTR, H5E_CANTUNPROTECT, FAIL, "unable to release object header");
|
|
if (atable.attrs && H5A__attr_release_table(&atable) < 0)
|
|
HDONE_ERROR(H5E_ATTR, H5E_CANTFREE, FAIL, "unable to release attribute table");
|
|
|
|
FUNC_LEAVE_NOAPI_TAG(ret_value)
|
|
} /* end H5O_attr_iterate_real() */
|
|
|
|
/*-------------------------------------------------------------------------
|
|
* Function: H5O__attr_iterate
|
|
*
|
|
* Purpose: Iterate over attributes for an object.
|
|
*
|
|
* Return: SUCCEED/FAIL
|
|
*
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
herr_t
|
|
H5O__attr_iterate(hid_t loc_id, H5_index_t idx_type, H5_iter_order_t order, hsize_t skip, hsize_t *last_attr,
|
|
const H5A_attr_iter_op_t *attr_op, void *op_data)
|
|
{
|
|
H5G_loc_t loc; /* Object location */
|
|
herr_t ret_value = FAIL; /* Return value */
|
|
|
|
FUNC_ENTER_PACKAGE
|
|
|
|
/* Check arguments */
|
|
assert(attr_op);
|
|
|
|
/* Look up location for location ID */
|
|
if (H5G_loc(loc_id, &loc) < 0)
|
|
HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a location");
|
|
|
|
/* Iterate over attributes to locate correct one */
|
|
if ((ret_value =
|
|
H5O_attr_iterate_real(loc_id, loc.oloc, idx_type, order, skip, last_attr, attr_op, op_data)) < 0)
|
|
HERROR(H5E_ATTR, H5E_BADITER, "error iterating over attributes");
|
|
|
|
done:
|
|
FUNC_LEAVE_NOAPI(ret_value)
|
|
} /* end H5O__attr_iterate() */
|
|
|
|
/*-------------------------------------------------------------------------
|
|
* Function: H5O__attr_remove_update
|
|
*
|
|
* Purpose: Check for reverting from dense to compact attribute storage
|
|
*
|
|
* When converting storage from dense to compact, if found
|
|
* the attribute is already opened, use the opened message
|
|
* to insert. If not, still use the message in the attribute
|
|
* table. This will guarantee that the attribute message is
|
|
* shared between the object in metadata cache and the opened
|
|
* object.
|
|
*
|
|
* Return: SUCCEED/FAIL
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
static herr_t
|
|
H5O__attr_remove_update(const H5O_loc_t *loc, H5O_t *oh, H5O_ainfo_t *ainfo)
|
|
{
|
|
H5A_attr_table_t atable = {0, 0, NULL}; /* Table of attributes */
|
|
herr_t ret_value = SUCCEED; /* Return value */
|
|
|
|
FUNC_ENTER_PACKAGE
|
|
|
|
/* Check arguments */
|
|
assert(loc);
|
|
assert(oh);
|
|
assert(ainfo);
|
|
|
|
/* Decrement the number of attributes on the object */
|
|
ainfo->nattrs--;
|
|
|
|
/* Check for shifting from dense storage back to compact storage */
|
|
if (H5_addr_defined(ainfo->fheap_addr) && ainfo->nattrs < oh->min_dense) {
|
|
bool can_convert = true; /* Whether converting to attribute messages is possible */
|
|
size_t u; /* Local index */
|
|
|
|
/* Build the table of attributes for this object */
|
|
if (H5A__dense_build_table(loc->file, ainfo, H5_INDEX_NAME, H5_ITER_NATIVE, &atable) < 0)
|
|
HGOTO_ERROR(H5E_ATTR, H5E_CANTINIT, FAIL, "error building attribute table");
|
|
|
|
/* Inspect attributes in table for ones that can't be converted back
|
|
* into attribute message form (currently only attributes which
|
|
* can't fit into an object header message)
|
|
*/
|
|
for (u = 0; u < ainfo->nattrs; u++)
|
|
if (H5O_msg_size_oh(loc->file, oh, H5O_ATTR_ID, (atable.attrs[u]), (size_t)0) >=
|
|
H5O_MESG_MAX_SIZE) {
|
|
can_convert = false;
|
|
break;
|
|
} /* end if */
|
|
|
|
/* If ok, insert attributes as object header messages */
|
|
if (can_convert) {
|
|
H5A_t *exist_attr = NULL;
|
|
htri_t found_open_attr = false;
|
|
|
|
/* Iterate over attributes, to put them into header */
|
|
for (u = 0; u < ainfo->nattrs; u++) {
|
|
htri_t shared_mesg; /* Should this message be stored in the Shared Message table? */
|
|
|
|
/* Check if attribute is shared */
|
|
if ((shared_mesg = H5O_msg_is_shared(H5O_ATTR_ID, (atable.attrs[u]))) < 0)
|
|
HGOTO_ERROR(H5E_ATTR, H5E_CANTGET, FAIL, "error determining if message is shared");
|
|
else if (shared_mesg == 0) {
|
|
/* Increment reference count on attribute components */
|
|
/* (so that they aren't deleted when the dense attribute storage is deleted) */
|
|
if (H5O__attr_link(loc->file, oh, (atable.attrs[u])) < 0)
|
|
HGOTO_ERROR(H5E_ATTR, H5E_LINKCOUNT, FAIL, "unable to adjust attribute link count");
|
|
} /* end if */
|
|
else {
|
|
/* Reset 'shared' status, so attribute will be shared again */
|
|
(atable.attrs[u])->sh_loc.type = H5O_SHARE_TYPE_UNSHARED;
|
|
} /* end else */
|
|
|
|
/* Insert attribute message into object header (Will increment
|
|
reference count on shared attributes) */
|
|
/* Find out whether the attribute has been opened */
|
|
if ((found_open_attr =
|
|
H5O__attr_find_opened_attr(loc, &exist_attr, (atable.attrs[u])->shared->name)) < 0)
|
|
HGOTO_ERROR(H5E_ATTR, H5E_CANTGET, FAIL, "failed in finding opened attribute");
|
|
|
|
/* If found the attribute is already opened, use the opened message to insert.
|
|
If not, still use the message in the attribute table. */
|
|
if (found_open_attr && exist_attr) {
|
|
if (H5O__msg_append_real(loc->file, oh, H5O_MSG_ATTR, 0, 0, exist_attr) < 0)
|
|
HGOTO_ERROR(H5E_ATTR, H5E_CANTINIT, FAIL, "can't create message");
|
|
|
|
} /* end if */
|
|
else if (H5O__msg_append_real(loc->file, oh, H5O_MSG_ATTR, 0, 0, (atable.attrs[u])) < 0)
|
|
HGOTO_ERROR(H5E_ATTR, H5E_CANTINIT, FAIL, "can't create message");
|
|
} /* end for */
|
|
|
|
/* Remove the dense storage */
|
|
if (H5A__dense_delete(loc->file, ainfo) < 0)
|
|
HGOTO_ERROR(H5E_ATTR, H5E_CANTDELETE, FAIL, "unable to delete dense attribute storage");
|
|
} /* end if */
|
|
} /* end if */
|
|
|
|
/* Update the message after removing the attribute */
|
|
/* This is particularly needed when removing the last attribute that is
|
|
* accessed via fractal heap/v2 B-tree (HDFFV-9277)
|
|
*/
|
|
if (H5O__msg_write_real(loc->file, oh, H5O_MSG_AINFO, H5O_MSG_FLAG_DONTSHARE, 0, ainfo) < 0)
|
|
HGOTO_ERROR(H5E_ATTR, H5E_CANTUPDATE, FAIL, "unable to update attribute info message");
|
|
|
|
/* Check if we have deleted all the attributes and the attribute info
|
|
* message should be deleted itself.
|
|
*/
|
|
if (ainfo->nattrs == 0) {
|
|
if (H5O__msg_remove_real(loc->file, oh, H5O_MSG_AINFO, H5O_ALL, NULL, NULL, true) < 0)
|
|
HGOTO_ERROR(H5E_ATTR, H5E_CANTDELETE, FAIL, "unable to delete attribute info");
|
|
} /* end if */
|
|
|
|
done:
|
|
/* Release resources */
|
|
if (atable.attrs && H5A__attr_release_table(&atable) < 0)
|
|
HDONE_ERROR(H5E_ATTR, H5E_CANTFREE, FAIL, "unable to release attribute table");
|
|
|
|
FUNC_LEAVE_NOAPI(ret_value)
|
|
} /* end H5O__attr_remove_update() */
|
|
|
|
/*-------------------------------------------------------------------------
|
|
* Function: H5O__attr_remove_cb
|
|
*
|
|
* Purpose: Object header iterator callback routine to remove an
|
|
* attribute stored compactly.
|
|
*
|
|
* Return: SUCCEED/FAIL
|
|
*
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
static herr_t
|
|
H5O__attr_remove_cb(H5O_t *oh, H5O_mesg_t *mesg /*in,out*/, unsigned H5_ATTR_UNUSED sequence,
|
|
unsigned *oh_modified, void *_udata /*in,out*/)
|
|
{
|
|
H5O_iter_rm_t *udata = (H5O_iter_rm_t *)_udata; /* Operator user data */
|
|
herr_t ret_value = H5_ITER_CONT; /* Return value */
|
|
|
|
FUNC_ENTER_PACKAGE
|
|
|
|
/* check args */
|
|
assert(oh);
|
|
assert(mesg);
|
|
assert(!udata->found);
|
|
|
|
/* Check for correct attribute message to modify */
|
|
if (strcmp(((H5A_t *)mesg->native)->shared->name, udata->name) == 0) {
|
|
/* Convert message into a null message (i.e. delete it) */
|
|
if (H5O__release_mesg(udata->f, oh, mesg, true) < 0)
|
|
HGOTO_ERROR(H5E_OHDR, H5E_CANTDELETE, H5_ITER_ERROR, "unable to convert into null message");
|
|
|
|
/* Indicate that the object header was modified */
|
|
*oh_modified = H5O_MODIFY_CONDENSE;
|
|
|
|
/* Indicate that this message is the attribute to be deleted */
|
|
udata->found = true;
|
|
|
|
/* Stop iterating */
|
|
ret_value = H5_ITER_STOP;
|
|
} /* end if */
|
|
|
|
done:
|
|
FUNC_LEAVE_NOAPI(ret_value)
|
|
} /* end H5O__attr_remove_cb() */
|
|
|
|
/*-------------------------------------------------------------------------
|
|
* Function: H5O__attr_remove
|
|
*
|
|
* Purpose: Delete an attribute on an object.
|
|
*
|
|
* Return: SUCCEED/FAIL
|
|
*
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
herr_t
|
|
H5O__attr_remove(const H5O_loc_t *loc, const char *name)
|
|
{
|
|
H5O_t *oh = NULL; /* Pointer to actual object header */
|
|
H5O_ainfo_t ainfo; /* Attribute information for object */
|
|
htri_t ainfo_exists = false; /* Whether the attribute info exists in the file */
|
|
herr_t ret_value = SUCCEED; /* Return value */
|
|
|
|
FUNC_ENTER_PACKAGE_TAG(loc->addr)
|
|
|
|
/* Check arguments */
|
|
assert(loc);
|
|
assert(name);
|
|
|
|
/* Pin the object header */
|
|
if (NULL == (oh = H5O_pin(loc)))
|
|
HGOTO_ERROR(H5E_ATTR, H5E_CANTPIN, FAIL, "unable to pin object header");
|
|
|
|
/* Check for attribute info stored */
|
|
ainfo.fheap_addr = HADDR_UNDEF;
|
|
if (oh->version > H5O_VERSION_1) {
|
|
/* Check for (& retrieve if available) attribute info */
|
|
if ((ainfo_exists = H5A__get_ainfo(loc->file, oh, &ainfo)) < 0)
|
|
HGOTO_ERROR(H5E_ATTR, H5E_CANTGET, FAIL, "can't check for attribute info message");
|
|
} /* end if */
|
|
|
|
/* Check for attributes stored densely */
|
|
if (H5_addr_defined(ainfo.fheap_addr)) {
|
|
/* Delete attribute from dense storage */
|
|
if (H5A__dense_remove(loc->file, &ainfo, name) < 0)
|
|
HGOTO_ERROR(H5E_ATTR, H5E_CANTDELETE, FAIL, "unable to delete attribute in dense storage");
|
|
} /* end if */
|
|
else {
|
|
H5O_iter_rm_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.name = name;
|
|
udata.found = false;
|
|
|
|
/* Iterate over attributes, to locate correct one to delete */
|
|
op.op_type = H5O_MESG_OP_LIB;
|
|
op.u.lib_op = H5O__attr_remove_cb;
|
|
if (H5O__msg_iterate_real(loc->file, oh, H5O_MSG_ATTR, &op, &udata) < 0)
|
|
HGOTO_ERROR(H5E_ATTR, H5E_CANTDELETE, FAIL, "error deleting attribute");
|
|
|
|
/* Check that we found the attribute */
|
|
if (!udata.found)
|
|
HGOTO_ERROR(H5E_ATTR, H5E_NOTFOUND, FAIL, "can't locate attribute");
|
|
} /* end else */
|
|
|
|
/* Update the attribute information after removing an attribute */
|
|
if (ainfo_exists)
|
|
if (H5O__attr_remove_update(loc, oh, &ainfo) < 0)
|
|
HGOTO_ERROR(H5E_ATTR, H5E_CANTUPDATE, FAIL, "unable to update attribute info");
|
|
|
|
/* Update the modification time, if any */
|
|
if (H5O_touch_oh(loc->file, oh, false) < 0)
|
|
HGOTO_ERROR(H5E_ATTR, H5E_CANTUPDATE, FAIL, "unable to update time on object");
|
|
|
|
done:
|
|
if (oh && H5O_unpin(oh) < 0)
|
|
HDONE_ERROR(H5E_ATTR, H5E_CANTUNPIN, FAIL, "unable to unpin object header");
|
|
|
|
FUNC_LEAVE_NOAPI_TAG(ret_value)
|
|
} /* end H5O__attr_remove() */
|
|
|
|
/*-------------------------------------------------------------------------
|
|
* Function: H5O__attr_remove_by_idx
|
|
*
|
|
* Purpose: Delete an attribute on an object, according to an order within
|
|
* an index.
|
|
*
|
|
* Return: SUCCEED/FAIL
|
|
*
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
herr_t
|
|
H5O__attr_remove_by_idx(const H5O_loc_t *loc, H5_index_t idx_type, H5_iter_order_t order, hsize_t n)
|
|
{
|
|
H5O_t *oh = NULL; /* Pointer to actual object header */
|
|
H5O_ainfo_t ainfo; /* Attribute information for object */
|
|
htri_t ainfo_exists = false; /* Whether the attribute info exists in the file */
|
|
H5A_attr_table_t atable = {0, 0, NULL}; /* Table of attributes */
|
|
herr_t ret_value = SUCCEED; /* Return value */
|
|
|
|
FUNC_ENTER_PACKAGE_TAG(loc->addr)
|
|
|
|
/* Check arguments */
|
|
assert(loc);
|
|
|
|
/* Pin the object header */
|
|
if (NULL == (oh = H5O_pin(loc)))
|
|
HGOTO_ERROR(H5E_ATTR, H5E_CANTPIN, FAIL, "unable to pin object header");
|
|
|
|
/* Check for attribute info stored */
|
|
ainfo.fheap_addr = HADDR_UNDEF;
|
|
if (oh->version > H5O_VERSION_1) {
|
|
/* Check for (& retrieve if available) attribute info */
|
|
if ((ainfo_exists = H5A__get_ainfo(loc->file, oh, &ainfo)) < 0)
|
|
HGOTO_ERROR(H5E_ATTR, H5E_CANTGET, FAIL, "can't check for attribute info message");
|
|
} /* end if */
|
|
|
|
/* Check for attributes stored densely */
|
|
if (H5_addr_defined(ainfo.fheap_addr)) {
|
|
/* Delete attribute from dense storage */
|
|
if (H5A__dense_remove_by_idx(loc->file, &ainfo, idx_type, order, n) < 0)
|
|
HGOTO_ERROR(H5E_ATTR, H5E_CANTDELETE, FAIL, "unable to delete attribute in dense storage");
|
|
} /* end if */
|
|
else {
|
|
H5O_iter_rm_t udata; /* User data for callback */
|
|
H5O_mesg_operator_t op; /* Wrapper for operator */
|
|
|
|
/* Build table of attributes for compact storage */
|
|
if (H5A__compact_build_table(loc->file, oh, idx_type, order, &atable) < 0)
|
|
HGOTO_ERROR(H5E_ATTR, H5E_CANTINIT, FAIL, "error building attribute table");
|
|
|
|
/* Check for skipping too many attributes */
|
|
if (n >= atable.num_attrs)
|
|
HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid index specified");
|
|
|
|
/* Set up user data for callback, to remove the attribute by name */
|
|
udata.f = loc->file;
|
|
udata.name = ((atable.attrs[n])->shared)->name;
|
|
udata.found = false;
|
|
|
|
/* Iterate over attributes, to locate correct one to delete */
|
|
op.op_type = H5O_MESG_OP_LIB;
|
|
op.u.lib_op = H5O__attr_remove_cb;
|
|
if (H5O__msg_iterate_real(loc->file, oh, H5O_MSG_ATTR, &op, &udata) < 0)
|
|
HGOTO_ERROR(H5E_ATTR, H5E_CANTDELETE, FAIL, "error deleting attribute");
|
|
|
|
/* Check that we found the attribute */
|
|
if (!udata.found)
|
|
HGOTO_ERROR(H5E_ATTR, H5E_NOTFOUND, FAIL, "can't locate attribute");
|
|
} /* end else */
|
|
|
|
/* Update the attribute information after removing an attribute */
|
|
if (ainfo_exists)
|
|
if (H5O__attr_remove_update(loc, oh, &ainfo) < 0)
|
|
HGOTO_ERROR(H5E_ATTR, H5E_CANTUPDATE, FAIL, "unable to update attribute info");
|
|
|
|
/* Update the modification time, if any */
|
|
if (H5O_touch_oh(loc->file, oh, false) < 0)
|
|
HGOTO_ERROR(H5E_ATTR, H5E_CANTUPDATE, FAIL, "unable to update time on object");
|
|
|
|
done:
|
|
if (oh && H5O_unpin(oh) < 0)
|
|
HDONE_ERROR(H5E_ATTR, H5E_CANTUNPIN, FAIL, "unable to unpin object header");
|
|
if (atable.attrs && H5A__attr_release_table(&atable) < 0)
|
|
HDONE_ERROR(H5E_ATTR, H5E_CANTFREE, FAIL, "unable to release attribute table");
|
|
|
|
FUNC_LEAVE_NOAPI_TAG(ret_value)
|
|
} /* end H5O__attr_remove_by_idx() */
|
|
|
|
/*-------------------------------------------------------------------------
|
|
* Function: H5O__attr_count_real
|
|
*
|
|
* Purpose: Determine the # of attributes on an object
|
|
*
|
|
* Return: SUCCEED/FAIL
|
|
*
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
herr_t
|
|
H5O__attr_count_real(H5F_t *f, H5O_t *oh, hsize_t *nattrs)
|
|
{
|
|
herr_t ret_value = SUCCEED; /* Return value */
|
|
|
|
FUNC_ENTER_PACKAGE
|
|
|
|
/* Check arguments */
|
|
assert(f);
|
|
assert(oh);
|
|
assert(nattrs);
|
|
|
|
/* Check for attributes stored densely */
|
|
if (oh->version > H5O_VERSION_1) {
|
|
htri_t ainfo_exists = false; /* Whether the attribute info exists in the file */
|
|
H5O_ainfo_t ainfo; /* Attribute information for object */
|
|
|
|
/* Attempt to get the attribute information from the object header */
|
|
if ((ainfo_exists = H5A__get_ainfo(f, oh, &ainfo)) < 0)
|
|
HGOTO_ERROR(H5E_ATTR, H5E_CANTGET, FAIL, "can't check for attribute info message");
|
|
else if (ainfo_exists > 0)
|
|
*nattrs = ainfo.nattrs;
|
|
else
|
|
*nattrs = 0;
|
|
} /* end if */
|
|
else {
|
|
hsize_t attr_count; /* Number of attributes found */
|
|
unsigned u; /* Local index variable */
|
|
|
|
/* Loop over all messages, counting the attributes */
|
|
attr_count = 0;
|
|
for (u = 0; u < oh->nmesgs; u++)
|
|
if (oh->mesg[u].type == H5O_MSG_ATTR)
|
|
attr_count++;
|
|
*nattrs = attr_count;
|
|
} /* end else */
|
|
|
|
done:
|
|
FUNC_LEAVE_NOAPI(ret_value)
|
|
} /* end H5O__attr_count_real */
|
|
|
|
/*-------------------------------------------------------------------------
|
|
* Function: H5O__attr_exists_cb
|
|
*
|
|
* Purpose: Object header iterator callback routine to check for an
|
|
* attribute stored compactly, by name.
|
|
*
|
|
* Return: SUCCEED/FAIL
|
|
*
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
static herr_t
|
|
H5O__attr_exists_cb(H5O_t H5_ATTR_UNUSED *oh, H5O_mesg_t *mesg /*in,out*/, unsigned H5_ATTR_UNUSED sequence,
|
|
unsigned H5_ATTR_UNUSED *oh_modified, void *_udata /*in,out*/)
|
|
{
|
|
H5O_iter_xst_t *udata = (H5O_iter_xst_t *)_udata; /* Operator user data */
|
|
herr_t ret_value = H5_ITER_CONT; /* Return value */
|
|
|
|
FUNC_ENTER_PACKAGE_NOERR
|
|
|
|
/* check args */
|
|
assert(mesg);
|
|
assert(udata->exists && !*udata->exists);
|
|
|
|
/* Check for correct attribute message */
|
|
if (strcmp(((H5A_t *)mesg->native)->shared->name, udata->name) == 0) {
|
|
/* Indicate that this message is the attribute sought */
|
|
*udata->exists = true;
|
|
|
|
/* Stop iterating */
|
|
ret_value = H5_ITER_STOP;
|
|
} /* end if */
|
|
|
|
FUNC_LEAVE_NOAPI(ret_value)
|
|
} /* end H5O__attr_exists_cb() */
|
|
|
|
/*-------------------------------------------------------------------------
|
|
* Function: H5O__attr_exists
|
|
*
|
|
* Purpose: Determine if an attribute with a particular name exists on an object
|
|
*
|
|
* Return: SUCCEED/FAIL
|
|
*
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
herr_t
|
|
H5O__attr_exists(const H5O_loc_t *loc, const char *name, bool *attr_exists)
|
|
{
|
|
H5O_t *oh = NULL; /* Pointer to actual object header */
|
|
H5O_ainfo_t ainfo; /* Attribute information for object */
|
|
herr_t ret_value = SUCCEED; /* Return value */
|
|
|
|
FUNC_ENTER_PACKAGE_TAG(loc->addr)
|
|
|
|
/* Check arguments */
|
|
assert(loc);
|
|
assert(name);
|
|
assert(attr_exists);
|
|
|
|
/* Protect the object header to iterate over */
|
|
if (NULL == (oh = H5O_protect(loc, H5AC__READ_ONLY_FLAG, false)))
|
|
HGOTO_ERROR(H5E_ATTR, H5E_CANTPROTECT, FAIL, "unable to load object header");
|
|
|
|
/* Check for attribute info stored */
|
|
ainfo.fheap_addr = HADDR_UNDEF;
|
|
if (oh->version > H5O_VERSION_1) {
|
|
/* Check for (& retrieve if available) attribute info */
|
|
if (H5A__get_ainfo(loc->file, oh, &ainfo) < 0)
|
|
HGOTO_ERROR(H5E_ATTR, H5E_CANTGET, FAIL, "can't check for attribute info message");
|
|
} /* end if */
|
|
|
|
/* Check for attributes stored densely */
|
|
if (H5_addr_defined(ainfo.fheap_addr)) {
|
|
/* Check if attribute exists in dense storage */
|
|
if (H5A__dense_exists(loc->file, &ainfo, name, attr_exists) < 0)
|
|
HGOTO_ERROR(H5E_ATTR, H5E_BADITER, FAIL, "error checking for existence of attribute");
|
|
} /* end if */
|
|
else {
|
|
H5O_iter_xst_t udata; /* User data for callback */
|
|
H5O_mesg_operator_t op; /* Wrapper for operator */
|
|
|
|
/* Set up user data for callback */
|
|
udata.name = name;
|
|
udata.exists = attr_exists;
|
|
|
|
/* Iterate over existing attributes, checking for attribute with same name */
|
|
op.op_type = H5O_MESG_OP_LIB;
|
|
op.u.lib_op = H5O__attr_exists_cb;
|
|
if (H5O__msg_iterate_real(loc->file, oh, H5O_MSG_ATTR, &op, &udata) < 0)
|
|
HGOTO_ERROR(H5E_ATTR, H5E_BADITER, FAIL, "error checking for existence of attribute");
|
|
} /* end else */
|
|
|
|
done:
|
|
if (oh && H5O_unprotect(loc, oh, H5AC__NO_FLAGS_SET) < 0)
|
|
HDONE_ERROR(H5E_ATTR, H5E_CANTUNPROTECT, FAIL, "unable to release object header");
|
|
|
|
FUNC_LEAVE_NOAPI_TAG(ret_value)
|
|
} /* end H5O__attr_exists() */
|
|
|
|
/*-------------------------------------------------------------------------
|
|
* Function: H5O__attr_bh_info
|
|
*
|
|
* Purpose: For 1.8 attribute, returns storage amount for btree and fractal heap
|
|
*
|
|
* Return: SUCCEED/FAIL
|
|
*
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
herr_t
|
|
H5O__attr_bh_info(H5F_t *f, H5O_t *oh, H5_ih_info_t *bh_info)
|
|
{
|
|
H5HF_t *fheap = NULL; /* Fractal heap handle */
|
|
H5B2_t *bt2_name = NULL; /* v2 B-tree handle for name index */
|
|
H5B2_t *bt2_corder = NULL; /* v2 B-tree handle for creation order index */
|
|
herr_t ret_value = SUCCEED; /* Return value */
|
|
|
|
FUNC_ENTER_PACKAGE
|
|
|
|
assert(f);
|
|
assert(oh);
|
|
assert(bh_info);
|
|
|
|
/* Attributes are only stored in fractal heap & indexed w/v2 B-tree in later versions */
|
|
if (oh->version > H5O_VERSION_1) {
|
|
H5O_ainfo_t ainfo; /* Attribute information for object */
|
|
htri_t ainfo_exists = false; /* Whether the attribute info exists in the file */
|
|
|
|
/* Check for (& retrieve if available) attribute info */
|
|
if ((ainfo_exists = H5A__get_ainfo(f, oh, &ainfo)) < 0)
|
|
HGOTO_ERROR(H5E_ATTR, H5E_CANTGET, FAIL, "can't check for attribute info message");
|
|
else if (ainfo_exists > 0) {
|
|
/* Check if name index available */
|
|
if (H5_addr_defined(ainfo.name_bt2_addr)) {
|
|
/* Open the name index v2 B-tree */
|
|
if (NULL == (bt2_name = H5B2_open(f, ainfo.name_bt2_addr, NULL)))
|
|
HGOTO_ERROR(H5E_ATTR, H5E_CANTOPENOBJ, FAIL, "unable to open v2 B-tree for name index");
|
|
|
|
/* Get name index B-tree size */
|
|
if (H5B2_size(bt2_name, &(bh_info->index_size)) < 0)
|
|
HGOTO_ERROR(H5E_ATTR, H5E_CANTGET, FAIL, "can't retrieve B-tree storage info");
|
|
} /* end if */
|
|
|
|
/* Check if creation order index available */
|
|
if (H5_addr_defined(ainfo.corder_bt2_addr)) {
|
|
/* Open the creation order index v2 B-tree */
|
|
if (NULL == (bt2_corder = H5B2_open(f, ainfo.corder_bt2_addr, NULL)))
|
|
HGOTO_ERROR(H5E_ATTR, H5E_CANTOPENOBJ, FAIL,
|
|
"unable to open v2 B-tree for creation order index");
|
|
|
|
/* Get creation order index B-tree size */
|
|
if (H5B2_size(bt2_corder, &(bh_info->index_size)) < 0)
|
|
HGOTO_ERROR(H5E_ATTR, H5E_CANTGET, FAIL, "can't retrieve B-tree storage info");
|
|
} /* end if */
|
|
|
|
/* Get storage size of fractal heap, if it's used */
|
|
if (H5_addr_defined(ainfo.fheap_addr)) {
|
|
/* Open the fractal heap for attributes */
|
|
if (NULL == (fheap = H5HF_open(f, ainfo.fheap_addr)))
|
|
HGOTO_ERROR(H5E_ATTR, H5E_CANTOPENOBJ, FAIL, "unable to open fractal heap");
|
|
|
|
/* Get heap storage size */
|
|
if (H5HF_size(fheap, &(bh_info->heap_size)) < 0)
|
|
HGOTO_ERROR(H5E_ATTR, H5E_CANTGET, FAIL, "can't retrieve B-tree storage info");
|
|
} /* end if */
|
|
} /* end else */
|
|
} /* end if */
|
|
|
|
done:
|
|
/* Release resources */
|
|
if (fheap && H5HF_close(fheap) < 0)
|
|
HDONE_ERROR(H5E_ATTR, H5E_CANTCLOSEOBJ, FAIL, "can't close fractal heap");
|
|
if (bt2_name && H5B2_close(bt2_name) < 0)
|
|
HDONE_ERROR(H5E_ATTR, H5E_CANTCLOSEOBJ, FAIL, "can't close v2 B-tree for name index");
|
|
if (bt2_corder && H5B2_close(bt2_corder) < 0)
|
|
HDONE_ERROR(H5E_ATTR, H5E_CANTCLOSEOBJ, FAIL, "can't close v2 B-tree for creation order index");
|
|
|
|
FUNC_LEAVE_NOAPI(ret_value)
|
|
} /* H5O__attr_bh_info() */
|