From dc73eca1599d065186baa6a44ed611cb37225ce1 Mon Sep 17 00:00:00 2001 From: Quincey Koziol Date: Mon, 11 Dec 2006 14:02:38 -0500 Subject: [svn-r13041] Description: Migrate "internalish" attribute operations into new source code file. Add test & basic support for opening attributes in dense storage (shared attributes not tested or supported yet). Tested on: Linux/32 2.6 (chicago) Linux/64 2.6 (chicago2) --- MANIFEST | 1 + src/H5A.c | 109 ++++++- src/H5Adense.c | 94 ++++++ src/H5Apkg.h | 6 + src/H5Gdense.c | 9 +- src/H5Oattr.c | 668 +-------------------------------------- src/H5Oattribute.c | 892 +++++++++++++++++++++++++++++++++++++++++++++++++++++ src/H5Opkg.h | 12 + src/H5Oprivate.h | 11 - src/Makefile.am | 2 +- src/Makefile.in | 5 +- test/tattr.c | 134 +++++++- 12 files changed, 1235 insertions(+), 708 deletions(-) create mode 100644 src/H5Oattribute.c diff --git a/MANIFEST b/MANIFEST index d801b6b..e43ab40 100644 --- a/MANIFEST +++ b/MANIFEST @@ -574,6 +574,7 @@ ./src/H5O.c ./src/H5Oalloc.c ./src/H5Oattr.c +./src/H5Oattribute.c ./src/H5Obogus.c ./src/H5Ocache.c ./src/H5Ocont.c diff --git a/src/H5A.c b/src/H5A.c index d4ca21b..a7aa381 100644 --- a/src/H5A.c +++ b/src/H5A.c @@ -17,6 +17,7 @@ /****************/ #define H5A_PACKAGE /*suppress error about including H5Apkg */ +#define H5O_PACKAGE /*suppress error about including H5Opkg */ /* Interface initialization */ #define H5_INTERFACE_INIT_FUNC H5A_init_interface @@ -31,6 +32,7 @@ #include "H5FLprivate.h" /* Free Lists */ #include "H5Iprivate.h" /* IDs */ #include "H5MMprivate.h" /* Memory management */ +#include "H5Opkg.h" /* Object headers */ #include "H5Sprivate.h" /* Dataspace functions */ #include "H5SMprivate.h" /* Shared Object Header Messages */ @@ -64,8 +66,10 @@ typedef struct H5A_iter_cb1 { /********************/ static hid_t H5A_create(const H5G_loc_t *loc, const char *name, - const H5T_t *type, const H5S_t *space, hid_t acpl_id, hid_t dxpl_id); + const H5T_t *type, const H5S_t *space, hid_t acpl_id, hid_t dxpl_id); static hid_t H5A_open(H5G_loc_t *loc, unsigned idx, hid_t dxpl_id); +static H5A_t *H5A_open_by_name(const H5G_loc_t *loc, const char *name, + hid_t dxpl_id); static herr_t H5A_write(H5A_t *attr, const H5T_t *mem_type, const void *buf, hid_t dxpl_id); static herr_t H5A_read(const H5A_t *attr, const H5T_t *mem_type, void *buf, hid_t dxpl_id); static int H5A_get_index(H5O_loc_t *loc, const char *name, hid_t dxpl_id); @@ -548,7 +552,7 @@ hid_t H5Aopen_name(hid_t loc_id, const char *name) { H5G_loc_t loc; /* Object location */ - int idx; + H5A_t *attr = NULL; /* Attribute opened */ hid_t ret_value; FUNC_ENTER_API(H5Aopen_name, FAIL) @@ -562,13 +566,13 @@ H5Aopen_name(hid_t loc_id, const char *name) if(!name || !*name) HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no name") - /* Look up the attribute for the object */ - if((idx = H5A_get_index(loc.oloc, name, H5AC_ind_dxpl_id)) < 0) - HGOTO_ERROR(H5E_ATTR, H5E_BADVALUE, FAIL, "attribute not found") + /* Open the attribute on the object header */ + if(NULL == (attr = H5A_open_by_name(&loc, name, H5AC_ind_dxpl_id))) + HGOTO_ERROR(H5E_ATTR, H5E_CANTOPENOBJ, FAIL, "can't open attribute") - /* Go do the real work for opening the attribute */ - if((ret_value = H5A_open(&loc, (unsigned)idx, H5AC_dxpl_id)) < 0) - HGOTO_ERROR(H5E_ATTR, H5E_CANTINIT, FAIL, "unable to open attribute") + /* Register the attribute and get an ID for it */ + if((ret_value = H5I_register(H5I_ATTR, attr)) < 0) + HGOTO_ERROR(H5E_ATOM, H5E_CANTREGISTER, FAIL, "unable to register attribute for ID") done: FUNC_LEAVE_API(ret_value) @@ -676,7 +680,7 @@ H5A_open(H5G_loc_t *loc, unsigned idx, hid_t dxpl_id) HGOTO_ERROR(H5E_ATTR, H5E_CANTOPENOBJ, FAIL, "unable to open") attr->obj_opened = TRUE; - /* Register the new attribute and get an ID for it */ + /* Register the attribute and get an ID for it */ if((ret_value = H5I_register(H5I_ATTR, attr)) < 0) HGOTO_ERROR(H5E_ATOM, H5E_CANTREGISTER, FAIL, "unable to register attribute for ID") @@ -690,6 +694,77 @@ done: } /* H5A_open() */ +/*------------------------------------------------------------------------- + * Function: H5A_open_by_name + * + * Purpose: + * Open an attribute in an object header, according to it's name + * + * Usage: + * herr_t H5A_open(loc, name, dxpl_id) + * const H5G_loc_t *loc; IN: Pointer to group location for object + * const char *name; IN: Name of attribute to open + * hid_t dxpl_id; IN: DXPL for operation + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Quincey Koziol + * December 11, 2006 + * + *------------------------------------------------------------------------- + */ +static H5A_t * +H5A_open_by_name(const H5G_loc_t *loc, const char *name, hid_t dxpl_id) +{ + H5A_t *attr = NULL; /* Attribute from object header */ + H5A_t *ret_value; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT(H5A_open_by_name) + + /* check args */ + HDassert(loc); + HDassert(name); + + /* Read in attribute from object header */ + if(NULL == (attr = H5O_attr_open(loc->oloc, name, dxpl_id))) + HGOTO_ERROR(H5E_ATTR, H5E_CANTINIT, NULL, "unable to load attribute info from object header") + attr->initialized = TRUE; + +#if defined(H5_USING_PURIFY) || !defined(NDEBUG) + /* Clear object location */ + if(H5O_loc_reset(&(attr->oloc)) < 0) + HGOTO_ERROR(H5E_ATTR, H5E_CANTOPENOBJ, NULL, "unable to reset location") + + /* Clear path name */ + if(H5G_name_reset(&(attr->path)) < 0) + HGOTO_ERROR(H5E_ATTR, H5E_CANTOPENOBJ, NULL, "unable to reset path") +#endif /* H5_USING_PURIFY */ + + /* Deep copy of the symbol table entry */ + if(H5O_loc_copy(&(attr->oloc), loc->oloc, H5_COPY_DEEP) < 0) + HGOTO_ERROR(H5E_ATTR, H5E_CANTOPENOBJ, NULL, "unable to copy entry") + + /* Deep copy of the group hier. path */ + if(H5G_name_copy(&(attr->path), loc->path, H5_COPY_DEEP) < 0) + HGOTO_ERROR(H5E_ATTR, H5E_CANTOPENOBJ, NULL, "unable to copy entry") + + /* Hold the symbol table entry (and file) open */ + if(H5O_open(&(attr->oloc)) < 0) + HGOTO_ERROR(H5E_ATTR, H5E_CANTOPENOBJ, NULL, "unable to open") + attr->obj_opened = TRUE; + + /* Set return value */ + ret_value = attr; + +done: + /* Cleanup on failure */ + if(ret_value == NULL && attr) + (void)H5A_close(attr); + + FUNC_LEAVE_NOAPI(ret_value) +} /* H5A_open_by_name() */ + + /*-------------------------------------------------------------------------- NAME H5Awrite @@ -1200,14 +1275,14 @@ H5Aget_name(hid_t attr_id, size_t buf_size, char *buf) /* Terminate the string */ buf[copy_len]='\0'; - } + } /* end if */ /* Set return value */ ret_value = (ssize_t)nbytes; done: FUNC_LEAVE_API(ret_value) -} /* H5Aget_type() */ +} /* H5Aget_name() */ /*------------------------------------------------------------------------- @@ -1511,9 +1586,12 @@ H5A_copy(H5A_t *_new_attr, const H5A_t *old_attr) new_attr->obj_opened = FALSE; /* Copy the guts of the attribute */ - new_attr->name = H5MM_xstrdup(old_attr->name); - new_attr->dt = H5T_copy(old_attr->dt, H5T_COPY_ALL); - new_attr->ds = H5S_copy(old_attr->ds, FALSE); + if(NULL == (new_attr->name = H5MM_xstrdup(old_attr->name))) + HGOTO_ERROR(H5E_ATTR, H5E_CANTCOPY, NULL, "unable to copy attribute name") + if(NULL == (new_attr->dt = H5T_copy(old_attr->dt, H5T_COPY_ALL))) + HGOTO_ERROR(H5E_ATTR, H5E_CANTCOPY, NULL, "unable to copy attribute datatype") + if(NULL == (new_attr->ds = H5S_copy(old_attr->ds, FALSE))) + HGOTO_ERROR(H5E_ATTR, H5E_CANTCOPY, NULL, "unable to copy attribute dataspace") /* XXX: Copy the object location and group path? -QAK */ /* Copy the attribute data, if there is any */ @@ -1530,10 +1608,9 @@ H5A_copy(H5A_t *_new_attr, const H5A_t *old_attr) ret_value = new_attr; done: - if(ret_value == NULL) { + if(ret_value == NULL) if(new_attr != NULL && allocated_attr) (void)H5A_close(new_attr); - } /* end if */ FUNC_LEAVE_NOAPI(ret_value) } /* end H5A_copy() */ diff --git a/src/H5Adense.c b/src/H5Adense.c index 7cacf13..b374e79 100644 --- a/src/H5Adense.c +++ b/src/H5Adense.c @@ -249,6 +249,100 @@ done: /*------------------------------------------------------------------------- + * Function: H5A_dense_open_cb + * + * Purpose: Callback when an attribute is located in an index + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Quincey Koziol + * koziol@hdfgroup.org + * Dec 11 2006 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5A_dense_open_cb(const void *_attr, void *_user_attr) +{ + const H5A_t *attr = (const H5A_t *)_attr; /* Record from B-tree */ + H5A_t **user_attr = (H5A_t **)_user_attr; /* User data from v2 B-tree attribute lookup */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT(H5A_dense_open_cb) + + /* + * Check arguments. + */ + HDassert(attr); + HDassert(user_attr); + + /* Copy attribute information */ + if(NULL == (*user_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 H5A_dense_open_cb() */ + + +/*------------------------------------------------------------------------- + * Function: H5A_dense_open + * + * Purpose: Open an attribute in dense storage structures for an object + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Quincey Koziol + * koziol@hdfgroup.org + * Dec 11 2006 + * + *------------------------------------------------------------------------- + */ +H5A_t * +H5A_dense_open(H5F_t *f, hid_t dxpl_id, const H5O_t *oh, const char *name) +{ + H5A_bt2_ud_common_t udata; /* User data for v2 B-tree modify */ + H5HF_t *fheap = NULL; /* Fractal heap handle */ + H5A_t *ret_value = NULL; /* Return value */ + + FUNC_ENTER_NOAPI(H5A_dense_open, NULL) + + /* + * Check arguments. + */ + HDassert(f); + HDassert(oh); + HDassert(name); + + /* Open the fractal heap */ + if(NULL == (fheap = H5HF_open(f, dxpl_id, oh->attr_fheap_addr))) + HGOTO_ERROR(H5E_ATTR, H5E_CANTOPENOBJ, NULL, "unable to open fractal heap") + + /* Create the "udata" information for v2 B-tree record modify */ + udata.f = f; + udata.dxpl_id = dxpl_id; + udata.fheap = fheap; + udata.name = name; + udata.name_hash = H5_checksum_lookup3(name, HDstrlen(name), 0); + udata.flags = 0; + udata.corder = -1; /* XXX: None yet */ + udata.found_op = H5A_dense_open_cb; /* v2 B-tree comparison callback */ + udata.found_op_data = &ret_value; + + /* Find & copy the attribute in the 'name' index */ + if(H5B2_find(f, dxpl_id, H5A_BT2_NAME, oh->name_bt2_addr, &udata, NULL, NULL) < 0) + HGOTO_ERROR(H5E_ATTR, H5E_NOTFOUND, NULL, "can't locate attribute in name index") + +done: + /* Release resources */ + if(fheap && H5HF_close(fheap, dxpl_id) < 0) + HDONE_ERROR(H5E_ATTR, H5E_CLOSEERROR, NULL, "can't close fractal heap") + + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5A_dense_open() */ + + +/*------------------------------------------------------------------------- * Function: H5A_dense_insert * * Purpose: Insert an attribute into dense storage structures for an object diff --git a/src/H5Apkg.h b/src/H5Apkg.h index a8a7dd7..754c215 100644 --- a/src/H5Apkg.h +++ b/src/H5Apkg.h @@ -140,11 +140,17 @@ H5_DLL herr_t H5A_free(H5A_t *attr); H5_DLL herr_t H5A_close(H5A_t *attr); /* Attribute "dense" storage routines */ +H5_DLL H5A_t *H5A_dense_open(H5F_t *f, hid_t dxpl_id, const H5O_t *oh, + const char *name); H5_DLL herr_t H5A_dense_write(H5F_t *f, hid_t dxpl_id, const H5O_t *oh, const H5A_t *attr); H5_DLL herr_t H5A_dense_iterate(H5F_t *f, hid_t dxpl_id, hid_t loc_id, haddr_t attr_fheap_addr, haddr_t name_bt2_addr, unsigned skip, unsigned *last_attr, H5A_operator_t op, void *op_data); +/* Attribute object header routines */ +H5_DLL herr_t H5O_attr_reset(void *_mesg); +H5_DLL herr_t H5O_attr_get_share(const void *_mesg, H5O_shared_t *sh); + #endif /* _H5Apkg_H */ diff --git a/src/H5Gdense.c b/src/H5Gdense.c index cd0b242..86f8353 100644 --- a/src/H5Gdense.c +++ b/src/H5Gdense.c @@ -482,12 +482,9 @@ H5G_dense_lookup_cb(const void *_lnk, void *_user_lnk) HDassert(lnk); HDassert(user_lnk); - /* Check if we want the link information */ - if(user_lnk) { - /* Copy link information */ - if(H5O_msg_copy(H5O_LINK_ID, lnk, user_lnk) == NULL) - HGOTO_ERROR(H5E_SYM, H5E_CANTCOPY, H5_ITER_ERROR, "can't copy link message") - } /* end if */ + /* Copy link information */ + if(H5O_msg_copy(H5O_LINK_ID, lnk, user_lnk) == NULL) + HGOTO_ERROR(H5E_SYM, H5E_CANTCOPY, H5_ITER_ERROR, "can't copy link message") done: FUNC_LEAVE_NOAPI(ret_value) diff --git a/src/H5Oattr.c b/src/H5Oattr.c index 9e22011..5c1aba8 100644 --- a/src/H5Oattr.c +++ b/src/H5Oattr.c @@ -21,63 +21,17 @@ #include "H5Apkg.h" /* Attributes */ #include "H5Dprivate.h" /* Datasets */ #include "H5Eprivate.h" /* Error handling */ -#include "H5FLprivate.h" /* Free Lists */ -#include "H5Gprivate.h" /* Groups */ #include "H5Iprivate.h" /* IDs */ #include "H5MMprivate.h" /* Memory management */ #include "H5Opkg.h" /* Object headers */ #include "H5Spkg.h" /* Dataspaces */ #include "H5SMprivate.h" /* Shared Object Header Messages */ -/* User data for iteration when converting attributes to dense storage */ -typedef struct { - H5F_t *f; /* Pointer to file for insertion */ - hid_t dxpl_id; /* DXPL during iteration */ -} H5O_iter_cvt_t; - -/* 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); 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); static herr_t H5O_attr_delete(H5F_t *f, hid_t dxpl_id, const void *_mesg, hbool_t adj_link); static herr_t H5O_attr_link(H5F_t *f, hid_t dxpl_id, const void *_mesg); @@ -86,7 +40,6 @@ static herr_t H5O_attr_pre_copy_file(H5F_t *file_src, const H5O_msg_class_t *typ static void *H5O_attr_copy_file(H5F_t *file_src, const H5O_msg_class_t *mesg_type, void *native_src, H5F_t *file_dst, hid_t dxpl_id, H5O_copy_t *cpy_info, void *udata); -static herr_t H5O_attr_get_share(const void *_mesg, H5O_shared_t *sh); static herr_t H5O_attr_set_share(void *_mesg, const H5O_shared_t *sh); static htri_t H5O_attr_is_shared(const void *_mesg); static herr_t H5O_attr_debug(H5F_t *f, hid_t dxpl_id, const void *_mesg, @@ -639,7 +592,7 @@ H5O_attr_size(const H5F_t *f, const void *_mesg) * *------------------------------------------------------------------------- */ -static herr_t +herr_t H5O_attr_reset(void *_mesg) { H5A_t *attr = (H5A_t *)_mesg; @@ -1098,7 +1051,7 @@ done: * *------------------------------------------------------------------------- */ -static herr_t +herr_t H5O_attr_get_share(const void *_mesg, H5O_shared_t *sh /*out*/) { const H5A_t *mesg = (const H5A_t *)_mesg; @@ -1271,620 +1224,3 @@ done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5O_attr_debug() */ - -/*------------------------------------------------------------------------- - * Function: H5O_msg_attr_to_dense_cb - * - * Purpose: Object header iterator callback routine to convert compact - * attributes to dense attributes - * - * Return: Non-negative on success/Negative on failure - * - * Programmer: Quincey Koziol - * koziol@hdfgroup.org - * Dec 4 2006 - * - *------------------------------------------------------------------------- - */ -static herr_t -H5A_attr_to_dense_cb(H5O_t *oh, H5O_mesg_t *mesg/*in,out*/, - unsigned UNUSED sequence, unsigned *oh_flags_ptr, void *_udata/*in,out*/) -{ - H5O_iter_cvt_t *udata = (H5O_iter_cvt_t *)_udata; /* Operator user data */ - herr_t ret_value = H5_ITER_CONT; /* Return value */ - - FUNC_ENTER_NOAPI_NOINIT(H5A_attr_to_dense_cb) - - /* check args */ - HDassert(oh); - HDassert(mesg); - - /* Insert attribute into dense storage */ - if(H5A_dense_insert(udata->f, udata->dxpl_id, oh, mesg->flags, mesg->native) < 0) - HGOTO_ERROR(H5E_OHDR, H5E_CANTINSERT, H5_ITER_ERROR, "unable to add to dense storage") - - /* Convert message into a null message */ - if(H5O_release_mesg(udata->f, udata->dxpl_id, oh, mesg, TRUE, 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_flags_ptr |= H5AC__DIRTIED_FLAG; - -done: - FUNC_LEAVE_NOAPI(ret_value) -} /* end H5A_attr_to_dense_cb() */ - - -/*------------------------------------------------------------------------- - * Function: H5O_attr_create - * - * Purpose: Create a new attribute in the object header. - * - * Return: Non-negative on success/Negative on failure - * - * Programmer: Quincey Koziol - * Friday, December 8, 2006 - * - *------------------------------------------------------------------------- - */ -herr_t -H5O_attr_create(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 */ - unsigned mesg_flags = 0; /* Flags for storing message */ - 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(H5O_attr_create) - - /* Check arguments */ - HDassert(loc); - HDassert(attr); - - /* Should this message be written as a SOHM? */ - if((shared_mesg = H5SM_try_share(loc->file, dxpl_id, H5O_ATTR_ID, attr)) > 0) - /* Mark the message as shared */ - mesg_flags |= H5O_MSG_FLAG_SHARED; - else if(shared_mesg < 0) - HGOTO_ERROR(H5E_ATTR, H5E_WRITEERROR, FAIL, "error determining if message should be shared") - - /* 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") - -#ifdef QAK -HDfprintf(stderr, "%s: adding attribute to new-style object header\n", FUNC); -HDfprintf(stderr, "%s: oh->nattrs = %Hu\n", FUNC, oh->nattrs); -HDfprintf(stderr, "%s: oh->max_compact = %u\n", FUNC, oh->max_compact); -HDfprintf(stderr, "%s: oh->min_dense = %u\n", FUNC, oh->min_dense); -#endif /* QAK */ - /* Check for switching to "dense" attribute storage */ - if(oh->version > H5O_VERSION_1 && oh->nattrs == oh->max_compact && - !H5F_addr_defined(oh->attr_fheap_addr)) { - H5O_iter_cvt_t udata; /* User data for callback */ - H5O_mesg_operator_t op; /* Wrapper for operator */ -#ifdef QAK -HDfprintf(stderr, "%s: converting attributes to dense storage\n", FUNC); -#endif /* QAK */ - - /* Create dense storage for attributes */ - if(H5A_dense_create(loc->file, dxpl_id, oh) < 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.dxpl_id = dxpl_id; - - /* Iterate over existing attributes, moving them to dense storage */ - op.lib_op = H5A_attr_to_dense_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_CANTCONVERT, FAIL, "error converting attributes to dense storage") - } /* end if */ - - /* Increment attribute count */ - oh->nattrs++; - - /* Check for storing attribute with dense storage */ - if(H5F_addr_defined(oh->attr_fheap_addr)) { - /* Insert attribute into dense storage */ -#ifdef QAK -HDfprintf(stderr, "%s: inserting attribute to dense storage\n", FUNC); -#endif /* QAK */ - if(H5A_dense_insert(loc->file, dxpl_id, oh, mesg_flags, 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, dxpl_id, oh, H5O_MSG_ATTR, mesg_flags, 0, attr, &oh_flags) < 0) - HGOTO_ERROR(H5E_ATTR, H5E_CANTINSERT, FAIL, "unable to create new attribute in header") - } /* 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_create */ - - -/*------------------------------------------------------------------------- - * 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 */ - diff --git a/src/H5Oattribute.c b/src/H5Oattribute.c new file mode 100644 index 0000000..3c440b6 --- /dev/null +++ b/src/H5Oattribute.c @@ -0,0 +1,892 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Copyright by the Board of Trustees of the University of Illinois. * + * All rights reserved. * + * * + * This file is part of HDF5. The full HDF5 copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the files COPYING and Copyright.html. COPYING can be found at the root * + * of the source code distribution tree; Copyright.html can be found at the * + * root level of an installed copy of the electronic HDF5 document set and * + * is linked from the top-level documents page. It can also be found at * + * http://hdf.ncsa.uiuc.edu/HDF5/doc/Copyright.html. If you do not have * + * access to either file, you may request a copy from hdfhelp@ncsa.uiuc.edu. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/*------------------------------------------------------------------------- + * + * Created: H5Oattribute.c + * Dec 11 2006 + * Quincey Koziol + * + * Purpose: Object header attribute routines. + * + *------------------------------------------------------------------------- + */ + +/****************/ +/* Module Setup */ +/****************/ + +#define H5A_PACKAGE /*suppress error about including H5Apkg */ +#define H5O_PACKAGE /*suppress error about including H5Opkg */ + +/***********/ +/* 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 */ + + +/****************/ +/* Local Macros */ +/****************/ + + +/******************/ +/* Local Typedefs */ +/******************/ + +/* User data for iteration when converting attributes to dense storage */ +typedef struct { + H5F_t *f; /* Pointer to file for insertion */ + hid_t dxpl_id; /* DXPL during iteration */ +} H5O_iter_cvt_t; + +/* User data for iteration when opening an attribute */ +typedef struct { + /* down */ + H5F_t *f; /* Pointer to file attribute is in */ + hid_t dxpl_id; /* DXPL for operation */ + 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 */ + 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; + + +/********************/ +/* Package Typedefs */ +/********************/ + + +/********************/ +/* Local Prototypes */ +/********************/ + + +/*********************/ +/* Package Variables */ +/*********************/ + + +/*****************************/ +/* Library Private Variables */ +/*****************************/ + + +/*******************/ +/* Local Variables */ +/*******************/ + + + +/*------------------------------------------------------------------------- + * Function: H5O_msg_attr_to_dense_cb + * + * Purpose: Object header iterator callback routine to convert compact + * attributes to dense attributes + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Quincey Koziol + * koziol@hdfgroup.org + * Dec 4 2006 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5A_attr_to_dense_cb(H5O_t *oh, H5O_mesg_t *mesg/*in,out*/, + unsigned UNUSED sequence, unsigned *oh_flags_ptr, void *_udata/*in,out*/) +{ + H5O_iter_cvt_t *udata = (H5O_iter_cvt_t *)_udata; /* Operator user data */ + herr_t ret_value = H5_ITER_CONT; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT(H5A_attr_to_dense_cb) + + /* check args */ + HDassert(oh); + HDassert(mesg); + + /* Insert attribute into dense storage */ + if(H5A_dense_insert(udata->f, udata->dxpl_id, oh, mesg->flags, mesg->native) < 0) + HGOTO_ERROR(H5E_OHDR, H5E_CANTINSERT, H5_ITER_ERROR, "unable to add to dense storage") + + /* Convert message into a null message */ + if(H5O_release_mesg(udata->f, udata->dxpl_id, oh, mesg, TRUE, 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_flags_ptr |= H5AC__DIRTIED_FLAG; + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5A_attr_to_dense_cb() */ + + +/*------------------------------------------------------------------------- + * Function: H5O_attr_create + * + * Purpose: Create a new attribute in the object header. + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Quincey Koziol + * Friday, December 8, 2006 + * + *------------------------------------------------------------------------- + */ +herr_t +H5O_attr_create(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 */ + unsigned mesg_flags = 0; /* Flags for storing message */ + 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(H5O_attr_create) + + /* Check arguments */ + HDassert(loc); + HDassert(attr); + + /* Should this message be written as a SOHM? */ + if((shared_mesg = H5SM_try_share(loc->file, dxpl_id, H5O_ATTR_ID, attr)) > 0) + /* Mark the message as shared */ + mesg_flags |= H5O_MSG_FLAG_SHARED; + else if(shared_mesg < 0) + HGOTO_ERROR(H5E_ATTR, H5E_WRITEERROR, FAIL, "error determining if message should be shared") + + /* 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") + +#ifdef QAK +HDfprintf(stderr, "%s: adding attribute to new-style object header\n", FUNC); +HDfprintf(stderr, "%s: oh->nattrs = %Hu\n", FUNC, oh->nattrs); +HDfprintf(stderr, "%s: oh->max_compact = %u\n", FUNC, oh->max_compact); +HDfprintf(stderr, "%s: oh->min_dense = %u\n", FUNC, oh->min_dense); +#endif /* QAK */ + /* Check for switching to "dense" attribute storage */ + if(oh->version > H5O_VERSION_1 && oh->nattrs == oh->max_compact && + !H5F_addr_defined(oh->attr_fheap_addr)) { + H5O_iter_cvt_t udata; /* User data for callback */ + H5O_mesg_operator_t op; /* Wrapper for operator */ +#ifdef QAK +HDfprintf(stderr, "%s: converting attributes to dense storage\n", FUNC); +#endif /* QAK */ + + /* Create dense storage for attributes */ + if(H5A_dense_create(loc->file, dxpl_id, oh) < 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.dxpl_id = dxpl_id; + + /* Iterate over existing attributes, moving them to dense storage */ + op.lib_op = H5A_attr_to_dense_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_CANTCONVERT, FAIL, "error converting attributes to dense storage") + } /* end if */ + + /* Increment attribute count */ + oh->nattrs++; + + /* Check for storing attribute with dense storage */ + if(H5F_addr_defined(oh->attr_fheap_addr)) { + /* Insert attribute into dense storage */ +#ifdef QAK +HDfprintf(stderr, "%s: inserting attribute to dense storage\n", FUNC); +#endif /* QAK */ + if(H5A_dense_insert(loc->file, dxpl_id, oh, mesg_flags, 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, dxpl_id, oh, H5O_MSG_ATTR, mesg_flags, 0, attr, &oh_flags) < 0) + HGOTO_ERROR(H5E_ATTR, H5E_CANTINSERT, FAIL, "unable to create new attribute in header") + } /* 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_create */ + + +/*------------------------------------------------------------------------- + * Function: H5O_attr_open_cb + * + * Purpose: Object header iterator callback routine to open an + * attribute stored compactly. + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Quincey Koziol + * koziol@hdfgroup.org + * Dec 11 2006 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5O_attr_open_cb(H5O_t *oh, H5O_mesg_t *mesg/*in,out*/, + unsigned UNUSED sequence, unsigned UNUSED *oh_flags_ptr, 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_NOAPI_NOINIT(H5O_attr_open_cb) + + /* check args */ + HDassert(oh); + HDassert(mesg); + HDassert(!udata->attr); + + /* 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->name) == 0) { + /* Make a copy of the attribute to return */ + if(NULL == (udata->attr = H5A_copy(NULL, &shared_attr))) + HGOTO_ERROR(H5E_ATTR, H5E_CANTCOPY, H5_ITER_ERROR, "unable to copy attribute") + } /* 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->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") + } /* end if */ + } /* end else */ + + /* Set common info, if we found the correct attribute */ + if(udata->attr) { + /* Stop iterating */ + ret_value = H5_ITER_STOP; + } /* end if */ + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5O_attr_open_cb() */ + + +/*------------------------------------------------------------------------- + * Function: H5O_attr_open + * + * Purpose: Open an existing attribute in an object header. + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Quincey Koziol + * Monday, December 11, 2006 + * + *------------------------------------------------------------------------- + */ +H5A_t * +H5O_attr_open(const H5O_loc_t *loc, const char *name, hid_t dxpl_id) +{ + H5O_t *oh = NULL; /* Pointer to actual object header */ + unsigned oh_flags = H5AC__NO_FLAGS_SET; /* Metadata cache flags for object header */ + H5A_t *ret_value; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT(H5O_attr_open) + + /* Check arguments */ + HDassert(loc); + HDassert(name); + + /* 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, NULL, "unable to load object header") + +#ifdef QAK +HDfprintf(stderr, "%s: opening attribute to new-style object header\n", FUNC); +HDfprintf(stderr, "%s: oh->nattrs = %Hu\n", FUNC, oh->nattrs); +HDfprintf(stderr, "%s: oh->max_compact = %u\n", FUNC, oh->max_compact); +HDfprintf(stderr, "%s: oh->min_dense = %u\n", FUNC, oh->min_dense); +#endif /* QAK */ + /* Check for opening attribute with dense storage */ + if(H5F_addr_defined(oh->attr_fheap_addr)) { + /* Open attribute in dense storage */ + if(NULL == (ret_value = H5A_dense_open(loc->file, dxpl_id, oh, 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.f = loc->file; + udata.dxpl_id = dxpl_id; + udata.name = name; + udata.attr = NULL; + + /* Iterate over attributes, to locate correct one to update */ + op.lib_op = H5O_attr_open_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, NULL, "error updating attribute") + + /* Check that we found the attribute */ + if(!udata.attr) + HGOTO_ERROR(H5E_ATTR, H5E_NOTFOUND, NULL, "can't locate attribute") + + /* Get attribute opened from object header */ + HDassert(udata.attr); + ret_value = udata.attr; + } /* end else */ + +done: + if(oh && H5AC_unprotect(loc->file, dxpl_id, H5AC_OHDR, loc->addr, oh, oh_flags) < 0) + HDONE_ERROR(H5E_ATTR, H5E_PROTECT, NULL, "unable to release object header") + + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5O_attr_open */ + + +/*------------------------------------------------------------------------- + * 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 */ + diff --git a/src/H5Opkg.h b/src/H5Opkg.h index eea0102..b4f5b15 100644 --- a/src/H5Opkg.h +++ b/src/H5Opkg.h @@ -23,6 +23,7 @@ #include "H5Oprivate.h" /* Object headers */ /* Other private headers needed by this file */ +#include "H5Aprivate.h" /* Attributes */ #include "H5ACprivate.h" /* Metadata cache */ /* Object header macros */ @@ -418,6 +419,17 @@ H5_DLL herr_t H5O_release_mesg(H5F_t *f, hid_t dxpl_id, H5O_t *oh, H5_DLL void * H5O_shared_read(H5F_t *f, hid_t dxpl_id, const H5O_shared_t *shared, const H5O_msg_class_t *type, void *mesg); +/* Attribute operations */ +H5_DLL herr_t H5O_attr_create(const H5O_loc_t *loc, hid_t dxpl_id, H5A_t *attr); +H5_DLL H5A_t *H5O_attr_open(const H5O_loc_t *loc, const char *name, + hid_t dxpl_id); +H5_DLL herr_t H5O_attr_write(const H5O_loc_t *loc, hid_t dxpl_id, + H5A_t *attr); +H5_DLL herr_t H5O_attr_rename(const H5O_loc_t *loc, hid_t dxpl_id, + const char *old_name, const char *new_name); +H5_DLL 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); + /* These functions operate on object locations */ H5_DLL H5O_loc_t *H5O_get_loc(hid_t id); diff --git a/src/H5Oprivate.h b/src/H5Oprivate.h index e578377..3c95953 100644 --- a/src/H5Oprivate.h +++ b/src/H5Oprivate.h @@ -31,7 +31,6 @@ #include "H5Opublic.h" /* Object header functions */ /* Public headers needed by this file */ -#include "H5Apublic.h" /* Attributes */ #include "H5Dpublic.h" /* Dataset functions */ #include "H5Lpublic.h" /* Link functions */ #include "H5Spublic.h" /* Dataspace functions */ @@ -375,7 +374,6 @@ typedef herr_t (*H5O_operator_t)(const void *mesg/*in*/, unsigned idx, struct H5P_genplist_t; struct H5SL_t; struct H5O_t; -struct H5A_t; /* Object header routines */ H5_DLL herr_t H5O_init(void); @@ -463,14 +461,5 @@ H5_DLL herr_t H5O_fill_convert(void *_fill, H5T_t *type, hid_t dxpl_id); /* Link operators */ H5_DLL herr_t H5O_link_delete(H5F_t *f, hid_t dxpl_id, const void *_mesg, hbool_t adj_link); -/* Attribute operations */ -H5_DLL herr_t H5O_attr_create(const H5O_loc_t *loc, hid_t dxpl_id, struct H5A_t *attr); -H5_DLL herr_t H5O_attr_write(const H5O_loc_t *loc, hid_t dxpl_id, - struct H5A_t *attr); -H5_DLL herr_t H5O_attr_rename(const H5O_loc_t *loc, hid_t dxpl_id, - const char *old_name, const char *new_name); -H5_DLL 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); - #endif /* _H5Oprivate_H */ diff --git a/src/Makefile.am b/src/Makefile.am index c6fe5fd..44c318f 100755 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -58,7 +58,7 @@ libhdf5_la_SOURCES= H5.c H5checksum.c H5dbg.c H5system.c H5timer.c H5trace.c \ H5HFspace.c H5HFstat.c H5HFtest.c H5HFtiny.c \ H5HG.c H5HGdbg.c H5HL.c H5HLdbg.c H5HP.c H5I.c H5MF.c H5MM.c \ H5MP.c H5MPtest.c H5L.c H5Lexternal.c H5O.c H5Oalloc.c H5Oattr.c \ - H5Obogus.c H5Ocache.c \ + H5Oattribute.c H5Obogus.c H5Ocache.c \ H5Ocont.c H5Ocopy.c H5Odbg.c H5Odtype.c H5Oefl.c H5Ofill.c H5Oginfo.c \ H5Olayout.c \ H5Olinfo.c H5Olink.c H5Omessage.c H5Omtime.c \ diff --git a/src/Makefile.in b/src/Makefile.in index 92085be..d6910be 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -99,7 +99,7 @@ am_libhdf5_la_OBJECTS = H5.lo H5checksum.lo H5dbg.lo H5system.lo \ H5HFspace.lo H5HFstat.lo H5HFtest.lo H5HFtiny.lo H5HG.lo \ H5HGdbg.lo H5HL.lo H5HLdbg.lo H5HP.lo H5I.lo H5MF.lo H5MM.lo \ H5MP.lo H5MPtest.lo H5L.lo H5Lexternal.lo H5O.lo H5Oalloc.lo \ - H5Oattr.lo H5Obogus.lo H5Ocache.lo H5Ocont.lo H5Ocopy.lo \ + H5Oattr.lo H5Oattribute.lo H5Obogus.lo H5Ocache.lo H5Ocont.lo H5Ocopy.lo \ H5Odbg.lo H5Odtype.lo H5Oefl.lo H5Ofill.lo H5Oginfo.lo \ H5Olayout.lo H5Olinfo.lo H5Olink.lo H5Omessage.lo H5Omtime.lo H5Oname.lo \ H5Onull.lo H5Opline.lo H5Osdspace.lo H5Oshared.lo H5Ostab.lo H5Otest.lo \ @@ -414,7 +414,7 @@ libhdf5_la_SOURCES = H5.c H5checksum.c H5dbg.c H5system.c H5timer.c H5trace.c \ H5HFspace.c H5HFstat.c H5HFtest.c H5HFtiny.c \ H5HG.c H5HGdbg.c H5HL.c H5HLdbg.c H5HP.c H5I.c H5MF.c H5MM.c \ H5MP.c H5MPtest.c H5L.c H5Lexternal.c H5O.c H5Oalloc.c H5Oattr.c \ - H5Obogus.c H5Ocache.c \ + H5Oattribute.c H5Obogus.c H5Ocache.c \ H5Ocont.c H5Ocopy.c H5Odbg.c H5Odtype.c H5Oefl.c H5Ofill.c H5Oginfo.c \ H5Olayout.c \ H5Olinfo.c H5Olink.c H5Omessage.c H5Omtime.c \ @@ -660,6 +660,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5O.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Oalloc.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Oattr.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Oattribute.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Obogus.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Ocache.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Ocont.Plo@am__quote@ diff --git a/test/tattr.c b/test/tattr.c index 51d70af..f8ac888 100644 --- a/test/tattr.c +++ b/test/tattr.c @@ -1683,12 +1683,12 @@ test_attr_dtype_shared(hid_t fapl) /**************************************************************** ** -** test_attr_dense(): Test basic H5A (attribute) code. -** Tests "dense" attribute storage +** test_attr_dense_create(): Test basic H5A (attribute) code. +** Tests "dense" attribute storage creation ** ****************************************************************/ static void -test_attr_dense(hid_t fapl) +test_attr_dense_create(hid_t fapl) { hid_t fid; /* HDF5 File ID */ hid_t dataset; /* Dataset ID */ @@ -1703,7 +1703,7 @@ test_attr_dense(hid_t fapl) herr_t ret; /* Generic return value */ /* Output message about test being performed */ - MESSAGE(5, ("Testing Dense Attribute Storage\n")); + MESSAGE(5, ("Testing Dense Attribute Storage Creation\n")); /* Create file */ fid = H5Fcreate(FILENAME, H5F_ACC_TRUNC, H5P_DEFAULT, fapl); @@ -1781,7 +1781,128 @@ HDfprintf(stderr, "max_compact = %u, min_dense = %u\n", max_compact, min_dense); /* Close file */ ret = H5Fclose(fid); CHECK(ret, FAIL, "H5Fclose"); -} /* test_attr_dense() */ +} /* test_attr_dense_create() */ + +/**************************************************************** +** +** test_attr_dense_open(): Test basic H5A (attribute) code. +** Tests opening attributes in "dense" storage +** +****************************************************************/ +static void +test_attr_dense_open(hid_t fapl) +{ + hid_t fid; /* HDF5 File ID */ + hid_t dataset; /* Dataset ID */ + hid_t sid; /* Dataspace ID */ + hid_t attr; /* Attribute ID */ + hid_t dcpl; /* Dataset creation property list ID */ + char attrname[NAME_BUF_SIZE]; /* Name of attribute */ + unsigned max_compact; /* Maximum # of attributes to store compactly */ + unsigned min_dense; /* Minimum # of attributes to store "densely" */ + htri_t is_dense; /* Are attributes stored densely? */ + unsigned u; /* Local index variable */ + herr_t ret; /* Generic return value */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing Opening Attributes in Dense Storage\n")); + + /* Create file */ + fid = H5Fcreate(FILENAME, H5F_ACC_TRUNC, H5P_DEFAULT, fapl); + CHECK(fid, FAIL, "H5Fcreate"); + + /* Create dataspace for dataset */ + sid = H5Screate(H5S_SCALAR); + CHECK(sid, FAIL, "H5Screate"); + + /* Query the group creation properties */ + dcpl = H5Pcreate(H5P_DATASET_CREATE); + CHECK(dcpl, FAIL, "H5Pcreate"); + + /* Create a dataset */ + dataset = H5Dcreate(fid, DSET1_NAME, H5T_NATIVE_UCHAR, sid, dcpl); + CHECK(dataset, FAIL, "H5Dcreate"); + + /* Retrieve limits for compact/dense attribute storage */ + ret = H5Pget_attr_phase_change(dcpl, &max_compact, &min_dense); + CHECK(ret, FAIL, "H5Pget_attr_phase_change"); +#ifdef QAK +HDfprintf(stderr, "max_compact = %u, min_dense = %u\n", max_compact, min_dense); +#endif /* QAK */ + + /* Check on dataset's attribute storage status */ + is_dense = H5O_is_attr_dense_test(dataset); + VERIFY(is_dense, FALSE, "H5O_is_attr_dense_test"); + + /* Add attributes, until just before coverting to dense storage */ + for(u = 0; u < max_compact; u++) { + /* Create attribute */ + sprintf(attrname, "attr %02u", u); + attr = H5Acreate(dataset, attrname, H5T_NATIVE_UINT, sid, H5P_DEFAULT); + CHECK(attr, FAIL, "H5Acreate"); + + /* Write data into the attribute */ + ret = H5Awrite(attr, H5T_NATIVE_UINT, &u); + CHECK(ret, FAIL, "H5Awrite"); + + /* Close attribute */ + ret = H5Aclose(attr); + CHECK(ret, FAIL, "H5Aclose"); + } /* end for */ + + /* Check on dataset's attribute storage status */ + is_dense = H5O_is_attr_dense_test(dataset); + VERIFY(is_dense, FALSE, "H5O_is_attr_dense_test"); + + /* Add one more attribute, to push into "dense" storage */ + /* Create attribute */ + sprintf(attrname, "attr %02u", u); + attr = H5Acreate(dataset, attrname, H5T_NATIVE_UINT, sid, H5P_DEFAULT); + CHECK(attr, FAIL, "H5Acreate"); + + /* Check on dataset's attribute storage status */ + is_dense = H5O_is_attr_dense_test(dataset); + VERIFY(is_dense, TRUE, "H5O_is_attr_dense_test"); + + /* Write data into the attribute */ + ret = H5Awrite(attr, H5T_NATIVE_UINT, &u); + CHECK(ret, FAIL, "H5Awrite"); + + /* Close attribute */ + ret = H5Aclose(attr); + CHECK(ret, FAIL, "H5Aclose"); + + /* Close dataspace */ + ret = H5Sclose(sid); + CHECK(ret, FAIL, "H5Sclose"); + + /* Re-open all the attributes and verify the data */ + for(u = 0; u <= max_compact; u++) { + unsigned value; + + /* Open attribute */ + sprintf(attrname, "attr %02u", u); + attr = H5Aopen_name(dataset, attrname); + CHECK(attr, FAIL, "H5Aopen"); + + /* Read data from the attribute */ + ret = H5Aread(attr, H5T_NATIVE_UINT, &value); + CHECK(ret, FAIL, "H5Aread"); + VERIFY(value, u, "H5Aread"); + + /* Close attribute */ + ret = H5Aclose(attr); + CHECK(ret, FAIL, "H5Aclose"); + } /* end for */ + + /* Close Dataset */ + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close file */ + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); +} /* test_attr_dense_open() */ /**************************************************************** ** @@ -1852,7 +1973,8 @@ test_attr(void) } /* end for */ /* Tests on "new format" attribute storage */ - test_attr_dense(fapl2); /* Test dense attribute storage */ + test_attr_dense_create(fapl2); /* Test dense attribute storage creation */ + test_attr_dense_open(fapl2); /* Test opening attributes in dense storage */ #else /* QAK */ HDfprintf(stderr, "Uncomment tests!\n"); #endif /* QAK */ -- cgit v0.12