Coverage Report

Created: 2022-11-18 06:58

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