NetCDF  4.6.2
hdf5file.c
Go to the documentation of this file.
1 /* Copyright 2003-2018, University Corporation for Atmospheric
2  * Research. See COPYRIGHT file for copying and redistribution
3  * conditions. */
14 #include "config.h"
15 #include "hdf5internal.h"
16 #include "ncrc.h"
17 
18 extern int NC4_extract_file_image(NC_FILE_INFO_T* h5); /* In nc4memcb.c */
19 
20 static void dumpopenobjects(NC_FILE_INFO_T* h5);
21 
24 #define LOGOPEN 1
25 
29 #define NRESERVED 11 /*|NC_reservedatt|*/
30 
33 static const NC_reservedatt NC_reserved[NRESERVED] = {
34  {NC_ATT_CLASS, READONLYFLAG|DIMSCALEFLAG}, /*CLASS*/
35  {NC_ATT_DIMENSION_LIST, READONLYFLAG|DIMSCALEFLAG}, /*DIMENSION_LIST*/
36  {NC_ATT_NAME, READONLYFLAG|DIMSCALEFLAG}, /*NAME*/
37  {NC_ATT_REFERENCE_LIST, READONLYFLAG|DIMSCALEFLAG}, /*REFERENCE_LIST*/
38  {NC_ATT_FORMAT, READONLYFLAG}, /*_Format*/
39  {ISNETCDF4ATT, READONLYFLAG|NAMEONLYFLAG}, /*_IsNetcdf4*/
40  {NCPROPS, READONLYFLAG|NAMEONLYFLAG|MATERIALIZEDFLAG},/*_NCProperties*/
41  {NC_ATT_COORDINATES, READONLYFLAG|DIMSCALEFLAG|MATERIALIZEDFLAG},/*_Netcdf4Coordinates*/
42  {NC_DIMID_ATT_NAME, READONLYFLAG|DIMSCALEFLAG|MATERIALIZEDFLAG},/*_Netcdf4Dimid*/
43  {SUPERBLOCKATT, READONLYFLAG|NAMEONLYFLAG},/*_SuperblockVersion*/
44  {NC3_STRICT_ATT_NAME, READONLYFLAG|MATERIALIZEDFLAG}, /*_nc3_strict*/
45 };
46 
47 /* Forward */
48 static int NC4_enddef(int ncid);
49 static void dumpopenobjects(NC_FILE_INFO_T* h5);
50 
58 const NC_reservedatt*
59 NC_findreserved(const char* name)
60 {
61  int n = NRESERVED;
62  int L = 0;
63  int R = (n - 1);
64  for(;;) {
65  if(L > R) break;
66  int m = (L + R) / 2;
67  const NC_reservedatt* p = &NC_reserved[m];
68  int cmp = strcmp(p->name,name);
69  if(cmp == 0) return p;
70  if(cmp < 0)
71  L = (m + 1);
72  else /*cmp > 0*/
73  R = (m - 1);
74  }
75  return NULL;
76 }
77 
89 static int
90 sync_netcdf4_file(NC_FILE_INFO_T *h5)
91 {
92  NC_HDF5_FILE_INFO_T *hdf5_info;
93  int retval;
94 
95  assert(h5 && h5->format_file_info);
96  LOG((3, "%s", __func__));
97 
98  /* If we're in define mode, that's an error, for strict nc3 rules,
99  * otherwise, end define mode. */
100  if (h5->flags & NC_INDEF)
101  {
102  if (h5->cmode & NC_CLASSIC_MODEL)
103  return NC_EINDEFINE;
104 
105  /* Turn define mode off. */
106  h5->flags ^= NC_INDEF;
107 
108  /* Redef mode needs to be tracked separately for nc_abort. */
109  h5->redef = NC_FALSE;
110  }
111 
112 #ifdef LOGGING
113  /* This will print out the names, types, lens, etc of the vars and
114  atts in the file, if the logging level is 2 or greater. */
115  log_metadata_nc(h5);
116 #endif
117 
118  /* Write any metadata that has changed. */
119  if (!h5->no_write)
120  {
121  nc_bool_t bad_coord_order = NC_FALSE;
122 
123  /* Write any user-defined types. */
124  if ((retval = nc4_rec_write_groups_types(h5->root_grp)))
125  return retval;
126 
127  /* Check to see if the coordinate order is messed up. If
128  * detected, propagate to all groups to consistently store
129  * dimids. */
130  if ((retval = nc4_detect_preserve_dimids(h5->root_grp, &bad_coord_order)))
131  return retval;
132 
133  /* Write all the metadata. */
134  if ((retval = nc4_rec_write_metadata(h5->root_grp, bad_coord_order)))
135  return retval;
136 
137  /* Write out _NCProperties */
138  if((retval = NC4_write_ncproperties(h5)))
139  return retval;
140  }
141 
142  /* Tell HDF5 to flush all changes to the file. */
143  hdf5_info = (NC_HDF5_FILE_INFO_T *)h5->format_file_info;
144  if (H5Fflush(hdf5_info->hdfid, H5F_SCOPE_GLOBAL) < 0)
145  return NC_EHDFERR;
146 
147  return NC_NOERR;
148 }
149 
165 int
166 nc4_close_netcdf4_file(NC_FILE_INFO_T *h5, int abort, NC_memio *memio)
167 {
168  NC_HDF5_FILE_INFO_T *hdf5_info;
169  int retval;
170 
171  assert(h5 && h5->root_grp && h5->format_file_info);
172  LOG((3, "%s: h5->path %s abort %d", __func__, h5->controller->path, abort));
173 
174  /* Get HDF5 specific info. */
175  hdf5_info = (NC_HDF5_FILE_INFO_T *)h5->format_file_info;
176 
177  /* Delete all the list contents for vars, dims, and atts, in each
178  * group. */
179  if ((retval = nc4_rec_grp_del(h5->root_grp)))
180  return retval;
181 
182  /* Free lists of dims, groups, and types in the root group. */
183  nclistfree(h5->alldims);
184  nclistfree(h5->allgroups);
185  nclistfree(h5->alltypes);
186 
187 #ifdef USE_PARALLEL4
188  /* Free the MPI Comm & Info objects, if we opened the file in
189  * parallel. */
190  if (h5->parallel)
191  {
192  if (h5->comm != MPI_COMM_NULL)
193  MPI_Comm_free(&h5->comm);
194  if (h5->info != MPI_INFO_NULL)
195  MPI_Info_free(&h5->info);
196  }
197 #endif
198 
199  /* Free the fileinfo struct, which holds info from the fileinfo
200  * hidden attribute. */
201  if (h5->provenance)
202  NC4_free_provenance(h5->provenance);
203  h5->provenance = NULL; /* Avoid double dealloc */
204 
205  /* Close hdf file. It may not be open, since this function is also
206  * called by NC_create() when a file opening is aborted. */
207  if (hdf5_info->hdfid > 0 && H5Fclose(hdf5_info->hdfid) < 0)
208  {
209  dumpopenobjects(h5);
210  return NC_EHDFERR;
211  }
212 
213  /* If inmemory is used and user wants the final memory block,
214  then capture and return the final memory block else free it */
215  if(h5->mem.inmemory) {
216  /* Pull out the final memory */
217  (void)NC4_extract_file_image(h5);
218  if(!abort && memio != NULL) {
219  *memio = h5->mem.memio; /* capture it */
220  h5->mem.memio.memory = NULL; /* avoid duplicate free */
221  }
222  /* If needed, reclaim extraneous memory */
223  if(h5->mem.memio.memory != NULL) {
224  /* If the original block of memory is not resizeable, then
225  it belongs to the caller and we should not free it. */
226  if(!h5->mem.locked)
227  free(h5->mem.memio.memory);
228  }
229  h5->mem.memio.memory = NULL;
230  h5->mem.memio.size = 0;
231  NC4_image_finalize(h5->mem.udata);
232  }
233 
234  /* Free the HDF5-specific info. */
235  if (h5->format_file_info)
236  free(h5->format_file_info);
237 
238  /* Free the nc4_info struct; above code should have reclaimed
239  everything else */
240  free(h5);
241 
242  return NC_NOERR;
243 }
244 
258 int
259 nc4_close_hdf5_file(NC_FILE_INFO_T *h5, int abort, NC_memio *memio)
260 {
261  int retval;
262 
263  assert(h5 && h5->root_grp && h5->format_file_info);
264  LOG((3, "%s: h5->path %s abort %d", __func__, h5->controller->path, abort));
265 
266  /* According to the docs, always end define mode on close. */
267  if (h5->flags & NC_INDEF)
268  h5->flags ^= NC_INDEF;
269 
270  /* Sync the file, unless we're aborting, or this is a read-only
271  * file. */
272  if (!h5->no_write && !abort)
273  if ((retval = sync_netcdf4_file(h5)))
274  return retval;
275 
276  /* Close all open HDF5 objects within the file. */
277  if ((retval = nc4_rec_grp_HDF5_del(h5->root_grp)))
278  return retval;
279 
280  /* Release all intarnal lists and metadata associated with this
281  * file. All HDF5 objects have already been released. */
282  if ((retval = nc4_close_netcdf4_file(h5, abort, memio)))
283  return retval;
284 
285  return NC_NOERR;
286 }
287 
296 static void
297 dumpopenobjects(NC_FILE_INFO_T* h5)
298 {
299  NC_HDF5_FILE_INFO_T *hdf5_info;
300  int nobjs;
301 
302  assert(h5 && h5->format_file_info);
303  hdf5_info = (NC_HDF5_FILE_INFO_T *)h5->format_file_info;
304 
305  if(hdf5_info->hdfid <= 0)
306  return; /* File was never opened */
307 
308  nobjs = H5Fget_obj_count(hdf5_info->hdfid, H5F_OBJ_ALL);
309 
310  /* Apparently we can get an error even when nobjs == 0 */
311  if(nobjs < 0) {
312  return;
313  } else if(nobjs > 0) {
314  char msg[1024];
315  int logit = 0;
316  /* If the close doesn't work, probably there are still some HDF5
317  * objects open, which means there's a bug in the library. So
318  * print out some info on to help the poor programmer figure it
319  * out. */
320  snprintf(msg,sizeof(msg),"There are %d HDF5 objects open!", nobjs);
321 #ifdef LOGGING
322 #ifdef LOGOPEN
323  LOG((0, msg));
324  logit = 1;
325 #endif
326 #else
327  fprintf(stdout,"%s\n",msg);
328  logit = 0;
329 #endif
330  reportopenobjects(logit,hdf5_info->hdfid);
331  fflush(stderr);
332  }
333 
334  return;
335 }
336 
351 int
352 NC4_set_fill(int ncid, int fillmode, int *old_modep)
353 {
354  NC_FILE_INFO_T *nc4_info;
355  int retval;
356 
357  LOG((2, "%s: ncid 0x%x fillmode %d", __func__, ncid, fillmode));
358 
359  /* Get pointer to file info. */
360  if ((retval = nc4_find_grp_h5(ncid, NULL, &nc4_info)))
361  return retval;
362  assert(nc4_info);
363 
364  /* Trying to set fill on a read-only file? You sicken me! */
365  if (nc4_info->no_write)
366  return NC_EPERM;
367 
368  /* Did you pass me some weird fillmode? */
369  if (fillmode != NC_FILL && fillmode != NC_NOFILL)
370  return NC_EINVAL;
371 
372  /* If the user wants to know, tell him what the old mode was. */
373  if (old_modep)
374  *old_modep = nc4_info->fill_mode;
375 
376  nc4_info->fill_mode = fillmode;
377 
378  return NC_NOERR;
379 }
380 
390 int
391 NC4_redef(int ncid)
392 {
393  NC_FILE_INFO_T *nc4_info;
394  int retval;
395 
396  LOG((1, "%s: ncid 0x%x", __func__, ncid));
397 
398  /* Find this file's metadata. */
399  if ((retval = nc4_find_grp_h5(ncid, NULL, &nc4_info)))
400  return retval;
401  assert(nc4_info);
402 
403  /* If we're already in define mode, return an error. */
404  if (nc4_info->flags & NC_INDEF)
405  return NC_EINDEFINE;
406 
407  /* If the file is read-only, return an error. */
408  if (nc4_info->no_write)
409  return NC_EPERM;
410 
411  /* Set define mode. */
412  nc4_info->flags |= NC_INDEF;
413 
414  /* For nc_abort, we need to remember if we're in define mode as a
415  redef. */
416  nc4_info->redef = NC_TRUE;
417 
418  return NC_NOERR;
419 }
420 
434 int
435 NC4__enddef(int ncid, size_t h_minfree, size_t v_align,
436  size_t v_minfree, size_t r_align)
437 {
438  return NC4_enddef(ncid);
439 }
440 
452 static int
453 NC4_enddef(int ncid)
454 {
455  NC_FILE_INFO_T *nc4_info;
456  NC_GRP_INFO_T *grp;
457  NC_VAR_INFO_T *var;
458  int i;
459  int retval;
460 
461  LOG((1, "%s: ncid 0x%x", __func__, ncid));
462 
463  /* Find pointer to group and nc4_info. */
464  if ((retval = nc4_find_nc_grp_h5(ncid, NULL, &grp, &nc4_info)))
465  return retval;
466 
467  /* When exiting define mode, mark all variable written. */
468  for (i = 0; i < ncindexsize(grp->vars); i++)
469  {
470  var = (NC_VAR_INFO_T *)ncindexith(grp->vars, i);
471  assert(var);
472  var->written_to = NC_TRUE;
473  }
474 
475  return nc4_enddef_netcdf4_file(nc4_info);
476 }
477 
489 int
490 NC4_sync(int ncid)
491 {
492  NC_FILE_INFO_T *nc4_info;
493  int retval;
494 
495  LOG((2, "%s: ncid 0x%x", __func__, ncid));
496 
497  if ((retval = nc4_find_grp_h5(ncid, NULL, &nc4_info)))
498  return retval;
499  assert(nc4_info);
500 
501  /* If we're in define mode, we can't sync. */
502  if (nc4_info->flags & NC_INDEF)
503  {
504  if (nc4_info->cmode & NC_CLASSIC_MODEL)
505  return NC_EINDEFINE;
506  if ((retval = NC4_enddef(ncid)))
507  return retval;
508  }
509 
510  return sync_netcdf4_file(nc4_info);
511 }
512 
526 int
527 NC4_abort(int ncid)
528 {
529  NC *nc;
530  NC_FILE_INFO_T *nc4_info;
531  int delete_file = 0;
532  char path[NC_MAX_NAME + 1];
533  int retval;
534 
535  LOG((2, "%s: ncid 0x%x", __func__, ncid));
536 
537  /* Find metadata for this file. */
538  if ((retval = nc4_find_nc_grp_h5(ncid, &nc, NULL, &nc4_info)))
539  return retval;
540  assert(nc4_info);
541 
542  /* If we're in define mode, but not redefing the file, delete it. */
543  if (nc4_info->flags & NC_INDEF && !nc4_info->redef)
544  {
545  delete_file++;
546  strncpy(path, nc->path, NC_MAX_NAME);
547  }
548 
549  /* Free any resources the netcdf-4 library has for this file's
550  * metadata. */
551  if ((retval = nc4_close_hdf5_file(nc4_info, 1, NULL)))
552  return retval;
553 
554  /* Delete the file, if we should. */
555  if (delete_file)
556  if (remove(path) < 0)
557  return NC_ECANTREMOVE;
558 
559  return NC_NOERR;
560 }
561 
571 int
572 NC4_close(int ncid, void* params)
573 {
574  NC_GRP_INFO_T *grp;
575  NC *nc;
576  NC_FILE_INFO_T *h5;
577  int retval;
578  int inmemory;
579  NC_memio* memio = NULL;
580 
581  LOG((1, "%s: ncid 0x%x", __func__, ncid));
582 
583  /* Find our metadata for this file. */
584  if ((retval = nc4_find_nc_grp_h5(ncid, &nc, &grp, &h5)))
585  return retval;
586 
587  assert(nc && h5 && grp);
588 
589  /* This must be the root group. */
590  if (grp->parent)
591  return NC_EBADGRPID;
592 
593  inmemory = ((h5->cmode & NC_INMEMORY) == NC_INMEMORY);
594 
595  if(inmemory && params != NULL) {
596  memio = (NC_memio*)params;
597  }
598 
599  /* Call the nc4 close. */
600  if ((retval = nc4_close_hdf5_file(grp->nc4_info, 0, memio)))
601  return retval;
602 
603  return NC_NOERR;
604 }
605 
623 int
624 NC4_inq(int ncid, int *ndimsp, int *nvarsp, int *nattsp, int *unlimdimidp)
625 {
626  NC *nc;
627  NC_FILE_INFO_T *h5;
628  NC_GRP_INFO_T *grp;
629  int retval;
630  int i;
631 
632  LOG((2, "%s: ncid 0x%x", __func__, ncid));
633 
634  /* Find file metadata. */
635  if ((retval = nc4_find_nc_grp_h5(ncid, &nc, &grp, &h5)))
636  return retval;
637 
638  assert(h5 && grp && nc);
639 
640  /* Count the number of dims, vars, and global atts; need to iterate
641  * because of possible nulls. */
642  if (ndimsp)
643  {
644  *ndimsp = ncindexcount(grp->dim);
645  }
646  if (nvarsp)
647  {
648  *nvarsp = ncindexcount(grp->vars);
649  }
650  if (nattsp)
651  {
652  /* Do we need to read the atts? */
653  if (grp->atts_not_read)
654  if ((retval = nc4_read_atts(grp, NULL)))
655  return retval;
656 
657  *nattsp = ncindexcount(grp->att);
658  }
659 
660  if (unlimdimidp)
661  {
662  /* Default, no unlimited dimension */
663  *unlimdimidp = -1;
664 
665  /* If there's more than one unlimited dim, which was not possible
666  with netcdf-3, then only the last unlimited one will be reported
667  back in xtendimp. */
668  /* Note that this code is inconsistent with nc_inq_unlimid() */
669  for(i=0;i<ncindexsize(grp->dim);i++) {
670  NC_DIM_INFO_T* d = (NC_DIM_INFO_T*)ncindexith(grp->dim,i);
671  if(d == NULL) continue;
672  if(d->unlimited) {
673  *unlimdimidp = d->hdr.id;
674  break;
675  }
676  }
677  }
678 
679  return NC_NOERR;
680 }
681 
691 int
692 nc4_enddef_netcdf4_file(NC_FILE_INFO_T *h5)
693 {
694  assert(h5);
695  LOG((3, "%s", __func__));
696 
697  /* If we're not in define mode, return an error. */
698  if (!(h5->flags & NC_INDEF))
699  return NC_ENOTINDEFINE;
700 
701  /* Turn define mode off. */
702  h5->flags ^= NC_INDEF;
703 
704  /* Redef mode needs to be tracked separately for nc_abort. */
705  h5->redef = NC_FALSE;
706 
707  return sync_netcdf4_file(h5);
708 }
#define NC_CLASSIC_MODEL
Enforce classic model on netCDF-4.
Definition: netcdf.h:137
#define NC_INMEMORY
Read from memory.
Definition: netcdf.h:160
#define NC_EHDFERR
Error at HDF5 layer.
Definition: netcdf.h:435
#define NC_ENOTINDEFINE
Operation not allowed in data mode.
Definition: netcdf.h:338
#define NC_EINDEFINE
Operation not allowed in define mode.
Definition: netcdf.h:347
#define NC_EINVAL
Invalid Argument.
Definition: netcdf.h:332
#define NC_EBADGRPID
Bad group ID.
Definition: netcdf.h:450
#define NC_NOFILL
Argument to nc_set_fill() to turn off filling of data.
Definition: netcdf.h:114
#define NC_MAX_NAME
Maximum for classic library.
Definition: netcdf.h:272
#define NC_ECANTREMOVE
Can&#39;t remove file.
Definition: netcdf.h:427
#define NC_EPERM
Write to read only.
Definition: netcdf.h:333
#define NC_NOERR
No Error.
Definition: netcdf.h:322
#define NC_FILL
Argument to nc_set_fill() to clear NC_NOFILL.
Definition: netcdf.h:113

Return to the Main Unidata NetCDF page.
Generated on Wed Dec 12 2018 10:27:40 for NetCDF. NetCDF is a Unidata library.