/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * Copyright by The HDF Group.                                               *
 * All rights reserved.                                                      *
 *                                                                           *
 * This file is part of HDF5.  The full HDF5 copyright notice, including     *
 * terms governing use, modification, and redistribution, is contained in    *
 * the COPYING file, which can be found at the root of the source code       *
 * distribution tree, or in https://www.hdfgroup.org/licenses.               *
 * If you do not have access to either file, you may request a copy from     *
 * help@hdfgroup.org.                                                        *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

/*
 * Purpose:     This is a "pass through" VOL connector, which forwards each
 *              VOL callback to an underlying connector.
 *
 *              It is designed as an example VOL connector for developers to
 *              use when creating new connectors, especially connectors that
 *              are outside of the HDF5 library.  As such, it should _NOT_
 *              include _any_ private HDF5 header files.  This connector should
 *              therefore only make public HDF5 API calls and use standard C /
 *              POSIX calls.
 *
 *              Note that the HDF5 error stack must be preserved on code paths
 *              that could be invoked when the underlying VOL connector's
 *              callback can fail.
 *
 */

/* Header files needed */
/* Do NOT include private HDF5 files here! */
#include <assert.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/* Public HDF5 file */
#include "hdf5.h"

/* This connector's header */
#include "H5VLpassthru.h"

/**********/
/* Macros */
/**********/

/* Whether to display log messge when callback is invoked */
/* (Uncomment to enable) */
/* #define ENABLE_PASSTHRU_LOGGING */

/* Hack for missing va_copy() in old Visual Studio editions
 * (from H5win2_defs.h - used on VS2012 and earlier)
 */
#if defined(_WIN32) && defined(_MSC_VER) && (_MSC_VER < 1800)
#define va_copy(D, S) ((D) = (S))
#endif

/************/
/* Typedefs */
/************/

/* The pass through VOL info object */
typedef struct H5VL_pass_through_t {
    hid_t under_vol_id; /* ID for underlying VOL connector */
    void *under_object; /* Info object for underlying VOL connector */
} H5VL_pass_through_t;

/* The pass through VOL wrapper context */
typedef struct H5VL_pass_through_wrap_ctx_t {
    hid_t under_vol_id;   /* VOL ID for under VOL */
    void *under_wrap_ctx; /* Object wrapping context for under VOL */
} H5VL_pass_through_wrap_ctx_t;

/********************* */
/* Function prototypes */
/********************* */

/* Helper routines */
static herr_t H5VL_pass_through_file_specific_reissue(void *obj, hid_t connector_id,
                                                      H5VL_file_specific_t specific_type, hid_t dxpl_id,
                                                      void **req, ...);
static herr_t H5VL_pass_through_request_specific_reissue(void *obj, hid_t connector_id,
                                                         H5VL_request_specific_t specific_type, ...);
static herr_t H5VL_pass_through_link_create_reissue(H5VL_link_create_type_t create_type, void *obj,
                                                    const H5VL_loc_params_t *loc_params, hid_t connector_id,
                                                    hid_t lcpl_id, hid_t lapl_id, hid_t dxpl_id, void **req,
                                                    ...);
static H5VL_pass_through_t *H5VL_pass_through_new_obj(void *under_obj, hid_t under_vol_id);
static herr_t               H5VL_pass_through_free_obj(H5VL_pass_through_t *obj);

/* "Management" callbacks */
static herr_t H5VL_pass_through_init(hid_t vipl_id);
static herr_t H5VL_pass_through_term(void);

/* VOL info callbacks */
static void * H5VL_pass_through_info_copy(const void *info);
static herr_t H5VL_pass_through_info_cmp(int *cmp_value, const void *info1, const void *info2);
static herr_t H5VL_pass_through_info_free(void *info);
static herr_t H5VL_pass_through_info_to_str(const void *info, char **str);
static herr_t H5VL_pass_through_str_to_info(const char *str, void **info);

/* VOL object wrap / retrieval callbacks */
static void * H5VL_pass_through_get_object(const void *obj);
static herr_t H5VL_pass_through_get_wrap_ctx(const void *obj, void **wrap_ctx);
static void * H5VL_pass_through_wrap_object(void *obj, H5I_type_t obj_type, void *wrap_ctx);
static void * H5VL_pass_through_unwrap_object(void *obj);
static herr_t H5VL_pass_through_free_wrap_ctx(void *obj);

/* Attribute callbacks */
static void * H5VL_pass_through_attr_create(void *obj, const H5VL_loc_params_t *loc_params, const char *name,
                                            hid_t type_id, hid_t space_id, hid_t acpl_id, hid_t aapl_id,
                                            hid_t dxpl_id, void **req);
static void * H5VL_pass_through_attr_open(void *obj, const H5VL_loc_params_t *loc_params, const char *name,
                                          hid_t aapl_id, hid_t dxpl_id, void **req);
static herr_t H5VL_pass_through_attr_read(void *attr, hid_t mem_type_id, void *buf, hid_t dxpl_id,
                                          void **req);
static herr_t H5VL_pass_through_attr_write(void *attr, hid_t mem_type_id, const void *buf, hid_t dxpl_id,
                                           void **req);
static herr_t H5VL_pass_through_attr_get(void *obj, H5VL_attr_get_t get_type, hid_t dxpl_id, void **req,
                                         va_list arguments);
static herr_t H5VL_pass_through_attr_specific(void *obj, const H5VL_loc_params_t *loc_params,
                                              H5VL_attr_specific_t specific_type, hid_t dxpl_id, void **req,
                                              va_list arguments);
static herr_t H5VL_pass_through_attr_optional(void *obj, H5VL_attr_optional_t opt_type, hid_t dxpl_id,
                                              void **req, va_list arguments);
static herr_t H5VL_pass_through_attr_close(void *attr, hid_t dxpl_id, void **req);

/* Dataset callbacks */
static void * H5VL_pass_through_dataset_create(void *obj, const H5VL_loc_params_t *loc_params,
                                               const char *name, hid_t lcpl_id, hid_t type_id, hid_t space_id,
                                               hid_t dcpl_id, hid_t dapl_id, hid_t dxpl_id, void **req);
static void * H5VL_pass_through_dataset_open(void *obj, const H5VL_loc_params_t *loc_params, const char *name,
                                             hid_t dapl_id, hid_t dxpl_id, void **req);
static herr_t H5VL_pass_through_dataset_read(void *dset, hid_t mem_type_id, hid_t mem_space_id,
                                             hid_t file_space_id, hid_t plist_id, void *buf, void **req);
static herr_t H5VL_pass_through_dataset_write(void *dset, hid_t mem_type_id, hid_t mem_space_id,
                                              hid_t file_space_id, hid_t plist_id, const void *buf,
                                              void **req);
static herr_t H5VL_pass_through_dataset_get(void *dset, H5VL_dataset_get_t get_type, hid_t dxpl_id,
                                            void **req, va_list arguments);
static herr_t H5VL_pass_through_dataset_specific(void *obj, H5VL_dataset_specific_t specific_type,
                                                 hid_t dxpl_id, void **req, va_list arguments);
static herr_t H5VL_pass_through_dataset_optional(void *obj, H5VL_dataset_optional_t opt_type, hid_t dxpl_id,
                                                 void **req, va_list arguments);
static herr_t H5VL_pass_through_dataset_close(void *dset, hid_t dxpl_id, void **req);

/* Datatype callbacks */
static void *H5VL_pass_through_datatype_commit(void *obj, const H5VL_loc_params_t *loc_params,
                                               const char *name, hid_t type_id, hid_t lcpl_id, hid_t tcpl_id,
                                               hid_t tapl_id, hid_t dxpl_id, void **req);
static void *H5VL_pass_through_datatype_open(void *obj, const H5VL_loc_params_t *loc_params, const char *name,
                                             hid_t tapl_id, hid_t dxpl_id, void **req);
static herr_t H5VL_pass_through_datatype_get(void *dt, H5VL_datatype_get_t get_type, hid_t dxpl_id,
                                             void **req, va_list arguments);
static herr_t H5VL_pass_through_datatype_specific(void *obj, H5VL_datatype_specific_t specific_type,
                                                  hid_t dxpl_id, void **req, va_list arguments);
static herr_t H5VL_pass_through_datatype_optional(void *obj, H5VL_datatype_optional_t opt_type, hid_t dxpl_id,
                                                  void **req, va_list arguments);
static herr_t H5VL_pass_through_datatype_close(void *dt, hid_t dxpl_id, void **req);

/* File callbacks */
static void * H5VL_pass_through_file_create(const char *name, unsigned flags, hid_t fcpl_id, hid_t fapl_id,
                                            hid_t dxpl_id, void **req);
static void * H5VL_pass_through_file_open(const char *name, unsigned flags, hid_t fapl_id, hid_t dxpl_id,
                                          void **req);
static herr_t H5VL_pass_through_file_get(void *file, H5VL_file_get_t get_type, hid_t dxpl_id, void **req,
                                         va_list arguments);
static herr_t H5VL_pass_through_file_specific(void *file, H5VL_file_specific_t specific_type, hid_t dxpl_id,
                                              void **req, va_list arguments);
static herr_t H5VL_pass_through_file_optional(void *file, H5VL_file_optional_t opt_type, hid_t dxpl_id,
                                              void **req, va_list arguments);
static herr_t H5VL_pass_through_file_close(void *file, hid_t dxpl_id, void **req);

/* Group callbacks */
static void * H5VL_pass_through_group_create(void *obj, const H5VL_loc_params_t *loc_params, const char *name,
                                             hid_t lcpl_id, hid_t gcpl_id, hid_t gapl_id, hid_t dxpl_id,
                                             void **req);
static void * H5VL_pass_through_group_open(void *obj, const H5VL_loc_params_t *loc_params, const char *name,
                                           hid_t gapl_id, hid_t dxpl_id, void **req);
static herr_t H5VL_pass_through_group_get(void *obj, H5VL_group_get_t get_type, hid_t dxpl_id, void **req,
                                          va_list arguments);
static herr_t H5VL_pass_through_group_specific(void *obj, H5VL_group_specific_t specific_type, hid_t dxpl_id,
                                               void **req, va_list arguments);
static herr_t H5VL_pass_through_group_optional(void *obj, H5VL_group_optional_t opt_type, hid_t dxpl_id,
                                               void **req, va_list arguments);
static herr_t H5VL_pass_through_group_close(void *grp, hid_t dxpl_id, void **req);

/* Link callbacks */
static herr_t H5VL_pass_through_link_create(H5VL_link_create_type_t create_type, void *obj,
                                            const H5VL_loc_params_t *loc_params, hid_t lcpl_id, hid_t lapl_id,
                                            hid_t dxpl_id, void **req, va_list arguments);
static herr_t H5VL_pass_through_link_copy(void *src_obj, const H5VL_loc_params_t *loc_params1, void *dst_obj,
                                          const H5VL_loc_params_t *loc_params2, hid_t lcpl_id, hid_t lapl_id,
                                          hid_t dxpl_id, void **req);
static herr_t H5VL_pass_through_link_move(void *src_obj, const H5VL_loc_params_t *loc_params1, void *dst_obj,
                                          const H5VL_loc_params_t *loc_params2, hid_t lcpl_id, hid_t lapl_id,
                                          hid_t dxpl_id, void **req);
static herr_t H5VL_pass_through_link_get(void *obj, const H5VL_loc_params_t *loc_params,
                                         H5VL_link_get_t get_type, hid_t dxpl_id, void **req,
                                         va_list arguments);
static herr_t H5VL_pass_through_link_specific(void *obj, const H5VL_loc_params_t *loc_params,
                                              H5VL_link_specific_t specific_type, hid_t dxpl_id, void **req,
                                              va_list arguments);
static herr_t H5VL_pass_through_link_optional(void *obj, H5VL_link_optional_t opt_type, hid_t dxpl_id,
                                              void **req, va_list arguments);

/* Object callbacks */
static void * H5VL_pass_through_object_open(void *obj, const H5VL_loc_params_t *loc_params,
                                            H5I_type_t *opened_type, hid_t dxpl_id, void **req);
static herr_t H5VL_pass_through_object_copy(void *src_obj, const H5VL_loc_params_t *src_loc_params,
                                            const char *src_name, void *dst_obj,
                                            const H5VL_loc_params_t *dst_loc_params, const char *dst_name,
                                            hid_t ocpypl_id, hid_t lcpl_id, hid_t dxpl_id, void **req);
static herr_t H5VL_pass_through_object_get(void *obj, const H5VL_loc_params_t *loc_params,
                                           H5VL_object_get_t get_type, hid_t dxpl_id, void **req,
                                           va_list arguments);
static herr_t H5VL_pass_through_object_specific(void *obj, const H5VL_loc_params_t *loc_params,
                                                H5VL_object_specific_t specific_type, hid_t dxpl_id,
                                                void **req, va_list arguments);
static herr_t H5VL_pass_through_object_optional(void *obj, H5VL_object_optional_t opt_type, hid_t dxpl_id,
                                                void **req, va_list arguments);

/* Container/connector introspection callbacks */
static herr_t H5VL_pass_through_introspect_get_conn_cls(void *obj, H5VL_get_conn_lvl_t lvl,
                                                        const H5VL_class_t **conn_cls);
static herr_t H5VL_pass_through_introspect_opt_query(void *obj, H5VL_subclass_t cls, int opt_type,
                                                     hbool_t *supported);

/* Async request callbacks */
static herr_t H5VL_pass_through_request_wait(void *req, uint64_t timeout, H5ES_status_t *status);
static herr_t H5VL_pass_through_request_notify(void *obj, H5VL_request_notify_t cb, void *ctx);
static herr_t H5VL_pass_through_request_cancel(void *req);
static herr_t H5VL_pass_through_request_specific(void *req, H5VL_request_specific_t specific_type,
                                                 va_list arguments);
static herr_t H5VL_pass_through_request_optional(void *req, H5VL_request_optional_t opt_type,
                                                 va_list arguments);
static herr_t H5VL_pass_through_request_free(void *req);

/* Blob callbacks */
static herr_t H5VL_pass_through_blob_put(void *obj, const void *buf, size_t size, void *blob_id, void *ctx);
static herr_t H5VL_pass_through_blob_get(void *obj, const void *blob_id, void *buf, size_t size, void *ctx);
static herr_t H5VL_pass_through_blob_specific(void *obj, void *blob_id, H5VL_blob_specific_t specific_type,
                                              va_list arguments);
static herr_t H5VL_pass_through_blob_optional(void *obj, void *blob_id, H5VL_blob_optional_t opt_type,
                                              va_list arguments);

/* Token callbacks */
static herr_t H5VL_pass_through_token_cmp(void *obj, const H5O_token_t *token1, const H5O_token_t *token2,
                                          int *cmp_value);
static herr_t H5VL_pass_through_token_to_str(void *obj, H5I_type_t obj_type, const H5O_token_t *token,
                                             char **token_str);
static herr_t H5VL_pass_through_token_from_str(void *obj, H5I_type_t obj_type, const char *token_str,
                                               H5O_token_t *token);

/* Generic optional callback */
static herr_t H5VL_pass_through_optional(void *obj, int op_type, hid_t dxpl_id, void **req,
                                         va_list arguments);

/*******************/
/* Local variables */
/*******************/

/* Pass through VOL connector class struct */
static const H5VL_class_t H5VL_pass_through_g = {
    H5VL_VERSION,                            /* VOL class struct version */
    (H5VL_class_value_t)H5VL_PASSTHRU_VALUE, /* value        */
    H5VL_PASSTHRU_NAME,                      /* name         */
    0,                                       /* capability flags */
    H5VL_pass_through_init,                  /* initialize   */
    H5VL_pass_through_term,                  /* terminate    */
    {
        /* info_cls */
        sizeof(H5VL_pass_through_info_t), /* size    */
        H5VL_pass_through_info_copy,      /* copy    */
        H5VL_pass_through_info_cmp,       /* compare */
        H5VL_pass_through_info_free,      /* free    */
        H5VL_pass_through_info_to_str,    /* to_str  */
        H5VL_pass_through_str_to_info     /* from_str */
    },
    {
        /* wrap_cls */
        H5VL_pass_through_get_object,    /* get_object   */
        H5VL_pass_through_get_wrap_ctx,  /* get_wrap_ctx */
        H5VL_pass_through_wrap_object,   /* wrap_object  */
        H5VL_pass_through_unwrap_object, /* unwrap_object */
        H5VL_pass_through_free_wrap_ctx  /* free_wrap_ctx */
    },
    {
        /* attribute_cls */
        H5VL_pass_through_attr_create,   /* create */
        H5VL_pass_through_attr_open,     /* open */
        H5VL_pass_through_attr_read,     /* read */
        H5VL_pass_through_attr_write,    /* write */
        H5VL_pass_through_attr_get,      /* get */
        H5VL_pass_through_attr_specific, /* specific */
        H5VL_pass_through_attr_optional, /* optional */
        H5VL_pass_through_attr_close     /* close */
    },
    {
        /* dataset_cls */
        H5VL_pass_through_dataset_create,   /* create */
        H5VL_pass_through_dataset_open,     /* open */
        H5VL_pass_through_dataset_read,     /* read */
        H5VL_pass_through_dataset_write,    /* write */
        H5VL_pass_through_dataset_get,      /* get */
        H5VL_pass_through_dataset_specific, /* specific */
        H5VL_pass_through_dataset_optional, /* optional */
        H5VL_pass_through_dataset_close     /* close */
    },
    {
        /* datatype_cls */
        H5VL_pass_through_datatype_commit,   /* commit */
        H5VL_pass_through_datatype_open,     /* open */
        H5VL_pass_through_datatype_get,      /* get_size */
        H5VL_pass_through_datatype_specific, /* specific */
        H5VL_pass_through_datatype_optional, /* optional */
        H5VL_pass_through_datatype_close     /* close */
    },
    {
        /* file_cls */
        H5VL_pass_through_file_create,   /* create */
        H5VL_pass_through_file_open,     /* open */
        H5VL_pass_through_file_get,      /* get */
        H5VL_pass_through_file_specific, /* specific */
        H5VL_pass_through_file_optional, /* optional */
        H5VL_pass_through_file_close     /* close */
    },
    {
        /* group_cls */
        H5VL_pass_through_group_create,   /* create */
        H5VL_pass_through_group_open,     /* open */
        H5VL_pass_through_group_get,      /* get */
        H5VL_pass_through_group_specific, /* specific */
        H5VL_pass_through_group_optional, /* optional */
        H5VL_pass_through_group_close     /* close */
    },
    {
        /* link_cls */
        H5VL_pass_through_link_create,   /* create */
        H5VL_pass_through_link_copy,     /* copy */
        H5VL_pass_through_link_move,     /* move */
        H5VL_pass_through_link_get,      /* get */
        H5VL_pass_through_link_specific, /* specific */
        H5VL_pass_through_link_optional  /* optional */
    },
    {
        /* object_cls */
        H5VL_pass_through_object_open,     /* open */
        H5VL_pass_through_object_copy,     /* copy */
        H5VL_pass_through_object_get,      /* get */
        H5VL_pass_through_object_specific, /* specific */
        H5VL_pass_through_object_optional  /* optional */
    },
    {
        /* introspect_cls */
        H5VL_pass_through_introspect_get_conn_cls, /* get_conn_cls */
        H5VL_pass_through_introspect_opt_query,    /* opt_query */
    },
    {
        /* request_cls */
        H5VL_pass_through_request_wait,     /* wait */
        H5VL_pass_through_request_notify,   /* notify */
        H5VL_pass_through_request_cancel,   /* cancel */
        H5VL_pass_through_request_specific, /* specific */
        H5VL_pass_through_request_optional, /* optional */
        H5VL_pass_through_request_free      /* free */
    },
    {
        /* blob_cls */
        H5VL_pass_through_blob_put,      /* put */
        H5VL_pass_through_blob_get,      /* get */
        H5VL_pass_through_blob_specific, /* specific */
        H5VL_pass_through_blob_optional  /* optional */
    },
    {
        /* token_cls */
        H5VL_pass_through_token_cmp,     /* cmp */
        H5VL_pass_through_token_to_str,  /* to_str */
        H5VL_pass_through_token_from_str /* from_str */
    },
    H5VL_pass_through_optional /* optional */
};

/* The connector identification number, initialized at runtime */
static hid_t H5VL_PASSTHRU_g = H5I_INVALID_HID;

/*-------------------------------------------------------------------------
 * Function:    H5VL__pass_through_new_obj
 *
 * Purpose:     Create a new pass through object for an underlying object
 *
 * Return:      Success:    Pointer to the new pass through object
 *              Failure:    NULL
 *
 * Programmer:  Quincey Koziol
 *              Monday, December 3, 2018
 *
 *-------------------------------------------------------------------------
 */
static H5VL_pass_through_t *
H5VL_pass_through_new_obj(void *under_obj, hid_t under_vol_id)
{
    H5VL_pass_through_t *new_obj;

    new_obj               = (H5VL_pass_through_t *)calloc(1, sizeof(H5VL_pass_through_t));
    new_obj->under_object = under_obj;
    new_obj->under_vol_id = under_vol_id;
    H5Iinc_ref(new_obj->under_vol_id);

    return new_obj;
} /* end H5VL__pass_through_new_obj() */

/*-------------------------------------------------------------------------
 * Function:    H5VL__pass_through_free_obj
 *
 * Purpose:     Release a pass through object
 *
 * Note:	Take care to preserve the current HDF5 error stack
 *		when calling HDF5 API calls.
 *
 * Return:      Success:    0
 *              Failure:    -1
 *
 * Programmer:  Quincey Koziol
 *              Monday, December 3, 2018
 *
 *-------------------------------------------------------------------------
 */
static herr_t
H5VL_pass_through_free_obj(H5VL_pass_through_t *obj)
{
    hid_t err_id;

    err_id = H5Eget_current_stack();

    H5Idec_ref(obj->under_vol_id);

    H5Eset_current_stack(err_id);

    free(obj);

    return 0;
} /* end H5VL__pass_through_free_obj() */

/*-------------------------------------------------------------------------
 * Function:    H5VL_pass_through_register
 *
 * Purpose:     Register the pass-through VOL connector and retrieve an ID
 *              for it.
 *
 * Return:      Success:    The ID for the pass-through VOL connector
 *              Failure:    -1
 *
 * Programmer:  Quincey Koziol
 *              Wednesday, November 28, 2018
 *
 *-------------------------------------------------------------------------
 */
hid_t
H5VL_pass_through_register(void)
{
    /* Singleton register the pass-through VOL connector ID */
    if (H5VL_PASSTHRU_g < 0)
        H5VL_PASSTHRU_g = H5VLregister_connector(&H5VL_pass_through_g, H5P_DEFAULT);

    return H5VL_PASSTHRU_g;
} /* end H5VL_pass_through_register() */

/*-------------------------------------------------------------------------
 * Function:    H5VL_pass_through_init
 *
 * Purpose:     Initialize this VOL connector, performing any necessary
 *              operations for the connector that will apply to all containers
 *              accessed with the connector.
 *
 * Return:      Success:    0
 *              Failure:    -1
 *
 *-------------------------------------------------------------------------
 */
static herr_t
H5VL_pass_through_init(hid_t vipl_id)
{
#ifdef ENABLE_PASSTHRU_LOGGING
    printf("------- PASS THROUGH VOL INIT\n");
#endif

    /* Shut compiler up about unused parameter */
    (void)vipl_id;

    return 0;
} /* end H5VL_pass_through_init() */

/*---------------------------------------------------------------------------
 * Function:    H5VL_pass_through_term
 *
 * Purpose:     Terminate this VOL connector, performing any necessary
 *              operations for the connector that release connector-wide
 *              resources (usually created / initialized with the 'init'
 *              callback).
 *
 * Return:      Success:    0
 *              Failure:    (Can't fail)
 *
 *---------------------------------------------------------------------------
 */
static herr_t
H5VL_pass_through_term(void)
{
#ifdef ENABLE_PASSTHRU_LOGGING
    printf("------- PASS THROUGH VOL TERM\n");
#endif

    /* Reset VOL ID */
    H5VL_PASSTHRU_g = H5I_INVALID_HID;

    return 0;
} /* end H5VL_pass_through_term() */

/*---------------------------------------------------------------------------
 * Function:    H5VL_pass_through_info_copy
 *
 * Purpose:     Duplicate the connector's info object.
 *
 * Returns:     Success:    New connector info object
 *              Failure:    NULL
 *
 *---------------------------------------------------------------------------
 */
static void *
H5VL_pass_through_info_copy(const void *_info)
{
    const H5VL_pass_through_info_t *info = (const H5VL_pass_through_info_t *)_info;
    H5VL_pass_through_info_t *      new_info;

#ifdef ENABLE_PASSTHRU_LOGGING
    printf("------- PASS THROUGH VOL INFO Copy\n");
#endif

    /* Allocate new VOL info struct for the pass through connector */
    new_info = (H5VL_pass_through_info_t *)calloc(1, sizeof(H5VL_pass_through_info_t));

    /* Increment reference count on underlying VOL ID, and copy the VOL info */
    new_info->under_vol_id = info->under_vol_id;
    H5Iinc_ref(new_info->under_vol_id);
    if (info->under_vol_info)
        H5VLcopy_connector_info(new_info->under_vol_id, &(new_info->under_vol_info), info->under_vol_info);

    return new_info;
} /* end H5VL_pass_through_info_copy() */

/*---------------------------------------------------------------------------
 * Function:    H5VL_pass_through_info_cmp
 *
 * Purpose:     Compare two of the connector's info objects, setting *cmp_value,
 *              following the same rules as strcmp().
 *
 * Return:      Success:    0
 *              Failure:    -1
 *
 *---------------------------------------------------------------------------
 */
static herr_t
H5VL_pass_through_info_cmp(int *cmp_value, const void *_info1, const void *_info2)
{
    const H5VL_pass_through_info_t *info1 = (const H5VL_pass_through_info_t *)_info1;
    const H5VL_pass_through_info_t *info2 = (const H5VL_pass_through_info_t *)_info2;

#ifdef ENABLE_PASSTHRU_LOGGING
    printf("------- PASS THROUGH VOL INFO Compare\n");
#endif

    /* Sanity checks */
    assert(info1);
    assert(info2);

    /* Initialize comparison value */
    *cmp_value = 0;

    /* Compare under VOL connector classes */
    H5VLcmp_connector_cls(cmp_value, info1->under_vol_id, info2->under_vol_id);
    if (*cmp_value != 0)
        return 0;

    /* Compare under VOL connector info objects */
    H5VLcmp_connector_info(cmp_value, info1->under_vol_id, info1->under_vol_info, info2->under_vol_info);
    if (*cmp_value != 0)
        return 0;

    return 0;
} /* end H5VL_pass_through_info_cmp() */

/*---------------------------------------------------------------------------
 * Function:    H5VL_pass_through_info_free
 *
 * Purpose:     Release an info object for the connector.
 *
 * Note:	Take care to preserve the current HDF5 error stack
 *		when calling HDF5 API calls.
 *
 * Return:      Success:    0
 *              Failure:    -1
 *
 *---------------------------------------------------------------------------
 */
static herr_t
H5VL_pass_through_info_free(void *_info)
{
    H5VL_pass_through_info_t *info = (H5VL_pass_through_info_t *)_info;
    hid_t                     err_id;

#ifdef ENABLE_PASSTHRU_LOGGING
    printf("------- PASS THROUGH VOL INFO Free\n");
#endif

    err_id = H5Eget_current_stack();

    /* Release underlying VOL ID and info */
    if (info->under_vol_info)
        H5VLfree_connector_info(info->under_vol_id, info->under_vol_info);
    H5Idec_ref(info->under_vol_id);

    H5Eset_current_stack(err_id);

    /* Free pass through info object itself */
    free(info);

    return 0;
} /* end H5VL_pass_through_info_free() */

/*---------------------------------------------------------------------------
 * Function:    H5VL_pass_through_info_to_str
 *
 * Purpose:     Serialize an info object for this connector into a string
 *
 * Return:      Success:    0
 *              Failure:    -1
 *
 *---------------------------------------------------------------------------
 */
static herr_t
H5VL_pass_through_info_to_str(const void *_info, char **str)
{
    const H5VL_pass_through_info_t *info              = (const H5VL_pass_through_info_t *)_info;
    H5VL_class_value_t              under_value       = (H5VL_class_value_t)-1;
    char *                          under_vol_string  = NULL;
    size_t                          under_vol_str_len = 0;

#ifdef ENABLE_PASSTHRU_LOGGING
    printf("------- PASS THROUGH VOL INFO To String\n");
#endif

    /* Get value and string for underlying VOL connector */
    H5VLget_value(info->under_vol_id, &under_value);
    H5VLconnector_info_to_str(info->under_vol_info, info->under_vol_id, &under_vol_string);

    /* Determine length of underlying VOL info string */
    if (under_vol_string)
        under_vol_str_len = strlen(under_vol_string);

    /* Allocate space for our info */
    *str = (char *)H5allocate_memory(32 + under_vol_str_len, (hbool_t)0);
    assert(*str);

    /* Encode our info
     * Normally we'd use snprintf() here for a little extra safety, but that
     * call had problems on Windows until recently. So, to be as platform-independent
     * as we can, we're using sprintf() instead.
     */
    sprintf(*str, "under_vol=%u;under_info={%s}", (unsigned)under_value,
            (under_vol_string ? under_vol_string : ""));

    return 0;
} /* end H5VL_pass_through_info_to_str() */

/*---------------------------------------------------------------------------
 * Function:    H5VL_pass_through_str_to_info
 *
 * Purpose:     Deserialize a string into an info object for this connector.
 *
 * Return:      Success:    0
 *              Failure:    -1
 *
 *---------------------------------------------------------------------------
 */
static herr_t
H5VL_pass_through_str_to_info(const char *str, void **_info)
{
    H5VL_pass_through_info_t *info;
    unsigned                  under_vol_value;
    const char *              under_vol_info_start, *under_vol_info_end;
    hid_t                     under_vol_id;
    void *                    under_vol_info = NULL;

#ifdef ENABLE_PASSTHRU_LOGGING
    printf("------- PASS THROUGH VOL INFO String To Info\n");
#endif

    /* Retrieve the underlying VOL connector value and info */
    sscanf(str, "under_vol=%u;", &under_vol_value);
    under_vol_id         = H5VLregister_connector_by_value((H5VL_class_value_t)under_vol_value, H5P_DEFAULT);
    under_vol_info_start = strchr(str, '{');
    under_vol_info_end   = strrchr(str, '}');
    assert(under_vol_info_end > under_vol_info_start);
    if (under_vol_info_end != (under_vol_info_start + 1)) {
        char *under_vol_info_str;

        under_vol_info_str = (char *)malloc((size_t)(under_vol_info_end - under_vol_info_start));
        memcpy(under_vol_info_str, under_vol_info_start + 1,
               (size_t)((under_vol_info_end - under_vol_info_start) - 1));
        *(under_vol_info_str + (under_vol_info_end - under_vol_info_start)) = '\0';

        H5VLconnector_str_to_info(under_vol_info_str, under_vol_id, &under_vol_info);

        free(under_vol_info_str);
    } /* end else */

    /* Allocate new pass-through VOL connector info and set its fields */
    info                 = (H5VL_pass_through_info_t *)calloc(1, sizeof(H5VL_pass_through_info_t));
    info->under_vol_id   = under_vol_id;
    info->under_vol_info = under_vol_info;

    /* Set return value */
    *_info = info;

    return 0;
} /* end H5VL_pass_through_str_to_info() */

/*---------------------------------------------------------------------------
 * Function:    H5VL_pass_through_get_object
 *
 * Purpose:     Retrieve the 'data' for a VOL object.
 *
 * Return:      Success:    0
 *              Failure:    -1
 *
 *---------------------------------------------------------------------------
 */
static void *
H5VL_pass_through_get_object(const void *obj)
{
    const H5VL_pass_through_t *o = (const H5VL_pass_through_t *)obj;

#ifdef ENABLE_PASSTHRU_LOGGING
    printf("------- PASS THROUGH VOL Get object\n");
#endif

    return H5VLget_object(o->under_object, o->under_vol_id);
} /* end H5VL_pass_through_get_object() */

/*---------------------------------------------------------------------------
 * Function:    H5VL_pass_through_get_wrap_ctx
 *
 * Purpose:     Retrieve a "wrapper context" for an object
 *
 * Return:      Success:    0
 *              Failure:    -1
 *
 *---------------------------------------------------------------------------
 */
static herr_t
H5VL_pass_through_get_wrap_ctx(const void *obj, void **wrap_ctx)
{
    const H5VL_pass_through_t *   o = (const H5VL_pass_through_t *)obj;
    H5VL_pass_through_wrap_ctx_t *new_wrap_ctx;

#ifdef ENABLE_PASSTHRU_LOGGING
    printf("------- PASS THROUGH VOL WRAP CTX Get\n");
#endif

    /* Allocate new VOL object wrapping context for the pass through connector */
    new_wrap_ctx = (H5VL_pass_through_wrap_ctx_t *)calloc(1, sizeof(H5VL_pass_through_wrap_ctx_t));

    /* Increment reference count on underlying VOL ID, and copy the VOL info */
    new_wrap_ctx->under_vol_id = o->under_vol_id;
    H5Iinc_ref(new_wrap_ctx->under_vol_id);
    H5VLget_wrap_ctx(o->under_object, o->under_vol_id, &new_wrap_ctx->under_wrap_ctx);

    /* Set wrap context to return */
    *wrap_ctx = new_wrap_ctx;

    return 0;
} /* end H5VL_pass_through_get_wrap_ctx() */

/*---------------------------------------------------------------------------
 * Function:    H5VL_pass_through_wrap_object
 *
 * Purpose:     Use a "wrapper context" to wrap a data object
 *
 * Return:      Success:    Pointer to wrapped object
 *              Failure:    NULL
 *
 *---------------------------------------------------------------------------
 */
static void *
H5VL_pass_through_wrap_object(void *obj, H5I_type_t obj_type, void *_wrap_ctx)
{
    H5VL_pass_through_wrap_ctx_t *wrap_ctx = (H5VL_pass_through_wrap_ctx_t *)_wrap_ctx;
    H5VL_pass_through_t *         new_obj;
    void *                        under;

#ifdef ENABLE_PASSTHRU_LOGGING
    printf("------- PASS THROUGH VOL WRAP Object\n");
#endif

    /* Wrap the object with the underlying VOL */
    under = H5VLwrap_object(obj, obj_type, wrap_ctx->under_vol_id, wrap_ctx->under_wrap_ctx);
    if (under)
        new_obj = H5VL_pass_through_new_obj(under, wrap_ctx->under_vol_id);
    else
        new_obj = NULL;

    return new_obj;
} /* end H5VL_pass_through_wrap_object() */

/*---------------------------------------------------------------------------
 * Function:    H5VL_pass_through_unwrap_object
 *
 * Purpose:     Unwrap a wrapped object, discarding the wrapper, but returning
 *		underlying object.
 *
 * Return:      Success:    Pointer to unwrapped object
 *              Failure:    NULL
 *
 *---------------------------------------------------------------------------
 */
static void *
H5VL_pass_through_unwrap_object(void *obj)
{
    H5VL_pass_through_t *o = (H5VL_pass_through_t *)obj;
    void *               under;

#ifdef ENABLE_PASSTHRU_LOGGING
    printf("------- PASS THROUGH VOL UNWRAP Object\n");
#endif

    /* Unrap the object with the underlying VOL */
    under = H5VLunwrap_object(o->under_object, o->under_vol_id);

    if (under)
        H5VL_pass_through_free_obj(o);

    return under;
} /* end H5VL_pass_through_unwrap_object() */

/*---------------------------------------------------------------------------
 * Function:    H5VL_pass_through_free_wrap_ctx
 *
 * Purpose:     Release a "wrapper context" for an object
 *
 * Note:	Take care to preserve the current HDF5 error stack
 *		when calling HDF5 API calls.
 *
 * Return:      Success:    0
 *              Failure:    -1
 *
 *---------------------------------------------------------------------------
 */
static herr_t
H5VL_pass_through_free_wrap_ctx(void *_wrap_ctx)
{
    H5VL_pass_through_wrap_ctx_t *wrap_ctx = (H5VL_pass_through_wrap_ctx_t *)_wrap_ctx;
    hid_t                         err_id;

#ifdef ENABLE_PASSTHRU_LOGGING
    printf("------- PASS THROUGH VOL WRAP CTX Free\n");
#endif

    err_id = H5Eget_current_stack();

    /* Release underlying VOL ID and wrap context */
    if (wrap_ctx->under_wrap_ctx)
        H5VLfree_wrap_ctx(wrap_ctx->under_wrap_ctx, wrap_ctx->under_vol_id);
    H5Idec_ref(wrap_ctx->under_vol_id);

    H5Eset_current_stack(err_id);

    /* Free pass through wrap context object itself */
    free(wrap_ctx);

    return 0;
} /* end H5VL_pass_through_free_wrap_ctx() */

/*-------------------------------------------------------------------------
 * Function:    H5VL_pass_through_attr_create
 *
 * Purpose:     Creates an attribute on an object.
 *
 * Return:      Success:    Pointer to attribute object
 *              Failure:    NULL
 *
 *-------------------------------------------------------------------------
 */
static void *
H5VL_pass_through_attr_create(void *obj, const H5VL_loc_params_t *loc_params, const char *name, hid_t type_id,
                              hid_t space_id, hid_t acpl_id, hid_t aapl_id, hid_t dxpl_id, void **req)
{
    H5VL_pass_through_t *attr;
    H5VL_pass_through_t *o = (H5VL_pass_through_t *)obj;
    void *               under;

#ifdef ENABLE_PASSTHRU_LOGGING
    printf("------- PASS THROUGH VOL ATTRIBUTE Create\n");
#endif

    under = H5VLattr_create(o->under_object, loc_params, o->under_vol_id, name, type_id, space_id, acpl_id,
                            aapl_id, dxpl_id, req);
    if (under) {
        attr = H5VL_pass_through_new_obj(under, o->under_vol_id);

        /* Check for async request */
        if (req && *req)
            *req = H5VL_pass_through_new_obj(*req, o->under_vol_id);
    } /* end if */
    else
        attr = NULL;

    return (void *)attr;
} /* end H5VL_pass_through_attr_create() */

/*-------------------------------------------------------------------------
 * Function:    H5VL_pass_through_attr_open
 *
 * Purpose:     Opens an attribute on an object.
 *
 * Return:      Success:    Pointer to attribute object
 *              Failure:    NULL
 *
 *-------------------------------------------------------------------------
 */
static void *
H5VL_pass_through_attr_open(void *obj, const H5VL_loc_params_t *loc_params, const char *name, hid_t aapl_id,
                            hid_t dxpl_id, void **req)
{
    H5VL_pass_through_t *attr;
    H5VL_pass_through_t *o = (H5VL_pass_through_t *)obj;
    void *               under;

#ifdef ENABLE_PASSTHRU_LOGGING
    printf("------- PASS THROUGH VOL ATTRIBUTE Open\n");
#endif

    under = H5VLattr_open(o->under_object, loc_params, o->under_vol_id, name, aapl_id, dxpl_id, req);
    if (under) {
        attr = H5VL_pass_through_new_obj(under, o->under_vol_id);

        /* Check for async request */
        if (req && *req)
            *req = H5VL_pass_through_new_obj(*req, o->under_vol_id);
    } /* end if */
    else
        attr = NULL;

    return (void *)attr;
} /* end H5VL_pass_through_attr_open() */

/*-------------------------------------------------------------------------
 * Function:    H5VL_pass_through_attr_read
 *
 * Purpose:     Reads data from attribute.
 *
 * Return:      Success:    0
 *              Failure:    -1
 *
 *-------------------------------------------------------------------------
 */
static herr_t
H5VL_pass_through_attr_read(void *attr, hid_t mem_type_id, void *buf, hid_t dxpl_id, void **req)
{
    H5VL_pass_through_t *o = (H5VL_pass_through_t *)attr;
    herr_t               ret_value;

#ifdef ENABLE_PASSTHRU_LOGGING
    printf("------- PASS THROUGH VOL ATTRIBUTE Read\n");
#endif

    ret_value = H5VLattr_read(o->under_object, o->under_vol_id, mem_type_id, buf, dxpl_id, req);

    /* Check for async request */
    if (req && *req)
        *req = H5VL_pass_through_new_obj(*req, o->under_vol_id);

    return ret_value;
} /* end H5VL_pass_through_attr_read() */

/*-------------------------------------------------------------------------
 * Function:    H5VL_pass_through_attr_write
 *
 * Purpose:     Writes data to attribute.
 *
 * Return:      Success:    0
 *              Failure:    -1
 *
 *-------------------------------------------------------------------------
 */
static herr_t
H5VL_pass_through_attr_write(void *attr, hid_t mem_type_id, const void *buf, hid_t dxpl_id, void **req)
{
    H5VL_pass_through_t *o = (H5VL_pass_through_t *)attr;
    herr_t               ret_value;

#ifdef ENABLE_PASSTHRU_LOGGING
    printf("------- PASS THROUGH VOL ATTRIBUTE Write\n");
#endif

    ret_value = H5VLattr_write(o->under_object, o->under_vol_id, mem_type_id, buf, dxpl_id, req);

    /* Check for async request */
    if (req && *req)
        *req = H5VL_pass_through_new_obj(*req, o->under_vol_id);

    return ret_value;
} /* end H5VL_pass_through_attr_write() */

/*-------------------------------------------------------------------------
 * Function:    H5VL_pass_through_attr_get
 *
 * Purpose:     Gets information about an attribute
 *
 * Return:      Success:    0
 *              Failure:    -1
 *
 *-------------------------------------------------------------------------
 */
static herr_t
H5VL_pass_through_attr_get(void *obj, H5VL_attr_get_t get_type, hid_t dxpl_id, void **req, va_list arguments)
{
    H5VL_pass_through_t *o = (H5VL_pass_through_t *)obj;
    herr_t               ret_value;

#ifdef ENABLE_PASSTHRU_LOGGING
    printf("------- PASS THROUGH VOL ATTRIBUTE Get\n");
#endif

    ret_value = H5VLattr_get(o->under_object, o->under_vol_id, get_type, dxpl_id, req, arguments);

    /* Check for async request */
    if (req && *req)
        *req = H5VL_pass_through_new_obj(*req, o->under_vol_id);

    return ret_value;
} /* end H5VL_pass_through_attr_get() */

/*-------------------------------------------------------------------------
 * Function:    H5VL_pass_through_attr_specific
 *
 * Purpose:     Specific operation on attribute
 *
 * Return:      Success:    0
 *              Failure:    -1
 *
 *-------------------------------------------------------------------------
 */
static herr_t
H5VL_pass_through_attr_specific(void *obj, const H5VL_loc_params_t *loc_params,
                                H5VL_attr_specific_t specific_type, hid_t dxpl_id, void **req,
                                va_list arguments)
{
    H5VL_pass_through_t *o = (H5VL_pass_through_t *)obj;
    herr_t               ret_value;

#ifdef ENABLE_PASSTHRU_LOGGING
    printf("------- PASS THROUGH VOL ATTRIBUTE Specific\n");
#endif

    ret_value = H5VLattr_specific(o->under_object, loc_params, o->under_vol_id, specific_type, dxpl_id, req,
                                  arguments);

    /* Check for async request */
    if (req && *req)
        *req = H5VL_pass_through_new_obj(*req, o->under_vol_id);

    return ret_value;
} /* end H5VL_pass_through_attr_specific() */

/*-------------------------------------------------------------------------
 * Function:    H5VL_pass_through_attr_optional
 *
 * Purpose:     Perform a connector-specific operation on an attribute
 *
 * Return:      Success:    0
 *              Failure:    -1
 *
 *-------------------------------------------------------------------------
 */
static herr_t
H5VL_pass_through_attr_optional(void *obj, H5VL_attr_optional_t opt_type, hid_t dxpl_id, void **req,
                                va_list arguments)
{
    H5VL_pass_through_t *o = (H5VL_pass_through_t *)obj;
    herr_t               ret_value;

#ifdef ENABLE_PASSTHRU_LOGGING
    printf("------- PASS THROUGH VOL ATTRIBUTE Optional\n");
#endif

    ret_value = H5VLattr_optional(o->under_object, o->under_vol_id, opt_type, dxpl_id, req, arguments);

    /* Check for async request */
    if (req && *req)
        *req = H5VL_pass_through_new_obj(*req, o->under_vol_id);

    return ret_value;
} /* end H5VL_pass_through_attr_optional() */

/*-------------------------------------------------------------------------
 * Function:    H5VL_pass_through_attr_close
 *
 * Purpose:     Closes an attribute.
 *
 * Return:      Success:    0
 *              Failure:    -1, attr not closed.
 *
 *-------------------------------------------------------------------------
 */
static herr_t
H5VL_pass_through_attr_close(void *attr, hid_t dxpl_id, void **req)
{
    H5VL_pass_through_t *o = (H5VL_pass_through_t *)attr;
    herr_t               ret_value;

#ifdef ENABLE_PASSTHRU_LOGGING
    printf("------- PASS THROUGH VOL ATTRIBUTE Close\n");
#endif

    ret_value = H5VLattr_close(o->under_object, o->under_vol_id, dxpl_id, req);

    /* Check for async request */
    if (req && *req)
        *req = H5VL_pass_through_new_obj(*req, o->under_vol_id);

    /* Release our wrapper, if underlying attribute was closed */
    if (ret_value >= 0)
        H5VL_pass_through_free_obj(o);

    return ret_value;
} /* end H5VL_pass_through_attr_close() */

/*-------------------------------------------------------------------------
 * Function:    H5VL_pass_through_dataset_create
 *
 * Purpose:     Creates a dataset in a container
 *
 * Return:      Success:    Pointer to a dataset object
 *              Failure:    NULL
 *
 *-------------------------------------------------------------------------
 */
static void *
H5VL_pass_through_dataset_create(void *obj, const H5VL_loc_params_t *loc_params, const char *name,
                                 hid_t lcpl_id, hid_t type_id, hid_t space_id, hid_t dcpl_id, hid_t dapl_id,
                                 hid_t dxpl_id, void **req)
{
    H5VL_pass_through_t *dset;
    H5VL_pass_through_t *o = (H5VL_pass_through_t *)obj;
    void *               under;

#ifdef ENABLE_PASSTHRU_LOGGING
    printf("------- PASS THROUGH VOL DATASET Create\n");
#endif

    under = H5VLdataset_create(o->under_object, loc_params, o->under_vol_id, name, lcpl_id, type_id, space_id,
                               dcpl_id, dapl_id, dxpl_id, req);
    if (under) {
        dset = H5VL_pass_through_new_obj(under, o->under_vol_id);

        /* Check for async request */
        if (req && *req)
            *req = H5VL_pass_through_new_obj(*req, o->under_vol_id);
    } /* end if */
    else
        dset = NULL;

    return (void *)dset;
} /* end H5VL_pass_through_dataset_create() */

/*-------------------------------------------------------------------------
 * Function:    H5VL_pass_through_dataset_open
 *
 * Purpose:     Opens a dataset in a container
 *
 * Return:      Success:    Pointer to a dataset object
 *              Failure:    NULL
 *
 *-------------------------------------------------------------------------
 */
static void *
H5VL_pass_through_dataset_open(void *obj, const H5VL_loc_params_t *loc_params, const char *name,
                               hid_t dapl_id, hid_t dxpl_id, void **req)
{
    H5VL_pass_through_t *dset;
    H5VL_pass_through_t *o = (H5VL_pass_through_t *)obj;
    void *               under;

#ifdef ENABLE_PASSTHRU_LOGGING
    printf("------- PASS THROUGH VOL DATASET Open\n");
#endif

    under = H5VLdataset_open(o->under_object, loc_params, o->under_vol_id, name, dapl_id, dxpl_id, req);
    if (under) {
        dset = H5VL_pass_through_new_obj(under, o->under_vol_id);

        /* Check for async request */
        if (req && *req)
            *req = H5VL_pass_through_new_obj(*req, o->under_vol_id);
    } /* end if */
    else
        dset = NULL;

    return (void *)dset;
} /* end H5VL_pass_through_dataset_open() */

/*-------------------------------------------------------------------------
 * Function:    H5VL_pass_through_dataset_read
 *
 * Purpose:     Reads data elements from a dataset into a buffer.
 *
 * Return:      Success:    0
 *              Failure:    -1
 *
 *-------------------------------------------------------------------------
 */
static herr_t
H5VL_pass_through_dataset_read(void *dset, hid_t mem_type_id, hid_t mem_space_id, hid_t file_space_id,
                               hid_t plist_id, void *buf, void **req)
{
    H5VL_pass_through_t *o = (H5VL_pass_through_t *)dset;
    herr_t               ret_value;

#ifdef ENABLE_PASSTHRU_LOGGING
    printf("------- PASS THROUGH VOL DATASET Read\n");
#endif

    ret_value = H5VLdataset_read(o->under_object, o->under_vol_id, mem_type_id, mem_space_id, file_space_id,
                                 plist_id, buf, req);

    /* Check for async request */
    if (req && *req)
        *req = H5VL_pass_through_new_obj(*req, o->under_vol_id);

    return ret_value;
} /* end H5VL_pass_through_dataset_read() */

/*-------------------------------------------------------------------------
 * Function:    H5VL_pass_through_dataset_write
 *
 * Purpose:     Writes data elements from a buffer into a dataset.
 *
 * Return:      Success:    0
 *              Failure:    -1
 *
 *-------------------------------------------------------------------------
 */
static herr_t
H5VL_pass_through_dataset_write(void *dset, hid_t mem_type_id, hid_t mem_space_id, hid_t file_space_id,
                                hid_t plist_id, const void *buf, void **req)
{
    H5VL_pass_through_t *o = (H5VL_pass_through_t *)dset;
    herr_t               ret_value;

#ifdef ENABLE_PASSTHRU_LOGGING
    printf("------- PASS THROUGH VOL DATASET Write\n");
#endif

    ret_value = H5VLdataset_write(o->under_object, o->under_vol_id, mem_type_id, mem_space_id, file_space_id,
                                  plist_id, buf, req);

    /* Check for async request */
    if (req && *req)
        *req = H5VL_pass_through_new_obj(*req, o->under_vol_id);

    return ret_value;
} /* end H5VL_pass_through_dataset_write() */

/*-------------------------------------------------------------------------
 * Function:    H5VL_pass_through_dataset_get
 *
 * Purpose:     Gets information about a dataset
 *
 * Return:      Success:    0
 *              Failure:    -1
 *
 *-------------------------------------------------------------------------
 */
static herr_t
H5VL_pass_through_dataset_get(void *dset, H5VL_dataset_get_t get_type, hid_t dxpl_id, void **req,
                              va_list arguments)
{
    H5VL_pass_through_t *o = (H5VL_pass_through_t *)dset;
    herr_t               ret_value;

#ifdef ENABLE_PASSTHRU_LOGGING
    printf("------- PASS THROUGH VOL DATASET Get\n");
#endif

    ret_value = H5VLdataset_get(o->under_object, o->under_vol_id, get_type, dxpl_id, req, arguments);

    /* Check for async request */
    if (req && *req)
        *req = H5VL_pass_through_new_obj(*req, o->under_vol_id);

    return ret_value;
} /* end H5VL_pass_through_dataset_get() */

/*-------------------------------------------------------------------------
 * Function:    H5VL_pass_through_dataset_specific
 *
 * Purpose:     Specific operation on a dataset
 *
 * Return:      Success:    0
 *              Failure:    -1
 *
 *-------------------------------------------------------------------------
 */
static herr_t
H5VL_pass_through_dataset_specific(void *obj, H5VL_dataset_specific_t specific_type, hid_t dxpl_id,
                                   void **req, va_list arguments)
{
    H5VL_pass_through_t *o = (H5VL_pass_through_t *)obj;
    hid_t                under_vol_id;
    herr_t               ret_value;

#ifdef ENABLE_PASSTHRU_LOGGING
    printf("------- PASS THROUGH VOL H5Dspecific\n");
#endif

    // Save copy of underlying VOL connector ID and prov helper, in case of
    // refresh destroying the current object
    under_vol_id = o->under_vol_id;

    ret_value =
        H5VLdataset_specific(o->under_object, o->under_vol_id, specific_type, dxpl_id, req, arguments);

    /* Check for async request */
    if (req && *req)
        *req = H5VL_pass_through_new_obj(*req, under_vol_id);

    return ret_value;
} /* end H5VL_pass_through_dataset_specific() */

/*-------------------------------------------------------------------------
 * Function:    H5VL_pass_through_dataset_optional
 *
 * Purpose:     Perform a connector-specific operation on a dataset
 *
 * Return:      Success:    0
 *              Failure:    -1
 *
 *-------------------------------------------------------------------------
 */
static herr_t
H5VL_pass_through_dataset_optional(void *obj, H5VL_dataset_optional_t opt_type, hid_t dxpl_id, void **req,
                                   va_list arguments)
{
    H5VL_pass_through_t *o = (H5VL_pass_through_t *)obj;
    herr_t               ret_value;

#ifdef ENABLE_PASSTHRU_LOGGING
    printf("------- PASS THROUGH VOL DATASET Optional\n");
#endif

    ret_value = H5VLdataset_optional(o->under_object, o->under_vol_id, opt_type, dxpl_id, req, arguments);

    /* Check for async request */
    if (req && *req)
        *req = H5VL_pass_through_new_obj(*req, o->under_vol_id);

    return ret_value;
} /* end H5VL_pass_through_dataset_optional() */

/*-------------------------------------------------------------------------
 * Function:    H5VL_pass_through_dataset_close
 *
 * Purpose:     Closes a dataset.
 *
 * Return:      Success:    0
 *              Failure:    -1, dataset not closed.
 *
 *-------------------------------------------------------------------------
 */
static herr_t
H5VL_pass_through_dataset_close(void *dset, hid_t dxpl_id, void **req)
{
    H5VL_pass_through_t *o = (H5VL_pass_through_t *)dset;
    herr_t               ret_value;

#ifdef ENABLE_PASSTHRU_LOGGING
    printf("------- PASS THROUGH VOL DATASET Close\n");
#endif

    ret_value = H5VLdataset_close(o->under_object, o->under_vol_id, dxpl_id, req);

    /* Check for async request */
    if (req && *req)
        *req = H5VL_pass_through_new_obj(*req, o->under_vol_id);

    /* Release our wrapper, if underlying dataset was closed */
    if (ret_value >= 0)
        H5VL_pass_through_free_obj(o);

    return ret_value;
} /* end H5VL_pass_through_dataset_close() */

/*-------------------------------------------------------------------------
 * Function:    H5VL_pass_through_datatype_commit
 *
 * Purpose:     Commits a datatype inside a container.
 *
 * Return:      Success:    Pointer to datatype object
 *              Failure:    NULL
 *
 *-------------------------------------------------------------------------
 */
static void *
H5VL_pass_through_datatype_commit(void *obj, const H5VL_loc_params_t *loc_params, const char *name,
                                  hid_t type_id, hid_t lcpl_id, hid_t tcpl_id, hid_t tapl_id, hid_t dxpl_id,
                                  void **req)
{
    H5VL_pass_through_t *dt;
    H5VL_pass_through_t *o = (H5VL_pass_through_t *)obj;
    void *               under;

#ifdef ENABLE_PASSTHRU_LOGGING
    printf("------- PASS THROUGH VOL DATATYPE Commit\n");
#endif

    under = H5VLdatatype_commit(o->under_object, loc_params, o->under_vol_id, name, type_id, lcpl_id, tcpl_id,
                                tapl_id, dxpl_id, req);
    if (under) {
        dt = H5VL_pass_through_new_obj(under, o->under_vol_id);

        /* Check for async request */
        if (req && *req)
            *req = H5VL_pass_through_new_obj(*req, o->under_vol_id);
    } /* end if */
    else
        dt = NULL;

    return (void *)dt;
} /* end H5VL_pass_through_datatype_commit() */

/*-------------------------------------------------------------------------
 * Function:    H5VL_pass_through_datatype_open
 *
 * Purpose:     Opens a named datatype inside a container.
 *
 * Return:      Success:    Pointer to datatype object
 *              Failure:    NULL
 *
 *-------------------------------------------------------------------------
 */
static void *
H5VL_pass_through_datatype_open(void *obj, const H5VL_loc_params_t *loc_params, const char *name,
                                hid_t tapl_id, hid_t dxpl_id, void **req)
{
    H5VL_pass_through_t *dt;
    H5VL_pass_through_t *o = (H5VL_pass_through_t *)obj;
    void *               under;

#ifdef ENABLE_PASSTHRU_LOGGING
    printf("------- PASS THROUGH VOL DATATYPE Open\n");
#endif

    under = H5VLdatatype_open(o->under_object, loc_params, o->under_vol_id, name, tapl_id, dxpl_id, req);
    if (under) {
        dt = H5VL_pass_through_new_obj(under, o->under_vol_id);

        /* Check for async request */
        if (req && *req)
            *req = H5VL_pass_through_new_obj(*req, o->under_vol_id);
    } /* end if */
    else
        dt = NULL;

    return (void *)dt;
} /* end H5VL_pass_through_datatype_open() */

/*-------------------------------------------------------------------------
 * Function:    H5VL_pass_through_datatype_get
 *
 * Purpose:     Get information about a datatype
 *
 * Return:      Success:    0
 *              Failure:    -1
 *
 *-------------------------------------------------------------------------
 */
static herr_t
H5VL_pass_through_datatype_get(void *dt, H5VL_datatype_get_t get_type, hid_t dxpl_id, void **req,
                               va_list arguments)
{
    H5VL_pass_through_t *o = (H5VL_pass_through_t *)dt;
    herr_t               ret_value;

#ifdef ENABLE_PASSTHRU_LOGGING
    printf("------- PASS THROUGH VOL DATATYPE Get\n");
#endif

    ret_value = H5VLdatatype_get(o->under_object, o->under_vol_id, get_type, dxpl_id, req, arguments);

    /* Check for async request */
    if (req && *req)
        *req = H5VL_pass_through_new_obj(*req, o->under_vol_id);

    return ret_value;
} /* end H5VL_pass_through_datatype_get() */

/*-------------------------------------------------------------------------
 * Function:    H5VL_pass_through_datatype_specific
 *
 * Purpose:     Specific operations for datatypes
 *
 * Return:      Success:    0
 *              Failure:    -1
 *
 *-------------------------------------------------------------------------
 */
static herr_t
H5VL_pass_through_datatype_specific(void *obj, H5VL_datatype_specific_t specific_type, hid_t dxpl_id,
                                    void **req, va_list arguments)
{
    H5VL_pass_through_t *o = (H5VL_pass_through_t *)obj;
    hid_t                under_vol_id;
    herr_t               ret_value;

#ifdef ENABLE_PASSTHRU_LOGGING
    printf("------- PASS THROUGH VOL DATATYPE Specific\n");
#endif

    // Save copy of underlying VOL connector ID and prov helper, in case of
    // refresh destroying the current object
    under_vol_id = o->under_vol_id;

    ret_value =
        H5VLdatatype_specific(o->under_object, o->under_vol_id, specific_type, dxpl_id, req, arguments);

    /* Check for async request */
    if (req && *req)
        *req = H5VL_pass_through_new_obj(*req, under_vol_id);

    return ret_value;
} /* end H5VL_pass_through_datatype_specific() */

/*-------------------------------------------------------------------------
 * Function:    H5VL_pass_through_datatype_optional
 *
 * Purpose:     Perform a connector-specific operation on a datatype
 *
 * Return:      Success:    0
 *              Failure:    -1
 *
 *-------------------------------------------------------------------------
 */
static herr_t
H5VL_pass_through_datatype_optional(void *obj, H5VL_datatype_optional_t opt_type, hid_t dxpl_id, void **req,
                                    va_list arguments)
{
    H5VL_pass_through_t *o = (H5VL_pass_through_t *)obj;
    herr_t               ret_value;

#ifdef ENABLE_PASSTHRU_LOGGING
    printf("------- PASS THROUGH VOL DATATYPE Optional\n");
#endif

    ret_value = H5VLdatatype_optional(o->under_object, o->under_vol_id, opt_type, dxpl_id, req, arguments);

    /* Check for async request */
    if (req && *req)
        *req = H5VL_pass_through_new_obj(*req, o->under_vol_id);

    return ret_value;
} /* end H5VL_pass_through_datatype_optional() */

/*-------------------------------------------------------------------------
 * Function:    H5VL_pass_through_datatype_close
 *
 * Purpose:     Closes a datatype.
 *
 * Return:      Success:    0
 *              Failure:    -1, datatype not closed.
 *
 *-------------------------------------------------------------------------
 */
static herr_t
H5VL_pass_through_datatype_close(void *dt, hid_t dxpl_id, void **req)
{
    H5VL_pass_through_t *o = (H5VL_pass_through_t *)dt;
    herr_t               ret_value;

#ifdef ENABLE_PASSTHRU_LOGGING
    printf("------- PASS THROUGH VOL DATATYPE Close\n");
#endif

    assert(o->under_object);

    ret_value = H5VLdatatype_close(o->under_object, o->under_vol_id, dxpl_id, req);

    /* Check for async request */
    if (req && *req)
        *req = H5VL_pass_through_new_obj(*req, o->under_vol_id);

    /* Release our wrapper, if underlying datatype was closed */
    if (ret_value >= 0)
        H5VL_pass_through_free_obj(o);

    return ret_value;
} /* end H5VL_pass_through_datatype_close() */

/*-------------------------------------------------------------------------
 * Function:    H5VL_pass_through_file_create
 *
 * Purpose:     Creates a container using this connector
 *
 * Return:      Success:    Pointer to a file object
 *              Failure:    NULL
 *
 *-------------------------------------------------------------------------
 */
static void *
H5VL_pass_through_file_create(const char *name, unsigned flags, hid_t fcpl_id, hid_t fapl_id, hid_t dxpl_id,
                              void **req)
{
    H5VL_pass_through_info_t *info;
    H5VL_pass_through_t *     file;
    hid_t                     under_fapl_id;
    void *                    under;

#ifdef ENABLE_PASSTHRU_LOGGING
    printf("------- PASS THROUGH VOL FILE Create\n");
#endif

    /* Get copy of our VOL info from FAPL */
    H5Pget_vol_info(fapl_id, (void **)&info);

    /* Make sure we have info about the underlying VOL to be used */
    if (!info)
        return NULL;

    /* Copy the FAPL */
    under_fapl_id = H5Pcopy(fapl_id);

    /* Set the VOL ID and info for the underlying FAPL */
    H5Pset_vol(under_fapl_id, info->under_vol_id, info->under_vol_info);

    /* Open the file with the underlying VOL connector */
    under = H5VLfile_create(name, flags, fcpl_id, under_fapl_id, dxpl_id, req);
    if (under) {
        file = H5VL_pass_through_new_obj(under, info->under_vol_id);

        /* Check for async request */
        if (req && *req)
            *req = H5VL_pass_through_new_obj(*req, info->under_vol_id);
    } /* end if */
    else
        file = NULL;

    /* Close underlying FAPL */
    H5Pclose(under_fapl_id);

    /* Release copy of our VOL info */
    H5VL_pass_through_info_free(info);

    return (void *)file;
} /* end H5VL_pass_through_file_create() */

/*-------------------------------------------------------------------------
 * Function:    H5VL_pass_through_file_open
 *
 * Purpose:     Opens a container created with this connector
 *
 * Return:      Success:    Pointer to a file object
 *              Failure:    NULL
 *
 *-------------------------------------------------------------------------
 */
static void *
H5VL_pass_through_file_open(const char *name, unsigned flags, hid_t fapl_id, hid_t dxpl_id, void **req)
{
    H5VL_pass_through_info_t *info;
    H5VL_pass_through_t *     file;
    hid_t                     under_fapl_id;
    void *                    under;

#ifdef ENABLE_PASSTHRU_LOGGING
    printf("------- PASS THROUGH VOL FILE Open\n");
#endif

    /* Get copy of our VOL info from FAPL */
    H5Pget_vol_info(fapl_id, (void **)&info);

    /* Make sure we have info about the underlying VOL to be used */
    if (!info)
        return NULL;

    /* Copy the FAPL */
    under_fapl_id = H5Pcopy(fapl_id);

    /* Set the VOL ID and info for the underlying FAPL */
    H5Pset_vol(under_fapl_id, info->under_vol_id, info->under_vol_info);

    /* Open the file with the underlying VOL connector */
    under = H5VLfile_open(name, flags, under_fapl_id, dxpl_id, req);
    if (under) {
        file = H5VL_pass_through_new_obj(under, info->under_vol_id);

        /* Check for async request */
        if (req && *req)
            *req = H5VL_pass_through_new_obj(*req, info->under_vol_id);
    } /* end if */
    else
        file = NULL;

    /* Close underlying FAPL */
    H5Pclose(under_fapl_id);

    /* Release copy of our VOL info */
    H5VL_pass_through_info_free(info);

    return (void *)file;
} /* end H5VL_pass_through_file_open() */

/*-------------------------------------------------------------------------
 * Function:    H5VL_pass_through_file_get
 *
 * Purpose:     Get info about a file
 *
 * Return:      Success:    0
 *              Failure:    -1
 *
 *-------------------------------------------------------------------------
 */
static herr_t
H5VL_pass_through_file_get(void *file, H5VL_file_get_t get_type, hid_t dxpl_id, void **req, va_list arguments)
{
    H5VL_pass_through_t *o = (H5VL_pass_through_t *)file;
    herr_t               ret_value;

#ifdef ENABLE_PASSTHRU_LOGGING
    printf("------- PASS THROUGH VOL FILE Get\n");
#endif

    ret_value = H5VLfile_get(o->under_object, o->under_vol_id, get_type, dxpl_id, req, arguments);

    /* Check for async request */
    if (req && *req)
        *req = H5VL_pass_through_new_obj(*req, o->under_vol_id);

    return ret_value;
} /* end H5VL_pass_through_file_get() */

/*-------------------------------------------------------------------------
 * Function:    H5VL_pass_through_file_specific_reissue
 *
 * Purpose:     Re-wrap vararg arguments into a va_list and reissue the
 *              file specific callback to the underlying VOL connector.
 *
 * Return:      Success:    0
 *              Failure:    -1
 *
 *-------------------------------------------------------------------------
 */
static herr_t
H5VL_pass_through_file_specific_reissue(void *obj, hid_t connector_id, H5VL_file_specific_t specific_type,
                                        hid_t dxpl_id, void **req, ...)
{
    va_list arguments;
    herr_t  ret_value;

    va_start(arguments, req);
    ret_value = H5VLfile_specific(obj, connector_id, specific_type, dxpl_id, req, arguments);
    va_end(arguments);

    return ret_value;
} /* end H5VL_pass_through_file_specific_reissue() */

/*-------------------------------------------------------------------------
 * Function:    H5VL_pass_through_file_specific
 *
 * Purpose:     Specific operation on file
 *
 * Return:      Success:    0
 *              Failure:    -1
 *
 *-------------------------------------------------------------------------
 */
static herr_t
H5VL_pass_through_file_specific(void *file, H5VL_file_specific_t specific_type, hid_t dxpl_id, void **req,
                                va_list arguments)
{
    H5VL_pass_through_t *o            = (H5VL_pass_through_t *)file;
    hid_t                under_vol_id = -1;
    herr_t               ret_value;

#ifdef ENABLE_PASSTHRU_LOGGING
    printf("------- PASS THROUGH VOL FILE Specific\n");
#endif

    /* Unpack arguments to get at the child file pointer when mounting a file */
    if (specific_type == H5VL_FILE_MOUNT) {
        H5I_type_t           loc_type;
        const char *         name;
        H5VL_pass_through_t *child_file;
        hid_t                plist_id;

        /* Retrieve parameters for 'mount' operation, so we can unwrap the child file */
        loc_type   = (H5I_type_t)va_arg(arguments, int); /* enum work-around */
        name       = va_arg(arguments, const char *);
        child_file = (H5VL_pass_through_t *)va_arg(arguments, void *);
        plist_id   = va_arg(arguments, hid_t);

        /* Keep the correct underlying VOL ID for possible async request token */
        under_vol_id = o->under_vol_id;

        /* Re-issue 'file specific' call, using the unwrapped pieces */
        ret_value = H5VL_pass_through_file_specific_reissue(o->under_object, o->under_vol_id, specific_type,
                                                            dxpl_id, req, (int)loc_type, name,
                                                            child_file->under_object, plist_id);
    } /* end if */
    else if (specific_type == H5VL_FILE_IS_ACCESSIBLE || specific_type == H5VL_FILE_DELETE) {
        H5VL_pass_through_info_t *info;
        hid_t                     fapl_id, under_fapl_id;
        const char *              name;
        htri_t *                  ret;

        /* Get the arguments for the 'is accessible' check */
        fapl_id = va_arg(arguments, hid_t);
        name    = va_arg(arguments, const char *);
        ret     = va_arg(arguments, htri_t *);

        /* Get copy of our VOL info from FAPL */
        H5Pget_vol_info(fapl_id, (void **)&info);

        /* Make sure we have info about the underlying VOL to be used */
        if (!info)
            return (-1);

        /* Copy the FAPL */
        under_fapl_id = H5Pcopy(fapl_id);

        /* Set the VOL ID and info for the underlying FAPL */
        H5Pset_vol(under_fapl_id, info->under_vol_id, info->under_vol_info);

        /* Keep the correct underlying VOL ID for possible async request token */
        under_vol_id = info->under_vol_id;

        /* Re-issue 'file specific' call */
        ret_value = H5VL_pass_through_file_specific_reissue(NULL, info->under_vol_id, specific_type, dxpl_id,
                                                            req, under_fapl_id, name, ret);

        /* Close underlying FAPL */
        H5Pclose(under_fapl_id);

        /* Release copy of our VOL info */
        H5VL_pass_through_info_free(info);
    } /* end else-if */
    else {
        va_list my_arguments;

        /* Make a copy of the argument list for later, if reopening */
        if (specific_type == H5VL_FILE_REOPEN)
            va_copy(my_arguments, arguments);

        /* Keep the correct underlying VOL ID for possible async request token */
        under_vol_id = o->under_vol_id;

        ret_value =
            H5VLfile_specific(o->under_object, o->under_vol_id, specific_type, dxpl_id, req, arguments);

        /* Wrap file struct pointer, if we reopened one */
        if (specific_type == H5VL_FILE_REOPEN) {
            if (ret_value >= 0) {
                void **ret = va_arg(my_arguments, void **);

                if (ret && *ret)
                    *ret = H5VL_pass_through_new_obj(*ret, o->under_vol_id);
            } /* end if */

            /* Finish use of copied vararg list */
            va_end(my_arguments);
        } /* end if */
    }     /* end else */

    /* Check for async request */
    if (req && *req)
        *req = H5VL_pass_through_new_obj(*req, under_vol_id);

    return ret_value;
} /* end H5VL_pass_through_file_specific() */

/*-------------------------------------------------------------------------
 * Function:    H5VL_pass_through_file_optional
 *
 * Purpose:     Perform a connector-specific operation on a file
 *
 * Return:      Success:    0
 *              Failure:    -1
 *
 *-------------------------------------------------------------------------
 */
static herr_t
H5VL_pass_through_file_optional(void *file, H5VL_file_optional_t opt_type, hid_t dxpl_id, void **req,
                                va_list arguments)
{
    H5VL_pass_through_t *o = (H5VL_pass_through_t *)file;
    herr_t               ret_value;

#ifdef ENABLE_PASSTHRU_LOGGING
    printf("------- PASS THROUGH VOL File Optional\n");
#endif

    ret_value = H5VLfile_optional(o->under_object, o->under_vol_id, opt_type, dxpl_id, req, arguments);

    /* Check for async request */
    if (req && *req)
        *req = H5VL_pass_through_new_obj(*req, o->under_vol_id);

    return ret_value;
} /* end H5VL_pass_through_file_optional() */

/*-------------------------------------------------------------------------
 * Function:    H5VL_pass_through_file_close
 *
 * Purpose:     Closes a file.
 *
 * Return:      Success:    0
 *              Failure:    -1, file not closed.
 *
 *-------------------------------------------------------------------------
 */
static herr_t
H5VL_pass_through_file_close(void *file, hid_t dxpl_id, void **req)
{
    H5VL_pass_through_t *o = (H5VL_pass_through_t *)file;
    herr_t               ret_value;

#ifdef ENABLE_PASSTHRU_LOGGING
    printf("------- PASS THROUGH VOL FILE Close\n");
#endif

    ret_value = H5VLfile_close(o->under_object, o->under_vol_id, dxpl_id, req);

    /* Check for async request */
    if (req && *req)
        *req = H5VL_pass_through_new_obj(*req, o->under_vol_id);

    /* Release our wrapper, if underlying file was closed */
    if (ret_value >= 0)
        H5VL_pass_through_free_obj(o);

    return ret_value;
} /* end H5VL_pass_through_file_close() */

/*-------------------------------------------------------------------------
 * Function:    H5VL_pass_through_group_create
 *
 * Purpose:     Creates a group inside a container
 *
 * Return:      Success:    Pointer to a group object
 *              Failure:    NULL
 *
 *-------------------------------------------------------------------------
 */
static void *
H5VL_pass_through_group_create(void *obj, const H5VL_loc_params_t *loc_params, const char *name,
                               hid_t lcpl_id, hid_t gcpl_id, hid_t gapl_id, hid_t dxpl_id, void **req)
{
    H5VL_pass_through_t *group;
    H5VL_pass_through_t *o = (H5VL_pass_through_t *)obj;
    void *               under;

#ifdef ENABLE_PASSTHRU_LOGGING
    printf("------- PASS THROUGH VOL GROUP Create\n");
#endif

    under = H5VLgroup_create(o->under_object, loc_params, o->under_vol_id, name, lcpl_id, gcpl_id, gapl_id,
                             dxpl_id, req);
    if (under) {
        group = H5VL_pass_through_new_obj(under, o->under_vol_id);

        /* Check for async request */
        if (req && *req)
            *req = H5VL_pass_through_new_obj(*req, o->under_vol_id);
    } /* end if */
    else
        group = NULL;

    return (void *)group;
} /* end H5VL_pass_through_group_create() */

/*-------------------------------------------------------------------------
 * Function:    H5VL_pass_through_group_open
 *
 * Purpose:     Opens a group inside a container
 *
 * Return:      Success:    Pointer to a group object
 *              Failure:    NULL
 *
 *-------------------------------------------------------------------------
 */
static void *
H5VL_pass_through_group_open(void *obj, const H5VL_loc_params_t *loc_params, const char *name, hid_t gapl_id,
                             hid_t dxpl_id, void **req)
{
    H5VL_pass_through_t *group;
    H5VL_pass_through_t *o = (H5VL_pass_through_t *)obj;
    void *               under;

#ifdef ENABLE_PASSTHRU_LOGGING
    printf("------- PASS THROUGH VOL GROUP Open\n");
#endif

    under = H5VLgroup_open(o->under_object, loc_params, o->under_vol_id, name, gapl_id, dxpl_id, req);
    if (under) {
        group = H5VL_pass_through_new_obj(under, o->under_vol_id);

        /* Check for async request */
        if (req && *req)
            *req = H5VL_pass_through_new_obj(*req, o->under_vol_id);
    } /* end if */
    else
        group = NULL;

    return (void *)group;
} /* end H5VL_pass_through_group_open() */

/*-------------------------------------------------------------------------
 * Function:    H5VL_pass_through_group_get
 *
 * Purpose:     Get info about a group
 *
 * Return:      Success:    0
 *              Failure:    -1
 *
 *-------------------------------------------------------------------------
 */
static herr_t
H5VL_pass_through_group_get(void *obj, H5VL_group_get_t get_type, hid_t dxpl_id, void **req,
                            va_list arguments)
{
    H5VL_pass_through_t *o = (H5VL_pass_through_t *)obj;
    herr_t               ret_value;

#ifdef ENABLE_PASSTHRU_LOGGING
    printf("------- PASS THROUGH VOL GROUP Get\n");
#endif

    ret_value = H5VLgroup_get(o->under_object, o->under_vol_id, get_type, dxpl_id, req, arguments);

    /* Check for async request */
    if (req && *req)
        *req = H5VL_pass_through_new_obj(*req, o->under_vol_id);

    return ret_value;
} /* end H5VL_pass_through_group_get() */

/*-------------------------------------------------------------------------
 * Function:    H5VL_pass_through_group_specific
 *
 * Purpose:     Specific operation on a group
 *
 * Return:      Success:    0
 *              Failure:    -1
 *
 *-------------------------------------------------------------------------
 */
static herr_t
H5VL_pass_through_group_specific(void *obj, H5VL_group_specific_t specific_type, hid_t dxpl_id, void **req,
                                 va_list arguments)
{
    H5VL_pass_through_t *o = (H5VL_pass_through_t *)obj;
    hid_t                under_vol_id;
    herr_t               ret_value;

#ifdef ENABLE_PASSTHRU_LOGGING
    printf("------- PASS THROUGH VOL GROUP Specific\n");
#endif

    // Save copy of underlying VOL connector ID and prov helper, in case of
    // refresh destroying the current object
    under_vol_id = o->under_vol_id;

    ret_value = H5VLgroup_specific(o->under_object, o->under_vol_id, specific_type, dxpl_id, req, arguments);

    /* Check for async request */
    if (req && *req)
        *req = H5VL_pass_through_new_obj(*req, under_vol_id);

    return ret_value;
} /* end H5VL_pass_through_group_specific() */

/*-------------------------------------------------------------------------
 * Function:    H5VL_pass_through_group_optional
 *
 * Purpose:     Perform a connector-specific operation on a group
 *
 * Return:      Success:    0
 *              Failure:    -1
 *
 *-------------------------------------------------------------------------
 */
static herr_t
H5VL_pass_through_group_optional(void *obj, H5VL_group_optional_t opt_type, hid_t dxpl_id, void **req,
                                 va_list arguments)
{
    H5VL_pass_through_t *o = (H5VL_pass_through_t *)obj;
    herr_t               ret_value;

#ifdef ENABLE_PASSTHRU_LOGGING
    printf("------- PASS THROUGH VOL GROUP Optional\n");
#endif

    ret_value = H5VLgroup_optional(o->under_object, o->under_vol_id, opt_type, dxpl_id, req, arguments);

    /* Check for async request */
    if (req && *req)
        *req = H5VL_pass_through_new_obj(*req, o->under_vol_id);

    return ret_value;
} /* end H5VL_pass_through_group_optional() */

/*-------------------------------------------------------------------------
 * Function:    H5VL_pass_through_group_close
 *
 * Purpose:     Closes a group.
 *
 * Return:      Success:    0
 *              Failure:    -1, group not closed.
 *
 *-------------------------------------------------------------------------
 */
static herr_t
H5VL_pass_through_group_close(void *grp, hid_t dxpl_id, void **req)
{
    H5VL_pass_through_t *o = (H5VL_pass_through_t *)grp;
    herr_t               ret_value;

#ifdef ENABLE_PASSTHRU_LOGGING
    printf("------- PASS THROUGH VOL H5Gclose\n");
#endif

    ret_value = H5VLgroup_close(o->under_object, o->under_vol_id, dxpl_id, req);

    /* Check for async request */
    if (req && *req)
        *req = H5VL_pass_through_new_obj(*req, o->under_vol_id);

    /* Release our wrapper, if underlying file was closed */
    if (ret_value >= 0)
        H5VL_pass_through_free_obj(o);

    return ret_value;
} /* end H5VL_pass_through_group_close() */

/*-------------------------------------------------------------------------
 * Function:    H5VL_pass_through_link_create_reissue
 *
 * Purpose:     Re-wrap vararg arguments into a va_list and reissue the
 *              link create callback to the underlying VOL connector.
 *
 * Return:      Success:    0
 *              Failure:    -1
 *
 *-------------------------------------------------------------------------
 */
static herr_t
H5VL_pass_through_link_create_reissue(H5VL_link_create_type_t create_type, void *obj,
                                      const H5VL_loc_params_t *loc_params, hid_t connector_id, hid_t lcpl_id,
                                      hid_t lapl_id, hid_t dxpl_id, void **req, ...)
{
    va_list arguments;
    herr_t  ret_value;

    va_start(arguments, req);
    ret_value = H5VLlink_create(create_type, obj, loc_params, connector_id, lcpl_id, lapl_id, dxpl_id, req,
                                arguments);
    va_end(arguments);

    return ret_value;
} /* end H5VL_pass_through_link_create_reissue() */

/*-------------------------------------------------------------------------
 * Function:    H5VL_pass_through_link_create
 *
 * Purpose:     Creates a hard / soft / UD / external link.
 *
 * Return:      Success:    0
 *              Failure:    -1
 *
 *-------------------------------------------------------------------------
 */
static herr_t
H5VL_pass_through_link_create(H5VL_link_create_type_t create_type, void *obj,
                              const H5VL_loc_params_t *loc_params, hid_t lcpl_id, hid_t lapl_id,
                              hid_t dxpl_id, void **req, va_list arguments)
{
    H5VL_pass_through_t *o            = (H5VL_pass_through_t *)obj;
    hid_t                under_vol_id = -1;
    herr_t               ret_value;

#ifdef ENABLE_PASSTHRU_LOGGING
    printf("------- PASS THROUGH VOL LINK Create\n");
#endif

    /* Try to retrieve the "under" VOL id */
    if (o)
        under_vol_id = o->under_vol_id;

    /* Fix up the link target object for hard link creation */
    if (H5VL_LINK_CREATE_HARD == create_type) {
        void *             cur_obj;
        H5VL_loc_params_t *cur_params;

        /* Retrieve the object & loc params for the link target */
        cur_obj    = va_arg(arguments, void *);
        cur_params = va_arg(arguments, H5VL_loc_params_t *);

        /* If it's a non-NULL pointer, find the 'under object' and re-set the property */
        if (cur_obj) {
            /* Check if we still need the "under" VOL ID */
            if (under_vol_id < 0)
                under_vol_id = ((H5VL_pass_through_t *)cur_obj)->under_vol_id;

            /* Set the object for the link target */
            cur_obj = ((H5VL_pass_through_t *)cur_obj)->under_object;
        } /* end if */

        /* Re-issue 'link create' call, using the unwrapped pieces */
        ret_value = H5VL_pass_through_link_create_reissue(create_type, (o ? o->under_object : NULL),
                                                          loc_params, under_vol_id, lcpl_id, lapl_id, dxpl_id,
                                                          req, cur_obj, cur_params);
    } /* end if */
    else
        ret_value = H5VLlink_create(create_type, (o ? o->under_object : NULL), loc_params, under_vol_id,
                                    lcpl_id, lapl_id, dxpl_id, req, arguments);

    /* Check for async request */
    if (req && *req)
        *req = H5VL_pass_through_new_obj(*req, under_vol_id);

    return ret_value;
} /* end H5VL_pass_through_link_create() */

/*-------------------------------------------------------------------------
 * Function:    H5VL_pass_through_link_copy
 *
 * Purpose:     Renames an object within an HDF5 container and copies it to a new
 *              group.  The original name SRC is unlinked from the group graph
 *              and then inserted with the new name DST (which can specify a
 *              new path for the object) as an atomic operation. The names
 *              are interpreted relative to SRC_LOC_ID and
 *              DST_LOC_ID, which are either file IDs or group ID.
 *
 * Return:      Success:    0
 *              Failure:    -1
 *
 *-------------------------------------------------------------------------
 */
static herr_t
H5VL_pass_through_link_copy(void *src_obj, const H5VL_loc_params_t *loc_params1, void *dst_obj,
                            const H5VL_loc_params_t *loc_params2, hid_t lcpl_id, hid_t lapl_id, hid_t dxpl_id,
                            void **req)
{
    H5VL_pass_through_t *o_src        = (H5VL_pass_through_t *)src_obj;
    H5VL_pass_through_t *o_dst        = (H5VL_pass_through_t *)dst_obj;
    hid_t                under_vol_id = -1;
    herr_t               ret_value;

#ifdef ENABLE_PASSTHRU_LOGGING
    printf("------- PASS THROUGH VOL LINK Copy\n");
#endif

    /* Retrieve the "under" VOL id */
    if (o_src)
        under_vol_id = o_src->under_vol_id;
    else if (o_dst)
        under_vol_id = o_dst->under_vol_id;
    assert(under_vol_id > 0);

    ret_value =
        H5VLlink_copy((o_src ? o_src->under_object : NULL), loc_params1, (o_dst ? o_dst->under_object : NULL),
                      loc_params2, under_vol_id, lcpl_id, lapl_id, dxpl_id, req);

    /* Check for async request */
    if (req && *req)
        *req = H5VL_pass_through_new_obj(*req, under_vol_id);

    return ret_value;
} /* end H5VL_pass_through_link_copy() */

/*-------------------------------------------------------------------------
 * Function:    H5VL_pass_through_link_move
 *
 * Purpose:     Moves a link within an HDF5 file to a new group.  The original
 *              name SRC is unlinked from the group graph
 *              and then inserted with the new name DST (which can specify a
 *              new path for the object) as an atomic operation. The names
 *              are interpreted relative to SRC_LOC_ID and
 *              DST_LOC_ID, which are either file IDs or group ID.
 *
 * Return:      Success:    0
 *              Failure:    -1
 *
 *-------------------------------------------------------------------------
 */
static herr_t
H5VL_pass_through_link_move(void *src_obj, const H5VL_loc_params_t *loc_params1, void *dst_obj,
                            const H5VL_loc_params_t *loc_params2, hid_t lcpl_id, hid_t lapl_id, hid_t dxpl_id,
                            void **req)
{
    H5VL_pass_through_t *o_src        = (H5VL_pass_through_t *)src_obj;
    H5VL_pass_through_t *o_dst        = (H5VL_pass_through_t *)dst_obj;
    hid_t                under_vol_id = -1;
    herr_t               ret_value;

#ifdef ENABLE_PASSTHRU_LOGGING
    printf("------- PASS THROUGH VOL LINK Move\n");
#endif

    /* Retrieve the "under" VOL id */
    if (o_src)
        under_vol_id = o_src->under_vol_id;
    else if (o_dst)
        under_vol_id = o_dst->under_vol_id;
    assert(under_vol_id > 0);

    ret_value =
        H5VLlink_move((o_src ? o_src->under_object : NULL), loc_params1, (o_dst ? o_dst->under_object : NULL),
                      loc_params2, under_vol_id, lcpl_id, lapl_id, dxpl_id, req);

    /* Check for async request */
    if (req && *req)
        *req = H5VL_pass_through_new_obj(*req, under_vol_id);

    return ret_value;
} /* end H5VL_pass_through_link_move() */

/*-------------------------------------------------------------------------
 * Function:    H5VL_pass_through_link_get
 *
 * Purpose:     Get info about a link
 *
 * Return:      Success:    0
 *              Failure:    -1
 *
 *-------------------------------------------------------------------------
 */
static herr_t
H5VL_pass_through_link_get(void *obj, const H5VL_loc_params_t *loc_params, H5VL_link_get_t get_type,
                           hid_t dxpl_id, void **req, va_list arguments)
{
    H5VL_pass_through_t *o = (H5VL_pass_through_t *)obj;
    herr_t               ret_value;

#ifdef ENABLE_PASSTHRU_LOGGING
    printf("------- PASS THROUGH VOL LINK Get\n");
#endif

    ret_value = H5VLlink_get(o->under_object, loc_params, o->under_vol_id, get_type, dxpl_id, req, arguments);

    /* Check for async request */
    if (req && *req)
        *req = H5VL_pass_through_new_obj(*req, o->under_vol_id);

    return ret_value;
} /* end H5VL_pass_through_link_get() */

/*-------------------------------------------------------------------------
 * Function:    H5VL_pass_through_link_specific
 *
 * Purpose:     Specific operation on a link
 *
 * Return:      Success:    0
 *              Failure:    -1
 *
 *-------------------------------------------------------------------------
 */
static herr_t
H5VL_pass_through_link_specific(void *obj, const H5VL_loc_params_t *loc_params,
                                H5VL_link_specific_t specific_type, hid_t dxpl_id, void **req,
                                va_list arguments)
{
    H5VL_pass_through_t *o = (H5VL_pass_through_t *)obj;
    herr_t               ret_value;

#ifdef ENABLE_PASSTHRU_LOGGING
    printf("------- PASS THROUGH VOL LINK Specific\n");
#endif

    ret_value = H5VLlink_specific(o->under_object, loc_params, o->under_vol_id, specific_type, dxpl_id, req,
                                  arguments);

    /* Check for async request */
    if (req && *req)
        *req = H5VL_pass_through_new_obj(*req, o->under_vol_id);

    return ret_value;
} /* end H5VL_pass_through_link_specific() */

/*-------------------------------------------------------------------------
 * Function:    H5VL_pass_through_link_optional
 *
 * Purpose:     Perform a connector-specific operation on a link
 *
 * Return:      Success:    0
 *              Failure:    -1
 *
 *-------------------------------------------------------------------------
 */
static herr_t
H5VL_pass_through_link_optional(void *obj, H5VL_link_optional_t opt_type, hid_t dxpl_id, void **req,
                                va_list arguments)
{
    H5VL_pass_through_t *o = (H5VL_pass_through_t *)obj;
    herr_t               ret_value;

#ifdef ENABLE_PASSTHRU_LOGGING
    printf("------- PASS THROUGH VOL LINK Optional\n");
#endif

    ret_value = H5VLlink_optional(o->under_object, o->under_vol_id, opt_type, dxpl_id, req, arguments);

    /* Check for async request */
    if (req && *req)
        *req = H5VL_pass_through_new_obj(*req, o->under_vol_id);

    return ret_value;
} /* end H5VL_pass_through_link_optional() */

/*-------------------------------------------------------------------------
 * Function:    H5VL_pass_through_object_open
 *
 * Purpose:     Opens an object inside a container.
 *
 * Return:      Success:    Pointer to object
 *              Failure:    NULL
 *
 *-------------------------------------------------------------------------
 */
static void *
H5VL_pass_through_object_open(void *obj, const H5VL_loc_params_t *loc_params, H5I_type_t *opened_type,
                              hid_t dxpl_id, void **req)
{
    H5VL_pass_through_t *new_obj;
    H5VL_pass_through_t *o = (H5VL_pass_through_t *)obj;
    void *               under;

#ifdef ENABLE_PASSTHRU_LOGGING
    printf("------- PASS THROUGH VOL OBJECT Open\n");
#endif

    under = H5VLobject_open(o->under_object, loc_params, o->under_vol_id, opened_type, dxpl_id, req);
    if (under) {
        new_obj = H5VL_pass_through_new_obj(under, o->under_vol_id);

        /* Check for async request */
        if (req && *req)
            *req = H5VL_pass_through_new_obj(*req, o->under_vol_id);
    } /* end if */
    else
        new_obj = NULL;

    return (void *)new_obj;
} /* end H5VL_pass_through_object_open() */

/*-------------------------------------------------------------------------
 * Function:    H5VL_pass_through_object_copy
 *
 * Purpose:     Copies an object inside a container.
 *
 * Return:      Success:    0
 *              Failure:    -1
 *
 *-------------------------------------------------------------------------
 */
static herr_t
H5VL_pass_through_object_copy(void *src_obj, const H5VL_loc_params_t *src_loc_params, const char *src_name,
                              void *dst_obj, const H5VL_loc_params_t *dst_loc_params, const char *dst_name,
                              hid_t ocpypl_id, hid_t lcpl_id, hid_t dxpl_id, void **req)
{
    H5VL_pass_through_t *o_src = (H5VL_pass_through_t *)src_obj;
    H5VL_pass_through_t *o_dst = (H5VL_pass_through_t *)dst_obj;
    herr_t               ret_value;

#ifdef ENABLE_PASSTHRU_LOGGING
    printf("------- PASS THROUGH VOL OBJECT Copy\n");
#endif

    ret_value =
        H5VLobject_copy(o_src->under_object, src_loc_params, src_name, o_dst->under_object, dst_loc_params,
                        dst_name, o_src->under_vol_id, ocpypl_id, lcpl_id, dxpl_id, req);

    /* Check for async request */
    if (req && *req)
        *req = H5VL_pass_through_new_obj(*req, o_src->under_vol_id);

    return ret_value;
} /* end H5VL_pass_through_object_copy() */

/*-------------------------------------------------------------------------
 * Function:    H5VL_pass_through_object_get
 *
 * Purpose:     Get info about an object
 *
 * Return:      Success:    0
 *              Failure:    -1
 *
 *-------------------------------------------------------------------------
 */
static herr_t
H5VL_pass_through_object_get(void *obj, const H5VL_loc_params_t *loc_params, H5VL_object_get_t get_type,
                             hid_t dxpl_id, void **req, va_list arguments)
{
    H5VL_pass_through_t *o = (H5VL_pass_through_t *)obj;
    herr_t               ret_value;

#ifdef ENABLE_PASSTHRU_LOGGING
    printf("------- PASS THROUGH VOL OBJECT Get\n");
#endif

    ret_value =
        H5VLobject_get(o->under_object, loc_params, o->under_vol_id, get_type, dxpl_id, req, arguments);

    /* Check for async request */
    if (req && *req)
        *req = H5VL_pass_through_new_obj(*req, o->under_vol_id);

    return ret_value;
} /* end H5VL_pass_through_object_get() */

/*-------------------------------------------------------------------------
 * Function:    H5VL_pass_through_object_specific
 *
 * Purpose:     Specific operation on an object
 *
 * Return:      Success:    0
 *              Failure:    -1
 *
 *-------------------------------------------------------------------------
 */
static herr_t
H5VL_pass_through_object_specific(void *obj, const H5VL_loc_params_t *loc_params,
                                  H5VL_object_specific_t specific_type, hid_t dxpl_id, void **req,
                                  va_list arguments)
{
    H5VL_pass_through_t *o = (H5VL_pass_through_t *)obj;
    hid_t                under_vol_id;
    herr_t               ret_value;

#ifdef ENABLE_PASSTHRU_LOGGING
    printf("------- PASS THROUGH VOL OBJECT Specific\n");
#endif

    // Save copy of underlying VOL connector ID and prov helper, in case of
    // refresh destroying the current object
    under_vol_id = o->under_vol_id;

    ret_value = H5VLobject_specific(o->under_object, loc_params, o->under_vol_id, specific_type, dxpl_id, req,
                                    arguments);

    /* Check for async request */
    if (req && *req)
        *req = H5VL_pass_through_new_obj(*req, under_vol_id);

    return ret_value;
} /* end H5VL_pass_through_object_specific() */

/*-------------------------------------------------------------------------
 * Function:    H5VL_pass_through_object_optional
 *
 * Purpose:     Perform a connector-specific operation for an object
 *
 * Return:      Success:    0
 *              Failure:    -1
 *
 *-------------------------------------------------------------------------
 */
static herr_t
H5VL_pass_through_object_optional(void *obj, H5VL_object_optional_t opt_type, hid_t dxpl_id, void **req,
                                  va_list arguments)
{
    H5VL_pass_through_t *o = (H5VL_pass_through_t *)obj;
    herr_t               ret_value;

#ifdef ENABLE_PASSTHRU_LOGGING
    printf("------- PASS THROUGH VOL OBJECT Optional\n");
#endif

    ret_value = H5VLobject_optional(o->under_object, o->under_vol_id, opt_type, dxpl_id, req, arguments);

    /* Check for async request */
    if (req && *req)
        *req = H5VL_pass_through_new_obj(*req, o->under_vol_id);

    return ret_value;
} /* end H5VL_pass_through_object_optional() */

/*-------------------------------------------------------------------------
 * Function:    H5VL_pass_through_introspect_get_conn_clss
 *
 * Purpose:     Query the connector class.
 *
 * Return:      SUCCEED / FAIL
 *
 *-------------------------------------------------------------------------
 */
herr_t
H5VL_pass_through_introspect_get_conn_cls(void *obj, H5VL_get_conn_lvl_t lvl, const H5VL_class_t **conn_cls)
{
    H5VL_pass_through_t *o = (H5VL_pass_through_t *)obj;
    herr_t               ret_value;

#ifdef ENABLE_PASSTHRU_LOGGING
    printf("------- PASS THROUGH VOL INTROSPECT GetConnCls\n");
#endif

    /* Check for querying this connector's class */
    if (H5VL_GET_CONN_LVL_CURR == lvl) {
        *conn_cls = &H5VL_pass_through_g;
        ret_value = 0;
    } /* end if */
    else
        ret_value = H5VLintrospect_get_conn_cls(o->under_object, o->under_vol_id, lvl, conn_cls);

    return ret_value;
} /* end H5VL_pass_through_introspect_get_conn_cls() */

/*-------------------------------------------------------------------------
 * Function:    H5VL_pass_through_introspect_opt_query
 *
 * Purpose:     Query if an optional operation is supported by this connector
 *
 * Return:      SUCCEED / FAIL
 *
 *-------------------------------------------------------------------------
 */
herr_t
H5VL_pass_through_introspect_opt_query(void *obj, H5VL_subclass_t cls, int opt_type, hbool_t *supported)
{
    H5VL_pass_through_t *o = (H5VL_pass_through_t *)obj;
    herr_t               ret_value;

#ifdef ENABLE_PASSTHRU_LOGGING
    printf("------- PASS THROUGH VOL INTROSPECT OptQuery\n");
#endif

    ret_value = H5VLintrospect_opt_query(o->under_object, o->under_vol_id, cls, opt_type, supported);

    return ret_value;
} /* end H5VL_pass_through_introspect_opt_query() */

/*-------------------------------------------------------------------------
 * Function:    H5VL_pass_through_request_wait
 *
 * Purpose:     Wait (with a timeout) for an async operation to complete
 *
 * Note:        Releases the request if the operation has completed and the
 *              connector callback succeeds
 *
 * Return:      Success:    0
 *              Failure:    -1
 *
 *-------------------------------------------------------------------------
 */
static herr_t
H5VL_pass_through_request_wait(void *obj, uint64_t timeout, H5ES_status_t *status)
{
    H5VL_pass_through_t *o = (H5VL_pass_through_t *)obj;
    herr_t               ret_value;

#ifdef ENABLE_PASSTHRU_LOGGING
    printf("------- PASS THROUGH VOL REQUEST Wait\n");
#endif

    ret_value = H5VLrequest_wait(o->under_object, o->under_vol_id, timeout, status);

    if (ret_value >= 0 && *status != H5ES_STATUS_IN_PROGRESS)
        H5VL_pass_through_free_obj(o);

    return ret_value;
} /* end H5VL_pass_through_request_wait() */

/*-------------------------------------------------------------------------
 * Function:    H5VL_pass_through_request_notify
 *
 * Purpose:     Registers a user callback to be invoked when an asynchronous
 *              operation completes
 *
 * Note:        Releases the request, if connector callback succeeds
 *
 * Return:      Success:    0
 *              Failure:    -1
 *
 *-------------------------------------------------------------------------
 */
static herr_t
H5VL_pass_through_request_notify(void *obj, H5VL_request_notify_t cb, void *ctx)
{
    H5VL_pass_through_t *o = (H5VL_pass_through_t *)obj;
    herr_t               ret_value;

#ifdef ENABLE_PASSTHRU_LOGGING
    printf("------- PASS THROUGH VOL REQUEST Notify\n");
#endif

    ret_value = H5VLrequest_notify(o->under_object, o->under_vol_id, cb, ctx);

    if (ret_value >= 0)
        H5VL_pass_through_free_obj(o);

    return ret_value;
} /* end H5VL_pass_through_request_notify() */

/*-------------------------------------------------------------------------
 * Function:    H5VL_pass_through_request_cancel
 *
 * Purpose:     Cancels an asynchronous operation
 *
 * Note:        Releases the request, if connector callback succeeds
 *
 * Return:      Success:    0
 *              Failure:    -1
 *
 *-------------------------------------------------------------------------
 */
static herr_t
H5VL_pass_through_request_cancel(void *obj)
{
    H5VL_pass_through_t *o = (H5VL_pass_through_t *)obj;
    herr_t               ret_value;

#ifdef ENABLE_PASSTHRU_LOGGING
    printf("------- PASS THROUGH VOL REQUEST Cancel\n");
#endif

    ret_value = H5VLrequest_cancel(o->under_object, o->under_vol_id);

    if (ret_value >= 0)
        H5VL_pass_through_free_obj(o);

    return ret_value;
} /* end H5VL_pass_through_request_cancel() */

/*-------------------------------------------------------------------------
 * Function:    H5VL_pass_through_request_specific_reissue
 *
 * Purpose:     Re-wrap vararg arguments into a va_list and reissue the
 *              request specific callback to the underlying VOL connector.
 *
 * Return:      Success:    0
 *              Failure:    -1
 *
 *-------------------------------------------------------------------------
 */
static herr_t
H5VL_pass_through_request_specific_reissue(void *obj, hid_t connector_id,
                                           H5VL_request_specific_t specific_type, ...)
{
    va_list arguments;
    herr_t  ret_value;

    va_start(arguments, specific_type);
    ret_value = H5VLrequest_specific(obj, connector_id, specific_type, arguments);
    va_end(arguments);

    return ret_value;
} /* end H5VL_pass_through_request_specific_reissue() */

/*-------------------------------------------------------------------------
 * Function:    H5VL_pass_through_request_specific
 *
 * Purpose:     Specific operation on a request
 *
 * Return:      Success:    0
 *              Failure:    -1
 *
 *-------------------------------------------------------------------------
 */
static herr_t
H5VL_pass_through_request_specific(void *obj, H5VL_request_specific_t specific_type, va_list arguments)
{
    herr_t ret_value = -1;

#ifdef ENABLE_PASSTHRU_LOGGING
    printf("------- PASS THROUGH VOL REQUEST Specific\n");
#endif

    if (H5VL_REQUEST_WAITANY == specific_type || H5VL_REQUEST_WAITSOME == specific_type ||
        H5VL_REQUEST_WAITALL == specific_type) {
        va_list tmp_arguments;
        size_t  req_count;

        /* Sanity check */
        assert(obj == NULL);

        /* Get enough info to call the underlying connector */
        va_copy(tmp_arguments, arguments);
        req_count = va_arg(tmp_arguments, size_t);

        /* Can only use a request to invoke the underlying VOL connector when there's >0 requests */
        if (req_count > 0) {
            void **              req_array;
            void **              under_req_array;
            uint64_t             timeout;
            H5VL_pass_through_t *o;
            size_t               u; /* Local index variable */

            /* Get the request array */
            req_array = va_arg(tmp_arguments, void **);

            /* Get a request to use for determining the underlying VOL connector */
            o = (H5VL_pass_through_t *)req_array[0];

            /* Create array of underlying VOL requests */
            under_req_array = (void **)malloc(req_count * sizeof(void **));
            for (u = 0; u < req_count; u++)
                under_req_array[u] = ((H5VL_pass_through_t *)req_array[u])->under_object;

            /* Remove the timeout value from the vararg list (it's used in all the calls below) */
            timeout = va_arg(tmp_arguments, uint64_t);

            /* Release requests that have completed */
            if (H5VL_REQUEST_WAITANY == specific_type) {
                size_t *       idx;    /* Pointer to the index of completed request */
                H5ES_status_t *status; /* Pointer to the request's status */

                /* Retrieve the remaining arguments */
                idx = va_arg(tmp_arguments, size_t *);
                assert(*idx <= req_count);
                status = va_arg(tmp_arguments, H5ES_status_t *);

                /* Reissue the WAITANY 'request specific' call */
                ret_value = H5VL_pass_through_request_specific_reissue(o->under_object, o->under_vol_id,
                                                                       specific_type, req_count,
                                                                       under_req_array, timeout, idx, status);

                /* Release the completed request, if it completed */
                if (ret_value >= 0 && *status != H5ES_STATUS_IN_PROGRESS) {
                    H5VL_pass_through_t *tmp_o;

                    tmp_o = (H5VL_pass_through_t *)req_array[*idx];
                    H5VL_pass_through_free_obj(tmp_o);
                } /* end if */
            }     /* end if */
            else if (H5VL_REQUEST_WAITSOME == specific_type) {
                size_t *       outcount;          /* # of completed requests */
                unsigned *     array_of_indices;  /* Array of indices for completed requests */
                H5ES_status_t *array_of_statuses; /* Array of statuses for completed requests */

                /* Retrieve the remaining arguments */
                outcount = va_arg(tmp_arguments, size_t *);
                assert(*outcount <= req_count);
                array_of_indices  = va_arg(tmp_arguments, unsigned *);
                array_of_statuses = va_arg(tmp_arguments, H5ES_status_t *);

                /* Reissue the WAITSOME 'request specific' call */
                ret_value = H5VL_pass_through_request_specific_reissue(
                    o->under_object, o->under_vol_id, specific_type, req_count, under_req_array, timeout,
                    outcount, array_of_indices, array_of_statuses);

                /* If any requests completed, release them */
                if (ret_value >= 0 && *outcount > 0) {
                    unsigned *idx_array; /* Array of indices of completed requests */

                    /* Retrieve the array of completed request indices */
                    idx_array = va_arg(tmp_arguments, unsigned *);

                    /* Release the completed requests */
                    for (u = 0; u < *outcount; u++) {
                        H5VL_pass_through_t *tmp_o;

                        tmp_o = (H5VL_pass_through_t *)req_array[idx_array[u]];
                        H5VL_pass_through_free_obj(tmp_o);
                    }                             /* end for */
                }                                 /* end if */
            }                                     /* end else-if */
            else {                                /* H5VL_REQUEST_WAITALL == specific_type */
                H5ES_status_t *array_of_statuses; /* Array of statuses for completed requests */

                /* Retrieve the remaining arguments */
                array_of_statuses = va_arg(tmp_arguments, H5ES_status_t *);

                /* Reissue the WAITALL 'request specific' call */
                ret_value = H5VL_pass_through_request_specific_reissue(
                    o->under_object, o->under_vol_id, specific_type, req_count, under_req_array, timeout,
                    array_of_statuses);

                /* Release the completed requests */
                if (ret_value >= 0) {
                    for (u = 0; u < req_count; u++) {
                        if (array_of_statuses[u] != H5ES_STATUS_IN_PROGRESS) {
                            H5VL_pass_through_t *tmp_o;

                            tmp_o = (H5VL_pass_through_t *)req_array[u];
                            H5VL_pass_through_free_obj(tmp_o);
                        } /* end if */
                    }     /* end for */
                }         /* end if */
            }             /* end else */

            /* Release array of requests for underlying connector */
            free(under_req_array);
        } /* end if */

        /* Finish use of copied vararg list */
        va_end(tmp_arguments);
    } /* end if */
    else {
        H5VL_pass_through_t *o = (H5VL_pass_through_t *)obj;

        ret_value = H5VLrequest_specific(o->under_object, o->under_vol_id, specific_type, arguments);
    } /* end else */

    return ret_value;
} /* end H5VL_pass_through_request_specific() */

/*-------------------------------------------------------------------------
 * Function:    H5VL_pass_through_request_optional
 *
 * Purpose:     Perform a connector-specific operation for a request
 *
 * Return:      Success:    0
 *              Failure:    -1
 *
 *-------------------------------------------------------------------------
 */
static herr_t
H5VL_pass_through_request_optional(void *obj, H5VL_request_optional_t opt_type, va_list arguments)
{
    H5VL_pass_through_t *o = (H5VL_pass_through_t *)obj;
    herr_t               ret_value;

#ifdef ENABLE_PASSTHRU_LOGGING
    printf("------- PASS THROUGH VOL REQUEST Optional\n");
#endif

    ret_value = H5VLrequest_optional(o->under_object, o->under_vol_id, opt_type, arguments);

    return ret_value;
} /* end H5VL_pass_through_request_optional() */

/*-------------------------------------------------------------------------
 * Function:    H5VL_pass_through_request_free
 *
 * Purpose:     Releases a request, allowing the operation to complete without
 *              application tracking
 *
 * Return:      Success:    0
 *              Failure:    -1
 *
 *-------------------------------------------------------------------------
 */
static herr_t
H5VL_pass_through_request_free(void *obj)
{
    H5VL_pass_through_t *o = (H5VL_pass_through_t *)obj;
    herr_t               ret_value;

#ifdef ENABLE_PASSTHRU_LOGGING
    printf("------- PASS THROUGH VOL REQUEST Free\n");
#endif

    ret_value = H5VLrequest_free(o->under_object, o->under_vol_id);

    if (ret_value >= 0)
        H5VL_pass_through_free_obj(o);

    return ret_value;
} /* end H5VL_pass_through_request_free() */

/*-------------------------------------------------------------------------
 * Function:    H5VL_pass_through_blob_put
 *
 * Purpose:     Handles the blob 'put' callback
 *
 * Return:      SUCCEED / FAIL
 *
 *-------------------------------------------------------------------------
 */
herr_t
H5VL_pass_through_blob_put(void *obj, const void *buf, size_t size, void *blob_id, void *ctx)
{
    H5VL_pass_through_t *o = (H5VL_pass_through_t *)obj;
    herr_t               ret_value;

#ifdef ENABLE_PASSTHRU_LOGGING
    printf("------- PASS THROUGH VOL BLOB Put\n");
#endif

    ret_value = H5VLblob_put(o->under_object, o->under_vol_id, buf, size, blob_id, ctx);

    return ret_value;
} /* end H5VL_pass_through_blob_put() */

/*-------------------------------------------------------------------------
 * Function:    H5VL_pass_through_blob_get
 *
 * Purpose:     Handles the blob 'get' callback
 *
 * Return:      SUCCEED / FAIL
 *
 *-------------------------------------------------------------------------
 */
herr_t
H5VL_pass_through_blob_get(void *obj, const void *blob_id, void *buf, size_t size, void *ctx)
{
    H5VL_pass_through_t *o = (H5VL_pass_through_t *)obj;
    herr_t               ret_value;

#ifdef ENABLE_PASSTHRU_LOGGING
    printf("------- PASS THROUGH VOL BLOB Get\n");
#endif

    ret_value = H5VLblob_get(o->under_object, o->under_vol_id, blob_id, buf, size, ctx);

    return ret_value;
} /* end H5VL_pass_through_blob_get() */

/*-------------------------------------------------------------------------
 * Function:    H5VL_pass_through_blob_specific
 *
 * Purpose:     Handles the blob 'specific' callback
 *
 * Return:      SUCCEED / FAIL
 *
 *-------------------------------------------------------------------------
 */
herr_t
H5VL_pass_through_blob_specific(void *obj, void *blob_id, H5VL_blob_specific_t specific_type,
                                va_list arguments)
{
    H5VL_pass_through_t *o = (H5VL_pass_through_t *)obj;
    herr_t               ret_value;

#ifdef ENABLE_PASSTHRU_LOGGING
    printf("------- PASS THROUGH VOL BLOB Specific\n");
#endif

    ret_value = H5VLblob_specific(o->under_object, o->under_vol_id, blob_id, specific_type, arguments);

    return ret_value;
} /* end H5VL_pass_through_blob_specific() */

/*-------------------------------------------------------------------------
 * Function:    H5VL_pass_through_blob_optional
 *
 * Purpose:     Handles the blob 'optional' callback
 *
 * Return:      SUCCEED / FAIL
 *
 *-------------------------------------------------------------------------
 */
herr_t
H5VL_pass_through_blob_optional(void *obj, void *blob_id, H5VL_blob_optional_t opt_type, va_list arguments)
{
    H5VL_pass_through_t *o = (H5VL_pass_through_t *)obj;
    herr_t               ret_value;

#ifdef ENABLE_PASSTHRU_LOGGING
    printf("------- PASS THROUGH VOL BLOB Optional\n");
#endif

    ret_value = H5VLblob_optional(o->under_object, o->under_vol_id, blob_id, opt_type, arguments);

    return ret_value;
} /* end H5VL_pass_through_blob_optional() */

/*---------------------------------------------------------------------------
 * Function:    H5VL_pass_through_token_cmp
 *
 * Purpose:     Compare two of the connector's object tokens, setting
 *              *cmp_value, following the same rules as strcmp().
 *
 * Return:      Success:    0
 *              Failure:    -1
 *
 *---------------------------------------------------------------------------
 */
static herr_t
H5VL_pass_through_token_cmp(void *obj, const H5O_token_t *token1, const H5O_token_t *token2, int *cmp_value)
{
    H5VL_pass_through_t *o = (H5VL_pass_through_t *)obj;
    herr_t               ret_value;

#ifdef ENABLE_PASSTHRU_LOGGING
    printf("------- PASS THROUGH VOL TOKEN Compare\n");
#endif

    /* Sanity checks */
    assert(obj);
    assert(token1);
    assert(token2);
    assert(cmp_value);

    ret_value = H5VLtoken_cmp(o->under_object, o->under_vol_id, token1, token2, cmp_value);

    return ret_value;
} /* end H5VL_pass_through_token_cmp() */

/*---------------------------------------------------------------------------
 * Function:    H5VL_pass_through_token_to_str
 *
 * Purpose:     Serialize the connector's object token into a string.
 *
 * Return:      Success:    0
 *              Failure:    -1
 *
 *---------------------------------------------------------------------------
 */
static herr_t
H5VL_pass_through_token_to_str(void *obj, H5I_type_t obj_type, const H5O_token_t *token, char **token_str)
{
    H5VL_pass_through_t *o = (H5VL_pass_through_t *)obj;
    herr_t               ret_value;

#ifdef ENABLE_PASSTHRU_LOGGING
    printf("------- PASS THROUGH VOL TOKEN To string\n");
#endif

    /* Sanity checks */
    assert(obj);
    assert(token);
    assert(token_str);

    ret_value = H5VLtoken_to_str(o->under_object, obj_type, o->under_vol_id, token, token_str);

    return ret_value;
} /* end H5VL_pass_through_token_to_str() */

/*---------------------------------------------------------------------------
 * Function:    H5VL_pass_through_token_from_str
 *
 * Purpose:     Deserialize the connector's object token from a string.
 *
 * Return:      Success:    0
 *              Failure:    -1
 *
 *---------------------------------------------------------------------------
 */
static herr_t
H5VL_pass_through_token_from_str(void *obj, H5I_type_t obj_type, const char *token_str, H5O_token_t *token)
{
    H5VL_pass_through_t *o = (H5VL_pass_through_t *)obj;
    herr_t               ret_value;

#ifdef ENABLE_PASSTHRU_LOGGING
    printf("------- PASS THROUGH VOL TOKEN From string\n");
#endif

    /* Sanity checks */
    assert(obj);
    assert(token);
    assert(token_str);

    ret_value = H5VLtoken_from_str(o->under_object, obj_type, o->under_vol_id, token_str, token);

    return ret_value;
} /* end H5VL_pass_through_token_from_str() */

/*-------------------------------------------------------------------------
 * Function:    H5VL_pass_through_optional
 *
 * Purpose:     Handles the generic 'optional' callback
 *
 * Return:      SUCCEED / FAIL
 *
 *-------------------------------------------------------------------------
 */
herr_t
H5VL_pass_through_optional(void *obj, int op_type, hid_t dxpl_id, void **req, va_list arguments)
{
    H5VL_pass_through_t *o = (H5VL_pass_through_t *)obj;
    herr_t               ret_value;

#ifdef ENABLE_PASSTHRU_LOGGING
    printf("------- PASS THROUGH VOL generic Optional\n");
#endif

    ret_value = H5VLoptional(o->under_object, o->under_vol_id, op_type, dxpl_id, req, arguments);

    return ret_value;
} /* end H5VL_pass_through_optional() */
