Coverage Report

Created: 2026-10-28 07:05

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/hdf5/src/H5Ocache.c
Line
Count
Source
1
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2
 * Copyright by The HDF Group.                                               *
3
 * All rights reserved.                                                      *
4
 *                                                                           *
5
 * This file is part of HDF5.  The full HDF5 copyright notice, including     *
6
 * terms governing use, modification, and redistribution, is contained in    *
7
 * the LICENSE file, which can be found at the root of the source code       *
8
 * distribution tree, or in https://www.hdfgroup.org/licenses.               *
9
 * If you do not have access to either file, you may request a copy from     *
10
 * help@hdfgroup.org.                                                        *
11
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
12
13
/*-------------------------------------------------------------------------
14
 *
15
 * Created:   H5Ocache.c
16
 *
17
 * Purpose:   Object header metadata cache virtual functions
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 "H5Eprivate.h"  /* Error handling              */
33
#include "H5FLprivate.h" /* Free lists                  */
34
#include "H5MMprivate.h" /* Memory management           */
35
#include "H5Opkg.h"      /* Object headers              */
36
37
/****************/
38
/* Local Macros */
39
/****************/
40
41
/******************/
42
/* Local Typedefs */
43
/******************/
44
45
/********************/
46
/* Package Typedefs */
47
/********************/
48
49
/********************/
50
/* Local Prototypes */
51
/********************/
52
53
/* Metadata cache callbacks */
54
static herr_t H5O__cache_get_initial_load_size(void *udata, size_t *image_len);
55
static herr_t H5O__cache_get_final_load_size(const void *image_ptr, size_t image_len, void *udata,
56
                                             size_t *actual_len);
57
static htri_t H5O__cache_verify_chksum(const void *image_ptr, size_t len, void *udata_ptr);
58
static void  *H5O__cache_deserialize(const void *image, size_t len, void *udata, bool *dirty);
59
static herr_t H5O__cache_image_len(const void *thing, size_t *image_len);
60
static herr_t H5O__cache_serialize(const H5F_t *f, void *image, size_t len, void *thing);
61
static herr_t H5O__cache_notify(H5AC_notify_action_t action, void *_thing);
62
static herr_t H5O__cache_free_icr(void *thing);
63
64
static herr_t H5O__cache_chk_get_initial_load_size(void *udata, size_t *image_len);
65
static htri_t H5O__cache_chk_verify_chksum(const void *image_ptr, size_t len, void *udata_ptr);
66
static void  *H5O__cache_chk_deserialize(const void *image, size_t len, void *udata, bool *dirty);
67
static herr_t H5O__cache_chk_image_len(const void *thing, size_t *image_len);
68
static herr_t H5O__cache_chk_serialize(const H5F_t *f, void *image, size_t len, void *thing);
69
static herr_t H5O__cache_chk_notify(H5AC_notify_action_t action, void *_thing);
70
static herr_t H5O__cache_chk_free_icr(void *thing);
71
72
/* Prefix routines */
73
static herr_t H5O__prefix_deserialize(const uint8_t *image, size_t len, H5O_cache_ud_t *udata);
74
75
/* Chunk routines */
76
static herr_t H5O__chunk_deserialize(H5O_t *oh, haddr_t addr, size_t chunk_size, const uint8_t *image,
77
                                     size_t len, H5O_common_cache_ud_t *udata, bool *dirty);
78
static herr_t H5O__chunk_serialize(const H5F_t *f, H5O_t *oh, unsigned chunkno);
79
80
/* Misc. routines */
81
static herr_t H5O__add_cont_msg(H5O_cont_msgs_t *cont_msg_info, const H5O_cont_t *cont);
82
83
/*********************/
84
/* Package Variables */
85
/*********************/
86
87
/* H5O object header prefix inherits cache-like properties from H5AC */
88
const H5AC_class_t H5AC_OHDR[1] = {{
89
    H5AC_OHDR_ID,                      /* Metadata client ID */
90
    "object header",                   /* Metadata client name (for debugging) */
91
    H5FD_MEM_OHDR,                     /* File space memory type for client */
92
    H5AC__CLASS_SPECULATIVE_LOAD_FLAG, /* Client class behavior flags */
93
    H5O__cache_get_initial_load_size,  /* 'get_initial_load_size' callback */
94
    H5O__cache_get_final_load_size,    /* 'get_final_load_size' callback */
95
    H5O__cache_verify_chksum,          /* 'verify_chksum' callback */
96
    H5O__cache_deserialize,            /* 'deserialize' callback */
97
    H5O__cache_image_len,              /* 'image_len' callback */
98
    NULL,                              /* 'pre_serialize' callback */
99
    H5O__cache_serialize,              /* 'serialize' callback */
100
    H5O__cache_notify,                 /* 'notify' callback */
101
    H5O__cache_free_icr,               /* 'free_icr' callback */
102
    NULL,                              /* 'fsf_size' callback */
103
}};
104
105
/* H5O object header chunk inherits cache-like properties from H5AC */
106
const H5AC_class_t H5AC_OHDR_CHK[1] = {{
107
    H5AC_OHDR_CHK_ID,                     /* Metadata client ID */
108
    "object header continuation chunk",   /* Metadata client name (for debugging) */
109
    H5FD_MEM_OHDR,                        /* File space memory type for client */
110
    H5AC__CLASS_NO_FLAGS_SET,             /* Client class behavior flags */
111
    H5O__cache_chk_get_initial_load_size, /* 'get_initial_load_size' callback */
112
    NULL,                                 /* 'get_final_load_size' callback */
113
    H5O__cache_chk_verify_chksum,         /* 'verify_chksum' callback */
114
    H5O__cache_chk_deserialize,           /* 'deserialize' callback */
115
    H5O__cache_chk_image_len,             /* 'image_len' callback */
116
    NULL,                                 /* 'pre_serialize' callback */
117
    H5O__cache_chk_serialize,             /* 'serialize' callback */
118
    H5O__cache_chk_notify,                /* 'notify' callback */
119
    H5O__cache_chk_free_icr,              /* 'free_icr' callback */
120
    NULL,                                 /* 'fsf_size' callback */
121
}};
122
123
/* Declare external the free list for H5O_unknown_t's */
124
H5FL_EXTERN(H5O_unknown_t);
125
126
/* Declare extern the free list for H5O_chunk_proxy_t's */
127
H5FL_EXTERN(H5O_chunk_proxy_t);
128
129
/* Declare the free list for H5O_cont_t sequences */
130
H5FL_SEQ_DEFINE(H5O_cont_t);
131
132
/*****************************/
133
/* Library Private Variables */
134
/*****************************/
135
136
/*******************/
137
/* Local Variables */
138
/*******************/
139
140
/*-------------------------------------------------------------------------
141
 * Function:    H5O__cache_get_initial_load_size()
142
 *
143
 * Purpose:     Tell the metadata cache how much data to read from file in
144
 *              the first speculative read for the object header.
145
 *
146
 * Return:      SUCCEED/FAIL
147
 *-------------------------------------------------------------------------
148
 */
149
static herr_t
150
H5O__cache_get_initial_load_size(void H5_ATTR_UNUSED *_udata, size_t *image_len)
151
0
{
152
0
    FUNC_ENTER_PACKAGE_NOERR
153
154
0
    assert(image_len);
155
156
    /* Set the image length size */
157
0
    *image_len = H5O_SPEC_READ_SIZE;
158
159
0
    FUNC_LEAVE_NOAPI(SUCCEED)
160
0
} /* end H5O__cache_get_initial_load_size() */
161
162
/*-------------------------------------------------------------------------
163
 * Function:    H5O__cache_get_final_load_size()
164
 *
165
 * Purpose:     Tell the metadata cache the final size of an object header.
166
 *
167
 * Return:      SUCCEED/FAIL
168
 *-------------------------------------------------------------------------
169
 */
170
static herr_t
171
H5O__cache_get_final_load_size(const void *image, size_t image_len, void *_udata, size_t *actual_len)
172
0
{
173
0
    H5O_cache_ud_t *udata     = (H5O_cache_ud_t *)_udata; /* User data for callback */
174
0
    herr_t          ret_value = SUCCEED;
175
176
0
    FUNC_ENTER_PACKAGE
177
178
0
    assert(image);
179
0
    assert(udata);
180
0
    assert(actual_len);
181
0
    assert(*actual_len == image_len);
182
183
    /* Deserialize the object header prefix */
184
0
    if (H5O__prefix_deserialize((const uint8_t *)image, image_len, udata) < 0)
185
0
        HGOTO_ERROR(H5E_OHDR, H5E_CANTDECODE, FAIL, "can't deserialize object header prefix");
186
187
    /* Sanity check */
188
0
    assert(udata->oh);
189
190
    /* Set the final size for the cache image */
191
0
    *actual_len = udata->chunk0_size + (size_t)H5O_SIZEOF_HDR(udata->oh);
192
193
    /* Save the oh version to be used later in verify_chksum callback
194
       because oh will be freed before leaving this routine */
195
0
    udata->oh_version = udata->oh->version;
196
197
    /* Free allocated memory: fix github issue #3970 */
198
0
    if (H5O__free(udata->oh, false) < 0)
199
0
        HGOTO_ERROR(H5E_OHDR, H5E_CANTRELEASE, FAIL, "can't destroy object header");
200
0
    udata->oh = NULL;
201
202
0
done:
203
0
    FUNC_LEAVE_NOAPI(ret_value)
204
0
} /* end H5O__cache_get_final_load_size() */
205
206
/*-------------------------------------------------------------------------
207
 * Function:    H5O__cache_verify_chksum
208
 *
209
 * Purpose:     Verify the computed checksum of the data structure is the
210
 *              same as the stored chksum.
211
 *
212
 * Return:      Success:        true/false
213
 *              Failure:        Negative
214
 *-------------------------------------------------------------------------
215
 */
216
static htri_t
217
H5O__cache_verify_chksum(const void *_image, size_t len, void *_udata)
218
0
{
219
0
    const uint8_t  *image     = (const uint8_t *)_image;  /* Pointer into raw data buffer */
220
0
    H5O_cache_ud_t *udata     = (H5O_cache_ud_t *)_udata; /* User data for callback */
221
0
    htri_t          ret_value = true;
222
223
0
    FUNC_ENTER_PACKAGE
224
225
0
    assert(image);
226
0
    assert(udata);
227
228
    /* There is no checksum for version 1 */
229
0
    if (udata->oh_version != H5O_VERSION_1) {
230
0
        uint32_t stored_chksum;   /* Stored metadata checksum value */
231
0
        uint32_t computed_chksum; /* Computed metadata checksum value */
232
233
        /* Get stored and computed checksums */
234
0
        if (H5F_get_checksums(image, len, &stored_chksum, &computed_chksum) < 0)
235
0
            HGOTO_ERROR(H5E_OHDR, H5E_CANTGET, FAIL, "can't get checksums");
236
237
0
        if (stored_chksum != computed_chksum)
238
0
            ret_value = false;
239
0
    }
240
0
    else
241
0
        assert(!(udata->common.file_intent & H5F_ACC_SWMR_WRITE));
242
243
0
done:
244
0
    FUNC_LEAVE_NOAPI(ret_value)
245
0
} /* end H5O__cache_verify_chksum() */
246
247
/*-------------------------------------------------------------------------
248
 * Function:    H5O__cache_deserialize
249
 *
250
 * Purpose:     Attempt to deserialize the object header contained in the
251
 *              supplied buffer, load the data into an instance of H5O_t, and
252
 *              return a pointer to the new instance.
253
 *
254
 *              Note that the object header is read with with a speculative
255
 *              read. If the initial read is too small, make note of this fact
256
 *              and return without error.  H5C__load_entry() will note the
257
 *              size discrepancy and retry the deserialize operation with
258
 *              the correct size read.
259
 *
260
 * Return:      Success:        Pointer to in core representation
261
 *              Failure:        NULL
262
 *-------------------------------------------------------------------------
263
 */
264
static void *
265
H5O__cache_deserialize(const void *image, size_t len, void *_udata, bool *dirty)
266
0
{
267
0
    H5O_t          *oh        = NULL;                     /* Object header read in */
268
0
    H5O_cache_ud_t *udata     = (H5O_cache_ud_t *)_udata; /* User data for callback */
269
0
    void           *ret_value = NULL;
270
271
0
    FUNC_ENTER_PACKAGE
272
273
0
    assert(image);
274
0
    assert(len > 0);
275
0
    assert(udata);
276
0
    assert(udata->common.f);
277
0
    assert(udata->common.cont_msg_info);
278
0
    assert(dirty);
279
0
    assert(udata->oh == NULL);
280
281
0
    if (H5O__prefix_deserialize((const uint8_t *)image, len, udata) < 0)
282
0
        HGOTO_ERROR(H5E_OHDR, H5E_CANTDECODE, NULL, "can't deserialize object header prefix");
283
0
    assert(udata->oh);
284
285
0
    oh = udata->oh;
286
287
    /* Set SWMR flag, if appropriate */
288
0
    oh->swmr_write = !!(H5F_INTENT(udata->common.f) & H5F_ACC_SWMR_WRITE);
289
290
    /* Create object header proxy if doing SWMR writes */
291
0
    if (oh->swmr_write) {
292
        /* Create virtual entry, for use as proxy */
293
0
        if (NULL == (oh->proxy = H5AC_proxy_entry_create()))
294
0
            HGOTO_ERROR(H5E_OHDR, H5E_CANTCREATE, NULL, "can't create object header proxy");
295
0
    }
296
0
    else
297
0
        oh->proxy = NULL;
298
299
    /* Parse the first chunk */
300
0
    if (H5O__chunk_deserialize(oh, udata->common.addr, udata->chunk0_size, (const uint8_t *)image, len,
301
0
                               &(udata->common), dirty) < 0)
302
0
        HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, NULL, "can't deserialize first object header chunk");
303
304
    /* Check for corruption in object header # of messages */
305
0
    if (oh->version == H5O_VERSION_1 && udata->v1_pfx_nmesgs < oh->nmesgs)
306
0
        HGOTO_ERROR(H5E_OHDR, H5E_BADVALUE, NULL, "bad object header message count");
307
308
    /* Note that we've loaded the object header from the file */
309
0
    udata->made_attempt = true;
310
311
    /* Set return value */
312
0
    ret_value = oh;
313
314
0
done:
315
    /* Release the [possibly partially initialized] object header on errors */
316
0
    if (!ret_value && oh)
317
0
        if (H5O__free(oh, false) < 0)
318
0
            HDONE_ERROR(H5E_OHDR, H5E_CANTRELEASE, NULL, "unable to destroy object header data");
319
320
    /* Release any continuation messages accumulated during the deserialize on
321
     *      error.  Normally the caller (H5O_protect) frees these after the
322
     *      object header is successfully loaded, but the caller can't do so
323
     *      if the object header failed to load (as its 'oh' is left NULL),
324
     *      so we must release them here to avoid leaking them.
325
     */
326
0
    if (!ret_value && udata->common.cont_msg_info->msgs)
327
0
        udata->common.cont_msg_info->msgs =
328
0
            (H5O_cont_t *)H5FL_SEQ_FREE(H5O_cont_t, udata->common.cont_msg_info->msgs);
329
330
0
    FUNC_LEAVE_NOAPI(ret_value)
331
0
} /* end H5O__cache_deserialize() */
332
333
/*-------------------------------------------------------------------------
334
 * Function:    H5O__cache_image_len
335
 *
336
 * Purpose:     Compute the size in bytes of the specified instance of
337
 *              H5O_t on disk, and return it in *image_len.  On failure,
338
 *              the value of *image_len is undefined.
339
 *
340
 * Return:      SUCCEED/FAIL
341
 *-------------------------------------------------------------------------
342
 */
343
static herr_t
344
H5O__cache_image_len(const void *_thing, size_t *image_len)
345
0
{
346
0
    const H5O_t *oh = (const H5O_t *)_thing; /* Object header to query */
347
348
0
    FUNC_ENTER_PACKAGE_NOERR
349
350
0
    assert(oh);
351
0
    assert(oh->cache_info.type == H5AC_OHDR);
352
0
    assert(image_len);
353
354
    /* Report the object header's prefix+first chunk length */
355
0
    *image_len = oh->chunk[0].size;
356
357
0
    FUNC_LEAVE_NOAPI(SUCCEED)
358
0
} /* end H5O__cache_image_len() */
359
360
/*-------------------------------------------------------------------------
361
 * Function:    H5O__cache_serialize
362
 *
363
 * Purpose:     Serialize the contents of the supplied object header, and
364
 *              load this data into the supplied buffer.
365
 *
366
 * Return:      SUCCEED/FAIL
367
 *-------------------------------------------------------------------------
368
 */
369
static herr_t
370
H5O__cache_serialize(const H5F_t *f, void *image, size_t len, void *_thing)
371
0
{
372
0
    H5O_t   *oh = (H5O_t *)_thing; /* Object header to encode */
373
0
    uint8_t *chunk_image;          /* Pointer to object header prefix buffer */
374
0
    herr_t   ret_value = SUCCEED;
375
376
0
    FUNC_ENTER_PACKAGE
377
378
0
    assert(f);
379
0
    assert(image);
380
0
    assert(oh);
381
0
    assert(oh->cache_info.type == H5AC_OHDR);
382
0
    assert(oh->chunk[0].size == len);
383
#ifdef H5O_DEBUG
384
    H5O__assert(oh);
385
#endif /* H5O_DEBUG */
386
387
    /* Point to raw data 'image' for first chunk, which
388
     * has room for the prefix
389
     */
390
0
    chunk_image = oh->chunk[0].image;
391
392
    /* Later versions of object header prefix have different format and
393
     * also require that chunk 0 always be updated, since the checksum
394
     * on the entire block of memory needs to be updated if anything is
395
     * modified
396
     */
397
0
    if (oh->version > H5O_VERSION_1) {
398
0
        uint64_t chunk0_size; /* Size of chunk 0's data */
399
400
0
        assert(oh->chunk[0].size >= (size_t)H5O_SIZEOF_HDR(oh));
401
0
        chunk0_size = oh->chunk[0].size - (size_t)H5O_SIZEOF_HDR(oh);
402
403
        /* Verify magic number */
404
0
        assert(!memcmp(chunk_image, H5O_HDR_MAGIC, H5_SIZEOF_MAGIC));
405
0
        chunk_image += H5_SIZEOF_MAGIC;
406
407
        /* Version */
408
0
        *chunk_image++ = oh->version;
409
410
        /* Flags */
411
0
        *chunk_image++ = oh->flags;
412
413
        /* Time fields */
414
0
        if (oh->flags & H5O_HDR_STORE_TIMES) {
415
0
            UINT32ENCODE(chunk_image, oh->atime);
416
0
            UINT32ENCODE(chunk_image, oh->mtime);
417
0
            UINT32ENCODE(chunk_image, oh->ctime);
418
0
            UINT32ENCODE(chunk_image, oh->btime);
419
0
        }
420
421
        /* Attribute fields */
422
0
        if (oh->flags & H5O_HDR_ATTR_STORE_PHASE_CHANGE) {
423
0
            UINT16ENCODE(chunk_image, oh->max_compact);
424
0
            UINT16ENCODE(chunk_image, oh->min_dense);
425
0
        }
426
427
        /* First chunk size */
428
0
        switch (oh->flags & H5O_HDR_CHUNK0_SIZE) {
429
0
            case 0: /* 1 byte size */
430
0
                assert(chunk0_size < 256);
431
0
                *chunk_image++ = (uint8_t)chunk0_size;
432
0
                break;
433
434
0
            case 1: /* 2 byte size */
435
0
                assert(chunk0_size < 65536);
436
0
                UINT16ENCODE(chunk_image, chunk0_size);
437
0
                break;
438
439
0
            case 2: /* 4 byte size */
440
                /* use <= 2**32 -1 to stay within 4 bytes integer range */
441
0
                assert(chunk0_size <= 4294967295UL);
442
0
                UINT32ENCODE(chunk_image, chunk0_size);
443
0
                break;
444
445
0
            case 3: /* 8 byte size */
446
0
                UINT64ENCODE(chunk_image, chunk0_size);
447
0
                break;
448
449
0
            default:
450
0
                HGOTO_ERROR(H5E_OHDR, H5E_BADVALUE, FAIL, "bad size for chunk 0");
451
0
        }
452
0
    }
453
0
    else {
454
        /* Version */
455
0
        *chunk_image++ = oh->version;
456
457
        /* Reserved */
458
0
        *chunk_image++ = 0;
459
460
        /* Number of messages */
461
#ifdef H5O_ENABLE_BAD_MESG_COUNT
462
        if (oh->store_bad_mesg_count)
463
            UINT16ENCODE(chunk_image, (oh->nmesgs - 1));
464
        else
465
#endif /* H5O_ENABLE_BAD_MESG_COUNT */
466
0
            UINT16ENCODE(chunk_image, oh->nmesgs);
467
468
        /* Link count */
469
0
        UINT32ENCODE(chunk_image, oh->nlink);
470
471
        /* First chunk size */
472
0
        UINT32ENCODE(chunk_image, (oh->chunk[0].size - (size_t)H5O_SIZEOF_HDR(oh)));
473
474
        /* Zero to alignment */
475
0
        memset(chunk_image, 0, (size_t)(H5O_SIZEOF_HDR(oh) - 12));
476
0
        chunk_image += (size_t)(H5O_SIZEOF_HDR(oh) - 12);
477
0
    }
478
479
0
    assert((size_t)(chunk_image - oh->chunk[0].image) ==
480
0
           (size_t)(H5O_SIZEOF_HDR(oh) - H5O_SIZEOF_CHKSUM_OH(oh)));
481
482
    /* Serialize messages for this chunk */
483
0
    if (H5O__chunk_serialize(f, oh, (unsigned)0) < 0)
484
0
        HGOTO_ERROR(H5E_OHDR, H5E_CANTSERIALIZE, FAIL, "unable to serialize first object header chunk");
485
486
    /* copy the chunk into the image -- this is potentially expensive.
487
     * Can we rework things so that the object header and the cache
488
     * share a buffer?
489
     */
490
0
    H5MM_memcpy(image, oh->chunk[0].image, len);
491
492
0
done:
493
0
    FUNC_LEAVE_NOAPI(ret_value)
494
0
} /* end H5O__cache_serialize() */
495
496
/*-------------------------------------------------------------------------
497
 * Function:    H5O__cache_notify
498
 *
499
 * Purpose:     Handle cache action notifications
500
 *
501
 * Return:      SUCCEED/FAIL
502
 *-------------------------------------------------------------------------
503
 */
504
static herr_t
505
H5O__cache_notify(H5AC_notify_action_t action, void *_thing)
506
0
{
507
0
    H5O_t *oh        = (H5O_t *)_thing;
508
0
    herr_t ret_value = SUCCEED;
509
510
0
    FUNC_ENTER_PACKAGE
511
512
0
    assert(oh);
513
514
0
    switch (action) {
515
0
        case H5AC_NOTIFY_ACTION_AFTER_INSERT:
516
0
        case H5AC_NOTIFY_ACTION_AFTER_LOAD:
517
0
            if (oh->swmr_write) {
518
                /* Sanity check */
519
0
                assert(oh->proxy);
520
521
                /* Register the object header as a parent of the virtual entry */
522
0
                if (H5AC_proxy_entry_add_parent(oh->proxy, oh) < 0)
523
0
                    HGOTO_ERROR(H5E_OHDR, H5E_CANTSET, FAIL, "can't add object header as parent of proxy");
524
0
            }
525
0
            break;
526
527
0
        case H5AC_NOTIFY_ACTION_AFTER_FLUSH:
528
0
        case H5AC_NOTIFY_ACTION_ENTRY_DIRTIED:
529
            /* Do nothing */
530
0
            break;
531
532
0
        case H5AC_NOTIFY_ACTION_ENTRY_CLEANED: {
533
0
            unsigned u; /* Local index variable */
534
535
            /* Mark messages stored with the object header (i.e. messages in chunk 0) as clean */
536
0
            for (u = 0; u < oh->nmesgs; u++)
537
0
                if (oh->mesg[u].chunkno == 0)
538
0
                    oh->mesg[u].dirty = false;
539
#ifndef NDEBUG
540
            /* Reset the number of messages dirtied by decoding */
541
            oh->ndecode_dirtied = 0;
542
#endif
543
0
        } break;
544
545
0
        case H5AC_NOTIFY_ACTION_CHILD_DIRTIED:
546
0
        case H5AC_NOTIFY_ACTION_CHILD_CLEANED:
547
0
        case H5AC_NOTIFY_ACTION_CHILD_UNSERIALIZED:
548
0
        case H5AC_NOTIFY_ACTION_CHILD_SERIALIZED:
549
            /* Do nothing */
550
0
            break;
551
552
0
        case H5AC_NOTIFY_ACTION_BEFORE_EVICT:
553
0
            if (oh->swmr_write) {
554
                /* Unregister the object header as a parent of the virtual entry */
555
0
                if (H5AC_proxy_entry_remove_parent(oh->proxy, oh) < 0)
556
0
                    HGOTO_ERROR(H5E_OHDR, H5E_CANTSET, FAIL, "can't remove object header as parent of proxy");
557
0
            }
558
0
            break;
559
560
0
        default:
561
0
            HGOTO_ERROR(H5E_OHDR, H5E_BADVALUE, FAIL, "unknown action from metadata cache");
562
0
    }
563
564
0
done:
565
0
    FUNC_LEAVE_NOAPI(ret_value)
566
0
} /* end H5O__cache_notify() */
567
568
/*-------------------------------------------------------------------------
569
 * Function:    H5O__cache_free_icr
570
 *
571
 * Purpose:     Free the in core representation of the supplied object header.
572
 *
573
 * Return:      SUCCEED/FAIL
574
 *-------------------------------------------------------------------------
575
 */
576
static herr_t
577
H5O__cache_free_icr(void *_thing)
578
0
{
579
0
    H5O_t *oh        = (H5O_t *)_thing; /* Object header to destroy */
580
0
    herr_t ret_value = SUCCEED;
581
582
0
    FUNC_ENTER_PACKAGE
583
584
0
    assert(oh);
585
0
    assert(oh->cache_info.type == H5AC_OHDR);
586
587
    /* Destroy object header */
588
0
    if (H5O__free(oh, false) < 0)
589
0
        HGOTO_ERROR(H5E_OHDR, H5E_CANTRELEASE, FAIL, "can't destroy object header");
590
591
0
done:
592
0
    FUNC_LEAVE_NOAPI(ret_value)
593
0
} /* end H5O__cache_free_icr() */
594
595
/*-------------------------------------------------------------------------
596
 * Function:    H5O__cache_chk_get_initial_load_size()
597
 *
598
 * Purpose:     Tell the metadata cache how large the on disk image of the
599
 *              chunk proxy is, so it can load the image into a buffer for the
600
 *              deserialize call.
601
 *
602
 * Return:      SUCCEED/FAIL
603
 *-------------------------------------------------------------------------
604
 */
605
static herr_t
606
H5O__cache_chk_get_initial_load_size(void *_udata, size_t *image_len)
607
0
{
608
0
    const H5O_chk_cache_ud_t *udata = (const H5O_chk_cache_ud_t *)_udata; /* User data for callback */
609
610
0
    FUNC_ENTER_PACKAGE_NOERR
611
612
0
    assert(udata);
613
0
    assert(udata->oh);
614
0
    assert(image_len);
615
0
    assert(udata->size);
616
617
    /* Set the image length size */
618
0
    *image_len = udata->size;
619
620
0
    FUNC_LEAVE_NOAPI(SUCCEED)
621
0
} /* end H5O__cache_chk_get_initial_load_size() */
622
623
/*-------------------------------------------------------------------------
624
 * Function:    H5B2__cache_chk_verify_chksum
625
 *
626
 * Purpose:     Verify the computed checksum of the data structure is the
627
 *              same as the stored chksum.
628
 *
629
 * Return:      Success:        true/false
630
 *              Failure:        Negative
631
 *-------------------------------------------------------------------------
632
 */
633
static htri_t
634
H5O__cache_chk_verify_chksum(const void *_image, size_t len, void *_udata)
635
0
{
636
0
    const uint8_t      *image     = (const uint8_t *)_image;      /* Pointer into raw data buffer */
637
0
    H5O_chk_cache_ud_t *udata     = (H5O_chk_cache_ud_t *)_udata; /* User data for callback */
638
0
    htri_t              ret_value = true;
639
640
0
    FUNC_ENTER_PACKAGE
641
642
0
    assert(image);
643
644
    /* There is no checksum for version 1 */
645
0
    if (udata->oh->version != H5O_VERSION_1) {
646
0
        uint32_t stored_chksum;   /* Stored metadata checksum value */
647
0
        uint32_t computed_chksum; /* Computed metadata checksum value */
648
649
        /* Get stored and computed checksums */
650
0
        if (H5F_get_checksums(image, len, &stored_chksum, &computed_chksum) < 0)
651
0
            HGOTO_ERROR(H5E_OHDR, H5E_CANTGET, FAIL, "can't get checksums");
652
653
0
        if (stored_chksum != computed_chksum)
654
0
            ret_value = false;
655
0
    }
656
657
0
done:
658
0
    FUNC_LEAVE_NOAPI(ret_value)
659
0
} /* end H5O__cache_chk_verify_chksum() */
660
661
/*-------------------------------------------------------------------------
662
 * Function:    H5O__cache_chk_deserialize
663
 *
664
 * Purpose:     Attempt to deserialize the object header continuation chunk
665
 *              contained in the supplied buffer, load the data into an instance
666
 *              of H5O_chunk_proxy_t, and return a pointer to the new instance.
667
 *
668
 * Return:      Success:        Pointer to in core representation
669
 *              Failure:        NULL
670
 *-------------------------------------------------------------------------
671
 */
672
static void *
673
H5O__cache_chk_deserialize(const void *image, size_t len, void *_udata, bool *dirty)
674
0
{
675
0
    H5O_chunk_proxy_t  *chk_proxy = NULL;                         /* Chunk proxy object */
676
0
    H5O_chk_cache_ud_t *udata     = (H5O_chk_cache_ud_t *)_udata; /* User data for callback */
677
0
    void               *ret_value = NULL;
678
679
0
    FUNC_ENTER_PACKAGE
680
681
0
    assert(image);
682
0
    assert(len > 0);
683
0
    assert(udata);
684
0
    assert(udata->oh);
685
0
    assert(dirty);
686
687
    /* Allocate space for the object header data structure */
688
0
    if (NULL == (chk_proxy = H5FL_CALLOC(H5O_chunk_proxy_t)))
689
0
        HGOTO_ERROR(H5E_OHDR, H5E_CANTALLOC, NULL, "memory allocation failed");
690
691
    /* Check if we are still decoding the object header */
692
    /* (as opposed to bringing a piece of it back from the file) */
693
0
    if (udata->decoding) {
694
0
        assert(udata->common.f);
695
0
        assert(udata->common.cont_msg_info);
696
697
        /* Parse the chunk */
698
0
        if (H5O__chunk_deserialize(udata->oh, udata->common.addr, udata->size, (const uint8_t *)image, len,
699
0
                                   &(udata->common), dirty) < 0)
700
0
            HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, NULL, "can't deserialize object header chunk");
701
702
        /* Set the chunk number for the chunk proxy */
703
0
        H5_CHECKED_ASSIGN(chk_proxy->chunkno, unsigned, udata->oh->nchunks - 1, size_t);
704
0
    }
705
0
    else {
706
        /* Sanity check */
707
0
        assert(udata->chunkno < udata->oh->nchunks);
708
709
        /* Set the chunk number for the chunk proxy */
710
0
        chk_proxy->chunkno = udata->chunkno;
711
712
        /* Sanity check that the chunk representation we have in memory is
713
         * the same as the one being brought in from disk.
714
         */
715
0
        assert(0 == memcmp(image, udata->oh->chunk[chk_proxy->chunkno].image,
716
0
                           udata->oh->chunk[chk_proxy->chunkno].size));
717
0
    }
718
719
    /* Increment reference count of object header */
720
0
    if (H5O__inc_rc(udata->oh) < 0)
721
0
        HGOTO_ERROR(H5E_OHDR, H5E_CANTINC, NULL, "can't increment reference count on object header");
722
0
    chk_proxy->oh = udata->oh;
723
724
    /* Set return value */
725
0
    ret_value = chk_proxy;
726
727
0
done:
728
0
    if (NULL == ret_value)
729
0
        if (chk_proxy && H5O__chunk_dest(chk_proxy) < 0)
730
0
            HDONE_ERROR(H5E_OHDR, H5E_CANTRELEASE, NULL, "unable to destroy object header chunk");
731
732
0
    FUNC_LEAVE_NOAPI(ret_value)
733
0
} /* end H5O__cache_chk_deserialize() */
734
735
/*-------------------------------------------------------------------------
736
 * Function:    H5O__cache_chk_image_len
737
 *
738
 * Purpose:     Return the on disk image size of a object header chunk to the
739
 *              metadata cache via the image_len.
740
 *
741
 * Return:      SUCCEED/FAIL
742
 *-------------------------------------------------------------------------
743
 */
744
static herr_t
745
H5O__cache_chk_image_len(const void *_thing, size_t *image_len)
746
0
{
747
0
    const H5O_chunk_proxy_t *chk_proxy = (const H5O_chunk_proxy_t *)_thing; /* Chunk proxy to query */
748
749
0
    FUNC_ENTER_PACKAGE_NOERR
750
751
0
    assert(chk_proxy);
752
0
    assert(chk_proxy->cache_info.type == H5AC_OHDR_CHK);
753
0
    assert(chk_proxy->oh);
754
0
    assert(image_len);
755
756
0
    *image_len = chk_proxy->oh->chunk[chk_proxy->chunkno].size;
757
758
0
    FUNC_LEAVE_NOAPI(SUCCEED)
759
0
} /* end H5O__cache_chk_image_len() */
760
761
/*-------------------------------------------------------------------------
762
 * Function:    H5O__cache_chk_serialize
763
 *
764
 * Purpose:     Given a pointer to an instance of an object header chunk and an
765
 *              appropriately sized buffer, serialize the contents of the
766
 *              instance for writing to disk, and copy the serialized data
767
 *              into the buffer.
768
 *
769
 * Return:      SUCCEED/FAIL
770
 *-------------------------------------------------------------------------
771
 */
772
static herr_t
773
H5O__cache_chk_serialize(const H5F_t *f, void *image, size_t len, void *_thing)
774
0
{
775
0
    H5O_chunk_proxy_t *chk_proxy = (H5O_chunk_proxy_t *)_thing; /* Object header chunk to serialize */
776
0
    herr_t             ret_value = SUCCEED;
777
778
0
    FUNC_ENTER_PACKAGE
779
780
0
    assert(f);
781
0
    assert(image);
782
0
    assert(chk_proxy);
783
0
    assert(chk_proxy->cache_info.type == H5AC_OHDR_CHK);
784
0
    assert(chk_proxy->oh);
785
0
    assert(chk_proxy->oh->chunk[chk_proxy->chunkno].size == len);
786
787
    /* Serialize messages for this chunk */
788
0
    if (H5O__chunk_serialize(f, chk_proxy->oh, chk_proxy->chunkno) < 0)
789
0
        HGOTO_ERROR(H5E_OHDR, H5E_CANTSERIALIZE, FAIL,
790
0
                    "unable to serialize object header continuation chunk");
791
792
    /* copy the chunk into the image -- this is potentially expensive.
793
     * Can we rework things so that the chunk and the cache share a buffer?
794
     */
795
    /* Ensure len does not exceed the size of the source buffer */
796
0
    if (len > chk_proxy->oh->chunk[chk_proxy->chunkno].size)
797
0
        HGOTO_ERROR(H5E_OHDR, H5E_OVERFLOW, FAIL, "buffer overflow detected");
798
799
0
    H5MM_memcpy(image, chk_proxy->oh->chunk[chk_proxy->chunkno].image, len);
800
801
0
done:
802
0
    FUNC_LEAVE_NOAPI(ret_value)
803
0
} /* end H5O__cache_chk_serialize() */
804
805
/*-------------------------------------------------------------------------
806
 * Function:    H5O__cache_chk_notify
807
 *
808
 * Purpose:     Handle cache action notifications
809
 *
810
 * Return:      SUCCEED/FAIL
811
 *-------------------------------------------------------------------------
812
 */
813
static herr_t
814
H5O__cache_chk_notify(H5AC_notify_action_t action, void *_thing)
815
0
{
816
0
    H5O_chunk_proxy_t *chk_proxy = (H5O_chunk_proxy_t *)_thing;
817
0
    herr_t             ret_value = SUCCEED;
818
819
0
    FUNC_ENTER_PACKAGE
820
821
0
    assert(chk_proxy);
822
0
    assert(chk_proxy->oh);
823
824
0
    switch (action) {
825
0
        case H5AC_NOTIFY_ACTION_AFTER_INSERT:
826
0
        case H5AC_NOTIFY_ACTION_AFTER_LOAD:
827
0
            if (chk_proxy->oh->swmr_write) {
828
                /* Add flush dependency on chunk with continuation, if one exists */
829
0
                if (chk_proxy->fd_parent) {
830
                    /* Sanity checks */
831
0
                    assert(((H5C_cache_entry_t *)(chk_proxy->fd_parent))->type);
832
0
                    assert((((H5C_cache_entry_t *)(chk_proxy->fd_parent))->type->id == H5AC_OHDR_ID) ||
833
0
                           (((H5C_cache_entry_t *)(chk_proxy->fd_parent))->type->id == H5AC_OHDR_CHK_ID));
834
835
                    /* Add flush dependency from chunk containing the continuation message
836
                     * that points to this chunk (either oh or another chunk proxy object)
837
                     */
838
0
                    if (H5AC_create_flush_dependency(chk_proxy->fd_parent, chk_proxy) < 0)
839
0
                        HGOTO_ERROR(H5E_OHDR, H5E_CANTDEPEND, FAIL, "unable to create flush dependency");
840
0
                }
841
842
                /* Add flush dependency on object header */
843
0
                {
844
0
                    if (H5AC_create_flush_dependency(chk_proxy->oh, chk_proxy) < 0)
845
0
                        HGOTO_ERROR(H5E_OHDR, H5E_CANTDEPEND, FAIL, "unable to create flush dependency");
846
0
                }
847
848
                /* Add flush dependency on object header proxy, if proxy exists */
849
0
                {
850
                    /* Sanity check */
851
0
                    assert(chk_proxy->oh->proxy);
852
853
                    /* Register the object header chunk as a parent of the virtual entry */
854
0
                    if (H5AC_proxy_entry_add_parent(chk_proxy->oh->proxy, chk_proxy) < 0)
855
0
                        HGOTO_ERROR(H5E_OHDR, H5E_CANTSET, FAIL,
856
0
                                    "can't add object header chunk as parent of proxy");
857
0
                }
858
0
            }
859
0
            break;
860
861
0
        case H5AC_NOTIFY_ACTION_AFTER_FLUSH:
862
0
        case H5AC_NOTIFY_ACTION_ENTRY_DIRTIED:
863
            /* Do nothing */
864
0
            break;
865
866
0
        case H5AC_NOTIFY_ACTION_ENTRY_CLEANED: {
867
0
            unsigned u; /* Local index variable */
868
869
            /* Mark messages in chunk as clean */
870
0
            for (u = 0; u < chk_proxy->oh->nmesgs; u++)
871
0
                if (chk_proxy->oh->mesg[u].chunkno == chk_proxy->chunkno)
872
0
                    chk_proxy->oh->mesg[u].dirty = false;
873
0
        } break;
874
875
0
        case H5AC_NOTIFY_ACTION_CHILD_DIRTIED:
876
0
        case H5AC_NOTIFY_ACTION_CHILD_CLEANED:
877
0
        case H5AC_NOTIFY_ACTION_CHILD_UNSERIALIZED:
878
0
        case H5AC_NOTIFY_ACTION_CHILD_SERIALIZED:
879
            /* Do nothing */
880
0
            break;
881
882
0
        case H5AC_NOTIFY_ACTION_BEFORE_EVICT:
883
0
            if (chk_proxy->oh->swmr_write) {
884
                /* Remove flush dependency on parent object header chunk, if one is set */
885
0
                if (chk_proxy->fd_parent) {
886
                    /* Sanity checks */
887
0
                    assert(((H5C_cache_entry_t *)(chk_proxy->fd_parent))->type);
888
0
                    assert((((H5C_cache_entry_t *)(chk_proxy->fd_parent))->type->id == H5AC_OHDR_ID) ||
889
0
                           (((H5C_cache_entry_t *)(chk_proxy->fd_parent))->type->id == H5AC_OHDR_CHK_ID));
890
891
0
                    if (H5AC_destroy_flush_dependency(chk_proxy->fd_parent, chk_proxy) < 0)
892
0
                        HGOTO_ERROR(H5E_OHDR, H5E_CANTUNDEPEND, FAIL, "unable to destroy flush dependency");
893
0
                    chk_proxy->fd_parent = NULL;
894
0
                }
895
896
                /* Unregister the object header as a parent of the virtual entry */
897
0
                if (H5AC_destroy_flush_dependency(chk_proxy->oh, chk_proxy) < 0)
898
0
                    HGOTO_ERROR(H5E_OHDR, H5E_CANTUNDEPEND, FAIL, "unable to destroy flush dependency");
899
900
                /* Unregister the object header chunk as a parent of the virtual entry */
901
0
                if (H5AC_proxy_entry_remove_parent(chk_proxy->oh->proxy, chk_proxy) < 0)
902
0
                    HGOTO_ERROR(H5E_OHDR, H5E_CANTSET, FAIL,
903
0
                                "can't remove object header chunk as parent of proxy");
904
0
            }
905
0
            break;
906
907
0
        default:
908
0
            HGOTO_ERROR(H5E_OHDR, H5E_BADVALUE, FAIL, "unknown action from metadata cache");
909
0
    }
910
911
0
done:
912
0
    FUNC_LEAVE_NOAPI(ret_value)
913
0
} /* end H5O__cache_chk_notify() */
914
915
/*-------------------------------------------------------------------------
916
 * Function:    H5O__cache_chk_free_icr
917
 *
918
 * Purpose:     Free the in core memory associated with the supplied object
919
 *              header continuation chunk.
920
 *
921
 * Return:      SUCCEED/FAIL
922
 *-------------------------------------------------------------------------
923
 */
924
static herr_t
925
H5O__cache_chk_free_icr(void *_thing)
926
0
{
927
0
    H5O_chunk_proxy_t *chk_proxy = (H5O_chunk_proxy_t *)_thing; /* Object header chunk proxy to release */
928
0
    herr_t             ret_value = SUCCEED;
929
930
0
    FUNC_ENTER_PACKAGE
931
932
0
    assert(chk_proxy);
933
0
    assert(chk_proxy->cache_info.type == H5AC_OHDR_CHK);
934
935
    /* Destroy object header chunk proxy */
936
0
    if (H5O__chunk_dest(chk_proxy) < 0)
937
0
        HGOTO_ERROR(H5E_OHDR, H5E_CANTRELEASE, FAIL, "unable to destroy object header chunk proxy");
938
939
0
done:
940
0
    FUNC_LEAVE_NOAPI(ret_value)
941
0
} /* end H5O__cache_chk_free_icr() */
942
943
/*-------------------------------------------------------------------------
944
 * Function:  H5O__add_cont_msg
945
 *
946
 * Purpose:     Add information from a continuation message to the list of
947
 *              continuation messages in the object header
948
 *
949
 * Return:      SUCCEED/FAIL
950
 *-------------------------------------------------------------------------
951
 */
952
static herr_t
953
H5O__add_cont_msg(H5O_cont_msgs_t *cont_msg_info, const H5O_cont_t *cont)
954
0
{
955
0
    size_t contno; /* Continuation message index */
956
0
    herr_t ret_value = SUCCEED;
957
958
0
    FUNC_ENTER_PACKAGE
959
960
0
    assert(cont_msg_info);
961
0
    assert(cont);
962
963
    /* Increase chunk array size, if necessary */
964
0
    if (cont_msg_info->nmsgs >= cont_msg_info->alloc_nmsgs) {
965
0
        size_t na = MAX(H5O_NCHUNKS, cont_msg_info->alloc_nmsgs * 2); /* Double # of messages allocated */
966
0
        H5O_cont_t *x;
967
968
0
        if (NULL == (x = H5FL_SEQ_REALLOC(H5O_cont_t, cont_msg_info->msgs, na)))
969
0
            HGOTO_ERROR(H5E_OHDR, H5E_NOSPACE, FAIL, "memory allocation failed");
970
0
        cont_msg_info->alloc_nmsgs = na;
971
0
        cont_msg_info->msgs        = x;
972
0
    }
973
974
    /* Init the continuation message info */
975
0
    contno                              = cont_msg_info->nmsgs++;
976
0
    cont_msg_info->msgs[contno].addr    = cont->addr;
977
0
    cont_msg_info->msgs[contno].size    = cont->size;
978
0
    cont_msg_info->msgs[contno].chunkno = cont->chunkno;
979
980
0
done:
981
0
    FUNC_LEAVE_NOAPI(ret_value)
982
0
} /* H5O__add_cont_msg() */
983
984
/*-------------------------------------------------------------------------
985
 * Function:    H5O__prefix_deserialize()
986
 *
987
 * Purpose:     Deserialize an object header prefix
988
 *
989
 * Return:      SUCCEED/FAIL
990
 *-------------------------------------------------------------------------
991
 */
992
static herr_t
993
H5O__prefix_deserialize(const uint8_t *_image, size_t len, H5O_cache_ud_t *udata)
994
0
{
995
0
    const uint8_t *image     = (const uint8_t *)_image; /* Pointer into raw data buffer */
996
0
    const uint8_t *p_end     = image + len - 1;         /* End of image buffer */
997
0
    H5O_t         *oh        = NULL;                    /* Object header read in */
998
0
    herr_t         ret_value = SUCCEED;
999
1000
0
    FUNC_ENTER_PACKAGE
1001
1002
0
    assert(image);
1003
0
    assert(udata);
1004
1005
    /* Allocate space for the new object header data structure */
1006
0
    if (NULL == (oh = H5FL_CALLOC(H5O_t)))
1007
0
        HGOTO_ERROR(H5E_OHDR, H5E_CANTALLOC, FAIL, "memory allocation failed");
1008
1009
    /* File-specific, non-stored information */
1010
0
    oh->sizeof_size = H5F_SIZEOF_SIZE(udata->common.f);
1011
0
    oh->sizeof_addr = H5F_SIZEOF_ADDR(udata->common.f);
1012
1013
    /* Check for presence of magic number */
1014
    /* (indicates version 2 or later) */
1015
0
    if (H5_IS_BUFFER_OVERFLOW(image, H5_SIZEOF_MAGIC, p_end))
1016
0
        HGOTO_ERROR(H5E_OHDR, H5E_OVERFLOW, FAIL, "ran off end of input buffer while decoding");
1017
0
    if (!memcmp(image, H5O_HDR_MAGIC, (size_t)H5_SIZEOF_MAGIC)) {
1018
1019
        /* Magic number (bounds checked above) */
1020
0
        image += H5_SIZEOF_MAGIC;
1021
1022
        /* Version */
1023
0
        if (H5_IS_BUFFER_OVERFLOW(image, 1, p_end))
1024
0
            HGOTO_ERROR(H5E_OHDR, H5E_OVERFLOW, FAIL, "ran off end of input buffer while decoding");
1025
0
        oh->version = *image++;
1026
0
        if (H5O_VERSION_2 != oh->version)
1027
0
            HGOTO_ERROR(H5E_OHDR, H5E_VERSION, FAIL, "bad object header version number");
1028
1029
        /* Flags */
1030
0
        if (H5_IS_BUFFER_OVERFLOW(image, 1, p_end))
1031
0
            HGOTO_ERROR(H5E_OHDR, H5E_OVERFLOW, FAIL, "ran off end of input buffer while decoding");
1032
0
        oh->flags = *image++;
1033
0
        if (oh->flags & ~H5O_HDR_ALL_FLAGS)
1034
0
            HGOTO_ERROR(H5E_OHDR, H5E_BADVALUE, FAIL, "unknown object header status flag(s)");
1035
1036
        /* Number of links to object (unless overridden by refcount message) */
1037
0
        oh->nlink = 1;
1038
1039
        /* Time fields */
1040
0
        if (oh->flags & H5O_HDR_STORE_TIMES) {
1041
0
            uint32_t tmp;
1042
1043
0
            if (H5_IS_BUFFER_OVERFLOW(image, 4 + 4 + 4 + 4, p_end))
1044
0
                HGOTO_ERROR(H5E_OHDR, H5E_OVERFLOW, FAIL, "ran off end of input buffer while decoding");
1045
1046
0
            UINT32DECODE(image, tmp);
1047
0
            oh->atime = (time_t)tmp;
1048
0
            UINT32DECODE(image, tmp);
1049
0
            oh->mtime = (time_t)tmp;
1050
0
            UINT32DECODE(image, tmp);
1051
0
            oh->ctime = (time_t)tmp;
1052
0
            UINT32DECODE(image, tmp);
1053
0
            oh->btime = (time_t)tmp;
1054
0
        }
1055
0
        else
1056
0
            oh->atime = oh->mtime = oh->ctime = oh->btime = 0;
1057
1058
        /* Attribute fields */
1059
0
        if (oh->flags & H5O_HDR_ATTR_STORE_PHASE_CHANGE) {
1060
0
            if (H5_IS_BUFFER_OVERFLOW(image, 2 + 2, p_end))
1061
0
                HGOTO_ERROR(H5E_OHDR, H5E_OVERFLOW, FAIL, "ran off end of input buffer while decoding");
1062
1063
0
            UINT16DECODE(image, oh->max_compact);
1064
0
            UINT16DECODE(image, oh->min_dense);
1065
0
            if (oh->max_compact < oh->min_dense)
1066
0
                HGOTO_ERROR(H5E_OHDR, H5E_BADVALUE, FAIL, "bad object header attribute phase change values");
1067
0
        }
1068
0
        else {
1069
0
            oh->max_compact = H5O_CRT_ATTR_MAX_COMPACT_DEF;
1070
0
            oh->min_dense   = H5O_CRT_ATTR_MIN_DENSE_DEF;
1071
0
        }
1072
1073
        /* First chunk size */
1074
0
        switch (oh->flags & H5O_HDR_CHUNK0_SIZE) {
1075
0
            case 0: /* 1 byte size */
1076
0
                if (H5_IS_BUFFER_OVERFLOW(image, 1, p_end))
1077
0
                    HGOTO_ERROR(H5E_OHDR, H5E_OVERFLOW, FAIL, "ran off end of input buffer while decoding");
1078
0
                udata->chunk0_size = *image++;
1079
0
                break;
1080
1081
0
            case 1: /* 2 byte size */
1082
0
                if (H5_IS_BUFFER_OVERFLOW(image, 2, p_end))
1083
0
                    HGOTO_ERROR(H5E_OHDR, H5E_OVERFLOW, FAIL, "ran off end of input buffer while decoding");
1084
0
                UINT16DECODE(image, udata->chunk0_size);
1085
0
                break;
1086
1087
0
            case 2: /* 4 byte size */
1088
0
                if (H5_IS_BUFFER_OVERFLOW(image, 4, p_end))
1089
0
                    HGOTO_ERROR(H5E_OHDR, H5E_OVERFLOW, FAIL, "ran off end of input buffer while decoding");
1090
0
                UINT32DECODE(image, udata->chunk0_size);
1091
0
                break;
1092
1093
0
            case 3: /* 8 byte size */
1094
0
                if (H5_IS_BUFFER_OVERFLOW(image, 8, p_end))
1095
0
                    HGOTO_ERROR(H5E_OHDR, H5E_OVERFLOW, FAIL, "ran off end of input buffer while decoding");
1096
0
                UINT64DECODE(image, udata->chunk0_size);
1097
0
                break;
1098
1099
0
            default:
1100
0
                HGOTO_ERROR(H5E_OHDR, H5E_BADVALUE, FAIL, "bad size for chunk 0");
1101
0
        }
1102
0
        if (udata->chunk0_size > 0 && udata->chunk0_size < H5O_SIZEOF_MSGHDR_OH(oh))
1103
0
            HGOTO_ERROR(H5E_OHDR, H5E_BADVALUE, FAIL, "bad object header chunk size");
1104
0
    }
1105
0
    else {
1106
        /* Version */
1107
0
        if (H5_IS_BUFFER_OVERFLOW(image, 1, p_end))
1108
0
            HGOTO_ERROR(H5E_OHDR, H5E_OVERFLOW, FAIL, "ran off end of input buffer while decoding");
1109
0
        oh->version = *image++;
1110
0
        if (H5O_VERSION_1 != oh->version)
1111
0
            HGOTO_ERROR(H5E_OHDR, H5E_VERSION, FAIL, "bad object header version number");
1112
1113
        /* Flags */
1114
0
        oh->flags = H5O_CRT_OHDR_FLAGS_DEF;
1115
1116
        /* Reserved */
1117
0
        if (H5_IS_BUFFER_OVERFLOW(image, 1, p_end))
1118
0
            HGOTO_ERROR(H5E_OHDR, H5E_OVERFLOW, FAIL, "ran off end of input buffer while decoding");
1119
0
        image++;
1120
1121
        /* Number of messages */
1122
0
        if (H5_IS_BUFFER_OVERFLOW(image, 2, p_end))
1123
0
            HGOTO_ERROR(H5E_OHDR, H5E_OVERFLOW, FAIL, "ran off end of input buffer while decoding");
1124
0
        UINT16DECODE(image, udata->v1_pfx_nmesgs);
1125
1126
        /* Link count */
1127
0
        if (H5_IS_BUFFER_OVERFLOW(image, 4, p_end))
1128
0
            HGOTO_ERROR(H5E_OHDR, H5E_OVERFLOW, FAIL, "ran off end of input buffer while decoding");
1129
0
        UINT32DECODE(image, oh->nlink);
1130
1131
        /* Reset unused time fields */
1132
0
        oh->atime = oh->mtime = oh->ctime = oh->btime = 0;
1133
1134
        /* Reset unused attribute fields */
1135
0
        oh->max_compact = 0;
1136
0
        oh->min_dense   = 0;
1137
1138
        /* First chunk size */
1139
0
        if (H5_IS_BUFFER_OVERFLOW(image, 4, p_end))
1140
0
            HGOTO_ERROR(H5E_OHDR, H5E_OVERFLOW, FAIL, "ran off end of input buffer while decoding");
1141
0
        UINT32DECODE(image, udata->chunk0_size);
1142
0
        if ((udata->v1_pfx_nmesgs > 0 && udata->chunk0_size < H5O_SIZEOF_MSGHDR_OH(oh)) ||
1143
0
            (udata->v1_pfx_nmesgs == 0 && udata->chunk0_size > 0))
1144
0
            HGOTO_ERROR(H5E_OHDR, H5E_BADVALUE, FAIL, "bad object header chunk size");
1145
1146
        /* Reserved, in version 1 (for 8-byte alignment padding) */
1147
0
        if (H5_IS_BUFFER_OVERFLOW(image, 4, p_end))
1148
0
            HGOTO_ERROR(H5E_OHDR, H5E_OVERFLOW, FAIL, "ran off end of input buffer while decoding");
1149
0
        image += 4;
1150
0
    }
1151
1152
    /* Verify object header prefix length */
1153
0
    if ((size_t)(image - _image) != (size_t)(H5O_SIZEOF_HDR(oh) - H5O_SIZEOF_CHKSUM_OH(oh)))
1154
0
        HGOTO_ERROR(H5E_OHDR, H5E_BADVALUE, FAIL, "bad object header prefix length");
1155
1156
    /* Save the object header for later use in 'deserialize' callback */
1157
0
    udata->oh = oh;
1158
0
    oh        = NULL;
1159
1160
0
done:
1161
    /* Release the [possibly partially initialized] object header on errors */
1162
0
    if (ret_value < 0 && oh)
1163
0
        if (H5O__free(oh, false) < 0)
1164
0
            HDONE_ERROR(H5E_OHDR, H5E_CANTRELEASE, FAIL, "unable to destroy object header data");
1165
1166
0
    FUNC_LEAVE_NOAPI(ret_value)
1167
0
} /* end H5O__prefix_deserialize() */
1168
1169
/*-------------------------------------------------------------------------
1170
 * Function:  H5O__chunk_deserialize
1171
 *
1172
 * Purpose:     Deserialize a chunk for an object header
1173
 *
1174
 * Return:      SUCCEED/FAIL
1175
 *-------------------------------------------------------------------------
1176
 */
1177
static herr_t
1178
H5O__chunk_deserialize(H5O_t *oh, haddr_t addr, size_t chunk_size, const uint8_t *image, size_t len,
1179
                       H5O_common_cache_ud_t *udata, bool *dirty)
1180
0
{
1181
0
    const uint8_t *chunk_image = NULL;   /* Pointer into buffer to decode */
1182
0
    const uint8_t *p_end       = NULL;   /* End of image buffer */
1183
0
    uint8_t       *eom_ptr;              /* Pointer to end of messages for a chunk */
1184
0
    unsigned       merged_null_msgs = 0; /* Number of null messages merged together */
1185
0
    unsigned       chunkno;              /* Current chunk's index */
1186
0
    unsigned       nullcnt;              /* Count of null messages (for sanity checking gaps in chunks) */
1187
0
    bool           mesgs_modified =
1188
0
        false; /* Whether any messages were modified when the object header was deserialized */
1189
0
    herr_t ret_value = SUCCEED;
1190
1191
0
    FUNC_ENTER_PACKAGE
1192
1193
0
    assert(oh);
1194
0
    assert(H5_addr_defined(addr));
1195
0
    assert(image);
1196
0
    assert(len);
1197
0
    assert(udata->f);
1198
0
    assert(udata->cont_msg_info);
1199
1200
    /* Increase chunk array size, if necessary */
1201
0
    if (oh->nchunks >= oh->alloc_nchunks) {
1202
0
        size_t       na = MAX(H5O_NCHUNKS, oh->alloc_nchunks * 2); /* Double # of chunks allocated */
1203
0
        H5O_chunk_t *x;
1204
1205
0
        if (NULL == (x = H5FL_SEQ_REALLOC(H5O_chunk_t, oh->chunk, na)))
1206
0
            HGOTO_ERROR(H5E_OHDR, H5E_CANTALLOC, FAIL, "memory allocation failed");
1207
0
        oh->alloc_nchunks = na;
1208
0
        oh->chunk         = x;
1209
0
    }
1210
1211
    /* Init the chunk data info */
1212
0
    chunkno                 = (unsigned)oh->nchunks++;
1213
0
    oh->chunk[chunkno].gap  = 0;
1214
0
    oh->chunk[chunkno].addr = addr;
1215
0
    if (chunkno == 0)
1216
        /* First chunk's 'image' includes room for the object header prefix */
1217
0
        oh->chunk[0].size = chunk_size + (size_t)H5O_SIZEOF_HDR(oh);
1218
0
    else
1219
0
        oh->chunk[chunkno].size = chunk_size;
1220
0
    if (NULL == (oh->chunk[chunkno].image = H5FL_BLK_MALLOC(chunk_image, oh->chunk[chunkno].size)))
1221
0
        HGOTO_ERROR(H5E_OHDR, H5E_CANTALLOC, FAIL, "memory allocation failed");
1222
0
    oh->chunk[chunkno].chunk_proxy = NULL;
1223
1224
    /* Copy disk image into chunk's image */
1225
0
    if (len < oh->chunk[chunkno].size)
1226
0
        HGOTO_ERROR(H5E_OHDR, H5E_CANTCOPY, FAIL, "attempted to copy too many disk image bytes into buffer");
1227
0
    H5MM_memcpy(oh->chunk[chunkno].image, image, oh->chunk[chunkno].size);
1228
1229
    /* Point into chunk image to decode */
1230
0
    chunk_image = oh->chunk[chunkno].image;
1231
0
    p_end       = chunk_image + oh->chunk[chunkno].size - 1;
1232
1233
    /* Skip over [already decoded] prefix in special case of chunk 0 */
1234
0
    if (chunkno == 0) {
1235
0
        size_t skip = (size_t)(H5O_SIZEOF_HDR(oh) - H5O_SIZEOF_CHKSUM_OH(oh));
1236
1237
0
        if (H5_IS_BUFFER_OVERFLOW(chunk_image, skip, p_end))
1238
0
            HGOTO_ERROR(H5E_OHDR, H5E_OVERFLOW, FAIL, "ran off end of input buffer while decoding");
1239
0
        chunk_image += skip;
1240
0
    }
1241
1242
    /* Check for magic # on chunks > 0 in later versions of the format */
1243
0
    else if (chunkno > 0 && oh->version > H5O_VERSION_1) {
1244
        /* Magic number */
1245
0
        if (H5_IS_BUFFER_OVERFLOW(chunk_image, H5_SIZEOF_MAGIC, p_end))
1246
0
            HGOTO_ERROR(H5E_OHDR, H5E_OVERFLOW, FAIL, "ran off end of input buffer while decoding");
1247
0
        if (memcmp(chunk_image, H5O_CHK_MAGIC, H5_SIZEOF_MAGIC) != 0)
1248
0
            HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, FAIL, "wrong object header chunk signature");
1249
0
        chunk_image += H5_SIZEOF_MAGIC;
1250
0
    }
1251
1252
    /* Decode messages from this chunk */
1253
0
    eom_ptr = oh->chunk[chunkno].image + (oh->chunk[chunkno].size - H5O_SIZEOF_CHKSUM_OH(oh));
1254
0
    nullcnt = 0;
1255
1256
0
    while (chunk_image < eom_ptr) {
1257
0
        size_t            mesg_size;   /* Size of message read in */
1258
0
        unsigned          id;          /* ID (type) of current message */
1259
0
        uint8_t           flags;       /* Flags for current message */
1260
0
        H5O_msg_crt_idx_t crt_idx = 0; /* Creation index for current message */
1261
1262
        /* Decode message prefix info */
1263
1264
        /* Version # */
1265
0
        if (oh->version == H5O_VERSION_1) {
1266
0
            if (H5_IS_BUFFER_OVERFLOW(chunk_image, 2, p_end))
1267
0
                HGOTO_ERROR(H5E_OHDR, H5E_OVERFLOW, FAIL, "ran off end of input buffer while decoding");
1268
0
            UINT16DECODE(chunk_image, id);
1269
0
        }
1270
0
        else {
1271
0
            if (H5_IS_BUFFER_OVERFLOW(chunk_image, 1, p_end))
1272
0
                HGOTO_ERROR(H5E_OHDR, H5E_OVERFLOW, FAIL, "ran off end of input buffer while decoding");
1273
0
            id = *chunk_image++;
1274
0
        }
1275
1276
        /* Message size */
1277
0
        if (H5_IS_BUFFER_OVERFLOW(chunk_image, 2, p_end))
1278
0
            HGOTO_ERROR(H5E_OHDR, H5E_OVERFLOW, FAIL, "ran off end of input buffer while decoding");
1279
0
        UINT16DECODE(chunk_image, mesg_size);
1280
0
        if (mesg_size != H5O_ALIGN_OH(oh, mesg_size))
1281
0
            HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, FAIL, "message not aligned");
1282
1283
        /* Message flags */
1284
0
        if (H5_IS_BUFFER_OVERFLOW(chunk_image, 1, p_end))
1285
0
            HGOTO_ERROR(H5E_OHDR, H5E_OVERFLOW, FAIL, "ran off end of input buffer while decoding");
1286
0
        flags = *chunk_image++;
1287
0
        if (flags & ~H5O_MSG_FLAG_BITS)
1288
0
            HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, FAIL, "unknown flag for message");
1289
0
        if ((flags & H5O_MSG_FLAG_SHARED) && (flags & H5O_MSG_FLAG_DONTSHARE))
1290
0
            HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, FAIL, "bad flag combination for message");
1291
0
        if ((flags & H5O_MSG_FLAG_WAS_UNKNOWN) && (flags & H5O_MSG_FLAG_FAIL_IF_UNKNOWN_AND_OPEN_FOR_WRITE))
1292
0
            HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, FAIL, "bad flag combination for message");
1293
0
        if ((flags & H5O_MSG_FLAG_WAS_UNKNOWN) && !(flags & H5O_MSG_FLAG_MARK_IF_UNKNOWN))
1294
0
            HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, FAIL, "bad flag combination for message");
1295
        /* Delay checking the "shareable" flag until we've made sure id
1296
         * references a valid message class that this version of the library
1297
         * knows about */
1298
1299
        /* Reserved bytes/creation index */
1300
0
        if (oh->version == H5O_VERSION_1) {
1301
            /* Reserved bytes */
1302
0
            if (H5_IS_BUFFER_OVERFLOW(chunk_image, 3, p_end))
1303
0
                HGOTO_ERROR(H5E_OHDR, H5E_OVERFLOW, FAIL, "ran off end of input buffer while decoding");
1304
0
            chunk_image += 3;
1305
0
        }
1306
0
        else {
1307
            /* Only decode creation index if they are being tracked */
1308
0
            if (oh->flags & H5O_HDR_ATTR_CRT_ORDER_TRACKED) {
1309
0
                if (H5_IS_BUFFER_OVERFLOW(chunk_image, 2, p_end))
1310
0
                    HGOTO_ERROR(H5E_OHDR, H5E_OVERFLOW, FAIL, "ran off end of input buffer while decoding");
1311
0
                UINT16DECODE(chunk_image, crt_idx);
1312
0
            }
1313
0
        }
1314
1315
        /* The message body starts after the message header, so its size can
1316
         * only be checked against the buffer once the whole header has been
1317
         * decoded
1318
         */
1319
0
        if (H5_IS_BUFFER_OVERFLOW(chunk_image, mesg_size, p_end))
1320
0
            HGOTO_ERROR(H5E_OHDR, H5E_BADVALUE, FAIL, "message size exceeds buffer end");
1321
1322
        /* Increment count of null messages */
1323
0
        if (H5O_NULL_ID == id)
1324
0
            nullcnt++;
1325
1326
        /* Check for combining two adjacent 'null' messages */
1327
0
        if ((udata->file_intent & H5F_ACC_RDWR) && H5O_NULL_ID == id && oh->nmesgs > 0 &&
1328
0
            H5O_NULL_ID == oh->mesg[oh->nmesgs - 1].type->id && oh->mesg[oh->nmesgs - 1].chunkno == chunkno) {
1329
1330
0
            size_t mesgno; /* Current message to operate on */
1331
1332
            /* Combine adjacent null messages */
1333
0
            mesgno = oh->nmesgs - 1;
1334
0
            oh->mesg[mesgno].raw_size += (size_t)H5O_SIZEOF_MSGHDR_OH(oh) + mesg_size;
1335
0
            oh->mesg[mesgno].dirty = true;
1336
0
            merged_null_msgs++;
1337
0
        }
1338
0
        else {
1339
0
            H5O_mesg_t *mesg;        /* Pointer to new message */
1340
0
            unsigned    ioflags = 0; /* Flags for decode routine */
1341
1342
            /* Check if we need to extend message table to hold the new message */
1343
0
            if (oh->nmesgs >= oh->alloc_nmesgs)
1344
0
                if (H5O__alloc_msgs(oh, (size_t)1) < 0)
1345
0
                    HGOTO_ERROR(H5E_OHDR, H5E_CANTALLOC, FAIL, "can't allocate more space for messages");
1346
1347
            /* Get pointer to message to set up */
1348
0
            mesg = &oh->mesg[oh->nmesgs];
1349
1350
            /* Increment # of messages */
1351
0
            oh->nmesgs++;
1352
1353
            /* Initialize information about message */
1354
0
            mesg->dirty   = false;
1355
0
            mesg->flags   = flags;
1356
0
            mesg->crt_idx = crt_idx;
1357
0
            mesg->native  = NULL;
1358
0
            H5_WARN_CAST_AWAY_CONST_OFF
1359
0
            mesg->raw = (uint8_t *)chunk_image;
1360
0
            H5_WARN_CAST_AWAY_CONST_ON
1361
0
            mesg->raw_size = mesg_size;
1362
0
            mesg->chunkno  = chunkno;
1363
1364
            /* Point unknown messages at 'unknown' message class */
1365
            /* (Usually from future versions of the library) */
1366
0
            if (id >= H5O_UNKNOWN_ID ||
1367
#ifdef H5O_ENABLE_BOGUS
1368
                id == H5O_BOGUS_VALID_ID ||
1369
#endif
1370
0
                NULL == H5O_msg_class_g[id]) {
1371
1372
0
                H5O_unknown_t *unknown; /* Pointer to "unknown" message info */
1373
1374
                /* Allocate "unknown" message info */
1375
0
                if (NULL == (unknown = H5FL_MALLOC(H5O_unknown_t)))
1376
0
                    HGOTO_ERROR(H5E_OHDR, H5E_CANTALLOC, FAIL, "memory allocation failed");
1377
1378
                /* Save the original message type ID */
1379
0
                *unknown = id;
1380
1381
                /* Save 'native' form of unknown message */
1382
0
                mesg->native = unknown;
1383
1384
                /* Set message to "unknown" class */
1385
0
                mesg->type = H5O_msg_class_g[H5O_UNKNOWN_ID];
1386
1387
                /* Check for "fail if unknown" message flags */
1388
0
                if (((udata->file_intent & H5F_ACC_RDWR) &&
1389
0
                     (flags & H5O_MSG_FLAG_FAIL_IF_UNKNOWN_AND_OPEN_FOR_WRITE)) ||
1390
0
                    (flags & H5O_MSG_FLAG_FAIL_IF_UNKNOWN_ALWAYS))
1391
0
                    HGOTO_ERROR(H5E_OHDR, H5E_BADMESG, FAIL,
1392
0
                                "unknown message with 'fail if unknown' flag found");
1393
                /* Check for "mark if unknown" message flag, etc. */
1394
0
                else if ((flags & H5O_MSG_FLAG_MARK_IF_UNKNOWN) && !(flags & H5O_MSG_FLAG_WAS_UNKNOWN) &&
1395
0
                         (udata->file_intent & H5F_ACC_RDWR)) {
1396
1397
                    /* Mark the message as "unknown" */
1398
                    /* This is a bit aggressive, since the application may
1399
                     * never change anything about the object (metadata or
1400
                     * raw data), but we can sort out the finer details
1401
                     * when/if we start using the flag.
1402
                     */
1403
                    /* Also, it's possible that this functionality may not
1404
                     * get invoked if the object header is brought into
1405
                     * the metadata cache in some other "weird" way, like
1406
                     * using H5Ocopy().
1407
                     */
1408
0
                    mesg->flags |= H5O_MSG_FLAG_WAS_UNKNOWN;
1409
1410
                    /* Mark the message and chunk as dirty */
1411
0
                    mesg->dirty    = true;
1412
0
                    mesgs_modified = true;
1413
0
                }
1414
0
            }
1415
0
            else {
1416
                /* Check for message of unshareable class marked as "shareable"
1417
                 */
1418
0
                if (((flags & H5O_MSG_FLAG_SHARED) || (flags & H5O_MSG_FLAG_SHAREABLE)) &&
1419
0
                    H5O_msg_class_g[id] && !(H5O_msg_class_g[id]->share_flags & H5O_SHARE_IS_SHARABLE))
1420
0
                    HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, FAIL,
1421
0
                                "message of unshareable class flagged as shareable");
1422
1423
                /* Set message class for "known" messages */
1424
0
                mesg->type = H5O_msg_class_g[id];
1425
0
            }
1426
1427
            /* Do some inspection/interpretation of new messages from this chunk */
1428
            /* (detect continuation messages, ref. count messages, etc.) */
1429
1430
            /* Check if message is a continuation message */
1431
0
            if (H5O_CONT_ID == id) {
1432
0
                H5O_cont_t *cont;
1433
1434
                /* Decode continuation message */
1435
0
                if (NULL == (cont = (H5O_cont_t *)(H5O_MSG_CONT->decode)(udata->f, NULL, 0, &ioflags,
1436
0
                                                                         mesg->raw_size, mesg->raw)))
1437
0
                    HGOTO_ERROR(H5E_OHDR, H5E_BADMESG, FAIL, "bad continuation message found");
1438
0
                H5_CHECKED_ASSIGN(cont->chunkno, unsigned, udata->cont_msg_info->nmsgs + 1,
1439
0
                                  size_t); /* the next continuation message/chunk */
1440
1441
                /* Save 'native' form of continuation message */
1442
0
                mesg->native = cont;
1443
1444
                /* Add to continuation messages left to interpret */
1445
0
                if (H5O__add_cont_msg(udata->cont_msg_info, cont) < 0)
1446
0
                    HGOTO_ERROR(H5E_OHDR, H5E_CANTSET, FAIL, "can't add continuation message");
1447
0
            }
1448
            /* Check if message is a ref. count message */
1449
0
            else if (H5O_REFCOUNT_ID == id) {
1450
0
                H5O_refcount_t *refcount;
1451
1452
                /* Decode ref. count message */
1453
0
                if (oh->version <= H5O_VERSION_1)
1454
0
                    HGOTO_ERROR(H5E_OHDR, H5E_VERSION, FAIL,
1455
0
                                "object header version does not support reference count message");
1456
0
                refcount = (H5O_refcount_t *)(H5O_MSG_REFCOUNT->decode)(udata->f, NULL, 0, &ioflags,
1457
0
                                                                        mesg->raw_size, mesg->raw);
1458
1459
                /* Save 'native' form of ref. count message */
1460
0
                mesg->native = refcount;
1461
1462
                /* Set object header values */
1463
0
                oh->has_refcount_msg = true;
1464
0
                if (!refcount)
1465
0
                    HGOTO_ERROR(H5E_OHDR, H5E_CANTSET, FAIL, "can't decode refcount");
1466
0
                oh->nlink = *refcount;
1467
0
            }
1468
            /* Check if message is an old mtime message */
1469
0
            else if (H5O_MTIME_ID == id) {
1470
0
                time_t *mtime = NULL;
1471
1472
                /* Decode mtime message */
1473
0
                mtime =
1474
0
                    (time_t *)(H5O_MSG_MTIME->decode)(udata->f, NULL, 0, &ioflags, mesg->raw_size, mesg->raw);
1475
1476
                /* Save the decoded old format mtime */
1477
0
                if (!mtime)
1478
0
                    HGOTO_ERROR(H5E_OHDR, H5E_CANTDECODE, FAIL, "can't decode old format mtime");
1479
1480
                /* Save 'native' form of mtime message and its value */
1481
0
                mesg->native = mtime;
1482
0
                oh->ctime    = *mtime;
1483
0
            }
1484
            /* Check if message is an new mtime message */
1485
0
            else if (H5O_MTIME_NEW_ID == id) {
1486
0
                time_t *mtime = NULL;
1487
1488
                /* Decode mtime message */
1489
0
                mtime = (time_t *)(H5O_MSG_MTIME_NEW->decode)(udata->f, NULL, 0, &ioflags, mesg->raw_size,
1490
0
                                                              mesg->raw);
1491
1492
                /* Save the decoded new format mtime */
1493
0
                if (!mtime)
1494
0
                    HGOTO_ERROR(H5E_OHDR, H5E_CANTDECODE, FAIL, "can't decode new format mtime");
1495
1496
                /* Save 'native' form of mtime message and its value */
1497
0
                mesg->native = mtime;
1498
0
                oh->ctime    = *mtime;
1499
0
            }
1500
            /* Check if message is a link message */
1501
0
            else if (H5O_LINK_ID == id) {
1502
                /* Increment the count of link messages */
1503
0
                oh->link_msgs_seen++;
1504
0
            }
1505
            /* Check if message is an attribute message */
1506
0
            else if (H5O_ATTR_ID == id) {
1507
                /* Increment the count of attribute messages */
1508
0
                oh->attr_msgs_seen++;
1509
0
            }
1510
1511
            /* Mark the message & chunk as dirty if the message was changed by decoding */
1512
0
            if ((ioflags & H5O_DECODEIO_DIRTY) && (udata->file_intent & H5F_ACC_RDWR)) {
1513
0
                mesg->dirty    = true;
1514
0
                mesgs_modified = true;
1515
0
            }
1516
0
        }
1517
1518
        /* Advance decode pointer past message */
1519
0
        chunk_image += mesg_size;
1520
1521
        /* Check for 'gap' at end of chunk */
1522
0
        if ((eom_ptr - chunk_image) > 0 && (eom_ptr - chunk_image) < H5O_SIZEOF_MSGHDR_OH(oh)) {
1523
            /* Gaps can only occur in later versions of the format */
1524
0
            if (oh->version == H5O_VERSION_1)
1525
0
                HGOTO_ERROR(H5E_OHDR, H5E_BADMESG, FAIL, "gap found in early version of file format");
1526
1527
            /* Gaps should only occur in chunks with no null messages */
1528
0
            if (nullcnt != 0)
1529
0
                HGOTO_ERROR(H5E_OHDR, H5E_BADMESG, FAIL, "gap in chunk with no null messages");
1530
1531
            /* Set gap information for chunk */
1532
0
            oh->chunk[chunkno].gap = (size_t)(eom_ptr - chunk_image);
1533
1534
            /* Increment location in chunk */
1535
0
            chunk_image += oh->chunk[chunkno].gap;
1536
0
        }
1537
0
    }
1538
1539
    /* Check for correct checksum on chunks, in later versions of the format */
1540
0
    if (oh->version > H5O_VERSION_1) {
1541
0
        uint32_t stored_chksum; /* Checksum from file */
1542
1543
        /* checksum verification already done in verify_chksum cb */
1544
1545
        /* Metadata checksum */
1546
0
        if (H5_IS_BUFFER_OVERFLOW(chunk_image, 4, p_end))
1547
0
            HGOTO_ERROR(H5E_OHDR, H5E_OVERFLOW, FAIL, "ran off end of input buffer while decoding");
1548
0
        UINT32DECODE(chunk_image, stored_chksum);
1549
0
    }
1550
1551
    /* Size check */
1552
0
    if (chunk_image != oh->chunk[chunkno].image + oh->chunk[chunkno].size)
1553
0
        HGOTO_ERROR(H5E_OHDR, H5E_OVERFLOW, FAIL, "object header image size mismatch");
1554
1555
    /* Mark the chunk dirty if we've modified messages */
1556
0
    if (mesgs_modified)
1557
0
        *dirty = true;
1558
1559
    /* Mark the chunk dirty if we've merged null messages */
1560
0
    if (merged_null_msgs > 0) {
1561
0
        udata->merged_null_msgs += merged_null_msgs;
1562
0
        *dirty = true;
1563
0
    }
1564
1565
0
done:
1566
0
    if (ret_value < 0 && udata->cont_msg_info->msgs) {
1567
0
        udata->cont_msg_info->msgs        = H5FL_SEQ_FREE(H5O_cont_t, udata->cont_msg_info->msgs);
1568
0
        udata->cont_msg_info->alloc_nmsgs = 0;
1569
0
    }
1570
0
    FUNC_LEAVE_NOAPI(ret_value)
1571
0
} /* H5O__chunk_deserialize() */
1572
1573
/*-------------------------------------------------------------------------
1574
 * Function:    H5O__chunk_serialize
1575
 *
1576
 * Purpose:     Serialize a chunk for an object header
1577
 *
1578
 * Return:      SUCCEED/FAIL
1579
 *-------------------------------------------------------------------------
1580
 */
1581
static herr_t
1582
H5O__chunk_serialize(const H5F_t *f, H5O_t *oh, unsigned chunkno)
1583
0
{
1584
0
    H5O_mesg_t *curr_msg; /* Pointer to current message being operated on */
1585
0
    unsigned    u;        /* Local index variable */
1586
0
    herr_t      ret_value = SUCCEED;
1587
1588
0
    FUNC_ENTER_PACKAGE
1589
1590
0
    assert(f);
1591
0
    assert(oh);
1592
1593
    /* Encode any dirty messages in this chunk */
1594
0
    for (u = 0, curr_msg = &oh->mesg[0]; u < oh->nmesgs; u++, curr_msg++)
1595
0
        if (curr_msg->dirty && curr_msg->chunkno == chunkno) {
1596
0
            H5_WARN_CAST_AWAY_CONST_OFF
1597
0
            if (H5O_msg_flush((H5F_t *)f, oh, curr_msg) < 0)
1598
0
                HGOTO_ERROR(H5E_OHDR, H5E_CANTENCODE, FAIL, "unable to encode object header message");
1599
0
            H5_WARN_CAST_AWAY_CONST_ON
1600
0
        }
1601
1602
    /* Sanity checks */
1603
0
    if (oh->version > H5O_VERSION_1)
1604
        /* Make certain the magic # is present */
1605
0
        assert(!memcmp(oh->chunk[chunkno].image, (chunkno == 0 ? H5O_HDR_MAGIC : H5O_CHK_MAGIC),
1606
0
                       H5_SIZEOF_MAGIC));
1607
0
    else
1608
        /* Gaps should never occur in version 1 of the format */
1609
0
        assert(oh->chunk[chunkno].gap == 0);
1610
1611
    /* Extra work, for later versions of the format */
1612
0
    if (oh->version > H5O_VERSION_1) {
1613
0
        uint32_t metadata_chksum; /* Computed metadata checksum value */
1614
0
        uint8_t *chunk_image;     /* Pointer into object header chunk */
1615
1616
        /* Check for gap in chunk & zero it out */
1617
0
        if (oh->chunk[chunkno].gap)
1618
0
            memset((oh->chunk[chunkno].image + oh->chunk[chunkno].size) -
1619
0
                       (H5O_SIZEOF_CHKSUM + oh->chunk[chunkno].gap),
1620
0
                   0, oh->chunk[chunkno].gap);
1621
1622
        /* Compute metadata checksum */
1623
0
        metadata_chksum =
1624
0
            H5_checksum_metadata(oh->chunk[chunkno].image, (oh->chunk[chunkno].size - H5O_SIZEOF_CHKSUM), 0);
1625
1626
        /* Metadata checksum */
1627
0
        chunk_image = oh->chunk[chunkno].image + (oh->chunk[chunkno].size - H5O_SIZEOF_CHKSUM);
1628
0
        UINT32ENCODE(chunk_image, metadata_chksum);
1629
0
    }
1630
1631
0
done:
1632
0
    FUNC_LEAVE_NOAPI(ret_value)
1633
0
} /* H5O__chunk_serialize() */