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

Return to the Main Unidata NetCDF page.
Generated on Wed Aug 1 2018 05:36:48 for NetCDF. NetCDF is a Unidata library.