电脑技术学习

同步 UNIX 文件

dn001

   这个脚本的基本原理是创建原目录结构的两个拷贝。第一个拷贝作为参照拷贝,其中包含目录结构的精确副本。这样,当再次同步目录时,就可以像一般情况一样比较源和目标文件并判断出差异。在 rsync 命令中使用 --itemize-changes 选项,rsync 就会创建一个参照列表,其中列出在同步期间每个文件所发生的情况。输出详细说明文件是否已经修改过(或新建),或文件是否已经删除。清单 3 中给出一个示例。

   清单 3. rsync 生成的修改记录

    .d..t...... t1/a/
*deleting   t1/a/3
.d..t...... t1/b/
>f.st...... t1/b/1
>f+++++++++ t1/b/6
 

   以 .d. 开头的行表示新目录或目录修改。*deleting 行表示文件已经从源目录中删除。>f 行表示文件已经修改过或是新建的文件(>f++++++++)。

   通过解析这个输出文件,可以判断出源目录和目标参照目录之间的差异。判断出差异之后,可以在第三个目录中创建原文件的加密版本。通过使用修改记录,只加密(或删除)在上一次同步操作之后修改过的文件。不能使用目录的加密版本直接执行同步,因为文件的加密版本总是与源文件不一样。

   完整的脚本见清单 4。

   清单 4. 完整脚本

    #!/usr/bin/perl

use warnings;
use strict;
use File::Basename;
use File::Path;

my $source = shift;
my $dest = shift;
my $encdest = shift;

if (!defined($source) || !defined($dest) || !defined($encdest))
{
    print "Error: Not enough arguments!n";
    print "Usage: $0 source destination encrypteddestn";
    exit(1);
}

print STDERR "Running rsync between $source and $dest ($encdest)n";

system("rsync --delete --recursive --times -og --links --perms " .
       "--hard-links --itemize-changes $source $dest " .
       ">/tmp/$$.rsynclog 2>&1");

open(DATA,"/tmp/$$.rsynclog") or dIE "Couldn't open the rsynclogn";

my @changedfiles;
my @delfiles;

while(<DATA>)
{
    next if (m/sending incremental file list/);
    chomp;
    last if (length($_) == 0);
    my ($changes,$filename) = split;
    push @changedfiles,$filename if ($changes =~ m/^>f/);
    push @delfiles,$filename if ($changes =~ m/^*del/);
}

close(DATA);

my $counter = 0;
foreach my $file (@changedfiles)
{
    if (-f "$dest/$file")
    {
        my $sourcename = encode_filename("$dest/$file");
        my $destname   = encode_filename("$encdest/$file");
        my $dirname    = dirname("$encdest/$file");
        mkpath($dirname);
        system(sprintf('cat "%s" |openssl enc -des3 ' .
                       '-pass file:/var/lib/passphrase -a >"%s"',
                       $sourcename,$destname));

        $counter++;
    }
}

my $delcounter = 0;
foreach my $file (@delfiles)
{
    unlink("$encdest/$file");
    $delcounter++;
}

print STDERR "Finished (changed: $counter, deleted: $delcounter)n";
unlink("/tmp/$$.rsynclog");

sub encode_filename
{
    my ($filename) = @_;

    $filename =~ s/ / /g;
    $filename =~ s/'/'/g;
    $filename =~ s/"/"/g;
    $filename =~ s/(/(/g;
    $filename =~ s/)/)/g;
    $filename =~ s/&/&/g;
    $filename =~ s/#/#/g;

    return($filename);
}
 

标签: