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