NetCDF  4.6.0
nc4file.c
Go to the documentation of this file.
1 
12 #include "config.h"
13 #include <errno.h> /* netcdf functions sometimes return system errors */
14 #include "nc.h"
15 #include "nc4internal.h"
16 #include "nc4dispatch.h"
17 #include <H5DSpublic.h> /* must be after nc4internal.h */
18 #include <H5Fpublic.h>
19 #ifdef USE_HDF4
20 #include <mfhdf.h>
21 #endif
22 #include <hdf5_hl.h>
23 
24 extern int nc4_vararray_add(NC_GRP_INFO_T *grp, NC_VAR_INFO_T *var);
25 
28 #define LOGOPEN 1
29 
30 #define CD_NELEMS_ZLIB 1
40 static void
41 hdf5free(void* memory)
42 {
43 #ifndef JNA
44  /* On Windows using the microsoft runtime, it is an error
45  for one library to free memory allocated by a different library.*/
46 #ifdef HDF5_HAS_H5FREE
47  if(memory != NULL) H5free_memory(memory);
48 #else
49 #ifndef _MSC_VER
50  if(memory != NULL) free(memory);
51 #endif
52 #endif
53 #endif
54 }
55 
56 /* Custom iteration callback data */
57 typedef struct {
58  NC_GRP_INFO_T *grp;
59  NC_VAR_INFO_T *var;
60 } att_iter_info;
61 
62 
76 static int
77 get_netcdf_type(NC_HDF5_FILE_INFO_T *h5, hid_t native_typeid,
78  nc_type *xtype)
79 {
80  NC_TYPE_INFO_T *type;
81  H5T_class_t class;
82  htri_t is_str, equal = 0;
83 
84  assert(h5 && xtype);
85 
86  if ((class = H5Tget_class(native_typeid)) < 0)
87  return NC_EHDFERR;
88 
89  /* H5Tequal doesn't work with H5T_C_S1 for some reason. But
90  * H5Tget_class will return H5T_STRING if this is a string. */
91  if (class == H5T_STRING)
92  {
93  if ((is_str = H5Tis_variable_str(native_typeid)) < 0)
94  return NC_EHDFERR;
95  if (is_str)
96  *xtype = NC_STRING;
97  else
98  *xtype = NC_CHAR;
99  return NC_NOERR;
100  }
101  else if (class == H5T_INTEGER || class == H5T_FLOAT)
102  {
103  /* For integers and floats, we don't have to worry about
104  * endianness if we compare native types. */
105  if ((equal = H5Tequal(native_typeid, H5T_NATIVE_SCHAR)) < 0)
106  return NC_EHDFERR;
107  if (equal)
108  {
109  *xtype = NC_BYTE;
110  return NC_NOERR;
111  }
112  if ((equal = H5Tequal(native_typeid, H5T_NATIVE_SHORT)) < 0)
113  return NC_EHDFERR;
114  if (equal)
115  {
116  *xtype = NC_SHORT;
117  return NC_NOERR;
118  }
119  if ((equal = H5Tequal(native_typeid, H5T_NATIVE_INT)) < 0)
120  return NC_EHDFERR;
121  if (equal)
122  {
123  *xtype = NC_INT;
124  return NC_NOERR;
125  }
126  if ((equal = H5Tequal(native_typeid, H5T_NATIVE_FLOAT)) < 0)
127  return NC_EHDFERR;
128  if (equal)
129  {
130  *xtype = NC_FLOAT;
131  return NC_NOERR;
132  }
133  if ((equal = H5Tequal(native_typeid, H5T_NATIVE_DOUBLE)) < 0)
134  return NC_EHDFERR;
135  if (equal)
136  {
137  *xtype = NC_DOUBLE;
138  return NC_NOERR;
139  }
140  if ((equal = H5Tequal(native_typeid, H5T_NATIVE_UCHAR)) < 0)
141  return NC_EHDFERR;
142  if (equal)
143  {
144  *xtype = NC_UBYTE;
145  return NC_NOERR;
146  }
147  if ((equal = H5Tequal(native_typeid, H5T_NATIVE_USHORT)) < 0)
148  return NC_EHDFERR;
149  if (equal)
150  {
151  *xtype = NC_USHORT;
152  return NC_NOERR;
153  }
154  if ((equal = H5Tequal(native_typeid, H5T_NATIVE_UINT)) < 0)
155  return NC_EHDFERR;
156  if (equal)
157  {
158  *xtype = NC_UINT;
159  return NC_NOERR;
160  }
161  if ((equal = H5Tequal(native_typeid, H5T_NATIVE_LLONG)) < 0)
162  return NC_EHDFERR;
163  if (equal)
164  {
165  *xtype = NC_INT64;
166  return NC_NOERR;
167  }
168  if ((equal = H5Tequal(native_typeid, H5T_NATIVE_ULLONG)) < 0)
169  return NC_EHDFERR;
170  if (equal)
171  {
172  *xtype = NC_UINT64;
173  return NC_NOERR;
174  }
175  }
176 
177  /* Maybe we already know about this type. */
178  if (!equal)
179  if((type = nc4_rec_find_hdf_type(h5->root_grp, native_typeid)))
180  {
181  *xtype = type->nc_typeid;
182  return NC_NOERR;
183  }
184 
185  *xtype = NC_NAT;
186  return NC_EBADTYPID;
187 }
188 
200 static int
201 read_hdf5_att(NC_GRP_INFO_T *grp, hid_t attid, NC_ATT_INFO_T *att)
202 {
203  hid_t spaceid = 0, file_typeid = 0;
204  hsize_t dims[1] = {0}; /* netcdf attributes always 1-D. */
205  int retval = NC_NOERR;
206  size_t type_size;
207  int att_ndims;
208  hssize_t att_npoints;
209  H5T_class_t att_class;
210  int fixed_len_string = 0;
211  size_t fixed_size = 0;
212 
213  assert(att->name);
214  LOG((5, "%s: att->attnum %d att->name %s att->nc_typeid %d att->len %d",
215  __func__, att->attnum, att->name, (int)att->nc_typeid, att->len));
216 
217  /* Get type of attribute in file. */
218  if ((file_typeid = H5Aget_type(attid)) < 0)
219  return NC_EATTMETA;
220  if ((att->native_hdf_typeid = H5Tget_native_type(file_typeid, H5T_DIR_DEFAULT)) < 0)
221  BAIL(NC_EHDFERR);
222  if ((att_class = H5Tget_class(att->native_hdf_typeid)) < 0)
223  BAIL(NC_EATTMETA);
224  if (att_class == H5T_STRING && !H5Tis_variable_str(att->native_hdf_typeid))
225  {
226  fixed_len_string++;
227  if (!(fixed_size = H5Tget_size(att->native_hdf_typeid)))
228  BAIL(NC_EATTMETA);
229  }
230  if ((retval = get_netcdf_type(grp->nc4_info, att->native_hdf_typeid, &(att->nc_typeid))))
231  BAIL(retval);
232 
233 
234  /* Get len. */
235  if ((spaceid = H5Aget_space(attid)) < 0)
236  BAIL(NC_EATTMETA);
237  if ((att_ndims = H5Sget_simple_extent_ndims(spaceid)) < 0)
238  BAIL(NC_EATTMETA);
239  if ((att_npoints = H5Sget_simple_extent_npoints(spaceid)) < 0)
240  BAIL(NC_EATTMETA);
241 
242  /* If both att_ndims and att_npoints are zero, then this is a
243  * zero length att. */
244  if (att_ndims == 0 && att_npoints == 0)
245  dims[0] = 0;
246  else if (att->nc_typeid == NC_STRING)
247  dims[0] = att_npoints;
248  else if (att->nc_typeid == NC_CHAR)
249  {
250  /* NC_CHAR attributes are written as a scalar in HDF5, of type
251  * H5T_C_S1, of variable length. */
252  if (att_ndims == 0)
253  {
254  if (!(dims[0] = H5Tget_size(file_typeid)))
255  BAIL(NC_EATTMETA);
256  }
257  else
258  {
259  /* This is really a string type! */
260  att->nc_typeid = NC_STRING;
261  dims[0] = att_npoints;
262  }
263  }
264  else
265  {
266  H5S_class_t space_class;
267 
268  /* All netcdf attributes are scalar or 1-D only. */
269  if (att_ndims > 1)
270  BAIL(NC_EATTMETA);
271 
272  /* Check class of HDF5 dataspace */
273  if ((space_class = H5Sget_simple_extent_type(spaceid)) < 0)
274  BAIL(NC_EATTMETA);
275 
276  /* Check for NULL HDF5 dataspace class (should be weeded out earlier) */
277  if (H5S_NULL == space_class)
278  BAIL(NC_EATTMETA);
279 
280  /* check for SCALAR HDF5 dataspace class */
281  if (H5S_SCALAR == space_class)
282  dims[0] = 1;
283  else /* Must be "simple" dataspace */
284  {
285  /* Read the size of this attribute. */
286  if (H5Sget_simple_extent_dims(spaceid, dims, NULL) < 0)
287  BAIL(NC_EATTMETA);
288  }
289  }
290 
291  /* Tell the user what the length if this attribute is. */
292  att->len = dims[0];
293 
294  /* Allocate some memory if the len is not zero, and read the
295  attribute. */
296  if (dims[0])
297  {
298  if ((retval = nc4_get_typelen_mem(grp->nc4_info, att->nc_typeid, 0,
299  &type_size)))
300  return retval;
301  if (att_class == H5T_VLEN)
302  {
303  if (!(att->vldata = malloc((unsigned int)(att->len * sizeof(hvl_t)))))
304  BAIL(NC_ENOMEM);
305  if (H5Aread(attid, att->native_hdf_typeid, att->vldata) < 0)
306  BAIL(NC_EATTMETA);
307  }
308  else if (att->nc_typeid == NC_STRING)
309  {
310  if (!(att->stdata = calloc(att->len, sizeof(char *))))
311  BAIL(NC_ENOMEM);
312  /* For a fixed length HDF5 string, the read requires
313  * contiguous memory. Meanwhile, the netCDF API requires that
314  * nc_free_string be called on string arrays, which would not
315  * work if one contiguous memory block were used. So here I
316  * convert the contiguous block of strings into an array of
317  * malloced strings (each string with its own malloc). Then I
318  * copy the data and free the contiguous memory. This
319  * involves copying the data, which is bad, but this only
320  * occurs for fixed length string attributes, and presumably
321  * these are small. (And netCDF-4 does not create them - it
322  * always uses variable length strings. */
323  if (fixed_len_string)
324  {
325  int i;
326  char *contig_buf, *cur;
327 
328  /* Alloc space for the contiguous memory read. */
329  if (!(contig_buf = malloc(att->len * fixed_size * sizeof(char))))
330  BAIL(NC_ENOMEM);
331 
332  /* Read the fixed-len strings as one big block. */
333  if (H5Aread(attid, att->native_hdf_typeid, contig_buf) < 0) {
334  free(contig_buf);
335  BAIL(NC_EATTMETA);
336  }
337 
338  /* Copy strings, one at a time, into their new home. Alloc
339  space for each string. The user will later free this
340  space with nc_free_string. */
341  cur = contig_buf;
342  for (i = 0; i < att->len; i++)
343  {
344  if (!(att->stdata[i] = malloc(fixed_size))) {
345  free(contig_buf);
346  BAIL(NC_ENOMEM);
347  }
348  strncpy(att->stdata[i], cur, fixed_size);
349  cur += fixed_size;
350  }
351 
352  /* Free contiguous memory buffer. */
353  free(contig_buf);
354  }
355  else
356  {
357  /* Read variable-length string atts. */
358  if (H5Aread(attid, att->native_hdf_typeid, att->stdata) < 0)
359  BAIL(NC_EATTMETA);
360  }
361  }
362  else
363  {
364  if (!(att->data = malloc((unsigned int)(att->len * type_size))))
365  BAIL(NC_ENOMEM);
366  if (H5Aread(attid, att->native_hdf_typeid, att->data) < 0)
367  BAIL(NC_EATTMETA);
368  }
369  }
370 
371  if (H5Tclose(file_typeid) < 0)
372  BAIL(NC_EHDFERR);
373  if (H5Sclose(spaceid) < 0)
374  return NC_EHDFERR;
375 
376  return NC_NOERR;
377 
378 exit:
379  if (H5Tclose(file_typeid) < 0)
380  BAIL2(NC_EHDFERR);
381  if (spaceid > 0 && H5Sclose(spaceid) < 0)
382  BAIL2(NC_EHDFERR);
383  return retval;
384 }
385 
400 static herr_t
401 att_read_var_callbk(hid_t loc_id, const char *att_name, const H5A_info_t *ainfo, void *att_data)
402 {
403 
404  hid_t attid = 0;
405  int retval = NC_NOERR;
406  NC_ATT_INFO_T *att;
407  att_iter_info *att_info = (att_iter_info *)att_data;
408  const char** reserved;
409 
410  /* Should we ignore this attribute? */
411  for(reserved=NC_RESERVED_VARATT_LIST;*reserved;reserved++) {
412  if (strcmp(att_name, *reserved)==0) break;
413  }
414 
415  if(*reserved == NULL) {
416  /* Open the att by name. */
417  if ((attid = H5Aopen(loc_id, att_name, H5P_DEFAULT)) < 0)
418  BAIL(NC_EATTMETA);
419  LOG((4, "%s:: att_name %s", __func__, att_name));
420  /* Add to the end of the list of atts for this var. */
421  if ((retval = nc4_att_list_add(&att_info->var->att, &att)))
422  BAIL(retval);
423  /* Fill in the information we know. */
424  att->attnum = att_info->var->natts++;
425  if (!(att->name = strdup(att_name)))
426  BAIL(NC_ENOMEM);
427 
428  /* Read the rest of the info about the att,
429  * including its values. */
430  if ((retval = read_hdf5_att(att_info->grp, attid, att)))
431  {
432  if (NC_EBADTYPID == retval)
433  {
434  if ((retval = nc4_att_list_del(&att_info->var->att, att)))
435  BAIL(retval);
436  att = NULL;
437  }
438  else
439  BAIL(retval);
440  }
441 
442  if (att)
443  att->created = NC_TRUE;
444 
445  if (attid > 0 && H5Aclose(attid) < 0)
446  BAIL2(NC_EHDFERR);
447 
448  } /* endif not HDF5 att */
449 
450  return NC_NOERR;
451 
452 exit:
453  if (attid > 0 && H5Aclose(attid) < 0)
454  BAIL2(NC_EHDFERR);
455 
456  return retval;
457 }
458 
460 static const int ILLEGAL_OPEN_FLAGS = (NC_MMAP|NC_64BIT_OFFSET);
461 
463 static const int ILLEGAL_CREATE_FLAGS = (NC_NOWRITE|NC_MMAP|NC_INMEMORY|NC_64BIT_OFFSET|NC_CDF5);
464 
465 extern void reportopenobjects(int log, hid_t);
466 
471 typedef struct NC4_rec_read_metadata_obj_info
472 {
473  hid_t oid; /* HDF5 object ID */
474  char oname[NC_MAX_NAME + 1]; /* Name of object */
475  H5G_stat_t statbuf; /* Information about the object */
476  struct NC4_rec_read_metadata_obj_info *next; /* Pointer to next node in list */
477 } NC4_rec_read_metadata_obj_info_t;
478 
484 typedef struct NC4_rec_read_metadata_ud
485 {
486  NC4_rec_read_metadata_obj_info_t *grps_head, *grps_tail; /* Pointers to head & tail of list of groups */
487  NC_GRP_INFO_T *grp; /* Pointer to parent group */
488 } NC4_rec_read_metadata_ud_t;
489 
490 /* Forward */
491 static int NC4_enddef(int ncid);
492 static int nc4_rec_read_metadata(NC_GRP_INFO_T *grp);
493 
503 static int
504 sync_netcdf4_file(NC_HDF5_FILE_INFO_T *h5)
505 {
506  int retval;
507 
508  assert(h5);
509  LOG((3, "%s", __func__));
510 
511  /* If we're in define mode, that's an error, for strict nc3 rules,
512  * otherwise, end define mode. */
513  if (h5->flags & NC_INDEF)
514  {
515  if (h5->cmode & NC_CLASSIC_MODEL)
516  return NC_EINDEFINE;
517 
518  /* Turn define mode off. */
519  h5->flags ^= NC_INDEF;
520 
521  /* Redef mode needs to be tracked separately for nc_abort. */
522  h5->redef = NC_FALSE;
523  }
524 
525 #ifdef LOGGING
526  /* This will print out the names, types, lens, etc of the vars and
527  atts in the file, if the logging level is 2 or greater. */
528  log_metadata_nc(h5->root_grp->nc4_info->controller);
529 #endif
530 
531  /* Write any metadata that has changed. */
532  if (!(h5->cmode & NC_NOWRITE))
533  {
534  nc_bool_t bad_coord_order = NC_FALSE; /* if detected, propagate to all groups to consistently store dimids */
535 
536  if ((retval = nc4_rec_write_groups_types(h5->root_grp)))
537  return retval;
538  if ((retval = nc4_rec_detect_need_to_preserve_dimids(h5->root_grp, &bad_coord_order)))
539  return retval;
540  if ((retval = nc4_rec_write_metadata(h5->root_grp, bad_coord_order)))
541  return retval;
542  }
543 
544  if (H5Fflush(h5->hdfid, H5F_SCOPE_GLOBAL) < 0)
545  return NC_EHDFERR;
546 
547  return retval;
548 }
549 
561 static int
562 close_netcdf4_file(NC_HDF5_FILE_INFO_T *h5, int abort)
563 {
564  int retval = NC_NOERR;
565 
566  assert(h5 && h5->root_grp);
567  LOG((3, "%s: h5->path %s abort %d", __func__, h5->controller->path, abort));
568 
569  /* According to the docs, always end define mode on close. */
570  if (h5->flags & NC_INDEF)
571  h5->flags ^= NC_INDEF;
572 
573  /* Sync the file, unless we're aborting, or this is a read-only
574  * file. */
575  if (!h5->no_write && !abort)
576  if ((retval = sync_netcdf4_file(h5)))
577  goto exit;
578 
579  /* Delete all the list contents for vars, dims, and atts, in each
580  * group. */
581  if ((retval = nc4_rec_grp_del(&h5->root_grp, h5->root_grp)))
582  goto exit;
583 
584  /* Close hdf file. */
585 #ifdef USE_HDF4
586  if (h5->hdf4)
587  {
588  if (SDend(h5->sdid))
589  BAIL_QUIET(NC_EHDFERR);
590  }
591  else
592 #endif /* USE_HDF4 */
593  {
594 #ifdef USE_PARALLEL4
595  /* Free the MPI Comm & Info objects, if we opened the file in parallel */
596  if(h5->parallel)
597  {
598  if(MPI_COMM_NULL != h5->comm)
599  MPI_Comm_free(&h5->comm);
600  if(MPI_INFO_NULL != h5->info)
601  MPI_Info_free(&h5->info);
602  }
603 #endif
604 
605  if(h5->fileinfo) free(h5->fileinfo);
606 
607  if (H5Fclose(h5->hdfid) < 0)
608  {
609  int nobjs;
610 
611  nobjs = H5Fget_obj_count(h5->hdfid, H5F_OBJ_ALL);
612  /* Apparently we can get an error even when nobjs == 0 */
613  if(nobjs < 0) {
614  BAIL_QUIET(NC_EHDFERR);
615  } else if(nobjs > 0) {
616 #ifdef LOGGING
617  char msg[1024];
618  int logit = 1;
619  /* If the close doesn't work, probably there are still some HDF5
620  * objects open, which means there's a bug in the library. So
621  * print out some info on to help the poor programmer figure it
622  * out. */
623  snprintf(msg,sizeof(msg),"There are %d HDF5 objects open!", nobjs);
624 #ifdef LOGOPEN
625  LOG((0, msg));
626 #else
627  fprintf(stdout,msg);
628  logit = 0;
629 #endif
630  reportopenobjects(logit,h5->hdfid);
631 #endif
632  }
633  }
634  }
635 exit:
636  /* Free the nc4_info struct; above code should have reclaimed
637  everything else */
638  if(!retval && h5 != NULL)
639  free(h5);
640  return retval;
641 }
642 
648 const char* NC_RESERVED_VARATT_LIST[] = {
649  NC_ATT_REFERENCE_LIST,
650  NC_ATT_CLASS,
651  NC_ATT_DIMENSION_LIST,
652  NC_ATT_NAME,
653  NC_ATT_COORDINATES,
654  NC_DIMID_ATT_NAME,
655  NULL
656 };
657 
663 const char* NC_RESERVED_ATT_LIST[] = {
664  NC_ATT_FORMAT,
665  NC3_STRICT_ATT_NAME,
666  NCPROPS,
667  ISNETCDF4ATT,
668  SUPERBLOCKATT,
669  NULL
670 };
671 
676 const char* NC_RESERVED_SPECIAL_LIST[] = {
677  ISNETCDF4ATT,
678  SUPERBLOCKATT,
679  NCPROPS,
680  NULL
681 };
682 
683 size_t nc4_chunk_cache_size = CHUNK_CACHE_SIZE;
684 size_t nc4_chunk_cache_nelems = CHUNK_CACHE_NELEMS;
685 float nc4_chunk_cache_preemption = CHUNK_CACHE_PREEMPTION;
687 #define NUM_TYPES 12
692 static hid_t h5_native_type_constant_g[NUM_TYPES];
693 
695 static const char nc_type_name_g[NUM_TYPES][NC_MAX_NAME + 1] = {"char", "byte", "short",
696  "int", "float", "double", "ubyte",
697  "ushort", "uint", "int64",
698  "uint64", "string"};
699 
701 static const nc_type nc_type_constant_g[NUM_TYPES] = {NC_CHAR, NC_BYTE, NC_SHORT,
705 
707 static const int nc_type_size_g[NUM_TYPES] = {sizeof(char), sizeof(char), sizeof(short),
708  sizeof(int), sizeof(float), sizeof(double), sizeof(unsigned char),
709  sizeof(unsigned short), sizeof(unsigned int), sizeof(long long),
710  sizeof(unsigned long long), sizeof(char *)};
711 
724 int
725 nc_set_chunk_cache(size_t size, size_t nelems, float preemption)
726 {
727  if (preemption < 0 || preemption > 1)
728  return NC_EINVAL;
729  nc4_chunk_cache_size = size;
730  nc4_chunk_cache_nelems = nelems;
731  nc4_chunk_cache_preemption = preemption;
732  return NC_NOERR;
733 }
734 
746 int
747 nc_get_chunk_cache(size_t *sizep, size_t *nelemsp, float *preemptionp)
748 {
749  if (sizep)
750  *sizep = nc4_chunk_cache_size;
751 
752  if (nelemsp)
753  *nelemsp = nc4_chunk_cache_nelems;
754 
755  if (preemptionp)
756  *preemptionp = nc4_chunk_cache_preemption;
757  return NC_NOERR;
758 }
759 
771 int
772 nc_set_chunk_cache_ints(int size, int nelems, int preemption)
773 {
774  if (size <= 0 || nelems <= 0 || preemption < 0 || preemption > 100)
775  return NC_EINVAL;
776  nc4_chunk_cache_size = size;
777  nc4_chunk_cache_nelems = nelems;
778  nc4_chunk_cache_preemption = (float)preemption / 100;
779  return NC_NOERR;
780 }
781 
793 int
794 nc_get_chunk_cache_ints(int *sizep, int *nelemsp, int *preemptionp)
795 {
796  if (sizep)
797  *sizep = (int)nc4_chunk_cache_size;
798  if (nelemsp)
799  *nelemsp = (int)nc4_chunk_cache_nelems;
800  if (preemptionp)
801  *preemptionp = (int)(nc4_chunk_cache_preemption * 100);
802 
803  return NC_NOERR;
804 }
805 
814 int
815 nc4typelen(nc_type type)
816 {
817  switch(type){
818  case NC_BYTE:
819  case NC_CHAR:
820  case NC_UBYTE:
821  return 1;
822  case NC_USHORT:
823  case NC_SHORT:
824  return 2;
825  case NC_FLOAT:
826  case NC_INT:
827  case NC_UINT:
828  return 4;
829  case NC_DOUBLE:
830  case NC_INT64:
831  case NC_UINT64:
832  return 8;
833  }
834  return -1;
835 }
836 
853 static int
854 nc4_create_file(const char *path, int cmode, MPI_Comm comm, MPI_Info info,
855  NC *nc)
856 {
857  hid_t fcpl_id, fapl_id = -1;
858  unsigned flags;
859  FILE *fp;
860  int retval = NC_NOERR;
861  NC_HDF5_FILE_INFO_T* nc4_info = NULL;
862 #ifdef USE_PARALLEL4
863  int comm_duped = 0; /* Whether the MPI Communicator was duplicated */
864  int info_duped = 0; /* Whether the MPI Info object was duplicated */
865 #else /* !USE_PARALLEL4 */
866  int persist = 0; /* Should diskless try to persist its data into file?*/
867 #endif
868 
869  assert(nc && path);
870  LOG((3, "%s: path %s mode 0x%x", __func__, path, cmode));
871 
872  if(cmode & NC_DISKLESS)
873  flags = H5F_ACC_TRUNC;
874  else if(cmode & NC_NOCLOBBER)
875  flags = H5F_ACC_EXCL;
876  else
877  flags = H5F_ACC_TRUNC;
878 
879  /* If this file already exists, and NC_NOCLOBBER is specified,
880  return an error. */
881  if (cmode & NC_DISKLESS) {
882 #ifndef USE_PARALLEL4
883  if(cmode & NC_WRITE)
884  persist = 1;
885 #endif
886  } else if ((cmode & NC_NOCLOBBER) && (fp = fopen(path, "r"))) {
887  fclose(fp);
888  return NC_EEXIST;
889  }
890 
891  /* Add necessary structs to hold netcdf-4 file data. */
892  if ((retval = nc4_nc4f_list_add(nc, path, (NC_WRITE | cmode))))
893  BAIL(retval);
894  nc4_info = NC4_DATA(nc);
895  assert(nc4_info && nc4_info->root_grp);
896 
897  /* Need this access plist to control how HDF5 handles open objects
898  * on file close. (Setting H5F_CLOSE_SEMI will cause H5Fclose to
899  * fail if there are any open objects in the file. */
900  if ((fapl_id = H5Pcreate(H5P_FILE_ACCESS)) < 0)
901  BAIL(NC_EHDFERR);
902  if (H5Pset_fclose_degree(fapl_id, H5F_CLOSE_SEMI))
903  BAIL(NC_EHDFERR);
904 
905 #ifdef USE_PARALLEL4
906  /* If this is a parallel file create, set up the file creation
907  property list. */
908  if ((cmode & NC_MPIIO) || (cmode & NC_MPIPOSIX))
909  {
910  nc4_info->parallel = NC_TRUE;
911  if (cmode & NC_MPIIO) /* MPI/IO */
912  {
913  LOG((4, "creating parallel file with MPI/IO"));
914  if (H5Pset_fapl_mpio(fapl_id, comm, info) < 0)
915  BAIL(NC_EPARINIT);
916  }
917 #ifdef USE_PARALLEL_POSIX
918  else /* MPI/POSIX */
919  {
920  LOG((4, "creating parallel file with MPI/posix"));
921  if (H5Pset_fapl_mpiposix(fapl_id, comm, 0) < 0)
922  BAIL(NC_EPARINIT);
923  }
924 #else /* USE_PARALLEL_POSIX */
925  /* Should not happen! Code in NC4_create/NC4_open should alias the
926  * NC_MPIPOSIX flag to NC_MPIIO, if the MPI-POSIX VFD is not
927  * available in HDF5. -QAK
928  */
929  else /* MPI/POSIX */
930  BAIL(NC_EPARINIT);
931 #endif /* USE_PARALLEL_POSIX */
932 
933  /* Keep copies of the MPI Comm & Info objects */
934  if (MPI_SUCCESS != MPI_Comm_dup(comm, &nc4_info->comm))
935  BAIL(NC_EMPI);
936  comm_duped++;
937  if (MPI_INFO_NULL != info)
938  {
939  if (MPI_SUCCESS != MPI_Info_dup(info, &nc4_info->info))
940  BAIL(NC_EMPI);
941  info_duped++;
942  }
943  else
944  {
945  /* No dup, just copy it. */
946  nc4_info->info = info;
947  }
948  }
949 #else /* only set cache for non-parallel... */
950  if(cmode & NC_DISKLESS) {
951  if (H5Pset_fapl_core(fapl_id, 4096, persist))
952  BAIL(NC_EDISKLESS);
953  }
954  if (H5Pset_cache(fapl_id, 0, nc4_chunk_cache_nelems, nc4_chunk_cache_size,
956  BAIL(NC_EHDFERR);
957  LOG((4, "%s: set HDF raw chunk cache to size %d nelems %d preemption %f",
959 #endif /* USE_PARALLEL4 */
960 
961 #ifdef HDF5_HAS_LIBVER_BOUNDS
962  if (H5Pset_libver_bounds(fapl_id, H5F_LIBVER_EARLIEST, H5F_LIBVER_LATEST) < 0)
963  BAIL(NC_EHDFERR);
964 #endif
965 
966  /* Create the property list. */
967  if ((fcpl_id = H5Pcreate(H5P_FILE_CREATE)) < 0)
968  BAIL(NC_EHDFERR);
969 
970  /* RJ: this suppose to be FALSE that is defined in H5 private.h as 0 */
971  if (H5Pset_obj_track_times(fcpl_id,0)<0)
972  BAIL(NC_EHDFERR);
973 
974  /* Set latest_format in access propertly list and
975  * H5P_CRT_ORDER_TRACKED in the creation property list. This turns
976  * on HDF5 creation ordering. */
977  if (H5Pset_link_creation_order(fcpl_id, (H5P_CRT_ORDER_TRACKED |
978  H5P_CRT_ORDER_INDEXED)) < 0)
979  BAIL(NC_EHDFERR);
980  if (H5Pset_attr_creation_order(fcpl_id, (H5P_CRT_ORDER_TRACKED |
981  H5P_CRT_ORDER_INDEXED)) < 0)
982  BAIL(NC_EHDFERR);
983 
984  /* Create the file. */
985 #ifdef HDF5_HAS_COLL_METADATA_OPS
986  H5Pset_all_coll_metadata_ops(fapl_id, 1 );
987  H5Pset_coll_metadata_write(fapl_id, 1);
988 #endif
989 
990  if ((nc4_info->hdfid = H5Fcreate(path, flags, fcpl_id, fapl_id)) < 0)
991  /*Change the return error from NC_EFILEMETADATA to
992  System error EACCES because that is the more likely problem */
993  BAIL(EACCES);
994 
995  /* Open the root group. */
996  if ((nc4_info->root_grp->hdf_grpid = H5Gopen2(nc4_info->hdfid, "/",
997  H5P_DEFAULT)) < 0)
998  BAIL(NC_EFILEMETA);
999 
1000  /* Release the property lists. */
1001  if (H5Pclose(fapl_id) < 0 || H5Pclose(fcpl_id) < 0)
1002  BAIL(NC_EHDFERR);
1003 
1004  /* Define mode gets turned on automatically on create. */
1005  nc4_info->flags |= NC_INDEF;
1006 
1007  NC4_get_fileinfo(nc4_info,&globalpropinfo);
1008  NC4_put_propattr(nc4_info);
1009 
1010  return NC_NOERR;
1011 
1012 exit: /*failure exit*/
1013 #ifdef USE_PARALLEL4
1014  if (comm_duped) MPI_Comm_free(&nc4_info->comm);
1015  if (info_duped) MPI_Info_free(&nc4_info->info);
1016 #endif
1017  if (fapl_id != H5P_DEFAULT) H5Pclose(fapl_id);
1018  if(!nc4_info) return retval;
1019  close_netcdf4_file(nc4_info,1); /* treat like abort */
1020  return retval;
1021 }
1022 
1042 int
1043 NC4_create(const char* path, int cmode, size_t initialsz, int basepe,
1044  size_t *chunksizehintp, int use_parallel, void *parameters,
1045  NC_Dispatch *dispatch, NC* nc_file)
1046 {
1047  MPI_Comm comm = MPI_COMM_WORLD;
1048  MPI_Info info = MPI_INFO_NULL;
1049  int res;
1050 
1051  assert(nc_file && path);
1052 
1053  LOG((1, "%s: path %s cmode 0x%x comm %d info %d",
1054  __func__, path, cmode, comm, info));
1055 
1056 #ifdef USE_PARALLEL4
1057  if (parameters)
1058  {
1059  comm = ((NC_MPI_INFO *)parameters)->comm;
1060  info = ((NC_MPI_INFO *)parameters)->info;
1061  }
1062 #endif /* USE_PARALLEL4 */
1063 
1064  /* If this is our first file, turn off HDF5 error messages. */
1065  if (!nc4_hdf5_initialized)
1066  nc4_hdf5_initialize();
1067 
1068  /* Check the cmode for validity. */
1069  if((cmode & ILLEGAL_CREATE_FLAGS) != 0)
1070  {res = NC_EINVAL; goto done;}
1071 
1072  /* Cannot have both */
1073  if((cmode & (NC_MPIIO|NC_MPIPOSIX)) == (NC_MPIIO|NC_MPIPOSIX))
1074  {res = NC_EINVAL; goto done;}
1075 
1076  /* Currently no parallel diskless io */
1077  if((cmode & (NC_MPIIO | NC_MPIPOSIX)) && (cmode & NC_DISKLESS))
1078  {res = NC_EINVAL; goto done;}
1079 
1080 #ifndef USE_PARALLEL_POSIX
1081 /* If the HDF5 library has been compiled without the MPI-POSIX VFD, alias
1082  * the NC_MPIPOSIX flag to NC_MPIIO. -QAK
1083  */
1084  if(cmode & NC_MPIPOSIX)
1085  {
1086  cmode &= ~NC_MPIPOSIX;
1087  cmode |= NC_MPIIO;
1088  }
1089 #endif /* USE_PARALLEL_POSIX */
1090 
1091  cmode |= NC_NETCDF4;
1092 
1093  /* Apply default create format. */
1094  if (nc_get_default_format() == NC_FORMAT_CDF5)
1095  cmode |= NC_CDF5;
1096  else if (nc_get_default_format() == NC_FORMAT_64BIT_OFFSET)
1097  cmode |= NC_64BIT_OFFSET;
1098  else if (nc_get_default_format() == NC_FORMAT_NETCDF4_CLASSIC)
1099  cmode |= NC_CLASSIC_MODEL;
1100 
1101  LOG((2, "cmode after applying default format: 0x%x", cmode));
1102 
1103  nc_file->int_ncid = nc_file->ext_ncid;
1104 
1105  res = nc4_create_file(path, cmode, comm, info, nc_file);
1106 
1107 done:
1108  return res;
1109 }
1110 
1130 static int
1131 read_scale(NC_GRP_INFO_T *grp, hid_t datasetid, const char *obj_name,
1132  const H5G_stat_t *statbuf, hsize_t scale_size, hsize_t max_scale_size,
1133  NC_DIM_INFO_T **dim)
1134 {
1135  NC_DIM_INFO_T *new_dim; /* Dimension added to group */
1136  char dimscale_name_att[NC_MAX_NAME + 1] = ""; /* Dimscale name, for checking if dim without var */
1137  htri_t attr_exists = -1; /* Flag indicating hidden attribute exists */
1138  hid_t attid = -1; /* ID of hidden attribute (to store dim ID) */
1139  int dimscale_created = 0; /* Remember if a dimension was created (for error recovery) */
1140  short initial_next_dimid = grp->nc4_info->next_dimid;/* Retain for error recovery */
1141  int retval;
1142 
1143  /* Add a dimension for this scale. */
1144  if ((retval = nc4_dim_list_add(&grp->dim, &new_dim)))
1145  BAIL(retval);
1146  dimscale_created++;
1147 
1148  /* Does this dataset have a hidden attribute that tells us its
1149  * dimid? If so, read it. */
1150  if ((attr_exists = H5Aexists(datasetid, NC_DIMID_ATT_NAME)) < 0)
1151  BAIL(NC_EHDFERR);
1152  if (attr_exists)
1153  {
1154  if ((attid = H5Aopen_name(datasetid, NC_DIMID_ATT_NAME)) < 0)
1155  BAIL(NC_EHDFERR);
1156 
1157  if (H5Aread(attid, H5T_NATIVE_INT, &new_dim->dimid) < 0)
1158  BAIL(NC_EHDFERR);
1159 
1160  /* Check if scale's dimid should impact the group's next dimid */
1161  if (new_dim->dimid >= grp->nc4_info->next_dimid)
1162  grp->nc4_info->next_dimid = new_dim->dimid + 1;
1163  }
1164  else
1165  {
1166  /* Assign dimid */
1167  new_dim->dimid = grp->nc4_info->next_dimid++;
1168  }
1169 
1170  if (!(new_dim->name = strdup(obj_name)))
1171  BAIL(NC_ENOMEM);
1172  if (SIZEOF_SIZE_T < 8 && scale_size > NC_MAX_UINT)
1173  {
1174  new_dim->len = NC_MAX_UINT;
1175  new_dim->too_long = NC_TRUE;
1176  }
1177  else
1178  new_dim->len = scale_size;
1179  new_dim->hdf5_objid.fileno[0] = statbuf->fileno[0];
1180  new_dim->hdf5_objid.fileno[1] = statbuf->fileno[1];
1181  new_dim->hdf5_objid.objno[0] = statbuf->objno[0];
1182  new_dim->hdf5_objid.objno[1] = statbuf->objno[1];
1183  new_dim->hash = hash_fast(obj_name, strlen(obj_name));
1184 
1185  /* If the dimscale has an unlimited dimension, then this dimension
1186  * is unlimited. */
1187  if (max_scale_size == H5S_UNLIMITED)
1188  new_dim->unlimited = NC_TRUE;
1189 
1190  /* If the scale name is set to DIM_WITHOUT_VARIABLE, then this is a
1191  * dimension, but not a variable. (If get_scale_name returns an
1192  * error, just move on, there's no NAME.) */
1193  if (H5DSget_scale_name(datasetid, dimscale_name_att, NC_MAX_NAME) >= 0)
1194  {
1195  if (!strncmp(dimscale_name_att, DIM_WITHOUT_VARIABLE,
1196  strlen(DIM_WITHOUT_VARIABLE)))
1197  {
1198  if (new_dim->unlimited)
1199  {
1200  size_t len = 0, *lenp = &len;
1201 
1202  if ((retval = nc4_find_dim_len(grp, new_dim->dimid, &lenp)))
1203  BAIL(retval);
1204  new_dim->len = *lenp;
1205  }
1206 
1207  /* Hold open the dataset, since the dimension doesn't have a coordinate variable */
1208  new_dim->hdf_dimscaleid = datasetid;
1209  H5Iinc_ref(new_dim->hdf_dimscaleid); /* Increment number of objects using ID */
1210  }
1211  }
1212 
1213  /* Set the dimension created */
1214  *dim = new_dim;
1215 
1216 exit:
1217  /* Close the hidden attribute, if it was opened (error, or no error) */
1218  if (attid > 0 && H5Aclose(attid) < 0)
1219  BAIL2(NC_EHDFERR);
1220 
1221  /* On error, undo any dimscale creation */
1222  if (retval < 0 && dimscale_created)
1223  {
1224  /* Delete the dimension */
1225  if ((retval = nc4_dim_list_del(&grp->dim, new_dim)))
1226  BAIL2(retval);
1227 
1228  /* Reset the group's information */
1229  grp->nc4_info->next_dimid = initial_next_dimid;
1230  }
1231 
1232  return retval;
1233 }
1234 
1245 static int
1246 read_coord_dimids(NC_GRP_INFO_T *grp, NC_VAR_INFO_T *var)
1247 {
1248  hid_t coord_att_typeid = -1, coord_attid = -1, spaceid = -1;
1249  hssize_t npoints;
1250  int ret = 0;
1251  int d;
1252 
1253  /* There is a hidden attribute telling us the ids of the
1254  * dimensions that apply to this multi-dimensional coordinate
1255  * variable. Read it. */
1256  if ((coord_attid = H5Aopen_name(var->hdf_datasetid, COORDINATES)) < 0) ret++;
1257  if (!ret && (coord_att_typeid = H5Aget_type(coord_attid)) < 0) ret++;
1258 
1259  /* How many dimensions are there? */
1260  if (!ret && (spaceid = H5Aget_space(coord_attid)) < 0) ret++;
1261  if (!ret && (npoints = H5Sget_simple_extent_npoints(spaceid)) < 0) ret++;
1262 
1263  /* Check that the number of points is the same as the number of dimensions
1264  * for the variable */
1265  if (!ret && npoints != var->ndims) ret++;
1266 
1267  if (!ret && H5Aread(coord_attid, coord_att_typeid, var->dimids) < 0) ret++;
1268  LOG((4, "dimscale %s is multidimensional and has coords", var->name));
1269 
1270  /* Update var->dim field based on the var->dimids */
1271  for (d = 0; d < var->ndims; d++) {
1272  /* Ok if does not find a dim at this time, but if found set it */
1273  nc4_find_dim(grp, var->dimids[d], &var->dim[d], NULL);
1274  }
1275 
1276  /* Set my HDF5 IDs free! */
1277  if (spaceid >= 0 && H5Sclose(spaceid) < 0) ret++;
1278  if (coord_att_typeid >= 0 && H5Tclose(coord_att_typeid) < 0) ret++;
1279  if (coord_attid >= 0 && H5Aclose(coord_attid) < 0) ret++;
1280  return ret ? NC_EATTMETA : NC_NOERR;
1281 }
1282 
1295 static herr_t
1296 dimscale_visitor(hid_t did, unsigned dim, hid_t dsid,
1297  void *dimscale_hdf5_objids)
1298 {
1299  H5G_stat_t statbuf;
1300 
1301  /* Get more info on the dimscale object.*/
1302  if (H5Gget_objinfo(dsid, ".", 1, &statbuf) < 0)
1303  return -1;
1304 
1305  /* Pass this information back to caller. */
1306  (*(HDF5_OBJID_T *)dimscale_hdf5_objids).fileno[0] = statbuf.fileno[0];
1307  (*(HDF5_OBJID_T *)dimscale_hdf5_objids).fileno[1] = statbuf.fileno[1];
1308  (*(HDF5_OBJID_T *)dimscale_hdf5_objids).objno[0] = statbuf.objno[0];
1309  (*(HDF5_OBJID_T *)dimscale_hdf5_objids).objno[1] = statbuf.objno[1];
1310  return 0;
1311 }
1312 
1328 static int
1329 get_type_info2(NC_HDF5_FILE_INFO_T *h5, hid_t datasetid,
1330  NC_TYPE_INFO_T **type_info)
1331 {
1332  htri_t is_str, equal = 0;
1333  H5T_class_t class;
1334  hid_t native_typeid, hdf_typeid;
1335  H5T_order_t order;
1336  int t;
1337 
1338  assert(h5 && type_info);
1339 
1340  /* Because these N5T_NATIVE_* constants are actually function calls
1341  * (!) in H5Tpublic.h, I can't initialize this array in the usual
1342  * way, because at least some C compilers (like Irix) complain
1343  * about calling functions when defining constants. So I have to do
1344  * it like this. Note that there's no native types for char or
1345  * string. Those are handled later. */
1346  if (!h5_native_type_constant_g[1])
1347  {
1348  h5_native_type_constant_g[1] = H5T_NATIVE_SCHAR;
1349  h5_native_type_constant_g[2] = H5T_NATIVE_SHORT;
1350  h5_native_type_constant_g[3] = H5T_NATIVE_INT;
1351  h5_native_type_constant_g[4] = H5T_NATIVE_FLOAT;
1352  h5_native_type_constant_g[5] = H5T_NATIVE_DOUBLE;
1353  h5_native_type_constant_g[6] = H5T_NATIVE_UCHAR;
1354  h5_native_type_constant_g[7] = H5T_NATIVE_USHORT;
1355  h5_native_type_constant_g[8] = H5T_NATIVE_UINT;
1356  h5_native_type_constant_g[9] = H5T_NATIVE_LLONG;
1357  h5_native_type_constant_g[10] = H5T_NATIVE_ULLONG;
1358  }
1359 
1360  /* Get the HDF5 typeid - we'll need it later. */
1361  if ((hdf_typeid = H5Dget_type(datasetid)) < 0)
1362  return NC_EHDFERR;
1363 
1364  /* Get the native typeid. Will be equivalent to hdf_typeid when
1365  * creating but not necessarily when reading, a variable. */
1366  if ((native_typeid = H5Tget_native_type(hdf_typeid, H5T_DIR_DEFAULT)) < 0)
1367  return NC_EHDFERR;
1368 
1369  /* Is this type an integer, string, compound, or what? */
1370  if ((class = H5Tget_class(native_typeid)) < 0)
1371  return NC_EHDFERR;
1372 
1373  /* Is this an atomic type? */
1374  if (class == H5T_STRING || class == H5T_INTEGER || class == H5T_FLOAT)
1375  {
1376  /* Allocate a phony NC_TYPE_INFO_T struct to hold type info. */
1377  if (!(*type_info = calloc(1, sizeof(NC_TYPE_INFO_T))))
1378  return NC_ENOMEM;
1379 
1380  /* H5Tequal doesn't work with H5T_C_S1 for some reason. But
1381  * H5Tget_class will return H5T_STRING if this is a string. */
1382  if (class == H5T_STRING)
1383  {
1384  if ((is_str = H5Tis_variable_str(native_typeid)) < 0)
1385  return NC_EHDFERR;
1386  /* Make sure fixed-len strings will work like variable-len strings */
1387  if (is_str || H5Tget_size(hdf_typeid) > 1)
1388  {
1389  /* Set a class for the type */
1390  t = NUM_TYPES - 1;
1391  (*type_info)->nc_type_class = NC_STRING;
1392  }
1393  else
1394  {
1395  /* Set a class for the type */
1396  t = 0;
1397  (*type_info)->nc_type_class = NC_CHAR;
1398  }
1399  }
1400  else if (class == H5T_INTEGER || class == H5T_FLOAT)
1401  {
1402  for (t = 1; t < NUM_TYPES - 1; t++)
1403  {
1404  if ((equal = H5Tequal(native_typeid, h5_native_type_constant_g[t])) < 0)
1405  return NC_EHDFERR;
1406  if (equal)
1407  break;
1408  }
1409 
1410  /* Find out about endianness.
1411  * As of HDF 1.8.6, this works with all data types
1412  * Not just H5T_INTEGER.
1413  *
1414  * See https://www.hdfgroup.org/HDF5/doc/RM/RM_H5T.html#Datatype-GetOrder
1415  */
1416  if((order = H5Tget_order(hdf_typeid)) < 0)
1417  return NC_EHDFERR;
1418 
1419  if(order == H5T_ORDER_LE)
1420  (*type_info)->endianness = NC_ENDIAN_LITTLE;
1421  else if(order == H5T_ORDER_BE)
1422  (*type_info)->endianness = NC_ENDIAN_BIG;
1423  else
1424  return NC_EBADTYPE;
1425 
1426  if(class == H5T_INTEGER)
1427  (*type_info)->nc_type_class = NC_INT;
1428  else
1429  (*type_info)->nc_type_class = NC_FLOAT;
1430  }
1431  (*type_info)->nc_typeid = nc_type_constant_g[t];
1432  (*type_info)->size = nc_type_size_g[t];
1433  if (!((*type_info)->name = strdup(nc_type_name_g[t])))
1434  return NC_ENOMEM;
1435  (*type_info)->hdf_typeid = hdf_typeid;
1436  (*type_info)->native_hdf_typeid = native_typeid;
1437  return NC_NOERR;
1438  }
1439  else
1440  {
1441  NC_TYPE_INFO_T *type;
1442 
1443  /* This is a user-defined type. */
1444  if((type = nc4_rec_find_hdf_type(h5->root_grp, native_typeid)))
1445  *type_info = type;
1446 
1447  /* The type entry in the array of user-defined types already has
1448  * an open data typeid (and native typeid), so close the ones we
1449  * opened above. */
1450  if (H5Tclose(native_typeid) < 0)
1451  return NC_EHDFERR;
1452  if (H5Tclose(hdf_typeid) < 0)
1453  return NC_EHDFERR;
1454 
1455  if (type)
1456  return NC_NOERR;
1457  }
1458 
1459  return NC_EBADTYPID;
1460 }
1461 
1476 static int
1477 read_type(NC_GRP_INFO_T *grp, hid_t hdf_typeid, char *type_name)
1478 {
1479  NC_TYPE_INFO_T *type;
1480  H5T_class_t class;
1481  hid_t native_typeid;
1482  size_t type_size;
1483  int retval = NC_NOERR;
1484 
1485  assert(grp && type_name);
1486 
1487  LOG((4, "%s: type_name %s grp->name %s", __func__, type_name, grp->name));
1488 
1489  /* What is the native type for this platform? */
1490  if ((native_typeid = H5Tget_native_type(hdf_typeid, H5T_DIR_DEFAULT)) < 0)
1491  return NC_EHDFERR;
1492 
1493  /* What is the size of this type on this platform. */
1494  if (!(type_size = H5Tget_size(native_typeid)))
1495  return NC_EHDFERR;
1496  LOG((5, "type_size %d", type_size));
1497 
1498  /* Add to the list for this new type, and get a local pointer to it. */
1499  if ((retval = nc4_type_list_add(grp, type_size, type_name, &type)))
1500  return retval;
1501 
1502  /* Remember common info about this type. */
1503  type->committed = NC_TRUE;
1504  type->hdf_typeid = hdf_typeid;
1505  H5Iinc_ref(type->hdf_typeid); /* Increment number of objects using ID */
1506  type->native_hdf_typeid = native_typeid;
1507 
1508  /* What is the class of this type, compound, vlen, etc. */
1509  if ((class = H5Tget_class(hdf_typeid)) < 0)
1510  return NC_EHDFERR;
1511  switch (class)
1512  {
1513  case H5T_STRING:
1514  type->nc_type_class = NC_STRING;
1515  break;
1516 
1517  case H5T_COMPOUND:
1518  {
1519  int nmembers;
1520  unsigned int m;
1521  char* member_name = NULL;
1522 #ifdef JNA
1523  char jna[1001];
1524 #endif
1525 
1526  type->nc_type_class = NC_COMPOUND;
1527 
1528  if ((nmembers = H5Tget_nmembers(hdf_typeid)) < 0)
1529  return NC_EHDFERR;
1530  LOG((5, "compound type has %d members", nmembers));
1531  for (m = 0; m < nmembers; m++)
1532  {
1533  hid_t member_hdf_typeid;
1534  hid_t member_native_typeid;
1535  size_t member_offset;
1536  H5T_class_t mem_class;
1537  nc_type member_xtype;
1538 
1539 
1540  /* Get the typeid and native typeid of this member of the
1541  * compound type. */
1542  if ((member_hdf_typeid = H5Tget_member_type(type->native_hdf_typeid, m)) < 0)
1543  return NC_EHDFERR;
1544 
1545  if ((member_native_typeid = H5Tget_native_type(member_hdf_typeid, H5T_DIR_DEFAULT)) < 0)
1546  return NC_EHDFERR;
1547 
1548  /* Get the name of the member.*/
1549  member_name = H5Tget_member_name(type->native_hdf_typeid, m);
1550  if (!member_name || strlen(member_name) > NC_MAX_NAME) {
1551  retval = NC_EBADNAME;
1552  break;
1553  }
1554 #ifdef JNA
1555  else {
1556  strncpy(jna,member_name,1000);
1557  member_name = jna;
1558  }
1559 #endif
1560 
1561  /* Offset in bytes on *this* platform. */
1562  member_offset = H5Tget_member_offset(type->native_hdf_typeid, m);
1563 
1564  /* Get dimensional data if this member is an array of something. */
1565  if ((mem_class = H5Tget_class(member_hdf_typeid)) < 0)
1566  return NC_EHDFERR;
1567  if (mem_class == H5T_ARRAY)
1568  {
1569  int ndims, dim_size[NC_MAX_VAR_DIMS];
1570  hsize_t dims[NC_MAX_VAR_DIMS];
1571  int d;
1572 
1573  if ((ndims = H5Tget_array_ndims(member_hdf_typeid)) < 0) {
1574  retval = NC_EHDFERR;
1575  break;
1576  }
1577  if (H5Tget_array_dims(member_hdf_typeid, dims, NULL) != ndims) {
1578  retval = NC_EHDFERR;
1579  break;
1580  }
1581  for (d = 0; d < ndims; d++)
1582  dim_size[d] = dims[d];
1583 
1584  /* What is the netCDF typeid of this member? */
1585  if ((retval = get_netcdf_type(grp->nc4_info, H5Tget_super(member_hdf_typeid),
1586  &member_xtype)))
1587  break;
1588 
1589  /* Add this member to our list of fields in this compound type. */
1590  if ((retval = nc4_field_list_add(&type->u.c.field, type->u.c.num_fields++, member_name,
1591  member_offset, H5Tget_super(member_hdf_typeid),
1592  H5Tget_super(member_native_typeid),
1593  member_xtype, ndims, dim_size)))
1594  break;
1595  }
1596  else
1597  {
1598  /* What is the netCDF typeid of this member? */
1599  if ((retval = get_netcdf_type(grp->nc4_info, member_native_typeid,
1600  &member_xtype)))
1601  break;
1602 
1603  /* Add this member to our list of fields in this compound type. */
1604  if ((retval = nc4_field_list_add(&type->u.c.field, type->u.c.num_fields++, member_name,
1605  member_offset, member_hdf_typeid, member_native_typeid,
1606  member_xtype, 0, NULL)))
1607  break;
1608  }
1609 
1610  hdf5free(member_name);
1611  member_name = NULL;
1612  }
1613  hdf5free(member_name);
1614  member_name = NULL;
1615  if(retval) /* error exit from loop */
1616  return retval;
1617  }
1618  break;
1619 
1620  case H5T_VLEN:
1621  {
1622  htri_t ret;
1623 
1624  /* For conveninence we allow user to pass vlens of strings
1625  * with null terminated strings. This means strings are
1626  * treated slightly differently by the API, although they are
1627  * really just VLENs of characters. */
1628  if ((ret = H5Tis_variable_str(hdf_typeid)) < 0)
1629  return NC_EHDFERR;
1630  if (ret)
1631  type->nc_type_class = NC_STRING;
1632  else
1633  {
1634  hid_t base_hdf_typeid;
1635  nc_type base_nc_type = NC_NAT;
1636 
1637  type->nc_type_class = NC_VLEN;
1638 
1639  /* Find the base type of this vlen (i.e. what is this a
1640  * vlen of?) */
1641  if (!(base_hdf_typeid = H5Tget_super(native_typeid)))
1642  return NC_EHDFERR;
1643 
1644  /* What size is this type? */
1645  if (!(type_size = H5Tget_size(base_hdf_typeid)))
1646  return NC_EHDFERR;
1647 
1648  /* What is the netcdf corresponding type. */
1649  if ((retval = get_netcdf_type(grp->nc4_info, base_hdf_typeid,
1650  &base_nc_type)))
1651  return retval;
1652  LOG((5, "base_hdf_typeid 0x%x type_size %d base_nc_type %d",
1653  base_hdf_typeid, type_size, base_nc_type));
1654 
1655  /* Remember the base types for this vlen */
1656  type->u.v.base_nc_typeid = base_nc_type;
1657  type->u.v.base_hdf_typeid = base_hdf_typeid;
1658  }
1659  }
1660  break;
1661 
1662  case H5T_OPAQUE:
1663  type->nc_type_class = NC_OPAQUE;
1664  break;
1665 
1666  case H5T_ENUM:
1667  {
1668  hid_t base_hdf_typeid;
1669  nc_type base_nc_type = NC_NAT;
1670  void *value;
1671  int i;
1672  char *member_name = NULL;
1673 #ifdef JNA
1674  char jna[1001];
1675 #endif
1676 
1677  type->nc_type_class = NC_ENUM;
1678 
1679  /* Find the base type of this enum (i.e. what is this a
1680  * enum of?) */
1681  if (!(base_hdf_typeid = H5Tget_super(hdf_typeid)))
1682  return NC_EHDFERR;
1683  /* What size is this type? */
1684  if (!(type_size = H5Tget_size(base_hdf_typeid)))
1685  return NC_EHDFERR;
1686  /* What is the netcdf corresponding type. */
1687  if ((retval = get_netcdf_type(grp->nc4_info, base_hdf_typeid,
1688  &base_nc_type)))
1689  return retval;
1690  LOG((5, "base_hdf_typeid 0x%x type_size %d base_nc_type %d",
1691  base_hdf_typeid, type_size, base_nc_type));
1692 
1693  /* Remember the base types for this enum */
1694  type->u.e.base_nc_typeid = base_nc_type;
1695  type->u.e.base_hdf_typeid = base_hdf_typeid;
1696 
1697  /* Find out how many member are in the enum. */
1698  if ((type->u.e.num_members = H5Tget_nmembers(hdf_typeid)) < 0)
1699  return NC_EHDFERR;
1700 
1701  /* Allocate space for one value. */
1702  if (!(value = calloc(1, type_size)))
1703  return NC_ENOMEM;
1704 
1705  /* Read each name and value defined in the enum. */
1706  for (i = 0; i < type->u.e.num_members; i++)
1707  {
1708 
1709  /* Get the name and value from HDF5. */
1710  if (!(member_name = H5Tget_member_name(hdf_typeid, i)))
1711  {
1712  retval = NC_EHDFERR;
1713  break;
1714  }
1715 #ifdef JNA
1716  strncpy(jna,member_name,1000);
1717  member_name = jna;
1718 #endif
1719 
1720  if (strlen(member_name) > NC_MAX_NAME)
1721  {
1722  retval = NC_EBADNAME;
1723  break;
1724  }
1725  if (H5Tget_member_value(hdf_typeid, i, value) < 0)
1726  {
1727  retval = NC_EHDFERR;
1728  break;
1729  }
1730 
1731  /* Insert new field into this type's list of fields. */
1732  if ((retval = nc4_enum_member_add(&type->u.e.enum_member, type->size,
1733  member_name, value)))
1734  {
1735  break;
1736  }
1737 
1738  hdf5free(member_name);
1739  member_name = NULL;
1740  }
1741  hdf5free(member_name);
1742  member_name = NULL;
1743  if(value) free(value);
1744  if(retval) /* error exit from loop */
1745  return retval;
1746  }
1747  break;
1748 
1749  default:
1750  LOG((0, "unknown class"));
1751  return NC_EBADCLASS;
1752  }
1753  return retval;
1754 }
1755 
1773 static int
1774 read_var(NC_GRP_INFO_T *grp, hid_t datasetid, const char *obj_name,
1775  size_t ndims, NC_DIM_INFO_T *dim)
1776 {
1777  NC_VAR_INFO_T *var = NULL;
1778  hid_t access_pid = 0;
1779  int incr_id_rc = 0; /* Whether the dataset ID's ref count has been incremented */
1780  int d;
1781  att_iter_info att_info; /* Custom iteration information */
1782  H5Z_filter_t filter;
1783  int num_filters;
1784  unsigned int cd_values_zip[CD_NELEMS_ZLIB];
1785  size_t cd_nelems = CD_NELEMS_ZLIB;
1786  hid_t propid = 0;
1787  H5D_fill_value_t fill_status;
1788  H5D_layout_t layout;
1789  hsize_t chunksize[NC_MAX_VAR_DIMS] = {0};
1790  int retval = NC_NOERR;
1791  double rdcc_w0;
1792  int f;
1793 
1794  assert(obj_name && grp);
1795  LOG((4, "%s: obj_name %s", __func__, obj_name));
1796 
1797  /* Add a variable to the end of the group's var list. */
1798  if ((retval = nc4_var_add(&var)))
1799  BAIL(retval);
1800 
1801  /* Fill in what we already know. */
1802  var->hdf_datasetid = datasetid;
1803  H5Iinc_ref(var->hdf_datasetid); /* Increment number of objects using ID */
1804  incr_id_rc++; /* Indicate that we've incremented the ref. count (for errors) */
1805  var->varid = grp->nvars++;
1806  var->created = NC_TRUE;
1807  var->ndims = ndims;
1808 
1809  /* We need some room to store information about dimensions for this
1810  * var. */
1811  if (var->ndims)
1812  {
1813  if (!(var->dim = calloc(var->ndims, sizeof(NC_DIM_INFO_T *))))
1814  BAIL(NC_ENOMEM);
1815  if (!(var->dimids = calloc(var->ndims, sizeof(int))))
1816  BAIL(NC_ENOMEM);
1817  }
1818 
1819  /* Get the current chunk cache settings. */
1820  if ((access_pid = H5Dget_access_plist(datasetid)) < 0)
1821  BAIL(NC_EVARMETA);
1822 
1823  /* Learn about current chunk cache settings. */
1824  if ((H5Pget_chunk_cache(access_pid, &(var->chunk_cache_nelems),
1825  &(var->chunk_cache_size), &rdcc_w0)) < 0)
1826  BAIL(NC_EHDFERR);
1827  var->chunk_cache_preemption = rdcc_w0;
1828 
1829  /* Check for a weird case: a non-coordinate variable that has the
1830  * same name as a dimension. It's legal in netcdf, and requires
1831  * that the HDF5 dataset name be changed. */
1832  if (strlen(obj_name) > strlen(NON_COORD_PREPEND) &&
1833  !strncmp(obj_name, NON_COORD_PREPEND, strlen(NON_COORD_PREPEND)))
1834  {
1835  /* Allocate space for the name. */
1836  if (!(var->name = malloc(((strlen(obj_name) - strlen(NON_COORD_PREPEND))+ 1) * sizeof(char))))
1837  BAIL(NC_ENOMEM);
1838 
1839  strcpy(var->name, &obj_name[strlen(NON_COORD_PREPEND)]);
1840 
1841  /* Allocate space for the HDF5 name. */
1842  if (!(var->hdf5_name = malloc((strlen(obj_name) + 1) * sizeof(char))))
1843  BAIL(NC_ENOMEM);
1844 
1845  strcpy(var->hdf5_name, obj_name);
1846  }
1847  else
1848  {
1849  /* Allocate space for the name. */
1850  if (!(var->name = malloc((strlen(obj_name) + 1) * sizeof(char))))
1851  BAIL(NC_ENOMEM);
1852 
1853  strcpy(var->name, obj_name);
1854  }
1855 
1856  var->hash = hash_fast(var->name, strlen(var->name));
1857  /* Find out what filters are applied to this HDF5 dataset,
1858  * fletcher32, deflate, and/or shuffle. All other filters are
1859  * just dumped */
1860  if ((propid = H5Dget_create_plist(datasetid)) < 0)
1861  BAIL(NC_EHDFERR);
1862 
1863  /* Get the chunking info for non-scalar vars. */
1864  if ((layout = H5Pget_layout(propid)) < -1)
1865  BAIL(NC_EHDFERR);
1866  if (layout == H5D_CHUNKED)
1867  {
1868  if (H5Pget_chunk(propid, NC_MAX_VAR_DIMS, chunksize) < 0)
1869  BAIL(NC_EHDFERR);
1870  if (!(var->chunksizes = malloc(var->ndims * sizeof(size_t))))
1871  BAIL(NC_ENOMEM);
1872  for (d = 0; d < var->ndims; d++)
1873  var->chunksizes[d] = chunksize[d];
1874  }
1875  else if (layout == H5D_CONTIGUOUS || layout == H5D_COMPACT)
1876  var->contiguous = NC_TRUE;
1877 
1878  /* The possible values of filter (which is just an int) can be
1879  * found in H5Zpublic.h. */
1880  if ((num_filters = H5Pget_nfilters(propid)) < 0)
1881  BAIL(NC_EHDFERR);
1882  for (f = 0; f < num_filters; f++)
1883  {
1884  if ((filter = H5Pget_filter2(propid, f, NULL, &cd_nelems,
1885  cd_values_zip, 0, NULL, NULL)) < 0)
1886  BAIL(NC_EHDFERR);
1887  switch (filter)
1888  {
1889  case H5Z_FILTER_SHUFFLE:
1890  var->shuffle = NC_TRUE;
1891  break;
1892 
1893  case H5Z_FILTER_FLETCHER32:
1894  var->fletcher32 = NC_TRUE;
1895  break;
1896 
1897  case H5Z_FILTER_DEFLATE:
1898  var->deflate = NC_TRUE;
1899  if (cd_nelems != CD_NELEMS_ZLIB || cd_values_zip[0] > NC_MAX_DEFLATE_LEVEL)
1900  BAIL(NC_EHDFERR);
1901  var->deflate_level = cd_values_zip[0];
1902  break;
1903 
1904  default:
1905  var->filterid = filter;
1906  var->nparams = cd_nelems;
1907  if(cd_nelems == 0)
1908  var->params = NULL;
1909  else {
1910  /* We have to re-read the parameters based on actual nparams */
1911  var->params = (unsigned int*)calloc(1,sizeof(unsigned int)*var->nparams);
1912  if(var->params == NULL)
1913  BAIL(NC_ENOMEM);
1914  if((filter = H5Pget_filter2(propid, f, NULL, &cd_nelems,
1915  var->params, 0, NULL, NULL)) < 0)
1916  BAIL(NC_EHDFERR);
1917  }
1918  break;
1919  }
1920  }
1921 
1922  /* Learn all about the type of this variable. */
1923  if ((retval = get_type_info2(grp->nc4_info, datasetid,
1924  &var->type_info)))
1925  BAIL(retval);
1926 
1927  /* Indicate that the variable has a pointer to the type */
1928  var->type_info->rc++;
1929 
1930  /* Is there a fill value associated with this dataset? */
1931  if (H5Pfill_value_defined(propid, &fill_status) < 0)
1932  BAIL(NC_EHDFERR);
1933 
1934  /* Get the fill value, if there is one defined. */
1935  if (fill_status == H5D_FILL_VALUE_USER_DEFINED)
1936  {
1937  /* Allocate space to hold the fill value. */
1938  if (!var->fill_value)
1939  {
1940  if (var->type_info->nc_type_class == NC_VLEN)
1941  {
1942  if (!(var->fill_value = malloc(sizeof(nc_vlen_t))))
1943  BAIL(NC_ENOMEM);
1944  }
1945  else if (var->type_info->nc_type_class == NC_STRING)
1946  {
1947  if (!(var->fill_value = malloc(sizeof(char *))))
1948  BAIL(NC_ENOMEM);
1949  }
1950  else
1951  {
1952  assert(var->type_info->size);
1953  if (!(var->fill_value = malloc(var->type_info->size)))
1954  BAIL(NC_ENOMEM);
1955  }
1956  }
1957 
1958  /* Get the fill value from the HDF5 property lust. */
1959  if (H5Pget_fill_value(propid, var->type_info->native_hdf_typeid,
1960  var->fill_value) < 0)
1961  BAIL(NC_EHDFERR);
1962  }
1963  else
1964  var->no_fill = NC_TRUE;
1965 
1966  /* If it's a scale, mark it as such. */
1967  if (dim)
1968  {
1969  assert(ndims);
1970  var->dimscale = NC_TRUE;
1971  if (var->ndims > 1)
1972  {
1973  if ((retval = read_coord_dimids(grp, var)))
1974  BAIL(retval);
1975  }
1976  else
1977  {
1978  /* sanity check */
1979  assert(0 == strcmp(var->name, dim->name));
1980 
1981  var->dimids[0] = dim->dimid;
1982  var->dim[0] = dim;
1983  }
1984  dim->coord_var = var;
1985  }
1986  /* If this is not a scale, but has scales, iterate
1987  * through them. (i.e. this is a variable that is not a
1988  * coordinate variable) */
1989  else
1990  {
1991  int num_scales = 0;
1992 
1993  /* Find out how many scales are attached to this
1994  * dataset. H5DSget_num_scales returns an error if there are no
1995  * scales, so convert a negative return value to zero. */
1996  num_scales = H5DSget_num_scales(datasetid, 0);
1997  if (num_scales < 0)
1998  num_scales = 0;
1999 
2000  if (num_scales && ndims)
2001  {
2002  /* Allocate space to remember whether the dimscale has been attached
2003  * for each dimension. */
2004  if (NULL == (var->dimscale_attached = calloc(ndims, sizeof(nc_bool_t))))
2005  BAIL(NC_ENOMEM);
2006 
2007  /* Store id information allowing us to match hdf5
2008  * dimscales to netcdf dimensions. */
2009  if (NULL == (var->dimscale_hdf5_objids = malloc(ndims * sizeof(struct hdf5_objid))))
2010  BAIL(NC_ENOMEM);
2011  for (d = 0; d < var->ndims; d++)
2012  {
2013  if (H5DSiterate_scales(var->hdf_datasetid, d, NULL, dimscale_visitor,
2014  &(var->dimscale_hdf5_objids[d])) < 0)
2015  BAIL(NC_EHDFERR);
2016  var->dimscale_attached[d] = NC_TRUE;
2017  }
2018  }
2019  }
2020 
2021  /* Now read all the attributes of this variable, ignoring the
2022  ones that hold HDF5 dimension scale information. */
2023 
2024  att_info.var = var;
2025  att_info.grp = grp;
2026 
2027  if ((H5Aiterate2(var->hdf_datasetid, H5_INDEX_CRT_ORDER, H5_ITER_INC, NULL,
2028  att_read_var_callbk, &att_info)) < 0)
2029  BAIL(NC_EATTMETA);
2030 
2031  /* Add a var to the variable array, growing it as needed. */
2032  if ((retval = nc4_vararray_add(grp, var)))
2033  BAIL(retval);
2034 
2035  /* Is this a deflated variable with a chunksize greater than the
2036  * current cache size? */
2037  if ((retval = nc4_adjust_var_cache(grp, var)))
2038  BAIL(retval);
2039 
2040 exit:
2041  if (retval)
2042  {
2043  if (incr_id_rc && H5Idec_ref(datasetid) < 0)
2044  BAIL2(NC_EHDFERR);
2045  if (var && nc4_var_del(var))
2046  BAIL2(NC_EHDFERR);
2047  }
2048  if (access_pid && H5Pclose(access_pid) < 0)
2049  BAIL2(NC_EHDFERR);
2050  if (propid > 0 && H5Pclose(propid) < 0)
2051  BAIL2(NC_EHDFERR);
2052  return retval;
2053 }
2054 
2066 static int
2067 read_grp_atts(NC_GRP_INFO_T *grp)
2068 {
2069  hid_t attid = -1;
2070  hsize_t num_obj, i;
2071  NC_ATT_INFO_T *att;
2072  NC_TYPE_INFO_T *type;
2073  char obj_name[NC_MAX_HDF5_NAME + 1];
2074  int max_len;
2075  int retval = NC_NOERR;
2076  int hidden = 0;
2077 
2078  num_obj = H5Aget_num_attrs(grp->hdf_grpid);
2079  for (i = 0; i < num_obj; i++)
2080  {
2081  if ((attid = H5Aopen_idx(grp->hdf_grpid, (unsigned int)i)) < 0)
2082  BAIL(NC_EATTMETA);
2083  if (H5Aget_name(attid, NC_MAX_NAME + 1, obj_name) < 0)
2084  BAIL(NC_EATTMETA);
2085  LOG((3, "reading attribute of _netCDF group, named %s", obj_name));
2086 
2087  /* See if this a hidden, global attribute */
2088  if(grp->nc4_info->root_grp == grp) {
2089  const char** reserved = NC_RESERVED_ATT_LIST;
2090  hidden = 0;
2091  for(;*reserved;reserved++) {
2092  if(strcmp(*reserved,obj_name)==0) {
2093  hidden = 1;
2094  break;
2095  }
2096  }
2097  }
2098 
2099  /* This may be an attribute telling us that strict netcdf-3
2100  * rules are in effect. If so, we will make note of the fact,
2101  * but not add this attribute to the metadata. It's not a user
2102  * attribute, but an internal netcdf-4 one. */
2103  if(strcmp(obj_name, NC3_STRICT_ATT_NAME)==0)
2104  grp->nc4_info->cmode |= NC_CLASSIC_MODEL;
2105  else if(!hidden) {
2106  /* Add an att struct at the end of the list, and then go to it. */
2107  if ((retval = nc4_att_list_add(&grp->att, &att)))
2108  BAIL(retval);
2109 
2110  /* Add the info about this attribute. */
2111  max_len = strlen(obj_name) > NC_MAX_NAME ? NC_MAX_NAME : strlen(obj_name);
2112  if (!(att->name = malloc((max_len + 1) * sizeof(char))))
2113  BAIL(NC_ENOMEM);
2114  strncpy(att->name, obj_name, max_len);
2115  att->name[max_len] = 0;
2116  att->attnum = grp->natts++;
2117  retval = read_hdf5_att(grp, attid, att);
2118  if(retval == NC_EBADTYPID) {
2119  if((retval = nc4_att_list_del(&grp->att, att)))
2120  BAIL(retval);
2121  } else if(retval) {
2122  BAIL(retval);
2123  } else {
2124  att->created = NC_TRUE;
2125  if ((retval = nc4_find_type(grp->nc4_info, att->nc_typeid, &type)))
2126  BAIL(retval);
2127  }
2128  }
2129  /* Unconditionally close the open attribute */
2130  H5Aclose(attid);
2131  attid = -1;
2132  }
2133 
2134 exit:
2135  if (attid > 0) {
2136  if(H5Aclose(attid) < 0)
2137  BAIL2(NC_EHDFERR);
2138  }
2139  return retval;
2140 }
2141 
2156 static int
2157 read_dataset(NC_GRP_INFO_T *grp, hid_t datasetid, const char *obj_name,
2158  const H5G_stat_t *statbuf)
2159 {
2160  NC_DIM_INFO_T *dim = NULL; /* Dimension created for scales */
2161  hid_t spaceid = 0;
2162  int ndims;
2163  htri_t is_scale;
2164  int retval = NC_NOERR;
2165 
2166  /* Get the dimension information for this dataset. */
2167  if ((spaceid = H5Dget_space(datasetid)) < 0)
2168  BAIL(NC_EHDFERR);
2169  if ((ndims = H5Sget_simple_extent_ndims(spaceid)) < 0)
2170  BAIL(NC_EHDFERR);
2171 
2172  /* Is this a dimscale? */
2173  if ((is_scale = H5DSis_scale(datasetid)) < 0)
2174  BAIL(NC_EHDFERR);
2175  if (is_scale)
2176  {
2177  hsize_t dims[H5S_MAX_RANK];
2178  hsize_t max_dims[H5S_MAX_RANK];
2179 
2180  /* Query the scale's size & max. size */
2181  if (H5Sget_simple_extent_dims(spaceid, dims, max_dims) < 0)
2182  BAIL(NC_EHDFERR);
2183 
2184  /* Read the scale information. */
2185  if ((retval = read_scale(grp, datasetid, obj_name, statbuf, dims[0],
2186  max_dims[0], &dim)))
2187  BAIL(retval);
2188  }
2189 
2190  /* Add a var to the linked list, and get its metadata,
2191  * unless this is one of those funny dimscales that are a
2192  * dimension in netCDF but not a variable. (Spooky!) */
2193  if (NULL == dim || (dim && !dim->hdf_dimscaleid))
2194  if ((retval = read_var(grp, datasetid, obj_name, ndims, dim)))
2195  BAIL(retval);
2196 
2197 exit:
2198  if (spaceid && H5Sclose(spaceid) <0)
2199  BAIL2(retval);
2200 
2201  return retval;
2202 }
2203 
2215 static int
2216 nc4_rec_read_metadata_cb_list_add(NC4_rec_read_metadata_obj_info_t **head,
2217  NC4_rec_read_metadata_obj_info_t **tail,
2218  const NC4_rec_read_metadata_obj_info_t *oinfo)
2219 {
2220  NC4_rec_read_metadata_obj_info_t *new_oinfo; /* Pointer to info for object */
2221 
2222  /* Allocate memory for the object's info */
2223  if (!(new_oinfo = calloc(1, sizeof(*new_oinfo))))
2224  return NC_ENOMEM;
2225 
2226  /* Make a copy of the object's info */
2227  memcpy(new_oinfo, oinfo, sizeof(*oinfo));
2228 
2229  if (*tail)
2230  {
2231  assert(*head);
2232  (*tail)->next = new_oinfo;
2233  *tail = new_oinfo;
2234  }
2235  else
2236  {
2237  assert(NULL == *head);
2238  *head = *tail = new_oinfo;
2239  }
2240 
2241  return (NC_NOERR);
2242 }
2243 
2256 static int
2257 nc4_rec_read_metadata_cb(hid_t grpid, const char *name, const H5L_info_t *info,
2258  void *_op_data)
2259 {
2260  NC4_rec_read_metadata_ud_t *udata = (NC4_rec_read_metadata_ud_t *)_op_data; /* Pointer to user data for callback */
2261  NC4_rec_read_metadata_obj_info_t oinfo; /* Pointer to info for object */
2262  int retval = H5_ITER_CONT;
2263 
2264  /* Reset the memory for the object's info */
2265  memset(&oinfo, 0, sizeof(oinfo));
2266 
2267  /* Open this critter. */
2268  if ((oinfo.oid = H5Oopen(grpid, name, H5P_DEFAULT)) < 0)
2269  BAIL(H5_ITER_ERROR);
2270 
2271  /* Get info about the object.*/
2272  if (H5Gget_objinfo(oinfo.oid, ".", 1, &oinfo.statbuf) < 0)
2273  BAIL(H5_ITER_ERROR);
2274 
2275  strncpy(oinfo.oname, name, NC_MAX_NAME);
2276 
2277  /* Add object to list, for later */
2278  switch(oinfo.statbuf.type)
2279  {
2280  case H5G_GROUP:
2281  LOG((3, "found group %s", oinfo.oname));
2282 
2283  /* Defer descending into child group immediately, so that the types
2284  * in the current group can be processed and be ready for use by
2285  * vars in the child group(s).
2286  */
2287  if (nc4_rec_read_metadata_cb_list_add(&udata->grps_head, &udata->grps_tail, &oinfo))
2288  BAIL(H5_ITER_ERROR);
2289  break;
2290 
2291  case H5G_DATASET:
2292  LOG((3, "found dataset %s", oinfo.oname));
2293 
2294  /* Learn all about this dataset, which may be a dimscale
2295  * (i.e. dimension metadata), or real data. */
2296  if ((retval = read_dataset(udata->grp, oinfo.oid, oinfo.oname, &oinfo.statbuf)))
2297  {
2298  /* Allow NC_EBADTYPID to transparently skip over datasets
2299  * which have a datatype that netCDF-4 doesn't undertand
2300  * (currently), but break out of iteration for other
2301  * errors.
2302  */
2303  if(NC_EBADTYPID != retval)
2304  BAIL(H5_ITER_ERROR);
2305  else
2306  retval = H5_ITER_CONT;
2307  }
2308 
2309  /* Close the object */
2310  if (H5Oclose(oinfo.oid) < 0)
2311  BAIL(H5_ITER_ERROR);
2312  break;
2313 
2314  case H5G_TYPE:
2315  LOG((3, "found datatype %s", oinfo.oname));
2316 
2317  /* Process the named datatype */
2318  if (read_type(udata->grp, oinfo.oid, oinfo.oname))
2319  BAIL(H5_ITER_ERROR);
2320 
2321  /* Close the object */
2322  if (H5Oclose(oinfo.oid) < 0)
2323  BAIL(H5_ITER_ERROR);
2324  break;
2325 
2326  default:
2327  LOG((0, "Unknown object class %d in %s!", oinfo.statbuf.type, __func__));
2328  BAIL(H5_ITER_ERROR);
2329  }
2330 
2331 exit:
2332  if (retval)
2333  {
2334  if (oinfo.oid > 0 && H5Oclose(oinfo.oid) < 0)
2335  BAIL2(H5_ITER_ERROR);
2336  }
2337 
2338  return (retval);
2339 }
2340 
2355 static int
2356 nc4_rec_read_metadata(NC_GRP_INFO_T *grp)
2357 {
2358  NC4_rec_read_metadata_ud_t udata; /* User data for iteration */
2359  NC4_rec_read_metadata_obj_info_t *oinfo; /* Pointer to info for object */
2360  hsize_t idx=0;
2361  hid_t pid = 0;
2362  unsigned crt_order_flags = 0;
2363  H5_index_t iter_index;
2364  int i, retval = NC_NOERR; /* everything worked! */
2365 
2366  assert(grp && grp->name);
2367  LOG((3, "%s: grp->name %s", __func__, grp->name));
2368 
2369  /* Portably initialize user data for later */
2370  memset(&udata, 0, sizeof(udata));
2371 
2372  /* Open this HDF5 group and retain its grpid. It will remain open
2373  * with HDF5 until this file is nc_closed. */
2374  if (!grp->hdf_grpid)
2375  {
2376  if (grp->parent)
2377  {
2378  if ((grp->hdf_grpid = H5Gopen2(grp->parent->hdf_grpid,
2379  grp->name, H5P_DEFAULT)) < 0)
2380  BAIL(NC_EHDFERR);
2381  }
2382  else
2383  {
2384  if ((grp->hdf_grpid = H5Gopen2(grp->nc4_info->hdfid,
2385  "/", H5P_DEFAULT)) < 0)
2386  BAIL(NC_EHDFERR);
2387  }
2388  }
2389  assert(grp->hdf_grpid > 0);
2390 
2391  /* Get the group creation flags, to check for creation ordering */
2392  pid = H5Gget_create_plist(grp->hdf_grpid);
2393  H5Pget_link_creation_order(pid, &crt_order_flags);
2394  if (H5Pclose(pid) < 0)
2395  BAIL(NC_EHDFERR);
2396 
2397  /* Set the iteration index to use */
2398  if (crt_order_flags & H5P_CRT_ORDER_TRACKED)
2399  iter_index = H5_INDEX_CRT_ORDER;
2400  else
2401  {
2402  NC_HDF5_FILE_INFO_T *h5 = grp->nc4_info;
2403 
2404  /* Without creation ordering, file must be read-only. */
2405  if (!h5->no_write)
2406  BAIL(NC_ECANTWRITE);
2407 
2408  iter_index = H5_INDEX_NAME;
2409  }
2410 
2411  /* Set user data for iteration */
2412  udata.grp = grp;
2413 
2414  /* Iterate over links in this group, building lists for the types,
2415  * datasets and groups encountered
2416  */
2417  if (H5Literate(grp->hdf_grpid, iter_index, H5_ITER_INC, &idx,
2418  nc4_rec_read_metadata_cb, (void *)&udata) < 0)
2419  BAIL(NC_EHDFERR);
2420 
2421  /* Process the child groups found */
2422  /* (Deferred until now, so that the types in the current group get
2423  * processed and are available for vars in the child group(s).)
2424  */
2425  for (oinfo = udata.grps_head; oinfo; oinfo = udata.grps_head)
2426  {
2427  NC_GRP_INFO_T *child_grp;
2428  NC_HDF5_FILE_INFO_T *h5 = grp->nc4_info;
2429 
2430  /* Add group to file's hierarchy */
2431  if ((retval = nc4_grp_list_add(&(grp->children), h5->next_nc_grpid++,
2432  grp, grp->nc4_info->controller, oinfo->oname, &child_grp)))
2433  BAIL(retval);
2434 
2435  /* Recursively read the child group's metadata */
2436  if ((retval = nc4_rec_read_metadata(child_grp)))
2437  BAIL(retval);
2438 
2439  /* Close the object */
2440  if (H5Oclose(oinfo->oid) < 0)
2441  BAIL(NC_EHDFERR);
2442 
2443  /* Advance to next node, free current node */
2444  udata.grps_head = oinfo->next;
2445  free(oinfo);
2446  }
2447 
2448  /* Scan the group for global (i.e. group-level) attributes. */
2449  if ((retval = read_grp_atts(grp)))
2450  BAIL(retval);
2451 
2452  /* when exiting define mode, mark all variable written */
2453  for (i=0; i<grp->vars.nelems; i++)
2454  grp->vars.value[i]->written_to = NC_TRUE;
2455 
2456 exit:
2457  /* Clean up local information on error, if anything remains */
2458  if (retval)
2459  {
2460  for (oinfo = udata.grps_head; oinfo; oinfo = udata.grps_head)
2461  {
2462  /* Close the object */
2463  if (H5Oclose(oinfo->oid) < 0)
2464  BAIL2(NC_EHDFERR);
2465 
2466  /* Advance to next node, free current node */
2467  udata.grps_head = oinfo->next;
2468  free(oinfo);
2469  }
2470  }
2471 
2472  return retval;
2473 }
2474 
2488 static int
2489 nc4_open_file(const char *path, int mode, void* parameters, NC *nc)
2490 {
2491  hid_t fapl_id = H5P_DEFAULT;
2492  unsigned flags = (mode & NC_WRITE) ?
2493  H5F_ACC_RDWR : H5F_ACC_RDONLY;
2494  int retval;
2495  NC_HDF5_FILE_INFO_T* nc4_info = NULL;
2496  int inmemory = ((mode & NC_INMEMORY) == NC_INMEMORY);
2497  NC_MEM_INFO* meminfo = (NC_MEM_INFO*)parameters;
2498 #ifdef USE_PARALLEL4
2499  NC_MPI_INFO* mpiinfo = (NC_MPI_INFO*)parameters;
2500  int comm_duped = 0; /* Whether the MPI Communicator was duplicated */
2501  int info_duped = 0; /* Whether the MPI Info object was duplicated */
2502 #endif /* !USE_PARALLEL4 */
2503 
2504  LOG((3, "%s: path %s mode %d", __func__, path, mode));
2505  assert(path && nc);
2506 
2507  /* Add necessary structs to hold netcdf-4 file data. */
2508  if ((retval = nc4_nc4f_list_add(nc, path, mode)))
2509  BAIL(retval);
2510  nc4_info = NC4_DATA(nc);
2511  assert(nc4_info && nc4_info->root_grp);
2512 
2513  /* Need this access plist to control how HDF5 handles open objects
2514  * on file close. (Setting H5F_CLOSE_SEMI will cause H5Fclose to
2515  * fail if there are any open objects in the file. */
2516  if ((fapl_id = H5Pcreate(H5P_FILE_ACCESS)) < 0)
2517  BAIL(NC_EHDFERR);
2518 
2519  if (H5Pset_fclose_degree(fapl_id, H5F_CLOSE_SEMI))
2520  BAIL(NC_EHDFERR);
2521 
2522 #ifdef USE_PARALLEL4
2523  /* If this is a parallel file create, set up the file creation
2524  property list. */
2525  if (mode & NC_MPIIO || mode & NC_MPIPOSIX)
2526  {
2527  nc4_info->parallel = NC_TRUE;
2528  if (mode & NC_MPIIO) /* MPI/IO */
2529  {
2530  LOG((4, "opening parallel file with MPI/IO"));
2531  if (H5Pset_fapl_mpio(fapl_id, mpiinfo->comm, mpiinfo->info) < 0)
2532  BAIL(NC_EPARINIT);
2533  }
2534 #ifdef USE_PARALLEL_POSIX
2535  else /* MPI/POSIX */
2536  {
2537  LOG((4, "opening parallel file with MPI/posix"));
2538  if (H5Pset_fapl_mpiposix(fapl_id, mpiinfo->comm, 0) < 0)
2539  BAIL(NC_EPARINIT);
2540  }
2541 #else /* USE_PARALLEL_POSIX */
2542  /* Should not happen! Code in NC4_create/NC4_open should alias the
2543  * NC_MPIPOSIX flag to NC_MPIIO, if the MPI-POSIX VFD is not
2544  * available in HDF5. -QAK
2545  */
2546  else /* MPI/POSIX */
2547  BAIL(NC_EPARINIT);
2548 #endif /* USE_PARALLEL_POSIX */
2549 
2550  /* Keep copies of the MPI Comm & Info objects */
2551  if (MPI_SUCCESS != MPI_Comm_dup(mpiinfo->comm, &nc4_info->comm))
2552  BAIL(NC_EMPI);
2553  comm_duped++;
2554  if (MPI_INFO_NULL != mpiinfo->info)
2555  {
2556  if (MPI_SUCCESS != MPI_Info_dup(mpiinfo->info, &nc4_info->info))
2557  BAIL(NC_EMPI);
2558  info_duped++;
2559  }
2560  else
2561  {
2562  /* No dup, just copy it. */
2563  nc4_info->info = mpiinfo->info;
2564  }
2565  }
2566 #else /* only set cache for non-parallel. */
2567  if (H5Pset_cache(fapl_id, 0, nc4_chunk_cache_nelems, nc4_chunk_cache_size,
2569  BAIL(NC_EHDFERR);
2570  LOG((4, "%s: set HDF raw chunk cache to size %d nelems %d preemption %f",
2572 #endif /* USE_PARALLEL4 */
2573 
2574  /* The NetCDF-3.x prototype contains an mode option NC_SHARE for
2575  multiple processes accessing the dataset concurrently. As there
2576  is no HDF5 equivalent, NC_SHARE is treated as NC_NOWRITE. */
2577 #ifdef HDF5_HAS_COLL_METADATA_OPS
2578  H5Pset_all_coll_metadata_ops(fapl_id, 1 );
2579 #endif
2580  if(inmemory) {
2581  if((nc4_info->hdfid = H5LTopen_file_image(meminfo->memory,meminfo->size,
2582  H5LT_FILE_IMAGE_DONT_COPY|H5LT_FILE_IMAGE_DONT_RELEASE
2583  )) < 0)
2584  BAIL(NC_EHDFERR);
2585  nc4_info->no_write = NC_TRUE;
2586  } else if ((nc4_info->hdfid = H5Fopen(path, flags, fapl_id)) < 0)
2587  BAIL(NC_EHDFERR);
2588 
2589  /* Does the mode specify that this file is read-only? */
2590  if ((mode & NC_WRITE) == 0)
2591  nc4_info->no_write = NC_TRUE;
2592 
2593  /* Now read in all the metadata. Some types and dimscale
2594  * information may be difficult to resolve here, if, for example, a
2595  * dataset of user-defined type is encountered before the
2596  * definition of that type. */
2597  if ((retval = nc4_rec_read_metadata(nc4_info->root_grp)))
2598  BAIL(retval);
2599 
2600  /* Now figure out which netCDF dims are indicated by the dimscale
2601  * information. */
2602  if ((retval = nc4_rec_match_dimscales(nc4_info->root_grp)))
2603  BAIL(retval);
2604 
2605 #ifdef LOGGING
2606  /* This will print out the names, types, lens, etc of the vars and
2607  atts in the file, if the logging level is 2 or greater. */
2608  log_metadata_nc(nc);
2609 #endif
2610 
2611  /* Close the property list. */
2612  if (H5Pclose(fapl_id) < 0)
2613  BAIL(NC_EHDFERR);
2614 
2615  NC4_get_fileinfo(nc4_info,NULL);
2616 
2617  return NC_NOERR;
2618 
2619 exit:
2620 #ifdef USE_PARALLEL4
2621  if (comm_duped) MPI_Comm_free(&nc4_info->comm);
2622  if (info_duped) MPI_Info_free(&nc4_info->info);
2623 #endif
2624  if (fapl_id != H5P_DEFAULT) H5Pclose(fapl_id);
2625  if (!nc4_info) return retval;
2626  close_netcdf4_file(nc4_info,1); /* treat like abort*/
2627  return retval;
2628 }
2629 
2630 #ifdef USE_HDF4
2631 
2645 static int
2646 get_netcdf_type_from_hdf4(NC_HDF5_FILE_INFO_T *h5, int32 hdf4_typeid,
2647  nc_type *xtype, NC_TYPE_INFO_T *type_info)
2648 {
2649  int t = 0;
2650 
2651  /* Added this variable in the course of fixing NCF-332.
2652  * Prior to the fix, all data types were assigned
2653  * NC_ENDIAN_BIG, so I am preserving that here for now.
2654  * Not sure why it wouldn't be NC_ENDIAN_NATIVE, although
2655  * I can hazard a guess or two.
2656  */
2657  int endianness = NC_ENDIAN_BIG;
2658  assert(h5 && xtype);
2659 
2660  switch(hdf4_typeid)
2661  {
2662  case DFNT_CHAR:
2663  *xtype = NC_CHAR;
2664  t = 0;
2665  break;
2666  case DFNT_UCHAR:
2667  case DFNT_UINT8:
2668  *xtype = NC_UBYTE;
2669  t = 6;
2670  break;
2671  case DFNT_LUINT8:
2672  *xtype = NC_UBYTE;
2673  t = 6;
2674  endianness = NC_ENDIAN_LITTLE;
2675  break;
2676  case DFNT_INT8:
2677  *xtype = NC_BYTE;
2678  t = 1;
2679  break;
2680  case DFNT_LINT8:
2681  *xtype = NC_BYTE;
2682  t = 1;
2683  endianness = NC_ENDIAN_LITTLE;
2684  break;
2685  case DFNT_INT16:
2686  *xtype = NC_SHORT;
2687  t = 2;
2688  break;
2689  case DFNT_LINT16:
2690  *xtype = NC_SHORT;
2691  t = 2;
2692  endianness = NC_ENDIAN_LITTLE;
2693  break;
2694  case DFNT_UINT16:
2695  *xtype = NC_USHORT;
2696  t = 7;
2697  break;
2698  case DFNT_LUINT16:
2699  *xtype = NC_USHORT;
2700  t = 7;
2701  endianness = NC_ENDIAN_LITTLE;
2702  break;
2703  case DFNT_INT32:
2704  *xtype = NC_INT;
2705  t = 3;
2706  break;
2707  case DFNT_LINT32:
2708  *xtype = NC_INT;
2709  t = 3;
2710  endianness = NC_ENDIAN_LITTLE;
2711  break;
2712  case DFNT_UINT32:
2713  *xtype = NC_UINT;
2714  t = 8;
2715  break;
2716  case DFNT_LUINT32:
2717  *xtype = NC_UINT;
2718  t = 8;
2719  endianness = NC_ENDIAN_LITTLE;
2720  break;
2721  case DFNT_FLOAT32:
2722  *xtype = NC_FLOAT;
2723  t = 4;
2724  break;
2725  case DFNT_LFLOAT32:
2726  *xtype = NC_FLOAT;
2727  t = 4;
2728  endianness = NC_ENDIAN_LITTLE;
2729  break;
2730  case DFNT_FLOAT64:
2731  *xtype = NC_DOUBLE;
2732  t = 5;
2733  break;
2734  case DFNT_LFLOAT64:
2735  *xtype = NC_DOUBLE;
2736  t = 5;
2737  endianness = NC_ENDIAN_LITTLE;
2738  break;
2739  default:
2740  *xtype = NC_NAT;
2741  return NC_EBADTYPID;
2742  }
2743 
2744  if (type_info)
2745  {
2746  if (hdf4_typeid == DFNT_FLOAT32)
2747  type_info->nc_type_class = NC_FLOAT;
2748  else if (hdf4_typeid == DFNT_FLOAT64)
2749  type_info->nc_type_class = NC_DOUBLE;
2750  else if (hdf4_typeid == DFNT_CHAR)
2751  type_info->nc_type_class = NC_STRING;
2752  else
2753  type_info->nc_type_class = NC_INT;
2754  type_info->endianness = endianness;
2755  type_info->nc_typeid = *xtype;
2756  type_info->size = nc_type_size_g[t];
2757  if (!(type_info->name = strdup(nc_type_name_g[t])))
2758  return NC_ENOMEM;
2759  }
2760 
2761  return NC_NOERR;
2762 }
2763 
2776 static int
2777 nc4_open_hdf4_file(const char *path, int mode, NC *nc)
2778 {
2779  NC_HDF5_FILE_INFO_T *h5;
2780  NC_GRP_INFO_T *grp;
2781  NC_ATT_INFO_T *att;
2782  int32 num_datasets, num_gatts;
2783  int32 rank;
2784  int v, d, a;
2785  int retval;
2786  NC_HDF5_FILE_INFO_T* nc4_info = NULL;
2787 
2788  LOG((3, "%s: path %s mode %d", __func__, path, mode));
2789  assert(path && nc);
2790 
2791  /* Must be read-only access to hdf4 files. */
2792  if (mode & NC_WRITE)
2793  return NC_EINVAL;
2794 
2795  /* Add necessary structs to hold netcdf-4 file data. */
2796  if ((retval = nc4_nc4f_list_add(nc, path, mode)))
2797  return retval;
2798  nc4_info = NC4_DATA(nc);
2799  assert(nc4_info && nc4_info->root_grp);
2800  h5 = nc4_info;
2801  h5->hdf4 = NC_TRUE;
2802  grp = h5->root_grp;
2803  h5->no_write = NC_TRUE;
2804 
2805  /* Open the file and initialize SD interface. */
2806  if ((h5->sdid = SDstart(path, DFACC_READ)) == FAIL)
2807  return NC_EHDFERR;
2808 
2809  /* Learn how many datasets and global atts we have. */
2810  if (SDfileinfo(h5->sdid, &num_datasets, &num_gatts))
2811  return NC_EHDFERR;
2812 
2813  /* Read the atts. */
2814  for (a = 0; a < num_gatts; a++)
2815  {
2816  int32 att_data_type, att_count;
2817  size_t att_type_size;
2818 
2819  /* Add to the end of the list of atts for this var. */
2820  if ((retval = nc4_att_list_add(&h5->root_grp->att, &att)))
2821  return retval;
2822  att->attnum = grp->natts++;
2823  att->created = NC_TRUE;
2824 
2825  /* Learn about this attribute. */
2826  if (!(att->name = malloc(NC_MAX_HDF4_NAME * sizeof(char))))
2827  return NC_ENOMEM;
2828  if (SDattrinfo(h5->sdid, a, att->name, &att_data_type, &att_count))
2829  return NC_EATTMETA;
2830  if ((retval = get_netcdf_type_from_hdf4(h5, att_data_type,
2831  &att->nc_typeid, NULL)))
2832  return retval;
2833  att->len = att_count;
2834 
2835  /* Allocate memory to hold the data. */
2836  if ((retval = nc4_get_typelen_mem(h5, att->nc_typeid, 0, &att_type_size)))
2837  return retval;
2838  if (!(att->data = malloc(att_type_size * att->len)))
2839  return NC_ENOMEM;
2840 
2841  /* Read the data. */
2842  if (SDreadattr(h5->sdid, a, att->data))
2843  return NC_EHDFERR;
2844  }
2845 
2846  /* Read each dataset. */
2847  for (v = 0; v < num_datasets; v++)
2848  {
2849  NC_VAR_INFO_T *var;
2850  int32 data_type, num_atts;
2851  /* Problem: Number of dims is returned by the call that requires
2852  a pre-allocated array, 'dimsize'.
2853  From SDS_SD website:
2854  http://www.hdfgroup.org/training/HDFtraining/UsersGuide/SDS_SD.fm3.html
2855  The maximum rank is 32, or MAX_VAR_DIMS (as defined in netcdf.h).
2856 
2857  int32 dimsize[MAX_VAR_DIMS];
2858  */
2859  int32 *dimsize = NULL;
2860  size_t var_type_size;
2861  int a;
2862 
2863  /* Add a variable. */
2864  if ((retval = nc4_var_add(&var)))
2865  return retval;
2866 
2867  var->varid = grp->nvars++;
2868  var->created = NC_TRUE;
2869  var->written_to = NC_TRUE;
2870 
2871  /* Add a var to the variable array, growing it as needed. */
2872  if ((retval = nc4_vararray_add(grp, var)))
2873  return retval;
2874 
2875  /* Open this dataset in HDF4 file. */
2876  if ((var->sdsid = SDselect(h5->sdid, v)) == FAIL)
2877  return NC_EVARMETA;
2878 
2879  /* Get shape, name, type, and attribute info about this dataset. */
2880  if (!(var->name = malloc(NC_MAX_HDF4_NAME + 1)))
2881  return NC_ENOMEM;
2882 
2883  /* Invoke SDgetInfo with null dimsize to get rank. */
2884  if (SDgetinfo(var->sdsid, var->name, &rank, NULL, &data_type, &num_atts))
2885  return NC_EVARMETA;
2886 
2887  var->hash = hash_fast(var->name, strlen(var->name));
2888 
2889  if(!(dimsize = (int32*)malloc(sizeof(int32)*rank)))
2890  return NC_ENOMEM;
2891 
2892  if (SDgetinfo(var->sdsid, var->name, &rank, dimsize, &data_type, &num_atts)) {
2893  if(dimsize) free(dimsize);
2894  return NC_EVARMETA;
2895  }
2896 
2897  var->ndims = rank;
2898  var->hdf4_data_type = data_type;
2899 
2900  /* Fill special type_info struct for variable type information. */
2901  if (!(var->type_info = calloc(1, sizeof(NC_TYPE_INFO_T)))) {
2902  if(dimsize) free(dimsize);
2903  return NC_ENOMEM;
2904  }
2905 
2906  if ((retval = get_netcdf_type_from_hdf4(h5, data_type, &var->type_info->nc_typeid, var->type_info))) {
2907  if(dimsize) free(dimsize);
2908  return retval;
2909  }
2910 
2911  /* Indicate that the variable has a pointer to the type */
2912  var->type_info->rc++;
2913 
2914  if ((retval = nc4_get_typelen_mem(h5, var->type_info->nc_typeid, 0, &var_type_size))) {
2915  if(dimsize) free(dimsize);
2916  return retval;
2917  }
2918 
2919  var->type_info->size = var_type_size;
2920  LOG((3, "reading HDF4 dataset %s, rank %d netCDF type %d", var->name,
2921  rank, var->type_info->nc_typeid));
2922 
2923  /* Get the fill value. */
2924  if (!(var->fill_value = malloc(var_type_size))) {
2925  if(dimsize) free(dimsize);
2926  return NC_ENOMEM;
2927  }
2928 
2929  if (SDgetfillvalue(var->sdsid, var->fill_value))
2930  {
2931  /* Whoops! No fill value! */
2932  free(var->fill_value);
2933  var->fill_value = NULL;
2934  }
2935 
2936  /* Allocate storage for dimension info in this variable. */
2937  if (var->ndims)
2938  {
2939  if (!(var->dim = malloc(sizeof(NC_DIM_INFO_T *) * var->ndims))) {
2940  if(dimsize) free(dimsize);
2941  return NC_ENOMEM;
2942  }
2943 
2944  if (!(var->dimids = malloc(sizeof(int) * var->ndims))) {
2945  if(dimsize) free(dimsize);
2946  return NC_ENOMEM;
2947  }
2948  }
2949 
2950 
2951  /* Find its dimensions. */
2952  for (d = 0; d < var->ndims; d++)
2953  {
2954  int32 dimid, dim_len, dim_data_type, dim_num_attrs;
2955  char dim_name[NC_MAX_NAME + 1];
2956  NC_DIM_INFO_T *dim;
2957 
2958  if ((dimid = SDgetdimid(var->sdsid, d)) == FAIL) {
2959  if(dimsize) free(dimsize);
2960  return NC_EDIMMETA;
2961  }
2962  if (SDdiminfo(dimid, dim_name, &dim_len, &dim_data_type,
2963  &dim_num_attrs))
2964  {
2965  if(dimsize) free(dimsize);
2966  return NC_EDIMMETA;
2967  }
2968 
2969  /* Do we already have this dimension? HDF4 explicitly uses
2970  * the name to tell. */
2971  for (dim = grp->dim; dim; dim = dim->l.next)
2972  if (!strcmp(dim->name, dim_name))
2973  break;
2974 
2975  /* If we didn't find this dimension, add one. */
2976  if (!dim)
2977  {
2978  LOG((4, "adding dimension %s for HDF4 dataset %s",
2979  dim_name, var->name));
2980  if ((retval = nc4_dim_list_add(&grp->dim, &dim)))
2981  return retval;
2982  dim->dimid = grp->nc4_info->next_dimid++;
2983  if (strlen(dim_name) > NC_MAX_HDF4_NAME)
2984  return NC_EMAXNAME;
2985  if (!(dim->name = strdup(dim_name)))
2986  return NC_ENOMEM;
2987  if (dim_len)
2988  dim->len = dim_len;
2989  else
2990  dim->len = *dimsize;
2991  dim->hash = hash_fast(dim_name, strlen(dim_name));
2992  }
2993 
2994  /* Tell the variable the id of this dimension. */
2995  var->dimids[d] = dim->dimid;
2996  var->dim[d] = dim;
2997  }
2998 
2999  /* Read the atts. */
3000  for (a = 0; a < num_atts; a++)
3001  {
3002  int32 att_data_type, att_count;
3003  size_t att_type_size;
3004 
3005  /* Add to the end of the list of atts for this var. */
3006  if ((retval = nc4_att_list_add(&var->att, &att))) {
3007  if(dimsize) free(dimsize);
3008  return retval;
3009  }
3010  att->attnum = var->natts++;
3011  att->created = NC_TRUE;
3012 
3013  /* Learn about this attribute. */
3014  if (!(att->name = malloc(NC_MAX_HDF4_NAME * sizeof(char)))) {
3015  if(dimsize) free(dimsize);
3016  return NC_ENOMEM;
3017  }
3018  if (SDattrinfo(var->sdsid, a, att->name, &att_data_type, &att_count)) {
3019  if(dimsize) free(dimsize);
3020  return NC_EATTMETA;
3021  }
3022  if ((retval = get_netcdf_type_from_hdf4(h5, att_data_type,
3023  &att->nc_typeid, NULL))) {
3024  if(dimsize) free(dimsize);
3025  return retval;
3026  }
3027 
3028  att->len = att_count;
3029 
3030  /* Allocate memory to hold the data. */
3031  if ((retval = nc4_get_typelen_mem(h5, att->nc_typeid, 0, &att_type_size))) {
3032  if(dimsize) free(dimsize);
3033  return retval;
3034  }
3035  if (!(att->data = malloc(att_type_size * att->len))) {
3036  if(dimsize) free(dimsize);
3037  return NC_ENOMEM;
3038  }
3039 
3040  /* Read the data. */
3041  if (SDreadattr(var->sdsid, a, att->data)) {
3042  if(dimsize) free(dimsize);
3043  return NC_EHDFERR;
3044  }
3045  }
3046  if(dimsize) free(dimsize);
3047 
3048  {
3049  /* HDF4 files can be chunked */
3050  HDF_CHUNK_DEF chunkdefs;
3051  int flag;
3052  if(!SDgetchunkinfo(var->sdsid, &chunkdefs, &flag)) {
3053  if(flag == HDF_NONE)
3054  var->contiguous = NC_TRUE;
3055  else if((flag & HDF_CHUNK) != 0) {
3056  var->contiguous = NC_FALSE;
3057  if (!(var->chunksizes = malloc(var->ndims * sizeof(size_t))))
3058  return NC_ENOMEM;
3059  for (d = 0; d < var->ndims; d++) {
3060  var->chunksizes[d] = chunkdefs.chunk_lengths[d];
3061  }
3062  }
3063  }
3064  }
3065 
3066  } /* next var */
3067 
3068 #ifdef LOGGING
3069  /* This will print out the names, types, lens, etc of the vars and
3070  atts in the file, if the logging level is 2 or greater. */
3071  log_metadata_nc(h5->root_grp->nc4_info->controller);
3072 #endif
3073  return NC_NOERR;
3074 }
3075 #endif /* USE_HDF4 */
3076 
3093 int
3094 NC4_open(const char *path, int mode, int basepe, size_t *chunksizehintp,
3095  int use_parallel, void *parameters, NC_Dispatch *dispatch, NC *nc_file)
3096 {
3097  int res;
3098  int is_hdf5_file = 0;
3099 #ifdef USE_HDF4
3100  int is_hdf4_file = 0;
3101 #endif /* USE_HDF4 */
3102 #ifdef USE_PARALLEL4
3103  NC_MPI_INFO mpidfalt = {MPI_COMM_WORLD, MPI_INFO_NULL};
3104 #endif
3105 #if defined USE_PARALLEL4 || defined USE_HDF4
3106  int inmemory = ((mode & NC_INMEMORY) == NC_INMEMORY);
3107 #endif
3108 
3109  assert(nc_file && path);
3110 
3111  LOG((1, "%s: path %s mode %d params %x",
3112  __func__, path, mode, parameters));
3113 
3114 #ifdef USE_PARALLEL4
3115  if (!inmemory && use_parallel && parameters == NULL)
3116  parameters = &mpidfalt;
3117 #endif /* USE_PARALLEL4 */
3118 
3119  /* If this is our first file, initialize HDF5. */
3120  if (!nc4_hdf5_initialized)
3121  nc4_hdf5_initialize();
3122 
3123  /* Check the mode for validity */
3124  if((mode & ILLEGAL_OPEN_FLAGS) != 0)
3125  {res = NC_EINVAL; goto done;}
3126 
3127  /* Cannot have both */
3128  if((mode & (NC_MPIIO|NC_MPIPOSIX)) == (NC_MPIIO|NC_MPIPOSIX))
3129  {res = NC_EINVAL; goto done;}
3130 
3131 #ifndef USE_PARALLEL_POSIX
3132 /* If the HDF5 library has been compiled without the MPI-POSIX VFD, alias
3133  * the NC_MPIPOSIX flag to NC_MPIIO. -QAK
3134  */
3135  if(mode & NC_MPIPOSIX)
3136  {
3137  mode &= ~NC_MPIPOSIX;
3138  mode |= NC_MPIIO;
3139  }
3140 #endif /* USE_PARALLEL_POSIX */
3141 
3142  /* Figure out if this is a hdf4 or hdf5 file. */
3143  if(nc_file->model == NC_FORMATX_NC4)
3144  is_hdf5_file = 1;
3145 #ifdef USE_HDF4
3146  else if(nc_file->model == NC_FORMATX_NC_HDF4)
3147  is_hdf4_file = 1;
3148 #endif /* USE_HDF4 */
3149  /* Depending on the type of file, open it. */
3150  nc_file->int_ncid = nc_file->ext_ncid;
3151  if (is_hdf5_file)
3152  res = nc4_open_file(path, mode, parameters, nc_file);
3153 #ifdef USE_HDF4
3154  else if (is_hdf4_file && inmemory)
3155  {res = NC_EDISKLESS; goto done;}
3156  else if (is_hdf4_file)
3157  res = nc4_open_hdf4_file(path, mode, nc_file);
3158 #endif /* USE_HDF4 */
3159  else
3160  res = NC_ENOTNC;
3161 done:
3162  return res;
3163 }
3164 
3179 int
3180 NC4_set_fill(int ncid, int fillmode, int *old_modep)
3181 {
3182  NC *nc;
3183  NC_HDF5_FILE_INFO_T* nc4_info;
3184 
3185  LOG((2, "%s: ncid 0x%x fillmode %d", __func__, ncid, fillmode));
3186 
3187  if (!(nc = nc4_find_nc_file(ncid,&nc4_info)))
3188  return NC_EBADID;
3189  assert(nc4_info);
3190 
3191  /* Trying to set fill on a read-only file? You sicken me! */
3192  if (nc4_info->no_write)
3193  return NC_EPERM;
3194 
3195  /* Did you pass me some weird fillmode? */
3196  if (fillmode != NC_FILL && fillmode != NC_NOFILL)
3197  return NC_EINVAL;
3198 
3199  /* If the user wants to know, tell him what the old mode was. */
3200  if (old_modep)
3201  *old_modep = nc4_info->fill_mode;
3202 
3203  nc4_info->fill_mode = fillmode;
3204 
3205 
3206  return NC_NOERR;
3207 }
3208 
3218 int
3219 NC4_redef(int ncid)
3220 {
3221  NC_HDF5_FILE_INFO_T* nc4_info;
3222 
3223  LOG((1, "%s: ncid 0x%x", __func__, ncid));
3224 
3225  /* Find this file's metadata. */
3226  if (!(nc4_find_nc_file(ncid,&nc4_info)))
3227  return NC_EBADID;
3228  assert(nc4_info);
3229 
3230  /* If we're already in define mode, return an error. */
3231  if (nc4_info->flags & NC_INDEF)
3232  return NC_EINDEFINE;
3233 
3234  /* If the file is read-only, return an error. */
3235  if (nc4_info->no_write)
3236  return NC_EPERM;
3237 
3238  /* Set define mode. */
3239  nc4_info->flags |= NC_INDEF;
3240 
3241  /* For nc_abort, we need to remember if we're in define mode as a
3242  redef. */
3243  nc4_info->redef = NC_TRUE;
3244 
3245  return NC_NOERR;
3246 }
3247 
3261 int
3262 NC4__enddef(int ncid, size_t h_minfree, size_t v_align,
3263  size_t v_minfree, size_t r_align)
3264 {
3265  if (nc4_find_nc_file(ncid,NULL) == NULL)
3266  return NC_EBADID;
3267 
3268  return NC4_enddef(ncid);
3269 }
3270 
3280 static int NC4_enddef(int ncid)
3281 {
3282  NC *nc;
3283  NC_HDF5_FILE_INFO_T* nc4_info;
3284  NC_GRP_INFO_T *grp;
3285  int i;
3286 
3287  LOG((1, "%s: ncid 0x%x", __func__, ncid));
3288 
3289  if (!(nc = nc4_find_nc_file(ncid,&nc4_info)))
3290  return NC_EBADID;
3291  assert(nc4_info);
3292 
3293  /* Find info for this file and group */
3294  if (!(grp = nc4_rec_find_grp(nc4_info->root_grp, (ncid & GRP_ID_MASK))))
3295  return NC_EBADGRPID;
3296 
3297  /* when exiting define mode, mark all variable written */
3298  for (i=0; i<grp->vars.nelems; i++)
3299  grp->vars.value[i]->written_to = NC_TRUE;
3300 
3301  return nc4_enddef_netcdf4_file(nc4_info);
3302 }
3303 
3313 int
3314 NC4_sync(int ncid)
3315 {
3316  NC *nc;
3317  int retval;
3318  NC_HDF5_FILE_INFO_T* nc4_info;
3319 
3320  LOG((2, "%s: ncid 0x%x", __func__, ncid));
3321 
3322  if (!(nc = nc4_find_nc_file(ncid,&nc4_info)))
3323  return NC_EBADID;
3324  assert(nc4_info);
3325 
3326  /* If we're in define mode, we can't sync. */
3327  if (nc4_info && nc4_info->flags & NC_INDEF)
3328  {
3329  if (nc4_info->cmode & NC_CLASSIC_MODEL)
3330  return NC_EINDEFINE;
3331  if ((retval = NC4_enddef(ncid)))
3332  return retval;
3333  }
3334 
3335  return sync_netcdf4_file(nc4_info);
3336 }
3337 
3351 int
3352 NC4_abort(int ncid)
3353 {
3354  NC *nc;
3355  int delete_file = 0;
3356  char path[NC_MAX_NAME + 1];
3357  int retval = NC_NOERR;
3358  NC_HDF5_FILE_INFO_T* nc4_info;
3359 
3360  LOG((2, "%s: ncid 0x%x", __func__, ncid));
3361 
3362  /* Find metadata for this file. */
3363  if (!(nc = nc4_find_nc_file(ncid,&nc4_info)))
3364  return NC_EBADID;
3365 
3366  assert(nc4_info);
3367 
3368  /* If we're in define mode, but not redefing the file, delete it. */
3369  if (nc4_info->flags & NC_INDEF && !nc4_info->redef)
3370  {
3371  delete_file++;
3372  strncpy(path, nc->path,NC_MAX_NAME);
3373  }
3374 
3375  /* Free any resources the netcdf-4 library has for this file's
3376  * metadata. */
3377  if ((retval = close_netcdf4_file(nc4_info, 1)))
3378  return retval;
3379 
3380  /* Delete the file, if we should. */
3381  if (delete_file)
3382  if (remove(path) < 0)
3383  return NC_ECANTREMOVE;
3384 
3385  return retval;
3386 }
3387 
3396 int
3397 NC4_close(int ncid)
3398 {
3399  NC_GRP_INFO_T *grp;
3400  NC *nc;
3401  NC_HDF5_FILE_INFO_T *h5;
3402  int retval;
3403 
3404  LOG((1, "%s: ncid 0x%x", __func__, ncid));
3405 
3406  /* Find our metadata for this file. */
3407  if ((retval = nc4_find_nc_grp_h5(ncid, &nc, &grp, &h5)))
3408  return retval;
3409 
3410  assert(nc && h5 && grp);
3411 
3412  /* This must be the root group. */
3413  if (grp->parent)
3414  return NC_EBADGRPID;
3415 
3416  /* Call the nc4 close. */
3417  if ((retval = close_netcdf4_file(grp->nc4_info, 0)))
3418  return retval;
3419 
3420  return NC_NOERR;
3421 }
3422 
3440 int
3441 NC4_inq(int ncid, int *ndimsp, int *nvarsp, int *nattsp, int *unlimdimidp)
3442 {
3443  NC *nc;
3444  NC_HDF5_FILE_INFO_T *h5;
3445  NC_GRP_INFO_T *grp;
3446  NC_DIM_INFO_T *dim;
3447  NC_ATT_INFO_T *att;
3448  int retval;
3449 
3450  LOG((2, "%s: ncid 0x%x", __func__, ncid));
3451 
3452  /* Find file metadata. */
3453  if ((retval = nc4_find_nc_grp_h5(ncid, &nc, &grp, &h5)))
3454  return retval;
3455 
3456  assert(h5 && grp && nc);
3457 
3458  /* Count the number of dims, vars, and global atts. */
3459  if (ndimsp)
3460  {
3461  *ndimsp = 0;
3462  for (dim = grp->dim; dim; dim = dim->l.next)
3463  (*ndimsp)++;
3464  }
3465  if (nvarsp)
3466  {
3467  int i;
3468  *nvarsp = 0;
3469  for (i=0; i < grp->vars.nelems; i++)
3470  {
3471  if (grp->vars.value[i])
3472  (*nvarsp)++;
3473  }
3474  }
3475  if (nattsp)
3476  {
3477  *nattsp = 0;
3478  for (att = grp->att; att; att = att->l.next)
3479  (*nattsp)++;
3480  }
3481 
3482  if (unlimdimidp)
3483  {
3484  /* Default, no unlimited dimension */
3485  *unlimdimidp = -1;
3486 
3487  /* If there's more than one unlimited dim, which was not possible
3488  with netcdf-3, then only the last unlimited one will be reported
3489  back in xtendimp. */
3490  /* Note that this code is inconsistent with nc_inq_unlimid() */
3491  for (dim = grp->dim; dim; dim = dim->l.next)
3492  if (dim->unlimited)
3493  {
3494  *unlimdimidp = dim->dimid;
3495  break;
3496  }
3497  }
3498 
3499  return NC_NOERR;
3500 }
3501 
3510 int
3511 nc4_enddef_netcdf4_file(NC_HDF5_FILE_INFO_T *h5)
3512 {
3513  assert(h5);
3514  LOG((3, "%s", __func__));
3515 
3516  /* If we're not in define mode, return an error. */
3517  if (!(h5->flags & NC_INDEF))
3518  return NC_ENOTINDEFINE;
3519 
3520  /* Turn define mode off. */
3521  h5->flags ^= NC_INDEF;
3522 
3523  /* Redef mode needs to be tracked separately for nc_abort. */
3524  h5->redef = NC_FALSE;
3525 
3526  return sync_netcdf4_file(h5);
3527 }
3528 
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:428
#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:426
#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:445
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_ENOTNC
Not a netcdf file.
Definition: netcdf.h:371
#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:432
#define NUM_TYPES
Number of netCDF atomic types.
Definition: nc4file.c:687
#define NC_VLEN
vlen (variable-length) types
Definition: netcdf.h:52
#define NC_EMPI
MPI operation failed.
Definition: netcdf.h:456
#define NC_EDISKLESS
Error in using diskless access.
Definition: netcdf.h:454
int nc4_hdf5_initialized
True if initialization has happened.
Definition: nc4internal.c:56
#define NC_EFILEMETA
Problem with file metadata.
Definition: netcdf.h:430
#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_EDIMMETA
Problem with dimension metadata.
Definition: netcdf.h:431
#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:684
#define NC_EINVAL
Invalid Argument.
Definition: netcdf.h:325
#define CD_NELEMS_ZLIB
Number of parameters needed for ZLIB filter.
Definition: nc4file.c:30
size_t nc4_chunk_cache_size
Default chunk cache size.
Definition: nc4file.c:683
#define NC_INT
signed 4 byte integer
Definition: netcdf.h:37
#define NC_EBADGRPID
Bad group ID.
Definition: netcdf.h:441
#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:442
#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:725
#define NC_EPARINIT
Error initializing for parallel access.
Definition: netcdf.h:440
#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_FORMATX_NC_HDF4
netCDF-4 subset of HDF4
Definition: netcdf.h:206
#define NC_EBADID
Not a netcdf id.
Definition: netcdf.h:322
#define NC_EVARMETA
Problem with variable metadata.
Definition: netcdf.h:433
This is the type of arrays of vlens.
Definition: netcdf.h:666
#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:747
#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:685
#define NC_WRITE
Set read-write access for nc_open().
Definition: netcdf.h:125
#define NC_EMAXNAME
NC_MAX_NAME exceeded.
Definition: netcdf.h:373
#define NC_EPERM
Write to read only.
Definition: netcdf.h:326
#define NC_MAX_HDF4_NAME
This is the max size of an SD dataset name in HDF4 (from HDF4 documentation).
Definition: netcdf.h:270
#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 Thu Jan 25 2018 21:06:33 for NetCDF. NetCDF is a Unidata library.