text: /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
   * Copyright by The HDF Group.                                               *
   * Copyright by the Board of Trustees of the University of Illinois.         *
   * 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://support.hdfgroup.org/ftp/HDF5/releases.  *
   * If you do not have access to either file, you may request a copy from     *
   * help@hdfgroup.org.                                                        *
   * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  
  /*-------------------------------------------------------------------------
   *
   * Created:		H5Groot.c
   *			Apr  8 2009
   *			Neil Fortner <nfortne2@hdfgroup.org>
   *
   * Purpose:		Functions for operating on the root group.
   *
   *-------------------------------------------------------------------------
   */
  
  /****************/
  /* Module Setup */
  /****************/
  
  #define H5F_PACKAGE		/*suppress error about including H5Fpkg	  */
  #define H5G_PACKAGE		/*suppress error about including H5Gpkg  */
  
  
  /***********/
  /* Headers */
  /***********/
  #include "H5private.h"		/* Generic Functions			*/
  #include "H5Eprivate.h"		/* Error handling		  	*/
  #include "H5Fpkg.h"		/* File access				*/
  #include "H5Gpkg.h"		/* Groups		  		*/
  #include "H5Iprivate.h"		/* IDs			  		*/
  #include "H5MMprivate.h"	/* Memory management			*/
  #include "H5Pprivate.h"         /* Property Lists			*/
  
  
  /****************/
  /* 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
   *
   * Programmer:	Robb Matzke
   *              Tuesday, October 13, 1998
   *
   *-------------------------------------------------------------------------
   */
  H5G_t *
  H5G_rootof(H5F_t *f)
  {
      FUNC_ENTER_NOAPI_NOINIT_NOERR
  
      /* Sanity check */
      HDassert(f);
      HDassert(f->shared);
  
      /* Walk to top of mounted files */
      while(f->parent)
          f = f->parent;
  
      /* Sanity check */
      HDassert(f);
      HDassert(f->shared);
      HDassert(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
   *
   * Programmer:	Robb Matzke
   *		matzke@llnl.gov
   *		Aug 11 1997
   *
   *-------------------------------------------------------------------------
   */
  herr_t
  H5G_mkroot(H5F_t *f, hid_t dxpl_id, hbool_t 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 */
      hbool_t     sblock_dirty = FALSE;   /* Whether superblock was dirtied */
      hbool_t     path_init = FALSE;      /* Whether path was initialized */
      herr_t      ret_value = SUCCEED;    /* Return value */
  
      FUNC_ENTER_NOAPI(FAIL)
  
      /* check args */
      HDassert(f);
      HDassert(f->shared);
      HDassert(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, dxpl_id, &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, dxpl_id))
  	    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, dxpl_id) < 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 */
          HDassert(!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, dxpl_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, dxpl_id, &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, dxpl_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, dxpl_id))
                  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.
       */
      HDassert((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
  *
  * Programmer:	James Laird
  *		Tuesday, September 7, 2004
  *
  *-------------------------------------------------------------------------
  */
  herr_t
  H5G_root_free(H5G_t *grp)
  {
      FUNC_ENTER_NOAPI_NOINIT_NOERR
  
      /* Check args */
      HDassert(grp && grp->shared);
      HDassert(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
   *
   * Programmer:	Quincey Koziol
   *		koziol@hdfgroup.org
   *		Mar  5 2007
   *
   *-------------------------------------------------------------------------
   */
  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)
  
      HDassert(f);
      HDassert(loc);
  
      /* Retrieve the root group for the file */
      root_grp = H5G_rootof(f);
      HDassert(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() */
  
  