/src/netcdf-c/libnczarr/zdim.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* Copyright 2003-2019, University Corporation for Atmospheric |
2 | | * Research. See the COPYRIGHT file for copying and redistribution |
3 | | * conditions. */ |
4 | | |
5 | | /** |
6 | | * @file @internal This file is part of netcdf-4, a netCDF-like |
7 | | * interface for NCZ, or a ZARR backend for netCDF, depending on your |
8 | | * point of view. |
9 | | * |
10 | | * This file includes the ZARR code to deal with dimensions. |
11 | | * |
12 | | * @author Dennis Heimbigner, Ed Hartnett |
13 | | */ |
14 | | |
15 | | #include "zincludes.h" |
16 | | |
17 | | /** |
18 | | * @internal Dimensions are defined in attributes attached to the |
19 | | * appropriate group in the data file. |
20 | | * |
21 | | * @param ncid File and group ID. |
22 | | * @param name Name of the new dimension. |
23 | | * @param len Length of the new dimension. |
24 | | * @param idp Pointer that gets the ID of the new dimension. Ignored |
25 | | * if NULL. |
26 | | * |
27 | | * @return ::NC_NOERR No error. |
28 | | * @return ::NC_EBADID Bad ncid. |
29 | | * @return ::NC_EMAXNAME Name is too long. |
30 | | * @return ::NC_EBADNAME Name breaks netCDF name rules. |
31 | | * @return ::NC_EINVAL Invalid input. |
32 | | * @return ::NC_EPERM Read-only file. |
33 | | * @return ::NC_EUNLIMIT Only one unlimited dim for classic model. |
34 | | * @return ::NC_ENOTINDEFINE Not in define mode. |
35 | | * @return ::NC_EDIMSIZE Dim length too large. |
36 | | * @return ::NC_ENAMEINUSE Name already in use in group. |
37 | | * @return ::NC_ENOMEM Out of memory. |
38 | | * @author Dennis Heimbigner, Ed Hartnett |
39 | | */ |
40 | | int |
41 | | NCZ_def_dim(int ncid, const char *name, size_t len, int *idp) |
42 | 0 | { |
43 | 0 | NC *nc; |
44 | 0 | NC_GRP_INFO_T *grp; |
45 | 0 | NC_FILE_INFO_T *h5; |
46 | 0 | NC_DIM_INFO_T *dim; |
47 | 0 | char norm_name[NC_MAX_NAME + 1]; |
48 | 0 | int stat = NC_NOERR; |
49 | |
|
50 | 0 | LOG((2, "%s: ncid 0x%x name %s len %d", __func__, ncid, name, |
51 | 0 | (int)len)); |
52 | | |
53 | | /* Find our global metadata structure. */ |
54 | 0 | if ((stat = nc4_find_nc_grp_h5(ncid, &nc, &grp, &h5))) |
55 | 0 | return stat; |
56 | 0 | assert(h5 && nc && grp); |
57 | | |
58 | | /* If the file is read-only, return an error. */ |
59 | 0 | if (h5->no_write) |
60 | 0 | return NC_EPERM; |
61 | | |
62 | | /* Check some stuff if strict nc3 rules are in effect. */ |
63 | 0 | if (h5->cmode & NC_CLASSIC_MODEL) |
64 | 0 | { |
65 | | #ifdef LOOK |
66 | | /* Only one limited dimenson for strict nc3. */ |
67 | | if (len == NC_UNLIMITED) { |
68 | | int i; |
69 | | for(i=0;i<ncindexsize(grp->dim);i++) { |
70 | | dim = (NC_DIM_INFO_T*)ncindexith(grp->dim,i); |
71 | | if(dim == NULL) continue; |
72 | | if (dim->unlimited) |
73 | | return NC_EUNLIMIT; |
74 | | } |
75 | | } |
76 | | /* Must be in define mode for stict nc3. */ |
77 | | if (!(h5->flags & NC_INDEF)) |
78 | | return NC_ENOTINDEFINE; |
79 | | #endif |
80 | 0 | } |
81 | | |
82 | | /* Make sure this is a valid netcdf name. */ |
83 | 0 | if ((stat = nc4_check_name(name, norm_name))) |
84 | 0 | return stat; |
85 | | |
86 | | /* Since unlimited is not supported, len > 0 */ |
87 | 0 | if(len <= 0) |
88 | 0 | return NC_EDIMSIZE; |
89 | | |
90 | | /* For classic model: dim length has to fit in a 32-bit unsigned |
91 | | * int, as permitted for 64-bit offset format. */ |
92 | 0 | if (h5->cmode & NC_CLASSIC_MODEL) |
93 | 0 | if(len > X_UINT_MAX) /* Backward compat */ |
94 | 0 | return NC_EDIMSIZE; |
95 | | |
96 | | /* Make sure the name is not already in use. */ |
97 | 0 | dim = (NC_DIM_INFO_T*)ncindexlookup(grp->dim,norm_name); |
98 | 0 | if(dim != NULL) |
99 | 0 | return NC_ENAMEINUSE; |
100 | | |
101 | | /* If it's not in define mode, enter define mode. Do this only |
102 | | * after checking all input data, so we only enter define mode if |
103 | | * input is good. */ |
104 | 0 | if (!(h5->flags & NC_INDEF)) |
105 | 0 | if ((stat = NCZ_redef(ncid))) |
106 | 0 | return stat; |
107 | | |
108 | | /* Add a dimension to the list. The ID must come from the file |
109 | | * information, since dimids are visible in more than one group. */ |
110 | 0 | if ((stat = nc4_dim_list_add(grp, norm_name, len, -1, &dim))) |
111 | 0 | return stat; |
112 | | |
113 | | /* Create struct for NCZ-specific dim info. */ |
114 | 0 | if (!(dim->format_dim_info = calloc(1, sizeof(NCZ_DIM_INFO_T)))) |
115 | 0 | return NC_ENOMEM; |
116 | 0 | ((NCZ_DIM_INFO_T*)dim->format_dim_info)->common.file = h5; |
117 | | |
118 | | /* Pass back the dimid. */ |
119 | 0 | if (idp) |
120 | 0 | *idp = dim->hdr.id; |
121 | |
|
122 | 0 | return stat; |
123 | 0 | } |
124 | | |
125 | | /** |
126 | | * @internal Find out name and len of a dim. For an unlimited |
127 | | * dimension, the length is the largest length so far written. If the |
128 | | * name of lenp pointers are NULL, they will be ignored. |
129 | | * |
130 | | * @param ncid File and group ID. |
131 | | * @param dimid Dimension ID. |
132 | | * @param name Pointer that gets name of the dimension. |
133 | | * @param lenp Pointer that gets length of dimension. |
134 | | * |
135 | | * @return ::NC_NOERR No error. |
136 | | * @return ::NC_EBADID Bad ncid. |
137 | | * @return ::NC_EDIMSIZE Dimension length too large. |
138 | | * @return ::NC_EBADDIM Dimension not found. |
139 | | * @author Dennis Heimbigner, Ed Hartnett |
140 | | */ |
141 | | int |
142 | | NCZ_inq_dim(int ncid, int dimid, char *name, size_t *lenp) |
143 | 0 | { |
144 | 0 | NC *nc; |
145 | 0 | NC_FILE_INFO_T *h5; |
146 | 0 | NC_GRP_INFO_T *grp, *dim_grp; |
147 | 0 | NC_DIM_INFO_T *dim; |
148 | 0 | int stat = NC_NOERR; |
149 | |
|
150 | 0 | LOG((2, "%s: ncid 0x%x dimid %d", __func__, ncid, dimid)); |
151 | | |
152 | | /* Find our global metadata structure. */ |
153 | 0 | if ((stat = nc4_find_nc_grp_h5(ncid, &nc, &grp, &h5))) |
154 | 0 | return stat; |
155 | 0 | assert(h5 && nc && grp); |
156 | | |
157 | | /* Find the dimension and its home group. */ |
158 | 0 | if ((stat = nc4_find_dim(grp, dimid, &dim, &dim_grp))) |
159 | 0 | return stat; |
160 | 0 | assert(dim); |
161 | | |
162 | | /* Return the dimension name, if the caller wants it. */ |
163 | 0 | if (name && dim->hdr.name) |
164 | 0 | strcpy(name, dim->hdr.name); |
165 | | |
166 | | /* Return the dimension length, if the caller wants it. */ |
167 | 0 | if (lenp) |
168 | 0 | { |
169 | | #ifdef LOOK |
170 | | if (dim->unlimited) |
171 | | { |
172 | | /* Since this is an unlimited dimension, go to the file |
173 | | and see how many records there are. Take the max number |
174 | | of records from all the vars that share this |
175 | | dimension. */ |
176 | | *lenp = 0; |
177 | | if ((stat = ncz_find_dim_len(dim_grp, dimid, &lenp))) |
178 | | return stat; |
179 | | } |
180 | | else |
181 | | #endif |
182 | 0 | { |
183 | 0 | if (dim->too_long) |
184 | 0 | { |
185 | 0 | stat = NC_EDIMSIZE; |
186 | 0 | *lenp = NC_MAX_UINT; |
187 | 0 | } |
188 | 0 | else |
189 | 0 | *lenp = dim->len; |
190 | 0 | } |
191 | 0 | } |
192 | |
|
193 | 0 | return stat; |
194 | 0 | } |
195 | | |
196 | | /** |
197 | | * @internal Rename a dimension, for those who like to prevaricate. |
198 | | * |
199 | | * @note If we're not in define mode, new name must be of equal or |
200 | | * less size, if strict nc3 rules are in effect for this file. But we |
201 | | * don't check this because reproducing the exact classic behavior |
202 | | * would be too difficult. See github issue #1340. |
203 | | * |
204 | | * @param ncid File and group ID. |
205 | | * @param dimid Dimension ID. |
206 | | * @param name New dimension name. |
207 | | * |
208 | | * @return ::NC_NOERR No error. |
209 | | * @return ::NC_EBADID Bad ncid. |
210 | | * @return ::NC_EHDFERR ZARR returned error. |
211 | | * @return ::NC_ENOMEM Out of memory. |
212 | | * @return ::NC_EINVAL Name must be provided. |
213 | | * @return ::NC_ENAMEINUSE Name is already in use in group. |
214 | | * @return ::NC_EMAXNAME Name is too long. |
215 | | * @return ::NC_EBADDIM Dimension not found. |
216 | | * @return ::NC_EBADNAME Name breaks netCDF name rules. |
217 | | * @return ::NC_EDIMMETA Unable to delete ZARR dataset. |
218 | | * @author Dennis Heimbigner, Ed Hartnett |
219 | | */ |
220 | | int |
221 | | NCZ_rename_dim(int ncid, int dimid, const char *name) |
222 | 0 | { |
223 | 0 | NC_GRP_INFO_T *grp; |
224 | 0 | NC_DIM_INFO_T *dim; |
225 | 0 | NC_FILE_INFO_T *h5; |
226 | 0 | char norm_name[NC_MAX_NAME + 1]; |
227 | 0 | int stat; |
228 | | |
229 | | /* Note: name is new name */ |
230 | 0 | if (!name) |
231 | 0 | return NC_EINVAL; |
232 | | |
233 | 0 | LOG((2, "%s: ncid 0x%x dimid %d name %s", __func__, ncid, |
234 | 0 | dimid, name)); |
235 | | |
236 | | /* Find info for this file and group, and set pointer to each. */ |
237 | 0 | if ((stat = nc4_find_grp_h5(ncid, &grp, &h5))) |
238 | 0 | return stat; |
239 | 0 | assert(h5 && grp); |
240 | | |
241 | | /* Trying to write to a read-only file? No way, Jose! */ |
242 | 0 | if (h5->no_write) |
243 | 0 | return NC_EPERM; |
244 | | |
245 | | /* Make sure this is a valid netcdf name. */ |
246 | 0 | if ((stat = nc4_check_name(name, norm_name))) |
247 | 0 | return stat; |
248 | | |
249 | | /* Get the original dim. */ |
250 | 0 | if ((stat = nc4_find_dim(grp, dimid, &dim, NULL))) |
251 | 0 | return stat; |
252 | 0 | assert(dim && dim->format_dim_info); |
253 | | |
254 | | /* Check if new name is in use. */ |
255 | 0 | if (ncindexlookup(grp->dim, norm_name)) |
256 | 0 | return NC_ENAMEINUSE; |
257 | | |
258 | | /* Give the dimension its new name in metadata. UTF8 normalization |
259 | | * has been done. */ |
260 | 0 | assert(dim->hdr.name); |
261 | 0 | free(dim->hdr.name); |
262 | 0 | if (!(dim->hdr.name = strdup(norm_name))) |
263 | 0 | return NC_ENOMEM; |
264 | 0 | LOG((3, "dim is now named %s", dim->hdr.name)); |
265 | | |
266 | | /* rebuild index. */ |
267 | 0 | if (!ncindexrebuild(grp->dim)) |
268 | 0 | return NC_EINTERNAL; |
269 | | |
270 | 0 | return NC_NOERR; |
271 | 0 | } |
272 | | |
273 | | int |
274 | | NCZ_inq_unlimdims(int ncid, int *ndimsp, int *unlimdimidsp) |
275 | 0 | { |
276 | 0 | if(ndimsp) *ndimsp = 0; |
277 | 0 | return NC_NOERR; |
278 | 0 | } |