1 /*
2 * Copyright 2018, University Corporation for Atmospheric Research
3 * See netcdf/COPYRIGHT file for copying and redistribution conditions.
4 */
5 /* $Id: ffio.c,v 1.56 2006/09/15 20:40:30 ed Exp $ */
6 /* addition by O. Heudecker, AWI-Bremerhaven, 12.3.1998 */
7 /* added correction by John Sheldon and Hans Vahlenkamp 15.4.1998*/
8
9
10 #if HAVE_CONFIG_H
11 #include <config.h>
12 #endif
13
14 #include <assert.h>
15 #include <stdlib.h>
16 #include <stdio.h> /* DEBUG */
17 #include <string.h>
18 #include <assert.h>
19 #include <errno.h>
20 #ifndef NC_NOERR
21 #define NC_NOERR 0
22 #endif
23 #ifdef HAVE_FCNTL_H
24 #include <fcntl.h>
25 #endif
26 #ifdef HAVE_SYS_STAT_H
27 #include <sys/stat.h>
28 #endif
29 #ifdef HAVE_UNISTD_H
30 #include <unistd.h>
31 #endif
32 #if 0
33 /* Insertion by O. R. Heudecker, AWI-Bremerhaven 12.3.98 (1 line)*/
34 #include <ffio.h>
35 #include <fortran.h>
36 #endif
37
38 #include "ncio.h"
39 #include "fbits.h"
40 #include "rnd.h"
41
42 #if !defined(NDEBUG) && !defined(X_INT_MAX)
43 #define X_INT_MAX 2147483647
44 #endif
45 #if 0 /* !defined(NDEBUG) && !defined(X_ALIGN) */
46 #define X_ALIGN 4
47 #endif
48
49 #define ALWAYS_NC_SHARE 0 /* DEBUG */
50
51 /* Forward */
52 static int ncio_ffio_filesize(ncio *nciop, off_t *filesizep);
53 static int ncio_ffio_pad_length(ncio *nciop, off_t length);
54 static int ncio_ffio_close(ncio *nciop, int doUnlink);
55
56
57 /* Begin OS */
58
59 /*
60 * What is the preferred I/O block size?
61 * (This becomes the default *sizehint == ncp->chunk in the higher layers.)
62 * TODO: What is the the best answer here?
63 */
64 static size_t
blksize(int fd)65 blksize(int fd)
66 {
67 struct ffc_stat_s sb;
68 struct ffsw sw;
69 #ifdef HAVE_STRUCT_STAT_ST_BLKSIZE
70 #ifdef HAVE_FCNTL_H
71 if (fffcntl(fd, FC_STAT, &sb, &sw) > -1)
72 {
73 #ifdef __crayx1
74 if(sb.st_blksize > 0)
75 return (size_t) sb.st_blksize;
76 #else
77 if(sb.st_oblksize > 0)
78 return (size_t) sb.st_oblksize;
79 #endif
80 }
81 #endif
82 #endif
83 /* else, silent in the face of error */
84 return (size_t) 32768;
85 }
86
87 /*
88 * Sortof like ftruncate, except won't make the
89 * file shorter.
90 */
91 static int
fgrow(const int fd,const off_t len)92 fgrow(const int fd, const off_t len)
93 {
94 struct ffc_stat_s sb;
95 struct ffsw sw;
96 if (fffcntl(fd, FC_STAT, &sb, &sw) < 0)
97 return errno;
98 if (len < sb.st_size)
99 return NC_NOERR;
100 {
101 const long dumb = 0;
102 /* cache current position */
103 const off_t pos = ffseek(fd, 0, SEEK_CUR);
104 if(pos < 0)
105 return errno;
106 if (ffseek(fd, len-sizeof(dumb), SEEK_SET) < 0)
107 return errno;
108 if(ffwrite(fd, (void *)&dumb, sizeof(dumb)) < 0)
109 return errno;
110 if (ffseek(fd, pos, SEEK_SET) < 0)
111 return errno;
112 }
113 /* else */
114 return NC_NOERR;
115 }
116
117
118 /*
119 * Sortof like ftruncate, except won't make the file shorter. Differs
120 * from fgrow by only writing one byte at designated seek position, if
121 * needed.
122 */
123 static int
fgrow2(const int fd,const off_t len)124 fgrow2(const int fd, const off_t len)
125 {
126 struct ffc_stat_s sb;
127 struct ffsw sw;
128 if (fffcntl(fd, FC_STAT, &sb, &sw) < 0)
129 return errno;
130 if (len <= sb.st_size)
131 return NC_NOERR;
132 {
133 const char dumb = 0;
134 /* we don't use ftruncate() due to problem with FAT32 file systems */
135 /* cache current position */
136 const off_t pos = ffseek(fd, 0, SEEK_CUR);
137 if(pos < 0)
138 return errno;
139 if (ffseek(fd, len-1, SEEK_SET) < 0)
140 return errno;
141 if(ffwrite(fd, (void *)&dumb, sizeof(dumb)) < 0)
142 return errno;
143 if (ffseek(fd, pos, SEEK_SET) < 0)
144 return errno;
145 }
146 return NC_NOERR;
147 }
148 /* End OS */
149 /* Begin ffio */
150
151 static int
ffio_pgout(ncio * const nciop,off_t const offset,const size_t extent,const void * const vp,off_t * posp)152 ffio_pgout(ncio *const nciop,
153 off_t const offset, const size_t extent,
154 const void *const vp, off_t *posp)
155 {
156 #ifdef X_ALIGN
157 assert(offset % X_ALIGN == 0);
158 assert(extent % X_ALIGN == 0);
159 #endif
160
161 if(*posp != offset)
162 {
163 if(ffseek(nciop->fd, offset, SEEK_SET) != offset)
164 {
165 return errno;
166 }
167 *posp = offset;
168 }
169 if(ffwrite(nciop->fd, vp, extent) != extent)
170 {
171 return errno;
172 }
173 *posp += extent;
174
175 return NC_NOERR;
176 }
177
178
179 static int
ffio_pgin(ncio * const nciop,off_t const offset,const size_t extent,void * const vp,size_t * nreadp,off_t * posp)180 ffio_pgin(ncio *const nciop,
181 off_t const offset, const size_t extent,
182 void *const vp, size_t *nreadp, off_t *posp)
183 {
184 int status;
185 ssize_t nread;
186
187 #ifdef X_ALIGN
188 assert(offset % X_ALIGN == 0);
189 assert(extent % X_ALIGN == 0);
190 #endif
191
192 if(*posp != offset)
193 {
194 if(ffseek(nciop->fd, offset, SEEK_SET) != offset)
195 {
196 status = errno;
197 return status;
198 }
199 *posp = offset;
200 }
201
202 errno = 0;
203 nread = ffread(nciop->fd, vp, extent);
204 if(nread != extent)
205 {
206 status = errno;
207 if(nread == -1 || status != NC_NOERR)
208 return status;
209 /* else it's okay we read 0. */
210 }
211 *nreadp = nread;
212 *posp += nread;
213
214 return NC_NOERR;
215 }
216
217 /* */
218
219 typedef struct ncio_ffio {
220 off_t pos;
221 /* buffer */
222 off_t bf_offset;
223 size_t bf_extent;
224 size_t bf_cnt;
225 void *bf_base;
226 } ncio_ffio;
227
228
229 static int
ncio_ffio_rel(ncio * const nciop,off_t offset,int rflags)230 ncio_ffio_rel(ncio *const nciop, off_t offset, int rflags)
231 {
232 ncio_ffio *ffp = (ncio_ffio *)nciop->pvt;
233 int status = NC_NOERR;
234
235 assert(ffp->bf_offset <= offset);
236 assert(ffp->bf_cnt != 0);
237 assert(ffp->bf_cnt <= ffp->bf_extent);
238 #ifdef X_ALIGN
239 assert(offset < ffp->bf_offset + X_ALIGN);
240 assert(ffp->bf_cnt % X_ALIGN == 0 );
241 #endif
242
243 if(fIsSet(rflags, RGN_MODIFIED))
244 {
245 if(!fIsSet(nciop->ioflags, NC_WRITE))
246 return EPERM; /* attempt to write readonly file */
247
248 status = ffio_pgout(nciop, ffp->bf_offset,
249 ffp->bf_cnt,
250 ffp->bf_base, &ffp->pos);
251 /* if error, invalidate buffer anyway */
252 }
253 ffp->bf_offset = OFF_NONE;
254 ffp->bf_cnt = 0;
255 return status;
256 }
257
258
259 static int
ncio_ffio_get(ncio * const nciop,off_t offset,size_t extent,int rflags,void ** const vpp)260 ncio_ffio_get(ncio *const nciop,
261 off_t offset, size_t extent,
262 int rflags,
263 void **const vpp)
264 {
265 ncio_ffio *ffp = (ncio_ffio *)nciop->pvt;
266 int status = NC_NOERR;
267 #ifdef X_ALIGN
268 size_t rem;
269 #endif
270
271 if(fIsSet(rflags, RGN_WRITE) && !fIsSet(nciop->ioflags, NC_WRITE))
272 return EPERM; /* attempt to write readonly file */
273
274 assert(extent != 0);
275 assert(extent < X_INT_MAX); /* sanity check */
276
277 assert(ffp->bf_cnt == 0);
278
279 #ifdef X_ALIGN
280 /* round to seekable boundaries */
281 rem = offset % X_ALIGN;
282 if(rem != 0)
283 {
284 offset -= rem;
285 extent += rem;
286 }
287
288 {
289 const size_t rndup = extent % X_ALIGN;
290 if(rndup != 0)
291 extent += X_ALIGN - rndup;
292 }
293
294 assert(offset % X_ALIGN == 0);
295 assert(extent % X_ALIGN == 0);
296 #endif
297
298 if(ffp->bf_extent < extent)
299 {
300 if(ffp->bf_base != NULL)
301 {
302 free(ffp->bf_base);
303 ffp->bf_base = NULL;
304 ffp->bf_extent = 0;
305 }
306 assert(ffp->bf_extent == 0);
307 ffp->bf_base = malloc(extent);
308 if(ffp->bf_base == NULL)
309 return ENOMEM;
310 ffp->bf_extent = extent;
311 }
312
313 status = ffio_pgin(nciop, offset,
314 extent,
315 ffp->bf_base,
316 &ffp->bf_cnt, &ffp->pos);
317 if(status != NC_NOERR)
318 return status;
319
320 ffp->bf_offset = offset;
321
322 if(ffp->bf_cnt < extent)
323 {
324 (void) memset((char *)ffp->bf_base + ffp->bf_cnt, 0,
325 extent - ffp->bf_cnt);
326 ffp->bf_cnt = extent;
327 }
328
329
330 #ifdef X_ALIGN
331 *vpp = (char *)ffp->bf_base + rem;
332 #else
333 *vpp = (char *)ffp->bf_base;
334 #endif
335 return NC_NOERR;
336 }
337
338
339 static int
ncio_ffio_move(ncio * const nciop,off_t to,off_t from,size_t nbytes,int rflags)340 ncio_ffio_move(ncio *const nciop, off_t to, off_t from,
341 size_t nbytes, int rflags)
342 {
343 int status = NC_NOERR;
344 off_t lower = from;
345 off_t upper = to;
346 char *base;
347 size_t diff = upper - lower;
348 size_t extent = diff + nbytes;
349
350 rflags &= RGN_NOLOCK; /* filter unwanted flags */
351
352 if(to == from)
353 return NC_NOERR; /* NOOP */
354
355 if(to > from)
356 {
357 /* growing */
358 lower = from;
359 upper = to;
360 }
361 else
362 {
363 /* shrinking */
364 lower = to;
365 upper = from;
366 }
367
368 diff = upper - lower;
369 extent = diff + nbytes;
370
371 status = ncio_ffio_get(nciop, lower, extent, RGN_WRITE|rflags,
372 (void **)&base);
373
374 if(status != NC_NOERR)
375 return status;
376
377 if(to > from)
378 (void) memmove(base + diff, base, nbytes);
379 else
380 (void) memmove(base, base + diff, nbytes);
381
382 (void) ncio_ffio_rel(nciop, lower, RGN_MODIFIED);
383
384 return status;
385 }
386
387 #ifdef NOFFFLUSH
388 /* ncio_ffio_sync_noffflush is only needed if the FFIO global layer is
389 * used, because it currently has a bug that causes the PEs to hang
390 * RKO 06/26/98
391 */
392 static int
ncio_ffio_sync_noffflush(ncio * const nciop)393 ncio_ffio_sync_noffflush(ncio *const nciop)
394 {
395 struct ffc_stat_s si; /* for call to fffcntl() */
396 struct ffsw ffstatus; /* to return ffsw.sw_error */
397 /* run some innocuous ffio routine to get if any errno */
398 if(fffcntl(nciop->fd, FC_STAT, &si, &ffstatus) < 0)
399 return ffstatus.sw_error;
400 return NC_NOERR;
401 }
402 /* this tests to see if the global FFIO layer is being called for
403 * returns ~0 if it is, else returns 0
404 */
405 static int
ncio_ffio_global_test(const char * ControlString)406 ncio_ffio_global_test(const char *ControlString)
407 {
408 if (strstr(ControlString,"global") != (char *) NULL) {
409 return ~0;
410 } else {
411 return 0;
412 }
413 }
414 #endif
415
416 static int
ncio_ffio_sync(ncio * const nciop)417 ncio_ffio_sync(ncio *const nciop)
418 {
419 int test_flush;
420 #ifdef __crayx1
421 struct ffsw stat;
422 test_flush = ffflush(nciop->fd,&stat) < 0;
423 #else
424 test_flush = ffflush(nciop->fd) < 0;
425 #endif
426 if(test_flush)
427 return errno;
428 return NC_NOERR;
429 }
430
431 static void
ncio_ffio_free(void * const pvt)432 ncio_ffio_free(void *const pvt)
433 {
434 ncio_ffio *ffp = (ncio_ffio *)pvt;
435 if(ffp == NULL)
436 return;
437
438 if(ffp->bf_base != NULL)
439 {
440 free(ffp->bf_base);
441 ffp->bf_base = NULL;
442 ffp->bf_offset = OFF_NONE;
443 ffp->bf_extent = 0;
444 ffp->bf_cnt = 0;
445 }
446 }
447
448
449 static int
ncio_ffio_init2(ncio * const nciop,size_t * sizehintp)450 ncio_ffio_init2(ncio *const nciop, size_t *sizehintp)
451 {
452 ncio_ffio *ffp = (ncio_ffio *)nciop->pvt;
453
454 assert(nciop->fd >= 0);
455
456 ffp->bf_extent = *sizehintp;
457
458 assert(ffp->bf_base == NULL);
459
460 /* this is separate allocation because it may grow */
461 ffp->bf_base = malloc(ffp->bf_extent);
462 if(ffp->bf_base == NULL)
463 {
464 ffp->bf_extent = 0;
465 return ENOMEM;
466 }
467 /* else */
468 return NC_NOERR;
469 }
470
471
472 static void
ncio_ffio_init(ncio * const nciop)473 ncio_ffio_init(ncio *const nciop)
474 {
475 ncio_ffio *ffp = (ncio_ffio *)nciop->pvt;
476
477 *((ncio_relfunc **)&nciop->rel) = ncio_ffio_rel; /* cast away const */
478 *((ncio_getfunc **)&nciop->get) = ncio_ffio_get; /* cast away const */
479 *((ncio_movefunc **)&nciop->move) = ncio_ffio_move; /* cast away const */
480 *((ncio_syncfunc **)&nciop->sync) = ncio_ffio_sync; /* cast away const */
481 *((ncio_filesizefunc **)&nciop->filesize) = ncio_ffio_filesize; /* cast away const */
482 *((ncio_pad_lengthfunc **)&nciop->pad_length) = ncio_ffio_pad_length; /* cast away const */
483 *((ncio_closefunc **)&nciop->close) = ncio_ffio_close; /* cast away const */
484
485 ffp->pos = -1;
486 ffp->bf_offset = OFF_NONE;
487 ffp->bf_extent = 0;
488 ffp->bf_cnt = 0;
489 ffp->bf_base = NULL;
490 }
491
492 /* */
493
494 static void
ncio_free(ncio * nciop)495 ncio_free(ncio *nciop)
496 {
497 if(nciop == NULL)
498 return;
499
500 if(nciop->free != NULL)
501 nciop->free(nciop->pvt);
502
503 free(nciop);
504 }
505
506
507 static ncio *
ncio_ffio_new(const char * path,int ioflags)508 ncio_ffio_new(const char *path, int ioflags)
509 {
510 size_t sz_ncio = M_RNDUP(sizeof(ncio));
511 size_t sz_path = M_RNDUP(strlen(path) +1);
512 size_t sz_ncio_pvt;
513 ncio *nciop;
514
515 #if ALWAYS_NC_SHARE /* DEBUG */
516 fSet(ioflags, NC_SHARE);
517 #endif
518
519 if(fIsSet(ioflags, NC_SHARE))
520 fprintf(stderr, "NC_SHARE not implemented for ffio\n");
521
522 sz_ncio_pvt = sizeof(ncio_ffio);
523
524 nciop = (ncio *) malloc(sz_ncio + sz_path + sz_ncio_pvt);
525 if(nciop == NULL)
526 return NULL;
527
528 nciop->ioflags = ioflags;
529 *((int *)&nciop->fd) = -1; /* cast away const */
530
531 nciop->path = (char *) ((char *)nciop + sz_ncio);
532 (void) strcpy((char *)nciop->path, path); /* cast away const */
533
534 /* cast away const */
535 *((void **)&nciop->pvt) = (void *)(nciop->path + sz_path);
536
537 ncio_ffio_init(nciop);
538
539 return nciop;
540 }
541
542 /* put all the FFIO assign specific code here
543 * returns a pointer to an internal static char location
544 * which may change when the function is called again
545 * if the returned pointer is NULL this indicates that an error occurred
546 * check errno for the netCDF error value
547 */
548 /* prototype fortran subroutines */
549 #ifdef __crayx1
550 void ASNQFILE(const char *filename, const char *attribute, int *istat, int flen, int alen);
551 void ASNFILE(const char *filename, const char *attribute, int *istat, int flen, int alen);
552 #else
553 void ASNQFILE(_fcd filename, _fcd attribute, int *istat);
554 void ASNFILE(_fcd filename, _fcd attribute, int *istat);
555 #endif
556
557 #define BUFLEN 256
558 static const char *
ncio_ffio_assign(const char * filename)559 ncio_ffio_assign(const char *filename) {
560 static char buffer[BUFLEN];
561 int istat;
562 #ifndef __crayx1
563 _fcd fnp, fbp;
564 #endif
565 char *envstr;
566 char *xtra_assign;
567 char emptystr='\0';
568
569 /* put things into known states */
570 memset(buffer,'\0',BUFLEN);
571 errno = NC_NOERR;
572
573 /* set up Fortran character pointers */
574 #ifdef __crayx1
575 ASNQFILE(filename, buffer, &istat, strlen(filename)+1, BUFLEN);
576 #else
577 fnp = _cptofcd((char *)filename, strlen(filename));
578 fbp = _cptofcd(buffer, BUFLEN);
579
580 /* see if the user has "assigned" to this file */
581 ASNQFILE(fnp, fbp, &istat);
582 #endif
583 if (istat == 0) { /* user has already specified an assign */
584 return buffer;
585 } else if (istat > 0 || istat < -1) { /* error occurred */
586 errno = EINVAL;
587 return (const char *) NULL;
588 } /* istat = -1 -> no assign for file */
589 envstr = getenv("NETCDF_FFIOSPEC");
590 if(envstr == (char *) NULL) {
591 envstr = "bufa:336:2"; /* this should be macroized */
592 }
593
594 /* Insertion by Olaf Heudecker, AWI-Bremerhaven, 12.8.1998
595 to allow more versatile FFIO-assigns */
596 /* this is unnecessary and could have been included
597 * into the NETCDF_FFIOSPEC environment variable */
598 xtra_assign = getenv("NETCDF_XFFIOSPEC");
599 if(xtra_assign == (char *) NULL) {
600 xtra_assign=&emptystr;
601 }
602 if (strlen(envstr)+strlen(xtra_assign) + 4 > BUFLEN) {
603 /* Error: AssignCommand too long */
604 errno=E2BIG;
605 return (const char *) NULL;
606 }
607 (void) sprintf(buffer,"-F %s %s", envstr,xtra_assign);
608 #ifdef __crayx1
609 ASNFILE(filename, buffer, &istat, strlen(filename)+1, strlen(buffer)+1);
610 #else
611 fbp = _cptofcd(buffer, strlen(buffer));
612 ASNFILE(fnp, fbp, &istat);
613 #endif
614 if (istat == 0) { /* success */
615 return buffer;
616 } else { /* error */
617 errno = EINVAL;
618 return (const char *) NULL;
619 }
620 }
621
622 /* Public below this point */
623
624 /* TODO: Is this reasonable for this platform? */
625 static const size_t NCIO_MINBLOCKSIZE = 256;
626 static const size_t NCIO_MAXBLOCKSIZE = 268435456; /* sanity check, about X_SIZE_T_MAX/8 */
627
628 int
ffio_create(const char * path,int ioflags,size_t initialsz,off_t igeto,size_t igetsz,size_t * sizehintp,void * parameters,ncio ** nciopp,void ** const igetvpp)629 ffio_create(const char *path, int ioflags,
630 size_t initialsz,
631 off_t igeto, size_t igetsz, size_t *sizehintp,
632 void* parameters,
633 ncio **nciopp, void **const igetvpp)
634 {
635 ncio *nciop;
636 const char *ControlString;
637 int oflags = (O_RDWR|O_CREAT|O_TRUNC);
638 int fd;
639 int status;
640 struct ffsw stat;
641
642 if(initialsz < (size_t)igeto + igetsz)
643 initialsz = (size_t)igeto + igetsz;
644
645 fSet(ioflags, NC_WRITE);
646
647 if(path == NULL || *path == 0)
648 return EINVAL;
649
650 nciop = ncio_ffio_new(path, ioflags);
651 if(nciop == NULL)
652 return ENOMEM;
653
654 if ((ControlString = ncio_ffio_assign(path)) == (const char *)NULL) {
655 /* an error occurred - just punt */
656 status = errno;
657 goto unwind_new;
658 }
659 #ifdef NOFFFLUSH
660 /* test whether the global layer is being called for
661 * this file ... if so then can't call FFIO ffflush()
662 * RKO 06/26/98
663 */
664 if (strstr(ControlString,"global") != (char *) NULL) {
665 /* use no ffflush version */
666 *((ncio_syncfunc **)&nciop->sync)
667 = ncio_ffio_sync_noffflush;
668 }
669 #endif
670 if(fIsSet(ioflags, NC_NOCLOBBER))
671 fSet(oflags, O_EXCL);
672
673 /* Orig: fd = ffopens(path, oflags, 0666, 0, &stat, ControlString); */
674 fd = ffopen(path, oflags, 0666, 0, &stat);
675 if(fd < 0)
676 {
677 status = errno;
678 goto unwind_new;
679 }
680 *((int *)&nciop->fd) = fd; /* cast away const */
681
682 if(*sizehintp < NCIO_MINBLOCKSIZE || *sizehintp > NCIO_MAXBLOCKSIZE)
683 {
684 /* Use default */
685 *sizehintp = blksize(fd);
686 }
687 else
688 {
689 *sizehintp = M_RNDUP(*sizehintp);
690 }
691
692 status = ncio_ffio_init2(nciop, sizehintp);
693 if(status != NC_NOERR)
694 goto unwind_open;
695
696 if(initialsz != 0)
697 {
698 status = fgrow(fd, (off_t)initialsz);
699 if(status != NC_NOERR)
700 goto unwind_open;
701 }
702
703 if(igetsz != 0)
704 {
705 status = nciop->get(nciop,
706 igeto, igetsz,
707 RGN_WRITE,
708 igetvpp);
709 if(status != NC_NOERR)
710 goto unwind_open;
711 }
712
713 *nciopp = nciop;
714 return NC_NOERR;
715
716 unwind_open:
717 (void) ffclose(fd);
718 /* ?? unlink */
719 /*FALLTHRU*/
720 unwind_new:
721 ncio_close(nciop,!fIsSet(ioflags, NC_NOCLOBBER));
722 return status;
723 }
724
725
726 int
ffio_open(const char * path,int ioflags,off_t igeto,size_t igetsz,size_t * sizehintp,void * parameters,ncio ** nciopp,void ** const igetvpp)727 ffio_open(const char *path,
728 int ioflags,
729 off_t igeto, size_t igetsz, size_t *sizehintp,
730 void* parameters,
731 ncio **nciopp, void **const igetvpp)
732 {
733 ncio *nciop;
734 const char *ControlString;
735 int oflags = fIsSet(ioflags, NC_WRITE) ? O_RDWR : O_RDONLY;
736 int fd;
737 int status;
738 struct ffsw stat;
739
740 if(path == NULL || *path == 0)
741 return EINVAL;
742
743 nciop = ncio_ffio_new(path, ioflags);
744 if(nciop == NULL)
745 return ENOMEM;
746
747 if ((ControlString = ncio_ffio_assign(path)) == (const char *)NULL) {
748 /* an error occurred - just punt */
749 status = errno;
750 goto unwind_new;
751 }
752 #ifdef NOFFFLUSH
753 /* test whether the global layer is being called for
754 * this file ... if so then can't call FFIO ffflush()
755 * RKO 06/26/98
756 */
757 if (strstr(ControlString,"global") != (char *) NULL) {
758 /* use no ffflush version */
759 *((ncio_syncfunc **)&nciop->sync)
760 = ncio_ffio_sync_noffflush;
761 }
762 #endif
763
764 /* Orig: fd = ffopens(path, oflags, 0, 0, &stat, ControlString); */
765 fd = ffopen(path, oflags, 0, 0, &stat);
766
767 if(fd < 0)
768 {
769 status = errno;
770 goto unwind_new;
771 }
772 *((int *)&nciop->fd) = fd; /* cast away const */
773
774 if(*sizehintp < NCIO_MINBLOCKSIZE || *sizehintp > NCIO_MAXBLOCKSIZE)
775 {
776 /* Use default */
777 *sizehintp = blksize(fd);
778 }
779 else
780 {
781 *sizehintp = M_RNDUP(*sizehintp);
782 }
783
784 status = ncio_ffio_init2(nciop, sizehintp);
785 if(status != NC_NOERR)
786 goto unwind_open;
787
788 if(igetsz != 0)
789 {
790 status = nciop->get(nciop,
791 igeto, igetsz,
792 0,
793 igetvpp);
794 if(status != NC_NOERR)
795 goto unwind_open;
796 }
797
798 *nciopp = nciop;
799 return NC_NOERR;
800
801 unwind_open:
802 (void) ffclose(fd);
803 /*FALLTHRU*/
804 unwind_new:
805 ncio_close(nciop,0);
806 return status;
807 }
808
809
810 /*
811 * Get file size in bytes.
812 * Is use of ffseek() really necessary, or could we use standard fstat() call
813 * and get st_size member?
814 */
815 static int
ncio_ffio_filesize(ncio * nciop,off_t * filesizep)816 ncio_ffio_filesize(ncio *nciop, off_t *filesizep)
817 {
818 off_t filesize, current, reset;
819
820 if(nciop == NULL)
821 return EINVAL;
822
823 current = ffseek(nciop->fd, 0, SEEK_CUR); /* save current */
824 *filesizep = ffseek(nciop->fd, 0, SEEK_END); /* get size */
825 reset = ffseek(nciop->fd, current, SEEK_SET); /* reset */
826
827 if(reset != current)
828 return EINVAL;
829 return NC_NOERR;
830 }
831
832
833 /*
834 * Sync any changes to disk, then extend file so its size is length.
835 * This is only intended to be called before close, if the file is
836 * open for writing and the actual size does not match the calculated
837 * size, perhaps as the result of having been previously written in
838 * NOFILL mode.
839 */
840 static int
ncio_ffio_pad_length(ncio * nciop,off_t length)841 ncio_ffio_pad_length(ncio *nciop, off_t length)
842 {
843 int status = NC_NOERR;
844
845 if(nciop == NULL)
846 return EINVAL;
847
848 if(!fIsSet(nciop->ioflags, NC_WRITE))
849 return EPERM; /* attempt to write readonly file */
850
851 status = nciop->sync(nciop);
852 if(status != NC_NOERR)
853 return status;
854
855 status = fgrow2(nciop->fd, length);
856 if(status != NC_NOERR)
857 return errno;
858 return NC_NOERR;
859 }
860
861
862 static int
ncio_ffio_close(ncio * nciop,int doUnlink)863 ncio_ffio_close(ncio *nciop, int doUnlink)
864 {
865 /*
866 * TODO: I believe this function is lacking the de-assignment of the
867 * Fortran LUN assigned by ASNFILE in ncio_ffio_assign(...) -- SRE
868 * 2002-07-10.
869 */
870
871 int status = NC_NOERR;
872
873 if(nciop == NULL)
874 return EINVAL;
875
876 status = nciop->sync(nciop);
877
878 (void) ffclose(nciop->fd);
879
880 if(doUnlink)
881 (void) unlink(nciop->path);
882
883 ncio__ffio_free(nciop);
884
885 return status;
886 }
887