# Craig Barratt <cbarratt@users.sourceforge.net>
#
# COPYRIGHT
-# Copyright (C) 2002 Craig Barratt
+# Copyright (C) 2002-2003 Craig Barratt
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
#
#========================================================================
#
-# Version 2.0.0_CVS, released 3 Feb 2003.
+# Version 2.1.3, released 21 Jan 2007.
#
# See http://backuppc.sourceforge.net.
#
$RsyncLibOK = 0;
$RsyncLibErr = "File::RsyncP module doesn't exist";
} else {
- if ( $File::RsyncP::VERSION < 0.30 ) {
+ #
+ # Note: also update configure.pl when this version number is changed!
+ #
+ if ( $File::RsyncP::VERSION < 0.52 ) {
$RsyncLibOK = 0;
- $RsyncLibErr = "File::RsyncP module version too old: need 0.30";
+ $RsyncLibErr = "File::RsyncP module version"
+ . " ($File::RsyncP::VERSION) too old: need 0.52";
} else {
$RsyncLibOK = 1;
}
} else {
#
# Turn $conf->{BackupFilesOnly} and $conf->{BackupFilesExclude}
- # into a hash of arrays of files.
+ # into a hash of arrays of files, and $conf->{RsyncShareName}
+ # to an array
#
- $conf->{RsyncShareName} = [ $conf->{RsyncShareName} ]
- unless ref($conf->{RsyncShareName}) eq "ARRAY";
- foreach my $param qw(BackupFilesOnly BackupFilesExclude) {
- next if ( !defined($conf->{$param}) );
- if ( ref($conf->{$param}) eq "ARRAY" ) {
- $conf->{$param} = {
- $conf->{RsyncShareName}[0] => $conf->{$param}
- };
- } elsif ( ref($conf->{$param}) eq "HASH" ) {
- # do nothing
- } else {
- $conf->{$param} = {
- $conf->{RsyncShareName}[0] => [ $conf->{$param} ]
- };
- }
- }
+ $bpc->backupFileConfFix($conf, "RsyncShareName");
+
if ( defined($conf->{BackupFilesOnly}{$t->{shareName}}) ) {
my(@inc, @exc, %incDone, %excDone);
foreach my $file ( @{$conf->{BackupFilesOnly}{$t->{shareName}}} ) {
# To make this easier we do all the includes first and all
# of the excludes at the end (hopefully they commute).
#
+ $file =~ s{/$}{};
$file = "/$file";
$file =~ s{//+}{/}g;
+ if ( $file eq "/" ) {
+ #
+ # This is a special case: if the user specifies
+ # "/" then just include it and don't exclude "/*".
+ #
+ push(@inc, $file) if ( !$incDone{$file} );
+ next;
+ }
my $f = "";
while ( $file =~ m{^/([^/]*)(.*)} ) {
my $elt = $1;
}
}
if ( $t->{type} eq "full" ) {
- $logMsg = "full backup started for directory $t->{shareName}";
+ if ( $t->{partialNum} ) {
+ $logMsg = "full backup started for directory $t->{shareName};"
+ . " updating partial $t->{partialNum}";
+ } else {
+ $logMsg = "full backup started for directory $t->{shareName}";
+ }
} else {
- $incrDate = $bpc->timeStampISO($t->{lastFull} - 3600, 1);
+ $incrDate = $bpc->timeStamp($t->{lastFull} - 3600, 1);
$logMsg = "incr backup started back to $incrDate for directory"
. " $t->{shareName}";
}
# transferred, even though it is a full dump.
#
$rsyncArgs = $conf->{RsyncArgs};
+ $rsyncArgs = [@$rsyncArgs, @fileList] if ( @fileList );
$rsyncArgs = [@$rsyncArgs, "--ignore-times"]
if ( $t->{type} eq "full" );
$rsyncClientCmd = $conf->{RsyncClientCmd};
$argList = ['--server', '--sender', @$rsyncArgs,
'.', $t->{shareNameSlash}];
$fioArgs = {
- client => $t->{client},
- share => $t->{shareName},
- viewNum => $t->{lastFullBkupNum},
+ client => $t->{client},
+ share => $t->{shareName},
+ viewNum => $t->{lastFullBkupNum},
+ partialNum => $t->{partialNum},
};
}
#
$t->{rsyncClientCmd} = $rsyncClientCmd;
$t->{rs} = File::RsyncP->new({
- logLevel => $conf->{RsyncLogLevel},
+ logLevel => $t->{logLevel} || $conf->{RsyncLogLevel},
rsyncCmd => sub {
+ $bpc->verbose(0);
$bpc->cmdExecOrEval($rsyncClientCmd, $args);
},
rsyncCmdType => "full",
rsyncArgs => $rsyncArgs,
timeout => $conf->{ClientTimeout},
- logHandler => sub {
- my($str) = @_;
- $str .= "\n";
- $t->{XferLOG}->write(\$str);
- },
+ doPartial => defined($t->{partialNum}) ? 1 : undef,
+ logHandler =>
+ sub {
+ my($str) = @_;
+ $str .= "\n";
+ $t->{XferLOG}->write(\$str);
+ if ( $str =~ /^Remote\[1\]: read errors mapping "(.*)"/ ) {
+ #
+ # Files with read errors (eg: region locked files
+ # on WinXX) are filled with 0 by rsync. Remember
+ # them and delete them later.
+ #
+ my $badFile = $1;
+ $badFile =~ s/^\/+//;
+ push(@{$t->{badFiles}}, {
+ share => $t->{shareName},
+ file => $badFile
+ });
+ }
+ },
+ pidHandler => sub {
+ $t->{pidHandler}(@_);
+ },
fio => BackupPC::Xfer::RsyncFileIO->new({
xfer => $t,
bpc => $t->{bpc},
conf => $t->{conf},
backups => $t->{backups},
- logLevel => $conf->{RsyncLogLevel},
+ logLevel => $t->{logLevel}
+ || $conf->{RsyncLogLevel},
logHandler => sub {
my($str) = @_;
$str .= "\n";
$t->{XferLOG}->write(\$str);
},
+ cacheCheckProb => $conf->{RsyncCsumCacheVerifyProb},
%$fioArgs,
}),
});
#
my $stats = $rs->statsFinal;
if ( !defined($error) && defined($stats) ) {
- $t->{xferOK} = 1;
+ $t->{xferOK} = 1;
} else {
- $t->{xferOK} = 0;
+ $t->{xferOK} = 0;
}
- $t->{byteCnt} = $stats->{childStats}{TotalFileSize}
- + $stats->{parentStats}{TotalFileSize};
- $t->{fileCnt} = $stats->{childStats}{TotalFileCnt}
- + $stats->{parentStats}{TotalFileCnt};
+ $t->{xferErrCnt} = $stats->{remoteErrCnt}
+ + $stats->{childStats}{errorCnt}
+ + $stats->{parentStats}{errorCnt};
+ $t->{byteCnt} = $stats->{childStats}{TotalFileSize}
+ + $stats->{parentStats}{TotalFileSize};
+ $t->{fileCnt} = $stats->{childStats}{TotalFileCnt}
+ + $stats->{parentStats}{TotalFileCnt};
+ my $str = "Done: $t->{fileCnt} files, $t->{byteCnt} bytes\n";
+ $t->{XferLOG}->write(\$str);
#
# TODO: get error count, and call fio to get stats...
#
}
}
+sub abort
+{
+ my($t, $reason) = @_;
+ my $rs = $t->{rs};
+
+ $rs->abort($reason);
+ return 1;
+}
+
sub setSelectMask
{
my($t, $FDreadRef) = @_;
{
my($t) = @_;
- return -1;
+ return ();
}
sub logMsg