BackupPC_backupDelete (BackupPC-4.3.2) | : | BackupPC_backupDelete (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 BackupPC::Lib; | use BackupPC::Lib; | |||
use BackupPC::XS qw( :all ); | use BackupPC::XS qw( :all ); | |||
use BackupPC::DirOps qw( :BPC_DT_ALL ); | use BackupPC::DirOps qw( :BPC_DT_ALL ); | |||
my $Errors = 0; | my $Errors = 0; | |||
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 $FileCnt = 0; | my $FileCnt = 0; | |||
my $FileCntNext = 100; | my $FileCntNext = 100; | |||
my $DirCnt = 0; | my $DirCnt = 0; | |||
my $DirCntNext = 20; | my $DirCntNext = 20; | |||
my $doRefCountUpdate; | my $doRefCountUpdate; | |||
my %opts; | my %opts; | |||
if ( !getopts("lLpmrh:n:s:", \%opts) || !defined($opts{h}) || !defined($opts{n}) | ||||
|| (!defined($opts{s}) && @ARGV >= 1) ) { | if ( !getopts("flLpmrh:n:s:", \%opts) | |||
|| !defined($opts{h}) | ||||
|| !defined($opts{n}) | ||||
|| (!defined($opts{s}) && @ARGV >= 1) ) { | ||||
print STDERR <<EOF; | print STDERR <<EOF; | |||
usage: BackupPC_backupDelete -h host -n num [-p] [-l] [-L] [-r] [-m] [-s shareNa me [dirs...]] | usage: BackupPC_backupDelete -h host -n num [-f] [-l] [-L] [-m] [-p] [-r] [-s sh areName [dirs...]] | |||
Options: | Options: | |||
-h host host name | -h host host name | |||
-n num backup number to delete | -n num backup number to delete | |||
-s shareName don't delete the backup; delete just this share | -s shareName don't delete the backup; delete just this share | |||
(or only dirs below this share if specified) | (or only dirs below this share if specified) | |||
-p don't print progress information | -f force delete even if keep is set for this backup | |||
-L log output to host's LOG file (instead of stdout) | -L log output to host's LOG file (instead of stdout) | |||
-l don't remove XferLOG files | -l don't remove XferLOG files | |||
-r do a ref count update (default: none) | ||||
-m run even if a backup on this host is running | -m run 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 | ||||
-r do a ref count update (default: none) | ||||
If a shareName is specified, just that share (or share/dirs) are deleted. | If a shareName is specified, just that share (or share/dirs) are deleted. | |||
The backup itself is not deleted, nor is the log file removed. | The backup itself is not deleted, nor is the log file removed. | |||
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_backupDelete: bad host name '$opts{h}'\n"); | print(STDERR "BackupPC_backupDelete: 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_backupDelete: Can't read $Host's config file: $error\ n"); | print(STDERR "BackupPC_backupDelete: Can't read $Host's config file: $error\ 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_backupDelete" | |||
kupDelete")) =~ /fail/ ) { | )) =~ /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}; | |||
# | # | |||
# 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 | |||
# files with the digest encoded in the file name (eg: attrib_md5HexDigest). We | # files with the digest encoded in the file name (eg: attrib_md5HexDigest). We | |||
skipping to change at line 128 | skipping to change at line 136 | |||
exit(1); | exit(1); | |||
} | } | |||
$bpc->ChildInit(); | $bpc->ChildInit(); | |||
my($idx, $idxMerge); | my($idx, $idxMerge); | |||
my @Backups = $bpc->BackupInfoRead($Host); | my @Backups = $bpc->BackupInfoRead($Host); | |||
for ( my $i = 0 ; $i < @Backups ; $i++ ) { | for ( my $i = 0 ; $i < @Backups ; $i++ ) { | |||
$idx = $i if ( $opts{n} == $Backups[$i]{num} ); | $idx = $i if ( $opts{n} == $Backups[$i]{num} ); | |||
$idxMerge = $i if ( $opts{n} > $Backups[$i]{num} | $idxMerge = $i | |||
&& (!defined($idxMerge) || $Backups[$i]{num} > $Backups[ | if ( $opts{n} > $Backups[$i]{num} | |||
$idxMerge]{num}) ); | && (!defined($idxMerge) || $Backups[$i]{num} > $Backups[$idxMerge]{num}) | |||
); | ||||
} | } | |||
if ( !defined($idx) ) { | if ( !defined($idx) ) { | |||
print(STDERR "BackupPC_backupDelete: can't find backup number $opts{n} on ho st $Host\n"); | print(STDERR "BackupPC_backupDelete: can't find backup number $opts{n} on ho st $Host\n"); | |||
exit(1); | exit(1); | |||
} | } | |||
if ( $Backups[$idx]{keep} && !$opts{f} ) { | ||||
print(STDERR | ||||
"BackupPC_backupDelete: host $Host backup #$Backups[$idx]{num} has kee | ||||
p set; not deleting (use -f to override)\n" | ||||
); | ||||
exit(1); | ||||
} | ||||
my($LogFd); | my($LogFd); | |||
if ( $opts{L} ) { | if ( $opts{L} ) { | |||
my($delPid, $delFd); | my($delPid, $delFd); | |||
# | # | |||
# Fork into a parent which reads stdout and puts the output into | # Fork into a parent which reads stdout and puts the output into | |||
# the client's LOG file, while the child runs BackupPC_backupDelete. | # the client's LOG file, while the child runs BackupPC_backupDelete. | |||
# | # | |||
if ( !defined($delPid = open($delFd, "-|")) ) { | if ( !defined($delPid = open($delFd, "-|")) ) { | |||
print(STDERR "BackupPC_backupDelete: can't fork to -L logging\n"); | print(STDERR "BackupPC_backupDelete: can't fork to -L logging\n"); | |||
exit(1); | exit(1); | |||
} | } | |||
binmode($delFd); | binmode($delFd); | |||
if ( !$delPid ) { | if ( !$delPid ) { | |||
# | # | |||
# This is the child: clone STDERR to STDOUT then continue | # This is the child: clone STDERR to STDOUT then continue | |||
# | # | |||
setpgrp 0,0; | setpgrp 0, 0; | |||
close(STDERR); | close(STDERR); | |||
open(STDERR, ">&STDOUT"); | open(STDERR, ">&STDOUT"); | |||
} else { | } else { | |||
# | # | |||
# This is the parent; open the $Host LOG file and write $delFd | # This is the parent; open the $Host LOG file and write $delFd | |||
# there | # there | |||
# | # | |||
my($LogPath, $pids); | my($LogPath, $pids); | |||
($LogFd, $LogPath) = $bpc->openPCLogFile($Host); | ($LogFd, $LogPath) = $bpc->openPCLogFile($Host); | |||
if ( !defined($LogFd) ) { | if ( !defined($LogFd) ) { | |||
print(STDERR "BackupPC_backupDelete: unable to open/create $LogPath; | print(STDERR "BackupPC_backupDelete: unable to open/create $LogPath; | |||
exiting\n"); | exiting\n"); | |||
exit(1); | exit(1); | |||
} | } | |||
$pids->{$$} = 1; | $pids->{$$} = 1; | |||
$pids->{$delPid} = 1; | $pids->{$delPid} = 1; | |||
pidHandler(keys(%$pids)); | pidHandler(keys(%$pids)); | |||
while ( <$delFd> ) { | while ( <$delFd> ) { | |||
if ( $_ =~ /^__bpc_progress_/ ) { | if ( $_ =~ /^__bpc_progress_/ ) { | |||
print($_); | print($_); | |||
} elsif ( $_ =~ /^__bpc_pidStart__ (\d+)/ ) { | } elsif ( $_ =~ /^__bpc_pidStart__ (\d+)/ ) { | |||
$pids->{$1} = 1; | $pids->{$1} = 1; | |||
pidHandler(keys(%$pids)); | pidHandler(keys(%$pids)); | |||
} elsif ( $_ =~ /^__bpc_pidEnd__ (\d+)/ ) { | } elsif ( $_ =~ /^__bpc_pidEnd__ (\d+)/ ) { | |||
delete($pids->{$1}); | delete($pids->{$1}); | |||
pidHandler(keys(%$pids)); | pidHandler(keys(%$pids)); | |||
} else { | } else { | |||
logMsg($_); | logMsg($_); | |||
} | } | |||
} | } | |||
close($delFd); | close($delFd); | |||
exit(0); | exit(0); | |||
} | } | |||
} else { | } else { | |||
print("__bpc_pidStart__ $$\n") if ( !$opts{p} ); | print("__bpc_pidStart__ $$\n") if ( !$opts{p} ); | |||
} | } | |||
my($MergeCompress, $MergeDir, $MergeFilled); | my($MergeCompress, $MergeDir, $MergeFilled); | |||
my($AttrDel, $DeltaDel, $AttrMerge, $DeltaMerge); | my($AttrDel, $DeltaDel, $AttrMerge, $DeltaMerge); | |||
my $HostDir = "$TopDir/pc/$Host"; | my $HostDir = "$TopDir/pc/$Host"; | |||
my $DelCompress = $Backups[$idx]{compress}; | my $DelCompress = $Backups[$idx]{compress}; | |||
my $DelTopDir = "$HostDir/$Backups[$idx]{num}"; | my $DelTopDir = "$HostDir/$Backups[$idx]{num}"; | |||
my $DelPaths = @ARGV ? [@ARGV] : [undef]; | my $DelPaths = @ARGV ? [@ARGV] : [undef]; | |||
my $ShareName = $opts{s}; | my $ShareName = $opts{s}; | |||
my $ShareNameM = $bpc->fileNameEltMangle($ShareName); | my $ShareNameM = $bpc->fileNameEltMangle($ShareName); | |||
if ( $Backups[$idx]{version} < 4 ) { | if ( $Backups[$idx]{version} < 4 ) { | |||
if ( defined($ShareName) ) { | if ( defined($ShareName) ) { | |||
foreach my $delPath ( @$DelPaths ) { | foreach my $delPath ( @$DelPaths ) { | |||
logMsg("BackupPC_backupDelete: removing pre-v4 path #$Backups[$idx]{ | logMsg("BackupPC_backupDelete: removing pre-v4 path #$Backups[$idx]{ | |||
num}/$ShareName/$delPath\n") if ( $LogLevel >= 1 ); | num}/$ShareName/$delPath\n") | |||
if ( $LogLevel >= 1 ); | ||||
if ( !$opts{p} ) { | if ( !$opts{p} ) { | |||
print("__bpc_progress_state__ delete #$Backups[$idx]{num}/$Share Name/$delPath\n"); | print("__bpc_progress_state__ delete #$Backups[$idx]{num}/$Share Name/$delPath\n"); | |||
} | } | |||
# | # | |||
# no reference counting for pre V4 - just remove the tree(s) | # no reference counting for pre V4 - just remove the tree(s) | |||
# | # | |||
my $delPathM = $bpc->fileNameMangle($delPath); | my $delPathM = $bpc->fileNameMangle($delPath); | |||
BackupPC::DirOps::RmTreeQuiet($bpc, "$DelTopDir/$ShareNameM/$delPath M", -2, undef, undef, \&progressUpdate); | BackupPC::DirOps::RmTreeQuiet($bpc, "$DelTopDir/$ShareNameM/$delPath M", -2, undef, undef, \&progressUpdate); | |||
} | } | |||
} else { | } else { | |||
skipping to change at line 228 | skipping to change at line 244 | |||
# | # | |||
BackupPC::DirOps::RmTreeQuiet($bpc, $DelTopDir, -2, undef, undef, \&prog ressUpdate); | BackupPC::DirOps::RmTreeQuiet($bpc, $DelTopDir, -2, undef, undef, \&prog ressUpdate); | |||
} | } | |||
} else { | } else { | |||
if ( defined($ShareName) ) { | if ( defined($ShareName) ) { | |||
# | # | |||
# Since we are only deleting portions of the backup tree, we | # Since we are only deleting portions of the backup tree, we | |||
# need to update reference counts | # need to update reference counts | |||
# | # | |||
$DeltaDel = BackupPC::XS::DeltaRefCnt::new($DelTopDir); | $DeltaDel = BackupPC::XS::DeltaRefCnt::new($DelTopDir); | |||
$AttrDel = BackupPC::XS::AttribCache::new($Host, $Backups[$idx]{num}, $S hareName, $Backups[$idx]{compress}); | $AttrDel = BackupPC::XS::AttribCache::new($Host, $Backups[$idx]{num}, $ ShareName, $Backups[$idx]{compress}); | |||
$AttrDel->setDeltaInfo($DeltaDel); | $AttrDel->setDeltaInfo($DeltaDel); | |||
# | # | |||
# 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. | |||
# | # | |||
mkdir("$DelTopDir/refCnt", 0770) if ( !-d "$DelTopDir/refCnt" ); | mkdir("$DelTopDir/refCnt", 0770) if ( !-d "$DelTopDir/refCnt" ); | |||
my $needFsckFH; | my $needFsckFH; | |||
if ( !(open($needFsckFH, ">", "$DelTopDir/refCnt/needFsck.del") && close ($needFsckFH)) ) { | if ( !(open($needFsckFH, ">", "$DelTopDir/refCnt/needFsck.del") && close ($needFsckFH)) ) { | |||
logMsg("BackupPC_backupDelete: can't create $DelTopDir/refCnt/needFs ck.del ($?)\n"); | logMsg("BackupPC_backupDelete: can't create $DelTopDir/refCnt/needFs ck.del ($?)\n"); | |||
} | } | |||
} else { | } else { | |||
$AttrDel = BackupPC::XS::AttribCache::new($Host, $Backups[$idx]{num}, "" , $Backups[$idx]{compress}); | $AttrDel = BackupPC::XS::AttribCache::new($Host, $Backups[$idx]{num}, "" , $Backups[$idx]{compress}); | |||
} | } | |||
foreach my $delPath ( @$DelPaths ) { | foreach my $delPath ( @$DelPaths ) { | |||
my($delPathM, $fullDelPath); | my($delPathM, $fullDelPath); | |||
if ( defined($delPath) ) { | if ( defined($delPath) ) { | |||
$fullDelPath = "/$delPath" if ( $delPath !~ m{^/} ); | $fullDelPath = $delPath; | |||
$fullDelPath = "/$fullDelPath" if ( $fullDelPath !~ m{^/} ); | ||||
$delPathM = $bpc->fileNameMangle($delPath); | $delPathM = $bpc->fileNameMangle($delPath); | |||
$fullDelPath = "/$ShareName$fullDelPath"; | $fullDelPath = "/$ShareName$fullDelPath"; | |||
$delPathM = "/$ShareNameM$delPathM"; | $delPathM = "/$ShareNameM$delPathM"; | |||
$fullDelPath =~ s{//+}{/}; | $fullDelPath =~ s{//+}{/}; | |||
$delPathM =~ s{//+}{/}; | $delPathM =~ s{//+}{/}; | |||
} | } | |||
logMsg("BackupPC_backupDelete: removing #$Backups[$idx]{num}$fullDelPath \n") if ( $LogLevel >= 1 ); | logMsg("BackupPC_backupDelete: removing #$Backups[$idx]{num}$fullDelPath \n") if ( $LogLevel >= 1 ); | |||
if ( !defined($idxMerge) | if ( !defined($idxMerge) || $Backups[$idxMerge]{version} < 4 || !$Backup | |||
|| $Backups[$idxMerge]{version} < 4 | s[$idxMerge]{noFill} ) { | |||
|| !$Backups[$idxMerge]{noFill} ) { | ||||
# | # | |||
# Either this is oldest backup or prior is non-V4 or prior | # Either this is oldest backup or prior is non-V4 or prior | |||
# is filled. There is no need to merge into the prior backup, | # is filled. There is no need to merge into the prior backup, | |||
# so just delete the tree. | # so just delete the tree. | |||
# | # | |||
if ( !$opts{p} ) { | if ( !$opts{p} ) { | |||
print("__bpc_progress_state__ delete #$Backups[$idx]{num}$fullDe lPath\n"); | print("__bpc_progress_state__ delete #$Backups[$idx]{num}$fullDe lPath\n"); | |||
} | } | |||
logMsg("BackupPC_backupDelete: No prior backup for merge\n") if ( $L ogLevel >= 1 ); | logMsg("BackupPC_backupDelete: No prior backup for merge\n") if ( $L ogLevel >= 1 ); | |||
BackupPC::DirOps::RmTreeQuiet($bpc, "$DelTopDir$delPathM", $DelCompr | BackupPC::DirOps::RmTreeQuiet($bpc, "$DelTopDir$delPathM", $DelCompr | |||
ess, $DeltaDel, $AttrDel, \&progressUpdate); | ess, $DeltaDel, $AttrDel, | |||
\&progressUpdate); | ||||
if ( defined($delPath) ) { | if ( defined($delPath) ) { | |||
my $ret = $AttrDel->delete($delPath); | my $ret = $AttrDel->delete($delPath); | |||
logMsg("AttrDel($delPath) returns $ret\n") if ( $LogLevel >= 5 ) ; | logMsg("AttrDel($delPath) returns $ret\n") if ( $LogLevel >= 5 ) ; | |||
$AttrDel->flush(1); | $AttrDel->flush(1); | |||
$bpc->flushXSLibMesgs(); | $bpc->flushXSLibMesgs(); | |||
} | } | |||
} else { | } else { | |||
if ( !$opts{p} ) { | if ( !$opts{p} ) { | |||
print("__bpc_progress_state__ merge #$Backups[$idx]{num}$fullDel | print( | |||
Path -> #$Backups[$idxMerge]{num}$fullDelPath\n"); | "__bpc_progress_state__ merge #$Backups[$idx]{num}$fullDelPa | |||
th -> #$Backups[$idxMerge]{num}$fullDelPath\n" | ||||
); | ||||
} | } | |||
logMsg("BackupPC_backupDelete: Merge into backup $Backups[$idxMerge] | logMsg("BackupPC_backupDelete: Merge into backup $Backups[$idxMerge] | |||
{num}$fullDelPath\n") if ( $LogLevel >= 1 ); | {num}$fullDelPath\n") | |||
if ( $LogLevel >= 1 ); | ||||
$Backups[$idxMerge]{noFill} = $Backups[$idx]{noFill}; | $Backups[$idxMerge]{noFill} = $Backups[$idx]{noFill}; | |||
if ( ($Backups[$idx]{compress} == 0 && $Backups[$idxMerge]{compress} | if ( ($Backups[$idx]{compress} == 0 && $Backups[$idxMerge]{compres | |||
!= 0) | s} != 0) | |||
|| ($Backups[$idx]{compress} != 0 && $Backups[$idxMerge]{com | || ($Backups[$idx]{compress} != 0 && $Backups[$idxMerge]{compres | |||
press} == 0) ) { | s} == 0) ) { | |||
printf(STDERR "BackupPC_backupDelete: backups #%d and #%d have d ifferent compression - cannot merge\n", | printf(STDERR "BackupPC_backupDelete: backups #%d and #%d have d ifferent compression - cannot merge\n", | |||
$Backups[$idx]{num}, $Backups[$idxMerge]{num}); | $Backups[$idx]{num}, | |||
$Backups[$idxMerge]{num} | ||||
); | ||||
print("__bpc_pidEnd__ $$\n") if ( !$opts{p} ); | print("__bpc_pidEnd__ $$\n") if ( !$opts{p} ); | |||
exit(1); | exit(1); | |||
} | } | |||
$MergeCompress = $Backups[$idxMerge]{compress}; | $MergeCompress = $Backups[$idxMerge]{compress}; | |||
$MergeDir = "$HostDir/$Backups[$idxMerge]{num}"; | $MergeDir = "$HostDir/$Backups[$idxMerge]{num}"; | |||
$MergeFilled = !$Backups[$idxMerge]{noFill}; | $MergeFilled = !$Backups[$idxMerge]{noFill}; | |||
# | # | |||
# 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. | |||
# | # | |||
skipping to change at line 304 | skipping to change at line 325 | |||
my $needFsckFH; | my $needFsckFH; | |||
if ( !(open($needFsckFH, ">", "$MergeDir/refCnt/needFsck.del") && cl ose($needFsckFH)) ) { | if ( !(open($needFsckFH, ">", "$MergeDir/refCnt/needFsck.del") && cl ose($needFsckFH)) ) { | |||
logMsg("BackupPC_backupDelete: can't create $MergeDir/refCnt/nee dFsck.del ($?)\n"); | logMsg("BackupPC_backupDelete: can't create $MergeDir/refCnt/nee dFsck.del ($?)\n"); | |||
} | } | |||
if ( !chdir($DelTopDir) ) { | if ( !chdir($DelTopDir) ) { | |||
print(STDERR "BackupPC_backupDelete: cannot chdir to $DelTopDir\ n"); | print(STDERR "BackupPC_backupDelete: cannot chdir to $DelTopDir\ n"); | |||
print("__bpc_pidEnd__ $$\n") if ( !$opts{p} ); | print("__bpc_pidEnd__ $$\n") if ( !$opts{p} ); | |||
exit(1); | exit(1); | |||
} | } | |||
$AttrMerge = BackupPC::XS::AttribCache::new($Host, $Backups[$idxMer | $AttrMerge = BackupPC::XS::AttribCache::new($Host, $Backups[$idxMerg | |||
ge]{num}, | e]{num}, | |||
$ShareName, $Backups[$i | $ShareName, $Backups[$idxMerge]{compress}); | |||
dxMerge]{compress}); | ||||
$DeltaMerge = BackupPC::XS::DeltaRefCnt::new($MergeDir); | $DeltaMerge = BackupPC::XS::DeltaRefCnt::new($MergeDir); | |||
$AttrMerge->setDeltaInfo($DeltaMerge); | $AttrMerge->setDeltaInfo($DeltaMerge); | |||
my $dir = defined($delPath) ? ".$delPathM" : "."; | my $dir = defined($delPath) ? ".$delPathM" : "."; | |||
mergeDir(".", $dir); | mergeDir(".", $dir); | |||
BackupPC::DirOps::find($bpc, {wanted => \&mergeDir}, $dir, 1); | BackupPC::DirOps::find($bpc, {wanted => \&mergeDir}, $dir, 1); | |||
$AttrDel->flush(1); | $AttrDel->flush(1); | |||
$bpc->flushXSLibMesgs(); | $bpc->flushXSLibMesgs(); | |||
# | # | |||
# Now delete the Del backup tree | # Now delete the Del backup tree | |||
# | # | |||
logMsg("removing remaining directory tree $DelTopDir$delPathM\n") if ( $LogLevel >= 5 ); | logMsg("removing remaining directory tree $DelTopDir$delPathM\n") if ( $LogLevel >= 5 ); | |||
BackupPC::DirOps::RmTreeQuiet($bpc, "$DelTopDir$delPathM", $DelCompr | BackupPC::DirOps::RmTreeQuiet($bpc, "$DelTopDir$delPathM", $DelCompr | |||
ess, $DeltaDel, $AttrDel, \&progressUpdate); | ess, $DeltaDel, $AttrDel, | |||
\&progressUpdate); | ||||
if ( defined($delPath) ) { | if ( defined($delPath) ) { | |||
if ( defined(my $attr = $AttrDel->get($delPath)) && !defined($At trMerge->get($delPath)) ) { | if ( defined(my $attr = $AttrDel->get($delPath)) && !defined($At trMerge->get($delPath)) ) { | |||
$AttrMerge->set($delPath, $attr); | $AttrMerge->set($delPath, $attr); | |||
} | } | |||
my $ret = $AttrDel->delete($delPath); | my $ret = $AttrDel->delete($delPath); | |||
logMsg("AttrDel($delPath) returns $ret\n") if ( $LogLevel >= 5 ) ; | logMsg("AttrDel($delPath) returns $ret\n") if ( $LogLevel >= 5 ) ; | |||
} | } | |||
$AttrDel->flush(1); | $AttrDel->flush(1); | |||
$DeltaDel->flush() if ( $DeltaDel ); | $DeltaDel->flush() if ( $DeltaDel ); | |||
skipping to change at line 346 | skipping to change at line 368 | |||
} | } | |||
# | # | |||
# Make sure we update the reference counts below since there are (likely) | # Make sure we update the reference counts below since there are (likely) | |||
# deltas in the merge backup and/or original backup (if $DelPaths) | # deltas in the merge backup and/or original backup (if $DelPaths) | |||
# | # | |||
$doRefCountUpdate = 1; | $doRefCountUpdate = 1; | |||
} | } | |||
if ( !defined($ShareName) ) { | if ( !defined($ShareName) ) { | |||
if ( !$opts{l} ) { | if ( !$opts{l} ) { | |||
unlink("$HostDir/SmbLOG.$Backups[$idx]{num}") | unlink("$HostDir/SmbLOG.$Backups[$idx]{num}") | |||
if ( -f "$HostDir/SmbLOG.$Backups[$idx]{num}" ); | if ( -f "$HostDir/SmbLOG.$Backups[$idx]{num}" ); | |||
unlink("$HostDir/SmbLOG.$Backups[$idx]{num}.z") | unlink("$HostDir/SmbLOG.$Backups[$idx]{num}.z") | |||
if ( -f "$HostDir/SmbLOG.$Backups[$idx]{num}.z" ); | if ( -f "$HostDir/SmbLOG.$Backups[$idx]{num}.z" ); | |||
unlink("$HostDir/XferLOG.$Backups[$idx]{num}") | unlink("$HostDir/XferLOG.$Backups[$idx]{num}") | |||
if ( -f "$HostDir/XferLOG.$Backups[$idx]{num}" ); | if ( -f "$HostDir/XferLOG.$Backups[$idx]{num}" ); | |||
unlink("$HostDir/XferLOG.$Backups[$idx]{num}.z") | unlink("$HostDir/XferLOG.$Backups[$idx]{num}.z") | |||
if ( -f "$HostDir/XferLOG.$Backups[$idx]{num}.z" ); | if ( -f "$HostDir/XferLOG.$Backups[$idx]{num}.z" ); | |||
} | } | |||
splice(@Backups, $idx, 1); | splice(@Backups, $idx, 1); | |||
$bpc->BackupInfoWrite($Host, @Backups); | $bpc->BackupInfoWrite($Host, @Backups); | |||
} | } | |||
unlink("$MergeDir/refCnt/needFsck.del") if ( $Errors == 0 && $Conf{RefCntFsck} | unlink("$MergeDir/refCnt/needFsck.del") | |||
== 0 && -f "$MergeDir/refCnt/needFsck.del" ); | if ( $Errors == 0 && $Conf{RefCntFsck} == 0 && -f "$MergeDir/refCnt/needFsck.d | |||
unlink("$DelTopDir/refCnt/needFsck.del") if ( $Errors == 0 && $Conf{RefCntFsck} | el" ); | |||
== 0 && -f "$DelTopDir/refCnt/needFsck.del" ); | unlink("$DelTopDir/refCnt/needFsck.del") | |||
if ( $Errors == 0 && $Conf{RefCntFsck} == 0 && -f "$DelTopDir/refCnt/needFsck. | ||||
del" ); | ||||
if ( $doRefCountUpdate || $opts{r} ) { | if ( $doRefCountUpdate || $opts{r} ) { | |||
my $optsp = " -p" if ( $opts{p} ); | my $optsp = " -p" if ( $opts{p} ); | |||
$Errors++ if ( system("$BinDir/BackupPC_refCountUpdate -h $Host -o 0$optsp") != 0 ); | $Errors++ if ( system("$BinDir/BackupPC_refCountUpdate -h $Host -o 0$optsp") != 0 ); | |||
} | } | |||
logMsg("BackupPC_backupDelete: got $Errors errors\n") if ( $Errors > 0 || $LogLe vel >= 2 ); | logMsg("BackupPC_backupDelete: got $Errors errors\n") if ( $Errors > 0 || $LogLe vel >= 2 ); | |||
print("__bpc_pidEnd__ $$\n") if ( !$opts{p} ); | print("__bpc_pidEnd__ $$\n") if ( !$opts{p} ); | |||
exit($Errors ? 1 : 0); | exit($Errors ? 1 : 0); | |||
sub copyInodes | sub copyInodes | |||
{ | { | |||
my($name, $path) = @_; | my($name, $path) = @_; | |||
logMsg("copyInodes: name = $name, path = $path\n") if ( $LogLevel >= 6 ); | logMsg("copyInodes: name = $name, path = $path\n") if ( $LogLevel >= 6 ); | |||
return if ( $path !~ m{(.*)/(attrib[^/]*)$} ); | return if ( $path !~ m{(.*)/(attrib[^/]*)$} ); | |||
$path = $1; | $path = $1; | |||
$name = $2; | $name = $2; | |||
my $attr = BackupPC::XS::Attrib::new($MergeCompress); | my $attr = BackupPC::XS::Attrib::new($MergeCompress); | |||
if ( -f "$path/$name" && !$attr->read($path, $name) ) { | if ( -f "$path/$name" && !$attr->read($path, $name) ) { | |||
logMsg("Can't read attribute file $path/$name\n"); | logMsg("Can't read attribute file $path/$name\n"); | |||
$Errors++; | $Errors++; | |||
return; | return; | |||
} | } | |||
my $digest = $attr->digest(); | my $digest = $attr->digest(); | |||
if ( length($digest) ) { | if ( length($digest) ) { | |||
$DeltaMerge->update($MergeCompress, $digest, 1); | $DeltaMerge->update($MergeCompress, $digest, 1); | |||
$DeltaDel->update($DelCompress, $digest, -1) if ( $DeltaDel ); | $DeltaDel->update($DelCompress, $digest, -1) if ( $DeltaDel ); | |||
} | } | |||
my $attrAll = $attr->get(); | my $idx = 0; | |||
foreach my $fileUM ( keys(%$attrAll) ) { | my $a; | |||
my $a = $attrAll->{$fileUM}; | while ( 1 ) { | |||
($a, $idx) = $attr->iterate($idx); | ||||
last if ( !defined($a) ); | ||||
my $fileUM = $a->{name}; | ||||
$FileCnt++; | $FileCnt++; | |||
$DeltaMerge->update($a->{compress}, $a->{digest}, 1) if ( length($a->{di gest}) ); | $DeltaMerge->update($a->{compress}, $a->{digest}, 1) if ( length($a->{di gest}) ); | |||
$DeltaDel->update($a->{compress}, $a->{digest}, -1) if ( $DeltaDel && le | $DeltaDel->update($a->{compress}, $a->{digest}, -1) if ( $DeltaDel && l | |||
ngth($a->{digest}) ); | ength($a->{digest}) ); | |||
next if ( $a->{nlinks} == 0 ); | next if ( $a->{nlinks} == 0 ); | |||
# | # | |||
# copy/update inode in merge, and reduce link count in delete backup | # copy/update inode in merge, and reduce link count in delete backup | |||
# | # | |||
my $aInode = $AttrDel->getInode($a->{inode}); | my $aInode = $AttrDel->getInode($a->{inode}); | |||
if ( !(my $inodeMerge = $AttrMerge->getInode($a->{inode})) ) { | if ( !(my $inodeMerge = $AttrMerge->getInode($a->{inode})) ) { | |||
# | # | |||
# Copy the inode if it doesn't exist in Merge. | # Copy the inode if it doesn't exist in Merge. | |||
# | # | |||
$AttrMerge->setInode($a->{inode}, $aInode); | $AttrMerge->setInode($a->{inode}, $aInode); | |||
$DeltaMerge->update($aInode->{compress}, $aInode->{digest}, 1) | $DeltaMerge->update($aInode->{compress}, $aInode->{digest}, 1) | |||
if ( length($aInode->{digest}) ) ; | if ( length($aInode->{digest}) ); | |||
} | } | |||
if ( $DeltaDel && $aInode ) { | if ( $DeltaDel && $aInode ) { | |||
$aInode->{nlinks}--; | $aInode->{nlinks}--; | |||
if ( $aInode->{nlinks} <= 0 ) { | if ( $aInode->{nlinks} <= 0 ) { | |||
$DeltaDel->update($DelCompress, $aInode->{digest}, -1) if ( $Del taDel && length($aInode->{digest}) ); | $DeltaDel->update($DelCompress, $aInode->{digest}, -1) if ( $Del taDel && length($aInode->{digest}) ); | |||
$AttrDel->deleteInode($a->{inode}); | $AttrDel->deleteInode($a->{inode}); | |||
} else { | } else { | |||
$AttrDel->setInode($a->{inode}, $aInode); | $AttrDel->setInode($a->{inode}, $aInode); | |||
} | } | |||
} | } | |||
skipping to change at line 447 | skipping to change at line 477 | |||
my $delDir = "$DelTopDir/$d"; | my $delDir = "$DelTopDir/$d"; | |||
my $mergeDir = "$MergeDir/$d"; | my $mergeDir = "$MergeDir/$d"; | |||
logMsg("mergeDir: delDir = $delDir, mergeDir = $mergeDir\n") if ( $LogLevel >= 6 ); | logMsg("mergeDir: delDir = $delDir, mergeDir = $mergeDir\n") if ( $LogLevel >= 6 ); | |||
my $attr = BackupPC::XS::Attrib::new($MergeCompress); | my $attr = BackupPC::XS::Attrib::new($MergeCompress); | |||
$attr->read($mergeDir, $name) if ( -d $mergeDir ); | $attr->read($mergeDir, $name) if ( -d $mergeDir ); | |||
my $attrAll = $attr->get(); | my $attrAll = $attr->get(); | |||
my($attrDelAll); | my($attrDelAll); | |||
my $dirty = 0; | my $dirty = 0; | |||
my $attrDel = BackupPC::XS::Attrib::new($DelCompress); | my $attrDel = BackupPC::XS::Attrib::new($DelCompress); | |||
if ( -d $delDir ) { | if ( -d $delDir ) { | |||
$attrDel->read($delDir, $name); | $attrDel->read($delDir, $name); | |||
$attrDelAll = $attrDel->get(); | $attrDelAll = $attrDel->get(); | |||
$DeltaDel->update($DelCompress, $attrDel->digest(), -1) if ( $DeltaDel & & length($attrDel->digest()) ); | $DeltaDel->update($DelCompress, $attrDel->digest(), -1) if ( $DeltaDel & & length($attrDel->digest()) ); | |||
} | } | |||
$bpc->flushXSLibMesgs(); | $bpc->flushXSLibMesgs(); | |||
# | # | |||
# Add non-attrib directories (ie: directories that were created | # Add non-attrib directories (ie: directories that were created | |||
# to store attributes in deeper directories), since these | # to store attributes in deeper directories), since these | |||
# directories may not appear in the attrib file at this level. | # directories may not appear in the attrib file at this level. | |||
# | # | |||
if ( defined(my $entries = BackupPC::DirOps::dirRead($bpc, $delDir)) ) { | if ( defined(my $entries = BackupPC::DirOps::dirRead($bpc, $delDir)) ) { | |||
foreach my $e ( @$entries ) { | foreach my $e ( @$entries ) { | |||
next if ( $e->{name} eq "." | next if ( $e->{name} eq "." || $e->{name} eq ".." || $e->{name} eq " | |||
|| $e->{name} eq ".." | inode" ); | |||
|| $e->{name} eq "inode" ); | ||||
if ( $e->{name} =~ /^attrib/ ) { | if ( $e->{name} =~ /^attrib/ ) { | |||
if ( $e->{name} =~ /attrib_(.{16,})/ ) { | if ( $e->{name} =~ /attrib_(.{16,})/ ) { | |||
my $digest = pack("H*", $1); | my $digest = pack("H*", $1); | |||
$DeltaDel->update($DelCompress, $digest, -1) if ( $DeltaDel && $attrDel->digest() ne $digest ); | $DeltaDel->update($DelCompress, $digest, -1) if ( $DeltaDel && $attrDel->digest() ne $digest ); | |||
} | } | |||
logMsg("Removing attrib file $delDir/$e->{name}\n") if ( $LogLev el >= 5 ); | logMsg("Removing attrib file $delDir/$e->{name}\n") if ( $LogLev el >= 5 ); | |||
unlink("$delDir/$e->{name}"); | unlink("$delDir/$e->{name}"); | |||
} elsif ( -d "$delDir/$e->{name}" ) { | } elsif ( -d "$delDir/$e->{name}" ) { | |||
my $fileUM = $bpc->fileNameUnmangle($e->{name}); | my $fileUM = $bpc->fileNameUnmangle($e->{name}); | |||
next if ( $attrDelAll && defined($attrDelAll->{$fileUM}) ); | next if ( $attrDelAll && defined($attrDelAll->{$fileUM}) ); | |||
$attrDelAll->{$fileUM} = { | $attrDelAll->{$fileUM} = { | |||
type => BPC_FTYPE_DIR, | type => BPC_FTYPE_DIR, | |||
noAttrib => 1, | noAttrib => 1, | |||
}; | }; | |||
} | } | |||
} | } | |||
} | } | |||
if ( defined(my $entries = BackupPC::DirOps::dirRead($bpc, $mergeDir)) ) { | if ( defined(my $entries = BackupPC::DirOps::dirRead($bpc, $mergeDir)) ) { | |||
foreach my $e ( @$entries ) { | foreach my $e ( @$entries ) { | |||
next if ( $e->{name} eq "." | next if ( $e->{name} eq "." | |||
|| $e->{name} eq ".." | || $e->{name} eq ".." | |||
|| $e->{name} eq "inode" | || $e->{name} eq "inode" | |||
|| !-d "$mergeDir/$e->{name}" ); | || !-d "$mergeDir/$e->{name}" ); | |||
my $fileUM = $bpc->fileNameUnmangle($e->{name}); | my $fileUM = $bpc->fileNameUnmangle($e->{name}); | |||
next if ( $attrAll && defined($attrAll->{$fileUM}) ); | next if ( $attrAll && defined($attrAll->{$fileUM}) ); | |||
$attrAll->{$fileUM} = { | $attrAll->{$fileUM} = { | |||
type => BPC_FTYPE_DIR, | type => BPC_FTYPE_DIR, | |||
noAttrib => 1, | noAttrib => 1, | |||
}; | }; | |||
} | } | |||
} | } | |||
#logMsg "MergeDir $mergeDir contents:\n", Dumper($attrAll); | #logMsg "MergeDir $mergeDir contents:\n", Dumper($attrAll); | |||
#logMsg "DelTopDir $delDir contents:\n", Dumper($attrDelAll); | #logMsg "DelTopDir $delDir contents:\n", Dumper($attrDelAll); | |||
foreach my $fileUM ( keys(%$attrDelAll) ) { | foreach my $fileUM ( keys(%$attrDelAll) ) { | |||
my $a = $attrDelAll->{$fileUM}; | my $a = $attrDelAll->{$fileUM}; | |||
$FileCnt++; | $FileCnt++; | |||
if ( defined(my $aMerge = $attrAll->{$fileUM}) ) { | if ( defined(my $aMerge = $attrAll->{$fileUM}) ) { | |||
logMsg("Got del file $delDir/$fileUM, type $a->{type}; mergeDir has type $aMerge->{type}\n") | logMsg("Got del file $delDir/$fileUM, type $a->{type}; mergeDir has type $aMerge->{type}\n") | |||
if ( $LogLevel >= 7 ); | if ( $LogLevel >= 7 ); | |||
# | # | |||
# The file exists in both the previous and | # The file exists in both the previous and | |||
# deleted backups. | # deleted backups. | |||
# | # | |||
# If they are both directories, then don't do | # If they are both directories, then don't do | |||
# anything for now | # anything for now | |||
# | # | |||
if ( $a->{type} == BPC_FTYPE_DIR && | if ( $a->{type} == BPC_FTYPE_DIR && $aMerge->{type} == BPC_FTYPE_DIR | |||
$aMerge->{type} == BPC_FTYPE_DIR ) { | ) { | |||
# | # | |||
# if the deleted directory has real attributes, and the | # if the deleted directory has real attributes, and the | |||
# merge doesn't, then copy the attributes to merge | # merge doesn't, then copy the attributes to merge | |||
# | # | |||
if ( $aMerge->{noAttrib} && !$a->{noAttrib} ) { | if ( $aMerge->{noAttrib} && !$a->{noAttrib} ) { | |||
logMsg("Copying del attributes to merge for $delDir/$fileUM\ n") if ( $LogLevel >= 7 ); | logMsg("Copying del attributes to merge for $delDir/$fileUM\ n") if ( $LogLevel >= 7 ); | |||
$attr->set($fileUM, $a); | $attr->set($fileUM, $a); | |||
$dirty = 1; | $dirty = 1; | |||
} | } | |||
next; | next; | |||
} | } | |||
# | # | |||
# The deleted version will get deleted. | # The deleted version will get deleted. | |||
# | # | |||
logMsg("removing $delDir/$fileUM\n") if ( $LogLevel >= 7 ); | logMsg("removing $delDir/$fileUM\n") if ( $LogLevel >= 7 ); | |||
if ( $DeltaDel ) { | if ( $DeltaDel ) { | |||
skipping to change at line 567 | skipping to change at line 595 | |||
# the reference counts for the merge backup. | # the reference counts for the merge backup. | |||
# | # | |||
if ( !$a->{noAttrib} ) { | if ( !$a->{noAttrib} ) { | |||
$attr->set($fileUM, $a); | $attr->set($fileUM, $a); | |||
if ( length($a->{digest}) ) { | if ( length($a->{digest}) ) { | |||
$DeltaMerge->update($a->{compress}, $a->{digest}, 1); | $DeltaMerge->update($a->{compress}, $a->{digest}, 1); | |||
$DeltaDel->update($a->{compress}, $a->{digest}, -1) if ( $DeltaD el ); | $DeltaDel->update($a->{compress}, $a->{digest}, -1) if ( $DeltaD el ); | |||
} | } | |||
if ( $LogLevel >= 7 ) { | if ( $LogLevel >= 7 ) { | |||
my $digestStr = unpack("H*", $a->{digest}); | my $digestStr = unpack("H*", $a->{digest}); | |||
logMsg("set $fileUM attrib (type = $a->{type}, size = $a->{size} | logMsg( | |||
, nlinks = $a->{nlinks}, inode = $a->{inode}, digest = $digestStr)\n") | "set $fileUM attrib (type = $a->{type}, size = $a->{size}, n | |||
links = $a->{nlinks}, inode = $a->{inode}, digest = $digestStr)\n" | ||||
); | ||||
} | } | |||
if ( $a->{nlinks} > 0 ) { | if ( $a->{nlinks} > 0 ) { | |||
my $aInode = $AttrDel->getInode($a->{inode}); | my $aInode = $AttrDel->getInode($a->{inode}); | |||
if ( $LogLevel >= 7 ) { | if ( $LogLevel >= 7 ) { | |||
my $digestStr = unpack("H*", $aInode->{digest}); | my $digestStr = unpack("H*", $aInode->{digest}); | |||
logMsg("got del $fileUM inode $a->{inode} (type = $aInode->{ | logMsg( | |||
type}, size = $aInode->{size}, nlinks = $aInode->{nlinks}, digest = $digestStr)\ | "got del $fileUM inode $a->{inode} (type = $aInode->{typ | |||
n") | e}, size = $aInode->{size}, nlinks = $aInode->{nlinks}, digest = $digestStr)\n" | |||
); | ||||
} | } | |||
if ( !(my $inodeMerge = $AttrMerge->getInode($a->{inode})) ) { | if ( !(my $inodeMerge = $AttrMerge->getInode($a->{inode})) ) { | |||
# | # | |||
# Copy the inode if it doesn't exist in Merge. | # Copy the inode if it doesn't exist in Merge. | |||
# | # | |||
$AttrMerge->setInode($a->{inode}, $aInode); | $AttrMerge->setInode($a->{inode}, $aInode); | |||
$DeltaMerge->update($aInode->{compress}, $aInode->{digest}, 1) | $DeltaMerge->update($aInode->{compress}, $aInode->{digest}, 1) | |||
if ( length($aInode->{digest}) ); | if ( length($aInode->{digest}) ); | |||
if ( $LogLevel >= 7 ) { | if ( $LogLevel >= 7 ) { | |||
my $digestStr = unpack("H*", $aInode->{digest}); | my $digestStr = unpack("H*", $aInode->{digest}); | |||
logMsg("setting merge inode $a->{inode} (type = $aInode- | logMsg( | |||
>{type}, size = $aInode->{size}, nlinks = $aInode->{nlinks}, digest = $digestStr | "setting merge inode $a->{inode} (type = $aInode->{t | |||
)\n") | ype}, size = $aInode->{size}, nlinks = $aInode->{nlinks}, digest = $digestStr)\n | |||
" | ||||
); | ||||
} | } | |||
} | } | |||
if ( $DeltaDel && $aInode ) { | if ( $DeltaDel && $aInode ) { | |||
$aInode->{nlinks}--; | $aInode->{nlinks}--; | |||
if ( $aInode->{nlinks} <= 0 ) { | if ( $aInode->{nlinks} <= 0 ) { | |||
$DeltaDel->update($DelCompress, $aInode->{digest}, -1) i f ( $DeltaDel ); | $DeltaDel->update($DelCompress, $aInode->{digest}, -1) i f ( $DeltaDel ); | |||
$AttrDel->deleteInode($a->{inode}); | $AttrDel->deleteInode($a->{inode}); | |||
if ( $LogLevel >= 7 ) { | if ( $LogLevel >= 7 ) { | |||
my $digestStr = unpack("H*", $aInode->{digest}); | my $digestStr = unpack("H*", $aInode->{digest}); | |||
logMsg("deleted del inode $a->{inode} (type = $aInod | logMsg( | |||
e->{type}, size = $aInode->{size}, nlinks = $aInode->{nlinks}, digest = $digestS | "deleted del inode $a->{inode} (type = $aInode-> | |||
tr)\n") | {type}, size = $aInode->{size}, nlinks = $aInode->{nlinks}, digest = $digestStr) | |||
\n" | ||||
); | ||||
} | } | |||
} else { | } else { | |||
$AttrDel->setInode($a->{inode}, $aInode); | $AttrDel->setInode($a->{inode}, $aInode); | |||
if ( $LogLevel >= 7 ) { | if ( $LogLevel >= 7 ) { | |||
my $digestStr = unpack("H*", $aInode->{digest}); | my $digestStr = unpack("H*", $aInode->{digest}); | |||
logMsg("updated del inode $a->{inode} (type = $aInod | logMsg( | |||
e->{type}, size = $aInode->{size}, nlinks = $aInode->{nlinks}, digest = $digestS | "updated del inode $a->{inode} (type = $aInode-> | |||
tr)\n") | {type}, size = $aInode->{size}, nlinks = $aInode->{nlinks}, digest = $digestStr) | |||
\n" | ||||
); | ||||
} | } | |||
} | } | |||
} | } | |||
} | } | |||
$dirty = 1; | $dirty = 1; | |||
} | } | |||
next if ( $a->{type} != BPC_FTYPE_DIR ); | next if ( $a->{type} != BPC_FTYPE_DIR ); | |||
# | # | |||
# Since it's a directory, if it exists, move the whole thing over. | # Since it's a directory, if it exists, move the whole thing over. | |||
# We need to traverse the moved directory to make sure any referenced | # We need to traverse the moved directory to make sure any referenced | |||
skipping to change at line 643 | skipping to change at line 681 | |||
BackupPC::DirOps::find($bpc, {wanted => \©Inodes}, "$mergeDir/$file" , 1); | BackupPC::DirOps::find($bpc, {wanted => \©Inodes}, "$mergeDir/$file" , 1); | |||
} | } | |||
printProgress() if ( $FileCnt >= $FileCntNext ); | printProgress() if ( $FileCnt >= $FileCntNext ); | |||
$bpc->flushXSLibMesgs(); | $bpc->flushXSLibMesgs(); | |||
if ( $MergeFilled ) { | if ( $MergeFilled ) { | |||
# | # | |||
# if the merge directory is filled, actually delete any files that have | # if the merge directory is filled, actually delete any files that have | |||
# BPC_FTYPE_DELETED types | # BPC_FTYPE_DELETED types | |||
# | # | |||
my $attrAll = $attr->get(); | my $idx = 0; | |||
foreach my $fileUM ( keys(%$attrAll) ) { | my $a; | |||
my $a = $attrAll->{$fileUM}; | while ( 1 ) { | |||
($a, $idx) = $attr->iterate($idx); | ||||
last if ( !defined($a) ); | ||||
my $fileUM = $a->{name}; | ||||
next if ( $a->{type} != BPC_FTYPE_DELETED ); | next if ( $a->{type} != BPC_FTYPE_DELETED ); | |||
logMsg("removing attrib for deleted file $mergeDir/$fileUM\n") if ( $LogLevel >= 7 ); | logMsg("removing attrib for deleted file $mergeDir/$fileUM\n") if ( $LogLevel >= 7 ); | |||
$attr->delete($fileUM); | $attr->delete($fileUM); | |||
$dirty = 1; | $dirty = 1; | |||
} | } | |||
} | } | |||
if ( $dirty ) { | if ( $dirty ) { | |||
my $oldDigest = $attr->digest(); | my $oldDigest = $attr->digest(); | |||
if ( !$attr->write($mergeDir, $name, $oldDigest, $DeltaMerge) ) { | if ( !$attr->write($mergeDir, $name, $oldDigest, $DeltaMerge) ) { | |||
my $digestStr = unpack("H*", $oldDigest); | my $digestStr = unpack("H*", $oldDigest); | |||
logMsg("mergeDir: attr write to $mergeDir/$name failed (digest was $ digestStr)\n"); | logMsg("mergeDir: attr write to $mergeDir/$name failed (digest was $ digestStr)\n"); | |||
} | } | |||
logMsg(sprintf("rewriting attrib file %s; digest is %s was %s\n", | logMsg(sprintf( | |||
"$mergeDir/$name", unpack("H*", $attr->digest()), unpack( | "rewriting attrib file %s; digest is %s was %s\n", | |||
"H*", $oldDigest))) | "$mergeDir/$name", | |||
if ( $LogLevel >= 5 ); | unpack("H*", $attr->digest()), | |||
unpack("H*", $oldDigest) | ||||
)) | ||||
if ( $LogLevel >= 5 ); | ||||
} | } | |||
$bpc->flushXSLibMesgs(); | $bpc->flushXSLibMesgs(); | |||
} | } | |||
sub progressUpdate | sub progressUpdate | |||
{ | { | |||
my($newCnt) = @_; | my($newCnt) = @_; | |||
if ( $DeltaDel ) { | if ( $DeltaDel ) { | |||
$FileCnt += $newCnt; | $FileCnt += $newCnt; | |||
skipping to change at line 714 | skipping to change at line 760 | |||
} else { | } else { | |||
print($str); | print($str); | |||
} | } | |||
} | } | |||
# | # | |||
# print the list of pids | # print the list of pids | |||
# | # | |||
sub pidHandler | sub pidHandler | |||
{ | { | |||
my @pids = sort {$a <=> $b} @_; | my @pids = sort { $a <=> $b } @_; | |||
printf("xferPids %s\n", join(",", @pids)); | printf("xferPids %s\n", join(",", @pids)); | |||
} | } | |||
End of changes. 57 change blocks. | ||||
134 lines changed or deleted | 179 lines changed or added |