NetCDF  4.3.2
dfile.c
Go to the documentation of this file.
00001 
00011 #include "config.h"
00012 #include <stdlib.h>
00013 #ifdef HAVE_SYS_RESOURCE_H
00014 #include <sys/resource.h>
00015 #endif
00016 #ifdef HAVE_SYS_TYPES_H
00017 #include <sys/types.h>
00018 #endif
00019 #ifdef HAVE_SYS_STAT_H
00020 #include <sys/stat.h>
00021 #endif
00022 #ifdef HAVE_FCNTL_H
00023 #include <fcntl.h>
00024 #endif
00025 #include "ncdispatch.h"
00026 
00027 /* Define an enum over the possible set of
00028    File Types
00029 */
00030 enum FileType {
00031 FT_UNKNOWN,
00032 FT_HDF,
00033 FT_NC,
00034 FT_PNETCDF
00035 };
00036 
00037 
00038 static int nc_initialized = 0;
00039 
00077 size_t NC_coord_zero[NC_MAX_VAR_DIMS];
00078 size_t NC_coord_one[NC_MAX_VAR_DIMS];
00079 
00080 static void
00081 nc_local_initialize(void)
00082 {
00083     int i;
00084 
00085     for(i=0;i<NC_MAX_VAR_DIMS;i++) {
00086         NC_coord_one[i] = 1;
00087         NC_coord_zero[i] = 0;
00088     }
00089 }
00090 
00091 static int
00092 NC_check_file_type(const char *path, int use_parallel, void *mpi_info,
00093                    enum FileType* filetype, int* version)
00094 {
00095    char magic[MAGIC_NUMBER_LEN];
00096     
00097    *filetype = FT_UNKNOWN;
00098 
00099    /* Get the 4-byte magic from the beginning of the file. Don't use posix
00100     * for parallel, use the MPI functions instead. */
00101 #ifdef USE_PARALLEL
00102    if (use_parallel) 
00103    {
00104       MPI_File fh;
00105       MPI_Status status;
00106       int retval;
00107       MPI_Comm comm = MPI_COMM_WORLD;
00108       MPI_Info info = MPI_INFO_NULL;
00109 
00110       if(mpi_info != NULL) {
00111          comm = ((NC_MPI_INFO*)mpi_info)->comm;
00112          info = ((NC_MPI_INFO*)mpi_info)->info;
00113       }
00114       if((retval = MPI_File_open(comm, (char *)path, MPI_MODE_RDONLY,info, 
00115                                  &fh)) != MPI_SUCCESS)
00116          return NC_EPARINIT;
00117       if((retval = MPI_File_read(fh, magic, MAGIC_NUMBER_LEN, MPI_CHAR,
00118                                  &status)) != MPI_SUCCESS)
00119          return NC_EPARINIT;
00120       if((retval = MPI_File_close(&fh)) != MPI_SUCCESS)
00121          return NC_EPARINIT;
00122    } else
00123 #endif /* USE_PARALLEL */
00124    {
00125       FILE *fp;
00126       size_t i;
00127 #ifdef HAVE_SYS_STAT_H
00128       struct stat st;
00129 #endif
00130 
00131       if(path == NULL || strlen(path)==0)
00132         return NC_EINVAL;
00133         
00134       if (!(fp = fopen(path, "r")))
00135          return errno;
00136 
00137 #ifdef HAVE_SYS_STAT_H
00138       /* The file must be at least MAGIC_NUMBER_LEN in size,
00139          or otherwise the following fread will exhibit unexpected
00140          behavior. */
00141       if(!(fstat(fileno(fp),&st) == 0)) {
00142         fclose(fp);
00143         return errno;
00144       }
00145       
00146       if(st.st_size < MAGIC_NUMBER_LEN) {
00147         fclose(fp);
00148         return NC_ENOTNC;
00149       }
00150 #endif
00151             
00152 
00153       i = fread(magic, MAGIC_NUMBER_LEN, 1, fp);
00154       fclose(fp);
00155           if(i == 0) 
00156                 return NC_ENOTNC;
00157       if(i != 1) 
00158         return errno;
00159     }
00160     
00161     /* Look at the magic number */
00162     /* Ignore the first byte for HDF */
00163     if(magic[1] == 'H' && magic[2] == 'D' && magic[3] == 'F') {
00164         *filetype = FT_HDF;
00165         *version = 5;
00166     } else if(magic[0] == '\016' && magic[1] == '\003'
00167               && magic[2] == '\023' && magic[3] == '\001') {
00168         *filetype = FT_HDF;
00169         *version = 4;
00170     } else if(magic[0] == 'C' && magic[1] == 'D' && magic[2] == 'F') {
00171         *filetype = FT_NC;
00172         if(magic[3] == '\001') 
00173             *version = 1; /* netcdf classic version 1 */
00174          else if(magic[3] == '\002') 
00175             *version = 2; /* netcdf classic version 2 */
00176          else if(magic[3] == '\005') {
00177             *filetype = FT_PNETCDF;
00178             *version = 5; /* pnetcdf file */
00179          } else
00180             return NC_ENOTNC;
00181      } else
00182             return NC_ENOTNC;
00183    return NC_NOERR;
00184 }
00185 
00382 int
00383 nc_create(const char *path, int cmode, int *ncidp)
00384 {
00385    return nc__create(path,cmode,NC_SIZEHINT_DEFAULT,NULL,ncidp);
00386 }
00387 
00449 int
00450 nc__create(const char *path, int cmode, size_t initialsz,
00451            size_t *chunksizehintp, int *ncidp)
00452 {
00453    return NC_create(path, cmode, initialsz, 0, 
00454                     chunksizehintp, 0, NULL, ncidp);
00455 
00456 }
00465 int
00466 nc__create_mp(const char *path, int cmode, size_t initialsz, 
00467               int basepe, size_t *chunksizehintp, int *ncidp)
00468 {
00469    return NC_create(path, cmode, initialsz, basepe, 
00470                     chunksizehintp, 0, NULL, ncidp);
00471 }
00472 
00587 int
00588 nc_open(const char *path, int mode, int *ncidp)
00589 {
00590    return NC_open(path, mode, 0, NULL, 0, NULL, ncidp);
00591 }
00592 
00644 int
00645 nc__open(const char *path, int mode,
00646          size_t *chunksizehintp, int *ncidp)
00647 {
00648    return NC_open(path, mode, 0, chunksizehintp, 0, 
00649                   NULL, ncidp);
00650 }
00651 
00660 int
00661 nc__open_mp(const char *path, int mode, int basepe, 
00662             size_t *chunksizehintp, int *ncidp)
00663 {
00664    return NC_open(path, mode, basepe, chunksizehintp,
00665                   0, NULL, ncidp);
00666 }
00667 
00685 int 
00686 nc_inq_path(int ncid, size_t *pathlen, char *path)
00687 {
00688    NC* ncp;
00689    int stat = NC_NOERR;
00690    if ((stat = NC_check_id(ncid, &ncp)))
00691       return stat;
00692    if(ncp->path == NULL) {
00693         if(pathlen) *pathlen = 0;
00694         if(path) path[0] = '\0';
00695    } else {
00696        if (pathlen) *pathlen = strlen(ncp->path);
00697        if (path) strcpy(path, ncp->path);
00698    }
00699    return stat;
00700 }
00701 
00750 int
00751 nc_redef(int ncid)
00752 {
00753    NC* ncp;
00754    int stat = NC_check_id(ncid, &ncp);
00755    if(stat != NC_NOERR) return stat;
00756    return ncp->dispatch->redef(ncid);
00757 }
00758 
00814 int
00815 nc_enddef(int ncid)
00816 {
00817    int status = NC_NOERR;
00818    NC *ncp;
00819    status = NC_check_id(ncid, &ncp); 
00820    if(status != NC_NOERR) return status;
00821    return ncp->dispatch->_enddef(ncid,0,1,0,1);
00822 }
00823 
00905 int
00906 nc__enddef(int ncid, size_t h_minfree, size_t v_align, size_t v_minfree, 
00907            size_t r_align)
00908 {
00909    NC* ncp;
00910    int stat = NC_check_id(ncid, &ncp);
00911    if(stat != NC_NOERR) return stat;
00912    return ncp->dispatch->_enddef(ncid,h_minfree,v_align,v_minfree,r_align);
00913 }
00914 
00982 int
00983 nc_sync(int ncid)
00984 {
00985    NC* ncp;
00986    int stat = NC_check_id(ncid, &ncp);
00987    if(stat != NC_NOERR) return stat;
00988    return ncp->dispatch->sync(ncid);
00989 }
00990 
01033 int
01034 nc_abort(int ncid)
01035 {
01036    NC* ncp;
01037    int stat = NC_check_id(ncid, &ncp);
01038    if(stat != NC_NOERR) return stat;
01039 
01040 #ifdef USE_REFCOUNT
01041    /* What to do if refcount > 0? */
01042    /* currently, forcibly abort */
01043    ncp->refcount = 0;
01044 #endif
01045 
01046    stat = ncp->dispatch->abort(ncid);
01047    del_from_NCList(ncp);
01048    free_NC(ncp);
01049    return stat;   
01050 }
01051 
01092 int
01093 nc_close(int ncid)
01094 {
01095    NC* ncp;
01096    int stat = NC_check_id(ncid, &ncp);
01097    if(stat != NC_NOERR) return stat;
01098 
01099 #ifdef USE_REFCOUNT
01100    ncp->refcount--;
01101    if(ncp->refcount <= 0)
01102 #endif
01103    {
01104        stat = ncp->dispatch->close(ncid);
01105        /* Remove from the nc list */
01106        del_from_NCList(ncp);
01107        free_NC(ncp);
01108    }
01109    return stat;
01110 }
01111 
01210 int
01211 nc_set_fill(int ncid, int fillmode, int *old_modep)
01212 {
01213    NC* ncp;
01214    int stat = NC_check_id(ncid, &ncp);
01215    if(stat != NC_NOERR) return stat;
01216    return ncp->dispatch->set_fill(ncid,fillmode,old_modep);
01217 }
01218 
01230 int
01231 nc_inq_base_pe(int ncid, int *pe)
01232 {
01233    NC* ncp;
01234    int stat = NC_check_id(ncid, &ncp);
01235    if(stat != NC_NOERR) return stat;
01236    return ncp->dispatch->inq_base_pe(ncid,pe);
01237 }
01238 
01250 int
01251 nc_set_base_pe(int ncid, int pe)
01252 {
01253    NC* ncp;
01254    int stat = NC_check_id(ncid, &ncp);
01255    if(stat != NC_NOERR) return stat;
01256    return ncp->dispatch->set_base_pe(ncid,pe);
01257 }
01258 
01277 int
01278 nc_inq_format(int ncid, int *formatp)
01279 {
01280    NC* ncp;
01281    int stat = NC_check_id(ncid, &ncp);
01282    if(stat != NC_NOERR) return stat;
01283    return ncp->dispatch->inq_format(ncid,formatp);
01284 }
01285 
01311 int
01312 nc_inq_format_extended(int ncid, int *formatp, int *modep)
01313 {
01314    NC* ncp;
01315    int stat = NC_check_id(ncid, &ncp);
01316    if(stat != NC_NOERR) return stat;
01317    return ncp->dispatch->inq_format_extended(ncid,formatp,modep);
01318 }
01319 
01364 int
01365 nc_inq(int ncid, int *ndimsp, int *nvarsp, int *nattsp, int *unlimdimidp)
01366 {
01367    NC* ncp;
01368    int stat = NC_check_id(ncid, &ncp);
01369    if(stat != NC_NOERR) return stat;
01370    return ncp->dispatch->inq(ncid,ndimsp,nvarsp,nattsp,unlimdimidp);
01371 }
01372 
01373 int
01374 nc_inq_nvars(int ncid, int *nvarsp)
01375 {
01376    NC* ncp;
01377    int stat = NC_check_id(ncid, &ncp);
01378    if(stat != NC_NOERR) return stat;
01379    return ncp->dispatch->inq(ncid, NULL, nvarsp, NULL, NULL);
01380 }
01381 
01447 int
01448 nc_inq_type(int ncid, nc_type xtype, char *name, size_t *size)
01449 {
01450    NC* ncp;
01451    /* For compatibility, we need to allow inq about
01452       atomic types, even if ncid is ill-defined */
01453    if(xtype <= ATOMICTYPEMAX) {
01454       if(xtype <= NC_NAT) return NC_EBADTYPE;
01455       if(name) strncpy(name,NC_atomictypename(xtype),NC_MAX_NAME);
01456       if(size) *size = NC_atomictypelen(xtype);
01457       return NC_NOERR;
01458    } else {
01459       int stat = NC_check_id(ncid, &ncp);
01460       if(stat != NC_NOERR) return NC_EBADTYPE; /* compatibility */
01461       return ncp->dispatch->inq_type(ncid,xtype,name,size);
01462    }
01463 }
01500 int
01501 NC_create(const char *path, int cmode, size_t initialsz, 
01502           int basepe, size_t *chunksizehintp, int useparallel, 
01503           void* mpi_info, int *ncidp)
01504 {
01505    int stat = NC_NOERR;
01506    NC* ncp = NULL;
01507    NC_Dispatch* dispatcher = NULL;
01508    /* Need three pieces of information for now */
01509    int model = 0; /* one of the NC_DISPATCH_XXX values */
01510    int isurl = 0;   /* dap or cdmremote or neither */
01511    int xcmode = 0; /* for implied cmode flags */
01512 
01513    /* Initialize the dispatch table. The function pointers in the
01514     * dispatch table will depend on how netCDF was built
01515     * (with/without netCDF-4, DAP, CDMREMOTE). */
01516    if(!nc_initialized)
01517    {
01518       if ((stat = NC_initialize()))
01519          return stat; 
01520       /* Do local initialization */
01521       nc_local_initialize();
01522       nc_initialized = 1;
01523    }
01524 
01525 #ifdef USE_REFCOUNT
01526    /* If this path is already open, then fail */
01527    ncp = find_in_NCList_by_name(path);
01528    if(ncp != NULL)
01529         return NC_ENFILE;   
01530 #endif
01531 
01532    if((isurl = NC_testurl(path)))
01533         model = NC_urlmodel(path);
01534 
01535    /* Look to the incoming cmode for hints */
01536    if(model == 0) {
01537       if(cmode & NC_NETCDF4)
01538         model = NC_DISPATCH_NC4;
01539       else if(cmode & NC_PNETCDF)
01540         model = NC_DISPATCH_NC5;
01541       else if(cmode & NC_CLASSIC_MODEL)
01542         model = NC_DISPATCH_NC3;
01543    }
01544 
01545    if(model == 0) {
01546       /* Check default format */
01547       int format = nc_get_default_format();
01548       switch (format) {
01549 #ifdef USE_NETCDF4
01550          case NC_FORMAT_NETCDF4:
01551             xcmode |= NC_NETCDF4;
01552             model = NC_DISPATCH_NC4;
01553             break;
01554          case NC_FORMAT_NETCDF4_CLASSIC:
01555             xcmode |= NC_CLASSIC_MODEL;
01556             model = NC_DISPATCH_NC4;
01557             break;
01558 #endif
01559          case NC_FORMAT_64BIT:
01560             xcmode |= NC_64BIT_OFFSET;
01561             /* fall thru */
01562          case NC_FORMAT_CLASSIC:
01563          default:
01564             model = NC_DISPATCH_NC3;
01565             break;
01566       }
01567    }
01568    
01569    /* Add inferred flags */
01570    cmode |= xcmode;
01571 
01572 #ifdef USE_NETCDF4
01573    if((cmode & NC_MPIIO && cmode & NC_MPIPOSIX))
01574       return  NC_EINVAL;
01575 #endif
01576 
01577    if (!(dispatcher = NC_get_dispatch_override()))
01578    {
01579 
01580       /* Figure out what dispatcher to use */
01581 #ifdef USE_NETCDF4
01582 #ifdef USE_CDMREMOTE
01583       if(model == (NC_DISPATCH_NC4 | NC_DISPATCH_NCR))
01584          dispatcher = NCCR_dispatch_table;
01585       else
01586 #endif
01587       if(model == (NC_DISPATCH_NC4))
01588         dispatcher = NC4_dispatch_table;
01589       else
01590 #endif /*USE_NETCDF4*/
01591 #ifdef USE_DAP
01592       if(model == (NC_DISPATCH_NC3 | NC_DISPATCH_NCD))
01593         dispatcher = NCD2_dispatch_table;
01594       else
01595 #endif
01596 #ifdef USE_PNETCDF
01597       if(model == (NC_DISPATCH_NC5))
01598         dispatcher = NC5_dispatch_table;
01599       else
01600 #endif
01601       if(model == (NC_DISPATCH_NC3))
01602         dispatcher = NC3_dispatch_table;
01603       else
01604          return NC_ENOTNC;
01605    }
01606 
01607    /* Create the NC* instance and insert its dispatcher */
01608    stat = new_NC(dispatcher,path,cmode,&ncp);
01609    if(stat) return stat;
01610 
01611    /* Add to list of known open files and define ext_ncid */
01612    add_to_NCList(ncp);
01613 
01614 #ifdef USE_REFCOUNT
01615    /* bump the refcount */
01616    ncp->refcount++;
01617 #endif
01618 
01619    /* Assume create will fill in remaining ncp fields */
01620    if ((stat = dispatcher->create(path, cmode, initialsz, basepe, chunksizehintp,
01621                                    useparallel, mpi_info, dispatcher, ncp))) {
01622         del_from_NCList(ncp); /* oh well */
01623         free_NC(ncp);
01624      } else {
01625        if(ncidp)*ncidp = ncp->ext_ncid;
01626      }
01627    return stat;
01628 }
01629 
01645 int
01646 NC_open(const char *path, int cmode,
01647         int basepe, size_t *chunksizehintp,
01648         int useparallel, void* mpi_info,
01649         int *ncidp)
01650 {
01651    int stat = NC_NOERR;
01652    NC* ncp = NULL;
01653    NC_Dispatch* dispatcher = NULL;
01654    /* Need two pieces of information for now */
01655    int model = 0;
01656    int isurl = 0; 
01657    int version = 0;
01658    enum FileType filetype = FT_UNKNOWN;
01659 
01660    if(!nc_initialized) {
01661       stat = NC_initialize();
01662       if(stat) return stat;
01663       /* Do local initialization */
01664       nc_local_initialize();
01665       nc_initialized = 1;
01666    }
01667 
01668 #ifdef USE_REFCOUNT
01669    /* If this path is already open, then bump the refcount and return it */
01670    ncp = find_in_NCList_by_name(path);
01671    if(ncp != NULL) {
01672         ncp->refcount++;
01673         if(ncidp) *ncidp = ncp->ext_ncid;       
01674         return NC_NOERR;
01675    }
01676 #endif
01677 
01678    isurl = NC_testurl(path);
01679    if(isurl)
01680       model = NC_urlmodel(path);
01681    else {
01682       filetype = FT_UNKNOWN;
01683       version = 0;
01684       model = 0;
01685       /* Look at the file if it exists */
01686       stat = NC_check_file_type(path,useparallel,mpi_info,
01687                                 &filetype,&version);
01688       if(stat == NC_NOERR) {
01689         switch (filetype) {
01690         case FT_NC:
01691             if(version == 1 || version == 2)
01692                 model = NC_DISPATCH_NC3;
01693             break;
01694         case FT_HDF:
01695             model = NC_DISPATCH_NC4;
01696             break;
01697         case FT_PNETCDF:
01698             model = NC_DISPATCH_NC5;
01699             break;
01700         default:
01701             return NC_ENOTNC;
01702         }
01703       } else /* presumably not a netcdf file */
01704         return stat;
01705    }
01706 
01707    /* Look to the incoming cmode for hints */
01708    if(model == 0) {
01709       if(cmode & NC_PNETCDF) model |= NC_DISPATCH_NC5;
01710       else if(cmode & NC_NETCDF4) model |= NC_DISPATCH_NC4;
01711    }
01712 
01713    if(model == 0) model = NC_DISPATCH_NC3; /* final default */
01714 
01715    /* Force flag consistentcy */
01716    if(model & NC_DISPATCH_NC4)
01717       cmode |= NC_NETCDF4;
01718    else if(model & NC_DISPATCH_NC3) {
01719       cmode &= ~NC_NETCDF4; /* must be netcdf-3 */
01720       if(version == 2) cmode |= NC_64BIT_OFFSET;
01721    } else if(model & NC_DISPATCH_NC5) {
01722       cmode &= ~(NC_NETCDF4 | NC_64BIT_OFFSET); /* must be pnetcdf */ 
01723       cmode |= NC_PNETCDF;
01724    }
01725 
01726    if((cmode & NC_MPIIO && cmode & NC_MPIPOSIX))
01727       return  NC_EINVAL;
01728 
01729    /* override overrides any other table choice */
01730    dispatcher = NC_get_dispatch_override();
01731    if(dispatcher != NULL) goto havetable;
01732 
01733    /* Figure out what dispatcher to use */
01734 #if  defined(USE_CDMREMOTE)
01735    if(model == (NC_DISPATCH_NC4 | NC_DISPATCH_NCR))
01736         dispatcher = NCCR_dispatch_table;
01737    else
01738 #endif
01739 #if defined(USE_DAP)
01740    if(model == (NC_DISPATCH_NC3 | NC_DISPATCH_NCD))
01741         dispatcher = NCD2_dispatch_table;
01742    else
01743 #endif
01744 #if  defined(USE_PNETCDF)
01745    if(model == (NC_DISPATCH_NC5))
01746         dispatcher = NC5_dispatch_table;
01747    else
01748 #endif
01749 #if defined(USE_NETCDF4)
01750    if(model == (NC_DISPATCH_NC4))
01751         dispatcher = NC4_dispatch_table;
01752    else
01753 #endif
01754    if(model == (NC_DISPATCH_NC3))
01755         dispatcher = NC3_dispatch_table;
01756    else
01757       return  NC_ENOTNC;
01758 
01759 havetable:
01760 
01761    /* Create the NC* instance and insert its dispatcher */
01762    stat = new_NC(dispatcher,path,cmode,&ncp);
01763    if(stat) return stat;
01764 
01765    /* Add to list of known open files */
01766    add_to_NCList(ncp);
01767 
01768 #ifdef USE_REFCOUNT
01769    /* bump the refcount */
01770    ncp->refcount++;
01771 #endif
01772 
01773    /* Assume open will fill in remaining ncp fields */
01774    stat = dispatcher->open(path, cmode, basepe, chunksizehintp,
01775                            useparallel, mpi_info, dispatcher, ncp);
01776    if(stat == NC_NOERR) {
01777      if(ncidp) *ncidp = ncp->ext_ncid;
01778    } else {
01779         del_from_NCList(ncp);
01780         free_NC(ncp);
01781    }
01782    return stat;
01783 }
01784 
01785 /*Provide an internal function for generating pseudo file descriptors
01786   for systems that are not file based (e.g. dap, memio).
01787 */
01788 
01789 /* Static counter for pseudo file descriptors (incremented) */
01790 static int pseudofd = 0;
01791 
01792 /* Create a pseudo file descriptor that does not
01793    overlap real file descriptors
01794 */
01795 int
01796 nc__pseudofd(void)
01797 {
01798     if(pseudofd == 0)  {
01799         int maxfd = 32767; /* default */
01800 #ifdef HAVE_GETRLIMIT
01801         struct rlimit rl;
01802         if(getrlimit(RLIMIT_NOFILE,&rl) == 0) {
01803             if(rl.rlim_max != RLIM_INFINITY)
01804                 maxfd = (int)rl.rlim_max;
01805             if(rl.rlim_cur != RLIM_INFINITY)
01806                 maxfd = (int)rl.rlim_cur;
01807         }
01808         pseudofd = maxfd+1;
01809 #endif
01810     }
01811 
01812     return pseudofd++;
01813 }
01814 
01815 
 All Data Structures Files Functions Variables Typedefs Defines