static NC * new_NC(const size_t *chunkp) { NC *ncp; #if _CRAYMPP && defined(LOCKNUMREC) ncp = (NC *) shmalloc(sizeof(NC)); #else ncp = (NC *) malloc(sizeof(NC)); #endif /* _CRAYMPP && LOCKNUMREC */ if(ncp == NULL) return NULL; (void) memset(ncp, 0, sizeof(NC)); ncp->xsz = MIN_NC_XSZ; assert(ncp->xsz == ncx_len_NC(ncp,0)); ncp->chunk = chunkp != NULL ? *chunkp : NC_SIZEHINT_DEFAULT; return ncp; }
/* Make the in-memory NC structure from reading the file header */ int nc_get_NC(NC3_INFO* ncp) { int status; v1hs gs; /* the get stream */ assert(ncp != NULL); /* Initialize stream gs */ gs.nciop = ncp->nciop; gs.offset = 0; /* beginning of file */ gs.extent = 0; gs.flags = 0; gs.version = 0; gs.base = NULL; gs.pos = gs.base; { /* * Come up with a reasonable stream read size. */ off_t filesize; size_t extent = ncp->xsz; if(extent <= ((fIsSet(ncp->flags, NC_64BIT_DATA))?MIN_NC5_XSZ:MIN_NC3_XSZ)) { status = ncio_filesize(ncp->nciop, &filesize); if(status) return status; if(filesize < sizeof(ncmagic)) { /* too small, not netcdf */ status = NC_ENOTNC; return status; } /* first time read */ extent = ncp->chunk; /* Protection for when ncp->chunk is huge; * no need to read hugely. */ if(extent > 4096) extent = 4096; if(extent > filesize) extent = filesize; } else if(extent > ncp->chunk) extent = ncp->chunk; /* * Invalidate the I/O buffers to force a read of the header * region. */ status = ncio_sync(gs.nciop); if(status) return status; status = fault_v1hs(&gs, extent); if(status) return status; } /* get the header from the stream gs */ { /* Get & check magic number */ schar magic[sizeof(ncmagic)]; (void) memset(magic, 0, sizeof(magic)); status = ncx_getn_schar_schar( (const void **)(&gs.pos), sizeof(magic), magic); if(status != ENOERR) goto unwind_get; if(memcmp(magic, ncmagic, sizeof(ncmagic)-1) != 0) { status = NC_ENOTNC; goto unwind_get; } /* Check version number in last byte of magic */ if (magic[sizeof(ncmagic)-1] == 0x1) { gs.version = 1; } else if (magic[sizeof(ncmagic)-1] == 0x2) { gs.version = 2; fSet(ncp->flags, NC_64BIT_OFFSET); /* Now we support version 2 file access on non-LFS systems -- rkr */ #if 0 if (sizeof(off_t) != 8) { fprintf(stderr, "NETCDF WARNING: Version 2 file on 32-bit system.\n"); } #endif } else if (magic[sizeof(ncmagic)-1] == 0x5) { gs.version = 5; fSet(ncp->flags, NC_64BIT_DATA); } else { status = NC_ENOTNC; goto unwind_get; } } { size_t nrecs = 0; if (gs.version == 5) { long long tmp = 0; status = ncx_get_int64((const void **)(&gs.pos), &tmp); nrecs = (size_t)tmp; } else status = ncx_get_size_t((const void **)(&gs.pos), &nrecs); if(status != ENOERR) goto unwind_get; NC_set_numrecs(ncp, nrecs); } assert((char *)gs.pos < (char *)gs.end); status = v1h_get_NC_dimarray(&gs, &ncp->dims); if(status != ENOERR) goto unwind_get; status = v1h_get_NC_attrarray(&gs, &ncp->attrs); if(status != ENOERR) goto unwind_get; status = v1h_get_NC_vararray(&gs, &ncp->vars); if(status != ENOERR) goto unwind_get; ncp->xsz = ncx_len_NC(ncp, (gs.version == 1) ? 4 : 8); status = NC_computeshapes(ncp); if(status != ENOERR) goto unwind_get; unwind_get: (void) rel_v1hs(&gs); return status; }
int nc__create_mp(const char * path, int ioflags, size_t initialsz, int basepe, size_t *chunksizehintp, int *ncid_ptr) { NC *ncp; int status; void *xp = NULL; int sizeof_off_t = 0; #if ALWAYS_NC_SHARE /* DEBUG */ fSet(ioflags, NC_SHARE); #endif ncp = new_NC(chunksizehintp); if(ncp == NULL) return NC_ENOMEM; #if defined(LOCKNUMREC) /* && _CRAYMPP */ if (status = NC_init_pe(ncp, basepe)) { return status; } #else /* * !_CRAYMPP, only pe 0 is valid */ if(basepe != 0) return NC_EINVAL; #endif assert(ncp->flags == 0); /* Apply default create format. */ if (default_create_format == NC_FORMAT_64BIT) ioflags |= NC_64BIT_OFFSET; if (fIsSet(ioflags, NC_64BIT_OFFSET)) { fSet(ncp->flags, NC_64BIT_OFFSET); sizeof_off_t = 8; } else { sizeof_off_t = 4; } assert(ncp->xsz == ncx_len_NC(ncp,sizeof_off_t)); status = ncio_create(path, ioflags, initialsz, 0, ncp->xsz, &ncp->chunk, &ncp->nciop, &xp); if(status != NC_NOERR) { /* translate error status */ if(status == EEXIST) status = NC_EEXIST; goto unwind_alloc; } fSet(ncp->flags, NC_CREAT); if(fIsSet(ncp->nciop->ioflags, NC_SHARE)) { /* * NC_SHARE implies sync up the number of records as well. * (File format version one.) * Note that other header changes are not shared * automatically. Some sort of IPC (external to this package) * would be used to trigger a call to nc_sync(). */ fSet(ncp->flags, NC_NSYNC); } status = ncx_put_NC(ncp, &xp, sizeof_off_t, ncp->xsz); if(status != NC_NOERR) goto unwind_ioc; add_to_NCList(ncp); if(chunksizehintp != NULL) *chunksizehintp = ncp->chunk; *ncid_ptr = ncp->nciop->fd; return NC_NOERR; unwind_ioc: (void) ncio_close(ncp->nciop, 1); /* N.B.: unlink */ ncp->nciop = NULL; /*FALLTHRU*/ unwind_alloc: free_NC(ncp); return status; }
/* * Compute each variable's 'begin' offset, * update 'begin_rec' as well. */ static int NC_begins(NC *ncp, size_t h_minfree, size_t v_align, size_t v_minfree, size_t r_align) { size_t ii; int sizeof_off_t; off_t index = 0; NC_var **vpp; NC_var *last = NULL; if(v_align == NC_ALIGN_CHUNK) v_align = ncp->chunk; if(r_align == NC_ALIGN_CHUNK) r_align = ncp->chunk; if (fIsSet(ncp->flags, NC_64BIT_OFFSET)) { sizeof_off_t = 8; } else { sizeof_off_t = 4; } ncp->xsz = ncx_len_NC(ncp,sizeof_off_t); if(ncp->vars.nelems == 0) return NC_NOERR; /* only (re)calculate begin_var if there is not sufficient space in header or start of non-record variables is not aligned as requested by valign */ if (ncp->begin_var < ncp->xsz + h_minfree || ncp->begin_var != D_RNDUP(ncp->begin_var, v_align) ) { index = (off_t) ncp->xsz; ncp->begin_var = D_RNDUP(index, v_align); if(ncp->begin_var < index + h_minfree) { ncp->begin_var = D_RNDUP(index + (off_t)h_minfree, v_align); } } index = ncp->begin_var; /* loop thru vars, first pass is for the 'non-record' vars */ vpp = ncp->vars.value; for(ii = 0; ii < ncp->vars.nelems ; ii++, vpp++) { if( IS_RECVAR(*vpp) ) { /* skip record variables on this pass */ continue; } #if 0 fprintf(stderr, " VAR %d %s: %ld\n", ii, (*vpp)->name->cp, (long)index); #endif if( sizeof_off_t == 4 && (index > X_OFF_MAX || index < 0) ) { return NC_EVARSIZE; } (*vpp)->begin = index; index += (*vpp)->len; } /* only (re)calculate begin_rec if there is not sufficient space at end of non-record variables or if start of record variables is not aligned as requested by r_align */ if (ncp->begin_rec < index + v_minfree || ncp->begin_rec != D_RNDUP(ncp->begin_rec, r_align) ) { ncp->begin_rec = D_RNDUP(index, r_align); if(ncp->begin_rec < index + v_minfree) { ncp->begin_rec = D_RNDUP(index + (off_t)v_minfree, r_align); } } index = ncp->begin_rec; ncp->recsize = 0; /* loop thru vars, second pass is for the 'record' vars */ vpp = (NC_var **)ncp->vars.value; for(ii = 0; ii < ncp->vars.nelems; ii++, vpp++) { if( !IS_RECVAR(*vpp) ) { /* skip non-record variables on this pass */ continue; } #if 0 fprintf(stderr, " REC %d %s: %ld\n", ii, (*vpp)->name->cp, (long)index); #endif if( sizeof_off_t == 4 && (index > X_OFF_MAX || index < 0) ) { return NC_EVARSIZE; } (*vpp)->begin = index; index += (*vpp)->len; /* check if record size must fit in 32-bits */ #if SIZEOF_OFF_T == SIZEOF_SIZE_T && SIZEOF_SIZE_T == 4 if( ncp->recsize > X_UINT_MAX - (*vpp)->len ) { return NC_EVARSIZE; } #endif ncp->recsize += (*vpp)->len; last = (*vpp); } /* * for special case of exactly one record variable, pack value */ if(last != NULL && ncp->recsize == last->len) ncp->recsize = *last->dsizes * last->xsz; if(NC_IsNew(ncp)) NC_set_numrecs(ncp, 0); return NC_NOERR; }