X-Git-Url: http://git.rot13.org/?p=BackupPC.git;a=blobdiff_plain;f=lib%2FBackupPC%2FPoolWrite.pm;h=23eb78853a13fb94aec3d6760453e81f9547dca8;hp=8ec9fd2b92b96eebdd81dbba61dc31786e0657c6;hb=27f513f89d885d24bf1a01242fba676c7a840fd5;hpb=c6cebe03e53dcc49f889cf15ccda5b0fe3acd235 diff --git a/lib/BackupPC/PoolWrite.pm b/lib/BackupPC/PoolWrite.pm index 8ec9fd2..23eb788 100644 --- a/lib/BackupPC/PoolWrite.pm +++ b/lib/BackupPC/PoolWrite.pm @@ -38,7 +38,7 @@ # Craig Barratt # # COPYRIGHT -# Copyright (C) 2001 Craig Barratt +# Copyright (C) 2001-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 @@ -56,7 +56,7 @@ # #======================================================================== # -# Version 2.0.0beta0, released 23 Feb 2003. +# Version 3.0.0alpha, released 23 Jan 2006. # # See http://backuppc.sourceforge.net. # @@ -98,8 +98,8 @@ sub new return $self; } -my $BufSize = 1048576; # 1MB or 2^20 -my $MaxFiles = 20; +my $BufSize = 1048576; # 1MB or 2^20 +my $MaxFiles = 20; # max number of compare files open at one time sub write { @@ -115,10 +115,12 @@ sub write # file list if the file changes between the file list sending # and the file sending). Here we only catch the case where # we haven't computed the digest (ie: we have written no more - # than $BufSize. We catch the big file case below. + # than $BufSize). We catch the big file case below. # if ( !defined($dataRef) && !defined($a->{digest}) && $a->{fileSize} != length($a->{data}) ) { + #my $newSize = length($a->{data}); + #print("Fixing file size from $a->{fileSize} to $newSize\n"); $a->{fileSize} = length($a->{data}); } @@ -270,9 +272,6 @@ sub write # We are at EOF, so finish up # $a->{eof} = 1; - foreach my $f ( @{$a->{files}} ) { - $f->{fh}->close(); - } # # Make sure the fileSize was correct. See above for comments about @@ -291,27 +290,39 @@ sub write my($fh, $fileName); $a->{fileSize} = $a->{nWrite}; - if ( $a->{fileName} =~ /(.*)\// ) { - $fileName = $1; - } else { - $fileName = "."; - } - # - # Find a unique target temporary file name - # - my $i = 0; - while ( -f "$fileName/t$$.$i" ) { - $i++; + if ( defined($a->{fhOut}) ) { + if ( $a->{fileName} =~ /(.*)\// ) { + $fileName = $1; + } else { + $fileName = "."; + } + # + # Find a unique target temporary file name + # + my $i = 0; + while ( -f "$fileName/t$$.$i" ) { + $i++; + } + $fileName = "$fileName/t$$.$i"; + $a->{fhOut}->close(); + if ( !rename($a->{fileName}, $fileName) + || !defined($fh = BackupPC::FileZIO->open($fileName, 0, + $a->{compress})) ) { + push(@{$a->{errors}}, "Can't rename $a->{fileName} -> $fileName" + . " or open during size fixup\n"); + } + #print("Using temporary name $fileName\n"); + } elsif ( defined($a->{files}) && defined($a->{files}[0]) ) { + # + # We haven't written anything yet, so just use the + # compare file to copy from. + # + $fh = $a->{files}[0]->{fh}; + $fh->rewind; + #print("Using compare file $a->{files}[0]->{name}\n"); } - $fileName = "$fileName/t$$.$i"; - $a->{fhOut}->close(); - if ( !rename($a->{fileName}, $fileName) - || !defined($fh = BackupPC::FileZIO->open($fileName, 0, - $a->{compress})) ) { - push(@{$a->{errors}}, "Can't rename $a->{fileName} -> $fileName" - . " or open during size fixup\n"); - } else { + if ( defined($fh) ) { my $poolWrite = BackupPC::PoolWrite->new($a->{bpc}, $a->{fileName}, $a->{fileSize}, $a->{compress}); my $nRead = 0; @@ -331,7 +342,7 @@ sub write $nRead += $thisRead; } $fh->close; - unlink($fileName); + unlink($fileName) if ( defined($fileName) ); if ( @{$a->{errors}} ) { $poolWrite->close; return (0, $a->{digest}, -s $a->{fileName}, $a->{errors}); @@ -341,6 +352,13 @@ sub write } } + # + # Close the compare files + # + foreach my $f ( @{$a->{files}} ) { + $f->{fh}->close(); + } + if ( $a->{fileSize} == 0 ) { # # Simply create an empty file @@ -394,6 +412,23 @@ sub close return $a->write(undef); } +# +# Abort a pool write +# +sub abort +{ + my($a) = @_; + + if ( defined($a->{fhOut}) ) { + $a->{fhOut}->close(); + unlink($a->{fileName}); + } + foreach my $f ( @{$a->{files}} ) { + $f->{fh}->close(); + } + $a->{files} = []; +} + # # Copy $nBytes from files $fhIn to $fhOut. # @@ -459,4 +494,53 @@ sub filePartialCompare return 1; } +# +# LinkOrCopy() does a hardlink from oldFile to newFile. +# +# If that fails (because there are too many links on oldFile) +# then oldFile is copied to newFile, and the pool stats are +# returned to be added to the new file list. That allows +# BackupPC_link to try again, and to create a new pool file +# if necessary. +# +sub LinkOrCopy +{ + my($bpc, $oldFile, $oldFileComp, $newFile, $newFileComp) = @_; + my($nRead, $data); + + unlink($newFile) if ( -f $newFile ); + # + # Try to link if hardlink limit is ok, and compression types + # are the same + # + return (1, undef) if ( (stat($oldFile))[3] < $bpc->{Conf}{HardLinkMax} + && !$oldFileComp == !$newFileComp + && link($oldFile, $newFile) ); + # + # There are too many links on oldFile, or compression + # type if different, so now we have to copy it. + # + # We need to compute the file size, which is expensive + # since we need to read the file twice. That's probably + # ok since the hardlink limit is rarely hit. + # + my $readFd = BackupPC::FileZIO->open($oldFile, 0, $oldFileComp); + if ( !defined($readFd) ) { + return (0, undef, undef, undef, ["LinkOrCopy: can't open $oldFile"]); + } + while ( $readFd->read(\$data, $BufSize) > 0 ) { + $nRead += length($data); + } + $readFd->rewind(); + + my $poolWrite = BackupPC::PoolWrite->new($bpc, $newFile, + $nRead, $newFileComp); + while ( $readFd->read(\$data, $BufSize) > 0 ) { + $poolWrite->write(\$data); + } + my($exists, $digest, $outSize, $errs) = $poolWrite->close; + + return ($exists, $digest, $nRead, $outSize, $errs); +} + 1;