source: XIOS/dev/branch_openmp/extern/src_netcdf4/posixio.c @ 1501

Last change on this file since 1501 was 409, checked in by ymipsl, 11 years ago

Add improved nectdf internal library src

YM

  • Property svn:eol-style set to native
File size: 41.1 KB
Line 
1/*
2 *      Copyright 1996, University Corporation for Atmospheric Research
3 *      See netcdf/COPYRIGHT file for copying and redistribution conditions.
4 */
5/* $Id: posixio.c,v 1.89 2010/05/22 21:59:08 dmh Exp $ */
6
7/* For MinGW Build */
8#if defined(_WIN32) || defined(_WIN64)
9#include <windows.h>
10#include <winbase.h>
11#include <io.h>
12#define fstat64 fstat
13#define lseek64 lseek
14#endif
15
16#include <config.h>
17#include <assert.h>
18#include <stdlib.h>
19#include <errno.h>
20#ifndef ENOERR
21#define ENOERR 0
22#endif
23#include <sys/types.h>
24#include <sys/stat.h>
25#include <fcntl.h>
26#include <string.h>
27#ifdef _MSC_VER /* Microsoft Compilers */
28#include <io.h>
29#else
30#include <unistd.h>
31#endif
32#ifndef HAVE_SSIZE_T
33#define ssize_t int
34#endif
35
36#ifndef SEEK_SET
37#define SEEK_SET 0
38#define SEEK_CUR 1
39#define SEEK_END 2
40#endif
41
42#include "ncio.h"
43#include "fbits.h"
44#include "rnd.h"
45
46/* #define INSTRUMENT 1 */
47#if INSTRUMENT /* debugging */
48#undef NDEBUG
49#include <stdio.h>
50/*#include "instr.h"*/
51#endif
52
53#undef MIN  /* system may define MIN somewhere and complain */
54#define MIN(mm,nn) (((mm) < (nn)) ? (mm) : (nn))
55
56#if !defined(NDEBUG) && !defined(X_INT_MAX)
57#define  X_INT_MAX 2147483647
58#endif
59
60#if 0 /* !defined(NDEBUG) && !defined(X_ALIGN) */
61#define  X_ALIGN 4
62#else
63#undef X_ALIGN
64#endif
65
66/* These are needed on mingw to get a dll to compile. They really
67 * should be provided in sys/stats.h, but what the heck. Let's not be
68 * too picky! */
69#ifndef S_IRGRP
70#define S_IRGRP   0000040
71#endif
72#ifndef S_IROTH
73#define S_IROTH   0000004
74#endif
75#ifndef S_IWGRP
76#define S_IWGRP   0000020
77#endif
78#ifndef S_IWOTH
79#define S_IWOTH   0000002
80#endif
81
82/*Forward*/
83static int ncio_px_filesize(ncio *nciop, off_t *filesizep);
84static int ncio_px_pad_length(ncio *nciop, off_t length);
85static int ncio_px_close(ncio *nciop, int doUnlink);
86static int ncio_spx_close(ncio *nciop, int doUnlink);
87
88
89/*
90 * Define the following for debugging.
91 */
92/* #define ALWAYS_NC_SHARE 1 */
93
94/* Begin OS */
95
96#ifndef POSIXIO_DEFAULT_PAGESIZE
97#define POSIXIO_DEFAULT_PAGESIZE 4096
98#endif
99/*
100 * What is the system pagesize?
101 */
102static size_t
103pagesize(void)
104{
105  size_t pgsz;
106#if defined(_WIN32) || defined(_WIN64)
107  SYSTEM_INFO info;
108#endif
109/* Hmm, aren't standards great? */
110#if defined(_SC_PAGE_SIZE) && !defined(_SC_PAGESIZE)
111#define _SC_PAGESIZE _SC_PAGE_SIZE
112#endif
113
114  /* For MinGW Builds */
115#if defined(_WIN32) || defined(_WIN64)
116  GetSystemInfo(&info);
117  pgsz = (size_t)info.dwPageSize;
118#elif defined(_SC_PAGESIZE)
119  pgsz = (size_t)sysconf(_SC_PAGESIZE);
120#elif defined(HAVE_GETPAGESIZE)
121  pgsz = (size_t) getpagesize();
122#endif
123  if(pgsz > 0)
124    return (size_t) pgsz;
125   return (size_t)POSIXIO_DEFAULT_PAGESIZE;
126}
127
128/*
129 * What is the preferred I/O block size?
130 */
131static size_t
132blksize(int fd)
133{
134#if defined(HAVE_ST_BLKSIZE)
135        struct stat sb;
136        if (fstat(fd, &sb) > -1)
137        {
138                if(sb.st_blksize >= 8192)
139                        return (size_t) sb.st_blksize;
140                return 8192;
141        }
142        /* else, silent in the face of error */
143#endif
144        return (size_t) 2 * pagesize();
145}
146
147
148/*
149 * Sortof like ftruncate, except won't make the
150 * file shorter.
151 */
152static int
153fgrow(const int fd, const off_t len)
154{
155        struct stat sb;
156        if (fstat(fd, &sb) < 0)
157                return errno;
158        if (len < sb.st_size)
159                return ENOERR;
160        {
161            const long dumb = 0;
162            /* we don't use ftruncate() due to problem with FAT32 file systems */
163            /* cache current position */
164            const off_t pos = lseek(fd, 0, SEEK_CUR);
165            if(pos < 0)
166                return errno;
167            if (lseek(fd, len-sizeof(dumb), SEEK_SET) < 0)
168                return errno;
169            if(write(fd, &dumb, sizeof(dumb)) < 0)
170                return errno;
171            if (lseek(fd, pos, SEEK_SET) < 0)
172                return errno;
173        }
174        return ENOERR;
175}
176
177
178/*
179 * Sortof like ftruncate, except won't make the file shorter.  Differs
180 * from fgrow by only writing one byte at designated seek position, if
181 * needed.
182 */
183static int
184fgrow2(const int fd, const off_t len)
185{
186        struct stat sb;
187        if (fstat(fd, &sb) < 0)
188                return errno;
189        if (len <= sb.st_size)
190                return ENOERR;
191        {
192            const char dumb = 0;
193            /* we don't use ftruncate() due to problem with FAT32 file systems */
194            /* cache current position */
195            const off_t pos = lseek(fd, 0, SEEK_CUR);
196            if(pos < 0)
197                return errno;
198            if (lseek(fd, len-1, SEEK_SET) < 0)
199                return errno;
200            if(write(fd, &dumb, sizeof(dumb)) < 0)
201                return errno;
202            if (lseek(fd, pos, SEEK_SET) < 0)
203                return errno;
204        }
205        return ENOERR;
206}
207/* End OS */
208/* Begin px */
209
210/* The px_ functions are for posix systems, when NC_SHARE is not in
211   effect. */
212
213/* Write out a "page" of data to the file. The size of the page
214   (i.e. the extent) varies.
215
216   nciop - pointer to the file metadata.
217   offset - where in the file should this page be written.
218   extent - how many bytes should be written.
219   vp - pointer to the data to write.
220   posp - pointer to current position in file, updated after write.
221*/
222static int
223px_pgout(ncio *const nciop, 
224        off_t const offset,  const size_t extent,
225        void *const vp, off_t *posp)
226{
227    ssize_t partial;
228    size_t nextent;
229    char *nvp;
230#ifdef X_ALIGN
231        assert(offset % X_ALIGN == 0);
232#endif
233
234        assert(*posp == OFF_NONE || *posp == lseek(nciop->fd, 0, SEEK_CUR));
235
236        if(*posp != offset)
237        {
238                if(lseek(nciop->fd, offset, SEEK_SET) != offset)
239                {
240                        return errno;
241                }
242                *posp = offset;
243        }
244        /* Old write, didn't handle partial writes correctly */
245        /* if(write(nciop->fd, vp, extent) != (ssize_t) extent) */
246        /* { */
247        /*      return errno; */
248        /* } */
249        nextent = extent;
250        nvp = vp;
251        while((partial = write(nciop->fd, nvp, nextent)) != -1) {
252            if(partial == nextent)
253                break;
254            nvp += partial;             
255            nextent -= partial;
256        }
257        if(partial == -1)
258            return errno;
259        *posp += extent;
260
261        return ENOERR;
262}
263
264/* Read in a page of data.
265
266   nciop - a pointer to the ncio struct for this file.
267   offset - byte offset in file where read starts.
268   extent - the size of the page that will be read.
269   vp - a pointer to where the data will end up.
270   nreadp - returned number of bytes actually read (may be less than extent).
271   posp - pointer to current position in file, updated after read.
272*/
273static int
274px_pgin(ncio *const nciop,
275        off_t const offset, const size_t extent,
276        void *const vp, size_t *nreadp, off_t *posp)
277{
278        int status;
279        ssize_t nread;
280
281#ifdef X_ALIGN
282        assert(offset % X_ALIGN == 0);
283        assert(extent % X_ALIGN == 0);
284#endif
285
286        assert(*posp == OFF_NONE || *posp == lseek(nciop->fd, 0, SEEK_CUR));
287
288        if(*posp != offset)
289        {
290                if(lseek(nciop->fd, offset, SEEK_SET) != offset)
291                {
292                        status = errno;
293                        return status;
294                }
295                *posp = offset;
296        }
297
298        errno = 0;
299        nread = read(nciop->fd, vp, extent);
300        if(nread != (ssize_t) extent)
301        {
302                status = errno;
303                if(nread == -1 || status != ENOERR)
304                        return status;
305                /* else it's okay we read less than asked for */
306                (void) memset((char *)vp + nread, 0, (ssize_t)extent - nread);
307        }
308        *nreadp = nread;
309        *posp += nread;
310
311        return ENOERR;
312}
313
314/* This struct is for POSIX systems, with NC_SHARE not in effect. If
315   NC_SHARE is used, see ncio_spx.
316
317   blksz - block size for reads and writes to file.
318   pos - current read/write position in file.
319   bf_offset - file offset corresponding to start of memory buffer
320   bf_extent - number of bytes in I/O request
321   bf_cnt - number of bytes available in buffer
322   bf_base - pointer to beginning of buffer.
323   bf_rflags - buffer region flags (defined in ncio.h) tell the lock
324   status, read/write permissions, and modification status of regions
325   of data in the buffer.
326   bf_refcount - buffer reference count.
327   slave - used in moves.
328*/
329typedef struct ncio_px {
330        size_t blksz;
331        off_t pos;
332        /* buffer */
333        off_t   bf_offset; 
334        size_t  bf_extent;
335        size_t  bf_cnt;
336        void    *bf_base;
337        int     bf_rflags;
338        int     bf_refcount;
339        /* chain for double buffering in px_move */
340        struct ncio_px *slave;
341} ncio_px;
342
343
344/*ARGSUSED*/
345/* This function indicates the file region starting at offset may be
346   released.
347
348   This is for POSIX, without NC_SHARE.  If called with RGN_MODIFIED
349   flag, sets the modified flag in pxp->bf_rflags and decrements the
350   reference count.
351
352   pxp - pointer to posix non-share ncio_px struct.
353
354   offset - file offset for beginning of to region to be
355   released.
356
357   rflags - only RGN_MODIFIED is relevent to this function, others ignored
358*/
359static int
360px_rel(ncio_px *const pxp, off_t offset, int rflags)
361{
362        assert(pxp->bf_offset <= offset
363                 && offset < pxp->bf_offset + (off_t) pxp->bf_extent);
364        assert(pIf(fIsSet(rflags, RGN_MODIFIED),
365                fIsSet(pxp->bf_rflags, RGN_WRITE)));
366
367        if(fIsSet(rflags, RGN_MODIFIED))
368        {
369                fSet(pxp->bf_rflags, RGN_MODIFIED);
370        }
371        pxp->bf_refcount--;
372
373        return ENOERR;
374}
375
376/* This function indicates the file region starting at offset may be
377   released.  Each read or write to the file is bracketed by a call to
378   the "get" region function and a call to the "rel" region function.
379   If you only read from the memory region, release it with a flag of
380   0, if you modify the region, release it with a flag of
381   RGN_MODIFIED.
382
383   For POSIX system, without NC_SHARE, this becomes the rel function
384   pointed to by the ncio rel function pointer. It mearly checks for
385   file write permission, then calls px_rel to do everything.
386
387   nciop - pointer to ncio struct.
388   offset - num bytes from beginning of buffer to region to be
389   released.
390   rflags - only RGN_MODIFIED is relevent to this function, others ignored
391*/
392static int
393ncio_px_rel(ncio *const nciop, off_t offset, int rflags)
394{
395        ncio_px *const pxp = (ncio_px *)nciop->pvt;
396
397        if(fIsSet(rflags, RGN_MODIFIED) && !fIsSet(nciop->ioflags, NC_WRITE))
398                return EPERM; /* attempt to write readonly file */
399
400        return px_rel(pxp, offset, rflags);
401}
402
403/* POSIX get. This will "make a region available." Since we're using
404   buffered IO, this means that if needed, we'll fetch a new page from
405   the file, otherwise, just return a pointer to what's in memory
406   already.
407
408   nciop - pointer to ncio struct, containing file info.
409   pxp - pointer to ncio_px struct, which contains special metadate
410   for posix files without NC_SHARE.
411   offset - start byte of region to get.
412   extent - how many bytes to read.
413   rflags - One of the RGN_* flags defined in ncio.h.
414   vpp - pointer to pointer that will recieve data.
415
416   NOTES:
417
418   * For blkoffset round offset down to the nearest pxp->blksz. This
419   provides the offset (in bytes) to the beginning of the block that
420   holds the current offset.
421
422   * diff tells how far into the current block we are.
423
424   * For blkextent round up to the number of bytes at the beginning of
425   the next block, after the one that holds our current position, plus
426   whatever extra (i.e. the extent) that we are about to grab.
427
428   * The blkextent can't be more than twice the pxp->blksz. That's
429   because the pxp->blksize is the sizehint, and in ncio_px_init2 the
430   buffer (pointed to by pxp->bf-base) is allocated with 2 *
431   *sizehintp. This is checked (unneccesarily) more than once in
432   asserts.
433
434   * If this is called on a newly opened file, pxp->bf_offset will be
435   OFF_NONE and we'll jump to label pgin to immediately read in a
436   page.
437*/
438static int
439px_get(ncio *const nciop, ncio_px *const pxp,
440                off_t offset, size_t extent,
441                int rflags,
442                void **const vpp)
443{
444        int status = ENOERR;
445
446        const off_t blkoffset = _RNDDOWN(offset, (off_t)pxp->blksz);
447        off_t diff = (size_t)(offset - blkoffset);
448        off_t blkextent = _RNDUP(diff + extent, pxp->blksz);
449       
450        assert(extent != 0);
451        assert(extent < X_INT_MAX); /* sanity check */
452        assert(offset >= 0); /* sanity check */
453
454        if(2 * pxp->blksz < blkextent)
455                return E2BIG; /* TODO: temporary kludge */
456        if(pxp->bf_offset == OFF_NONE)
457        {
458                /* Uninitialized */
459                if(pxp->bf_base == NULL)
460                {
461                        assert(pxp->bf_extent == 0);
462                        assert(blkextent <= 2 * pxp->blksz);
463                        pxp->bf_base = malloc(2 * pxp->blksz);
464                        if(pxp->bf_base == NULL)
465                                return ENOMEM;
466                }
467                goto pgin;
468        }
469        /* else */
470        assert(blkextent <= 2 * pxp->blksz);
471
472        if(blkoffset == pxp->bf_offset)
473        {
474                /* hit */
475                if(blkextent > pxp->bf_extent) 
476                {
477                        /* page in upper */
478                        void *const middle =
479                                (void *)((char *)pxp->bf_base + pxp->blksz);
480                        assert(pxp->bf_extent == pxp->blksz);
481                        status = px_pgin(nciop,
482                                 pxp->bf_offset + (off_t)pxp->blksz,
483                                 pxp->blksz,
484                                 middle,
485                                 &pxp->bf_cnt,
486                                 &pxp->pos);
487                        if(status != ENOERR)
488                                return status;
489                        pxp->bf_extent = 2 * pxp->blksz;
490                        pxp->bf_cnt += pxp->blksz;
491                }
492                goto done;
493        }
494        /* else */
495
496        if(pxp->bf_extent > pxp->blksz
497                 && blkoffset == pxp->bf_offset + (off_t)pxp->blksz)
498        {
499                /* hit in upper half */
500                if(blkextent == pxp->blksz)
501                {
502                        /* all in upper half, no fault needed */
503                        diff += pxp->blksz;
504                        goto done;
505                }
506                /* else */
507                if(pxp->bf_cnt > pxp->blksz)
508                {
509                        /* data in upper half */
510                        void *const middle =
511                                (void *)((char *)pxp->bf_base + pxp->blksz);
512                        assert(pxp->bf_extent == 2 * pxp->blksz);
513                        if(fIsSet(pxp->bf_rflags, RGN_MODIFIED))
514                        {
515                                /* page out lower half */
516                                assert(pxp->bf_refcount <= 0);
517                                status = px_pgout(nciop,
518                                        pxp->bf_offset,
519                                        pxp->blksz,
520                                        pxp->bf_base,
521                                        &pxp->pos);
522                                if(status != ENOERR)
523                                        return status;
524                        }
525                        pxp->bf_cnt -= pxp->blksz;
526                        /* copy upper half into lower half */
527                        (void) memcpy(pxp->bf_base, middle, pxp->bf_cnt);
528                }
529                else            /* added to fix nofill bug */
530                {
531                        assert(pxp->bf_extent == 2 * pxp->blksz);
532                        /* still have to page out lower half, if modified */
533                        if(fIsSet(pxp->bf_rflags, RGN_MODIFIED))
534                        {
535                                assert(pxp->bf_refcount <= 0);
536                                status = px_pgout(nciop,
537                                        pxp->bf_offset,
538                                        pxp->blksz,
539                                        pxp->bf_base,
540                                        &pxp->pos);
541                                if(status != ENOERR)
542                                        return status;
543                        }
544                }
545                pxp->bf_offset = blkoffset;
546                /* pxp->bf_extent = pxp->blksz; */
547
548                assert(blkextent == 2 * pxp->blksz);
549                {
550                        /* page in upper */
551                        void *const middle =
552                                (void *)((char *)pxp->bf_base + pxp->blksz);
553                        status = px_pgin(nciop,
554                                 pxp->bf_offset + (off_t)pxp->blksz,
555                                 pxp->blksz,
556                                 middle,
557                                 &pxp->bf_cnt,
558                                 &pxp->pos);
559                        if(status != ENOERR)
560                                return status;
561                        pxp->bf_extent = 2 * pxp->blksz;
562                        pxp->bf_cnt += pxp->blksz;
563                }
564                goto done;
565        }
566        /* else */
567
568        if(blkoffset == pxp->bf_offset - (off_t)pxp->blksz)
569        {
570                /* wants the page below */
571                void *const middle =
572                        (void *)((char *)pxp->bf_base + pxp->blksz);
573                size_t upper_cnt = 0;
574                if(pxp->bf_cnt > pxp->blksz)
575                {
576                        /* data in upper half */
577                        assert(pxp->bf_extent == 2 * pxp->blksz);
578                        if(fIsSet(pxp->bf_rflags, RGN_MODIFIED))
579                        {
580                                /* page out upper half */
581                                assert(pxp->bf_refcount <= 0);
582                                status = px_pgout(nciop,
583                                        pxp->bf_offset + (off_t)pxp->blksz,
584                                        pxp->bf_cnt - pxp->blksz,
585                                        middle,
586                                        &pxp->pos);
587                                if(status != ENOERR)
588                                        return status;
589                        }
590                        pxp->bf_cnt = pxp->blksz;
591                        pxp->bf_extent = pxp->blksz;
592                }
593                if(pxp->bf_cnt > 0)
594                {
595                        /* copy lower half into upper half */
596                        (void) memcpy(middle, pxp->bf_base, pxp->blksz);
597                        upper_cnt = pxp->bf_cnt;
598                }
599                /* read page below into lower half */
600                status = px_pgin(nciop,
601                         blkoffset,
602                         pxp->blksz,
603                         pxp->bf_base,
604                         &pxp->bf_cnt,
605                         &pxp->pos);
606                if(status != ENOERR)
607                        return status;
608                pxp->bf_offset = blkoffset;
609                if(upper_cnt != 0)
610                {
611                        pxp->bf_extent = 2 * pxp->blksz;
612                        pxp->bf_cnt = pxp->blksz + upper_cnt;
613                }
614                else
615                {
616                        pxp->bf_extent = pxp->blksz;
617                }
618                goto done;
619        }
620        /* else */
621
622        /* no overlap */
623        if(fIsSet(pxp->bf_rflags, RGN_MODIFIED))
624        {
625                assert(pxp->bf_refcount <= 0);
626                status = px_pgout(nciop,
627                        pxp->bf_offset,
628                        pxp->bf_cnt,
629                        pxp->bf_base,
630                        &pxp->pos);
631                if(status != ENOERR)
632                        return status;
633                pxp->bf_rflags = 0;
634        }
635
636pgin:
637        status = px_pgin(nciop,
638                 blkoffset,
639                 blkextent,
640                 pxp->bf_base,
641                 &pxp->bf_cnt,
642                 &pxp->pos);
643        if(status != ENOERR)
644                return status;
645         pxp->bf_offset = blkoffset;
646         pxp->bf_extent = blkextent;
647
648done:
649        extent += diff;
650        if(pxp->bf_cnt < extent)
651                pxp->bf_cnt = extent;
652        assert(pxp->bf_cnt <= pxp->bf_extent);
653
654        pxp->bf_rflags |= rflags;
655        pxp->bf_refcount++;
656
657        *vpp = (char *)pxp->bf_base + diff;
658        return ENOERR;
659}
660
661/* Request that the region (offset, extent) be made available through
662   *vpp.
663
664   This function converts a file region specified by an offset and
665   extent to a memory pointer. The region may be locked until the
666   corresponding call to rel().
667
668   For POSIX systems, without NC_SHARE. This function gets a page of
669   size extent?
670
671   This is a wrapper for the function px_get, which does all the heavy
672   lifting.
673
674   nciop - pointer to ncio struct for this file.
675   offset - offset (from beginning of file?) to the data we want to
676   read.
677   extent - the number of bytes to read from the file.
678   rflags - One of the RGN_* flags defined in ncio.h.
679   vpp - handle to point at data when it's been read.
680*/
681static int
682ncio_px_get(ncio *const nciop, 
683                off_t offset, size_t extent,
684                int rflags,
685                void **const vpp)
686{
687        ncio_px *const pxp = (ncio_px *)nciop->pvt;
688       
689        if(fIsSet(rflags, RGN_WRITE) && !fIsSet(nciop->ioflags, NC_WRITE))
690                return EPERM; /* attempt to write readonly file */
691
692        /* reclaim space used in move */
693        if(pxp->slave != NULL)
694        {
695                if(pxp->slave->bf_base != NULL)
696                {
697                        free(pxp->slave->bf_base);
698                        pxp->slave->bf_base = NULL;
699                        pxp->slave->bf_extent = 0;
700                        pxp->slave->bf_offset = OFF_NONE;
701                }
702                free(pxp->slave);
703                pxp->slave = NULL;
704        }
705        return px_get(nciop, pxp, offset, extent, rflags, vpp);
706}
707
708
709/* ARGSUSED */
710static int
711px_double_buffer(ncio *const nciop, off_t to, off_t from,
712                        size_t nbytes, int rflags)
713{
714        ncio_px *const pxp = (ncio_px *)nciop->pvt;
715        int status = ENOERR;
716        void *src;
717        void *dest;
718       
719#if INSTRUMENT
720fprintf(stderr, "\tdouble_buffr %ld %ld %ld\n",
721                 (long)to, (long)from, (long)nbytes);
722#endif
723        status = px_get(nciop, pxp, to, nbytes, RGN_WRITE,
724                        &dest);
725        if(status != ENOERR)
726                return status;
727
728        if(pxp->slave == NULL)
729        {
730                pxp->slave = (ncio_px *) malloc(sizeof(ncio_px));
731                if(pxp->slave == NULL)
732                        return ENOMEM;
733
734                pxp->slave->blksz = pxp->blksz;
735                /* pos done below */
736                pxp->slave->bf_offset = pxp->bf_offset; 
737                pxp->slave->bf_extent = pxp->bf_extent;
738                pxp->slave->bf_cnt = pxp->bf_cnt;
739                pxp->slave->bf_base = malloc(2 * pxp->blksz);
740                if(pxp->slave->bf_base == NULL)
741                        return ENOMEM;
742                (void) memcpy(pxp->slave->bf_base, pxp->bf_base,
743                         pxp->bf_extent);
744                pxp->slave->bf_rflags = 0;
745                pxp->slave->bf_refcount = 0;
746                pxp->slave->slave = NULL;
747        }
748       
749        pxp->slave->pos = pxp->pos;
750        status = px_get(nciop, pxp->slave, from, nbytes, 0,
751                        &src);
752        if(status != ENOERR)
753                return status;
754        if(pxp->pos != pxp->slave->pos)
755        {
756                /* position changed, sync */
757                pxp->pos = pxp->slave->pos;
758        }
759
760        (void) memcpy(dest, src, nbytes);
761
762        (void)px_rel(pxp->slave, from, 0);
763        (void)px_rel(pxp, to, RGN_MODIFIED);
764       
765        return status;
766}
767
768/* Like memmove(), safely move possibly overlapping data.
769
770   Copy one region to another without making anything available to
771   higher layers. May be just implemented in terms of get() and rel(),
772   or may be tricky to be efficient. Only used in by nc_enddef()
773   after redefinition.
774
775   nciop - pointer to ncio struct with file info.
776   to - src for move?
777   from - dest for move?
778   nbytes - number of bytes to move.
779   rflags - One of the RGN_* flags defined in ncio.h. The only
780   reasonable flag value is RGN_NOLOCK.
781*/
782static int
783ncio_px_move(ncio *const nciop, off_t to, off_t from,
784                        size_t nbytes, int rflags)
785{
786        ncio_px *const pxp = (ncio_px *)nciop->pvt;
787        int status = ENOERR;
788        off_t lower;   
789        off_t upper;
790        char *base;
791        size_t diff;
792        size_t extent;
793
794        if(to == from)
795                return ENOERR; /* NOOP */
796       
797        if(fIsSet(rflags, RGN_WRITE) && !fIsSet(nciop->ioflags, NC_WRITE))
798                return EPERM; /* attempt to write readonly file */
799
800        rflags &= RGN_NOLOCK; /* filter unwanted flags */
801
802        if(to > from)
803        {
804                /* growing */
805                lower = from;   
806                upper = to;
807        }
808        else
809        {
810                /* shrinking */
811                lower = to;
812                upper = from;
813        }
814        diff = (size_t)(upper - lower);
815        extent = diff + nbytes;
816
817#if INSTRUMENT
818fprintf(stderr, "ncio_px_move %ld %ld %ld %ld %ld\n",
819                 (long)to, (long)from, (long)nbytes, (long)lower, (long)extent);
820#endif
821        if(extent > pxp->blksz)
822        {
823                size_t remaining = nbytes;
824
825if(to > from)
826{
827                off_t frm = from + nbytes;
828                off_t toh = to + nbytes;
829                for(;;)
830                {
831                        size_t loopextent = MIN(remaining, pxp->blksz);
832                        frm -= loopextent;
833                        toh -= loopextent;
834
835                        status = px_double_buffer(nciop, toh, frm,
836                                        loopextent, rflags) ;
837                        if(status != ENOERR)
838                                return status;
839                        remaining -= loopextent;
840
841                        if(remaining == 0)
842                                break; /* normal loop exit */
843                }
844}
845else
846{
847                for(;;)
848                {
849                        size_t loopextent = MIN(remaining, pxp->blksz);
850
851                        status = px_double_buffer(nciop, to, from,
852                                        loopextent, rflags) ;
853                        if(status != ENOERR)
854                                return status;
855                        remaining -= loopextent;
856
857                        if(remaining == 0)
858                                break; /* normal loop exit */
859                        to += loopextent;
860                        from += loopextent;
861                }
862}
863                return ENOERR;
864        }
865       
866#if INSTRUMENT
867fprintf(stderr, "\tncio_px_move small\n");
868#endif
869        status = px_get(nciop, pxp, lower, extent, RGN_WRITE|rflags,
870                        (void **)&base);
871
872        if(status != ENOERR)
873                return status;
874
875        if(to > from)
876                (void) memmove(base + diff, base, nbytes); 
877        else
878                (void) memmove(base, base + diff, nbytes); 
879               
880        (void) px_rel(pxp, lower, RGN_MODIFIED);
881
882        return status;
883}
884
885
886/* Flush any buffers to disk. May be a no-op on if I/O is unbuffered.
887   This function is used when NC_SHARE is NOT used.
888*/
889static int
890ncio_px_sync(ncio *const nciop)
891{
892        ncio_px *const pxp = (ncio_px *)nciop->pvt;
893        int status = ENOERR;
894        if(fIsSet(pxp->bf_rflags, RGN_MODIFIED))
895        {
896                assert(pxp->bf_refcount <= 0);
897                status = px_pgout(nciop, pxp->bf_offset,
898                        pxp->bf_cnt,
899                        pxp->bf_base, &pxp->pos);
900                if(status != ENOERR)
901                        return status;
902                pxp->bf_rflags = 0;
903        }
904        else if (!fIsSet(pxp->bf_rflags, RGN_WRITE))
905        {
906            /*
907             * The dataset is readonly.  Invalidate the buffers so
908             * that the next ncio_px_get() will actually read data.
909             */
910            pxp->bf_offset = OFF_NONE;
911            pxp->bf_cnt = 0;
912        }
913        return status;
914}
915
916/* Internal function called at close to
917   free up anything hanging off pvt.
918*/
919static void
920ncio_px_freepvt(void *const pvt)
921{
922        ncio_px *const pxp = (ncio_px *)pvt;
923        if(pxp == NULL)
924                return;
925
926        if(pxp->slave != NULL)
927        {
928                if(pxp->slave->bf_base != NULL)
929                {
930                        free(pxp->slave->bf_base);
931                        pxp->slave->bf_base = NULL;
932                        pxp->slave->bf_extent = 0;
933                        pxp->slave->bf_offset = OFF_NONE;
934                }
935                free(pxp->slave);
936                pxp->slave = NULL;
937        }
938               
939        if(pxp->bf_base != NULL)
940        {
941                free(pxp->bf_base);
942                pxp->bf_base = NULL;
943                pxp->bf_extent = 0;
944                pxp->bf_offset = OFF_NONE;
945        }
946}
947
948
949/* This is the second half of the ncio initialization. This is called
950   after the file has actually been opened.
951
952   The most important thing that happens is the allocation of a block
953   of memory at pxp->bf_base. This is going to be twice the size of
954   the chunksizehint (rounded up to the nearest sizeof(double)) passed
955   in from nc__create or nc__open. The rounded chunksizehint (passed
956   in here in sizehintp) is going to be stored as pxp->blksize.
957
958   According to our "contract" we are not allowed to ask for an extent
959   larger than this chunksize/sizehint/blksize from the ncio get
960   function.
961
962   nciop - pointer to the ncio struct
963   sizehintp - pointer to a size hint that will be rounded up and
964   passed back to the caller.
965   isNew - true if this is being called from ncio_create for a new
966   file.
967*/
968static int
969ncio_px_init2(ncio *const nciop, size_t *sizehintp, int isNew)
970{
971        ncio_px *const pxp = (ncio_px *)nciop->pvt;
972        const size_t bufsz = 2 * *sizehintp;
973
974        assert(nciop->fd >= 0);
975
976        pxp->blksz = *sizehintp;
977
978        assert(pxp->bf_base == NULL);
979
980        /* this is separate allocation because it may grow */
981        pxp->bf_base = malloc(bufsz);
982        if(pxp->bf_base == NULL)
983                return ENOMEM;
984        /* else */
985        pxp->bf_cnt = 0;
986        if(isNew)
987        {
988                /* save a read */
989                pxp->pos = 0;
990                pxp->bf_offset = 0;
991                pxp->bf_extent = bufsz;
992                (void) memset(pxp->bf_base, 0, pxp->bf_extent);
993        }
994        return ENOERR;
995}
996
997
998/* This is the first of a two-part initialization of the ncio struct.
999   Here the rel, get, move, sync, and free function pointers are set
1000   to their POSIX non-NC_SHARE functions (ncio_px_*).
1001
1002   The ncio_px struct is also partially initialized.
1003*/
1004static void
1005ncio_px_init(ncio *const nciop)
1006{
1007        ncio_px *const pxp = (ncio_px *)nciop->pvt;
1008
1009        *((ncio_relfunc **)&nciop->rel) = ncio_px_rel; /* cast away const */
1010        *((ncio_getfunc **)&nciop->get) = ncio_px_get; /* cast away const */
1011        *((ncio_movefunc **)&nciop->move) = ncio_px_move; /* cast away const */
1012        *((ncio_syncfunc **)&nciop->sync) = ncio_px_sync; /* cast away const */
1013        *((ncio_filesizefunc **)&nciop->filesize) = ncio_px_filesize; /* cast away const */
1014        *((ncio_pad_lengthfunc **)&nciop->pad_length) = ncio_px_pad_length; /* cast away const */
1015        *((ncio_closefunc **)&nciop->close) = ncio_px_close; /* cast away const */
1016
1017        pxp->blksz = 0;
1018        pxp->pos = -1;
1019        pxp->bf_offset = OFF_NONE;
1020        pxp->bf_extent = 0;
1021        pxp->bf_rflags = 0;
1022        pxp->bf_refcount = 0;
1023        pxp->bf_base = NULL;
1024        pxp->slave = NULL;
1025
1026}
1027
1028/* Begin spx */
1029
1030/* This is the struct that gets hung of ncio->pvt(?) when the NC_SHARE
1031   flag is used.
1032*/
1033typedef struct ncio_spx {
1034        off_t pos;
1035        /* buffer */
1036        off_t   bf_offset; 
1037        size_t  bf_extent;
1038        size_t  bf_cnt;
1039        void    *bf_base;
1040} ncio_spx;
1041
1042
1043/*ARGSUSED*/
1044/* This function releases the region specified by offset.
1045
1046   For POSIX system, with NC_SHARE, this becomes the rel function
1047   pointed to by the ncio rel function pointer. It mearly checks for
1048   file write permission, then calls px_rel to do everything.
1049
1050   nciop - pointer to ncio struct.
1051
1052   offset - beginning of region.
1053
1054   rflags - One of the RGN_* flags defined in ncio.h. If set to
1055   RGN_MODIFIED it means that the data in this region were modified,
1056   and it needs to be written out to the disk immediately (since we
1057   are not buffering with NC_SHARE on).
1058
1059*/
1060static int
1061ncio_spx_rel(ncio *const nciop, off_t offset, int rflags)
1062{
1063        ncio_spx *const pxp = (ncio_spx *)nciop->pvt;
1064        int status = ENOERR;
1065
1066        assert(pxp->bf_offset <= offset);
1067        assert(pxp->bf_cnt != 0);
1068        assert(pxp->bf_cnt <= pxp->bf_extent);
1069#ifdef X_ALIGN
1070        assert(offset < pxp->bf_offset + X_ALIGN);
1071        assert(pxp->bf_cnt % X_ALIGN == 0 );
1072#endif
1073
1074        if(fIsSet(rflags, RGN_MODIFIED))
1075        {
1076                if(!fIsSet(nciop->ioflags, NC_WRITE))
1077                        return EPERM; /* attempt to write readonly file */
1078
1079                status = px_pgout(nciop, pxp->bf_offset,
1080                        pxp->bf_cnt,
1081                        pxp->bf_base, &pxp->pos);
1082                /* if error, invalidate buffer anyway */
1083        }
1084        pxp->bf_offset = OFF_NONE;
1085        pxp->bf_cnt = 0;
1086        return status;
1087}
1088
1089
1090/* Request that the region (offset, extent) be made available through
1091   *vpp.
1092
1093   This function converts a file region specified by an offset and
1094   extent to a memory pointer. The region may be locked until the
1095   corresponding call to rel().
1096
1097   For POSIX systems, with NC_SHARE.
1098
1099   nciop - pointer to ncio struct for this file.
1100   offset - offset (from beginning of file?) to the data we want to
1101   read.
1102   extent - the number of bytes we want.
1103   rflags - One of the RGN_* flags defined in ncio.h. May be RGN_NOLOCK.
1104   vpp - handle to point at data when it's been read.
1105*/
1106static int
1107ncio_spx_get(ncio *const nciop,
1108                off_t offset, size_t extent,
1109                int rflags,
1110                void **const vpp)
1111{
1112        ncio_spx *const pxp = (ncio_spx *)nciop->pvt;
1113        int status = ENOERR;
1114#ifdef X_ALIGN
1115        size_t rem;
1116#endif
1117       
1118        if(fIsSet(rflags, RGN_WRITE) && !fIsSet(nciop->ioflags, NC_WRITE))
1119                return EPERM; /* attempt to write readonly file */
1120
1121        assert(extent != 0);
1122        assert(extent < X_INT_MAX); /* sanity check */
1123
1124        assert(pxp->bf_cnt == 0);
1125
1126#ifdef X_ALIGN
1127        rem = (size_t)(offset % X_ALIGN);
1128        if(rem != 0)
1129        {
1130                offset -= rem;
1131                extent += rem;
1132        }
1133
1134        {
1135                const size_t rndup = extent % X_ALIGN;
1136                if(rndup != 0)
1137                        extent += X_ALIGN - rndup;
1138        }
1139
1140        assert(offset % X_ALIGN == 0);
1141        assert(extent % X_ALIGN == 0);
1142#endif
1143
1144        if(pxp->bf_extent < extent)
1145        {
1146                if(pxp->bf_base != NULL)
1147                {
1148                        free(pxp->bf_base);
1149                        pxp->bf_base = NULL;
1150                        pxp->bf_extent = 0;
1151                }
1152                assert(pxp->bf_extent == 0);
1153                pxp->bf_base = malloc(extent);
1154                if(pxp->bf_base == NULL)
1155                        return ENOMEM;
1156                pxp->bf_extent = extent;
1157        }
1158
1159        status = px_pgin(nciop, offset,
1160                 extent,
1161                 pxp->bf_base,
1162                 &pxp->bf_cnt, &pxp->pos);
1163        if(status != ENOERR)
1164                return status;
1165
1166        pxp->bf_offset = offset;
1167
1168        if(pxp->bf_cnt < extent)
1169                pxp->bf_cnt = extent;
1170
1171#ifdef X_ALIGN
1172        *vpp = (char *)pxp->bf_base + rem;
1173#else
1174        *vpp = pxp->bf_base;
1175#endif
1176        return ENOERR;
1177}
1178
1179
1180#if 0
1181/*ARGSUSED*/
1182static int
1183strategy(ncio *const nciop, off_t to, off_t offset,
1184                        size_t extent, int rflags)
1185{
1186        static ncio_spx pxp[1];
1187        int status = ENOERR;
1188#ifdef X_ALIGN
1189        size_t rem;
1190#endif
1191       
1192        assert(extent != 0);
1193        assert(extent < X_INT_MAX); /* sanity check */
1194#if INSTRUMENT
1195fprintf(stderr, "strategy %ld at %ld to %ld\n",
1196         (long)extent, (long)offset, (long)to);
1197#endif
1198
1199
1200#ifdef X_ALIGN
1201        rem = (size_t)(offset % X_ALIGN);
1202        if(rem != 0)
1203        {
1204                offset -= rem;
1205                extent += rem;
1206        }
1207
1208        {
1209                const size_t rndup = extent % X_ALIGN;
1210                if(rndup != 0)
1211                        extent += X_ALIGN - rndup;
1212        }
1213
1214        assert(offset % X_ALIGN == 0);
1215        assert(extent % X_ALIGN == 0);
1216#endif
1217
1218        if(pxp->bf_extent < extent)
1219        {
1220                if(pxp->bf_base != NULL)
1221                {
1222                        free(pxp->bf_base);
1223                        pxp->bf_base = NULL;
1224                        pxp->bf_extent = 0;
1225                }
1226                assert(pxp->bf_extent == 0);
1227                pxp->bf_base = malloc(extent);
1228                if(pxp->bf_base == NULL)
1229                        return ENOMEM;
1230                pxp->bf_extent = extent;
1231        }
1232
1233        status = px_pgin(nciop, offset,
1234                 extent,
1235                 pxp->bf_base,
1236                 &pxp->bf_cnt, &pxp->pos);
1237        if(status != ENOERR)
1238                return status;
1239
1240        pxp->bf_offset = to; /* TODO: XALIGN */
1241       
1242        if(pxp->bf_cnt < extent)
1243                pxp->bf_cnt = extent;
1244
1245        status = px_pgout(nciop, pxp->bf_offset,
1246                pxp->bf_cnt,
1247                pxp->bf_base, &pxp->pos);
1248        /* if error, invalidate buffer anyway */
1249        pxp->bf_offset = OFF_NONE;
1250        pxp->bf_cnt = 0;
1251        return status;
1252}
1253#endif
1254
1255/* Copy one region to another without making anything available to
1256   higher layers. May be just implemented in terms of get() and rel(),
1257   or may be tricky to be efficient.  Only used in by nc_enddef()
1258   after redefinition.
1259
1260   nciop - pointer to ncio struct for this file.
1261   to - dest for move?
1262   from - src for move?
1263   nbytes - number of bytes to move.
1264   rflags - One of the RGN_* flags defined in ncio.h.
1265*/
1266static int
1267ncio_spx_move(ncio *const nciop, off_t to, off_t from,
1268                        size_t nbytes, int rflags)
1269{
1270        int status = ENOERR;
1271        off_t lower = from;     
1272        off_t upper = to;
1273        char *base;
1274        size_t diff;
1275        size_t extent;
1276
1277        rflags &= RGN_NOLOCK; /* filter unwanted flags */
1278
1279        if(to == from)
1280                return ENOERR; /* NOOP */
1281       
1282        if(to > from)
1283        {
1284                /* growing */
1285                lower = from;   
1286                upper = to;
1287        }
1288        else
1289        {
1290                /* shrinking */
1291                lower = to;
1292                upper = from;
1293        }
1294
1295        diff = (size_t)(upper - lower);
1296        extent = diff + nbytes;
1297
1298        status = ncio_spx_get(nciop, lower, extent, RGN_WRITE|rflags,
1299                        (void **)&base);
1300
1301        if(status != ENOERR)
1302                return status;
1303
1304        if(to > from)
1305                (void) memmove(base + diff, base, nbytes); 
1306        else
1307                (void) memmove(base, base + diff, nbytes); 
1308               
1309        (void) ncio_spx_rel(nciop, lower, RGN_MODIFIED);
1310
1311        return status;
1312}
1313
1314
1315/*ARGSUSED*/
1316/* Flush any buffers to disk. May be a no-op on if I/O is unbuffered.
1317*/
1318static int
1319ncio_spx_sync(ncio *const nciop)
1320{
1321        /* NOOP */
1322        return ENOERR;
1323}
1324
1325static void
1326ncio_spx_freepvt(void *const pvt)
1327{
1328        ncio_spx *const pxp = (ncio_spx *)pvt;
1329        if(pxp == NULL)
1330                return;
1331
1332        if(pxp->bf_base != NULL)
1333        {
1334                free(pxp->bf_base);
1335                pxp->bf_base = NULL;
1336                pxp->bf_offset = OFF_NONE;
1337                pxp->bf_extent = 0;
1338                pxp->bf_cnt = 0;
1339        }
1340}
1341
1342
1343/* This does the second half of the ncio_spx struct initialization for
1344   POSIX systems, with NC_SHARE on.
1345
1346   nciop - pointer to ncio struct for this file. File has been opened.
1347   sizehintp - pointer to a size which will be rounded up to the
1348   nearest 8-byt boundary and then used as the max size "chunk" (or
1349   page) to read from the file.
1350*/
1351static int
1352ncio_spx_init2(ncio *const nciop, const size_t *const sizehintp)
1353{
1354        ncio_spx *const pxp = (ncio_spx *)nciop->pvt;
1355
1356        assert(nciop->fd >= 0);
1357
1358        pxp->bf_extent = *sizehintp;
1359
1360        assert(pxp->bf_base == NULL);
1361
1362        /* this is separate allocation because it may grow */
1363        pxp->bf_base = malloc(pxp->bf_extent);
1364        if(pxp->bf_base == NULL)
1365        {
1366                pxp->bf_extent = 0;
1367                return ENOMEM;
1368        }
1369        /* else */
1370        return ENOERR;
1371}
1372
1373
1374/* First half of init for ncio_spx struct, setting the rel, get, move,
1375   snyc, and free function pointers to the NC_SHARE versions of these
1376   functions (i.e. the ncio_spx_* functions).
1377*/
1378static void
1379ncio_spx_init(ncio *const nciop)
1380{
1381        ncio_spx *const pxp = (ncio_spx *)nciop->pvt;
1382
1383        *((ncio_relfunc **)&nciop->rel) = ncio_spx_rel; /* cast away const */
1384        *((ncio_getfunc **)&nciop->get) = ncio_spx_get; /* cast away const */
1385        *((ncio_movefunc **)&nciop->move) = ncio_spx_move; /* cast away const */
1386        *((ncio_syncfunc **)&nciop->sync) = ncio_spx_sync; /* cast away const */
1387        /* shared with _px_ */
1388        *((ncio_filesizefunc **)&nciop->filesize) = ncio_px_filesize; /* cast away const */
1389        *((ncio_pad_lengthfunc **)&nciop->pad_length) = ncio_px_pad_length; /* cast away const */
1390        *((ncio_closefunc **)&nciop->close) = ncio_spx_close; /* cast away const */
1391
1392        pxp->pos = -1;
1393        pxp->bf_offset = OFF_NONE;
1394        pxp->bf_extent = 0;
1395        pxp->bf_cnt = 0;
1396        pxp->bf_base = NULL;
1397}
1398
1399
1400/* */
1401
1402/* This will call whatever free function is attached to the free
1403   function pointer in ncio. It's called from ncio_close, and from
1404   ncio_open and ncio_create when an error occurs that the file
1405   metadata must be freed.
1406*/
1407static void
1408ncio_px_free(ncio *nciop)
1409{
1410        if(nciop == NULL)
1411                return;
1412        if(nciop->pvt != NULL)
1413                ncio_px_freepvt(nciop->pvt);
1414        free(nciop);
1415}
1416
1417static void
1418ncio_spx_free(ncio *nciop)
1419{
1420        if(nciop == NULL)
1421                return;
1422        if(nciop->pvt != NULL)
1423                ncio_spx_freepvt(nciop->pvt);
1424        free(nciop);
1425}
1426
1427
1428/* Create a new ncio struct to hold info about the file. This will
1429   create and init the ncio_px or ncio_spx struct (the latter if
1430   NC_SHARE is used.)
1431*/
1432static ncio *
1433ncio_px_new(const char *path, int ioflags)
1434{
1435        size_t sz_ncio = M_RNDUP(sizeof(ncio));
1436        size_t sz_path = M_RNDUP(strlen(path) +1);
1437        size_t sz_ncio_pvt;
1438        ncio *nciop;
1439 
1440#if ALWAYS_NC_SHARE /* DEBUG */
1441        fSet(ioflags, NC_SHARE);
1442#endif
1443
1444        if(fIsSet(ioflags, NC_SHARE))
1445                sz_ncio_pvt = sizeof(ncio_spx);
1446        else
1447                sz_ncio_pvt = sizeof(ncio_px);
1448
1449        nciop = (ncio *) malloc(sz_ncio + sz_path + sz_ncio_pvt);
1450        if(nciop == NULL)
1451                return NULL;
1452       
1453        nciop->ioflags = ioflags;
1454        *((int *)&nciop->fd) = -1; /* cast away const */
1455
1456        nciop->path = (char *) ((char *)nciop + sz_ncio);
1457        (void) strcpy((char *)nciop->path, path); /* cast away const */
1458
1459                                /* cast away const */
1460        *((void **)&nciop->pvt) = (void *)(nciop->path + sz_path);
1461
1462        if(fIsSet(ioflags, NC_SHARE))
1463                ncio_spx_init(nciop);
1464        else
1465                ncio_px_init(nciop);
1466
1467        return nciop;
1468}
1469
1470
1471/* Public below this point */
1472#ifndef NCIO_MINBLOCKSIZE
1473#define NCIO_MINBLOCKSIZE 256
1474#endif
1475#ifndef NCIO_MAXBLOCKSIZE
1476#define NCIO_MAXBLOCKSIZE 268435456 /* sanity check, about X_SIZE_T_MAX/8 */
1477#endif
1478
1479#ifdef S_IRUSR
1480#define NC_DEFAULT_CREAT_MODE \
1481        (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH) /* 0666 */
1482
1483#else
1484#define NC_DEFAULT_CREAT_MODE 0666
1485#endif
1486
1487/* Create a file, and the ncio struct to go with it. This funtion is
1488   only called from nc__create_mp.
1489
1490   path - path of file to create.
1491   ioflags - flags from nc_create
1492   initialsz - From the netcdf man page: "The argument
1493   Iinitialsize sets the initial size of the file at creation time."
1494   igeto -
1495   igetsz -
1496   sizehintp - this eventually goes into pxp->blksz and is the size of
1497   a page of data for buffered reads and writes.
1498   nciopp - pointer to a pointer that will get location of newly
1499   created and inited ncio struct.
1500   igetvpp - pointer to pointer which will get the location of ?
1501*/
1502int
1503posixio_create(const char *path, int ioflags,
1504        size_t initialsz,
1505        off_t igeto, size_t igetsz, size_t *sizehintp,
1506        ncio **nciopp, void **const igetvpp)
1507{
1508        ncio *nciop;
1509        int oflags = (O_RDWR|O_CREAT);
1510        int fd;
1511        int status;
1512
1513        if(initialsz < (size_t)igeto + igetsz)
1514                initialsz = (size_t)igeto + igetsz;
1515
1516        fSet(ioflags, NC_WRITE);
1517
1518        if(path == NULL || *path == 0)
1519                return EINVAL;
1520
1521        nciop = ncio_px_new(path, ioflags);
1522        if(nciop == NULL)
1523                return ENOMEM;
1524
1525        if(fIsSet(ioflags, NC_NOCLOBBER))
1526                fSet(oflags, O_EXCL);
1527        else
1528                fSet(oflags, O_TRUNC);
1529#ifdef O_BINARY
1530        fSet(oflags, O_BINARY);
1531#endif
1532#ifdef vms
1533        fd = open(path, oflags, NC_DEFAULT_CREAT_MODE, "ctx=stm");
1534#else
1535        /* Should we mess with the mode based on NC_SHARE ?? */
1536        fd = open(path, oflags, NC_DEFAULT_CREAT_MODE);
1537#endif
1538#if 0
1539        (void) fprintf(stderr, "ncio_create(): path=\"%s\"\n", path);
1540        (void) fprintf(stderr, "ncio_create(): oflags=0x%x\n", oflags);
1541#endif
1542        if(fd < 0)
1543        {
1544                status = errno;
1545                goto unwind_new;
1546        }
1547        *((int *)&nciop->fd) = fd; /* cast away const */
1548
1549        if(*sizehintp < NCIO_MINBLOCKSIZE)
1550        {
1551                /* Use default */
1552                *sizehintp = blksize(fd);
1553        }
1554        else if(*sizehintp >= NCIO_MAXBLOCKSIZE)
1555        {
1556                /* Use maximum allowed value */
1557                *sizehintp = NCIO_MAXBLOCKSIZE;
1558        }
1559        else
1560        {
1561                *sizehintp = M_RNDUP(*sizehintp);
1562        }
1563
1564        if(fIsSet(nciop->ioflags, NC_SHARE))
1565                status = ncio_spx_init2(nciop, sizehintp);
1566        else
1567                status = ncio_px_init2(nciop, sizehintp, 1);
1568
1569        if(status != ENOERR)
1570                goto unwind_open;
1571
1572        if(initialsz != 0)
1573        {
1574                status = fgrow(fd, (off_t)initialsz);
1575                if(status != ENOERR)
1576                        goto unwind_open;
1577        }
1578
1579        if(igetsz != 0)
1580        {
1581                status = nciop->get(nciop,
1582                                igeto, igetsz,
1583                                RGN_WRITE,
1584                                igetvpp);
1585                if(status != ENOERR)
1586                        goto unwind_open;
1587        }
1588
1589        *nciopp = nciop;
1590        return ENOERR;
1591
1592unwind_open:
1593        (void) close(fd);
1594        /* ?? unlink */
1595        /*FALLTHRU*/
1596unwind_new:
1597        ncio_close(nciop,!fIsSet(ioflags, NC_NOCLOBBER));
1598        return status;
1599}
1600
1601
1602/* This function opens the data file. It is only called from nc.c,
1603   from nc__open_mp and nc_delete_mp.
1604
1605   path - path of data file.
1606
1607   ioflags - flags passed into nc_open.
1608   
1609   igeto - looks like this function can do an initial page get, and
1610   igeto is going to be the offset for that. But it appears to be
1611   unused
1612
1613   igetsz - the size in bytes of initial page get (a.k.a. extent). Not
1614   ever used in the library.
1615   
1616   sizehintp - pointer to sizehint parameter from nc__open or
1617   nc__create. This is used to set pxp->blksz.
1618   
1619   Here's what the man page has to say:
1620
1621   "The argument referenced by chunksize controls a space versus time
1622   tradeoff, memory allocated in the netcdf library versus number of
1623   system calls.
1624
1625   Because of internal requirements, the value may not be set to
1626   exactly the value requested. The actual value chosen is returned by reference.
1627
1628   Using the value NC_SIZEHINT_DEFAULT causes the library to choose a
1629   default. How the system choses the default depends on the
1630   system. On many systems, the "preferred I/O block size" is
1631   available from the stat() system call, struct stat member
1632   st_blksize. If this is available it is used. Lacking that, twice
1633   the system pagesize is used. Lacking a call to discover the system
1634   pagesize, we just set default chunksize to 8192.
1635
1636   The chunksize is a property of a given open netcdf descriptor ncid,
1637   it is not a persistent property of the netcdf dataset."
1638
1639   nciopp - pointer to pointer that will get address of newly created
1640   and inited ncio struct.
1641
1642   igetvpp - handle to pass back pointer to data from inital page
1643   read, if this were ever used, which it isn't.
1644*/
1645int
1646posixio_open(const char *path,
1647        int ioflags,
1648        off_t igeto, size_t igetsz, size_t *sizehintp,
1649        ncio **nciopp, void **const igetvpp)
1650{
1651        ncio *nciop;
1652        int oflags = fIsSet(ioflags, NC_WRITE) ? O_RDWR : O_RDONLY;
1653        int fd;
1654        int status;
1655
1656        if(path == NULL || *path == 0)
1657                return EINVAL;
1658
1659        nciop = ncio_px_new(path, ioflags);
1660        if(nciop == NULL)
1661                return ENOMEM;
1662
1663#ifdef O_BINARY
1664        fSet(oflags, O_BINARY);
1665#endif
1666#ifdef vms
1667        fd = open(path, oflags, 0, "ctx=stm");
1668#else
1669        fd = open(path, oflags, 0);
1670#endif
1671        if(fd < 0)
1672        {
1673                status = errno;
1674                goto unwind_new;
1675        }
1676        *((int *)&nciop->fd) = fd; /* cast away const */
1677
1678        if(*sizehintp < NCIO_MINBLOCKSIZE)
1679        {
1680                /* Use default */
1681                *sizehintp = blksize(fd);
1682        }
1683        else if(*sizehintp >= NCIO_MAXBLOCKSIZE)
1684        {
1685                /* Use maximum allowed value */
1686                *sizehintp = NCIO_MAXBLOCKSIZE;
1687        }
1688        else
1689        {
1690                *sizehintp = M_RNDUP(*sizehintp);
1691        }
1692
1693        if(fIsSet(nciop->ioflags, NC_SHARE))
1694                status = ncio_spx_init2(nciop, sizehintp);
1695        else
1696                status = ncio_px_init2(nciop, sizehintp, 0);
1697
1698        if(status != ENOERR)
1699                goto unwind_open;
1700
1701        if(igetsz != 0)
1702        {
1703                status = nciop->get(nciop,
1704                                igeto, igetsz,
1705                                0,
1706                                igetvpp);
1707                if(status != ENOERR)
1708                        goto unwind_open;
1709        }
1710
1711        *nciopp = nciop;
1712        return ENOERR;
1713
1714unwind_open:
1715        (void) close(fd);
1716        /*FALLTHRU*/
1717unwind_new:
1718        ncio_close(nciop,0);
1719        return status;
1720}
1721
1722/*
1723 * Get file size in bytes.
1724 */
1725static int
1726ncio_px_filesize(ncio *nciop, off_t *filesizep)
1727{
1728    struct stat sb;
1729
1730    assert(nciop != NULL);
1731    if (fstat(nciop->fd, &sb) < 0)
1732        return errno;
1733    *filesizep = sb.st_size;
1734    return ENOERR;
1735}
1736
1737/*
1738 * Sync any changes to disk, then truncate or extend file so its size
1739 * is length.  This is only intended to be called before close, if the
1740 * file is open for writing and the actual size does not match the
1741 * calculated size, perhaps as the result of having been previously
1742 * written in NOFILL mode.
1743 */
1744static int
1745ncio_px_pad_length(ncio *nciop, off_t length)
1746{
1747        int status = ENOERR;
1748
1749        if(nciop == NULL)
1750                return EINVAL;
1751
1752        if(!fIsSet(nciop->ioflags, NC_WRITE))
1753                return EPERM; /* attempt to write readonly file */
1754
1755        status = nciop->sync(nciop);
1756        if(status != ENOERR)
1757                return status;
1758
1759        status = fgrow2(nciop->fd, length);
1760        if(status != ENOERR)
1761                return status;
1762        return ENOERR;
1763}
1764
1765
1766/* Write out any dirty buffers to disk and
1767   ensure that next read will get data from disk.
1768
1769   Sync any changes, then close the open file associated with the ncio
1770   struct, and free its memory.
1771   
1772   nciop - pointer to ncio to close.
1773
1774   doUnlink - if true, unlink file
1775*/
1776static int 
1777ncio_px_close(ncio *nciop, int doUnlink)
1778{
1779        int status = ENOERR;
1780        if(nciop == NULL)
1781                return EINVAL;
1782        status = nciop->sync(nciop);
1783        (void) close(nciop->fd);
1784        if(doUnlink)
1785                (void) unlink(nciop->path);
1786        ncio_px_free(nciop);
1787        return status;
1788}
1789
1790static int 
1791ncio_spx_close(ncio *nciop, int doUnlink)
1792{
1793        int status = ENOERR;
1794        if(nciop == NULL)
1795                return EINVAL;
1796        status = nciop->sync(nciop);
1797        (void) close(nciop->fd);
1798        if(doUnlink)
1799                (void) unlink(nciop->path);
1800        ncio_spx_free(nciop);
1801        return status;
1802}
Note: See TracBrowser for help on using the repository browser.