/* ARGSUSED */ static int px_double_buffer(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; void *src; void *dest; (void)rflags; #if INSTRUMENT fprintf(stderr, "\tdouble_buffr %ld %ld %ld\n", (long)to, (long)from, (long)nbytes); #endif status = px_get(nciop, pxp, to, nbytes, RGN_WRITE, &dest); if(status != ENOERR) return status; if(pxp->slave == NULL) { pxp->slave = (ncio_px *) malloc(sizeof(ncio_px)); if(pxp->slave == NULL) return ENOMEM; pxp->slave->blksz = pxp->blksz; /* pos done below */ pxp->slave->bf_offset = pxp->bf_offset; pxp->slave->bf_extent = pxp->bf_extent; pxp->slave->bf_cnt = pxp->bf_cnt; pxp->slave->bf_base = malloc(2 * pxp->blksz); if(pxp->slave->bf_base == NULL) return ENOMEM; (void) memcpy(pxp->slave->bf_base, pxp->bf_base, pxp->bf_extent); pxp->slave->bf_rflags = 0; pxp->slave->bf_refcount = 0; pxp->slave->slave = NULL; } pxp->slave->pos = pxp->pos; status = px_get(nciop, pxp->slave, from, nbytes, 0, &src); if(status != ENOERR) return status; if(pxp->pos != pxp->slave->pos) { /* position changed, sync */ pxp->pos = pxp->slave->pos; } (void) memcpy(dest, src, nbytes); (void)px_rel(pxp->slave, from, 0); (void)px_rel(pxp, to, RGN_MODIFIED); return status; }
/* 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); }
/* 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; }