diff options
author | Dana Robinson <derobins@hdfgroup.org> | 2017-08-01 16:02:41 (GMT) |
---|---|---|
committer | Dana Robinson <derobins@hdfgroup.org> | 2017-08-01 16:02:41 (GMT) |
commit | 464926f2a3adf3ef1c1e3ae60105544f08ff1e51 (patch) | |
tree | 31ad5d96c432f466844091a51e732b75ef3c6a00 | |
parent | 80745c75087fc30200fd6a6ceed4ce94378ee0ee (diff) | |
parent | 9bcf8b2f2568083449ae3f9b6c2efbf6ed7f413a (diff) | |
download | hdf5-464926f2a3adf3ef1c1e3ae60105544f08ff1e51.zip hdf5-464926f2a3adf3ef1c1e3ae60105544f08ff1e51.tar.gz hdf5-464926f2a3adf3ef1c1e3ae60105544f08ff1e51.tar.bz2 |
Merge pull request #621 in HDFFV/hdf5 from ~DEROBINS/hdf5_der:h5pl_commit to develop
* commit '9bcf8b2f2568083449ae3f9b6c2efbf6ed7f413a':
Minor tweaks in response to code review.
Fixed a failing Java plugin test.
Major rework of H5PL package code before bringing VOL changes over.
-rw-r--r-- | MANIFEST | 3 | ||||
-rwxr-xr-x | bin/trace | 4 | ||||
-rw-r--r-- | java/test/TestH5PL.java | 88 | ||||
-rw-r--r-- | src/CMakeLists.txt | 3 | ||||
-rw-r--r-- | src/H5PL.c | 987 | ||||
-rw-r--r-- | src/H5PLextern.h | 4 | ||||
-rw-r--r-- | src/H5PLint.c | 381 | ||||
-rw-r--r-- | src/H5PLmodule.h | 10 | ||||
-rw-r--r-- | src/H5PLpath.c | 776 | ||||
-rw-r--r-- | src/H5PLpkg.h | 113 | ||||
-rw-r--r-- | src/H5PLplugin_cache.c | 308 | ||||
-rw-r--r-- | src/H5PLprivate.h | 4 | ||||
-rw-r--r-- | src/H5PLpublic.h | 34 | ||||
-rw-r--r-- | src/H5system.c | 46 | ||||
-rw-r--r-- | src/H5win32defs.h | 1 | ||||
-rw-r--r-- | src/Makefile.am | 2 | ||||
-rw-r--r-- | test/plugin.c | 486 |
17 files changed, 2235 insertions, 1015 deletions
@@ -799,8 +799,11 @@ ./src/H5PBpkg.h ./src/H5PBprivate.h ./src/H5PL.c +./src/H5PLint.c ./src/H5PLmodule.h +./src/H5PLpath.c ./src/H5PLpkg.h +./src/H5PLplugin_cache.c ./src/H5PLprivate.h ./src/H5PLpublic.h ./src/H5PLextern.h @@ -76,7 +76,7 @@ $Source = ""; "off_t" => "o", "H5O_type_t" => "Ot", "H5P_class_t" => "p", - "hobj_ref_t" => "r", + "hobj_ref_t" => "r", "H5R_type_t" => "Rt", "char" => "s", "unsigned char" => "s", @@ -124,7 +124,7 @@ $Source = ""; "H5G_iterate_t" => "x", "H5G_info_t" => "x", "H5I_free_t" => "x", - "H5I_search_func_t" => "x", + "H5I_search_func_t" => "x", "H5L_class_t" => "x", "H5L_elink_traverse_t" => "x", "H5L_iterate_t" => "x", diff --git a/java/test/TestH5PL.java b/java/test/TestH5PL.java index aa59478..8ce708b 100644 --- a/java/test/TestH5PL.java +++ b/java/test/TestH5PL.java @@ -70,26 +70,74 @@ public class TestH5PL { @Test public void TestH5PLpaths() { try { - int original_entries = H5.H5PLsize(); - H5.H5PLappend("path_one"); - int plugin_entries = H5.H5PLsize(); - assertTrue("H5.H5PLsize: "+plugin_entries, (original_entries+1) == plugin_entries); - H5.H5PLprepend("path_two"); - plugin_entries = H5.H5PLsize(); - assertTrue("H5.H5PLsize: "+plugin_entries, (original_entries+2) == plugin_entries); - H5.H5PLinsert("path_three", original_entries); - plugin_entries = H5.H5PLsize(); - assertTrue("H5.H5PLsize: "+plugin_entries, (original_entries+3) == plugin_entries); - String first_path = H5.H5PLget(original_entries); - assertTrue("First path was : "+first_path + " ",first_path.compareToIgnoreCase("path_three")==0); - H5.H5PLreplace("path_four", original_entries); - first_path = H5.H5PLget(original_entries); - assertTrue("First path changed to : "+first_path + " ",first_path.compareToIgnoreCase("path_four")==0); - H5.H5PLremove(original_entries); - first_path = H5.H5PLget(original_entries); - assertTrue("First path now : "+first_path + " ",first_path.compareToIgnoreCase("path_two")==0); - plugin_entries = H5.H5PLsize(); - assertTrue("H5.H5PLsize: "+plugin_entries, (original_entries+2) == plugin_entries); + // Get the original number of paths + int nStartPaths = H5.H5PLsize(); + + int nPaths; /* # paths from H5PLSize() */ + int nTruePaths = nStartPaths; /* What the # paths should be */ + int index; /* Path table index */ + String path; /* Path from H5PLget() */ + + // APPEND a path and ensure it was added correctly + String pathAppend = "path_append"; + H5.H5PLappend(pathAppend); + + nPaths = H5.H5PLsize(); + nTruePaths++; + assertTrue("# paths should be " + nTruePaths + " but was " + nPaths, nTruePaths == nPaths); + + index = nTruePaths - 1; + path = H5.H5PLget(index); + assertTrue("Path should be " + pathAppend + " but was " + path, path.compareToIgnoreCase(pathAppend) == 0); + + // PREPEND a path and ensure it was added correctly + String pathPrepend = "path_prepend"; + H5.H5PLprepend(pathPrepend); + + nPaths = H5.H5PLsize(); + nTruePaths++; + assertTrue("# paths should be " + nTruePaths + " but was " + nPaths, nTruePaths == nPaths); + + index = 0; + path = H5.H5PLget(index); + assertTrue("Path should be " + pathPrepend + " but was " + path, path.compareToIgnoreCase(pathPrepend) == 0); + + // INSERT a path and ensure it was added correctly + // Inserting at the index == # of start paths ensures we're in the middle + String pathInsert = "path_insert"; + index = nStartPaths; + H5.H5PLinsert(pathInsert, index); + + nPaths = H5.H5PLsize(); + nTruePaths++; + assertTrue("# paths should be " + nTruePaths + " but was " + nPaths, nTruePaths == nPaths); + + path = H5.H5PLget(index); + assertTrue("Path should be " + pathInsert + " but was " + path, path.compareToIgnoreCase(pathInsert) == 0); + + // REPLACE the path we just added and ensure it updated correctly + String pathReplace = "path_replace"; + index = nStartPaths; + H5.H5PLreplace(pathReplace, index); + + nPaths = H5.H5PLsize(); + assertTrue("# paths should be " + nTruePaths + " but was " + nPaths, nTruePaths == nPaths); + + path = H5.H5PLget(index); + assertTrue("Path should be " + pathReplace + " but was " + path, path.compareToIgnoreCase(pathReplace) == 0); + + // REMOVE the path we just replaced and check that the table was compacted + // The (index+1) path should move down to fill the space when the path is removed. + index = nStartPaths; + String pathRemove = H5.H5PLget(index + 1); + H5.H5PLremove(index); + + nPaths = H5.H5PLsize(); + nTruePaths--; + assertTrue("# paths should be " + nTruePaths + " but was " + nPaths, nTruePaths == nPaths); + + path = H5.H5PLget(index); + assertTrue("Path should be " + pathRemove + " but was " + path, path.compareToIgnoreCase(pathRemove) == 0); } catch (Throwable err) { err.printStackTrace(); diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 178c954..96ea589 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -516,6 +516,9 @@ IDE_GENERATED_PROPERTIES ("H5PB" "${H5PB_HDRS}" "${H5PB_SOURCES}" ) set (H5PL_SOURCES ${HDF5_SRC_DIR}/H5PL.c + ${HDF5_SRC_DIR}/H5PLint.c + ${HDF5_SRC_DIR}/H5PLpath.c + ${HDF5_SRC_DIR}/H5PLplugin_cache.c ) set (H5PL_HDRS @@ -22,135 +22,28 @@ /***********/ #include "H5private.h" /* Generic Functions */ #include "H5Eprivate.h" /* Error handling */ -#include "H5MMprivate.h" /* Memory management */ #include "H5PLpkg.h" /* Plugin */ -#include "H5Zprivate.h" /* Filter pipeline */ /****************/ /* Local Macros */ /****************/ -#ifdef H5_HAVE_WIN32_API -#define H5PL_EXPAND_ENV_VAR { \ - long bufCharCount; \ - char *tempbuf; \ - if(NULL == (tempbuf = (char *)H5MM_malloc(H5PL_EXPAND_BUFFER_SIZE))) \ - HGOTO_ERROR(H5E_PLUGIN, H5E_CANTALLOC, FAIL, "can't allocate memory for expanded path") \ - if((bufCharCount = ExpandEnvironmentStringsA(dl_path, tempbuf, H5PL_EXPAND_BUFFER_SIZE)) > H5PL_EXPAND_BUFFER_SIZE) { \ - tempbuf = (char *)H5MM_xfree(tempbuf); \ - HGOTO_ERROR(H5E_PLUGIN, H5E_NOSPACE, FAIL, "expanded path is too long") \ - } \ - if(bufCharCount == 0) { \ - tempbuf = (char *)H5MM_xfree(tempbuf); \ - HGOTO_ERROR(H5E_PLUGIN, H5E_CANTGET, FAIL, "failed to expand path") \ - } \ - dl_path = (char *)H5MM_xfree(dl_path); \ - dl_path = tempbuf; \ - } -#else -#define H5PL_EXPAND_ENV_VAR -#endif /* H5_HAVE_WIN32_API */ - -/****************************/ -/* Macros for supporting - * both Windows and Unix */ -/****************************/ -/* Windows support - * - * SPECIAL WINDOWS NOTE - * - * Some of the Win32 API functions expand to fooA or fooW depending on - * whether UNICODE or _UNICODE are defined. You MUST explicitly use - * the A version of the functions to force char * behavior until we - * work out a scheme for proper Windows Unicode support. - * - * If you do not do this, people will be unable to incorporate our - * source code into their own CMake builds if they define UNICODE. - */ -#ifdef H5_HAVE_WIN32_API - -#define H5PL_PATH_SEPARATOR ";" - -/* Handle for dynamic library */ -#define H5PL_HANDLE HINSTANCE - -/* Get a handle to a plugin library. Windows: TEXT macro handles Unicode strings */ -#define H5PL_OPEN_DLIB(S) LoadLibraryExA(S, NULL, LOAD_WITH_ALTERED_SEARCH_PATH) - -/* Get the address of a symbol in dynamic library */ -#define H5PL_GET_LIB_FUNC(H,N) GetProcAddress(H,N) - -/* Close dynamic library */ -#define H5PL_CLOSE_LIB(H) FreeLibrary(H) - -/* Clear error - nothing to do */ -#define H5PL_CLR_ERROR - -/* maximum size for expanding env vars */ -#define H5PL_EXPAND_BUFFER_SIZE 32767 - -typedef const void *(__cdecl *H5PL_get_plugin_info_t)(void); - -/* Unix support */ -#else /* H5_HAVE_WIN32_API */ - -#define H5PL_PATH_SEPARATOR ":" - -/* Handle for dynamic library */ -#define H5PL_HANDLE void * - -/* Get a handle to a plugin library. Windows: TEXT macro handles Unicode strings */ -#define H5PL_OPEN_DLIB(S) dlopen(S, RTLD_LAZY) - -/* Get the address of a symbol in dynamic library */ -#define H5PL_GET_LIB_FUNC(H,N) dlsym(H,N) - -/* Close dynamic library */ -#define H5PL_CLOSE_LIB(H) dlclose(H) - -/* Clear error */ -#define H5PL_CLR_ERROR HERROR(H5E_PLUGIN, H5E_CANTGET, "can't dlopen:%s", dlerror()) - -typedef const void *(*H5PL_get_plugin_info_t)(void); -#endif /* H5_HAVE_WIN32_API */ - -/* Whether to preload pathnames for plugin libraries */ -#define H5PL_DEFAULT_PATH H5_DEFAULT_PLUGINDIR - -/* Special symbol to indicate no plugin loading */ -#define H5PL_NO_PLUGIN "::" /******************/ /* Local Typedefs */ /******************/ -/* Type for the list of info for opened plugin libraries */ -typedef struct H5PL_table_t { - H5PL_type_t pl_type; /* plugin type */ - int pl_id; /* ID for the plugin */ - H5PL_HANDLE handle; /* plugin handle */ -} H5PL_table_t; - /********************/ /* Local Prototypes */ /********************/ -static herr_t H5PL__init_path_table(void); -static htri_t H5PL__find(H5PL_type_t plugin_type, int type_id, char *dir, const void **info); -static htri_t H5PL__open(H5PL_type_t pl_type, char *libname, int plugin_id, const void **pl_info); -static htri_t H5PL__search_table(H5PL_type_t plugin_type, int type_id, const void **info); -static herr_t H5PL__close(H5PL_HANDLE handle); - /*********************/ /* Package Variables */ /*********************/ -/* Package initialization variable */ -hbool_t H5_PKG_INIT_VAR = FALSE; - /*****************************/ /* Library Private Variables */ @@ -161,145 +54,43 @@ hbool_t H5_PKG_INIT_VAR = FALSE; /* Local Variables */ /*******************/ -/* Table for opened plugin libraries */ -static size_t H5PL_table_alloc_g = 0; -static size_t H5PL_table_used_g = 0; -static H5PL_table_t *H5PL_table_g = NULL; - -/* Table of location paths for plugin libraries */ -static char *H5PL_path_table_g[H5PL_MAX_PATH_NUM]; -static size_t H5PL_num_paths_g = 0; -static hbool_t H5PL_path_found_g = FALSE; - -/* Enable all plugin libraries */ -static unsigned int H5PL_plugin_g = H5PL_ALL_PLUGIN; - - - -/*-------------------------------------------------------------------------- -NAME - H5PL__init_package -- Initialize interface-specific information -USAGE - herr_t H5PL__init_package() -RETURNS - Non-negative on success/Negative on failure -DESCRIPTION - Initializes any interface-specific data or routines. - ---------------------------------------------------------------------------*/ -herr_t -H5PL__init_package(void) -{ - char *preload_path; - - FUNC_ENTER_PACKAGE_NOERR - - /* Retrieve pathnames from HDF5_PLUGIN_PRELOAD if the user sets it - * to tell the library to load plugin libraries without search. - */ - if(NULL != (preload_path = HDgetenv("HDF5_PLUGIN_PRELOAD"))) - /* Special symbol "::" means no plugin during data reading. */ - if(!HDstrcmp(preload_path, H5PL_NO_PLUGIN)) - H5PL_plugin_g = 0; - - FUNC_LEAVE_NOAPI(SUCCEED) -} /* end H5PL__init_package() */ /*------------------------------------------------------------------------- - * Function: H5PL_term_package - * - * Purpose: Terminate the H5PL interface: release all memory, reset all - * global variables to initial values. This only happens if all - * types have been destroyed from other interfaces. + * Function: H5PLset_loading_state * - * Return: Success: Positive if any action was taken that might - * affect some other interface; zero otherwise. - * Failure: Negative. - * - * Programmer: Raymond Lu - * 20 February 2013 - * - *------------------------------------------------------------------------- - */ -int -H5PL_term_package(void) -{ - int n = 0; - - FUNC_ENTER_NOAPI_NOINIT_NOERR - - if(H5_PKG_INIT_VAR) { - size_t u; /* Local index variable */ - - /* Close opened dynamic libraries */ - if(H5PL_table_g) { - for(u = 0; u < H5PL_table_used_g; u++) - H5PL__close((H5PL_table_g[u]).handle); - - /* Free the table of dynamic libraries */ - H5PL_table_g = (H5PL_table_t *)H5MM_xfree(H5PL_table_g); - H5PL_table_used_g = H5PL_table_alloc_g = 0; - - n++; - } /* end if */ - - /* Free the table of search paths */ - if(H5PL_num_paths_g > 0) { - for(u = 0; u < H5PL_num_paths_g; u++) - if(H5PL_path_table_g[u]) - H5PL_path_table_g[u] = (char *)H5MM_xfree(H5PL_path_table_g[u]); - H5PL_num_paths_g = 0; - H5PL_path_found_g = FALSE; - - n++; - } /* end if */ - - /* Mark the interface as uninitialized */ - if(0 == n) - H5_PKG_INIT_VAR = FALSE; - } /* end if */ - - FUNC_LEAVE_NOAPI(n) -} /* end H5PL_term_package() */ - - -/*------------------------------------------------------------------------- - * Function: H5PLset_loading_state + * Purpose: Control the loading of dynamic plugin types. * - * Purpose: Control the loading of dynamic plugin types. + * The plugin_control_mask parameter is a bitfield that controls + * whether certain classes of plugins (e.g.: filters, + * VOL drivers) will be loaded by the library. * - * This function will not allow plugin types if the pathname from the HDF5_PLUGIN_PRELOAD - * environment variable is set to the special "::" string. + * plugin bit = 0, will prevent the use of that dynamic plugin type. + * plugin bit = 1, will allow the use of that dynamic plugin type. * - * plugin bit = 0, will prevent the use of that dynamic plugin type. - * plugin bit = 1, will allow the use of that dynamic plugin type. + * A list of pre-defined masks can be found in H5PLpublic.h. + * Set the mask to 0 to disable all plugins. * - * H5PL_TYPE_FILTER changes just dynamic filters - * A H5PL_ALL_PLUGIN will enable all dynamic plugin types - * A zero value will disable all dynamic plugin types + * This function will not allow plugin types if the pathname + * from the HDF5_PLUGIN_PRELOAD environment variable is set to + * the special "::" string. * - * Return: Non-negative or success + * Return: Success: Non-negative + * Failture: Negative * *------------------------------------------------------------------------- */ herr_t -H5PLset_loading_state(unsigned int plugin_type) +H5PLset_loading_state(unsigned int plugin_control_mask) { - char *preload_path; - herr_t ret_value = SUCCEED; /* Return value */ + herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_API(FAIL) - H5TRACE1("e", "Iu", plugin_type); - - /* change the bit value of the requested plugin type(s) */ - H5PL_plugin_g = plugin_type; + H5TRACE1("e", "Iu", plugin_control_mask); - /* check if special ENV variable is set and disable all plugin types */ - if(NULL != (preload_path = HDgetenv("HDF5_PLUGIN_PRELOAD"))) - /* Special symbol "::" means no plugin during data reading. */ - if(!HDstrcmp(preload_path, H5PL_NO_PLUGIN)) - H5PL_plugin_g = 0; + /* Set the plugin control mask */ + if(H5PL__set_plugin_control_mask(plugin_control_mask) < 0) + HGOTO_ERROR(H5E_ARGS, H5E_CANTSET, FAIL, "error setting plugin control mask") done: FUNC_LEAVE_API(ret_value) @@ -307,27 +98,35 @@ done: /*------------------------------------------------------------------------- - * Function: H5PLget_loading_state + * Function: H5PLget_loading_state * - * Purpose: Query state of the loading of dynamic plugin types. + * Purpose: Get the bitmask that controls whether certain classes + * of plugins (e.g.: filters, VOL drivers) will be loaded + * by the library. * - * This function will return the state of the global flag. + * Zero if all plugin types are disabled + * Negative if all plugin types are enabled + * Positive if one or more of the plugin types are enabled * - * Return: Zero if all plugin types are disabled, negative if all - * plugin types are enabled, positive if one or more of the plugin types are enabled. + * Return: Success: Non-negative + * Failture: Negative * *------------------------------------------------------------------------- */ herr_t -H5PLget_loading_state(unsigned int *plugin_type) +H5PLget_loading_state(unsigned int *plugin_control_mask) { - herr_t ret_value = SUCCEED; /* Return value */ + herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_API(FAIL) - H5TRACE1("e", "*Iu", plugin_type); + H5TRACE1("e", "*Iu", plugin_control_mask); + + if (NULL == plugin_control_mask) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "plugin_control_mask parameter cannot be NULL") - if(plugin_type) - *plugin_type = H5PL_plugin_g; + /* Set the plugin control mask */ + if(H5PL__get_plugin_control_mask(plugin_control_mask) < 0) + HGOTO_ERROR(H5E_ARGS, H5E_CANTGET, FAIL, "error getting plugin control mask") done: FUNC_LEAVE_API(ret_value) @@ -335,674 +134,282 @@ done: /*------------------------------------------------------------------------- - * Function: H5PL_load - * - * Purpose: Given the plugin type and identifier, this function searches - * and/or loads a dynamic plugin library first among the already - * opened libraries then in the designated location paths. - * - * Return: Non-NULL on success/NULL on failure - * - * Programmer: Raymond Lu - * 13 February 2013 - * - *------------------------------------------------------------------------- - */ -const void * -H5PL_load(H5PL_type_t type, int id) -{ - htri_t found; /* Whether the plugin was found */ - const void *plugin_info = NULL; - const void *ret_value = NULL; - - FUNC_ENTER_NOAPI(NULL) - - switch(type) { - case H5PL_TYPE_FILTER: - if((H5PL_plugin_g & H5PL_FILTER_PLUGIN) == 0) - HGOTO_ERROR(H5E_PLUGIN, H5E_CANTLOAD, NULL, "required dynamically loaded plugin filter '%d' is not available", id) - break; - - case H5PL_TYPE_ERROR: - case H5PL_TYPE_NONE: - default: - HGOTO_ERROR(H5E_PLUGIN, H5E_CANTLOAD, NULL, "required dynamically loaded plugin '%d' is not valid", id) - } /* end switch */ - - /* Initialize the location paths for dynamic libraries, if they aren't - * already set up. - */ - if(FALSE == H5PL_path_found_g) - if(H5PL__init_path_table() < 0) - HGOTO_ERROR(H5E_PLUGIN, H5E_CANTINIT, NULL, "can't initialize search path table") - - /* Search in the table of already loaded plugin libraries */ - if((found = H5PL__search_table(type, id, &plugin_info)) < 0) - HGOTO_ERROR(H5E_PLUGIN, H5E_CANTGET, NULL, "search in table failed") - - /* If not found, iterate through the path table to find the right dynamic library */ - if(!found) { - size_t i; /* Local index variable */ - - for(i = 0; i < H5PL_num_paths_g; i++) { - if((found = H5PL__find(type, id, H5PL_path_table_g[i], &plugin_info)) < 0) - HGOTO_ERROR(H5E_PLUGIN, H5E_CANTGET, NULL, "search in paths failed") - - /* Break out if found */ - if(found) { - HDassert(plugin_info); - break; - } /* end if */ - } /* end for */ - } /* end if */ - - /* Check if we found the plugin */ - if(found) - ret_value = plugin_info; - -done: - FUNC_LEAVE_NOAPI(ret_value) -} /* end H5PL_load() */ - - -/*------------------------------------------------------------------------- - * Function: H5PLappend + * Function: H5PLappend * - * Purpose: Insert a plugin path at the end of the list. + * Purpose: Insert a plugin search path at the end of the list. * - * Return: Non-negative or success. + * Return: Success: Non-negative + * Failture: Negative * *------------------------------------------------------------------------- */ herr_t -H5PLappend(const char *plugin_path) +H5PLappend(const char *search_path) { herr_t ret_value = SUCCEED; /* Return value */ - char *dl_path = NULL; FUNC_ENTER_API(FAIL) - H5TRACE1("e", "*s", plugin_path); - if(H5PL_num_paths_g == H5PL_MAX_PATH_NUM) - HGOTO_ERROR(H5E_PLUGIN, H5E_NOSPACE, FAIL, "too many directories in path for table") - if(NULL == plugin_path) - HGOTO_ERROR(H5E_PLUGIN, H5E_CANTALLOC, FAIL, "no path provided") - if(NULL == (dl_path = H5MM_strdup(plugin_path))) - HGOTO_ERROR(H5E_PLUGIN, H5E_CANTALLOC, FAIL, "can't allocate memory for path") + H5TRACE1("e", "*s", search_path); - H5PL_EXPAND_ENV_VAR + /* Check args */ + if (NULL == search_path) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "plugin_path parameter cannot be NULL") + if (0 == HDstrlen(search_path)) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "plugin_path parameter cannot have length zero") - H5PL_path_table_g[H5PL_num_paths_g] = dl_path; - H5PL_num_paths_g++; + /* Append the search path to the path table */ + if (H5PL__append_path(search_path) < 0) + HGOTO_ERROR(H5E_PLUGIN, H5E_CANTAPPEND, FAIL, "unable to append search path") done: FUNC_LEAVE_API(ret_value) } /* end H5PLappend() */ - + /*------------------------------------------------------------------------- - * Function: H5PLprepend + * Function: H5PLprepend * - * Purpose: Insert a plugin path at the beginning of the list. + * Purpose: Insert a plugin search path at the beginning of the list. * - * Return: Non-negative or success. + * Return: Success: Non-negative + * Failture: Negative * *------------------------------------------------------------------------- */ herr_t -H5PLprepend(const char *plugin_path) +H5PLprepend(const char *search_path) { herr_t ret_value = SUCCEED; /* Return value */ - char *dl_path = NULL; - unsigned int plindex; FUNC_ENTER_API(FAIL) - H5TRACE1("e", "*s", plugin_path); - if(H5PL_num_paths_g == H5PL_MAX_PATH_NUM) - HGOTO_ERROR(H5E_PLUGIN, H5E_NOSPACE, FAIL, "too many directories in path for table") - if(NULL == plugin_path) - HGOTO_ERROR(H5E_PLUGIN, H5E_CANTALLOC, FAIL, "no path provided") - if(NULL == (dl_path = H5MM_strdup(plugin_path))) - HGOTO_ERROR(H5E_PLUGIN, H5E_CANTALLOC, FAIL, "can't allocate memory for path") + H5TRACE1("e", "*s", search_path); - H5PL_EXPAND_ENV_VAR + /* Check args */ + if (NULL == search_path) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "plugin_path parameter cannot be NULL") + if (0 == HDstrlen(search_path)) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "plugin_path parameter cannot have length zero") - for (plindex = (unsigned int)H5PL_num_paths_g; plindex > 0; plindex--) - H5PL_path_table_g[plindex] = H5PL_path_table_g[plindex - 1]; - H5PL_path_table_g[0] = dl_path; - H5PL_num_paths_g++; + /* Prepend the search path to the path table */ + if (H5PL__prepend_path(search_path) < 0) + HGOTO_ERROR(H5E_PLUGIN, H5E_CANTINSERT, FAIL, "unable to prepend search path") done: FUNC_LEAVE_API(ret_value) } /* end H5PLprepend() */ - + /*------------------------------------------------------------------------- - * Function: H5PLreplace + * Function: H5PLreplace * - * Purpose: Replace the path at the specified index. + * Purpose: Replace the path at the specified index. The path at the + * index must exist. * - * Return: Non-negative or success. + * Return: Non-negative or success. * *------------------------------------------------------------------------- */ herr_t -H5PLreplace(const char *plugin_path, unsigned int index) +H5PLreplace(const char *search_path, unsigned int index) { - herr_t ret_value = SUCCEED; /* Return value */ - char *dl_path = NULL; + unsigned num_paths; /* Current number of stored paths */ + herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_API(FAIL) - H5TRACE2("e", "*sIu", plugin_path, index); - if(NULL == plugin_path) - HGOTO_ERROR(H5E_PLUGIN, H5E_CANTALLOC, FAIL, "no path provided") - if(index >= H5PL_MAX_PATH_NUM) - HGOTO_ERROR(H5E_PLUGIN, H5E_NOSPACE, FAIL, "index path out of bounds for table") - if(NULL == (dl_path = H5MM_strdup(plugin_path))) - HGOTO_ERROR(H5E_PLUGIN, H5E_CANTALLOC, FAIL, "can't allocate memory for path") + H5TRACE2("e", "*sIu", search_path, index); - H5PL_EXPAND_ENV_VAR + /* Check args */ + if (NULL == search_path) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "plugin_path parameter cannot be NULL") + if (0 == HDstrlen(search_path)) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "plugin_path parameter cannot have length zero") - if(H5PL_path_table_g[index]) - H5PL_path_table_g[index] = (char *)H5MM_xfree(H5PL_path_table_g[index]); - H5PL_path_table_g[index] = dl_path; + /* Check index */ + num_paths = H5PL__get_num_paths(); + if (0 == num_paths) + HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, FAIL, "path table is empty") + else if (index >= num_paths) + HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, FAIL, "index path out of bounds for table - can't be more than %u", (num_paths - 1)) + + /* Insert the search path into the path table */ + if (H5PL__replace_path(search_path, index) < 0) + HGOTO_ERROR(H5E_PLUGIN, H5E_CANTINSERT, FAIL, "unable to replace search path") done: FUNC_LEAVE_API(ret_value) } /* end H5PLreplace() */ - + /*------------------------------------------------------------------------- - * Function: H5PLinsert + * Function: H5PLinsert * - * Purpose: Insert a plugin path at the specified index, moving other paths after the index. + * Purpose: Insert a plugin search path at the specified index, moving + * other paths after the index. * - * Return: Non-negative or success. + * Return: Success: Non-negative + * Failture: Negative * *------------------------------------------------------------------------- */ herr_t -H5PLinsert(const char *plugin_path, unsigned int index) +H5PLinsert(const char *search_path, unsigned int index) { - herr_t ret_value = SUCCEED; /* Return value */ - char *dl_path = NULL; - unsigned int plindex; + unsigned num_paths; /* Current number of stored paths */ + herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_API(FAIL) - H5TRACE2("e", "*sIu", plugin_path, index); - if(H5PL_num_paths_g == H5PL_MAX_PATH_NUM) - HGOTO_ERROR(H5E_PLUGIN, H5E_NOSPACE, FAIL, "too many directories in path for table") - if(NULL == plugin_path) - HGOTO_ERROR(H5E_PLUGIN, H5E_CANTALLOC, FAIL, "no path provided") - if(index >= H5PL_MAX_PATH_NUM) - HGOTO_ERROR(H5E_PLUGIN, H5E_NOSPACE, FAIL, "index path out of bounds for table") - if(NULL == (dl_path = H5MM_strdup(plugin_path))) - HGOTO_ERROR(H5E_PLUGIN, H5E_CANTALLOC, FAIL, "can't allocate memory for path") - - H5PL_EXPAND_ENV_VAR - - for(plindex = (unsigned int)H5PL_num_paths_g; plindex > index; plindex--) - H5PL_path_table_g[plindex] = H5PL_path_table_g[plindex - 1]; - H5PL_path_table_g[index] = dl_path; - H5PL_num_paths_g++; + H5TRACE2("e", "*sIu", search_path, index); + + /* Check args */ + if (NULL == search_path) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "plugin_path parameter cannot be NULL") + if (0 == HDstrlen(search_path)) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "plugin_path parameter cannot have length zero") + + /* Check index */ + num_paths = H5PL__get_num_paths(); + if ((0 != num_paths) && (index >= num_paths)) + HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, FAIL, "index path out of bounds for table - can't be more than %u", (num_paths - 1)) + + /* Insert the search path into the path table */ + if (H5PL__insert_path(search_path, index) < 0) + HGOTO_ERROR(H5E_PLUGIN, H5E_CANTINSERT, FAIL, "unable to insert search path") done: FUNC_LEAVE_API(ret_value) } /* end H5PLinsert() */ - + /*------------------------------------------------------------------------- - * Function: H5PLremove + * Function: H5PLremove + * + * Purpose: Remove the plugin path at the specifed index and compact + * the list. * - * Purpose: Remove the plugin path at the specifed index and compacting the list. + * Return: Success: Non-negative + * Failture: Negative * - * Return: Non-negative or success. + * Return: Non-negative or success. * *------------------------------------------------------------------------- */ herr_t H5PLremove(unsigned int index) { - herr_t ret_value = SUCCEED; /* Return value */ - unsigned int plindex; + unsigned num_paths; /* Current number of stored paths */ + herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_API(FAIL) H5TRACE1("e", "Iu", index); - if(H5PL_num_paths_g == 0) - HGOTO_ERROR(H5E_PLUGIN, H5E_NOSPACE, FAIL, "no directories in table") - if(index >= H5PL_MAX_PATH_NUM) - HGOTO_ERROR(H5E_PLUGIN, H5E_NOSPACE, FAIL, "index path out of bounds for table") - if(NULL == H5PL_path_table_g[index]) - HGOTO_ERROR(H5E_PLUGIN, H5E_CANTALLOC, FAIL, "no directory path at index") - H5PL_path_table_g[index] = (char *)H5MM_xfree(H5PL_path_table_g[index]); - - H5PL_num_paths_g--; - for(plindex = index; plindex < (unsigned int)H5PL_num_paths_g; plindex++) - H5PL_path_table_g[plindex] = H5PL_path_table_g[plindex + 1]; - H5PL_path_table_g[H5PL_num_paths_g] = NULL; + + /* Check index */ + num_paths = H5PL__get_num_paths(); + if (0 == num_paths) + HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, FAIL, "path table is empty") + else if (index >= num_paths) + HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, FAIL, "index path out of bounds for table - can't be more than %u", (num_paths - 1)) + + /* Delete the search path from the path table */ + if (H5PL__remove_path(index) < 0) + HGOTO_ERROR(H5E_PLUGIN, H5E_CANTDELETE, FAIL, "unable to remove search path") done: FUNC_LEAVE_API(ret_value) } /* end H5PLremove() */ - + /*------------------------------------------------------------------------- - * Function: H5PLget + * Function: H5PLget + * + * Purpose: Query the plugin path at a specified index. + * + * If 'path_buf' is non-NULL then up to 'buf_size' bytes will be written into + * that buffer and the length of the path name will be returned. * - * Purpose: Query the plugin path at the specified index. + * If 'path_buf' is NULL, this function will simply return the number of + * characters required to store the path name, ignoring 'path_buf' and + * 'buf_size' * - * Return: Success: The length of path. + * If an error occurs then the buffer pointed to by 'path_buf' + * (NULL or non-NULL) will be unchanged and the function will return a + * negative value. * - * If `pathname' is non-NULL then write up to `size' bytes into that - * buffer and always return the length of the pathname. - * Otherwise `size' is ignored and the function does not store the pathname, - * just returning the number of characters required to store the pathname. - * If an error occurs then the buffer pointed to by `pathname' (NULL or non-NULL) - * is unchanged and the function returns a negative value. - * If a zero is returned for the name's length, then there is no pathname - * associated with the index. + * If a zero is returned for the name's length, then there is no path name + * associated with the index and the 'path_buf' buffer will be unchanged. + * + * Return: Success: The length of path + * Failure: A negative value * *------------------------------------------------------------------------- */ ssize_t -H5PLget(unsigned int index, char *pathname/*out*/, size_t size) +H5PLget(unsigned int index, char *path_buf, size_t buf_size) { - ssize_t ret_value = 0; /* Return value */ - size_t len = 0; /* Length of pathname */ - char *dl_path = NULL; + unsigned num_paths; /* Current number of stored paths */ + const char *path = NULL; /* path from table */ + size_t path_len = 0; /* Length of path */ + ssize_t ret_value = 0; /* Return value */ FUNC_ENTER_API(FAIL) - H5TRACE3("Zs", "Iuxz", index, pathname, size); - if(H5PL_num_paths_g == 0) - HGOTO_ERROR(H5E_PLUGIN, H5E_NOSPACE, FAIL, "no directories in table") - if(index >= H5PL_MAX_PATH_NUM) - HGOTO_ERROR(H5E_PLUGIN, H5E_NOSPACE, FAIL, "index path out of bounds for table") - if(NULL == (dl_path = H5PL_path_table_g[index])) - HGOTO_ERROR(H5E_PLUGIN, H5E_CANTALLOC, FAIL, "no directory path at index") - len = HDstrlen(dl_path); - if(pathname) { - HDstrncpy(pathname, dl_path, MIN((size_t)(len + 1), size)); - if((size_t)len >= size) - pathname[size - 1] = '\0'; + H5TRACE3("Zs", "Iu*sz", index, path_buf, buf_size); + + /* Check index */ + num_paths = H5PL__get_num_paths(); + if (0 == num_paths) + HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, FAIL, "path table is empty") + else if (index >= num_paths) + HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, FAIL, "index path out of bounds for table - can't be more than %u", (num_paths - 1)) + + /* Check if the search table is empty */ + if (H5PL__get_num_paths() == 0) + HGOTO_ERROR(H5E_PLUGIN, H5E_NOSPACE, (-1), "plugin search path table is empty") + + /* Get the path at the specified index and its length */ + if (NULL == (path = H5PL__get_path(index))) + HGOTO_ERROR(H5E_PLUGIN, H5E_BADVALUE, (-1), "no path stored at that index") + path_len = HDstrlen(path); + + /* If the path buffer is not NULL, copy the path to the buffer */ + if (path_buf) { + HDstrncpy(path_buf, path, MIN((size_t)(path_len + 1), buf_size)); + if ((size_t)path_len >= buf_size) + path_buf[buf_size - 1] = '\0'; } /* end if */ /* Set return value */ - ret_value = (ssize_t)len; + ret_value = (ssize_t)path_len; done: FUNC_LEAVE_API(ret_value) } /* end H5PLget() */ - + /*------------------------------------------------------------------------- - * Function: H5PLsize + * Function: H5PLsize * - * Purpose: Query the size of the current list of plugin paths. + * Purpose: Get the number of stored plugin paths. + * XXX: This is a terrible name. Can it be changed? * - * Return: Plugin path size + * Return: SUCCEED/FAIL * *------------------------------------------------------------------------- */ herr_t -H5PLsize(unsigned int *listsize) +H5PLsize(unsigned int *num_paths) { herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_API(FAIL) - H5TRACE1("e", "*Iu", listsize); + H5TRACE1("e", "*Iu", num_paths); - *listsize = (unsigned int)H5PL_num_paths_g; + /* Check arguments */ + if (!num_paths) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "num_paths parameter cannot be NULL") + + /* Get the number of stored plugin paths */ + *num_paths = H5PL__get_num_paths(); done: FUNC_LEAVE_API(ret_value) } /* end H5PLsize() */ - -/*------------------------------------------------------------------------- - * Function: H5PL__init_path_table - * - * Purpose: Initialize the path table. - * - * Return: Non-negative on success/Negative on failure - * - * Programmer: Quincey Koziol - * 18 March 2013 - * - *------------------------------------------------------------------------- - */ -static herr_t -H5PL__init_path_table(void) -{ - char *dl_path = NULL; - char *origin_dl_path; - char *dir; - herr_t ret_value = SUCCEED; /* Return value */ - - FUNC_ENTER_STATIC - - /* Retrieve paths from HDF5_PLUGIN_PATH if the user sets it - * or from the default paths if it isn't set. - */ - origin_dl_path = HDgetenv("HDF5_PLUGIN_PATH"); - if(NULL == origin_dl_path) - dl_path = H5MM_strdup(H5PL_DEFAULT_PATH); - else - dl_path = H5MM_strdup(origin_dl_path); - if(NULL == dl_path) - HGOTO_ERROR(H5E_PLUGIN, H5E_CANTALLOC, FAIL, "can't allocate memory for path") - - H5PL_EXPAND_ENV_VAR - - /* Put paths in the path table. They are separated by ":" */ - dir = HDstrtok(dl_path, H5PL_PATH_SEPARATOR); - while(dir) { - /* Check for too many directories in path */ - if(H5PL_num_paths_g == H5PL_MAX_PATH_NUM) - HGOTO_ERROR(H5E_PLUGIN, H5E_NOSPACE, FAIL, "too many directories in path for table") - if(NULL == (H5PL_path_table_g[H5PL_num_paths_g] = H5MM_strdup(dir))) - HGOTO_ERROR(H5E_PLUGIN, H5E_CANTALLOC, FAIL, "can't allocate memory for path") - H5PL_num_paths_g++; - dir = HDstrtok(NULL, H5PL_PATH_SEPARATOR); - } /* end while */ - - H5PL_path_found_g = TRUE; - -done: - if(dl_path) - dl_path = (char *)H5MM_xfree(dl_path); - - FUNC_LEAVE_NOAPI(ret_value) -} /* end H5PL__init_path_table() */ - - -/*------------------------------------------------------------------------- - * Function: H5PL__find - * - * Purpose: Given a path, this function opens the directory and envokes - * another function to go through all files to find the right - * plugin library. Two function definitions are for Unix and - * Windows. - * - * Return: TRUE on success, - * FALSE on not found, - * negative on failure - * - * Programmer: Raymond Lu - * 13 February 2013 - * - *------------------------------------------------------------------------- - */ -#ifndef H5_HAVE_WIN32_API -static htri_t -H5PL__find(H5PL_type_t plugin_type, int type_id, char *dir, const void **info) -{ - char *pathname = NULL; - DIR *dirp = NULL; - struct dirent *dp; - htri_t ret_value = FALSE; - - FUNC_ENTER_STATIC - - /* Open the directory */ - if(!(dirp = HDopendir(dir))) - HGOTO_ERROR(H5E_PLUGIN, H5E_OPENERROR, FAIL, "can't open directory: %s", dir) - - /* Iterates through all entries in the directory to find the right plugin library */ - 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 - h5_stat_t my_stat; - size_t pathname_len; - htri_t found_in_dir; - - /* Allocate & initialize the path name */ - pathname_len = HDstrlen(dir) + HDstrlen(dp->d_name) + 2; - if(NULL == (pathname = (char *)H5MM_malloc(pathname_len))) - HGOTO_ERROR(H5E_PLUGIN, H5E_CANTALLOC, FAIL, "can't allocate memory for path") - HDsnprintf(pathname, pathname_len, "%s/%s", dir, dp->d_name); - - /* Get info for directory entry */ - if(HDstat(pathname, &my_stat) == -1) - HGOTO_ERROR(H5E_FILE, H5E_CANTGET, FAIL, "can't stat file: %s", HDstrerror(errno)) - - /* If it is a directory, skip it */ - if(S_ISDIR(my_stat.st_mode)) - continue; - - /* Attempt to open the dynamic library as a filter library */ - if((found_in_dir = H5PL__open(plugin_type, pathname, type_id, info)) < 0) - HGOTO_ERROR(H5E_PLUGIN, H5E_CANTGET, FAIL, "search in directory failed") - if(found_in_dir) - HGOTO_DONE(TRUE) /* Indicate success */ - pathname = (char *)H5MM_xfree(pathname); - } /* end if */ - } /* end while */ - -done: - if(dirp) - if(HDclosedir(dirp) < 0) - HDONE_ERROR(H5E_FILE, H5E_CLOSEERROR, FAIL, "can't close directory: %s", HDstrerror(errno)) - pathname = (char *)H5MM_xfree(pathname); - - FUNC_LEAVE_NOAPI(ret_value) -} /* end H5PL__find() */ -#else /* H5_HAVE_WIN32_API */ -static htri_t -H5PL__find(H5PL_type_t plugin_type, int type_id, char *dir, const void **info) -{ - WIN32_FIND_DATAA fdFile; - HANDLE hFind; - char *pathname = NULL; - char service[2048]; - htri_t ret_value = FALSE; - - FUNC_ENTER_STATIC - - /* Specify a file mask. *.* = We want everything! */ - sprintf(service, "%s\\*.dll", dir); - if((hFind = FindFirstFileA(service, &fdFile)) == INVALID_HANDLE_VALUE) - HGOTO_ERROR(H5E_PLUGIN, H5E_OPENERROR, FAIL, "can't open directory") - - do { - /* Find first file will always return "." - * and ".." as the first two directories. - */ - if(HDstrcmp(fdFile.cFileName, ".") != 0 && HDstrcmp(fdFile.cFileName, "..") != 0) { - size_t pathname_len; - htri_t found_in_dir; - - /* Allocate & initialize the path name */ - pathname_len = HDstrlen(dir) + HDstrlen(fdFile.cFileName) + 2; - if(NULL == (pathname = (char *)H5MM_malloc(pathname_len))) - HGOTO_ERROR(H5E_PLUGIN, H5E_CANTALLOC, FAIL, "can't allocate memory for path") - HDsnprintf(pathname, pathname_len, "%s\\%s", dir, fdFile.cFileName); - - /* Is the entity a File or Folder? */ - if(fdFile.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) - continue; - - if((found_in_dir = H5PL__open(plugin_type, pathname, type_id, info)) < 0) - HGOTO_ERROR(H5E_PLUGIN, H5E_CANTGET, FAIL, "search in directory failed") - if(found_in_dir) - HGOTO_DONE(TRUE) /* Indicate success */ - pathname = (char *)H5MM_xfree(pathname); - } /* end if */ - } while(FindNextFileA(hFind, &fdFile)); /* Find the next file. */ - -done: - if(hFind) - FindClose(hFind); - if(pathname) - pathname = (char *)H5MM_xfree(pathname); - - FUNC_LEAVE_NOAPI(ret_value) -} /* end H5PL__find() */ -#endif /* H5_HAVE_WIN32_API */ - - -/*------------------------------------------------------------------------- - * Function: H5PL__open - * - * Purpose: Iterates through all files to find the right plugin library. - * It loads the dynamic plugin library and keeps it on the list - * of loaded libraries. - * - * Return: TRUE on success, - * FALSE on not found, - * negative on failure - * - * Programmer: Raymond Lu - * 13 February 2013 - * - *------------------------------------------------------------------------- - */ -static htri_t -H5PL__open(H5PL_type_t pl_type, char *libname, int pl_id, const void **pl_info) -{ - H5PL_HANDLE handle = NULL; - htri_t ret_value = FALSE; - - FUNC_ENTER_STATIC - - /* There are different reasons why a library can't be open, e.g. wrong architecture. - * simply continue if we can't open it. - */ - if(NULL == (handle = H5PL_OPEN_DLIB(libname))) { - H5PL_CLR_ERROR; /* clear error */ - } /* end if */ - else { - H5PL_get_plugin_info_t get_plugin_info = NULL; - - /* Return a handle for the function H5PLget_plugin_info in the dynamic library. - * The plugin library is suppose to define this function. - */ - if(NULL == (get_plugin_info = (H5PL_get_plugin_info_t)H5PL_GET_LIB_FUNC(handle, "H5PLget_plugin_info"))) { - if(H5PL__close(handle) < 0) - HGOTO_ERROR(H5E_PLUGIN, H5E_CLOSEERROR, FAIL, "can't close dynamic library") - } /* end if */ - else { - const H5Z_class2_t *plugin_info; - - /* Invoke H5PLget_plugin_info to verify this is the right library we are looking for. - * Move on if it isn't. - */ - if(NULL == (plugin_info = (const H5Z_class2_t *)(*get_plugin_info)())) { - if(H5PL__close(handle) < 0) - HGOTO_ERROR(H5E_PLUGIN, H5E_CLOSEERROR, FAIL, "can't close dynamic library") - HGOTO_ERROR(H5E_PLUGIN, H5E_CANTGET, FAIL, "can't get plugin info") - } /* end if */ - - /* Successfully found plugin library, check if it's the right one */ - if(plugin_info->id == pl_id) { - /* Expand the table if it is too small */ - if(H5PL_table_used_g >= H5PL_table_alloc_g) { - size_t n = MAX(H5Z_MAX_NFILTERS, 2 * H5PL_table_alloc_g); - H5PL_table_t *table = (H5PL_table_t *)H5MM_realloc(H5PL_table_g, n * sizeof(H5PL_table_t)); - - if(!table) - HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "unable to extend dynamic library table") - - H5PL_table_g = table; - H5PL_table_alloc_g = n; - } /* end if */ - - (H5PL_table_g[H5PL_table_used_g]).handle = handle; - (H5PL_table_g[H5PL_table_used_g]).pl_type = pl_type; - (H5PL_table_g[H5PL_table_used_g]).pl_id = plugin_info->id; - H5PL_table_used_g++; - - /* Set the plugin info to return */ - *pl_info = (const void *)plugin_info; - - /* Indicate success */ - ret_value = TRUE; - } /* end if */ - else - if(H5PL__close(handle) < 0) - HGOTO_ERROR(H5E_PLUGIN, H5E_CLOSEERROR, FAIL, "can't close dynamic library") - } /* end if */ - } /* end else */ - -done: - FUNC_LEAVE_NOAPI(ret_value) -} /* end H5PL__open() */ - - -/*------------------------------------------------------------------------- - * Function: H5PL__search_table - * - * Purpose: Search in the list of already opened dynamic libraries - * to see if the one we are looking for is already opened. - * - * Return: TRUE on success, - * FALSE on not found, - * Negative on failure - * - * Programmer: Raymond Lu - * 13 February 2013 - * - *------------------------------------------------------------------------- - */ -static htri_t -H5PL__search_table(H5PL_type_t plugin_type, int type_id, const void **info) -{ - htri_t ret_value = FALSE; - - FUNC_ENTER_STATIC - - /* Search in the table of already opened dynamic libraries */ - if(H5PL_table_used_g > 0) { - size_t i; - - for(i = 0; i < H5PL_table_used_g; i++) { - if((plugin_type == (H5PL_table_g[i]).pl_type) && (type_id == (H5PL_table_g[i]).pl_id)) { - H5PL_get_plugin_info_t get_plugin_info; - const H5Z_class2_t *plugin_info; - - if(NULL == (get_plugin_info = (H5PL_get_plugin_info_t)H5PL_GET_LIB_FUNC((H5PL_table_g[i]).handle, "H5PLget_plugin_info"))) - HGOTO_ERROR(H5E_DATATYPE, H5E_CANTGET, FAIL, "can't get function for H5PLget_plugin_info") - - if(NULL == (plugin_info = (const H5Z_class2_t *)(*get_plugin_info)())) - HGOTO_ERROR(H5E_DATATYPE, H5E_CANTGET, FAIL, "can't get plugin info") - - *info = plugin_info; - HGOTO_DONE(TRUE) - } /* end if */ - } /* end for */ - } /* end if */ - -done: - FUNC_LEAVE_NOAPI(ret_value) -} /* end H5PL__search_table() */ - - -/*------------------------------------------------------------------------- - * Function: H5PL__close - * - * Purpose: Closes the handle for dynamic library - * - * Return: Non-negative on success/Negative on failure - * - * Programmer: Raymond Lu - * 13 February 2013 - * - *------------------------------------------------------------------------- - */ -static herr_t -H5PL__close(H5PL_HANDLE handle) -{ - FUNC_ENTER_STATIC_NOERR - - H5PL_CLOSE_LIB(handle); - - FUNC_LEAVE_NOAPI(SUCCEED) -} /* end H5PL__close() */ - diff --git a/src/H5PLextern.h b/src/H5PLextern.h index 7547ad7..cd5464d 100644 --- a/src/H5PLextern.h +++ b/src/H5PLextern.h @@ -11,9 +11,9 @@ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* - * Programmer: Raymond Lu <songyulu@hdfgroup.org> - * 13 February 2013 + * Purpose: Header file for writing external HDF5 plugins. */ + #ifndef _H5PLextern_H #define _H5PLextern_H diff --git a/src/H5PLint.c b/src/H5PLint.c new file mode 100644 index 0000000..bd6bf7d --- /dev/null +++ b/src/H5PLint.c @@ -0,0 +1,381 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Copyright by The HDF Group. * + * All rights reserved. * + * * + * This file is part of HDF5. The full HDF5 copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the root of the source code * + * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. * + * If you do not have access to either file, you may request a copy from * + * help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/* + * Purpose: Internal routines for managing plugins. + * + */ + + +/****************/ +/* Module Setup */ +/****************/ + +#include "H5PLmodule.h" /* This source code file is part of the H5PL module */ + + +/***********/ +/* Headers */ +/***********/ +#include "H5private.h" /* Generic Functions */ +#include "H5Eprivate.h" /* Error handling */ +#include "H5MMprivate.h" /* Memory management */ +#include "H5PLpkg.h" /* Plugin */ +#include "H5Zprivate.h" /* Filter pipeline */ + + +/****************/ +/* Local Macros */ +/****************/ + + +/******************/ +/* Local Typedefs */ +/******************/ + + +/********************/ +/* Local Prototypes */ +/********************/ + + +/*********************/ +/* Package Variables */ +/*********************/ + +/* Package initialization variable */ +hbool_t H5_PKG_INIT_VAR = FALSE; + + +/*****************************/ +/* Library Private Variables */ +/*****************************/ + + +/*******************/ +/* Local Variables */ +/*******************/ + +/* Bitmask that controls whether classes of plugins + * (e.g.: filters, VOL drivers) can be loaded. + */ +static unsigned int H5PL_plugin_control_mask_g = H5PL_ALL_PLUGIN; + +/* This flag will be set to FALSE if the HDF5_PLUGIN_PRELOAD + * environment variable was set to H5PL_NO_PLUGIN at + * package initialization. + */ +static hbool_t H5PL_allow_plugins_g = TRUE; + + + +/*------------------------------------------------------------------------- + * Function: H5PL__get_plugin_control_mask + * + * Purpose: Gets the internal plugin control mask value. + * + * Return: SUCCEED/FAIL + * + *------------------------------------------------------------------------- + */ +herr_t +H5PL__get_plugin_control_mask(unsigned int *mask /*out*/) +{ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_PACKAGE_NOERR + + /* Check args - Just assert on package functions */ + HDassert(mask); + + /* Return the mask */ + *mask = H5PL_plugin_control_mask_g; + + FUNC_LEAVE_NOAPI(ret_value) + +} /* end H5PL__get_plugin_control_mask() */ + + +/*------------------------------------------------------------------------- + * Function: H5PL__set_plugin_control_mask + * + * Purpose: Sets the internal plugin control mask value. + * + * Return: SUCCEED/FAIL + * + *------------------------------------------------------------------------- + */ +herr_t +H5PL__set_plugin_control_mask(unsigned int mask) +{ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_PACKAGE_NOERR + + /* Only allow setting this if plugins have not been disabled. + * XXX: Note that we don't consider this an error, but instead + * silently ignore it. We may want to consider this behavior + * more carefully. + */ + if (H5PL_allow_plugins_g) + H5PL_plugin_control_mask_g = mask; + + FUNC_LEAVE_NOAPI(ret_value) + +} /* end H5PL__set_plugin_control_mask() */ + + +/*------------------------------------------------------------------------- + * Function: H5PL__init_package + * + * Purpose: Initialize any package-specific data and call any init + * routines for the package. + * + * Return: SUCCEED/FAIL + * + *------------------------------------------------------------------------- + */ +herr_t +H5PL__init_package(void) +{ + char *env_var = NULL; + herr_t ret_value = SUCCEED; + + FUNC_ENTER_PACKAGE + + /* Check the environment variable to determine if the user wants + * to ignore plugins. The special symbol H5PL_NO_PLUGIN (defined in + * H5PLpublic.h) means we don't want to load plugins. + */ + if (NULL != (env_var = HDgetenv("HDF5_PLUGIN_PRELOAD"))) + if (!HDstrcmp(env_var, H5PL_NO_PLUGIN)) { + H5PL_plugin_control_mask_g = 0; + H5PL_allow_plugins_g = FALSE; + } + + /* Create the table of previously-loaded plugins */ + if (H5PL__create_plugin_cache() < 0) + HGOTO_ERROR(H5E_PLUGIN, H5E_CANTINIT, FAIL, "can't create plugin cache") + + /* Create the table of search paths for dynamic libraries */ + if (H5PL__create_path_table() < 0) + HGOTO_ERROR(H5E_PLUGIN, H5E_CANTINIT, FAIL, "can't create plugin search path table") + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5PL__init_package() */ + + +/*------------------------------------------------------------------------- + * Function: H5PL_term_package + * + * Purpose: Terminate the H5PL interface: release all memory, reset all + * global variables to initial values. This only happens if all + * types have been destroyed from other interfaces. + * + * Return: Success: Positive if any action was taken that might + * affect some other interface; zero otherwise + * Failure: Negative + * + *------------------------------------------------------------------------- + */ +int +H5PL_term_package(void) +{ + hbool_t already_closed = FALSE; + int ret_value = 0; + + FUNC_ENTER_NOAPI_NOINIT + + if (H5_PKG_INIT_VAR) { + + /* Close the plugin cache. + * We need to bump the return value if we did any real work here. + */ + if (H5PL__close_plugin_cache(&already_closed) < 0) + HGOTO_ERROR(H5E_PLUGIN, H5E_CANTFREE, (-1), "problem closing plugin cache") + if (!already_closed) + ret_value++; + + /* Close the search path table and free the paths */ + if (H5PL__close_path_table() < 0) + HGOTO_ERROR(H5E_PLUGIN, H5E_CANTFREE, (-1), "problem closing search path table") + + /* Mark the interface as uninitialized */ + if (0 == ret_value) + H5_PKG_INIT_VAR = FALSE; + } /* end if */ + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5PL_term_package() */ + + +/*------------------------------------------------------------------------- + * Function: H5PL_load + * + * Purpose: Given the plugin type and identifier, this function searches + * for and, if found, loads a dynamic plugin library. + * + * The function searches first in the cached plugins and then + * in the paths listed in the path table. + * + * Return: Success: A pointer to the plugin info + * Failure: NULL + * + *------------------------------------------------------------------------- + */ +const void * +H5PL_load(H5PL_type_t type, int id) +{ + H5PL_search_params_t search_params; + hbool_t found = FALSE; /* Whether the plugin was found */ + const void *plugin_info = NULL; + const void *ret_value = NULL; + + FUNC_ENTER_NOAPI(NULL) + + /* Check if plugins can be loaded for this plugin type */ + switch (type) { + case H5PL_TYPE_FILTER: + if ((H5PL_plugin_control_mask_g & H5PL_FILTER_PLUGIN) == 0) + HGOTO_ERROR(H5E_PLUGIN, H5E_CANTLOAD, NULL, "required dynamically loaded plugin filter '%d' is not available", id) + break; + + case H5PL_TYPE_ERROR: + case H5PL_TYPE_NONE: + default: + HGOTO_ERROR(H5E_PLUGIN, H5E_CANTLOAD, NULL, "required dynamically loaded plugin '%d' is not valid", id) + } + + /* Set up the search parameters */ + search_params.type = type; + search_params.id = id; + + /* 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") + + /* If not found, try iterating through the path table to find an appropriate plugin */ + if (!found) + if (H5PL__find_plugin_in_path_table(&search_params, &found, &plugin_info) < 0) + HGOTO_ERROR(H5E_PLUGIN, H5E_CANTGET, NULL, "search in path table failed") + + /* Set the return value we found the plugin */ + if (found) + ret_value = plugin_info; + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5PL_load() */ + + +/*------------------------------------------------------------------------- + * Function: H5PL__open + * + * Purpose: Opens a plugin. + * + * The success parameter will be set to TRUE and the plugin_info + * parameter will be filled in on success. Otherwise, they + * will be FALSE and NULL, respectively. + * + * Return: SUCCEED/FAIL + * + *------------------------------------------------------------------------- + */ +herr_t +H5PL__open(const char *path, H5PL_type_t type, int id, hbool_t *success, const void **plugin_info) +{ + H5PL_HANDLE handle = NULL; + H5PL_get_plugin_info_t get_plugin_info = NULL; + htri_t ret_value = SUCCEED; + + FUNC_ENTER_PACKAGE + + /* Check args - Just assert on package functions */ + HDassert(path); + HDassert(success); + HDassert(plugin_info); + + /* Initialize out parameters */ + *success = FALSE; + *plugin_info = NULL; + + /* There are different reasons why a library can't be open, e.g. wrong architecture. + * If we can't open the library, just return. + */ + if (NULL == (handle = H5PL_OPEN_DLIB(path))) { + H5PL_CLR_ERROR; /* clear error */ + HGOTO_DONE(SUCCEED); + } + + + /* Return a handle for the function H5PLget_plugin_info in the dynamic library. + * The plugin library is suppose to define this function. + * + * NOTE: We turn off -Wpedantic in gcc to quiet a warning about converting + * object pointers to function pointers, which is undefined in ANSI C. + * This is basically unavoidable due to the nature of dlsym() and *is* + * defined in POSIX, so it's fine. + */ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wpedantic" + if (NULL != (get_plugin_info = (H5PL_get_plugin_info_t)H5PL_GET_LIB_FUNC(handle, "H5PLget_plugin_info"))) { +#pragma GCC diagnostic pop + + const H5Z_class2_t *info; + + /* Get the plugin info */ + if (NULL == (info = (const H5Z_class2_t *)(*get_plugin_info)())) + HGOTO_ERROR(H5E_PLUGIN, H5E_CANTGET, FAIL, "can't get plugin info") + + /* Check if the filter IDs match */ + if (info->id == id) { + + /* Store the plugin in the cache */ + if (H5PL__add_plugin(type, id, handle)) + HGOTO_ERROR(H5E_PLUGIN, H5E_CANTINSERT, FAIL, "unable to add new plugin to plugin cache") + + /* Set output parameters */ + *success = TRUE; + *plugin_info = (const void *)info; + } + } + +done: + if (!success && handle) + if (H5PL__close(handle) < 0) + HDONE_ERROR(H5E_PLUGIN, H5E_CLOSEERROR, FAIL, "can't close dynamic library") + + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5PL__open() */ + + +/*------------------------------------------------------------------------- + * Function: H5PL__close + * + * Purpose: Closes the handle for dynamic library + * + * Return: SUCCEED/FAIL + * + *------------------------------------------------------------------------- + */ +herr_t +H5PL__close(H5PL_HANDLE handle) +{ + FUNC_ENTER_PACKAGE_NOERR + + H5PL_CLOSE_LIB(handle); + + FUNC_LEAVE_NOAPI(SUCCEED) +} /* end H5PL__close() */ + diff --git a/src/H5PLmodule.h b/src/H5PLmodule.h index b441aed..945441e 100644 --- a/src/H5PLmodule.h +++ b/src/H5PLmodule.h @@ -11,13 +11,11 @@ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* - * Programmer: Quincey Koziol <koziol@hdfgroup.org> - * Saturday, September 12, 2015 - * - * Purpose: This file contains declarations which define macros for the - * H5PL package. Including this header means that the source file - * is part of the H5PL package. + * Purpose: This file contains declarations which define macros for the + * H5PL package. Including this header means that the source file + * is part of the H5PL package. */ + #ifndef _H5PLmodule_H #define _H5PLmodule_H diff --git a/src/H5PLpath.c b/src/H5PLpath.c new file mode 100644 index 0000000..435802a --- /dev/null +++ b/src/H5PLpath.c @@ -0,0 +1,776 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Copyright by The HDF Group. * + * All rights reserved. * + * * + * This file is part of HDF5. The full HDF5 copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the root of the source code * + * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. * + * If you do not have access to either file, you may request a copy from * + * help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/* + * Purpose: Code to implement a path table which stores plugin search paths. + * + * The path table is implemented as a dynamic, global array which + * will grow as new paths are inserted. The capacity of the path + * table never shrinks (though given the low number of paths + * expected and the low likelihood of paths being removed, this + * seems unlikely to be a problem). Inserts and removals rework + * the array so that there are no 'holes' in the in-use part + * of the array. + * + * Note that it's basically up to the user to manage the indexes + * when a complicated series of insert, overwrite, and, remove + * operations take place. + */ + +/****************/ +/* Module Setup */ +/****************/ + +#include "H5PLmodule.h" /* This source code file is part of the H5PL module */ + + +/***********/ +/* Headers */ +/***********/ +#include "H5private.h" /* Generic Functions */ +#include "H5Eprivate.h" /* Error handling */ +#include "H5MMprivate.h" /* Memory management */ +#include "H5PLpkg.h" /* Plugin */ + + +/****************/ +/* Local Macros */ +/****************/ + +/* Initial capacity of the path table */ +#define H5PL_INITIAL_PATH_CAPACITY 16 + +/* The amount to add to the capacity when the table is full */ +#define H5PL_PATH_CAPACITY_ADD 16 + + +/******************/ +/* Local Typedefs */ +/******************/ + + +/********************/ +/* Local Prototypes */ +/********************/ + +static herr_t H5PL__insert_at(const char *path, unsigned int index); +static herr_t H5PL__make_space_at(unsigned int index); +static herr_t H5PL__replace_at(const char *path, unsigned int index); +static herr_t H5PL__expand_path_table(void); +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); + +/*********************/ +/* Package Variables */ +/*********************/ + + +/*****************************/ +/* Library Private Variables */ +/*****************************/ + + +/*******************/ +/* Local Variables */ +/*******************/ + +/* Stored plugin paths to search */ +static char **H5PL_paths_g = NULL; + +/* The number of stored paths */ +static unsigned H5PL_num_paths_g = 0; + +/* The capacity of the path table */ +static unsigned H5PL_path_capacity_g = H5PL_INITIAL_PATH_CAPACITY; + + + +/*------------------------------------------------------------------------- + * Function: H5PL__insert_at() + * + * Purpose: Insert a path at a particular index in the path table. + * Does not clobber! Will move existing paths up to make + * room. Use H5PL__replace_at(index) if you want to clobber. + * + * Return: SUCCEED/FAIL + * + *------------------------------------------------------------------------- + */ +static herr_t +H5PL__insert_at(const char *path, unsigned int index) +{ + char *path_copy = NULL; /* copy of path string (for storing) */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_STATIC + + /* Check args - Just assert on package functions */ + HDassert(path); + HDassert(HDstrlen(path)); + + /* Expand the table if it is full */ + if (H5PL_num_paths_g == H5PL_path_capacity_g) + if (H5PL__expand_path_table() < 0) + HGOTO_ERROR(H5E_PLUGIN, H5E_CANTALLOC, FAIL, "can't expand path table") + + /* Copy the path for storage so the caller can dispose of theirs */ + if (NULL == (path_copy = H5MM_strdup(path))) + HGOTO_ERROR(H5E_PLUGIN, H5E_CANTALLOC, FAIL, "can't make internal copy of path") + +#ifdef H5_HAVE_WIN32_API + /* Clean up Microsoft Windows environment variables in the path string */ + if(H5_expand_windows_env_vars(&path_copy)) + HGOTO_ERROR(H5E_PLUGIN, H5E_CANTCONVERT, FAIL, "can't expand environment variable string") +#endif /* H5_HAVE_WIN32_API */ + + /* If the table entry is in use, make some space */ + if (H5PL_paths_g[index]) + if (H5PL__make_space_at(index) < 0) + HGOTO_ERROR(H5E_PLUGIN, H5E_NOSPACE, FAIL, "unable to make space in the table for the new entry") + + /* Insert the copy of the search path into the table at the specified index */ + H5PL_paths_g[index] = path_copy; + H5PL_num_paths_g++; + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5PL__insert_at() */ + + +/*------------------------------------------------------------------------- + * Function: H5PL__make_space_at() + * + * Purpose: Free up a slot in the path table, moving existing path + * entries as necessary. + * + * Return: SUCCEED/FAIL + * + *------------------------------------------------------------------------- + */ +static herr_t +H5PL__make_space_at(unsigned int index) +{ + unsigned u; /* iterator */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_STATIC_NOERR + + /* Check args - Just assert on package functions */ + HDassert(index < H5PL_path_capacity_g); + + /* Copy the paths back to make a space */ + for (u = H5PL_num_paths_g; u > index; u--) + H5PL_paths_g[u] = H5PL_paths_g[u-1]; + + H5PL_paths_g[index] = NULL; + + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5PL__make_space_at() */ + + +/*------------------------------------------------------------------------- + * Function: H5PL__replace_at() + * + * Purpose: Replace a path at a particular index in the path table. + * The path in the table must exist and will be freed by this + * function. + * + * Return: SUCCEED/FAIL + * + *------------------------------------------------------------------------- + */ +static herr_t +H5PL__replace_at(const char *path, unsigned int index) +{ + char *path_copy = NULL; /* copy of path string (for storing) */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_STATIC + + /* Check args - Just assert on package functions */ + HDassert(path); + HDassert(HDstrlen(path)); + + /* Check that the table entry is in use */ + if (!H5PL_paths_g[index]) + HGOTO_ERROR(H5E_PLUGIN, H5E_CANTFREE, FAIL, "path entry at index %u in the table is NULL", index) + + /* Copy the path for storage so the caller can dispose of theirs */ + if (NULL == (path_copy = H5MM_strdup(path))) + HGOTO_ERROR(H5E_PLUGIN, H5E_CANTALLOC, FAIL, "can't make internal copy of path") + +#ifdef H5_HAVE_WIN32_API + /* Clean up Microsoft Windows environment variables in the path string */ + if (H5_expand_windows_env_vars(&path_copy)) + HGOTO_ERROR(H5E_PLUGIN, H5E_CANTCONVERT, FAIL, "can't expand environment variable string") +#endif /* H5_HAVE_WIN32_API */ + + /* Free the existing path entry */ + H5PL_paths_g[index] = (char *)H5MM_xfree(H5PL_paths_g[index]); + + /* Copy the search path into the table at the specified index */ + H5PL_paths_g[index] = path_copy; + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5PL__replace_at() */ + + +/*------------------------------------------------------------------------- + * Function: H5PL__create_path_table + * + * Purpose: Create the collection of paths that will be searched + * when loading plugins. + * + * Return: SUCCEED/FAIL + * + *------------------------------------------------------------------------- + */ +herr_t +H5PL__create_path_table(void) +{ + char *env_var= NULL; /* Path string from environment variable */ + char *paths = NULL; /* Delimited paths string. Either from the + * environment variable or the default. + */ + char *next_path = NULL; /* A path tokenized from the paths string */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_PACKAGE + + /* Allocate memory for the path table */ + H5PL_num_paths_g = 0; + H5PL_path_capacity_g = H5PL_INITIAL_PATH_CAPACITY; + if (NULL == (H5PL_paths_g = (char **)H5MM_calloc((size_t)H5PL_path_capacity_g * sizeof(char *)))) + HGOTO_ERROR(H5E_PLUGIN, H5E_CANTALLOC, FAIL, "can't allocate memory for path table") + + /* Retrieve paths from HDF5_PLUGIN_PATH if the user sets it + * or from the default paths if it isn't set. + */ + env_var = HDgetenv("HDF5_PLUGIN_PATH"); + if (NULL == env_var) + paths = H5MM_strdup(H5PL_DEFAULT_PATH); + else + paths = H5MM_strdup(env_var); + + if (NULL == paths) + HGOTO_ERROR(H5E_PLUGIN, H5E_CANTALLOC, FAIL, "can't allocate memory for path copy") + + /* Separate the paths and store them */ + /* XXX: strtok() is not thread-safe */ + next_path = HDstrtok(paths, H5PL_PATH_SEPARATOR); + while (next_path) { + + /* Insert the path into the table */ + if (H5PL__append_path(next_path) < 0) + HGOTO_ERROR(H5E_PLUGIN, H5E_CANTALLOC, FAIL, "can't insert path: %s", next_path) + + /* Get the next path from the environment string */ + next_path = HDstrtok(NULL, H5PL_PATH_SEPARATOR); + } /* end while */ + +done: + if (paths) + paths = (char *)H5MM_xfree(paths); + + /* Try to clean up on errors */ + if (FAIL == ret_value) { + if (H5PL_paths_g) + H5PL_paths_g = (char **)H5MM_xfree(H5PL_paths_g); + H5PL_path_capacity_g = 0; + } + + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5PL__create_path_table() */ + + +/*------------------------------------------------------------------------- + * Function: H5PL__close_path_table + * + * Purpose: Close the collection of paths that will be searched + * when loading plugins. + * + * Return: SUCCEED/FAIL + * + *------------------------------------------------------------------------- + */ +herr_t +H5PL__close_path_table(void) +{ + unsigned u; /* iterator */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_PACKAGE_NOERR + + /* Free paths */ + for (u = 0; u < H5PL_num_paths_g; u++) + if (H5PL_paths_g[u]) + H5PL_paths_g[u] = (char *)H5MM_xfree(H5PL_paths_g[u]); + + /* Free path table */ + H5PL_paths_g = (char **)H5MM_xfree(H5PL_paths_g); + + /* Reset values */ + H5PL_num_paths_g = 0; + + FUNC_LEAVE_NOAPI(ret_value) + +} /* end H5PL__close_path_table() */ + + +/*------------------------------------------------------------------------- + * Function: H5PL__get_num_paths + * + * Purpose: Gets the number of plugin paths that have been stored. + * + * Return: Success: The number of paths + * Failture: Can't fail + *------------------------------------------------------------------------- + */ +unsigned +H5PL__get_num_paths(void) +{ + FUNC_ENTER_PACKAGE_NOERR + + FUNC_LEAVE_NOAPI(H5PL_num_paths_g) + +} /* end H5PL__get_num_paths() */ + + +/*------------------------------------------------------------------------- + * Function: H5PL__expand_path_table + * + * Purpose: Expand the path table when it's full. + * + * Return: SUCCEED/FAIL + * + *------------------------------------------------------------------------- + */ +static herr_t +H5PL__expand_path_table(void) +{ + herr_t ret_value = SUCCEED; + + FUNC_ENTER_STATIC + + /* Update the capacity */ + H5PL_path_capacity_g += H5PL_PATH_CAPACITY_ADD; + + /* Resize the array */ + if(NULL == (H5PL_paths_g = (char **)H5MM_realloc(H5PL_paths_g, (size_t)H5PL_path_capacity_g * sizeof(char *)))) + HGOTO_ERROR(H5E_PLUGIN, H5E_CANTALLOC, FAIL, "allocating additional memory for path table failed") + + /* Initialize the new memory */ + HDmemset(H5PL_paths_g + H5PL_num_paths_g, 0, (size_t)H5PL_PATH_CAPACITY_ADD * sizeof(char *)); + +done: + /* Set the path capacity back if there were problems */ + if (FAIL == ret_value) + H5PL_path_capacity_g -= H5PL_PATH_CAPACITY_ADD; + + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5PL__expand_path_table() */ + + +/*------------------------------------------------------------------------- + * Function: H5PL__append_path + * + * Purpose: Insert a path at the end of the table. + * + * Return: SUCCEED/FAIL + * + *------------------------------------------------------------------------- + */ +herr_t +H5PL__append_path(const char *path) +{ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_PACKAGE + + /* Check args - Just assert on package functions */ + HDassert(path); + HDassert(HDstrlen(path)); + + /* Insert the path at the end of the table */ + if (H5PL__insert_at(path, H5PL_num_paths_g) < 0) + HGOTO_ERROR(H5E_PLUGIN, H5E_CANTINSERT, FAIL, "unable to append search path") + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5PL__append_path() */ + + +/*------------------------------------------------------------------------- + * Function: H5PL__prepend_path + * + * Purpose: Insert a path at the beginning of the table. + * + * Return: SUCCEED/FAIL + * + *------------------------------------------------------------------------- + */ +herr_t +H5PL__prepend_path(const char *path) +{ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_PACKAGE + + /* Check args - Just assert on package functions */ + HDassert(path); + HDassert(HDstrlen(path)); + + /* Insert the path at the beginning of the table */ + if (H5PL__insert_at(path, 0) < 0) + HGOTO_ERROR(H5E_PLUGIN, H5E_CANTINSERT, FAIL, "unable to prepend search path") + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5PL__prepend_path() */ + + +/*------------------------------------------------------------------------- + * Function: H5PL__replace_path + * + * Purpose: Replace a path at particular index in the table. + * + * Return: SUCCEED/FAIL + * + *------------------------------------------------------------------------- + */ +herr_t +H5PL__replace_path(const char *path, unsigned int index) +{ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_PACKAGE + + /* Check args - Just assert on package functions */ + HDassert(path); + HDassert(HDstrlen(path)); + HDassert(index < H5PL_path_capacity_g); + + /* Insert the path at the requested index */ + if (H5PL__replace_at(path, index) < 0) + HGOTO_ERROR(H5E_PLUGIN, H5E_CANTINSERT, FAIL, "unable to replace search path") + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5PL__replace_path() */ + + +/*------------------------------------------------------------------------- + * Function: H5PL__insert_path + * + * Purpose: Insert a path at particular index in the table, moving + * any existing paths back to make space. + * + * Return: SUCCEED/FAIL + * + *------------------------------------------------------------------------- + */ +herr_t +H5PL__insert_path(const char *path, unsigned int index) +{ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_PACKAGE + + /* Check args - Just assert on package functions */ + HDassert(path); + HDassert(HDstrlen(path)); + HDassert(index < H5PL_path_capacity_g); + + /* Insert the path at the requested index */ + if (H5PL__insert_at(path, index) < 0) + HGOTO_ERROR(H5E_PLUGIN, H5E_CANTINSERT, FAIL, "unable to insert search path") + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5PL__insert_path() */ + + +/*------------------------------------------------------------------------- + * Function: H5PL__remove_path + * + * Purpose: Remove a path at particular index in the table, freeing + * the path string and moving the paths down to close the gap. + * + * Return: SUCCEED/FAIL + * + *------------------------------------------------------------------------- + */ +herr_t +H5PL__remove_path(unsigned int index) +{ + unsigned u; /* iterator */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_PACKAGE + + /* Check args - Just assert on package functions */ + HDassert(index < H5PL_path_capacity_g); + + /* Check if the path at that index is set */ + if (!H5PL_paths_g[index]) + HGOTO_ERROR(H5E_PLUGIN, H5E_CANTDELETE, FAIL, "search path at index %u is NULL", index) + + /* Delete the path */ + H5PL_num_paths_g--; + H5PL_paths_g[index] = (char *)H5MM_xfree(H5PL_paths_g[index]); + + /* Shift the paths down to close the gap */ + for (u = index; u < H5PL_num_paths_g; u++) + H5PL_paths_g[u] = H5PL_paths_g[u+1]; + + /* Set the (former) last path to NULL */ + H5PL_paths_g[H5PL_num_paths_g] = NULL; + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5PL__remove_path() */ + + +/*------------------------------------------------------------------------- + * Function: H5PL__get_path + * + * Purpose: Get a pointer to a path at particular index in the table. + * + * Return: Success: A pointer to a path string stored in the table + * Failure: NULL + * + *------------------------------------------------------------------------- + */ +const char * +H5PL__get_path(unsigned int index) +{ + char *ret_value = NULL; /* Return value */ + + FUNC_ENTER_PACKAGE + + /* Get the path at the requested index */ + if (index >= H5PL_num_paths_g) + HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, NULL, "path index %u is out of range in table", index) + + return H5PL_paths_g[index]; +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5PL__replace_path() */ + + +/*------------------------------------------------------------------------- + * Function: H5PL__find_plugin_in_path_table + * + * Purpose: Attempts to find a matching plugin in the file system + * using the paths stored in the path table. + *. + * The 'found' parameter will be set appropriately. + * + * Return: SUCCEED/FAIL + * + *------------------------------------------------------------------------- + */ +herr_t +H5PL__find_plugin_in_path_table(const H5PL_search_params_t *search_params, hbool_t *found, const void **plugin_info) +{ + unsigned int u; /* iterator */ + herr_t ret_value = SUCCEED; + + FUNC_ENTER_PACKAGE + + /* Check args - Just assert on package functions */ + HDassert(search_params); + HDassert(found); + HDassert(plugin_info); + + /* Initialize output parameters */ + *found = FALSE; + *plugin_info = NULL; + + /* Loop over the paths in the table, checking for an appropriate plugin */ + for (u = 0; u < H5PL_num_paths_g; u++) { + + /* Search for the plugin in this path */ + if (H5PL__find_plugin_in_path(search_params, found, H5PL_paths_g[u], plugin_info) < 0) + HGOTO_ERROR(H5E_PLUGIN, H5E_CANTGET, FAIL, "search in path %s encountered an error", H5PL_paths_g[u]) + + /* Break out if found */ + if (*found) { + if (!plugin_info) + HGOTO_ERROR(H5E_PLUGIN, H5E_BADVALUE, FAIL, "plugin info should not be NULL") + break; + } + } + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5PL__find_plugin_in_path_table() */ + + +/*------------------------------------------------------------------------- + * Function: H5PL__find_plugin_in_path + * + * Purpose: Given a path, this function opens the directory and envokes + * another function to go through all files to find the right + * plugin library. Two function definitions are for Unix and + * Windows. + * + * The found parameter will be set to TRUE and the info + * parameter will be filled in on success. + * + * Return: SUCCEED/FAIL + * + *------------------------------------------------------------------------- + */ +#ifndef H5_HAVE_WIN32_API +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) +{ + char *path = NULL; + DIR *dirp = NULL; /* Directory stream */ + struct dirent *dp = NULL; /* Directory entry */ + herr_t ret_value = SUCCEED; + + FUNC_ENTER_STATIC + + /* Check args - Just assert on package functions */ + HDassert(search_params); + HDassert(found); + HDassert(dir); + HDassert(plugin_info); + + /* Initialize the found parameter */ + *found = FALSE; + + /* Open the directory */ + if (!(dirp = HDopendir(dir))) + HGOTO_ERROR(H5E_PLUGIN, H5E_OPENERROR, FAIL, "can't open directory: %s", dir) + + /* 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 + + h5_stat_t my_stat; + size_t len; + + /* Allocate & initialize the path name */ + len = HDstrlen(dir) + HDstrlen(H5PL_PATH_SEPARATOR) + HDstrlen(dp->d_name) + 1 /*\0*/; + + if (NULL == (path = (char *)H5MM_calloc(len))) + HGOTO_ERROR(H5E_PLUGIN, H5E_CANTALLOC, FAIL, "can't allocate memory for path") + + HDsnprintf(path, len, "%s/%s", dir, dp->d_name); + + /* Get info for directory entry */ + if (HDstat(path, &my_stat) == -1) + HGOTO_ERROR(H5E_FILE, H5E_CANTGET, FAIL, "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 as a filter library */ + if (H5PL__open(path, search_params->type, search_params->id, found, plugin_info) < 0) + HGOTO_ERROR(H5E_PLUGIN, H5E_CANTGET, FAIL, "search in directory failed") + if (*found) + HGOTO_DONE(SUCCEED) + + path = (char *)H5MM_xfree(path); + } /* end if */ + } /* end while */ + +done: + if (dirp) + if (HDclosedir(dirp) < 0) + HDONE_ERROR(H5E_FILE, H5E_CLOSEERROR, FAIL, "can't close directory: %s", HDstrerror(errno)) + + path = (char *)H5MM_xfree(path); + + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5PL__find_plugin_in_path() */ +#else /* H5_HAVE_WIN32_API */ +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) +{ + WIN32_FIND_DATAA fdFile; + HANDLE hFind = INVALID_HANDLE_VALUE; + char *path = NULL; + char service[2048]; + herr_t ret_value = SUCCEED; + + FUNC_ENTER_STATIC + + /* Check args - Just assert on package functions */ + HDassert(search_params); + HDassert(found); + HDassert(dir); + HDassert(plugin_info); + + /* Initialize the found parameter */ + *found = FALSE; + + /* Specify a file mask. *.* = We want everything! */ + HDsprintf(service, "%s\\*.dll", dir); + if ((hFind = FindFirstFileA(service, &fdFile)) == INVALID_HANDLE_VALUE) + HGOTO_ERROR(H5E_PLUGIN, H5E_OPENERROR, FAIL, "can't open directory") + + /* Loop over all the files */ + do { + /* Ignore '.' and '..' */ + if (HDstrcmp(fdFile.cFileName, ".") != 0 && HDstrcmp(fdFile.cFileName, "..") != 0) { + + /* XXX: Probably just continue here and move the code below over one tab */ + + size_t len; + + /* Allocate & initialize the path name */ + len = HDstrlen(dir) + HDstrlen(H5PL_PATH_SEPARATOR) + HDstrlen(fdFile.cFileName) + 1; + + if (NULL == (path = (char *)H5MM_calloc(len))) + HGOTO_ERROR(H5E_PLUGIN, H5E_CANTALLOC, FAIL, "can't allocate memory for path") + + HDsnprintf(path, len, "%s\\%s", dir, fdFile.cFileName); + + /* Ignore directories */ + 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->id, found, plugin_info) < 0) + HGOTO_ERROR(H5E_PLUGIN, H5E_CANTGET, FAIL, "search in directory failed") + if (*found) + HGOTO_DONE(SUCCEED) + + path = (char *)H5MM_xfree(path); + } + } while (FindNextFileA(hFind, &fdFile)); + +done: + if (hFind != INVALID_HANDLE_VALUE) + FindClose(hFind); + if (path) + path = (char *)H5MM_xfree(path); + + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5PL__find_plugin_in_path() */ +#endif /* H5_HAVE_WIN32_API */ + diff --git a/src/H5PLpkg.h b/src/H5PLpkg.h index e356893..0d1c271 100644 --- a/src/H5PLpkg.h +++ b/src/H5PLpkg.h @@ -11,6 +11,12 @@ * help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ +/* + * Purpose: This file contains declarations which are visible only within + * the H5PL package. Source files outside the H5PL package should + * include H5PLprivate.h instead. + */ + #if !(defined H5PL_FRIEND || defined H5PL_MODULE) #error "Do not include this file outside the H5PL package!" #endif @@ -27,13 +33,92 @@ /* Package Private Macros */ /**************************/ -#define H5PL_MAX_PATH_NUM 16 +/* Whether to pre-load pathnames for plugin libraries */ +#define H5PL_DEFAULT_PATH H5_DEFAULT_PLUGINDIR + + +/****************************/ +/* Macros for supporting */ +/* both Windows and POSIX */ +/****************************/ + +/*******************/ +/* Windows support */ +/*******************/ +/* + * SPECIAL WINDOWS NOTE + * + * Some of the Win32 API functions expand to fooA or fooW depending on + * whether UNICODE or _UNICODE are defined. You MUST explicitly use + * the A version of the functions to force char * behavior until we + * work out a scheme for proper Windows Unicode support. + * + * If you do not do this, people will be unable to incorporate our + * source code into their own CMake builds if they define UNICODE. + */ +#ifdef H5_HAVE_WIN32_API + + /* The path separator on this platform */ +# define H5PL_PATH_SEPARATOR ";" + + /* Handle for dynamic library */ +# define H5PL_HANDLE HINSTANCE + + /* Get a handle to a plugin library. Windows: TEXT macro handles Unicode strings */ +# define H5PL_OPEN_DLIB(S) LoadLibraryExA(S, NULL, LOAD_WITH_ALTERED_SEARCH_PATH) + + /* Get the address of a symbol in dynamic library */ +# define H5PL_GET_LIB_FUNC(H,N) GetProcAddress(H,N) + + /* Close dynamic library */ +# define H5PL_CLOSE_LIB(H) FreeLibrary(H) + + /* Clear error - nothing to do */ +# define H5PL_CLR_ERROR + + /* maximum size for expanding env vars */ +# define H5PL_EXPAND_BUFFER_SIZE 32767 + + typedef const void *(__cdecl *H5PL_get_plugin_info_t)(void); + +#else /* H5_HAVE_WIN32_API */ + + /*****************/ + /* POSIX support */ + /*****************/ + + /* The path separator on this platform */ +# define H5PL_PATH_SEPARATOR ":" + + /* Handle for dynamic library */ +# define H5PL_HANDLE void * + + /* Get a handle to a plugin library. Windows: TEXT macro handles Unicode strings */ +# define H5PL_OPEN_DLIB(S) dlopen(S, RTLD_LAZY) + + /* Get the address of a symbol in dynamic library */ +# define H5PL_GET_LIB_FUNC(H,N) dlsym(H,N) + + /* Close dynamic library */ +# define H5PL_CLOSE_LIB(H) dlclose(H) + + /* Clear error */ +# define H5PL_CLR_ERROR HERROR(H5E_PLUGIN, H5E_CANTGET, "can't dlopen:%s", dlerror()) + + typedef const void *(*H5PL_get_plugin_info_t)(void); +#endif /* H5_HAVE_WIN32_API */ /****************************/ /* Package Private Typedefs */ /****************************/ +/* Data used to search for plugins */ +typedef struct H5PL_search_params_t { + H5PL_type_t type; + int id; +} H5PL_search_params_t; + /*****************************/ /* Package Private Variables */ @@ -44,5 +129,31 @@ /* Package Private Prototypes */ /******************************/ +/* Accessors to global variables and flags */ +H5_DLL herr_t H5PL__get_plugin_control_mask(unsigned int *mask /*out*/); +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, int id, hbool_t *success /*out*/, const void **plugin_info /*out*/); +H5_DLL herr_t H5PL__close(H5PL_HANDLE handle); + +/* Plugin cache calls */ +H5_DLL herr_t H5PL__create_plugin_cache(void); +H5_DLL herr_t H5PL__close_plugin_cache(hbool_t *already_closed /*out*/); +H5_DLL herr_t H5PL__add_plugin(H5PL_type_t type, int id, H5PL_HANDLE handle); +H5_DLL herr_t H5PL__find_plugin_in_cache(const H5PL_search_params_t *search_params, hbool_t *found /*out*/, const void **plugin_info /*out*/); + +/* Plugin search path calls */ +H5_DLL herr_t H5PL__create_path_table(void); +H5_DLL herr_t H5PL__close_path_table(void); +H5_DLL unsigned H5PL__get_num_paths(void); +H5_DLL herr_t H5PL__append_path(const char *path); +H5_DLL herr_t H5PL__prepend_path(const char *path); +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*/); + #endif /* _H5PLpkg_H */ diff --git a/src/H5PLplugin_cache.c b/src/H5PLplugin_cache.c new file mode 100644 index 0000000..30a0798 --- /dev/null +++ b/src/H5PLplugin_cache.c @@ -0,0 +1,308 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Copyright by The HDF Group. * + * All rights reserved. * + * * + * This file is part of HDF5. The full HDF5 copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the root of the source code * + * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. * + * If you do not have access to either file, you may request a copy from * + * help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/* + * Purpose: Code to implement a plugin cache which stores information + * about plugins which have already been loaded. + * + * The plugin cache is implemented as a dynamic, global array which + * will grow as new plugins are added. The capacity of the cache + * never shrinks since plugins stay in memory once loaded. + * + * Note that this functionality has absolutely nothing to do with + * the metadata or chunk caches. + */ + +/****************/ +/* Module Setup */ +/****************/ + +#include "H5PLmodule.h" /* This source code file is part of the H5PL module */ + + +/***********/ +/* Headers */ +/***********/ +#include "H5private.h" /* Generic Functions */ +#include "H5Eprivate.h" /* Error handling */ +#include "H5MMprivate.h" /* Memory management */ +#include "H5PLpkg.h" /* Plugin */ +#include "H5Zprivate.h" /* Filter pipeline */ + + +/****************/ +/* Local Macros */ +/****************/ + +/* Initial capacity of the plugin cache */ +#define H5PL_INITIAL_CACHE_CAPACITY 16 + +/* The amount to add to the capacity when the cache is full */ +#define H5PL_CACHE_CAPACITY_ADD 16 + + +/******************/ +/* Local Typedefs */ +/******************/ + +/* Type for the list of info for opened plugin libraries */ +typedef struct H5PL_plugin_t { + H5PL_type_t type; /* Plugin type */ + int id; /* ID for the plugin */ + H5PL_HANDLE handle; /* Plugin handle */ +} H5PL_plugin_t; + + +/********************/ +/* Local Prototypes */ +/********************/ + +static herr_t H5PL__expand_cache(void); + + +/*********************/ +/* Package Variables */ +/*********************/ + + +/*****************************/ +/* Library Private Variables */ +/*****************************/ + + +/*******************/ +/* Local Variables */ +/*******************/ + +/* Cache for storing opened plugin libraries */ +static H5PL_plugin_t *H5PL_cache_g = NULL; + +/* The number of stored plugins */ +static unsigned int H5PL_num_plugins_g = 0; + +/* The capacity of the plugin cache */ +static unsigned int H5PL_cache_capacity_g = 0; + + + +/*------------------------------------------------------------------------- + * Function: H5PL__create_plugin_cache + * + * Purpose: Create the cache that will store plugins that have already + * been loaded. + * + * Return: SUCCEED/FAIL + * + *------------------------------------------------------------------------- + */ +herr_t +H5PL__create_plugin_cache(void) +{ + herr_t ret_value = SUCCEED; + + FUNC_ENTER_PACKAGE + + /* Allocate memory for the plugin cache */ + H5PL_num_plugins_g = 0; + + H5PL_cache_capacity_g = H5PL_INITIAL_CACHE_CAPACITY; + + if (NULL == (H5PL_cache_g = (H5PL_plugin_t *)H5MM_calloc((size_t)H5PL_cache_capacity_g * sizeof(H5PL_plugin_t)))) + HGOTO_ERROR(H5E_PLUGIN, H5E_CANTALLOC, FAIL, "can't allocate memory for plugin cache") + +done: + /* Try to clean up on errors */ + if (FAIL == ret_value) { + if (H5PL_cache_g) + H5PL_cache_g = (H5PL_plugin_t *)H5MM_xfree(H5PL_cache_g); + H5PL_cache_capacity_g = 0; + } + + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5PL__create_plugin_cache() */ + + +/*------------------------------------------------------------------------- + * Function: H5PL__close_plugin_cache + * + * Purpose: Close the cache of plugins that have already been loaded, + * closing all the plugins contained inside. + * + * Return: SUCCEED/FAIL + * + *------------------------------------------------------------------------- + */ +herr_t +H5PL__close_plugin_cache(hbool_t *already_closed /*out*/) +{ + unsigned int u; /* iterator */ + herr_t ret_value = SUCCEED; + + FUNC_ENTER_PACKAGE_NOERR + + /* Close opened dynamic libraries */ + if (H5PL_cache_g) { + + /* Close any cached plugins */ + for (u = 0; u < H5PL_num_plugins_g; u++) + H5PL__close((H5PL_cache_g[u]).handle); + + /* Free the cache array */ + H5PL_cache_g = (H5PL_plugin_t *)H5MM_xfree(H5PL_cache_g); + H5PL_num_plugins_g = 0; + H5PL_cache_capacity_g = 0; + + /* Note that actually closed the table (needed by package close call) */ + *already_closed = FALSE; + } + else + *already_closed = TRUE; + + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5PL__close_plugin_cache() */ + + +/*------------------------------------------------------------------------- + * Function: H5PL__expand_cache + * + * Purpose: Expand the plugin cache when it's full. + * + * Return: SUCCEED/FAIL + * + *------------------------------------------------------------------------- + */ +static herr_t +H5PL__expand_cache(void) +{ + herr_t ret_value = SUCCEED; + + FUNC_ENTER_STATIC + + /* Update the capacity */ + H5PL_cache_capacity_g += H5PL_CACHE_CAPACITY_ADD; + + /* Resize the array */ + if(NULL == (H5PL_cache_g = (H5PL_plugin_t *)H5MM_realloc(H5PL_cache_g, (size_t)H5PL_cache_capacity_g * sizeof(H5PL_plugin_t)))) + HGOTO_ERROR(H5E_PLUGIN, H5E_CANTALLOC, FAIL, "allocating additional memory for plugin cache failed") + + /* Initialize the new memory */ + HDmemset(H5PL_cache_g + H5PL_num_plugins_g, 0, (size_t)H5PL_CACHE_CAPACITY_ADD * sizeof(H5PL_plugin_t)); + +done: + /* Set the cache capacity back if there were problems */ + if (FAIL == ret_value) + H5PL_cache_capacity_g -= H5PL_CACHE_CAPACITY_ADD; + + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5PL__expand_cache() */ + + +/*------------------------------------------------------------------------- + * Function: H5PL__add_plugin + * + * Purpose: Add a plugin to the plugin cached. + * + * Return: SUCCEED/FAIL + * + *------------------------------------------------------------------------- + */ +herr_t +H5PL__add_plugin(H5PL_type_t type, int id, H5PL_HANDLE handle) +{ + herr_t ret_value = SUCCEED; + + FUNC_ENTER_PACKAGE + + /* Expand the cache if it is too small */ + if (H5PL_num_plugins_g >= H5PL_cache_capacity_g) + if (H5PL__expand_cache() < 0) + HGOTO_ERROR(H5E_PLUGIN, H5E_CANTALLOC, FAIL, "can't expand plugin cache") + + /* Store the plugin info and bump the # of plugins */ + H5PL_cache_g[H5PL_num_plugins_g].type = type; + H5PL_cache_g[H5PL_num_plugins_g].id = id; + H5PL_cache_g[H5PL_num_plugins_g].handle = handle; + + H5PL_num_plugins_g++; + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5PL__add_plugin() */ + + +/*------------------------------------------------------------------------- + * Function: H5PL__find_plugin_in_cache + * + * Purpose: Attempts to find a matching plugin from the cache. + * + * The 'found' parameter will be set appropriately. + * + * Return: SUCCEED/FAIL + * + *------------------------------------------------------------------------- + */ +herr_t +H5PL__find_plugin_in_cache(const H5PL_search_params_t *search_params, hbool_t *found, const void **plugin_info) +{ + unsigned int u; /* iterator */ + herr_t ret_value = SUCCEED; + + FUNC_ENTER_PACKAGE + + /* Check args - Just assert on package functions */ + HDassert(search_params); + HDassert(found); + HDassert(plugin_info); + + /* Initialize output parameters */ + *found = FALSE; + *plugin_info = NULL; + + /* 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 ((search_params->type == (H5PL_cache_g[u]).type) && (search_params->id == (H5PL_cache_g[u]).id)) { + + H5PL_get_plugin_info_t get_plugin_info_function; + const H5Z_class2_t *filter_info; + + /* Get the "get plugin info" function from the plugin. + * + * See the other use of H5PL_GET_LIB_FUNC() for an explanation + * for why we disable -Wpedantic here. + */ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wpedantic" + if (NULL == (get_plugin_info_function = (H5PL_get_plugin_info_t)H5PL_GET_LIB_FUNC((H5PL_cache_g[u]).handle, "H5PLget_plugin_info"))) + HGOTO_ERROR(H5E_DATATYPE, H5E_CANTGET, FAIL, "can't get function for H5PLget_plugin_info") +#pragma GCC diagnostic pop + + /* Call the "get plugin info" function */ + if (NULL == (filter_info = (const H5Z_class2_t *)(*get_plugin_info_function)())) + HGOTO_ERROR(H5E_DATATYPE, H5E_CANTGET, FAIL, "can't get plugin info") + + /* Set output parameters */ + *found = TRUE; + *plugin_info = filter_info; + + /* No need to continue processing */ + break; + + } /* end if */ + + } /* end for */ + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5PL__find_plugin_in_cache() */ + diff --git a/src/H5PLprivate.h b/src/H5PLprivate.h index 0ab8f8c..bc12e64 100644 --- a/src/H5PLprivate.h +++ b/src/H5PLprivate.h @@ -10,8 +10,8 @@ * help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -/* Programmer: Raymond Lu <songyulu@hdfgroup.org> - * 13 February 2013 +/* + * This file contains private information about the H5PL module */ #ifndef _H5PLprivate_H diff --git a/src/H5PLpublic.h b/src/H5PLpublic.h index 9ce1fca..3b36ccd 100644 --- a/src/H5PLpublic.h +++ b/src/H5PLpublic.h @@ -10,8 +10,8 @@ * help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -/* Programmer: Raymond Lu <songyulu@hdfgroup.org> - * 13 February 2013 +/* + * This file contains public declarations for the H5PL module. */ #ifndef _H5PLpublic_H @@ -24,31 +24,35 @@ /* Public Typedefs */ /*******************/ +/* Special string to indicate no plugin loading. + */ +#define H5PL_NO_PLUGIN "::" + /* Plugin type used by the plugin library */ typedef enum H5PL_type_t { - H5PL_TYPE_ERROR = -1, /*error */ - H5PL_TYPE_FILTER = 0, /*filter */ - H5PL_TYPE_NONE = 1 /*this must be last! */ + H5PL_TYPE_ERROR = -1, /* Error */ + H5PL_TYPE_FILTER = 0, /* Filter */ + H5PL_TYPE_NONE = 1 /* This must be last! */ } H5PL_type_t; /* Common dynamic plugin type flags used by the set/get_loading_state functions */ -#define H5PL_FILTER_PLUGIN 0x0001 -#define H5PL_ALL_PLUGIN 0xFFFF +#define H5PL_FILTER_PLUGIN 0x0001 +#define H5PL_ALL_PLUGIN 0xFFFF #ifdef __cplusplus extern "C" { #endif /* plugin state */ -H5_DLL herr_t H5PLset_loading_state(unsigned int plugin_type); -H5_DLL herr_t H5PLget_loading_state(unsigned int *plugin_type/*out*/); -H5_DLL herr_t H5PLappend(const char *plugin_path); -H5_DLL herr_t H5PLprepend(const char *plugin_path); -H5_DLL herr_t H5PLreplace(const char *plugin_path, unsigned int index); -H5_DLL herr_t H5PLinsert(const char *plugin_path, unsigned int index); +H5_DLL herr_t H5PLset_loading_state(unsigned int plugin_control_mask); +H5_DLL herr_t H5PLget_loading_state(unsigned int *plugin_control_mask /*out*/); +H5_DLL herr_t H5PLappend(const char *search_path); +H5_DLL herr_t H5PLprepend(const char *search_path); +H5_DLL herr_t H5PLreplace(const char *search_path, unsigned int index); +H5_DLL herr_t H5PLinsert(const char *search_path, unsigned int index); H5_DLL herr_t H5PLremove(unsigned int index); -H5_DLL ssize_t H5PLget(unsigned int index, char *pathname/*out*/, size_t size); -H5_DLL herr_t H5PLsize(unsigned int *listsize/*out*/); +H5_DLL ssize_t H5PLget(unsigned int index, char *path_buf /*out*/, size_t buf_size); +H5_DLL herr_t H5PLsize(unsigned int *num_paths /*out*/); #ifdef __cplusplus } diff --git a/src/H5system.c b/src/H5system.c index 7e25540..a1cdf19 100644 --- a/src/H5system.c +++ b/src/H5system.c @@ -1237,3 +1237,49 @@ H5_get_time(void) } /* end H5_get_time() */ +#ifdef H5_HAVE_WIN32_API + +#define H5_WIN32_ENV_VAR_BUFFER_SIZE 32767 + + +/*------------------------------------------------------------------------- + * Function: H5_expand_windows_env_vars() + * + * Purpose: Replaces windows environment variables of the form %foo% + * with user-specific values. + * + * Return: SUCCEED/FAIL + * + *------------------------------------------------------------------------- + */ +herr_t +H5_expand_windows_env_vars(char **env_var) +{ + long n_chars = 0; + char *temp_buf = NULL; + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT + + /* Allocate buffer for expanded environment variable string */ + if (NULL == (temp_buf = (char *)H5MM_calloc((size_t)H5_WIN32_ENV_VAR_BUFFER_SIZE))) + HGOTO_ERROR(H5E_PLUGIN, H5E_CANTALLOC, FAIL, "can't allocate memory for expanded path") + + /* Expand the environment variable string */ + if ((n_chars = ExpandEnvironmentStringsA(*env_var, temp_buf, H5_WIN32_ENV_VAR_BUFFER_SIZE)) > H5_WIN32_ENV_VAR_BUFFER_SIZE) + HGOTO_ERROR(H5E_PLUGIN, H5E_NOSPACE, FAIL, "expanded path is too long") + + if (0 == n_chars) + HGOTO_ERROR(H5E_PLUGIN, H5E_CANTGET, FAIL, "failed to expand path") + + *env_var = (char *)H5MM_xfree(*env_var); + *env_var = temp_buf; + +done: + if (FAIL == ret_value && temp_buf) + temp_buf = (char *)H5MM_xfree(temp_buf); + + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5_expand_windows_env_vars() */ +#endif /* H5_HAVE_WIN32_API */ + diff --git a/src/H5win32defs.h b/src/H5win32defs.h index 97f7179..4522228 100644 --- a/src/H5win32defs.h +++ b/src/H5win32defs.h @@ -119,6 +119,7 @@ extern "C" { H5_DLL int c99_snprintf(char* str, size_t size, const char* format, ...); H5_DLL int c99_vsnprintf(char* str, size_t size, const char* format, va_list ap); H5_DLL int Wnanosleep(const struct timespec *req, struct timespec *rem); + H5_DLL herr_t H5_expand_windows_env_vars(char **env_var); /* Round functions only needed for VS2012 and earlier. * They are always built to ensure they don't go stale and diff --git a/src/Makefile.am b/src/Makefile.am index 0b664a7..9a64717 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -97,7 +97,7 @@ libhdf5_la_SOURCES= H5.c H5checksum.c H5dbg.c H5system.c H5timer.c H5trace.c \ H5Pgcpl.c H5Pint.c \ H5Plapl.c H5Plcpl.c H5Pocpl.c H5Pocpypl.c H5Pstrcpl.c H5Ptest.c \ H5PB.c \ - H5PL.c \ + H5PL.c H5PLint.c H5PLpath.c H5PLplugin_cache.c \ H5R.c H5Rdeprec.c \ H5UC.c \ H5RS.c \ diff --git a/test/plugin.c b/test/plugin.c index 3034c0b..ea199f6 100644 --- a/test/plugin.c +++ b/test/plugin.c @@ -10,9 +10,6 @@ * help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* - * Programmer: Raymond Lu - * 13 February 2013 - * * Purpose: Tests the plugin module (H5PL) */ @@ -660,13 +657,10 @@ error: /*------------------------------------------------------------------------- * Function: test_groups_with_filters * - * Purpose: Tests opening group with dynamically loaded filters - * - * Return: Success: 0 - * Failure: -1 + * Purpose: Tests opening group with dynamically loaded filters * - * Programmer: Raymond Lu - * 1 April 2013 + * Return: Success: 0 + * Failure: -1 * *------------------------------------------------------------------------- */ @@ -710,264 +704,388 @@ error: /*------------------------------------------------------------------------- - * Function: test_filter_path_apis + * Function: test_path_api_calls * - * Purpose: Tests accessing the path table for dynamically loaded filters + * Purpose: Tests the H5PL API calls that manipulate the plugin search + * paths. * - * Return: Success: 0 - * Failure: -1 + * Return: SUCCEED/FAIL + * *------------------------------------------------------------------------- */ static herr_t -test_filter_path_apis(void) +test_path_api_calls(void) { - herr_t ret_value = -1; - unsigned int i; - unsigned int ndx; + unsigned int n_starting_paths; + unsigned int u; + unsigned int n_paths; herr_t ret; - ssize_t pathlen = -1; - char pathname[256]; - char tempname[256]; + ssize_t path_len = -1; + char path[256]; + char temp_name[256]; HDputs("Testing access to the filter path table"); - if(H5Zfilter_avail(H5Z_FILTER_DYNLIB1) != TRUE) TEST_ERROR + if(H5Zfilter_avail(H5Z_FILTER_DYNLIB1) != TRUE) + TEST_ERROR + + /* Set the number of paths to create for this test. + * + * This should be set high enough to ensure that at least one array + * expansion will take place. See H5PLpath.c for details. + */ + n_starting_paths = 42; + /* Check that initialization is correct */ TESTING(" initialize"); - H5PLsize(&ndx); - if(ndx!=2) TEST_ERROR + + if(H5PLsize(&n_paths) < 0) + TEST_ERROR + if(n_paths != 2) + TEST_ERROR + PASSED(); + /****************/ + /* H5PLremove() */ + /****************/ + + /* Remove all the current paths */ TESTING(" remove"); - /* Remove all existing paths*/ - for(i=ndx; i > 0; i--) - if(H5PLremove(i-1) < 0) { - HDfprintf(stderr," at %d: %s\n", i, pathname); + + /* Get the current size */ + if(H5PLsize(&n_paths) < 0) + TEST_ERROR + + /* Remove all existing paths */ + for(u = n_paths; u > 0; u--) + if(H5PLremove(u-1) < 0) { + HDfprintf(stderr," at %u: %s\n", u, path); TEST_ERROR - } /* end if */ + } + /* Verify the table is empty */ - H5PLsize(&ndx); - if(ndx > 0) TEST_ERROR + if(H5PLsize(&n_paths) < 0) + TEST_ERROR + if(n_paths > 0) + TEST_ERROR + PASSED(); - TESTING(" remove (exceed min)"); - /* Exceed the min path removal */ + + TESTING(" remove (index 0 in empty table)"); + + /* Try to remove index zero in an empty list (SHOULD FAIL) */ H5E_BEGIN_TRY { ret = H5PLremove(0); } H5E_END_TRY - if(ret >= 0) TEST_ERROR + if(ret >= 0) + TEST_ERROR + PASSED(); + + /****************/ + /* H5PLappend() */ + /****************/ + TESTING(" append"); - /* Create multiple paths to fill table */ - for(i=0; i < H5PL_MAX_PATH_NUM; i++) { - HDsprintf(pathname, "a_path_%d", i); - if(H5PLappend(pathname) < 0) { - HDfprintf(stderr," at %d: %s\n", i, pathname); + + /* Add a bunch of paths to the path table */ + for(u = 0; u < n_starting_paths; u++) { + HDsprintf(path, "a_path_%u", u); + if(H5PLappend(path) < 0) { + HDfprintf(stderr," at %u: %s\n", u, path); TEST_ERROR } } - /* Verify the table is full */ - H5PLsize(&ndx); - if(ndx != H5PL_MAX_PATH_NUM) TEST_ERROR - PASSED(); - TESTING(" append (exceed)"); - /* Exceed the max path append */ - H5E_BEGIN_TRY { - HDsprintf(pathname, "a_path_%d", H5PL_MAX_PATH_NUM); - ret = H5PLappend(pathname); - } H5E_END_TRY - if(ret >= 0) TEST_ERROR PASSED(); - TESTING(" remove (exceed max)"); - /* Exceed the max path removal */ + + /**********************/ + /* H5PLremove() again */ + /**********************/ + + TESTING(" remove (index too high)"); + + /* Try to remove a path where the index is beyond the table capacity (SHOULD FAIL) */ H5E_BEGIN_TRY { - ret = H5PLremove(H5PL_MAX_PATH_NUM); + ret = H5PLremove(n_starting_paths); } H5E_END_TRY - if(ret >= 0) TEST_ERROR + + if(ret >= 0) + TEST_ERROR + PASSED(); + + /*************/ + /* H5PLget() */ + /*************/ + TESTING(" get (path name)"); - if((pathlen = H5PLget(0, NULL, 0)) <= 0) { + + /* Get the path length by passing in NULL */ + if((path_len = H5PLget(0, NULL, 0)) <= 0) { HDfprintf(stderr," get path 0 length failed\n"); TEST_ERROR } - if(pathlen != 8) TEST_ERROR + if(path_len != 8) + TEST_ERROR - if((pathlen = H5PLget(0, pathname, 256)) <= 0) { - HDfprintf(stderr," get 0 len: %d : %s\n", pathlen, pathname); + /* Get the path */ + if((path_len = H5PLget(0, path, 256)) <= 0) { + HDfprintf(stderr," get 0 len: %u : %s\n", path_len, path); TEST_ERROR } - if(HDstrcmp(pathname, "a_path_0") != 0) { - HDfprintf(stderr," get 0: %s\n", pathname); + if(HDstrcmp(path, "a_path_0") != 0) { + HDfprintf(stderr," get 0: %s\n", path); TEST_ERROR } + PASSED(); - TESTING(" get (bounds)"); - if((pathlen = H5PLget(1, pathname, 256)) <= 0) TEST_ERROR - if(HDstrcmp(pathname, "a_path_1") != 0) { - HDfprintf(stderr," get 1: %s\n", pathname); + + TESTING(" get (high and low indices)"); + + /* Get path at index 1 */ + if((path_len = H5PLget(1, path, 256)) <= 0) + TEST_ERROR + if(HDstrcmp(path, "a_path_1") != 0) { + HDfprintf(stderr," get 1: %s\n", path); TEST_ERROR } - if((pathlen = H5PLget(H5PL_MAX_PATH_NUM - 1, pathname, 256)) <= 0) TEST_ERROR - HDsprintf(tempname, "a_path_%d", H5PL_MAX_PATH_NUM - 1); - if(HDstrcmp(pathname, tempname) != 0) { - HDfprintf(stderr," get %d: %s\n", H5PL_MAX_PATH_NUM - 1, pathname); + + /* Get path at the last index */ + if((path_len = H5PLget(n_starting_paths - 1, path, 256)) <= 0) + TEST_ERROR + HDsprintf(temp_name, "a_path_%u", n_starting_paths - 1); + if(HDstrcmp(path, temp_name) != 0) { + HDfprintf(stderr," get %u: %s\n", n_starting_paths - 1, path); TEST_ERROR } + PASSED(); - TESTING(" get (bounds exceed)"); + + TESTING(" get (index too high)"); + + /* Get path at the last + 1 index (SHOULD FAIL) */ H5E_BEGIN_TRY { - pathlen = H5PLget(H5PL_MAX_PATH_NUM, NULL, 0); + path_len = H5PLget(n_starting_paths, NULL, 0); } H5E_END_TRY - if(pathlen > 0) TEST_ERROR + if(path_len > 0) + TEST_ERROR + PASSED(); - TESTING(" remove (verify for prepend)"); - /* Remove one path*/ - if(H5PLremove(8) < 0) TEST_ERROR + + /*****************/ + /* H5PLprepend() */ + /*****************/ + + /* We'll remove a path at an arbitrary index and then + * prepend a new path. + */ + + TESTING(" remove (arbitrary index 1)"); + + /* Remove one path */ + if(H5PLremove(8) < 0) + TEST_ERROR /* Verify that the entries were moved */ - if((pathlen = H5PLget(8, pathname, 256)) <= 0) TEST_ERROR - if(HDstrcmp(pathname, "a_path_9") != 0) { - HDfprintf(stderr," get 8: %s\n", pathname); + if((path_len = H5PLget(8, path, 256)) <= 0) + TEST_ERROR + if(HDstrcmp(path, "a_path_9") != 0) { + HDfprintf(stderr," get 8: %s\n", path); TEST_ERROR } + + /* Verify the table shrank */ + if(H5PLsize(&n_paths) < 0) + TEST_ERROR + if(n_paths != n_starting_paths - 1) + TEST_ERROR + PASSED(); - /* Verify the table is not full */ - H5PLsize(&ndx); - if (ndx != H5PL_MAX_PATH_NUM - 1) TEST_ERROR TESTING(" prepend"); - /* Prepend one path*/ - HDsprintf(pathname, "a_path_%d", H5PL_MAX_PATH_NUM + 1); - if(H5PLprepend(pathname) < 0) { - HDfprintf(stderr," prepend %d: %s\n", H5PL_MAX_PATH_NUM + 1, pathname); + + /* Prepend one path */ + HDsprintf(path, "a_path_%d", n_starting_paths + 1); + if(H5PLprepend(path) < 0) { + HDfprintf(stderr," prepend %u: %s\n", n_starting_paths + 1, path); TEST_ERROR } - /* Verify the table is full */ - H5PLsize(&ndx); - if(ndx != H5PL_MAX_PATH_NUM) TEST_ERROR + /* Verify the table increased */ + if(H5PLsize(&n_paths) < 0) + TEST_ERROR + if(n_paths != n_starting_paths) + TEST_ERROR /* Verify that the entries were moved */ - if(H5PLget(8, pathname, 256) <= 0) TEST_ERROR - if(HDstrcmp(pathname, "a_path_7") != 0) { - HDfprintf(stderr," get 8: %s\n", pathname); + if(H5PLget(8, path, 256) <= 0) + TEST_ERROR + if(HDstrcmp(path, "a_path_7") != 0) { + HDfprintf(stderr," get 8: %s\n", path); TEST_ERROR } - if(H5PLget(0, pathname, 256) <= 0) TEST_ERROR - HDsprintf(tempname, "a_path_%d", H5PL_MAX_PATH_NUM + 1); - if(HDstrcmp(pathname, tempname) != 0) { - HDfprintf(stderr," get 0: %s\n", pathname); + + /* Verify that the path was inserted at index zero */ + if(H5PLget(0, path, 256) <= 0) + TEST_ERROR + HDsprintf(temp_name, "a_path_%d", n_starting_paths + 1); + if(HDstrcmp(path, temp_name) != 0) { + HDfprintf(stderr," get 0: %s\n", path); TEST_ERROR } - PASSED(); - TESTING(" prepend (exceed)"); - /* Exceed the max path prepend */ - H5E_BEGIN_TRY { - HDsprintf(pathname, "a_path_%d", H5PL_MAX_PATH_NUM + 2); - ret = H5PLprepend(pathname); - } H5E_END_TRY - if(ret >= 0) TEST_ERROR PASSED(); + + /*****************/ + /* H5PLreplace() */ + /*****************/ + TESTING(" replace"); - /* Replace one path*/ - HDsprintf(pathname, "a_path_%d", H5PL_MAX_PATH_NUM + 4); - if(H5PLreplace(pathname, 1) < 0) { - HDfprintf(stderr," replace 1: %s\n", pathname); + + /* Replace one path at index 1 */ + HDsprintf(path, "a_path_%u", n_starting_paths + 4); + if(H5PLreplace(path, 1) < 0) { + HDfprintf(stderr," replace 1: %s\n", path); TEST_ERROR } - /* Verify the table is full */ - H5PLsize(&ndx); - if(ndx != H5PL_MAX_PATH_NUM) TEST_ERROR + /* Verify the table size remained the same */ + if(H5PLsize(&n_paths) < 0) + TEST_ERROR + if(n_paths != n_starting_paths) + TEST_ERROR + + /* Verify that the entries were not moved by + * inspecting the paths at indices +/- 1. + */ - /* Verify that the entries were not moved */ - if(H5PLget(0, pathname, 256) <= 0) TEST_ERROR - HDsprintf(tempname, "a_path_%d", H5PL_MAX_PATH_NUM + 1); - if(HDstrcmp(pathname, tempname) != 0) { - HDfprintf(stderr," get 0: %s\n", pathname); + /* Check path at index 0 */ + if(H5PLget(0, path, 256) <= 0) + TEST_ERROR + HDsprintf(temp_name, "a_path_%u", n_starting_paths + 1); + if(HDstrcmp(path, temp_name) != 0) { + HDfprintf(stderr," get 0: %s\n", path); TEST_ERROR } - if(H5PLget(2, pathname, 256) <= 0) TEST_ERROR - if(HDstrcmp(pathname, "a_path_1") != 0) { - HDfprintf(stderr," get 2: %s\n", pathname); + + /* Check path at index 2 */ + if(H5PLget(2, path, 256) <= 0) + TEST_ERROR + if(HDstrcmp(path, "a_path_1") != 0) { + HDfprintf(stderr," get 2: %s\n", path); TEST_ERROR } + PASSED(); - TESTING(" remove (verify for insert)"); - /* Remove one path*/ - if(H5PLremove(4) < 0) TEST_ERROR + + /****************/ + /* H5PLinsert() */ + /****************/ + + /* We'll remove a path at an arbitrary index and then + * insert a new path. + */ + + TESTING(" remove (arbitrary index 2)"); + + /* Remove one path */ + if(H5PLremove(4) < 0) + TEST_ERROR /* Verify that the entries were moved */ - if(H5PLget(4, pathname, 256) <= 0) TEST_ERROR - if(HDstrcmp(pathname, "a_path_4") != 0) { - HDfprintf(stderr," get 4: %s\n", pathname); + if(H5PLget(4, path, 256) <= 0) + TEST_ERROR + if(HDstrcmp(path, "a_path_4") != 0) { + HDfprintf(stderr," get 4: %s\n", path); TEST_ERROR } + + /* Verify the table size */ + if(H5PLsize(&n_paths) < 0) + TEST_ERROR + if(n_paths != n_starting_paths - 1) + TEST_ERROR PASSED(); - /* Verify the table is not full */ - H5PLsize(&ndx); - if(ndx != 15) TEST_ERROR TESTING(" insert"); - /* Insert one path*/ - HDsprintf(pathname, "a_path_%d", H5PL_MAX_PATH_NUM + 5); - if(H5PLinsert(pathname, 3) < 0) { - HDfprintf(stderr," insert 3: %s\n", pathname); + + /* Insert one path at index 3*/ + HDsprintf(path, "a_path_%d", n_starting_paths + 5); + if(H5PLinsert(path, 3) < 0) { + HDfprintf(stderr," insert 3: %s\n", path); TEST_ERROR } /* Verify that the entries were moved */ - if(H5PLget(4, pathname, 256) <= 0) TEST_ERROR - if(HDstrcmp(pathname, "a_path_2") != 0) { - HDfprintf(stderr," get 4: %s\n", pathname); + if(H5PLget(4, path, 256) <= 0) + TEST_ERROR + if(HDstrcmp(path, "a_path_2") != 0) { + HDfprintf(stderr," get 4: %s\n", path); TEST_ERROR } + + /* Verify the table size increased */ + if(H5PLsize(&n_paths) < 0) + TEST_ERROR + if(n_paths != n_starting_paths) + TEST_ERROR + PASSED(); - /* Verify the table is full */ - H5PLsize(&ndx); - if(ndx != H5PL_MAX_PATH_NUM) TEST_ERROR - TESTING(" insert (exceed)"); - /* Exceed the max path insert */ - H5E_BEGIN_TRY { - HDsprintf(pathname, "a_path_%d", H5PL_MAX_PATH_NUM + 6); - ret = H5PLinsert(pathname, 12); - } H5E_END_TRY - if(ret >= 0) TEST_ERROR + /****************/ + /* H5PLremove() */ + /****************/ + + /* Remove all the current paths */ + TESTING(" remove (all)"); + + /* Get the current size */ + if(H5PLsize(&n_paths) < 0) + TEST_ERROR + + /* Remove all existing paths */ + for(u = n_paths; u > 0; u--) + if(H5PLremove(u-1) < 0) { + HDfprintf(stderr," at %u: %s\n", u, path); + TEST_ERROR + } + + /* Verify the table is empty */ + if(H5PLsize(&n_paths) < 0) + TEST_ERROR + if(n_paths > 0) + TEST_ERROR PASSED(); - ret_value = 0; + + return SUCCEED; error: - return ret_value; -} + return FAIL; +} /* end test_path_api_calls() */ /*------------------------------------------------------------------------- * Function: main * - * Purpose: Tests the plugin module (H5PL) + * Purpose: Tests the plugin module (H5PL) * - * Return: Success: exit(EXIT_SUCCESS) - * - * Failure: exit(EXIT_FAILURE) - * - * Programmer: Raymond Lu - * 14 March 2013 + * Return: EXIT_SUCCESS/EXIT_FAILURE * *------------------------------------------------------------------------- */ @@ -987,37 +1105,44 @@ main(void) /* Testing setup */ h5_reset(); - fapl = h5_fileaccess(); + + if ((fapl = h5_fileaccess()) < 0) + TEST_ERROR /* Turn off the chunk cache, so all the chunks are immediately written to disk */ - if(H5Pget_cache(fapl, &mdc_nelmts, &rdcc_nelmts, &rdcc_nbytes, &rdcc_w0) < 0) TEST_ERROR + if (H5Pget_cache(fapl, &mdc_nelmts, &rdcc_nelmts, &rdcc_nbytes, &rdcc_w0) < 0) + TEST_ERROR rdcc_nbytes = 0; - if(H5Pset_cache(fapl, mdc_nelmts, rdcc_nelmts, rdcc_nbytes, rdcc_w0) < 0) TEST_ERROR + if (H5Pset_cache(fapl, mdc_nelmts, rdcc_nelmts, rdcc_nbytes, rdcc_w0) < 0) + TEST_ERROR /* Copy the file access property list */ - if((fapl2 = H5Pcopy(fapl)) < 0) TEST_ERROR + if ((fapl2 = H5Pcopy(fapl)) < 0) + TEST_ERROR /* Set the "use the latest version of the format" bounds for creating objects in the file */ - if(H5Pset_libver_bounds(fapl2, H5F_LIBVER_LATEST, H5F_LIBVER_LATEST) < 0) TEST_ERROR + if (H5Pset_libver_bounds(fapl2, H5F_LIBVER_LATEST, H5F_LIBVER_LATEST) < 0) + TEST_ERROR - h5_fixname(FILENAME[0], fapl, filename, sizeof filename); + h5_fixname(FILENAME[0], fapl, filename, sizeof(filename)); /* Test with old & new format groups */ - for(new_format = FALSE; new_format <= TRUE; new_format++) { + for (new_format = FALSE; new_format <= TRUE; new_format++) { hid_t my_fapl; /* Set the FAPL for the type of format */ - if(new_format) { + if (new_format) { HDputs("\nTesting with new file format:"); my_fapl = fapl2; - } /* end if */ + } else { HDputs("Testing with old file format:"); my_fapl = fapl; - } /* end else */ + } /* Create the file for this test */ - if((file = H5Fcreate(filename, H5F_ACC_TRUNC, H5P_DEFAULT, my_fapl)) < 0) TEST_ERROR + if ((file = H5Fcreate(filename, H5F_ACC_TRUNC, H5P_DEFAULT, my_fapl)) < 0) + TEST_ERROR /* Test dynamically loaded filters for chunked dataset */ nerrors += (test_filters_for_datasets(file) < 0 ? 1 : 0); @@ -1025,12 +1150,15 @@ main(void) /* Test dynamically loaded filters for groups */ nerrors += (test_filters_for_groups(file) < 0 ? 1 : 0); - if(H5Fclose(file) < 0) TEST_ERROR + if (H5Fclose(file) < 0) + TEST_ERROR } /* end for */ /* Close FAPL */ - if(H5Pclose(fapl2) < 0) TEST_ERROR - if(H5Pclose(fapl) < 0) TEST_ERROR + if (H5Pclose(fapl2) < 0) + TEST_ERROR + if (H5Pclose(fapl) < 0) + TEST_ERROR /* Restore the default error handler (set in h5_reset()) */ h5_restore_err(); @@ -1039,10 +1167,12 @@ main(void) /* Close the library so that all loaded plugin libraries are unloaded */ h5_reset(); - fapl = h5_fileaccess(); + if ((fapl = h5_fileaccess()) < 0) + TEST_ERROR /* Reopen the file for testing data reading */ - if((file = H5Fopen(filename, H5F_ACC_RDONLY, fapl)) < 0) TEST_ERROR + if ((file = H5Fopen(filename, H5F_ACC_RDONLY, fapl)) < 0) + TEST_ERROR /* Read the data with filters */ nerrors += (test_read_with_filters(file) < 0 ? 1 : 0); @@ -1055,29 +1185,33 @@ main(void) /* Close the library so that all loaded plugin libraries are unloaded */ h5_reset(); - fapl = h5_fileaccess(); + if ((fapl = h5_fileaccess()) < 0) + TEST_ERROR /* Reopen the file for testing data reading */ - if((file = H5Fopen(filename, H5F_ACC_RDONLY, fapl)) < 0) TEST_ERROR + if ((file = H5Fopen(filename, H5F_ACC_RDONLY, fapl)) < 0) + TEST_ERROR /* Read the data with disabled filters */ nerrors += (test_noread_with_filters(file) < 0 ? 1 : 0); - if(H5Fclose(file) < 0) TEST_ERROR + if (H5Fclose(file) < 0) + TEST_ERROR /* Test the APIs for access to the filter plugin path table */ - nerrors += (test_filter_path_apis() < 0 ? 1 : 0); + nerrors += (test_path_api_calls() < 0 ? 1 : 0); - if(nerrors) TEST_ERROR + if (nerrors) + TEST_ERROR HDprintf("All plugin tests passed.\n"); h5_cleanup(FILENAME, fapl); - return 0; + HDexit(EXIT_SUCCESS); error: nerrors = MAX(1, nerrors); HDprintf("***** %d PLUGIN TEST%s FAILED! *****\n", nerrors, 1 == nerrors ? "" : "S"); - return 1; -} + HDexit(EXIT_FAILURE); +} /* end main() */ |