📄 rsyncdigest.pm
字号:
## - doCache < 0: don't generate/use cached checksums# - doCache == 0: don't generate, but do use cached checksums if available# - doCache > 0: generate (if necessary) and use cached checksums## Note: caching is only enabled when compression is on and the# checksum seed is RSYNC_CSUMSEED_CACHE (32761).## Returns 0 on success. Returns a variety of negative values on error.#sub digestStart{ my($class, $fileName, $fileSize, $blockSize, $defBlkSize, $checksumSeed, $needMD4, $compress, $doCache, $protocol_version) = @_; return -1 if ( !$RsyncLibOK ); my $data; my $dg = bless { name => $fileName, needMD4 => $needMD4, digest => File::RsyncP::Digest->new, protocol_version => $protocol_version, }, $class; $dg->{digest}->protocol($dg->{protocol_version}) if ( defined($dg->{protocol_version}) ); if ( $fileSize > 0 && $compress && $doCache >= 0 ) { open(my $fh, "<", $fileName) || return -2; binmode($fh); return -3 if ( sysread($fh, $data, 4096) < 1 ); my $ret; if ( (vec($data, 0, 8) == 0x78 || vec($data, 0, 8) == 0xd6) && $doCache > 0 && $checksumSeed == RSYNC_CSUMSEED_CACHE ) { # # RSYNC_CSUMSEED_CACHE (32761) is the magic number that # rsync uses for checksumSeed with the --fixed-csum option. # # We now add the cached checksum data to the file. There # is a possible race condition here since two BackupPC_dump # processes might call this function at the same time # on the same file. But this should be ok since both # processes will write the same data, and the order # in which they write it doesn't matter. # close($fh); $ret = $dg->digestAdd($fileName, $blockSize || BackupPC::Xfer::RsyncDigest->blockSize( $fileSize, $defBlkSize), $checksumSeed, 0, $dg->{protocol_version}); if ( $ret < 0 ) { &$Log("digestAdd($fileName) failed ($ret)"); } # # now re-open the file and re-read the first byte # open($fh, "<", $fileName) || return -4; binmode($fh); return -5 if ( read($fh, $data, 1) != 1 ); } if ( $ret >= 0 && vec($data, 0, 8) == 0xd7 ) { # # Looks like this file has cached checksums # Read the last 48 bytes: that's 2 file MD4s (32 bytes) # plus 4 words of meta data # my $cacheInfo; if ( length($data) >= 4096 ) { return -6 if ( !defined(sysseek($fh, -4096, 2)) ); return -7 if ( sysread($fh, $data, 4096) != 4096 ); } $cacheInfo = substr($data, -48); ($dg->{md4DigestOld}, $dg->{md4Digest}, $dg->{blockSize}, $dg->{checksumSeed}, $dg->{nBlocks}, $dg->{magic}) = unpack("a16 a16 V V V V", $cacheInfo); if ( $dg->{magic} == 0x5fe3c289 && $dg->{checksumSeed} == $checksumSeed && ($blockSize == 0 || $dg->{blockSize} == $blockSize) ) { $dg->{fh} = $fh; $dg->{cached} = 1; if ( length($data) >= $dg->{nBlocks} * 20 + 48 ) { # # We have all the data already - just remember it # $dg->{digestData} = substr($data, length($data) - $dg->{nBlocks} * 20 - 48, $dg->{nBlocks} * 20); } else { # # position the file at the start of the rsync block checksums # (4 (adler) + 16 (md4) bytes each) # return -8 if ( !defined(sysseek($fh, -$dg->{nBlocks} * 20 - 48, 2)) ); } } else { # # cached checksums are not valid, so we close the # file and treat it as uncached. # $dg->{cachedInvalid} = 1; close($fh); } } } if ( !$dg->{cached} ) { # # This file doesn't have cached checksums, or the checksumSeed # or blocksize doesn't match. Open the file and prepare to # compute the checksums. # $blockSize = BackupPC::Xfer::RsyncDigest->blockSize($fileSize, $defBlkSize) if ( $blockSize == 0 ); $dg->{checksumSeed} = $checksumSeed; $dg->{blockSize} = $blockSize; $dg->{fh} = BackupPC::FileZIO->open($fileName, 0, $compress); return -9 if ( !defined($dg->{fh}) ); if ( $needMD4) { $dg->{csumDigest} = File::RsyncP::Digest->new; $dg->{csumDigest}->protocol($dg->{protocol_version}) if ( defined($dg->{protocol_version}) ); $dg->{csumDigest}->add(pack("V", $dg->{checksumSeed})); } } return (undef, $dg, $dg->{blockSize});}sub digestGet{ my($dg, $num, $csumLen, $noPad) = @_; my($fileData); my $blockSize = $dg->{blockSize}; if ( $dg->{cached} ) { my $thisNum = $num; $thisNum = $dg->{nBlocks} if ( $thisNum > $dg->{nBlocks} ); if ( defined($dg->{digestData}) ) { $fileData = substr($dg->{digestData}, 0, 20 * $thisNum); $dg->{digestData} = substr($dg->{digestData}, 20 * $thisNum); } else { sysread($dg->{fh}, $fileData, 20 * $thisNum); } $dg->{nBlocks} -= $thisNum; if ( $thisNum < $num && !$noPad) { # # unexpected shortfall of data; pad with zero digest # $fileData .= pack("c", 0) x (20 * ($num - $thisNum)); } return $dg->{digest}->blockDigestExtract($fileData, $csumLen); } else { if ( $dg->{fh}->read(\$fileData, $blockSize * $num) <= 0 ) { # # unexpected shortfall of data; pad with zeros # $fileData = pack("c", 0) x ($blockSize * $num) if ( !$noPad ); } $dg->{csumDigest}->add($fileData) if ( $dg->{needMD4} ); return $dg->{digest}->blockDigest($fileData, $blockSize, $csumLen, $dg->{checksumSeed}); }}sub digestEnd{ my($dg, $skipMD4) = @_; my($fileData); if ( $dg->{cached} ) { close($dg->{fh}); if ( $dg->{needMD4} ) { if ( $dg->{protocol_version} <= 26 ) { return $dg->{md4DigestOld}; } else { return $dg->{md4Digest}; } } } else { # # make sure we read the entire file for the file MD4 digest # if ( $dg->{needMD4} && !$skipMD4 ) { my $fileData; while ( $dg->{fh}->read(\$fileData, 65536) > 0 ) { $dg->{csumDigest}->add($fileData); } } $dg->{fh}->close(); return $dg->{csumDigest}->digest if ( $dg->{needMD4} ); }}sub isCached{ my($dg) = @_; return wantarray ? ($dg->{cached}, $dg->{cachedInvalid}) : $dg->{cached};}sub blockSizeCurr{ my($dg) = @_; return $dg->{blockSize};}## Default log handler#sub logHandler{ my($str) = @_; print(STDERR $str, "\n");}## Set log handler to a new subroutine.#sub logHandlerSet{ my($dg, $sub) = @_; $Log = $sub;}1;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -