X-Git-Url: http://git.rot13.org/?p=BackupPC.git;a=blobdiff_plain;f=lib%2FBackupPC%2FXfer%2FRsyncFileIO.pm;h=ea72dce06bccee89d6d604eaf2a8c7e2ee1830a8;hp=820f898192d7e17240b8e5ffd1e1f403d378c1f2;hb=4cdaa6b8a9f5161ee2da4371d68cbbad41248ea0;hpb=5b3e6091d542c2e7445d5dd511cdf6e20aec8b8d diff --git a/lib/BackupPC/Xfer/RsyncFileIO.pm b/lib/BackupPC/Xfer/RsyncFileIO.pm index 820f898..ea72dce 100644 --- a/lib/BackupPC/Xfer/RsyncFileIO.pm +++ b/lib/BackupPC/Xfer/RsyncFileIO.pm @@ -12,7 +12,7 @@ # #======================================================================== # -# Version 3.0.0alpha, released 23 Jan 2006. +# Version 3.0.0beta0, released 11 Jul 2006. # # See http://backuppc.sourceforge.net. # @@ -61,7 +61,7 @@ sub new my $fio = bless { blockSize => 700, logLevel => 0, - digest => File::RsyncP::Digest->new($options->{protocol_version}), + digest => File::RsyncP::Digest->new(), checksumSeed => 0, attrib => {}, logHandler => \&logHandler, @@ -76,6 +76,7 @@ sub new %$options, }, $class; + $fio->{digest}->protocol($fio->{protocol_version}); $fio->{shareM} = $fio->{bpc}->fileNameEltMangle($fio->{share}); $fio->{outDir} = "$fio->{xfer}{outDir}/new/"; $fio->{outDirSh} = "$fio->{outDir}/$fio->{shareM}/"; @@ -320,8 +321,8 @@ sub viewCacheDir sub attribGetWhere { - my($fio, $f) = @_; - my($dir, $fname, $share, $shareM); + my($fio, $f, $noCache) = @_; + my($dir, $fname, $share, $shareM, $partial, $attr); $fname = $f->{name}; $fname = "$fio->{xfer}{pathHdrSrc}/$fname" @@ -340,15 +341,27 @@ sub attribGetWhere $dir = ""; $fname = $fio->{share}; } - $fio->viewCacheDir($share, $dir); $shareM .= "/$dir" if ( $dir ne "" ); - if ( defined(my $attr = $fio->{viewCache}{$shareM}{$fname}) ) { - return ($attr, 0); - } elsif ( defined(my $attr = $fio->{partialCache}{$shareM}{$fname}) ) { - return ($attr, 1); + + if ( $noCache ) { + $share = $fio->{share} if ( !defined($share) ); + my $dirAttr = $fio->{view}->dirAttrib($fio->{viewNum}, $share, $dir); + $attr = $dirAttr->{$fname}; } else { - return; + $fio->viewCacheDir($share, $dir); + if ( defined($attr = $fio->{viewCache}{$shareM}{$fname}) ) { + $partial = 0; + } elsif ( defined($attr = $fio->{partialCache}{$shareM}{$fname}) ) { + $partial = 1; + } else { + return; + } + if ( $attr->{mode} & S_HLINK_TARGET ) { + $attr->{hlink_self} = 1; + $attr->{mode} &= ~S_HLINK_TARGET; + } } + return ($attr, $partial); } sub attribGet @@ -376,8 +389,12 @@ sub attribGet $fio->log("$attr->{fullPath}: redirecting to $target (will trim " . "$fio->{xfer}{pathHdrSrc})") if ( $fio->{logLevel} >= 4 ); $target =~ s/^\Q$fio->{xfer}{pathHdrSrc}//; + $target =~ s{^/+}{}; + # + # Note: overwrites name to point to real file + # $f->{name} = $target; - $attr = $fio->attribGet($f); + ($attr) = $fio->attribGetWhere($f, 1); $fio->log(" ... now got $attr->{fullPath}") if ( $fio->{logLevel} >= 4 ); } @@ -474,6 +491,11 @@ sub attribWrite my($fio, $d) = @_; my($poolWrite); + # + # Don't write attributes on 2nd phase - they're already + # taken care of during the first phase. + # + return if ( $fio->{phase} > 0 ); if ( !defined($d) ) { # # flush all entries (in reverse order) @@ -517,7 +539,8 @@ sub attribWrite $fio->logFileAction("skip", { %{$fio->{viewCache}{$d}{$f}}, name => $name, - }) if ( $fio->{logLevel} >= 2 ); + }) if ( $fio->{logLevel} >= 2 + && $a->{type} == BPC_FTYPE_FILE ); } } elsif ( !$fio->{full} ) { ##print("Delete file $f\n"); @@ -656,12 +679,13 @@ sub makeSpecial my($fh, $fileData); if ( $fio->{full} || !defined($attr) - || $attr->{type} != $type - || $attr->{mtime} != $f->{mtime} - || $attr->{size} != $f->{size} - || $attr->{uid} != $f->{uid} - || $attr->{gid} != $f->{gid} - || $attr->{mode} != $f->{mode} + || $attr->{type} != $type + || $attr->{mtime} != $f->{mtime} + || $attr->{size} != $f->{size} + || $attr->{uid} != $f->{uid} + || $attr->{gid} != $f->{gid} + || $attr->{mode} != $f->{mode} + || $attr->{hlink_self} != $f->{hlink_self} || !defined($fh = BackupPC::FileZIO->open($attr->{fullPath}, 0, $attr->{compress})) || $fh->read(\$fileData, length($str) + 1) != length($str) @@ -831,6 +855,21 @@ sub fileDeltaRxStart . " ($fio->{rxLocalAttr}{compress} vs $fio->{xfer}{compress})") if ( $fio->{logLevel} >= 4 ); } + # + # If the local file is a hardlink then no match + # + if ( defined($fio->{rxLocalAttr}) + && $fio->{rxLocalAttr}{type} == BPC_FTYPE_HARDLINK ) { + $fio->{rxMatchBlk} = undef; + $fio->log("$fio->{rxFile}{name}: no match on hardlinks") + if ( $fio->{logLevel} >= 4 ); + my $fCopy; + # need to copy since hardlink attribGet overwrites the name + %{$fCopy} = %$f; + $fio->{rxHLinkAttr} = $fio->attribGet($fCopy, 1); # hardlink attributes + } else { + delete($fio->{rxHLinkAttr}); + } delete($fio->{rxInFd}); delete($fio->{rxOutFd}); delete($fio->{rxDigest}); @@ -883,7 +922,8 @@ sub fileDeltaRxNext if ( $fio->{logLevel} >= 9 ); $fio->{rxOutFile} = $rxOutFile; $fio->{rxOutFileRel} = $rxOutFileRel; - $fio->{rxDigest} = File::RsyncP::Digest->new($fio->{protocol_version}); + $fio->{rxDigest} = File::RsyncP::Digest->new(); + $fio->{rxDigest}->protocol($fio->{protocol_version}); $fio->{rxDigest}->add(pack("V", $fio->{checksumSeed})); } if ( defined($fio->{rxMatchBlk}) @@ -899,12 +939,15 @@ sub fileDeltaRxNext my $attr = $fio->{rxLocalAttr}; my $fh; if ( !defined($fio->{rxInFd}) && !defined($fio->{rxInData}) ) { + my $inPath = $attr->{fullPath}; + $inPath = $fio->{rxHLinkAttr}{fullPath} + if ( defined($fio->{rxHLinkAttr}) ); if ( $attr->{compress} ) { if ( !defined($fh = BackupPC::FileZIO->open( - $attr->{fullPath}, + $inPath, 0, $attr->{compress})) ) { - $fio->log("Can't open $attr->{fullPath}"); + $fio->log("Can't open $inPath"); $fio->{stats}{errorCnt}++; return -1; } @@ -955,12 +998,12 @@ sub fileDeltaRxNext } $fh->close; } else { - if ( open(F, "<", $attr->{fullPath}) ) { + if ( open(F, "<", $inPath) ) { binmode(F); $fio->{rxInFd} = *F; $fio->{rxInName} = $attr->{fullPath}; } else { - $fio->log("Unable to open $attr->{fullPath}"); + $fio->log("Unable to open $inPath"); $fio->{stats}{errorCnt}++; return -1; } @@ -973,7 +1016,7 @@ sub fileDeltaRxNext my $seekPosn = $fio->{rxMatchBlk} * $fio->{rxBlkSize}; if ( defined($fio->{rxInFd}) && !sysseek($fio->{rxInFd}, $seekPosn, 0) ) { - $fio->log("Unable to seek $attr->{rxInName} to $seekPosn"); + $fio->log("Unable to seek $fio->{rxInName} to $seekPosn"); $fio->{stats}{errorCnt}++; return -1; } @@ -1041,6 +1084,7 @@ sub fileDeltaRxDone close($fio->{rxInFd}) if ( defined($fio->{rxInFd}) ); unlink("$fio->{outDirSh}RStmp") if ( -f "$fio->{outDirSh}RStmp" ); + $fio->{phase} = $phase; # # Check the final md4 digest @@ -1080,7 +1124,8 @@ sub fileDeltaRxDone # # Empty file; just create an empty file digest # - $fio->{rxDigest} = File::RsyncP::Digest->new($fio->{protocol_version}); + $fio->{rxDigest} = File::RsyncP::Digest->new(); + $fio->{rxDigest}->protocol($fio->{protocol_version}); $fio->{rxDigest}->add(pack("V", $fio->{checksumSeed})); $newDigest = $fio->{rxDigest}->digest; } @@ -1134,11 +1179,13 @@ sub fileDeltaRxDone my $f = $fio->{rxFile}; $fio->logFileAction("same", $f) if ( $fio->{logLevel} >= 1 ); if ( $fio->{full} - || $attr->{type} != $f->{type} - || $attr->{mtime} != $f->{mtime} - || $attr->{size} != $f->{size} - || $attr->{gid} != $f->{gid} - || $attr->{mode} != $f->{mode} ) { + || $attr->{type} != $f->{type} + || $attr->{mtime} != $f->{mtime} + || $attr->{size} != $f->{size} + || $attr->{uid} != $f->{uid} + || $attr->{gid} != $f->{gid} + || $attr->{mode} != $f->{mode} + || $attr->{hlink_self} != $f->{hlink_self} ) { # # In the full case, or if the attributes are different, # we need to make a link from the previous file and @@ -1207,6 +1254,10 @@ sub fileListEltSend my $type = $a->{type}; my $extraAttribs = {}; + if ( $a->{mode} & S_HLINK_TARGET ) { + $a->{hlink_self} = 1; + $a->{mode} &= ~S_HLINK_TARGET; + } $n =~ s/^\Q$fio->{xfer}{pathHdrSrc}//; $fio->log("Sending $name (remote=$n) type = $type") if ( $fio->{logLevel} >= 1 ); if ( $type == BPC_FTYPE_CHARDEV @@ -1252,7 +1303,7 @@ sub fileListEltSend && ($type == BPC_FTYPE_HARDLINK || $type == BPC_FTYPE_FILE) && ($type == BPC_FTYPE_HARDLINK || $fio->{protocol_version} < 27 - || ($a->{mode} & S_HLINK_TARGET) ) ) { + || $a->{hlink_self}) ) { # # Fill in fake inode information so that the remote rsync # can correctly create hardlinks. @@ -1277,7 +1328,7 @@ sub fileListEltSend $fio->log("$a->{fullPath}: can't open for hardlink"); $fio->{stats}{errorCnt}++; } - } elsif ( $a->{mode} & S_HLINK_TARGET ) { + } elsif ( $a->{hlink_self} ) { if ( defined($fio->{hlinkFile2Num}{$name}) ) { $inode = $fio->{hlinkFile2Num}{$name}; } else {