[ftp] ミラーリングの前にバイナリモードとテキストモードの話
バイナリモードとテキストモードの切り替えを自動的にしてくれるftpクライアントがある。このようなソフトの多くはモード自動判定にファイルの拡張子を使っていることが多い。以降で述べるffftpもそんなソフトのひとつだ。バイナリモードはファイル中の改行コード変換を行わないモードで、テキストモードはファイル中の改行コード変換を行うモードである。
そもそもバイナリモードとテキストモードとは何で生じたかというとサーバとクライアントが採用している改行コードが互いに異なることが原因なのである。逆に言えば、サーバとクライアントが同じ改行コードを用いていれば全てのファイルをバイナリモードで転送しても全く問題ない。より間違いのないように言うならば、アップロードするファイルの改行コードをローカルで編集しているときからリモートの改行コードと同じものにすれば、全てのファイルをバイナリモードで転送しても問題無い。親切なエディタは改行コードを変換してくれる機能を持ちあわせている。
例えばサーバがunix機だった場合、改行コードはLFである(つまりエスケープシーケンス\nで出力されるのはLine Feed、行を始める、である。)。これに対しクライアントがWindows機だった場合、改行コードはCR+LFである(つまりエスケープシーケンス\nで出力されるのはCarriage Return + Line Feed、行頭へカーソルを持ってきて行を始める、である。)。サーバとクライアントの改行コードは異なっている。したがってファイルごとにモードを指定してアップロードしなめればならない。
ここから先は憶測だが、今までのことに間違いがなければftpユーザは少なくともサーバの改行コードを知っていなければならない。ということは、モード自動判定ができるソフトはユーザーが設定すること無しにサーバの改行コードを判定しているということになるのかもしれない。言い換えれば、テキストモードの場合には、CRまたはLFまたはCR+LFを全てLFにするという方法ではサーバがunix機の場合はいいけど、サーバがWindows機の場合は問題ありだと思う(Windowsの改行コードはCR+LF)。
[ftp] ホスト対ローカルがホスト対ホストになると改行コードはどう考える?
ローカルで作った Web ページをホストにアップロードすることをよくやる。このとき僕らは転送モード切り替えを自動にしていることが多い。前述のように、ローカルとホストの改行コードが異なっているからだ。では、ホスト対ホストの場合はどうだろう。例えばホスト A が Unix でローカルが Windows でホスト B が Unix の場合を考えてみよう。ローカルでファイル内容の書き換えを行わない限り、わざわざ自動モード切り替え機能はオフにしたほうがいいと思う。なぜならホスト同士は同じ改行コードを採用しているから。もっと言えば、文字コード切り替えや半角かなを全角かなに書き換える機能もオフにしたほうがいい。なぜならミラーサイトを作るうえで余分な機能は必要ないから。
上で述べたような機能は結局転送されてきた内容や転送する内容をチェックしているわけだから余分な負荷をかけることになる。話を戻して、OS と改行コードの相対表は下のようなものである。ascii モードとはこれらの改行コードの相互変換を行ってアップロードやダウンロードするのだ。つまりファイルが使われる環境のもとでしかるべき改行コードが守れていれば問題は無いのである。では、ホスト間で同じ OS を使っている場合は、ワンクッションおいてローカルへのダウンロード作業を含めるとしても、バイナリモードでダウンロードとアップロードを行えばよいということになる。これはローカルでファイルの編集作業を行わないならばの話である。
つまり、ホスト A が Web ページの公開ファイルを直接編集できるサービスを提供していて、管理者は Web ページの編集をこのサービスを通して行う。管理者は別のミラーサイトであるホスト B にも全く同じデータをおきたい。管理者のコンピュータもしくはサーバ上で上のようなスクリプトを起動させてミラーリングを行う。このようなニーズにこたえることができる。
Remote | Host | Remote 改行コード | Host 改行コード |
---|---|---|---|
Mac | Mac | CR | CR |
Mac | Win | CR | CR+LF |
Mac | Unix | CR | LF |
Win | Mac | CR+LF | CR |
Win | Win | CR+LF | CR+LF |
Win | Unix | CR+LF | LF |
Unix | Mac | LF | CR |
Unix | Win | LF | CR+LF |
Unix | Unix | LF | LF |
+--------+ Write +----------------+ +--------+ | |<--------| | | | | Host A | | Author Machine | | Host B | | |-------->| |-------->| | +--------+ Get +----------------+ Put +--------+
+--------+ Write +-----------+ +--------+ | |XX<-----------------XX| Author | | | | Host A | | Machine | | Host B | | |21<-----------------BB| |AA----------------->21| | | | Get index.html | | Put index.html | | | | |+---------+| | | | | || Port || | | | |20----------------->CC|| Forward ||FF----------------->20| | | | index.html || Deamon || index.html | | | | |+---------+| | | +--------+ +-----------+ +--------+
[ftp] リモートホスト間でミラーリングするには
ftpの仕様によれば間にローカルホストを挟まなくても直接リモートホスト同士でやり取りができるらしい。でも、これに対応しているサーバ自体が少ないため(攻撃の可能性があるため)、この方法は使えない。仕方ないのでリモートA、ローカル、リモートB、の順番でリモートAの最新ファイルをリモートBまで持ってくるようにする。例えば下のようなbatファイルを作ってみた。
ffftp.exe -s REMOTE_A -d -f -q ffftp.exe -s REMOTE_B -m -f -q
でも上手くいかない。なぜなら、ffftpがローカルにリモートAの内容をもってくる前に次の処理に進んでしまうからだ。これを解決するにはプロセスを監視してffftpが終了したら次の処理に進むようにする。でもこれをWindowsでやろうと思うとはなはだめんどくさいことになる。例えばCygwin等のシェルスクリプトが動く環境を導入して、ps -W | grep FFFTPとかやるしかないだろう。ただ、Cygwinを導入するくらいならばもっと別の方法があると思う。
紆余曲折あって結論は次のようになった。それは、上のコマンドをそれぞれ人間が終了確認して行うようにするのだ。ほっとけばミラーサイトが作れるというわけではないが、そのくらいの手間はしかたないだろう。まぁ1時間ごとに交互にダウンロード、アップロードするようなスケジュールを組むというのも一つの解決策だとは思う。
[ftp] NcFTPを使ってみたらどうなるか
最初はCygwin+lftpでいけるかと思ったが、少なくとも内の環境では上手くいかなかった。仕方いないのでCyuwin+NcFTPにしてみた。NcFTPのffftpに対するアドバンテージといえば、ほっといてもミラーリングを行ってくれることと、アップロードされたファイルのタイムスタンプをアップロード時のタイムスタンプではない物にしてくれること、の2点だと思う。欠点はとにかく処理が遅いこと。ffftpに比べると格段にのろい。その上、付加されるタイムスタンプの設定が利かないと思う。付加されたタイムスタンプはローカルのものと全く同じ物ではないし、9時間問題というわけでもないので、多分サーバの現在時刻だろう。したがってNcFTPを上のように使う方法はお勧めできない。
でもとりあえず手法だけは公開しておこうと思う。僕よりもずっと賢い人が何か解決策を見つけてくれるかもしれないし。僕はCygwin上で下のようなシェルスクリプトを動かしてみた。とにかくこれはテストのために書いたものだからぜんぜんきれいではないけどね。
ncftp -u USER_A -p PASS_A ftp.HOST_NAME_A << __GET__ get -R * __GET__ ncftp -u USER_B -p PASS_B ftp.HOST_NAME_B << __PUT__ put -R * __PUT__