#! /usr/bin/perl use autodie; (my $prog = $0) =~ s!^.*/!!; die "usage: $prog ORIG COPY\n" unless @ARGV == 2; my ($orig, $copy) = @ARGV; open my $ofh, "<", $orig; binmode $ofh; open my $cfh, "<", $copy; binmode $cfh; my $SECSZ = 2048; my $ZERO = "\0" x $SECSZ; my $rc = 0; sub bad ($) { my ($msg) = @_; print STDERR "$prog: $msg\n"; $rc = 2 unless $rc > 2; } my ($obuf, $cbuf); my $i = 0; my $report = ""; my $prev = undef; my $st = undef; sub update ($) { my ($newst) = @_; if ($newst ne $st) { if (defined $st) { $report .= ", " if $report; if ($st eq 'copy') { $report .= "$prev .. $i"; } elsif ($st eq 'zero') { $report .= "[$prev .. $i]"; } else { $report .= "($st: $prev .. $i)"; } } $st = $newst; $prev = $i; } } SECTOR: for (;;) { my $on = read $ofh, $obuf, $SECSZ; my $cn = read $cfh, $cbuf, $SECSZ; if ($on < $SECSZ || $cn < $SECSZ) { if ($on == $SECSZ) { if (!$cn) { bad "premature end at sector #$i in `$copy'"; } else { bad "short sector #$i in `$copy'"; } } elsif (!on) { bad "continuation from sector #$i in `$copy'"; } elsif ($on == $cn) { bad "final short sector #$i in both files" if $on; if ($cbuf eq $obuf) { $newst = 'copy'; } elsif ($cbuf eq "\0" x $on) { $newst = 'zero'; } else { bad "corrupted short sector #$i in `$copy'"; } } else { bad "short sector #$i in both files" } last SECTOR; } my $newst; if ($cbuf eq $obuf) { $newst = 'copy'; } elsif ($cbuf eq $ZERO) { $newst = 'zero'; } else { $newst = 'bogus'; } update $newst; $i++; } update 'end'; print $report, "\n"; exit $rc;