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


HyperKWIC - Version 7.20DA executed at 11:37 on 27 Oct 2017 | Polyhedron Solutions - INTERNAL USE | COMMERCIAL (Any O/S) SN 4AKIed