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