NetCDF  4.9.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 "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 "ncrc.h"
28 
39 static const NC_reservedatt NC_reserved[] = {
40  {NC_ATT_CLASS, READONLYFLAG|HIDDENATTRFLAG}, /*CLASS*/
41  {NC_ATT_DIMENSION_LIST, READONLYFLAG|HIDDENATTRFLAG}, /*DIMENSION_LIST*/
42  {NC_ATT_NAME, READONLYFLAG|HIDDENATTRFLAG}, /*NAME*/
43  {NC_ATT_REFERENCE_LIST, READONLYFLAG|HIDDENATTRFLAG}, /*REFERENCE_LIST*/
44  {NC_XARRAY_DIMS, READONLYFLAG|HIDDENATTRFLAG}, /*_ARRAY_DIMENSIONS*/
45  {NC_ATT_CODECS, VARFLAG|READONLYFLAG|NAMEONLYFLAG|HIDDENATTRFLAG}, /*_Codecs*/
46  {NC_ATT_FORMAT, READONLYFLAG}, /*_Format*/
47  {ISNETCDF4ATT, READONLYFLAG|NAMEONLYFLAG}, /*_IsNetcdf4*/
48  {NCPROPS, READONLYFLAG|NAMEONLYFLAG|MATERIALIZEDFLAG}, /*_NCProperties*/
49  {NC_NCZARR_ATTR, READONLYFLAG|HIDDENATTRFLAG}, /*_NCZARR_ATTR*/
50  {NC_ATT_COORDINATES, READONLYFLAG|HIDDENATTRFLAG|MATERIALIZEDFLAG}, /*_Netcdf4Coordinates*/
51  {NC_ATT_DIMID_NAME, READONLYFLAG|HIDDENATTRFLAG|MATERIALIZEDFLAG}, /*_Netcdf4Dimid*/
52  {SUPERBLOCKATT, READONLYFLAG|NAMEONLYFLAG}, /*_SuperblockVersion*/
53  {NC_ATT_NC3_STRICT_NAME, READONLYFLAG|MATERIALIZEDFLAG}, /*_nc3_strict*/
54 };
55 #define NRESERVED (sizeof(NC_reserved) / sizeof(NC_reservedatt)) /*|NC_reservedatt|*/
56 
57 static int NC4_move_in_NCList(NC* nc, int new_id);
58 
59 #if NC_HAS_LOGGING
60 /* This is the severity level of messages which will be logged. Use
61  severity 0 for errors, 1 for important log messages, 2 for less
62  important, etc. */
63 int nc_log_level = NC_TURN_OFF_LOGGING;
64 #if NC_HAS_PARALLEL4
65 /* File pointer for the parallel I/O log file. */
66 FILE *LOG_FILE = NULL;
67 #endif /* NC_HAS_PARALLEL4 */
68 
69 /* This function prints out a message, if the severity of
70  * the message is lower than the global nc_log_level. To use it, do
71  * something like this:
72  *
73  * nc_log(0, "this computer will explode in %d seconds", i);
74  *
75  * After the first arg (the severity), use the rest like a normal
76  * printf statement. Output will appear on stderr for sequential
77  * builds, and in a file nc4_log_R.log for each process for a parallel
78  * build, where R is the rank of the process.
79  *
80  * Ed Hartnett
81  */
82 void
83 nc_log(int severity, const char *fmt, ...)
84 {
85  va_list argp;
86  int t;
87  FILE *f = stderr;
88 
89  /* If the severity is greater than the log level, we don't print
90  * this message. */
91  if (severity > nc_log_level)
92  return;
93 
94 #if NC_HAS_PARALLEL4
95  /* For parallel I/O build, if MPI has been initialized, instead of
96  * printing logging output to stderr, it goes to a file for each
97  * process. */
98  {
99  int mpi_initialized;
100  int mpierr;
101 
102  /* Check to see if MPI has been initialized. */
103  if ((mpierr = MPI_Initialized(&mpi_initialized)))
104  return;
105 
106  /* If MPI has been initialized use a log file. */
107  assert(LOG_FILE);
108  if (mpi_initialized)
109  f = LOG_FILE;
110  }
111 #endif /* NC_HAS_PARALLEL4 */
112 
113  /* If the severity is zero, this is an error. Otherwise insert that
114  many tabs before the message. */
115  if (!severity)
116  fprintf(f, "ERROR: ");
117  for (t = 0; t < severity; t++)
118  fprintf(f, "\t");
119 
120  /* Print out the variable list of args with vprintf. */
121  va_start(argp, fmt);
122  vfprintf(f, fmt, argp);
123  va_end(argp);
124 
125  /* Put on a final linefeed. */
126  fprintf(f, "\n");
127  fflush(f);
128 }
129 #endif /* NC_HAS_LOGGING */
130 
143 int
144 nc4_check_name(const char *name, char *norm_name)
145 {
146  char *temp;
147  int retval;
148 
149  assert(norm_name);
150 
151  /* Check for NULL. */
152  if (!name)
153  return NC_EINVAL;
154 
155  /* Make sure this is a valid netcdf name. This should be done
156  * before the name is normalized, because it gives better error
157  * codes for bad utf8 strings. */
158  if ((retval = NC_check_name(name)))
159  return retval;
160 
161  /* Normalize the name. */
162  if ((retval = nc_utf8_normalize((const unsigned char *)name,
163  (unsigned char **)&temp)))
164  return retval;
165 
166  /* Check length of normalized name. */
167  if (strlen(temp) > NC_MAX_NAME)
168  {
169  free(temp);
170  return NC_EMAXNAME;
171  }
172 
173  /* Copy the normalized name. */
174  strcpy(norm_name, temp);
175  free(temp);
176 
177  return NC_NOERR;
178 }
179 
200 int
201 nc4_file_list_add(int ncid, const char *path, int mode, void **dispatchdata)
202 {
203  NC *nc;
204  int ret;
205 
206  /* Find NC pointer for this file. */
207  if ((ret = NC_check_id(ncid, &nc)))
208  return ret;
209 
210  /* Add necessary structs to hold netcdf-4 file data. This is where
211  * the NC_FILE_INFO_T struct is allocated for the file. */
212  if ((ret = nc4_nc4f_list_add(nc, path, mode)))
213  return ret;
214 
215  /* If the user wants a pointer to the NC_FILE_INFO_T, then provide
216  * it. */
217  if (dispatchdata)
218  *dispatchdata = nc->dispatchdata;
219 
220  return NC_NOERR;
221 }
222 
236 int
237 nc4_file_change_ncid(int ncid, unsigned short new_ncid_index)
238 {
239  NC *nc;
240  int ret;
241 
242  LOG((2, "%s: ncid %d new_ncid_index %d", __func__, ncid, new_ncid_index));
243 
244  /* Find NC pointer for this file. */
245  if ((ret = NC_check_id(ncid, &nc)))
246  return ret;
247 
248  /* Move it in the list. It will faile if list spot is already
249  * occupied. */
250  LOG((3, "moving nc->ext_ncid %d nc->ext_ncid >> ID_SHIFT %d",
251  nc->ext_ncid, nc->ext_ncid >> ID_SHIFT));
252  if (NC4_move_in_NCList(nc, new_ncid_index))
253  return NC_EIO;
254  LOG((3, "moved to new_ncid_index %d new nc->ext_ncid %d", new_ncid_index,
255  nc->ext_ncid));
256 
257  return NC_NOERR;
258 }
259 
279 int
280 nc4_file_list_get(int ncid, char **path, int *mode, void **dispatchdata)
281 {
282  NC *nc;
283  int ret;
284 
285  /* Find NC pointer for this file. */
286  if ((ret = NC_check_id(ncid, &nc)))
287  return ret;
288 
289  /* If the user wants path, give it. */
290  if (path)
291  strncpy(*path, nc->path, NC_MAX_NAME);
292 
293  /* If the user wants mode, give it. */
294  if (mode)
295  *mode = nc->mode;
296 
297  /* If the user wants dispatchdata, give it. */
298  if (dispatchdata)
299  *dispatchdata = nc->dispatchdata;
300 
301  return NC_NOERR;
302 }
303 
318 int
319 nc4_nc4f_list_add(NC *nc, const char *path, int mode)
320 {
321  NC_FILE_INFO_T *h5;
322  int retval;
323 
324  assert(nc && !NC4_DATA(nc) && path);
325 
326  /* We need to malloc and initialize the substructure
327  NC_FILE_INFO_T. */
328  if (!(h5 = calloc(1, sizeof(NC_FILE_INFO_T))))
329  return NC_ENOMEM;
330  nc->dispatchdata = h5;
331  h5->controller = nc;
332 
333  h5->hdr.sort = NCFIL;
334  h5->hdr.name = strdup(path);
335  h5->hdr.id = nc->ext_ncid;
336 
337  /* Hang on to cmode, and note that we're in define mode. */
338  h5->cmode = mode | NC_INDEF;
339 
340  /* The next_typeid needs to be set beyond the end of our atomic
341  * types. */
342  h5->next_typeid = NC_FIRSTUSERTYPEID;
343 
344  /* Initialize lists for dimensions, types, and groups. */
345  h5->alldims = nclistnew();
346  h5->alltypes = nclistnew();
347  h5->allgroups = nclistnew();
348 
349  /* There's always at least one open group - the root
350  * group. Allocate space for one group's worth of information. Set
351  * its grp id, name, and allocate associated empty lists. */
352  if ((retval = nc4_grp_list_add(h5, NULL, NC_GROUP_NAME, &h5->root_grp)))
353  return retval;
354 
355  return NC_NOERR;
356 }
357 
370 int
371 nc4_find_nc4_grp(int ncid, NC_GRP_INFO_T **grp)
372 {
373  return nc4_find_nc_grp_h5(ncid, NULL, grp, NULL);
374 }
375 
391 int
392 nc4_find_grp_h5(int ncid, NC_GRP_INFO_T **grp, NC_FILE_INFO_T **h5)
393 {
394  return nc4_find_nc_grp_h5(ncid, NULL, grp, h5);
395 }
396 
411 int
412 nc4_find_nc_grp_h5(int ncid, NC **nc, NC_GRP_INFO_T **grp, NC_FILE_INFO_T **h5)
413 {
414  NC_GRP_INFO_T *my_grp = NULL;
415  NC_FILE_INFO_T *my_h5 = NULL;
416  NC *my_nc;
417  int retval;
418  size_t index;
419 
420  /* Look up file metadata. */
421  if ((retval = NC_check_id(ncid, &my_nc)))
422  return retval;
423  my_h5 = my_nc->dispatchdata;
424  assert(my_h5 && my_h5->root_grp);
425 
426  /* If we can't find it, the grp id part of ncid is bad. */
427  index = (ncid & GRP_ID_MASK);
428  if (!(my_grp = nclistget(my_h5->allgroups,index)))
429  return NC_EBADID;
430 
431  /* Return pointers to caller, if desired. */
432  if (nc)
433  *nc = my_nc;
434  if (h5)
435  *h5 = my_h5;
436  if (grp)
437  *grp = my_grp;
438 
439  return NC_NOERR;
440 }
441 
457 int
458 nc4_find_grp_h5_var(int ncid, int varid, NC_FILE_INFO_T **h5, NC_GRP_INFO_T **grp,
459  NC_VAR_INFO_T **var)
460 {
461  NC_FILE_INFO_T *my_h5;
462  NC_GRP_INFO_T *my_grp;
463  NC_VAR_INFO_T *my_var;
464  int retval;
465 
466  /* Look up file and group metadata. */
467  if ((retval = nc4_find_grp_h5(ncid, &my_grp, &my_h5)))
468  return retval;
469  assert(my_grp && my_h5);
470 
471  /* Find the var. */
472  if (!(my_var = (NC_VAR_INFO_T *)ncindexith(my_grp->vars, varid)))
473  return NC_ENOTVAR;
474  assert(my_var && my_var->hdr.id == varid);
475 
476  /* Return pointers that caller wants. */
477  if (h5)
478  *h5 = my_h5;
479  if (grp)
480  *grp = my_grp;
481  if (var)
482  *var = my_var;
483 
484  return NC_NOERR;
485 }
486 
500 int
501 nc4_find_dim(NC_GRP_INFO_T *grp, int dimid, NC_DIM_INFO_T **dim,
502  NC_GRP_INFO_T **dim_grp)
503 {
504  assert(grp && grp->nc4_info && dim);
505  LOG((4, "%s: dimid %d", __func__, dimid));
506 
507  /* Find the dim info. */
508  if (!((*dim) = nclistget(grp->nc4_info->alldims, dimid)))
509  return NC_EBADDIM;
510 
511  /* Give the caller the group the dimension is in. */
512  if (dim_grp)
513  *dim_grp = (*dim)->container;
514 
515  return NC_NOERR;
516 }
517 
528 int
529 nc4_find_var(NC_GRP_INFO_T *grp, const char *name, NC_VAR_INFO_T **var)
530 {
531  assert(grp && var && name);
532 
533  /* Find the var info. */
534  *var = (NC_VAR_INFO_T*)ncindexlookup(grp->vars,name);
535  return NC_NOERR;
536 }
537 
547 NC_TYPE_INFO_T *
548 nc4_rec_find_named_type(NC_GRP_INFO_T *start_grp, char *name)
549 {
550  NC_GRP_INFO_T *g;
551  NC_TYPE_INFO_T *type, *res;
552  int i;
553 
554  assert(start_grp);
555 
556  /* Does this group have the type we are searching for? */
557  type = (NC_TYPE_INFO_T*)ncindexlookup(start_grp->type,name);
558  if(type != NULL)
559  return type;
560 
561  /* Search subgroups. */
562  for(i=0;i<ncindexsize(start_grp->children);i++) {
563  g = (NC_GRP_INFO_T*)ncindexith(start_grp->children,i);
564  if(g == NULL) continue;
565  if ((res = nc4_rec_find_named_type(g, name)))
566  return res;
567  }
568  /* Can't find it. Oh, woe is me! */
569  return NULL;
570 }
571 
583 int
584 nc4_find_type(const NC_FILE_INFO_T *h5, nc_type typeid, NC_TYPE_INFO_T **type)
585 {
586  /* Check inputs. */
587  assert(h5);
588  if (typeid < 0 || !type)
589  return NC_EINVAL;
590  *type = NULL;
591 
592  /* Atomic types don't have associated NC_TYPE_INFO_T struct, just
593  * return NOERR. */
594  if (typeid <= NC_STRING)
595  return NC_NOERR;
596 
597  /* Find the type. */
598  if (!(*type = nclistget(h5->alltypes,typeid)))
599  return NC_EBADTYPID;
600 
601  return NC_NOERR;
602 }
603 
619 int
620 nc4_find_grp_att(NC_GRP_INFO_T *grp, int varid, const char *name, int attnum,
621  NC_ATT_INFO_T **att)
622 {
623  NC_VAR_INFO_T *var;
624  NC_ATT_INFO_T *my_att;
625  NCindex *attlist = NULL;
626 
627  assert(grp && grp->hdr.name && att);
628 
629  LOG((4, "%s: grp->name %s varid %d attnum %d", __func__, grp->hdr.name,
630  varid, attnum));
631 
632  /* Get either the global or a variable attribute list. */
633  if (varid == NC_GLOBAL)
634  {
635  attlist = grp->att;
636  }
637  else
638  {
639  var = (NC_VAR_INFO_T*)ncindexith(grp->vars,varid);
640  if (!var) return NC_ENOTVAR;
641 
642  attlist = var->att;
643  }
644  assert(attlist);
645 
646  /* Now find the attribute by name or number. If a name is provided,
647  * ignore the attnum. */
648  if (name)
649  my_att = (NC_ATT_INFO_T *)ncindexlookup(attlist, name);
650  else
651  my_att = (NC_ATT_INFO_T *)ncindexith(attlist, attnum);
652 
653  if (!my_att)
654  return NC_ENOTATT;
655 
656  *att = my_att;
657  return NC_NOERR;
658 }
659 
676 int
677 nc4_find_nc_att(int ncid, int varid, const char *name, int attnum,
678  NC_ATT_INFO_T **att)
679 {
680  NC_GRP_INFO_T *grp;
681  int retval;
682 
683  LOG((4, "nc4_find_nc_att: ncid 0x%x varid %d name %s attnum %d",
684  ncid, varid, name, attnum));
685 
686  /* Find info for this file and group, and set pointer to each. */
687  if ((retval = nc4_find_grp_h5(ncid, &grp, NULL)))
688  return retval;
689  assert(grp);
690 
691  return nc4_find_grp_att(grp, varid, name, attnum, att);
692 }
693 
702 static void
703 obj_track(NC_FILE_INFO_T* file, NC_OBJ* obj)
704 {
705  NClist* list = NULL;
706  /* record the object in the file */
707  switch (obj->sort) {
708  case NCDIM: list = file->alldims; break;
709  case NCTYP: list = file->alltypes; break;
710  case NCGRP: list = file->allgroups; break;
711  default:
712  assert(NC_FALSE);
713  }
714  /* Insert at the appropriate point in the list */
715  nclistset(list,obj->id,obj);
716 }
717 
732 int
733 nc4_var_list_add2(NC_GRP_INFO_T *grp, const char *name, NC_VAR_INFO_T **var)
734 {
735  NC_VAR_INFO_T *new_var = NULL;
736  NCglobalstate* gs = NC_getglobalstate();
737 
738  /* Allocate storage for new variable. */
739  if (!(new_var = calloc(1, sizeof(NC_VAR_INFO_T))))
740  return NC_ENOMEM;
741  new_var->hdr.sort = NCVAR;
742  new_var->container = grp;
743 
744  /* These are the HDF5-1.8.4 defaults. */
745  new_var->chunkcache.size = gs->chunkcache.size;
746  new_var->chunkcache.nelems = gs->chunkcache.nelems;
747  new_var->chunkcache.preemption = gs->chunkcache.preemption;
748 
749  /* Now fill in the values in the var info structure. */
750  new_var->hdr.id = ncindexsize(grp->vars);
751  if (!(new_var->hdr.name = strdup(name))) {
752  if(new_var)
753  free(new_var);
754  return NC_ENOMEM;
755  }
756 
757  /* Create an indexed list for the attributes. */
758  new_var->att = ncindexnew(0);
759 
760  /* Officially track it */
761  ncindexadd(grp->vars, (NC_OBJ *)new_var);
762 
763  /* Set the var pointer, if one was given */
764  if (var)
765  *var = new_var;
766 
767  return NC_NOERR;
768 }
769 
782 int
783 nc4_var_set_ndims(NC_VAR_INFO_T *var, int ndims)
784 {
785  assert(var);
786 
787  /* Remember the number of dimensions. */
788  var->ndims = ndims;
789 
790  /* Allocate space for dimension information. */
791  if (ndims)
792  {
793  if (!(var->dim = calloc(ndims, sizeof(NC_DIM_INFO_T *))))
794  return NC_ENOMEM;
795  if (!(var->dimids = calloc(ndims, sizeof(int))))
796  return NC_ENOMEM;
797 
798  /* Initialize dimids to illegal values (-1). See the comment
799  in nc4_rec_match_dimscales(). */
800  memset(var->dimids, -1, ndims * sizeof(int));
801  }
802 
803  return NC_NOERR;
804 }
805 
820 int
821 nc4_var_list_add(NC_GRP_INFO_T* grp, const char* name, int ndims,
822  NC_VAR_INFO_T **var)
823 {
824  int retval;
825 
826  if ((retval = nc4_var_list_add2(grp, name, var)))
827  return retval;
828  if ((retval = nc4_var_set_ndims(*var, ndims)))
829  return retval;
830 
831  return NC_NOERR;
832 }
833 
847 int
848 nc4_dim_list_add(NC_GRP_INFO_T *grp, const char *name, size_t len,
849  int assignedid, NC_DIM_INFO_T **dim)
850 {
851  NC_DIM_INFO_T *new_dim = NULL;
852 
853  assert(grp && name);
854 
855  /* Allocate memory for dim metadata. */
856  if (!(new_dim = calloc(1, sizeof(NC_DIM_INFO_T))))
857  return NC_ENOMEM;
858 
859  new_dim->hdr.sort = NCDIM;
860 
861  /* Assign the dimension ID. */
862  if (assignedid >= 0)
863  new_dim->hdr.id = assignedid;
864  else
865  new_dim->hdr.id = grp->nc4_info->next_dimid++;
866 
867  /* Remember the name and create a hash. */
868  if (!(new_dim->hdr.name = strdup(name))) {
869  if(new_dim)
870  free(new_dim);
871 
872  return NC_ENOMEM;
873  }
874 
875  /* Is dimension unlimited? */
876  new_dim->len = len;
877  if (len == NC_UNLIMITED)
878  new_dim->unlimited = NC_TRUE;
879 
880  /* Remember the containing group. */
881  new_dim->container = grp;
882 
883  /* Add object to dimension list for this group. */
884  ncindexadd(grp->dim, (NC_OBJ *)new_dim);
885  obj_track(grp->nc4_info, (NC_OBJ *)new_dim);
886 
887  /* Set the dim pointer, if one was given */
888  if (dim)
889  *dim = new_dim;
890 
891  return NC_NOERR;
892 }
893 
906 int
907 nc4_att_list_add(NCindex *list, const char *name, NC_ATT_INFO_T **att)
908 {
909  NC_ATT_INFO_T *new_att = NULL;
910 
911  LOG((3, "%s: name %s ", __func__, name));
912 
913  if (!(new_att = calloc(1, sizeof(NC_ATT_INFO_T))))
914  return NC_ENOMEM;
915  new_att->hdr.sort = NCATT;
916 
917  /* Fill in the information we know. */
918  new_att->hdr.id = ncindexsize(list);
919  if (!(new_att->hdr.name = strdup(name))) {
920  if(new_att)
921  free(new_att);
922  return NC_ENOMEM;
923  }
924 
925  /* Add object to list as specified by its number */
926  ncindexadd(list, (NC_OBJ *)new_att);
927 
928  /* Set the attribute pointer, if one was given */
929  if (att)
930  *att = new_att;
931 
932  return NC_NOERR;
933 }
934 
949 int
950 nc4_grp_list_add(NC_FILE_INFO_T *h5, NC_GRP_INFO_T *parent, char *name,
951  NC_GRP_INFO_T **grp)
952 {
953  NC_GRP_INFO_T *new_grp;
954 
955  /* Check inputs. */
956  assert(h5 && name);
957  LOG((3, "%s: name %s ", __func__, name));
958 
959  /* Get the memory to store this groups info. */
960  if (!(new_grp = calloc(1, sizeof(NC_GRP_INFO_T))))
961  return NC_ENOMEM;
962 
963  /* Fill in this group's information. */
964  new_grp->hdr.sort = NCGRP;
965  new_grp->nc4_info = h5;
966  new_grp->parent = parent;
967 
968  /* Assign the group ID. The root group will get id 0. */
969  new_grp->hdr.id = h5->next_nc_grpid++;
970  assert(parent || !new_grp->hdr.id);
971 
972  /* Handle the group name. */
973  if (!(new_grp->hdr.name = strdup(name)))
974  {
975  free(new_grp);
976  return NC_ENOMEM;
977  }
978 
979  /* Set up new indexed lists for stuff this group can contain. */
980  new_grp->children = ncindexnew(0);
981  new_grp->dim = ncindexnew(0);
982  new_grp->att = ncindexnew(0);
983  new_grp->type = ncindexnew(0);
984  new_grp->vars = ncindexnew(0);
985 
986  /* Add object to lists */
987  if (parent)
988  ncindexadd(parent->children, (NC_OBJ *)new_grp);
989  obj_track(h5, (NC_OBJ *)new_grp);
990 
991  /* Set the group pointer, if one was given */
992  if (grp)
993  *grp = new_grp;
994 
995  return NC_NOERR;
996 }
997 
1011 int
1012 nc4_check_dup_name(NC_GRP_INFO_T *grp, char *name)
1013 {
1014  NC_TYPE_INFO_T *type;
1015  NC_GRP_INFO_T *g;
1016  NC_VAR_INFO_T *var;
1017 
1018  /* Any types of this name? */
1019  type = (NC_TYPE_INFO_T*)ncindexlookup(grp->type,name);
1020  if(type != NULL)
1021  return NC_ENAMEINUSE;
1022 
1023  /* Any child groups of this name? */
1024  g = (NC_GRP_INFO_T*)ncindexlookup(grp->children,name);
1025  if(g != NULL)
1026  return NC_ENAMEINUSE;
1027 
1028  /* Any variables of this name? */
1029  var = (NC_VAR_INFO_T*)ncindexlookup(grp->vars,name);
1030  if(var != NULL)
1031  return NC_ENAMEINUSE;
1032 
1033  return NC_NOERR;
1034 }
1035 
1049 int
1050 nc4_type_new(size_t size, const char *name, int assignedid,
1051  NC_TYPE_INFO_T **type)
1052 {
1053  NC_TYPE_INFO_T *new_type;
1054 
1055  LOG((4, "%s: size %d name %s assignedid %d", __func__, size, name, assignedid));
1056 
1057  /* Check inputs. */
1058  assert(type);
1059 
1060  /* Allocate memory for the type */
1061  if (!(new_type = calloc(1, sizeof(NC_TYPE_INFO_T))))
1062  return NC_ENOMEM;
1063  new_type->hdr.sort = NCTYP;
1064  new_type->hdr.id = assignedid;
1065 
1066  /* Remember info about this type. */
1067  new_type->size = size;
1068  if (!(new_type->hdr.name = strdup(name))) {
1069  free(new_type);
1070  return NC_ENOMEM;
1071  }
1072 
1073  /* Return a pointer to the new type. */
1074  *type = new_type;
1075 
1076  return NC_NOERR;
1077 }
1078 
1092 int
1093 nc4_type_list_add(NC_GRP_INFO_T *grp, size_t size, const char *name,
1094  NC_TYPE_INFO_T **type)
1095 {
1096  NC_TYPE_INFO_T *new_type;
1097  int retval;
1098 
1099  /* Check inputs. */
1100  assert(grp && name && type);
1101  LOG((4, "%s: size %d name %s", __func__, size, name));
1102 
1103  /* Create the new TYPE_INFO struct. */
1104  if ((retval = nc4_type_new(size, name, grp->nc4_info->next_typeid,
1105  &new_type)))
1106  return retval;
1107  grp->nc4_info->next_typeid++;
1108 
1109  /* Increment the ref. count on the type */
1110  new_type->rc++;
1111 
1112  /* Add object to lists */
1113  ncindexadd(grp->type, (NC_OBJ *)new_type);
1114  obj_track(grp->nc4_info,(NC_OBJ*)new_type);
1115 
1116  /* Return a pointer to the new type. */
1117  *type = new_type;
1118 
1119  return NC_NOERR;
1120 }
1121 
1135 int
1136 nc4_field_list_add(NC_TYPE_INFO_T *parent, const char *name,
1137  size_t offset, nc_type xtype, int ndims,
1138  const int *dim_sizesp)
1139 {
1140  NC_FIELD_INFO_T *field;
1141 
1142  /* Name has already been checked and UTF8 normalized. */
1143  if (!name)
1144  return NC_EINVAL;
1145 
1146  /* Allocate storage for this field information. */
1147  if (!(field = calloc(1, sizeof(NC_FIELD_INFO_T))))
1148  return NC_ENOMEM;
1149  field->hdr.sort = NCFLD;
1150 
1151  /* Store the information about this field. */
1152  if (!(field->hdr.name = strdup(name)))
1153  {
1154  free(field);
1155  return NC_ENOMEM;
1156  }
1157  field->nc_typeid = xtype;
1158  field->offset = offset;
1159  field->ndims = ndims;
1160  if (ndims)
1161  {
1162  int i;
1163  if (!(field->dim_size = malloc(ndims * sizeof(int))))
1164  {
1165  free(field->hdr.name);
1166  free(field);
1167  return NC_ENOMEM;
1168  }
1169  for (i = 0; i < ndims; i++)
1170  field->dim_size[i] = dim_sizesp[i];
1171  }
1172 
1173  /* Add object to lists */
1174  field->hdr.id = nclistlength(parent->u.c.field);
1175  nclistpush(parent->u.c.field,field);
1176 
1177  return NC_NOERR;
1178 }
1179 
1192 int
1193 nc4_enum_member_add(NC_TYPE_INFO_T *parent, size_t size,
1194  const char *name, const void *value)
1195 {
1196  NC_ENUM_MEMBER_INFO_T *member;
1197 
1198  /* Name has already been checked. */
1199  assert(name && size > 0 && value);
1200  LOG((4, "%s: size %d name %s", __func__, size, name));
1201 
1202  /* Allocate storage for this field information. */
1203  if (!(member = calloc(1, sizeof(NC_ENUM_MEMBER_INFO_T))))
1204  return NC_ENOMEM;
1205  if (!(member->value = malloc(size))) {
1206  free(member);
1207  return NC_ENOMEM;
1208  }
1209  if (!(member->name = strdup(name))) {
1210  free(member->value);
1211  free(member);
1212  return NC_ENOMEM;
1213  }
1214 
1215  /* Store the value for this member. */
1216  memcpy(member->value, value, size);
1217 
1218  /* Add object to list */
1219  nclistpush(parent->u.e.enum_member,member);
1220 
1221  return NC_NOERR;
1222 }
1223 
1232 static void
1233 field_free(NC_FIELD_INFO_T *field)
1234 {
1235  /* Free some stuff. */
1236  if (field->hdr.name)
1237  free(field->hdr.name);
1238  if (field->dim_size)
1239  free(field->dim_size);
1240 
1241  /* Nc_Free the memory. */
1242  free(field);
1243 }
1244 
1254 int
1255 nc4_type_free(NC_TYPE_INFO_T *type)
1256 {
1257  int i;
1258 
1259  assert(type && type->rc && type->hdr.name);
1260 
1261  /* Decrement the ref. count on the type */
1262  type->rc--;
1263 
1264  /* Release the type, if the ref. count drops to zero */
1265  if (type->rc == 0)
1266  {
1267  LOG((4, "%s: deleting type %s", __func__, type->hdr.name));
1268 
1269  /* Free the name. */
1270  free(type->hdr.name);
1271 
1272  /* Enums and compound types have lists of fields to clean up. */
1273  switch (type->nc_type_class)
1274  {
1275  case NC_COMPOUND:
1276  {
1277  NC_FIELD_INFO_T *field;
1278 
1279  /* Delete all the fields in this type (there will be some if its a
1280  * compound). */
1281  for(i=0;i<nclistlength(type->u.c.field);i++) {
1282  field = nclistget(type->u.c.field,i);
1283  field_free(field);
1284  }
1285  nclistfree(type->u.c.field);
1286  }
1287  break;
1288 
1289  case NC_ENUM:
1290  {
1291  NC_ENUM_MEMBER_INFO_T *enum_member;
1292 
1293  /* Delete all the enum_members, if any. */
1294  for(i=0;i<nclistlength(type->u.e.enum_member);i++) {
1295  enum_member = nclistget(type->u.e.enum_member,i);
1296  free(enum_member->value);
1297  free(enum_member->name);
1298  free(enum_member);
1299  }
1300  nclistfree(type->u.e.enum_member);
1301  }
1302  break;
1303 
1304  default:
1305  break;
1306  }
1307 
1308  /* Release the memory. */
1309  free(type);
1310  }
1311 
1312  return NC_NOERR;
1313 }
1314 
1323 int
1324 nc4_att_free(NC_ATT_INFO_T *att)
1325 {
1326  int stat = NC_NOERR;
1327 
1328  assert(att);
1329  LOG((3, "%s: name %s ", __func__, att->hdr.name));
1330 
1331  /* Free the name. */
1332  if (att->hdr.name)
1333  free(att->hdr.name);
1334 
1335 #ifdef SEPDATA
1336  /* Free memory that was malloced to hold data for this
1337  * attribute. */
1338  if (att->data) {
1339  free(att->data);
1340  }
1341 
1342  /* If this is a string array attribute, delete all members of the
1343  * string array, then delete the array of pointers to strings. (The
1344  * array was filled with pointers by HDF5 when the att was read,
1345  * and memory for each string was allocated by HDF5. That's why I
1346  * use free and not nc_free, because the netCDF library didn't
1347  * allocate the memory that is being freed.) */
1348  if (att->stdata)
1349  {
1350  int i;
1351  for (i = 0; i < att->len; i++)
1352  if(att->stdata[i])
1353  free(att->stdata[i]);
1354  free(att->stdata);
1355  }
1356 
1357  /* If this att has vlen data, release it. */
1358  if (att->vldata)
1359  {
1360  int i;
1361  for (i = 0; i < att->len; i++)
1362  nc_free_vlen(&att->vldata[i]);
1363  free(att->vldata);
1364  }
1365 #else
1366  if (att->data) {
1367  NC_OBJ* parent;
1368  NC_FILE_INFO_T* h5 = NULL;
1369 
1370  /* Locate relevant objects */
1371  parent = att->container;
1372  if(parent->sort == NCVAR) parent = (NC_OBJ*)(((NC_VAR_INFO_T*)parent)->container);
1373  assert(parent->sort == NCGRP);
1374  h5 = ((NC_GRP_INFO_T*)parent)->nc4_info;
1375  /* Reclaim the attribute data */
1376  if((stat = nc_reclaim_data(h5->controller->ext_ncid,att->nc_typeid,att->data,att->len))) goto done;
1377  free(att->data); /* reclaim top level */
1378  att->data = NULL;
1379  }
1380 #endif
1381 
1382 done:
1383  free(att);
1384  return stat;
1385 }
1386 
1396 static int
1397 var_free(NC_VAR_INFO_T *var)
1398 {
1399  int i;
1400  int retval;
1401 
1402  assert(var);
1403  LOG((4, "%s: deleting var %s", __func__, var->hdr.name));
1404 
1405  /* First delete all the attributes attached to this var. */
1406  for (i = 0; i < ncindexsize(var->att); i++)
1407  if ((retval = nc4_att_free((NC_ATT_INFO_T *)ncindexith(var->att, i))))
1408  return retval;
1409  ncindexfree(var->att);
1410 
1411  /* Free some things that may be allocated. */
1412  if (var->chunksizes)
1413  free(var->chunksizes);
1414 
1415  if (var->alt_name)
1416  free(var->alt_name);
1417 
1418  if (var->dimids)
1419  free(var->dimids);
1420 
1421  if (var->dim)
1422  free(var->dim);
1423 
1424  /* Delete any fill value allocation. */
1425  if (var->fill_value) {
1426  int ncid = var->container->nc4_info->controller->ext_ncid;
1427  int tid = var->type_info->hdr.id;
1428  if((retval = nc_reclaim_data_all(ncid, tid, var->fill_value, 1))) return retval;
1429  var->fill_value = NULL;
1430  }
1431 
1432  /* Release type information */
1433  if (var->type_info)
1434  if ((retval = nc4_type_free(var->type_info)))
1435  return retval;
1436 
1437  /* Do this last because debugging may need it */
1438  if (var->hdr.name)
1439  free(var->hdr.name);
1440 
1441  /* Delete the var. */
1442  free(var);
1443 
1444  return NC_NOERR;
1445 }
1446 
1456 int
1457 nc4_var_list_del(NC_GRP_INFO_T *grp, NC_VAR_INFO_T *var)
1458 {
1459  int i;
1460 
1461  assert(var && grp);
1462 
1463  /* Remove from lists */
1464  i = ncindexfind(grp->vars, (NC_OBJ *)var);
1465  if (i >= 0)
1466  ncindexidel(grp->vars, i);
1467 
1468  return var_free(var);
1469 }
1470 
1479 static int
1480 dim_free(NC_DIM_INFO_T *dim)
1481 {
1482  assert(dim);
1483  LOG((4, "%s: deleting dim %s", __func__, dim->hdr.name));
1484 
1485  /* Free memory allocated for names. */
1486  if (dim->hdr.name)
1487  free(dim->hdr.name);
1488 
1489  free(dim);
1490  return NC_NOERR;
1491 }
1492 
1502 int
1503 nc4_dim_list_del(NC_GRP_INFO_T *grp, NC_DIM_INFO_T *dim)
1504 {
1505  if (grp && dim)
1506  {
1507  int pos = ncindexfind(grp->dim, (NC_OBJ *)dim);
1508  if(pos >= 0)
1509  ncindexidel(grp->dim, pos);
1510  }
1511 
1512  return dim_free(dim);
1513 }
1514 
1524 int
1525 nc4_rec_grp_del(NC_GRP_INFO_T *grp)
1526 {
1527  int i;
1528  int retval;
1529 
1530  assert(grp);
1531  LOG((3, "%s: grp->name %s", __func__, grp->hdr.name));
1532 
1533  /* Recursively call this function for each child, if any, stopping
1534  * if there is an error. */
1535  for (i = 0; i < ncindexsize(grp->children); i++)
1536  if ((retval = nc4_rec_grp_del((NC_GRP_INFO_T *)ncindexith(grp->children,
1537  i))))
1538  return retval;
1539  ncindexfree(grp->children);
1540 
1541  /* Free attributes */
1542  for (i = 0; i < ncindexsize(grp->att); i++)
1543  if ((retval = nc4_att_free((NC_ATT_INFO_T *)ncindexith(grp->att, i))))
1544  return retval;
1545  ncindexfree(grp->att);
1546 
1547  /* Delete all vars. */
1548  for (i = 0; i < ncindexsize(grp->vars); i++) {
1549  NC_VAR_INFO_T* v = (NC_VAR_INFO_T *)ncindexith(grp->vars, i);
1550  if ((retval = var_free(v)))
1551  return retval;
1552  }
1553  ncindexfree(grp->vars);
1554 
1555  /* Delete all dims, and free the list of dims. */
1556  for (i = 0; i < ncindexsize(grp->dim); i++)
1557  if ((retval = dim_free((NC_DIM_INFO_T *)ncindexith(grp->dim, i))))
1558  return retval;
1559  ncindexfree(grp->dim);
1560 
1561  /* Delete all types. */
1562  for (i = 0; i < ncindexsize(grp->type); i++)
1563  if ((retval = nc4_type_free((NC_TYPE_INFO_T *)ncindexith(grp->type, i))))
1564  return retval;
1565  ncindexfree(grp->type);
1566 
1567  /* Free the name. */
1568  free(grp->hdr.name);
1569 
1570  /* Free up this group */
1571  free(grp);
1572 
1573  return NC_NOERR;
1574 }
1575 
1585 int
1586 nc4_rec_grp_del_att_data(NC_GRP_INFO_T *grp)
1587 {
1588  int i;
1589  int retval;
1590 
1591  assert(grp);
1592  LOG((3, "%s: grp->name %s", __func__, grp->hdr.name));
1593 
1594  /* Recursively call this function for each child, if any, stopping
1595  * if there is an error. */
1596  for (i = 0; i < ncindexsize(grp->children); i++)
1597  if ((retval = nc4_rec_grp_del_att_data((NC_GRP_INFO_T *)ncindexith(grp->children, i))))
1598  return retval;
1599 
1600  /* Free attribute data in this group */
1601  for (i = 0; i < ncindexsize(grp->att); i++) {
1602  NC_ATT_INFO_T * att = (NC_ATT_INFO_T*)ncindexith(grp->att, i);
1603  if((retval = nc_reclaim_data_all(grp->nc4_info->controller->ext_ncid,att->nc_typeid,att->data,att->len)))
1604  return retval;
1605  att->data = NULL;
1606  att->len = 0;
1607  att->dirty = 0;
1608  }
1609 
1610  /* Delete att data from all contained vars in this group */
1611  for (i = 0; i < ncindexsize(grp->vars); i++) {
1612  int j;
1613  NC_VAR_INFO_T* v = (NC_VAR_INFO_T *)ncindexith(grp->vars, i);
1614  for(j=0;j<ncindexsize(v->att);j++) {
1615  NC_ATT_INFO_T* att = (NC_ATT_INFO_T*)ncindexith(v->att, j);
1616  if((retval = nc_reclaim_data_all(grp->nc4_info->controller->ext_ncid,att->nc_typeid,att->data,att->len)))
1617  return retval;
1618  att->data = NULL;
1619  att->len = 0;
1620  att->dirty = 0;
1621  }
1622  }
1623 
1624  return NC_NOERR;
1625 }
1626 
1637 int
1638 nc4_att_list_del(NCindex *list, NC_ATT_INFO_T *att)
1639 {
1640  assert(att && list);
1641  ncindexidel(list, ((NC_OBJ *)att)->id);
1642  return nc4_att_free(att);
1643 }
1644 
1658 int
1659 nc4_file_list_del(int ncid)
1660 {
1661  NC_FILE_INFO_T *h5;
1662  int retval;
1663 
1664  /* Find our metadata for this file. */
1665  if ((retval = nc4_find_grp_h5(ncid, NULL, &h5)))
1666  return retval;
1667  assert(h5);
1668 
1669  /* Delete the file resources. */
1670  if ((retval = nc4_nc4f_list_del(h5)))
1671  return retval;
1672 
1673  return NC_NOERR;
1674 }
1675 
1685 int
1686 nc4_nc4f_list_del(NC_FILE_INFO_T *h5)
1687 {
1688  int retval;
1689 
1690  assert(h5);
1691 
1692  /* Order is important here. We must delete the attribute contents
1693  before deleteing any metadata because nc_reclaim_data depends
1694  on the existence of the type info.
1695  */
1696 
1697  /* Delete all the attribute data contents in each group and variable. */
1698  if ((retval = nc4_rec_grp_del_att_data(h5->root_grp)))
1699  return retval;
1700 
1701  /* Delete all the list contents for vars, dims, and atts, in each
1702  * group. */
1703  if ((retval = nc4_rec_grp_del(h5->root_grp)))
1704  return retval;
1705 
1706  /* Cleanup these (extra) lists of all dims, groups, and types. */
1707  nclistfree(h5->alldims);
1708  nclistfree(h5->allgroups);
1709  nclistfree(h5->alltypes);
1710 
1711  /* Free the NC_FILE_INFO_T struct. */
1712  nullfree(h5->hdr.name);
1713  free(h5);
1714 
1715  return NC_NOERR;
1716 }
1717 
1731 int
1732 nc4_normalize_name(const char *name, char *norm_name)
1733 {
1734  char *temp_name;
1735  int stat = nc_utf8_normalize((const unsigned char *)name,(unsigned char **)&temp_name);
1736  if(stat != NC_NOERR)
1737  return stat;
1738  if (strlen(temp_name) > NC_MAX_NAME)
1739  {
1740  free(temp_name);
1741  return NC_EMAXNAME;
1742  }
1743  strcpy(norm_name, temp_name);
1744  free(temp_name);
1745  return NC_NOERR;
1746 }
1747 
1748 #ifdef ENABLE_SET_LOG_LEVEL
1749 
1756 int
1757 nc4_init_logging(void)
1758 {
1759  int ret = NC_NOERR;
1760 
1761 #if NC_HAS_LOGGING
1762 #if NC_HAS_PARALLEL4
1763  if (!LOG_FILE && nc_log_level >= 0)
1764  {
1765  char log_filename[NC_MAX_NAME];
1766  int my_rank = 0;
1767  int mpierr;
1768  int mpi_initialized;
1769 
1770  /* If MPI has been initialized find the rank. */
1771  if ((mpierr = MPI_Initialized(&mpi_initialized)))
1772  return NC_EMPI;
1773  if (mpi_initialized)
1774  {
1775  if ((mpierr = MPI_Comm_rank(MPI_COMM_WORLD, &my_rank)))
1776  return NC_EMPI;
1777  }
1778 
1779  /* Create a filename with the rank in it. */
1780  sprintf(log_filename, "nc4_log_%d.log", my_rank);
1781 
1782  /* Open a file for this rank to log messages. */
1783  if (!(LOG_FILE = fopen(log_filename, "w")))
1784  return NC_EINTERNAL;
1785  }
1786 #endif /* NC_HAS_PARALLEL4 */
1787 #endif /* NC_HAS_LOGGING */
1788 
1789  return ret;
1790 }
1791 
1798 void
1799 nc4_finalize_logging(void)
1800 {
1801 #if NC_HAS_LOGGING
1802 #if NC_HAS_PARALLEL4
1803  if (LOG_FILE)
1804  {
1805  fclose(LOG_FILE);
1806  LOG_FILE = NULL;
1807  }
1808 #endif /* NC_HAS_PARALLEL4 */
1809 #endif /* NC_HAS_LOGGING */
1810 }
1811 
1825 int
1826 nc_set_log_level(int new_level)
1827 {
1828 #if NC_HAS_LOGGING
1829  /* Remember the new level. */
1830  nc_log_level = new_level;
1831 
1832 #if NC_HAS_PARALLEL4
1833  /* For parallel I/O builds, call the log init/finalize functions
1834  * as needed, to open and close the log files. */
1835  if (new_level >= 0)
1836  {
1837  if (!LOG_FILE)
1838  nc4_init_logging();
1839  }
1840  else
1841  nc4_finalize_logging();
1842 #endif /* NC_HAS_PARALLEL4 */
1843 
1844  LOG((1, "log_level changed to %d", nc_log_level));
1845 #endif /*NC_HAS_LOGGING */
1846 
1847  return NC_NOERR;
1848 }
1849 #endif /* ENABLE_SET_LOG_LEVEL */
1850 
1851 #if NC_HAS_LOGGING
1852 #define MAX_NESTS 10
1862 static int
1863 rec_print_metadata(NC_GRP_INFO_T *grp, int tab_count)
1864 {
1865  NC_ATT_INFO_T *att;
1866  NC_VAR_INFO_T *var;
1867  NC_DIM_INFO_T *dim;
1868  NC_TYPE_INFO_T *type;
1869  NC_FIELD_INFO_T *field;
1870  char tabs[MAX_NESTS+1] = "";
1871  char temp_string[10];
1872  int t, retval, d, i;
1873 
1874  /* Come up with a number of tabs relative to the group. */
1875  for (t = 0; t < tab_count && t < MAX_NESTS; t++)
1876  tabs[t] = '\t';
1877  tabs[t] = '\0';
1878 
1879  LOG((2, "%s GROUP - %s nc_grpid: %d nvars: %d natts: %d",
1880  tabs, grp->hdr.name, grp->hdr.id, ncindexsize(grp->vars), ncindexsize(grp->att)));
1881 
1882  for (i = 0; i < ncindexsize(grp->att); i++)
1883  {
1884  att = (NC_ATT_INFO_T *)ncindexith(grp->att, i);
1885  assert(att);
1886  LOG((2, "%s GROUP ATTRIBUTE - attnum: %d name: %s type: %d len: %d",
1887  tabs, att->hdr.id, att->hdr.name, att->nc_typeid, att->len));
1888  }
1889 
1890  for (i = 0; i < ncindexsize(grp->dim); i++)
1891  {
1892  dim = (NC_DIM_INFO_T *)ncindexith(grp->dim, i);
1893  assert(dim);
1894  LOG((2, "%s DIMENSION - dimid: %d name: %s len: %d unlimited: %d",
1895  tabs, dim->hdr.id, dim->hdr.name, dim->len, dim->unlimited));
1896  }
1897 
1898  for (i = 0; i < ncindexsize(grp->vars); i++)
1899  {
1900  int j;
1901  char storage_str[NC_MAX_NAME] = "";
1902  char *dims_string = NULL;
1903 
1904  var = (NC_VAR_INFO_T*)ncindexith(grp->vars,i);
1905  assert(var);
1906  if (var->ndims > 0)
1907  {
1908  if (!(dims_string = malloc(sizeof(char) * var->ndims * 4)))
1909  return NC_ENOMEM;
1910  strcpy(dims_string, "");
1911  for (d = 0; d < var->ndims; d++)
1912  {
1913  sprintf(temp_string, " %d", var->dimids[d]);
1914  strcat(dims_string, temp_string);
1915  }
1916  }
1917  if (!var->meta_read)
1918  strcat(storage_str, "unknown");
1919  else if (var->storage == NC_CONTIGUOUS)
1920  strcat(storage_str, "contiguous");
1921  else if (var->storage == NC_COMPACT)
1922  strcat(storage_str, "compact");
1923  else if (var->storage == NC_CHUNKED)
1924  strcat(storage_str, "chunked");
1925  else if (var->storage == NC_VIRTUAL)
1926  strcat(storage_str, "virtual");
1927  else
1928  strcat(storage_str, "unknown");
1929  LOG((2, "%s VARIABLE - varid: %d name: %s ndims: %d "
1930  "dimids:%s storage: %s", tabs, var->hdr.id, var->hdr.name,
1931  var->ndims,
1932  (dims_string ? dims_string : " -"), storage_str));
1933  for (j = 0; j < ncindexsize(var->att); j++)
1934  {
1935  att = (NC_ATT_INFO_T *)ncindexith(var->att, j);
1936  assert(att);
1937  LOG((2, "%s VAR ATTRIBUTE - attnum: %d name: %s type: %d len: %d",
1938  tabs, att->hdr.id, att->hdr.name, att->nc_typeid, att->len));
1939  }
1940  if (dims_string)
1941  free(dims_string);
1942  }
1943 
1944  for (i = 0; i < ncindexsize(grp->type); i++)
1945  {
1946  type = (NC_TYPE_INFO_T*)ncindexith(grp->type, i);
1947  assert(type);
1948  LOG((2, "%s TYPE - nc_typeid: %d size: %d committed: %d name: %s",
1949  tabs, type->hdr.id, type->size, (int)type->committed, type->hdr.name));
1950  /* Is this a compound type? */
1951  if (type->nc_type_class == NC_COMPOUND)
1952  {
1953  int j;
1954  LOG((3, "compound type"));
1955  for (j = 0; j < nclistlength(type->u.c.field); j++)
1956  {
1957  field = (NC_FIELD_INFO_T *)nclistget(type->u.c.field, j);
1958  LOG((4, "field %s offset %d nctype %d ndims %d", field->hdr.name,
1959  field->offset, field->nc_typeid, field->ndims));
1960  }
1961  }
1962  else if (type->nc_type_class == NC_VLEN)
1963  {
1964  LOG((3, "VLEN type"));
1965  LOG((4, "base_nc_type: %d", type->u.v.base_nc_typeid));
1966  }
1967  else if (type->nc_type_class == NC_OPAQUE)
1968  LOG((3, "Opaque type"));
1969  else if (type->nc_type_class == NC_ENUM)
1970  {
1971  LOG((3, "Enum type"));
1972  LOG((4, "base_nc_type: %d", type->u.e.base_nc_typeid));
1973  }
1974  else
1975  {
1976  LOG((0, "Unknown class: %d", type->nc_type_class));
1977  return NC_EBADTYPE;
1978  }
1979  }
1980 
1981  /* Call self for each child of this group. */
1982  for (i = 0; i < ncindexsize(grp->children); i++)
1983  if ((retval = rec_print_metadata((NC_GRP_INFO_T *)ncindexith(grp->children, i),
1984  tab_count + 1)))
1985  return retval;
1986 
1987  return NC_NOERR;
1988 }
1989 
2000 int
2001 log_metadata_nc(NC_FILE_INFO_T *h5)
2002 {
2003  LOG((2, "*** NetCDF-4 Internal Metadata: int_ncid 0x%x ext_ncid 0x%x",
2004  h5->root_grp->nc4_info->controller->int_ncid,
2005  h5->root_grp->nc4_info->controller->ext_ncid));
2006  if (!h5)
2007  {
2008  LOG((2, "This is a netCDF-3 file."));
2009  return NC_NOERR;
2010  }
2011  LOG((2, "FILE - path: %s cmode: 0x%x parallel: %d redef: %d "
2012  "fill_mode: %d no_write: %d next_nc_grpid: %d", h5->root_grp->nc4_info->controller->path,
2013  h5->cmode, (int)h5->parallel, (int)h5->redef, h5->fill_mode, (int)h5->no_write,
2014  h5->next_nc_grpid));
2015  if(nc_log_level >= 2)
2016  return rec_print_metadata(h5->root_grp, 0);
2017  return NC_NOERR;
2018 }
2019 
2020 #endif /*NC_HAS_LOGGING */
2021 
2033 int
2034 NC4_show_metadata(int ncid)
2035 {
2036  int retval = NC_NOERR;
2037 #if NC_HAS_LOGGING
2038  NC_FILE_INFO_T *h5;
2039  int old_log_level = nc_log_level;
2040 
2041  /* Find file metadata. */
2042  if ((retval = nc4_find_grp_h5(ncid, NULL, &h5)))
2043  return retval;
2044 
2045  /* Log level must be 2 to see metadata. */
2046  nc_log_level = 2;
2047  retval = log_metadata_nc(h5);
2048  nc_log_level = old_log_level;
2049 #endif /*NC_HAS_LOGGING*/
2050  return retval;
2051 }
2052 
2060 const NC_reservedatt*
2061 NC_findreserved(const char* name)
2062 {
2063  int n = NRESERVED;
2064  int L = 0;
2065  int R = (n - 1);
2066 
2067  for(;;) {
2068  if(L > R) break;
2069  int m = (L + R) / 2;
2070  const NC_reservedatt* p = &NC_reserved[m];
2071  int cmp = strcmp(p->name,name);
2072  if(cmp == 0) return p;
2073  if(cmp < 0)
2074  L = (m + 1);
2075  else /*cmp > 0*/
2076  R = (m - 1);
2077  }
2078  return NULL;
2079 }
2080 
2081 static int
2082 NC4_move_in_NCList(NC* nc, int new_id)
2083 {
2084  int stat = move_in_NCList(nc,new_id);
2085  if(stat == NC_NOERR) {
2086  /* Synchronize header */
2087  if(nc->dispatchdata)
2088  ((NC_OBJ*)nc->dispatchdata)->id = nc->ext_ncid;
2089  }
2090  return stat;
2091 }
2092 
2093 /**************************************************/
2094 /* NCglobal state management */
2095 
2096 static NCglobalstate* nc_globalstate = NULL;
2097 
2098 static int
2100 {
2101  int stat = NC_NOERR;
2102  const char* tmp = NULL;
2103 
2104  if(nc_globalstate == NULL) {
2105  nc_globalstate = calloc(1,sizeof(NCglobalstate));
2106  }
2107  /* Initialize struct pointers */
2108  nc_globalstate->rcinfo = (struct NCRCinfo*)calloc(1,sizeof(struct NCRCinfo));
2109  if(nc_globalstate == NULL) return NC_ENOMEM;
2110 
2111  /* Get environment variables */
2112  if(getenv(NCRCENVIGNORE) != NULL)
2113  nc_globalstate->rcinfo->ignore = 1;
2114  tmp = getenv(NCRCENVRC);
2115  if(tmp != NULL && strlen(tmp) > 0)
2116  nc_globalstate->rcinfo->rcfile = strdup(tmp);
2117  /* Initialize chunk cache defaults */
2118  nc_globalstate->chunkcache.size = CHUNK_CACHE_SIZE;
2119  nc_globalstate->chunkcache.nelems = CHUNK_CACHE_NELEMS;
2120  nc_globalstate->chunkcache.preemption = CHUNK_CACHE_PREEMPTION;
2122  return stat;
2123 }
2124 
2125 /* Get global state */
2126 NCglobalstate*
2127 NC_getglobalstate(void)
2128 {
2129  if(nc_globalstate == NULL)
2131  return nc_globalstate;
2132 }
2133 
2134 void
2135 NC_freeglobalstate(void)
2136 {
2137  if(nc_globalstate != NULL) {
2138  nullfree(nc_globalstate->tempdir);
2139  nullfree(nc_globalstate->home);
2140  nullfree(nc_globalstate->cwd);
2141  NC_rcclear(nc_globalstate->rcinfo);
2142  free(nc_globalstate->rcinfo);
2143  free(nc_globalstate);
2144  nc_globalstate = NULL;
2145  }
2146 }
2147 /**************************************************/
2148 /* Specific property functions */
2149 
2196 int
2197 nc_set_alignment(int threshold, int alignment)
2198 {
2199  NCglobalstate* gs = NC_getglobalstate();
2200  gs->alignment.threshold = threshold;
2201  gs->alignment.alignment = alignment;
2202  gs->alignment.defined = 1;
2203  return NC_NOERR;
2204 }
2205 
2223 int
2224 nc_get_alignment(int* thresholdp, int* alignmentp)
2225 {
2226  NCglobalstate* gs = NC_getglobalstate();
2227  if(thresholdp) *thresholdp = gs->alignment.threshold;
2228  if(alignmentp) *alignmentp = gs->alignment.alignment;
2229  return NC_NOERR;
2230 }
int nc_get_alignment(int *thresholdp, int *alignmentp)
Provide get function to retrieve global data alignment information.
Definition: nc4internal.c:2224
int nc_set_alignment(int threshold, int alignment)
Provide a function to store global data alignment information.
Definition: nc4internal.c:2197
EXTERNL int nc_free_vlen(nc_vlen_t *vl)
Free memory in a VLEN object.
Definition: dvlen.c:43
static int NC_createglobalstate(void)
Definition: nc4internal.c:2099
Main header file for the C API.
#define NC_UNLIMITED
Size argument to nc_def_dim() for an unlimited dimension.
Definition: netcdf.h:251
#define NC_EBADTYPE
Not a netcdf data type.
Definition: netcdf.h:410
#define NC_VIRTUAL
In HDF5 files you can set storage for each variable to be either contiguous or chunked,...
Definition: netcdf.h:308
#define NC_VLEN
vlen (variable-length) types
Definition: netcdf.h:53
#define NC_ENAMEINUSE
String match to name in use.
Definition: netcdf.h:407
#define NC_ENOMEM
Memory allocation (malloc) failure.
Definition: netcdf.h:448
#define NC_COMPOUND
compound types
Definition: netcdf.h:56
#define NC_EINTERNAL
NetCDF Library Internal Error.
Definition: netcdf.h:474
#define NC_CHUNKED
In HDF5 files you can set storage for each variable to be either contiguous or chunked,...
Definition: netcdf.h:304
#define NC_ENUM
enum types
Definition: netcdf.h:55
#define NC_CONTIGUOUS
In HDF5 files you can set storage for each variable to be either contiguous or chunked,...
Definition: netcdf.h:305
#define NC_GLOBAL
Attribute id to put/get a global attribute.
Definition: netcdf.h:254
#define NC_EMAXNAME
NC_MAX_NAME exceeded.
Definition: netcdf.h:426
#define NC_ENOTATT
Attribute not found.
Definition: netcdf.h:408
EXTERNL int nc_reclaim_data(int ncid, nc_type xtypeid, void *memory, size_t count)
Reclaim a vector of instances of arbitrary type.
#define NC_COMPACT
In HDF5 files you can set storage for each variable to be either contiguous or chunked,...
Definition: netcdf.h:306
#define NC_ENOTVAR
Variable not found.
Definition: netcdf.h:422
#define NC_EINVAL
Invalid Argument.
Definition: netcdf.h:378
#define NC_MAX_NAME
Maximum for classic library.
Definition: netcdf.h:281
#define NC_NOERR
No Error.
Definition: netcdf.h:368
#define NC_EMPI
MPI operation failed.
Definition: netcdf.h:511
#define NC_OPAQUE
opaque types
Definition: netcdf.h:54
#define NC_EIO
Generic IO error.
Definition: netcdf.h:457
#define NC_STRING
string
Definition: netcdf.h:47
#define NC_EBADID
Not a netcdf id.
Definition: netcdf.h:375
#define NC_EBADTYPID
Bad type ID.
Definition: netcdf.h:497
#define NC_EBADDIM
Invalid dimension id or name.
Definition: netcdf.h:411
int nc_type
The nc_type type is just an int.
Definition: netcdf.h:25