1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 2579 2580 2581 2582 2583 2584 2585 2586 2587 2588 2589 2590 2591 2592 2593 2594 2595 2596 2597 2598 2599 2600 2601 2602 2603 2604 2605 2606 2607 2608 2609 2610 2611 2612 2613 2614 2615 2616 2617 2618 2619 2620 2621 2622 2623 2624 2625 2626 2627 2628
|
/**
* @file
*
* File create and open functions
*
* These functions end up calling functions in one of the dispatch
* layers (netCDF-4, dap server, etc).
*
* Copyright 2010 University Corporation for Atmospheric
* Research/Unidata. See COPYRIGHT file for more info.
*/
#include "config.h"
#include <stdlib.h>
#ifdef HAVE_SYS_RESOURCE_H
#include <sys/resource.h>
#endif
#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
#ifdef HAVE_SYS_STAT_H
#include <sys/stat.h>
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h> /* lseek() */
#endif
#include "ncdispatch.h"
#include "netcdf_mem.h"
#include "ncwinpath.h"
#include "fbits.h"
/* If Defined, then use only stdio for all magic number io;
otherwise use stdio or mpio as required.
*/
#undef DEBUG
/**
Sort info for open/read/close of
file when searching for magic numbers
*/
struct MagicFile {
const char* path;
long long filelen;
int use_parallel;
int inmemory;
int diskless;
void* parameters; /* !NULL if inmemory && !diskless */
FILE* fp;
#ifdef USE_PARALLEL
MPI_File fh;
#endif
};
static int openmagic(struct MagicFile* file);
static int readmagic(struct MagicFile* file, long pos, char* magic);
static int closemagic(struct MagicFile* file);
#ifdef DEBUG
static void printmagic(const char* tag, char* magic,struct MagicFile*);
#endif
extern int NC_initialized; /**< True when dispatch table is initialized. */
/** @internal Magic number for HDF5 files. To be consistent with
* H5Fis_hdf5, use the complete HDF5 magic number */
static char HDF5_SIGNATURE[MAGIC_NUMBER_LEN] = "\211HDF\r\n\032\n";
#ifdef USE_NETCDF4
/* User-defined formats. */
NC_Dispatch *UDF0_dispatch_table = NULL;
char UDF0_magic_number[NC_MAX_MAGIC_NUMBER_LEN + 1] = "";
NC_Dispatch *UDF1_dispatch_table = NULL;
char UDF1_magic_number[NC_MAX_MAGIC_NUMBER_LEN + 1] = "";
#endif /* USE_NETCDF4 */
/** \defgroup datasets NetCDF File and Data I/O
NetCDF opens datasets as files or remote access URLs.
A netCDF dataset that has not yet been opened can only be referred to
by its dataset name. Once a netCDF dataset is opened, it is referred
to by a netCDF ID, which is a small non-negative integer returned when
you create or open the dataset. A netCDF ID is much like a file
descriptor in C or a logical unit number in FORTRAN. In any single
program, the netCDF IDs of distinct open netCDF datasets are
distinct. A single netCDF dataset may be opened multiple times and
will then have multiple distinct netCDF IDs; however at most one of
the open instances of a single netCDF dataset should permit
writing. When an open netCDF dataset is closed, the ID is no longer
associated with a netCDF dataset.
Functions that deal with the netCDF library include:
- Get version of library.
- Get error message corresponding to a returned error code.
The operations supported on a netCDF dataset as a single object are:
- Create, given dataset name and whether to overwrite or not.
- Open for access, given dataset name and read or write intent.
- Put into define mode, to add dimensions, variables, or attributes.
- Take out of define mode, checking consistency of additions.
- Close, writing to disk if required.
- Inquire about the number of dimensions, number of variables,
number of global attributes, and ID of the unlimited dimension, if
any.
- Synchronize to disk to make sure it is current.
- Set and unset nofill mode for optimized sequential writes.
- After a summary of conventions used in describing the netCDF
interfaces, the rest of this chapter presents a detailed description
of the interfaces for these operations.
*/
#ifdef USE_NETCDF4
/**
* Add handling of user-defined format.
*
* @param mode_flag NC_UDF0 or NC_UDF1
* @param dispatch_table Pointer to dispatch table to use for this user format.
* @param magic_number Magic number used to identify file. Ignored if
* NULL.
*
* @return ::NC_NOERR No error.
* @return ::NC_EINVAL Invalid input.
* @author Ed Hartnett
* @ingroup datasets
*/
int
nc_def_user_format(int mode_flag, NC_Dispatch *dispatch_table, char *magic_number)
{
/* Check inputs. */
if (mode_flag != NC_UDF0 && mode_flag != NC_UDF1)
return NC_EINVAL;
if (!dispatch_table)
return NC_EINVAL;
if (magic_number && strlen(magic_number) > NC_MAX_MAGIC_NUMBER_LEN)
return NC_EINVAL;
/* Retain a pointer to the dispatch_table and a copy of the magic
* number, if one was provided. */
switch(mode_flag)
{
case NC_UDF0:
UDF0_dispatch_table = dispatch_table;
if (magic_number)
strncpy(UDF0_magic_number, magic_number, NC_MAX_MAGIC_NUMBER_LEN);
break;
case NC_UDF1:
UDF1_dispatch_table = dispatch_table;
if (magic_number)
strncpy(UDF1_magic_number, magic_number, NC_MAX_MAGIC_NUMBER_LEN);
break;
}
return NC_NOERR;
}
/**
* Inquire about user-defined format.
*
* @param mode_flag NC_UDF0 or NC_UDF1
* @param dispatch_table Pointer that gets pointer to dispatch table
* to use for this user format, or NULL if this user-defined format is
* not defined. Ignored if NULL.
* @param magic_number Pointer that gets magic number used to identify
* file, if one has been set. Magic number will be of max size
* NC_MAX_MAGIC_NUMBER_LEN. Ignored if NULL.
*
* @return ::NC_NOERR No error.
* @return ::NC_EINVAL Invalid input.
* @author Ed Hartnett
* @ingroup datasets
*/
int
nc_inq_user_format(int mode_flag, NC_Dispatch **dispatch_table, char *magic_number)
{
/* Check inputs. */
if (mode_flag != NC_UDF0 && mode_flag != NC_UDF1)
return NC_EINVAL;
switch(mode_flag)
{
case NC_UDF0:
if (dispatch_table)
*dispatch_table = UDF0_dispatch_table;
if (magic_number)
strncpy(magic_number, UDF0_magic_number, NC_MAX_MAGIC_NUMBER_LEN);
break;
case NC_UDF1:
if (dispatch_table)
*dispatch_table = UDF1_dispatch_table;
if (magic_number)
strncpy(magic_number, UDF1_magic_number, NC_MAX_MAGIC_NUMBER_LEN);
break;
}
return NC_NOERR;
}
#endif /* USE_NETCDF4 */
/*!
Interpret the magic number found in the header of a netCDF file.
This function interprets the magic number/string contained in the header of a netCDF file and sets the appropriate NC_FORMATX flags.
@param[in] magic Pointer to a character array with the magic number block.
@param[out] model Pointer to an integer to hold the corresponding netCDF type.
@param[out] version Pointer to an integer to hold the corresponding netCDF version.
@returns NC_NOERR if a legitimate file type found
@returns NC_ENOTNC otherwise
\internal
\ingroup datasets
*/
static int
NC_interpret_magic_number(char* magic, int* model, int* version)
{
int status = NC_NOERR;
/* Look at the magic number */
*model = 0;
*version = 0;
#ifdef USE_NETCDF4
if (strlen(UDF0_magic_number) && !strncmp(UDF0_magic_number, magic,
strlen(UDF0_magic_number)))
{
*model = NC_FORMATX_UDF0;
*version = 6; /* redundant */
goto done;
}
if (strlen(UDF1_magic_number) && !strncmp(UDF1_magic_number, magic,
strlen(UDF1_magic_number)))
{
*model = NC_FORMATX_UDF1;
*version = 7; /* redundant */
goto done;
}
#endif /* USE_NETCDF4 */
/* Use the complete magic number string for HDF5 */
if(memcmp(magic,HDF5_SIGNATURE,sizeof(HDF5_SIGNATURE))==0) {
*model = NC_FORMATX_NC4;
*version = 5; /* redundant */
goto done;
}
if(magic[0] == '\016' && magic[1] == '\003'
&& magic[2] == '\023' && magic[3] == '\001') {
*model = NC_FORMATX_NC_HDF4;
*version = 4; /* redundant */
goto done;
}
if(magic[0] == 'C' && magic[1] == 'D' && magic[2] == 'F') {
if(magic[3] == '\001') {
*version = 1; /* netcdf classic version 1 */
*model = NC_FORMATX_NC3;
goto done;
}
if(magic[3] == '\002') {
*version = 2; /* netcdf classic version 2 */
*model = NC_FORMATX_NC3;
goto done;
}
if(magic[3] == '\005') {
*version = 5; /* cdf5 file */
*model = NC_FORMATX_NC3;
goto done;
}
}
/* No match */
status = NC_ENOTNC;
goto done;
done:
return status;
}
/**
* @internal Given an existing file, figure out its format and return
* that format value (NC_FORMATX_XXX) in model arg. Assume any path
* conversion was already performed at a higher level.
*
* @param path File name.
* @param flags
* @param use_parallel
* @param parameters
* @param model Pointer that gets the model to use for the dispatch table.
* @param version Pointer that gets version of the file.
*
* @return ::NC_NOERR No error.
* @author Dennis Heimbigner
*/
static int
NC_check_file_type(const char *path, int flags, int use_parallel,
void *parameters, int* model, int* version)
{
char magic[MAGIC_NUMBER_LEN];
int status = NC_NOERR;
int diskless = ((flags & NC_DISKLESS) == NC_DISKLESS);
int inmemory = ((flags & NC_INMEMORY) == NC_INMEMORY);
int mmap = ((flags & NC_MMAP) == NC_MMAP);
struct MagicFile file;
*model = 0;
*version = 0;
/* NC_INMEMORY and NC_DISKLESS and NC_MMAP are all mutually exclusive */
if(diskless && inmemory) {status = NC_EDISKLESS; goto done;}
if(diskless && mmap) {status = NC_EDISKLESS; goto done;}
if(inmemory && mmap) {status = NC_EINMEMORY; goto done;}
/* mmap is not allowed for netcdf-4 */
if(mmap && (flags & NC_NETCDF4)) {status = NC_EINVAL; goto done;}
memset((void*)&file,0,sizeof(file));
file.path = path; /* do not free */
file.parameters = parameters;
file.inmemory = inmemory;
file.diskless = diskless;
file.use_parallel = use_parallel;
status = openmagic(&file);
if(status != NC_NOERR) {goto done;}
/* Verify we have a large enough file */
if(file.filelen < MAGIC_NUMBER_LEN)
{status = NC_ENOTNC; goto done;}
if((status = readmagic(&file,0L,magic)) != NC_NOERR) {
status = NC_ENOTNC;
*model = 0;
*version = 0;
goto done;
}
/* Look at the magic number */
if(NC_interpret_magic_number(magic,model,version) == NC_NOERR
&& *model != 0) {
if (*model == NC_FORMATX_NC3 && use_parallel)
/* this is called from nc_open_par() and file is classic */
*model = NC_FORMATX_PNETCDF;
goto done; /* found something */
}
/* Remaining case is to search forward at starting at 512
and doubling to see if we have HDF5 magic number */
{
long pos = 512L;
for(;;) {
if((pos+MAGIC_NUMBER_LEN) > file.filelen)
{status = NC_ENOTNC; goto done;}
if((status = readmagic(&file,pos,magic)) != NC_NOERR)
{status = NC_ENOTNC; goto done; }
NC_interpret_magic_number(magic,model,version);
if(*model == NC_FORMATX_NC4) break;
/* double and try again */
pos = 2*pos;
}
}
done:
closemagic(&file);
return status;
}
/** \ingroup datasets
Create a new netCDF file.
This function creates a new netCDF dataset, returning a netCDF ID that
can subsequently be used to refer to the netCDF dataset in other
netCDF function calls. The new netCDF dataset opened for write access
and placed in define mode, ready for you to add dimensions, variables,
and attributes.
\param path The file name of the new netCDF dataset.
\param cmode The creation mode flag. The following flags are available:
NC_CLOBBER (overwrite existing file),
NC_NOCLOBBER (do not overwrite existing file),
NC_SHARE (limit write caching - netcdf classic files only),
NC_64BIT_OFFSET (create 64-bit offset file),
NC_64BIT_DATA (alias NC_CDF5) (create CDF-5 file),
NC_NETCDF4 (create netCDF-4/HDF5 file),
NC_CLASSIC_MODEL (enforce netCDF classic mode on netCDF-4/HDF5 files),
NC_DISKLESS (store data in memory), and
NC_PERSIST (force the NC_DISKLESS data from memory to a file),
NC_MMAP (use MMAP for NC_DISKLESS instead of NC_INMEMORY -- deprecated).
See discussion below.
\param ncidp Pointer to location where returned netCDF ID is to be
stored.
<h2>The cmode Flag</h2>
The cmode flag is used to control the type of file created, and some
aspects of how it may be used.
Setting NC_NOCLOBBER means you do not want to clobber (overwrite) an
existing dataset; an error (NC_EEXIST) is returned if the specified
dataset already exists.
The NC_SHARE flag is appropriate when one process may be writing the
dataset and one or more other processes reading the dataset
concurrently; it means that dataset accesses are not buffered and
caching is limited. Since the buffering scheme is optimized for
sequential access, programs that do not access data sequentially may
see some performance improvement by setting the NC_SHARE flag. This
flag is ignored for netCDF-4 files.
Setting NC_64BIT_OFFSET causes netCDF to create a 64-bit offset format
file, instead of a netCDF classic format file. The 64-bit offset
format imposes far fewer restrictions on very large (i.e. over 2 GB)
data files. See Large File Support.
Setting NC_64BIT_DATA (alias NC_CDF5) causes netCDF to create a CDF-5
file format that supports large files (i.e. over 2GB) and large
variables (over 2B array elements.). See Large File Support.
A zero value (defined for convenience as NC_CLOBBER) specifies the
default behavior: overwrite any existing dataset with the same file
name and buffer and cache accesses for efficiency. The dataset will be
in netCDF classic format. See NetCDF Classic Format Limitations.
Setting NC_NETCDF4 causes netCDF to create a HDF5/NetCDF-4 file.
Setting NC_CLASSIC_MODEL causes netCDF to enforce the classic data
model in this file. (This only has effect for netCDF-4/HDF5 files, as
CDF-1, 2 and 5 files always use the classic model.) When
used with NC_NETCDF4, this flag ensures that the resulting
netCDF-4/HDF5 file may never contain any new constructs from the
enhanced data model. That is, it cannot contain groups, user defined
types, multiple unlimited dimensions, or new atomic types. The
advantage of this restriction is that such files are guaranteed to
work with existing netCDF software.
Setting NC_DISKLESS causes netCDF to create the file only in
memory and to optionally write the final contents to the
correspondingly named disk file. This allows for the use of
files that have no long term purpose. Operating on an existing file
in memory may also be faster. The decision on whether
or not to "persist" the memory contents to a disk file is
described in detail in the file docs/inmemory.md, which is
definitive. By default, closing a diskless fill will cause it's
contents to be lost.
If NC_DISKLESS is going to be used for creating a large classic
file, it behooves one to use nc__create and specify an
appropriately large value of the initialsz parameter to avoid to
many extensions to the in-memory space for the file. This flag
applies to files in classic format and to file in extended
format (netcdf-4).
Note that nc_create(path,cmode,ncidp) is equivalent to the invocation of
nc__create(path,cmode,NC_SIZEHINT_DEFAULT,NULL,ncidp).
\returns ::NC_NOERR No error.
\returns ::NC_EEXIST Specifying a file name of a file that exists and also specifying NC_NOCLOBBER.
\returns ::NC_EPERM Attempting to create a netCDF file in a directory where you do not have permission to create files.
\returns ::NC_ENOMEM System out of memory.
\returns ::NC_ENFILE Too many files open.
\returns ::NC_EHDFERR HDF5 error (netCDF-4 files only).
\returns ::NC_EFILEMETA Error writing netCDF-4 file-level metadata in
HDF5 file. (netCDF-4 files only).
\returns ::NC_EDISKLESS if there was an error in creating the
in-memory file.
\note When creating a netCDF-4 file HDF5 error reporting is turned
off, if it is on. This doesn't stop the HDF5 error stack from
recording the errors, it simply stops their display to the user
through stderr.
<h1>Examples</h1>
In this example we create a netCDF dataset named foo.nc; we want the
dataset to be created in the current directory only if a dataset with
that name does not already exist:
@code
#include <netcdf.h>
...
int status = NC_NOERR;
int ncid;
...
status = nc_create("foo.nc", NC_NOCLOBBER, &ncid);
if (status != NC_NOERR) handle_error(status);
@endcode
In this example we create a netCDF dataset named foo_large.nc. It will
be in the 64-bit offset format.
@code
#include <netcdf.h>
...
int status = NC_NOERR;
int ncid;
...
status = nc_create("foo_large.nc", NC_NOCLOBBER|NC_64BIT_OFFSET, &ncid);
if (status != NC_NOERR) handle_error(status);
@endcode
In this example we create a netCDF dataset named foo_HDF5.nc. It will
be in the HDF5 format.
@code
#include <netcdf.h>
...
int status = NC_NOERR;
int ncid;
...
status = nc_create("foo_HDF5.nc", NC_NOCLOBBER|NC_NETCDF4, &ncid);
if (status != NC_NOERR) handle_error(status);
@endcode
In this example we create a netCDF dataset named
foo_HDF5_classic.nc. It will be in the HDF5 format, but will not allow
the use of any netCDF-4 advanced features. That is, it will conform to
the classic netCDF-3 data model.
@code
#include <netcdf.h>
...
int status = NC_NOERR;
int ncid;
...
status = nc_create("foo_HDF5_classic.nc", NC_NOCLOBBER|NC_NETCDF4|NC_CLASSIC_MODEL, &ncid);
if (status != NC_NOERR) handle_error(status);
@endcode
In this example we create an in-memory netCDF classic dataset named
diskless.nc whose content will be lost when nc_close() is called.
@code
#include <netcdf.h>
...
int status = NC_NOERR;
int ncid;
...
status = nc_create("diskless.nc", NC_DISKLESS, &ncid);
if (status != NC_NOERR) handle_error(status);
@endcode
In this example we create a in-memory netCDF classic dataset named
diskless.nc and specify that it should be made persistent
in a file named diskless.nc when nc_close() is called.
@code
#include <netcdf.h>
...
int status = NC_NOERR;
int ncid;
...
status = nc_create("diskless.nc", NC_DISKLESS|NC_PERSIST, &ncid);
if (status != NC_NOERR) handle_error(status);
@endcode
A variant of nc_create(), nc__create() (note the double underscore) allows
users to specify two tuning parameters for the file that it is
creating. */
int
nc_create(const char *path, int cmode, int *ncidp)
{
return nc__create(path,cmode,NC_SIZEHINT_DEFAULT,NULL,ncidp);
}
/**
* Create a netCDF file with some extra parameters controlling classic
* file caching.
*
* Like nc_create(), this function creates a netCDF file.
*
* @param path The file name of the new netCDF dataset.
* @param cmode The creation mode flag, the same as in nc_create().
* @param initialsz On some systems, and with custom I/O layers, it
* may be advantageous to set the size of the output file at creation
* time. This parameter sets the initial size of the file at creation
* time. This only applies to classic CDF-1, 2, and 5 files. The
* special value NC_SIZEHINT_DEFAULT (which is the value 0), lets the
* netcdf library choose a suitable initial size.
* @param chunksizehintp A pointer to the chunk size hint, which
* controls a space versus time tradeoff, memory allocated in the
* netcdf library versus number of system calls. Because of internal
* requirements, the value may not be set to exactly the value
* requested. The actual value chosen is returned by reference. Using
* a NULL pointer or having the pointer point to the value
* NC_SIZEHINT_DEFAULT causes the library to choose a default. How the
* system chooses the default depends on the system. On many systems,
* the "preferred I/O block size" is available from the stat() system
* call, struct stat member st_blksize. If this is available it is
* used. Lacking that, twice the system pagesize is used. Lacking a
* call to discover the system pagesize, we just set default bufrsize
* to 8192. The bufrsize is a property of a given open netcdf
* descriptor ncid, it is not a persistent property of the netcdf
* dataset. This only applies to classic files.
* @param ncidp Pointer to location where returned netCDF ID is to be
* stored.
*
* @note This function uses the same return codes as the nc_create()
* function.
*
* @returns ::NC_NOERR No error.
* @returns ::NC_ENOMEM System out of memory.
* @returns ::NC_EHDFERR HDF5 error (netCDF-4 files only).
* @returns ::NC_EFILEMETA Error writing netCDF-4 file-level metadata in
* HDF5 file. (netCDF-4 files only).
* @returns ::NC_EDISKLESS if there was an error in creating the
* in-memory file.
*
* <h1>Examples</h1>
*
* In this example we create a netCDF dataset named foo_large.nc; we
* want the dataset to be created in the current directory only if a
* dataset with that name does not already exist. We also specify that
* bufrsize and initial size for the file.
*
* @code
#include <netcdf.h>
...
int status = NC_NOERR;
int ncid;
int intialsz = 2048;
int *bufrsize;
...
*bufrsize = 1024;
status = nc__create("foo.nc", NC_NOCLOBBER, initialsz, bufrsize, &ncid);
if (status != NC_NOERR) handle_error(status);
@endcode
*
* @ingroup datasets
* @author Glenn Davis
*/
int
nc__create(const char *path, int cmode, size_t initialsz,
size_t *chunksizehintp, int *ncidp)
{
return NC_create(path, cmode, initialsz, 0,
chunksizehintp, 0, NULL, ncidp);
}
/** \ingroup datasets
Create a netCDF file with the contents stored in memory.
\param path Must be non-null, but otherwise only used to set the dataset name.
\param mode the mode flags; Note that this procedure uses a limited set of flags because it forcibly sets NC_INMEMORY.
\param initialsize (advisory) size to allocate for the created file
\param ncidp Pointer to location where returned netCDF ID is to be
stored.
\returns ::NC_NOERR No error.
\returns ::NC_ENOMEM Out of memory.
\returns ::NC_EDISKLESS diskless io is not enabled for fails.
\returns ::NC_EINVAL, etc. other errors also returned by nc_open.
<h1>Examples</h1>
In this example we use nc_create_mem() to create a classic netCDF dataset
named foo.nc. The initial size is set to 4096.
@code
#include <netcdf.h>
...
int status = NC_NOERR;
int ncid;
int mode = 0;
size_t initialsize = 4096;
...
status = nc_create_mem("foo.nc", mode, initialsize, &ncid);
if (status != NC_NOERR) handle_error(status);
@endcode
*/
int
nc_create_mem(const char* path, int mode, size_t initialsize, int* ncidp)
{
if(mode & NC_MMAP) return NC_EINVAL;
mode |= NC_INMEMORY; /* Specifically, do not set NC_DISKLESS */
return NC_create(path, mode, initialsize, 0, NULL, 0, NULL, ncidp);
}
/**
* @internal Create a file with special (deprecated) Cray settings.
*
* @deprecated This function was used in the old days with the Cray at
* NCAR. The Cray is long gone, and this call is supported only for
* backward compatibility. Use nc_create() instead.
*
* @param path File name.
* @param cmode Create mode.
* @param initialsz Initial size of metadata region for classic files,
* ignored for other files.
* @param basepe Deprecated parameter from the Cray days.
* @param chunksizehintp A pointer to the chunk size hint. This only
* applies to classic files.
* @param ncidp Pointer that gets ncid.
*
* @return ::NC_NOERR No error.
* @author Glenn Davis
*/
int
nc__create_mp(const char *path, int cmode, size_t initialsz,
int basepe, size_t *chunksizehintp, int *ncidp)
{
return NC_create(path, cmode, initialsz, basepe,
chunksizehintp, 0, NULL, ncidp);
}
/**
* Open an existing netCDF file.
*
* This function opens an existing netCDF dataset for access. It
* determines the underlying file format automatically. Use the same
* call to open a netCDF classic or netCDF-4 file.
*
* @param path File name for netCDF dataset to be opened. When DAP
* support is enabled, then the path may be an OPeNDAP URL rather than
* a file path.
* @param omode The open mode flag may include NC_WRITE (for read/write
* access) and NC_SHARE (see below) and NC_DISKLESS (see below).
* @param ncidp Pointer to location where returned netCDF ID is to be
* stored.
*
* <h2>Open Mode</h2>
*
* A zero value (or ::NC_NOWRITE) specifies the default behavior: open
* the dataset with read-only access, buffering and caching accesses
* for efficiency.
*
* Otherwise, the open mode is ::NC_WRITE, ::NC_SHARE, or
* ::NC_WRITE|::NC_SHARE. Setting the ::NC_WRITE flag opens the
* dataset with read-write access. ("Writing" means any kind of change
* to the dataset, including appending or changing data, adding or
* renaming dimensions, variables, and attributes, or deleting
* attributes.)
*
* The NC_SHARE flag is only used for netCDF classic
* files. It is appropriate when one process may be writing the
* dataset and one or more other processes reading the dataset
* concurrently; it means that dataset accesses are not buffered and
* caching is limited. Since the buffering scheme is optimized for
* sequential access, programs that do not access data sequentially
* may see some performance improvement by setting the NC_SHARE flag.
*
* This procedure may also be invoked with the NC_DISKLESS flag set in
* the omode argument if the file to be opened is a classic format
* file. For nc_open(), this flag applies only to files in classic
* format. If the file is of type NC_NETCDF4, then the NC_DISKLESS
* flag will be ignored.
*
* If NC_DISKLESS is specified, then the whole file is read completely
* into memory. In effect this creates an in-memory cache of the file.
* If the omode flag also specifies NC_PERSIST, then the in-memory cache
* will be re-written to the disk file when nc_close() is called. For
* some kinds of manipulations, having the in-memory cache can speed
* up file processing. But in simple cases, non-cached processing may
* actually be faster than using cached processing. You will need to
* experiment to determine if the in-memory caching is worthwhile for
* your application.
*
* Normally, NC_DISKLESS allocates space in the heap for storing the
* in-memory file. If, however, the ./configure flags --enable-mmap is
* used, and the additional omode flag NC_MMAP is specified, then the
* file will be opened using the operating system MMAP facility. This
* flag only applies to files in classic format. Extended format
* (netcdf-4) files will ignore the NC_MMAP flag.
*
* In most cases, using MMAP provides no advantage for just
* NC_DISKLESS. The one case where using MMAP is an advantage is when
* a file is to be opened and only a small portion of its data is to
* be read and/or written. In this scenario, MMAP will cause only the
* accessed data to be retrieved from disk. Without MMAP, NC_DISKLESS
* will read the whole file into memory on nc_open. Thus, MMAP will
* provide some performance improvement in this case.
*
* It is not necessary to pass any information about the format of the
* file being opened. The file type will be detected automatically by
* the netCDF library.
*
* If a the path is a DAP URL, then the open mode is read-only.
* Setting NC_WRITE will be ignored.
*
* As of version 4.3.1.2, multiple calls to nc_open with the same
* path will return the same ncid value.
*
* @note When opening a netCDF-4 file HDF5 error reporting is turned
* off, if it is on. This doesn't stop the HDF5 error stack from
* recording the errors, it simply stops their display to the user
* through stderr.
*
* nc_open()returns the value NC_NOERR if no errors
* occurred. Otherwise, the returned status indicates an
* error. Possible causes of errors include:
*
* Note that nc_open(path,omode,ncidp) is equivalent to the invocation
* of nc__open(path,omode,NC_SIZEHINT_DEFAULT,NULL,ncidp).
*
* @returns ::NC_NOERR No error.
* @returns ::NC_EPERM Attempting to create a netCDF file in a directory where you do not have permission to open files.
* @returns ::NC_ENFILE Too many files open
* @returns ::NC_ENOMEM Out of memory.
* @returns ::NC_EHDFERR HDF5 error. (NetCDF-4 files only.)
* @returns ::NC_EDIMMETA Error in netCDF-4 dimension metadata. (NetCDF-4 files only.)
*
* <h1>Examples</h1>
*
* Here is an example using nc_open()to open an existing netCDF dataset
* named foo.nc for read-only, non-shared access:
*
* @code
* #include <netcdf.h>
* ...
* int status = NC_NOERR;
* int ncid;
* ...
* status = nc_open("foo.nc", 0, &ncid);
* if (status != NC_NOERR) handle_error(status);
* @endcode
* @ingroup datasets
* @author Glenn Davis, Ed Hartnett, Dennis Heimbigner
*/
int
nc_open(const char *path, int omode, int *ncidp)
{
return NC_open(path, omode, 0, NULL, 0, NULL, ncidp);
}
/** \ingroup datasets
Open a netCDF file with extra performance parameters for the classic
library.
\param path File name for netCDF dataset to be opened. When DAP
support is enabled, then the path may be an OPeNDAP URL rather than a
file path.
\param omode The open mode flag may include NC_WRITE (for read/write
access) and NC_SHARE as in nc_open().
\param chunksizehintp A size hint for the classic library. Only
applies to classic files. See below for more
information.
\param ncidp Pointer to location where returned netCDF ID is to be
stored.
<h1>The chunksizehintp Parameter</h1>
The argument referenced by bufrsizehintp controls a space versus time
tradeoff, memory allocated in the netcdf library versus number of
system calls.
Because of internal requirements, the value may not be set to exactly
the value requested. The actual value chosen is returned by reference.
Using a NULL pointer or having the pointer point to the value
NC_SIZEHINT_DEFAULT causes the library to choose a default.
How the system chooses the default depends on the system. On
many systems, the "preferred I/O block size" is available from the
stat() system call, struct stat member st_blksize. If this is
available it is used. Lacking that, twice the system pagesize is used.
Lacking a call to discover the system pagesize, we just set default
bufrsize to 8192.
The bufrsize is a property of a given open netcdf descriptor ncid, it
is not a persistent property of the netcdf dataset.
\returns ::NC_NOERR No error.
\returns ::NC_ENOMEM Out of memory.
\returns ::NC_EHDFERR HDF5 error. (NetCDF-4 files only.)
\returns ::NC_EDIMMETA Error in netCDF-4 dimension metadata. (NetCDF-4
files only.)
*/
int
nc__open(const char *path, int omode,
size_t *chunksizehintp, int *ncidp)
{
/* this API is for non-parallel access.
* Note nc_open_par() also calls NC_open().
*/
return NC_open(path, omode, 0, chunksizehintp, 0, NULL, ncidp);
}
/** \ingroup datasets
Open a netCDF file with the contents taken from a block of memory.
\param path Must be non-null, but otherwise only used to set the dataset name.
\param omode the open mode flags; Note that this procedure uses a limited set of flags because it forcibly sets NC_INMEMORY.
\param size The length of the block of memory being passed.
\param memory Pointer to the block of memory containing the contents
of a netcdf file.
\param ncidp Pointer to location where returned netCDF ID is to be
stored.
\returns ::NC_NOERR No error.
\returns ::NC_ENOMEM Out of memory.
\returns ::NC_EDISKLESS diskless io is not enabled for fails.
\returns ::NC_EINVAL, etc. other errors also returned by nc_open.
<h1>Examples</h1>
Here is an example using nc_open_mem() to open an existing netCDF dataset
named foo.nc for read-only, non-shared access. It differs from the nc_open()
example in that it assumes the contents of foo.nc have been read into memory.
@code
#include <netcdf.h>
#include <netcdf_mem.h>
...
int status = NC_NOERR;
int ncid;
size_t size;
void* memory;
...
size = <compute file size of foo.nc in bytes>;
memory = malloc(size);
...
status = nc_open_mem("foo.nc", 0, size, memory, &ncid);
if (status != NC_NOERR) handle_error(status);
@endcode
*/
int
nc_open_mem(const char* path, int omode, size_t size, void* memory, int* ncidp)
{
NC_memio meminfo;
/* Sanity checks */
if(memory == NULL || size < MAGIC_NUMBER_LEN || path == NULL)
return NC_EINVAL;
if(omode & (NC_WRITE|NC_MMAP))
return NC_EINVAL;
omode |= (NC_INMEMORY); /* Note: NC_INMEMORY and NC_DISKLESS are mutually exclusive*/
meminfo.size = size;
meminfo.memory = memory;
meminfo.flags = NC_MEMIO_LOCKED;
return NC_open(path, omode, 0, NULL, 0, &meminfo, ncidp);
}
/** \ingroup datasets
Open a netCDF file with the contents taken from a block of memory.
Similar to nc_open_mem, but with parameters. Warning: if you do
specify that the provided memory is locked, then <b>never</b>
pass in non-heap allocated memory. Additionally, if not locked,
then do not assume that the memory returned by nc_close_mem
is the same as passed to nc_open_memio. You <b>must</b> check
before attempting to free the original memory.
\param path Must be non-null, but otherwise only used to set the dataset name.
\param omode the open mode flags; Note that this procedure uses a limited set of flags because it forcibly sets NC_INMEMORY.
\param params controlling parameters
\param ncidp Pointer to location where returned netCDF ID is to be
stored.
\returns ::NC_NOERR No error.
\returns ::NC_ENOMEM Out of memory.
\returns ::NC_EDISKLESS diskless io is not enabled for fails.
\returns ::NC_EINVAL, etc. other errors also returned by nc_open.
<h1>Examples</h1>
Here is an example using nc_open_memio() to open an existing netCDF dataset
named foo.nc for read-only, non-shared access. It differs from the nc_open_mem()
example in that it uses a parameter block.
@code
#include <netcdf.h>
#include <netcdf_mem.h>
...
int status = NC_NOERR;
int ncid;
NC_memio params;
...
params.size = <compute file size of foo.nc in bytes>;
params.memory = malloc(size);
params.flags = <see netcdf_mem.h>
...
status = nc_open_memio("foo.nc", 0, ¶ms, &ncid);
if (status != NC_NOERR) handle_error(status);
@endcode
*/
int
nc_open_memio(const char* path, int omode, NC_memio* params, int* ncidp)
{
/* Sanity checks */
if(path == NULL || params == NULL)
return NC_EINVAL;
if(params->memory == NULL || params->size < MAGIC_NUMBER_LEN)
return NC_EINVAL;
if(omode & NC_MMAP)
return NC_EINVAL;
omode |= (NC_INMEMORY);
return NC_open(path, omode, 0, NULL, 0, params, ncidp);
}
/**
* @internal Open a netCDF file with extra parameters for Cray.
*
* @deprecated This function was used in the old days with the Cray at
* NCAR. The Cray is long gone, and this call is supported only for
* backward compatibility. Use nc_open() instead.
*
* @param path The file name of the new netCDF dataset.
* @param omode Open mode.
* @param basepe Deprecated parameter from the Cray days.
* @param chunksizehintp A pointer to the chunk size hint. This only
* applies to classic files.
* @param ncidp Pointer to location where returned netCDF ID is to be
* stored.
*
* @return ::NC_NOERR
* @author Glenn Davis
*/
int
nc__open_mp(const char *path, int omode, int basepe,
size_t *chunksizehintp, int *ncidp)
{
return NC_open(path, omode, basepe, chunksizehintp, 0, NULL, ncidp);
}
/** \ingroup datasets
Get the file pathname (or the opendap URL) which was used to
open/create the ncid's file.
\param ncid NetCDF ID, from a previous call to nc_open() or
nc_create().
\param pathlen Pointer where length of path will be returned. Ignored
if NULL.
\param path Pointer where path name will be copied. Space must already
be allocated. Ignored if NULL.
\returns ::NC_NOERR No error.
\returns ::NC_EBADID Invalid ncid passed.
*/
int
nc_inq_path(int ncid, size_t *pathlen, char *path)
{
NC* ncp;
int stat = NC_NOERR;
if ((stat = NC_check_id(ncid, &ncp)))
return stat;
if(ncp->path == NULL) {
if(pathlen) *pathlen = 0;
if(path) path[0] = '\0';
} else {
if (pathlen) *pathlen = strlen(ncp->path);
if (path) strcpy(path, ncp->path);
}
return stat;
}
/** \ingroup datasets
Put open netcdf dataset into define mode
The function nc_redef puts an open netCDF dataset into define mode, so
dimensions, variables, and attributes can be added or renamed and
attributes can be deleted.
For netCDF-4 files (i.e. files created with NC_NETCDF4 in the cmode in
their call to nc_create()), it is not necessary to call nc_redef()
unless the file was also created with NC_STRICT_NC3. For straight-up
netCDF-4 files, nc_redef() is called automatically, as needed.
For all netCDF-4 files, the root ncid must be used. This is the ncid
returned by nc_open() and nc_create(), and points to the root of the
hierarchy tree for netCDF-4 files.
\param ncid NetCDF ID, from a previous call to nc_open() or
nc_create().
\returns ::NC_NOERR No error.
\returns ::NC_EBADID Bad ncid.
\returns ::NC_EBADGRPID The ncid must refer to the root group of the
file, that is, the group returned by nc_open() or nc_create().
\returns ::NC_EINDEFINE Already in define mode.
\returns ::NC_EPERM File is read-only.
<h1>Example</h1>
Here is an example using nc_redef to open an existing netCDF dataset
named foo.nc and put it into define mode:
\code
#include <netcdf.h>
...
int status = NC_NOERR;
int ncid;
...
status = nc_open("foo.nc", NC_WRITE, &ncid);
if (status != NC_NOERR) handle_error(status);
...
status = nc_redef(ncid);
if (status != NC_NOERR) handle_error(status);
\endcode
*/
int
nc_redef(int ncid)
{
NC* ncp;
int stat = NC_check_id(ncid, &ncp);
if(stat != NC_NOERR) return stat;
return ncp->dispatch->redef(ncid);
}
/** \ingroup datasets
Leave define mode
The function nc_enddef() takes an open netCDF dataset out of define
mode. The changes made to the netCDF dataset while it was in define
mode are checked and committed to disk if no problems
occurred. Non-record variables may be initialized to a "fill value" as
well with nc_set_fill(). The netCDF dataset is then placed in data
mode, so variable data can be read or written.
It's not necessary to call nc_enddef() for netCDF-4 files. With netCDF-4
files, nc_enddef() is called when needed by the netcdf-4 library. User
calls to nc_enddef() for netCDF-4 files still flush the metadata to
disk.
This call may involve copying data under some circumstances. For a
more extensive discussion see File Structure and Performance.
For netCDF-4/HDF5 format files there are some variable settings (the
compression, endianness, fletcher32 error correction, and fill value)
which must be set (if they are going to be set at all) between the
nc_def_var() and the next nc_enddef(). Once the nc_enddef() is called,
these settings can no longer be changed for a variable.
\param ncid NetCDF ID, from a previous call to nc_open() or
nc_create().
If you use a group id (in a netCDF-4/HDF5 file), the enddef
will apply to the entire file. That means the enddef will not just end
define mode in one group, but in the entire file.
\returns ::NC_NOERR no error
\returns ::NC_EBADID Invalid ncid passed.
<h1>Example</h1>
Here is an example using nc_enddef() to finish the definitions of a new
netCDF dataset named foo.nc and put it into data mode:
\code
#include <netcdf.h>
...
int status = NC_NOERR;
int ncid;
...
status = nc_create("foo.nc", NC_NOCLOBBER, &ncid);
if (status != NC_NOERR) handle_error(status);
... create dimensions, variables, attributes
status = nc_enddef(ncid);
if (status != NC_NOERR) handle_error(status);
\endcode
*/
int
nc_enddef(int ncid)
{
int status = NC_NOERR;
NC *ncp;
status = NC_check_id(ncid, &ncp);
if(status != NC_NOERR) return status;
return ncp->dispatch->_enddef(ncid,0,1,0,1);
}
/** \ingroup datasets
Leave define mode with performance tuning
The function nc__enddef takes an open netCDF dataset out of define
mode. The changes made to the netCDF dataset while it was in define
mode are checked and committed to disk if no problems
occurred. Non-record variables may be initialized to a "fill value" as
well with nc_set_fill(). The netCDF dataset is then placed in data mode,
so variable data can be read or written.
This call may involve copying data under some circumstances. For a
more extensive discussion see File Structure and Performance.
\warning This function exposes internals of the netcdf version 1 file
format. Users should use nc_enddef() in most circumstances. This
function may not be available on future netcdf implementations.
The classic netcdf file format has three sections, the "header"
section, the data section for fixed size variables, and the data
section for variables which have an unlimited dimension (record
variables).
The header begins at the beginning of the file. The index (offset) of
the beginning of the other two sections is contained in the
header. Typically, there is no space between the sections. This causes
copying overhead to accrue if one wishes to change the size of the
sections, as may happen when changing names of things, text attribute
values, adding attributes or adding variables. Also, for buffered i/o,
there may be advantages to aligning sections in certain ways.
The minfree parameters allow one to control costs of future calls to
nc_redef, nc_enddef() by requesting that minfree bytes be available at
the end of the section.
The align parameters allow one to set the alignment of the beginning
of the corresponding sections. The beginning of the section is rounded
up to an index which is a multiple of the align parameter. The flag
value ALIGN_CHUNK tells the library to use the bufrsize (see above) as
the align parameter. It has nothing to do with the chunking
(multidimensional tiling) features of netCDF-4.
The file format requires mod 4 alignment, so the align parameters are
silently rounded up to multiples of 4. The usual call,
\code
nc_enddef(ncid);
\endcode
is equivalent to
\code
nc__enddef(ncid, 0, 4, 0, 4);
\endcode
The file format does not contain a "record size" value, this is
calculated from the sizes of the record variables. This unfortunate
fact prevents us from providing minfree and alignment control of the
"records" in a netcdf file. If you add a variable which has an
unlimited dimension, the third section will always be copied with the
new variable added.
\param ncid NetCDF ID, from a previous call to nc_open() or
nc_create().
\param h_minfree Sets the pad at the end of the "header" section.
\param v_align Controls the alignment of the beginning of the data
section for fixed size variables.
\param v_minfree Sets the pad at the end of the data section for fixed
size variables.
\param r_align Controls the alignment of the beginning of the data
section for variables which have an unlimited dimension (record
variables).
\returns ::NC_NOERR No error.
\returns ::NC_EBADID Invalid ncid passed.
*/
int
nc__enddef(int ncid, size_t h_minfree, size_t v_align, size_t v_minfree,
size_t r_align)
{
NC* ncp;
int stat = NC_check_id(ncid, &ncp);
if(stat != NC_NOERR) return stat;
return ncp->dispatch->_enddef(ncid,h_minfree,v_align,v_minfree,r_align);
}
/** \ingroup datasets
Synchronize an open netcdf dataset to disk
The function nc_sync() offers a way to synchronize the disk copy of a
netCDF dataset with in-memory buffers. There are two reasons you might
want to synchronize after writes:
- To minimize data loss in case of abnormal termination, or
- To make data available to other processes for reading immediately
after it is written. But note that a process that already had the
dataset open for reading would not see the number of records
increase when the writing process calls nc_sync(); to accomplish this,
the reading process must call nc_sync.
This function is backward-compatible with previous versions of the
netCDF library. The intent was to allow sharing of a netCDF dataset
among multiple readers and one writer, by having the writer call
nc_sync() after writing and the readers call nc_sync() before each
read. For a writer, this flushes buffers to disk. For a reader, it
makes sure that the next read will be from disk rather than from
previously cached buffers, so that the reader will see changes made by
the writing process (e.g., the number of records written) without
having to close and reopen the dataset. If you are only accessing a
small amount of data, it can be expensive in computer resources to
always synchronize to disk after every write, since you are giving up
the benefits of buffering.
An easier way to accomplish sharing (and what is now recommended) is
to have the writer and readers open the dataset with the NC_SHARE
flag, and then it will not be necessary to call nc_sync() at
all. However, the nc_sync() function still provides finer granularity
than the NC_SHARE flag, if only a few netCDF accesses need to be
synchronized among processes.
It is important to note that changes to the ancillary data, such as
attribute values, are not propagated automatically by use of the
NC_SHARE flag. Use of the nc_sync() function is still required for this
purpose.
Sharing datasets when the writer enters define mode to change the data
schema requires extra care. In previous releases, after the writer
left define mode, the readers were left looking at an old copy of the
dataset, since the changes were made to a new copy. The only way
readers could see the changes was by closing and reopening the
dataset. Now the changes are made in place, but readers have no
knowledge that their internal tables are now inconsistent with the new
dataset schema. If netCDF datasets are shared across redefinition,
some mechanism external to the netCDF library must be provided that
prevents access by readers during redefinition and causes the readers
to call nc_sync before any subsequent access.
When calling nc_sync(), the netCDF dataset must be in data mode. A
netCDF dataset in define mode is synchronized to disk only when
nc_enddef() is called. A process that is reading a netCDF dataset that
another process is writing may call nc_sync to get updated with the
changes made to the data by the writing process (e.g., the number of
records written), without having to close and reopen the dataset.
Data is automatically synchronized to disk when a netCDF dataset is
closed, or whenever you leave define mode.
\param ncid NetCDF ID, from a previous call to nc_open() or
nc_create().
\returns ::NC_NOERR No error.
\returns ::NC_EBADID Invalid ncid passed.
*/
int
nc_sync(int ncid)
{
NC* ncp;
int stat = NC_check_id(ncid, &ncp);
if(stat != NC_NOERR) return stat;
return ncp->dispatch->sync(ncid);
}
/** \ingroup datasets
No longer necessary for user to invoke manually.
\warning Users no longer need to call this function since it is called
automatically by nc_close() in case the dataset is in define mode and
something goes wrong with committing the changes. The function
nc_abort() just closes the netCDF dataset, if not in define mode. If
the dataset is being created and is still in define mode, the dataset
is deleted. If define mode was entered by a call to nc_redef(), the
netCDF dataset is restored to its state before definition mode was
entered and the dataset is closed.
\param ncid NetCDF ID, from a previous call to nc_open() or
nc_create().
\returns ::NC_NOERR No error.
<h1>Example</h1>
Here is an example using nc_abort to back out of redefinitions of a
dataset named foo.nc:
\code
#include <netcdf.h>
...
int ncid, status, latid;
...
status = nc_open("foo.nc", NC_WRITE, &ncid);
if (status != NC_NOERR) handle_error(status);
...
status = nc_redef(ncid);
if (status != NC_NOERR) handle_error(status);
...
status = nc_def_dim(ncid, "lat", 18L, &latid);
if (status != NC_NOERR) {
handle_error(status);
status = nc_abort(ncid);
if (status != NC_NOERR) handle_error(status);
}
\endcode
*/
int
nc_abort(int ncid)
{
NC* ncp;
int stat = NC_check_id(ncid, &ncp);
if(stat != NC_NOERR) return stat;
#ifdef USE_REFCOUNT
/* What to do if refcount > 0? */
/* currently, forcibly abort */
ncp->refcount = 0;
#endif
stat = ncp->dispatch->abort(ncid);
del_from_NCList(ncp);
free_NC(ncp);
return stat;
}
/** \ingroup datasets
Close an open netCDF dataset
If the dataset in define mode, nc_enddef() will be called before
closing. (In this case, if nc_enddef() returns an error, nc_abort() will
automatically be called to restore the dataset to the consistent state
before define mode was last entered.) After an open netCDF dataset is
closed, its netCDF ID may be reassigned to the next netCDF dataset
that is opened or created.
\param ncid NetCDF ID, from a previous call to nc_open() or nc_create().
\returns ::NC_NOERR No error.
\returns ::NC_EBADID Invalid id passed.
\returns ::NC_EBADGRPID ncid did not contain the root group id of this
file. (NetCDF-4 only).
<h1>Example</h1>
Here is an example using nc_close to finish the definitions of a new
netCDF dataset named foo.nc and release its netCDF ID:
\code
#include <netcdf.h>
...
int status = NC_NOERR;
int ncid;
...
status = nc_create("foo.nc", NC_NOCLOBBER, &ncid);
if (status != NC_NOERR) handle_error(status);
... create dimensions, variables, attributes
status = nc_close(ncid);
if (status != NC_NOERR) handle_error(status);
\endcode
*/
int
nc_close(int ncid)
{
NC* ncp;
int stat = NC_check_id(ncid, &ncp);
if(stat != NC_NOERR) return stat;
#ifdef USE_REFCOUNT
ncp->refcount--;
if(ncp->refcount <= 0)
#endif
{
stat = ncp->dispatch->close(ncid,NULL);
/* Remove from the nc list */
if (!stat)
{
del_from_NCList(ncp);
free_NC(ncp);
}
}
return stat;
}
/** \ingroup datasets
Do a normal close (see nc_close()) on an in-memory dataset,
then return a copy of the final memory contents of the dataset.
\param ncid NetCDF ID, from a previous call to nc_open() or nc_create().
\param memio a pointer to an NC_memio object into which the final valid memory
size and memory will be returned.
\returns ::NC_NOERR No error.
\returns ::NC_EBADID Invalid id passed.
\returns ::NC_ENOMEM Out of memory.
\returns ::NC_EDISKLESS if the file was not created as an inmemory file.
\returns ::NC_EBADGRPID ncid did not contain the root group id of this
file. (NetCDF-4 only).
<h1>Example</h1>
Here is an example using nc_close_mem to finish the definitions of a new
netCDF dataset named foo.nc, return the final memory,
and release its netCDF ID:
\code
#include <netcdf.h>
...
int status = NC_NOERR;
int ncid;
NC_memio finalmem;
size_t initialsize = 65000;
...
status = nc_create_mem("foo.nc", NC_NOCLOBBER, initialsize, &ncid);
if (status != NC_NOERR) handle_error(status);
... create dimensions, variables, attributes
status = nc_close_memio(ncid,&finalmem);
if (status != NC_NOERR) handle_error(status);
\endcode
*/
int
nc_close_memio(int ncid, NC_memio* memio)
{
NC* ncp;
int stat = NC_check_id(ncid, &ncp);
if(stat != NC_NOERR) return stat;
#ifdef USE_REFCOUNT
ncp->refcount--;
if(ncp->refcount <= 0)
#endif
{
stat = ncp->dispatch->close(ncid,memio);
/* Remove from the nc list */
if (!stat)
{
del_from_NCList(ncp);
free_NC(ncp);
}
}
return stat;
}
/** \ingroup datasets
Change the fill-value mode to improve write performance.
This function is intended for advanced usage, to optimize writes under
some circumstances described below. The function nc_set_fill() sets the
fill mode for a netCDF dataset open for writing and returns the
current fill mode in a return parameter. The fill mode can be
specified as either ::NC_FILL or ::NC_NOFILL. The default behavior
corresponding to ::NC_FILL is that data is pre-filled with fill values,
that is fill values are written when you create non-record variables
or when you write a value beyond data that has not yet been
written. This makes it possible to detect attempts to read data before
it was written. For more information on the use of fill values see
Fill Values. For information about how to define your own fill values
see Attribute Conventions.
The behavior corresponding to ::NC_NOFILL overrides the default behavior
of prefilling data with fill values. This can be used to enhance
performance, because it avoids the duplicate writes that occur when
the netCDF library writes fill values that are later overwritten with
data.
A value indicating which mode the netCDF dataset was already in is
returned. You can use this value to temporarily change the fill mode
of an open netCDF dataset and then restore it to the previous mode.
After you turn on ::NC_NOFILL mode for an open netCDF dataset, you must
be certain to write valid data in all the positions that will later be
read. Note that nofill mode is only a transient property of a netCDF
dataset open for writing: if you close and reopen the dataset, it will
revert to the default behavior. You can also revert to the default
behavior by calling nc_set_fill() again to explicitly set the fill mode
to ::NC_FILL.
There are three situations where it is advantageous to set nofill
mode:
- Creating and initializing a netCDF dataset. In this case, you should
set nofill mode before calling nc_enddef() and then write completely
all non-record variables and the initial records of all the record
variables you want to initialize.
- Extending an existing record-oriented netCDF dataset. Set nofill
mode after opening the dataset for writing, then append the
additional records to the dataset completely, leaving no intervening
unwritten records.
- Adding new variables that you are going to initialize to an existing
netCDF dataset. Set nofill mode before calling nc_enddef() then write
all the new variables completely.
If the netCDF dataset has an unlimited dimension and the last record
was written while in nofill mode, then the dataset may be shorter than
if nofill mode was not set, but this will be completely transparent if
you access the data only through the netCDF interfaces.
The use of this feature may not be available (or even needed) in
future releases. Programmers are cautioned against heavy reliance upon
this feature.
\param ncid NetCDF ID, from a previous call to nc_open() or
nc_create().
\param fillmode Desired fill mode for the dataset, either ::NC_NOFILL or
::NC_FILL.
\param old_modep Pointer to location for returned current fill mode of
the dataset before this call, either ::NC_NOFILL or ::NC_FILL.
\returns ::NC_NOERR No error.
\returns ::NC_EBADID The specified netCDF ID does not refer to an open
netCDF dataset.
\returns ::NC_EPERM The specified netCDF ID refers to a dataset open for
read-only access.
\returns ::NC_EINVAL The fill mode argument is neither ::NC_NOFILL nor
::NC_FILL.
<h1>Example</h1>
Here is an example using nc_set_fill() to set nofill mode for subsequent
writes of a netCDF dataset named foo.nc:
\code
#include <netcdf.h>
...
int ncid, status, old_fill_mode;
...
status = nc_open("foo.nc", NC_WRITE, &ncid);
if (status != NC_NOERR) handle_error(status);
... write data with default prefilling behavior
status = nc_set_fill(ncid, ::NC_NOFILL, &old_fill_mode);
if (status != NC_NOERR) handle_error(status);
... write data with no prefilling
\endcode
*/
int
nc_set_fill(int ncid, int fillmode, int *old_modep)
{
NC* ncp;
int stat = NC_check_id(ncid, &ncp);
if(stat != NC_NOERR) return stat;
return ncp->dispatch->set_fill(ncid,fillmode,old_modep);
}
/**
* @internal Learn base PE.
*
* @deprecated This function was used in the old days with the Cray at
* NCAR. The Cray is long gone, and this call is supported only for
* backward compatibility.
*
* @param ncid File and group ID.
* @param pe Pointer for base PE.
*
* @return ::NC_NOERR No error.
* @return ::NC_EBADID Invalid ncid passed.
* @author Glenn Davis
*/
int
nc_inq_base_pe(int ncid, int *pe)
{
NC* ncp;
int stat = NC_check_id(ncid, &ncp);
if(stat != NC_NOERR) return stat;
return ncp->dispatch->inq_base_pe(ncid,pe);
}
/**
* @internal Sets base processing element (ignored).
*
* @deprecated This function was used in the old days with the Cray at
* NCAR. The Cray is long gone, and this call is supported only for
* backward compatibility.
*
* @param ncid File ID.
* @param pe Base PE.
*
* @return ::NC_NOERR No error.
* @return ::NC_EBADID Invalid ncid passed.
* @author Glenn Davis
*/
int
nc_set_base_pe(int ncid, int pe)
{
NC* ncp;
int stat = NC_check_id(ncid, &ncp);
if(stat != NC_NOERR) return stat;
return ncp->dispatch->set_base_pe(ncid,pe);
}
/** \ingroup datasets
Inquire about the binary format of a netCDF file
as presented by the API.
This function returns the (rarely needed) format version.
\param ncid NetCDF ID, from a previous call to nc_open() or
nc_create().
\param formatp Pointer to location for returned format version, one of
NC_FORMAT_CLASSIC, NC_FORMAT_64BIT_OFFSET, NC_FORMAT_CDF5, NC_FORMAT_NETCDF4,
NC_FORMAT_NETCDF4_CLASSIC.
\returns ::NC_NOERR No error.
\returns ::NC_EBADID Invalid ncid passed.
*/
int
nc_inq_format(int ncid, int *formatp)
{
NC* ncp;
int stat = NC_check_id(ncid, &ncp);
if(stat != NC_NOERR) return stat;
return ncp->dispatch->inq_format(ncid,formatp);
}
/** \ingroup datasets
Obtain more detailed (vis-a-vis nc_inq_format)
format information about an open dataset.
Note that the netcdf API will present the file
as if it had the format specified by nc_inq_format.
The true file format, however, may not even be
a netcdf file; it might be DAP, HDF4, or PNETCDF,
for example. This function returns that true file type.
It also returns the effective mode for the file.
\param ncid NetCDF ID, from a previous call to nc_open() or
nc_create().
\param formatp Pointer to location for returned true format.
\param modep Pointer to location for returned mode flags.
Refer to the actual list in the file netcdf.h to see the
currently defined set.
\returns ::NC_NOERR No error.
\returns ::NC_EBADID Invalid ncid passed.
*/
int
nc_inq_format_extended(int ncid, int *formatp, int *modep)
{
NC* ncp;
int stat = NC_check_id(ncid, &ncp);
if(stat != NC_NOERR) return stat;
return ncp->dispatch->inq_format_extended(ncid,formatp,modep);
}
/**\ingroup datasets
Inquire about a file or group.
\param ncid NetCDF or group ID, from a previous call to nc_open(),
nc_create(), nc_def_grp(), or associated inquiry functions such as
nc_inq_ncid().
\param ndimsp Pointer to location for returned number of dimensions
defined for this netCDF dataset. Ignored if NULL.
\param nvarsp Pointer to location for returned number of variables
defined for this netCDF dataset. Ignored if NULL.
\param nattsp Pointer to location for returned number of global
attributes defined for this netCDF dataset. Ignored if NULL.
\param unlimdimidp Pointer to location for returned ID of the
unlimited dimension, if there is one for this netCDF dataset. If no
unlimited length dimension has been defined, -1 is returned. Ignored
if NULL. If there are multiple unlimited dimensions (possible only
for netCDF-4 files), only a pointer to the first is returned, for
backward compatibility. If you want them all, use nc_inq_unlimids().
\returns ::NC_NOERR No error.
\returns ::NC_EBADID Invalid ncid passed.
<h1>Example</h1>
Here is an example using nc_inq to find out about a netCDF dataset
named foo.nc:
\code
#include <netcdf.h>
...
int status, ncid, ndims, nvars, ngatts, unlimdimid;
...
status = nc_open("foo.nc", NC_NOWRITE, &ncid);
if (status != NC_NOERR) handle_error(status);
...
status = nc_inq(ncid, &ndims, &nvars, &ngatts, &unlimdimid);
if (status != NC_NOERR) handle_error(status);
\endcode
*/
int
nc_inq(int ncid, int *ndimsp, int *nvarsp, int *nattsp, int *unlimdimidp)
{
NC* ncp;
int stat = NC_check_id(ncid, &ncp);
if(stat != NC_NOERR) return stat;
return ncp->dispatch->inq(ncid,ndimsp,nvarsp,nattsp,unlimdimidp);
}
/**
* Learn the number of variables in a file or group.
*
* @param ncid File and group ID.
* @param nvarsp Pointer that gets number of variables. Ignored if NULL.
*
* @return ::NC_NOERR No error.
* @return ::NC_EBADID Bad ncid.
* @author Glenn Davis, Ed Hartnett, Dennis Heimbigner
*/
int
nc_inq_nvars(int ncid, int *nvarsp)
{
NC* ncp;
int stat = NC_check_id(ncid, &ncp);
if(stat != NC_NOERR) return stat;
return ncp->dispatch->inq(ncid, NULL, nvarsp, NULL, NULL);
}
/**\ingroup datasets
Inquire about a type.
Given an ncid and a typeid, get the information about a type. This
function will work on any type, including atomic and any user defined
type, whether compound, opaque, enumeration, or variable length array.
For even more information about a user defined type nc_inq_user_type().
\param ncid The ncid for the group containing the type (ignored for
atomic types).
\param xtype The typeid for this type, as returned by nc_def_compound,
nc_def_opaque, nc_def_enum, nc_def_vlen, or nc_inq_var, or as found in
netcdf.h in the list of atomic types (NC_CHAR, NC_INT, etc.).
\param name If non-NULL, the name of the user defined type will be
copied here. It will be NC_MAX_NAME bytes or less. For atomic types,
the type name from CDL will be given.
\param size If non-NULL, the (in-memory) size of the type in bytes
will be copied here. VLEN type size is the size of nc_vlen_t. String
size is returned as the size of a character pointer. The size may be
used to malloc space for the data, no matter what the type.
\returns ::NC_NOERR No error.
\returns ::NC_EBADTYPE Bad typeid.
\returns ::NC_ENOTNC4 Seeking a user-defined type in a netCDF-3 file.
\returns ::NC_ESTRICTNC3 Seeking a user-defined type in a netCDF-4 file
for which classic model has been turned on.
\returns ::NC_EBADGRPID Bad group ID in ncid.
\returns ::NC_EBADID Type ID not found.
\returns ::NC_EHDFERR An error was reported by the HDF5 layer.
<h1>Example</h1>
This example is from the test program tst_enums.c, and it uses all the
possible inquiry functions on an enum type.
\code
if (nc_inq_user_type(ncid, typeids[0], name_in, &base_size_in, &base_nc_type_in,
&nfields_in, &class_in)) ERR;
if (strcmp(name_in, TYPE_NAME) || base_size_in != sizeof(int) ||
base_nc_type_in != NC_INT || nfields_in != NUM_MEMBERS || class_in != NC_ENUM) ERR;
if (nc_inq_type(ncid, typeids[0], name_in, &base_size_in)) ERR;
if (strcmp(name_in, TYPE_NAME) || base_size_in != sizeof(int)) ERR;
if (nc_inq_enum(ncid, typeids[0], name_in, &base_nc_type, &base_size_in, &num_members)) ERR;
if (strcmp(name_in, TYPE_NAME) || base_nc_type != NC_INT || num_members != NUM_MEMBERS) ERR;
for (i = 0; i < NUM_MEMBERS; i++)
{
if (nc_inq_enum_member(ncid, typeid, i, name_in, &value_in)) ERR;
if (strcmp(name_in, member_name[i]) || value_in != member_value[i]) ERR;
if (nc_inq_enum_ident(ncid, typeid, member_value[i], name_in)) ERR;
if (strcmp(name_in, member_name[i])) ERR;
}
if (nc_close(ncid)) ERR;
\endcode
*/
int
nc_inq_type(int ncid, nc_type xtype, char *name, size_t *size)
{
NC* ncp;
int stat;
/* Do a quick triage on xtype */
if(xtype <= NC_NAT) return NC_EBADTYPE;
/* For compatibility, we need to allow inq about
atomic types, even if ncid is ill-defined */
if(xtype <= ATOMICTYPEMAX4) {
if(name) strncpy(name,NC_atomictypename(xtype),NC_MAX_NAME);
if(size) *size = NC_atomictypelen(xtype);
return NC_NOERR;
}
/* Apparently asking about a user defined type, so we need
a valid ncid */
stat = NC_check_id(ncid, &ncp);
if(stat != NC_NOERR) /* bad ncid */
return NC_EBADTYPE;
/* have good ncid */
return ncp->dispatch->inq_type(ncid,xtype,name,size);
}
/**
Check the create mode parameter for sanity.
Some create flags cannot be used if corresponding library features are
enabled during the build. This function does a pre-check of the mode
flag before calling the dispatch layer nc_create functions.
\param mode The creation mode flag.
\returns ::NC_NOERR No error.
\returns ::NC_ENOTBUILT Requested feature not built into library
\returns ::NC_EINVAL Invalid combination of modes.
\internal
\ingroup dispatch
\author Ed Hartnett
*/
static int
check_create_mode(int mode)
{
int mode_format;
int mmap = 0;
int inmemory = 0;
int diskless = 0;
/* This is a clever check to see if more than one format bit is
* set. */
mode_format = (mode & NC_NETCDF4) | (mode & NC_64BIT_OFFSET) |
(mode & NC_CDF5);
if (mode_format && (mode_format & (mode_format - 1)))
return NC_EINVAL;
mmap = ((mode & NC_MMAP) == NC_MMAP);
inmemory = ((mode & NC_INMEMORY) == NC_INMEMORY);
diskless = ((mode & NC_DISKLESS) == NC_DISKLESS);
/* NC_INMEMORY and NC_DISKLESS and NC_MMAP are all mutually exclusive */
if(diskless && inmemory) return NC_EDISKLESS;
if(diskless && mmap) return NC_EDISKLESS;
if(inmemory && mmap) return NC_EINMEMORY;
/* mmap is not allowed for netcdf-4 */
if(mmap && (mode & NC_NETCDF4)) return NC_EINVAL;
/* Can't use both parallel and diskless|inmemory|mmap. */
if (mode & NC_MPIIO && mode & (NC_DISKLESS|NC_INMEMORY|NC_MMAP))
return NC_EINVAL;
#ifndef USE_NETCDF4
/* If the user asks for a netCDF-4 file, and the library was built
* without netCDF-4, then return an error.*/
if (mode & NC_NETCDF4)
return NC_ENOTBUILT;
#endif /* USE_NETCDF4 undefined */
/* Well I guess there is some sanity in the world after all. */
return NC_NOERR;
}
/**
* @internal Create a file, calling the appropriate dispatch create
* call.
*
* For create, we have the following pieces of information to use to
* determine the dispatch table:
* - path
* - cmode
*
* @param path0 The file name of the new netCDF dataset.
* @param cmode The creation mode flag, the same as in nc_create().
* @param initialsz This parameter sets the initial size of the file
* at creation time. This only applies to classic
* files.
* @param basepe Deprecated parameter from the Cray days.
* @param chunksizehintp A pointer to the chunk size hint. This only
* applies to classic files.
* @param useparallel Non-zero if parallel I/O is to be used on this
* file.
* @param parameters Pointer to MPI comm and info.
* @param ncidp Pointer to location where returned netCDF ID is to be
* stored.
*
* @returns ::NC_NOERR No error.
* @ingroup dispatch
* @author Dennis Heimbigner, Ed Hartnett, Ward Fisher
*/
int
NC_create(const char *path0, int cmode, size_t initialsz,
int basepe, size_t *chunksizehintp, int useparallel,
void* parameters, int *ncidp)
{
int stat = NC_NOERR;
NC* ncp = NULL;
NC_Dispatch* dispatcher = NULL;
/* Need three pieces of information for now */
int model = NC_FORMATX_UNDEFINED; /* one of the NC_FORMATX values */
int isurl = 0; /* dap or cdmremote or neither */
char* path = NULL;
TRACE(nc_create);
if(path0 == NULL)
return NC_EINVAL;
/* Check mode flag for sanity. */
if ((stat = check_create_mode(cmode)))
return stat;
/* Initialize the library. The available dispatch tables
* will depend on how netCDF was built
* (with/without netCDF-4, DAP, CDMREMOTE). */
if(!NC_initialized)
{
if ((stat = nc_initialize()))
return stat;
}
#ifdef WINPATH
/* Need to do path conversion */
path = NCpathcvt(path0);
#else
path = nulldup(path0);
#endif
#ifdef USE_REFCOUNT
/* If this path is already open, then fail */
ncp = find_in_NCList_by_name(path);
if(ncp != NULL) {
nullfree(path);
return NC_ENFILE;
}
#endif
{
char* newpath = NULL;
model = NC_urlmodel(path,cmode,&newpath);
isurl = (model != 0);
if(isurl) {
nullfree(path);
path = newpath;
}
}
/* determine the model */
#ifdef USE_NETCDF4
if (model == NC_FORMATX_UNDEFINED && (cmode & NC_NETCDF4))
model = NC_FORMATX_NC4;
#else
if (model == NC_FORMATX_UNDEFINED && (cmode & NC_NETCDF4))
return NC_ENOTBUILT;
#endif
#ifdef USE_PNETCDF
if (model == NC_FORMATX_UNDEFINED && useparallel)
/* PnetCDF is used for parallel io on CDF-1, CDF-2, and CDF-5 */
model = NC_FORMATX_PNETCDF;
#else
if (model == NC_FORMATX_UNDEFINED && useparallel)
return NC_ENOTBUILT;
#endif
/* Check default format (not formatx) */
if (!fIsSet(cmode, NC_64BIT_OFFSET) && !fIsSet(cmode, NC_64BIT_DATA) &&
!fIsSet(cmode, NC_CLASSIC_MODEL) && !fIsSet(cmode, NC_NETCDF4)) {
/* if no file format flag is set in cmode, use default */
int format = nc_get_default_format();
switch (format) {
#ifdef USE_NETCDF4
case NC_FORMAT_NETCDF4:
cmode |= NC_NETCDF4;
if (model == NC_FORMATX_UNDEFINED) model = NC_FORMATX_NC4;
break;
case NC_FORMAT_NETCDF4_CLASSIC:
cmode |= NC_NETCDF4 | NC_CLASSIC_MODEL;
if (model == NC_FORMATX_UNDEFINED) model = NC_FORMATX_NC4;
break;
#endif
case NC_FORMAT_CDF5:
cmode |= NC_64BIT_DATA;
break;
case NC_FORMAT_64BIT_OFFSET:
cmode |= NC_64BIT_OFFSET;
break;
case NC_FORMAT_CLASSIC: break;
default: break;
}
}
/* default model */
if (model == NC_FORMATX_UNDEFINED) {
if (useparallel)
model = NC_FORMATX_PNETCDF;
else
model = NC_FORMATX_NC3;
}
#ifndef ENABLE_CDF5
if (model == NC_FORMATX_NC3 && (cmode & NC_64BIT_DATA))
return NC_ENOTBUILT;
#endif
/* Figure out what dispatcher to use */
if (model == NC_FORMATX_NC4)
#ifdef USE_NETCDF4
dispatcher = NC4_dispatch_table;
#else
return NC_ENOTBUILT;
#endif
else if (model == NC_FORMATX_PNETCDF)
#ifdef USE_PNETCDF
dispatcher = NCP_dispatch_table;
#else
return NC_ENOTBUILT;
#endif
else if (model == NC_FORMATX_NC3)
dispatcher = NC3_dispatch_table;
else {
nullfree(path);
return NC_ENOTNC;
}
/* Create the NC* instance and insert its dispatcher */
stat = new_NC(dispatcher,path,cmode,model,&ncp);
nullfree(path); path = NULL; /* no longer needed */
if(stat) return stat;
/* Add to list of known open files and define ext_ncid */
add_to_NCList(ncp);
#ifdef USE_REFCOUNT
/* bump the refcount */
ncp->refcount++;
#endif
/* Assume create will fill in remaining ncp fields */
if ((stat = dispatcher->create(ncp->path, cmode, initialsz, basepe, chunksizehintp,
parameters, dispatcher, ncp))) {
del_from_NCList(ncp); /* oh well */
free_NC(ncp);
} else {
if(ncidp)*ncidp = ncp->ext_ncid;
}
return stat;
}
/**
* @internal Open a netCDF file (or remote dataset) calling the
* appropriate dispatch function.
*
* For open, we have the following pieces of information to use to
* determine the dispatch table.
* - table specified by override
* - path
* - omode
* - the contents of the file (if it exists), basically checking its magic number.
*
* @param path0 Path to the file to open.
* @param omode Open mode.
* @param basepe Base processing element (ignored).
* @param chunksizehintp Size hint for classic files.
* @param useparallel If true use parallel I/O.
* @param parameters Extra parameters for the open.
* @param ncidp Pointer that gets ncid.
*
* @returns ::NC_NOERR No error.
* @ingroup dispatch
* @author Dennis Heimbigner
*/
int
NC_open(const char *path0, int omode, int basepe, size_t *chunksizehintp,
int useparallel, void* parameters, int *ncidp)
{
int stat = NC_NOERR;
NC* ncp = NULL;
NC_Dispatch* dispatcher = NULL;
int inmemory = 0;
int diskless = 0;
int mmap = 0;
/* Need pieces of information for now to decide model*/
int model = 0;
int isurl = 0;
int version = 0;
char* path = NULL;
TRACE(nc_open);
if(!NC_initialized) {
stat = nc_initialize();
if(stat) return stat;
}
/* Fix the inmemory related flags */
mmap = ((omode & NC_MMAP) == NC_MMAP);
diskless = ((omode & NC_DISKLESS) == NC_DISKLESS);
inmemory = ((omode & NC_INMEMORY) == NC_INMEMORY);
if(mmap && inmemory) /* cannot have both */
return NC_EINMEMORY;
if(mmap && diskless) /* cannot have both */
return NC_EDISKLESS;
/* Attempt to do file path conversion: note that this will do
nothing if path is a 'file:...' url, so it will need to be
repeated in protocol code: libdap2 and libdap4
*/
#ifdef WINPATH
path = NCpathcvt(path0);
#else
path = nulldup(path0);
#endif
#ifdef USE_REFCOUNT
/* If this path is already open, then bump the refcount and return it */
ncp = find_in_NCList_by_name(path);
if(ncp != NULL) {
nullfree(path);
ncp->refcount++;
if(ncidp) *ncidp = ncp->ext_ncid;
return NC_NOERR;
}
#endif
if(!inmemory) {
char* newpath = NULL;
model = NC_urlmodel(path,omode,&newpath);
isurl = (model != 0);
if(isurl) {
nullfree(path);
path = newpath;
} else
nullfree(newpath);
}
#ifdef USE_NETCDF4
/* Check for use of user-defined format 0. */
if (omode & NC_UDF0)
{
if (!UDF0_dispatch_table)
return NC_EINVAL;
model = NC_FORMATX_UDF0;
dispatcher = UDF0_dispatch_table;
}
/* Check for use of user-defined format 1. */
if (omode & NC_UDF1)
{
if (!UDF1_dispatch_table)
return NC_EINVAL;
model = NC_FORMATX_UDF1;
dispatcher = UDF1_dispatch_table;
}
#endif /* USE_NETCDF4 */
if(model == 0) {
version = 0;
/* Try to find dataset type */
int flags = omode;
stat = NC_check_file_type(path,flags,useparallel,parameters,&model,&version);
if(stat == NC_NOERR) {
if(model == 0) {
nullfree(path);
return NC_ENOTNC;
}
} else {
/* presumably not a netcdf file */
nullfree(path);
return stat;
}
}
if(model == 0) {
fprintf(stderr,"Model == 0\n");
return NC_ENOTNC;
}
/* Suppress unsupported formats */
{
int hdf5built = 0;
int hdf4built = 0;
int cdf5built = 0;
#ifdef USE_NETCDF4
hdf5built = 1;
#ifdef USEHDF4
hdf4built = 1;
#endif
#endif
#ifdef ENABLE_CDF5
cdf5built = 1;
#endif
if(!hdf5built && model == NC_FORMATX_NC4) {
free(path);
return NC_ENOTBUILT;
}
if(!hdf4built && model == NC_FORMATX_NC4 && version == 4) {
free(path);
return NC_ENOTBUILT;
}
if(!cdf5built && model == NC_FORMATX_NC3 && version == 5) {
free(path);
return NC_ENOTBUILT;
}
}
/* Force flag consistency */
if(model == NC_FORMATX_NC4 || model == NC_FORMATX_NC_HDF4 || model == NC_FORMATX_DAP4 ||
model == NC_FORMATX_UDF0 || model == NC_FORMATX_UDF1)
omode |= NC_NETCDF4;
else if(model == NC_FORMATX_DAP2) {
omode &= ~NC_NETCDF4;
omode &= ~NC_64BIT_OFFSET;
} else if(model == NC_FORMATX_NC3) {
omode &= ~NC_NETCDF4; /* must be netcdf-3 (CDF-1, CDF-2, CDF-5) */
if(version == 2) omode |= NC_64BIT_OFFSET;
else if(version == 5) omode |= NC_64BIT_DATA;
} else if(model == NC_FORMATX_PNETCDF) {
omode &= ~NC_NETCDF4; /* must be netcdf-3 (CDF-1, CDF-2, CDF-5) */
if(version == 2) omode |= NC_64BIT_OFFSET;
else if(version == 5) omode |= NC_64BIT_DATA;
}
/* Figure out what dispatcher to use */
if (!dispatcher) {
switch (model) {
#if defined(ENABLE_DAP)
case NC_FORMATX_DAP2:
dispatcher = NCD2_dispatch_table;
break;
#endif
#if defined(ENABLE_DAP4)
case NC_FORMATX_DAP4:
dispatcher = NCD4_dispatch_table;
break;
#endif
#if defined(USE_PNETCDF)
case NC_FORMATX_PNETCDF:
dispatcher = NCP_dispatch_table;
break;
#endif
#if defined(USE_NETCDF4)
case NC_FORMATX_NC4:
dispatcher = NC4_dispatch_table;
break;
#endif
#if defined(USE_HDF4)
case NC_FORMATX_NC_HDF4:
dispatcher = HDF4_dispatch_table;
break;
#endif
#ifdef USE_NETCDF4
case NC_FORMATX_UDF0:
dispatcher = UDF0_dispatch_table;
break;
case NC_FORMATX_UDF1:
dispatcher = UDF1_dispatch_table;
break;
#endif /* USE_NETCDF4 */
case NC_FORMATX_NC3:
dispatcher = NC3_dispatch_table;
break;
default:
nullfree(path);
return NC_ENOTNC;
}
}
/* If we can't figure out what dispatch table to use, give up. */
if (!dispatcher) {
nullfree(path);
return NC_ENOTNC;
}
/* Create the NC* instance and insert its dispatcher */
stat = new_NC(dispatcher,path,omode,model,&ncp);
nullfree(path); path = NULL; /* no longer need path */
if(stat) return stat;
/* Add to list of known open files */
add_to_NCList(ncp);
#ifdef USE_REFCOUNT
/* bump the refcount */
ncp->refcount++;
#endif
/* Assume open will fill in remaining ncp fields */
stat = dispatcher->open(ncp->path, omode, basepe, chunksizehintp,
parameters, dispatcher, ncp);
if(stat == NC_NOERR) {
if(ncidp) *ncidp = ncp->ext_ncid;
} else {
del_from_NCList(ncp);
free_NC(ncp);
}
return stat;
}
/*Provide an internal function for generating pseudo file descriptors
for systems that are not file based (e.g. dap, memio).
*/
/** @internal Static counter for pseudo file descriptors (incremented) */
static int pseudofd = 0;
/**
* @internal Create a pseudo file descriptor that does not
* overlap real file descriptors
*
* @return pseudo file number
* @author Dennis Heimbigner
*/
int
nc__pseudofd(void)
{
if(pseudofd == 0) {
int maxfd = 32767; /* default */
#ifdef HAVE_GETRLIMIT
struct rlimit rl;
if(getrlimit(RLIMIT_NOFILE,&rl) == 0) {
if(rl.rlim_max != RLIM_INFINITY)
maxfd = (int)rl.rlim_max;
if(rl.rlim_cur != RLIM_INFINITY)
maxfd = (int)rl.rlim_cur;
}
pseudofd = maxfd+1;
#endif
}
return pseudofd++;
}
/**
\internal
\ingroup datasets
Provide open, read and close for use when searching for magic numbers
*/
static int
openmagic(struct MagicFile* file)
{
int status = NC_NOERR;
assert((file->inmemory) ? file->parameters != NULL : 1);
if(file->inmemory) {
/* Get its length */
NC_memio* meminfo = (NC_memio*)file->parameters;
file->filelen = (long long)meminfo->size;
goto done;
}
#ifdef USE_PARALLEL
if (file->use_parallel) {
int retval;
MPI_Offset size;
assert(file->parameters);
if((retval = MPI_File_open(((NC_MPI_INFO*)file->parameters)->comm,
(char*)file->path,MPI_MODE_RDONLY,
((NC_MPI_INFO*)file->parameters)->info,
&file->fh)) != MPI_SUCCESS) {
#ifdef MPI_ERR_NO_SUCH_FILE
int errorclass;
MPI_Error_class(retval, &errorclass);
if (errorclass == MPI_ERR_NO_SUCH_FILE)
#ifdef NC_ENOENT
status = NC_ENOENT;
#else
status = errno;
#endif
else
#endif
status = NC_EPARINIT;
goto done;
}
/* Get its length */
if((retval=MPI_File_get_size(file->fh, &size)) != MPI_SUCCESS)
{status = NC_EPARINIT; goto done;}
file->filelen = (long long)size;
goto done;
}
#endif /* USE_PARALLEL */
{
if(file->path == NULL || strlen(file->path)==0)
{status = NC_EINVAL; goto done;}
#ifdef _MSC_VER
file->fp = fopen(file->path, "rb");
#else
file->fp = fopen(file->path, "r");
#endif
if(file->fp == NULL)
{status = errno; goto done;}
/* Get its length */
{
int fd = fileno(file->fp);
#ifdef _MSC_VER
__int64 len64 = _filelengthi64(fd);
if(len64 < 0)
{status = errno; goto done;}
file->filelen = (long long)len64;
#else
off_t size;
size = lseek(fd, 0, SEEK_END);
if(size == -1)
{status = errno; goto done;}
file->filelen = (long long)size;
#endif
rewind(file->fp);
}
goto done;
}
done:
return status;
}
static int
readmagic(struct MagicFile* file, long pos, char* magic)
{
int status = NC_NOERR;
memset(magic,0,MAGIC_NUMBER_LEN);
if(file->inmemory) {
char* mempos;
NC_memio* meminfo = (NC_memio*)file->parameters;
if((pos + MAGIC_NUMBER_LEN) > meminfo->size)
{status = NC_EINMEMORY; goto done;}
mempos = ((char*)meminfo->memory) + pos;
memcpy((void*)magic,mempos,MAGIC_NUMBER_LEN);
#ifdef DEBUG
printmagic("XXX: readmagic",magic,file);
#endif
goto done;
}
#ifdef USE_PARALLEL
if (file->use_parallel) {
MPI_Status mstatus;
int retval;
if((retval = MPI_File_read_at_all(file->fh, pos, magic,
MAGIC_NUMBER_LEN, MPI_CHAR, &mstatus)) != MPI_SUCCESS)
{status = NC_EPARINIT; goto done;}
goto done;
}
#endif /* USE_PARALLEL */
{
int count;
int i = fseek(file->fp,pos,SEEK_SET);
if(i < 0)
{status = errno; goto done;}
for(i=0;i<MAGIC_NUMBER_LEN;) {/* make sure to read proper # of bytes */
count=fread(&magic[i],1,(size_t)(MAGIC_NUMBER_LEN-i),file->fp);
if(count == 0 || ferror(file->fp))
{status = errno; goto done;}
i += count;
}
goto done;
}
done:
if(file && file->fp) clearerr(file->fp);
return status;
}
/**
* Close the file opened to check for magic number.
*
* @param file pointer to the MagicFile struct for this open file.
* @returns NC_NOERR for success
* @returns NC_EPARINIT if there was a problem closing file with MPI
* (parallel builds only).
* @author Dennis Heimbigner
*/
static int
closemagic(struct MagicFile* file)
{
int status = NC_NOERR;
if(file->inmemory) goto done; /* noop*/
#ifdef USE_PARALLEL
if (file->use_parallel) {
int retval;
if((retval = MPI_File_close(&file->fh)) != MPI_SUCCESS)
{status = NC_EPARINIT; goto done;}
goto done;
}
#endif
{
if(file->fp) fclose(file->fp);
goto done;
}
done:
return status;
}
#ifdef DEBUG
static void
printmagic(const char* tag, char* magic, struct MagicFile* f)
{
int i;
fprintf(stderr,"%s: inmem=%d ispar=%d magic=",tag,f->inmemory,f->use_parallel);
for(i=0;i<MAGIC_NUMBER_LEN;i++) {
unsigned int c = (unsigned int)magic[i];
c = c & 0x000000FF;
if(c == '\n')
fprintf(stderr," 0x%0x/'\\n'",c);
else if(c == '\r')
fprintf(stderr," 0x%0x/'\\r'",c);
else if(c < ' ')
fprintf(stderr," 0x%0x/'?'",c);
else
fprintf(stderr," 0x%0x/'%c'",c,c);
}
fprintf(stderr,"\n");
fflush(stderr);
}
#endif
|