Coverage Report

Created: 2025-06-09 07:43

/src/gdal/netcdf-c-4.7.4/libhdf5/hdf5internal.c
Line
Count
Source (jump to first uncovered line)
1
/* Copyright 2003-2018, University Corporation for Atmospheric
2
 * Research. See the COPYRIGHT file for copying and redistribution
3
 * conditions.
4
 */
5
/**
6
 * @file @internal Internal netcdf-4 functions.
7
 *
8
 * This file contains functions internal to the netcdf4 library. None of
9
 * the functions in this file are exposed in the exetnal API. These
10
 * functions all relate to the manipulation of netcdf-4's in-memory
11
 * buffer of metadata information, i.e. the linked list of NC
12
 * structs.
13
 *
14
 * @author Ed Hartnett
15
 */
16
17
#include "config.h"
18
#include "hdf5internal.h"
19
20
#undef DEBUGH5
21
22
#ifdef DEBUGH5
23
/**
24
 * @internal Provide a catchable error reporting function
25
 *
26
 * @param ignored Ignored.
27
 *
28
 * @return 0 for success.
29
 */
30
static herr_t
31
h5catch(void* ignored)
32
{
33
    H5Eprint(NULL);
34
    return 0;
35
}
36
#endif
37
38
/* These are the default chunk cache sizes for HDF5 files created or
39
 * opened with netCDF-4. */
40
extern size_t nc4_chunk_cache_size;
41
extern size_t nc4_chunk_cache_nelems;
42
extern float nc4_chunk_cache_preemption;
43
44
#ifdef LOGGING
45
/* This is the severity level of messages which will be logged. Use
46
   severity 0 for errors, 1 for important log messages, 2 for less
47
   important, etc. */
48
extern int nc_log_level;
49
50
#endif /* LOGGING */
51
52
int nc4_hdf5_initialized = 0; /**< True if initialization has happened. */
53
54
/**
55
 * @internal Provide a wrapper for H5Eset_auto
56
 * @param func Pointer to func.
57
 * @param client_data Client data.
58
 *
59
 * @return 0 for success
60
 */
61
static herr_t
62
set_auto(void* func, void *client_data)
63
1
{
64
#ifdef DEBUGH5
65
    return H5Eset_auto2(H5E_DEFAULT,(H5E_auto2_t)h5catch,client_data);
66
#else
67
1
    return H5Eset_auto2(H5E_DEFAULT,(H5E_auto2_t)func,client_data);
68
1
#endif
69
1
}
70
71
/**
72
 * @internal Provide a function to do any necessary initialization of
73
 * the HDF5 library.
74
 */
75
void
76
nc4_hdf5_initialize(void)
77
1
{
78
1
    if (set_auto(NULL, NULL) < 0)
79
0
        LOG((0, "Couldn't turn off HDF5 error messages!"));
80
1
    LOG((1, "HDF5 error messages have been turned off."));
81
1
    nc4_hdf5_initialized = 1;
82
1
}
83
84
/**
85
 * @internal Provide a function to do any necessary finalization of
86
 * the HDF5 library.
87
 */
88
void
89
nc4_hdf5_finalize(void)
90
0
{
91
    /* Reclaim global resources */
92
0
    NC4_provenance_finalize();
93
0
    nc4_hdf5_initialized = 0;
94
0
}
95
96
/**
97
 * @internal Given a varid, return the maximum length of a dimension
98
 * using dimid.
99
 *
100
 * @param grp Pointer to group info struct.
101
 * @param varid Variable ID.
102
 * @param dimid Dimension ID.
103
 * @param maxlen Pointer that gets the max length.
104
 *
105
 * @return ::NC_NOERR No error.
106
 * @author Ed Hartnett
107
 */
108
static int
109
find_var_dim_max_length(NC_GRP_INFO_T *grp, int varid, int dimid,
110
                        size_t *maxlen)
111
254k
{
112
254k
    hid_t datasetid = 0, spaceid = 0;
113
254k
    NC_VAR_INFO_T *var;
114
254k
    hsize_t *h5dimlen = NULL, *h5dimlenmax = NULL;
115
254k
    int d, dataset_ndims = 0;
116
254k
    int retval = NC_NOERR;
117
118
254k
    *maxlen = 0;
119
120
    /* Find this var. */
121
254k
    var = (NC_VAR_INFO_T*)ncindexith(grp->vars,varid);
122
254k
    if (!var) return NC_ENOTVAR;
123
254k
    assert(var->hdr.id == varid);
124
125
    /* If the var hasn't been created yet, its size is 0. */
126
254k
    if (!var->created)
127
0
    {
128
0
        *maxlen = 0;
129
0
    }
130
254k
    else
131
254k
    {
132
        /* Get the number of records in the dataset. */
133
254k
        if ((retval = nc4_open_var_grp2(grp, var->hdr.id, &datasetid)))
134
0
            BAIL(retval);
135
254k
        if ((spaceid = H5Dget_space(datasetid)) < 0)
136
0
            BAIL(NC_EHDFERR);
137
138
        /* If it's a scalar dataset, it has length one. */
139
254k
        if (H5Sget_simple_extent_type(spaceid) == H5S_SCALAR)
140
150k
        {
141
150k
            *maxlen = (var->dimids && var->dimids[0] == dimid) ? 1 : 0;
142
150k
        }
143
104k
        else
144
104k
        {
145
            /* Check to make sure ndims is right, then get the len of each
146
               dim in the space. */
147
104k
            if ((dataset_ndims = H5Sget_simple_extent_ndims(spaceid)) < 0)
148
0
                BAIL(NC_EHDFERR);
149
104k
            if (dataset_ndims != var->ndims)
150
859
                BAIL(NC_EHDFERR);
151
103k
            if (!(h5dimlen = malloc(dataset_ndims * sizeof(hsize_t))))
152
0
                BAIL(NC_ENOMEM);
153
103k
            if (!(h5dimlenmax = malloc(dataset_ndims * sizeof(hsize_t))))
154
0
                BAIL(NC_ENOMEM);
155
103k
            if ((dataset_ndims = H5Sget_simple_extent_dims(spaceid,
156
103k
                                                           h5dimlen, h5dimlenmax)) < 0)
157
0
                BAIL(NC_EHDFERR);
158
103k
            LOG((5, "find_var_dim_max_length: varid %d len %d max: %d",
159
103k
                 varid, (int)h5dimlen[0], (int)h5dimlenmax[0]));
160
278k
            for (d=0; d<dataset_ndims; d++) {
161
174k
                if (var->dimids[d] == dimid) {
162
87.5k
                    *maxlen = *maxlen > h5dimlen[d] ? *maxlen : h5dimlen[d];
163
87.5k
                }
164
174k
            }
165
103k
        }
166
254k
    }
167
168
254k
exit:
169
254k
    if (spaceid > 0 && H5Sclose(spaceid) < 0)
170
0
        BAIL2(NC_EHDFERR);
171
254k
    if (h5dimlen) free(h5dimlen);
172
254k
    if (h5dimlenmax) free(h5dimlenmax);
173
254k
    return retval;
174
254k
}
175
176
/**
177
 * @internal Search for type with a given HDF type id.
178
 *
179
 * @param h5 File
180
 * @param target_hdf_typeid HDF5 type ID to find.
181
 *
182
 * @return Pointer to type info struct, or NULL if not found.
183
 * @author Ed Hartnett
184
 */
185
NC_TYPE_INFO_T *
186
nc4_rec_find_hdf_type(NC_FILE_INFO_T *h5, hid_t target_hdf_typeid)
187
0
{
188
0
    NC_TYPE_INFO_T *type;
189
0
    htri_t equal;
190
0
    int i;
191
192
0
    assert(h5);
193
194
0
    for (i = 0; i < nclistlength(h5->alltypes); i++)
195
0
    {
196
0
        NC_HDF5_TYPE_INFO_T *hdf5_type;
197
0
        hid_t hdf_typeid;
198
199
0
        type = (NC_TYPE_INFO_T*)nclistget(h5->alltypes, i);
200
0
        if(type == NULL) continue;
201
202
        /* Get HDF5-specific type info. */
203
0
        hdf5_type = (NC_HDF5_TYPE_INFO_T *)type->format_type_info;
204
205
        /* Select the HDF5 typeid to use. */
206
0
        hdf_typeid = hdf5_type->native_hdf_typeid ?
207
0
            hdf5_type->native_hdf_typeid : hdf5_type->hdf_typeid;
208
209
        /* Is this the type we are searching for? */
210
0
        if ((equal = H5Tequal(hdf_typeid, target_hdf_typeid)) < 0)
211
0
            return NULL;
212
0
        if (equal)
213
0
            return type;
214
0
    }
215
    /* Can't find it. Fate, why do you mock me? */
216
0
    return NULL;
217
0
}
218
219
/**
220
 * @internal Find the actual length of a dim by checking the length of
221
 * that dim in all variables that use it, in grp or children. **len
222
 * must be initialized to zero before this function is called.
223
 *
224
 * @param grp Pointer to group info struct.
225
 * @param dimid Dimension ID.
226
 * @param len Pointer to pointer that gets length.
227
 *
228
 * @return ::NC_NOERR No error.
229
 * @author Ed Hartnett
230
 */
231
int
232
nc4_find_dim_len(NC_GRP_INFO_T *grp, int dimid, size_t **len)
233
6.27k
{
234
6.27k
    NC_VAR_INFO_T *var;
235
6.27k
    int retval;
236
6.27k
    int i;
237
238
6.27k
    assert(grp && len);
239
6.27k
    LOG((3, "%s: grp->name %s dimid %d", __func__, grp->hdr.name, dimid));
240
241
    /* If there are any groups, call this function recursively on
242
     * them. */
243
6.27k
    for (i = 0; i < ncindexsize(grp->children); i++)
244
0
        if ((retval = nc4_find_dim_len((NC_GRP_INFO_T*)ncindexith(grp->children, i),
245
0
                                       dimid, len)))
246
0
            return retval;
247
248
    /* For all variables in this group, find the ones that use this
249
     * dimension, and remember the max length. */
250
260k
    for (i = 0; i < ncindexsize(grp->vars); i++)
251
254k
    {
252
254k
        size_t mylen;
253
254k
        var = (NC_VAR_INFO_T *)ncindexith(grp->vars, i);
254
254k
        assert(var);
255
256
        /* Find max length of dim in this variable... */
257
254k
        if ((retval = find_var_dim_max_length(grp, var->hdr.id, dimid, &mylen)))
258
859
            return retval;
259
260
254k
        **len = **len > mylen ? **len : mylen;
261
254k
    }
262
263
5.41k
    return NC_NOERR;
264
6.27k
}
265
266
/**
267
 * @internal Break a coordinate variable to separate the dimension and
268
 * the variable.
269
 *
270
 * This is called from nc_rename_dim() and nc_rename_var(). In some
271
 * renames, the coord variable must stay, but it is no longer a coord
272
 * variable. This function changes a coord var into an ordinary
273
 * variable.
274
 *
275
 * @param grp Pointer to group info struct.
276
 * @param coord_var Pointer to variable info struct.
277
 * @param dim Pointer to dimension info struct.
278
 *
279
 * @return ::NC_NOERR No error.
280
 * @return ::NC_ENOMEM Out of memory.
281
 * @author Quincey Koziol, Ed Hartnett
282
 */
283
int
284
nc4_break_coord_var(NC_GRP_INFO_T *grp, NC_VAR_INFO_T *coord_var,
285
                    NC_DIM_INFO_T *dim)
286
0
{
287
0
    int retval;
288
289
    /* Sanity checks */
290
0
    assert(grp && coord_var && dim && dim->coord_var == coord_var &&
291
0
           coord_var->dim[0] == dim && coord_var->dimids[0] == dim->hdr.id &&
292
0
           !((NC_HDF5_DIM_INFO_T *)(dim->format_dim_info))->hdf_dimscaleid);
293
0
    LOG((3, "%s dim %s was associated with var %s, but now has different name",
294
0
         __func__, dim->hdr.name, coord_var->hdr.name));
295
296
    /* If we're replacing an existing dimscale dataset, go to
297
     * every var in the file and detach this dimension scale. */
298
0
    if ((retval = rec_detach_scales(grp->nc4_info->root_grp,
299
0
                                    dim->hdr.id,
300
0
                                    ((NC_HDF5_VAR_INFO_T *)(coord_var->format_var_info))->hdf_datasetid)))
301
0
        return retval;
302
303
    /* Allow attached dimscales to be tracked on the [former]
304
     * coordinate variable */
305
0
    if (coord_var->ndims)
306
0
    {
307
        /* Coordinate variables shouldn't have dimscales attached. */
308
0
        assert(!coord_var->dimscale_attached);
309
310
        /* Allocate space for tracking them */
311
0
        if (!(coord_var->dimscale_attached = calloc(coord_var->ndims,
312
0
                                                    sizeof(nc_bool_t))))
313
0
            return NC_ENOMEM;
314
0
    }
315
316
    /* Detach dimension from variable */
317
0
    coord_var->dimscale = NC_FALSE;
318
0
    dim->coord_var = NULL;
319
320
    /* Set state transition indicators */
321
0
    coord_var->was_coord_var = NC_TRUE;
322
0
    coord_var->became_coord_var = NC_FALSE;
323
324
0
    return NC_NOERR;
325
0
}
326
327
/**
328
 * @internal Delete an existing dimscale-only dataset.
329
 *
330
 * A dimscale-only HDF5 dataset is created when a dim is defined
331
 * without an accompanying coordinate variable.
332
 *
333
 * Sometimes, during renames, or late creation of variables, an
334
 * existing, dimscale-only dataset must be removed. This means
335
 * detaching all variables that use the dataset, then closing and
336
 * unlinking it.
337
 *
338
 * @param grp The grp of the dimscale-only dataset to be deleted, or a
339
 * higher group in the hierarchy (ex. root group).
340
 * @param dimid id of the dimension
341
 * @param dim Pointer to the dim with the dimscale-only dataset to be
342
 * deleted.
343
 *
344
 * @return ::NC_NOERR No error.
345
 * @return ::NC_EHDFERR HDF5 error.
346
 * @author Ed Hartnett
347
 */
348
int
349
delete_dimscale_dataset(NC_GRP_INFO_T *grp, int dimid, NC_DIM_INFO_T *dim)
350
0
{
351
0
    NC_HDF5_DIM_INFO_T *hdf5_dim;
352
0
    NC_HDF5_GRP_INFO_T *hdf5_grp;
353
0
    int retval;
354
355
0
    assert(grp && grp->format_grp_info && dim && dim->format_dim_info);
356
0
    LOG((2, "%s: deleting dimscale dataset %s dimid %d", __func__, dim->hdr.name,
357
0
         dimid));
358
359
    /* Get HDF5 specific grp and dim info. */
360
0
    hdf5_dim = (NC_HDF5_DIM_INFO_T *)dim->format_dim_info;
361
0
    hdf5_grp = (NC_HDF5_GRP_INFO_T *)grp->format_grp_info;
362
363
    /* Detach dimscale from any variables using it */
364
0
    if ((retval = rec_detach_scales(grp, dimid, hdf5_dim->hdf_dimscaleid)) < 0)
365
0
        return retval;
366
367
    /* Close the HDF5 dataset */
368
0
    if (H5Dclose(hdf5_dim->hdf_dimscaleid) < 0)
369
0
        return NC_EHDFERR;
370
0
    hdf5_dim->hdf_dimscaleid = 0;
371
372
    /* Now delete the dataset. */
373
0
    if (H5Gunlink(hdf5_grp->hdf_grpid, dim->hdr.name) < 0)
374
0
        return NC_EHDFERR;
375
376
0
    return NC_NOERR;
377
0
}
378
379
/**
380
 * @internal Reform a coordinate variable from a dimension and a
381
 * variable.
382
 *
383
 * @param grp Pointer to group info struct.
384
 * @param var Pointer to variable info struct.
385
 * @param dim Pointer to dimension info struct.
386
 *
387
 * @return ::NC_NOERR No error.
388
 * @author Quincey Koziol, Ed Hartnett
389
 */
390
int
391
nc4_reform_coord_var(NC_GRP_INFO_T *grp, NC_VAR_INFO_T *var, NC_DIM_INFO_T *dim)
392
0
{
393
0
    NC_HDF5_DIM_INFO_T *hdf5_dim;
394
0
    NC_HDF5_GRP_INFO_T *hdf5_grp;
395
0
    NC_HDF5_VAR_INFO_T *hdf5_var;
396
0
    int need_to_reattach_scales = 0;
397
0
    int retval = NC_NOERR;
398
399
0
    assert(grp && grp->format_grp_info && var && var->format_var_info &&
400
0
           dim && dim->format_dim_info);
401
0
    LOG((3, "%s: dim->hdr.name %s var->hdr.name %s", __func__, dim->hdr.name,
402
0
         var->hdr.name));
403
404
    /* Get HDF5-specific dim, group, and var info. */
405
0
    hdf5_dim = (NC_HDF5_DIM_INFO_T *)dim->format_dim_info;
406
0
    hdf5_grp = (NC_HDF5_GRP_INFO_T *)grp->format_grp_info;
407
0
    hdf5_var = (NC_HDF5_VAR_INFO_T *)var->format_var_info;
408
409
    /* Detach dimscales from the [new] coordinate variable. */
410
0
    if (var->dimscale_attached)
411
0
    {
412
0
        int dims_detached = 0;
413
0
        int finished = 0;
414
0
        int d;
415
416
        /* Loop over all dimensions for variable. */
417
0
        for (d = 0; d < var->ndims && !finished; d++)
418
0
        {
419
            /* Is there a dimscale attached to this axis? */
420
0
            if (var->dimscale_attached[d])
421
0
            {
422
0
                NC_GRP_INFO_T *g;
423
0
                int k;
424
425
0
                for (g = grp; g && !finished; g = g->parent)
426
0
                {
427
0
                    NC_DIM_INFO_T *dim1;
428
0
                    NC_HDF5_DIM_INFO_T *hdf5_dim1;
429
430
0
                    for (k = 0; k < ncindexsize(g->dim); k++)
431
0
                    {
432
0
                        dim1 = (NC_DIM_INFO_T *)ncindexith(g->dim, k);
433
0
                        assert(dim1 && dim1->format_dim_info);
434
0
                        hdf5_dim1 = (NC_HDF5_DIM_INFO_T *)dim1->format_dim_info;
435
436
0
                        if (var->dimids[d] == dim1->hdr.id)
437
0
                        {
438
0
                            hid_t dim_datasetid;  /* Dataset ID for dimension */
439
440
                            /* Find dataset ID for dimension */
441
0
                            if (dim1->coord_var)
442
0
                                dim_datasetid = ((NC_HDF5_VAR_INFO_T *)
443
0
                                                 (dim1->coord_var->format_var_info))->hdf_datasetid;
444
0
                            else
445
0
                                dim_datasetid = hdf5_dim1->hdf_dimscaleid;
446
447
                            /* dim_datasetid may be 0 in some cases when
448
                             * renames of dims and vars are happening. In
449
                             * this case, the scale has already been
450
                             * detached. */
451
0
                            if (dim_datasetid > 0)
452
0
                            {
453
0
                                LOG((3, "detaching scale from %s", var->hdr.name));
454
0
                                if (H5DSdetach_scale(hdf5_var->hdf_datasetid,
455
0
                                                     dim_datasetid, d) < 0)
456
0
                                    BAIL(NC_EHDFERR);
457
0
                            }
458
0
                            var->dimscale_attached[d] = NC_FALSE;
459
0
                            if (dims_detached++ == var->ndims)
460
0
                                finished++;
461
0
                        }
462
0
                    }
463
0
                }
464
0
            }
465
0
        } /* next variable dimension */
466
467
        /* Release & reset the array tracking attached dimscales. */
468
0
        free(var->dimscale_attached);
469
0
        var->dimscale_attached = NULL;
470
0
        need_to_reattach_scales++;
471
0
    }
472
473
    /* Use variable's dataset ID for the dimscale ID. */
474
0
    if (hdf5_dim->hdf_dimscaleid && grp != NULL)
475
0
    {
476
0
        LOG((3, "closing and unlinking dimscale dataset %s", dim->hdr.name));
477
0
        if (H5Dclose(hdf5_dim->hdf_dimscaleid) < 0)
478
0
            BAIL(NC_EHDFERR);
479
0
        hdf5_dim->hdf_dimscaleid = 0;
480
481
        /* Now delete the dimscale's dataset (it will be recreated
482
           later, if necessary). */
483
0
        if (H5Gunlink(hdf5_grp->hdf_grpid, dim->hdr.name) < 0)
484
0
            return NC_EDIMMETA;
485
0
    }
486
487
    /* Attach variable to dimension. */
488
0
    var->dimscale = NC_TRUE;
489
0
    dim->coord_var = var;
490
491
    /* Check if this variable used to be a coord. var */
492
0
    if (need_to_reattach_scales || (var->was_coord_var && grp != NULL))
493
0
    {
494
        /* Reattach the scale everywhere it is used. (Recall that netCDF
495
         * dimscales are always 1-D) */
496
0
        if ((retval = rec_reattach_scales(grp->nc4_info->root_grp,
497
0
                                          var->dimids[0], hdf5_var->hdf_datasetid)))
498
0
            return retval;
499
500
        /* Set state transition indicator (cancels earlier
501
         * transition). */
502
0
        var->was_coord_var = NC_FALSE;
503
0
    }
504
505
    /* Set state transition indicator */
506
0
    var->became_coord_var = NC_TRUE;
507
508
0
exit:
509
0
    return retval;
510
0
}
511
512
/**
513
 * @internal Close HDF5 resources for global atts in a group.
514
 *
515
 * @param grp Pointer to group info struct.
516
 *
517
 * @return ::NC_NOERR No error.
518
 * @return ::NC_EHDFERR HDF5 error.
519
 * @author Ed Hartnett
520
 */
521
static int
522
close_gatts(NC_GRP_INFO_T *grp)
523
1.35k
{
524
1.35k
    NC_ATT_INFO_T *att;
525
1.35k
    int a;
526
527
3.72k
    for (a = 0; a < ncindexsize(grp->att); a++)
528
2.36k
    {
529
2.36k
        NC_HDF5_ATT_INFO_T *hdf5_att;
530
531
2.36k
        att = (NC_ATT_INFO_T *)ncindexith(grp->att, a);
532
2.36k
        assert(att && att->format_att_info);
533
2.36k
        hdf5_att = (NC_HDF5_ATT_INFO_T *)att->format_att_info;
534
535
        /* Close the HDF5 typeid. */
536
2.36k
        if (hdf5_att->native_hdf_typeid &&
537
2.36k
            H5Tclose(hdf5_att->native_hdf_typeid) < 0)
538
0
            return NC_EHDFERR;
539
2.36k
    }
540
1.35k
    return NC_NOERR;
541
1.35k
}
542
543
/**
544
 * @internal Close HDF5 resources for vars in a group.
545
 *
546
 * @param grp Pointer to group info struct.
547
 *
548
 * @return ::NC_NOERR No error.
549
 * @return ::NC_EHDFERR HDF5 error.
550
 * @author Ed Hartnett
551
 */
552
static int
553
close_vars(NC_GRP_INFO_T *grp)
554
1.35k
{
555
1.35k
    NC_VAR_INFO_T *var;
556
1.35k
    NC_HDF5_VAR_INFO_T *hdf5_var;
557
1.35k
    NC_ATT_INFO_T *att;
558
1.35k
    int a, i;
559
560
13.5k
    for (i = 0; i < ncindexsize(grp->vars); i++)
561
12.1k
    {
562
12.1k
        var = (NC_VAR_INFO_T *)ncindexith(grp->vars, i);
563
12.1k
        assert(var && var->format_var_info);
564
12.1k
        hdf5_var = (NC_HDF5_VAR_INFO_T *)var->format_var_info;
565
566
        /* Close the HDF5 dataset associated with this var. */
567
12.1k
        if (hdf5_var->hdf_datasetid)
568
12.1k
        {
569
12.1k
            LOG((3, "closing HDF5 dataset %lld", hdf5_var->hdf_datasetid));
570
12.1k
            if (H5Dclose(hdf5_var->hdf_datasetid) < 0)
571
0
                return NC_EHDFERR;
572
573
12.1k
            if (var->fill_value)
574
6.12k
            {
575
6.12k
                if (var->type_info)
576
6.12k
                {
577
6.12k
                    if (var->type_info->nc_type_class == NC_VLEN)
578
0
                        nc_free_vlen((nc_vlen_t *)var->fill_value);
579
6.12k
                    else if (var->type_info->nc_type_class == NC_STRING && *(char **)var->fill_value)
580
0
                        free(*(char **)var->fill_value);
581
6.12k
                }
582
6.12k
            }
583
12.1k
        }
584
585
        /* Free the HDF5 typeids. */
586
12.1k
        if (var->type_info->rc == 1)
587
12.1k
        {
588
12.1k
            if (((NC_HDF5_TYPE_INFO_T *)(var->type_info->format_type_info))->hdf_typeid &&
589
12.1k
                H5Tclose(((NC_HDF5_TYPE_INFO_T *)(var->type_info->format_type_info))->hdf_typeid) < 0)
590
0
                return NC_EHDFERR;
591
12.1k
            if (((NC_HDF5_TYPE_INFO_T *)(var->type_info->format_type_info))->native_hdf_typeid &&
592
12.1k
                H5Tclose(((NC_HDF5_TYPE_INFO_T *)(var->type_info->format_type_info))->native_hdf_typeid) < 0)
593
0
                return NC_EHDFERR;
594
12.1k
        }
595
596
        /* Delete any HDF5 dimscale objid information. */
597
12.1k
        if (hdf5_var->dimscale_hdf5_objids)
598
1.76k
            free(hdf5_var->dimscale_hdf5_objids);
599
600
16.5k
        for (a = 0; a < ncindexsize(var->att); a++)
601
4.39k
        {
602
4.39k
            NC_HDF5_ATT_INFO_T *hdf5_att;
603
4.39k
            att = (NC_ATT_INFO_T *)ncindexith(var->att, a);
604
4.39k
            assert(att && att->format_att_info);
605
4.39k
            hdf5_att = (NC_HDF5_ATT_INFO_T *)att->format_att_info;
606
607
            /* Close the HDF5 typeid if one is open. */
608
4.39k
            if (hdf5_att->native_hdf_typeid &&
609
4.39k
                H5Tclose(hdf5_att->native_hdf_typeid) < 0)
610
0
                return NC_EHDFERR;
611
4.39k
        }
612
12.1k
    }
613
614
1.35k
    return NC_NOERR;
615
1.35k
}
616
617
/**
618
 * @internal Close HDF5 resources for dims in a group.
619
 *
620
 * @param grp Pointer to group info struct.
621
 *
622
 * @return ::NC_NOERR No error.
623
 * @return ::NC_EHDFERR HDF5 error.
624
 * @author Ed Hartnett
625
 */
626
static int
627
close_dims(NC_GRP_INFO_T *grp)
628
1.35k
{
629
1.35k
    NC_DIM_INFO_T *dim;
630
1.35k
    int i;
631
632
8.96k
    for (i = 0; i < ncindexsize(grp->dim); i++)
633
7.60k
    {
634
7.60k
        NC_HDF5_DIM_INFO_T *hdf5_dim;
635
636
7.60k
        dim = (NC_DIM_INFO_T *)ncindexith(grp->dim, i);
637
7.60k
        assert(dim && dim->format_dim_info);
638
7.60k
        hdf5_dim = (NC_HDF5_DIM_INFO_T *)dim->format_dim_info;
639
640
        /* If this is a dim without a coordinate variable, then close
641
         * the HDF5 DIM_WITHOUT_VARIABLE dataset associated with this
642
         * dim. */
643
7.60k
        if (hdf5_dim->hdf_dimscaleid && H5Dclose(hdf5_dim->hdf_dimscaleid) < 0)
644
0
            return NC_EHDFERR;
645
7.60k
    }
646
647
1.35k
    return NC_NOERR;
648
1.35k
}
649
650
/**
651
 * @internal Close HDF5 resources for types in a group.  Set values to
652
 * 0 after closing types. Because of type reference counters, these
653
 * closes can be called multiple times.
654
 *
655
 * @param grp Pointer to group info struct.
656
 *
657
 * @return ::NC_NOERR No error.
658
 * @return ::NC_EHDFERR HDF5 error.
659
 * @author Ed Hartnett, Dennis Heimbigner
660
 */
661
static int
662
close_types(NC_GRP_INFO_T *grp)
663
1.35k
{
664
1.35k
    int i;
665
666
1.35k
    for (i = 0; i < ncindexsize(grp->type); i++)
667
0
    {
668
0
        NC_TYPE_INFO_T *type;
669
0
        NC_HDF5_TYPE_INFO_T *hdf5_type;
670
671
0
        type = (NC_TYPE_INFO_T *)ncindexith(grp->type, i);
672
0
        assert(type && type->format_type_info);
673
674
        /* Get HDF5-specific type info. */
675
0
        hdf5_type = (NC_HDF5_TYPE_INFO_T *)type->format_type_info;
676
677
        /* Close any open user-defined HDF5 typeids. */
678
0
        if (hdf5_type->hdf_typeid && H5Tclose(hdf5_type->hdf_typeid) < 0)
679
0
            return NC_EHDFERR;
680
0
        hdf5_type->hdf_typeid = 0;
681
0
        if (hdf5_type->native_hdf_typeid &&
682
0
            H5Tclose(hdf5_type->native_hdf_typeid) < 0)
683
0
            return NC_EHDFERR;
684
0
        hdf5_type->native_hdf_typeid = 0;
685
0
    }
686
687
1.35k
    return NC_NOERR;
688
1.35k
}
689
690
/**
691
 * @internal Recursively free HDF5 objects for a group (and everything
692
 * it contains).
693
 *
694
 * @param grp Pointer to group info struct.
695
 *
696
 * @return ::NC_NOERR No error.
697
 * @return ::NC_EHDFERR HDF5 error.
698
 * @author Ed Hartnett
699
 */
700
int
701
nc4_rec_grp_HDF5_del(NC_GRP_INFO_T *grp)
702
1.35k
{
703
1.35k
    NC_HDF5_GRP_INFO_T *hdf5_grp;
704
1.35k
    int i;
705
1.35k
    int retval;
706
707
1.35k
    assert(grp && grp->format_grp_info);
708
1.35k
    LOG((3, "%s: grp->name %s", __func__, grp->hdr.name));
709
710
1.35k
    hdf5_grp = (NC_HDF5_GRP_INFO_T *)grp->format_grp_info;
711
712
    /* Recursively call this function for each child, if any, stopping
713
     * if there is an error. */
714
1.35k
    for (i = 0; i < ncindexsize(grp->children); i++)
715
0
        if ((retval = nc4_rec_grp_HDF5_del((NC_GRP_INFO_T *)ncindexith(grp->children,
716
0
                                                                       i))))
717
0
            return retval;
718
719
    /* Close HDF5 resources associated with global attributes. */
720
1.35k
    if ((retval = close_gatts(grp)))
721
0
        return retval;
722
723
    /* Close HDF5 resources associated with vars. */
724
1.35k
    if ((retval = close_vars(grp)))
725
0
        return retval;
726
727
    /* Close HDF5 resources associated with dims. */
728
1.35k
    if ((retval = close_dims(grp)))
729
0
        return retval;
730
731
    /* Close HDF5 resources associated with types. */
732
1.35k
    if ((retval = close_types(grp)))
733
0
        return retval;
734
735
    /* Close the HDF5 group. */
736
1.35k
    LOG((4, "%s: closing group %s", __func__, grp->hdr.name));
737
1.35k
    if (hdf5_grp->hdf_grpid && H5Gclose(hdf5_grp->hdf_grpid) < 0)
738
0
        return NC_EHDFERR;
739
740
1.35k
    return NC_NOERR;
741
1.35k
}
742
743
/**
744
 * @internal Given an ncid and varid, get pointers to the group and var
745
 * metadata. Lazy var metadata reads are done as needed.
746
 *
747
 * @param ncid File ID.
748
 * @param varid Variable ID.
749
 * @param h5 Pointer that gets pointer to the NC_FILE_INFO_T struct
750
 * for this file. Ignored if NULL.
751
 * @param grp Pointer that gets pointer to group info. Ignored if
752
 * NULL.
753
 * @param var Pointer that gets pointer to var info. Ignored if NULL.
754
 *
755
 * @return ::NC_NOERR No error.
756
 * @return ::NC_ENOTVAR Variable not found.
757
 * @author Ed Hartnett
758
 */
759
int
760
nc4_hdf5_find_grp_h5_var(int ncid, int varid, NC_FILE_INFO_T **h5,
761
                         NC_GRP_INFO_T **grp, NC_VAR_INFO_T **var)
762
48.7k
{
763
48.7k
    NC_FILE_INFO_T *my_h5;
764
48.7k
    NC_GRP_INFO_T *my_grp;
765
48.7k
    NC_VAR_INFO_T *my_var;
766
48.7k
    int retval;
767
768
    /* Look up file and group metadata. */
769
48.7k
    if ((retval = nc4_find_grp_h5(ncid, &my_grp, &my_h5)))
770
0
        return retval;
771
48.7k
    assert(my_grp && my_h5);
772
773
    /* Find the var. */
774
48.7k
    if (!(my_var = (NC_VAR_INFO_T *)ncindexith(my_grp->vars, varid)))
775
0
        return NC_ENOTVAR;
776
48.7k
    assert(my_var && my_var->hdr.id == varid);
777
778
    /* Do we need to read var metadata? */
779
48.7k
    if (!my_var->meta_read && my_var->created)
780
0
        if ((retval = nc4_get_var_meta(my_var)))
781
0
            return retval;
782
783
    /* Return pointers that caller wants. */
784
48.7k
    if (h5)
785
48.7k
        *h5 = my_h5;
786
48.7k
    if (grp)
787
48.7k
        *grp = my_grp;
788
48.7k
    if (var)
789
48.7k
        *var = my_var;
790
791
48.7k
    return NC_NOERR;
792
48.7k
}
793
794
/**
795
 * @internal Given an ncid, varid, and attribute name, return
796
 * normalized name and pointers to the file, group, var, and att info
797
 * structs. Lazy reads of attributes and variable metadata are done as
798
 * needed.
799
 *
800
 * @param ncid File/group ID.
801
 * @param varid Variable ID.
802
 * @param name Name to of attribute.
803
 * @param attnum Number of attribute.
804
 * @param use_name If true, use the name to get the
805
 * attribute. Otherwise use the attnum.
806
 * @param norm_name Pointer to storage of size NC_MAX_NAME + 1,
807
 * which will get the normalized name, if use_name is true. Ignored if
808
 * NULL.
809
 * @param h5 Pointer to pointer that gets file info struct. Ignored if
810
 * NULL.
811
 * @param grp Pointer to pointer that gets group info struct. Ignored
812
 * if NULL.
813
 * @param h5 Pointer to pointer that gets variable info
814
 * struct. Ignored if NULL.
815
 * @param att Pointer to pointer that gets attribute info
816
 * struct. Ignored if NULL.
817
 *
818
 * @return ::NC_NOERR No error.
819
 * @return ::NC_EBADID Bad ncid.
820
 * @return ::NC_ENOTVAR Variable not found.
821
 * @return ::NC_ENOTATT Attribute not found.
822
 * @author Ed Hartnett
823
 */
824
int
825
nc4_hdf5_find_grp_var_att(int ncid, int varid, const char *name, int attnum,
826
                          int use_name, char *norm_name, NC_FILE_INFO_T **h5,
827
                          NC_GRP_INFO_T **grp, NC_VAR_INFO_T **var,
828
                          NC_ATT_INFO_T **att)
829
271k
{
830
271k
    NC_FILE_INFO_T *my_h5;
831
271k
    NC_GRP_INFO_T *my_grp;
832
271k
    NC_VAR_INFO_T *my_var = NULL;
833
271k
    NC_ATT_INFO_T *my_att;
834
271k
    char my_norm_name[NC_MAX_NAME + 1] = "";
835
271k
    NCindex *attlist = NULL;
836
271k
    int retval;
837
838
271k
    LOG((4, "%s: ncid %d varid %d attnum %d use_name %d", __func__, ncid, varid,
839
271k
         attnum, use_name));
840
841
    /* Don't need to provide name unless getting att pointer and using
842
     * use_name. */
843
271k
    assert(!att || ((use_name && name) || !use_name));
844
845
    /* Find info for this file, group, and h5 info. */
846
271k
    if ((retval = nc4_find_nc_grp_h5(ncid, NULL, &my_grp, &my_h5)))
847
0
        return retval;
848
271k
    assert(my_grp && my_h5);
849
850
    /* Get either the global or a variable attribute list. */
851
271k
    if (varid == NC_GLOBAL)
852
5.68k
    {
853
        /* Do we need to read the atts? */
854
5.68k
        if (!my_grp->atts_read)
855
0
            if ((retval = nc4_read_atts(my_grp, NULL)))
856
0
                return retval;
857
858
5.68k
        attlist = my_grp->att;
859
5.68k
    }
860
265k
    else
861
265k
    {
862
265k
        if (!(my_var = (NC_VAR_INFO_T *)ncindexith(my_grp->vars, varid)))
863
0
            return NC_ENOTVAR;
864
865
        /* Do we need to read the var attributes? */
866
265k
        if (!my_var->atts_read)
867
6.08k
            if ((retval = nc4_read_atts(my_grp, my_var)))
868
0
                return retval;
869
870
        /* Do we need to read var metadata? */
871
265k
        if (!my_var->meta_read && my_var->created)
872
6.08k
            if ((retval = nc4_get_var_meta(my_var)))
873
0
                return retval;
874
875
265k
        attlist = my_var->att;
876
265k
    }
877
271k
    assert(attlist);
878
879
    /* Need a name if use_name is true. */
880
271k
    if (use_name && !name)
881
0
        return NC_EBADNAME;
882
883
    /* Normalize the name. */
884
271k
    if (use_name)
885
79.7k
        if ((retval = nc4_normalize_name(name, my_norm_name)))
886
0
            return retval;
887
888
    /* Now find the attribute by name or number. */
889
271k
    if (att)
890
5.01k
    {
891
5.01k
        my_att = use_name ? (NC_ATT_INFO_T *)ncindexlookup(attlist, my_norm_name) :
892
5.01k
            (NC_ATT_INFO_T *)ncindexith(attlist, attnum);
893
5.01k
        if (!my_att)
894
0
            return NC_ENOTATT;
895
5.01k
    }
896
897
    /* Give the people what they want. */
898
271k
    if (norm_name)
899
79.7k
    {
900
79.7k
        strncpy(norm_name, my_norm_name, NC_MAX_NAME);
901
79.7k
        norm_name[NC_MAX_NAME] = 0;
902
79.7k
    }
903
271k
    if (h5)
904
266k
        *h5 = my_h5;
905
271k
    if (grp)
906
266k
        *grp = my_grp;
907
271k
    if (var)
908
266k
        *var = my_var;
909
271k
    if (att)
910
5.01k
        *att = my_att;
911
912
271k
    return NC_NOERR;
913
271k
}
914
915
#ifdef LOGGING
916
/* We will need to check against nc log level from nc4internal.c. */
917
extern int nc_log_level;
918
919
/**
920
 * @internal This is like nc_set_log_level(), but will also turn on
921
 * HDF5 internal logging, in addition to netCDF logging. This should
922
 * never be called by the user. It is called in open/create when the
923
 * nc logging level has changed.
924
 *
925
 * @return ::NC_NOERR No error.
926
 * @author Ed Hartnett
927
 */
928
int
929
hdf5_set_log_level()
930
{
931
    /* If the user wants to completely turn off logging, turn off HDF5
932
       logging too. Now I truly can't think of what to do if this
933
       fails, so just ignore the return code. */
934
    if (nc_log_level == NC_TURN_OFF_LOGGING)
935
    {
936
        set_auto(NULL, NULL);
937
        LOG((1, "HDF5 error messages turned off!"));
938
    }
939
    else
940
    {
941
        if (set_auto((H5E_auto_t)&H5Eprint, stderr) < 0)
942
            LOG((0, "H5Eset_auto failed!"));
943
        LOG((1, "HDF5 error messages turned on."));
944
    }
945
946
    return NC_NOERR;
947
}
948
#endif /* LOGGING */