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


HyperKWIC - Version 7.20DA executed at 11:37 on 27 Oct 2017 | Polyhedron Solutions - INTERNAL USE | COMMERCIAL (Any O/S) SN 4AKIed