+#
+# Removes any partial backups
+#
+sub BackupPartialRemove
+{
+ my($client, $Backups) = @_;
+
+ for ( my $i = @$Backups - 1 ; $i >= 0 ; $i-- ) {
+ next if ( $Backups->[$i]{type} ne "partial" );
+ BackupRemove($client, $Backups, $i);
+ }
+}
+
+sub BackupSave
+{
+ my @Backups = $bpc->BackupInfoRead($client);
+ my $num = -1;
+
+ #
+ # Since we got a good backup we should remove any partial dumps
+ # (the new backup might also be a partial, but that's ok).
+ #
+ BackupPartialRemove($client, \@Backups);
+
+ #
+ # Number the new backup
+ #
+ for ( my $i = 0 ; $i < @Backups ; $i++ ) {
+ $num = $Backups[$i]{num} if ( $num < $Backups[$i]{num} );
+ }
+ $num++;
+ $bpc->RmTreeDefer("$TopDir/trash", "$Dir/$num")
+ if ( -d "$Dir/$num" );
+ if ( !rename("$Dir/new", "$Dir/$num") ) {
+ print(LOG $bpc->timeStamp,
+ "Rename $Dir/new -> $Dir/$num failed\n");
+ $stat{xferOK} = 0;
+ }
+ rename("$Dir/XferLOG$fileExt", "$Dir/XferLOG.$num$fileExt");
+ rename("$Dir/NewFileList", "$Dir/NewFileList.$num");
+
+ #
+ # Add the new backup information to the backup file
+ #
+ my $i = @Backups;
+ $Backups[$i]{num} = $num;
+ $Backups[$i]{type} = $type;
+ $Backups[$i]{startTime} = $startTime;
+ $Backups[$i]{endTime} = $endTime;
+ $Backups[$i]{size} = $sizeTotal;
+ $Backups[$i]{nFiles} = $nFilesTotal;
+ $Backups[$i]{xferErrs} = $stat{xferErrCnt} || 0;
+ $Backups[$i]{xferBadFile} = $stat{xferBadFileCnt} || 0;
+ $Backups[$i]{xferBadShare} = $stat{xferBadShareCnt} || 0;
+ $Backups[$i]{nFilesExist} = $nFilesExist;
+ $Backups[$i]{sizeExist} = $sizeExist;
+ $Backups[$i]{sizeExistComp} = $sizeExistComp;
+ $Backups[$i]{tarErrs} = $tarErrs;
+ $Backups[$i]{compress} = $Conf{CompressLevel};
+ $Backups[$i]{noFill} = $type eq "incr" ? 1 : 0;
+ $Backups[$i]{level} = $type eq "incr" ? 1 : 0;
+ $Backups[$i]{mangle} = 1; # name mangling always on for v1.04+
+ $bpc->BackupInfoWrite($client, @Backups);
+
+ unlink("$Dir/timeStamp.level0");
+
+ #
+ # Now remove the bad files, replacing them if possible with links to
+ # earlier backups.
+ #
+ foreach my $f ( $xfer->getBadFiles ) {
+ my $j;
+ my $shareM = $bpc->fileNameEltMangle($f->{share});
+ my $fileM = $bpc->fileNameMangle($f->{file});
+ unlink("$Dir/$num/$shareM/$fileM");
+ for ( $j = $i - 1 ; $j >= 0 ; $j-- ) {
+ my $file;
+ if ( $Backups[$j]{mangle} ) {
+ $file = "$shareM/$fileM";
+ } else {
+ $file = "$f->{share}/$f->{file}";
+ }
+ next if ( !-f "$Dir/$Backups[$j]{num}/$file" );
+ if ( !link("$Dir/$Backups[$j]{num}/$file",
+ "$Dir/$num/$shareM/$fileM") ) {
+ print(LOG $bpc->timeStamp,
+ "Unable to link $num/$shareM/$fileM to"
+ . " $Backups[$j]{num}/$file\n");
+ } else {
+ print(LOG $bpc->timeStamp,
+ "Bad file $num/$shareM/$fileM replaced by link to"
+ . " $Backups[$j]{num}/$file\n");
+ }
+ last;
+ }
+ if ( $j < 0 ) {
+ print(LOG $bpc->timeStamp,
+ "Removed bad file $num/$shareM/$fileM (no older"
+ . " copy to link to)\n");
+ }
+ }
+ return $num;
+}
+
+#
+# Removes a specific backup
+#
+sub BackupRemove
+{
+ my($client, $Backups, $idx) = @_;
+ my($Dir) = "$TopDir/pc/$client";
+
+ $bpc->RmTreeDefer("$TopDir/trash",
+ "$Dir/$Backups->[$idx]{num}");
+ unlink("$Dir/SmbLOG.$Backups->[$idx]{num}")
+ if ( -f "$Dir/SmbLOG.$Backups->[$idx]{num}" );
+ unlink("$Dir/SmbLOG.$Backups->[$idx]{num}.z")
+ if ( -f "$Dir/SmbLOG.$Backups->[$idx]{num}.z" );
+ unlink("$Dir/XferLOG.$Backups->[$idx]{num}")
+ if ( -f "$Dir/XferLOG.$Backups->[$idx]{num}" );
+ unlink("$Dir/XferLOG.$Backups->[$idx]{num}.z")
+ if ( -f "$Dir/XferLOG.$Backups->[$idx]{num}.z" );
+ splice(@{$Backups}, $idx, 1);
+}
+