NetCDF  4.6.2
nc4info.c
Go to the documentation of this file.
1 
10 #include "config.h"
11 #include "nc4internal.h"
12 #include "hdf5internal.h"
13 #include "nclist.h"
14 #include "ncbytes.h"
15 
16 /* Various Constants */
17 #define NCPROPS_MAX_NAME 1024 /* max key name size */
18 #define NCPROPS_MAX_VALUE 1024 /* max value size */
19 #define HDF5_MAX_NAME 1024
21 #define ESCAPECHARS "\\=|,"
22 
24 #define NCHECK(expr) {if((expr)!=NC_NOERR) {goto done;}}
25 
27 #define HCHECK(expr) {if((expr)<0) {ncstat = NC_EHDFERR; goto done;}}
28 
29 static int globalpropinitialized = 0;
30 struct NCPROPINFO globalpropinfo;
32 /* Forward */
33 static int properties_parse(const char* text0, NClist* pairs);
34 
44 int
45 NC4_provenance_init(void)
46 {
47  int stat = NC_NOERR;
48  int i;
49  NClist* other = NULL;
50  char* name = NULL;
51  char* value = NULL;
52  unsigned major,minor,release;
53 
54  if(globalpropinitialized)
55  return stat;
56 
57  /* Build _NCProperties info */
58 
59  /* Initialize globalpropinfo */
60  memset((void*)&globalpropinfo,0,sizeof(globalpropinfo));
61  globalpropinfo.version = NCPROPS_VERSION;
62  globalpropinfo.properties = nclistnew();
63  if(globalpropinfo.properties == NULL)
64  {stat = NC_ENOMEM; goto done;}
65 
66  /* Insert primary library version as first entry */
67  if((name = strdup(NCPNCLIB2)) == NULL)
68  {stat = NC_ENOMEM; goto done;}
69  nclistpush(globalpropinfo.properties,name);
70  name = NULL; /* Avoid multiple free() */
71 
72  if((value = strdup(PACKAGE_VERSION)) == NULL)
73  {stat = NC_ENOMEM; goto done;}
74  nclistpush(globalpropinfo.properties,value);
75  value = NULL;
76 
77  /* Insert the HDF5 as underlying storage format library */
78  if((name = strdup(NCPHDF5LIB2)) == NULL)
79  {stat = NC_ENOMEM; goto done;}
80  nclistpush(globalpropinfo.properties,name);
81  name = NULL;
82 
83  stat = NC4_hdf5get_libversion(&major,&minor,&release);
84  if(stat) goto done;
85  {
86  char sversion[64];
87  snprintf(sversion,sizeof(sversion),"%1u.%1u.%1u",major,minor,release);
88  if((value = strdup(sversion)) == NULL)
89  {stat = NC_ENOMEM; goto done;}
90  }
91  nclistpush(globalpropinfo.properties,value);
92  value = NULL;
93 
94  /* Add any extra fields */
95  /*Parse them into an NClist */
96  other = nclistnew();
97  if(other == NULL) {stat = NC_ENOMEM; goto done;}
98 #ifdef NCPROPERTIES
99  stat = properties_parse(NCPROPERTIES_EXTRA,other);
100  if(stat) goto done;
101 #endif
102  /* merge into the properties list */
103  for(i=0;i<nclistlength(other);i++)
104  nclistpush(globalpropinfo.properties,strdup(nclistget(other,i)));
105  nclistfreeall(other);
106  other = NULL;
107 
108 done:
109  if(name != NULL) free(name);
110  if(value != NULL) free(value);
111  if(other != NULL)
112  nclistfreeall(other);
113  if(stat && globalpropinfo.properties != NULL) {
114  nclistfreeall(globalpropinfo.properties);
115  globalpropinfo.properties = NULL;
116  }
117  if(stat == NC_NOERR)
118  globalpropinitialized = 1; /* avoid repeating it */
119  return stat;
120 }
121 
122 /* Locate a specific character and return its pointer
123  or EOS if not found
124  take \ escapes into account */
125 static char*
126 locate(char* p, char tag)
127 {
128  char* next;
129  int c;
130  assert(p != NULL);
131  for(next = p;(c = *next);next++) {
132  if(c == tag)
133  return next;
134  else if(c == '\\' && next[1] != '\0')
135  next++; /* skip escaped char */
136  }
137  return next; /* not found */
138 }
139 
146 int
147 NC4_provenance_finalize(void)
148 {
149  nclistfreeall(globalpropinfo.properties);
150  return NC_NOERR;
151 }
152 
162 static int
163 properties_parse(const char* text0, NClist* pairs)
164 {
165  int ret = NC_NOERR;
166  char* p;
167  char* q;
168  char* text = NULL;
169 
170  if(text0 == NULL || strlen(text0) == 0)
171  goto done;
172 
173  text = strdup(text0);
174  if(text == NULL) return NC_ENOMEM;
175 
176  /* For back compatibility with version 1, translate '|' -> ',' */
177  for(p=text;*p;p++) {
178  if(*p == NCPROPSSEP1)
179  *p = NCPROPSSEP2;
180  }
181 
182  /* Walk and fill in ncinfo */
183  p = text;
184  while(*p) {
185  char* name = p;
186  char* value = NULL;
187  char* next = NULL;
188 
189  /* Delimit whole (key,value) pair */
190  q = locate(p,NCPROPSSEP2);
191  if(*q != '\0') /* Never go beyond the final nul term */
192  *q++ = '\0';
193  next = q;
194  /* split key and value */
195  q = locate(p,'=');
196  name = p;
197  *q++ = '\0';
198  value = q;
199  /* Set up p for next iteration */
200  p = next;
201  nclistpush(pairs,strdup(name));
202  nclistpush(pairs,strdup(value));
203  }
204 done:
205  if(text) free(text);
206  return ret;
207 }
208 
209 
210 /* Utility to transfer a string to a buffer with escaping */
211 static void
212 escapify(NCbytes* buffer, const char* s)
213 {
214  const char* p;
215  for(p=s;*p;p++) {
216  if(strchr(ESCAPECHARS,*p) != NULL)
217  ncbytesappend(buffer,'\\');
218  ncbytesappend(buffer,*p);
219  }
220 }
221 
222 /* Utility to copy contents of the dfalt into an NCPROPINFO object */
223 static int
224 propinfo_default(struct NCPROPINFO* dst, const struct NCPROPINFO* dfalt)
225 {
226  int i;
227  if(dst->properties == NULL) {
228  dst->properties = nclistnew();
229  if(dst->properties == NULL) return NC_ENOMEM;
230  }
231  dst->version = dfalt->version;
232  for(i=0;i<nclistlength(dfalt->properties);i++) {
233  char* s = nclistget(dfalt->properties,i);
234  s = strdup(s);
235  if(s == NULL) return NC_ENOMEM;
236  nclistpush(dst->properties,s);
237  }
238  return NC_NOERR;
239 }
240 
253 int
254 NC4_buildpropinfo(struct NCPROPINFO* info, char** propdatap)
255 {
256  int stat = NC_NOERR;
257  int i;
258  NCbytes* buffer = NULL;
259  char sversion[64];
260 
261  if(info == NULL || info->version == 0 || propdatap == NULL)
262  {stat = NC_EINVAL; goto done;}
263 
264  *propdatap = NULL;
265 
266  buffer = ncbytesnew();
267  if(!buffer) {stat = NC_ENOMEM; goto done;}
268 
269  /* start with version */
270  ncbytescat(buffer,NCPVERSION);
271  ncbytesappend(buffer,'=');
272  snprintf(sversion,sizeof(sversion),"%d",info->version);
273  ncbytescat(buffer,sversion);
274 
275  for(i=0;i<nclistlength(info->properties);i+=2) {
276  char* value, *name;
277  name = nclistget(info->properties,i);
278  if(name == NULL) continue;
279  value = nclistget(info->properties,i+1);
280  ncbytesappend(buffer,NCPROPSSEP2); /* terminate last entry */
281  escapify(buffer,name);
282  ncbytesappend(buffer,'=');
283  escapify(buffer,value);
284  }
285  /* Force null termination */
286  ncbytesnull(buffer);
287  *propdatap = ncbytesextract(buffer);
288 
289 done:
290  if(buffer != NULL) ncbytesfree(buffer);
291  return stat;
292 }
293 
294 #if 0
295 
303 int
304 NC4_put_ncproperties(NC_FILE_INFO_T* file)
305 {
306  int ncstat = NC_NOERR;
307  char* text = NULL;
308 
309  /* Get root group */
310  grp = ((NC_HDF5_GRP_INFO_T *)(h5->root_grp->format_grp_info))->hdf_grpid;
311  /* See if the NCPROPS attribute exists */
312  if(H5Aexists(grp,NCPROPS) <= 0) { /* Does not exist */
313  ncstat = NC4_buildpropinfo(&h5->fileinfo->propattr,&text);
314  if(text == NULL || ncstat != NC_NOERR) {
315  goto done;
316  }
317  /* Create a datatype to refer to. */
318  HCHECK((atype = H5Tcopy(H5T_C_S1)));
319  HCHECK((H5Tset_cset(atype, H5T_CSET_ASCII)));
320  HCHECK((H5Tset_size(atype, strlen(text)+1))); /*keep nul term */
321  HCHECK((aspace = H5Screate(H5S_SCALAR)));
322  HCHECK((attid = H5Acreate(grp, NCPROPS, atype, aspace, H5P_DEFAULT)));
323  HCHECK((H5Awrite(attid, atype, text)));
324  }
325  done:
326  if(text != NULL) {
327  free(text);
328  text = NULL;
329  }
330 
331  if(attid >= 0) HCHECK((H5Aclose(attid)));
332  if(aspace >= 0) HCHECK((H5Sclose(aspace)));
333  if(atype >= 0) HCHECK((H5Tclose(atype)));
334  return ncstat;
335 }
336 #endif
337 
353 int
354 NC4_set_provenance(NC_FILE_INFO_T* file, const struct NCPROPINFO* dfalt)
355 {
356  int ncstat = NC_NOERR;
357  struct NCPROVENANCE* provenance = NULL;
358  int superblock = -1;
359 
360  assert(file->provenance == NULL);
361  provenance = calloc(1,sizeof(struct NCPROVENANCE));
362  if(provenance == NULL) {ncstat = NC_ENOMEM; goto done;}
363 
364  /* Initialize from the default */
365  provenance->propattr.version = globalpropinfo.version;
366  /* Get the superblock number */
367  if((ncstat = NC4_hdf5get_superblock(file,&superblock)))
368  goto done;
369  provenance->superblockversion = superblock;
370 
371  /* Capture properties */
372  provenance->propattr.properties = nclistnew();
373  if(provenance->propattr.properties == NULL)
374  {ncstat = NC_ENOMEM; goto done;}
375  /* add in the dfalt values */
376  if(dfalt != NULL) {
377  int i;
378  for(i=0;i<nclistlength(dfalt->properties);i++) {
379  char* prop = nclistget(dfalt->properties,i);
380  if(prop != NULL) {
381  prop = strdup(prop);
382  if(prop == NULL) {ncstat = NC_ENOMEM; goto done;}
383  nclistpush(provenance->propattr.properties,prop);
384  }
385  }
386  }
387 
388 done:
389  if(ncstat) {
390  LOG((0,"Could not create _NCProperties attribute"));
391  (void)NC4_free_provenance(provenance);
392  } else
393  file->provenance = provenance;
394  return NC_NOERR;
395 }
396 
413 int
414 NC4_get_provenance(NC_FILE_INFO_T* file, const char* propstring, const struct NCPROPINFO* dfalt)
415 {
416  int ncstat = NC_NOERR;
417  struct NCPROVENANCE* provenance;
418  char *name = NULL;
419  char *value = NULL;
420  int v = 0;
421  int superblock = -1;
422 
423  assert(file->provenance == NULL);
424  if((file->provenance = calloc(1,sizeof(struct NCPROVENANCE))) == NULL)
425  {ncstat = NC_ENOMEM; goto done;}
426  provenance = file->provenance;
427  if((provenance->propattr.properties = nclistnew()) == NULL)
428  {ncstat = NC_ENOMEM; goto done;}
429 
430  /* Set the superblock */
431  if((ncstat = NC4_hdf5get_superblock(file,&superblock)))
432  goto done;
433  provenance->superblockversion = superblock;
434 
435  if(propstring == NULL) {
436  /* Use dfalt */
437  if((ncstat=propinfo_default(&provenance->propattr,dfalt)))
438  goto done;
439  } else {
440  NClist* list = provenance->propattr.properties;
441  if((ncstat=properties_parse(propstring,list)))
442  goto done;
443  /* Check the version and remove from properties list*/
444  if(nclistlength(list) < 2)
445  {ncstat = NC_EINVAL; goto done;} /* bad _NCProperties attribute */
446  /* Extract the purported version=... */
447  name = nclistremove(list,0);
448  value = nclistremove(list,0);
449  if(strcmp(name,NCPVERSION) == 0) {
450  if(sscanf(value,"%d",&v) != 1)
451  {ncstat = NC_EINVAL; goto done;} /* illegal version */
452  if(v <= 0 || v > NCPROPS_VERSION)
453  {ncstat = NC_EINVAL; goto done;} /* unknown version */
454  provenance->propattr.version = v;
455  } else
456  {ncstat = NC_EINVAL; goto done;} /* bad _NCProperties attribute */
457 #if 0
458  /* Now, rebuild from version 1 to version 2 if necessary */
459  if(provenance->propattr.version == 1) {
460  int i;
461  for(i=0;i<nclistlength(list);i+=2) {
462  char* newname = NULL;
463  name = nclistget(list,i);
464  if(name == NULL) continue; /* ignore */
465  if(strcmp(name,NCPNCLIB1) == 0)
466  newname = NCPNCLIB2; /* change name */
467  else if(strcmp(name,NCPHDF5LIB1) == 0)
468  newname = NCPHDF5LIB2;
469  else continue; /* ignore */
470  /* Do any rename */
471  nclistset(list,i,strdup(newname));
472  if(name) free(name);
473  }
474  }
475 #endif
476  }
477 done:
478  if(name != NULL) free(name);
479  if(value != NULL) free(value);
480  return ncstat;
481 }
482 
492 int
493 NC4_free_provenance(struct NCPROVENANCE* prov)
494 {
495  if(prov == NULL) return NC_NOERR;
496  if(prov->propattr.properties != NULL)
497  nclistfreeall(prov->propattr.properties);
498  prov->propattr.properties = NULL;
499  free(prov);
500  return NC_NOERR;
501 }
502 
503 /* HDF5 Specific attribute read/write of _NCProperties */
504 int
505 NC4_read_ncproperties(NC_FILE_INFO_T* h5)
506 {
507  int retval = NC_NOERR;
508  hid_t hdf5grpid = -1;
509  hid_t attid = -1;
510  hid_t aspace = -1;
511  hid_t atype = -1;
512  hid_t ntype = -1;
513  char* text = NULL;
514  H5T_class_t t_class;
515  hsize_t size;
516 
517  hdf5grpid = ((NC_HDF5_GRP_INFO_T *)(h5->root_grp->format_grp_info))->hdf_grpid;
518 
519  if(H5Aexists(hdf5grpid,NCPROPS) <= 0) { /* Does not exist */
520  /* File did not contain a _NCProperties attribute */
521  retval=NC4_get_provenance(h5,NULL,&globalpropinfo);
522  goto done;
523  }
524 
525  /* NCPROPS Attribute exists, make sure it is legitimate */
526  attid = H5Aopen_name(hdf5grpid, NCPROPS);
527  assert(attid > 0);
528  aspace = H5Aget_space(attid);
529  atype = H5Aget_type(attid);
530  /* Verify atype and size */
531  t_class = H5Tget_class(atype);
532  if(t_class != H5T_STRING)
533  {retval = NC_EINVAL; goto done;}
534  size = H5Tget_size(atype);
535  if(size == 0)
536  {retval = NC_EINVAL; goto done;}
537  text = (char*)malloc(1+(size_t)size);
538  if(text == NULL)
539  {retval = NC_ENOMEM; goto done;}
540  if((ntype = H5Tget_native_type(atype, H5T_DIR_DEFAULT)) < 0)
541  {retval = NC_EHDFERR; goto done;}
542  if((H5Aread(attid, ntype, text)) < 0)
543  {retval = NC_EHDFERR; goto done;}
544  /* Make sure its null terminated */
545  text[(size_t)size] = '\0';
546  /* Process the _NCProperties value */
547  if((retval = NC4_get_provenance(h5, text, &globalpropinfo)))
548  goto done;
549 
550 done:
551  if(text != NULL) free(text);
552  /* Close out the HDF5 objects */
553  if(attid > 0 && H5Aclose(attid) < 0) retval = NC_EHDFERR;
554  if(aspace > 0 && H5Sclose(aspace) < 0) retval = NC_EHDFERR;
555  if(atype > 0 && H5Tclose(atype) < 0) retval = NC_EHDFERR;
556  if(ntype > 0 && H5Tclose(ntype) < 0) retval = NC_EHDFERR;
557 
558  /* For certain errors, actually fail, else log that attribute was invalid and ignore */
559  if(retval != NC_ENOMEM && retval != NC_EHDFERR) {
560  LOG((0,"Invalid _NCProperties attribute"));
561  retval = NC_NOERR;
562  }
563  return retval;
564 }
565 
566 int
567 NC4_write_ncproperties(NC_FILE_INFO_T* h5)
568 {
569  int retval = NC_NOERR;
570  hid_t hdf5grpid = -1;
571  hid_t attid = -1;
572  hid_t aspace = -1;
573  hid_t atype = -1;
574  char* text = NULL;
575  size_t len = 0;
576 
577  /* If the file is read-only, return an error. */
578  if (h5->no_write)
579  {retval = NC_EPERM; goto done;}
580 
581  hdf5grpid = ((NC_HDF5_GRP_INFO_T *)(h5->root_grp->format_grp_info))->hdf_grpid;
582 
583  if(H5Aexists(hdf5grpid,NCPROPS) > 0) /* Already exists, no overwrite */
584  goto done;
585 
586  /* Build the attribute string */
587  if((retval = NC4_buildpropinfo(&h5->provenance->propattr,&text)))
588  goto done;
589 
590  /* Build the HDF5 string type */
591  if ((atype = H5Tcopy(H5T_C_S1)) < 0)
592  {retval = NC_EHDFERR; goto done;}
593  if (H5Tset_strpad(atype, H5T_STR_NULLTERM) < 0)
594  {retval = NC_EHDFERR; goto done;}
595  if(H5Tset_cset(atype, H5T_CSET_ASCII) < 0)
596  {retval = NC_EHDFERR; goto done;}
597 
598  /* Create NCPROPS attribute */
599 
600  len = strlen(text);
601  if(H5Tset_size(atype, len) < 0)
602  {retval = NC_EFILEMETA; goto done;}
603  if((aspace = H5Screate(H5S_SCALAR)) < 0)
604  {retval = NC_EFILEMETA; goto done;}
605  if ((attid = H5Acreate(hdf5grpid, NCPROPS, atype, aspace, H5P_DEFAULT)) < 0)
606  {retval = NC_EFILEMETA; goto done;}
607  if (H5Awrite(attid, atype, text) < 0)
608  {retval = NC_EFILEMETA; goto done;}
609 
610 done:
611  if(text != NULL) free(text);
612  /* Close out the HDF5 objects */
613  if(attid > 0 && H5Aclose(attid) < 0) retval = NC_EHDFERR;
614  if(aspace > 0 && H5Sclose(aspace) < 0) retval = NC_EHDFERR;
615  if(atype > 0 && H5Tclose(atype) < 0) retval = NC_EHDFERR;
616 
617  /* For certain errors, actually fail, else log that attribute was invalid and ignore */
618  switch (retval) {
619  case NC_ENOMEM:
620  case NC_EHDFERR:
621  case NC_EPERM:
622  case NC_EFILEMETA:
623  case NC_NOERR:
624  break;
625  default:
626  LOG((0,"Invalid _NCProperties attribute"));
627  retval = NC_NOERR;
628  break;
629  }
630  return retval;
631 }
632 
633 /* Debugging */
634 
635 void
636 ncprintpropinfo(struct NCPROPINFO* info)
637 {
638  int i;
639  fprintf(stderr,"[%p] version=%d\n",info,info->version);
640  for(i=0;i<nclistlength(info->properties);i+=2) {
641  char* name = nclistget(info->properties,i);
642  char* value = nclistget(info->properties,i+1);
643  fprintf(stderr,"\t[%d] name=|%s| value=|%s|\n",i,name,value);
644  }
645 }
646 
647 void
648 ncprintprovenance(struct NCPROVENANCE* prov)
649 {
650  fprintf(stderr,"[%p] superblockversion=%d\n",prov,prov->superblockversion);
651  ncprintpropinfo(&prov->propattr);
652 }
653 
struct NCPROPINFO globalpropinfo
Global property info.
Definition: nc4info.c:30
#define NC_ENOMEM
Memory allocation (malloc) failure.
Definition: netcdf.h:402
#define NC_EHDFERR
Error at HDF5 layer.
Definition: netcdf.h:435
#define NC_EFILEMETA
Problem with file metadata.
Definition: netcdf.h:439
#define NC_EINVAL
Invalid Argument.
Definition: netcdf.h:332
#define NC_EPERM
Write to read only.
Definition: netcdf.h:333
#define NC_NOERR
No Error.
Definition: netcdf.h:322

Return to the Main Unidata NetCDF page.
Generated on Wed Dec 12 2018 10:27:40 for NetCDF. NetCDF is a Unidata library.