NetCDF  4.6.0
dfile.c
Go to the documentation of this file.
1 
13 #include "config.h"
14 #include <stdlib.h>
15 #ifdef HAVE_SYS_RESOURCE_H
16 #include <sys/resource.h>
17 #endif
18 #ifdef HAVE_SYS_TYPES_H
19 #include <sys/types.h>
20 #endif
21 #ifdef HAVE_SYS_STAT_H
22 #include <sys/stat.h>
23 #endif
24 #include "ncdispatch.h"
25 #include "netcdf_mem.h"
26 #include "ncwinpath.h"
27 
28 /* If Defined, then use only stdio for all magic number io;
29  otherwise use stdio or mpio as required.
30  */
31 #undef DEBUG
32 
37 struct MagicFile {
38  const char* path;
39  long long filelen;
40  int use_parallel;
41  int inmemory;
42  void* parameters;
43  FILE* fp;
44 #ifdef USE_PARALLEL
45  MPI_File fh;
46 #endif
47 };
48 
49 static int openmagic(struct MagicFile* file);
50 static int readmagic(struct MagicFile* file, long pos, char* magic);
51 static int closemagic(struct MagicFile* file);
52 #ifdef DEBUG
53 static void printmagic(const char* tag, char* magic,struct MagicFile*);
54 #endif
55 
56 extern int NC_initialized;
60 static char HDF5_SIGNATURE[MAGIC_NUMBER_LEN] = "\211HDF\r\n\032\n";
61 
112 static int
113 NC_interpret_magic_number(char* magic, int* model, int* version)
114 {
115  int status = NC_NOERR;
116  /* Look at the magic number */
117  *model = 0;
118  *version = 0;
119 #ifdef USE_NETCDF4
120  /* Use the complete magic number string for HDF5 */
121  if(memcmp(magic,HDF5_SIGNATURE,sizeof(HDF5_SIGNATURE))==0) {
122  *model = NC_FORMATX_NC4;
123  *version = 5; /* redundant */
124  goto done;
125  }
126 #endif
127 #if defined(USE_NETCDF4) && defined(USE_HDF4)
128  if(magic[0] == '\016' && magic[1] == '\003'
129  && magic[2] == '\023' && magic[3] == '\001') {
130  *model = NC_FORMATX_NC_HDF4;
131  *version = 4; /* redundant */
132  goto done;
133  }
134 #endif
135  if(magic[0] == 'C' && magic[1] == 'D' && magic[2] == 'F') {
136  if(magic[3] == '\001') {
137  *version = 1; /* netcdf classic version 1 */
138  *model = NC_FORMATX_NC3;
139  goto done;
140  }
141  if(magic[3] == '\002') {
142  *version = 2; /* netcdf classic version 2 */
143  *model = NC_FORMATX_NC3;
144  goto done;
145  }
146 #ifdef USE_CDF5
147  if(magic[3] == '\005') {
148  *version = 5; /* cdf5 (including pnetcdf) file */
149  *model = NC_FORMATX_NC3;
150  goto done;
151  }
152 #endif
153  }
154  /* No match */
155  status = NC_ENOTNC;
156  goto done;
157 
158 done:
159  return status;
160 }
161 
177 int
178 NC_check_file_type(const char *path, int flags, void *parameters,
179  int* model, int* version)
180 {
181  char magic[MAGIC_NUMBER_LEN];
182  int status = NC_NOERR;
183 
184  int diskless = ((flags & NC_DISKLESS) == NC_DISKLESS);
185 #ifdef USE_PARALLEL
186  int use_parallel = ((flags & NC_MPIIO) == NC_MPIIO);
187 #endif /* USE_PARALLEL */
188  int inmemory = (diskless && ((flags & NC_INMEMORY) == NC_INMEMORY));
189  struct MagicFile file;
190 
191  *model = 0;
192  *version = 0;
193 
194  memset((void*)&file,0,sizeof(file));
195  file.path = path; /* do not free */
196  file.parameters = parameters;
197  if(inmemory && parameters == NULL)
198  {status = NC_EDISKLESS; goto done;}
199  if(inmemory) {
200  file.inmemory = inmemory;
201  goto next;
202  }
203  /* presumably a real file */
204 #ifdef USE_PARALLEL
205  /* for parallel, use the MPI functions instead (why?) */
206  if (use_parallel) {
207  file.use_parallel = use_parallel;
208  goto next;
209  }
210 #endif /* USE_PARALLEL */
211 
212 next:
213  status = openmagic(&file);
214  if(status != NC_NOERR) {goto done;}
215  /* Verify we have a large enough file */
216  if(file.filelen < MAGIC_NUMBER_LEN)
217  {status = NC_ENOTNC; goto done;}
218  if((status = readmagic(&file,0L,magic)) != NC_NOERR) {
219  status = NC_ENOTNC;
220  *model = 0;
221  *version = 0;
222  goto done;
223  }
224  /* Look at the magic number */
225  if(NC_interpret_magic_number(magic,model,version) == NC_NOERR
226  && *model != 0)
227  goto done; /* found something */
228 
229  /* Remaining case is to search forward at starting at 512
230  and doubling to see if we have HDF5 magic number */
231  {
232  long pos = 512L;
233  for(;;) {
234  if((pos+MAGIC_NUMBER_LEN) > file.filelen)
235  {status = NC_ENOTNC; goto done;}
236  if((status = readmagic(&file,pos,magic)) != NC_NOERR)
237  {status = NC_ENOTNC; goto done; }
238  NC_interpret_magic_number(magic,model,version);
239  if(*model == NC_FORMATX_NC4) break;
240  /* double and try again */
241  pos = 2*pos;
242  }
243  }
244 done:
245  closemagic(&file);
246  return status;
247 }
248 
452 int
453 nc_create(const char *path, int cmode, int *ncidp)
454 {
455  return nc__create(path,cmode,NC_SIZEHINT_DEFAULT,NULL,ncidp);
456 }
457 
524 int
525 nc__create(const char *path, int cmode, size_t initialsz,
526  size_t *chunksizehintp, int *ncidp)
527 {
528  return NC_create(path, cmode, initialsz, 0,
529  chunksizehintp, 0, NULL, ncidp);
530 
531 }
551 int
552 nc__create_mp(const char *path, int cmode, size_t initialsz,
553  int basepe, size_t *chunksizehintp, int *ncidp)
554 {
555  return NC_create(path, cmode, initialsz, basepe,
556  chunksizehintp, 0, NULL, ncidp);
557 }
558 
670 int
671 nc_open(const char *path, int mode, int *ncidp)
672 {
673  return NC_open(path, mode, 0, NULL, 0, NULL, ncidp);
674 }
675 
727 int
728 nc__open(const char *path, int mode,
729  size_t *chunksizehintp, int *ncidp)
730 {
731  /* this API is for non-parallel access: TODO check for illegal cmode
732  * flags, such as NC_PNETCDF, NC_MPIIO, or NC_MPIPOSIX, before entering
733  * NC_open()? Note nc_open_par() also calls NC_open().
734  */
735  return NC_open(path, mode, 0, chunksizehintp, 0,
736  NULL, ncidp);
737 }
738 
784 int
785 nc_open_mem(const char* path, int mode, size_t size, void* memory, int* ncidp)
786 {
787 #ifdef USE_DISKLESS
788  NC_MEM_INFO meminfo;
789 
790  /* Sanity checks */
791  if(memory == NULL || size < MAGIC_NUMBER_LEN || path == NULL)
792  return NC_EINVAL;
793  if(mode & (NC_WRITE|NC_MPIIO|NC_MPIPOSIX|NC_MMAP))
794  return NC_EINVAL;
795  mode |= (NC_INMEMORY|NC_DISKLESS);
796  meminfo.size = size;
797  meminfo.memory = memory;
798  return NC_open(path, mode, 0, NULL, 0, &meminfo, ncidp);
799 #else
800  return NC_EDISKLESS;
801 #endif
802 }
803 
822 int
823 nc__open_mp(const char *path, int mode, int basepe,
824  size_t *chunksizehintp, int *ncidp)
825 {
826  return NC_open(path, mode, basepe, chunksizehintp,
827  0, NULL, ncidp);
828 }
829 
847 int
848 nc_inq_path(int ncid, size_t *pathlen, char *path)
849 {
850  NC* ncp;
851  int stat = NC_NOERR;
852  if ((stat = NC_check_id(ncid, &ncp)))
853  return stat;
854  if(ncp->path == NULL) {
855  if(pathlen) *pathlen = 0;
856  if(path) path[0] = '\0';
857  } else {
858  if (pathlen) *pathlen = strlen(ncp->path);
859  if (path) strcpy(path, ncp->path);
860  }
861  return stat;
862 }
863 
912 int
913 nc_redef(int ncid)
914 {
915  NC* ncp;
916  int stat = NC_check_id(ncid, &ncp);
917  if(stat != NC_NOERR) return stat;
918  return ncp->dispatch->redef(ncid);
919 }
920 
976 int
977 nc_enddef(int ncid)
978 {
979  int status = NC_NOERR;
980  NC *ncp;
981  status = NC_check_id(ncid, &ncp);
982  if(status != NC_NOERR) return status;
983  return ncp->dispatch->_enddef(ncid,0,1,0,1);
984 }
985 
1067 int
1068 nc__enddef(int ncid, size_t h_minfree, size_t v_align, size_t v_minfree,
1069  size_t r_align)
1070 {
1071  NC* ncp;
1072  int stat = NC_check_id(ncid, &ncp);
1073  if(stat != NC_NOERR) return stat;
1074  return ncp->dispatch->_enddef(ncid,h_minfree,v_align,v_minfree,r_align);
1075 }
1076 
1144 int
1145 nc_sync(int ncid)
1146 {
1147  NC* ncp;
1148  int stat = NC_check_id(ncid, &ncp);
1149  if(stat != NC_NOERR) return stat;
1150  return ncp->dispatch->sync(ncid);
1151 }
1152 
1196 int
1197 nc_abort(int ncid)
1198 {
1199  NC* ncp;
1200  int stat = NC_check_id(ncid, &ncp);
1201  if(stat != NC_NOERR) return stat;
1202 
1203 #ifdef USE_REFCOUNT
1204  /* What to do if refcount > 0? */
1205  /* currently, forcibly abort */
1206  ncp->refcount = 0;
1207 #endif
1208 
1209  stat = ncp->dispatch->abort(ncid);
1210  del_from_NCList(ncp);
1211  free_NC(ncp);
1212  return stat;
1213 }
1214 
1255 int
1256 nc_close(int ncid)
1257 {
1258  NC* ncp;
1259  int stat = NC_check_id(ncid, &ncp);
1260  if(stat != NC_NOERR) return stat;
1261 
1262 #ifdef USE_REFCOUNT
1263  ncp->refcount--;
1264  if(ncp->refcount <= 0)
1265 #endif
1266  {
1267 
1268  stat = ncp->dispatch->close(ncid);
1269  /* Remove from the nc list */
1270  if (!stat)
1271  {
1272  del_from_NCList(ncp);
1273  free_NC(ncp);
1274  }
1275  }
1276  return stat;
1277 }
1278 
1377 int
1378 nc_set_fill(int ncid, int fillmode, int *old_modep)
1379 {
1380  NC* ncp;
1381  int stat = NC_check_id(ncid, &ncp);
1382  if(stat != NC_NOERR) return stat;
1383  return ncp->dispatch->set_fill(ncid,fillmode,old_modep);
1384 }
1385 
1400 int
1401 nc_inq_base_pe(int ncid, int *pe)
1402 {
1403  NC* ncp;
1404  int stat = NC_check_id(ncid, &ncp);
1405  if(stat != NC_NOERR) return stat;
1406  return ncp->dispatch->inq_base_pe(ncid,pe);
1407 }
1408 
1423 int
1424 nc_set_base_pe(int ncid, int pe)
1425 {
1426  NC* ncp;
1427  int stat = NC_check_id(ncid, &ncp);
1428  if(stat != NC_NOERR) return stat;
1429  return ncp->dispatch->set_base_pe(ncid,pe);
1430 }
1431 
1450 int
1451 nc_inq_format(int ncid, int *formatp)
1452 {
1453  NC* ncp;
1454  int stat = NC_check_id(ncid, &ncp);
1455  if(stat != NC_NOERR) return stat;
1456  return ncp->dispatch->inq_format(ncid,formatp);
1457 }
1458 
1485 int
1486 nc_inq_format_extended(int ncid, int *formatp, int *modep)
1487 {
1488  NC* ncp;
1489  int stat = NC_check_id(ncid, &ncp);
1490  if(stat != NC_NOERR) return stat;
1491  return ncp->dispatch->inq_format_extended(ncid,formatp,modep);
1492 }
1493 
1538 int
1539 nc_inq(int ncid, int *ndimsp, int *nvarsp, int *nattsp, int *unlimdimidp)
1540 {
1541  NC* ncp;
1542  int stat = NC_check_id(ncid, &ncp);
1543  if(stat != NC_NOERR) return stat;
1544  return ncp->dispatch->inq(ncid,ndimsp,nvarsp,nattsp,unlimdimidp);
1545 }
1546 
1557 int
1558 nc_inq_nvars(int ncid, int *nvarsp)
1559 {
1560  NC* ncp;
1561  int stat = NC_check_id(ncid, &ncp);
1562  if(stat != NC_NOERR) return stat;
1563  return ncp->dispatch->inq(ncid, NULL, nvarsp, NULL, NULL);
1564 }
1565 
1631 int
1632 nc_inq_type(int ncid, nc_type xtype, char *name, size_t *size)
1633 {
1634  NC* ncp;
1635  int stat;
1636 
1637  /* Do a quick triage on xtype */
1638  if(xtype <= NC_NAT) return NC_EBADTYPE;
1639  /* For compatibility, we need to allow inq about
1640  atomic types, even if ncid is ill-defined */
1641  if(xtype <= ATOMICTYPEMAX4) {
1642  if(name) strncpy(name,NC_atomictypename(xtype),NC_MAX_NAME);
1643  if(size) *size = NC_atomictypelen(xtype);
1644  return NC_NOERR;
1645  }
1646  /* Apparently asking about a user defined type, so we need
1647  a valid ncid */
1648  stat = NC_check_id(ncid, &ncp);
1649  if(stat != NC_NOERR) /* bad ncid */
1650  return NC_EBADTYPE;
1651  /* have good ncid */
1652  return ncp->dispatch->inq_type(ncid,xtype,name,size);
1653 }
1654 
1671 static int
1673 {
1674  int mode_format;
1675 
1676  /* This is a clever check to see if more than one format bit is
1677  * set. */
1678  mode_format = (mode & NC_NETCDF4) | (mode & NC_64BIT_OFFSET) |
1679  (mode & NC_CDF5);
1680  if (mode_format && (mode_format & (mode_format - 1)))
1681  return NC_EINVAL;
1682 
1683  /* Can't use both NC_MPIIO and NC_MPIPOSIX. Make up your damn
1684  * mind! */
1685  if (mode & NC_MPIIO && mode & NC_MPIPOSIX)
1686  return NC_EINVAL;
1687 
1688  /* Can't use both parallel and diskless. */
1689  if ((mode & NC_MPIIO && mode & NC_DISKLESS) ||
1690  (mode & NC_MPIPOSIX && mode & NC_DISKLESS))
1691  return NC_EINVAL;
1692 
1693 #ifndef USE_DISKLESS
1694  /* If diskless is requested, but not built, return error. */
1695  if (mode & NC_DISKLESS)
1696  return NC_ENOTBUILT;
1697  if (mode & NC_INMEMORY)
1698  return NC_ENOTBUILT;
1699 #endif
1700 
1701 #ifndef USE_NETCDF4
1702  /* If the user asks for a netCDF-4 file, and the library was built
1703  * without netCDF-4, then return an error.*/
1704  if (mode & NC_NETCDF4)
1705  return NC_ENOTBUILT;
1706 #endif /* USE_NETCDF4 undefined */
1707 
1708 #ifndef USE_PARALLEL
1709  /* If parallel support is not included, these mode flags won't
1710  * work. */
1711  if (mode & NC_PNETCDF || mode & NC_MPIPOSIX)
1712  return NC_ENOTBUILT;
1713 #endif /* USE_PARALLEL */
1714 
1715  /* Well I guess there is some sanity in the world after all. */
1716  return NC_NOERR;
1717 }
1718 
1746 int
1747 NC_create(const char *path0, int cmode, size_t initialsz,
1748  int basepe, size_t *chunksizehintp, int useparallel,
1749  void* parameters, int *ncidp)
1750 {
1751  int stat = NC_NOERR;
1752  NC* ncp = NULL;
1753  NC_Dispatch* dispatcher = NULL;
1754  /* Need three pieces of information for now */
1755  int model = NC_FORMATX_UNDEFINED; /* one of the NC_FORMATX values */
1756  int isurl = 0; /* dap or cdmremote or neither */
1757  int xcmode = 0; /* for implied cmode flags */
1758  char* path = NULL;
1759 
1760  TRACE(nc_create);
1761  if(path0 == NULL)
1762  return NC_EINVAL;
1763 
1764  /* Check mode flag for sanity. */
1765  if ((stat = check_create_mode(cmode)))
1766  return stat;
1767 
1768  /* Initialize the dispatch table. The function pointers in the
1769  * dispatch table will depend on how netCDF was built
1770  * (with/without netCDF-4, DAP, CDMREMOTE). */
1771  if(!NC_initialized)
1772  {
1773  if ((stat = nc_initialize()))
1774  return stat;
1775  }
1776 
1777 #ifndef USE_DISKLESS
1778  cmode &= (~ NC_DISKLESS); /* Force off */
1779 #endif
1780 
1781 #ifdef WINPATH
1782  /* Need to do path conversion */
1783  path = NCpathcvt(path0);
1784 #else
1785  path = nulldup(path0);
1786 #endif
1787 
1788 #ifdef USE_REFCOUNT
1789  /* If this path is already open, then fail */
1790  ncp = find_in_NCList_by_name(path);
1791  if(ncp != NULL) {
1792  nullfree(path);
1793  return NC_ENFILE;
1794  }
1795 #endif
1796 
1797  {
1798  char* newpath = NULL;
1799  model = NC_urlmodel(path,cmode,&newpath);
1800  isurl = (model != 0);
1801  if(isurl) {
1802  nullfree(path);
1803  path = newpath;
1804  }
1805  }
1806 
1807  /* Look to the incoming cmode for hints */
1808  if(model == NC_FORMATX_UNDEFINED) {
1809 #ifdef USE_NETCDF4
1810  if((cmode & NC_NETCDF4) == NC_NETCDF4)
1811  model = NC_FORMATX_NC4;
1812  else
1813 #endif
1814 #ifdef USE_PNETCDF
1815  /* pnetcdf is used for parallel io on CDF-1, CDF-2, and CDF-5 */
1816  if((cmode & NC_MPIIO) == NC_MPIIO)
1817  model = NC_FORMATX_PNETCDF;
1818  else
1819 #endif
1820  {}
1821  }
1822  if(model == NC_FORMATX_UNDEFINED) {
1823  /* Check default format (not formatx) */
1824  int format = nc_get_default_format();
1825  switch (format) {
1826 #ifdef USE_NETCDF4
1827  case NC_FORMAT_NETCDF4:
1828  xcmode |= NC_NETCDF4;
1829  model = NC_FORMATX_NC4;
1830  break;
1832  xcmode |= NC_CLASSIC_MODEL;
1833  model = NC_FORMATX_NC4;
1834  break;
1835 #endif
1836 #ifdef USE_CDF5
1837  case NC_FORMAT_CDF5:
1838  xcmode |= NC_64BIT_DATA;
1839  model = NC_FORMATX_NC3;
1840  break;
1841 #endif
1843  xcmode |= NC_64BIT_OFFSET;
1844  model = NC_FORMATX_NC3;
1845  break;
1846  case NC_FORMAT_CLASSIC:
1847  model = NC_FORMATX_NC3;
1848  break;
1849  default:
1850  model = NC_FORMATX_NC3;
1851  break;
1852  }
1853  }
1854 
1855  /* Add inferred flags */
1856  cmode |= xcmode;
1857 
1858  /* Clean up illegal combinations */
1860  cmode &= ~(NC_64BIT_OFFSET); /*NC_64BIT_DATA=>NC_64BIT_OFFSET*/
1861 
1862  if((cmode & NC_MPIIO) && (cmode & NC_MPIPOSIX))
1863  {
1864  nullfree(path);
1865  return NC_EINVAL;
1866  }
1867 
1868  if (dispatcher == NULL)
1869  {
1870 
1871  /* Figure out what dispatcher to use */
1872 #ifdef USE_NETCDF4
1873  if(model == (NC_FORMATX_NC4))
1874  dispatcher = NC4_dispatch_table;
1875  else
1876 #endif /*USE_NETCDF4*/
1877 #ifdef USE_PNETCDF
1878  if(model == (NC_FORMATX_PNETCDF))
1879  dispatcher = NCP_dispatch_table;
1880  else
1881 #endif
1882  if(model == (NC_FORMATX_NC3))
1883  dispatcher = NC3_dispatch_table;
1884  else
1885  {
1886  nullfree(path);
1887  return NC_ENOTNC;
1888  }
1889  }
1890 
1891  /* Create the NC* instance and insert its dispatcher */
1892  stat = new_NC(dispatcher,path,cmode,model,&ncp);
1893  nullfree(path); path = NULL; /* no longer needed */
1894 
1895  if(stat) return stat;
1896 
1897  /* Add to list of known open files and define ext_ncid */
1898  add_to_NCList(ncp);
1899 
1900 #ifdef USE_REFCOUNT
1901  /* bump the refcount */
1902  ncp->refcount++;
1903 #endif
1904 
1905  /* Assume create will fill in remaining ncp fields */
1906  if ((stat = dispatcher->create(ncp->path, cmode, initialsz, basepe, chunksizehintp,
1907  useparallel, parameters, dispatcher, ncp))) {
1908  del_from_NCList(ncp); /* oh well */
1909  free_NC(ncp);
1910  } else {
1911  if(ncidp)*ncidp = ncp->ext_ncid;
1912  }
1913  return stat;
1914 }
1915 
1939 int
1940 NC_open(const char *path0, int cmode, int basepe, size_t *chunksizehintp,
1941  int useparallel, void* parameters, int *ncidp)
1942 {
1943  int stat = NC_NOERR;
1944  NC* ncp = NULL;
1945  NC_Dispatch* dispatcher = NULL;
1946  int inmemory = 0;
1947  int diskless = 0;
1948  /* Need pieces of information for now to decide model*/
1949  int model = 0;
1950  int isurl = 0;
1951  int version = 0;
1952  int flags = 0;
1953  char* path = NULL;
1954 
1955  TRACE(nc_open);
1956  if(!NC_initialized) {
1957  stat = nc_initialize();
1958  if(stat) return stat;
1959  }
1960 
1961  /* Attempt to do file path conversion: note that this will do
1962  nothing if path is a 'file:...' url, so it will need to be
1963  repeated in protocol code: libdap2 and libdap4
1964  */
1965 
1966 #ifndef USE_DISKLESS
1967  /* Clean up cmode */
1968  cmode &= (~ NC_DISKLESS);
1969 #endif
1970 
1971  inmemory = ((cmode & NC_INMEMORY) == NC_INMEMORY);
1972  diskless = ((cmode & NC_DISKLESS) == NC_DISKLESS);
1973 
1974 
1975 #ifdef WINPATH
1976  path = NCpathcvt(path0);
1977 #else
1978  path = nulldup(path0);
1979 #endif
1980 
1981 #ifdef USE_REFCOUNT
1982  /* If this path is already open, then bump the refcount and return it */
1983  ncp = find_in_NCList_by_name(path);
1984  if(ncp != NULL) {
1985  nullfree(path);
1986  ncp->refcount++;
1987  if(ncidp) *ncidp = ncp->ext_ncid;
1988  return NC_NOERR;
1989  }
1990 #endif
1991 
1992  if(!inmemory) {
1993  char* newpath = NULL;
1994  model = NC_urlmodel(path,cmode,&newpath);
1995  isurl = (model != 0);
1996  if(isurl) {
1997  nullfree(path);
1998  path = newpath;
1999  } else
2000  nullfree(newpath);
2001  }
2002  if(model == 0) {
2003  version = 0;
2004  /* Try to find dataset type */
2005  if(useparallel) flags |= NC_MPIIO;
2006  if(inmemory) flags |= NC_INMEMORY;
2007  if(diskless) flags |= NC_DISKLESS;
2008  stat = NC_check_file_type(path,flags,parameters,&model,&version);
2009  if(stat == NC_NOERR) {
2010  if(model == 0) {
2011  nullfree(path);
2012  return NC_ENOTNC;
2013  }
2014  } else {
2015  /* presumably not a netcdf file */
2016  nullfree(path);
2017  return stat;
2018  }
2019  }
2020 
2021  if(model == 0) {
2022  fprintf(stderr,"Model == 0\n");
2023  return NC_ENOTNC;
2024  }
2025 
2026  /* Force flag consistentcy */
2027  if(model == NC_FORMATX_NC4 || model == NC_FORMATX_NC_HDF4 || model == NC_FORMATX_DAP4)
2028  cmode |= NC_NETCDF4;
2029  else if(model == NC_FORMATX_DAP2) {
2030  cmode &= ~NC_NETCDF4;
2031  cmode &= ~NC_PNETCDF;
2032  cmode &= ~NC_64BIT_OFFSET;
2033  } else if(model == NC_FORMATX_NC3) {
2034  cmode &= ~NC_NETCDF4; /* must be netcdf-3 (CDF-1, CDF-2, CDF-5) */
2035  /* User may want to open file using the pnetcdf library */
2036  if(cmode & NC_PNETCDF) {
2037  /* dispatch is determined by cmode, rather than file format */
2038  model = NC_FORMATX_PNETCDF;
2039  }
2040  /* For opening an existing file, flags NC_64BIT_OFFSET and NC_64BIT_DATA
2041  * will be ignored, as the file is already in either CDF-1, 2, or 5
2042  * format. However, below we add the file format info to cmode so the
2043  * internal netcdf file open subroutine knows what file format to open.
2044  * The mode will be saved in ncp->mode, to be used by
2045  * nc_inq_format_extended() to report the file format.
2046  * See NC3_inq_format_extended() in libsrc/nc3internal.c for example.
2047  */
2048  if(version == 2) cmode |= NC_64BIT_OFFSET;
2049  else if(version == 5) {
2050  cmode |= NC_64BIT_DATA;
2051  cmode &= ~(NC_64BIT_OFFSET); /*NC_64BIT_DATA=>NC_64BIT_OFFSET*/
2052  }
2053  } else if(model == NC_FORMATX_PNETCDF) {
2054  cmode &= ~(NC_NETCDF4|NC_64BIT_OFFSET);
2055  cmode |= NC_64BIT_DATA;
2056  }
2057 
2058  /* Invalid to use both NC_MPIIO and NC_MPIPOSIX. Make up your damn
2059  * mind! */
2060  if((cmode & NC_MPIIO && cmode & NC_MPIPOSIX)) {
2061  nullfree(path);
2062  return NC_EINVAL;
2063  }
2064 
2065  /* override any other table choice */
2066  if(dispatcher != NULL) goto havetable;
2067 
2068  /* Figure out what dispatcher to use */
2069 #if defined(ENABLE_DAP)
2070  if(model == (NC_FORMATX_DAP2))
2071  dispatcher = NCD2_dispatch_table;
2072  else
2073 #endif
2074 #if defined(ENABLE_DAP4)
2075  if(model == (NC_FORMATX_DAP4))
2076  dispatcher = NCD4_dispatch_table;
2077  else
2078 #endif
2079 #if defined(USE_PNETCDF)
2080  if(model == (NC_FORMATX_PNETCDF))
2081  dispatcher = NCP_dispatch_table;
2082  else
2083 #endif
2084 #if defined(USE_NETCDF4)
2085  if(model == (NC_FORMATX_NC4) || model == (NC_FORMATX_NC_HDF4))
2086  dispatcher = NC4_dispatch_table;
2087  else
2088 #endif
2089  if(model == (NC_FORMATX_NC3))
2090  dispatcher = NC3_dispatch_table;
2091  else {
2092  nullfree(path);
2093  return NC_ENOTNC;
2094  }
2095 
2096 havetable:
2097 
2098  if(dispatcher == NULL) {
2099  nullfree(path);
2100  return NC_ENOTNC;
2101  }
2102 
2103  /* Create the NC* instance and insert its dispatcher */
2104  stat = new_NC(dispatcher,path,cmode,model,&ncp);
2105  nullfree(path); path = NULL; /* no longer need path */
2106  if(stat) return stat;
2107 
2108  /* Add to list of known open files */
2109  add_to_NCList(ncp);
2110 
2111 #ifdef USE_REFCOUNT
2112  /* bump the refcount */
2113  ncp->refcount++;
2114 #endif
2115 
2116  /* Assume open will fill in remaining ncp fields */
2117  stat = dispatcher->open(ncp->path, cmode, basepe, chunksizehintp,
2118  useparallel, parameters, dispatcher, ncp);
2119  if(stat == NC_NOERR) {
2120  if(ncidp) *ncidp = ncp->ext_ncid;
2121  } else {
2122  del_from_NCList(ncp);
2123  free_NC(ncp);
2124  }
2125  return stat;
2126 }
2127 
2128 /*Provide an internal function for generating pseudo file descriptors
2129  for systems that are not file based (e.g. dap, memio).
2130 */
2131 
2133 static int pseudofd = 0;
2134 
2142 int
2143 nc__pseudofd(void)
2144 {
2145  if(pseudofd == 0) {
2146  int maxfd = 32767; /* default */
2147 #ifdef HAVE_GETRLIMIT
2148  struct rlimit rl;
2149  if(getrlimit(RLIMIT_NOFILE,&rl) == 0) {
2150  if(rl.rlim_max != RLIM_INFINITY)
2151  maxfd = (int)rl.rlim_max;
2152  if(rl.rlim_cur != RLIM_INFINITY)
2153  maxfd = (int)rl.rlim_cur;
2154  }
2155  pseudofd = maxfd+1;
2156 #endif
2157  }
2158  return pseudofd++;
2159 }
2160 
2166 static int
2167 openmagic(struct MagicFile* file)
2168 {
2169  int status = NC_NOERR;
2170  if(file->inmemory) {
2171  /* Get its length */
2172  NC_MEM_INFO* meminfo = (NC_MEM_INFO*)file->parameters;
2173  file->filelen = (long long)meminfo->size;
2174  goto done;
2175  }
2176 #ifdef USE_PARALLEL
2177  if (file->use_parallel) {
2178  MPI_Status mstatus;
2179  int retval;
2180  MPI_Offset size;
2181  MPI_Comm comm = MPI_COMM_WORLD;
2182  MPI_Info info = MPI_INFO_NULL;
2183  if(file->parameters != NULL) {
2184  comm = ((NC_MPI_INFO*)file->parameters)->comm;
2185  info = ((NC_MPI_INFO*)file->parameters)->info;
2186  }
2187  if((retval = MPI_File_open(comm,(char*)file->path,MPI_MODE_RDONLY,info,
2188  &file->fh)) != MPI_SUCCESS)
2189  {status = NC_EPARINIT; goto done;}
2190  /* Get its length */
2191  if((retval=MPI_File_get_size(file->fh, &size)) != MPI_SUCCESS)
2192  {status = NC_EPARINIT; goto done;}
2193  file->filelen = (long long)size;
2194  goto done;
2195  }
2196 #endif /* USE_PARALLEL */
2197  {
2198  if(file->path == NULL || strlen(file->path)==0)
2199  {status = NC_EINVAL; goto done;}
2200 #ifdef _MSC_VER
2201  file->fp = fopen(file->path, "rb");
2202 #else
2203  file->fp = fopen(file->path, "r");
2204 #endif
2205  if(file->fp == NULL)
2206  {status = errno; goto done;}
2207  /* Get its length */
2208  {
2209 #ifdef _MSC_VER
2210  int fd = fileno(file->fp);
2211  __int64 len64 = _filelengthi64(fd);
2212  if(len64 < 0)
2213  {status = errno; goto done;}
2214  file->filelen = (long long)len64;
2215 #else
2216  long size;
2217  if((status = fseek(file->fp, 0L, SEEK_END)) < 0)
2218  {status = errno; goto done;}
2219  size = ftell(file->fp);
2220  file->filelen = (long long)size;
2221 #endif
2222  rewind(file->fp);
2223  }
2224  goto done;
2225  }
2226 
2227 done:
2228  return status;
2229 }
2230 
2231 static int
2232 readmagic(struct MagicFile* file, long pos, char* magic)
2233 {
2234  int status = NC_NOERR;
2235  memset(magic,0,MAGIC_NUMBER_LEN);
2236  if(file->inmemory) {
2237  char* mempos;
2238  NC_MEM_INFO* meminfo = (NC_MEM_INFO*)file->parameters;
2239  if((pos + MAGIC_NUMBER_LEN) > meminfo->size)
2240  {status = NC_EDISKLESS; goto done;}
2241  mempos = ((char*)meminfo->memory) + pos;
2242  memcpy((void*)magic,mempos,MAGIC_NUMBER_LEN);
2243 #ifdef DEBUG
2244  printmagic("XXX: readmagic",magic,file);
2245 #endif
2246  goto done;
2247  }
2248 #ifdef USE_PARALLEL
2249  if (file->use_parallel) {
2250  MPI_Status mstatus;
2251  int retval;
2252  MPI_Offset offset;
2253  offset = pos;
2254  if((retval = MPI_File_seek(file->fh, offset, MPI_SEEK_SET)) != MPI_SUCCESS)
2255  {status = NC_EPARINIT; goto done;}
2256  if((retval = MPI_File_read(file->fh, magic, MAGIC_NUMBER_LEN, MPI_CHAR,
2257  &mstatus)) != MPI_SUCCESS)
2258  {status = NC_EPARINIT; goto done;}
2259  goto done;
2260  }
2261 #endif /* USE_PARALLEL */
2262  {
2263  size_t count;
2264  int i = fseek(file->fp,pos,SEEK_SET);
2265  if(i < 0)
2266  {status = errno; goto done;}
2267  for(i=0;i<MAGIC_NUMBER_LEN;) {/* make sure to read proper # of bytes */
2268  count=fread(&magic[i],1,(MAGIC_NUMBER_LEN-i),file->fp);
2269  if(count == 0 || ferror(file->fp))
2270  {status = errno; goto done;}
2271  i += count;
2272  }
2273  goto done;
2274  }
2275 done:
2276  if(file && file->fp) clearerr(file->fp);
2277  return status;
2278 }
2279 
2289 static int
2290 closemagic(struct MagicFile* file)
2291 {
2292  int status = NC_NOERR;
2293  if(file->inmemory) goto done; /* noop*/
2294 #ifdef USE_PARALLEL
2295  if (file->use_parallel) {
2296  MPI_Status mstatus;
2297  int retval;
2298  if((retval = MPI_File_close(&file->fh)) != MPI_SUCCESS)
2299  {status = NC_EPARINIT; goto done;}
2300  goto done;
2301  }
2302 #endif
2303  {
2304  if(file->fp) fclose(file->fp);
2305  goto done;
2306  }
2307 done:
2308  return status;
2309 }
2310 
2311 #ifdef DEBUG
2312 static void
2313 printmagic(const char* tag, char* magic, struct MagicFile* f)
2314 {
2315  int i;
2316  fprintf(stderr,"%s: inmem=%d ispar=%d magic=",tag,f->inmemory,f->use_parallel);
2317  for(i=0;i<MAGIC_NUMBER_LEN;i++) {
2318  unsigned int c = (unsigned int)magic[i];
2319  c = c & 0x000000FF;
2320  if(c == '\n')
2321  fprintf(stderr," 0x%0x/'\\n'",c);
2322  else if(c == '\r')
2323  fprintf(stderr," 0x%0x/'\\r'",c);
2324  else if(c < ' ')
2325  fprintf(stderr," 0x%0x/'?'",c);
2326  else
2327  fprintf(stderr," 0x%0x/'%c'",c,c);
2328  }
2329  fprintf(stderr,"\n");
2330  fflush(stderr);
2331 }
2332 #endif
#define NC_PNETCDF
Use parallel-netcdf library; alias for NC_MPIIO.
Definition: netcdf.h:159
int nc__open(const char *path, int mode, size_t *chunksizehintp, int *ncidp)
Open a netCDF file with extra performance parameters for the classic library.
Definition: dfile.c:728
#define NC_ENFILE
Too many netcdfs open.
Definition: netcdf.h:323
int NC_initialized
True when dispatch table is initialized.
#define NC_FORMATX_NC4
alias
Definition: netcdf.h:205
#define NC_CLASSIC_MODEL
Enforce classic model on netCDF-4.
Definition: netcdf.h:135
Main header file for in-memory (diskless) functionality.
int nc_redef(int ncid)
Put open netcdf dataset into define mode.
Definition: dfile.c:913
int nc__enddef(int ncid, size_t h_minfree, size_t v_align, size_t v_minfree, size_t r_align)
Leave define mode with performance tuning.
Definition: dfile.c:1068
#define NC_INMEMORY
Read from memory.
Definition: netcdf.h:157
#define NC_MPIIO
Turn on MPI I/O.
Definition: netcdf.h:152
int nc_inq_format(int ncid, int *formatp)
Inquire about the binary format of a netCDF file as presented by the API.
Definition: dfile.c:1451
int nc_inq(int ncid, int *ndimsp, int *nvarsp, int *nattsp, int *unlimdimidp)
Inquire about a file or group.
Definition: dfile.c:1539
int nc_type
The nc_type type is just an int.
Definition: netcdf.h:24
#define NC_64BIT_OFFSET
Use large (64-bit) file offsets.
Definition: netcdf.h:136
int nc_inq_format_extended(int ncid, int *formatp, int *modep)
Obtain more detailed (vis-a-vis nc_inq_format) format information about an open dataset.
Definition: dfile.c:1486
#define NC_ENOTNC
Not a netcdf file.
Definition: netcdf.h:371
#define NC_FORMAT_CDF5
Format specifier for nc_set_default_format() and returned by nc_inq_format.
Definition: netcdf.h:181
#define NC_64BIT_DATA
CDF-5 format: classic model but 64 bit dimensions and sizes.
Definition: netcdf.h:132
#define NC_ENOTBUILT
Attempt to use feature that was not turned on when netCDF was built.
Definition: netcdf.h:453
int nc_close(int ncid)
Close an open netCDF dataset.
Definition: dfile.c:1256
#define NC_EDISKLESS
Error in using diskless access.
Definition: netcdf.h:454
int nc_abort(int ncid)
No longer necessary for user to invoke manually.
Definition: dfile.c:1197
#define NC_EBADTYPE
Not a netcdf data type.
Definition: netcdf.h:357
#define NC_SIZEHINT_DEFAULT
Let nc__create() or nc__open() figure out a suitable buffer size.
Definition: netcdf.h:229
#define NC_EINVAL
Invalid Argument.
Definition: netcdf.h:325
int nc_set_fill(int ncid, int fillmode, int *old_modep)
Change the fill-value mode to improve write performance.
Definition: dfile.c:1378
#define NC_MAX_NAME
Maximum for classic library.
Definition: netcdf.h:265
#define NC_NAT
Not A Type.
Definition: netcdf.h:33
int nc_inq_type(int ncid, nc_type xtype, char *name, size_t *size)
Inquire about a type.
Definition: dfile.c:1632
#define NC_FORMATX_DAP2
Extended format specifier returned by nc_inq_format_extended() Added in version 4.3.1.
Definition: netcdf.h:208
#define NC_FORMATX_NC3
Extended format specifier returned by nc_inq_format_extended() Added in version 4.3.1.
Definition: netcdf.h:203
#define NC_EPARINIT
Error initializing for parallel access.
Definition: netcdf.h:440
#define NC_NETCDF4
Use netCDF-4/HDF5 format.
Definition: netcdf.h:148
int nc__create(const char *path, int cmode, size_t initialsz, size_t *chunksizehintp, int *ncidp)
Create a netCDF file with some extra parameters controlling classic file cacheing.
Definition: dfile.c:525
#define NC_FORMAT_NETCDF4_CLASSIC
Format specifier for nc_set_default_format() and returned by nc_inq_format.
Definition: netcdf.h:177
#define NC_FORMATX_NC_HDF4
netCDF-4 subset of HDF4
Definition: netcdf.h:206
#define NC_FORMAT_NETCDF4
Format specifier for nc_set_default_format() and returned by nc_inq_format.
Definition: netcdf.h:176
#define NC_CDF5
Alias NC_CDF5 to NC_64BIT_DATA.
Definition: netcdf.h:133
#define NC_WRITE
Set read-write access for nc_open().
Definition: netcdf.h:125
int nc_inq_path(int ncid, size_t *pathlen, char *path)
Get the file pathname (or the opendap URL) which was used to open/create the ncid&#39;s file...
Definition: dfile.c:848
#define NC_NOERR
No Error.
Definition: netcdf.h:315
int nc_inq_nvars(int ncid, int *nvarsp)
Learn the number of variables in a file or group.
Definition: dfile.c:1558
#define NC_DISKLESS
Use diskless file.
Definition: netcdf.h:129
static int check_create_mode(int mode)
Check the create mode parameter for sanity.
Definition: dfile.c:1672
int nc_open(const char *path, int mode, int *ncidp)
Open an existing netCDF file.
Definition: dfile.c:671
#define NC_FORMATX_DAP4
Extended format specifier returned by nc_inq_format_extended() Added in version 4.3.1.
Definition: netcdf.h:209
int nc_enddef(int ncid)
Leave define mode.
Definition: dfile.c:977
#define NC_FORMATX_PNETCDF
Extended format specifier returned by nc_inq_format_extended() Added in version 4.3.1.
Definition: netcdf.h:207
int nc_open_mem(const char *path, int mode, size_t size, void *memory, int *ncidp)
Open a netCDF file with the contents taken from a block of memory.
Definition: dfile.c:785
static int NC_interpret_magic_number(char *magic, int *model, int *version)
Interpret the magic number found in the header of a netCDF file.
Definition: dfile.c:113
#define NC_FORMAT_64BIT_OFFSET
Format specifier for nc_set_default_format() and returned by nc_inq_format.
Definition: netcdf.h:174
#define NC_MMAP
Use diskless file with mmap.
Definition: netcdf.h:130
static int closemagic(struct MagicFile *file)
Close the file opened to check for magic number.
Definition: dfile.c:2290
#define NC_FORMATX_UNDEFINED
Extended format specifier returned by nc_inq_format_extended() Added in version 4.3.1.
Definition: netcdf.h:210
#define NC_FORMAT_CLASSIC
Format specifier for nc_set_default_format() and returned by nc_inq_format.
Definition: netcdf.h:168
int nc_sync(int ncid)
Synchronize an open netcdf dataset to disk.
Definition: dfile.c:1145
int nc_create(const char *path, int cmode, int *ncidp)
Create a new netCDF file.
Definition: dfile.c:453
#define NC_MPIPOSIX
Turn on MPI POSIX I/O.
Definition: netcdf.h:155

Return to the Main Unidata NetCDF page.
Generated on Thu Jan 25 2018 21:06:33 for NetCDF. NetCDF is a Unidata library.