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