/src/netcdf-c/libnczarr/zarr.c
Line | Count | Source (jump to first uncovered line) |
1 | | /********************************************************************* |
2 | | * Copyright 2018, UCAR/Unidata |
3 | | * See netcdf/COPYRIGHT file for copying and redistribution conditions. |
4 | | *********************************************************************/ |
5 | | |
6 | | #include "zincludes.h" |
7 | | |
8 | | /**************************************************/ |
9 | | /* Forwards */ |
10 | | |
11 | | static int applycontrols(NCZ_FILE_INFO_T* zinfo); |
12 | | |
13 | | /***************************************************/ |
14 | | /* API */ |
15 | | |
16 | | /** |
17 | | @internal Create the topmost dataset object and setup up |
18 | | NCZ_FILE_INFO_T state. |
19 | | @param zinfo - [in] the internal state |
20 | | @return NC_NOERR |
21 | | @author Dennis Heimbigner |
22 | | */ |
23 | | |
24 | | int |
25 | | ncz_create_dataset(NC_FILE_INFO_T* file, NC_GRP_INFO_T* root, const char** controls) |
26 | 0 | { |
27 | 0 | int stat = NC_NOERR; |
28 | 0 | NCZ_FILE_INFO_T* zinfo = NULL; |
29 | 0 | NCZ_GRP_INFO_T* zgrp = NULL; |
30 | 0 | NCURI* uri = NULL; |
31 | 0 | NC* nc = NULL; |
32 | 0 | NCjson* json = NULL; |
33 | 0 | char* key = NULL; |
34 | |
|
35 | 0 | ZTRACE(3,"file=%s root=%s controls=%s",file->hdr.name,root->hdr.name,(controls?nczprint_envv(controls):"null")); |
36 | |
|
37 | 0 | nc = (NC*)file->controller; |
38 | | |
39 | | /* Add struct to hold NCZ-specific file metadata. */ |
40 | 0 | if (!(zinfo = calloc(1, sizeof(NCZ_FILE_INFO_T)))) |
41 | 0 | {stat = NC_ENOMEM; goto done;} |
42 | 0 | file->format_file_info = zinfo; |
43 | 0 | zinfo->common.file = file; |
44 | | |
45 | | /* Add struct to hold NCZ-specific group info. */ |
46 | 0 | if (!(zgrp = calloc(1, sizeof(NCZ_GRP_INFO_T)))) |
47 | 0 | {stat = NC_ENOMEM; goto done;} |
48 | 0 | root->format_grp_info = zgrp; |
49 | 0 | zgrp->common.file = file; |
50 | | |
51 | | /* Fill in NCZ_FILE_INFO_T */ |
52 | 0 | zinfo->created = 1; |
53 | 0 | zinfo->common.file = file; |
54 | 0 | zinfo->native_endianness = (NCZ_isLittleEndian() ? NC_ENDIAN_LITTLE : NC_ENDIAN_BIG); |
55 | 0 | if((zinfo->envv_controls=NCZ_clonestringvec(0,controls)) == NULL) |
56 | 0 | {stat = NC_ENOMEM; goto done;} |
57 | | |
58 | | /* fill in some of the zinfo and zroot fields */ |
59 | 0 | zinfo->zarr.zarr_version = atoi(ZARRVERSION); |
60 | 0 | sscanf(NCZARRVERSION,"%lu.%lu.%lu", |
61 | 0 | &zinfo->zarr.nczarr_version.major, |
62 | 0 | &zinfo->zarr.nczarr_version.minor, |
63 | 0 | &zinfo->zarr.nczarr_version.release); |
64 | |
|
65 | 0 | zinfo->default_maxstrlen = NCZ_MAXSTR_DEFAULT; |
66 | | |
67 | | /* Apply client controls */ |
68 | 0 | if((stat = applycontrols(zinfo))) goto done; |
69 | | |
70 | | /* Load auth info from rc file */ |
71 | 0 | if((stat = ncuriparse(nc->path,&uri))) goto done; |
72 | 0 | if(uri) { |
73 | 0 | if((stat = NC_authsetup(&zinfo->auth, uri))) |
74 | 0 | goto done; |
75 | 0 | } |
76 | | |
77 | | /* initialize map handle*/ |
78 | 0 | if((stat = nczmap_create(zinfo->controls.mapimpl,nc->path,nc->mode,zinfo->controls.flags,NULL,&zinfo->map))) |
79 | 0 | goto done; |
80 | | |
81 | 0 | done: |
82 | 0 | ncurifree(uri); |
83 | 0 | NCJreclaim(json); |
84 | 0 | nullfree(key); |
85 | 0 | return ZUNTRACE(stat); |
86 | 0 | } |
87 | | |
88 | | /** |
89 | | @internal Open the topmost dataset object. |
90 | | @param file - [in] the file struct |
91 | | @param controls - [in] the fragment list in envv form from uri |
92 | | @return NC_NOERR |
93 | | @author Dennis Heimbigner |
94 | | */ |
95 | | |
96 | | int |
97 | | ncz_open_dataset(NC_FILE_INFO_T* file, const char** controls) |
98 | 0 | { |
99 | 0 | int stat = NC_NOERR; |
100 | 0 | NC* nc = NULL; |
101 | 0 | NC_GRP_INFO_T* root = NULL; |
102 | 0 | NCURI* uri = NULL; |
103 | 0 | void* content = NULL; |
104 | 0 | NCjson* json = NULL; |
105 | 0 | NCZ_FILE_INFO_T* zinfo = NULL; |
106 | 0 | int mode; |
107 | 0 | NClist* modeargs = NULL; |
108 | 0 | char* nczarr_version = NULL; |
109 | 0 | char* zarr_format = NULL; |
110 | |
|
111 | 0 | ZTRACE(3,"file=%s controls=%s",file->hdr.name,(controls?nczprint_envv(controls):"null")); |
112 | | |
113 | | /* Extract info reachable via file */ |
114 | 0 | nc = (NC*)file->controller; |
115 | 0 | mode = nc->mode; |
116 | |
|
117 | 0 | root = file->root_grp; |
118 | 0 | assert(root != NULL && root->hdr.sort == NCGRP); |
119 | | |
120 | | /* Add struct to hold NCZ-specific file metadata. */ |
121 | 0 | if (!(file->format_file_info = calloc(1, sizeof(NCZ_FILE_INFO_T)))) |
122 | 0 | {stat = NC_ENOMEM; goto done;} |
123 | 0 | zinfo = file->format_file_info; |
124 | | |
125 | | /* Fill in NCZ_FILE_INFO_T */ |
126 | 0 | zinfo->created = 0; |
127 | 0 | zinfo->common.file = file; |
128 | 0 | zinfo->native_endianness = (NCZ_isLittleEndian() ? NC_ENDIAN_LITTLE : NC_ENDIAN_BIG); |
129 | 0 | if((zinfo->envv_controls = NCZ_clonestringvec(0,controls))==NULL) /*0=>envv style*/ |
130 | 0 | {stat = NC_ENOMEM; goto done;} |
131 | 0 | zinfo->default_maxstrlen = NCZ_MAXSTR_DEFAULT; |
132 | | |
133 | | /* Add struct to hold NCZ-specific group info. */ |
134 | 0 | if (!(root->format_grp_info = calloc(1, sizeof(NCZ_GRP_INFO_T)))) |
135 | 0 | {stat = NC_ENOMEM; goto done;} |
136 | 0 | ((NCZ_GRP_INFO_T*)root->format_grp_info)->common.file = file; |
137 | | |
138 | | /* Apply client controls */ |
139 | 0 | if((stat = applycontrols(zinfo))) goto done; |
140 | | |
141 | | /* initialize map handle*/ |
142 | 0 | if((stat = nczmap_open(zinfo->controls.mapimpl,nc->path,mode,zinfo->controls.flags,NULL,&zinfo->map))) |
143 | 0 | goto done; |
144 | | |
145 | | /* Ok, try to read superblock */ |
146 | 0 | if((stat = ncz_read_superblock(file,&nczarr_version,&zarr_format))) goto done; |
147 | | |
148 | 0 | if(nczarr_version == NULL) /* default */ |
149 | 0 | nczarr_version = strdup(NCZARRVERSION); |
150 | 0 | if(zarr_format == NULL) /* default */ |
151 | 0 | zarr_format = strdup(ZARRVERSION); |
152 | | /* Extract the information from it */ |
153 | 0 | if(sscanf(zarr_format,"%d",&zinfo->zarr.zarr_version)!=1) |
154 | 0 | {stat = NC_ENCZARR; goto done;} |
155 | 0 | if(sscanf(nczarr_version,"%lu.%lu.%lu", |
156 | 0 | &zinfo->zarr.nczarr_version.major, |
157 | 0 | &zinfo->zarr.nczarr_version.minor, |
158 | 0 | &zinfo->zarr.nczarr_version.release) == 0) |
159 | 0 | {stat = NC_ENCZARR; goto done;} |
160 | | |
161 | | /* Load auth info from rc file */ |
162 | 0 | if((stat = ncuriparse(nc->path,&uri))) goto done; |
163 | 0 | if(uri) { |
164 | 0 | if((stat = NC_authsetup(&zinfo->auth, uri))) |
165 | 0 | goto done; |
166 | 0 | } |
167 | | |
168 | 0 | done: |
169 | 0 | nullfree(zarr_format); |
170 | 0 | nullfree(nczarr_version); |
171 | 0 | ncurifree(uri); |
172 | 0 | nclistfreeall(modeargs); |
173 | 0 | if(json) NCJreclaim(json); |
174 | 0 | nullfree(content); |
175 | 0 | return ZUNTRACE(stat); |
176 | 0 | } |
177 | | |
178 | | /** |
179 | | * @internal Determine whether file is netCDF-4. |
180 | | * |
181 | | * For libzarr, this is always true. |
182 | | * |
183 | | * @param h5 Pointer to HDF5 file info struct. |
184 | | * |
185 | | * @returns NC_NOERR No error. |
186 | | * @author Dennis Heimbigner. |
187 | | */ |
188 | | int |
189 | | NCZ_isnetcdf4(struct NC_FILE_INFO* h5) |
190 | 0 | { |
191 | 0 | int isnc4 = 1; |
192 | 0 | NC_UNUSED(h5); |
193 | 0 | return isnc4; |
194 | 0 | } |
195 | | |
196 | | /** |
197 | | * @internal Determine version info |
198 | | * |
199 | | * For libzarr, this is not well defined |
200 | | * |
201 | | * @param majorp Pointer to major version number |
202 | | * @param minorp Pointer to minor version number |
203 | | * @param releasep Pointer to release version number |
204 | | * |
205 | | * @returns NC_NOERR No error. |
206 | | * @author Dennis Heimbigner. |
207 | | */ |
208 | | int |
209 | | NCZ_get_libversion(unsigned long* majorp, unsigned long* minorp,unsigned long* releasep) |
210 | 1 | { |
211 | 1 | unsigned long m0,m1,m2; |
212 | 1 | sscanf(NCZARRVERSION,"%lu.%lu.%lu",&m0,&m1,&m2); |
213 | 1 | if(majorp) *majorp = m0; |
214 | 1 | if(minorp) *minorp = m1; |
215 | 1 | if(releasep) *releasep = m2; |
216 | 1 | return NC_NOERR; |
217 | 1 | } |
218 | | |
219 | | /** |
220 | | * @internal Determine "superblock" number. |
221 | | * |
222 | | * For libzarr, use the value of the major part of the nczarr version. |
223 | | * |
224 | | * @param superblocp Pointer to place to return superblock. |
225 | | * use the nczarr format version major as the superblock number. |
226 | | * |
227 | | * @returns NC_NOERR No error. |
228 | | * @author Dennis Heimbigner. |
229 | | */ |
230 | | int |
231 | | NCZ_get_superblock(NC_FILE_INFO_T* file, int* superblockp) |
232 | 0 | { |
233 | 0 | NCZ_FILE_INFO_T* zinfo = file->format_file_info; |
234 | 0 | if(superblockp) *superblockp = zinfo->zarr.nczarr_version.major; |
235 | 0 | return NC_NOERR; |
236 | 0 | } |
237 | | |
238 | | /**************************************************/ |
239 | | /* Utilities */ |
240 | | |
241 | | #if 0 |
242 | | /** |
243 | | @internal Open the root group object |
244 | | @param dataset - [in] the root dataset object |
245 | | @param rootp - [out] created root group |
246 | | @return NC_NOERR |
247 | | @author Dennis Heimbigner |
248 | | */ |
249 | | static int |
250 | | ncz_open_rootgroup(NC_FILE_INFO_T* dataset) |
251 | | { |
252 | | int stat = NC_NOERR; |
253 | | int i; |
254 | | NCZ_FILE_INFO_T* zfile = NULL; |
255 | | NC_GRP_INFO_T* root = NULL; |
256 | | void* content = NULL; |
257 | | char* rootpath = NULL; |
258 | | NCjson* json = NULL; |
259 | | |
260 | | ZTRACE(3,"dataset=",dataset->hdr.name); |
261 | | |
262 | | zfile = dataset->format_file_info; |
263 | | |
264 | | /* Root should already be defined */ |
265 | | root = dataset->root_grp; |
266 | | |
267 | | assert(root != NULL); |
268 | | |
269 | | if((stat=nczm_concat(NULL,ZGROUP,&rootpath))) |
270 | | goto done; |
271 | | if((stat = NCZ_downloadjson(zfile->map, rootpath, &json))) |
272 | | goto done; |
273 | | /* Process the json */ |
274 | | for(i=0;i<nclistlength(json->contents);i+=2) { |
275 | | const NCjson* key = nclistget(json->contents,i); |
276 | | const NCjson* value = nclistget(json->contents,i+1); |
277 | | if(strcmp(NCJstring(key),"zarr_format")==0) { |
278 | | int zversion; |
279 | | if(sscanf(NCJstring(value),"%d",&zversion)!=1) |
280 | | {stat = NC_ENOTNC; goto done;} |
281 | | /* Verify against the dataset */ |
282 | | if(zversion != zfile->zarr.zarr_version) |
283 | | {stat = NC_ENOTNC; goto done;} |
284 | | } |
285 | | } |
286 | | |
287 | | done: |
288 | | if(json) NCJreclaim(json); |
289 | | nullfree(rootpath); |
290 | | nullfree(content); |
291 | | return ZUNTRACE(stat); |
292 | | } |
293 | | #endif |
294 | | |
295 | | |
296 | | static const char* |
297 | | controllookup(const char** envv_controls, const char* key) |
298 | 0 | { |
299 | 0 | const char** p; |
300 | 0 | for(p=envv_controls;*p;p+=2) { |
301 | 0 | if(strcasecmp(key,*p)==0) { |
302 | 0 | return p[1]; |
303 | 0 | } |
304 | 0 | } |
305 | 0 | return NULL; |
306 | 0 | } |
307 | | |
308 | | |
309 | | static int |
310 | | applycontrols(NCZ_FILE_INFO_T* zinfo) |
311 | 0 | { |
312 | 0 | int i,stat = NC_NOERR; |
313 | 0 | const char* value = NULL; |
314 | 0 | NClist* modelist = nclistnew(); |
315 | 0 | int noflags = 0; /* track non-default negative flags */ |
316 | |
|
317 | 0 | if((value = controllookup((const char**)zinfo->envv_controls,"mode")) != NULL) { |
318 | 0 | if((stat = NCZ_comma_parse(value,modelist))) goto done; |
319 | 0 | } |
320 | | /* Process the modelist first */ |
321 | 0 | zinfo->controls.mapimpl = NCZM_DEFAULT; |
322 | 0 | zinfo->controls.flags |= FLAG_XARRAYDIMS; /* Always support XArray convention where possible */ |
323 | 0 | for(i=0;i<nclistlength(modelist);i++) { |
324 | 0 | const char* p = nclistget(modelist,i); |
325 | 0 | if(strcasecmp(p,PUREZARRCONTROL)==0) |
326 | 0 | zinfo->controls.flags |= (FLAG_PUREZARR); |
327 | 0 | else if(strcasecmp(p,XARRAYCONTROL)==0) |
328 | 0 | zinfo->controls.flags |= FLAG_PUREZARR; |
329 | 0 | else if(strcasecmp(p,NOXARRAYCONTROL)==0) |
330 | 0 | noflags |= FLAG_XARRAYDIMS; |
331 | 0 | else if(strcasecmp(p,"zip")==0) zinfo->controls.mapimpl = NCZM_ZIP; |
332 | 0 | else if(strcasecmp(p,"file")==0) zinfo->controls.mapimpl = NCZM_FILE; |
333 | 0 | else if(strcasecmp(p,"s3")==0) zinfo->controls.mapimpl = NCZM_S3; |
334 | 0 | } |
335 | | /* Apply negative controls by turning off negative flags */ |
336 | | /* This is necessary to avoid order dependence of mode flags when both positive and negative flags are defined */ |
337 | 0 | zinfo->controls.flags &= (~noflags); |
338 | | |
339 | | /* Process other controls */ |
340 | 0 | if((value = controllookup((const char**)zinfo->envv_controls,"log")) != NULL) { |
341 | 0 | zinfo->controls.flags |= FLAG_LOGGING; |
342 | 0 | ncsetlogging(1); |
343 | 0 | } |
344 | 0 | if((value = controllookup((const char**)zinfo->envv_controls,"show")) != NULL) { |
345 | 0 | if(strcasecmp(value,"fetch")==0) |
346 | 0 | zinfo->controls.flags |= FLAG_SHOWFETCH; |
347 | 0 | } |
348 | 0 | done: |
349 | 0 | nclistfreeall(modelist); |
350 | 0 | return stat; |
351 | 0 | } |
352 | | |
353 | | #if 0 |
354 | | /** |
355 | | @internal Rewrite attributes into a group or var |
356 | | @param map - [in] the map object for storage |
357 | | @param container - [in] the containing object |
358 | | @param jattrs - [in] the json for .zattrs |
359 | | @param jtypes - [in] the json for .ztypes |
360 | | @return NC_NOERR |
361 | | @author Dennis Heimbigner |
362 | | */ |
363 | | int |
364 | | ncz_unload_jatts(NCZ_FILE_INFO_T* zinfo, NC_OBJ* container, NCjson* jattrs, NCjson* jtypes) |
365 | | { |
366 | | int stat = NC_NOERR; |
367 | | char* fullpath = NULL; |
368 | | char* akey = NULL; |
369 | | char* tkey = NULL; |
370 | | NCZMAP* map = zinfo->map; |
371 | | |
372 | | assert((NCJsort(jattrs) == NCJ_DICT)); |
373 | | assert((NCJsort(jtypes) == NCJ_DICT)); |
374 | | |
375 | | if(container->sort == NCGRP) { |
376 | | NC_GRP_INFO_T* grp = (NC_GRP_INFO_T*)container; |
377 | | /* Get grp's fullpath name */ |
378 | | if((stat = NCZ_grpkey(grp,&fullpath))) |
379 | | goto done; |
380 | | } else { |
381 | | NC_VAR_INFO_T* var = (NC_VAR_INFO_T*)container; |
382 | | /* Get var's fullpath name */ |
383 | | if((stat = NCZ_varkey(var,&fullpath))) |
384 | | goto done; |
385 | | } |
386 | | |
387 | | /* Construct the path to the .zattrs object */ |
388 | | if((stat = nczm_concat(fullpath,ZATTRS,&akey))) |
389 | | goto done; |
390 | | |
391 | | /* Always write as V2 */ |
392 | | |
393 | | { |
394 | | NCjson* k = NULL; |
395 | | NCjson* v = NULL; |
396 | | /* remove any previous version */ |
397 | | if(!NCJremove(jattrs,NCZ_V2_ATTRS,1,&k,&v)) { |
398 | | NCJreclaim(k); NCJreclaim(v); |
399 | | } |
400 | | } |
401 | | |
402 | | if(!(zinfo->controls.flags & FLAG_PUREZARR)) { |
403 | | /* Insert the jtypes into the set of attributes */ |
404 | | if((stat = NCJinsert(jattrs,NCZ_V2_ATTRS,jtypes))) goto done; |
405 | | } |
406 | | |
407 | | /* Upload the .zattrs object */ |
408 | | if((stat=NCZ_uploadjson(map,tkey,jattrs))) |
409 | | goto done; |
410 | | |
411 | | done: |
412 | | if(stat) { |
413 | | NCJreclaim(jattrs); |
414 | | NCJreclaim(jtypes); |
415 | | } |
416 | | nullfree(fullpath); |
417 | | nullfree(akey); |
418 | | nullfree(tkey); |
419 | | return stat; |
420 | | } |
421 | | #endif |
422 | | |
423 | | |
424 | | |