File common_tree of Package openSUSE-images
#! /usr/bin/perl
use Getopt::Long;
use Digest::MD5;
use Fcntl ':mode';
sub add_md5;
sub sub_dirs;
sub del_dups;
sub copy_files;
sub remove_files;
sub new_tmp_file;
sub cleanup;
END { cleanup }
$SIG{INT} = \&cleanup;
$SIG{TERM} = \&cleanup;
GetOptions(
'dst=s' => \$opt_dst,
'prim=s' => \$opt_primary,
'sec=s' => \$opt_secondary,
'verbose+' => \$opt_verbose,
);
die "usage: common_tree --dst dst_dir --prim src_1 --sec src_2 \n" unless $opt_dst;
die "error: \"$opt_dst\" already exists; please delete\n" if -e $opt_dst;
die "$opt_dst: $!\n" unless mkdir $opt_dst, 0755;
for (`find '$opt_primary'`) {
chomp;
my $prim_file = $_;
s,^$opt_primary/,,;
my $secu_file = "$opt_secondary/$_";
($mode1, $uid1, $gid1, $size1) = (lstat $prim_file)[2,4,5,7];
($mode2, $uid2, $gid2, $size2) = (lstat $secu_file)[2,4,5,7];
next if (!defined $mode2 || $mode1 != $mode2 || $size1 != $size2 || $uid1 != $uid2 || $gid1 != $gid2 );
if ( S_ISREG $mode1 )
{
open F, $prim_file;
$md5_1 = Digest::MD5->new->addfile(*F)->hexdigest;
close F;
open F, $secu_file;
$md5_2 = Digest::MD5->new->addfile(*F)->hexdigest;
close F;
if ($md5_1 ne $md5_2)
{
print "$prim_file $md5_1 $md5_2\n";
next;
}
push @$common, sub_dirs($_);
push @$common, $_;
}
}
del_dups $common;
if($opt_verbose) {
$dir = $dir_list[0];
for (@$common) {
print "c: $dir $_: $l->{$dir}{$_}\n";
}
}
copy_files $common, $opt_primary, "$opt_dst";
remove_files $common, $opt_primary;
remove_files $common, $opt_secondary;
sub add_md5
{
local $_;
my $file = shift;
my ($dir, $md5);
return if $have_md5->{$file};
$have_md5->{$file} = 1;
for $dir (@dir_list) {
if(exists($l->{$dir}{$file}) && $l->{$dir}{$file} =~ /^f:/) {
die "$dir/$file: $!\n"unless open F, "$dir/$file";
$md5 = Digest::MD5->new->addfile(*F)->hexdigest;
close F;
$l->{$dir}{$file} .= ":$md5";
}
}
}
sub sub_dirs
{
local $_;
my $file = shift;
my (@dirs);
# print ">$file: ";
unshift @dirs, $file while $file =~ s#/[^/]*$##;
# print join(',', @dirs), "<\n";
return @dirs;
}
sub del_dups
{
local $_;
my %x;
$_[0] = [ grep { !$x{$_}++ } @{$_[0]} ];
}
sub copy_files
{
local $_;
my ($files, $src, $dst, $tmp);
($files, $src, $dst) = @_;
if($dst !~ /^\//) {
chomp($_ = `pwd`);
$dst = "$_/$dst";
}
$tmp = new_tmp_file;
open F, "|cd $src ; cpio --quiet -pm $dst 2>$tmp";
print F "$_\n" for (@$files);
close F;
if(-s $tmp) {
print STDERR scalar(`cat $tmp`);
die "error copying files\n";
}
}
sub remove_files
{
local $_;
my ($files, $src);
($files, $src) = @_;
for (@$files) {
unlink "$src/$_";
}
}
sub new_tmp_file
{
local $_;
chomp ($_ = `mktemp /tmp/common_tree.XXXXXXXXXX`);
die "error: mktemp failed\n" if $?;
push @tmp_files, $_;
return $_;
}
sub cleanup
{
unlink @tmp_files;
undef @tmp_files;
}