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-2007 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.0beta0, released 17 Jan 2009.
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) = @_;
90 # args() can be used to send additional argument to the Xfer object
91 # via a hash reference.
97 foreach my $arg ( keys(%$args) ) {
98 $t->{$arg} = $args->{$arg};
106 # start() executes the actual data transfer. Must be implemented by
113 $t->{_errStr} = "start() not implemented by ".ref($t);
124 $t->{_errStr} = "run() not implemented by ".ref($t);
132 # This function is only used when $t->useTar() == 1.
138 $t->{_errStr} = "readOutput() not implemented by " . ref($t);
144 # $t->abort($reason);
146 # Aborts the current job.
150 my($t, $reason) = @_;
151 my @xferPid = $t->xferPid;
154 $t->{abortReason} = $reason;
156 kill($t->{bpc}->sigName2num("INT"), @xferPid);
164 # This function sets a mask for files when ($t->useTar == 1).
170 $t->{_errStr} = "readOutput() not implemented by " . ref($t);
181 return $t->{_errStr};
186 # $pid = $t->xferPid();
188 # xferPid() returns the process id of the child forked process.
194 return ($t->{xferPid});
205 push(@{$t->{_logMsg}}, $msg);
216 return shift(@{$t->{_logMsg}});
223 # This function returns xfer statistics. It Returns a hash ref giving
224 # various status information about the transfer.
231 map { $_ => $t->{$_} }
232 qw(byteCnt fileCnt xferErrCnt xferBadShareCnt xferBadFileCnt
233 xferOK hostAbort hostError lastOutputLine)
241 return @{$t->{badFiles}};
245 # useTar function. In order to work correctly, the protocol in
246 # question should overwrite the function if it needs to return true.
253 ##############################################################################
255 ##############################################################################
259 # $t->logWrite($msg [, $level])
261 # This function writes to XferLOG.
265 my($t, $msg, $level) = @_;
267 my $XferLOG = $t->{XferLOG};
268 $level = 3 if ( !defined($level) );
270 return ( $XferLOG->write(\$msg) ) if ( $level <= $t->{logLevel} );
273 ##############################################################################
274 # File Inclusion/Exclusion
275 ##############################################################################
278 # loadInclExclRegexps() places the appropriate file include/exclude regexps
280 sub loadInclExclRegexps
282 my ( $t, $shareType ) = @_;
284 my $conf = $t->{conf};
286 my @BackupFilesOnly = ();
287 my @BackupFilesExclude = ();
288 my ($shareName, $shareNameRE);
291 # $conf->{$shareType} shold be a reference to an array with one
292 # element, thanks to BackupFileConfFix().
294 $shareName = @{ $conf->{$shareType} }[0];
295 $shareName =~ s/\/*$//; # remove trailing slashes
297 $t->{shareName} = $shareName;
298 $t->{shareNameRE} = $bpc->glob2re($shareName);
301 # load all relevant values into @BackupFilesOnly
303 if ( ref( $conf->{BackupFilesOnly} ) eq "HASH" ) {
305 foreach my $share ( ( '*', $shareName ) ) {
306 push @BackupFilesOnly, @{ $conf->{BackupFilesOnly}{$share} }
307 if ( defined( $conf->{BackupFilesOnly}{$share} ) );
310 } elsif ( ref( $conf->{BackupFilesOnly} ) eq "ARRAY" ) {
312 push( @BackupFilesOnly, @{ $conf->{BackupFilesOnly} } );
314 } elsif ( !defined( $conf->{BackupFilesOnly} ) ) {
323 # not a legitimate entry for $conf->{BackupFilesOnly}
325 $t->{_errStr} = "Incorrect syntax in BackupFilesOnly for host $t->{Host}";
331 # load all relevant values into @BackupFilesExclude
333 if ( ref( $conf->{BackupFilesExclude} ) eq "HASH" ) {
335 foreach my $share ( ( '*', $shareName ) ) {
336 push( @BackupFilesExclude,
339 ? ( $t->{shareNameRE} . $bpc->glob2re($_) )
340 : ( '.*\/' . $bpc->glob2re($_) . '(?=\/.*)?' )
341 } @{ $conf->{BackupFilesExclude}{$share} }
342 ) if ( defined( $conf->{BackupFilesExclude}{$share} ) ) ;
345 } elsif ( ref( $conf->{BackupFilesExclude} ) eq "ARRAY" ) {
347 push( @BackupFilesExclude,
350 ? ( $bpc->glob2re($_) )
351 : ( '.*\/' . $bpc->glob2re($_) . '(?<=\/.*)?' )
352 } @{ $conf->{BackupFilesExclude} } );
354 } elsif ( !defined( $conf->{BackupFilesOnly} ) ) {
363 # not a legitimate entry for $conf->{BackupFilesExclude}
366 "Incorrect syntax in BackupFilesExclude for host $t->{Host}";
371 # load the regular expressions into the xfer object
373 $t->{BackupFilesOnly} = ( @BackupFilesOnly > 0 ) ? \@BackupFilesOnly : undef;
374 $t->{BackupFilesExclude} = ( @BackupFilesExclude > 0 ) ? \@BackupFilesExclude : undef;
380 sub checkIncludeExclude
384 return ( $t->checkIncludeMatch($file) && !$t->checkExcludeMatch($file) );
387 sub checkIncludeMatch
391 my $shareName = $t->{shareName};
392 my $includes = $t->{BackupFilesOnly} || return 1;
395 foreach my $include ( @{$includes} ) {
398 # construct regexp elsewhere to avoid syntactical evil
400 $match = '^' . quotemeta( $shareName . $include ) . '(?=\/.*)?';
403 # return true if the include folder is a parent of the file,
404 # or the folder itself.
406 return 1 if ( $file =~ /$match/ );
408 $match = '^' . quotemeta($file) . '(?=\/.*)?';
411 # return true if the file is a parent of the include folder,
412 # or the folder itself.
414 return 1 if ( "$shareName$include" =~ /$match/ );
419 sub checkExcludeMatch
423 my $shareName = $t->{shareName};
424 my $includes = $t->{BackupFilesOnly} || return 0;
427 foreach my $include ( @{$includes} ) {
430 # construct regexp elsewhere to avoid syntactical evil
432 $match = '^' . quotemeta( $shareName . $include ) . '(?=\/.*)?';
435 # return true if the include folder is a parent of the file,
436 # or the folder itself.
438 return 1 if ( $file =~ /$match/ );
440 $match = '^' . quotemeta($file) . '(?=\/.*)?';
443 # return true if the file is a parent of the include folder,
444 # or the folder itself.
446 return 1 if ( "$shareName$include" =~ /$match/ );