#!/usr/bin/perl

$| = 1;

require 'find.pl';

sub wanted {
	return unless -f $_;
	$len{-s _} .= "$name\n";
	# print "$name\n";
}

@ARGV = ('.') unless @ARGV;
&find(@ARGV);

sub numdown { $b <=> $a; }
$savesum = 0;
for $len (sort numdown keys len) {
	@samelen = split(/\n/,$len{$len});
	while ($target = shift(samelen)) {
		next unless @samelen > 0;
		@t = lstat($target);
		print "$target (dev $t[0] inode $t[1] nlink $t[3] size $t[7])\n";
		for $cand (@samelen) {
			@c = lstat($cand);
			print "  $cand (dev $c[0] inode $c[1] nlink $c[3] size $c[7])\n";
			next if $t[0] != $c[0]; # different disk
			next if $t[1] == $c[1]; # same file
			print "  comparing...\n";
			# next if system "cmp -s $target $cand";
			next if &different($target,$cand);
			print "  saving $c[7] bytes..." if $c[3] < 2;
			$savesum += $c[7] if $c[3] < 2;
			print "  rm $cand; ln $target $cand\n";
			unlink($cand) || die "cannot unlink $cand ($!)";
			link($target,$cand) || die "cannot link $target $cand ($!)";
		}
	}
}
print "saved $savesum total bytes\n";

sub different {
	($different'LEFT,$different'RIGHT) = @_;
	package different;
	open(LEFT) || return 1; # different if cannot open
	open(RIGHT) || return 1; # ditto
	return 1 if -s LEFT != -s RIGHT; # quick check if different sizes
	while (read(LEFT,$l,32768)) {
		read(RIGHT,$r,32768);
		return 1 if $l ne $r;
	}
	0;
}
