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