PageRenderTime 41ms CodeModel.GetById 16ms RepoModel.GetById 1ms app.codeStats 0ms

/other/netcdf_write_matrix/src/libsrc/ffio.c

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