Coverage Report

Created: 2023-05-28 06:42

/src/netcdf-c/libsrc/v1hpg.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 *  Copyright 2018, University 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 <stdio.h>
12
#include <string.h>
13
#include <assert.h>
14
#include "nc3internal.h"
15
#include "rnd.h"
16
#include "ncx.h"
17
18
/*
19
 * This module defines the external representation
20
 * of the "header" of a netcdf version one file and
21
 * the version two variant that uses 64-bit file
22
 * offsets instead of the 32-bit file offsets in version
23
 * one files.
24
 * For each of the components of the NC structure,
25
 * There are (static) ncx_len_XXX(), v1h_put_XXX()
26
 * and v1h_get_XXX() functions. These define the
27
 * external representation of the components.
28
 * The exported entry points for the whole NC structure
29
 * are built up from these.
30
 */
31
32
33
/*
34
 * "magic number" at beginning of file: 0x43444601 (big endian)
35
 * assert(sizeof(ncmagic) % X_ALIGN == 0);
36
 */
37
static const schar ncmagic[] = {'C', 'D', 'F', 0x02};
38
static const schar ncmagic1[] = {'C', 'D', 'F', 0x01};
39
static const schar ncmagic5[] = {'C', 'D', 'F', 0x05};
40
41
/*
42
 * v1hs == "Version 1 Header Stream"
43
 *
44
 * The netcdf file version 1 header is
45
 * of unknown and potentially unlimited size.
46
 * So, we don't know how much to get() on
47
 * the initial read. We build a stream, 'v1hs'
48
 * on top of ncio to do the header get.
49
 */
50
typedef struct v1hs {
51
  ncio *nciop;
52
  off_t offset; /* argument to nciop->get() */
53
  size_t extent;  /* argument to nciop->get() */
54
  int flags;  /* set to RGN_WRITE for write */
55
        int version;    /* format variant: NC_FORMAT_CLASSIC, NC_FORMAT_64BIT_OFFSET or NC_FORMAT_CDF5 */
56
  void *base; /* beginning of current buffer */
57
  void *pos;  /* current position in buffer */
58
  void *end;  /* end of current buffer = base + extent */
59
} v1hs;
60
61
62
/*
63
 * Release the stream, invalidate buffer
64
 */
65
static int
66
rel_v1hs(v1hs *gsp)
67
4.13k
{
68
4.13k
  int status;
69
4.13k
  if(gsp->offset == OFF_NONE || gsp->base == NULL)
70
77
        return NC_NOERR;
71
4.05k
  status = ncio_rel(gsp->nciop, gsp->offset,
72
4.05k
       gsp->flags == RGN_WRITE ? RGN_MODIFIED : 0);
73
4.05k
  gsp->end = NULL;
74
4.05k
  gsp->pos = NULL;
75
4.05k
  gsp->base = NULL;
76
4.05k
  return status;
77
4.13k
}
78
79
80
/*
81
 * Release the current chunk and get the next one.
82
 * Also used for initialization when gsp->base == NULL.
83
 */
84
static int
85
fault_v1hs(v1hs *gsp, size_t extent)
86
4.13k
{
87
4.13k
  int status;
88
89
4.13k
  if(gsp->base != NULL)
90
4.02k
  {
91
4.02k
    const ptrdiff_t incr = (char *)gsp->pos - (char *)gsp->base;
92
4.02k
    status = rel_v1hs(gsp);
93
4.02k
    if(status)
94
0
      return status;
95
4.02k
    gsp->offset += incr;
96
4.02k
  }
97
98
4.13k
  if(extent > gsp->extent)
99
144
    gsp->extent = extent;
100
101
4.13k
  status = ncio_get(gsp->nciop,
102
4.13k
      gsp->offset, gsp->extent,
103
4.13k
      gsp->flags, &gsp->base);
104
4.13k
  if(status)
105
77
    return status;
106
107
4.05k
  gsp->pos = gsp->base;
108
109
4.05k
  gsp->end = (char *)gsp->base + gsp->extent;
110
4.05k
    return NC_NOERR;
111
4.13k
}
112
113
114
/*
115
 * Ensure that 'nextread' bytes are available.
116
 */
117
static int
118
check_v1hs(v1hs *gsp, size_t nextread)
119
1.45M
{
120
121
#if 0 /* DEBUG */
122
fprintf(stderr, "nextread %lu, remaining %lu\n",
123
  (unsigned long)nextread,
124
  (unsigned long)((char *)gsp->end - (char *)gsp->pos));
125
#endif
126
1.45M
    if((char *)gsp->pos + nextread <= (char *)gsp->end)
127
1.44M
  return NC_NOERR;
128
129
4.02k
    return fault_v1hs(gsp, nextread);
130
1.45M
}
131
132
/* End v1hs */
133
134
/* Write a size_t to the header */
135
static int
136
v1h_put_size_t(v1hs *psp, const size_t *sp)
137
0
{
138
0
  int status;
139
0
  if (psp->version == 5) /* all integers in CDF-5 are 64 bits */
140
0
    status = check_v1hs(psp, X_SIZEOF_INT64);
141
0
  else
142
0
    status = check_v1hs(psp, X_SIZEOF_SIZE_T);
143
0
  if(status != NC_NOERR)
144
0
    return status;
145
0
        if (psp->version == 5) {
146
0
                unsigned long long tmp = (unsigned long long) (*sp);
147
0
    return ncx_put_uint64(&psp->pos, tmp);
148
0
        }
149
0
        else
150
0
      return ncx_put_size_t(&psp->pos, sp);
151
0
}
152
153
/* Read a size_t from the header */
154
static int
155
v1h_get_size_t(v1hs *gsp, size_t *sp)
156
812k
{
157
812k
  int status;
158
812k
  if (gsp->version == 5) /* all integers in CDF-5 are 64 bits */
159
217k
    status = check_v1hs(gsp, X_SIZEOF_INT64);
160
595k
  else
161
595k
    status = check_v1hs(gsp, X_SIZEOF_SIZE_T);
162
812k
  if(status != NC_NOERR)
163
26
    return status;
164
812k
        if (gsp->version == 5) {
165
217k
    unsigned long long tmp=0;
166
217k
    status = ncx_get_uint64((const void **)(&gsp->pos), &tmp);
167
217k
    *sp = (size_t)tmp;
168
217k
    return status;
169
217k
        }
170
595k
        else
171
595k
      return ncx_get_size_t((const void **)(&gsp->pos), sp);
172
812k
}
173
174
/* Begin nc_type */
175
176
0
#define X_SIZEOF_NC_TYPE X_SIZEOF_INT
177
178
/* Write a nc_type to the header */
179
static int
180
v1h_put_nc_type(v1hs *psp, const nc_type *typep)
181
0
{
182
0
    const unsigned int itype = (unsigned int) *typep;
183
0
    int status = check_v1hs(psp, X_SIZEOF_INT);
184
0
    if(status != NC_NOERR) return status;
185
0
    status =  ncx_put_uint32(&psp->pos, itype);
186
0
    return status;
187
0
}
188
189
190
/* Read a nc_type from the header */
191
static int
192
v1h_get_nc_type(v1hs *gsp, nc_type *typep)
193
92.0k
{
194
92.0k
    unsigned int type = 0;
195
92.0k
    int status = check_v1hs(gsp, X_SIZEOF_INT);
196
92.0k
    if(status != NC_NOERR) return status;
197
92.0k
    status =  ncx_get_uint32((const void**)(&gsp->pos), &type);
198
92.0k
    if(status != NC_NOERR)
199
0
    return status;
200
/* Fix 35382
201
  assert(type == NC_BYTE
202
    || type == NC_CHAR
203
    || type == NC_SHORT
204
    || type == NC_INT
205
    || type == NC_FLOAT
206
    || type == NC_DOUBLE
207
    || type == NC_UBYTE
208
    || type == NC_USHORT
209
    || type == NC_UINT
210
    || type == NC_INT64
211
    || type == NC_UINT64
212
    || type == NC_STRING);
213
*/
214
92.0k
    if(type == NC_NAT || type > NC_MAX_ATOMIC_TYPE)
215
11
        return NC_EINVAL;
216
92.0k
    else
217
92.0k
  *typep = (nc_type) type;
218
219
92.0k
    return NC_NOERR;
220
92.0k
}
221
222
/* End nc_type */
223
/* Begin NCtype (internal tags) */
224
225
6
#define X_SIZEOF_NCTYPE X_SIZEOF_INT
226
227
/* Write a NCtype to the header */
228
static int
229
v1h_put_NCtype(v1hs *psp, NCtype type)
230
0
{
231
0
    const unsigned int itype = (unsigned int) type;
232
0
    int status = check_v1hs(psp, X_SIZEOF_INT);
233
0
    if(status != NC_NOERR) return status;
234
0
    status = ncx_put_uint32(&psp->pos, itype);
235
0
    return status;
236
0
}
237
238
/* Read a NCtype from the header */
239
static int
240
v1h_get_NCtype(v1hs *gsp, NCtype *typep)
241
48.6k
{
242
48.6k
    unsigned int type = 0;
243
48.6k
    int status = check_v1hs(gsp, X_SIZEOF_INT);
244
48.6k
    if(status != NC_NOERR) return status;
245
48.6k
    status =  ncx_get_uint32((const void**)(&gsp->pos), &type);
246
48.6k
    if(status != NC_NOERR) return status;
247
    /* else */
248
48.6k
    *typep = (NCtype) type;
249
48.6k
    return NC_NOERR;
250
48.6k
}
251
252
/* End NCtype */
253
/* Begin NC_string */
254
255
/*
256
 * How much space will the xdr'd string take.
257
 * Formerly
258
NC_xlen_string(cdfstr)
259
 */
260
static size_t
261
ncx_len_NC_string(const NC_string *ncstrp, int version)
262
22
{
263
22
  size_t sz = (version == 5) ? X_SIZEOF_INT64 : X_SIZEOF_INT; /* nchars */
264
265
22
  assert(ncstrp != NULL);
266
267
22
  if(ncstrp->nchars != 0)
268
8
  {
269
#if 0
270
    assert(ncstrp->nchars % X_ALIGN == 0);
271
    sz += ncstrp->nchars;
272
#else
273
8
    sz += _RNDUP(ncstrp->nchars, X_ALIGN);
274
8
#endif
275
8
  }
276
22
  return sz;
277
22
}
278
279
280
/* Write a NC_string to the header */
281
static int
282
v1h_put_NC_string(v1hs *psp, const NC_string *ncstrp)
283
0
{
284
0
  int status;
285
286
#if 0
287
  assert(ncstrp->nchars % X_ALIGN == 0);
288
#endif
289
290
0
  status = v1h_put_size_t(psp, &ncstrp->nchars);
291
0
    if(status != NC_NOERR)
292
0
    return status;
293
0
  status = check_v1hs(psp, _RNDUP(ncstrp->nchars, X_ALIGN));
294
0
    if(status != NC_NOERR)
295
0
    return status;
296
0
  status = ncx_pad_putn_text(&psp->pos, ncstrp->nchars, ncstrp->cp);
297
0
    if(status != NC_NOERR)
298
0
    return status;
299
300
0
    return NC_NOERR;
301
0
}
302
303
304
/* Read a NC_string from the header */
305
static int
306
v1h_get_NC_string(v1hs *gsp, NC_string **ncstrpp)
307
357k
{
308
357k
  int status = 0;
309
357k
  size_t nchars = 0;
310
357k
  NC_string *ncstrp = NULL;
311
#if USE_STRICT_NULL_BYTE_HEADER_PADDING
312
        size_t padding = 0;        
313
#endif /* USE_STRICT_NULL_BYTE_HEADER_PADDING */
314
315
357k
  status = v1h_get_size_t(gsp, &nchars);
316
357k
  if(status != NC_NOERR)
317
7
    return status;
318
319
357k
  ncstrp = new_NC_string(nchars, NULL);
320
357k
  if(ncstrp == NULL)
321
2
  {
322
2
    return NC_ENOMEM;
323
2
  }
324
325
#if 0
326
/* assert(ncstrp->nchars == nchars || ncstrp->nchars - nchars < X_ALIGN); */
327
  assert(ncstrp->nchars % X_ALIGN == 0);
328
  status = check_v1hs(gsp, ncstrp->nchars);
329
#else
330
331
357k
  status = check_v1hs(gsp, _RNDUP(ncstrp->nchars, X_ALIGN));
332
357k
#endif
333
357k
  if(status != NC_NOERR)
334
13
    goto unwind_alloc;
335
336
357k
  status = ncx_pad_getn_text((const void **)(&gsp->pos),
337
357k
     nchars, ncstrp->cp);
338
357k
  if(status != NC_NOERR)
339
0
    goto unwind_alloc;
340
341
#if USE_STRICT_NULL_BYTE_HEADER_PADDING
342
  padding = _RNDUP(X_SIZEOF_CHAR * ncstrp->nchars, X_ALIGN)
343
    - X_SIZEOF_CHAR * ncstrp->nchars;
344
345
  if (padding > 0) {
346
    /* CDF specification: Header padding uses null (\x00) bytes. */
347
    char pad[X_ALIGN-1];
348
    memset(pad, 0, X_ALIGN-1);
349
    if (memcmp((char*)gsp->pos-padding, pad, padding) != 0) {
350
      free_NC_string(ncstrp);
351
      return NC_ENULLPAD;
352
    }
353
  }
354
#endif
355
356
357k
  *ncstrpp = ncstrp;
357
358
357k
  return NC_NOERR;
359
360
13
unwind_alloc:
361
13
  free_NC_string(ncstrp);
362
13
  return status;
363
357k
}
364
365
/* End NC_string */
366
/* Begin NC_dim */
367
368
/*
369
 * How much space will the xdr'd dim take.
370
 * Formerly
371
NC_xlen_dim(dpp)
372
 */
373
static size_t
374
ncx_len_NC_dim(const NC_dim *dimp, int version)
375
22
{
376
22
  size_t sz;
377
378
22
  assert(dimp != NULL);
379
380
22
  sz = ncx_len_NC_string(dimp->name, version);
381
22
  sz += (version == 5) ? X_SIZEOF_INT64 : X_SIZEOF_SIZE_T;
382
383
22
  return(sz);
384
22
}
385
386
387
/* Write a NC_dim to the header */
388
static int
389
v1h_put_NC_dim(v1hs *psp, const NC_dim *dimp)
390
0
{
391
0
  int status;
392
393
0
  status = v1h_put_NC_string(psp, dimp->name);
394
0
    if(status != NC_NOERR)
395
0
    return status;
396
397
0
  status = v1h_put_size_t(psp, &dimp->size);
398
0
    if(status != NC_NOERR)
399
0
    return status;
400
401
0
    return NC_NOERR;
402
0
}
403
404
/* Read a NC_dim from the header */
405
static int
406
v1h_get_NC_dim(v1hs *gsp, NC_dim **dimpp)
407
265k
{
408
265k
  int status;
409
265k
  NC_string *ncstrp;
410
265k
  NC_dim *dimp;
411
412
265k
  status = v1h_get_NC_string(gsp, &ncstrp);
413
265k
    if(status != NC_NOERR)
414
16
    return status;
415
416
265k
  dimp = new_x_NC_dim(ncstrp);
417
265k
  if(dimp == NULL)
418
0
  {
419
0
    status = NC_ENOMEM;
420
0
    goto unwind_name;
421
0
  }
422
423
265k
  status = v1h_get_size_t(gsp, &dimp->size);
424
265k
    if(status != NC_NOERR)
425
10
  {
426
10
    free_NC_dim(dimp); /* frees name */
427
10
    return status;
428
10
  }
429
430
265k
  *dimpp = dimp;
431
432
265k
    return NC_NOERR;
433
434
0
unwind_name:
435
0
  free_NC_string(ncstrp);
436
0
  return status;
437
265k
}
438
439
440
/* How much space in the header is required for this NC_dimarray? */
441
static size_t
442
ncx_len_NC_dimarray(const NC_dimarray *ncap, int version)
443
2
{
444
2
  size_t xlen = X_SIZEOF_NCTYPE; /* type */
445
2
  xlen += (version == 5) ? X_SIZEOF_INT64 : X_SIZEOF_SIZE_T; /* count */
446
2
  if(ncap == NULL)
447
0
    return xlen;
448
  /* else */
449
2
  {
450
2
    const NC_dim **dpp = (const NC_dim **)ncap->value;
451
2
    const NC_dim *const *const end = &dpp[ncap->nelems];
452
24
    for(  /*NADA*/; dpp < end; dpp++)
453
22
    {
454
22
      xlen += ncx_len_NC_dim(*dpp,version);
455
22
    }
456
2
  }
457
2
  return xlen;
458
2
}
459
460
461
/* Write a NC_dimarray to the header */
462
static int
463
v1h_put_NC_dimarray(v1hs *psp, const NC_dimarray *ncap)
464
0
{
465
0
  int status;
466
467
0
  assert(psp != NULL);
468
469
0
  if(ncap == NULL
470
0
#if 1
471
    /* Backward:
472
     * This clause is for 'byte for byte'
473
     * backward compatibility.
474
     * Strickly speaking, it is 'bug for bug'.
475
     */
476
0
    || ncap->nelems == 0
477
0
#endif
478
0
    )
479
0
  {
480
    /*
481
     * Handle empty netcdf
482
     */
483
0
    const size_t nosz = 0;
484
485
0
    status = v1h_put_NCtype(psp, NC_UNSPECIFIED);
486
0
        if(status != NC_NOERR)
487
0
      return status;
488
0
    status = v1h_put_size_t(psp, &nosz);
489
0
        if(status != NC_NOERR)
490
0
      return status;
491
0
        return NC_NOERR;
492
0
  }
493
  /* else */
494
495
0
  status = v1h_put_NCtype(psp, NC_DIMENSION);
496
0
    if(status != NC_NOERR)
497
0
    return status;
498
0
  status = v1h_put_size_t(psp, &ncap->nelems);
499
0
    if(status != NC_NOERR)
500
0
    return status;
501
502
0
  {
503
0
    const NC_dim **dpp = (const NC_dim **)ncap->value;
504
0
    const NC_dim *const *const end = &dpp[ncap->nelems];
505
0
    for( /*NADA*/; dpp < end; dpp++)
506
0
    {
507
0
      status = v1h_put_NC_dim(psp, *dpp);
508
0
      if(status)
509
0
        return status;
510
0
    }
511
0
  }
512
0
    return NC_NOERR;
513
0
}
514
515
516
/* Read a NC_dimarray from the header */
517
static int
518
v1h_get_NC_dimarray(v1hs *gsp, NC_dimarray *ncap)
519
104
{
520
104
  int status;
521
104
  NCtype type = NC_UNSPECIFIED;
522
523
104
  assert(gsp != NULL && gsp->pos != NULL);
524
104
  assert(ncap != NULL);
525
104
  assert(ncap->value == NULL);
526
527
104
  status = v1h_get_NCtype(gsp, &type);
528
104
    if(status != NC_NOERR)
529
0
    return status;
530
531
104
  status = v1h_get_size_t(gsp, &ncap->nelems);
532
104
    if(status != NC_NOERR)
533
0
    return status;
534
535
104
  if(ncap->nelems == 0)
536
71
        return NC_NOERR;
537
  /* else */
538
33
  if(type != NC_DIMENSION)
539
4
    return EINVAL;
540
541
29
  ncap->value = (NC_dim **) calloc(1,ncap->nelems * sizeof(NC_dim *));
542
29
  if(ncap->value == NULL)
543
0
    return NC_ENOMEM;
544
29
  ncap->nalloc = ncap->nelems;
545
546
29
  ncap->hashmap = NC_hashmapnew(ncap->nelems);
547
548
29
  {
549
29
    NC_dim **dpp = ncap->value;
550
29
    NC_dim *const *const end = &dpp[ncap->nelems];
551
265k
    for( /*NADA*/; dpp < end; dpp++)
552
265k
    {
553
265k
      status = v1h_get_NC_dim(gsp, dpp);
554
265k
      if(status)
555
26
      {
556
26
        ncap->nelems = (size_t)(dpp - ncap->value);
557
26
        free_NC_dimarrayV(ncap);
558
26
        return status;
559
26
      }
560
265k
      {
561
265k
        int dimid = (size_t)(dpp - ncap->value);
562
265k
        NC_hashmapadd(ncap->hashmap, (uintptr_t)dimid, (*dpp)->name->cp,strlen((*dpp)->name->cp));
563
265k
      }
564
265k
    }
565
29
  }
566
567
3
    return NC_NOERR;
568
29
}
569
570
571
/* End NC_dim */
572
/* Begin NC_attr */
573
574
575
/*
576
 * How much space will 'attrp' take in external representation?
577
 * Formerly
578
NC_xlen_attr(app)
579
 */
580
static size_t
581
ncx_len_NC_attr(const NC_attr *attrp, int version)
582
0
{
583
0
  size_t sz;
584
585
0
  assert(attrp != NULL);
586
587
0
  sz = ncx_len_NC_string(attrp->name, version);
588
0
  sz += X_SIZEOF_NC_TYPE; /* type */
589
0
  sz += (version == 5) ? X_SIZEOF_INT64 : X_SIZEOF_SIZE_T; /* nelems */
590
0
  sz += attrp->xsz;
591
592
0
  return(sz);
593
0
}
594
595
596
#undef MIN
597
45.3k
#define MIN(mm,nn) (((mm) < (nn)) ? (mm) : (nn))
598
599
/*----< ncmpix_len_nctype() >------------------------------------------------*/
600
/* return the length of external data type */
601
static int
602
0
ncmpix_len_nctype(nc_type type) {
603
0
    switch(type) {
604
0
        case NC_BYTE:
605
0
        case NC_CHAR:
606
0
        case NC_UBYTE:  return X_SIZEOF_CHAR;
607
0
        case NC_SHORT:  return X_SIZEOF_SHORT;
608
0
        case NC_USHORT: return X_SIZEOF_USHORT;
609
0
        case NC_INT:    return X_SIZEOF_INT;
610
0
        case NC_UINT:   return X_SIZEOF_UINT;
611
0
        case NC_FLOAT:  return X_SIZEOF_FLOAT;
612
0
        case NC_DOUBLE: return X_SIZEOF_DOUBLE;
613
0
        case NC_INT64:  return X_SIZEOF_INT64;
614
0
        case NC_UINT64: return X_SIZEOF_UINT64;
615
0
        default: fprintf(stderr,"ncmpix_len_nctype bad type %d\n",type);
616
0
                 assert(0);
617
0
    }
618
0
    return 0;
619
0
}
620
621
/*
622
 * Put the values of an attribute
623
 * The loop is necessary since attrp->nelems
624
 * could potentially be quite large.
625
 */
626
static int
627
v1h_put_NC_attrV(v1hs *psp, const NC_attr *attrp)
628
0
{
629
0
  int status = 0;
630
0
  const size_t perchunk =  psp->extent;
631
0
  size_t remaining = attrp->xsz;
632
0
  void *value = attrp->xvalue;
633
0
  size_t nbytes = 0, padding = 0;
634
635
0
  assert(psp->extent % X_ALIGN == 0);
636
637
0
  do {
638
0
    nbytes = MIN(perchunk, remaining);
639
640
0
    status = check_v1hs(psp, nbytes);
641
0
    if(status != NC_NOERR)
642
0
      return status;
643
644
0
    (void) memcpy(psp->pos, value, nbytes);
645
646
0
    psp->pos = (void *)((char *)psp->pos + nbytes);
647
0
    value = (void *)((char *)value + nbytes);
648
0
          remaining -= nbytes;
649
650
0
  } while(remaining != 0);
651
652
653
0
  padding = attrp->xsz - ncmpix_len_nctype(attrp->type) * attrp->nelems;
654
0
  if (padding > 0) {
655
    /* CDF specification: Header padding uses null (\x00) bytes. */
656
0
    memset((char*)psp->pos-padding, 0, padding);
657
0
  }
658
659
0
  return NC_NOERR;
660
0
}
661
662
/* Write a NC_attr to the header */
663
static int
664
v1h_put_NC_attr(v1hs *psp, const NC_attr *attrp)
665
0
{
666
0
  int status;
667
668
0
  status = v1h_put_NC_string(psp, attrp->name);
669
0
    if(status != NC_NOERR)
670
0
    return status;
671
672
0
  status = v1h_put_nc_type(psp, &attrp->type);
673
0
    if(status != NC_NOERR)
674
0
    return status;
675
676
0
  status = v1h_put_size_t(psp, &attrp->nelems);
677
0
    if(status != NC_NOERR)
678
0
    return status;
679
680
0
  status = v1h_put_NC_attrV(psp, attrp);
681
0
    if(status != NC_NOERR)
682
0
    return status;
683
684
0
    return NC_NOERR;
685
0
}
686
687
688
/*
689
 * Get the values of an attribute
690
 * The loop is necessary since attrp->nelems
691
 * could potentially be quite large.
692
 */
693
static int
694
v1h_get_NC_attrV(v1hs *gsp, NC_attr *attrp)
695
43.6k
{
696
43.6k
  int status;
697
43.6k
  const size_t perchunk =  gsp->extent;
698
43.6k
  size_t remaining = attrp->xsz;
699
43.6k
  void *value = attrp->xvalue;
700
43.6k
  size_t nget;
701
#if USE_STRICT_NULL_BYTE_HEADER_PADDING
702
  size_t padding;
703
#endif /* USE_STRICT_NULL_BYTE_HEADER_PADDING */
704
705
45.3k
  do {
706
45.3k
    nget = MIN(perchunk, remaining);
707
708
45.3k
    status = check_v1hs(gsp, nget);
709
45.3k
    if(status != NC_NOERR)
710
19
      return status;
711
712
45.3k
    (void) memcpy(value, gsp->pos, nget);
713
45.3k
    gsp->pos = (void*)((unsigned char *)gsp->pos + nget);
714
715
45.3k
    value = (void *)((signed char *)value + nget);
716
717
45.3k
    remaining -= nget;
718
719
45.3k
  } while(remaining != 0);
720
721
#if USE_STRICT_NULL_BYTE_HEADER_PADDING
722
  padding = attrp->xsz - ncmpix_len_nctype(attrp->type) * attrp->nelems;
723
  if (padding > 0) {
724
    /* CDF specification: Header padding uses null (\x00) bytes. */
725
    char pad[X_ALIGN-1];
726
    memset(pad, 0, X_ALIGN-1);
727
    if (memcmp((char*)gsp->pos-padding, pad, (size_t)padding) != 0)
728
      return NC_ENULLPAD;
729
  }
730
#endif
731
732
43.6k
  return NC_NOERR;
733
43.6k
}
734
735
736
/* Read a NC_attr from the header */
737
static int
738
v1h_get_NC_attr(v1hs *gsp, NC_attr **attrpp)
739
43.6k
{
740
43.6k
  NC_string *strp;
741
43.6k
  int status;
742
43.6k
  nc_type type;
743
43.6k
  size_t nelems;
744
43.6k
  NC_attr *attrp;
745
746
43.6k
  status = v1h_get_NC_string(gsp, &strp);
747
43.6k
    if(status != NC_NOERR)
748
4
    return status;
749
750
43.6k
  status = v1h_get_nc_type(gsp, &type);
751
43.6k
    if(status != NC_NOERR)
752
12
    goto unwind_name;
753
754
43.6k
  status = v1h_get_size_t(gsp, &nelems);
755
43.6k
    if(status != NC_NOERR)
756
2
    goto unwind_name;
757
758
43.6k
  attrp = new_x_NC_attr(strp, type, nelems);
759
43.6k
  if(attrp == NULL)
760
0
  {
761
0
    status = NC_ENOMEM;
762
0
    goto unwind_name;
763
0
  }
764
765
43.6k
  status = v1h_get_NC_attrV(gsp, attrp);
766
43.6k
        if(status != NC_NOERR)
767
19
  {
768
19
    free_NC_attr(attrp); /* frees strp */
769
19
    return status;
770
19
  }
771
772
43.6k
  *attrpp = attrp;
773
774
43.6k
    return NC_NOERR;
775
776
14
unwind_name:
777
14
  free_NC_string(strp);
778
14
  return status;
779
43.6k
}
780
781
782
/* How much space in the header is required for this NC_attrarray? */
783
static size_t
784
ncx_len_NC_attrarray(const NC_attrarray *ncap, int version)
785
2
{
786
2
  size_t xlen = X_SIZEOF_NCTYPE; /* type */
787
2
  xlen += (version == 5) ? X_SIZEOF_INT64 : X_SIZEOF_SIZE_T; /* count */
788
2
  if(ncap == NULL)
789
0
    return xlen;
790
  /* else */
791
2
  {
792
2
    const NC_attr **app = (const NC_attr **)ncap->value;
793
2
    const NC_attr *const *const end = &app[ncap->nelems];
794
2
    for( /*NADA*/; app < end; app++)
795
0
    {
796
0
      xlen += ncx_len_NC_attr(*app,version);
797
0
    }
798
2
  }
799
2
  return xlen;
800
2
}
801
802
803
/* Write a NC_attrarray to the header */
804
static int
805
v1h_put_NC_attrarray(v1hs *psp, const NC_attrarray *ncap)
806
0
{
807
0
  int status;
808
809
0
  assert(psp != NULL);
810
811
0
  if(ncap == NULL
812
0
#if 1
813
    /* Backward:
814
     * This clause is for 'byte for byte'
815
     * backward compatibility.
816
     * Strickly speaking, it is 'bug for bug'.
817
     */
818
0
    || ncap->nelems == 0
819
0
#endif
820
0
    )
821
0
  {
822
    /*
823
     * Handle empty netcdf
824
     */
825
0
    const size_t nosz = 0;
826
827
0
    status = v1h_put_NCtype(psp, NC_UNSPECIFIED);
828
0
        if(status != NC_NOERR)
829
0
      return status;
830
0
    status = v1h_put_size_t(psp, &nosz);
831
0
        if(status != NC_NOERR)
832
0
      return status;
833
0
        return NC_NOERR;
834
0
  }
835
  /* else */
836
837
0
  status = v1h_put_NCtype(psp, NC_ATTRIBUTE);
838
0
    if(status != NC_NOERR)
839
0
    return status;
840
0
  status = v1h_put_size_t(psp, &ncap->nelems);
841
0
    if(status != NC_NOERR)
842
0
    return status;
843
844
0
  {
845
0
    const NC_attr **app = (const NC_attr **)ncap->value;
846
0
    const NC_attr *const *const end = &app[ncap->nelems];
847
0
    for( /*NADA*/; app < end; app++)
848
0
    {
849
0
      status = v1h_put_NC_attr(psp, *app);
850
0
      if(status)
851
0
        return status;
852
0
    }
853
0
  }
854
0
    return NC_NOERR;
855
0
}
856
857
858
/* Read a NC_attrarray from the header */
859
static int
860
v1h_get_NC_attrarray(v1hs *gsp, NC_attrarray *ncap)
861
48.4k
{
862
48.4k
  int status;
863
48.4k
  NCtype type = NC_UNSPECIFIED;
864
865
48.4k
  assert(gsp != NULL && gsp->pos != NULL);
866
48.4k
  assert(ncap != NULL);
867
48.4k
  assert(ncap->value == NULL);
868
869
48.4k
  status = v1h_get_NCtype(gsp, &type);
870
48.4k
    if(status != NC_NOERR)
871
6
    return status;
872
48.4k
  status = v1h_get_size_t(gsp, &ncap->nelems);
873
48.4k
    if(status != NC_NOERR)
874
2
    return status;
875
876
48.4k
  if(ncap->nelems == 0)
877
48.4k
        return NC_NOERR;
878
  /* else */
879
43
  if(type != NC_ATTRIBUTE)
880
6
    return EINVAL;
881
882
37
  ncap->value = (NC_attr **) malloc(ncap->nelems * sizeof(NC_attr *));
883
37
  if(ncap->value == NULL)
884
0
    return NC_ENOMEM;
885
37
  ncap->nalloc = ncap->nelems;
886
887
37
  {
888
37
    NC_attr **app = ncap->value;
889
37
    NC_attr *const *const end = &app[ncap->nelems];
890
43.6k
    for( /*NADA*/; app < end; app++)
891
43.6k
    {
892
43.6k
      status = v1h_get_NC_attr(gsp, app);
893
43.6k
      if(status)
894
37
      {
895
37
        ncap->nelems = (size_t)(app - ncap->value);
896
37
        free_NC_attrarrayV(ncap);
897
37
        return status;
898
37
      }
899
43.6k
    }
900
37
  }
901
902
0
    return NC_NOERR;
903
37
}
904
905
/* End NC_attr */
906
/* Begin NC_var */
907
908
/*
909
 * How much space will the xdr'd var take.
910
 * Formerly
911
NC_xlen_var(vpp)
912
 */
913
static size_t
914
ncx_len_NC_var(const NC_var *varp, size_t sizeof_off_t, int version)
915
0
{
916
0
  size_t sz;
917
918
0
  assert(varp != NULL);
919
0
  assert(sizeof_off_t != 0);
920
921
0
  sz = ncx_len_NC_string(varp->name, version);
922
0
        if (version == 5) {
923
0
      sz += X_SIZEOF_INT64; /* ndims */
924
0
      sz += ncx_len_int64(varp->ndims); /* dimids */
925
0
        }
926
0
        else {
927
0
      sz += X_SIZEOF_SIZE_T; /* ndims */
928
0
      sz += ncx_len_int(varp->ndims); /* dimids */
929
0
  }
930
0
  sz += ncx_len_NC_attrarray(&varp->attrs, version);
931
0
  sz += X_SIZEOF_NC_TYPE; /* nc_type */
932
0
  sz += (version == 5) ? X_SIZEOF_INT64 : X_SIZEOF_SIZE_T; /* vsize */
933
0
  sz += sizeof_off_t; /* begin */
934
935
0
  return(sz);
936
0
}
937
938
939
/* Write a NC_var to the header */
940
static int
941
v1h_put_NC_var(v1hs *psp, const NC_var *varp)
942
0
{
943
0
  int status;
944
0
    size_t vsize;
945
946
0
  status = v1h_put_NC_string(psp, varp->name);
947
0
    if(status != NC_NOERR)
948
0
    return status;
949
950
0
  status = v1h_put_size_t(psp, &varp->ndims);
951
0
    if(status != NC_NOERR)
952
0
    return status;
953
954
0
  if (psp->version == 5) {
955
0
    status = check_v1hs(psp, ncx_len_int64(varp->ndims));
956
0
        if(status != NC_NOERR)
957
0
      return status;
958
0
    status = ncx_putn_longlong_int(&psp->pos,
959
0
        varp->ndims, varp->dimids, NULL);
960
0
        if(status != NC_NOERR)
961
0
      return status;
962
0
  }
963
0
  else {
964
0
        status = check_v1hs(psp, ncx_len_int(varp->ndims));
965
0
        if(status != NC_NOERR)
966
0
    return status;
967
0
      status = ncx_putn_int_int(&psp->pos,
968
0
      varp->ndims, varp->dimids, NULL);
969
0
        if(status != NC_NOERR)
970
0
    return status;
971
0
  }
972
973
0
  status = v1h_put_NC_attrarray(psp, &varp->attrs);
974
0
    if(status != NC_NOERR)
975
0
    return status;
976
977
0
  status = v1h_put_nc_type(psp, &varp->type);
978
0
    if(status != NC_NOERR)
979
0
    return status;
980
981
    /* write vsize to header.
982
     * CDF format specification: The vsize field is actually redundant, because
983
     * its value may be computed from other information in the header. The
984
     * 32-bit vsize field is not large enough to contain the size of variables
985
     * that require more than 2^32 - 4 bytes, so 2^32 - 1 is used in the vsize
986
     * field for such variables.
987
     */
988
0
    vsize = varp->len;
989
0
    if (varp->len > 4294967292UL && (psp->version == NC_FORMAT_CLASSIC ||
990
0
                                     psp->version == NC_FORMAT_64BIT_OFFSET))
991
0
        vsize = 4294967295UL; /* 2^32-1 */
992
0
    status = v1h_put_size_t(psp, &vsize);
993
0
    if(status != NC_NOERR) return status;
994
995
0
  status = check_v1hs(psp, psp->version == 1 ? 4 : 8); /*begin*/
996
0
    if(status != NC_NOERR)
997
0
     return status;
998
0
  status = ncx_put_off_t(&psp->pos, &varp->begin, psp->version == 1 ? 4 : 8);
999
0
    if(status != NC_NOERR)
1000
0
    return status;
1001
1002
0
    return NC_NOERR;
1003
0
}
1004
1005
1006
/* Read a NC_var from the header */
1007
static int
1008
v1h_get_NC_var(v1hs *gsp, NC_var **varpp)
1009
48.4k
{
1010
48.4k
  NC_string *strp;
1011
48.4k
  int status;
1012
48.4k
  size_t ndims;
1013
48.4k
  NC_var *varp;
1014
1015
48.4k
  status = v1h_get_NC_string(gsp, &strp);
1016
48.4k
    if(status != NC_NOERR)
1017
2
    return status;
1018
1019
48.4k
  status = v1h_get_size_t(gsp, &ndims);
1020
48.4k
    if(status != NC_NOERR)
1021
3
    goto unwind_name;
1022
1023
48.4k
  varp = new_x_NC_var(strp, ndims);
1024
48.4k
  if(varp == NULL)
1025
0
  {
1026
0
    status = NC_ENOMEM;
1027
0
    goto unwind_name;
1028
0
  }
1029
1030
48.4k
  if (gsp->version == 5) {
1031
6.82k
    status = check_v1hs(gsp, ncx_len_int64(ndims));
1032
6.82k
        if(status != NC_NOERR)
1033
2
      goto unwind_alloc;
1034
6.82k
    status = ncx_getn_longlong_int((const void **)(&gsp->pos),
1035
6.82k
        ndims, varp->dimids);
1036
6.82k
        if(status != NC_NOERR)
1037
1
      goto unwind_alloc;
1038
6.82k
  }
1039
41.5k
  else {
1040
41.5k
      status = check_v1hs(gsp, ncx_len_int(ndims));
1041
41.5k
        if(status != NC_NOERR)
1042
3
    goto unwind_alloc;
1043
41.5k
      status = ncx_getn_int_int((const void **)(&gsp->pos),
1044
41.5k
      ndims, varp->dimids);
1045
41.5k
        if(status != NC_NOERR)
1046
0
    goto unwind_alloc;
1047
41.5k
  }
1048
48.4k
  status = v1h_get_NC_attrarray(gsp, &varp->attrs);
1049
48.4k
    if(status != NC_NOERR)
1050
10
    goto unwind_alloc;
1051
48.4k
  status = v1h_get_nc_type(gsp, &varp->type);
1052
48.4k
    if(status != NC_NOERR)
1053
5
     goto unwind_alloc;
1054
1055
48.4k
    size_t tmp;
1056
48.4k
    status = v1h_get_size_t(gsp, &tmp);
1057
48.4k
    varp->len = tmp;
1058
48.4k
    if(status != NC_NOERR)
1059
2
     goto unwind_alloc;
1060
1061
48.4k
  status = check_v1hs(gsp, gsp->version == 1 ? 4 : 8);
1062
48.4k
    if(status != NC_NOERR)
1063
2
     goto unwind_alloc;
1064
48.3k
  status = ncx_get_off_t((const void **)&gsp->pos,
1065
48.3k
             &varp->begin, gsp->version == 1 ? 4 : 8);
1066
48.3k
    if(status != NC_NOERR)
1067
0
     goto unwind_alloc;
1068
1069
48.3k
  *varpp = varp;
1070
48.3k
    return NC_NOERR;
1071
1072
25
unwind_alloc:
1073
25
  free_NC_var(varp); /* frees name */
1074
25
  return status;
1075
1076
3
unwind_name:
1077
3
  free_NC_string(strp);
1078
3
  return status;
1079
48.3k
}
1080
1081
1082
/* How much space in the header is required for this NC_vararray? */
1083
static size_t
1084
ncx_len_NC_vararray(const NC_vararray *ncap, size_t sizeof_off_t, int version)
1085
2
{
1086
2
  size_t xlen = X_SIZEOF_NCTYPE; /* type */
1087
2
  xlen += (version == 5) ? X_SIZEOF_INT64 : X_SIZEOF_SIZE_T; /* count */
1088
2
  if(ncap == NULL)
1089
0
    return xlen;
1090
  /* else */
1091
2
  {
1092
2
    const NC_var **vpp = (const NC_var **)ncap->value;
1093
2
    const NC_var *const *const end = &vpp[ncap->nelems];
1094
2
    for( /*NADA*/; vpp < end; vpp++)
1095
0
    {
1096
0
      xlen += ncx_len_NC_var(*vpp, sizeof_off_t, version);
1097
0
    }
1098
2
  }
1099
2
  return xlen;
1100
2
}
1101
1102
1103
/* Write a NC_vararray to the header */
1104
static int
1105
v1h_put_NC_vararray(v1hs *psp, const NC_vararray *ncap)
1106
0
{
1107
0
  int status;
1108
1109
0
  assert(psp != NULL);
1110
1111
0
  if(ncap == NULL
1112
0
#if 1
1113
    /* Backward:
1114
     * This clause is for 'byte for byte'
1115
     * backward compatibility.
1116
     * Strickly speaking, it is 'bug for bug'.
1117
     */
1118
0
    || ncap->nelems == 0
1119
0
#endif
1120
0
    )
1121
0
  {
1122
    /*
1123
     * Handle empty netcdf
1124
     */
1125
0
    const size_t nosz = 0;
1126
1127
0
    status = v1h_put_NCtype(psp, NC_UNSPECIFIED);
1128
0
        if(status != NC_NOERR)
1129
0
      return status;
1130
0
    status = v1h_put_size_t(psp, &nosz);
1131
0
        if(status != NC_NOERR)
1132
0
      return status;
1133
0
        return NC_NOERR;
1134
0
  }
1135
  /* else */
1136
1137
0
  status = v1h_put_NCtype(psp, NC_VARIABLE);
1138
0
    if(status != NC_NOERR)
1139
0
    return status;
1140
0
  status = v1h_put_size_t(psp, &ncap->nelems);
1141
0
    if(status != NC_NOERR)
1142
0
    return status;
1143
1144
0
  {
1145
0
    const NC_var **vpp = (const NC_var **)ncap->value;
1146
0
    const NC_var *const *const end = &vpp[ncap->nelems];
1147
0
    for( /*NADA*/; vpp < end; vpp++)
1148
0
    {
1149
0
      status = v1h_put_NC_var(psp, *vpp);
1150
0
      if(status)
1151
0
        return status;
1152
0
    }
1153
0
  }
1154
0
    return NC_NOERR;
1155
0
}
1156
1157
1158
/* Read a NC_vararray from the header */
1159
static int
1160
v1h_get_NC_vararray(v1hs *gsp, NC_vararray *ncap)
1161
33
{
1162
33
  int status;
1163
33
  NCtype type = NC_UNSPECIFIED;
1164
1165
33
  assert(gsp != NULL && gsp->pos != NULL);
1166
33
  assert(ncap != NULL);
1167
33
  assert(ncap->value == NULL);
1168
1169
33
  status = v1h_get_NCtype(gsp, &type);
1170
33
    if(status != NC_NOERR)
1171
0
    return status;
1172
1173
33
  status = v1h_get_size_t(gsp, &ncap->nelems);
1174
33
    if(status != NC_NOERR)
1175
0
    return status;
1176
1177
33
  if(ncap->nelems == 0)
1178
2
        return NC_NOERR;
1179
  /* else */
1180
31
  if(type != NC_VARIABLE)
1181
1
    return EINVAL;
1182
1183
30
  ncap->value = (NC_var **) calloc(1,ncap->nelems * sizeof(NC_var *));
1184
30
  if(ncap->value == NULL)
1185
0
    return NC_ENOMEM;
1186
30
  ncap->nalloc = ncap->nelems;
1187
1188
30
  ncap->hashmap = NC_hashmapnew(ncap->nelems);
1189
30
  {
1190
30
    NC_var **vpp = ncap->value;
1191
30
    NC_var *const *const end = &vpp[ncap->nelems];
1192
48.4k
    for( /*NADA*/; vpp < end; vpp++)
1193
48.4k
    {
1194
48.4k
      status = v1h_get_NC_var(gsp, vpp);
1195
48.4k
      if(status)
1196
30
      {
1197
30
        ncap->nelems = (size_t)(vpp - ncap->value);
1198
30
        free_NC_vararrayV(ncap);
1199
30
        return status;
1200
30
      }
1201
48.3k
      {
1202
48.3k
        int varid = (size_t)(vpp - ncap->value);
1203
48.3k
        NC_hashmapadd(ncap->hashmap, (uintptr_t)varid, (*vpp)->name->cp,strlen((*vpp)->name->cp));
1204
48.3k
      }
1205
48.3k
    }
1206
30
  }
1207
1208
0
    return NC_NOERR;
1209
30
}
1210
1211
1212
/* End NC_var */
1213
/* Begin NC */
1214
1215
/*
1216
 * Recompute the shapes of all variables
1217
 * Sets ncp->begin_var to start of first variable.
1218
 * Sets ncp->begin_rec to start of first record variable.
1219
 * Returns -1 on error. The only possible error is a reference
1220
 * to a non existent dimension, which could occur for a corrupted
1221
 * netcdf file.
1222
 */
1223
static int
1224
NC_computeshapes(NC3_INFO* ncp)
1225
2
{
1226
2
  NC_var **vpp = (NC_var **)ncp->vars.value;
1227
2
  NC_var *const *const end = &vpp[ncp->vars.nelems];
1228
2
  NC_var *first_var = NULL; /* first "non-record" var */
1229
2
  NC_var *first_rec = NULL; /* first "record" var */
1230
2
  int status;
1231
1232
2
  ncp->begin_var = (off_t) ncp->xsz;
1233
2
  ncp->begin_rec = (off_t) ncp->xsz;
1234
2
  ncp->recsize = 0;
1235
1236
2
  if(ncp->vars.nelems == 0)
1237
2
    return(0);
1238
1239
0
  for( /*NADA*/; vpp < end; vpp++)
1240
0
  {
1241
0
    status = NC_var_shape(*vpp, &ncp->dims);
1242
0
        if(status != NC_NOERR)
1243
0
      return(status);
1244
1245
0
      if(IS_RECVAR(*vpp))
1246
0
    {
1247
0
        if(first_rec == NULL)
1248
0
        first_rec = *vpp;
1249
0
          ncp->recsize += (*vpp)->len;
1250
0
    }
1251
0
    else
1252
0
    {
1253
0
            if(first_var == NULL)
1254
0
              first_var = *vpp;
1255
      /*
1256
       * Overwritten each time thru.
1257
       * Usually overwritten in first_rec != NULL clause below.
1258
       */
1259
0
      ncp->begin_rec = (*vpp)->begin + (off_t)(*vpp)->len;
1260
0
    }
1261
0
  }
1262
1263
0
  if(first_rec != NULL)
1264
0
  {
1265
0
    if(ncp->begin_rec > first_rec->begin)
1266
0
        return(NC_ENOTNC); /* not a netCDF file or corrupted */
1267
0
    ncp->begin_rec = first_rec->begin;
1268
    /*
1269
     * for special case of exactly one record variable, pack value
1270
     */
1271
0
    if(ncp->recsize == first_rec->len)
1272
0
      ncp->recsize = *first_rec->dsizes * first_rec->xsz;
1273
0
  }
1274
1275
0
  if(first_var != NULL)
1276
0
  {
1277
0
    ncp->begin_var = first_var->begin;
1278
0
  }
1279
0
  else
1280
0
  {
1281
0
    ncp->begin_var = ncp->begin_rec;
1282
0
  }
1283
1284
0
  if(ncp->begin_var <= 0 ||
1285
0
     ncp->xsz > (size_t)ncp->begin_var ||
1286
0
     ncp->begin_rec <= 0 ||
1287
0
     ncp->begin_var > ncp->begin_rec)
1288
0
      return(NC_ENOTNC); /* not a netCDF file or corrupted */
1289
1290
0
    return(NC_NOERR);
1291
0
}
1292
1293
/* How much space in the header is required for the NC data structure? */
1294
size_t
1295
ncx_len_NC(const NC3_INFO* ncp, size_t sizeof_off_t)
1296
2
{
1297
2
  int version=1;
1298
2
  size_t xlen = sizeof(ncmagic);
1299
1300
2
  assert(ncp != NULL);
1301
2
  if (fIsSet(ncp->flags, NC_64BIT_DATA)) /* CDF-5 */
1302
0
    version = 5;
1303
2
      else if (fIsSet(ncp->flags, NC_64BIT_OFFSET)) /* CDF-2 */
1304
2
    version = 2;
1305
1306
2
  xlen += (version == 5) ? X_SIZEOF_INT64 : X_SIZEOF_SIZE_T; /* numrecs */
1307
2
  xlen += ncx_len_NC_dimarray(&ncp->dims, version);
1308
2
  xlen += ncx_len_NC_attrarray(&ncp->attrs, version);
1309
2
  xlen += ncx_len_NC_vararray(&ncp->vars, sizeof_off_t, version);
1310
1311
2
  return xlen;
1312
2
}
1313
1314
1315
/* Write the file header */
1316
int
1317
ncx_put_NC(const NC3_INFO* ncp, void **xpp, off_t offset, size_t extent)
1318
0
{
1319
0
    int status = NC_NOERR;
1320
0
  v1hs ps; /* the get stream */
1321
1322
0
  assert(ncp != NULL);
1323
1324
  /* Initialize stream ps */
1325
1326
0
  ps.nciop = ncp->nciop;
1327
0
  ps.flags = RGN_WRITE;
1328
1329
0
  if (ncp->flags & NC_64BIT_DATA)
1330
0
    ps.version = 5;
1331
0
  else if (ncp->flags & NC_64BIT_OFFSET)
1332
0
    ps.version = 2;
1333
0
  else
1334
0
    ps.version = 1;
1335
1336
0
  if(xpp == NULL)
1337
0
  {
1338
    /*
1339
     * Come up with a reasonable stream read size.
1340
     */
1341
0
    extent = ncp->xsz;
1342
0
    if(extent <= ((ps.version==5)?MIN_NC5_XSZ:MIN_NC3_XSZ))
1343
0
    {
1344
      /* first time read */
1345
0
      extent = ncp->chunk;
1346
      /* Protection for when ncp->chunk is huge;
1347
       * no need to read hugely. */
1348
0
            if(extent > 4096)
1349
0
        extent = 4096;
1350
0
    }
1351
0
    else if(extent > ncp->chunk)
1352
0
        extent = ncp->chunk;
1353
1354
0
    ps.offset = 0;
1355
0
    ps.extent = extent;
1356
0
    ps.base = NULL;
1357
0
    ps.pos = ps.base;
1358
1359
0
    status = fault_v1hs(&ps, extent);
1360
0
    if(status)
1361
0
      return status;
1362
0
  }
1363
0
  else
1364
0
  {
1365
0
    ps.offset = offset;
1366
0
    ps.extent = extent;
1367
0
    ps.base = *xpp;
1368
0
    ps.pos = ps.base;
1369
0
    ps.end = (char *)ps.base + ps.extent;
1370
0
  }
1371
1372
0
  if (ps.version == 5)
1373
0
    status = ncx_putn_schar_schar(&ps.pos, sizeof(ncmagic5), ncmagic5, NULL);
1374
0
  else if (ps.version == 2)
1375
0
    status = ncx_putn_schar_schar(&ps.pos, sizeof(ncmagic), ncmagic, NULL);
1376
0
  else
1377
0
    status = ncx_putn_schar_schar(&ps.pos, sizeof(ncmagic1), ncmagic1, NULL);
1378
0
  if(status != NC_NOERR)
1379
0
    goto release;
1380
1381
0
  {
1382
0
  const size_t nrecs = NC_get_numrecs(ncp);
1383
0
  if (ps.version == 5) {
1384
0
            unsigned long long tmp = (unsigned long long) nrecs;
1385
0
      status = ncx_put_uint64(&ps.pos, tmp);
1386
0
        }
1387
0
        else
1388
0
      status = ncx_put_size_t(&ps.pos, &nrecs);
1389
0
  if(status != NC_NOERR)
1390
0
    goto release;
1391
0
  }
1392
1393
0
  assert((char *)ps.pos < (char *)ps.end);
1394
1395
0
  status = v1h_put_NC_dimarray(&ps, &ncp->dims);
1396
0
    if(status != NC_NOERR)
1397
0
    goto release;
1398
1399
0
  status = v1h_put_NC_attrarray(&ps, &ncp->attrs);
1400
0
    if(status != NC_NOERR)
1401
0
    goto release;
1402
1403
0
  status = v1h_put_NC_vararray(&ps, &ncp->vars);
1404
0
    if(status != NC_NOERR)
1405
0
    goto release;
1406
1407
0
release:
1408
0
  (void) rel_v1hs(&ps);
1409
1410
0
  return status;
1411
0
}
1412
1413
1414
/* Make the in-memory NC structure from reading the file header */
1415
int
1416
nc_get_NC(NC3_INFO* ncp)
1417
104
{
1418
104
  int status;
1419
104
  v1hs gs; /* the get stream */
1420
1421
104
  assert(ncp != NULL);
1422
1423
  /* Initialize stream gs */
1424
1425
104
  gs.nciop = ncp->nciop;
1426
104
  gs.offset = 0; /* beginning of file */
1427
104
  gs.extent = 0;
1428
104
  gs.flags = 0;
1429
104
  gs.version = 0;
1430
104
  gs.base = NULL;
1431
104
  gs.pos = gs.base;
1432
1433
104
  {
1434
    /*
1435
     * Come up with a reasonable stream read size.
1436
     */
1437
104
          off_t filesize;
1438
104
    size_t extent = ncp->xsz;
1439
1440
104
    if(extent <= ((fIsSet(ncp->flags, NC_64BIT_DATA))?MIN_NC5_XSZ:MIN_NC3_XSZ))
1441
104
    {
1442
104
            status = ncio_filesize(ncp->nciop, &filesize);
1443
104
      if(status)
1444
0
          return status;
1445
104
      if(filesize < sizeof(ncmagic)) { /* too small, not netcdf */
1446
1447
0
          status = NC_ENOTNC;
1448
0
          return status;
1449
0
      }
1450
      /* first time read */
1451
104
      extent = ncp->chunk;
1452
      /* Protection for when ncp->chunk is huge;
1453
       * no need to read hugely. */
1454
104
            if(extent > 4096)
1455
104
        extent = 4096;
1456
104
      if(extent > filesize)
1457
0
              extent = (size_t)filesize;
1458
104
    }
1459
0
    else if(extent > ncp->chunk)
1460
0
        extent = ncp->chunk;
1461
1462
    /*
1463
     * Invalidate the I/O buffers to force a read of the header
1464
     * region.
1465
     */
1466
104
    status = ncio_sync(gs.nciop);
1467
104
    if(status)
1468
0
      return status;
1469
1470
104
    status = fault_v1hs(&gs, extent);
1471
104
    if(status)
1472
0
      return status;
1473
104
  }
1474
1475
  /* get the header from the stream gs */
1476
1477
104
  {
1478
    /* Get & check magic number */
1479
104
    schar magic[sizeof(ncmagic)];
1480
104
    (void) memset(magic, 0, sizeof(magic));
1481
1482
104
    status = ncx_getn_schar_schar(
1483
104
      (const void **)(&gs.pos), sizeof(magic), magic);
1484
104
        if(status != NC_NOERR)
1485
0
      goto unwind_get;
1486
1487
104
    if(memcmp(magic, ncmagic, sizeof(ncmagic)-1) != 0)
1488
0
    {
1489
0
      status = NC_ENOTNC;
1490
0
      goto unwind_get;
1491
0
    }
1492
    /* Check version number in last byte of magic */
1493
104
    if (magic[sizeof(ncmagic)-1] == 0x1) {
1494
27
      gs.version = 1;
1495
77
    } else if (magic[sizeof(ncmagic)-1] == 0x2) {
1496
42
      gs.version = 2;
1497
42
      fSet(ncp->flags, NC_64BIT_OFFSET);
1498
      /* Now we support version 2 file access on non-LFS systems -- rkr */
1499
#if 0
1500
      if (sizeof(off_t) != 8) {
1501
        fprintf(stderr, "NETCDF WARNING: Version 2 file on 32-bit system.\n");
1502
      }
1503
#endif
1504
42
    } else if (magic[sizeof(ncmagic)-1] == 0x5) {
1505
35
      gs.version = 5;
1506
35
      fSet(ncp->flags, NC_64BIT_DATA);
1507
35
    } else {
1508
0
      status = NC_ENOTNC;
1509
0
      goto unwind_get;
1510
0
    }
1511
104
  }
1512
1513
104
  {
1514
104
  size_t nrecs = 0;
1515
104
        if (gs.version == 5) {
1516
35
    unsigned long long tmp = 0;
1517
35
    status = ncx_get_uint64((const void **)(&gs.pos), &tmp);
1518
35
    nrecs = (size_t)tmp;
1519
35
        }
1520
69
        else
1521
69
      status = ncx_get_size_t((const void **)(&gs.pos), &nrecs);
1522
104
    if(status != NC_NOERR)
1523
0
    goto unwind_get;
1524
104
  NC_set_numrecs(ncp, nrecs);
1525
104
  }
1526
1527
0
  assert((char *)gs.pos < (char *)gs.end);
1528
1529
104
  status = v1h_get_NC_dimarray(&gs, &ncp->dims);
1530
104
    if(status != NC_NOERR)
1531
30
    goto unwind_get;
1532
1533
74
  status = v1h_get_NC_attrarray(&gs, &ncp->attrs);
1534
74
    if(status != NC_NOERR)
1535
41
    goto unwind_get;
1536
1537
33
  status = v1h_get_NC_vararray(&gs, &ncp->vars);
1538
33
    if(status != NC_NOERR)
1539
31
    goto unwind_get;
1540
1541
2
  ncp->xsz = ncx_len_NC(ncp, (gs.version == 1) ? 4 : 8);
1542
1543
2
  status = NC_computeshapes(ncp);
1544
2
    if(status != NC_NOERR)
1545
0
    goto unwind_get;
1546
1547
2
  status = NC_check_vlens(ncp);
1548
2
    if(status != NC_NOERR)
1549
0
    goto unwind_get;
1550
1551
2
  status = NC_check_voffs(ncp);
1552
2
    if(status != NC_NOERR)
1553
0
    goto unwind_get;
1554
1555
104
unwind_get:
1556
104
  (void) rel_v1hs(&gs);
1557
104
  return status;
1558
2
}