Coverage Report

Created: 2026-08-11 08:26

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gdal/netcdf-c-4.7.4/libsrc/nc3internal.c
Line
Count
Source
1
/*
2
 *  Copyright 2018, Unuiversity Corporation for Atmospheric Research
3
 *      See netcdf/COPYRIGHT file for copying and redistribution conditions.
4
 */
5
6
#if HAVE_CONFIG_H
7
#include <config.h>
8
#endif
9
10
#include <stdlib.h>
11
#include <string.h>
12
#include <assert.h>
13
#ifdef HAVE_UNISTD_H
14
#include <unistd.h>
15
#endif
16
17
#include "nc3internal.h"
18
#include "netcdf_mem.h"
19
#include "rnd.h"
20
#include "ncx.h"
21
#include "ncrc.h"
22
23
/* These have to do with version numbers. */
24
#define MAGIC_NUM_LEN 4
25
#define VER_CLASSIC 1
26
#define VER_64BIT_OFFSET 2
27
#define VER_HDF5 3
28
29
0
#define NC_NUMRECS_OFFSET 4
30
31
/* For netcdf classic */
32
0
#define NC_NUMRECS_EXTENT3 4
33
/* For cdf5 */
34
0
#define NC_NUMRECS_EXTENT5 8
35
36
/* Internal function; breaks ncio abstraction */
37
extern int memio_extract(ncio* const nciop, size_t* sizep, void** memoryp);
38
39
static void
40
free_NC3INFO(NC3_INFO *nc3)
41
27.8k
{
42
27.8k
  if(nc3 == NULL)
43
0
    return;
44
27.8k
  free_NC_dimarrayV(&nc3->dims);
45
27.8k
  free_NC_attrarrayV(&nc3->attrs);
46
27.8k
  free_NC_vararrayV(&nc3->vars);
47
27.8k
  free(nc3);
48
27.8k
}
49
50
static NC3_INFO *
51
new_NC3INFO(const size_t *chunkp)
52
27.8k
{
53
27.8k
  NC3_INFO *ncp;
54
27.8k
  ncp = (NC3_INFO*)calloc(1,sizeof(NC3_INFO));
55
27.8k
  if(ncp == NULL) return ncp;
56
27.8k
        ncp->chunk = chunkp != NULL ? *chunkp : NC_SIZEHINT_DEFAULT;
57
  /* Note that ncp->xsz is not set yet because we do not know the file format */
58
27.8k
  return ncp;
59
27.8k
}
60
61
static NC3_INFO *
62
dup_NC3INFO(const NC3_INFO *ref)
63
0
{
64
0
  NC3_INFO *ncp;
65
0
  ncp = (NC3_INFO*)calloc(1,sizeof(NC3_INFO));
66
0
  if(ncp == NULL) return ncp;
67
68
0
  if(dup_NC_dimarrayV(&ncp->dims, &ref->dims) != NC_NOERR)
69
0
    goto err;
70
0
  if(dup_NC_attrarrayV(&ncp->attrs, &ref->attrs) != NC_NOERR)
71
0
    goto err;
72
0
  if(dup_NC_vararrayV(&ncp->vars, &ref->vars) != NC_NOERR)
73
0
    goto err;
74
75
0
  ncp->xsz = ref->xsz;
76
0
  ncp->begin_var = ref->begin_var;
77
0
  ncp->begin_rec = ref->begin_rec;
78
0
  ncp->recsize = ref->recsize;
79
0
  NC_set_numrecs(ncp, NC_get_numrecs(ref));
80
0
  return ncp;
81
0
err:
82
0
  free_NC3INFO(ncp);
83
0
  return NULL;
84
0
}
85
86
87
/*
88
 *  Verify that this is a user nc_type
89
 * Formerly NCcktype()
90
 * Sense of the return is changed.
91
 */
92
int
93
nc3_cktype(int mode, nc_type type)
94
350k
{
95
350k
#ifdef ENABLE_CDF5
96
350k
    if (mode & NC_CDF5) { /* CDF-5 format */
97
0
        if (type >= NC_BYTE && type < NC_STRING) return NC_NOERR;
98
0
    } else
99
350k
#endif
100
350k
      if (mode & NC_64BIT_OFFSET) { /* CDF-2 format */
101
0
        if (type >= NC_BYTE && type <= NC_DOUBLE) return NC_NOERR;
102
350k
    } else if ((mode & NC_64BIT_OFFSET) == 0) { /* CDF-1 format */
103
350k
        if (type >= NC_BYTE && type <= NC_DOUBLE) return NC_NOERR;
104
350k
    }
105
8.17k
    return(NC_EBADTYPE);
106
350k
}
107
108
109
/*
110
 * How many objects of 'type'
111
 * will fit into xbufsize?
112
 */
113
size_t
114
ncx_howmany(nc_type type, size_t xbufsize)
115
3.47M
{
116
3.47M
  switch(type){
117
1.59M
  case NC_BYTE:
118
3.35M
  case NC_CHAR:
119
3.35M
    return xbufsize;
120
0
  case NC_SHORT:
121
0
    return xbufsize/X_SIZEOF_SHORT;
122
86.0k
  case NC_INT:
123
86.0k
    return xbufsize/X_SIZEOF_INT;
124
19.1k
  case NC_FLOAT:
125
19.1k
    return xbufsize/X_SIZEOF_FLOAT;
126
11.5k
  case NC_DOUBLE:
127
11.5k
    return xbufsize/X_SIZEOF_DOUBLE;
128
0
  case NC_UBYTE:
129
0
    return xbufsize;
130
0
  case NC_USHORT:
131
0
    return xbufsize/X_SIZEOF_USHORT;
132
0
  case NC_UINT:
133
0
    return xbufsize/X_SIZEOF_UINT;
134
0
  case NC_INT64:
135
0
    return xbufsize/X_SIZEOF_LONGLONG;
136
0
  case NC_UINT64:
137
0
    return xbufsize/X_SIZEOF_ULONGLONG;
138
0
  default:
139
0
          assert("ncx_howmany: Bad type" == 0);
140
0
    return(0);
141
3.47M
  }
142
3.47M
}
143
144
19.8k
#define D_RNDUP(x, align) _RNDUP(x, (off_t)(align))
145
146
/*
147
 * Compute each variable's 'begin' offset,
148
 * update 'begin_rec' as well.
149
 */
150
static int
151
NC_begins(NC3_INFO* ncp,
152
  size_t h_minfree, size_t v_align,
153
  size_t v_minfree, size_t r_align)
154
13.9k
{
155
13.9k
  size_t ii, j;
156
13.9k
  int sizeof_off_t;
157
13.9k
  off_t index = 0;
158
13.9k
  off_t old_ncp_begin_var;
159
13.9k
  NC_var **vpp;
160
13.9k
  NC_var *last = NULL;
161
13.9k
  NC_var *first_var = NULL;       /* first "non-record" var */
162
163
164
13.9k
  if(v_align == NC_ALIGN_CHUNK)
165
0
    v_align = ncp->chunk;
166
13.9k
  if(r_align == NC_ALIGN_CHUNK)
167
0
    r_align = ncp->chunk;
168
169
13.9k
  if (fIsSet(ncp->flags, NC_64BIT_OFFSET) || fIsSet(ncp->flags, NC_64BIT_DATA)) {
170
0
    sizeof_off_t = 8;
171
13.9k
  } else {
172
13.9k
    sizeof_off_t = 4;
173
13.9k
  }
174
175
13.9k
  ncp->xsz = ncx_len_NC(ncp,sizeof_off_t);
176
177
13.9k
  if(ncp->vars.nelems == 0)
178
4.03k
    return NC_NOERR;
179
180
9.90k
        old_ncp_begin_var = ncp->begin_var;
181
182
  /* only (re)calculate begin_var if there is not sufficient space in header
183
     or start of non-record variables is not aligned as requested by valign */
184
9.90k
  if (ncp->begin_var < ncp->xsz + h_minfree ||
185
0
      ncp->begin_var != D_RNDUP(ncp->begin_var, v_align) )
186
9.90k
  {
187
9.90k
    index = (off_t) ncp->xsz;
188
9.90k
    ncp->begin_var = D_RNDUP(index, v_align);
189
9.90k
    if(ncp->begin_var < index + h_minfree)
190
0
    {
191
0
      ncp->begin_var = D_RNDUP(index + (off_t)h_minfree, v_align);
192
0
    }
193
9.90k
  }
194
195
9.90k
  if (ncp->old != NULL) {
196
            /* check whether the new begin_var is smaller */
197
0
            if (ncp->begin_var < ncp->old->begin_var)
198
0
                ncp->begin_var = ncp->old->begin_var;
199
0
  }
200
201
9.90k
  index = ncp->begin_var;
202
203
  /* loop thru vars, first pass is for the 'non-record' vars */
204
9.90k
  j = 0;
205
9.90k
  vpp = ncp->vars.value;
206
98.8k
  for(ii = 0; ii < ncp->vars.nelems ; ii++, vpp++)
207
88.9k
  {
208
88.9k
    if( IS_RECVAR(*vpp) )
209
3.05k
    {
210
      /* skip record variables on this pass */
211
3.05k
      continue;
212
3.05k
    }
213
85.8k
    if (first_var == NULL) first_var = *vpp;
214
215
#if 0
216
fprintf(stderr, "    VAR %d %s: %ld\n", ii, (*vpp)->name->cp, (long)index);
217
#endif
218
85.8k
                if( sizeof_off_t == 4 && (index > X_OFF_MAX || index < 0) )
219
0
    {
220
0
                    ncp->begin_var = old_ncp_begin_var;
221
0
        return NC_EVARSIZE;
222
0
                }
223
85.8k
    (*vpp)->begin = index;
224
225
85.8k
    if (ncp->old != NULL) {
226
          /* move to the next fixed variable */
227
0
          for (; j<ncp->old->vars.nelems; j++) {
228
0
            if (!IS_RECVAR(ncp->old->vars.value[j]))
229
0
              break;
230
0
          }
231
232
0
          if (j < ncp->old->vars.nelems) {
233
0
            if ((*vpp)->begin < ncp->old->vars.value[j]->begin) {
234
              /* the first ncp->vars.nelems fixed variables
235
                 should be the same. If the new begin is smaller,
236
                 reuse the old begin */
237
0
              (*vpp)->begin = ncp->old->vars.value[j]->begin;
238
0
              index = (*vpp)->begin;
239
0
            }
240
0
            j++;
241
0
          }
242
0
    }
243
244
85.8k
    index += (*vpp)->len;
245
85.8k
  }
246
247
9.90k
  if (ncp->old != NULL) {
248
      /* check whether the new begin_rec is smaller */
249
0
      if (ncp->begin_rec < ncp->old->begin_rec)
250
0
          ncp->begin_rec = ncp->old->begin_rec;
251
0
  }
252
253
  /* only (re)calculate begin_rec if there is not sufficient
254
     space at end of non-record variables or if start of record
255
     variables is not aligned as requested by r_align */
256
9.90k
  if (ncp->begin_rec < index + v_minfree ||
257
0
      ncp->begin_rec != D_RNDUP(ncp->begin_rec, r_align) )
258
9.90k
  {
259
9.90k
    ncp->begin_rec = D_RNDUP(index, r_align);
260
9.90k
    if(ncp->begin_rec < index + v_minfree)
261
0
    {
262
0
      ncp->begin_rec = D_RNDUP(index + (off_t)v_minfree, r_align);
263
0
    }
264
9.90k
  }
265
266
9.90k
  if (first_var != NULL)
267
9.76k
      ncp->begin_var = first_var->begin;
268
142
  else
269
142
      ncp->begin_var = ncp->begin_rec;
270
271
9.90k
  index = ncp->begin_rec;
272
273
9.90k
  ncp->recsize = 0;
274
275
  /* loop thru vars, second pass is for the 'record' vars */
276
9.90k
  j = 0;
277
9.90k
  vpp = (NC_var **)ncp->vars.value;
278
98.8k
  for(ii = 0; ii < ncp->vars.nelems; ii++, vpp++)
279
88.9k
  {
280
88.9k
    if( !IS_RECVAR(*vpp) )
281
85.8k
    {
282
      /* skip non-record variables on this pass */
283
85.8k
      continue;
284
85.8k
    }
285
286
#if 0
287
fprintf(stderr, "    REC %d %s: %ld\n", ii, (*vpp)->name->cp, (long)index);
288
#endif
289
3.05k
                if( sizeof_off_t == 4 && (index > X_OFF_MAX || index < 0) )
290
0
    {
291
0
                    ncp->begin_var = old_ncp_begin_var;
292
0
        return NC_EVARSIZE;
293
0
                }
294
3.05k
    (*vpp)->begin = index;
295
296
3.05k
                if (ncp->old != NULL) {
297
                    /* move to the next record variable */
298
0
                    for (; j<ncp->old->vars.nelems; j++)
299
0
                        if (IS_RECVAR(ncp->old->vars.value[j]))
300
0
                            break;
301
0
                    if (j < ncp->old->vars.nelems) {
302
0
                        if ((*vpp)->begin < ncp->old->vars.value[j]->begin)
303
                            /* if the new begin is smaller, use the old begin */
304
0
                            (*vpp)->begin = ncp->old->vars.value[j]->begin;
305
0
                        j++;
306
0
                    }
307
0
                }
308
309
3.05k
    index += (*vpp)->len;
310
    /* check if record size must fit in 32-bits */
311
#if SIZEOF_OFF_T == SIZEOF_SIZE_T && SIZEOF_SIZE_T == 4
312
    if( ncp->recsize > X_UINT_MAX - (*vpp)->len )
313
    {
314
                    ncp->begin_var = old_ncp_begin_var;
315
        return NC_EVARSIZE;
316
    }
317
#endif
318
3.05k
    ncp->recsize += (*vpp)->len;
319
3.05k
    last = (*vpp);
320
3.05k
  }
321
322
    /*
323
     * for special case (Check CDF-1 and CDF-2 file format specifications.)
324
     * "A special case: Where there is exactly one record variable, we drop the
325
     * requirement that each record be four-byte aligned, so in this case there
326
     * is no record padding."
327
     */
328
9.90k
    if (last != NULL) {
329
1.08k
        if (ncp->recsize == last->len) {
330
            /* exactly one record variable, pack value */
331
589
            ncp->recsize = *last->dsizes * last->xsz;
332
589
        }
333
1.08k
    }
334
335
9.90k
  if(NC_IsNew(ncp))
336
9.90k
    NC_set_numrecs(ncp, 0);
337
9.90k
  return NC_NOERR;
338
9.90k
}
339
340
341
/*
342
 * Read just the numrecs member.
343
 * (A relatively expensive way to do things.)
344
 */
345
int
346
read_numrecs(NC3_INFO *ncp)
347
0
{
348
0
  int status = NC_NOERR;
349
0
  const void *xp = NULL;
350
0
  size_t new_nrecs = 0;
351
0
  size_t  old_nrecs = NC_get_numrecs(ncp);
352
0
  size_t nc_numrecs_extent = NC_NUMRECS_EXTENT3; /* CDF-1 and CDF-2 */
353
354
0
  assert(!NC_indef(ncp));
355
356
0
  if (fIsSet(ncp->flags, NC_64BIT_DATA))
357
0
    nc_numrecs_extent = NC_NUMRECS_EXTENT5; /* CDF-5 */
358
359
0
  status = ncio_get(ncp->nciop,
360
0
     NC_NUMRECS_OFFSET, nc_numrecs_extent, 0, (void **)&xp);/* cast away const */
361
0
  if(status != NC_NOERR)
362
0
    return status;
363
364
0
  if (fIsSet(ncp->flags, NC_64BIT_DATA)) {
365
0
      unsigned long long tmp=0;
366
0
      status = ncx_get_uint64(&xp, &tmp);
367
0
      new_nrecs = (size_t)tmp;
368
0
        } else
369
0
      status = ncx_get_size_t(&xp, &new_nrecs);
370
371
0
  (void) ncio_rel(ncp->nciop, NC_NUMRECS_OFFSET, 0);
372
373
0
  if(status == NC_NOERR && old_nrecs != new_nrecs)
374
0
  {
375
0
    NC_set_numrecs(ncp, new_nrecs);
376
0
    fClr(ncp->flags, NC_NDIRTY);
377
0
  }
378
379
0
  return status;
380
0
}
381
382
383
/*
384
 * Write out just the numrecs member.
385
 * (A relatively expensive way to do things.)
386
 */
387
int
388
write_numrecs(NC3_INFO *ncp)
389
0
{
390
0
  int status = NC_NOERR;
391
0
  void *xp = NULL;
392
0
  size_t nc_numrecs_extent = NC_NUMRECS_EXTENT3; /* CDF-1 and CDF-2 */
393
394
0
  assert(!NC_readonly(ncp));
395
0
  assert(!NC_indef(ncp));
396
397
0
  if (fIsSet(ncp->flags, NC_64BIT_DATA))
398
0
      nc_numrecs_extent = NC_NUMRECS_EXTENT5; /* CDF-5 */
399
400
0
  status = ncio_get(ncp->nciop,
401
0
     NC_NUMRECS_OFFSET, nc_numrecs_extent, RGN_WRITE, &xp);
402
0
  if(status != NC_NOERR)
403
0
    return status;
404
405
0
  {
406
0
    const size_t nrecs = NC_get_numrecs(ncp);
407
0
    if (fIsSet(ncp->flags, NC_64BIT_DATA))
408
0
        status = ncx_put_uint64(&xp, (unsigned long long)nrecs);
409
0
    else
410
0
        status = ncx_put_size_t(&xp, &nrecs);
411
0
  }
412
413
0
  (void) ncio_rel(ncp->nciop, NC_NUMRECS_OFFSET, RGN_MODIFIED);
414
415
0
  if(status == NC_NOERR)
416
0
    fClr(ncp->flags, NC_NDIRTY);
417
418
0
  return status;
419
0
}
420
421
422
/*
423
 * Read in the header
424
 * It is expensive.
425
 */
426
static int
427
read_NC(NC3_INFO *ncp)
428
0
{
429
0
  int status = NC_NOERR;
430
431
0
  free_NC_dimarrayV(&ncp->dims);
432
0
  free_NC_attrarrayV(&ncp->attrs);
433
0
  free_NC_vararrayV(&ncp->vars);
434
435
0
  status = nc_get_NC(ncp);
436
437
0
  if(status == NC_NOERR)
438
0
    fClr(ncp->flags, NC_NDIRTY | NC_HDIRTY);
439
440
0
  return status;
441
0
}
442
443
444
/*
445
 * Write out the header
446
 */
447
static int
448
write_NC(NC3_INFO *ncp)
449
13.9k
{
450
13.9k
  int status = NC_NOERR;
451
452
13.9k
  assert(!NC_readonly(ncp));
453
454
13.9k
  status = ncx_put_NC(ncp, NULL, 0, 0);
455
456
13.9k
  if(status == NC_NOERR)
457
13.9k
    fClr(ncp->flags, NC_NDIRTY | NC_HDIRTY);
458
459
13.9k
  return status;
460
13.9k
}
461
462
463
/*
464
 * Write the header or the numrecs if necessary.
465
 */
466
int
467
NC_sync(NC3_INFO *ncp)
468
2.23k
{
469
2.23k
  assert(!NC_readonly(ncp));
470
471
2.23k
  if(NC_hdirty(ncp))
472
0
  {
473
0
    return write_NC(ncp);
474
0
  }
475
  /* else */
476
477
2.23k
  if(NC_ndirty(ncp))
478
0
  {
479
0
    return write_numrecs(ncp);
480
0
  }
481
  /* else */
482
483
2.23k
  return NC_NOERR;
484
2.23k
}
485
486
487
/*
488
 * Initialize the 'non-record' variables.
489
 */
490
static int
491
fillerup(NC3_INFO *ncp)
492
13.9k
{
493
13.9k
  int status = NC_NOERR;
494
13.9k
  size_t ii;
495
13.9k
  NC_var **varpp;
496
497
13.9k
  assert(!NC_readonly(ncp));
498
499
  /* loop thru vars */
500
13.9k
  varpp = ncp->vars.value;
501
102k
  for(ii = 0; ii < ncp->vars.nelems; ii++, varpp++)
502
88.9k
  {
503
88.9k
    if ((*varpp)->no_fill) continue;
504
505
88.9k
    if(IS_RECVAR(*varpp))
506
3.05k
    {
507
      /* skip record variables */
508
3.05k
      continue;
509
3.05k
    }
510
511
85.8k
    status = fill_NC_var(ncp, *varpp, (*varpp)->len, 0);
512
85.8k
    if(status != NC_NOERR)
513
0
      break;
514
85.8k
  }
515
13.9k
  return status;
516
13.9k
}
517
518
/* Begin endef */
519
520
/*
521
 */
522
static int
523
fill_added_recs(NC3_INFO *gnu, NC3_INFO *old)
524
0
{
525
0
  NC_var ** const gnu_varpp = (NC_var **)gnu->vars.value;
526
527
0
  const int old_nrecs = (int) NC_get_numrecs(old);
528
0
  int recno = 0;
529
0
  NC_var **vpp = gnu_varpp;
530
0
  NC_var *const *const end = &vpp[gnu->vars.nelems];
531
0
  int numrecvars = 0;
532
533
  /* Determine if there is only one record variable.  If so, we
534
     must treat as a special case because there's no record padding */
535
0
  for(; vpp < end; vpp++) {
536
0
      if(IS_RECVAR(*vpp)) {
537
0
    numrecvars++;
538
0
      }
539
0
  }
540
541
0
  for(; recno < old_nrecs; recno++)
542
0
      {
543
0
    int varid = (int)old->vars.nelems;
544
0
    for(; varid < (int)gnu->vars.nelems; varid++)
545
0
        {
546
0
      const NC_var *const gnu_varp = *(gnu_varpp + varid);
547
548
0
      if (gnu_varp->no_fill) continue;
549
550
0
      if(!IS_RECVAR(gnu_varp))
551
0
          {
552
        /* skip non-record variables */
553
0
        continue;
554
0
          }
555
      /* else */
556
0
      {
557
0
          size_t varsize = numrecvars == 1 ? gnu->recsize :  gnu_varp->len;
558
0
          const int status = fill_NC_var(gnu, gnu_varp, varsize, recno);
559
0
          if(status != NC_NOERR)
560
0
        return status;
561
0
      }
562
0
        }
563
0
      }
564
0
  return NC_NOERR;
565
0
}
566
567
/*
568
 */
569
static int
570
fill_added(NC3_INFO *gnu, NC3_INFO *old)
571
0
{
572
0
  NC_var ** const gnu_varpp = (NC_var **)gnu->vars.value;
573
0
  int varid = (int)old->vars.nelems;
574
575
0
  for(; varid < (int)gnu->vars.nelems; varid++)
576
0
  {
577
0
    const NC_var *const gnu_varp = *(gnu_varpp + varid);
578
579
0
    if (gnu_varp->no_fill) continue;
580
581
0
    if(IS_RECVAR(gnu_varp))
582
0
    {
583
      /* skip record variables */
584
0
      continue;
585
0
    }
586
    /* else */
587
0
    {
588
0
    const int status = fill_NC_var(gnu, gnu_varp, gnu_varp->len, 0);
589
0
    if(status != NC_NOERR)
590
0
      return status;
591
0
    }
592
0
  }
593
594
0
  return NC_NOERR;
595
0
}
596
597
598
/*
599
 * Move the records "out".
600
 * Fill as needed.
601
 */
602
static int
603
move_recs_r(NC3_INFO *gnu, NC3_INFO *old)
604
0
{
605
0
  int status;
606
0
  int recno;
607
0
  int varid;
608
0
  NC_var **gnu_varpp = (NC_var **)gnu->vars.value;
609
0
  NC_var **old_varpp = (NC_var **)old->vars.value;
610
0
  NC_var *gnu_varp;
611
0
  NC_var *old_varp;
612
0
  off_t gnu_off;
613
0
  off_t old_off;
614
0
  const size_t old_nrecs = NC_get_numrecs(old);
615
616
  /* Don't parallelize this loop */
617
0
  for(recno = (int)old_nrecs -1; recno >= 0; recno--)
618
0
  {
619
  /* Don't parallelize this loop */
620
0
  for(varid = (int)old->vars.nelems -1; varid >= 0; varid--)
621
0
  {
622
0
    gnu_varp = *(gnu_varpp + varid);
623
0
    if(!IS_RECVAR(gnu_varp))
624
0
    {
625
      /* skip non-record variables on this pass */
626
0
      continue;
627
0
    }
628
    /* else */
629
630
    /* else, a pre-existing variable */
631
0
    old_varp = *(old_varpp + varid);
632
0
    gnu_off = gnu_varp->begin + (off_t)(gnu->recsize * recno);
633
0
    old_off = old_varp->begin + (off_t)(old->recsize * recno);
634
635
0
    if(gnu_off == old_off)
636
0
      continue;   /* nothing to do */
637
638
0
    assert(gnu_off > old_off);
639
640
0
    status = ncio_move(gnu->nciop, gnu_off, old_off,
641
0
       old_varp->len, 0);
642
643
0
    if(status != NC_NOERR)
644
0
      return status;
645
646
0
  }
647
0
  }
648
649
0
  NC_set_numrecs(gnu, old_nrecs);
650
651
0
  return NC_NOERR;
652
0
}
653
654
655
/*
656
 * Move the "non record" variables "out".
657
 * Fill as needed.
658
 */
659
static int
660
move_vars_r(NC3_INFO *gnu, NC3_INFO *old)
661
0
{
662
0
  int err, status=NC_NOERR;
663
0
  int varid;
664
0
  NC_var **gnu_varpp = (NC_var **)gnu->vars.value;
665
0
  NC_var **old_varpp = (NC_var **)old->vars.value;
666
0
  NC_var *gnu_varp;
667
0
  NC_var *old_varp;
668
0
  off_t gnu_off;
669
0
  off_t old_off;
670
671
  /* Don't parallelize this loop */
672
0
  for(varid = (int)old->vars.nelems -1;
673
0
     varid >= 0; varid--)
674
0
  {
675
0
    gnu_varp = *(gnu_varpp + varid);
676
0
    if(IS_RECVAR(gnu_varp))
677
0
    {
678
      /* skip record variables on this pass */
679
0
      continue;
680
0
    }
681
    /* else */
682
683
0
    old_varp = *(old_varpp + varid);
684
0
    gnu_off = gnu_varp->begin;
685
0
    old_off = old_varp->begin;
686
687
0
    if (gnu_off > old_off) {
688
0
        err = ncio_move(gnu->nciop, gnu_off, old_off,
689
0
                     old_varp->len, 0);
690
0
        if (status == NC_NOERR) status = err;
691
0
    }
692
0
  }
693
0
  return status;
694
0
}
695
696
697
/*
698
 * Given a valid ncp, return NC_EVARSIZE if any variable has a bad len
699
 * (product of non-rec dim sizes too large), else return NC_NOERR.
700
 */
701
int
702
NC_check_vlens(NC3_INFO *ncp)
703
27.8k
{
704
27.8k
    NC_var **vpp;
705
    /* maximum permitted variable size (or size of one record's worth
706
       of a record variable) in bytes.  This is different for format 1
707
       and format 2. */
708
27.8k
    long long vlen_max;
709
27.8k
    size_t ii;
710
27.8k
    size_t large_vars_count;
711
27.8k
    size_t rec_vars_count;
712
27.8k
    int last = 0;
713
714
27.8k
    if(ncp->vars.nelems == 0)
715
8.06k
  return NC_NOERR;
716
717
19.8k
    if (fIsSet(ncp->flags,NC_64BIT_DATA)) /* CDF-5 */
718
0
  vlen_max = X_INT64_MAX - 3; /* "- 3" handles rounded-up size */
719
19.8k
    else if (fIsSet(ncp->flags,NC_64BIT_OFFSET) && sizeof(off_t) > 4)
720
  /* CDF2 format and LFS */
721
0
  vlen_max = X_UINT_MAX - 3; /* "- 3" handles rounded-up size */
722
19.8k
    else /* CDF1 format */
723
19.8k
  vlen_max = X_INT_MAX - 3;
724
725
    /* Loop through vars, first pass is for non-record variables.   */
726
19.8k
    large_vars_count = 0;
727
19.8k
    rec_vars_count = 0;
728
19.8k
    vpp = ncp->vars.value;
729
197k
    for (ii = 0; ii < ncp->vars.nelems; ii++, vpp++) {
730
177k
  if( !IS_RECVAR(*vpp) ) {
731
171k
      last = 0;
732
171k
      if( NC_check_vlen(*vpp, vlen_max) == 0 ) {
733
0
                if (fIsSet(ncp->flags,NC_64BIT_DATA)) /* too big for CDF-5 */
734
0
                    return NC_EVARSIZE;
735
0
    large_vars_count++;
736
0
    last = 1;
737
0
      }
738
171k
  } else {
739
6.11k
    rec_vars_count++;
740
6.11k
  }
741
177k
    }
742
    /* OK if last non-record variable size too large, since not used to
743
       compute an offset */
744
19.8k
    if( large_vars_count > 1) { /* only one "too-large" variable allowed */
745
0
      return NC_EVARSIZE;
746
0
    }
747
    /* and it has to be the last one */
748
19.8k
    if( large_vars_count == 1 && last == 0) {
749
0
      return NC_EVARSIZE;
750
0
    }
751
19.8k
    if( rec_vars_count > 0 ) {
752
  /* and if it's the last one, there can't be any record variables */
753
2.17k
  if( large_vars_count == 1 && last == 1) {
754
0
      return NC_EVARSIZE;
755
0
  }
756
  /* Loop through vars, second pass is for record variables.   */
757
2.17k
  large_vars_count = 0;
758
2.17k
  vpp = ncp->vars.value;
759
34.3k
  for (ii = 0; ii < ncp->vars.nelems; ii++, vpp++) {
760
32.1k
      if( IS_RECVAR(*vpp) ) {
761
6.11k
    last = 0;
762
6.11k
    if( NC_check_vlen(*vpp, vlen_max) == 0 ) {
763
0
                    if (fIsSet(ncp->flags,NC_64BIT_DATA)) /* too big for CDF-5 */
764
0
                        return NC_EVARSIZE;
765
0
        large_vars_count++;
766
0
        last = 1;
767
0
    }
768
6.11k
      }
769
32.1k
  }
770
  /* OK if last record variable size too large, since not used to
771
     compute an offset */
772
2.17k
  if( large_vars_count > 1) { /* only one "too-large" variable allowed */
773
0
      return NC_EVARSIZE;
774
0
  }
775
  /* and it has to be the last one */
776
2.17k
  if( large_vars_count == 1 && last == 0) {
777
0
      return NC_EVARSIZE;
778
0
  }
779
2.17k
    }
780
19.8k
    return NC_NOERR;
781
19.8k
}
782
783
/*----< NC_check_voffs() >---------------------------------------------------*/
784
/*
785
 * Given a valid ncp, check whether the file starting offsets (begin) of all
786
 * variables follows the same increasing order as they were defined.
787
 */
788
int
789
NC_check_voffs(NC3_INFO *ncp)
790
27.8k
{
791
27.8k
    size_t i;
792
27.8k
    off_t prev_off;
793
27.8k
    NC_var *varp;
794
795
27.8k
    if (ncp->vars.nelems == 0) return NC_NOERR;
796
797
    /* Loop through vars, first pass is for non-record variables */
798
19.8k
    prev_off = ncp->begin_var;
799
197k
    for (i=0; i<ncp->vars.nelems; i++) {
800
177k
        varp = ncp->vars.value[i];
801
177k
        if (IS_RECVAR(varp)) continue;
802
803
171k
        if (varp->begin < prev_off) {
804
#if 0
805
            fprintf(stderr,"Variable \"%s\" begin offset (%lld) is less than previous variable end offset (%lld)\n", varp->name->cp, varp->begin, prev_off);
806
#endif
807
0
            return NC_ENOTNC;
808
0
        }
809
171k
        prev_off = varp->begin + varp->len;
810
171k
    }
811
812
19.8k
    if (ncp->begin_rec < prev_off) {
813
#if 0
814
        fprintf(stderr,"Record variable section begin offset (%lld) is less than fix-sized variable section end offset (%lld)\n", varp->begin, prev_off);
815
#endif
816
0
        return NC_ENOTNC;
817
0
    }
818
819
    /* Loop through vars, second pass is for record variables */
820
19.8k
    prev_off = ncp->begin_rec;
821
197k
    for (i=0; i<ncp->vars.nelems; i++) {
822
177k
        varp = ncp->vars.value[i];
823
177k
        if (!IS_RECVAR(varp)) continue;
824
825
6.11k
        if (varp->begin < prev_off) {
826
#if 0
827
            fprintf(stderr,"Variable \"%s\" begin offset (%lld) is less than previous variable end offset (%lld)\n", varp->name->cp, varp->begin, prev_off);
828
#endif
829
0
            return NC_ENOTNC;
830
0
        }
831
6.11k
        prev_off = varp->begin + varp->len;
832
6.11k
    }
833
834
19.8k
    return NC_NOERR;
835
19.8k
}
836
837
/*
838
 *  End define mode.
839
 *  Common code for ncendef, ncclose(endef)
840
 *  Flushes I/O buffers.
841
 */
842
static int
843
NC_endef(NC3_INFO *ncp,
844
  size_t h_minfree, size_t v_align,
845
  size_t v_minfree, size_t r_align)
846
13.9k
{
847
13.9k
  int status = NC_NOERR;
848
849
13.9k
  assert(!NC_readonly(ncp));
850
13.9k
  assert(NC_indef(ncp));
851
852
13.9k
  status = NC_check_vlens(ncp);
853
13.9k
  if(status != NC_NOERR)
854
0
      return status;
855
13.9k
  status = NC_begins(ncp, h_minfree, v_align, v_minfree, r_align);
856
13.9k
  if(status != NC_NOERR)
857
0
      return status;
858
13.9k
  status = NC_check_voffs(ncp);
859
13.9k
  if(status != NC_NOERR)
860
0
      return status;
861
862
13.9k
  if(ncp->old != NULL)
863
0
  {
864
    /* a plain redef, not a create */
865
0
    assert(!NC_IsNew(ncp));
866
0
    assert(fIsSet(ncp->flags, NC_INDEF));
867
0
    assert(ncp->begin_rec >= ncp->old->begin_rec);
868
0
    assert(ncp->begin_var >= ncp->old->begin_var);
869
870
0
    if(ncp->vars.nelems != 0)
871
0
    {
872
0
    if(ncp->begin_rec > ncp->old->begin_rec)
873
0
    {
874
0
      status = move_recs_r(ncp, ncp->old);
875
0
      if(status != NC_NOERR)
876
0
        return status;
877
0
      if(ncp->begin_var > ncp->old->begin_var)
878
0
      {
879
0
        status = move_vars_r(ncp, ncp->old);
880
0
        if(status != NC_NOERR)
881
0
          return status;
882
0
      }
883
      /* else if (ncp->begin_var == ncp->old->begin_var) { NOOP } */
884
0
    }
885
0
    else
886
0
                {
887
      /* due to fixed variable alignment, it is possible that header
888
                           grows but begin_rec did not change */
889
0
      if(ncp->begin_var > ncp->old->begin_var)
890
0
      {
891
0
        status = move_vars_r(ncp, ncp->old);
892
0
        if(status != NC_NOERR)
893
0
          return status;
894
0
      }
895
      /* Even if (ncp->begin_rec == ncp->old->begin_rec)
896
         and     (ncp->begin_var == ncp->old->begin_var)
897
         might still have added a new record variable */
898
0
            if(ncp->recsize > ncp->old->recsize)
899
0
      {
900
0
              status = move_recs_r(ncp, ncp->old);
901
0
        if(status != NC_NOERR)
902
0
              return status;
903
0
      }
904
0
    }
905
0
    }
906
0
  }
907
908
13.9k
  status = write_NC(ncp);
909
13.9k
  if(status != NC_NOERR)
910
0
    return status;
911
912
  /* fill mode is now per variable */
913
13.9k
  {
914
13.9k
    if(NC_IsNew(ncp))
915
13.9k
    {
916
13.9k
      status = fillerup(ncp);
917
13.9k
      if(status != NC_NOERR)
918
0
        return status;
919
920
13.9k
    }
921
0
    else if(ncp->old == NULL ? 0
922
0
                                         : (ncp->vars.nelems > ncp->old->vars.nelems))
923
0
          {
924
0
            status = fill_added(ncp, ncp->old);
925
0
            if(status != NC_NOERR)
926
0
              return status;
927
0
            status = fill_added_recs(ncp, ncp->old);
928
0
            if(status != NC_NOERR)
929
0
              return status;
930
0
          }
931
13.9k
  }
932
933
13.9k
  if(ncp->old != NULL)
934
0
  {
935
0
    free_NC3INFO(ncp->old);
936
0
    ncp->old = NULL;
937
0
  }
938
939
13.9k
  fClr(ncp->flags, NC_CREAT | NC_INDEF);
940
941
13.9k
  return ncio_sync(ncp->nciop);
942
13.9k
}
943
944
945
/*
946
 * Compute the expected size of the file.
947
 */
948
int
949
NC_calcsize(const NC3_INFO *ncp, off_t *calcsizep)
950
27.8k
{
951
27.8k
  NC_var **vpp = (NC_var **)ncp->vars.value;
952
27.8k
  NC_var *const *const end = &vpp[ncp->vars.nelems];
953
27.8k
  NC_var *last_fix = NULL; /* last "non-record" var */
954
27.8k
  int numrecvars = 0; /* number of record variables */
955
956
27.8k
  if(ncp->vars.nelems == 0) { /* no non-record variables and
957
               no record variables */
958
8.06k
      *calcsizep = ncp->xsz; /* size of header */
959
8.06k
      return NC_NOERR;
960
8.06k
  }
961
962
197k
  for( /*NADA*/; vpp < end; vpp++) {
963
177k
      if(IS_RECVAR(*vpp)) {
964
6.11k
    numrecvars++;
965
171k
      } else {
966
171k
    last_fix = *vpp;
967
171k
      }
968
177k
  }
969
970
19.8k
  if(numrecvars == 0) {
971
17.6k
      off_t varsize;
972
17.6k
      assert(last_fix != NULL);
973
17.6k
      varsize = last_fix->len;
974
17.6k
      if(last_fix->len == X_UINT_MAX) { /* huge last fixed var */
975
0
    int i;
976
0
    varsize = 1;
977
0
            for(i = 0; i < last_fix->ndims; i++ ) {
978
0
                varsize *= (last_fix->shape ? last_fix->shape[i] : 1);
979
0
        }
980
0
      }
981
17.6k
      *calcsizep = last_fix->begin + varsize;
982
      /*last_var = last_fix;*/
983
17.6k
  } else {       /* we have at least one record variable */
984
2.17k
      *calcsizep = ncp->begin_rec + ncp->numrecs * ncp->recsize;
985
2.17k
  }
986
987
19.8k
  return NC_NOERR;
988
19.8k
}
989
990
/* Public */
991
992
#if 0 /* no longer needed */
993
int NC3_new_nc(NC3_INFO** ncpp)
994
{
995
  NC *nc;
996
  NC3_INFO* nc3;
997
998
  ncp = (NC *) malloc(sizeof(NC));
999
  if(ncp == NULL)
1000
    return NC_ENOMEM;
1001
  (void) memset(ncp, 0, sizeof(NC));
1002
1003
  ncp->xsz = MIN_NC_XSZ;
1004
  assert(ncp->xsz == ncx_len_NC(ncp,0));
1005
1006
        if(ncpp) *ncpp = ncp;
1007
        return NC_NOERR;
1008
1009
}
1010
#endif
1011
1012
/* WARNING: SIGNATURE CHANGE */
1013
int
1014
NC3_create(const char *path, int ioflags, size_t initialsz, int basepe,
1015
           size_t *chunksizehintp, void *parameters,
1016
           const NC_Dispatch *dispatch, int ncid)
1017
13.9k
{
1018
13.9k
  int status = NC_NOERR;
1019
13.9k
  void *xp = NULL;
1020
13.9k
  int sizeof_off_t = 0;
1021
13.9k
        NC *nc;
1022
13.9k
  NC3_INFO* nc3 = NULL;
1023
1024
        /* Find NC struct for this file. */
1025
13.9k
        if ((status = NC_check_id(ncid, &nc)))
1026
0
            return status;
1027
1028
  /* Create our specific NC3_INFO instance */
1029
13.9k
  nc3 = new_NC3INFO(chunksizehintp);
1030
1031
#if ALWAYS_NC_SHARE /* DEBUG */
1032
  fSet(ioflags, NC_SHARE);
1033
#endif
1034
1035
  /*
1036
   * Only pe 0 is valid
1037
   */
1038
13.9k
  if(basepe != 0) {
1039
0
            if(nc3) free(nc3);
1040
0
            return NC_EINVAL;
1041
0
        }
1042
13.9k
  assert(nc3->flags == 0);
1043
1044
  /* Now we can set min size */
1045
13.9k
  if (fIsSet(ioflags, NC_64BIT_DATA))
1046
0
      nc3->xsz = MIN_NC5_XSZ; /* CDF-5 has minimum 16 extra bytes */
1047
13.9k
  else
1048
13.9k
      nc3->xsz = MIN_NC3_XSZ;
1049
1050
13.9k
  if (fIsSet(ioflags, NC_64BIT_OFFSET)) {
1051
0
      fSet(nc3->flags, NC_64BIT_OFFSET);
1052
0
      sizeof_off_t = 8;
1053
13.9k
  } else if (fIsSet(ioflags, NC_64BIT_DATA)) {
1054
0
      fSet(nc3->flags, NC_64BIT_DATA);
1055
0
      sizeof_off_t = 8;
1056
13.9k
  } else {
1057
13.9k
    sizeof_off_t = 4;
1058
13.9k
  }
1059
1060
13.9k
  assert(nc3->xsz == ncx_len_NC(nc3,sizeof_off_t));
1061
1062
13.9k
        status =  ncio_create(path, ioflags, initialsz,
1063
13.9k
            0, nc3->xsz, &nc3->chunk, NULL,
1064
13.9k
            &nc3->nciop, &xp);
1065
13.9k
  if(status != NC_NOERR)
1066
0
  {
1067
    /* translate error status */
1068
0
    if(status == EEXIST)
1069
0
      status = NC_EEXIST;
1070
0
    goto unwind_alloc;
1071
0
  }
1072
1073
13.9k
  fSet(nc3->flags, NC_CREAT);
1074
1075
13.9k
  if(fIsSet(nc3->nciop->ioflags, NC_SHARE))
1076
0
  {
1077
    /*
1078
     * NC_SHARE implies sync up the number of records as well.
1079
     * (File format version one.)
1080
     * Note that other header changes are not shared
1081
     * automatically.  Some sort of IPC (external to this package)
1082
     * would be used to trigger a call to nc_sync().
1083
     */
1084
0
    fSet(nc3->flags, NC_NSYNC);
1085
0
  }
1086
1087
13.9k
  status = ncx_put_NC(nc3, &xp, sizeof_off_t, nc3->xsz);
1088
13.9k
  if(status != NC_NOERR)
1089
0
    goto unwind_ioc;
1090
1091
13.9k
  if(chunksizehintp != NULL)
1092
0
    *chunksizehintp = nc3->chunk;
1093
1094
  /* Link nc3 and nc */
1095
13.9k
        NC3_DATA_SET(nc,nc3);
1096
13.9k
  nc->int_ncid = nc3->nciop->fd;
1097
1098
13.9k
  return NC_NOERR;
1099
1100
0
unwind_ioc:
1101
0
  if(nc3 != NULL) {
1102
0
      (void) ncio_close(nc3->nciop, 1); /* N.B.: unlink */
1103
0
      nc3->nciop = NULL;
1104
0
  }
1105
  /*FALLTHRU*/
1106
0
unwind_alloc:
1107
0
  free_NC3INFO(nc3);
1108
0
  if(nc)
1109
0
            NC3_DATA_SET(nc,NULL);
1110
0
  return status;
1111
0
}
1112
1113
#if 0
1114
/* This function sets a default create flag that will be logically
1115
   or'd to whatever flags are passed into nc_create for all future
1116
   calls to nc_create.
1117
   Valid default create flags are NC_64BIT_OFFSET, NC_CDF5, NC_CLOBBER,
1118
   NC_LOCK, NC_SHARE. */
1119
int
1120
nc_set_default_format(int format, int *old_formatp)
1121
{
1122
    /* Return existing format if desired. */
1123
    if (old_formatp)
1124
      *old_formatp = default_create_format;
1125
1126
    /* Make sure only valid format is set. */
1127
#ifdef USE_NETCDF4
1128
    if (format != NC_FORMAT_CLASSIC && format != NC_FORMAT_64BIT_OFFSET &&
1129
  format != NC_FORMAT_NETCDF4 && format != NC_FORMAT_NETCDF4_CLASSIC)
1130
      return NC_EINVAL;
1131
#else
1132
    if (format != NC_FORMAT_CLASSIC && format != NC_FORMAT_64BIT_OFFSET
1133
#ifdef ENABLE_CDF5
1134
        && format != NC_FORMAT_CDF5
1135
#endif
1136
        )
1137
      return NC_EINVAL;
1138
#endif
1139
    default_create_format = format;
1140
    return NC_NOERR;
1141
}
1142
#endif
1143
1144
int
1145
NC3_open(const char *path, int ioflags, int basepe, size_t *chunksizehintp,
1146
         void *parameters, const NC_Dispatch *dispatch, int ncid)
1147
13.9k
{
1148
13.9k
  int status;
1149
13.9k
  NC3_INFO* nc3 = NULL;
1150
13.9k
        NC *nc;
1151
1152
        /* Find NC struct for this file. */
1153
13.9k
        if ((status = NC_check_id(ncid, &nc)))
1154
0
            return status;
1155
1156
  /* Create our specific NC3_INFO instance */
1157
13.9k
  nc3 = new_NC3INFO(chunksizehintp);
1158
1159
#if ALWAYS_NC_SHARE /* DEBUG */
1160
  fSet(ioflags, NC_SHARE);
1161
#endif
1162
1163
  /*
1164
   * Only pe 0 is valid.
1165
   */
1166
13.9k
  if(basepe != 0) {
1167
0
            if(nc3) {
1168
0
                free(nc3);
1169
0
                nc3 = NULL;
1170
0
            }
1171
0
            status = NC_EINVAL;
1172
0
            goto unwind_alloc;
1173
0
        }
1174
1175
#ifdef ENABLE_BYTERANGE
1176
    /* If the model specified the use of byte-ranges, then signal by
1177
       a temporary hack using one of the flags in the ioflags.
1178
    */
1179
    if(NC_testmode(path,"bytes"))
1180
        ioflags |= NC_HTTP;
1181
#endif /*ENABLE_BYTERANGE*/
1182
1183
13.9k
        status = ncio_open(path, ioflags, 0, 0, &nc3->chunk, parameters,
1184
13.9k
             &nc3->nciop, NULL);
1185
13.9k
  if(status)
1186
0
    goto unwind_alloc;
1187
1188
13.9k
  assert(nc3->flags == 0);
1189
1190
13.9k
  if(fIsSet(nc3->nciop->ioflags, NC_SHARE))
1191
0
  {
1192
    /*
1193
     * NC_SHARE implies sync up the number of records as well.
1194
     * (File format version one.)
1195
     * Note that other header changes are not shared
1196
     * automatically.  Some sort of IPC (external to this package)
1197
     * would be used to trigger a call to nc_sync().
1198
     */
1199
0
    fSet(nc3->flags, NC_NSYNC);
1200
0
  }
1201
1202
13.9k
  status = nc_get_NC(nc3);
1203
13.9k
  if(status != NC_NOERR)
1204
0
    goto unwind_ioc;
1205
1206
13.9k
  if(chunksizehintp != NULL)
1207
0
    *chunksizehintp = nc3->chunk;
1208
1209
  /* Link nc3 and nc */
1210
13.9k
        NC3_DATA_SET(nc,nc3);
1211
13.9k
  nc->int_ncid = nc3->nciop->fd;
1212
1213
13.9k
  return NC_NOERR;
1214
1215
0
unwind_ioc:
1216
0
  if(nc3) {
1217
0
          (void) ncio_close(nc3->nciop, 0);
1218
0
      nc3->nciop = NULL;
1219
0
  }
1220
  /*FALLTHRU*/
1221
0
unwind_alloc:
1222
0
  free_NC3INFO(nc3);
1223
0
  if(nc)
1224
0
            NC3_DATA_SET(nc,NULL);
1225
0
  return status;
1226
0
}
1227
1228
int
1229
NC3__enddef(int ncid,
1230
  size_t h_minfree, size_t v_align,
1231
  size_t v_minfree, size_t r_align)
1232
2.23k
{
1233
2.23k
  int status;
1234
2.23k
  NC *nc;
1235
2.23k
  NC3_INFO* nc3;
1236
1237
2.23k
  status = NC_check_id(ncid, &nc);
1238
2.23k
  if(status != NC_NOERR)
1239
0
    return status;
1240
2.23k
  nc3 = NC3_DATA(nc);
1241
1242
2.23k
  if(!NC_indef(nc3))
1243
0
    return(NC_ENOTINDEFINE);
1244
1245
2.23k
  return (NC_endef(nc3, h_minfree, v_align, v_minfree, r_align));
1246
2.23k
}
1247
1248
/*
1249
 * In data mode, same as ncclose.
1250
 * In define mode, restore previous definition.
1251
 * In create, remove the file.
1252
 */
1253
int
1254
NC3_abort(int ncid)
1255
0
{
1256
0
  int status;
1257
0
  NC *nc;
1258
0
  NC3_INFO* nc3;
1259
0
  int doUnlink = 0;
1260
1261
0
  status = NC_check_id(ncid, &nc);
1262
0
  if(status != NC_NOERR)
1263
0
      return status;
1264
0
  nc3 = NC3_DATA(nc);
1265
1266
0
  doUnlink = NC_IsNew(nc3);
1267
1268
0
  if(nc3->old != NULL)
1269
0
  {
1270
    /* a plain redef, not a create */
1271
0
    assert(!NC_IsNew(nc3));
1272
0
    assert(fIsSet(nc3->flags, NC_INDEF));
1273
0
    free_NC3INFO(nc3->old);
1274
0
    nc3->old = NULL;
1275
0
    fClr(nc3->flags, NC_INDEF);
1276
0
  }
1277
0
  else if(!NC_readonly(nc3))
1278
0
  {
1279
0
    status = NC_sync(nc3);
1280
0
    if(status != NC_NOERR)
1281
0
      return status;
1282
0
  }
1283
1284
1285
0
  (void) ncio_close(nc3->nciop, doUnlink);
1286
0
  nc3->nciop = NULL;
1287
1288
0
  free_NC3INFO(nc3);
1289
0
  if(nc)
1290
0
            NC3_DATA_SET(nc,NULL);
1291
1292
0
  return NC_NOERR;
1293
0
}
1294
1295
int
1296
NC3_close(int ncid, void* params)
1297
27.8k
{
1298
27.8k
  int status = NC_NOERR;
1299
27.8k
  NC *nc;
1300
27.8k
  NC3_INFO* nc3;
1301
1302
27.8k
  status = NC_check_id(ncid, &nc);
1303
27.8k
  if(status != NC_NOERR)
1304
0
      return status;
1305
27.8k
  nc3 = NC3_DATA(nc);
1306
1307
27.8k
  if(NC_indef(nc3))
1308
11.7k
  {
1309
11.7k
    status = NC_endef(nc3, 0, 1, 0, 1); /* TODO: defaults */
1310
11.7k
    if(status != NC_NOERR )
1311
0
    {
1312
0
      (void) NC3_abort(ncid);
1313
0
      return status;
1314
0
    }
1315
11.7k
  }
1316
16.1k
  else if(!NC_readonly(nc3))
1317
2.23k
  {
1318
2.23k
    status = NC_sync(nc3);
1319
    /* flush buffers before any filesize comparisons */
1320
2.23k
    (void) ncio_sync(nc3->nciop);
1321
2.23k
  }
1322
1323
  /*
1324
   * If file opened for writing and filesize is less than
1325
   * what it should be (due to previous use of NOFILL mode),
1326
   * pad it to correct size, as reported by NC_calcsize().
1327
   */
1328
27.8k
  if (status == NC_NOERR) {
1329
27.8k
      off_t filesize;   /* current size of open file */
1330
27.8k
      off_t calcsize; /* calculated file size, from header */
1331
27.8k
      status = ncio_filesize(nc3->nciop, &filesize);
1332
27.8k
      if(status != NC_NOERR)
1333
0
    return status;
1334
27.8k
      status = NC_calcsize(nc3, &calcsize);
1335
27.8k
      if(status != NC_NOERR)
1336
0
    return status;
1337
27.8k
      if(filesize < calcsize && !NC_readonly(nc3)) {
1338
0
    status = ncio_pad_length(nc3->nciop, calcsize);
1339
0
    if(status != NC_NOERR)
1340
0
        return status;
1341
0
      }
1342
27.8k
  }
1343
1344
27.8k
  if(params != NULL && (nc->mode & NC_INMEMORY) != 0) {
1345
0
      NC_memio* memio = (NC_memio*)params;
1346
            /* Extract the final memory size &/or contents */
1347
0
            status = memio_extract(nc3->nciop,&memio->size,&memio->memory);
1348
0
        }
1349
1350
27.8k
  (void) ncio_close(nc3->nciop, 0);
1351
27.8k
  nc3->nciop = NULL;
1352
1353
27.8k
  free_NC3INFO(nc3);
1354
27.8k
        NC3_DATA_SET(nc,NULL);
1355
1356
27.8k
  return status;
1357
27.8k
}
1358
1359
int
1360
NC3_redef(int ncid)
1361
0
{
1362
0
  int status;
1363
0
  NC *nc;
1364
0
  NC3_INFO* nc3;
1365
1366
0
  status = NC_check_id(ncid, &nc);
1367
0
  if(status != NC_NOERR)
1368
0
    return status;
1369
0
  nc3 = NC3_DATA(nc);
1370
1371
0
  if(NC_readonly(nc3))
1372
0
    return NC_EPERM;
1373
1374
0
  if(NC_indef(nc3))
1375
0
    return NC_EINDEFINE;
1376
1377
1378
0
  if(fIsSet(nc3->nciop->ioflags, NC_SHARE))
1379
0
  {
1380
    /* read in from disk */
1381
0
    status = read_NC(nc3);
1382
0
    if(status != NC_NOERR)
1383
0
      return status;
1384
0
  }
1385
1386
0
  nc3->old = dup_NC3INFO(nc3);
1387
0
  if(nc3->old == NULL)
1388
0
    return NC_ENOMEM;
1389
1390
0
  fSet(nc3->flags, NC_INDEF);
1391
1392
0
  return NC_NOERR;
1393
0
}
1394
1395
1396
int
1397
NC3_inq(int ncid,
1398
  int *ndimsp,
1399
  int *nvarsp,
1400
  int *nattsp,
1401
  int *xtendimp)
1402
57.0k
{
1403
57.0k
  int status;
1404
57.0k
  NC *nc;
1405
57.0k
  NC3_INFO* nc3;
1406
1407
57.0k
  status = NC_check_id(ncid, &nc);
1408
57.0k
  if(status != NC_NOERR)
1409
0
    return status;
1410
57.0k
  nc3 = NC3_DATA(nc);
1411
1412
57.0k
  if(ndimsp != NULL)
1413
14.9k
    *ndimsp = (int) nc3->dims.nelems;
1414
57.0k
  if(nvarsp != NULL)
1415
42.1k
    *nvarsp = (int) nc3->vars.nelems;
1416
57.0k
  if(nattsp != NULL)
1417
27.8k
    *nattsp = (int) nc3->attrs.nelems;
1418
57.0k
  if(xtendimp != NULL)
1419
13.9k
    *xtendimp = find_NC_Udim(&nc3->dims, NULL);
1420
1421
57.0k
  return NC_NOERR;
1422
57.0k
}
1423
1424
int
1425
NC3_inq_unlimdim(int ncid, int *xtendimp)
1426
0
{
1427
0
  int status;
1428
0
  NC *nc;
1429
0
  NC3_INFO* nc3;
1430
1431
0
  status = NC_check_id(ncid, &nc);
1432
0
  if(status != NC_NOERR)
1433
0
    return status;
1434
0
  nc3 = NC3_DATA(nc);
1435
1436
0
  if(xtendimp != NULL)
1437
0
    *xtendimp = find_NC_Udim(&nc3->dims, NULL);
1438
1439
0
  return NC_NOERR;
1440
0
}
1441
1442
int
1443
NC3_sync(int ncid)
1444
0
{
1445
0
  int status;
1446
0
  NC *nc;
1447
0
  NC3_INFO* nc3;
1448
1449
0
  status = NC_check_id(ncid, &nc);
1450
0
  if(status != NC_NOERR)
1451
0
    return status;
1452
0
  nc3 = NC3_DATA(nc);
1453
1454
0
  if(NC_indef(nc3))
1455
0
    return NC_EINDEFINE;
1456
1457
0
  if(NC_readonly(nc3))
1458
0
  {
1459
0
    return read_NC(nc3);
1460
0
  }
1461
  /* else, read/write */
1462
1463
0
  status = NC_sync(nc3);
1464
0
  if(status != NC_NOERR)
1465
0
    return status;
1466
1467
0
  status = ncio_sync(nc3->nciop);
1468
0
  if(status != NC_NOERR)
1469
0
    return status;
1470
1471
#ifdef USE_FSYNC
1472
  /* may improve concurrent access, but slows performance if
1473
   * called frequently */
1474
#ifndef _WIN32
1475
  status = fsync(nc3->nciop->fd);
1476
#else
1477
  status = _commit(nc3->nciop->fd);
1478
#endif  /* _WIN32 */
1479
#endif  /* USE_FSYNC */
1480
1481
0
  return status;
1482
0
}
1483
1484
1485
int
1486
NC3_set_fill(int ncid,
1487
  int fillmode, int *old_mode_ptr)
1488
0
{
1489
0
  int i, status;
1490
0
  NC *nc;
1491
0
  NC3_INFO* nc3;
1492
0
  int oldmode;
1493
1494
0
  status = NC_check_id(ncid, &nc);
1495
0
  if(status != NC_NOERR)
1496
0
    return status;
1497
0
  nc3 = NC3_DATA(nc);
1498
1499
0
  if(NC_readonly(nc3))
1500
0
    return NC_EPERM;
1501
1502
0
  oldmode = fIsSet(nc3->flags, NC_NOFILL) ? NC_NOFILL : NC_FILL;
1503
1504
0
  if(fillmode == NC_NOFILL)
1505
0
  {
1506
0
    fSet(nc3->flags, NC_NOFILL);
1507
0
  }
1508
0
  else if(fillmode == NC_FILL)
1509
0
  {
1510
0
    if(fIsSet(nc3->flags, NC_NOFILL))
1511
0
    {
1512
      /*
1513
       * We are changing back to fill mode
1514
       * so do a sync
1515
       */
1516
0
      status = NC_sync(nc3);
1517
0
      if(status != NC_NOERR)
1518
0
        return status;
1519
0
    }
1520
0
    fClr(nc3->flags, NC_NOFILL);
1521
0
  }
1522
0
  else
1523
0
  {
1524
0
    return NC_EINVAL; /* Invalid fillmode */
1525
0
  }
1526
1527
0
  if(old_mode_ptr != NULL)
1528
0
    *old_mode_ptr = oldmode;
1529
1530
  /* loop thru all variables to set/overwrite its fill mode */
1531
0
  for (i=0; i<nc3->vars.nelems; i++)
1532
0
    nc3->vars.value[i]->no_fill = (fillmode == NC_NOFILL);
1533
1534
  /* once the file's fill mode is set, any new variables defined after
1535
   * this call will check NC_dofill(nc3) and set their no_fill accordingly.
1536
   * See NC3_def_var() */
1537
1538
0
  return NC_NOERR;
1539
0
}
1540
1541
/**
1542
 * Return the file format.
1543
 *
1544
 * \param ncid the ID of the open file.
1545
1546
 * \param formatp a pointer that gets the format. Ignored if NULL.
1547
 *
1548
 * \returns NC_NOERR No error.
1549
 * \returns NC_EBADID Bad ncid.
1550
 * \internal
1551
 * \author Ed Hartnett, Dennis Heimbigner
1552
 */
1553
int
1554
NC3_inq_format(int ncid, int *formatp)
1555
14.2k
{
1556
14.2k
   int status;
1557
14.2k
   NC *nc;
1558
14.2k
   NC3_INFO* nc3;
1559
1560
14.2k
   status = NC_check_id(ncid, &nc);
1561
14.2k
   if(status != NC_NOERR)
1562
0
      return status;
1563
14.2k
   nc3 = NC3_DATA(nc);
1564
1565
   /* Why even call this function with no format pointer? */
1566
14.2k
   if (!formatp)
1567
0
      return NC_NOERR;
1568
1569
   /* only need to check for netCDF-3 variants, since this is never called for netCDF-4 files */
1570
14.2k
#ifdef ENABLE_CDF5
1571
14.2k
   if (fIsSet(nc3->flags, NC_64BIT_DATA))
1572
0
      *formatp = NC_FORMAT_CDF5;
1573
14.2k
   else
1574
14.2k
#endif
1575
14.2k
      if (fIsSet(nc3->flags, NC_64BIT_OFFSET))
1576
0
         *formatp = NC_FORMAT_64BIT_OFFSET;
1577
14.2k
      else
1578
14.2k
         *formatp = NC_FORMAT_CLASSIC;
1579
14.2k
   return NC_NOERR;
1580
14.2k
}
1581
1582
/**
1583
 * Return the extended format (i.e. the dispatch model), plus the mode
1584
 * associated with an open file.
1585
 *
1586
 * \param ncid the ID of the open file.
1587
 * \param formatp a pointer that gets the extended format. Note that
1588
 * this is not the same as the format provided by nc_inq_format(). The
1589
 * extended format indicates the dispatch layer model. Classic, 64-bit
1590
 * offset, and CDF5 files all have an extended format of
1591
 * ::NC_FORMATX_NC3. Ignored if NULL.
1592
 * \param modep a pointer that gets the open/create mode associated with
1593
 * this file. Ignored if NULL.
1594
 *
1595
 * \returns NC_NOERR No error.
1596
 * \returns NC_EBADID Bad ncid.
1597
 * \internal
1598
 * \author Dennis Heimbigner
1599
 */
1600
int
1601
NC3_inq_format_extended(int ncid, int *formatp, int *modep)
1602
0
{
1603
0
   int status;
1604
0
   NC *nc;
1605
1606
0
   status = NC_check_id(ncid, &nc);
1607
0
   if(status != NC_NOERR)
1608
0
      return status;
1609
0
   if(formatp) *formatp = NC_FORMATX_NC3;
1610
0
   if(modep) *modep = nc->mode;
1611
0
   return NC_NOERR;
1612
0
}
1613
1614
/**
1615
 * Determine name and size of netCDF type. This netCDF-4 function
1616
 * proved so popular that a netCDF-classic version is provided. You're
1617
 * welcome.
1618
 *
1619
 * \param ncid The ID of an open file.
1620
 * \param typeid The ID of a netCDF type.
1621
 * \param name Pointer that will get the name of the type. Maximum
1622
 * size will be NC_MAX_NAME. Ignored if NULL.
1623
 * \param size Pointer that will get size of type in bytes. Ignored if
1624
 * null.
1625
 *
1626
 * \returns NC_NOERR No error.
1627
 * \returns NC_EBADID Bad ncid.
1628
 * \returns NC_EBADTYPE Bad typeid.
1629
 * \internal
1630
 * \author Ed Hartnett
1631
 */
1632
int
1633
NC3_inq_type(int ncid, nc_type typeid, char *name, size_t *size)
1634
0
{
1635
0
   NC *ncp;
1636
0
   int stat = NC_check_id(ncid, &ncp);
1637
0
   if (stat != NC_NOERR)
1638
0
      return stat;
1639
1640
0
   if(typeid < NC_BYTE || typeid > NC_STRING)
1641
0
      return NC_EBADTYPE;
1642
1643
   /* Give the user the values they want. */
1644
0
   if (name)
1645
0
      strcpy(name, NC_atomictypename(typeid));
1646
0
   if (size)
1647
0
      *size = NC_atomictypelen(typeid);
1648
1649
0
   return NC_NOERR;
1650
0
}
1651
1652
/**
1653
 * This is an obsolete form of nc_delete(), supported for backwards
1654
 * compatibility.
1655
 *
1656
 * @param path Filename to delete.
1657
 * @param basepe Must be 0.
1658
 *
1659
 * @return ::NC_NOERR No error.
1660
 * @return ::NC_EIO Couldn't delete file.
1661
 * @return ::NC_EINVAL Invaliod basepe. Must be 0.
1662
 * @author Glenn Davis, Ed Hartnett
1663
 */
1664
int
1665
nc_delete_mp(const char * path, int basepe)
1666
0
{
1667
0
  NC *nc;
1668
0
  int status;
1669
0
  int ncid;
1670
1671
0
  status = nc_open(path,NC_NOWRITE,&ncid);
1672
0
        if(status) return status;
1673
1674
0
  status = NC_check_id(ncid,&nc);
1675
0
        if(status) return status;
1676
1677
  /*
1678
   * Only pe 0 is valid.
1679
   */
1680
0
  if(basepe != 0)
1681
0
    return NC_EINVAL;
1682
1683
0
  (void) nc_close(ncid);
1684
0
  if(unlink(path) == -1) {
1685
0
      return NC_EIO; /* No more specific error code is appropriate */
1686
0
  }
1687
0
  return NC_NOERR;
1688
0
}
1689
1690
int
1691
nc_delete(const char * path)
1692
0
{
1693
0
        return nc_delete_mp(path, 0);
1694
0
}
1695
1696
/*----< NC3_inq_default_fill_value() >---------------------------------------*/
1697
/* copy the default fill value to the memory space pointed by fillp */
1698
int
1699
NC3_inq_default_fill_value(int xtype, void *fillp)
1700
241k
{
1701
241k
    if (fillp == NULL) return NC_NOERR;
1702
1703
241k
    switch(xtype) {
1704
114k
        case NC_CHAR   :               *(char*)fillp = NC_FILL_CHAR;   break;
1705
14.6k
        case NC_BYTE   :        *(signed char*)fillp = NC_FILL_BYTE;   break;
1706
23.7k
        case NC_SHORT  :              *(short*)fillp = NC_FILL_SHORT;  break;
1707
78.1k
        case NC_INT    :                *(int*)fillp = NC_FILL_INT;    break;
1708
0
        case NC_FLOAT  :              *(float*)fillp = NC_FILL_FLOAT;  break;
1709
10.8k
        case NC_DOUBLE :             *(double*)fillp = NC_FILL_DOUBLE; break;
1710
0
        case NC_UBYTE  :      *(unsigned char*)fillp = NC_FILL_UBYTE;  break;
1711
0
        case NC_USHORT :     *(unsigned short*)fillp = NC_FILL_USHORT; break;
1712
0
        case NC_UINT   :       *(unsigned int*)fillp = NC_FILL_UINT;   break;
1713
0
        case NC_INT64  :          *(long long*)fillp = NC_FILL_INT64;  break;
1714
0
        case NC_UINT64 : *(unsigned long long*)fillp = NC_FILL_UINT64; break;
1715
0
        default : return NC_EBADTYPE;
1716
241k
    }
1717
241k
    return NC_NOERR;
1718
241k
}
1719
1720
1721
/*----< NC3_inq_var_fill() >-------------------------------------------------*/
1722
/* inquire the fill value of a variable */
1723
int
1724
NC3_inq_var_fill(const NC_var *varp, void *fill_value)
1725
0
{
1726
0
    NC_attr **attrpp = NULL;
1727
1728
0
    if (fill_value == NULL) return NC_EINVAL;
1729
1730
    /*
1731
     * find fill value
1732
     */
1733
0
    attrpp = NC_findattr(&varp->attrs, _FillValue);
1734
0
    if ( attrpp != NULL ) {
1735
0
        const void *xp;
1736
        /* User defined fill value */
1737
0
        if ( (*attrpp)->type != varp->type || (*attrpp)->nelems != 1 )
1738
0
            return NC_EBADTYPE;
1739
1740
0
        xp = (*attrpp)->xvalue;
1741
        /* value stored in xvalue is in external representation, may need byte-swap */
1742
0
        switch(varp->type) {
1743
0
            case NC_CHAR:   return ncx_getn_text               (&xp, 1,               (char*)fill_value);
1744
0
            case NC_BYTE:   return ncx_getn_schar_schar        (&xp, 1,        (signed char*)fill_value);
1745
0
            case NC_UBYTE:  return ncx_getn_uchar_uchar        (&xp, 1,      (unsigned char*)fill_value);
1746
0
            case NC_SHORT:  return ncx_getn_short_short        (&xp, 1,              (short*)fill_value);
1747
0
            case NC_USHORT: return ncx_getn_ushort_ushort      (&xp, 1,     (unsigned short*)fill_value);
1748
0
            case NC_INT:    return ncx_getn_int_int            (&xp, 1,                (int*)fill_value);
1749
0
            case NC_UINT:   return ncx_getn_uint_uint          (&xp, 1,       (unsigned int*)fill_value);
1750
0
            case NC_FLOAT:  return ncx_getn_float_float        (&xp, 1,              (float*)fill_value);
1751
0
            case NC_DOUBLE: return ncx_getn_double_double      (&xp, 1,             (double*)fill_value);
1752
0
            case NC_INT64:  return ncx_getn_longlong_longlong  (&xp, 1,          (long long*)fill_value);
1753
0
            case NC_UINT64: return ncx_getn_ulonglong_ulonglong(&xp, 1, (unsigned long long*)fill_value);
1754
0
            default: return NC_EBADTYPE;
1755
0
        }
1756
0
    }
1757
0
    else {
1758
        /* use the default */
1759
0
        switch(varp->type){
1760
0
            case NC_CHAR:                *(char *)fill_value = NC_FILL_CHAR;
1761
0
                 break;
1762
0
            case NC_BYTE:          *(signed char *)fill_value = NC_FILL_BYTE;
1763
0
                 break;
1764
0
            case NC_SHORT:               *(short *)fill_value = NC_FILL_SHORT;
1765
0
                 break;
1766
0
            case NC_INT:                   *(int *)fill_value = NC_FILL_INT;
1767
0
                 break;
1768
0
            case NC_UBYTE:       *(unsigned char *)fill_value = NC_FILL_UBYTE;
1769
0
                 break;
1770
0
            case NC_USHORT:     *(unsigned short *)fill_value = NC_FILL_USHORT;
1771
0
                 break;
1772
0
            case NC_UINT:         *(unsigned int *)fill_value = NC_FILL_UINT;
1773
0
                 break;
1774
0
            case NC_INT64:           *(long long *)fill_value = NC_FILL_INT64;
1775
0
                 break;
1776
0
            case NC_UINT64: *(unsigned long long *)fill_value = NC_FILL_UINT64;
1777
0
                 break;
1778
0
            case NC_FLOAT:               *(float *)fill_value = NC_FILL_FLOAT;
1779
0
                 break;
1780
0
            case NC_DOUBLE:             *(double *)fill_value = NC_FILL_DOUBLE;
1781
0
                 break;
1782
0
            default:
1783
0
                 return NC_EINVAL;
1784
0
        }
1785
0
    }
1786
0
    return NC_NOERR;
1787
0
}