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>