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