Coverage Report

Created: 2024-06-18 06:29

/src/hdf5/src/H5Omessage.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:   H5Omessage.c
16
 *
17
 * Purpose:   Object header message 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 "H5Eprivate.h"  /* Error handling        */
33
#include "H5Fprivate.h"  /* File access       */
34
#include "H5Iprivate.h"  /* IDs           */
35
#include "H5MMprivate.h" /* Memory management     */
36
#include "H5Opkg.h"      /* Object headers      */
37
#include "H5SMprivate.h" /* Shared object header messages        */
38
39
/****************/
40
/* Local Macros */
41
/****************/
42
43
/******************/
44
/* Local Typedefs */
45
/******************/
46
47
/* User data for iteration while removing a message */
48
typedef struct {
49
    H5F_t         *f;        /* Pointer to file for insertion */
50
    int            sequence; /* Sequence # to search for */
51
    unsigned       nfailed;  /* # of failed message removals */
52
    H5O_operator_t op;       /* Callback routine for removal operations */
53
    void          *op_data;  /* Callback data for removal operations */
54
    bool           adj_link; /* Whether to adjust links when removing messages */
55
} H5O_iter_rm_t;
56
57
/********************/
58
/* Package Typedefs */
59
/********************/
60
61
/********************/
62
/* Local Prototypes */
63
/********************/
64
65
static herr_t H5O__msg_reset_real(const H5O_msg_class_t *type, void *native);
66
static herr_t H5O__msg_remove_cb(H5O_t *oh, H5O_mesg_t *mesg /*in,out*/, unsigned sequence,
67
                                 unsigned *oh_modified, void *_udata /*in,out*/);
68
static herr_t H5O__copy_mesg(H5F_t *f, H5O_t *oh, size_t idx, const H5O_msg_class_t *type, const void *mesg,
69
                             unsigned mesg_flags, unsigned update_flags);
70
71
/*********************/
72
/* Package Variables */
73
/*********************/
74
75
/*****************************/
76
/* Library Private Variables */
77
/*****************************/
78
79
/*******************/
80
/* Local Variables */
81
/*******************/
82
83
/*-------------------------------------------------------------------------
84
 * Function:  H5O_msg_create
85
 *
86
 * Purpose: Create a new object header message
87
 *
88
 * Return:  Success:  Non-negative
89
 *
90
 *    Failure:  Negative
91
 *
92
 *-------------------------------------------------------------------------
93
 */
94
herr_t
95
H5O_msg_create(const H5O_loc_t *loc, unsigned type_id, unsigned mesg_flags, unsigned update_flags, void *mesg)
96
0
{
97
0
    H5O_t *oh        = NULL;    /* Object header */
98
0
    herr_t ret_value = SUCCEED; /* Return value */
99
100
0
    FUNC_ENTER_NOAPI(FAIL)
101
102
    /* check args */
103
0
    assert(loc);
104
0
    assert(type_id < NELMTS(H5O_msg_class_g));
105
0
    assert(0 == (mesg_flags & ~H5O_MSG_FLAG_BITS));
106
0
    assert(mesg);
107
108
    /* Pin the object header */
109
0
    if (NULL == (oh = H5O_pin(loc)))
110
0
        HGOTO_ERROR(H5E_OHDR, H5E_CANTPIN, FAIL, "unable to pin object header");
111
112
    /* Go append message to object header */
113
0
    if (H5O_msg_append_oh(loc->file, oh, type_id, mesg_flags, update_flags, mesg) < 0)
114
0
        HGOTO_ERROR(H5E_OHDR, H5E_WRITEERROR, FAIL, "unable to append to object header");
115
116
0
done:
117
0
    if (oh && H5O_unpin(oh) < 0)
118
0
        HDONE_ERROR(H5E_OHDR, H5E_CANTUNPIN, FAIL, "unable to unpin object header");
119
120
0
    FUNC_LEAVE_NOAPI(ret_value)
121
0
} /* end H5O_msg_create() */
122
123
/*-------------------------------------------------------------------------
124
 * Function:  H5O_msg_append_oh
125
 *
126
 * Purpose: Simplified version of H5O_msg_create, used when creating a new
127
 *              object header message (usually during object creation) and
128
 *              several messages will be added to the object header at once.
129
 *
130
 * Return:  Success:  Non-negative
131
 *
132
 *    Failure:  Negative
133
 *
134
 *-------------------------------------------------------------------------
135
 */
136
herr_t
137
H5O_msg_append_oh(H5F_t *f, H5O_t *oh, unsigned type_id, unsigned mesg_flags, unsigned update_flags,
138
                  void *mesg)
139
0
{
140
0
    const H5O_msg_class_t *type;                /* Original H5O class type for the ID */
141
0
    herr_t                 ret_value = SUCCEED; /* Return value */
142
143
0
    FUNC_ENTER_NOAPI(FAIL)
144
145
    /* check args */
146
0
    assert(f);
147
0
    assert(oh);
148
0
    assert(H5O_ATTR_ID != type_id); /* Attributes are modified in another routine */
149
0
    assert(type_id < NELMTS(H5O_msg_class_g));
150
0
    type = H5O_msg_class_g[type_id]; /* map the type ID to the actual type object */
151
0
    assert(type);
152
0
    assert(0 == (mesg_flags & ~H5O_MSG_FLAG_BITS));
153
0
    assert(mesg);
154
155
    /* Append new message to object header */
156
0
    if (H5O__msg_append_real(f, oh, type, mesg_flags, update_flags, mesg) < 0)
157
0
        HGOTO_ERROR(H5E_ATTR, H5E_CANTINSERT, FAIL, "unable to create new message in header");
158
159
0
done:
160
0
    FUNC_LEAVE_NOAPI(ret_value)
161
0
} /* end H5O_msg_append_oh() */
162
163
/*-------------------------------------------------------------------------
164
 * Function:  H5O__msg_append_real
165
 *
166
 * Purpose: Append a new message to an object header.
167
 *
168
 * Return:  Success:  Non-negative
169
 *
170
 *    Failure:  Negative
171
 *
172
 *-------------------------------------------------------------------------
173
 */
174
herr_t
175
H5O__msg_append_real(H5F_t *f, H5O_t *oh, const H5O_msg_class_t *type, unsigned mesg_flags,
176
                     unsigned update_flags, void *mesg)
177
0
{
178
0
    size_t idx;                 /* Index of message to modify */
179
0
    herr_t ret_value = SUCCEED; /* Return value */
180
181
0
    FUNC_ENTER_PACKAGE
182
183
    /* check args */
184
0
    assert(f);
185
0
    assert(oh);
186
0
    assert(type);
187
0
    assert(0 == (mesg_flags & ~H5O_MSG_FLAG_BITS));
188
0
    assert(mesg);
189
190
    /* Allocate space for a new message */
191
0
    if (H5O__msg_alloc(f, oh, type, &mesg_flags, mesg, &idx) < 0)
192
0
        HGOTO_ERROR(H5E_OHDR, H5E_NOSPACE, FAIL, "unable to create new message");
193
194
    /* Copy the information for the message */
195
0
    if (H5O__copy_mesg(f, oh, idx, type, mesg, mesg_flags, update_flags) < 0)
196
0
        HGOTO_ERROR(H5E_OHDR, H5E_CANTCOPY, FAIL, "unable to write message");
197
#ifdef H5O_DEBUG
198
    H5O__assert(oh);
199
#endif /* H5O_DEBUG */
200
201
0
done:
202
0
    FUNC_LEAVE_NOAPI(ret_value)
203
0
} /* end H5O__msg_append_real() */
204
205
/*-------------------------------------------------------------------------
206
 * Function:  H5O_msg_write
207
 *
208
 * Purpose: Modifies an existing message or creates a new message.
209
 *
210
 *              The UPDATE_FLAGS argument are flags that allow the caller
211
 *              to skip updating the modification time or resetting the message
212
 *              data.  This is useful when several calls to H5O_msg_write will be
213
 *              made in a sequence.
214
 *
215
 * Return:  Success:  Non-negative
216
 *
217
 *    Failure:  Negative
218
 *
219
 *-------------------------------------------------------------------------
220
 */
221
herr_t
222
H5O_msg_write(const H5O_loc_t *loc, unsigned type_id, unsigned mesg_flags, unsigned update_flags, void *mesg)
223
0
{
224
0
    H5O_t                 *oh = NULL;           /* Object header to use */
225
0
    const H5O_msg_class_t *type;                /* Actual H5O class type for the ID */
226
0
    herr_t                 ret_value = SUCCEED; /* Return value */
227
228
0
    FUNC_ENTER_NOAPI(FAIL)
229
230
    /* check args */
231
0
    assert(loc);
232
0
    assert(loc->file);
233
0
    assert(H5_addr_defined(loc->addr));
234
0
    assert(H5O_ATTR_ID != type_id); /* Attributes are modified in another routine */
235
0
    assert(type_id < NELMTS(H5O_msg_class_g));
236
0
    type = H5O_msg_class_g[type_id]; /* map the type ID to the actual type object */
237
0
    assert(type);
238
0
    assert(mesg);
239
0
    assert(0 == (mesg_flags & ~H5O_MSG_FLAG_BITS));
240
241
    /* Pin the object header */
242
0
    if (NULL == (oh = H5O_pin(loc)))
243
0
        HGOTO_ERROR(H5E_OHDR, H5E_CANTPIN, FAIL, "unable to pin object header");
244
245
    /* Call the "real" modify routine */
246
0
    if (H5O__msg_write_real(loc->file, oh, type, mesg_flags, update_flags, mesg) < 0)
247
0
        HGOTO_ERROR(H5E_OHDR, H5E_WRITEERROR, FAIL, "unable to write object header message");
248
249
0
done:
250
0
    if (oh && H5O_unpin(oh) < 0)
251
0
        HDONE_ERROR(H5E_OHDR, H5E_CANTUNPIN, FAIL, "unable to unpin object header");
252
253
0
    FUNC_LEAVE_NOAPI(ret_value)
254
0
} /* end H5O_msg_write() */
255
256
/*-------------------------------------------------------------------------
257
 * Function:  H5O_msg_write_oh
258
 *
259
 * Purpose: Modifies an existing message or creates a new message.
260
 *
261
 *              The UPDATE_FLAGS argument are flags that allow the caller
262
 *              to skip updating the modification time or resetting the message
263
 *              data.  This is useful when several calls to H5O_msg_write will be
264
 *              made in a sequence.
265
 *
266
 * Return:  Success:  Non-negative
267
 *    Failure:  Negative
268
 *
269
 *-------------------------------------------------------------------------
270
 */
271
herr_t
272
H5O_msg_write_oh(H5F_t *f, H5O_t *oh, unsigned type_id, unsigned mesg_flags, unsigned update_flags,
273
                 void *mesg)
274
0
{
275
0
    const H5O_msg_class_t *type;                /* Actual H5O class type for the ID */
276
0
    herr_t                 ret_value = SUCCEED; /* Return value */
277
278
0
    FUNC_ENTER_NOAPI_TAG(oh->cache_info.addr, FAIL)
279
280
    /* check args */
281
0
    assert(f);
282
0
    assert(oh);
283
0
    assert(H5O_ATTR_ID != type_id); /* Attributes are modified in another routine */
284
0
    assert(type_id < NELMTS(H5O_msg_class_g));
285
0
    type = H5O_msg_class_g[type_id]; /* map the type ID to the actual type object */
286
0
    assert(type);
287
0
    assert(mesg);
288
0
    assert(0 == (mesg_flags & ~H5O_MSG_FLAG_BITS));
289
290
    /* Call the "real" modify routine */
291
0
    if (H5O__msg_write_real(f, oh, type, mesg_flags, update_flags, mesg) < 0)
292
0
        HGOTO_ERROR(H5E_OHDR, H5E_WRITEERROR, FAIL, "unable to write object header message");
293
294
0
done:
295
0
    FUNC_LEAVE_NOAPI_TAG(ret_value)
296
0
} /* end H5O_msg_write_oh() */
297
298
/*-------------------------------------------------------------------------
299
 * Function:  H5O__msg_write_real
300
 *
301
 * Purpose: Modifies an existing message or creates a new message.
302
 *
303
 *              The UPDATE_FLAGS argument are flags that allow the caller
304
 *              to skip updating the modification time or resetting the message
305
 *              data.  This is useful when several calls to H5O_msg_write will be
306
 *              made in a sequence.
307
 *
308
 * Return:  Success:  Non-negative
309
 *
310
 *    Failure:  Negative
311
 *
312
 *-------------------------------------------------------------------------
313
 */
314
herr_t
315
H5O__msg_write_real(H5F_t *f, H5O_t *oh, const H5O_msg_class_t *type, unsigned mesg_flags,
316
                    unsigned update_flags, void *mesg)
317
0
{
318
0
    H5O_mesg_t *idx_msg;             /* Pointer to message to modify */
319
0
    size_t      idx;                 /* Index of message to modify */
320
0
    herr_t      ret_value = SUCCEED; /* Return value */
321
322
0
    FUNC_ENTER_PACKAGE
323
324
    /* check args */
325
0
    assert(f);
326
0
    assert(oh);
327
0
    assert(type);
328
0
    assert(type != H5O_MSG_ATTR);
329
0
    assert(mesg);
330
0
    assert(0 == (mesg_flags & ~H5O_MSG_FLAG_BITS));
331
332
    /* Locate message of correct type */
333
0
    for (idx = 0, idx_msg = &oh->mesg[0]; idx < oh->nmesgs; idx++, idx_msg++)
334
0
        if (type == idx_msg->type)
335
0
            break;
336
0
    if (idx == oh->nmesgs)
337
0
        HGOTO_ERROR(H5E_OHDR, H5E_NOTFOUND, FAIL, "message type not found");
338
339
    /* Check for modifying a constant message */
340
0
    if (!(update_flags & H5O_UPDATE_FORCE) && (idx_msg->flags & H5O_MSG_FLAG_CONSTANT))
341
0
        HGOTO_ERROR(H5E_OHDR, H5E_WRITEERROR, FAIL, "unable to modify constant message");
342
    /* This message is shared, but it's being modified. */
343
0
    else if ((idx_msg->flags & H5O_MSG_FLAG_SHARED) || (idx_msg->flags & H5O_MSG_FLAG_SHAREABLE)) {
344
0
        htri_t status; /* Status of "try share" call */
345
346
        /* First, sanity check to make sure it's not a committed message;
347
         *     these can't ever be modified.
348
         */
349
0
        assert(((H5O_shared_t *)idx_msg->native)->type != H5O_SHARE_TYPE_COMMITTED);
350
351
        /* Also, sanity check that a message doesn't switch status from being
352
         *      shared (or shareable) to being unshareable.  (Which could cause
353
         *      a message to increase in size in the object header)
354
         */
355
0
        assert(!(mesg_flags & H5O_MSG_FLAG_DONTSHARE));
356
357
        /* Remove the old message from the SOHM index */
358
        /* (It would be more efficient to try to share the message first, then
359
         *      delete it (avoiding thrashing the index in the case the ref.
360
         *      count on the message is one), but this causes problems when
361
         *      the location of the object changes (from in another object's
362
         *      header to the SOHM heap), so just delete it first -QAK)
363
         */
364
0
        if (H5SM_delete(f, oh, (H5O_shared_t *)idx_msg->native) < 0)
365
0
            HGOTO_ERROR(H5E_OHDR, H5E_CANTDELETE, FAIL, "unable to delete message from SOHM index");
366
367
        /* If we're replacing a shared message, the new message must be shared
368
         * (or else it may increase in size!), so pass in NULL for the OH
369
         * location.
370
         *
371
         * XXX: This doesn't handle freeing extra space in object header from
372
         *      a message shrinking.
373
         */
374
0
        if ((status = H5SM_try_share(f, ((mesg_flags & H5O_MSG_FLAG_SHARED) ? NULL : oh), 0,
375
0
                                     idx_msg->type->id, mesg, &mesg_flags)) < 0)
376
0
            HGOTO_ERROR(H5E_OHDR, H5E_BADMESG, FAIL, "error while trying to share message");
377
0
        if (status == false && (mesg_flags & H5O_MSG_FLAG_SHARED))
378
0
            HGOTO_ERROR(H5E_OHDR, H5E_BADMESG, FAIL, "message changed sharing status");
379
0
    } /* end if */
380
381
    /* Copy the information for the message */
382
0
    if (H5O__copy_mesg(f, oh, idx, type, mesg, mesg_flags, update_flags) < 0)
383
0
        HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, FAIL, "unable to write message");
384
#ifdef H5O_DEBUG
385
    H5O__assert(oh);
386
#endif /* H5O_DEBUG */
387
388
0
done:
389
0
    FUNC_LEAVE_NOAPI(ret_value)
390
0
} /* end H5O__msg_write_real() */
391
392
/*-------------------------------------------------------------------------
393
 * Function:  H5O_msg_read
394
 *
395
 * Purpose: Reads a message from an object header and returns a pointer
396
 *    to it.  The caller will usually supply the memory through
397
 *    MESG and the return value will be MESG.  But if MESG is
398
 *    the null pointer, then this function will malloc() memory
399
 *    to hold the result and return its pointer instead.
400
 *
401
 * Return:  Success:  Ptr to message in native format.  The message
402
 *        should be freed by calling H5O_msg_reset().  If
403
 *        MESG is a null pointer then the caller should
404
 *        also call H5MM_xfree() on the return value
405
 *        after calling H5O_msg_reset().
406
 *
407
 *    Failure:  NULL
408
 *
409
 *-------------------------------------------------------------------------
410
 */
411
void *
412
H5O_msg_read(const H5O_loc_t *loc, unsigned type_id, void *mesg)
413
574
{
414
574
    H5O_t *oh        = NULL; /* Object header to use */
415
574
    void  *ret_value = NULL; /* Return value */
416
417
574
    FUNC_ENTER_NOAPI_TAG(loc->addr, NULL)
418
419
    /* check args */
420
574
    assert(loc);
421
574
    assert(loc->file);
422
574
    assert(H5_addr_defined(loc->addr));
423
574
    assert(type_id < NELMTS(H5O_msg_class_g));
424
425
    /* Get the object header */
426
574
    if (NULL == (oh = H5O_protect(loc, H5AC__READ_ONLY_FLAG, false)))
427
0
        HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, NULL, "unable to protect object header");
428
429
    /* Call the "real" read routine */
430
574
    if (NULL == (ret_value = H5O_msg_read_oh(loc->file, oh, type_id, mesg)))
431
3
        HGOTO_ERROR(H5E_OHDR, H5E_READERROR, NULL, "unable to read object header message");
432
433
574
done:
434
574
    if (oh && H5O_unprotect(loc, oh, H5AC__NO_FLAGS_SET) < 0)
435
0
        HDONE_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, NULL, "unable to release object header");
436
437
574
    FUNC_LEAVE_NOAPI_TAG(ret_value)
438
574
} /* end H5O_msg_read() */
439
440
/*-------------------------------------------------------------------------
441
 * Function:  H5O_msg_read_oh
442
 *
443
 * Purpose: Reads a message from an object header and returns a pointer
444
 *    to it.  The caller will usually supply the memory through
445
 *    MESG and the return value will be MESG.  But if MESG is
446
 *    the null pointer, then this function will malloc() memory
447
 *    to hold the result and return its pointer instead.
448
 *
449
 * Return:  Success:  Ptr to message in native format.  The message
450
 *        should be freed by calling H5O_msg_reset().  If
451
 *        MESG is a null pointer then the caller should
452
 *        also call H5MM_xfree() on the return value
453
 *        after calling H5O_msg_reset().
454
 *
455
 *    Failure:  NULL
456
 *
457
 *-------------------------------------------------------------------------
458
 */
459
void *
460
H5O_msg_read_oh(H5F_t *f, H5O_t *oh, unsigned type_id, void *mesg)
461
574
{
462
574
    const H5O_msg_class_t *type; /* Actual H5O class type for the ID */
463
574
    unsigned               idx;  /* Message's index in object header */
464
574
    void                  *ret_value = NULL;
465
466
574
    FUNC_ENTER_NOAPI_NOINIT
467
468
    /* check args */
469
574
    assert(f);
470
574
    assert(oh);
471
574
    assert(type_id < NELMTS(H5O_msg_class_g));
472
574
    type = H5O_msg_class_g[type_id]; /* map the type ID to the actual type object */
473
574
    assert(type);
474
475
    /* Scan through the messages looking for the right one */
476
913
    for (idx = 0; idx < oh->nmesgs; idx++)
477
913
        if (type == oh->mesg[idx].type)
478
574
            break;
479
574
    if (idx == oh->nmesgs)
480
0
        HGOTO_ERROR(H5E_OHDR, H5E_NOTFOUND, NULL, "message type not found");
481
482
    /*
483
     * Decode the message if necessary.  If the message is shared then retrieve
484
     * native message through the shared interface.
485
     */
486
574
    H5O_LOAD_NATIVE(f, 0, oh, &(oh->mesg[idx]), NULL)
487
488
    /*
489
     * The object header caches the native message (along with
490
     * the raw message) so we must copy the native message before
491
     * returning.
492
     */
493
571
    if (NULL == (ret_value = (type->copy)(oh->mesg[idx].native, mesg)))
494
0
        HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, NULL, "unable to copy message to user space");
495
496
574
done:
497
574
    FUNC_LEAVE_NOAPI(ret_value)
498
571
} /* end H5O_msg_read_oh() */
499
500
/*-------------------------------------------------------------------------
501
 * Function:  H5O_msg_reset
502
 *
503
 * Purpose: Some message data structures have internal fields that
504
 *    need to be freed.  This function does that if appropriate
505
 *    but doesn't free NATIVE.
506
 *
507
 * Return:  Non-negative on success/Negative on failure
508
 *
509
 *-------------------------------------------------------------------------
510
 */
511
herr_t
512
H5O_msg_reset(unsigned type_id, void *native)
513
1.52k
{
514
1.52k
    const H5O_msg_class_t *type;                /* Actual H5O class type for the ID */
515
1.52k
    herr_t                 ret_value = SUCCEED; /* Return value */
516
517
1.52k
    FUNC_ENTER_NOAPI(FAIL)
518
519
    /* check args */
520
1.52k
    assert(type_id < NELMTS(H5O_msg_class_g));
521
1.52k
    type = H5O_msg_class_g[type_id]; /* map the type ID to the actual type object */
522
1.52k
    assert(type);
523
524
    /* Call the "real" reset routine */
525
1.52k
    if (H5O__msg_reset_real(type, native) < 0)
526
0
        HGOTO_ERROR(H5E_OHDR, H5E_CANTRESET, FAIL, "unable to reset object header");
527
528
1.52k
done:
529
1.52k
    FUNC_LEAVE_NOAPI(ret_value)
530
1.52k
} /* end H5O_msg_reset() */
531
532
/*-------------------------------------------------------------------------
533
 * Function:  H5O__msg_reset_real
534
 *
535
 * Purpose: Some message data structures have internal fields that
536
 *    need to be freed.  This function does that if appropriate
537
 *    but doesn't free NATIVE.
538
 *
539
 * Return:  Non-negative on success/Negative on failure
540
 *
541
 *-------------------------------------------------------------------------
542
 */
543
static herr_t
544
H5O__msg_reset_real(const H5O_msg_class_t *type, void *native)
545
1.74k
{
546
1.74k
    herr_t ret_value = SUCCEED; /* Return value */
547
548
1.74k
    FUNC_ENTER_PACKAGE
549
550
    /* check args */
551
1.74k
    assert(type);
552
553
1.74k
    if (native) {
554
1.74k
        if (type->reset) {
555
1.72k
            if ((type->reset)(native) < 0)
556
0
                HGOTO_ERROR(H5E_OHDR, H5E_CANTRELEASE, FAIL, "reset method failed");
557
1.72k
        } /* end if */
558
21
        else
559
21
            memset(native, 0, type->native_size);
560
1.74k
    } /* end if */
561
562
1.74k
done:
563
1.74k
    FUNC_LEAVE_NOAPI(ret_value)
564
1.74k
} /* end H5O__msg_reset_real() */
565
566
/*-------------------------------------------------------------------------
567
 * Function:  H5O_msg_free
568
 *
569
 * Purpose: Similar to H5O_msg_reset() except it also frees the message
570
 *    pointer.
571
 *
572
 * Return:  Success:  NULL
573
 *
574
 *    Failure:  NULL
575
 *
576
 *-------------------------------------------------------------------------
577
 */
578
void *
579
H5O_msg_free(unsigned type_id, void *mesg)
580
0
{
581
0
    const H5O_msg_class_t *type;             /* Actual H5O class type for the ID */
582
0
    void                  *ret_value = NULL; /* Return value */
583
584
0
    FUNC_ENTER_NOAPI_NOINIT_NOERR
585
586
    /* check args */
587
0
    assert(type_id < NELMTS(H5O_msg_class_g));
588
0
    type = H5O_msg_class_g[type_id]; /* map the type ID to the actual type object */
589
0
    assert(type);
590
591
    /* Call the "real" free routine */
592
0
    ret_value = H5O_msg_free_real(type, mesg);
593
594
0
    FUNC_LEAVE_NOAPI(ret_value)
595
0
} /* end H5O_msg_free() */
596
597
/*-------------------------------------------------------------------------
598
 * Function:  H5O__msg_free_mesg
599
 *
600
 * Purpose: Call H5O_msg_free_real() on a message.
601
 *
602
 * Return:  Non-negative on success/Negative on failure
603
 *
604
 *-------------------------------------------------------------------------
605
 */
606
herr_t
607
H5O__msg_free_mesg(H5O_mesg_t *mesg)
608
413
{
609
413
    FUNC_ENTER_PACKAGE_NOERR
610
611
    /* check args */
612
413
    assert(mesg);
613
614
    /* Free any native information */
615
413
    mesg->native = H5O_msg_free_real(mesg->type, mesg->native);
616
617
413
    FUNC_LEAVE_NOAPI(SUCCEED)
618
413
} /* end H5O__msg_free_mesg() */
619
620
/*-------------------------------------------------------------------------
621
 * Function:    H5O_msg_free_real
622
 *
623
 * Purpose:     Similar to H5O_msg_reset() except it also frees the message
624
 *              pointer
625
 *
626
 * Return:      NULL (always)
627
 *
628
 *-------------------------------------------------------------------------
629
 */
630
void *
631
H5O_msg_free_real(const H5O_msg_class_t *type, void *msg_native)
632
413
{
633
413
    FUNC_ENTER_NOAPI_NOINIT_NOERR
634
635
    /* Don't assert on args since this could be called in cleanup code */
636
637
413
    if (msg_native) {
638
225
        H5O__msg_reset_real(type, msg_native);
639
225
        if (type && type->free)
640
225
            (type->free)(msg_native);
641
0
        else
642
0
            H5MM_xfree(msg_native);
643
225
    }
644
645
413
    FUNC_LEAVE_NOAPI(NULL)
646
413
} /* end H5O_msg_free_real() */
647
648
/*-------------------------------------------------------------------------
649
 * Function:  H5O_msg_copy
650
 *
651
 * Purpose: Copies a message.  If MESG is the null pointer then a null
652
 *    pointer is returned with no error.
653
 *
654
 * Return:  Success:  Ptr to the new message
655
 *
656
 *    Failure:  NULL
657
 *
658
 *-------------------------------------------------------------------------
659
 */
660
void *
661
H5O_msg_copy(unsigned type_id, const void *mesg, void *dst)
662
486
{
663
486
    const H5O_msg_class_t *type;             /* Actual H5O class type for the ID */
664
486
    void                  *ret_value = NULL; /* Return value */
665
666
486
    FUNC_ENTER_NOAPI(NULL)
667
668
    /* check args */
669
486
    assert(mesg);
670
486
    assert(type_id < NELMTS(H5O_msg_class_g));
671
486
    type = H5O_msg_class_g[type_id]; /* map the type ID to the actual type object */
672
486
    assert(type);
673
674
    /* Call the message class's copy routine */
675
486
    if (NULL == (ret_value = (type->copy)(mesg, dst)))
676
0
        HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, NULL, "unable to copy object header message");
677
678
486
done:
679
486
    FUNC_LEAVE_NOAPI(ret_value)
680
486
} /* end H5O_msg_copy() */
681
682
/*-------------------------------------------------------------------------
683
 * Function:  H5O_msg_count
684
 *
685
 * Purpose: Counts the number of messages in an object header which are a
686
 *    certain type.
687
 *
688
 * Return:  Success:  Number of messages of specified type.
689
 *
690
 *    Failure:  Negative
691
 *
692
 *-------------------------------------------------------------------------
693
 */
694
int
695
H5O_msg_count(const H5O_loc_t *loc, unsigned type_id)
696
0
{
697
0
    H5O_t                 *oh = NULL;        /* Object header to operate on */
698
0
    const H5O_msg_class_t *type;             /* Actual H5O class type for the ID */
699
0
    unsigned               msg_count;        /* Message count */
700
0
    int                    ret_value = FAIL; /* Return value */
701
702
0
    FUNC_ENTER_NOAPI(FAIL)
703
704
    /* Check args */
705
0
    assert(loc);
706
0
    assert(loc->file);
707
0
    assert(H5_addr_defined(loc->addr));
708
0
    assert(type_id < NELMTS(H5O_msg_class_g));
709
0
    type = H5O_msg_class_g[type_id]; /* map the type ID to the actual type object */
710
0
    assert(type);
711
712
    /* Load the object header */
713
0
    if (NULL == (oh = H5O_protect(loc, H5AC__READ_ONLY_FLAG, false)))
714
0
        HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, FAIL, "unable to protect object header");
715
716
    /* Count the messages of the correct type */
717
0
    msg_count = H5O__msg_count_real(oh, type);
718
0
    H5_CHECKED_ASSIGN(ret_value, int, msg_count, unsigned);
719
720
0
done:
721
0
    if (oh && H5O_unprotect(loc, oh, H5AC__NO_FLAGS_SET) < 0)
722
0
        HDONE_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, FAIL, "unable to release object header");
723
724
0
    FUNC_LEAVE_NOAPI(ret_value)
725
0
} /* end H5O_msg_count() */
726
727
/*-------------------------------------------------------------------------
728
 * Function:  H5O__msg_count_real
729
 *
730
 * Purpose: Counts the number of messages in an object header which are a
731
 *    certain type.
732
 *
733
 * Return:  Success:  Number of messages of specified type.
734
 *
735
 *    Failure:  (can't fail)
736
 *
737
 *-------------------------------------------------------------------------
738
 */
739
unsigned
740
H5O__msg_count_real(const H5O_t *oh, const H5O_msg_class_t *type)
741
0
{
742
0
    unsigned u;             /* Local index variable */
743
0
    unsigned ret_value = 0; /* Return value */
744
745
0
    FUNC_ENTER_PACKAGE_NOERR
746
747
    /* Check args */
748
0
    assert(oh);
749
0
    assert(type);
750
751
    /* Loop over all messages, counting the ones of the type looked for */
752
0
    for (u = ret_value = 0; u < oh->nmesgs; u++)
753
0
        if (oh->mesg[u].type == type)
754
0
            ret_value++;
755
756
0
    FUNC_LEAVE_NOAPI(ret_value)
757
0
} /* end H5O__msg_count_real() */
758
759
/*-------------------------------------------------------------------------
760
 * Function:  H5O_msg_exists
761
 *
762
 * Purpose: Determines if a particular message exists in an object
763
 *    header without trying to decode the message.
764
 *
765
 * Return:  Success:  false if the message does not exist; true if
766
 *        th message exists.
767
 *
768
 *    Failure:  FAIL if the existence of the message could
769
 *        not be determined due to some error such as
770
 *        not being able to read the object header.
771
 *
772
 *-------------------------------------------------------------------------
773
 */
774
htri_t
775
H5O_msg_exists(const H5O_loc_t *loc, unsigned type_id)
776
617
{
777
617
    H5O_t *oh        = NULL; /* Object header for location */
778
617
    htri_t ret_value = FAIL; /* Return value */
779
780
617
    FUNC_ENTER_NOAPI_TAG(loc->addr, FAIL)
781
782
617
    assert(loc);
783
617
    assert(loc->file);
784
617
    assert(type_id < NELMTS(H5O_msg_class_g));
785
786
    /* Load the object header */
787
617
    if (NULL == (oh = H5O_protect(loc, H5AC__READ_ONLY_FLAG, false)))
788
0
        HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, FAIL, "unable to protect object header");
789
790
    /* Call the "real" exists routine */
791
617
    if ((ret_value = H5O_msg_exists_oh(oh, type_id)) < 0)
792
0
        HGOTO_ERROR(H5E_OHDR, H5E_READERROR, FAIL, "unable to verify object header message");
793
794
617
done:
795
617
    if (oh && H5O_unprotect(loc, oh, H5AC__NO_FLAGS_SET) < 0)
796
0
        HDONE_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, FAIL, "unable to release object header");
797
798
617
    FUNC_LEAVE_NOAPI_TAG(ret_value)
799
617
} /* end H5O_msg_exists() */
800
801
/*-------------------------------------------------------------------------
802
 * Function:  H5O_msg_exists_oh
803
 *
804
 * Purpose: Determines if a particular message exists in an object
805
 *    header without trying to decode the message.
806
 *
807
 * Return:  Success:  false if the message does not exist; true if
808
 *        th message exists.
809
 *
810
 *    Failure:  FAIL if the existence of the message could
811
 *        not be determined due to some error such as
812
 *        not being able to read the object header.
813
 *
814
 *-------------------------------------------------------------------------
815
 */
816
htri_t
817
H5O_msg_exists_oh(const H5O_t *oh, unsigned type_id)
818
1.19k
{
819
1.19k
    const H5O_msg_class_t *type;              /* Actual H5O class type for the ID */
820
1.19k
    unsigned               u;                 /* Local index variable */
821
1.19k
    htri_t                 ret_value = false; /* Return value */
822
823
1.19k
    FUNC_ENTER_NOAPI_NOINIT_NOERR
824
825
1.19k
    assert(oh);
826
1.19k
    assert(type_id < NELMTS(H5O_msg_class_g));
827
1.19k
    type = H5O_msg_class_g[type_id]; /* map the type ID to the actual type object */
828
1.19k
    assert(type);
829
830
    /* Scan through the messages looking for the right one */
831
4.22k
    for (u = 0; u < oh->nmesgs; u++)
832
3.46k
        if (type == oh->mesg[u].type)
833
440
            HGOTO_DONE(true);
834
835
1.19k
done:
836
1.19k
    FUNC_LEAVE_NOAPI(ret_value)
837
1.19k
} /* end H5O_msg_exists_oh() */
838
839
/*-------------------------------------------------------------------------
840
 * Function:  H5O_msg_remove
841
 *
842
 * Purpose: Removes the specified message from the object header.
843
 *    If sequence is H5O_ALL (-1) then all messages of the
844
 *    specified type are removed.  Removing a message causes
845
 *    the sequence numbers to change for subsequent messages of
846
 *    the same type.
847
 *
848
 *    No attempt is made to join adjacent free areas of the
849
 *    object header into a single larger free area.
850
 *
851
 * Return:  Non-negative on success/Negative on failure
852
 *
853
 *-------------------------------------------------------------------------
854
 */
855
herr_t
856
H5O_msg_remove(const H5O_loc_t *loc, unsigned type_id, int sequence, bool adj_link)
857
0
{
858
0
    H5O_t                 *oh = NULL;        /* Pointer to actual object header */
859
0
    const H5O_msg_class_t *type;             /* Actual H5O class type for the ID */
860
0
    herr_t                 ret_value = FAIL; /* Return value */
861
862
0
    FUNC_ENTER_NOAPI(FAIL)
863
864
    /* check args */
865
0
    assert(loc);
866
0
    assert(loc->file);
867
0
    assert(H5_addr_defined(loc->addr));
868
0
    assert(H5O_ATTR_ID != type_id); /* Attributes are modified in another routine */
869
0
    assert(type_id < NELMTS(H5O_msg_class_g));
870
0
    type = H5O_msg_class_g[type_id]; /* map the type ID to the actual type object */
871
0
    assert(type);
872
873
    /* Pin the object header */
874
0
    if (NULL == (oh = H5O_pin(loc)))
875
0
        HGOTO_ERROR(H5E_OHDR, H5E_CANTPIN, FAIL, "unable to pin object header");
876
877
    /* Call the "real" remove routine */
878
0
    if ((ret_value = H5O__msg_remove_real(loc->file, oh, type, sequence, NULL, NULL, adj_link)) < 0)
879
0
        HGOTO_ERROR(H5E_OHDR, H5E_CANTDELETE, FAIL, "unable to remove object header message");
880
881
0
done:
882
0
    if (oh && H5O_unpin(oh) < 0)
883
0
        HDONE_ERROR(H5E_OHDR, H5E_CANTUNPIN, FAIL, "unable to unpin object header");
884
885
0
    FUNC_LEAVE_NOAPI(ret_value)
886
0
} /* end H5O_msg_remove() */
887
888
/*-------------------------------------------------------------------------
889
 * Function:  H5O_msg_remove_op
890
 *
891
 * Purpose: Removes messages from the object header that a callback
892
 *              routine indicates should be removed.
893
 *
894
 *    No attempt is made to join adjacent free areas of the
895
 *    object header into a single larger free area.
896
 *
897
 * Return:  Non-negative on success/Negative on failure
898
 *
899
 *-------------------------------------------------------------------------
900
 */
901
herr_t
902
H5O_msg_remove_op(const H5O_loc_t *loc, unsigned type_id, int sequence, H5O_operator_t op, void *op_data,
903
                  bool adj_link)
904
0
{
905
0
    H5O_t                 *oh = NULL;        /* Pointer to actual object header */
906
0
    const H5O_msg_class_t *type;             /* Actual H5O class type for the ID */
907
0
    herr_t                 ret_value = FAIL; /* Return value */
908
909
0
    FUNC_ENTER_NOAPI(FAIL)
910
911
    /* check args */
912
0
    assert(loc);
913
0
    assert(loc->file);
914
0
    assert(H5_addr_defined(loc->addr));
915
0
    assert(H5O_ATTR_ID != type_id); /* Attributes are modified in another routine */
916
0
    assert(type_id < NELMTS(H5O_msg_class_g));
917
0
    type = H5O_msg_class_g[type_id]; /* map the type ID to the actual type object */
918
0
    assert(type);
919
920
    /* Pin the object header */
921
0
    if (NULL == (oh = H5O_pin(loc)))
922
0
        HGOTO_ERROR(H5E_OHDR, H5E_CANTPIN, FAIL, "unable to pin object header");
923
924
    /* Call the "real" remove routine */
925
0
    if ((ret_value = H5O__msg_remove_real(loc->file, oh, type, sequence, op, op_data, adj_link)) < 0)
926
0
        HGOTO_ERROR(H5E_OHDR, H5E_CANTDELETE, FAIL, "unable to remove object header message");
927
928
0
done:
929
0
    if (oh && H5O_unpin(oh) < 0)
930
0
        HDONE_ERROR(H5E_OHDR, H5E_CANTUNPIN, FAIL, "unable to unpin object header");
931
932
0
    FUNC_LEAVE_NOAPI(ret_value)
933
0
} /* end H5O_msg_remove_op() */
934
935
/*-------------------------------------------------------------------------
936
 * Function:  H5O__msg_remove_cb
937
 *
938
 * Purpose: Object header iterator callback routine to remove messages
939
 *              of a particular type that match a particular sequence number,
940
 *              or all messages if the sequence number is H5O_ALL (-1).
941
 *
942
 * Return:  Non-negative on success/Negative on failure
943
 *
944
 *-------------------------------------------------------------------------
945
 */
946
static herr_t
947
H5O__msg_remove_cb(H5O_t *oh, H5O_mesg_t *mesg /*in,out*/, unsigned sequence, unsigned *oh_modified,
948
                   void *_udata /*in,out*/)
949
0
{
950
0
    H5O_iter_rm_t *udata      = (H5O_iter_rm_t *)_udata; /* Operator user data */
951
0
    htri_t         try_remove = false;                   /* Whether to try removing a message */
952
0
    herr_t         ret_value  = H5_ITER_CONT;            /* Return value */
953
954
0
    FUNC_ENTER_PACKAGE
955
956
    /* check args */
957
0
    assert(mesg);
958
959
    /* Check for callback routine */
960
0
    if (udata->op) {
961
        /* Call the iterator callback */
962
0
        if ((try_remove = (udata->op)(mesg->native, sequence, udata->op_data)) < 0)
963
0
            HGOTO_ERROR(H5E_OHDR, H5E_CANTDELETE, H5_ITER_ERROR,
964
0
                        "object header message deletion callback failed");
965
0
    } /* end if */
966
0
    else {
967
        /* If there's no callback routine, does the sequence # match? */
968
0
        if ((int)sequence == udata->sequence || H5O_ALL == udata->sequence)
969
0
            try_remove = true;
970
0
    } /* end else */
971
972
    /* Try removing the message, if indicated */
973
0
    if (try_remove) {
974
        /*
975
         * Keep track of how many times we failed trying to remove constant
976
         * messages.
977
         * (OK to remove constant messages - QAK)
978
         */
979
        /* Convert message into a null message */
980
0
        if (H5O__release_mesg(udata->f, oh, mesg, udata->adj_link) < 0)
981
0
            HGOTO_ERROR(H5E_OHDR, H5E_CANTDELETE, H5_ITER_ERROR, "unable to release message");
982
983
        /* Indicate that the object header was modified */
984
0
        *oh_modified = H5O_MODIFY_CONDENSE;
985
986
        /* Break out now, if we've found the correct message */
987
0
        if (udata->sequence == H5O_FIRST || udata->sequence != H5O_ALL)
988
0
            HGOTO_DONE(H5_ITER_STOP);
989
0
    } /* end if */
990
991
0
done:
992
0
    FUNC_LEAVE_NOAPI(ret_value)
993
0
} /* end H5O__msg_remove_cb() */
994
995
/*-------------------------------------------------------------------------
996
 * Function:  H5O__msg_remove_real
997
 *
998
 * Purpose: Removes the specified message from the object header.
999
 *    If sequence is H5O_ALL (-1) then all messages of the
1000
 *    specified type are removed.  Removing a message causes
1001
 *    the sequence numbers to change for subsequent messages of
1002
 *    the same type.
1003
 *
1004
 * Return:  Non-negative on success/Negative on failure
1005
 *
1006
 *-------------------------------------------------------------------------
1007
 */
1008
herr_t
1009
H5O__msg_remove_real(H5F_t *f, H5O_t *oh, const H5O_msg_class_t *type, int sequence, H5O_operator_t app_op,
1010
                     void *op_data, bool adj_link)
1011
0
{
1012
0
    H5O_iter_rm_t       udata;               /* User data for iterator */
1013
0
    H5O_mesg_operator_t op;                  /* Wrapper for operator */
1014
0
    herr_t              ret_value = SUCCEED; /* Return value */
1015
1016
0
    FUNC_ENTER_PACKAGE
1017
1018
    /* check args */
1019
0
    assert(f);
1020
0
    assert(oh);
1021
0
    assert(type);
1022
1023
    /* Make certain we are allowed to modify the file */
1024
0
    if (0 == (H5F_INTENT(f) & H5F_ACC_RDWR))
1025
0
        HGOTO_ERROR(H5E_OHDR, H5E_WRITEERROR, FAIL, "no write intent on file");
1026
1027
    /* Set up iterator operator data */
1028
0
    udata.f        = f;
1029
0
    udata.sequence = sequence;
1030
0
    udata.nfailed  = 0;
1031
0
    udata.op       = app_op;
1032
0
    udata.op_data  = op_data;
1033
0
    udata.adj_link = adj_link;
1034
1035
    /* Iterate over the messages, deleting appropriate one(s) */
1036
0
    op.op_type  = H5O_MESG_OP_LIB;
1037
0
    op.u.lib_op = H5O__msg_remove_cb;
1038
0
    if (H5O__msg_iterate_real(f, oh, type, &op, &udata) < 0)
1039
0
        HGOTO_ERROR(H5E_OHDR, H5E_NOTFOUND, FAIL, "error iterating over messages");
1040
1041
    /* Fail if we tried to remove any constant messages */
1042
0
    if (udata.nfailed)
1043
0
        HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, FAIL, "unable to remove constant message(s)");
1044
1045
0
done:
1046
0
    FUNC_LEAVE_NOAPI(ret_value)
1047
0
} /* end H5O__msg_remove_real() */
1048
1049
/*-------------------------------------------------------------------------
1050
 * Function:  H5O_msg_iterate
1051
 *
1052
 * Purpose: Iterate through object headers of a certain type.
1053
 *
1054
 * Return:  Returns a negative value if something is wrong, the return
1055
 *      value of the last operator if it was non-zero, or zero if all
1056
 *      object headers were processed.
1057
 *
1058
 * Description:
1059
 *      This function iterates over the object headers of an object
1060
 *  specified with 'loc' of type 'type_id'.  For each object header of the
1061
 *  object, the 'op_data' and some additional information (specified below) are
1062
 *  passed to the 'op' function.
1063
 *      The operation receives a pointer to the object header message for the
1064
 *  object being iterated over ('mesg'), and the pointer to the operator data
1065
 *  passed in to H5O_msg_iterate ('op_data').  The return values from an operator
1066
 *  are:
1067
 *      A. Zero causes the iterator to continue, returning zero when all
1068
 *          object headers of that type have been processed.
1069
 *      B. Positive causes the iterator to immediately return that positive
1070
 *          value, indicating short-circuit success.
1071
 *      C. Negative causes the iterator to immediately return that value,
1072
 *          indicating failure.
1073
 *
1074
 *-------------------------------------------------------------------------
1075
 */
1076
herr_t
1077
H5O_msg_iterate(const H5O_loc_t *loc, unsigned type_id, const H5O_mesg_operator_t *op, void *op_data)
1078
0
{
1079
0
    H5O_t                 *oh = NULL;        /* Pointer to actual object header */
1080
0
    const H5O_msg_class_t *type;             /* Actual H5O class type for the ID */
1081
0
    herr_t                 ret_value = FAIL; /* Return value */
1082
1083
0
    FUNC_ENTER_NOAPI(FAIL)
1084
1085
    /* check args */
1086
0
    assert(loc);
1087
0
    assert(loc->file);
1088
0
    assert(H5_addr_defined(loc->addr));
1089
0
    assert(type_id < NELMTS(H5O_msg_class_g));
1090
0
    type = H5O_msg_class_g[type_id]; /* map the type ID to the actual type object */
1091
0
    assert(type);
1092
0
    assert(op);
1093
1094
    /* Protect the object header to iterate over */
1095
0
    if (NULL == (oh = H5O_protect(loc, H5AC__READ_ONLY_FLAG, false)))
1096
0
        HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, FAIL, "unable to protect object header");
1097
1098
    /* Call the "real" iterate routine */
1099
0
    if ((ret_value = H5O__msg_iterate_real(loc->file, oh, type, op, op_data)) < 0)
1100
0
        HERROR(H5E_OHDR, H5E_BADITER, "unable to iterate over object header messages");
1101
1102
0
done:
1103
0
    if (oh && H5O_unprotect(loc, oh, H5AC__NO_FLAGS_SET) < 0)
1104
0
        HDONE_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, FAIL, "unable to release object header");
1105
1106
0
    FUNC_LEAVE_NOAPI(ret_value)
1107
0
} /* end H5O_msg_iterate() */
1108
1109
/*-------------------------------------------------------------------------
1110
 * Function:  H5O__msg_iterate_real
1111
 *
1112
 * Purpose: Iterate through object headers of a certain type.
1113
 *
1114
 * Return:  Returns a negative value if something is wrong, the return
1115
 *      value of the last operator if it was non-zero, or zero if all
1116
 *      object headers were processed.
1117
 *
1118
 * Description:
1119
 *      This function iterates over the object headers of an object
1120
 *  specified with 'ent' of type 'type_id'.  For each object header of the
1121
 *  object, the 'op_data' and some additional information (specified below) are
1122
 *  passed to the 'op' function.
1123
 *      The operation receives a pointer to the object header message for the
1124
 *  object being iterated over ('mesg'), and the pointer to the operator data
1125
 *  passed in to H5O_msg_iterate ('op_data').  The return values from an operator
1126
 *  are:
1127
 *      A. Zero causes the iterator to continue, returning zero when all
1128
 *          object headers of that type have been processed.
1129
 *      B. Positive causes the iterator to immediately return that positive
1130
 *          value, indicating short-circuit success.
1131
 *      C. Negative causes the iterator to immediately return that value,
1132
 *          indicating failure.
1133
 *
1134
 *-------------------------------------------------------------------------
1135
 */
1136
herr_t
1137
H5O__msg_iterate_real(H5F_t *f, H5O_t *oh, const H5O_msg_class_t *type, const H5O_mesg_operator_t *op,
1138
                      void *op_data)
1139
185
{
1140
185
    H5O_mesg_t *idx_msg;                    /* Pointer to current message */
1141
185
    unsigned    idx;                        /* Absolute index of current message in all messages */
1142
185
    unsigned    sequence;                   /* Relative index of current message for messages of type */
1143
185
    unsigned    oh_modified = 0;            /* Whether the callback modified the object header */
1144
185
    herr_t      ret_value   = H5_ITER_CONT; /* Return value */
1145
1146
185
    FUNC_ENTER_PACKAGE
1147
1148
    /* check args */
1149
185
    assert(f);
1150
185
    assert(oh);
1151
185
    assert(type);
1152
185
    assert(op);
1153
185
    assert(op->u.app_op);
1154
1155
    /* Iterate over messages */
1156
1.27k
    for (sequence = 0, idx = 0, idx_msg = &oh->mesg[0]; idx < oh->nmesgs && !ret_value; idx++, idx_msg++) {
1157
1.18k
        if (type == idx_msg->type) {
1158
            /* Decode the message if necessary.  */
1159
255
            H5O_LOAD_NATIVE(f, 0, oh, idx_msg, FAIL)
1160
1161
            /* Check for making an "internal" (i.e. within the H5O package) callback */
1162
231
            if (op->op_type == H5O_MESG_OP_LIB)
1163
231
                ret_value = (op->u.lib_op)(oh, idx_msg, sequence, &oh_modified, op_data);
1164
0
            else
1165
0
                ret_value = (op->u.app_op)(idx_msg->native, sequence, op_data);
1166
1167
            /* Check for iterator callback indicating to get out of loop */
1168
231
            if (ret_value != 0)
1169
73
                break;
1170
1171
            /* Increment sequence value for message type */
1172
158
            sequence++;
1173
158
        } /* end if */
1174
1.18k
    }     /* end for */
1175
1176
    /* Check for error from iterator */
1177
161
    if (ret_value < 0)
1178
0
        HERROR(H5E_OHDR, H5E_CANTLIST, "iterator function failed");
1179
1180
185
done:
1181
    /* Check if object message was modified */
1182
185
    if (oh_modified) {
1183
        /* Try to condense object header info */
1184
        /* (Since this routine is used to remove messages from an
1185
         *  object header, the header will be condensed after each
1186
         *  message removal)
1187
         */
1188
0
        if (oh_modified & H5O_MODIFY_CONDENSE)
1189
0
            if (H5O__condense_header(f, oh) < 0)
1190
0
                HDONE_ERROR(H5E_OHDR, H5E_CANTPACK, FAIL, "can't pack object header");
1191
1192
        /* Mark object header as changed */
1193
0
        if (H5O_touch_oh(f, oh, false) < 0)
1194
0
            HDONE_ERROR(H5E_OHDR, H5E_CANTUPDATE, FAIL, "unable to update time on object");
1195
1196
        /* Mark object header as dirty in cache */
1197
0
        if (H5AC_mark_entry_dirty(oh) < 0)
1198
0
            HGOTO_ERROR(H5E_OHDR, H5E_CANTMARKDIRTY, FAIL, "unable to mark object header as dirty");
1199
0
    } /* end if */
1200
1201
185
    FUNC_LEAVE_NOAPI(ret_value)
1202
185
} /* end H5O__msg_iterate_real() */
1203
1204
/*-------------------------------------------------------------------------
1205
 * Function:  H5O_msg_raw_size
1206
 *
1207
 * Purpose: Call the 'raw_size' method for a
1208
 *              particular class of object header.
1209
 *
1210
 * Return:  Size of message on success, 0 on failure
1211
 *
1212
 *-------------------------------------------------------------------------
1213
 */
1214
size_t
1215
H5O_msg_raw_size(const H5F_t *f, unsigned type_id, bool disable_shared, const void *mesg)
1216
0
{
1217
0
    const H5O_msg_class_t *type;          /* Actual H5O class type for the ID */
1218
0
    size_t                 ret_value = 0; /* Return value */
1219
1220
0
    FUNC_ENTER_NOAPI(0)
1221
1222
    /* Check args */
1223
0
    assert(type_id < NELMTS(H5O_msg_class_g));
1224
0
    type = H5O_msg_class_g[type_id]; /* map the type ID to the actual type object */
1225
0
    assert(type);
1226
0
    assert(type->raw_size);
1227
0
    assert(f);
1228
0
    assert(mesg);
1229
1230
    /* Compute the raw data size for the mesg */
1231
0
    if (0 == (ret_value = (type->raw_size)(f, disable_shared, mesg)))
1232
0
        HGOTO_ERROR(H5E_OHDR, H5E_CANTCOUNT, 0, "unable to determine size of message");
1233
1234
0
done:
1235
0
    FUNC_LEAVE_NOAPI(ret_value)
1236
0
} /* end H5O_msg_raw_size() */
1237
1238
/*-------------------------------------------------------------------------
1239
 * Function:  H5O_msg_size_f
1240
 *
1241
 * Purpose: Calculate the final size of an encoded message in an object
1242
 *              header.
1243
 *
1244
 * Note:  This routine assumes that the message size will be used in the
1245
 *              creation of a new object header.
1246
 *
1247
 * Return:  Size of message on success, 0 on failure
1248
 *
1249
 *-------------------------------------------------------------------------
1250
 */
1251
size_t
1252
H5O_msg_size_f(const H5F_t *f, hid_t ocpl_id, unsigned type_id, const void *mesg, size_t extra_raw)
1253
0
{
1254
0
    const H5O_msg_class_t *type;          /* Actual H5O class type for the ID */
1255
0
    H5P_genplist_t        *ocpl;          /* Object Creation Property list */
1256
0
    uint8_t                oh_flags;      /* Object header status flags */
1257
0
    size_t                 ret_value = 0; /* Return value */
1258
1259
0
    FUNC_ENTER_NOAPI(0)
1260
1261
    /* Check args */
1262
0
    assert(type_id < NELMTS(H5O_msg_class_g));
1263
0
    type = H5O_msg_class_g[type_id]; /* map the type ID to the actual type object */
1264
0
    assert(type);
1265
0
    assert(type->raw_size);
1266
0
    assert(f);
1267
0
    assert(mesg);
1268
1269
    /* Get the property list */
1270
0
    if (NULL == (ocpl = (H5P_genplist_t *)H5I_object(ocpl_id)))
1271
0
        HGOTO_ERROR(H5E_PLIST, H5E_BADTYPE, 0, "not a property list");
1272
1273
    /* Get any object header status flags set by properties */
1274
0
    if (H5P_get(ocpl, H5O_CRT_OHDR_FLAGS_NAME, &oh_flags) < 0)
1275
0
        HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, 0, "can't get object header flags");
1276
1277
    /* Compute the raw data size for the mesg */
1278
0
    if ((ret_value = (type->raw_size)(f, false, mesg)) == 0)
1279
0
        HGOTO_ERROR(H5E_OHDR, H5E_CANTCOUNT, 0, "unable to determine size of message");
1280
1281
    /* Add in "extra" raw space */
1282
0
    ret_value += extra_raw;
1283
1284
    /* Adjust size for alignment, if necessary */
1285
0
    ret_value = (size_t)H5O_ALIGN_F(f, ret_value);
1286
1287
    /* Add space for message header */
1288
0
    ret_value += (size_t)H5O_SIZEOF_MSGHDR_F(
1289
0
        f, (H5F_STORE_MSG_CRT_IDX(f) || oh_flags & H5O_HDR_ATTR_CRT_ORDER_TRACKED));
1290
1291
0
done:
1292
0
    FUNC_LEAVE_NOAPI(ret_value)
1293
0
} /* end H5O_msg_size_f() */
1294
1295
/*-------------------------------------------------------------------------
1296
 * Function:  H5O_msg_size_oh
1297
 *
1298
 * Purpose: Calculate the final size of an encoded message in an object
1299
 *              header.
1300
 *
1301
 * Note:  This routine assumes that the message is already used in
1302
 *              an object header.
1303
 *
1304
 * Return:  Size of message on success, 0 on failure
1305
 *
1306
 *-------------------------------------------------------------------------
1307
 */
1308
size_t
1309
H5O_msg_size_oh(const H5F_t *f, const H5O_t *oh, unsigned type_id, const void *mesg, size_t extra_raw)
1310
0
{
1311
0
    const H5O_msg_class_t *type;          /* Actual H5O class type for the ID */
1312
0
    size_t                 ret_value = 0; /* Return value */
1313
1314
0
    FUNC_ENTER_NOAPI(0)
1315
1316
    /* Check args */
1317
0
    assert(type_id < NELMTS(H5O_msg_class_g));
1318
0
    type = H5O_msg_class_g[type_id]; /* map the type ID to the actual type object */
1319
0
    assert(type);
1320
0
    assert(type->raw_size);
1321
0
    assert(f);
1322
0
    assert(mesg);
1323
1324
    /* Compute the raw data size for the mesg */
1325
0
    if ((ret_value = (type->raw_size)(f, false, mesg)) == 0)
1326
0
        HGOTO_ERROR(H5E_OHDR, H5E_CANTCOUNT, 0, "unable to determine size of message");
1327
1328
    /* Add in "extra" raw space */
1329
0
    ret_value += extra_raw;
1330
1331
    /* Adjust size for alignment, if necessary */
1332
0
    ret_value = (size_t)H5O_ALIGN_OH(oh, ret_value);
1333
1334
    /* Add space for message header */
1335
0
    ret_value += (size_t)H5O_SIZEOF_MSGHDR_OH(oh);
1336
1337
0
done:
1338
0
    FUNC_LEAVE_NOAPI(ret_value)
1339
0
} /* end H5O_msg_size_oh() */
1340
1341
/*-------------------------------------------------------------------------
1342
 * Function:    H5O_msg_can_share
1343
 *
1344
 * Purpose:     Call the 'can share' method for a
1345
 *              particular class of object header.  This returns true
1346
 *              if the message is allowed to be put in the shared message
1347
 *              heap and false otherwise (e.g., for committed or immutable
1348
 *              datatypes).
1349
 *
1350
 * Return:      Object can be shared:        true
1351
 *              Object cannot be shared:    false
1352
 *
1353
 *-------------------------------------------------------------------------
1354
 */
1355
htri_t
1356
H5O_msg_can_share(unsigned type_id, const void *mesg)
1357
0
{
1358
0
    const H5O_msg_class_t *type;             /* Actual H5O class type for the ID */
1359
0
    htri_t                 ret_value = FAIL; /* Return value */
1360
1361
0
    FUNC_ENTER_NOAPI_NOINIT_NOERR
1362
1363
    /* Check args */
1364
0
    assert(type_id < NELMTS(H5O_msg_class_g));
1365
0
    type = H5O_msg_class_g[type_id]; /* map the type ID to the actual type object */
1366
0
    assert(type);
1367
0
    assert(mesg);
1368
1369
    /* If there is a can_share callback, use it */
1370
0
    if (type->can_share)
1371
0
        ret_value = (type->can_share)(mesg);
1372
0
    else {
1373
        /* Otherwise, the message can be shared if messages of this type are
1374
         * shareable in general; i.e., if they have the "is_sharable" flag
1375
         * in the "share_flags" class member set.
1376
         */
1377
0
        ret_value = (type->share_flags & H5O_SHARE_IS_SHARABLE) ? true : false;
1378
0
    } /* end else */
1379
1380
    /* If the message is shareable, both copy_file and post_copy_file must be
1381
     * defined */
1382
0
    assert((type->post_copy_file && type->copy_file) || ret_value == false);
1383
1384
0
    FUNC_LEAVE_NOAPI(ret_value)
1385
0
} /* end H5O_msg_can_share() */
1386
1387
/*-------------------------------------------------------------------------
1388
 * Function:    H5O_msg_can_share_in_ohdr
1389
 *
1390
 * Purpose:     Check if the message class allows its messages to be shared
1391
 *              in the object's header.
1392
 *
1393
 * Return:      Object can be shared:        true
1394
 *              Object cannot be shared:    false
1395
 *
1396
 *-------------------------------------------------------------------------
1397
 */
1398
htri_t
1399
H5O_msg_can_share_in_ohdr(unsigned type_id)
1400
0
{
1401
0
    const H5O_msg_class_t *type;             /* Actual H5O class type for the ID */
1402
0
    htri_t                 ret_value = FAIL; /* Return value */
1403
1404
0
    FUNC_ENTER_NOAPI_NOINIT_NOERR
1405
1406
    /* Check args */
1407
0
    assert(type_id < NELMTS(H5O_msg_class_g));
1408
0
    type = H5O_msg_class_g[type_id]; /* map the type ID to the actual type object */
1409
0
    assert(type);
1410
1411
    /* Otherwise, the message can be shared if messages of this type are
1412
     * shareable in general; i.e., if they have the "is_sharable" flag
1413
     * in the "share_flags" class member set.
1414
     */
1415
0
    ret_value = (type->share_flags & H5O_SHARE_IN_OHDR) ? true : false;
1416
1417
0
    FUNC_LEAVE_NOAPI(ret_value)
1418
0
} /* end H5O_msg_can_share_in_ohdr() */
1419
1420
/*-------------------------------------------------------------------------
1421
 * Function:    H5O_msg_is_shared
1422
 *
1423
 * Purpose:     Call the 'is_shared' method for a
1424
 *              particular class of object header.
1425
 *
1426
 * Return:      Object is shared:        true
1427
 *              Object is not shared:    false
1428
 *
1429
 *-------------------------------------------------------------------------
1430
 */
1431
htri_t
1432
H5O_msg_is_shared(unsigned type_id, const void *mesg)
1433
0
{
1434
0
    const H5O_msg_class_t *type;             /* Actual H5O class type for the ID */
1435
0
    htri_t                 ret_value = FAIL; /* Return value */
1436
1437
0
    FUNC_ENTER_NOAPI_NOINIT_NOERR
1438
1439
    /* Check args */
1440
#ifdef H5O_ENABLE_BOGUS
1441
    if (type_id >= NELMTS(H5O_msg_class_g))
1442
        ret_value = false;
1443
    else
1444
#endif /* H5O_ENABLE_BOGUS */
1445
0
    {
1446
0
        assert(type_id < NELMTS(H5O_msg_class_g));
1447
0
        type = H5O_msg_class_g[type_id]; /* map the type ID to the actual type object */
1448
0
        assert(type);
1449
0
        assert(mesg);
1450
1451
        /* If messages in a class aren't shareable, then obviously this message isn't shared! :-) */
1452
0
        if (type->share_flags & H5O_SHARE_IS_SHARABLE)
1453
0
            ret_value = H5O_IS_STORED_SHARED(((const H5O_shared_t *)mesg)->type);
1454
0
        else
1455
0
            ret_value = false;
1456
0
    } /* end block/else */
1457
1458
0
    FUNC_LEAVE_NOAPI(ret_value)
1459
0
} /* end H5O_msg_is_shared() */
1460
1461
/*-------------------------------------------------------------------------
1462
 * Function:  H5O_msg_set_share
1463
 *
1464
 * Purpose: Set the shared information for an object header message.
1465
 *
1466
 * Return:  Success:  Non-negative
1467
 *    Failure:  Negative
1468
 *
1469
 *-------------------------------------------------------------------------
1470
 */
1471
herr_t
1472
H5O_msg_set_share(unsigned type_id, const H5O_shared_t *share, void *mesg)
1473
0
{
1474
0
    const H5O_msg_class_t *type;                /* Actual H5O class type for the ID */
1475
0
    herr_t                 ret_value = SUCCEED; /* Return value */
1476
1477
0
    FUNC_ENTER_NOAPI(FAIL)
1478
1479
    /* Check args */
1480
0
    assert(type_id < NELMTS(H5O_msg_class_g));
1481
0
    type = H5O_msg_class_g[type_id]; /* map the type ID to the actual type object */
1482
0
    assert(type);
1483
0
    assert(type->share_flags & H5O_SHARE_IS_SHARABLE);
1484
0
    assert(mesg);
1485
0
    assert(share);
1486
0
    assert(share->type != H5O_SHARE_TYPE_UNSHARED);
1487
1488
    /* If there's a special action for this class that needs to be performed
1489
     *  when setting the shared component, do that
1490
     */
1491
0
    if (type->set_share) {
1492
0
        if ((type->set_share)(mesg, share) < 0)
1493
0
            HGOTO_ERROR(H5E_OHDR, H5E_CANTSET, FAIL, "unable to set shared message information");
1494
0
    } /* end if */
1495
0
    else {
1496
        /* Set this message as the shared component for the message, wiping out
1497
         * any information that was there before
1498
         */
1499
0
        if (H5O_set_shared((H5O_shared_t *)mesg, share) < 0)
1500
0
            HGOTO_ERROR(H5E_OHDR, H5E_CANTSET, FAIL, "unable to set shared message information");
1501
0
    } /* end else */
1502
1503
0
done:
1504
0
    FUNC_LEAVE_NOAPI(ret_value)
1505
0
} /* end H5O_msg_set_share() */
1506
1507
/*-------------------------------------------------------------------------
1508
 * Function:  H5O_msg_reset_share
1509
 *
1510
 * Purpose: Reset the shared information for an object header message.
1511
 *
1512
 * Return:  Success:  Non-negative
1513
 *    Failure:  Negative
1514
 *
1515
 *-------------------------------------------------------------------------
1516
 */
1517
herr_t
1518
H5O_msg_reset_share(unsigned H5_ATTR_NDEBUG_UNUSED type_id, void *mesg)
1519
634
{
1520
634
    FUNC_ENTER_NOAPI_NOINIT_NOERR
1521
1522
    /* Check args */
1523
634
    assert(type_id < NELMTS(H5O_msg_class_g));
1524
634
    assert(H5O_msg_class_g[type_id]); /* map the type ID to the actual type object */
1525
634
    assert(H5O_msg_class_g[type_id]->share_flags & H5O_SHARE_IS_SHARABLE);
1526
634
    assert(mesg);
1527
1528
    /* Reset the shared component in the message to zero. */
1529
634
    memset((H5O_shared_t *)mesg, 0, sizeof(H5O_shared_t));
1530
1531
634
    FUNC_LEAVE_NOAPI(SUCCEED)
1532
634
} /* end H5O_msg_reset_share() */
1533
1534
/*-------------------------------------------------------------------------
1535
 * Function:    H5O_msg_get_crt_index
1536
 *
1537
 * Purpose:     Call the 'get creation index' method for a message.
1538
 *
1539
 * Return:  Success:  Non-negative
1540
 *    Failure:  Negative
1541
 *
1542
 *-------------------------------------------------------------------------
1543
 */
1544
herr_t
1545
H5O_msg_get_crt_index(unsigned type_id, const void *mesg, H5O_msg_crt_idx_t *crt_idx)
1546
0
{
1547
0
    const H5O_msg_class_t *type; /* Actual H5O class type for the ID */
1548
0
    herr_t                 ret_value = SUCCEED;
1549
1550
0
    FUNC_ENTER_NOAPI(FAIL)
1551
1552
    /* Check args */
1553
0
    assert(type_id < NELMTS(H5O_msg_class_g));
1554
0
    type = H5O_msg_class_g[type_id]; /* map the type ID to the actual type object */
1555
0
    assert(type);
1556
0
    assert(mesg);
1557
0
    assert(crt_idx);
1558
1559
    /* If there is a "get_crt_index callback, use it */
1560
0
    if (type->get_crt_index) {
1561
        /* Retrieve the creation index from the native message */
1562
0
        if ((type->get_crt_index)(mesg, crt_idx) < 0)
1563
0
            HGOTO_ERROR(H5E_OHDR, H5E_CANTGET, FAIL, "unable to retrieve creation index");
1564
0
    } /* end if */
1565
0
    else
1566
0
        *crt_idx = 0;
1567
1568
0
done:
1569
0
    FUNC_LEAVE_NOAPI(ret_value)
1570
0
} /* end H5O_msg_get_crt_index() */
1571
1572
/*-------------------------------------------------------------------------
1573
 * Function:  H5O_msg_encode
1574
 *
1575
 * Purpose: Encode an object(data type and simple dataspace only)
1576
 *              description into a buffer.
1577
 *
1578
 * Return:  Success:  Non-negative
1579
 *
1580
 *    Failure:  Negative
1581
 *
1582
 *-------------------------------------------------------------------------
1583
 */
1584
herr_t
1585
H5O_msg_encode(H5F_t *f, unsigned type_id, bool disable_shared, unsigned char *buf, const void *mesg)
1586
0
{
1587
0
    const H5O_msg_class_t *type;                /* Actual H5O class type for the ID */
1588
0
    herr_t                 ret_value = SUCCEED; /* Return value */
1589
1590
0
    FUNC_ENTER_NOAPI(FAIL)
1591
1592
    /* check args */
1593
0
    assert(f);
1594
0
    assert(type_id < NELMTS(H5O_msg_class_g));
1595
0
    type = H5O_msg_class_g[type_id]; /* map the type ID to the actual type object */
1596
0
    assert(type);
1597
1598
    /* Encode */
1599
0
    if ((type->encode)(f, disable_shared, SIZE_MAX, buf, mesg) < 0)
1600
0
        HGOTO_ERROR(H5E_OHDR, H5E_CANTENCODE, FAIL, "unable to encode message");
1601
1602
0
done:
1603
0
    FUNC_LEAVE_NOAPI(ret_value)
1604
0
} /* end H5O_msg_encode() */
1605
1606
/*-------------------------------------------------------------------------
1607
 * Function:  H5O_msg_decode
1608
 *
1609
 * Purpose: Decode a binary object description and return a new
1610
 *              object handle.
1611
 *
1612
 * Return:  Success:        Pointer to object(data type or space)
1613
 *
1614
 *    Failure:  NULL
1615
 *
1616
 *-------------------------------------------------------------------------
1617
 */
1618
void *
1619
H5O_msg_decode(H5F_t *f, H5O_t *open_oh, unsigned type_id, size_t buf_size, const unsigned char *buf)
1620
0
{
1621
0
    const H5O_msg_class_t *type;             /* Actual H5O class type for the ID */
1622
0
    unsigned               ioflags   = 0;    /* Flags for decode routine */
1623
0
    void                  *ret_value = NULL; /* Return value */
1624
1625
0
    FUNC_ENTER_NOAPI(NULL)
1626
1627
    /* check args */
1628
0
    assert(f);
1629
0
    assert(type_id < NELMTS(H5O_msg_class_g));
1630
0
    type = H5O_msg_class_g[type_id]; /* map the type ID to the actual type object */
1631
0
    assert(type);
1632
1633
    /* decode */
1634
0
    if (NULL == (ret_value = (type->decode)(f, open_oh, 0, &ioflags, buf_size, buf)))
1635
0
        HGOTO_ERROR(H5E_OHDR, H5E_CANTDECODE, NULL, "unable to decode message");
1636
1637
0
done:
1638
0
    FUNC_LEAVE_NOAPI(ret_value)
1639
0
} /* end H5O_msg_decode() */
1640
1641
/*-------------------------------------------------------------------------
1642
 * Function:    H5O__msg_copy_file
1643
 *
1644
 * Purpose:     Copies a message to file.  If MESG is the null pointer then a null
1645
 *              pointer is returned with no error.
1646
 *
1647
 *              Attempts to share the message in the destination and sets
1648
 *              SHARED to true or false depending on whether this succeeds.
1649
 *
1650
 * Return:      Success:        Ptr to the new message
1651
 *
1652
 *              Failure:        NULL
1653
 *
1654
 *-------------------------------------------------------------------------
1655
 */
1656
void *
1657
H5O__msg_copy_file(const H5O_msg_class_t *type, H5F_t *file_src, void *native_src, H5F_t *file_dst,
1658
                   bool *recompute_size, unsigned *mesg_flags, H5O_copy_t *cpy_info, void *udata)
1659
0
{
1660
0
    void *ret_value = NULL; /* Return value */
1661
1662
0
    FUNC_ENTER_PACKAGE
1663
1664
    /* check args */
1665
0
    assert(type);
1666
0
    assert(type->copy_file);
1667
0
    assert(file_src);
1668
0
    assert(native_src);
1669
0
    assert(file_dst);
1670
0
    assert(recompute_size);
1671
0
    assert(cpy_info);
1672
1673
    /* The copy_file callback will return an H5O_shared_t only if the message
1674
     * to be copied is a committed datatype.
1675
     */
1676
0
    if (NULL == (ret_value = (type->copy_file)(file_src, native_src, file_dst, recompute_size, mesg_flags,
1677
0
                                               cpy_info, udata)))
1678
0
        HGOTO_ERROR(H5E_OHDR, H5E_CANTCOPY, NULL, "unable to copy object header message to file");
1679
1680
0
done:
1681
0
    FUNC_LEAVE_NOAPI(ret_value)
1682
0
} /* end H5O__msg_copy_file() */
1683
1684
/*-------------------------------------------------------------------------
1685
 * Function:  H5O__msg_alloc
1686
 *
1687
 * Purpose: Create a new message in an object header
1688
 *
1689
 * Return:  Success:  Index of message
1690
 *    Failure:  Negative
1691
 *
1692
 *-------------------------------------------------------------------------
1693
 */
1694
herr_t
1695
H5O__msg_alloc(H5F_t *f, H5O_t *oh, const H5O_msg_class_t *type, unsigned *mesg_flags, void *native,
1696
               size_t *mesg_idx)
1697
0
{
1698
0
    size_t new_idx;             /* New index for message */
1699
0
    htri_t shared_mesg;         /* Should this message be stored in the Shared Message table? */
1700
0
    herr_t ret_value = SUCCEED; /* Return value */
1701
1702
0
    FUNC_ENTER_PACKAGE
1703
1704
    /* check args */
1705
0
    assert(f);
1706
0
    assert(oh);
1707
0
    assert(mesg_flags);
1708
0
    assert(!(*mesg_flags & H5O_MSG_FLAG_SHARED));
1709
0
    assert(type);
1710
0
    assert(native);
1711
0
    assert(mesg_idx);
1712
1713
    /* Check if message is already shared */
1714
0
    if ((shared_mesg = H5O_msg_is_shared(type->id, native)) < 0)
1715
0
        HGOTO_ERROR(H5E_OHDR, H5E_CANTGET, FAIL, "error determining if message is shared");
1716
0
    else if (shared_mesg > 0) {
1717
        /* Increment message's reference count */
1718
0
        if (type->link && (type->link)(f, oh, native) < 0)
1719
0
            HGOTO_ERROR(H5E_OHDR, H5E_LINKCOUNT, FAIL, "unable to adjust shared message ref count");
1720
0
        *mesg_flags |= H5O_MSG_FLAG_SHARED;
1721
0
    } /* end if */
1722
0
    else {
1723
        /* Attempt to share message */
1724
0
        if (H5SM_try_share(f, oh, 0, type->id, native, mesg_flags) < 0)
1725
0
            HGOTO_ERROR(H5E_OHDR, H5E_WRITEERROR, FAIL, "error determining if message should be shared");
1726
0
    } /* end else */
1727
1728
    /* Allocate space in the object header for the message */
1729
0
    if (H5O__alloc(f, oh, type, native, &new_idx) < 0)
1730
0
        HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, FAIL, "unable to allocate space for message");
1731
1732
    /* Get the message's "creation index", if it has one */
1733
0
    if (type->get_crt_index) {
1734
        /* Retrieve the creation index from the native message */
1735
0
        if ((type->get_crt_index)(native, &oh->mesg[new_idx].crt_idx) < 0)
1736
0
            HGOTO_ERROR(H5E_OHDR, H5E_CANTGET, FAIL, "unable to retrieve creation index");
1737
0
    } /* end if */
1738
1739
    /* Set new message index */
1740
0
    *mesg_idx = new_idx;
1741
1742
0
done:
1743
0
    FUNC_LEAVE_NOAPI(ret_value)
1744
0
} /* end H5O__msg_alloc() */
1745
1746
/*-------------------------------------------------------------------------
1747
 * Function:  H5O__copy_mesg
1748
 *
1749
 * Purpose: Make a copy of the native object for an object header's
1750
 *              native message info
1751
 *
1752
 * Return:  Non-negative on success/Negative on failure
1753
 *
1754
 *-------------------------------------------------------------------------
1755
 */
1756
static herr_t
1757
H5O__copy_mesg(H5F_t *f, H5O_t *oh, size_t idx, const H5O_msg_class_t *type, const void *mesg,
1758
               unsigned mesg_flags, unsigned update_flags)
1759
0
{
1760
0
    H5O_chunk_proxy_t *chk_proxy   = NULL;           /* Chunk that message is in */
1761
0
    H5O_mesg_t        *idx_msg     = &oh->mesg[idx]; /* Pointer to message to modify */
1762
0
    bool               chk_dirtied = false;          /* Flag for unprotecting chunk */
1763
0
    herr_t             ret_value   = SUCCEED;        /* Return value */
1764
1765
0
    FUNC_ENTER_PACKAGE
1766
1767
    /* check args */
1768
0
    assert(f);
1769
0
    assert(oh);
1770
0
    assert(type);
1771
0
    assert(type->copy);
1772
0
    assert(mesg);
1773
1774
    /* Protect chunk */
1775
0
    if (NULL == (chk_proxy = H5O__chunk_protect(f, oh, idx_msg->chunkno)))
1776
0
        HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, FAIL, "unable to protect object header chunk");
1777
1778
    /* Reset existing native information for the header's message */
1779
0
    H5O__msg_reset_real(type, idx_msg->native);
1780
1781
    /* Copy the native object for the message */
1782
0
    if (NULL == (idx_msg->native = (type->copy)(mesg, idx_msg->native)))
1783
0
        HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, FAIL, "unable to copy message to object header");
1784
1785
    /* Update the message flags */
1786
0
    idx_msg->flags = (uint8_t)mesg_flags;
1787
1788
    /* Mark the message as modified */
1789
0
    idx_msg->dirty = true;
1790
0
    chk_dirtied    = true;
1791
1792
    /* Release chunk */
1793
0
    if (H5O__chunk_unprotect(f, chk_proxy, chk_dirtied) < 0)
1794
0
        HGOTO_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, FAIL, "unable to release object header chunk");
1795
0
    chk_proxy = NULL;
1796
1797
    /* Update the modification time, if requested */
1798
0
    if (update_flags & H5O_UPDATE_TIME)
1799
0
        if (H5O_touch_oh(f, oh, false) < 0)
1800
0
            HGOTO_ERROR(H5E_OHDR, H5E_CANTUPDATE, FAIL, "unable to update time on object");
1801
1802
0
done:
1803
    /* Release chunk, if not already released */
1804
0
    if (chk_proxy && H5O__chunk_unprotect(f, chk_proxy, chk_dirtied) < 0)
1805
0
        HDONE_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, FAIL, "unable to release object header chunk");
1806
1807
0
    FUNC_LEAVE_NOAPI(ret_value)
1808
0
} /* end H5O__copy_mesg() */
1809
1810
/*-------------------------------------------------------------------------
1811
 * Function:    H5O_msg_delete
1812
 *
1813
 * Purpose:     Calls a message's delete callback.
1814
 *
1815
 *              This is mostly redundant with H5O__delete_mesg below,
1816
 *              but H5O__delete_mesg only works on messages in object headers
1817
 *              (while the shared message code needs to delete messages in
1818
 *              the heap).
1819
 *
1820
 *              open_oh is a pointer to a currently open object header so
1821
 *              that the library doesn't try to re-protect it.  If there is
1822
 *              no such object header, it should be NULL.
1823
 *
1824
 * Return:      Success:        Non-negative
1825
 *              Failure:        Negative
1826
 *
1827
 *-------------------------------------------------------------------------
1828
 */
1829
herr_t
1830
H5O_msg_delete(H5F_t *f, H5O_t *open_oh, unsigned type_id, void *mesg)
1831
0
{
1832
0
    const H5O_msg_class_t *type;                /* Actual H5O class type for the ID */
1833
0
    herr_t                 ret_value = SUCCEED; /* Return value */
1834
1835
0
    FUNC_ENTER_NOAPI(FAIL)
1836
1837
    /* check args */
1838
0
    assert(f);
1839
0
    assert(type_id < NELMTS(H5O_msg_class_g));
1840
0
    type = H5O_msg_class_g[type_id]; /* map the type ID to the actual type object */
1841
0
    assert(type);
1842
1843
    /* delete */
1844
0
    if ((type->del) && (type->del)(f, open_oh, mesg) < 0)
1845
0
        HGOTO_ERROR(H5E_OHDR, H5E_CANTDELETE, FAIL, "unable to delete file space for object header message");
1846
1847
0
done:
1848
0
    FUNC_LEAVE_NOAPI(ret_value)
1849
0
} /* end H5O_msg_delete() */
1850
1851
/*-------------------------------------------------------------------------
1852
 * Function:  H5O__delete_mesg
1853
 *
1854
 * Purpose: Internal function to:
1855
 *              Delete an object header message from a file.  This frees the file
1856
 *              space used for anything referred to in the object header message.
1857
 *
1858
 * Return:  Non-negative on success/Negative on failure
1859
 *
1860
 *-------------------------------------------------------------------------
1861
 */
1862
herr_t
1863
H5O__delete_mesg(H5F_t *f, H5O_t *oh, H5O_mesg_t *mesg)
1864
0
{
1865
0
    const H5O_msg_class_t *type      = mesg->type; /* Type of object to free */
1866
0
    herr_t                 ret_value = SUCCEED;    /* Return value */
1867
1868
0
    FUNC_ENTER_PACKAGE
1869
1870
    /* Check args */
1871
0
    assert(f);
1872
0
    assert(mesg);
1873
0
    assert(oh);
1874
1875
    /* Check if there is a file space deletion callback for this type of message */
1876
0
    if (type->del) {
1877
        /* Decode the message if necessary. */
1878
0
        H5O_LOAD_NATIVE(f, H5O_DECODEIO_NOCHANGE, oh, mesg, FAIL)
1879
1880
0
        if ((type->del)(f, oh, mesg->native) < 0)
1881
0
            HGOTO_ERROR(H5E_OHDR, H5E_CANTDELETE, FAIL,
1882
0
                        "unable to delete file space for object header message");
1883
0
    } /* end if */
1884
1885
0
done:
1886
0
    FUNC_LEAVE_NOAPI(ret_value)
1887
0
} /* end H5O__delete_mesg() */
1888
1889
/*-------------------------------------------------------------------------
1890
 * Function:  H5O_msg_flush
1891
 *
1892
 * Purpose: Flushes a message for an object header.
1893
 *
1894
 * Return:  Non-negative on success/Negative on failure
1895
 *
1896
 *-------------------------------------------------------------------------
1897
 */
1898
herr_t
1899
H5O_msg_flush(H5F_t *f, H5O_t *oh, H5O_mesg_t *mesg)
1900
0
{
1901
0
    uint8_t *p;                   /* Temporary pointer to encode with */
1902
0
    unsigned msg_id;              /* ID for message */
1903
0
    herr_t   ret_value = SUCCEED; /* Return value */
1904
1905
0
    FUNC_ENTER_NOAPI(FAIL)
1906
1907
    /* check args */
1908
0
    assert(f);
1909
0
    assert(oh);
1910
1911
    /* Point into message's chunk's image */
1912
0
    p = mesg->raw - H5O_SIZEOF_MSGHDR_OH(oh);
1913
1914
    /* Retrieve actual message ID, for unknown messages */
1915
0
    if (mesg->type == H5O_MSG_UNKNOWN)
1916
0
        msg_id = *(H5O_unknown_t *)(mesg->native);
1917
0
    else
1918
0
        msg_id = (uint8_t)mesg->type->id;
1919
1920
    /* Encode the message prefix */
1921
0
    if (oh->version == H5O_VERSION_1)
1922
0
        UINT16ENCODE(p, msg_id);
1923
0
    else
1924
0
        *p++ = (uint8_t)msg_id;
1925
0
    assert(mesg->raw_size < H5O_MESG_MAX_SIZE);
1926
0
    UINT16ENCODE(p, mesg->raw_size);
1927
0
    *p++ = mesg->flags;
1928
1929
    /* Only encode reserved bytes for version 1 of format */
1930
0
    if (oh->version == H5O_VERSION_1) {
1931
0
        *p++ = 0; /*reserved*/
1932
0
        *p++ = 0; /*reserved*/
1933
0
        *p++ = 0; /*reserved*/
1934
0
    }             /* end for */
1935
    /* Only encode creation index for version 2+ of format */
1936
0
    else {
1937
        /* Only encode creation index if they are being tracked */
1938
0
        if (oh->flags & H5O_HDR_ATTR_CRT_ORDER_TRACKED)
1939
0
            UINT16ENCODE(p, mesg->crt_idx);
1940
0
    } /* end else */
1941
0
    assert(p == mesg->raw);
1942
1943
#ifndef NDEBUG
1944
    /* Make certain that null messages aren't in chunks w/gaps */
1945
    if (H5O_NULL_ID == msg_id)
1946
        assert(oh->chunk[mesg->chunkno].gap == 0);
1947
    else
1948
        /* Non-null messages should always have a native pointer */
1949
        assert(mesg->native);
1950
#endif /* NDEBUG */
1951
1952
    /* Encode the message itself, if it's not an "unknown" message */
1953
0
    if (mesg->native && mesg->type != H5O_MSG_UNKNOWN) {
1954
        /*
1955
         * Encode the message.  If the message is shared then we
1956
         * encode a Shared Object message instead of the object
1957
         * which is being shared.
1958
         */
1959
0
        assert(mesg->raw >= oh->chunk[mesg->chunkno].image);
1960
0
        assert(mesg->raw_size == H5O_ALIGN_OH(oh, mesg->raw_size));
1961
0
        assert(mesg->raw + mesg->raw_size <=
1962
0
               oh->chunk[mesg->chunkno].image + (oh->chunk[mesg->chunkno].size - H5O_SIZEOF_CHKSUM_OH(oh)));
1963
#ifndef NDEBUG
1964
        /* Sanity check that the message won't overwrite past it's allocated space */
1965
        {
1966
            size_t msg_size;
1967
1968
            msg_size = mesg->type->raw_size(f, false, mesg->native);
1969
            msg_size = H5O_ALIGN_OH(oh, msg_size);
1970
            assert(msg_size <= mesg->raw_size);
1971
        }
1972
#endif /* NDEBUG */
1973
0
        assert(mesg->type->encode);
1974
0
        if ((mesg->type->encode)(f, false, mesg->raw_size, mesg->raw, mesg->native) < 0)
1975
0
            HGOTO_ERROR(H5E_OHDR, H5E_CANTENCODE, FAIL, "unable to encode object header message");
1976
0
    } /* end if */
1977
1978
    /* Mark the message as clean now */
1979
0
    mesg->dirty = false;
1980
1981
0
done:
1982
0
    FUNC_LEAVE_NOAPI(ret_value)
1983
0
} /* end H5O_msg_flush() */
1984
1985
/*-------------------------------------------------------------------------
1986
 * Function:  H5O__flush_msgs
1987
 *
1988
 * Purpose: Flushes messages for object header.
1989
 *
1990
 * Return:  Non-negative on success/Negative on failure
1991
 *
1992
 *-------------------------------------------------------------------------
1993
 */
1994
herr_t
1995
H5O__flush_msgs(H5F_t *f, H5O_t *oh)
1996
0
{
1997
0
    H5O_mesg_t *curr_msg;            /* Pointer to current message being operated on */
1998
0
    unsigned    u;                   /* Local index variable */
1999
0
    herr_t      ret_value = SUCCEED; /* Return value */
2000
2001
0
    FUNC_ENTER_PACKAGE
2002
2003
    /* check args */
2004
0
    assert(f);
2005
0
    assert(oh);
2006
2007
    /* Encode any dirty messages */
2008
0
    for (u = 0, curr_msg = &oh->mesg[0]; u < oh->nmesgs; u++, curr_msg++)
2009
0
        if (curr_msg->dirty)
2010
0
            if (H5O_msg_flush(f, oh, curr_msg) < 0)
2011
0
                HGOTO_ERROR(H5E_OHDR, H5E_CANTENCODE, FAIL, "unable to encode object header message");
2012
2013
    /* Sanity check for the correct # of messages in object header */
2014
0
    if (oh->nmesgs != u)
2015
0
        HGOTO_ERROR(H5E_OHDR, H5E_CANTFLUSH, FAIL, "corrupt object header - too few messages");
2016
2017
#ifndef NDEBUG
2018
    /* Reset the number of messages dirtied by decoding, as they have all
2019
     * been flushed */
2020
    oh->ndecode_dirtied = 0;
2021
#endif /* NDEBUG */
2022
2023
0
done:
2024
0
    FUNC_LEAVE_NOAPI(ret_value)
2025
0
} /* end H5O__flush_msgs() */
2026
2027
/*-------------------------------------------------------------------------
2028
 * Function:  H5O_msg_get_flags
2029
 *
2030
 * Purpose: Queries a message's message flags in the object header
2031
 *
2032
 * Return:  Non-negative on success/Negative on failure
2033
 *
2034
 *-------------------------------------------------------------------------
2035
 */
2036
herr_t
2037
H5O_msg_get_flags(const H5O_loc_t *loc, unsigned type_id, uint8_t *flags)
2038
0
{
2039
0
    H5O_t                 *oh = NULL;           /* Object header to use */
2040
0
    const H5O_msg_class_t *type;                /* Actual H5O class type for the ID */
2041
0
    H5O_mesg_t            *idx_msg;             /* Pointer to message to modify */
2042
0
    unsigned               idx;                 /* Index of message to modify */
2043
0
    herr_t                 ret_value = SUCCEED; /* Return value */
2044
2045
0
    FUNC_ENTER_NOAPI(FAIL)
2046
2047
    /* check args */
2048
0
    assert(loc);
2049
0
    assert(loc->file);
2050
0
    assert(H5_addr_defined(loc->addr));
2051
0
    assert(type_id < NELMTS(H5O_msg_class_g));
2052
0
    type = H5O_msg_class_g[type_id]; /* map the type ID to the actual type object */
2053
0
    assert(type);
2054
2055
    /* Get the object header */
2056
0
    if (NULL == (oh = H5O_protect(loc, H5AC__READ_ONLY_FLAG, false)))
2057
0
        HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, FAIL, "unable to protect object header");
2058
2059
    /* Locate message of correct type */
2060
0
    for (idx = 0, idx_msg = &oh->mesg[0]; idx < oh->nmesgs; idx++, idx_msg++)
2061
0
        if (type == idx_msg->type)
2062
0
            break;
2063
2064
0
    if (idx == oh->nmesgs)
2065
0
        HGOTO_ERROR(H5E_OHDR, H5E_NOTFOUND, FAIL, "message type not found");
2066
2067
    /* Set return value */
2068
0
    *flags = idx_msg->flags;
2069
2070
0
done:
2071
0
    if (oh && H5O_unprotect(loc, oh, H5AC__NO_FLAGS_SET) < 0)
2072
0
        HDONE_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, FAIL, "unable to release object header");
2073
2074
0
    FUNC_LEAVE_NOAPI(ret_value)
2075
0
} /* end H5O_msg_get_flags() */