Coverage Report

Created: 2025-06-09 08:44

/src/gdal/netcdf-c-4.7.4/libdispatch/nclistmgr.c
Line
Count
Source (jump to first uncovered line)
1
/*********************************************************************
2
   Copyright 2018, UCAR/Unidata See netcdf/COPYRIGHT file for
3
   copying and redistribution conditions.
4
*********************************************************************/
5
/**
6
 * @file
7
 *
8
 * Functions to manage the list of NC structs. There is one NC struct
9
 * for each open file.
10
 *
11
 * @author Dennis Heimbigner
12
*/
13
14
#include "config.h"
15
#include <stdlib.h>
16
#include <string.h>
17
#include <assert.h>
18
#include "ncdispatch.h"
19
20
/** This shift is applied to the ext_ncid in order to get the index in
21
 * the array of NC. */
22
62.2M
#define ID_SHIFT (16)
23
24
/** This is the length of the NC list - the number of files that can
25
 * be open at one time. We use 2^16 = 65536 entries in the array, but
26
 * slot 0 is not used, so only 65535 files may be open at one
27
 * time. */
28
63.4k
#define NCFILELISTLENGTH 0x10000
29
30
/** This is the pointer to the array of NC, one for each open file. */
31
static NC** nc_filelist = NULL;
32
33
/** The number of files currently open. */
34
static int numfiles = 0;
35
36
/**
37
 * How many files are currently open?
38
 *
39
 * @return number of open files.
40
 * @author Dennis Heimbigner
41
 */
42
int
43
count_NCList(void)
44
0
{
45
0
    return numfiles;
46
0
}
47
48
/**
49
 * Free an empty NCList. @note If list is not empty, or has not been
50
 * allocated, function will silently exit.
51
 *
52
 * @author Dennis Heimbigner
53
 */
54
void
55
free_NCList(void)
56
31.4k
{
57
31.4k
    if(numfiles > 0) return; /* not empty */
58
31.4k
    if(nc_filelist != NULL) free(nc_filelist);
59
31.4k
    nc_filelist = NULL;
60
31.4k
}
61
62
/**
63
 * Add an already-allocated NC to the list. It will be assigned an
64
 * ncid in this function.
65
 *
66
 * If this is the first file to be opened, the nc_filelist will be
67
 * allocated and set to all 0.
68
 *
69
 * The ncid is assigned by finding the first open index in the
70
 * nc_filelist array (skipping index 0). The ncid is this index
71
 * left-shifted ID_SHIFT bits (16). This puts the file ID in the first
72
 * two bytes of the 4-byte integer, and leaves the last two bytes for
73
 * group IDs for netCDF-4 files.
74
 *
75
 * @param ncp Pointer to already-allocated and initialized NC struct.
76
 *
77
 * @return ::NC_NOERR No error.
78
 * @return ::NC_ENOMEM Out of memory.
79
 * @author Dennis Heimbigner
80
 */
81
int
82
add_to_NCList(NC* ncp)
83
31.7k
{
84
31.7k
    int i;
85
31.7k
    int new_id;
86
31.7k
    if(nc_filelist == NULL) {
87
31.4k
        if (!(nc_filelist = calloc(1, sizeof(NC*)*NCFILELISTLENGTH)))
88
0
            return NC_ENOMEM;
89
31.4k
        numfiles = 0;
90
31.4k
    }
91
92
31.7k
    new_id = 0; /* id's begin at 1 */
93
31.9k
    for(i=1; i < NCFILELISTLENGTH; i++) {
94
31.9k
        if(nc_filelist[i] == NULL) {new_id = i; break;}
95
31.9k
    }
96
31.7k
    if(new_id == 0) return NC_ENOMEM; /* no more slots */
97
31.7k
    nc_filelist[new_id] = ncp;
98
31.7k
    numfiles++;
99
31.7k
    ncp->ext_ncid = (new_id << ID_SHIFT);
100
31.7k
    return NC_NOERR;
101
31.7k
}
102
103
/**
104
 * Move an NC in the nc_filelist. This is required by PIO.
105
 *
106
 * @param ncp Pointer to already-allocated and initialized NC struct.
107
 * @param new_id New index in the nc_filelist for this file.
108
 *
109
 * @return ::NC_NOERR No error.
110
 * @return ::NC_EINVAL Invalid input.
111
 * @author Ed Hartnett
112
 */
113
int
114
move_in_NCList(NC *ncp, int new_id)
115
0
{
116
    /* If no files in list, error. */
117
0
    if (!nc_filelist)
118
0
        return NC_EINVAL;
119
120
    /* If new slot is already taken, error. */
121
0
    if (nc_filelist[new_id])
122
0
        return NC_EINVAL;
123
124
    /* Move the file. */
125
0
    nc_filelist[ncp->ext_ncid >> ID_SHIFT] = NULL;
126
0
    nc_filelist[new_id] = ncp;
127
0
    ncp->ext_ncid = (new_id << ID_SHIFT);
128
129
0
    return NC_NOERR;
130
0
}
131
132
/**
133
 * Delete an NC struct from the list. This happens when the file is
134
 * closed. Relies on all memory in the NC being deallocated after this
135
 * function with freeNC().
136
 *
137
 * @note If the file list is empty, or this NC can't be found in the
138
 * list, this function will silently exit.
139
 *
140
 * @param ncp Pointer to NC to be removed from list.
141
 *
142
 * @author Dennis Heimbigner
143
 */
144
void
145
del_from_NCList(NC* ncp)
146
31.7k
{
147
31.7k
    unsigned int ncid = ((unsigned int)ncp->ext_ncid) >> ID_SHIFT;
148
31.7k
    if(numfiles == 0 || ncid == 0 || nc_filelist == NULL) return;
149
31.7k
    if(nc_filelist[ncid] != ncp) return;
150
151
31.7k
    nc_filelist[ncid] = NULL;
152
31.7k
    numfiles--;
153
154
    /* If all files have been closed, release the filelist memory. */
155
31.7k
    if (numfiles == 0)
156
31.4k
        free_NCList();
157
31.7k
}
158
159
/**
160
 * Find an NC in the list, given an ext_ncid. The NC list is indexed
161
 * with the first two bytes of ext_ncid. (The last two bytes specify
162
 * the group for netCDF4 files, or are zeros for classic files.)
163
 *
164
 * @param ext_ncid The ncid of the file to find.
165
 *
166
 * @return pointer to NC or NULL if not found.
167
 * @author Dennis Heimbigner, Ed Hartnett
168
 */
169
NC *
170
find_in_NCList(int ext_ncid)
171
38.9M
{
172
38.9M
    NC* f = NULL;
173
174
    /* Discard the first two bytes of ext_ncid to get ncid. */
175
38.9M
    unsigned int ncid = ((unsigned int)ext_ncid) >> ID_SHIFT;
176
177
    /* If we have a filelist, there will be an entry, possibly NULL,
178
     * for this ncid. */
179
38.9M
    if (nc_filelist)
180
38.9M
    {
181
38.9M
        assert(numfiles);
182
38.9M
        f = nc_filelist[ncid];
183
38.9M
    }
184
185
    /* For classic files, ext_ncid must be a multiple of
186
     * (1<<ID_SHIFT). That is, the group part of the ext_ncid (the
187
     * last two bytes) must be zero. If not, then return NULL, which
188
     * will eventually lead to an NC_EBADID error being returned to
189
     * user. */
190
38.9M
    if (f != NULL && f->dispatch != NULL
191
38.9M
  && f->dispatch->model == NC_FORMATX_NC3 && (ext_ncid % (1<<ID_SHIFT)))
192
0
        return NULL;
193
194
38.9M
    return f;
195
38.9M
}
196
197
/**
198
 * Find an NC in the list using the file name.
199
 *
200
 * @param path Name of the file.
201
 *
202
 * @return pointer to NC or NULL if not found.
203
 * @author Dennis Heimbigner
204
 */
205
NC*
206
find_in_NCList_by_name(const char* path)
207
0
{
208
0
    int i;
209
0
    NC* f = NULL;
210
0
    if(nc_filelist == NULL)
211
0
        return NULL;
212
0
    for(i=1; i < NCFILELISTLENGTH; i++) {
213
0
        if(nc_filelist[i] != NULL) {
214
0
            if(strcmp(nc_filelist[i]->path,path)==0) {
215
0
                f = nc_filelist[i];
216
0
                break;
217
0
            }
218
0
        }
219
0
    }
220
0
    return f;
221
0
}
222
223
/**
224
 * Find an NC in list based on its index. The index is ((unsigned
225
 * int)ext_ncid) >> ID_SHIFT. This is the two high bytes of the
226
 * ext_ncid. (The other two bytes are used for the group ID for
227
 * netCDF-4 files.)
228
 *
229
 * @param index The index in the NC list.
230
 * @param ncp Pointer that gets pointer to the next NC. Ignored if
231
 * NULL.
232
 *
233
 * @return ::NC_NOERR No error.
234
 * @return ::NC_ERANGE Index out of range.
235
 * @author Dennis Heimbigner
236
 */
237
int
238
iterate_NCList(int index, NC** ncp)
239
0
{
240
    /* Walk from 0 ...; 0 return => stop */
241
0
    if(index < 0 || index >= NCFILELISTLENGTH)
242
0
        return NC_ERANGE;
243
0
    if(ncp) *ncp = nc_filelist[index];
244
0
    return NC_NOERR;
245
0
}