Coverage Report

Created: 2026-09-04 06:51

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