| version 1.3, 2005/05/24 12:31:28 |
version 1.4, 2005/05/24 15:43:00 |
|
|
| # 2005-04-17 - created |
# 2005-04-17 - created |
| # |
# |
| |
|
| # $Platon: scripts/perl/filesystem/hardlink-files.pl,v 1.2 2005/05/24 11:55:46 rajo Exp $ |
# $Platon: scripts/perl/filesystem/hardlink-files.pl,v 1.3 2005/05/24 12:31:28 rajo Exp $ |
| |
|
| use strict; |
use strict; |
| |
|
| |
use Quota; |
| use File::Find; |
use File::Find; |
| use Cwd qw( abs_path ); |
use Cwd qw( abs_path ); |
| use Digest::MD5; |
use Digest::MD5; |
| Line 25 use Data::Dumper; |
|
| Line 27 use Data::Dumper; |
|
| |
|
| $| = 1; |
$| = 1; |
| |
|
| use vars qw(*file *dir *prune); |
use vars qw ( |
| |
*file *dir *prune |
| |
$md5sums $cache $stat $stat_global $mountpoints |
| |
); |
| |
|
| *file = *File::Find::name; |
*file = *File::Find::name; |
| *dir = *File::Find::dir; |
*dir = *File::Find::dir; |
| *prune = *File::Find::prune; |
*prune = *File::Find::prune; |
| |
|
| my $md5binary; |
|
| my $md5sums = { |
|
| }; |
|
| my $cache = { |
|
| }; |
|
| |
|
| sub wanted() |
sub wanted() |
| { # {{{ |
{ # {{{ |
| my ($dev, $ino, $mode, $nlink, $uid, $gid, $rdev, $size, $atime, $mtime, $ctime, $blksize, $blocks); |
my ($dev, $ino, $mode, $nlink, $uid, $gid, $rdev, $size, $atime, $mtime, $ctime, $blksize, $blocks); |
|
|
| |
|
| # |
# |
| # Load cache |
# Load cache |
| # |
# TODO: |
| foreach my $xdir (@ARGV) { |
foreach my $xdir (@ARGV) { |
| if (-f "$xdir/.hardlink-cache") { |
if (-f "$xdir/.hardlink-cache") { |
| |
|
|
|
| |
|
| #print Dumper($md5sums); |
#print Dumper($md5sums); |
| |
|
| |
# |
| |
# Statistics |
| |
# {{{ |
| my $hashes; |
my $hashes; |
| foreach my $dev (keys %$md5sums) { |
foreach my $dev (keys %$md5sums) { |
| foreach my $key (keys %{$md5sums->{$dev}}) { |
foreach my $key (keys %{$md5sums->{$dev}}) { |
| $hashes->{$key} = 1; |
$hashes->{$key} = 1; |
| } |
} |
| |
$stat->{$dev} = { |
| |
count => 0, |
| |
size => 0, |
| |
blksize => 0, |
| |
blocks => 0, |
| |
}; |
| } |
} |
| print scalar(keys %$hashes), " unique files found\n"; |
$stat_global->{unique_files} = scalar(keys %$hashes); |
| |
# }}} |
| |
|
| |
# |
| |
# Get mountpoints info |
| |
# {{{ |
| |
Quota::setmntent(); |
| |
while (my ($mountdev, $mountpoint, $type, $opts) = Quota::getmntent()) { |
| |
my ($dev, $ino, $mode, $nlink, $uid, $gid, $rdev, $size, $atime, $mtime, $ctime, $blksize, $blocks) = lstat($mountpoint); |
| |
$mountpoints->{$dev} = { |
| |
mountpoint => $mountpoint, |
| |
mountdev => $mountdev, |
| |
} if (defined $dev); |
| |
} |
| |
Quota::endmntent(); |
| |
# }}} |
| |
|
| |
# |
| |
# Do the real work: hardlink files and compute stats |
| |
# |
| foreach my $dev (keys %$md5sums) { |
foreach my $dev (keys %$md5sums) { |
| foreach my $key (keys %{$md5sums->{$dev}}) { |
foreach my $key (keys %{$md5sums->{$dev}}) { |
| my $arr = $md5sums->{$dev}->{$key}; |
my @arr = @{$md5sums->{$dev}->{$key}}; |
| if (scalar(@$arr) > 1) { |
my $count = scalar(@arr); |
| my $source = $arr->[0]->{filename}; |
if ($count > 1) { |
| my $inum = $arr->[0]->{ino}; |
my $source = $arr[0]->{filename}; |
| |
my $inum = $arr[0]->{ino}; |
| |
|
| |
# statistics report # {{{ |
| |
$stat->{$dev}->{count} += ($count - 1); |
| |
$stat->{$dev}->{size} += ($count - 1) * $arr[0]->{size}; |
| |
$stat->{$dev}->{blocks} += ($count - 1) * $arr[0]->{blocks}; |
| |
$stat->{$dev}->{blksize} = $arr[0]->{blksize}; |
| |
# }}} |
| |
|
| print $source; |
print $source; |
| for (my $i = 1; $i < scalar(@$arr); $i++) { |
for (my $i = 1; $i < $count; $i++) { # hardlink files {{{ |
| print "\n\t<-- ", $arr->[$i]->{filename}; |
print "\n\t<-- ", $arr[$i]->{filename}; |
| if ($arr->[$i]->{ino} == $inum) { |
if ($arr[$i]->{ino} == $inum) { |
| print " [already linked]"; |
print " [already linked]"; |
| } |
} |
| else { |
else { |
| unlink $arr->[$i]->{filename} or warn "\n\nunlink error: $!\n"; |
unlink $arr[$i]->{filename} or warn "\n\nunlink error: $!\n"; |
| link $source, $arr->[$i]->{filename} or warn "\n\nlink error: $!\n"; |
link $source, $arr[$i]->{filename} or warn "\n\nlink error: $!\n"; |
| } |
} |
| } |
} # }}} |
| print "\n\n"; |
print "\n\n"; |
| } |
} |
| } |
} |
| } |
} |
| |
|
| |
#print Dumper($stat, $mountpoints); |
| #print Dumper($md5sums); |
#print Dumper($md5sums); |
| |
|
| |
# |
| |
# Print statistics |
| |
# {{{ |
| |
foreach my $dev (keys %$md5sums) { |
| |
my $info = $stat->{$dev}; |
| |
print '-' x 60, "\n"; |
| |
if (defined $mountpoints->{$dev}) { |
| |
print "$mountpoints->{$dev}->{mountpoint} [$mountpoints->{$dev}->{mountdev}]\n"; |
| |
} |
| |
else { |
| |
print "??? [$dev]\n"; |
| |
} |
| |
print " Unique files: ", scalar(keys %{$md5sums->{$dev}}), "\n"; |
| |
print " Hardlinked files: $info->{count}\n"; |
| |
print " Saved bytes: $info->{size}\n"; |
| |
print " Saved blocks: $info->{blocks}\n"; |
| |
print "Saved bytes in blocks: ", $info->{blksize} * $info->{blocks}, "\n"; |
| |
} |
| |
print '-' x 60, "\n"; |
| |
print "TOTAL:\n"; |
| |
print " Total unique files: $stat_global->{unique_files}\n"; |
| |
# }}} |
| |
|
| # vim: ts=4 |
# vim: ts=4 |
| # vim600: fdm=marker fdl=0 fdc=3 |
# vim600: fdm=marker fdl=0 fdc=3 |
| |
|