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