1 #============================================================= -*-perl-*-
3 # BackupPC::Xfer::Protocol package
7 # This library defines a BackupPC::Xfer::Protocol class which
8 # defines standard methods for the transfer protocols in BackupPC.
11 # Paul Mantz <pcmantz@zmanda.com>
14 # Copyright (C) 2001-2009 Craig Barratt
16 # This program is free software; you can redistribute it and/or modify
17 # it under the terms of the GNU General Public License as published by
18 # the Free Software Foundation; either version 2 of the License, or
19 # (at your option) any later version.
21 # This program is distributed in the hope that it will be useful,
22 # but WITHOUT ANY WARRANTY; without even the implied warranty of
23 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 # GNU General Public License for more details.
26 # You should have received a copy of the GNU General Public License
27 # along with this program; if not, write to the Free Software
28 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
30 #========================================================================
32 # Version 3.2.0, released 31 Jul 2010.
34 # See http://backuppc.sourceforge.net.
36 #========================================================================
38 package BackupPC::Xfer::Protocol;
42 use Encode qw/from_to encode/;
44 use BackupPC::Attrib qw(:all);
48 # $t = BackupPC::Xfer::Protocol->new($args);
50 # new() is the constructor. There's nothing special going on here.
54 my($class, $bpc, $args) = @_;
66 logLevel => $bpc->{Conf}{XferLogLevel},
91 # args() can be used to send additional argument to the Xfer object
92 # via a hash reference.
98 foreach my $arg ( keys(%$args) ) {
99 $t->{$arg} = $args->{$arg};
107 # start() executes the actual data transfer. Must be implemented by
114 $t->{_errStr} = "start() not implemented by ".ref($t);
125 $t->{_errStr} = "run() not implemented by ".ref($t);
133 # This function is only used when $t->useTar() == 1.
139 $t->{_errStr} = "readOutput() not implemented by " . ref($t);
145 # $t->abort($reason);
147 # Aborts the current job.
151 my($t, $reason) = @_;
152 my @xferPid = $t->xferPid;
155 $t->{abortReason} = $reason;
157 kill($t->{bpc}->sigName2num("INT"), @xferPid);
165 # This function sets a mask for files when ($t->useTar == 1).
171 $t->{_errStr} = "readOutput() not implemented by " . ref($t);
182 return $t->{_errStr};
187 # $pid = $t->xferPid();
189 # xferPid() returns the process id of the child forked process.
195 return ($t->{xferPid});
206 push(@{$t->{_logMsg}}, $msg);
217 return shift(@{$t->{_logMsg}});
224 # This function returns xfer statistics. It Returns a hash ref giving
225 # various status information about the transfer.
232 map { $_ => $t->{$_} }
233 qw(byteCnt fileCnt xferErrCnt xferBadShareCnt xferBadFileCnt
234 xferOK hostAbort hostError lastOutputLine)
242 return @{$t->{badFiles}};
246 # useTar function. In order to work correctly, the protocol in
247 # question should overwrite the function if it needs to return true.
254 ##############################################################################
256 ##############################################################################
260 # $t->logWrite($msg [, $level])
262 # This function writes to XferLOG.
266 my($t, $msg, $level) = @_;
268 my $XferLOG = $t->{XferLOG};
269 $level = 3 if ( !defined($level) );
271 return ( $XferLOG->write(\$msg) ) if ( $level <= $t->{logLevel} );
274 ##############################################################################
275 # File Inclusion/Exclusion
276 ##############################################################################
279 # loadInclExclRegexps() places the appropriate file include/exclude regexps
281 sub loadInclExclRegexps
283 my ( $t, $shareType ) = @_;
285 my $conf = $t->{conf};
287 my @BackupFilesOnly = ();
288 my @BackupFilesExclude = ();
289 my ($shareName, $shareNameRE);
292 # $conf->{$shareType} shold be a reference to an array with one
293 # element, thanks to BackupFileConfFix().
295 $shareName = @{ $conf->{$shareType} }[0];
296 $shareName =~ s/\/*$//; # remove trailing slashes
298 $t->{shareName} = $shareName;
299 $t->{shareNameRE} = $bpc->glob2re($shareName);
302 # load all relevant values into @BackupFilesOnly
304 if ( ref( $conf->{BackupFilesOnly} ) eq "HASH" ) {
306 foreach my $share ( ( '*', $shareName ) ) {
307 push @BackupFilesOnly, @{ $conf->{BackupFilesOnly}{$share} }
308 if ( defined( $conf->{BackupFilesOnly}{$share} ) );
311 } elsif ( ref( $conf->{BackupFilesOnly} ) eq "ARRAY" ) {
313 push( @BackupFilesOnly, @{ $conf->{BackupFilesOnly} } );
315 } elsif ( !defined( $conf->{BackupFilesOnly} ) ) {
324 # not a legitimate entry for $conf->{BackupFilesOnly}
326 $t->{_errStr} = "Incorrect syntax in BackupFilesOnly for host $t->{Host}";
332 # load all relevant values into @BackupFilesExclude
334 if ( ref( $conf->{BackupFilesExclude} ) eq "HASH" ) {
336 foreach my $share ( ( '*', $shareName ) ) {
337 push( @BackupFilesExclude,
340 ? ( $t->{shareNameRE} . $bpc->glob2re($_) )
341 : ( '.*\/' . $bpc->glob2re($_) . '(?=\/.*)?' )
342 } @{ $conf->{BackupFilesExclude}{$share} }
343 ) if ( defined( $conf->{BackupFilesExclude}{$share} ) ) ;
346 } elsif ( ref( $conf->{BackupFilesExclude} ) eq "ARRAY" ) {
348 push( @BackupFilesExclude,
351 ? ( $bpc->glob2re($_) )
352 : ( '.*\/' . $bpc->glob2re($_) . '(?<=\/.*)?' )
353 } @{ $conf->{BackupFilesExclude} } );
355 } elsif ( !defined( $conf->{BackupFilesOnly} ) ) {
364 # not a legitimate entry for $conf->{BackupFilesExclude}
367 "Incorrect syntax in BackupFilesExclude for host $t->{Host}";
372 # load the regular expressions into the xfer object
374 $t->{BackupFilesOnly} = ( @BackupFilesOnly > 0 ) ? \@BackupFilesOnly : undef;
375 $t->{BackupFilesExclude} = ( @BackupFilesExclude > 0 ) ? \@BackupFilesExclude : undef;
381 sub checkIncludeExclude
385 return ( $t->checkIncludeMatch($file) && !$t->checkExcludeMatch($file) );
388 sub checkIncludeMatch
392 my $shareName = $t->{shareName};
393 my $includes = $t->{BackupFilesOnly} || return 1;
396 foreach my $include ( @{$includes} ) {
399 # construct regexp elsewhere to avoid syntactical evil
401 $match = '^' . quotemeta( $shareName . $include ) . '(?=\/.*)?';
404 # return true if the include folder is a parent of the file,
405 # or the folder itself.
407 return 1 if ( $file =~ /$match/ );
409 $match = '^' . quotemeta($file) . '(?=\/.*)?';
412 # return true if the file is a parent of the include folder,
413 # or the folder itself.
415 return 1 if ( "$shareName$include" =~ /$match/ );
420 sub checkExcludeMatch
424 my $shareName = $t->{shareName};
425 my $includes = $t->{BackupFilesOnly} || return 0;
428 foreach my $include ( @{$includes} ) {
431 # construct regexp elsewhere to avoid syntactical evil
433 $match = '^' . quotemeta( $shareName . $include ) . '(?=\/.*)?';
436 # return true if the include folder is a parent of the file,
437 # or the folder itself.
439 return 1 if ( $file =~ /$match/ );
441 $match = '^' . quotemeta($file) . '(?=\/.*)?';
444 # return true if the file is a parent of the include folder,
445 # or the folder itself.
447 return 1 if ( "$shareName$include" =~ /$match/ );