Improved the rsyncsums script to have a --check mode.
authorWayne Davison <wayned@samba.org>
Mon, 29 Oct 2007 20:44:16 +0000 (20:44 +0000)
committerWayne Davison <wayned@samba.org>
Mon, 29 Oct 2007 20:44:16 +0000 (20:44 +0000)
checksum4mirrors.diff

index 6ff006d53413ff67f8a2e6c2a04906f0d3bbbf4c..dd390267d29bac5a1ccb833544202266db6665a3 100644 (file)
@@ -295,7 +295,7 @@ To use this patch, run these commands for a successful build:
        return isprint(*(unsigned char *)ptr);
 --- old/support/rsyncsums
 +++ new/support/rsyncsums
-@@ -0,0 +1,183 @@
+@@ -0,0 +1,203 @@
 +#!/usr/bin/perl -w
 +use strict;
 +
@@ -308,8 +308,9 @@ To use this patch, run these commands for a successful build:
 +
 +&Getopt::Long::Configure('bundling');
 +&usage if !&GetOptions(
-+    'simple-cmp|s' => \( my $ignore_ctime_and_inode ),
 +    'recurse|r' => \( my $recurse_opt ),
++    'simple-cmp|s' => \( my $ignore_ctime_and_inode ),
++    'check|c' => \( my $check_opt ),
 +    'verbose|v+' => \( my $verbosity = 0 ),
 +    'help|h' => \( my $help_opt ),
 +);
@@ -325,6 +326,8 @@ To use this patch, run these commands for a successful build:
 +
 +$| = 1;
 +
++my $exit_code = 0;
++
 +my $md4 = Digest::MD4->new;
 +my $md5 = Digest::MD5->new;
 +
@@ -340,16 +343,28 @@ To use this patch, run these commands for a successful build:
 +      next;
 +    }
 +
++    my $reldir = $dir;
++    $reldir =~ s#^$start_dir(/|$)# $1 ? '' : '.' #eo;
 +    if ($verbosity) {
-+      my $reldir = $dir;
-+      $reldir =~ s#^$start_dir(/|$)# $1 ? '' : '.' #eo;
 +      print "$reldir ... ";
++      print "\n" if $check_opt;
 +    }
 +
-+    my $sums_file_exists = -e $SUMS_FILE;
 +    my %cache;
++    my $f_cnt = 0;
++    if (open(FP, '<', $SUMS_FILE)) {
++      while (<FP>) {
++          chomp;
++          my($sum4, $sum5, $size, $mtime, $ctime, $inode, $fn) = split(' ', $_, 7);
++          $cache{$fn} = [ 0, $sum4, $sum5, $size, $mtime, $ctime & 0xFFFFFFFF, $inode & 0xFFFFFFFF ];
++          $f_cnt++;
++      }
++      close FP;
++    }
++
 +    my @subdirs;
-+    my $cnt = 0;
++    my $d_cnt = 0;
++    my $update_cnt = 0;
 +    while (defined(my $fn = readdir(DP))) {
 +      next if $fn =~ /^\.\.?$/ || $fn =~ /^\Q$SUMS_FILE\E$/o || -l $fn;
 +      if (-d _) {
@@ -359,114 +374,118 @@ To use this patch, run these commands for a successful build:
 +      next unless -f _;
 +
 +      my($size,$mtime,$ctime,$inode) = (stat(_))[7,9,10,1];
-+      next if $size == 0;
-+
-+      $cache{$fn} = [ $size, $mtime, $ctime & 0xFFFFFFFF, $inode & 0xFFFFFFFF ];
-+      $cnt++;
-+    }
-+
-+    closedir DP;
-+
-+    unshift(@dirs, sort @subdirs) if $recurse_opt;
-+
-+    if (!$cnt) {
-+      if ($sums_file_exists) {
-+          print "(removed $SUMS_FILE) " if $verbosity;
-+          unlink($SUMS_FILE);
++      my $ref = $cache{$fn};
++      if ($size == 0) {
++          if (defined $ref) {
++              delete $cache{$fn};
++              $f_cnt--;
++              if (!$check_opt && !$update_cnt++) {
++                  print "UPDATING\n" if $verbosity;
++              }
++          }
++          next;
 +      }
-+      print "empty\n" if $verbosity;
-+      next;
-+    }
++      $d_cnt++;
 +
-+    if (open(FP, '+<', $SUMS_FILE)) {
-+      while (<FP>) {
-+          chomp;
-+          my($sum4, $sum5, $size, $mtime, $ctime, $inode, $fn) = split(' ', $_, 7);
-+          my $ref = $cache{$fn};
++      if (!$check_opt) {
 +          if (defined $ref) {
-+              if ($ignore_ctime_and_inode) {
-+                  $ctime = $$ref[2];
-+                  $inode = $$ref[3];
-+              }
-+              if ($$ref[0] == $size
-+               && $$ref[1] == $mtime
-+               && $$ref[2] == $ctime
-+               && $$ref[3] == $inode
-+               && $sum4 !~ /=/ && $sum5 !~ /=/) {
-+                  $$ref[4] = $sum4;
-+                  $$ref[5] = $sum5;
-+                  $cnt--;
-+              } else {
-+                  $$ref[4] = $$ref[5] = undef;
++              $$ref[0] = 1;
++              if ($$ref[3] == $size
++               && $$ref[4] == $mtime
++               && ($ignore_ctime_and_inode || ($$ref[5] == $ctime && $$ref[6] == $inode))
++               && $$ref[1] !~ /=/ && $$ref[2] !~ /=/) {
++                  next;
 +              }
-+          } else {
-+              $cnt = -1; # Force rewrite due to removed line.
++          }
++          if (!$update_cnt++) {
++              print "UPDATING\n" if $verbosity;
 +          }
 +      }
-+    } else {
-+      open(FP, '>', $SUMS_FILE) or die "Unable to write $dir/$SUMS_FILE: $!\n";
-+      $cnt = -1;
-+    }
 +
-+    if ($cnt) {
-+      print "UPDATING\n" if $verbosity;
-+      while (my($fn, $ref) = each %cache) {
-+          next if defined $$ref[3] && defined $$ref[4];
-+          if (!open(IN, $fn)) {
-+              print STDERR "Unable to read $fn: $!\n";
++      if (!open(IN, $fn)) {
++          print STDERR "Unable to read $fn: $!\n";
++          if (defined $ref) {
 +              delete $cache{$fn};
-+              next;
++              $f_cnt--;
 +          }
++          next;
++      }
 +
-+          my($size,$mtime,$ctime,$inode) = (stat(IN))[7,9,10,1];
-+          if ($size == 0) {
-+              close IN;
-+              next;
++      my($sum4, $sum5);
++      while (1) {
++          while (sysread(IN, $_, 64*1024)) {
++              $md4->add($_);
++              $md5->add($_);
 +          }
++          $sum4 = $md4->hexdigest;
++          $sum5 = $md5->hexdigest;
++          print " $sum4 $sum5" if $verbosity > 2;
++          print " $fn" if $verbosity > 1;
++          my($size2,$mtime2,$ctime2,$inode2) = (stat(IN))[7,9,10,1];
++          last if $size == $size2 && $mtime == $mtime2
++           && ($ignore_ctime_and_inode || ($ctime == $ctime2 && $inode == $inode2));
++          $size = $size2;
++          $mtime = $mtime2;
++          $ctime = $ctime2;
++          $inode = $inode2;
++          sysseek(IN, 0, 0);
++          print " REREADING\n" if $verbosity > 1;
++      }
 +
-+          my($sum4, $sum5);
-+          while (1) {
-+              while (sysread(IN, $_, 64*1024)) {
-+                  $md4->add($_);
-+                  $md5->add($_);
-+              }
-+              $sum4 = $md4->hexdigest;
-+              $sum5 = $md5->hexdigest;
-+              print " $sum4 $sum5" if $verbosity > 2;
-+              print " $fn\n" if $verbosity > 1;
-+              my($size2,$mtime2,$ctime2,$inode2) = (stat(IN))[7,9,10,1];
-+              if ($ignore_ctime_and_inode) {
-+                  $ctime = $ctime2;
-+                  $inode = $inode2;
-+              }
-+              last if $size == $size2 && $mtime == $mtime2
-+                   && $ctime == $ctime2 && $inode == $inode2;
-+              $size = $size2;
-+              $mtime = $mtime2;
-+              $ctime = $ctime2;
-+              $inode = $inode2;
-+              sysseek(IN, 0, 0);
++      close IN;
++
++      if ($check_opt) {
++          my $dif;
++          if (!defined $ref) {
++              $dif = 'MISSING';
++          } elsif ($sum4 ne $$ref[1] || $sum5 ne $$ref[2]) {
++              $dif = 'FAILED';
++          } else {
++              print " OK\n" if $verbosity > 1;
++              next;
++          }
++          if ($verbosity < 2) {
++              print $verbosity ? ' ' : "$reldir/";
++              print $fn;
 +          }
-+          
-+          close IN;
++          print " $dif\n";
++          $exit_code = 1;
++      } else {
++          print "\n" if $verbosity > 1;
++          $cache{$fn} = [ 1, $sum4, $sum5, $size, $mtime, $ctime & 0xFFFFFFFF, $inode & 0xFFFFFFFF ];
++      }
++    }
++
++    closedir DP;
 +
-+          $cache{$fn} = [ $size, $mtime, $ctime, $inode, $sum4, $sum5 ];
++    unshift(@dirs, sort @subdirs) if $recurse_opt;
++
++    if ($check_opt) {
++      ;
++    } elsif ($d_cnt == 0) {
++      if ($f_cnt) {
++          print "(removed $SUMS_FILE) " if $verbosity;
++          unlink($SUMS_FILE);
 +      }
++      print "empty\n" if $verbosity;
++    } elsif ($update_cnt || $d_cnt != $f_cnt) {
++      print "UPDATING\n" if $verbosity && !$update_cnt;
++      open(FP, '>', $SUMS_FILE) or die "Unable to write $dir/$SUMS_FILE: $!\n";
 +
-+      seek(FP, 0, 0);
 +      foreach my $fn (sort keys %cache) {
 +          my $ref = $cache{$fn};
-+          my($size, $mtime, $ctime, $inode, $sum4, $sum5) = @$ref;
++          my($found, $sum4, $sum5, $size, $mtime, $ctime, $inode) = @$ref;
++          next unless $found;
 +          printf FP '%s %s %10d %10d %10d %10d %s' . "\n", $sum4, $sum5, $size, $mtime, $ctime, $inode, $fn;
 +      }
-+      truncate(FP, tell(FP));
++      close FP;
 +    } else {
 +      print "ok\n" if $verbosity;
 +    }
-+
-+    close FP;
 +}
 +
++exit $exit_code;
++
 +sub usage
 +{
 +    die <<EOT;
@@ -475,6 +494,7 @@ To use this patch, run these commands for a successful build:
 +Options:
 + -r, --recurse     Update $SUMS_FILE files in subdirectories too.
 + -s, --simple-cmp  Ignore ctime and inode values when comparing identicality.
++ -c, --check       Check if the checksums are right (doesn't update).
 + -v, --verbose     Mention what we're doing.  Repeat for more info.
 + -h, --help        Display this help message.
 +EOT