line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
# -*-perl-*- |
2
|
|
|
|
|
|
|
# Creation date: 2003-03-09 15:38:36 |
3
|
|
|
|
|
|
|
# Authors: Don |
4
|
|
|
|
|
|
|
# Change log: |
5
|
|
|
|
|
|
|
# $Id: Backup.pm,v 1.33 2007/12/14 03:37:30 don Exp $ |
6
|
|
|
|
|
|
|
# |
7
|
|
|
|
|
|
|
# Copyright (c) 2003-2007 Don Owens. All rights reserved. |
8
|
|
|
|
|
|
|
# |
9
|
|
|
|
|
|
|
# This is free software; you can redistribute it and/or modify it under |
10
|
|
|
|
|
|
|
# the Perl Artistic license. You should have received a copy of the |
11
|
|
|
|
|
|
|
# Artistic license with this distribution, in the file named |
12
|
|
|
|
|
|
|
# "Artistic". You may also obtain a copy from |
13
|
|
|
|
|
|
|
# http://regexguy.com/license/Artistic |
14
|
|
|
|
|
|
|
# |
15
|
|
|
|
|
|
|
# This program is distributed in the hope that it will be |
16
|
|
|
|
|
|
|
# useful, but WITHOUT ANY WARRANTY; without even the implied |
17
|
|
|
|
|
|
|
# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR |
18
|
|
|
|
|
|
|
# PURPOSE. |
19
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
=pod |
21
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
=head1 NAME |
23
|
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
File::Rotate::Backup - Make backups of multiple directories and |
25
|
|
|
|
|
|
|
rotate them on unix. |
26
|
|
|
|
|
|
|
|
27
|
|
|
|
|
|
|
=head1 SYNOPSIS |
28
|
|
|
|
|
|
|
|
29
|
|
|
|
|
|
|
my $params = { archive_copies => 2, |
30
|
|
|
|
|
|
|
dir_copies => 1, |
31
|
|
|
|
|
|
|
backup_dir => '/backups', |
32
|
|
|
|
|
|
|
file_prefix => 'backup_' |
33
|
|
|
|
|
|
|
secondary_backup_dir => '/backups2', |
34
|
|
|
|
|
|
|
secondary_archive_copies => 2, |
35
|
|
|
|
|
|
|
verbose => 1, |
36
|
|
|
|
|
|
|
use_flock => 1, |
37
|
|
|
|
|
|
|
}; |
38
|
|
|
|
|
|
|
|
39
|
|
|
|
|
|
|
my $backup = File::Rotate::Backup->new($params); |
40
|
|
|
|
|
|
|
|
41
|
|
|
|
|
|
|
$backup->backup([ [ '/etc/httpd/conf' => 'httpd_conf' ], |
42
|
|
|
|
|
|
|
[ '/var/named' => 'named' ], |
43
|
|
|
|
|
|
|
]); |
44
|
|
|
|
|
|
|
|
45
|
|
|
|
|
|
|
$backup->rotate; |
46
|
|
|
|
|
|
|
|
47
|
|
|
|
|
|
|
=head1 DESCRIPTION |
48
|
|
|
|
|
|
|
|
49
|
|
|
|
|
|
|
This module will make backups and rotate them according to your |
50
|
|
|
|
|
|
|
specification. It creates a backup directory based on the |
51
|
|
|
|
|
|
|
file_prefix you specify and the current time. It then copies the |
52
|
|
|
|
|
|
|
directories you specified in the call to new() to that backup |
53
|
|
|
|
|
|
|
directory. Then a tar'd and compressed file is created from that |
54
|
|
|
|
|
|
|
directory. By default, bzip2 is used for compression. |
55
|
|
|
|
|
|
|
|
56
|
|
|
|
|
|
|
This module has only been tested on Linux and Solaris. |
57
|
|
|
|
|
|
|
|
58
|
|
|
|
|
|
|
The only external programs used are tar and a compression |
59
|
|
|
|
|
|
|
program. Copies and deletes are implemented internally. |
60
|
|
|
|
|
|
|
|
61
|
|
|
|
|
|
|
=head1 METHODS |
62
|
|
|
|
|
|
|
|
63
|
|
|
|
|
|
|
=cut |
64
|
|
|
|
|
|
|
|
65
|
1
|
|
|
1
|
|
6232
|
use strict; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
33
|
|
66
|
1
|
|
|
1
|
|
7
|
use File::Find (); |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
32
|
|
67
|
|
|
|
|
|
|
# use File::Copy (); |
68
|
|
|
|
|
|
|
|
69
|
|
|
|
|
|
|
{ package File::Rotate::Backup; |
70
|
|
|
|
|
|
|
|
71
|
1
|
|
|
1
|
|
6
|
use vars qw($VERSION); |
|
1
|
|
|
|
|
5
|
|
|
1
|
|
|
|
|
50
|
|
72
|
|
|
|
|
|
|
|
73
|
|
|
|
|
|
|
BEGIN { |
74
|
1
|
|
|
1
|
|
15
|
$VERSION = '0.13'; # update below in POD as well |
75
|
|
|
|
|
|
|
} |
76
|
|
|
|
|
|
|
|
77
|
1
|
|
|
1
|
|
1623
|
use File::Rotate::Backup::Copy; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
3127
|
|
78
|
|
|
|
|
|
|
|
79
|
|
|
|
|
|
|
=pod |
80
|
|
|
|
|
|
|
|
81
|
|
|
|
|
|
|
=head2 new(\%params) |
82
|
|
|
|
|
|
|
|
83
|
|
|
|
|
|
|
my $params = { archive_copies => 2, |
84
|
|
|
|
|
|
|
dir_copies => 1, |
85
|
|
|
|
|
|
|
backup_dir => '/backups', |
86
|
|
|
|
|
|
|
file_prefix => 'backup_' |
87
|
|
|
|
|
|
|
secondary_backup_dir => '/backups2', |
88
|
|
|
|
|
|
|
secondary_archive_copies => 2, |
89
|
|
|
|
|
|
|
verbose => 1, |
90
|
|
|
|
|
|
|
use_flock => 1, |
91
|
|
|
|
|
|
|
dir_regex => '\d+-\d+-\d+_\d+_\d+_\d+', |
92
|
|
|
|
|
|
|
file_regex => '\d+-\d+-\d+_\d+_\d+_\d+', |
93
|
|
|
|
|
|
|
}; |
94
|
|
|
|
|
|
|
|
95
|
|
|
|
|
|
|
my $backup = File::Rotate::Backup->new($params); |
96
|
|
|
|
|
|
|
|
97
|
|
|
|
|
|
|
Creates a backup object. |
98
|
|
|
|
|
|
|
|
99
|
|
|
|
|
|
|
=over 4 |
100
|
|
|
|
|
|
|
|
101
|
|
|
|
|
|
|
=item archive_copies |
102
|
|
|
|
|
|
|
|
103
|
|
|
|
|
|
|
The number of old archive files to keep. |
104
|
|
|
|
|
|
|
|
105
|
|
|
|
|
|
|
=item no_archive |
106
|
|
|
|
|
|
|
|
107
|
|
|
|
|
|
|
If set to true, then no compressed archive(s) will be created |
108
|
|
|
|
|
|
|
even if archive_copies is set. |
109
|
|
|
|
|
|
|
|
110
|
|
|
|
|
|
|
=item dir_copies |
111
|
|
|
|
|
|
|
|
112
|
|
|
|
|
|
|
The number of old backup directories to keep. |
113
|
|
|
|
|
|
|
|
114
|
|
|
|
|
|
|
=item backup_dir |
115
|
|
|
|
|
|
|
|
116
|
|
|
|
|
|
|
Where backups are placed. |
117
|
|
|
|
|
|
|
|
118
|
|
|
|
|
|
|
=item file_prefix |
119
|
|
|
|
|
|
|
|
120
|
|
|
|
|
|
|
The prefix to use for the backup directories and archive files. |
121
|
|
|
|
|
|
|
When the directories and archive files are created, the name for |
122
|
|
|
|
|
|
|
each is created by appending a timestamp to the end of the file |
123
|
|
|
|
|
|
|
prefix you specify. |
124
|
|
|
|
|
|
|
|
125
|
|
|
|
|
|
|
=item secondary_backup_dir |
126
|
|
|
|
|
|
|
|
127
|
|
|
|
|
|
|
Overflow directory to copy files to before deleting them from the |
128
|
|
|
|
|
|
|
backup directory when rotating. |
129
|
|
|
|
|
|
|
|
130
|
|
|
|
|
|
|
=item secondary_archive_copies |
131
|
|
|
|
|
|
|
|
132
|
|
|
|
|
|
|
The number of archive files to keep in the secondary backup |
133
|
|
|
|
|
|
|
directory. |
134
|
|
|
|
|
|
|
|
135
|
|
|
|
|
|
|
=item verbose |
136
|
|
|
|
|
|
|
|
137
|
|
|
|
|
|
|
If set to a true value, status messages will be printed as the |
138
|
|
|
|
|
|
|
files are being processed. |
139
|
|
|
|
|
|
|
|
140
|
|
|
|
|
|
|
=item use_flock |
141
|
|
|
|
|
|
|
|
142
|
|
|
|
|
|
|
If set to a true value, an attempt will be made to acquire a |
143
|
|
|
|
|
|
|
write lock on any file to be removed during rotation. If a lock |
144
|
|
|
|
|
|
|
cannot be acquired, the file will not be removed. This is useful |
145
|
|
|
|
|
|
|
for concurrency control, e.g., when your backup script gets run |
146
|
|
|
|
|
|
|
at the same time as another script that is writing the backups to |
147
|
|
|
|
|
|
|
tape. |
148
|
|
|
|
|
|
|
|
149
|
|
|
|
|
|
|
=item use_rm |
150
|
|
|
|
|
|
|
|
151
|
|
|
|
|
|
|
If set to a true value, the external program /bin/rm will be used |
152
|
|
|
|
|
|
|
to remove a file in the case where unlink() fails. This may |
153
|
|
|
|
|
|
|
occur on systems where the file being removed is larger than 2GB |
154
|
|
|
|
|
|
|
and such files are not fully supported. |
155
|
|
|
|
|
|
|
|
156
|
|
|
|
|
|
|
=item dir_regex |
157
|
|
|
|
|
|
|
|
158
|
|
|
|
|
|
|
Regular expression used to search for directories to rotate. The |
159
|
|
|
|
|
|
|
file_prefix is prepended to this to create the final regular |
160
|
|
|
|
|
|
|
expression. This is useful for rotating directories that were |
161
|
|
|
|
|
|
|
not created by this module. |
162
|
|
|
|
|
|
|
|
163
|
|
|
|
|
|
|
=item file_regex |
164
|
|
|
|
|
|
|
|
165
|
|
|
|
|
|
|
Regular expression used to search for archive files to rotate. |
166
|
|
|
|
|
|
|
The file_prefix is prepended to this to create the final regular |
167
|
|
|
|
|
|
|
expression. This is useful for rotating files that were not |
168
|
|
|
|
|
|
|
created by this module. |
169
|
|
|
|
|
|
|
|
170
|
|
|
|
|
|
|
=back |
171
|
|
|
|
|
|
|
|
172
|
|
|
|
|
|
|
=cut |
173
|
|
|
|
|
|
|
|
174
|
|
|
|
|
|
|
# BEGIN { |
175
|
|
|
|
|
|
|
# use vars '%Config'; |
176
|
|
|
|
|
|
|
# eval 'use Config'; |
177
|
|
|
|
|
|
|
# } |
178
|
|
|
|
|
|
|
|
179
|
|
|
|
|
|
|
sub new { |
180
|
0
|
|
|
0
|
1
|
|
my ($proto, $params) = @_; |
181
|
|
|
|
|
|
|
|
182
|
0
|
|
|
|
|
|
my $self = {}; |
183
|
0
|
|
0
|
|
|
|
bless $self, ref($proto) || $proto; |
184
|
|
|
|
|
|
|
|
185
|
0
|
0
|
|
|
|
|
$self->setArchiveCopies(defined($$params{archive_copies}) ? $$params{archive_copies} : 1); |
186
|
0
|
0
|
|
|
|
|
$self->setDirCopies(defined($$params{dir_copies}) ? $$params{dir_copies} : 1); |
187
|
0
|
|
|
|
|
|
my $dir = $$params{backup_dir}; |
188
|
0
|
0
|
|
|
|
|
$dir = '/tmp' if $dir eq ''; |
189
|
0
|
|
|
|
|
|
$self->setBackupDir($dir); |
190
|
0
|
|
|
|
|
|
$self->setSecondaryBackupDir($$params{secondary_backup_dir}); |
191
|
0
|
|
|
|
|
|
$self->setSecondaryArchiveCopies($$params{secondary_archive_copies}); |
192
|
0
|
|
|
|
|
|
$self->setFilePrefix($$params{file_prefix}); |
193
|
0
|
|
|
|
|
|
$self->_setVerbose($$params{verbose}); |
194
|
0
|
|
|
|
|
|
$self->_setUseFileLock($$params{use_flock}); |
195
|
0
|
|
|
|
|
|
$self->_setUseRm($$params{use_rm}); |
196
|
0
|
0
|
|
|
|
|
$self->{_archive_dir_regex} = $params->{dir_regex} if defined $params->{dir_regex}; |
197
|
0
|
0
|
|
|
|
|
$self->{_archive_file_regex} = $params->{file_regex} if defined $params->{file_regex}; |
198
|
0
|
0
|
|
|
|
|
$self->{_no_archive} = defined $params->{no_archive} ? $params->{no_archive} : 0; |
199
|
|
|
|
|
|
|
|
200
|
|
|
|
|
|
|
# foreach my $exe ('tar', 'gzip', 'bzip2', 'rm', 'mv') { |
201
|
|
|
|
|
|
|
# if (defined($Config{$exe}) and $Config{$exe} ne '') { |
202
|
|
|
|
|
|
|
# $self->{'_' . $exe} = $Config{$exe}; |
203
|
|
|
|
|
|
|
# } |
204
|
|
|
|
|
|
|
# } |
205
|
0
|
|
|
|
|
|
return $self; |
206
|
|
|
|
|
|
|
} |
207
|
|
|
|
|
|
|
|
208
|
|
|
|
|
|
|
=pod |
209
|
|
|
|
|
|
|
|
210
|
|
|
|
|
|
|
=head2 backup(\@conf) |
211
|
|
|
|
|
|
|
|
212
|
|
|
|
|
|
|
Makes the backup -- creates the backed up directory and archive |
213
|
|
|
|
|
|
|
file. @conf is an array where each element is either a string or |
214
|
|
|
|
|
|
|
an array. If it is a string, it is expected to be the path to a |
215
|
|
|
|
|
|
|
directory that is to be backed up. If the element is an array, |
216
|
|
|
|
|
|
|
the first element is expected to be a directory that is to be |
217
|
|
|
|
|
|
|
backed up, and the second should be the name the directory is |
218
|
|
|
|
|
|
|
called once it has been copied to the backup directory. The |
219
|
|
|
|
|
|
|
return value is the name of the archive file created; unless |
220
|
|
|
|
|
|
|
'no_archive' is set, then it will return an empty string. |
221
|
|
|
|
|
|
|
|
222
|
|
|
|
|
|
|
=cut |
223
|
|
|
|
|
|
|
sub backup { |
224
|
0
|
|
|
0
|
1
|
|
my ($self, $conf) = @_; |
225
|
|
|
|
|
|
|
|
226
|
0
|
|
|
|
|
|
my $today = $self->_getTimestampForFileName; |
227
|
0
|
|
|
|
|
|
my $file_prefix = $self->getFilePrefix . $today; |
228
|
0
|
|
|
|
|
|
my $backup_dir = $self->getBackupDir; |
229
|
0
|
|
|
|
|
|
my $dst = "$backup_dir/$file_prefix"; |
230
|
0
|
|
|
|
|
|
my $dst_file = ''; |
231
|
0
|
|
|
|
|
|
mkdir $dst, 0755; |
232
|
|
|
|
|
|
|
|
233
|
0
|
|
|
|
|
|
my $cp = $self->getCpPath; |
234
|
0
|
|
|
|
|
|
foreach my $entry (@$conf) { |
235
|
0
|
0
|
|
|
|
|
if (ref($entry) eq 'ARRAY') { |
236
|
0
|
|
|
|
|
|
my ($dir, $name) = @$entry; |
237
|
0
|
|
|
|
|
|
$self->copy($dir, "$dst/$name"); |
238
|
|
|
|
|
|
|
} else { |
239
|
0
|
|
|
|
|
|
$self->copy($entry, "$dst/"); |
240
|
|
|
|
|
|
|
} |
241
|
|
|
|
|
|
|
} |
242
|
|
|
|
|
|
|
|
243
|
0
|
0
|
|
|
|
|
unless ( $self->{_no_archive} ) |
244
|
|
|
|
|
|
|
{ |
245
|
0
|
|
|
|
|
|
my $compress = $self->getCompressProgramPath; |
246
|
0
|
|
|
|
|
|
my $ext = $self->getCompressExtension; |
247
|
0
|
0
|
|
|
|
|
$ext = '.' . $ext unless $ext eq ''; |
248
|
0
|
|
|
|
|
|
$dst_file = $dst . '.tar' . $ext; |
249
|
0
|
|
|
|
|
|
my $params = '-p'; |
250
|
0
|
0
|
|
|
|
|
$params = '-v ' . $params if $self->_getVerbose; |
251
|
0
|
|
|
|
|
|
my $tar_cmd = $self->getTarPath . " $params -c -f - -C '$backup_dir' '$file_prefix'"; |
252
|
0
|
|
|
|
|
|
system "$tar_cmd | $compress > $dst_file"; |
253
|
|
|
|
|
|
|
} |
254
|
|
|
|
|
|
|
|
255
|
0
|
|
|
|
|
|
return $dst_file; |
256
|
|
|
|
|
|
|
} |
257
|
|
|
|
|
|
|
|
258
|
|
|
|
|
|
|
=pod |
259
|
|
|
|
|
|
|
|
260
|
|
|
|
|
|
|
=head2 rotate() |
261
|
|
|
|
|
|
|
|
262
|
|
|
|
|
|
|
Rotates the backup directories and archive files. The number of |
263
|
|
|
|
|
|
|
archive files to keep and the number of directories to keep are |
264
|
|
|
|
|
|
|
specified in the new() constructor. |
265
|
|
|
|
|
|
|
|
266
|
|
|
|
|
|
|
=cut |
267
|
|
|
|
|
|
|
sub rotate { |
268
|
0
|
|
|
0
|
1
|
|
my ($self) = @_; |
269
|
0
|
|
|
|
|
|
my $archive_copies = $self->getArchiveCopies; |
270
|
0
|
|
|
|
|
|
my $dir_copies = $self->getDirCopies; |
271
|
0
|
|
|
|
|
|
my $backup_dir = $self->getBackupDir; |
272
|
0
|
|
|
|
|
|
my $secondary_backup_dir = $self->getSecondaryBackupDir; |
273
|
|
|
|
|
|
|
|
274
|
0
|
|
|
|
|
|
$self->_rotate($backup_dir, $archive_copies, $dir_copies, $secondary_backup_dir); |
275
|
|
|
|
|
|
|
|
276
|
0
|
0
|
|
|
|
|
return 1 if $secondary_backup_dir eq ''; |
277
|
0
|
|
|
|
|
|
my $secondary_archive_copies = $self->getSecondaryArchiveCopies; |
278
|
0
|
|
|
|
|
|
$self->_rotate($secondary_backup_dir, $secondary_archive_copies, 0, ''); |
279
|
|
|
|
|
|
|
} |
280
|
|
|
|
|
|
|
|
281
|
|
|
|
|
|
|
=pod |
282
|
|
|
|
|
|
|
|
283
|
|
|
|
|
|
|
=head2 my $archives = getArchiveDeleteList() |
284
|
|
|
|
|
|
|
|
285
|
|
|
|
|
|
|
Returns a list of archive files that will get deleted if the |
286
|
|
|
|
|
|
|
rotate() method is called. |
287
|
|
|
|
|
|
|
|
288
|
|
|
|
|
|
|
=cut |
289
|
|
|
|
|
|
|
sub getArchiveDeleteList { |
290
|
0
|
|
|
0
|
1
|
|
my ($self) = @_; |
291
|
|
|
|
|
|
|
|
292
|
0
|
|
|
|
|
|
my $backup_dir = $self->getBackupDir; |
293
|
0
|
|
|
|
|
|
my $archives = $self->_getSortedArchives($backup_dir); |
294
|
0
|
|
|
|
|
|
my $num_archives = scalar(@$archives); |
295
|
0
|
|
|
|
|
|
my $archive_copies = $self->getArchiveCopies; |
296
|
|
|
|
|
|
|
|
297
|
0
|
|
|
|
|
|
my @files_to_delete; |
298
|
0
|
0
|
|
|
|
|
if ($num_archives > $archive_copies) { |
299
|
0
|
|
|
|
|
|
my $num_to_delete = $num_archives - $archive_copies; |
300
|
0
|
|
|
|
|
|
@files_to_delete = @$archives[0 .. $num_to_delete - 1]; |
301
|
|
|
|
|
|
|
} |
302
|
|
|
|
|
|
|
|
303
|
0
|
|
|
|
|
|
@files_to_delete = map { "$backup_dir/$_" } @files_to_delete; |
|
0
|
|
|
|
|
|
|
304
|
|
|
|
|
|
|
|
305
|
0
|
|
|
|
|
|
return \@files_to_delete; |
306
|
|
|
|
|
|
|
} |
307
|
|
|
|
|
|
|
|
308
|
|
|
|
|
|
|
=pod |
309
|
|
|
|
|
|
|
|
310
|
|
|
|
|
|
|
=head2 my $dirs = getDirDeleteList() |
311
|
|
|
|
|
|
|
|
312
|
|
|
|
|
|
|
Returns a list of directories that will get deleted if the |
313
|
|
|
|
|
|
|
rotate() method is called. |
314
|
|
|
|
|
|
|
|
315
|
|
|
|
|
|
|
|
316
|
|
|
|
|
|
|
=cut |
317
|
|
|
|
|
|
|
|
318
|
|
|
|
|
|
|
sub getDirDeleteList { |
319
|
0
|
|
|
0
|
1
|
|
my ($self) = @_; |
320
|
|
|
|
|
|
|
|
321
|
0
|
|
|
|
|
|
my $backup_dir = $self->getBackupDir; |
322
|
0
|
|
|
|
|
|
my $dirs = $self->_getSortedArchiveDirs($backup_dir); |
323
|
0
|
|
|
|
|
|
my $num_dirs = scalar(@$dirs); |
324
|
0
|
|
|
|
|
|
my $dir_copies = $self->getDirCopies; |
325
|
|
|
|
|
|
|
|
326
|
0
|
|
|
|
|
|
my @dirs_to_delete; |
327
|
0
|
0
|
|
|
|
|
if ($num_dirs > $dir_copies) { |
328
|
0
|
|
|
|
|
|
my $num_to_delete = $num_dirs - $dir_copies; |
329
|
0
|
|
|
|
|
|
@dirs_to_delete = @$dirs[0 .. $num_to_delete - 1]; |
330
|
|
|
|
|
|
|
} |
331
|
|
|
|
|
|
|
|
332
|
0
|
|
|
|
|
|
@dirs_to_delete = map { "$backup_dir/$_" } @dirs_to_delete; |
|
0
|
|
|
|
|
|
|
333
|
|
|
|
|
|
|
|
334
|
0
|
|
|
|
|
|
return \@dirs_to_delete; |
335
|
|
|
|
|
|
|
} |
336
|
|
|
|
|
|
|
|
337
|
|
|
|
|
|
|
sub _rotate { |
338
|
0
|
|
|
0
|
|
|
my ($self, $backup_dir, $archive_copies, $dir_copies, $secondary_backup_dir) = @_; |
339
|
|
|
|
|
|
|
|
340
|
0
|
|
|
|
|
|
my $archives = $self->_getSortedArchives($backup_dir); |
341
|
0
|
|
|
|
|
|
my $num_archives = scalar(@$archives); |
342
|
0
|
|
|
|
|
|
my $dirs = $self->_getSortedArchiveDirs($backup_dir); |
343
|
0
|
|
|
|
|
|
my $num_dirs = scalar(@$dirs); |
344
|
|
|
|
|
|
|
|
345
|
0
|
0
|
|
|
|
|
if ($num_archives > $archive_copies) { |
346
|
0
|
|
|
|
|
|
my $num_to_delete = $num_archives - $archive_copies; |
347
|
0
|
|
|
|
|
|
my @files_to_delete = @$archives[0 .. $num_to_delete - 1]; |
348
|
0
|
|
|
|
|
|
foreach my $file (@files_to_delete) { |
349
|
0
|
|
|
|
|
|
my $path = "$backup_dir/$file"; |
350
|
0
|
0
|
|
|
|
|
unless ($secondary_backup_dir eq '') { |
351
|
0
|
|
|
|
|
|
$self->copy($path, "$secondary_backup_dir/"); |
352
|
|
|
|
|
|
|
} |
353
|
0
|
|
|
|
|
|
$self->_debugPrint("removing $path\n"); |
354
|
0
|
|
|
|
|
|
$self->remove($path); |
355
|
|
|
|
|
|
|
} |
356
|
|
|
|
|
|
|
} |
357
|
|
|
|
|
|
|
|
358
|
0
|
0
|
|
|
|
|
if ($num_dirs > $dir_copies) { |
359
|
0
|
|
|
|
|
|
my $num_to_delete = $num_dirs - $dir_copies; |
360
|
0
|
|
|
|
|
|
my @dirs_to_delete = @$dirs[0 .. $num_to_delete - 1]; |
361
|
0
|
|
|
|
|
|
foreach my $dir (@dirs_to_delete) { |
362
|
0
|
|
|
|
|
|
my $path = "$backup_dir/$dir"; |
363
|
0
|
|
|
|
|
|
$self->_debugPrint("removing $path\n"); |
364
|
0
|
|
|
|
|
|
$self->remove($path); |
365
|
|
|
|
|
|
|
} |
366
|
|
|
|
|
|
|
|
367
|
|
|
|
|
|
|
} |
368
|
|
|
|
|
|
|
} |
369
|
|
|
|
|
|
|
|
370
|
|
|
|
|
|
|
sub _debug { |
371
|
0
|
|
|
0
|
|
|
my ($self) = @_; |
372
|
0
|
|
|
|
|
|
return $$self{_debug}; |
373
|
|
|
|
|
|
|
} |
374
|
|
|
|
|
|
|
|
375
|
|
|
|
|
|
|
sub _debugOff { |
376
|
0
|
|
|
0
|
|
|
my ($self) = @_; |
377
|
0
|
|
|
|
|
|
undef $$self{_debug}; |
378
|
0
|
|
|
|
|
|
undef $$self{_debug_fh}; |
379
|
|
|
|
|
|
|
} |
380
|
|
|
|
|
|
|
|
381
|
|
|
|
|
|
|
sub _debugOn { |
382
|
0
|
|
|
0
|
|
|
my ($self, $fh) = @_; |
383
|
0
|
|
|
|
|
|
$$self{_debug} = 1; |
384
|
0
|
|
|
|
|
|
$$self{_debug_fh} = $fh; |
385
|
|
|
|
|
|
|
} |
386
|
|
|
|
|
|
|
|
387
|
|
|
|
|
|
|
sub _debugPrint { |
388
|
0
|
|
|
0
|
|
|
my ($self, $str) = @_; |
389
|
0
|
0
|
|
|
|
|
return undef unless $$self{_debug}; |
390
|
0
|
|
|
|
|
|
my $fh = $$self{_debug_fh}; |
391
|
0
|
|
|
|
|
|
print $fh $str; |
392
|
|
|
|
|
|
|
} |
393
|
|
|
|
|
|
|
|
394
|
|
|
|
|
|
|
sub _getVerbose { |
395
|
0
|
|
|
0
|
|
|
my ($self) = @_; |
396
|
0
|
|
|
|
|
|
return $$self{_verbose}; |
397
|
|
|
|
|
|
|
} |
398
|
|
|
|
|
|
|
|
399
|
|
|
|
|
|
|
sub _setVerbose { |
400
|
0
|
|
|
0
|
|
|
my ($self, $val) = @_; |
401
|
0
|
|
|
|
|
|
return $$self{_verbose} = $val; |
402
|
|
|
|
|
|
|
} |
403
|
|
|
|
|
|
|
|
404
|
|
|
|
|
|
|
sub _getUseFileLock { |
405
|
0
|
|
|
0
|
|
|
my ($self) = @_; |
406
|
0
|
|
|
|
|
|
return $$self{_use_flock}; |
407
|
|
|
|
|
|
|
} |
408
|
|
|
|
|
|
|
|
409
|
|
|
|
|
|
|
sub _setUseFileLock { |
410
|
0
|
|
|
0
|
|
|
my ($self, $val) = @_; |
411
|
0
|
|
|
|
|
|
$$self{_use_flock} = $val; |
412
|
|
|
|
|
|
|
} |
413
|
|
|
|
|
|
|
|
414
|
|
|
|
|
|
|
sub _getUseRm { |
415
|
0
|
|
|
0
|
|
|
my ($self) = @_; |
416
|
0
|
|
|
|
|
|
return $$self{_use_rm}; |
417
|
|
|
|
|
|
|
} |
418
|
|
|
|
|
|
|
|
419
|
|
|
|
|
|
|
sub _setUseRm { |
420
|
0
|
|
|
0
|
|
|
my ($self, $val) = @_; |
421
|
0
|
|
|
|
|
|
$$self{_use_rm} = $val; |
422
|
|
|
|
|
|
|
} |
423
|
|
|
|
|
|
|
|
424
|
|
|
|
|
|
|
sub copy { |
425
|
0
|
|
|
0
|
0
|
|
my ($self, $src, $dst) = @_; |
426
|
|
|
|
|
|
|
|
427
|
0
|
|
|
|
|
|
my $copy = $self->_getCopyObject; |
428
|
0
|
|
|
|
|
|
$copy->copy($src, $dst); |
429
|
|
|
|
|
|
|
} |
430
|
|
|
|
|
|
|
|
431
|
|
|
|
|
|
|
sub _getCopyObject { |
432
|
0
|
|
|
0
|
|
|
my ($self) = @_; |
433
|
0
|
|
|
|
|
|
my $copy = $$self{_copy_obj}; |
434
|
0
|
0
|
|
|
|
|
unless ($copy) { |
435
|
0
|
|
|
|
|
|
$copy = File::Rotate::Backup::Copy->new({ use_flock => $self->_getUseFileLock, |
436
|
|
|
|
|
|
|
use_rm => $self->_getUseRm |
437
|
|
|
|
|
|
|
}); |
438
|
0
|
|
|
|
|
|
$$self{_copy_obj} = $copy; |
439
|
|
|
|
|
|
|
} |
440
|
|
|
|
|
|
|
|
441
|
0
|
0
|
|
|
|
|
if ($$self{_debug}) { |
|
|
0
|
|
|
|
|
|
442
|
0
|
|
|
|
|
|
$copy->debugOn($$self{_debug_fh}, 1); |
443
|
|
|
|
|
|
|
} elsif ($self->_getVerbose) { |
444
|
0
|
|
|
|
|
|
$copy->debugOn(\*STDERR, 1); |
445
|
|
|
|
|
|
|
} else { |
446
|
0
|
|
|
|
|
|
$copy->debugOff; |
447
|
|
|
|
|
|
|
} |
448
|
|
|
|
|
|
|
|
449
|
0
|
|
|
|
|
|
return $copy; |
450
|
|
|
|
|
|
|
} |
451
|
|
|
|
|
|
|
|
452
|
|
|
|
|
|
|
sub remove { |
453
|
0
|
|
|
0
|
0
|
|
my ($self, $victim) = @_; |
454
|
|
|
|
|
|
|
|
455
|
0
|
|
|
|
|
|
my $remove = $self->_getCopyObject; |
456
|
0
|
|
|
|
|
|
$remove->remove($victim); |
457
|
|
|
|
|
|
|
} |
458
|
|
|
|
|
|
|
|
459
|
|
|
|
|
|
|
sub _getArchiveFileRegex { |
460
|
0
|
|
|
0
|
|
|
my $self = shift; |
461
|
0
|
|
|
|
|
|
my $prefix = quotemeta($self->getFilePrefix); |
462
|
0
|
|
|
|
|
|
my $regex; |
463
|
|
|
|
|
|
|
|
464
|
0
|
0
|
|
|
|
|
if (exists($self->{_archive_file_regex})) { |
465
|
0
|
|
|
|
|
|
$regex = $self->{_archive_file_regex}; |
466
|
|
|
|
|
|
|
} |
467
|
|
|
|
|
|
|
else { |
468
|
0
|
|
|
|
|
|
$regex = '\d+-\d+-\d+_\d+_\d+_\d+'; |
469
|
|
|
|
|
|
|
} |
470
|
|
|
|
|
|
|
|
471
|
0
|
|
|
|
|
|
$regex = $prefix . $regex; |
472
|
|
|
|
|
|
|
|
473
|
0
|
|
|
|
|
|
return $regex; |
474
|
|
|
|
|
|
|
} |
475
|
|
|
|
|
|
|
|
476
|
|
|
|
|
|
|
sub _getSortedArchives { |
477
|
0
|
|
|
0
|
|
|
my ($self, $dir) = @_; |
478
|
|
|
|
|
|
|
# my $prefix = quotemeta($self->getFilePrefix); |
479
|
0
|
0
|
|
|
|
|
$dir = $self->getBackupDir if $dir eq ''; |
480
|
0
|
|
|
|
|
|
local(*DIR); |
481
|
0
|
0
|
|
|
|
|
opendir(DIR, $dir) or return undef; |
482
|
0
|
|
|
|
|
|
my $regex = $self->_getArchiveFileRegex; |
483
|
0
|
0
|
|
|
|
|
my @files = grep { m/^$regex/ and not -d "$dir/$_" } readdir DIR; |
|
0
|
|
|
|
|
|
|
484
|
0
|
|
|
|
|
|
closedir DIR; |
485
|
|
|
|
|
|
|
|
486
|
0
|
|
|
|
|
|
@files = sort { $a cmp $b } @files; |
|
0
|
|
|
|
|
|
|
487
|
0
|
|
|
|
|
|
return \@files; |
488
|
|
|
|
|
|
|
} |
489
|
|
|
|
|
|
|
|
490
|
|
|
|
|
|
|
sub _getArchiveDirRegex { |
491
|
0
|
|
|
0
|
|
|
my $self = shift; |
492
|
0
|
|
|
|
|
|
my $prefix = quotemeta($self->getFilePrefix); |
493
|
|
|
|
|
|
|
|
494
|
0
|
|
|
|
|
|
my $regex; |
495
|
0
|
0
|
|
|
|
|
if (exists($self->{_archive_dir_regex})) { |
496
|
0
|
|
|
|
|
|
$regex = $self->{_archive_dir_regex}; |
497
|
0
|
0
|
|
|
|
|
$regex = '' unless defined $regex; |
498
|
|
|
|
|
|
|
} |
499
|
|
|
|
|
|
|
else { |
500
|
0
|
|
|
|
|
|
$regex = '\d+-\d+-\d+_\d+_\d+_\d+'; |
501
|
|
|
|
|
|
|
} |
502
|
|
|
|
|
|
|
|
503
|
0
|
|
|
|
|
|
$regex = $prefix . $regex; |
504
|
|
|
|
|
|
|
|
505
|
0
|
|
|
|
|
|
return $regex; |
506
|
|
|
|
|
|
|
} |
507
|
|
|
|
|
|
|
|
508
|
|
|
|
|
|
|
sub _getSortedArchiveDirs { |
509
|
0
|
|
|
0
|
|
|
my ($self, $dir) = @_; |
510
|
|
|
|
|
|
|
# my $prefix = quotemeta($self->getFilePrefix); |
511
|
0
|
0
|
|
|
|
|
$dir = $self->getBackupDir if $dir eq ''; |
512
|
0
|
|
|
|
|
|
local(*DIR); |
513
|
0
|
0
|
|
|
|
|
opendir(DIR, $dir) or return undef; |
514
|
|
|
|
|
|
|
# my @files = grep { m/^$prefix\d+-\d+-\d+_\d+_\d+_\d+/ and -d "$dir/$_" } readdir DIR;' |
515
|
0
|
|
|
|
|
|
my $regex = $self->_getArchiveDirRegex; |
516
|
0
|
0
|
|
|
|
|
my @files = grep { m/^$regex/ and -d "$dir/$_" } readdir DIR; |
|
0
|
|
|
|
|
|
|
517
|
0
|
|
|
|
|
|
closedir DIR; |
518
|
|
|
|
|
|
|
|
519
|
0
|
|
|
|
|
|
@files = sort { $a cmp $b } @files; |
|
0
|
|
|
|
|
|
|
520
|
0
|
|
|
|
|
|
return \@files; |
521
|
|
|
|
|
|
|
} |
522
|
|
|
|
|
|
|
|
523
|
|
|
|
|
|
|
sub _getTimestampForFileName { |
524
|
0
|
|
|
0
|
|
|
my ($self, $time) = @_; |
525
|
|
|
|
|
|
|
|
526
|
0
|
0
|
|
|
|
|
$time = time() unless $time; |
527
|
|
|
|
|
|
|
|
528
|
0
|
|
|
|
|
|
my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime($time); |
529
|
0
|
|
|
|
|
|
$mon += 1; |
530
|
0
|
|
|
|
|
|
$year += 1900; |
531
|
0
|
|
|
|
|
|
my $date = sprintf "%04d-%02d-%02d_%02d_%02d_%02d", $year, $mon, $mday, |
532
|
|
|
|
|
|
|
$hour, $min, $sec; |
533
|
|
|
|
|
|
|
|
534
|
0
|
|
|
|
|
|
return $date; |
535
|
|
|
|
|
|
|
} |
536
|
|
|
|
|
|
|
|
537
|
|
|
|
|
|
|
|
538
|
|
|
|
|
|
|
################# |
539
|
|
|
|
|
|
|
# getters/setters |
540
|
|
|
|
|
|
|
|
541
|
|
|
|
|
|
|
sub getCompressProgramPath { |
542
|
0
|
|
|
0
|
0
|
|
my ($self) = @_; |
543
|
0
|
|
|
|
|
|
my $path = $$self{_compress_program_path}; |
544
|
0
|
0
|
|
|
|
|
if ($path eq '') { |
545
|
0
|
|
0
|
|
|
|
return $self->{_bzip2_path} || 'bzip2'; |
546
|
|
|
|
|
|
|
} |
547
|
|
|
|
|
|
|
|
548
|
0
|
|
|
|
|
|
return $path; |
549
|
|
|
|
|
|
|
} |
550
|
|
|
|
|
|
|
|
551
|
|
|
|
|
|
|
=pod |
552
|
|
|
|
|
|
|
|
553
|
|
|
|
|
|
|
=head2 setCompressProgramPath($path) |
554
|
|
|
|
|
|
|
|
555
|
|
|
|
|
|
|
Set the path to the compression program you want to use when |
556
|
|
|
|
|
|
|
creating the archive files in the call to backup(). The given |
557
|
|
|
|
|
|
|
compression program must provide the same API as gzip and bzip2, |
558
|
|
|
|
|
|
|
at least to the extent that it will except input from stdin and |
559
|
|
|
|
|
|
|
will write output to stdout when no file names are provided. |
560
|
|
|
|
|
|
|
This defaults to 'bzip2' (no explicit path). |
561
|
|
|
|
|
|
|
|
562
|
|
|
|
|
|
|
=cut |
563
|
|
|
|
|
|
|
sub setCompressProgramPath { |
564
|
0
|
|
|
0
|
1
|
|
my ($self, $path) = @_; |
565
|
0
|
|
|
|
|
|
$$self{_compress_program_path} = $path; |
566
|
|
|
|
|
|
|
} |
567
|
|
|
|
|
|
|
|
568
|
|
|
|
|
|
|
sub getCompressExtension { |
569
|
0
|
|
|
0
|
0
|
|
my ($self) = @_; |
570
|
|
|
|
|
|
|
|
571
|
0
|
0
|
|
|
|
|
if (exists($$self{_compress_ext})) { |
572
|
0
|
|
|
|
|
|
return $$self{_compress_ext}; |
573
|
|
|
|
|
|
|
} |
574
|
|
|
|
|
|
|
|
575
|
0
|
|
|
|
|
|
my $compress_prog_path = $self->getCompressProgramPath; |
576
|
0
|
|
|
|
|
|
my $prog; |
577
|
0
|
0
|
|
|
|
|
if ($compress_prog_path =~ m{(?:\A|/)([^/\s]+)([^/]*)$}) { |
578
|
0
|
|
|
|
|
|
$prog = $1; |
579
|
|
|
|
|
|
|
} |
580
|
|
|
|
|
|
|
|
581
|
0
|
|
|
|
|
|
my $ext = { 'bzip2' => 'bz2', |
582
|
|
|
|
|
|
|
'gzip' => 'gz', |
583
|
|
|
|
|
|
|
}->{$prog}; |
584
|
|
|
|
|
|
|
|
585
|
0
|
|
|
|
|
|
return $ext; |
586
|
|
|
|
|
|
|
} |
587
|
|
|
|
|
|
|
|
588
|
|
|
|
|
|
|
=pod |
589
|
|
|
|
|
|
|
|
590
|
|
|
|
|
|
|
=head2 setCompressExtension($ext) |
591
|
|
|
|
|
|
|
|
592
|
|
|
|
|
|
|
This sets the extension given to the archive name after the .tar. |
593
|
|
|
|
|
|
|
This defaults to .bz2 if bzip2 is used for compression, and .gz |
594
|
|
|
|
|
|
|
if gzip is used. |
595
|
|
|
|
|
|
|
|
596
|
|
|
|
|
|
|
=cut |
597
|
|
|
|
|
|
|
sub setCompressExtension { |
598
|
0
|
|
|
0
|
1
|
|
my ($self, $ext) = @_; |
599
|
0
|
0
|
|
|
|
|
$ext =~ s/^\.// unless $ext eq '.'; |
600
|
0
|
|
|
|
|
|
$$self{_compress_ext} = $ext; |
601
|
|
|
|
|
|
|
} |
602
|
|
|
|
|
|
|
|
603
|
|
|
|
|
|
|
sub getTarPath { |
604
|
0
|
|
|
0
|
0
|
|
my ($self) = @_; |
605
|
0
|
|
|
|
|
|
my $path = $$self{_tar_path}; |
606
|
0
|
0
|
|
|
|
|
if ($path eq '') { |
607
|
0
|
|
|
|
|
|
return 'tar'; |
608
|
|
|
|
|
|
|
} |
609
|
|
|
|
|
|
|
|
610
|
0
|
|
|
|
|
|
return $path; |
611
|
|
|
|
|
|
|
} |
612
|
|
|
|
|
|
|
|
613
|
|
|
|
|
|
|
=pod |
614
|
|
|
|
|
|
|
|
615
|
|
|
|
|
|
|
=head2 setTarPath($path) |
616
|
|
|
|
|
|
|
|
617
|
|
|
|
|
|
|
Set the path to the tar program. This defaults to 'tar' (no |
618
|
|
|
|
|
|
|
explicit path). |
619
|
|
|
|
|
|
|
|
620
|
|
|
|
|
|
|
=cut |
621
|
|
|
|
|
|
|
sub setTarPath { |
622
|
0
|
|
|
0
|
1
|
|
my ($self, $path) = @_; |
623
|
0
|
|
|
|
|
|
$$self{_tar_path} = $path; |
624
|
|
|
|
|
|
|
} |
625
|
|
|
|
|
|
|
|
626
|
|
|
|
|
|
|
sub getRmPath { |
627
|
0
|
|
|
0
|
0
|
|
my ($self) = @_; |
628
|
0
|
|
|
|
|
|
my $path = $$self{_rm_path}; |
629
|
0
|
0
|
|
|
|
|
if ($path eq '') { |
630
|
0
|
|
|
|
|
|
return '/bin/rm'; |
631
|
|
|
|
|
|
|
} |
632
|
|
|
|
|
|
|
|
633
|
0
|
|
|
|
|
|
return $path; |
634
|
|
|
|
|
|
|
} |
635
|
|
|
|
|
|
|
|
636
|
|
|
|
|
|
|
sub setRmPath { |
637
|
0
|
|
|
0
|
0
|
|
my ($self, $path) = @_; |
638
|
0
|
|
|
|
|
|
$$self{_rm_path} = $path; |
639
|
|
|
|
|
|
|
} |
640
|
|
|
|
|
|
|
|
641
|
|
|
|
|
|
|
sub getCpPath { |
642
|
0
|
|
|
0
|
0
|
|
my ($self) = @_; |
643
|
0
|
|
|
|
|
|
my $path = $$self{_cp_path}; |
644
|
0
|
0
|
|
|
|
|
if ($path eq '') { |
645
|
0
|
|
|
|
|
|
return 'cp'; |
646
|
|
|
|
|
|
|
} |
647
|
|
|
|
|
|
|
|
648
|
0
|
|
|
|
|
|
return $path; |
649
|
|
|
|
|
|
|
} |
650
|
|
|
|
|
|
|
|
651
|
|
|
|
|
|
|
sub setCpPath { |
652
|
0
|
|
|
0
|
0
|
|
my ($self, $path) = @_; |
653
|
0
|
|
|
|
|
|
$$self{_cp_path} = $path; |
654
|
|
|
|
|
|
|
} |
655
|
|
|
|
|
|
|
|
656
|
|
|
|
|
|
|
sub getArchiveCopies { |
657
|
0
|
|
|
0
|
0
|
|
my ($self) = @_; |
658
|
0
|
|
|
|
|
|
return $$self{_archive_copies}; |
659
|
|
|
|
|
|
|
} |
660
|
|
|
|
|
|
|
|
661
|
|
|
|
|
|
|
sub setArchiveCopies { |
662
|
0
|
|
|
0
|
0
|
|
my ($self, $num) = @_; |
663
|
0
|
|
|
|
|
|
$$self{_archive_copies} = $num; |
664
|
|
|
|
|
|
|
} |
665
|
|
|
|
|
|
|
|
666
|
|
|
|
|
|
|
sub getDirCopies { |
667
|
0
|
|
|
0
|
0
|
|
my ($self) = @_; |
668
|
0
|
|
|
|
|
|
return $$self{_dir_copies}; |
669
|
|
|
|
|
|
|
} |
670
|
|
|
|
|
|
|
|
671
|
|
|
|
|
|
|
sub setDirCopies { |
672
|
0
|
|
|
0
|
0
|
|
my ($self, $num) = @_; |
673
|
0
|
|
|
|
|
|
$$self{_dir_copies} = $num; |
674
|
|
|
|
|
|
|
} |
675
|
|
|
|
|
|
|
|
676
|
|
|
|
|
|
|
sub getBackupDir { |
677
|
0
|
|
|
0
|
0
|
|
my ($self) = @_; |
678
|
0
|
|
|
|
|
|
return $$self{_backup_dir}; |
679
|
|
|
|
|
|
|
} |
680
|
|
|
|
|
|
|
|
681
|
|
|
|
|
|
|
sub setBackupDir { |
682
|
0
|
|
|
0
|
0
|
|
my ($self, $dir) = @_; |
683
|
0
|
|
|
|
|
|
$$self{_backup_dir} = $dir; |
684
|
|
|
|
|
|
|
} |
685
|
|
|
|
|
|
|
|
686
|
|
|
|
|
|
|
# added for v0_02 |
687
|
|
|
|
|
|
|
sub getSecondaryBackupDir { |
688
|
0
|
|
|
0
|
0
|
|
my ($self) = @_; |
689
|
0
|
|
|
|
|
|
return $$self{_secondary_backup_dir}; |
690
|
|
|
|
|
|
|
} |
691
|
|
|
|
|
|
|
|
692
|
|
|
|
|
|
|
# added for v0_02 |
693
|
|
|
|
|
|
|
sub setSecondaryBackupDir { |
694
|
0
|
|
|
0
|
0
|
|
my ($self, $dir) = @_; |
695
|
0
|
|
|
|
|
|
$$self{_secondary_backup_dir} = $dir; |
696
|
|
|
|
|
|
|
} |
697
|
|
|
|
|
|
|
|
698
|
|
|
|
|
|
|
sub getSecondaryArchiveCopies { |
699
|
0
|
|
|
0
|
0
|
|
my ($self) = @_; |
700
|
0
|
|
|
|
|
|
return $$self{_secondary_archive_copies}; |
701
|
|
|
|
|
|
|
} |
702
|
|
|
|
|
|
|
|
703
|
|
|
|
|
|
|
sub setSecondaryArchiveCopies { |
704
|
0
|
|
|
0
|
0
|
|
my ($self, $num) = @_; |
705
|
0
|
|
|
|
|
|
$$self{_secondary_archive_copies} = $num; |
706
|
|
|
|
|
|
|
} |
707
|
|
|
|
|
|
|
|
708
|
|
|
|
|
|
|
sub getFilePrefix { |
709
|
0
|
|
|
0
|
0
|
|
my ($self) = @_; |
710
|
0
|
|
|
|
|
|
return $$self{_file_prefix}; |
711
|
|
|
|
|
|
|
} |
712
|
|
|
|
|
|
|
|
713
|
|
|
|
|
|
|
sub setFilePrefix { |
714
|
0
|
|
|
0
|
0
|
|
my ($self, $prefix) = @_; |
715
|
0
|
|
|
|
|
|
$$self{_file_prefix} = $prefix; |
716
|
|
|
|
|
|
|
} |
717
|
|
|
|
|
|
|
|
718
|
|
|
|
|
|
|
|
719
|
|
|
|
|
|
|
} |
720
|
|
|
|
|
|
|
|
721
|
|
|
|
|
|
|
1; |
722
|
|
|
|
|
|
|
|
723
|
|
|
|
|
|
|
__END__ |