Ejemplo n.º 1
0
static int
ncio_fileio_rel(ncio *const nciop, off_t offset, int rflags)
{
	int status = NC_NOERR;
        FILE* f = descriptors[nciop->fd];

	ncio_ffio *ffp = (ncio_ffio *)nciop->pvt;

	assert(ffp->bf_offset <= offset);
	assert(ffp->bf_cnt != 0);
	assert(ffp->bf_cnt <= ffp->bf_extent);
#ifdef X_ALIGN
	assert(offset < ffp->bf_offset + X_ALIGN);
	assert(ffp->bf_cnt % X_ALIGN == 0 );
#endif

	if(fIsSet(rflags, RGN_MODIFIED))
	{
		if(!fIsSet(nciop->ioflags, NC_WRITE))
			return EPERM; /* attempt to write readonly file */

		status = fileio_pgout(nciop, ffp->bf_offset,
			ffp->bf_cnt,
			ffp->bf_base, &ffp->pos);
		/* if error, invalidate buffer anyway */
	}
	ffp->bf_offset = OFF_NONE;
	ffp->bf_cnt = 0;
	return status;
}
Ejemplo n.º 2
0
int
ncmpi_rename_var(int ncid,  int varid, const char *newname)
{
    int file_ver, status, other;
    NC *ncp;
    NC_var *varp;
    NC_string *old, *newStr;

    status = ncmpii_NC_check_id(ncid, &ncp); 
    if (status != NC_NOERR)
        return status;

    if (NC_readonly(ncp))
        return NC_EPERM;

    file_ver = 1;
    if (fIsSet(ncp->flags, NC_64BIT_OFFSET))
        file_ver = 2;
    else if (fIsSet(ncp->flags, NC_64BIT_DATA))
        file_ver = 5;

    status = ncmpii_NC_check_name(newname, file_ver);
    if (status != NC_NOERR) return status;

    /* check for name in use */
    other = ncmpii_NC_findvar(&ncp->vars, newname, &varp);
    if (other != -1)
        return NC_ENAMEINUSE;
        
    varp = ncmpii_NC_lookupvar(ncp, varid);
    if (varp == NULL)
        /* invalid varid */
        return NC_ENOTVAR; /* TODO: is this the right error code? */

    old = varp->name;
    if (NC_indef(ncp)) {
       newStr = ncmpii_new_NC_string(strlen(newname),newname);
       if (newStr == NULL)
           return(-1);
       varp->name = newStr;
       ncmpii_free_NC_string(old);
       return NC_NOERR;
    }
    /* else, not in define mode */

    status = ncmpii_set_NC_string(varp->name, newname);
    if (status != NC_NOERR)
        return status;

    set_NC_hdirty(ncp);

    if (NC_doHsync(ncp)) {
        status = ncmpii_NC_sync(ncp, 1);
        if (status != NC_NOERR)
            return status;
    }

    return NC_NOERR;
}
Ejemplo n.º 3
0
int
ncmpi_rename_dim( int ncid, int dimid, const char *newname)
{
    int file_ver, status, existid;
    NC *ncp;
    NC_dim *dimp;

    status = ncmpii_NC_check_id(ncid, &ncp); 
    if (status != NC_NOERR)
        return status;

    if (NC_readonly(ncp))
        return NC_EPERM;

    file_ver = 1;
    if (fIsSet(ncp->flags, NC_64BIT_OFFSET))
        file_ver = 2;
    else if (fIsSet(ncp->flags, NC_64BIT_DATA))
        file_ver = 5;

    status = ncmpii_NC_check_name(newname, file_ver);
    if (status != NC_NOERR) return status;

    existid = NC_finddim(&ncp->dims, newname, &dimp);
    if (existid != -1)
        return NC_ENAMEINUSE;

    dimp = ncmpii_elem_NC_dimarray(&ncp->dims, (size_t) dimid);
    if (dimp == NULL)
        return NC_EBADDIM;

    if (NC_indef(ncp)) {
        NC_string *old = dimp->name;
        NC_string *newStr = ncmpii_new_NC_string(strlen(newname), newname);
        if (newStr == NULL)
            return NC_ENOMEM;
        dimp->name = newStr;
        ncmpii_free_NC_string(old);
        return NC_NOERR;
    }
    /* else, not in define mode */

    status = ncmpii_set_NC_string(dimp->name, newname);
    if (status != NC_NOERR)
        return status;

    set_NC_hdirty(ncp);

    if (NC_doHsync(ncp)) {
        status = ncmpii_NC_sync(ncp, 1);
        if (status != NC_NOERR)
            return status;
    }

    return NC_NOERR;
}
Ejemplo n.º 4
0
/* This function indicates the file region starting at offset may be
   released.  Each read or write to the file is bracketed by a call to
   the "get" region function and a call to the "rel" region function.
   If you only read from the memory region, release it with a flag of
   0, if you modify the region, release it with a flag of
   RGN_MODIFIED.

   For POSIX system, without NC_SHARE, this becomes the rel function
   pointed to by the ncio rel function pointer. It mearly checks for
   file write permission, then calls px_rel to do everything.

   nciop - pointer to ncio struct.
   offset - num bytes from beginning of buffer to region to be
   released.
   rflags - only RGN_MODIFIED is relevent to this function, others ignored
*/
static int
ncio_px_rel(ncio *const nciop, off_t offset, int rflags)
{
	ncio_px *const pxp = (ncio_px *)nciop->pvt;

	if(fIsSet(rflags, RGN_MODIFIED) && !fIsSet(nciop->ioflags, NC_WRITE))
		return EPERM; /* attempt to write readonly file */

	return px_rel(pxp, offset, rflags);
}
Ejemplo n.º 5
0
int
nc_redef(int ncid)
{
	int status;
	NC *ncp;

	status = NC_check_id(ncid, &ncp); 
	if(status != NC_NOERR)
		return status;

	if(NC_readonly(ncp))
		return NC_EPERM;

	if(NC_indef(ncp))
		return NC_EINDEFINE;

	
	if(fIsSet(ncp->nciop->ioflags, NC_SHARE))
	{
		/* read in from disk */
		status = read_NC(ncp);
		if(status != NC_NOERR)
			return status;
	}

	ncp->old = dup_NC(ncp);
	if(ncp->old == NULL)
		return NC_ENOMEM;

	fSet(ncp->flags, NC_INDEF);

	return NC_NOERR;
}
Ejemplo n.º 6
0
static ncio *
ncio_new(const char *path, int ioflags)
{
	size_t sz_ncio = M_RNDUP(sizeof(ncio));
	size_t sz_path = M_RNDUP(strlen(path) +1);
	size_t sz_ncio_pvt;
	ncio *nciop;
 
#if ALWAYS_NC_SHARE /* DEBUG */
	fSet(ioflags, NC_SHARE);
#endif

	if(fIsSet(ioflags, NC_SHARE))
		fprintf(stderr, "NC_SHARE not implemented for fileio\n");

	sz_ncio_pvt = sizeof(ncio_ffio);

	nciop = (ncio *) malloc(sz_ncio + sz_path + sz_ncio_pvt);
	if(nciop == NULL)
		return NULL;
	
	nciop->ioflags = ioflags;
	*((int *)&nciop->fd) = -1; /* cast away const */

	nciop->path = (char *) ((char *)nciop + sz_ncio);
	(void) strcpy((char *)nciop->path, path); /* cast away const */

				/* cast away const */
	*((void **)&nciop->pvt) = (void *)(nciop->path + sz_path);

	ncio_fileio_init(nciop);

	return nciop;
}
Ejemplo n.º 7
0
/* This function indicates the file region starting at offset may be
   released.

   This is for POSIX, without NC_SHARE.  If called with RGN_MODIFIED
   flag, sets the modified flag in pxp->bf_rflags and decrements the
   reference count.

   pxp - pointer to posix non-share ncio_px struct.

   offset - file offset for beginning of to region to be
   released.

   rflags - only RGN_MODIFIED is relevent to this function, others ignored
*/
static int
px_rel(ncio_px *const pxp, off_t offset, int rflags)
{
	assert(pxp->bf_offset <= offset
		 && offset < pxp->bf_offset + (off_t) pxp->bf_extent);
	assert(pIf(fIsSet(rflags, RGN_MODIFIED),
		fIsSet(pxp->bf_rflags, RGN_WRITE)));

	if(fIsSet(rflags, RGN_MODIFIED))
	{
		fSet(pxp->bf_rflags, RGN_MODIFIED);
	}
	pxp->bf_refcount--;

	return ENOERR;
}
Ejemplo n.º 8
0
int
nc_set_fill(int ncid,
	int fillmode, int *old_mode_ptr)
{
	int status;
	NC *ncp;
	int oldmode;

	status = NC_check_id(ncid, &ncp); 
	if(status != NC_NOERR)
		return status;

	if(NC_readonly(ncp))
		return NC_EPERM;

	oldmode = fIsSet(ncp->flags, NC_NOFILL) ? NC_NOFILL : NC_FILL;

	if(fillmode == NC_NOFILL)
	{
		fSet(ncp->flags, NC_NOFILL);
	}
	else if(fillmode == NC_FILL)
	{
		if(fIsSet(ncp->flags, NC_NOFILL))
		{
			/*
			 * We are changing back to fill mode
			 * so do a sync
			 */
			status = NC_sync(ncp);
			if(status != NC_NOERR)
				return status;
		}
		fClr(ncp->flags, NC_NOFILL);
	}
	else
	{
		return NC_EINVAL; /* Invalid fillmode */
	}

	if(old_mode_ptr != NULL)
		*old_mode_ptr = oldmode;

	return NC_NOERR;
}
Ejemplo n.º 9
0
/* How much space in the header is required for the NC data structure? */
size_t
ncx_len_NC(const NC3_INFO* ncp, size_t sizeof_off_t)
{
	int version=1;
	size_t xlen = sizeof(ncmagic);

	assert(ncp != NULL);
	if (fIsSet(ncp->flags, NC_64BIT_DATA)) /* CDF-5 */
		version = 5;
    	else if (fIsSet(ncp->flags, NC_64BIT_OFFSET)) /* CDF-2 */
		version = 2;

	xlen += (version == 5) ? X_SIZEOF_INT64 : X_SIZEOF_SIZE_T; /* numrecs */
	xlen += ncx_len_NC_dimarray(&ncp->dims, version);
	xlen += ncx_len_NC_attrarray(&ncp->attrs, version);
	xlen += ncx_len_NC_vararray(&ncp->vars, sizeof_off_t, version);
	
	return xlen;
}
Ejemplo n.º 10
0
Archivo: mmapio.c Proyecto: Kitware/VTK
/*
 *  Sync any changes to disk, then truncate or extend file so its size
 *  is length.  This is only intended to be called before close, if the
 *  file is open for writing and the actual size does not match the
 *  calculated size, perhaps as the result of having been previously
 *  written in NOFILL mode.
 */
static int
mmapio_pad_length(ncio* nciop, off_t length)
{
    NCMMAPIO* mmapio;
    if(nciop == NULL || nciop->pvt == NULL) return NC_EINVAL;
    mmapio = (NCMMAPIO*)nciop->pvt;

    if(!fIsSet(nciop->ioflags, NC_WRITE))
        return EPERM; /* attempt to write readonly file*/

    if(mmapio->locked > 0)
	return NC_EDISKLESS;

    if(length > mmapio->alloc) {
        /* Realloc the allocated memory to a multiple of the pagesize*/
	off_t newsize = length;
	void* newmem = NULL;
	/* Round to a multiple of pagesize */
	if((newsize % pagesize) != 0)
	    newsize += (pagesize - (newsize % pagesize));

	/* Force file size to be properly extended */
	{ /* Cause the output file to have enough allocated space */
	off_t pos = lseek(mmapio->mapfd,0,SEEK_CUR); /* save current position*/
	/* cause file to be extended in size */
	lseek(mmapio->mapfd,newsize-1,SEEK_SET);
        write(mmapio->mapfd,"",mmapio->alloc);
	lseek(mmapio->mapfd,pos,SEEK_SET); /* reset position */
	}

#ifdef HAVE_MREMAP
	newmem = (char*)mremap(mmapio->memory,mmapio->alloc,newsize,MREMAP_MAYMOVE);
	if(newmem == NULL) return NC_ENOMEM;
#else
        newmemory = (char*)mmap(NULL,newsize,
                                    persist?(PROT_READ|PROT_WRITE):(PROT_READ),
				    MAP_SHARED,
                                    mmapio->mapfd,0);
	if(newmem == NULL) return NC_ENOMEM;
	memcpy(newmemory,mmapio->memory,mmapio->alloc);
        munmap(mmapio->memory,mmapio->alloc);
#endif

#ifdef DEBUG
fprintf(stderr,"realloc: %lu/%lu -> %lu/%lu\n",
(unsigned long)mmapio->memory,(unsigned long)mmapio->alloc,
(unsigned long)newmem,(unsigned long)newsize);
#endif
	mmapio->memory = newmem;
	mmapio->alloc = newsize;
    }  
    mmapio->size = length;
    return NC_NOERR;
}
Ejemplo n.º 11
0
int
ncio_open(const char *path,
	int ioflags,
	off_t igeto, size_t igetsz, size_t *sizehintp,
	ncio **nciopp, void **const igetvpp)
{
	ncio *nciop;
	char* oflags = fIsSet(ioflags, NC_WRITE) ? "r+"
#ifdef WINCE
						 : "rb";
#else
						 : "r";
Ejemplo n.º 12
0
/*
 *  Sync any changes to disk, then truncate or extend file so its size
 *  is length.  This is only intended to be called before close, if the
 *  file is open for writing and the actual size does not match the
 *  calculated size, perhaps as the result of having been previously
 *  written in NOFILL mode.
 */
static int
memio_pad_length(ncio* nciop, off_t length)
{
    NCMEMIO* memio;
    size_t len = (size_t)length;
    if(nciop == NULL || nciop->pvt == NULL) return NC_EINVAL;
    memio = (NCMEMIO*)nciop->pvt;

    if(!fIsSet(nciop->ioflags,NC_WRITE))
        return EPERM; /* attempt to write readonly file*/
    if(memio->locked)
	return NC_EINMEMORY;

    if(len > memio->alloc) {
        /* Realloc the allocated memory to a multiple of the pagesize*/
	size_t newsize = (size_t)len;
	void* newmem = NULL;
	/* Round to a multiple of pagesize */
	if((newsize % pagesize) != 0)
	    newsize += (pagesize - (newsize % pagesize));

        newmem = (char*)reallocx(memio->memory,newsize,memio->alloc);
        if(newmem == NULL) return NC_ENOMEM;
	/* If not copy is set, then fail if the newmem address is different
           from old address */
	if(newmem != memio->memory) {
	    memio->modified++;
	    if(memio->locked) {
		free(newmem);
		return NC_EINMEMORY;
	    }
        }
	/* zero out the extra memory */
        memset((void*)((char*)newmem+memio->alloc),0,(size_t)(newsize - memio->alloc));

#ifdef DEBUG
fprintf(stderr,"realloc: %lu/%lu -> %lu/%lu\n",
(unsigned long)memio->memory,(unsigned long)memio->alloc,
(unsigned long)newmem,(unsigned long)newsize);
#endif
	if(memio->memory != NULL && (!memio->locked || memio->modified))
	    free(memio->memory);
	memio->memory = newmem;
	memio->alloc = newsize;
	memio->modified = 1;
    }
    memio->size = len;
    return NC_NOERR;
}
Ejemplo n.º 13
0
int
nc_inq_format(int ncid, int *formatp)
{
	int status;
	NC *ncp;

	status = NC_check_id(ncid, &ncp); 
	if(status != NC_NOERR)
		return status;

	/* only need to check for netCDF-3 variants, since this is never called for netCDF-4 
	   files */
	*formatp = fIsSet(ncp->flags, NC_64BIT_OFFSET) ? NC_FORMAT_64BIT 
	    : NC_FORMAT_CLASSIC; 
	return NC_NOERR;
}
Ejemplo n.º 14
0
/*
 * Sync any changes to disk, then truncate or extend file so its size
 * is length.  This is only intended to be called before close, if the
 * file is open for writing and the actual size does not match the
 * calculated size, perhaps as the result of having been previously
 * written in NOFILL mode.
 */
int
ncio_pad_length(ncio *nciop, off_t length)
{
  int status = ENOERR;

  if(nciop == NULL)
    return EINVAL;

  if(!fIsSet(nciop->ioflags, NC_WRITE))
          return EPERM; /* attempt to write readonly file */

  status = nciop->sync(nciop);
  if(status != ENOERR)
          return status;

  status = fgrow2(nciop->fd, length);
  if(status != ENOERR)
          return status;
  return ENOERR;
}
Ejemplo n.º 15
0
/*
Infer from the mode
only call if iscreate or file is not easily readable.
*/
static int
NC_omodeinfer(int cmode, NCmodel* model)
{
    int stat = NC_NOERR;

    /* If no format flags are set, then use default */
    if(!fIsSet(cmode,NC_FORMAT_ALL))
	conflictset(MF,model->format,nc_get_default_format());

    /* Process the cmode; may override some already set flags */
    if(fIsSet(cmode,NC_64BIT_OFFSET)) {
	conflictset(MF,model->format,NC_FORMAT_64BIT_OFFSET);
    }
    if(fIsSet(cmode,NC_64BIT_DATA)) {
	conflictset(MF,model->format,NC_FORMAT_64BIT_DATA);
    }
    if(fIsSet(cmode,NC_NETCDF4)) {
	conflictset(MF,model->format,NC_FORMAT_NETCDF4);
    }
    if(fIsSet(cmode,(NC_UDF0|NC_UDF1))) {
	conflictset(MF,model->format,NC_FORMAT_NETCDF4);
	/* For user formats, we must back out some previous decisions */
	model->iosp = NC_IOSP_UDF; /* Do not know anything about this */
        if(fIsSet(cmode,NC_UDF0)) {
	    conflictset(MI,model->impl,NC_FORMATX_UDF0);
	} else {
	    conflictset(MI,model->impl,NC_FORMATX_UDF1);
	}
    }
    /* Ignore following flags for now */
#if 0 /* keep lgtm happy */
    if(fIsSet(cmode,NC_CLASSIC_MODEL)) {}
    if(fIsSet(cmode,NC_DISKLESS)) {}
#endif

done:
    return check(stat);
}
Ejemplo n.º 16
0
/* Given a mode= argument, and the mode flags,
   infer the iosp part of the model */
static int
extractiosp(NClist* modeargs, int cmode, NCmodel* model)
{
    int stat = NC_NOERR;
    struct IOSPS* io = iosps;

    assert(model->iosp == 0);
    for(;io->tag;io++) {
	int i;
	for(i=0;i<nclistlength(modeargs);i++) {
	    const char* p = nclistget(modeargs,i);
	    if(strcmp(p,io->tag)==0) {
		conflictset(MIO,model->iosp,io->iosp);
		goto done;
	    }
	}
    }
done:
    if(model->iosp == 0)
	model->iosp = (fIsSet(cmode,NC_INMEMORY) ? NC_IOSP_MEMORY:NC_IOSP_FILE);
    return stat;
}
Ejemplo n.º 17
0
/*
 * In data mode, same as ncclose.
 * In define mode, restore previous definition.
 * In create, remove the file.
 */
int
nc_abort(int ncid)
{
	int status;
	NC *ncp;
	int doUnlink = 0;

	status = NC_check_id(ncid, &ncp); 
	if(status != NC_NOERR)
		return status;

	doUnlink = NC_IsNew(ncp);

	if(ncp->old != NULL)
	{
		/* a plain redef, not a create */
		assert(!NC_IsNew(ncp));
		assert(fIsSet(ncp->flags, NC_INDEF));
		free_NC(ncp->old);
		ncp->old = NULL;
		fClr(ncp->flags, NC_INDEF);
	}
	else if(!NC_readonly(ncp))
	{
		status = NC_sync(ncp);
		if(status != NC_NOERR)
			return status;
	}


	(void) ncio_close(ncp->nciop, doUnlink);
	ncp->nciop = NULL;

	del_from_NCList(ncp);

	free_NC(ncp);

	return NC_NOERR;
}
Ejemplo n.º 18
0
/*
 *  Sync any changes to disk, then truncate or extend file so its size
 *  is length.  This is only intended to be called before close, if the
 *  file is open for writing and the actual size does not match the
 *  calculated size, perhaps as the result of having been previously
 *  written in NOFILL mode.
 */
static int
memio_pad_length(ncio* nciop, off_t length)
{
    NCMEMIO* memio;
    if(nciop == NULL || nciop->pvt == NULL) return NC_EINVAL;
    memio = (NCMEMIO*)nciop->pvt;

    if(!fIsSet(nciop->ioflags, NC_WRITE))
        return EPERM; /* attempt to write readonly file*/

    if(memio->locked > 0)
	return NC_EDISKLESS;

    if(length > memio->alloc) {
        /* Realloc the allocated memory to a multiple of the pagesize*/
	off_t newsize = length;
	void* newmem = NULL;
	/* Round to a multiple of pagesize */
	if((newsize % pagesize) != 0)
	    newsize += (pagesize - (newsize % pagesize));

        newmem = (char*)realloc(memio->memory,newsize);
        if(newmem == NULL) return NC_ENOMEM;

	/* zero out the extra memory */
        memset((void*)(newmem+memio->alloc),0,(newsize - memio->alloc));

#ifdef DEBUG
fprintf(stderr,"realloc: %lu/%lu -> %lu/%lu\n",
(unsigned long)memio->memory,(unsigned long)memio->alloc,
(unsigned long)newmem,(unsigned long)newsize);
#endif
	memio->memory = newmem;
	memio->alloc = newsize;
    }  
    memio->size = length;
    return NC_NOERR;
}
Ejemplo n.º 19
0
/*
 * Recompute the shapes of all variables
 * Sets ncp->begin_var to start of first variable.
 * Sets ncp->begin_rec to start of first record variable.
 * Returns -1 on error. The only possible error is a reference
 * to a non existent dimension, which could occur for a corrupted
 * netcdf file.
 */
static int
NC_computeshapes(NC3_INFO* ncp)
{
	NC_var **vpp = (NC_var **)ncp->vars.value;
	NC_var *const *const end = &vpp[ncp->vars.nelems];
	NC_var *first_var = NULL;	/* first "non-record" var */
	NC_var *first_rec = NULL;	/* first "record" var */
	int status;

	ncp->begin_var = (off_t) ncp->xsz;
	ncp->begin_rec = (off_t) ncp->xsz;
	ncp->recsize = 0;

	if(ncp->vars.nelems == 0)
		return(0);
	
	for( /*NADA*/; vpp < end; vpp++)
	{
		status = NC_var_shape(*vpp, &ncp->dims);
		if(status != ENOERR)
			return(status);

	  	if(IS_RECVAR(*vpp))	
		{
	  		if(first_rec == NULL)	
				first_rec = *vpp;
			if((*vpp)->len == UINT32_MAX &&
                           fIsSet(ncp->flags, NC_64BIT_OFFSET)) /* Flag for large last record */
                            ncp->recsize += (*vpp)->dsizes[0] * (*vpp)->xsz;
			else
			    ncp->recsize += (*vpp)->len;
		}
		else
		{
		        if(first_var == NULL)
			        first_var = *vpp;
			/*
			 * Overwritten each time thru.
			 * Usually overwritten in first_rec != NULL clause below.
			 */
			ncp->begin_rec = (*vpp)->begin + (off_t)(*vpp)->len;
		}
	}

	if(first_rec != NULL)
	{
		if(ncp->begin_rec > first_rec->begin)
		    return(NC_ENOTNC); /* not a netCDF file or corrupted */
		ncp->begin_rec = first_rec->begin;
		/*
	 	 * for special case of exactly one record variable, pack value
	 	 */
		if(ncp->recsize == first_rec->len)
			ncp->recsize = *first_rec->dsizes * first_rec->xsz;
	}

	if(first_var != NULL)
	{
		ncp->begin_var = first_var->begin;
	}
	else
	{
		ncp->begin_var = ncp->begin_rec;
	}

	if(ncp->begin_var <= 0 ||
	   ncp->xsz > (size_t)ncp->begin_var ||
	   ncp->begin_rec <= 0 ||
	   ncp->begin_var > ncp->begin_rec)
	    return(NC_ENOTNC); /* not a netCDF file or corrupted */

	return(ENOERR);
}
Ejemplo n.º 20
0
/* Create a new ncio struct to hold info about the file. */
static int
memio_new(const char* path, int ioflags, off_t initialsize, ncio** nciopp, NCMEMIO** memiop)
{
    int status = NC_NOERR;
    ncio* nciop = NULL;
    NCMEMIO* memio = NULL;
    int openfd = -1;

    if(pagesize == 0) {

#if defined (_WIN32) || defined(_WIN64)
      SYSTEM_INFO info;
      GetSystemInfo (&info);
      pagesize = info.dwPageSize;
#elif defined HAVE_SYSCONF
        pagesize = sysconf(_SC_PAGE_SIZE);
#elif defined HAVE_GETPAGESIZE
        pagesize = getpagesize();
#else
        pagesize = 4096; /* good guess */
#endif
    }

    errno = 0;

    /* Always force the allocated size to be a multiple of pagesize */
    if(initialsize == 0) initialsize = pagesize;
    if((initialsize % pagesize) != 0)
	initialsize += (pagesize - (initialsize % pagesize));

    nciop = (ncio* )calloc(1,sizeof(ncio));
    if(nciop == NULL) {status = NC_ENOMEM; goto fail;}
    
    nciop->ioflags = ioflags;
    *((int*)&nciop->fd) = -1; /* caller will fix */

    *((char**)&nciop->path) = strdup(path);
    if(nciop->path == NULL) {status = NC_ENOMEM; goto fail;}

    *((ncio_relfunc**)&nciop->rel) = memio_rel;
    *((ncio_getfunc**)&nciop->get) = memio_get;
    *((ncio_movefunc**)&nciop->move) = memio_move;
    *((ncio_syncfunc**)&nciop->sync) = memio_sync;
    *((ncio_filesizefunc**)&nciop->filesize) = memio_filesize;
    *((ncio_pad_lengthfunc**)&nciop->pad_length) = memio_pad_length;
    *((ncio_closefunc**)&nciop->close) = memio_close;

    memio = (NCMEMIO*)calloc(1,sizeof(NCMEMIO));
    if(memio == NULL) {status = NC_ENOMEM; goto fail;}
    *((void* *)&nciop->pvt) = memio;

    memio->alloc = initialsize;

    memio->memory = NULL;
    memio->size = 0;
    memio->pos = 0;
    memio->persist = fIsSet(ioflags,NC_WRITE);

    if(nciopp) *nciopp = nciop;
    if(memiop) *memiop = memio;

done:
    if(openfd >= 0) close(openfd);
    return status;

fail:
    if(nciop != NULL) {
        if(nciop->path != NULL) free((char*)nciop->path);
    }
    goto done;
}
Ejemplo n.º 21
0
/* This function opens the data file. It is only called from nc.c,
   from nc__open_mp and nc_delete_mp.

   path - path of data file.
   ioflags - flags passed into nc_open.
   igeto - looks like this function can do an initial page get, and
   igeto is going to be the offset for that. But it appears to be
   unused 
   igetsz - the size in bytes of initial page get (a.k.a. extent). Not
   ever used in the library.
   sizehintp - the size of a page of data for buffered reads and writes.
   nciopp - pointer to pointer that will get address of newly created
   and inited ncio struct.
   mempp - pointer to pointer to the initial memory read.
*/
int
memio_open(const char* path,
    int ioflags,
    off_t igeto, size_t igetsz, size_t* sizehintp,
    ncio* *nciopp, void** const mempp)
{
    ncio* nciop;
    int fd;
    int status;
    int persist = (fIsSet(ioflags,NC_WRITE)?1:0);
    int oflags;
    NCMEMIO* memio = NULL;
    size_t sizehint;
    off_t filesize;

    if(path == NULL ||* path == 0)
        return EINVAL;

    assert(sizehintp != NULL);
    sizehint = *sizehintp;

    /* Open the file, but make sure we can write it if needed */
    oflags = (persist ? O_RDWR : O_RDONLY);    
#ifdef O_BINARY
    fSet(oflags, O_BINARY);
#endif
    oflags |= O_EXCL;
#ifdef vms
    fd = open(path, oflags, 0, "ctx=stm");
#else
    fd  = open(path, oflags, OPENMODE);
#endif
#ifdef DEBUG
    if(fd < 0) {
	fprintf(stderr,"open failed: file=%s err=",path);
	perror("");
    }
#endif
    if(fd < 0) {status = errno; goto unwind_open;}

    /* get current filesize  = max(|file|,initialize)*/
    filesize = lseek(fd,0,SEEK_END);
    if(filesize < 0) {status = errno; goto unwind_open;}
    /* move pointer back to beginning of file */
    (void)lseek(fd,0,SEEK_SET);
    if(filesize < (off_t)sizehint)
        filesize = (off_t)sizehint;

    status = memio_new(path, ioflags, filesize, &nciop, &memio);
    if(status != NC_NOERR)
	return status;
    memio->size = filesize;

    memio->memory = (char*)malloc(memio->alloc);
    if(memio->memory == NULL) {status = NC_ENOMEM; goto unwind_open;}

#ifdef DEBUG
fprintf(stderr,"memio_open: initial memory: %lu/%lu\n",(unsigned long)memio->memory,(unsigned long)memio->alloc);
#endif

    /* Read the file into the memio memory */
    /* We need to do multiple reads because there is no
       guarantee that the amount read will be the full amount */
    {
	off_t red = memio->size;
	char* pos = memio->memory;
	while(red > 0) {
	    ssize_t count = read(fd, pos, red);
	    if(count < 0)
	        {close(fd); status = errno; goto unwind_open;}
	    if(count == 0)
	        {close(fd); status = NC_ENOTNC; goto unwind_open;}
	    red -= count;
	    pos += count;
	}
    }
    (void)close(fd); /* until memio_close() */

    /* Use half the filesize as the blocksize */
    sizehint = filesize/2;

    fd = nc__pseudofd();
    *((int* )&nciop->fd) = fd; 

    if(igetsz != 0)
    {
        status = nciop->get(nciop,
                igeto, igetsz,
                0,
                mempp);
        if(status != NC_NOERR)
            goto unwind_open;
    }

    *sizehintp = sizehint;
    *nciopp = nciop;
    return NC_NOERR;

unwind_open:
    memio_close(nciop,0);
    return status;
}
Ejemplo n.º 22
0
/* Create a file, and the ncio struct to go with it. This function is
   only called from nc__create_mp.

   path - path of file to create.
   ioflags - flags from nc_create
   initialsz - From the netcdf man page: "The argument
   Iinitialsize sets the initial size of the file at creation time."
   igeto - 
   igetsz - 
   sizehintp - the size of a page of data for buffered reads and writes.
   nciopp - pointer to a pointer that will get location of newly
   created and inited ncio struct.
   mempp - pointer to pointer to the initial memory read.
*/
int
memio_create(const char* path, int ioflags,
    size_t initialsz,
    off_t igeto, size_t igetsz, size_t* sizehintp,
    ncio* *nciopp, void** const mempp)
{
    ncio* nciop;
    int fd;
    int status;
    NCMEMIO* memio = NULL;
    int persist = (ioflags & NC_WRITE?1:0);
    int oflags;

    if(path == NULL ||* path == 0)
        return NC_EINVAL;

    /* For diskless open has, the file must be classic version 1 or 2.*/
    if(fIsSet(ioflags,NC_NETCDF4))
        return NC_EDISKLESS; /* violates constraints */

    status = memio_new(path, ioflags, initialsz, &nciop, &memio);
    if(status != NC_NOERR)
        return status;
    memio->size = 0;

    if(!persist) {
	memio->memory = (char*)malloc(memio->alloc);
	if(memio->memory == NULL) {status = NC_ENOMEM; goto unwind_open;}
    } else { /*persist */
        /* Open the file, but make sure we can write it if needed */
        oflags = (persist ? O_RDWR : O_RDONLY);    
#ifdef O_BINARY
        fSet(oflags, O_BINARY);
#endif
    	oflags |= (O_CREAT|O_TRUNC);
        if(fIsSet(ioflags,NC_NOCLOBBER))
	    oflags |= O_EXCL;
#ifdef vms
        fd = open(path, oflags, 0, "ctx=stm");
#else
        fd  = open(path, oflags, OPENMODE);
#endif
        if(fd < 0) {status = errno; goto unwind_open;}

        (void)close(fd); /* will reopen at nc_close */
	/* malloc memory */
	memio->memory = (char*)malloc(memio->alloc);
	if(memio->memory == NULL) {status = NC_ENOMEM; goto unwind_open;}
    } /*!persist*/

#ifdef DEBUG
fprintf(stderr,"memio_create: initial memory: %lu/%lu\n",(unsigned long)memio->memory,(unsigned long)memio->alloc);
#endif

    fd = nc__pseudofd();
    *((int* )&nciop->fd) = fd; 

    fSet(nciop->ioflags, NC_WRITE);

    if(igetsz != 0)
    {
        status = nciop->get(nciop,
                igeto, igetsz,
                RGN_WRITE,
                mempp);
        if(status != NC_NOERR)
            goto unwind_open;
    }

    /* Pick a default sizehint */
    if(sizehintp) *sizehintp = pagesize;

    *nciopp = nciop;
    return NC_NOERR;

unwind_open:
    memio_close(nciop,1);
    return status;
}
Ejemplo n.º 23
0
/*----< ncmpi_def_var() >----------------------------------------------------*/
int
ncmpi_def_var(int         ncid,
              const char *name,
              nc_type     type,
              int         ndims,
              const int  *dimids,
              int        *varidp)
{
    int varid, file_ver, status;
    NC *ncp;
    NC_var *varp;

    /* check if ncid is valid */
    status = ncmpii_NC_check_id(ncid, &ncp); 
    if (status != NC_NOERR) return status;

    /* check if called in define mode */
    if (!NC_indef(ncp)) return NC_ENOTINDEFINE;

    /* check if the name string is legal for netcdf format */
    file_ver = 1;
    if (fIsSet(ncp->flags, NC_64BIT_OFFSET))
        file_ver = 2;
    else if (fIsSet(ncp->flags, NC_64BIT_DATA))
        file_ver = 5;
    status = ncmpii_NC_check_name(name, file_ver);
    if (status != NC_NOERR) return status;

    /* check if type is a valid netcdf type */
    status = ncmpii_cktype(type);
    if (status != NC_NOERR) return status;

    /* TODO: can ndims > 2^32 in CDF-5 ? */
    if ((ndims < 0) || ndims > X_INT_MAX) return NC_EINVAL;

    /* there is an upperbound for the number of variables defeined in a file */
    if (ncp->vars.ndefined >= NC_MAX_VARS) return NC_EMAXVARS;

    /* check whether the variable name has been used */
    varid = ncmpii_NC_findvar(&ncp->vars, name, &varp);
    if (varid != -1) return NC_ENAMEINUSE;

    /* create a new variable */
    varp = ncmpii_new_NC_var(name, type, ndims, dimids);
    if (varp == NULL) return NC_ENOMEM;

    /* set up array dimensional structures */
    status = ncmpii_NC_var_shape64(ncp, varp, &ncp->dims);
    if (status != NC_NOERR) {
        ncmpii_free_NC_var(varp);
        return status;
    }

    /* Add a new handle to the end of an array of handles */
    status = incr_NC_vararray(&ncp->vars, varp);
    if (status != NC_NOERR) {
        ncmpii_free_NC_var(varp);
        return status;
    }

    if (varidp != NULL)
        *varidp = (int)ncp->vars.ndefined - 1; /* varid */
        /* ncp->vars.ndefined has been increased in incr_NC_vararray() */

    return NC_NOERR;
}
Ejemplo n.º 24
0
/* 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;
}
Ejemplo n.º 25
0
/*
 * set varp->xsz, varp->shape and varp->len of a variable
 */
int
ncmpii_NC_var_shape64(NC                *ncp,
                      NC_var            *varp,
                      const NC_dimarray *dims)
{
    int i;
    MPI_Offset product = 1;

    /* set the size of 1 element */
    varp->xsz = ncx_szof(varp->type);

    if (varp->ndims == 0) goto out;

    /*
     * use the user supplied dimension indices to determine the shape
     */
    for (i=0; i<varp->ndims; i++) {
        const NC_dim *dimp;

        if (varp->dimids[i] < 0)
            return NC_EBADDIM;

        if (varp->dimids[i] >= ((dims != NULL) ? dims->ndefined : 1))
            return NC_EBADDIM;

        /* get the pointer to the dim object */
        dimp = ncmpii_elem_NC_dimarray(dims, varp->dimids[i]);
        varp->shape[i] = dimp->size;

        /* check for record variable, only the highest dimension can
         * be unlimited */
        if (varp->shape[i] == NC_UNLIMITED && i != 0)
            return NC_EUNLIMPOS;
    }

    /* 
     * compute the dsizes, the right to left product of shape
     */
    product = 1;
    if (varp->ndims == 1) {
        if (varp->shape[0] == NC_UNLIMITED)
            varp->dsizes[0] = 1;
        else {
            varp->dsizes[0] = varp->shape[0];
            product = varp->shape[0];
        }
    }
    else { /* varp->ndims > 1 */
        varp->dsizes[varp->ndims-1] = varp->shape[varp->ndims-1];
        product = varp->shape[varp->ndims-1];
        for (i=varp->ndims-2; i>=0; i--) {
            if (varp->shape[i] != NC_UNLIMITED)
                product *= varp->shape[i];
            varp->dsizes[i] = product;
        }
    }

out :
    /*
     * For CDF-1 and CDF-2 formats, the total number of array elements
     * cannot exceed 2^32
     */
    if (! fIsSet(ncp->flags, NC_64BIT_DATA) && product >= X_UINT_MAX)
        return NC_EVARSIZE;

    /*
     * align variable size to 4 byte boundary, required by all netcdf file
     * formats
     */
    varp->len = product * varp->xsz;
    if (varp->len % 4 > 0)
        varp->len += 4 - varp->len % 4; /* round up */

    return NC_NOERR;
}
Ejemplo n.º 26
0
/* This function opens the data file. It is only called from nc.c,
   from nc__open_mp and nc_delete_mp.

   path - path of data file.

   ioflags - flags passed into nc_open.

   igeto - looks like this function can do an initial page get, and
   igeto is going to be the offset for that. But it appears to be
   unused

   igetsz - the size in bytes of initial page get (a.k.a. extent). Not
   ever used in the library.

   sizehintp - pointer to sizehint parameter from nc__open or
   nc__create. This is used to set pxp->blksz.

   Here's what the man page has to say:

   "The argument referenced by chunksize controls a space versus time
   tradeoff, memory allocated in the netcdf library versus number of
   system calls.

   Because of internal requirements, the value may not be set to
   exactly the value requested. The actual value chosen is returned by reference.

   Using the value NC_SIZEHINT_DEFAULT causes the library to choose a
   default. How the system choses the default depends on the
   system. On many systems, the "preferred I/O block size" is
   available from the stat() system call, struct stat member
   st_blksize. If this is available it is used. Lacking that, twice
   the system pagesize is used. Lacking a call to discover the system
   pagesize, we just set default chunksize to 8192.

   The chunksize is a property of a given open netcdf descriptor ncid,
   it is not a persistent property of the netcdf dataset."

   nciopp - pointer to pointer that will get address of newly created
   and inited ncio struct.

   igetvpp - handle to pass back pointer to data from inital page
   read, if this were ever used, which it isn't.
*/
int
posixio_open(const char *path,
	int ioflags,
	off_t igeto, size_t igetsz, size_t *sizehintp,
	ncio **nciopp, void **const igetvpp)
{
	ncio *nciop;
	int oflags = fIsSet(ioflags, NC_WRITE) ? O_RDWR : O_RDONLY;
	int fd = -1;
	int status = 0;

	if(path == NULL || *path == 0)
		return EINVAL;

	nciop = ncio_px_new(path, ioflags);
	if(nciop == NULL)
		return ENOMEM;

//#ifdef O_BINARY
#if _MSC_VER
	fSet(oflags, O_BINARY);
#endif
#ifdef vms
	fd = open(path, oflags, 0, "ctx=stm");
#else
	fd = open(path, oflags, 0);
#endif
	if(fd < 0)
	{
		status = errno;
		goto unwind_new;
	}
	*((int *)&nciop->fd) = fd; /* cast away const */

	if(*sizehintp < NCIO_MINBLOCKSIZE)
	{
		/* Use default */
		*sizehintp = blksize(fd);
	}
	else if(*sizehintp >= NCIO_MAXBLOCKSIZE)
	{
		/* Use maximum allowed value */
		*sizehintp = NCIO_MAXBLOCKSIZE;
	}
	else
	{
		*sizehintp = M_RNDUP(*sizehintp);
	}

	if(fIsSet(nciop->ioflags, NC_SHARE))
		status = ncio_spx_init2(nciop, sizehintp);
	else
		status = ncio_px_init2(nciop, sizehintp, 0);

	if(status != ENOERR)
		goto unwind_open;

	if(igetsz != 0)
	{
		status = nciop->get(nciop,
				igeto, igetsz,
                        	0,
                        	igetvpp);
		if(status != ENOERR)
			goto unwind_open;
	}

	*nciopp = nciop;
	return ENOERR;

unwind_open:
	(void) close(fd); /* assert fd >= 0 */
	/*FALLTHRU*/
unwind_new:
	ncio_close(nciop,0);
	return status;
}
Ejemplo n.º 27
0
/* POSIX get. This will "make a region available." Since we're using
   buffered IO, this means that if needed, we'll fetch a new page from
   the file, otherwise, just return a pointer to what's in memory
   already.

   nciop - pointer to ncio struct, containing file info.
   pxp - pointer to ncio_px struct, which contains special metadate
   for posix files without NC_SHARE.
   offset - start byte of region to get.
   extent - how many bytes to read.
   rflags - One of the RGN_* flags defined in ncio.h.
   vpp - pointer to pointer that will recieve data.

   NOTES:

   * For blkoffset round offset down to the nearest pxp->blksz. This
   provides the offset (in bytes) to the beginning of the block that
   holds the current offset.

   * diff tells how far into the current block we are.

   * For blkextent round up to the number of bytes at the beginning of
   the next block, after the one that holds our current position, plus
   whatever extra (i.e. the extent) that we are about to grab.

   * The blkextent can't be more than twice the pxp->blksz. That's
   because the pxp->blksize is the sizehint, and in ncio_px_init2 the
   buffer (pointed to by pxp->bf-base) is allocated with 2 *
   *sizehintp. This is checked (unneccesarily) more than once in
   asserts.

   * If this is called on a newly opened file, pxp->bf_offset will be
   OFF_NONE and we'll jump to label pgin to immediately read in a
   page.
*/
static int
px_get(ncio *const nciop, ncio_px *const pxp,
		off_t offset, size_t extent,
		int rflags,
		void **const vpp)
{
	int status = ENOERR;

	const off_t blkoffset = _RNDDOWN(offset, (off_t)pxp->blksz);
	off_t diff = (size_t)(offset - blkoffset);
	off_t blkextent = _RNDUP(diff + extent, pxp->blksz);

	assert(extent != 0);
	assert(extent < X_INT_MAX); /* sanity check */
	assert(offset >= 0); /* sanity check */

	if(2 * pxp->blksz < blkextent)
		return E2BIG; /* TODO: temporary kludge */
	if(pxp->bf_offset == OFF_NONE)
	{
		/* Uninitialized */
		if(pxp->bf_base == NULL)
		{
			assert(pxp->bf_extent == 0);
			assert(blkextent <= 2 * pxp->blksz);
			pxp->bf_base = malloc(2 * pxp->blksz);
			if(pxp->bf_base == NULL)
				return ENOMEM;
		}
		goto pgin;
	}
	/* else */
	assert(blkextent <= 2 * pxp->blksz);

	if(blkoffset == pxp->bf_offset)
	{
		/* hit */
 		if(blkextent > pxp->bf_extent)
		{
			/* page in upper */
			void *const middle =
			 	(void *)((char *)pxp->bf_base + pxp->blksz);
			assert(pxp->bf_extent == pxp->blksz);
			status = px_pgin(nciop,
				 pxp->bf_offset + (off_t)pxp->blksz,
				 pxp->blksz,
				 middle,
				 &pxp->bf_cnt,
				 &pxp->pos);
			if(status != ENOERR)
				return status;
			pxp->bf_extent = 2 * pxp->blksz;
			pxp->bf_cnt += pxp->blksz;
		}
		goto done;
	}
	/* else */

	if(pxp->bf_extent > pxp->blksz
		 && blkoffset == pxp->bf_offset + (off_t)pxp->blksz)
	{
		/* hit in upper half */
		if(blkextent == pxp->blksz)
		{
			/* all in upper half, no fault needed */
			diff += pxp->blksz;
			goto done;
		}
		/* else */
		if(pxp->bf_cnt > pxp->blksz)
		{
			/* data in upper half */
			void *const middle =
				(void *)((char *)pxp->bf_base + pxp->blksz);
			assert(pxp->bf_extent == 2 * pxp->blksz);
			if(fIsSet(pxp->bf_rflags, RGN_MODIFIED))
			{
				/* page out lower half */
				assert(pxp->bf_refcount <= 0);
				status = px_pgout(nciop,
					pxp->bf_offset,
					pxp->blksz,
					pxp->bf_base,
					&pxp->pos);
				if(status != ENOERR)
					return status;
			}
			pxp->bf_cnt -= pxp->blksz;
			/* copy upper half into lower half */
			(void) memcpy(pxp->bf_base, middle, pxp->bf_cnt);
		}
		else		/* added to fix nofill bug */
		{
			assert(pxp->bf_extent == 2 * pxp->blksz);
			/* still have to page out lower half, if modified */
			if(fIsSet(pxp->bf_rflags, RGN_MODIFIED))
			{
				assert(pxp->bf_refcount <= 0);
				status = px_pgout(nciop,
					pxp->bf_offset,
					pxp->blksz,
					pxp->bf_base,
					&pxp->pos);
				if(status != ENOERR)
					return status;
			}
		}
		pxp->bf_offset = blkoffset;
		/* pxp->bf_extent = pxp->blksz; */

 		assert(blkextent == 2 * pxp->blksz);
		{
			/* page in upper */
			void *const middle =
			 	(void *)((char *)pxp->bf_base + pxp->blksz);
			status = px_pgin(nciop,
				 pxp->bf_offset + (off_t)pxp->blksz,
				 pxp->blksz,
				 middle,
				 &pxp->bf_cnt,
				 &pxp->pos);
			if(status != ENOERR)
				return status;
			pxp->bf_extent = 2 * pxp->blksz;
			pxp->bf_cnt += pxp->blksz;
		}
		goto done;
	}
	/* else */

	if(blkoffset == pxp->bf_offset - (off_t)pxp->blksz)
	{
		/* wants the page below */
		void *const middle =
			(void *)((char *)pxp->bf_base + pxp->blksz);
		size_t upper_cnt = 0;
		if(pxp->bf_cnt > pxp->blksz)
		{
			/* data in upper half */
			assert(pxp->bf_extent == 2 * pxp->blksz);
			if(fIsSet(pxp->bf_rflags, RGN_MODIFIED))
			{
				/* page out upper half */
				assert(pxp->bf_refcount <= 0);
				status = px_pgout(nciop,
					pxp->bf_offset + (off_t)pxp->blksz,
					pxp->bf_cnt - pxp->blksz,
					middle,
					&pxp->pos);
				if(status != ENOERR)
					return status;
			}
			pxp->bf_cnt = pxp->blksz;
			pxp->bf_extent = pxp->blksz;
		}
		if(pxp->bf_cnt > 0)
		{
			/* copy lower half into upper half */
			(void) memcpy(middle, pxp->bf_base, pxp->blksz);
			upper_cnt = pxp->bf_cnt;
		}
		/* read page below into lower half */
		status = px_pgin(nciop,
			 blkoffset,
			 pxp->blksz,
			 pxp->bf_base,
			 &pxp->bf_cnt,
			 &pxp->pos);
		if(status != ENOERR)
			return status;
		pxp->bf_offset = blkoffset;
		if(upper_cnt != 0)
		{
			pxp->bf_extent = 2 * pxp->blksz;
			pxp->bf_cnt = pxp->blksz + upper_cnt;
		}
		else
		{
			pxp->bf_extent = pxp->blksz;
		}
		goto done;
	}
	/* else */

	/* no overlap */
	if(fIsSet(pxp->bf_rflags, RGN_MODIFIED))
	{
		assert(pxp->bf_refcount <= 0);
		status = px_pgout(nciop,
			pxp->bf_offset,
			pxp->bf_cnt,
			pxp->bf_base,
			&pxp->pos);
		if(status != ENOERR)
			return status;
		pxp->bf_rflags = 0;
	}

pgin:
	status = px_pgin(nciop,
		 blkoffset,
		 blkextent,
		 pxp->bf_base,
		 &pxp->bf_cnt,
		 &pxp->pos);
	if(status != ENOERR)
		return status;
	 pxp->bf_offset = blkoffset;
	 pxp->bf_extent = blkextent;

done:
	extent += diff;
	if(pxp->bf_cnt < extent)
		pxp->bf_cnt = extent;
	assert(pxp->bf_cnt <= pxp->bf_extent);

	pxp->bf_rflags |= rflags;
	pxp->bf_refcount++;

	*vpp = (char *)pxp->bf_base + diff;
	return ENOERR;
}
Ejemplo n.º 28
0
/* Like memmove(), safely move possibly overlapping data.

   Copy one region to another without making anything available to
   higher layers. May be just implemented in terms of get() and rel(),
   or may be tricky to be efficient. Only used in by nc_enddef()
   after redefinition.

   nciop - pointer to ncio struct with file info.
   to - src for move?
   from - dest for move?
   nbytes - number of bytes to move.
   rflags - One of the RGN_* flags defined in ncio.h. The only
   reasonable flag value is RGN_NOLOCK.
*/
static int
ncio_px_move(ncio *const nciop, off_t to, off_t from,
			size_t nbytes, int rflags)
{
	ncio_px *const pxp = (ncio_px *)nciop->pvt;
	int status = ENOERR;
	off_t lower;
	off_t upper;
	char *base;
	size_t diff;
	size_t extent;

	if(to == from)
		return ENOERR; /* NOOP */

	if(fIsSet(rflags, RGN_WRITE) && !fIsSet(nciop->ioflags, NC_WRITE))
		return EPERM; /* attempt to write readonly file */

	rflags &= RGN_NOLOCK; /* filter unwanted flags */

	if(to > from)
	{
		/* growing */
		lower = from;
		upper = to;
	}
	else
	{
		/* shrinking */
		lower = to;
		upper = from;
	}
	diff = (size_t)(upper - lower);
	extent = diff + nbytes;

#if INSTRUMENT
fprintf(stderr, "ncio_px_move %ld %ld %ld %ld %ld\n",
		 (long)to, (long)from, (long)nbytes, (long)lower, (long)extent);
#endif
	if(extent > pxp->blksz)
	{
		size_t remaining = nbytes;

if(to > from)
{
		off_t frm = from + nbytes;
		off_t toh = to + nbytes;
		for(;;)
		{
			size_t loopextent = MIN(remaining, pxp->blksz);
			frm -= loopextent;
			toh -= loopextent;

			status = px_double_buffer(nciop, toh, frm,
				 	loopextent, rflags) ;
			if(status != ENOERR)
				return status;
			remaining -= loopextent;

			if(remaining == 0)
				break; /* normal loop exit */
		}
}
else
{
		for(;;)
		{
			size_t loopextent = MIN(remaining, pxp->blksz);

			status = px_double_buffer(nciop, to, from,
				 	loopextent, rflags) ;
			if(status != ENOERR)
				return status;
			remaining -= loopextent;

			if(remaining == 0)
				break; /* normal loop exit */
			to += loopextent;
			from += loopextent;
		}
}
		return ENOERR;
	}

#if INSTRUMENT
fprintf(stderr, "\tncio_px_move small\n");
#endif
	status = px_get(nciop, pxp, lower, extent, RGN_WRITE|rflags,
			(void **)&base);

	if(status != ENOERR)
		return status;

	if(to > from)
		(void) memmove(base + diff, base, nbytes);
	else
		(void) memmove(base, base + diff, nbytes);

	(void) px_rel(pxp, lower, RGN_MODIFIED);

	return status;
}
Ejemplo n.º 29
0
int
ncio_create(const char *path, int ioflags,
	size_t initialsz,
	off_t igeto, size_t igetsz, size_t *sizehintp,
	ncio **nciopp, void **const igetvpp)
{
	ncio *nciop;
#ifdef _WIN32_WCE
	char* oflags = "bw+"; /*==?(O_RDWR|O_CREAT|O_TRUNC) && binary*/
#else
	char* oflags = "w+"; /*==?(O_RDWR|O_CREAT|O_TRUNC);*/
#endif
	FILE* f;
	int i,fd;
	int status = ENOERR;

	if(initialsz < (size_t)igeto + igetsz)
		initialsz = (size_t)igeto + igetsz;

	fSet(ioflags, NC_WRITE);

	if(path == NULL || *path == 0)
		return EINVAL;

	nciop = ncio_new(path, ioflags);
	if(nciop == NULL)
		return ENOMEM;

	if(fIsSet(ioflags, NC_NOCLOBBER)) {
	    /* Since we do not have use of the O_EXCL flag,
               we need to fake it */
#ifdef WINCE
	    f = fopen(path,"rb");
#else
	    f = fopen(path,"r");
#endif
	    if(f != NULL) { /* do not overwrite */
		(void)fclose(f);
		return EEXIST;
	    }		
	}

	f = fopen(path, oflags);
	if(f == NULL)
	{
		status = errno;
		goto unwind_new;
	}

	/* Locate an open pseudo file descriptor */
	fd = -1;
	for(i=1;i<fdmax;i++) {if(descriptors[i] == NULL) {fd=i;break;}}
	if(fd < 0) {fd = fdmax; fdmax++;}
	descriptors[fd] = f;

	*((int *)&nciop->fd) = fd; /* cast away const */
	if(*sizehintp < NCIO_MINBLOCKSIZE || *sizehintp > NCIO_MAXBLOCKSIZE)
	{
		/* Use default */
		*sizehintp = blksize(fd);
	}
	else
	{
		*sizehintp = M_RNDUP(*sizehintp);
	}

	status = ncio_fileio_init2(nciop, sizehintp);
	if(status != ENOERR)
		goto unwind_open;

	if(initialsz != 0)
	{
		status = fgrow(f, (off_t)initialsz);
		if(status != ENOERR)
			goto unwind_open;
	}

	if(igetsz != 0)
	{
		status = nciop->get(nciop,
				igeto, igetsz,
                        	RGN_WRITE,
                        	igetvpp);
		if(status != ENOERR)
			goto unwind_open;
	}

	*nciopp = nciop;
	return ENOERR;

unwind_open:
	(void) fclose(descriptors[fd]);
	descriptors[fd] = NULL;
	/* ?? unlink */
	/*FALLTHRU*/
unwind_new:
	ncio_free(nciop);
	return status;
}
Ejemplo n.º 30
0
static int
ncio_fileio_get(ncio *const nciop,
		off_t offset, size_t extent,
		int rflags,
		void **const vpp)
{
	ncio_ffio *ffp = (ncio_ffio *)nciop->pvt;
	int status = ENOERR;
        FILE* f = descriptors[nciop->fd];
#ifdef X_ALIGN
	size_t rem;
#endif
	
	if(fIsSet(rflags, RGN_WRITE) && !fIsSet(nciop->ioflags, NC_WRITE))
		return EPERM; /* attempt to write readonly file */

	assert(extent != 0);
	assert(extent < X_INT_MAX); /* sanity check */

	assert(ffp->bf_cnt == 0);

#ifdef X_ALIGN
	/* round to seekable boundaries */
	rem = offset % X_ALIGN;
	if(rem != 0)
	{
		offset -= rem;
		extent += rem;
	}

	{
		const size_t rndup = extent % X_ALIGN;
		if(rndup != 0)
			extent += X_ALIGN - rndup;
	}

	assert(offset % X_ALIGN == 0);
	assert(extent % X_ALIGN == 0);
#endif

	if(ffp->bf_extent < extent)
	{
		if(ffp->bf_base != NULL)
		{
			free(ffp->bf_base);
			ffp->bf_base = NULL;
			ffp->bf_extent = 0;
		}
		assert(ffp->bf_extent == 0);
		ffp->bf_base = malloc(extent);
		if(ffp->bf_base == NULL)
			return ENOMEM;
		ffp->bf_extent = extent;
	}

	status = fileio_pgin(nciop, offset,
		 extent,
		 ffp->bf_base,
		 &ffp->bf_cnt, &ffp->pos);
	if(status != ENOERR)
		return status;

	ffp->bf_offset = offset;

	if(ffp->bf_cnt < extent)
	{
		(void) memset((char *)ffp->bf_base + ffp->bf_cnt, 0,
			extent - ffp->bf_cnt);
		ffp->bf_cnt = extent;
	}


#ifdef X_ALIGN
	*vpp = (char *)ffp->bf_base + rem;
#else
	*vpp = (char *)ffp->bf_base;
#endif
	return ENOERR;
}