Coverage Report

Created: 2025-08-28 06:37

/src/hdf5/src/H5Oattribute.c
Line
Count
Source (jump to first uncovered line)
1
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2
 * Copyright by The HDF Group.                                               *
3
 * All rights reserved.                                                      *
4
 *                                                                           *
5
 * This file is part of HDF5.  The full HDF5 copyright notice, including     *
6
 * terms governing use, modification, and redistribution, is contained in    *
7
 * the LICENSE file, which can be found at the root of the source code       *
8
 * distribution tree, or in https://www.hdfgroup.org/licenses.               *
9
 * If you do not have access to either file, you may request a copy from     *
10
 * help@hdfgroup.org.                                                        *
11
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
12
13
/*-------------------------------------------------------------------------
14
 *
15
 * Created:     H5Oattribute.c
16
 *
17
 * Purpose:     Object header attribute routines.
18
 *
19
 *-------------------------------------------------------------------------
20
 */
21
22
/****************/
23
/* Module Setup */
24
/****************/
25
26
#define H5A_FRIEND     /* Suppress error about including H5Apkg.h */
27
#include "H5Omodule.h" /* This source code file is part of the H5O module */
28
29
/***********/
30
/* Headers */
31
/***********/
32
#include "H5private.h"   /* Generic Functions                        */
33
#include "H5Apkg.h"      /* Attributes                               */
34
#include "H5Eprivate.h"  /* Error handling                           */
35
#include "H5MMprivate.h" /* Memory management                        */
36
#include "H5Opkg.h"      /* Object headers                           */
37
#include "H5SMprivate.h" /* Shared Object Header Messages            */
38
#include "H5Iprivate.h"  /* IDs                                      */
39
#include "H5Fprivate.h"  /* File                                     */
40
41
/****************/
42
/* Local Macros */
43
/****************/
44
45
/******************/
46
/* Local Typedefs */
47
/******************/
48
49
/* User data for iteration when converting attributes to dense storage */
50
typedef struct {
51
    H5F_t       *f;     /* Pointer to file for insertion */
52
    H5O_ainfo_t *ainfo; /* Attribute info struct */
53
} H5O_iter_cvt_t;
54
55
/* User data for iteration when opening an attribute */
56
typedef struct {
57
    /* down */
58
    const char *name; /* Name of attribute to open */
59
60
    /* up */
61
    H5A_t *attr; /* Attribute data to update object header with */
62
} H5O_iter_opn_t;
63
64
/* User data for iteration when updating an attribute */
65
typedef struct {
66
    /* down */
67
    H5F_t *f;    /* Pointer to file attribute is in */
68
    H5A_t *attr; /* Attribute data to update object header with */
69
70
    /* up */
71
    bool found; /* Whether the attribute was found */
72
} H5O_iter_wrt_t;
73
74
/* User data for iteration when renaming an attribute */
75
typedef struct {
76
    /* down */
77
    H5F_t      *f;        /* Pointer to file attribute is in */
78
    const char *old_name; /* Old name of attribute */
79
    const char *new_name; /* New name of attribute */
80
81
    /* up */
82
    bool found; /* Whether the attribute was found */
83
} H5O_iter_ren_t;
84
85
/* User data for iteration when removing an attribute */
86
typedef struct {
87
    /* down */
88
    H5F_t      *f;    /* Pointer to file attribute is in */
89
    const char *name; /* Name of attribute to open */
90
91
    /* up */
92
    bool found; /* Found attribute to delete */
93
} H5O_iter_rm_t;
94
95
/* User data for iteration when checking if an attribute exists */
96
typedef struct {
97
    /* down */
98
    const char *name; /* Name of attribute to open */
99
100
    /* up */
101
    bool *exists; /* Pointer to flag to indicate attribute exists */
102
} H5O_iter_xst_t;
103
104
/********************/
105
/* Package Typedefs */
106
/********************/
107
108
/********************/
109
/* Local Prototypes */
110
/********************/
111
static herr_t H5O__attr_to_dense_cb(H5O_t *oh, H5O_mesg_t *mesg, unsigned H5_ATTR_UNUSED sequence,
112
                                    unsigned *oh_modified, void *_udata);
113
static htri_t H5O__attr_find_opened_attr(const H5O_loc_t *loc, H5A_t **attr, const char *name_to_open);
114
static herr_t H5O__attr_open_cb(H5O_t *oh, H5O_mesg_t *mesg, unsigned sequence,
115
                                unsigned H5_ATTR_UNUSED *oh_modified, void *_udata);
116
static herr_t H5O__attr_open_by_idx_cb(const H5A_t *attr, void *_ret_attr);
117
static herr_t H5O__attr_write_cb(H5O_t *oh, H5O_mesg_t *mesg, unsigned H5_ATTR_UNUSED sequence,
118
                                 unsigned *oh_modified, void *_udata);
119
static herr_t H5O__attr_rename_chk_cb(H5O_t H5_ATTR_UNUSED *oh, H5O_mesg_t *mesg,
120
                                      unsigned H5_ATTR_UNUSED sequence, unsigned H5_ATTR_UNUSED *oh_modified,
121
                                      void *_udata);
122
static herr_t H5O__attr_rename_mod_cb(H5O_t *oh, H5O_mesg_t *mesg, unsigned H5_ATTR_UNUSED sequence,
123
                                      unsigned *oh_modified, void *_udata);
124
static herr_t H5O__attr_remove_update(const H5O_loc_t *loc, H5O_t *oh, H5O_ainfo_t *ainfo);
125
static herr_t H5O__attr_remove_cb(H5O_t *oh, H5O_mesg_t *mesg, unsigned H5_ATTR_UNUSED sequence,
126
                                  unsigned *oh_modified, void *_udata);
127
static herr_t H5O__attr_exists_cb(H5O_t H5_ATTR_UNUSED *oh, H5O_mesg_t *mesg,
128
                                  unsigned H5_ATTR_UNUSED sequence, unsigned H5_ATTR_UNUSED *oh_modified,
129
                                  void *_udata);
130
131
/*********************/
132
/* Package Variables */
133
/*********************/
134
135
/*****************************/
136
/* Library Private Variables */
137
/*****************************/
138
139
/*******************/
140
/* Local Variables */
141
/*******************/
142
143
/*-------------------------------------------------------------------------
144
 * Function:    H5O__attr_to_dense_cb
145
 *
146
 * Purpose:     Object header iterator callback routine to convert compact
147
 *              attributes to dense attributes
148
 *
149
 * Return:      SUCCEED/FAIL
150
 *
151
 *-------------------------------------------------------------------------
152
 */
153
static herr_t
154
H5O__attr_to_dense_cb(H5O_t *oh, H5O_mesg_t *mesg /*in,out*/, unsigned H5_ATTR_UNUSED sequence,
155
                      unsigned *oh_modified, void *_udata /*in,out*/)
156
0
{
157
0
    H5O_iter_cvt_t *udata     = (H5O_iter_cvt_t *)_udata; /* Operator user data */
158
0
    H5A_t          *attr      = (H5A_t *)mesg->native;    /* Pointer to attribute to insert */
159
0
    herr_t          ret_value = H5_ITER_CONT;             /* Return value */
160
161
0
    FUNC_ENTER_PACKAGE
162
163
    /* check args */
164
0
    assert(oh);
165
0
    assert(mesg);
166
0
    assert(udata);
167
0
    assert(udata->f);
168
0
    assert(udata->ainfo);
169
0
    assert(attr);
170
171
    /* Insert attribute into dense storage */
172
0
    if (H5A__dense_insert(udata->f, udata->ainfo, attr) < 0)
173
0
        HGOTO_ERROR(H5E_OHDR, H5E_CANTINSERT, H5_ITER_ERROR, "unable to add to dense storage");
174
175
    /* Convert message into a null message in the header */
176
    /* (don't delete attribute's space in the file though) */
177
0
    if (H5O__release_mesg(udata->f, oh, mesg, false) < 0)
178
0
        HGOTO_ERROR(H5E_OHDR, H5E_CANTDELETE, H5_ITER_ERROR, "unable to convert into null message");
179
180
    /* Indicate that the object header was modified */
181
0
    *oh_modified = H5O_MODIFY_CONDENSE;
182
183
0
done:
184
0
    FUNC_LEAVE_NOAPI(ret_value)
185
0
} /* end H5O__attr_to_dense_cb() */
186
187
/*-------------------------------------------------------------------------
188
 * Function:    H5O__attr_create
189
 *
190
 * Purpose:     Create a new attribute in the object header.
191
 *
192
 * Return:      SUCCEED/FAIL
193
 *
194
 *-------------------------------------------------------------------------
195
 */
196
herr_t
197
H5O__attr_create(const H5O_loc_t *loc, H5A_t *attr)
198
0
{
199
0
    H5O_t      *oh = NULL;           /* Pointer to actual object header */
200
0
    H5O_ainfo_t ainfo;               /* Attribute information for object */
201
0
    htri_t      shared_mesg;         /* Should this message be stored in the Shared Message table? */
202
0
    herr_t      ret_value = SUCCEED; /* Return value */
203
204
0
    FUNC_ENTER_PACKAGE
205
206
    /* Check arguments */
207
0
    assert(loc);
208
0
    assert(attr);
209
210
    /* Pin the object header */
211
0
    if (NULL == (oh = H5O_pin(loc)))
212
0
        HGOTO_ERROR(H5E_ATTR, H5E_CANTPIN, FAIL, "unable to pin object header");
213
214
    /* Check for creating attribute with unusual datatype */
215
0
    if (!(H5O_has_chksum(oh) || (H5F_RFIC_FLAGS(loc->file) & H5F_RFIC_UNUSUAL_NUM_UNUSED_NUMERIC_BITS)) &&
216
0
        H5T_is_numeric_with_unusual_unused_bits(attr->shared->dt))
217
0
        HGOTO_ERROR(H5E_ATTR, H5E_CANTINIT, FAIL,
218
0
                    "creating attribute with unusual datatype, see documentation for "
219
0
                    "H5Pset_relax_file_integrity_checks for details.");
220
221
    /* Check if this object already has attribute information */
222
0
    if (oh->version > H5O_VERSION_1) {
223
0
        bool   new_ainfo = false; /* Flag to indicate that the attribute information is new */
224
0
        htri_t ainfo_exists;      /* Whether the attribute info was retrieved */
225
226
        /* Check for (& retrieve if available) attribute info */
227
0
        if ((ainfo_exists = H5A__get_ainfo(loc->file, oh, &ainfo)) < 0)
228
0
            HGOTO_ERROR(H5E_ATTR, H5E_CANTGET, FAIL, "can't check for attribute info message");
229
0
        if (!ainfo_exists) {
230
            /* Initialize attribute information */
231
0
            ainfo.track_corder    = (bool)((oh->flags & H5O_HDR_ATTR_CRT_ORDER_TRACKED) ? true : false);
232
0
            ainfo.index_corder    = (bool)((oh->flags & H5O_HDR_ATTR_CRT_ORDER_INDEXED) ? true : false);
233
0
            ainfo.max_crt_idx     = 0;
234
0
            ainfo.corder_bt2_addr = HADDR_UNDEF;
235
0
            ainfo.nattrs          = 0;
236
0
            ainfo.fheap_addr      = HADDR_UNDEF;
237
0
            ainfo.name_bt2_addr   = HADDR_UNDEF;
238
239
            /* Set flag to add attribute information to object header */
240
0
            new_ainfo = true;
241
0
        } /* end if */
242
0
        else {
243
            /* Sanity check attribute info read in */
244
0
            assert(ainfo.nattrs > 0);
245
0
            assert(ainfo.track_corder == ((oh->flags & H5O_HDR_ATTR_CRT_ORDER_TRACKED) > 0));
246
0
            assert(ainfo.index_corder == ((oh->flags & H5O_HDR_ATTR_CRT_ORDER_INDEXED) > 0));
247
0
        } /* end else */
248
249
        /* Check if switching to "dense" attribute storage is possible */
250
0
        if (!H5_addr_defined(ainfo.fheap_addr)) {
251
0
            htri_t shareable;    /* Whether the attribute will be shared */
252
0
            size_t raw_size = 0; /* Raw size of message */
253
254
            /* Check for attribute being shareable */
255
0
            if ((shareable = H5SM_can_share(loc->file, NULL, NULL, H5O_ATTR_ID, attr)) < 0)
256
0
                HGOTO_ERROR(H5E_ATTR, H5E_BADMESG, FAIL, "can't determine attribute sharing status");
257
0
            else if (shareable == false) {
258
                /* Compute the size needed to encode the attribute */
259
0
                raw_size = (H5O_MSG_ATTR->raw_size)(loc->file, false, attr);
260
0
            } /* end if */
261
262
            /* Check for condititions for switching to "dense" attribute storage are met */
263
0
            if (ainfo.nattrs == oh->max_compact || (!shareable && raw_size >= H5O_MESG_MAX_SIZE)) {
264
0
                H5O_iter_cvt_t      udata; /* User data for callback */
265
0
                H5O_mesg_operator_t op;    /* Wrapper for operator */
266
267
                /* Create dense storage for attributes */
268
0
                if (H5A__dense_create(loc->file, &ainfo) < 0)
269
0
                    HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, FAIL,
270
0
                                "unable to create dense storage for attributes");
271
272
                /* Set up user data for callback */
273
0
                udata.f     = loc->file;
274
0
                udata.ainfo = &ainfo;
275
276
                /* Iterate over existing attributes, moving them to dense storage */
277
0
                op.op_type  = H5O_MESG_OP_LIB;
278
0
                op.u.lib_op = H5O__attr_to_dense_cb;
279
0
                if (H5O__msg_iterate_real(loc->file, oh, H5O_MSG_ATTR, &op, &udata) < 0)
280
0
                    HGOTO_ERROR(H5E_ATTR, H5E_CANTCONVERT, FAIL,
281
0
                                "error converting attributes to dense storage");
282
0
            } /* end if */
283
0
        }     /* end if */
284
285
        /* Increment attribute count on object */
286
0
        ainfo.nattrs++;
287
288
        /* Check whether we're tracking the creation index on attributes */
289
0
        if (ainfo.track_corder) {
290
            /* Check for attribute creation order index on the object wrapping around */
291
0
            if (ainfo.max_crt_idx == H5O_MAX_CRT_ORDER_IDX)
292
0
                HGOTO_ERROR(H5E_ATTR, H5E_CANTINC, FAIL, "attribute creation index can't be incremented");
293
294
            /* Set the creation order index on the attribute & incr. creation order index */
295
0
            attr->shared->crt_idx = ainfo.max_crt_idx++;
296
0
        } /* end if */
297
0
        else
298
            /* Set "bogus" creation index for attribute */
299
0
            attr->shared->crt_idx = H5O_MAX_CRT_ORDER_IDX;
300
301
        /* Add the attribute information message, if one is needed */
302
0
        if (new_ainfo) {
303
0
            if (H5O__msg_append_real(loc->file, oh, H5O_MSG_AINFO, H5O_MSG_FLAG_DONTSHARE, 0, &ainfo) < 0)
304
0
                HGOTO_ERROR(H5E_ATTR, H5E_CANTINSERT, FAIL, "unable to create new attribute info message");
305
0
        } /* end if */
306
        /* Otherwise, update existing message */
307
0
        else if (H5O__msg_write_real(loc->file, oh, H5O_MSG_AINFO, H5O_MSG_FLAG_DONTSHARE, 0, &ainfo) < 0)
308
0
            HGOTO_ERROR(H5E_ATTR, H5E_CANTUPDATE, FAIL, "unable to update attribute info message");
309
0
    } /* end if */
310
0
    else {
311
        /* Set "bogus" creation index for attribute */
312
0
        attr->shared->crt_idx = H5O_MAX_CRT_ORDER_IDX;
313
314
        /* Set attribute info value to get attribute into object header */
315
0
        ainfo.fheap_addr = HADDR_UNDEF;
316
0
    } /* end else */
317
318
    /* Check for storing attribute with dense storage */
319
0
    if (H5_addr_defined(ainfo.fheap_addr)) {
320
        /* Insert attribute into dense storage */
321
0
        if (H5A__dense_insert(loc->file, &ainfo, attr) < 0)
322
0
            HGOTO_ERROR(H5E_ATTR, H5E_CANTINSERT, FAIL, "unable to add to dense storage");
323
0
    } /* end if */
324
0
    else
325
        /* Append new message to object header */
326
0
        if (H5O__msg_append_real(loc->file, oh, H5O_MSG_ATTR, 0, 0, attr) < 0)
327
0
            HGOTO_ERROR(H5E_ATTR, H5E_CANTINSERT, FAIL, "unable to create new attribute in header");
328
329
    /* Increment reference count for shared attribute object for the
330
     * object handle created by the caller function H5A__create.  The count
331
     * for the cached object header has been incremented in the step above
332
     * (in H5O__msg_append_real).  The dense storage doesn't need a count.
333
     */
334
0
    attr->shared->nrefs += 1;
335
336
    /* Was new attribute shared? */
337
0
    if ((shared_mesg = H5O_msg_is_shared(H5O_ATTR_ID, attr)) > 0) {
338
0
        hsize_t attr_rc; /* Attribute's ref count in shared message storage */
339
340
        /* Retrieve ref count for shared attribute */
341
0
        if (H5SM_get_refcount(loc->file, H5O_ATTR_ID, &attr->sh_loc, &attr_rc) < 0)
342
0
            HGOTO_ERROR(H5E_ATTR, H5E_CANTGET, FAIL, "can't retrieve shared message ref count");
343
344
        /* If this is not the first copy of the attribute in the shared message
345
         *      storage, decrement the reference count on any shared components
346
         *      of the attribute.  This is done because the shared message
347
         *      storage's "try delete" call doesn't call the message class's
348
         *      "delete" callback until the reference count drops to zero.
349
         *      However, attributes have already increased the reference
350
         *      count on shared components before passing the attribute
351
         *      to the shared message code to manage, causing an asymmetry
352
         *      in the reference counting for any shared components.
353
         *
354
         *      The alternate solution is to have the shared message's "try
355
         *      delete" code always call the message class's "delete" callback,
356
         *      even when the reference count is positive.  This can be done
357
         *      without an appreciable performance hit (by using H5HF_op() in
358
         *      the shared message comparison v2 B-tree callback), but it has
359
         *      the undesirable side-effect of leaving the reference count on
360
         *      the attribute's shared components artificially (and possibly
361
         *      misleadingly) high, because there's only one shared attribute
362
         *      referencing the shared components, not <refcount for the
363
         *      shared attribute> objects referencing the shared components.
364
         *
365
         *      *ick* -QAK, 2007/01/08
366
         */
367
0
        if (attr_rc > 1) {
368
0
            if (H5O__attr_delete(loc->file, oh, attr) < 0)
369
0
                HGOTO_ERROR(H5E_ATTR, H5E_CANTDELETE, FAIL, "unable to delete attribute");
370
0
        } /* end if */
371
0
    }     /* end if */
372
0
    else if (shared_mesg < 0)
373
0
        HGOTO_ERROR(H5E_ATTR, H5E_WRITEERROR, FAIL, "error determining if message should be shared");
374
375
    /* Update the modification time, if any */
376
0
    if (H5O_touch_oh(loc->file, oh, false) < 0)
377
0
        HGOTO_ERROR(H5E_ATTR, H5E_CANTUPDATE, FAIL, "unable to update time on object");
378
379
0
done:
380
0
    if (oh && H5O_unpin(oh) < 0)
381
0
        HDONE_ERROR(H5E_ATTR, H5E_CANTUNPIN, FAIL, "unable to unpin object header");
382
383
0
    FUNC_LEAVE_NOAPI(ret_value)
384
0
} /* end H5O__attr_create() */
385
386
/*-------------------------------------------------------------------------
387
 * Function:    H5O__attr_open_cb
388
 *
389
 * Purpose:     Object header iterator callback routine to open an
390
 *              attribute stored compactly.
391
 *
392
 * Return:      SUCCEED/FAIL
393
 *
394
 *-------------------------------------------------------------------------
395
 */
396
static herr_t
397
H5O__attr_open_cb(H5O_t *oh, H5O_mesg_t *mesg /*in,out*/, unsigned sequence,
398
                  unsigned H5_ATTR_UNUSED *oh_modified, void *_udata /*in,out*/)
399
1
{
400
1
    H5O_iter_opn_t *udata     = (H5O_iter_opn_t *)_udata; /* Operator user data */
401
1
    herr_t          ret_value = H5_ITER_CONT;             /* Return value */
402
403
1
    FUNC_ENTER_PACKAGE
404
405
    /* check args */
406
1
    assert(oh);
407
1
    assert(mesg);
408
1
    assert(!udata->attr);
409
410
    /* Check for correct attribute message to modify */
411
1
    if (strcmp(((H5A_t *)mesg->native)->shared->name, udata->name) == 0) {
412
        /* Make a copy of the attribute to return */
413
0
        if (NULL == (udata->attr = H5A__copy(NULL, (H5A_t *)mesg->native)))
414
0
            HGOTO_ERROR(H5E_ATTR, H5E_CANTCOPY, H5_ITER_ERROR, "unable to copy attribute");
415
416
        /* Assign [somewhat arbitrary] creation order value, for older versions
417
         * of the format or if creation order is not tracked */
418
0
        if (oh->version == H5O_VERSION_1 || !(oh->flags & H5O_HDR_ATTR_CRT_ORDER_TRACKED))
419
0
            udata->attr->shared->crt_idx = sequence;
420
421
        /* Stop iterating */
422
0
        ret_value = H5_ITER_STOP;
423
0
    } /* end if */
424
425
1
done:
426
1
    FUNC_LEAVE_NOAPI(ret_value)
427
1
} /* end H5O__attr_open_cb() */
428
429
/*-------------------------------------------------------------------------
430
 * Function:    H5O__attr_open_by_name
431
 *
432
 * Purpose:     Open an existing attribute in an object header.
433
 *
434
 * Return:      SUCCEED/FAIL
435
 *
436
 *-------------------------------------------------------------------------
437
 */
438
H5A_t *
439
H5O__attr_open_by_name(const H5O_loc_t *loc, const char *name)
440
52
{
441
52
    H5O_t      *oh = NULL;               /* Pointer to actual object header */
442
52
    H5O_ainfo_t ainfo;                   /* Attribute information for object */
443
52
    H5A_t      *exist_attr      = NULL;  /* Existing opened attribute object */
444
52
    H5A_t      *opened_attr     = NULL;  /* Newly opened attribute object */
445
52
    htri_t      found_open_attr = false; /* Whether opened object is found */
446
52
    H5A_t      *ret_value       = NULL;  /* Return value */
447
448
52
    FUNC_ENTER_PACKAGE_TAG(loc->addr)
449
450
    /* Check arguments */
451
52
    assert(loc);
452
52
    assert(name);
453
454
    /* Protect the object header to iterate over */
455
52
    if (NULL == (oh = H5O_protect(loc, H5AC__READ_ONLY_FLAG, false)))
456
0
        HGOTO_ERROR(H5E_ATTR, H5E_CANTPROTECT, NULL, "unable to load object header");
457
458
    /* Check for attribute info stored */
459
52
    ainfo.fheap_addr = HADDR_UNDEF;
460
52
    if (oh->version > H5O_VERSION_1) {
461
        /* Check for (& retrieve if available) attribute info */
462
0
        if (H5A__get_ainfo(loc->file, oh, &ainfo) < 0)
463
0
            HGOTO_ERROR(H5E_ATTR, H5E_CANTGET, NULL, "can't check for attribute info message");
464
0
    } /* end if */
465
466
    /* If found the attribute is already opened, make a copy of it to share the
467
     * object information.  If not, open attribute as a new object
468
     */
469
52
    if ((found_open_attr = H5O__attr_find_opened_attr(loc, &exist_attr, name)) < 0)
470
0
        HGOTO_ERROR(H5E_ATTR, H5E_CANTGET, NULL, "failed in finding opened attribute");
471
52
    else if (found_open_attr == true) {
472
0
        if (NULL == (opened_attr = H5A__copy(NULL, exist_attr)))
473
0
            HGOTO_ERROR(H5E_ATTR, H5E_CANTCOPY, NULL, "can't copy existing attribute");
474
0
    } /* end else if */
475
52
    else {
476
        /* Check for attributes in dense storage */
477
52
        if (H5_addr_defined(ainfo.fheap_addr)) {
478
            /* Open attribute with dense storage */
479
0
            if (NULL == (opened_attr = H5A__dense_open(loc->file, &ainfo, name)))
480
0
                HGOTO_ERROR(H5E_ATTR, H5E_CANTOPENOBJ, NULL, "can't open attribute");
481
0
        } /* end if */
482
52
        else {
483
52
            H5O_iter_opn_t      udata; /* User data for callback */
484
52
            H5O_mesg_operator_t op;    /* Wrapper for operator */
485
486
            /* Set up user data for callback */
487
52
            udata.name = name;
488
52
            udata.attr = NULL;
489
490
            /* Iterate over attributes, to locate correct one to open */
491
52
            op.op_type  = H5O_MESG_OP_LIB;
492
52
            op.u.lib_op = H5O__attr_open_cb;
493
52
            if (H5O__msg_iterate_real(loc->file, oh, H5O_MSG_ATTR, &op, &udata) < 0)
494
18
                HGOTO_ERROR(H5E_ATTR, H5E_CANTOPENOBJ, NULL, "error updating attribute");
495
496
            /* Check that we found the attribute */
497
34
            if (!udata.attr)
498
34
                HGOTO_ERROR(H5E_ATTR, H5E_NOTFOUND, NULL, "can't locate attribute: '%s'", name);
499
500
            /* Get attribute opened from object header */
501
0
            assert(udata.attr);
502
0
            opened_attr = udata.attr;
503
0
        } /* end else */
504
505
        /* Mark datatype as being on disk now */
506
0
        if (H5T_set_loc(opened_attr->shared->dt, H5F_VOL_OBJ(loc->file), H5T_LOC_DISK) < 0)
507
0
            HGOTO_ERROR(H5E_ATTR, H5E_CANTINIT, NULL, "invalid datatype location");
508
0
    } /* end else */
509
510
    /* Set return value */
511
0
    ret_value = opened_attr;
512
513
52
done:
514
52
    if (oh && H5O_unprotect(loc, oh, H5AC__NO_FLAGS_SET) < 0)
515
0
        HDONE_ERROR(H5E_ATTR, H5E_CANTUNPROTECT, NULL, "unable to release object header");
516
517
    /* Release any resources, on error */
518
52
    if (NULL == ret_value && opened_attr)
519
0
        if (H5A__close(opened_attr) < 0)
520
0
            HDONE_ERROR(H5E_ATTR, H5E_CANTCLOSEOBJ, NULL, "can't close attribute");
521
522
52
    FUNC_LEAVE_NOAPI_TAG(ret_value)
523
52
} /* end H5O__attr_open_by_name() */
524
525
/*-------------------------------------------------------------------------
526
 * Function:    H5O__attr_open_by_idx_cb
527
 *
528
 * Purpose:     Callback routine opening an attribute by index
529
 *
530
 * Return:      SUCCEED/FAIL
531
 *
532
 *-------------------------------------------------------------------------
533
 */
534
static herr_t
535
H5O__attr_open_by_idx_cb(const H5A_t *attr, void *_ret_attr)
536
0
{
537
0
    H5A_t **ret_attr  = (H5A_t **)_ret_attr; /* 'User data' passed in */
538
0
    herr_t  ret_value = H5_ITER_STOP;        /* Return value */
539
540
0
    FUNC_ENTER_PACKAGE
541
542
    /* check arguments */
543
0
    assert(attr);
544
0
    assert(ret_attr);
545
546
    /* Copy attribute information.  Shared some attribute information. */
547
0
    if (NULL == (*ret_attr = H5A__copy(NULL, attr)))
548
0
        HGOTO_ERROR(H5E_ATTR, H5E_CANTCOPY, H5_ITER_ERROR, "can't copy attribute");
549
550
0
done:
551
0
    FUNC_LEAVE_NOAPI(ret_value)
552
0
} /* end H5O__attr_open_by_idx_cb() */
553
554
/*-------------------------------------------------------------------------
555
 * Function:    H5O__attr_open_by_idx
556
 *
557
 * Purpose:     Open an existing attribute in an object header according to
558
 *              an index.
559
 *
560
 * Return:      SUCCEED/FAIL
561
 *
562
 *-------------------------------------------------------------------------
563
 */
564
H5A_t *
565
H5O__attr_open_by_idx(const H5O_loc_t *loc, H5_index_t idx_type, H5_iter_order_t order, hsize_t n)
566
0
{
567
0
    H5A_attr_iter_op_t attr_op;                 /* Attribute operator */
568
0
    H5A_t             *exist_attr      = NULL;  /* Existing opened attribute object */
569
0
    H5A_t             *opened_attr     = NULL;  /* Newly opened attribute object */
570
0
    htri_t             found_open_attr = false; /* Whether opened object is found */
571
0
    H5A_t             *ret_value       = NULL;  /* Return value */
572
573
0
    FUNC_ENTER_PACKAGE
574
575
    /* Check arguments */
576
0
    assert(loc);
577
578
    /* Build attribute operator info */
579
0
    attr_op.op_type  = H5A_ATTR_OP_LIB;
580
0
    attr_op.u.lib_op = H5O__attr_open_by_idx_cb;
581
582
    /* Iterate over attributes to locate correct one */
583
0
    if (H5O_attr_iterate_real((hid_t)-1, loc, idx_type, order, n, NULL, &attr_op, &opened_attr) < 0)
584
0
        HGOTO_ERROR(H5E_ATTR, H5E_BADITER, NULL, "can't locate attribute");
585
586
    /* Find out whether it has already been opened.  If it has, close the object
587
     * and make a copy of the already opened object to share the object info.
588
     */
589
0
    if (opened_attr) {
590
0
        if ((found_open_attr = H5O__attr_find_opened_attr(loc, &exist_attr, opened_attr->shared->name)) < 0)
591
0
            HGOTO_ERROR(H5E_ATTR, H5E_CANTGET, NULL, "failed in finding opened attribute");
592
593
        /* If found that the attribute is already opened, make a copy of it
594
         * and close the object just opened.
595
         */
596
0
        if (found_open_attr && exist_attr) {
597
0
            if (H5A__close(opened_attr) < 0)
598
0
                HGOTO_ERROR(H5E_ATTR, H5E_CANTCLOSEOBJ, NULL, "can't close attribute");
599
0
            if (NULL == (opened_attr = H5A__copy(NULL, exist_attr)))
600
0
                HGOTO_ERROR(H5E_ATTR, H5E_CANTCOPY, NULL, "can't copy existing attribute");
601
0
        }
602
0
        else {
603
            /* Mark datatype as being on disk now */
604
0
            if (H5T_set_loc(opened_attr->shared->dt, H5F_VOL_OBJ(loc->file), H5T_LOC_DISK) < 0)
605
0
                HGOTO_ERROR(H5E_ATTR, H5E_CANTINIT, NULL, "invalid datatype location");
606
0
        } /* end if */
607
0
    }     /* end if */
608
609
    /* Set return value */
610
0
    ret_value = opened_attr;
611
612
0
done:
613
    /* Release any resources, on error */
614
0
    if (NULL == ret_value && opened_attr)
615
0
        if (H5A__close(opened_attr) < 0)
616
0
            HDONE_ERROR(H5E_ATTR, H5E_CANTCLOSEOBJ, NULL, "can't close attribute");
617
618
0
    FUNC_LEAVE_NOAPI(ret_value)
619
0
} /* end H5O__attr_open_by_idx() */
620
621
/*-------------------------------------------------------------------------
622
 * Function:    H5O__attr_find_opened_attr
623
 *
624
 * Purpose:     Find out whether an attribute has been opened by giving
625
 *              the name.  Return the pointer to the object if found.
626
 *
627
 * Return:      true: found the already opened object
628
 *              false:  didn't find the opened object
629
 *              FAIL: function failed.
630
 *
631
 *-------------------------------------------------------------------------
632
 */
633
static htri_t
634
H5O__attr_find_opened_attr(const H5O_loc_t *loc, H5A_t **attr, const char *name_to_open)
635
52
{
636
52
    hid_t        *attr_id_list = NULL; /* List of IDs for opened attributes */
637
52
    unsigned long loc_fnum;            /* File serial # for object */
638
52
    size_t        num_open_attr;       /* Number of opened attributes */
639
52
    htri_t        ret_value = false;   /* Return value */
640
641
52
    FUNC_ENTER_PACKAGE
642
643
    /* Get file serial number for the location of attribute */
644
52
    if (H5F_get_fileno(loc->file, &loc_fnum) < 0)
645
0
        HGOTO_ERROR(H5E_ATTR, H5E_BADVALUE, FAIL, "can't get file serial number");
646
647
    /* Count all opened attributes */
648
52
    if (H5F_get_obj_count(loc->file, H5F_OBJ_ATTR | H5F_OBJ_LOCAL, false, &num_open_attr) < 0)
649
0
        HGOTO_ERROR(H5E_ATTR, H5E_CANTGET, FAIL, "can't count opened attributes");
650
651
    /* Find out whether the attribute has been opened */
652
52
    if (num_open_attr) {
653
0
        size_t check_num_attr; /* Number of open attribute IDs */
654
0
        size_t u;              /* Local index variable */
655
656
        /* Allocate space for the attribute ID list */
657
0
        if (NULL == (attr_id_list = (hid_t *)H5MM_malloc(num_open_attr * sizeof(hid_t))))
658
0
            HGOTO_ERROR(H5E_ATTR, H5E_CANTALLOC, FAIL, "unable to allocate memory for attribute ID list");
659
660
        /* Retrieve the IDs of all opened attributes */
661
0
        if (H5F_get_obj_ids(loc->file, H5F_OBJ_ATTR | H5F_OBJ_LOCAL, num_open_attr, attr_id_list, false,
662
0
                            &check_num_attr) < 0)
663
0
            HGOTO_ERROR(H5E_ATTR, H5E_CANTGET, FAIL, "can't get IDs of opened attributes");
664
0
        if (check_num_attr != num_open_attr)
665
0
            HGOTO_ERROR(H5E_ATTR, H5E_BADITER, FAIL, "open attribute count mismatch");
666
667
        /* Iterate over the attributes */
668
0
        for (u = 0; u < num_open_attr; u++) {
669
0
            unsigned long attr_fnum; /* Attributes file serial number */
670
671
            /* Get pointer to attribute */
672
0
            if (NULL == (*attr = (H5A_t *)H5VL_object_verify(attr_id_list[u], H5I_ATTR)))
673
0
                HGOTO_ERROR(H5E_ATTR, H5E_BADTYPE, FAIL, "not an attribute");
674
675
            /* Get file serial number for attribute */
676
0
            if (H5F_get_fileno((*attr)->oloc.file, &attr_fnum) < 0)
677
0
                HGOTO_ERROR(H5E_ATTR, H5E_BADVALUE, FAIL, "can't get file serial number");
678
679
            /* Verify whether it's the right object.  The attribute name, object
680
             *  address to which the attribute is attached, and file serial
681
             *  number should all match.
682
             */
683
0
            if (!strcmp(name_to_open, (*attr)->shared->name) && loc->addr == (*attr)->oloc.addr &&
684
0
                loc_fnum == attr_fnum) {
685
0
                ret_value = true;
686
0
                break;
687
0
            } /* end if */
688
0
        }     /* end for */
689
0
    }         /* end if */
690
691
52
done:
692
52
    if (attr_id_list)
693
0
        H5MM_free(attr_id_list);
694
695
52
    FUNC_LEAVE_NOAPI(ret_value)
696
52
} /* end H5O__attr_find_opened_attr() */
697
698
/*-------------------------------------------------------------------------
699
 * Function:    H5O__attr_update_shared
700
 *
701
 * Purpose:     Update a shared attribute.
702
 *
703
 * Return:      SUCCEED/FAIL
704
 *
705
 *-------------------------------------------------------------------------
706
 */
707
herr_t
708
H5O__attr_update_shared(H5F_t *f, H5O_t *oh, H5A_t *attr, H5O_shared_t *update_sh_mesg)
709
0
{
710
0
    H5O_shared_t sh_mesg;             /* Shared object header message */
711
0
    hsize_t      attr_rc;             /* Attribute's ref count in shared message storage */
712
0
    htri_t       shared_mesg;         /* Whether the message should be shared */
713
0
    herr_t       ret_value = SUCCEED; /* Return value */
714
715
0
    FUNC_ENTER_PACKAGE
716
717
    /* check args */
718
0
    assert(f);
719
0
    assert(attr);
720
721
    /* Extract shared message info from current attribute (for later use) */
722
0
    if (H5O_set_shared(&sh_mesg, &(attr->sh_loc)) < 0)
723
0
        HGOTO_ERROR(H5E_ATTR, H5E_CANTCOPY, FAIL, "can't get shared message");
724
725
    /* Reset existing sharing information */
726
0
    if (H5O_msg_reset_share(H5O_ATTR_ID, attr) < 0)
727
0
        HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, FAIL, "unable to reset attribute sharing");
728
729
    /* Store new version of message as a SOHM */
730
    /* (should always work, since we're not changing the size of the attribute) */
731
0
    if ((shared_mesg = H5SM_try_share(f, oh, 0, H5O_ATTR_ID, attr, NULL)) == 0)
732
0
        HGOTO_ERROR(H5E_ATTR, H5E_BADMESG, FAIL, "attribute changed sharing status");
733
0
    else if (shared_mesg < 0)
734
0
        HGOTO_ERROR(H5E_ATTR, H5E_BADMESG, FAIL, "can't share attribute");
735
736
    /* Retrieve shared message storage ref count for new shared attribute */
737
0
    if (H5SM_get_refcount(f, H5O_ATTR_ID, &attr->sh_loc, &attr_rc) < 0)
738
0
        HGOTO_ERROR(H5E_ATTR, H5E_CANTGET, FAIL, "can't retrieve shared message ref count");
739
740
    /* If the newly shared attribute needs to share "ownership" of the shared
741
     *      components (ie. its reference count is 1), increment the reference
742
     *      count on any shared components of the attribute, so that they won't
743
     *      be removed from the file by the following "delete" operation on the
744
     *      original attribute shared message info.  (Essentially a "copy on
745
     *      write" operation).
746
     *
747
     *      *ick* -QAK, 2007/01/08
748
     */
749
0
    if (attr_rc == 1)
750
        /* Increment reference count on attribute components */
751
0
        if (H5O__attr_link(f, oh, attr) < 0)
752
0
            HGOTO_ERROR(H5E_ATTR, H5E_LINKCOUNT, FAIL, "unable to adjust attribute link count");
753
754
    /* Remove the old attribute from the SOHM storage */
755
0
    if (H5SM_delete(f, oh, &sh_mesg) < 0)
756
0
        HGOTO_ERROR(H5E_ATTR, H5E_CANTFREE, FAIL, "unable to delete shared attribute in shared storage");
757
758
    /* Extract updated shared message info from modified attribute, if requested */
759
0
    if (update_sh_mesg)
760
0
        if (H5O_set_shared(update_sh_mesg, &(attr->sh_loc)) < 0)
761
0
            HGOTO_ERROR(H5E_ATTR, H5E_CANTCOPY, FAIL, "can't get shared message");
762
763
0
done:
764
0
    FUNC_LEAVE_NOAPI(ret_value)
765
0
} /* end H5O__attr_update_shared() */
766
767
/*-------------------------------------------------------------------------
768
 * Function:    H5O__attr_write_cb
769
 *
770
 * Purpose:     Object header iterator callback routine to update an
771
 *              attribute stored compactly.
772
 *
773
 * Return:      SUCCEED/FAIL
774
 *
775
 *-------------------------------------------------------------------------
776
 */
777
static herr_t
778
H5O__attr_write_cb(H5O_t *oh, H5O_mesg_t *mesg /*in,out*/, unsigned H5_ATTR_UNUSED sequence,
779
                   unsigned *oh_modified, void *_udata /*in,out*/)
780
0
{
781
0
    H5O_iter_wrt_t    *udata       = (H5O_iter_wrt_t *)_udata; /* Operator user data */
782
0
    H5O_chunk_proxy_t *chk_proxy   = NULL;                     /* Chunk that message is in */
783
0
    bool               chk_dirtied = false;                    /* Flag for unprotecting chunk */
784
0
    herr_t             ret_value   = H5_ITER_CONT;             /* Return value */
785
786
0
    FUNC_ENTER_PACKAGE
787
788
    /* check args */
789
0
    assert(oh);
790
0
    assert(mesg);
791
0
    assert(!udata->found);
792
793
    /* Check for correct attribute message to modify */
794
0
    if (0 == strcmp(((H5A_t *)mesg->native)->shared->name, udata->attr->shared->name)) {
795
        /* Protect chunk */
796
0
        if (NULL == (chk_proxy = H5O__chunk_protect(udata->f, oh, mesg->chunkno)))
797
0
            HGOTO_ERROR(H5E_ATTR, H5E_CANTPROTECT, H5_ITER_ERROR, "unable to load object header chunk");
798
799
        /* Because the attribute structure is shared now. The only situation that requires
800
         * copying the data is when the metadata cache evicts and reloads this attribute.
801
         * The shared attribute structure will be different in that situation. SLU-2010/7/29 */
802
0
        if (((H5A_t *)mesg->native)->shared != udata->attr->shared) {
803
            /* Sanity check */
804
0
            assert(((H5A_t *)mesg->native)->shared->data);
805
0
            assert(udata->attr->shared->data);
806
0
            assert(((H5A_t *)mesg->native)->shared->data != udata->attr->shared->data);
807
808
            /* (Needs to occur before updating the shared message, or the hash
809
             *      value on the old & new messages will be the same) */
810
0
            H5MM_memcpy(((H5A_t *)mesg->native)->shared->data, udata->attr->shared->data,
811
0
                        udata->attr->shared->data_size);
812
0
        } /* end if */
813
814
        /* Mark the message as modified */
815
0
        mesg->dirty = true;
816
0
        chk_dirtied = true;
817
818
        /* Release chunk */
819
0
        if (H5O__chunk_unprotect(udata->f, chk_proxy, chk_dirtied) < 0)
820
0
            HGOTO_ERROR(H5E_ATTR, H5E_CANTUNPROTECT, H5_ITER_ERROR,
821
0
                        "unable to unprotect object header chunk");
822
0
        chk_proxy = NULL;
823
824
        /* Update the shared attribute in the SOHM storage */
825
0
        if (mesg->flags & H5O_MSG_FLAG_SHARED)
826
0
            if (H5O__attr_update_shared(udata->f, oh, udata->attr, (H5O_shared_t *)mesg->native) < 0)
827
0
                HGOTO_ERROR(H5E_ATTR, H5E_CANTUPDATE, H5_ITER_ERROR,
828
0
                            "unable to update attribute in shared storage");
829
830
        /* Indicate that the object header was modified */
831
0
        *oh_modified = H5O_MODIFY;
832
833
        /* Indicate that the attribute was found */
834
0
        udata->found = true;
835
836
        /* Stop iterating */
837
0
        ret_value = H5_ITER_STOP;
838
0
    } /* end if */
839
840
0
done:
841
    /* Release chunk, if not already done */
842
0
    if (chk_proxy && H5O__chunk_unprotect(udata->f, chk_proxy, chk_dirtied) < 0)
843
0
        HDONE_ERROR(H5E_ATTR, H5E_CANTUNPROTECT, H5_ITER_ERROR, "unable to unprotect object header chunk");
844
845
0
    FUNC_LEAVE_NOAPI(ret_value)
846
0
} /* end H5O__attr_write_cb() */
847
848
/*-------------------------------------------------------------------------
849
 * Function:    H5O__attr_write
850
 *
851
 * Purpose:     Write a new value to an attribute.
852
 *
853
 * Return:      SUCCEED/FAIL
854
 *
855
 *-------------------------------------------------------------------------
856
 */
857
herr_t
858
H5O__attr_write(const H5O_loc_t *loc, H5A_t *attr)
859
0
{
860
0
    H5O_t      *oh = NULL;           /* Pointer to actual object header */
861
0
    H5O_ainfo_t ainfo;               /* Attribute information for object */
862
0
    herr_t      ret_value = SUCCEED; /* Return value */
863
864
0
    FUNC_ENTER_PACKAGE
865
866
    /* Check arguments */
867
0
    assert(loc);
868
0
    assert(attr);
869
870
    /* Pin the object header */
871
0
    if (NULL == (oh = H5O_pin(loc)))
872
0
        HGOTO_ERROR(H5E_ATTR, H5E_CANTPIN, FAIL, "unable to pin object header");
873
874
    /* Check for attribute info stored */
875
0
    ainfo.fheap_addr = HADDR_UNDEF;
876
0
    if (oh->version > H5O_VERSION_1) {
877
        /* Check for (& retrieve if available) attribute info */
878
0
        if (H5A__get_ainfo(loc->file, oh, &ainfo) < 0)
879
0
            HGOTO_ERROR(H5E_ATTR, H5E_CANTGET, FAIL, "can't check for attribute info message");
880
0
    } /* end if */
881
882
    /* Check for attributes stored densely */
883
0
    if (H5_addr_defined(ainfo.fheap_addr)) {
884
        /* Modify the attribute data in dense storage */
885
0
        if (H5A__dense_write(loc->file, &ainfo, attr) < 0)
886
0
            HGOTO_ERROR(H5E_ATTR, H5E_CANTUPDATE, FAIL, "error updating attribute");
887
0
    } /* end if */
888
0
    else {
889
0
        H5O_iter_wrt_t      udata; /* User data for callback */
890
0
        H5O_mesg_operator_t op;    /* Wrapper for operator */
891
892
        /* Set up user data for callback */
893
0
        udata.f     = loc->file;
894
0
        udata.attr  = attr;
895
0
        udata.found = false;
896
897
        /* Iterate over attributes, to locate correct one to update */
898
0
        op.op_type  = H5O_MESG_OP_LIB;
899
0
        op.u.lib_op = H5O__attr_write_cb;
900
0
        if (H5O__msg_iterate_real(loc->file, oh, H5O_MSG_ATTR, &op, &udata) < 0)
901
0
            HGOTO_ERROR(H5E_ATTR, H5E_CANTUPDATE, FAIL, "error updating attribute");
902
903
        /* Check that we found the attribute */
904
0
        if (!udata.found)
905
0
            HGOTO_ERROR(H5E_ATTR, H5E_NOTFOUND, FAIL, "can't locate open attribute?");
906
0
    } /* end else */
907
908
    /* Update the modification time, if any */
909
0
    if (H5O_touch_oh(loc->file, oh, false) < 0)
910
0
        HGOTO_ERROR(H5E_ATTR, H5E_CANTUPDATE, FAIL, "unable to update time on object");
911
912
0
done:
913
0
    if (oh && H5O_unpin(oh) < 0)
914
0
        HDONE_ERROR(H5E_ATTR, H5E_CANTUNPIN, FAIL, "unable to unpin object header");
915
916
0
    FUNC_LEAVE_NOAPI(ret_value)
917
0
} /* end H5O__attr_write */
918
919
/*-------------------------------------------------------------------------
920
 * Function:    H5O__attr_rename_chk_cb
921
 *
922
 * Purpose:     Object header iterator callback routine to check for
923
 *              duplicate name during rename
924
 *
925
 * Return:      SUCCEED/FAIL
926
 *
927
 *-------------------------------------------------------------------------
928
 */
929
static herr_t
930
H5O__attr_rename_chk_cb(H5O_t H5_ATTR_UNUSED *oh, H5O_mesg_t *mesg /*in,out*/,
931
                        unsigned H5_ATTR_UNUSED sequence, unsigned H5_ATTR_UNUSED *oh_modified,
932
                        void *_udata /*in,out*/)
933
0
{
934
0
    H5O_iter_ren_t *udata     = (H5O_iter_ren_t *)_udata; /* Operator user data */
935
0
    herr_t          ret_value = H5_ITER_CONT;             /* Return value */
936
937
0
    FUNC_ENTER_PACKAGE_NOERR
938
939
    /* check args */
940
0
    assert(oh);
941
0
    assert(mesg);
942
0
    assert(!udata->found);
943
944
    /* Check for existing attribute with new name */
945
0
    if (strcmp(((H5A_t *)mesg->native)->shared->name, udata->new_name) == 0) {
946
        /* Indicate that we found an existing attribute with the new name*/
947
0
        udata->found = true;
948
949
        /* Stop iterating */
950
0
        ret_value = H5_ITER_STOP;
951
0
    } /* end if */
952
953
0
    FUNC_LEAVE_NOAPI(ret_value)
954
0
} /* end H5O__attr_rename_chk_cb() */
955
956
/*-------------------------------------------------------------------------
957
 * Function:    H5O__attr_rename_mod_cb
958
 *
959
 * Purpose:     Object header iterator callback routine to change name of
960
 *              attribute during rename
961
 *
962
 * Note:        This routine doesn't currently allow an attribute to change
963
 *              its "shared" status, if the name change would cause a size
964
 *              difference that would put it into a different category.
965
 *              Something for later...
966
 *
967
 * Return:      SUCCEED/FAIL
968
 *
969
 *-------------------------------------------------------------------------
970
 */
971
static herr_t
972
H5O__attr_rename_mod_cb(H5O_t *oh, H5O_mesg_t *mesg /*in,out*/, unsigned H5_ATTR_UNUSED sequence,
973
                        unsigned *oh_modified, void *_udata /*in,out*/)
974
0
{
975
0
    H5O_iter_ren_t    *udata       = (H5O_iter_ren_t *)_udata; /* Operator user data */
976
0
    H5O_chunk_proxy_t *chk_proxy   = NULL;                     /* Chunk that message is in */
977
0
    bool               chk_dirtied = false;                    /* Flag for unprotecting chunk */
978
0
    herr_t             ret_value   = H5_ITER_CONT;             /* Return value */
979
980
0
    FUNC_ENTER_PACKAGE
981
982
    /* check args */
983
0
    assert(oh);
984
0
    assert(mesg);
985
0
    assert(!udata->found);
986
987
    /* Find correct attribute message to rename */
988
0
    if (strcmp(((H5A_t *)mesg->native)->shared->name, udata->old_name) == 0) {
989
0
        unsigned old_version = ((H5A_t *)mesg->native)->shared->version; /* Old version of the attribute */
990
991
        /* Protect chunk */
992
0
        if (NULL == (chk_proxy = H5O__chunk_protect(udata->f, oh, mesg->chunkno)))
993
0
            HGOTO_ERROR(H5E_ATTR, H5E_CANTPROTECT, H5_ITER_ERROR, "unable to load object header chunk");
994
995
        /* Change the name for the attribute */
996
0
        H5MM_xfree(((H5A_t *)mesg->native)->shared->name);
997
0
        ((H5A_t *)mesg->native)->shared->name = H5MM_xstrdup(udata->new_name);
998
999
        /* Recompute the version to encode the attribute with */
1000
0
        if (H5A__set_version(udata->f, ((H5A_t *)mesg->native)) < 0)
1001
0
            HGOTO_ERROR(H5E_ATTR, H5E_CANTSET, H5_ITER_ERROR, "unable to update attribute version");
1002
1003
        /* Mark the message as modified */
1004
0
        mesg->dirty = true;
1005
0
        chk_dirtied = true;
1006
1007
        /* Release chunk */
1008
0
        if (H5O__chunk_unprotect(udata->f, chk_proxy, chk_dirtied) < 0)
1009
0
            HGOTO_ERROR(H5E_ATTR, H5E_CANTUNPROTECT, H5_ITER_ERROR,
1010
0
                        "unable to unprotect object header chunk");
1011
0
        chk_proxy = NULL;
1012
1013
        /* Check for shared message */
1014
0
        if (mesg->flags & H5O_MSG_FLAG_SHARED) {
1015
            /* Update the shared attribute in the SOHM storage */
1016
0
            if (H5O__attr_update_shared(udata->f, oh, (H5A_t *)mesg->native, NULL) < 0)
1017
0
                HGOTO_ERROR(H5E_ATTR, H5E_CANTUPDATE, H5_ITER_ERROR,
1018
0
                            "unable to update attribute in shared storage");
1019
0
        } /* end if */
1020
0
        else {
1021
            /* Sanity check */
1022
0
            assert(H5O_msg_is_shared(H5O_ATTR_ID, (H5A_t *)mesg->native) == false);
1023
1024
            /* Check for attribute message changing size */
1025
0
            if (strlen(udata->new_name) != strlen(udata->old_name) ||
1026
0
                old_version != ((H5A_t *)mesg->native)->shared->version) {
1027
0
                H5A_t *attr; /* Attribute to re-add */
1028
1029
                /* Take ownership of the message's native info (the attribute)
1030
                 *      so any shared objects in the file aren't adjusted (and
1031
                 *      possibly deleted) when the message is released.
1032
                 */
1033
                /* (We do this more complicated sequence of actions because the
1034
                 *      simpler solution of adding the modified attribute first
1035
                 *      and then deleting the old message can re-allocate the
1036
                 *      list of messages during the "add the modified attribute"
1037
                 *      step, invalidating the message pointer we have here - QAK)
1038
                 */
1039
0
                attr         = (H5A_t *)mesg->native;
1040
0
                mesg->native = NULL;
1041
1042
                /* Delete old attribute */
1043
                /* (doesn't decrement the link count on shared components because
1044
                 *      the "native" pointer has been reset)
1045
                 */
1046
0
                if (H5O__release_mesg(udata->f, oh, mesg, false) < 0)
1047
0
                    HGOTO_ERROR(H5E_ATTR, H5E_CANTDELETE, H5_ITER_ERROR,
1048
0
                                "unable to release previous attribute");
1049
1050
0
                *oh_modified = H5O_MODIFY_CONDENSE;
1051
1052
                /* Append renamed attribute to object header */
1053
                /* (Don't let it become shared) */
1054
0
                if (H5O__msg_append_real(udata->f, oh, H5O_MSG_ATTR, (mesg->flags | H5O_MSG_FLAG_DONTSHARE),
1055
0
                                         0, attr) < 0)
1056
0
                    HGOTO_ERROR(H5E_ATTR, H5E_CANTINSERT, H5_ITER_ERROR,
1057
0
                                "unable to relocate renamed attribute in header");
1058
1059
                /* Sanity check */
1060
0
                assert(H5O_msg_is_shared(H5O_ATTR_ID, attr) == false);
1061
1062
                /* Close the local copy of the attribute */
1063
0
                H5A__close(attr);
1064
0
            } /* end if */
1065
0
        }     /* end else */
1066
1067
        /* Indicate that the object header was modified */
1068
0
        *oh_modified |= H5O_MODIFY;
1069
1070
        /* Indicate that we found an existing attribute with the old name */
1071
0
        udata->found = true;
1072
1073
        /* Stop iterating */
1074
0
        ret_value = H5_ITER_STOP;
1075
0
    } /* end if */
1076
1077
0
done:
1078
    /* Release chunk, if not already done */
1079
0
    if (chk_proxy && H5O__chunk_unprotect(udata->f, chk_proxy, chk_dirtied) < 0)
1080
0
        HDONE_ERROR(H5E_ATTR, H5E_CANTUNPROTECT, H5_ITER_ERROR, "unable to unprotect object header chunk");
1081
1082
0
    FUNC_LEAVE_NOAPI(ret_value)
1083
0
} /* end H5O__attr_rename_mod_cb() */
1084
1085
/*-------------------------------------------------------------------------
1086
 * Function:    H5O__attr_rename
1087
 *
1088
 * Purpose:     Rename an attribute.
1089
 *
1090
 * Return:      SUCCEED/FAIL
1091
 *
1092
 *-------------------------------------------------------------------------
1093
 */
1094
herr_t
1095
H5O__attr_rename(const H5O_loc_t *loc, const char *old_name, const char *new_name)
1096
0
{
1097
0
    H5O_t      *oh = NULL;           /* Pointer to actual object header */
1098
0
    H5O_ainfo_t ainfo;               /* Attribute information for object */
1099
0
    herr_t      ret_value = SUCCEED; /* Return value */
1100
1101
0
    FUNC_ENTER_PACKAGE_TAG(loc->addr)
1102
1103
    /* Check arguments */
1104
0
    assert(loc);
1105
0
    assert(old_name);
1106
0
    assert(new_name);
1107
1108
    /* Pin the object header */
1109
0
    if (NULL == (oh = H5O_pin(loc)))
1110
0
        HGOTO_ERROR(H5E_ATTR, H5E_CANTPIN, FAIL, "unable to pin object header");
1111
1112
    /* Check for attribute info stored */
1113
0
    ainfo.fheap_addr = HADDR_UNDEF;
1114
0
    if (oh->version > H5O_VERSION_1) {
1115
        /* Check for (& retrieve if available) attribute info */
1116
0
        if (H5A__get_ainfo(loc->file, oh, &ainfo) < 0)
1117
0
            HGOTO_ERROR(H5E_ATTR, H5E_CANTGET, FAIL, "can't check for attribute info message");
1118
0
    } /* end if */
1119
1120
    /* Check for attributes stored densely */
1121
0
    if (H5_addr_defined(ainfo.fheap_addr)) {
1122
        /* Rename the attribute data in dense storage */
1123
0
        if (H5A__dense_rename(loc->file, &ainfo, old_name, new_name) < 0)
1124
0
            HGOTO_ERROR(H5E_ATTR, H5E_CANTUPDATE, FAIL, "error updating attribute");
1125
0
    } /* end if */
1126
0
    else {
1127
0
        H5O_iter_ren_t      udata; /* User data for callback */
1128
0
        H5O_mesg_operator_t op;    /* Wrapper for operator */
1129
1130
        /* Set up user data for callback */
1131
0
        udata.f        = loc->file;
1132
0
        udata.old_name = old_name;
1133
0
        udata.new_name = new_name;
1134
0
        udata.found    = false;
1135
1136
        /* Iterate over attributes, to check if "new name" exists already */
1137
0
        op.op_type  = H5O_MESG_OP_LIB;
1138
0
        op.u.lib_op = H5O__attr_rename_chk_cb;
1139
0
        if (H5O__msg_iterate_real(loc->file, oh, H5O_MSG_ATTR, &op, &udata) < 0)
1140
0
            HGOTO_ERROR(H5E_ATTR, H5E_CANTUPDATE, FAIL, "error updating attribute");
1141
1142
        /* If the new name was found, indicate an error */
1143
0
        if (udata.found)
1144
0
            HGOTO_ERROR(H5E_ATTR, H5E_EXISTS, FAIL, "attribute with new name already exists");
1145
1146
        /* Iterate over attributes again, to actually rename attribute with old name */
1147
0
        op.op_type  = H5O_MESG_OP_LIB;
1148
0
        op.u.lib_op = H5O__attr_rename_mod_cb;
1149
0
        if (H5O__msg_iterate_real(loc->file, oh, H5O_MSG_ATTR, &op, &udata) < 0)
1150
0
            HGOTO_ERROR(H5E_ATTR, H5E_CANTUPDATE, FAIL, "error updating attribute");
1151
1152
        /* Check that we found the attribute to rename */
1153
0
        if (!udata.found)
1154
0
            HGOTO_ERROR(H5E_ATTR, H5E_NOTFOUND, FAIL, "can't locate attribute with old name");
1155
0
    } /* end else */
1156
1157
    /* Update the modification time, if any */
1158
0
    if (H5O_touch_oh(loc->file, oh, false) < 0)
1159
0
        HGOTO_ERROR(H5E_ATTR, H5E_CANTUPDATE, FAIL, "unable to update time on object");
1160
1161
0
done:
1162
0
    if (oh && H5O_unpin(oh) < 0)
1163
0
        HDONE_ERROR(H5E_ATTR, H5E_CANTUNPIN, FAIL, "unable to unpin object header");
1164
1165
0
    FUNC_LEAVE_NOAPI_TAG(ret_value)
1166
0
} /* end H5O__attr_rename() */
1167
1168
/*-------------------------------------------------------------------------
1169
 * Function:    H5O_attr_iterate_real
1170
 *
1171
 * Purpose:     Internal routine to iterate over attributes for an object.
1172
 *
1173
 * Return:      SUCCEED/FAIL
1174
 *
1175
 *-------------------------------------------------------------------------
1176
 */
1177
herr_t
1178
H5O_attr_iterate_real(hid_t loc_id, const H5O_loc_t *loc, H5_index_t idx_type, H5_iter_order_t order,
1179
                      hsize_t skip, hsize_t *last_attr, const H5A_attr_iter_op_t *attr_op, void *op_data)
1180
0
{
1181
0
    H5O_t           *oh = NULL;                /* Pointer to actual object header */
1182
0
    H5O_ainfo_t      ainfo;                    /* Attribute information for object */
1183
0
    H5A_attr_table_t atable    = {0, 0, NULL}; /* Table of attributes */
1184
0
    herr_t           ret_value = FAIL;         /* Return value */
1185
1186
0
    FUNC_ENTER_NOAPI_NOINIT_TAG(loc->addr)
1187
1188
    /* Check arguments */
1189
0
    assert(loc);
1190
0
    assert(loc->file);
1191
0
    assert(H5_addr_defined(loc->addr));
1192
0
    assert(attr_op);
1193
1194
    /* Protect the object header to iterate over */
1195
0
    if (NULL == (oh = H5O_protect(loc, H5AC__READ_ONLY_FLAG, false)))
1196
0
        HGOTO_ERROR(H5E_ATTR, H5E_CANTPROTECT, FAIL, "unable to load object header");
1197
1198
    /* Check for attribute info stored */
1199
0
    ainfo.fheap_addr = HADDR_UNDEF;
1200
0
    if (oh->version > H5O_VERSION_1) {
1201
        /* Check for (& retrieve if available) attribute info */
1202
0
        if (H5A__get_ainfo(loc->file, oh, &ainfo) < 0)
1203
0
            HGOTO_ERROR(H5E_ATTR, H5E_CANTGET, FAIL, "can't check for attribute info message");
1204
0
    } /* end if */
1205
1206
    /* Check for attributes stored densely */
1207
0
    if (H5_addr_defined(ainfo.fheap_addr)) {
1208
        /* Check for skipping too many attributes */
1209
0
        if (skip > 0 && skip >= ainfo.nattrs)
1210
0
            HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid index specified");
1211
1212
        /* Release the object header */
1213
0
        if (H5O_unprotect(loc, oh, H5AC__NO_FLAGS_SET) < 0)
1214
0
            HGOTO_ERROR(H5E_ATTR, H5E_CANTUNPROTECT, FAIL, "unable to release object header");
1215
0
        oh = NULL;
1216
1217
        /* Iterate over attributes in dense storage */
1218
0
        if ((ret_value = H5A__dense_iterate(loc->file, loc_id, &ainfo, idx_type, order, skip, last_attr,
1219
0
                                            attr_op, op_data)) < 0)
1220
0
            HERROR(H5E_ATTR, H5E_BADITER, "error iterating over attributes");
1221
0
    } /* end if */
1222
0
    else {
1223
        /* Build table of attributes for compact storage */
1224
0
        if (H5A__compact_build_table(loc->file, oh, idx_type, order, &atable) < 0)
1225
0
            HGOTO_ERROR(H5E_ATTR, H5E_CANTINIT, FAIL, "error building attribute table");
1226
1227
        /* Release the object header */
1228
0
        if (H5O_unprotect(loc, oh, H5AC__NO_FLAGS_SET) < 0)
1229
0
            HGOTO_ERROR(H5E_ATTR, H5E_CANTUNPROTECT, FAIL, "unable to release object header");
1230
0
        oh = NULL;
1231
1232
        /* Check for skipping too many attributes */
1233
0
        if (skip > 0 && skip >= atable.num_attrs)
1234
0
            HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid index specified");
1235
1236
        /* Iterate over attributes in table */
1237
0
        if ((ret_value = H5A__attr_iterate_table(&atable, skip, last_attr, loc_id, attr_op, op_data)) < 0)
1238
0
            HERROR(H5E_ATTR, H5E_BADITER, "iteration operator failed");
1239
0
    } /* end else */
1240
1241
0
done:
1242
    /* Release resources */
1243
0
    if (oh && H5O_unprotect(loc, oh, H5AC__NO_FLAGS_SET) < 0)
1244
0
        HDONE_ERROR(H5E_ATTR, H5E_CANTUNPROTECT, FAIL, "unable to release object header");
1245
0
    if (atable.attrs && H5A__attr_release_table(&atable) < 0)
1246
0
        HDONE_ERROR(H5E_ATTR, H5E_CANTFREE, FAIL, "unable to release attribute table");
1247
1248
0
    FUNC_LEAVE_NOAPI_TAG(ret_value)
1249
0
} /* end H5O_attr_iterate_real() */
1250
1251
/*-------------------------------------------------------------------------
1252
 * Function:    H5O__attr_iterate
1253
 *
1254
 * Purpose:     Iterate over attributes for an object.
1255
 *
1256
 * Return:      SUCCEED/FAIL
1257
 *
1258
 *-------------------------------------------------------------------------
1259
 */
1260
herr_t
1261
H5O__attr_iterate(hid_t loc_id, H5_index_t idx_type, H5_iter_order_t order, hsize_t skip, hsize_t *last_attr,
1262
                  const H5A_attr_iter_op_t *attr_op, void *op_data)
1263
0
{
1264
0
    H5G_loc_t loc;              /* Object location */
1265
0
    herr_t    ret_value = FAIL; /* Return value */
1266
1267
0
    FUNC_ENTER_PACKAGE
1268
1269
    /* Check arguments */
1270
0
    assert(attr_op);
1271
1272
    /* Look up location for location ID */
1273
0
    if (H5G_loc(loc_id, &loc) < 0)
1274
0
        HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a location");
1275
1276
    /* Iterate over attributes to locate correct one */
1277
0
    if ((ret_value =
1278
0
             H5O_attr_iterate_real(loc_id, loc.oloc, idx_type, order, skip, last_attr, attr_op, op_data)) < 0)
1279
0
        HERROR(H5E_ATTR, H5E_BADITER, "error iterating over attributes");
1280
1281
0
done:
1282
0
    FUNC_LEAVE_NOAPI(ret_value)
1283
0
} /* end H5O__attr_iterate() */
1284
1285
/*-------------------------------------------------------------------------
1286
 * Function:    H5O__attr_remove_update
1287
 *
1288
 * Purpose:     Check for reverting from dense to compact attribute storage
1289
 *
1290
 *              When converting storage from dense to compact, if found
1291
 *              the attribute is already opened, use the opened message
1292
 *              to insert.  If not, still use the message in the attribute
1293
 *              table. This will guarantee that the attribute message is
1294
 *              shared between the object in metadata cache and the opened
1295
 *              object.
1296
 *
1297
 * Return:      SUCCEED/FAIL
1298
 *-------------------------------------------------------------------------
1299
 */
1300
static herr_t
1301
H5O__attr_remove_update(const H5O_loc_t *loc, H5O_t *oh, H5O_ainfo_t *ainfo)
1302
0
{
1303
0
    H5A_attr_table_t atable    = {0, 0, NULL}; /* Table of attributes */
1304
0
    herr_t           ret_value = SUCCEED;      /* Return value */
1305
1306
0
    FUNC_ENTER_PACKAGE
1307
1308
    /* Check arguments */
1309
0
    assert(loc);
1310
0
    assert(oh);
1311
0
    assert(ainfo);
1312
1313
    /* Decrement the number of attributes on the object */
1314
0
    ainfo->nattrs--;
1315
1316
    /* Check for shifting from dense storage back to compact storage */
1317
0
    if (H5_addr_defined(ainfo->fheap_addr) && ainfo->nattrs < oh->min_dense) {
1318
0
        bool   can_convert = true; /* Whether converting to attribute messages is possible */
1319
0
        size_t u;                  /* Local index */
1320
1321
        /* Build the table of attributes for this object */
1322
0
        if (H5A__dense_build_table(loc->file, ainfo, H5_INDEX_NAME, H5_ITER_NATIVE, &atable) < 0)
1323
0
            HGOTO_ERROR(H5E_ATTR, H5E_CANTINIT, FAIL, "error building attribute table");
1324
1325
        /* Inspect attributes in table for ones that can't be converted back
1326
         * into attribute message form (currently only attributes which
1327
         * can't fit into an object header message)
1328
         */
1329
0
        for (u = 0; u < ainfo->nattrs; u++)
1330
0
            if (H5O_msg_size_oh(loc->file, oh, H5O_ATTR_ID, (atable.attrs[u]), (size_t)0) >=
1331
0
                H5O_MESG_MAX_SIZE) {
1332
0
                can_convert = false;
1333
0
                break;
1334
0
            } /* end if */
1335
1336
        /* If ok, insert attributes as object header messages */
1337
0
        if (can_convert) {
1338
0
            H5A_t *exist_attr      = NULL;
1339
0
            htri_t found_open_attr = false;
1340
1341
            /* Iterate over attributes, to put them into header */
1342
0
            for (u = 0; u < ainfo->nattrs; u++) {
1343
0
                htri_t shared_mesg; /* Should this message be stored in the Shared Message table? */
1344
1345
                /* Check if attribute is shared */
1346
0
                if ((shared_mesg = H5O_msg_is_shared(H5O_ATTR_ID, (atable.attrs[u]))) < 0)
1347
0
                    HGOTO_ERROR(H5E_ATTR, H5E_CANTGET, FAIL, "error determining if message is shared");
1348
0
                else if (shared_mesg == 0) {
1349
                    /* Increment reference count on attribute components */
1350
                    /* (so that they aren't deleted when the dense attribute storage is deleted) */
1351
0
                    if (H5O__attr_link(loc->file, oh, (atable.attrs[u])) < 0)
1352
0
                        HGOTO_ERROR(H5E_ATTR, H5E_LINKCOUNT, FAIL, "unable to adjust attribute link count");
1353
0
                } /* end if */
1354
0
                else {
1355
                    /* Reset 'shared' status, so attribute will be shared again */
1356
0
                    (atable.attrs[u])->sh_loc.type = H5O_SHARE_TYPE_UNSHARED;
1357
0
                } /* end else */
1358
1359
                /* Insert attribute message into object header (Will increment
1360
                   reference count on shared attributes) */
1361
                /* Find out whether the attribute has been opened */
1362
0
                if ((found_open_attr =
1363
0
                         H5O__attr_find_opened_attr(loc, &exist_attr, (atable.attrs[u])->shared->name)) < 0)
1364
0
                    HGOTO_ERROR(H5E_ATTR, H5E_CANTGET, FAIL, "failed in finding opened attribute");
1365
1366
                /* If found the attribute is already opened, use the opened message to insert.
1367
                   If not, still use the message in the attribute table. */
1368
0
                if (found_open_attr && exist_attr) {
1369
0
                    if (H5O__msg_append_real(loc->file, oh, H5O_MSG_ATTR, 0, 0, exist_attr) < 0)
1370
0
                        HGOTO_ERROR(H5E_ATTR, H5E_CANTINIT, FAIL, "can't create message");
1371
1372
0
                } /* end if */
1373
0
                else if (H5O__msg_append_real(loc->file, oh, H5O_MSG_ATTR, 0, 0, (atable.attrs[u])) < 0)
1374
0
                    HGOTO_ERROR(H5E_ATTR, H5E_CANTINIT, FAIL, "can't create message");
1375
0
            } /* end for */
1376
1377
            /* Remove the dense storage */
1378
0
            if (H5A__dense_delete(loc->file, ainfo) < 0)
1379
0
                HGOTO_ERROR(H5E_ATTR, H5E_CANTDELETE, FAIL, "unable to delete dense attribute storage");
1380
0
        } /* end if */
1381
0
    }     /* end if */
1382
1383
    /* Update the message after removing the attribute */
1384
    /* This is particularly needed when removing the last attribute that is
1385
     * accessed via fractal heap/v2 B-tree (HDFFV-9277)
1386
     */
1387
0
    if (H5O__msg_write_real(loc->file, oh, H5O_MSG_AINFO, H5O_MSG_FLAG_DONTSHARE, 0, ainfo) < 0)
1388
0
        HGOTO_ERROR(H5E_ATTR, H5E_CANTUPDATE, FAIL, "unable to update attribute info message");
1389
1390
    /* Check if we have deleted all the attributes and the attribute info
1391
     *  message should be deleted itself.
1392
     */
1393
0
    if (ainfo->nattrs == 0) {
1394
0
        if (H5O__msg_remove_real(loc->file, oh, H5O_MSG_AINFO, H5O_ALL, NULL, NULL, true) < 0)
1395
0
            HGOTO_ERROR(H5E_ATTR, H5E_CANTDELETE, FAIL, "unable to delete attribute info");
1396
0
    } /* end if */
1397
1398
0
done:
1399
    /* Release resources */
1400
0
    if (atable.attrs && H5A__attr_release_table(&atable) < 0)
1401
0
        HDONE_ERROR(H5E_ATTR, H5E_CANTFREE, FAIL, "unable to release attribute table");
1402
1403
0
    FUNC_LEAVE_NOAPI(ret_value)
1404
0
} /* end H5O__attr_remove_update() */
1405
1406
/*-------------------------------------------------------------------------
1407
 * Function:    H5O__attr_remove_cb
1408
 *
1409
 * Purpose:     Object header iterator callback routine to remove an
1410
 *              attribute stored compactly.
1411
 *
1412
 * Return:      SUCCEED/FAIL
1413
 *
1414
 *-------------------------------------------------------------------------
1415
 */
1416
static herr_t
1417
H5O__attr_remove_cb(H5O_t *oh, H5O_mesg_t *mesg /*in,out*/, unsigned H5_ATTR_UNUSED sequence,
1418
                    unsigned *oh_modified, void *_udata /*in,out*/)
1419
0
{
1420
0
    H5O_iter_rm_t *udata     = (H5O_iter_rm_t *)_udata; /* Operator user data */
1421
0
    herr_t         ret_value = H5_ITER_CONT;            /* Return value */
1422
1423
0
    FUNC_ENTER_PACKAGE
1424
1425
    /* check args */
1426
0
    assert(oh);
1427
0
    assert(mesg);
1428
0
    assert(!udata->found);
1429
1430
    /* Check for correct attribute message to modify */
1431
0
    if (strcmp(((H5A_t *)mesg->native)->shared->name, udata->name) == 0) {
1432
        /* Convert message into a null message (i.e. delete it) */
1433
0
        if (H5O__release_mesg(udata->f, oh, mesg, true) < 0)
1434
0
            HGOTO_ERROR(H5E_OHDR, H5E_CANTDELETE, H5_ITER_ERROR, "unable to convert into null message");
1435
1436
        /* Indicate that the object header was modified */
1437
0
        *oh_modified = H5O_MODIFY_CONDENSE;
1438
1439
        /* Indicate that this message is the attribute to be deleted */
1440
0
        udata->found = true;
1441
1442
        /* Stop iterating */
1443
0
        ret_value = H5_ITER_STOP;
1444
0
    } /* end if */
1445
1446
0
done:
1447
0
    FUNC_LEAVE_NOAPI(ret_value)
1448
0
} /* end H5O__attr_remove_cb() */
1449
1450
/*-------------------------------------------------------------------------
1451
 * Function:    H5O__attr_remove
1452
 *
1453
 * Purpose:     Delete an attribute on an object.
1454
 *
1455
 * Return:      SUCCEED/FAIL
1456
 *
1457
 *-------------------------------------------------------------------------
1458
 */
1459
herr_t
1460
H5O__attr_remove(const H5O_loc_t *loc, const char *name)
1461
0
{
1462
0
    H5O_t      *oh = NULL;              /* Pointer to actual object header */
1463
0
    H5O_ainfo_t ainfo;                  /* Attribute information for object */
1464
0
    htri_t      ainfo_exists = false;   /* Whether the attribute info exists in the file */
1465
0
    herr_t      ret_value    = SUCCEED; /* Return value */
1466
1467
0
    FUNC_ENTER_PACKAGE_TAG(loc->addr)
1468
1469
    /* Check arguments */
1470
0
    assert(loc);
1471
0
    assert(name);
1472
1473
    /* Pin the object header */
1474
0
    if (NULL == (oh = H5O_pin(loc)))
1475
0
        HGOTO_ERROR(H5E_ATTR, H5E_CANTPIN, FAIL, "unable to pin object header");
1476
1477
    /* Check for attribute info stored */
1478
0
    ainfo.fheap_addr = HADDR_UNDEF;
1479
0
    if (oh->version > H5O_VERSION_1) {
1480
        /* Check for (& retrieve if available) attribute info */
1481
0
        if ((ainfo_exists = H5A__get_ainfo(loc->file, oh, &ainfo)) < 0)
1482
0
            HGOTO_ERROR(H5E_ATTR, H5E_CANTGET, FAIL, "can't check for attribute info message");
1483
0
    } /* end if */
1484
1485
    /* Check for attributes stored densely */
1486
0
    if (H5_addr_defined(ainfo.fheap_addr)) {
1487
        /* Delete attribute from dense storage */
1488
0
        if (H5A__dense_remove(loc->file, &ainfo, name) < 0)
1489
0
            HGOTO_ERROR(H5E_ATTR, H5E_CANTDELETE, FAIL, "unable to delete attribute in dense storage");
1490
0
    } /* end if */
1491
0
    else {
1492
0
        H5O_iter_rm_t       udata; /* User data for callback */
1493
0
        H5O_mesg_operator_t op;    /* Wrapper for operator */
1494
1495
        /* Set up user data for callback */
1496
0
        udata.f     = loc->file;
1497
0
        udata.name  = name;
1498
0
        udata.found = false;
1499
1500
        /* Iterate over attributes, to locate correct one to delete */
1501
0
        op.op_type  = H5O_MESG_OP_LIB;
1502
0
        op.u.lib_op = H5O__attr_remove_cb;
1503
0
        if (H5O__msg_iterate_real(loc->file, oh, H5O_MSG_ATTR, &op, &udata) < 0)
1504
0
            HGOTO_ERROR(H5E_ATTR, H5E_CANTDELETE, FAIL, "error deleting attribute");
1505
1506
        /* Check that we found the attribute */
1507
0
        if (!udata.found)
1508
0
            HGOTO_ERROR(H5E_ATTR, H5E_NOTFOUND, FAIL, "can't locate attribute");
1509
0
    } /* end else */
1510
1511
    /* Update the attribute information after removing an attribute */
1512
0
    if (ainfo_exists)
1513
0
        if (H5O__attr_remove_update(loc, oh, &ainfo) < 0)
1514
0
            HGOTO_ERROR(H5E_ATTR, H5E_CANTUPDATE, FAIL, "unable to update attribute info");
1515
1516
    /* Update the modification time, if any */
1517
0
    if (H5O_touch_oh(loc->file, oh, false) < 0)
1518
0
        HGOTO_ERROR(H5E_ATTR, H5E_CANTUPDATE, FAIL, "unable to update time on object");
1519
1520
0
done:
1521
0
    if (oh && H5O_unpin(oh) < 0)
1522
0
        HDONE_ERROR(H5E_ATTR, H5E_CANTUNPIN, FAIL, "unable to unpin object header");
1523
1524
0
    FUNC_LEAVE_NOAPI_TAG(ret_value)
1525
0
} /* end H5O__attr_remove() */
1526
1527
/*-------------------------------------------------------------------------
1528
 * Function:    H5O__attr_remove_by_idx
1529
 *
1530
 * Purpose:     Delete an attribute on an object, according to an order within
1531
 *              an index.
1532
 *
1533
 * Return:      SUCCEED/FAIL
1534
 *
1535
 *-------------------------------------------------------------------------
1536
 */
1537
herr_t
1538
H5O__attr_remove_by_idx(const H5O_loc_t *loc, H5_index_t idx_type, H5_iter_order_t order, hsize_t n)
1539
0
{
1540
0
    H5O_t           *oh = NULL;                   /* Pointer to actual object header */
1541
0
    H5O_ainfo_t      ainfo;                       /* Attribute information for object */
1542
0
    htri_t           ainfo_exists = false;        /* Whether the attribute info exists in the file */
1543
0
    H5A_attr_table_t atable       = {0, 0, NULL}; /* Table of attributes */
1544
0
    herr_t           ret_value    = SUCCEED;      /* Return value */
1545
1546
0
    FUNC_ENTER_PACKAGE_TAG(loc->addr)
1547
1548
    /* Check arguments */
1549
0
    assert(loc);
1550
1551
    /* Pin the object header */
1552
0
    if (NULL == (oh = H5O_pin(loc)))
1553
0
        HGOTO_ERROR(H5E_ATTR, H5E_CANTPIN, FAIL, "unable to pin object header");
1554
1555
    /* Check for attribute info stored */
1556
0
    ainfo.fheap_addr = HADDR_UNDEF;
1557
0
    if (oh->version > H5O_VERSION_1) {
1558
        /* Check for (& retrieve if available) attribute info */
1559
0
        if ((ainfo_exists = H5A__get_ainfo(loc->file, oh, &ainfo)) < 0)
1560
0
            HGOTO_ERROR(H5E_ATTR, H5E_CANTGET, FAIL, "can't check for attribute info message");
1561
0
    } /* end if */
1562
1563
    /* Check for attributes stored densely */
1564
0
    if (H5_addr_defined(ainfo.fheap_addr)) {
1565
        /* Delete attribute from dense storage */
1566
0
        if (H5A__dense_remove_by_idx(loc->file, &ainfo, idx_type, order, n) < 0)
1567
0
            HGOTO_ERROR(H5E_ATTR, H5E_CANTDELETE, FAIL, "unable to delete attribute in dense storage");
1568
0
    } /* end if */
1569
0
    else {
1570
0
        H5O_iter_rm_t       udata; /* User data for callback */
1571
0
        H5O_mesg_operator_t op;    /* Wrapper for operator */
1572
1573
        /* Build table of attributes for compact storage */
1574
0
        if (H5A__compact_build_table(loc->file, oh, idx_type, order, &atable) < 0)
1575
0
            HGOTO_ERROR(H5E_ATTR, H5E_CANTINIT, FAIL, "error building attribute table");
1576
1577
        /* Check for skipping too many attributes */
1578
0
        if (n >= atable.num_attrs)
1579
0
            HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid index specified");
1580
1581
        /* Set up user data for callback, to remove the attribute by name */
1582
0
        udata.f     = loc->file;
1583
0
        udata.name  = ((atable.attrs[n])->shared)->name;
1584
0
        udata.found = false;
1585
1586
        /* Iterate over attributes, to locate correct one to delete */
1587
0
        op.op_type  = H5O_MESG_OP_LIB;
1588
0
        op.u.lib_op = H5O__attr_remove_cb;
1589
0
        if (H5O__msg_iterate_real(loc->file, oh, H5O_MSG_ATTR, &op, &udata) < 0)
1590
0
            HGOTO_ERROR(H5E_ATTR, H5E_CANTDELETE, FAIL, "error deleting attribute");
1591
1592
        /* Check that we found the attribute */
1593
0
        if (!udata.found)
1594
0
            HGOTO_ERROR(H5E_ATTR, H5E_NOTFOUND, FAIL, "can't locate attribute");
1595
0
    } /* end else */
1596
1597
    /* Update the attribute information after removing an attribute */
1598
0
    if (ainfo_exists)
1599
0
        if (H5O__attr_remove_update(loc, oh, &ainfo) < 0)
1600
0
            HGOTO_ERROR(H5E_ATTR, H5E_CANTUPDATE, FAIL, "unable to update attribute info");
1601
1602
    /* Update the modification time, if any */
1603
0
    if (H5O_touch_oh(loc->file, oh, false) < 0)
1604
0
        HGOTO_ERROR(H5E_ATTR, H5E_CANTUPDATE, FAIL, "unable to update time on object");
1605
1606
0
done:
1607
0
    if (oh && H5O_unpin(oh) < 0)
1608
0
        HDONE_ERROR(H5E_ATTR, H5E_CANTUNPIN, FAIL, "unable to unpin object header");
1609
0
    if (atable.attrs && H5A__attr_release_table(&atable) < 0)
1610
0
        HDONE_ERROR(H5E_ATTR, H5E_CANTFREE, FAIL, "unable to release attribute table");
1611
1612
0
    FUNC_LEAVE_NOAPI_TAG(ret_value)
1613
0
} /* end H5O__attr_remove_by_idx() */
1614
1615
/*-------------------------------------------------------------------------
1616
 * Function:    H5O__attr_count_real
1617
 *
1618
 * Purpose:     Determine the # of attributes on an object
1619
 *
1620
 * Return:      SUCCEED/FAIL
1621
 *
1622
 *-------------------------------------------------------------------------
1623
 */
1624
herr_t
1625
H5O__attr_count_real(H5F_t *f, H5O_t *oh, hsize_t *nattrs)
1626
0
{
1627
0
    herr_t ret_value = SUCCEED; /* Return value */
1628
1629
0
    FUNC_ENTER_PACKAGE
1630
1631
    /* Check arguments */
1632
0
    assert(f);
1633
0
    assert(oh);
1634
0
    assert(nattrs);
1635
1636
    /* Check for attributes stored densely */
1637
0
    if (oh->version > H5O_VERSION_1) {
1638
0
        htri_t      ainfo_exists = false; /* Whether the attribute info exists in the file */
1639
0
        H5O_ainfo_t ainfo;                /* Attribute information for object */
1640
1641
        /* Attempt to get the attribute information from the object header */
1642
0
        if ((ainfo_exists = H5A__get_ainfo(f, oh, &ainfo)) < 0)
1643
0
            HGOTO_ERROR(H5E_ATTR, H5E_CANTGET, FAIL, "can't check for attribute info message");
1644
0
        else if (ainfo_exists > 0)
1645
0
            *nattrs = ainfo.nattrs;
1646
0
        else
1647
0
            *nattrs = 0;
1648
0
    } /* end if */
1649
0
    else {
1650
0
        hsize_t  attr_count; /* Number of attributes found */
1651
0
        unsigned u;          /* Local index variable */
1652
1653
        /* Loop over all messages, counting the attributes */
1654
0
        attr_count = 0;
1655
0
        for (u = 0; u < oh->nmesgs; u++)
1656
0
            if (oh->mesg[u].type == H5O_MSG_ATTR)
1657
0
                attr_count++;
1658
0
        *nattrs = attr_count;
1659
0
    } /* end else */
1660
1661
0
done:
1662
0
    FUNC_LEAVE_NOAPI(ret_value)
1663
0
} /* end H5O__attr_count_real */
1664
1665
/*-------------------------------------------------------------------------
1666
 * Function:    H5O__attr_exists_cb
1667
 *
1668
 * Purpose:     Object header iterator callback routine to check for an
1669
 *              attribute stored compactly, by name.
1670
 *
1671
 * Return:      SUCCEED/FAIL
1672
 *
1673
 *-------------------------------------------------------------------------
1674
 */
1675
static herr_t
1676
H5O__attr_exists_cb(H5O_t H5_ATTR_UNUSED *oh, H5O_mesg_t *mesg /*in,out*/, unsigned H5_ATTR_UNUSED sequence,
1677
                    unsigned H5_ATTR_UNUSED *oh_modified, void *_udata /*in,out*/)
1678
0
{
1679
0
    H5O_iter_xst_t *udata     = (H5O_iter_xst_t *)_udata; /* Operator user data */
1680
0
    herr_t          ret_value = H5_ITER_CONT;             /* Return value */
1681
1682
0
    FUNC_ENTER_PACKAGE_NOERR
1683
1684
    /* check args */
1685
0
    assert(mesg);
1686
0
    assert(udata->exists && !*udata->exists);
1687
1688
    /* Check for correct attribute message */
1689
0
    if (strcmp(((H5A_t *)mesg->native)->shared->name, udata->name) == 0) {
1690
        /* Indicate that this message is the attribute sought */
1691
0
        *udata->exists = true;
1692
1693
        /* Stop iterating */
1694
0
        ret_value = H5_ITER_STOP;
1695
0
    } /* end if */
1696
1697
0
    FUNC_LEAVE_NOAPI(ret_value)
1698
0
} /* end H5O__attr_exists_cb() */
1699
1700
/*-------------------------------------------------------------------------
1701
 * Function:    H5O__attr_exists
1702
 *
1703
 * Purpose:     Determine if an attribute with a particular name exists on an object
1704
 *
1705
 * Return:      SUCCEED/FAIL
1706
 *
1707
 *-------------------------------------------------------------------------
1708
 */
1709
herr_t
1710
H5O__attr_exists(const H5O_loc_t *loc, const char *name, bool *attr_exists)
1711
0
{
1712
0
    H5O_t      *oh = NULL;           /* Pointer to actual object header */
1713
0
    H5O_ainfo_t ainfo;               /* Attribute information for object */
1714
0
    herr_t      ret_value = SUCCEED; /* Return value */
1715
1716
0
    FUNC_ENTER_PACKAGE_TAG(loc->addr)
1717
1718
    /* Check arguments */
1719
0
    assert(loc);
1720
0
    assert(name);
1721
0
    assert(attr_exists);
1722
1723
    /* Protect the object header to iterate over */
1724
0
    if (NULL == (oh = H5O_protect(loc, H5AC__READ_ONLY_FLAG, false)))
1725
0
        HGOTO_ERROR(H5E_ATTR, H5E_CANTPROTECT, FAIL, "unable to load object header");
1726
1727
    /* Check for attribute info stored */
1728
0
    ainfo.fheap_addr = HADDR_UNDEF;
1729
0
    if (oh->version > H5O_VERSION_1) {
1730
        /* Check for (& retrieve if available) attribute info */
1731
0
        if (H5A__get_ainfo(loc->file, oh, &ainfo) < 0)
1732
0
            HGOTO_ERROR(H5E_ATTR, H5E_CANTGET, FAIL, "can't check for attribute info message");
1733
0
    } /* end if */
1734
1735
    /* Check for attributes stored densely */
1736
0
    if (H5_addr_defined(ainfo.fheap_addr)) {
1737
        /* Check if attribute exists in dense storage */
1738
0
        if (H5A__dense_exists(loc->file, &ainfo, name, attr_exists) < 0)
1739
0
            HGOTO_ERROR(H5E_ATTR, H5E_BADITER, FAIL, "error checking for existence of attribute");
1740
0
    } /* end if */
1741
0
    else {
1742
0
        H5O_iter_xst_t      udata; /* User data for callback */
1743
0
        H5O_mesg_operator_t op;    /* Wrapper for operator */
1744
1745
        /* Set up user data for callback */
1746
0
        udata.name   = name;
1747
0
        udata.exists = attr_exists;
1748
1749
        /* Iterate over existing attributes, checking for attribute with same name */
1750
0
        op.op_type  = H5O_MESG_OP_LIB;
1751
0
        op.u.lib_op = H5O__attr_exists_cb;
1752
0
        if (H5O__msg_iterate_real(loc->file, oh, H5O_MSG_ATTR, &op, &udata) < 0)
1753
0
            HGOTO_ERROR(H5E_ATTR, H5E_BADITER, FAIL, "error checking for existence of attribute");
1754
0
    } /* end else */
1755
1756
0
done:
1757
0
    if (oh && H5O_unprotect(loc, oh, H5AC__NO_FLAGS_SET) < 0)
1758
0
        HDONE_ERROR(H5E_ATTR, H5E_CANTUNPROTECT, FAIL, "unable to release object header");
1759
1760
0
    FUNC_LEAVE_NOAPI_TAG(ret_value)
1761
0
} /* end H5O__attr_exists() */
1762
1763
/*-------------------------------------------------------------------------
1764
 * Function:    H5O__attr_bh_info
1765
 *
1766
 * Purpose:     For 1.8 attribute, returns storage amount for btree and fractal heap
1767
 *
1768
 * Return:      SUCCEED/FAIL
1769
 *
1770
 *-------------------------------------------------------------------------
1771
 */
1772
herr_t
1773
H5O__attr_bh_info(H5F_t *f, H5O_t *oh, H5_ih_info_t *bh_info)
1774
0
{
1775
0
    H5HF_t *fheap      = NULL;    /* Fractal heap handle */
1776
0
    H5B2_t *bt2_name   = NULL;    /* v2 B-tree handle for name index */
1777
0
    H5B2_t *bt2_corder = NULL;    /* v2 B-tree handle for creation order index */
1778
0
    herr_t  ret_value  = SUCCEED; /* Return value */
1779
1780
0
    FUNC_ENTER_PACKAGE
1781
1782
0
    assert(f);
1783
0
    assert(oh);
1784
0
    assert(bh_info);
1785
1786
    /* Attributes are only stored in fractal heap & indexed w/v2 B-tree in later versions */
1787
0
    if (oh->version > H5O_VERSION_1) {
1788
0
        H5O_ainfo_t ainfo;                /* Attribute information for object */
1789
0
        htri_t      ainfo_exists = false; /* Whether the attribute info exists in the file */
1790
1791
        /* Check for (& retrieve if available) attribute info */
1792
0
        if ((ainfo_exists = H5A__get_ainfo(f, oh, &ainfo)) < 0)
1793
0
            HGOTO_ERROR(H5E_ATTR, H5E_CANTGET, FAIL, "can't check for attribute info message");
1794
0
        else if (ainfo_exists > 0) {
1795
            /* Check if name index available */
1796
0
            if (H5_addr_defined(ainfo.name_bt2_addr)) {
1797
                /* Open the name index v2 B-tree */
1798
0
                if (NULL == (bt2_name = H5B2_open(f, ainfo.name_bt2_addr, NULL)))
1799
0
                    HGOTO_ERROR(H5E_ATTR, H5E_CANTOPENOBJ, FAIL, "unable to open v2 B-tree for name index");
1800
1801
                /* Get name index B-tree size */
1802
0
                if (H5B2_size(bt2_name, &(bh_info->index_size)) < 0)
1803
0
                    HGOTO_ERROR(H5E_ATTR, H5E_CANTGET, FAIL, "can't retrieve B-tree storage info");
1804
0
            } /* end if */
1805
1806
            /* Check if creation order index available */
1807
0
            if (H5_addr_defined(ainfo.corder_bt2_addr)) {
1808
                /* Open the creation order index v2 B-tree */
1809
0
                if (NULL == (bt2_corder = H5B2_open(f, ainfo.corder_bt2_addr, NULL)))
1810
0
                    HGOTO_ERROR(H5E_ATTR, H5E_CANTOPENOBJ, FAIL,
1811
0
                                "unable to open v2 B-tree for creation order index");
1812
1813
                /* Get creation order index B-tree size */
1814
0
                if (H5B2_size(bt2_corder, &(bh_info->index_size)) < 0)
1815
0
                    HGOTO_ERROR(H5E_ATTR, H5E_CANTGET, FAIL, "can't retrieve B-tree storage info");
1816
0
            } /* end if */
1817
1818
            /* Get storage size of fractal heap, if it's used */
1819
0
            if (H5_addr_defined(ainfo.fheap_addr)) {
1820
                /* Open the fractal heap for attributes */
1821
0
                if (NULL == (fheap = H5HF_open(f, ainfo.fheap_addr)))
1822
0
                    HGOTO_ERROR(H5E_ATTR, H5E_CANTOPENOBJ, FAIL, "unable to open fractal heap");
1823
1824
                /* Get heap storage size */
1825
0
                if (H5HF_size(fheap, &(bh_info->heap_size)) < 0)
1826
0
                    HGOTO_ERROR(H5E_ATTR, H5E_CANTGET, FAIL, "can't retrieve B-tree storage info");
1827
0
            } /* end if */
1828
0
        }     /* end else */
1829
0
    }         /* end if */
1830
1831
0
done:
1832
    /* Release resources */
1833
0
    if (fheap && H5HF_close(fheap) < 0)
1834
0
        HDONE_ERROR(H5E_ATTR, H5E_CANTCLOSEOBJ, FAIL, "can't close fractal heap");
1835
0
    if (bt2_name && H5B2_close(bt2_name) < 0)
1836
0
        HDONE_ERROR(H5E_ATTR, H5E_CANTCLOSEOBJ, FAIL, "can't close v2 B-tree for name index");
1837
0
    if (bt2_corder && H5B2_close(bt2_corder) < 0)
1838
0
        HDONE_ERROR(H5E_ATTR, H5E_CANTCLOSEOBJ, FAIL, "can't close v2 B-tree for creation order index");
1839
1840
0
    FUNC_LEAVE_NOAPI(ret_value)
1841
0
} /* H5O__attr_bh_info() */