mirror of
https://github.com/HDFGroup/hdf5.git
synced 2024-11-27 02:10:55 +08:00
8f65e4252d
h5repack new features Description: addded the copy routines for hard links changed the traversal structure to store information about the hard links added tests Solution: Platforms tested: linux solaris IRIX Misc. update:
542 lines
14 KiB
C
542 lines
14 KiB
C
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
|
* Copyright by the Board of Trustees of the University of Illinois. *
|
|
* All rights reserved. *
|
|
* *
|
|
* This file is part of HDF5. The full HDF5 copyright notice, including *
|
|
* terms governing use, modification, and redistribution, is contained in *
|
|
* the files COPYING and Copyright.html. COPYING can be found at the root *
|
|
* of the source code distribution tree; Copyright.html can be found at the *
|
|
* root level of an installed copy of the electronic HDF5 document set and *
|
|
* is linked from the top-level documents page. It can also be found at *
|
|
* http://hdf.ncsa.uiuc.edu/HDF5/doc/Copyright.html. If you do not have *
|
|
* access to either file, you may request a copy from hdfhelp@ncsa.uiuc.edu. *
|
|
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
|
|
|
|
|
#include "h5diff.h"
|
|
#include "H5private.h"
|
|
#include <stdlib.h>
|
|
#include <assert.h>
|
|
|
|
|
|
|
|
/*-------------------------------------------------------------------------
|
|
* Function: h5diff
|
|
*
|
|
* Purpose: public function, can be called in an applicattion program.
|
|
* return differences between 2 HDF5 files
|
|
*
|
|
* Return: Number of differences found; -1 for error.
|
|
*
|
|
* Programmer: Pedro Vicente, pvn@ncsa.uiuc.edu
|
|
*
|
|
* Date: October 22, 2003
|
|
*
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
|
|
int h5diff(const char *fname1,
|
|
const char *fname2,
|
|
const char *objname1,
|
|
const char *objname2,
|
|
diff_opt_t *options)
|
|
{
|
|
int nobjects1, nobjects2;
|
|
trav_info_t *info1=NULL;
|
|
trav_info_t *info2=NULL;
|
|
hid_t file1_id, file2_id;
|
|
int nfound=0;
|
|
|
|
/*-------------------------------------------------------------------------
|
|
* open the files first; if they are not valid, no point in continuing
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
|
|
/* disable error reporting */
|
|
H5E_BEGIN_TRY {
|
|
|
|
/* Open the files */
|
|
if ((file1_id=H5Fopen(fname1,H5F_ACC_RDONLY,H5P_DEFAULT))<0 )
|
|
{
|
|
printf("h5diff: %s: No such file or directory\n", fname1 );
|
|
nfound = -1;
|
|
}
|
|
if ((file2_id=H5Fopen(fname2,H5F_ACC_RDONLY,H5P_DEFAULT))<0 )
|
|
{
|
|
printf("h5diff: %s: No such file or directory\n", fname2 );
|
|
nfound = -1;
|
|
}
|
|
/* enable error reporting */
|
|
} H5E_END_TRY;
|
|
if (nfound<0)
|
|
return -1;
|
|
|
|
/*-------------------------------------------------------------------------
|
|
* get the number of objects in the files
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
|
|
nobjects1 = h5trav_getinfo( file1_id, NULL );
|
|
nobjects2 = h5trav_getinfo( file2_id, NULL );
|
|
|
|
/*-------------------------------------------------------------------------
|
|
* get the list of objects in the files
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
|
|
info1 = (trav_info_t*) malloc( nobjects1 * sizeof(trav_info_t));
|
|
info2 = (trav_info_t*) malloc( nobjects2 * sizeof(trav_info_t));
|
|
if (info1==NULL || info2==NULL)
|
|
{
|
|
nfound=-1;
|
|
goto out;
|
|
}
|
|
|
|
h5trav_getinfo( file1_id, info1 );
|
|
h5trav_getinfo( file2_id, info2 );
|
|
|
|
/*-------------------------------------------------------------------------
|
|
* object name was supplied
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
|
|
if ( objname1 )
|
|
{
|
|
assert(objname2);
|
|
nfound=diff_compare(file1_id,fname1,objname1,nobjects1,info1,
|
|
file2_id,fname2,objname2,nobjects2,info2,options);
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------
|
|
* compare all
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
|
|
else
|
|
{
|
|
nfound=diff_match(file1_id,nobjects1,info1,
|
|
file2_id,nobjects2,info2,options);
|
|
}
|
|
|
|
|
|
h5trav_freeinfo(info1,nobjects1);
|
|
h5trav_freeinfo(info2,nobjects2);
|
|
|
|
out:
|
|
/* close */
|
|
H5Fclose(file1_id);
|
|
H5Fclose(file2_id);
|
|
|
|
return nfound;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
/*-------------------------------------------------------------------------
|
|
* Function: diff_match
|
|
*
|
|
* Purpose: Find common objects; the algorithm used for this search is the
|
|
* cosequential match algorithm and is described in
|
|
* Folk, Michael; Zoellick, Bill. (1992). File Structures. Addison-Wesley.
|
|
*
|
|
* Return: Number of differences found
|
|
*
|
|
* Programmer: Pedro Vicente, pvn@ncsa.uiuc.edu
|
|
*
|
|
* Date: May 9, 2003
|
|
*
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
int diff_match( hid_t file1_id,
|
|
int nobjects1,
|
|
trav_info_t *info1,
|
|
hid_t file2_id,
|
|
int nobjects2,
|
|
trav_info_t *info2,
|
|
diff_opt_t *options )
|
|
{
|
|
int more_names_exist = (nobjects1>0 && nobjects2>0) ? 1 : 0;
|
|
trav_table_t *table=NULL;
|
|
int cmp;
|
|
int curr1=0;
|
|
int curr2=0;
|
|
unsigned infile[2];
|
|
char c1, c2;
|
|
int nfound=0, i;
|
|
|
|
/*-------------------------------------------------------------------------
|
|
* build the list
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
trav_table_init( &table );
|
|
|
|
|
|
while ( more_names_exist )
|
|
{
|
|
/* criteria is string compare */
|
|
cmp = strcmp( info1[curr1].name, info2[curr2].name );
|
|
if ( cmp == 0 )
|
|
{
|
|
infile[0]=1; infile[1]=1;
|
|
trav_table_addflags(infile, info1[curr1].name, info1[curr1].type, table );
|
|
|
|
curr1++;
|
|
curr2++;
|
|
}
|
|
else if ( cmp < 0 )
|
|
{
|
|
infile[0]=1; infile[1]=0;
|
|
trav_table_addflags(infile, info1[curr1].name, info1[curr1].type, table );
|
|
curr1++;
|
|
}
|
|
else
|
|
{
|
|
infile[0]=0; infile[1]=1;
|
|
trav_table_addflags(infile, info2[curr2].name, info2[curr2].type, table );
|
|
curr2++;
|
|
}
|
|
|
|
more_names_exist = (curr1<nobjects1 && curr2<nobjects2) ? 1 : 0;
|
|
|
|
|
|
} /* end while */
|
|
|
|
/* list1 did not end */
|
|
if (curr1<nobjects1)
|
|
{
|
|
while ( curr1<nobjects1 )
|
|
{
|
|
infile[0]=1; infile[1]=0;
|
|
trav_table_addflags(infile, info1[curr1].name, info1[curr1].type, table );
|
|
curr1++;
|
|
}
|
|
}
|
|
|
|
/* list2 did not end */
|
|
if (curr2<nobjects2)
|
|
{
|
|
while ( curr2<nobjects2 )
|
|
{
|
|
infile[0]=0; infile[1]=1;
|
|
trav_table_addflags(infile, info2[curr2].name, info2[curr2].type, table );
|
|
curr2++;
|
|
}
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------
|
|
* print the list
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
|
|
if (options->verbose)
|
|
{
|
|
printf("\n");
|
|
printf("file1 file2\n");
|
|
printf("---------------------------------------\n");
|
|
for (i = 0; i < table->nobjs; i++)
|
|
{
|
|
c1 = (table->objs[i].flags[0]) ? 'x' : ' ';
|
|
c2 = (table->objs[i].flags[1]) ? 'x' : ' ';
|
|
printf("%5c %6c %-15s\n", c1, c2, table->objs[i].name);
|
|
}
|
|
printf("\n");
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------------------------------
|
|
* do the diff for common objects
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
|
|
for (i = 0; i < table->nobjs; i++)
|
|
{
|
|
if ( table->objs[i].flags[0] && table->objs[i].flags[1] )
|
|
nfound+=diff( file1_id,
|
|
table->objs[i].name,
|
|
file2_id,
|
|
table->objs[i].name,
|
|
options,
|
|
table->objs[i].type );
|
|
}
|
|
|
|
/* free table */
|
|
trav_table_free(table);
|
|
|
|
|
|
/*-------------------------------------------------------------------------
|
|
* do the diff for the root.
|
|
* this is a special case, we get an ID for the root group and call diff()
|
|
* with this ID; it compares only the root group attributes
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
|
|
nfound+=diff( file1_id,
|
|
"/",
|
|
file2_id,
|
|
"/",
|
|
options,
|
|
H5G_GROUP );
|
|
|
|
|
|
return nfound;
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------------------------------
|
|
* Function: diff_compare
|
|
*
|
|
* Purpose: get objects from list, and check for the same type
|
|
*
|
|
* Return: Number of differences found
|
|
*
|
|
* Programmer: Pedro Vicente, pvn@ncsa.uiuc.edu
|
|
*
|
|
* Date: May 9, 2003
|
|
*
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
|
|
int diff_compare( hid_t file1_id,
|
|
const char *file1_name,
|
|
const char *obj1_name,
|
|
int nobjects1,
|
|
trav_info_t *info1,
|
|
hid_t file2_id,
|
|
const char *file2_name,
|
|
const char *obj2_name,
|
|
int nobjects2,
|
|
trav_info_t *info2,
|
|
diff_opt_t *options )
|
|
{
|
|
|
|
int f1=0, f2=0;
|
|
int nfound=0;
|
|
|
|
int i = h5trav_getindex( obj1_name, nobjects1, info1 );
|
|
int j = h5trav_getindex( obj2_name, nobjects2, info2 );
|
|
|
|
if ( i == -1 )
|
|
{
|
|
printf( "Object <%s> could not be found in <%s>\n", obj1_name, file1_name );
|
|
f1=1;
|
|
}
|
|
if ( j == -1 )
|
|
{
|
|
printf( "Object <%s> could not be found in <%s>\n", obj2_name, file2_name );
|
|
f2=1;
|
|
}
|
|
if ( f1 || f2 )
|
|
return -1;
|
|
|
|
/* use the name with "/" first, as obtained by iterator function */
|
|
obj1_name=info1[i].name;
|
|
obj2_name=info2[j].name;
|
|
|
|
/* objects are not the same type */
|
|
if ( info1[i].type != info2[j].type && options->verbose)
|
|
{
|
|
printf("Comparison not possible: <%s> is of type %s and <%s> is of type %s\n",
|
|
obj1_name, get_type(info1[i].type),
|
|
obj2_name, get_type(info2[j].type) );
|
|
return 1;
|
|
}
|
|
|
|
nfound=diff( file1_id, obj1_name, file2_id, obj2_name, options, info1[i].type );
|
|
|
|
return nfound;
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------------------------------
|
|
* Function: diff
|
|
*
|
|
* Purpose: switch between types and choose the diff function
|
|
* TYPE is either
|
|
* H5G_LINK Object is a symbolic link
|
|
* H5G_GROUP Object is a group
|
|
* H5G_DATASET Object is a dataset
|
|
* H5G_TYPE Object is a named data type
|
|
*
|
|
* Return: Number of differences found
|
|
*
|
|
* Programmer: Pedro Vicente, pvn@ncsa.uiuc.edu
|
|
*
|
|
* Date: May 9, 2003
|
|
*
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
|
|
int diff( hid_t file1_id,
|
|
const char *path1,
|
|
hid_t file2_id,
|
|
const char *path2,
|
|
diff_opt_t *options,
|
|
H5G_obj_t type )
|
|
{
|
|
hid_t type1_id;
|
|
hid_t type2_id;
|
|
hid_t grp1_id;
|
|
hid_t grp2_id;
|
|
int ret;
|
|
H5G_stat_t sb1;
|
|
H5G_stat_t sb2;
|
|
char *buf1=NULL;
|
|
char *buf2=NULL;
|
|
int nfound=-1;
|
|
|
|
switch ( type )
|
|
{
|
|
/*-------------------------------------------------------------------------
|
|
* H5G_DATASET
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
case H5G_DATASET:
|
|
if (options->verbose)
|
|
printf( "Dataset: <%s> and <%s>\n",path1,path2);
|
|
nfound=diff_dataset(file1_id,file2_id,path1,path2,options);
|
|
break;
|
|
|
|
/*-------------------------------------------------------------------------
|
|
* H5G_TYPE
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
case H5G_TYPE:
|
|
if (options->verbose)
|
|
printf( "Datatype: <%s> and <%s>\n",path1,path2);
|
|
|
|
if ((type1_id = H5Topen(file1_id, path1))<0)
|
|
goto out;
|
|
if ((type2_id = H5Topen(file2_id, path2))<0)
|
|
goto out;
|
|
|
|
if ((ret = H5Tequal(type1_id,type2_id))<0)
|
|
goto out;
|
|
|
|
/* if H5Tequal is > 0 then the datatypes refer to the same datatype */
|
|
nfound = (ret>0) ? 0 : 1;
|
|
|
|
/*-------------------------------------------------------------------------
|
|
* compare attributes
|
|
* the if condition refers to cases when the dataset is a referenced object
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
if (path1)
|
|
nfound=diff_attr(type1_id,type2_id,path1,path2,options);
|
|
|
|
if ( H5Tclose(type1_id)<0)
|
|
goto out;
|
|
if ( H5Tclose(type2_id)<0)
|
|
goto out;
|
|
|
|
break;
|
|
|
|
/*-------------------------------------------------------------------------
|
|
* H5G_GROUP
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
case H5G_GROUP:
|
|
if (options->verbose)
|
|
printf( "Group: <%s> and <%s>\n",path1,path2);
|
|
|
|
if ((grp1_id = H5Gopen(file1_id, path1))<0)
|
|
goto out;
|
|
if ((grp2_id = H5Gopen(file2_id, path2))<0)
|
|
goto out;
|
|
|
|
ret = HDstrcmp(path1,path2);
|
|
|
|
/* if "path1" != "path2" then the groups are "different" */
|
|
nfound = (ret!=0) ? 1 : 0;
|
|
|
|
/*-------------------------------------------------------------------------
|
|
* compare attributes
|
|
* the if condition refers to cases when the dataset is a referenced object
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
if (path1)
|
|
nfound=diff_attr(grp1_id,grp2_id,path1,path2,options);
|
|
|
|
if ( H5Gclose(grp1_id)<0)
|
|
goto out;
|
|
if ( H5Gclose(grp2_id)<0)
|
|
goto out;
|
|
|
|
break;
|
|
|
|
|
|
/*-------------------------------------------------------------------------
|
|
* H5G_LINK
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
case H5G_LINK:
|
|
if (options->verbose)
|
|
printf( "Link: <%s> and <%s>\n",path1,path2);
|
|
|
|
if (H5Gget_objinfo(file1_id,path1,FALSE,&sb1)<0)
|
|
goto out;
|
|
if (H5Gget_objinfo(file1_id,path1,FALSE,&sb2)<0)
|
|
goto out;
|
|
|
|
buf1 = malloc(sb1.linklen);
|
|
buf2 = malloc(sb2.linklen);
|
|
|
|
if (H5Gget_linkval(file1_id,path1,sb1.linklen,buf1)<0)
|
|
goto out;
|
|
if (H5Gget_linkval(file2_id,path2,sb1.linklen,buf2)<0)
|
|
goto out;
|
|
|
|
ret = HDstrcmp(buf1,buf2);
|
|
|
|
/* if "buf1" != "buf2" then the links are "different" */
|
|
nfound = (ret!=0) ? 1 : 0;
|
|
|
|
if (buf1) {
|
|
free(buf1);
|
|
buf1=NULL;
|
|
}
|
|
|
|
if (buf2) {
|
|
free(buf2);
|
|
buf2=NULL;
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
default:
|
|
nfound=0;
|
|
if (options->verbose) {
|
|
printf("Comparison not supported: <%s> and <%s> are of type %s\n",
|
|
path1, path2, get_type(type) );
|
|
}
|
|
break;
|
|
}
|
|
|
|
|
|
out:
|
|
|
|
/* close */
|
|
/* disable error reporting */
|
|
H5E_BEGIN_TRY {
|
|
H5Tclose(type1_id);
|
|
H5Tclose(type2_id);
|
|
H5Gclose(grp1_id);
|
|
H5Tclose(grp2_id);
|
|
/* enable error reporting */
|
|
} H5E_END_TRY;
|
|
|
|
if (buf1)
|
|
free(buf1);
|
|
if (buf2)
|
|
free(buf2);
|
|
|
|
return nfound;
|
|
}
|
|
|
|
|
|
|
|
|
|
|