text: /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
   * 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://support.hdfgroup.org/ftp/HDF5/releases.  *
   * If you do not have access to either file, you may request a copy from     *
   * help@hdfgroup.org.                                                        *
   * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  
  /*
   * Purpose:     The Virtual Object Layer as described in documentation.
   *              The pupose is to provide an abstraction on how to access the
   *              underlying HDF5 container, whether in a local file with
   *              a specific file format, or remotely on other machines, etc...
   */
  
  /****************/
  /* Module Setup */
  /****************/
  
  #include "H5VLmodule.h" /* This source code file is part of the H5VL module */
  
  /***********/
  /* Headers */
  /***********/
  
  #include "H5private.h"   /* Generic Functions                    */
  #include "H5Aprivate.h"  /* Attributes                           */
  #include "H5CXprivate.h" /* API Contexts                         */
  #include "H5Dprivate.h"  /* Datasets                             */
  #include "H5Eprivate.h"  /* Error handling                       */
  #include "H5Fprivate.h"  /* Files                                */
  #include "H5FLprivate.h" /* Free lists                           */
  #include "H5Gprivate.h"  /* Groups                               */
  #include "H5Iprivate.h"  /* IDs                                  */
  #include "H5Mprivate.h"  /* Maps                                 */
  #include "H5MMprivate.h" /* Memory management                    */
  #include "H5PLprivate.h" /* Plugins                              */
  #include "H5Tprivate.h"  /* Datatypes                            */
  #include "H5VLpkg.h"     /* Virtual Object Layer                 */
  
  /* VOL connectors */
  #include "H5VLnative.h"   /* Native VOL connector                 */
  #include "H5VLpassthru.h" /* Pass-through VOL connector           */
  
  /****************/
  /* Local Macros */
  /****************/
  
  /******************/
  /* Local Typedefs */
  /******************/
  
  /* Object wrapping context info */
  typedef struct H5VL_wrap_ctx_t {
      unsigned rc;           /* Ref. count for the # of times the context was set / reset */
      H5VL_t * connector;    /* VOL connector for "outermost" class to start wrap */
      void *   obj_wrap_ctx; /* "wrap context" for outermost connector */
  } H5VL_wrap_ctx_t;
  
  /* Information needed for iterating over the registered VOL connector hid_t IDs.
   * The name or value of the new VOL connector that is being registered is
   * stored in the name (or value) field and the found_id field is initialized to
   * H5I_INVALID_HID (-1).  If we find a VOL connector with the same name / value,
   * we set the found_id field to the existing ID for return to the function.
   */
  typedef struct {
      /* IN */
      H5VL_get_connector_kind_t kind; /* Which kind of connector search to make */
      union {
          const char *       name;  /* The name of the VOL connector to check */
          H5VL_class_value_t value; /* The value of the VOL connector to check */
      } u;
  
      /* OUT */
      hid_t found_id; /* The connector ID, if we found a match */
  } H5VL_get_connector_ud_t;
  
  /********************/
  /* Package Typedefs */
  /********************/
  
  /********************/
  /* Local Prototypes */
  /********************/
  static herr_t         H5VL__free_cls(H5VL_class_t *cls, void **request);
  static int            H5VL__get_connector_cb(void *obj, hid_t id, void *_op_data);
  static herr_t         H5VL__set_def_conn(void);
  static void *         H5VL__wrap_obj(void *obj, H5I_type_t obj_type);
  static H5VL_object_t *H5VL__new_vol_obj(H5I_type_t type, void *object, H5VL_t *vol_connector,
                                          hbool_t wrap_obj);
  static void *         H5VL__object(hid_t id, H5I_type_t obj_type);
  static herr_t         H5VL__free_vol_wrapper(H5VL_wrap_ctx_t *vol_wrap_ctx);
  
  /*********************/
  /* Package Variables */
  /*********************/
  
  /* Package initialization variable */
  hbool_t H5_PKG_INIT_VAR = FALSE;
  
  /*****************************/
  /* Library Private Variables */
  /*****************************/
  
  /*******************/
  /* Local Variables */
  /*******************/
  
  /* VOL ID class */
  static const H5I_class_t H5I_VOL_CLS[1] = {{
      H5I_VOL,                   /* ID class value */
      0,                         /* Class flags */
      0,                         /* # of reserved IDs for class */
      (H5I_free_t)H5VL__free_cls /* Callback routine for closing objects of this class */
  }};
  
  /* Declare a free list to manage the H5VL_class_t struct */
  H5FL_DEFINE_STATIC(H5VL_class_t);
  
  /* Declare a free list to manage the H5VL_t struct */
  H5FL_DEFINE(H5VL_t);
  
  /* Declare a free list to manage the H5VL_object_t struct */
  H5FL_DEFINE(H5VL_object_t);
  
  /* Declare a free list to manage the H5VL_wrap_ctx_t struct */
  H5FL_DEFINE_STATIC(H5VL_wrap_ctx_t);
  
  /* Default VOL connector */
  static H5VL_connector_prop_t H5VL_def_conn_s = {-1, NULL};
  
  /*-------------------------------------------------------------------------
   * Function:    H5VL_init_phase1
   *
   * Purpose:     Initialize the interface from some other package.  This should
   *		be followed with a call to H5VL_init_phase2 after the H5P
   *		interface is completely set up, finish setting up the H5VL
   *		information.
   *
   *
   * Return:      Success:    Non-negative
   *              Failure:    Negative
   *
   *-------------------------------------------------------------------------
   */
  herr_t
  H5VL_init_phase1(void)
  {
      herr_t ret_value = SUCCEED; /* Return value */
  
      FUNC_ENTER_NOAPI(FAIL)
  
      /* FUNC_ENTER() does all the work */
  
  done:
      FUNC_LEAVE_NOAPI(ret_value)
  } /* end H5VL_init_phase1() */
  
  /*-------------------------------------------------------------------------
   * Function:    H5VL_init_phase2
   *
   * Purpose:     Finish initializing the interface from some other package.
   *
   * Note:	This is broken out as a separate routine to avoid a circular
   *		reference with the H5P package.
   *
   * Return:      Success:    Non-negative
   *              Failure:    Negative
   *
   *-------------------------------------------------------------------------
   */
  herr_t
  H5VL_init_phase2(void)
  {
      herr_t ret_value = SUCCEED; /* Return value */
  
      FUNC_ENTER_NOAPI(FAIL)
  
      /* Initialize all packages for VOL-managed objects */
      if (H5T_init() < 0)
          HGOTO_ERROR(H5E_VOL, H5E_CANTINIT, FAIL, "unable to initialize datatype interface")
      if (H5D_init() < 0)
          HGOTO_ERROR(H5E_VOL, H5E_CANTINIT, FAIL, "unable to initialize dataset interface")
      if (H5F_init() < 0)
          HGOTO_ERROR(H5E_VOL, H5E_CANTINIT, FAIL, "unable to initialize file interface")
      if (H5G_init() < 0)
          HGOTO_ERROR(H5E_VOL, H5E_CANTINIT, FAIL, "unable to initialize group interface")
      if (H5A_init() < 0)
          HGOTO_ERROR(H5E_VOL, H5E_CANTINIT, FAIL, "unable to initialize attribute interface")
      if (H5M_init() < 0)
          HGOTO_ERROR(H5E_VOL, H5E_CANTINIT, FAIL, "unable to initialize map interface")
  
      /* Set up the default VOL connector in the default FAPL */
      if (H5VL__set_def_conn() < 0)
          HGOTO_ERROR(H5E_VOL, H5E_CANTSET, FAIL, "unable to set default VOL connector")
  
  done:
      FUNC_LEAVE_NOAPI(ret_value)
  } /* end H5VL_init_phase2() */
  
  /*-------------------------------------------------------------------------
   * Function:	H5VL__init_package
   *
   * Purpose:     Initialize interface-specific information
   *
   * Return:      Success:    Non-negative
   *
   *              Failure:    Negative
   *
   *-------------------------------------------------------------------------
   */
  herr_t
  H5VL__init_package(void)
  {
      herr_t ret_value = SUCCEED; /* Return value */
  
      FUNC_ENTER_PACKAGE
  
      /* Initialize the ID group for the VL IDs */
      if (H5I_register_type(H5I_VOL_CLS) < 0)
          HGOTO_ERROR(H5E_VOL, H5E_CANTINIT, FAIL, "unable to initialize H5VL interface")
  
  done:
      FUNC_LEAVE_NOAPI(ret_value)
  } /* end H5VL__init_package() */
  
  /*-------------------------------------------------------------------------
   * Function:	H5VL_term_package
   *
   * Purpose:     Terminate various H5VL objects
   *
   * Return:      Success:    Positive if anything was done that might
   *                          affect other interfaces; zero otherwise.
   *              Failure:    Negative
   *
   *-------------------------------------------------------------------------
   */
  int
  H5VL_term_package(void)
  {
      int n = 0;
  
      FUNC_ENTER_NOAPI_NOINIT_NOERR
  
      if (H5_PKG_INIT_VAR) {
          if (H5VL_def_conn_s.connector_id > 0) {
              /* Release the default VOL connector */
              (void)H5VL_conn_free(&H5VL_def_conn_s);
              H5VL_def_conn_s.connector_id   = -1;
              H5VL_def_conn_s.connector_info = NULL;
              n++;
          } /* end if */
          else {
              if (H5I_nmembers(H5I_VOL) > 0) {
                  /* Unregister all VOL connectors */
                  (void)H5I_clear_type(H5I_VOL, TRUE, FALSE);
                  n++;
              } /* end if */
              else {
                  /* Destroy the VOL connector ID group */
                  n += (H5I_dec_type_ref(H5I_VOL) > 0);
  
                  /* Mark interface as closed */
                  if (0 == n)
                      H5_PKG_INIT_VAR = FALSE;
              } /* end else */
          }     /* end else */
      }         /* end if */
  
      FUNC_LEAVE_NOAPI(n)
  } /* end H5VL_term_package() */
  
  /*-------------------------------------------------------------------------
   * Function:    H5VL__free_cls
   *
   * Purpose:     Frees a file VOL class struct and returns an indication of
   *              success. This function is used as the free callback for the
   *              virtual object layer object identifiers
   *              (c.f.: H5VL_init_interface).
   *
   * Return:      SUCCEED/FAIL
   *
   *-------------------------------------------------------------------------
   */
  static herr_t
  H5VL__free_cls(H5VL_class_t *cls, void H5_ATTR_UNUSED **request)
  {
      herr_t ret_value = SUCCEED;
  
      FUNC_ENTER_STATIC
  
      /* Sanity check */
      HDassert(cls);
  
      /* Shut down the VOL connector */
      if (cls->terminate && cls->terminate() < 0)
          HGOTO_ERROR(H5E_VOL, H5E_CANTCLOSEOBJ, FAIL, "VOL connector did not terminate cleanly")
  
      /* Release the class */
      H5MM_xfree_const(cls->name);
      H5FL_FREE(H5VL_class_t, cls);
  
  done:
      FUNC_LEAVE_NOAPI(ret_value)
  } /* end H5VL__free_cls() */
  
  /*-------------------------------------------------------------------------
   * Function:    H5VL__get_connector_cb
   *
   * Purpose:     Callback routine to search through registered VOLs
   *
   * Return:      Success:    H5_ITER_STOP if the class and op_data name
   *                          members match. H5_ITER_CONT otherwise.
   *              Failure:    Can't fail
   *
   * Programmer:  Dana Robinson
   *              June 22, 2017
   *
   *-------------------------------------------------------------------------
   */
  static int
  H5VL__get_connector_cb(void *obj, hid_t id, void *_op_data)
  {
      H5VL_get_connector_ud_t *op_data   = (H5VL_get_connector_ud_t *)_op_data; /* User data for callback */
      H5VL_class_t *           cls       = (H5VL_class_t *)obj;
      int                      ret_value = H5_ITER_CONT; /* Callback return value */
  
      FUNC_ENTER_STATIC_NOERR
  
      if (H5VL_GET_CONNECTOR_BY_NAME == op_data->kind) {
          if (0 == HDstrcmp(cls->name, op_data->u.name)) {
              op_data->found_id = id;
              ret_value         = H5_ITER_STOP;
          } /* end if */
      }     /* end if */
      else {
          HDassert(H5VL_GET_CONNECTOR_BY_VALUE == op_data->kind);
          if (cls->value == op_data->u.value) {
              op_data->found_id = id;
              ret_value         = H5_ITER_STOP;
          } /* end if */
      }     /* end else */
  
      FUNC_LEAVE_NOAPI(ret_value)
  } /* end H5VL__get_connector_cb() */
  
  /*-------------------------------------------------------------------------
   * Function:    H5VL__set_def_conn
   *
   * Purpose:     Parses a string that contains the default VOL connector for
   *              the library.
   *
   * Note:	Usually from the environment variable "HDF5_VOL_CONNECTOR",
   *		but could be from elsewhere.
   *
   * Return:      Success:    0
   *              Failure:    -1
   *
   * Programmer:  Jordan Henderson
   *              November 2018
   *
   *-------------------------------------------------------------------------
   */
  static herr_t
  H5VL__set_def_conn(void)
  {
      H5P_genplist_t *def_fapl;               /* Default file access property list */
      H5P_genclass_t *def_fapclass;           /* Default file access property class */
      const char *    env_var;                /* Environment variable for default VOL connector */
      char *          buf          = NULL;    /* Buffer for tokenizing string */
      hid_t           connector_id = -1;      /* VOL conntector ID */
      void *          vol_info     = NULL;    /* VOL connector info */
      herr_t          ret_value    = SUCCEED; /* Return value */
  
      FUNC_ENTER_STATIC
  
      /* Sanity check */
      HDassert(H5VL_def_conn_s.connector_id == (-1));
      HDassert(H5VL_def_conn_s.connector_info == NULL);
  
      /* Check for environment variable set */
      env_var = HDgetenv("HDF5_VOL_CONNECTOR");
  
      /* Only parse the string if it's set */
      if (env_var && *env_var) {
          char *      lasts = NULL;            /* Context pointer for strtok_r() call */
          const char *tok   = NULL;            /* Token from strtok_r call */
          htri_t      connector_is_registered; /* Whether connector is already registered */
  
          /* Duplicate the string to parse, as it is modified as we go */
          if (NULL == (buf = H5MM_strdup(env_var)))
              HGOTO_ERROR(H5E_VOL, H5E_CANTALLOC, FAIL, "can't allocate memory for environment variable string")
  
          /* Get the first 'word' of the environment variable.
           * If it's nothing (environment variable was whitespace) return error.
           */
          if (NULL == (tok = HDstrtok_r(buf, " \t\n\r", &lasts)))
              HGOTO_ERROR(H5E_VOL, H5E_BADVALUE, FAIL, "VOL connector environment variable set empty?")
  
          /* First, check to see if the connector is already registered */
          if ((connector_is_registered = H5VL__is_connector_registered_by_name(tok)) < 0)
              HGOTO_ERROR(H5E_VOL, H5E_CANTGET, FAIL, "can't check if VOL connector already registered")
          else if (connector_is_registered) {
              /* Retrieve the ID of the already-registered VOL connector */
              if ((connector_id = H5VL__get_connector_id_by_name(tok, FALSE)) < 0)
                  HGOTO_ERROR(H5E_VOL, H5E_CANTGET, FAIL, "can't get VOL connector ID")
          } /* end else-if */
          else {
              /* Check for VOL connectors that ship with the library */
              if (!HDstrcmp(tok, "native")) {
                  connector_id = H5VL_NATIVE;
                  if (H5I_inc_ref(connector_id, FALSE) < 0)
                      HGOTO_ERROR(H5E_VOL, H5E_CANTINC, FAIL, "can't increment VOL connector refcount")
              } /* end if */
              else if (!HDstrcmp(tok, "pass_through")) {
                  connector_id = H5VL_PASSTHRU;
                  if (H5I_inc_ref(connector_id, FALSE) < 0)
                      HGOTO_ERROR(H5E_VOL, H5E_CANTINC, FAIL, "can't increment VOL connector refcount")
              } /* end else-if */
              else {
                  /* Register the VOL connector */
                  /* (NOTE: No provisions for vipl_id currently) */
                  if ((connector_id = H5VL__register_connector_by_name(tok, TRUE, H5P_VOL_INITIALIZE_DEFAULT)) <
                      0)
                      HGOTO_ERROR(H5E_VOL, H5E_CANTREGISTER, FAIL, "can't register connector")
              } /* end else */
          }     /* end else */
  
          /* Was there any connector info specified in the environment variable? */
          if (NULL != (tok = HDstrtok_r(NULL, " \t\n\r", &lasts)))
              if (H5VL__connector_str_to_info(tok, connector_id, &vol_info) < 0)
                  HGOTO_ERROR(H5E_VOL, H5E_CANTDECODE, FAIL, "can't deserialize connector info")
  
          /* Set the default VOL connector */
          H5VL_def_conn_s.connector_id   = connector_id;
          H5VL_def_conn_s.connector_info = vol_info;
      } /* end if */
      else {
          /* Set the default VOL connector */
          H5VL_def_conn_s.connector_id   = H5_DEFAULT_VOL;
          H5VL_def_conn_s.connector_info = NULL;
  
          /* Increment the ref count on the default connector */
          if (H5I_inc_ref(H5VL_def_conn_s.connector_id, FALSE) < 0)
              HGOTO_ERROR(H5E_VOL, H5E_CANTINC, FAIL, "can't increment VOL connector refcount")
      } /* end else */
  
      /* Get default file access pclass */
      if (NULL == (def_fapclass = (H5P_genclass_t *)H5I_object(H5P_FILE_ACCESS)))
          HGOTO_ERROR(H5E_VOL, H5E_BADID, FAIL, "can't find object for default file access property class ID")
  
      /* Change the default VOL for the default file access pclass */
      if (H5P_reset_vol_class(def_fapclass, &H5VL_def_conn_s) < 0)
          HGOTO_ERROR(H5E_VOL, H5E_CANTSET, FAIL,
                      "can't set default VOL connector for default file access property class")
  
      /* Get default file access plist */
      if (NULL == (def_fapl = (H5P_genplist_t *)H5I_object(H5P_FILE_ACCESS_DEFAULT)))
          HGOTO_ERROR(H5E_VOL, H5E_BADID, FAIL, "can't find object for default fapl ID")
  
      /* Change the default VOL for the default FAPL */
      if (H5P_set_vol(def_fapl, H5VL_def_conn_s.connector_id, H5VL_def_conn_s.connector_info) < 0)
          HGOTO_ERROR(H5E_VOL, H5E_CANTSET, FAIL, "can't set default VOL connector for default FAPL")
  
  done:
      /* Clean up on error */
      if (ret_value < 0) {
          if (vol_info)
              if (H5VL_free_connector_info(connector_id, vol_info) < 0)
                  HDONE_ERROR(H5E_VOL, H5E_CANTRELEASE, FAIL, "can't free VOL connector info")
          if (connector_id >= 0)
              /* The H5VL_class_t struct will be freed by this function */
              if (H5I_dec_ref(connector_id) < 0)
                  HDONE_ERROR(H5E_VOL, H5E_CANTDEC, FAIL, "unable to unregister VOL connector")
      } /* end if */
  
      /* Clean up */
      H5MM_xfree(buf);
  
      FUNC_LEAVE_NOAPI(ret_value)
  } /* end H5VL__set_def_conn() */
  
  /*-------------------------------------------------------------------------
   * Function:    H5VL__wrap_obj
   *
   * Purpose:     Wraps a library object with possible VOL connector wrappers, to
   *		match the VOL connector stack for the file.
   *
   * Return:      Success:        Wrapped object pointer
   *              Failure:        NULL
   *
   * Programmer:	Quincey Koziol
   *		Friday, October  7, 2018
   *
   *-------------------------------------------------------------------------
   */
  static void *
  H5VL__wrap_obj(void *obj, H5I_type_t obj_type)
  {
      H5VL_wrap_ctx_t *vol_wrap_ctx = NULL; /* Object wrapping context */
      void *           ret_value    = NULL; /* Return value */
  
      FUNC_ENTER_STATIC
  
      /* Check arguments */
      HDassert(obj);
  
      /* Retrieve the VOL object wrapping context */
      if (H5CX_get_vol_wrap_ctx((void **)&vol_wrap_ctx) < 0)
          HGOTO_ERROR(H5E_VOL, H5E_CANTGET, NULL, "can't get VOL object wrap context")
  
      /* If there is a VOL object wrapping context, wrap the object */
      if (vol_wrap_ctx) {
          /* Wrap object, using the VOL callback */
          if (NULL == (ret_value = H5VL_wrap_object(vol_wrap_ctx->connector->cls, vol_wrap_ctx->obj_wrap_ctx,
                                                    obj, obj_type)))
              HGOTO_ERROR(H5E_VOL, H5E_CANTGET, NULL, "can't wrap object")
      } /* end if */
      else
          ret_value = obj;
  
  done:
      FUNC_LEAVE_NOAPI(ret_value)
  } /* end H5VL__wrap_obj() */
  
  /*-------------------------------------------------------------------------
   * Function:    H5VL__new_vol_obj
   *
   * Purpose:     Creates a new VOL object, to use when registering an ID.
   *
   * Return:      Success:        VOL object pointer
   *              Failure:        NULL
   *
   * Programmer:	Quincey Koziol
   *		Friday, October  7, 2018
   *
   *-------------------------------------------------------------------------
   */
  static H5VL_object_t *
  H5VL__new_vol_obj(H5I_type_t type, void *object, H5VL_t *vol_connector, hbool_t wrap_obj)
  {
      H5VL_object_t *new_vol_obj  = NULL;  /* Pointer to new VOL object                    */
      hbool_t        conn_rc_incr = FALSE; /* Whether the VOL connector refcount has been incremented */
      H5VL_object_t *ret_value    = NULL;  /* Return value                                 */
  
      FUNC_ENTER_STATIC
  
      /* Check arguments */
      HDassert(object);
      HDassert(vol_connector);
  
      /* Make sure type number is valid */
      if (type != H5I_ATTR && type != H5I_DATASET && type != H5I_DATATYPE && type != H5I_FILE &&
          type != H5I_GROUP && type != H5I_MAP)
          HGOTO_ERROR(H5E_VOL, H5E_BADVALUE, NULL, "invalid type number")
  
      /* Create the new VOL object */
      if (NULL == (new_vol_obj = H5FL_CALLOC(H5VL_object_t)))
          HGOTO_ERROR(H5E_VOL, H5E_CANTALLOC, NULL, "can't allocate memory for VOL object")
      new_vol_obj->connector = vol_connector;
      if (wrap_obj) {
          if (NULL == (new_vol_obj->data = H5VL__wrap_obj(object, type)))
              HGOTO_ERROR(H5E_VOL, H5E_CANTCREATE, NULL, "can't wrap library object")
      } /* end if */
      else
          new_vol_obj->data = object;
  
      /* Bump the reference count on the VOL connector */
      H5VL_conn_inc_rc(vol_connector);
      conn_rc_incr = TRUE;
  
      /* If this is a datatype, we have to hide the VOL object under the H5T_t pointer */
      if (H5I_DATATYPE == type) {
          if (NULL == (ret_value = (H5VL_object_t *)H5T_construct_datatype(new_vol_obj)))
              HGOTO_ERROR(H5E_VOL, H5E_CANTINIT, NULL, "can't construct datatype object")
      } /* end if */
      else
          ret_value = (H5VL_object_t *)new_vol_obj;
  
  done:
      /* Cleanup on error */
      if (NULL == ret_value) {
          if (conn_rc_incr && H5VL_conn_dec_rc(vol_connector) < 0)
              HDONE_ERROR(H5E_VOL, H5E_CANTDEC, NULL, "unable to decrement ref count on VOL connector")
      } /* end if */
  
      FUNC_LEAVE_NOAPI(ret_value)
  } /* end H5VL__new_vol_obj() */
  
  /*-------------------------------------------------------------------------
   * Function:    H5VL_conn_copy
   *
   * Purpose:     Copy VOL connector ID & info.
   *
   * Note:        This is an "in-place" copy.
   *
   * Return:      Success:        Non-negative
   *              Failure:        Negative
   *
   *-------------------------------------------------------------------------
   */
  herr_t
  H5VL_conn_copy(H5VL_connector_prop_t *connector_prop)
  {
      herr_t ret_value = SUCCEED; /* Return value */
  
      FUNC_ENTER_NOAPI(FAIL)
  
      if (connector_prop) {
          /* Copy the connector ID & info, if there is one */
          if (connector_prop->connector_id > 0) {
              /* Increment the reference count on connector ID and copy connector info */
              if (H5I_inc_ref(connector_prop->connector_id, FALSE) < 0)
                  HGOTO_ERROR(H5E_PLIST, H5E_CANTINC, FAIL, "unable to increment ref count on VOL connector ID")
  
              /* Copy connector info, if it exists */
              if (connector_prop->connector_info) {
                  H5VL_class_t *connector;                 /* Pointer to connector */
                  void *        new_connector_info = NULL; /* Copy of connector info */
  
                  /* Retrieve the connector for the ID */
                  if (NULL == (connector = (H5VL_class_t *)H5I_object(connector_prop->connector_id)))
                      HGOTO_ERROR(H5E_PLIST, H5E_BADTYPE, FAIL, "not a VOL connector ID")
  
                  /* Allocate and copy connector info */
                  if (H5VL_copy_connector_info(connector, &new_connector_info, connector_prop->connector_info) <
                      0)
                      HGOTO_ERROR(H5E_PLIST, H5E_CANTCOPY, FAIL, "connector info copy failed")
  
                  /* Set the connector info to the copy */
                  connector_prop->connector_info = new_connector_info;
              } /* end if */
          }     /* end if */
      }         /* end if */
  
  done:
      FUNC_LEAVE_NOAPI(ret_value)
  } /* end H5VL_conn_copy() */
  
  /*-------------------------------------------------------------------------
   * Function:    H5VL_conn_free
   *
   * Purpose:     Free VOL connector ID & info.
   *
   * Return:      Success:        Non-negative
   *              Failure:        Negative
   *
   *-------------------------------------------------------------------------
   */
  herr_t
  H5VL_conn_free(const H5VL_connector_prop_t *connector_prop)
  {
      herr_t ret_value = SUCCEED; /* Return value */
  
      FUNC_ENTER_NOAPI(FAIL)
  
      if (connector_prop) {
          /* Free the connector info (if it exists) and decrement the ID */
          if (connector_prop->connector_id > 0) {
              if (connector_prop->connector_info)
                  /* Free the connector info */
                  if (H5VL_free_connector_info(connector_prop->connector_id, connector_prop->connector_info) <
                      0)
                      HGOTO_ERROR(H5E_VOL, H5E_CANTRELEASE, FAIL, "unable to release VOL connector info object")
  
              /* Decrement reference count for connector ID */
              if (H5I_dec_ref(connector_prop->connector_id) < 0)
                  HGOTO_ERROR(H5E_VOL, H5E_CANTDEC, FAIL, "can't decrement reference count for connector ID")
          }
      }
  
  done:
      FUNC_LEAVE_NOAPI(ret_value)
  } /* end H5VL_conn_free() */
  
  /*-------------------------------------------------------------------------
   * Function:    H5VL_register
   *
   * Purpose:     VOL-aware version of H5I_register. Constructs an H5VL_object_t
   *              from the passed-in object and registers that. Does the right
   *              thing with datatypes, which are complicated under the VOL.
   *
   * Return:      Success:    A valid HDF5 ID
   *              Failure:    H5I_INVALID_HID
   *
   *-------------------------------------------------------------------------
   */
  hid_t
  H5VL_register(H5I_type_t type, void *object, H5VL_t *vol_connector, hbool_t app_ref)
  {
      H5VL_object_t *vol_obj   = NULL;            /* VOL object wrapper for library object */
      hid_t          ret_value = H5I_INVALID_HID; /* Return value */
  
      FUNC_ENTER_NOAPI(H5I_INVALID_HID)
  
      /* Check arguments */
      HDassert(object);
      HDassert(vol_connector);
  
      /* Set up VOL object for the passed-in data */
      /* (Does not wrap object, since it's from a VOL callback) */
      if (NULL == (vol_obj = H5VL__new_vol_obj(type, object, vol_connector, FALSE)))
          HGOTO_ERROR(H5E_VOL, H5E_CANTCREATE, FAIL, "can't create VOL object")
  
      /* Register VOL object as _object_ type, for future object API calls */
      if ((ret_value = H5I_register(type, vol_obj, app_ref)) < 0)
          HGOTO_ERROR(H5E_VOL, H5E_CANTREGISTER, H5I_INVALID_HID, "unable to register handle")
  
  done:
      FUNC_LEAVE_NOAPI(ret_value)
  } /* end H5VL_register() */
  
  /*-------------------------------------------------------------------------
   * Function:    H5VL_register_using_existing_id
   *
   * Purpose:     Registers an OBJECT in a TYPE with the supplied ID for it.
   *              This routine will check to ensure the supplied ID is not already
   *              in use, and ensure that it is a valid ID for the given type,
   *              but will NOT check to ensure the OBJECT is not already
   *              registered (thus, it is possible to register one object under
   *              multiple IDs).
   *
   * NOTE:        Intended for use in refresh calls, where we have to close
   *              and re-open the underlying data, then hook the VOL object back
   *              up to the original ID.
   *
   * Return:      SUCCEED/FAIL
   *
   *-------------------------------------------------------------------------
   */
  herr_t
  H5VL_register_using_existing_id(H5I_type_t type, void *object, H5VL_t *vol_connector, hbool_t app_ref,
                                  hid_t existing_id)
  {
      H5VL_object_t *new_vol_obj = NULL;    /* Pointer to new VOL object                    */
      herr_t         ret_value   = SUCCEED; /* Return value                                 */
  
      FUNC_ENTER_NOAPI(FAIL)
  
      /* Check arguments */
      HDassert(object);
      HDassert(vol_connector);
  
      /* Set up VOL object for the passed-in data */
      /* (Wraps object, since it's a library object) */
      if (NULL == (new_vol_obj = H5VL__new_vol_obj(type, object, vol_connector, TRUE)))
          HGOTO_ERROR(H5E_VOL, H5E_CANTCREATE, FAIL, "can't create VOL object")
  
      /* Call the underlying H5I function to complete the registration */
      if (H5I_register_using_existing_id(type, new_vol_obj, app_ref, existing_id) < 0)
          HGOTO_ERROR(H5E_VOL, H5E_CANTREGISTER, FAIL, "can't register object under existing ID")
  
  done:
      FUNC_LEAVE_NOAPI(ret_value)
  } /* end H5VL_register_using_existing_id() */
  
  /*-------------------------------------------------------------------------
   * Function:	H5VL_register_using_vol_id
   *
   * Purpose:     Utility function to create a user ID for an object created
   *              or opened through the VOL. Uses the VOL connector's ID to
   *              get the connector information instead of it being passed in.
   *
   * Return:      Success:    A valid HDF5 ID
   *              Failure:    H5I_INVALID_HID
   *
   *-------------------------------------------------------------------------
   */
  hid_t
  H5VL_register_using_vol_id(H5I_type_t type, void *obj, hid_t connector_id, hbool_t app_ref)
  {
      H5VL_class_t *cls          = NULL;            /* VOL connector class */
      H5VL_t *      connector    = NULL;            /* VOL connector struct */
      hbool_t       conn_id_incr = FALSE;           /* Whether the VOL connector ID has been incremented */
      hid_t         ret_value    = H5I_INVALID_HID; /* Return value */
  
      FUNC_ENTER_NOAPI(FAIL)
  
      /* Get the VOL class object from the connector's ID */
      if (NULL == (cls = (H5VL_class_t *)H5I_object_verify(connector_id, H5I_VOL)))
          HGOTO_ERROR(H5E_VOL, H5E_BADTYPE, H5I_INVALID_HID, "not a VOL connector ID")
  
      /* Setup VOL info struct */
      if (NULL == (connector = H5FL_CALLOC(H5VL_t)))
          HGOTO_ERROR(H5E_VOL, H5E_CANTALLOC, H5I_INVALID_HID, "can't allocate VOL info struct")
      connector->cls = cls;
      connector->id  = connector_id;
      if (H5I_inc_ref(connector->id, FALSE) < 0)
          HGOTO_ERROR(H5E_VOL, H5E_CANTINC, H5I_INVALID_HID, "unable to increment ref count on VOL connector")
      conn_id_incr = TRUE;
  
      /* Get an ID for the VOL object */
      if ((ret_value = H5VL_register(type, obj, connector, app_ref)) < 0)
          HGOTO_ERROR(H5E_VOL, H5E_CANTREGISTER, H5I_INVALID_HID, "unable to register object handle")
  
  done:
      /* Clean up on error */
      if (ret_value < 0) {
          /* Decrement VOL connector ID ref count on error */
          if (conn_id_incr && H5I_dec_ref(connector_id) < 0)
              HDONE_ERROR(H5E_VOL, H5E_CANTDEC, H5I_INVALID_HID,
                          "unable to decrement ref count on VOL connector")
  
          /* Free VOL connector struct */
          if (NULL != connector)
              connector = H5FL_FREE(H5VL_t, connector);
      } /* end if */
  
      FUNC_LEAVE_NOAPI(ret_value)
  } /* end H5VL_register_using_vol_id() */
  
  /*-------------------------------------------------------------------------
   * Function:    H5VL_create_object
   *
   * Purpose:     Similar to H5VL_register but does not create an ID.
   *              Creates a new VOL object for the provided generic object
   *              using the provided vol connector.  Should only be used for
   *              internal objects returned from the connector such as
   *              requests.
   *
   * Return:      Success:    A valid VOL object
   *              Failure:    NULL
   *
   *-------------------------------------------------------------------------
   */
  H5VL_object_t *
  H5VL_create_object(void *object, H5VL_t *vol_connector)
  {
      H5VL_object_t *ret_value = NULL; /* Return value */
  
      FUNC_ENTER_NOAPI(NULL)
  
      /* Check arguments */
      HDassert(object);
      HDassert(vol_connector);
  
      /* Set up VOL object for the passed-in data */
      /* (Does not wrap object, since it's from a VOL callback) */
      if (NULL == (ret_value = H5FL_CALLOC(H5VL_object_t)))
          HGOTO_ERROR(H5E_VOL, H5E_CANTALLOC, NULL, "can't allocate memory for VOL object")
      ret_value->connector = vol_connector;
      ret_value->data      = object;
  
      /* Bump the reference count on the VOL connector */
      H5VL_conn_inc_rc(vol_connector);
  
  done:
      FUNC_LEAVE_NOAPI(ret_value)
  } /* end H5VL_create_object() */
  
  /*-------------------------------------------------------------------------
   * Function:	H5VL_create_object_using_vol_id
   *
   * Purpose:     Similar to H5VL_register_using_vol_id but does not create
   *              an id.  Intended for use by internal library routines,
   *              therefore it wraps the object.
   *
   * Return:      Success:        VOL object pointer
   *              Failure:        NULL
   *
   *-------------------------------------------------------------------------
   */
  H5VL_object_t *
  H5VL_create_object_using_vol_id(H5I_type_t type, void *obj, hid_t connector_id)
  {
      H5VL_class_t * cls          = NULL;  /* VOL connector class */
      H5VL_t *       connector    = NULL;  /* VOL connector struct */
      hbool_t        conn_id_incr = FALSE; /* Whether the VOL connector ID has been incremented */
      H5VL_object_t *ret_value    = NULL;  /* Return value */
  
      FUNC_ENTER_NOAPI(NULL)
  
      /* Get the VOL class object from the connector's ID */
      if (NULL == (cls = (H5VL_class_t *)H5I_object_verify(connector_id, H5I_VOL)))
          HGOTO_ERROR(H5E_VOL, H5E_BADTYPE, NULL, "not a VOL connector ID")
  
      /* Setup VOL info struct */
      if (NULL == (connector = H5FL_CALLOC(H5VL_t)))
          HGOTO_ERROR(H5E_VOL, H5E_CANTALLOC, NULL, "can't allocate VOL info struct")
      connector->cls = cls;
      connector->id  = connector_id;
      if (H5I_inc_ref(connector->id, FALSE) < 0)
          HGOTO_ERROR(H5E_VOL, H5E_CANTINC, NULL, "unable to increment ref count on VOL connector")
      conn_id_incr = TRUE;
  
      /* Set up VOL object for the passed-in data */
      /* (Wraps object, since it's a library object) */
      if (NULL == (ret_value = H5VL__new_vol_obj(type, obj, connector, TRUE)))
          HGOTO_ERROR(H5E_VOL, H5E_CANTCREATE, NULL, "can't create VOL object")
  
  done:
      /* Clean up on error */
      if (!ret_value) {
          /* Decrement VOL connector ID ref count on error */
          if (conn_id_incr && H5I_dec_ref(connector_id) < 0)
              HDONE_ERROR(H5E_VOL, H5E_CANTDEC, NULL, "unable to decrement ref count on VOL connector")
  
          /* Free VOL connector struct */
          if (NULL != connector)
              connector = H5FL_FREE(H5VL_t, connector);
      } /* end if */
  
      FUNC_LEAVE_NOAPI(ret_value)
  } /* end H5VL_create_object_using_vol_id() */
  
  /*-------------------------------------------------------------------------
   * Function:    H5VL_conn_inc_rc
   *
   * Purpose:     Wrapper to increment the ref. count on a connector.
   *
   * Return:      Current ref. count (can't fail)
   *
   * Programmer:  Quincey Koziol
   *              February 23, 2019
   *
   *-------------------------------------------------------------------------
   */
  int64_t
  H5VL_conn_inc_rc(H5VL_t *connector)
  {
      int64_t ret_value = -1;
  
      FUNC_ENTER_NOAPI(-1)
  
      /* Check arguments */
      HDassert(connector);
  
      /* Increment refcount for connector */
      connector->nrefs++;
  
      ret_value = connector->nrefs;
  
  done:
      FUNC_LEAVE_NOAPI(ret_value)
  } /* end H5VL_conn_inc_rc() */
  
  /*-------------------------------------------------------------------------
   * Function:    H5VL_conn_dec_rc
   *
   * Purpose:     Wrapper to decrement the ref. count on a connector.
   *
   * Return:      Current ref. count (>=0) on success, <0 on failure
   *
   * Programmer:  Quincey Koziol
   *              February 23, 2019
   *
   *-------------------------------------------------------------------------
   */
  int64_t
  H5VL_conn_dec_rc(H5VL_t *connector)
  {
      int64_t ret_value = -1; /* Return value */
  
      FUNC_ENTER_NOAPI(-1)
  
      /* Check arguments */
      HDassert(connector);
  
      /* Decrement refcount for connector */
      connector->nrefs--;
  
      /* Check for last reference */
      if (0 == connector->nrefs) {
          if (H5I_dec_ref(connector->id) < 0)
              HGOTO_ERROR(H5E_VOL, H5E_CANTDEC, FAIL, "unable to decrement ref count on VOL connector")
          H5FL_FREE(H5VL_t, connector);
  
          /* Set return value */
          ret_value = 0;
      } /* end if */
      else
          /* Set return value */
          ret_value = connector->nrefs;
  
  done:
      FUNC_LEAVE_NOAPI(ret_value)
  } /* end H5VL_conn_dec_rc() */
  
  /*-------------------------------------------------------------------------
   * Function:    H5VL_free_object
   *
   * Purpose:     Wrapper to unregister an object ID with a VOL aux struct
   *              and decrement ref count on VOL connector ID
   *
   * Return:      SUCCEED/FAIL
   *
   *-------------------------------------------------------------------------
   */
  herr_t
  H5VL_free_object(H5VL_object_t *vol_obj)
  {
      herr_t ret_value = SUCCEED; /* Return value */
  
      FUNC_ENTER_NOAPI(FAIL)
  
      /* Check arguments */
      HDassert(vol_obj);
  
      /* Decrement refcount on connector */
      if (H5VL_conn_dec_rc(vol_obj->connector) < 0)
          HGOTO_ERROR(H5E_VOL, H5E_CANTDEC, FAIL, "unable to decrement ref count on VOL connector")
  
      vol_obj = H5FL_FREE(H5VL_object_t, vol_obj);
  
  done:
      FUNC_LEAVE_NOAPI(ret_value)
  } /* end H5VL_free_object() */
  
  /*-------------------------------------------------------------------------
   * Function:    H5VL_object_is_native
   *
   * Purpose:     Query if an object is (if it's a file object) / is in (if its
   *              an object) a native connector's file.
   *
   * Return:      SUCCEED/FAIL
   *
   * Programmer:  Quincey Koziol
   *              December 14, 2019
   *
   *-------------------------------------------------------------------------
   */
  herr_t
  H5VL_object_is_native(const H5VL_object_t *obj, hbool_t *is_native)
  {
      const H5VL_class_t *cls;                 /* VOL connector class structs for object */
      const H5VL_class_t *native_cls;          /* Native VOL connector class structs */
      int                 cmp_value;           /* Comparison result */
      herr_t              ret_value = SUCCEED; /* Return value */
  
      FUNC_ENTER_NOAPI(FAIL)
  
      /* Check arguments */
      HDassert(obj);
      HDassert(is_native);
  
      /* Retrieve the terminal connector class for the object */
      cls = NULL;
      if (H5VL_introspect_get_conn_cls(obj, H5VL_GET_CONN_LVL_TERM, &cls) < 0)
          HGOTO_ERROR(H5E_VOL, H5E_CANTGET, FAIL, "can't get VOL connector class")
  
      /* Retrieve the native connector class */
      if (NULL == (native_cls = (H5VL_class_t *)H5I_object_verify(H5VL_NATIVE, H5I_VOL)))
          HGOTO_ERROR(H5E_VOL, H5E_CANTGET, FAIL, "can't retrieve native VOL connector class")
  
      /* Compare connector classes */
      if (H5VL_cmp_connector_cls(&cmp_value, cls, native_cls) < 0)
          HGOTO_ERROR(H5E_VOL, H5E_CANTCOMPARE, FAIL, "can't compare connector classes")
  
      /* If classes compare equal, then the object is / is in a native connector's file */
      *is_native = (cmp_value == 0);
  
  done:
      FUNC_LEAVE_NOAPI(ret_value)
  } /* end H5VL_object_is_native() */
  
  /*-------------------------------------------------------------------------
   * Function:    H5VL_file_is_same
   *
   * Purpose:     Query if two files are the same.
   *
   * Return:      SUCCEED/FAIL
   *
   * Programmer:  Quincey Koziol
   *              December 14, 2019
   *
   *-------------------------------------------------------------------------
   */
  herr_t
  H5VL_file_is_same(const H5VL_object_t *vol_obj1, const H5VL_object_t *vol_obj2, hbool_t *same_file)
  {
      const H5VL_class_t *cls1;                /* VOL connector class struct for first object */
      const H5VL_class_t *cls2;                /* VOL connector class struct for second object */
      int                 cmp_value;           /* Comparison result */
      herr_t              ret_value = SUCCEED; /* Return value */
  
      FUNC_ENTER_NOAPI(FAIL)
  
      /* Check arguments */
      HDassert(vol_obj1);
      HDassert(vol_obj2);
      HDassert(same_file);
  
      /* Retrieve the terminal connectors for each object */
      cls1 = NULL;
      if (H5VL_introspect_get_conn_cls(vol_obj1, H5VL_GET_CONN_LVL_TERM, &cls1) < 0)
          HGOTO_ERROR(H5E_VOL, H5E_CANTGET, FAIL, "can't get VOL connector class")
      cls2 = NULL;
      if (H5VL_introspect_get_conn_cls(vol_obj2, H5VL_GET_CONN_LVL_TERM, &cls2) < 0)
          HGOTO_ERROR(H5E_VOL, H5E_CANTGET, FAIL, "can't get VOL connector class")
  
      /* Compare connector classes */
      if (H5VL_cmp_connector_cls(&cmp_value, cls1, cls2) < 0)
          HGOTO_ERROR(H5E_VOL, H5E_CANTCOMPARE, FAIL, "can't compare connector classes")
  
      /* If the connector classes are different, the files are different */
      if (cmp_value)
          *same_file = FALSE;
      else {
          void *obj2; /* Terminal object for second file */
  
          /* Get unwrapped (terminal) object for vol_obj2 */
          if (NULL == (obj2 = H5VL_object_data(vol_obj2)))
              HGOTO_ERROR(H5E_VOL, H5E_CANTGET, FAIL, "can't get unwrapped object")
  
          /* Make callback */
          if (H5VL_file_specific(vol_obj1, H5VL_FILE_IS_EQUAL, H5P_DATASET_XFER_DEFAULT, NULL, obj2,
                                 same_file) < 0)
              HGOTO_ERROR(H5E_VOL, H5E_CANTOPERATE, FAIL, "file specific failed")
      } /* end else */
  
  done:
      FUNC_LEAVE_NOAPI(ret_value)
  } /* end H5VL_file_is_same() */
  
  /*-------------------------------------------------------------------------
   * Function:    H5VL__register_connector
   *
   * Purpose:     Registers a new VOL connector as a member of the virtual object
   *              layer class.
   *
   * Return:      Success:    A VOL connector ID which is good until the
   *                          library is closed or the connector is unregistered.
   *
   *              Failure:    H5I_INVALID_HID
   *
   * Programmer:  Dana Robinson
   *              June 22, 2017
   *
   *-------------------------------------------------------------------------
   */
  hid_t
  H5VL__register_connector(const void *_cls, hbool_t app_ref, hid_t vipl_id)
  {
      const H5VL_class_t *cls       = (const H5VL_class_t *)_cls;
      H5VL_class_t *      saved     = NULL;
      hid_t               ret_value = H5I_INVALID_HID;
  
      FUNC_ENTER_PACKAGE
  
      /* Check arguments */
      HDassert(cls);
  
      /* Copy the class structure so the caller can reuse or free it */
      if (NULL == (saved = H5FL_MALLOC(H5VL_class_t)))
          HGOTO_ERROR(H5E_VOL, H5E_CANTALLOC, H5I_INVALID_HID,
                      "memory allocation failed for VOL connector class struct")
      H5MM_memcpy(saved, cls, sizeof(H5VL_class_t));
      if (NULL == (saved->name = H5MM_strdup(cls->name)))
          HGOTO_ERROR(H5E_VOL, H5E_CANTALLOC, H5I_INVALID_HID,
                      "memory allocation failed for VOL connector name")
  
      /* Initialize the VOL connector */
      if (cls->initialize && cls->initialize(vipl_id) < 0)
          HGOTO_ERROR(H5E_VOL, H5E_CANTINIT, H5I_INVALID_HID, "unable to init VOL connector")
  
      /* Create the new class ID */
      if ((ret_value = H5I_register(H5I_VOL, saved, app_ref)) < 0)
          HGOTO_ERROR(H5E_VOL, H5E_CANTREGISTER, H5I_INVALID_HID, "unable to register VOL connector ID")
  
  done:
      if (ret_value < 0 && saved) {
          if (saved->name)
              H5MM_xfree_const(saved->name);
  
          H5FL_FREE(H5VL_class_t, saved);
      } /* end if */
  
      FUNC_LEAVE_NOAPI(ret_value)
  } /* end H5VL__register_connector() */
  
  /*-------------------------------------------------------------------------
   * Function:    H5VL__register_connector_by_class
   *
   * Purpose:     Registers a new VOL connector as a member of the virtual object
   *              layer class.
   *
   * Return:      Success:    A VOL connector ID which is good until the
   *                          library is closed or the connector is
   *                          unregistered.
   *
   *              Failure:    H5I_INVALID_HID
   *
   * Programmer:  Dana Robinson
   *              June 22, 2017
   *
   *-------------------------------------------------------------------------
   */
  hid_t
  H5VL__register_connector_by_class(const H5VL_class_t *cls, hbool_t app_ref, hid_t vipl_id)
  {
      H5VL_get_connector_ud_t op_data;                     /* Callback info for connector search */
      hid_t                   ret_value = H5I_INVALID_HID; /* Return value */
  
      FUNC_ENTER_PACKAGE
  
      /* Check arguments */
      if (!cls)
          HGOTO_ERROR(H5E_ARGS, H5E_UNINITIALIZED, H5I_INVALID_HID,
                      "VOL connector class pointer cannot be NULL")
      if (H5VL_VERSION != cls->version)
          HGOTO_ERROR(H5E_VOL, H5E_CANTREGISTER, H5I_INVALID_HID, "VOL connector has incompatible version")
      if (!cls->name)
          HGOTO_ERROR(H5E_VOL, H5E_CANTREGISTER, H5I_INVALID_HID,
                      "VOL connector class name cannot be the NULL pointer")
      if (0 == HDstrlen(cls->name))
          HGOTO_ERROR(H5E_VOL, H5E_CANTREGISTER, H5I_INVALID_HID,
                      "VOL connector class name cannot be the empty string")
      if (cls->info_cls.copy && !cls->info_cls.free)
          HGOTO_ERROR(
              H5E_VOL, H5E_CANTREGISTER, H5I_INVALID_HID,
              "VOL connector must provide free callback for VOL info objects when a copy callback is provided")
      if (cls->wrap_cls.get_wrap_ctx && !cls->wrap_cls.free_wrap_ctx)
          HGOTO_ERROR(H5E_VOL, H5E_CANTREGISTER, H5I_INVALID_HID,
                      "VOL connector must provide free callback for object wrapping contexts when a get "
                      "callback is provided")
  
      /* Set up op data for iteration */
      op_data.kind     = H5VL_GET_CONNECTOR_BY_NAME;
      op_data.u.name   = cls->name;
      op_data.found_id = H5I_INVALID_HID;
  
      /* Check if connector is already registered */
      if (H5I_iterate(H5I_VOL, H5VL__get_connector_cb, &op_data, TRUE) < 0)
          HGOTO_ERROR(H5E_VOL, H5E_BADITER, H5I_INVALID_HID, "can't iterate over VOL IDs")
  
      /* Increment the ref count on the existing VOL connector ID, if it's already registered */
      if (op_data.found_id != H5I_INVALID_HID) {
          if (H5I_inc_ref(op_data.found_id, app_ref) < 0)
              HGOTO_ERROR(H5E_VOL, H5E_CANTINC, H5I_INVALID_HID,
                          "unable to increment ref count on VOL connector")
          ret_value = op_data.found_id;
      } /* end if */
      else {
          /* Create a new class ID */
          if ((ret_value = H5VL__register_connector(cls, app_ref, vipl_id)) < 0)
              HGOTO_ERROR(H5E_VOL, H5E_CANTREGISTER, H5I_INVALID_HID, "unable to register VOL connector")
      } /* end else */
  
  done:
      FUNC_LEAVE_NOAPI(ret_value)
  } /* end H5VL__register_connector_by_class() */
  
  /*-------------------------------------------------------------------------
   * Function:    H5VL__register_connector_by_name
   *
   * Purpose:     Registers a new VOL connector as a member of the virtual object
   *              layer class.
   *
   * Return:      Success:    A VOL connector ID which is good until the
   *                          library is closed or the connector is
   *                          unregistered.
   *
   *              Failure:    H5I_INVALID_HID
   *
   * Programmer:  Dana Robinson
   *              June 22, 2017
   *
   *-------------------------------------------------------------------------
   */
  hid_t
  H5VL__register_connector_by_name(const char *name, hbool_t app_ref, hid_t vipl_id)
  {
      H5VL_get_connector_ud_t op_data;                     /* Callback info for connector search */
      hid_t                   ret_value = H5I_INVALID_HID; /* Return value */
  
      FUNC_ENTER_PACKAGE
  
      /* Set up op data for iteration */
      op_data.kind     = H5VL_GET_CONNECTOR_BY_NAME;
      op_data.u.name   = name;
      op_data.found_id = H5I_INVALID_HID;
  
      /* Check if connector is already registered */
      if (H5I_iterate(H5I_VOL, H5VL__get_connector_cb, &op_data, app_ref) < 0)
          HGOTO_ERROR(H5E_VOL, H5E_BADITER, H5I_INVALID_HID, "can't iterate over VOL ids")
  
      /* If connector alread registered, increment ref count on ID and return ID */
      if (op_data.found_id != H5I_INVALID_HID) {
          if (H5I_inc_ref(op_data.found_id, app_ref) < 0)
              HGOTO_ERROR(H5E_VOL, H5E_CANTINC, H5I_INVALID_HID,
                          "unable to increment ref count on VOL connector")
          ret_value = op_data.found_id;
      } /* end if */
      else {
          H5PL_key_t          key;
          const H5VL_class_t *cls;
  
          /* Try loading the connector */
          key.vol.kind   = H5VL_GET_CONNECTOR_BY_NAME;
          key.vol.u.name = name;
          if (NULL == (cls = (const H5VL_class_t *)H5PL_load(H5PL_TYPE_VOL, &key)))
              HGOTO_ERROR(H5E_VOL, H5E_CANTINIT, H5I_INVALID_HID, "unable to load VOL connector")
  
          /* Register the connector we loaded */
          if ((ret_value = H5VL__register_connector(cls, app_ref, vipl_id)) < 0)
              HGOTO_ERROR(H5E_VOL, H5E_CANTREGISTER, H5I_INVALID_HID, "unable to register VOL connector ID")
      } /* end else */
  
  done:
      FUNC_LEAVE_NOAPI(ret_value)
  } /* end H5VL__register_connector_by_name() */
  
  /*-------------------------------------------------------------------------
   * Function:    H5VL__register_connector_by_value
   *
   * Purpose:     Registers a new VOL connector as a member of the virtual object
   *              layer class.
   *
   * Return:      Success:    A VOL connector ID which is good until the
   *                          library is closed or the connector is
   *                          unregistered.
   *
   *              Failure:    H5I_INVALID_HID
   *
   * Programmer:  Dana Robinson
   *              June 22, 2017
   *
   *-------------------------------------------------------------------------
   */
  hid_t
  H5VL__register_connector_by_value(H5VL_class_value_t value, hbool_t app_ref, hid_t vipl_id)
  {
      H5VL_get_connector_ud_t op_data;                     /* Callback info for connector search */
      hid_t                   ret_value = H5I_INVALID_HID; /* Return value */
  
      FUNC_ENTER_PACKAGE
  
      /* Set up op data for iteration */
      op_data.kind     = H5VL_GET_CONNECTOR_BY_VALUE;
      op_data.u.value  = value;
      op_data.found_id = H5I_INVALID_HID;
  
      /* Check if connector is already registered */
      if (H5I_iterate(H5I_VOL, H5VL__get_connector_cb, &op_data, TRUE) < 0)
          HGOTO_ERROR(H5E_VOL, H5E_BADITER, H5I_INVALID_HID, "can't iterate over VOL ids")
  
      /* If connector alread registered, increment ref count on ID and return ID */
      if (op_data.found_id != H5I_INVALID_HID) {
          if (H5I_inc_ref(op_data.found_id, app_ref) < 0)
              HGOTO_ERROR(H5E_VOL, H5E_CANTINC, H5I_INVALID_HID,
                          "unable to increment ref count on VOL connector")
          ret_value = op_data.found_id;
      } /* end if */
      else {
          H5PL_key_t          key;
          const H5VL_class_t *cls;
  
          /* Try loading the connector */
          key.vol.kind    = H5VL_GET_CONNECTOR_BY_VALUE;
          key.vol.u.value = value;
          if (NULL == (cls = (const H5VL_class_t *)H5PL_load(H5PL_TYPE_VOL, &key)))
              HGOTO_ERROR(H5E_VOL, H5E_CANTINIT, H5I_INVALID_HID, "unable to load VOL connector")
  
          /* Register the connector we loaded */
          if ((ret_value = H5VL__register_connector(cls, app_ref, vipl_id)) < 0)
              HGOTO_ERROR(H5E_VOL, H5E_CANTREGISTER, H5I_INVALID_HID, "unable to register VOL connector ID")
      } /* end else */
  
  done:
      FUNC_LEAVE_NOAPI(ret_value)
  } /* end H5VL__register_connector_by_value() */
  
  /*-------------------------------------------------------------------------
   * Function:    H5VL__is_connector_registered_by_name
   *
   * Purpose:     Checks if a connector with a particular name is registered.
   *
   * Return:      Success:    0
   *              Failure:    -1
   *
   * Programmer:  Dana Robinson
   *              June 17, 2017
   *
   *-------------------------------------------------------------------------
   */
  htri_t
  H5VL__is_connector_registered_by_name(const char *name)
  {
      H5VL_get_connector_ud_t op_data;           /* Callback info for connector search */
      htri_t                  ret_value = FALSE; /* Return value */
  
      FUNC_ENTER_PACKAGE
  
      /* Set up op data for iteration */
      op_data.kind     = H5VL_GET_CONNECTOR_BY_NAME;
      op_data.u.name   = name;
      op_data.found_id = H5I_INVALID_HID;
  
      /* Find connector with name */
      if (H5I_iterate(H5I_VOL, H5VL__get_connector_cb, &op_data, TRUE) < 0)
          HGOTO_ERROR(H5E_VOL, H5E_BADITER, FAIL, "can't iterate over VOL connectors")
  
      /* Found a connector with that name */
      if (op_data.found_id != H5I_INVALID_HID)
          ret_value = TRUE;
  
  done:
      FUNC_LEAVE_NOAPI(ret_value)
  } /* end H5VL__is_connector_registered_by_name() */
  
  /*-------------------------------------------------------------------------
   * Function:    H5VL__is_connector_registered_by_value
   *
   * Purpose:     Checks if a connector with a particular value (ID) is
   *              registered.
   *
   * Return:      Success:    0
   *              Failure:    -1
   *
   *-------------------------------------------------------------------------
   */
  htri_t
  H5VL__is_connector_registered_by_value(H5VL_class_value_t value)
  {
      H5VL_get_connector_ud_t op_data;           /* Callback info for connector search */
      htri_t                  ret_value = FALSE; /* Return value */
  
      FUNC_ENTER_PACKAGE
  
      /* Set up op data for iteration */
      op_data.kind     = H5VL_GET_CONNECTOR_BY_VALUE;
      op_data.u.value  = value;
      op_data.found_id = H5I_INVALID_HID;
  
      /* Find connector with value */
      if (H5I_iterate(H5I_VOL, H5VL__get_connector_cb, &op_data, TRUE) < 0)
          HGOTO_ERROR(H5E_VOL, H5E_BADITER, FAIL, "can't iterate over VOL connectors")
  
      /* Found a connector with that name */
      if (op_data.found_id != H5I_INVALID_HID)
          ret_value = TRUE;
  
  done:
      FUNC_LEAVE_NOAPI(ret_value)
  } /* end H5VL__is_connector_registered_by_value() */
  
  /*-------------------------------------------------------------------------
   * Function:    H5VL__get_connector_id
   *
   * Purpose:     Retrieves the VOL connector ID for a given object ID.
   *
   * Return:      Positive if the VOL class has been registered
   *              Negative on error (if the class is not a valid class or not registered)
   *
   * Programmer:  Dana Robinson
   *              June 17, 2017
   *
   *-------------------------------------------------------------------------
   */
  hid_t
  H5VL__get_connector_id(hid_t obj_id, hbool_t is_api)
  {
      H5VL_object_t *vol_obj   = NULL;
      hid_t          ret_value = H5I_INVALID_HID; /* Return value */
  
      FUNC_ENTER_PACKAGE
  
      /* Get the underlying VOL object for the object ID */
      if (NULL == (vol_obj = H5VL_vol_object(obj_id)))
          HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, H5I_INVALID_HID, "invalid location identifier")
  
      /* Return the VOL object's VOL class ID */
      ret_value = vol_obj->connector->id;
      if (H5I_inc_ref(ret_value, is_api) < 0)
          HGOTO_ERROR(H5E_FILE, H5E_CANTINC, H5I_INVALID_HID, "unable to increment ref count on VOL connector")
  
  done:
      FUNC_LEAVE_NOAPI(ret_value)
  } /* end H5VL__get_connector_id() */
  
  /*-------------------------------------------------------------------------
   * Function:    H5VL__get_connector_id_by_name
   *
   * Purpose:     Retrieves the ID for a registered VOL connector.
   *
   * Return:      Positive if the VOL class has been registered
   *              Negative on error (if the class is not a valid class or not registered)
   *
   * Programmer:  Dana Robinson
   *              June 17, 2017
   *
   *-------------------------------------------------------------------------
   */
  hid_t
  H5VL__get_connector_id_by_name(const char *name, hbool_t is_api)
  {
      hid_t ret_value = H5I_INVALID_HID; /* Return value */
  
      FUNC_ENTER_PACKAGE
  
      /* Find connector with name */
      if ((ret_value = H5VL__peek_connector_id_by_name(name)) < 0)
          HGOTO_ERROR(H5E_VOL, H5E_BADITER, H5I_INVALID_HID, "can't find VOL connector")
  
      /* Found a connector with that name */
      if (H5I_inc_ref(ret_value, is_api) < 0)
          HGOTO_ERROR(H5E_FILE, H5E_CANTINC, H5I_INVALID_HID, "unable to increment ref count on VOL connector")
  
  done:
      FUNC_LEAVE_NOAPI(ret_value)
  } /* end H5VL__get_connector_id_by_name() */
  
  /*-------------------------------------------------------------------------
   * Function:    H5VL__get_connector_id_by_value
   *
   * Purpose:     Retrieves the ID for a registered VOL connector.
   *
   * Return:      Positive if the VOL class has been registered
   *              Negative on error (if the class is not a valid class or
   *                not registered)
   *
   *-------------------------------------------------------------------------
   */
  hid_t
  H5VL__get_connector_id_by_value(H5VL_class_value_t value, hbool_t is_api)
  {
      hid_t ret_value = H5I_INVALID_HID; /* Return value */
  
      FUNC_ENTER_PACKAGE
  
      /* Find connector with value */
      if ((ret_value = H5VL__peek_connector_id_by_value(value)) < 0)
          HGOTO_ERROR(H5E_VOL, H5E_BADITER, H5I_INVALID_HID, "can't find VOL connector")
  
      /* Found a connector with that value */
      if (H5I_inc_ref(ret_value, is_api) < 0)
          HGOTO_ERROR(H5E_FILE, H5E_CANTINC, H5I_INVALID_HID, "unable to increment ref count on VOL connector")
  
  done:
      FUNC_LEAVE_NOAPI(ret_value)
  } /* end H5VL__get_connector_id_by_value() */
  
  /*-------------------------------------------------------------------------
   * Function:    H5VL__peek_connector_id_by_name
   *
   * Purpose:     Retrieves the ID for a registered VOL connector.  Does not
   *              increment the ref count
   *
   * Return:      Positive if the VOL class has been registered
   *              Negative on error (if the class is not a valid class or
   *                not registered)
   *
   *-------------------------------------------------------------------------
   */
  hid_t
  H5VL__peek_connector_id_by_name(const char *name)
  {
      H5VL_get_connector_ud_t op_data;                     /* Callback info for connector search */
      hid_t                   ret_value = H5I_INVALID_HID; /* Return value */
  
      FUNC_ENTER_PACKAGE
  
      /* Set up op data for iteration */
      op_data.kind     = H5VL_GET_CONNECTOR_BY_NAME;
      op_data.u.name   = name;
      op_data.found_id = H5I_INVALID_HID;
  
      /* Find connector with name */
      if (H5I_iterate(H5I_VOL, H5VL__get_connector_cb, &op_data, TRUE) < 0)
          HGOTO_ERROR(H5E_VOL, H5E_BADITER, H5I_INVALID_HID, "can't iterate over VOL connectors")
  
      /* Set return value */
      ret_value = op_data.found_id;
  
  done:
      FUNC_LEAVE_NOAPI(ret_value)
  } /* end H5VL__peek_connector_id_by_name() */
  
  /*-------------------------------------------------------------------------
   * Function:    H5VL__peek_connector_id_by_value
   *
   * Purpose:     Retrieves the ID for a registered VOL connector.  Does not
   *              increment the ref count
   *
   * Return:      Positive if the VOL class has been registered
   *              Negative on error (if the class is not a valid class or
   *                not registered)
   *
   *-------------------------------------------------------------------------
   */
  hid_t
  H5VL__peek_connector_id_by_value(H5VL_class_value_t value)
  {
      H5VL_get_connector_ud_t op_data;                     /* Callback info for connector search */
      hid_t                   ret_value = H5I_INVALID_HID; /* Return value */
  
      FUNC_ENTER_PACKAGE
  
      /* Set up op data for iteration */
      op_data.kind     = H5VL_GET_CONNECTOR_BY_VALUE;
      op_data.u.value  = value;
      op_data.found_id = H5I_INVALID_HID;
  
      /* Find connector with value */
      if (H5I_iterate(H5I_VOL, H5VL__get_connector_cb, &op_data, TRUE) < 0)
          HGOTO_ERROR(H5E_VOL, H5E_BADITER, H5I_INVALID_HID, "can't iterate over VOL connectors")
  
      /* Set return value */
      ret_value = op_data.found_id;
  
  done:
      FUNC_LEAVE_NOAPI(ret_value)
  } /* end H5VL__peek_connector_id_by_value() */
  
  /*-------------------------------------------------------------------------
   * Function:    H5VL__connector_str_to_info
   *
   * Purpose:     Deserializes a string into a connector's info object
   *
   * Return:      Success:    Non-negative
   *              Failure:    Negative
   *
   * Programmer:  Quincey Koziol
   *              March 2, 2019
   *
   *-------------------------------------------------------------------------
   */
  herr_t
  H5VL__connector_str_to_info(const char *str, hid_t connector_id, void **info)
  {
      herr_t ret_value = SUCCEED; /* Return value */
  
      FUNC_ENTER_PACKAGE
  
      /* Only deserialize string, if it's non-NULL */
      if (str) {
          H5VL_class_t *cls; /* VOL connector's class struct */
  
          /* Check args and get class pointer */
          if (NULL == (cls = (H5VL_class_t *)H5I_object_verify(connector_id, H5I_VOL)))
              HGOTO_ERROR(H5E_VOL, H5E_BADTYPE, FAIL, "not a VOL connector ID")
  
          /* Allow the connector to deserialize info */
          if (cls->info_cls.from_str) {
              if ((cls->info_cls.from_str)(str, info) < 0)
                  HGOTO_ERROR(H5E_VOL, H5E_CANTUNSERIALIZE, FAIL, "can't deserialize connector info")
          } /* end if */
          else
              *info = NULL;
      } /* end if */
      else
          *info = NULL;
  
  done:
      FUNC_LEAVE_NOAPI(ret_value)
  } /* end H5VL__connector_str_to_info() */
  
  /*-------------------------------------------------------------------------
   * Function:    H5VL__get_connector_name
   *
   * Purpose:     Private version of H5VLget_connector_name
   *
   * Return:      Success:        The length of the connector name
   *              Failure:        Negative
   *
   *-------------------------------------------------------------------------
   */
  ssize_t
  H5VL__get_connector_name(hid_t id, char *name /*out*/, size_t size)
  {
      H5VL_object_t *     vol_obj;
      const H5VL_class_t *cls;
      size_t              len;
      ssize_t             ret_value = -1;
  
      FUNC_ENTER_PACKAGE
  
      /* get the object pointer */
      if (NULL == (vol_obj = H5VL_vol_object(id)))
          HGOTO_ERROR(H5E_VOL, H5E_BADTYPE, FAIL, "invalid VOL identifier")
  
      cls = vol_obj->connector->cls;
  
      len = HDstrlen(cls->name);
      if (name) {
          HDstrncpy(name, cls->name, MIN(len + 1, size));
          if (len >= size)
              name[size - 1] = '\0';
      } /* end if */
  
      /* Set the return value for the API call */
      ret_value = (ssize_t)len;
  
  done:
      FUNC_LEAVE_NOAPI(ret_value)
  } /* end H5VL__get_connector_name() */
  
  /*-------------------------------------------------------------------------
   * Function:    H5VL_vol_object
   *
   * Purpose:     Utility function to return the object pointer associated with
   *              a hid_t. This routine is the same as H5I_object for all types
   *              except for named datatypes, where the vol_obj is returned that
   *              is attached to the H5T_t struct.
   *
   * Return:      Success:        object pointer
   *              Failure:        NULL
   *
   *-------------------------------------------------------------------------
   */
  H5VL_object_t *
  H5VL_vol_object(hid_t id)
  {
      void *         obj = NULL;
      H5I_type_t     obj_type;
      H5VL_object_t *ret_value = NULL;
  
      FUNC_ENTER_NOAPI(NULL)
  
      obj_type = H5I_get_type(id);
      if (H5I_FILE == obj_type || H5I_GROUP == obj_type || H5I_ATTR == obj_type || H5I_DATASET == obj_type ||
          H5I_DATATYPE == obj_type || H5I_MAP == obj_type) {
          /* Get the object */
          if (NULL == (obj = H5I_object(id)))
              HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, NULL, "invalid identifier")
  
          /* If this is a datatype, get the VOL object attached to the H5T_t struct */
          if (H5I_DATATYPE == obj_type)
              if (NULL == (obj = H5T_get_named_type((H5T_t *)obj)))
                  HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, NULL, "not a named datatype")
      } /* end if */
      else
          HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, NULL, "invalid identifier type to function")
  
      ret_value = (H5VL_object_t *)obj;
  
  done:
      FUNC_LEAVE_NOAPI(ret_value)
  } /* end H5VL_vol_object() */
  
  /*-------------------------------------------------------------------------
   * Function:    H5VL_object_data
   *
   * Purpose:     Correctly retrieve the 'data' field for a VOL object (H5VL_object),
   *              even for nested / stacked VOL connectors.
   *
   * Return:      Success:        object pointer
   *              Failure:        NULL
   *
   *-------------------------------------------------------------------------
   */
  void *
  H5VL_object_data(const H5VL_object_t *vol_obj)
  {
      void *ret_value = NULL;
  
      FUNC_ENTER_NOAPI_NOINIT_NOERR
  
      /* Check for 'get_object' callback in connector */
      if (vol_obj->connector->cls->wrap_cls.get_object)
          ret_value = (vol_obj->connector->cls->wrap_cls.get_object)(vol_obj->data);
      else
          ret_value = vol_obj->data;
  
      FUNC_LEAVE_NOAPI(ret_value)
  } /* end H5VL_object_data() */
  
  /*-------------------------------------------------------------------------
   * Function:    H5VL_object_unwrap
   *
   * Purpose:     Correctly unwrap the 'data' field for a VOL object (H5VL_object),
   *              even for nested / stacked VOL connectors.
   *
   * Return:      Success:        Object pointer
   *              Failure:        NULL
   *
   *-------------------------------------------------------------------------
   */
  void *
  H5VL_object_unwrap(const H5VL_object_t *vol_obj)
  {
      void *ret_value = NULL;
  
      FUNC_ENTER_NOAPI(NULL)
  
      if (NULL == (ret_value = H5VL_unwrap_object(vol_obj->connector->cls, vol_obj->data)))
          HGOTO_ERROR(H5E_VOL, H5E_CANTGET, NULL, "can't unwrap object")
  
  done:
      FUNC_LEAVE_NOAPI(ret_value)
  } /* end H5VL_object_unwrap() */
  
  /*-------------------------------------------------------------------------
   * Function:    H5VL__object
   *
   * Purpose:     Internal function to return the VOL object pointer associated
   *              with an hid_t.
   *
   * Return:      Success:    object pointer
   *              Failure:    NULL
   *
   *-------------------------------------------------------------------------
   */
  static void *
  H5VL__object(hid_t id, H5I_type_t obj_type)
  {
      H5VL_object_t *vol_obj   = NULL;
      void *         ret_value = NULL;
  
      FUNC_ENTER_STATIC
  
      /* Get the underlying object */
      switch (obj_type) {
          case H5I_GROUP:
          case H5I_DATASET:
          case H5I_FILE:
          case H5I_ATTR:
          case H5I_MAP:
              /* get the object */
              if (NULL == (vol_obj = (H5VL_object_t *)H5I_object(id)))
                  HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, NULL, "invalid identifier")
              break;
  
          case H5I_DATATYPE: {
              H5T_t *dt = NULL;
  
              /* get the object */
              if (NULL == (dt = (H5T_t *)H5I_object(id)))
                  HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, NULL, "invalid identifier")
  
              /* Get the actual datatype object that should be the vol_obj */
              if (NULL == (vol_obj = H5T_get_named_type(dt)))
                  HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, NULL, "not a named datatype")
              break;
          }
  
          case H5I_UNINIT:
          case H5I_BADID:
          case H5I_DATASPACE:
          case H5I_VFL:
          case H5I_VOL:
          case H5I_GENPROP_CLS:
          case H5I_GENPROP_LST:
          case H5I_ERROR_CLASS:
          case H5I_ERROR_MSG:
          case H5I_ERROR_STACK:
          case H5I_SPACE_SEL_ITER:
          case H5I_EVENTSET:
          case H5I_NTYPES:
          default:
              HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, NULL, "unknown data object type")
      } /* end switch */
  
      /* Set the return value */
      ret_value = H5VL_object_data(vol_obj);
  
  done:
      FUNC_LEAVE_NOAPI(ret_value)
  } /* end H5VL__object() */
  
  /*-------------------------------------------------------------------------
   * Function:    H5VL_object
   *
   * Purpose:     Utility function to return the VOL object pointer associated with
   *              a hid_t.
   *
   * Return:      Success:    object pointer
   *              Failure:    NULL
   *
   *-------------------------------------------------------------------------
   */
  void *
  H5VL_object(hid_t id)
  {
      void *ret_value = NULL;
  
      FUNC_ENTER_NOAPI(NULL)
  
      /* Get the underlying object */
      if (NULL == (ret_value = H5VL__object(id, H5I_get_type(id))))
          HGOTO_ERROR(H5E_VOL, H5E_CANTGET, NULL, "can't retrieve object for ID")
  
  done:
      FUNC_LEAVE_NOAPI(ret_value)
  } /* end H5VL_object() */
  
  /*-------------------------------------------------------------------------
   * Function:    H5VL_object_verify
   *
   * Purpose:     Utility function to return the VOL object pointer associated
   *              with an identifier.
   *
   * Return:      Success:    object pointer
   *              Failure:    NULL
   *
   *-------------------------------------------------------------------------
   */
  void *
  H5VL_object_verify(hid_t id, H5I_type_t obj_type)
  {
      void *ret_value = NULL;
  
      FUNC_ENTER_NOAPI(NULL)
  
      /* Check of ID of correct type */
      if (obj_type != H5I_get_type(id))
          HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, NULL, "invalid identifier")
  
      /* Get the underlying object */
      if (NULL == (ret_value = H5VL__object(id, obj_type)))
          HGOTO_ERROR(H5E_ARGS, H5E_CANTGET, NULL, "can't retrieve object for ID")
  
  done:
      FUNC_LEAVE_NOAPI(ret_value)
  } /* end H5VL_object_verify() */
  
  /*-------------------------------------------------------------------------
   * Function:    H5VL_cmp_connector_cls
   *
   * Purpose:     Compare VOL class for a connector
   *
   * Note:        Sets *cmp_value positive if VALUE1 is greater than VALUE2,
   *		negative if VALUE2 is greater than VALUE1, and zero if VALUE1
   *              and VALUE2 are equal (like strcmp).
   *
   * Return:      SUCCEED / FAIL
   *
   *-------------------------------------------------------------------------
   */
  herr_t
  H5VL_cmp_connector_cls(int *cmp_value, const H5VL_class_t *cls1, const H5VL_class_t *cls2)
  {
      herr_t ret_value = SUCCEED; /* Return value */
  
      FUNC_ENTER_NOAPI(FAIL)
  
      /* Sanity checks */
      HDassert(cls1);
      HDassert(cls2);
  
      /* If the pointers are the same the classes are the same */
      if (cls1 == cls2) {
          *cmp_value = 0;
          HGOTO_DONE(SUCCEED);
      } /* end if */
  
      /* Compare connector "values" */
      if (cls1->value < cls2->value) {
          *cmp_value = -1;
          HGOTO_DONE(SUCCEED)
      } /* end if */
      if (cls1->value > cls2->value) {
          *cmp_value = 1;
          HGOTO_DONE(SUCCEED)
      } /* end if */
      HDassert(cls1->value == cls2->value);
  
      /* Compare connector names */
      if (cls1->name == NULL && cls2->name != NULL) {
          *cmp_value = -1;
          HGOTO_DONE(SUCCEED)
      } /* end if */
      if (cls1->name != NULL && cls2->name == NULL) {
          *cmp_value = 1;
          HGOTO_DONE(SUCCEED)
      } /* end if */
      if (0 != (*cmp_value = HDstrcmp(cls1->name, cls2->name)))
          HGOTO_DONE(SUCCEED)
  
      /* Compare connector VOL API versions */
      if (cls1->version < cls2->version) {
          *cmp_value = -1;
          HGOTO_DONE(SUCCEED)
      } /* end if */
      if (cls1->version > cls2->version) {
          *cmp_value = 1;
          HGOTO_DONE(SUCCEED)
      } /* end if */
      HDassert(cls1->version == cls2->version);
  
      /* Compare connector info */
      if (cls1->info_cls.size < cls2->info_cls.size) {
          *cmp_value = -1;
          HGOTO_DONE(SUCCEED)
      } /* end if */
      if (cls1->info_cls.size > cls2->info_cls.size) {
          *cmp_value = 1;
          HGOTO_DONE(SUCCEED)
      } /* end if */
      HDassert(cls1->info_cls.size == cls2->info_cls.size);
  
      /* Set comparison value to 'equal' */
      *cmp_value = 0;
  
  done:
      FUNC_LEAVE_NOAPI(ret_value)
  } /* end H5VL_cmp_connector_cls() */
  
  /*-------------------------------------------------------------------------
   * Function:    H5VL_retrieve_lib_state
   *
   * Purpose:     Retrieve the state of the library.
   *
   * Note:        Currently just retrieves the API context state, but could be
   *		expanded in the future.
   *
   * Return:      Success:    Non-negative, *state set
   *              Failure:    Negative, *state unset
   *
   *-------------------------------------------------------------------------
   */
  herr_t
  H5VL_retrieve_lib_state(void **state)
  {
      herr_t ret_value = SUCCEED; /* Return value */
  
      FUNC_ENTER_NOAPI(FAIL)
  
      /* Sanity checks */
      HDassert(state);
  
      /* Retrieve the API context state */
      if (H5CX_retrieve_state((H5CX_state_t **)state) < 0)
          HGOTO_ERROR(H5E_VOL, H5E_CANTGET, FAIL, "can't get API context state")
  
  done:
      FUNC_LEAVE_NOAPI(ret_value)
  } /* end H5VL_retrieve_lib_state() */
  
  /*-------------------------------------------------------------------------
   * Function:    H5VL_restore_lib_state
   *
   * Purpose:     Restore the state of the library.
   *
   * Note:        Currently just restores the API context state, but could be
   *		expanded in the future.
   *
   * Return:      SUCCEED / FAIL
   *
   * Programmer:	Quincey Koziol
   *		Thursday, January 10, 2019
   *
   *-------------------------------------------------------------------------
   */
  herr_t
  H5VL_restore_lib_state(const void *state)
  {
      herr_t ret_value = SUCCEED; /* Return value */
  
      FUNC_ENTER_NOAPI(FAIL)
  
      /* Sanity checks */
      HDassert(state);
  
      /* Push a new API context on the stack */
      if (H5CX_push() < 0)
          HGOTO_ERROR(H5E_VOL, H5E_CANTSET, FAIL, "can't push API context")
  
      /* Restore the API context state */
      if (H5CX_restore_state((const H5CX_state_t *)state) < 0)
          HGOTO_ERROR(H5E_VOL, H5E_CANTSET, FAIL, "can't set API context state")
  
  done:
      FUNC_LEAVE_NOAPI(ret_value)
  } /* end H5VL_restore_lib_state() */
  
  /*-------------------------------------------------------------------------
   * Function:    H5VL_reset_lib_state
   *
   * Purpose:     Reset the state of the library, undoing affects of
   *		H5VL_restore_lib_state.
   *
   * Note:        Currently just resets the API context state, but could be
   *		expanded in the future.
   *
   * Note:	This routine must be called as a "pair" with
   * 		H5VL_restore_lib_state.  It can be called before / after /
   * 		independently of H5VL_free_lib_state.
   *
   * Return:      SUCCEED / FAIL
   *
   * Programmer:	Quincey Koziol
   *		Saturday, February 23, 2019
   *
   *-------------------------------------------------------------------------
   */
  herr_t
  H5VL_reset_lib_state(void)
  {
      herr_t ret_value = SUCCEED; /* Return value */
  
      FUNC_ENTER_NOAPI(FAIL)
  
      /* Pop the API context off the stack */
      if (H5CX_pop(FALSE) < 0)
          HGOTO_ERROR(H5E_VOL, H5E_CANTRESET, FAIL, "can't pop API context")
  
  done:
      FUNC_LEAVE_NOAPI(ret_value)
  } /* end H5VL_reset_lib_state() */
  
  /*-------------------------------------------------------------------------
   * Function:    H5VL_free_lib_state
   *
   * Purpose:     Free a library state.
   *
   * Note:	This routine must be called as a "pair" with
   * 		H5VL_retrieve_lib_state.
   *
   * Return:      SUCCEED / FAIL
   *
   * Programmer:	Quincey Koziol
   *		Thursday, January 10, 2019
   *
   *-------------------------------------------------------------------------
   */
  herr_t
  H5VL_free_lib_state(void *state)
  {
      herr_t ret_value = SUCCEED; /* Return value */
  
      FUNC_ENTER_NOAPI(FAIL)
  
      /* Sanity checks */
      HDassert(state);
  
      /* Free the API context state */
      if (H5CX_free_state((H5CX_state_t *)state) < 0)
          HGOTO_ERROR(H5E_VOL, H5E_CANTRELEASE, FAIL, "can't free API context state")
  
  done:
      FUNC_LEAVE_NOAPI(ret_value)
  } /* end H5VL_free_lib_state() */
  
  /*-------------------------------------------------------------------------
   * Function:    H5VL__free_vol_wrapper
   *
   * Purpose:     Free object wrapping context for VOL connector
   *
   * Return:      SUCCEED / FAIL
   *
   * Programmer:	Quincey Koziol
   *		Wednesday, January  9, 2019
   *
   *-------------------------------------------------------------------------
   */
  static herr_t
  H5VL__free_vol_wrapper(H5VL_wrap_ctx_t *vol_wrap_ctx)
  {
      herr_t ret_value = SUCCEED; /* Return value */
  
      FUNC_ENTER_STATIC
  
      /* Sanity check */
      HDassert(vol_wrap_ctx);
      HDassert(0 == vol_wrap_ctx->rc);
      HDassert(vol_wrap_ctx->connector);
      HDassert(vol_wrap_ctx->connector->cls);
  
      /* If there is a VOL connector object wrapping context, release it */
      if (vol_wrap_ctx->obj_wrap_ctx)
          /* Release the VOL connector's object wrapping context */
          if ((*vol_wrap_ctx->connector->cls->wrap_cls.free_wrap_ctx)(vol_wrap_ctx->obj_wrap_ctx) < 0)
              HGOTO_ERROR(H5E_VOL, H5E_CANTRELEASE, FAIL,
                          "unable to release connector's object wrapping context")
  
      /* Decrement refcount on connector */
      if (H5VL_conn_dec_rc(vol_wrap_ctx->connector) < 0)
          HGOTO_ERROR(H5E_VOL, H5E_CANTDEC, FAIL, "unable to decrement ref count on VOL connector")
  
      /* Release object wrapping context */
      H5FL_FREE(H5VL_wrap_ctx_t, vol_wrap_ctx);
  
  done:
      FUNC_LEAVE_NOAPI(ret_value)
  } /* end H5VL__free_vol_wrapper() */
  
  /*-------------------------------------------------------------------------
   * Function:    H5VL_set_vol_wrapper
   *
   * Purpose:     Set up object wrapping context for current VOL connector
   *
   * Return:      SUCCEED / FAIL
   *
   *-------------------------------------------------------------------------
   */
  herr_t
  H5VL_set_vol_wrapper(const H5VL_object_t *vol_obj)
  {
      H5VL_wrap_ctx_t *vol_wrap_ctx = NULL;    /* Object wrapping context */
      herr_t           ret_value    = SUCCEED; /* Return value */
  
      FUNC_ENTER_NOAPI(FAIL)
  
      /* Sanity check */
      HDassert(vol_obj);
  
      /* Retrieve the VOL object wrap context */
      if (H5CX_get_vol_wrap_ctx((void **)&vol_wrap_ctx) < 0)
          HGOTO_ERROR(H5E_VOL, H5E_CANTGET, FAIL, "can't get VOL object wrap context")
  
      /* Check for existing wrapping context */
      if (NULL == vol_wrap_ctx) {
          void *obj_wrap_ctx = NULL; /* VOL connector's wrapping context */
  
          /* Sanity checks */
          HDassert(vol_obj->data);
          HDassert(vol_obj->connector);
  
          /* Check if the connector can create a wrap context */
          if (vol_obj->connector->cls->wrap_cls.get_wrap_ctx) {
              /* Sanity check */
              HDassert(vol_obj->connector->cls->wrap_cls.free_wrap_ctx);
  
              /* Get the wrap context from the connector */
              if ((vol_obj->connector->cls->wrap_cls.get_wrap_ctx)(vol_obj->data, &obj_wrap_ctx) < 0)
                  HGOTO_ERROR(H5E_VOL, H5E_CANTGET, FAIL, "can't retrieve VOL connector's object wrap context")
          } /* end if */
  
          /* Allocate VOL object wrapper context */
          if (NULL == (vol_wrap_ctx = H5FL_MALLOC(H5VL_wrap_ctx_t)))
              HGOTO_ERROR(H5E_VOL, H5E_CANTALLOC, FAIL, "can't allocate VOL wrap context")
  
          /* Increment the outstanding objects that are using the connector */
          H5VL_conn_inc_rc(vol_obj->connector);
  
          /* Set up VOL object wrapper context */
          vol_wrap_ctx->rc           = 1;
          vol_wrap_ctx->connector    = vol_obj->connector;
          vol_wrap_ctx->obj_wrap_ctx = obj_wrap_ctx;
      } /* end if */
      else
          /* Incremeent ref count on existing wrapper context */
          vol_wrap_ctx->rc++;
  
      /* Save the wrapper context */
      if (H5CX_set_vol_wrap_ctx(vol_wrap_ctx) < 0)
          HGOTO_ERROR(H5E_VOL, H5E_CANTSET, FAIL, "can't set VOL object wrap context")
  
  done:
      if (ret_value < 0 && vol_wrap_ctx)
          /* Release object wrapping context */
          H5FL_FREE(H5VL_wrap_ctx_t, vol_wrap_ctx);
  
      FUNC_LEAVE_NOAPI(ret_value)
  } /* end H5VL_set_vol_wrapper() */
  
  /*-------------------------------------------------------------------------
   * Function:    H5VL_inc_vol_wrapper
   *
   * Purpose:     Increment refcount on object wrapping context
   *
   * Return:      SUCCEED / FAIL
   *
   * Programmer:	Quincey Koziol
   *		Wednesday, January  9, 2019
   *
   *-------------------------------------------------------------------------
   */
  herr_t
  H5VL_inc_vol_wrapper(void *_vol_wrap_ctx)
  {
      H5VL_wrap_ctx_t *vol_wrap_ctx = (H5VL_wrap_ctx_t *)_vol_wrap_ctx; /* VOL object wrapping context */
      herr_t           ret_value    = SUCCEED;                          /* Return value */
  
      FUNC_ENTER_NOAPI(FAIL)
  
      /* Check for valid, active VOL object wrap context */
      if (NULL == vol_wrap_ctx)
          HGOTO_ERROR(H5E_VOL, H5E_BADVALUE, FAIL, "no VOL object wrap context?")
      if (0 == vol_wrap_ctx->rc)
          HGOTO_ERROR(H5E_VOL, H5E_BADVALUE, FAIL, "bad VOL object wrap context refcount?")
  
      /* Increment ref count on wrapping context */
      vol_wrap_ctx->rc++;
  
  done:
      FUNC_LEAVE_NOAPI(ret_value)
  } /* end H5VL_inc_vol_wrapper() */
  
  /*-------------------------------------------------------------------------
   * Function:    H5VL_dec_vol_wrapper
   *
   * Purpose:     Decrement refcount on object wrapping context, releasing it
   *		if the refcount drops to zero.
   *
   * Return:      SUCCEED / FAIL
   *
   * Programmer:	Quincey Koziol
   *		Wednesday, January  9, 2019
   *
   *-------------------------------------------------------------------------
   */
  herr_t
  H5VL_dec_vol_wrapper(void *_vol_wrap_ctx)
  {
      H5VL_wrap_ctx_t *vol_wrap_ctx = (H5VL_wrap_ctx_t *)_vol_wrap_ctx; /* VOL object wrapping context */
      herr_t           ret_value    = SUCCEED;                          /* Return value */
  
      FUNC_ENTER_NOAPI(FAIL)
  
      /* Check for valid, active VOL object wrap context */
      if (NULL == vol_wrap_ctx)
          HGOTO_ERROR(H5E_VOL, H5E_BADVALUE, FAIL, "no VOL object wrap context?")
      if (0 == vol_wrap_ctx->rc)
          HGOTO_ERROR(H5E_VOL, H5E_BADVALUE, FAIL, "bad VOL object wrap context refcount?")
  
      /* Decrement ref count on wrapping context */
      vol_wrap_ctx->rc--;
  
      /* Release context if the ref count drops to zero */
      if (0 == vol_wrap_ctx->rc)
          if (H5VL__free_vol_wrapper(vol_wrap_ctx) < 0)
              HGOTO_ERROR(H5E_VOL, H5E_CANTRELEASE, FAIL, "unable to release VOL object wrapping context")
  
  done:
      FUNC_LEAVE_NOAPI(ret_value)
  } /* end H5VL_dec_vol_wrapper() */
  
  /*-------------------------------------------------------------------------
   * Function:    H5VL_reset_vol_wrapper
   *
   * Purpose:     Reset object wrapping context for current VOL connector
   *
   * Return:      SUCCEED / FAIL
   *
   *-------------------------------------------------------------------------
   */
  herr_t
  H5VL_reset_vol_wrapper(void)
  {
      H5VL_wrap_ctx_t *vol_wrap_ctx = NULL;    /* Object wrapping context */
      herr_t           ret_value    = SUCCEED; /* Return value */
  
      FUNC_ENTER_NOAPI(FAIL)
  
      /* Retrieve the VOL object wrap context */
      if (H5CX_get_vol_wrap_ctx((void **)&vol_wrap_ctx) < 0)
          HGOTO_ERROR(H5E_VOL, H5E_CANTGET, FAIL, "can't get VOL object wrap context")
  
      /* Check for VOL object wrap context */
      if (NULL == vol_wrap_ctx)
          HGOTO_ERROR(H5E_VOL, H5E_BADVALUE, FAIL, "no VOL object wrap context?")
  
      /* Decrement ref count on wrapping context */
      vol_wrap_ctx->rc--;
  
      /* Release context if the ref count drops to zero */
      if (0 == vol_wrap_ctx->rc) {
          /* Release object wrapping context */
          if (H5VL__free_vol_wrapper(vol_wrap_ctx) < 0)
              HGOTO_ERROR(H5E_VOL, H5E_CANTRELEASE, FAIL, "unable to release VOL object wrapping context")
  
          /* Reset the wrapper context */
          if (H5CX_set_vol_wrap_ctx(NULL) < 0)
              HGOTO_ERROR(H5E_VOL, H5E_CANTSET, FAIL, "can't set VOL object wrap context")
      } /* end if */
      else
          /* Save the updated wrapper context */
          if (H5CX_set_vol_wrap_ctx(vol_wrap_ctx) < 0)
          HGOTO_ERROR(H5E_VOL, H5E_CANTSET, FAIL, "can't set VOL object wrap context")
  
  done:
      FUNC_LEAVE_NOAPI(ret_value)
  } /* end H5VL_reset_vol_wrapper() */
  
  /*-------------------------------------------------------------------------
   * Function:    H5VL_wrap_register
   *
   * Purpose:     Wrap an object and register an ID for it
   *
   * Return:      SUCCEED / FAIL
   *
   *-------------------------------------------------------------------------
   */
  hid_t
  H5VL_wrap_register(H5I_type_t type, void *obj, hbool_t app_ref)
  {
      H5VL_wrap_ctx_t *vol_wrap_ctx = NULL;         /* Object wrapping context */
      void *           new_obj;                     /* Newly wrapped object */
      hid_t            ret_value = H5I_INVALID_HID; /* Return value */
  
      FUNC_ENTER_NOAPI(H5I_INVALID_HID)
  
      /* Sanity check */
      HDassert(obj);
  
      /* Retrieve the VOL object wrapping context */
      if (H5CX_get_vol_wrap_ctx((void **)&vol_wrap_ctx) < 0)
          HGOTO_ERROR(H5E_VOL, H5E_CANTGET, H5I_INVALID_HID, "can't get VOL object wrap context")
      if (NULL == vol_wrap_ctx || NULL == vol_wrap_ctx->connector)
          HGOTO_ERROR(H5E_VOL, H5E_BADVALUE, H5I_INVALID_HID,
                      "VOL object wrap context or its connector is NULL???")
  
      /* If the datatype is already VOL-managed, the datatype's vol_obj
       * field will get clobbered later, so disallow this.
       */
      if (type == H5I_DATATYPE)
          if (vol_wrap_ctx->connector->id == H5VL_NATIVE)
              if (TRUE == H5T_already_vol_managed((const H5T_t *)obj))
                  HGOTO_ERROR(H5E_VOL, H5E_BADTYPE, H5I_INVALID_HID, "can't wrap an uncommitted datatype")
  
      /* Wrap the object with VOL connector info */
      if (NULL == (new_obj = H5VL__wrap_obj(obj, type)))
          HGOTO_ERROR(H5E_VOL, H5E_CANTCREATE, H5I_INVALID_HID, "can't wrap library object")
  
      /* Get an ID for the object */
      if ((ret_value = H5VL_register_using_vol_id(type, new_obj, vol_wrap_ctx->connector->id, app_ref)) < 0)
          HGOTO_ERROR(H5E_VOL, H5E_CANTREGISTER, H5I_INVALID_HID, "unable to get an ID for the object")
  
  done:
      FUNC_LEAVE_NOAPI(ret_value)
  } /* end H5VL_wrap_register() */
  
  /*-------------------------------------------------------------------------
   * Function:    H5VL_check_plugin_load
   *
   * Purpose:     Check if a VOL connector matches the search criteria, and
   *              can be loaded.
   *
   * Note:        Matching the connector's name / value, but the connector
   *              having an incompatible version is not an error, but means
   *              that the connector isn't a "match".  Setting the SUCCEED
   *              value to FALSE and not failing for that case allows the
   *              plugin framework to keep looking for other DLLs that match
   *              and have a compatible version.
   *
   * Return:      SUCCEED / FAIL
   *
   *-------------------------------------------------------------------------
   */
  herr_t
  H5VL_check_plugin_load(const H5VL_class_t *cls, const H5PL_key_t *key, hbool_t *success)
  {
      herr_t ret_value = SUCCEED; /* Return value */
  
      FUNC_ENTER_NOAPI(FAIL)
  
      /* Sanity checks */
      HDassert(cls);
      HDassert(key);
      HDassert(success);
  
      /* Which kind of key are we looking for? */
      if (key->vol.kind == H5VL_GET_CONNECTOR_BY_NAME) {
          /* Check if plugin name matches VOL connector class name */
          if (cls->name && !HDstrcmp(cls->name, key->vol.u.name))
              *success = TRUE;
      } /* end if */
      else {
          /* Sanity check */
          HDassert(key->vol.kind == H5VL_GET_CONNECTOR_BY_VALUE);
  
          /* Check if plugin value matches VOL connector class value */
          if (cls->value == key->vol.u.value)
              *success = TRUE;
      } /* end else */
  
      /* Connector is a match, but might not be a compatible version */
      if (*success && cls->version != H5VL_VERSION)
          *success = FALSE;
  
  done:
      FUNC_LEAVE_NOAPI(ret_value)
  } /* end H5VL_check_plugin_load() */
  
  /*-------------------------------------------------------------------------
   * Function:    H5VL_setup_args
   *
   * Purpose:     Set up arguments to access an object
   *
   * Return:      SUCCEED / FAIL
   *
   *-------------------------------------------------------------------------
   */
  herr_t
  H5VL_setup_args(hid_t loc_id, H5I_type_t id_type, H5VL_object_t **vol_obj)
  {
      herr_t ret_value = SUCCEED; /* Return value */
  
      FUNC_ENTER_NOAPI(FAIL)
  
      /* Sanity check */
      HDassert(vol_obj);
  
      /* Get attribute pointer */
      if (NULL == (*vol_obj = (H5VL_object_t *)H5I_object_verify(loc_id, id_type)))
          HGOTO_ERROR(H5E_VOL, H5E_BADTYPE, FAIL, "not the correct type of ID")
  
      /* Set up collective metadata (if appropriate */
      if (H5CX_set_loc(loc_id) < 0)
          HGOTO_ERROR(H5E_VOL, H5E_CANTSET, FAIL, "can't set collective metadata read")
  
  done:
      FUNC_LEAVE_NOAPI(ret_value)
  } /* end H5VL_setup_args() */
  
  /*-------------------------------------------------------------------------
   * Function:    H5VL_setup_loc_args
   *
   * Purpose:     Set up arguments to access an object
   *
   * Return:      SUCCEED / FAIL
   *
   *-------------------------------------------------------------------------
   */
  herr_t
  H5VL_setup_loc_args(hid_t loc_id, H5VL_object_t **vol_obj, H5VL_loc_params_t *loc_params)
  {
      herr_t ret_value = SUCCEED; /* Return value */
  
      FUNC_ENTER_NOAPI(FAIL)
  
      /* Sanity check */
      HDassert(vol_obj);
      HDassert(loc_params);
  
      /* Get the location object */
      if (NULL == (*vol_obj = (H5VL_object_t *)H5VL_vol_object(loc_id)))
          HGOTO_ERROR(H5E_VOL, H5E_BADTYPE, FAIL, "not the correct type of ID")
  
      /* Set up collective metadata (if appropriate */
      if (H5CX_set_loc(loc_id) < 0)
          HGOTO_ERROR(H5E_VOL, H5E_CANTSET, FAIL, "can't set collective metadata read")
  
      /* Set location parameters */
      loc_params->type     = H5VL_OBJECT_BY_SELF;
      loc_params->obj_type = H5I_get_type(loc_id);
  
  done:
      FUNC_LEAVE_NOAPI(ret_value)
  } /* end H5VL_setup_loc_args() */
  
  /*-------------------------------------------------------------------------
   * Function:    H5VL_setup_acc_args
   *
   * Purpose:     Set up arguments to access an object
   *
   * Return:      SUCCEED / FAIL
   *
   *-------------------------------------------------------------------------
   */
  herr_t
  H5VL_setup_acc_args(hid_t loc_id, const H5P_libclass_t *libclass, hbool_t is_collective, hid_t *acspl_id,
                      H5VL_object_t **vol_obj, H5VL_loc_params_t *loc_params)
  {
      herr_t ret_value = SUCCEED; /* Return value */
  
      FUNC_ENTER_NOAPI(FAIL)
  
      /* Sanity check */
      HDassert(libclass);
      HDassert(acspl_id);
      HDassert(vol_obj);
      HDassert(loc_params);
  
      /* Verify access property list and set up collective metadata if appropriate */
      if (H5CX_set_apl(acspl_id, libclass, loc_id, is_collective) < 0)
          HGOTO_ERROR(H5E_VOL, H5E_CANTSET, FAIL, "can't set access property list info")
  
      /* Get the location object */
      if (NULL == (*vol_obj = (H5VL_object_t *)H5VL_vol_object(loc_id)))
          HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "invalid location identifier")
  
      /* Set location parameters */
      loc_params->type     = H5VL_OBJECT_BY_SELF;
      loc_params->obj_type = H5I_get_type(loc_id);
  
  done:
      FUNC_LEAVE_NOAPI(ret_value)
  } /* end H5VL_setup_acc_args() */
  
  /*-------------------------------------------------------------------------
   * Function:    H5VL_setup_self_args
   *
   * Purpose:     Set up arguments to access an object "by self"
   *
   * Return:      SUCCEED / FAIL
   *
   *-------------------------------------------------------------------------
   */
  herr_t
  H5VL_setup_self_args(hid_t loc_id, H5VL_object_t **vol_obj, H5VL_loc_params_t *loc_params)
  {
      herr_t ret_value = SUCCEED; /* Return value */
  
      FUNC_ENTER_NOAPI(FAIL)
  
      /* Sanity check */
      HDassert(vol_obj);
      HDassert(loc_params);
  
      /* Get the location object */
      if (NULL == (*vol_obj = (H5VL_object_t *)H5VL_vol_object(loc_id)))
          HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "invalid location identifier")
  
      /* Set location parameters */
      loc_params->type     = H5VL_OBJECT_BY_SELF;
      loc_params->obj_type = H5I_get_type(loc_id);
  
  done:
      FUNC_LEAVE_NOAPI(ret_value)
  } /* end H5VL_setup_self_args() */
  
  /*-------------------------------------------------------------------------
   * Function:    H5VL_setup_name_args
   *
   * Purpose:     Set up arguments to access an object "by name"
   *
   * Return:      SUCCEED / FAIL
   *
   *-------------------------------------------------------------------------
   */
  herr_t
  H5VL_setup_name_args(hid_t loc_id, const char *name, const H5P_libclass_t *libclass, hbool_t is_collective,
                       hid_t acspl_id, H5VL_object_t **vol_obj, H5VL_loc_params_t *loc_params)
  {
      herr_t ret_value = SUCCEED; /* Return value */
  
      FUNC_ENTER_NOAPI(FAIL)
  
      /* Sanity check */
      HDassert(vol_obj);
      HDassert(loc_params);
  
      /* Check args */
      if (!name)
          HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "name parameter cannot be NULL")
      if (!*name)
          HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "name parameter cannot be an empty string")
  
      /* Verify access property list and set up collective metadata if appropriate */
      if (H5CX_set_apl(&acspl_id, libclass, loc_id, is_collective) < 0)
          HGOTO_ERROR(H5E_VOL, H5E_CANTSET, FAIL, "can't set access property list info")
  
      /* Get the location object */
      if (NULL == (*vol_obj = (H5VL_object_t *)H5VL_vol_object(loc_id)))
          HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "invalid location identifier")
  
      /* Set up location parameters */
      loc_params->type                         = H5VL_OBJECT_BY_NAME;
      loc_params->loc_data.loc_by_name.name    = name;
      loc_params->loc_data.loc_by_name.lapl_id = acspl_id;
      loc_params->obj_type                     = H5I_get_type(loc_id);
  
  done:
      FUNC_LEAVE_NOAPI(ret_value)
  } /* end H5VL_setup_name_args() */
  
  /*-------------------------------------------------------------------------
   * Function:    H5VL_setup_idx_args
   *
   * Purpose:     Set up arguments to access an object "by idx"
   *
   * Return:      SUCCEED / FAIL
   *
   *-------------------------------------------------------------------------
   */
  herr_t
  H5VL_setup_idx_args(hid_t loc_id, const char *name, H5_index_t idx_type, H5_iter_order_t order, hsize_t n,
                      const H5P_libclass_t *libclass, hbool_t is_collective, hid_t acspl_id,
                      H5VL_object_t **vol_obj, H5VL_loc_params_t *loc_params)
  {
      herr_t ret_value = SUCCEED; /* Return value */
  
      FUNC_ENTER_NOAPI(FAIL)
  
      /* Sanity check */
      HDassert(vol_obj);
      HDassert(loc_params);
  
      /* Check args */
      if (!name)
          HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "name parameter cannot be NULL")
      if (!*name)
          HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "name parameter cannot be an empty string")
      if (idx_type <= H5_INDEX_UNKNOWN || idx_type >= H5_INDEX_N)
          HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid index type specified")
      if (order <= H5_ITER_UNKNOWN || order >= H5_ITER_N)
          HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid iteration order specified")
  
      /* Verify access property list and set up collective metadata if appropriate */
      if (H5CX_set_apl(&acspl_id, libclass, loc_id, is_collective) < 0)
          HGOTO_ERROR(H5E_VOL, H5E_CANTSET, FAIL, "can't set access property list info")
  
      /* Get the location object */
      if (NULL == (*vol_obj = (H5VL_object_t *)H5VL_vol_object(loc_id)))
          HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "invalid location identifier")
  
      /* Set location parameters */
      loc_params->type                         = H5VL_OBJECT_BY_IDX;
      loc_params->loc_data.loc_by_idx.name     = name;
      loc_params->loc_data.loc_by_idx.idx_type = idx_type;
      loc_params->loc_data.loc_by_idx.order    = order;
      loc_params->loc_data.loc_by_idx.n        = n;
      loc_params->loc_data.loc_by_idx.lapl_id  = acspl_id;
      loc_params->obj_type                     = H5I_get_type(loc_id);
  
  done:
      FUNC_LEAVE_NOAPI(ret_value)
  } /* end H5VL_setup_idx_args() */
  
  /*-------------------------------------------------------------------------
   * Function:    H5VL_setup_token_args
   *
   * Purpose:     Set up arguments to access an object by token
   *
   * Return:      SUCCEED / FAIL
   *
   *-------------------------------------------------------------------------
   */
  herr_t
  H5VL_setup_token_args(hid_t loc_id, H5O_token_t *obj_token, H5VL_object_t **vol_obj,
                        H5VL_loc_params_t *loc_params)
  {
      herr_t ret_value = SUCCEED; /* Return value */
  
      FUNC_ENTER_NOAPI(FAIL)
  
      /* Sanity check */
      HDassert(vol_obj);
      HDassert(loc_params);
  
      /* Get the location object */
      if (NULL == (*vol_obj = (H5VL_object_t *)H5VL_vol_object(loc_id)))
          HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "invalid location identifier")
  
      /* Set location parameters */
      loc_params->type                        = H5VL_OBJECT_BY_TOKEN;
      loc_params->loc_data.loc_by_token.token = obj_token;
      loc_params->obj_type                    = H5I_get_type(loc_id);
  
  done:
      FUNC_LEAVE_NOAPI(ret_value)
  } /* end H5VL_setup_token_args() */
  