Coverage Report

Created: 2024-06-18 06:29

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