From c193d436f512e73be6569e56bf875bb2673ebdf8 Mon Sep 17 00:00:00 2001 From: jhendersonHDF Date: Mon, 15 Mar 2021 08:16:41 -0500 Subject: Merge H5Fopen VOL auto-detect feature and latest VOL fixes to 1.12 (#395) * Enable H5Fopen to probe list of available VOL connectors when opening a file * Unwrap file VOL object when destroying file (#308) * Check for wrap context before unwrapping file VOL object in H5F__dest (#325) --- src/H5Fint.c | 28 ++++-- src/H5PLint.c | 63 ++++++++++++-- src/H5PLpath.c | 225 +++++++++++++++++++++++++++++++++++++++++++++++-- src/H5PLpkg.h | 8 +- src/H5PLplugin_cache.c | 8 +- src/H5PLprivate.h | 13 +++ src/H5VL.c | 21 ----- src/H5VLcallback.c | 157 +++++++++++++++++++++++++++++++++- src/H5VLint.c | 21 +++++ src/H5VLprivate.h | 2 +- 10 files changed, 493 insertions(+), 53 deletions(-) diff --git a/src/H5Fint.c b/src/H5Fint.c index a999741..6922948 100644 --- a/src/H5Fint.c +++ b/src/H5Fint.c @@ -249,7 +249,8 @@ H5F__close_cb(H5VL_object_t *file_vol_obj) if (H5VL_file_close(file_vol_obj, H5P_DATASET_XFER_DEFAULT, H5_REQUEST_NULL) < 0) HGOTO_ERROR(H5E_FILE, H5E_CANTCLOSEFILE, FAIL, "unable to close file") - /* Free the VOL object */ + /* Free the VOL object; it is unnecessary to unwrap the VOL + * object before freeing it, as the object was not wrapped */ if (H5VL_free_object(file_vol_obj) < 0) HGOTO_ERROR(H5E_FILE, H5E_CANTDEC, FAIL, "unable to free VOL object") @@ -1337,6 +1338,8 @@ H5F__new(H5F_shared_t *shared, unsigned flags, hid_t fcpl_id, hid_t fapl_id, H5F done: if (!ret_value && f) { + HDassert(NULL == f->vol_obj); + if (!shared) { /* Attempt to clean up some of the shared file structures */ if (f->shared->efc) @@ -1349,11 +1352,6 @@ done: f->shared = H5FL_FREE(H5F_shared_t, f->shared); } - /* Free VOL object */ - if (f->vol_obj) - if (H5VL_free_object(f->vol_obj) < 0) - HDONE_ERROR(H5E_FILE, H5E_CANTDEC, NULL, "unable to free VOL object") - f = H5FL_FREE(H5F_t, f); } @@ -1620,9 +1618,21 @@ H5F__dest(H5F_t *f, hbool_t flush) /* Free the non-shared part of the file */ f->open_name = (char *)H5MM_xfree(f->open_name); f->actual_name = (char *)H5MM_xfree(f->actual_name); - if (f->vol_obj && H5VL_free_object(f->vol_obj) < 0) - HDONE_ERROR(H5E_FILE, H5E_CANTDEC, FAIL, "unable to free VOL object") - f->vol_obj = NULL; + if (f->vol_obj) { + void *vol_wrap_ctx = NULL; + + /* If a VOL wrapping context is available, retrieve it + * and unwrap file VOL object + */ + if (H5CX_get_vol_wrap_ctx((void **)&vol_wrap_ctx) < 0) + HDONE_ERROR(H5E_FILE, H5E_CANTGET, FAIL, "can't get VOL object wrap context") + if (vol_wrap_ctx && (NULL == H5VL_object_unwrap(f->vol_obj))) + HDONE_ERROR(H5E_FILE, H5E_CANTGET, FAIL, "can't unwrap VOL object") + + if (H5VL_free_object(f->vol_obj) < 0) + HDONE_ERROR(H5E_FILE, H5E_CANTDEC, FAIL, "unable to free VOL object") + f->vol_obj = NULL; + } if (H5FO_top_dest(f) < 0) HDONE_ERROR(H5E_FILE, H5E_CANTINIT, FAIL, "problems closing file") f->shared = NULL; diff --git a/src/H5PLint.c b/src/H5PLint.c index 94751bd..cf6135d 100644 --- a/src/H5PLint.c +++ b/src/H5PLint.c @@ -253,7 +253,7 @@ H5PL_load(H5PL_type_t type, const H5PL_key_t *key) /* Search in the table of already loaded plugin libraries */ if (H5PL__find_plugin_in_cache(&search_params, &found, &plugin_info) < 0) - HGOTO_ERROR(H5E_PLUGIN, H5E_CANTGET, NULL, "search in plugin cache failed") + HGOTO_ERROR(H5E_PLUGIN, H5E_CANTGET, NULL, "search in plugin cache failed") /* If not found, try iterating through the path table to find an appropriate plugin */ if (!found) @@ -293,12 +293,14 @@ done: H5_GCC_DIAG_OFF("pedantic") herr_t H5PL__open(const char *path, H5PL_type_t type, const H5PL_key_t *key, hbool_t *success, - const void **plugin_info) + H5PL_type_t *plugin_type, const void **plugin_info) { H5PL_HANDLE handle = NULL; H5PL_get_plugin_type_t get_plugin_type = NULL; H5PL_get_plugin_info_t get_plugin_info = NULL; - herr_t ret_value = SUCCEED; + H5PL_type_t loaded_plugin_type; + H5PL_key_t tmp_key; + herr_t ret_value = SUCCEED; FUNC_ENTER_PACKAGE @@ -310,6 +312,8 @@ H5PL__open(const char *path, H5PL_type_t type, const H5PL_key_t *key, hbool_t *s /* Initialize out parameters */ *success = FALSE; *plugin_info = NULL; + if (plugin_type) + *plugin_type = H5PL_TYPE_ERROR; /* There are different reasons why a library can't be open, e.g. wrong architecture. * If we can't open the library, just return. @@ -332,11 +336,12 @@ H5PL__open(const char *path, H5PL_type_t type, const H5PL_key_t *key, hbool_t *s HGOTO_DONE(SUCCEED) /* Check the plugin type and return if it doesn't match the one passed in */ - if (type != (H5PL_type_t)(*get_plugin_type)()) + loaded_plugin_type = (H5PL_type_t)(*get_plugin_type)(); + if ((type != H5PL_TYPE_NONE) && (type != loaded_plugin_type)) HGOTO_DONE(SUCCEED) /* Get the plugin information */ - switch (type) { + switch (loaded_plugin_type) { case H5PL_TYPE_FILTER: { const H5Z_class2_t *filter_info; @@ -344,8 +349,16 @@ H5PL__open(const char *path, H5PL_type_t type, const H5PL_key_t *key, hbool_t *s if (NULL == (filter_info = (const H5Z_class2_t *)(*get_plugin_info)())) HGOTO_ERROR(H5E_PLUGIN, H5E_CANTGET, FAIL, "can't get filter info from plugin") + /* Setup temporary plugin key if one wasn't supplied */ + if (!key) { + tmp_key.id = filter_info->id; + key = &tmp_key; + } + /* If the filter IDs match, we're done. Set the output parameters. */ if (filter_info->id == key->id) { + if (plugin_type) + *plugin_type = H5PL_TYPE_FILTER; *plugin_info = (const void *)filter_info; *success = TRUE; } @@ -360,13 +373,23 @@ H5PL__open(const char *path, H5PL_type_t type, const H5PL_key_t *key, hbool_t *s if (NULL == (cls = (const void *)(*get_plugin_info)())) HGOTO_ERROR(H5E_PLUGIN, H5E_CANTGET, FAIL, "can't get VOL connector info from plugin") + /* Setup temporary plugin key if one wasn't supplied */ + if (!key) { + tmp_key.vol.kind = H5VL_GET_CONNECTOR_BY_NAME; + tmp_key.vol.u.name = ((const H5VL_class_t *)cls)->name; + key = &tmp_key; + } + /* Ask VOL interface if this class is the one we are looking for and is compatible, etc */ if (H5VL_check_plugin_load(cls, key, success) < 0) HGOTO_ERROR(H5E_PLUGIN, H5E_CANTLOAD, FAIL, "VOL connector compatibility check failed") /* Check for finding the correct plugin */ - if (*success) + if (*success) { + if (plugin_type) + *plugin_type = H5PL_TYPE_VOL; *plugin_info = cls; + } break; } @@ -379,7 +402,7 @@ H5PL__open(const char *path, H5PL_type_t type, const H5PL_key_t *key, hbool_t *s /* If we found the correct plugin, store it in the cache */ if (*success) - if (H5PL__add_plugin(type, key, handle)) + if (H5PL__add_plugin(loaded_plugin_type, key, handle)) HGOTO_ERROR(H5E_PLUGIN, H5E_CANTINSERT, FAIL, "unable to add new plugin to plugin cache") done: @@ -409,3 +432,29 @@ H5PL__close(H5PL_HANDLE handle) FUNC_LEAVE_NOAPI(SUCCEED) } /* end H5PL__close() */ + +/*------------------------------------------------------------------------- + * Function: H5PL_iterate + * + * Purpose: Iterates over all the available plugins and calls the + * specified callback function on each plugin. + * + * Return: H5_ITER_CONT if all plugins are processed successfully + * H5_ITER_STOP if short-circuit success occurs while + * processing plugins + * H5_ITER_ERROR if an error occurs while processing plugins + * + *------------------------------------------------------------------------- + */ +herr_t +H5PL_iterate(H5PL_iterate_type_t iter_type, H5PL_iterate_t iter_op, void *op_data) +{ + herr_t ret_value = H5_ITER_CONT; + + FUNC_ENTER_NOAPI(H5_ITER_ERROR) + + ret_value = H5PL__path_table_iterate(iter_type, iter_op, op_data); + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5PL_iterate() */ diff --git a/src/H5PLpath.c b/src/H5PLpath.c index 047e0d0..39a7d0d 100644 --- a/src/H5PLpath.c +++ b/src/H5PLpath.c @@ -62,6 +62,8 @@ static herr_t H5PL__insert_at(const char *path, unsigned int idx); static herr_t H5PL__make_space_at(unsigned int idx); static herr_t H5PL__replace_at(const char *path, unsigned int idx); static herr_t H5PL__expand_path_table(void); +static herr_t H5PL__path_table_iterate_process_path(const char *plugin_path, H5PL_iterate_type_t iter_type, + H5PL_iterate_t iter_op, void *op_data); static herr_t H5PL__find_plugin_in_path(const H5PL_search_params_t *search_params, hbool_t *found, const char *dir, const void **plugin_info); @@ -546,7 +548,220 @@ H5PL__get_path(unsigned int idx) return H5PL_paths_g[idx]; done: FUNC_LEAVE_NOAPI(ret_value) -} /* end H5PL__replace_path() */ +} /* end H5PL__get_path() */ + +/*------------------------------------------------------------------------- + * Function: H5PL__path_table_iterate + * + * Purpose: Iterates over all the plugins in the plugin path table and + * calls the specified callback function on each plugin found. + * + * Return: H5_ITER_CONT if all plugins are processed successfully + * H5_ITER_STOP if short-circuit success occurs while + * processing plugins + * H5_ITER_ERROR if an error occurs while processing plugins + * + *------------------------------------------------------------------------- + */ +herr_t +H5PL__path_table_iterate(H5PL_iterate_type_t iter_type, H5PL_iterate_t iter_op, void *op_data) +{ + unsigned int u; + herr_t ret_value = H5_ITER_CONT; + + FUNC_ENTER_PACKAGE + + for (u = 0; (u < H5PL_num_paths_g) && (ret_value == H5_ITER_CONT); u++) + ret_value = H5PL__path_table_iterate_process_path(H5PL_paths_g[u], iter_type, iter_op, op_data); + + if (ret_value < 0) + HGOTO_ERROR(H5E_PLUGIN, H5E_BADITER, H5_ITER_ERROR, "can't iterate over plugins in plugin path '%s'", + H5PL_paths_g[u]); + +done: + FUNC_LEAVE_NOAPI(ret_value); +} /* end H5PL__path_table_iterate() */ + +/*------------------------------------------------------------------------- + * Function: H5PL__path_table_iterate_process_path + * + * Purpose: Iterates over all the plugins within a single plugin path + * entry in the plugin path table and calls the specified + * callback function on each plugin found. Two function + * definitions are for Unix and Windows. + * + * Return: H5_ITER_CONT if all plugins are processed successfully + * H5_ITER_STOP if short-circuit success occurs while + * processing plugins + * H5_ITER_ERROR if an error occurs while processing plugins + * + *------------------------------------------------------------------------- + */ +#ifndef H5_HAVE_WIN32_API +static herr_t +H5PL__path_table_iterate_process_path(const char *plugin_path, H5PL_iterate_type_t iter_type, + H5PL_iterate_t iter_op, void *op_data) +{ + H5PL_type_t plugin_type; + const void * plugin_info = NULL; + hbool_t plugin_loaded; + char * path = NULL; + DIR * dirp = NULL; /* Directory stream */ + struct dirent *dp = NULL; /* Directory entry */ + herr_t ret_value = H5_ITER_CONT; + + FUNC_ENTER_STATIC + + HDassert(plugin_path); + HDassert(iter_op); + + /* Open the directory */ + if (!(dirp = HDopendir(plugin_path))) + HGOTO_ERROR(H5E_PLUGIN, H5E_OPENERROR, H5_ITER_ERROR, "can't open directory: %s", plugin_path) + + /* Iterate through all entries in the directory */ + while (NULL != (dp = HDreaddir(dirp))) { + /* The library we are looking for should be called libxxx.so... on Unix + * or libxxx.xxx.dylib on Mac. + */ +#ifndef __CYGWIN__ + if (!HDstrncmp(dp->d_name, "lib", (size_t)3) && + (HDstrstr(dp->d_name, ".so") || HDstrstr(dp->d_name, ".dylib"))) { +#else + if (!HDstrncmp(dp->d_name, "cyg", (size_t)3) && HDstrstr(dp->d_name, ".dll")) { +#endif + + hbool_t plugin_matches; + h5_stat_t my_stat; + size_t len; + + /* Allocate & initialize the path name */ + len = HDstrlen(plugin_path) + HDstrlen(H5PL_PATH_SEPARATOR) + HDstrlen(dp->d_name) + 1 /*\0*/ + + 4; /* Extra "+4" to quiet GCC warning - 2019/07/05, QAK */ + + if (NULL == (path = (char *)H5MM_calloc(len))) + HGOTO_ERROR(H5E_PLUGIN, H5E_CANTALLOC, H5_ITER_ERROR, "can't allocate memory for path") + + HDsnprintf(path, len, "%s/%s", plugin_path, dp->d_name); + + /* Get info for directory entry */ + if (HDstat(path, &my_stat) == -1) + HGOTO_ERROR(H5E_FILE, H5E_CANTGET, H5_ITER_ERROR, "can't stat file %s -- error was: %s", path, + HDstrerror(errno)) + + /* If it is a directory, skip it */ + if (S_ISDIR(my_stat.st_mode)) + continue; + + /* Attempt to open the dynamic library */ + plugin_type = H5PL_TYPE_ERROR; + plugin_info = NULL; + plugin_loaded = FALSE; + if (H5PL__open(path, H5PL_TYPE_NONE, NULL, &plugin_loaded, &plugin_type, &plugin_info) < 0) + HGOTO_ERROR(H5E_PLUGIN, H5E_CANTGET, H5_ITER_ERROR, "failed to open plugin '%s'", path); + + /* Determine if we should process this plugin */ + plugin_matches = (iter_type == H5PL_ITER_TYPE_ALL) || + ((iter_type == H5PL_ITER_TYPE_FILTER) && (plugin_type == H5PL_TYPE_FILTER)) || + ((iter_type == H5PL_ITER_TYPE_VOL) && (plugin_type == H5PL_TYPE_VOL)); + + /* If the plugin was successfully loaded, call supplied callback function on plugin */ + if (plugin_loaded && plugin_matches && (ret_value = iter_op(plugin_type, plugin_info, op_data))) + break; + + path = (char *)H5MM_xfree(path); + } /* end if */ + } /* end while */ + + if (ret_value < 0) + HERROR(H5E_PLUGIN, H5E_CALLBACK, "callback operator function returned failure"); + +done: + if (dirp) + if (HDclosedir(dirp) < 0) + HDONE_ERROR(H5E_FILE, H5E_CLOSEERROR, H5_ITER_ERROR, "can't close directory: %s", + HDstrerror(errno)) + + path = (char *)H5MM_xfree(path); + + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5PL__path_table_iterate_process_path() */ +#else /* H5_HAVE_WIN32_API */ +static herr_t +H5PL__path_table_iterate_process_path(const char *plugin_path, H5PL_iterate_type_t iter_type, + H5PL_iterate_t iter_op, void *op_data) +{ + WIN32_FIND_DATAA fdFile; + HANDLE hFind = INVALID_HANDLE_VALUE; + H5PL_type_t plugin_type; + const void * plugin_info = NULL; + hbool_t plugin_loaded; + char * path = NULL; + char service[2048]; + herr_t ret_value = H5_ITER_CONT; + + FUNC_ENTER_STATIC + + /* Check args - Just assert on package functions */ + HDassert(plugin_path); + HDassert(iter_op); + + /* Specify a file mask. *.* = We want everything! */ + HDsprintf(service, "%s\\*.dll", plugin_path); + if ((hFind = FindFirstFileA(service, &fdFile)) == INVALID_HANDLE_VALUE) + HGOTO_ERROR(H5E_PLUGIN, H5E_OPENERROR, H5_ITER_ERROR, "can't open directory") + + /* Loop over all the files */ + do { + /* Ignore '.' and '..' */ + if (HDstrcmp(fdFile.cFileName, ".") != 0 && HDstrcmp(fdFile.cFileName, "..") != 0) { + hbool_t plugin_matches; + size_t len; + + /* Allocate & initialize the path name */ + len = HDstrlen(plugin_path) + HDstrlen(H5PL_PATH_SEPARATOR) + HDstrlen(fdFile.cFileName) + 1; + + if (NULL == (path = (char *)H5MM_calloc(len))) + HGOTO_ERROR(H5E_PLUGIN, H5E_CANTALLOC, H5_ITER_ERROR, "can't allocate memory for path") + + HDsnprintf(path, len, "%s\\%s", plugin_path, fdFile.cFileName); + + /* Ignore directories */ + if (fdFile.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + continue; + + /* Attempt to open the dynamic library */ + plugin_type = H5PL_TYPE_ERROR; + plugin_info = NULL; + plugin_loaded = FALSE; + if (H5PL__open(path, H5PL_TYPE_NONE, NULL, &plugin_loaded, &plugin_type, &plugin_info) < 0) + HGOTO_ERROR(H5E_PLUGIN, H5E_CANTGET, H5_ITER_ERROR, "failed to open plugin '%s'", path); + + /* Determine if we should process this plugin */ + plugin_matches = (iter_type == H5PL_ITER_TYPE_ALL) || + ((iter_type == H5PL_ITER_TYPE_FILTER) && (plugin_type == H5PL_TYPE_FILTER)) || + ((iter_type == H5PL_ITER_TYPE_VOL) && (plugin_type == H5PL_TYPE_VOL)); + + /* If the plugin was successfully loaded, call supplied callback function on plugin */ + if (plugin_loaded && plugin_matches && (ret_value = iter_op(plugin_type, plugin_info, op_data))) + break; + + path = (char *)H5MM_xfree(path); + } + } while (FindNextFileA(hFind, &fdFile)); + + if (ret_value < 0) + HERROR(H5E_PLUGIN, H5E_CALLBACK, "callback operator function returned failure"); + +done: + if (hFind != INVALID_HANDLE_VALUE) + FindClose(hFind); + + path = (char *)H5MM_xfree(path); + + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5PL__path_table_iterate_process_path() */ +#endif /* H5_HAVE_WIN32_API */ /*------------------------------------------------------------------------- * Function: H5PL__find_plugin_in_path_table @@ -674,8 +889,8 @@ H5PL__find_plugin_in_path(const H5PL_search_params_t *search_params, hbool_t *fo continue; } - /* attempt to open the dynamic library as a filter library */ - if (H5PL__open(path, search_params->type, search_params->key, found, plugin_info) < 0) + /* attempt to open the dynamic library */ + if (H5PL__open(path, search_params->type, search_params->key, found, NULL, plugin_info) < 0) HGOTO_ERROR(H5E_PLUGIN, H5E_CANTGET, FAIL, "search in directory failed") if (*found) HGOTO_DONE(SUCCEED) @@ -741,8 +956,8 @@ H5PL__find_plugin_in_path(const H5PL_search_params_t *search_params, hbool_t *fo if (fdFile.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) continue; - /* attempt to open the dynamic library as a filter library */ - if (H5PL__open(path, search_params->type, search_params->key, found, plugin_info) < 0) + /* attempt to open the dynamic library */ + if (H5PL__open(path, search_params->type, search_params->key, found, NULL, plugin_info) < 0) HGOTO_ERROR(H5E_PLUGIN, H5E_CANTGET, FAIL, "search in directory failed") if (*found) HGOTO_DONE(SUCCEED) diff --git a/src/H5PLpkg.h b/src/H5PLpkg.h index 6e0d1dc..cffc358 100644 --- a/src/H5PLpkg.h +++ b/src/H5PLpkg.h @@ -133,7 +133,8 @@ H5_DLL herr_t H5PL__set_plugin_control_mask(unsigned int mask); /* Plugin search and manipulation */ H5_DLL herr_t H5PL__open(const char *libname, H5PL_type_t type, const H5PL_key_t *key, - hbool_t *success /*out*/, const void **plugin_info /*out*/); + hbool_t *success /*out*/, H5PL_type_t *plugin_type /*out*/, + const void **plugin_info /*out*/); H5_DLL herr_t H5PL__close(H5PL_HANDLE handle); /* Plugin cache calls */ @@ -153,7 +154,8 @@ H5_DLL herr_t H5PL__replace_path(const char *path, unsigned int index); H5_DLL herr_t H5PL__insert_path(const char *path, unsigned int index); H5_DLL herr_t H5PL__remove_path(unsigned int index); H5_DLL const char *H5PL__get_path(unsigned int index); -H5_DLL herr_t H5PL__find_plugin_in_path_table(const H5PL_search_params_t *search_params, - hbool_t *found /*out*/, const void **plugin_info /*out*/); +H5_DLL herr_t H5PL__path_table_iterate(H5PL_iterate_type_t iter_type, H5PL_iterate_t iter_op, void *op_data); +H5_DLL herr_t H5PL__find_plugin_in_path_table(const H5PL_search_params_t *search_params, + hbool_t *found /*out*/, const void **plugin_info /*out*/); #endif /* H5PLpkg_H */ diff --git a/src/H5PLplugin_cache.c b/src/H5PLplugin_cache.c index 970b511..2ec0845 100644 --- a/src/H5PLplugin_cache.c +++ b/src/H5PLplugin_cache.c @@ -264,12 +264,12 @@ H5PL__find_plugin_in_cache(const H5PL_search_params_t *search_params, hbool_t *f /* Loop over all the plugins, looking for one that matches */ for (u = 0; u < H5PL_num_plugins_g; u++) { - /* If the plugin type (filter, etc.) and ID match, query the plugin for its info */ + /* If the plugin type (filter, VOL connector, etc.) and ID match, query the plugin for its info */ if ((search_params->type == (H5PL_cache_g[u]).type) && (search_params->key->id == (H5PL_cache_g[u]).key.id)) { H5PL_get_plugin_info_t get_plugin_info_function; - const H5Z_class2_t * filter_info; + const void * info; /* Get the "get plugin info" function from the plugin. */ if (NULL == (get_plugin_info_function = (H5PL_get_plugin_info_t)H5PL_GET_LIB_FUNC( @@ -277,12 +277,12 @@ H5PL__find_plugin_in_cache(const H5PL_search_params_t *search_params, hbool_t *f HGOTO_ERROR(H5E_PLUGIN, H5E_CANTGET, FAIL, "can't get function for H5PLget_plugin_info") /* Call the "get plugin info" function */ - if (NULL == (filter_info = (const H5Z_class2_t *)(*get_plugin_info_function)())) + if (NULL == (info = (*get_plugin_info_function)())) HGOTO_ERROR(H5E_PLUGIN, H5E_CANTGET, FAIL, "can't get plugin info") /* Set output parameters */ *found = TRUE; - *plugin_info = filter_info; + *plugin_info = info; /* No need to continue processing */ break; diff --git a/src/H5PLprivate.h b/src/H5PLprivate.h index 36b8ba2..7eae513 100644 --- a/src/H5PLprivate.h +++ b/src/H5PLprivate.h @@ -44,6 +44,18 @@ typedef union H5PL_key_t { } vol; } H5PL_key_t; +/* Enum dictating the type of plugins to process + * when iterating through available plugins + */ +typedef enum { + H5PL_ITER_TYPE_FILTER, + H5PL_ITER_TYPE_VOL, + H5PL_ITER_TYPE_ALL, +} H5PL_iterate_type_t; + +/* Callback function for iterating through the available plugins */ +typedef herr_t (*H5PL_iterate_t)(H5PL_type_t plugin_type, const void *plugin_info, void *op_data); + /*****************************/ /* Library-private Variables */ /*****************************/ @@ -54,5 +66,6 @@ typedef union H5PL_key_t { /* Internal API routines */ H5_DLL const void *H5PL_load(H5PL_type_t plugin_type, const H5PL_key_t *key); +H5_DLL herr_t H5PL_iterate(H5PL_iterate_type_t iter_type, H5PL_iterate_t iter_op, void *op_data); #endif /* H5PLprivate_H */ diff --git a/src/H5VL.c b/src/H5VL.c index 45a5d8e..f65d149 100644 --- a/src/H5VL.c +++ b/src/H5VL.c @@ -87,27 +87,6 @@ H5VLregister_connector(const H5VL_class_t *cls, hid_t vipl_id) FUNC_ENTER_API(H5I_INVALID_HID) H5TRACE2("i", "*xi", cls, vipl_id); - /* Check arguments */ - if (!cls) - HGOTO_ERROR(H5E_ARGS, H5E_UNINITIALIZED, H5I_INVALID_HID, - "VOL connector class pointer cannot be NULL") - if (H5VL_VERSION != cls->version) - HGOTO_ERROR(H5E_VOL, H5E_CANTREGISTER, H5I_INVALID_HID, "VOL connector has incompatible version") - if (!cls->name) - HGOTO_ERROR(H5E_VOL, H5E_CANTREGISTER, H5I_INVALID_HID, - "VOL connector class name cannot be the NULL pointer") - if (0 == HDstrlen(cls->name)) - HGOTO_ERROR(H5E_VOL, H5E_CANTREGISTER, H5I_INVALID_HID, - "VOL connector class name cannot be the empty string") - if (cls->info_cls.copy && !cls->info_cls.free) - HGOTO_ERROR( - H5E_VOL, H5E_CANTREGISTER, H5I_INVALID_HID, - "VOL connector must provide free callback for VOL info objects when a copy callback is provided") - if (cls->wrap_cls.get_wrap_ctx && !cls->wrap_cls.free_wrap_ctx) - HGOTO_ERROR(H5E_VOL, H5E_CANTREGISTER, H5I_INVALID_HID, - "VOL connector must provide free callback for object wrapping contexts when a get " - "callback is provided") - /* Check VOL initialization property list */ if (H5P_DEFAULT == vipl_id) vipl_id = H5P_VOL_INITIALIZE_DEFAULT; diff --git a/src/H5VLcallback.c b/src/H5VLcallback.c index b8db453..cde3f84 100644 --- a/src/H5VLcallback.c +++ b/src/H5VLcallback.c @@ -33,6 +33,7 @@ #include "H5Iprivate.h" /* IDs */ #include "H5MMprivate.h" /* Memory management */ #include "H5Pprivate.h" /* Property lists */ +#include "H5PLprivate.h" /* Plugins */ #include "H5VLpkg.h" /* Virtual Object Layer */ /****************/ @@ -43,6 +44,16 @@ /* Local Typedefs */ /******************/ +/* Structure used when trying to find a + * VOL connector to open a given file with. + */ +typedef struct H5VL_file_open_find_connector_t { + const char * filename; + const H5VL_class_t * cls; + H5VL_connector_prop_t *connector_prop; + hid_t fapl_id; +} H5VL_file_open_find_connector_t; + /********************/ /* Package Typedefs */ /********************/ @@ -101,6 +112,8 @@ static void * H5VL__file_create(const H5VL_class_t *cls, const char *name, unsig hid_t fapl_id, hid_t dxpl_id, void **req); static void * H5VL__file_open(const H5VL_class_t *cls, const char *name, unsigned flags, hid_t fapl_id, hid_t dxpl_id, void **req); +static herr_t H5VL__file_open_find_connector_cb(H5PL_type_t plugin_type, const void *plugin_info, + void *op_data); static herr_t H5VL__file_get(void *obj, const H5VL_class_t *cls, H5VL_file_get_t get_type, hid_t dxpl_id, void **req, va_list arguments); static herr_t H5VL__file_specific(void *obj, const H5VL_class_t *cls, H5VL_file_specific_t specific_type, @@ -3342,6 +3355,98 @@ done: } /* end H5VL__file_open() */ /*------------------------------------------------------------------------- + * Function: H5VL__file_open_find_connector_cb + * + * Purpose: Iteration callback for H5PL_iterate that tries to find the + * correct VOL connector to open a file with when + * H5VL_file_open fails for its given VOL connector. Iterates + * through all of the available VOL connector plugins until + * H5Fis_accessible returns true for the given filename and + * VOL connector. + * + * Return: H5_ITER_CONT if current plugin can't open the given file + * H5_ITER_STOP if current plugin can open given file + * H5_ITER_ERROR if an error occurs while trying to determine + * if current plugin can open given file. + * + *------------------------------------------------------------------------- + */ +static herr_t +H5VL__file_open_find_connector_cb(H5PL_type_t plugin_type, const void *plugin_info, void *op_data) +{ + H5VL_file_open_find_connector_t *udata = (H5VL_file_open_find_connector_t *)op_data; + const H5VL_class_t * cls = (const H5VL_class_t *)plugin_info; + H5P_genplist_t * fapl_plist; + H5P_genplist_t * fapl_plist_copy; + herr_t status; + htri_t is_accessible = FALSE; + hid_t connector_id = H5I_INVALID_HID; + hid_t fapl_id = H5I_INVALID_HID; + herr_t ret_value = H5_ITER_CONT; + + FUNC_ENTER_STATIC + + HDassert(udata); + HDassert(udata->filename); + HDassert(udata->connector_prop); + HDassert(cls); + HDassert(plugin_type == H5PL_TYPE_VOL); + + /* Silence compiler */ + (void)plugin_type; + + udata->cls = cls; + + /* Attempt to register plugin as a VOL connector */ + if ((connector_id = H5VL__register_connector_by_class(cls, TRUE, H5P_VOL_INITIALIZE_DEFAULT)) < 0) + HGOTO_ERROR(H5E_VOL, H5E_CANTREGISTER, H5_ITER_ERROR, "unable to register VOL connector") + + /* Setup FAPL with registered VOL connector */ + if (NULL == (fapl_plist = (H5P_genplist_t *)H5I_object_verify(udata->fapl_id, H5I_GENPROP_LST))) + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, H5_ITER_ERROR, "not a property list") + if ((fapl_id = H5P_copy_plist(fapl_plist, TRUE)) < 0) + HGOTO_ERROR(H5E_PLIST, H5E_CANTCOPY, H5_ITER_ERROR, "can't copy fapl"); + if (NULL == (fapl_plist_copy = (H5P_genplist_t *)H5I_object_verify(fapl_id, H5I_GENPROP_LST))) + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, H5_ITER_ERROR, "not a property list") + if (H5P_set_vol(fapl_plist_copy, connector_id, NULL) < 0) + HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, H5_ITER_ERROR, "can't set VOL connector on fapl") + + /* Check if file is accessible with given VOL connector */ + H5E_BEGIN_TRY + { + status = H5VL_file_specific(NULL, H5VL_FILE_IS_ACCESSIBLE, H5P_DATASET_XFER_DEFAULT, H5_REQUEST_NULL, + fapl_id, udata->filename, &is_accessible); + } + H5E_END_TRY; + + /* If the file was accessible with the current VOL connector, return + * the FAPL with that VOL connector set on it. Errors are ignored here + * as some VOL connectors may not support H5Fis_accessible. + */ + if (status == SUCCEED && is_accessible > 0) { + /* Modify 'connector_prop' to point to the VOL connector that + * was actually used to open the file, rather than the original + * VOL connector that was requested. + */ + udata->connector_prop->connector_id = connector_id; + udata->connector_prop->connector_info = NULL; + + udata->fapl_id = fapl_id; + ret_value = H5_ITER_STOP; + } /* end if */ + +done: + if (ret_value != H5_ITER_STOP) { + if (fapl_id >= 0 && H5I_dec_app_ref(fapl_id) < 0) + HDONE_ERROR(H5E_PLIST, H5E_CANTCLOSEOBJ, H5_ITER_ERROR, "can't close fapl") + if (connector_id >= 0 && H5I_dec_app_ref(connector_id) < 0) + HDONE_ERROR(H5E_ATOM, H5E_CANTCLOSEOBJ, H5_ITER_ERROR, "can't close VOL connector ID") + } /* end if */ + + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5VL__file_open_find_connector_cb() */ + +/*------------------------------------------------------------------------- * Function: H5VL_file_open * * Purpose: Opens a file through the VOL. @@ -3355,7 +3460,7 @@ done: *------------------------------------------------------------------------- */ void * -H5VL_file_open(const H5VL_connector_prop_t *connector_prop, const char *name, unsigned flags, hid_t fapl_id, +H5VL_file_open(H5VL_connector_prop_t *connector_prop, const char *name, unsigned flags, hid_t fapl_id, hid_t dxpl_id, void **req) { H5VL_class_t *cls; /* VOL Class structure for callback info */ @@ -3368,8 +3473,54 @@ H5VL_file_open(const H5VL_connector_prop_t *connector_prop, const char *name, un HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, NULL, "not a VOL connector ID") /* Call the corresponding internal VOL routine */ - if (NULL == (ret_value = H5VL__file_open(cls, name, flags, fapl_id, dxpl_id, req))) - HGOTO_ERROR(H5E_VOL, H5E_CANTOPENOBJ, NULL, "open failed") + if (NULL == (ret_value = H5VL__file_open(cls, name, flags, fapl_id, dxpl_id, req))) { + H5VL_file_open_find_connector_t find_connector_ud; + hbool_t find_connector; + hbool_t connector_available = FALSE; + + /* Opening the file failed - Determine whether we should search + * the plugin path to see if any other VOL connectors are available + * to attempt to open the file with. This only occurs if no particular + * VOL connector was specified (either via a FAPL or the + * HDF5_VOL_CONNECTOR environment variable). + */ + find_connector = !getenv("HDF5_VOL_CONNECTOR") && ((H5P_FILE_ACCESS_DEFAULT == fapl_id) || + connector_prop->connector_id == H5_DEFAULT_VOL); + + if (find_connector) { + herr_t iter_ret; + + find_connector_ud.connector_prop = connector_prop; + find_connector_ud.filename = name; + find_connector_ud.cls = NULL; + find_connector_ud.fapl_id = fapl_id; + + iter_ret = H5PL_iterate(H5PL_ITER_TYPE_VOL, H5VL__file_open_find_connector_cb, + (void *)&find_connector_ud); + if (iter_ret < 0) + HGOTO_ERROR(H5E_VOL, H5E_BADITER, NULL, + "failed to iterate over available VOL connector plugins") + else if (iter_ret) + connector_available = TRUE; + } /* end if */ + + /* If one of the available VOL connector plugins is + * able to open the file, clear the error stack from any + * previous file open failures and then open the file. + * Otherwise, if no VOL connectors are available, throw + * error from original file open failure. + */ + if (connector_available) { + H5E_clear_stack(NULL); + + if (NULL == (ret_value = H5VL__file_open(find_connector_ud.cls, name, flags, + find_connector_ud.fapl_id, dxpl_id, req))) + HGOTO_ERROR(H5E_VOL, H5E_CANTOPENOBJ, NULL, "can't open file '%s' with VOL connector '%s'", + name, find_connector_ud.cls->name) + } + else + HGOTO_ERROR(H5E_VOL, H5E_CANTOPENOBJ, NULL, "open failed") + } /* end if */ done: FUNC_LEAVE_NOAPI(ret_value) diff --git a/src/H5VLint.c b/src/H5VLint.c index a0596fd..774d160 100644 --- a/src/H5VLint.c +++ b/src/H5VLint.c @@ -1219,6 +1219,27 @@ H5VL__register_connector_by_class(const H5VL_class_t *cls, hbool_t app_ref, hid_ FUNC_ENTER_PACKAGE + /* Check arguments */ + if (!cls) + HGOTO_ERROR(H5E_ARGS, H5E_UNINITIALIZED, H5I_INVALID_HID, + "VOL connector class pointer cannot be NULL") + if (H5VL_VERSION != cls->version) + HGOTO_ERROR(H5E_VOL, H5E_CANTREGISTER, H5I_INVALID_HID, "VOL connector has incompatible version") + if (!cls->name) + HGOTO_ERROR(H5E_VOL, H5E_CANTREGISTER, H5I_INVALID_HID, + "VOL connector class name cannot be the NULL pointer") + if (0 == HDstrlen(cls->name)) + HGOTO_ERROR(H5E_VOL, H5E_CANTREGISTER, H5I_INVALID_HID, + "VOL connector class name cannot be the empty string") + if (cls->info_cls.copy && !cls->info_cls.free) + HGOTO_ERROR( + H5E_VOL, H5E_CANTREGISTER, H5I_INVALID_HID, + "VOL connector must provide free callback for VOL info objects when a copy callback is provided") + if (cls->wrap_cls.get_wrap_ctx && !cls->wrap_cls.free_wrap_ctx) + HGOTO_ERROR(H5E_VOL, H5E_CANTREGISTER, H5I_INVALID_HID, + "VOL connector must provide free callback for object wrapping contexts when a get " + "callback is provided") + /* Set up op data for iteration */ op_data.kind = H5VL_GET_CONNECTOR_BY_NAME; op_data.u.name = cls->name; diff --git a/src/H5VLprivate.h b/src/H5VLprivate.h index d87ebb1..678a27f 100644 --- a/src/H5VLprivate.h +++ b/src/H5VLprivate.h @@ -181,7 +181,7 @@ H5_DLL herr_t H5VL_datatype_close(const H5VL_object_t *vol_obj, hid_t dxpl_id, v /* File functions */ H5_DLL void * H5VL_file_create(const H5VL_connector_prop_t *connector_prop, const char *name, unsigned flags, hid_t fcpl_id, hid_t fapl_id, hid_t dxpl_id, void **req); -H5_DLL void * H5VL_file_open(const H5VL_connector_prop_t *connector_prop, const char *name, unsigned flags, +H5_DLL void * H5VL_file_open(H5VL_connector_prop_t *connector_prop, const char *name, unsigned flags, hid_t fapl_id, hid_t dxpl_id, void **req); H5_DLL herr_t H5VL_file_get(const H5VL_object_t *vol_obj, H5VL_file_get_t get_type, hid_t dxpl_id, void **req, ...); -- cgit v0.12