Line # Revision Author
1 3 ahitrov@rambler.ru #!/usr/bin/perl
2
3 use strict;
4 use warnings 'all';
5 use locale;
6
7 use Getopt::Std;
8 use FindBin;
9
10
11 my %opts;
12 getopts('hd:km', \%opts);
13
14 &usage if $opts{h} || $#ARGV || ! -d $ARGV[0];
15 $ARGV[0]=~s/\/+$/\//;
16
17 my $md5;
18 if ($opts{m}) {
19 $md5 = (`which md5`=~/(.*)/)[0] || (`which md5sum`=~/(.*)/)[0] || die "No md5 binary found\n";
20 $md5 .= ($md5=~/md5$/ ? ' -r ' : '');
21 }
22
23 my %snap;
24 for (grep {$_} map {chomp; s/^$ARGV[0]\///; $_} `find $ARGV[0]`) {
25 unless (-f "$ARGV[0]/$_") {
26 $snap{$_} = undef;
27 next;
28 }
29
30 if ($opts{m}) {
31 $snap{$_} = (`$md5 $ARGV[0]/$_ | awk '{print \$1}'`=~/(.*)/)[0];
32 } else {
33 $snap{$_} = join(':', (stat("$ARGV[0]/$_"))[1,9]) or die $!;
34 }
35 }
36
37 unless ($opts{d}) {
38 print 'STATE='.($opts{m} ? 'MD5' : 'MTIME')."\n";
39 print $_.($snap{$_} ? ' STATE='.$snap{$_} : '')."\n" for sort keys %snap;
40 exit;
41 }
42
43 my %base;
44 open BASE, "<$opts{d}" or die $!;
45 $_ = <BASE>;
46 /^STATE=(MD5|MTIME)$/ or die "Unknown STATE line: $_\n";
47 die "Incompatible mode: $1\n" unless ($opts{m} && $1 eq 'MD5') || (!$opts{m} && $1 eq 'MTIME');
48 for (map {chomp; $_} <BASE>) {
49 if (/^(.+)\s+STATE=(.+)$/) {
50 $base{$1} = $2;
51 next;
52 }
53 $base{$_} = undef;
54 }
55 close BASE;
56
57 print 'STATE='.($opts{m} ? 'MD5' : 'MTIME')."\n";
58 for (sort keys %snap) {
59 next if exists $base{$_} && ($base{$_}||'') eq ($snap{$_}||'');
60 print $_.($snap{$_} ? ' STATE='.$snap{$_} : '')."\n";
61 }
62
63 unlink $opts{d} unless $opts{k};
64
65 sub usage {
66 print <<EOM;
67 Usage: $FindBin::RealScript [options] directory
68
69 Options:
70 -d file Deltify relative to file content
71 -h Print this message
72 -k Keep file specified with -d option
73 -m Use MD5 sum instead mtime checking
74
75 EOM
76 exit;
77 }