~ubuntu-branches/ubuntu/edgy/rsnapshot/edgy

« back to all changes in this revision

Viewing changes to rsnapshot-diff.pl

  • Committer: Bazaar Package Importer
  • Author(s): Simon Boulet
  • Date: 2006-06-05 22:03:45 UTC
  • mfrom: (3.1.1 etch)
  • Revision ID: james.westby@ubuntu.com-20060605220345-byz0jaecexc3h2m4
Tags: 1.2.9-1
* New upstream release
* Updated Free Software Foundation address in debian/copyright
* Added rsnapshot-diff man page from CVS
* Switched autotools-dev and rsync back to Build-Depends-Indep

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#!/usr/bin/perl -w
 
2
 
 
3
##############################################################################
 
4
# rsnapshot-diff
 
5
# by David Cantrell <david@cantrell.org.uk>
 
6
#
 
7
# This program calculates the differences between two directories. It is
 
8
# designed to work with two different subdirectories under the rsnapshot
 
9
# snapshot_root. For example:
 
10
#
 
11
#   rsnapshot-diff /.snapshots/daily.0/ /.snapshots/daily.1/
 
12
#
 
13
# http://www.rsnapshot.org/
 
14
##############################################################################
 
15
 
 
16
# $Id: rsnapshot-diff.pl,v 1.3 2006/05/31 19:51:03 drhyde Exp $
 
17
 
 
18
=head1 NAME
 
19
 
 
20
rsnapshot-diff - a utility for comparing the disk usage of two snapshots
 
21
taken by rsnapshot
 
22
 
 
23
=cut
 
24
 
 
25
use strict;
 
26
 
 
27
use constant DEBUG => 0;
 
28
use Getopt::Std;
 
29
 
 
30
my $program_name = 'rsnapshot-diff';
 
31
 
 
32
my %opts;
 
33
my $verbose = 0;
 
34
my $ignore = 0;
 
35
 
 
36
my $result = getopts('vVhi', \%opts);
 
37
 
 
38
# help
 
39
if ($opts{'h'}) {
 
40
    print qq{
 
41
    $program_name [-vVhi] dir1 dir2
 
42
 
 
43
    $program_name shows the differences between two 'rsnapshot' backups.
 
44
 
 
45
    -h    show this help
 
46
    -v    be verbose
 
47
    -V    be more verbose (mutter about unchanged files)
 
48
    -i    ignore symlinks, directories, and special files in verbose output
 
49
    dir1  the first directory to look at
 
50
    dir2  the second directory to look at
 
51
 
 
52
    if you want to look at directories called '-h' or '-v' pass a
 
53
    first parameter of '--'.
 
54
 
 
55
    $program_name always show the changes made starting from the older
 
56
    of the two directories.
 
57
};
 
58
        exit;
 
59
}
 
60
 
 
61
=head1 SYNOPSIS
 
62
 
 
63
rsnapshot-diff [-h|vVi] dir1 dir2
 
64
 
 
65
=head1 DESCRIPTION
 
66
 
 
67
rsnapshot-diff is a companion utility for rsnapshot, which traverses two
 
68
parallel directory structures and calculates the difference between them.
 
69
By default it is silent apart from displaying summary information at the
 
70
end, but it can be made more verbose.
 
71
 
 
72
In the summary, "added" files may very well include files which at first
 
73
glance also appear at the same place in the older directory structure.
 
74
However, because the files differ in some respect, they are different files.
 
75
They have a different inode number.  Consequently if you use -v most of its
 
76
output may appear to be pairs of files with the same name being removed
 
77
and added.
 
78
 
 
79
=head1 OPTIONS
 
80
 
 
81
=over 4
 
82
 
 
83
=item -h (help)
 
84
 
 
85
Displays help information
 
86
 
 
87
=item -v (verbose)
 
88
 
 
89
Be verbose.  This will spit out a list of all changes as they are encountered,
 
90
as well as the summary at the end.
 
91
 
 
92
=item -V (more verbose)
 
93
 
 
94
Be more verbose - as well as listed changes, unchanged files will be listed
 
95
too.
 
96
 
 
97
=item -i (ignore)
 
98
 
 
99
If verbosity is turned on, -i suppresses information about symlinks,
 
100
directories, and special files.
 
101
 
 
102
=item dir1 and dir2
 
103
 
 
104
These are the only compulsory parameters, and should be the names of two
 
105
directories to compare.  Their order doesn't matter, rsnapshot-diff will
 
106
always compare the younger to the older, so files that appear only in the
 
107
older will be reported as having been removed, and files that appear only
 
108
in the younger will be reported as having been added.
 
109
 
 
110
=back
 
111
 
 
112
=cut
 
113
 
 
114
# verbose
 
115
if ($opts{'v'}) { $verbose = 1; }
 
116
 
 
117
# extra verbose
 
118
if ($opts{'V'}) { $verbose = 2; }
 
119
 
 
120
# ignore
 
121
if ($opts{'i'}) { $ignore = 1; }
 
122
 
 
123
 
 
124
if(!exists($ARGV[1]) || !-d $ARGV[0] || !-d $ARGV[1]) {
 
125
    die("$program_name\nUsage: $program_name [-vVhi] dir1 dir2\nType $program_name -h for details\n");
 
126
}
 
127
 
 
128
my($dirold, $dirnew) = @ARGV;
 
129
($dirold, $dirnew) = ($dirnew, $dirold) if(-M $dirold < -M $dirnew);
 
130
print "Comparing $dirold to $dirnew\n";
 
131
 
 
132
my($addedfiles, $addedspace, $deletedfiles, $deletedspace) = (0, 0, 0, 0);
 
133
 
 
134
compare_dirs($dirold, $dirnew);
 
135
 
 
136
print "Between $dirold and $dirnew:\n";
 
137
print "  $addedfiles were added, taking $addedspace bytes;\n";
 
138
print "  $deletedfiles were removed, saving $deletedspace bytes;\n";
 
139
 
 
140
sub compare_dirs {
 
141
    my($old, $new) = @_;
 
142
 
 
143
    opendir(OLD, $old) || die("Can't open dir $old\n");
 
144
    opendir(NEW, $new) || die("Can't open dir $new\n");
 
145
    my %old = map {
 
146
        my $fn = $old.'/'.$_;
 
147
        ($_, (mystat($fn))[1])
 
148
    } grep { $_ ne '.' && $_ ne '..' } readdir(OLD);
 
149
    my %new = map {
 
150
        my $fn = $new.'/'.$_;
 
151
        ($_, (mystat($fn))[1])
 
152
    } grep { $_ ne '.' && $_ ne '..' } readdir(NEW);
 
153
    closedir(OLD);
 
154
    closedir(NEW);
 
155
 
 
156
    my @added = grep { !exists($old{$_}) } keys %new;
 
157
    my @deleted = grep { !exists($new{$_}) } keys %old;
 
158
    my @changed = grep { !-d $new.'/'.$_ && exists($old{$_}) && $old{$_} != $new{$_} } keys %new;
 
159
 
 
160
    add(map { $new.'/'.$_ } @added, @changed);
 
161
    remove(map { $old.'/'.$_ } @deleted, @changed);
 
162
 
 
163
    if($verbose == 2) {
 
164
        my %changed = map { ($_, 1) } @changed, @added, @deleted;
 
165
        print "0 $new/$_\n" foreach(grep { !-d "$new/$_" && !exists($changed{$_}) } keys %new);
 
166
    }
 
167
    
 
168
    foreach (grep { !-l $new.'/'.$_ && !-l $old.'/'.$_ && -d $new.'/'.$_ && -d $old.'/'.$_ } keys %new) {
 
169
        print "Comparing subdirs $new/$_ and $old/$_ ...\n" if(DEBUG);
 
170
        compare_dirs($old.'/'.$_, $new.'/'.$_);
 
171
    }
 
172
}
 
173
 
 
174
sub add {
 
175
    my @added = @_;
 
176
    print "Adding ".join(', ', @added)."\n" if(DEBUG && @added);
 
177
    foreach(grep { !-d } @added) {
 
178
        $addedfiles++;
 
179
        $addedspace += (mystat($_))[7];
 
180
        # if ignore is on, only print files
 
181
        unless ($ignore && (-l || !-f)) {
 
182
            print "+ $_\n" if($verbose);
 
183
        }
 
184
    }
 
185
    foreach my $dir (grep { !-l && -d } @added) {
 
186
        opendir(DIR, $dir) || die("Can't open dir $dir\n");
 
187
        add(map { $dir.'/'.$_ } grep { $_ ne '.' && $_ ne '..' } readdir(DIR))
 
188
    }
 
189
}
 
190
 
 
191
sub remove {
 
192
    my @removed = @_;
 
193
    print "Removing ".join(', ', @removed)."\n" if(DEBUG && @removed);
 
194
    foreach(grep { !-d } @removed) {
 
195
        $deletedfiles++;
 
196
        $deletedspace += (mystat($_))[7];
 
197
        # if ignore is on, only print files
 
198
        unless ($ignore && (-l || !-f)) {
 
199
            print "- $_\n" if($verbose);
 
200
        }
 
201
    }
 
202
    foreach my $dir (grep { !-l && -d } @removed) {
 
203
        opendir(DIR, $dir) || die("Can't open dir $dir\n");
 
204
        remove(map { $dir.'/'.$_ } grep { $_ ne '.' && $_ ne '..' } readdir(DIR))
 
205
    }
 
206
}
 
207
 
 
208
{
 
209
    my $device;
 
210
 
 
211
    sub mystat {
 
212
        local $_ = shift;
 
213
        my @stat = (-l) ? lstat() : stat();
 
214
 
 
215
        # on first stat, memorise device
 
216
        $device = $stat[0] unless(defined($device));
 
217
        die("Can't compare across devices.\n(looking at $_)\n")
 
218
            unless($device == $stat[0] || -p $_);
 
219
 
 
220
        return @stat;
 
221
    }
 
222
}
 
223
 
 
224
=head1 SEE ALSO
 
225
 
 
226
rsnapshot
 
227
 
 
228
=head1 BUGS
 
229
 
 
230
Please report bugs (and other comments) to the rsnapshot-discuss mailing list:
 
231
 
 
232
L<http://lists.sourceforge.net/lists/listinfo/rsnapshot-discuss>
 
233
 
 
234
=head1 AUTHOR
 
235
 
 
236
David Cantrell E<lt>david@cantrell.org.ukE<gt>
 
237
 
 
238
=head1 COPYRIGHT
 
239
 
 
240
Copyright 2005 David Cantrell
 
241
 
 
242
=head1 LICENCE
 
243
 
 
244
This program is free software; you can redistribute it and/or modify
 
245
it under the terms of the GNU General Public License as published by
 
246
the Free Software Foundation; either version 2 of the License, or
 
247
(at your option) any later version.
 
248
 
 
249
This program is distributed in the hope that it will be useful,
 
250
but WITHOUT ANY WARRANTY; without even the implied warranty of
 
251
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
252
GNU General Public License for more details.
 
253
 
 
254
You should have received a copy of the GNU General Public License along
 
255
with this program; if not, write to the Free Software Foundation, Inc.,
 
256
51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA
 
257
 
 
258
=cut