NetCDF  4.6.3
 All Data Structures Files Functions Variables Typedefs Macros Modules Pages
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  LOG((3, "%s", __func__));
262 
263  if(info == NULL || info->version == 0 || propdatap == NULL)
264  {stat = NC_EINVAL; goto done;}
265 
266  *propdatap = NULL;
267 
268  buffer = ncbytesnew();
269  if(!buffer) {stat = NC_ENOMEM; goto done;}
270 
271  /* start with version */
272  ncbytescat(buffer,NCPVERSION);
273  ncbytesappend(buffer,'=');
274  snprintf(sversion,sizeof(sversion),"%d",info->version);
275  ncbytescat(buffer,sversion);
276 
277  for(i=0;i<nclistlength(info->properties);i+=2) {
278  char* value, *name;
279  name = nclistget(info->properties,i);
280  if(name == NULL) continue;
281  value = nclistget(info->properties,i+1);
282  ncbytesappend(buffer,NCPROPSSEP2); /* terminate last entry */
283  escapify(buffer,name);
284  ncbytesappend(buffer,'=');
285  escapify(buffer,value);
286  }
287  /* Force null termination */
288  ncbytesnull(buffer);
289  *propdatap = ncbytesextract(buffer);
290 
291 done:
292  if(buffer != NULL) ncbytesfree(buffer);
293  return stat;
294 }
295 
311 int
312 NC4_set_provenance(NC_FILE_INFO_T* file, const struct NCPROPINFO* dfalt)
313 {
314  int ncstat = NC_NOERR;
315  struct NCPROVENANCE* provenance = NULL;
316  int superblock = -1;
317 
318  LOG((3, "%s: ncid 0x%x", __func__, file->root_grp->hdr.id));
319 
320  assert(file->provenance == NULL);
321 
322  provenance = calloc(1,sizeof(struct NCPROVENANCE));
323  if(provenance == NULL) {ncstat = NC_ENOMEM; goto done;}
324 
325  /* Initialize from the default */
326  provenance->propattr.version = globalpropinfo.version;
327  /* Get the superblock number */
328  if((ncstat = NC4_hdf5get_superblock(file,&superblock)))
329  goto done;
330  provenance->superblockversion = superblock;
331 
332  /* Capture properties */
333  provenance->propattr.properties = nclistnew();
334  if(provenance->propattr.properties == NULL)
335  {ncstat = NC_ENOMEM; goto done;}
336  /* add in the dfalt values */
337  if(dfalt != NULL) {
338  int i;
339  for(i=0;i<nclistlength(dfalt->properties);i++) {
340  char* prop = nclistget(dfalt->properties,i);
341  if(prop != NULL) {
342  prop = strdup(prop);
343  if(prop == NULL) {ncstat = NC_ENOMEM; goto done;}
344  nclistpush(provenance->propattr.properties,prop);
345  }
346  }
347  }
348 
349 done:
350  if(ncstat) {
351  LOG((0,"Could not create _NCProperties attribute"));
352  (void)NC4_free_provenance(provenance);
353  } else
354  file->provenance = provenance;
355  return NC_NOERR;
356 }
357 
374 int
375 NC4_get_provenance(NC_FILE_INFO_T* file, const char* propstring, const struct NCPROPINFO* dfalt)
376 {
377  int ncstat = NC_NOERR;
378  struct NCPROVENANCE* provenance;
379  char *name = NULL;
380  char *value = NULL;
381  int v = 0;
382  int superblock = -1;
383 
384  LOG((3, "%s: ncid 0x%x propstring %s", __func__, file->root_grp->hdr.id, propstring));
385 
386  assert(file->provenance == NULL);
387  if((file->provenance = calloc(1,sizeof(struct NCPROVENANCE))) == NULL)
388  {ncstat = NC_ENOMEM; goto done;}
389  provenance = file->provenance;
390  if((provenance->propattr.properties = nclistnew()) == NULL)
391  {ncstat = NC_ENOMEM; goto done;}
392 
393  /* Set the superblock */
394  if((ncstat = NC4_hdf5get_superblock(file,&superblock)))
395  goto done;
396  provenance->superblockversion = superblock;
397 
398  if(propstring == NULL) {
399  /* Use dfalt */
400  if((ncstat=propinfo_default(&provenance->propattr,dfalt)))
401  goto done;
402  } else {
403  NClist* list = provenance->propattr.properties;
404  if((ncstat=properties_parse(propstring,list)))
405  goto done;
406  /* Check the version and remove from properties list*/
407  if(nclistlength(list) < 2)
408  {ncstat = NC_EINVAL; goto done;} /* bad _NCProperties attribute */
409  /* Extract the purported version=... */
410  name = nclistremove(list,0);
411  value = nclistremove(list,0);
412  if(strcmp(name,NCPVERSION) == 0) {
413  if(sscanf(value,"%d",&v) != 1)
414  {ncstat = NC_EINVAL; goto done;} /* illegal version */
415  if(v <= 0 || v > NCPROPS_VERSION)
416  {ncstat = NC_EINVAL; goto done;} /* unknown version */
417  provenance->propattr.version = v;
418  } else
419  {ncstat = NC_EINVAL; goto done;} /* bad _NCProperties attribute */
420  /* Now, rebuild from version 1 to version 2 if necessary */
421  if(provenance->propattr.version == 1) {
422  int i;
423  for(i=0;i<nclistlength(list);i+=2) {
424  char* newname = NULL;
425  name = nclistget(list,i);
426  if(name == NULL) continue; /* ignore */
427  if(strcmp(name,NCPNCLIB1) == 0)
428  newname = NCPNCLIB2; /* change name */
429  else if(strcmp(name,NCPHDF5LIB1) == 0)
430  newname = NCPHDF5LIB2;
431  else continue; /* ignore */
432  /* Do any rename */
433  nclistset(list,i,strdup(newname));
434  if(name) {free(name); name = NULL;}
435  }
436  }
437  }
438 done:
439  if(name != NULL) free(name);
440  if(value != NULL) free(value);
441  return ncstat;
442 }
443 
453 int
454 NC4_free_provenance(struct NCPROVENANCE* prov)
455 {
456  LOG((3, "%s", __func__));
457 
458  if(prov == NULL) return NC_NOERR;
459  if(prov->propattr.properties != NULL)
460  nclistfreeall(prov->propattr.properties);
461  prov->propattr.properties = NULL;
462  free(prov);
463  return NC_NOERR;
464 }
465 
466 /* HDF5 Specific attribute read/write of _NCProperties */
467 int
468 NC4_read_ncproperties(NC_FILE_INFO_T* h5)
469 {
470  int retval = NC_NOERR;
471  hid_t hdf5grpid = -1;
472  hid_t attid = -1;
473  hid_t aspace = -1;
474  hid_t atype = -1;
475  hid_t ntype = -1;
476  char* text = NULL;
477  H5T_class_t t_class;
478  hsize_t size;
479 
480  LOG((3, "%s", __func__));
481 
482  hdf5grpid = ((NC_HDF5_GRP_INFO_T *)(h5->root_grp->format_grp_info))->hdf_grpid;
483 
484  if(H5Aexists(hdf5grpid,NCPROPS) <= 0) { /* Does not exist */
485  /* File did not contain a _NCProperties attribute */
486  retval=NC4_get_provenance(h5,NULL,&globalpropinfo);
487  goto done;
488  }
489 
490  /* NCPROPS Attribute exists, make sure it is legitimate */
491  attid = H5Aopen_name(hdf5grpid, NCPROPS);
492  assert(attid > 0);
493  aspace = H5Aget_space(attid);
494  atype = H5Aget_type(attid);
495  /* Verify atype and size */
496  t_class = H5Tget_class(atype);
497  if(t_class != H5T_STRING)
498  {retval = NC_EINVAL; goto done;}
499  size = H5Tget_size(atype);
500  if(size == 0)
501  {retval = NC_EINVAL; goto done;}
502  text = (char*)malloc(1+(size_t)size);
503  if(text == NULL)
504  {retval = NC_ENOMEM; goto done;}
505  if((ntype = H5Tget_native_type(atype, H5T_DIR_DEFAULT)) < 0)
506  {retval = NC_EHDFERR; goto done;}
507  if((H5Aread(attid, ntype, text)) < 0)
508  {retval = NC_EHDFERR; goto done;}
509  /* Make sure its null terminated */
510  text[(size_t)size] = '\0';
511  /* Process the _NCProperties value */
512  if((retval = NC4_get_provenance(h5, text, &globalpropinfo)))
513  goto done;
514 
515 done:
516  if(text != NULL) free(text);
517  /* Close out the HDF5 objects */
518  if(attid > 0 && H5Aclose(attid) < 0) retval = NC_EHDFERR;
519  if(aspace > 0 && H5Sclose(aspace) < 0) retval = NC_EHDFERR;
520  if(atype > 0 && H5Tclose(atype) < 0) retval = NC_EHDFERR;
521  if(ntype > 0 && H5Tclose(ntype) < 0) retval = NC_EHDFERR;
522 
523  /* For certain errors, actually fail, else log that attribute was invalid and ignore */
524  if(retval != NC_NOERR) {
525  if(retval != NC_ENOMEM && retval != NC_EHDFERR) {
526  LOG((0,"Invalid _NCProperties attribute: ignored"));
527  retval = NC_NOERR;
528  }
529  }
530  return retval;
531 }
532 
533 int
534 NC4_write_ncproperties(NC_FILE_INFO_T* h5)
535 {
536  int retval = NC_NOERR;
537  hid_t hdf5grpid = -1;
538  hid_t attid = -1;
539  hid_t aspace = -1;
540  hid_t atype = -1;
541  char* text = NULL;
542  size_t len = 0;
543 
544  LOG((3, "%s", __func__));
545 
546  /* If the file is read-only, return an error. */
547  if (h5->no_write)
548  {retval = NC_EPERM; goto done;}
549 
550  hdf5grpid = ((NC_HDF5_GRP_INFO_T *)(h5->root_grp->format_grp_info))->hdf_grpid;
551 
552  if(H5Aexists(hdf5grpid,NCPROPS) > 0) /* Already exists, no overwrite */
553  goto done;
554 
555  /* Build the attribute string */
556  if((retval = NC4_buildpropinfo(&h5->provenance->propattr,&text)))
557  goto done;
558 
559  /* Build the HDF5 string type */
560  if ((atype = H5Tcopy(H5T_C_S1)) < 0)
561  {retval = NC_EHDFERR; goto done;}
562  if (H5Tset_strpad(atype, H5T_STR_NULLTERM) < 0)
563  {retval = NC_EHDFERR; goto done;}
564  if(H5Tset_cset(atype, H5T_CSET_ASCII) < 0)
565  {retval = NC_EHDFERR; goto done;}
566  len = strlen(text);
567  if(H5Tset_size(atype, len) < 0)
568  {retval = NC_EFILEMETA; goto done;}
569 
570  /* Create NCPROPS attribute */
571  if((aspace = H5Screate(H5S_SCALAR)) < 0)
572  {retval = NC_EFILEMETA; goto done;}
573  if ((attid = H5Acreate(hdf5grpid, NCPROPS, atype, aspace, H5P_DEFAULT)) < 0)
574  {retval = NC_EFILEMETA; goto done;}
575  if (H5Awrite(attid, atype, text) < 0)
576  {retval = NC_EFILEMETA; goto done;}
577 
578 /* Verify */
579 #if 0
580  {
581  hid_t spacev, typev;
582  hsize_t dsize, tsize;
583  typev = H5Aget_type(attid);
584  spacev = H5Aget_space(attid);
585  dsize = H5Aget_storage_size(attid);
586  tsize = H5Tget_size(typev);
587  fprintf(stderr,"dsize=%lu tsize=%lu\n",(unsigned long)dsize,(unsigned long)tsize);
588  }
589 #endif
590 
591 done:
592  if(text != NULL) free(text);
593  /* Close out the HDF5 objects */
594  if(attid > 0 && H5Aclose(attid) < 0) retval = NC_EHDFERR;
595  if(aspace > 0 && H5Sclose(aspace) < 0) retval = NC_EHDFERR;
596  if(atype > 0 && H5Tclose(atype) < 0) retval = NC_EHDFERR;
597 
598  /* For certain errors, actually fail, else log that attribute was invalid and ignore */
599  switch (retval) {
600  case NC_ENOMEM:
601  case NC_EHDFERR:
602  case NC_EPERM:
603  case NC_EFILEMETA:
604  case NC_NOERR:
605  break;
606  default:
607  LOG((0,"Invalid _NCProperties attribute"));
608  retval = NC_NOERR;
609  break;
610  }
611  return retval;
612 }
613 
614 /* Debugging */
615 
616 void
617 ncprintpropinfo(struct NCPROPINFO* info)
618 {
619  int i;
620  fprintf(stderr,"[%p] version=%d\n",info,info->version);
621  for(i=0;i<nclistlength(info->properties);i+=2) {
622  char* name = nclistget(info->properties,i);
623  char* value = nclistget(info->properties,i+1);
624  fprintf(stderr,"\t[%d] name=|%s| value=|%s|\n",i,name,value);
625  }
626 }
627 
628 void
629 ncprintprovenance(struct NCPROVENANCE* prov)
630 {
631  fprintf(stderr,"[%p] superblockversion=%d\n",prov,prov->superblockversion);
632  ncprintpropinfo(&prov->propattr);
633 }
struct NCPROPINFO globalpropinfo
Global property info.
Definition: nc4info.c:30
#define NC_ENOMEM
Memory allocation (malloc) failure.
Definition: netcdf.h:403
#define NC_EHDFERR
Error at HDF5 layer.
Definition: netcdf.h:436
#define NC_EFILEMETA
Problem with file metadata.
Definition: netcdf.h:440
#define NC_EINVAL
Invalid Argument.
Definition: netcdf.h:333
#define NC_EPERM
Write to read only.
Definition: netcdf.h:334
#define NC_NOERR
No Error.
Definition: netcdf.h:323

Return to the Main Unidata NetCDF page.
Generated on Sat Apr 6 2019 08:19:00 for NetCDF. NetCDF is a Unidata library.