ncdf4a13/libsrc/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 /* $Id: posixio.c,v 1.79 2006/01/03 04:58:07 russ Exp $ */
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 /* Microsoft Compilers */
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 /* #define INSTRUMENT 1 */
00035 #if INSTRUMENT /* debugging */
00036 #undef NDEBUG
00037 #include <stdio.h>
00038 #include "instr.h"
00039 #endif
00040 
00041 #undef MIN  /* system may define MIN somewhere and complain */
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 /* !defined(NDEBUG) && !defined(X_ALIGN) */
00049 #define  X_ALIGN 4
00050 #else
00051 #undef X_ALIGN
00052 #endif
00053 
00054 /*
00055  * Define the following for debugging.
00056  */
00057 /* #define ALWAYS_NC_SHARE 1 */
00058 
00059 /* Begin OS */
00060 
00061 #ifndef POSIXIO_DEFAULT_PAGESIZE
00062 #define POSIXIO_DEFAULT_PAGESIZE 4096
00063 #endif
00064 /*
00065  * What is the system pagesize?
00066  */
00067 static size_t
00068 pagesize(void)
00069 {
00070 /* Hmm, aren't standards great? */
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                 /* else, silent in the face of error */
00081         }
00082 #elif defined(HAVE_GETPAGESIZE)
00083         return (size_t) getpagesize();
00084 #endif
00085         return (size_t) POSIXIO_DEFAULT_PAGESIZE;
00086 }
00087 
00088 /*
00089  * What is the preferred I/O block size?
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         /* else, silent in the face of error */
00103 #endif
00104         return (size_t) 2 * pagesize();
00105 }
00106 
00107 
00108 /*
00109  * Sortof like ftruncate, except won't make the
00110  * file shorter.
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             /* we don't use ftruncate() due to problem with FAT32 file systems */
00123             /* cache current position */
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  * Sortof like ftruncate, except won't make the file shorter.  Differs
00140  * from fgrow by only writing one byte at designated seek position, if
00141  * needed.
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             /* we don't use ftruncate() due to problem with FAT32 file systems */
00154             /* cache current position */
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 /* End OS */
00168 /* Begin px */
00169 
00170 /* The px_ functions are for posix systems, when NC_SHARE is not in
00171    effect. */
00172 
00173 /* Write out a "page" of data to the file. The size of the page
00174    (i.e. the extent) varies.
00175 
00176    nciop - pointer to the file metadata.
00177    offset - where in the file should this page be written.
00178    extent - how many bytes should be written.
00179    vp - pointer to the data to write.
00180    posp - pointer to current position in file, updated after write.
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 /* Read in a page of data. 
00211 
00212    nciop - a pointer to the ncio struct for this file.
00213    offset - byte offset in file where read starts.
00214    extent - the size of the page that will be read.
00215    vp - a pointer to where the data will end up.
00216    nreadp - returned number of bytes actually read (may be less than extent).
00217    posp - pointer to current position in file, updated after read.
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                 /* else it's okay we read less than asked for */
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 /* This struct is for POSIX systems, with NC_SHARE not in effect. If
00261    NC_SHARE is used, see ncio_spx.
00262 
00263    blksz - block size for reads and writes to file.
00264    pos - current read/write position in file.
00265    bf_offset - file offset corresponding to start of memory buffer
00266    bf_extent - number of bytes in I/O request
00267    bf_cnt - number of bytes available in buffer
00268    bf_base - pointer to beginning of buffer.
00269    bf_rflags - buffer region flags (defined in ncio.h) tell the lock
00270    status, read/write permissions, and modification status of regions
00271    of data in the buffer.
00272    bf_refcount - buffer reference count.
00273    slave - used in moves.
00274 */
00275 typedef struct ncio_px {
00276         size_t blksz;
00277         off_t pos;
00278         /* buffer */
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         /* chain for double buffering in px_move */
00286         struct ncio_px *slave;
00287 } ncio_px;
00288 
00289 
00290 /*ARGSUSED*/
00291 /* This function indicates the file region starting at offset may be
00292    released.
00293 
00294    This is for POSIX, without NC_SHARE.  If called with RGN_MODIFIED
00295    flag, sets the modified flag in pxp->bf_rflags and decrements the
00296    reference count.
00297 
00298    pxp - pointer to posix non-share ncio_px struct.
00299 
00300    offset - file offset for beginning of to region to be
00301    released.
00302 
00303    rflags - only RGN_MODIFIED is relevent to this function, others ignored
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 /* This function indicates the file region starting at offset may be
00323    released.  Each read or write to the file is bracketed by a call to
00324    the "get" region function and a call to the "rel" region function.
00325    If you only read from the memory region, release it with a flag of
00326    0, if you modify the region, release it with a flag of
00327    RGN_MODIFIED.
00328 
00329    For POSIX system, without NC_SHARE, this becomes the rel function
00330    pointed to by the ncio rel function pointer. It mearly checks for
00331    file write permission, then calls px_rel to do everything.
00332 
00333    nciop - pointer to ncio struct.
00334    offset - num bytes from beginning of buffer to region to be
00335    released.
00336    rflags - only RGN_MODIFIED is relevent to this function, others ignored
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; /* attempt to write readonly file */
00345 
00346         return px_rel(pxp, offset, rflags);
00347 }
00348 
00349 /* POSIX get. This will "make a region available." Since we're using
00350    buffered IO, this means that if needed, we'll fetch a new page from
00351    the file, otherwise, just return a pointer to what's in memory
00352    already. 
00353 
00354    nciop - pointer to ncio struct, containing file info.
00355    pxp - pointer to ncio_px struct, which contains special metadate
00356    for posix files without NC_SHARE.
00357    offset - start byte of region to get.
00358    extent - how many bytes to read.
00359    rflags - One of the RGN_* flags defined in ncio.h.
00360    vpp - pointer to pointer that will recieve data.
00361 
00362    NOTES: 
00363 
00364    * For blkoffset round offset down to the nearest pxp->blksz. This
00365    provides the offset (in bytes) to the beginning of the block that
00366    holds the current offset.
00367 
00368    * diff tells how far into the current block we are.
00369 
00370    * For blkextent round up to the number of bytes at the beginning of
00371    the next block, after the one that holds our current position, plus
00372    whatever extra (i.e. the extent) that we are about to grab.
00373 
00374    * The blkextent can't be more than twice the pxp->blksz. That's
00375    because the pxp->blksize is the sizehint, and in ncio_px_init2 the
00376    buffer (pointed to by pxp->bf-base) is allocated with 2 *
00377    *sizehintp. This is checked (unneccesarily) more than once in
00378    asserts.
00379 
00380    * If this is called on a newly opened file, pxp->bf_offset will be
00381    OFF_NONE and we'll jump to label pgin to immediately read in a
00382    page. 
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); /* sanity check */
00398         assert(offset >= 0); /* sanity check */
00399 
00400         if(2 * pxp->blksz < blkextent)
00401                 return E2BIG; /* TODO: temporary kludge */
00402         if(pxp->bf_offset == OFF_NONE)
00403         {
00404                 /* Uninitialized */
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         /* else */
00416         assert(blkextent <= 2 * pxp->blksz);
00417 
00418         if(blkoffset == pxp->bf_offset)
00419         {
00420                 /* hit */
00421                 if(blkextent > pxp->bf_extent) 
00422                 {
00423                         /* page in upper */
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         /* else */
00441 
00442         if(pxp->bf_extent > pxp->blksz
00443                  && blkoffset == pxp->bf_offset + (off_t)pxp->blksz)
00444         {
00445                 /* hit in upper half */
00446                 if(blkextent == pxp->blksz)
00447                 {
00448                         /* all in upper half, no fault needed */
00449                         diff += pxp->blksz;
00450                         goto done;
00451                 }
00452                 /* else */
00453                 if(pxp->bf_cnt > pxp->blksz)
00454                 {
00455                         /* data in upper half */
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                                 /* page out lower half */
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                         /* copy upper half into lower half */
00473                         (void) memcpy(pxp->bf_base, middle, pxp->bf_cnt);
00474                 }
00475                 pxp->bf_offset = blkoffset;
00476                 /* pxp->bf_extent = pxp->blksz; */
00477 
00478                 assert(blkextent == 2 * pxp->blksz);
00479                 {
00480                         /* page in upper */
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         /* else */
00497 
00498         if(blkoffset == pxp->bf_offset - (off_t)pxp->blksz)
00499         {
00500                 /* wants the page below */
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                         /* data in upper half */
00507                         assert(pxp->bf_extent == 2 * pxp->blksz);
00508                         if(fIsSet(pxp->bf_rflags, RGN_MODIFIED))
00509                         {
00510                                 /* page out upper half */
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                         /* copy lower half into upper half */
00526                         (void) memcpy(middle, pxp->bf_base, pxp->blksz);
00527                         upper_cnt = pxp->bf_cnt;
00528                 }
00529                 /* read page below into lower half */
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         /* else */
00551 
00552         /* no overlap */
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 /* Request that the region (offset, extent) be made available through
00592    *vpp.
00593 
00594    This function converts a file region specified by an offset and
00595    extent to a memory pointer. The region may be locked until the
00596    corresponding call to rel().
00597 
00598    For POSIX systems, without NC_SHARE. This function gets a page of
00599    size extent? 
00600 
00601    This is a wrapper for the function px_get, which does all the heavy
00602    lifting.
00603 
00604    nciop - pointer to ncio struct for this file.
00605    offset - offset (from beginning of file?) to the data we want to
00606    read.
00607    extent - the number of bytes to read from the file.
00608    rflags - One of the RGN_* flags defined in ncio.h.
00609    vpp - handle to point at data when it's been read.
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; /* attempt to write readonly file */
00621 
00622         /* reclaim space used in move */
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 /* ARGSUSED */
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                 /* pos done below */
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                 /* position changed, sync */
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 /* Like memmove(), safely move possibly overlapping data.
00699 
00700    Copy one region to another without making anything available to
00701    higher layers. May be just implemented in terms of get() and rel(),
00702    or may be tricky to be efficient. Only used in by nc_enddef()
00703    after redefinition.
00704 
00705    nciop - pointer to ncio struct with file info.
00706    to - src for move?
00707    from - dest for move?
00708    nbytes - number of bytes to move.
00709    rflags - One of the RGN_* flags defined in ncio.h. The only
00710    reasonable flag value is RGN_NOLOCK.
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; /* NOOP */
00726         
00727         if(fIsSet(rflags, RGN_WRITE) && !fIsSet(nciop->ioflags, NC_WRITE))
00728                 return EPERM; /* attempt to write readonly file */
00729 
00730         rflags &= RGN_NOLOCK; /* filter unwanted flags */
00731 
00732         if(to > from)
00733         {
00734                 /* growing */
00735                 lower = from;   
00736                 upper = to;
00737         }
00738         else
00739         {
00740                 /* shrinking */
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; /* normal loop exit */
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; /* normal loop exit */
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 /* Flush any buffers to disk. May be a no-op on if I/O is unbuffered.
00817    This function is used when NC_SHARE is NOT used.
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              * The dataset is readonly.  Invalidate the buffers so
00838              * that the next ncio_px_get() will actually read data.
00839              */
00840             pxp->bf_offset = OFF_NONE;
00841             pxp->bf_cnt = 0;
00842         }
00843         return status;
00844 }
00845 
00846 /* Internal function called at close to
00847    free up anything hanging off pvt.
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 /* This is the second half of the ncio initialization. This is called
00880    after the file has actually been opened.
00881 
00882    The most important thing that happens is the allocation of a block
00883    of memory at pxp->bf_base. This is going to be twice the size of
00884    the chunksizehint (rounded up to the nearest sizeof(double)) passed
00885    in from nc__create or nc__open. The rounded chunksizehint (passed
00886    in here in sizehintp) is going to be stored as pxp->blksize.
00887 
00888    According to our "contract" we are not allowed to ask for an extent
00889    larger than this chunksize/sizehint/blksize from the ncio get
00890    function.
00891 
00892    nciop - pointer to the ncio struct
00893    sizehintp - pointer to a size hint that will be rounded up and
00894    passed back to the caller.
00895    isNew - true if this is being called from ncio_create for a new
00896    file.
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         /* this is separate allocation because it may grow */
00911         pxp->bf_base = malloc(bufsz);
00912         if(pxp->bf_base == NULL)
00913                 return ENOMEM;
00914         /* else */
00915         pxp->bf_cnt = 0;
00916         if(isNew)
00917         {
00918                 /* save a read */
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 /* This is the first of a two-part initialization of the ncio struct.
00929    Here the rel, get, move, sync, and free function pointers are set
00930    to their POSIX non-NC_SHARE functions (ncio_px_*).
00931 
00932    The ncio_px struct is also partially initialized.
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; /* cast away const */
00940         *((ncio_getfunc **)&nciop->get) = ncio_px_get; /* cast away const */
00941         *((ncio_movefunc **)&nciop->move) = ncio_px_move; /* cast away const */
00942         *((ncio_syncfunc **)&nciop->sync) = ncio_px_sync; /* cast away const */
00943         *((ncio_freefunc **)&nciop->free) = ncio_px_free; /* cast away const */
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 /* Begin spx */
00957 
00958 /* This is the struct that gets hung of ncio->pvt(?) when the NC_SHARE
00959    flag is used.
00960 */
00961 typedef struct ncio_spx {
00962         off_t pos;
00963         /* buffer */
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 /*ARGSUSED*/
00972 /* This function releases the region specified by offset.
00973 
00974    For POSIX system, with NC_SHARE, this becomes the rel function
00975    pointed to by the ncio rel function pointer. It mearly checks for
00976    file write permission, then calls px_rel to do everything.
00977 
00978    nciop - pointer to ncio struct.
00979 
00980    offset - beginning of region.
00981 
00982    rflags - One of the RGN_* flags defined in ncio.h. If set to
00983    RGN_MODIFIED it means that the data in this region were modified,
00984    and it needs to be written out to the disk immediately (since we
00985    are not buffering with NC_SHARE on).
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; /* attempt to write readonly file */
01006 
01007                 status = px_pgout(nciop, pxp->bf_offset,
01008                         pxp->bf_cnt,
01009                         pxp->bf_base, &pxp->pos);
01010                 /* if error, invalidate buffer anyway */
01011         }
01012         pxp->bf_offset = OFF_NONE;
01013         pxp->bf_cnt = 0;
01014         return status;
01015 }
01016 
01017 
01018 /* Request that the region (offset, extent) be made available through
01019    *vpp.
01020 
01021    This function converts a file region specified by an offset and
01022    extent to a memory pointer. The region may be locked until the
01023    corresponding call to rel().
01024 
01025    For POSIX systems, with NC_SHARE.
01026 
01027    nciop - pointer to ncio struct for this file.
01028    offset - offset (from beginning of file?) to the data we want to
01029    read.
01030    extent - the number of bytes we want.
01031    rflags - One of the RGN_* flags defined in ncio.h. May be RGN_NOLOCK.
01032    vpp - handle to point at data when it's been read.
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; /* attempt to write readonly file */
01048 
01049         assert(extent != 0);
01050         assert(extent < X_INT_MAX); /* sanity check */
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 /*ARGSUSED*/
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); /* sanity check */
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; /* TODO: XALIGN */
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         /* if error, invalidate buffer anyway */
01177         pxp->bf_offset = OFF_NONE;
01178         pxp->bf_cnt = 0;
01179         return status;
01180 }
01181 #endif
01182 
01183 /* Copy one region to another without making anything available to
01184    higher layers. May be just implemented in terms of get() and rel(),
01185    or may be tricky to be efficient.  Only used in by nc_enddef()
01186    after redefinition.
01187 
01188    nciop - pointer to ncio struct for this file.
01189    to - dest for move?
01190    from - src for move?
01191    nbytes - number of bytes to move.
01192    rflags - One of the RGN_* flags defined in ncio.h.
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; /* filter unwanted flags */
01206 
01207         if(to == from)
01208                 return ENOERR; /* NOOP */
01209         
01210         if(to > from)
01211         {
01212                 /* growing */
01213                 lower = from;   
01214                 upper = to;
01215         }
01216         else
01217         {
01218                 /* shrinking */
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 /*ARGSUSED*/
01244 /* Flush any buffers to disk. May be a no-op on if I/O is unbuffered.
01245 */
01246 static int
01247 ncio_spx_sync(ncio *const nciop)
01248 {
01249         /* NOOP */
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 /* This does the second half of the ncio_spx struct initialization for
01272    POSIX systems, with NC_SHARE on. 
01273 
01274    nciop - pointer to ncio struct for this file. File has been opened.
01275    sizehintp - pointer to a size which will be rounded up to the
01276    nearest 8-byt boundary and then used as the max size "chunk" (or
01277    page) to read from the file. 
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         /* this is separate allocation because it may grow */
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         /* else */
01298         return ENOERR;
01299 }
01300 
01301 
01302 /* First half of init for ncio_spx struct, setting the rel, get, move,
01303    snyc, and free function pointers to the NC_SHARE versions of these
01304    functions (i.e. the ncio_spx_* functions).
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; /* cast away const */
01312         *((ncio_getfunc **)&nciop->get) = ncio_spx_get; /* cast away const */
01313         *((ncio_movefunc **)&nciop->move) = ncio_spx_move; /* cast away const */
01314         *((ncio_syncfunc **)&nciop->sync) = ncio_spx_sync; /* cast away const */
01315         *((ncio_freefunc **)&nciop->free) = ncio_spx_free; /* cast away const */
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 /* This will call whatever free function is attached to the free
01328    function pointer in ncio. It's called from ncio_close, and from
01329    ncio_open and ncio_create when an error occurs that the file
01330    metadata must be freed.
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 /* Create a new ncio struct to hold info about the file. This will
01346    create and init the ncio_px or ncio_spx struct (the latter if
01347    NC_SHARE is used.)
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 /* DEBUG */
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; /* cast away const */
01372 
01373         nciop->path = (char *) ((char *)nciop + sz_ncio);
01374         (void) strcpy((char *)nciop->path, path); /* cast away const */
01375 
01376                                 /* cast away const */
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 /* Public below this point */
01389 
01390 #define NCIO_MINBLOCKSIZE 256
01391 #define NCIO_MAXBLOCKSIZE 268435456 /* sanity check, about X_SIZE_T_MAX/8 */
01392 
01393 #ifdef S_IRUSR
01394 #define NC_DEFAULT_CREAT_MODE \
01395         (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH) /* 0666 */
01396 
01397 #else
01398 #define NC_DEFAULT_CREAT_MODE 0666
01399 #endif
01400 
01401 /* Create a file, and the ncio struct to go with it. This funtion is
01402    only called from nc__create_mp.
01403 
01404    path - path of file to create.
01405    ioflags - flags from nc_create
01406    initialsz - From the netcdf man page: "The argument
01407    Iinitialsize sets the initial size of the file at creation time."
01408    igeto - 
01409    igetsz - 
01410    sizehintp - this eventually goes into pxp->blksz and is the size of
01411    a page of data for buffered reads and writes.
01412    nciopp - pointer to a pointer that will get location of newly
01413    created and inited ncio struct.
01414    igetvpp - pointer to pointer which will get the location of ?
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         /* Should we mess with the mode based on NC_SHARE ?? */
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; /* cast away const */
01462 
01463         if(*sizehintp < NCIO_MINBLOCKSIZE || *sizehintp > NCIO_MAXBLOCKSIZE)
01464         {
01465                 /* Use default */
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         /* ?? unlink */
01504         /*FALLTHRU*/
01505 unwind_new:
01506         ncio_free(nciop);
01507         return status;
01508 }
01509 
01510 
01511 /* This function opens the data file. It is only called from nc.c,
01512    from nc__open_mp and nc_delete_mp.
01513 
01514    path - path of data file.
01515 
01516    ioflags - flags passed into nc_open.
01517    
01518    igeto - looks like this function can do an initial page get, and
01519    igeto is going to be the offset for that. But it appears to be
01520    unused 
01521 
01522    igetsz - the size in bytes of initial page get (a.k.a. extent). Not
01523    ever used in the library.
01524    
01525    sizehintp - pointer to sizehint parameter from nc__open or
01526    nc__create. This is used to set pxp->blksz. 
01527    
01528    Here's what the man page has to say:
01529 
01530    "The argument referenced by chunksize controls a space versus time
01531    tradeoff, memory allocated in the netcdf library versus number of
01532    system calls.
01533 
01534    Because of internal requirements, the value may not be set to
01535    exactly the value requested. The actual value chosen is returned by reference.
01536 
01537    Using the value NC_SIZEHINT_DEFAULT causes the library to choose a
01538    default. How the system choses the default depends on the
01539    system. On many systems, the "preferred I/O block size" is
01540    available from the stat() system call, struct stat member
01541    st_blksize. If this is available it is used. Lacking that, twice
01542    the system pagesize is used. Lacking a call to discover the system
01543    pagesize, we just set default chunksize to 8192.
01544 
01545    The chunksize is a property of a given open netcdf descriptor ncid,
01546    it is not a persistent property of the netcdf dataset."
01547 
01548    nciopp - pointer to pointer that will get address of newly created
01549    and inited ncio struct.
01550 
01551    igetvpp - handle to pass back pointer to data from inital page
01552    read, if this were ever used, which it isn't.
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; /* cast away const */
01586 
01587         if(*sizehintp < NCIO_MINBLOCKSIZE || *sizehintp > NCIO_MAXBLOCKSIZE)
01588         {
01589                 /* Use default */
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         /*FALLTHRU*/
01621 unwind_new:
01622         ncio_free(nciop);
01623         return status;
01624 }
01625 
01626 /* 
01627  * Get file size in bytes.
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  * Sync any changes to disk, then truncate or extend file so its size
01643  * is length.  This is only intended to be called before close, if the
01644  * file is open for writing and the actual size does not match the
01645  * calculated size, perhaps as the result of having been previously
01646  * written in NOFILL mode.
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; /* attempt to write readonly file */
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 /* Write out any dirty buffers to disk and
01671    ensure that next read will get data from disk.
01672 
01673    Sync any changes, then close the open file associated with the ncio
01674    struct, and free its memory.
01675    
01676    nciop - pointer to ncio to close.
01677 
01678    doUnlink - if true, unlink file
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 }

Generated on Thu Mar 16 18:10:09 2006 for nco by  doxygen 1.4.4