00001
00002
00003
00004
00005
00006
00007
00008 #include "ncconfig.h"
00009 #include <assert.h>
00010 #include <stdlib.h>
00011 #include <stdio.h>
00012 #include <errno.h>
00013 #ifndef ENOERR
00014 #define ENOERR 0
00015 #endif
00016 #include <fcntl.h>
00017 #include <ffio.h>
00018 #include <unistd.h>
00019 #include <string.h>
00020
00021 #include <fortran.h>
00022
00023 #include "ncio.h"
00024 #include "fbits.h"
00025 #include "rnd.h"
00026
00027 #if !defined(NDEBUG) && !defined(X_INT_MAX)
00028 #define X_INT_MAX 2147483647
00029 #endif
00030 #if 0
00031 #define X_ALIGN 4
00032 #endif
00033
00034 #define ALWAYS_NC_SHARE 0
00035
00036
00037
00038
00039
00040
00041
00042
00043 static size_t
00044 blksize(int fd)
00045 {
00046 struct ffc_stat_s sb;
00047 struct ffsw sw;
00048 if (fffcntl(fd, FC_STAT, &sb, &sw) > -1)
00049 {
00050 if(sb.st_oblksize > 0)
00051 return (size_t) sb.st_oblksize;
00052 }
00053
00054 return (size_t) 32768;
00055 }
00056
00057
00058
00059
00060
00061 static int
00062 fgrow(const int fd, const off_t len)
00063 {
00064 struct ffc_stat_s sb;
00065 struct ffsw sw;
00066 if (fffcntl(fd, FC_STAT, &sb, &sw) < 0)
00067 return errno;
00068 if (len < sb.st_size)
00069 return ENOERR;
00070 {
00071 const long dumb = 0;
00072
00073 const off_t pos = ffseek(fd, 0, SEEK_CUR);
00074 if(pos < 0)
00075 return errno;
00076 if (ffseek(fd, len-sizeof(dumb), SEEK_SET) < 0)
00077 return errno;
00078 if(ffwrite(fd, (void *)&dumb, sizeof(dumb)) < 0)
00079 return errno;
00080 if (ffseek(fd, pos, SEEK_SET) < 0)
00081 return errno;
00082 }
00083
00084 return ENOERR;
00085 }
00086
00087
00088
00089
00090 static int
00091 ffio_pgout(ncio *const nciop,
00092 off_t const offset, const size_t extent,
00093 const void *const vp, off_t *posp)
00094 {
00095 #ifdef X_ALIGN
00096 assert(offset % X_ALIGN == 0);
00097 assert(extent % X_ALIGN == 0);
00098 #endif
00099
00100 if(*posp != offset)
00101 {
00102 if(ffseek(nciop->fd, offset, SEEK_SET) != offset)
00103 {
00104 return errno;
00105 }
00106 *posp = offset;
00107 }
00108 if(ffwrite(nciop->fd, vp, extent) != extent)
00109 {
00110 return errno;
00111 }
00112 *posp += extent;
00113
00114 return ENOERR;
00115 }
00116
00117
00118 static int
00119 ffio_pgin(ncio *const nciop,
00120 off_t const offset, const size_t extent,
00121 void *const vp, size_t *nreadp, off_t *posp)
00122 {
00123 int status;
00124 ssize_t nread;
00125
00126 #ifdef X_ALIGN
00127 assert(offset % X_ALIGN == 0);
00128 assert(extent % X_ALIGN == 0);
00129 #endif
00130
00131 if(*posp != offset)
00132 {
00133 if(ffseek(nciop->fd, offset, SEEK_SET) != offset)
00134 {
00135 status = errno;
00136 return status;
00137 }
00138 *posp = offset;
00139 }
00140
00141 errno = 0;
00142 nread = ffread(nciop->fd, vp, extent);
00143 if(nread != extent)
00144 {
00145 status = errno;
00146 if(nread == -1 || status != ENOERR)
00147 return status;
00148
00149 }
00150 *nreadp = nread;
00151 *posp += nread;
00152
00153 return ENOERR;
00154 }
00155
00156
00157
00158 typedef struct ncio_ffio {
00159 off_t pos;
00160
00161 off_t bf_offset;
00162 size_t bf_extent;
00163 size_t bf_cnt;
00164 void *bf_base;
00165 } ncio_ffio;
00166
00167
00168 static int
00169 ncio_ffio_rel(ncio *const nciop, off_t offset, int rflags)
00170 {
00171 ncio_ffio *ffp = (ncio_ffio *)nciop->pvt;
00172 int status = ENOERR;
00173
00174 assert(ffp->bf_offset <= offset);
00175 assert(ffp->bf_cnt != 0);
00176 assert(ffp->bf_cnt <= ffp->bf_extent);
00177 #ifdef X_ALIGN
00178 assert(offset < ffp->bf_offset + X_ALIGN);
00179 assert(ffp->bf_cnt % X_ALIGN == 0 );
00180 #endif
00181
00182 if(fIsSet(rflags, RGN_MODIFIED))
00183 {
00184 if(!fIsSet(nciop->ioflags, NC_WRITE))
00185 return EPERM;
00186
00187 status = ffio_pgout(nciop, ffp->bf_offset,
00188 ffp->bf_cnt,
00189 ffp->bf_base, &ffp->pos);
00190
00191 }
00192 ffp->bf_offset = OFF_NONE;
00193 ffp->bf_cnt = 0;
00194 return status;
00195 }
00196
00197
00198 static int
00199 ncio_ffio_get(ncio *const nciop,
00200 off_t offset, size_t extent,
00201 int rflags,
00202 void **const vpp)
00203 {
00204 ncio_ffio *ffp = (ncio_ffio *)nciop->pvt;
00205 int status = ENOERR;
00206 #ifdef X_ALIGN
00207 size_t rem;
00208 #endif
00209
00210 if(fIsSet(rflags, RGN_WRITE) && !fIsSet(nciop->ioflags, NC_WRITE))
00211 return EPERM;
00212
00213 assert(extent != 0);
00214 assert(extent < X_INT_MAX);
00215 assert(offset < X_INT_MAX);
00216
00217 assert(ffp->bf_cnt == 0);
00218
00219 #ifdef X_ALIGN
00220
00221 rem = offset % X_ALIGN;
00222 if(rem != 0)
00223 {
00224 offset -= rem;
00225 extent += rem;
00226 }
00227
00228 {
00229 const size_t rndup = extent % X_ALIGN;
00230 if(rndup != 0)
00231 extent += X_ALIGN - rndup;
00232 }
00233
00234 assert(offset % X_ALIGN == 0);
00235 assert(extent % X_ALIGN == 0);
00236 #endif
00237
00238 if(ffp->bf_extent < extent)
00239 {
00240 if(ffp->bf_base != NULL)
00241 {
00242 free(ffp->bf_base);
00243 ffp->bf_base = NULL;
00244 ffp->bf_extent = 0;
00245 }
00246 assert(ffp->bf_extent == 0);
00247 ffp->bf_base = malloc(extent);
00248 if(ffp->bf_base == NULL)
00249 return ENOMEM;
00250 ffp->bf_extent = extent;
00251 }
00252
00253 status = ffio_pgin(nciop, offset,
00254 extent,
00255 ffp->bf_base,
00256 &ffp->bf_cnt, &ffp->pos);
00257 if(status != ENOERR)
00258 return status;
00259
00260 ffp->bf_offset = offset;
00261
00262 if(ffp->bf_cnt < extent)
00263 {
00264 (void) memset((char *)ffp->bf_base + ffp->bf_cnt, 0,
00265 extent - ffp->bf_cnt);
00266 ffp->bf_cnt = extent;
00267 }
00268
00269
00270 #ifdef X_ALIGN
00271 *vpp = (char *)ffp->bf_base + rem;
00272 #else
00273 *vpp = (char *)ffp->bf_base;
00274 #endif
00275 return ENOERR;
00276 }
00277
00278
00279 static int
00280 ncio_ffio_move(ncio *const nciop, off_t to, off_t from,
00281 size_t nbytes, int rflags)
00282 {
00283 int status = ENOERR;
00284 off_t lower = from;
00285 off_t upper = to;
00286 char *base;
00287 size_t diff = upper - lower;
00288 size_t extent = diff + nbytes;
00289
00290 rflags &= RGN_NOLOCK;
00291
00292 if(to == from)
00293 return ENOERR;
00294
00295 if(to > from)
00296 {
00297
00298 lower = from;
00299 upper = to;
00300 }
00301 else
00302 {
00303
00304 lower = to;
00305 upper = from;
00306 }
00307
00308 diff = upper - lower;
00309 extent = diff + nbytes;
00310
00311 status = ncio_ffio_get(nciop, lower, extent, RGN_WRITE|rflags,
00312 (void **)&base);
00313
00314 if(status != ENOERR)
00315 return status;
00316
00317 if(to > from)
00318 (void) memmove(base + diff, base, nbytes);
00319 else
00320 (void) memmove(base, base + diff, nbytes);
00321
00322 (void) ncio_ffio_rel(nciop, lower, RGN_MODIFIED);
00323
00324 return status;
00325 }
00326
00327 #ifdef NOFFFLUSH
00328
00329
00330
00331
00332 static int
00333 ncio_ffio_sync_noffflush(ncio *const nciop)
00334 {
00335 struct ffc_stat_s si;
00336 struct ffsw ffstatus;
00337
00338 if(fffcntl(nciop->fd, FC_STAT, &si, &ffstatus) < 0)
00339 return ffstatus.sw_error;
00340 return ENOERR;
00341 }
00342
00343
00344
00345 static int
00346 ncio_ffio_global_test(const char *ControlString)
00347 {
00348 if (strstr(ControlString,"global") != (char *) NULL) {
00349 return ~0;
00350 } else {
00351 return 0;
00352 }
00353 }
00354 #endif
00355
00356 static int
00357 ncio_ffio_sync(ncio *const nciop)
00358 {
00359 if(ffflush(nciop->fd) < 0)
00360 return errno;
00361 return ENOERR;
00362 }
00363
00364 static void
00365 ncio_ffio_free(void *const pvt)
00366 {
00367 ncio_ffio *ffp = (ncio_ffio *)pvt;
00368 if(ffp == NULL)
00369 return;
00370
00371 if(ffp->bf_base != NULL)
00372 {
00373 free(ffp->bf_base);
00374 ffp->bf_base = NULL;
00375 ffp->bf_offset = OFF_NONE;
00376 ffp->bf_extent = 0;
00377 ffp->bf_cnt = 0;
00378 }
00379 }
00380
00381
00382 static int
00383 ncio_ffio_init2(ncio *const nciop, size_t *sizehintp)
00384 {
00385 ncio_ffio *ffp = (ncio_ffio *)nciop->pvt;
00386
00387 assert(nciop->fd >= 0);
00388
00389 ffp->bf_extent = *sizehintp;
00390
00391 assert(ffp->bf_base == NULL);
00392
00393
00394 ffp->bf_base = malloc(ffp->bf_extent);
00395 if(ffp->bf_base == NULL)
00396 {
00397 ffp->bf_extent = 0;
00398 return ENOMEM;
00399 }
00400
00401 return ENOERR;
00402 }
00403
00404
00405 static void
00406 ncio_ffio_init(ncio *const nciop)
00407 {
00408 ncio_ffio *ffp = (ncio_ffio *)nciop->pvt;
00409
00410 *((ncio_relfunc **)&nciop->rel) = ncio_ffio_rel;
00411 *((ncio_getfunc **)&nciop->get) = ncio_ffio_get;
00412 *((ncio_movefunc **)&nciop->move) = ncio_ffio_move;
00413 *((ncio_syncfunc **)&nciop->sync) = ncio_ffio_sync;
00414 *((ncio_freefunc **)&nciop->free) = ncio_ffio_free;
00415
00416 ffp->pos = -1;
00417 ffp->bf_offset = OFF_NONE;
00418 ffp->bf_extent = 0;
00419 ffp->bf_cnt = 0;
00420 ffp->bf_base = NULL;
00421 }
00422
00423
00424
00425 static void
00426 ncio_free(ncio *nciop)
00427 {
00428 if(nciop == NULL)
00429 return;
00430
00431 if(nciop->free != NULL)
00432 nciop->free(nciop->pvt);
00433
00434 free(nciop);
00435 }
00436
00437
00438 static ncio *
00439 ncio_new(const char *path, int ioflags)
00440 {
00441 size_t sz_ncio = M_RNDUP(sizeof(ncio));
00442 size_t sz_path = M_RNDUP(strlen(path) +1);
00443 size_t sz_ncio_pvt;
00444 ncio *nciop;
00445
00446 #if ALWAYS_NC_SHARE
00447 fSet(ioflags, NC_SHARE);
00448 #endif
00449
00450 if(fIsSet(ioflags, NC_SHARE))
00451 fprintf(stderr, "NC_SHARE not implemented for ffio\n");
00452
00453 sz_ncio_pvt = sizeof(ncio_ffio);
00454
00455 nciop = (ncio *) malloc(sz_ncio + sz_path + sz_ncio_pvt);
00456 if(nciop == NULL)
00457 return NULL;
00458
00459 nciop->ioflags = ioflags;
00460 *((int *)&nciop->fd) = -1;
00461
00462 nciop->path = (char *) ((char *)nciop + sz_ncio);
00463 (void) strcpy((char *)nciop->path, path);
00464
00465
00466 *((void **)&nciop->pvt) = (void *)(nciop->path + sz_path);
00467
00468 ncio_ffio_init(nciop);
00469
00470 return nciop;
00471 }
00472
00473
00474
00475
00476
00477
00478
00479
00480 void ASNQFILE(_fcd filename, _fcd attribute, int *istat);
00481 void ASNFILE(_fcd filename, _fcd attribute, int *istat);
00482
00483 #define BUFLEN 256
00484 static const char *
00485 ncio_ffio_assign(const char *filename) {
00486 static char buffer[BUFLEN];
00487 int istat;
00488 _fcd fnp, fbp;
00489 char *envstr;
00490 char *xtra_assign;
00491 char emptystr='\0';
00492
00493
00494 memset(buffer,'\0',BUFLEN);
00495 errno = ENOERR;
00496
00497
00498 fnp = _cptofcd((char *)filename, strlen(filename));
00499 fbp = _cptofcd(buffer, BUFLEN);
00500
00501
00502 ASNQFILE(fnp, fbp, &istat);
00503 if (istat == 0) {
00504 return buffer;
00505 } else if (istat > 0 || istat < -1) {
00506 errno = NC_EINVAL;
00507 return (const char *) NULL;
00508 }
00509 envstr = getenv("NETCDF_FFIOSPEC");
00510 if(envstr == (char *) NULL) {
00511 envstr = "bufa:336:2";
00512 }
00513
00514
00515
00516
00517
00518 xtra_assign = getenv("NETCDF_XFFIOSPEC");
00519 if(xtra_assign == (char *) NULL) {
00520 xtra_assign=&emptystr;
00521 }
00522 if (strlen(envstr)+strlen(xtra_assign) + 4 > BUFLEN) {
00523
00524 errno=E2BIG;
00525 return (const char *) NULL;
00526 }
00527 (void) sprintf(buffer,"-F %s %s", envstr,xtra_assign);
00528 fbp = _cptofcd(buffer, strlen(buffer));
00529 ASNFILE(fnp, fbp, &istat);
00530 if (istat == 0) {
00531 return buffer;
00532 } else {
00533 errno = NC_EINVAL;
00534 return (const char *) NULL;
00535 }
00536 }
00537
00538
00539
00540
00541 static const size_t NCIO_MINBLOCKSIZE = 256;
00542 static const size_t NCIO_MAXBLOCKSIZE = 268435456;
00543
00544 int
00545 ncio_create(const char *path, int ioflags,
00546 size_t initialsz,
00547 off_t igeto, size_t igetsz, size_t *sizehintp,
00548 ncio **nciopp, void **const igetvpp)
00549 {
00550 ncio *nciop;
00551 const char *ControlString;
00552 int oflags = (O_RDWR|O_CREAT|O_TRUNC);
00553 int fd;
00554 int status;
00555 struct ffsw stat;
00556
00557 if(initialsz < (size_t)igeto + igetsz)
00558 initialsz = (size_t)igeto + igetsz;
00559
00560 fSet(ioflags, NC_WRITE);
00561
00562 if(path == NULL || *path == 0)
00563 return EINVAL;
00564
00565 nciop = ncio_new(path, ioflags);
00566 if(nciop == NULL)
00567 return ENOMEM;
00568
00569 if ((ControlString = ncio_ffio_assign(path)) == (const char *)NULL) {
00570
00571 status = errno;
00572 goto unwind_new;
00573 }
00574 #ifdef NOFFFLUSH
00575
00576
00577
00578
00579 if (strstr(ControlString,"global") != (char *) NULL) {
00580
00581 *((ncio_syncfunc **)&nciop->sync)
00582 = ncio_ffio_sync_noffflush;
00583 }
00584 #endif
00585 if(fIsSet(ioflags, NC_NOCLOBBER))
00586 fSet(oflags, O_EXCL);
00587
00588
00589 fd = ffopen(path, oflags, 0666, 0, &stat);
00590 if(fd < 0)
00591 {
00592 status = errno;
00593 goto unwind_new;
00594 }
00595 *((int *)&nciop->fd) = fd;
00596
00597 if(*sizehintp < NCIO_MINBLOCKSIZE || *sizehintp > NCIO_MAXBLOCKSIZE)
00598 {
00599
00600 *sizehintp = blksize(fd);
00601 }
00602 else
00603 {
00604 *sizehintp = M_RNDUP(*sizehintp);
00605 }
00606
00607 status = ncio_ffio_init2(nciop, sizehintp);
00608 if(status != ENOERR)
00609 goto unwind_open;
00610
00611 if(initialsz != 0)
00612 {
00613 status = fgrow(fd, (off_t)initialsz);
00614 if(status != ENOERR)
00615 goto unwind_open;
00616 }
00617
00618 if(igetsz != 0)
00619 {
00620 status = nciop->get(nciop,
00621 igeto, igetsz,
00622 RGN_WRITE,
00623 igetvpp);
00624 if(status != ENOERR)
00625 goto unwind_open;
00626 }
00627
00628 *nciopp = nciop;
00629 return ENOERR;
00630
00631 unwind_open:
00632 (void) ffclose(fd);
00633
00634
00635 unwind_new:
00636 ncio_free(nciop);
00637 return status;
00638 }
00639
00640
00641 int
00642 ncio_open(const char *path,
00643 int ioflags,
00644 off_t igeto, size_t igetsz, size_t *sizehintp,
00645 ncio **nciopp, void **const igetvpp)
00646 {
00647 ncio *nciop;
00648 const char *ControlString;
00649 int oflags = fIsSet(ioflags, NC_WRITE) ? O_RDWR : O_RDONLY;
00650 int fd;
00651 int status;
00652 struct ffsw stat;
00653
00654 if(path == NULL || *path == 0)
00655 return EINVAL;
00656
00657 nciop = ncio_new(path, ioflags);
00658 if(nciop == NULL)
00659 return ENOMEM;
00660
00661 if ((ControlString = ncio_ffio_assign(path)) == (const char *)NULL) {
00662
00663 status = errno;
00664 goto unwind_new;
00665 }
00666 #ifdef NOFFFLUSH
00667
00668
00669
00670
00671 if (strstr(ControlString,"global") != (char *) NULL) {
00672
00673 *((ncio_syncfunc **)&nciop->sync)
00674 = ncio_ffio_sync_noffflush;
00675 }
00676 #endif
00677
00678
00679 fd = ffopen(path, oflags, 0, 0, &stat);
00680
00681 if(fd < 0)
00682 {
00683 status = errno;
00684 goto unwind_new;
00685 }
00686 *((int *)&nciop->fd) = fd;
00687
00688 if(*sizehintp < NCIO_MINBLOCKSIZE || *sizehintp > NCIO_MAXBLOCKSIZE)
00689 {
00690
00691 *sizehintp = blksize(fd);
00692 }
00693 else
00694 {
00695 *sizehintp = M_RNDUP(*sizehintp);
00696 }
00697
00698 status = ncio_ffio_init2(nciop, sizehintp);
00699 if(status != ENOERR)
00700 goto unwind_open;
00701
00702 if(igetsz != 0)
00703 {
00704 status = nciop->get(nciop,
00705 igeto, igetsz,
00706 0,
00707 igetvpp);
00708 if(status != ENOERR)
00709 goto unwind_open;
00710 }
00711
00712 *nciopp = nciop;
00713 return ENOERR;
00714
00715 unwind_open:
00716 (void) ffclose(fd);
00717
00718 unwind_new:
00719 ncio_free(nciop);
00720 return status;
00721 }
00722
00723
00724 int
00725 ncio_close(ncio *nciop, int doUnlink)
00726 {
00727 int status = ENOERR;
00728
00729 if(nciop == NULL)
00730 return EINVAL;
00731
00732 status = nciop->sync(nciop);
00733
00734 (void) ffclose(nciop->fd);
00735
00736 if(doUnlink)
00737 (void) unlink(nciop->path);
00738
00739 ncio_free(nciop);
00740
00741 return status;
00742 }