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 Data::Dumper;
8 use FindBin;
9 use Getopt::Std;
10
11
12 my %opts;
13 getopts('hkn', \%opts);
14
15 &usage if $opts{h} || $#ARGV!=1 || ! -d $ARGV[0] || ! -f $ARGV[1];
16 $ARGV[0]=~s/\/+$/\//;
17
18 my $md5;
19 if ($opts{m}) {
20 $md5 = (`which md5`=~/(.*)/)[0] || (`which md5sum`=~/(.*)/)[0] || die "No md5 binary found\n";
21 $md5 .= ($md5=~/md5$/ ? ' -r ' : '');
22 }
23
24 my %snap;
25 open SNAP, "<$ARGV[1]" or die $!;
26 $_ = <SNAP>;
27 /^STATE=(MD5|MTIME)$/ or die "Unknown STATE line: $_\n";
28 my $stype = $1;
29 for (map {chomp; $_} <SNAP>) {
30 next unless /^(.+?)(\s+STATE=(.+))?$/;
31 if ($2) {
32 $snap{$1} = $3;
33 } else {
34 $snap{$1} = undef;
35 }
36 }
37 close SNAP;
38
39 for (grep {$snap{$_}} keys %snap) {
40 next unless -f "$ARGV[0]/$_";
41
42 my $state;
43 if ($stype eq 'MD5') {
44 $state = (`$md5 $ARGV[0]/$_ | awk '{print \$1}'`=~/(.*)/)[0];
45 } else {
46 $state = join(':', (stat("$ARGV[0]/$_"))[1,9]) or die $!;
47 }
48
49 if ($snap{$_} eq $state) {
50 unlink "$ARGV[0]/$_" unless $opts{n};
51 print " removing old file: $_\n";
52 } else {
53 print " skipping modified file: $_\n";
54 }
55 }
56
57 for (sort {(length($b)<=>length($a))||($a cmp $b)} grep {!$snap{$_}} keys %snap) {
58 opendir DIR, "$ARGV[0]/$_" or die $!;
59 my @cont = readdir DIR;
60 if ($#cont==1) {
61 rmdir "$ARGV[0]/$_";
62 print " removing empty dir: $_\n";
63 } else {
64 print " skipping non-empty dir: $_\n";
65 }
66 closedir DIR;
67 }
68
69 unlink $ARGV[1] unless $opts{k} || $opts{n};
70
71
72 sub usage {
73 print <<EOM;
74 Usage: $FindBin::RealScript [options] prefix file
75
76 Options:
77 -h Print this message
78 -k Keep file
79 -n Dry-run mode
80
81 EOM
82 exit;
83 }