Coverage Report

Created: 2025-10-28 07:06

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/netcdf-c/libdispatch/dplugins.c
Line
Count
Source
1
/*
2
 * Copyright 2018, University Corporation for Atmospheric Research
3
 * See netcdf/COPYRIGHT file for copying and redistribution conditions.
4
 */
5
6
/**************************************************/
7
/* Global state plugin path implementation */
8
9
/**
10
 * @file
11
 * Functions for working with plugins. 
12
 */
13
14
#include "config.h"
15
#include <stdlib.h>
16
#include <stdio.h>
17
#include <string.h>
18
#ifdef _MSC_VER
19
#include <io.h>
20
#endif
21
22
#include "netcdf.h"
23
#include "netcdf_filter.h"
24
#include "ncdispatch.h"
25
#include "nc4internal.h"
26
#include "nclog.h"
27
#include "ncbytes.h"
28
#include "ncplugins.h"
29
#include "netcdf_aux.h"
30
31
/*
32
Unified plugin related code
33
*/
34
/**************************************************/
35
/* Plugin-path API */ 
36
37
/* list of environment variables to check for plugin roots */
38
1
#define PLUGIN_ENV "HDF5_PLUGIN_PATH"
39
40
/* Control path verification */
41
1
#define PLUGINPATHVERIFY "NC_PLUGIN_PATH_VERIFY"
42
43
/*Forward*/
44
static int buildinitialpluginpath(NCPluginList* dirs);
45
46
static int NC_plugin_path_initialized = 0;
47
static int NC_plugin_path_verify = 1;
48
49
/**
50
 * This function is called as part of nc_initialize.
51
 * Its purpose is to initialize the plugin paths state.
52
 *
53
 * @return NC_NOERR
54
 *
55
 * @author Dennis Heimbigner
56
*/
57
58
EXTERNL int
59
nc_plugin_path_initialize(void)
60
1
{
61
1
    int stat = NC_NOERR;
62
1
    struct NCglobalstate* gs = NULL;
63
1
    NCPluginList dirs = {0,NULL};
64
#ifdef USE_HDF5
65
    int hdf5found = 0; /* 1 => we got a legit plugin path set from HDF5 */
66
#endif
67
68
1
    if(!NC_initialized) nc_initialize();
69
1
    if(NC_plugin_path_initialized != 0) goto done;
70
1
    NC_plugin_path_initialized = 1;
71
72
1
    if(getenv(PLUGINPATHVERIFY) != NULL) NC_plugin_path_verify = 1;
73
74
1
    gs = NC_getglobalstate();
75
76
   /**
77
    * When the netcdf-c library initializes itself (at runtime), it chooses an
78
    * initial global plugin path using the following rules, which are those used
79
    * by the HDF5 library, except as modified for plugin install (which HDF5 does not support).
80
    */
81
82
    /* Initialize the implementations */
83
#ifdef NETCDF_ENABLE_NCZARR_FILTERS
84
    if((stat = NCZ_plugin_path_initialize())) goto done;    
85
#endif
86
#ifdef USE_HDF5
87
    if((stat = NC4_hdf5_plugin_path_initialize())) goto done;
88
#endif
89
90
    /* Compute the initial global plugin path */
91
1
    assert(dirs.ndirs == 0 && dirs.dirs == NULL);
92
1
    if((stat = buildinitialpluginpath(&dirs))) goto done; /* Construct a default */
93
94
    /* Sync to the actual implementations */
95
#ifdef USE_HDF5
96
    if(!hdf5found)
97
  {if((stat = NC4_hdf5_plugin_path_set(&dirs))) goto done;}
98
#endif
99
#ifdef NETCDF_ENABLE_NCZARR_FILTERS
100
    if((stat = NCZ_plugin_path_set(&dirs))) goto done;
101
#endif
102
    /* Set the global plugin dirs sequence */
103
1
    assert(gs->pluginpaths == NULL);
104
1
    gs->pluginpaths = nclistnew();
105
1
    if(dirs.ndirs > 0) {
106
1
  size_t i;
107
1
  char** dst;
108
1
        nclistsetlength(gs->pluginpaths,dirs.ndirs);
109
1
  dst = (char**)nclistcontents(gs->pluginpaths);
110
1
  assert(dst != NULL);
111
3
  for(i=0;i<dirs.ndirs;i++)
112
2
      dst[i] = strdup(dirs.dirs[i]);
113
1
    }
114
1
done:
115
1
    ncaux_plugin_path_clear(&dirs);
116
1
    return NCTHROW(stat);
117
1
}
118
119
/**
120
 * This function is called as part of nc_finalize()
121
 * Its purpose is to clean-up plugin path state.
122
 *
123
 * @return NC_NOERR
124
 *
125
 * @author Dennis Heimbigner
126
*/
127
128
int
129
nc_plugin_path_finalize(void)
130
1
{
131
1
    int stat = NC_NOERR;
132
1
    struct NCglobalstate* gs = NC_getglobalstate();
133
134
1
    if(NC_plugin_path_initialized == 0) goto done;
135
1
    NC_plugin_path_initialized = 0;
136
137
1
    NC_plugin_path_verify = 0;
138
139
    /* Finalize the actual implementatios */
140
#ifdef NETCDF_ENABLE_NCZARR_FILTERS
141
    if((stat = NCZ_plugin_path_finalize())) goto done;    
142
#endif
143
#ifdef USE_HDF5
144
    if((stat = NC4_hdf5_plugin_path_finalize())) goto done;
145
#endif
146
147
1
    nclistfreeall(gs->pluginpaths); gs->pluginpaths = NULL;
148
1
done:
149
1
    return NCTHROW(stat);
150
1
}
151
152
/**
153
 * Return the length of the current sequence of directories
154
 * in the internal global plugin path list.
155
 * @param ndirsp length is returned here
156
 * @return NC_NOERR | NC_EXXX
157
 *
158
 * @author Dennis Heimbigner
159
 */
160
161
int
162
nc_plugin_path_ndirs(size_t* ndirsp)
163
0
{
164
0
    int stat = NC_NOERR;
165
0
    size_t ndirs = 0;
166
0
    struct NCglobalstate* gs = NC_getglobalstate();
167
168
0
    if(gs->pluginpaths == NULL) gs->pluginpaths = nclistnew(); /* suspenders and belt */
169
0
    ndirs = nclistlength(gs->pluginpaths);
170
171
    /* Verify that the implementation plugin paths are consistent in length*/
172
0
    if(NC_plugin_path_verify) {
173
#ifdef NETCDF_ENABLE_HDF5
174
  {
175
      size_t ndirs5 = 0;
176
      if((stat=NC4_hdf5_plugin_path_ndirs(&ndirs5))) goto done;
177
      assert(ndirs5 == ndirs);
178
  }
179
#endif /*NETCDF_ENABLE_HDF5*/
180
#ifdef NETCDF_ENABLE_NCZARR_FILTERS
181
  {
182
      size_t ndirsz = 0;
183
      if((stat=NCZ_plugin_path_ndirs(&ndirsz))) goto done;
184
      assert(ndirsz == ndirs);
185
        }
186
#endif /*NETCDF_ENABLE_NCZARR_FILTERS*/
187
0
    }
188
0
    if(ndirsp) *ndirsp = ndirs;
189
0
done:
190
0
    return NCTHROW(stat);
191
0
}
192
193
/**
194
 * Return the current sequence of directories in the internal global
195
 * plugin path list. Since this function does not modify the plugin path,
196
 * it can be called at any time.
197
 * @param dirs pointer to an NCPluginList object
198
 * @return NC_NOERR | NC_EXXX
199
 * @author Dennis Heimbigner
200
 *
201
 * WARNING: if dirs->dirs is NULL, then space for the directory
202
 * vector will be allocated. If not NULL, then the specified space will
203
 * be overwritten with the vector.
204
 *
205
 * @author: Dennis Heimbigner
206
*/
207
208
int
209
nc_plugin_path_get(NCPluginList* dirs)
210
0
{
211
0
    int stat = NC_NOERR;
212
0
    struct NCglobalstate* gs = NC_getglobalstate();
213
0
    size_t i;
214
215
0
    if(gs->pluginpaths == NULL) gs->pluginpaths = nclistnew(); /* suspenders and belt */
216
0
    if(dirs == NULL) goto done;
217
0
    dirs->ndirs = nclistlength(gs->pluginpaths);
218
0
    if(dirs->ndirs > 0 && dirs->dirs == NULL) {
219
0
  if((dirs->dirs = (char**)calloc(dirs->ndirs,sizeof(char*)))==NULL)
220
0
      {stat = NC_ENOMEM; goto done;}
221
0
    }
222
0
    for(i=0;i<dirs->ndirs;i++) {
223
0
  const char* dir = nclistget(gs->pluginpaths,i);
224
0
  dirs->dirs[i] = nulldup(dir);
225
0
    }
226
227
    /* Verify that the implementation plugin paths are consistent */
228
0
    if(NC_plugin_path_verify) {
229
#ifdef NETCDF_ENABLE_HDF5
230
  {
231
      size_t i;
232
      NCPluginList l5 = {0,NULL};
233
      if((stat=NC4_hdf5_plugin_path_get(&l5))) goto done;
234
      assert(l5.ndirs == nclistlength(gs->pluginpaths));
235
      for(i=0;i<l5.ndirs;i++) {
236
    assert(strcmp(dirs->dirs[i],l5.dirs[i])==0);
237
    nullfree(l5.dirs[i]);
238
      }
239
      nullfree(l5.dirs);
240
  }
241
#endif /*NETCDF_ENABLE_HDF5*/
242
#ifdef NETCDF_ENABLE_NCZARR_FILTERS
243
  {
244
      size_t i;
245
      NCPluginList lz = {0,NULL};
246
      if((stat=NCZ_plugin_path_get(&lz))) goto done;
247
      assert(lz.ndirs == nclistlength(gs->pluginpaths));
248
      for(i=0;i<lz.ndirs;i++) {
249
    assert(strcmp(dirs->dirs[i],lz.dirs[i])==0);
250
    nullfree(lz.dirs[i]);
251
      }
252
      nullfree(lz.dirs);
253
        }
254
#endif /*NETCDF_ENABLE_NCZARR_FILTERS*/
255
0
    }
256
0
done:
257
0
    return NCTHROW(stat);
258
0
}
259
260
/**
261
 * Empty the current internal path sequence
262
 * and replace with the sequence of directories argument.
263
 * Using a dirs->ndirs argument of 0 will clear the set of plugin dirs.
264
 *
265
 * @param dirs to overwrite the current internal dir list
266
 * @return NC_NOERR | NC_EXXX
267
 *
268
 * @author Dennis Heimbigner
269
*/
270
int
271
nc_plugin_path_set(NCPluginList* dirs)
272
0
{
273
0
    int stat = NC_NOERR;
274
0
    struct NCglobalstate* gs = NC_getglobalstate();
275
276
0
    if(dirs == NULL) {stat = NC_EINVAL; goto done;}
277
278
    /* Clear the current dir list */
279
0
    nclistfreeall(gs->pluginpaths);
280
0
    gs->pluginpaths = nclistnew();
281
282
0
    if(dirs->ndirs > 0) {
283
0
  size_t i;
284
0
        assert(gs->pluginpaths != NULL);
285
0
  for(i=0;i<dirs->ndirs;i++) {
286
0
      nclistpush(gs->pluginpaths,nulldup(dirs->dirs[i]));
287
0
  }
288
0
    }
289
290
    /* Sync the global plugin path set to the individual implementations */
291
#ifdef NETCDF_ENABLE_HDF5
292
    if((stat = NC4_hdf5_plugin_path_set(dirs))) goto done;
293
#endif
294
#ifdef NETCDF_ENABLE_NCZARR_FILTERS
295
    if((stat = NCZ_plugin_path_set(dirs))) goto done;
296
#endif
297
298
0
done:
299
0
    return NCTHROW(stat);
300
0
}
301
302
/**
303
 * When the netcdf-c library initializes itself (at runtime), it chooses an
304
 * initial global plugin path using the following rules, which are those used
305
 * by the HDF5 library, except as modified for plugin install (which HDF5 does not support).
306
 *
307
 * Note: In the following, PLATFORMPATH is:
308
 * -- /usr/local/lhdf5/lib/plugin if platform is *nix*
309
 * -- %ALLUSERSPROFILE%/hdf5/lib/plugin if platform is Windows or Mingw
310
 * and in the following, PLATFORMSEP is:
311
 * -- ":" if platform is *nix*
312
 * -- ";" if platform is Windows or Mingw
313
 * and
314
 *     NETCDF_PLUGIN_SEARCH_PATH is the value constructed at build-time (see configure.ac)
315
 *
316
 * Table showing the computation of the initial global plugin path
317
 * =================================================
318
 * | HDF5_PLUGIN_PATH | Initial global plugin path |
319
 * =================================================
320
 * | undefined        | NETCDF_PLUGIN_SEARCH_PATH  |
321
 * -------------------------------------------------
322
 * | <path1;...pathn> | <path1;...pathn>           |
323
 * -------------------------------------------------
324
 */
325
static int
326
buildinitialpluginpath(NCPluginList* dirs)
327
1
{
328
1
    int stat = NC_NOERR;
329
1
    const char* hdf5path = NULL;
330
    /* Find the plugin directory root(s) */
331
1
    hdf5path = getenv(PLUGIN_ENV); /* HDF5_PLUGIN_PATH */
332
1
    if(hdf5path == NULL) {
333
  /* Use NETCDF_PLUGIN_SEARCH_PATH */
334
1
  hdf5path = NETCDF_PLUGIN_SEARCH_PATH;
335
1
    }
336
1
    if((stat = ncaux_plugin_path_parse(hdf5path,'\0',dirs))) goto done;
337
338
1
done:
339
1
    return stat;
340
1
}