-
Notifications
You must be signed in to change notification settings - Fork 1
/
brackup-verify-chunks
executable file
·172 lines (126 loc) · 4.86 KB
/
brackup-verify-chunks
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
#!/usr/bin/perl
# LICENCE INFORMATION
#
# This file is part of brackup-nn, a backup tool based on Brackup.
#
# Brackup is authored by Brad Fitzpatrick <[email protected]> (and others)
# and is copyright (c) Six Apart, Ltd, with portions copyright (c) Gavin Carr
# <[email protected]> (see code for details). Brackup is licensed for
# use, modification and/or distribution under the same terms as Perl itself.
#
# This file was forked from Brackup on 18 March 2013 and changed on and since
# this date by NewsNow Publishing Limited to effect bug fixes, reliability
# stability and/or performance improvements, and/or feature enhancements;
# and such changes are copyright (c) 2013 NewsNow Publishing Limited. You may
# use, modify, and/or redistribute brackup-nn under the same terms as Perl itself.
#
=head1 NAME
brackup-verify-chunks - utility to check brackup chunk consistency on a
brackup target, reporting on errors (and optionally deleting bad chunks)
=head1 SYNOPSIS
brackup-verify-chunks [-v] [-q] [--delete] [--limit=<count>] [<brackup_dir>]
=head2 ARGUMENTS
=over 4
=item <brackup_dir>
Brackup directory root to check. Default: current directory.
=back
=head2 OPTIONS
=over 4
=item --delete
Optional. Delete invalid chunks from the tree.
=item --limit|-l=<count>
Optional. Delete no more than this many chunks (i.e. a safety check).
=item --verbose|-v
Optional. Give more verbose output.
=item --quiet|-q
Optional. Give no output except for errors.
=back
=head1 SEE ALSO
L<brackup>
L<Brackup::Manual::Overview>
=head1 AUTHOR
Gavin Carr <[email protected]>
Copyright (c) 2008-2012 Gavin Carr.
This module is free software. You may use, modify, and/or redistribute this
software under the terms of same terms as perl itself.
=cut
use strict;
use warnings;
use Cwd;
use Getopt::Long;
use File::Find::Rule;
use Digest::SHA1 qw(sha1_hex);
$|=1;
sub usage { die "brackup-verify-chunks [-q|-v] [--delete] [--limit=<count>] [<brackup_dir>]\nbrackup-verify-chunks --help\n" }
my ($opt_help, $opt_quiet, $opt_verbose, $opt_delete, $opt_limit);
usage() unless
GetOptions(
'delete' => \$opt_delete,
'limit|l=i' => \$opt_limit,
'verbose|v+' => \$opt_verbose,
'quiet|q' => \$opt_quiet,
'help|h|?' => \$opt_help,
);
if ($opt_help) {
eval "use Pod::Usage;";
Pod::Usage::pod2usage( -verbose => 1, -exitval => 0 );
exit 0;
}
usage() unless @ARGV < 2;
my $dir = shift @ARGV || cwd;
chdir $dir or die "Failed to chdir to $dir: $!\n";
if ($opt_limit && ! $opt_delete) {
warn "--limit is only used with --delete - ignoring\n";
}
my $deleting = $opt_delete ? ' - deleting' : '';
my $total = 0;
if ($opt_verbose) {
print "Counting chunks ... ";
File::Find::Rule->name('*.chunk')->file()->exec(sub { $total++ })->in($dir);
print "found $total\n";
$total /= 100;
}
my ($count, $ok, $bad, $deleted) = (0, 0, 0, 0);
File::Find::Rule->name('*.chunk')
->file()
->exec( sub {
my ($shortname, $path, $fullname) = @_;
$path =~ s!^$dir/?!!;
open my $fh, '<', $fullname
or die "Cannot open '$fullname': $!";
my $text = '';
{
local $/;
$text = <$fh>;
}
close $fh;
my $calc_sum = sha1_hex($text);
my ($name_sum) = $shortname =~ m/^sha1[:\.]([0-9A-F]+)/i;
if ($opt_verbose && $opt_verbose == 1) {
printf "Checked %s chunks (%0.1f%%)\n", $count, $count / $total
if $count && $count % 100 == 0;
}
elsif ($opt_verbose && $opt_verbose >= 2) {
printf "Checking %s, checksum %s (%0.01f%%)\n",
"$path/$shortname", $name_sum eq $calc_sum ? 'ok' : $calc_sum,
$count / $total;
}
if ($name_sum ne $calc_sum) {
warn "Error: chunk $path/$shortname\n has invalid checksum ${calc_sum}$deleting\n";
$bad++;
if ($opt_delete) {
if ($opt_limit && $deleted >= $opt_limit) {
die "Delete limit exceeded - check terminating\n";
}
unlink $fullname;
$deleted++;
}
} else {
$ok++;
}
$count++;
})
->in($dir);
print "Checked $count chunks: $ok good, $bad bad.\n" unless $opt_quiet;
exit $bad ? 1 : 0;
# vim:sw=4