NetCDF  4.7.4
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 
94 static int
95 detect_preserve_dimids(NC_GRP_INFO_T *grp, nc_bool_t *bad_coord_orderp)
96 {
97  NC_VAR_INFO_T *var;
98  NC_GRP_INFO_T *child_grp;
99  int last_dimid = -1;
100  int retval;
101  int i;
102 
103  /* Iterate over variables in this group */
104  for (i=0; i < ncindexsize(grp->vars); i++)
105  {
106  var = (NC_VAR_INFO_T*)ncindexith(grp->vars,i);
107  if (var == NULL) continue;
108  /* Only matters for dimension scale variables, with non-scalar dimensionality */
109  if (var->dimscale && var->ndims)
110  {
111  /* If the user writes coord vars in a different order then he
112  * defined their dimensions, then, when the file is reopened, the
113  * order of the dimids will change to match the order of the coord
114  * vars. Detect if this is about to happen. */
115  if (var->dimids[0] < last_dimid)
116  {
117  LOG((5, "%s: %s is out of order coord var", __func__, var->hdr.name));
118  *bad_coord_orderp = NC_TRUE;
119  return NC_NOERR;
120  }
121  last_dimid = var->dimids[0];
122 
123  /* If there are multidimensional coordinate variables defined, then
124  * it's also necessary to preserve dimension IDs when the file is
125  * reopened ... */
126  if (var->ndims > 1)
127  {
128  LOG((5, "%s: %s is multidimensional coord var", __func__, var->hdr.name));
129  *bad_coord_orderp = NC_TRUE;
130  return NC_NOERR;
131  }
132 
133  /* Did the user define a dimension, end define mode, reenter define
134  * mode, and then define a coordinate variable for that dimension?
135  * If so, dimensions will be out of order. */
136  if (var->is_new_var || var->became_coord_var)
137  {
138  LOG((5, "%s: coord var defined after enddef/redef", __func__));
139  *bad_coord_orderp = NC_TRUE;
140  return NC_NOERR;
141  }
142  }
143  }
144 
145  /* If there are any child groups, check them also for this condition. */
146  for (i = 0; i < ncindexsize(grp->children); i++)
147  {
148  if (!(child_grp = (NC_GRP_INFO_T *)ncindexith(grp->children, i)))
149  continue;
150  if ((retval = detect_preserve_dimids(child_grp, bad_coord_orderp)))
151  return retval;
152  }
153  return NC_NOERR;
154 }
155 
167 static int
168 sync_netcdf4_file(NC_FILE_INFO_T *h5)
169 {
170  NC_HDF5_FILE_INFO_T *hdf5_info;
171  int retval;
172 
173  assert(h5 && h5->format_file_info);
174  LOG((3, "%s", __func__));
175 
176  /* If we're in define mode, that's an error, for strict nc3 rules,
177  * otherwise, end define mode. */
178  if (h5->flags & NC_INDEF)
179  {
180  if (h5->cmode & NC_CLASSIC_MODEL)
181  return NC_EINDEFINE;
182 
183  /* Turn define mode off. */
184  h5->flags ^= NC_INDEF;
185 
186  /* Redef mode needs to be tracked separately for nc_abort. */
187  h5->redef = NC_FALSE;
188  }
189 
190 #ifdef LOGGING
191  /* This will print out the names, types, lens, etc of the vars and
192  atts in the file, if the logging level is 2 or greater. */
193  log_metadata_nc(h5);
194 #endif
195 
196  /* Write any metadata that has changed. */
197  if (!h5->no_write)
198  {
199  nc_bool_t bad_coord_order = NC_FALSE;
200 
201  /* Write any user-defined types. */
202  if ((retval = nc4_rec_write_groups_types(h5->root_grp)))
203  return retval;
204 
205  /* Check to see if the coordinate order is messed up. If
206  * detected, propagate to all groups to consistently store
207  * dimids. */
208  if ((retval = detect_preserve_dimids(h5->root_grp, &bad_coord_order)))
209  return retval;
210 
211  /* Write all the metadata. */
212  if ((retval = nc4_rec_write_metadata(h5->root_grp, bad_coord_order)))
213  return retval;
214 
215  /* Write out provenance*/
216  if((retval = NC4_write_provenance(h5)))
217  return retval;
218  }
219 
220  /* Tell HDF5 to flush all changes to the file. */
221  hdf5_info = (NC_HDF5_FILE_INFO_T *)h5->format_file_info;
222  if (H5Fflush(hdf5_info->hdfid, H5F_SCOPE_GLOBAL) < 0)
223  return NC_EHDFERR;
224 
225  return NC_NOERR;
226 }
227 
243 int
244 nc4_close_netcdf4_file(NC_FILE_INFO_T *h5, int abort, NC_memio *memio)
245 {
246  NC_HDF5_FILE_INFO_T *hdf5_info;
247  int retval;
248 
249  assert(h5 && h5->root_grp && h5->format_file_info);
250  LOG((3, "%s: h5->path %s abort %d", __func__, h5->controller->path, abort));
251 
252  /* Get HDF5 specific info. */
253  hdf5_info = (NC_HDF5_FILE_INFO_T *)h5->format_file_info;
254 
255 #ifdef USE_PARALLEL4
256  /* Free the MPI Comm & Info objects, if we opened the file in
257  * parallel. */
258  if (h5->parallel)
259  {
260  if (h5->comm != MPI_COMM_NULL)
261  MPI_Comm_free(&h5->comm);
262  if (h5->info != MPI_INFO_NULL)
263  MPI_Info_free(&h5->info);
264  }
265 #endif
266 
267  /* Free the fileinfo struct, which holds info from the fileinfo
268  * hidden attribute. */
269  NC4_clear_provenance(&h5->provenance);
270 
271  /* Close hdf file. It may not be open, since this function is also
272  * called by NC_create() when a file opening is aborted. */
273  if (hdf5_info->hdfid > 0 && H5Fclose(hdf5_info->hdfid) < 0)
274  {
275  dumpopenobjects(h5);
276  return NC_EHDFERR;
277  }
278 
279  /* If inmemory is used and user wants the final memory block,
280  then capture and return the final memory block else free it */
281  if (h5->mem.inmemory)
282  {
283  /* Pull out the final memory */
284  (void)NC4_extract_file_image(h5);
285  if (!abort && memio != NULL)
286  {
287  *memio = h5->mem.memio; /* capture it */
288  h5->mem.memio.memory = NULL; /* avoid duplicate free */
289  }
290  /* If needed, reclaim extraneous memory */
291  if (h5->mem.memio.memory != NULL)
292  {
293  /* If the original block of memory is not resizeable, then
294  it belongs to the caller and we should not free it. */
295  if(!h5->mem.locked)
296  free(h5->mem.memio.memory);
297  }
298  h5->mem.memio.memory = NULL;
299  h5->mem.memio.size = 0;
300  NC4_image_finalize(h5->mem.udata);
301  }
302 
303  /* Free the HDF5-specific info. */
304  if (h5->format_file_info)
305  free(h5->format_file_info);
306 
307  /* Free the NC_FILE_INFO_T struct. */
308  if ((retval = nc4_nc4f_list_del(h5)))
309  return retval;
310 
311  return NC_NOERR;
312 }
313 
327 int
328 nc4_close_hdf5_file(NC_FILE_INFO_T *h5, int abort, NC_memio *memio)
329 {
330  int retval;
331 
332  assert(h5 && h5->root_grp && h5->format_file_info);
333  LOG((3, "%s: h5->path %s abort %d", __func__, h5->controller->path, abort));
334 
335  /* According to the docs, always end define mode on close. */
336  if (h5->flags & NC_INDEF)
337  h5->flags ^= NC_INDEF;
338 
339  /* Sync the file, unless we're aborting, or this is a read-only
340  * file. */
341  if (!h5->no_write && !abort)
342  if ((retval = sync_netcdf4_file(h5)))
343  return retval;
344 
345  /* Close all open HDF5 objects within the file. */
346  if ((retval = nc4_rec_grp_HDF5_del(h5->root_grp)))
347  return retval;
348 
349  /* Release all intarnal lists and metadata associated with this
350  * file. All HDF5 objects have already been released. */
351  if ((retval = nc4_close_netcdf4_file(h5, abort, memio)))
352  return retval;
353 
354  return NC_NOERR;
355 }
356 
365 static void
366 dumpopenobjects(NC_FILE_INFO_T* h5)
367 {
368  NC_HDF5_FILE_INFO_T *hdf5_info;
369  int nobjs;
370 
371  assert(h5 && h5->format_file_info);
372  hdf5_info = (NC_HDF5_FILE_INFO_T *)h5->format_file_info;
373 
374  if(hdf5_info->hdfid <= 0)
375  return; /* File was never opened */
376 
377  nobjs = H5Fget_obj_count(hdf5_info->hdfid, H5F_OBJ_ALL);
378 
379  /* Apparently we can get an error even when nobjs == 0 */
380  if(nobjs < 0) {
381  return;
382  } else if(nobjs > 0) {
383  char msg[1024];
384  int logit = 0;
385  /* If the close doesn't work, probably there are still some HDF5
386  * objects open, which means there's a bug in the library. So
387  * print out some info on to help the poor programmer figure it
388  * out. */
389  snprintf(msg,sizeof(msg),"There are %d HDF5 objects open!", nobjs);
390 #ifdef LOGGING
391 #ifdef LOGOPEN
392  LOG((0, msg));
393  logit = 1;
394 #endif
395 #else
396  fprintf(stdout,"%s\n",msg);
397  logit = 0;
398 #endif
399  reportopenobjects(logit,hdf5_info->hdfid);
400  fflush(stderr);
401  }
402 
403  return;
404 }
405 
420 int
421 NC4_set_fill(int ncid, int fillmode, int *old_modep)
422 {
423  NC_FILE_INFO_T *nc4_info;
424  int retval;
425 
426  LOG((2, "%s: ncid 0x%x fillmode %d", __func__, ncid, fillmode));
427 
428  /* Get pointer to file info. */
429  if ((retval = nc4_find_grp_h5(ncid, NULL, &nc4_info)))
430  return retval;
431  assert(nc4_info);
432 
433  /* Trying to set fill on a read-only file? You sicken me! */
434  if (nc4_info->no_write)
435  return NC_EPERM;
436 
437  /* Did you pass me some weird fillmode? */
438  if (fillmode != NC_FILL && fillmode != NC_NOFILL)
439  return NC_EINVAL;
440 
441  /* If the user wants to know, tell him what the old mode was. */
442  if (old_modep)
443  *old_modep = nc4_info->fill_mode;
444 
445  nc4_info->fill_mode = fillmode;
446 
447  return NC_NOERR;
448 }
449 
459 int
460 NC4_redef(int ncid)
461 {
462  NC_FILE_INFO_T *nc4_info;
463  int retval;
464 
465  LOG((1, "%s: ncid 0x%x", __func__, ncid));
466 
467  /* Find this file's metadata. */
468  if ((retval = nc4_find_grp_h5(ncid, NULL, &nc4_info)))
469  return retval;
470  assert(nc4_info);
471 
472  /* If we're already in define mode, return an error. */
473  if (nc4_info->flags & NC_INDEF)
474  return NC_EINDEFINE;
475 
476  /* If the file is read-only, return an error. */
477  if (nc4_info->no_write)
478  return NC_EPERM;
479 
480  /* Set define mode. */
481  nc4_info->flags |= NC_INDEF;
482 
483  /* For nc_abort, we need to remember if we're in define mode as a
484  redef. */
485  nc4_info->redef = NC_TRUE;
486 
487  return NC_NOERR;
488 }
489 
503 int
504 NC4__enddef(int ncid, size_t h_minfree, size_t v_align,
505  size_t v_minfree, size_t r_align)
506 {
507  return NC4_enddef(ncid);
508 }
509 
521 static int
522 NC4_enddef(int ncid)
523 {
524  NC_FILE_INFO_T *nc4_info;
525  NC_GRP_INFO_T *grp;
526  NC_VAR_INFO_T *var;
527  int i;
528  int retval;
529 
530  LOG((1, "%s: ncid 0x%x", __func__, ncid));
531 
532  /* Find pointer to group and nc4_info. */
533  if ((retval = nc4_find_grp_h5(ncid, &grp, &nc4_info)))
534  return retval;
535 
536  /* When exiting define mode, mark all variable written. */
537  for (i = 0; i < ncindexsize(grp->vars); i++)
538  {
539  var = (NC_VAR_INFO_T *)ncindexith(grp->vars, i);
540  assert(var);
541  var->written_to = NC_TRUE;
542  }
543 
544  return nc4_enddef_netcdf4_file(nc4_info);
545 }
546 
558 int
559 NC4_sync(int ncid)
560 {
561  NC_FILE_INFO_T *nc4_info;
562  int retval;
563 
564  LOG((2, "%s: ncid 0x%x", __func__, ncid));
565 
566  if ((retval = nc4_find_grp_h5(ncid, NULL, &nc4_info)))
567  return retval;
568  assert(nc4_info);
569 
570  /* If we're in define mode, we can't sync. */
571  if (nc4_info->flags & NC_INDEF)
572  {
573  if (nc4_info->cmode & NC_CLASSIC_MODEL)
574  return NC_EINDEFINE;
575  if ((retval = NC4_enddef(ncid)))
576  return retval;
577  }
578 
579  return sync_netcdf4_file(nc4_info);
580 }
581 
595 int
596 NC4_abort(int ncid)
597 {
598  NC *nc;
599  NC_FILE_INFO_T *nc4_info;
600  int delete_file = 0;
601  char path[NC_MAX_NAME + 1];
602  int retval;
603 
604  LOG((2, "%s: ncid 0x%x", __func__, ncid));
605 
606  /* Find metadata for this file. */
607  if ((retval = nc4_find_nc_grp_h5(ncid, &nc, NULL, &nc4_info)))
608  return retval;
609  assert(nc4_info);
610 
611  /* If we're in define mode, but not redefing the file, delete it. */
612  if (nc4_info->flags & NC_INDEF && !nc4_info->redef)
613  {
614  delete_file++;
615  strncpy(path, nc->path, NC_MAX_NAME);
616  }
617 
618  /* Free any resources the netcdf-4 library has for this file's
619  * metadata. */
620  if ((retval = nc4_close_hdf5_file(nc4_info, 1, NULL)))
621  return retval;
622 
623  /* Delete the file, if we should. */
624  if (delete_file)
625  if (remove(path) < 0)
626  return NC_ECANTREMOVE;
627 
628  return NC_NOERR;
629 }
630 
640 int
641 NC4_close(int ncid, void* params)
642 {
643  NC_GRP_INFO_T *grp;
644  NC_FILE_INFO_T *h5;
645  int retval;
646  int inmemory;
647  NC_memio* memio = NULL;
648 
649  LOG((1, "%s: ncid 0x%x", __func__, ncid));
650 
651  /* Find our metadata for this file. */
652  if ((retval = nc4_find_grp_h5(ncid, &grp, &h5)))
653  return retval;
654 
655  assert(h5 && grp);
656 
657  /* This must be the root group. */
658  if (grp->parent)
659  return NC_EBADGRPID;
660 
661  inmemory = ((h5->cmode & NC_INMEMORY) == NC_INMEMORY);
662 
663  if(inmemory && params != NULL) {
664  memio = (NC_memio*)params;
665  }
666 
667  /* Call the nc4 close. */
668  if ((retval = nc4_close_hdf5_file(grp->nc4_info, 0, memio)))
669  return retval;
670 
671  return NC_NOERR;
672 }
673 
691 int
692 NC4_inq(int ncid, int *ndimsp, int *nvarsp, int *nattsp, int *unlimdimidp)
693 {
694  NC *nc;
695  NC_FILE_INFO_T *h5;
696  NC_GRP_INFO_T *grp;
697  int retval;
698  int i;
699 
700  LOG((2, "%s: ncid 0x%x", __func__, ncid));
701 
702  /* Find file metadata. */
703  if ((retval = nc4_find_nc_grp_h5(ncid, &nc, &grp, &h5)))
704  return retval;
705 
706  assert(h5 && grp && nc);
707 
708  /* Count the number of dims, vars, and global atts; need to iterate
709  * because of possible nulls. */
710  if (ndimsp)
711  {
712  *ndimsp = ncindexcount(grp->dim);
713  }
714  if (nvarsp)
715  {
716  *nvarsp = ncindexcount(grp->vars);
717  }
718  if (nattsp)
719  {
720  /* Do we need to read the atts? */
721  if (!grp->atts_read)
722  if ((retval = nc4_read_atts(grp, NULL)))
723  return retval;
724 
725  *nattsp = ncindexcount(grp->att);
726  }
727 
728  if (unlimdimidp)
729  {
730  /* Default, no unlimited dimension */
731  *unlimdimidp = -1;
732 
733  /* If there's more than one unlimited dim, which was not possible
734  with netcdf-3, then only the last unlimited one will be reported
735  back in xtendimp. */
736  /* Note that this code is inconsistent with nc_inq_unlimid() */
737  for(i=0;i<ncindexsize(grp->dim);i++) {
738  NC_DIM_INFO_T* d = (NC_DIM_INFO_T*)ncindexith(grp->dim,i);
739  if(d == NULL) continue;
740  if(d->unlimited) {
741  *unlimdimidp = d->hdr.id;
742  break;
743  }
744  }
745  }
746 
747  return NC_NOERR;
748 }
749 
759 int
760 nc4_enddef_netcdf4_file(NC_FILE_INFO_T *h5)
761 {
762  assert(h5);
763  LOG((3, "%s", __func__));
764 
765  /* If we're not in define mode, return an error. */
766  if (!(h5->flags & NC_INDEF))
767  return NC_ENOTINDEFINE;
768 
769  /* Turn define mode off. */
770  h5->flags ^= NC_INDEF;
771 
772  /* Redef mode needs to be tracked separately for nc_abort. */
773  h5->redef = NC_FALSE;
774 
775  return sync_netcdf4_file(h5);
776 }
#define NC_CLASSIC_MODEL
Enforce classic model on netCDF-4.
Definition: netcdf.h:138
#define NC_INMEMORY
Read from memory.
Definition: netcdf.h:161
#define NC_EHDFERR
Error at HDF5 layer.
Definition: netcdf.h:442
#define NC_ENOTINDEFINE
Operation not allowed in data mode.
Definition: netcdf.h:345
#define NC_EINDEFINE
Operation not allowed in define mode.
Definition: netcdf.h:354
#define NC_EINVAL
Invalid Argument.
Definition: netcdf.h:339
#define NC_EBADGRPID
Bad group ID.
Definition: netcdf.h:457
#define NC_NOFILL
Argument to nc_set_fill() to turn off filling of data.
Definition: netcdf.h:115
#define NC_MAX_NAME
Maximum for classic library.
Definition: netcdf.h:275
#define NC_ECANTREMOVE
Can't remove file.
Definition: netcdf.h:434
#define NC_EPERM
Write to read only.
Definition: netcdf.h:340
#define NC_NOERR
No Error.
Definition: netcdf.h:329
#define NC_FILL
Argument to nc_set_fill() to clear NC_NOFILL.
Definition: netcdf.h:114

Return to the Main Unidata NetCDF page.
Generated on Mon Nov 16 2020 02:07:55 for NetCDF. NetCDF is a Unidata library.