NetCDF  4.9.3
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 "netcdf_meta.h"
22 #include "nc4internal.h"
23 #include "nc.h" /* from libsrc */
24 #include "ncdispatch.h" /* from libdispatch */
25 #include "ncutf8.h"
26 #include <stdarg.h>
27 #include <stddef.h>
28 #include "ncrc.h"
29 
42 static NC_reservedatt NC_reserved[] = {
43  {NC_ATT_CLASS, READONLYFLAG|HIDDENATTRFLAG}, /*CLASS*/
44  {NC_ATT_DIMENSION_LIST, READONLYFLAG|HIDDENATTRFLAG}, /*DIMENSION_LIST*/
45  {NC_ATT_NAME, READONLYFLAG|HIDDENATTRFLAG}, /*NAME*/
46  {NC_ATT_REFERENCE_LIST, READONLYFLAG|HIDDENATTRFLAG}, /*REFERENCE_LIST*/
47  {NC_XARRAY_DIMS, READONLYFLAG|HIDDENATTRFLAG}, /*_ARRAY_DIMENSIONS*/
48  {NC_ATT_CODECS, VARFLAG|READONLYFLAG|NAMEONLYFLAG}, /*_Codecs*/
49  {NC_ATT_FORMAT, READONLYFLAG}, /*_Format*/
50  {ISNETCDF4ATT, READONLYFLAG|NAMEONLYFLAG|VIRTUALFLAG}, /*_IsNetcdf4*/
51  {NCPROPS,READONLYFLAG|NAMEONLYFLAG|HIDDENATTRFLAG}, /*_NCProperties*/
52  {NC_ATT_COORDINATES, READONLYFLAG|HIDDENATTRFLAG}, /*_Netcdf4Coordinates*/
53  {NC_ATT_DIMID_NAME, READONLYFLAG|HIDDENATTRFLAG}, /*_Netcdf4Dimid*/
54  {SUPERBLOCKATT, READONLYFLAG|NAMEONLYFLAG|VIRTUALFLAG}, /*_SuperblockVersion*/
55  {NC_ATT_NC3_STRICT_NAME, READONLYFLAG}, /*_nc3_strict*/
56  {NC_ATT_NC3_STRICT_NAME, READONLYFLAG}, /*_nc3_strict*/
57  {NC_NCZARR_ATTR, READONLYFLAG|HIDDENATTRFLAG}, /*_nczarr_attr */
58  {NC_NCZARR_GROUP, READONLYFLAG|HIDDENATTRFLAG}, /*_nczarr_group */
59  {NC_NCZARR_ARRAY, READONLYFLAG|HIDDENATTRFLAG}, /*_nczarr_array */
60  {NC_NCZARR_SUPERBLOCK, READONLYFLAG|HIDDENATTRFLAG}, /*_nczarr_superblock */
61 };
62 #define NRESERVED (sizeof(NC_reserved) / sizeof(NC_reservedatt)) /*|NC_reservedatt*/
63 
64 /*Forward */
65 static int NC4_move_in_NCList(NC* nc, int new_id);
66 static int bincmp(const void* arg1, const void* arg2);
67 static int sortcmp(const void* arg1, const void* arg2);
68 
69 #if LOGGING
70 /* This is the severity level of messages which will be logged. Use
71  severity 0 for errors, 1 for important log messages, 2 for less
72  important, etc. */
73 int nc_log_level = NC_TURN_OFF_LOGGING;
74 #if NC_HAS_PARALLEL4
75 /* File pointer for the parallel I/O log file. */
76 FILE *LOG_FILE = NULL;
77 #endif /* NC_HAS_PARALLEL4 */
78 
79 /* This function prints out a message, if the severity of
80  * the message is lower than the global nc_log_level. To use it, do
81  * something like this:
82  *
83  * nc_log(0, "this computer will explode in %d seconds", i);
84  *
85  * After the first arg (the severity), use the rest like a normal
86  * printf statement. Output will appear on stderr for sequential
87  * builds, and in a file nc4_log_R.log for each process for a parallel
88  * build, where R is the rank of the process.
89  *
90  * Ed Hartnett
91  */
92 void
93 nc_log(int severity, const char *fmt, ...)
94 {
95  va_list argp;
96  int t;
97  FILE *f = stderr;
98 
99  /* If the severity is greater than the log level, we don't print
100  * this message. */
101  if (severity > nc_log_level)
102  return;
103 
104 #if NC_HAS_PARALLEL4
105  /* For parallel I/O build, if MPI has been initialized, instead of
106  * printing logging output to stderr, it goes to a file for each
107  * process. */
108  {
109  int mpi_initialized;
110  int mpierr;
111 
112  /* Check to see if MPI has been initialized. */
113  if ((mpierr = MPI_Initialized(&mpi_initialized)))
114  return;
115 
116  /* If MPI has been initialized use a log file. */
117  assert(LOG_FILE);
118  if (mpi_initialized)
119  f = LOG_FILE;
120  }
121 #endif /* NC_HAS_PARALLEL4 */
122 
123  /* If the severity is zero, this is an error. Otherwise insert that
124  many tabs before the message. */
125  if (!severity)
126  fprintf(f, "ERROR: ");
127  for (t = 0; t < severity; t++)
128  fprintf(f, "\t");
129 
130  /* Print out the variable list of args with vprintf. */
131  va_start(argp, fmt);
132  vfprintf(f, fmt, argp);
133  va_end(argp);
134 
135  /* Put on a final linefeed. */
136  fprintf(f, "\n");
137  fflush(f);
138 }
139 #endif /* LOGGING */
140 
153 int
154 nc4_check_name(const char *name, char *norm_name)
155 {
156  char *temp;
157  int retval;
158 
159  assert(norm_name);
160 
161  /* Check for NULL. */
162  if (!name)
163  return NC_EINVAL;
164 
165  /* Make sure this is a valid netcdf name. This should be done
166  * before the name is normalized, because it gives better error
167  * codes for bad utf8 strings. */
168  if ((retval = NC_check_name(name)))
169  return retval;
170 
171  /* Normalize the name. */
172  if ((retval = nc_utf8_normalize((const unsigned char *)name,
173  (unsigned char **)&temp)))
174  return retval;
175 
176  /* Check length of normalized name. */
177  if (strlen(temp) > NC_MAX_NAME)
178  {
179  free(temp);
180  return NC_EMAXNAME;
181  }
182 
183  /* Copy the normalized name. */
184  strcpy(norm_name, temp);
185  free(temp);
186 
187  return NC_NOERR;
188 }
189 
210 int
211 nc4_file_list_add(int ncid, const char *path, int mode, void **dispatchdata)
212 {
213  NC *nc;
214  int ret;
215 
216  /* Find NC pointer for this file. */
217  if ((ret = NC_check_id(ncid, &nc)))
218  return ret;
219 
220  /* Add necessary structs to hold netcdf-4 file data. This is where
221  * the NC_FILE_INFO_T struct is allocated for the file. */
222  if ((ret = nc4_nc4f_list_add(nc, path, mode)))
223  return ret;
224 
225  /* If the user wants a pointer to the NC_FILE_INFO_T, then provide
226  * it. */
227  if (dispatchdata)
228  *dispatchdata = nc->dispatchdata;
229 
230  return NC_NOERR;
231 }
232 
246 int
247 nc4_file_change_ncid(int ncid, unsigned short new_ncid_index)
248 {
249  NC *nc;
250  int ret;
251 
252  LOG((2, "%s: ncid %d new_ncid_index %d", __func__, ncid, new_ncid_index));
253 
254  /* Find NC pointer for this file. */
255  if ((ret = NC_check_id(ncid, &nc)))
256  return ret;
257 
258  /* Move it in the list. It will faile if list spot is already
259  * occupied. */
260  LOG((3, "moving nc->ext_ncid %d nc->ext_ncid >> ID_SHIFT %d",
261  nc->ext_ncid, nc->ext_ncid >> ID_SHIFT));
262  if (NC4_move_in_NCList(nc, new_ncid_index))
263  return NC_EIO;
264  LOG((3, "moved to new_ncid_index %d new nc->ext_ncid %d", new_ncid_index,
265  nc->ext_ncid));
266 
267  return NC_NOERR;
268 }
269 
289 int
290 nc4_file_list_get(int ncid, char **path, int *mode, void **dispatchdata)
291 {
292  NC *nc;
293  int ret;
294 
295  /* Find NC pointer for this file. */
296  if ((ret = NC_check_id(ncid, &nc)))
297  return ret;
298 
299  /* If the user wants path, give it. */
300  if (path)
301  strncpy(*path, nc->path, NC_MAX_NAME);
302 
303  /* If the user wants mode, give it. */
304  if (mode)
305  *mode = nc->mode;
306 
307  /* If the user wants dispatchdata, give it. */
308  if (dispatchdata)
309  *dispatchdata = nc->dispatchdata;
310 
311  return NC_NOERR;
312 }
313 
328 int
329 nc4_nc4f_list_add(NC *nc, const char *path, int mode)
330 {
331  NC_FILE_INFO_T *h5;
332  int retval;
333 
334  assert(nc && !NC4_DATA(nc) && path);
335 
336  /* We need to malloc and initialize the substructure
337  NC_FILE_INFO_T. */
338  if (!(h5 = calloc(1, sizeof(NC_FILE_INFO_T))))
339  return NC_ENOMEM;
340  nc->dispatchdata = h5;
341  h5->controller = nc;
342 
343  h5->hdr.sort = NCFIL;
344  h5->hdr.name = strdup(path);
345  h5->hdr.id = nc->ext_ncid;
346 
347  /* Hang on to cmode, and note that we're in define mode. */
348  h5->cmode = mode | NC_INDEF;
349 
350  /* The next_typeid needs to be set beyond the end of our atomic
351  * types. */
352  h5->next_typeid = NC_FIRSTUSERTYPEID;
353 
354  /* Initialize lists for dimensions, types, and groups. */
355  h5->alldims = nclistnew();
356  h5->alltypes = nclistnew();
357  h5->allgroups = nclistnew();
358 
359  /* There's always at least one open group - the root
360  * group. Allocate space for one group's worth of information. Set
361  * its grp id, name, and allocate associated empty lists. */
362  if ((retval = nc4_grp_list_add(h5, NULL, NC_GROUP_NAME, &h5->root_grp)))
363  return retval;
364 
365  return NC_NOERR;
366 }
367 
380 int
381 nc4_find_nc4_grp(int ncid, NC_GRP_INFO_T **grp)
382 {
383  return nc4_find_nc_grp_h5(ncid, NULL, grp, NULL);
384 }
385 
401 int
402 nc4_find_grp_h5(int ncid, NC_GRP_INFO_T **grp, NC_FILE_INFO_T **h5)
403 {
404  return nc4_find_nc_grp_h5(ncid, NULL, grp, h5);
405 }
406 
421 int
422 nc4_find_nc_grp_h5(int ncid, NC **nc, NC_GRP_INFO_T **grp, NC_FILE_INFO_T **h5)
423 {
424  NC_GRP_INFO_T *my_grp = NULL;
425  NC_FILE_INFO_T *my_h5 = NULL;
426  NC *my_nc;
427  int retval;
428  size_t index;
429 
430  /* Look up file metadata. */
431  if ((retval = NC_check_id(ncid, &my_nc)))
432  return retval;
433  my_h5 = my_nc->dispatchdata;
434  assert(my_h5 && my_h5->root_grp);
435 
436  /* If we can't find it, the grp id part of ncid is bad. */
437  index = (ncid & GRP_ID_MASK);
438  if (!(my_grp = nclistget(my_h5->allgroups,index)))
439  return NC_EBADID;
440 
441  /* Return pointers to caller, if desired. */
442  if (nc)
443  *nc = my_nc;
444  if (h5)
445  *h5 = my_h5;
446  if (grp)
447  *grp = my_grp;
448 
449  return NC_NOERR;
450 }
451 
467 int
468 nc4_find_grp_h5_var(int ncid, int varid, NC_FILE_INFO_T **h5, NC_GRP_INFO_T **grp,
469  NC_VAR_INFO_T **var)
470 {
471  NC_FILE_INFO_T *my_h5;
472  NC_GRP_INFO_T *my_grp;
473  NC_VAR_INFO_T *my_var;
474  int retval;
475 
476  /* Look up file and group metadata. */
477  if ((retval = nc4_find_grp_h5(ncid, &my_grp, &my_h5)))
478  return retval;
479  assert(my_grp && my_h5);
480 
481  /* Find the var. */
482  if (!(my_var = (NC_VAR_INFO_T *)ncindexith(my_grp->vars, (size_t)varid)))
483  return NC_ENOTVAR;
484  assert(my_var && my_var->hdr.id == varid);
485 
486  /* Return pointers that caller wants. */
487  if (h5)
488  *h5 = my_h5;
489  if (grp)
490  *grp = my_grp;
491  if (var)
492  *var = my_var;
493 
494  return NC_NOERR;
495 }
496 
510 int
511 nc4_find_dim(NC_GRP_INFO_T *grp, int dimid, NC_DIM_INFO_T **dim,
512  NC_GRP_INFO_T **dim_grp)
513 {
514  assert(grp && grp->nc4_info && dim);
515  LOG((4, "%s: dimid %d", __func__, dimid));
516 
517  /* Find the dim info. */
518  if (!((*dim) = nclistget(grp->nc4_info->alldims, (size_t)dimid)))
519  return NC_EBADDIM;
520 
521  /* Give the caller the group the dimension is in. */
522  if (dim_grp)
523  *dim_grp = (*dim)->container;
524 
525  return NC_NOERR;
526 }
527 
538 int
539 nc4_find_var(NC_GRP_INFO_T *grp, const char *name, NC_VAR_INFO_T **var)
540 {
541  assert(grp && var && name);
542 
543  /* Find the var info. */
544  *var = (NC_VAR_INFO_T*)ncindexlookup(grp->vars,name);
545  return NC_NOERR;
546 }
547 
557 NC_TYPE_INFO_T *
558 nc4_rec_find_named_type(NC_GRP_INFO_T *start_grp, char *name)
559 {
560  NC_GRP_INFO_T *g;
561  NC_TYPE_INFO_T *type, *res;
562 
563  assert(start_grp);
564 
565  /* Does this group have the type we are searching for? */
566  type = (NC_TYPE_INFO_T*)ncindexlookup(start_grp->type,name);
567  if(type != NULL)
568  return type;
569 
570  /* Search subgroups. */
571  for(size_t i=0;i<ncindexsize(start_grp->children);i++) {
572  g = (NC_GRP_INFO_T*)ncindexith(start_grp->children,i);
573  if(g == NULL) continue;
574  if ((res = nc4_rec_find_named_type(g, name)))
575  return res;
576  }
577  /* Can't find it. Oh, woe is me! */
578  return NULL;
579 }
580 
592 int
593 nc4_find_type(const NC_FILE_INFO_T *h5, nc_type typeid, NC_TYPE_INFO_T **type)
594 {
595  /* Check inputs. */
596  assert(h5);
597  if (typeid < 0 || !type)
598  return NC_EINVAL;
599  *type = NULL;
600 
601  /* Atomic types don't have associated NC_TYPE_INFO_T struct, just
602  * return NOERR. */
603  if (typeid <= NC_STRING)
604  return NC_NOERR;
605 
606  /* Find the type. */
607  if (!(*type = nclistget(h5->alltypes, (size_t)typeid)))
608  return NC_EBADTYPID;
609 
610  return NC_NOERR;
611 }
612 
628 int
629 nc4_find_grp_att(NC_GRP_INFO_T *grp, int varid, const char *name, int attnum,
630  NC_ATT_INFO_T **att)
631 {
632  NC_VAR_INFO_T *var;
633  NC_ATT_INFO_T *my_att;
634  NCindex *attlist = NULL;
635 
636  assert(grp && grp->hdr.name && att);
637 
638  LOG((4, "%s: grp->name %s varid %d attnum %d", __func__, grp->hdr.name,
639  varid, attnum));
640 
641  /* Get either the global or a variable attribute list. */
642  if (varid == NC_GLOBAL)
643  {
644  attlist = grp->att;
645  }
646  else
647  {
648  var = (NC_VAR_INFO_T*)ncindexith(grp->vars,(size_t)varid);
649  if (!var) return NC_ENOTVAR;
650 
651  attlist = var->att;
652  }
653  assert(attlist);
654 
655  /* Now find the attribute by name or number. If a name is provided,
656  * ignore the attnum. */
657  if (name)
658  my_att = (NC_ATT_INFO_T *)ncindexlookup(attlist, name);
659  else
660  my_att = (NC_ATT_INFO_T *)ncindexith(attlist, (size_t)attnum);
661 
662  if (!my_att)
663  return NC_ENOTATT;
664 
665  *att = my_att;
666  return NC_NOERR;
667 }
668 
685 int
686 nc4_find_nc_att(int ncid, int varid, const char *name, int attnum,
687  NC_ATT_INFO_T **att)
688 {
689  NC_GRP_INFO_T *grp;
690  int retval;
691 
692  LOG((4, "nc4_find_nc_att: ncid 0x%x varid %d name %s attnum %d",
693  ncid, varid, name, attnum));
694 
695  /* Find info for this file and group, and set pointer to each. */
696  if ((retval = nc4_find_grp_h5(ncid, &grp, NULL)))
697  return retval;
698  assert(grp);
699 
700  return nc4_find_grp_att(grp, varid, name, attnum, att);
701 }
702 
711 static void
712 obj_track(NC_FILE_INFO_T* file, NC_OBJ* obj)
713 {
714  NClist* list = NULL;
715  /* record the object in the file */
716  switch (obj->sort) {
717  case NCDIM: list = file->alldims; break;
718  case NCTYP: list = file->alltypes; break;
719  case NCGRP: list = file->allgroups; break;
720  default:
721  assert(NC_FALSE);
722  }
723  /* Insert at the appropriate point in the list */
724  nclistset(list,(size_t)obj->id,obj);
725 }
726 
739 int
740 nc4_var_list_add2(NC_GRP_INFO_T *grp, const char *name, NC_VAR_INFO_T **var)
741 {
742  NC_VAR_INFO_T *new_var = NULL;
743  NCglobalstate* gs = NC_getglobalstate();
744 
745  /* Allocate storage for new variable. */
746  if (!(new_var = calloc(1, sizeof(NC_VAR_INFO_T))))
747  return NC_ENOMEM;
748  new_var->hdr.sort = NCVAR;
749  new_var->container = grp;
750 
751  /* These are the HDF5-1.8.4 defaults. */
752  new_var->chunkcache.size = gs->chunkcache.size;
753  new_var->chunkcache.nelems = gs->chunkcache.nelems;
754  new_var->chunkcache.preemption = gs->chunkcache.preemption;
755 
756  /* Now fill in the values in the var info structure. */
757  new_var->hdr.id = (int)ncindexsize(grp->vars);
758  if (!(new_var->hdr.name = strdup(name))) {
759  if(new_var)
760  free(new_var);
761  return NC_ENOMEM;
762  }
763 
764  /* Create an indexed list for the attributes. */
765  new_var->att = ncindexnew(0);
766 
767  /* Officially track it */
768  ncindexadd(grp->vars, (NC_OBJ *)new_var);
769 
770  /* Set the var pointer, if one was given */
771  if (var)
772  *var = new_var;
773 
774  return NC_NOERR;
775 }
776 
787 int
788 nc4_var_set_ndims(NC_VAR_INFO_T *var, int ndims)
789 {
790  assert(var);
791 
792  /* Remember the number of dimensions. */
793  var->ndims = (size_t)ndims;
794 
795  /* Allocate space for dimension information. */
796  if (ndims)
797  {
798  if (!(var->dim = calloc((size_t)ndims, sizeof(NC_DIM_INFO_T *))))
799  return NC_ENOMEM;
800  if (!(var->dimids = calloc((size_t)ndims, sizeof(int))))
801  return NC_ENOMEM;
802 
803  /* Initialize dimids to illegal values (-1). See the comment
804  in nc4_rec_match_dimscales(). */
805  memset(var->dimids, -1, (size_t)ndims * sizeof(int));
806  }
807 
808  return NC_NOERR;
809 }
810 
823 int
824 nc4_var_list_add(NC_GRP_INFO_T* grp, const char* name, int ndims,
825  NC_VAR_INFO_T **var)
826 {
827  int retval;
828 
829  if ((retval = nc4_var_list_add2(grp, name, var)))
830  return retval;
831  if ((retval = nc4_var_set_ndims(*var, ndims)))
832  return retval;
833 
834  return NC_NOERR;
835 }
836 
850 int
851 nc4_dim_list_add(NC_GRP_INFO_T *grp, const char *name, size_t len,
852  int assignedid, NC_DIM_INFO_T **dim)
853 {
854  NC_DIM_INFO_T *new_dim = NULL;
855 
856  assert(grp && name);
857 
858  /* Allocate memory for dim metadata. */
859  if (!(new_dim = calloc(1, sizeof(NC_DIM_INFO_T))))
860  return NC_ENOMEM;
861 
862  new_dim->hdr.sort = NCDIM;
863 
864  /* Assign the dimension ID. */
865  if (assignedid >= 0)
866  new_dim->hdr.id = assignedid;
867  else
868  new_dim->hdr.id = grp->nc4_info->next_dimid++;
869 
870  /* Remember the name and create a hash. */
871  if (!(new_dim->hdr.name = strdup(name))) {
872  if(new_dim)
873  free(new_dim);
874 
875  return NC_ENOMEM;
876  }
877 
878  /* Is dimension unlimited? */
879  new_dim->len = len;
880  if (len == NC_UNLIMITED)
881  new_dim->unlimited = NC_TRUE;
882 
883  /* Remember the containing group. */
884  new_dim->container = grp;
885 
886  /* Add object to dimension list for this group. */
887  ncindexadd(grp->dim, (NC_OBJ *)new_dim);
888  obj_track(grp->nc4_info, (NC_OBJ *)new_dim);
889 
890  /* Set the dim pointer, if one was given */
891  if (dim)
892  *dim = new_dim;
893 
894  return NC_NOERR;
895 }
896 
909 int
910 nc4_att_list_add(NCindex *list, const char *name, NC_ATT_INFO_T **att)
911 {
912  NC_ATT_INFO_T *new_att = NULL;
913 
914  LOG((3, "%s: name %s ", __func__, name));
915 
916  if (!(new_att = calloc(1, sizeof(NC_ATT_INFO_T))))
917  return NC_ENOMEM;
918  new_att->hdr.sort = NCATT;
919 
920  /* Fill in the information we know. */
921  new_att->hdr.id = (int)ncindexsize(list);
922  if (!(new_att->hdr.name = strdup(name))) {
923  if(new_att)
924  free(new_att);
925  return NC_ENOMEM;
926  }
927 
928  /* Add object to list as specified by its number */
929  ncindexadd(list, (NC_OBJ *)new_att);
930 
931  /* Set the attribute pointer, if one was given */
932  if (att)
933  *att = new_att;
934 
935  return NC_NOERR;
936 }
937 
952 int
953 nc4_grp_list_add(NC_FILE_INFO_T *h5, NC_GRP_INFO_T *parent, char *name,
954  NC_GRP_INFO_T **grp)
955 {
956  NC_GRP_INFO_T *new_grp;
957 
958  /* Check inputs. */
959  assert(h5 && name);
960  LOG((3, "%s: name %s ", __func__, name));
961 
962  /* Get the memory to store this groups info. */
963  if (!(new_grp = calloc(1, sizeof(NC_GRP_INFO_T))))
964  return NC_ENOMEM;
965 
966  /* Fill in this group's information. */
967  new_grp->hdr.sort = NCGRP;
968  new_grp->nc4_info = h5;
969  new_grp->parent = parent;
970 
971  /* Assign the group ID. The root group will get id 0. */
972  new_grp->hdr.id = h5->next_nc_grpid++;
973  assert(parent || !new_grp->hdr.id);
974 
975  /* Handle the group name. */
976  if (!(new_grp->hdr.name = strdup(name)))
977  {
978  free(new_grp);
979  return NC_ENOMEM;
980  }
981 
982  /* Set up new indexed lists for stuff this group can contain. */
983  new_grp->children = ncindexnew(0);
984  new_grp->dim = ncindexnew(0);
985  new_grp->att = ncindexnew(0);
986  new_grp->type = ncindexnew(0);
987  new_grp->vars = ncindexnew(0);
988 
989  /* Add object to lists */
990  if (parent)
991  ncindexadd(parent->children, (NC_OBJ *)new_grp);
992  obj_track(h5, (NC_OBJ *)new_grp);
993 
994  /* Set the group pointer, if one was given */
995  if (grp)
996  *grp = new_grp;
997 
998  return NC_NOERR;
999 }
1000 
1014 int
1015 nc4_check_dup_name(NC_GRP_INFO_T *grp, char *name)
1016 {
1017  NC_TYPE_INFO_T *type;
1018  NC_GRP_INFO_T *g;
1019  NC_VAR_INFO_T *var;
1020 
1021  /* Any types of this name? */
1022  type = (NC_TYPE_INFO_T*)ncindexlookup(grp->type,name);
1023  if(type != NULL)
1024  return NC_ENAMEINUSE;
1025 
1026  /* Any child groups of this name? */
1027  g = (NC_GRP_INFO_T*)ncindexlookup(grp->children,name);
1028  if(g != NULL)
1029  return NC_ENAMEINUSE;
1030 
1031  /* Any variables of this name? */
1032  var = (NC_VAR_INFO_T*)ncindexlookup(grp->vars,name);
1033  if(var != NULL)
1034  return NC_ENAMEINUSE;
1035 
1036  return NC_NOERR;
1037 }
1038 
1052 int
1053 nc4_type_new(size_t size, const char *name, int assignedid,
1054  NC_TYPE_INFO_T **type)
1055 {
1056  NC_TYPE_INFO_T *new_type;
1057 
1058  LOG((4, "%s: size %d name %s assignedid %d", __func__, size, name, assignedid));
1059 
1060  /* Check inputs. */
1061  assert(type);
1062 
1063  /* Allocate memory for the type */
1064  if (!(new_type = calloc(1, sizeof(NC_TYPE_INFO_T))))
1065  return NC_ENOMEM;
1066  new_type->hdr.sort = NCTYP;
1067  new_type->hdr.id = assignedid;
1068 
1069  /* Remember info about this type. */
1070  new_type->size = size;
1071  if (!(new_type->hdr.name = strdup(name))) {
1072  free(new_type);
1073  return NC_ENOMEM;
1074  }
1075 
1076  /* Return a pointer to the new type. */
1077  *type = new_type;
1078 
1079  return NC_NOERR;
1080 }
1081 
1095 int
1096 nc4_type_list_add(NC_GRP_INFO_T *grp, size_t size, const char *name,
1097  NC_TYPE_INFO_T **type)
1098 {
1099  NC_TYPE_INFO_T *new_type;
1100  int retval;
1101 
1102  /* Check inputs. */
1103  assert(grp && name && type);
1104  LOG((4, "%s: size %d name %s", __func__, size, name));
1105 
1106  /* Create the new TYPE_INFO struct. */
1107  if ((retval = nc4_type_new(size, name, grp->nc4_info->next_typeid,
1108  &new_type)))
1109  return retval;
1110  grp->nc4_info->next_typeid++;
1111 
1112  /* Increment the ref. count on the type */
1113  new_type->rc++;
1114 
1115  /* Add object to lists */
1116  ncindexadd(grp->type, (NC_OBJ *)new_type);
1117  obj_track(grp->nc4_info,(NC_OBJ*)new_type);
1118 
1119  /* back link */
1120  new_type->container = grp;
1121 
1122  /* Return a pointer to the new type. */
1123  *type = new_type;
1124 
1125  return NC_NOERR;
1126 }
1127 
1141 int
1142 nc4_field_list_add(NC_TYPE_INFO_T *parent, const char *name,
1143  size_t offset, nc_type xtype, int ndims,
1144  const int *dim_sizesp)
1145 {
1146  NC_FIELD_INFO_T *field;
1147 
1148  /* Name has already been checked and UTF8 normalized. */
1149  if (!name)
1150  return NC_EINVAL;
1151 
1152  /* Allocate storage for this field information. */
1153  if (!(field = calloc(1, sizeof(NC_FIELD_INFO_T))))
1154  return NC_ENOMEM;
1155  field->hdr.sort = NCFLD;
1156 
1157  /* Store the information about this field. */
1158  if (!(field->hdr.name = strdup(name)))
1159  {
1160  free(field);
1161  return NC_ENOMEM;
1162  }
1163  field->nc_typeid = xtype;
1164  field->offset = offset;
1165  field->ndims = ndims;
1166  if (ndims)
1167  {
1168  int i;
1169  if (!(field->dim_size = malloc((size_t)ndims * sizeof(int))))
1170  {
1171  free(field->hdr.name);
1172  free(field);
1173  return NC_ENOMEM;
1174  }
1175  for (i = 0; i < ndims; i++)
1176  field->dim_size[i] = dim_sizesp[i];
1177  }
1178 
1179  /* Add object to lists */
1180  field->hdr.id = (int)nclistlength(parent->u.c.field);
1181  nclistpush(parent->u.c.field,field);
1182 
1183  return NC_NOERR;
1184 }
1185 
1198 int
1199 nc4_enum_member_add(NC_TYPE_INFO_T *parent, size_t size,
1200  const char *name, const void *value)
1201 {
1202  NC_ENUM_MEMBER_INFO_T *member;
1203 
1204  /* Name has already been checked. */
1205  assert(name && size > 0 && value);
1206  LOG((4, "%s: size %d name %s", __func__, size, name));
1207 
1208  /* Allocate storage for this field information. */
1209  if (!(member = calloc(1, sizeof(NC_ENUM_MEMBER_INFO_T))))
1210  return NC_ENOMEM;
1211  if (!(member->value = malloc(size))) {
1212  free(member);
1213  return NC_ENOMEM;
1214  }
1215  if (!(member->name = strdup(name))) {
1216  free(member->value);
1217  free(member);
1218  return NC_ENOMEM;
1219  }
1220 
1221  /* Store the value for this member. */
1222  memcpy(member->value, value, size);
1223 
1224  /* Add object to list */
1225  nclistpush(parent->u.e.enum_member,member);
1226 
1227  return NC_NOERR;
1228 }
1229 
1237 static void
1238 field_free(NC_FIELD_INFO_T *field)
1239 {
1240  /* Free some stuff. */
1241  if (field->hdr.name)
1242  free(field->hdr.name);
1243  if (field->dim_size)
1244  free(field->dim_size);
1245 
1246  /* Nc_Free the memory. */
1247  free(field);
1248 }
1249 
1259 int
1260 nc4_type_free(NC_TYPE_INFO_T *type)
1261 {
1262  size_t i;
1263 
1264  assert(type && type->rc && type->hdr.name);
1265 
1266  /* Decrement the ref. count on the type */
1267  type->rc--;
1268 
1269  /* Release the type, if the ref. count drops to zero */
1270  if (type->rc == 0)
1271  {
1272  LOG((4, "%s: deleting type %s", __func__, type->hdr.name));
1273 
1274  /* Free the name. */
1275  free(type->hdr.name);
1276 
1277  /* Enums and compound types have lists of fields to clean up. */
1278  switch (type->nc_type_class)
1279  {
1280  case NC_COMPOUND:
1281  {
1282  NC_FIELD_INFO_T *field;
1283 
1284  /* Delete all the fields in this type (there will be some if its a
1285  * compound). */
1286  for(i=0;i<nclistlength(type->u.c.field);i++) {
1287  field = nclistget(type->u.c.field,i);
1288  field_free(field);
1289  }
1290  nclistfree(type->u.c.field);
1291  }
1292  break;
1293 
1294  case NC_ENUM:
1295  {
1296  NC_ENUM_MEMBER_INFO_T *enum_member;
1297 
1298  /* Delete all the enum_members, if any. */
1299  for(i=0;i<nclistlength(type->u.e.enum_member);i++) {
1300  enum_member = nclistget(type->u.e.enum_member,i);
1301  free(enum_member->value);
1302  free(enum_member->name);
1303  free(enum_member);
1304  }
1305  nclistfree(type->u.e.enum_member);
1306  }
1307  break;
1308 
1309  default:
1310  break;
1311  }
1312 
1313  /* Release the memory. */
1314  free(type);
1315  }
1316 
1317  return NC_NOERR;
1318 }
1319 
1328 int
1329 nc4_att_free(NC_ATT_INFO_T *att)
1330 {
1331  int stat = NC_NOERR;
1332 
1333  assert(att);
1334  LOG((3, "%s: name %s ", __func__, att->hdr.name));
1335 
1336  /* Free the name. */
1337  if (att->hdr.name)
1338  free(att->hdr.name);
1339 
1340  if (att->data) {
1341  NC_OBJ* parent;
1342  NC_FILE_INFO_T* h5 = NULL;
1343 
1344  /* Locate relevant objects */
1345  parent = att->container;
1346  if(parent->sort == NCVAR) parent = (NC_OBJ*)(((NC_VAR_INFO_T*)parent)->container);
1347  assert(parent->sort == NCGRP);
1348  h5 = ((NC_GRP_INFO_T*)parent)->nc4_info;
1349  /* Reclaim the attribute data */
1350  if((stat = NC_reclaim_data(h5->controller,att->nc_typeid,att->data,att->len))) goto done;
1351  free(att->data); /* reclaim top level */
1352  att->data = NULL;
1353  }
1354 
1355 done:
1356  free(att);
1357  return stat;
1358 }
1359 
1369 static int
1370 var_free(NC_VAR_INFO_T *var)
1371 {
1372  int retval;
1373 
1374  assert(var);
1375  LOG((4, "%s: deleting var %s", __func__, var->hdr.name));
1376 
1377  /* First delete all the attributes attached to this var. */
1378  for (size_t i = 0; i < ncindexsize(var->att); i++)
1379  if ((retval = nc4_att_free((NC_ATT_INFO_T *)ncindexith(var->att, i))))
1380  return retval;
1381  ncindexfree(var->att);
1382 
1383  /* Free some things that may be allocated. */
1384  if (var->chunksizes)
1385  free(var->chunksizes);
1386 
1387  if (var->alt_name)
1388  free(var->alt_name);
1389 
1390  if (var->dimids)
1391  free(var->dimids);
1392 
1393  if (var->dim)
1394  free(var->dim);
1395 
1396  /* Delete any fill value allocation. */
1397  if (var->fill_value) {
1398  int tid = var->type_info->hdr.id;
1399  if((retval = NC_reclaim_data_all(var->container->nc4_info->controller, tid, var->fill_value, 1))) return retval;
1400  var->fill_value = NULL;
1401  }
1402 
1403  /* Release type information */
1404  if (var->type_info)
1405  if ((retval = nc4_type_free(var->type_info)))
1406  return retval;
1407 
1408  /* Do this last because debugging may need it */
1409  if (var->hdr.name)
1410  free(var->hdr.name);
1411 
1412  /* Delete the var. */
1413  free(var);
1414 
1415  return NC_NOERR;
1416 }
1417 
1427 int
1428 nc4_var_list_del(NC_GRP_INFO_T *grp, NC_VAR_INFO_T *var)
1429 {
1430  int i;
1431 
1432  assert(var && grp);
1433 
1434  /* Remove from lists */
1435  i = ncindexfind(grp->vars, (NC_OBJ *)var);
1436  if (i >= 0)
1437  ncindexidel(grp->vars, (size_t)i);
1438 
1439  return var_free(var);
1440 }
1441 
1450 static int
1451 dim_free(NC_DIM_INFO_T *dim)
1452 {
1453  assert(dim);
1454  LOG((4, "%s: deleting dim %s", __func__, dim->hdr.name));
1455 
1456  /* Free memory allocated for names. */
1457  if (dim->hdr.name)
1458  free(dim->hdr.name);
1459 
1460  free(dim);
1461  return NC_NOERR;
1462 }
1463 
1473 int
1474 nc4_dim_list_del(NC_GRP_INFO_T *grp, NC_DIM_INFO_T *dim)
1475 {
1476  if (grp && dim)
1477  {
1478  int pos = ncindexfind(grp->dim, (NC_OBJ *)dim);
1479  if(pos >= 0)
1480  ncindexidel(grp->dim, (size_t)pos);
1481  }
1482 
1483  return dim_free(dim);
1484 }
1485 
1495 int
1496 nc4_rec_grp_del(NC_GRP_INFO_T *grp)
1497 {
1498  int retval;
1499 
1500  assert(grp);
1501  LOG((3, "%s: grp->name %s", __func__, grp->hdr.name));
1502 
1503  /* Recursively call this function for each child, if any, stopping
1504  * if there is an error. */
1505  for (size_t i = 0; i < ncindexsize(grp->children); i++)
1506  if ((retval = nc4_rec_grp_del((NC_GRP_INFO_T *)ncindexith(grp->children,
1507  i))))
1508  return retval;
1509  ncindexfree(grp->children);
1510 
1511  /* Free attributes */
1512  for (size_t i = 0; i < ncindexsize(grp->att); i++)
1513  if ((retval = nc4_att_free((NC_ATT_INFO_T *)ncindexith(grp->att, i))))
1514  return retval;
1515  ncindexfree(grp->att);
1516 
1517  /* Delete all vars. */
1518  for (size_t i = 0; i < ncindexsize(grp->vars); i++) {
1519  NC_VAR_INFO_T* v = (NC_VAR_INFO_T *)ncindexith(grp->vars, i);
1520  if ((retval = var_free(v)))
1521  return retval;
1522  }
1523  ncindexfree(grp->vars);
1524 
1525  /* Delete all dims, and free the list of dims. */
1526  for (size_t i = 0; i < ncindexsize(grp->dim); i++)
1527  if ((retval = dim_free((NC_DIM_INFO_T *)ncindexith(grp->dim, i))))
1528  return retval;
1529  ncindexfree(grp->dim);
1530 
1531  /* Delete all types. */
1532  for (size_t i = 0; i < ncindexsize(grp->type); i++)
1533  if ((retval = nc4_type_free((NC_TYPE_INFO_T *)ncindexith(grp->type, i))))
1534  return retval;
1535  ncindexfree(grp->type);
1536 
1537  /* Free the name. */
1538  free(grp->hdr.name);
1539 
1540  /* Free up this group */
1541  free(grp);
1542 
1543  return NC_NOERR;
1544 }
1545 
1555 int
1556 nc4_rec_grp_del_att_data(NC_GRP_INFO_T *grp)
1557 {
1558  int retval;
1559 
1560  assert(grp);
1561  LOG((3, "%s: grp->name %s", __func__, grp->hdr.name));
1562 
1563  /* Recursively call this function for each child, if any, stopping
1564  * if there is an error. */
1565  for (size_t i = 0; i < ncindexsize(grp->children); i++)
1566  if ((retval = nc4_rec_grp_del_att_data((NC_GRP_INFO_T *)ncindexith(grp->children, i))))
1567  return retval;
1568 
1569  /* Free attribute data in this group */
1570  for (size_t i = 0; i < ncindexsize(grp->att); i++) {
1571  NC_ATT_INFO_T * att = (NC_ATT_INFO_T*)ncindexith(grp->att, i);
1572  if((retval = NC_reclaim_data_all(grp->nc4_info->controller,att->nc_typeid,att->data,att->len)))
1573  return retval;
1574  att->data = NULL;
1575  att->len = 0;
1576  att->dirty = 0;
1577  }
1578 
1579  /* Delete att data from all contained vars in this group */
1580  for (size_t i = 0; i < ncindexsize(grp->vars); i++) {
1581  NC_VAR_INFO_T* v = (NC_VAR_INFO_T *)ncindexith(grp->vars, i);
1582  for(size_t j=0;j<ncindexsize(v->att);j++) {
1583  NC_ATT_INFO_T* att = (NC_ATT_INFO_T*)ncindexith(v->att, j);
1584  if((retval = NC_reclaim_data_all(grp->nc4_info->controller,att->nc_typeid,att->data,att->len)))
1585  return retval;
1586  att->data = NULL;
1587  att->len = 0;
1588  att->dirty = 0;
1589  }
1590  }
1591 
1592  return NC_NOERR;
1593 }
1594 
1605 int
1606 nc4_att_list_del(NCindex *list, NC_ATT_INFO_T *att)
1607 {
1608  assert(att && list);
1609  ncindexidel(list, (size_t)((NC_OBJ *)att)->id);
1610  return nc4_att_free(att);
1611 }
1612 
1626 int
1627 nc4_file_list_del(int ncid)
1628 {
1629  NC_FILE_INFO_T *h5;
1630  int retval;
1631 
1632  /* Find our metadata for this file. */
1633  if ((retval = nc4_find_grp_h5(ncid, NULL, &h5)))
1634  return retval;
1635  assert(h5);
1636 
1637  /* Delete the file resources. */
1638  if ((retval = nc4_nc4f_list_del(h5)))
1639  return retval;
1640 
1641  return NC_NOERR;
1642 }
1643 
1653 int
1654 nc4_nc4f_list_del(NC_FILE_INFO_T *h5)
1655 {
1656  int retval;
1657 
1658  assert(h5);
1659 
1660  /* Order is important here. We must delete the attribute contents
1661  before deleteing any metadata because nc_reclaim_data depends
1662  on the existence of the type info.
1663  */
1664 
1665  /* Delete all the attribute data contents in each group and variable. */
1666  if ((retval = nc4_rec_grp_del_att_data(h5->root_grp)))
1667  return retval;
1668 
1669  /* Delete all the list contents for vars, dims, and atts, in each
1670  * group. */
1671  if ((retval = nc4_rec_grp_del(h5->root_grp)))
1672  return retval;
1673 
1674  /* Cleanup these (extra) lists of all dims, groups, and types. */
1675  nclistfree(h5->alldims);
1676  nclistfree(h5->allgroups);
1677  nclistfree(h5->alltypes);
1678 
1679  /* Free the NC_FILE_INFO_T struct. */
1680  nullfree(h5->hdr.name);
1681  free(h5);
1682 
1683  return NC_NOERR;
1684 }
1685 
1699 int
1700 nc4_normalize_name(const char *name, char *norm_name)
1701 {
1702  char *temp_name;
1703  int stat = nc_utf8_normalize((const unsigned char *)name,(unsigned char **)&temp_name);
1704  if(stat != NC_NOERR)
1705  return stat;
1706  if (strlen(temp_name) > NC_MAX_NAME)
1707  {
1708  free(temp_name);
1709  return NC_EMAXNAME;
1710  }
1711  strcpy(norm_name, temp_name);
1712  free(temp_name);
1713  return NC_NOERR;
1714 }
1715 
1716 #ifdef NETCDF_ENABLE_SET_LOG_LEVEL
1717 
1724 int
1725 nc4_init_logging(void)
1726 {
1727  int ret = NC_NOERR;
1728 
1729 #if LOGGING
1730 #if NC_HAS_PARALLEL4
1731  if (!LOG_FILE && nc_log_level >= 0)
1732  {
1733  char log_filename[NC_MAX_NAME];
1734  int my_rank = 0;
1735  int mpierr;
1736  int mpi_initialized;
1737 
1738  /* If MPI has been initialized find the rank. */
1739  if ((mpierr = MPI_Initialized(&mpi_initialized)))
1740  return NC_EMPI;
1741  if (mpi_initialized)
1742  {
1743  if ((mpierr = MPI_Comm_rank(MPI_COMM_WORLD, &my_rank)))
1744  return NC_EMPI;
1745  }
1746 
1747  /* Create a filename with the rank in it. */
1748  snprintf(log_filename, sizeof(log_filename), "nc4_log_%d.log", my_rank);
1749 
1750  /* Open a file for this rank to log messages. */
1751  if (!(LOG_FILE = fopen(log_filename, "w")))
1752  return NC_EINTERNAL;
1753  }
1754 #endif /* NC_HAS_PARALLEL4 */
1755 #endif /* LOGGING */
1756 
1757  return ret;
1758 }
1759 
1766 void
1767 nc4_finalize_logging(void)
1768 {
1769 #if LOGGING
1770 #if NC_HAS_PARALLEL4
1771  if (LOG_FILE)
1772  {
1773  fclose(LOG_FILE);
1774  LOG_FILE = NULL;
1775  }
1776 #endif /* NC_HAS_PARALLEL4 */
1777 #endif /* LOGGING */
1778 }
1779 
1793 int
1794 nc_set_log_level(int new_level)
1795 {
1796 #if LOGGING
1797  /* Remember the new level. */
1798  nc_log_level = new_level;
1799 
1800 #if NC_HAS_PARALLEL4
1801  /* For parallel I/O builds, call the log init/finalize functions
1802  * as needed, to open and close the log files. */
1803  if (new_level >= 0)
1804  {
1805  if (!LOG_FILE)
1806  nc4_init_logging();
1807  }
1808  else
1809  nc4_finalize_logging();
1810 #endif /* NC_HAS_PARALLEL4 */
1811 
1812  LOG((1, "log_level changed to %d", nc_log_level));
1813 #endif /* LOGGING */
1814 
1815  return NC_NOERR;
1816 }
1817 #endif /* NETCDF_ENABLE_SET_LOG_LEVEL */
1818 
1819 #if LOGGING
1820 #define MAX_NESTS 10
1821 
1830 static int
1831 rec_print_metadata(NC_GRP_INFO_T *grp, int tab_count)
1832 {
1833  NC_ATT_INFO_T *att;
1834  NC_VAR_INFO_T *var;
1835  NC_DIM_INFO_T *dim;
1836  NC_TYPE_INFO_T *type;
1837  NC_FIELD_INFO_T *field;
1838  char tabs[MAX_NESTS+1] = "";
1839  char temp_string[10];
1840  int t, retval, d, i;
1841 
1842  /* Come up with a number of tabs relative to the group. */
1843  for (t = 0; t < tab_count && t < MAX_NESTS; t++)
1844  tabs[t] = '\t';
1845  tabs[t] = '\0';
1846 
1847  LOG((2, "%s GROUP - %s nc_grpid: %d nvars: %d natts: %d",
1848  tabs, grp->hdr.name, grp->hdr.id, ncindexsize(grp->vars), ncindexsize(grp->att)));
1849 
1850  for (i = 0; i < ncindexsize(grp->att); i++)
1851  {
1852  att = (NC_ATT_INFO_T *)ncindexith(grp->att, i);
1853  assert(att);
1854  LOG((2, "%s GROUP ATTRIBUTE - attnum: %d name: %s type: %d len: %d",
1855  tabs, att->hdr.id, att->hdr.name, att->nc_typeid, att->len));
1856  }
1857 
1858  for (i = 0; i < ncindexsize(grp->dim); i++)
1859  {
1860  dim = (NC_DIM_INFO_T *)ncindexith(grp->dim, i);
1861  assert(dim);
1862  LOG((2, "%s DIMENSION - dimid: %d name: %s len: %d unlimited: %d",
1863  tabs, dim->hdr.id, dim->hdr.name, dim->len, dim->unlimited));
1864  }
1865 
1866  for (i = 0; i < ncindexsize(grp->vars); i++)
1867  {
1868  int j;
1869  char storage_str[NC_MAX_NAME] = "";
1870  char *dims_string = NULL;
1871 
1872  var = (NC_VAR_INFO_T*)ncindexith(grp->vars,i);
1873  assert(var);
1874  if (var->ndims > 0)
1875  {
1876  if (!(dims_string = malloc(sizeof(char) * var->ndims * 4)))
1877  return NC_ENOMEM;
1878  strcpy(dims_string, "");
1879  for (d = 0; d < var->ndims; d++)
1880  {
1881  snprintf(temp_string, sizeof(temp_string), " %d", var->dimids[d]);
1882  strcat(dims_string, temp_string);
1883  }
1884  }
1885  if (!var->meta_read)
1886  strcat(storage_str, "unknown");
1887  else if (var->storage == NC_CONTIGUOUS)
1888  strcat(storage_str, "contiguous");
1889  else if (var->storage == NC_COMPACT)
1890  strcat(storage_str, "compact");
1891  else if (var->storage == NC_CHUNKED)
1892  strcat(storage_str, "chunked");
1893  else if (var->storage == NC_VIRTUAL)
1894  strcat(storage_str, "virtual");
1895  else
1896  strcat(storage_str, "unknown");
1897  LOG((2, "%s VARIABLE - varid: %d name: %s ndims: %d "
1898  "dimids:%s storage: %s", tabs, var->hdr.id, var->hdr.name,
1899  var->ndims,
1900  (dims_string ? dims_string : " -"), storage_str));
1901  for (j = 0; j < ncindexsize(var->att); j++)
1902  {
1903  att = (NC_ATT_INFO_T *)ncindexith(var->att, j);
1904  assert(att);
1905  LOG((2, "%s VAR ATTRIBUTE - attnum: %d name: %s type: %d len: %d",
1906  tabs, att->hdr.id, att->hdr.name, att->nc_typeid, att->len));
1907  }
1908  if (dims_string)
1909  free(dims_string);
1910  }
1911 
1912  for (i = 0; i < ncindexsize(grp->type); i++)
1913  {
1914  type = (NC_TYPE_INFO_T*)ncindexith(grp->type, i);
1915  assert(type);
1916  LOG((2, "%s TYPE - nc_typeid: %d size: %d committed: %d name: %s",
1917  tabs, type->hdr.id, type->size, (int)type->committed, type->hdr.name));
1918  /* Is this a compound type? */
1919  if (type->nc_type_class == NC_COMPOUND)
1920  {
1921  int j;
1922  LOG((3, "compound type"));
1923  for (j = 0; j < nclistlength(type->u.c.field); j++)
1924  {
1925  field = (NC_FIELD_INFO_T *)nclistget(type->u.c.field, j);
1926  LOG((4, "field %s offset %d nctype %d ndims %d", field->hdr.name,
1927  field->offset, field->nc_typeid, field->ndims));
1928  }
1929  }
1930  else if (type->nc_type_class == NC_VLEN)
1931  {
1932  LOG((3, "VLEN type"));
1933  LOG((4, "base_nc_type: %d", type->u.v.base_nc_typeid));
1934  }
1935  else if (type->nc_type_class == NC_OPAQUE)
1936  LOG((3, "Opaque type"));
1937  else if (type->nc_type_class == NC_ENUM)
1938  {
1939  LOG((3, "Enum type"));
1940  LOG((4, "base_nc_type: %d", type->u.e.base_nc_typeid));
1941  }
1942  else
1943  {
1944  LOG((0, "Unknown class: %d", type->nc_type_class));
1945  return NC_EBADTYPE;
1946  }
1947  }
1948 
1949  /* Call self for each child of this group. */
1950  for (i = 0; i < ncindexsize(grp->children); i++)
1951  if ((retval = rec_print_metadata((NC_GRP_INFO_T *)ncindexith(grp->children, i),
1952  tab_count + 1)))
1953  return retval;
1954 
1955  return NC_NOERR;
1956 }
1957 
1968 int
1969 log_metadata_nc(NC_FILE_INFO_T *h5)
1970 {
1971  LOG((2, "*** NetCDF-4 Internal Metadata: int_ncid 0x%x ext_ncid 0x%x",
1972  h5->root_grp->nc4_info->controller->int_ncid,
1973  h5->root_grp->nc4_info->controller->ext_ncid));
1974  if (!h5)
1975  {
1976  LOG((2, "This is a netCDF-3 file."));
1977  return NC_NOERR;
1978  }
1979  LOG((2, "FILE - path: %s cmode: 0x%x parallel: %d redef: %d "
1980  "fill_mode: %d no_write: %d next_nc_grpid: %d", h5->root_grp->nc4_info->controller->path,
1981  h5->cmode, (int)h5->parallel, (int)h5->redef, h5->fill_mode, (int)h5->no_write,
1982  h5->next_nc_grpid));
1983  if(nc_log_level >= 2)
1984  return rec_print_metadata(h5->root_grp, 0);
1985  return NC_NOERR;
1986 }
1987 
1988 #endif /*LOGGING */
1989 
2001 int
2002 NC4_show_metadata(int ncid)
2003 {
2004  int retval = NC_NOERR;
2005 #if LOGGING
2006  NC_FILE_INFO_T *h5;
2007  int old_log_level = nc_log_level;
2008 
2009  /* Find file metadata. */
2010  if ((retval = nc4_find_grp_h5(ncid, NULL, &h5)))
2011  return retval;
2012 
2013  /* Log level must be 2 to see metadata. */
2014  nc_log_level = 2;
2015  retval = log_metadata_nc(h5);
2016  nc_log_level = old_log_level;
2017 #endif /*LOGGING*/
2018  return retval;
2019 }
2020 
2028 const NC_reservedatt*
2029 NC_findreserved(const char* name)
2030 {
2031 #if 0
2032  int n = NRESERVED;
2033  int L = 0;
2034  int R = (n - 1);
2035 
2036  for(;;) {
2037  if(L > R) break;
2038  int m = (L + R) / 2;
2039  const NC_reservedatt* p = &NC_reserved[m];
2040  int cmp = strcmp(p->name,name);
2041  if(cmp == 0) return p;
2042  if(cmp < 0)
2043  L = (m + 1);
2044  else /*cmp > 0*/
2045  R = (m - 1);
2046  }
2047  return NULL;
2048 #else
2049  return (const NC_reservedatt*)bsearch(name,NC_reserved,NRESERVED,sizeof(NC_reservedatt),bincmp);
2050 #endif
2051 }
2052 
2053 /* Ed Hartness requires this function */
2054 static int
2055 NC4_move_in_NCList(NC* nc, int new_id)
2056 {
2057  int stat = move_in_NCList(nc,new_id);
2058  if(stat == NC_NOERR) {
2059  /* Synchronize header */
2060  if(nc->dispatchdata)
2061  ((NC_OBJ*)nc->dispatchdata)->id = nc->ext_ncid;
2062  }
2063  return stat;
2064 }
2065 
2066 static int
2067 sortcmp(const void* arg1, const void* arg2)
2068 {
2069  NC_reservedatt* r1 = (NC_reservedatt*)arg1;
2070  NC_reservedatt* r2 = (NC_reservedatt*)arg2;
2071  return strcmp(r1->name,r2->name);
2072 }
2073 
2074 static int
2075 bincmp(const void* arg1, const void* arg2)
2076 {
2077  const char* name = (const char*)arg1;
2078  NC_reservedatt* ra = (NC_reservedatt*)arg2;
2079  return strcmp(name,ra->name);
2080 }
2081 
2082 void
2083 NC_initialize_reserved(void)
2084 {
2085  /* Guarantee the reserved attribute list is sorted */
2086  qsort((void*)NC_reserved,NRESERVED,sizeof(NC_reservedatt),sortcmp);
2087 }
#define NC_ENOMEM
Memory allocation (malloc) failure.
Definition: netcdf.h:458
#define NC_CHUNKED
In HDF5 files you can set storage for each variable to be either contiguous or chunked, with nc_def_var_chunking().
Definition: netcdf.h:314
#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:315
#define NC_OPAQUE
opaque types
Definition: netcdf.h:54
Main header file for the C API.
#define NC_EINTERNAL
NetCDF Library Internal Error.
Definition: netcdf.h:484
#define NC_STRING
string
Definition: netcdf.h:47
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:421
#define NC_EIO
Generic IO error.
Definition: netcdf.h:467
#define NC_ENAMEINUSE
String match to name in use.
Definition: netcdf.h:417
#define NC_VLEN
vlen (variable-length) types
Definition: netcdf.h:53
#define NC_EMPI
MPI operation failed.
Definition: netcdf.h:521
#define NC_EBADTYPE
Not a netcdf data type.
Definition: netcdf.h:420
#define NC_VIRTUAL
In HDF5 files you can set storage for each variable to be either contiguous or chunked, with nc_def_var_chunking().
Definition: netcdf.h:318
#define NC_EINVAL
Invalid Argument.
Definition: netcdf.h:388
#define NC_MAX_NAME
Maximum for classic library.
Definition: netcdf.h:291
#define NC_EBADTYPID
Bad type ID.
Definition: netcdf.h:507
#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:316
#define NC_EBADID
Not a netcdf id.
Definition: netcdf.h:385
#define NC_UNLIMITED
Size argument to nc_def_dim() for an unlimited dimension.
Definition: netcdf.h:261
#define NC_ENOTVAR
Variable not found.
Definition: netcdf.h:432
#define NC_EMAXNAME
NC_MAX_NAME exceeded.
Definition: netcdf.h:436
#define NC_NOERR
No Error.
Definition: netcdf.h:378
#define NC_ENUM
enum types
Definition: netcdf.h:55
#define NC_COMPOUND
compound types
Definition: netcdf.h:56
#define NC_GLOBAL
Attribute id to put/get a global attribute.
Definition: netcdf.h:264
#define NC_ENOTATT
Attribute not found.
Definition: netcdf.h:418