Skip to content

AFNI/NIfTI Server

Sections
Personal tools
You are here: Home » AFNI » Documentation

Doxygen Source Code Documentation


Main Page   Alphabetical List   Data Structures   File List   Data Fields   Globals   Search  

ffio.c

Go to the documentation of this file.
00001 /*
00002  *      Copyright 1996, University Corporation for Atmospheric Research
00003  *      See netcdf/COPYRIGHT file for copying and redistribution conditions.
00004  */
00005 /* addition by O. Heudecker, AWI-Bremerhaven, 12.3.1998 */
00006 /* added correction by John Sheldon and Hans Vahlenkamp 15.4.1998*/
00007 
00008 #include "ncconfig.h"
00009 #include <assert.h>
00010 #include <stdlib.h>
00011 #include <stdio.h>      /* DEBUG */
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 /* Insertion by O. R. Heudecker, AWI-Bremerhaven 12.3.98 (1 line)*/
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 /* !defined(NDEBUG) && !defined(X_ALIGN) */
00031 #define  X_ALIGN 4
00032 #endif
00033 
00034 #define ALWAYS_NC_SHARE 0 /* DEBUG */
00035 
00036 /* Begin OS */
00037 
00038 /*
00039  * What is the preferred I/O block size?
00040  * (This becomes the default *sizehint == ncp->chunk in the higher layers.)
00041  * TODO: What is the the best answer here?
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         /* else, silent in the face of error */
00054         return (size_t) 32768;
00055 }
00056 
00057 /*
00058  * Sortof like ftruncate, except won't make the
00059  * file shorter.
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                         /* cache current position */
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         /* else */
00084         return ENOERR;
00085 }
00086 
00087 /* End OS */
00088 /* Begin ffio */
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                 /* else it's okay we read 0. */
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         /* buffer */
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; /* attempt to write readonly file */
00186 
00187                 status = ffio_pgout(nciop, ffp->bf_offset,
00188                         ffp->bf_cnt,
00189                         ffp->bf_base, &ffp->pos);
00190                 /* if error, invalidate buffer anyway */
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; /* attempt to write readonly file */
00212 
00213         assert(extent != 0);
00214         assert(extent < X_INT_MAX); /* sanity check */
00215         assert(offset < X_INT_MAX); /* sanity check */
00216 
00217         assert(ffp->bf_cnt == 0);
00218 
00219 #ifdef X_ALIGN
00220         /* round to seekable boundaries */
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; /* filter unwanted flags */
00291 
00292         if(to == from)
00293                 return ENOERR; /* NOOP */
00294         
00295         if(to > from)
00296         {
00297                 /* growing */
00298                 lower = from;   
00299                 upper = to;
00300         }
00301         else
00302         {
00303                 /* shrinking */
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 /* ncio_ffio_sync_noffflush is only needed if the FFIO global layer is
00329  * used, because it currently has a bug that causes the PEs to hang
00330  * RKO 06/26/98
00331  */
00332 static int
00333 ncio_ffio_sync_noffflush(ncio *const nciop)
00334 {
00335         struct ffc_stat_s si;   /* for call to fffcntl() */
00336         struct ffsw ffstatus;   /* to return ffsw.sw_error */
00337         /* run some innocuous ffio routine to get if any errno */
00338         if(fffcntl(nciop->fd, FC_STAT, &si, &ffstatus) < 0)
00339                 return ffstatus.sw_error;
00340         return ENOERR;
00341 }
00342 /* this tests to see if the global FFIO layer is being called for
00343  * returns ~0 if it is, else returns 0
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         /* this is separate allocation because it may grow */
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         /* else */
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; /* cast away const */
00411         *((ncio_getfunc **)&nciop->get) = ncio_ffio_get; /* cast away const */
00412         *((ncio_movefunc **)&nciop->move) = ncio_ffio_move; /* cast away const */
00413         *((ncio_syncfunc **)&nciop->sync) = ncio_ffio_sync; /* cast away const */
00414         *((ncio_freefunc **)&nciop->free) = ncio_ffio_free; /* cast away const */
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 /* DEBUG */
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; /* cast away const */
00461 
00462         nciop->path = (char *) ((char *)nciop + sz_ncio);
00463         (void) strcpy((char *)nciop->path, path); /* cast away const */
00464 
00465                                 /* cast away const */
00466         *((void **)&nciop->pvt) = (void *)(nciop->path + sz_path);
00467 
00468         ncio_ffio_init(nciop);
00469 
00470         return nciop;
00471 }
00472 
00473 /* put all the FFIO assign specific code here
00474  * returns a pointer to an internal static char location
00475  * which may change when the function is called again
00476  * if the returned pointer is NULL this indicates that an error occured
00477  * check errno for the netCDF error value
00478  */
00479 /* prototype fortran subroutines */
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 /* put things into known states */
00494         memset(buffer,'\0',BUFLEN);
00495         errno = ENOERR;
00496 
00497 /* set up Fortran character pointers */
00498         fnp = _cptofcd((char *)filename, strlen(filename));
00499         fbp = _cptofcd(buffer, BUFLEN);
00500 
00501 /* see if the user has "assigned" to this file */
00502         ASNQFILE(fnp, fbp, &istat);
00503         if (istat == 0) {       /* user has already specified an assign */
00504                 return buffer;
00505         } else if (istat > 0 || istat < -1) {   /* error occured */
00506                 errno = NC_EINVAL;              /* as good as any */
00507                 return (const char *) NULL;
00508         } /* istat = -1 -> no assign for file */
00509         envstr = getenv("NETCDF_FFIOSPEC");
00510         if(envstr == (char *) NULL) {
00511                  envstr = "bufa:336:2";         /* this should be macroized */
00512         }
00513         
00514         /* Insertion by Olaf Heudecker, AWI-Bremerhaven, 12.8.1998
00515            to allow more versatile FFIO-assigns */
00516         /* this is unnecessary and could have been included
00517          * into the NETCDF_FFIOSPEC environment variable */
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         /* Error: AssignCommand too long */
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) {       /* success */
00531                 return buffer;
00532         } else {                /* error */
00533                 errno = NC_EINVAL;
00534                 return (const char *) NULL;
00535         }
00536 }
00537 
00538 /* Public below this point */
00539 
00540 /* TODO: Is this reasonable for this platform? */
00541 static const size_t NCIO_MINBLOCKSIZE = 256;
00542 static const size_t NCIO_MAXBLOCKSIZE = 268435456; /* sanity check, about X_SIZE_T_MAX/8 */
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                 /* an error occured - just punt */
00571                 status = errno;
00572                 goto unwind_new;
00573         }
00574 #ifdef NOFFFLUSH
00575         /* test whether the global layer is being called for
00576          * this file ... if so then can't call FFIO ffflush()
00577          * RKO 06/26/98
00578          */
00579         if (strstr(ControlString,"global") != (char *) NULL) {
00580                 /* use no ffflush version */
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         /* Orig: fd = ffopens(path, oflags, 0666, 0, &stat, ControlString); */
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; /* cast away const */
00596 
00597         if(*sizehintp < NCIO_MINBLOCKSIZE || *sizehintp > NCIO_MAXBLOCKSIZE)
00598         {
00599                 /* Use default */
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         /* ?? unlink */
00634         /*FALLTHRU*/
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                 /* an error occured - just punt */
00663                 status = errno;
00664                 goto unwind_new;
00665         }
00666 #ifdef NOFFFLUSH
00667         /* test whether the global layer is being called for
00668          * this file ... if so then can't call FFIO ffflush()
00669          * RKO 06/26/98
00670          */
00671         if (strstr(ControlString,"global") != (char *) NULL) {
00672                 /* use no ffflush version */
00673                 *((ncio_syncfunc **)&nciop->sync)
00674                         = ncio_ffio_sync_noffflush;
00675         }
00676 #endif
00677 
00678         /* Orig: fd = ffopens(path, oflags, 0, 0, &stat, ControlString); */
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; /* cast away const */
00687 
00688         if(*sizehintp < NCIO_MINBLOCKSIZE || *sizehintp > NCIO_MAXBLOCKSIZE)
00689         {
00690                 /* Use default */
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         /*FALLTHRU*/
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 }
 

Powered by Plone

This site conforms to the following standards: