Skip to content

AFNI/NIfTI Server

Sections
Personal tools
You are here: Home » AFNI » Documentation

Doxygen Source Code Documentation


Main Page   Alphabetical List   Data Structures   File List   Data Fields   Globals   Search  

posixio.c

Go to the documentation of this file.
00001 /*
00002  *      Copyright 1996, University Corporation for Atmospheric Research
00003  *      See netcdf/COPYRIGHT file for copying and redistribution conditions.
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 /* Microsoft Compilers */
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 /* #define INSTRUMENT 1 */
00034 #if INSTRUMENT /* debugging */
00035 #undef NDEBUG
00036 #include <stdio.h>
00037 #include "instr.h"
00038 #endif
00039 
00040 #undef MIN  /* system may define MIN somewhere and complain */
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 /* !defined(NDEBUG) && !defined(X_ALIGN) */
00048 #define  X_ALIGN 4
00049 #else
00050 #undef X_ALIGN
00051 #endif
00052 
00053 /*
00054  * Define the following for debugging.
00055  */
00056 /* #define ALWAYS_NC_SHARE 1 */
00057 
00058 /* Begin OS */
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  * What is the system pagesize?
00067  */
00068 static size_t
00069 pagesize(void)
00070 {
00071 /* Hmm, aren't standards great? */
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                 /* else, silent in the face of error */
00082         }
00083 #elif defined(HAVE_GETPAGESIZE)
00084         return (size_t) getpagesize();
00085 #endif
00086         return (size_t) POSIXIO_DEFAULT_PAGESIZE;
00087 }
00088 
00089 /*
00090  * What is the preferred I/O block size?
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         /* else, silent in the face of error */
00104 #endif
00105         return (size_t) 2 * pagesize();
00106 }
00107 
00108 
00109 /*
00110  * Sortof like ftruncate, except won't make the
00111  * file shorter.
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                         /* cache current position */
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 /* HAVE_FTRUNCATE */
00139         /* else */
00140         return ENOERR;
00141 }
00142 
00143 /* End OS */
00144 /* Begin px */
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                 /* else it's okay we read less than asked for */
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         /* buffer */
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         /* chain for double buffering in px_move */
00228         struct ncio_px *slave;
00229 } ncio_px;
00230 
00231 
00232 /*ARGSUSED*/
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; /* attempt to write readonly file */
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); /* sanity check */
00275         assert(offset >= 0); /* sanity check */
00276         assert(offset < X_INT_MAX); /* sanity check */
00277 
00278         if(2 * pxp->blksz < blkextent)
00279                 return E2BIG; /* TODO: temporary kludge */
00280         if(pxp->bf_offset == OFF_NONE)
00281         {
00282                 /* Uninitialized */
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         /* else */
00294         assert(blkextent <= 2 * pxp->blksz);
00295 
00296         if(blkoffset == pxp->bf_offset)
00297         {
00298                 /* hit */
00299                 if(blkextent > pxp->bf_extent) 
00300                 {
00301                         /* page in upper */
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         /* else */
00319 
00320         if(pxp->bf_extent > pxp->blksz
00321                  && blkoffset == pxp->bf_offset + pxp->blksz)
00322         {
00323                 /* hit in upper half */
00324                 if(blkextent == pxp->blksz)
00325                 {
00326                         /* all in upper half, no fault needed */
00327                         diff += pxp->blksz;
00328                         goto done;
00329                 }
00330                 /* else */
00331                 if(pxp->bf_cnt > pxp->blksz)
00332                 {
00333                         /* data in upper half */
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                                 /* page out lower half */
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                         /* copy upper half into lower half */
00351                         (void) memcpy(pxp->bf_base, middle, pxp->bf_cnt);
00352                 }
00353                 pxp->bf_offset = blkoffset;
00354                 /* pxp->bf_extent = pxp->blksz; */
00355 
00356                 assert(blkextent == 2 * pxp->blksz);
00357                 {
00358                         /* page in upper */
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         /* else */
00375 
00376         if(blkoffset == pxp->bf_offset - pxp->blksz)
00377         {
00378                 /* wants the page below */
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                         /* data in upper half */
00385                         assert(pxp->bf_extent == 2 * pxp->blksz);
00386                         if(fIsSet(pxp->bf_rflags, RGN_MODIFIED))
00387                         {
00388                                 /* page out upper half */
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                         /* copy lower half into upper half */
00404                         (void) memcpy(middle, pxp->bf_base, pxp->blksz);
00405                         upper_cnt = pxp->bf_cnt;
00406                 }
00407                 /* read page below into lower half */
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         /* else */
00429 
00430         /* no overlap */
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)       /* NULL => force read */
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; /* attempt to write readonly file */
00479 
00480         /*
00481          * If the base of the stream buffer is NULL, then a read is forced
00482          * for synchronization purposes (see fault_v1hs() in v1hpg.c).  The
00483          * implementation is based on ncio_spx_rel() in this file.
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         /* reclaim space used in move */
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 /* ARGSUSED */
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                 /* pos done below */
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                 /* position changed, sync */
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; /* NOOP */
00582         
00583         if(fIsSet(rflags, RGN_WRITE) && !fIsSet(nciop->ioflags, NC_WRITE))
00584                 return EPERM; /* attempt to write readonly file */
00585 
00586         rflags &= RGN_NOLOCK; /* filter unwanted flags */
00587 
00588         if(to > from)
00589         {
00590                 /* growing */
00591                 lower = from;   
00592                 upper = to;
00593         }
00594         else
00595         {
00596                 /* shrinking */
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; /* normal loop exit */
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; /* normal loop exit */
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         /* this is separate allocation because it may grow */
00733         pxp->bf_base = malloc(bufsz);
00734         if(pxp->bf_base == NULL)
00735                 return ENOMEM;
00736         /* else */
00737         pxp->bf_cnt = 0;
00738         if(isNew)
00739         {
00740                 /* save a read */
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; /* cast away const */
00756         *((ncio_getfunc **)&nciop->get) = ncio_px_get; /* cast away const */
00757         *((ncio_movefunc **)&nciop->move) = ncio_px_move; /* cast away const */
00758         *((ncio_syncfunc **)&nciop->sync) = ncio_px_sync; /* cast away const */
00759         *((ncio_freefunc **)&nciop->free) = ncio_px_free; /* cast away const */
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 /* Begin spx */
00773 
00774 typedef struct ncio_spx {
00775         off_t pos;
00776         /* buffer */
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 /*ARGSUSED*/
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; /* attempt to write readonly file */
00803 
00804                 status = px_pgout(nciop, pxp->bf_offset,
00805                         pxp->bf_cnt,
00806                         pxp->bf_base, &pxp->pos);
00807                 /* if error, invalidate buffer anyway */
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; /* attempt to write readonly file */
00829 
00830         assert(extent != 0);
00831         assert(extent < X_INT_MAX); /* sanity check */
00832         assert(offset < X_INT_MAX); /* sanity check */
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 /*ARGSUSED*/
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); /* sanity check */
00904         assert(offset < X_INT_MAX); /* sanity check */
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; /* TODO: XALIGN */
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         /* if error, invalidate buffer anyway */
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; /* filter unwanted flags */
00978 
00979         if(to == from)
00980                 return ENOERR; /* NOOP */
00981         
00982         if(to > from)
00983         {
00984                 /* growing */
00985                 lower = from;   
00986                 upper = to;
00987         }
00988         else
00989         {
00990                 /* shrinking */
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 /*ARGSUSED*/
01016 static int
01017 ncio_spx_sync(ncio *const nciop)
01018 {
01019         /* NOOP */
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         /* this is separate allocation because it may grow */
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         /* else */
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; /* cast away const */
01070         *((ncio_getfunc **)&nciop->get) = ncio_spx_get; /* cast away const */
01071         *((ncio_movefunc **)&nciop->move) = ncio_spx_move; /* cast away const */
01072         *((ncio_syncfunc **)&nciop->sync) = ncio_spx_sync; /* cast away const */
01073         *((ncio_freefunc **)&nciop->free) = ncio_spx_free; /* cast away const */
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 /* DEBUG */
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; /* cast away const */
01121 
01122         nciop->path = (char *) ((char *)nciop + sz_ncio);
01123         (void) strcpy((char *)nciop->path, path); /* cast away const */
01124 
01125                                 /* cast away const */
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 /* Public below this point */
01138 
01139 #define NCIO_MINBLOCKSIZE 256
01140 #define NCIO_MAXBLOCKSIZE 268435456 /* sanity check, about X_SIZE_T_MAX/8 */
01141 
01142 #ifdef S_IRUSR
01143 #define NC_DEFAULT_CREAT_MODE \
01144         (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH) /* 0666 */
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         /* Should we mess with the mode based on NC_SHARE ?? */
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; /* cast away const */
01196 
01197         if(*sizehintp < NCIO_MINBLOCKSIZE || *sizehintp > NCIO_MAXBLOCKSIZE)
01198         {
01199                 /* Use default */
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         /* ?? unlink */
01238         /*FALLTHRU*/
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; /* cast away const */
01277 
01278         if(*sizehintp < NCIO_MINBLOCKSIZE || *sizehintp > NCIO_MAXBLOCKSIZE)
01279         {
01280                 /* Use default */
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         /*FALLTHRU*/
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 }
 

Powered by Plone

This site conforms to the following standards: