File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / rsync / support / xsums
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Mar 17 00:32:36 2021 UTC (3 years, 3 months ago) by misho
Branches: rsync, MAIN
CVS tags: v3_2_3, HEAD
rsync 3.2.3

    1: #!/usr/bin/perl -w
    2: use strict;
    3: 
    4: use Getopt::Long;
    5: use Cwd qw(abs_path cwd);
    6: use Digest::MD4;
    7: use Digest::MD5;
    8: use File::ExtAttr ':all';
    9: 
   10: &Getopt::Long::Configure('bundling');
   11: &usage if !&GetOptions(
   12:     'recurse|r' => \( my $recurse_opt ),
   13:     'list|l' => \( my $list_opt ),
   14:     'check|c' => \( my $check_opt ),
   15:     'verbose|v+' => \( my $verbosity = 0 ),
   16:     'help|h' => \( my $help_opt ),
   17: );
   18: &usage if $help_opt;
   19: 
   20: my $start_dir = cwd();
   21: 
   22: my @dirs = @ARGV;
   23: @dirs = '.' unless @dirs;
   24: foreach (@dirs) {
   25:     $_ = abs_path($_);
   26: }
   27: 
   28: $| = 1;
   29: 
   30: my $exit_code = 0;
   31: 
   32: my $md4 = Digest::MD4->new;
   33: my $md5 = Digest::MD5->new;
   34: 
   35: while (@dirs) {
   36:     my $dir = shift @dirs;
   37: 
   38:     if (!chdir($dir)) {
   39: 	warn "Unable to chdir to $dir: $!\n";
   40: 	next;
   41:     }
   42:     if (!opendir(DP, '.')) {
   43: 	warn "Unable to opendir $dir: $!\n";
   44: 	next;
   45:     }
   46: 
   47:     my $reldir = $dir;
   48:     $reldir =~ s#^$start_dir(/|$)# $1 ? '' : '.' #eo;
   49:     print "$reldir ... " if $verbosity;
   50: 
   51:     my @subdirs;
   52:     my $d_cnt = 0;
   53:     my $need_newline = $verbosity;
   54:     while (defined(my $fn = readdir(DP))) {
   55: 	next if $fn =~ /^\.\.?$/ || -l $fn;
   56: 	if (-d _) {
   57: 	    push(@subdirs, "$dir/$fn");
   58: 	    next;
   59: 	}
   60: 	next unless -f _;
   61: 	$d_cnt++;
   62: 
   63: 	my($size,$mtime,$ctime) = (stat(_))[7,9,10];
   64: 
   65: 	my $xsum4 = getfattr($fn, 'rsync.%md4');
   66: 	my $xsum5 = getfattr($fn, 'rsync.%md5');
   67: 
   68: 	my $sum_count = 0;
   69: 	foreach ($xsum4, $xsum5) {
   70: 	    if (defined $_) {
   71: 		if (length($_) == 24) {
   72: 		    my($sz,$mt,$sum) = unpack('V2a16', $_);
   73: 		    if ($sz != ($size & 0xFFFFFFFF)
   74: 		     || $mt != ($mtime & 0xFFFFFFFF)) {
   75: 			$_ = undef;
   76: 		    } else {
   77: 			$_ = $sum;
   78: 			$sum_count++;
   79: 		    }
   80: 		} else {
   81: 		    $_ = undef;
   82: 		}
   83: 	    }
   84: 	}
   85: 
   86: 	if ($list_opt) {
   87: 	    if ($need_newline) {
   88: 		print "\n";
   89: 		$need_newline = 0;
   90: 	    }
   91: 	    if (defined $xsum4) {
   92: 		print ' ', unpack('H32', $xsum4);
   93: 	    } else {
   94: 		print ' ' x (1 + 32);
   95: 	    }
   96: 	    if (defined $xsum5) {
   97: 		print ' ', unpack('H32', $xsum5);
   98: 	    } else {
   99: 		print ' ' x (1 + 32);
  100: 	    }
  101: 	    print $verbosity ? ' ' : " $reldir/";
  102: 	    print $fn, "\n";
  103: 	    next;
  104: 	}
  105: 
  106: 	if ($check_opt) {
  107: 	    if (!$sum_count) {
  108: 		if ($need_newline) {
  109: 		    print "\n";
  110: 		    $need_newline = 0;
  111: 		}
  112: 		print ' ' x (1 + 32 + 1 + 32) if $verbosity > 2;
  113: 		print $verbosity ? ' ' : "$reldir/";
  114: 		print $fn, " MISSING\n";
  115: 		next;
  116: 	    }
  117: 	} else {
  118: 	    next if $sum_count == 2;
  119: 	    print 'UPDATING' if $need_newline && $verbosity == 1;
  120: 	}
  121: 
  122: 	if ($need_newline && (!$check_opt || $verbosity > 1)) {
  123: 	    print "\n";
  124: 	    $need_newline = 0;
  125: 	}
  126: 
  127: 	if (!open(IN, $fn)) {
  128: 	    print STDERR "Unable to read $fn: $!\n";
  129: 	    next;
  130: 	}
  131: 
  132: 	my($sum4, $sum5);
  133: 	while (1) {
  134: 	    while (sysread(IN, $_, 64*1024)) {
  135: 		$md4->add($_);
  136: 		$md5->add($_);
  137: 	    }
  138: 	    $sum4 = $md4->digest;
  139: 	    $sum5 = $md5->digest;
  140: 	    print ' ', unpack('H32', $sum4), ' ', unpack('H32', $sum5) if $verbosity > 2;
  141: 	    print " $fn" if $verbosity > 1;
  142: 	    my($size2,$mtime2,$ctime2) = (stat(IN))[7,9,10];
  143: 	    last if $size == $size2 && $mtime == $mtime2 && $ctime == $ctime2;
  144: 	    $size = $size2;
  145: 	    $mtime = $mtime2;
  146: 	    $ctime = $ctime2;
  147: 	    sysseek(IN, 0, 0);
  148: 	    print " REREADING\n" if $verbosity > 1;
  149: 	}
  150: 
  151: 	close IN;
  152: 
  153: 	if ($check_opt) {
  154: 	    if ((!defined $xsum4 || $xsum4 eq $sum4) && (!defined $xsum5 || $xsum5 eq $sum5)) {
  155: 		print " OK\n" if $verbosity > 1;
  156: 		next;
  157: 	    }
  158: 	    if ($need_newline) {
  159: 		print "\n";
  160: 		$need_newline = 0;
  161: 	    }
  162: 	    if ($verbosity < 2) {
  163: 		print $verbosity ? ' ' : "$reldir/";
  164: 		print $fn;
  165: 	    }
  166: 	    print " FAILED\n";
  167: 	    $exit_code = 1;
  168: 	} else {
  169: 	    print "\n" if $verbosity > 1;
  170: 	    my $szmt = pack('V2', $size, $mtime); # 32-bits, may truncate
  171: 	    setfattr($fn, 'rsync.%md4', $szmt.$sum4);
  172: 	    setfattr($fn, 'rsync.%md5', $szmt.$sum5);
  173: 	    #utime $mtime, $mtime, $fn; # Set mtime if it changes.
  174: 	}
  175:     }
  176: 
  177:     if ($need_newline) {
  178: 	if ($d_cnt) {
  179: 	    print "ok\n";
  180: 	} else {
  181: 	    print "empty\n";
  182: 	}
  183:     }
  184: 
  185:     closedir DP;
  186: 
  187:     unshift(@dirs, sort @subdirs) if $recurse_opt;
  188: }
  189: 
  190: exit $exit_code;
  191: 
  192: sub usage
  193: {
  194:     die <<EOT;
  195: Usage: rsyncsums [OPTIONS] [DIRS]
  196: 
  197: Options:
  198:  -r, --recurse     Update checksums in subdirectories too.
  199:  -l, --list        List the checksums for each file (doesn't update).
  200:  -c, --check       Check if the checksums are right (doesn't update).
  201:  -v, --verbose     Mention what we're doing.  Repeat for more info.
  202:  -h, --help        Display this help message.
  203: EOT
  204: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>