/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 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 files COPYING and Copyright.html. COPYING can be found at the root * * of the source code distribution tree; Copyright.html can be found at the * * root level of an installed copy of the electronic document set and is * * linked from the top-level documents page. It can also be found at * * http://hdfgroup.org/HDF5/doc/Copyright.html. If you do not have access * * to either file, you may request a copy from help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /****************/ /* Module Setup */ /****************/ /* Interface initialization */ #define H5_INTERFACE_INIT_FUNC H5PL__init_interface /***********/ /* Headers */ /***********/ #include "H5private.h" /* Generic Functions */ #include "H5Eprivate.h" /* Error handling */ #include "H5MMprivate.h" /* Memory management */ #include "H5PLprivate.h" /* Plugin */ #include "H5Zprivate.h" /* Filter pipeline */ /****************/ /* Local Macros */ /****************/ #define H5PL_MAX_PATH_NUM 16 /****************************/ /* 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 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_NOW) /* 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 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 */ /*********************/ /*****************************/ /* Library Private Variables */ /*****************************/ /*******************/ /* 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_interface -- Initialize interface-specific information USAGE herr_t H5PL__init_interface() RETURNS Non-negative on success/Negative on failure DESCRIPTION Initializes any interface-specific data or routines. --------------------------------------------------------------------------*/ static herr_t H5PL__init_interface(void) { char *preload_path; FUNC_ENTER_STATIC_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 symbal "::" means no plugin during data reading. */ if(!HDstrcmp(preload_path, H5PL_NO_PLUGIN)) H5PL_plugin_g = 0; } /* end if */ FUNC_LEAVE_NOAPI(SUCCEED) } /* end H5PL__init_interface() */ /*------------------------------------------------------------------------- * Function: H5PLset_loading_state * * Purpose: Control the loading of 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. * * plugin bit = 0, will prevent the use of that dynamic plugin type. * plugin bit = 1, will allow the use of that dynamic plugin type. * * 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 * * Return: Non-negative or success * *------------------------------------------------------------------------- */ herr_t H5PLset_loading_state(unsigned int plugin_type) { char *preload_path; 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; /* 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; } done: FUNC_LEAVE_API(ret_value) } /* end H5PLset_loading_state() */ /*------------------------------------------------------------------------- * Function: H5PLget_loading_state * * Purpose: Query state of the loading of dynamic plugin types. * * This function will return the state of the global flag. * * 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. * *------------------------------------------------------------------------- */ herr_t H5PLget_loading_state(unsigned int *plugin_type) { herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_API(FAIL) H5TRACE1("e", "*Iu", plugin_type); if(plugin_type) *plugin_type = H5PL_plugin_g; done: FUNC_LEAVE_API(ret_value) } /* end H5PLget_loading_state() */ /*------------------------------------------------------------------------- * Function: H5PL_term_interface * * 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. * * Programmer: Raymond Lu * 20 February 2013 * *------------------------------------------------------------------------- */ int H5PL_term_interface(void) { int i = 0; FUNC_ENTER_NOAPI_NOINIT_NOERR if(H5_interface_initialize_g) { size_t u; /* Local index variable */ /* Close opened dynamic libraries */ 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; /* Free the table of search paths */ 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; H5_interface_initialize_g = 0; i = 1; } /* end if */ FUNC_LEAVE_NOAPI(i) } /* end H5PL_term_interface() */ /*------------------------------------------------------------------------- * 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; default: HGOTO_ERROR(H5E_PLUGIN, H5E_CANTLOAD, NULL, "required dynamically loaded plugin '%d' is not valid", id) } /* 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: 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 = HDstrdup(H5PL_DEFAULT_PATH); else dl_path = HDstrdup(origin_dl_path); if(NULL == dl_path) HGOTO_ERROR(H5E_PLUGIN, H5E_CANTALLOC, FAIL, "can't allocate memory for path") /* 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] = HDstrdup(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") /* 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) { /* Indicate success */ HGOTO_DONE(TRUE) } /* end if */ else HDassert(pathname); 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)) if(pathname) 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) { /* Indicate success */ HGOTO_DONE(TRUE) } /* end if */ else HDassert(pathname); 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() */