Annotation of embedaddon/rsync/support/xsums, revision 1.1
1.1 ! misho 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>