NetCDF  4.6.1
nc4file.c
Go to the documentation of this file.
1 /* Copyright 2003-2018, University Corporation for Atmospheric
2  * Research. See COPYRIGHT file for copying and redistribution
3  * conditions. */
14 #include "config.h"
15 #include <errno.h> /* netcdf functions sometimes return system errors */
16 #include "nc.h"
17 #include "nc4internal.h"
18 #include "nc4dispatch.h"
19 #include <H5DSpublic.h> /* must be after nc4internal.h */
20 #include <H5Fpublic.h>
21 #include <hdf5_hl.h>
22 
25 #define LOGOPEN 1
26 
27 #define CD_NELEMS_ZLIB 1
37 static void
38 hdf5free(void* memory)
39 {
40 #ifndef JNA
41  /* On Windows using the microsoft runtime, it is an error
42  for one library to free memory allocated by a different library.*/
43 #ifdef HDF5_HAS_H5FREE
44  if(memory != NULL) H5free_memory(memory);
45 #else
46 #ifndef _MSC_VER
47  if(memory != NULL) free(memory);
48 #endif
49 #endif
50 #endif
51 }
52 
53 /* Custom iteration callback data */
54 typedef struct {
55  NC_GRP_INFO_T *grp;
56  NC_VAR_INFO_T *var;
57 } att_iter_info;
58 
59 
73 static int
74 get_netcdf_type(NC_HDF5_FILE_INFO_T *h5, hid_t native_typeid,
75  nc_type *xtype)
76 {
77  NC_TYPE_INFO_T *type;
78  H5T_class_t class;
79  htri_t is_str, equal = 0;
80 
81  assert(h5 && xtype);
82 
83  if ((class = H5Tget_class(native_typeid)) < 0)
84  return NC_EHDFERR;
85 
86  /* H5Tequal doesn't work with H5T_C_S1 for some reason. But
87  * H5Tget_class will return H5T_STRING if this is a string. */
88  if (class == H5T_STRING)
89  {
90  if ((is_str = H5Tis_variable_str(native_typeid)) < 0)
91  return NC_EHDFERR;
92  if (is_str)
93  *xtype = NC_STRING;
94  else
95  *xtype = NC_CHAR;
96  return NC_NOERR;
97  }
98  else if (class == H5T_INTEGER || class == H5T_FLOAT)
99  {
100  /* For integers and floats, we don't have to worry about
101  * endianness if we compare native types. */
102  if ((equal = H5Tequal(native_typeid, H5T_NATIVE_SCHAR)) < 0)
103  return NC_EHDFERR;
104  if (equal)
105  {
106  *xtype = NC_BYTE;
107  return NC_NOERR;
108  }
109  if ((equal = H5Tequal(native_typeid, H5T_NATIVE_SHORT)) < 0)
110  return NC_EHDFERR;
111  if (equal)
112  {
113  *xtype = NC_SHORT;
114  return NC_NOERR;
115  }
116  if ((equal = H5Tequal(native_typeid, H5T_NATIVE_INT)) < 0)
117  return NC_EHDFERR;
118  if (equal)
119  {
120  *xtype = NC_INT;
121  return NC_NOERR;
122  }
123  if ((equal = H5Tequal(native_typeid, H5T_NATIVE_FLOAT)) < 0)
124  return NC_EHDFERR;
125  if (equal)
126  {
127  *xtype = NC_FLOAT;
128  return NC_NOERR;
129  }
130  if ((equal = H5Tequal(native_typeid, H5T_NATIVE_DOUBLE)) < 0)
131  return NC_EHDFERR;
132  if (equal)
133  {
134  *xtype = NC_DOUBLE;
135  return NC_NOERR;
136  }
137  if ((equal = H5Tequal(native_typeid, H5T_NATIVE_UCHAR)) < 0)
138  return NC_EHDFERR;
139  if (equal)
140  {
141  *xtype = NC_UBYTE;
142  return NC_NOERR;
143  }
144  if ((equal = H5Tequal(native_typeid, H5T_NATIVE_USHORT)) < 0)
145  return NC_EHDFERR;
146  if (equal)
147  {
148  *xtype = NC_USHORT;
149  return NC_NOERR;
150  }
151  if ((equal = H5Tequal(native_typeid, H5T_NATIVE_UINT)) < 0)
152  return NC_EHDFERR;
153  if (equal)
154  {
155  *xtype = NC_UINT;
156  return NC_NOERR;
157  }
158  if ((equal = H5Tequal(native_typeid, H5T_NATIVE_LLONG)) < 0)
159  return NC_EHDFERR;
160  if (equal)
161  {
162  *xtype = NC_INT64;
163  return NC_NOERR;
164  }
165  if ((equal = H5Tequal(native_typeid, H5T_NATIVE_ULLONG)) < 0)
166  return NC_EHDFERR;
167  if (equal)
168  {
169  *xtype = NC_UINT64;
170  return NC_NOERR;
171  }
172  }
173 
174  /* Maybe we already know about this type. */
175  if (!equal)
176  if((type = nc4_rec_find_hdf_type(h5->root_grp, native_typeid)))
177  {
178  *xtype = type->nc_typeid;
179  return NC_NOERR;
180  }
181 
182  *xtype = NC_NAT;
183  return NC_EBADTYPID;
184 }
185 
197 static int
198 read_hdf5_att(NC_GRP_INFO_T *grp, hid_t attid, NC_ATT_INFO_T *att)
199 {
200  hid_t spaceid = 0, file_typeid = 0;
201  hsize_t dims[1] = {0}; /* netcdf attributes always 1-D. */
202  int retval = NC_NOERR;
203  size_t type_size;
204  int att_ndims;
205  hssize_t att_npoints;
206  H5T_class_t att_class;
207  int fixed_len_string = 0;
208  size_t fixed_size = 0;
209 
210  assert(att->name);
211  LOG((5, "%s: att->attnum %d att->name %s att->nc_typeid %d att->len %d",
212  __func__, att->attnum, att->name, (int)att->nc_typeid, att->len));
213 
214  /* Get type of attribute in file. */
215  if ((file_typeid = H5Aget_type(attid)) < 0)
216  return NC_EATTMETA;
217  if ((att->native_hdf_typeid = H5Tget_native_type(file_typeid, H5T_DIR_DEFAULT)) < 0)
218  BAIL(NC_EHDFERR);
219  if ((att_class = H5Tget_class(att->native_hdf_typeid)) < 0)
220  BAIL(NC_EATTMETA);
221  if (att_class == H5T_STRING && !H5Tis_variable_str(att->native_hdf_typeid))
222  {
223  fixed_len_string++;
224  if (!(fixed_size = H5Tget_size(att->native_hdf_typeid)))
225  BAIL(NC_EATTMETA);
226  }
227  if ((retval = get_netcdf_type(grp->nc4_info, att->native_hdf_typeid, &(att->nc_typeid))))
228  BAIL(retval);
229 
230 
231  /* Get len. */
232  if ((spaceid = H5Aget_space(attid)) < 0)
233  BAIL(NC_EATTMETA);
234  if ((att_ndims = H5Sget_simple_extent_ndims(spaceid)) < 0)
235  BAIL(NC_EATTMETA);
236  if ((att_npoints = H5Sget_simple_extent_npoints(spaceid)) < 0)
237  BAIL(NC_EATTMETA);
238 
239  /* If both att_ndims and att_npoints are zero, then this is a
240  * zero length att. */
241  if (att_ndims == 0 && att_npoints == 0)
242  dims[0] = 0;
243  else if (att->nc_typeid == NC_STRING)
244  dims[0] = att_npoints;
245  else if (att->nc_typeid == NC_CHAR)
246  {
247  /* NC_CHAR attributes are written as a scalar in HDF5, of type
248  * H5T_C_S1, of variable length. */
249  if (att_ndims == 0)
250  {
251  if (!(dims[0] = H5Tget_size(file_typeid)))
252  BAIL(NC_EATTMETA);
253  }
254  else
255  {
256  /* This is really a string type! */
257  att->nc_typeid = NC_STRING;
258  dims[0] = att_npoints;
259  }
260  }
261  else
262  {
263  H5S_class_t space_class;
264 
265  /* All netcdf attributes are scalar or 1-D only. */
266  if (att_ndims > 1)
267  BAIL(NC_EATTMETA);
268 
269  /* Check class of HDF5 dataspace */
270  if ((space_class = H5Sget_simple_extent_type(spaceid)) < 0)
271  BAIL(NC_EATTMETA);
272 
273  /* Check for NULL HDF5 dataspace class (should be weeded out earlier) */
274  if (H5S_NULL == space_class)
275  BAIL(NC_EATTMETA);
276 
277  /* check for SCALAR HDF5 dataspace class */
278  if (H5S_SCALAR == space_class)
279  dims[0] = 1;
280  else /* Must be "simple" dataspace */
281  {
282  /* Read the size of this attribute. */
283  if (H5Sget_simple_extent_dims(spaceid, dims, NULL) < 0)
284  BAIL(NC_EATTMETA);
285  }
286  }
287 
288  /* Tell the user what the length if this attribute is. */
289  att->len = dims[0];
290 
291  /* Allocate some memory if the len is not zero, and read the
292  attribute. */
293  if (dims[0])
294  {
295  if ((retval = nc4_get_typelen_mem(grp->nc4_info, att->nc_typeid, 0,
296  &type_size)))
297  return retval;
298  if (att_class == H5T_VLEN)
299  {
300  if (!(att->vldata = malloc((unsigned int)(att->len * sizeof(hvl_t)))))
301  BAIL(NC_ENOMEM);
302  if (H5Aread(attid, att->native_hdf_typeid, att->vldata) < 0)
303  BAIL(NC_EATTMETA);
304  }
305  else if (att->nc_typeid == NC_STRING)
306  {
307  if (!(att->stdata = calloc(att->len, sizeof(char *))))
308  BAIL(NC_ENOMEM);
309  /* For a fixed length HDF5 string, the read requires
310  * contiguous memory. Meanwhile, the netCDF API requires that
311  * nc_free_string be called on string arrays, which would not
312  * work if one contiguous memory block were used. So here I
313  * convert the contiguous block of strings into an array of
314  * malloced strings (each string with its own malloc). Then I
315  * copy the data and free the contiguous memory. This
316  * involves copying the data, which is bad, but this only
317  * occurs for fixed length string attributes, and presumably
318  * these are small. (And netCDF-4 does not create them - it
319  * always uses variable length strings. */
320  if (fixed_len_string)
321  {
322  int i;
323  char *contig_buf, *cur;
324 
325  /* Alloc space for the contiguous memory read. */
326  if (!(contig_buf = malloc(att->len * fixed_size * sizeof(char))))
327  BAIL(NC_ENOMEM);
328 
329  /* Read the fixed-len strings as one big block. */
330  if (H5Aread(attid, att->native_hdf_typeid, contig_buf) < 0) {
331  free(contig_buf);
332  BAIL(NC_EATTMETA);
333  }
334 
335  /* Copy strings, one at a time, into their new home. Alloc
336  space for each string. The user will later free this
337  space with nc_free_string. */
338  cur = contig_buf;
339  for (i = 0; i < att->len; i++)
340  {
341  if (!(att->stdata[i] = malloc(fixed_size))) {
342  free(contig_buf);
343  BAIL(NC_ENOMEM);
344  }
345  strncpy(att->stdata[i], cur, fixed_size);
346  cur += fixed_size;
347  }
348 
349  /* Free contiguous memory buffer. */
350  free(contig_buf);
351  }
352  else
353  {
354  /* Read variable-length string atts. */
355  if (H5Aread(attid, att->native_hdf_typeid, att->stdata) < 0)
356  BAIL(NC_EATTMETA);
357  }
358  }
359  else
360  {
361  if (!(att->data = malloc((unsigned int)(att->len * type_size))))
362  BAIL(NC_ENOMEM);
363  if (H5Aread(attid, att->native_hdf_typeid, att->data) < 0)
364  BAIL(NC_EATTMETA);
365  }
366  }
367 
368  if (H5Tclose(file_typeid) < 0)
369  BAIL(NC_EHDFERR);
370  if (H5Sclose(spaceid) < 0)
371  return NC_EHDFERR;
372 
373  return NC_NOERR;
374 
375 exit:
376  if (H5Tclose(file_typeid) < 0)
377  BAIL2(NC_EHDFERR);
378  if (spaceid > 0 && H5Sclose(spaceid) < 0)
379  BAIL2(NC_EHDFERR);
380  return retval;
381 }
382 
397 static herr_t
398 att_read_var_callbk(hid_t loc_id, const char *att_name, const H5A_info_t *ainfo, void *att_data)
399 {
400 
401  hid_t attid = 0;
402  int retval = NC_NOERR;
403  NC_ATT_INFO_T *att;
404  att_iter_info *att_info = (att_iter_info *)att_data;
405  const char** reserved;
406 
407  /* Should we ignore this attribute? */
408  for(reserved=NC_RESERVED_VARATT_LIST;*reserved;reserved++) {
409  if (strcmp(att_name, *reserved)==0) break;
410  }
411 
412  if(*reserved == NULL) {
413  /* Open the att by name. */
414  if ((attid = H5Aopen(loc_id, att_name, H5P_DEFAULT)) < 0)
415  BAIL(NC_EATTMETA);
416  LOG((4, "%s:: att_name %s", __func__, att_name));
417  /* Add to the end of the list of atts for this var. */
418  if ((retval = nc4_att_list_add(&att_info->var->att, &att)))
419  BAIL(retval);
420  /* Fill in the information we know. */
421  att->attnum = att_info->var->natts++;
422  if (!(att->name = strdup(att_name)))
423  BAIL(NC_ENOMEM);
424 
425  /* Read the rest of the info about the att,
426  * including its values. */
427  if ((retval = read_hdf5_att(att_info->grp, attid, att)))
428  {
429  if (NC_EBADTYPID == retval)
430  {
431  if ((retval = nc4_att_list_del(&att_info->var->att, att)))
432  BAIL(retval);
433  att = NULL;
434  }
435  else
436  BAIL(retval);
437  }
438 
439  if (att)
440  att->created = NC_TRUE;
441 
442  if (attid > 0 && H5Aclose(attid) < 0)
443  BAIL2(NC_EHDFERR);
444 
445  } /* endif not HDF5 att */
446 
447  return NC_NOERR;
448 
449 exit:
450  if (attid > 0 && H5Aclose(attid) < 0)
451  BAIL2(NC_EHDFERR);
452 
453  return retval;
454 }
455 
457 static const int ILLEGAL_OPEN_FLAGS = (NC_MMAP|NC_64BIT_OFFSET);
458 
460 static const int ILLEGAL_CREATE_FLAGS = (NC_NOWRITE|NC_MMAP|NC_INMEMORY|NC_64BIT_OFFSET|NC_CDF5);
461 
462 extern void reportopenobjects(int log, hid_t);
463 
468 typedef struct NC4_rec_read_metadata_obj_info
469 {
470  hid_t oid; /* HDF5 object ID */
471  char oname[NC_MAX_NAME + 1]; /* Name of object */
472  H5G_stat_t statbuf; /* Information about the object */
473  struct NC4_rec_read_metadata_obj_info *next; /* Pointer to next node in list */
474 } NC4_rec_read_metadata_obj_info_t;
475 
481 typedef struct NC4_rec_read_metadata_ud
482 {
483  NC4_rec_read_metadata_obj_info_t *grps_head, *grps_tail; /* Pointers to head & tail of list of groups */
484  NC_GRP_INFO_T *grp; /* Pointer to parent group */
485 } NC4_rec_read_metadata_ud_t;
486 
487 /* Forward */
488 static int NC4_enddef(int ncid);
489 static int nc4_rec_read_metadata(NC_GRP_INFO_T *grp);
490 
500 static int
501 sync_netcdf4_file(NC_HDF5_FILE_INFO_T *h5)
502 {
503  int retval;
504 
505  assert(h5);
506  LOG((3, "%s", __func__));
507 
508  /* If we're in define mode, that's an error, for strict nc3 rules,
509  * otherwise, end define mode. */
510  if (h5->flags & NC_INDEF)
511  {
512  if (h5->cmode & NC_CLASSIC_MODEL)
513  return NC_EINDEFINE;
514 
515  /* Turn define mode off. */
516  h5->flags ^= NC_INDEF;
517 
518  /* Redef mode needs to be tracked separately for nc_abort. */
519  h5->redef = NC_FALSE;
520  }
521 
522 #ifdef LOGGING
523  /* This will print out the names, types, lens, etc of the vars and
524  atts in the file, if the logging level is 2 or greater. */
525  log_metadata_nc(h5->root_grp->nc4_info->controller);
526 #endif
527 
528  /* Write any metadata that has changed. */
529  if (!(h5->cmode & NC_NOWRITE))
530  {
531  nc_bool_t bad_coord_order = NC_FALSE; /* if detected, propagate to all groups to consistently store dimids */
532 
533  if ((retval = nc4_rec_write_groups_types(h5->root_grp)))
534  return retval;
535  if ((retval = nc4_rec_detect_need_to_preserve_dimids(h5->root_grp, &bad_coord_order)))
536  return retval;
537  if ((retval = nc4_rec_write_metadata(h5->root_grp, bad_coord_order)))
538  return retval;
539  }
540 
541  if (H5Fflush(h5->hdfid, H5F_SCOPE_GLOBAL) < 0)
542  return NC_EHDFERR;
543 
544  return retval;
545 }
546 
558 static int
559 close_netcdf4_file(NC_HDF5_FILE_INFO_T *h5, int abort)
560 {
561  int retval = NC_NOERR;
562 
563  assert(h5 && h5->root_grp);
564  LOG((3, "%s: h5->path %s abort %d", __func__, h5->controller->path, abort));
565 
566  /* According to the docs, always end define mode on close. */
567  if (h5->flags & NC_INDEF)
568  h5->flags ^= NC_INDEF;
569 
570  /* Sync the file, unless we're aborting, or this is a read-only
571  * file. */
572  if (!h5->no_write && !abort)
573  if ((retval = sync_netcdf4_file(h5)))
574  goto exit;
575 
576  /* Delete all the list contents for vars, dims, and atts, in each
577  * group. */
578  if ((retval = nc4_rec_grp_del(&h5->root_grp, h5->root_grp)))
579  goto exit;
580 
581  /* Close hdf file. */
582 #ifdef USE_PARALLEL4
583  /* Free the MPI Comm & Info objects, if we opened the file in parallel */
584  if(h5->parallel)
585  {
586  if(MPI_COMM_NULL != h5->comm)
587  MPI_Comm_free(&h5->comm);
588  if(MPI_INFO_NULL != h5->info)
589  MPI_Info_free(&h5->info);
590  }
591 #endif
592 
593  if(h5->fileinfo) free(h5->fileinfo);
594 
595  if (H5Fclose(h5->hdfid) < 0)
596  {
597  int nobjs;
598 
599  nobjs = H5Fget_obj_count(h5->hdfid, H5F_OBJ_ALL);
600  /* Apparently we can get an error even when nobjs == 0 */
601  if(nobjs < 0) {
602  BAIL_QUIET(NC_EHDFERR);
603  } else if(nobjs > 0) {
604 #ifdef LOGGING
605  char msg[1024];
606  int logit = 1;
607  /* If the close doesn't work, probably there are still some HDF5
608  * objects open, which means there's a bug in the library. So
609  * print out some info on to help the poor programmer figure it
610  * out. */
611  snprintf(msg,sizeof(msg),"There are %d HDF5 objects open!", nobjs);
612 #ifdef LOGOPEN
613  LOG((0, msg));
614 #else
615  fprintf(stdout,msg);
616  logit = 0;
617 #endif
618  reportopenobjects(logit,h5->hdfid);
619 #endif
620  }
621  }
622 exit:
623  /* Free the nc4_info struct; above code should have reclaimed
624  everything else */
625  if(!retval && h5 != NULL)
626  free(h5);
627  return retval;
628 }
629 
635 const char* NC_RESERVED_VARATT_LIST[] = {
636  NC_ATT_REFERENCE_LIST,
637  NC_ATT_CLASS,
638  NC_ATT_DIMENSION_LIST,
639  NC_ATT_NAME,
640  NC_ATT_COORDINATES,
641  NC_DIMID_ATT_NAME,
642  NULL
643 };
644 
650 const char* NC_RESERVED_ATT_LIST[] = {
651  NC_ATT_FORMAT,
652  NC3_STRICT_ATT_NAME,
653  NCPROPS,
654  ISNETCDF4ATT,
655  SUPERBLOCKATT,
656  NULL
657 };
658 
663 const char* NC_RESERVED_SPECIAL_LIST[] = {
664  ISNETCDF4ATT,
665  SUPERBLOCKATT,
666  NCPROPS,
667  NULL
668 };
669 
670 size_t nc4_chunk_cache_size = CHUNK_CACHE_SIZE;
671 size_t nc4_chunk_cache_nelems = CHUNK_CACHE_NELEMS;
672 float nc4_chunk_cache_preemption = CHUNK_CACHE_PREEMPTION;
674 #define NUM_TYPES 12
679 static hid_t h5_native_type_constant_g[NUM_TYPES];
680 
682 static const char nc_type_name_g[NUM_TYPES][NC_MAX_NAME + 1] = {"char", "byte", "short",
683  "int", "float", "double", "ubyte",
684  "ushort", "uint", "int64",
685  "uint64", "string"};
686 
688 static const nc_type nc_type_constant_g[NUM_TYPES] = {NC_CHAR, NC_BYTE, NC_SHORT,
692 
694 static const int nc_type_size_g[NUM_TYPES] = {sizeof(char), sizeof(char), sizeof(short),
695  sizeof(int), sizeof(float), sizeof(double), sizeof(unsigned char),
696  sizeof(unsigned short), sizeof(unsigned int), sizeof(long long),
697  sizeof(unsigned long long), sizeof(char *)};
698 
711 int
712 nc_set_chunk_cache(size_t size, size_t nelems, float preemption)
713 {
714  if (preemption < 0 || preemption > 1)
715  return NC_EINVAL;
716  nc4_chunk_cache_size = size;
717  nc4_chunk_cache_nelems = nelems;
718  nc4_chunk_cache_preemption = preemption;
719  return NC_NOERR;
720 }
721 
733 int
734 nc_get_chunk_cache(size_t *sizep, size_t *nelemsp, float *preemptionp)
735 {
736  if (sizep)
737  *sizep = nc4_chunk_cache_size;
738 
739  if (nelemsp)
740  *nelemsp = nc4_chunk_cache_nelems;
741 
742  if (preemptionp)
743  *preemptionp = nc4_chunk_cache_preemption;
744  return NC_NOERR;
745 }
746 
758 int
759 nc_set_chunk_cache_ints(int size, int nelems, int preemption)
760 {
761  if (size <= 0 || nelems <= 0 || preemption < 0 || preemption > 100)
762  return NC_EINVAL;
763  nc4_chunk_cache_size = size;
764  nc4_chunk_cache_nelems = nelems;
765  nc4_chunk_cache_preemption = (float)preemption / 100;
766  return NC_NOERR;
767 }
768 
780 int
781 nc_get_chunk_cache_ints(int *sizep, int *nelemsp, int *preemptionp)
782 {
783  if (sizep)
784  *sizep = (int)nc4_chunk_cache_size;
785  if (nelemsp)
786  *nelemsp = (int)nc4_chunk_cache_nelems;
787  if (preemptionp)
788  *preemptionp = (int)(nc4_chunk_cache_preemption * 100);
789 
790  return NC_NOERR;
791 }
792 
801 int
802 nc4typelen(nc_type type)
803 {
804  switch(type){
805  case NC_BYTE:
806  case NC_CHAR:
807  case NC_UBYTE:
808  return 1;
809  case NC_USHORT:
810  case NC_SHORT:
811  return 2;
812  case NC_FLOAT:
813  case NC_INT:
814  case NC_UINT:
815  return 4;
816  case NC_DOUBLE:
817  case NC_INT64:
818  case NC_UINT64:
819  return 8;
820  }
821  return -1;
822 }
823 
840 static int
841 nc4_create_file(const char *path, int cmode, MPI_Comm comm, MPI_Info info,
842  NC *nc)
843 {
844  hid_t fcpl_id, fapl_id = -1;
845  unsigned flags;
846  FILE *fp;
847  int retval = NC_NOERR;
848  NC_HDF5_FILE_INFO_T* nc4_info = NULL;
849 #ifdef USE_PARALLEL4
850  int comm_duped = 0; /* Whether the MPI Communicator was duplicated */
851  int info_duped = 0; /* Whether the MPI Info object was duplicated */
852 #else /* !USE_PARALLEL4 */
853  int persist = 0; /* Should diskless try to persist its data into file?*/
854 #endif
855 
856  assert(nc && path);
857  LOG((3, "%s: path %s mode 0x%x", __func__, path, cmode));
858 
859  if(cmode & NC_DISKLESS)
860  flags = H5F_ACC_TRUNC;
861  else if(cmode & NC_NOCLOBBER)
862  flags = H5F_ACC_EXCL;
863  else
864  flags = H5F_ACC_TRUNC;
865 
866  /* If this file already exists, and NC_NOCLOBBER is specified,
867  return an error. */
868  if (cmode & NC_DISKLESS) {
869 #ifndef USE_PARALLEL4
870  if(cmode & NC_WRITE)
871  persist = 1;
872 #endif
873  } else if ((cmode & NC_NOCLOBBER) && (fp = fopen(path, "r"))) {
874  fclose(fp);
875  return NC_EEXIST;
876  }
877 
878  /* Add necessary structs to hold netcdf-4 file data. */
879  if ((retval = nc4_nc4f_list_add(nc, path, (NC_WRITE | cmode))))
880  BAIL(retval);
881  nc4_info = NC4_DATA(nc);
882  assert(nc4_info && nc4_info->root_grp);
883 
884  /* Need this access plist to control how HDF5 handles open objects
885  * on file close. (Setting H5F_CLOSE_SEMI will cause H5Fclose to
886  * fail if there are any open objects in the file. */
887  if ((fapl_id = H5Pcreate(H5P_FILE_ACCESS)) < 0)
888  BAIL(NC_EHDFERR);
889  if (H5Pset_fclose_degree(fapl_id, H5F_CLOSE_SEMI))
890  BAIL(NC_EHDFERR);
891 
892 #ifdef USE_PARALLEL4
893  /* If this is a parallel file create, set up the file creation
894  property list. */
895  if ((cmode & NC_MPIIO) || (cmode & NC_MPIPOSIX))
896  {
897  nc4_info->parallel = NC_TRUE;
898  if (cmode & NC_MPIIO) /* MPI/IO */
899  {
900  LOG((4, "creating parallel file with MPI/IO"));
901  if (H5Pset_fapl_mpio(fapl_id, comm, info) < 0)
902  BAIL(NC_EPARINIT);
903  }
904 #ifdef USE_PARALLEL_POSIX
905  else /* MPI/POSIX */
906  {
907  LOG((4, "creating parallel file with MPI/posix"));
908  if (H5Pset_fapl_mpiposix(fapl_id, comm, 0) < 0)
909  BAIL(NC_EPARINIT);
910  }
911 #else /* USE_PARALLEL_POSIX */
912  /* Should not happen! Code in NC4_create/NC4_open should alias the
913  * NC_MPIPOSIX flag to NC_MPIIO, if the MPI-POSIX VFD is not
914  * available in HDF5. -QAK
915  */
916  else /* MPI/POSIX */
917  BAIL(NC_EPARINIT);
918 #endif /* USE_PARALLEL_POSIX */
919 
920  /* Keep copies of the MPI Comm & Info objects */
921  if (MPI_SUCCESS != MPI_Comm_dup(comm, &nc4_info->comm))
922  BAIL(NC_EMPI);
923  comm_duped++;
924  if (MPI_INFO_NULL != info)
925  {
926  if (MPI_SUCCESS != MPI_Info_dup(info, &nc4_info->info))
927  BAIL(NC_EMPI);
928  info_duped++;
929  }
930  else
931  {
932  /* No dup, just copy it. */
933  nc4_info->info = info;
934  }
935  }
936 #else /* only set cache for non-parallel... */
937  if(cmode & NC_DISKLESS) {
938  if (H5Pset_fapl_core(fapl_id, 4096, persist))
939  BAIL(NC_EDISKLESS);
940  }
941  if (H5Pset_cache(fapl_id, 0, nc4_chunk_cache_nelems, nc4_chunk_cache_size,
943  BAIL(NC_EHDFERR);
944  LOG((4, "%s: set HDF raw chunk cache to size %d nelems %d preemption %f",
946 #endif /* USE_PARALLEL4 */
947 
948 #ifdef HDF5_HAS_LIBVER_BOUNDS
949  if (H5Pset_libver_bounds(fapl_id, H5F_LIBVER_EARLIEST, H5F_LIBVER_LATEST) < 0)
950  BAIL(NC_EHDFERR);
951 #endif
952 
953  /* Create the property list. */
954  if ((fcpl_id = H5Pcreate(H5P_FILE_CREATE)) < 0)
955  BAIL(NC_EHDFERR);
956 
957  /* RJ: this suppose to be FALSE that is defined in H5 private.h as 0 */
958  if (H5Pset_obj_track_times(fcpl_id,0)<0)
959  BAIL(NC_EHDFERR);
960 
961  /* Set latest_format in access propertly list and
962  * H5P_CRT_ORDER_TRACKED in the creation property list. This turns
963  * on HDF5 creation ordering. */
964  if (H5Pset_link_creation_order(fcpl_id, (H5P_CRT_ORDER_TRACKED |
965  H5P_CRT_ORDER_INDEXED)) < 0)
966  BAIL(NC_EHDFERR);
967  if (H5Pset_attr_creation_order(fcpl_id, (H5P_CRT_ORDER_TRACKED |
968  H5P_CRT_ORDER_INDEXED)) < 0)
969  BAIL(NC_EHDFERR);
970 
971  /* Create the file. */
972 #ifdef HDF5_HAS_COLL_METADATA_OPS
973  H5Pset_all_coll_metadata_ops(fapl_id, 1 );
974  H5Pset_coll_metadata_write(fapl_id, 1);
975 #endif
976 
977  if ((nc4_info->hdfid = H5Fcreate(path, flags, fcpl_id, fapl_id)) < 0)
978  /*Change the return error from NC_EFILEMETADATA to
979  System error EACCES because that is the more likely problem */
980  BAIL(EACCES);
981 
982  /* Open the root group. */
983  if ((nc4_info->root_grp->hdf_grpid = H5Gopen2(nc4_info->hdfid, "/",
984  H5P_DEFAULT)) < 0)
985  BAIL(NC_EFILEMETA);
986 
987  /* Release the property lists. */
988  if (H5Pclose(fapl_id) < 0 || H5Pclose(fcpl_id) < 0)
989  BAIL(NC_EHDFERR);
990 
991  /* Define mode gets turned on automatically on create. */
992  nc4_info->flags |= NC_INDEF;
993 
994  NC4_get_fileinfo(nc4_info,&globalpropinfo);
995  NC4_put_propattr(nc4_info);
996 
997  return NC_NOERR;
998 
999 exit: /*failure exit*/
1000 #ifdef USE_PARALLEL4
1001  if (comm_duped) MPI_Comm_free(&nc4_info->comm);
1002  if (info_duped) MPI_Info_free(&nc4_info->info);
1003 #endif
1004  if (fapl_id != H5P_DEFAULT) H5Pclose(fapl_id);
1005  if(!nc4_info) return retval;
1006  close_netcdf4_file(nc4_info,1); /* treat like abort */
1007  return retval;
1008 }
1009 
1029 int
1030 NC4_create(const char* path, int cmode, size_t initialsz, int basepe,
1031  size_t *chunksizehintp, int use_parallel, void *parameters,
1032  NC_Dispatch *dispatch, NC* nc_file)
1033 {
1034  MPI_Comm comm = MPI_COMM_WORLD;
1035  MPI_Info info = MPI_INFO_NULL;
1036  int res;
1037 
1038  assert(nc_file && path);
1039 
1040  LOG((1, "%s: path %s cmode 0x%x comm %d info %d",
1041  __func__, path, cmode, comm, info));
1042 
1043 #ifdef USE_PARALLEL4
1044  if (parameters)
1045  {
1046  comm = ((NC_MPI_INFO *)parameters)->comm;
1047  info = ((NC_MPI_INFO *)parameters)->info;
1048  }
1049 #endif /* USE_PARALLEL4 */
1050 
1051  /* If this is our first file, turn off HDF5 error messages. */
1052  if (!nc4_hdf5_initialized)
1053  nc4_hdf5_initialize();
1054 
1055  /* Check the cmode for validity. */
1056  if((cmode & ILLEGAL_CREATE_FLAGS) != 0)
1057  {res = NC_EINVAL; goto done;}
1058 
1059  /* Cannot have both */
1060  if((cmode & (NC_MPIIO|NC_MPIPOSIX)) == (NC_MPIIO|NC_MPIPOSIX))
1061  {res = NC_EINVAL; goto done;}
1062 
1063  /* Currently no parallel diskless io */
1064  if((cmode & (NC_MPIIO | NC_MPIPOSIX)) && (cmode & NC_DISKLESS))
1065  {res = NC_EINVAL; goto done;}
1066 
1067 #ifndef USE_PARALLEL_POSIX
1068 /* If the HDF5 library has been compiled without the MPI-POSIX VFD, alias
1069  * the NC_MPIPOSIX flag to NC_MPIIO. -QAK
1070  */
1071  if(cmode & NC_MPIPOSIX)
1072  {
1073  cmode &= ~NC_MPIPOSIX;
1074  cmode |= NC_MPIIO;
1075  }
1076 #endif /* USE_PARALLEL_POSIX */
1077 
1078  cmode |= NC_NETCDF4;
1079 
1080  /* Apply default create format. */
1081  if (nc_get_default_format() == NC_FORMAT_CDF5)
1082  cmode |= NC_CDF5;
1083  else if (nc_get_default_format() == NC_FORMAT_64BIT_OFFSET)
1084  cmode |= NC_64BIT_OFFSET;
1085  else if (nc_get_default_format() == NC_FORMAT_NETCDF4_CLASSIC)
1086  cmode |= NC_CLASSIC_MODEL;
1087 
1088  LOG((2, "cmode after applying default format: 0x%x", cmode));
1089 
1090  nc_file->int_ncid = nc_file->ext_ncid;
1091 
1092  res = nc4_create_file(path, cmode, comm, info, nc_file);
1093 
1094 done:
1095  return res;
1096 }
1097 
1117 static int
1118 read_scale(NC_GRP_INFO_T *grp, hid_t datasetid, const char *obj_name,
1119  const H5G_stat_t *statbuf, hsize_t scale_size, hsize_t max_scale_size,
1120  NC_DIM_INFO_T **dim)
1121 {
1122  NC_DIM_INFO_T *new_dim; /* Dimension added to group */
1123  char dimscale_name_att[NC_MAX_NAME + 1] = ""; /* Dimscale name, for checking if dim without var */
1124  htri_t attr_exists = -1; /* Flag indicating hidden attribute exists */
1125  hid_t attid = -1; /* ID of hidden attribute (to store dim ID) */
1126  int dimscale_created = 0; /* Remember if a dimension was created (for error recovery) */
1127  short initial_next_dimid = grp->nc4_info->next_dimid;/* Retain for error recovery */
1128  int retval;
1129 
1130  /* Add a dimension for this scale. */
1131  if ((retval = nc4_dim_list_add(&grp->dim, &new_dim)))
1132  BAIL(retval);
1133  dimscale_created++;
1134 
1135  /* Does this dataset have a hidden attribute that tells us its
1136  * dimid? If so, read it. */
1137  if ((attr_exists = H5Aexists(datasetid, NC_DIMID_ATT_NAME)) < 0)
1138  BAIL(NC_EHDFERR);
1139  if (attr_exists)
1140  {
1141  if ((attid = H5Aopen_name(datasetid, NC_DIMID_ATT_NAME)) < 0)
1142  BAIL(NC_EHDFERR);
1143 
1144  if (H5Aread(attid, H5T_NATIVE_INT, &new_dim->dimid) < 0)
1145  BAIL(NC_EHDFERR);
1146 
1147  /* Check if scale's dimid should impact the group's next dimid */
1148  if (new_dim->dimid >= grp->nc4_info->next_dimid)
1149  grp->nc4_info->next_dimid = new_dim->dimid + 1;
1150  }
1151  else
1152  {
1153  /* Assign dimid */
1154  new_dim->dimid = grp->nc4_info->next_dimid++;
1155  }
1156 
1157  if (!(new_dim->name = strdup(obj_name)))
1158  BAIL(NC_ENOMEM);
1159  if (SIZEOF_SIZE_T < 8 && scale_size > NC_MAX_UINT)
1160  {
1161  new_dim->len = NC_MAX_UINT;
1162  new_dim->too_long = NC_TRUE;
1163  }
1164  else
1165  new_dim->len = scale_size;
1166  new_dim->hdf5_objid.fileno[0] = statbuf->fileno[0];
1167  new_dim->hdf5_objid.fileno[1] = statbuf->fileno[1];
1168  new_dim->hdf5_objid.objno[0] = statbuf->objno[0];
1169  new_dim->hdf5_objid.objno[1] = statbuf->objno[1];
1170  new_dim->hash = hash_fast(obj_name, strlen(obj_name));
1171 
1172  /* If the dimscale has an unlimited dimension, then this dimension
1173  * is unlimited. */
1174  if (max_scale_size == H5S_UNLIMITED)
1175  new_dim->unlimited = NC_TRUE;
1176 
1177  /* If the scale name is set to DIM_WITHOUT_VARIABLE, then this is a
1178  * dimension, but not a variable. (If get_scale_name returns an
1179  * error, just move on, there's no NAME.) */
1180  if (H5DSget_scale_name(datasetid, dimscale_name_att, NC_MAX_NAME) >= 0)
1181  {
1182  if (!strncmp(dimscale_name_att, DIM_WITHOUT_VARIABLE,
1183  strlen(DIM_WITHOUT_VARIABLE)))
1184  {
1185  if (new_dim->unlimited)
1186  {
1187  size_t len = 0, *lenp = &len;
1188 
1189  if ((retval = nc4_find_dim_len(grp, new_dim->dimid, &lenp)))
1190  BAIL(retval);
1191  new_dim->len = *lenp;
1192  }
1193 
1194  /* Hold open the dataset, since the dimension doesn't have a coordinate variable */
1195  new_dim->hdf_dimscaleid = datasetid;
1196  H5Iinc_ref(new_dim->hdf_dimscaleid); /* Increment number of objects using ID */
1197  }
1198  }
1199 
1200  /* Set the dimension created */
1201  *dim = new_dim;
1202 
1203 exit:
1204  /* Close the hidden attribute, if it was opened (error, or no error) */
1205  if (attid > 0 && H5Aclose(attid) < 0)
1206  BAIL2(NC_EHDFERR);
1207 
1208  /* On error, undo any dimscale creation */
1209  if (retval < 0 && dimscale_created)
1210  {
1211  /* Delete the dimension */
1212  if ((retval = nc4_dim_list_del(&grp->dim, new_dim)))
1213  BAIL2(retval);
1214 
1215  /* Reset the group's information */
1216  grp->nc4_info->next_dimid = initial_next_dimid;
1217  }
1218 
1219  return retval;
1220 }
1221 
1232 static int
1233 read_coord_dimids(NC_GRP_INFO_T *grp, NC_VAR_INFO_T *var)
1234 {
1235  hid_t coord_att_typeid = -1, coord_attid = -1, spaceid = -1;
1236  hssize_t npoints;
1237  int ret = 0;
1238  int d;
1239 
1240  /* There is a hidden attribute telling us the ids of the
1241  * dimensions that apply to this multi-dimensional coordinate
1242  * variable. Read it. */
1243  if ((coord_attid = H5Aopen_name(var->hdf_datasetid, COORDINATES)) < 0) ret++;
1244  if (!ret && (coord_att_typeid = H5Aget_type(coord_attid)) < 0) ret++;
1245 
1246  /* How many dimensions are there? */
1247  if (!ret && (spaceid = H5Aget_space(coord_attid)) < 0) ret++;
1248  if (!ret && (npoints = H5Sget_simple_extent_npoints(spaceid)) < 0) ret++;
1249 
1250  /* Check that the number of points is the same as the number of dimensions
1251  * for the variable */
1252  if (!ret && npoints != var->ndims) ret++;
1253 
1254  if (!ret && H5Aread(coord_attid, coord_att_typeid, var->dimids) < 0) ret++;
1255  LOG((4, "dimscale %s is multidimensional and has coords", var->name));
1256 
1257  /* Update var->dim field based on the var->dimids */
1258  for (d = 0; d < var->ndims; d++) {
1259  /* Ok if does not find a dim at this time, but if found set it */
1260  nc4_find_dim(grp, var->dimids[d], &var->dim[d], NULL);
1261  }
1262 
1263  /* Set my HDF5 IDs free! */
1264  if (spaceid >= 0 && H5Sclose(spaceid) < 0) ret++;
1265  if (coord_att_typeid >= 0 && H5Tclose(coord_att_typeid) < 0) ret++;
1266  if (coord_attid >= 0 && H5Aclose(coord_attid) < 0) ret++;
1267  return ret ? NC_EATTMETA : NC_NOERR;
1268 }
1269 
1282 static herr_t
1283 dimscale_visitor(hid_t did, unsigned dim, hid_t dsid,
1284  void *dimscale_hdf5_objids)
1285 {
1286  H5G_stat_t statbuf;
1287 
1288  /* Get more info on the dimscale object.*/
1289  if (H5Gget_objinfo(dsid, ".", 1, &statbuf) < 0)
1290  return -1;
1291 
1292  /* Pass this information back to caller. */
1293  (*(HDF5_OBJID_T *)dimscale_hdf5_objids).fileno[0] = statbuf.fileno[0];
1294  (*(HDF5_OBJID_T *)dimscale_hdf5_objids).fileno[1] = statbuf.fileno[1];
1295  (*(HDF5_OBJID_T *)dimscale_hdf5_objids).objno[0] = statbuf.objno[0];
1296  (*(HDF5_OBJID_T *)dimscale_hdf5_objids).objno[1] = statbuf.objno[1];
1297  return 0;
1298 }
1299 
1315 static int
1316 get_type_info2(NC_HDF5_FILE_INFO_T *h5, hid_t datasetid,
1317  NC_TYPE_INFO_T **type_info)
1318 {
1319  htri_t is_str, equal = 0;
1320  H5T_class_t class;
1321  hid_t native_typeid, hdf_typeid;
1322  H5T_order_t order;
1323  int t;
1324 
1325  assert(h5 && type_info);
1326 
1327  /* Because these N5T_NATIVE_* constants are actually function calls
1328  * (!) in H5Tpublic.h, I can't initialize this array in the usual
1329  * way, because at least some C compilers (like Irix) complain
1330  * about calling functions when defining constants. So I have to do
1331  * it like this. Note that there's no native types for char or
1332  * string. Those are handled later. */
1333  if (!h5_native_type_constant_g[1])
1334  {
1335  h5_native_type_constant_g[1] = H5T_NATIVE_SCHAR;
1336  h5_native_type_constant_g[2] = H5T_NATIVE_SHORT;
1337  h5_native_type_constant_g[3] = H5T_NATIVE_INT;
1338  h5_native_type_constant_g[4] = H5T_NATIVE_FLOAT;
1339  h5_native_type_constant_g[5] = H5T_NATIVE_DOUBLE;
1340  h5_native_type_constant_g[6] = H5T_NATIVE_UCHAR;
1341  h5_native_type_constant_g[7] = H5T_NATIVE_USHORT;
1342  h5_native_type_constant_g[8] = H5T_NATIVE_UINT;
1343  h5_native_type_constant_g[9] = H5T_NATIVE_LLONG;
1344  h5_native_type_constant_g[10] = H5T_NATIVE_ULLONG;
1345  }
1346 
1347  /* Get the HDF5 typeid - we'll need it later. */
1348  if ((hdf_typeid = H5Dget_type(datasetid)) < 0)
1349  return NC_EHDFERR;
1350 
1351  /* Get the native typeid. Will be equivalent to hdf_typeid when
1352  * creating but not necessarily when reading, a variable. */
1353  if ((native_typeid = H5Tget_native_type(hdf_typeid, H5T_DIR_DEFAULT)) < 0)
1354  return NC_EHDFERR;
1355 
1356  /* Is this type an integer, string, compound, or what? */
1357  if ((class = H5Tget_class(native_typeid)) < 0)
1358  return NC_EHDFERR;
1359 
1360  /* Is this an atomic type? */
1361  if (class == H5T_STRING || class == H5T_INTEGER || class == H5T_FLOAT)
1362  {
1363  /* Allocate a phony NC_TYPE_INFO_T struct to hold type info. */
1364  if (!(*type_info = calloc(1, sizeof(NC_TYPE_INFO_T))))
1365  return NC_ENOMEM;
1366 
1367  /* H5Tequal doesn't work with H5T_C_S1 for some reason. But
1368  * H5Tget_class will return H5T_STRING if this is a string. */
1369  if (class == H5T_STRING)
1370  {
1371  if ((is_str = H5Tis_variable_str(native_typeid)) < 0)
1372  return NC_EHDFERR;
1373  /* Make sure fixed-len strings will work like variable-len strings */
1374  if (is_str || H5Tget_size(hdf_typeid) > 1)
1375  {
1376  /* Set a class for the type */
1377  t = NUM_TYPES - 1;
1378  (*type_info)->nc_type_class = NC_STRING;
1379  }
1380  else
1381  {
1382  /* Set a class for the type */
1383  t = 0;
1384  (*type_info)->nc_type_class = NC_CHAR;
1385  }
1386  }
1387  else if (class == H5T_INTEGER || class == H5T_FLOAT)
1388  {
1389  for (t = 1; t < NUM_TYPES - 1; t++)
1390  {
1391  if ((equal = H5Tequal(native_typeid, h5_native_type_constant_g[t])) < 0)
1392  return NC_EHDFERR;
1393  if (equal)
1394  break;
1395  }
1396 
1397  /* Find out about endianness.
1398  * As of HDF 1.8.6, this works with all data types
1399  * Not just H5T_INTEGER.
1400  *
1401  * See https://www.hdfgroup.org/HDF5/doc/RM/RM_H5T.html#Datatype-GetOrder
1402  */
1403  if((order = H5Tget_order(hdf_typeid)) < 0)
1404  return NC_EHDFERR;
1405 
1406  if(order == H5T_ORDER_LE)
1407  (*type_info)->endianness = NC_ENDIAN_LITTLE;
1408  else if(order == H5T_ORDER_BE)
1409  (*type_info)->endianness = NC_ENDIAN_BIG;
1410  else
1411  return NC_EBADTYPE;
1412 
1413  if(class == H5T_INTEGER)
1414  (*type_info)->nc_type_class = NC_INT;
1415  else
1416  (*type_info)->nc_type_class = NC_FLOAT;
1417  }
1418  (*type_info)->nc_typeid = nc_type_constant_g[t];
1419  (*type_info)->size = nc_type_size_g[t];
1420  if (!((*type_info)->name = strdup(nc_type_name_g[t])))
1421  return NC_ENOMEM;
1422  (*type_info)->hdf_typeid = hdf_typeid;
1423  (*type_info)->native_hdf_typeid = native_typeid;
1424  return NC_NOERR;
1425  }
1426  else
1427  {
1428  NC_TYPE_INFO_T *type;
1429 
1430  /* This is a user-defined type. */
1431  if((type = nc4_rec_find_hdf_type(h5->root_grp, native_typeid)))
1432  *type_info = type;
1433 
1434  /* The type entry in the array of user-defined types already has
1435  * an open data typeid (and native typeid), so close the ones we
1436  * opened above. */
1437  if (H5Tclose(native_typeid) < 0)
1438  return NC_EHDFERR;
1439  if (H5Tclose(hdf_typeid) < 0)
1440  return NC_EHDFERR;
1441 
1442  if (type)
1443  return NC_NOERR;
1444  }
1445 
1446  return NC_EBADTYPID;
1447 }
1448 
1463 static int
1464 read_type(NC_GRP_INFO_T *grp, hid_t hdf_typeid, char *type_name)
1465 {
1466  NC_TYPE_INFO_T *type;
1467  H5T_class_t class;
1468  hid_t native_typeid;
1469  size_t type_size;
1470  int retval = NC_NOERR;
1471 
1472  assert(grp && type_name);
1473 
1474  LOG((4, "%s: type_name %s grp->name %s", __func__, type_name, grp->name));
1475 
1476  /* What is the native type for this platform? */
1477  if ((native_typeid = H5Tget_native_type(hdf_typeid, H5T_DIR_DEFAULT)) < 0)
1478  return NC_EHDFERR;
1479 
1480  /* What is the size of this type on this platform. */
1481  if (!(type_size = H5Tget_size(native_typeid)))
1482  return NC_EHDFERR;
1483  LOG((5, "type_size %d", type_size));
1484 
1485  /* Add to the list for this new type, and get a local pointer to it. */
1486  if ((retval = nc4_type_list_add(grp, type_size, type_name, &type)))
1487  return retval;
1488 
1489  /* Remember common info about this type. */
1490  type->committed = NC_TRUE;
1491  type->hdf_typeid = hdf_typeid;
1492  H5Iinc_ref(type->hdf_typeid); /* Increment number of objects using ID */
1493  type->native_hdf_typeid = native_typeid;
1494 
1495  /* What is the class of this type, compound, vlen, etc. */
1496  if ((class = H5Tget_class(hdf_typeid)) < 0)
1497  return NC_EHDFERR;
1498  switch (class)
1499  {
1500  case H5T_STRING:
1501  type->nc_type_class = NC_STRING;
1502  break;
1503 
1504  case H5T_COMPOUND:
1505  {
1506  int nmembers;
1507  unsigned int m;
1508  char* member_name = NULL;
1509 #ifdef JNA
1510  char jna[1001];
1511 #endif
1512 
1513  type->nc_type_class = NC_COMPOUND;
1514 
1515  if ((nmembers = H5Tget_nmembers(hdf_typeid)) < 0)
1516  return NC_EHDFERR;
1517  LOG((5, "compound type has %d members", nmembers));
1518  for (m = 0; m < nmembers; m++)
1519  {
1520  hid_t member_hdf_typeid;
1521  hid_t member_native_typeid;
1522  size_t member_offset;
1523  H5T_class_t mem_class;
1524  nc_type member_xtype;
1525 
1526 
1527  /* Get the typeid and native typeid of this member of the
1528  * compound type. */
1529  if ((member_hdf_typeid = H5Tget_member_type(type->native_hdf_typeid, m)) < 0)
1530  return NC_EHDFERR;
1531 
1532  if ((member_native_typeid = H5Tget_native_type(member_hdf_typeid, H5T_DIR_DEFAULT)) < 0)
1533  return NC_EHDFERR;
1534 
1535  /* Get the name of the member.*/
1536  member_name = H5Tget_member_name(type->native_hdf_typeid, m);
1537  if (!member_name || strlen(member_name) > NC_MAX_NAME) {
1538  retval = NC_EBADNAME;
1539  break;
1540  }
1541 #ifdef JNA
1542  else {
1543  strncpy(jna,member_name,1000);
1544  member_name = jna;
1545  }
1546 #endif
1547 
1548  /* Offset in bytes on *this* platform. */
1549  member_offset = H5Tget_member_offset(type->native_hdf_typeid, m);
1550 
1551  /* Get dimensional data if this member is an array of something. */
1552  if ((mem_class = H5Tget_class(member_hdf_typeid)) < 0)
1553  return NC_EHDFERR;
1554  if (mem_class == H5T_ARRAY)
1555  {
1556  int ndims, dim_size[NC_MAX_VAR_DIMS];
1557  hsize_t dims[NC_MAX_VAR_DIMS];
1558  int d;
1559 
1560  if ((ndims = H5Tget_array_ndims(member_hdf_typeid)) < 0) {
1561  retval = NC_EHDFERR;
1562  break;
1563  }
1564  if (H5Tget_array_dims(member_hdf_typeid, dims, NULL) != ndims) {
1565  retval = NC_EHDFERR;
1566  break;
1567  }
1568  for (d = 0; d < ndims; d++)
1569  dim_size[d] = dims[d];
1570 
1571  /* What is the netCDF typeid of this member? */
1572  if ((retval = get_netcdf_type(grp->nc4_info, H5Tget_super(member_hdf_typeid),
1573  &member_xtype)))
1574  break;
1575 
1576  /* Add this member to our list of fields in this compound type. */
1577  if ((retval = nc4_field_list_add(&type->u.c.field, type->u.c.num_fields++, member_name,
1578  member_offset, H5Tget_super(member_hdf_typeid),
1579  H5Tget_super(member_native_typeid),
1580  member_xtype, ndims, dim_size)))
1581  break;
1582  }
1583  else
1584  {
1585  /* What is the netCDF typeid of this member? */
1586  if ((retval = get_netcdf_type(grp->nc4_info, member_native_typeid,
1587  &member_xtype)))
1588  break;
1589 
1590  /* Add this member to our list of fields in this compound type. */
1591  if ((retval = nc4_field_list_add(&type->u.c.field, type->u.c.num_fields++, member_name,
1592  member_offset, member_hdf_typeid, member_native_typeid,
1593  member_xtype, 0, NULL)))
1594  break;
1595  }
1596 
1597  hdf5free(member_name);
1598  member_name = NULL;
1599  }
1600  hdf5free(member_name);
1601  member_name = NULL;
1602  if(retval) /* error exit from loop */
1603  return retval;
1604  }
1605  break;
1606 
1607  case H5T_VLEN:
1608  {
1609  htri_t ret;
1610 
1611  /* For conveninence we allow user to pass vlens of strings
1612  * with null terminated strings. This means strings are
1613  * treated slightly differently by the API, although they are
1614  * really just VLENs of characters. */
1615  if ((ret = H5Tis_variable_str(hdf_typeid)) < 0)
1616  return NC_EHDFERR;
1617  if (ret)
1618  type->nc_type_class = NC_STRING;
1619  else
1620  {
1621  hid_t base_hdf_typeid;
1622  nc_type base_nc_type = NC_NAT;
1623 
1624  type->nc_type_class = NC_VLEN;
1625 
1626  /* Find the base type of this vlen (i.e. what is this a
1627  * vlen of?) */
1628  if (!(base_hdf_typeid = H5Tget_super(native_typeid)))
1629  return NC_EHDFERR;
1630 
1631  /* What size is this type? */
1632  if (!(type_size = H5Tget_size(base_hdf_typeid)))
1633  return NC_EHDFERR;
1634 
1635  /* What is the netcdf corresponding type. */
1636  if ((retval = get_netcdf_type(grp->nc4_info, base_hdf_typeid,
1637  &base_nc_type)))
1638  return retval;
1639  LOG((5, "base_hdf_typeid 0x%x type_size %d base_nc_type %d",
1640  base_hdf_typeid, type_size, base_nc_type));
1641 
1642  /* Remember the base types for this vlen */
1643  type->u.v.base_nc_typeid = base_nc_type;
1644  type->u.v.base_hdf_typeid = base_hdf_typeid;
1645  }
1646  }
1647  break;
1648 
1649  case H5T_OPAQUE:
1650  type->nc_type_class = NC_OPAQUE;
1651  break;
1652 
1653  case H5T_ENUM:
1654  {
1655  hid_t base_hdf_typeid;
1656  nc_type base_nc_type = NC_NAT;
1657  void *value;
1658  int i;
1659  char *member_name = NULL;
1660 #ifdef JNA
1661  char jna[1001];
1662 #endif
1663 
1664  type->nc_type_class = NC_ENUM;
1665 
1666  /* Find the base type of this enum (i.e. what is this a
1667  * enum of?) */
1668  if (!(base_hdf_typeid = H5Tget_super(hdf_typeid)))
1669  return NC_EHDFERR;
1670  /* What size is this type? */
1671  if (!(type_size = H5Tget_size(base_hdf_typeid)))
1672  return NC_EHDFERR;
1673  /* What is the netcdf corresponding type. */
1674  if ((retval = get_netcdf_type(grp->nc4_info, base_hdf_typeid,
1675  &base_nc_type)))
1676  return retval;
1677  LOG((5, "base_hdf_typeid 0x%x type_size %d base_nc_type %d",
1678  base_hdf_typeid, type_size, base_nc_type));
1679 
1680  /* Remember the base types for this enum */
1681  type->u.e.base_nc_typeid = base_nc_type;
1682  type->u.e.base_hdf_typeid = base_hdf_typeid;
1683 
1684  /* Find out how many member are in the enum. */
1685  if ((type->u.e.num_members = H5Tget_nmembers(hdf_typeid)) < 0)
1686  return NC_EHDFERR;
1687 
1688  /* Allocate space for one value. */
1689  if (!(value = calloc(1, type_size)))
1690  return NC_ENOMEM;
1691 
1692  /* Read each name and value defined in the enum. */
1693  for (i = 0; i < type->u.e.num_members; i++)
1694  {
1695 
1696  /* Get the name and value from HDF5. */
1697  if (!(member_name = H5Tget_member_name(hdf_typeid, i)))
1698  {
1699  retval = NC_EHDFERR;
1700  break;
1701  }
1702 #ifdef JNA
1703  strncpy(jna,member_name,1000);
1704  member_name = jna;
1705 #endif
1706 
1707  if (strlen(member_name) > NC_MAX_NAME)
1708  {
1709  retval = NC_EBADNAME;
1710  break;
1711  }
1712  if (H5Tget_member_value(hdf_typeid, i, value) < 0)
1713  {
1714  retval = NC_EHDFERR;
1715  break;
1716  }
1717 
1718  /* Insert new field into this type's list of fields. */
1719  if ((retval = nc4_enum_member_add(&type->u.e.enum_member, type->size,
1720  member_name, value)))
1721  {
1722  break;
1723  }
1724 
1725  hdf5free(member_name);
1726  member_name = NULL;
1727  }
1728  hdf5free(member_name);
1729  member_name = NULL;
1730  if(value) free(value);
1731  if(retval) /* error exit from loop */
1732  return retval;
1733  }
1734  break;
1735 
1736  default:
1737  LOG((0, "unknown class"));
1738  return NC_EBADCLASS;
1739  }
1740  return retval;
1741 }
1742 
1760 static int
1761 read_var(NC_GRP_INFO_T *grp, hid_t datasetid, const char *obj_name,
1762  size_t ndims, NC_DIM_INFO_T *dim)
1763 {
1764  NC_VAR_INFO_T *var = NULL;
1765  hid_t access_pid = 0;
1766  int incr_id_rc = 0; /* Whether the dataset ID's ref count has been incremented */
1767  int d;
1768  att_iter_info att_info; /* Custom iteration information */
1769  H5Z_filter_t filter;
1770  int num_filters;
1771  unsigned int cd_values_zip[CD_NELEMS_ZLIB];
1772  size_t cd_nelems = CD_NELEMS_ZLIB;
1773  hid_t propid = 0;
1774  H5D_fill_value_t fill_status;
1775  H5D_layout_t layout;
1776  hsize_t chunksize[NC_MAX_VAR_DIMS] = {0};
1777  int retval = NC_NOERR;
1778  double rdcc_w0;
1779  int f;
1780 
1781  assert(obj_name && grp);
1782  LOG((4, "%s: obj_name %s", __func__, obj_name));
1783 
1784  /* Add a variable to the end of the group's var list. */
1785  if ((retval = nc4_var_add(&var)))
1786  BAIL(retval);
1787 
1788  /* Fill in what we already know. */
1789  var->hdf_datasetid = datasetid;
1790  H5Iinc_ref(var->hdf_datasetid); /* Increment number of objects using ID */
1791  incr_id_rc++; /* Indicate that we've incremented the ref. count (for errors) */
1792  var->varid = grp->nvars++;
1793  var->created = NC_TRUE;
1794  var->ndims = ndims;
1795 
1796  /* We need some room to store information about dimensions for this
1797  * var. */
1798  if (var->ndims)
1799  {
1800  if (!(var->dim = calloc(var->ndims, sizeof(NC_DIM_INFO_T *))))
1801  BAIL(NC_ENOMEM);
1802  if (!(var->dimids = calloc(var->ndims, sizeof(int))))
1803  BAIL(NC_ENOMEM);
1804  }
1805 
1806  /* Get the current chunk cache settings. */
1807  if ((access_pid = H5Dget_access_plist(datasetid)) < 0)
1808  BAIL(NC_EVARMETA);
1809 
1810  /* Learn about current chunk cache settings. */
1811  if ((H5Pget_chunk_cache(access_pid, &(var->chunk_cache_nelems),
1812  &(var->chunk_cache_size), &rdcc_w0)) < 0)
1813  BAIL(NC_EHDFERR);
1814  var->chunk_cache_preemption = rdcc_w0;
1815 
1816  /* Check for a weird case: a non-coordinate variable that has the
1817  * same name as a dimension. It's legal in netcdf, and requires
1818  * that the HDF5 dataset name be changed. */
1819  if (strlen(obj_name) > strlen(NON_COORD_PREPEND) &&
1820  !strncmp(obj_name, NON_COORD_PREPEND, strlen(NON_COORD_PREPEND)))
1821  {
1822  /* Allocate space for the name. */
1823  if (!(var->name = malloc(((strlen(obj_name) - strlen(NON_COORD_PREPEND))+ 1) * sizeof(char))))
1824  BAIL(NC_ENOMEM);
1825 
1826  strcpy(var->name, &obj_name[strlen(NON_COORD_PREPEND)]);
1827 
1828  /* Allocate space for the HDF5 name. */
1829  if (!(var->hdf5_name = malloc((strlen(obj_name) + 1) * sizeof(char))))
1830  BAIL(NC_ENOMEM);
1831 
1832  strcpy(var->hdf5_name, obj_name);
1833  }
1834  else
1835  {
1836  /* Allocate space for the name. */
1837  if (!(var->name = malloc((strlen(obj_name) + 1) * sizeof(char))))
1838  BAIL(NC_ENOMEM);
1839 
1840  strcpy(var->name, obj_name);
1841  }
1842 
1843  var->hash = hash_fast(var->name, strlen(var->name));
1844  /* Find out what filters are applied to this HDF5 dataset,
1845  * fletcher32, deflate, and/or shuffle. All other filters are
1846  * just dumped */
1847  if ((propid = H5Dget_create_plist(datasetid)) < 0)
1848  BAIL(NC_EHDFERR);
1849 
1850  /* Get the chunking info for non-scalar vars. */
1851  if ((layout = H5Pget_layout(propid)) < -1)
1852  BAIL(NC_EHDFERR);
1853  if (layout == H5D_CHUNKED)
1854  {
1855  if (H5Pget_chunk(propid, NC_MAX_VAR_DIMS, chunksize) < 0)
1856  BAIL(NC_EHDFERR);
1857  if (!(var->chunksizes = malloc(var->ndims * sizeof(size_t))))
1858  BAIL(NC_ENOMEM);
1859  for (d = 0; d < var->ndims; d++)
1860  var->chunksizes[d] = chunksize[d];
1861  }
1862  else if (layout == H5D_CONTIGUOUS || layout == H5D_COMPACT)
1863  var->contiguous = NC_TRUE;
1864 
1865  /* The possible values of filter (which is just an int) can be
1866  * found in H5Zpublic.h. */
1867  if ((num_filters = H5Pget_nfilters(propid)) < 0)
1868  BAIL(NC_EHDFERR);
1869  for (f = 0; f < num_filters; f++)
1870  {
1871  if ((filter = H5Pget_filter2(propid, f, NULL, &cd_nelems,
1872  cd_values_zip, 0, NULL, NULL)) < 0)
1873  BAIL(NC_EHDFERR);
1874  switch (filter)
1875  {
1876  case H5Z_FILTER_SHUFFLE:
1877  var->shuffle = NC_TRUE;
1878  break;
1879 
1880  case H5Z_FILTER_FLETCHER32:
1881  var->fletcher32 = NC_TRUE;
1882  break;
1883 
1884  case H5Z_FILTER_DEFLATE:
1885  var->deflate = NC_TRUE;
1886  if (cd_nelems != CD_NELEMS_ZLIB || cd_values_zip[0] > NC_MAX_DEFLATE_LEVEL)
1887  BAIL(NC_EHDFERR);
1888  var->deflate_level = cd_values_zip[0];
1889  break;
1890 
1891  default:
1892  var->filterid = filter;
1893  var->nparams = cd_nelems;
1894  if(cd_nelems == 0)
1895  var->params = NULL;
1896  else {
1897  /* We have to re-read the parameters based on actual nparams */
1898  var->params = (unsigned int*)calloc(1,sizeof(unsigned int)*var->nparams);
1899  if(var->params == NULL)
1900  BAIL(NC_ENOMEM);
1901  if((filter = H5Pget_filter2(propid, f, NULL, &cd_nelems,
1902  var->params, 0, NULL, NULL)) < 0)
1903  BAIL(NC_EHDFERR);
1904  }
1905  break;
1906  }
1907  }
1908 
1909  /* Learn all about the type of this variable. */
1910  if ((retval = get_type_info2(grp->nc4_info, datasetid,
1911  &var->type_info)))
1912  BAIL(retval);
1913 
1914  /* Indicate that the variable has a pointer to the type */
1915  var->type_info->rc++;
1916 
1917  /* Is there a fill value associated with this dataset? */
1918  if (H5Pfill_value_defined(propid, &fill_status) < 0)
1919  BAIL(NC_EHDFERR);
1920 
1921  /* Get the fill value, if there is one defined. */
1922  if (fill_status == H5D_FILL_VALUE_USER_DEFINED)
1923  {
1924  /* Allocate space to hold the fill value. */
1925  if (!var->fill_value)
1926  {
1927  if (var->type_info->nc_type_class == NC_VLEN)
1928  {
1929  if (!(var->fill_value = malloc(sizeof(nc_vlen_t))))
1930  BAIL(NC_ENOMEM);
1931  }
1932  else if (var->type_info->nc_type_class == NC_STRING)
1933  {
1934  if (!(var->fill_value = malloc(sizeof(char *))))
1935  BAIL(NC_ENOMEM);
1936  }
1937  else
1938  {
1939  assert(var->type_info->size);
1940  if (!(var->fill_value = malloc(var->type_info->size)))
1941  BAIL(NC_ENOMEM);
1942  }
1943  }
1944 
1945  /* Get the fill value from the HDF5 property lust. */
1946  if (H5Pget_fill_value(propid, var->type_info->native_hdf_typeid,
1947  var->fill_value) < 0)
1948  BAIL(NC_EHDFERR);
1949  }
1950  else
1951  var->no_fill = NC_TRUE;
1952 
1953  /* If it's a scale, mark it as such. */
1954  if (dim)
1955  {
1956  assert(ndims);
1957  var->dimscale = NC_TRUE;
1958  if (var->ndims > 1)
1959  {
1960  if ((retval = read_coord_dimids(grp, var)))
1961  BAIL(retval);
1962  }
1963  else
1964  {
1965  /* sanity check */
1966  assert(0 == strcmp(var->name, dim->name));
1967 
1968  var->dimids[0] = dim->dimid;
1969  var->dim[0] = dim;
1970  }
1971  dim->coord_var = var;
1972  }
1973  /* If this is not a scale, but has scales, iterate
1974  * through them. (i.e. this is a variable that is not a
1975  * coordinate variable) */
1976  else
1977  {
1978  int num_scales = 0;
1979 
1980  /* Find out how many scales are attached to this
1981  * dataset. H5DSget_num_scales returns an error if there are no
1982  * scales, so convert a negative return value to zero. */
1983  num_scales = H5DSget_num_scales(datasetid, 0);
1984  if (num_scales < 0)
1985  num_scales = 0;
1986 
1987  if (num_scales && ndims)
1988  {
1989  /* Allocate space to remember whether the dimscale has been attached
1990  * for each dimension. */
1991  if (NULL == (var->dimscale_attached = calloc(ndims, sizeof(nc_bool_t))))
1992  BAIL(NC_ENOMEM);
1993 
1994  /* Store id information allowing us to match hdf5
1995  * dimscales to netcdf dimensions. */
1996  if (NULL == (var->dimscale_hdf5_objids = malloc(ndims * sizeof(struct hdf5_objid))))
1997  BAIL(NC_ENOMEM);
1998  for (d = 0; d < var->ndims; d++)
1999  {
2000  if (H5DSiterate_scales(var->hdf_datasetid, d, NULL, dimscale_visitor,
2001  &(var->dimscale_hdf5_objids[d])) < 0)
2002  BAIL(NC_EHDFERR);
2003  var->dimscale_attached[d] = NC_TRUE;
2004  }
2005  }
2006  }
2007 
2008  /* Now read all the attributes of this variable, ignoring the
2009  ones that hold HDF5 dimension scale information. */
2010 
2011  att_info.var = var;
2012  att_info.grp = grp;
2013 
2014  if ((H5Aiterate2(var->hdf_datasetid, H5_INDEX_CRT_ORDER, H5_ITER_INC, NULL,
2015  att_read_var_callbk, &att_info)) < 0)
2016  BAIL(NC_EATTMETA);
2017 
2018  /* Add a var to the variable array, growing it as needed. */
2019  if ((retval = nc4_vararray_add(grp, var)))
2020  BAIL(retval);
2021 
2022  /* Is this a deflated variable with a chunksize greater than the
2023  * current cache size? */
2024  if ((retval = nc4_adjust_var_cache(grp, var)))
2025  BAIL(retval);
2026 
2027 exit:
2028  if (retval)
2029  {
2030  if (incr_id_rc && H5Idec_ref(datasetid) < 0)
2031  BAIL2(NC_EHDFERR);
2032  if (var && nc4_var_del(var))
2033  BAIL2(NC_EHDFERR);
2034  }
2035  if (access_pid && H5Pclose(access_pid) < 0)
2036  BAIL2(NC_EHDFERR);
2037  if (propid > 0 && H5Pclose(propid) < 0)
2038  BAIL2(NC_EHDFERR);
2039  return retval;
2040 }
2041 
2053 static int
2054 read_grp_atts(NC_GRP_INFO_T *grp)
2055 {
2056  hid_t attid = -1;
2057  hsize_t num_obj, i;
2058  NC_ATT_INFO_T *att;
2059  NC_TYPE_INFO_T *type;
2060  char obj_name[NC_MAX_HDF5_NAME + 1];
2061  int max_len;
2062  int retval = NC_NOERR;
2063  int hidden = 0;
2064 
2065  num_obj = H5Aget_num_attrs(grp->hdf_grpid);
2066  for (i = 0; i < num_obj; i++)
2067  {
2068  if ((attid = H5Aopen_idx(grp->hdf_grpid, (unsigned int)i)) < 0)
2069  BAIL(NC_EATTMETA);
2070  if (H5Aget_name(attid, NC_MAX_NAME + 1, obj_name) < 0)
2071  BAIL(NC_EATTMETA);
2072  LOG((3, "reading attribute of _netCDF group, named %s", obj_name));
2073 
2074  /* See if this a hidden, global attribute */
2075  if(grp->nc4_info->root_grp == grp) {
2076  const char** reserved = NC_RESERVED_ATT_LIST;
2077  hidden = 0;
2078  for(;*reserved;reserved++) {
2079  if(strcmp(*reserved,obj_name)==0) {
2080  hidden = 1;
2081  break;
2082  }
2083  }
2084  }
2085 
2086  /* This may be an attribute telling us that strict netcdf-3
2087  * rules are in effect. If so, we will make note of the fact,
2088  * but not add this attribute to the metadata. It's not a user
2089  * attribute, but an internal netcdf-4 one. */
2090  if(strcmp(obj_name, NC3_STRICT_ATT_NAME)==0)
2091  grp->nc4_info->cmode |= NC_CLASSIC_MODEL;
2092  else if(!hidden) {
2093  /* Add an att struct at the end of the list, and then go to it. */
2094  if ((retval = nc4_att_list_add(&grp->att, &att)))
2095  BAIL(retval);
2096 
2097  /* Add the info about this attribute. */
2098  max_len = strlen(obj_name) > NC_MAX_NAME ? NC_MAX_NAME : strlen(obj_name);
2099  if (!(att->name = malloc((max_len + 1) * sizeof(char))))
2100  BAIL(NC_ENOMEM);
2101  strncpy(att->name, obj_name, max_len);
2102  att->name[max_len] = 0;
2103  att->attnum = grp->natts++;
2104  retval = read_hdf5_att(grp, attid, att);
2105  if(retval == NC_EBADTYPID) {
2106  if((retval = nc4_att_list_del(&grp->att, att)))
2107  BAIL(retval);
2108  } else if(retval) {
2109  BAIL(retval);
2110  } else {
2111  att->created = NC_TRUE;
2112  if ((retval = nc4_find_type(grp->nc4_info, att->nc_typeid, &type)))
2113  BAIL(retval);
2114  }
2115  }
2116  /* Unconditionally close the open attribute */
2117  H5Aclose(attid);
2118  attid = -1;
2119  }
2120 
2121 exit:
2122  if (attid > 0) {
2123  if(H5Aclose(attid) < 0)
2124  BAIL2(NC_EHDFERR);
2125  }
2126  return retval;
2127 }
2128 
2143 static int
2144 read_dataset(NC_GRP_INFO_T *grp, hid_t datasetid, const char *obj_name,
2145  const H5G_stat_t *statbuf)
2146 {
2147  NC_DIM_INFO_T *dim = NULL; /* Dimension created for scales */
2148  hid_t spaceid = 0;
2149  int ndims;
2150  htri_t is_scale;
2151  int retval = NC_NOERR;
2152 
2153  /* Get the dimension information for this dataset. */
2154  if ((spaceid = H5Dget_space(datasetid)) < 0)
2155  BAIL(NC_EHDFERR);
2156  if ((ndims = H5Sget_simple_extent_ndims(spaceid)) < 0)
2157  BAIL(NC_EHDFERR);
2158 
2159  /* Is this a dimscale? */
2160  if ((is_scale = H5DSis_scale(datasetid)) < 0)
2161  BAIL(NC_EHDFERR);
2162  if (is_scale)
2163  {
2164  hsize_t dims[H5S_MAX_RANK];
2165  hsize_t max_dims[H5S_MAX_RANK];
2166 
2167  /* Query the scale's size & max. size */
2168  if (H5Sget_simple_extent_dims(spaceid, dims, max_dims) < 0)
2169  BAIL(NC_EHDFERR);
2170 
2171  /* Read the scale information. */
2172  if ((retval = read_scale(grp, datasetid, obj_name, statbuf, dims[0],
2173  max_dims[0], &dim)))
2174  BAIL(retval);
2175  }
2176 
2177  /* Add a var to the linked list, and get its metadata,
2178  * unless this is one of those funny dimscales that are a
2179  * dimension in netCDF but not a variable. (Spooky!) */
2180  if (NULL == dim || (dim && !dim->hdf_dimscaleid))
2181  if ((retval = read_var(grp, datasetid, obj_name, ndims, dim)))
2182  BAIL(retval);
2183 
2184 exit:
2185  if (spaceid && H5Sclose(spaceid) <0)
2186  BAIL2(retval);
2187 
2188  return retval;
2189 }
2190 
2202 static int
2203 nc4_rec_read_metadata_cb_list_add(NC4_rec_read_metadata_obj_info_t **head,
2204  NC4_rec_read_metadata_obj_info_t **tail,
2205  const NC4_rec_read_metadata_obj_info_t *oinfo)
2206 {
2207  NC4_rec_read_metadata_obj_info_t *new_oinfo; /* Pointer to info for object */
2208 
2209  /* Allocate memory for the object's info */
2210  if (!(new_oinfo = calloc(1, sizeof(*new_oinfo))))
2211  return NC_ENOMEM;
2212 
2213  /* Make a copy of the object's info */
2214  memcpy(new_oinfo, oinfo, sizeof(*oinfo));
2215 
2216  if (*tail)
2217  {
2218  assert(*head);
2219  (*tail)->next = new_oinfo;
2220  *tail = new_oinfo;
2221  }
2222  else
2223  {
2224  assert(NULL == *head);
2225  *head = *tail = new_oinfo;
2226  }
2227 
2228  return (NC_NOERR);
2229 }
2230 
2243 static int
2244 nc4_rec_read_metadata_cb(hid_t grpid, const char *name, const H5L_info_t *info,
2245  void *_op_data)
2246 {
2247  NC4_rec_read_metadata_ud_t *udata = (NC4_rec_read_metadata_ud_t *)_op_data; /* Pointer to user data for callback */
2248  NC4_rec_read_metadata_obj_info_t oinfo; /* Pointer to info for object */
2249  int retval = H5_ITER_CONT;
2250 
2251  /* Reset the memory for the object's info */
2252  memset(&oinfo, 0, sizeof(oinfo));
2253 
2254  /* Open this critter. */
2255  if ((oinfo.oid = H5Oopen(grpid, name, H5P_DEFAULT)) < 0)
2256  BAIL(H5_ITER_ERROR);
2257 
2258  /* Get info about the object.*/
2259  if (H5Gget_objinfo(oinfo.oid, ".", 1, &oinfo.statbuf) < 0)
2260  BAIL(H5_ITER_ERROR);
2261 
2262  strncpy(oinfo.oname, name, NC_MAX_NAME);
2263 
2264  /* Add object to list, for later */
2265  switch(oinfo.statbuf.type)
2266  {
2267  case H5G_GROUP:
2268  LOG((3, "found group %s", oinfo.oname));
2269 
2270  /* Defer descending into child group immediately, so that the types
2271  * in the current group can be processed and be ready for use by
2272  * vars in the child group(s).
2273  */
2274  if (nc4_rec_read_metadata_cb_list_add(&udata->grps_head, &udata->grps_tail, &oinfo))
2275  BAIL(H5_ITER_ERROR);
2276  break;
2277 
2278  case H5G_DATASET:
2279  LOG((3, "found dataset %s", oinfo.oname));
2280 
2281  /* Learn all about this dataset, which may be a dimscale
2282  * (i.e. dimension metadata), or real data. */
2283  if ((retval = read_dataset(udata->grp, oinfo.oid, oinfo.oname, &oinfo.statbuf)))
2284  {
2285  /* Allow NC_EBADTYPID to transparently skip over datasets
2286  * which have a datatype that netCDF-4 doesn't undertand
2287  * (currently), but break out of iteration for other
2288  * errors.
2289  */
2290  if(NC_EBADTYPID != retval)
2291  BAIL(H5_ITER_ERROR);
2292  else
2293  retval = H5_ITER_CONT;
2294  }
2295 
2296  /* Close the object */
2297  if (H5Oclose(oinfo.oid) < 0)
2298  BAIL(H5_ITER_ERROR);
2299  break;
2300 
2301  case H5G_TYPE:
2302  LOG((3, "found datatype %s", oinfo.oname));
2303 
2304  /* Process the named datatype */
2305  if (read_type(udata->grp, oinfo.oid, oinfo.oname))
2306  BAIL(H5_ITER_ERROR);
2307 
2308  /* Close the object */
2309  if (H5Oclose(oinfo.oid) < 0)
2310  BAIL(H5_ITER_ERROR);
2311  break;
2312 
2313  default:
2314  LOG((0, "Unknown object class %d in %s!", oinfo.statbuf.type, __func__));
2315  BAIL(H5_ITER_ERROR);
2316  }
2317 
2318 exit:
2319  if (retval)
2320  {
2321  if (oinfo.oid > 0 && H5Oclose(oinfo.oid) < 0)
2322  BAIL2(H5_ITER_ERROR);
2323  }
2324 
2325  return (retval);
2326 }
2327 
2342 static int
2343 nc4_rec_read_metadata(NC_GRP_INFO_T *grp)
2344 {
2345  NC4_rec_read_metadata_ud_t udata; /* User data for iteration */
2346  NC4_rec_read_metadata_obj_info_t *oinfo; /* Pointer to info for object */
2347  hsize_t idx=0;
2348  hid_t pid = 0;
2349  unsigned crt_order_flags = 0;
2350  H5_index_t iter_index;
2351  int i, retval = NC_NOERR; /* everything worked! */
2352 
2353  assert(grp && grp->name);
2354  LOG((3, "%s: grp->name %s", __func__, grp->name));
2355 
2356  /* Portably initialize user data for later */
2357  memset(&udata, 0, sizeof(udata));
2358 
2359  /* Open this HDF5 group and retain its grpid. It will remain open
2360  * with HDF5 until this file is nc_closed. */
2361  if (!grp->hdf_grpid)
2362  {
2363  if (grp->parent)
2364  {
2365  if ((grp->hdf_grpid = H5Gopen2(grp->parent->hdf_grpid,
2366  grp->name, H5P_DEFAULT)) < 0)
2367  BAIL(NC_EHDFERR);
2368  }
2369  else
2370  {
2371  if ((grp->hdf_grpid = H5Gopen2(grp->nc4_info->hdfid,
2372  "/", H5P_DEFAULT)) < 0)
2373  BAIL(NC_EHDFERR);
2374  }
2375  }
2376  assert(grp->hdf_grpid > 0);
2377 
2378  /* Get the group creation flags, to check for creation ordering */
2379  pid = H5Gget_create_plist(grp->hdf_grpid);
2380  H5Pget_link_creation_order(pid, &crt_order_flags);
2381  if (H5Pclose(pid) < 0)
2382  BAIL(NC_EHDFERR);
2383 
2384  /* Set the iteration index to use */
2385  if (crt_order_flags & H5P_CRT_ORDER_TRACKED)
2386  iter_index = H5_INDEX_CRT_ORDER;
2387  else
2388  {
2389  NC_HDF5_FILE_INFO_T *h5 = grp->nc4_info;
2390 
2391  /* Without creation ordering, file must be read-only. */
2392  if (!h5->no_write)
2393  BAIL(NC_ECANTWRITE);
2394 
2395  iter_index = H5_INDEX_NAME;
2396  }
2397 
2398  /* Set user data for iteration */
2399  udata.grp = grp;
2400 
2401  /* Iterate over links in this group, building lists for the types,
2402  * datasets and groups encountered
2403  */
2404  if (H5Literate(grp->hdf_grpid, iter_index, H5_ITER_INC, &idx,
2405  nc4_rec_read_metadata_cb, (void *)&udata) < 0)
2406  BAIL(NC_EHDFERR);
2407 
2408  /* Process the child groups found */
2409  /* (Deferred until now, so that the types in the current group get
2410  * processed and are available for vars in the child group(s).)
2411  */
2412  for (oinfo = udata.grps_head; oinfo; oinfo = udata.grps_head)
2413  {
2414  NC_GRP_INFO_T *child_grp;
2415  NC_HDF5_FILE_INFO_T *h5 = grp->nc4_info;
2416 
2417  /* Add group to file's hierarchy */
2418  if ((retval = nc4_grp_list_add(&(grp->children), h5->next_nc_grpid++,
2419  grp, grp->nc4_info->controller, oinfo->oname, &child_grp)))
2420  BAIL(retval);
2421 
2422  /* Recursively read the child group's metadata */
2423  if ((retval = nc4_rec_read_metadata(child_grp)))
2424  BAIL(retval);
2425 
2426  /* Close the object */
2427  if (H5Oclose(oinfo->oid) < 0)
2428  BAIL(NC_EHDFERR);
2429 
2430  /* Advance to next node, free current node */
2431  udata.grps_head = oinfo->next;
2432  free(oinfo);
2433  }
2434 
2435  /* Scan the group for global (i.e. group-level) attributes. */
2436  if ((retval = read_grp_atts(grp)))
2437  BAIL(retval);
2438 
2439  /* when exiting define mode, mark all variable written */
2440  for (i=0; i<grp->vars.nelems; i++)
2441  grp->vars.value[i]->written_to = NC_TRUE;
2442 
2443 exit:
2444  /* Clean up local information on error, if anything remains */
2445  if (retval)
2446  {
2447  for (oinfo = udata.grps_head; oinfo; oinfo = udata.grps_head)
2448  {
2449  /* Close the object */
2450  if (H5Oclose(oinfo->oid) < 0)
2451  BAIL2(NC_EHDFERR);
2452 
2453  /* Advance to next node, free current node */
2454  udata.grps_head = oinfo->next;
2455  free(oinfo);
2456  }
2457  }
2458 
2459  return retval;
2460 }
2461 
2475 static int
2476 nc4_open_file(const char *path, int mode, void* parameters, NC *nc)
2477 {
2478  hid_t fapl_id = H5P_DEFAULT;
2479  unsigned flags = (mode & NC_WRITE) ?
2480  H5F_ACC_RDWR : H5F_ACC_RDONLY;
2481  int retval;
2482  NC_HDF5_FILE_INFO_T* nc4_info = NULL;
2483  int inmemory = ((mode & NC_INMEMORY) == NC_INMEMORY);
2484  NC_MEM_INFO* meminfo = (NC_MEM_INFO*)parameters;
2485 #ifdef USE_PARALLEL4
2486  NC_MPI_INFO* mpiinfo = (NC_MPI_INFO*)parameters;
2487  int comm_duped = 0; /* Whether the MPI Communicator was duplicated */
2488  int info_duped = 0; /* Whether the MPI Info object was duplicated */
2489 #endif /* !USE_PARALLEL4 */
2490 
2491  LOG((3, "%s: path %s mode %d", __func__, path, mode));
2492  assert(path && nc);
2493 
2494  /* Add necessary structs to hold netcdf-4 file data. */
2495  if ((retval = nc4_nc4f_list_add(nc, path, mode)))
2496  BAIL(retval);
2497  nc4_info = NC4_DATA(nc);
2498  assert(nc4_info && nc4_info->root_grp);
2499 
2500  /* Need this access plist to control how HDF5 handles open objects
2501  * on file close. (Setting H5F_CLOSE_SEMI will cause H5Fclose to
2502  * fail if there are any open objects in the file. */
2503  if ((fapl_id = H5Pcreate(H5P_FILE_ACCESS)) < 0)
2504  BAIL(NC_EHDFERR);
2505 
2506  if (H5Pset_fclose_degree(fapl_id, H5F_CLOSE_SEMI))
2507  BAIL(NC_EHDFERR);
2508 
2509 #ifdef USE_PARALLEL4
2510  /* If this is a parallel file create, set up the file creation
2511  property list. */
2512  if (mode & NC_MPIIO || mode & NC_MPIPOSIX)
2513  {
2514  nc4_info->parallel = NC_TRUE;
2515  if (mode & NC_MPIIO) /* MPI/IO */
2516  {
2517  LOG((4, "opening parallel file with MPI/IO"));
2518  if (H5Pset_fapl_mpio(fapl_id, mpiinfo->comm, mpiinfo->info) < 0)
2519  BAIL(NC_EPARINIT);
2520  }
2521 #ifdef USE_PARALLEL_POSIX
2522  else /* MPI/POSIX */
2523  {
2524  LOG((4, "opening parallel file with MPI/posix"));
2525  if (H5Pset_fapl_mpiposix(fapl_id, mpiinfo->comm, 0) < 0)
2526  BAIL(NC_EPARINIT);
2527  }
2528 #else /* USE_PARALLEL_POSIX */
2529  /* Should not happen! Code in NC4_create/NC4_open should alias the
2530  * NC_MPIPOSIX flag to NC_MPIIO, if the MPI-POSIX VFD is not
2531  * available in HDF5. -QAK
2532  */
2533  else /* MPI/POSIX */
2534  BAIL(NC_EPARINIT);
2535 #endif /* USE_PARALLEL_POSIX */
2536 
2537  /* Keep copies of the MPI Comm & Info objects */
2538  if (MPI_SUCCESS != MPI_Comm_dup(mpiinfo->comm, &nc4_info->comm))
2539  BAIL(NC_EMPI);
2540  comm_duped++;
2541  if (MPI_INFO_NULL != mpiinfo->info)
2542  {
2543  if (MPI_SUCCESS != MPI_Info_dup(mpiinfo->info, &nc4_info->info))
2544  BAIL(NC_EMPI);
2545  info_duped++;
2546  }
2547  else
2548  {
2549  /* No dup, just copy it. */
2550  nc4_info->info = mpiinfo->info;
2551  }
2552  }
2553 #else /* only set cache for non-parallel. */
2554  if (H5Pset_cache(fapl_id, 0, nc4_chunk_cache_nelems, nc4_chunk_cache_size,
2556  BAIL(NC_EHDFERR);
2557  LOG((4, "%s: set HDF raw chunk cache to size %d nelems %d preemption %f",
2559 #endif /* USE_PARALLEL4 */
2560 
2561  /* The NetCDF-3.x prototype contains an mode option NC_SHARE for
2562  multiple processes accessing the dataset concurrently. As there
2563  is no HDF5 equivalent, NC_SHARE is treated as NC_NOWRITE. */
2564 #ifdef HDF5_HAS_COLL_METADATA_OPS
2565  H5Pset_all_coll_metadata_ops(fapl_id, 1 );
2566 #endif
2567  if(inmemory) {
2568  if((nc4_info->hdfid = H5LTopen_file_image(meminfo->memory,meminfo->size,
2569  H5LT_FILE_IMAGE_DONT_COPY|H5LT_FILE_IMAGE_DONT_RELEASE
2570  )) < 0)
2571  BAIL(NC_EHDFERR);
2572  nc4_info->no_write = NC_TRUE;
2573  } else if ((nc4_info->hdfid = H5Fopen(path, flags, fapl_id)) < 0)
2574  BAIL(NC_EHDFERR);
2575 
2576  /* Does the mode specify that this file is read-only? */
2577  if ((mode & NC_WRITE) == 0)
2578  nc4_info->no_write = NC_TRUE;
2579 
2580  /* Now read in all the metadata. Some types and dimscale
2581  * information may be difficult to resolve here, if, for example, a
2582  * dataset of user-defined type is encountered before the
2583  * definition of that type. */
2584  if ((retval = nc4_rec_read_metadata(nc4_info->root_grp)))
2585  BAIL(retval);
2586 
2587  /* Now figure out which netCDF dims are indicated by the dimscale
2588  * information. */
2589  if ((retval = nc4_rec_match_dimscales(nc4_info->root_grp)))
2590  BAIL(retval);
2591 
2592 #ifdef LOGGING
2593  /* This will print out the names, types, lens, etc of the vars and
2594  atts in the file, if the logging level is 2 or greater. */
2595  log_metadata_nc(nc);
2596 #endif
2597 
2598  /* Close the property list. */
2599  if (H5Pclose(fapl_id) < 0)
2600  BAIL(NC_EHDFERR);
2601 
2602  NC4_get_fileinfo(nc4_info,NULL);
2603 
2604  return NC_NOERR;
2605 
2606 exit:
2607 #ifdef USE_PARALLEL4
2608  if (comm_duped) MPI_Comm_free(&nc4_info->comm);
2609  if (info_duped) MPI_Info_free(&nc4_info->info);
2610 #endif
2611  if (fapl_id != H5P_DEFAULT) H5Pclose(fapl_id);
2612  if (!nc4_info) return retval;
2613  close_netcdf4_file(nc4_info,1); /* treat like abort*/
2614  return retval;
2615 }
2616 
2633 int
2634 NC4_open(const char *path, int mode, int basepe, size_t *chunksizehintp,
2635  int use_parallel, void *parameters, NC_Dispatch *dispatch, NC *nc_file)
2636 {
2637  int res;
2638 #ifdef USE_PARALLEL4
2639  NC_MPI_INFO mpidfalt = {MPI_COMM_WORLD, MPI_INFO_NULL};
2640 #endif
2641 #if defined USE_PARALLEL4
2642  int inmemory = ((mode & NC_INMEMORY) == NC_INMEMORY);
2643 #endif
2644 
2645  assert(nc_file && path);
2646 
2647  LOG((1, "%s: path %s mode %d params %x",
2648  __func__, path, mode, parameters));
2649 
2650 #ifdef USE_PARALLEL4
2651  if (!inmemory && use_parallel && parameters == NULL)
2652  parameters = &mpidfalt;
2653 #endif /* USE_PARALLEL4 */
2654 
2655  /* If this is our first file, initialize HDF5. */
2656  if (!nc4_hdf5_initialized)
2657  nc4_hdf5_initialize();
2658 
2659  /* Check the mode for validity */
2660  if((mode & ILLEGAL_OPEN_FLAGS) != 0)
2661  {res = NC_EINVAL; goto done;}
2662 
2663  /* Cannot have both */
2664  if((mode & (NC_MPIIO|NC_MPIPOSIX)) == (NC_MPIIO|NC_MPIPOSIX))
2665  {res = NC_EINVAL; goto done;}
2666 
2667 #ifndef USE_PARALLEL_POSIX
2668 /* If the HDF5 library has been compiled without the MPI-POSIX VFD, alias
2669  * the NC_MPIPOSIX flag to NC_MPIIO. -QAK
2670  */
2671  if(mode & NC_MPIPOSIX)
2672  {
2673  mode &= ~NC_MPIPOSIX;
2674  mode |= NC_MPIIO;
2675  }
2676 #endif /* USE_PARALLEL_POSIX */
2677 
2678  /* This is a hdf5 file. */
2679  assert(nc_file->model == NC_FORMATX_NC4);
2680 
2681  /* Open the file. */
2682  nc_file->int_ncid = nc_file->ext_ncid;
2683  res = nc4_open_file(path, mode, parameters, nc_file);
2684 
2685 done:
2686  return res;
2687 }
2688 
2703 int
2704 NC4_set_fill(int ncid, int fillmode, int *old_modep)
2705 {
2706  NC *nc;
2707  NC_HDF5_FILE_INFO_T* nc4_info;
2708 
2709  LOG((2, "%s: ncid 0x%x fillmode %d", __func__, ncid, fillmode));
2710 
2711  if (!(nc = nc4_find_nc_file(ncid,&nc4_info)))
2712  return NC_EBADID;
2713  assert(nc4_info);
2714 
2715  /* Trying to set fill on a read-only file? You sicken me! */
2716  if (nc4_info->no_write)
2717  return NC_EPERM;
2718 
2719  /* Did you pass me some weird fillmode? */
2720  if (fillmode != NC_FILL && fillmode != NC_NOFILL)
2721  return NC_EINVAL;
2722 
2723  /* If the user wants to know, tell him what the old mode was. */
2724  if (old_modep)
2725  *old_modep = nc4_info->fill_mode;
2726 
2727  nc4_info->fill_mode = fillmode;
2728 
2729 
2730  return NC_NOERR;
2731 }
2732 
2742 int
2743 NC4_redef(int ncid)
2744 {
2745  NC_HDF5_FILE_INFO_T* nc4_info;
2746 
2747  LOG((1, "%s: ncid 0x%x", __func__, ncid));
2748 
2749  /* Find this file's metadata. */
2750  if (!(nc4_find_nc_file(ncid,&nc4_info)))
2751  return NC_EBADID;
2752  assert(nc4_info);
2753 
2754  /* If we're already in define mode, return an error. */
2755  if (nc4_info->flags & NC_INDEF)
2756  return NC_EINDEFINE;
2757 
2758  /* If the file is read-only, return an error. */
2759  if (nc4_info->no_write)
2760  return NC_EPERM;
2761 
2762  /* Set define mode. */
2763  nc4_info->flags |= NC_INDEF;
2764 
2765  /* For nc_abort, we need to remember if we're in define mode as a
2766  redef. */
2767  nc4_info->redef = NC_TRUE;
2768 
2769  return NC_NOERR;
2770 }
2771 
2785 int
2786 NC4__enddef(int ncid, size_t h_minfree, size_t v_align,
2787  size_t v_minfree, size_t r_align)
2788 {
2789  if (nc4_find_nc_file(ncid,NULL) == NULL)
2790  return NC_EBADID;
2791 
2792  return NC4_enddef(ncid);
2793 }
2794 
2804 static int NC4_enddef(int ncid)
2805 {
2806  NC *nc;
2807  NC_HDF5_FILE_INFO_T* nc4_info;
2808  NC_GRP_INFO_T *grp;
2809  int i;
2810 
2811  LOG((1, "%s: ncid 0x%x", __func__, ncid));
2812 
2813  if (!(nc = nc4_find_nc_file(ncid,&nc4_info)))
2814  return NC_EBADID;
2815  assert(nc4_info);
2816 
2817  /* Find info for this file and group */
2818  if (!(grp = nc4_rec_find_grp(nc4_info->root_grp, (ncid & GRP_ID_MASK))))
2819  return NC_EBADGRPID;
2820 
2821  /* when exiting define mode, mark all variable written */
2822  for (i=0; i<grp->vars.nelems; i++)
2823  grp->vars.value[i]->written_to = NC_TRUE;
2824 
2825  return nc4_enddef_netcdf4_file(nc4_info);
2826 }
2827 
2837 int
2838 NC4_sync(int ncid)
2839 {
2840  NC *nc;
2841  int retval;
2842  NC_HDF5_FILE_INFO_T* nc4_info;
2843 
2844  LOG((2, "%s: ncid 0x%x", __func__, ncid));
2845 
2846  if (!(nc = nc4_find_nc_file(ncid,&nc4_info)))
2847  return NC_EBADID;
2848  assert(nc4_info);
2849 
2850  /* If we're in define mode, we can't sync. */
2851  if (nc4_info && nc4_info->flags & NC_INDEF)
2852  {
2853  if (nc4_info->cmode & NC_CLASSIC_MODEL)
2854  return NC_EINDEFINE;
2855  if ((retval = NC4_enddef(ncid)))
2856  return retval;
2857  }
2858 
2859  return sync_netcdf4_file(nc4_info);
2860 }
2861 
2875 int
2876 NC4_abort(int ncid)
2877 {
2878  NC *nc;
2879  int delete_file = 0;
2880  char path[NC_MAX_NAME + 1];
2881  int retval = NC_NOERR;
2882  NC_HDF5_FILE_INFO_T* nc4_info;
2883 
2884  LOG((2, "%s: ncid 0x%x", __func__, ncid));
2885 
2886  /* Find metadata for this file. */
2887  if (!(nc = nc4_find_nc_file(ncid,&nc4_info)))
2888  return NC_EBADID;
2889 
2890  assert(nc4_info);
2891 
2892  /* If we're in define mode, but not redefing the file, delete it. */
2893  if (nc4_info->flags & NC_INDEF && !nc4_info->redef)
2894  {
2895  delete_file++;
2896  strncpy(path, nc->path,NC_MAX_NAME);
2897  }
2898 
2899  /* Free any resources the netcdf-4 library has for this file's
2900  * metadata. */
2901  if ((retval = close_netcdf4_file(nc4_info, 1)))
2902  return retval;
2903 
2904  /* Delete the file, if we should. */
2905  if (delete_file)
2906  if (remove(path) < 0)
2907  return NC_ECANTREMOVE;
2908 
2909  return retval;
2910 }
2911 
2920 int
2921 NC4_close(int ncid)
2922 {
2923  NC_GRP_INFO_T *grp;
2924  NC *nc;
2925  NC_HDF5_FILE_INFO_T *h5;
2926  int retval;
2927 
2928  LOG((1, "%s: ncid 0x%x", __func__, ncid));
2929 
2930  /* Find our metadata for this file. */
2931  if ((retval = nc4_find_nc_grp_h5(ncid, &nc, &grp, &h5)))
2932  return retval;
2933 
2934  assert(nc && h5 && grp);
2935 
2936  /* This must be the root group. */
2937  if (grp->parent)
2938  return NC_EBADGRPID;
2939 
2940  /* Call the nc4 close. */
2941  if ((retval = close_netcdf4_file(grp->nc4_info, 0)))
2942  return retval;
2943 
2944  return NC_NOERR;
2945 }
2946 
2964 int
2965 NC4_inq(int ncid, int *ndimsp, int *nvarsp, int *nattsp, int *unlimdimidp)
2966 {
2967  NC *nc;
2968  NC_HDF5_FILE_INFO_T *h5;
2969  NC_GRP_INFO_T *grp;
2970  NC_DIM_INFO_T *dim;
2971  NC_ATT_INFO_T *att;
2972  int retval;
2973 
2974  LOG((2, "%s: ncid 0x%x", __func__, ncid));
2975 
2976  /* Find file metadata. */
2977  if ((retval = nc4_find_nc_grp_h5(ncid, &nc, &grp, &h5)))
2978  return retval;
2979 
2980  assert(h5 && grp && nc);
2981 
2982  /* Count the number of dims, vars, and global atts. */
2983  if (ndimsp)
2984  {
2985  *ndimsp = 0;
2986  for (dim = grp->dim; dim; dim = dim->l.next)
2987  (*ndimsp)++;
2988  }
2989  if (nvarsp)
2990  {
2991  int i;
2992  *nvarsp = 0;
2993  for (i=0; i < grp->vars.nelems; i++)
2994  {
2995  if (grp->vars.value[i])
2996  (*nvarsp)++;
2997  }
2998  }
2999  if (nattsp)
3000  {
3001  *nattsp = 0;
3002  for (att = grp->att; att; att = att->l.next)
3003  (*nattsp)++;
3004  }
3005 
3006  if (unlimdimidp)
3007  {
3008  /* Default, no unlimited dimension */
3009  *unlimdimidp = -1;
3010 
3011  /* If there's more than one unlimited dim, which was not possible
3012  with netcdf-3, then only the last unlimited one will be reported
3013  back in xtendimp. */
3014  /* Note that this code is inconsistent with nc_inq_unlimid() */
3015  for (dim = grp->dim; dim; dim = dim->l.next)
3016  if (dim->unlimited)
3017  {
3018  *unlimdimidp = dim->dimid;
3019  break;
3020  }
3021  }
3022 
3023  return NC_NOERR;
3024 }
3025 
3034 int
3035 nc4_enddef_netcdf4_file(NC_HDF5_FILE_INFO_T *h5)
3036 {
3037  assert(h5);
3038  LOG((3, "%s", __func__));
3039 
3040  /* If we're not in define mode, return an error. */
3041  if (!(h5->flags & NC_INDEF))
3042  return NC_ENOTINDEFINE;
3043 
3044  /* Turn define mode off. */
3045  h5->flags ^= NC_INDEF;
3046 
3047  /* Redef mode needs to be tracked separately for nc_abort. */
3048  h5->redef = NC_FALSE;
3049 
3050  return sync_netcdf4_file(h5);
3051 }
3052 
struct NCPROPINFO globalpropinfo
Global property info.
Definition: nc4info.c:24
#define NC_ENOMEM
Memory allocation (malloc) failure.
Definition: netcdf.h:395
#define NC_CHAR
ISO/ASCII character.
Definition: netcdf.h:35
#define NC_ECANTWRITE
Can&#39;t write.
Definition: netcdf.h:429
#define NC_FORMATX_NC4
alias
Definition: netcdf.h:205
#define NC_UBYTE
unsigned 1 byte int
Definition: netcdf.h:41
#define NC_CLASSIC_MODEL
Enforce classic model on netCDF-4.
Definition: netcdf.h:135
#define NC_MAX_VAR_DIMS
max per variable dimensions
Definition: netcdf.h:266
#define NC_UINT
unsigned 4-byte int
Definition: netcdf.h:43
#define NC_NOCLOBBER
Don&#39;t destroy existing file.
Definition: netcdf.h:127
#define NC_INMEMORY
Read from memory.
Definition: netcdf.h:157
#define NC_EHDFERR
Error at HDF5 layer.
Definition: netcdf.h:427
#define NC_OPAQUE
opaque types
Definition: netcdf.h:53
#define NC_MPIIO
Turn on MPI I/O.
Definition: netcdf.h:152
#define NC_INT64
signed 8-byte int
Definition: netcdf.h:44
#define NC_STRING
string
Definition: netcdf.h:46
#define NC_ENOTINDEFINE
Operation not allowed in data mode.
Definition: netcdf.h:331
#define NC_DOUBLE
double precision floating point number
Definition: netcdf.h:40
#define NC_EBADCLASS
Bad class.
Definition: netcdf.h:446
int nc_type
The nc_type type is just an int.
Definition: netcdf.h:24
#define NC_64BIT_OFFSET
Use large (64-bit) file offsets.
Definition: netcdf.h:136
#define NC_NOWRITE
Set read-only access for nc_open().
Definition: netcdf.h:124
#define NC_BYTE
signed 1 byte integer
Definition: netcdf.h:34
#define NC_EINDEFINE
Operation not allowed in define mode.
Definition: netcdf.h:340
#define NC_FORMAT_CDF5
Format specifier for nc_set_default_format() and returned by nc_inq_format.
Definition: netcdf.h:181
#define NC_ENDIAN_LITTLE
In HDF5 files you can set the endianness of variables with nc_def_var_endian().
Definition: netcdf.h:276
#define NC_EATTMETA
Problem with attribute metadata.
Definition: netcdf.h:433
#define NUM_TYPES
Number of netCDF atomic types.
Definition: nc4file.c:674
#define NC_VLEN
vlen (variable-length) types
Definition: netcdf.h:52
#define NC_EMPI
MPI operation failed.
Definition: netcdf.h:457
#define NC_EDISKLESS
Error in using diskless access.
Definition: netcdf.h:455
int nc4_hdf5_initialized
True if initialization has happened.
Definition: nc4internal.c:57
#define NC_EFILEMETA
Problem with file metadata.
Definition: netcdf.h:431
#define NC_EBADTYPE
Not a netcdf data type.
Definition: netcdf.h:357
#define NC_EBADNAME
Attribute or variable name contains illegal characters.
Definition: netcdf.h:387
#define NC_MAX_DEFLATE_LEVEL
Maximum deflate level.
Definition: netcdf.h:307
size_t nc4_chunk_cache_nelems
Default chunk cache number of elements.
Definition: nc4file.c:671
#define NC_EINVAL
Invalid Argument.
Definition: netcdf.h:325
#define CD_NELEMS_ZLIB
Number of parameters needed for ZLIB filter.
Definition: nc4file.c:27
size_t nc4_chunk_cache_size
Default chunk cache size.
Definition: nc4file.c:670
#define NC_INT
signed 4 byte integer
Definition: netcdf.h:37
#define NC_EBADGRPID
Bad group ID.
Definition: netcdf.h:442
#define NC_NOFILL
Argument to nc_set_fill() to turn off filling of data.
Definition: netcdf.h:114
#define NC_ENDIAN_BIG
In HDF5 files you can set the endianness of variables with nc_def_var_endian().
Definition: netcdf.h:277
#define NC_MAX_NAME
Maximum for classic library.
Definition: netcdf.h:265
#define NC_ECANTREMOVE
Can&#39;t remove file.
Definition: netcdf.h:420
#define NC_NAT
Not A Type.
Definition: netcdf.h:33
#define NC_EBADTYPID
Bad type ID.
Definition: netcdf.h:443
#define NC_USHORT
unsigned 2-byte int
Definition: netcdf.h:42
int nc_set_chunk_cache(size_t size, size_t nelems, float preemption)
Set chunk cache size.
Definition: nc4file.c:712
#define NC_EPARINIT
Error initializing for parallel access.
Definition: netcdf.h:441
#define NC_NETCDF4
Use netCDF-4/HDF5 format.
Definition: netcdf.h:148
#define NC_EEXIST
netcdf file exists && NC_NOCLOBBER
Definition: netcdf.h:324
#define NC_FORMAT_NETCDF4_CLASSIC
Format specifier for nc_set_default_format() and returned by nc_inq_format.
Definition: netcdf.h:177
#define NC_EBADID
Not a netcdf id.
Definition: netcdf.h:322
#define NC_EVARMETA
Problem with variable metadata.
Definition: netcdf.h:434
This is the type of arrays of vlens.
Definition: netcdf.h:667
#define NC_MAX_UINT
Max or min values for a type.
Definition: netcdf.h:101
int nc_get_chunk_cache(size_t *sizep, size_t *nelemsp, float *preemptionp)
Get chunk cache size.
Definition: nc4file.c:734
#define NC_SHORT
signed 2 byte integer
Definition: netcdf.h:36
#define NC_CDF5
Alias NC_CDF5 to NC_64BIT_DATA.
Definition: netcdf.h:133
float nc4_chunk_cache_preemption
Default chunk cache preemption.
Definition: nc4file.c:672
#define NC_WRITE
Set read-write access for nc_open().
Definition: netcdf.h:125
#define NC_EPERM
Write to read only.
Definition: netcdf.h:326
#define NC_NOERR
No Error.
Definition: netcdf.h:315
#define NC_ENUM
enum types
Definition: netcdf.h:54
#define NC_DISKLESS
Use diskless file.
Definition: netcdf.h:129
#define NC_COMPOUND
compound types
Definition: netcdf.h:55
#define NC_FORMAT_64BIT_OFFSET
Format specifier for nc_set_default_format() and returned by nc_inq_format.
Definition: netcdf.h:174
#define NC_MMAP
Use diskless file with mmap.
Definition: netcdf.h:130
#define NC_FILL
Argument to nc_set_fill() to clear NC_NOFILL.
Definition: netcdf.h:113
#define NC_FLOAT
single precision floating point number
Definition: netcdf.h:39
#define NC_UINT64
unsigned 8-byte int
Definition: netcdf.h:45
#define NC_MPIPOSIX
Turn on MPI POSIX I/O.
Definition: netcdf.h:155

Return to the Main Unidata NetCDF page.
Generated on Wed Aug 1 2018 05:36:48 for NetCDF. NetCDF is a Unidata library.