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