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