/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 | } |