Coverage Report

Created: 2025-10-28 07:06

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