📄 posixio.c
字号:
rem = (size_t)(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(pxp->bf_extent < extent) { if(pxp->bf_base != NULL) { free(pxp->bf_base); pxp->bf_base = NULL; pxp->bf_extent = 0; } assert(pxp->bf_extent == 0); pxp->bf_base = malloc(extent); if(pxp->bf_base == NULL) return ENOMEM; pxp->bf_extent = extent; } status = px_pgin(nciop, offset, extent, pxp->bf_base, &pxp->bf_cnt, &pxp->pos); if(status != ENOERR) return status; pxp->bf_offset = to; /* TODO: XALIGN */ if(pxp->bf_cnt < extent) pxp->bf_cnt = extent; status = px_pgout(nciop, pxp->bf_offset, pxp->bf_cnt, pxp->bf_base, &pxp->pos); /* if error, invalidate buffer anyway */ pxp->bf_offset = OFF_NONE; pxp->bf_cnt = 0; return status;}#endif/* 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 for this file. to - dest for move? from - src for move? nbytes - number of bytes to move. rflags - One of the RGN_* flags defined in ncio.h.*/static intncio_spx_move(ncio *const nciop, off_t to, off_t from, size_t nbytes, int rflags){ int status = ENOERR; off_t lower = from; off_t upper = to; char *base; size_t diff = (size_t)(upper - lower); size_t extent = diff + nbytes; rflags &= RGN_NOLOCK; /* filter unwanted flags */ if(to == from) return ENOERR; /* NOOP */ if(to > from) { /* growing */ lower = from; upper = to; } else { /* shrinking */ lower = to; upper = from; } diff = (size_t)(upper - lower); extent = diff + nbytes; status = ncio_spx_get(nciop, 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) ncio_spx_rel(nciop, lower, RGN_MODIFIED); return status;}/*ARGSUSED*//* Flush any buffers to disk. May be a no-op on if I/O is unbuffered.*/static intncio_spx_sync(ncio *const nciop){ /* NOOP */ return ENOERR;}static voidncio_spx_free(void *const pvt){ ncio_spx *const pxp = (ncio_spx *)pvt; if(pxp == NULL) return; if(pxp->bf_base != NULL) { free(pxp->bf_base); pxp->bf_base = NULL; pxp->bf_offset = OFF_NONE; pxp->bf_extent = 0; pxp->bf_cnt = 0; }}/* This does the second half of the ncio_spx struct initialization for POSIX systems, with NC_SHARE on. nciop - pointer to ncio struct for this file. File has been opened. sizehintp - pointer to a size which will be rounded up to the nearest 8-byt boundary and then used as the max size "chunk" (or page) to read from the file. */static intncio_spx_init2(ncio *const nciop, const size_t *const sizehintp){ ncio_spx *const pxp = (ncio_spx *)nciop->pvt; assert(nciop->fd >= 0); pxp->bf_extent = *sizehintp; assert(pxp->bf_base == NULL); /* this is separate allocation because it may grow */ pxp->bf_base = malloc(pxp->bf_extent); if(pxp->bf_base == NULL) { pxp->bf_extent = 0; return ENOMEM; } /* else */ return ENOERR;}/* First half of init for ncio_spx struct, setting the rel, get, move, snyc, and free function pointers to the NC_SHARE versions of these functions (i.e. the ncio_spx_* functions).*/static voidncio_spx_init(ncio *const nciop){ ncio_spx *const pxp = (ncio_spx *)nciop->pvt; *((ncio_relfunc **)&nciop->rel) = ncio_spx_rel; /* cast away const */ *((ncio_getfunc **)&nciop->get) = ncio_spx_get; /* cast away const */ *((ncio_movefunc **)&nciop->move) = ncio_spx_move; /* cast away const */ *((ncio_syncfunc **)&nciop->sync) = ncio_spx_sync; /* cast away const */ *((ncio_freefunc **)&nciop->free) = ncio_spx_free; /* cast away const */ pxp->pos = -1; pxp->bf_offset = OFF_NONE; pxp->bf_extent = 0; pxp->bf_cnt = 0; pxp->bf_base = NULL;}/* *//* This will call whatever free function is attached to the free function pointer in ncio. It's called from ncio_close, and from ncio_open and ncio_create when an error occurs that the file metadata must be freed.*/static voidncio_free(ncio *nciop){ if(nciop == NULL) return; if(nciop->free != NULL) nciop->free(nciop->pvt); free(nciop);}/* Create a new ncio struct to hold info about the file. This will create and init the ncio_px or ncio_spx struct (the latter if NC_SHARE is used.)*/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)) sz_ncio_pvt = sizeof(ncio_spx); else sz_ncio_pvt = sizeof(ncio_px); 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); if(fIsSet(ioflags, NC_SHARE)) ncio_spx_init(nciop); else ncio_px_init(nciop); return nciop;}/* Public below this point */#define NCIO_MINBLOCKSIZE 256#define NCIO_MAXBLOCKSIZE 268435456 /* sanity check, about X_SIZE_T_MAX/8 */#ifdef S_IRUSR#define NC_DEFAULT_CREAT_MODE \ (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH) /* 0666 */#else#define NC_DEFAULT_CREAT_MODE 0666#endif/* Create a file, and the ncio struct to go with it. This funtion 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 - this eventually goes into pxp->blksz and is 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. igetvpp - pointer to pointer which will get the location of ?*/intncio_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; int oflags = (O_RDWR|O_CREAT); int fd; int status; 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)) fSet(oflags, O_EXCL); else fSet(oflags, O_TRUNC);#ifdef O_BINARY fSet(oflags, O_BINARY);#endif#ifdef vms fd = open(path, oflags, NC_DEFAULT_CREAT_MODE, "ctx=stm");#else /* Should we mess with the mode based on NC_SHARE ?? */ fd = open(path, oflags, NC_DEFAULT_CREAT_MODE);#endif#if 0 (void) fprintf(stderr, "ncio_create(): path=\"%s\"\n", path); (void) fprintf(stderr, "ncio_create(): oflags=0x%x\n", oflags);#endif if(fd < 0) { status = errno; goto unwind_new; } *((int *)&nciop->fd) = fd; /* cast away const */ if(*sizehintp < NCIO_MINBLOCKSIZE || *sizehintp > NCIO_MAXBLOCKSIZE) { /* Use default */ *sizehintp = blksize(fd); } else { *sizehintp = M_RNDUP(*sizehintp); } if(fIsSet(nciop->ioflags, NC_SHARE)) status = ncio_spx_init2(nciop, sizehintp); else status = ncio_px_init2(nciop, sizehintp, 1); if(status != ENOERR) goto unwind_open; if(initialsz != 0) { status = fgrow(fd, (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) close(fd); /* ?? unlink */ /*FALLTHRU*/unwind_new: ncio_free(nciop); return status;}/* 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.*/intncio_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; int status; if(path == NULL || *path == 0) return EINVAL; nciop = ncio_new(path, ioflags); if(nciop == NULL) return ENOMEM;#ifdef O_BINARY 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 || *sizehintp > NCIO_MAXBLOCKSIZE) { /* Use default */ *sizehintp = blksize(fd); } 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); /*FALLTHRU*/unwind_new: ncio_free(nciop); return status;}/* * Get file size in bytes. */intncio_filesize(ncio *nciop, off_t *filesizep){ struct stat sb; assert(nciop != NULL); if (fstat(nciop->fd, &sb) < 0) return errno; *filesizep = sb.st_size; return ENOERR;}/* * 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. */intncio_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;}/* Write out any dirty buffers to disk and ensure that next read will get data from disk. Sync any changes, then close the open file associated with the ncio struct, and free its memory. nciop - pointer to ncio to close. doUnlink - if true, unlink file*/int ncio_close(ncio *nciop, int doUnlink){ int status = ENOERR; if(nciop == NULL) return EINVAL; status = nciop->sync(nciop); (void) close(nciop->fd); if(doUnlink) (void) unlink(nciop->path); ncio_free(nciop); return status;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -