⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 rsyncdigest.pm

📁 老外写的linux下的文件备份软件
💻 PM
📖 第 1 页 / 共 2 页
字号:
#============================================================= -*-perl-*-## BackupPC::Xfer::RsyncDigest package## DESCRIPTION##   This library defines a BackupPC::Xfer::RsyncDigest class for computing#   and caching rsync checksums.## AUTHOR#   Craig Barratt  <cbarratt@users.sourceforge.net>## COPYRIGHT#   Copyright (C) 2001-2007  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#   the Free Software Foundation; either version 2 of the License, or#   (at your option) any later version.##   This program is distributed in the hope that it will be useful,#   but WITHOUT ANY WARRANTY; without even the implied warranty of#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the#   GNU General Public License for more details.##   You should have received a copy of the GNU General Public License#   along with this program; if not, write to the Free Software#   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA##========================================================================## Version 3.1.0, released 25 Nov 2007.## See http://backuppc.sourceforge.net.##========================================================================package BackupPC::Xfer::RsyncDigest;use strict;use BackupPC::FileZIO;use vars qw( $RsyncLibOK );use Carp;use Fcntl;require Exporter;use vars qw( @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS );my $Log = \&logHandler;## Magic value for checksum seed.  We only cache block and file digests# when the checksum seed matches this value.#use constant RSYNC_CSUMSEED_CACHE     => 32761;@ISA = qw(Exporter);@EXPORT    = qw( );@EXPORT_OK = qw(                  RSYNC_CSUMSEED_CACHE             );%EXPORT_TAGS = (    'all'    => [ @EXPORT_OK ],);BEGIN {    eval "use File::RsyncP;";    if ( $@ ) {        #        # File::RsyncP doesn't exist.  Define some dummy constant        # subs so that the code below doesn't barf.        #        $RsyncLibOK = 0;    } else {        $RsyncLibOK = 1;    }};## Return the rsync block size based on the file size.# We also make sure the block size plus 4 (ie: cheeksumSeed)# is not a multiple of 64 - otherwise the cached checksums# will not be the same for protocol versions <= 26 and > 26.#sub blockSize{    my($class, $fileSize, $defaultBlkSize) = @_;    my $blkSize = int($fileSize / 10000);    $blkSize = $defaultBlkSize if ( $blkSize < $defaultBlkSize );    $blkSize = 16384 if ( $blkSize > 16384 );    $blkSize += 4 if ( (($blkSize + 4) % 64) == 0 );    return $blkSize;}sub fileDigestIsCached{    my($class, $file) = @_;    my $data;    sysopen(my $fh, $file, O_RDONLY) || return -1;    binmode($fh);    return -2 if ( sysread($fh, $data, 1) != 1 );    close($fh);    return $data eq chr(0xd7) ? 1 : 0;}## Compute and add rsync block and file digests to the given file.## Empty files don't get cached checksums.## If verify is set then existing cached checksums are checked.# If verify == 2 then only a verify is done; no fixes are applied.# # Returns 0 on success.  Returns 1 on good verify and 2 on bad verify.# Returns a variety of negative values on error.#sub digestAdd{    my($class, $file, $blockSize, $checksumSeed, $verify,                $protocol_version) = @_;    my $retValue = 0;    #    # Don't cache checksums if the checksumSeed is not RSYNC_CSUMSEED_CACHE    # or if the file is empty.    #    return -100 if ( $checksumSeed != RSYNC_CSUMSEED_CACHE || !-s $file );    if ( $blockSize == 0 ) {	&$Log("digestAdd: bad blockSize ($file, $blockSize, $checksumSeed)");	$blockSize = 2048;    }    my $nBlks = int(65536 * 16 / $blockSize) + 1;    my($data, $blockDigest, $fileDigest);    return -101 if ( !$RsyncLibOK );    my $digest = File::RsyncP::Digest->new;    $digest->protocol($protocol_version)                        if ( defined($protocol_version) );    $digest->add(pack("V", $checksumSeed)) if ( $checksumSeed );    return -102 if ( !defined(my $fh = BackupPC::FileZIO->open($file, 0, 1)) );    my $fileSize;    while ( 1 ) {        $fh->read(\$data, $nBlks * $blockSize);        $fileSize += length($data);        last if ( $data eq "" );        $blockDigest .= $digest->blockDigest($data, $blockSize, 16,                                             $checksumSeed);        $digest->add($data);    }    $fileDigest = $digest->digest2;    my $eofPosn = sysseek($fh->{fh}, 0, 1);    $fh->close;    my $rsyncData = $blockDigest . $fileDigest;    my $metaData  = pack("VVVV", $blockSize,                                 $checksumSeed,                                 length($blockDigest) / 20,                                 0x5fe3c289,                # magic number                        );    my $data2 = chr(0xb3) . $rsyncData . $metaData;#    printf("appending %d+%d bytes to %s at offset %d\n",#                                            length($rsyncData),#                                            length($metaData),#                                            $file,#                                            $eofPosn);    sysopen(my $fh2, $file, O_RDWR) || return -103;    binmode($fh2);    return -104 if ( sysread($fh2, $data, 1) != 1 );    if ( $data ne chr(0x78) && $data ne chr(0xd6) && $data ne chr(0xd7) ) {        &$Log(sprintf("digestAdd: $file has unexpected first char 0x%x",                             ord($data)));        return -105;    }    return -106 if ( sysseek($fh2, $eofPosn, 0) != $eofPosn );    if ( $verify ) {        my $data3;        #        # Verify the cached checksums        #        return -107 if ( $data ne chr(0xd7) );        return -108 if ( sysread($fh2, $data3, length($data2) + 1) < 0 );        if ( $data2 eq $data3 ) {            return 1;        }        #        # Checksums don't agree - fall through so we rewrite the data        #        &$Log(sprintf("digestAdd: %s verify failed; redoing checksums; len = %d,%d; eofPosn = %d, fileSize = %d",                $file, length($data2), length($data3), $eofPosn, $fileSize));        #&$Log(sprintf("dataNew  = %s", unpack("H*", $data2)));        #&$Log(sprintf("dataFile = %s", unpack("H*", $data3)));        return -109 if ( sysseek($fh2, $eofPosn, 0) != $eofPosn );        $retValue = 2;        return $retValue if ( $verify == 2 );    }    return -110 if ( syswrite($fh2, $data2) != length($data2) );    if ( $verify ) {        #        # Make sure there is no extraneous data on the end of        # the file.  Seek to the end and truncate if it doesn't        # match our expected length.        #        return -111 if ( !defined(sysseek($fh2, 0, 2)) );        if ( sysseek($fh2, 0, 1) != $eofPosn + length($data2) ) {            if ( !truncate($fh2, $eofPosn + length($data2)) ) {                &$Log(sprintf("digestAdd: $file truncate from %d to %d failed",                                sysseek($fh2, 0, 1), $eofPosn + length($data2)));                return -112;            } else {                &$Log(sprintf("digestAdd: %s truncated from %d to %d",                                $file,                                sysseek($fh2, 0, 1), $eofPosn + length($data2)));            }        }    }    return -113 if ( !defined(sysseek($fh2, 0, 0)) );    return -114 if ( syswrite($fh2, chr(0xd7)) != 1 );    close($fh2);    return $retValue;}## Return rsync checksums for the given file.  We read the cached checksums# if they exist and the block size and checksum seed match.  Otherwise# we compute the checksums from the file contents.## The doCache flag can take three ranges:

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -