Coverage Report

Created: 2025-11-24 06:13

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/hdf5/src/H5Gcompact.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:   H5Gcompact.c
16
 *
17
 * Purpose:   Functions for handling compact storage.
18
 *
19
 *-------------------------------------------------------------------------
20
 */
21
#include "H5Gmodule.h" /* This source code file is part of the H5G module */
22
23
/* Packages needed by this file... */
24
#include "H5private.h"   /* Generic Functions     */
25
#include "H5Eprivate.h"  /* Error handling        */
26
#include "H5Gpkg.h"      /* Groups          */
27
#include "H5MMprivate.h" /* Memory management     */
28
29
/* Private typedefs */
30
31
/* User data for link message iteration when building link table */
32
typedef struct {
33
    H5G_link_table_t *ltable;   /* Pointer to link table to build */
34
    size_t            curr_lnk; /* Current link to operate on */
35
} H5G_iter_bt_t;
36
37
/* User data for deleting a link in the link messages */
38
typedef struct {
39
    /* downward */
40
    H5F_t      *file;            /* File that object header is located within */
41
    H5RS_str_t *grp_full_path_r; /* Full path for group of link */
42
    const char *name;            /* Link name to search for */
43
} H5G_iter_rm_t;
44
45
/* User data for link message iteration when querying link info */
46
typedef struct {
47
    /* downward */
48
    const char *name; /* Name to search for */
49
50
    /* upward */
51
    H5O_link_t *lnk;   /* Link struct to fill in */
52
    bool       *found; /* Pointer to flag to indicate that the object was found */
53
} H5G_iter_lkp_t;
54
55
/* Private macros */
56
57
/* PRIVATE PROTOTYPES */
58
static herr_t H5G__compact_build_table_cb(const void *_mesg, unsigned idx, void *_udata);
59
static herr_t H5G__compact_build_table(const H5O_loc_t *oloc, const H5O_linfo_t *linfo, H5_index_t idx_type,
60
                                       H5_iter_order_t order, H5G_link_table_t *ltable);
61
static herr_t H5G__compact_lookup_cb(const void *_mesg, unsigned H5_ATTR_UNUSED idx, void *_udata);
62
63
/*-------------------------------------------------------------------------
64
 * Function:    H5G__compact_build_table_cb
65
 *
66
 * Purpose:     Callback routine for searching 'link' messages for a particular
67
 *              name.
68
 *
69
 * Return:      SUCCEED/FAIL
70
 *
71
 *-------------------------------------------------------------------------
72
 */
73
static herr_t
74
H5G__compact_build_table_cb(const void *_mesg, unsigned H5_ATTR_UNUSED idx, void *_udata)
75
0
{
76
0
    const H5O_link_t *lnk       = (const H5O_link_t *)_mesg; /* Pointer to link */
77
0
    H5G_iter_bt_t    *udata     = (H5G_iter_bt_t *)_udata;   /* 'User data' passed in */
78
0
    herr_t            ret_value = H5_ITER_CONT;              /* Return value */
79
80
0
    FUNC_ENTER_PACKAGE
81
82
    /* check arguments */
83
0
    assert(lnk);
84
0
    assert(udata);
85
0
    assert(udata->curr_lnk < udata->ltable->nlinks);
86
87
    /* Copy link message into table */
88
0
    if (NULL == H5O_msg_copy(H5O_LINK_ID, lnk, &(udata->ltable->lnks[udata->curr_lnk])))
89
0
        HGOTO_ERROR(H5E_SYM, H5E_CANTCOPY, H5_ITER_ERROR, "can't copy link message");
90
91
    /* Increment current link entry to operate on */
92
0
    udata->curr_lnk++;
93
94
0
done:
95
0
    FUNC_LEAVE_NOAPI(ret_value)
96
0
} /* end H5G__compact_build_table_cb() */
97
98
/*-------------------------------------------------------------------------
99
 * Function:  H5G__compact_build_table
100
 *
101
 * Purpose:     Builds a table containing a sorted (alphabetically) list of
102
 *              links for a group
103
 *
104
 * Return:  Success:        Non-negative
105
 *    Failure:  Negative
106
 *
107
 *-------------------------------------------------------------------------
108
 */
109
static herr_t
110
H5G__compact_build_table(const H5O_loc_t *oloc, const H5O_linfo_t *linfo, H5_index_t idx_type,
111
                         H5_iter_order_t order, H5G_link_table_t *ltable)
112
0
{
113
0
    herr_t ret_value = SUCCEED; /* Return value */
114
115
0
    FUNC_ENTER_PACKAGE
116
117
    /* Sanity check */
118
0
    assert(oloc);
119
0
    assert(linfo);
120
0
    assert(ltable);
121
122
    /* Set size of table */
123
0
    H5_CHECK_OVERFLOW(linfo->nlinks, hsize_t, size_t);
124
0
    ltable->nlinks = (size_t)linfo->nlinks;
125
126
    /* Allocate space for the table entries */
127
0
    if (ltable->nlinks > 0) {
128
0
        H5G_iter_bt_t       udata; /* User data for iteration callback */
129
0
        H5O_mesg_operator_t op;    /* Message operator */
130
131
        /* Allocate the link table */
132
0
        if ((ltable->lnks = (H5O_link_t *)H5MM_calloc(sizeof(H5O_link_t) * ltable->nlinks)) == NULL)
133
0
            HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed");
134
135
        /* Set up user data for iteration */
136
0
        udata.ltable   = ltable;
137
0
        udata.curr_lnk = 0;
138
139
        /* Iterate through the link messages, adding them to the table */
140
0
        op.op_type  = H5O_MESG_OP_APP;
141
0
        op.u.app_op = H5G__compact_build_table_cb;
142
0
        if (H5O_msg_iterate(oloc, H5O_LINK_ID, &op, &udata) < 0)
143
0
            HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "error iterating over link messages");
144
145
        /* Sort link table in correct iteration order */
146
0
        if (H5G__link_sort_table(ltable, idx_type, order) < 0)
147
0
            HGOTO_ERROR(H5E_SYM, H5E_CANTSORT, FAIL, "error sorting link messages");
148
0
    } /* end if */
149
0
    else
150
0
        ltable->lnks = NULL;
151
152
0
done:
153
0
    FUNC_LEAVE_NOAPI(ret_value)
154
0
} /* end H5G__compact_build_table() */
155
156
/*-------------------------------------------------------------------------
157
 * Function:  H5G__compact_insert
158
 *
159
 * Purpose: Insert a new symbol into the table described by GRP_ENT in
160
 *    file F.  The name of the new symbol is NAME and its symbol
161
 *    table entry is OBJ_ENT.
162
 *
163
 * Return:  Non-negative on success/Negative on failure
164
 *
165
 *-------------------------------------------------------------------------
166
 */
167
herr_t
168
H5G__compact_insert(const H5O_loc_t *grp_oloc, H5O_link_t *obj_lnk)
169
0
{
170
0
    herr_t ret_value = SUCCEED; /* Return value */
171
172
0
    FUNC_ENTER_PACKAGE
173
174
    /* check arguments */
175
0
    assert(grp_oloc && grp_oloc->file);
176
0
    assert(obj_lnk);
177
178
    /* Insert link message into group */
179
0
    if (H5O_msg_create(grp_oloc, H5O_LINK_ID, 0, H5O_UPDATE_TIME, obj_lnk) < 0)
180
0
        HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "can't create message");
181
182
0
done:
183
0
    FUNC_LEAVE_NOAPI(ret_value)
184
0
} /* end H5G__compact_insert() */
185
186
/*-------------------------------------------------------------------------
187
 * Function:  H5G__compact_get_name_by_idx
188
 *
189
 * Purpose:     Returns the name of objects in the group by giving index.
190
 *
191
 * Return:  Non-negative on success/Negative on failure
192
 *
193
 *-------------------------------------------------------------------------
194
 */
195
herr_t
196
H5G__compact_get_name_by_idx(const H5O_loc_t *oloc, const H5O_linfo_t *linfo, H5_index_t idx_type,
197
                             H5_iter_order_t order, hsize_t idx, char *name, size_t name_size,
198
                             size_t *name_len)
199
0
{
200
0
    H5G_link_table_t ltable    = {0, NULL}; /* Link table */
201
0
    herr_t           ret_value = SUCCEED;   /* Return value */
202
203
0
    FUNC_ENTER_PACKAGE
204
205
    /* Sanity check */
206
0
    assert(oloc);
207
208
    /* Build table of all link messages */
209
0
    if (H5G__compact_build_table(oloc, linfo, idx_type, order, &ltable) < 0)
210
0
        HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "can't create link message table");
211
212
    /* Check for going out of bounds */
213
0
    if (idx >= ltable.nlinks)
214
0
        HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "index out of bound");
215
216
    /* Get the length of the name */
217
0
    *name_len = strlen(ltable.lnks[idx].name);
218
219
    /* Copy the name into the user's buffer, if given */
220
0
    if (name) {
221
0
        strncpy(name, ltable.lnks[idx].name, MIN((*name_len + 1), name_size));
222
0
        if (*name_len >= name_size)
223
0
            name[name_size - 1] = '\0';
224
0
    } /* end if */
225
226
0
done:
227
    /* Release link table */
228
0
    if (ltable.lnks && H5G__link_release_table(&ltable) < 0)
229
0
        HDONE_ERROR(H5E_SYM, H5E_CANTFREE, FAIL, "unable to release link table");
230
231
0
    FUNC_LEAVE_NOAPI(ret_value)
232
0
} /* end H5G__compact_get_name_by_idx() */
233
234
/*-------------------------------------------------------------------------
235
 * Function:  H5G__compact_remove_common_cb
236
 *
237
 * Purpose: Common callback routine for deleting 'link' message for a
238
 *              particular name.
239
 *
240
 * Return:  Non-negative on success/Negative on failure
241
 *
242
 *-------------------------------------------------------------------------
243
 */
244
static herr_t
245
H5G__compact_remove_common_cb(const void *_mesg, unsigned H5_ATTR_UNUSED idx, void *_udata)
246
0
{
247
0
    const H5O_link_t *lnk       = (const H5O_link_t *)_mesg; /* Pointer to link */
248
0
    H5G_iter_rm_t    *udata     = (H5G_iter_rm_t *)_udata;   /* 'User data' passed in */
249
0
    herr_t            ret_value = H5_ITER_CONT;              /* Return value */
250
251
0
    FUNC_ENTER_PACKAGE
252
253
    /* check arguments */
254
0
    assert(lnk);
255
0
    assert(udata);
256
257
    /* If we've found the right link, get the object type */
258
0
    if (strcmp(lnk->name, udata->name) == 0) {
259
        /* Replace path names for link being removed */
260
0
        if (H5G__link_name_replace(udata->file, udata->grp_full_path_r, lnk) < 0)
261
0
            HGOTO_ERROR(H5E_SYM, H5E_CANTGET, H5_ITER_ERROR, "unable to get object type");
262
263
        /* Stop the iteration, we found the correct link */
264
0
        HGOTO_DONE(H5_ITER_STOP);
265
0
    } /* end if */
266
267
0
done:
268
0
    FUNC_LEAVE_NOAPI(ret_value)
269
0
} /* end H5G__compact_remove_common_cb() */
270
271
/*-------------------------------------------------------------------------
272
 * Function:  H5G__compact_remove
273
 *
274
 * Purpose: Remove NAME from links.
275
 *
276
 * Return:  Non-negative on success/Negative on failure
277
 *
278
 *-------------------------------------------------------------------------
279
 */
280
herr_t
281
H5G__compact_remove(const H5O_loc_t *oloc, H5RS_str_t *grp_full_path_r, const char *name)
282
0
{
283
0
    H5G_iter_rm_t udata;               /* Data to pass through OH iteration */
284
0
    herr_t        ret_value = SUCCEED; /* Return value */
285
286
0
    FUNC_ENTER_PACKAGE
287
288
0
    assert(oloc && oloc->file);
289
0
    assert(name && *name);
290
291
    /* Initialize data to pass through object header iteration */
292
0
    udata.file            = oloc->file;
293
0
    udata.grp_full_path_r = grp_full_path_r;
294
0
    udata.name            = name;
295
296
    /* Iterate over the link messages to delete the right one */
297
0
    if (H5O_msg_remove_op(oloc, H5O_LINK_ID, H5O_FIRST, H5G__compact_remove_common_cb, &udata, true) < 0)
298
0
        HGOTO_ERROR(H5E_SYM, H5E_CANTDELETE, FAIL, "unable to delete link message");
299
300
0
done:
301
0
    FUNC_LEAVE_NOAPI(ret_value)
302
0
} /* end H5G__compact_remove() */
303
304
/*-------------------------------------------------------------------------
305
 * Function:  H5G__compact_remove_by_idx
306
 *
307
 * Purpose: Remove link from group, according to an index order.
308
 *
309
 * Return:  Non-negative on success/Negative on failure
310
 *
311
 *-------------------------------------------------------------------------
312
 */
313
herr_t
314
H5G__compact_remove_by_idx(const H5O_loc_t *oloc, const H5O_linfo_t *linfo, H5RS_str_t *grp_full_path_r,
315
                           H5_index_t idx_type, H5_iter_order_t order, hsize_t n)
316
0
{
317
0
    H5G_link_table_t ltable = {0, NULL};  /* Link table */
318
0
    H5G_iter_rm_t    udata;               /* Data to pass through OH iteration */
319
0
    herr_t           ret_value = SUCCEED; /* Return value */
320
321
0
    FUNC_ENTER_PACKAGE
322
323
0
    assert(oloc && oloc->file);
324
0
    assert(linfo);
325
326
    /* Build table of all link messages, sorted according to desired order */
327
0
    if (H5G__compact_build_table(oloc, linfo, idx_type, order, &ltable) < 0)
328
0
        HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "can't create link message table");
329
330
    /* Check for going out of bounds */
331
0
    if (n >= ltable.nlinks)
332
0
        HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, FAIL, "index out of bound");
333
334
    /* Initialize data to pass through object header iteration */
335
0
    udata.file            = oloc->file;
336
0
    udata.grp_full_path_r = grp_full_path_r;
337
0
    udata.name            = ltable.lnks[n].name;
338
339
    /* Iterate over the link messages to delete the right one */
340
0
    if (H5O_msg_remove_op(oloc, H5O_LINK_ID, H5O_FIRST, H5G__compact_remove_common_cb, &udata, true) < 0)
341
0
        HGOTO_ERROR(H5E_SYM, H5E_CANTDELETE, FAIL, "unable to delete link message");
342
343
0
done:
344
    /* Release link table */
345
0
    if (ltable.lnks && H5G__link_release_table(&ltable) < 0)
346
0
        HDONE_ERROR(H5E_SYM, H5E_CANTFREE, FAIL, "unable to release link table");
347
348
0
    FUNC_LEAVE_NOAPI(ret_value)
349
0
} /* end H5G__compact_remove_by_idx() */
350
351
/*-------------------------------------------------------------------------
352
 * Function:  H5G__compact_iterate
353
 *
354
 * Purpose: Iterate over the links in a group
355
 *
356
 * Return:  Non-negative on success/Negative on failure
357
 *
358
 *-------------------------------------------------------------------------
359
 */
360
herr_t
361
H5G__compact_iterate(const H5O_loc_t *oloc, const H5O_linfo_t *linfo, H5_index_t idx_type,
362
                     H5_iter_order_t order, hsize_t skip, hsize_t *last_lnk, H5G_lib_iterate_t op,
363
                     void *op_data)
364
0
{
365
0
    H5G_link_table_t ltable    = {0, NULL}; /* Link table */
366
0
    herr_t           ret_value = FAIL;      /* Return value */
367
368
0
    FUNC_ENTER_PACKAGE
369
370
    /* Sanity check */
371
0
    assert(oloc);
372
0
    assert(linfo);
373
0
    assert(op);
374
375
    /* Build table of all link messages */
376
0
    if (H5G__compact_build_table(oloc, linfo, idx_type, order, &ltable) < 0)
377
0
        HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "can't create link message table");
378
379
    /* Iterate over links in table */
380
0
    if ((ret_value = H5G__link_iterate_table(&ltable, skip, last_lnk, op, op_data)) < 0)
381
0
        HERROR(H5E_SYM, H5E_CANTNEXT, "iteration operator failed");
382
383
0
done:
384
    /* Release link table */
385
0
    if (ltable.lnks && H5G__link_release_table(&ltable) < 0)
386
0
        HDONE_ERROR(H5E_SYM, H5E_CANTFREE, FAIL, "unable to release link table");
387
388
0
    FUNC_LEAVE_NOAPI(ret_value)
389
0
} /* end H5G__compact_iterate() */
390
391
/*-------------------------------------------------------------------------
392
 * Function:    H5G__compact_lookup_cb
393
 *
394
 * Purpose:     Callback routine for searching 'link' messages for a particular
395
 *              name & getting object location for it
396
 *
397
 * Return:      SUCCEED/FAIL
398
 *
399
 *-------------------------------------------------------------------------
400
 */
401
static herr_t
402
H5G__compact_lookup_cb(const void *_mesg, unsigned H5_ATTR_UNUSED idx, void *_udata)
403
0
{
404
0
    const H5O_link_t *lnk       = (const H5O_link_t *)_mesg; /* Pointer to link */
405
0
    H5G_iter_lkp_t   *udata     = (H5G_iter_lkp_t *)_udata;  /* 'User data' passed in */
406
0
    herr_t            ret_value = H5_ITER_CONT;              /* Return value */
407
408
0
    FUNC_ENTER_PACKAGE
409
410
    /* check arguments */
411
0
    assert(lnk);
412
0
    assert(udata);
413
414
    /* Check for name to get information */
415
0
    if (strcmp(lnk->name, udata->name) == 0) {
416
0
        if (udata->lnk) {
417
            /* Copy link information */
418
0
            if (NULL == H5O_msg_copy(H5O_LINK_ID, lnk, udata->lnk))
419
0
                HGOTO_ERROR(H5E_SYM, H5E_CANTCOPY, H5_ITER_ERROR, "can't copy link message");
420
0
        } /* end if */
421
422
        /* Indicate that the correct link was found */
423
0
        *udata->found = true;
424
425
        /* Stop iteration now */
426
0
        HGOTO_DONE(H5_ITER_STOP);
427
0
    } /* end if */
428
429
0
done:
430
0
    FUNC_LEAVE_NOAPI(ret_value)
431
0
} /* end H5G__compact_lookup_cb() */
432
433
/*-------------------------------------------------------------------------
434
 * Function:  H5G__compact_lookup
435
 *
436
 * Purpose: Look up an object relative to a group, using link messages.
437
 *
438
 * Return:  Non-negative (true/false) on success/Negative on failure
439
 *
440
 *-------------------------------------------------------------------------
441
 */
442
herr_t
443
H5G__compact_lookup(const H5O_loc_t *oloc, const char *name, bool *found, H5O_link_t *lnk)
444
0
{
445
0
    H5G_iter_lkp_t      udata;               /* User data for iteration callback */
446
0
    H5O_mesg_operator_t op;                  /* Message operator */
447
0
    herr_t              ret_value = SUCCEED; /* Return value */
448
449
0
    FUNC_ENTER_PACKAGE
450
451
    /* check arguments */
452
0
    assert(name && *name);
453
0
    assert(found);
454
0
    assert(lnk && oloc->file);
455
456
    /* Set up user data for iteration */
457
0
    udata.name  = name;
458
0
    udata.lnk   = lnk;
459
0
    udata.found = found;
460
461
    /* Iterate through the link messages, adding them to the table */
462
0
    op.op_type  = H5O_MESG_OP_APP;
463
0
    op.u.app_op = H5G__compact_lookup_cb;
464
0
    if (H5O_msg_iterate(oloc, H5O_LINK_ID, &op, &udata) < 0)
465
0
        HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "error iterating over link messages");
466
467
0
done:
468
0
    FUNC_LEAVE_NOAPI(ret_value)
469
0
} /* end H5G__compact_lookup() */
470
471
/*-------------------------------------------------------------------------
472
 * Function:  H5G__compact_lookup_by_idx
473
 *
474
 * Purpose: Look up an object in a group using link messages,
475
 *              according to the order of an index
476
 *
477
 * Return:  Non-negative on success/Negative on failure
478
 *
479
 *-------------------------------------------------------------------------
480
 */
481
herr_t
482
H5G__compact_lookup_by_idx(const H5O_loc_t *oloc, const H5O_linfo_t *linfo, H5_index_t idx_type,
483
                           H5_iter_order_t order, hsize_t n, H5O_link_t *lnk)
484
0
{
485
0
    H5G_link_table_t ltable    = {0, NULL}; /* Link table */
486
0
    herr_t           ret_value = SUCCEED;   /* Return value */
487
488
0
    FUNC_ENTER_PACKAGE
489
490
    /* check arguments */
491
0
    assert(oloc && oloc->file);
492
0
    assert(linfo);
493
0
    assert(lnk);
494
495
    /* Build table of all link messages, sorted according to desired order */
496
0
    if (H5G__compact_build_table(oloc, linfo, idx_type, order, &ltable) < 0)
497
0
        HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "can't create link message table");
498
499
    /* Check for going out of bounds */
500
0
    if (n >= ltable.nlinks)
501
0
        HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, FAIL, "index out of bound");
502
503
    /* Copy link information */
504
0
    if (NULL == H5O_msg_copy(H5O_LINK_ID, &ltable.lnks[n], lnk))
505
0
        HGOTO_ERROR(H5E_SYM, H5E_CANTCOPY, H5_ITER_ERROR, "can't copy link message");
506
507
0
done:
508
    /* Release link table */
509
0
    if (ltable.lnks && H5G__link_release_table(&ltable) < 0)
510
0
        HDONE_ERROR(H5E_SYM, H5E_CANTFREE, FAIL, "unable to release link table");
511
512
0
    FUNC_LEAVE_NOAPI(ret_value)
513
0
} /* end H5G__compact_lookup_by_idx() */