NetCDF  4.7.4
nc4internal.c
Go to the documentation of this file.
1 /* Copyright 2003-2018, University Corporation for Atmospheric
2  * Research. See the COPYRIGHT file for copying and redistribution
3  * conditions.
4  */
18 #include "config.h"
19 #include "netcdf.h"
20 #include "netcdf_filter.h"
21 #include "nc4internal.h"
22 #include "nc.h" /* from libsrc */
23 #include "ncdispatch.h" /* from libdispatch */
24 #include "ncutf8.h"
25 
26 /* These hold the file caching settings for the library. */
27 size_t nc4_chunk_cache_size = CHUNK_CACHE_SIZE;
28 size_t nc4_chunk_cache_nelems = CHUNK_CACHE_NELEMS;
29 float nc4_chunk_cache_preemption = CHUNK_CACHE_PREEMPTION;
31 static void freefilterlist(NClist* filters);
32 
33 #ifdef LOGGING
34 /* This is the severity level of messages which will be logged. Use
35  severity 0 for errors, 1 for important log messages, 2 for less
36  important, etc. */
37 int nc_log_level = NC_TURN_OFF_LOGGING;
38 #endif /* LOGGING */
39 
52 int
53 nc4_check_name(const char *name, char *norm_name)
54 {
55  char *temp;
56  int retval;
57 
58  assert(norm_name);
59 
60  /* Check for NULL. */
61  if (!name)
62  return NC_EINVAL;
63 
64  /* Make sure this is a valid netcdf name. This should be done
65  * before the name is normalized, because it gives better error
66  * codes for bad utf8 strings. */
67  if ((retval = NC_check_name(name)))
68  return retval;
69 
70  /* Normalize the name. */
71  if ((retval = nc_utf8_normalize((const unsigned char *)name,
72  (unsigned char **)&temp)))
73  return retval;
74 
75  /* Check length of normalized name. */
76  if (strlen(temp) > NC_MAX_NAME)
77  {
78  free(temp);
79  return NC_EMAXNAME;
80  }
81 
82  /* Copy the normalized name. */
83  strcpy(norm_name, temp);
84  free(temp);
85 
86  return NC_NOERR;
87 }
88 
109 int
110 nc4_file_list_add(int ncid, const char *path, int mode, void **dispatchdata)
111 {
112  NC *nc;
113  int ret;
114 
115  /* Find NC pointer for this file. */
116  if ((ret = NC_check_id(ncid, &nc)))
117  return ret;
118 
119  /* Add necessary structs to hold netcdf-4 file data. This is where
120  * the NC_FILE_INFO_T struct is allocated for the file. */
121  if ((ret = nc4_nc4f_list_add(nc, path, mode)))
122  return ret;
123 
124  /* If the user wants a pointer to the NC_FILE_INFO_T, then provide
125  * it. */
126  if (dispatchdata)
127  *dispatchdata = nc->dispatchdata;
128 
129  return NC_NOERR;
130 }
131 
145 int
146 nc4_file_change_ncid(int ncid, unsigned short new_ncid_index)
147 {
148  NC *nc;
149  int ret;
150 
151  LOG((2, "%s: ncid %d new_ncid_index %d", __func__, ncid, new_ncid_index));
152 
153  /* Find NC pointer for this file. */
154  if ((ret = NC_check_id(ncid, &nc)))
155  return ret;
156 
157  /* Move it in the list. It will faile if list spot is already
158  * occupied. */
159  LOG((3, "moving nc->ext_ncid %d nc->ext_ncid >> ID_SHIFT %d",
160  nc->ext_ncid, nc->ext_ncid >> ID_SHIFT));
161  if (move_in_NCList(nc, new_ncid_index))
162  return NC_EIO;
163  LOG((3, "moved to new_ncid_index %d new nc->ext_ncid %d", new_ncid_index,
164  nc->ext_ncid));
165 
166  return NC_NOERR;
167 }
168 
188 int
189 nc4_file_list_get(int ncid, char **path, int *mode, void **dispatchdata)
190 {
191  NC *nc;
192  int ret;
193 
194  /* Find NC pointer for this file. */
195  if ((ret = NC_check_id(ncid, &nc)))
196  return ret;
197 
198  /* If the user wants path, give it. */
199  if (path)
200  strncpy(*path, nc->path, NC_MAX_NAME);
201 
202  /* If the user wants mode, give it. */
203  if (mode)
204  *mode = nc->mode;
205 
206  /* If the user wants dispatchdata, give it. */
207  if (dispatchdata)
208  *dispatchdata = nc->dispatchdata;
209 
210  return NC_NOERR;
211 }
212 
227 int
228 nc4_nc4f_list_add(NC *nc, const char *path, int mode)
229 {
230  NC_FILE_INFO_T *h5;
231  int retval;
232 
233  assert(nc && !NC4_DATA(nc) && path);
234 
235  /* We need to malloc and initialize the substructure
236  NC_FILE_INFO_T. */
237  if (!(h5 = calloc(1, sizeof(NC_FILE_INFO_T))))
238  return NC_ENOMEM;
239  nc->dispatchdata = h5;
240  h5->controller = nc;
241 
242  /* Hang on to cmode, and note that we're in define mode. */
243  h5->cmode = mode | NC_INDEF;
244 
245  /* The next_typeid needs to be set beyond the end of our atomic
246  * types. */
247  h5->next_typeid = NC_FIRSTUSERTYPEID;
248 
249  /* Initialize lists for dimensions, types, and groups. */
250  h5->alldims = nclistnew();
251  h5->alltypes = nclistnew();
252  h5->allgroups = nclistnew();
253 
254  /* There's always at least one open group - the root
255  * group. Allocate space for one group's worth of information. Set
256  * its grp id, name, and allocate associated empty lists. */
257  if ((retval = nc4_grp_list_add(h5, NULL, NC_GROUP_NAME, &h5->root_grp)))
258  return retval;
259 
260  return NC_NOERR;
261 }
262 
275 int
276 nc4_find_nc4_grp(int ncid, NC_GRP_INFO_T **grp)
277 {
278  return nc4_find_nc_grp_h5(ncid, NULL, grp, NULL);
279 }
280 
296 int
297 nc4_find_grp_h5(int ncid, NC_GRP_INFO_T **grp, NC_FILE_INFO_T **h5)
298 {
299  return nc4_find_nc_grp_h5(ncid, NULL, grp, h5);
300 }
301 
316 int
317 nc4_find_nc_grp_h5(int ncid, NC **nc, NC_GRP_INFO_T **grp, NC_FILE_INFO_T **h5)
318 {
319  NC_GRP_INFO_T *my_grp = NULL;
320  NC_FILE_INFO_T *my_h5 = NULL;
321  NC *my_nc;
322  int retval;
323 
324  /* Look up file metadata. */
325  if ((retval = NC_check_id(ncid, &my_nc)))
326  return retval;
327  my_h5 = my_nc->dispatchdata;
328  assert(my_h5 && my_h5->root_grp);
329 
330  /* If we can't find it, the grp id part of ncid is bad. */
331  if (!(my_grp = nclistget(my_h5->allgroups, (ncid & GRP_ID_MASK))))
332  return NC_EBADID;
333 
334  /* Return pointers to caller, if desired. */
335  if (nc)
336  *nc = my_nc;
337  if (h5)
338  *h5 = my_h5;
339  if (grp)
340  *grp = my_grp;
341 
342  return NC_NOERR;
343 }
344 
360 int
361 nc4_find_grp_h5_var(int ncid, int varid, NC_FILE_INFO_T **h5, NC_GRP_INFO_T **grp,
362  NC_VAR_INFO_T **var)
363 {
364  NC_FILE_INFO_T *my_h5;
365  NC_GRP_INFO_T *my_grp;
366  NC_VAR_INFO_T *my_var;
367  int retval;
368 
369  /* Look up file and group metadata. */
370  if ((retval = nc4_find_grp_h5(ncid, &my_grp, &my_h5)))
371  return retval;
372  assert(my_grp && my_h5);
373 
374  /* Find the var. */
375  if (!(my_var = (NC_VAR_INFO_T *)ncindexith(my_grp->vars, varid)))
376  return NC_ENOTVAR;
377  assert(my_var && my_var->hdr.id == varid);
378 
379  /* Return pointers that caller wants. */
380  if (h5)
381  *h5 = my_h5;
382  if (grp)
383  *grp = my_grp;
384  if (var)
385  *var = my_var;
386 
387  return NC_NOERR;
388 }
389 
403 int
404 nc4_find_dim(NC_GRP_INFO_T *grp, int dimid, NC_DIM_INFO_T **dim,
405  NC_GRP_INFO_T **dim_grp)
406 {
407  assert(grp && grp->nc4_info && dim);
408  LOG((4, "%s: dimid %d", __func__, dimid));
409 
410  /* Find the dim info. */
411  if (!((*dim) = nclistget(grp->nc4_info->alldims, dimid)))
412  return NC_EBADDIM;
413 
414  /* Give the caller the group the dimension is in. */
415  if (dim_grp)
416  *dim_grp = (*dim)->container;
417 
418  return NC_NOERR;
419 }
420 
431 int
432 nc4_find_var(NC_GRP_INFO_T *grp, const char *name, NC_VAR_INFO_T **var)
433 {
434  assert(grp && var && name);
435 
436  /* Find the var info. */
437  *var = (NC_VAR_INFO_T*)ncindexlookup(grp->vars,name);
438  return NC_NOERR;
439 }
440 
450 NC_TYPE_INFO_T *
451 nc4_rec_find_named_type(NC_GRP_INFO_T *start_grp, char *name)
452 {
453  NC_GRP_INFO_T *g;
454  NC_TYPE_INFO_T *type, *res;
455  int i;
456 
457  assert(start_grp);
458 
459  /* Does this group have the type we are searching for? */
460  type = (NC_TYPE_INFO_T*)ncindexlookup(start_grp->type,name);
461  if(type != NULL)
462  return type;
463 
464  /* Search subgroups. */
465  for(i=0;i<ncindexsize(start_grp->children);i++) {
466  g = (NC_GRP_INFO_T*)ncindexith(start_grp->children,i);
467  if(g == NULL) continue;
468  if ((res = nc4_rec_find_named_type(g, name)))
469  return res;
470  }
471  /* Can't find it. Oh, woe is me! */
472  return NULL;
473 }
474 
486 int
487 nc4_find_type(const NC_FILE_INFO_T *h5, nc_type typeid, NC_TYPE_INFO_T **type)
488 {
489  /* Check inputs. */
490  assert(h5);
491  if (typeid < 0 || !type)
492  return NC_EINVAL;
493  *type = NULL;
494 
495  /* Atomic types don't have associated NC_TYPE_INFO_T struct, just
496  * return NOERR. */
497  if (typeid <= NC_STRING)
498  return NC_NOERR;
499 
500  /* Find the type. */
501  if (!(*type = nclistget(h5->alltypes,typeid)))
502  return NC_EBADTYPID;
503 
504  return NC_NOERR;
505 }
506 
522 int
523 nc4_find_grp_att(NC_GRP_INFO_T *grp, int varid, const char *name, int attnum,
524  NC_ATT_INFO_T **att)
525 {
526  NC_VAR_INFO_T *var;
527  NC_ATT_INFO_T *my_att;
528  NCindex *attlist = NULL;
529 
530  assert(grp && grp->hdr.name && att);
531 
532  LOG((4, "%s: grp->name %s varid %d attnum %d", __func__, grp->hdr.name,
533  varid, attnum));
534 
535  /* Get either the global or a variable attribute list. */
536  if (varid == NC_GLOBAL)
537  {
538  attlist = grp->att;
539  }
540  else
541  {
542  var = (NC_VAR_INFO_T*)ncindexith(grp->vars,varid);
543  if (!var) return NC_ENOTVAR;
544 
545  attlist = var->att;
546  }
547  assert(attlist);
548 
549  /* Now find the attribute by name or number. If a name is provided,
550  * ignore the attnum. */
551  if (name)
552  my_att = (NC_ATT_INFO_T *)ncindexlookup(attlist, name);
553  else
554  my_att = (NC_ATT_INFO_T *)ncindexith(attlist, attnum);
555 
556  if (!my_att)
557  return NC_ENOTATT;
558 
559  *att = my_att;
560  return NC_NOERR;
561 }
562 
579 int
580 nc4_find_nc_att(int ncid, int varid, const char *name, int attnum,
581  NC_ATT_INFO_T **att)
582 {
583  NC_GRP_INFO_T *grp;
584  int retval;
585 
586  LOG((4, "nc4_find_nc_att: ncid 0x%x varid %d name %s attnum %d",
587  ncid, varid, name, attnum));
588 
589  /* Find info for this file and group, and set pointer to each. */
590  if ((retval = nc4_find_grp_h5(ncid, &grp, NULL)))
591  return retval;
592  assert(grp);
593 
594  return nc4_find_grp_att(grp, varid, name, attnum, att);
595 }
596 
605 static void
606 obj_track(NC_FILE_INFO_T* file, NC_OBJ* obj)
607 {
608  NClist* list = NULL;
609  /* record the object in the file */
610  switch (obj->sort) {
611  case NCDIM: list = file->alldims; break;
612  case NCTYP: list = file->alltypes; break;
613  case NCGRP: list = file->allgroups; break;
614  default:
615  assert(NC_FALSE);
616  }
617  /* Insert at the appropriate point in the list */
618  nclistset(list,obj->id,obj);
619 }
620 
635 int
636 nc4_var_list_add2(NC_GRP_INFO_T *grp, const char *name, NC_VAR_INFO_T **var)
637 {
638  NC_VAR_INFO_T *new_var = NULL;
639 
640  /* Allocate storage for new variable. */
641  if (!(new_var = calloc(1, sizeof(NC_VAR_INFO_T))))
642  return NC_ENOMEM;
643  new_var->hdr.sort = NCVAR;
644  new_var->container = grp;
645 
646  /* These are the HDF5-1.8.4 defaults. */
647  new_var->chunk_cache_size = nc4_chunk_cache_size;
648  new_var->chunk_cache_nelems = nc4_chunk_cache_nelems;
649  new_var->chunk_cache_preemption = nc4_chunk_cache_preemption;
650 
651  /* Now fill in the values in the var info structure. */
652  new_var->hdr.id = ncindexsize(grp->vars);
653  if (!(new_var->hdr.name = strdup(name))) {
654  if(new_var)
655  free(new_var);
656  return NC_ENOMEM;
657  }
658 
659  new_var->hdr.hashkey = NC_hashmapkey(new_var->hdr.name,
660  strlen(new_var->hdr.name));
661 
662  /* Create an indexed list for the attributes. */
663  new_var->att = ncindexnew(0);
664 
665  /* Officially track it */
666  ncindexadd(grp->vars, (NC_OBJ *)new_var);
667 
668  /* Set the var pointer, if one was given */
669  if (var)
670  *var = new_var;
671 
672  return NC_NOERR;
673 }
674 
687 int
688 nc4_var_set_ndims(NC_VAR_INFO_T *var, int ndims)
689 {
690  assert(var);
691 
692  /* Remember the number of dimensions. */
693  var->ndims = ndims;
694 
695  /* Allocate space for dimension information. */
696  if (ndims)
697  {
698  if (!(var->dim = calloc(ndims, sizeof(NC_DIM_INFO_T *))))
699  return NC_ENOMEM;
700  if (!(var->dimids = calloc(ndims, sizeof(int))))
701  return NC_ENOMEM;
702 
703  /* Initialize dimids to illegal values (-1). See the comment
704  in nc4_rec_match_dimscales(). */
705  memset(var->dimids, -1, ndims * sizeof(int));
706  }
707 
708  return NC_NOERR;
709 }
710 
725 int
726 nc4_var_list_add(NC_GRP_INFO_T* grp, const char* name, int ndims,
727  NC_VAR_INFO_T **var)
728 {
729  int retval;
730 
731  if ((retval = nc4_var_list_add2(grp, name, var)))
732  return retval;
733  if ((retval = nc4_var_set_ndims(*var, ndims)))
734  return retval;
735 
736  return NC_NOERR;
737 }
738 
752 int
753 nc4_dim_list_add(NC_GRP_INFO_T *grp, const char *name, size_t len,
754  int assignedid, NC_DIM_INFO_T **dim)
755 {
756  NC_DIM_INFO_T *new_dim = NULL;
757 
758  assert(grp && name);
759 
760  /* Allocate memory for dim metadata. */
761  if (!(new_dim = calloc(1, sizeof(NC_DIM_INFO_T))))
762  return NC_ENOMEM;
763 
764  new_dim->hdr.sort = NCDIM;
765 
766  /* Assign the dimension ID. */
767  if (assignedid >= 0)
768  new_dim->hdr.id = assignedid;
769  else
770  new_dim->hdr.id = grp->nc4_info->next_dimid++;
771 
772  /* Remember the name and create a hash. */
773  if (!(new_dim->hdr.name = strdup(name))) {
774  if(new_dim)
775  free(new_dim);
776 
777  return NC_ENOMEM;
778  }
779  new_dim->hdr.hashkey = NC_hashmapkey(new_dim->hdr.name,
780  strlen(new_dim->hdr.name));
781 
782  /* Is dimension unlimited? */
783  new_dim->len = len;
784  if (len == NC_UNLIMITED)
785  new_dim->unlimited = NC_TRUE;
786 
787  /* Remember the containing group. */
788  new_dim->container = grp;
789 
790  /* Add object to dimension list for this group. */
791  ncindexadd(grp->dim, (NC_OBJ *)new_dim);
792  obj_track(grp->nc4_info, (NC_OBJ *)new_dim);
793 
794  /* Set the dim pointer, if one was given */
795  if (dim)
796  *dim = new_dim;
797 
798  return NC_NOERR;
799 }
800 
813 int
814 nc4_att_list_add(NCindex *list, const char *name, NC_ATT_INFO_T **att)
815 {
816  NC_ATT_INFO_T *new_att = NULL;
817 
818  LOG((3, "%s: name %s ", __func__, name));
819 
820  if (!(new_att = calloc(1, sizeof(NC_ATT_INFO_T))))
821  return NC_ENOMEM;
822  new_att->hdr.sort = NCATT;
823 
824  /* Fill in the information we know. */
825  new_att->hdr.id = ncindexsize(list);
826  if (!(new_att->hdr.name = strdup(name))) {
827  if(new_att)
828  free(new_att);
829  return NC_ENOMEM;
830  }
831  /* Create a hash of the name. */
832  new_att->hdr.hashkey = NC_hashmapkey(name, strlen(name));
833 
834  /* Add object to list as specified by its number */
835  ncindexadd(list, (NC_OBJ *)new_att);
836 
837  /* Set the attribute pointer, if one was given */
838  if (att)
839  *att = new_att;
840 
841  return NC_NOERR;
842 }
843 
858 int
859 nc4_grp_list_add(NC_FILE_INFO_T *h5, NC_GRP_INFO_T *parent, char *name,
860  NC_GRP_INFO_T **grp)
861 {
862  NC_GRP_INFO_T *new_grp;
863 
864  /* Check inputs. */
865  assert(h5 && name);
866  LOG((3, "%s: name %s ", __func__, name));
867 
868  /* Get the memory to store this groups info. */
869  if (!(new_grp = calloc(1, sizeof(NC_GRP_INFO_T))))
870  return NC_ENOMEM;
871 
872  /* Fill in this group's information. */
873  new_grp->hdr.sort = NCGRP;
874  new_grp->nc4_info = h5;
875  new_grp->parent = parent;
876 
877  /* Assign the group ID. The root group will get id 0. */
878  new_grp->hdr.id = h5->next_nc_grpid++;
879  assert(parent || !new_grp->hdr.id);
880 
881  /* Handle the group name. */
882  if (!(new_grp->hdr.name = strdup(name)))
883  {
884  free(new_grp);
885  return NC_ENOMEM;
886  }
887  new_grp->hdr.hashkey = NC_hashmapkey(new_grp->hdr.name,
888  strlen(new_grp->hdr.name));
889 
890  /* Set up new indexed lists for stuff this group can contain. */
891  new_grp->children = ncindexnew(0);
892  new_grp->dim = ncindexnew(0);
893  new_grp->att = ncindexnew(0);
894  new_grp->type = ncindexnew(0);
895  new_grp->vars = ncindexnew(0);
896 
897  /* Add object to lists */
898  if (parent)
899  ncindexadd(parent->children, (NC_OBJ *)new_grp);
900  obj_track(h5, (NC_OBJ *)new_grp);
901 
902  /* Set the group pointer, if one was given */
903  if (grp)
904  *grp = new_grp;
905 
906  return NC_NOERR;
907 }
908 
922 int
923 nc4_check_dup_name(NC_GRP_INFO_T *grp, char *name)
924 {
925  NC_TYPE_INFO_T *type;
926  NC_GRP_INFO_T *g;
927  NC_VAR_INFO_T *var;
928 
929  /* Any types of this name? */
930  type = (NC_TYPE_INFO_T*)ncindexlookup(grp->type,name);
931  if(type != NULL)
932  return NC_ENAMEINUSE;
933 
934  /* Any child groups of this name? */
935  g = (NC_GRP_INFO_T*)ncindexlookup(grp->children,name);
936  if(g != NULL)
937  return NC_ENAMEINUSE;
938 
939  /* Any variables of this name? */
940  var = (NC_VAR_INFO_T*)ncindexlookup(grp->vars,name);
941  if(var != NULL)
942  return NC_ENAMEINUSE;
943 
944  return NC_NOERR;
945 }
946 
960 int
961 nc4_type_new(size_t size, const char *name, int assignedid,
962  NC_TYPE_INFO_T **type)
963 {
964  NC_TYPE_INFO_T *new_type;
965 
966  LOG((4, "%s: size %d name %s assignedid %d", __func__, size, name, assignedid));
967 
968  /* Check inputs. */
969  assert(type);
970 
971  /* Allocate memory for the type */
972  if (!(new_type = calloc(1, sizeof(NC_TYPE_INFO_T))))
973  return NC_ENOMEM;
974  new_type->hdr.sort = NCTYP;
975 
976  /* Remember info about this type. */
977  new_type->hdr.id = assignedid;
978  new_type->size = size;
979  if (!(new_type->hdr.name = strdup(name))) {
980  free(new_type);
981  return NC_ENOMEM;
982  }
983 
984  new_type->hdr.hashkey = NC_hashmapkey(name, strlen(name));
985 
986  /* Return a pointer to the new type. */
987  *type = new_type;
988 
989  return NC_NOERR;
990 }
991 
1005 int
1006 nc4_type_list_add(NC_GRP_INFO_T *grp, size_t size, const char *name,
1007  NC_TYPE_INFO_T **type)
1008 {
1009  NC_TYPE_INFO_T *new_type;
1010  int retval;
1011 
1012  /* Check inputs. */
1013  assert(grp && name && type);
1014  LOG((4, "%s: size %d name %s", __func__, size, name));
1015 
1016  /* Create the new TYPE_INFO struct. */
1017  if ((retval = nc4_type_new(size, name, grp->nc4_info->next_typeid,
1018  &new_type)))
1019  return retval;
1020  grp->nc4_info->next_typeid++;
1021 
1022  /* Increment the ref. count on the type */
1023  new_type->rc++;
1024 
1025  /* Add object to lists */
1026  ncindexadd(grp->type, (NC_OBJ *)new_type);
1027  obj_track(grp->nc4_info,(NC_OBJ*)new_type);
1028 
1029  /* Return a pointer to the new type. */
1030  *type = new_type;
1031 
1032  return NC_NOERR;
1033 }
1034 
1048 int
1049 nc4_field_list_add(NC_TYPE_INFO_T *parent, const char *name,
1050  size_t offset, nc_type xtype, int ndims,
1051  const int *dim_sizesp)
1052 {
1053  NC_FIELD_INFO_T *field;
1054 
1055  /* Name has already been checked and UTF8 normalized. */
1056  if (!name)
1057  return NC_EINVAL;
1058 
1059  /* Allocate storage for this field information. */
1060  if (!(field = calloc(1, sizeof(NC_FIELD_INFO_T))))
1061  return NC_ENOMEM;
1062  field->hdr.sort = NCFLD;
1063 
1064  /* Store the information about this field. */
1065  if (!(field->hdr.name = strdup(name)))
1066  {
1067  free(field);
1068  return NC_ENOMEM;
1069  }
1070  field->hdr.hashkey = NC_hashmapkey(field->hdr.name,strlen(field->hdr.name));
1071  field->nc_typeid = xtype;
1072  field->offset = offset;
1073  field->ndims = ndims;
1074  if (ndims)
1075  {
1076  int i;
1077  if (!(field->dim_size = malloc(ndims * sizeof(int))))
1078  {
1079  free(field->hdr.name);
1080  free(field);
1081  return NC_ENOMEM;
1082  }
1083  for (i = 0; i < ndims; i++)
1084  field->dim_size[i] = dim_sizesp[i];
1085  }
1086 
1087  /* Add object to lists */
1088  field->hdr.id = nclistlength(parent->u.c.field);
1089  nclistpush(parent->u.c.field,field);
1090 
1091  return NC_NOERR;
1092 }
1093 
1106 int
1107 nc4_enum_member_add(NC_TYPE_INFO_T *parent, size_t size,
1108  const char *name, const void *value)
1109 {
1110  NC_ENUM_MEMBER_INFO_T *member;
1111 
1112  /* Name has already been checked. */
1113  assert(name && size > 0 && value);
1114  LOG((4, "%s: size %d name %s", __func__, size, name));
1115 
1116  /* Allocate storage for this field information. */
1117  if (!(member = calloc(1, sizeof(NC_ENUM_MEMBER_INFO_T))))
1118  return NC_ENOMEM;
1119  if (!(member->value = malloc(size))) {
1120  free(member);
1121  return NC_ENOMEM;
1122  }
1123  if (!(member->name = strdup(name))) {
1124  free(member->value);
1125  free(member);
1126  return NC_ENOMEM;
1127  }
1128 
1129  /* Store the value for this member. */
1130  memcpy(member->value, value, size);
1131 
1132  /* Add object to list */
1133  nclistpush(parent->u.e.enum_member,member);
1134 
1135  return NC_NOERR;
1136 }
1137 
1146 static void
1147 field_free(NC_FIELD_INFO_T *field)
1148 {
1149  /* Free some stuff. */
1150  if (field->hdr.name)
1151  free(field->hdr.name);
1152  if (field->dim_size)
1153  free(field->dim_size);
1154 
1155  /* Nc_Free the memory. */
1156  free(field);
1157 }
1158 
1168 int
1169 nc4_type_free(NC_TYPE_INFO_T *type)
1170 {
1171  int i;
1172 
1173  assert(type && type->rc && type->hdr.name);
1174 
1175  /* Decrement the ref. count on the type */
1176  type->rc--;
1177 
1178  /* Release the type, if the ref. count drops to zero */
1179  if (type->rc == 0)
1180  {
1181  LOG((4, "%s: deleting type %s", __func__, type->hdr.name));
1182 
1183  /* Free the name. */
1184  free(type->hdr.name);
1185 
1186  /* Enums and compound types have lists of fields to clean up. */
1187  switch (type->nc_type_class)
1188  {
1189  case NC_COMPOUND:
1190  {
1191  NC_FIELD_INFO_T *field;
1192 
1193  /* Delete all the fields in this type (there will be some if its a
1194  * compound). */
1195  for(i=0;i<nclistlength(type->u.c.field);i++) {
1196  field = nclistget(type->u.c.field,i);
1197  field_free(field);
1198  }
1199  nclistfree(type->u.c.field);
1200  }
1201  break;
1202 
1203  case NC_ENUM:
1204  {
1205  NC_ENUM_MEMBER_INFO_T *enum_member;
1206 
1207  /* Delete all the enum_members, if any. */
1208  for(i=0;i<nclistlength(type->u.e.enum_member);i++) {
1209  enum_member = nclistget(type->u.e.enum_member,i);
1210  free(enum_member->value);
1211  free(enum_member->name);
1212  free(enum_member);
1213  }
1214  nclistfree(type->u.e.enum_member);
1215  }
1216  break;
1217 
1218  default:
1219  break;
1220  }
1221 
1222  /* Release any HDF5-specific type info. */
1223  if (type->format_type_info)
1224  free(type->format_type_info);
1225 
1226  /* Release the memory. */
1227  free(type);
1228  }
1229 
1230  return NC_NOERR;
1231 }
1232 
1241 static int
1242 att_free(NC_ATT_INFO_T *att)
1243 {
1244  int i;
1245 
1246  assert(att);
1247  LOG((3, "%s: name %s ", __func__, att->hdr.name));
1248 
1249  /* Free memory that was malloced to hold data for this
1250  * attribute. */
1251  if (att->data)
1252  free(att->data);
1253 
1254  /* Free the name. */
1255  if (att->hdr.name)
1256  free(att->hdr.name);
1257 
1258  /* If this is a string array attribute, delete all members of the
1259  * string array, then delete the array of pointers to strings. (The
1260  * array was filled with pointers by HDF5 when the att was read,
1261  * and memory for each string was allocated by HDF5. That's why I
1262  * use free and not nc_free, because the netCDF library didn't
1263  * allocate the memory that is being freed.) */
1264  if (att->stdata)
1265  {
1266  for (i = 0; i < att->len; i++)
1267  if(att->stdata[i])
1268  free(att->stdata[i]);
1269  free(att->stdata);
1270  }
1271 
1272  /* If this att has vlen data, release it. */
1273  if (att->vldata)
1274  {
1275  for (i = 0; i < att->len; i++)
1276  nc_free_vlen(&att->vldata[i]);
1277  free(att->vldata);
1278  }
1279 
1280  /* Free any format-sepecific info. Some formats use this (ex. HDF5)
1281  * and some don't (ex. HDF4). So it may be NULL. */
1282  if (att->format_att_info)
1283  free(att->format_att_info);
1284 
1285  free(att);
1286  return NC_NOERR;
1287 }
1288 
1298 static int
1299 var_free(NC_VAR_INFO_T *var)
1300 {
1301  int i;
1302  int retval;
1303 
1304  assert(var);
1305  LOG((4, "%s: deleting var %s", __func__, var->hdr.name));
1306 
1307  /* First delete all the attributes attached to this var. */
1308  for (i = 0; i < ncindexsize(var->att); i++)
1309  if ((retval = att_free((NC_ATT_INFO_T *)ncindexith(var->att, i))))
1310  return retval;
1311  ncindexfree(var->att);
1312 
1313  /* Free some things that may be allocated. */
1314  if (var->chunksizes)
1315  free(var->chunksizes);
1316 
1317  if (var->hdf5_name)
1318  free(var->hdf5_name);
1319 
1320  if (var->hdr.name)
1321  free(var->hdr.name);
1322 
1323  if (var->dimids)
1324  free(var->dimids);
1325 
1326  if (var->dim)
1327  free(var->dim);
1328 
1329  /* Delete any fill value allocation. */
1330  if (var->fill_value)
1331  free(var->fill_value);
1332 
1333  /* Release type information */
1334  if (var->type_info)
1335  if ((retval = nc4_type_free(var->type_info)))
1336  return retval;
1337 
1338  /* Delete information about the attachment status of dimscales. */
1339  if (var->dimscale_attached)
1340  free(var->dimscale_attached);
1341 
1342  /* Release filter information. */
1343  freefilterlist(var->filters);
1344 
1345  /* Delete any format-specific info. */
1346  if (var->format_var_info)
1347  free(var->format_var_info);
1348 
1349  /* Delete the var. */
1350  free(var);
1351 
1352  return NC_NOERR;
1353 }
1354 
1364 int
1365 nc4_var_list_del(NC_GRP_INFO_T *grp, NC_VAR_INFO_T *var)
1366 {
1367  int i;
1368 
1369  assert(var && grp);
1370 
1371  /* Remove from lists */
1372  i = ncindexfind(grp->vars, (NC_OBJ *)var);
1373  if (i >= 0)
1374  ncindexidel(grp->vars, i);
1375 
1376  return var_free(var);
1377 }
1378 
1387 static int
1388 dim_free(NC_DIM_INFO_T *dim)
1389 {
1390  assert(dim);
1391  LOG((4, "%s: deleting dim %s", __func__, dim->hdr.name));
1392 
1393  /* Free memory allocated for names. */
1394  if (dim->hdr.name)
1395  free(dim->hdr.name);
1396 
1397  /* Release any format-specific information. */
1398  if (dim->format_dim_info)
1399  free(dim->format_dim_info);
1400 
1401  free(dim);
1402  return NC_NOERR;
1403 }
1404 
1414 int
1415 nc4_dim_list_del(NC_GRP_INFO_T *grp, NC_DIM_INFO_T *dim)
1416 {
1417  if (grp && dim)
1418  {
1419  int pos = ncindexfind(grp->dim, (NC_OBJ *)dim);
1420  if(pos >= 0)
1421  ncindexidel(grp->dim, pos);
1422  }
1423 
1424  return dim_free(dim);
1425 }
1426 
1436 int
1437 nc4_rec_grp_del(NC_GRP_INFO_T *grp)
1438 {
1439  int i;
1440  int retval;
1441 
1442  assert(grp);
1443  LOG((3, "%s: grp->name %s", __func__, grp->hdr.name));
1444 
1445  /* Recursively call this function for each child, if any, stopping
1446  * if there is an error. */
1447  for (i = 0; i < ncindexsize(grp->children); i++)
1448  if ((retval = nc4_rec_grp_del((NC_GRP_INFO_T *)ncindexith(grp->children,
1449  i))))
1450  return retval;
1451  ncindexfree(grp->children);
1452 
1453  /* Free attributes, but leave in parent list */
1454  for (i = 0; i < ncindexsize(grp->att); i++)
1455  if ((retval = att_free((NC_ATT_INFO_T *)ncindexith(grp->att, i))))
1456  return retval;
1457  ncindexfree(grp->att);
1458 
1459  /* Delete all vars. */
1460  for (i = 0; i < ncindexsize(grp->vars); i++) {
1461  NC_VAR_INFO_T* v = (NC_VAR_INFO_T *)ncindexith(grp->vars, i);
1462  if ((retval = var_free(v)))
1463  return retval;
1464  }
1465  ncindexfree(grp->vars);
1466 
1467  /* Delete all dims, and free the list of dims. */
1468  for (i = 0; i < ncindexsize(grp->dim); i++)
1469  if ((retval = dim_free((NC_DIM_INFO_T *)ncindexith(grp->dim, i))))
1470  return retval;
1471  ncindexfree(grp->dim);
1472 
1473  /* Delete all types. */
1474  for (i = 0; i < ncindexsize(grp->type); i++)
1475  if ((retval = nc4_type_free((NC_TYPE_INFO_T *)ncindexith(grp->type, i))))
1476  return retval;
1477  ncindexfree(grp->type);
1478 
1479  /* Free the name. */
1480  free(grp->hdr.name);
1481 
1482  /* Release any format-specific information about this group. */
1483  if (grp->format_grp_info)
1484  free(grp->format_grp_info);
1485 
1486  /* Free up this group */
1487  free(grp);
1488 
1489  return NC_NOERR;
1490 }
1491 
1502 int
1503 nc4_att_list_del(NCindex *list, NC_ATT_INFO_T *att)
1504 {
1505  assert(att && list);
1506  ncindexidel(list, ((NC_OBJ *)att)->id);
1507  return att_free(att);
1508 }
1509 
1523 int
1524 nc4_file_list_del(int ncid)
1525 {
1526  NC_FILE_INFO_T *h5;
1527  int retval;
1528 
1529  /* Find our metadata for this file. */
1530  if ((retval = nc4_find_grp_h5(ncid, NULL, &h5)))
1531  return retval;
1532  assert(h5);
1533 
1534  /* Delete the file resources. */
1535  if ((retval = nc4_nc4f_list_del(h5)))
1536  return retval;
1537 
1538  return NC_NOERR;
1539 }
1540 
1550 int
1551 nc4_nc4f_list_del(NC_FILE_INFO_T *h5)
1552 {
1553  int retval;
1554 
1555  assert(h5);
1556 
1557  /* Delete all the list contents for vars, dims, and atts, in each
1558  * group. */
1559  if ((retval = nc4_rec_grp_del(h5->root_grp)))
1560  return retval;
1561 
1562  /* Cleanup these (extra) lists of all dims, groups, and types. */
1563  nclistfree(h5->alldims);
1564  nclistfree(h5->allgroups);
1565  nclistfree(h5->alltypes);
1566 
1567  /* Free the NC_FILE_INFO_T struct. */
1568  free(h5);
1569 
1570  return NC_NOERR;
1571 }
1572 
1586 int
1587 nc4_normalize_name(const char *name, char *norm_name)
1588 {
1589  char *temp_name;
1590  int stat = nc_utf8_normalize((const unsigned char *)name,(unsigned char **)&temp_name);
1591  if(stat != NC_NOERR)
1592  return stat;
1593  if (strlen(temp_name) > NC_MAX_NAME)
1594  {
1595  free(temp_name);
1596  return NC_EMAXNAME;
1597  }
1598  strcpy(norm_name, temp_name);
1599  free(temp_name);
1600  return NC_NOERR;
1601 }
1602 
1603 #ifdef ENABLE_SET_LOG_LEVEL
1604 
1619 int
1620 nc_set_log_level(int new_level)
1621 {
1622 #ifdef LOGGING
1623  /* Remember the new level. */
1624  nc_log_level = new_level;
1625  LOG((4, "log_level changed to %d", nc_log_level));
1626 #endif /*LOGGING */
1627  return 0;
1628 }
1629 #endif /* ENABLE_SET_LOG_LEVEL */
1630 
1631 #ifdef LOGGING
1632 #define MAX_NESTS 10
1633 
1642 static int
1643 rec_print_metadata(NC_GRP_INFO_T *grp, int tab_count)
1644 {
1645  NC_ATT_INFO_T *att;
1646  NC_VAR_INFO_T *var;
1647  NC_DIM_INFO_T *dim;
1648  NC_TYPE_INFO_T *type;
1649  NC_FIELD_INFO_T *field;
1650  char tabs[MAX_NESTS+1] = "";
1651  char temp_string[10];
1652  int t, retval, d, i;
1653 
1654  /* Come up with a number of tabs relative to the group. */
1655  for (t = 0; t < tab_count && t < MAX_NESTS; t++)
1656  tabs[t] = '\t';
1657  tabs[t] = '\0';
1658 
1659  LOG((2, "%s GROUP - %s nc_grpid: %d nvars: %d natts: %d",
1660  tabs, grp->hdr.name, grp->hdr.id, ncindexsize(grp->vars), ncindexsize(grp->att)));
1661 
1662  for (i = 0; i < ncindexsize(grp->att); i++)
1663  {
1664  att = (NC_ATT_INFO_T *)ncindexith(grp->att, i);
1665  assert(att);
1666  LOG((2, "%s GROUP ATTRIBUTE - attnum: %d name: %s type: %d len: %d",
1667  tabs, att->hdr.id, att->hdr.name, att->nc_typeid, att->len));
1668  }
1669 
1670  for (i = 0; i < ncindexsize(grp->dim); i++)
1671  {
1672  dim = (NC_DIM_INFO_T *)ncindexith(grp->dim, i);
1673  assert(dim);
1674  LOG((2, "%s DIMENSION - dimid: %d name: %s len: %d unlimited: %d",
1675  tabs, dim->hdr.id, dim->hdr.name, dim->len, dim->unlimited));
1676  }
1677 
1678  for (i = 0; i < ncindexsize(grp->vars); i++)
1679  {
1680  int j;
1681  char storage_str[NC_MAX_NAME] = "";
1682  char *dims_string = NULL;
1683 
1684  var = (NC_VAR_INFO_T*)ncindexith(grp->vars,i);
1685  assert(var);
1686  if (var->ndims > 0)
1687  {
1688  if (!(dims_string = malloc(sizeof(char) * var->ndims * 4)))
1689  return NC_ENOMEM;
1690  strcpy(dims_string, "");
1691  for (d = 0; d < var->ndims; d++)
1692  {
1693  sprintf(temp_string, " %d", var->dimids[d]);
1694  strcat(dims_string, temp_string);
1695  }
1696  }
1697  if (!var->meta_read)
1698  strcat(storage_str, "unknown");
1699  else if (var->storage == NC_CONTIGUOUS)
1700  strcat(storage_str, "contiguous");
1701  else if (var->storage == NC_COMPACT)
1702  strcat(storage_str, "compact");
1703  else
1704  strcat(storage_str, "chunked");
1705  LOG((2, "%s VARIABLE - varid: %d name: %s ndims: %d dimscale: %d "
1706  "dimids:%s storage: %s", tabs, var->hdr.id, var->hdr.name,
1707  var->ndims, (int)var->dimscale,
1708  (dims_string ? dims_string : " -"), storage_str));
1709  for (j = 0; j < ncindexsize(var->att); j++)
1710  {
1711  att = (NC_ATT_INFO_T *)ncindexith(var->att, j);
1712  assert(att);
1713  LOG((2, "%s VAR ATTRIBUTE - attnum: %d name: %s type: %d len: %d",
1714  tabs, att->hdr.id, att->hdr.name, att->nc_typeid, att->len));
1715  }
1716  if (dims_string)
1717  free(dims_string);
1718  }
1719 
1720  for (i = 0; i < ncindexsize(grp->type); i++)
1721  {
1722  type = (NC_TYPE_INFO_T*)ncindexith(grp->type, i);
1723  assert(type);
1724  LOG((2, "%s TYPE - nc_typeid: %d size: %d committed: %d name: %s",
1725  tabs, type->hdr.id, type->size, (int)type->committed, type->hdr.name));
1726  /* Is this a compound type? */
1727  if (type->nc_type_class == NC_COMPOUND)
1728  {
1729  int j;
1730  LOG((3, "compound type"));
1731  for (j = 0; j < nclistlength(type->u.c.field); j++)
1732  {
1733  field = (NC_FIELD_INFO_T *)nclistget(type->u.c.field, j);
1734  LOG((4, "field %s offset %d nctype %d ndims %d", field->hdr.name,
1735  field->offset, field->nc_typeid, field->ndims));
1736  }
1737  }
1738  else if (type->nc_type_class == NC_VLEN)
1739  {
1740  LOG((3, "VLEN type"));
1741  LOG((4, "base_nc_type: %d", type->u.v.base_nc_typeid));
1742  }
1743  else if (type->nc_type_class == NC_OPAQUE)
1744  LOG((3, "Opaque type"));
1745  else if (type->nc_type_class == NC_ENUM)
1746  {
1747  LOG((3, "Enum type"));
1748  LOG((4, "base_nc_type: %d", type->u.e.base_nc_typeid));
1749  }
1750  else
1751  {
1752  LOG((0, "Unknown class: %d", type->nc_type_class));
1753  return NC_EBADTYPE;
1754  }
1755  }
1756 
1757  /* Call self for each child of this group. */
1758  for (i = 0; i < ncindexsize(grp->children); i++)
1759  if ((retval = rec_print_metadata((NC_GRP_INFO_T *)ncindexith(grp->children, i),
1760  tab_count + 1)))
1761  return retval;
1762 
1763  return NC_NOERR;
1764 }
1765 
1776 int
1777 log_metadata_nc(NC_FILE_INFO_T *h5)
1778 {
1779  LOG((2, "*** NetCDF-4 Internal Metadata: int_ncid 0x%x ext_ncid 0x%x",
1780  h5->root_grp->nc4_info->controller->int_ncid,
1781  h5->root_grp->nc4_info->controller->ext_ncid));
1782  if (!h5)
1783  {
1784  LOG((2, "This is a netCDF-3 file."));
1785  return NC_NOERR;
1786  }
1787  LOG((2, "FILE - path: %s cmode: 0x%x parallel: %d redef: %d "
1788  "fill_mode: %d no_write: %d next_nc_grpid: %d", h5->root_grp->nc4_info->controller->path,
1789  h5->cmode, (int)h5->parallel, (int)h5->redef, h5->fill_mode, (int)h5->no_write,
1790  h5->next_nc_grpid));
1791  if(nc_log_level >= 2)
1792  return rec_print_metadata(h5->root_grp, 0);
1793  return NC_NOERR;
1794 }
1795 
1796 #endif /*LOGGING */
1797 
1809 int
1810 NC4_show_metadata(int ncid)
1811 {
1812  int retval = NC_NOERR;
1813 #ifdef LOGGING
1814  NC_FILE_INFO_T *h5;
1815  int old_log_level = nc_log_level;
1816 
1817  /* Find file metadata. */
1818  if ((retval = nc4_find_grp_h5(ncid, NULL, &h5)))
1819  return retval;
1820 
1821  /* Log level must be 2 to see metadata. */
1822  nc_log_level = 2;
1823  retval = log_metadata_nc(h5);
1824  nc_log_level = old_log_level;
1825 #endif /*LOGGING*/
1826  return retval;
1827 }
1828 
1829 static void
1830 freefilterlist(NClist* filters)
1831 {
1832  int i;
1833  if(filters == NULL) return;
1834  for(i=0;i<nclistlength(filters);i++) {
1835  NC_FILTER_SPEC_HDF5* f = nclistget(filters,i);
1836  NC4_freefilterspec(f);
1837  }
1838  nclistfree(filters);
1839 }
#define NC_ENOMEM
Memory allocation (malloc) failure.
Definition: netcdf.h:409
#define NC_CONTIGUOUS
In HDF5 files you can set storage for each variable to be either contiguous or chunked, with nc_def_var_chunking().
Definition: netcdf.h:298
#define NC_OPAQUE
opaque types
Definition: netcdf.h:54
Main header file for the C API.
#define NC_STRING
string
Definition: netcdf.h:47
size_t nc4_chunk_cache_nelems
Default chunk cache number of elements.
Definition: nc4internal.c:28
int nc_type
The nc_type type is just an int.
Definition: netcdf.h:25
#define NC_EBADDIM
Invalid dimension id or name.
Definition: netcdf.h:372
#define NC_EIO
Generic IO error.
Definition: netcdf.h:418
#define NC_ENAMEINUSE
String match to name in use.
Definition: netcdf.h:368
#define NC_VLEN
vlen (variable-length) types
Definition: netcdf.h:53
#define NC_EBADTYPE
Not a netcdf data type.
Definition: netcdf.h:371
#define NC_EINVAL
Invalid Argument.
Definition: netcdf.h:339
#define NC_MAX_NAME
Maximum for classic library.
Definition: netcdf.h:275
#define NC_EBADTYPID
Bad type ID.
Definition: netcdf.h:458
EXTERNL int nc_free_vlen(nc_vlen_t *vl)
Free memory in a VLEN object.
Definition: dvlen.c:41
#define NC_COMPACT
In HDF5 files you can set storage for each variable to be either contiguous or chunked, with nc_def_var_chunking().
Definition: netcdf.h:299
#define NC_EBADID
Not a netcdf id.
Definition: netcdf.h:336
#define NC_UNLIMITED
Size argument to nc_def_dim() for an unlimited dimension.
Definition: netcdf.h:245
size_t nc4_chunk_cache_size
Default chunk cache size.
Definition: nc4internal.c:27
#define NC_ENOTVAR
Variable not found.
Definition: netcdf.h:383
#define NC_EMAXNAME
NC_MAX_NAME exceeded.
Definition: netcdf.h:387
#define NC_NOERR
No Error.
Definition: netcdf.h:329
#define NC_ENUM
enum types
Definition: netcdf.h:55
float nc4_chunk_cache_preemption
Default chunk cache preemption.
Definition: nc4internal.c:29
#define NC_COMPOUND
compound types
Definition: netcdf.h:56
#define NC_GLOBAL
Attribute id to put/get a global attribute.
Definition: netcdf.h:248
#define NC_ENOTATT
Attribute not found.
Definition: netcdf.h:369

Return to the Main Unidata NetCDF page.
Generated on Mon Nov 16 2020 01:48:49 for NetCDF. NetCDF is a Unidata library.