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