/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Copyright by The HDF Group. * * All rights reserved. * * * * This file is part of HDF5. The full HDF5 copyright notice, including * * terms governing use, modification, and redistribution, is contained in * * the COPYING file, which can be found at the root of the source code * * distribution tree, or in https://www.hdfgroup.org/licenses. * * If you do not have access to either file, you may request a copy from * * help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /*------------------------------------------------------------------------- * * Created: H5Groot.c * * Purpose: Functions for operating on the root group. * *------------------------------------------------------------------------- */ /****************/ /* Module Setup */ /****************/ #define H5F_FRIEND /*suppress error about including H5Fpkg */ #include "H5Gmodule.h" /* This source code file is part of the H5G module */ /***********/ /* Headers */ /***********/ #include "H5private.h" /* Generic Functions */ #include "H5Eprivate.h" /* Error handling */ #include "H5Fpkg.h" /* File access */ #include "H5Gpkg.h" /* Groups */ #include "H5MMprivate.h" /* Memory management */ /****************/ /* Local Macros */ /****************/ /******************/ /* Local Typedefs */ /******************/ /********************/ /* Package Typedefs */ /********************/ /********************/ /* Local Prototypes */ /********************/ /*********************/ /* Package Variables */ /*********************/ /*****************************/ /* Library Private Variables */ /*****************************/ /*******************/ /* Local Variables */ /*******************/ /*------------------------------------------------------------------------- * Function: H5G_rootof * * Purpose: Return a pointer to the root group of the file. If the file * is part of a virtual file then the root group of the virtual * file is returned. * * Return: Success: Ptr to the root group of the file. Do not * free the pointer -- it points directly into * the file struct. * * Failure: NULL * *------------------------------------------------------------------------- */ H5G_t * H5G_rootof(H5F_t *f) { FUNC_ENTER_NOAPI_NOINIT_NOERR /* Sanity check */ assert(f); assert(f->shared); /* Walk to top of mounted files */ while (f->parent) f = f->parent; /* Sanity check */ assert(f); assert(f->shared); assert(f->shared->root_grp); /* Check to see if the root group was opened through a different * "top" file, and switch it to point at the current "top" file. */ if (f->shared->root_grp->oloc.file != f) f->shared->root_grp->oloc.file = f; FUNC_LEAVE_NOAPI(f->shared->root_grp) } /* end H5G_rootof() */ /*------------------------------------------------------------------------- * Function: H5G_mkroot * * Purpose: Creates a root group in an empty file and opens it. If a * root group is already open then this function immediately * returns. If ENT is non-null then it's the symbol table * entry for an existing group which will be opened as the root * group. Otherwise a new root group is created and then * opened. * * Return: Non-negative on success/Negative on failure * *------------------------------------------------------------------------- */ herr_t H5G_mkroot(H5F_t *f, bool create_root) { H5G_loc_t root_loc; /* Root location information */ H5G_obj_create_t gcrt_info; /* Root group object creation info */ htri_t stab_exists = -1; /* Whether the symbol table exists */ bool sblock_dirty = false; /* Whether superblock was dirtied */ bool path_init = false; /* Whether path was initialized */ herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_NOAPI(FAIL) /* check args */ assert(f); assert(f->shared); assert(f->shared->sblock); /* Check if the root group is already initialized */ if (f->shared->root_grp) HGOTO_DONE(SUCCEED); /* Create information needed for group nodes */ if (H5G__node_init(f) < 0) HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "unable to create group node info"); /* * Create the group pointer */ if (NULL == (f->shared->root_grp = H5FL_CALLOC(H5G_t))) HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed"); if (NULL == (f->shared->root_grp->shared = H5FL_CALLOC(H5G_shared_t))) { f->shared->root_grp = H5FL_FREE(H5G_t, f->shared->root_grp); HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed"); } /* end if */ /* Initialize the root_loc structure to point to fields in the newly created * f->shared->root_grp structure */ root_loc.oloc = &(f->shared->root_grp->oloc); root_loc.path = &(f->shared->root_grp->path); H5G_loc_reset(&root_loc); /* * If there is no root object then create one. The root group always starts * with a hard link count of one since it's pointed to by the superblock. */ if (create_root) { /* Create root group */ /* (Pass the FCPL which is a sub-class of the group creation property class) */ gcrt_info.gcpl_id = f->shared->fcpl_id; gcrt_info.cache_type = H5G_NOTHING_CACHED; if (H5G__obj_create(f, &gcrt_info, root_loc.oloc /*out*/) < 0) HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "unable to create group entry"); if (1 != H5O_link(root_loc.oloc, 1)) HGOTO_ERROR(H5E_SYM, H5E_LINKCOUNT, FAIL, "internal error (wrong link count)"); /* Decrement refcount on root group's object header in memory */ if (H5O_dec_rc_by_loc(root_loc.oloc) < 0) HGOTO_ERROR(H5E_SYM, H5E_CANTDEC, FAIL, "unable to decrement refcount on root group's object header"); /* Mark superblock dirty, so root group info is flushed */ sblock_dirty = true; /* Create the root group symbol table entry */ assert(!f->shared->sblock->root_ent); if (f->shared->sblock->super_vers < HDF5_SUPERBLOCK_VERSION_2) { /* Allocate space for the root group symbol table entry */ if (NULL == (f->shared->sblock->root_ent = (H5G_entry_t *)H5MM_calloc(sizeof(H5G_entry_t)))) HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "can't allocate space for symbol table entry"); /* Initialize the root group symbol table entry */ f->shared->sblock->root_ent->type = gcrt_info.cache_type; if (gcrt_info.cache_type != H5G_NOTHING_CACHED) f->shared->sblock->root_ent->cache = gcrt_info.cache; f->shared->sblock->root_ent->name_off = 0; /* No name (yet) */ f->shared->sblock->root_ent->header = root_loc.oloc->addr; } /* end if */ } /* end if */ else { /* Create root group object location from f */ root_loc.oloc->addr = f->shared->sblock->root_addr; root_loc.oloc->file = f; /* * Open the root object as a group. */ if (H5O_open(root_loc.oloc) < 0) HGOTO_ERROR(H5E_SYM, H5E_CANTOPENOBJ, FAIL, "unable to open root group"); /* Actions to take if the symbol table information is cached */ if (f->shared->sblock->root_ent && f->shared->sblock->root_ent->type == H5G_CACHED_STAB) { /* Check for the situation where the symbol table is cached but does * not exist. This can happen if, for example, an external link is * added to the root group. */ if ((stab_exists = H5O_msg_exists(root_loc.oloc, H5O_STAB_ID)) < 0) HGOTO_ERROR(H5E_SYM, H5E_CANTGET, FAIL, "can't check if symbol table message exists"); /* Remove the cache if the stab does not exist */ if (!stab_exists) f->shared->sblock->root_ent->type = H5G_NOTHING_CACHED; #ifndef H5_STRICT_FORMAT_CHECKS /* If symbol table information is cached, check if we should replace the * symbol table message with the cached symbol table information */ else if (H5F_INTENT(f) & H5F_ACC_RDWR) { H5O_stab_t cached_stab; /* Retrieve the cached symbol table information */ cached_stab.btree_addr = f->shared->sblock->root_ent->cache.stab.btree_addr; cached_stab.heap_addr = f->shared->sblock->root_ent->cache.stab.heap_addr; /* Check if the symbol table message is valid, and replace with the * cached symbol table if necessary */ if (H5G__stab_valid(root_loc.oloc, &cached_stab) < 0) HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "unable to verify symbol table"); } /* end if */ #endif /* H5_STRICT_FORMAT_CHECKS */ } /* end if */ } /* end else */ /* Cache the root group's symbol table information in the root group symbol * table entry. It will have been allocated by now if it needs to be * present, so we don't need to check the superblock version. We do this if * we have write access, the root entry has been allocated (i.e. * super_vers < 2) and the stab info is not already cached. */ if ((H5F_INTENT(f) & H5F_ACC_RDWR) && stab_exists != false && f->shared->sblock->root_ent && f->shared->sblock->root_ent->type != H5G_CACHED_STAB) { H5O_stab_t stab; /* Symbol table */ /* Check if the stab message exists. It's possible for the root group * to use the latest version while the superblock is an old version. * If stab_exists is not -1 then we have already checked. */ if (stab_exists == -1 && (stab_exists = H5O_msg_exists(root_loc.oloc, H5O_STAB_ID)) < 0) HGOTO_ERROR(H5E_SYM, H5E_CANTGET, FAIL, "can't check if symbol table message exists"); if (stab_exists) { /* Read the root group's symbol table message */ if (NULL == H5O_msg_read(root_loc.oloc, H5O_STAB_ID, &stab)) HGOTO_ERROR(H5E_SYM, H5E_BADMESG, FAIL, "unable to read symbol table message"); /* Update the root group symbol table entry */ f->shared->sblock->root_ent->type = H5G_CACHED_STAB; f->shared->sblock->root_ent->cache.stab.btree_addr = stab.btree_addr; f->shared->sblock->root_ent->cache.stab.heap_addr = stab.heap_addr; /* Mark superblock dirty, so root group info is flushed */ sblock_dirty = true; } /* end if */ } /* end if */ /* Create the path names for the root group's entry */ H5G__name_init(root_loc.path, "/"); path_init = true; f->shared->root_grp->shared->fo_count = 1; /* The only other open object should be the superblock extension, if it * exists. Don't count either the superblock extension or the root group * in the number of open objects in the file. */ assert((1 == f->nopen_objs) || (2 == f->nopen_objs && HADDR_UNDEF != f->shared->sblock->ext_addr)); f->nopen_objs--; done: /* In case of error, free various memory locations that may have been * allocated */ if (ret_value < 0) { if (f->shared->root_grp) { if (path_init) H5G_name_free(root_loc.path); if (f->shared->root_grp->shared) f->shared->root_grp->shared = H5FL_FREE(H5G_shared_t, f->shared->root_grp->shared); f->shared->root_grp = H5FL_FREE(H5G_t, f->shared->root_grp); } /* end if */ if (f->shared->sblock) f->shared->sblock->root_ent = (H5G_entry_t *)H5MM_xfree(f->shared->sblock->root_ent); } /* end if */ /* Mark superblock dirty in cache, if necessary */ if (sblock_dirty) if (H5AC_mark_entry_dirty(f->shared->sblock) < 0) HDONE_ERROR(H5E_FILE, H5E_CANTMARKDIRTY, FAIL, "unable to mark superblock as dirty"); FUNC_LEAVE_NOAPI(ret_value) } /* end H5G_mkroot() */ /*------------------------------------------------------------------------- * Function: H5G_root_free * * Purpose: Free memory used by an H5G_t struct (and its H5G_shared_t). * Does not close the group or decrement the reference count. * Used to free memory used by the root group. * * Return: Success: Non-negative * Failure: Negative * *------------------------------------------------------------------------- */ herr_t H5G_root_free(H5G_t *grp) { FUNC_ENTER_NOAPI_NOINIT_NOERR /* Check args */ assert(grp && grp->shared); assert(grp->shared->fo_count > 0); /* Free the path */ H5G_name_free(&(grp->path)); grp->shared = H5FL_FREE(H5G_shared_t, grp->shared); grp = H5FL_FREE(H5G_t, grp); FUNC_LEAVE_NOAPI(SUCCEED) } /* end H5G_root_free() */ /*------------------------------------------------------------------------- * Function: H5G_root_loc * * Purpose: Construct a "group location" for the root group of a file * * Return: Success: Non-negative * Failure: Negative * *------------------------------------------------------------------------- */ herr_t H5G_root_loc(H5F_t *f, H5G_loc_t *loc) { H5G_t *root_grp; /* Pointer to root group's info */ herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_NOAPI(FAIL) assert(f); assert(loc); /* Retrieve the root group for the file */ root_grp = H5G_rootof(f); assert(root_grp); /* Build the group location for the root group */ if (NULL == (loc->oloc = H5G_oloc(root_grp))) HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "unable to get object location for root group"); if (NULL == (loc->path = H5G_nameof(root_grp))) HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "unable to get path for root group"); /* Patch up root group's object location to reflect this file */ /* (Since the root group info is only stored once for files which * share an underlying low-level file) */ /* (but only for non-mounted files) */ if (!H5F_is_mount(f)) { loc->oloc->file = f; loc->oloc->holding_file = false; } /* end if */ done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5G_root_loc() */