use File::Find;
use File::Path;
use File::Basename;
use IO::File;
use MD5;
use Getopt::Long;
use strict;
use vars qw($SOURCE $DESTINATION $MD5);

GetOptions('source=s'     =>  \$SOURCE,
 	   'destination=s' =>  \$DESTINATION)  || die <<USAGE;
 Usage: $0
    Create a checksum tree.
  Options:
    -source       <path>  File tree to traverse [.]
    -destination  <path>  Destination for checksum tree [TMPDIR]
    Option names may be abbreviated.
USAGE
    
$SOURCE      ||= '.';
$DESTINATION ||= $ENV{TMPDIR} || '/tmp';
die "Must specify absolute destination directory" unless $DESTINATION=~m!^/!;
$MD5 = new MD5;

find(\&wanted,$SOURCE);

# This routine is called for each node (directory or file) in the
# source tree.  On entry, $_ contains the filename, 
# and $File::Find::name contains its full path.
sub wanted {
    return unless -f $_ && -r _;
    my $modtime = -M _;
    my ($source,$dest,$url);
    $source = $File::Find::name;
    ($dest = $source)=~s/^$SOURCE/$DESTINATION/o;
    return if -e $dest && $modtime >= -M $dest;
    ($url = $source) =~s/^$SOURCE//o;
    make_checksum($_,$dest,$url);
}

# This routine is called with the source file, the destination in which
# to write the checksum, and a URL to attach as a comment to the checksum.
sub make_checksum {
    my ($source,$dest,$url) = @_;
    my $sfile = IO::File->new($source) || die "Couldn't open $source: $!\n";
    mkpath dirname($dest);  # create the intermediate directories
    my $dfile = IO::File->new(">$dest") || die "Couldn't open $dest: $!\n";
    $MD5->reset;
    $MD5->addfile($sfile);
    print $dfile $MD5->hexdigest(),"\t$url\n"; # write the checksum
}
__END__
