Coverage Report

Created: 2025-11-15 08:43

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gdal/netcdf-c-4.7.4/libhdf5/hdf5create.c
Line
Count
Source
1
/* Copyright 2003-2018, University Corporation for Atmospheric
2
 * Research. See COPYRIGHT file for copying and redistribution
3
 * conditions. */
4
/**
5
 * @file
6
 * @internal The netCDF-4 file functions relating to file creation.
7
 *
8
 * @author Ed Hartnett
9
 */
10
11
#include "config.h"
12
#include "hdf5internal.h"
13
14
/* From hdf5file.c. */
15
extern size_t nc4_chunk_cache_size;
16
extern size_t nc4_chunk_cache_nelems;
17
extern float nc4_chunk_cache_preemption;
18
19
/** @internal These flags may not be set for create. */
20
static const int ILLEGAL_CREATE_FLAGS = (NC_NOWRITE|NC_MMAP|NC_64BIT_OFFSET|NC_CDF5);
21
22
/* From nc4mem.c */
23
extern int NC4_create_image_file(NC_FILE_INFO_T* h5, size_t);
24
25
/**
26
 * @internal Create a netCDF-4/HDF5 file.
27
 *
28
 * @param path The file name of the new file.
29
 * @param cmode The creation mode flag.
30
 * @param initialsz The proposed initial file size (advisory, for
31
 * in-memory netCDF-4/HDF5 files only).
32
 * @param parameters extra parameter info (like MPI communicator).
33
 * @param ncid The already-assigned ncid for this file (aka ext_ncid).
34
 *
35
 * @return ::NC_NOERR No error.
36
 * @return ::NC_EINVAL Invalid input (check cmode).
37
 * @return ::NC_EEXIST File exists and NC_NOCLOBBER used.
38
 * @return ::NC_EHDFERR HDF5 returned error.
39
 * @ingroup netcdf4
40
 * @author Ed Hartnett, Dennis Heimbigner
41
 */
42
static int
43
nc4_create_file(const char *path, int cmode, size_t initialsz,
44
                void* parameters, int ncid)
45
6.69k
{
46
6.69k
    hid_t fcpl_id, fapl_id = -1;
47
6.69k
    unsigned flags;
48
6.69k
    FILE *fp;
49
6.69k
    int retval = NC_NOERR;
50
6.69k
    NC_FILE_INFO_T *nc4_info;
51
6.69k
    NC_HDF5_FILE_INFO_T *hdf5_info;
52
6.69k
    NC_HDF5_GRP_INFO_T *hdf5_grp;
53
54
#ifdef USE_PARALLEL4
55
    NC_MPI_INFO *mpiinfo = NULL;
56
    MPI_Comm comm;
57
    MPI_Info info;
58
    int comm_duped = 0; /* Whether the MPI Communicator was duplicated */
59
    int info_duped = 0; /* Whether the MPI Info object was duplicated */
60
#endif /* !USE_PARALLEL4 */
61
62
6.69k
    assert(path);
63
6.69k
    LOG((3, "%s: path %s mode 0x%x", __func__, path, cmode));
64
65
    /* Add necessary structs to hold netcdf-4 file data. */
66
6.69k
    if ((retval = nc4_file_list_add(ncid, path, NC_WRITE | cmode,
67
6.69k
                                    (void **)&nc4_info)))
68
0
        BAIL(retval);
69
6.69k
    assert(nc4_info && nc4_info->root_grp);
70
6.69k
    nc4_info->root_grp->atts_read = 1;
71
72
    /* Add struct to hold HDF5-specific file metadata. */
73
6.69k
    if (!(nc4_info->format_file_info = calloc(1, sizeof(NC_HDF5_FILE_INFO_T))))
74
0
        BAIL(NC_ENOMEM);
75
6.69k
    hdf5_info = (NC_HDF5_FILE_INFO_T *)nc4_info->format_file_info;
76
77
    /* Add struct to hold HDF5-specific group info. */
78
6.69k
    if (!(nc4_info->root_grp->format_grp_info = calloc(1, sizeof(NC_HDF5_GRP_INFO_T))))
79
0
        return NC_ENOMEM;
80
6.69k
    hdf5_grp = (NC_HDF5_GRP_INFO_T *)nc4_info->root_grp->format_grp_info;
81
82
6.69k
    nc4_info->mem.inmemory = (cmode & NC_INMEMORY) == NC_INMEMORY;
83
6.69k
    nc4_info->mem.diskless = (cmode & NC_DISKLESS) == NC_DISKLESS;
84
6.69k
    nc4_info->mem.persist =  (cmode & NC_PERSIST) == NC_PERSIST;
85
6.69k
    nc4_info->mem.created = 1;
86
6.69k
    nc4_info->mem.initialsize = initialsz;
87
88
    /* diskless => !inmemory */
89
6.69k
    if(nc4_info->mem.inmemory && nc4_info->mem.diskless)
90
0
        BAIL(NC_EINTERNAL);
91
92
6.69k
    if(nc4_info->mem.inmemory && parameters)
93
0
        nc4_info->mem.memio = *(NC_memio*)parameters;
94
#ifdef USE_PARALLEL4
95
    else if(parameters) {
96
        mpiinfo = (NC_MPI_INFO *)parameters;
97
        comm = mpiinfo->comm;
98
        info = mpiinfo->info;
99
    }
100
#endif
101
6.69k
    if(nc4_info->mem.diskless)
102
0
        flags = H5F_ACC_TRUNC;
103
6.69k
    else if(cmode & NC_NOCLOBBER)
104
0
        flags = H5F_ACC_EXCL;
105
6.69k
    else
106
6.69k
        flags = H5F_ACC_TRUNC;
107
108
    /* If this file already exists, and NC_NOCLOBBER is specified,
109
       return an error (unless diskless|inmemory) */
110
6.69k
    if (!nc4_info->mem.diskless && !nc4_info->mem.inmemory) {
111
6.69k
        if ((cmode & NC_NOCLOBBER) && (fp = fopen(path, "r"))) {
112
0
            fclose(fp);
113
0
            BAIL(NC_EEXIST);
114
0
        }
115
6.69k
    }
116
117
    /* Need this access plist to control how HDF5 handles open objects
118
     * on file close. Setting H5F_CLOSE_SEMI will cause H5Fclose to
119
     * fail if there are any open objects in the file. */
120
6.69k
    if ((fapl_id = H5Pcreate(H5P_FILE_ACCESS)) < 0)
121
0
        BAIL(NC_EHDFERR);
122
6.69k
    if (H5Pset_fclose_degree(fapl_id, H5F_CLOSE_SEMI))
123
0
        BAIL(NC_EHDFERR);
124
125
#ifdef USE_PARALLEL4
126
    /* If this is a parallel file create, set up the file creation
127
       property list. */
128
    if (mpiinfo != NULL) {
129
        nc4_info->parallel = NC_TRUE;
130
        LOG((4, "creating parallel file with MPI/IO"));
131
        if (H5Pset_fapl_mpio(fapl_id, comm, info) < 0)
132
            BAIL(NC_EPARINIT);
133
134
        /* Keep copies of the MPI Comm & Info objects */
135
        if (MPI_SUCCESS != MPI_Comm_dup(comm, &nc4_info->comm))
136
            BAIL(NC_EMPI);
137
        comm_duped++;
138
        if (MPI_INFO_NULL != info)
139
        {
140
            if (MPI_SUCCESS != MPI_Info_dup(info, &nc4_info->info))
141
                BAIL(NC_EMPI);
142
            info_duped++;
143
        }
144
        else
145
        {
146
            /* No dup, just copy it. */
147
            nc4_info->info = info;
148
        }
149
    }
150
#else /* only set cache for non-parallel... */
151
6.69k
    if (H5Pset_cache(fapl_id, 0, nc4_chunk_cache_nelems, nc4_chunk_cache_size,
152
6.69k
                     nc4_chunk_cache_preemption) < 0)
153
0
        BAIL(NC_EHDFERR);
154
6.69k
    LOG((4, "%s: set HDF raw chunk cache to size %d nelems %d preemption %f",
155
6.69k
         __func__, nc4_chunk_cache_size, nc4_chunk_cache_nelems,
156
6.69k
         nc4_chunk_cache_preemption));
157
6.69k
#endif /* USE_PARALLEL4 */
158
159
#ifdef HAVE_H5PSET_LIBVER_BOUNDS
160
#if H5_VERSION_GE(1,10,2)
161
    if (H5Pset_libver_bounds(fapl_id, H5F_LIBVER_EARLIEST, H5F_LIBVER_V18) < 0)
162
#else
163
        if (H5Pset_libver_bounds(fapl_id, H5F_LIBVER_EARLIEST,
164
                                 H5F_LIBVER_LATEST) < 0)
165
#endif
166
            BAIL(NC_EHDFERR);
167
#endif
168
169
    /* Create the property list. */
170
6.69k
    if ((fcpl_id = H5Pcreate(H5P_FILE_CREATE)) < 0)
171
0
        BAIL(NC_EHDFERR);
172
173
    /* RJ: this suppose to be FALSE that is defined in H5 private.h as 0 */
174
6.69k
    if (H5Pset_obj_track_times(fcpl_id,0)<0)
175
0
        BAIL(NC_EHDFERR);
176
177
    /* Set latest_format in access propertly list and
178
     * H5P_CRT_ORDER_TRACKED in the creation property list. This turns
179
     * on HDF5 creation ordering. */
180
6.69k
    if (H5Pset_link_creation_order(fcpl_id, (H5P_CRT_ORDER_TRACKED |
181
6.69k
                                             H5P_CRT_ORDER_INDEXED)) < 0)
182
0
        BAIL(NC_EHDFERR);
183
6.69k
    if (H5Pset_attr_creation_order(fcpl_id, (H5P_CRT_ORDER_TRACKED |
184
6.69k
                                             H5P_CRT_ORDER_INDEXED)) < 0)
185
0
        BAIL(NC_EHDFERR);
186
187
#ifdef HDF5_HAS_COLL_METADATA_OPS
188
    /* If HDF5 supports collective metadata operations, turn them
189
     * on. This is only relevant for parallel I/O builds of HDF5. */
190
    if (H5Pset_all_coll_metadata_ops(fapl_id, 1) < 0)
191
        BAIL(NC_EHDFERR);
192
    if (H5Pset_coll_metadata_write(fapl_id, 1) < 0)
193
        BAIL(NC_EHDFERR);
194
#endif
195
196
6.69k
    if(nc4_info->mem.inmemory) {
197
0
        retval = NC4_create_image_file(nc4_info,initialsz);
198
0
        if(retval)
199
0
            BAIL(retval);
200
0
    }
201
6.69k
    else
202
6.69k
        if(nc4_info->mem.diskless) {
203
0
            size_t alloc_incr;     /* Buffer allocation increment */
204
0
            size_t min_incr = 65536; /* Minimum buffer increment */
205
0
            double buf_prcnt = 0.1f;  /* Percentage of buffer size to set as increment */
206
            /* set allocation increment to a percentage of the supplied buffer size, or
207
             * a pre-defined minimum increment value, whichever is larger
208
             */
209
0
            if ((buf_prcnt * initialsz) > min_incr)
210
0
                alloc_incr = (size_t)(buf_prcnt * initialsz);
211
0
            else
212
0
                alloc_incr = min_incr;
213
            /* Configure FAPL to use the core file driver */
214
0
            if (H5Pset_fapl_core(fapl_id, alloc_incr, (nc4_info->mem.persist?1:0)) < 0)
215
0
                BAIL(NC_EHDFERR);
216
0
            if ((hdf5_info->hdfid = H5Fcreate(path, flags, fcpl_id, fapl_id)) < 0)
217
0
                BAIL(EACCES);
218
0
        }
219
6.69k
        else /* Normal file */
220
6.69k
        {
221
            /* Create the HDF5 file. */
222
6.69k
            if ((hdf5_info->hdfid = H5Fcreate(path, flags, fcpl_id, fapl_id)) < 0)
223
0
                BAIL(EACCES);
224
6.69k
        }
225
226
    /* Open the root group. */
227
6.69k
    if ((hdf5_grp->hdf_grpid = H5Gopen2(hdf5_info->hdfid, "/", H5P_DEFAULT)) < 0)
228
0
        BAIL(NC_EFILEMETA);
229
230
    /* Release the property lists. */
231
6.69k
    if (H5Pclose(fapl_id) < 0 || H5Pclose(fcpl_id) < 0)
232
0
        BAIL(NC_EHDFERR);
233
234
    /* Define mode gets turned on automatically on create. */
235
6.69k
    nc4_info->flags |= NC_INDEF;
236
237
    /* Save the HDF5 superblock number and set the _NCProperties attribute. */
238
6.69k
    if ((retval = NC4_new_provenance(nc4_info)))
239
0
        BAIL(retval);
240
241
6.69k
    return NC_NOERR;
242
243
0
exit: /*failure exit*/
244
#ifdef USE_PARALLEL4
245
    if (comm_duped) MPI_Comm_free(&nc4_info->comm);
246
    if (info_duped) MPI_Info_free(&nc4_info->info);
247
#endif
248
0
    if (fapl_id != H5P_DEFAULT) H5Pclose(fapl_id);
249
0
    if(!nc4_info) return retval;
250
0
    nc4_close_hdf5_file(nc4_info, 1, NULL); /* treat like abort */
251
0
    return retval;
252
0
}
253
254
/**
255
 * @internal Create a netCDF-4/HDF5 file.
256
 *
257
 * @param path The file name of the new file.
258
 * @param cmode The creation mode flag.
259
 * @param initialsz Ignored by this function.
260
 * @param basepe Ignored by this function.
261
 * @param chunksizehintp Ignored by this function.
262
 * @param parameters pointer to struct holding extra data (e.g. for
263
 * parallel I/O) layer. Ignored if NULL.
264
 * @param dispatch Pointer to the dispatch table for this file.
265
 * @param ncid The ncid that has been assigned by the dispatch layer
266
 * (aka ext_ncid).
267
 *
268
 * @return ::NC_NOERR No error.
269
 * @return ::NC_EINVAL Invalid input (check cmode).
270
 * @ingroup netcdf4
271
 * @author Ed Hartnett
272
 */
273
int
274
NC4_create(const char* path, int cmode, size_t initialsz, int basepe,
275
           size_t *chunksizehintp, void *parameters,
276
           const NC_Dispatch *dispatch, int ncid)
277
6.69k
{
278
6.69k
    int res;
279
280
6.69k
    assert(path);
281
282
6.69k
    LOG((1, "%s: path %s cmode 0x%x parameters %p",
283
6.69k
         __func__, path, cmode, parameters));
284
285
    /* If this is our first file, turn off HDF5 error messages. */
286
6.69k
    if (!nc4_hdf5_initialized)
287
0
        nc4_hdf5_initialize();
288
289
#ifdef LOGGING
290
    /* If nc logging level has changed, see if we need to turn on
291
     * HDF5's error messages. */
292
    hdf5_set_log_level();
293
#endif /* LOGGING */
294
295
    /* Check the cmode for validity. Checking parallel against
296
     * NC_DISKLESS already done in NC_create(). */
297
6.69k
    if (cmode & ILLEGAL_CREATE_FLAGS)
298
0
        return NC_EINVAL;
299
300
    /* Create the netCDF-4/HDF5 file. */
301
6.69k
    res = nc4_create_file(path, cmode, initialsz, parameters, ncid);
302
303
6.69k
    return res;
304
6.69k
}