1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2  * Copyright by The HDF Group.                                               *
3  * Copyright by the Board of Trustees of the University of Illinois.         *
4  * All rights reserved.                                                      *
5  *                                                                           *
6  * This file is part of HDF5.  The full HDF5 copyright notice, including     *
7  * terms governing use, modification, and redistribution, is contained in    *
8  * the COPYING file, which can be found at the root of the source code       *
9  * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases.  *
10  * If you do not have access to either file, you may request a copy from     *
11  * help@hdfgroup.org.                                                        *
12  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
13 
14 #include "h5repack.h"
15 #include "h5diff.h"
16 #include "h5tools.h"
17 
18 
19 /*-------------------------------------------------------------------------
20  * local functions
21  *-------------------------------------------------------------------------
22  */
23 
24 static const char* MapIdToName(hid_t refobj_id,trav_table_t *travt);
25 static int copy_refs_attr(hid_t loc_in, hid_t loc_out, pack_opt_t *options,
26                           trav_table_t *travt, hid_t fidout);
27 static herr_t update_ref_value(hid_t obj_id, H5R_type_t ref_type, void *ref_in,
28         hid_t fid_out, void *ref_out, trav_table_t *travt);
29 
30 /*-------------------------------------------------------------------------
31  * Function: do_copy_refobjs
32  *
33  * Purpose:  duplicate all referenced HDF5 objects in the file
34  *           and create hard links
35  *
36  * Return:   0, ok, -1 no
37  *-------------------------------------------------------------------------
38  */
39 
do_copy_refobjs(hid_t fidin,hid_t fidout,trav_table_t * travt,pack_opt_t * options)40 int do_copy_refobjs(hid_t fidin,
41                     hid_t fidout,
42                     trav_table_t *travt,
43                     pack_opt_t *options) /* repack options */
44 {
45     int       ret_value = 0;          /*no need to LEAVE() on ERROR: HERR_INIT(int, SUCCEED) */
46     hid_t     grp_in = -1;            /* read group ID */
47     hid_t     grp_out = -1;           /* write group ID */
48     hid_t     dset_in = -1;           /* read dataset ID */
49     hid_t     dset_out = -1;          /* write dataset ID */
50     hid_t     type_in = -1;           /* named type ID */
51     hid_t     dcpl_id = -1;           /* dataset creation property list ID */
52     hid_t     space_id = -1;          /* space ID */
53     hid_t     ftype_id = -1;          /* file data type ID */
54     hid_t     mtype_id = -1;          /* memory data type ID */
55     size_t    msize;                  /* memory size of memory type */
56     hsize_t   nelmts;                 /* number of elements in dataset */
57     int       rank;                   /* rank of dataset */
58     hsize_t   dims[H5S_MAX_RANK];     /* dimensions of dataset */
59     unsigned int i, j;
60     int       k;
61     named_dt_t *named_dt_head = NULL; /* Pointer to the stack of named datatypes copied */
62 
63     /*-------------------------------------------------------------------------
64     * browse
65     *-------------------------------------------------------------------------
66     */
67     for(i = 0; i < travt->nobjs; i++) {
68         switch(travt->objs[i].type) {
69             /*-------------------------------------------------------------------------
70              * H5TRAV_TYPE_GROUP
71              *-------------------------------------------------------------------------
72              */
73             case H5TRAV_TYPE_GROUP:
74                 /*-------------------------------------------------------------------------
75                  * copy referenced objects in attributes
76                  *-------------------------------------------------------------------------
77                  */
78                 if((grp_out = H5Gopen2(fidout, travt->objs[i].name, H5P_DEFAULT)) < 0)
79                     HGOTO_ERROR(FAIL, H5E_tools_min_id_g, "H5Gopen2 failed");
80 
81                 if((grp_in = H5Gopen2(fidin, travt->objs[i].name, H5P_DEFAULT)) < 0)
82                     HGOTO_ERROR(FAIL, H5E_tools_min_id_g, "H5Gopen2 failed");
83 
84                 if(copy_refs_attr(grp_in, grp_out, options, travt, fidout) < 0)
85                     HGOTO_ERROR(FAIL, H5E_tools_min_id_g, "copy_refs_attr failed");
86 
87                 if(H5Gclose(grp_out) < 0)
88                     HGOTO_ERROR(FAIL, H5E_tools_min_id_g, "H5Gclose failed");
89                 if(H5Gclose(grp_in) < 0)
90                     HGOTO_ERROR(FAIL, H5E_tools_min_id_g, "H5Gclose failed");
91 
92                 /*-------------------------------------------------------------------------
93                  * check for hard links
94                  *-------------------------------------------------------------------------
95                  */
96                 if(travt->objs[i].nlinks)
97                     for(j = 0; j < travt->objs[i].nlinks; j++)
98                         H5Lcreate_hard(fidout, travt->objs[i].name, H5L_SAME_LOC, travt->objs[i].links[j].new_name, H5P_DEFAULT, H5P_DEFAULT);
99                 break;
100 
101             /*-------------------------------------------------------------------------
102              * H5TRAV_TYPE_DATASET
103              *-------------------------------------------------------------------------
104              */
105             case H5TRAV_TYPE_DATASET:
106                 if((dset_in = H5Dopen2(fidin, travt->objs[i].name, H5P_DEFAULT)) < 0)
107                     HGOTO_ERROR(FAIL, H5E_tools_min_id_g, "H5Dopen2 failed");
108                 if((space_id = H5Dget_space(dset_in)) < 0)
109                     HGOTO_ERROR(FAIL, H5E_tools_min_id_g, "H5Dget_space failed");
110                 if((ftype_id = H5Dget_type(dset_in)) < 0)
111                     HGOTO_ERROR(FAIL, H5E_tools_min_id_g, "H5Dget_type failed");
112                 if((dcpl_id = H5Dget_create_plist(dset_in)) < 0)
113                     HGOTO_ERROR(FAIL, H5E_tools_min_id_g, "H5Dget_create_plist failed");
114                 if((rank = H5Sget_simple_extent_ndims(space_id)) < 0)
115                     HGOTO_ERROR(FAIL, H5E_tools_min_id_g, "H5Sget_simple_extent_ndims failed");
116                 if(H5Sget_simple_extent_dims(space_id, dims, NULL) < 0)
117                     HGOTO_ERROR(FAIL, H5E_tools_min_id_g, "H5Sget_simple_extent_dims failed");
118                 nelmts = 1;
119                 for(k = 0; k < rank; k++)
120                     nelmts *= dims[k];
121 
122                 if((mtype_id = H5Tget_native_type(ftype_id, H5T_DIR_DEFAULT)) < 0)
123                     HGOTO_ERROR(FAIL, H5E_tools_min_id_g, "H5Tget_native_type failed");
124 
125                 if((msize = H5Tget_size(mtype_id)) == 0)
126                     HGOTO_ERROR(FAIL, H5E_tools_min_id_g, "H5Tget_size failed");
127 
128                 /*-------------------------------------------------------------------------
129                  * check if the dataset creation property list has filters that
130                  * are not registered in the current configuration
131                  * 1) the external filters GZIP and SZIP might not be available
132                  * 2) the internal filters might be turned off
133                  *-------------------------------------------------------------------------
134                  */
135                 if(h5tools_canreadf(NULL, dcpl_id) == 1) {
136                     /*-------------------------------------------------------------------------
137                      * test for a valid output dataset
138                      *-------------------------------------------------------------------------
139                      */
140                     dset_out = FAIL;
141 
142                     /*-------------------------------------------------------------------------
143                      * object references are a special case
144                      * we cannot just copy the buffers, but instead we recreate the reference
145                      *-------------------------------------------------------------------------
146                      */
147                     if(H5Tequal(mtype_id, H5T_STD_REF_OBJ)) {
148                         hid_t            refobj_id = -1;
149                         hobj_ref_t       *refbuf = NULL; /* buffer for object references */
150                         hobj_ref_t       *buf = NULL;
151                         const char*      refname;
152                         unsigned         u;
153 
154                         /*-------------------------------------------------------------------------
155                          * read to memory
156                          *-------------------------------------------------------------------------
157                          */
158                         if(nelmts) {
159                             buf = (hobj_ref_t *)HDmalloc((unsigned)(nelmts * msize));
160                             if(buf==NULL) {
161                                 printf("cannot read into memory\n" );
162                                 HGOTO_ERROR(FAIL, H5E_tools_min_id_g, "HDmalloc failed");
163                             } /* end if */
164                             if(H5Dread(dset_in, mtype_id, H5S_ALL, H5S_ALL, H5P_DEFAULT, buf) < 0)
165                                 HGOTO_ERROR(FAIL, H5E_tools_min_id_g, "H5Dread failed");
166 
167                             refbuf = (hobj_ref_t*) HDcalloc((unsigned)nelmts, msize);
168                             if(refbuf == NULL){
169                                 printf("cannot allocate memory\n" );
170                                 HGOTO_ERROR(FAIL, H5E_tools_min_id_g, "HDcalloc failed");
171                             } /* end if */
172                             for(u = 0; u < nelmts; u++) {
173                                 H5E_BEGIN_TRY {
174                                     if((refobj_id = H5Rdereference(dset_in, H5R_OBJECT, &buf[u])) < 0)
175                                         continue;
176                                 } H5E_END_TRY;
177 
178                                 /* get the name. a valid name could only occur
179                                  * in the second traversal of the file
180                                  */
181                                 if((refname = MapIdToName(refobj_id, travt)) != NULL) {
182                                     /* create the reference, -1 parameter for objects */
183                                     if(H5Rcreate(&refbuf[u], fidout, refname, H5R_OBJECT, (hid_t)-1) < 0)
184                                         HGOTO_ERROR(FAIL, H5E_tools_min_id_g, "H5Rcreate failed");
185                                     if(options->verbose) {
186                                         printf(FORMAT_OBJ,"dset",travt->objs[i].name );
187                                         printf("object <%s> object reference created to <%s>\n",
188                                             travt->objs[i].name,
189                                             refname);
190                                     }
191                                 } /*refname*/
192                                 if (H5Oclose(refobj_id) < 0)
193                                     H5TOOLS_INFO(H5E_tools_min_id_g, "H5Oclose refob failed");
194                             } /* u */
195                         } /*nelmts*/
196 
197                         /*-------------------------------------------------------------------------
198                          * create/write dataset/close
199                          *-------------------------------------------------------------------------
200                          */
201                         if((dset_out = H5Dcreate2(fidout, travt->objs[i].name, mtype_id, space_id, H5P_DEFAULT, dcpl_id, H5P_DEFAULT)) < 0)
202                             HGOTO_ERROR(FAIL, H5E_tools_min_id_g, "H5Dcreate2 failed");
203                         if(nelmts)
204                             if(H5Dwrite(dset_out, mtype_id, H5S_ALL, H5S_ALL, H5P_DEFAULT, refbuf) < 0)
205                                 HGOTO_ERROR(FAIL, H5E_tools_min_id_g, "H5Dwrite failed");
206 
207                         if(buf)
208                             HDfree(buf);
209                         if(refbuf)
210                             HDfree(refbuf);
211 
212                        /*------------------------------------------------------
213                         * copy attrs
214                         *----------------------------------------------------*/
215                         if(copy_attr(dset_in, dset_out, &named_dt_head, travt, options) < 0)
216                             HGOTO_ERROR(FAIL, H5E_tools_min_id_g, "copy_attr failed");
217                     } /*H5T_STD_REF_OBJ*/
218 
219                     /*-------------------------------------------------------------------------
220                      * dataset region references
221                      *-------------------------------------------------------------------------
222                      */
223                     else if(H5Tequal(mtype_id, H5T_STD_REF_DSETREG)) {
224                         hid_t            refobj_id = -1;
225                         hdset_reg_ref_t  *refbuf = NULL; /* input buffer for region references */
226                         hdset_reg_ref_t  *buf = NULL;    /* output buffer */
227                         const char*      refname;
228                         unsigned         u;
229 
230                         /*-------------------------------------------------------------------------
231                          * read input to memory
232                          *-------------------------------------------------------------------------
233                          */
234                         if(nelmts) {
235                             buf = (hdset_reg_ref_t *)HDmalloc((unsigned)(nelmts * msize));
236                             if(buf == NULL) {
237                                 printf("cannot read into memory\n");
238                                 HGOTO_ERROR(FAIL, H5E_tools_min_id_g, "HDmalloc failed");
239                             } /* end if */
240                             if(H5Dread(dset_in, mtype_id, H5S_ALL, H5S_ALL, H5P_DEFAULT, buf) < 0)
241                                 HGOTO_ERROR(FAIL, H5E_tools_min_id_g, "H5Dread failed");
242 
243                             /*-------------------------------------------------------------------------
244                              * create output
245                              *-------------------------------------------------------------------------
246                              */
247                             refbuf = (hdset_reg_ref_t *)HDcalloc(sizeof(hdset_reg_ref_t), (size_t)nelmts); /*init to zero */
248                             if(refbuf == NULL) {
249                                 printf("cannot allocate memory\n");
250                                 HGOTO_ERROR(FAIL, H5E_tools_min_id_g, "HDcalloc failed");
251                             } /* end if */
252 
253                             for(u = 0; u < nelmts; u++) {
254                                 H5E_BEGIN_TRY {
255                                     if((refobj_id = H5Rdereference(dset_in, H5R_DATASET_REGION, &buf[u])) < 0)
256                                         continue;
257                                 } H5E_END_TRY;
258 
259                                 /* get the name. a valid name could only occur
260                                  * in the second traversal of the file
261                                  */
262                                 if((refname = MapIdToName(refobj_id, travt)) != NULL) {
263                                     hid_t region_id = -1;    /* region id of the referenced dataset */
264 
265                                     if((region_id = H5Rget_region(dset_in, H5R_DATASET_REGION, &buf[u])) < 0)
266                                         HGOTO_ERROR(FAIL, H5E_tools_min_id_g, "H5Rget_region failed");
267 
268                                     /* create the reference, we need the space_id */
269                                     if(H5Rcreate(&refbuf[u], fidout, refname, H5R_DATASET_REGION, region_id) < 0)
270                                         HGOTO_ERROR(FAIL, H5E_tools_min_id_g, "H5Rcreate failed");
271                                     if(H5Sclose(region_id) < 0)
272                                         HGOTO_ERROR(FAIL, H5E_tools_min_id_g, "H5Sclose failed");
273                                     if(options->verbose) {
274                                         printf(FORMAT_OBJ,"dset",travt->objs[i].name );
275                                         printf("object <%s> region reference created to <%s>\n",
276                                             travt->objs[i].name,
277                                             refname);
278                                     }
279                                 } /*refname*/
280                                 if (H5Oclose(refobj_id) < 0)
281                                     H5TOOLS_INFO(H5E_tools_min_id_g, "H5Oclose refobj_id failed");
282                             } /* u */
283                         } /*nelmts*/
284 
285                         /*-------------------------------------------------------------------------
286                          * create/write dataset/close
287                          *-------------------------------------------------------------------------
288                          */
289                         if((dset_out = H5Dcreate2(fidout, travt->objs[i].name, mtype_id, space_id, H5P_DEFAULT, dcpl_id, H5P_DEFAULT)) < 0)
290                             HGOTO_ERROR(FAIL, H5E_tools_min_id_g, "H5Dcreate2 failed");
291                         if(nelmts)
292                             if(H5Dwrite(dset_out, mtype_id, H5S_ALL, H5S_ALL, H5P_DEFAULT, refbuf) < 0)
293                                 HGOTO_ERROR(FAIL, H5E_tools_min_id_g, "H5Dwrite failed");
294 
295                         if(buf)
296                             HDfree(buf);
297                         if(refbuf)
298                             HDfree(refbuf);
299 
300                        /*-----------------------------------------------------
301                         * copy attrs
302                         *----------------------------------------------------*/
303                         if(copy_attr(dset_in, dset_out, &named_dt_head, travt, options) < 0)
304                             HGOTO_ERROR(FAIL, H5E_tools_min_id_g, "copy_attr failed");
305                     } /* H5T_STD_REF_DSETREG */
306                     /*-------------------------------------------------------------------------
307                      * not references, open previously created object in 1st traversal
308                      *-------------------------------------------------------------------------
309                      */
310                     else {
311                         if((dset_out = H5Dopen2(fidout, travt->objs[i].name, H5P_DEFAULT)) < 0)
312                             HGOTO_ERROR(FAIL, H5E_tools_min_id_g, "H5Dopen2 failed");
313                     } /* end else */
314 
315                     /*-------------------------------------------------------------------------
316                      * copy referenced objects in attributes
317                      *-------------------------------------------------------------------------
318                      */
319                     if(copy_refs_attr(dset_in, dset_out, options, travt, fidout) < 0)
320                         HGOTO_ERROR(FAIL, H5E_tools_min_id_g, "copy_refs_attr failed");
321 
322                     /*-------------------------------------------------------------------------
323                      * check for hard links
324                      *-------------------------------------------------------------------------
325                      */
326                     if(travt->objs[i].nlinks)
327                         for(j = 0; j < travt->objs[i].nlinks; j++)
328                             H5Lcreate_hard(fidout, travt->objs[i].name, H5L_SAME_LOC, travt->objs[i].links[j].new_name, H5P_DEFAULT, H5P_DEFAULT);
329 
330                     if(H5Dclose(dset_out) < 0)
331                         HGOTO_ERROR(FAIL, H5E_tools_min_id_g, "H5Dclose failed");
332                 } /*can_read*/
333 
334                 /*-------------------------------------------------------------------------
335                  * close
336                  *-------------------------------------------------------------------------
337                  */
338                 if(H5Tclose(ftype_id) < 0)
339                     HGOTO_ERROR(FAIL, H5E_tools_min_id_g, "H5Tclose failed");
340                 if(H5Tclose(mtype_id) < 0)
341                     HGOTO_ERROR(FAIL, H5E_tools_min_id_g, "H5Tclose failed");
342                 if(H5Pclose(dcpl_id) < 0)
343                     HGOTO_ERROR(FAIL, H5E_tools_min_id_g, "H5Pclose failed");
344                 if(H5Sclose(space_id) < 0)
345                     HGOTO_ERROR(FAIL, H5E_tools_min_id_g, "H5Sclose failed");
346                 if(H5Dclose(dset_in) < 0)
347                     HGOTO_ERROR(FAIL, H5E_tools_min_id_g, "H5Dclose failed");
348                 break;
349 
350             /*-------------------------------------------------------------------------
351              * H5TRAV_TYPE_NAMED_DATATYPE
352              *-------------------------------------------------------------------------
353              */
354             case H5TRAV_TYPE_NAMED_DATATYPE:
355                 if((type_in = H5Topen2(fidin, travt->objs[i].name, H5P_DEFAULT)) < 0)
356                     HGOTO_ERROR(FAIL, H5E_tools_min_id_g, "H5Topen2 failed");
357                 if(H5Tclose(type_in) < 0)
358                     HGOTO_ERROR(FAIL, H5E_tools_min_id_g, "H5Tclose failed");
359                 break;
360 
361             /*-------------------------------------------------------------------------
362              * H5TRAV_TYPE_LINK
363              *-------------------------------------------------------------------------
364              */
365             case H5TRAV_TYPE_LINK:
366                 /*nothing to do */
367                 break;
368 
369             case H5TRAV_TYPE_UNKNOWN:
370             case H5TRAV_TYPE_UDLINK:
371                 HGOTO_ERROR(FAIL, H5E_tools_min_id_g, "H5TRAV invalid type");
372 
373             default:
374                 break;
375         } /* end switch */
376     } /* end for */
377 
378     /* Finalize (link) the stack of named datatypes (if any)
379      * This function is paired with copy_named_datatype() which is called
380      * in copy_attr(), so need to free.
381      */
382     if (named_datatype_free(&named_dt_head, 0) < 0)
383         H5TOOLS_INFO(H5E_tools_min_id_g, "named_datatype_free failed");
384 
385     return ret_value;
386 
387 done:
388     H5E_BEGIN_TRY {
389         H5Gclose(grp_in);
390         H5Gclose(grp_out);
391         H5Pclose(dcpl_id);
392         H5Sclose(space_id);
393         H5Dclose(dset_in);
394         H5Dclose(dset_out);
395         H5Tclose(ftype_id);
396         H5Tclose(mtype_id);
397         H5Tclose(type_in);
398         named_datatype_free(&named_dt_head, 1);
399     } H5E_END_TRY;
400 
401     return ret_value;
402 }
403 
404 
405 /*-------------------------------------------------------------------------
406  * Function: copy_refs_attr
407  *
408  * Purpose:  duplicate all referenced HDF5 located in attributes
409  *           relative to LOC_IN, which is obtained either from
410  *           loc_id = H5Gopen2(fid, name, H5P_DEFAULT);
411  *           loc_id = H5Dopen2(fid, name, H5P_DEFAULT);
412  *           loc_id = H5Topen2(fid, name, H5P_DEFAULT);
413  *
414  * Return:   0, ok, -1 no
415  *
416  * Modified:
417  *           Update values of references(object and region) for the following types:
418  *               1) References,
419  *               2) ARRAY of reference,
420  *               3) VLEN of references.
421  *               4) COMPOUND of references.
422  *           This function does not handle references in other complicated structures,
423  *           such as references in nested compound datatypes.
424  *-------------------------------------------------------------------------
425  */
426 
copy_refs_attr(hid_t loc_in,hid_t loc_out,pack_opt_t * options,trav_table_t * travt,hid_t fidout)427 static int copy_refs_attr(hid_t loc_in,
428                           hid_t loc_out,
429                           pack_opt_t *options,
430                           trav_table_t *travt,
431                           hid_t fidout)         /* for saving references */
432 {
433     int         ret_value = 0;     /*no need to LEAVE() on ERROR: HERR_INIT(int, SUCCEED) */
434     hid_t       attr_id = -1;      /* attr ID */
435     hid_t       attr_out = -1;     /* attr ID */
436     hid_t       space_id = -1;     /* space ID */
437     hid_t       ftype_id = -1;     /* file data type ID */
438     hid_t       mtype_id = -1;     /* memory data type ID */
439     size_t      msize;             /* memory size of type */
440     hsize_t     nelmts;            /* number of elements in dataset */
441     hsize_t     dims[H5S_MAX_RANK];/* dimensions of dataset */
442     char        name[255];
443     H5O_info_t  oinfo;             /* Object info */
444     unsigned    u, i, j;
445     int         rank;
446     H5T_class_t type_class = -1;
447     hbool_t     is_ref = 0,
448                 is_ref_vlen = 0,
449                 is_ref_array = 0,
450                 is_ref_comp = 0;
451     void       *refbuf = NULL;
452     void       *buf = NULL;
453     const char *refname = NULL;
454     unsigned   *ref_comp_index = NULL;
455     size_t     *ref_comp_size = NULL;
456     int         ref_comp_field_n = 0;
457 
458 
459     if(H5Oget_info(loc_in, &oinfo) < 0)
460         HGOTO_ERROR(FAIL, H5E_tools_min_id_g, "H5Oget_info failed");
461 
462     for(u = 0; u < (unsigned)oinfo.num_attrs; u++) {
463         is_ref = is_ref_vlen = is_ref_array = is_ref_comp = 0;
464 
465         /* open attribute */
466         if((attr_id = H5Aopen_by_idx(loc_in, ".", H5_INDEX_CRT_ORDER, H5_ITER_INC, (hsize_t)u, H5P_DEFAULT, H5P_DEFAULT)) < 0)
467             HGOTO_ERROR(FAIL, H5E_tools_min_id_g, "H5Aopen_by_idx failed");
468 
469         /* get the file datatype  */
470         if((ftype_id = H5Aget_type(attr_id)) < 0)
471             HGOTO_ERROR(FAIL, H5E_tools_min_id_g, "H5Aget_type failed");
472 
473         type_class = H5Tget_class(ftype_id);
474 
475         if((mtype_id = H5Tget_native_type(ftype_id, H5T_DIR_DEFAULT)) < 0)
476             HGOTO_ERROR(FAIL, H5E_tools_min_id_g, "H5Tget_native_type failed");
477 
478         if((msize = H5Tget_size(mtype_id)) == 0)
479             HGOTO_ERROR(FAIL, H5E_tools_min_id_g, "H5Tget_size failed");
480 
481         is_ref = (type_class == H5T_REFERENCE);
482 
483         if(type_class == H5T_VLEN ) {
484             hid_t base_type = H5Tget_super(ftype_id);
485 
486             is_ref_vlen = (H5Tget_class(base_type) == H5T_REFERENCE);
487             msize = H5Tget_size(base_type);
488             if (H5Tclose(base_type) < 0)
489                 H5TOOLS_INFO(H5E_tools_min_id_g, "H5Tclose base_type failed");
490         }
491         else if(type_class == H5T_ARRAY ) {
492             hid_t base_type = H5Tget_super(ftype_id);
493 
494             is_ref_array = (H5Tget_class(base_type) == H5T_REFERENCE);
495             msize = H5Tget_size(base_type);
496             if (H5Tclose(base_type) < 0)
497                 H5TOOLS_INFO(H5E_tools_min_id_g, "H5Tclose base_type failed");
498         }
499         else if(type_class == H5T_COMPOUND) {
500             int nmembers = H5Tget_nmembers(ftype_id) ;
501 
502             if (nmembers < 1)
503                 HGOTO_ERROR(FAIL, H5E_tools_min_id_g, "H5Tget_nmembers failed");
504 
505             ref_comp_index = (unsigned *)HDmalloc((size_t)nmembers*sizeof(unsigned));
506             ref_comp_size = (size_t *)HDmalloc((size_t)nmembers*sizeof(ref_comp_size));
507             ref_comp_field_n = 0;
508 
509             for (i=0; i<(unsigned)nmembers; i++) {
510                 hid_t mtid = H5Tget_member_type(ftype_id, i);
511 
512                 if ((H5Tget_class(mtid) == H5T_REFERENCE)) {
513                     ref_comp_index[ref_comp_field_n] = i;
514                     ref_comp_size[ref_comp_field_n] = H5Tget_size(mtid);
515                     ref_comp_field_n++;
516                 }
517                 if (H5Tclose(mtid) < 0)
518                     H5TOOLS_INFO(H5E_tools_min_id_g, "H5Tclose mtid failed");
519             }
520 
521             /* if compound don't contain reference type member, free the above
522              * mallocs. Otherwise there can be memory leaks by the 'continue'
523              * statement below. */
524             if (!ref_comp_field_n) {
525                 if (ref_comp_index) {
526                     HDfree(ref_comp_index);
527                     ref_comp_index = NULL;
528                 }
529 
530                 if (ref_comp_size) {
531                     HDfree(ref_comp_size);
532                     ref_comp_size = NULL;
533                 }
534             }
535         }
536 
537         is_ref_comp = (ref_comp_field_n > 0);
538 
539         if (!(is_ref || is_ref_vlen || is_ref_array || is_ref_comp)) {
540             if (H5Tclose(mtype_id) < 0)
541                 H5TOOLS_INFO(H5E_tools_min_id_g, "H5Tclose mtype_id failed");
542             if (H5Tclose(ftype_id) < 0)
543                 H5TOOLS_INFO(H5E_tools_min_id_g, "H5Tclose ftype_id failed");
544             if (H5Aclose(attr_id) < 0)
545                 H5TOOLS_INFO(H5E_tools_min_id_g, "H5Aclose attr_id failed");
546             continue;
547         }
548 
549         /* get name */
550         if(H5Aget_name(attr_id, 255, name) < 0)
551             HGOTO_ERROR(FAIL, H5E_tools_min_id_g, "H5Aget_name failed");
552 
553         /* get the dataspace handle  */
554         if((space_id = H5Aget_space(attr_id)) < 0)
555             HGOTO_ERROR(FAIL, H5E_tools_min_id_g, "H5Aget_space failed");
556 
557         /* get dimensions  */
558         if((rank = H5Sget_simple_extent_dims(space_id, dims, NULL)) < 0)
559             HGOTO_ERROR(FAIL, H5E_tools_min_id_g, "H5Sget_simple_extent_dims failed");
560 
561 
562         /*-------------------------------------------------------------------------
563         * elements
564         *-------------------------------------------------------------------------
565         */
566         nelmts = 1;
567         for(j = 0; j < (unsigned)rank; j++)
568             nelmts *= dims[j];
569 
570         if (is_ref_array) {
571             unsigned  array_rank = 0;
572             hsize_t   array_size = 1;
573             hsize_t array_dims[H5S_MAX_RANK];
574             hid_t base_type = H5Tget_super(ftype_id);
575 
576             msize = H5Tget_size(base_type);
577             if (H5Tclose(base_type) < 0)
578                 H5TOOLS_INFO(H5E_tools_min_id_g, "H5Tclose base_type failed");
579 
580             array_rank = (unsigned)H5Tget_array_ndims(mtype_id);
581             H5Tget_array_dims2(mtype_id, array_dims);
582             for(j = 0; j <array_rank; j++)
583                 array_size *= array_dims[j];
584             nelmts *= array_size;
585         }
586 
587         if((attr_out = H5Acreate2(loc_out, name, ftype_id, space_id, H5P_DEFAULT, H5P_DEFAULT)) < 0)
588             HGOTO_ERROR(FAIL, H5E_tools_min_id_g, "H5Acreate2 failed");
589 
590         if (nelmts>0) {
591             /* handle object references */
592             if((is_ref || is_ref_array) && (H5R_OBJ_REF_BUF_SIZE==msize)) {
593                 buf = (hobj_ref_t *)HDmalloc((unsigned)(nelmts * msize));
594                 if(buf == NULL) {
595                     printf("cannot read into memory\n");
596                     HGOTO_ERROR(FAIL, H5E_tools_min_id_g, "HDmalloc failed");
597                 } /* end if */
598                 if(H5Aread(attr_id, mtype_id, buf) < 0)
599                     HGOTO_ERROR(FAIL, H5E_tools_min_id_g, "H5Aread failed");
600 
601                 refbuf = (hobj_ref_t *)HDcalloc((unsigned)nelmts, msize);
602                 if(refbuf == NULL) {
603                     printf("cannot allocate memory\n");
604                     HGOTO_ERROR(FAIL, H5E_tools_min_id_g, "HDcalloc failed");
605                 } /* end if */
606 
607                 for(i = 0; i < (unsigned)nelmts; i++) {
608                     if (update_ref_value(attr_id, H5R_OBJECT, &((hobj_ref_t *)buf)[i], fidout, &((hobj_ref_t *)refbuf)[i], travt)<0)
609                         continue;
610                     if(options->verbose)
611                         printf("object <%s> reference created to <%s>\n", name, refname);
612                 } /* i */
613             } /* H5T_STD_REF_OBJ */
614             /* handle region references */
615             else if((is_ref || is_ref_array) && (H5R_DSET_REG_REF_BUF_SIZE == msize)) {
616                 buf = (hdset_reg_ref_t *)HDmalloc((unsigned)(nelmts * msize));
617 
618                 if(buf == NULL) {
619                     printf( "cannot read into memory\n" );
620                     HGOTO_ERROR(FAIL, H5E_tools_min_id_g, "HDmalloc failed");
621                 } /* end if */
622                 if(H5Aread(attr_id, mtype_id, buf) < 0)
623                     HGOTO_ERROR(FAIL, H5E_tools_min_id_g, "H5Aread failed");
624 
625                 /*-------------------------------------------------------------------------
626                  * create output
627                  *-------------------------------------------------------------------------
628                  */
629                 refbuf = (hdset_reg_ref_t *)HDcalloc(sizeof(hdset_reg_ref_t), (size_t)nelmts); /*init to zero */
630                 if(refbuf == NULL) {
631                     printf( "cannot allocate memory\n" );
632                     HGOTO_ERROR(FAIL, H5E_tools_min_id_g, "HDcalloc failed");
633                 } /* end if */
634 
635                 for(i = 0; i < (unsigned)nelmts; i++) {
636                     if (update_ref_value(attr_id, H5R_DATASET_REGION, &((hdset_reg_ref_t *)buf)[i], fidout, &((hdset_reg_ref_t *)refbuf)[i], travt)<0)
637                         continue;
638                     if(options->verbose)
639                         printf("object <%s> region reference created to <%s>\n", name, refname);
640                 }
641             } /* H5T_STD_REF_DSETREG */
642             else if (is_ref_vlen) {
643                 /* handle VLEN of references */
644 
645                 buf = (hvl_t *)HDmalloc((unsigned)(nelmts * sizeof(hvl_t)));
646                 refbuf = buf; /* reuse the read buffer for write */
647 
648                 if(buf == NULL) {
649                     printf( "cannot read into memory\n" );
650                     HGOTO_ERROR(FAIL, H5E_tools_min_id_g, "HDmalloc failed");
651                 } /* end if */
652 
653                 if(H5Aread(attr_id, mtype_id, buf) < 0)
654                     HGOTO_ERROR(FAIL, H5E_tools_min_id_g, "H5Aread failed");
655 
656                 if (H5R_OBJ_REF_BUF_SIZE==msize) {
657                     hobj_ref_t ref_out;
658 
659                     for (i=0; i<(unsigned)nelmts; i++) {
660                         hobj_ref_t *ptr = (hobj_ref_t *)((hvl_t *)buf)[i].p;
661 
662                         for (j=0; j<((hvl_t *)buf)[i].len; j++ ) {
663                             if (update_ref_value(attr_id, H5R_OBJECT, &(ptr[j]), fidout, &ref_out, travt)<0)
664                                 continue;
665                             HDmemcpy(&(ptr[j]), &ref_out, msize);
666                         }
667                     }  /* for (i=0; i<nelems; i++) */
668                 }
669                 else if (H5R_DSET_REG_REF_BUF_SIZE == msize) {
670                     hdset_reg_ref_t ref_out;
671 
672                     for (i=0; i<(unsigned)nelmts; i++) {
673                         hdset_reg_ref_t *ptr = (hdset_reg_ref_t *)((hvl_t *)buf)[i].p;
674 
675                         for (j=0; j<((hvl_t *)buf)[i].len; j++ ) {
676                             if (update_ref_value(attr_id, H5R_DATASET_REGION, &(ptr[j]), fidout, &ref_out, travt)<0)
677                                 continue;
678                             HDmemcpy(&(ptr[j]), &ref_out, msize);
679                         }
680                     }  /* for (i=0; i<nelems; i++) */
681                 }
682             } /* else if (is_ref_vlen) */
683             else if (is_ref_comp) {
684                 /* handle ref fields in a compound */
685 
686                 buf = HDmalloc((unsigned)(nelmts * msize));
687                 refbuf = buf; /* reuse the read buffer for write */
688 
689                 if(buf == NULL) {
690                     printf( "cannot read into memory\n" );
691                     HGOTO_ERROR(FAIL, H5E_tools_min_id_g, "HDmalloc failed");
692                 } /* end if */
693 
694                 if(H5Aread(attr_id, mtype_id, buf) < 0)
695                     HGOTO_ERROR(FAIL, H5E_tools_min_id_g, "H5Aread failed");
696 
697                 for (i=0; i<(unsigned)nelmts; i++) {
698                     for (j=0; j<(unsigned)ref_comp_field_n; j++) {
699                         if (ref_comp_size[j] == H5R_OBJ_REF_BUF_SIZE) {
700                             size_t idx = (i * msize) + H5Tget_member_offset(mtype_id, ref_comp_index[j]);
701                             hobj_ref_t ref_out;
702 
703                             if (update_ref_value(attr_id, H5R_OBJECT, (hobj_ref_t *)(((char *)buf)+idx), fidout, &ref_out, travt)<0)
704                                 continue;
705                             HDmemcpy(((char *)buf)+idx, &ref_out, ref_comp_size[j]);
706                         } /* if */
707                         else if (ref_comp_size[j] == H5R_DSET_REG_REF_BUF_SIZE) {
708                             size_t idx = i * msize + H5Tget_member_offset(mtype_id, ref_comp_index[j]);
709                             hdset_reg_ref_t ref_out;
710 
711                             if (update_ref_value(attr_id, H5R_DATASET_REGION, (hdset_reg_ref_t *)(((char *)buf)+idx), fidout, &ref_out, travt)<0)
712                                 continue;
713                             HDmemcpy(((char *)buf)+idx, &ref_out, ref_comp_size[j]);
714                         } /* else if */
715                     } /* j */
716                 } /* i */
717             } /* else if (is_ref_comp) */
718 
719             if(H5Awrite(attr_out, mtype_id, refbuf) < 0)
720                 HGOTO_ERROR(FAIL, H5E_tools_min_id_g, "H5Awrite failed");
721 
722             if (is_ref_vlen && buf)
723                 H5Dvlen_reclaim (mtype_id, space_id, H5P_DEFAULT, buf);
724         } /* if (nelmts) */
725 
726         if (refbuf == buf)
727             refbuf = NULL; /* set it to NULL to avoid double free since buf and refbuf are the same. */
728 
729         if(buf) {
730             HDfree(buf);
731             buf = NULL;
732         }
733 
734         if(refbuf) {
735             HDfree(refbuf);
736             refbuf = NULL;
737         }
738 
739         if (ref_comp_index) {
740             HDfree(ref_comp_index);
741             ref_comp_index = NULL;
742         }
743 
744         if (ref_comp_size) {
745             HDfree(ref_comp_size);
746             ref_comp_size = NULL;
747         }
748 
749         if(H5Aclose(attr_out) < 0)
750             HGOTO_ERROR(FAIL, H5E_tools_min_id_g, "H5Aclose failed");
751 
752         /*-------------------------------------------------------------------------
753         * close
754         *-------------------------------------------------------------------------
755         */
756         if(H5Tclose(ftype_id) < 0)
757             HGOTO_ERROR(FAIL, H5E_tools_min_id_g, "H5Tclose failed");
758         if(H5Tclose(mtype_id) < 0)
759             HGOTO_ERROR(FAIL, H5E_tools_min_id_g, "H5Tclose failed");
760         if(H5Sclose(space_id) < 0)
761             HGOTO_ERROR(FAIL, H5E_tools_min_id_g, "H5Sclose failed");
762         if(H5Aclose(attr_id) < 0)
763             HGOTO_ERROR(FAIL, H5E_tools_min_id_g, "H5Aclose failed");
764     } /* for(u = 0; u < (unsigned)oinfo.num_attrs; u++) */
765 
766 done:
767     if(refbuf)
768         HDfree(refbuf);
769     if(buf)
770         HDfree(buf);
771 
772     if (ref_comp_index)
773         HDfree(ref_comp_index);
774 
775     if (ref_comp_size)
776         HDfree(ref_comp_size);
777 
778     H5E_BEGIN_TRY {
779         H5Tclose(ftype_id);
780         H5Tclose(mtype_id);
781         H5Sclose(space_id);
782         H5Aclose(attr_id);
783         H5Aclose(attr_out);
784     } H5E_END_TRY;
785 
786     return ret_value;
787 }
788 
789 /*-------------------------------------------------------------------------
790  * Function:    MapIdToName
791  *
792  * Purpose:     map a ID from a reference to a dataset name
793  *
794  *-------------------------------------------------------------------------
795  */
796 static const char*
MapIdToName(hid_t refobj_id,trav_table_t * travt)797 MapIdToName(hid_t refobj_id, trav_table_t *travt)
798 {
799     unsigned int u;
800     const char   *ret = NULL;
801 
802     /* linear search */
803     for(u = 0; u < travt->nobjs; u++) {
804         if(travt->objs[u].type == (h5trav_type_t)H5O_TYPE_DATASET ||
805                 travt->objs[u].type == (h5trav_type_t)H5O_TYPE_GROUP ||
806                 travt->objs[u].type == (h5trav_type_t)H5O_TYPE_NAMED_DATATYPE) {
807             H5O_info_t   ref_oinfo;     /* Stat for the refobj id */
808 
809             /* obtain information to identify the referenced object uniquely */
810             if(H5Oget_info(refobj_id, &ref_oinfo) < 0)
811                 goto out;
812 
813             if(ref_oinfo.addr == travt->objs[u].objno) {
814                 ret = travt->objs[u].name;
815                 goto out;
816             } /* end if */
817         }  /* end if */
818     } /* u */
819 
820 out:
821     return ret;
822 }
823 
824 /*-------------------------------------------------------------------------
825  * Function:    Update_Ref_value
826  *
827  * Purpose:     Update a reference value
828  *-------------------------------------------------------------------------
829  */
update_ref_value(hid_t obj_id,H5R_type_t ref_type,void * ref_in,hid_t fid_out,void * ref_out,trav_table_t * travt)830 static herr_t update_ref_value(hid_t obj_id, H5R_type_t ref_type, void *ref_in,
831         hid_t fid_out, void *ref_out, trav_table_t *travt)
832 {
833     int         ret_value = 0;   /*no need to LEAVE() on ERROR: HERR_INIT(int, SUCCEED) */
834     const char *ref_obj_name;
835     hid_t       space_id = -1;
836     hid_t       ref_obj_id = -1;
837 
838     ref_obj_id = H5Rdereference(obj_id, ref_type, ref_in);
839     if (ref_obj_id < 0)
840         HGOTO_ERROR(FAIL, H5E_tools_min_id_g, "H5Rdereference2 failed");
841 
842     ref_obj_name = MapIdToName(ref_obj_id, travt);
843     if (ref_obj_name == NULL)
844         HGOTO_ERROR(FAIL, H5E_tools_min_id_g, "MapIdToName failed");
845 
846     if (ref_type == H5R_DATASET_REGION) {
847         space_id = H5Rget_region(obj_id, H5R_DATASET_REGION, ref_in);
848         if (space_id < 0)
849             HGOTO_ERROR(FAIL, H5E_tools_min_id_g, "H5Rget_region failed");
850     }
851 
852     if(H5Rcreate(ref_out, fid_out, ref_obj_name, ref_type, space_id) < 0)
853         HGOTO_ERROR(FAIL, H5E_tools_min_id_g, "H5Rcreate failed");
854 
855 done:
856     H5E_BEGIN_TRY {
857       H5Sclose(space_id);
858       H5Oclose(ref_obj_id);
859     } H5E_END_TRY;
860 
861     return ret_value;
862 }
863 
864