"Fossies" - the Fresh Open Source Software Archive  

Source code changes of the file "bin/BackupPC_backupDuplicate" between
BackupPC-4.3.2.tar.gz and BackupPC-4.4.0.tar.gz

About: BackupPC is a high-performance, enterprise-grade system for backing up Linux and WinXX PCs and laptops to a server’s disk (http/cgi user interface).

BackupPC_backupDuplicate  (BackupPC-4.3.2):BackupPC_backupDuplicate  (BackupPC-4.4.0)
skipping to change at line 34 skipping to change at line 34
# This program is distributed in the hope that it will be useful, # This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of # but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details. # GNU General Public License for more details.
# #
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
# #
#======================================================================== #========================================================================
# #
# Version 4.3.2, released 17 Feb 2020. # Version 4.4.0, released 20 Jun 2020.
# #
# See http://backuppc.sourceforge.net. # See http://backuppc.sourceforge.net.
# #
#======================================================================== #========================================================================
use strict; use strict;
no utf8; no utf8;
use lib "__INSTALLDIR__/lib"; use lib "__INSTALLDIR__/lib";
use Getopt::Std; use Getopt::Std;
use File::Copy; use File::Copy;
use File::Path; use File::Path;
use Data::Dumper; use Data::Dumper;
use Digest::MD5; use Digest::MD5;
use BackupPC::Lib; use BackupPC::Lib;
use BackupPC::XS qw( :all ); use BackupPC::XS qw( :all );
use BackupPC::DirOps; use BackupPC::DirOps;
use BackupPC::View; use BackupPC::View;
my $ErrorCnt = 0; my $ErrorCnt = 0;
my $FileErrorCnt = 0; my $FileErrorCnt = 0;
my $FileCnt = 0; my $FileCnt = 0;
my $FileCntNext = 100; my $FileCntNext = 100;
die("BackupPC::Lib->new failed\n") if ( !(my $bpc = BackupPC::Lib->new) ); die("BackupPC::Lib->new failed\n") if ( !(my $bpc = BackupPC::Lib->new) );
my $TopDir = $bpc->TopDir(); my $TopDir = $bpc->TopDir();
my $BinDir = $bpc->BinDir(); my $BinDir = $bpc->BinDir();
my %Conf = $bpc->Conf(); my %Conf = $bpc->Conf();
my $Hosts = $bpc->HostInfoRead(); my $Hosts = $bpc->HostInfoRead();
my %opts; my %opts;
if ( !getopts("mph:", \%opts) || @ARGV >= 1 || !defined($opts{h}) ) { if ( !getopts("mph:", \%opts) || @ARGV >= 1 || !defined($opts{h}) ) {
print STDERR <<EOF; print STDERR <<EOF;
usage: BackupPC_backupDuplicate [-m] [-p] -h host usage: BackupPC_backupDuplicate [-m] [-p] -h host
Options: Options:
-h host host name -h host host name
-m force running even if a backup on this host is running -m force running even if a backup on this host is running
(specifically, don't take the server host mutex) (specifically, don't take the server host mutex)
-p don't print progress information -p don't print progress information
EOF EOF
exit(1); exit(1);
} }
if ( $opts{h} !~ /^([\w\.\s-]+)$/ if ( $opts{h} !~ /^([\w\.\s-]+)$/
|| $opts{h} =~ m{(^|/)\.\.(/|$)} || $opts{h} =~ m{(^|/)\.\.(/|$)}
|| !defined($Hosts->{$opts{h}}) ) { || !defined($Hosts->{$opts{h}}) ) {
print(STDERR "BackupPC_backupDuplicate: bad host name '$opts{h}'\n"); print(STDERR "BackupPC_backupDuplicate: bad host name '$opts{h}'\n");
exit(1); exit(1);
} }
my $Host = $opts{h}; my $Host = $opts{h};
if ( defined(my $error = $bpc->ConfigRead($Host)) ) { if ( defined(my $error = $bpc->ConfigRead($Host)) ) {
print(STDERR "BackupPC_backupDuplicate: Can't read $Host's config file: $err or\n"); print(STDERR "BackupPC_backupDuplicate: Can't read $Host's config file: $err or\n");
exit(1); exit(1);
} }
%Conf = $bpc->Conf(); %Conf = $bpc->Conf();
if ( !$opts{m} && !defined($bpc->ServerConnect($Conf{ServerHost}, $Conf{ServerPo if ( !$opts{m}
rt})) && !defined($bpc->ServerConnect($Conf{ServerHost}, $Conf{ServerPort}))
&& (my $status = $bpc->ServerMesg("hostMutex $Host -1 BackupPC_bac && (my $status = $bpc->ServerMesg("hostMutex $Host -1 BackupPC_backupDuplica
kupDuplicate")) =~ /fail/ ) { te")) =~ /fail/ ) {
print(STDERR "$0: $status (use -m option to force running)\n"); print(STDERR "$0: $status (use -m option to force running)\n");
exit(1); exit(1);
} }
BackupPC::XS::Lib::logLevelSet($Conf{XferLogLevel}); BackupPC::XS::Lib::logLevelSet($Conf{XferLogLevel});
my $LogLevel = $Conf{XferLogLevel}; my $LogLevel = $Conf{XferLogLevel};
$bpc->ChildInit(); $bpc->ChildInit();
# #
# Write new-style attrib files (<= 4.0.0beta3 uses old-style), which are 0-lengt h # Write new-style attrib files (<= 4.0.0beta3 uses old-style), which are 0-lengt h
skipping to change at line 138 skipping to change at line 141
$newNum = $lastNum; $newNum = $lastNum;
do { do {
$newNum++; $newNum++;
$DestDir = "$TopDir/pc/$Host/$newNum"; $DestDir = "$TopDir/pc/$Host/$newNum";
} while ( -d $DestDir ); } while ( -d $DestDir );
for ( my $i = 0 ; $i < @Backups ; $i++ ) { for ( my $i = 0 ; $i < @Backups ; $i++ ) {
$Inode = $Backups[$i]{inodeLast} + 1 if ( $Inode <= $Backups[$i]{inodeLast} ); $Inode = $Backups[$i]{inodeLast} + 1 if ( $Inode <= $Backups[$i]{inodeLast} );
} }
%{$Backups[$newIdx]} = %{$Backups[$lastIdx]}; %{$Backups[$newIdx]} = %{$Backups[$lastIdx]};
$Backups[$newIdx]{num} = $newNum; $Backups[$newIdx]{num} = $newNum;
$Backups[$newIdx]{noFill} = 0; $Backups[$newIdx]{noFill} = 0;
$Backups[$newIdx]{compress} = $Compress; $Backups[$newIdx]{compress} = $Compress;
$Backups[$newIdx]{version} = $bpc->Version(); $Backups[$newIdx]{version} = $bpc->Version();
$Backups[$newIdx]{keep} = 0;
print("__bpc_pidStart__ $$\n") if ( !$opts{p} ); print("__bpc_pidStart__ $$\n") if ( !$opts{p} );
createFsckFile($DestDir); createFsckFile($DestDir);
$bpc->flushXSLibMesgs(); $bpc->flushXSLibMesgs();
if ( $Backups[$lastIdx]{version} >= 4 ) { if ( $Backups[$lastIdx]{version} >= 4 ) {
# #
# Duplicate a V4 backup by copying #lastNum to #newNum. # Duplicate a V4 backup by copying #lastNum to #newNum.
# We write directly to $DestDir. # We write directly to $DestDir.
skipping to change at line 216 skipping to change at line 220
printProgress(); printProgress();
} }
# #
# merge in backups (in case it changed) # merge in backups (in case it changed)
# #
my @newBackups = $bpc->BackupInfoRead($Host); my @newBackups = $bpc->BackupInfoRead($Host);
%{$newBackups[scalar(@newBackups)]} = %{$Backups[$newIdx]}; %{$newBackups[scalar(@newBackups)]} = %{$Backups[$newIdx]};
@Backups = @newBackups; @Backups = @newBackups;
$bpc->BackupInfoWrite($Host, @Backups); $bpc->BackupInfoWrite($Host, @Backups);
BackupPC::Storage->backupInfoWrite("$TopDir/pc/$Host", BackupPC::Storage->backupInfoWrite("$TopDir/pc/$Host", $Backups[$newIdx]{num}, $
$Backups[$newIdx]{num}, $Backups[$newIdx], 1 Backups[$newIdx], 1);
);
$ErrorCnt += BackupPC::XS::Lib::logErrorCntGet(); $ErrorCnt += BackupPC::XS::Lib::logErrorCntGet();
$bpc->flushXSLibMesgs(); $bpc->flushXSLibMesgs();
unlink("$DestDir/refCnt/needFsck.dup") if ( $ErrorCnt == 0 ); unlink("$DestDir/refCnt/needFsck.dup") if ( $ErrorCnt == 0 );
my $optsp = " -p" if ( $opts{p} ); my $optsp = " -p" if ( $opts{p} );
$ErrorCnt++ if ( system("$BinDir/BackupPC_refCountUpdate -h $Host -o 0$optsp") ! = 0 ); $ErrorCnt++ if ( system("$BinDir/BackupPC_refCountUpdate -h $Host -o 0$optsp") ! = 0 );
print("BackupPC_backupDuplicate: got $ErrorCnt errors and $FileErrorCnt file ope n errors\n"); print("BackupPC_backupDuplicate: got $ErrorCnt errors and $FileErrorCnt file ope n errors\n");
print("__bpc_pidEnd__ $$\n") if ( !$opts{p} ); print("__bpc_pidEnd__ $$\n") if ( !$opts{p} );
exit($ErrorCnt ? 1 : 0); exit($ErrorCnt ? 1 : 0);
sub copy_v4_file sub copy_v4_file
{ {
my($name, $path) = @_; my($name, $path) = @_;
printf("Got path = %s, name = %s, e,d,f = %d,%d,%d\n", $path, $name, -e $pat h, -d $path, -f $path) printf("Got path = %s, name = %s, e,d,f = %d,%d,%d\n", $path, $name, -e $pat h, -d $path, -f $path)
if ( $LogLevel >= 5 ); if ( $LogLevel >= 5 );
if ( -d $path ) { if ( -d $path ) {
print("Creating directory $DestDir/$path\n") if ( $LogLevel >= 4 ); print("Creating directory $DestDir/$path\n") if ( $LogLevel >= 4 );
eval { mkpath("$DestDir/$path", 0, 0777) }; eval { mkpath("$DestDir/$path", 0, 0777) };
if ( $@ ) { if ( $@ ) {
print(STDERR "Can't mkpath $DestDir/$path ($@)\n"); print(STDERR "Can't mkpath $DestDir/$path ($@)\n");
$ErrorCnt++; $ErrorCnt++;
} }
# #
# this is actually the directory count; it's expensive to get the file c ount since # this is actually the directory count; it's expensive to get the file c ount since
# we'd have to open every attrib file # we'd have to open every attrib file
skipping to change at line 294 skipping to change at line 297
if ( $@ ) { if ( $@ ) {
print("Can't mkpath $path ($@)\n"); print("Can't mkpath $path ($@)\n");
$ErrorCnt++; $ErrorCnt++;
return -1; return -1;
} }
print("copy_v3_file: mkpath $path\n") if ( $LogLevel >= 4 ); print("copy_v3_file: mkpath $path\n") if ( $LogLevel >= 4 );
} }
} else { } else {
printProgress() if ( ++$FileCnt >= $FileCntNext ); printProgress() if ( ++$FileCnt >= $FileCntNext );
} }
$copyFile = 1 if ( $a->{type} == BPC_FTYPE_FILE $copyFile = 1
|| $a->{type} == BPC_FTYPE_SYMLINK if ( $a->{type} == BPC_FTYPE_FILE
|| $a->{type} == BPC_FTYPE_CHARDEV || $a->{type} == BPC_FTYPE_SYMLINK
|| $a->{type} == BPC_FTYPE_BLOCKDEV ); || $a->{type} == BPC_FTYPE_CHARDEV
|| $a->{type} == BPC_FTYPE_BLOCKDEV );
# #
# TODO: confirm charset for v3 symlink contents: do we need to convert to ut f8? # TODO: confirm charset for v3 symlink contents: do we need to convert to ut f8?
# #
# assign inodes; handle hardlinks and nlinks # assign inodes; handle hardlinks and nlinks
# #
if ( $a->{type} == BPC_FTYPE_HARDLINK ) { if ( $a->{type} == BPC_FTYPE_HARDLINK ) {
# #
# old-style hardlink: the file gives the path of the linked-to file, # old-style hardlink: the file gives the path of the linked-to file,
# which we might or might not have processed yet. # which we might or might not have processed yet.
# #
skipping to change at line 328 skipping to change at line 332
# os if the link count is 0, we set it to 2. # os if the link count is 0, we set it to 2.
# #
my $origRelPath = $a->{relPath}; my $origRelPath = $a->{relPath};
$a = $aCurr; $a = $aCurr;
if ( $a->{nlinks} == 0 ) { if ( $a->{nlinks} == 0 ) {
$a->{nlinks} = 2; $a->{nlinks} = 2;
} else { } else {
$a->{nlinks}++; $a->{nlinks}++;
} }
$ac->set($origRelPath, $a); $ac->set($origRelPath, $a);
$ac->set($target, $a); $ac->set($target, $a);
print("target $target exists, set both inode = $a->{inode}, nlinks = $a->{nlinks}\n") print("target $target exists, set both inode = $a->{inode}, nlinks = $a->{nlinks}\n")
if ( $LogLevel >= 5 ); if ( $LogLevel >= 5 );
return; return;
} else { } else {
# #
# Target file not processed. Just set attributes with one link, # Target file not processed. Just set attributes with one link,
# so that an inode is created for us and target. # so that an inode is created for us and target.
# #
$a->{type} = BPC_FTYPE_FILE; $a->{type} = BPC_FTYPE_FILE;
$a->{nlinks} = 1; $a->{nlinks} = 1;
$a->{inode} = $Inode++; $a->{inode} = $Inode++;
$ac->set($a->{relPath}, $a); $ac->set($a->{relPath}, $a);
$ac->set($target, $a); $ac->set($target, $a);
print("target $target doesn't exist, set both inode = $a->{inode}, n links = $a->{nlinks}\n") print("target $target doesn't exist, set both inode = $a->{inode}, n links = $a->{nlinks}\n")
if ( $LogLevel >= 5 ); if ( $LogLevel >= 5 );
return; return;
} }
} else { } else {
my $aCurr = $ac->get($a->{relPath}); my $aCurr = $ac->get($a->{relPath});
if ( defined($aCurr) ) { if ( defined($aCurr) ) {
# #
# we are processing the target of other hardlinks; keep the inode # we are processing the target of other hardlinks; keep the inode
# and increment the link count. # and increment the link count.
# #
$a->{inode} = $aCurr->{inode}; $a->{inode} = $aCurr->{inode};
$a->{nlinks} = $aCurr->{nlinks} + 1; $a->{nlinks} = $aCurr->{nlinks} + 1;
} else { } else {
# #
# new non-hardlink has a new inode, and no links # new non-hardlink has a new inode, and no links
# #
$a->{inode} = $Inode++; $a->{inode} = $Inode++;
$a->{nlinks} = 0; $a->{nlinks} = 0;
} }
} }
if ( $copyFile ) { if ( $copyFile ) {
my $f = BackupPC::XS::FileZIO::open($a->{fullPath}, 0, $Compress); my $f = BackupPC::XS::FileZIO::open($a->{fullPath}, 0, $Compress);
my($size, $data, $data1MB, $fileSize, $found, @s, $thisRead); my($size, $data, $data1MB, $fileSize, $found, @s, $thisRead);
if ( !defined($f) ) { if ( !defined($f) ) {
print(STDERR "Unable to open file $a->{fullPath}\n"); print(STDERR "Unable to open file $a->{fullPath}\n");
$FileErrorCnt++; $FileErrorCnt++;
skipping to change at line 386 skipping to change at line 390
print(STDERR "error reading file $a->{fullPath} (read returns $t hisRead)\n"); print(STDERR "error reading file $a->{fullPath} (read returns $t hisRead)\n");
$ErrorCnt++; $ErrorCnt++;
$f->close(); $f->close();
return; return;
} elsif ( $thisRead > 0 ) { } elsif ( $thisRead > 0 ) {
$md5->add($data); $md5->add($data);
$fileSize += length($data); $fileSize += length($data);
$data1MB .= $data if ( length($data1MB) < (1 << 20) ); $data1MB .= $data if ( length($data1MB) < (1 << 20) );
} }
} while ( $thisRead > 0 ); } while ( $thisRead > 0 );
my $inode = (stat($a->{fullPath}))[1];
my $inode = (stat($a->{fullPath}))[1];
my $digest4 = $md5->digest(); my $digest4 = $md5->digest();
my $digest3 = $bpc->Buffer2MD5_v3(Digest::MD5->new(), $fileSize, \$data1 MB); my $digest3 = $bpc->Buffer2MD5_v3(Digest::MD5->new(), $fileSize, \$data1 MB);
my $path3 = $bpc->MD52Path_v3($digest3, $Compress); my $path3 = $bpc->MD52Path_v3($digest3, $Compress);
my $path4 = $bpc->MD52Path($digest4, $Compress); my $path4 = $bpc->MD52Path($digest4, $Compress);
my $i = -1; my $i = -1;
print("$a->{relPath}: path3 = $path3, path4 = $path4\n") if ( $LogLevel >= 5 ); print("$a->{relPath}: path3 = $path3, path4 = $path4\n") if ( $LogLevel >= 5 );
# #
# see if it's already in the v4 pool # see if it's already in the v4 pool
# #
if ( $fileSize == 0 ) { if ( $fileSize == 0 ) {
$found = 1; $found = 1;
print("$a->{relPath}: empty file in pool by default\n") if ( $LogLev el >= 4 ); print("$a->{relPath}: empty file in pool by default\n") if ( $LogLev el >= 4 );
} elsif ( (@s = stat($path4)) && $s[1] == $inode ) { } elsif ( (@s = stat($path4)) && $s[1] == $inode ) {
skipping to change at line 452 skipping to change at line 457
last; last;
} }
} }
# #
# check one more time for the V4 pool in case someone else just moved it there # check one more time for the V4 pool in case someone else just moved it there
# (in which case the link error above is actually not an error). # (in which case the link error above is actually not an error).
# #
if ( !$found && (@s = stat($path4)) && $s[1] == $inode ) { if ( !$found && (@s = stat($path4)) && $s[1] == $inode ) {
$found = 1; $found = 1;
print("$a->{relPath}: rediscovered in pool4 $path4; prior link error is benign\n"); print("$a->{relPath}: rediscovered in pool4 $path4; prior link error is benign\n");
$ErrorCnt-- if ( $ErrorCnt > 0 ); # reverse increment above $ErrorCnt-- if ( $ErrorCnt > 0 ); # reverse increment above
} }
if ( $found ) { if ( $found ) {
$f->close(); $f->close();
$a->{digest} = $digest4; $a->{digest} = $digest4;
$deltaInfo->update($Compress, $digest4, 1) if ( length($digest4) ); $deltaInfo->update($Compress, $digest4, 1) if ( length($digest4) );
$Backups[$newIdx]{nFiles}++; $Backups[$newIdx]{nFiles}++;
$Backups[$newIdx]{nFilesExist}++; $Backups[$newIdx]{nFilesExist}++;
if ( $a->{type} == BPC_FTYPE_FILE || $a->{type} == BPC_FTYPE_SYMLINK ) { if ( $a->{type} == BPC_FTYPE_FILE || $a->{type} == BPC_FTYPE_SYMLINK ) {
$Backups[$newIdx]{size} += $fileSize; $Backups[$newIdx]{size} += $fileSize;
skipping to change at line 480 skipping to change at line 485
$f->rewind(); $f->rewind();
my $pw = BackupPC::XS::PoolWrite::new($Compress); my $pw = BackupPC::XS::PoolWrite::new($Compress);
while ( $f->read(\$data, 1 << 20) > 0 ) { while ( $f->read(\$data, 1 << 20) > 0 ) {
$pw->write(\$data); $pw->write(\$data);
$size += length($data); $size += length($data);
} }
$f->close(); $f->close();
my($match, $digest, $poolSize, $errorCnt) = $pw->close(); my($match, $digest, $poolSize, $errorCnt) = $pw->close();
if ( $LogLevel >= 5 ) { if ( $LogLevel >= 5 ) {
my $digestStr = unpack("H*", $digest); my $digestStr = unpack("H*", $digest);
print("poolWrite->close $fileName: returned match $match, digest print(
$digestStr, poolSize $poolSize, errCnt $errorCnt\n"); "poolWrite->close $fileName: returned match $match, digest $
digestStr, poolSize $poolSize, errCnt $errorCnt\n"
);
} }
$ErrorCnt += $errorCnt; $ErrorCnt += $errorCnt;
$a->{digest} = $digest; $a->{digest} = $digest;
$deltaInfo->update($Compress, $digest, 1) if ( length($digest) ); $deltaInfo->update($Compress, $digest, 1) if ( length($digest) );
$bpc->flushXSLibMesgs(); $bpc->flushXSLibMesgs();
$Backups[$newIdx]{nFiles}++; $Backups[$newIdx]{nFiles}++;
if ( $match ) { if ( $match ) {
$Backups[$newIdx]{nFilesExist}++; $Backups[$newIdx]{nFilesExist}++;
} else { } else {
$Backups[$newIdx]{nFilesNew}++; $Backups[$newIdx]{nFilesNew}++;
} }
if ( $a->{type} == BPC_FTYPE_FILE || $a->{type} == BPC_FTYPE_SYMLINK ) { if ( $a->{type} == BPC_FTYPE_FILE || $a->{type} == BPC_FTYPE_SYMLINK ) {
$Backups[$newIdx]{size} += $size; $Backups[$newIdx]{size} += $size;
if ( $match ) { if ( $match ) {
$Backups[$newIdx]{sizeExist} += $size; $Backups[$newIdx]{sizeExist} += $size;
$Backups[$newIdx]{sizeExistComp} += $poolSize; $Backups[$newIdx]{sizeExistComp} += $poolSize;
} else { } else {
$Backups[$newIdx]{sizeNew} += $size; $Backups[$newIdx]{sizeNew} += $size;
$Backups[$newIdx]{sizeNewComp} += $poolSize; $Backups[$newIdx]{sizeNewComp} += $poolSize;
} }
} }
} }
} elsif ( $a->{type} != BPC_FTYPE_DIR ) { } elsif ( $a->{type} != BPC_FTYPE_DIR ) {
$Backups[$newIdx]{nFiles}++; $Backups[$newIdx]{nFiles}++;
$Backups[$newIdx]{nFilesExist}++; $Backups[$newIdx]{nFilesExist}++;
} }
print("setting $a->{relPath} attrib (type $a->{type}, inode $a->{inode}, nli print("setting $a->{relPath} attrib (type $a->{type}, inode $a->{inode}, nli
nks $a->{nlinks})\n") if ( $LogLevel >= 5 ); nks $a->{nlinks})\n")
if ( $LogLevel >= 5 );
$ac->set($a->{relPath}, $a); $ac->set($a->{relPath}, $a);
$bpc->flushXSLibMesgs(); $bpc->flushXSLibMesgs();
} }
# #
# Create a needFsck file, so if we are killed and can't recover, we can # Create a needFsck file, so if we are killed and can't recover, we can
# make sure an fsck is run next time. # make sure an fsck is run next time.
# #
sub createFsckFile sub createFsckFile
{ {
 End of changes. 24 change blocks. 
40 lines changed or deleted 47 lines changed or added

Home  |  About  |  Features  |  All  |  Newest  |  Dox  |  Diffs  |  RSS Feeds  |  Screenshots  |  Comments  |  Imprint  |  Privacy  |  HTTP(S)