netCDF
4.2.1.1
|
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 static int nc_initialized = 0; 00028 00066 size_t* NC_coord_zero; 00067 size_t* NC_coord_one; 00068 00069 static void 00070 nc_local_initialize(void) 00071 { 00072 int i; 00073 NC_coord_zero = (size_t*)malloc(sizeof(size_t)*NC_MAX_VAR_DIMS); 00074 if(NC_coord_zero == NULL) abort(); 00075 NC_coord_one = (size_t*)malloc(sizeof(size_t)*NC_MAX_VAR_DIMS); 00076 if(NC_coord_one == NULL) abort(); 00077 for(i=0;i<NC_MAX_VAR_DIMS;i++) { 00078 NC_coord_one[i] = 1; 00079 NC_coord_zero[i] = 0; 00080 } 00081 } 00082 00083 static int 00084 NC_check_file_type(const char *path, int use_parallel, void *mpi_info, 00085 int *cdf, int *hdf) 00086 { 00087 char magic[MAGIC_NUMBER_LEN]; 00088 00089 *hdf = 0; *cdf = 0; 00090 00091 /* Get the 4-byte magic from the beginning of the file. Don't use posix 00092 * for parallel, use the MPI functions instead. */ 00093 #ifdef USE_PARALLEL_MPIO 00094 if (use_parallel) 00095 { 00096 MPI_File fh; 00097 MPI_Status status; 00098 int retval; 00099 MPI_Comm comm = 0; 00100 MPI_Info info = 0; 00101 00102 if(mpi_info != NULL) { 00103 comm = ((NC_MPI_INFO*)mpi_info)->comm; 00104 info = ((NC_MPI_INFO*)mpi_info)->info; 00105 } 00106 if((retval = MPI_File_open(comm, (char *)path, MPI_MODE_RDONLY,info, 00107 &fh)) != MPI_SUCCESS) 00108 return NC_EPARINIT; 00109 if((retval = MPI_File_read(fh, magic, MAGIC_NUMBER_LEN, MPI_CHAR, 00110 &status)) != MPI_SUCCESS) 00111 return NC_EPARINIT; 00112 if((retval = MPI_File_close(&fh)) != MPI_SUCCESS) 00113 return NC_EPARINIT; 00114 } else 00115 #endif /* USE_PARALLEL */ 00116 { 00117 FILE *fp; 00118 int i; 00119 00120 if(path == NULL || strlen(path)==0) 00121 return NC_EINVAL; 00122 00123 if (!(fp = fopen(path, "r"))) 00124 return errno; 00125 i = fread(magic, MAGIC_NUMBER_LEN, 1, fp); 00126 fclose(fp); 00127 if(i != 1) 00128 return errno; 00129 } 00130 00131 /* Ignore the first byte for HDF */ 00132 if(magic[1] == 'H' && magic[2] == 'D' && magic[3] == 'F') 00133 *hdf = 5; 00134 else if(magic[0] == '\016' && magic[1] == '\003' 00135 && magic[2] == '\023' && magic[3] == '\001') 00136 *hdf = 4; 00137 else if(magic[0] == 'C' && magic[1] == 'D' && magic[2] == 'F') 00138 { 00139 if(magic[3] == '\001') 00140 *cdf = 1; /* netcdf classic version 1 */ 00141 else if(magic[3] == '\002') 00142 *cdf = 2; /* netcdf classic version 2 */ 00143 } 00144 00145 return NC_NOERR; 00146 } 00147 00344 int 00345 nc_create(const char *path, int cmode, int *ncidp) 00346 { 00347 return nc__create(path,cmode,NC_SIZEHINT_DEFAULT,NULL,ncidp); 00348 } 00349 00411 int 00412 nc__create(const char *path, int cmode, size_t initialsz, 00413 size_t *chunksizehintp, int *ncidp) 00414 { 00415 return NC_create(path, cmode, initialsz, 0, 00416 chunksizehintp, 0, NULL, ncidp); 00417 00418 } 00427 int 00428 nc__create_mp(const char *path, int cmode, size_t initialsz, 00429 int basepe, size_t *chunksizehintp, int *ncidp) 00430 { 00431 return NC_create(path, cmode, initialsz, basepe, 00432 chunksizehintp, 0, NULL, ncidp); 00433 } 00434 00546 int 00547 nc_open(const char *path, int mode, int *ncidp) 00548 { 00549 return NC_open(path, mode, 0, NULL, 0, NULL, ncidp); 00550 } 00551 00603 int 00604 nc__open(const char *path, int mode, 00605 size_t *chunksizehintp, int *ncidp) 00606 { 00607 return NC_open(path, mode, 0, chunksizehintp, 0, 00608 NULL, ncidp); 00609 } 00610 00619 int 00620 nc__open_mp(const char *path, int mode, int basepe, 00621 size_t *chunksizehintp, int *ncidp) 00622 { 00623 return NC_open(path, mode, basepe, chunksizehintp, 00624 0, NULL, ncidp); 00625 } 00626 00644 int 00645 nc_inq_path(int ncid, size_t *pathlen, char *path) 00646 { 00647 NC* ncp; 00648 int stat = NC_NOERR; 00649 if ((stat = NC_check_id(ncid, &ncp))) 00650 return stat; 00651 if(ncp->path == NULL) { 00652 if(pathlen) *pathlen = 0; 00653 if(path) path[0] = '\0'; 00654 } else { 00655 if (pathlen) *pathlen = strlen(ncp->path); 00656 if (path) strcpy(path, ncp->path); 00657 } 00658 return stat; 00659 } 00660 00709 int 00710 nc_redef(int ncid) 00711 { 00712 NC* ncp; 00713 int stat = NC_check_id(ncid, &ncp); 00714 if(stat != NC_NOERR) return stat; 00715 return ncp->dispatch->redef(ncid); 00716 } 00717 00773 int 00774 nc_enddef(int ncid) 00775 { 00776 int status = NC_NOERR; 00777 NC *ncp; 00778 status = NC_check_id(ncid, &ncp); 00779 if(status != NC_NOERR) return status; 00780 return ncp->dispatch->_enddef(ncid,0,1,0,1); 00781 } 00782 00864 int 00865 nc__enddef(int ncid, size_t h_minfree, size_t v_align, size_t v_minfree, 00866 size_t r_align) 00867 { 00868 NC* ncp; 00869 int stat = NC_check_id(ncid, &ncp); 00870 if(stat != NC_NOERR) return stat; 00871 return ncp->dispatch->_enddef(ncid,h_minfree,v_align,v_minfree,r_align); 00872 } 00873 00941 int 00942 nc_sync(int ncid) 00943 { 00944 NC* ncp; 00945 int stat = NC_check_id(ncid, &ncp); 00946 if(stat != NC_NOERR) return stat; 00947 return ncp->dispatch->sync(ncid); 00948 } 00949 00992 int 00993 nc_abort(int ncid) 00994 { 00995 NC* ncp; 00996 int stat = NC_check_id(ncid, &ncp); 00997 if(stat != NC_NOERR) return stat; 00998 if(ncp->path != NULL) free(ncp->path); 00999 ncp->path = NULL; 01000 return ncp->dispatch->abort(ncid); 01001 } 01002 01043 int 01044 nc_close(int ncid) 01045 { 01046 NC* ncp; 01047 int stat = NC_check_id(ncid, &ncp); 01048 if(stat != NC_NOERR) return stat; 01049 return ncp->dispatch->close(ncid); 01050 } 01051 01150 int 01151 nc_set_fill(int ncid, int fillmode, int *old_modep) 01152 { 01153 NC* ncp; 01154 int stat = NC_check_id(ncid, &ncp); 01155 if(stat != NC_NOERR) return stat; 01156 return ncp->dispatch->set_fill(ncid,fillmode,old_modep); 01157 } 01158 01170 int 01171 nc_inq_base_pe(int ncid, int *pe) 01172 { 01173 NC* ncp; 01174 int stat = NC_check_id(ncid, &ncp); 01175 if(stat != NC_NOERR) return stat; 01176 return ncp->dispatch->inq_base_pe(ncid,pe); 01177 } 01178 01190 int 01191 nc_set_base_pe(int ncid, int pe) 01192 { 01193 NC* ncp; 01194 int stat = NC_check_id(ncid, &ncp); 01195 if(stat != NC_NOERR) return stat; 01196 return ncp->dispatch->set_base_pe(ncid,pe); 01197 } 01198 01216 int 01217 nc_inq_format(int ncid, int *formatp) 01218 { 01219 NC* ncp; 01220 int stat = NC_check_id(ncid, &ncp); 01221 if(stat != NC_NOERR) return stat; 01222 return ncp->dispatch->inq_format(ncid,formatp); 01223 } 01224 01269 int 01270 nc_inq(int ncid, int *ndimsp, int *nvarsp, int *nattsp, int *unlimdimidp) 01271 { 01272 NC* ncp; 01273 int stat = NC_check_id(ncid, &ncp); 01274 if(stat != NC_NOERR) return stat; 01275 return ncp->dispatch->inq(ncid,ndimsp,nvarsp,nattsp,unlimdimidp); 01276 } 01277 01278 int 01279 nc_inq_nvars(int ncid, int *nvarsp) 01280 { 01281 NC* ncp; 01282 int stat = NC_check_id(ncid, &ncp); 01283 if(stat != NC_NOERR) return stat; 01284 return ncp->dispatch->inq(ncid, NULL, nvarsp, NULL, NULL); 01285 } 01286 01352 int 01353 nc_inq_type(int ncid, nc_type xtype, char *name, size_t *size) 01354 { 01355 NC* ncp; 01356 /* For compatibility, we need to allow inq about 01357 atomic types, even if ncid is ill-defined */ 01358 if(xtype <= ATOMICTYPEMAX) { 01359 if(xtype <= NC_NAT) return NC_EBADTYPE; 01360 if(name) strncpy(name,NC_atomictypename(xtype),NC_MAX_NAME); 01361 if(size) *size = NC_atomictypelen(xtype); 01362 return NC_NOERR; 01363 } else { 01364 int stat = NC_check_id(ncid, &ncp); 01365 if(stat != NC_NOERR) return NC_EBADTYPE; /* compatibility */ 01366 return ncp->dispatch->inq_type(ncid,xtype,name,size); 01367 } 01368 } 01405 int 01406 NC_create(const char *path, int cmode, size_t initialsz, 01407 int basepe, size_t *chunksizehintp, int useparallel, 01408 void* mpi_info, int *ncidp) 01409 { 01410 int stat = NC_NOERR; 01411 NC* ncp = NULL; 01412 NC_Dispatch* dispatcher = NULL; 01413 /* Need three pieces of information for now */ 01414 int model = 0; /* one of the NC_DISPATCH_XXX values */ 01415 int isurl = 0; /* dap or cdmremote or neither */ 01416 int xcmode = 0; /* for implied cmode flags */ 01417 extern int default_create_format; 01418 01419 /* Initialize the dispatch table. The function pointers in the 01420 * dispatch table will depend on how netCDF was built 01421 * (with/without netCDF-4, DAP, CDMREMOTE). */ 01422 if(!nc_initialized) 01423 { 01424 if ((stat = NC_initialize())) 01425 return stat; 01426 /* Do local initialization */ 01427 nc_local_initialize(); 01428 nc_initialized = 1; 01429 } 01430 01431 if((isurl = NC_testurl(path))) 01432 model = NC_urlmodel(path); 01433 01434 /* Look to the incoming cmode for hints */ 01435 if(model == 0) { 01436 if(cmode & NC_NETCDF4 || cmode & NC_PNETCDF) 01437 model = NC_DISPATCH_NC4; 01438 } 01439 01440 if(model == 0) { 01441 /* Check default format */ 01442 int format = default_create_format; 01443 switch (format) { 01444 #ifdef USE_NETCDF4 01445 case NC_FORMAT_NETCDF4: 01446 xcmode |= NC_NETCDF4; 01447 model = NC_DISPATCH_NC4; 01448 break; 01449 case NC_FORMAT_NETCDF4_CLASSIC: 01450 xcmode |= NC_CLASSIC_MODEL; 01451 model = NC_DISPATCH_NC4; 01452 break; 01453 #endif 01454 case NC_FORMAT_64BIT: 01455 xcmode |= NC_64BIT_OFFSET; 01456 /* fall thru */ 01457 case NC_FORMAT_CLASSIC: 01458 default: 01459 model = NC_DISPATCH_NC3; 01460 break; 01461 } 01462 } 01463 01464 /* Add inferred flags */ 01465 cmode |= xcmode; 01466 01467 #ifdef USE_NETCDF4 01468 if((cmode & NC_MPIIO && cmode & NC_MPIPOSIX)) 01469 return NC_EINVAL; 01470 #endif 01471 01472 if (!(dispatcher = NC_get_dispatch_override())) 01473 { 01474 01475 /* Figure out what dispatcher to use */ 01476 #ifdef USE_NETCDF4 01477 #ifdef USE_CDMREMOTE 01478 if(model == (NC_DISPATCH_NC4 | NC_DISPATCH_NCR)) 01479 dispatcher = NCCR_dispatch_table; 01480 else 01481 #endif 01482 if(model == (NC_DISPATCH_NC4)) 01483 dispatcher = NC4_dispatch_table; 01484 else 01485 #endif /*USE_NETCDF4*/ 01486 #ifdef USE_DAP 01487 if(model == (NC_DISPATCH_NC3 | NC_DISPATCH_NCD)) 01488 dispatcher = NCD3_dispatch_table; 01489 else 01490 #endif 01491 if(model == (NC_DISPATCH_NC3)) 01492 dispatcher = NC3_dispatch_table; 01493 else 01494 return NC_ENOTNC; 01495 } 01496 01497 if ((stat = dispatcher->create(path, cmode, initialsz, basepe, chunksizehintp, 01498 useparallel, mpi_info, dispatcher, &ncp))) 01499 return stat; 01500 01501 ncp->dispatch = dispatcher; 01502 if(ncidp) 01503 *ncidp = ncp->ext_ncid; 01504 if (!(ncp->path = nulldup(path))) 01505 return NC_ENOMEM; 01506 return NC_NOERR; 01507 } 01508 01524 int 01525 NC_open(const char *path, int cmode, 01526 int basepe, size_t *chunksizehintp, 01527 int useparallel, void* mpi_info, 01528 int *ncidp) 01529 { 01530 int stat = NC_NOERR; 01531 NC* ncp = NULL; 01532 NC_Dispatch* dispatcher = NULL; 01533 /* Need two pieces of information for now */ 01534 int model = 0; 01535 int isurl = 0; 01536 int cdfversion = 0; 01537 int hdfversion = 0; 01538 extern int default_create_format; 01539 01540 if(!nc_initialized) { 01541 stat = NC_initialize(); 01542 if(stat) return stat; 01543 /* Do local initialization */ 01544 nc_local_initialize(); 01545 nc_initialized = 1; 01546 } 01547 01548 isurl = NC_testurl(path); 01549 if(isurl) 01550 model = NC_urlmodel(path); 01551 01552 if(!isurl) { 01553 /* Look at the file if it exists */ 01554 stat = NC_check_file_type(path,useparallel,mpi_info,&cdfversion,&hdfversion); 01555 if(stat == NC_NOERR) { 01556 if(hdfversion != 0) { 01557 model = NC_DISPATCH_NC4; 01558 } else if(cdfversion != 0) { 01559 model = NC_DISPATCH_NC3; 01560 } 01561 } 01562 /* else ignore the file */ 01563 } 01564 01565 /* Look to the incoming cmode for hints */ 01566 if(model == 0) { 01567 if(cmode & NC_NETCDF4 || cmode & NC_PNETCDF) model |= NC_DISPATCH_NC4; 01568 } 01569 01570 if(model == 0) model = NC_DISPATCH_NC3; /* final default */ 01571 01572 /* Force flag consistentcy */ 01573 if(model & NC_DISPATCH_NC4) 01574 cmode |= NC_NETCDF4; 01575 else if(model & NC_DISPATCH_NC3) { 01576 cmode &= ~NC_NETCDF4; /* must be netcdf-3 */ 01577 if(cdfversion == 2) cmode |= NC_64BIT_OFFSET; 01578 } 01579 01580 if((cmode & NC_MPIIO && cmode & NC_MPIPOSIX)) 01581 return NC_EINVAL; 01582 01583 /* override overrides any other table choice */ 01584 dispatcher = NC_get_dispatch_override(); 01585 if(dispatcher != NULL) goto havetable; 01586 01587 /* Figure out what dispatcher to use */ 01588 #if defined(USE_CDMREMOTE) 01589 if(model == (NC_DISPATCH_NC4 | NC_DISPATCH_NCR)) 01590 dispatcher = NCCR_dispatch_table; 01591 else 01592 #endif 01593 #if defined(USE_DAP) 01594 if(model == (NC_DISPATCH_NC3 | NC_DISPATCH_NCD)) 01595 dispatcher = NCD3_dispatch_table; 01596 else 01597 #endif 01598 #if defined(USE_NETCDF4) 01599 if(model == (NC_DISPATCH_NC4)) 01600 dispatcher = NC4_dispatch_table; 01601 else 01602 #endif 01603 if(model == (NC_DISPATCH_NC3)) 01604 dispatcher = NC3_dispatch_table; 01605 else 01606 return NC_ENOTNC; 01607 01608 havetable: 01609 stat = dispatcher->open(path, cmode, basepe, chunksizehintp, 01610 useparallel, mpi_info, dispatcher, &ncp); 01611 if(stat == NC_NOERR) { 01612 ncp->dispatch = dispatcher; 01613 if(ncidp) *ncidp = ncp->ext_ncid; 01614 ncp->path = nulldup(path); 01615 if(path == NULL) stat = NC_ENOMEM; 01616 } 01617 return stat; 01618 } 01619 01620 /*Provide an internal function for generating pseudo file descriptors 01621 for systems that are not file based (e.g. dap, memio). 01622 */ 01623 01624 /* Static counter for pseudo file descriptors (incremented) */ 01625 static int pseudofd = 0; 01626 01627 /* Create a pseudo file descriptor that does not 01628 overlap real file descriptors 01629 */ 01630 int 01631 nc__pseudofd(void) 01632 { 01633 if(pseudofd == 0) { 01634 int maxfd = 32767; /* default */ 01635 #ifdef HAVE_GETRLIMIT 01636 struct rlimit rl; 01637 if(getrlimit(RLIMIT_NOFILE,&rl) == 0) { 01638 if(rl.rlim_max != RLIM_INFINITY) 01639 maxfd = rl.rlim_max; 01640 if(rl.rlim_cur != RLIM_INFINITY) 01641 maxfd = rl.rlim_cur; 01642 } 01643 pseudofd = maxfd+1; 01644 #endif 01645 } 01646 01647 return pseudofd++; 01648 } 01649 01650