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