Coverage Report

Created: 2025-11-24 06:13

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/hdf5/src/H5Gnode.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:     H5Gnode.c
16
 *
17
 * Purpose:     Functions for handling symbol table nodes.  A
18
 *              symbol table node is a small collection of symbol
19
 *              table entries.  A B-tree usually points to the
20
 *              symbol table nodes for any given symbol table.
21
 *
22
 *-------------------------------------------------------------------------
23
 */
24
25
/****************/
26
/* Module Setup */
27
/****************/
28
29
#include "H5Gmodule.h" /* This source code file is part of the H5G module */
30
31
/***********/
32
/* Headers */
33
/***********/
34
#include "H5private.h"   /* Generic Functions        */
35
#include "H5ACprivate.h" /* Metadata cache           */
36
#include "H5Eprivate.h"  /* Error handling           */
37
#include "H5Fprivate.h"  /* File access              */
38
#include "H5FLprivate.h" /* Free Lists               */
39
#include "H5Gpkg.h"      /* Groups                   */
40
#include "H5HLprivate.h" /* Local Heaps              */
41
#include "H5MFprivate.h" /* File memory management   */
42
#include "H5MMprivate.h" /* Memory management        */
43
#include "H5Ppublic.h"   /* Property Lists           */
44
45
/****************/
46
/* Local Macros */
47
/****************/
48
49
/******************/
50
/* Local Typedefs */
51
/******************/
52
53
/*
54
 * Each key field of the B-link tree that points to symbol table
55
 * nodes consists of this structure...
56
 */
57
typedef struct H5G_node_key_t {
58
    size_t offset; /*offset into heap for name          */
59
} H5G_node_key_t;
60
61
/********************/
62
/* Package Typedefs */
63
/********************/
64
65
/********************/
66
/* Local Prototypes */
67
/********************/
68
69
/* B-tree callbacks */
70
static H5UC_t   *H5G__node_get_shared(const H5F_t *f, const void *_udata);
71
static herr_t    H5G__node_create(H5F_t *f, H5B_ins_t op, void *_lt_key, void *_udata, void *_rt_key,
72
                                  haddr_t *addr_p /*out*/);
73
static int       H5G__node_cmp2(void *_lt_key, void *_udata, void *_rt_key);
74
static int       H5G__node_cmp3(void *_lt_key, void *_udata, void *_rt_key);
75
static herr_t    H5G__node_found(H5F_t *f, haddr_t addr, const void *_lt_key, bool *found, void *_udata);
76
static H5B_ins_t H5G__node_insert(H5F_t *f, haddr_t addr, void *_lt_key, bool *lt_key_changed, void *_md_key,
77
                                  void *_udata, void *_rt_key, bool *rt_key_changed,
78
                                  haddr_t *new_node_p /*out*/);
79
static H5B_ins_t H5G__node_remove(H5F_t *f, haddr_t addr, void *lt_key, bool *lt_key_changed, void *udata,
80
                                  void *rt_key, bool *rt_key_changed);
81
static herr_t    H5G__node_decode_key(const H5B_shared_t *shared, const uint8_t *raw, void *_key);
82
static herr_t    H5G__node_encode_key(const H5B_shared_t *shared, uint8_t *raw, const void *_key);
83
static herr_t H5G__node_debug_key(FILE *stream, int indent, int fwidth, const void *key, const void *udata);
84
85
/*********************/
86
/* Package Variables */
87
/*********************/
88
89
/* H5G inherits B-tree like properties from H5B */
90
H5B_class_t H5B_SNODE[1] = {{
91
    H5B_SNODE_ID,           /*id            */
92
    sizeof(H5G_node_key_t), /*sizeof_nkey   */
93
    H5G__node_get_shared,   /*get_shared    */
94
    H5G__node_create,       /*new           */
95
    H5G__node_cmp2,         /*cmp2          */
96
    H5G__node_cmp3,         /*cmp3          */
97
    H5G__node_found,        /*found         */
98
    H5G__node_insert,       /*insert        */
99
    true,                   /*follow min branch?    */
100
    true,                   /*follow max branch?    */
101
    H5B_RIGHT,              /*critical key  */
102
    H5G__node_remove,       /*remove        */
103
    H5G__node_decode_key,   /*decode        */
104
    H5G__node_encode_key,   /*encode        */
105
    H5G__node_debug_key     /*debug         */
106
}};
107
108
/* Declare a free list to manage the H5G_node_t struct */
109
H5FL_DEFINE(H5G_node_t);
110
111
/* Declare a free list to manage sequences of H5G_entry_t's */
112
H5FL_SEQ_DEFINE(H5G_entry_t);
113
114
/*****************************/
115
/* Library Private Variables */
116
/*****************************/
117
118
/*******************/
119
/* Local Variables */
120
/*******************/
121
122
/*-------------------------------------------------------------------------
123
 * Function:    H5G__node_get_shared
124
 *
125
 * Purpose:     Returns the shared B-tree info for the specified UDATA.
126
 *
127
 * Return:      Success:    Pointer to the raw B-tree page for this file's groups
128
 *
129
 *              Failure:  Can't fail
130
 *
131
 *-------------------------------------------------------------------------
132
 */
133
static H5UC_t *
134
H5G__node_get_shared(const H5F_t *f, const void H5_ATTR_UNUSED *_udata)
135
1.03k
{
136
1.03k
    FUNC_ENTER_PACKAGE_NOERR
137
138
1.03k
    assert(f);
139
140
    /* Return the pointer to the ref-count object */
141
1.03k
    FUNC_LEAVE_NOAPI(H5F_GRP_BTREE_SHARED(f))
142
1.03k
} /* end H5G__node_get_shared() */
143
144
/*-------------------------------------------------------------------------
145
 * Function:    H5G__node_decode_key
146
 *
147
 * Purpose:     Decodes a raw key into a native key.
148
 *
149
 * Return:      Non-negative on success/Negative on failure
150
 *
151
 *-------------------------------------------------------------------------
152
 */
153
static herr_t
154
H5G__node_decode_key(const H5B_shared_t *shared, const uint8_t *raw, void *_key)
155
1.91k
{
156
1.91k
    H5G_node_key_t *key = (H5G_node_key_t *)_key;
157
158
1.91k
    FUNC_ENTER_PACKAGE_NOERR
159
160
1.91k
    assert(shared);
161
1.91k
    assert(raw);
162
1.91k
    assert(key);
163
164
1.91k
    H5_DECODE_LENGTH_LEN(raw, key->offset, shared->sizeof_len);
165
166
1.91k
    FUNC_LEAVE_NOAPI(SUCCEED)
167
1.91k
} /* end H5G__node_decode_key() */
168
169
/*-------------------------------------------------------------------------
170
 * Function:  H5G__node_encode_key
171
 *
172
 * Purpose:     Encodes a native key into a raw key.
173
 *
174
 * Return:      Non-negative on success/Negative on failure
175
 *
176
 *-------------------------------------------------------------------------
177
 */
178
static herr_t
179
H5G__node_encode_key(const H5B_shared_t *shared, uint8_t *raw, const void *_key)
180
0
{
181
0
    const H5G_node_key_t *key = (const H5G_node_key_t *)_key;
182
183
0
    FUNC_ENTER_PACKAGE_NOERR
184
185
0
    assert(shared);
186
0
    assert(raw);
187
0
    assert(key);
188
189
0
    H5_ENCODE_LENGTH_LEN(raw, key->offset, shared->sizeof_len);
190
191
0
    FUNC_LEAVE_NOAPI(SUCCEED)
192
0
} /* end H5G__node_encode_key() */
193
194
/*-------------------------------------------------------------------------
195
 * Function:    H5G__node_debug_key
196
 *
197
 * Purpose:     Prints a key.
198
 *
199
 * Return:      Non-negative on success/Negative on failure
200
 *
201
 *-------------------------------------------------------------------------
202
 */
203
static herr_t
204
H5G__node_debug_key(FILE *stream, int indent, int fwidth, const void *_key, const void *_udata)
205
0
{
206
0
    const H5G_node_key_t  *key   = (const H5G_node_key_t *)_key;
207
0
    const H5G_bt_common_t *udata = (const H5G_bt_common_t *)_udata;
208
209
0
    FUNC_ENTER_PACKAGE_NOERR
210
211
0
    assert(key);
212
213
0
    fprintf(stream, "%*s%-*s %u\n", indent, "", fwidth, "Heap offset:", (unsigned)key->offset);
214
215
0
    if (udata->heap) {
216
0
        const char *s;
217
218
0
        fprintf(stream, "%*s%-*s ", indent, "", fwidth, "Name:");
219
220
0
        if ((s = (const char *)H5HL_offset_into(udata->heap, key->offset)) != NULL)
221
0
            fprintf(stream, "%s\n", s);
222
0
    } /* end if */
223
0
    else
224
0
        fprintf(stream, "%*s%-*s ", indent, "", fwidth, "Cannot get name; heap address not specified\n");
225
226
0
    FUNC_LEAVE_NOAPI(SUCCEED)
227
0
} /* end H5G__node_debug_key() */
228
229
/*-------------------------------------------------------------------------
230
 * Function:  H5G__node_free
231
 *
232
 * Purpose:     Destroy a symbol table node in memory.
233
 *
234
 * Return:      Non-negative on success/Negative on failure
235
 *
236
 *-------------------------------------------------------------------------
237
 */
238
herr_t
239
H5G__node_free(H5G_node_t *sym)
240
398
{
241
398
    FUNC_ENTER_PACKAGE_NOERR
242
243
    /*
244
     * Check arguments.
245
     */
246
398
    assert(sym);
247
248
    /* Verify that node is clean */
249
398
    assert(sym->cache_info.is_dirty == false);
250
251
398
    if (sym->entry)
252
398
        sym->entry = H5FL_SEQ_FREE(H5G_entry_t, sym->entry);
253
398
    sym = H5FL_FREE(H5G_node_t, sym);
254
255
398
    FUNC_LEAVE_NOAPI(SUCCEED)
256
398
} /* end H5G__node_free() */
257
258
/*-------------------------------------------------------------------------
259
 * Function:  H5G__node_create
260
 *
261
 * Purpose: Creates a new empty symbol table node.  This function is
262
 *          called by the B-tree insert function for an empty tree.  It
263
 *          is also called internally to split a symbol node with LT_KEY
264
 *          and RT_KEY null pointers.
265
 *
266
 * Return:  Success:    Non-negative.   The address of symbol table
267
 *                      node is returned through the ADDR_P argument.
268
 *
269
 *          Failure:    Negative
270
 *
271
 *-------------------------------------------------------------------------
272
 */
273
static herr_t
274
H5G__node_create(H5F_t *f, H5B_ins_t H5_ATTR_UNUSED op, void *_lt_key, void H5_ATTR_UNUSED *_udata,
275
                 void *_rt_key, haddr_t *addr_p /*out*/)
276
0
{
277
0
    H5G_node_key_t *lt_key    = (H5G_node_key_t *)_lt_key;
278
0
    H5G_node_key_t *rt_key    = (H5G_node_key_t *)_rt_key;
279
0
    H5G_node_t     *sym       = NULL;
280
0
    herr_t          ret_value = SUCCEED; /* Return value */
281
282
0
    FUNC_ENTER_PACKAGE
283
284
    /*
285
     * Check arguments.
286
     */
287
0
    assert(f);
288
0
    assert(H5B_INS_FIRST == op);
289
290
0
    if (NULL == (sym = H5FL_CALLOC(H5G_node_t)))
291
0
        HGOTO_ERROR(H5E_SYM, H5E_CANTALLOC, FAIL, "memory allocation failed");
292
0
    sym->node_size = H5G_NODE_SIZE(f);
293
0
    if (HADDR_UNDEF == (*addr_p = H5MF_alloc(f, H5FD_MEM_BTREE, (hsize_t)sym->node_size)))
294
0
        HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "unable to allocate file space");
295
0
    if (NULL == (sym->entry = H5FL_SEQ_CALLOC(H5G_entry_t, (size_t)(2 * H5F_SYM_LEAF_K(f)))))
296
0
        HGOTO_ERROR(H5E_SYM, H5E_CANTALLOC, FAIL, "memory allocation failed");
297
298
0
    if (H5AC_insert_entry(f, H5AC_SNODE, *addr_p, sym, H5AC__NO_FLAGS_SET) < 0)
299
0
        HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "unable to cache symbol table leaf node");
300
    /*
301
     * The left and right symbols in an empty tree are both the
302
     * empty string stored at offset zero by the H5G functions. This
303
     * allows the comparison functions to work correctly without knowing
304
     * that there are no symbols.
305
     */
306
0
    if (lt_key)
307
0
        lt_key->offset = 0;
308
0
    if (rt_key)
309
0
        rt_key->offset = 0;
310
311
0
done:
312
0
    if (ret_value < 0)
313
0
        if (sym != NULL) {
314
0
            if (sym->entry != NULL)
315
0
                sym->entry = H5FL_SEQ_FREE(H5G_entry_t, sym->entry);
316
0
            sym = H5FL_FREE(H5G_node_t, sym);
317
0
        } /* end if */
318
319
0
    FUNC_LEAVE_NOAPI(ret_value)
320
0
} /* end H5G__node_create() */
321
322
/*-------------------------------------------------------------------------
323
 * Function:  H5G__node_cmp2
324
 *
325
 * Purpose: Compares two keys from a B-tree node (LT_KEY and RT_KEY).
326
 *          The UDATA pointer supplies extra data not contained in the
327
 *          keys (in this case, the heap address).
328
 *
329
 * Return:  Success:    negative if LT_KEY is less than RT_KEY.
330
 *
331
 *                      positive if LT_KEY is greater than RT_KEY.
332
 *
333
 *                      zero if LT_KEY and RT_KEY are equal.
334
 *
335
 *          Failure:    FAIL (same as LT_KEY<RT_KEY)
336
 *
337
 *-------------------------------------------------------------------------
338
 */
339
static herr_t
340
H5G__node_cmp2(void *_lt_key, void *_udata, void *_rt_key)
341
0
{
342
0
    H5G_bt_common_t *udata  = (H5G_bt_common_t *)_udata;
343
0
    H5G_node_key_t  *lt_key = (H5G_node_key_t *)_lt_key;
344
0
    H5G_node_key_t  *rt_key = (H5G_node_key_t *)_rt_key;
345
0
    const char      *s1, *s2;
346
0
    size_t           max_len;
347
0
    int              ret_value = SUCCEED; /* Return value */
348
349
0
    FUNC_ENTER_PACKAGE
350
351
    /* Sanity checks */
352
0
    assert(udata && udata->heap);
353
0
    assert(lt_key);
354
0
    assert(rt_key);
355
356
    /* Get pointers to string names */
357
0
    if ((s1 = (const char *)H5HL_offset_into(udata->heap, lt_key->offset)) == NULL)
358
0
        HGOTO_ERROR(H5E_SYM, H5E_CANTGET, FAIL, "unable to get key name");
359
0
    if ((s2 = (const char *)H5HL_offset_into(udata->heap, rt_key->offset)) == NULL)
360
0
        HGOTO_ERROR(H5E_SYM, H5E_CANTGET, FAIL, "unable to get key name");
361
362
    /* Compute maximum length of string to compare */
363
0
    if (rt_key->offset > lt_key->offset)
364
0
        max_len = udata->block_size - rt_key->offset;
365
0
    else
366
0
        max_len = udata->block_size - lt_key->offset;
367
368
    /* Set return value */
369
0
    ret_value = strncmp(s1, s2, max_len);
370
371
0
done:
372
0
    FUNC_LEAVE_NOAPI(ret_value)
373
0
} /* H5G__node_cmp2() */
374
375
/*-------------------------------------------------------------------------
376
 * Function:  H5G__node_cmp3
377
 *
378
 * Purpose: Compares two keys from a B-tree node (LT_KEY and RT_KEY)
379
 *          against another key (not necessarily the same type)
380
 *          pointed to by UDATA.
381
 *
382
 * Return:  Success:    negative if the UDATA key is less than
383
 *                      or equal to the LT_KEY
384
 *
385
 *                      positive if the UDATA key is greater
386
 *                      than the RT_KEY.
387
 *
388
 *                      zero if the UDATA key falls between
389
 *                      the LT_KEY (exclusive) and the
390
 *                      RT_KEY (inclusive).
391
 *
392
 *          Failure:    FAIL (same as UDATA < LT_KEY)
393
 *
394
 *-------------------------------------------------------------------------
395
 */
396
static herr_t
397
H5G__node_cmp3(void *_lt_key, void *_udata, void *_rt_key)
398
535
{
399
535
    H5G_bt_common_t *udata  = (H5G_bt_common_t *)_udata;
400
535
    H5G_node_key_t  *lt_key = (H5G_node_key_t *)_lt_key;
401
535
    H5G_node_key_t  *rt_key = (H5G_node_key_t *)_rt_key;
402
535
    const char      *s;
403
535
    herr_t           ret_value = SUCCEED; /* Return value */
404
405
535
    FUNC_ENTER_PACKAGE
406
407
    /* Sanity checks */
408
535
    assert(udata && udata->heap);
409
535
    assert(lt_key);
410
535
    assert(rt_key);
411
412
    /* left side */
413
535
    if ((s = (const char *)H5HL_offset_into(udata->heap, lt_key->offset)) == NULL)
414
24
        HGOTO_ERROR(H5E_SYM, H5E_CANTGET, FAIL, "unable to get key name");
415
511
    if (strncmp(udata->name, s, (udata->block_size - lt_key->offset)) <= 0)
416
51
        ret_value = (-1);
417
460
    else {
418
        /* right side */
419
460
        if ((s = (const char *)H5HL_offset_into(udata->heap, rt_key->offset)) == NULL)
420
45
            HGOTO_ERROR(H5E_SYM, H5E_CANTGET, FAIL, "unable to get key name");
421
415
        if (strncmp(udata->name, s, (udata->block_size - rt_key->offset)) > 0)
422
16
            ret_value = 1;
423
415
    } /* end else */
424
425
535
done:
426
535
    FUNC_LEAVE_NOAPI(ret_value)
427
535
} /* end H5G__node_cmp3() */
428
429
/*-------------------------------------------------------------------------
430
 * Function:    H5G__node_found
431
 *
432
 * Purpose:     The B-tree search engine has found the symbol table node
433
 *              which contains the requested symbol if the symbol exists.
434
 *              This function should examine that node for the symbol and
435
 *              return information about the symbol through the UDATA
436
 *              structure which contains the symbol name on function
437
 *              entry.
438
 *
439
 *              If the operation flag in UDATA is H5G_OPER_FIND, then
440
 *              the entry is copied from the symbol table to the UDATA
441
 *              entry field.  Otherwise the entry is copied from the
442
 *              UDATA entry field to the symbol table.
443
 *
444
 * Return:      Success:    Non-negative (true/false) if found and data
445
 *                          returned through the UDATA pointer, if *FOUND is true.
446
 *              Failure:    Negative if not found.
447
 *
448
 *-------------------------------------------------------------------------
449
 */
450
static herr_t
451
H5G__node_found(H5F_t *f, haddr_t addr, const void H5_ATTR_UNUSED *_lt_key, bool *found, void *_udata)
452
399
{
453
399
    H5G_bt_lkp_t *udata = (H5G_bt_lkp_t *)_udata;
454
399
    H5G_node_t   *sn    = NULL;
455
399
    unsigned      lt = 0, idx = 0, rt;
456
399
    int           cmp = 1;
457
399
    const char   *s;
458
399
    herr_t        ret_value = SUCCEED; /* Return value */
459
460
399
    FUNC_ENTER_PACKAGE
461
462
    /*
463
     * Check arguments.
464
     */
465
399
    assert(f);
466
399
    assert(H5_addr_defined(addr));
467
399
    assert(found);
468
399
    assert(udata && udata->common.heap);
469
470
    /*
471
     * Load the symbol table node for exclusive access.
472
     */
473
399
    if (NULL == (sn = (H5G_node_t *)H5AC_protect(f, H5AC_SNODE, addr, f, H5AC__READ_ONLY_FLAG)))
474
1
        HGOTO_ERROR(H5E_SYM, H5E_CANTPROTECT, FAIL, "unable to protect symbol table node");
475
476
    /*
477
     * Binary search.
478
     */
479
398
    rt = sn->nsyms;
480
803
    while (lt < rt && cmp) {
481
405
        idx = (lt + rt) / 2;
482
483
405
        if ((s = (const char *)H5HL_offset_into(udata->common.heap, sn->entry[idx].name_off)) == NULL)
484
0
            HGOTO_ERROR(H5E_SYM, H5E_CANTGET, FAIL, "unable to get symbol table name");
485
405
        cmp = strncmp(udata->common.name, s, (udata->common.block_size - sn->entry[idx].name_off));
486
487
405
        if (cmp < 0)
488
13
            rt = idx;
489
392
        else
490
392
            lt = idx + 1;
491
405
    } /* end while */
492
493
398
    if (cmp)
494
7
        *found = false;
495
391
    else {
496
        /* Set the 'found it' flag */
497
391
        *found = true;
498
499
        /* Call user's callback operator */
500
391
        if ((udata->op)(&sn->entry[idx], udata->op_data) < 0)
501
0
            HGOTO_ERROR(H5E_SYM, H5E_BADITER, FAIL, "iterator callback failed");
502
391
    } /* end else */
503
504
399
done:
505
399
    if (sn && H5AC_unprotect(f, H5AC_SNODE, addr, sn, H5AC__NO_FLAGS_SET) < 0)
506
0
        HDONE_ERROR(H5E_SYM, H5E_CANTUNPROTECT, FAIL, "unable to release symbol table node");
507
508
399
    FUNC_LEAVE_NOAPI(ret_value)
509
399
} /* end H5G__node_found() */
510
511
/*-------------------------------------------------------------------------
512
 * Function:    H5G__node_insert
513
 *
514
 * Purpose:     The B-tree insertion engine has found the symbol table node
515
 *              which should receive the new symbol/address pair.  This
516
 *              function adds it to that node unless it already existed.
517
 *
518
 *              If the node has no room for the symbol then the node is
519
 *              split into two nodes.  The original node contains the
520
 *              low values and the new node contains the high values.
521
 *              The new symbol table entry is added to either node as
522
 *              appropriate.  When a split occurs, this function will
523
 *              write the maximum key of the low node to the MID buffer
524
 *              and return the address of the new node.
525
 *
526
 *              If the new key is larger than RIGHT then update RIGHT
527
 *              with the new key.
528
 *
529
 * Return:      Success:    An insertion command for the caller, one of
530
 *                          the H5B_INS_* constants.  The address of the
531
 *                          new node, if any, is returned through the
532
 *                          NEW_NODE_P argument.  NEW_NODE_P might not be
533
 *                          initialized if the return value is H5B_INS_NOOP.
534
 *
535
 *              Failure:    H5B_INS_ERROR, NEW_NODE_P might not be initialized.
536
 *
537
 *-------------------------------------------------------------------------
538
 */
539
static H5B_ins_t
540
H5G__node_insert(H5F_t *f, haddr_t addr, void H5_ATTR_UNUSED *_lt_key, bool H5_ATTR_UNUSED *lt_key_changed,
541
                 void *_md_key, void *_udata, void *_rt_key, bool *rt_key_changed, haddr_t *new_node_p)
542
0
{
543
0
    H5G_node_key_t *md_key = (H5G_node_key_t *)_md_key;
544
0
    H5G_node_key_t *rt_key = (H5G_node_key_t *)_rt_key;
545
0
    H5G_bt_ins_t   *udata  = (H5G_bt_ins_t *)_udata;
546
0
    H5G_node_t     *sn = NULL, *snrt = NULL;
547
0
    unsigned        sn_flags = H5AC__NO_FLAGS_SET, snrt_flags = H5AC__NO_FLAGS_SET;
548
0
    const char     *s;
549
0
    unsigned        lt  = 0, rt; /* Binary search cntrs */
550
0
    int             cmp = 1, idx = -1;
551
0
    H5G_node_t     *insert_into = NULL; /*node that gets new entry*/
552
0
    H5G_entry_t     ent;                /* Entry to insert in node */
553
0
    H5B_ins_t       ret_value = H5B_INS_ERROR;
554
555
0
    FUNC_ENTER_PACKAGE
556
557
    /*
558
     * Check arguments.
559
     */
560
0
    assert(f);
561
0
    assert(H5_addr_defined(addr));
562
0
    assert(md_key);
563
0
    assert(rt_key);
564
0
    assert(udata && udata->common.heap);
565
0
    assert(new_node_p);
566
567
    /*
568
     * Load the symbol node.
569
     */
570
0
    if (NULL == (sn = (H5G_node_t *)H5AC_protect(f, H5AC_SNODE, addr, f, H5AC__NO_FLAGS_SET)))
571
0
        HGOTO_ERROR(H5E_SYM, H5E_CANTPROTECT, H5B_INS_ERROR, "unable to protect symbol table node");
572
573
    /*
574
     * Where does the new symbol get inserted?  We use a binary search.
575
     */
576
0
    rt = sn->nsyms;
577
0
    while (lt < rt) {
578
0
        idx = (int)((lt + rt) / 2);
579
0
        if ((s = (const char *)H5HL_offset_into(udata->common.heap, sn->entry[idx].name_off)) == NULL)
580
0
            HGOTO_ERROR(H5E_SYM, H5E_CANTGET, H5B_INS_ERROR, "unable to get symbol table name");
581
582
        /* Check if symbol is already present */
583
0
        if (0 == (cmp = strncmp(udata->common.name, s, (udata->common.block_size - sn->entry[idx].name_off))))
584
0
            HGOTO_ERROR(H5E_SYM, H5E_CANTINSERT, H5B_INS_ERROR, "symbol is already present in symbol table");
585
586
0
        if (cmp < 0)
587
0
            rt = (unsigned)idx;
588
0
        else
589
0
            lt = (unsigned)(idx + 1);
590
0
    } /* end while */
591
0
    idx += cmp > 0 ? 1 : 0;
592
593
    /* Convert link information & name to symbol table entry */
594
0
    if (H5G__link_to_ent(f, udata->common.heap, udata->lnk, udata->obj_type, udata->crt_info, &ent) < 0)
595
0
        HGOTO_ERROR(H5E_SYM, H5E_CANTCONVERT, H5B_INS_ERROR, "unable to convert link");
596
597
    /* Determine where to place entry in node */
598
0
    if (sn->nsyms >= 2 * H5F_SYM_LEAF_K(f)) {
599
        /*
600
         * The node is full.  Split it into a left and right
601
         * node and return the address of the new right node (the
602
         * left node is at the same address as the original node).
603
         */
604
0
        ret_value = H5B_INS_RIGHT;
605
606
        /* The right node */
607
0
        if (H5G__node_create(f, H5B_INS_FIRST, NULL, NULL, NULL, new_node_p /*out*/) < 0)
608
0
            HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, H5B_INS_ERROR, "unable to split symbol table node");
609
610
0
        if (NULL == (snrt = (H5G_node_t *)H5AC_protect(f, H5AC_SNODE, *new_node_p, f, H5AC__NO_FLAGS_SET)))
611
0
            HGOTO_ERROR(H5E_SYM, H5E_CANTPROTECT, H5B_INS_ERROR, "unable to split symbol table node");
612
613
0
        H5MM_memcpy(snrt->entry, sn->entry + H5F_SYM_LEAF_K(f), H5F_SYM_LEAF_K(f) * sizeof(H5G_entry_t));
614
0
        snrt->nsyms = H5F_SYM_LEAF_K(f);
615
0
        snrt_flags |= H5AC__DIRTIED_FLAG;
616
617
        /* The left node */
618
0
        memset(sn->entry + H5F_SYM_LEAF_K(f), 0, H5F_SYM_LEAF_K(f) * sizeof(H5G_entry_t));
619
0
        sn->nsyms = H5F_SYM_LEAF_K(f);
620
0
        sn_flags |= H5AC__DIRTIED_FLAG;
621
622
        /* The middle key */
623
0
        md_key->offset = sn->entry[sn->nsyms - 1].name_off;
624
625
        /* Where to insert the new entry? */
626
0
        if (idx <= (int)H5F_SYM_LEAF_K(f)) {
627
0
            insert_into = sn;
628
0
            if (idx == (int)H5F_SYM_LEAF_K(f))
629
0
                md_key->offset = ent.name_off;
630
0
        } /* end if */
631
0
        else {
632
0
            idx -= (int)H5F_SYM_LEAF_K(f);
633
0
            insert_into = snrt;
634
0
            if (idx == (int)H5F_SYM_LEAF_K(f)) {
635
0
                rt_key->offset  = ent.name_off;
636
0
                *rt_key_changed = true;
637
0
            } /* end if */
638
0
        }     /* end else */
639
0
    }         /* end if */
640
0
    else {
641
        /* Where to insert the new entry? */
642
0
        ret_value = H5B_INS_NOOP;
643
0
        sn_flags |= H5AC__DIRTIED_FLAG;
644
0
        insert_into = sn;
645
0
        if (idx == (int)sn->nsyms) {
646
0
            rt_key->offset  = ent.name_off;
647
0
            *rt_key_changed = true;
648
0
        } /* end if */
649
0
    }     /* end else */
650
651
    /* Move entries down to make room for new entry */
652
0
    assert(idx >= 0);
653
0
    memmove(insert_into->entry + idx + 1, insert_into->entry + idx,
654
0
            (insert_into->nsyms - (unsigned)idx) * sizeof(H5G_entry_t));
655
656
    /* Copy new entry into table */
657
0
    H5G__ent_copy(&(insert_into->entry[idx]), &ent, H5_COPY_SHALLOW);
658
659
    /* Increment # of symbols in table */
660
0
    insert_into->nsyms += 1;
661
662
0
done:
663
0
    if (snrt && H5AC_unprotect(f, H5AC_SNODE, *new_node_p, snrt, snrt_flags) < 0)
664
0
        HDONE_ERROR(H5E_SYM, H5E_CANTUNPROTECT, H5B_INS_ERROR, "unable to release symbol table node");
665
0
    if (sn && H5AC_unprotect(f, H5AC_SNODE, addr, sn, sn_flags) < 0)
666
0
        HDONE_ERROR(H5E_SYM, H5E_CANTUNPROTECT, H5B_INS_ERROR, "unable to release symbol table node");
667
668
0
    FUNC_LEAVE_NOAPI(ret_value)
669
0
} /* end H5G__node_insert() */
670
671
/*-------------------------------------------------------------------------
672
 * Function:    H5G__node_remove
673
 *
674
 * Purpose: The B-tree removal engine has found the symbol table node
675
 *          which should contain the name which is being removed.  This
676
 *          function removes the name from the symbol table and
677
 *          decrements the link count on the object to which the name
678
 *          points.
679
 *
680
 *          If the udata->name parameter is set to NULL, then remove
681
 *          all entries in this symbol table node.  This only occurs
682
 *          during the deletion of the entire group, so don't bother
683
 *          freeing individual name entries in the local heap, the group's
684
 *          symbol table removal code will just free the entire local
685
 *          heap eventually.  Do reduce the link counts for each object
686
 *          however.
687
 *
688
 * Return:  Success:    If all names are removed from the symbol
689
 *                      table node then H5B_INS_REMOVE is returned;
690
 *                      otherwise H5B_INS_NOOP is returned.
691
 *
692
 *          Failure:    H5B_INS_ERROR
693
 *
694
 *-------------------------------------------------------------------------
695
 */
696
static H5B_ins_t
697
H5G__node_remove(H5F_t *f, haddr_t addr, void H5_ATTR_NDEBUG_UNUSED *_lt_key /*in,out*/,
698
                 bool H5_ATTR_UNUSED *lt_key_changed /*out*/, void *_udata /*in,out*/,
699
                 void *_rt_key /*in,out*/, bool *rt_key_changed /*out*/)
700
0
{
701
0
    H5G_node_key_t *rt_key   = (H5G_node_key_t *)_rt_key;
702
0
    H5G_bt_rm_t    *udata    = (H5G_bt_rm_t *)_udata;
703
0
    H5G_node_t     *sn       = NULL;
704
0
    unsigned        sn_flags = H5AC__NO_FLAGS_SET;
705
0
    unsigned        lt = 0, rt, idx = 0;
706
0
    int             cmp       = 1;
707
0
    H5B_ins_t       ret_value = H5B_INS_ERROR;
708
709
0
    FUNC_ENTER_PACKAGE
710
711
    /* Check arguments */
712
0
    assert(f);
713
0
    assert(H5_addr_defined(addr));
714
0
    assert((H5G_node_key_t *)_lt_key);
715
0
    assert(rt_key);
716
0
    assert(udata && udata->common.heap);
717
718
    /* Load the symbol table */
719
0
    if (NULL == (sn = (H5G_node_t *)H5AC_protect(f, H5AC_SNODE, addr, f, H5AC__NO_FLAGS_SET)))
720
0
        HGOTO_ERROR(H5E_SYM, H5E_CANTPROTECT, H5B_INS_ERROR, "unable to protect symbol table node");
721
722
    /* "Normal" removal of a single entry from the symbol table node */
723
0
    if (udata->common.name != NULL) {
724
0
        H5O_link_t lnk;           /* Constructed link for replacement */
725
0
        size_t     link_name_len; /* Length of string in local heap */
726
727
        /* Find the name with a binary search */
728
0
        rt = sn->nsyms;
729
0
        while (lt < rt && cmp) {
730
0
            const char *s; /* Pointer to string in local heap */
731
732
0
            idx = (lt + rt) / 2;
733
0
            if ((s = (const char *)H5HL_offset_into(udata->common.heap, sn->entry[idx].name_off)) == NULL)
734
0
                HGOTO_ERROR(H5E_SYM, H5E_CANTGET, H5B_INS_ERROR, "unable to get symbol table name");
735
0
            cmp = strncmp(udata->common.name, s, (udata->common.block_size - sn->entry[idx].name_off));
736
0
            if (cmp < 0)
737
0
                rt = idx;
738
0
            else
739
0
                lt = idx + 1;
740
0
        } /* end while */
741
742
0
        if (cmp)
743
0
            HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, H5B_INS_ERROR, "name not found");
744
745
        /* Get a pointer to the name of the link */
746
0
        if (NULL == (lnk.name = (char *)H5HL_offset_into(udata->common.heap, sn->entry[idx].name_off)))
747
0
            HGOTO_ERROR(H5E_SYM, H5E_CANTGET, H5B_INS_ERROR, "unable to get link name");
748
749
        /* Compute the size of the link name in the heap, being defensive about corrupted data */
750
0
        link_name_len = strnlen(lnk.name, (udata->common.block_size - sn->entry[idx].name_off)) + 1;
751
0
        if (link_name_len > (udata->common.block_size - sn->entry[idx].name_off))
752
0
            link_name_len = (udata->common.block_size - sn->entry[idx].name_off);
753
754
        /* Set up rest of link structure */
755
0
        lnk.corder_valid = false;
756
0
        lnk.corder       = 0;
757
0
        lnk.cset         = H5T_CSET_ASCII;
758
0
        if (sn->entry[idx].type == H5G_CACHED_SLINK) {
759
0
            lnk.type = H5L_TYPE_SOFT;
760
0
            if (NULL == (lnk.u.soft.name = (char *)H5HL_offset_into(udata->common.heap,
761
0
                                                                    sn->entry[idx].cache.slink.lval_offset)))
762
0
                HGOTO_ERROR(H5E_SYM, H5E_CANTGET, H5B_INS_ERROR, "unable to get link name");
763
0
        } /* end if */
764
0
        else {
765
0
            lnk.type = H5L_TYPE_HARD;
766
0
            assert(H5_addr_defined(sn->entry[idx].header));
767
0
            lnk.u.hard.addr = sn->entry[idx].header;
768
0
        } /* end else */
769
770
        /* Replace any object names */
771
0
        if (H5G__link_name_replace(f, udata->grp_full_path_r, &lnk) < 0)
772
0
            HGOTO_ERROR(H5E_SYM, H5E_CANTGET, H5B_INS_ERROR, "unable to get object type");
773
774
        /* Decrement the ref. count for hard links */
775
0
        if (lnk.type == H5L_TYPE_HARD) {
776
0
            H5O_loc_t tmp_oloc; /* Temporary object location */
777
778
            /* Build temporary object location */
779
0
            tmp_oloc.file = f;
780
0
            tmp_oloc.addr = lnk.u.hard.addr;
781
782
0
            if (H5O_link(&tmp_oloc, -1) < 0)
783
0
                HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, H5B_INS_ERROR, "unable to decrement object link count");
784
0
        } /* end if */
785
0
        else {
786
            /* Remove the soft link's value from the local heap */
787
0
            if (lnk.u.soft.name) {
788
0
                size_t soft_link_len; /* Length of string in local heap */
789
790
                /* Compute the size of the soft link name in the heap, being defensive about corrupted data */
791
0
                soft_link_len = strnlen(lnk.u.soft.name,
792
0
                                        (udata->common.block_size - sn->entry[idx].cache.slink.lval_offset)) +
793
0
                                1;
794
0
                if (soft_link_len > (udata->common.block_size - sn->entry[idx].cache.slink.lval_offset))
795
0
                    soft_link_len = (udata->common.block_size - sn->entry[idx].cache.slink.lval_offset);
796
797
0
                if (H5HL_remove(f, udata->common.heap, sn->entry[idx].cache.slink.lval_offset,
798
0
                                soft_link_len) < 0)
799
0
                    HGOTO_ERROR(H5E_SYM, H5E_CANTDELETE, H5B_INS_ERROR,
800
0
                                "unable to remove soft link from local heap");
801
0
            } /* end if */
802
0
        }     /* end else */
803
804
        /* Remove the link's name from the local heap */
805
0
        if (H5HL_remove(f, udata->common.heap, sn->entry[idx].name_off, link_name_len) < 0)
806
0
            HGOTO_ERROR(H5E_SYM, H5E_CANTDELETE, H5B_INS_ERROR, "unable to remove link name from local heap");
807
808
        /* Remove the entry from the symbol table node */
809
0
        if (1 == sn->nsyms) {
810
            /*
811
             * We are about to remove the only symbol in this node.  Free this
812
             * node and indicate that the pointer to this node in the B-tree
813
             * should be removed also.
814
             */
815
0
            assert(0 == idx);
816
0
            sn->nsyms = 0;
817
0
            sn_flags |= H5AC__DIRTIED_FLAG | H5AC__DELETED_FLAG | H5AC__FREE_FILE_SPACE_FLAG;
818
0
            ret_value = H5B_INS_REMOVE;
819
0
        }
820
0
        else if (0 == idx) {
821
            /*
822
             * We are about to remove the left-most entry from the symbol table
823
             * node but there are other entries to the right.  No key values
824
             * change.
825
             */
826
0
            sn->nsyms -= 1;
827
0
            sn_flags |= H5AC__DIRTIED_FLAG;
828
0
            memmove(sn->entry + idx, sn->entry + idx + 1, (sn->nsyms - idx) * sizeof(H5G_entry_t));
829
0
            ret_value = H5B_INS_NOOP;
830
0
        }
831
0
        else if (idx + 1 == sn->nsyms) {
832
            /*
833
             * We are about to remove the right-most entry from the symbol table
834
             * node but there are other entries to the left.  The right key
835
             * should be changed to reflect the new right-most entry.
836
             */
837
0
            sn->nsyms -= 1;
838
0
            sn_flags |= H5AC__DIRTIED_FLAG;
839
0
            rt_key->offset  = sn->entry[sn->nsyms - 1].name_off;
840
0
            *rt_key_changed = true;
841
0
            ret_value       = H5B_INS_NOOP;
842
0
        }
843
0
        else {
844
            /*
845
             * We are about to remove an entry from the middle of a symbol table
846
             * node.
847
             */
848
0
            sn->nsyms -= 1;
849
0
            sn_flags |= H5AC__DIRTIED_FLAG;
850
0
            memmove(sn->entry + idx, sn->entry + idx + 1, (sn->nsyms - idx) * sizeof(H5G_entry_t));
851
0
            ret_value = H5B_INS_NOOP;
852
0
        } /* end else */
853
0
    }     /* end if */
854
    /* Remove all entries from node, during B-tree deletion */
855
0
    else {
856
0
        H5O_loc_t tmp_oloc; /* Temporary object location */
857
858
        /* Build temporary object location */
859
0
        tmp_oloc.file = f;
860
861
        /* Reduce the link count for all entries in this node */
862
0
        for (idx = 0; idx < sn->nsyms; idx++)
863
0
            if (!(H5G_CACHED_SLINK == sn->entry[idx].type)) {
864
                /* Decrement the reference count */
865
0
                assert(H5_addr_defined(sn->entry[idx].header));
866
0
                tmp_oloc.addr = sn->entry[idx].header;
867
868
0
                if (H5O_link(&tmp_oloc, -1) < 0)
869
0
                    HGOTO_ERROR(H5E_SYM, H5E_CANTDELETE, H5B_INS_ERROR,
870
0
                                "unable to decrement object link count");
871
0
            } /* end if */
872
873
        /*
874
         * We are about to remove all the symbols in this node.  Free this
875
         * node and indicate that the pointer to this node in the B-tree
876
         * should be removed also.
877
         */
878
0
        sn->nsyms = 0;
879
0
        sn_flags |= H5AC__DIRTIED_FLAG | H5AC__DELETED_FLAG | H5AC__FREE_FILE_SPACE_FLAG;
880
0
        ret_value = H5B_INS_REMOVE;
881
0
    } /* end else */
882
883
0
done:
884
0
    if (sn && H5AC_unprotect(f, H5AC_SNODE, addr, sn, sn_flags) < 0)
885
0
        HDONE_ERROR(H5E_SYM, H5E_CANTUNPROTECT, H5B_INS_ERROR, "unable to release symbol table node");
886
887
0
    FUNC_LEAVE_NOAPI(ret_value)
888
0
} /* end H5G__node_remove() */
889
890
/*-------------------------------------------------------------------------
891
 * Function:    H5G__node_iterate
892
 *
893
 * Purpose:     This function gets called during a group iterate operation.
894
 *
895
 * Return:      Non-negative on success/Negative on failure
896
 *
897
 *-------------------------------------------------------------------------
898
 */
899
int
900
H5G__node_iterate(H5F_t *f, const void H5_ATTR_UNUSED *_lt_key, haddr_t addr,
901
                  const void H5_ATTR_UNUSED *_rt_key, void *_udata)
902
0
{
903
0
    H5G_bt_it_it_t *udata = (H5G_bt_it_it_t *)_udata;
904
0
    H5G_node_t     *sn    = NULL;
905
0
    H5G_entry_t    *ents; /* Pointer to entries in this node */
906
0
    unsigned        u;    /* Local index variable */
907
0
    int             ret_value = H5_ITER_CONT;
908
909
0
    FUNC_ENTER_PACKAGE
910
911
    /*
912
     * Check arguments.
913
     */
914
0
    assert(f);
915
0
    assert(H5_addr_defined(addr));
916
0
    assert(udata && udata->heap);
917
918
    /* Protect the symbol table node & local heap while we iterate over entries */
919
0
    if (NULL == (sn = (H5G_node_t *)H5AC_protect(f, H5AC_SNODE, addr, f, H5AC__READ_ONLY_FLAG)))
920
0
        HGOTO_ERROR(H5E_SYM, H5E_CANTPROTECT, H5_ITER_ERROR, "unable to load symbol table node");
921
922
    /*
923
     * Iterate over the symbol table node entries.
924
     */
925
0
    for (u = 0, ents = sn->entry; u < sn->nsyms && ret_value == H5_ITER_CONT; u++) {
926
0
        if (udata->skip > 0)
927
0
            --udata->skip;
928
0
        else {
929
0
            H5O_link_t lnk; /* Link for entry */
930
931
            /* Convert the entry to a link */
932
0
            if (H5G__ent_to_link(&ents[u], udata->heap, &lnk) < 0)
933
0
                HGOTO_ERROR(H5E_SYM, H5E_CANTCONVERT, H5_ITER_ERROR,
934
0
                            "unable to convert symbol table entry to link");
935
936
            /* Make the callback */
937
0
            ret_value = (udata->op)(&lnk, udata->op_data);
938
939
            /* Release memory for link object */
940
0
            if (H5O_msg_reset(H5O_LINK_ID, &lnk) < 0)
941
0
                HGOTO_ERROR(H5E_SYM, H5E_CANTFREE, H5_ITER_ERROR, "unable to release link message");
942
0
        } /* end else */
943
944
        /* Increment the number of entries passed through */
945
        /* (whether we skipped them or not) */
946
0
        if (udata->final_ent)
947
0
            (*udata->final_ent)++;
948
0
    } /* end for */
949
0
    if (ret_value < 0)
950
0
        HERROR(H5E_SYM, H5E_CANTNEXT, "iteration operator failed");
951
952
0
done:
953
    /* Release resources */
954
0
    if (sn && H5AC_unprotect(f, H5AC_SNODE, addr, sn, H5AC__NO_FLAGS_SET) < 0)
955
0
        HDONE_ERROR(H5E_SYM, H5E_CANTUNPROTECT, H5_ITER_ERROR, "unable to release object header");
956
957
0
    FUNC_LEAVE_NOAPI(ret_value)
958
0
} /* end H5G__node_iterate() */
959
960
/*-------------------------------------------------------------------------
961
 * Function:    H5G__node_sumup
962
 *
963
 * Purpose:     This function gets called during a group iterate operation
964
 *              to return total number of members in the group.
965
 *
966
 * Return:      Non-negative on success/Negative on failure
967
 *
968
 *-------------------------------------------------------------------------
969
 */
970
int
971
H5G__node_sumup(H5F_t *f, const void H5_ATTR_UNUSED *_lt_key, haddr_t addr,
972
                const void H5_ATTR_UNUSED *_rt_key, void *_udata)
973
0
{
974
0
    hsize_t    *num_objs  = (hsize_t *)_udata;
975
0
    H5G_node_t *sn        = NULL;
976
0
    int         ret_value = H5_ITER_CONT;
977
978
0
    FUNC_ENTER_PACKAGE
979
980
    /*
981
     * Check arguments.
982
     */
983
0
    assert(f);
984
0
    assert(H5_addr_defined(addr));
985
0
    assert(num_objs);
986
987
    /* Find the object node and add the number of symbol entries. */
988
0
    if (NULL == (sn = (H5G_node_t *)H5AC_protect(f, H5AC_SNODE, addr, f, H5AC__READ_ONLY_FLAG)))
989
0
        HGOTO_ERROR(H5E_SYM, H5E_CANTPROTECT, H5_ITER_ERROR, "unable to load symbol table node");
990
991
0
    *num_objs += sn->nsyms;
992
993
0
done:
994
0
    if (sn && H5AC_unprotect(f, H5AC_SNODE, addr, sn, H5AC__NO_FLAGS_SET) < 0)
995
0
        HDONE_ERROR(H5E_SYM, H5E_CANTUNPROTECT, H5_ITER_ERROR, "unable to release object header");
996
997
0
    FUNC_LEAVE_NOAPI(ret_value)
998
0
} /* end H5G__node_sumup() */
999
1000
/*-------------------------------------------------------------------------
1001
 * Function:    H5G__node_by_idx
1002
 *
1003
 * Purpose:     This function gets called during a group iterate operation
1004
 *              to return object name by giving idx.
1005
 *
1006
 * Return:      0 if object isn't found in this node; 1 if object is found;
1007
 *              Negative on failure
1008
 *
1009
 *-------------------------------------------------------------------------
1010
 */
1011
int
1012
H5G__node_by_idx(H5F_t *f, const void H5_ATTR_UNUSED *_lt_key, haddr_t addr,
1013
                 const void H5_ATTR_UNUSED *_rt_key, void *_udata)
1014
0
{
1015
0
    H5G_bt_it_idx_common_t *udata     = (H5G_bt_it_idx_common_t *)_udata;
1016
0
    H5G_node_t             *sn        = NULL;
1017
0
    int                     ret_value = H5_ITER_CONT;
1018
1019
0
    FUNC_ENTER_PACKAGE
1020
1021
    /*
1022
     * Check arguments.
1023
     */
1024
0
    assert(f);
1025
0
    assert(H5_addr_defined(addr));
1026
0
    assert(udata);
1027
1028
    /* Get a pointer to the symbol table node */
1029
0
    if (NULL == (sn = (H5G_node_t *)H5AC_protect(f, H5AC_SNODE, addr, f, H5AC__READ_ONLY_FLAG)))
1030
0
        HGOTO_ERROR(H5E_SYM, H5E_CANTPROTECT, H5_ITER_ERROR, "unable to load symbol table node");
1031
1032
    /* Find the node, locate the object symbol table entry and retrieve the name */
1033
0
    if (udata->idx >= udata->num_objs && udata->idx < (udata->num_objs + sn->nsyms)) {
1034
0
        hsize_t ent_idx; /* Entry index in this node */
1035
1036
        /* Compute index of entry */
1037
0
        ent_idx = udata->idx - udata->num_objs;
1038
1039
        /* Call 'by index' callback */
1040
0
        assert(udata->op);
1041
0
        if ((udata->op)(&sn->entry[ent_idx], udata) < 0)
1042
0
            HGOTO_ERROR(H5E_SYM, H5E_CANTGET, H5B_INS_ERROR, "'by index' callback failed");
1043
1044
        /* Indicate that we found the entry we are interested in */
1045
0
        ret_value = H5_ITER_STOP;
1046
0
    } /* end if */
1047
0
    else
1048
0
        udata->num_objs += sn->nsyms;
1049
1050
0
done:
1051
0
    if (sn && H5AC_unprotect(f, H5AC_SNODE, addr, sn, H5AC__NO_FLAGS_SET) < 0)
1052
0
        HDONE_ERROR(H5E_SYM, H5E_CANTUNPROTECT, H5_ITER_ERROR, "unable to release object header");
1053
1054
0
    FUNC_LEAVE_NOAPI(ret_value)
1055
0
} /* end H5G__node_by_idx() */
1056
1057
/*-------------------------------------------------------------------------
1058
 * Function:    H5G__node_init
1059
 *
1060
 * Purpose:     This function gets called during a file opening to initialize
1061
 *              global information about group B-tree nodes for file.
1062
 *
1063
 * Return:      Non-negative on success
1064
 *              Negative on failure
1065
 *
1066
 *-------------------------------------------------------------------------
1067
 */
1068
herr_t
1069
H5G__node_init(H5F_t *f)
1070
484
{
1071
484
    H5B_shared_t *shared;              /* Shared B-tree node info  */
1072
484
    size_t        sizeof_rkey;         /* Size of raw (disk) key   */
1073
484
    herr_t        ret_value = SUCCEED; /* Return value             */
1074
1075
484
    FUNC_ENTER_PACKAGE
1076
1077
    /* Check arguments. */
1078
484
    assert(f);
1079
1080
    /* Set the raw key size */
1081
484
    sizeof_rkey = H5F_SIZEOF_SIZE(f); /*name offset */
1082
1083
    /* Allocate & initialize global info for the shared structure */
1084
484
    if (NULL == (shared = H5B_shared_new(f, H5B_SNODE, sizeof_rkey)))
1085
0
        HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "memory allocation failed for shared B-tree info");
1086
1087
    /* Set up the "local" information for this file's groups */
1088
    /* <none> */
1089
1090
    /* Make shared B-tree info reference counted */
1091
484
    if (H5F_SET_GRP_BTREE_SHARED(f, H5UC_create(shared, H5B_shared_free)) < 0)
1092
0
        HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "can't create ref-count wrapper for shared B-tree info");
1093
1094
484
done:
1095
484
    FUNC_LEAVE_NOAPI(ret_value)
1096
484
} /* end H5G__node_init() */
1097
1098
/*-------------------------------------------------------------------------
1099
 * Function:    H5G_node_close
1100
 *
1101
 * Purpose:     This function gets called during a file close to shutdown
1102
 *              global information about group B-tree nodes for file.
1103
 *
1104
 * Return:      Non-negative on success
1105
 *              Negative on failure
1106
 *
1107
 *
1108
 *-------------------------------------------------------------------------
1109
 */
1110
herr_t
1111
H5G_node_close(const H5F_t *f)
1112
543
{
1113
543
    FUNC_ENTER_NOAPI_NOINIT_NOERR
1114
1115
    /* Check arguments. */
1116
543
    assert(f);
1117
1118
    /* Free the raw B-tree node buffer */
1119
543
    if (H5F_GRP_BTREE_SHARED(f))
1120
484
        H5UC_DEC(H5F_GRP_BTREE_SHARED(f));
1121
1122
543
    FUNC_LEAVE_NOAPI(SUCCEED)
1123
543
} /* end H5G_node_close */
1124
1125
/*-------------------------------------------------------------------------
1126
 * Function:    H5G__node_copy
1127
 *
1128
 * Purpose:     This function gets called during a group iterate operation
1129
 *              to copy objects of this node into a new location.
1130
 *
1131
 * Return:      0(zero) on success/Negative on failure
1132
 *
1133
 *-------------------------------------------------------------------------
1134
 */
1135
int
1136
H5G__node_copy(H5F_t *f, const void H5_ATTR_UNUSED *_lt_key, haddr_t addr, const void H5_ATTR_UNUSED *_rt_key,
1137
               void *_udata)
1138
0
{
1139
0
    H5G_bt_it_cpy_t *udata    = (H5G_bt_it_cpy_t *)_udata;
1140
0
    const H5O_loc_t *src_oloc = udata->src_oloc;
1141
0
    H5O_copy_t      *cpy_info = udata->cpy_info;
1142
0
    H5G_node_t      *sn       = NULL;
1143
0
    unsigned int     i; /* Local index variable */
1144
0
    int              ret_value = H5_ITER_CONT;
1145
1146
0
    FUNC_ENTER_PACKAGE
1147
1148
    /* Check arguments. */
1149
0
    assert(f);
1150
0
    assert(H5_addr_defined(addr));
1151
0
    assert(udata);
1152
0
    assert(udata->src_heap);
1153
1154
    /* load the symbol table into memory from the source file */
1155
0
    if (NULL == (sn = (H5G_node_t *)H5AC_protect(f, H5AC_SNODE, addr, f, H5AC__READ_ONLY_FLAG)))
1156
0
        HGOTO_ERROR(H5E_SYM, H5E_CANTPROTECT, H5_ITER_ERROR, "unable to load symbol table node");
1157
1158
    /* copy object in this node one by one */
1159
0
    for (i = 0; i < sn->nsyms; i++) {
1160
0
        H5G_entry_t *src_ent =
1161
0
            &(sn->entry[i]);             /* Convenience variable to refer to current source group entry */
1162
0
        H5O_link_t          lnk;         /* Link to insert */
1163
0
        char               *name;        /* Name of source object */
1164
0
        H5G_entry_t         tmp_src_ent; /* Temporary copy. Change will not affect the cache */
1165
0
        H5O_type_t          obj_type = H5O_TYPE_UNKNOWN; /* Target object type */
1166
0
        H5G_copy_file_ud_t *cpy_udata;                   /* Copy file udata */
1167
0
        H5G_obj_create_t    gcrt_info;                   /* Group creation info */
1168
0
        size_t              max_link_len;                /* Max. length of string in local heap */
1169
1170
        /* expand soft link */
1171
0
        if (H5G_CACHED_SLINK == src_ent->type && cpy_info->expand_soft_link) {
1172
0
            haddr_t    obj_addr = HADDR_UNDEF; /* Address of object pointed to by soft link */
1173
0
            H5G_loc_t  grp_loc;                /* Group location holding soft link */
1174
0
            H5G_name_t grp_path;               /* Path for group holding soft link */
1175
0
            char      *link_name;              /* Pointer to value of soft link */
1176
1177
            /* Make a temporary copy, so that it will not change the info in the cache */
1178
0
            H5MM_memcpy(&tmp_src_ent, src_ent, sizeof(H5G_entry_t));
1179
1180
            /* Set up group location for soft link to start in */
1181
0
            H5G_name_reset(&grp_path);
1182
0
            grp_loc.path = &grp_path;
1183
0
            H5_WARN_CAST_AWAY_CONST_OFF
1184
0
            grp_loc.oloc = (H5O_loc_t *)src_oloc;
1185
0
            H5_WARN_CAST_AWAY_CONST_ON
1186
1187
            /* Get pointer to link value in local heap */
1188
0
            if ((link_name =
1189
0
                     (char *)H5HL_offset_into(udata->src_heap, tmp_src_ent.cache.slink.lval_offset)) == NULL)
1190
0
                HGOTO_ERROR(H5E_SYM, H5E_CANTGET, H5_ITER_ERROR, "unable to get link name");
1191
1192
            /* Sanity check soft link name, to detect running off the end of the heap block */
1193
0
            max_link_len = udata->src_block_size - tmp_src_ent.cache.slink.lval_offset;
1194
0
            if (strnlen(link_name, max_link_len) == max_link_len)
1195
0
                HGOTO_ERROR(H5E_SYM, H5E_BADVALUE, H5_ITER_ERROR, "invalid link name offset");
1196
1197
            /* Check if the object pointed by the soft link exists in the source file */
1198
0
            if (H5G__loc_addr(&grp_loc, link_name, &obj_addr) < 0)
1199
0
                HGOTO_ERROR(H5E_SYM, H5E_CANTFIND, H5_ITER_ERROR,
1200
0
                            "unable to check if soft link resolves to an object");
1201
0
            if (H5_addr_defined(obj_addr)) {
1202
0
                tmp_src_ent.header = obj_addr;
1203
0
                src_ent            = &tmp_src_ent;
1204
0
            } /* end if */
1205
0
        }     /* if ((H5G_CACHED_SLINK == src_ent->type)... */
1206
1207
        /* Check if object in source group is a hard link */
1208
0
        if (H5_addr_defined(src_ent->header)) {
1209
0
            H5O_loc_t new_dst_oloc; /* Copied object location in destination */
1210
0
            H5O_loc_t tmp_src_oloc; /* Temporary object location for source object */
1211
1212
            /* Set up copied object location to fill in */
1213
0
            H5O_loc_reset(&new_dst_oloc);
1214
0
            new_dst_oloc.file = udata->dst_file;
1215
1216
            /* Build temporary object location for source */
1217
0
            H5O_loc_reset(&tmp_src_oloc);
1218
0
            tmp_src_oloc.file = f;
1219
0
            tmp_src_oloc.addr = src_ent->header;
1220
1221
            /* Copy the shared object from source to destination */
1222
0
            if (H5O_copy_header_map(&tmp_src_oloc, &new_dst_oloc, cpy_info, true, &obj_type,
1223
0
                                    (void **)&cpy_udata) < 0)
1224
0
                HGOTO_ERROR(H5E_SYM, H5E_CANTCOPY, H5_ITER_ERROR, "unable to copy object");
1225
1226
            /* Set up object creation info for symbol table insertion.  Only
1227
             * case so far is for inserting old-style groups (for caching stab
1228
             * info). */
1229
0
            if (obj_type == H5O_TYPE_GROUP) {
1230
0
                gcrt_info.gcpl_id    = H5P_DEFAULT;
1231
0
                gcrt_info.cache_type = cpy_udata->cache_type;
1232
0
                gcrt_info.cache      = cpy_udata->cache;
1233
0
            } /* end if */
1234
1235
            /* Construct link information for eventual insertion */
1236
0
            lnk.type        = H5L_TYPE_HARD;
1237
0
            lnk.u.hard.addr = new_dst_oloc.addr;
1238
0
        } /* ( H5_addr_defined(src_ent->header)) */
1239
0
        else if (H5G_CACHED_SLINK == src_ent->type) {
1240
            /* it is a soft link */
1241
            /* Set object type to unknown */
1242
0
            obj_type = H5O_TYPE_UNKNOWN;
1243
1244
            /* Construct link information for eventual insertion */
1245
0
            lnk.type = H5L_TYPE_SOFT;
1246
0
            if ((lnk.u.soft.name =
1247
0
                     (char *)H5HL_offset_into(udata->src_heap, src_ent->cache.slink.lval_offset)) == NULL)
1248
0
                HGOTO_ERROR(H5E_SYM, H5E_CANTGET, H5_ITER_ERROR, "unable to get link name");
1249
1250
            /* Sanity check soft link name, to detect running off the end of the heap block */
1251
0
            max_link_len = udata->src_block_size - src_ent->cache.slink.lval_offset;
1252
0
            if (strnlen(lnk.u.soft.name, max_link_len) == max_link_len)
1253
0
                HGOTO_ERROR(H5E_SYM, H5E_BADVALUE, H5_ITER_ERROR, "invalid link name offset");
1254
0
        } /* else if */
1255
0
        else
1256
0
            assert(0 && "Unknown entry type");
1257
1258
        /* Determine name of source object */
1259
0
        if ((name = (char *)H5HL_offset_into(udata->src_heap, src_ent->name_off)) == NULL)
1260
0
            HGOTO_ERROR(H5E_SYM, H5E_CANTGET, H5_ITER_ERROR, "unable to get source object name");
1261
1262
        /* Sanity check soft link name, to detect running off the end of the heap block */
1263
0
        max_link_len = udata->src_block_size - src_ent->name_off;
1264
0
        if (strnlen(name, max_link_len) == max_link_len)
1265
0
            HGOTO_ERROR(H5E_SYM, H5E_BADVALUE, H5_ITER_ERROR, "invalid link name offset");
1266
1267
        /* Set up common link data */
1268
0
        lnk.cset         = H5F_DEFAULT_CSET; /* XXX: Allow user to set this */
1269
0
        lnk.corder       = 0;                /* Creation order is not tracked for old-style links */
1270
0
        lnk.corder_valid = false;            /* Creation order is not valid */
1271
0
        lnk.name         = name;             /* Name of link */
1272
1273
        /* Set copied metadata tag */
1274
0
        H5_BEGIN_TAG(H5AC__COPIED_TAG)
1275
1276
        /* Insert the new object in the destination file's group */
1277
        /* (Don't increment the link count - that's already done above for hard links) */
1278
0
        if (H5G__stab_insert_real(udata->dst_file, udata->dst_stab, &lnk, obj_type,
1279
0
                                  (obj_type == H5O_TYPE_GROUP ? &gcrt_info : NULL)) < 0)
1280
0
            HGOTO_ERROR_TAG(H5E_DATATYPE, H5E_CANTINIT, H5_ITER_ERROR, "unable to insert the name");
1281
1282
        /* Reset metadata tag */
1283
0
        H5_END_TAG
1284
1285
0
    } /* end of for (i=0; i<sn->nsyms; i++) */
1286
1287
0
done:
1288
0
    if (sn && H5AC_unprotect(f, H5AC_SNODE, addr, sn, H5AC__NO_FLAGS_SET) < 0)
1289
0
        HDONE_ERROR(H5E_SYM, H5E_CANTUNPROTECT, H5_ITER_ERROR, "unable to release object header");
1290
1291
0
    FUNC_LEAVE_NOAPI(ret_value)
1292
0
} /* end H5G__node_copy() */
1293
1294
/*-------------------------------------------------------------------------
1295
 * Function:    H5G__node_build_table
1296
 *
1297
 * Purpose:     B-link tree callback for building table of links
1298
 *
1299
 * Return:      Non-negative on success/Negative on failure
1300
 *
1301
 *-------------------------------------------------------------------------
1302
 */
1303
int
1304
H5G__node_build_table(H5F_t *f, const void H5_ATTR_UNUSED *_lt_key, haddr_t addr,
1305
                      const void H5_ATTR_UNUSED *_rt_key, void *_udata)
1306
0
{
1307
0
    H5G_bt_it_bt_t *udata = (H5G_bt_it_bt_t *)_udata;
1308
0
    H5G_node_t     *sn    = NULL; /* Symbol table node */
1309
0
    unsigned        u;            /* Local index variable */
1310
0
    int             ret_value = H5_ITER_CONT;
1311
1312
0
    FUNC_ENTER_PACKAGE
1313
1314
    /*
1315
     * Check arguments.
1316
     */
1317
0
    assert(f);
1318
0
    assert(H5_addr_defined(addr));
1319
0
    assert(udata && udata->heap);
1320
1321
    /*
1322
     * Save information about the symbol table node since we can't lock it
1323
     * because we're about to call an application function.
1324
     */
1325
0
    if (NULL == (sn = (H5G_node_t *)H5AC_protect(f, H5AC_SNODE, addr, f, H5AC__READ_ONLY_FLAG)))
1326
0
        HGOTO_ERROR(H5E_SYM, H5E_CANTPROTECT, H5_ITER_ERROR, "unable to load symbol table node");
1327
1328
    /* Check if the link table needs to be extended */
1329
0
    if ((udata->ltable->nlinks + sn->nsyms) >= udata->alloc_nlinks) {
1330
0
        size_t      na = MAX((udata->ltable->nlinks + sn->nsyms),
1331
0
                             (udata->alloc_nlinks * 2)); /* Double # of links allocated */
1332
0
        H5O_link_t *x;                                   /* Pointer to larger array of links */
1333
1334
        /* Re-allocate the link table */
1335
0
        if (NULL == (x = (H5O_link_t *)H5MM_realloc(udata->ltable->lnks, sizeof(H5O_link_t) * na)))
1336
0
            HGOTO_ERROR(H5E_SYM, H5E_CANTALLOC, H5_ITER_ERROR, "memory allocation failed");
1337
0
        udata->ltable->lnks = x;
1338
0
    } /* end if */
1339
1340
    /* Iterate over the symbol table node entries, adding to link table */
1341
0
    for (u = 0; u < sn->nsyms; u++) {
1342
0
        size_t linkno; /* Link allocated */
1343
1344
        /* Determine the link to operate on in the table */
1345
0
        linkno = udata->ltable->nlinks++;
1346
1347
        /* Convert the entry to a link */
1348
0
        if (H5G__ent_to_link(&sn->entry[u], udata->heap, &udata->ltable->lnks[linkno]) < 0)
1349
0
            HGOTO_ERROR(H5E_SYM, H5E_CANTCONVERT, H5_ITER_ERROR,
1350
0
                        "unable to convert symbol table entry to link");
1351
0
    } /* end for */
1352
1353
0
done:
1354
    /* Release the locked items */
1355
0
    if (sn && H5AC_unprotect(f, H5AC_SNODE, addr, sn, H5AC__NO_FLAGS_SET) < 0)
1356
0
        HDONE_ERROR(H5E_SYM, H5E_CANTUNPROTECT, H5_ITER_ERROR, "unable to release object header");
1357
1358
0
    FUNC_LEAVE_NOAPI(ret_value)
1359
0
} /* end H5G__node_build_table() */
1360
1361
/*-------------------------------------------------------------------------
1362
 * Function:    H5G__node_iterate_size
1363
 *
1364
 * Purpose:     This function gets called by H5B_iterate_helper()
1365
 *              to gather storage info for SNODs.
1366
 *
1367
 * Return:      Non-negative on success/Negative on failure
1368
 *
1369
 *-------------------------------------------------------------------------
1370
 */
1371
herr_t
1372
H5G__node_iterate_size(H5F_t *f, const void H5_ATTR_UNUSED *_lt_key, haddr_t H5_ATTR_UNUSED addr,
1373
                       const void H5_ATTR_UNUSED *_rt_key, void *_udata)
1374
0
{
1375
0
    hsize_t *stab_size = (hsize_t *)_udata; /* User data */
1376
1377
0
    FUNC_ENTER_PACKAGE_NOERR
1378
1379
    /* Check arguments */
1380
0
    assert(f);
1381
0
    assert(stab_size);
1382
1383
0
    *stab_size += H5G_NODE_SIZE(f);
1384
1385
0
    FUNC_LEAVE_NOAPI(SUCCEED)
1386
0
} /* end H5G__node_iterate_size() */
1387
1388
/*-------------------------------------------------------------------------
1389
 * Function:    H5G_node_debug
1390
 *
1391
 * Purpose:     Prints debugging information about a symbol table node
1392
 *              or a B-tree node for a symbol table B-tree.
1393
 *
1394
 * Return:      0(zero) on success/Negative on failure
1395
 *
1396
 *-------------------------------------------------------------------------
1397
 */
1398
herr_t
1399
H5G_node_debug(H5F_t *f, haddr_t addr, FILE *stream, int indent, int fwidth, haddr_t heap_addr)
1400
0
{
1401
0
    H5G_node_t *sn        = NULL;
1402
0
    H5HL_t     *heap      = NULL;
1403
0
    herr_t      ret_value = SUCCEED; /* Return value */
1404
1405
0
    FUNC_ENTER_NOAPI(FAIL)
1406
1407
    /*
1408
     * Check arguments.
1409
     */
1410
0
    assert(f);
1411
0
    assert(H5_addr_defined(addr));
1412
0
    assert(stream);
1413
0
    assert(indent >= 0);
1414
0
    assert(fwidth >= 0);
1415
1416
    /* Pin the heap down in memory */
1417
0
    if (heap_addr > 0 && H5_addr_defined(heap_addr))
1418
0
        if (NULL == (heap = H5HL_protect(f, heap_addr, H5AC__READ_ONLY_FLAG)))
1419
0
            HGOTO_ERROR(H5E_SYM, H5E_CANTPROTECT, FAIL, "unable to protect symbol table heap");
1420
1421
    /* Try loading symbol table node */
1422
0
    H5E_PAUSE_ERRORS
1423
0
        {
1424
0
            sn = (H5G_node_t *)H5AC_protect(f, H5AC_SNODE, addr, f, H5AC__READ_ONLY_FLAG);
1425
0
        }
1426
0
    H5E_RESUME_ERRORS
1427
0
    if (sn) {
1428
0
        unsigned u; /* Local index variable */
1429
1430
0
        fprintf(stream, "%*sSymbol Table Node...\n", indent, "");
1431
0
        fprintf(stream, "%*s%-*s %s\n", indent, "", fwidth, "Dirty:", sn->cache_info.is_dirty ? "Yes" : "No");
1432
0
        fprintf(stream, "%*s%-*s %u\n", indent, "", fwidth,
1433
0
                "Size of Node (in bytes):", (unsigned)sn->node_size);
1434
0
        fprintf(stream, "%*s%-*s %u of %u\n", indent, "", fwidth, "Number of Symbols:", sn->nsyms,
1435
0
                (unsigned)(2 * H5F_SYM_LEAF_K(f)));
1436
1437
0
        indent += 3;
1438
0
        fwidth = MAX(0, fwidth - 3);
1439
0
        for (u = 0; u < sn->nsyms; u++) {
1440
0
            fprintf(stream, "%*sSymbol %u:\n", indent - 3, "", u);
1441
1442
0
            if (heap) {
1443
0
                const char *s = (const char *)H5HL_offset_into(heap, sn->entry[u].name_off);
1444
1445
0
                if (s)
1446
0
                    fprintf(stream, "%*s%-*s `%s'\n", indent, "", fwidth, "Name:", s);
1447
0
            } /* end if */
1448
0
            else
1449
0
                fprintf(stream, "%*s%-*s\n", indent, "", fwidth,
1450
0
                        "Warning: Invalid heap address given, name not displayed!");
1451
1452
0
            H5G__ent_debug(sn->entry + u, stream, indent, fwidth, heap);
1453
0
        } /* end for */
1454
0
    }     /* end if */
1455
    /*
1456
     * If we couldn't load the symbol table node, then try loading the
1457
     * B-tree node.
1458
     */
1459
0
    else {
1460
0
        H5G_bt_common_t udata; /*data to pass through B-tree  */
1461
1462
0
        udata.heap       = heap;
1463
0
        udata.block_size = H5HL_heap_get_size(heap);
1464
0
        if (H5B_debug(f, addr, stream, indent, fwidth, H5B_SNODE, &udata) < 0)
1465
0
            HGOTO_ERROR(H5E_SYM, H5E_BADVALUE, FAIL, "unable to debug B-tree node");
1466
0
    } /* end else */
1467
1468
0
done:
1469
0
    if (sn && H5AC_unprotect(f, H5AC_SNODE, addr, sn, H5AC__NO_FLAGS_SET) < 0)
1470
0
        HDONE_ERROR(H5E_SYM, H5E_CANTUNPROTECT, FAIL, "unable to release symbol table node");
1471
0
    if (heap && H5HL_unprotect(heap) < 0)
1472
0
        HDONE_ERROR(H5E_SYM, H5E_CANTUNPROTECT, FAIL, "unable to unprotect symbol table heap");
1473
1474
0
    FUNC_LEAVE_NOAPI(ret_value)
1475
0
} /* end H5G_node_debug() */