NetCDF  4.3.2
 All Data Structures Files Functions Variables Typedefs Macros Modules Pages
nc4file.c
Go to the documentation of this file.
1 
11 #include "config.h"
12 #include <errno.h> /* netcdf functions sometimes return system errors */
13 
14 #include "nc.h"
15 #include "nc4internal.h"
16 #include "nc4dispatch.h"
17 
18 #include "H5DSpublic.h"
19 
20 #ifdef USE_HDF4
21 #include <mfhdf.h>
22 #endif
23 
24 #if 0 /*def USE_PNETCDF*/
25 #include <pnetcdf.h>
26 #endif
27 
28 /* This is to track opened HDF5 objects to make sure they are
29  * closed. */
30 #ifdef EXTRA_TESTS
31 extern int num_plists;
32 extern int num_spaces;
33 #endif /* EXTRA_TESTS */
34 
35 #define MIN_DEFLATE_LEVEL 0
36 #define MAX_DEFLATE_LEVEL 9
37 
38 /* These are the special attributes added by the HDF5 dimension scale
39  * API. They will be ignored by netCDF-4. */
40 #define REFERENCE_LIST "REFERENCE_LIST"
41 #define CLASS "CLASS"
42 #define DIMENSION_LIST "DIMENSION_LIST"
43 #define NAME "NAME"
44 
45 /* Struct to track information about objects in a group, for nc4_rec_read_metadata() */
47 {
48  hid_t oid; /* HDF5 object ID */
49  char oname[NC_MAX_NAME + 1]; /* Name of object */
50  H5G_stat_t statbuf; /* Information about the object */
51  struct NC4_rec_read_metadata_obj_info *next; /* Pointer to next node in list */
53 
54 /* User data struct for call to H5Literate() in nc4_rec_read_metadata() */
55 /* Tracks the groups, named datatypes and datasets in the group, for later use */
57 {
58  NC4_rec_read_metadata_obj_info_t *grps_head, *grps_tail; /* Pointers to head & tail of list of groups */
59  NC_GRP_INFO_T *grp; /* Pointer to parent group */
61 
62 /* Forward */
63 static int NC4_enddef(int ncid);
64 static int nc4_rec_read_metadata(NC_GRP_INFO_T *grp);
65 static int close_netcdf4_file(NC_HDF5_FILE_INFO_T *h5, int abort);
66 
67 /* These are the default chunk cache sizes for HDF5 files created or
68  * opened with netCDF-4. */
69 size_t nc4_chunk_cache_size = CHUNK_CACHE_SIZE;
70 size_t nc4_chunk_cache_nelems = CHUNK_CACHE_NELEMS;
71 float nc4_chunk_cache_preemption = CHUNK_CACHE_PREEMPTION;
72 
73 /* To turn off HDF5 error messages, I have to catch an early
74  invocation of a netcdf function. */
75 static int virgin = 1;
76 
77 /* For performance, fill this array only the first time, and keep it
78  * in global memory for each further use. */
79 #define NUM_TYPES 12
80 static hid_t h5_native_type_constant_g[NUM_TYPES];
81 static const char nc_type_name_g[NUM_TYPES][NC_MAX_NAME + 1] = {"char", "byte", "short",
82  "int", "float", "double", "ubyte",
83  "ushort", "uint", "int64",
84  "uint64", "string"};
85 static const nc_type nc_type_constant_g[NUM_TYPES] = {NC_CHAR, NC_BYTE, NC_SHORT,
89 static const int nc_type_size_g[NUM_TYPES] = {sizeof(char), sizeof(char), sizeof(short),
90  sizeof(int), sizeof(float), sizeof(double), sizeof(unsigned char),
91  sizeof(unsigned short), sizeof(unsigned int), sizeof(long long),
92  sizeof(unsigned long long), sizeof(char *)};
93 
94 /* Set chunk cache size. Only affects files opened/created *after* it
95  * is called. */
96 int
97 nc_set_chunk_cache(size_t size, size_t nelems, float preemption)
98 {
99  if (preemption < 0 || preemption > 1)
100  return NC_EINVAL;
101  nc4_chunk_cache_size = size;
102  nc4_chunk_cache_nelems = nelems;
103  nc4_chunk_cache_preemption = preemption;
104  return NC_NOERR;
105 }
106 
107 /* Get chunk cache size. Only affects files opened/created *after* it
108  * is called. */
109 int
110 nc_get_chunk_cache(size_t *sizep, size_t *nelemsp, float *preemptionp)
111 {
112  if (sizep)
113  *sizep = nc4_chunk_cache_size;
114 
115  if (nelemsp)
116  *nelemsp = nc4_chunk_cache_nelems;
117 
118  if (preemptionp)
119  *preemptionp = nc4_chunk_cache_preemption;
120  return NC_NOERR;
121 }
122 
123 /* Required for fortran to avoid size_t issues. */
124 int
125 nc_set_chunk_cache_ints(int size, int nelems, int preemption)
126 {
127  if (size <= 0 || nelems <= 0 || preemption < 0 || preemption > 100)
128  return NC_EINVAL;
129  nc4_chunk_cache_size = size;
130  nc4_chunk_cache_nelems = nelems;
131  nc4_chunk_cache_preemption = (float)preemption / 100;
132  return NC_NOERR;
133 }
134 
135 int
136 nc_get_chunk_cache_ints(int *sizep, int *nelemsp, int *preemptionp)
137 {
138  if (sizep)
139  *sizep = (int)nc4_chunk_cache_size;
140  if (nelemsp)
141  *nelemsp = (int)nc4_chunk_cache_nelems;
142  if (preemptionp)
143  *preemptionp = (int)(nc4_chunk_cache_preemption * 100);
144 
145  return NC_NOERR;
146 }
147 
148 /* This will return the length of a netcdf data type in bytes. */
149 int
150 nc4typelen(nc_type type)
151 {
152  switch(type){
153  case NC_BYTE:
154  case NC_CHAR:
155  case NC_UBYTE:
156  return 1;
157  case NC_USHORT:
158  case NC_SHORT:
159  return 2;
160  case NC_FLOAT:
161  case NC_INT:
162  case NC_UINT:
163  return 4;
164  case NC_DOUBLE:
165  case NC_INT64:
166  case NC_UINT64:
167  return 8;
168  }
169  return -1;
170 }
171 
172 /* Given a filename, check to see if it is a HDF5 file. */
173 #define MAGIC_NUMBER_LEN 4
174 #define NC_HDF5_FILE 1
175 #define NC_HDF4_FILE 2
176 static int
177 nc_check_for_hdf(const char *path, int use_parallel, MPI_Comm comm, MPI_Info info,
178  int *hdf_file)
179 {
180  char blob[MAGIC_NUMBER_LEN];
181 
182  assert(hdf_file && path);
183  LOG((3, "%s: path %s", __func__, path));
184 
185  /* HDF5 function handles possible user block at beginning of file */
186  if(H5Fis_hdf5(path))
187  {
188  *hdf_file = NC_HDF5_FILE;
189  } else {
190 
191 /* Get the 4-byte blob from the beginning of the file. Don't use posix
192  * for parallel, use the MPI functions instead. */
193 #ifdef USE_PARALLEL
194  if (use_parallel)
195  {
196  MPI_File fh;
197  MPI_Status status;
198  int retval;
199  if ((retval = MPI_File_open(comm, (char *)path, MPI_MODE_RDONLY,
200  info, &fh)) != MPI_SUCCESS)
201  return NC_EPARINIT;
202  if ((retval = MPI_File_read(fh, blob, MAGIC_NUMBER_LEN, MPI_CHAR,
203  &status)) != MPI_SUCCESS)
204  return NC_EPARINIT;
205  if ((retval = MPI_File_close(&fh)) != MPI_SUCCESS)
206  return NC_EPARINIT;
207  }
208  else
209 #endif /* USE_PARALLEL */
210  {
211  FILE *fp;
212  if (!(fp = fopen(path, "r")) ||
213  fread(blob, MAGIC_NUMBER_LEN, 1, fp) != 1) {
214 
215  if(fp) fclose(fp);
216  return errno;
217  }
218  fclose(fp);
219  }
220 
221  /* Check for HDF4. */
222  if (!strncmp(blob, "\016\003\023\001", MAGIC_NUMBER_LEN))
223  *hdf_file = NC_HDF4_FILE;
224  else
225  *hdf_file = 0;
226  }
227  return NC_NOERR;
228 }
229 
230 /* Create a HDF5/netcdf-4 file. */
231 
232 static int
233 nc4_create_file(const char *path, int cmode, MPI_Comm comm, MPI_Info info,
234  NC *nc)
235 {
236  hid_t fcpl_id, fapl_id = -1;
237  unsigned flags;
238  FILE *fp;
239  int retval = NC_NOERR;
240  NC_HDF5_FILE_INFO_T* nc4_info = NULL;
241 #ifdef USE_PARALLEL
242  int comm_duped = 0; /* Whether the MPI Communicator was duplicated */
243  int info_duped = 0; /* Whether the MPI Info object was duplicated */
244 #else /* !USE_PARALLEL */
245  int persist = 0; /* Should diskless try to persist its data into file?*/
246 #endif
247 
248  assert(nc);
249 
250  if(cmode & NC_DISKLESS)
251  flags = H5F_ACC_TRUNC;
252  else if(cmode & NC_NOCLOBBER)
253  flags = H5F_ACC_EXCL;
254  else
255  flags = H5F_ACC_TRUNC;
256 
257  LOG((3, "%s: path %s mode 0x%x", __func__, path, cmode));
258  assert(nc && path);
259 
260  /* If this file already exists, and NC_NOCLOBBER is specified,
261  return an error. */
262  if (cmode & NC_DISKLESS) {
263 #ifndef USE_PARALLEL
264  if(cmode & NC_WRITE)
265  persist = 1;
266 #endif
267  } else if ((cmode & NC_NOCLOBBER) && (fp = fopen(path, "r"))) {
268  fclose(fp);
269  return NC_EEXIST;
270  }
271 
272  /* Add necessary structs to hold netcdf-4 file data. */
273  if ((retval = nc4_nc4f_list_add(nc, path, (NC_WRITE | cmode))))
274  BAIL(retval);
275  nc4_info = NC4_DATA(nc);
276  assert(nc4_info && nc4_info->root_grp);
277 
278 #if 0 /*def USE_PNETCDF*/
279  if (cmode & NC_PNETCDF)
280  return NC_NOERR;
281 #endif
282 
283  /* Need this access plist to control how HDF5 handles open onjects
284  * on file close. (Setting H5F_CLOSE_SEMI will cause H5Fclose to
285  * fail if there are any open objects in the file. */
286  if ((fapl_id = H5Pcreate(H5P_FILE_ACCESS)) < 0)
287  BAIL(NC_EHDFERR);
288 #ifdef EXTRA_TESTS
289  num_plists++;
290 #endif
291 #ifdef EXTRA_TESTS
292  if (H5Pset_fclose_degree(fapl_id, H5F_CLOSE_SEMI))
293  BAIL(NC_EHDFERR);
294 #else
295  if (H5Pset_fclose_degree(fapl_id, H5F_CLOSE_STRONG))
296  BAIL(NC_EHDFERR);
297 #endif /* EXTRA_TESTS */
298 
299 #ifdef USE_PARALLEL
300  /* If this is a parallel file create, set up the file creation
301  property list. */
302  if ((cmode & NC_MPIIO) || (cmode & NC_MPIPOSIX))
303  {
304  nc4_info->parallel = NC_TRUE;
305  if (cmode & NC_MPIIO) /* MPI/IO */
306  {
307  LOG((4, "creating parallel file with MPI/IO"));
308  if (H5Pset_fapl_mpio(fapl_id, comm, info) < 0)
309  BAIL(NC_EPARINIT);
310  }
311  else /* MPI/POSIX */
312  {
313  LOG((4, "creating parallel file with MPI/posix"));
314  if (H5Pset_fapl_mpiposix(fapl_id, comm, 0) < 0)
315  BAIL(NC_EPARINIT);
316  }
317 
318  /* Keep copies of the MPI Comm & Info objects */
319  if (MPI_SUCCESS != MPI_Comm_dup(comm, &nc4_info->comm))
320  BAIL(NC_EMPI);
321  comm_duped++;
322  if (MPI_INFO_NULL != info)
323  {
324  if (MPI_SUCCESS != MPI_Info_dup(info, &nc4_info->info))
325  BAIL(NC_EMPI);
326  info_duped++;
327  }
328  else
329  {
330  /* No dup, just copy it. */
331  nc4_info->info = info;
332  }
333  }
334 #else /* only set cache for non-parallel... */
335  if(cmode & NC_DISKLESS) {
336  if (H5Pset_fapl_core(fapl_id, 4096, persist))
337  BAIL(NC_EDISKLESS);
338  }
339  if (H5Pset_cache(fapl_id, 0, nc4_chunk_cache_nelems, nc4_chunk_cache_size,
340  nc4_chunk_cache_preemption) < 0)
341  BAIL(NC_EHDFERR);
342  LOG((4, "%s: set HDF raw chunk cache to size %d nelems %d preemption %f",
343  __func__, nc4_chunk_cache_size, nc4_chunk_cache_nelems, nc4_chunk_cache_preemption));
344 #endif /* USE_PARALLEL */
345 
346  if (H5Pset_libver_bounds(fapl_id, H5F_LIBVER_LATEST, H5F_LIBVER_LATEST) < 0)
347  BAIL(NC_EHDFERR);
348 
349  /* Create the property list. */
350  if ((fcpl_id = H5Pcreate(H5P_FILE_CREATE)) < 0)
351  BAIL(NC_EHDFERR);
352 #ifdef EXTRA_TESTS
353  num_plists++;
354 #endif
355 
356  /* RJ: this suppose to be FALSE that is defined in H5 private.h as 0 */
357  if (H5Pset_obj_track_times(fcpl_id,0)<0)
358  BAIL(NC_EHDFERR);
359 
360  /* Set latest_format in access propertly list and
361  * H5P_CRT_ORDER_TRACKED in the creation property list. This turns
362  * on HDF5 creation ordering. */
363  if (H5Pset_link_creation_order(fcpl_id, (H5P_CRT_ORDER_TRACKED |
364  H5P_CRT_ORDER_INDEXED)) < 0)
365  BAIL(NC_EHDFERR);
366  if (H5Pset_attr_creation_order(fcpl_id, (H5P_CRT_ORDER_TRACKED |
367  H5P_CRT_ORDER_INDEXED)) < 0)
368  BAIL(NC_EHDFERR);
369 
370  /* Create the file. */
371  if ((nc4_info->hdfid = H5Fcreate(path, flags, fcpl_id, fapl_id)) < 0)
372  /*Change the return error from NC_EFILEMETADATA to
373  System error EACCES because that is the more likely problem */
374  BAIL(EACCES);
375 
376  /* Open the root group. */
377  if ((nc4_info->root_grp->hdf_grpid = H5Gopen2(nc4_info->hdfid, "/",
378  H5P_DEFAULT)) < 0)
379  BAIL(NC_EFILEMETA);
380 
381  /* Release the property lists. */
382  if (H5Pclose(fapl_id) < 0 ||
383  H5Pclose(fcpl_id) < 0)
384  BAIL(NC_EHDFERR);
385 #ifdef EXTRA_TESTS
386  num_plists--;
387  num_plists--;
388 #endif
389 
390  /* Define mode gets turned on automatically on create. */
391  nc4_info->flags |= NC_INDEF;
392 
393  return NC_NOERR;
394 
395 exit: /*failure exit*/
396 #ifdef USE_PARALLEL
397  if (comm_duped) MPI_Comm_free(&nc4_info->comm);
398  if (info_duped) MPI_Info_free(&nc4_info->info);
399 #endif
400 #ifdef EXTRA_TESTS
401  num_plists--;
402 #endif
403  if (fapl_id != H5P_DEFAULT) H5Pclose(fapl_id);
404  if(!nc4_info) return retval;
405  close_netcdf4_file(nc4_info,1); /* treat like abort */
406  return retval;
407 }
408 
424 int
425 NC4_create(const char* path, int cmode, size_t initialsz, int basepe,
426  size_t *chunksizehintp, int use_parallel, void *mpidata,
427  NC_Dispatch *dispatch, NC* nc_file)
428 {
429  MPI_Comm comm = MPI_COMM_WORLD;
430  MPI_Info info = MPI_INFO_NULL;
431  int res;
432 
433  assert(nc_file && path);
434 
435  LOG((1, "%s: path %s cmode 0x%x comm %d info %d",
436  __func__, path, cmode, comm, info));
437 
438 #ifdef USE_PARALLEL
439  if (mpidata)
440  {
441  comm = ((NC_MPI_INFO *)mpidata)->comm;
442  info = ((NC_MPI_INFO *)mpidata)->info;
443  }
444 #endif /* USE_PARALLEL */
445 
446  /* If this is our first file, turn off HDF5 error messages. */
447  if (virgin)
448  {
449  if (H5Eset_auto(NULL, NULL) < 0)
450  LOG((0, "Couldn't turn off HDF5 error messages!"));
451  LOG((1, "HDF5 error messages have been turned off."));
452  virgin = 0;
453  }
454 
455  /* Check the cmode for validity. */
456  if (cmode & ~(NC_NOCLOBBER | NC_64BIT_OFFSET
458  | NC_SHARE | NC_MPIIO | NC_MPIPOSIX | NC_LOCK | NC_PNETCDF
459  | NC_DISKLESS
460  | NC_WRITE /* to support diskless persistence */
461  )
462  || (cmode & NC_MPIIO && cmode & NC_MPIPOSIX)
463  || (cmode & NC_64BIT_OFFSET && cmode & NC_NETCDF4)
464  || (cmode & (NC_MPIIO | NC_MPIPOSIX) && cmode & NC_DISKLESS)
465  )
466  return NC_EINVAL;
467 
468  cmode |= NC_NETCDF4;
469 
470  /* Apply default create format. */
471  if (nc_get_default_format() == NC_FORMAT_64BIT)
472  cmode |= NC_64BIT_OFFSET;
473  else if (nc_get_default_format() == NC_FORMAT_NETCDF4_CLASSIC)
474  cmode |= NC_CLASSIC_MODEL;
475 
476  LOG((2, "cmode after applying default format: 0x%x", cmode));
477 
478  nc_file->int_ncid = nc_file->ext_ncid;
479  res = nc4_create_file(path, cmode, comm, info, nc_file);
480 
481 #if 0 /*def USE_PNETCDF*/
482  if (cmode & NC_PNETCDF)
483  {
484  NC_HDF5_FILE_INFO_T* nc4_info;
485  nc4_info = NC4_DATA(nc_file);
486  assert(nc4_info);
487 
488  nc4_info->pnetcdf_file++;
489  res = ncmpi_create(comm, path, cmode, info, &(nc_file->int_ncid));
490  }
491 #endif /* USE_PNETCDF */
492 
493  return res;
494 }
495 
496 /* This function is called by read_dataset when a dimension scale
497  * dataset is encountered. It reads in the dimension data (creating a
498  * new NC_DIM_INFO_T object), and also checks to see if this is a
499  * dimension without a variable - that is, a coordinate dimension
500  * which does not have any coordinate data. */
501 static int
502 read_scale(NC_GRP_INFO_T *grp, hid_t datasetid, const char *obj_name,
503  const H5G_stat_t *statbuf, hsize_t scale_size, hsize_t max_scale_size,
504  NC_DIM_INFO_T **dim)
505 {
506  NC_DIM_INFO_T *new_dim; /* Dimension added to group */
507  char dimscale_name_att[NC_MAX_NAME + 1] = ""; /* Dimscale name, for checking if dim without var */
508  htri_t attr_exists = -1; /* Flag indicating hidden attribute exists */
509  hid_t attid = -1; /* ID of hidden attribute (to store dim ID) */
510  int dimscale_created = 0; /* Remember if a dimension was created (for error recovery) */
511  int initial_grp_ndims = grp->ndims; /* Retain for error recovery */
512  short initial_next_dimid = grp->nc4_info->next_dimid;/* Retain for error recovery */
513  int retval;
514 
515  /* Add a dimension for this scale. */
516  if ((retval = nc4_dim_list_add(&grp->dim, &new_dim)))
517  BAIL(retval);
518  dimscale_created++;
519 
520  /* Does this dataset have a hidden attribute that tells us its
521  * dimid? If so, read it. */
522  if ((attr_exists = H5Aexists(datasetid, NC_DIMID_ATT_NAME)) < 0)
523  BAIL(NC_EHDFERR);
524  if (attr_exists)
525  {
526  if ((attid = H5Aopen_by_name(datasetid, ".", NC_DIMID_ATT_NAME,
527  H5P_DEFAULT, H5P_DEFAULT)) < 0)
528  BAIL(NC_EHDFERR);
529 
530  if (H5Aread(attid, H5T_NATIVE_INT, &new_dim->dimid) < 0)
531  BAIL(NC_EHDFERR);
532 
533  /* Check if scale's dimid should impact the group's next dimid */
534  if (new_dim->dimid >= grp->nc4_info->next_dimid)
535  grp->nc4_info->next_dimid = new_dim->dimid + 1;
536  }
537  else
538  {
539  /* Assign dimid */
540  new_dim->dimid = grp->nc4_info->next_dimid++;
541  }
542 
543  /* Increment number of dimensions. */
544  grp->ndims++;
545 
546  if (!(new_dim->name = strdup(obj_name)))
547  BAIL(NC_ENOMEM);
548  if (SIZEOF_SIZE_T < 8 && scale_size > NC_MAX_UINT)
549  {
550  new_dim->len = NC_MAX_UINT;
551  new_dim->too_long = NC_TRUE;
552  }
553  else
554  new_dim->len = scale_size;
555  new_dim->hdf5_objid.fileno[0] = statbuf->fileno[0];
556  new_dim->hdf5_objid.fileno[1] = statbuf->fileno[1];
557  new_dim->hdf5_objid.objno[0] = statbuf->objno[0];
558  new_dim->hdf5_objid.objno[1] = statbuf->objno[1];
559 
560  /* If the dimscale has an unlimited dimension, then this dimension
561  * is unlimited. */
562  if (max_scale_size == H5S_UNLIMITED)
563  new_dim->unlimited = NC_TRUE;
564 
565  /* If the scale name is set to DIM_WITHOUT_VARIABLE, then this is a
566  * dimension, but not a variable. (If get_scale_name returns an
567  * error, just move on, there's no NAME.) */
568  if (H5DSget_scale_name(datasetid, dimscale_name_att, NC_MAX_NAME) >= 0)
569  {
570  if (!strncmp(dimscale_name_att, DIM_WITHOUT_VARIABLE,
571  strlen(DIM_WITHOUT_VARIABLE)))
572  {
573  if (new_dim->unlimited)
574  {
575  size_t len = 0, *lenp = &len;
576 
577  if ((retval = nc4_find_dim_len(grp, new_dim->dimid, &lenp)))
578  BAIL(retval);
579  new_dim->len = *lenp;
580  }
581 
582  /* Hold open the dataset, since the dimension doesn't have a coordinate variable */
583  new_dim->hdf_dimscaleid = datasetid;
584  H5Iinc_ref(new_dim->hdf_dimscaleid); /* Increment number of objects using ID */
585  }
586  }
587 
588  /* Set the dimension created */
589  *dim = new_dim;
590 
591 exit:
592  /* Close the hidden attribute, if it was opened (error, or no error) */
593  if (attid > 0 && H5Aclose(attid) < 0)
594  BAIL2(NC_EHDFERR);
595 
596  /* On error, undo any dimscale creation */
597  if (retval < 0 && dimscale_created)
598  {
599  /* Delete the dimension */
600  if ((retval = nc4_dim_list_del(&grp->dim, new_dim)))
601  BAIL2(retval);
602 
603  /* Reset the group's information */
604  grp->ndims = initial_grp_ndims;
605  grp->nc4_info->next_dimid = initial_next_dimid;
606  }
607 
608  return retval;
609 }
610 
611 /* This function reads the hacked in coordinates attribute I use for
612  * multi-dimensional coordinates. */
613 static int
614 read_coord_dimids(NC_VAR_INFO_T *var)
615 {
616  hid_t coord_att_typeid = -1, coord_attid = -1, spaceid = -1;
617  hssize_t npoints;
618  int ret = 0;
619 
620  /* There is a hidden attribute telling us the ids of the
621  * dimensions that apply to this multi-dimensional coordinate
622  * variable. Read it. */
623  if ((coord_attid = H5Aopen_name(var->hdf_datasetid, COORDINATES)) < 0) ret++;
624  if (!ret && (coord_att_typeid = H5Aget_type(coord_attid)) < 0) ret++;
625 
626  /* How many dimensions are there? */
627  if (!ret && (spaceid = H5Aget_space(coord_attid)) < 0) ret++;
628 #ifdef EXTRA_TESTS
629  num_spaces++;
630 #endif
631  if (!ret && (npoints = H5Sget_simple_extent_npoints(spaceid)) < 0) ret++;
632 
633  /* Check that the number of points is the same as the number of dimensions
634  * for the variable */
635  if (!ret && npoints != var->ndims) ret++;
636 
637  if (!ret && H5Aread(coord_attid, coord_att_typeid, var->dimids) < 0) ret++;
638  LOG((4, "dimscale %s is multidimensional and has coords", var->name));
639 
640  /* Set my HDF5 IDs free! */
641  if (spaceid >= 0 && H5Sclose(spaceid) < 0) ret++;
642 #ifdef EXTRA_TESTS
643  num_spaces--;
644 #endif
645  if (coord_att_typeid >= 0 && H5Tclose(coord_att_typeid) < 0) ret++;
646  if (coord_attid >= 0 && H5Aclose(coord_attid) < 0) ret++;
647  return ret ? NC_EATTMETA : NC_NOERR;
648 }
649 
650 /* This function is called when reading a file's metadata for each
651  * dimension scale attached to a variable.*/
652 static herr_t
653 dimscale_visitor(hid_t did, unsigned dim, hid_t dsid,
654  void *dimscale_hdf5_objids)
655 {
656  H5G_stat_t statbuf;
657 
658  /* Get more info on the dimscale object.*/
659  if (H5Gget_objinfo(dsid, ".", 1, &statbuf) < 0)
660  return -1;
661 
662  /* Pass this information back to caller. */
663  (*(HDF5_OBJID_T *)dimscale_hdf5_objids).fileno[0] = statbuf.fileno[0];
664  (*(HDF5_OBJID_T *)dimscale_hdf5_objids).fileno[1] = statbuf.fileno[1];
665  (*(HDF5_OBJID_T *)dimscale_hdf5_objids).objno[0] = statbuf.objno[0];
666  (*(HDF5_OBJID_T *)dimscale_hdf5_objids).objno[1] = statbuf.objno[1];
667  return 0;
668 }
669 
670 /* Given an HDF5 type, set a pointer to netcdf type. */
671 static int
672 get_netcdf_type(NC_HDF5_FILE_INFO_T *h5, hid_t native_typeid,
673  nc_type *xtype)
674 {
675  NC_TYPE_INFO_T *type;
676  H5T_class_t class;
677  htri_t is_str, equal = 0;
678 
679  assert(h5 && xtype);
680 
681  if ((class = H5Tget_class(native_typeid)) < 0)
682  return NC_EHDFERR;
683 
684  /* H5Tequal doesn't work with H5T_C_S1 for some reason. But
685  * H5Tget_class will return H5T_STRING if this is a string. */
686  if (class == H5T_STRING)
687  {
688  if ((is_str = H5Tis_variable_str(native_typeid)) < 0)
689  return NC_EHDFERR;
690  if (is_str)
691  *xtype = NC_STRING;
692  else
693  *xtype = NC_CHAR;
694  return NC_NOERR;
695  }
696  else if (class == H5T_INTEGER || class == H5T_FLOAT)
697  {
698  /* For integers and floats, we don't have to worry about
699  * endianness if we compare native types. */
700  if ((equal = H5Tequal(native_typeid, H5T_NATIVE_SCHAR)) < 0)
701  return NC_EHDFERR;
702  if (equal)
703  {
704  *xtype = NC_BYTE;
705  return NC_NOERR;
706  }
707  if ((equal = H5Tequal(native_typeid, H5T_NATIVE_SHORT)) < 0)
708  return NC_EHDFERR;
709  if (equal)
710  {
711  *xtype = NC_SHORT;
712  return NC_NOERR;
713  }
714  if ((equal = H5Tequal(native_typeid, H5T_NATIVE_INT)) < 0)
715  return NC_EHDFERR;
716  if (equal)
717  {
718  *xtype = NC_INT;
719  return NC_NOERR;
720  }
721  if ((equal = H5Tequal(native_typeid, H5T_NATIVE_FLOAT)) < 0)
722  return NC_EHDFERR;
723  if (equal)
724  {
725  *xtype = NC_FLOAT;
726  return NC_NOERR;
727  }
728  if ((equal = H5Tequal(native_typeid, H5T_NATIVE_DOUBLE)) < 0)
729  return NC_EHDFERR;
730  if (equal)
731  {
732  *xtype = NC_DOUBLE;
733  return NC_NOERR;
734  }
735  if ((equal = H5Tequal(native_typeid, H5T_NATIVE_UCHAR)) < 0)
736  return NC_EHDFERR;
737  if (equal)
738  {
739  *xtype = NC_UBYTE;
740  return NC_NOERR;
741  }
742  if ((equal = H5Tequal(native_typeid, H5T_NATIVE_USHORT)) < 0)
743  return NC_EHDFERR;
744  if (equal)
745  {
746  *xtype = NC_USHORT;
747  return NC_NOERR;
748  }
749  if ((equal = H5Tequal(native_typeid, H5T_NATIVE_UINT)) < 0)
750  return NC_EHDFERR;
751  if (equal)
752  {
753  *xtype = NC_UINT;
754  return NC_NOERR;
755  }
756  if ((equal = H5Tequal(native_typeid, H5T_NATIVE_LLONG)) < 0)
757  return NC_EHDFERR;
758  if (equal)
759  {
760  *xtype = NC_INT64;
761  return NC_NOERR;
762  }
763  if ((equal = H5Tequal(native_typeid, H5T_NATIVE_ULLONG)) < 0)
764  return NC_EHDFERR;
765  if (equal)
766  {
767  *xtype = NC_UINT64;
768  return NC_NOERR;
769  }
770  }
771 
772  /* Maybe we already know about this type. */
773  if (!equal)
774  if((type = nc4_rec_find_hdf_type(h5->root_grp, native_typeid)))
775  {
776  *xtype = type->nc_typeid;
777  return NC_NOERR;
778  }
779 
780  *xtype = NC_NAT;
781  return NC_EBADTYPID;
782 }
783 
784 /* Given an HDF5 type, set a pointer to netcdf type_info struct,
785  * either an existing one (for user-defined types) or a newly created
786  * one. */
787 static int
788 get_type_info2(NC_HDF5_FILE_INFO_T *h5, hid_t datasetid,
789  NC_TYPE_INFO_T **type_info)
790 {
791  htri_t is_str, equal = 0;
792  H5T_class_t class;
793  hid_t native_typeid, hdf_typeid;
794  H5T_order_t order;
795  int t;
796 
797  assert(h5 && type_info);
798 
799  /* Because these N5T_NATIVE_* constants are actually function calls
800  * (!) in H5Tpublic.h, I can't initialize this array in the usual
801  * way, because at least some C compilers (like Irix) complain
802  * about calling functions when defining constants. So I have to do
803  * it like this. Note that there's no native types for char or
804  * string. Those are handled later. */
805  if (!h5_native_type_constant_g[1])
806  {
807  h5_native_type_constant_g[1] = H5T_NATIVE_SCHAR;
808  h5_native_type_constant_g[2] = H5T_NATIVE_SHORT;
809  h5_native_type_constant_g[3] = H5T_NATIVE_INT;
810  h5_native_type_constant_g[4] = H5T_NATIVE_FLOAT;
811  h5_native_type_constant_g[5] = H5T_NATIVE_DOUBLE;
812  h5_native_type_constant_g[6] = H5T_NATIVE_UCHAR;
813  h5_native_type_constant_g[7] = H5T_NATIVE_USHORT;
814  h5_native_type_constant_g[8] = H5T_NATIVE_UINT;
815  h5_native_type_constant_g[9] = H5T_NATIVE_LLONG;
816  h5_native_type_constant_g[10] = H5T_NATIVE_ULLONG;
817  }
818 
819  /* Get the HDF5 typeid - we'll need it later. */
820  if ((hdf_typeid = H5Dget_type(datasetid)) < 0)
821  return NC_EHDFERR;
822 
823  /* Get the native typeid. Will be equivalent to hdf_typeid when
824  * creating but not necessarily when reading, a variable. */
825  if ((native_typeid = H5Tget_native_type(hdf_typeid, H5T_DIR_DEFAULT)) < 0)
826  return NC_EHDFERR;
827 
828  /* Is this type an integer, string, compound, or what? */
829  if ((class = H5Tget_class(native_typeid)) < 0)
830  return NC_EHDFERR;
831 
832  /* Is this an atomic type? */
833  if (class == H5T_STRING || class == H5T_INTEGER || class == H5T_FLOAT)
834  {
835  /* Allocate a phony NC_TYPE_INFO_T struct to hold type info. */
836  if (!(*type_info = calloc(1, sizeof(NC_TYPE_INFO_T))))
837  return NC_ENOMEM;
838 
839  /* H5Tequal doesn't work with H5T_C_S1 for some reason. But
840  * H5Tget_class will return H5T_STRING if this is a string. */
841  if (class == H5T_STRING)
842  {
843  if ((is_str = H5Tis_variable_str(native_typeid)) < 0)
844  return NC_EHDFERR;
845  /* Make sure fixed-len strings will work like variable-len strings */
846  if (is_str || H5Tget_size(hdf_typeid) > 1)
847  {
848  /* Set a class for the type */
849  t = NUM_TYPES - 1;
850  (*type_info)->nc_type_class = NC_STRING;
851  }
852  else
853  {
854  /* Set a class for the type */
855  t = 0;
856  (*type_info)->nc_type_class = NC_CHAR;
857  }
858  }
859  else if (class == H5T_INTEGER || class == H5T_FLOAT)
860  {
861  for (t = 1; t < NUM_TYPES - 1; t++)
862  {
863  if ((equal = H5Tequal(native_typeid, h5_native_type_constant_g[t])) < 0)
864  return NC_EHDFERR;
865  if (equal)
866  break;
867  }
868 
869  /* Find out about endianness. */
870  if (class == H5T_INTEGER)
871  {
872  if ((order = H5Tget_order(hdf_typeid)) < 0)
873  return NC_EHDFERR;
874 
875  /* Copy this into the type_info struct. */
876  if (order == H5T_ORDER_LE)
877  (*type_info)->endianness = NC_ENDIAN_LITTLE;
878  else if (order == H5T_ORDER_BE)
879  (*type_info)->endianness = NC_ENDIAN_BIG;
880  else /* don't support H5T_ORDER_VAX, H5T_ORDER_MIXED, H5T_ORDER_NONE */
881  return NC_EBADTYPE;
882 
883  /* Set a class for the type */
884  /* (Note use of 'NC_INT' for all integer types) */
885  (*type_info)->nc_type_class = NC_INT;
886  }
887  else
888  {
889  /* Set a class for the type */
890  /* (Note use of 'NC_FLOAT' for all floating-point types) */
891  (*type_info)->nc_type_class = NC_FLOAT;
892  }
893  }
894  (*type_info)->nc_typeid = nc_type_constant_g[t];
895  (*type_info)->size = nc_type_size_g[t];
896  if (!((*type_info)->name = strdup(nc_type_name_g[t])))
897  return NC_ENOMEM;
898  (*type_info)->hdf_typeid = hdf_typeid;
899  (*type_info)->native_hdf_typeid = native_typeid;
900  return NC_NOERR;
901  }
902  else
903  {
904  NC_TYPE_INFO_T *type;
905 
906  /* This is a user-defined type. */
907  if((type = nc4_rec_find_hdf_type(h5->root_grp, native_typeid)))
908  *type_info = type;
909 
910  /* The type entry in the array of user-defined types already has
911  * an open data typeid (and native typeid), so close the ones we
912  * opened above. */
913  if (H5Tclose(native_typeid) < 0)
914  return NC_EHDFERR;
915  if (H5Tclose(hdf_typeid) < 0)
916  return NC_EHDFERR;
917 
918  if (type)
919  return NC_NOERR;
920  }
921 
922  return NC_EBADTYPID;
923 }
924 
925 /* Read an attribute. */
926 static int
927 read_hdf5_att(NC_GRP_INFO_T *grp, hid_t attid, NC_ATT_INFO_T *att)
928 {
929  hid_t spaceid = 0, file_typeid = 0;
930  hsize_t dims[1] = {0}; /* netcdf attributes always 1-D. */
931  int retval = NC_NOERR;
932  size_t type_size;
933  int att_ndims;
934  hssize_t att_npoints;
935  H5T_class_t att_class;
936  int fixed_len_string = 0;
937  size_t fixed_size = 0;
938 
939  assert(att->name);
940  LOG((5, "%s: att->attnum %d att->name %s att->nc_typeid %d att->len %d",
941  __func__, att->attnum, att->name, (int)att->nc_typeid, att->len));
942 
943  /* Get type of attribute in file. */
944  if ((file_typeid = H5Aget_type(attid)) < 0)
945  return NC_EATTMETA;
946  if ((att->native_hdf_typeid = H5Tget_native_type(file_typeid, H5T_DIR_DEFAULT)) < 0)
947  BAIL(NC_EHDFERR);
948  if ((att_class = H5Tget_class(att->native_hdf_typeid)) < 0)
949  BAIL(NC_EATTMETA);
950  if (att_class == H5T_STRING && !H5Tis_variable_str(att->native_hdf_typeid))
951  {
952  fixed_len_string++;
953  if (!(fixed_size = H5Tget_size(att->native_hdf_typeid)))
954  BAIL(NC_EATTMETA);
955  }
956  if ((retval = get_netcdf_type(grp->nc4_info, att->native_hdf_typeid, &(att->nc_typeid))))
957  BAIL(retval);
958 
959 
960  /* Get len. */
961  if ((spaceid = H5Aget_space(attid)) < 0)
962  BAIL(NC_EATTMETA);
963 #ifdef EXTRA_TESTS
964  num_spaces++;
965 #endif
966  if ((att_ndims = H5Sget_simple_extent_ndims(spaceid)) < 0)
967  BAIL(NC_EATTMETA);
968  if ((att_npoints = H5Sget_simple_extent_npoints(spaceid)) < 0)
969  BAIL(NC_EATTMETA);
970 
971  /* If both att_ndims and att_npoints are zero, then this is a
972  * zero length att. */
973  if (att_ndims == 0 && att_npoints == 0)
974  dims[0] = 0;
975  else if (att->nc_typeid == NC_STRING)
976  dims[0] = att_npoints;
977  else if (att->nc_typeid == NC_CHAR)
978  {
979  /* NC_CHAR attributes are written as a scalar in HDF5, of type
980  * H5T_C_S1, of variable length. */
981  if (att_ndims == 0)
982  {
983  if (!(dims[0] = H5Tget_size(file_typeid)))
984  BAIL(NC_EATTMETA);
985  }
986  else
987  {
988  /* This is really a string type! */
989  att->nc_typeid = NC_STRING;
990  dims[0] = att_npoints;
991  }
992  }
993  else
994  {
995  H5S_class_t space_class;
996 
997  /* All netcdf attributes are scalar or 1-D only. */
998  if (att_ndims > 1)
999  BAIL(NC_EATTMETA);
1000 
1001  /* Check class of HDF5 dataspace */
1002  if ((space_class = H5Sget_simple_extent_type(spaceid)) < 0)
1003  BAIL(NC_EATTMETA);
1004 
1005  /* Check for NULL HDF5 dataspace class (should be weeded out earlier) */
1006  if (H5S_NULL == space_class)
1007  BAIL(NC_EATTMETA);
1008 
1009  /* check for SCALAR HDF5 dataspace class */
1010  if (H5S_SCALAR == space_class)
1011  dims[0] = 1;
1012  else /* Must be "simple" dataspace */
1013  {
1014  /* Read the size of this attribute. */
1015  if (H5Sget_simple_extent_dims(spaceid, dims, NULL) < 0)
1016  BAIL(NC_EATTMETA);
1017  }
1018  }
1019 
1020  /* Tell the user what the length if this attribute is. */
1021  att->len = dims[0];
1022 
1023  /* Allocate some memory if the len is not zero, and read the
1024  attribute. */
1025  if (dims[0])
1026  {
1027  if ((retval = nc4_get_typelen_mem(grp->nc4_info, att->nc_typeid, 0,
1028  &type_size)))
1029  return retval;
1030  if (att_class == H5T_VLEN)
1031  {
1032  if (!(att->vldata = malloc((unsigned int)(att->len * sizeof(hvl_t)))))
1033  BAIL(NC_ENOMEM);
1034  if (H5Aread(attid, att->native_hdf_typeid, att->vldata) < 0)
1035  BAIL(NC_EATTMETA);
1036  }
1037  else if (att->nc_typeid == NC_STRING)
1038  {
1039  if (!(att->stdata = calloc(att->len, sizeof(char *))))
1040  BAIL(NC_ENOMEM);
1041  /* For a fixed length HDF5 string, the read requires
1042  * contiguous memory. Meanwhile, the netCDF API requires that
1043  * nc_free_string be called on string arrays, which would not
1044  * work if one contiguous memory block were used. So here I
1045  * convert the contiguous block of strings into an array of
1046  * malloced strings (each string with its own malloc). Then I
1047  * copy the data and free the contiguous memory. This
1048  * involves copying the data, which is bad, but this only
1049  * occurs for fixed length string attributes, and presumably
1050  * these are small. (And netCDF-4 does not create them - it
1051  * always uses variable length strings. */
1052  if (fixed_len_string)
1053  {
1054  int i;
1055  char *contig_buf, *cur;
1056 
1057  /* Alloc space for the contiguous memory read. */
1058  if (!(contig_buf = malloc(att->len * fixed_size * sizeof(char))))
1059  BAIL(NC_ENOMEM);
1060 
1061  /* Read the fixed-len strings as one big block. */
1062  if (H5Aread(attid, att->native_hdf_typeid, contig_buf) < 0)
1063  BAIL(NC_EATTMETA);
1064 
1065  /* Copy strings, one at a time, into their new home. Alloc
1066  space for each string. The user will later free this
1067  space with nc_free_string. */
1068  cur = contig_buf;
1069  for (i = 0; i < att->len; i++)
1070  {
1071  if (!(att->stdata[i] = malloc(fixed_size)))
1072  BAIL(NC_ENOMEM);
1073  strncpy(att->stdata[i], cur, fixed_size);
1074  cur += fixed_size;
1075  }
1076 
1077  /* Free contiguous memory buffer. */
1078  free(contig_buf);
1079  }
1080  else
1081  {
1082  /* Read variable-length string atts. */
1083  if (H5Aread(attid, att->native_hdf_typeid, att->stdata) < 0)
1084  BAIL(NC_EATTMETA);
1085  }
1086  }
1087  else
1088  {
1089  if (!(att->data = malloc((unsigned int)(att->len * type_size))))
1090  BAIL(NC_ENOMEM);
1091  if (H5Aread(attid, att->native_hdf_typeid, att->data) < 0)
1092  BAIL(NC_EATTMETA);
1093  }
1094  }
1095 
1096  if (H5Tclose(file_typeid) < 0)
1097  BAIL(NC_EHDFERR);
1098  if (H5Sclose(spaceid) < 0)
1099  return NC_EHDFERR;
1100 #ifdef EXTRA_TESTS
1101  num_spaces--;
1102 #endif
1103 
1104  return NC_NOERR;
1105 
1106  exit:
1107  if (H5Tclose(file_typeid) < 0)
1108  BAIL2(NC_EHDFERR);
1109  if (spaceid > 0 && H5Sclose(spaceid) < 0)
1110  BAIL2(NC_EHDFERR);
1111 #ifdef EXTRA_TESTS
1112  num_spaces--;
1113 #endif
1114  return retval;
1115 }
1116 
1117 /* Read information about a user defined type from the HDF5 file, and
1118  * stash it in the group's list of types. */
1119 static int
1120 read_type(NC_GRP_INFO_T *grp, hid_t hdf_typeid, char *type_name)
1121 {
1122  NC_TYPE_INFO_T *type;
1123  H5T_class_t class;
1124  hid_t native_typeid;
1125  size_t type_size;
1126  int retval = NC_NOERR;
1127 
1128  assert(grp && type_name);
1129 
1130  LOG((4, "%s: type_name %s grp->name %s", __func__, type_name, grp->name));
1131 
1132  /* What is the native type for this platform? */
1133  if ((native_typeid = H5Tget_native_type(hdf_typeid, H5T_DIR_DEFAULT)) < 0)
1134  return NC_EHDFERR;
1135 
1136  /* What is the size of this type on this platform. */
1137  if (!(type_size = H5Tget_size(native_typeid)))
1138  return NC_EHDFERR;
1139  LOG((5, "type_size %d", type_size));
1140 
1141  /* Add to the list for this new type, and get a local pointer to it. */
1142  if ((retval = nc4_type_list_add(grp, type_size, type_name, &type)))
1143  return retval;
1144 
1145  /* Remember common info about this type. */
1146  type->committed = NC_TRUE;
1147  type->hdf_typeid = hdf_typeid;
1148  H5Iinc_ref(type->hdf_typeid); /* Increment number of objects using ID */
1149  type->native_hdf_typeid = native_typeid;
1150 
1151  /* What is the class of this type, compound, vlen, etc. */
1152  if ((class = H5Tget_class(hdf_typeid)) < 0)
1153  return NC_EHDFERR;
1154  switch (class)
1155  {
1156  case H5T_STRING:
1157  type->nc_type_class = NC_STRING;
1158  break;
1159 
1160  case H5T_COMPOUND:
1161  {
1162  int nmembers;
1163  unsigned int m;
1164  char* member_name = NULL;
1165 #ifdef JNA
1166  char jna[1001];
1167 #endif
1168 
1169  type->nc_type_class = NC_COMPOUND;
1170 
1171  if ((nmembers = H5Tget_nmembers(hdf_typeid)) < 0)
1172  return NC_EHDFERR;
1173  LOG((5, "compound type has %d members", nmembers));
1174  for (m = 0; m < nmembers; m++)
1175  {
1176  hid_t member_hdf_typeid;
1177  hid_t member_native_typeid;
1178  size_t member_offset;
1179  H5T_class_t mem_class;
1180  nc_type member_xtype;
1181 
1182  retval = NC_NOERR;
1183 
1184  /* Get the typeid and native typeid of this member of the
1185  * compound type. */
1186  if ((member_hdf_typeid = H5Tget_member_type(type->native_hdf_typeid, m)) < 0)
1187  return NC_EHDFERR;
1188 
1189  if ((member_native_typeid = H5Tget_native_type(member_hdf_typeid, H5T_DIR_DEFAULT)) < 0)
1190  return NC_EHDFERR;
1191 
1192  /* Get the name of the member.*/
1193  member_name = H5Tget_member_name(type->native_hdf_typeid, m);
1194  if (!member_name || strlen(member_name) > NC_MAX_NAME) {
1195  retval = NC_EBADNAME;
1196  break;
1197  }
1198 #ifdef JNA
1199  else {
1200  strncpy(jna,member_name,1000);
1201  member_name = jna;
1202  }
1203 #endif
1204 
1205  /* Offset in bytes on *this* platform. */
1206  member_offset = H5Tget_member_offset(type->native_hdf_typeid, m);
1207 
1208  /* Get dimensional data if this member is an array of something. */
1209  if ((mem_class = H5Tget_class(member_hdf_typeid)) < 0)
1210  return NC_EHDFERR;
1211  if (mem_class == H5T_ARRAY)
1212  {
1213  int ndims, dim_size[NC_MAX_VAR_DIMS];
1214  hsize_t dims[NC_MAX_VAR_DIMS];
1215  int d;
1216 
1217  if ((ndims = H5Tget_array_ndims(member_hdf_typeid)) < 0) {
1218  retval = NC_EHDFERR;
1219  break;
1220  }
1221  if (H5Tget_array_dims(member_hdf_typeid, dims, NULL) != ndims) {
1222  retval = NC_EHDFERR;
1223  break;
1224  }
1225  for (d = 0; d < ndims; d++)
1226  dim_size[d] = dims[d];
1227 
1228  /* What is the netCDF typeid of this member? */
1229  if ((retval = get_netcdf_type(grp->nc4_info, H5Tget_super(member_hdf_typeid),
1230  &member_xtype)))
1231  break;
1232 
1233  /* Add this member to our list of fields in this compound type. */
1234  if ((retval = nc4_field_list_add(&type->u.c.field, type->u.c.num_fields++, member_name,
1235  member_offset, H5Tget_super(member_hdf_typeid),
1236  H5Tget_super(member_native_typeid),
1237  member_xtype, ndims, dim_size)))
1238  break;
1239  }
1240  else
1241  {
1242  /* What is the netCDF typeid of this member? */
1243  if ((retval = get_netcdf_type(grp->nc4_info, member_native_typeid,
1244  &member_xtype)))
1245  break;
1246 
1247  /* Add this member to our list of fields in this compound type. */
1248  if ((retval = nc4_field_list_add(&type->u.c.field, type->u.c.num_fields++, member_name,
1249  member_offset, member_hdf_typeid, member_native_typeid,
1250  member_xtype, 0, NULL)))
1251  break;
1252  }
1253 
1254 #ifndef JNA
1255  /* Free the member name (which HDF5 allocated for us). */
1256  if(member_name != NULL) free(member_name);
1257 #endif
1258  member_name = NULL;
1259  }
1260 #ifndef JNA
1261  if(member_name != NULL)
1262  free(member_name);
1263 #endif
1264  if(retval) /* error exit from loop */
1265  return retval;
1266  }
1267  break;
1268 
1269  case H5T_VLEN:
1270  {
1271  htri_t ret;
1272 
1273  /* For conveninence we allow user to pass vlens of strings
1274  * with null terminated strings. This means strings are
1275  * treated slightly differently by the API, although they are
1276  * really just VLENs of characters. */
1277  if ((ret = H5Tis_variable_str(hdf_typeid)) < 0)
1278  return NC_EHDFERR;
1279  if (ret)
1280  type->nc_type_class = NC_STRING;
1281  else
1282  {
1283  hid_t base_hdf_typeid;
1284  nc_type base_nc_type = NC_NAT;
1285 
1286  type->nc_type_class = NC_VLEN;
1287 
1288  /* Find the base type of this vlen (i.e. what is this a
1289  * vlen of?) */
1290  if (!(base_hdf_typeid = H5Tget_super(native_typeid)))
1291  return NC_EHDFERR;
1292 
1293  /* What size is this type? */
1294  if (!(type_size = H5Tget_size(base_hdf_typeid)))
1295  return NC_EHDFERR;
1296 
1297  /* What is the netcdf corresponding type. */
1298  if ((retval = get_netcdf_type(grp->nc4_info, base_hdf_typeid,
1299  &base_nc_type)))
1300  return retval;
1301  LOG((5, "base_hdf_typeid 0x%x type_size %d base_nc_type %d",
1302  base_hdf_typeid, type_size, base_nc_type));
1303 
1304  /* Remember the base types for this vlen */
1305  type->u.v.base_nc_typeid = base_nc_type;
1306  type->u.v.base_hdf_typeid = base_hdf_typeid;
1307  }
1308  }
1309  break;
1310 
1311  case H5T_OPAQUE:
1312  type->nc_type_class = NC_OPAQUE;
1313  break;
1314 
1315  case H5T_ENUM:
1316  {
1317  hid_t base_hdf_typeid;
1318  nc_type base_nc_type = NC_NAT;
1319  void *value;
1320  int i;
1321  char *member_name = NULL;
1322 #ifdef JNA
1323  char jna[1001];
1324 #endif
1325 
1326  type->nc_type_class = NC_ENUM;
1327 
1328  /* Find the base type of this enum (i.e. what is this a
1329  * enum of?) */
1330  if (!(base_hdf_typeid = H5Tget_super(hdf_typeid)))
1331  return NC_EHDFERR;
1332  /* What size is this type? */
1333  if (!(type_size = H5Tget_size(base_hdf_typeid)))
1334  return NC_EHDFERR;
1335  /* What is the netcdf corresponding type. */
1336  if ((retval = get_netcdf_type(grp->nc4_info, base_hdf_typeid,
1337  &base_nc_type)))
1338  return retval;
1339  LOG((5, "base_hdf_typeid 0x%x type_size %d base_nc_type %d",
1340  base_hdf_typeid, type_size, base_nc_type));
1341 
1342  /* Remember the base types for this enum */
1343  type->u.e.base_nc_typeid = base_nc_type;
1344  type->u.e.base_hdf_typeid = base_hdf_typeid;
1345 
1346  /* Find out how many member are in the enum. */
1347  if ((type->u.e.num_members = H5Tget_nmembers(hdf_typeid)) < 0)
1348  return NC_EHDFERR;
1349 
1350  /* Allocate space for one value. */
1351  if (!(value = calloc(1, type_size)))
1352  return NC_ENOMEM;
1353 
1354  /* Read each name and value defined in the enum. */
1355  for (i = 0; i < type->u.e.num_members; i++)
1356  {
1357  retval = NC_NOERR;
1358  /* Get the name and value from HDF5. */
1359  if (!(member_name = H5Tget_member_name(hdf_typeid, i)))
1360  {
1361  retval = NC_EHDFERR;
1362  break;
1363  }
1364 #ifdef JNA
1365  strncpy(jna,member_name,1000);
1366  member_name = jna;
1367 #endif
1368 
1369  if (strlen(member_name) > NC_MAX_NAME)
1370  {
1371  retval = NC_EBADNAME;
1372  break;
1373  }
1374  if (H5Tget_member_value(hdf_typeid, i, value) < 0)
1375  {
1376  retval = NC_EHDFERR;
1377  break;
1378  }
1379 
1380  /* Insert new field into this type's list of fields. */
1381  if ((retval = nc4_enum_member_add(&type->u.e.enum_member, type->size,
1382  member_name, value)))
1383  {
1384  break;
1385  }
1386 
1387 #ifndef JNA
1388  /* Free the member name (which HDF5 allocated for us). */
1389  if(member_name != NULL) free(member_name);
1390 #endif
1391  member_name = NULL;
1392  }
1393 
1394 #ifndef JNA
1395  if(member_name != NULL)
1396  free(member_name);
1397 #endif
1398  if(value) free(value);
1399  if(retval) /* error exit from loop */
1400  return retval;
1401  }
1402  break;
1403 
1404  default:
1405  LOG((0, "unknown class"));
1406  return NC_EBADCLASS;
1407  }
1408  return retval;
1409 }
1410 
1411 /* This function is called by read_dataset, (which is called by
1412  * nc4_rec_read_metadata) when a netCDF variable is found in the
1413  * file. This function reads in all the metadata about the var,
1414  * including the attributes. */
1415 static int
1416 read_var(NC_GRP_INFO_T *grp, hid_t datasetid, const char *obj_name,
1417  size_t ndims, NC_DIM_INFO_T *dim)
1418 {
1419  NC_VAR_INFO_T *var = NULL;
1420  hid_t access_pid = 0;
1421  int incr_id_rc = 0; /* Whether the dataset ID's ref count has been incremented */
1422  int natts, a, d;
1423 
1424  NC_ATT_INFO_T *att;
1425  hid_t attid = 0;
1426  char att_name[NC_MAX_HDF5_NAME + 1];
1427 
1428 #define CD_NELEMS_ZLIB 1
1429 #define CD_NELEMS_SZIP 4
1430  H5Z_filter_t filter;
1431  int num_filters;
1432  unsigned int cd_values[CD_NELEMS_SZIP];
1433  size_t cd_nelems = CD_NELEMS_SZIP;
1434  hid_t propid = 0;
1435  H5D_fill_value_t fill_status;
1436  H5D_layout_t layout;
1437  hsize_t chunksize[NC_MAX_VAR_DIMS] = {0};
1438  int retval = NC_NOERR;
1439  double rdcc_w0;
1440  int f;
1441 
1442  assert(obj_name && grp);
1443  LOG((4, "%s: obj_name %s", __func__, obj_name));
1444 
1445  /* Add a variable to the end of the group's var list. */
1446  if ((retval = nc4_var_list_add(&grp->var, &var)))
1447  BAIL(retval);
1448 
1449  /* Fill in what we already know. */
1450  var->hdf_datasetid = datasetid;
1451  H5Iinc_ref(var->hdf_datasetid); /* Increment number of objects using ID */
1452  incr_id_rc++; /* Indicate that we've incremented the ref. count (for errors) */
1453  var->varid = grp->nvars++;
1454  var->created = NC_TRUE;
1455  var->ndims = ndims;
1456 
1457  /* We need some room to store information about dimensions for this
1458  * var. */
1459  if (var->ndims)
1460  {
1461  if (!(var->dim = calloc(var->ndims, sizeof(NC_DIM_INFO_T *))))
1462  BAIL(NC_ENOMEM);
1463  if (!(var->dimids = calloc(var->ndims, sizeof(int))))
1464  BAIL(NC_ENOMEM);
1465  }
1466 
1467  /* Get the current chunk cache settings. */
1468  if ((access_pid = H5Dget_access_plist(datasetid)) < 0)
1469  BAIL(NC_EVARMETA);
1470 #ifdef EXTRA_TESTS
1471  num_plists++;
1472 #endif
1473 
1474  /* Learn about current chunk cache settings. */
1475  if ((H5Pget_chunk_cache(access_pid, &(var->chunk_cache_nelems),
1476  &(var->chunk_cache_size), &rdcc_w0)) < 0)
1477  BAIL(NC_EHDFERR);
1478  var->chunk_cache_preemption = rdcc_w0;
1479 
1480  /* Check for a weird case: a non-coordinate variable that has the
1481  * same name as a dimension. It's legal in netcdf, and requires
1482  * that the HDF5 dataset name be changed. */
1483  if (strlen(obj_name) > strlen(NON_COORD_PREPEND) &&
1484  !strncmp(obj_name, NON_COORD_PREPEND, strlen(NON_COORD_PREPEND)))
1485  {
1486  /* Allocate space for the name. */
1487  if (!(var->name = malloc(((strlen(obj_name) - strlen(NON_COORD_PREPEND))+ 1) * sizeof(char))))
1488  BAIL(NC_ENOMEM);
1489 
1490  strcpy(var->name, &obj_name[strlen(NON_COORD_PREPEND)]);
1491 
1492  /* Allocate space for the HDF5 name. */
1493  if (!(var->hdf5_name = malloc((strlen(obj_name) + 1) * sizeof(char))))
1494  BAIL(NC_ENOMEM);
1495 
1496  strcpy(var->hdf5_name, obj_name);
1497  }
1498  else
1499  {
1500  /* Allocate space for the name. */
1501  if (!(var->name = malloc((strlen(obj_name) + 1) * sizeof(char))))
1502  BAIL(NC_ENOMEM);
1503 
1504  strcpy(var->name, obj_name);
1505  }
1506 
1507  /* Find out what filters are applied to this HDF5 dataset,
1508  * fletcher32, deflate, and/or shuffle. All other filters are
1509  * ignored. */
1510  if ((propid = H5Dget_create_plist(datasetid)) < 0)
1511  BAIL(NC_EHDFERR);
1512 #ifdef EXTRA_TESTS
1513  num_plists++;
1514 #endif /* EXTRA_TESTS */
1515 
1516  /* Get the chunking info for non-scalar vars. */
1517  if ((layout = H5Pget_layout(propid)) < -1)
1518  BAIL(NC_EHDFERR);
1519  if (layout == H5D_CHUNKED)
1520  {
1521  if (H5Pget_chunk(propid, NC_MAX_VAR_DIMS, chunksize) < 0)
1522  BAIL(NC_EHDFERR);
1523  if (!(var->chunksizes = malloc(var->ndims * sizeof(size_t))))
1524  BAIL(NC_ENOMEM);
1525  for (d = 0; d < var->ndims; d++)
1526  var->chunksizes[d] = chunksize[d];
1527  }
1528  else if (layout == H5D_CONTIGUOUS || layout == H5D_COMPACT)
1529  var->contiguous = NC_TRUE;
1530 
1531  /* The possible values of filter (which is just an int) can be
1532  * found in H5Zpublic.h. */
1533  if ((num_filters = H5Pget_nfilters(propid)) < 0)
1534  BAIL(NC_EHDFERR);
1535  for (f = 0; f < num_filters; f++)
1536  {
1537  if ((filter = H5Pget_filter2(propid, f, NULL, &cd_nelems,
1538  cd_values, 0, NULL, NULL)) < 0)
1539  BAIL(NC_EHDFERR);
1540  switch (filter)
1541  {
1542  case H5Z_FILTER_SHUFFLE:
1543  var->shuffle = NC_TRUE;
1544  break;
1545 
1546  case H5Z_FILTER_FLETCHER32:
1547  var->fletcher32 = NC_TRUE;
1548  break;
1549 
1550  case H5Z_FILTER_DEFLATE:
1551  var->deflate = NC_TRUE;
1552  if (cd_nelems != CD_NELEMS_ZLIB || cd_values[0] > MAX_DEFLATE_LEVEL)
1553  BAIL(NC_EHDFERR);
1554  var->deflate_level = cd_values[0];
1555  break;
1556 
1557  case H5Z_FILTER_SZIP:
1558  var->szip = NC_TRUE;
1559  if (cd_nelems != CD_NELEMS_SZIP)
1560  BAIL(NC_EHDFERR);
1561  var->options_mask = cd_values[0];
1562  var->pixels_per_block = cd_values[1];
1563  break;
1564 
1565  default:
1566  LOG((1, "Yikes! Unknown filter type found on dataset!"));
1567  break;
1568  }
1569  }
1570 
1571  /* Learn all about the type of this variable. */
1572  if ((retval = get_type_info2(grp->nc4_info, datasetid,
1573  &var->type_info)))
1574  BAIL(retval);
1575 
1576  /* Indicate that the variable has a pointer to the type */
1577  var->type_info->rc++;
1578 
1579  /* Is there a fill value associated with this dataset? */
1580  if (H5Pfill_value_defined(propid, &fill_status) < 0)
1581  BAIL(NC_EHDFERR);
1582 
1583  /* Get the fill value, if there is one defined. */
1584  if (fill_status == H5D_FILL_VALUE_USER_DEFINED)
1585  {
1586  /* Allocate space to hold the fill value. */
1587  if (!var->fill_value)
1588  {
1589  if (var->type_info->nc_type_class == NC_VLEN)
1590  {
1591  if (!(var->fill_value = malloc(sizeof(nc_vlen_t))))
1592  BAIL(NC_ENOMEM);
1593  }
1594  else if (var->type_info->nc_type_class == NC_STRING)
1595  {
1596  if (!(var->fill_value = malloc(sizeof(char *))))
1597  BAIL(NC_ENOMEM);
1598  }
1599  else
1600  {
1601  assert(var->type_info->size);
1602  if (!(var->fill_value = malloc(var->type_info->size)))
1603  BAIL(NC_ENOMEM);
1604  }
1605  }
1606 
1607  /* Get the fill value from the HDF5 property lust. */
1608  if (H5Pget_fill_value(propid, var->type_info->native_hdf_typeid,
1609  var->fill_value) < 0)
1610  BAIL(NC_EHDFERR);
1611  }
1612  else
1613  var->no_fill = NC_TRUE;
1614 
1615  /* If it's a scale, mark it as such. */
1616  if (dim)
1617  {
1618  assert(ndims);
1619  var->dimscale = NC_TRUE;
1620  if (var->ndims > 1)
1621  {
1622  if ((retval = read_coord_dimids(var)))
1623  BAIL(retval);
1624  }
1625  else
1626  {
1627  /* sanity check */
1628  assert(0 == strcmp(var->name, dim->name));
1629 
1630  var->dimids[0] = dim->dimid;
1631  var->dim[0] = dim;
1632  }
1633  dim->coord_var = var;
1634  }
1635  /* If this is not a scale, but has scales, iterate
1636  * through them. (i.e. this is a variable that is not a
1637  * coordinate variable) */
1638  else
1639  {
1640  int num_scales = 0;
1641 
1642  /* Find out how many scales are attached to this
1643  * dataset. H5DSget_num_scales returns an error if there are no
1644  * scales, so convert a negative return value to zero. */
1645  num_scales = H5DSget_num_scales(datasetid, 0);
1646  if (num_scales < 0)
1647  num_scales = 0;
1648 
1649  if (num_scales && ndims)
1650  {
1651  /* Allocate space to remember whether the dimscale has been attached
1652  * for each dimension. */
1653  if (NULL == (var->dimscale_attached = calloc(ndims, sizeof(nc_bool_t))))
1654  BAIL(NC_ENOMEM);
1655 
1656  /* Store id information allowing us to match hdf5
1657  * dimscales to netcdf dimensions. */
1658  if (NULL == (var->dimscale_hdf5_objids = malloc(ndims * sizeof(struct hdf5_objid))))
1659  BAIL(NC_ENOMEM);
1660  for (d = 0; d < var->ndims; d++)
1661  {
1662  if (H5DSiterate_scales(var->hdf_datasetid, d, NULL, dimscale_visitor,
1663  &(var->dimscale_hdf5_objids[d])) < 0)
1664  BAIL(NC_EHDFERR);
1665  var->dimscale_attached[d] = NC_TRUE;
1666  }
1667  }
1668  }
1669 
1670  /* Now read all the attributes of this variable, ignoring the
1671  ones that hold HDF5 dimension scale information. */
1672  if ((natts = H5Aget_num_attrs(var->hdf_datasetid)) < 0)
1673  BAIL(NC_EATTMETA);
1674  for (a = 0; a < natts; a++)
1675  {
1676  /* Close the attribute and try to move on with our
1677  * lives. Like bits through the network port, so
1678  * flows the Days of Our Lives! */
1679  if (attid && H5Aclose(attid) < 0)
1680  BAIL(NC_EHDFERR);
1681 
1682  /* Open the att and get its name. */
1683  if ((attid = H5Aopen_idx(var->hdf_datasetid, (unsigned int)a)) < 0)
1684  BAIL(NC_EATTMETA);
1685  if (H5Aget_name(attid, NC_MAX_HDF5_NAME, att_name) < 0)
1686  BAIL(NC_EATTMETA);
1687  LOG((4, "%s:: a %d att_name %s", __func__, a, att_name));
1688 
1689  /* Should we ignore this attribute? */
1690  if (strcmp(att_name, REFERENCE_LIST) &&
1691  strcmp(att_name, CLASS) &&
1692  strcmp(att_name, DIMENSION_LIST) &&
1693  strcmp(att_name, NAME) &&
1694  strcmp(att_name, COORDINATES) &&
1695  strcmp(att_name, NC_DIMID_ATT_NAME))
1696  {
1697  /* Add to the end of the list of atts for this var. */
1698  if ((retval = nc4_att_list_add(&var->att, &att)))
1699  BAIL(retval);
1700 
1701  /* Fill in the information we know. */
1702  att->attnum = var->natts++;
1703  if (!(att->name = strdup(att_name)))
1704  BAIL(NC_ENOMEM);
1705 
1706  /* Read the rest of the info about the att,
1707  * including its values. */
1708  if ((retval = read_hdf5_att(grp, attid, att)))
1709  {
1710  if (NC_EBADTYPID == retval)
1711  {
1712  if ((retval = nc4_att_list_del(&var->att, att)))
1713  BAIL(retval);
1714  continue;
1715  }
1716  else
1717  BAIL(retval);
1718  }
1719 
1720  att->created = NC_TRUE;
1721  } /* endif not HDF5 att */
1722  } /* next attribute */
1723 
1724  /* Is this a deflated variable with a chunksize greater than the
1725  * current cache size? */
1726  if ((retval = nc4_adjust_var_cache(grp, var)))
1727  BAIL(retval);
1728 
1729 exit:
1730  if (retval)
1731  {
1732  if (incr_id_rc && H5Idec_ref(datasetid) < 0)
1733  BAIL2(NC_EHDFERR);
1734  if (var && nc4_var_list_del(&grp->var, var))
1735  BAIL2(NC_EHDFERR);
1736  }
1737  if (access_pid && H5Pclose(access_pid) < 0)
1738  BAIL2(NC_EHDFERR);
1739 #ifdef EXTRA_TESTS
1740  num_plists--;
1741 #endif
1742  if (propid > 0 && H5Pclose(propid) < 0)
1743  BAIL2(NC_EHDFERR);
1744 #ifdef EXTRA_TESTS
1745  num_plists--;
1746 #endif
1747  if (attid > 0 && H5Aclose(attid) < 0)
1748  BAIL2(NC_EHDFERR);
1749  return retval;
1750 }
1751 
1752 /* This function is called by nc4_rec_read_metadata to read all the
1753  * group level attributes (the NC_GLOBAL atts for this group). */
1754 static int
1755 read_grp_atts(NC_GRP_INFO_T *grp)
1756 {
1757  hid_t attid = 0;
1758  hsize_t num_obj, i;
1759  NC_ATT_INFO_T *att;
1760  NC_TYPE_INFO_T *type;
1761  char obj_name[NC_MAX_HDF5_NAME + 1];
1762  int max_len;
1763  int retval = NC_NOERR;
1764 
1765  num_obj = H5Aget_num_attrs(grp->hdf_grpid);
1766  for (i = 0; i < num_obj; i++)
1767  {
1768  /* Close an attribute from previous loop iteration */
1769  /* (Should be from 'continue' statement, below) */
1770  if (attid && H5Aclose(attid) < 0)
1771  BAIL(NC_EHDFERR);
1772 
1773  if ((attid = H5Aopen_idx(grp->hdf_grpid, (unsigned int)i)) < 0)
1774  BAIL(NC_EATTMETA);
1775  if (H5Aget_name(attid, NC_MAX_NAME + 1, obj_name) < 0)
1776  BAIL(NC_EATTMETA);
1777  LOG((3, "reading attribute of _netCDF group, named %s", obj_name));
1778 
1779  /* This may be an attribute telling us that strict netcdf-3
1780  * rules are in effect. If so, we will make note of the fact,
1781  * but not add this attribute to the metadata. It's not a user
1782  * attribute, but an internal netcdf-4 one. */
1783  if (!strcmp(obj_name, NC3_STRICT_ATT_NAME))
1784  grp->nc4_info->cmode |= NC_CLASSIC_MODEL;
1785  else
1786  {
1787  /* Add an att struct at the end of the list, and then go to it. */
1788  if ((retval = nc4_att_list_add(&grp->att, &att)))
1789  BAIL(retval);
1790 
1791  /* Add the info about this attribute. */
1792  max_len = strlen(obj_name) > NC_MAX_NAME ? NC_MAX_NAME : strlen(obj_name);
1793  if (!(att->name = malloc((max_len + 1) * sizeof(char))))
1794  BAIL(NC_ENOMEM);
1795  strncpy(att->name, obj_name, max_len);
1796  att->name[max_len] = 0;
1797  att->attnum = grp->natts++;
1798  if ((retval = read_hdf5_att(grp, attid, att)))
1799  {
1800  if (NC_EBADTYPID == retval)
1801  {
1802  if ((retval = nc4_att_list_del(&grp->att, att)))
1803  BAIL(retval);
1804  continue;
1805  }
1806  else
1807  BAIL(retval);
1808  }
1809  att->created = NC_TRUE;
1810  if ((retval = nc4_find_type(grp->nc4_info, att->nc_typeid, &type)))
1811  BAIL(retval);
1812  }
1813  }
1814 
1815  exit:
1816  if (attid > 0 && H5Aclose(attid) < 0)
1817  BAIL2(NC_EHDFERR);
1818  return retval;
1819 }
1820 
1821 /* This function is called when nc4_rec_read_metadata encounters an HDF5
1822  * dataset when reading a file. */
1823 static int
1824 read_dataset(NC_GRP_INFO_T *grp, hid_t datasetid, const char *obj_name,
1825  const H5G_stat_t *statbuf)
1826 {
1827  NC_DIM_INFO_T *dim = NULL; /* Dimension created for scales */
1828  hid_t spaceid = 0;
1829  int ndims;
1830  int is_scale = 0;
1831  int retval = NC_NOERR;
1832 
1833  /* Get the dimension information for this dataset. */
1834  if ((spaceid = H5Dget_space(datasetid)) < 0)
1835  BAIL(NC_EHDFERR);
1836 #ifdef EXTRA_TESTS
1837  num_spaces++;
1838 #endif
1839  if ((ndims = H5Sget_simple_extent_ndims(spaceid)) < 0)
1840  BAIL(NC_EHDFERR);
1841 
1842  /* Is this a dimscale? */
1843  if ((is_scale = H5DSis_scale(datasetid)) < 0)
1844  BAIL(NC_EHDFERR);
1845  if (is_scale)
1846  {
1847  hsize_t dims[H5S_MAX_RANK];
1848  hsize_t max_dims[H5S_MAX_RANK];
1849 
1850  /* Query the scale's size & max. size */
1851  if (H5Sget_simple_extent_dims(spaceid, dims, max_dims) < 0)
1852  BAIL(NC_EHDFERR);
1853 
1854  /* Read the scale information. */
1855  if ((retval = read_scale(grp, datasetid, obj_name, statbuf, dims[0],
1856  max_dims[0], &dim)))
1857  BAIL(retval);
1858  }
1859 
1860  /* Add a var to the linked list, and get its metadata,
1861  * unless this is one of those funny dimscales that are a
1862  * dimension in netCDF but not a variable. (Spooky!) */
1863  if (NULL == dim || (dim && !dim->hdf_dimscaleid))
1864  if ((retval = read_var(grp, datasetid, obj_name, ndims, dim)))
1865  BAIL(retval);
1866 
1867 exit:
1868  if (spaceid && H5Sclose(spaceid) <0)
1869  BAIL2(retval);
1870 #ifdef EXTRA_TESTS
1871  num_spaces--;
1872 #endif
1873 
1874  return retval;
1875 }
1876 
1877 static int
1878 nc4_rec_read_metadata_cb_list_add(NC4_rec_read_metadata_obj_info_t **head,
1880  const NC4_rec_read_metadata_obj_info_t *oinfo)
1881 {
1882  NC4_rec_read_metadata_obj_info_t *new_oinfo; /* Pointer to info for object */
1883 
1884  /* Allocate memory for the object's info */
1885  if (!(new_oinfo = calloc(1, sizeof(*new_oinfo))))
1886  return NC_ENOMEM;
1887 
1888  /* Make a copy of the object's info */
1889  memcpy(new_oinfo, oinfo, sizeof(*oinfo));
1890 
1891  if (*tail)
1892  {
1893  assert(*head);
1894  (*tail)->next = new_oinfo;
1895  *tail = new_oinfo;
1896  }
1897  else
1898  {
1899  assert(NULL == *head);
1900  *head = *tail = new_oinfo;
1901  }
1902 
1903  return (NC_NOERR);
1904 }
1905 
1906 static int
1907 nc4_rec_read_metadata_cb(hid_t grpid, const char *name, const H5L_info_t *info,
1908  void *_op_data)
1909 {
1910  NC4_rec_read_metadata_ud_t *udata = (NC4_rec_read_metadata_ud_t *)_op_data; /* Pointer to user data for callback */
1911  NC4_rec_read_metadata_obj_info_t oinfo; /* Pointer to info for object */
1912  int retval = H5_ITER_CONT;
1913 
1914  /* Reset the memory for the object's info */
1915  memset(&oinfo, 0, sizeof(oinfo));
1916 
1917  /* Open this critter. */
1918  if ((oinfo.oid = H5Oopen(grpid, name, H5P_DEFAULT)) < 0)
1919  BAIL(H5_ITER_ERROR);
1920 
1921  /* Get info about the object.*/
1922  if (H5Gget_objinfo(oinfo.oid, ".", 1, &oinfo.statbuf) < 0)
1923  BAIL(H5_ITER_ERROR);
1924 
1925  strncpy(oinfo.oname, name, NC_MAX_NAME);
1926 
1927  /* Add object to list, for later */
1928  switch(oinfo.statbuf.type)
1929  {
1930  case H5G_GROUP:
1931  LOG((3, "found group %s", oinfo.oname));
1932 
1933  /* Defer descending into child group immediately, so that the types
1934  * in the current group can be processed and be ready for use by
1935  * vars in the child group(s).
1936  */
1937  if (nc4_rec_read_metadata_cb_list_add(&udata->grps_head, &udata->grps_tail, &oinfo))
1938  BAIL(H5_ITER_ERROR);
1939  break;
1940 
1941  case H5G_DATASET:
1942  LOG((3, "found dataset %s", oinfo.oname));
1943 
1944  /* Learn all about this dataset, which may be a dimscale
1945  * (i.e. dimension metadata), or real data. */
1946  if ((retval = read_dataset(udata->grp, oinfo.oid, oinfo.oname, &oinfo.statbuf)))
1947  {
1948  /* Allow NC_EBADTYPID to transparently skip over datasets
1949  * which have a datatype that netCDF-4 doesn't undertand
1950  * (currently), but break out of iteration for other
1951  * errors.
1952  */
1953  if(NC_EBADTYPID != retval)
1954  BAIL(H5_ITER_ERROR);
1955  else
1956  retval = H5_ITER_CONT;
1957  }
1958 
1959  /* Close the object */
1960  if (H5Oclose(oinfo.oid) < 0)
1961  BAIL(H5_ITER_ERROR);
1962  break;
1963 
1964  case H5G_TYPE:
1965  LOG((3, "found datatype %s", oinfo.oname));
1966 
1967  /* Process the named datatype */
1968  if (read_type(udata->grp, oinfo.oid, oinfo.oname))
1969  BAIL(H5_ITER_ERROR);
1970 
1971  /* Close the object */
1972  if (H5Oclose(oinfo.oid) < 0)
1973  BAIL(H5_ITER_ERROR);
1974  break;
1975 
1976  default:
1977  LOG((0, "Unknown object class %d in %s!", oinfo.statbuf.type, __func__));
1978  BAIL(H5_ITER_ERROR);
1979  }
1980 
1981 exit:
1982  if (retval)
1983  {
1984  if (oinfo.oid > 0 && H5Oclose(oinfo.oid) < 0)
1985  BAIL2(H5_ITER_ERROR);
1986  }
1987 
1988  return (retval);
1989 }
1990 
1991 /* This is the main function to recursively read all the metadata for the file. */
1992 /* The links in the 'grp' are iterated over and added to the file's metadata
1993  * information. Note that child groups are not immediately processed, but
1994  * are deferred until all the other links in the group are handled (so that
1995  * vars in the child groups are guaranteed to have types that they use in
1996  * a parent group in place).
1997  */
1998 static int
1999 nc4_rec_read_metadata(NC_GRP_INFO_T *grp)
2000 {
2001  NC4_rec_read_metadata_ud_t udata; /* User data for iteration */
2002  NC4_rec_read_metadata_obj_info_t *oinfo; /* Pointer to info for object */
2003  hsize_t idx=0;
2004  hid_t pid = 0;
2005  unsigned crt_order_flags = 0;
2006  H5_index_t iter_index;
2007  int retval = NC_NOERR; /* everything worked! */
2008 
2009  assert(grp && grp->name);
2010  LOG((3, "%s: grp->name %s", __func__, grp->name));
2011 
2012  /* Portably initialize user data for later */
2013  memset(&udata, 0, sizeof(udata));
2014 
2015  /* Open this HDF5 group and retain its grpid. It will remain open
2016  * with HDF5 until this file is nc_closed. */
2017  if (!grp->hdf_grpid)
2018  {
2019  if (grp->parent)
2020  {
2021  if ((grp->hdf_grpid = H5Gopen2(grp->parent->hdf_grpid,
2022  grp->name, H5P_DEFAULT)) < 0)
2023  BAIL(NC_EHDFERR);
2024  }
2025  else
2026  {
2027  if ((grp->hdf_grpid = H5Gopen2(grp->nc4_info->hdfid,
2028  "/", H5P_DEFAULT)) < 0)
2029  BAIL(NC_EHDFERR);
2030  }
2031  }
2032  assert(grp->hdf_grpid > 0);
2033 
2034  /* Get the group creation flags, to check for creation ordering */
2035  pid = H5Gget_create_plist(grp->hdf_grpid);
2036  H5Pget_link_creation_order(pid, &crt_order_flags);
2037  if (H5Pclose(pid) < 0)
2038  BAIL(NC_EHDFERR);
2039 
2040  /* Set the iteration index to use */
2041  if (crt_order_flags & H5P_CRT_ORDER_TRACKED)
2042  iter_index = H5_INDEX_CRT_ORDER;
2043  else
2044  {
2045  NC_HDF5_FILE_INFO_T *h5 = grp->nc4_info;
2046 
2047  /* Without creation ordering, file must be read-only. */
2048  if (!h5->no_write)
2049  BAIL(NC_ECANTWRITE);
2050 
2051  iter_index = H5_INDEX_NAME;
2052  }
2053 
2054  /* Set user data for iteration */
2055  udata.grp = grp;
2056 
2057  /* Iterate over links in this group, building lists for the types,
2058  * datasets and groups encountered
2059  */
2060  if (H5Literate(grp->hdf_grpid, iter_index, H5_ITER_INC, &idx,
2061  nc4_rec_read_metadata_cb, (void *)&udata) < 0)
2062  BAIL(NC_EHDFERR);
2063 
2064  /* Process the child groups found */
2065  /* (Deferred until now, so that the types in the current group get
2066  * processed and are available for vars in the child group(s).)
2067  */
2068  for (oinfo = udata.grps_head; oinfo; oinfo = udata.grps_head)
2069  {
2070  NC_GRP_INFO_T *child_grp;
2071  NC_HDF5_FILE_INFO_T *h5 = grp->nc4_info;
2072 
2073  /* Add group to file's hierarchy */
2074  if ((retval = nc4_grp_list_add(&(grp->children), h5->next_nc_grpid++,
2075  grp, grp->nc4_info->controller, oinfo->oname, &child_grp)))
2076  BAIL(retval);
2077 
2078  /* Recursively read the child group's metadata */
2079  if ((retval = nc4_rec_read_metadata(child_grp)))
2080  BAIL(retval);
2081 
2082  /* Close the object */
2083  if (H5Oclose(oinfo->oid) < 0)
2084  BAIL(NC_EHDFERR);
2085 
2086  /* Advance to next node, free current node */
2087  udata.grps_head = oinfo->next;
2088  free(oinfo);
2089  }
2090 
2091  /* Scan the group for global (i.e. group-level) attributes. */
2092  if ((retval = read_grp_atts(grp)))
2093  BAIL(retval);
2094 
2095 exit:
2096  /* Clean up local information on error, if anything remains */
2097  if (retval)
2098  {
2099  for (oinfo = udata.grps_head; oinfo; oinfo = udata.grps_head)
2100  {
2101  /* Close the object */
2102  if (H5Oclose(oinfo->oid) < 0)
2103  BAIL2(NC_EHDFERR);
2104 
2105  /* Advance to next node, free current node */
2106  udata.grps_head = oinfo->next;
2107  free(oinfo);
2108  }
2109  }
2110 
2111  return retval;
2112 }
2113 
2114 /* Open a netcdf-4 file. Things have already been kicked off in
2115  * ncfunc.c in nc_open, but here the netCDF-4 part of opening a file
2116  * is handled. */
2117 static int
2118 nc4_open_file(const char *path, int mode, MPI_Comm comm,
2119  MPI_Info info, NC *nc)
2120 {
2121  hid_t fapl_id = H5P_DEFAULT;
2122  unsigned flags = (mode & NC_WRITE) ?
2123  H5F_ACC_RDWR : H5F_ACC_RDONLY;
2124  int retval;
2125  NC_HDF5_FILE_INFO_T* nc4_info = NULL;
2126 #ifdef USE_PARALLEL
2127  int comm_duped = 0; /* Whether the MPI Communicator was duplicated */
2128  int info_duped = 0; /* Whether the MPI Info object was duplicated */
2129 #endif /* !USE_PARALLEL */
2130 
2131  LOG((3, "%s: path %s mode %d", __func__, path, mode));
2132  assert(path && nc);
2133  /* Stop diskless open in its tracks */
2134  if(mode & NC_DISKLESS)
2135  return NC_EDISKLESS;
2136 
2137  /* Add necessary structs to hold netcdf-4 file data. */
2138  if ((retval = nc4_nc4f_list_add(nc, path, mode)))
2139  BAIL(retval);
2140  nc4_info = NC4_DATA(nc);
2141  assert(nc4_info && nc4_info->root_grp);
2142 
2143  /* Need this access plist to control how HDF5 handles open onjects
2144  * on file close. (Setting H5F_CLOSE_SEMI will cause H5Fclose to
2145  * fail if there are any open objects in the file. */
2146  if ((fapl_id = H5Pcreate(H5P_FILE_ACCESS)) < 0)
2147  BAIL(NC_EHDFERR);
2148 #ifdef EXTRA_TESTS
2149  num_plists++;
2150 #endif
2151 #ifdef EXTRA_TESTS
2152  if (H5Pset_fclose_degree(fapl_id, H5F_CLOSE_SEMI))
2153  BAIL(NC_EHDFERR);
2154 #else
2155  if (H5Pset_fclose_degree(fapl_id, H5F_CLOSE_STRONG))
2156  BAIL(NC_EHDFERR);
2157 #endif
2158 
2159 #ifdef USE_PARALLEL
2160  /* If this is a parallel file create, set up the file creation
2161  property list. */
2162  if (mode & NC_MPIIO || mode & NC_MPIPOSIX)
2163  {
2164  nc4_info->parallel = NC_TRUE;
2165  if (mode & NC_MPIIO) /* MPI/IO */
2166  {
2167  LOG((4, "opening parallel file with MPI/IO"));
2168  if (H5Pset_fapl_mpio(fapl_id, comm, info) < 0)
2169  BAIL(NC_EPARINIT);
2170  }
2171  else /* MPI/POSIX */
2172  {
2173  LOG((4, "opening parallel file with MPI/posix"));
2174  if (H5Pset_fapl_mpiposix(fapl_id, comm, 0) < 0)
2175  BAIL(NC_EPARINIT);
2176  }
2177 
2178  /* Keep copies of the MPI Comm & Info objects */
2179  if (MPI_SUCCESS != MPI_Comm_dup(comm, &nc4_info->comm))
2180  BAIL(NC_EMPI);
2181  comm_duped++;
2182  if (MPI_INFO_NULL != info)
2183  {
2184  if (MPI_SUCCESS != MPI_Info_dup(info, &nc4_info->info))
2185  BAIL(NC_EMPI);
2186  info_duped++;
2187  }
2188  else
2189  {
2190  /* No dup, just copy it. */
2191  nc4_info->info = info;
2192  }
2193  }
2194 #else /* only set cache for non-parallel. */
2195  if (H5Pset_cache(fapl_id, 0, nc4_chunk_cache_nelems, nc4_chunk_cache_size,
2196  nc4_chunk_cache_preemption) < 0)
2197  BAIL(NC_EHDFERR);
2198  LOG((4, "%s: set HDF raw chunk cache to size %d nelems %d preemption %f",
2199  __func__, nc4_chunk_cache_size, nc4_chunk_cache_nelems, nc4_chunk_cache_preemption));
2200 #endif /* USE_PARALLEL */
2201 
2202  /* The NetCDF-3.x prototype contains an mode option NC_SHARE for
2203  multiple processes accessing the dataset concurrently. As there
2204  is no HDF5 equivalent, NC_SHARE is treated as NC_NOWRITE. */
2205  if ((nc4_info->hdfid = H5Fopen(path, flags, fapl_id)) < 0)
2206  BAIL(NC_EHDFERR);
2207 
2208  /* Does the mode specify that this file is read-only? */
2209  if ((mode & NC_WRITE) == 0)
2210  nc4_info->no_write = NC_TRUE;
2211 
2212  /* Now read in all the metadata. Some types and dimscale
2213  * information may be difficult to resolve here, if, for example, a
2214  * dataset of user-defined type is encountered before the
2215  * definition of that type. */
2216  if ((retval = nc4_rec_read_metadata(nc4_info->root_grp)))
2217  BAIL(retval);
2218 
2219  /* Now figure out which netCDF dims are indicated by the dimscale
2220  * information. */
2221  if ((retval = nc4_rec_match_dimscales(nc4_info->root_grp)))
2222  BAIL(retval);
2223 
2224 #ifdef LOGGING
2225  /* This will print out the names, types, lens, etc of the vars and
2226  atts in the file, if the logging level is 2 or greater. */
2227  log_metadata_nc(nc);
2228 #endif
2229 
2230  /* Close the property list. */
2231  if (H5Pclose(fapl_id) < 0)
2232  BAIL(NC_EHDFERR);
2233 #ifdef EXTRA_TESTS
2234  num_plists--;
2235 #endif
2236 
2237  return NC_NOERR;
2238 
2239 exit:
2240 #ifdef USE_PARALLEL
2241  if (comm_duped) MPI_Comm_free(&nc4_info->comm);
2242  if (info_duped) MPI_Info_free(&nc4_info->info);
2243 #endif
2244 #ifdef EXTRA_TESTS
2245  num_plists--;
2246 #endif
2247  if (fapl_id != H5P_DEFAULT) H5Pclose(fapl_id);
2248  if (!nc4_info) return retval;
2249  close_netcdf4_file(nc4_info,1); /* treat like abort*/
2250  return retval;
2251 }
2252 
2253 /* Given an HDF4 type, set a pointer to netcdf type. */
2254 #ifdef USE_HDF4
2255 static int
2256 get_netcdf_type_from_hdf4(NC_HDF5_FILE_INFO_T *h5, int32 hdf4_typeid,
2257  nc_type *xtype, NC_TYPE_INFO_T *type_info)
2258 {
2259  int t;
2260  assert(h5 && xtype);
2261 
2262  switch(hdf4_typeid)
2263  {
2264  case DFNT_CHAR:
2265  *xtype = NC_CHAR;
2266  t = 0;
2267  break;
2268  case DFNT_UCHAR:
2269  case DFNT_UINT8:
2270  *xtype = NC_UBYTE;
2271  t = 6;
2272  break;
2273  case DFNT_INT8:
2274  *xtype = NC_BYTE;
2275  t = 1;
2276  break;
2277  case DFNT_INT16:
2278  *xtype = NC_SHORT;
2279  t = 2;
2280  break;
2281  case DFNT_UINT16:
2282  *xtype = NC_USHORT;
2283  t = 7;
2284  break;
2285  case DFNT_INT32:
2286  *xtype = NC_INT;
2287  t = 3;
2288  break;
2289  case DFNT_UINT32:
2290  *xtype = NC_UINT;
2291  t = 8;
2292  break;
2293  case DFNT_FLOAT32:
2294  *xtype = NC_FLOAT;
2295  t = 4;
2296  break;
2297  case DFNT_FLOAT64:
2298  *xtype = NC_DOUBLE;
2299  t = 5;
2300  break;
2301  default:
2302  *xtype = NC_NAT;
2303  return NC_EBADTYPID;
2304  }
2305 
2306  if (type_info)
2307  {
2308  if (hdf4_typeid == DFNT_FLOAT32)
2309  type_info->nc_type_class = NC_FLOAT;
2310  else if (hdf4_typeid == DFNT_FLOAT64)
2311  type_info->nc_type_class = NC_DOUBLE;
2312  else if (hdf4_typeid == DFNT_CHAR)
2313  type_info->nc_type_class = NC_STRING;
2314  else
2315  type_info->nc_type_class = NC_INT;
2316  type_info->endianness = NC_ENDIAN_BIG;
2317  type_info->nc_typeid = *xtype;
2318  type_info->size = nc_type_size_g[t];
2319  if (!(type_info->name = strdup(nc_type_name_g[t])))
2320  return NC_ENOMEM;
2321  }
2322 
2323  return NC_NOERR;
2324 }
2325 
2326 /* Open a HDF4 file. Things have already been kicked off in nc_open,
2327  * but here the netCDF-4 part of opening a file is handled. */
2328 static int
2329 nc4_open_hdf4_file(const char *path, int mode, NC *nc)
2330 {
2331  NC_HDF5_FILE_INFO_T *h5;
2332  NC_GRP_INFO_T *grp;
2333  NC_ATT_INFO_T *att;
2334  int32 num_datasets, num_gatts;
2335  int32 rank;
2336  int v, d, a;
2337  int retval;
2338  NC_HDF5_FILE_INFO_T* nc4_info = NULL;
2339 
2340  LOG((3, "%s: path %s mode %d", __func__, path, mode));
2341  assert(path && nc);
2342 
2343  /* Must be read-only access to hdf4 files. */
2344  if (mode & NC_WRITE)
2345  return NC_EINVAL;
2346 
2347  /* Add necessary structs to hold netcdf-4 file data. */
2348  if ((retval = nc4_nc4f_list_add(nc, path, mode)))
2349  return retval;
2350  nc4_info = NC4_DATA(nc);
2351  assert(nc4_info && nc4_info->root_grp);
2352  h5 = nc4_info;
2353  h5->hdf4 = NC_TRUE;
2354  grp = h5->root_grp;
2355  h5->no_write = NC_TRUE;
2356 
2357  /* Open the file and initialize SD interface. */
2358  if ((h5->sdid = SDstart(path, DFACC_READ)) == FAIL)
2359  return NC_EHDFERR;
2360 
2361  /* Learn how many datasets and global atts we have. */
2362  if (SDfileinfo(h5->sdid, &num_datasets, &num_gatts))
2363  return NC_EHDFERR;
2364 
2365  /* Read the atts. */
2366  for (a = 0; a < num_gatts; a++)
2367  {
2368  int32 att_data_type, att_count;
2369  size_t att_type_size;
2370 
2371  /* Add to the end of the list of atts for this var. */
2372  if ((retval = nc4_att_list_add(&h5->root_grp->att, &att)))
2373  return retval;
2374  att->attnum = grp->natts++;
2375  att->created = NC_TRUE;
2376 
2377  /* Learn about this attribute. */
2378  if (!(att->name = malloc(NC_MAX_HDF4_NAME * sizeof(char))))
2379  return NC_ENOMEM;
2380  if (SDattrinfo(h5->sdid, a, att->name, &att_data_type, &att_count))
2381  return NC_EATTMETA;
2382  if ((retval = get_netcdf_type_from_hdf4(h5, att_data_type,
2383  &att->nc_typeid, NULL)))
2384  return retval;
2385  att->len = att_count;
2386 
2387  /* Allocate memory to hold the data. */
2388  if ((retval = nc4_get_typelen_mem(h5, att->nc_typeid, 0, &att_type_size)))
2389  return retval;
2390  if (!(att->data = malloc(att_type_size * att->len)))
2391  return NC_ENOMEM;
2392 
2393  /* Read the data. */
2394  if (SDreadattr(h5->sdid, a, att->data))
2395  return NC_EHDFERR;
2396  }
2397 
2398  /* Read each dataset. */
2399  for (v = 0; v < num_datasets; v++)
2400  {
2401  NC_VAR_INFO_T *var;
2402  int32 data_type, num_atts;
2403  /* Problem: Number of dims is returned by the call that requires
2404  a pre-allocated array, 'dimsize'.
2405  From SDS_SD website:
2406  http://www.hdfgroup.org/training/HDFtraining/UsersGuide/SDS_SD.fm3.html
2407  The maximum rank is 32, or MAX_VAR_DIMS (as defined in netcdf.h).
2408 
2409  int32 dimsize[MAX_VAR_DIMS];
2410  */
2411  int32 *dimsize = NULL;
2412  size_t var_type_size;
2413  int a;
2414 
2415  /* Add a variable to the end of the group's var list. */
2416  if ((retval = nc4_var_list_add(&grp->var, &var)))
2417  return retval;
2418 
2419  var->varid = grp->nvars++;
2420  var->created = NC_TRUE;
2421  var->written_to = NC_TRUE;
2422 
2423  /* Open this dataset in HDF4 file. */
2424  if ((var->sdsid = SDselect(h5->sdid, v)) == FAIL)
2425  return NC_EVARMETA;
2426 
2427  /* Get shape, name, type, and attribute info about this dataset. */
2428  if (!(var->name = malloc(NC_MAX_HDF4_NAME + 1)))
2429  return NC_ENOMEM;
2430 
2431  /* Invoke SDgetInfo with null dimsize to get rank. */
2432  if (SDgetinfo(var->sdsid, var->name, &rank, NULL, &data_type, &num_atts))
2433  return NC_EVARMETA;
2434 
2435  if(!(dimsize = (int32*)malloc(sizeof(int32)*rank)))
2436  return NC_ENOMEM;
2437 
2438  if (SDgetinfo(var->sdsid, var->name, &rank, dimsize, &data_type, &num_atts)) {
2439  if(dimsize) free(dimsize);
2440  return NC_EVARMETA;
2441  }
2442 
2443  var->ndims = rank;
2444  var->hdf4_data_type = data_type;
2445 
2446  /* Fill special type_info struct for variable type information. */
2447  if (!(var->type_info = calloc(1, sizeof(NC_TYPE_INFO_T)))) {
2448  if(dimsize) free(dimsize);
2449  return NC_ENOMEM;
2450  }
2451 
2452  if ((retval = get_netcdf_type_from_hdf4(h5, data_type, &var->type_info->nc_typeid, var->type_info))) {
2453  if(dimsize) free(dimsize);
2454  return retval;
2455  }
2456 
2457  /* Indicate that the variable has a pointer to the type */
2458  var->type_info->rc++;
2459 
2460  if ((retval = nc4_get_typelen_mem(h5, var->type_info->nc_typeid, 0, &var_type_size))) {
2461  if(dimsize) free(dimsize);
2462  return retval;
2463  }
2464 
2465  var->type_info->size = var_type_size;
2466  LOG((3, "reading HDF4 dataset %s, rank %d netCDF type %d", var->name,
2467  rank, var->type_info->nc_typeid));
2468 
2469  /* Get the fill value. */
2470  if (!(var->fill_value = malloc(var_type_size))) {
2471  if(dimsize) free(dimsize);
2472  return NC_ENOMEM;
2473  }
2474 
2475  if (SDgetfillvalue(var->sdsid, var->fill_value))
2476  {
2477  /* Whoops! No fill value! */
2478  free(var->fill_value);
2479  var->fill_value = NULL;
2480  }
2481 
2482  /* Allocate storage for dimension info in this variable. */
2483  if (var->ndims)
2484  {
2485  if (!(var->dim = malloc(sizeof(NC_DIM_INFO_T *) * var->ndims))) {
2486  if(dimsize) free(dimsize);
2487  return NC_ENOMEM;
2488  }
2489 
2490  if (!(var->dimids = malloc(sizeof(int) * var->ndims))) {
2491  if(dimsize) free(dimsize);
2492  return NC_ENOMEM;
2493  }
2494  }
2495 
2496 
2497  /* Find its dimensions. */
2498  for (d = 0; d < var->ndims; d++)
2499  {
2500  int32 dimid, dim_len, dim_data_type, dim_num_attrs;
2501  char dim_name[NC_MAX_NAME + 1];
2502  NC_DIM_INFO_T *dim;
2503 
2504  if ((dimid = SDgetdimid(var->sdsid, d)) == FAIL) {
2505  if(dimsize) free(dimsize);
2506  return NC_EDIMMETA;
2507  }
2508  if (SDdiminfo(dimid, dim_name, &dim_len, &dim_data_type,
2509  &dim_num_attrs))
2510  {
2511  if(dimsize) free(dimsize);
2512  return NC_EDIMMETA;
2513  }
2514 
2515  /* Do we already have this dimension? HDF4 explicitly uses
2516  * the name to tell. */
2517  for (dim = grp->dim; dim; dim = dim->l.next)
2518  if (!strcmp(dim->name, dim_name))
2519  break;
2520 
2521  /* If we didn't find this dimension, add one. */
2522  if (!dim)
2523  {
2524  LOG((4, "adding dimension %s for HDF4 dataset %s",
2525  dim_name, var->name));
2526  if ((retval = nc4_dim_list_add(&grp->dim, &dim)))
2527  return retval;
2528  grp->ndims++;
2529  dim->dimid = grp->nc4_info->next_dimid++;
2530  if (strlen(dim_name) > NC_MAX_HDF4_NAME)
2531  return NC_EMAXNAME;
2532  if (!(dim->name = strdup(dim_name)))
2533  return NC_ENOMEM;
2534  if (dim_len)
2535  dim->len = dim_len;
2536  else
2537  dim->len = *dimsize;
2538  }
2539 
2540  /* Tell the variable the id of this dimension. */
2541  var->dimids[d] = dim->dimid;
2542  }
2543 
2544  /* Read the atts. */
2545  for (a = 0; a < num_atts; a++)
2546  {
2547  int32 att_data_type, att_count;
2548  size_t att_type_size;
2549 
2550  /* Add to the end of the list of atts for this var. */
2551  if ((retval = nc4_att_list_add(&var->att, &att))) {
2552  if(dimsize) free(dimsize);
2553  return retval;
2554  }
2555  att->attnum = var->natts++;
2556  att->created = NC_TRUE;
2557 
2558  /* Learn about this attribute. */
2559  if (!(att->name = malloc(NC_MAX_HDF4_NAME * sizeof(char)))) {
2560  if(dimsize) free(dimsize);
2561  return NC_ENOMEM;
2562  }
2563  if (SDattrinfo(var->sdsid, a, att->name, &att_data_type, &att_count)) {
2564  if(dimsize) free(dimsize);
2565  return NC_EATTMETA;
2566  }
2567  if ((retval = get_netcdf_type_from_hdf4(h5, att_data_type,
2568  &att->nc_typeid, NULL))) {
2569  if(dimsize) free(dimsize);
2570  return retval;
2571  }
2572 
2573  att->len = att_count;
2574 
2575  /* Allocate memory to hold the data. */
2576  if ((retval = nc4_get_typelen_mem(h5, att->nc_typeid, 0, &att_type_size))) {
2577  if(dimsize) free(dimsize);
2578  return retval;
2579  }
2580  if (!(att->data = malloc(att_type_size * att->len))) {
2581  if(dimsize) free(dimsize);
2582  return NC_ENOMEM;
2583  }
2584 
2585  /* Read the data. */
2586  if (SDreadattr(var->sdsid, a, att->data)) {
2587  if(dimsize) free(dimsize);
2588  return NC_EHDFERR;
2589  }
2590  }
2591  if(dimsize) free(dimsize);
2592  } /* next var */
2593 
2594 #ifdef LOGGING
2595  /* This will print out the names, types, lens, etc of the vars and
2596  atts in the file, if the logging level is 2 or greater. */
2597  log_metadata_nc(h5->root_grp->nc4_info->controller);
2598 #endif
2599  return NC_NOERR;
2600  return NC_ENOTBUILT;
2601 }
2602 #endif /* USE_HDF4 */
2603 
2604 int
2605 NC4_open(const char *path, int mode, int basepe, size_t *chunksizehintp,
2606  int use_parallel, void *mpidata, NC_Dispatch *dispatch, NC *nc_file)
2607 {
2608  int hdf_file = 0;
2609  MPI_Comm comm = MPI_COMM_WORLD;
2610  MPI_Info info = MPI_INFO_NULL;
2611  int res;
2612 
2613  assert(nc_file && path);
2614 
2615  LOG((1, "%s: path %s mode %d comm %d info %d",
2616  __func__, path, mode, comm, info));
2617 
2618 #ifdef USE_PARALLEL
2619  if (mpidata)
2620  {
2621  comm = ((NC_MPI_INFO *)mpidata)->comm;
2622  info = ((NC_MPI_INFO *)mpidata)->info;
2623  }
2624 #endif /* USE_PARALLEL */
2625 
2626  /* If this is our first file, turn off HDF5 error messages. */
2627  if (virgin)
2628  {
2629  if (H5Eset_auto(NULL, NULL) < 0)
2630  LOG((0, "Couldn't turn off HDF5 error messages!"));
2631  LOG((1, "HDF5 error messages turned off!"));
2632  virgin = 0;
2633  }
2634 
2635  /* Check the mode for validity. First make sure only certain bits
2636  * are turned on. Also MPI I/O and MPI POSIX cannot both be
2637  * selected at once. */
2638  if (mode & ~(NC_WRITE | NC_SHARE | NC_MPIIO | NC_MPIPOSIX |
2639  NC_PNETCDF | NC_NOCLOBBER | NC_NETCDF4 | NC_CLASSIC_MODEL) ||
2640  (mode & NC_MPIIO && mode & NC_MPIPOSIX))
2641  return NC_EINVAL;
2642 
2643 
2644  /* Depending on the type of file, open it. */
2645 
2646 #if 0 /*def USE_PNETCDF*/
2647  if(mode & NC_PNETCDF) {
2648  /* this is not really an hdf file */
2649  int pnetcdf_nvars, i;
2650  NC_HDF5_FILE_INFO_T* nc4_info;
2651 
2652  /* Create the fake nc4_info data */
2653  res = nc4_nc4f_list_add(nc_file, path, mode);
2654 
2655  nc4_info = NC4_DATA(nc_file);
2656  assert(nc4_info);
2657 
2658  res = ncmpi_open(comm, path, mode, info, &(nc_file->int_ncid));
2659  nc4_info->pnetcdf_file++;
2660 
2661  /* Default to independent access, like netCDF-4/HDF5 files. */
2662  if (!res)
2663  res = ncmpi_begin_indep_data(nc_file->int_ncid);
2664 
2665  /* I need to keep track of the ndims of each var to translate
2666  * start, count, and stride arrays to MPI_Offset type. */
2667  if (!res)
2668  {
2669  res = ncmpi_inq_nvars(nc_file->int_ncid, &pnetcdf_nvars);
2670  for (i = 0; i < pnetcdf_nvars; i++)
2671  res = ncmpi_inq_varndims(nc_file->int_ncid, i,
2672  &(nc4_info->pnetcdf_ndims[i]));
2673 
2674  }
2675  } else
2676 #endif
2677  {
2678  /* Figure out if this is a hdf4 or hdf5 file. */
2679  if ((res = nc_check_for_hdf(path, use_parallel, comm, info, &hdf_file)))
2680  return res;
2681 
2682  if (hdf_file == NC_HDF5_FILE)
2683  {
2684  nc_file->int_ncid = nc_file->ext_ncid;
2685  res = nc4_open_file(path, mode, comm, info, nc_file);
2686  }
2687 #ifdef USE_HDF4
2688  else if (hdf_file == NC_HDF4_FILE)
2689  {
2690  nc_file->int_ncid = nc_file->ext_ncid;
2691  res = nc4_open_hdf4_file(path, mode, nc_file);
2692  }
2693 #endif /* USE_HDF4 */
2694  else /* netcdf */
2695  {
2696  assert(0); /* should never happen */
2697  }
2698  }
2699 
2700  return res;
2701 }
2702 
2703 /* Unfortunately HDF only allows specification of fill value only when
2704  a dataset is created. Whereas in netcdf, you first create the
2705  variable and then (optionally) specify the fill value. To
2706  accomplish this in HDF5 I have to delete the dataset, and recreate
2707  it, with the fill value specified. */
2708 /* QAK: This looks completely unused in the code. (?) */
2709 int
2710 NC4_set_fill(int ncid, int fillmode, int *old_modep)
2711 {
2712  NC *nc;
2713  NC_HDF5_FILE_INFO_T* nc4_info;
2714 
2715  LOG((2, "%s: ncid 0x%x fillmode %d", __func__, ncid, fillmode));
2716 
2717  if (!(nc = nc4_find_nc_file(ncid,&nc4_info)))
2718  return NC_EBADID;
2719  assert(nc4_info);
2720 
2721  /* Trying to set fill on a read-only file? You sicken me! */
2722  if (nc4_info->no_write)
2723  return NC_EPERM;
2724 
2725  /* Did you pass me some weird fillmode? */
2726  if (fillmode != NC_FILL && fillmode != NC_NOFILL)
2727  return NC_EINVAL;
2728 
2729  /* If the user wants to know, tell him what the old mode was. */
2730  if (old_modep)
2731  *old_modep = nc4_info->fill_mode;
2732 
2733  nc4_info->fill_mode = fillmode;
2734 
2735 #if 0 /*def USE_PNETCDF*/
2736  /* Take care of files created/opened with parallel-netcdf library. */
2737  if (nc4_info->pnetcdf_file)
2738  return ncmpi_set_fill(nc->int_ncid, fillmode, old_modep);
2739 #endif /* USE_PNETCDF */
2740 
2741 
2742  return NC_NOERR;
2743 }
2744 
2745 /* Put the file back in redef mode. This is done automatically for
2746  * netcdf-4 files, if the user forgets. */
2747 int
2748 NC4_redef(int ncid)
2749 {
2750  //NC *nc;
2751  NC_HDF5_FILE_INFO_T* nc4_info;
2752 
2753  LOG((1, "%s: ncid 0x%x", __func__, ncid));
2754 
2755  /* Find this file's metadata. */
2756  if (!(nc4_find_nc_file(ncid,&nc4_info)))
2757  return NC_EBADID;
2758  assert(nc4_info);
2759 
2760 #if 0 /*def USE_PNETCDF*/
2761  /* Take care of files created/opened with parallel-netcdf library. */
2762  if (nc4_info->pnetcdf_file)
2763  return ncmpi_redef(nc->int_ncid);
2764 #endif /* USE_PNETCDF */
2765 
2766  /* If we're already in define mode, return an error. */
2767  if (nc4_info->flags & NC_INDEF)
2768  return NC_EINDEFINE;
2769 
2770  /* If the file is read-only, return an error. */
2771  if (nc4_info->no_write)
2772  return NC_EPERM;
2773 
2774  /* Set define mode. */
2775  nc4_info->flags |= NC_INDEF;
2776 
2777  /* For nc_abort, we need to remember if we're in define mode as a
2778  redef. */
2779  nc4_info->redef = NC_TRUE;
2780 
2781  return NC_NOERR;
2782 }
2783 
2784 /* For netcdf-4 files, this just calls nc_enddef, ignoring the extra
2785  * parameters. */
2786 int
2787 NC4__enddef(int ncid, size_t h_minfree, size_t v_align,
2788  size_t v_minfree, size_t r_align)
2789 {
2790  if (nc4_find_nc_file(ncid,NULL) == NULL)
2791  return NC_EBADID;
2792 
2793  return NC4_enddef(ncid);
2794 }
2795 
2796 /* Take the file out of define mode. This is called automatically for
2797  * netcdf-4 files, if the user forgets. */
2798 static int NC4_enddef(int ncid)
2799 {
2800  NC *nc;
2801  NC_HDF5_FILE_INFO_T* nc4_info;
2802 
2803  LOG((1, "%s: ncid 0x%x", __func__, ncid));
2804 
2805  if (!(nc = nc4_find_nc_file(ncid,&nc4_info)))
2806  return NC_EBADID;
2807  assert(nc4_info);
2808 
2809 #if 0 /*def USE_PNETCDF*/
2810  if (nc4_info->pnetcdf_file)
2811  {
2812  int res;
2813  res = ncmpi_enddef(nc->int_ncid);
2814  if (!res)
2815  {
2816  if (nc4_info->pnetcdf_access_mode == NC_INDEPENDENT)
2817  res = ncmpi_begin_indep_data(nc->int_ncid);
2818  }
2819  return res;
2820  }
2821 #endif /* USE_PNETCDF */
2822 
2823  return nc4_enddef_netcdf4_file(nc4_info);
2824 }
2825 
2826 /* This function will write all changed metadata, and (someday) reread
2827  * all metadata from the file. */
2828 static int
2829 sync_netcdf4_file(NC_HDF5_FILE_INFO_T *h5)
2830 {
2831  int retval;
2832 
2833  assert(h5);
2834  LOG((3, "%s", __func__));
2835 
2836  /* If we're in define mode, that's an error, for strict nc3 rules,
2837  * otherwise, end define mode. */
2838  if (h5->flags & NC_INDEF)
2839  {
2840  if (h5->cmode & NC_CLASSIC_MODEL)
2841  return NC_EINDEFINE;
2842 
2843  /* Turn define mode off. */
2844  h5->flags ^= NC_INDEF;
2845 
2846  /* Redef mode needs to be tracked seperately for nc_abort. */
2847  h5->redef = NC_FALSE;
2848  }
2849 
2850 #ifdef LOGGING
2851  /* This will print out the names, types, lens, etc of the vars and
2852  atts in the file, if the logging level is 2 or greater. */
2853  log_metadata_nc(h5->root_grp->nc4_info->controller);
2854 #endif
2855 
2856  /* Write any metadata that has changed. */
2857  if (!(h5->cmode & NC_NOWRITE))
2858  {
2859  int bad_coord_order = 0; /* if detected, propagate to all groups to consistently store dimids */
2860 
2861  if ((retval = nc4_rec_write_groups_types(h5->root_grp)))
2862  return retval;
2863  if ((retval = nc4_rec_detect_need_to_preserve_dimids(h5->root_grp, &bad_coord_order)))
2864  return retval;
2865  if ((retval = nc4_rec_write_metadata(h5->root_grp, bad_coord_order)))
2866  return retval;
2867  }
2868 
2869  if (H5Fflush(h5->hdfid, H5F_SCOPE_GLOBAL) < 0)
2870  return NC_EHDFERR;
2871 
2872  return retval;
2873 }
2874 
2875 /* Flushes all buffers associated with the file, after writing all
2876  changed metadata. This may only be called in data mode. */
2877 int
2878 NC4_sync(int ncid)
2879 {
2880  NC *nc;
2881  int retval;
2882  NC_HDF5_FILE_INFO_T* nc4_info;
2883 
2884  LOG((2, "%s: ncid 0x%x", __func__, ncid));
2885 
2886  if (!(nc = nc4_find_nc_file(ncid,&nc4_info)))
2887  return NC_EBADID;
2888  assert(nc4_info);
2889 
2890 #if 0 /*def USE_PNETCDF*/
2891  /* Take care of files created/opened with parallel-netcdf library. */
2892  if (nc4_info->pnetcdf_file)
2893  return ncmpi_sync(nc->int_ncid);
2894 #endif /* USE_PNETCDF */
2895 
2896  /* If we're in define mode, we can't sync. */
2897  if (nc4_info && nc4_info->flags & NC_INDEF)
2898  {
2899  if (nc4_info->cmode & NC_CLASSIC_MODEL)
2900  return NC_EINDEFINE;
2901  if ((retval = NC4_enddef(ncid)))
2902  return retval;
2903  }
2904 
2905  return sync_netcdf4_file(nc4_info);
2906 }
2907 
2908 /* This function will free all allocated metadata memory, and close
2909  the HDF5 file. The group that is passed in must be the root group
2910  of the file. */
2911 static int
2912 close_netcdf4_file(NC_HDF5_FILE_INFO_T *h5, int abort)
2913 {
2914  int retval = NC_NOERR;
2915 
2916  assert(h5 && h5->root_grp);
2917  LOG((3, "%s: h5->path %s abort %d", __func__, h5->controller->path, abort));
2918 
2919  /* According to the docs, always end define mode on close. */
2920  if (h5->flags & NC_INDEF)
2921  h5->flags ^= NC_INDEF;
2922 
2923  /* Sync the file, unless we're aborting, or this is a read-only
2924  * file. */
2925  if (!h5->no_write && !abort)
2926  if ((retval = sync_netcdf4_file(h5)))
2927  goto exit;
2928 
2929  /* Delete all the list contents for vars, dims, and atts, in each
2930  * group. */
2931  if ((retval = nc4_rec_grp_del(&h5->root_grp, h5->root_grp)))
2932  goto exit;
2933 
2934  /* Close hdf file. */
2935 #ifdef USE_HDF4
2936  if (h5->hdf4)
2937  {
2938  if (SDend(h5->sdid))
2939  BAIL_QUIET(NC_EHDFERR);
2940  }
2941  else
2942 #endif /* USE_HDF4 */
2943  {
2944 #ifdef USE_PARALLEL
2945  /* Free the MPI Comm & Info objects, if we opened the file in parallel */
2946  if(h5->parallel)
2947  {
2948  MPI_Comm_free(&h5->comm);
2949  if(MPI_INFO_NULL != h5->info)
2950  MPI_Info_free(&h5->info);
2951  }
2952 #endif
2953  if (H5Fclose(h5->hdfid) < 0)
2954  {
2955  int nobjs;
2956 
2957  nobjs = H5Fget_obj_count(h5->hdfid, H5F_OBJ_ALL);
2958  /* Apparently we can get an error even when nobjs == 0 */
2959  if(nobjs < 0) {
2960  BAIL_QUIET(NC_EHDFERR);
2961  } else if(nobjs > 0) {
2962 #ifdef LOGGING
2963  /* If the close doesn't work, probably there are still some HDF5
2964  * objects open, which means there's a bug in the library. So
2965  * print out some info on to help the poor programmer figure it
2966  * out. */
2967  LOG((0, "There are %d HDF5 objects open!", nobjs));
2968 #endif
2969  BAIL_QUIET(NC_EHDFERR);
2970  }
2971  }
2972  }
2973 
2974 exit:
2975  /* Free the nc4_info struct; above code should have reclaimed
2976  everything else */
2977  if(h5 != NULL)
2978  free(h5);
2979 
2980  return retval;
2981 }
2982 
2983 /* From the netcdf-3 docs: The function nc_abort just closes the
2984  netCDF dataset, if not in define mode. If the dataset is being
2985  created and is still in define mode, the dataset is deleted. If
2986  define mode was entered by a call to nc_redef, the netCDF dataset
2987  is restored to its state before definition mode was entered and the
2988  dataset is closed. */
2989 int
2990 NC4_abort(int ncid)
2991 {
2992  NC *nc;
2993  int delete_file = 0;
2994  char path[NC_MAX_NAME + 1];
2995  int retval = NC_NOERR;
2996  NC_HDF5_FILE_INFO_T* nc4_info;
2997 
2998  LOG((2, "%s: ncid 0x%x", __func__, ncid));
2999 
3000  /* Find metadata for this file. */
3001  if (!(nc = nc4_find_nc_file(ncid,&nc4_info)))
3002  return NC_EBADID;
3003 
3004  assert(nc4_info);
3005 
3006 #if 0 /*def USE_PNETCDF*/
3007  /* Take care of files created/opened with parallel-netcdf library. */
3008  if (nc4_info->pnetcdf_file)
3009  return ncmpi_abort(nc->int_ncid);
3010 #endif /* USE_PNETCDF */
3011 
3012  /* If we're in define mode, but not redefing the file, delete it. */
3013  if (nc4_info->flags & NC_INDEF && !nc4_info->redef)
3014  {
3015  delete_file++;
3016  strncpy(path, nc->path,NC_MAX_NAME);
3017  }
3018 
3019  /* Free any resources the netcdf-4 library has for this file's
3020  * metadata. */
3021  if ((retval = close_netcdf4_file(nc4_info, 1)))
3022  return retval;
3023 
3024  /* Delete the file, if we should. */
3025  if (delete_file)
3026  if (remove(path) < 0)
3027  return NC_ECANTREMOVE;
3028 
3029  return retval;
3030 }
3031 
3032 /* Close the netcdf file, writing any changes first. */
3033 int
3034 NC4_close(int ncid)
3035 {
3036  NC_GRP_INFO_T *grp;
3037  NC *nc;
3038  NC_HDF5_FILE_INFO_T *h5;
3039  int retval;
3040 
3041  LOG((1, "%s: ncid 0x%x", __func__, ncid));
3042 
3043  /* Find our metadata for this file. */
3044  if ((retval = nc4_find_nc_grp_h5(ncid, &nc, &grp, &h5)))
3045  return retval;
3046 
3047  assert(nc && h5 && grp);
3048 
3049  /* This must be the root group. */
3050  if (grp->parent)
3051  return NC_EBADGRPID;
3052 
3053 #if 0 /*def USE_PNETCDF*/
3054  /* Take care of files created/opened with parallel-netcdf library. */
3055  if (h5->pnetcdf_file)
3056  return ncmpi_close(nc->int_ncid);
3057 #endif /* USE_PNETCDF */
3058 
3059  /* Call the nc4 close. */
3060  if ((retval = close_netcdf4_file(grp->nc4_info, 0)))
3061  return retval;
3062 
3063  return NC_NOERR;
3064 }
3065 
3066 /* It's possible for any of these pointers to be NULL, in which case
3067  don't try to figure out that value. */
3068 int
3069 NC4_inq(int ncid, int *ndimsp, int *nvarsp, int *nattsp, int *unlimdimidp)
3070 {
3071  NC *nc;
3072  NC_HDF5_FILE_INFO_T *h5;
3073  NC_GRP_INFO_T *grp;
3074  NC_DIM_INFO_T *dim;
3075  NC_ATT_INFO_T *att;
3076  NC_VAR_INFO_T *var;
3077  int retval;
3078 
3079  LOG((2, "%s: ncid 0x%x", __func__, ncid));
3080 
3081  /* Find file metadata. */
3082  if ((retval = nc4_find_nc_grp_h5(ncid, &nc, &grp, &h5)))
3083  return retval;
3084 
3085  assert(h5 && grp && nc);
3086 
3087 #if 0 /*def USE_PNETCDF*/
3088  /* Take care of files created/opened with parallel-netcdf library. */
3089  if (h5->pnetcdf_file)
3090  return ncmpi_inq(nc->int_ncid, ndimsp, nvarsp, nattsp, unlimdimidp);
3091 #endif /* USE_PNETCDF */
3092 
3093  /* Count the number of dims, vars, and global atts. */
3094  if (ndimsp)
3095  {
3096  *ndimsp = 0;
3097  for (dim = grp->dim; dim; dim = dim->l.next)
3098  (*ndimsp)++;
3099  }
3100  if (nvarsp)
3101  {
3102  *nvarsp = 0;
3103  for (var = grp->var; var; var= var->l.next)
3104  (*nvarsp)++;
3105  }
3106  if (nattsp)
3107  {
3108  *nattsp = 0;
3109  for (att = grp->att; att; att = att->l.next)
3110  (*nattsp)++;
3111  }
3112 
3113  if (unlimdimidp)
3114  {
3115  /* Default, no unlimited dimension */
3116  *unlimdimidp = -1;
3117 
3118  /* If there's more than one unlimited dim, which was not possible
3119  with netcdf-3, then only the last unlimited one will be reported
3120  back in xtendimp. */
3121  /* Note that this code is inconsistent with nc_inq_unlimid() */
3122  for (dim = grp->dim; dim; dim = dim->l.next)
3123  if (dim->unlimited)
3124  {
3125  *unlimdimidp = dim->dimid;
3126  break;
3127  }
3128  }
3129 
3130  return NC_NOERR;
3131 }
3132 
3133 
3134 /* This function will do the enddef stuff for a netcdf-4 file. */
3135 int
3136 nc4_enddef_netcdf4_file(NC_HDF5_FILE_INFO_T *h5)
3137 {
3138  assert(h5);
3139  LOG((3, "%s", __func__));
3140 
3141  /* If we're not in define mode, return an error. */
3142  if (!(h5->flags & NC_INDEF))
3143  return NC_ENOTINDEFINE;
3144 
3145  /* Turn define mode off. */
3146  h5->flags ^= NC_INDEF;
3147 
3148  /* Redef mode needs to be tracked seperately for nc_abort. */
3149  h5->redef = NC_FALSE;
3150 
3151  return sync_netcdf4_file(h5);
3152 }
3153 
3154 #ifdef EXTRA_TESTS
3155 int
3156 nc_exit()
3157 {
3158  if (num_plists || num_spaces)
3159  return NC_EHDFERR;
3160 
3161  return NC_NOERR;
3162 }
3163 #endif /* EXTRA_TESTS */
3164 
3165 #ifdef USE_PARALLEL
3166 int
3167 nc_use_parallel_enabled()
3168 {
3169  return 0;
3170 }
3171 #endif /* USE_PARALLEL */
3172 
3173 
#define NC_PNETCDF
Use parallel-netcdf library.
Definition: netcdf.h:156
#define NC_ENOMEM
Memory allocation (malloc) failure.
Definition: netcdf.h:353
#define NC_CHAR
ISO/ASCII character.
Definition: netcdf.h:38
#define NC_ECANTWRITE
Can't write.
Definition: netcdf.h:386
#define NC_SHARE
Share updates, limit cacheing.
Definition: netcdf.h:146
#define NC_UBYTE
unsigned 1 byte int
Definition: netcdf.h:44
#define NC_CLASSIC_MODEL
Enforce classic model.
Definition: netcdf.h:135
#define NC_MAX_VAR_DIMS
max per variable dimensions
Definition: netcdf.h:232
#define NC_UINT
unsigned 4-byte int
Definition: netcdf.h:46
#define NC_NOCLOBBER
Don't destroy existing file.
Definition: netcdf.h:130
#define NC_EHDFERR
Error at HDF5 layer.
Definition: netcdf.h:384
#define NC_OPAQUE
opaque types
Definition: netcdf.h:56
#define NC_MPIIO
Turn on MPI I/O.
Definition: netcdf.h:152
#define NC_LOCK
Definition: netcdf.h:142
#define NC_INT64
signed 8-byte int
Definition: netcdf.h:47
#define NC_STRING
string
Definition: netcdf.h:49
#define NC_ENOTINDEFINE
Operation not allowed in data mode.
Definition: netcdf.h:294
#define NC_DOUBLE
double precision floating point number
Definition: netcdf.h:43
#define NC_EBADCLASS
Bad class.
Definition: netcdf.h:405
int nc_type
The nc_type type is just an int.
Definition: netcdf.h:27
#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:126
#define NC_BYTE
signed 1 byte integer
Definition: netcdf.h:37
#define NC_EINDEFINE
Operation not allowed in define mode.
Definition: netcdf.h:303
#define NC_ENOTBUILT
Attempt to use feature that was not turned on when netCDF was built.
Definition: netcdf.h:413
#define NC_ENDIAN_LITTLE
In HDF5 files you can set the endianness of variables with nc_def_var_endian().
Definition: netcdf.h:242
#define NC_EATTMETA
Problem with attribute metadata.
Definition: netcdf.h:390
#define NC_VLEN
vlen (variable-length) types
Definition: netcdf.h:55
#define NC_EMPI
MPI operation failed.
Definition: netcdf.h:416
#define NC_EDISKLESS
Error in using diskless access.
Definition: netcdf.h:414
#define NC_EFILEMETA
Problem with file metadata.
Definition: netcdf.h:388
#define NC_FORMAT_64BIT
Format specifier for nc_set_default_format() and returned by nc_inq_format.
Definition: netcdf.h:166
This is the type of arrays of vlens.
Definition: netcdf.h:624
#define NC_EBADTYPE
Not a netcdf data type.
Definition: netcdf.h:315
#define NC_EBADNAME
Attribute or variable name contains illegal characters.
Definition: netcdf.h:345
#define NC_EDIMMETA
Problem with dimension metadata.
Definition: netcdf.h:389
#define NC_EINVAL
Invalid Argument.
Definition: netcdf.h:288
#define NC_INT
signed 4 byte integer
Definition: netcdf.h:40
#define NC_EBADGRPID
Bad group ID.
Definition: netcdf.h:401
#define NC_NOFILL
Argument to nc_set_fill() to turn off filling of data.
Definition: netcdf.h:119
#define NC_ENDIAN_BIG
In HDF5 files you can set the endianness of variables with nc_def_var_endian().
Definition: netcdf.h:243
#define NC_MAX_NAME
Maximum for classic library.
Definition: netcdf.h:231
#define NC_ECANTREMOVE
Can't remove file.
Definition: netcdf.h:376
#define NC_NAT
Not A Type.
Definition: netcdf.h:36
#define NC_EBADTYPID
Bad type ID.
Definition: netcdf.h:402
#define NC_USHORT
unsigned 2-byte int
Definition: netcdf.h:45
#define NC_EPARINIT
Error initializing for parallel access.
Definition: netcdf.h:400
#define NC_NETCDF4
Use netCDF-4/HDF5 format.
Definition: netcdf.h:148
#define NC_EEXIST
netcdf file exists && NC_NOCLOBBER
Definition: netcdf.h:287
#define NC_FORMAT_NETCDF4_CLASSIC
Format specifier for nc_set_default_format() and returned by nc_inq_format.
Definition: netcdf.h:168
#define NC_EBADID
Not a netcdf id.
Definition: netcdf.h:285
#define NC_EVARMETA
Problem with variable metadata.
Definition: netcdf.h:391
#define NC_MAX_UINT
Max or min values for a type.
Definition: netcdf.h:103
int NC4_create(const char *path, int cmode, size_t initialsz, int basepe, size_t *chunksizehintp, int use_parallel, void *mpidata, NC_Dispatch *dispatch, NC *nc_file)
Create a netCDF-4/HDF5 file.
Definition: nc4file.c:425
#define NC_SHORT
signed 2 byte integer
Definition: netcdf.h:39
#define NC_WRITE
Set read-write access for nc_open().
Definition: netcdf.h:127
#define NC_EMAXNAME
NC_MAX_NAME exceeded.
Definition: netcdf.h:331
#define NC_EPERM
Write to read only.
Definition: netcdf.h:289
#define NC_MAX_HDF4_NAME
This is the max size of an SD dataset name in HDF4 (from HDF4 documentation).
Definition: netcdf.h:236
#define NC_NOERR
No Error.
Definition: netcdf.h:278
#define NC_ENUM
enum types
Definition: netcdf.h:57
#define NC_DISKLESS
Use diskless file.
Definition: netcdf.h:132
#define NC_COMPOUND
compound types
Definition: netcdf.h:58
#define NC_FILL
Argument to nc_set_fill() to clear NC_NOFILL.
Definition: netcdf.h:118
#define NC_FLOAT
single precision floating point number
Definition: netcdf.h:42
#define NC_UINT64
unsigned 8-byte int
Definition: netcdf.h:48
#define NC_MPIPOSIX
Turn on MPI POSIX I/O.
Definition: netcdf.h:155

Return to the Main Unidata NetCDF page.
Generated on Sun Nov 23 2014 16:17:49 for NetCDF. NetCDF is a Unidata library.