📄 rsyncfileio.pm
字号:
}}## Finish up the current receive file. Returns undef if ok, -1 if not.# Returns 1 if the md4 digest doesn't match.#sub fileDeltaRxDone{ my($fio, $md4, $phase) = @_; my $name = $1 if ( $fio->{rxFile}{name} =~ /(.*)/s ); my $ret; close($fio->{rxInFd}) if ( defined($fio->{rxInFd}) ); unlink("$fio->{outDirSh}RStmp") if ( -f "$fio->{outDirSh}RStmp" ); $fio->{phase} = $phase; # # Check the final md4 digest # if ( defined($md4) ) { my $newDigest; if ( !defined($fio->{rxDigest}) ) { # # File was exact match, but we still need to verify the # MD4 checksum. Compute the md4 digest (or fetch the # cached one.) # if ( defined(my $attr = $fio->{rxLocalAttr}) ) { # # block size doesn't matter: we're only going to # fetch the md4 file digest, not the block digests. # my($err, $csum, $blkSize) = BackupPC::Xfer::RsyncDigest->digestStart( $attr->{fullPath}, $attr->{size}, 0, 2048, $fio->{checksumSeed}, 1, $attr->{compress}, 1, $fio->{protocol_version}); if ( $err ) { $fio->log("Can't open $attr->{fullPath} for MD4" . " check (err=$err, $name)"); $fio->{stats}{errorCnt}++; } else { if ( $fio->{logLevel} >= 5 ) { my($isCached, $invalid) = $csum->isCached; $fio->log("MD4 $attr->{fullPath} cache = $isCached," . " invalid = $invalid"); } $newDigest = $csum->digestEnd; } $fio->{rxSize} = $attr->{size}; } else { # # Empty file; just create an empty file digest # $fio->{rxDigest} = File::RsyncP::Digest->new(); $fio->{rxDigest}->protocol($fio->{protocol_version}); $fio->{rxDigest}->add(pack("V", $fio->{checksumSeed})); $newDigest = $fio->{rxDigest}->digest; } $fio->log("$name got exact match") if ( $fio->{logLevel} >= 5 ); } else { $newDigest = $fio->{rxDigest}->digest; } if ( $fio->{logLevel} >= 3 ) { my $md4Str = unpack("H*", $md4); my $newStr = unpack("H*", $newDigest); $fio->log("$name got digests $md4Str vs $newStr") } if ( $md4 ne $newDigest ) { if ( $phase > 0 ) { $fio->log("$name: fatal error: md4 doesn't match on retry;" . " file removed"); $fio->{stats}{errorCnt}++; } else { $fio->log("$name: md4 doesn't match: will retry in phase 1;" . " file removed"); } if ( defined($fio->{rxOutFd}) ) { $fio->{rxOutFd}->close; unlink($fio->{rxOutFile}); } delete($fio->{rxFile}); delete($fio->{rxOutFile}); return 1; } } # # One special case is an empty file: if the file size is # zero we need to open the output file to create it. # if ( $fio->{rxSize} == 0 ) { my $rxOutFileRel = "$fio->{shareM}/" . $fio->{bpc}->fileNameMangle($name); my $rxOutFile = $fio->{outDir} . $rxOutFileRel; $fio->{rxOutFd} = BackupPC::PoolWrite->new($fio->{bpc}, $rxOutFile, $fio->{rxSize}, $fio->{xfer}{compress}); } if ( !defined($fio->{rxOutFd}) ) { # # No output file, meaning original was an exact match. # $fio->log("$name: nothing to do") if ( $fio->{logLevel} >= 5 ); my $attr = $fio->{rxLocalAttr}; 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->{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 # set the attributes. # my $rxOutFile = $fio->{outDirSh} . $fio->{bpc}->fileNameMangle($name); my($exists, $digest, $origSize, $outSize, $errs) = BackupPC::PoolWrite::LinkOrCopy( $fio->{bpc}, $attr->{fullPath}, $attr->{compress}, $rxOutFile, $fio->{xfer}{compress}); # # Cumulate the stats # $fio->{stats}{TotalFileCnt}++; $fio->{stats}{TotalFileSize} += $fio->{rxSize}; $fio->{stats}{ExistFileCnt}++; $fio->{stats}{ExistFileSize} += $fio->{rxSize}; $fio->{stats}{ExistFileCompSize} += -s $rxOutFile; $fio->{rxFile}{size} = $fio->{rxSize}; $ret = $fio->attribSet($fio->{rxFile}); $fio->log(@$errs) if ( defined($errs) && @$errs ); if ( !$exists && $outSize > 0 ) { # # the hard link failed, most likely because the target # file has too many links. We have copied the file # instead, so add this to the new file list. # my $rxOutFileRel = "$fio->{shareM}/" . $fio->{bpc}->fileNameMangle($name); $rxOutFileRel =~ s{^/+}{}; my $fh = $fio->{newFilesFH}; print($fh "$digest $origSize $rxOutFileRel\n") if ( defined($fh) ); } } } else { my $exist = $fio->processClose($fio->{rxOutFd}, $fio->{rxOutFileRel}, $fio->{rxSize}, 1); $fio->logFileAction($exist ? "pool" : "create", $fio->{rxFile}) if ( $fio->{logLevel} >= 1 ); $fio->{rxFile}{size} = $fio->{rxSize}; $ret = $fio->attribSet($fio->{rxFile}); } delete($fio->{rxDigest}); delete($fio->{rxInData}); delete($fio->{rxFile}); delete($fio->{rxOutFile}); return $ret;}## Callback function for BackupPC::View->find. Note the order of the# first two arguments.#sub fileListEltSend{ my($a, $fio, $fList, $outputFunc) = @_; my $name = $a->{relPath}; my $n = $name; 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 || $type == BPC_FTYPE_BLOCKDEV || $type == BPC_FTYPE_SYMLINK ) { my $fh = BackupPC::FileZIO->open($a->{fullPath}, 0, $a->{compress}); my($str, $rdSize); if ( defined($fh) ) { $rdSize = $fh->read(\$str, $a->{size} + 1024); if ( $type == BPC_FTYPE_SYMLINK ) { # # Reconstruct symbolic link # $extraAttribs = { link => $str }; if ( $rdSize != $a->{size} ) { # ERROR $fio->log("$name: can't read exactly $a->{size} bytes"); $fio->{stats}{errorCnt}++; } } elsif ( $str =~ /(\d*),(\d*)/ ) { # # Reconstruct char or block special major/minor device num # # Note: char/block devices have $a->{size} = 0, so we # can't do an error check on $rdSize. # $extraAttribs = { rdev => $1 * 256 + $2, rdev_major => $1, rdev_minor => $2, }; } else { $fio->log("$name: unexpected special file contents $str"); $fio->{stats}{errorCnt}++; } $fh->close; } else { # ERROR $fio->log("$name: can't open"); $fio->{stats}{errorCnt}++; } } elsif ( $fio->{preserve_hard_links} && ($type == BPC_FTYPE_HARDLINK || $type == BPC_FTYPE_FILE) && ($type == BPC_FTYPE_HARDLINK || $fio->{protocol_version} < 27 || $a->{hlink_self}) ) { # # Fill in fake inode information so that the remote rsync # can correctly create hardlinks. # $name =~ s/^\.?\/+//; my($target, $inode); if ( $type == BPC_FTYPE_HARDLINK ) { my $fh = BackupPC::FileZIO->open($a->{fullPath}, 0, $a->{compress}); if ( defined($fh) ) { $fh->read(\$target, 65536); $fh->close; $target =~ s/^\.?\/+//; if ( defined($fio->{hlinkFile2Num}{$target}) ) { $inode = $fio->{hlinkFile2Num}{$target}; } else { $inode = $fio->{fileListCnt}; $fio->{hlinkFile2Num}{$target} = $inode; } } else { $fio->log("$a->{fullPath}: can't open for hardlink"); $fio->{stats}{errorCnt}++; } } elsif ( $a->{hlink_self} ) { if ( defined($fio->{hlinkFile2Num}{$name}) ) { $inode = $fio->{hlinkFile2Num}{$name}; } else { $inode = $fio->{fileListCnt}; $fio->{hlinkFile2Num}{$name} = $inode; } } $inode = $fio->{fileListCnt} if ( !defined($inode) ); $fio->log("$name: setting inode to $inode"); $extraAttribs = { %$extraAttribs, dev => 0, inode => $inode, }; } my $f = { name => $n, mode => $a->{mode} & ~S_HLINK_TARGET, uid => $a->{uid}, gid => $a->{gid}, mtime => $a->{mtime}, size => $a->{size}, %$extraAttribs, }; my $logName = $f->{name}; from_to($f->{name}, "utf8", $fio->{clientCharset}) if ( $fio->{clientCharset} ne "" ); $fList->encode($f); $logName = "$fio->{xfer}{pathHdrDest}/$logName"; $logName =~ s{//+}{/}g; $f->{name} = $logName; $fio->logFileAction("restore", $f) if ( $fio->{logLevel} >= 1 ); &$outputFunc($fList->encodeData); # # Cumulate stats # $fio->{fileListCnt}++; if ( $type != BPC_FTYPE_DIR ) { $fio->{stats}{TotalFileCnt}++; $fio->{stats}{TotalFileSize} += $a->{size}; }}sub fileListSend{ my($fio, $flist, $outputFunc) = @_; # # Populate the file list with the files requested by the user. # Since some might be directories so we call BackupPC::View::find. # $fio->log("fileListSend: sending file list: " . join(" ", @{$fio->{fileList}})) if ( $fio->{logLevel} >= 4 ); $fio->{fileListCnt} = 0; $fio->{hlinkFile2Num} = {}; foreach my $name ( @{$fio->{fileList}} ) { $fio->{view}->find($fio->{xfer}{bkupSrcNum}, $fio->{xfer}{bkupSrcShare}, $name, 1, \&fileListEltSend, $fio, $flist, $outputFunc); }}sub finish{ my($fio, $isChild) = @_; # # If we are aborting early, remove the last file since # it was not complete # if ( $isChild && defined($fio->{rxFile}) ) { unlink("$fio->{outDirSh}RStmp") if ( -f "$fio->{outDirSh}RStmp" ); if ( defined($fio->{rxFile}) ) { unlink($fio->{rxOutFile}); $fio->log("finish: removing in-process file $fio->{rxFile}{name}"); } } # # Flush the attributes if this is the child # $fio->attribWrite(undef) if ( $isChild );}#sub is_tainted#{# return ! eval {# join('',@_), kill 0;# 1;# };#}1;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -