差分FTPを考える(5 – 組み込み

ここまで出来たら、もとのFTPプログラムに組み込みました。

#!/usr/bin/perl

use strict;
use Net::FTP;
use Storable qw(nstore retrieve);
use Cwd;
my $cwd = getcwd();

# 引数を読み取る
if ($#ARGV ne 4 ){
    print "引数が誤っています。\n";
    print "$0 [hostname] [user] [password] [fromdir] [todir]\n";
    exit 1;
}

my $hostname=$ARGV[0];
my $user =$ARGV[1];
my $password=$ARGV[2];
my $from =$ARGV[3];
my $to =$ARGV[4];

my $from_dir =`dirname $from`;
my $from_base=`basename $from`;
my $ret;
chomp $from_base;
chomp $from_dir;

# 前回の状態を読み込む
#----- conf --------
my $bdata='before.dat';
#-------------------
#### Read ###########################
my %btmp;
if ( -f $bdata ){
    %btmp=%{ retrieve(${bdata}) };
}
#####################################

# 転送予定のフォルダのリストを取る
my $ret=chdir("$from");
my %ftmp;
open (FNAME,qq(find . -type f|));
while (<FNAME>){
    chomp;
    my $dn=`dirname $_`;
    my $fn=`basename $_`;
    chomp($dn);
    chomp($fn);
    my $cksum=`cksum $_`;
    my @cksums=split( " " , $cksum );

    $ftmp{$_} = qq($cksums[0],$cksums[1]);
}

# 接続
my $ftp= Net::FTP->new(qq($hostname), Debug => 0);
$ftp->login($user , $password );
$ftp->binary();
$ret=$ftp->cwd($to );
if($ret eq ''){
    print qq(cwd error \[$to\]\n);
    exit 1;
}

# ディレクトリをfindで検索してput先にmkdirする。
open (DIRNAME,qq(/usr/bin/find . -type d|));
while (<DIRNAME>){
    chomp;
    $ftp->mkdir($_);
}
close DIRNAME;

# ファイルをfindで検索してput先にputする。
open (FNAME,qq(/usr/bin/find . -type f|));
while (<FNAME>){
    chomp;
    # 前回と同じかどうかをチェック
    if ( $btmp{$_} eq $ftmp{$_} ){
        next;
    }
    my $dn=`dirname $_`;
    my $fn=`basename $_`;
    chomp($dn);
    chomp($fn);
    $ftp->cwd($dn);
    if($ret eq ''){
        print qq(cwd error \[$dn\]\n);
        exit 1;
    }
    print &getdate . qq( [put] $_\n);
    $ret=$ftp->put($_);
    if($ret eq ''){
         print qq(put error \[$_\]\n);
        exit 1;
    }
    $ftp->cwd($to);
}
close FNAME;

#### Write ##########################
chdir $cwd;
nstore \%ftmp , $bdata;
#####################################

sub getdate{
    my ($sec,$min,$hh,$dd,$mm,$yy,$weak,$yday,$opt) = localtime(time);
    #my $t="$yy/$mm/$dd $hh:$min:$sec";
    my $t=sprintf("%04d/%02d/%02d %02d:%02d:%02d",$yy+1900,$mm+1,$dd,$hh,$min,$sec);
    return $t;
}

1;

ファイル情報はハッシュに詰めています。
%btmpが前回のファイル情報、%ftmpが現在のファイル情報です。
キーがファイルパスで、値にチェックサム値を入れています。
%btmpはbefore.datから読み込んで、全てが正常に終わったら%ftmpに上書きしています。
こうして常に前回の情報が保存されるようにしています。

ファイルの変化を確かめるためにcksumコマンドで確認しています。

$ cksum test.dat
3517503372 127 test.dat

チェックサム値 ファイルサイズ ファイル名

という表記になっています。
チェックサム値だけでも良いのですが、"3517503372,127″のようにカンマでつなげて精度を高めています。
とは言え、実際には単にファイルが変わったかどうかを知りたいだけなので、チェックサム値だけで十分だと思います。