NetCDF  4.8.0
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 #include "netcdf_aux.h"
26 
35 #define NRESERVED 11 /*|NC_reservedatt|*/
36 
39 static const NC_reservedatt NC_reserved[NRESERVED] = {
40  {NC_ATT_CLASS, READONLYFLAG|DIMSCALEFLAG}, /*CLASS*/
41  {NC_ATT_DIMENSION_LIST, READONLYFLAG|DIMSCALEFLAG}, /*DIMENSION_LIST*/
42  {NC_ATT_NAME, READONLYFLAG|DIMSCALEFLAG}, /*NAME*/
43  {NC_ATT_REFERENCE_LIST, READONLYFLAG|DIMSCALEFLAG}, /*REFERENCE_LIST*/
44  {NC_ATT_FORMAT, READONLYFLAG}, /*_Format*/
45  {ISNETCDF4ATT, READONLYFLAG|NAMEONLYFLAG}, /*_IsNetcdf4*/
46  {NCPROPS, READONLYFLAG|NAMEONLYFLAG|MATERIALIZEDFLAG},/*_NCProperties*/
47  {NC_ATT_COORDINATES, READONLYFLAG|DIMSCALEFLAG|MATERIALIZEDFLAG},/*_Netcdf4Coordinates*/
48  {NC_ATT_DIMID_NAME, READONLYFLAG|DIMSCALEFLAG|MATERIALIZEDFLAG},/*_Netcdf4Dimid*/
49  {SUPERBLOCKATT, READONLYFLAG|NAMEONLYFLAG},/*_SuperblockVersion*/
50  {NC_ATT_NC3_STRICT_NAME, READONLYFLAG|MATERIALIZEDFLAG}, /*_nc3_strict*/
51 };
52 
53 /* These hold the file caching settings for the library. */
54 size_t nc4_chunk_cache_size = CHUNK_CACHE_SIZE;
55 size_t nc4_chunk_cache_nelems = CHUNK_CACHE_NELEMS;
56 float nc4_chunk_cache_preemption = CHUNK_CACHE_PREEMPTION;
58 static int NC4_move_in_NCList(NC* nc, int new_id);
59 
60 #ifdef LOGGING
61 /* This is the severity level of messages which will be logged. Use
62  severity 0 for errors, 1 for important log messages, 2 for less
63  important, etc. */
64 int nc_log_level = NC_TURN_OFF_LOGGING;
65 #endif /* LOGGING */
66 
79 int
80 nc4_check_name(const char *name, char *norm_name)
81 {
82  char *temp;
83  int retval;
84 
85  assert(norm_name);
86 
87  /* Check for NULL. */
88  if (!name)
89  return NC_EINVAL;
90 
91  /* Make sure this is a valid netcdf name. This should be done
92  * before the name is normalized, because it gives better error
93  * codes for bad utf8 strings. */
94  if ((retval = NC_check_name(name)))
95  return retval;
96 
97  /* Normalize the name. */
98  if ((retval = nc_utf8_normalize((const unsigned char *)name,
99  (unsigned char **)&temp)))
100  return retval;
101 
102  /* Check length of normalized name. */
103  if (strlen(temp) > NC_MAX_NAME)
104  {
105  free(temp);
106  return NC_EMAXNAME;
107  }
108 
109  /* Copy the normalized name. */
110  strcpy(norm_name, temp);
111  free(temp);
112 
113  return NC_NOERR;
114 }
115 
136 int
137 nc4_file_list_add(int ncid, const char *path, int mode, void **dispatchdata)
138 {
139  NC *nc;
140  int ret;
141 
142  /* Find NC pointer for this file. */
143  if ((ret = NC_check_id(ncid, &nc)))
144  return ret;
145 
146  /* Add necessary structs to hold netcdf-4 file data. This is where
147  * the NC_FILE_INFO_T struct is allocated for the file. */
148  if ((ret = nc4_nc4f_list_add(nc, path, mode)))
149  return ret;
150 
151  /* If the user wants a pointer to the NC_FILE_INFO_T, then provide
152  * it. */
153  if (dispatchdata)
154  *dispatchdata = nc->dispatchdata;
155 
156  return NC_NOERR;
157 }
158 
172 int
173 nc4_file_change_ncid(int ncid, unsigned short new_ncid_index)
174 {
175  NC *nc;
176  int ret;
177 
178  LOG((2, "%s: ncid %d new_ncid_index %d", __func__, ncid, new_ncid_index));
179 
180  /* Find NC pointer for this file. */
181  if ((ret = NC_check_id(ncid, &nc)))
182  return ret;
183 
184  /* Move it in the list. It will faile if list spot is already
185  * occupied. */
186  LOG((3, "moving nc->ext_ncid %d nc->ext_ncid >> ID_SHIFT %d",
187  nc->ext_ncid, nc->ext_ncid >> ID_SHIFT));
188  if (NC4_move_in_NCList(nc, new_ncid_index))
189  return NC_EIO;
190  LOG((3, "moved to new_ncid_index %d new nc->ext_ncid %d", new_ncid_index,
191  nc->ext_ncid));
192 
193  return NC_NOERR;
194 }
195 
215 int
216 nc4_file_list_get(int ncid, char **path, int *mode, void **dispatchdata)
217 {
218  NC *nc;
219  int ret;
220 
221  /* Find NC pointer for this file. */
222  if ((ret = NC_check_id(ncid, &nc)))
223  return ret;
224 
225  /* If the user wants path, give it. */
226  if (path)
227  strncpy(*path, nc->path, NC_MAX_NAME);
228 
229  /* If the user wants mode, give it. */
230  if (mode)
231  *mode = nc->mode;
232 
233  /* If the user wants dispatchdata, give it. */
234  if (dispatchdata)
235  *dispatchdata = nc->dispatchdata;
236 
237  return NC_NOERR;
238 }
239 
254 int
255 nc4_nc4f_list_add(NC *nc, const char *path, int mode)
256 {
257  NC_FILE_INFO_T *h5;
258  int retval;
259 
260  assert(nc && !NC4_DATA(nc) && path);
261 
262  /* We need to malloc and initialize the substructure
263  NC_FILE_INFO_T. */
264  if (!(h5 = calloc(1, sizeof(NC_FILE_INFO_T))))
265  return NC_ENOMEM;
266  nc->dispatchdata = h5;
267  h5->controller = nc;
268 
269  h5->hdr.sort = NCFIL;
270  h5->hdr.name = strdup(path);
271  h5->hdr.id = nc->ext_ncid;
272 
273  /* Hang on to cmode, and note that we're in define mode. */
274  h5->cmode = mode | NC_INDEF;
275 
276  /* The next_typeid needs to be set beyond the end of our atomic
277  * types. */
278  h5->next_typeid = NC_FIRSTUSERTYPEID;
279 
280  /* Initialize lists for dimensions, types, and groups. */
281  h5->alldims = nclistnew();
282  h5->alltypes = nclistnew();
283  h5->allgroups = nclistnew();
284 
285  /* There's always at least one open group - the root
286  * group. Allocate space for one group's worth of information. Set
287  * its grp id, name, and allocate associated empty lists. */
288  if ((retval = nc4_grp_list_add(h5, NULL, NC_GROUP_NAME, &h5->root_grp)))
289  return retval;
290 
291  return NC_NOERR;
292 }
293 
306 int
307 nc4_find_nc4_grp(int ncid, NC_GRP_INFO_T **grp)
308 {
309  return nc4_find_nc_grp_h5(ncid, NULL, grp, NULL);
310 }
311 
327 int
328 nc4_find_grp_h5(int ncid, NC_GRP_INFO_T **grp, NC_FILE_INFO_T **h5)
329 {
330  return nc4_find_nc_grp_h5(ncid, NULL, grp, h5);
331 }
332 
347 int
348 nc4_find_nc_grp_h5(int ncid, NC **nc, NC_GRP_INFO_T **grp, NC_FILE_INFO_T **h5)
349 {
350  NC_GRP_INFO_T *my_grp = NULL;
351  NC_FILE_INFO_T *my_h5 = NULL;
352  NC *my_nc;
353  int retval;
354 
355  /* Look up file metadata. */
356  if ((retval = NC_check_id(ncid, &my_nc)))
357  return retval;
358  my_h5 = my_nc->dispatchdata;
359  assert(my_h5 && my_h5->root_grp);
360 
361  /* If we can't find it, the grp id part of ncid is bad. */
362  if (!(my_grp = nclistget(my_h5->allgroups, (ncid & GRP_ID_MASK))))
363  return NC_EBADID;
364 
365  /* Return pointers to caller, if desired. */
366  if (nc)
367  *nc = my_nc;
368  if (h5)
369  *h5 = my_h5;
370  if (grp)
371  *grp = my_grp;
372 
373  return NC_NOERR;
374 }
375 
391 int
392 nc4_find_grp_h5_var(int ncid, int varid, NC_FILE_INFO_T **h5, NC_GRP_INFO_T **grp,
393  NC_VAR_INFO_T **var)
394 {
395  NC_FILE_INFO_T *my_h5;
396  NC_GRP_INFO_T *my_grp;
397  NC_VAR_INFO_T *my_var;
398  int retval;
399 
400  /* Look up file and group metadata. */
401  if ((retval = nc4_find_grp_h5(ncid, &my_grp, &my_h5)))
402  return retval;
403  assert(my_grp && my_h5);
404 
405  /* Find the var. */
406  if (!(my_var = (NC_VAR_INFO_T *)ncindexith(my_grp->vars, varid)))
407  return NC_ENOTVAR;
408  assert(my_var && my_var->hdr.id == varid);
409 
410  /* Return pointers that caller wants. */
411  if (h5)
412  *h5 = my_h5;
413  if (grp)
414  *grp = my_grp;
415  if (var)
416  *var = my_var;
417 
418  return NC_NOERR;
419 }
420 
434 int
435 nc4_find_dim(NC_GRP_INFO_T *grp, int dimid, NC_DIM_INFO_T **dim,
436  NC_GRP_INFO_T **dim_grp)
437 {
438  assert(grp && grp->nc4_info && dim);
439  LOG((4, "%s: dimid %d", __func__, dimid));
440 
441  /* Find the dim info. */
442  if (!((*dim) = nclistget(grp->nc4_info->alldims, dimid)))
443  return NC_EBADDIM;
444 
445  /* Give the caller the group the dimension is in. */
446  if (dim_grp)
447  *dim_grp = (*dim)->container;
448 
449  return NC_NOERR;
450 }
451 
462 int
463 nc4_find_var(NC_GRP_INFO_T *grp, const char *name, NC_VAR_INFO_T **var)
464 {
465  assert(grp && var && name);
466 
467  /* Find the var info. */
468  *var = (NC_VAR_INFO_T*)ncindexlookup(grp->vars,name);
469  return NC_NOERR;
470 }
471 
481 NC_TYPE_INFO_T *
482 nc4_rec_find_named_type(NC_GRP_INFO_T *start_grp, char *name)
483 {
484  NC_GRP_INFO_T *g;
485  NC_TYPE_INFO_T *type, *res;
486  int i;
487 
488  assert(start_grp);
489 
490  /* Does this group have the type we are searching for? */
491  type = (NC_TYPE_INFO_T*)ncindexlookup(start_grp->type,name);
492  if(type != NULL)
493  return type;
494 
495  /* Search subgroups. */
496  for(i=0;i<ncindexsize(start_grp->children);i++) {
497  g = (NC_GRP_INFO_T*)ncindexith(start_grp->children,i);
498  if(g == NULL) continue;
499  if ((res = nc4_rec_find_named_type(g, name)))
500  return res;
501  }
502  /* Can't find it. Oh, woe is me! */
503  return NULL;
504 }
505 
517 int
518 nc4_find_type(const NC_FILE_INFO_T *h5, nc_type typeid, NC_TYPE_INFO_T **type)
519 {
520  /* Check inputs. */
521  assert(h5);
522  if (typeid < 0 || !type)
523  return NC_EINVAL;
524  *type = NULL;
525 
526  /* Atomic types don't have associated NC_TYPE_INFO_T struct, just
527  * return NOERR. */
528  if (typeid <= NC_STRING)
529  return NC_NOERR;
530 
531  /* Find the type. */
532  if (!(*type = nclistget(h5->alltypes,typeid)))
533  return NC_EBADTYPID;
534 
535  return NC_NOERR;
536 }
537 
553 int
554 nc4_find_grp_att(NC_GRP_INFO_T *grp, int varid, const char *name, int attnum,
555  NC_ATT_INFO_T **att)
556 {
557  NC_VAR_INFO_T *var;
558  NC_ATT_INFO_T *my_att;
559  NCindex *attlist = NULL;
560 
561  assert(grp && grp->hdr.name && att);
562 
563  LOG((4, "%s: grp->name %s varid %d attnum %d", __func__, grp->hdr.name,
564  varid, attnum));
565 
566  /* Get either the global or a variable attribute list. */
567  if (varid == NC_GLOBAL)
568  {
569  attlist = grp->att;
570  }
571  else
572  {
573  var = (NC_VAR_INFO_T*)ncindexith(grp->vars,varid);
574  if (!var) return NC_ENOTVAR;
575 
576  attlist = var->att;
577  }
578  assert(attlist);
579 
580  /* Now find the attribute by name or number. If a name is provided,
581  * ignore the attnum. */
582  if (name)
583  my_att = (NC_ATT_INFO_T *)ncindexlookup(attlist, name);
584  else
585  my_att = (NC_ATT_INFO_T *)ncindexith(attlist, attnum);
586 
587  if (!my_att)
588  return NC_ENOTATT;
589 
590  *att = my_att;
591  return NC_NOERR;
592 }
593 
610 int
611 nc4_find_nc_att(int ncid, int varid, const char *name, int attnum,
612  NC_ATT_INFO_T **att)
613 {
614  NC_GRP_INFO_T *grp;
615  int retval;
616 
617  LOG((4, "nc4_find_nc_att: ncid 0x%x varid %d name %s attnum %d",
618  ncid, varid, name, attnum));
619 
620  /* Find info for this file and group, and set pointer to each. */
621  if ((retval = nc4_find_grp_h5(ncid, &grp, NULL)))
622  return retval;
623  assert(grp);
624 
625  return nc4_find_grp_att(grp, varid, name, attnum, att);
626 }
627 
636 static void
637 obj_track(NC_FILE_INFO_T* file, NC_OBJ* obj)
638 {
639  NClist* list = NULL;
640  /* record the object in the file */
641  switch (obj->sort) {
642  case NCDIM: list = file->alldims; break;
643  case NCTYP: list = file->alltypes; break;
644  case NCGRP: list = file->allgroups; break;
645  default:
646  assert(NC_FALSE);
647  }
648  /* Insert at the appropriate point in the list */
649  nclistset(list,obj->id,obj);
650 }
651 
666 int
667 nc4_var_list_add2(NC_GRP_INFO_T *grp, const char *name, NC_VAR_INFO_T **var)
668 {
669  NC_VAR_INFO_T *new_var = NULL;
670 
671  /* Allocate storage for new variable. */
672  if (!(new_var = calloc(1, sizeof(NC_VAR_INFO_T))))
673  return NC_ENOMEM;
674  new_var->hdr.sort = NCVAR;
675  new_var->container = grp;
676 
677  /* These are the HDF5-1.8.4 defaults. */
678  new_var->chunk_cache_size = nc4_chunk_cache_size;
679  new_var->chunk_cache_nelems = nc4_chunk_cache_nelems;
680  new_var->chunk_cache_preemption = nc4_chunk_cache_preemption;
681 
682  /* Now fill in the values in the var info structure. */
683  new_var->hdr.id = ncindexsize(grp->vars);
684  if (!(new_var->hdr.name = strdup(name))) {
685  if(new_var)
686  free(new_var);
687  return NC_ENOMEM;
688  }
689 
690  /* Create an indexed list for the attributes. */
691  new_var->att = ncindexnew(0);
692 
693  /* Officially track it */
694  ncindexadd(grp->vars, (NC_OBJ *)new_var);
695 
696  /* Set the var pointer, if one was given */
697  if (var)
698  *var = new_var;
699 
700  return NC_NOERR;
701 }
702 
715 int
716 nc4_var_set_ndims(NC_VAR_INFO_T *var, int ndims)
717 {
718  assert(var);
719 
720  /* Remember the number of dimensions. */
721  var->ndims = ndims;
722 
723  /* Allocate space for dimension information. */
724  if (ndims)
725  {
726  if (!(var->dim = calloc(ndims, sizeof(NC_DIM_INFO_T *))))
727  return NC_ENOMEM;
728  if (!(var->dimids = calloc(ndims, sizeof(int))))
729  return NC_ENOMEM;
730 
731  /* Initialize dimids to illegal values (-1). See the comment
732  in nc4_rec_match_dimscales(). */
733  memset(var->dimids, -1, ndims * sizeof(int));
734  }
735 
736  return NC_NOERR;
737 }
738 
753 int
754 nc4_var_list_add(NC_GRP_INFO_T* grp, const char* name, int ndims,
755  NC_VAR_INFO_T **var)
756 {
757  int retval;
758 
759  if ((retval = nc4_var_list_add2(grp, name, var)))
760  return retval;
761  if ((retval = nc4_var_set_ndims(*var, ndims)))
762  return retval;
763 
764  return NC_NOERR;
765 }
766 
780 int
781 nc4_dim_list_add(NC_GRP_INFO_T *grp, const char *name, size_t len,
782  int assignedid, NC_DIM_INFO_T **dim)
783 {
784  NC_DIM_INFO_T *new_dim = NULL;
785 
786  assert(grp && name);
787 
788  /* Allocate memory for dim metadata. */
789  if (!(new_dim = calloc(1, sizeof(NC_DIM_INFO_T))))
790  return NC_ENOMEM;
791 
792  new_dim->hdr.sort = NCDIM;
793 
794  /* Assign the dimension ID. */
795  if (assignedid >= 0)
796  new_dim->hdr.id = assignedid;
797  else
798  new_dim->hdr.id = grp->nc4_info->next_dimid++;
799 
800  /* Remember the name and create a hash. */
801  if (!(new_dim->hdr.name = strdup(name))) {
802  if(new_dim)
803  free(new_dim);
804 
805  return NC_ENOMEM;
806  }
807 
808  /* Is dimension unlimited? */
809  new_dim->len = len;
810  if (len == NC_UNLIMITED)
811  new_dim->unlimited = NC_TRUE;
812 
813  /* Remember the containing group. */
814  new_dim->container = grp;
815 
816  /* Add object to dimension list for this group. */
817  ncindexadd(grp->dim, (NC_OBJ *)new_dim);
818  obj_track(grp->nc4_info, (NC_OBJ *)new_dim);
819 
820  /* Set the dim pointer, if one was given */
821  if (dim)
822  *dim = new_dim;
823 
824  return NC_NOERR;
825 }
826 
839 int
840 nc4_att_list_add(NCindex *list, const char *name, NC_ATT_INFO_T **att)
841 {
842  NC_ATT_INFO_T *new_att = NULL;
843 
844  LOG((3, "%s: name %s ", __func__, name));
845 
846  if (!(new_att = calloc(1, sizeof(NC_ATT_INFO_T))))
847  return NC_ENOMEM;
848  new_att->hdr.sort = NCATT;
849 
850  /* Fill in the information we know. */
851  new_att->hdr.id = ncindexsize(list);
852  if (!(new_att->hdr.name = strdup(name))) {
853  if(new_att)
854  free(new_att);
855  return NC_ENOMEM;
856  }
857 
858  /* Add object to list as specified by its number */
859  ncindexadd(list, (NC_OBJ *)new_att);
860 
861  /* Set the attribute pointer, if one was given */
862  if (att)
863  *att = new_att;
864 
865  return NC_NOERR;
866 }
867 
882 int
883 nc4_grp_list_add(NC_FILE_INFO_T *h5, NC_GRP_INFO_T *parent, char *name,
884  NC_GRP_INFO_T **grp)
885 {
886  NC_GRP_INFO_T *new_grp;
887 
888  /* Check inputs. */
889  assert(h5 && name);
890  LOG((3, "%s: name %s ", __func__, name));
891 
892  /* Get the memory to store this groups info. */
893  if (!(new_grp = calloc(1, sizeof(NC_GRP_INFO_T))))
894  return NC_ENOMEM;
895 
896  /* Fill in this group's information. */
897  new_grp->hdr.sort = NCGRP;
898  new_grp->nc4_info = h5;
899  new_grp->parent = parent;
900 
901  /* Assign the group ID. The root group will get id 0. */
902  new_grp->hdr.id = h5->next_nc_grpid++;
903  assert(parent || !new_grp->hdr.id);
904 
905  /* Handle the group name. */
906  if (!(new_grp->hdr.name = strdup(name)))
907  {
908  free(new_grp);
909  return NC_ENOMEM;
910  }
911 
912  /* Set up new indexed lists for stuff this group can contain. */
913  new_grp->children = ncindexnew(0);
914  new_grp->dim = ncindexnew(0);
915  new_grp->att = ncindexnew(0);
916  new_grp->type = ncindexnew(0);
917  new_grp->vars = ncindexnew(0);
918 
919  /* Add object to lists */
920  if (parent)
921  ncindexadd(parent->children, (NC_OBJ *)new_grp);
922  obj_track(h5, (NC_OBJ *)new_grp);
923 
924  /* Set the group pointer, if one was given */
925  if (grp)
926  *grp = new_grp;
927 
928  return NC_NOERR;
929 }
930 
944 int
945 nc4_check_dup_name(NC_GRP_INFO_T *grp, char *name)
946 {
947  NC_TYPE_INFO_T *type;
948  NC_GRP_INFO_T *g;
949  NC_VAR_INFO_T *var;
950 
951  /* Any types of this name? */
952  type = (NC_TYPE_INFO_T*)ncindexlookup(grp->type,name);
953  if(type != NULL)
954  return NC_ENAMEINUSE;
955 
956  /* Any child groups of this name? */
957  g = (NC_GRP_INFO_T*)ncindexlookup(grp->children,name);
958  if(g != NULL)
959  return NC_ENAMEINUSE;
960 
961  /* Any variables of this name? */
962  var = (NC_VAR_INFO_T*)ncindexlookup(grp->vars,name);
963  if(var != NULL)
964  return NC_ENAMEINUSE;
965 
966  return NC_NOERR;
967 }
968 
982 int
983 nc4_type_new(size_t size, const char *name, int assignedid,
984  NC_TYPE_INFO_T **type)
985 {
986  NC_TYPE_INFO_T *new_type;
987 
988  LOG((4, "%s: size %d name %s assignedid %d", __func__, size, name, assignedid));
989 
990  /* Check inputs. */
991  assert(type);
992 
993  /* Allocate memory for the type */
994  if (!(new_type = calloc(1, sizeof(NC_TYPE_INFO_T))))
995  return NC_ENOMEM;
996  new_type->hdr.sort = NCTYP;
997  new_type->hdr.id = assignedid;
998 
999  /* Remember info about this type. */
1000  new_type->size = size;
1001  if (!(new_type->hdr.name = strdup(name))) {
1002  free(new_type);
1003  return NC_ENOMEM;
1004  }
1005 
1006  /* Return a pointer to the new type. */
1007  *type = new_type;
1008 
1009  return NC_NOERR;
1010 }
1011 
1025 int
1026 nc4_type_list_add(NC_GRP_INFO_T *grp, size_t size, const char *name,
1027  NC_TYPE_INFO_T **type)
1028 {
1029  NC_TYPE_INFO_T *new_type;
1030  int retval;
1031 
1032  /* Check inputs. */
1033  assert(grp && name && type);
1034  LOG((4, "%s: size %d name %s", __func__, size, name));
1035 
1036  /* Create the new TYPE_INFO struct. */
1037  if ((retval = nc4_type_new(size, name, grp->nc4_info->next_typeid,
1038  &new_type)))
1039  return retval;
1040  grp->nc4_info->next_typeid++;
1041 
1042  /* Increment the ref. count on the type */
1043  new_type->rc++;
1044 
1045  /* Add object to lists */
1046  ncindexadd(grp->type, (NC_OBJ *)new_type);
1047  obj_track(grp->nc4_info,(NC_OBJ*)new_type);
1048 
1049  /* Return a pointer to the new type. */
1050  *type = new_type;
1051 
1052  return NC_NOERR;
1053 }
1054 
1068 int
1069 nc4_field_list_add(NC_TYPE_INFO_T *parent, const char *name,
1070  size_t offset, nc_type xtype, int ndims,
1071  const int *dim_sizesp)
1072 {
1073  NC_FIELD_INFO_T *field;
1074 
1075  /* Name has already been checked and UTF8 normalized. */
1076  if (!name)
1077  return NC_EINVAL;
1078 
1079  /* Allocate storage for this field information. */
1080  if (!(field = calloc(1, sizeof(NC_FIELD_INFO_T))))
1081  return NC_ENOMEM;
1082  field->hdr.sort = NCFLD;
1083 
1084  /* Store the information about this field. */
1085  if (!(field->hdr.name = strdup(name)))
1086  {
1087  free(field);
1088  return NC_ENOMEM;
1089  }
1090  field->nc_typeid = xtype;
1091  field->offset = offset;
1092  field->ndims = ndims;
1093  if (ndims)
1094  {
1095  int i;
1096  if (!(field->dim_size = malloc(ndims * sizeof(int))))
1097  {
1098  free(field->hdr.name);
1099  free(field);
1100  return NC_ENOMEM;
1101  }
1102  for (i = 0; i < ndims; i++)
1103  field->dim_size[i] = dim_sizesp[i];
1104  }
1105 
1106  /* Add object to lists */
1107  field->hdr.id = nclistlength(parent->u.c.field);
1108  nclistpush(parent->u.c.field,field);
1109 
1110  return NC_NOERR;
1111 }
1112 
1125 int
1126 nc4_enum_member_add(NC_TYPE_INFO_T *parent, size_t size,
1127  const char *name, const void *value)
1128 {
1129  NC_ENUM_MEMBER_INFO_T *member;
1130 
1131  /* Name has already been checked. */
1132  assert(name && size > 0 && value);
1133  LOG((4, "%s: size %d name %s", __func__, size, name));
1134 
1135  /* Allocate storage for this field information. */
1136  if (!(member = calloc(1, sizeof(NC_ENUM_MEMBER_INFO_T))))
1137  return NC_ENOMEM;
1138  if (!(member->value = malloc(size))) {
1139  free(member);
1140  return NC_ENOMEM;
1141  }
1142  if (!(member->name = strdup(name))) {
1143  free(member->value);
1144  free(member);
1145  return NC_ENOMEM;
1146  }
1147 
1148  /* Store the value for this member. */
1149  memcpy(member->value, value, size);
1150 
1151  /* Add object to list */
1152  nclistpush(parent->u.e.enum_member,member);
1153 
1154  return NC_NOERR;
1155 }
1156 
1165 static void
1166 field_free(NC_FIELD_INFO_T *field)
1167 {
1168  /* Free some stuff. */
1169  if (field->hdr.name)
1170  free(field->hdr.name);
1171  if (field->dim_size)
1172  free(field->dim_size);
1173 
1174  /* Nc_Free the memory. */
1175  free(field);
1176 }
1177 
1187 int
1188 nc4_type_free(NC_TYPE_INFO_T *type)
1189 {
1190  int i;
1191 
1192  assert(type && type->rc && type->hdr.name);
1193 
1194  /* Decrement the ref. count on the type */
1195  type->rc--;
1196 
1197  /* Release the type, if the ref. count drops to zero */
1198  if (type->rc == 0)
1199  {
1200  LOG((4, "%s: deleting type %s", __func__, type->hdr.name));
1201 
1202  /* Free the name. */
1203  free(type->hdr.name);
1204 
1205  /* Enums and compound types have lists of fields to clean up. */
1206  switch (type->nc_type_class)
1207  {
1208  case NC_COMPOUND:
1209  {
1210  NC_FIELD_INFO_T *field;
1211 
1212  /* Delete all the fields in this type (there will be some if its a
1213  * compound). */
1214  for(i=0;i<nclistlength(type->u.c.field);i++) {
1215  field = nclistget(type->u.c.field,i);
1216  field_free(field);
1217  }
1218  nclistfree(type->u.c.field);
1219  }
1220  break;
1221 
1222  case NC_ENUM:
1223  {
1224  NC_ENUM_MEMBER_INFO_T *enum_member;
1225 
1226  /* Delete all the enum_members, if any. */
1227  for(i=0;i<nclistlength(type->u.e.enum_member);i++) {
1228  enum_member = nclistget(type->u.e.enum_member,i);
1229  free(enum_member->value);
1230  free(enum_member->name);
1231  free(enum_member);
1232  }
1233  nclistfree(type->u.e.enum_member);
1234  }
1235  break;
1236 
1237  default:
1238  break;
1239  }
1240 
1241  /* Release the memory. */
1242  free(type);
1243  }
1244 
1245  return NC_NOERR;
1246 }
1247 
1256 int
1257 nc4_att_free(NC_ATT_INFO_T *att)
1258 {
1259  int i;
1260 
1261  assert(att);
1262  LOG((3, "%s: name %s ", __func__, att->hdr.name));
1263 
1264  /* Free memory that was malloced to hold data for this
1265  * attribute. */
1266  if (att->data)
1267  free(att->data);
1268 
1269  /* Free the name. */
1270  if (att->hdr.name)
1271  free(att->hdr.name);
1272 
1273  /* If this is a string array attribute, delete all members of the
1274  * string array, then delete the array of pointers to strings. (The
1275  * array was filled with pointers by HDF5 when the att was read,
1276  * and memory for each string was allocated by HDF5. That's why I
1277  * use free and not nc_free, because the netCDF library didn't
1278  * allocate the memory that is being freed.) */
1279  if (att->stdata)
1280  {
1281  for (i = 0; i < att->len; i++)
1282  if(att->stdata[i])
1283  free(att->stdata[i]);
1284  free(att->stdata);
1285  }
1286 
1287  /* If this att has vlen data, release it. */
1288  if (att->vldata)
1289  {
1290  for (i = 0; i < att->len; i++)
1291  nc_free_vlen(&att->vldata[i]);
1292  free(att->vldata);
1293  }
1294 
1295  free(att);
1296  return NC_NOERR;
1297 }
1298 
1308 static int
1309 var_free(NC_VAR_INFO_T *var)
1310 {
1311  int i;
1312  int retval;
1313 
1314  assert(var);
1315  LOG((4, "%s: deleting var %s", __func__, var->hdr.name));
1316 
1317  /* First delete all the attributes attached to this var. */
1318  for (i = 0; i < ncindexsize(var->att); i++)
1319  if ((retval = nc4_att_free((NC_ATT_INFO_T *)ncindexith(var->att, i))))
1320  return retval;
1321  ncindexfree(var->att);
1322 
1323  /* Free some things that may be allocated. */
1324  if (var->chunksizes)
1325  free(var->chunksizes);
1326 
1327  if (var->alt_name)
1328  free(var->alt_name);
1329 
1330  if (var->dimids)
1331  free(var->dimids);
1332 
1333  if (var->dim)
1334  free(var->dim);
1335 
1336  /* Delete any fill value allocation. */
1337  if (var->fill_value)
1338  free(var->fill_value);
1339 
1340  /* Release type information */
1341  if (var->type_info)
1342  if ((retval = nc4_type_free(var->type_info)))
1343  return retval;
1344 
1345  /* Do this last because debugging may need it */
1346  if (var->hdr.name)
1347  free(var->hdr.name);
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  free(dim);
1398  return NC_NOERR;
1399 }
1400 
1410 int
1411 nc4_dim_list_del(NC_GRP_INFO_T *grp, NC_DIM_INFO_T *dim)
1412 {
1413  if (grp && dim)
1414  {
1415  int pos = ncindexfind(grp->dim, (NC_OBJ *)dim);
1416  if(pos >= 0)
1417  ncindexidel(grp->dim, pos);
1418  }
1419 
1420  return dim_free(dim);
1421 }
1422 
1432 int
1433 nc4_rec_grp_del(NC_GRP_INFO_T *grp)
1434 {
1435  int i;
1436  int retval;
1437 
1438  assert(grp);
1439  LOG((3, "%s: grp->name %s", __func__, grp->hdr.name));
1440 
1441  /* Recursively call this function for each child, if any, stopping
1442  * if there is an error. */
1443  for (i = 0; i < ncindexsize(grp->children); i++)
1444  if ((retval = nc4_rec_grp_del((NC_GRP_INFO_T *)ncindexith(grp->children,
1445  i))))
1446  return retval;
1447  ncindexfree(grp->children);
1448 
1449  /* Free attributes */
1450  for (i = 0; i < ncindexsize(grp->att); i++)
1451  if ((retval = nc4_att_free((NC_ATT_INFO_T *)ncindexith(grp->att, i))))
1452  return retval;
1453  ncindexfree(grp->att);
1454 
1455  /* Delete all vars. */
1456  for (i = 0; i < ncindexsize(grp->vars); i++) {
1457  NC_VAR_INFO_T* v = (NC_VAR_INFO_T *)ncindexith(grp->vars, i);
1458  if ((retval = var_free(v)))
1459  return retval;
1460  }
1461  ncindexfree(grp->vars);
1462 
1463  /* Delete all dims, and free the list of dims. */
1464  for (i = 0; i < ncindexsize(grp->dim); i++)
1465  if ((retval = dim_free((NC_DIM_INFO_T *)ncindexith(grp->dim, i))))
1466  return retval;
1467  ncindexfree(grp->dim);
1468 
1469  /* Delete all types. */
1470  for (i = 0; i < ncindexsize(grp->type); i++)
1471  if ((retval = nc4_type_free((NC_TYPE_INFO_T *)ncindexith(grp->type, i))))
1472  return retval;
1473  ncindexfree(grp->type);
1474 
1475  /* Free the name. */
1476  free(grp->hdr.name);
1477 
1478  /* Free up this group */
1479  free(grp);
1480 
1481  return NC_NOERR;
1482 }
1483 
1494 int
1495 nc4_att_list_del(NCindex *list, NC_ATT_INFO_T *att)
1496 {
1497  assert(att && list);
1498  ncindexidel(list, ((NC_OBJ *)att)->id);
1499  return nc4_att_free(att);
1500 }
1501 
1515 int
1516 nc4_file_list_del(int ncid)
1517 {
1518  NC_FILE_INFO_T *h5;
1519  int retval;
1520 
1521  /* Find our metadata for this file. */
1522  if ((retval = nc4_find_grp_h5(ncid, NULL, &h5)))
1523  return retval;
1524  assert(h5);
1525 
1526  /* Delete the file resources. */
1527  if ((retval = nc4_nc4f_list_del(h5)))
1528  return retval;
1529 
1530  return NC_NOERR;
1531 }
1532 
1542 int
1543 nc4_nc4f_list_del(NC_FILE_INFO_T *h5)
1544 {
1545  int retval;
1546 
1547  assert(h5);
1548 
1549  /* Delete all the list contents for vars, dims, and atts, in each
1550  * group. */
1551  if ((retval = nc4_rec_grp_del(h5->root_grp)))
1552  return retval;
1553 
1554  /* Cleanup these (extra) lists of all dims, groups, and types. */
1555  nclistfree(h5->alldims);
1556  nclistfree(h5->allgroups);
1557  nclistfree(h5->alltypes);
1558 
1559  /* Free the NC_FILE_INFO_T struct. */
1560  nullfree(h5->hdr.name);
1561  free(h5);
1562 
1563  return NC_NOERR;
1564 }
1565 
1579 int
1580 nc4_normalize_name(const char *name, char *norm_name)
1581 {
1582  char *temp_name;
1583  int stat = nc_utf8_normalize((const unsigned char *)name,(unsigned char **)&temp_name);
1584  if(stat != NC_NOERR)
1585  return stat;
1586  if (strlen(temp_name) > NC_MAX_NAME)
1587  {
1588  free(temp_name);
1589  return NC_EMAXNAME;
1590  }
1591  strcpy(norm_name, temp_name);
1592  free(temp_name);
1593  return NC_NOERR;
1594 }
1595 
1596 #ifdef ENABLE_SET_LOG_LEVEL
1597 
1612 int
1613 nc_set_log_level(int new_level)
1614 {
1615 #ifdef LOGGING
1616  /* Remember the new level. */
1617  nc_log_level = new_level;
1618  LOG((4, "log_level changed to %d", nc_log_level));
1619 #endif /*LOGGING */
1620  return 0;
1621 }
1622 #endif /* ENABLE_SET_LOG_LEVEL */
1623 
1624 #ifdef LOGGING
1625 #define MAX_NESTS 10
1626 
1635 static int
1636 rec_print_metadata(NC_GRP_INFO_T *grp, int tab_count)
1637 {
1638  NC_ATT_INFO_T *att;
1639  NC_VAR_INFO_T *var;
1640  NC_DIM_INFO_T *dim;
1641  NC_TYPE_INFO_T *type;
1642  NC_FIELD_INFO_T *field;
1643  char tabs[MAX_NESTS+1] = "";
1644  char temp_string[10];
1645  int t, retval, d, i;
1646 
1647  /* Come up with a number of tabs relative to the group. */
1648  for (t = 0; t < tab_count && t < MAX_NESTS; t++)
1649  tabs[t] = '\t';
1650  tabs[t] = '\0';
1651 
1652  LOG((2, "%s GROUP - %s nc_grpid: %d nvars: %d natts: %d",
1653  tabs, grp->hdr.name, grp->hdr.id, ncindexsize(grp->vars), ncindexsize(grp->att)));
1654 
1655  for (i = 0; i < ncindexsize(grp->att); i++)
1656  {
1657  att = (NC_ATT_INFO_T *)ncindexith(grp->att, i);
1658  assert(att);
1659  LOG((2, "%s GROUP ATTRIBUTE - attnum: %d name: %s type: %d len: %d",
1660  tabs, att->hdr.id, att->hdr.name, att->nc_typeid, att->len));
1661  }
1662 
1663  for (i = 0; i < ncindexsize(grp->dim); i++)
1664  {
1665  dim = (NC_DIM_INFO_T *)ncindexith(grp->dim, i);
1666  assert(dim);
1667  LOG((2, "%s DIMENSION - dimid: %d name: %s len: %d unlimited: %d",
1668  tabs, dim->hdr.id, dim->hdr.name, dim->len, dim->unlimited));
1669  }
1670 
1671  for (i = 0; i < ncindexsize(grp->vars); i++)
1672  {
1673  int j;
1674  char storage_str[NC_MAX_NAME] = "";
1675  char *dims_string = NULL;
1676 
1677  var = (NC_VAR_INFO_T*)ncindexith(grp->vars,i);
1678  assert(var);
1679  if (var->ndims > 0)
1680  {
1681  if (!(dims_string = malloc(sizeof(char) * var->ndims * 4)))
1682  return NC_ENOMEM;
1683  strcpy(dims_string, "");
1684  for (d = 0; d < var->ndims; d++)
1685  {
1686  sprintf(temp_string, " %d", var->dimids[d]);
1687  strcat(dims_string, temp_string);
1688  }
1689  }
1690  if (!var->meta_read)
1691  strcat(storage_str, "unknown");
1692  else if (var->storage == NC_CONTIGUOUS)
1693  strcat(storage_str, "contiguous");
1694  else if (var->storage == NC_COMPACT)
1695  strcat(storage_str, "compact");
1696  else
1697  strcat(storage_str, "chunked");
1698  LOG((2, "%s VARIABLE - varid: %d name: %s ndims: %d "
1699  "dimids:%s storage: %s", tabs, var->hdr.id, var->hdr.name,
1700  var->ndims,
1701  (dims_string ? dims_string : " -"), storage_str));
1702  for (j = 0; j < ncindexsize(var->att); j++)
1703  {
1704  att = (NC_ATT_INFO_T *)ncindexith(var->att, j);
1705  assert(att);
1706  LOG((2, "%s VAR ATTRIBUTE - attnum: %d name: %s type: %d len: %d",
1707  tabs, att->hdr.id, att->hdr.name, att->nc_typeid, att->len));
1708  }
1709  if (dims_string)
1710  free(dims_string);
1711  }
1712 
1713  for (i = 0; i < ncindexsize(grp->type); i++)
1714  {
1715  type = (NC_TYPE_INFO_T*)ncindexith(grp->type, i);
1716  assert(type);
1717  LOG((2, "%s TYPE - nc_typeid: %d size: %d committed: %d name: %s",
1718  tabs, type->hdr.id, type->size, (int)type->committed, type->hdr.name));
1719  /* Is this a compound type? */
1720  if (type->nc_type_class == NC_COMPOUND)
1721  {
1722  int j;
1723  LOG((3, "compound type"));
1724  for (j = 0; j < nclistlength(type->u.c.field); j++)
1725  {
1726  field = (NC_FIELD_INFO_T *)nclistget(type->u.c.field, j);
1727  LOG((4, "field %s offset %d nctype %d ndims %d", field->hdr.name,
1728  field->offset, field->nc_typeid, field->ndims));
1729  }
1730  }
1731  else if (type->nc_type_class == NC_VLEN)
1732  {
1733  LOG((3, "VLEN type"));
1734  LOG((4, "base_nc_type: %d", type->u.v.base_nc_typeid));
1735  }
1736  else if (type->nc_type_class == NC_OPAQUE)
1737  LOG((3, "Opaque type"));
1738  else if (type->nc_type_class == NC_ENUM)
1739  {
1740  LOG((3, "Enum type"));
1741  LOG((4, "base_nc_type: %d", type->u.e.base_nc_typeid));
1742  }
1743  else
1744  {
1745  LOG((0, "Unknown class: %d", type->nc_type_class));
1746  return NC_EBADTYPE;
1747  }
1748  }
1749 
1750  /* Call self for each child of this group. */
1751  for (i = 0; i < ncindexsize(grp->children); i++)
1752  if ((retval = rec_print_metadata((NC_GRP_INFO_T *)ncindexith(grp->children, i),
1753  tab_count + 1)))
1754  return retval;
1755 
1756  return NC_NOERR;
1757 }
1758 
1769 int
1770 log_metadata_nc(NC_FILE_INFO_T *h5)
1771 {
1772  LOG((2, "*** NetCDF-4 Internal Metadata: int_ncid 0x%x ext_ncid 0x%x",
1773  h5->root_grp->nc4_info->controller->int_ncid,
1774  h5->root_grp->nc4_info->controller->ext_ncid));
1775  if (!h5)
1776  {
1777  LOG((2, "This is a netCDF-3 file."));
1778  return NC_NOERR;
1779  }
1780  LOG((2, "FILE - path: %s cmode: 0x%x parallel: %d redef: %d "
1781  "fill_mode: %d no_write: %d next_nc_grpid: %d", h5->root_grp->nc4_info->controller->path,
1782  h5->cmode, (int)h5->parallel, (int)h5->redef, h5->fill_mode, (int)h5->no_write,
1783  h5->next_nc_grpid));
1784  if(nc_log_level >= 2)
1785  return rec_print_metadata(h5->root_grp, 0);
1786  return NC_NOERR;
1787 }
1788 
1789 #endif /*LOGGING */
1790 
1802 int
1803 NC4_show_metadata(int ncid)
1804 {
1805  int retval = NC_NOERR;
1806 #ifdef LOGGING
1807  NC_FILE_INFO_T *h5;
1808  int old_log_level = nc_log_level;
1809 
1810  /* Find file metadata. */
1811  if ((retval = nc4_find_grp_h5(ncid, NULL, &h5)))
1812  return retval;
1813 
1814  /* Log level must be 2 to see metadata. */
1815  nc_log_level = 2;
1816  retval = log_metadata_nc(h5);
1817  nc_log_level = old_log_level;
1818 #endif /*LOGGING*/
1819  return retval;
1820 }
1821 
1829 const NC_reservedatt*
1830 NC_findreserved(const char* name)
1831 {
1832  int n = NRESERVED;
1833  int L = 0;
1834  int R = (n - 1);
1835  for(;;) {
1836  if(L > R) break;
1837  int m = (L + R) / 2;
1838  const NC_reservedatt* p = &NC_reserved[m];
1839  int cmp = strcmp(p->name,name);
1840  if(cmp == 0) return p;
1841  if(cmp < 0)
1842  L = (m + 1);
1843  else /*cmp > 0*/
1844  R = (m - 1);
1845  }
1846  return NULL;
1847 }
1848 
1849 static int
1850 NC4_move_in_NCList(NC* nc, int new_id)
1851 {
1852  int stat = move_in_NCList(nc,new_id);
1853  if(stat == NC_NOERR) {
1854  /* Synchronize header */
1855  if(nc->dispatchdata)
1856  ((NC_OBJ*)nc->dispatchdata)->id = nc->ext_ncid;
1857  }
1858  return stat;
1859 }
NC_NOERR
#define NC_NOERR
No Error.
Definition: netcdf.h:330
NC_EINVAL
#define NC_EINVAL
Invalid Argument.
Definition: netcdf.h:340
NC_EBADTYPID
#define NC_EBADTYPID
Bad type ID.
Definition: netcdf.h:459
NC_VLEN
#define NC_VLEN
vlen (variable-length) types
Definition: netcdf.h:53
NC_ENAMEINUSE
#define NC_ENAMEINUSE
String match to name in use.
Definition: netcdf.h:369
NC_CONTIGUOUS
#define NC_CONTIGUOUS
In HDF5 files you can set storage for each variable to be either contiguous or chunked,...
Definition: netcdf.h:299
nc4_chunk_cache_preemption
float nc4_chunk_cache_preemption
Default chunk cache preemption.
Definition: nc4internal.c:56
NC_MAX_NAME
#define NC_MAX_NAME
Maximum for classic library.
Definition: netcdf.h:276
NC_GLOBAL
#define NC_GLOBAL
Attribute id to put/get a global attribute.
Definition: netcdf.h:249
NC_EMAXNAME
#define NC_EMAXNAME
NC_MAX_NAME exceeded.
Definition: netcdf.h:388
nc4_chunk_cache_size
size_t nc4_chunk_cache_size
Default chunk cache size.
Definition: nc4internal.c:54
NC_UNLIMITED
#define NC_UNLIMITED
Size argument to nc_def_dim() for an unlimited dimension.
Definition: netcdf.h:246
NC_ENOTATT
#define NC_ENOTATT
Attribute not found.
Definition: netcdf.h:370
NC_COMPACT
#define NC_COMPACT
In HDF5 files you can set storage for each variable to be either contiguous or chunked,...
Definition: netcdf.h:300
NC_COMPOUND
#define NC_COMPOUND
compound types
Definition: netcdf.h:56
netcdf.h
NC_EIO
#define NC_EIO
Generic IO error.
Definition: netcdf.h:419
NC_OPAQUE
#define NC_OPAQUE
opaque types
Definition: netcdf.h:54
nc4_chunk_cache_nelems
size_t nc4_chunk_cache_nelems
Default chunk cache number of elements.
Definition: nc4internal.c:55
nc_type
int nc_type
The nc_type type is just an int.
Definition: netcdf.h:25
NC_EBADTYPE
#define NC_EBADTYPE
Not a netcdf data type.
Definition: netcdf.h:372
NC_ENUM
#define NC_ENUM
enum types
Definition: netcdf.h:55
nc_free_vlen
EXTERNL int nc_free_vlen(nc_vlen_t *vl)
Definition: dvlen.c:41
NC_ENOMEM
#define NC_ENOMEM
Memory allocation (malloc) failure.
Definition: netcdf.h:410
NC_STRING
#define NC_STRING
string
Definition: netcdf.h:47
NC_EBADID
#define NC_EBADID
Not a netcdf id.
Definition: netcdf.h:337
NC_EBADDIM
#define NC_EBADDIM
Invalid dimension id or name.
Definition: netcdf.h:373
NC_ENOTVAR
#define NC_ENOTVAR
Variable not found.
Definition: netcdf.h:384