Coverage Report

Created: 2026-03-04 00:50

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/hdf5/src/H5Oint.c
Line
Count
Source
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:     H5O.c
16
 *
17
 * Purpose:     Internal object header routines
18
 *
19
 *-------------------------------------------------------------------------
20
 */
21
22
/****************/
23
/* Module Setup */
24
/****************/
25
26
#include "H5Omodule.h" /* This source code file is part of the H5O module */
27
28
/***********/
29
/* Headers */
30
/***********/
31
#include "H5private.h"   /* Generic Functions                        */
32
#include "H5CXprivate.h" /* API Contexts                             */
33
#include "H5Eprivate.h"  /* Error handling                           */
34
#include "H5Fprivate.h"  /* File access                              */
35
#include "H5FLprivate.h" /* Free lists                               */
36
#include "H5FOprivate.h" /* File objects                             */
37
#include "H5Iprivate.h"  /* IDs                                      */
38
#include "H5Lprivate.h"  /* Links                                    */
39
#include "H5MFprivate.h" /* File memory management                   */
40
#include "H5MMprivate.h" /* Memory management                        */
41
#include "H5Opkg.h"      /* Object headers                           */
42
#include "H5SLprivate.h" /* Skip Lists                               */
43
#include "H5VLprivate.h" /* Virtual Object Layer                     */
44
45
#include "H5VLnative_private.h" /* Native VOL connector                     */
46
47
/****************/
48
/* Local Macros */
49
/****************/
50
51
/******************/
52
/* Local Typedefs */
53
/******************/
54
55
/* User data for recursive traversal over objects from a group */
56
typedef struct {
57
    hid_t          obj_id;    /* The ID for the starting group */
58
    H5G_loc_t     *start_loc; /* Location of starting group */
59
    H5SL_t        *visited;   /* Skip list for tracking visited nodes */
60
    H5O_iterate2_t op;        /* Application callback */
61
    void          *op_data;   /* Application's op data */
62
    unsigned       fields;    /* Selection of object info */
63
} H5O_iter_visit_ud_t;
64
65
/********************/
66
/* Package Typedefs */
67
/********************/
68
69
/********************/
70
/* Local Prototypes */
71
/********************/
72
73
static herr_t H5O__delete_oh(H5F_t *f, H5O_t *oh);
74
static herr_t H5O__obj_type_real(const H5O_t *oh, H5O_type_t *obj_type);
75
static herr_t H5O__get_hdr_info_real(const H5O_t *oh, H5O_hdr_info_t *hdr);
76
static herr_t H5O__free_visit_visited(void *item, void *key, void *operator_data /*in,out*/);
77
static herr_t H5O__visit_cb(hid_t group, const char *name, const H5L_info2_t *linfo, void *_udata);
78
static herr_t H5O__obj_class_real(const H5O_t *oh, const H5O_obj_class_t **cls);
79
static herr_t H5O__reset_info2(H5O_info2_t *oinfo);
80
81
/*********************/
82
/* Package Variables */
83
/*********************/
84
85
/* Package initialization variable */
86
bool H5_PKG_INIT_VAR = false;
87
88
/* Header message ID to class mapping
89
 *
90
 * Remember to increment H5O_MSG_TYPES in H5Opkg.h when adding a new
91
 * message.
92
 */
93
const H5O_msg_class_t *const H5O_msg_class_g[] = {
94
    H5O_MSG_NULL,     /*0x0000 Null                            */
95
    H5O_MSG_SDSPACE,  /*0x0001 Dataspace                       */
96
    H5O_MSG_LINFO,    /*0x0002 Link information                */
97
    H5O_MSG_DTYPE,    /*0x0003 Datatype                        */
98
    H5O_MSG_FILL,     /*0x0004 Old data storage -- fill value  */
99
    H5O_MSG_FILL_NEW, /*0x0005 New data storage -- fill value  */
100
    H5O_MSG_LINK,     /*0x0006 Link                            */
101
    H5O_MSG_EFL,      /*0x0007 Data storage -- external data files */
102
    H5O_MSG_LAYOUT,   /*0x0008 Data Layout                     */
103
#ifdef H5O_ENABLE_BOGUS
104
    H5O_MSG_BOGUS_VALID, /*0x0009 "Bogus valid" (for testing)     */
105
#else                    /* H5O_ENABLE_BOGUS */
106
    NULL, /*0x0009 "Bogus valid" (for testing)     */
107
#endif                   /* H5O_ENABLE_BOGUS */
108
    H5O_MSG_GINFO,       /*0x000A Group information               */
109
    H5O_MSG_PLINE,       /*0x000B Data storage -- filter pipeline */
110
    H5O_MSG_ATTR,        /*0x000C Attribute                       */
111
    H5O_MSG_NAME,        /*0x000D Object name                     */
112
    H5O_MSG_MTIME,       /*0x000E Object modification date and time */
113
    H5O_MSG_SHMESG,      /*0x000F File-wide shared message table  */
114
    H5O_MSG_CONT,        /*0x0010 Object header continuation      */
115
    H5O_MSG_STAB,        /*0x0011 Symbol table                    */
116
    H5O_MSG_MTIME_NEW,   /*0x0012 New Object modification date and time */
117
    H5O_MSG_BTREEK,      /*0x0013 Non-default v1 B-tree 'K' values */
118
    H5O_MSG_DRVINFO,     /*0x0014 Driver info settings            */
119
    H5O_MSG_AINFO,       /*0x0015 Attribute information           */
120
    H5O_MSG_REFCOUNT,    /*0x0016 Object's ref. count             */
121
    H5O_MSG_FSINFO,      /*0x0017 Free-space manager info         */
122
    H5O_MSG_MDCI,        /*0x0018 Metadata cache image            */
123
    H5O_MSG_UNKNOWN,     /*0x0019 Placeholder for unknown message */
124
    H5O_MSG_DELETED      /*0x001a Placeholder for deleted message */
125
};
126
127
/* Format version bounds for object header */
128
const unsigned H5O_obj_ver_bounds[] = {
129
    H5O_VERSION_1,     /* H5F_LIBVER_EARLIEST */
130
    H5O_VERSION_2,     /* H5F_LIBVER_V18 */
131
    H5O_VERSION_2,     /* H5F_LIBVER_V110 */
132
    H5O_VERSION_2,     /* H5F_LIBVER_V112 */
133
    H5O_VERSION_2,     /* H5F_LIBVER_V114 */
134
    H5O_VERSION_2,     /* H5F_LIBVER_V200 */
135
    H5O_VERSION_LATEST /* H5F_LIBVER_LATEST */
136
};
137
138
/* Declare a free list to manage the H5O_t struct */
139
H5FL_DEFINE(H5O_t);
140
141
/* Declare a free list to manage the H5O_mesg_t sequence information */
142
H5FL_SEQ_DEFINE(H5O_mesg_t);
143
144
/* Declare a free list to manage the H5O_chunk_t sequence information */
145
H5FL_SEQ_DEFINE(H5O_chunk_t);
146
147
/* Declare a free list to manage the chunk image information */
148
H5FL_BLK_DEFINE(chunk_image);
149
150
/* Declare external the free list for H5O_cont_t sequences */
151
H5FL_SEQ_EXTERN(H5O_cont_t);
152
153
/* The canonical 'undefined' token */
154
const H5O_token_t H5O_TOKEN_UNDEF_g = {
155
    {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}};
156
157
/*****************************/
158
/* Library Private Variables */
159
/*****************************/
160
161
/* Declare external the free list for time_t's */
162
H5FL_EXTERN(time_t);
163
164
/* Declare external the free list for H5_obj_t's */
165
H5FL_EXTERN(H5_obj_t);
166
167
/*******************/
168
/* Local Variables */
169
/*******************/
170
171
/* Header object ID to class mapping */
172
/*
173
 * Initialize the object class info table.  Begin with the most general types
174
 * and end with the most specific. For instance, any object that has a
175
 * datatype message is a datatype but only some of them are datasets.
176
 */
177
static const H5O_obj_class_t *const H5O_obj_class_g[] = {
178
    H5O_OBJ_DATATYPE, /* Datatype object (H5O_TYPE_NAMED_DATATYPE - 2) */
179
    H5O_OBJ_DATASET,  /* Dataset object (H5O_TYPE_DATASET - 1) */
180
    H5O_OBJ_GROUP,    /* Group object (H5O_TYPE_GROUP - 0) */
181
};
182
183
/*-------------------------------------------------------------------------
184
 * Function:    H5O_init
185
 *
186
 * Purpose:     Initialize the interface from some other package.
187
 *
188
 * Return:      Success:  non-negative
189
 *              Failure:  negative
190
 *
191
 *-------------------------------------------------------------------------
192
 */
193
H5_ATTR_CONST herr_t
194
H5O_init(void)
195
1
{
196
1
    herr_t ret_value = SUCCEED; /* Return value */
197
198
1
    FUNC_ENTER_NOAPI(FAIL)
199
    /* FUNC_ENTER() does all the work */
200
201
1
done:
202
1
    FUNC_LEAVE_NOAPI(ret_value)
203
1
} /* end H5O_init() */
204
205
/*-------------------------------------------------------------------------
206
 * Function:    H5O__init_package
207
 *
208
 * Purpose:     Initialize information specific to H5O interface.
209
 *
210
 * Return:      Success:        non-negative
211
 *              Failure:        negative
212
 *
213
 *-------------------------------------------------------------------------
214
 */
215
herr_t
216
H5O__init_package(void)
217
1
{
218
1
    FUNC_ENTER_PACKAGE_NOERR
219
220
    /* H5O interface sanity checks */
221
1
    HDcompile_assert(H5O_MSG_TYPES == NELMTS(H5O_msg_class_g));
222
1
    HDcompile_assert(sizeof(H5O_fheap_id_t) == H5O_FHEAP_ID_LEN);
223
224
1
    HDcompile_assert(H5O_UNKNOWN_ID < H5O_MSG_TYPES);
225
226
1
    FUNC_LEAVE_NOAPI(SUCCEED)
227
1
} /* end H5O__init_package() */
228
229
/*-------------------------------------------------------------------------
230
 * Function:    H5O__set_version
231
 *
232
 * Purpose:     Sets the correct version to encode the object header.
233
 *              Chooses the oldest version possible, unless the file's
234
 *              low bound indicates otherwise.
235
 *
236
 * Return:  Success:    Non-negative
237
 *          Failure:    Negative
238
 *
239
 *-------------------------------------------------------------------------
240
 */
241
static herr_t
242
H5O__set_version(H5F_t *f, H5O_t *oh, uint8_t oh_flags, bool store_msg_crt_idx)
243
0
{
244
0
    uint8_t version;             /* Message version */
245
0
    herr_t  ret_value = SUCCEED; /* Return value */
246
247
0
    FUNC_ENTER_PACKAGE
248
249
    /* check arguments */
250
0
    assert(f);
251
0
    assert(oh);
252
253
    /* Set the correct version to encode object header with */
254
0
    if (store_msg_crt_idx || (oh_flags & H5O_HDR_ATTR_CRT_ORDER_TRACKED))
255
0
        version = H5O_VERSION_LATEST;
256
0
    else
257
0
        version = H5O_VERSION_1;
258
259
    /* Upgrade to the version indicated by the file's low bound if higher */
260
0
    version = (uint8_t)MAX(version, (uint8_t)H5O_obj_ver_bounds[H5F_LOW_BOUND(f)]);
261
262
    /* Version bounds check */
263
0
    if (version > H5O_obj_ver_bounds[H5F_HIGH_BOUND(f)])
264
0
        HGOTO_ERROR(H5E_OHDR, H5E_BADRANGE, FAIL, "object header version out of bounds");
265
266
    /* Set the message version */
267
0
    oh->version = version;
268
269
0
done:
270
0
    FUNC_LEAVE_NOAPI(ret_value)
271
0
} /* end H5O__set_version() */
272
273
/*-------------------------------------------------------------------------
274
 * Function:    H5O_create
275
 *
276
 * Purpose:    Creates a new object header. Allocates space for it and
277
 *              then calls an initialization function. The object header
278
 *              is opened for write access and should eventually be
279
 *              closed by calling H5O_close().
280
 *
281
 * Return:    Success:    Non-negative, the ENT argument contains
282
 *                information about the object header,
283
 *                including its address.
284
 *
285
 *        Failure:    Negative
286
 *
287
 *-------------------------------------------------------------------------
288
 */
289
herr_t
290
H5O_create(H5F_t *f, size_t size_hint, size_t initial_rc, hid_t ocpl_id, H5O_loc_t *loc /*out*/)
291
0
{
292
0
    H5O_t *oh        = NULL;
293
0
    herr_t ret_value = SUCCEED;
294
295
0
    FUNC_ENTER_NOAPI(FAIL)
296
297
0
    assert(f);
298
0
    assert(loc);
299
0
    assert(true == H5P_isa_class(ocpl_id, H5P_OBJECT_CREATE));
300
301
    /* create object header in freelist
302
     * header version is set internally
303
     */
304
0
    oh = H5O_create_ohdr(f, ocpl_id);
305
0
    if (NULL == oh)
306
0
        HGOTO_ERROR(H5E_OHDR, H5E_BADVALUE, FAIL, "Can't instantiate object header");
307
308
    /* apply object header information to file
309
     */
310
0
    if (H5O_apply_ohdr(f, oh, ocpl_id, size_hint, initial_rc, loc) < 0)
311
0
        HGOTO_ERROR(H5E_OHDR, H5E_BADVALUE, FAIL, "Can't apply object header to file");
312
313
0
done:
314
0
    if ((FAIL == ret_value) && (NULL != oh) && (H5O__free(oh, true) < 0))
315
0
        HDONE_ERROR(H5E_OHDR, H5E_CANTFREE, FAIL, "can't delete object header");
316
317
0
    FUNC_LEAVE_NOAPI(ret_value)
318
0
} /* end H5O_create() */
319
320
/*-----------------------------------------------------------------------------
321
 * Function:   H5O_create_ohdr
322
 *
323
 * Purpose:    Create the object header, set version and flags.
324
 *
325
 * Return:     Success: Pointer to the newly-crated header object.
326
 *             Failure: NULL
327
 *
328
 *-----------------------------------------------------------------------------
329
 */
330
H5O_t *
331
H5O_create_ohdr(H5F_t *f, hid_t ocpl_id)
332
0
{
333
0
    H5P_genplist_t *oc_plist;
334
0
    H5O_t          *oh = NULL; /* Object header in Freelist */
335
0
    uint8_t         oh_flags;  /* Initial status flags */
336
0
    H5O_t          *ret_value = NULL;
337
338
0
    FUNC_ENTER_NOAPI(NULL)
339
340
0
    assert(f);
341
0
    assert(true == H5P_isa_class(ocpl_id, H5P_OBJECT_CREATE));
342
343
    /* Check for invalid access request */
344
0
    if (0 == (H5F_INTENT(f) & H5F_ACC_RDWR))
345
0
        HGOTO_ERROR(H5E_OHDR, H5E_BADVALUE, NULL, "no write intent on file");
346
347
0
    oh = H5FL_CALLOC(H5O_t);
348
0
    if (NULL == oh)
349
0
        HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed");
350
351
0
    oc_plist = (H5P_genplist_t *)H5I_object(ocpl_id);
352
0
    if (NULL == oc_plist)
353
0
        HGOTO_ERROR(H5E_PLIST, H5E_BADTYPE, NULL, "not a property list");
354
355
    /* Get any object header status flags set by properties */
356
0
    if (H5P_DATASET_CREATE_DEFAULT == ocpl_id) {
357
        /* If the OCPL is the default DCPL, we can get the header flags from the
358
         * API context. Otherwise we have to call H5P_get */
359
0
        if (H5CX_get_ohdr_flags(&oh_flags) < 0)
360
0
            HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, NULL, "can't get object header flags");
361
0
    }
362
0
    else {
363
0
        if (H5P_get(oc_plist, H5O_CRT_OHDR_FLAGS_NAME, &oh_flags) < 0)
364
0
            HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, NULL, "can't get object header flags");
365
0
    }
366
367
0
    if (H5O__set_version(f, oh, oh_flags, H5F_STORE_MSG_CRT_IDX(f)) < 0)
368
0
        HGOTO_ERROR(H5E_OHDR, H5E_CANTSET, NULL, "can't set version of object header");
369
370
0
    oh->flags = oh_flags;
371
372
0
    ret_value = oh;
373
374
0
done:
375
0
    if ((NULL == ret_value) && (NULL != oh) && (H5O__free(oh, true) < 0))
376
0
        HDONE_ERROR(H5E_OHDR, H5E_CANTFREE, NULL, "can't delete object header");
377
378
0
    FUNC_LEAVE_NOAPI(ret_value)
379
0
} /* H5O_create_ohdr() */
380
381
/*-----------------------------------------------------------------------------
382
 * Function:   H5O_apply_ohdr
383
 *
384
 * Purpose:    Initialize and set the object header in the file.
385
 *             Record some information at `loc_out`.
386
 *
387
 * Return:     Success: SUCCEED (0) (non-negative value)
388
 *             Failure: FAIL (-1) (negative value)
389
 *
390
 *-----------------------------------------------------------------------------
391
 */
392
herr_t
393
H5O_apply_ohdr(H5F_t *f, H5O_t *oh, hid_t ocpl_id, size_t size_hint, size_t initial_rc, H5O_loc_t *loc_out)
394
0
{
395
0
    haddr_t         oh_addr;
396
0
    size_t          oh_size;
397
0
    H5P_genplist_t *oc_plist     = NULL;
398
0
    unsigned        insert_flags = H5AC__NO_FLAGS_SET;
399
0
    herr_t          ret_value    = SUCCEED;
400
401
0
    FUNC_ENTER_NOAPI(FAIL)
402
403
0
    assert(f);
404
0
    assert(loc_out);
405
0
    assert(oh);
406
0
    assert(true == H5P_isa_class(ocpl_id, H5P_OBJECT_CREATE));
407
408
    /* Allocate at least a reasonable size for the object header */
409
0
    size_hint = H5O_ALIGN_F(f, MAX(H5O_MIN_SIZE, size_hint));
410
411
0
    oh->sizeof_size = H5F_SIZEOF_SIZE(f);
412
0
    oh->sizeof_addr = H5F_SIZEOF_ADDR(f);
413
0
    oh->swmr_write  = !!(H5F_INTENT(f) & H5F_ACC_SWMR_WRITE); /* funky cast */
414
415
#ifdef H5O_ENABLE_BAD_MESG_COUNT
416
    /* Check whether the "bad message count" property is set */
417
    if (0 < H5P_exist_plist(oc_plist, H5O_BAD_MESG_COUNT_NAME))
418
        /* Get bad message count flag -- from property list */
419
        if (H5P_get(oc_plist, H5O_BAD_MESG_COUNT_NAME, &oh->store_bad_mesg_count) < 0)
420
            HGOTO_ERROR(H5E_OHDR, H5E_CANTGET, FAIL, "can't get bad message count flag");
421
#endif /* H5O_ENABLE_BAD_MESG_COUNT */
422
423
    /* Create object header proxy if doing SWMR writes */
424
0
    if (oh->swmr_write) {
425
0
        oh->proxy = H5AC_proxy_entry_create();
426
0
        if (NULL == oh->proxy)
427
0
            HGOTO_ERROR(H5E_OHDR, H5E_CANTCREATE, FAIL, "can't create object header proxy");
428
0
    }
429
0
    else {
430
0
        oh->proxy = NULL;
431
0
    }
432
433
0
    oc_plist = (H5P_genplist_t *)H5I_object(ocpl_id);
434
0
    if (NULL == oc_plist)
435
0
        HGOTO_ERROR(H5E_PLIST, H5E_BADTYPE, FAIL, "not a property list");
436
437
    /* Initialize version-specific fields */
438
0
    if (oh->version > H5O_VERSION_1) {
439
        /* Initialize all time fields */
440
0
        if (oh->flags & H5O_HDR_STORE_TIMES)
441
0
            oh->atime = oh->mtime = oh->ctime = oh->btime = H5_now();
442
0
        else
443
0
            oh->atime = oh->mtime = oh->ctime = oh->btime = 0;
444
445
0
        if (H5F_STORE_MSG_CRT_IDX(f))
446
            /* flag to record message creation indices */
447
0
            oh->flags |= H5O_HDR_ATTR_CRT_ORDER_TRACKED;
448
449
        /* Get attribute storage phase change values -- from property list */
450
0
        if (H5P_get(oc_plist, H5O_CRT_ATTR_MAX_COMPACT_NAME, &oh->max_compact) < 0)
451
0
            HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get max. # of compact attributes");
452
0
        if (H5P_get(oc_plist, H5O_CRT_ATTR_MIN_DENSE_NAME, &oh->min_dense) < 0)
453
0
            HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get min. # of dense attributes");
454
455
        /* Check for non-default attribute storage phase change values */
456
0
        if (H5O_CRT_ATTR_MAX_COMPACT_DEF != oh->max_compact || H5O_CRT_ATTR_MIN_DENSE_DEF != oh->min_dense)
457
0
            oh->flags |= H5O_HDR_ATTR_STORE_PHASE_CHANGE;
458
459
            /* Determine correct value for chunk #0 size bits */
460
/* Avoid compiler warning on 32-bit machines */
461
0
#if H5_SIZEOF_SIZE_T > H5_SIZEOF_INT32_T
462
0
        if (size_hint > 4294967295UL)
463
0
            oh->flags |= H5O_HDR_CHUNK0_8;
464
0
        else if (size_hint > 65535)
465
0
            oh->flags |= H5O_HDR_CHUNK0_4;
466
0
        else if (size_hint > 255)
467
0
            oh->flags |= H5O_HDR_CHUNK0_2;
468
#else
469
        if (size_hint > 65535)
470
            oh->flags |= H5O_HDR_CHUNK0_4;
471
        else if (size_hint > 255)
472
            oh->flags |= H5O_HDR_CHUNK0_2;
473
#endif
474
0
    }
475
0
    else {
476
        /* Reset unused time fields */
477
0
        oh->atime = oh->mtime = oh->ctime = oh->btime = 0;
478
0
    } /* end if/else header version >1 */
479
480
    /* Compute total size of initial object header */
481
    /* (i.e. object header prefix and first chunk) */
482
0
    oh_size = (size_t)H5O_SIZEOF_HDR(oh) + size_hint;
483
484
    /* Allocate disk space for header and first chunk */
485
0
    oh_addr = H5MF_alloc(f, H5FD_MEM_OHDR, (hsize_t)oh_size);
486
0
    if (HADDR_UNDEF == oh_addr)
487
0
        HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "file allocation failed for object header");
488
489
    /* Create the chunk list */
490
0
    oh->nchunks       = 1;
491
0
    oh->alloc_nchunks = 1;
492
0
    oh->chunk         = H5FL_SEQ_MALLOC(H5O_chunk_t, (size_t)oh->alloc_nchunks);
493
0
    if (NULL == oh->chunk)
494
0
        HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed");
495
496
    /* Initialize the first chunk */
497
0
    oh->chunk[0].addr = oh_addr;
498
0
    oh->chunk[0].size = oh_size;
499
0
    oh->chunk[0].gap  = 0;
500
501
    /* Allocate enough space for the first chunk */
502
    /* (including space for serializing the object header prefix */
503
0
    oh->chunk[0].image = H5FL_BLK_CALLOC(chunk_image, oh_size);
504
0
    if (NULL == oh->chunk[0].image)
505
0
        HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed");
506
0
    oh->chunk[0].chunk_proxy = NULL;
507
508
    /* Put magic # for object header in first chunk */
509
0
    if (H5O_VERSION_1 < oh->version)
510
0
        H5MM_memcpy(oh->chunk[0].image, H5O_HDR_MAGIC, (size_t)H5_SIZEOF_MAGIC);
511
512
    /* Create the message list */
513
0
    oh->nmesgs       = 1;
514
0
    oh->alloc_nmesgs = H5O_NMESGS;
515
0
    oh->mesg         = H5FL_SEQ_CALLOC(H5O_mesg_t, oh->alloc_nmesgs);
516
0
    if (NULL == oh->mesg)
517
0
        HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed");
518
519
    /* Initialize the initial "null" message; covers the entire first chunk */
520
0
    oh->mesg[0].type   = H5O_MSG_NULL;
521
0
    oh->mesg[0].dirty  = true;
522
0
    oh->mesg[0].native = NULL;
523
0
    oh->mesg[0].raw =
524
0
        oh->chunk[0].image + H5O_SIZEOF_HDR(oh) - H5O_SIZEOF_CHKSUM_OH(oh) + H5O_SIZEOF_MSGHDR_OH(oh);
525
0
    oh->mesg[0].raw_size = size_hint - (size_t)H5O_SIZEOF_MSGHDR_OH(oh);
526
0
    oh->mesg[0].chunkno  = 0;
527
528
    /* Check for non-zero initial refcount on the object header */
529
0
    if (initial_rc > 0) {
530
        /* Set the initial refcount & pin the header when its inserted */
531
0
        oh->rc = initial_rc;
532
0
        insert_flags |= H5AC__PIN_ENTRY_FLAG;
533
0
    }
534
535
    /* Set metadata tag in API context */
536
0
    H5_BEGIN_TAG(oh_addr)
537
538
    /* Cache object header */
539
0
    if (H5AC_insert_entry(f, H5AC_OHDR, oh_addr, oh, insert_flags) < 0)
540
0
        HGOTO_ERROR_TAG(H5E_OHDR, H5E_CANTINSERT, FAIL, "unable to cache object header");
541
542
    /* Reset object header pointer, now that it's been inserted into the cache */
543
0
    oh = NULL;
544
545
    /* Reset metadata tag in API context */
546
0
    H5_END_TAG
547
548
    /* Set up object location */
549
0
    loc_out->file = f;
550
0
    loc_out->addr = oh_addr;
551
552
0
    if (H5O_open(loc_out) < 0)
553
0
        HGOTO_ERROR(H5E_OHDR, H5E_CANTOPENOBJ, FAIL, "unable to open object header");
554
555
0
done:
556
0
    FUNC_LEAVE_NOAPI(ret_value)
557
0
} /* H5O_apply_ohdr() */
558
559
/*-------------------------------------------------------------------------
560
 * Function:    H5O_open
561
 *
562
 * Purpose:    Opens an object header which is described by the symbol table
563
 *        entry OBJ_ENT.
564
 *
565
 * Return:    Non-negative on success/Negative on failure
566
 *-------------------------------------------------------------------------
567
 */
568
herr_t
569
H5O_open(H5O_loc_t *loc)
570
16.1k
{
571
16.1k
    herr_t ret_value = SUCCEED; /* Return value */
572
573
16.1k
    FUNC_ENTER_NOAPI(FAIL)
574
575
    /* Check args */
576
16.1k
    assert(loc);
577
16.1k
    assert(loc->file);
578
579
    /* Turn off the variable for holding file or increment open-lock counters */
580
16.1k
    if (loc->holding_file)
581
0
        loc->holding_file = false;
582
16.1k
    else
583
16.1k
        H5F_INCR_NOPEN_OBJS(loc->file);
584
585
16.1k
done:
586
16.1k
    FUNC_LEAVE_NOAPI(ret_value)
587
16.1k
} /* end H5O_open() */
588
589
/*-------------------------------------------------------------------------
590
 * Function:    H5O_open_name
591
 *
592
 * Purpose:     Opens an object by name
593
 *
594
 * Return:      Success:    Pointer to object data
595
 *              Failure:    NULL
596
 *
597
 *-------------------------------------------------------------------------
598
 */
599
void *
600
H5O_open_name(const H5G_loc_t *loc, const char *name, H5I_type_t *opened_type)
601
0
{
602
0
    H5G_loc_t  obj_loc;           /* Location used to open group */
603
0
    H5G_name_t obj_path;          /* Opened object group hier. path */
604
0
    H5O_loc_t  obj_oloc;          /* Opened object object location */
605
0
    bool       loc_found = false; /* Entry at 'name' found */
606
0
    void      *ret_value = NULL;  /* Return value */
607
608
0
    FUNC_ENTER_NOAPI(NULL)
609
610
    /* Check args */
611
0
    assert(loc);
612
0
    assert(name && *name);
613
614
    /* Set up opened group location to fill in */
615
0
    obj_loc.oloc = &obj_oloc;
616
0
    obj_loc.path = &obj_path;
617
0
    H5G_loc_reset(&obj_loc);
618
619
    /* Find the object's location */
620
0
    if (H5G_loc_find(loc, name, &obj_loc /*out*/) < 0)
621
0
        HGOTO_ERROR(H5E_OHDR, H5E_NOTFOUND, NULL, "object not found");
622
0
    loc_found = true;
623
624
    /* Open the object */
625
0
    if (NULL == (ret_value = H5O_open_by_loc(&obj_loc, opened_type)))
626
0
        HGOTO_ERROR(H5E_OHDR, H5E_CANTOPENOBJ, NULL, "unable to open object");
627
628
0
done:
629
0
    if (NULL == ret_value)
630
0
        if (loc_found && H5G_loc_free(&obj_loc) < 0)
631
0
            HDONE_ERROR(H5E_OHDR, H5E_CANTRELEASE, NULL, "can't free location");
632
633
0
    FUNC_LEAVE_NOAPI(ret_value)
634
0
} /* end H5O_open_name() */
635
636
/*-------------------------------------------------------------------------
637
 * Function:    H5O__open_by_idx
638
 *
639
 * Purpose:     Internal routine to open an object by index within group
640
 *
641
 * Return:      Success:    Pointer to object data
642
 *              Failure:    NULL
643
 *
644
 *-------------------------------------------------------------------------
645
 */
646
void *
647
H5O__open_by_idx(const H5G_loc_t *loc, const char *name, H5_index_t idx_type, H5_iter_order_t order,
648
                 hsize_t n, H5I_type_t *opened_type)
649
0
{
650
0
    H5G_loc_t  obj_loc;           /* Location used to open group */
651
0
    H5G_name_t obj_path;          /* Opened object group hier. path */
652
0
    H5O_loc_t  obj_oloc;          /* Opened object object location */
653
0
    bool       loc_found = false; /* Entry at 'name' found */
654
0
    void      *ret_value = NULL;  /* Return value */
655
656
0
    FUNC_ENTER_PACKAGE
657
658
    /* Check arguments */
659
0
    assert(loc);
660
661
    /* Set up opened group location to fill in */
662
0
    obj_loc.oloc = &obj_oloc;
663
0
    obj_loc.path = &obj_path;
664
0
    H5G_loc_reset(&obj_loc);
665
666
    /* Find the object's location, according to the order in the index */
667
0
    if (H5G_loc_find_by_idx(loc, name, idx_type, order, n, &obj_loc /*out*/) < 0)
668
0
        HGOTO_ERROR(H5E_OHDR, H5E_NOTFOUND, NULL, "group not found");
669
0
    loc_found = true;
670
671
    /* Open the object */
672
0
    if (NULL == (ret_value = H5O_open_by_loc(&obj_loc, opened_type)))
673
0
        HGOTO_ERROR(H5E_OHDR, H5E_CANTOPENOBJ, NULL, "unable to open object");
674
675
0
done:
676
    /* Release the object location if we failed after copying it */
677
0
    if (NULL == ret_value)
678
0
        if (loc_found && H5G_loc_free(&obj_loc) < 0)
679
0
            HDONE_ERROR(H5E_OHDR, H5E_CANTRELEASE, NULL, "can't free location");
680
681
0
    FUNC_LEAVE_NOAPI(ret_value)
682
0
} /* end H5O__open_by_idx() */
683
684
/*-------------------------------------------------------------------------
685
 * Function:    H5O__open_by_addr
686
 *
687
 * Purpose:     Internal routine to open an object by its address
688
 *
689
 * Return:      Success:    Pointer to object data
690
 *              Failure:    NULL
691
 *
692
 *-------------------------------------------------------------------------
693
 */
694
void *
695
H5O__open_by_addr(const H5G_loc_t *loc, haddr_t addr, H5I_type_t *opened_type)
696
1.33k
{
697
1.33k
    H5G_loc_t  obj_loc;          /* Location used to open group */
698
1.33k
    H5G_name_t obj_path;         /* Opened object group hier. path */
699
1.33k
    H5O_loc_t  obj_oloc;         /* Opened object object location */
700
1.33k
    void      *ret_value = NULL; /* Return value */
701
702
1.33k
    FUNC_ENTER_PACKAGE
703
704
    /* Check arguments */
705
1.33k
    assert(loc);
706
707
    /* Set up opened group location to fill in */
708
1.33k
    obj_loc.oloc = &obj_oloc;
709
1.33k
    obj_loc.path = &obj_path;
710
1.33k
    H5G_loc_reset(&obj_loc);
711
1.33k
    obj_loc.oloc->addr = addr;
712
1.33k
    obj_loc.oloc->file = loc->oloc->file;
713
1.33k
    H5G_name_reset(obj_loc.path); /* objects opened through this routine don't have a path name */
714
715
    /* Open the object */
716
1.33k
    if (NULL == (ret_value = H5O_open_by_loc(&obj_loc, opened_type)))
717
16
        HGOTO_ERROR(H5E_OHDR, H5E_CANTOPENOBJ, NULL, "unable to open object");
718
719
1.33k
done:
720
1.33k
    FUNC_LEAVE_NOAPI(ret_value)
721
1.33k
} /* end H5O__open_by_addr() */
722
723
/*-------------------------------------------------------------------------
724
 * Function:    H5O_open_by_loc
725
 *
726
 * Purpose:     Opens an object
727
 *
728
 * Return:      Success:    Pointer to object data
729
 *              Failure:    NULL
730
 *
731
 *-------------------------------------------------------------------------
732
 */
733
void *
734
H5O_open_by_loc(const H5G_loc_t *obj_loc, H5I_type_t *opened_type)
735
1.33k
{
736
1.33k
    const H5O_obj_class_t *obj_class;        /* Class of object for location */
737
1.33k
    void                  *ret_value = NULL; /* Return value */
738
739
1.33k
    FUNC_ENTER_NOAPI(NULL)
740
741
1.33k
    assert(obj_loc);
742
743
    /* Get the object class for this location */
744
1.33k
    if (NULL == (obj_class = H5O__obj_class(obj_loc->oloc)))
745
12
        HGOTO_ERROR(H5E_OHDR, H5E_CANTGET, NULL, "unable to determine object class");
746
747
    /* Call the object class's 'open' routine */
748
1.33k
    assert(obj_class->open);
749
1.32k
    if (NULL == (ret_value = obj_class->open(obj_loc, opened_type)))
750
4
        HGOTO_ERROR(H5E_OHDR, H5E_CANTOPENOBJ, NULL, "unable to open object");
751
752
1.33k
done:
753
1.33k
    FUNC_LEAVE_NOAPI(ret_value)
754
1.33k
} /* end H5O_open_by_loc() */
755
756
/*-------------------------------------------------------------------------
757
 * Function:    H5O_close
758
 *
759
 * Purpose:    Closes an object header that was previously open.
760
 *
761
 * Return:    Non-negative on success/Negative on failure
762
 *
763
 *-------------------------------------------------------------------------
764
 */
765
herr_t
766
H5O_close(H5O_loc_t *loc, bool *file_closed /*out*/)
767
16.0k
{
768
16.0k
    herr_t ret_value = SUCCEED; /* Return value */
769
770
16.0k
    FUNC_ENTER_NOAPI(FAIL)
771
772
    /* Check args */
773
16.0k
    assert(loc);
774
16.0k
    assert(loc->file);
775
16.0k
    assert(H5F_NOPEN_OBJS(loc->file) > 0);
776
777
    /* Set the file_closed flag to the default value.
778
     * This flag lets downstream code know if the file struct is
779
     * still accessible and/or likely to contain useful data.
780
     * It's needed by the evict-on-close code. Clients can ignore
781
     * this value by passing in NULL.
782
     */
783
16.0k
    if (file_closed)
784
8.94k
        *file_closed = false;
785
786
    /* Decrement open-lock counters */
787
16.0k
    H5F_DECR_NOPEN_OBJS(loc->file);
788
789
    /*
790
     * If the file open object count has reached the number of open mount points
791
     * (each of which has a group open in the file) attempt to close the file.
792
     */
793
16.0k
    if (H5F_NOPEN_OBJS(loc->file) == H5F_NMOUNTS(loc->file))
794
        /* Attempt to close down the file hierarchy */
795
2.15k
        if (H5F_try_close(loc->file, file_closed) < 0)
796
0
            HGOTO_ERROR(H5E_OHDR, H5E_CANTCLOSEFILE, FAIL, "problem attempting file close");
797
798
    /* Release location information */
799
16.0k
    if (H5O_loc_free(loc) < 0)
800
0
        HGOTO_ERROR(H5E_OHDR, H5E_CANTRELEASE, FAIL, "problem attempting to free location");
801
802
16.0k
done:
803
16.0k
    FUNC_LEAVE_NOAPI(ret_value)
804
16.0k
} /* end H5O_close() */
805
806
/*-------------------------------------------------------------------------
807
 * Function:    H5O__link_oh
808
 *
809
 * Purpose:     Adjust the link count for an open object header by adding
810
 *              ADJUST to the link count.
811
 *
812
 * Return:      Success:    New link count
813
 *
814
 *              Failure:    -1
815
 *
816
 *-------------------------------------------------------------------------
817
 */
818
int
819
H5O__link_oh(H5F_t *f, int adjust, H5O_t *oh, bool *deleted)
820
0
{
821
0
    haddr_t addr      = H5O_OH_GET_ADDR(oh); /* Object header address */
822
0
    int     ret_value = -1;                  /* Return value */
823
824
0
    FUNC_ENTER_PACKAGE
825
826
    /* check args */
827
0
    assert(f);
828
0
    assert(oh);
829
0
    assert(deleted);
830
831
    /* Check for adjusting link count */
832
0
    if (adjust) {
833
0
        if (adjust < 0) {
834
            /* Check for too large of an adjustment */
835
0
            if ((unsigned)(-adjust) > oh->nlink)
836
0
                HGOTO_ERROR(H5E_OHDR, H5E_LINKCOUNT, (-1), "link count would be negative");
837
838
            /* Adjust the link count for the object header */
839
0
            oh->nlink = (unsigned)((int)oh->nlink + adjust);
840
841
            /* Mark object header as dirty in cache */
842
0
            if (H5AC_mark_entry_dirty(oh) < 0)
843
0
                HGOTO_ERROR(H5E_OHDR, H5E_CANTMARKDIRTY, (-1), "unable to mark object header as dirty");
844
845
            /* Check if the object should be deleted */
846
0
            if (oh->nlink == 0) {
847
                /* Check if the object is still open by the user */
848
0
                if (H5FO_opened(f, addr) != NULL) {
849
                    /* Flag the object to be deleted when it's closed */
850
0
                    if (H5FO_mark(f, addr, true) < 0)
851
0
                        HGOTO_ERROR(H5E_OHDR, H5E_CANTDELETE, (-1), "can't mark object for deletion");
852
0
                } /* end if */
853
0
                else {
854
                    /* Mark the object header for deletion */
855
0
                    *deleted = true;
856
0
                } /* end else */
857
0
            }     /* end if */
858
0
        }         /* end if */
859
0
        else {
860
            /* A new object, or one that will be deleted */
861
0
            if (0 == oh->nlink) {
862
                /* Check if the object is currently open, but marked for deletion */
863
0
                if (H5FO_marked(f, addr)) {
864
                    /* Remove "delete me" flag on the object */
865
0
                    if (H5FO_mark(f, addr, false) < 0)
866
0
                        HGOTO_ERROR(H5E_OHDR, H5E_CANTDELETE, (-1), "can't mark object for deletion");
867
0
                } /* end if */
868
0
            }     /* end if */
869
870
            /* Adjust the link count for the object header */
871
0
            oh->nlink = (unsigned)((int)oh->nlink + adjust);
872
873
            /* Mark object header as dirty in cache */
874
0
            if (H5AC_mark_entry_dirty(oh) < 0)
875
0
                HGOTO_ERROR(H5E_OHDR, H5E_CANTMARKDIRTY, (-1), "unable to mark object header as dirty");
876
0
        } /* end if */
877
878
        /* Check for operations on refcount message */
879
0
        if (oh->version > H5O_VERSION_1) {
880
            /* Check if the object has a refcount message already */
881
0
            if (oh->has_refcount_msg) {
882
                /* Check for removing refcount message */
883
0
                if (oh->nlink <= 1) {
884
0
                    if (H5O__msg_remove_real(f, oh, H5O_MSG_REFCOUNT, H5O_ALL, NULL, NULL, true) < 0)
885
0
                        HGOTO_ERROR(H5E_OHDR, H5E_CANTDELETE, (-1), "unable to delete refcount message");
886
0
                    oh->has_refcount_msg = false;
887
0
                } /* end if */
888
                /* Update refcount message with new link count */
889
0
                else {
890
0
                    H5O_refcount_t refcount = oh->nlink;
891
892
0
                    if (H5O__msg_write_real(f, oh, H5O_MSG_REFCOUNT, H5O_MSG_FLAG_DONTSHARE, 0, &refcount) <
893
0
                        0)
894
0
                        HGOTO_ERROR(H5E_OHDR, H5E_CANTUPDATE, (-1), "unable to update refcount message");
895
0
                } /* end else */
896
0
            }     /* end if */
897
0
            else {
898
                /* Check for adding refcount message to object */
899
0
                if (oh->nlink > 1) {
900
0
                    H5O_refcount_t refcount = oh->nlink;
901
902
0
                    if (H5O__msg_append_real(f, oh, H5O_MSG_REFCOUNT, H5O_MSG_FLAG_DONTSHARE, 0, &refcount) <
903
0
                        0)
904
0
                        HGOTO_ERROR(H5E_OHDR, H5E_CANTINSERT, (-1), "unable to create new refcount message");
905
0
                    oh->has_refcount_msg = true;
906
0
                } /* end if */
907
0
            }     /* end else */
908
0
        }         /* end if */
909
0
    }             /* end if */
910
911
    /* Set return value */
912
0
    ret_value = (int)oh->nlink;
913
914
0
done:
915
0
    FUNC_LEAVE_NOAPI(ret_value)
916
0
} /* end H5O__link_oh() */
917
918
/*-------------------------------------------------------------------------
919
 * Function:    H5O_link
920
 *
921
 * Purpose:    Adjust the link count for an object header by adding
922
 *        ADJUST to the link count.
923
 *
924
 * Return:    Success:    New link count
925
 *
926
 *        Failure:    Negative
927
 *
928
 *-------------------------------------------------------------------------
929
 */
930
int
931
H5O_link(const H5O_loc_t *loc, int adjust)
932
0
{
933
0
    H5O_t *oh        = NULL;
934
0
    bool   deleted   = false; /* Whether the object was deleted */
935
0
    int    ret_value = -1;    /* Return value */
936
937
0
    FUNC_ENTER_NOAPI_TAG(loc->addr, FAIL)
938
939
    /* check args */
940
0
    assert(loc);
941
0
    assert(loc->file);
942
0
    assert(H5_addr_defined(loc->addr));
943
944
    /* Pin the object header */
945
0
    if (NULL == (oh = H5O_pin(loc)))
946
0
        HGOTO_ERROR(H5E_OHDR, H5E_CANTPIN, FAIL, "unable to pin object header");
947
948
    /* Call the "real" link routine */
949
0
    if ((ret_value = H5O__link_oh(loc->file, adjust, oh, &deleted)) < 0)
950
0
        HGOTO_ERROR(H5E_OHDR, H5E_LINKCOUNT, FAIL, "unable to adjust object link count");
951
952
0
done:
953
0
    if (oh && H5O_unpin(oh) < 0)
954
0
        HDONE_ERROR(H5E_OHDR, H5E_CANTUNPIN, FAIL, "unable to unpin object header");
955
0
    if (ret_value >= 0 && deleted && H5O_delete(loc->file, loc->addr) < 0)
956
0
        HDONE_ERROR(H5E_OHDR, H5E_CANTDELETE, FAIL, "can't delete object from file");
957
958
0
    FUNC_LEAVE_NOAPI_TAG(ret_value)
959
0
} /* end H5O_link() */
960
961
/*-------------------------------------------------------------------------
962
 * Function:    H5O_protect
963
 *
964
 * Purpose:    Wrapper around H5AC_protect for use during a H5O_protect->
965
 *              H5O_msg_append->...->H5O_msg_append->H5O_unprotect sequence of calls
966
 *              during an object's creation.
967
 *
968
 * Return:    Success:    Pointer to the object header structure for the
969
 *                              object.
970
 *        Failure:    NULL
971
 *
972
 *-------------------------------------------------------------------------
973
 */
974
H5O_t *
975
H5O_protect(const H5O_loc_t *loc, unsigned prot_flags, bool pin_all_chunks)
976
116k
{
977
116k
    H5O_t          *oh = NULL;        /* Object header protected */
978
116k
    H5O_cache_ud_t  udata;            /* User data for protecting object header */
979
116k
    H5O_cont_msgs_t cont_msg_info;    /* Continuation message info */
980
116k
    unsigned        file_intent;      /* R/W intent on file */
981
116k
    H5O_t          *ret_value = NULL; /* Return value */
982
983
116k
    FUNC_ENTER_NOAPI_TAG(loc->addr, NULL)
984
985
    /* check args */
986
116k
    assert(loc);
987
116k
    assert(loc->file);
988
989
    /* prot_flags may only contain the H5AC__READ_ONLY_FLAG */
990
116k
    assert((prot_flags & (unsigned)(~H5AC__READ_ONLY_FLAG)) == 0);
991
992
    /* Check for valid address */
993
116k
    if (!H5_addr_defined(loc->addr))
994
0
        HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, NULL, "address undefined");
995
996
    /* Check for write access on the file */
997
116k
    file_intent = H5F_INTENT(loc->file);
998
116k
    if ((0 == (prot_flags & H5AC__READ_ONLY_FLAG)) && (0 == (file_intent & H5F_ACC_RDWR)))
999
0
        HGOTO_ERROR(H5E_OHDR, H5E_BADVALUE, NULL, "no write intent on file");
1000
1001
    /* Construct the user data for protect callback */
1002
116k
    udata.made_attempt            = false;
1003
116k
    udata.v1_pfx_nmesgs           = 0;
1004
116k
    udata.chunk0_size             = 0;
1005
116k
    udata.oh                      = NULL;
1006
116k
    udata.oh_version              = 0;
1007
116k
    udata.common.f                = loc->file;
1008
116k
    udata.common.file_intent      = file_intent;
1009
116k
    udata.common.merged_null_msgs = 0;
1010
116k
    memset(&cont_msg_info, 0, sizeof(cont_msg_info));
1011
116k
    udata.common.cont_msg_info = &cont_msg_info;
1012
116k
    udata.common.addr          = loc->addr;
1013
1014
    /* Lock the object header into the cache */
1015
116k
    if (NULL == (oh = (H5O_t *)H5AC_protect(loc->file, H5AC_OHDR, loc->addr, &udata, prot_flags)))
1016
282
        HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, NULL, "unable to load object header");
1017
1018
    /* Check if there are any continuation messages to process */
1019
115k
    if (cont_msg_info.nmsgs > 0) {
1020
483
        size_t             curr_msg;  /* Current continuation message to process */
1021
483
        H5O_chk_cache_ud_t chk_udata; /* User data for loading chunk */
1022
1023
        /* Sanity check - we should only have continuation messages to process
1024
         *      when the object header is actually loaded from the file.
1025
         */
1026
483
        assert(udata.made_attempt == true);
1027
483
        assert(cont_msg_info.msgs);
1028
1029
        /* Construct the user data for protecting chunks */
1030
483
        chk_udata.decoding                = true;
1031
483
        chk_udata.oh                      = oh;
1032
483
        chk_udata.chunkno                 = UINT_MAX; /* Set to invalid value, for better error detection */
1033
483
        chk_udata.common.f                = loc->file;
1034
483
        chk_udata.common.file_intent      = file_intent;
1035
483
        chk_udata.common.merged_null_msgs = udata.common.merged_null_msgs;
1036
483
        chk_udata.common.cont_msg_info    = &cont_msg_info;
1037
1038
        /* Read in continuation messages, until there are no more */
1039
        /* (Note that loading chunks could increase the # of continuation
1040
         *      messages if new ones are found - QAK, 19/11/2016)
1041
         */
1042
483
        curr_msg = 0;
1043
1.04k
        while (curr_msg < cont_msg_info.nmsgs) {
1044
606
            H5O_chunk_proxy_t *chk_proxy;            /* Proxy for chunk, to bring it into memory */
1045
606
            unsigned           chunkno;              /* Chunk number for chunk proxy */
1046
606
            size_t             chkcnt = oh->nchunks; /* Count of chunks (for sanity checking) */
1047
1048
            /* Bring the chunk into the cache */
1049
            /* (which adds to the object header) */
1050
606
            chk_udata.common.addr = cont_msg_info.msgs[curr_msg].addr;
1051
606
            chk_udata.size        = cont_msg_info.msgs[curr_msg].size;
1052
606
            if (NULL == (chk_proxy = (H5O_chunk_proxy_t *)H5AC_protect(loc->file, H5AC_OHDR_CHK,
1053
606
                                                                       cont_msg_info.msgs[curr_msg].addr,
1054
606
                                                                       &chk_udata, prot_flags)))
1055
46
                HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, NULL, "unable to load object header chunk");
1056
1057
            /* Sanity check */
1058
606
            assert(chk_proxy->oh == oh);
1059
1060
560
            chunkno = chk_proxy->chunkno;
1061
1062
            /* Release the chunk from the cache */
1063
560
            if (H5AC_unprotect(loc->file, H5AC_OHDR_CHK, cont_msg_info.msgs[curr_msg].addr, chk_proxy,
1064
560
                               H5AC__NO_FLAGS_SET) < 0)
1065
0
                HGOTO_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, NULL, "unable to release object header chunk");
1066
1067
560
            if (chunkno != chkcnt)
1068
0
                HGOTO_ERROR(H5E_OHDR, H5E_BADVALUE, NULL, "incorrect chunk number for object header chunk");
1069
560
            if (oh->nchunks != (chkcnt + 1))
1070
0
                HGOTO_ERROR(H5E_OHDR, H5E_BADVALUE, NULL,
1071
560
                            "incorrect number of chunks after deserializing object header chunk");
1072
1073
            /* Advance to next continuation message */
1074
560
            curr_msg++;
1075
560
        } /* end while */
1076
1077
        /* Release any continuation messages built up */
1078
437
        cont_msg_info.msgs = (H5O_cont_t *)H5FL_SEQ_FREE(H5O_cont_t, cont_msg_info.msgs);
1079
1080
        /* Pass back out some of the chunk's user data */
1081
437
        udata.common.merged_null_msgs = chk_udata.common.merged_null_msgs;
1082
437
    } /* end if */
1083
1084
    /* Check for incorrect # of object header messages, if we've just loaded
1085
     *  this object header from the file
1086
     */
1087
115k
    if (udata.made_attempt) {
1088
/* Don't enforce the error on an incorrect # of object header messages bug
1089
 *      unless strict format checking is enabled.  This allows for older
1090
 *      files, created with a version of the library that had a bug in tracking
1091
 *      the correct # of header messages to be read in without the library
1092
 *      erroring out here. -QAK
1093
 */
1094
#ifdef H5_STRICT_FORMAT_CHECKS
1095
        /* Check for incorrect # of messages in v1 object header */
1096
        if (oh->version == H5O_VERSION_1 &&
1097
            (oh->nmesgs + udata.common.merged_null_msgs) != udata.v1_pfx_nmesgs)
1098
            HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, NULL, "corrupt object header - incorrect # of messages");
1099
#endif /* H5_STRICT_FORMAT_CHECKS */
1100
3.29k
    }  /* end if */
1101
1102
#ifdef H5O_DEBUG
1103
    H5O__assert(oh);
1104
#endif /* H5O_DEBUG */
1105
1106
    /* Pin the other chunks also when requested, so that the object header
1107
     *  proxy can be set up.
1108
     */
1109
115k
    if (pin_all_chunks && oh->nchunks > 1) {
1110
0
        unsigned u; /* Local index variable */
1111
1112
        /* Sanity check */
1113
0
        assert(oh->swmr_write);
1114
1115
        /* Iterate over chunks > 0 */
1116
0
        for (u = 1; u < oh->nchunks; u++) {
1117
0
            H5O_chunk_proxy_t *chk_proxy; /* Chunk proxy */
1118
1119
            /* Protect chunk */
1120
0
            if (NULL == (chk_proxy = H5O__chunk_protect(loc->file, oh, u)))
1121
0
                HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, NULL, "unable to protect object header chunk");
1122
1123
            /* Pin chunk proxy*/
1124
0
            if (H5AC_pin_protected_entry(chk_proxy) < 0)
1125
0
                HGOTO_ERROR(H5E_OHDR, H5E_CANTPIN, NULL, "unable to pin object header chunk");
1126
1127
            /* Unprotect chunk */
1128
0
            if (H5O__chunk_unprotect(loc->file, chk_proxy, false) < 0)
1129
0
                HGOTO_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, NULL, "unable to unprotect object header chunk");
1130
1131
            /* Preserve chunk proxy pointer for later */
1132
0
            oh->chunk[u].chunk_proxy = chk_proxy;
1133
0
        } /* end for */
1134
1135
        /* Set the flag for the unprotect */
1136
0
        oh->chunks_pinned = true;
1137
0
    } /* end if */
1138
1139
    /* Set return value */
1140
115k
    ret_value = oh;
1141
1142
116k
done:
1143
116k
    if (ret_value == NULL && oh) {
1144
        /* Release any continuation messages built up */
1145
46
        if (cont_msg_info.msgs)
1146
7
            cont_msg_info.msgs = (H5O_cont_t *)H5FL_SEQ_FREE(H5O_cont_t, cont_msg_info.msgs);
1147
1148
        /* Unprotect the ohdr and delete it from cache since if we failed to load it it's in an inconsistent
1149
         * state */
1150
46
        if (H5O_unprotect(loc, oh, H5AC__DELETED_FLAG) < 0)
1151
0
            HDONE_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, NULL, "unable to release object header");
1152
46
    }
1153
1154
116k
    FUNC_LEAVE_NOAPI_TAG(ret_value)
1155
116k
} /* end H5O_protect() */
1156
1157
/*-------------------------------------------------------------------------
1158
 * Function:    H5O_pin
1159
 *
1160
 * Purpose:    Pin an object header down for use during a sequence of message
1161
 *              operations, which prevents the object header from being
1162
 *              evicted from the cache.
1163
 *
1164
 * Return:    Success:    Pointer to the object header structure for the
1165
 *                              object.
1166
 *        Failure:    NULL
1167
 *
1168
 *-------------------------------------------------------------------------
1169
 */
1170
H5O_t *
1171
H5O_pin(const H5O_loc_t *loc)
1172
0
{
1173
0
    H5O_t *oh        = NULL; /* Object header */
1174
0
    H5O_t *ret_value = NULL; /* Return value */
1175
1176
0
    FUNC_ENTER_NOAPI(NULL)
1177
1178
    /* check args */
1179
0
    assert(loc);
1180
1181
    /* Get header */
1182
0
    if (NULL == (oh = H5O_protect(loc, H5AC__NO_FLAGS_SET, false)))
1183
0
        HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, NULL, "unable to protect object header");
1184
1185
    /* Increment the reference count on the object header */
1186
    /* (which will pin it, if appropriate) */
1187
0
    if (H5O__inc_rc(oh) < 0)
1188
0
        HGOTO_ERROR(H5E_OHDR, H5E_CANTINC, NULL, "unable to increment reference count on object header");
1189
1190
    /* Set the return value */
1191
0
    ret_value = oh;
1192
1193
0
done:
1194
    /* Release the object header from the cache */
1195
0
    if (oh && H5O_unprotect(loc, oh, H5AC__NO_FLAGS_SET) < 0)
1196
0
        HDONE_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, NULL, "unable to release object header");
1197
1198
0
    FUNC_LEAVE_NOAPI(ret_value)
1199
0
} /* end H5O_pin() */
1200
1201
/*-------------------------------------------------------------------------
1202
 * Function:    H5O_unpin
1203
 *
1204
 * Purpose:    Unpin an object header, allowing it to be evicted from the
1205
 *              metadata cache.
1206
 *
1207
 * Return:    Success:    Non-negative
1208
 *        Failure:    Negative
1209
 *
1210
 *-------------------------------------------------------------------------
1211
 */
1212
herr_t
1213
H5O_unpin(H5O_t *oh)
1214
0
{
1215
0
    herr_t ret_value = SUCCEED; /* Return value */
1216
1217
0
    FUNC_ENTER_NOAPI(FAIL)
1218
1219
    /* check args */
1220
0
    assert(oh);
1221
1222
    /* Decrement the reference count on the object header */
1223
    /* (which will unpin it, if appropriate) */
1224
0
    if (H5O__dec_rc(oh) < 0)
1225
0
        HGOTO_ERROR(H5E_OHDR, H5E_CANTDEC, FAIL, "unable to decrement reference count on object header");
1226
1227
0
done:
1228
0
    FUNC_LEAVE_NOAPI(ret_value)
1229
0
} /* end H5O_unpin() */
1230
1231
/*-------------------------------------------------------------------------
1232
 * Function:    H5O_unprotect
1233
 *
1234
 * Purpose:    Wrapper around H5AC_unprotect for use during a H5O_protect->
1235
 *              H5O_msg_append->...->H5O_msg_append->H5O_unprotect sequence of calls
1236
 *              during an object's creation.
1237
 *
1238
 * Return:    Success:    Non-negative
1239
 *        Failure:    Negative
1240
 *
1241
 *-------------------------------------------------------------------------
1242
 */
1243
herr_t
1244
H5O_unprotect(const H5O_loc_t *loc, H5O_t *oh, unsigned oh_flags)
1245
115k
{
1246
115k
    herr_t ret_value = SUCCEED; /* Return value */
1247
1248
115k
    FUNC_ENTER_NOAPI(FAIL)
1249
1250
    /* check args */
1251
115k
    assert(loc);
1252
115k
    assert(oh);
1253
1254
    /* Unpin the other chunks */
1255
115k
    if (oh->chunks_pinned && oh->nchunks > 1) {
1256
0
        unsigned u; /* Local index variable */
1257
1258
        /* Sanity check */
1259
0
        assert(oh->swmr_write);
1260
1261
        /* Iterate over chunks > 0 */
1262
0
        for (u = 1; u < oh->nchunks; u++) {
1263
0
            if (NULL != oh->chunk[u].chunk_proxy) {
1264
                /* Release chunk proxy */
1265
0
                if (H5AC_unpin_entry(oh->chunk[u].chunk_proxy) < 0)
1266
0
                    HGOTO_ERROR(H5E_OHDR, H5E_CANTUNPIN, FAIL, "unable to unpin object header chunk");
1267
0
                oh->chunk[u].chunk_proxy = NULL;
1268
0
            } /* end if */
1269
0
        }     /* end for */
1270
1271
        /* Reset the flag from the unprotect */
1272
0
        oh->chunks_pinned = false;
1273
0
    } /* end if */
1274
1275
    /* Remove the other chunks if we're removing the ohdr (due to a failure) */
1276
115k
    if (oh_flags & H5AC__DELETED_FLAG) {
1277
46
        unsigned u; /* Local index variable */
1278
1279
        /* Iterate over chunks > 0 */
1280
85
        for (u = 1; u < oh->nchunks; u++)
1281
            /* Expunge chunk proxy from cache */
1282
39
            if (H5AC_expunge_entry(loc->file, H5AC_OHDR_CHK, oh->chunk[u].addr, H5AC__NO_FLAGS_SET) < 0)
1283
0
                HGOTO_ERROR(H5E_OHDR, H5E_CANTUNPIN, FAIL, "unable to expunge object header chunk");
1284
46
    } /* end if */
1285
1286
    /* Unprotect the object header */
1287
115k
    if (H5AC_unprotect(loc->file, H5AC_OHDR, oh->chunk[0].addr, oh, oh_flags) < 0)
1288
0
        HGOTO_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, FAIL, "unable to release object header");
1289
1290
115k
done:
1291
115k
    FUNC_LEAVE_NOAPI(ret_value)
1292
115k
} /* end H5O_unprotect() */
1293
1294
/*-------------------------------------------------------------------------
1295
 * Function:    H5O_touch_oh
1296
 *
1297
 * Purpose:    If FORCE is non-zero then create a modification time message
1298
 *        unless one already exists.  Then update any existing
1299
 *        modification time message with the current time.
1300
 *
1301
 * Return:    Non-negative on success/Negative on failure
1302
 *
1303
 *-------------------------------------------------------------------------
1304
 */
1305
herr_t
1306
H5O_touch_oh(H5F_t *f, H5O_t *oh, bool force)
1307
0
{
1308
0
    H5O_chunk_proxy_t *chk_proxy   = NULL;  /* Chunk that message is in */
1309
0
    bool               chk_dirtied = false; /* Flag for unprotecting chunk */
1310
0
    time_t             now;                 /* Current time */
1311
0
    herr_t             ret_value = SUCCEED; /* Return value */
1312
1313
0
    FUNC_ENTER_NOAPI_NOINIT
1314
1315
0
    assert(f);
1316
0
    assert(oh);
1317
1318
    /* Check if this object header is tracking times */
1319
0
    if (oh->flags & H5O_HDR_STORE_TIMES) {
1320
        /* Get current time */
1321
0
        now = H5_now();
1322
1323
        /* Check version, to determine how to store time information */
1324
0
        if (oh->version == H5O_VERSION_1) {
1325
0
            size_t idx; /* Index of modification time message to update */
1326
1327
            /* Look for existing message */
1328
0
            for (idx = 0; idx < oh->nmesgs; idx++)
1329
0
                if (H5O_MSG_MTIME == oh->mesg[idx].type || H5O_MSG_MTIME_NEW == oh->mesg[idx].type)
1330
0
                    break;
1331
1332
            /* Create a new message, if necessary */
1333
0
            if (idx == oh->nmesgs) {
1334
0
                unsigned mesg_flags = 0; /* Flags for message in object header */
1335
1336
                /* If we would have to create a new message, but we aren't 'forcing' it, get out now */
1337
0
                if (!force)
1338
0
                    HGOTO_DONE(SUCCEED); /*nothing to do*/
1339
1340
                /* Allocate space for the modification time message */
1341
0
                if (H5O__msg_alloc(f, oh, H5O_MSG_MTIME_NEW, &mesg_flags, &now, &idx) < 0)
1342
0
                    HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, FAIL,
1343
0
                                "unable to allocate space for modification time message");
1344
1345
                /* Set the message's flags if appropriate */
1346
0
                oh->mesg[idx].flags = (uint8_t)mesg_flags;
1347
0
            } /* end if */
1348
1349
            /* Protect chunk */
1350
0
            if (NULL == (chk_proxy = H5O__chunk_protect(f, oh, oh->mesg[idx].chunkno)))
1351
0
                HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, FAIL, "unable to load object header chunk");
1352
1353
            /* Allocate 'native' space, if necessary */
1354
0
            if (NULL == oh->mesg[idx].native) {
1355
0
                if (NULL == (oh->mesg[idx].native = H5FL_MALLOC(time_t)))
1356
0
                    HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, FAIL,
1357
0
                                "memory allocation failed for modification time message");
1358
0
            } /* end if */
1359
1360
            /* Update the message */
1361
0
            *((time_t *)(oh->mesg[idx].native)) = now;
1362
1363
            /* Mark the message as dirty */
1364
0
            oh->mesg[idx].dirty = true;
1365
0
            chk_dirtied         = true;
1366
0
        } /* end if */
1367
0
        else {
1368
            /* XXX: For now, update access time & change fields in the object header
1369
             * (will need to add some code to update modification time appropriately)
1370
             */
1371
0
            oh->atime = oh->ctime = now;
1372
1373
            /* Mark object header as dirty in cache */
1374
0
            if (H5AC_mark_entry_dirty(oh) < 0)
1375
0
                HGOTO_ERROR(H5E_OHDR, H5E_CANTMARKDIRTY, FAIL, "unable to mark object header as dirty");
1376
0
        } /* end else */
1377
0
    }     /* end if */
1378
1379
0
done:
1380
    /* Release chunk */
1381
0
    if (chk_proxy && H5O__chunk_unprotect(f, chk_proxy, chk_dirtied) < 0)
1382
0
        HDONE_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, FAIL, "unable to unprotect object header chunk");
1383
1384
0
    FUNC_LEAVE_NOAPI(ret_value)
1385
0
} /* end H5O_touch_oh() */
1386
1387
/*-------------------------------------------------------------------------
1388
 * Function:    H5O_touch
1389
 *
1390
 * Purpose:    Touch an object by setting the modification time to the
1391
 *        current time and marking the object as dirty.  Unless FORCE
1392
 *        is non-zero, nothing happens if there is no MTIME message in
1393
 *        the object header.
1394
 *
1395
 * Return:    Non-negative on success/Negative on failure
1396
 *
1397
 *-------------------------------------------------------------------------
1398
 */
1399
herr_t
1400
H5O_touch(const H5O_loc_t *loc, bool force)
1401
0
{
1402
0
    H5O_t   *oh        = NULL;               /* Object header to modify */
1403
0
    unsigned oh_flags  = H5AC__NO_FLAGS_SET; /* Flags for unprotecting object header */
1404
0
    herr_t   ret_value = SUCCEED;            /* Return value */
1405
1406
0
    FUNC_ENTER_NOAPI(FAIL)
1407
1408
    /* check args */
1409
0
    assert(loc);
1410
1411
    /* Get the object header */
1412
0
    if (NULL == (oh = H5O_protect(loc, H5AC__NO_FLAGS_SET, false)))
1413
0
        HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, FAIL, "unable to load object header");
1414
1415
    /* Create/Update the modification time message */
1416
0
    if (H5O_touch_oh(loc->file, oh, force) < 0)
1417
0
        HGOTO_ERROR(H5E_OHDR, H5E_CANTSET, FAIL, "unable to update object modification time");
1418
1419
    /* Mark object header as changed */
1420
0
    oh_flags |= H5AC__DIRTIED_FLAG;
1421
1422
0
done:
1423
0
    if (oh && H5O_unprotect(loc, oh, oh_flags) < 0)
1424
0
        HDONE_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, FAIL, "unable to release object header");
1425
1426
0
    FUNC_LEAVE_NOAPI(ret_value)
1427
0
} /* end H5O_touch() */
1428
1429
#ifdef H5O_ENABLE_BOGUS
1430
1431
/*-------------------------------------------------------------------------
1432
 * Function:    H5O_bogus_oh
1433
 *
1434
 * Purpose:    Create a "bogus" message unless one already exists.
1435
 *
1436
 * Return:    Non-negative on success/Negative on failure
1437
 *
1438
 *-------------------------------------------------------------------------
1439
 */
1440
herr_t
1441
H5O_bogus_oh(H5F_t *f, H5O_t *oh, unsigned bogus_id, unsigned mesg_flags)
1442
{
1443
    size_t           idx;                 /* Local index variable */
1444
    H5O_msg_class_t *type;                /* Message class type */
1445
    herr_t           ret_value = SUCCEED; /* Return value */
1446
1447
    FUNC_ENTER_NOAPI(FAIL)
1448
1449
    assert(f);
1450
    assert(oh);
1451
1452
    /* Look for existing message */
1453
    for (idx = 0; idx < oh->nmesgs; idx++)
1454
        if (H5O_MSG_BOGUS_VALID == oh->mesg[idx].type || H5O_MSG_BOGUS_INVALID == oh->mesg[idx].type)
1455
            break;
1456
1457
    /* Create a new message */
1458
    if (idx == oh->nmesgs) {
1459
        H5O_bogus_t *bogus; /* Pointer to the bogus information */
1460
1461
        /* Allocate the native message in memory */
1462
        if (NULL == (bogus = H5MM_malloc(sizeof(H5O_bogus_t))))
1463
            HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, FAIL, "memory allocation failed for 'bogus' message");
1464
1465
        /* Update the native value */
1466
        bogus->u = H5O_BOGUS_VALUE;
1467
1468
        if (bogus_id == H5O_BOGUS_VALID_ID)
1469
            type = H5O_MSG_BOGUS_VALID;
1470
        else if (bogus_id == H5O_BOGUS_INVALID_ID)
1471
            type = H5O_MSG_BOGUS_INVALID;
1472
        else
1473
            HGOTO_ERROR(H5E_ID, H5E_BADID, FAIL, "invalid ID for 'bogus' message");
1474
1475
        /* Allocate space in the object header for bogus message */
1476
        if (H5O__msg_alloc(f, oh, type, &mesg_flags, bogus, &idx) < 0)
1477
            HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, FAIL, "unable to allocate space for 'bogus' message");
1478
1479
        /* Point to "bogus" information (take it over) */
1480
        oh->mesg[idx].native = bogus;
1481
1482
        /* Set the appropriate flags for the message */
1483
        oh->mesg[idx].flags = mesg_flags;
1484
1485
        /* Mark the message and object header as dirty */
1486
        oh->mesg[idx].dirty     = true;
1487
        oh->cache_info.is_dirty = true;
1488
    } /* end if */
1489
1490
done:
1491
    FUNC_LEAVE_NOAPI(ret_value)
1492
} /* end H5O_bogus_oh() */
1493
#endif /* H5O_ENABLE_BOGUS */
1494
1495
/*-------------------------------------------------------------------------
1496
 * Function:    H5O_delete
1497
 *
1498
 * Purpose:    Delete an object header from a file.  This frees the file
1499
 *              space used for the object header (and it's continuation blocks)
1500
 *              and also walks through each header message and asks it to
1501
 *              remove all the pieces of the file referenced by the header.
1502
 *
1503
 * Return:    Non-negative on success/Negative on failure
1504
 *
1505
 *-------------------------------------------------------------------------
1506
 */
1507
herr_t
1508
H5O_delete(H5F_t *f, haddr_t addr)
1509
0
{
1510
0
    H5O_t    *oh = NULL;                     /* Object header information */
1511
0
    H5O_loc_t loc;                           /* Object location for object to delete */
1512
0
    unsigned  oh_flags = H5AC__NO_FLAGS_SET; /* Flags for unprotecting object header */
1513
0
    bool      corked;
1514
0
    herr_t    ret_value = SUCCEED; /* Return value */
1515
1516
0
    FUNC_ENTER_NOAPI_TAG(addr, FAIL)
1517
1518
    /* Check args */
1519
0
    assert(f);
1520
0
    assert(H5_addr_defined(addr));
1521
1522
    /* Set up the object location */
1523
0
    loc.file         = f;
1524
0
    loc.addr         = addr;
1525
0
    loc.holding_file = false;
1526
1527
    /* Get the object header information */
1528
0
    if (NULL == (oh = H5O_protect(&loc, H5AC__NO_FLAGS_SET, false)))
1529
0
        HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, FAIL, "unable to load object header");
1530
1531
    /* Delete object */
1532
0
    if (H5O__delete_oh(f, oh) < 0)
1533
0
        HGOTO_ERROR(H5E_OHDR, H5E_CANTDELETE, FAIL, "can't delete object from file");
1534
1535
    /* Uncork cache entries with tag: addr */
1536
0
    if (H5AC_cork(f, addr, H5AC__GET_CORKED, &corked) < 0)
1537
0
        HGOTO_ERROR(H5E_OHDR, H5E_CANTGET, FAIL, "unable to retrieve an object's cork status");
1538
0
    if (corked)
1539
0
        if (H5AC_cork(f, addr, H5AC__UNCORK, NULL) < 0)
1540
0
            HGOTO_ERROR(H5E_OHDR, H5E_CANTUNCORK, FAIL, "unable to uncork an object");
1541
1542
    /* Mark object header as deleted */
1543
0
    oh_flags = H5AC__DIRTIED_FLAG | H5AC__DELETED_FLAG | H5AC__FREE_FILE_SPACE_FLAG;
1544
1545
0
done:
1546
0
    if (oh && H5O_unprotect(&loc, oh, oh_flags) < 0)
1547
0
        HDONE_ERROR(H5E_OHDR, H5E_PROTECT, FAIL, "unable to release object header");
1548
1549
0
    FUNC_LEAVE_NOAPI_TAG(ret_value)
1550
0
} /* end H5O_delete() */
1551
1552
/*-------------------------------------------------------------------------
1553
 * Function:    H5O__delete_oh
1554
 *
1555
 * Purpose:    Internal function to:
1556
 *              Delete an object header from a file.  This frees the file
1557
 *              space used for the object header (and it's continuation blocks)
1558
 *              and also walks through each header message and asks it to
1559
 *              remove all the pieces of the file referenced by the header.
1560
 *
1561
 * Return:    Non-negative on success/Negative on failure
1562
 *
1563
 *-------------------------------------------------------------------------
1564
 */
1565
static herr_t
1566
H5O__delete_oh(H5F_t *f, H5O_t *oh)
1567
0
{
1568
0
    H5O_mesg_t *curr_msg; /* Pointer to current message being operated on */
1569
0
    unsigned    u;
1570
0
    herr_t      ret_value = SUCCEED; /* Return value */
1571
1572
0
    FUNC_ENTER_PACKAGE
1573
1574
    /* Check args */
1575
0
    assert(f);
1576
0
    assert(oh);
1577
1578
    /* Walk through the list of object header messages, asking each one to
1579
     * delete any file space used
1580
     */
1581
0
    for (u = 0, curr_msg = &oh->mesg[0]; u < oh->nmesgs; u++, curr_msg++) {
1582
        /* Free any space referred to in the file from this message */
1583
0
        if (H5O__delete_mesg(f, oh, curr_msg) < 0)
1584
0
            HGOTO_ERROR(H5E_OHDR, H5E_CANTDELETE, FAIL,
1585
0
                        "unable to delete file space for object header message");
1586
0
    } /* end for */
1587
1588
0
done:
1589
0
    FUNC_LEAVE_NOAPI(ret_value)
1590
0
} /* end H5O__delete_oh() */
1591
1592
/*-------------------------------------------------------------------------
1593
 * Function:    H5O_obj_type
1594
 *
1595
 * Purpose:    Retrieves the type of object pointed to by `loc'.
1596
 *
1597
 * Return:    Success:    Non-negative
1598
 *        Failure:    Negative
1599
 *
1600
 *-------------------------------------------------------------------------
1601
 */
1602
herr_t
1603
H5O_obj_type(const H5O_loc_t *loc, H5O_type_t *obj_type)
1604
7.79k
{
1605
7.79k
    H5O_t *oh        = NULL;    /* Object header for location */
1606
7.79k
    herr_t ret_value = SUCCEED; /* Return value */
1607
1608
7.79k
    FUNC_ENTER_NOAPI_TAG(loc->addr, FAIL)
1609
1610
    /* Load the object header */
1611
7.79k
    if (NULL == (oh = H5O_protect(loc, H5AC__READ_ONLY_FLAG, false)))
1612
124
        HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, FAIL, "unable to load object header");
1613
1614
    /* Retrieve the type of the object */
1615
7.66k
    if (H5O__obj_type_real(oh, obj_type) < 0)
1616
0
        HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, FAIL, "unable to determine object type");
1617
1618
7.79k
done:
1619
7.79k
    if (oh && H5O_unprotect(loc, oh, H5AC__NO_FLAGS_SET) < 0)
1620
0
        HDONE_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, FAIL, "unable to release object header");
1621
1622
7.79k
    FUNC_LEAVE_NOAPI_TAG(ret_value)
1623
7.79k
} /* end H5O_obj_type() */
1624
1625
/*-------------------------------------------------------------------------
1626
 * Function:    H5O__obj_type_real
1627
 *
1628
 * Purpose:     On success, returns the type of object pointed to by `oh' or
1629
 *              NULL in *obj_type.  *obj_type not defined on failure.
1630
 *
1631
 * Return:      Success:    Non-negative
1632
 *              Failure:    Negative
1633
 *
1634
 *-------------------------------------------------------------------------
1635
 */
1636
static herr_t
1637
H5O__obj_type_real(const H5O_t *oh, H5O_type_t *obj_type)
1638
12.1k
{
1639
12.1k
    const H5O_obj_class_t *obj_class = NULL; /* Class of object for header */
1640
12.1k
    herr_t                 ret_value = SUCCEED;
1641
1642
12.1k
    FUNC_ENTER_PACKAGE
1643
1644
    /* Sanity check */
1645
12.1k
    assert(oh);
1646
12.1k
    assert(obj_type);
1647
1648
    /* Look up class for object header */
1649
12.1k
    if (H5O__obj_class_real(oh, &obj_class) < 0)
1650
1
        HGOTO_ERROR(H5E_OHDR, H5E_CANTGET, FAIL, "unable to determine object class");
1651
12.1k
    assert(obj_class);
1652
1653
    /* Set object type */
1654
12.1k
    *obj_type = obj_class->type;
1655
1656
12.1k
done:
1657
12.1k
    FUNC_LEAVE_NOAPI(ret_value)
1658
12.1k
} /* end H5O__obj_type_real() */
1659
1660
/*-------------------------------------------------------------------------
1661
 * Function:    H5O__obj_class
1662
 *
1663
 * Purpose:     Returns the class of object pointed to by 'loc'.
1664
 *
1665
 * Return:      Success:    An object class
1666
 *              Failure:    NULL
1667
 *
1668
 *-------------------------------------------------------------------------
1669
 */
1670
const H5O_obj_class_t *
1671
H5O__obj_class(const H5O_loc_t *loc)
1672
1.33k
{
1673
1.33k
    H5O_t                 *oh        = NULL; /* Object header for location */
1674
1.33k
    const H5O_obj_class_t *ret_value = NULL; /* Return value */
1675
1676
1.33k
    FUNC_ENTER_PACKAGE_TAG(loc->addr)
1677
1678
    /* Load the object header */
1679
1.33k
    if (NULL == (oh = H5O_protect(loc, H5AC__READ_ONLY_FLAG, false)))
1680
12
        HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, NULL, "unable to load object header");
1681
1682
    /* Test whether entry qualifies as a particular type of object */
1683
1.32k
    if (H5O__obj_class_real(oh, &ret_value) < 0)
1684
0
        HGOTO_ERROR(H5E_OHDR, H5E_CANTGET, NULL, "unable to determine object type");
1685
1686
1.33k
done:
1687
1.33k
    if (oh && H5O_unprotect(loc, oh, H5AC__NO_FLAGS_SET) < 0)
1688
0
        HDONE_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, NULL, "unable to release object header");
1689
1690
1.33k
    FUNC_LEAVE_NOAPI_TAG(ret_value)
1691
1.33k
} /* end H5O__obj_class() */
1692
1693
/*-------------------------------------------------------------------------
1694
 * Function:    H5O__obj_class_real
1695
 *
1696
 * Purpose:     On success returns the class of object pointed to by `oh' or
1697
 *              NULL in *cls.  *cls not defined on failure.
1698
 *
1699
 * Return:      Success:    Non-negative
1700
 *              Failure:    Negative
1701
 *
1702
 *-------------------------------------------------------------------------
1703
 */
1704
static herr_t
1705
H5O__obj_class_real(const H5O_t *oh, const H5O_obj_class_t **cls)
1706
13.4k
{
1707
13.4k
    size_t i; /* Local index variable */
1708
13.4k
    herr_t ret_value = SUCCEED;
1709
1710
13.4k
    FUNC_ENTER_PACKAGE
1711
1712
    /* Sanity check */
1713
13.4k
    assert(oh);
1714
13.4k
    assert(cls);
1715
1716
    /* Test whether entry qualifies as a particular type of object */
1717
    /* (Note: loop is in reverse order, to test specific objects first) */
1718
23.6k
    for (i = NELMTS(H5O_obj_class_g); i > 0; --i) {
1719
23.6k
        htri_t isa; /* Is entry a particular type? */
1720
1721
23.6k
        if ((isa = (H5O_obj_class_g[i - 1]->isa)(oh)) < 0)
1722
0
            HGOTO_ERROR(H5E_OHDR, H5E_CANTGET, FAIL, "unable to determine object type");
1723
23.6k
        else if (isa) {
1724
13.4k
            *cls = H5O_obj_class_g[i - 1];
1725
13.4k
            break;
1726
13.4k
        }
1727
23.6k
    }
1728
1729
13.4k
    if (0 == i)
1730
1
        HGOTO_ERROR(H5E_OHDR, H5E_CANTGET, FAIL, "unable to determine object type");
1731
1732
13.4k
done:
1733
13.4k
    FUNC_LEAVE_NOAPI(ret_value)
1734
13.4k
} /* end H5O__obj_class_real() */
1735
1736
/*-------------------------------------------------------------------------
1737
 * Function:    H5O_get_loc
1738
 *
1739
 * Purpose:    Gets the object location for an object given its ID.
1740
 *
1741
 * Return:    Success:    Pointer to H5O_loc_t
1742
 *        Failure:    NULL
1743
 *
1744
 *-------------------------------------------------------------------------
1745
 */
1746
H5O_loc_t *
1747
H5O_get_loc(hid_t object_id)
1748
0
{
1749
0
    H5O_loc_t *ret_value = NULL; /* Return value */
1750
1751
0
    FUNC_ENTER_NOAPI_NOINIT
1752
1753
0
    switch (H5I_get_type(object_id)) {
1754
0
        case H5I_GROUP:
1755
0
            if (NULL == (ret_value = H5O_OBJ_GROUP->get_oloc(object_id)))
1756
0
                HGOTO_ERROR(H5E_OHDR, H5E_CANTGET, NULL, "unable to get object location from group ID");
1757
0
            break;
1758
1759
0
        case H5I_DATASET:
1760
0
            if (NULL == (ret_value = H5O_OBJ_DATASET->get_oloc(object_id)))
1761
0
                HGOTO_ERROR(H5E_OHDR, H5E_CANTGET, NULL, "unable to get object location from dataset ID");
1762
0
            break;
1763
1764
0
        case H5I_DATATYPE:
1765
0
            if (NULL == (ret_value = H5O_OBJ_DATATYPE->get_oloc(object_id)))
1766
0
                HGOTO_ERROR(H5E_OHDR, H5E_CANTGET, NULL, "unable to get object location from datatype ID");
1767
0
            break;
1768
1769
0
        case H5I_MAP:
1770
0
            HGOTO_ERROR(H5E_OHDR, H5E_BADTYPE, NULL, "maps not supported in native VOL connector");
1771
1772
0
        case H5I_UNINIT:
1773
0
        case H5I_BADID:
1774
0
        case H5I_FILE:
1775
0
        case H5I_DATASPACE:
1776
0
        case H5I_ATTR:
1777
0
        case H5I_VFL:
1778
0
        case H5I_VOL:
1779
0
        case H5I_GENPROP_CLS:
1780
0
        case H5I_GENPROP_LST:
1781
0
        case H5I_ERROR_CLASS:
1782
0
        case H5I_ERROR_MSG:
1783
0
        case H5I_ERROR_STACK:
1784
0
        case H5I_SPACE_SEL_ITER:
1785
0
        case H5I_EVENTSET:
1786
0
        case H5I_NTYPES:
1787
0
        default:
1788
0
            HGOTO_ERROR(H5E_OHDR, H5E_BADTYPE, NULL, "invalid object type");
1789
0
    } /* end switch */
1790
1791
0
done:
1792
0
    FUNC_LEAVE_NOAPI(ret_value)
1793
0
} /* end H5O_get_loc() */
1794
1795
/*-------------------------------------------------------------------------
1796
 * Function:    H5O_loc_reset
1797
 *
1798
 * Purpose:    Reset a object location to an empty state
1799
 *
1800
 * Return:    Success:    Non-negative
1801
 *        Failure:    Negative
1802
 *
1803
 *-------------------------------------------------------------------------
1804
 */
1805
herr_t
1806
H5O_loc_reset(H5O_loc_t *loc)
1807
128k
{
1808
128k
    FUNC_ENTER_NOAPI_NOINIT_NOERR
1809
1810
    /* Check arguments */
1811
128k
    assert(loc);
1812
1813
    /* Clear the object location to an empty state */
1814
128k
    memset(loc, 0, sizeof(H5O_loc_t));
1815
128k
    loc->addr = HADDR_UNDEF;
1816
1817
128k
    FUNC_LEAVE_NOAPI(SUCCEED)
1818
128k
} /* end H5O_loc_reset() */
1819
1820
/*-------------------------------------------------------------------------
1821
 * Function:    H5O_loc_copy
1822
 *
1823
 * Purpose:     Copy object location information, according to the depth.
1824
 *
1825
 * Return:    Success:    Non-negative
1826
 *            Failure:    Negative
1827
 *
1828
 *-------------------------------------------------------------------------
1829
 */
1830
herr_t
1831
H5O_loc_copy(H5O_loc_t *dst, H5O_loc_t *src, H5_copy_depth_t depth)
1832
62.6k
{
1833
62.6k
    FUNC_ENTER_NOAPI_NOINIT_NOERR
1834
1835
    /* Check arguments */
1836
62.6k
    assert(src);
1837
62.6k
    assert(dst);
1838
62.6k
    assert(depth == H5_COPY_SHALLOW || depth == H5_COPY_DEEP);
1839
1840
    /* Invoke correct routine */
1841
62.6k
    if (depth == H5_COPY_SHALLOW)
1842
27.0k
        H5O_loc_copy_shallow(dst, src);
1843
35.6k
    else
1844
35.6k
        H5O_loc_copy_deep(dst, src);
1845
1846
62.6k
    FUNC_LEAVE_NOAPI(SUCCEED)
1847
62.6k
} /* end H5O_loc_copy() */
1848
1849
/*-------------------------------------------------------------------------
1850
 * Function:    H5O_loc_copy_shallow
1851
 *
1852
 * Purpose:     Shallow copy object location information.  Copies all the field
1853
 *              values from the source to the destination, but not copying
1854
 *              objects pointed to.  (i.e. destination "takes ownership" of
1855
 *              objects pointed to)
1856
 *
1857
 * Return:    Success:    Non-negative
1858
 *            Failure:    Negative
1859
 *
1860
 *-------------------------------------------------------------------------
1861
 */
1862
herr_t
1863
H5O_loc_copy_shallow(H5O_loc_t *dst, H5O_loc_t *src)
1864
36.0k
{
1865
36.0k
    FUNC_ENTER_NOAPI_NOINIT_NOERR
1866
1867
    /* Check arguments */
1868
36.0k
    assert(src);
1869
36.0k
    assert(dst);
1870
1871
    /* Copy the top level information */
1872
36.0k
    H5MM_memcpy(dst, src, sizeof(H5O_loc_t));
1873
1874
    /* Reset the source location, as the destination 'owns' it now */
1875
36.0k
    H5O_loc_reset(src);
1876
1877
36.0k
    FUNC_LEAVE_NOAPI(SUCCEED)
1878
36.0k
} /* end H5O_loc_copy_shallow() */
1879
1880
/*-------------------------------------------------------------------------
1881
 * Function:    H5O_loc_copy_deep
1882
 *
1883
 * Purpose:     Deep copy object location information.  Copies all the fields
1884
 *              from the source to the destination, deep copying objects
1885
 *              pointed to.
1886
 *
1887
 * Return:    Success:    Non-negative
1888
 *            Failure:    Negative
1889
 *
1890
 *-------------------------------------------------------------------------
1891
 */
1892
herr_t
1893
H5O_loc_copy_deep(H5O_loc_t *dst, const H5O_loc_t *src)
1894
42.7k
{
1895
42.7k
    FUNC_ENTER_NOAPI_NOINIT_NOERR
1896
1897
    /* Check arguments */
1898
42.7k
    assert(src);
1899
42.7k
    assert(dst);
1900
1901
    /* Copy the top level information */
1902
42.7k
    H5MM_memcpy(dst, src, sizeof(H5O_loc_t));
1903
1904
    /* If the original entry was holding open the file, this one should
1905
     * hold it open, too.
1906
     */
1907
42.7k
    if (src->holding_file)
1908
0
        H5F_INCR_NOPEN_OBJS(dst->file);
1909
1910
42.7k
    FUNC_LEAVE_NOAPI(SUCCEED)
1911
42.7k
} /* end H5O_loc_copy_deep() */
1912
1913
/*-------------------------------------------------------------------------
1914
 * Function:    H5O_loc_hold_file
1915
 *
1916
 * Purpose:    Have this object header hold a file open until it is
1917
 *              released.
1918
 *
1919
 * Return:    Success:    Non-negative
1920
 *        Failure:    Negative
1921
 *
1922
 *-------------------------------------------------------------------------
1923
 */
1924
herr_t
1925
H5O_loc_hold_file(H5O_loc_t *loc)
1926
0
{
1927
0
    FUNC_ENTER_NOAPI_NOINIT_NOERR
1928
1929
    /* Check arguments */
1930
0
    assert(loc);
1931
0
    assert(loc->file);
1932
1933
    /* If this location is not already holding its file open, do so. */
1934
0
    if (!loc->holding_file) {
1935
0
        H5F_INCR_NOPEN_OBJS(loc->file);
1936
0
        loc->holding_file = true;
1937
0
    }
1938
1939
0
    FUNC_LEAVE_NOAPI(SUCCEED)
1940
0
} /* end H5O_loc_hold_file() */
1941
1942
/*-------------------------------------------------------------------------
1943
 * Function:    H5O_loc_free
1944
 *
1945
 * Purpose:    Release resources used by this object header location.
1946
 *              Not to be confused with H5O_close; this is used on
1947
 *              locations that don't correspond to open objects.
1948
 *
1949
 * Return:    Success:    Non-negative
1950
 *        Failure:    Negative
1951
 *
1952
 *-------------------------------------------------------------------------
1953
 */
1954
herr_t
1955
H5O_loc_free(H5O_loc_t *loc)
1956
55.6k
{
1957
55.6k
    herr_t ret_value = SUCCEED;
1958
1959
55.6k
    FUNC_ENTER_NOAPI_NOINIT
1960
1961
    /* Check arguments */
1962
55.6k
    assert(loc);
1963
1964
    /* If this location is holding its file open try to close the file. */
1965
55.6k
    if (loc->holding_file) {
1966
0
        H5F_DECR_NOPEN_OBJS(loc->file);
1967
0
        loc->holding_file = false;
1968
0
        if (H5F_NOPEN_OBJS(loc->file) <= 0) {
1969
0
            if (H5F_try_close(loc->file, NULL) < 0)
1970
0
                HGOTO_ERROR(H5E_FILE, H5E_CANTCLOSEFILE, FAIL, "can't close file");
1971
0
        }
1972
0
    }
1973
1974
55.6k
done:
1975
55.6k
    FUNC_LEAVE_NOAPI(ret_value)
1976
55.6k
} /* end H5O_loc_free() */
1977
1978
/*-------------------------------------------------------------------------
1979
 * Function:    H5O_get_hdr_info
1980
 *
1981
 * Purpose:    Retrieve the object header information for an object
1982
 *
1983
 * Return:    Success:    Non-negative
1984
 *        Failure:    Negative
1985
 *
1986
 *-------------------------------------------------------------------------
1987
 */
1988
herr_t
1989
H5O_get_hdr_info(const H5O_loc_t *loc, H5O_hdr_info_t *hdr)
1990
0
{
1991
0
    H5O_t *oh        = NULL;    /* Object header */
1992
0
    herr_t ret_value = SUCCEED; /* Return value */
1993
1994
0
    FUNC_ENTER_NOAPI(FAIL)
1995
1996
    /* Check args */
1997
0
    assert(loc);
1998
0
    assert(hdr);
1999
2000
    /* Reset the object header info structure */
2001
0
    memset(hdr, 0, sizeof(*hdr));
2002
2003
    /* Get the object header */
2004
0
    if (NULL == (oh = H5O_protect(loc, H5AC__READ_ONLY_FLAG, false)))
2005
0
        HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, FAIL, "unable to load object header");
2006
2007
    /* Get the information for the object header */
2008
0
    if (H5O__get_hdr_info_real(oh, hdr) < 0)
2009
0
        HGOTO_ERROR(H5E_OHDR, H5E_CANTGET, FAIL, "can't retrieve object header info");
2010
2011
0
done:
2012
0
    if (oh && H5O_unprotect(loc, oh, H5AC__NO_FLAGS_SET) < 0)
2013
0
        HDONE_ERROR(H5E_OHDR, H5E_PROTECT, FAIL, "unable to release object header");
2014
2015
0
    FUNC_LEAVE_NOAPI(ret_value)
2016
0
} /* end H5O_get_hdr_info() */
2017
2018
/*-------------------------------------------------------------------------
2019
 * Function:    H5O__get_hdr_info_real
2020
 *
2021
 * Purpose:    Internal routine to retrieve the object header information for an object
2022
 *
2023
 * Return:    Success:    Non-negative
2024
 *        Failure:    Negative
2025
 *
2026
 *-------------------------------------------------------------------------
2027
 */
2028
static herr_t
2029
H5O__get_hdr_info_real(const H5O_t *oh, H5O_hdr_info_t *hdr)
2030
0
{
2031
0
    const H5O_mesg_t  *curr_msg;   /* Pointer to current message being operated on */
2032
0
    const H5O_chunk_t *curr_chunk; /* Pointer to current message being operated on */
2033
0
    unsigned           u;          /* Local index variable */
2034
2035
0
    FUNC_ENTER_PACKAGE_NOERR
2036
2037
    /* Check args */
2038
0
    assert(oh);
2039
0
    assert(hdr);
2040
2041
    /* Set the version for the object header */
2042
0
    hdr->version = oh->version;
2043
2044
    /* Set the number of messages & chunks */
2045
0
    H5_CHECKED_ASSIGN(hdr->nmesgs, unsigned, oh->nmesgs, size_t);
2046
0
    H5_CHECKED_ASSIGN(hdr->nchunks, unsigned, oh->nchunks, size_t);
2047
2048
    /* Set the status flags */
2049
0
    hdr->flags = oh->flags;
2050
2051
    /* Iterate over all the messages, accumulating message size & type information */
2052
0
    hdr->space.meta   = (hsize_t)H5O_SIZEOF_HDR(oh) + (hsize_t)(H5O_SIZEOF_CHKHDR_OH(oh) * (oh->nchunks - 1));
2053
0
    hdr->space.mesg   = 0;
2054
0
    hdr->space.free   = 0;
2055
0
    hdr->mesg.present = 0;
2056
0
    hdr->mesg.shared  = 0;
2057
0
    for (u = 0, curr_msg = &oh->mesg[0]; u < oh->nmesgs; u++, curr_msg++) {
2058
0
        uint64_t type_flag; /* Flag for message type */
2059
2060
        /* Accumulate space usage information, based on the type of message */
2061
0
        if (H5O_NULL_ID == curr_msg->type->id)
2062
0
            hdr->space.free += (hsize_t)((size_t)H5O_SIZEOF_MSGHDR_OH(oh) + curr_msg->raw_size);
2063
0
        else if (H5O_CONT_ID == curr_msg->type->id)
2064
0
            hdr->space.meta += (hsize_t)((size_t)H5O_SIZEOF_MSGHDR_OH(oh) + curr_msg->raw_size);
2065
0
        else {
2066
0
            hdr->space.meta += (hsize_t)H5O_SIZEOF_MSGHDR_OH(oh);
2067
0
            hdr->space.mesg += curr_msg->raw_size;
2068
0
        } /* end else */
2069
2070
        /* Set flag to indicate presence of message type */
2071
0
        type_flag = ((uint64_t)1) << curr_msg->type->id;
2072
0
        hdr->mesg.present |= type_flag;
2073
2074
        /* Set flag if the message is shared in some way */
2075
0
        if (curr_msg->flags & H5O_MSG_FLAG_SHARED)
2076
0
            hdr->mesg.shared |= type_flag;
2077
0
    } /* end for */
2078
2079
    /* Iterate over all the chunks, adding any gaps to the free space */
2080
0
    hdr->space.total = 0;
2081
0
    for (u = 0, curr_chunk = &oh->chunk[0]; u < oh->nchunks; u++, curr_chunk++) {
2082
        /* Accumulate the size of the header on disk */
2083
0
        hdr->space.total += curr_chunk->size;
2084
2085
        /* If the chunk has a gap, add it to the free space */
2086
0
        hdr->space.free += curr_chunk->gap;
2087
0
    } /* end for */
2088
2089
    /* Sanity check that all the bytes are accounted for */
2090
0
    assert(hdr->space.total == (hdr->space.free + hdr->space.meta + hdr->space.mesg));
2091
2092
0
    FUNC_LEAVE_NOAPI(SUCCEED)
2093
0
} /* end H5O__get_hdr_info_real() */
2094
2095
/*-------------------------------------------------------------------------
2096
 * Function:    H5O_get_info
2097
 *
2098
 * Purpose:     Retrieve the data model information for an object
2099
 *
2100
 * Return:      Success:    Non-negative
2101
 *              Failure:    Negative
2102
 *
2103
 *-------------------------------------------------------------------------
2104
 */
2105
herr_t
2106
H5O_get_info(const H5O_loc_t *loc, H5O_info2_t *oinfo, unsigned fields)
2107
4.67k
{
2108
4.67k
    H5O_t *oh        = NULL;    /* Object header */
2109
4.67k
    herr_t ret_value = SUCCEED; /* Return value */
2110
2111
4.67k
    FUNC_ENTER_NOAPI_TAG(loc->addr, FAIL)
2112
2113
    /* Check args */
2114
4.67k
    assert(loc);
2115
4.67k
    assert(oinfo);
2116
2117
    /* Get the object header */
2118
4.67k
    if (NULL == (oh = H5O_protect(loc, H5AC__READ_ONLY_FLAG, false)))
2119
192
        HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, FAIL, "unable to load object header");
2120
2121
    /* Reset the object info structure */
2122
4.48k
    if (H5O__reset_info2(oinfo) < 0)
2123
0
        HGOTO_ERROR(H5E_OHDR, H5E_CANTSET, FAIL, "can't reset object data struct");
2124
2125
    /* Get basic information, if requested */
2126
4.48k
    if (fields & H5O_INFO_BASIC) {
2127
4.48k
        H5O_type_t obj_type = H5O_TYPE_UNKNOWN; /* Type of object */
2128
2129
        /* Retrieve the file's fileno */
2130
4.48k
        H5F_GET_FILENO(loc->file, oinfo->fileno);
2131
2132
        /* Set the object's address into the token */
2133
4.48k
        if (H5VL_native_addr_to_token(loc->file, H5I_FILE, loc->addr, &oinfo->token) < 0)
2134
0
            HGOTO_ERROR(H5E_OHDR, H5E_CANTSERIALIZE, FAIL, "can't serialize address into object token");
2135
2136
        /* Get type of object */
2137
4.48k
        if (H5O__obj_type_real(oh, &obj_type) < 0)
2138
1
            HGOTO_ERROR(H5E_OHDR, H5E_CANTGET, FAIL, "unable to determine object type");
2139
2140
        /* Set the type of the object */
2141
4.48k
        oinfo->type = obj_type;
2142
2143
        /* Set the object's reference count */
2144
4.48k
        oinfo->rc = oh->nlink;
2145
4.48k
    }
2146
2147
    /* Get time information, if requested */
2148
4.48k
    if (fields & H5O_INFO_TIME) {
2149
0
        if (oh->version > H5O_VERSION_1) {
2150
0
            oinfo->atime = oh->atime;
2151
0
            oinfo->mtime = oh->mtime;
2152
0
            oinfo->ctime = oh->ctime;
2153
0
            oinfo->btime = oh->btime;
2154
0
        } /* end if */
2155
0
        else {
2156
0
            htri_t exists; /* Flag if header message of interest exists */
2157
2158
            /* No information for access & modification fields */
2159
            /* (we stopped updating the "modification time" header message for
2160
             *      raw data changes, so the "modification time" header message
2161
             *      is closest to the 'change time', in POSIX terms - QAK)
2162
             */
2163
0
            oinfo->atime = 0;
2164
0
            oinfo->mtime = 0;
2165
0
            oinfo->btime = 0;
2166
2167
            /* Might be information for modification time */
2168
0
            if ((exists = H5O_msg_exists_oh(oh, H5O_MTIME_ID)) < 0)
2169
0
                HGOTO_ERROR(H5E_OHDR, H5E_NOTFOUND, FAIL, "unable to check for MTIME message");
2170
0
            if (exists > 0) {
2171
                /* Get "old style" modification time info */
2172
0
                if (NULL == H5O_msg_read_oh(loc->file, oh, H5O_MTIME_ID, &oinfo->ctime))
2173
0
                    HGOTO_ERROR(H5E_OHDR, H5E_CANTGET, FAIL, "can't read MTIME message");
2174
0
            } /* end if */
2175
0
            else {
2176
                /* Check for "new style" modification time info */
2177
0
                if ((exists = H5O_msg_exists_oh(oh, H5O_MTIME_NEW_ID)) < 0)
2178
0
                    HGOTO_ERROR(H5E_OHDR, H5E_NOTFOUND, FAIL, "unable to check for MTIME_NEW message");
2179
0
                if (exists > 0) {
2180
                    /* Get "new style" modification time info */
2181
0
                    if (NULL == H5O_msg_read_oh(loc->file, oh, H5O_MTIME_NEW_ID, &oinfo->ctime))
2182
0
                        HGOTO_ERROR(H5E_OHDR, H5E_CANTGET, FAIL, "can't read MTIME_NEW message");
2183
0
                } /* end if */
2184
0
                else
2185
0
                    oinfo->ctime = 0;
2186
0
            } /* end else */
2187
0
        }     /* end else */
2188
0
    }         /* end if */
2189
2190
    /* Retrieve # of attributes */
2191
4.48k
    if (fields & H5O_INFO_NUM_ATTRS)
2192
0
        if (H5O__attr_count_real(loc->file, oh, &oinfo->num_attrs) < 0)
2193
0
            HGOTO_ERROR(H5E_OHDR, H5E_CANTGET, FAIL, "can't retrieve attribute count");
2194
2195
4.67k
done:
2196
4.67k
    if (oh && H5O_unprotect(loc, oh, H5AC__NO_FLAGS_SET) < 0)
2197
0
        HDONE_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, FAIL, "unable to release object header");
2198
2199
4.67k
    FUNC_LEAVE_NOAPI_TAG(ret_value)
2200
4.67k
} /* end H5O_get_info() */
2201
2202
/*-------------------------------------------------------------------------
2203
 * Function:    H5O_get_native_info
2204
 *
2205
 * Purpose:     Retrieve the native file-format information for an object
2206
 *
2207
 * Return:      Success:    Non-negative
2208
 *              Failure:    Negative
2209
 *
2210
 *-------------------------------------------------------------------------
2211
 */
2212
herr_t
2213
H5O_get_native_info(const H5O_loc_t *loc, H5O_native_info_t *oinfo, unsigned fields)
2214
0
{
2215
0
    H5O_t *oh        = NULL;    /* Object header */
2216
0
    herr_t ret_value = SUCCEED; /* Return value */
2217
2218
0
    FUNC_ENTER_NOAPI_TAG(loc->addr, FAIL)
2219
2220
    /* Check args */
2221
0
    assert(loc);
2222
0
    assert(oinfo);
2223
2224
    /* Get the object header */
2225
0
    if (NULL == (oh = H5O_protect(loc, H5AC__READ_ONLY_FLAG, false)))
2226
0
        HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, FAIL, "unable to load object header");
2227
2228
    /* Reset the object info structure */
2229
0
    memset(oinfo, 0, sizeof(*oinfo));
2230
2231
    /* Get the information for the object header, if requested */
2232
0
    if (fields & H5O_NATIVE_INFO_HDR)
2233
0
        if (H5O__get_hdr_info_real(oh, &oinfo->hdr) < 0)
2234
0
            HGOTO_ERROR(H5E_OHDR, H5E_CANTGET, FAIL, "can't retrieve object header info");
2235
2236
    /* Get B-tree & heap metadata storage size, if requested */
2237
0
    if (fields & H5O_NATIVE_INFO_META_SIZE) {
2238
0
        const H5O_obj_class_t *obj_class = NULL; /* Class of object for header */
2239
2240
        /* Get class for object */
2241
0
        if (H5O__obj_class_real(oh, &obj_class) < 0)
2242
0
            HGOTO_ERROR(H5E_OHDR, H5E_CANTGET, FAIL, "unable to determine object class");
2243
2244
        /* Check for 'bh_info' callback for this type of object */
2245
0
        if (obj_class->bh_info)
2246
            /* Call the object's class 'bh_info' routine */
2247
0
            if ((obj_class->bh_info)(loc, oh, &oinfo->meta_size.obj) < 0)
2248
0
                HGOTO_ERROR(H5E_OHDR, H5E_CANTGET, FAIL, "can't retrieve object's btree & heap info");
2249
2250
        /* Get B-tree & heap info for any attributes */
2251
0
        if (H5O__attr_bh_info(loc->file, oh, &oinfo->meta_size.attr) < 0)
2252
0
            HGOTO_ERROR(H5E_OHDR, H5E_CANTGET, FAIL, "can't retrieve attribute btree & heap info");
2253
0
    } /* end if */
2254
2255
0
done:
2256
0
    if (oh && H5O_unprotect(loc, oh, H5AC__NO_FLAGS_SET) < 0)
2257
0
        HDONE_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, FAIL, "unable to release object header");
2258
2259
0
    FUNC_LEAVE_NOAPI_TAG(ret_value)
2260
0
} /* end H5O_get_native_info() */
2261
2262
/*-------------------------------------------------------------------------
2263
 * Function:    H5O_get_create_plist
2264
 *
2265
 * Purpose:    Retrieve the object creation properties for an object
2266
 *
2267
 * Return:    Success:    Non-negative
2268
 *        Failure:    Negative
2269
 *
2270
 *-------------------------------------------------------------------------
2271
 */
2272
herr_t
2273
H5O_get_create_plist(const H5O_loc_t *loc, H5P_genplist_t *oc_plist)
2274
4.65k
{
2275
4.65k
    H5O_t *oh        = NULL;    /* Object header */
2276
4.65k
    herr_t ret_value = SUCCEED; /* Return value */
2277
2278
4.65k
    FUNC_ENTER_NOAPI(FAIL)
2279
2280
    /* Check args */
2281
4.65k
    assert(loc);
2282
4.65k
    assert(oc_plist);
2283
2284
    /* Get the object header */
2285
4.65k
    if (NULL == (oh = H5O_protect(loc, H5AC__READ_ONLY_FLAG, false)))
2286
0
        HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, FAIL, "unable to load object header");
2287
2288
    /* Set property values, if they were used for the object */
2289
4.65k
    if (oh->version > H5O_VERSION_1) {
2290
0
        uint8_t ohdr_flags; /* "User-visible" object header status flags */
2291
2292
        /* Set attribute storage values */
2293
0
        if (H5P_set(oc_plist, H5O_CRT_ATTR_MAX_COMPACT_NAME, &oh->max_compact) < 0)
2294
0
            HGOTO_ERROR(H5E_OHDR, H5E_CANTSET, FAIL,
2295
0
                        "can't set max. # of compact attributes in property list");
2296
0
        if (H5P_set(oc_plist, H5O_CRT_ATTR_MIN_DENSE_NAME, &oh->min_dense) < 0)
2297
0
            HGOTO_ERROR(H5E_OHDR, H5E_CANTSET, FAIL, "can't set min. # of dense attributes in property list");
2298
2299
        /* Mask off non-"user visible" flags */
2300
0
        H5_CHECKED_ASSIGN(ohdr_flags, uint8_t,
2301
0
                          oh->flags & (H5O_HDR_ATTR_CRT_ORDER_TRACKED | H5O_HDR_ATTR_CRT_ORDER_INDEXED |
2302
0
                                       H5O_HDR_STORE_TIMES),
2303
0
                          int);
2304
2305
        /* Set object header flags */
2306
0
        if (H5P_set(oc_plist, H5O_CRT_OHDR_FLAGS_NAME, &ohdr_flags) < 0)
2307
0
            HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set object header flags");
2308
0
    } /* end if */
2309
2310
4.65k
done:
2311
4.65k
    if (oh && H5O_unprotect(loc, oh, H5AC__NO_FLAGS_SET) < 0)
2312
0
        HDONE_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, FAIL, "unable to release object header");
2313
2314
4.65k
    FUNC_LEAVE_NOAPI(ret_value)
2315
4.65k
} /* end H5O_get_create_plist() */
2316
2317
/*-------------------------------------------------------------------------
2318
 * Function:    H5O_get_nlinks
2319
 *
2320
 * Purpose:    Retrieve the number of link messages read in from the file
2321
 *
2322
 * Return:    Success:    Non-negative
2323
 *        Failure:    Negative
2324
 *
2325
 *-------------------------------------------------------------------------
2326
 */
2327
herr_t
2328
H5O_get_nlinks(const H5O_loc_t *loc, hsize_t *nlinks)
2329
0
{
2330
0
    H5O_t *oh        = NULL;    /* Object header */
2331
0
    herr_t ret_value = SUCCEED; /* Return value */
2332
2333
0
    FUNC_ENTER_NOAPI(FAIL)
2334
2335
    /* Check args */
2336
0
    assert(loc);
2337
0
    assert(nlinks);
2338
2339
    /* Get the object header */
2340
0
    if (NULL == (oh = H5O_protect(loc, H5AC__READ_ONLY_FLAG, false)))
2341
0
        HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, FAIL, "unable to load object header");
2342
2343
    /* Retrieve the # of link messages seen when the object header was loaded */
2344
0
    *nlinks = oh->link_msgs_seen;
2345
2346
0
done:
2347
0
    if (oh && H5O_unprotect(loc, oh, H5AC__NO_FLAGS_SET) < 0)
2348
0
        HDONE_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, FAIL, "unable to release object header");
2349
2350
0
    FUNC_LEAVE_NOAPI(ret_value)
2351
0
} /* end H5O_get_nlinks() */
2352
2353
/*-------------------------------------------------------------------------
2354
 * Function:    H5O_obj_create
2355
 *
2356
 * Purpose:    Creates an object, in an abstract manner.
2357
 *
2358
 * Return:    Success:    Pointer to object opened
2359
 *        Failure:    NULL
2360
 *
2361
 *-------------------------------------------------------------------------
2362
 */
2363
void *
2364
H5O_obj_create(H5F_t *f, H5O_type_t obj_type, void *crt_info, H5G_loc_t *obj_loc)
2365
0
{
2366
0
    size_t u;                /* Local index variable */
2367
0
    void  *ret_value = NULL; /* Return value */
2368
2369
0
    FUNC_ENTER_NOAPI(NULL)
2370
2371
    /* Sanity checks */
2372
0
    assert(f);
2373
0
    assert(obj_type >= H5O_TYPE_GROUP && obj_type <= H5O_TYPE_NAMED_DATATYPE);
2374
0
    assert(crt_info);
2375
0
    assert(obj_loc);
2376
2377
    /* Iterate through the object classes */
2378
0
    for (u = 0; u < NELMTS(H5O_obj_class_g); u++) {
2379
        /* Check for correct type of object to create */
2380
0
        if (H5O_obj_class_g[u]->type == obj_type) {
2381
            /* Call the object class's 'create' routine */
2382
0
            assert(H5O_obj_class_g[u]->create);
2383
0
            if (NULL == (ret_value = H5O_obj_class_g[u]->create(f, crt_info, obj_loc)))
2384
0
                HGOTO_ERROR(H5E_OHDR, H5E_CANTOPENOBJ, NULL, "unable to open object");
2385
2386
            /* Break out of loop */
2387
0
            break;
2388
0
        } /* end if */
2389
0
    }     /* end for */
2390
0
    assert(ret_value);
2391
2392
0
done:
2393
0
    FUNC_LEAVE_NOAPI(ret_value)
2394
0
} /* end H5O_obj_create() */
2395
2396
/*-------------------------------------------------------------------------
2397
 * Function:    H5O_get_oh_addr
2398
 *
2399
 * Purpose:    Retrieve the address of the object header
2400
 *
2401
 * Note:    This routine participates in the "Inlining C struct access"
2402
 *        pattern, don't call it directly, use the appropriate macro
2403
 *        defined in H5Oprivate.h.
2404
 *
2405
 * Return:    Success:    Valid haddr_t
2406
 *        Failure:    HADDR_UNDEF
2407
 *
2408
 *-------------------------------------------------------------------------
2409
 */
2410
H5_ATTR_PURE haddr_t
2411
H5O_get_oh_addr(const H5O_t *oh)
2412
0
{
2413
    /* Use FUNC_ENTER_NOAPI_NOINIT_NOERR here to avoid performance issues */
2414
0
    FUNC_ENTER_NOAPI_NOINIT_NOERR
2415
2416
0
    assert(oh);
2417
0
    assert(oh->chunk);
2418
2419
0
    FUNC_LEAVE_NOAPI(oh->chunk[0].addr)
2420
0
} /* end H5O_get_oh_addr() */
2421
2422
/*-------------------------------------------------------------------------
2423
 * Function:    H5O_get_oh_flags
2424
 *
2425
 *-------------------------------------------------------------------------
2426
 */
2427
H5_ATTR_PURE uint8_t
2428
H5O_get_oh_flags(const H5O_t *oh)
2429
0
{
2430
0
    FUNC_ENTER_NOAPI_NOINIT_NOERR
2431
0
    assert(oh);
2432
0
    FUNC_LEAVE_NOAPI(oh->flags) /* flags can be 0 */
2433
0
} /* H5O_get_oh_flags() */
2434
2435
/*-------------------------------------------------------------------------
2436
 * Function:    H5O_get_oh_mtime
2437
 *
2438
 * Purpose:     Retrieve an object's modification time. Assumes that the
2439
 *              caller has verified that accessing this variable is appropriate
2440
 *              to the header in question.
2441
 *
2442
 *-------------------------------------------------------------------------
2443
 */
2444
H5_ATTR_PURE time_t
2445
H5O_get_oh_mtime(const H5O_t *oh)
2446
0
{
2447
0
    FUNC_ENTER_NOAPI_NOINIT_NOERR
2448
0
    assert(oh);
2449
0
    assert(oh->mtime);
2450
0
    FUNC_LEAVE_NOAPI(oh->mtime)
2451
0
} /* H5O_get_oh_mtime() */
2452
2453
/*-------------------------------------------------------------------------
2454
 * Function:    H5O_get_oh_version
2455
 *
2456
 *-------------------------------------------------------------------------
2457
 */
2458
H5_ATTR_PURE uint8_t
2459
H5O_get_oh_version(const H5O_t *oh)
2460
0
{
2461
0
    FUNC_ENTER_NOAPI_NOINIT_NOERR
2462
0
    assert(oh);
2463
0
    assert(oh->version);
2464
0
    FUNC_LEAVE_NOAPI(oh->version)
2465
0
} /* H5O_get_oh_version() */
2466
2467
/*-------------------------------------------------------------------------
2468
 * Function:    H5O_get_rc_and_type
2469
 *
2470
 * Purpose:    Retrieve an object's reference count and type
2471
 *
2472
 * Return:    Success:    Non-negative
2473
 *        Failure:    Negative
2474
 *
2475
 *-------------------------------------------------------------------------
2476
 */
2477
herr_t
2478
H5O_get_rc_and_type(const H5O_loc_t *loc, unsigned *rc, H5O_type_t *otype)
2479
0
{
2480
0
    H5O_t *oh        = NULL;    /* Object header */
2481
0
    herr_t ret_value = SUCCEED; /* Return value */
2482
2483
0
    FUNC_ENTER_NOAPI(FAIL)
2484
2485
    /* Check args */
2486
0
    assert(loc);
2487
2488
    /* Get the object header */
2489
0
    if (NULL == (oh = H5O_protect(loc, H5AC__READ_ONLY_FLAG, false)))
2490
0
        HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, FAIL, "unable to load object header");
2491
2492
    /* Set the object's reference count */
2493
0
    if (rc)
2494
0
        *rc = oh->nlink;
2495
2496
    /* Retrieve the type of the object */
2497
0
    if (otype)
2498
0
        if (H5O__obj_type_real(oh, otype) < 0)
2499
0
            HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, FAIL, "unable to determine object type");
2500
2501
0
done:
2502
0
    if (oh && H5O_unprotect(loc, oh, H5AC__NO_FLAGS_SET) < 0)
2503
0
        HDONE_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, FAIL, "unable to release object header");
2504
2505
0
    FUNC_LEAVE_NOAPI(ret_value)
2506
0
} /* end H5O_get_rc_and_type() */
2507
2508
/*-------------------------------------------------------------------------
2509
 * Function:    H5O__free_visit_visited
2510
 *
2511
 * Purpose:     Free the key for an object visited during a group traversal
2512
 *
2513
 * Return:      Non-negative on success, negative on failure
2514
 *
2515
 *-------------------------------------------------------------------------
2516
 */
2517
static herr_t
2518
H5O__free_visit_visited(void *item, void H5_ATTR_UNUSED *key, void H5_ATTR_UNUSED *operator_data /*in,out*/)
2519
0
{
2520
0
    FUNC_ENTER_PACKAGE_NOERR
2521
2522
0
    item = H5FL_FREE(H5_obj_t, item);
2523
2524
0
    FUNC_LEAVE_NOAPI(SUCCEED)
2525
0
} /* end H5O__free_visit_visited() */
2526
2527
/*-------------------------------------------------------------------------
2528
 * Function:    H5O__visit_cb
2529
 *
2530
 * Purpose:     Callback function for recursively visiting objects from a group
2531
 *
2532
 * Return:    Success:        Non-negative
2533
 *        Failure:    Negative
2534
 *
2535
 *-------------------------------------------------------------------------
2536
 */
2537
static herr_t
2538
H5O__visit_cb(hid_t H5_ATTR_UNUSED group, const char *name, const H5L_info2_t *linfo, void *_udata)
2539
0
{
2540
0
    H5O_iter_visit_ud_t *udata = (H5O_iter_visit_ud_t *)_udata; /* User data for callback */
2541
0
    H5G_loc_t            obj_loc;                               /* Location of object */
2542
0
    H5G_name_t           obj_path;                              /* Object's group hier. path */
2543
0
    H5O_loc_t            obj_oloc;                              /* Object's object location */
2544
0
    bool                 obj_found = false;                     /* Object at 'name' found */
2545
0
    herr_t               ret_value = H5_ITER_CONT;              /* Return value */
2546
2547
0
    FUNC_ENTER_PACKAGE
2548
2549
    /* Sanity check */
2550
0
    assert(name);
2551
0
    assert(linfo);
2552
0
    assert(udata);
2553
2554
    /* Check if this is a hard link */
2555
0
    if (linfo->type == H5L_TYPE_HARD) {
2556
0
        H5_obj_t obj_pos; /* Object "position" for this object */
2557
2558
        /* Set up opened group location to fill in */
2559
0
        obj_loc.oloc = &obj_oloc;
2560
0
        obj_loc.path = &obj_path;
2561
0
        H5G_loc_reset(&obj_loc);
2562
2563
        /* Find the object using the LAPL passed in */
2564
        /* (Correctly handles mounted files) */
2565
0
        if (H5G_loc_find(udata->start_loc, name, &obj_loc /*out*/) < 0)
2566
0
            HGOTO_ERROR(H5E_OHDR, H5E_NOTFOUND, H5_ITER_ERROR, "object not found");
2567
0
        obj_found = true;
2568
2569
        /* Construct unique "position" for this object */
2570
0
        H5F_GET_FILENO(obj_oloc.file, obj_pos.fileno);
2571
0
        obj_pos.addr = obj_oloc.addr;
2572
2573
        /* Check if we've seen the object the link references before */
2574
0
        if (NULL == H5SL_search(udata->visited, &obj_pos)) {
2575
0
            H5O_info2_t oinfo; /* Object info */
2576
2577
            /* Get the object's info */
2578
0
            if (H5O_get_info(&obj_oloc, &oinfo, udata->fields) < 0)
2579
0
                HGOTO_ERROR(H5E_OHDR, H5E_CANTGET, H5_ITER_ERROR, "unable to get object info");
2580
2581
            /* Prepare & restore library for user callback */
2582
0
            H5_BEFORE_USER_CB(FAIL)
2583
0
                {
2584
                    /* Make the application callback */
2585
0
                    ret_value = (udata->op)(udata->obj_id, name, &oinfo, udata->op_data);
2586
0
                }
2587
0
            H5_AFTER_USER_CB(FAIL)
2588
2589
            /* Check for continuing to visit objects */
2590
0
            if (ret_value == H5_ITER_CONT) {
2591
                /* If its ref count is > 1, we add it to the list of visited objects */
2592
                /* (because it could come up again during traversal) */
2593
0
                if (oinfo.rc > 1) {
2594
0
                    H5_obj_t *new_node; /* New object node for visited list */
2595
2596
                    /* Allocate new object "position" node */
2597
0
                    if ((new_node = H5FL_MALLOC(H5_obj_t)) == NULL)
2598
0
                        HGOTO_ERROR(H5E_OHDR, H5E_NOSPACE, H5_ITER_ERROR, "can't allocate object node");
2599
2600
                    /* Set node information */
2601
0
                    *new_node = obj_pos;
2602
2603
                    /* Add to list of visited objects */
2604
0
                    if (H5SL_insert(udata->visited, new_node, new_node) < 0)
2605
0
                        HGOTO_ERROR(H5E_OHDR, H5E_CANTINSERT, H5_ITER_ERROR,
2606
0
                                    "can't insert object node into visited list");
2607
0
                } /* end if */
2608
0
            }     /* end if */
2609
0
        }         /* end if */
2610
0
    }             /* end if */
2611
2612
0
done:
2613
    /* Release resources */
2614
0
    if (obj_found && H5G_loc_free(&obj_loc) < 0)
2615
0
        HDONE_ERROR(H5E_OHDR, H5E_CANTRELEASE, H5_ITER_ERROR, "can't free location");
2616
2617
0
    FUNC_LEAVE_NOAPI(ret_value)
2618
0
} /* end H5O__visit_cb() */
2619
2620
/*-------------------------------------------------------------------------
2621
 * Function:    H5O__visit
2622
 *
2623
 * Purpose:     Recursively visit an object and all the objects reachable
2624
 *              from it.  If the starting object is a group, all the objects
2625
 *              linked to from that group will be visited.  Links within
2626
 *              each group are visited according to the order within the
2627
 *              specified index (unless the specified index does not exist for
2628
 *              a particular group, then the "name" index is used).
2629
 *
2630
 *              NOTE: Soft links and user-defined links are ignored during
2631
 *              this operation.
2632
 *
2633
 *              NOTE: Each _object_ reachable from the initial group will only
2634
 *              be visited once.  If multiple hard links point to the same
2635
 *              object, the first link to the object's path (according to the
2636
 *              iteration index and iteration order given) will be used to in
2637
 *              the callback about the object.
2638
 *
2639
 * Note:        Add a parameter "fields" to indicate selection of object info.
2640
 *
2641
 * Return:      Success:    The return value of the first operator that
2642
 *                          returns non-zero, or zero if all members were
2643
 *                          processed with no operator returning non-zero.
2644
 *
2645
 *              Failure:    Negative if something goes wrong within the
2646
 *                          library, or the negative value returned by one
2647
 *                          of the operators.
2648
 *
2649
 *-------------------------------------------------------------------------
2650
 */
2651
herr_t
2652
H5O__visit(H5G_loc_t *loc, const char *obj_name, H5_index_t idx_type, H5_iter_order_t order,
2653
           H5O_iterate2_t op, void *op_data, unsigned fields)
2654
0
{
2655
0
    H5O_iter_visit_ud_t udata;                       /* User data for callback */
2656
0
    H5G_loc_t           obj_loc;                     /* Location used to open object */
2657
0
    H5G_name_t          obj_path;                    /* Opened object group hier. path */
2658
0
    H5O_loc_t           obj_oloc;                    /* Opened object object location */
2659
0
    bool                loc_found = false;           /* Entry at 'name' found */
2660
0
    H5O_info2_t         oinfo;                       /* Object info struct */
2661
0
    H5O_info2_t         int_oinfo;                   /* Internal object info */
2662
0
    H5O_info2_t        *oinfop = &oinfo;             /* Object info pointer */
2663
0
    void               *obj    = NULL;               /* Object */
2664
0
    H5I_type_t          opened_type;                 /* ID type of object */
2665
0
    hid_t               obj_id    = H5I_INVALID_HID; /* ID of object */
2666
0
    herr_t              ret_value = FAIL;            /* Return value */
2667
2668
0
    FUNC_ENTER_PACKAGE
2669
2670
    /* Portably initialize user data struct to zeros */
2671
0
    memset(&udata, 0, sizeof(udata));
2672
2673
    /* Check args */
2674
0
    assert(loc);
2675
2676
    /* Set up opened group location to fill in */
2677
0
    obj_loc.oloc = &obj_oloc;
2678
0
    obj_loc.path = &obj_path;
2679
0
    H5G_loc_reset(&obj_loc);
2680
2681
    /* Find the object's location */
2682
0
    if (H5G_loc_find(loc, obj_name, &obj_loc /*out*/) < 0)
2683
0
        HGOTO_ERROR(H5E_OHDR, H5E_NOTFOUND, FAIL, "object not found");
2684
0
    loc_found = true;
2685
2686
    /* Get the object's info */
2687
0
    if (H5O_get_info(&obj_oloc, &oinfo, fields) < 0)
2688
0
        HGOTO_ERROR(H5E_OHDR, H5E_CANTGET, FAIL, "unable to get object info");
2689
2690
    /* If basic fields are not requested, get object basic info to use here */
2691
0
    if (!(fields & H5O_INFO_BASIC)) {
2692
0
        oinfop = &int_oinfo;
2693
        /* Get the object's basic info for local use */
2694
0
        if (H5O_get_info(&obj_oloc, &int_oinfo, H5O_INFO_BASIC) < 0)
2695
0
            HGOTO_ERROR(H5E_OHDR, H5E_CANTGET, FAIL, "unable to get object's basic info");
2696
0
    }
2697
2698
    /* Open the object */
2699
    /* (Takes ownership of the obj_loc information) */
2700
0
    if (NULL == (obj = H5O_open_by_loc(&obj_loc, &opened_type)))
2701
0
        HGOTO_ERROR(H5E_OHDR, H5E_CANTOPENOBJ, FAIL, "unable to open object");
2702
2703
    /* Get an ID for the visited object */
2704
0
    if ((obj_id = H5VL_wrap_register(opened_type, obj, true)) < 0)
2705
0
        HGOTO_ERROR(H5E_ID, H5E_CANTREGISTER, FAIL, "unable to register visited object");
2706
2707
    /* Make callback for starting object */
2708
0
    if ((ret_value = op(obj_id, ".", &oinfo, op_data)) < 0)
2709
0
        HGOTO_ERROR(H5E_OHDR, H5E_BADITER, FAIL, "can't visit objects");
2710
2711
    /* Check return value of first callback */
2712
0
    if (ret_value != H5_ITER_CONT)
2713
0
        HGOTO_DONE(ret_value);
2714
2715
    /* Check for object being a group */
2716
0
    if (oinfop->type == H5O_TYPE_GROUP) {
2717
0
        H5G_loc_t start_loc; /* Location of starting group */
2718
0
        H5G_loc_t vis_loc;   /* Location of visited group */
2719
2720
        /* Get the location of the starting group */
2721
0
        if (H5G_loc(obj_id, &start_loc) < 0)
2722
0
            HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a location");
2723
2724
        /* Set up user data for visiting links */
2725
0
        udata.obj_id    = obj_id;
2726
0
        udata.start_loc = &start_loc;
2727
0
        udata.op        = op;
2728
0
        udata.op_data   = op_data;
2729
0
        udata.fields    = fields;
2730
2731
        /* Create skip list to store visited object information */
2732
0
        if ((udata.visited = H5SL_create(H5SL_TYPE_OBJ, NULL)) == NULL)
2733
0
            HGOTO_ERROR(H5E_OHDR, H5E_CANTCREATE, FAIL, "can't create skip list for visited objects");
2734
2735
        /* If its ref count is > 1, we add it to the list of visited objects */
2736
        /* (because it could come up again during traversal) */
2737
0
        if (oinfop->rc > 1) {
2738
0
            H5_obj_t *obj_pos; /* New object node for visited list */
2739
2740
            /* Allocate new object "position" node */
2741
0
            if ((obj_pos = H5FL_MALLOC(H5_obj_t)) == NULL)
2742
0
                HGOTO_ERROR(H5E_OHDR, H5E_NOSPACE, FAIL, "can't allocate object node");
2743
2744
            /* Construct unique "position" for this object */
2745
0
            obj_pos->fileno = oinfop->fileno;
2746
2747
            /* De-serialize object token into an object address */
2748
0
            if (H5VL_native_token_to_addr(loc->oloc->file, H5I_FILE, oinfop->token, &(obj_pos->addr)) < 0)
2749
0
                HGOTO_ERROR(H5E_OHDR, H5E_CANTUNSERIALIZE, FAIL,
2750
0
                            "can't deserialize object token into address");
2751
2752
            /* Add to list of visited objects */
2753
0
            if (H5SL_insert(udata.visited, obj_pos, obj_pos) < 0)
2754
0
                HGOTO_ERROR(H5E_OHDR, H5E_CANTINSERT, FAIL, "can't insert object node into visited list");
2755
0
        }
2756
2757
        /* Get the location of the visited group */
2758
0
        if (H5G_loc(obj_id, &vis_loc) < 0)
2759
0
            HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a location");
2760
2761
        /* Call internal group visitation routine */
2762
0
        if ((ret_value = H5G_visit(&vis_loc, ".", idx_type, order, H5O__visit_cb, &udata)) < 0)
2763
0
            HGOTO_ERROR(H5E_OHDR, H5E_BADITER, FAIL, "object visitation failed");
2764
0
    } /* end if */
2765
2766
0
done:
2767
    /* XXX (VOL MERGE): Probably also want to consider closing obj here on failures */
2768
0
    if (obj_id != H5I_INVALID_HID) {
2769
0
        if (H5I_dec_app_ref(obj_id) < 0)
2770
0
            HDONE_ERROR(H5E_OHDR, H5E_CANTRELEASE, FAIL, "unable to close object");
2771
0
    }
2772
0
    else if (loc_found && H5G_loc_free(&obj_loc) < 0)
2773
0
        HDONE_ERROR(H5E_OHDR, H5E_CANTRELEASE, FAIL, "can't free location");
2774
2775
0
    if (udata.visited)
2776
0
        H5SL_destroy(udata.visited, H5O__free_visit_visited, NULL);
2777
2778
0
    FUNC_LEAVE_NOAPI(ret_value)
2779
0
} /* end H5O__visit() */
2780
2781
/*-------------------------------------------------------------------------
2782
 * Function:    H5O__inc_rc
2783
 *
2784
 * Purpose:    Increments the reference count on an object header
2785
 *
2786
 * Return:    Non-negative on success/Negative on failure
2787
 *
2788
 *-------------------------------------------------------------------------
2789
 */
2790
herr_t
2791
H5O__inc_rc(H5O_t *oh)
2792
560
{
2793
560
    herr_t ret_value = SUCCEED; /* Return value */
2794
2795
560
    FUNC_ENTER_PACKAGE
2796
2797
    /* check args */
2798
560
    assert(oh);
2799
2800
    /* Pin the object header when the reference count goes above 0 */
2801
560
    if (oh->rc == 0)
2802
437
        if (H5AC_pin_protected_entry(oh) < 0)
2803
0
            HGOTO_ERROR(H5E_OHDR, H5E_CANTPIN, FAIL, "unable to pin object header");
2804
2805
    /* Increment reference count */
2806
560
    oh->rc++;
2807
2808
560
done:
2809
560
    FUNC_LEAVE_NOAPI(ret_value)
2810
560
} /* end H5O__inc_rc() */
2811
2812
/*-------------------------------------------------------------------------
2813
 * Function:    H5O__dec_rc
2814
 *
2815
 * Purpose:    Decrements the reference count on an object header
2816
 *
2817
 * Return:    Non-negative on success/Negative on failure
2818
 *
2819
 *-------------------------------------------------------------------------
2820
 */
2821
herr_t
2822
H5O__dec_rc(H5O_t *oh)
2823
599
{
2824
599
    herr_t ret_value = SUCCEED; /* Return value */
2825
2826
599
    FUNC_ENTER_PACKAGE
2827
2828
    /* check args */
2829
599
    if (!oh)
2830
39
        HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid object header");
2831
2832
    /* Decrement reference count */
2833
560
    oh->rc--;
2834
2835
    /* Unpin the object header when the reference count goes back to 0 */
2836
560
    if (oh->rc == 0)
2837
437
        if (H5AC_unpin_entry(oh) < 0)
2838
0
            HGOTO_ERROR(H5E_OHDR, H5E_CANTUNPIN, FAIL, "unable to unpin object header");
2839
2840
599
done:
2841
599
    FUNC_LEAVE_NOAPI(ret_value)
2842
599
} /* end H5O__dec_rc() */
2843
2844
/*-------------------------------------------------------------------------
2845
 * Function:   H5O_dec_rc_by_loc
2846
 *
2847
 * Purpose:    Decrement the refcount of an object header, using its
2848
 *              object location information.
2849
 *
2850
 * Return:     Non-negative on success/Negative on failure
2851
 *
2852
 *-------------------------------------------------------------------------
2853
 */
2854
herr_t
2855
H5O_dec_rc_by_loc(const H5O_loc_t *loc)
2856
0
{
2857
0
    H5O_t *oh        = NULL;    /* Object header */
2858
0
    herr_t ret_value = SUCCEED; /* Return value */
2859
2860
0
    FUNC_ENTER_NOAPI(FAIL)
2861
2862
    /* check args */
2863
0
    assert(loc);
2864
2865
    /* Get header */
2866
0
    if (NULL == (oh = H5O_protect(loc, H5AC__READ_ONLY_FLAG, false)))
2867
0
        HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, FAIL, "unable to protect object header");
2868
2869
    /* Decrement the reference count on the object header */
2870
    /* (which will unpin it, if appropriate) */
2871
0
    if (H5O__dec_rc(oh) < 0)
2872
0
        HGOTO_ERROR(H5E_OHDR, H5E_CANTDEC, FAIL, "unable to decrement reference count on object header");
2873
2874
0
done:
2875
    /* Release the object header from the cache */
2876
0
    if (oh && H5O_unprotect(loc, oh, H5AC__NO_FLAGS_SET) < 0)
2877
0
        HDONE_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, FAIL, "unable to release object header");
2878
2879
0
    FUNC_LEAVE_NOAPI(ret_value)
2880
0
} /* end H5O_dec_rc_by_loc() */
2881
2882
/*-------------------------------------------------------------------------
2883
 * Function:    H5O_get_proxy
2884
 *
2885
 * Purpose:    Retrieve the proxy for the object header.
2886
 *
2887
 * Return:    Non-negative on success/Negative on failure
2888
 *
2889
 *-------------------------------------------------------------------------
2890
 */
2891
H5_ATTR_PURE H5AC_proxy_entry_t *
2892
H5O_get_proxy(const H5O_t *oh)
2893
0
{
2894
0
    FUNC_ENTER_NOAPI_NOINIT_NOERR
2895
2896
    /* Check args */
2897
0
    assert(oh);
2898
2899
0
    FUNC_LEAVE_NOAPI(oh->proxy)
2900
0
} /* end H5O_get_proxy() */
2901
2902
/*-------------------------------------------------------------------------
2903
 * Function:    H5O__free
2904
 *
2905
 * Purpose:    Destroys an object header.
2906
 *
2907
 * Return:    Non-negative on success/Negative on failure
2908
 *
2909
 *-------------------------------------------------------------------------
2910
 */
2911
herr_t
2912
H5O__free(H5O_t *oh, bool H5_ATTR_NDEBUG_UNUSED force)
2913
7.03k
{
2914
7.03k
    unsigned u;                   /* Local index variable */
2915
7.03k
    herr_t   ret_value = SUCCEED; /* Return value */
2916
2917
7.03k
    FUNC_ENTER_PACKAGE
2918
2919
    /* check args */
2920
7.03k
    assert(oh);
2921
7.03k
    assert(0 == oh->rc);
2922
7.03k
    assert(0 == oh->mesgs_modified);
2923
7.03k
    assert(0 == oh->recursion_level);
2924
2925
    /* Destroy chunks */
2926
7.03k
    if (oh->chunk) {
2927
7.50k
        for (u = 0; u < oh->nchunks; u++)
2928
4.05k
            oh->chunk[u].image = H5FL_BLK_FREE(chunk_image, oh->chunk[u].image);
2929
2930
3.45k
        oh->chunk = (H5O_chunk_t *)H5FL_SEQ_FREE(H5O_chunk_t, oh->chunk);
2931
3.45k
    } /* end if */
2932
2933
    /* Destroy messages */
2934
7.03k
    if (oh->mesg) {
2935
27.0k
        for (u = 0; u < oh->nmesgs; u++) {
2936
#ifndef NDEBUG
2937
            /* Verify that message is clean, unless it could have been marked
2938
             * dirty by decoding, or if this is a forced free (in case of
2939
             * failure during creation of the object some messages may be dirty)
2940
             */
2941
            if (oh->ndecode_dirtied && oh->mesg[u].dirty)
2942
                oh->ndecode_dirtied--;
2943
            else if (!force)
2944
                assert(oh->mesg[u].dirty == 0);
2945
#endif /* NDEBUG */
2946
2947
23.6k
            H5O__msg_free_mesg(&oh->mesg[u]);
2948
23.6k
        } /* end for */
2949
2950
        /* Make sure we accounted for all the messages dirtied by decoding */
2951
3.45k
        assert(!oh->ndecode_dirtied);
2952
2953
3.45k
        oh->mesg = (H5O_mesg_t *)H5FL_SEQ_FREE(H5O_mesg_t, oh->mesg);
2954
3.45k
    } /* end if */
2955
2956
    /* Destroy the proxy */
2957
7.03k
    if (oh->proxy)
2958
0
        if (H5AC_proxy_entry_dest(oh->proxy) < 0)
2959
0
            HGOTO_ERROR(H5E_OHDR, H5E_CANTFREE, FAIL, "unable to destroy virtual entry used for proxy");
2960
2961
    /* destroy object header */
2962
7.03k
    oh = H5FL_FREE(H5O_t, oh);
2963
2964
7.03k
done:
2965
7.03k
    FUNC_LEAVE_NOAPI(ret_value)
2966
7.03k
} /* end H5O__free() */
2967
2968
/*-------------------------------------------------------------------------
2969
 * Function:    H5O__reset_info2
2970
 *
2971
 * Purpose:     Resets/initializes an H5O_info2_t struct.
2972
 *
2973
 * Return:      SUCCEED/FAIL
2974
 *
2975
 *-------------------------------------------------------------------------
2976
 */
2977
static herr_t
2978
H5O__reset_info2(H5O_info2_t *oinfo)
2979
4.48k
{
2980
4.48k
    FUNC_ENTER_PACKAGE_NOERR
2981
2982
    /* Reset the passed-in info struct */
2983
4.48k
    memset(oinfo, 0, sizeof(H5O_info2_t));
2984
4.48k
    oinfo->type  = H5O_TYPE_UNKNOWN;
2985
4.48k
    oinfo->token = H5O_TOKEN_UNDEF;
2986
2987
4.48k
    FUNC_LEAVE_NOAPI(SUCCEED)
2988
4.48k
} /* end H5O__reset_info2() */
2989
2990
/*-------------------------------------------------------------------------
2991
 * Function:    H5O_has_chksum
2992
 *
2993
 * Purpose:     Returns true if object header is checksummed
2994
 *
2995
 * Return:      true/false on success, can't fail
2996
 *
2997
 *-------------------------------------------------------------------------
2998
 */
2999
H5_ATTR_PURE bool
3000
H5O_has_chksum(const H5O_t *oh)
3001
0
{
3002
0
    FUNC_ENTER_NOAPI_NOINIT_NOERR
3003
3004
    /* Check args */
3005
0
    assert(oh);
3006
3007
0
    FUNC_LEAVE_NOAPI(H5O_SIZEOF_CHKSUM_OH(oh) > 0)
3008
0
} /* end H5O_has_chksum() */
3009
3010
/*-------------------------------------------------------------------------
3011
 * Function:    H5O_get_version_bound
3012
 *
3013
 * Purpose:     Retrieve the version for a given bound from object version array
3014
 *
3015
 *-------------------------------------------------------------------------
3016
 */
3017
herr_t
3018
H5O_get_version_bound(H5F_libver_t bound, uint8_t *version)
3019
0
{
3020
0
    FUNC_ENTER_NOAPI_NOINIT_NOERR
3021
3022
0
    *version = (uint8_t)H5O_obj_ver_bounds[bound];
3023
3024
0
    FUNC_LEAVE_NOAPI(SUCCEED)
3025
0
} /* end H5O_get_version_bound() */