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 "H5private.h"
15 #include "h5tools.h"
16 #include "h5tools_utils.h"
17 #include "h5diff.h"
18 
19 #define ATTR_NAME_MAX 255
20 
21 typedef struct table_attr_t {
22     char      *name;
23     unsigned   exist[2];
24 } match_attr_t;
25 
26 typedef struct table_attrs_t {
27     size_t      size;
28     size_t      nattrs;
29     size_t      nattrs_only1;
30     size_t      nattrs_only2;
31     match_attr_t *attrs;
32 } table_attrs_t;
33 
34 
35 /*-------------------------------------------------------------------------
36  * Function: table_attrs_init
37  *
38  * Purpose: Initialize the table
39  *
40  * Parameter:
41  *  - tbl [OUT]
42  *
43  * Programmer: Jonathan Kim
44  *
45  * Date: March 15, 2011
46  *------------------------------------------------------------------------*/
table_attrs_init(table_attrs_t ** tbl)47 static void table_attrs_init(table_attrs_t **tbl)
48 {
49     table_attrs_t* table_attrs = (table_attrs_t*) HDmalloc(sizeof(table_attrs_t));
50 
51     table_attrs->size = 0;
52     table_attrs->nattrs = 0;
53     table_attrs->nattrs_only1 = 0;
54     table_attrs->nattrs_only2 = 0;
55     table_attrs->attrs = NULL;
56 
57     *tbl = table_attrs;
58 }
59 
60 /*-------------------------------------------------------------------------
61  * Function: table_attrs_free
62  *
63  * Purpose: free given table
64  *
65  * Parameter:
66  *  - table [IN]
67  *
68  * Programmer: Jonathan Kim
69  *
70  * Date: March 15, 2011
71  *------------------------------------------------------------------------*/
table_attrs_free(table_attrs_t * table)72 static void table_attrs_free( table_attrs_t *table )
73 {
74     unsigned int i;
75 
76     if (table) {
77         if (table->attrs) {
78             for (i = 0; i < table->nattrs; i++) {
79                 if (table->attrs[i].name) {
80                     HDfree(table->attrs[i].name);
81                 }
82             } /* end for */
83             HDfree(table->attrs);
84             table->attrs = NULL;
85         } /* end if */
86         HDfree(table);
87         table = NULL;
88     }
89 }
90 
91 /*-------------------------------------------------------------------------
92  * Function: table_attr_mark_exist
93  *
94  * Purpose: mark given attribute name to table as sign of exist
95  *
96  * Parameter:
97  *  - exist [IN]
98  *  - name [IN]  : attribute name
99  *  - table [OUT]
100  *
101  * Programmer: Jonathan Kim
102  *
103  * Date: March 15, 2011
104  *------------------------------------------------------------------------*/
table_attr_mark_exist(unsigned * exist,char * name,table_attrs_t * table)105 static void table_attr_mark_exist(unsigned *exist, char *name, table_attrs_t *table)
106 {
107     if(table->nattrs == table->size) {
108         match_attr_t *new_attrs;
109 
110         table->size = MAX(1, table->size * 2);
111         new_attrs = (match_attr_t *)HDrealloc(table->attrs, table->size * sizeof(match_attr_t));
112         if(new_attrs)
113             table->attrs = new_attrs;
114     } /* end if */
115 
116     if(table->nattrs < table->size) {
117         size_t curr_val;
118 
119         curr_val = table->nattrs;
120         table->attrs[curr_val].exist[0] = exist[0];
121         table->attrs[curr_val].exist[1] = exist[1];
122         if(name)
123             table->attrs[curr_val].name = (char *)HDstrdup(name);
124         table->nattrs++;
125     }
126 }
127 
128 /*-------------------------------------------------------------------------
129  * Function: build_match_list_attrs
130  *
131  * Purpose: get list of matching attribute name from obj1 and obj2
132  *
133  * Note:
134  *  Find common attribute; the algorithm for search is referred from
135  *  build_match_list() in h5diff.c .
136  *
137  * Parameter:
138  *  table_out [OUT] : return the list
139  *------------------------------------------------------------------------*/
build_match_list_attrs(hid_t loc1_id,hid_t loc2_id,table_attrs_t ** table_out,diff_opt_t * opts)140 static herr_t build_match_list_attrs(hid_t loc1_id, hid_t loc2_id, table_attrs_t ** table_out,  diff_opt_t *opts)
141 {
142     int        ret_value = 0;
143     H5O_info_t oinfo1, oinfo2;    /* Object info */
144     hid_t      attr1_id = -1;     /* attr ID */
145     hid_t      attr2_id = -1;     /* attr ID */
146     size_t     curr1 = 0;
147     size_t     curr2 = 0;
148     unsigned   infile[2];
149     char       name1[ATTR_NAME_MAX];
150     char       name2[ATTR_NAME_MAX];
151     int        cmp;
152     unsigned   i;
153     table_attrs_t *table_lp = NULL;
154 
155     h5difftrace("build_match_list_attrs start\n");
156 
157     if(H5Oget_info(loc1_id, &oinfo1) < 0)
158         HGOTO_ERROR(FAIL, H5E_tools_min_id_g, "H5Oget_info first object failed");
159     if(H5Oget_info(loc2_id, &oinfo2) < 0)
160         HGOTO_ERROR(FAIL, H5E_tools_min_id_g, "H5Oget_info second object failed");
161 
162     table_attrs_init(&table_lp);
163     if (table_lp == NULL)
164         HGOTO_ERROR(FAIL, H5E_tools_min_id_g, "Table allocation failed");
165 
166     /*--------------------------------------------------
167      * build the list
168      */
169     while(curr1 < oinfo1.num_attrs && curr2 < oinfo2.num_attrs) {
170         h5diffdebug3("build_match_list_attrs 1: %ld - %ld\n", curr1, oinfo1.num_attrs);
171         h5diffdebug3("build_match_list_attrs 2: %ld - %ld\n", curr2, oinfo2.num_attrs);
172 
173         /*------------------
174         * open attribute1 */
175         if((attr1_id = H5Aopen_by_idx(loc1_id, ".", H5_INDEX_NAME, H5_ITER_INC, (hsize_t)curr1, H5P_DEFAULT, H5P_DEFAULT)) < 0)
176             HGOTO_ERROR(FAIL, H5E_tools_min_id_g, "H5Aopen_by_idx first attribute failed");
177         /* get name */
178         if(H5Aget_name(attr1_id, (size_t)ATTR_NAME_MAX, name1) < 0)
179             HGOTO_ERROR(FAIL, H5E_tools_min_id_g, "H5Aget_name first attribute failed");
180 
181         /*------------------
182         * open attribute2 */
183         if((attr2_id = H5Aopen_by_idx(loc2_id, ".", H5_INDEX_NAME, H5_ITER_INC, (hsize_t)curr2, H5P_DEFAULT, H5P_DEFAULT)) < 0)
184             HGOTO_ERROR(FAIL, H5E_tools_min_id_g, "H5Aopen_by_idx second attribute failed");
185         /* get name */
186         if(H5Aget_name(attr2_id, (size_t)ATTR_NAME_MAX, name2) < 0)
187             HGOTO_ERROR(FAIL, H5E_tools_min_id_g, "H5Aget_name second attribute failed");
188 
189         /* criteria is string compare */
190         cmp = HDstrcmp(name1, name2);
191 
192         if(cmp == 0) {
193             infile[0] = 1;
194             infile[1] = 1;
195             table_attr_mark_exist(infile, name1, table_lp);
196             curr1++;
197             curr2++;
198         }
199         else if(cmp < 0) {
200             infile[0] = 1;
201             infile[1] = 0;
202             table_attr_mark_exist(infile, name1, table_lp);
203             table_lp->nattrs_only1++;
204             curr1++;
205         }
206         else {
207             infile[0] = 0;
208             infile[1] = 1;
209             table_attr_mark_exist(infile, name2, table_lp);
210             table_lp->nattrs_only2++;
211             curr2++;
212         }
213 
214         /* close for next turn */
215         H5Aclose(attr1_id);
216         attr1_id = -1;
217         H5Aclose(attr2_id);
218         attr2_id = -1;
219     } /* end while */
220 
221     /* list1 did not end */
222     infile[0] = 1;
223     infile[1] = 0;
224     while(curr1 < oinfo1.num_attrs) {
225         h5diffdebug3("build_match_list_attrs 1: %ld - %ld\n", curr1, oinfo1.num_attrs);
226 
227         /*------------------
228         * open attribute1 */
229         if((attr1_id = H5Aopen_by_idx(loc1_id, ".", H5_INDEX_NAME, H5_ITER_INC, (hsize_t)curr1, H5P_DEFAULT, H5P_DEFAULT)) < 0)
230             HGOTO_ERROR(FAIL, H5E_tools_min_id_g, "H5Aopen_by_idx first attribute failed");
231         /* get name */
232         if(H5Aget_name(attr1_id, (size_t)ATTR_NAME_MAX, name1) < 0)
233             HGOTO_ERROR(FAIL, H5E_tools_min_id_g, "H5Aget_name first attribute failed");
234         h5diffdebug2("build_match_list_attrs #1 name - %s\n", name1);
235 
236         table_attr_mark_exist(infile, name1, table_lp);
237         table_lp->nattrs_only1++;
238         curr1++;
239 
240         /* close for next turn */
241         H5Aclose(attr1_id);
242         attr1_id = -1;
243     }
244 
245     /* list2 did not end */
246     infile[0] = 0;
247     infile[1] = 1;
248     while(curr2 < oinfo2.num_attrs) {
249         h5diffdebug3("build_match_list_attrs 2: %ld - %ld\n", curr2, oinfo2.num_attrs);
250         /*------------------
251         * open attribute2 */
252         if((attr2_id = H5Aopen_by_idx(loc2_id, ".", H5_INDEX_NAME, H5_ITER_INC, (hsize_t)curr2, H5P_DEFAULT, H5P_DEFAULT)) < 0)
253             HGOTO_ERROR(FAIL, H5E_tools_min_id_g, "H5Aopen_by_idx second attribute failed");
254         /* get name */
255         if(H5Aget_name(attr2_id, (size_t)ATTR_NAME_MAX, name2) < 0)
256             HGOTO_ERROR(FAIL, H5E_tools_min_id_g, "H5Aget_name second attribute failed");
257         h5diffdebug2("build_match_list_attrs #2 name - %s\n", name2);
258 
259         table_attr_mark_exist(infile, name2, table_lp);
260         table_lp->nattrs_only2++;
261         curr2++;
262 
263         /* close for next turn */
264         H5Aclose(attr2_id);
265         attr2_id = -1;
266     }
267 
268     /*------------------------------------------------------
269      * print the list
270      */
271     if(opts->m_verbose_level == 2) {
272         /* if '-v2' is detected */
273         parallel_print("   obj1   obj2\n");
274         parallel_print(" --------------------------------------\n");
275         for(i = 0; i < (unsigned int) table_lp->nattrs; i++) {
276             char c1, c2;
277             c1 = (table_lp->attrs[i].exist[0]) ? 'x' : ' ';
278             c2 = (table_lp->attrs[i].exist[1]) ? 'x' : ' ';
279             parallel_print("%5c %6c    %-15s\n", c1, c2, table_lp->attrs[i].name);
280         } /* end for */
281     }
282 
283     if(opts->m_verbose_level >= 1)
284         parallel_print("Attributes status:  %d common, %d only in obj1, %d only in obj2\n",
285                 table_lp->nattrs - table_lp->nattrs_only1 - table_lp->nattrs_only2,
286                 table_lp->nattrs_only1, table_lp->nattrs_only2);
287 
288 done:
289     *table_out = table_lp;
290 
291     /* disable error reporting */
292     H5E_BEGIN_TRY {
293         H5Aclose(attr1_id);
294         H5Aclose(attr2_id);
295     } H5E_END_TRY;
296 
297     h5diffdebug2("build_match_list_attrs end - errstat:%d\n", opts->err_stat);
298 
299     return ret_value;
300 }
301 
302 /*-------------------------------------------------------------------------
303  * Function: diff_attr
304  *
305  * Purpose:  compare attributes located in LOC1_ID and LOC2_ID, which are
306  *           obtained either from
307  *               loc_id = H5Gopen2(fid, name, H5P_DEFAULT);
308  *               loc_id = H5Dopen2(fid, name);
309  *               loc_id = H5Topen2(fid, name, H5P_DEFAULT);
310  *
311  * Return:   number of differences found
312  *-------------------------------------------------------------------------
313  */
314 
diff_attr(hid_t loc1_id,hid_t loc2_id,const char * path1,const char * path2,diff_opt_t * opts)315 hsize_t diff_attr(hid_t loc1_id,
316                   hid_t loc2_id,
317                   const char *path1,
318                   const char *path2,
319                   diff_opt_t *opts)
320 {
321     int        ret_value = opts->err_stat;
322     hid_t      attr1_id = -1;     /* attr ID */
323     hid_t      attr2_id = -1;     /* attr ID */
324     hid_t      space1_id = -1;    /* space ID */
325     hid_t      space2_id = -1;    /* space ID */
326     hid_t      ftype1_id = -1;    /* file data type ID */
327     hid_t      ftype2_id = -1;    /* file data type ID */
328     hid_t      mtype1_id = -1;    /* memory data type ID */
329     hid_t      mtype2_id = -1;    /* memory data type ID */
330     size_t     msize1;            /* memory size of memory type */
331     size_t     msize2;            /* memory size of memory type */
332     void       *buf1 = NULL;      /* data buffer */
333     void       *buf2 = NULL;      /* data buffer */
334     hbool_t    buf1hasdata = FALSE;    /* buffer has data */
335     hbool_t    buf2hasdata = FALSE;    /* buffer has data */
336     hsize_t    nelmts1;           /* number of elements in dataset */
337     int        rank1;             /* rank of dataset */
338     int        rank2;             /* rank of dataset */
339     hsize_t    dims1[H5S_MAX_RANK];    /* dimensions of dataset */
340     hsize_t    dims2[H5S_MAX_RANK];    /* dimensions of dataset */
341     char       *name1 = NULL;
342     char       *name2 = NULL;
343     char       np1[512];
344     char       np2[512];
345     unsigned   u;                 /* Local index variable */
346     hsize_t    nfound = 0;
347     hsize_t    nfound_total = 0;
348     int       j;
349 
350     table_attrs_t *match_list_attrs = NULL;
351     h5difftrace("diff_attr start\n");
352 
353     if(build_match_list_attrs(loc1_id, loc2_id, &match_list_attrs, opts) < 0) {
354         HGOTO_ERROR(1, H5E_tools_min_id_g, "build_match_list_attrs failed");
355     }
356     h5diffdebug2("build_match_list_attrs - errstat:%d\n", opts->err_stat);
357 
358     /* if detect any unique extra attr */
359     if(match_list_attrs->nattrs_only1 || match_list_attrs->nattrs_only2) {
360         h5difftrace("diff_attr attributes only in one file\n");
361         /* exit will be 1 */
362         opts->contents = 0;
363     }
364     h5diffdebug2("match_list_attrs info - errstat:%d\n", opts->err_stat);
365 
366     for(u = 0; u < (unsigned)match_list_attrs->nattrs; u++) {
367         h5diffdebug3("match_list_attrs loop[%d] - errstat:%d\n", u, opts->err_stat);
368         if((match_list_attrs->attrs[u].exist[0]) && (match_list_attrs->attrs[u].exist[1])) {
369             name1 = name2 = match_list_attrs->attrs[u].name;
370             h5diffdebug2("diff_attr name - %s\n", name1);
371 
372             /*--------------
373             * attribute 1 */
374             if((attr1_id = H5Aopen(loc1_id, name1, H5P_DEFAULT)) < 0)
375                 HGOTO_ERROR(1, H5E_tools_min_id_g, "H5Aopen first attribute failed");
376 
377             /*--------------
378             * attribute 2 */
379             if((attr2_id = H5Aopen(loc2_id, name2, H5P_DEFAULT)) < 0)
380                 HGOTO_ERROR(1, H5E_tools_min_id_g, "H5Aopen second attribute failed");
381 
382             h5difftrace("diff_attr got attributes\n");
383             /* get the datatypes  */
384             if((ftype1_id = H5Aget_type(attr1_id)) < 0)
385                 HGOTO_ERROR(1, H5E_tools_min_id_g, "H5Aget_type first attribute failed");
386             if((ftype2_id = H5Aget_type(attr2_id)) < 0)
387                 HGOTO_ERROR(1, H5E_tools_min_id_g, "H5Aget_type second attribute failed");
388 
389             if((mtype1_id = H5Tget_native_type(ftype1_id, H5T_DIR_DEFAULT)) < 0)
390                 HGOTO_ERROR(1, H5E_tools_min_id_g, "H5Tget_native_type first attribute ftype failed");
391             if((mtype2_id = H5Tget_native_type(ftype2_id, H5T_DIR_DEFAULT)) < 0)
392                 HGOTO_ERROR(1, H5E_tools_min_id_g, "H5Tget_native_type second attribute ftype failed");
393             if((msize1 = H5Tget_size(mtype1_id)) == 0)
394                 HGOTO_ERROR(1, H5E_tools_min_id_g, "H5Tget_size first attribute mtype failed");
395             if((msize2 = H5Tget_size(mtype2_id)) == 0)
396                 HGOTO_ERROR(1, H5E_tools_min_id_g, "H5Tget_size second attribute mtype failed");
397 
398             /* get the dataspace   */
399             if((space1_id = H5Aget_space(attr1_id)) < 0)
400                 HGOTO_ERROR(1, H5E_tools_min_id_g, "H5Aget_space first attribute failed");
401             if((space2_id = H5Aget_space(attr2_id)) < 0)
402                 HGOTO_ERROR(1, H5E_tools_min_id_g, "H5Aget_space second attribute failed");
403 
404             /* get dimensions  */
405             if((rank1 = H5Sget_simple_extent_dims(space1_id, dims1, NULL)) < 0)
406                 HGOTO_ERROR(1, H5E_tools_min_id_g, "H5Sget_simple_extent_dims first attribute failed");
407             if((rank2 = H5Sget_simple_extent_dims(space2_id, dims2, NULL)) < 0)
408                 HGOTO_ERROR(1, H5E_tools_min_id_g, "H5Sget_simple_extent_dims second attribute failed");
409 
410             /*----------------------------------------------------------------------
411             * check for comparable TYPE and SPACE
412             *----------------------------------------------------------------------
413             */
414 
415             /* pass dims1 and dims2 for maxdims as well since attribute's maxdims
416             * are always same */
417             if(diff_can_type(ftype1_id, ftype2_id, rank1, rank2, dims1, dims2,
418                     dims1, dims2, name1, name2, opts, 0) != 1) {
419                 if(H5Tclose(ftype1_id) < 0)
420                     HGOTO_ERROR(1, H5E_tools_min_id_g, "H5Tclose first attribute ftype failed");
421                 if(H5Tclose(ftype2_id) < 0)
422                     HGOTO_ERROR(1, H5E_tools_min_id_g, "H5Tclose second attribute ftype failed");
423                 if(H5Sclose(space1_id) < 0)
424                     HGOTO_ERROR(1, H5E_tools_min_id_g, "H5Sclose first attribute failed");
425                 if(H5Sclose(space2_id) < 0)
426                     HGOTO_ERROR(1, H5E_tools_min_id_g, "H5Sclose second attribute failed");
427                 if(H5Aclose(attr1_id) < 0)
428                     HGOTO_ERROR(1, H5E_tools_min_id_g, "H5Aclose first attribute failed");
429                 if(H5Aclose(attr2_id) < 0)
430                     HGOTO_ERROR(1, H5E_tools_min_id_g, "H5Aclose second attribute failed");
431                 if(H5Tclose(mtype1_id) < 0)
432                     HGOTO_ERROR(1, H5E_tools_min_id_g, "H5Tclose first attribute mtype failed");
433                 if(H5Tclose(mtype2_id) < 0)
434                     HGOTO_ERROR(1, H5E_tools_min_id_g, "H5Tclose second attribute mtype failed");
435 
436                 continue;
437             }
438 
439             /*-----------------------------------------------------------------
440             * "upgrade" the smaller memory size
441             *------------------------------------------------------------------
442             */
443             if(FAIL == match_up_memsize(ftype1_id, ftype2_id, &mtype1_id,
444                             &mtype2_id, &msize1, &msize2))
445                 HGOTO_ERROR(1, H5E_tools_min_id_g, "match_up_memsize failed");
446 
447             /*---------------------------------------------------------------------
448             * read
449             *----------------------------------------------------------------------
450             */
451             nelmts1 = 1;
452             for(j = 0; j < rank1; j++)
453                 nelmts1 *= dims1[j];
454 
455             buf1 = (void *)HDcalloc((size_t)(nelmts1), msize1);
456             buf2 = (void *)HDcalloc((size_t)(nelmts1), msize2);
457             if(buf1 == NULL || buf2 == NULL) {
458                 parallel_print("cannot read into memory\n");
459                 HGOTO_ERROR(1, H5E_tools_min_id_g, "buffer allocation failed");
460             }
461             if(H5Aread(attr1_id, mtype1_id, buf1) < 0) {
462                 parallel_print("Failed reading attribute1 %s/%s\n", path1, name1);
463                 HGOTO_ERROR(1, H5E_tools_min_id_g, "H5Aget_type first attribute failed");
464             }
465             else
466                 buf1hasdata = TRUE;
467 
468             if(H5Aread(attr2_id, mtype2_id, buf2) < 0) {
469                 parallel_print("Failed reading attribute2 %s/%s\n", path2, name2);
470                 HGOTO_ERROR(1, H5E_tools_min_id_g, "H5Aget_type second attribute failed");
471             }
472             else
473                 buf2hasdata = TRUE;
474 
475             /* format output string */
476             HDsnprintf(np1, sizeof(np1), "%s of <%s>", name1, path1);
477             HDsnprintf(np2, sizeof(np1), "%s of <%s>", name2, path2);
478 
479             /*---------------------------------------------------------------------
480             * array compare
481             *----------------------------------------------------------------------
482             */
483 
484             /* always print name */
485             /* verbose (-v) and report (-r) mode */
486             if(opts->m_verbose || opts->m_report) {
487                 do_print_attrname("attribute", np1, np2);
488 
489                 nfound = diff_array(buf1, buf2, nelmts1, (hsize_t) 0, rank1,
490                         dims1, opts, np1, np2, mtype1_id, attr1_id, attr2_id);
491                 print_found(nfound);
492             }
493             /* quiet mode (-q), just count differences */
494             else if(opts->m_quiet) {
495                 nfound = diff_array(buf1, buf2, nelmts1, (hsize_t) 0, rank1,
496                         dims1, opts, np1, np2, mtype1_id, attr1_id, attr2_id);
497             }
498             /* the rest (-c, none, ...) */
499             else {
500                 nfound = diff_array(buf1, buf2, nelmts1, (hsize_t) 0, rank1,
501                         dims1, opts, np1, np2, mtype1_id, attr1_id, attr2_id);
502 
503                 /* print info if compatible and difference found */
504                 if (nfound) {
505                     do_print_attrname("attribute", np1, np2);
506                     print_found(nfound);
507                 } /* end if */
508             } /* end else */
509 
510             /*----------------------------------------------------------------------
511             * close
512             *----------------------------------------------------------------------
513             */
514 
515             /* Free buf1 and buf2, check both VLEN-data VLEN-string to reclaim any
516             * VLEN memory first */
517             if(TRUE == h5tools_detect_vlen(mtype1_id))
518                 H5Dvlen_reclaim(mtype1_id, space1_id, H5P_DEFAULT, buf1);
519             HDfree(buf1);
520             buf1 = NULL;
521 
522             if(TRUE == h5tools_detect_vlen(mtype2_id))
523                 H5Dvlen_reclaim(mtype2_id, space2_id, H5P_DEFAULT, buf2);
524             HDfree(buf2);
525             buf2 = NULL;
526 
527             if(H5Tclose(ftype1_id) < 0)
528                 HGOTO_ERROR(1, H5E_tools_min_id_g, "H5Aget_type first attribute failed");
529             if(H5Tclose(ftype2_id) < 0)
530                 HGOTO_ERROR(1, H5E_tools_min_id_g, "H5Aget_type second attribute failed");
531             if(H5Sclose(space1_id) < 0)
532                 HGOTO_ERROR(1, H5E_tools_min_id_g, "H5Aget_type first attribute failed");
533             if(H5Sclose(space2_id) < 0)
534                 HGOTO_ERROR(1, H5E_tools_min_id_g, "H5Aget_type second attribute failed");
535             if(H5Aclose(attr1_id) < 0)
536                 HGOTO_ERROR(1, H5E_tools_min_id_g, "H5Aget_type first attribute failed");
537             if(H5Aclose(attr2_id) < 0)
538                 HGOTO_ERROR(1, H5E_tools_min_id_g, "H5Aget_type second attribute failed");
539             if(H5Tclose(mtype1_id) < 0)
540                 HGOTO_ERROR(1, H5E_tools_min_id_g, "H5Tclose first attribute mtype failed");
541             if(H5Tclose(mtype2_id) < 0)
542                 HGOTO_ERROR(1, H5E_tools_min_id_g, "H5Tclose second attribute mtype failed");
543 
544             nfound_total += nfound;
545         }
546     } /* u */
547 
548 done:
549     opts->err_stat = opts->err_stat | ret_value;
550 
551     H5E_BEGIN_TRY {
552         if(buf1) {
553             if(buf1hasdata && TRUE == h5tools_detect_vlen(mtype1_id))
554                 H5Dvlen_reclaim(mtype1_id, space1_id, H5P_DEFAULT, buf1);
555             HDfree(buf1);
556         } /* end if */
557         if(buf2) {
558             if(buf2hasdata && TRUE == h5tools_detect_vlen(mtype2_id))
559                 H5Dvlen_reclaim(mtype2_id, space2_id, H5P_DEFAULT, buf2);
560             HDfree(buf2);
561         } /* end if */
562 
563         table_attrs_free(match_list_attrs);
564 
565         H5Tclose(ftype1_id);
566         H5Tclose(ftype2_id);
567         H5Tclose(mtype1_id);
568         H5Tclose(mtype2_id);
569         H5Sclose(space1_id);
570         H5Sclose(space2_id);
571         H5Aclose(attr1_id);
572         H5Aclose(attr2_id);
573     } H5E_END_TRY;
574 
575     h5diffdebug2("diff_attr end - errstat:%d\n", opts->err_stat);
576     return nfound_total;
577 }
578 
579