Coverage Report

Created: 2025-12-08 06:52

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/hdf5/src/H5Groot.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:   H5Groot.c
16
 *
17
 * Purpose:   Functions for operating on the root group.
18
 *
19
 *-------------------------------------------------------------------------
20
 */
21
22
/****************/
23
/* Module Setup */
24
/****************/
25
26
#define H5F_FRIEND     /*suppress error about including H5Fpkg    */
27
#include "H5Gmodule.h" /* This source code file is part of the H5G module */
28
29
/***********/
30
/* Headers */
31
/***********/
32
#include "H5private.h"   /* Generic Functions     */
33
#include "H5Eprivate.h"  /* Error handling        */
34
#include "H5Fpkg.h"      /* File access       */
35
#include "H5FLprivate.h" /* Free Lists                               */
36
#include "H5Gpkg.h"      /* Groups          */
37
#include "H5MMprivate.h" /* Memory management     */
38
39
/****************/
40
/* Local Macros */
41
/****************/
42
43
/******************/
44
/* Local Typedefs */
45
/******************/
46
47
/********************/
48
/* Package Typedefs */
49
/********************/
50
51
/********************/
52
/* Local Prototypes */
53
/********************/
54
55
/*********************/
56
/* Package Variables */
57
/*********************/
58
59
/*****************************/
60
/* Library Private Variables */
61
/*****************************/
62
63
/*******************/
64
/* Local Variables */
65
/*******************/
66
67
/*-------------------------------------------------------------------------
68
 * Function:  H5G_rootof
69
 *
70
 * Purpose: Return a pointer to the root group of the file.  If the file
71
 *    is part of a virtual file then the root group of the virtual
72
 *    file is returned.
73
 *
74
 * Return:  Success:  Ptr to the root group of the file.  Do not
75
 *        free the pointer -- it points directly into
76
 *        the file struct.
77
 *
78
 *    Failure:  NULL
79
 *
80
 *-------------------------------------------------------------------------
81
 */
82
H5G_t *
83
H5G_rootof(H5F_t *f)
84
0
{
85
0
    FUNC_ENTER_NOAPI_NOINIT_NOERR
86
87
    /* Sanity check */
88
0
    assert(f);
89
0
    assert(f->shared);
90
91
    /* Walk to top of mounted files */
92
0
    while (f->parent)
93
0
        f = f->parent;
94
95
    /* Sanity check */
96
0
    assert(f);
97
0
    assert(f->shared);
98
0
    assert(f->shared->root_grp);
99
100
    /* Check to see if the root group was opened through a different
101
     * "top" file, and switch it to point at the current "top" file.
102
     */
103
0
    if (f->shared->root_grp->oloc.file != f)
104
0
        f->shared->root_grp->oloc.file = f;
105
106
0
    FUNC_LEAVE_NOAPI(f->shared->root_grp)
107
0
} /* end H5G_rootof() */
108
109
/*-------------------------------------------------------------------------
110
 * Function:  H5G_mkroot
111
 *
112
 * Purpose: Creates a root group in an empty file and opens it.  If a
113
 *    root group is already open then this function immediately
114
 *    returns.   If ENT is non-null then it's the symbol table
115
 *    entry for an existing group which will be opened as the root
116
 *    group.  Otherwise a new root group is created and then
117
 *    opened.
118
 *
119
 * Return:  Non-negative on success/Negative on failure
120
 *
121
 *-------------------------------------------------------------------------
122
 */
123
herr_t
124
H5G_mkroot(H5F_t *f, bool create_root)
125
205
{
126
205
    H5G_loc_t        root_loc;               /* Root location information */
127
205
    H5G_obj_create_t gcrt_info;              /* Root group object creation info */
128
205
    htri_t           stab_exists  = -1;      /* Whether the symbol table exists */
129
205
    bool             sblock_dirty = false;   /* Whether superblock was dirtied */
130
205
    bool             path_init    = false;   /* Whether path was initialized */
131
205
    herr_t           ret_value    = SUCCEED; /* Return value */
132
133
205
    FUNC_ENTER_NOAPI(FAIL)
134
135
    /* check args */
136
205
    assert(f);
137
205
    assert(f->shared);
138
205
    assert(f->shared->sblock);
139
140
    /* Check if the root group is already initialized */
141
205
    if (f->shared->root_grp)
142
0
        HGOTO_DONE(SUCCEED);
143
144
    /* Create information needed for group nodes */
145
205
    if (H5G__node_init(f) < 0)
146
0
        HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "unable to create group node info");
147
148
    /*
149
     * Create the group pointer
150
     */
151
205
    if (NULL == (f->shared->root_grp = H5FL_CALLOC(H5G_t)))
152
0
        HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed");
153
205
    if (NULL == (f->shared->root_grp->shared = H5FL_CALLOC(H5G_shared_t))) {
154
0
        f->shared->root_grp = H5FL_FREE(H5G_t, f->shared->root_grp);
155
0
        HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed");
156
0
    } /* end if */
157
158
    /* Initialize the root_loc structure to point to fields in the newly created
159
     * f->shared->root_grp structure */
160
205
    root_loc.oloc = &(f->shared->root_grp->oloc);
161
205
    root_loc.path = &(f->shared->root_grp->path);
162
205
    H5G_loc_reset(&root_loc);
163
164
    /*
165
     * If there is no root object then create one. The root group always starts
166
     * with a hard link count of one since it's pointed to by the superblock.
167
     */
168
205
    if (create_root) {
169
        /* Create root group */
170
        /* (Pass the FCPL which is a sub-class of the group creation property class) */
171
0
        gcrt_info.gcpl_id    = f->shared->fcpl_id;
172
0
        gcrt_info.cache_type = H5G_NOTHING_CACHED;
173
0
        if (H5G__obj_create(f, &gcrt_info, root_loc.oloc /*out*/) < 0)
174
0
            HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "unable to create group entry");
175
0
        if (1 != H5O_link(root_loc.oloc, 1))
176
0
            HGOTO_ERROR(H5E_SYM, H5E_LINKCOUNT, FAIL, "internal error (wrong link count)");
177
178
        /* Decrement refcount on root group's object header in memory */
179
0
        if (H5O_dec_rc_by_loc(root_loc.oloc) < 0)
180
0
            HGOTO_ERROR(H5E_SYM, H5E_CANTDEC, FAIL,
181
0
                        "unable to decrement refcount on root group's object header");
182
183
        /* Mark superblock dirty, so root group info is flushed */
184
0
        sblock_dirty = true;
185
186
        /* Create the root group symbol table entry */
187
0
        assert(!f->shared->sblock->root_ent);
188
0
        if (f->shared->sblock->super_vers < HDF5_SUPERBLOCK_VERSION_2) {
189
            /* Allocate space for the root group symbol table entry */
190
0
            if (NULL == (f->shared->sblock->root_ent = (H5G_entry_t *)H5MM_calloc(sizeof(H5G_entry_t))))
191
0
                HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "can't allocate space for symbol table entry");
192
193
            /* Initialize the root group symbol table entry */
194
0
            f->shared->sblock->root_ent->type = gcrt_info.cache_type;
195
0
            if (gcrt_info.cache_type != H5G_NOTHING_CACHED)
196
0
                f->shared->sblock->root_ent->cache = gcrt_info.cache;
197
0
            f->shared->sblock->root_ent->name_off = 0; /* No name (yet) */
198
0
            f->shared->sblock->root_ent->header   = root_loc.oloc->addr;
199
0
        } /* end if */
200
0
    }     /* end if */
201
205
    else {
202
        /* Create root group object location from f */
203
205
        root_loc.oloc->addr = f->shared->sblock->root_addr;
204
205
        root_loc.oloc->file = f;
205
206
        /*
207
         * Open the root object as a group.
208
         */
209
205
        if (H5O_open(root_loc.oloc) < 0)
210
0
            HGOTO_ERROR(H5E_SYM, H5E_CANTOPENOBJ, FAIL, "unable to open root group");
211
212
        /* Actions to take if the symbol table information is cached */
213
205
        if (f->shared->sblock->root_ent && f->shared->sblock->root_ent->type == H5G_CACHED_STAB) {
214
            /* Check for the situation where the symbol table is cached but does
215
             * not exist.  This can happen if, for example, an external link is
216
             * added to the root group. */
217
136
            if ((stab_exists = H5O_msg_exists(root_loc.oloc, H5O_STAB_ID)) < 0)
218
69
                HGOTO_ERROR(H5E_SYM, H5E_CANTGET, FAIL, "can't check if symbol table message exists");
219
220
            /* Remove the cache if the stab does not exist */
221
67
            if (!stab_exists)
222
24
                f->shared->sblock->root_ent->type = H5G_NOTHING_CACHED;
223
43
#ifndef H5_STRICT_FORMAT_CHECKS
224
            /* If symbol table information is cached, check if we should replace the
225
             * symbol table message with the cached symbol table information */
226
43
            else if (H5F_INTENT(f) & H5F_ACC_RDWR) {
227
43
                H5O_stab_t cached_stab;
228
229
                /* Retrieve the cached symbol table information */
230
43
                cached_stab.btree_addr = f->shared->sblock->root_ent->cache.stab.btree_addr;
231
43
                cached_stab.heap_addr  = f->shared->sblock->root_ent->cache.stab.heap_addr;
232
233
                /* Check if the symbol table message is valid, and replace with the
234
                 * cached symbol table if necessary */
235
43
                if (H5G__stab_valid(root_loc.oloc, &cached_stab) < 0)
236
13
                    HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "unable to verify symbol table");
237
43
            } /* end if */
238
67
#endif        /* H5_STRICT_FORMAT_CHECKS */
239
67
        }     /* end if */
240
205
    }         /* end else */
241
242
    /* Cache the root group's symbol table information in the root group symbol
243
     * table entry.  It will have been allocated by now if it needs to be
244
     * present, so we don't need to check the superblock version.  We do this if
245
     * we have write access, the root entry has been allocated (i.e.
246
     * super_vers < 2) and the stab info is not already cached. */
247
123
    if ((H5F_INTENT(f) & H5F_ACC_RDWR) && stab_exists != false && f->shared->sblock->root_ent &&
248
99
        f->shared->sblock->root_ent->type != H5G_CACHED_STAB) {
249
69
        H5O_stab_t stab; /* Symbol table */
250
251
        /* Check if the stab message exists.  It's possible for the root group
252
         * to use the latest version while the superblock is an old version.
253
         * If stab_exists is not -1 then we have already checked. */
254
69
        if (stab_exists == -1 && (stab_exists = H5O_msg_exists(root_loc.oloc, H5O_STAB_ID)) < 0)
255
58
            HGOTO_ERROR(H5E_SYM, H5E_CANTGET, FAIL, "can't check if symbol table message exists");
256
257
11
        if (stab_exists) {
258
            /* Read the root group's symbol table message */
259
0
            if (NULL == H5O_msg_read(root_loc.oloc, H5O_STAB_ID, &stab))
260
0
                HGOTO_ERROR(H5E_SYM, H5E_BADMESG, FAIL, "unable to read symbol table message");
261
262
            /* Update the root group symbol table entry */
263
0
            f->shared->sblock->root_ent->type                  = H5G_CACHED_STAB;
264
0
            f->shared->sblock->root_ent->cache.stab.btree_addr = stab.btree_addr;
265
0
            f->shared->sblock->root_ent->cache.stab.heap_addr  = stab.heap_addr;
266
267
            /* Mark superblock dirty, so root group info is flushed */
268
0
            sblock_dirty = true;
269
0
        } /* end if */
270
11
    }     /* end if */
271
272
    /* Create the path names for the root group's entry */
273
65
    H5G__name_init(root_loc.path, "/");
274
65
    path_init = true;
275
276
65
    f->shared->root_grp->shared->fo_count = 1;
277
    /* The only other open object should be the superblock extension, if it
278
     * exists.  Don't count either the superblock extension or the root group
279
     * in the number of open objects in the file.
280
     */
281
65
    assert((1 == f->nopen_objs) || (2 == f->nopen_objs && HADDR_UNDEF != f->shared->sblock->ext_addr));
282
65
    f->nopen_objs--;
283
284
205
done:
285
    /* In case of error, free various memory locations that may have been
286
     * allocated */
287
205
    if (ret_value < 0) {
288
140
        if (f->shared->root_grp) {
289
140
            if (path_init)
290
0
                H5G_name_free(root_loc.path);
291
140
            if (f->shared->root_grp->shared)
292
140
                f->shared->root_grp->shared = H5FL_FREE(H5G_shared_t, f->shared->root_grp->shared);
293
140
            f->shared->root_grp = H5FL_FREE(H5G_t, f->shared->root_grp);
294
140
        } /* end if */
295
140
        if (f->shared->sblock)
296
140
            f->shared->sblock->root_ent = (H5G_entry_t *)H5MM_xfree(f->shared->sblock->root_ent);
297
140
    } /* end if */
298
299
    /* Mark superblock dirty in cache, if necessary */
300
205
    if (sblock_dirty)
301
0
        if (H5AC_mark_entry_dirty(f->shared->sblock) < 0)
302
0
            HDONE_ERROR(H5E_FILE, H5E_CANTMARKDIRTY, FAIL, "unable to mark superblock as dirty");
303
304
205
    FUNC_LEAVE_NOAPI(ret_value)
305
205
} /* end H5G_mkroot() */
306
307
/*-------------------------------------------------------------------------
308
 * Function:    H5G_root_free
309
 *
310
 * Purpose: Free memory used by an H5G_t struct (and its H5G_shared_t).
311
 *    Does not close the group or decrement the reference count.
312
 *    Used to free memory used by the root group.
313
 *
314
 * Return:  Success:    Non-negative
315
 *    Failure:    Negative
316
 *
317
 *-------------------------------------------------------------------------
318
 */
319
herr_t
320
H5G_root_free(H5G_t *grp)
321
65
{
322
65
    FUNC_ENTER_NOAPI_NOINIT_NOERR
323
324
    /* Check args */
325
65
    assert(grp && grp->shared);
326
65
    assert(grp->shared->fo_count > 0);
327
328
    /* Free the path */
329
65
    H5G_name_free(&(grp->path));
330
331
65
    grp->shared = H5FL_FREE(H5G_shared_t, grp->shared);
332
65
    grp         = H5FL_FREE(H5G_t, grp);
333
334
65
    FUNC_LEAVE_NOAPI(SUCCEED)
335
65
} /* end H5G_root_free() */
336
337
/*-------------------------------------------------------------------------
338
 * Function:  H5G_root_loc
339
 *
340
 * Purpose: Construct a "group location" for the root group of a file
341
 *
342
 * Return:  Success:  Non-negative
343
 *    Failure:  Negative
344
 *
345
 *-------------------------------------------------------------------------
346
 */
347
herr_t
348
H5G_root_loc(H5F_t *f, H5G_loc_t *loc)
349
0
{
350
0
    H5G_t *root_grp;            /* Pointer to root group's info */
351
0
    herr_t ret_value = SUCCEED; /* Return value */
352
353
0
    FUNC_ENTER_NOAPI(FAIL)
354
355
0
    assert(f);
356
0
    assert(loc);
357
358
    /* Retrieve the root group for the file */
359
0
    root_grp = H5G_rootof(f);
360
0
    assert(root_grp);
361
362
    /* Build the group location for the root group */
363
0
    if (NULL == (loc->oloc = H5G_oloc(root_grp)))
364
0
        HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "unable to get object location for root group");
365
0
    if (NULL == (loc->path = H5G_nameof(root_grp)))
366
0
        HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "unable to get path for root group");
367
368
    /* Patch up root group's object location to reflect this file */
369
    /* (Since the root group info is only stored once for files which
370
     *  share an underlying low-level file)
371
     */
372
    /* (but only for non-mounted files) */
373
0
    if (!H5F_is_mount(f)) {
374
0
        loc->oloc->file         = f;
375
0
        loc->oloc->holding_file = false;
376
0
    } /* end if */
377
378
0
done:
379
0
    FUNC_LEAVE_NOAPI(ret_value)
380
0
} /* end H5G_root_loc() */