#!/usr/bin/perl ## no critic pod use strict; use warnings; =head1 NAME cksum-tgz - Checksum the contents of a tarball =head1 SYNOPSIS cksum-tgz tarball.tgz > tarball.cksum Options: --help --man =head1 DESCRIPTION This is kind of equivalent to unpacking a tarball, running cksum on everything in it, then deleting the stuff that was unpacked. It attempts to keep a minimum of files around on the disk while operating. =head1 OPTIONS =over =item C<--help> Shows a short help message. =item C<--man> Even more help. =back =cut use Getopt::Long 'GetOptions'; use autouse 'Carp' => 'croak'; use autouse 'Pod::Usage' => 'pod2usage'; GetOptions( man => sub { pod2usage( -verbose => 2 ) }, help => sub { pod2usage( -verbose => 1 ) }, ) or pod2usage( -verbose => 0 ); @ARGV == 1 or pod2usage( -verbose => 0 ); my ($tgz) = shift @ARGV; ## no critic noisy open my $tgz_fh, '-|', 'tar', 'xvzf', $tgz or croak "Can't tar xvzf $tgz: $!"; # tar will print a file before it is done so I have this reader to # wait for the next file to get mentioned. my $file_reader = do { my @files; sub { # Add to @files if necessary and possible. while ( @files < 2 and $tgz_fh ) { chomp( my $file = <$tgz_fh> ); if ( not defined $file ) { close $tgz_fh; undef $tgz_fh; } else { push @files, $file; } } if (@files) { return shift @files; } else { return; } }; }; # For each file, cksum it. # For each directory, plan to remove it in LIFO order. my @directories; while ( my $file = $file_reader->() ) { if ( -f $file ) { 0 == system 'cksum', $file or croak "Can't exec cksum $file: $?"; unlink $file or croak "Can't unlink $file: $!"; } elsif ( -d _ ) { unshift @directories, $file; } } # Remove my directories in LIFO order. while (@directories) { my $size_before = @directories; @directories = grep { not rmdir } @directories; last if @directories == $size_before; }