00001
00002
00003
00004
00005
00006 #include "ncconfig.h"
00007 #include <assert.h>
00008 #include <stdlib.h>
00009 #include <errno.h>
00010 #ifndef ENOERR
00011 #define ENOERR 0
00012 #endif
00013 #include <sys/types.h>
00014 #include <sys/stat.h>
00015 #include <fcntl.h>
00016 #include <string.h>
00017 #ifdef _MSC_VER
00018 #include <io.h>
00019 #else
00020 #include <unistd.h>
00021 #endif
00022
00023 #ifndef SEEK_SET
00024 #define SEEK_SET 0
00025 #define SEEK_CUR 1
00026 #define SEEK_END 2
00027 #endif
00028
00029 #include "ncio.h"
00030 #include "fbits.h"
00031 #include "rnd.h"
00032
00033
00034 #if INSTRUMENT
00035 #undef NDEBUG
00036 #include <stdio.h>
00037 #include "instr.h"
00038 #endif
00039
00040 #undef MIN
00041 #define MIN(mm,nn) (((mm) < (nn)) ? (mm) : (nn))
00042
00043 #if !defined(NDEBUG) && !defined(X_INT_MAX)
00044 #define X_INT_MAX 2147483647
00045 #endif
00046
00047 #if 0
00048 #define X_ALIGN 4
00049 #else
00050 #undef X_ALIGN
00051 #endif
00052
00053
00054
00055
00056
00057
00058
00059
00060 static int ncio_px_sync(ncio *const nciop);
00061
00062 #ifndef POSIXIO_DEFAULT_PAGESIZE
00063 #define POSIXIO_DEFAULT_PAGESIZE 4096
00064 #endif
00065
00066
00067
00068 static size_t
00069 pagesize(void)
00070 {
00071
00072 #if defined(_SC_PAGE_SIZE) && !defined(_SC_PAGESIZE)
00073 #define _SC_PAGESIZE _SC_PAGE_SIZE
00074 #endif
00075
00076 #ifdef _SC_PAGESIZE
00077 {
00078 const long pgsz = sysconf(_SC_PAGESIZE);
00079 if(pgsz > 0)
00080 return (size_t) pgsz;
00081
00082 }
00083 #elif defined(HAVE_GETPAGESIZE)
00084 return (size_t) getpagesize();
00085 #endif
00086 return (size_t) POSIXIO_DEFAULT_PAGESIZE;
00087 }
00088
00089
00090
00091
00092 static size_t
00093 blksize(int fd)
00094 {
00095 #if defined(HAVE_ST_BLKSIZE)
00096 struct stat sb;
00097 if (fstat(fd, &sb) > -1)
00098 {
00099 if(sb.st_blksize >= 8192)
00100 return (size_t) sb.st_blksize;
00101 return 8192;
00102 }
00103
00104 #endif
00105 return (size_t) 2 * pagesize();
00106 }
00107
00108
00109
00110
00111
00112
00113 static int
00114 fgrow(const int fd, const off_t len)
00115 {
00116 struct stat sb;
00117 if (fstat(fd, &sb) < 0)
00118 return errno;
00119 if (len < sb.st_size)
00120 return ENOERR;
00121 #if defined(HAVE_FTRUNCATE)
00122 if (ftruncate(fd, len) < 0)
00123 return errno;
00124 #else
00125 {
00126 const long dumb = 0;
00127
00128 const off_t pos = lseek(fd, 0, SEEK_CUR);
00129 if(pos < 0)
00130 return errno;
00131 if (lseek(fd, len-sizeof(dumb), SEEK_SET) < 0)
00132 return errno;
00133 if(write(fd, &dumb, sizeof(dumb)) < 0)
00134 return errno;
00135 if (lseek(fd, pos, SEEK_SET) < 0)
00136 return errno;
00137 }
00138 #endif
00139
00140 return ENOERR;
00141 }
00142
00143
00144
00145
00146 static int
00147 px_pgout(ncio *const nciop,
00148 off_t const offset, const size_t extent,
00149 void *const vp, off_t *posp)
00150 {
00151 #ifdef X_ALIGN
00152 assert(offset % X_ALIGN == 0);
00153 #endif
00154
00155 assert(*posp == OFF_NONE || *posp == lseek(nciop->fd, 0, SEEK_CUR));
00156
00157 if(*posp != offset)
00158 {
00159 if(lseek(nciop->fd, offset, SEEK_SET) != offset)
00160 {
00161 return errno;
00162 }
00163 *posp = offset;
00164 }
00165 if(write(nciop->fd, vp, extent) != (ssize_t) extent)
00166 {
00167 return errno;
00168 }
00169 *posp += extent;
00170
00171 return ENOERR;
00172 }
00173
00174
00175 static int
00176 px_pgin(ncio *const nciop,
00177 off_t const offset, const size_t extent,
00178 void *const vp, size_t *nreadp, off_t *posp)
00179 {
00180 int status;
00181 ssize_t nread;
00182
00183 #ifdef X_ALIGN
00184 assert(offset % X_ALIGN == 0);
00185 assert(extent % X_ALIGN == 0);
00186 #endif
00187
00188 assert(*posp == OFF_NONE || *posp == lseek(nciop->fd, 0, SEEK_CUR));
00189
00190 if(*posp != offset)
00191 {
00192 if(lseek(nciop->fd, offset, SEEK_SET) != offset)
00193 {
00194 status = errno;
00195 return status;
00196 }
00197 *posp = offset;
00198 }
00199
00200 errno = 0;
00201 nread = read(nciop->fd, vp, extent);
00202 if(nread != (ssize_t) extent)
00203 {
00204 status = errno;
00205 if(nread == -1 || status != ENOERR)
00206 return status;
00207
00208 (void) memset((char *)vp + nread, 0, (ssize_t)extent - nread);
00209 }
00210 *nreadp = nread;
00211 *posp += nread;
00212
00213 return ENOERR;
00214 }
00215
00216
00217 typedef struct ncio_px {
00218 size_t blksz;
00219 off_t pos;
00220
00221 off_t bf_offset;
00222 size_t bf_extent;
00223 size_t bf_cnt;
00224 void *bf_base;
00225 int bf_rflags;
00226 int bf_refcount;
00227
00228 struct ncio_px *slave;
00229 } ncio_px;
00230
00231
00232
00233 static int
00234 px_rel(ncio_px *const pxp, off_t offset, int rflags)
00235 {
00236 assert(pxp->bf_offset <= offset
00237 && offset < pxp->bf_offset + (off_t) pxp->bf_extent);
00238 assert(pIf(fIsSet(rflags, RGN_MODIFIED),
00239 fIsSet(pxp->bf_rflags, RGN_WRITE)));
00240
00241 if(fIsSet(rflags, RGN_MODIFIED))
00242 {
00243 fSet(pxp->bf_rflags, RGN_MODIFIED);
00244 }
00245 pxp->bf_refcount--;
00246
00247 return ENOERR;
00248 }
00249
00250 static int
00251 ncio_px_rel(ncio *const nciop, off_t offset, int rflags)
00252 {
00253 ncio_px *const pxp = (ncio_px *)nciop->pvt;
00254
00255 if(fIsSet(rflags, RGN_MODIFIED) && !fIsSet(nciop->ioflags, NC_WRITE))
00256 return EPERM;
00257
00258 return px_rel(pxp, offset, rflags);
00259 }
00260
00261 static int
00262 px_get(ncio *const nciop, ncio_px *const pxp,
00263 off_t offset, size_t extent,
00264 int rflags,
00265 void **const vpp)
00266 {
00267 int status = ENOERR;
00268
00269 const off_t blkoffset = _RNDDOWN(offset, (off_t)pxp->blksz);
00270 size_t diff = (size_t)(offset - blkoffset);
00271 size_t blkextent = _RNDUP(diff + extent, pxp->blksz);
00272
00273 assert(extent != 0);
00274 assert(extent < X_INT_MAX);
00275 assert(offset >= 0);
00276 assert(offset < X_INT_MAX);
00277
00278 if(2 * pxp->blksz < blkextent)
00279 return E2BIG;
00280 if(pxp->bf_offset == OFF_NONE)
00281 {
00282
00283 if(pxp->bf_base == NULL)
00284 {
00285 assert(pxp->bf_extent == 0);
00286 assert(blkextent <= 2 * pxp->blksz);
00287 pxp->bf_base = malloc(2 * pxp->blksz);
00288 if(pxp->bf_base == NULL)
00289 return ENOMEM;
00290 }
00291 goto pgin;
00292 }
00293
00294 assert(blkextent <= 2 * pxp->blksz);
00295
00296 if(blkoffset == pxp->bf_offset)
00297 {
00298
00299 if(blkextent > pxp->bf_extent)
00300 {
00301
00302 void *const middle =
00303 (void *)((char *)pxp->bf_base + pxp->blksz);
00304 assert(pxp->bf_extent == pxp->blksz);
00305 status = px_pgin(nciop,
00306 pxp->bf_offset + (off_t)pxp->blksz,
00307 pxp->blksz,
00308 middle,
00309 &pxp->bf_cnt,
00310 &pxp->pos);
00311 if(status != ENOERR)
00312 return status;
00313 pxp->bf_extent = 2 * pxp->blksz;
00314 pxp->bf_cnt += pxp->blksz;
00315 }
00316 goto done;
00317 }
00318
00319
00320 if(pxp->bf_extent > pxp->blksz
00321 && blkoffset == pxp->bf_offset + pxp->blksz)
00322 {
00323
00324 if(blkextent == pxp->blksz)
00325 {
00326
00327 diff += pxp->blksz;
00328 goto done;
00329 }
00330
00331 if(pxp->bf_cnt > pxp->blksz)
00332 {
00333
00334 void *const middle =
00335 (void *)((char *)pxp->bf_base + pxp->blksz);
00336 assert(pxp->bf_extent == 2 * pxp->blksz);
00337 if(fIsSet(pxp->bf_rflags, RGN_MODIFIED))
00338 {
00339
00340 assert(pxp->bf_refcount <= 0);
00341 status = px_pgout(nciop,
00342 pxp->bf_offset,
00343 pxp->blksz,
00344 pxp->bf_base,
00345 &pxp->pos);
00346 if(status != ENOERR)
00347 return status;
00348 }
00349 pxp->bf_cnt -= pxp->blksz;
00350
00351 (void) memcpy(pxp->bf_base, middle, pxp->bf_cnt);
00352 }
00353 pxp->bf_offset = blkoffset;
00354
00355
00356 assert(blkextent == 2 * pxp->blksz);
00357 {
00358
00359 void *const middle =
00360 (void *)((char *)pxp->bf_base + pxp->blksz);
00361 status = px_pgin(nciop,
00362 pxp->bf_offset + (off_t)pxp->blksz,
00363 pxp->blksz,
00364 middle,
00365 &pxp->bf_cnt,
00366 &pxp->pos);
00367 if(status != ENOERR)
00368 return status;
00369 pxp->bf_extent = 2 * pxp->blksz;
00370 pxp->bf_cnt += pxp->blksz;
00371 }
00372 goto done;
00373 }
00374
00375
00376 if(blkoffset == pxp->bf_offset - pxp->blksz)
00377 {
00378
00379 void *const middle =
00380 (void *)((char *)pxp->bf_base + pxp->blksz);
00381 size_t upper_cnt = 0;
00382 if(pxp->bf_cnt > pxp->blksz)
00383 {
00384
00385 assert(pxp->bf_extent == 2 * pxp->blksz);
00386 if(fIsSet(pxp->bf_rflags, RGN_MODIFIED))
00387 {
00388
00389 assert(pxp->bf_refcount <= 0);
00390 status = px_pgout(nciop,
00391 pxp->bf_offset + (off_t)pxp->blksz,
00392 pxp->bf_cnt - pxp->blksz,
00393 middle,
00394 &pxp->pos);
00395 if(status != ENOERR)
00396 return status;
00397 }
00398 pxp->bf_cnt = pxp->blksz;
00399 pxp->bf_extent = pxp->blksz;
00400 }
00401 if(pxp->bf_cnt > 0)
00402 {
00403
00404 (void) memcpy(middle, pxp->bf_base, pxp->blksz);
00405 upper_cnt = pxp->bf_cnt;
00406 }
00407
00408 status = px_pgin(nciop,
00409 blkoffset,
00410 pxp->blksz,
00411 pxp->bf_base,
00412 &pxp->bf_cnt,
00413 &pxp->pos);
00414 if(status != ENOERR)
00415 return status;
00416 pxp->bf_offset = blkoffset;
00417 if(upper_cnt != 0)
00418 {
00419 pxp->bf_extent = 2 * pxp->blksz;
00420 pxp->bf_cnt = pxp->blksz + upper_cnt;
00421 }
00422 else
00423 {
00424 pxp->bf_extent = pxp->blksz;
00425 }
00426 goto done;
00427 }
00428
00429
00430
00431 if(fIsSet(pxp->bf_rflags, RGN_MODIFIED))
00432 {
00433 assert(pxp->bf_refcount <= 0);
00434 status = px_pgout(nciop,
00435 pxp->bf_offset,
00436 pxp->bf_cnt,
00437 pxp->bf_base,
00438 &pxp->pos);
00439 if(status != ENOERR)
00440 return status;
00441 pxp->bf_rflags = 0;
00442 }
00443
00444 pgin:
00445 status = px_pgin(nciop,
00446 blkoffset,
00447 blkextent,
00448 pxp->bf_base,
00449 &pxp->bf_cnt,
00450 &pxp->pos);
00451 if(status != ENOERR)
00452 return status;
00453 pxp->bf_offset = blkoffset;
00454 pxp->bf_extent = blkextent;
00455
00456 done:
00457 extent += diff;
00458 if(pxp->bf_cnt < extent)
00459 pxp->bf_cnt = extent;
00460 assert(pxp->bf_cnt <= pxp->bf_extent);
00461
00462 pxp->bf_rflags |= rflags;
00463 pxp->bf_refcount++;
00464
00465 *vpp = (char *)pxp->bf_base + diff;
00466 return ENOERR;
00467 }
00468
00469 static int
00470 ncio_px_get(ncio *const nciop,
00471 off_t offset, size_t extent,
00472 int rflags,
00473 void **const vpp)
00474 {
00475 ncio_px *const pxp = (ncio_px *)nciop->pvt;
00476
00477 if(fIsSet(rflags, RGN_WRITE) && !fIsSet(nciop->ioflags, NC_WRITE))
00478 return EPERM;
00479
00480
00481
00482
00483
00484
00485 if (*vpp == NULL)
00486 {
00487 ncio_px_sync(nciop);
00488 pxp->bf_offset = OFF_NONE;
00489 pxp->bf_cnt = 0;
00490 }
00491
00492
00493 if(pxp->slave != NULL)
00494 {
00495 if(pxp->slave->bf_base != NULL)
00496 {
00497 free(pxp->slave->bf_base);
00498 pxp->slave->bf_base = NULL;
00499 pxp->slave->bf_extent = 0;
00500 pxp->slave->bf_offset = OFF_NONE;
00501 }
00502 free(pxp->slave);
00503 pxp->slave = NULL;
00504 }
00505 return px_get(nciop, pxp, offset, extent, rflags, vpp);
00506 }
00507
00508
00509
00510 static int
00511 px_double_buffer(ncio *const nciop, off_t to, off_t from,
00512 size_t nbytes, int rflags)
00513 {
00514 ncio_px *const pxp = (ncio_px *)nciop->pvt;
00515 int status = ENOERR;
00516 void *src;
00517 void *dest;
00518
00519 #if INSTRUMENT
00520 fprintf(stderr, "\tdouble_buffr %ld %ld %ld\n",
00521 (long)to, (long)from, (long)nbytes);
00522 #endif
00523 status = px_get(nciop, pxp, to, nbytes, RGN_WRITE,
00524 &dest);
00525 if(status != ENOERR)
00526 return status;
00527
00528 if(pxp->slave == NULL)
00529 {
00530 pxp->slave = (ncio_px *) malloc(sizeof(ncio_px));
00531 if(pxp->slave == NULL)
00532 return ENOMEM;
00533
00534 pxp->slave->blksz = pxp->blksz;
00535
00536 pxp->slave->bf_offset = pxp->bf_offset;
00537 pxp->slave->bf_extent = pxp->bf_extent;
00538 pxp->slave->bf_cnt = pxp->bf_cnt;
00539 pxp->slave->bf_base = malloc(2 * pxp->blksz);
00540 if(pxp->slave->bf_base == NULL)
00541 return ENOMEM;
00542 (void) memcpy(pxp->slave->bf_base, pxp->bf_base,
00543 pxp->bf_extent);
00544 pxp->slave->bf_rflags = 0;
00545 pxp->slave->bf_refcount = 0;
00546 pxp->slave->slave = NULL;
00547 }
00548
00549 pxp->slave->pos = pxp->pos;
00550 status = px_get(nciop, pxp->slave, from, nbytes, 0,
00551 &src);
00552 if(status != ENOERR)
00553 return status;
00554 if(pxp->pos != pxp->slave->pos)
00555 {
00556
00557 pxp->pos = pxp->slave->pos;
00558 }
00559
00560 (void) memcpy(dest, src, nbytes);
00561
00562 (void)px_rel(pxp->slave, from, 0);
00563 (void)px_rel(pxp, to, RGN_MODIFIED);
00564
00565 return status;
00566 }
00567
00568 static int
00569 ncio_px_move(ncio *const nciop, off_t to, off_t from,
00570 size_t nbytes, int rflags)
00571 {
00572 ncio_px *const pxp = (ncio_px *)nciop->pvt;
00573 int status = ENOERR;
00574 off_t lower;
00575 off_t upper;
00576 char *base;
00577 size_t diff;
00578 size_t extent;
00579
00580 if(to == from)
00581 return ENOERR;
00582
00583 if(fIsSet(rflags, RGN_WRITE) && !fIsSet(nciop->ioflags, NC_WRITE))
00584 return EPERM;
00585
00586 rflags &= RGN_NOLOCK;
00587
00588 if(to > from)
00589 {
00590
00591 lower = from;
00592 upper = to;
00593 }
00594 else
00595 {
00596
00597 lower = to;
00598 upper = from;
00599 }
00600 diff = (size_t)(upper - lower);
00601 extent = diff + nbytes;
00602
00603 #if INSTRUMENT
00604 fprintf(stderr, "ncio_px_move %ld %ld %ld %ld %ld\n",
00605 (long)to, (long)from, (long)nbytes, (long)lower, (long)extent);
00606 #endif
00607 if(extent > pxp->blksz)
00608 {
00609 size_t remaining = nbytes;
00610
00611 if(to > from)
00612 {
00613 off_t frm = from + nbytes;
00614 off_t toh = to + nbytes;
00615 for(;;)
00616 {
00617 size_t loopextent = MIN(remaining, pxp->blksz);
00618 frm -= loopextent;
00619 toh -= loopextent;
00620
00621 status = px_double_buffer(nciop, toh, frm,
00622 loopextent, rflags) ;
00623 if(status != ENOERR)
00624 return status;
00625 remaining -= loopextent;
00626
00627 if(remaining == 0)
00628 break;
00629 }
00630 }
00631 else
00632 {
00633 for(;;)
00634 {
00635 size_t loopextent = MIN(remaining, pxp->blksz);
00636
00637 status = px_double_buffer(nciop, to, from,
00638 loopextent, rflags) ;
00639 if(status != ENOERR)
00640 return status;
00641 remaining -= loopextent;
00642
00643 if(remaining == 0)
00644 break;
00645 to += loopextent;
00646 from += loopextent;
00647 }
00648 }
00649 return ENOERR;
00650 }
00651
00652 #if INSTRUMENT
00653 fprintf(stderr, "\tncio_px_move small\n");
00654 #endif
00655 status = px_get(nciop, pxp, lower, extent, RGN_WRITE|rflags,
00656 (void **)&base);
00657
00658 if(status != ENOERR)
00659 return status;
00660
00661 if(to > from)
00662 (void) memmove(base + diff, base, nbytes);
00663 else
00664 (void) memmove(base, base + diff, nbytes);
00665
00666 (void) px_rel(pxp, lower, RGN_MODIFIED);
00667
00668 return status;
00669 }
00670
00671
00672 static int
00673 ncio_px_sync(ncio *const nciop)
00674 {
00675 ncio_px *const pxp = (ncio_px *)nciop->pvt;
00676 int status = ENOERR;
00677 if(fIsSet(pxp->bf_rflags, RGN_MODIFIED))
00678 {
00679 assert(pxp->bf_refcount <= 0);
00680 status = px_pgout(nciop, pxp->bf_offset,
00681 pxp->bf_cnt,
00682 pxp->bf_base, &pxp->pos);
00683 if(status != ENOERR)
00684 return status;
00685 pxp->bf_rflags = 0;
00686 }
00687 return status;
00688 }
00689
00690 static void
00691 ncio_px_free(void *const pvt)
00692 {
00693 ncio_px *const pxp = (ncio_px *)pvt;
00694 if(pxp == NULL)
00695 return;
00696
00697 if(pxp->slave != NULL)
00698 {
00699 if(pxp->slave->bf_base != NULL)
00700 {
00701 free(pxp->slave->bf_base);
00702 pxp->slave->bf_base = NULL;
00703 pxp->slave->bf_extent = 0;
00704 pxp->slave->bf_offset = OFF_NONE;
00705 }
00706 free(pxp->slave);
00707 pxp->slave = NULL;
00708 }
00709
00710 if(pxp->bf_base != NULL)
00711 {
00712 free(pxp->bf_base);
00713 pxp->bf_base = NULL;
00714 pxp->bf_extent = 0;
00715 pxp->bf_offset = OFF_NONE;
00716 }
00717 }
00718
00719
00720 static int
00721 ncio_px_init2(ncio *const nciop, size_t *sizehintp, int isNew)
00722 {
00723 ncio_px *const pxp = (ncio_px *)nciop->pvt;
00724 const size_t bufsz = 2 * *sizehintp;
00725
00726 assert(nciop->fd >= 0);
00727
00728 pxp->blksz = *sizehintp;
00729
00730 assert(pxp->bf_base == NULL);
00731
00732
00733 pxp->bf_base = malloc(bufsz);
00734 if(pxp->bf_base == NULL)
00735 return ENOMEM;
00736
00737 pxp->bf_cnt = 0;
00738 if(isNew)
00739 {
00740
00741 pxp->pos = 0;
00742 pxp->bf_offset = 0;
00743 pxp->bf_extent = bufsz;
00744 (void) memset(pxp->bf_base, 0, pxp->bf_extent);
00745 }
00746 return ENOERR;
00747 }
00748
00749
00750 static void
00751 ncio_px_init(ncio *const nciop)
00752 {
00753 ncio_px *const pxp = (ncio_px *)nciop->pvt;
00754
00755 *((ncio_relfunc **)&nciop->rel) = ncio_px_rel;
00756 *((ncio_getfunc **)&nciop->get) = ncio_px_get;
00757 *((ncio_movefunc **)&nciop->move) = ncio_px_move;
00758 *((ncio_syncfunc **)&nciop->sync) = ncio_px_sync;
00759 *((ncio_freefunc **)&nciop->free) = ncio_px_free;
00760
00761 pxp->blksz = 0;
00762 pxp->pos = -1;
00763 pxp->bf_offset = OFF_NONE;
00764 pxp->bf_extent = 0;
00765 pxp->bf_rflags = 0;
00766 pxp->bf_refcount = 0;
00767 pxp->bf_base = NULL;
00768 pxp->slave = NULL;
00769
00770 }
00771
00772
00773
00774 typedef struct ncio_spx {
00775 off_t pos;
00776
00777 off_t bf_offset;
00778 size_t bf_extent;
00779 size_t bf_cnt;
00780 void *bf_base;
00781 } ncio_spx;
00782
00783
00784
00785 static int
00786 ncio_spx_rel(ncio *const nciop, off_t offset, int rflags)
00787 {
00788 ncio_spx *const pxp = (ncio_spx *)nciop->pvt;
00789 int status = ENOERR;
00790
00791 assert(pxp->bf_offset <= offset);
00792 assert(pxp->bf_cnt != 0);
00793 assert(pxp->bf_cnt <= pxp->bf_extent);
00794 #ifdef X_ALIGN
00795 assert(offset < pxp->bf_offset + X_ALIGN);
00796 assert(pxp->bf_cnt % X_ALIGN == 0 );
00797 #endif
00798
00799 if(fIsSet(rflags, RGN_MODIFIED))
00800 {
00801 if(!fIsSet(nciop->ioflags, NC_WRITE))
00802 return EPERM;
00803
00804 status = px_pgout(nciop, pxp->bf_offset,
00805 pxp->bf_cnt,
00806 pxp->bf_base, &pxp->pos);
00807
00808 }
00809 pxp->bf_offset = OFF_NONE;
00810 pxp->bf_cnt = 0;
00811 return status;
00812 }
00813
00814
00815 static int
00816 ncio_spx_get(ncio *const nciop,
00817 off_t offset, size_t extent,
00818 int rflags,
00819 void **const vpp)
00820 {
00821 ncio_spx *const pxp = (ncio_spx *)nciop->pvt;
00822 int status = ENOERR;
00823 #ifdef X_ALIGN
00824 size_t rem;
00825 #endif
00826
00827 if(fIsSet(rflags, RGN_WRITE) && !fIsSet(nciop->ioflags, NC_WRITE))
00828 return EPERM;
00829
00830 assert(extent != 0);
00831 assert(extent < X_INT_MAX);
00832 assert(offset < X_INT_MAX);
00833
00834 assert(pxp->bf_cnt == 0);
00835
00836 #ifdef X_ALIGN
00837 rem = (size_t)(offset % X_ALIGN);
00838 if(rem != 0)
00839 {
00840 offset -= rem;
00841 extent += rem;
00842 }
00843
00844 {
00845 const size_t rndup = extent % X_ALIGN;
00846 if(rndup != 0)
00847 extent += X_ALIGN - rndup;
00848 }
00849
00850 assert(offset % X_ALIGN == 0);
00851 assert(extent % X_ALIGN == 0);
00852 #endif
00853
00854 if(pxp->bf_extent < extent)
00855 {
00856 if(pxp->bf_base != NULL)
00857 {
00858 free(pxp->bf_base);
00859 pxp->bf_base = NULL;
00860 pxp->bf_extent = 0;
00861 }
00862 assert(pxp->bf_extent == 0);
00863 pxp->bf_base = malloc(extent);
00864 if(pxp->bf_base == NULL)
00865 return ENOMEM;
00866 pxp->bf_extent = extent;
00867 }
00868
00869 status = px_pgin(nciop, offset,
00870 extent,
00871 pxp->bf_base,
00872 &pxp->bf_cnt, &pxp->pos);
00873 if(status != ENOERR)
00874 return status;
00875
00876 pxp->bf_offset = offset;
00877
00878 if(pxp->bf_cnt < extent)
00879 pxp->bf_cnt = extent;
00880
00881 #ifdef X_ALIGN
00882 *vpp = (char *)pxp->bf_base + rem;
00883 #else
00884 *vpp = pxp->bf_base;
00885 #endif
00886 return ENOERR;
00887 }
00888
00889
00890 #if 0
00891
00892 static int
00893 strategy(ncio *const nciop, off_t to, off_t offset,
00894 size_t extent, int rflags)
00895 {
00896 static ncio_spx pxp[1];
00897 int status = ENOERR;
00898 #ifdef X_ALIGN
00899 size_t rem;
00900 #endif
00901
00902 assert(extent != 0);
00903 assert(extent < X_INT_MAX);
00904 assert(offset < X_INT_MAX);
00905 #if INSTRUMENT
00906 fprintf(stderr, "strategy %ld at %ld to %ld\n",
00907 (long)extent, (long)offset, (long)to);
00908 #endif
00909
00910
00911 #ifdef X_ALIGN
00912 rem = (size_t)(offset % X_ALIGN);
00913 if(rem != 0)
00914 {
00915 offset -= rem;
00916 extent += rem;
00917 }
00918
00919 {
00920 const size_t rndup = extent % X_ALIGN;
00921 if(rndup != 0)
00922 extent += X_ALIGN - rndup;
00923 }
00924
00925 assert(offset % X_ALIGN == 0);
00926 assert(extent % X_ALIGN == 0);
00927 #endif
00928
00929 if(pxp->bf_extent < extent)
00930 {
00931 if(pxp->bf_base != NULL)
00932 {
00933 free(pxp->bf_base);
00934 pxp->bf_base = NULL;
00935 pxp->bf_extent = 0;
00936 }
00937 assert(pxp->bf_extent == 0);
00938 pxp->bf_base = malloc(extent);
00939 if(pxp->bf_base == NULL)
00940 return ENOMEM;
00941 pxp->bf_extent = extent;
00942 }
00943
00944 status = px_pgin(nciop, offset,
00945 extent,
00946 pxp->bf_base,
00947 &pxp->bf_cnt, &pxp->pos);
00948 if(status != ENOERR)
00949 return status;
00950
00951 pxp->bf_offset = to;
00952
00953 if(pxp->bf_cnt < extent)
00954 pxp->bf_cnt = extent;
00955
00956 status = px_pgout(nciop, pxp->bf_offset,
00957 pxp->bf_cnt,
00958 pxp->bf_base, &pxp->pos);
00959
00960 pxp->bf_offset = OFF_NONE;
00961 pxp->bf_cnt = 0;
00962 return status;
00963 }
00964 #endif
00965
00966 static int
00967 ncio_spx_move(ncio *const nciop, off_t to, off_t from,
00968 size_t nbytes, int rflags)
00969 {
00970 int status = ENOERR;
00971 off_t lower = from;
00972 off_t upper = to;
00973 char *base;
00974 size_t diff = (size_t)(upper - lower);
00975 size_t extent = diff + nbytes;
00976
00977 rflags &= RGN_NOLOCK;
00978
00979 if(to == from)
00980 return ENOERR;
00981
00982 if(to > from)
00983 {
00984
00985 lower = from;
00986 upper = to;
00987 }
00988 else
00989 {
00990
00991 lower = to;
00992 upper = from;
00993 }
00994
00995 diff = (size_t)(upper - lower);
00996 extent = diff + nbytes;
00997
00998 status = ncio_spx_get(nciop, lower, extent, RGN_WRITE|rflags,
00999 (void **)&base);
01000
01001 if(status != ENOERR)
01002 return status;
01003
01004 if(to > from)
01005 (void) memmove(base + diff, base, nbytes);
01006 else
01007 (void) memmove(base, base + diff, nbytes);
01008
01009 (void) ncio_spx_rel(nciop, lower, RGN_MODIFIED);
01010
01011 return status;
01012 }
01013
01014
01015
01016 static int
01017 ncio_spx_sync(ncio *const nciop)
01018 {
01019
01020 return ENOERR;
01021 }
01022
01023 static void
01024 ncio_spx_free(void *const pvt)
01025 {
01026 ncio_spx *const pxp = (ncio_spx *)pvt;
01027 if(pxp == NULL)
01028 return;
01029
01030 if(pxp->bf_base != NULL)
01031 {
01032 free(pxp->bf_base);
01033 pxp->bf_base = NULL;
01034 pxp->bf_offset = OFF_NONE;
01035 pxp->bf_extent = 0;
01036 pxp->bf_cnt = 0;
01037 }
01038 }
01039
01040
01041 static int
01042 ncio_spx_init2(ncio *const nciop, const size_t *const sizehintp)
01043 {
01044 ncio_spx *const pxp = (ncio_spx *)nciop->pvt;
01045
01046 assert(nciop->fd >= 0);
01047
01048 pxp->bf_extent = *sizehintp;
01049
01050 assert(pxp->bf_base == NULL);
01051
01052
01053 pxp->bf_base = malloc(pxp->bf_extent);
01054 if(pxp->bf_base == NULL)
01055 {
01056 pxp->bf_extent = 0;
01057 return ENOMEM;
01058 }
01059
01060 return ENOERR;
01061 }
01062
01063
01064 static void
01065 ncio_spx_init(ncio *const nciop)
01066 {
01067 ncio_spx *const pxp = (ncio_spx *)nciop->pvt;
01068
01069 *((ncio_relfunc **)&nciop->rel) = ncio_spx_rel;
01070 *((ncio_getfunc **)&nciop->get) = ncio_spx_get;
01071 *((ncio_movefunc **)&nciop->move) = ncio_spx_move;
01072 *((ncio_syncfunc **)&nciop->sync) = ncio_spx_sync;
01073 *((ncio_freefunc **)&nciop->free) = ncio_spx_free;
01074
01075 pxp->pos = -1;
01076 pxp->bf_offset = OFF_NONE;
01077 pxp->bf_extent = 0;
01078 pxp->bf_cnt = 0;
01079 pxp->bf_base = NULL;
01080 }
01081
01082
01083
01084
01085 static void
01086 ncio_free(ncio *nciop)
01087 {
01088 if(nciop == NULL)
01089 return;
01090
01091 if(nciop->free != NULL)
01092 nciop->free(nciop->pvt);
01093
01094 free(nciop);
01095 }
01096
01097
01098 static ncio *
01099 ncio_new(const char *path, int ioflags)
01100 {
01101 size_t sz_ncio = M_RNDUP(sizeof(ncio));
01102 size_t sz_path = M_RNDUP(strlen(path) +1);
01103 size_t sz_ncio_pvt;
01104 ncio *nciop;
01105
01106 #if ALWAYS_NC_SHARE
01107 fSet(ioflags, NC_SHARE);
01108 #endif
01109
01110 if(fIsSet(ioflags, NC_SHARE))
01111 sz_ncio_pvt = sizeof(ncio_spx);
01112 else
01113 sz_ncio_pvt = sizeof(ncio_px);
01114
01115 nciop = (ncio *) malloc(sz_ncio + sz_path + sz_ncio_pvt);
01116 if(nciop == NULL)
01117 return NULL;
01118
01119 nciop->ioflags = ioflags;
01120 *((int *)&nciop->fd) = -1;
01121
01122 nciop->path = (char *) ((char *)nciop + sz_ncio);
01123 (void) strcpy((char *)nciop->path, path);
01124
01125
01126 *((void **)&nciop->pvt) = (void *)(nciop->path + sz_path);
01127
01128 if(fIsSet(ioflags, NC_SHARE))
01129 ncio_spx_init(nciop);
01130 else
01131 ncio_px_init(nciop);
01132
01133 return nciop;
01134 }
01135
01136
01137
01138
01139 #define NCIO_MINBLOCKSIZE 256
01140 #define NCIO_MAXBLOCKSIZE 268435456
01141
01142 #ifdef S_IRUSR
01143 #define NC_DEFAULT_CREAT_MODE \
01144 (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)
01145
01146 #else
01147 #define NC_DEFAULT_CREAT_MODE 0666
01148 #endif
01149
01150 int
01151 ncio_create(const char *path, int ioflags,
01152 size_t initialsz,
01153 off_t igeto, size_t igetsz, size_t *sizehintp,
01154 ncio **nciopp, void **const igetvpp)
01155 {
01156 ncio *nciop;
01157 int oflags = (O_RDWR|O_CREAT);
01158 int fd;
01159 int status;
01160
01161 if(initialsz < (size_t)igeto + igetsz)
01162 initialsz = (size_t)igeto + igetsz;
01163
01164 fSet(ioflags, NC_WRITE);
01165
01166 if(path == NULL || *path == 0)
01167 return EINVAL;
01168
01169 nciop = ncio_new(path, ioflags);
01170 if(nciop == NULL)
01171 return ENOMEM;
01172
01173 if(fIsSet(ioflags, NC_NOCLOBBER))
01174 fSet(oflags, O_EXCL);
01175 else
01176 fSet(oflags, O_TRUNC);
01177 #ifdef O_BINARY
01178 fSet(oflags, O_BINARY);
01179 #endif
01180 #ifdef vms
01181 fd = open(path, oflags, NC_DEFAULT_CREAT_MODE, "ctx=stm");
01182 #else
01183
01184 fd = open(path, oflags, NC_DEFAULT_CREAT_MODE);
01185 #endif
01186 #if 0
01187 (void) fprintf(stderr, "ncio_create(): path=\"%s\"\n", path);
01188 (void) fprintf(stderr, "ncio_create(): oflags=0x%x\n", oflags);
01189 #endif
01190 if(fd < 0)
01191 {
01192 status = errno;
01193 goto unwind_new;
01194 }
01195 *((int *)&nciop->fd) = fd;
01196
01197 if(*sizehintp < NCIO_MINBLOCKSIZE || *sizehintp > NCIO_MAXBLOCKSIZE)
01198 {
01199
01200 *sizehintp = blksize(fd);
01201 }
01202 else
01203 {
01204 *sizehintp = M_RNDUP(*sizehintp);
01205 }
01206
01207 if(fIsSet(nciop->ioflags, NC_SHARE))
01208 status = ncio_spx_init2(nciop, sizehintp);
01209 else
01210 status = ncio_px_init2(nciop, sizehintp, 1);
01211
01212 if(status != ENOERR)
01213 goto unwind_open;
01214
01215 if(initialsz != 0)
01216 {
01217 status = fgrow(fd, (off_t)initialsz);
01218 if(status != ENOERR)
01219 goto unwind_open;
01220 }
01221
01222 if(igetsz != 0)
01223 {
01224 status = nciop->get(nciop,
01225 igeto, igetsz,
01226 RGN_WRITE,
01227 igetvpp);
01228 if(status != ENOERR)
01229 goto unwind_open;
01230 }
01231
01232 *nciopp = nciop;
01233 return ENOERR;
01234
01235 unwind_open:
01236 (void) close(fd);
01237
01238
01239 unwind_new:
01240 ncio_free(nciop);
01241 return status;
01242 }
01243
01244
01245 int
01246 ncio_open(const char *path,
01247 int ioflags,
01248 off_t igeto, size_t igetsz, size_t *sizehintp,
01249 ncio **nciopp, void **const igetvpp)
01250 {
01251 ncio *nciop;
01252 int oflags = fIsSet(ioflags, NC_WRITE) ? O_RDWR : O_RDONLY;
01253 int fd;
01254 int status;
01255
01256 if(path == NULL || *path == 0)
01257 return EINVAL;
01258
01259 nciop = ncio_new(path, ioflags);
01260 if(nciop == NULL)
01261 return ENOMEM;
01262
01263 #ifdef O_BINARY
01264 fSet(oflags, O_BINARY);
01265 #endif
01266 #ifdef vms
01267 fd = open(path, oflags, 0, "ctx=stm");
01268 #else
01269 fd = open(path, oflags, 0);
01270 #endif
01271 if(fd < 0)
01272 {
01273 status = errno;
01274 goto unwind_new;
01275 }
01276 *((int *)&nciop->fd) = fd;
01277
01278 if(*sizehintp < NCIO_MINBLOCKSIZE || *sizehintp > NCIO_MAXBLOCKSIZE)
01279 {
01280
01281 *sizehintp = blksize(fd);
01282 }
01283 else
01284 {
01285 *sizehintp = M_RNDUP(*sizehintp);
01286 }
01287
01288 if(fIsSet(nciop->ioflags, NC_SHARE))
01289 status = ncio_spx_init2(nciop, sizehintp);
01290 else
01291 status = ncio_px_init2(nciop, sizehintp, 0);
01292
01293 if(status != ENOERR)
01294 goto unwind_open;
01295
01296 if(igetsz != 0)
01297 {
01298 status = nciop->get(nciop,
01299 igeto, igetsz,
01300 0,
01301 igetvpp);
01302 if(status != ENOERR)
01303 goto unwind_open;
01304 }
01305
01306 *nciopp = nciop;
01307 return ENOERR;
01308
01309 unwind_open:
01310 (void) close(fd);
01311
01312 unwind_new:
01313 ncio_free(nciop);
01314 return status;
01315 }
01316
01317
01318 int
01319 ncio_close(ncio *nciop, int doUnlink)
01320 {
01321 int status = ENOERR;
01322
01323 if(nciop == NULL)
01324 return EINVAL;
01325
01326 status = nciop->sync(nciop);
01327
01328 (void) close(nciop->fd);
01329
01330 if(doUnlink)
01331 (void) unlink(nciop->path);
01332
01333 ncio_free(nciop);
01334
01335 return status;
01336 }