#!/usr/bin/perl -w
#   deldups [dir]...

# Get rid of multi-linked files in named directories, or in . by default.  We
# don't predict which link will be deleted.

# At present, what we do is create a .del  subdirectory,  and  move  all  the
# duplicate files there.  This has turned out useful in a number of projects,
# though we do need to remember to remove the  .del  directories  when  we're
# sure we don't need their contents.

# We don't look into subdirectories at all.  Maybe we need a -r option.

$| = 1;
$exitstat = 0;
($P = $0) =~ s".*/"";
$V = $ENV{"V_$P"} || $ENV{"D_$P"} || 2;	# Verbose level.

$LS     = '/bin/ls';
$SORT   = '/usr/bin/sort';
$deldir = '.del';   # If nonnull, we move files here to "delete" them
@dirs   = ();       # Directories to scan

for $arg (@ARGV) {
    if (-d $arg) {
        print "$P: Dir: \"$arg\"\n" if $V>1;
        push @dirs, $arg;
    } else {
        print STDERR "$P: Arg \"$arg\" unknown, ignored.\n" if $V>0;
    }
}
unless (@dirs) {
    print "$P: Dir: \".\"\n" if $V>1;
    push @dirs, '.';
}

for $dir (@dirs) {
    $cmd = "$LS -li $dir | $SORT -n";	# files sorted by inode number
    @files = `$cmd`;	# Get file list
    $lastf = '';		# Previous file name
    $lasti = 0;			# Previous inode number
    print "$P: DIR \"$dir\" ...\n" if $V>1;
    mkdir "$dir/$deldir", 0755 unless -d "$dir/$deldir";
file:
    for $line (@files) {
        $line =~ s/[\r\s]+$//;		# Trim off white stuff
        if (($ino,$fil) = ($line =~ /^\s*(\d+) .* (.*)$/)) {
            $pth = "$dir/$fil";
            print "    $ino\t$pth\n" if $V>2;
            if ($ino != $lasti) {
                $lasti = $ino;
                $lastf = $pth;
                next file;
            }
            print "DUP $ino\t$lastf\n";
            if ($pth gt $lastf) {
                print "DEL $ino\t$pth\n";
                if (link($pth,"$dir/$deldir/$fil")) {
                    unlink($pth);
                    # Note: Remember previous file name, not this one
                } else {
                    print STDERR "### Can't link \"$pth\" -> \"$dir/$deldir/$fil\" [$!]\n" if $V>0;
                }
            } else {
                print "DEL $ino\t$lastf\n";
                if (link($lastf,"$dir/$deldir/$lastf")) {
                    unlink($lastf);
                    $lastf = $pth;	# Remember this file name, not previous one
                } else {
                    print STDERR "### Can't link \"$lastf\" -> \"$dir/$deldir/$lastf\" [!?]\n" if $V>0;
                }
            }
        }
    }
}

exit $exitstat;
