Coverage Report

Created: 2026-03-04 00:50

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/hdf5/src/H5Glink.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:   H5Glink.c
16
 *
17
 * Purpose:   Functions for handling links in groups.
18
 *
19
 *-------------------------------------------------------------------------
20
 */
21
22
/****************/
23
/* Module Setup */
24
/****************/
25
26
#include "H5Gmodule.h" /* This source code file is part of the H5G module */
27
28
/***********/
29
/* Headers */
30
/***********/
31
#include "H5private.h"   /* Generic Functions     */
32
#include "H5Eprivate.h"  /* Error handling        */
33
#include "H5Gpkg.h"      /* Groups          */
34
#include "H5HLprivate.h" /* Local Heaps       */
35
#include "H5Iprivate.h"  /* IDs                                  */
36
#include "H5Lprivate.h"  /* Links                                */
37
#include "H5MMprivate.h" /* Memory management     */
38
39
#include "H5VLnative_private.h" /* Native VOL connector                     */
40
41
/****************/
42
/* Local Macros */
43
/****************/
44
45
/******************/
46
/* Local Typedefs */
47
/******************/
48
49
/********************/
50
/* Package Typedefs */
51
/********************/
52
53
/********************/
54
/* Local Prototypes */
55
/********************/
56
57
static int H5G__link_cmp_name_inc(const void *lnk1, const void *lnk2);
58
static int H5G__link_cmp_name_dec(const void *lnk1, const void *lnk2);
59
static int H5G__link_cmp_corder_inc(const void *lnk1, const void *lnk2);
60
static int H5G__link_cmp_corder_dec(const void *lnk1, const void *lnk2);
61
62
/*********************/
63
/* Package Variables */
64
/*********************/
65
66
/*****************************/
67
/* Library Private Variables */
68
/*****************************/
69
70
/*******************/
71
/* Local Variables */
72
/*******************/
73
74
/*-------------------------------------------------------------------------
75
 * Function:  H5G__link_cmp_name_inc
76
 *
77
 * Purpose: Callback routine for comparing two link names, in
78
 *              increasing alphabetic order
79
 *
80
 * Return:  An integer less than, equal to, or greater than zero if the
81
 *              first argument is considered to be respectively less than,
82
 *              equal to, or greater than the second.  If two members compare
83
 *              as equal, their order in the sorted array is undefined.
84
 *              (i.e. same as strcmp())
85
 *
86
 *-------------------------------------------------------------------------
87
 */
88
static int
89
H5G__link_cmp_name_inc(const void *lnk1, const void *lnk2)
90
0
{
91
0
    FUNC_ENTER_PACKAGE_NOERR
92
93
0
    FUNC_LEAVE_NOAPI(strcmp(((const H5O_link_t *)lnk1)->name, ((const H5O_link_t *)lnk2)->name))
94
0
} /* end H5G__link_cmp_name_inc() */
95
96
/*-------------------------------------------------------------------------
97
 * Function:  H5G__link_cmp_name_dec
98
 *
99
 * Purpose: Callback routine for comparing two link names, in
100
 *              decreasing alphabetic order
101
 *
102
 * Return:  An integer less than, equal to, or greater than zero if the
103
 *              second argument is considered to be respectively less than,
104
 *              equal to, or greater than the first.  If two members compare
105
 *              as equal, their order in the sorted array is undefined.
106
 *              (i.e. opposite strcmp())
107
 *
108
 *-------------------------------------------------------------------------
109
 */
110
static int
111
H5G__link_cmp_name_dec(const void *lnk1, const void *lnk2)
112
0
{
113
0
    FUNC_ENTER_PACKAGE_NOERR
114
115
0
    FUNC_LEAVE_NOAPI(strcmp(((const H5O_link_t *)lnk2)->name, ((const H5O_link_t *)lnk1)->name))
116
0
} /* end H5G__link_cmp_name_dec() */
117
118
/*-------------------------------------------------------------------------
119
 * Function:  H5G__link_cmp_corder_inc
120
 *
121
 * Purpose: Callback routine for comparing two link creation orders, in
122
 *              increasing order
123
 *
124
 * Return:  An integer less than, equal to, or greater than zero if the
125
 *              first argument is considered to be respectively less than,
126
 *              equal to, or greater than the second.  If two members compare
127
 *              as equal, their order in the sorted array is undefined.
128
 *
129
 *-------------------------------------------------------------------------
130
 */
131
static int
132
H5G__link_cmp_corder_inc(const void *lnk1, const void *lnk2)
133
0
{
134
0
    int ret_value = -1; /* Return value */
135
136
0
    FUNC_ENTER_PACKAGE_NOERR
137
138
0
    if (((const H5O_link_t *)lnk1)->corder < ((const H5O_link_t *)lnk2)->corder)
139
0
        ret_value = -1;
140
0
    else if (((const H5O_link_t *)lnk1)->corder > ((const H5O_link_t *)lnk2)->corder)
141
0
        ret_value = 1;
142
0
    else
143
0
        ret_value = 0;
144
145
0
    FUNC_LEAVE_NOAPI(ret_value)
146
0
} /* end H5G__link_cmp_corder_inc() */
147
148
/*-------------------------------------------------------------------------
149
 * Function:  H5G__link_cmp_corder_dec
150
 *
151
 * Purpose: Callback routine for comparing two link creation orders, in
152
 *              decreasing order
153
 *
154
 * Return:  An integer less than, equal to, or greater than zero if the
155
 *              second argument is considered to be respectively less than,
156
 *              equal to, or greater than the first.  If two members compare
157
 *              as equal, their order in the sorted array is undefined.
158
 *
159
 *-------------------------------------------------------------------------
160
 */
161
static int
162
H5G__link_cmp_corder_dec(const void *lnk1, const void *lnk2)
163
0
{
164
0
    int ret_value = -1; /* Return value */
165
166
0
    FUNC_ENTER_PACKAGE_NOERR
167
168
0
    if (((const H5O_link_t *)lnk1)->corder < ((const H5O_link_t *)lnk2)->corder)
169
0
        ret_value = 1;
170
0
    else if (((const H5O_link_t *)lnk1)->corder > ((const H5O_link_t *)lnk2)->corder)
171
0
        ret_value = -1;
172
0
    else
173
0
        ret_value = 0;
174
175
0
    FUNC_LEAVE_NOAPI(ret_value)
176
0
} /* end H5G__link_cmp_corder_dec() */
177
178
/*-------------------------------------------------------------------------
179
 * Function:  H5G_link_to_info
180
 *
181
 * Purpose: Retrieve information from a link object
182
 *
183
 * Return:  Non-negative on success/Negative on failure
184
 *
185
 *-------------------------------------------------------------------------
186
 */
187
herr_t
188
H5G_link_to_info(const H5O_loc_t *link_loc, const H5O_link_t *lnk, H5L_info2_t *info)
189
15.4k
{
190
15.4k
    herr_t ret_value = SUCCEED; /* Return value */
191
192
15.4k
    FUNC_ENTER_NOAPI(FAIL)
193
194
    /* Sanity check */
195
15.4k
    assert(link_loc);
196
15.4k
    assert(lnk);
197
198
    /* Get information from the link */
199
15.4k
    if (info) {
200
15.4k
        info->cset         = lnk->cset;
201
15.4k
        info->corder       = lnk->corder;
202
15.4k
        info->corder_valid = lnk->corder_valid;
203
15.4k
        info->type         = lnk->type;
204
205
15.4k
        switch (lnk->type) {
206
15.4k
            case H5L_TYPE_HARD:
207
                /* Serialize the address into a VOL token */
208
15.4k
                if (H5VL_native_addr_to_token(link_loc->file, H5I_FILE, lnk->u.hard.addr, &info->u.token) < 0)
209
0
                    HGOTO_ERROR(H5E_LINK, H5E_CANTSERIALIZE, FAIL,
210
15.4k
                                "can't serialize address into object token");
211
15.4k
                break;
212
213
15.4k
            case H5L_TYPE_SOFT:
214
0
                info->u.val_size = strlen(lnk->u.soft.name) + 1; /*count the null terminator*/
215
0
                break;
216
217
0
            case H5L_TYPE_ERROR:
218
0
            case H5L_TYPE_EXTERNAL:
219
0
            case H5L_TYPE_MAX:
220
0
            default: {
221
0
                const H5L_class_t *link_class; /* User-defined link class */
222
223
0
                if (lnk->type < H5L_TYPE_UD_MIN || lnk->type > H5L_TYPE_MAX)
224
0
                    HGOTO_ERROR(H5E_LINK, H5E_BADTYPE, FAIL, "unknown link class");
225
226
                /* User-defined link; call its query function to get the link udata size. */
227
                /* Get the link class for this type of link.  It's okay if the class
228
                 * isn't registered, though--we just can't give any more information
229
                 * about it
230
                 */
231
0
                link_class = H5L_find_class(lnk->type);
232
233
0
                if (link_class != NULL && link_class->query_func != NULL) {
234
0
                    ssize_t cb_ret; /* Return value from UD callback */
235
236
                    /* Prepare & restore library for user callback */
237
0
                    H5_BEFORE_USER_CB(FAIL)
238
0
                        {
239
                            /* Call the link's query routine to retrieve the user-defined link's value size */
240
                            /* (in case the query routine packs/unpacks the link value in some way that
241
                             * changes its size) */
242
0
                            cb_ret = (link_class->query_func)(lnk->name, lnk->u.ud.udata, lnk->u.ud.size,
243
0
                                                              NULL, (size_t)0);
244
0
                        }
245
0
                    H5_AFTER_USER_CB(FAIL)
246
0
                    if (cb_ret < 0)
247
0
                        HGOTO_ERROR(H5E_LINK, H5E_CALLBACK, FAIL,
248
0
                                    "query buffer size callback returned failure");
249
250
0
                    info->u.val_size = (size_t)cb_ret;
251
0
                } /* end if */
252
0
                else
253
0
                    info->u.val_size = 0;
254
0
            } /* end case */
255
15.4k
        }     /* end switch */
256
15.4k
    }         /* end if */
257
258
15.4k
done:
259
15.4k
    FUNC_LEAVE_NOAPI(ret_value)
260
15.4k
} /* end H5G_link_to_info() */
261
262
/*-------------------------------------------------------------------------
263
 * Function:    H5G__link_to_ent
264
 *
265
 * Purpose:     Convert a link to a symbol table entry
266
 *
267
 * Return:  Success:  Non-negative
268
 *    Failure:  Negative
269
 *
270
 *-------------------------------------------------------------------------
271
 */
272
herr_t
273
H5G__link_to_ent(H5F_t *f, H5HL_t *heap, const H5O_link_t *lnk, H5O_type_t obj_type, const void *crt_info,
274
                 H5G_entry_t *ent)
275
0
{
276
0
    size_t name_offset;         /* Offset of name in heap */
277
0
    herr_t ret_value = SUCCEED; /* Return value */
278
279
0
    FUNC_ENTER_PACKAGE
280
281
    /* check arguments */
282
0
    assert(f);
283
0
    assert(heap);
284
0
    assert(lnk && lnk->name);
285
286
    /* Reset the new entry */
287
0
    H5G__ent_reset(ent);
288
289
    /* Add the new name to the heap */
290
0
    if (H5HL_insert(f, heap, strlen(lnk->name) + 1, lnk->name, &name_offset) < 0)
291
0
        HGOTO_ERROR(H5E_SYM, H5E_CANTINSERT, FAIL, "unable to insert symbol name into heap");
292
0
    ent->name_off = name_offset;
293
294
    /* Build correct information for symbol table entry based on link type */
295
0
    switch (lnk->type) {
296
0
        case H5L_TYPE_HARD:
297
0
            if (obj_type == H5O_TYPE_GROUP) {
298
0
                const H5G_obj_create_t *gcrt_info = (const H5G_obj_create_t *)crt_info;
299
300
0
                ent->type = gcrt_info->cache_type;
301
0
                if (ent->type != H5G_NOTHING_CACHED)
302
0
                    ent->cache = gcrt_info->cache;
303
#ifndef NDEBUG
304
                else {
305
                    /* Make sure there is no stab message in the target object
306
                     */
307
                    H5O_loc_t targ_oloc;   /* Location of link target */
308
                    htri_t    stab_exists; /* Whether the target symbol table exists */
309
310
                    /* Build target object location */
311
                    if (H5O_loc_reset(&targ_oloc) < 0)
312
                        HGOTO_ERROR(H5E_SYM, H5E_CANTRESET, FAIL, "unable to initialize target location");
313
                    targ_oloc.file = f;
314
                    targ_oloc.addr = lnk->u.hard.addr;
315
316
                    /* Check if a symbol table message exists */
317
                    if ((stab_exists = H5O_msg_exists(&targ_oloc, H5O_STAB_ID)) < 0)
318
                        HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "unable to check for STAB message");
319
320
                    assert(!stab_exists);
321
                } /* end else */
322
#endif            /* NDEBUG */
323
0
            }     /* end if */
324
0
            else if (obj_type == H5O_TYPE_UNKNOWN) {
325
                /* Try to retrieve symbol table information for caching */
326
0
                H5O_loc_t  targ_oloc;   /* Location of link target */
327
0
                H5O_t     *oh;          /* Link target object header */
328
0
                H5O_stab_t stab;        /* Link target symbol table */
329
0
                htri_t     stab_exists; /* Whether the target symbol table exists */
330
331
                /* Build target object location */
332
0
                if (H5O_loc_reset(&targ_oloc) < 0)
333
0
                    HGOTO_ERROR(H5E_SYM, H5E_CANTRESET, FAIL, "unable to initialize target location");
334
0
                targ_oloc.file = f;
335
0
                targ_oloc.addr = lnk->u.hard.addr;
336
337
                /* Get the object header */
338
0
                if (NULL == (oh = H5O_protect(&targ_oloc, H5AC__READ_ONLY_FLAG, false)))
339
0
                    HGOTO_ERROR(H5E_SYM, H5E_CANTPROTECT, FAIL, "unable to protect target object header");
340
341
                /* Check if a symbol table message exists */
342
0
                if ((stab_exists = H5O_msg_exists_oh(oh, H5O_STAB_ID)) < 0) {
343
0
                    if (H5O_unprotect(&targ_oloc, oh, H5AC__NO_FLAGS_SET) < 0)
344
0
                        HERROR(H5E_SYM, H5E_CANTUNPROTECT, "unable to release object header");
345
0
                    HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "unable to check for STAB message");
346
0
                } /* end if */
347
348
0
                if (stab_exists) {
349
                    /* Read symbol table message */
350
0
                    if (NULL == H5O_msg_read_oh(f, oh, H5O_STAB_ID, &stab)) {
351
0
                        if (H5O_unprotect(&targ_oloc, oh, H5AC__NO_FLAGS_SET) < 0)
352
0
                            HERROR(H5E_SYM, H5E_CANTUNPROTECT, "unable to release object header");
353
0
                        HGOTO_ERROR(H5E_SYM, H5E_CANTGET, FAIL, "unable to read STAB message");
354
0
                    } /* end if */
355
356
                    /* Cache symbol table message */
357
0
                    ent->type                  = H5G_CACHED_STAB;
358
0
                    ent->cache.stab.btree_addr = stab.btree_addr;
359
0
                    ent->cache.stab.heap_addr  = stab.heap_addr;
360
0
                } /* end if */
361
0
                else
362
                    /* No symbol table message, don't cache anything */
363
0
                    ent->type = H5G_NOTHING_CACHED;
364
365
0
                if (H5O_unprotect(&targ_oloc, oh, H5AC__NO_FLAGS_SET) < 0)
366
0
                    HGOTO_ERROR(H5E_SYM, H5E_CANTUNPROTECT, FAIL, "unable to release object header");
367
0
            } /* end else */
368
0
            else
369
0
                ent->type = H5G_NOTHING_CACHED;
370
371
0
            ent->header = lnk->u.hard.addr;
372
0
            break;
373
374
0
        case H5L_TYPE_SOFT: {
375
0
            size_t lnk_offset; /* Offset to sym-link value  */
376
377
            /* Insert link value into local heap */
378
0
            if (H5HL_insert(f, heap, strlen(lnk->u.soft.name) + 1, lnk->u.soft.name, &lnk_offset) < 0)
379
0
                HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "unable to write link value to local heap");
380
381
0
            ent->type                    = H5G_CACHED_SLINK;
382
0
            ent->cache.slink.lval_offset = lnk_offset;
383
0
        } break;
384
385
0
        case H5L_TYPE_ERROR:
386
0
        case H5L_TYPE_EXTERNAL:
387
0
        case H5L_TYPE_MAX:
388
0
        default:
389
0
            HGOTO_ERROR(H5E_SYM, H5E_BADVALUE, FAIL, "unrecognized link type");
390
0
    } /* end switch */
391
392
0
done:
393
0
    FUNC_LEAVE_NOAPI(ret_value)
394
0
} /* end H5G__link_to_ent() */
395
396
/*-------------------------------------------------------------------------
397
 * Function:  H5G__link_to_loc
398
 *
399
 * Purpose: Build group location from group and link object
400
 *
401
 * Return:  Non-negative on success/Negative on failure
402
 *
403
 *-------------------------------------------------------------------------
404
 */
405
herr_t
406
H5G__link_to_loc(const H5G_loc_t *grp_loc, const H5O_link_t *lnk, H5G_loc_t *obj_loc)
407
11.3k
{
408
11.3k
    herr_t ret_value = SUCCEED; /* Return value */
409
410
11.3k
    FUNC_ENTER_PACKAGE
411
412
    /* Sanity check */
413
11.3k
    assert(grp_loc);
414
11.3k
    assert(lnk);
415
11.3k
    assert(obj_loc);
416
417
    /*
418
     * Build location from the link
419
     */
420
421
    /* Check for unknown library-internal link */
422
11.3k
    if (lnk->type > H5L_TYPE_BUILTIN_MAX && lnk->type < H5L_TYPE_UD_MIN)
423
0
        HGOTO_ERROR(H5E_SYM, H5E_UNSUPPORTED, FAIL, "unknown link type");
424
425
    /* Build object's group hier. location */
426
11.3k
    if (H5G_name_set(grp_loc->path, obj_loc->path, lnk->name) < 0)
427
0
        HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "cannot set name");
428
429
    /* Set the object location, if it's a hard link set the address also */
430
11.3k
    obj_loc->oloc->file         = grp_loc->oloc->file;
431
11.3k
    obj_loc->oloc->holding_file = false;
432
11.3k
    if (lnk->type == H5L_TYPE_HARD)
433
11.3k
        obj_loc->oloc->addr = lnk->u.hard.addr;
434
435
11.3k
done:
436
11.3k
    FUNC_LEAVE_NOAPI(ret_value)
437
11.3k
} /* end H5G__link_to_loc() */
438
439
/*-------------------------------------------------------------------------
440
 * Function:    H5G__link_sort_table
441
 *
442
 * Purpose:     Sort table containing a list of links for a group
443
 *
444
 * Return:      SUCCEED/FAIL
445
 *
446
 *-------------------------------------------------------------------------
447
 */
448
herr_t
449
H5G__link_sort_table(H5G_link_table_t *ltable, H5_index_t idx_type, H5_iter_order_t order)
450
0
{
451
0
    herr_t ret_value = SUCCEED;
452
453
0
    FUNC_ENTER_PACKAGE_NOERR
454
455
    /* Sanity check */
456
0
    assert(ltable);
457
458
    /* Can't sort when empty since the links table will be NULL */
459
0
    if (0 == ltable->nlinks)
460
0
        HGOTO_DONE(ret_value);
461
462
    /* This should never be NULL if the number of links is non-zero */
463
0
    assert(ltable->lnks);
464
465
    /* Pick appropriate sorting routine */
466
0
    if (idx_type == H5_INDEX_NAME) {
467
0
        if (order == H5_ITER_INC)
468
0
            qsort(ltable->lnks, ltable->nlinks, sizeof(H5O_link_t), H5G__link_cmp_name_inc);
469
0
        else if (order == H5_ITER_DEC)
470
0
            qsort(ltable->lnks, ltable->nlinks, sizeof(H5O_link_t), H5G__link_cmp_name_dec);
471
0
        else
472
0
            assert(order == H5_ITER_NATIVE);
473
0
    } /* end if */
474
0
    else {
475
0
        assert(idx_type == H5_INDEX_CRT_ORDER);
476
0
        if (order == H5_ITER_INC)
477
0
            qsort(ltable->lnks, ltable->nlinks, sizeof(H5O_link_t), H5G__link_cmp_corder_inc);
478
0
        else if (order == H5_ITER_DEC)
479
0
            qsort(ltable->lnks, ltable->nlinks, sizeof(H5O_link_t), H5G__link_cmp_corder_dec);
480
0
        else
481
0
            assert(order == H5_ITER_NATIVE);
482
0
    } /* end else */
483
484
0
done:
485
0
    FUNC_LEAVE_NOAPI(SUCCEED)
486
0
} /* end H5G__link_sort_table() */
487
488
/*-------------------------------------------------------------------------
489
 * Function:  H5G__link_iterate_table
490
 *
491
 * Purpose:     Iterate over table containing a list of links for a group,
492
 *              making appropriate callbacks
493
 *
494
 * Return:  Success:        Non-negative
495
 *    Failure:  Negative
496
 *
497
 *-------------------------------------------------------------------------
498
 */
499
herr_t
500
H5G__link_iterate_table(const H5G_link_table_t *ltable, hsize_t skip, hsize_t *last_lnk,
501
                        const H5G_lib_iterate_t op, void *op_data)
502
0
{
503
0
    size_t u;                        /* Local index variable */
504
0
    herr_t ret_value = H5_ITER_CONT; /* Return value */
505
506
0
    FUNC_ENTER_PACKAGE_NOERR
507
508
    /* Sanity check */
509
0
    assert(ltable);
510
0
    assert(op);
511
512
    /* Skip over links, if requested */
513
0
    if (last_lnk)
514
0
        *last_lnk += skip;
515
516
    /* Iterate over link messages */
517
0
    H5_CHECKED_ASSIGN(u, size_t, skip, hsize_t);
518
0
    for (; u < ltable->nlinks && !ret_value; u++) {
519
        /* Make the callback */
520
0
        ret_value = (op)(&(ltable->lnks[u]), op_data);
521
522
        /* Increment the number of entries passed through */
523
0
        if (last_lnk)
524
0
            (*last_lnk)++;
525
0
    } /* end for */
526
527
    /* Check for callback failure and pass along return value */
528
0
    if (ret_value < 0)
529
0
        HERROR(H5E_SYM, H5E_CANTNEXT, "iteration operator failed");
530
531
0
    FUNC_LEAVE_NOAPI(ret_value)
532
0
} /* end H5G__link_iterate_table() */
533
534
/*-------------------------------------------------------------------------
535
 * Function:  H5G__link_release_table
536
 *
537
 * Purpose:     Release table containing a list of links for a group
538
 *
539
 * Return:  Success:        Non-negative
540
 *    Failure:  Negative
541
 *
542
 *-------------------------------------------------------------------------
543
 */
544
herr_t
545
H5G__link_release_table(H5G_link_table_t *ltable)
546
0
{
547
0
    size_t u;                   /* Local index variable */
548
0
    herr_t ret_value = SUCCEED; /* Return value */
549
550
0
    FUNC_ENTER_PACKAGE
551
552
    /* Sanity check */
553
0
    assert(ltable);
554
555
    /* Release link info, if any */
556
0
    if (ltable->nlinks > 0) {
557
        /* Free link message information */
558
0
        for (u = 0; u < ltable->nlinks; u++)
559
0
            if (H5O_msg_reset(H5O_LINK_ID, &(ltable->lnks[u])) < 0)
560
0
                HGOTO_ERROR(H5E_SYM, H5E_CANTFREE, FAIL, "unable to release link message");
561
562
        /* Free table of links */
563
0
        H5MM_xfree(ltable->lnks);
564
0
    } /* end if */
565
0
    else
566
0
        assert(ltable->lnks == NULL);
567
568
0
done:
569
0
    FUNC_LEAVE_NOAPI(ret_value)
570
0
} /* end H5G__link_release_table() */
571
572
/*-------------------------------------------------------------------------
573
 * Function:  H5G__link_name_replace
574
 *
575
 * Purpose: Determine the type of object referred to (for hard links) or
576
 *              the link type (for soft links and user-defined links).
577
 *
578
 * Return:  Non-negative on success/Negative on failure
579
 *
580
 *-------------------------------------------------------------------------
581
 */
582
herr_t
583
H5G__link_name_replace(H5F_t *file, H5RS_str_t *grp_full_path_r, const H5O_link_t *lnk)
584
0
{
585
0
    H5RS_str_t *obj_path_r = NULL;    /* Full path for link being removed */
586
0
    herr_t      ret_value  = SUCCEED; /* Return value */
587
588
0
    FUNC_ENTER_PACKAGE
589
590
    /* check arguments */
591
0
    assert(file);
592
593
    /* Search the open IDs and replace names for unlinked object */
594
0
    if (grp_full_path_r) {
595
0
        obj_path_r = H5G_build_fullpath_refstr_str(grp_full_path_r, lnk->name);
596
0
        if (H5G_name_replace(lnk, H5G_NAME_DELETE, file, obj_path_r, NULL, NULL) < 0)
597
0
            HGOTO_ERROR(H5E_SYM, H5E_CANTDELETE, FAIL, "unable to replace name");
598
0
    }
599
600
0
done:
601
0
    if (obj_path_r)
602
0
        H5RS_decr(obj_path_r);
603
604
0
    FUNC_LEAVE_NOAPI(ret_value)
605
0
} /* end H5G__link_name_replace() */