NetCDF 4.9.3
Loading...
Searching...
No Matches
nc4info.c
Go to the documentation of this file.
1
9
10#include "config.h"
11#include "nc4internal.h"
12#include "hdf5internal.h"
13#include "nc_provenance.h"
14#include "nclist.h"
15#include "ncbytes.h"
16
17/* Provide a hack to suppress the writing of _NCProperties attribute.
18 This is for creating a file without _NCProperties for testing purposes.
19*/
20#undef SUPPRESSNCPROPS
21
22/* Various Constants */
23#define NCPROPS_MAX_NAME 1024 /* max key name size */
24#define NCPROPS_MAX_VALUE 1024 /* max value size */
25#define HDF5_MAX_NAME 1024
26
27#define ESCAPECHARS "\\=|,"
28
30#define NCHECK(expr) {if((expr)!=NC_NOERR) {goto done;}}
31
33#define HCHECK(expr) {if((expr)<0) {ncstat = NC_EHDFERR; goto done;}}
34
35static int NC4_read_ncproperties(NC_FILE_INFO_T* h5, char** propstring);
36static int NC4_write_ncproperties(NC_FILE_INFO_T* h5);
37
38static int globalpropinitialized = 0;
39static NC4_Provenance globalprovenance;
40
50int
51NC4_provenance_init(void)
52{
53 int stat = NC_NOERR;
54 char* name = NULL;
55 char* value = NULL;
56 unsigned major,minor,release;
57 NCbytes* buffer = NULL; /* for constructing the global _NCProperties */
58 char printbuf[1024];
59
60 if(globalpropinitialized)
61 return stat;
62
63 /* Build _NCProperties info */
64
65 /* Initialize globalpropinfo */
66 memset((void*)&globalprovenance,0,sizeof(NC4_Provenance));
67 globalprovenance.version = NCPROPS_VERSION;
68
69 buffer = ncbytesnew();
70
71 /* Insert version as first entry */
72 ncbytescat(buffer,NCPVERSION);
73 ncbytescat(buffer,"=");
74
75 snprintf(printbuf,sizeof(printbuf),"%d",globalprovenance.version);
76 ncbytescat(buffer,printbuf);
77
78 /* Insert the netcdf version */
79 ncbytesappend(buffer,NCPROPSSEP2);
80 ncbytescat(buffer,NCPNCLIB2);
81 ncbytescat(buffer,"=");
82 ncbytescat(buffer,PACKAGE_VERSION);
83
84 /* Insert the HDF5 as underlying storage format library */
85 ncbytesappend(buffer,NCPROPSSEP2);
86 ncbytescat(buffer,NCPHDF5LIB2);
87 ncbytescat(buffer,"=");
88 if((stat = NC4_hdf5get_libversion(&major,&minor,&release))) goto done;
89 snprintf(printbuf,sizeof(printbuf),"%1u.%1u.%1u",major,minor,release);
90 ncbytescat(buffer,printbuf);
91
92#ifdef NCPROPERTIES_EXTRA
93 if(NCPROPERTIES_EXTRA != NULL && strlen(NCPROPERTIES_EXTRA) > 0)
94 { const char* p;
95 /* Add any extra fields */
96 p = NCPROPERTIES_EXTRA;
97 if(p[0] == NCPROPSSEP2) p++; /* If leading separator */
98 ncbytesappend(buffer,NCPROPSSEP2);
99 ncbytescat(buffer,p);
100 }
101#endif
102 ncbytesnull(buffer);
103 globalprovenance.ncproperties = ncbytesextract(buffer);
104
105done:
106 ncbytesfree(buffer);
107 if(name != NULL) free(name);
108 if(value != NULL) free(value);
109 if(stat == NC_NOERR)
110 globalpropinitialized = 1; /* avoid repeating it */
111 return stat;
112}
113
120int
121NC4_provenance_finalize(void)
122{
123 return NC4_clear_provenance(&globalprovenance);
124}
125
139int
140NC4_new_provenance(NC_FILE_INFO_T* file)
141{
142 int ncstat = NC_NOERR;
143 NC4_Provenance* provenance = NULL;
144 int superblock = -1;
145
146 LOG((5, "%s: ncid 0x%x", __func__, file->root_grp->hdr.id));
147
148 assert(file->provenance.ncproperties == NULL); /* not yet defined */
149
150 provenance = &file->provenance;
151 memset(provenance,0,sizeof(NC4_Provenance)); /* make sure */
152
153 /* Set the version */
154 provenance->version = globalprovenance.version;
155
156 /* Set the superblock number */
157 if((ncstat = NC4_hdf5get_superblock(file,&superblock))) goto done;
158 provenance->superblockversion = superblock;
159
160 if(globalprovenance.ncproperties != NULL) {
161 if((provenance->ncproperties = strdup(globalprovenance.ncproperties)) == NULL)
162 {ncstat = NC_ENOMEM; goto done;}
163 }
164
165done:
166 if(ncstat) {
167 LOG((0,"Could not create _NCProperties attribute"));
168 }
169 return NC_NOERR;
170}
171
183int
184NC4_read_provenance(NC_FILE_INFO_T* file)
185{
186 int ncstat = NC_NOERR;
187 NC4_Provenance* provenance = NULL;
188 int superblock = -1;
189 char* propstring = NULL;
190
191 LOG((5, "%s: ncid 0x%x", __func__, file->root_grp->hdr.id));
192
193 assert(file->provenance.version == 0); /* not yet defined */
194
195 provenance = &file->provenance;
196 memset(provenance,0,sizeof(NC4_Provenance)); /* make sure */
197
198 /* Set the superblock number */
199 if((ncstat = NC4_hdf5get_superblock(file,&superblock))) goto done;
200 provenance->superblockversion = superblock;
201
202 /* Read the _NCProperties value from the file */
203 /* We do not return a size and assume the size is that upto the
204 first nul character */
205 if((ncstat = NC4_read_ncproperties(file,&propstring))) goto done;
206 provenance->ncproperties = propstring;
207 propstring = NULL;
208
209done:
210 nullfree(propstring);
211 if(ncstat) {
212 LOG((0,"Could not create _NCProperties attribute"));
213 }
214 return NC_NOERR;
215}
216
228int
229NC4_write_provenance(NC_FILE_INFO_T* file)
230{
231 int ncstat = NC_NOERR;
232 if((ncstat = NC4_write_ncproperties(file)))
233 goto done;
234done:
235 return ncstat;
236}
237
238/* HDF5 Specific attribute read/write of _NCProperties */
239static int
240NC4_read_ncproperties(NC_FILE_INFO_T* h5, char** propstring)
241{
242 int retval = NC_NOERR;
243 hid_t hdf5grpid = -1;
244 hid_t attid = -1;
245 hid_t aspace = -1;
246 hid_t atype = -1;
247 hid_t ntype = -1;
248 char* text = NULL;
249 H5T_class_t t_class;
250 hsize_t size;
251
252 LOG((5, "%s", __func__));
253
254 hdf5grpid = ((NC_HDF5_GRP_INFO_T *)(h5->root_grp->format_grp_info))->hdf_grpid;
255
256 if(H5Aexists(hdf5grpid,NCPROPS) <= 0) { /* Does not exist */
257 /* File did not contain a _NCProperties attribute; leave empty */
258 goto done;
259 }
260
261 /* NCPROPS Attribute exists, make sure it is legitimate */
262 attid = H5Aopen_by_name(hdf5grpid, ".", NCPROPS, H5P_DEFAULT, H5P_DEFAULT);
263 assert(attid > 0);
264 aspace = H5Aget_space(attid);
265 atype = H5Aget_type(attid);
266 /* Verify atype and size */
267 t_class = H5Tget_class(atype);
268 if(t_class != H5T_STRING)
269 {retval = NC_EINVAL; goto done;}
270 size = H5Tget_size(atype);
271 if(size == 0)
272 {retval = NC_EINVAL; goto done;}
273 text = (char*)malloc(1+(size_t)size);
274 if(text == NULL)
275 {retval = NC_ENOMEM; goto done;}
276 if((ntype = H5Tget_native_type(atype, H5T_DIR_DEFAULT)) < 0)
277 {retval = NC_EHDFERR; goto done;}
278 if((H5Aread(attid, ntype, text)) < 0)
279 {retval = NC_EHDFERR; goto done;}
280 /* Make sure its null terminated */
281 text[(size_t)size] = '\0';
282 if(propstring) {*propstring = text; text = NULL;}
283
284done:
285 if(text != NULL) free(text);
286 /* Close out the HDF5 objects */
287 if(attid > 0 && H5Aclose(attid) < 0) retval = NC_EHDFERR;
288 if(aspace > 0 && H5Sclose(aspace) < 0) retval = NC_EHDFERR;
289 if(atype > 0 && H5Tclose(atype) < 0) retval = NC_EHDFERR;
290 if(ntype > 0 && H5Tclose(ntype) < 0) retval = NC_EHDFERR;
291
292 /* For certain errors, actually fail, else log that attribute was invalid and ignore */
293 if(retval != NC_NOERR) {
294 if(retval != NC_ENOMEM && retval != NC_EHDFERR) {
295 LOG((0,"Invalid _NCProperties attribute: ignored"));
296 retval = NC_NOERR;
297 }
298 }
299 return retval;
300}
301
302static int
303NC4_write_ncproperties(NC_FILE_INFO_T* h5)
304{
305#ifdef SUPPRESSNCPROPERTY
306 return NC_NOERR;
307#else
308 int retval = NC_NOERR;
309 hid_t hdf5grpid = -1;
310 hid_t attid = -1;
311 hid_t aspace = -1;
312 hid_t atype = -1;
313 size_t len = 0;
314 NC4_Provenance* prov = &h5->provenance;
315
316 LOG((5, "%s", __func__));
317
318 /* If the file is read-only, return an error. */
319 if (h5->no_write)
320 {retval = NC_EPERM; goto done;}
321
322 hdf5grpid = ((NC_HDF5_GRP_INFO_T *)(h5->root_grp->format_grp_info))->hdf_grpid;
323
324 if(H5Aexists(hdf5grpid,NCPROPS) > 0) /* Already exists, no overwrite */
325 goto done;
326
327 /* Build the property if we have legit value */
328 if(prov->ncproperties != NULL) {
329 /* Build the HDF5 string type */
330 if ((atype = H5Tcopy(H5T_C_S1)) < 0)
331 {retval = NC_EHDFERR; goto done;}
332 if (H5Tset_strpad(atype, H5T_STR_NULLTERM) < 0)
333 {retval = NC_EHDFERR; goto done;}
334 if(H5Tset_cset(atype, H5T_CSET_ASCII) < 0)
335 {retval = NC_EHDFERR; goto done;}
336 len = strlen(prov->ncproperties);
337 if(H5Tset_size(atype, len) < 0)
338 {retval = NC_EFILEMETA; goto done;}
339 /* Create NCPROPS attribute */
340 if((aspace = H5Screate(H5S_SCALAR)) < 0)
341 {retval = NC_EFILEMETA; goto done;}
342 if ((attid = H5Acreate1(hdf5grpid, NCPROPS, atype, aspace, H5P_DEFAULT)) < 0)
343 {retval = NC_EFILEMETA; goto done;}
344 if (H5Awrite(attid, atype, prov->ncproperties) < 0)
345 {retval = NC_EFILEMETA; goto done;}
346/* Verify */
347#if 0
348 {
349 hid_t spacev, typev;
350 hsize_t dsize, tsize;
351 typev = H5Aget_type(attid);
352 spacev = H5Aget_space(attid);
353 dsize = H5Aget_storage_size(attid);
354 tsize = H5Tget_size(typev);
355 fprintf(stderr,"dsize=%lu tsize=%lu\n",(unsigned long)dsize,(unsigned long)tsize);
356 }
357#endif
358 }
359
360done:
361 /* Close out the HDF5 objects */
362 if(attid > 0 && H5Aclose(attid) < 0) retval = NC_EHDFERR;
363 if(aspace > 0 && H5Sclose(aspace) < 0) retval = NC_EHDFERR;
364 if(atype > 0 && H5Tclose(atype) < 0) retval = NC_EHDFERR;
365
366 /* For certain errors, actually fail, else log that attribute was invalid and ignore */
367 switch (retval) {
368 case NC_ENOMEM:
369 case NC_EHDFERR:
370 case NC_EPERM:
371 case NC_EFILEMETA:
372 case NC_NOERR:
373 break;
374 default:
375 LOG((0,"Invalid _NCProperties attribute"));
376 retval = NC_NOERR;
377 break;
378 }
379 return retval;
380#endif
381}
382
383/**************************************************/
384/* Utilities */
385
386/* Debugging */
387
388void
389ncprintprovenance(NC4_Provenance* info)
390{
391 fprintf(stderr,"[%p] version=%d superblockversion=%d ncproperties=|%s|\n",
392 info,
393 info->version,
394 info->superblockversion,
395 (info->ncproperties==NULL?"":info->ncproperties));
396}
397
407int
408NC4_clear_provenance(NC4_Provenance* prov)
409{
410 LOG((5, "%s", __func__));
411
412 if(prov == NULL) return NC_NOERR;
413 nullfree(prov->ncproperties);
414 memset(prov,0,sizeof(NC4_Provenance));
415 return NC_NOERR;
416}
417
418#if 0
419/* Unused functions */
420
430static int
431properties_parse(const char* text0, NClist* pairs)
432{
433 int ret = NC_NOERR;
434 char* p;
435 char* q;
436 char* text = NULL;
437
438 if(text0 == NULL || strlen(text0) == 0)
439 goto done;
440
441 text = strdup(text0);
442 if(text == NULL) return NC_ENOMEM;
443
444 /* For back compatibility with version 1, translate '|' -> ',' */
445 for(p=text;*p;p++) {
446 if(*p == NCPROPSSEP1)
447 *p = NCPROPSSEP2;
448 }
449
450 /* Walk and fill in ncinfo */
451 p = text;
452 while(*p) {
453 char* name = p;
454 char* value = NULL;
455 char* next = NULL;
456
457 /* Delimit whole (key,value) pair */
458 q = locate(p,NCPROPSSEP2);
459 if(*q != '\0') /* Never go beyond the final nul term */
460 *q++ = '\0';
461 next = q;
462 /* split key and value */
463 q = locate(p,'=');
464 name = p;
465 *q++ = '\0';
466 value = q;
467 /* Set up p for next iteration */
468 p = next;
469 nclistpush(pairs,strdup(name));
470 nclistpush(pairs,strdup(value));
471 }
472done:
473 if(text) free(text);
474 return ret;
475}
476
477/* Locate a specific character and return its pointer
478 or EOS if not found
479 take \ escapes into account */
480static char*
481locate(char* p, char tag)
482{
483 char* next;
484 int c;
485 assert(p != NULL);
486 for(next = p;(c = *next);next++) {
487 if(c == tag)
488 return next;
489 else if(c == '\\' && next[1] != '\0')
490 next++; /* skip escaped char */
491 }
492 return next; /* not found */
493}
494
495/* Utility to transfer a string to a buffer with escaping */
496static void
497escapify(NCbytes* buffer, const char* s)
498{
499 const char* p;
500 for(p=s;*p;p++) {
501 if(strchr(ESCAPECHARS,*p) != NULL)
502 ncbytesappend(buffer,'\\');
503 ncbytesappend(buffer,*p);
504 }
505}
506
520static int
521build_propstring(int version, NClist* list, char** spropp)
522{
523 int stat = NC_NOERR;
524 int i;
525 NCbytes* buffer = NULL;
526 char sversion[64];
527
528 LOG((5, "%s version=%d", __func__, version));
529
530 if(spropp != NULL) *spropp = NULL;
531
532 if(version == 0 || version > NCPROPS_VERSION) /* unknown case */
533 goto done;
534 if(list == NULL)
535 {stat = NC_EINVAL; goto done;}
536
537 if((buffer = ncbytesnew()) == NULL)
538 {stat = NC_ENOMEM; goto done;}
539
540 /* start with version */
541 ncbytescat(buffer,NCPVERSION);
542 ncbytesappend(buffer,'=');
543 /* Use current version */
544 snprintf(sversion,sizeof(sversion),"%d",NCPROPS_VERSION);
545 ncbytescat(buffer,sversion);
546
547 for(i=0;i<nclistlength(list);i+=2) {
548 char* value, *name;
549 name = nclistget(list,i);
550 if(name == NULL) continue;
551 value = nclistget(list,i+1);
552 ncbytesappend(buffer,NCPROPSSEP2); /* terminate last entry */
553 escapify(buffer,name);
554 ncbytesappend(buffer,'=');
555 escapify(buffer,value);
556 }
557 /* Force null termination */
558 ncbytesnull(buffer);
559 if(spropp) *spropp = ncbytesextract(buffer);
560
561done:
562 if(buffer != NULL) ncbytesfree(buffer);
563 return stat;
564}
565
566static int
567properties_getversion(const char* propstring, int* versionp)
568{
569 int ncstat = NC_NOERR;
570 int version = 0;
571 /* propstring should begin with "version=dddd" */
572 if(propstring == NULL || strlen(propstring) < strlen("version=") + strlen("1"))
573 {ncstat = NC_EINVAL; goto done;} /* illegal version */
574 if(memcmp(propstring,"version=",strlen("version=")) != 0)
575 {ncstat = NC_EINVAL; goto done;} /* illegal version */
576 propstring += strlen("version=");
577 /* get version */
578 version = atoi(propstring);
579 if(version < 0)
580 {ncstat = NC_EINVAL; goto done;} /* illegal version */
581 if(versionp) *versionp = version;
582done:
583 return ncstat;
584}
585
598static int
599parse_provenance(NC4_Provenance* prov)
600{
601 int ncstat = NC_NOERR;
602 char *name = NULL;
603 char *value = NULL;
604 int version = 0;
605 NClist* list = NULL;
606
607 LOG((5, "%s: prov 0x%x", __func__, prov));
608
609 if(prov->ncproperty == NULL || strlen(prov->ncproperty) < strlen("version="))
610 {ncstat = NC_EINVAL; goto done;}
611 if((list = nclistnew()) == NULL)
612 {ncstat = NC_ENOMEM; goto done;}
613
614 /* Do we understand the version? */
615 if(prov->version > 0 && prov->version <= NCPROPS_VERSION) {/* recognized version */
616 if((ncstat=properties_parse(prov->ncproperty,list)))
617 goto done;
618 /* Remove version pair from properties list*/
619 if(nclistlength(list) < 2)
620 {ncstat = NC_EINVAL; goto done;} /* bad _NCProperties attribute */
621 /* Throw away the purported version=... */
622 nclistremove(list,0); /* version key */
623 nclistremove(list,0); /* version value */
624
625 /* Now, rebuild to the latest version */
626 switch (version) {
627 default: break; /* do nothing */
628 case 1: {
629 int i;
630 for(i=0;i<nclistlength(list);i+=2) {
631 char* newname = NULL;
632 name = nclistget(list,i);
633 if(name == NULL) continue; /* ignore */
634 if(strcmp(name,NCPNCLIB1) == 0)
635 newname = NCPNCLIB2; /* change name */
636 else if(strcmp(name,NCPHDF5LIB1) == 0)
637 newname = NCPHDF5LIB2;
638 else continue; /* ignore */
639 /* Do any rename */
640 nclistset(list,i,strdup(newname));
641 if(name) {free(name); name = NULL;}
642 }
643 } break;
644 } /*switch*/
645 }
646 prov->properties = list;
647 list = NULL;
648
649done:
650 nclistfreeall(list);
651 if(name != NULL) free(name);
652 if(value != NULL) free(value);
653 return ncstat;
654}
655
665static int
666NC4_free_provenance(NC4_Provenance* prov)
667{
668 LOG((5, "%s", __func__));
669
670 if(prov == NULL) return NC_NOERR;
671 NC4_clear_provenance(prov);
672 free(prov);
673 return NC_NOERR;
674}
675
676/* Utility to copy contents of the dfalt into an NCPROPINFO object */
677static int
678propinfo_default(NC4_Properties* dst, const NC4_Properties* dfalt)
679{
680 int i;
681 if(dst->properties == NULL) {
682 dst->properties = nclistnew();
683 if(dst->properties == NULL) return NC_ENOMEM;
684 }
685 dst->version = dfalt->version;
686 for(i=0;i<nclistlength(dfalt->properties);i++) {
687 char* s = nclistget(dfalt->properties,i);
688 s = strdup(s);
689 if(s == NULL) return NC_ENOMEM;
690 nclistpush(dst->properties,s);
691 }
692 return NC_NOERR;
693}
694
695#endif /*0*/
static int NC4_write_ncproperties(NC_FILE_INFO_T *h5)
Definition nc4info.c:303
#define NC_EPERM
Write to read only.
Definition netcdf.h:389
#define NC_ENOMEM
Memory allocation (malloc) failure.
Definition netcdf.h:458
#define NC_EHDFERR
Error at HDF5 layer.
Definition netcdf.h:491
#define NC_EFILEMETA
Problem with file metadata.
Definition netcdf.h:495
#define NC_EINVAL
Invalid Argument.
Definition netcdf.h:388
#define NC_NOERR
No Error.
Definition netcdf.h:378