Coverage Report

Created: 2025-10-28 07:06

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/netcdf-c/libdispatch/ddispatch.c
Line
Count
Source
1
/*
2
Copyright (c) 1998-2018 University Corporation for Atmospheric Research/Unidata
3
See LICENSE.txt for license information.
4
*/
5
6
#include "config.h"
7
#include "ncdispatch.h"
8
#include "ncuri.h"
9
#include "nclog.h"
10
#include "ncbytes.h"
11
#include "ncrc.h"
12
#include "ncoffsets.h"
13
#include "ncpathmgr.h"
14
#include "ncxml.h"
15
#include "nc4internal.h"
16
17
/* Required for getcwd, other functions. */
18
#ifdef HAVE_UNISTD_H
19
#include <unistd.h>
20
#endif
21
22
/* Required for getcwd, other functions. */
23
#ifdef _WIN32
24
#include <direct.h>
25
#endif
26
27
#if defined(NETCDF_ENABLE_BYTERANGE) || defined(NETCDF_ENABLE_DAP) || defined(NETCDF_ENABLE_DAP4)
28
#include <curl/curl.h>
29
#endif
30
31
#ifdef NETCDF_ENABLE_S3
32
#include "ncs3sdk.h"
33
#endif
34
35
0
#define MAXPATH 1024
36
37
/* Define vectors of zeros and ones for use with various nc_get_varX functions */
38
/* Note, this form of initialization fails under Cygwin */
39
size_t NC_coord_zero[NC_MAX_VAR_DIMS] = {0};
40
size_t NC_coord_one[NC_MAX_VAR_DIMS] = {1};
41
ptrdiff_t NC_stride_one[NC_MAX_VAR_DIMS] = {1};
42
43
/*
44
static nc_type longtype = (sizeof(long) == sizeof(int)?NC_INT:NC_INT64);
45
static nc_type ulongtype = (sizeof(unsigned long) == sizeof(unsigned int)?NC_UINT:NC_UINT64);
46
*/
47
48
/* Allow dispatch to do general initialization and finalization */
49
int
50
NCDISPATCH_initialize(void)
51
1
{
52
1
    int status = NC_NOERR;
53
1
    int i;
54
1
    NCglobalstate* globalstate = NULL;
55
56
1.02k
    for(i=0;i<NC_MAX_VAR_DIMS;i++) {
57
1.02k
        NC_coord_zero[i] = 0;
58
1.02k
        NC_coord_one[i]  = 1;
59
1.02k
        NC_stride_one[i] = 1;
60
1.02k
    }
61
62
1
    globalstate = NC_getglobalstate(); /* will allocate and clear */
63
64
    /* Capture temp dir*/
65
1
    {
66
1
  char* tempdir = NULL;
67
#if defined _WIN32 || defined __MSYS__ || defined __CYGWIN__
68
        tempdir = getenv("TEMP");
69
#else
70
1
  tempdir = "/tmp";
71
1
#endif
72
1
        if(tempdir == NULL) {
73
0
      fprintf(stderr,"Cannot find a temp dir; using ./\n");
74
0
      tempdir = ".";
75
0
  }
76
1
  globalstate->tempdir= strdup(tempdir);
77
1
    }
78
79
    /* Capture $HOME */
80
1
    {
81
#if defined(_WIN32) && !defined(__MINGW32__)
82
        char* home = getenv("USERPROFILE");
83
#else
84
1
        char* home = getenv("HOME");
85
1
#endif
86
1
        if(home == NULL) {
87
      /* use cwd */
88
0
      home = malloc(MAXPATH+1);
89
0
      NCgetcwd(home,MAXPATH);
90
0
        } else
91
1
      home = strdup(home); /* make it always free'able */
92
1
  assert(home != NULL);
93
1
        NCpathcanonical(home,&globalstate->home);
94
1
  nullfree(home);
95
1
    }
96
 
97
    /* Capture $CWD */
98
1
    {
99
1
        char cwdbuf[4096];
100
101
1
        cwdbuf[0] = '\0';
102
1
  (void)NCgetcwd(cwdbuf,sizeof(cwdbuf));
103
104
1
        if(strlen(cwdbuf) == 0) {
105
      /* use tempdir */
106
0
      strcpy(cwdbuf, globalstate->tempdir);
107
0
  }
108
1
        globalstate->cwd = strdup(cwdbuf);
109
1
    }
110
111
1
    ncloginit();
112
113
    /* Now load RC Files */
114
1
    ncrc_initialize();
115
116
    /* Compute type alignments */
117
1
    NC_compute_alignments();
118
119
#if defined(NETCDF_ENABLE_BYTERANGE) || defined(NETCDF_ENABLE_DAP) || defined(NETCDF_ENABLE_DAP4)
120
    /* Initialize curl if it is being used */
121
    {
122
        CURLcode cstat = curl_global_init(CURL_GLOBAL_ALL);
123
  if(cstat != CURLE_OK)
124
      status = NC_ECURL;
125
    }
126
#endif
127
128
1
    return status;
129
1
}
130
131
int
132
NCDISPATCH_finalize(void)
133
1
{
134
1
    int status = NC_NOERR;
135
#if defined(NETCDF_ENABLE_BYTERANGE) || defined(NETCDF_ENABLE_DAP) || defined(NETCDF_ENABLE_DAP4)
136
    curl_global_cleanup();
137
#endif
138
#if defined(NETCDF_ENABLE_DAP4)
139
   ncxml_finalize();
140
#endif
141
1
    NC_freeglobalstate(); /* should be one of the last things done */
142
1
    return status;
143
1
}
144
145
/**************************************************/
146
/* Global State constants and state */
147
148
/* The singleton global state object */
149
static NCglobalstate* nc_globalstate = NULL;
150
151
/* Forward */
152
static int NC_createglobalstate(void);
153
154
/** \defgroup global_state Global state functions. */
155
/** \{
156
157
\ingroup global_state
158
*/
159
160
/* NCglobal state management */
161
162
static int
163
NC_createglobalstate(void)
164
1
{
165
1
    int stat = NC_NOERR;
166
1
    const char* tmp = NULL;
167
    
168
1
    if(nc_globalstate == NULL) {
169
1
        nc_globalstate = calloc(1,sizeof(NCglobalstate));
170
1
    }
171
    /* Initialize struct pointers */
172
1
    if((nc_globalstate->rcinfo = calloc(1,sizeof(struct NCRCinfo)))==NULL)
173
0
            {stat = NC_ENOMEM; goto done;}
174
1
    if((nc_globalstate->rcinfo->entries = nclistnew())==NULL)
175
0
            {stat = NC_ENOMEM; goto done;}
176
1
    if((nc_globalstate->rcinfo->s3profiles = nclistnew())==NULL)
177
0
            {stat = NC_ENOMEM; goto done;}
178
179
    /* Get environment variables */
180
1
    if(getenv(NCRCENVIGNORE) != NULL)
181
0
        nc_globalstate->rcinfo->ignore = 1;
182
1
    tmp = getenv(NCRCENVRC);
183
1
    if(tmp != NULL && strlen(tmp) > 0)
184
0
        nc_globalstate->rcinfo->rcfile = strdup(tmp);
185
    /* Initialize chunk cache defaults */
186
1
    nc_globalstate->chunkcache.size = DEFAULT_CHUNK_CACHE_SIZE;       /**< Default chunk cache size. */
187
1
    nc_globalstate->chunkcache.nelems = DEFAULT_CHUNKS_IN_CACHE;     /**< Default chunk cache number of elements. */
188
1
    nc_globalstate->chunkcache.preemption = DEFAULT_CHUNK_CACHE_PREEMPTION; /**< Default chunk cache preemption. */
189
    
190
1
done:
191
1
    return stat;
192
1
}
193
194
/* Get global state */
195
NCglobalstate*
196
NC_getglobalstate(void)
197
11
{
198
11
    if(nc_globalstate == NULL)
199
1
        NC_createglobalstate();
200
11
    return nc_globalstate;
201
11
}
202
203
void
204
NC_freeglobalstate(void)
205
1
{
206
1
    if(nc_globalstate != NULL) {
207
1
        nullfree(nc_globalstate->tempdir);
208
1
        nullfree(nc_globalstate->home);
209
1
        nullfree(nc_globalstate->cwd);
210
1
  nullfree(nc_globalstate->aws.default_region);
211
1
  nullfree(nc_globalstate->aws.config_file);
212
1
  nullfree(nc_globalstate->aws.profile);
213
1
  nullfree(nc_globalstate->aws.access_key_id);
214
1
  nullfree(nc_globalstate->aws.secret_access_key);
215
1
        if(nc_globalstate->rcinfo) {
216
1
      NC_rcclear(nc_globalstate->rcinfo);
217
1
      free(nc_globalstate->rcinfo);
218
1
  }
219
1
  nclistfree(nc_globalstate->pluginpaths);
220
1
  free(nc_globalstate);
221
1
  nc_globalstate = NULL;
222
1
    }
223
1
}
224
225
/** \} */
226
227
/**************************************************/
228
/** \defgroup atomic_types Atomic Type functions */
229
/** \{
230
231
\ingroup atomic_types
232
*/
233
234
/* The sizes of types may vary from platform to platform, but within
235
 * netCDF files, type sizes are fixed. */
236
#define NC_CHAR_LEN sizeof(char)      /**< @internal Size of char. */
237
#define NC_STRING_LEN sizeof(char *)  /**< @internal Size of char *. */
238
#define NC_BYTE_LEN 1     /**< @internal Size of byte. */
239
#define NC_SHORT_LEN 2    /**< @internal Size of short. */
240
#define NC_INT_LEN 4      /**< @internal Size of int. */
241
#define NC_FLOAT_LEN 4    /**< @internal Size of float. */
242
#define NC_DOUBLE_LEN 8   /**< @internal Size of double. */
243
#define NC_INT64_LEN 8    /**< @internal Size of int64. */
244
245
/** @internal Names of atomic types. */
246
const char* nc4_atomic_name[NUM_ATOMIC_TYPES] = {"none", "byte", "char",
247
                                           "short", "int", "float",
248
                                           "double", "ubyte",
249
                                           "ushort", "uint",
250
                                           "int64", "uint64", "string"};
251
static const size_t nc4_atomic_size[NUM_ATOMIC_TYPES] = {0, NC_BYTE_LEN, NC_CHAR_LEN, NC_SHORT_LEN,
252
                                                      NC_INT_LEN, NC_FLOAT_LEN, NC_DOUBLE_LEN,
253
                                                      NC_BYTE_LEN, NC_SHORT_LEN, NC_INT_LEN, NC_INT64_LEN,
254
                                                      NC_INT64_LEN, NC_STRING_LEN};
255
256
/**
257
 * @internal Get the name and size of an atomic type. For strings, 1 is
258
 * returned.
259
 *
260
 * @param typeid1 Type ID.
261
 * @param name Gets the name of the type.
262
 * @param size Gets the size of one element of the type in bytes.
263
 *
264
 * @return ::NC_NOERR No error.
265
 * @return ::NC_EBADID Bad ncid.
266
 * @return ::NC_EBADTYPE Type not found.
267
 * @author Dennis Heimbigner
268
 */
269
int
270
NC4_inq_atomic_type(nc_type typeid1, char *name, size_t *size)
271
0
{
272
0
    if (typeid1 >= NUM_ATOMIC_TYPES)
273
0
  return NC_EBADTYPE;
274
0
    if (name)
275
0
            strcpy(name, nc4_atomic_name[typeid1]);
276
0
    if (size)
277
0
            *size = nc4_atomic_size[typeid1];
278
0
    return NC_NOERR;
279
0
}
280
281
/**
282
 * @internal Get the id and size of an atomic type by name.
283
 *
284
 * @param name [in] the name of the type.
285
 * @param idp [out] the type index of the type.
286
 * @param sizep [out] the size of one element of the type in bytes.
287
 *
288
 * @return ::NC_NOERR No error.
289
 * @return ::NC_EBADID Bad ncid.
290
 * @return ::NC_EBADTYPE Type not found.
291
 * @author Dennis Heimbigner
292
 */
293
int
294
NC4_lookup_atomic_type(const char *name, nc_type* idp, size_t *sizep)
295
0
{
296
0
    int i;
297
298
0
    if (name == NULL || strlen(name) == 0)
299
0
  return NC_EBADTYPE;
300
0
    for(i=0;i<NUM_ATOMIC_TYPES;i++) {
301
0
  if(strcasecmp(name,nc4_atomic_name[i])==0) { 
302
0
      if(idp) *idp = i;
303
0
            if(sizep) *sizep = nc4_atomic_size[i];
304
0
      return NC_NOERR;
305
0
        }
306
0
    }
307
0
    return NC_EBADTYPE;
308
0
}
309
310
/**
311
 * @internal Get the id of an atomic type from the name.
312
 *
313
 * @param ncid File and group ID.
314
 * @param name Name of type
315
 * @param typeidp Pointer that will get the type ID.
316
 *
317
 * @return ::NC_NOERR No error.
318
 * @return ::NC_EBADTYPE Type not found.
319
 * @author Ed Hartnett
320
 */
321
int
322
NC4_inq_atomic_typeid(int ncid, const char *name, nc_type *typeidp)
323
0
{
324
0
    int i;
325
326
0
    NC_UNUSED(ncid);
327
328
    /* Handle atomic types. */
329
0
    for (i = 0; i < NUM_ATOMIC_TYPES; i++) {
330
0
        if (!strcmp(name, nc4_atomic_name[i]))
331
0
        {
332
0
            if (typeidp)
333
0
                *typeidp = i;
334
0
      return NC_NOERR;
335
0
        }
336
0
    }
337
0
    return NC_EBADTYPE;
338
0
}
339
340
/**
341
 * @internal Get the class of a type
342
 *
343
 * @param xtype NetCDF type ID.
344
 * @param type_class Pointer that gets class of type, NC_INT,
345
 * NC_FLOAT, NC_CHAR, or NC_STRING, NC_ENUM, NC_VLEN, NC_COMPOUND, or
346
 * NC_OPAQUE.
347
 *
348
 * @return ::NC_NOERR No error.
349
 * @author Ed Hartnett, Dennis Heimbigner
350
 */
351
int
352
NC4_get_atomic_typeclass(nc_type xtype, int *type_class)
353
0
{
354
0
    assert(type_class);
355
0
    switch (xtype) {
356
0
        case NC_BYTE:
357
0
        case NC_UBYTE:
358
0
        case NC_SHORT:
359
0
        case NC_USHORT:
360
0
        case NC_INT:
361
0
        case NC_UINT:
362
0
        case NC_INT64:
363
0
        case NC_UINT64:
364
            /* NC_INT is class used for all integral types */
365
0
            *type_class = NC_INT;
366
0
            break;
367
0
        case NC_FLOAT:
368
0
        case NC_DOUBLE:
369
            /* NC_FLOAT is class used for all floating-point types */
370
0
            *type_class = NC_FLOAT;
371
0
            break;
372
0
        case NC_CHAR:
373
0
            *type_class = NC_CHAR;
374
0
            break;
375
0
        case NC_STRING:
376
0
            *type_class = NC_STRING;
377
0
            break;
378
0
        default:
379
0
     return NC_EBADTYPE;
380
0
        }
381
0
    return NC_NOERR;
382
0
}
383
384
/** \} */
385
386
/**************************************************/
387
/** \defgroup alignment Alignment functions. */
388
389
/** \{
390
391
\ingroup alignment
392
*/
393
394
/**
395
Provide a function to store global data alignment
396
information.
397
Repeated calls to nc_set_alignment will overwrite any existing values.
398
399
If defined, then for every file created or opened after the call to
400
nc_set_alignment, and for every new variable added to the file, the
401
most recently set threshold and alignment values will be applied
402
to that variable.
403
404
The nc_set_alignment function causes new data written to a
405
netCDF-4 file to be aligned on disk to a specified block
406
size. To be effective, alignment should be the system disk block
407
size, or a multiple of it. This setting is effective with MPI
408
I/O and other parallel systems.
409
410
This is a trade-off of write speed versus file size. Alignment
411
leaves holes between file objects. The default of no alignment
412
writes file objects contiguously, without holes. Alignment has
413
no impact on file readability.
414
415
Alignment settings apply only indirectly, through the file open
416
functions. Call nc_set_alignment first, then nc_create or
417
nc_open for one or more files. Current alignment settings are
418
locked in when each file is opened, then forgotten when the same
419
file is closed. For illustration, it is possible to write
420
different files at the same time with different alignments, by
421
interleaving nc_set_alignment and nc_open calls.
422
423
Alignment applies to all newly written low-level file objects at
424
or above the threshold size, including chunks of variables,
425
attributes, and internal infrastructure. Alignment is not locked
426
in to a data variable. It can change between data chunks of the
427
same variable, based on a file's history.
428
429
Refer to H5Pset_alignment in HDF5 documentation for more
430
specific details, interactions, and additional rules.
431
432
@param threshold The minimum size to which alignment is applied.
433
@param alignment The alignment value.
434
435
@return ::NC_NOERR No error.
436
@return ::NC_EINVAL Invalid input.
437
@author Dennis Heimbigner
438
@ingroup datasets
439
*/
440
int
441
nc_set_alignment(int threshold, int alignment)
442
0
{
443
0
    NCglobalstate* gs = NC_getglobalstate();
444
0
    gs->alignment.threshold = threshold;
445
0
    gs->alignment.alignment = alignment;
446
0
    gs->alignment.defined = 1;
447
0
    return NC_NOERR;
448
0
}
449
450
/**
451
Provide get function to retrieve global data alignment
452
information.
453
454
The nc_get_alignment function return the last values set by
455
nc_set_alignment.  If nc_set_alignment has not been called, then
456
it returns the value 0 for both threshold and alignment.
457
458
@param thresholdp Return the current minimum size to which alignment is applied or zero.
459
@param alignmentp Return the current alignment value or zero.
460
461
@return ::NC_NOERR No error.
462
@return ::NC_EINVAL Invalid input.
463
@author Dennis Heimbigner
464
@ingroup datasets
465
*/
466
467
int
468
nc_get_alignment(int* thresholdp, int* alignmentp)
469
0
{
470
0
    NCglobalstate* gs = NC_getglobalstate();
471
0
    if(thresholdp) *thresholdp = gs->alignment.threshold;
472
0
    if(alignmentp) *alignmentp = gs->alignment.alignment;
473
0
    return NC_NOERR;
474
0
}
475
476
/** \} */