NetCDF
4.3.2
|
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