Coverage Report

Created: 2023-05-28 06:42

/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, &params, &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
}