Coverage Report

Created: 2023-05-28 06:42

/src/netcdf-c/libnczarr/zfile.c
Line
Count
Source (jump to first uncovered line)
1
/* Copyright 2003-2018, University Corporation for Atmospheric
2
 * Research. See COPYRIGHT file for copying and redistribution
3
 * conditions. */
4
5
/**
6
 * @file
7
 * @internal The netCDF-4 file functions.
8
 *
9
 * This file is part of netcdf-4, a netCDF-like interface for NCZ, or
10
 * a ZARR backend for netCDF, depending on your point of view.
11
 *
12
 * @author Dennis Heimbigner, Ed Hartnett
13
 */
14
15
#include "zincludes.h"
16
#include "zfilter.h"
17
18
/* Forward */
19
static int NCZ_enddef(NC_FILE_INFO_T* h5);
20
static int ncz_sync_netcdf4_file(NC_FILE_INFO_T* file, int isclose);
21
22
/**
23
 * @internal Put the file back in redef mode. This is done
24
 * automatically for netcdf-4 files, if the user forgets.
25
 *
26
 * @param ncid File and group ID.
27
 *
28
 * @return ::NC_NOERR No error.
29
 * @author Dennis Heimbigner, Ed Hartnett
30
 */
31
int
32
NCZ_redef(int ncid)
33
0
{
34
0
    NC_FILE_INFO_T* zinfo = NULL;
35
0
    int stat = NC_NOERR;
36
37
0
    ZTRACE(0,"NCZ_redef(ncid)");
38
39
    /* Find this file's metadata. */
40
0
    if ((stat = nc4_find_grp_h5(ncid, NULL, &zinfo)))
41
0
        goto done;
42
0
    assert(zinfo);
43
44
    /* If we're already in define mode, return an error. */
45
0
    if (zinfo->flags & NC_INDEF)
46
0
        {stat = NC_EINDEFINE; goto done;}
47
48
    /* If the file is read-only, return an error. */
49
0
    if (zinfo->no_write)
50
0
        {stat = NC_EPERM; goto done;}
51
52
    /* Set define mode. */
53
0
    zinfo->flags |= NC_INDEF;
54
55
    /* For nc_abort, we need to remember if we're in define mode as a
56
       redef. */
57
0
    zinfo->redef = NC_TRUE;
58
59
0
done:
60
0
    return ZUNTRACE(stat);
61
0
}
62
63
/**
64
 * @internal For netcdf-4 files, this just calls nc_enddef, ignoring
65
 * the extra parameters.
66
 *
67
 * @param ncid File and group ID.
68
 * @param h_minfree Ignored for netCDF-4 files.
69
 * @param v_align Ignored for netCDF-4 files.
70
 * @param v_minfree Ignored for netCDF-4 files.
71
 * @param r_align Ignored for netCDF-4 files.
72
 *
73
 * @return ::NC_NOERR No error.
74
 * @author Dennis Heimbigner, Ed Hartnett
75
 */
76
int
77
NCZ__enddef(int ncid, size_t h_minfree, size_t v_align,
78
            size_t v_minfree, size_t r_align)
79
0
{
80
0
    int stat = NC_NOERR;
81
0
    NC_FILE_INFO_T* h5 = NULL;
82
0
    NC_GRP_INFO_T* grp = NULL;
83
0
    ZTRACE(0,"ncid=%d",ncid);
84
0
    if ((stat = nc4_find_grp_h5(ncid, &grp, &h5)))
85
0
        goto done;
86
0
    stat = NCZ_enddef(h5);
87
0
done:
88
0
    return ZUNTRACE(stat);
89
0
}
90
91
/**
92
 * @internal Take the file out of define mode. This is called
93
 * automatically for netcdf-4 files, if the user forgets.
94
 *
95
 * @param h5 File object
96
 *
97
 * @return ::NC_NOERR No error.
98
 * @return ::NC_EBADID Bad ncid.
99
 * @return ::NC_EBADGRPID Bad group ID.
100
 * @author Dennis Heimbigner, Ed Hartnett
101
 */
102
static int
103
NCZ_enddef(NC_FILE_INFO_T* h5)
104
0
{
105
0
    NC_VAR_INFO_T *var;
106
0
    int i,j;
107
0
    int stat = NC_NOERR;
108
109
0
    ZTRACE(1,"h5=%s",h5->hdr.name);
110
111
    /* When exiting define mode, process all variables */
112
0
    for (i = 0; i < nclistlength(h5->allgroups); i++) { 
113
0
  NC_GRP_INFO_T* g = nclistget(h5->allgroups,i);
114
0
        for (j = 0; j < ncindexsize(g->vars); j++) {
115
0
            var = (NC_VAR_INFO_T *)ncindexith(g->vars, j);
116
0
            assert(var);
117
0
            var->written_to = NC_TRUE; /* mark it written */
118
0
      var->created = 1;
119
0
        }
120
0
    }
121
0
    if((stat = ncz_enddef_netcdf4_file(h5))) goto done;
122
0
done:
123
0
    return ZUNTRACE(stat);
124
0
}
125
126
/**
127
 * @internal Flushes all buffers associated with the file, after
128
 * writing all changed metadata. This may only be called in data mode.
129
 *
130
 * @param ncid File and group ID.
131
 *
132
 * @return ::NC_NOERR No error.
133
 * @return ::NC_EBADID Bad ncid.
134
 * @return ::NC_EINDEFINE Classic model file is in define mode.
135
 * @author Dennis Heimbigner, Ed Hartnett
136
 */
137
int
138
NCZ_sync(int ncid)
139
0
{
140
0
    int stat = NC_NOERR;
141
0
    NC_FILE_INFO_T* file = NULL;
142
143
0
    ZTRACE(0,"ncid=%d",ncid);
144
145
0
    LOG((2, "%s: ncid 0x%x", __func__, ncid));
146
147
0
    if ((stat = nc4_find_grp_h5(ncid, NULL, &file)))
148
0
        return stat;
149
0
    assert(file);
150
151
    /* If we're in define mode, we can't sync. */
152
0
    if (file->flags & NC_INDEF)
153
0
    {
154
0
        if (file->cmode & NC_CLASSIC_MODEL)
155
0
            return NC_EINDEFINE;
156
0
        if ((stat = NCZ_enddef(file)))
157
0
            return stat;
158
0
    }
159
160
    /* do not do this if file is writeonce */
161
0
    stat = ncz_sync_netcdf4_file(file,!ZCLOSE);
162
0
    return stat;
163
0
}
164
165
/**
166
 * @internal From the netcdf-3 docs: The function nc_abort just closes
167
 * the netCDF dataset, if not in define mode. If the dataset is being
168
 * created and is still in define mode, the dataset is deleted. If
169
 * define mode was entered by a call to nc_redef, the netCDF dataset
170
 * is restored to its state before definition mode was entered and the
171
 * dataset is closed.
172
 *
173
 * @param ncid File and group ID.
174
 *
175
 * @return ::NC_NOERR No error.
176
 * @author Dennis Heimbigner, Ed Hartnett
177
 */
178
int
179
NCZ_abort(int ncid)
180
0
{
181
0
    int stat = NC_NOERR;
182
0
    NC_FILE_INFO_T* h5 = NULL;
183
0
    ZTRACE(0,"ncid=%d",ncid);
184
0
    LOG((2, "%s: ncid 0x%x", __func__, ncid));
185
    /* Find metadata for this file. */
186
0
    if ((stat = nc4_find_grp_h5(ncid, NULL, &h5)))
187
0
        return stat;
188
0
    assert(h5);
189
0
    stat = ncz_closeorabort(h5, NULL, 1);
190
0
    return ZUNTRACE(stat);
191
0
}
192
193
/**
194
 * @internal Close the netcdf file, writing any changes first.
195
 *
196
 * @param ncid File and group ID.
197
 * @param params any extra parameters in/out of close
198
 *
199
 * @return ::NC_NOERR No error.
200
 * @author Dennis Heimbigner, Ed Hartnett
201
 */
202
int
203
NCZ_close(int ncid, void* params)
204
0
{
205
0
    int stat = NC_NOERR;
206
0
    NC_FILE_INFO_T* h5 = NULL;
207
208
0
    ZTRACE(0,"ncid=%d",ncid);
209
0
    LOG((1, "%s: ncid 0x%x", __func__, ncid));
210
    /* Find metadata for this file. */
211
0
    if ((stat = nc4_find_grp_h5(ncid, NULL, &h5)))
212
0
        return stat;
213
0
    assert(h5);
214
0
    return ncz_closeorabort(h5, params, 0);
215
0
}
216
217
/**
218
 * @internal From the netcdf-3 docs: The function nc_abort just closes
219
 * the netCDF dataset, if not in define mode. If the dataset is being
220
 * created and is still in define mode, the dataset is deleted. If
221
 * define mode was entered by a call to nc_redef, the netCDF dataset
222
 * is restored to its state before definition mode was entered and the
223
 * dataset is closed.
224
 *
225
 * @param ncid File and group ID.
226
 *
227
 * @return ::NC_NOERR No error.
228
 * @author Dennis Heimbigner, Ed Hartnett
229
 */
230
int
231
ncz_closeorabort(NC_FILE_INFO_T* h5, void* params, int abort)
232
0
{
233
0
    int stat = NC_NOERR;
234
235
0
    assert(h5);
236
237
0
    NC_UNUSED(params);
238
239
0
    ZTRACE(3,"file=%s abort=%d",h5->hdr.name,abort);
240
241
0
    LOG((2, "%s: file: %p", __func__, h5));
242
243
    /* If we're in define mode, but not redefing the file, delete it. */
244
0
    if(!abort) {
245
  /* Invoke enddef if needed, which includes sync first */
246
0
  if(h5->flags & NC_INDEF) h5->flags ^= NC_INDEF;
247
  /* Sync the file unless this is a read-only file. */
248
0
  if(!h5->no_write) {
249
0
      if((stat = ncz_sync_netcdf4_file(h5,ZCLOSE)))
250
0
    goto done;
251
0
  }
252
0
    }
253
254
    /* Reclaim memory */
255
256
    /* Free any zarr-related data, including the map */
257
0
    if ((stat = ncz_close_file(h5, abort)))
258
0
  goto done;
259
260
    /* Reclaim provenance info */
261
0
    NCZ_clear_provenance(&h5->provenance);
262
263
    /* Free the NC_FILE_INFO_T struct. */
264
0
    if ((stat = nc4_nc4f_list_del(h5)))
265
0
        return stat;
266
267
0
done:
268
0
    return ZUNTRACE(stat);
269
0
}
270
271
/**************************************************/
272
/**
273
 * @internal Learn number of dimensions, variables, global attributes,
274
 * and the ID of the first unlimited dimension (if any).
275
 *
276
 * @note It's possible for any of these pointers to be NULL, in which
277
 * case don't try to figure out that value.
278
 *
279
 * @param ncid File and group ID.
280
 * @param ndimsp Pointer that gets number of dimensions.
281
 * @param nvarsp Pointer that gets number of variables.
282
 * @param nattsp Pointer that gets number of global attributes.
283
 * @param unlimdimidp Pointer that gets first unlimited dimension ID,
284
 * or -1 if there are no unlimied dimensions.
285
 *
286
 * @return ::NC_NOERR No error.
287
 * @author Dennis Heimbigner, Ed Hartnett
288
 */
289
int
290
NCZ_inq(int ncid, int *ndimsp, int *nvarsp, int *nattsp, int *unlimdimidp)
291
0
{
292
0
    NC *nc;
293
0
    NC_FILE_INFO_T* file;
294
0
    NC_GRP_INFO_T *grp;
295
0
    int stat = NC_NOERR;
296
0
    int i;
297
298
0
    LOG((2, "%s: ncid 0x%x", __func__, ncid));
299
300
    /* Find file metadata. */
301
0
    if ((stat = nc4_find_nc_grp_h5(ncid, &nc, &grp, &file)))
302
0
        return stat;
303
304
0
    assert(file && grp && nc);
305
306
    /* Count the number of dims, vars, and global atts; need to iterate
307
     * because of possible nulls. */
308
0
    if (ndimsp)
309
0
    {
310
0
        *ndimsp = ncindexcount(grp->dim);
311
0
    }
312
0
    if (nvarsp)
313
0
    {
314
0
        *nvarsp = ncindexcount(grp->vars);
315
0
    }
316
0
    if (nattsp)
317
0
    {
318
        /* Do we need to read the atts? */
319
0
        if (!grp->atts_read)
320
0
            if ((stat = ncz_read_atts(file,(NC_OBJ*)grp)))
321
0
                return stat;
322
323
0
        *nattsp = ncindexcount(grp->att);
324
0
    }
325
326
0
    if (unlimdimidp)
327
0
    {
328
        /* Default, no unlimited dimension */
329
0
        *unlimdimidp = -1;
330
331
        /* If there's more than one unlimited dim, which was not possible
332
           with netcdf-3, then only the last unlimited one will be reported
333
           back in xtendimp. */
334
        /* Note that this code is inconsistent with nc_inq_unlimid() */
335
0
        for(i=0;i<ncindexsize(grp->dim);i++) {
336
0
            NC_DIM_INFO_T* d = (NC_DIM_INFO_T*)ncindexith(grp->dim,i);
337
0
            if(d == NULL) continue;
338
0
            if(d->unlimited) {
339
0
                *unlimdimidp = d->hdr.id;
340
0
                break;
341
0
            }
342
0
        }
343
0
    }
344
345
0
    return NC_NOERR;
346
0
}
347
348
/**
349
 * @internal This function will write all changed metadata and flush
350
 * ZARR file to disk.
351
 *
352
 * @param file Pointer to file info struct.
353
 *
354
 * @return ::NC_NOERR No error.
355
 * @return ::NC_EINDEFINE Classic model file in define mode.
356
 * @return ::NC_EHDFERR ZARR error.
357
 * @author Dennis Heimbigner, Ed Hartnett
358
 */
359
360
static int
361
ncz_sync_netcdf4_file(NC_FILE_INFO_T* file, int isclose)
362
0
{
363
0
    int stat = NC_NOERR;
364
365
0
    assert(file && file->format_file_info);
366
0
    LOG((3, "%s", __func__));
367
0
    ZTRACE(2,"file=%s",file->hdr.name);
368
369
    /* End depend mode if needed. (Error checking for classic mode has
370
     * already happened). */
371
0
    if (file->flags & NC_INDEF)
372
0
    {
373
        /* Turn define mode off. */
374
0
        file->flags ^= NC_INDEF;
375
376
        /* Redef mode needs to be tracked separately for nc_abort. */
377
0
        file->redef = NC_FALSE;
378
0
    }
379
380
#ifdef LOGGING
381
    /* This will print out the names, types, lens, etc of the vars and
382
       atts in the file, if the logging level is 2 or greater. */
383
    log_metadata_nc(file);
384
#endif
385
386
    /* Write any metadata that has changed. */
387
0
    if (!file->no_write)
388
0
    {
389
        /* Write out provenance; will create _NCProperties */
390
0
        if((stat = NCZ_write_provenance(file)))
391
0
            goto done;
392
393
        /* Write all the metadata. */
394
0
  if((stat = ncz_sync_file(file,isclose)))
395
0
      goto done;
396
0
    }
397
0
done:
398
0
    return ZUNTRACE(stat);
399
0
}
400
401
/**
402
 * @internal This function will do the enddef stuff for an nczarr file.
403
 *
404
 * @param file Pointer to ZARR file info struct.
405
 *
406
 * @return ::NC_NOERR No error.
407
 * @return ::NC_ENOTINDEFINE Not in define mode.
408
 * @author Dennis Heimbigner, Ed Hartnett
409
 */
410
int
411
ncz_enddef_netcdf4_file(NC_FILE_INFO_T* file)
412
0
{
413
0
    assert(file);
414
0
    LOG((3, "%s", __func__));
415
416
    /* If we're not in define mode, return an error. */
417
0
    if (!(file->flags & NC_INDEF))
418
0
        return NC_ENOTINDEFINE;
419
420
    /* Turn define mode off. */
421
0
    file->flags ^= NC_INDEF;
422
423
    /* Redef mode needs to be tracked separately for nc_abort. */
424
0
    file->redef = NC_FALSE;
425
426
0
    return ncz_sync_netcdf4_file(file,!ZCLOSE);
427
0
}
428
429
/**
430
 * @internal IN netcdf, you first create
431
 * the variable and then (optionally) specify the fill value.
432
 *
433
 * @param ncid File and group ID.
434
 * @param fillmode File mode.
435
 * @param old_modep Pointer that gets old mode. Ignored if NULL.
436
 *
437
 * @return ::NC_NOERR No error.
438
 * @author Dennis Heimbigner
439
 */
440
int
441
NCZ_set_fill(int ncid, int fillmode, int *old_modep)
442
0
{
443
0
    NC_FILE_INFO_T* h5 = NULL;
444
0
    int stat = NC_NOERR;
445
446
0
    ZTRACE(0,"NCZ_set_fill(ncid,fillmode,old)");
447
448
    /* Get pointer to file info. */
449
0
    if ((stat = nc4_find_grp_h5(ncid, NULL, &h5)))
450
0
        goto done;
451
0
    assert(h5);
452
453
    /* Trying to set fill on a read-only file? You sicken me! */
454
0
    if (h5->no_write)
455
0
        {stat = NC_EPERM; goto done;}
456
457
    /* Did you pass me some weird fillmode? */
458
0
    if (fillmode != NC_FILL && fillmode != NC_NOFILL)
459
0
        {stat = NC_EINVAL; goto done;}
460
461
    /* If the user wants to know, tell him what the old mode was. */
462
0
    if (old_modep)
463
0
        *old_modep = h5->fill_mode;
464
465
0
    h5->fill_mode = fillmode;
466
467
0
done:
468
0
    return ZUNTRACE(stat);
469
0
}