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

差分のみ転送するように修正しました。
findを-lsをつけて実行すると以下のように出力します。

1125899906910144    4 -rwx------   1 Admin None         1094 2月 21  2013 test.lnk

0番目がiノード、10番目がファイル名になっています。
あとは前述した、リトライと削除されてしまったファイルのハッシュキーの削除が追加されています。

更に前述したように考慮されていない点が2点あります。

  1. ファイルが削除されても既にアップされたファイルは消さない
  2. ディレクトリが削除されても、削除しない

ファイルについてはハッシュのキーを比較すればできそうですが、
ディレクトリについてはちょっと難しいかもしれません。
ディレクトリについては妥協しても良いかもしれませんが。

#!/usr/bin/perl

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

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

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

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

my $ret;
chomp $from_base;
chomp $from_dir;

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

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

# 接続
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 -ls|));
while (<FNAME>){
    chomp;
    my $inode =(split(" ",$_))[0];
    my $filepath=(split(" ",$_))[10];
    # 前回と同じかどうかをチェック
    if ( $btmp{$filepath} eq $ftmp{$filepath} ){
        next;
    }
    my $dn=`dirname $filepath`;
    my $fn=`basename $filepath`;
    chomp($dn);
    chomp($fn);
    $ftp->cwd($dn);
    if($ret eq ''){
        print qq(cwd error \[$dn\]\n);
        exit 1;
    }
    print &getdate . qq( [put] $filepath\n);
    # エラーになることがある.
    for my $var (3,5,10,30,60){
        #ファイルが無くなることがある?
        if ( -f $filepath ){
            $ret=$ftp->put($filepath);
            if($ret eq ''){
                print qq(put error \[$filepath\] sleep $var\n);
                sleep $var;
            }else{
                if ( $var ne 3 ){
                    print qq(retry \[$filepath\] ok.\n);
                }
            last;
            }
        }else{
            print qq(not found \[$filepath\] skip.\n);
            delete $ftmp{$filepath};
            last;
        }
    }
    $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;