1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2  * Copyright by The HDF Group.                                               *
3  * All rights reserved.                                                      *
4  *                                                                           *
5  * This file is part of HDF5. The full HDF5 copyright notice, including      *
6  * terms governing use, modification, and redistribution, is contained in    *
7  * the COPYING file, which can be found at the root of the source code       *
8  * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases.  *
9  * If you do not have access to either file, you may request a copy from     *
10  * help@hdfgroup.org.                                                        *
11  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
12 #define H5PL_PACKAGE        /*suppress error about including H5PLpkg   */
13 
14 /****************/
15 /* Module Setup */
16 /****************/
17 
18 /* Interface initialization */
19 #define H5_INTERFACE_INIT_FUNC    H5PL__init_interface
20 
21 
22 /***********/
23 /* Headers */
24 /***********/
25 #include "H5private.h"      /* Generic Functions            */
26 #include "H5Eprivate.h"     /* Error handling               */
27 #include "H5MMprivate.h"    /* Memory management            */
28 #include "H5PLpkg.h"        /* Plugin                       */
29 #include "H5Zprivate.h"     /* Filter pipeline              */
30 
31 
32 /****************/
33 /* Local Macros */
34 /****************/
35 #ifdef H5_HAVE_WIN32_API
36 #define H5PL_EXPAND_ENV_VAR {                                                            \
37         long bufCharCount;                                                               \
38         char *tempbuf;                                                                   \
39         if(NULL == (tempbuf = (char *)H5MM_malloc(H5PL_EXPAND_BUFFER_SIZE)))             \
40             HGOTO_ERROR(H5E_PLUGIN, H5E_CANTALLOC, FAIL, "can't allocate memory for expanded path")                          \
41         if((bufCharCount = ExpandEnvironmentStringsA(dl_path, tempbuf, H5PL_EXPAND_BUFFER_SIZE)) > H5PL_EXPAND_BUFFER_SIZE) { \
42             tempbuf = (char *)H5MM_xfree(tempbuf);                                       \
43             HGOTO_ERROR(H5E_PLUGIN, H5E_NOSPACE, FAIL, "expanded path is too long")      \
44         }                                                                                \
45         if(bufCharCount == 0) {                                                          \
46             tempbuf = (char *)H5MM_xfree(tempbuf);                                       \
47             HGOTO_ERROR(H5E_PLUGIN, H5E_CANTGET, FAIL, "failed to expand path")          \
48         }                                                                                \
49         dl_path = (char *)H5MM_xfree(dl_path);                                           \
50         dl_path = tempbuf;                                                               \
51  }
52 #else
53 #define H5PL_EXPAND_ENV_VAR
54 #endif /* H5_HAVE_WIN32_API */
55 
56 /****************************/
57 /* Macros for supporting
58  * both Windows and Unix */
59 /****************************/
60 /* Windows support
61  *
62  * SPECIAL WINDOWS NOTE
63  *
64  * Some of the Win32 API functions expand to fooA or fooW depending on
65  * whether UNICODE or _UNICODE are defined. You MUST explicitly use
66  * the A version of the functions to force char * behavior until we
67  * work out a scheme for proper Windows Unicode support.
68  *
69  * If you do not do this, people will be unable to incorporate our
70  * source code into their own CMake builds if they define UNICODE.
71  */
72 
73 #ifdef H5_HAVE_WIN32_API
74 
75 #define H5PL_PATH_SEPARATOR     ";"
76 
77 /* Handle for dynamic library */
78 #define H5PL_HANDLE HINSTANCE
79 
80 /* Get a handle to a plugin library.  Windows: TEXT macro handles Unicode strings */
81 #define H5PL_OPEN_DLIB(S) LoadLibraryExA(S, NULL, LOAD_WITH_ALTERED_SEARCH_PATH)
82 
83 /* Get the address of a symbol in dynamic library */
84 #define H5PL_GET_LIB_FUNC(H,N) GetProcAddress(H,N)
85 
86 /* Close dynamic library */
87 #define H5PL_CLOSE_LIB(H) FreeLibrary(H)
88 
89 /* Clear error - nothing to do */
90 #define H5PL_CLR_ERROR
91 
92 /* maximum size for expanding env vars */
93 #define H5PL_EXPAND_BUFFER_SIZE 32767
94 
95 typedef const void *(__cdecl *H5PL_get_plugin_info_t)(void);
96 
97 /* Unix support */
98 #else /* H5_HAVE_WIN32_API */
99 
100 #define H5PL_PATH_SEPARATOR     ":"
101 
102 /* Handle for dynamic library */
103 #define H5PL_HANDLE void *
104 
105 /* Get a handle to a plugin library.  Windows: TEXT macro handles Unicode strings */
106 #define H5PL_OPEN_DLIB(S) dlopen(S, RTLD_LAZY)
107 
108 /* Get the address of a symbol in dynamic library */
109 #define H5PL_GET_LIB_FUNC(H,N) dlsym(H,N)
110 
111 /* Close dynamic library */
112 #define H5PL_CLOSE_LIB(H) dlclose(H)
113 
114 /* Clear error */
115 #define H5PL_CLR_ERROR HERROR(H5E_PLUGIN, H5E_CANTGET, "can't dlopen:%s", dlerror())
116 
117 typedef const void *(*H5PL_get_plugin_info_t)(void);
118 #endif /* H5_HAVE_WIN32_API */
119 
120 /* Whether to preload pathnames for plugin libraries */
121 #define H5PL_DEFAULT_PATH       H5_DEFAULT_PLUGINDIR
122 
123 /* Special symbol to indicate no plugin loading */
124 #define H5PL_NO_PLUGIN          "::"
125 
126 /******************/
127 /* Local Typedefs */
128 /******************/
129 
130 /* Type for the list of info for opened plugin libraries */
131 typedef struct H5PL_table_t {
132     H5PL_type_t pl_type;            /* plugin type          */
133     int         pl_id;              /* ID for the plugin    */
134     H5PL_HANDLE handle;             /* plugin handle        */
135 } H5PL_table_t;
136 
137 
138 /********************/
139 /* Local Prototypes */
140 /********************/
141 
142 static herr_t H5PL__init_path_table(void);
143 static htri_t H5PL__find(H5PL_type_t plugin_type, int type_id, char *dir, const void **info);
144 static htri_t H5PL__open(H5PL_type_t pl_type, char *libname, int plugin_id, const void **pl_info);
145 static htri_t H5PL__search_table(H5PL_type_t plugin_type, int type_id, const void **info);
146 static herr_t H5PL__close(H5PL_HANDLE handle);
147 
148 
149 /*********************/
150 /* Package Variables */
151 /*********************/
152 
153 
154 /*****************************/
155 /* Library Private Variables */
156 /*****************************/
157 
158 
159 /*******************/
160 /* Local Variables */
161 /*******************/
162 
163 /* Table for opened plugin libraries */
164 static size_t           H5PL_table_alloc_g = 0;
165 static size_t           H5PL_table_used_g = 0;
166 static H5PL_table_t     *H5PL_table_g = NULL;
167 
168 /* Table of location paths for plugin libraries */
169 static char             *H5PL_path_table_g[H5PL_MAX_PATH_NUM];
170 static size_t           H5PL_num_paths_g = 0;
171 static hbool_t          H5PL_path_found_g = FALSE;
172 
173 /* Enable all plugin libraries */
174 static unsigned int     H5PL_plugin_g = H5PL_ALL_PLUGIN;
175 
176 
177 /*--------------------------------------------------------------------------
178 NAME
179    H5PL__init_interface -- Initialize interface-specific information
180 USAGE
181     herr_t H5PL__init_interface()
182 RETURNS
183     Non-negative on success/Negative on failure
184 DESCRIPTION
185     Initializes any interface-specific data or routines.
186 
187 --------------------------------------------------------------------------*/
188 static herr_t
H5PL__init_interface(void)189 H5PL__init_interface(void)
190 {
191     char        *preload_path;
192 
193     FUNC_ENTER_STATIC_NOERR
194 
195     /* Retrieve pathnames from HDF5_PLUGIN_PRELOAD if the user sets it
196      * to tell the library to load plugin libraries without search.
197      */
198     if(NULL != (preload_path = HDgetenv("HDF5_PLUGIN_PRELOAD"))) {
199         /* Special symbal "::" means no plugin during data reading. */
200         if(!HDstrcmp(preload_path, H5PL_NO_PLUGIN))
201             H5PL_plugin_g = 0;
202     } /* end if */
203 
204     FUNC_LEAVE_NOAPI(SUCCEED)
205 } /* end H5PL__init_interface() */
206 
207 
208 /*-------------------------------------------------------------------------
209  * Function: H5PLset_loading_state
210  *
211  * Purpose: Control the loading of dynamic plugin types.
212  *
213  * This function will not allow plugin types if the pathname from the HDF5_PLUGIN_PRELOAD
214  * environment variable is set to the special "::" string.
215  *
216  * plugin bit = 0, will prevent the use of that dynamic plugin type.
217  * plugin bit = 1, will allow the use of that dynamic plugin type.
218  *
219  * H5PL_TYPE_FILTER changes just dynamic filters
220  * A H5PL_ALL_PLUGIN will enable all dynamic plugin types
221  * A zero value will disable all dynamic plugin types
222  *
223  * Return: Non-negative or success
224  *
225  *-------------------------------------------------------------------------
226  */
227 herr_t
H5PLset_loading_state(unsigned int plugin_type)228 H5PLset_loading_state(unsigned int plugin_type)
229 {
230     char *preload_path;
231     herr_t ret_value = SUCCEED; /* Return value */
232 
233     FUNC_ENTER_API(FAIL)
234     H5TRACE1("e", "Iu", plugin_type);
235 
236     /* change the bit value of the requested plugin type(s) */
237     H5PL_plugin_g = plugin_type;
238 
239     /* check if special ENV variable is set and disable all plugin types */
240     if(NULL != (preload_path = HDgetenv("HDF5_PLUGIN_PRELOAD"))) {
241         /* Special symbol "::" means no plugin during data reading. */
242         if(!HDstrcmp(preload_path, H5PL_NO_PLUGIN))
243             H5PL_plugin_g = 0;
244     }
245 done:
246     FUNC_LEAVE_API(ret_value)
247 } /* end H5PLset_loading_state() */
248 
249 
250 /*-------------------------------------------------------------------------
251  * Function: H5PLget_loading_state
252  *
253  * Purpose: Query state of the loading of dynamic plugin types.
254  *
255  * This function will return the state of the global flag.
256  *
257  * Return: Zero if all plugin types are disabled, negative if all
258  * plugin types are enabled, positive if one or more of the plugin types are enabled.
259  *
260  *-------------------------------------------------------------------------
261  */
262 herr_t
H5PLget_loading_state(unsigned int * plugin_type)263 H5PLget_loading_state(unsigned int *plugin_type)
264 {
265     herr_t ret_value = SUCCEED; /* Return value */
266 
267     FUNC_ENTER_API(FAIL)
268     H5TRACE1("e", "*Iu", plugin_type);
269 
270     if(plugin_type)
271         *plugin_type = H5PL_plugin_g;
272 
273 done:
274     FUNC_LEAVE_API(ret_value)
275 } /* end H5PLget_loading_state() */
276 
277 
278 /*-------------------------------------------------------------------------
279  * Function:    H5PL_term_interface
280  *
281  * Purpose:     Terminate the H5PL interface: release all memory, reset all
282  *              global variables to initial values. This only happens if all
283  *              types have been destroyed from other interfaces.
284  *
285  * Return:      Success:    Positive if any action was taken that might
286  *                          affect some other interface; zero otherwise.
287  *
288  *              Failure:    Negative.
289  *
290  * Programmer:  Raymond Lu
291  *              20 February 2013
292  *
293  *-------------------------------------------------------------------------
294  */
295 int
H5PL_term_interface(void)296 H5PL_term_interface(void)
297 {
298     int  i = 0;
299 
300     FUNC_ENTER_NOAPI_NOINIT_NOERR
301 
302     if(H5_interface_initialize_g) {
303         size_t u;       /* Local index variable */
304 
305         /* Close opened dynamic libraries */
306         for(u = 0; u < H5PL_table_used_g; u++)
307             H5PL__close((H5PL_table_g[u]).handle);
308 
309         /* Free the table of dynamic libraries */
310         H5PL_table_g = (H5PL_table_t *)H5MM_xfree(H5PL_table_g);
311         H5PL_table_used_g = H5PL_table_alloc_g = 0;
312 
313         /* Free the table of search paths */
314         for(u = 0; u < H5PL_num_paths_g; u++)
315             if(H5PL_path_table_g[u])
316                 H5PL_path_table_g[u] = (char *)H5MM_xfree(H5PL_path_table_g[u]);
317         H5PL_num_paths_g = 0;
318         H5PL_path_found_g = FALSE;
319 
320         H5_interface_initialize_g = 0;
321         i = 1;
322     } /* end if */
323 
324     FUNC_LEAVE_NOAPI(i)
325 } /* end H5PL_term_interface() */
326 
327 
328 /*-------------------------------------------------------------------------
329  * Function:    H5PL_load
330  *
331  * Purpose:     Given the plugin type and identifier, this function searches
332  *              and/or loads a dynamic plugin library first among the already
333  *              opened libraries then in the designated location paths.
334  *
335  * Return:      Non-NULL on success/NULL on failure
336  *
337  * Programmer:  Raymond Lu
338  *              13 February 2013
339  *
340  *-------------------------------------------------------------------------
341  */
342 const void *
H5PL_load(H5PL_type_t type,int id)343 H5PL_load(H5PL_type_t type, int id)
344 {
345     htri_t      found;               /* Whether the plugin was found */
346     const void  *plugin_info = NULL;
347     const void  *ret_value = NULL;
348 
349     FUNC_ENTER_NOAPI(NULL)
350 
351     switch(type) {
352         case H5PL_TYPE_FILTER:
353             if((H5PL_plugin_g & H5PL_FILTER_PLUGIN) == 0)
354                 HGOTO_ERROR(H5E_PLUGIN, H5E_CANTLOAD, NULL, "required dynamically loaded plugin filter '%d' is not available", id)
355             break;
356 
357         case H5PL_TYPE_ERROR:
358         case H5PL_TYPE_NONE:
359         default:
360             HGOTO_ERROR(H5E_PLUGIN, H5E_CANTLOAD, NULL, "required dynamically loaded plugin '%d' is not valid", id)
361     } /* end switch */
362 
363     /* Initialize the location paths for dynamic libraries, if they aren't
364      * already set up.
365      */
366     if(FALSE == H5PL_path_found_g)
367         if(H5PL__init_path_table() < 0)
368             HGOTO_ERROR(H5E_PLUGIN, H5E_CANTINIT, NULL, "can't initialize search path table")
369 
370     /* Search in the table of already loaded plugin libraries */
371     if((found = H5PL__search_table(type, id, &plugin_info)) < 0)
372         HGOTO_ERROR(H5E_PLUGIN, H5E_CANTGET, NULL, "search in table failed")
373 
374     /* If not found, iterate through the path table to find the right dynamic library */
375     if(!found) {
376         size_t       i;                   /* Local index variable */
377 
378         for(i = 0; i < H5PL_num_paths_g; i++) {
379             if((found = H5PL__find(type, id, H5PL_path_table_g[i], &plugin_info)) < 0)
380                 HGOTO_ERROR(H5E_PLUGIN, H5E_CANTGET, NULL, "search in paths failed")
381 
382             /* Break out if found */
383             if(found) {
384                 HDassert(plugin_info);
385                 break;
386             } /* end if */
387         } /* end for */
388     } /* end if */
389 
390     /* Check if we found the plugin */
391     if(found)
392         ret_value = plugin_info;
393 
394 done:
395     FUNC_LEAVE_NOAPI(ret_value)
396 } /* end H5PL_load() */
397 
398 
399 /*-------------------------------------------------------------------------
400  * Function: H5PLappend
401  *
402  * Purpose: Insert a plugin path at the end of the list.
403  *
404  * Return: Non-negative or success.
405  *
406  *-------------------------------------------------------------------------
407  */
408 herr_t
H5PLappend(const char * plugin_path)409 H5PLappend(const char *plugin_path)
410 {
411     herr_t ret_value = SUCCEED; /* Return value */
412     char        *dl_path = NULL;
413 
414     FUNC_ENTER_API(FAIL)
415     H5TRACE1("e", "*s", plugin_path);
416     if(H5PL_num_paths_g == H5PL_MAX_PATH_NUM)
417         HGOTO_ERROR(H5E_PLUGIN, H5E_NOSPACE, FAIL, "too many directories in path for table")
418     if(NULL == plugin_path)
419         HGOTO_ERROR(H5E_PLUGIN, H5E_CANTALLOC, FAIL, "no path provided")
420     if(NULL == (dl_path = H5MM_strdup(plugin_path)))
421         HGOTO_ERROR(H5E_PLUGIN, H5E_CANTALLOC, FAIL, "can't allocate memory for path")
422 
423     H5PL_EXPAND_ENV_VAR
424 
425     H5PL_path_table_g[H5PL_num_paths_g] = dl_path;
426     H5PL_num_paths_g++;
427 
428 done:
429     FUNC_LEAVE_API(ret_value)
430 } /* end H5PLappend() */
431 
432 
433 /*-------------------------------------------------------------------------
434  * Function: H5PLprepend
435  *
436  * Purpose: Insert a plugin path at the beginning of the list.
437  *
438  * Return: Non-negative or success.
439  *
440  *-------------------------------------------------------------------------
441  */
442 herr_t
H5PLprepend(const char * plugin_path)443 H5PLprepend(const char *plugin_path)
444 {
445     herr_t ret_value = SUCCEED; /* Return value */
446     char        *dl_path = NULL;
447     unsigned int plindex;
448 
449     FUNC_ENTER_API(FAIL)
450     H5TRACE1("e", "*s", plugin_path);
451     if(H5PL_num_paths_g == H5PL_MAX_PATH_NUM)
452         HGOTO_ERROR(H5E_PLUGIN, H5E_NOSPACE, FAIL, "too many directories in path for table")
453     if(NULL == plugin_path)
454         HGOTO_ERROR(H5E_PLUGIN, H5E_CANTALLOC, FAIL, "no path provided")
455     if(NULL == (dl_path = H5MM_strdup(plugin_path)))
456         HGOTO_ERROR(H5E_PLUGIN, H5E_CANTALLOC, FAIL, "can't allocate memory for path")
457 
458     H5PL_EXPAND_ENV_VAR
459 
460     for (plindex = (unsigned int)H5PL_num_paths_g; plindex > 0; plindex--)
461         H5PL_path_table_g[plindex] = H5PL_path_table_g[plindex - 1];
462     H5PL_path_table_g[0] = dl_path;
463     H5PL_num_paths_g++;
464 
465 done:
466     FUNC_LEAVE_API(ret_value)
467 } /* end H5PLprepend() */
468 
469 
470 /*-------------------------------------------------------------------------
471  * Function: H5PLreplace
472  *
473  * Purpose: Replace the path at the specified index.
474  *
475  * Return: Non-negative or success.
476  *
477  *-------------------------------------------------------------------------
478  */
479 herr_t
H5PLreplace(const char * plugin_path,unsigned int index)480 H5PLreplace(const char *plugin_path, unsigned int index)
481 {
482     herr_t ret_value = SUCCEED; /* Return value */
483     char        *dl_path = NULL;
484 
485     FUNC_ENTER_API(FAIL)
486     H5TRACE2("e", "*sIu", plugin_path, index);
487     if(NULL == plugin_path)
488         HGOTO_ERROR(H5E_PLUGIN, H5E_CANTALLOC, FAIL, "no path provided")
489     if(index >= H5PL_MAX_PATH_NUM)
490         HGOTO_ERROR(H5E_PLUGIN, H5E_NOSPACE, FAIL, "index path out of bounds for table")
491     if(NULL == (dl_path = H5MM_strdup(plugin_path)))
492         HGOTO_ERROR(H5E_PLUGIN, H5E_CANTALLOC, FAIL, "can't allocate memory for path")
493 
494     H5PL_EXPAND_ENV_VAR
495 
496     if(H5PL_path_table_g[index])
497         H5PL_path_table_g[index] = (char *)H5MM_xfree(H5PL_path_table_g[index]);
498     H5PL_path_table_g[index] = dl_path;
499 
500 done:
501     FUNC_LEAVE_API(ret_value)
502 } /* end H5PLreplace() */
503 
504 
505 /*-------------------------------------------------------------------------
506  * Function: H5PLinsert
507  *
508  * Purpose: Insert a plugin path at the specified index, moving other paths after the index.
509  *
510  * Return: Non-negative or success.
511  *
512  *-------------------------------------------------------------------------
513  */
514 herr_t
H5PLinsert(const char * plugin_path,unsigned int index)515 H5PLinsert(const char *plugin_path, unsigned int index)
516 {
517     herr_t ret_value = SUCCEED; /* Return value */
518     char        *dl_path = NULL;
519     unsigned int plindex;
520 
521     FUNC_ENTER_API(FAIL)
522     H5TRACE2("e", "*sIu", plugin_path, index);
523     if(H5PL_num_paths_g == H5PL_MAX_PATH_NUM)
524         HGOTO_ERROR(H5E_PLUGIN, H5E_NOSPACE, FAIL, "too many directories in path for table")
525     if(NULL == plugin_path)
526         HGOTO_ERROR(H5E_PLUGIN, H5E_CANTALLOC, FAIL, "no path provided")
527     if(index >= H5PL_MAX_PATH_NUM)
528         HGOTO_ERROR(H5E_PLUGIN, H5E_NOSPACE, FAIL, "index path out of bounds for table")
529     if(NULL == (dl_path = H5MM_strdup(plugin_path)))
530         HGOTO_ERROR(H5E_PLUGIN, H5E_CANTALLOC, FAIL, "can't allocate memory for path")
531 
532     H5PL_EXPAND_ENV_VAR
533 
534     for(plindex = (unsigned int)H5PL_num_paths_g; plindex > index; plindex--)
535         H5PL_path_table_g[plindex] = H5PL_path_table_g[plindex - 1];
536     H5PL_path_table_g[index] = dl_path;
537     H5PL_num_paths_g++;
538 
539 done:
540     FUNC_LEAVE_API(ret_value)
541 } /* end H5PLinsert() */
542 
543 
544 /*-------------------------------------------------------------------------
545  * Function: H5PLremove
546  *
547  * Purpose: Remove the plugin path at the specifed index and compacting the list.
548  *
549  * Return: Non-negative or success.
550  *
551  *-------------------------------------------------------------------------
552  */
553 herr_t
H5PLremove(unsigned int index)554 H5PLremove(unsigned int index)
555 {
556     herr_t ret_value = SUCCEED; /* Return value */
557     unsigned int plindex;
558 
559     FUNC_ENTER_API(FAIL)
560     H5TRACE1("e", "Iu", index);
561     if(H5PL_num_paths_g == 0)
562         HGOTO_ERROR(H5E_PLUGIN, H5E_NOSPACE, FAIL, "no directories in table")
563     if(index >= H5PL_MAX_PATH_NUM)
564         HGOTO_ERROR(H5E_PLUGIN, H5E_NOSPACE, FAIL, "index path out of bounds for table")
565     if(NULL == H5PL_path_table_g[index])
566         HGOTO_ERROR(H5E_PLUGIN, H5E_CANTALLOC, FAIL, "no directory path at index")
567     H5PL_path_table_g[index] = (char *)H5MM_xfree(H5PL_path_table_g[index]);
568 
569     H5PL_num_paths_g--;
570     for(plindex = index; plindex < (unsigned int)H5PL_num_paths_g; plindex++)
571         H5PL_path_table_g[plindex] = H5PL_path_table_g[plindex + 1];
572     H5PL_path_table_g[H5PL_num_paths_g] = NULL;
573 
574 done:
575     FUNC_LEAVE_API(ret_value)
576 } /* end H5PLremove() */
577 
578 
579 /*-------------------------------------------------------------------------
580  * Function: H5PLget
581  *
582  * Purpose: Query the plugin path at the specified index.
583  *
584  * Return: Success: The length of path.
585  *
586  *  If `pathname' is non-NULL then write up to `size' bytes into that
587  *  buffer and always return the length of the pathname.
588  *  Otherwise `size' is ignored and the function does not store the pathname,
589  *  just returning the number of characters required to store the pathname.
590  *  If an error occurs then the buffer pointed to by `pathname' (NULL or non-NULL)
591  *  is unchanged and the function returns a negative value.
592  *  If a zero is returned for the name's length, then there is no pathname
593  *  associated with the index.
594  *
595  *-------------------------------------------------------------------------
596  */
597 ssize_t
H5PLget(unsigned int index,char * pathname,size_t size)598 H5PLget(unsigned int index, char *pathname/*out*/, size_t size)
599 {
600     ssize_t      ret_value = 0;    /* Return value */
601     size_t       len = 0;          /* Length of pathname */
602     char        *dl_path = NULL;
603 
604     FUNC_ENTER_API(FAIL)
605     H5TRACE3("Zs", "Iuxz", index, pathname, size);
606     if(H5PL_num_paths_g == 0)
607         HGOTO_ERROR(H5E_PLUGIN, H5E_NOSPACE, FAIL, "no directories in table")
608     if(index >= H5PL_MAX_PATH_NUM)
609         HGOTO_ERROR(H5E_PLUGIN, H5E_NOSPACE, FAIL, "index path out of bounds for table")
610     if(NULL == (dl_path = H5PL_path_table_g[index]))
611         HGOTO_ERROR(H5E_PLUGIN, H5E_CANTALLOC, FAIL, "no directory path at index")
612     len = HDstrlen(dl_path);
613     if(pathname) {
614         HDstrncpy(pathname, dl_path, MIN((size_t)(len + 1), size));
615         if((size_t)len >= size)
616             pathname[size - 1] = '\0';
617     } /* end if */
618 
619     /* Set return value */
620     ret_value = (ssize_t)len;
621 
622 done:
623     FUNC_LEAVE_API(ret_value)
624 } /* end H5PLget() */
625 
626 
627 /*-------------------------------------------------------------------------
628  * Function: H5PLsize
629  *
630  * Purpose: Query the size of the current list of plugin paths.
631  *
632  * Return: Plugin path size
633  *
634  *-------------------------------------------------------------------------
635  */
636 herr_t
H5PLsize(unsigned int * listsize)637 H5PLsize(unsigned int *listsize)
638 {
639     herr_t ret_value = SUCCEED; /* Return value */
640 
641     FUNC_ENTER_API(FAIL)
642     H5TRACE1("e", "*Iu", listsize);
643 
644     *listsize = (unsigned int)H5PL_num_paths_g;
645 
646 done:
647     FUNC_LEAVE_API(ret_value)
648 } /* end H5PLsize() */
649 
650 
651 /*-------------------------------------------------------------------------
652  * Function:    H5PL__init_path_table
653  *
654  * Purpose:     Initialize the path table.
655  *
656  * Return:      Non-negative on success/Negative on failure
657  *
658  * Programmer:  Quincey Koziol
659  *              18 March 2013
660  *
661  *-------------------------------------------------------------------------
662  */
663 static herr_t
H5PL__init_path_table(void)664 H5PL__init_path_table(void)
665 {
666     char        *dl_path = NULL;
667     char        *origin_dl_path;
668     char        *dir;
669     herr_t      ret_value = SUCCEED;    /* Return value */
670 
671     FUNC_ENTER_STATIC
672 
673     /* Retrieve paths from HDF5_PLUGIN_PATH if the user sets it
674      * or from the default paths if it isn't set.
675      */
676     origin_dl_path = HDgetenv("HDF5_PLUGIN_PATH");
677     if(NULL == origin_dl_path)
678         dl_path = H5MM_strdup(H5PL_DEFAULT_PATH);
679     else
680         dl_path = H5MM_strdup(origin_dl_path);
681     if(NULL == dl_path)
682         HGOTO_ERROR(H5E_PLUGIN, H5E_CANTALLOC, FAIL, "can't allocate memory for path")
683 
684     H5PL_EXPAND_ENV_VAR
685 
686     /* Put paths in the path table.  They are separated by ":" */
687     dir = HDstrtok(dl_path, H5PL_PATH_SEPARATOR);
688     while(dir) {
689         /* Check for too many directories in path */
690         if(H5PL_num_paths_g == H5PL_MAX_PATH_NUM)
691             HGOTO_ERROR(H5E_PLUGIN, H5E_NOSPACE, FAIL, "too many directories in path for table")
692         if(NULL == (H5PL_path_table_g[H5PL_num_paths_g] = H5MM_strdup(dir)))
693             HGOTO_ERROR(H5E_PLUGIN, H5E_CANTALLOC, FAIL, "can't allocate memory for path")
694         H5PL_num_paths_g++;
695         dir = HDstrtok(NULL, H5PL_PATH_SEPARATOR);
696     } /* end while */
697 
698     H5PL_path_found_g = TRUE;
699 
700 done:
701     if(dl_path)
702         dl_path = (char *)H5MM_xfree(dl_path);
703 
704     FUNC_LEAVE_NOAPI(ret_value)
705 } /* end H5PL__init_path_table() */
706 
707 
708 /*-------------------------------------------------------------------------
709  * Function:    H5PL__find
710  *
711  * Purpose:     Given a path, this function opens the directory and envokes
712  *              another function to go through all files to find the right
713  *              plugin library. Two function definitions are for Unix and
714  *              Windows.
715  *
716  * Return:      TRUE on success,
717  *              FALSE on not found,
718  *              negative on failure
719  *
720  * Programmer:  Raymond Lu
721  *              13 February 2013
722  *
723  *-------------------------------------------------------------------------
724  */
725 #ifndef H5_HAVE_WIN32_API
726 static htri_t
H5PL__find(H5PL_type_t plugin_type,int type_id,char * dir,const void ** info)727 H5PL__find(H5PL_type_t plugin_type, int type_id, char *dir, const void **info)
728 {
729     char           *pathname = NULL;
730     DIR            *dirp = NULL;
731     struct dirent  *dp;
732     htri_t         ret_value = FALSE;
733 
734     FUNC_ENTER_STATIC
735 
736     /* Open the directory */
737     if(!(dirp = HDopendir(dir)))
738         HGOTO_ERROR(H5E_PLUGIN, H5E_OPENERROR, FAIL, "can't open directory: %s", dir)
739 
740     /* Iterates through all entries in the directory to find the right plugin library */
741     while(NULL != (dp = HDreaddir(dirp))) {
742         /* The library we are looking for should be called libxxx.so... on Unix
743          * or libxxx.xxx.dylib on Mac.
744          */
745 #ifndef __CYGWIN__
746         if(!HDstrncmp(dp->d_name, "lib", (size_t)3) &&
747                 (HDstrstr(dp->d_name, ".so") || HDstrstr(dp->d_name, ".dylib"))) {
748 #else
749         if(!HDstrncmp(dp->d_name, "cyg", (size_t)3) &&
750                 HDstrstr(dp->d_name, ".dll") ) {
751 
752 #endif
753             h5_stat_t   my_stat;
754             size_t      pathname_len;
755             htri_t      found_in_dir;
756 
757             /* Allocate & initialize the path name */
758             pathname_len = HDstrlen(dir) + HDstrlen(dp->d_name) + 2;
759             if(NULL == (pathname = (char *)H5MM_malloc(pathname_len)))
760                 HGOTO_ERROR(H5E_PLUGIN, H5E_CANTALLOC, FAIL, "can't allocate memory for path")
761             HDsnprintf(pathname, pathname_len, "%s/%s", dir, dp->d_name);
762 
763             /* Get info for directory entry */
764             if(HDstat(pathname, &my_stat) == -1)
765                 HGOTO_ERROR(H5E_FILE, H5E_CANTGET, FAIL, "can't stat file: %s", HDstrerror(errno))
766 
767             /* If it is a directory, skip it */
768             if(S_ISDIR(my_stat.st_mode))
769                 continue;
770 
771             /* Attempt to open the dynamic library as a filter library */
772             if((found_in_dir = H5PL__open(plugin_type, pathname, type_id, info)) < 0)
773                 HGOTO_ERROR(H5E_PLUGIN, H5E_CANTGET, FAIL, "search in directory failed")
774             if(found_in_dir)
775                 HGOTO_DONE(TRUE)    /* Indicate success */
776             pathname = (char *)H5MM_xfree(pathname);
777         } /* end if */
778     } /* end while */
779 
780 done:
781     if(dirp)
782         if(HDclosedir(dirp) < 0)
783             HDONE_ERROR(H5E_FILE, H5E_CLOSEERROR, FAIL, "can't close directory: %s", HDstrerror(errno))
784     pathname = (char *)H5MM_xfree(pathname);
785 
786     FUNC_LEAVE_NOAPI(ret_value)
787 } /* end H5PL__find() */
788 #else /* H5_HAVE_WIN32_API */
789 static htri_t
790 H5PL__find(H5PL_type_t plugin_type, int type_id, char *dir, const void **info)
791 {
792     WIN32_FIND_DATAA    fdFile;
793     HANDLE              hFind;
794     char                *pathname = NULL;
795     char                service[2048];
796     htri_t              ret_value = FALSE;
797 
798     FUNC_ENTER_STATIC
799 
800     /* Specify a file mask. *.* = We want everything! */
801     sprintf(service, "%s\\*.dll", dir);
802     if((hFind = FindFirstFileA(service, &fdFile)) == INVALID_HANDLE_VALUE)
803         HGOTO_ERROR(H5E_PLUGIN, H5E_OPENERROR, FAIL, "can't open directory")
804 
805     do {
806         /* Find first file will always return "."
807          * and ".." as the first two directories.
808          */
809         if(HDstrcmp(fdFile.cFileName, ".") != 0 && HDstrcmp(fdFile.cFileName, "..") != 0) {
810             size_t      pathname_len;
811             htri_t      found_in_dir;
812 
813             /* Allocate & initialize the path name */
814             pathname_len = HDstrlen(dir) + HDstrlen(fdFile.cFileName) + 2;
815             if(NULL == (pathname = (char *)H5MM_malloc(pathname_len)))
816                 HGOTO_ERROR(H5E_PLUGIN, H5E_CANTALLOC, FAIL, "can't allocate memory for path")
817             HDsnprintf(pathname, pathname_len, "%s\\%s", dir, fdFile.cFileName);
818 
819             /* Is the entity a File or Folder? */
820             if(fdFile.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
821                 continue;
822 
823             if((found_in_dir = H5PL__open(plugin_type, pathname, type_id, info)) < 0)
824                 HGOTO_ERROR(H5E_PLUGIN, H5E_CANTGET, FAIL, "search in directory failed")
825             if(found_in_dir)
826                 HGOTO_DONE(TRUE)    /* Indicate success */
827             pathname = (char *)H5MM_xfree(pathname);
828         } /* end if */
829     } while(FindNextFileA(hFind, &fdFile)); /* Find the next file. */
830 
831 done:
832     if(hFind)
833         FindClose(hFind);
834     if(pathname)
835         pathname = (char *)H5MM_xfree(pathname);
836 
837     FUNC_LEAVE_NOAPI(ret_value)
838 } /* end H5PL__find() */
839 #endif /* H5_HAVE_WIN32_API */
840 
841 
842 /*-------------------------------------------------------------------------
843  * Function:    H5PL__open
844  *
845  * Purpose:     Iterates through all files to find the right plugin library.
846  *              It loads the dynamic plugin library and keeps it on the list
847  *              of loaded libraries.
848  *
849  * Return:      TRUE on success,
850  *              FALSE on not found,
851  *              negative on failure
852  *
853  * Programmer:  Raymond Lu
854  *              13 February 2013
855  *
856  *-------------------------------------------------------------------------
857  */
858 static htri_t
859 H5PL__open(H5PL_type_t pl_type, char *libname, int pl_id, const void **pl_info)
860 {
861     H5PL_HANDLE    handle = NULL;
862     htri_t         ret_value = FALSE;
863 
864     FUNC_ENTER_STATIC
865 
866     /* There are different reasons why a library can't be open, e.g. wrong architecture.
867      * simply continue if we can't open it.
868      */
869     if(NULL == (handle = H5PL_OPEN_DLIB(libname))) {
870         H5PL_CLR_ERROR; /* clear error */
871     } /* end if */
872     else {
873         H5PL_get_plugin_info_t get_plugin_info = NULL;
874 
875         /* Return a handle for the function H5PLget_plugin_info in the dynamic library.
876          * The plugin library is suppose to define this function.
877          */
878         if(NULL == (get_plugin_info = (H5PL_get_plugin_info_t)H5PL_GET_LIB_FUNC(handle, "H5PLget_plugin_info"))) {
879             if(H5PL__close(handle) < 0)
880                 HGOTO_ERROR(H5E_PLUGIN, H5E_CLOSEERROR, FAIL, "can't close dynamic library")
881         } /* end if */
882         else {
883             const H5Z_class2_t *plugin_info;
884 
885             /* Invoke H5PLget_plugin_info to verify this is the right library we are looking for.
886              * Move on if it isn't.
887              */
888             if(NULL == (plugin_info = (const H5Z_class2_t *)(*get_plugin_info)())) {
889                 if(H5PL__close(handle) < 0)
890                     HGOTO_ERROR(H5E_PLUGIN, H5E_CLOSEERROR, FAIL, "can't close dynamic library")
891                 HGOTO_ERROR(H5E_PLUGIN, H5E_CANTGET, FAIL, "can't get plugin info")
892             } /* end if */
893 
894             /* Successfully found plugin library, check if it's the right one */
895             if(plugin_info->id == pl_id) {
896                 /* Expand the table if it is too small */
897                 if(H5PL_table_used_g >= H5PL_table_alloc_g) {
898                     size_t n = MAX(H5Z_MAX_NFILTERS, 2 * H5PL_table_alloc_g);
899                     H5PL_table_t *table = (H5PL_table_t *)H5MM_realloc(H5PL_table_g, n * sizeof(H5PL_table_t));
900 
901                     if(!table)
902                         HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "unable to extend dynamic library table")
903 
904                     H5PL_table_g = table;
905                     H5PL_table_alloc_g = n;
906                 } /* end if */
907 
908                 (H5PL_table_g[H5PL_table_used_g]).handle = handle;
909                 (H5PL_table_g[H5PL_table_used_g]).pl_type = pl_type;
910                 (H5PL_table_g[H5PL_table_used_g]).pl_id = plugin_info->id;
911                 H5PL_table_used_g++;
912 
913                 /* Set the plugin info to return */
914                 *pl_info = (const void *)plugin_info;
915 
916                 /* Indicate success */
917                 ret_value = TRUE;
918             } /* end if */
919             else
920                 if(H5PL__close(handle) < 0)
921                     HGOTO_ERROR(H5E_PLUGIN, H5E_CLOSEERROR, FAIL, "can't close dynamic library")
922         } /* end if */
923     } /* end else */
924 
925 done:
926     FUNC_LEAVE_NOAPI(ret_value)
927 } /* end H5PL__open() */
928 
929 
930 /*-------------------------------------------------------------------------
931  * Function:    H5PL__search_table
932  *
933  * Purpose:     Search in the list of already opened dynamic libraries
934  *              to see if the one we are looking for is already opened.
935  *
936  * Return:      TRUE on success,
937  *              FALSE on not found,
938  *              Negative on failure
939  *
940  * Programmer:  Raymond Lu
941  *              13 February 2013
942  *
943  *-------------------------------------------------------------------------
944  */
945 static htri_t
946 H5PL__search_table(H5PL_type_t plugin_type, int type_id, const void **info)
947 {
948     htri_t         ret_value = FALSE;
949 
950     FUNC_ENTER_STATIC
951 
952     /* Search in the table of already opened dynamic libraries */
953     if(H5PL_table_used_g > 0) {
954         size_t         i;
955 
956         for(i = 0; i < H5PL_table_used_g; i++) {
957             if((plugin_type == (H5PL_table_g[i]).pl_type) && (type_id == (H5PL_table_g[i]).pl_id)) {
958                 H5PL_get_plugin_info_t get_plugin_info;
959                 const H5Z_class2_t   *plugin_info;
960 
961                 if(NULL == (get_plugin_info = (H5PL_get_plugin_info_t)H5PL_GET_LIB_FUNC((H5PL_table_g[i]).handle, "H5PLget_plugin_info")))
962                     HGOTO_ERROR(H5E_DATATYPE, H5E_CANTGET, FAIL, "can't get function for H5PLget_plugin_info")
963 
964                 if(NULL == (plugin_info = (const H5Z_class2_t *)(*get_plugin_info)()))
965                     HGOTO_ERROR(H5E_DATATYPE, H5E_CANTGET, FAIL, "can't get plugin info")
966 
967                 *info = plugin_info;
968                 HGOTO_DONE(TRUE)
969             } /* end if */
970         } /* end for */
971     } /* end if */
972 
973 done:
974     FUNC_LEAVE_NOAPI(ret_value)
975 } /* end H5PL__search_table() */
976 
977 
978 /*-------------------------------------------------------------------------
979  * Function:    H5PL__close
980  *
981  * Purpose:     Closes the handle for dynamic library
982  *
983  * Return:      Non-negative on success/Negative on failure
984  *
985  * Programmer:  Raymond Lu
986  *              13 February 2013
987  *
988  *-------------------------------------------------------------------------
989  */
990 static herr_t
991 H5PL__close(H5PL_HANDLE handle)
992 {
993     FUNC_ENTER_STATIC_NOERR
994 
995     H5PL_CLOSE_LIB(handle);
996 
997     FUNC_LEAVE_NOAPI(SUCCEED)
998 } /* end H5PL__close() */
999