"Shade検索"Wiki

CGI/USBメモリで大容量ハードディスクを同期させる

会社と自宅のPCでデータを共有している人は多いのではないでしょうか。
会社で作ったファイルを自宅に持ち帰って自宅のPCでさらに編集したり、また、自宅で途中まで作成したファイルを会社で仕上げたり・・・
会社と自宅でパソコンのハードディスクの中身が同じになっていると何かと都合がいいので同期しておきたい。どちらかのハードディスクがクラッシュしたときのバックアップにもなるし。
ということで、私も会社と自宅のパソコンの一部のデータを同期させています。
しかし共有するデータが増えてくると、これがけっこう面倒なんですよね。
手軽に、同期させることができないか考えてみました。

外付けハードディスクを使ってすべてのファイルをバックアップ


現状は、同期させたいフォルダ内のファイルをすべて、ポータブルハードディスクにコピーして、2カ所のPCのハードディスクを同期させています。
My Documentsフォルダ内のファイルをすべて同期させたいので、それぞれのパソコンのMy Documentsフォルダをそっくりポータブルハードディスクにコピーし、そのポータブルハードディスクのMy Documentsフォルダをもう一方のパソコンにそっくり上書きするというやり方です。
ポータブルハードディスクはコンパクトなものがあるので、多少データ量が増えても持ち運びに支障はありません。
しかし、データは予想以上に膨らむのが早いもの。以前使っていた40GBのポータブルHDDに入りきれなくなったので、今は80GBのものに買い換えましたが、これもいつの間にかいっぱいいっぱいになってきました。

バックアップに使っているソフトは、FFFTP作者のSotaさんのフリーウェアBackup
更新されたファイルだけ変更してくれるので、80GBくらいあっても、数分でバックアップは終了します。
さらに高速にバックアップを行ってくれるBunBackupなどもありますが、私の用途には今のところ、Backupが一番適しているようです。
バックアップ.gif


上の図でいうとPC Aのハードディスク、PC Bのハードディスク、それにHDD C内にいずれも同じ量のデータを保存し続けるということになります。
私の場合はこれが80GB近くになります。
しかし、実のところ一度の更新で変更するデータ量はごくわずかです。
せいぜい数10MBから多くて、数100MBといったところです。これくらいのデータ量なら大容量のHDDではなく、もっと手軽に扱えるUSBメモリで何とかならないかなと考えてしまいます。

更新ファイルのみのバックアップはできないか


いくらコンパクトになったとはいえ、ハードディスクだと最低でも文庫1冊分くらいはあります。上着の内ポケット1個を占領する大きさです。
これがUSBメモリで済むということになると、もうどこにでも入れておける大きさで、ほとんどじゃまになりません。

で本題ですが、変更したファイルだけをUSBメモリのような仲介メディアに入れて、2カ所のPCのデータを同期させるようなバックアップはできないだろうかということです。
近いことをできるフリーウェアがあります。ZCopyというツールです。このソフトで
Modified Afterというオプションを使えば、指定した日時以降に作成、更新されたフィルのみのバックアップをとることができます。一度このオプションでバックアップをとると、次回からはバックアップした日時以降のみが対象になります。
この設定でUSBメモリなどにバックアップをとり、同期をとりたいPCでこのファイルを上書きしてやれば、バックアップ対象すべてのファイルを入れたハードディスクをいつも持ち歩く必要はなくなります。
しかし、このZCopyを使って更新ファイルのみをバックアップする場合、一方のPCで削除されたファイルが反映されないという問題があります。
たとえば、PC Aで
C:\\My Documents\My Videos\abc.tsというファイルを
C:\\My Documents\test\abc.ts
に移動し、上記の方法でバックアップしたとすると、PC Bでは
C:\\My Documents\test\abc.tsはコピーされますが、
C:\\My Documents\My Videos
フォルダ内にもabc.tsが残ることになります。
バックアップ2.gif

ポータブルハードディスクにバックアップ対象のファイルをすべて入れて持ち運ぶ場合は、PC Aでファイルが削除されたら、ミラーリングで仲介メディア内の該当ファイルを削除し、同様に仲介メディアからPC Bでのバックアップで同様にPC Bの該当ファイルが削除されます。
変更ファイルのみを仲介メディアにコピーする方式でこのようなバックアップはできないでしょうか。たとえば以下のようなイメージです。
バックアップ3.gif

要するに、ファイルを削除した場合は、バックアップメディアにファイルそのものではなく、このファイルは削除したよという情報をコピーするということです。もう一方のPCでは仲介メディアに削除情報があった場合は、該当するファイルを削除するという仕組みです。
ただ、PC Aであるファイルが削除されたかどうかを知るには、元々どんなファイルがあるのかという情報、バックアップ対象ファイルのデータベースが必要になります。
データベースを作るということになると、削除情報もデータベースに書き込んだ方がすっきりするかもしれません。

データベース方式

概要


データベースを使うと、以下のような流れになると思います。

STEP1


まず最初に現状のデータベースを仲介メディアに作っておきます。データベースは実際のファイルに比べると、圧倒的に容量は少なくて済みます。仲介メディアはHDD Cと書いていますが、これはUSBメモリのように容量がそんなに多くないメディアでも大丈夫です。
データベース01.gif

STEP2


PC Aの中身を変更します。
データベース02.gif

STEP3


HDD Cにバックアップします。修正、追加されたファイルはファイルそのものをコピーし、削除されたファイルはデータベースに削除されたという情報を書き加えます。
データベース03.gif

STEP4-1


PC Bをバックアップします。HDD C中のファイルはそのまま上書きし、データベースで削除情報があれば、PC B中の該当ファイルを削除します。
データベース04.gif

STEP4-2


同時にHDD Cのデータベースを最新のものに書き換えます。これで、PC AとPC B、のハードディスクとHDD Cのデータベースが同じ状態になりました。
データベース05.gif

通常のバックアップと違うのは、仲介メディアへのバックアップは、追加、更新したファイル以外は、実際のファイルではなく、データベースのバックアップとなるという点です。
この方式でバックアップしてくれるフリーウェアとかないかなと思って探してみましたが、見つけられませんでした。
それほどややこしいことをするのではないので、ちゃんとしたソフトではなく、スクリプトのようなものでもいいのかもしれません。
むしろ、バックアップするソフトは仲介メディアに入れておいて、仲介メディアから起動するようになっていた方が、バックアップの設定もやりやすいと思います。PC AとPC Bで同じ設定を保存する手間が省けるし。


STEP1から4まで、さらに細かい部分はどうなるか整理してみました。

STEP1


仲介メディアに何もない状態から、PC Aのバックアップフォルダの中身をデータベースとして書き込みます。
書き込む場所は仲介メディアのバックアップ保存先フォルダのルートぐらいが無難でしょう。

PC Aのバックアップ元フォルダをスキャンしてフォルダ、ファイルすべてのフルパスをテキストファイルで書き込みます。
ついでにフォルダ、ファイルの別、ファイルのデータサイズ最終更新日時などのデータも保存する必要があります。

設定ファイル


あ、その前に、バックアップの設定を決めてこれも設定ファイルに保存しておく必要があるか。
設定ファイルに必要なのは

  1. バックアップ元フォルダのフルパス(リスト形式?)
  2. バックアップ先フォルダのフルパス
  3. PCから仲介メディアへのバックアップなのか、仲介メディアからPCへのバックアップなのか
  4. バックアップを選択するための識別名
  5. バックアップ対象外フォルダ(リスト形式で複数選択可)
  6. バックアップ対象外ファイル(リスト形式で複数選択可)

といったところでしょうか。バックアップ元フォルダのフルパスもリスト形式で複数選択できるようにした方がいいかもしれません。
実際の運用を考えると、1回目の処理については、現状のデータベースを記録するだけでなく、
日時を指定して、その日時以降に作成、更新されたファイルについてはその時点で仲介メディアにバックアップするようにした方が効率的かもしれません。
そうなると設定情報として、バックアップ対象日時も必要となります。これはバックアップを行うたびに更新する必要があります。

バックアップ開始


プログラムの流れとしては、

  • まず設定ファイルを作成、保存する。
  • 設定ファイルを選択すると、バックアップ実行ボタンが現れ、バックアップ可能になる。このとき、いきなりバックアップするだけではなく、プレビューも選択できるようになっていた方が安心だ。
  • バックアップ元フォルダのフルパスについて、その中のサブフォルダとファイルをスキャンし、保存先のバックアップ先フォルダ内にデータベースファイルを書き込む。(プレビューの場合は書き込まない。)書き込む内容は、バックアップフォルダ内にあるフォルダ、ファイルのフルパス、およびファイルサイズ更新時間などのファイルデータ。
    この際、バックアップ対象外フォルダ、バックアップ対象外ファイルをスキップすべきかどうかが悩ましいところです。
    実際の更新ファイルのコピーでは、この対象外中のファイルはもちろん対象外になりますが、データベースとしてはそのようなファイルのデータベースもあった方が、後で役立つような気もします。
  • データベースを更新すると同時に、対象外フォルダ、対象外ファイルではなく、指定日時以降に作成、更新したファイルは仲介メディアにコピーする。
    コピーするフォルダはバックアップ先フォルダ内にダイレクトではなく、バックアップ元フォルダの一番下のフォルダを一段作ってからコピーした方が、バックアップ元フォルダが複数ある時に都合がいい。と思います。たとえばバックアップ元フォルダが
    C:\\My Documents\My Videosで、バックアップ先フォルダが
    V:\\バックアップフォルダ
    だとしたら
    V:\\バックアップフォルダ\My Videosフォルダ内にコピーするということになります。
    データベースファイルの保存場所もここがわかりやすいでしょう。
  • プレビューモードの時は、実際にファイルをコピーするのではなく、どのファイルを(どこに)コピーするかをプレビューします。
  • プレビュー結果画面でもバックアップ実行ボタンを表示しますが、プレビューを行った時点で、どのファイルをコピーすべきか調査済みなので、何らかの方法でそのデータを保持し、そのデータを使ってバックアップした方が早いと思います。データベースの更新は再度スキャンする必要があるが・・・いや、データベースも保存した方が効率的だ。
    うーん、プレビューしただけで、データベースは更新するようにした方が、絶対速いな。
    いきなりバックアップするときは、バックアップ元フォルダをスキャンして、データベースの更新、ファイルのコピーを行い、
    プレビューの時はデータベースを更新してコピーすべきファイルのピックアップを行う。ということでどうでしょう。
    問題は削除ファイルがあった場合ですが、プレビューだけ行って、データベースは削除するよう書き換えたのに、実際のバックアップはキャンセルした場合はどうするかが問題です。
    プレビューモードでのデータベース更新では、削除するファイルについては更新せず、削除情報のみを保持して、そのままバックアップを実行した場合は、データベースからそのファイル部分を抜き出し、削除済みと書き換えて保存する。これだと再度バックアップ元フォルダをスキャンするよりは遙かに高速に処理できるはずです。
    ・・・ん、勘違いしてました。これは最初のデータベース作成だから、削除されたかどうかはわからない。考える必要がないのか。
    ということはいずれにしてもプレビューモードでデータベース作った方が絶対良さそうですね。

STEP2


STEP2はPC Aでファイルを更新するというステップなので、特に関係なし

STEP3


前回のバックアップ以降更新されたファイルを仲介メディアにコピーし、データベースを更新する。
これもプレビューモードと実行モードがあった方がいいでしょう。STEP1での処理とここでの処理の違いはデータベースファイルが存在するかどうかです。
処理は違いますが、ユーザーインターフェイス上ではSTEP1と同じで、プログラム側でデータベースファイルのありなしで分岐することになると思います。

STEP1と同様、バックアップ元フォルダをスキャンしてコピーすべきファイルを探さなければなりませんが、どうやって探すか。
一つの方法としては、前回のバックアップ日時以降に作成、更新されたファイルをピックアップするという方法が考えられます。
これが一番簡単で早いが、作成、更新日時はそれ以前のファイルをバックアップ対象フォルダに移動したというケースではピックアップできません。
また、削除されたファイルを特定するため、いずれにしても仲介メディアにあるデータベースを読み込む必要があります。どうせデータベースを読み込むなら、データベースの記録に基づいてピックアップした方がいいのかもしれません。

更新ファイルの検索


まず、データベースを読み込んで、データベースに存在しないファイル
存在してもデータベースのファイル情報と異なるファイル情報を持つファイル(データサイズが違うとか、更新日時が違うとか)をピックアップします。
データベースの情報と、バックアップ元のファイルの情報を照らし合わせるのが面倒そうですが、たとえばperlでやるなら、ハッシュを使う方法が速いかもしれません。
つまり、データベースから取得したバックアップ元のファイルパスをキーとしたハッシュを作っておけば、実際のファイルパスをキーとするハッシュを調べることで一発で照合できます。
具体的には、データベースのファイルパスが'C:\\My Documents\My Videos\yyy.ts'、ファイル情報のデータサイズが1258787バイト、更新時間が1212602244だったとすると、

$exsit{'C:\\My Documents\My Videos\yyy.ts'} = 1;
$file_size{'C:\\My Documents\My Videos\yyy.ts'} = 1258787;
$mod_time{'C:\\My Documents\My Videos\yyy.ts'} = 1212602244;

のようにハッシュを作ります。
この作業はデータベースすべてについて行いますが、このとき、このファイルパスが存在するかどうか調べれば、バックアップ元から削除されたファイルのリストが作れます。削除ファイルを調べるために再度データベースをスキャンするのも効率が悪いので、このとき併せて行うのがいいでしょう。
そしてバックアップ元のファイルをすべてスキャンします。
各ファイルについて、たとえば次のように処理します。ファイルパスが$path、ファイルサイズが$f_size、更新時間が$m_timeだとすると

if (!$exsit{"$path"} || $file_size{"$path"} != $f_size || $mod_time != $m_time) {
 	バックアップリストに追加
}

つまり、データベースにファイルパスが存在しないか、データサイズが違うか、更新時間が違えば、新たに作成されたか、更新されたと判断してバックアップリストに加えるということです。
ここでもプレビューモードと実行モードを用意しておくべきでしょう。いきなり実行モードの場合は、データベースの更新(削除されたファイル情報部分に削除されたというフラグを立てる)と、コピーするファイルのピックアップと同時にコピーを行います。

更新されたファイルのデータベースはどうすべきかということがまた悩ましいですね。新しく追加されたファイル情報を追加し、更新されたファイルの情報もここで更新すべきでしょうか。それとも、削除されたファイルのデータベースはこの段階で削除されたという情報を追加し、PC Bへのバックアップと同時にデータベース上からファイル情報そのものを削除することになるの、更新されたファイルのデータベース更新についてもそのタイミングにするという手順も考えられると思います。
プレビューモードの場合は、データベーススキャンで削除されたファイルのリスト作成、フォルダスキャンでコピーするファイルのリスト作成を行います。プレビューモードではデータベースの更新は行わない方がいいでしょう。
プレビューモードから続けて実行の場合は、(再度データベースとフォルダのスキャンを行わずに)これらのリストに基づいてファイルをコピーし、データベースを更新するので、かなり高速に実行できるはずです。

続けてバックアップを行った場合


ついでに特殊な場合についても考えておきます。通常ならここでデータベースを更新し、ファイルをコピーした状態でもう一方のPC Bに仲介メディアを接続し、仲介メディアからPCへのバックアップを行います。バックアップが済むと仲介メディア中のコピーファイルは削除され、データベース中の削除情報も削除されます。しかし、仲介メディアからのバックアップを行わずに再度PC Aから仲介メディアにバックアップを行った場合の処理も想定しておく必要があります。

まず考えられるのが、メディアにバックアップ済みのファイルと同じファイルがバックアップ元でさらに更新された場合。
バックアップ元のファイルの更新日時がバックアップ済みのファイルより新しければ当然上書きですが、古い場合はどうでしょう。これは古くても上書きした方がいいのかな。
メディアにコピーしたファイルのデータベースでの情報はこの段階では更新していないかもしれないので、
ファイル情報はメディアにコピーされたファイルそのものから取得した上で比較する必要があります。
次にデータベースで削除済みとなっているファイルについてですが、削除されたはずのファイルが復活した場合はどうするか。
これは更新されたものとしてファイルをメディアにコピーするのがいいでしょう。削除されたとなっているデータベースはそのままでいいか。もう一方のPCにバックアップした時点で、いずれにしてもデータベースを更新されるわけだし。
データベース上からファイル情報を削除する代わりに新しいファイルの情報で置き換えることになります。

STEP4


やっと、STEP4まで来ました。
仲介メディアからのバックアップで大前提となるのが、仲介メディアにデータベースが存在するかどうかです。なので、まず最初にデータベースがあるかどうか確認する必要があります。
もしなかった場合はどうするか。バックアップファイルは存在するのに、データベースはない場合、ファイルだけ上書きしてしまうという方法も考えられますが、やはりデータベースがない場合は、エラーとして処理を中止するのが無難でしょう。

設定


バックアップの設定ですが、PCからメディアへのバックアップ設定と同様

  1. バックアップ元フォルダのフルパス(リスト形式?)
  2. バックアップ先フォルダのフルパス
  3. PCから仲介メディアへのバックアップなのか、仲介メディアからPCへのバックアップなのか
  4. バックアップを選択するための識別名
  5. バックアップ対象外フォルダ(リスト形式で複数選択可)
  6. バックアップ対象外ファイル(リスト形式で複数選択可)
  7. バックアップ対象日時

が必要でしょう。もちろん仲介メディアからPCへのバックアップとなります。

ファイルの削除


データベースを読み込んで、まず削除すべきファイルを削除します。
削除対象ファイルの情報を調べた上で削除した方がいいでしょう。気になるのは削除対象ファイルが最近更新されている場合です。
これはオプションで設定できるようにした方がいいかもしれませんが、前回のバックアップより更新日時が新しい場合は削除しないという選択肢もあり得るかもしれません。
前回のバックアップというのは、このPC Bでのバックアップで、PC Bから仲介メディアへのバックアップの日時のことです。
それを行っていない場合は、前回の仲介メディアからPC Bへのバックアップの日時ということになります。この日時はバックアップを行った際に設定ファイルに書き込まれることになります。
「前回のバックアップ以降更新されたファイルを削除しない」とでもいうようなオプションを設定して、これが有効で、削除対象ファイルの更新日時が前回のバックアップ日時より新しい場合は、削除しないことになります。
削除されるべきファイルがすでに存在しない場合は、これはどうしようもないですね。

これもプレビューモード、実行モードが必要です。

いきなり実行モード


データベースを読み込んで削除対象ファイルを削除します。あとでデータベースから削除するために、削除する際にそのパスをリストに追加しておく必要があります。
ここでパスの変換が必要になります。
ん・・・・
これまでのところ、データベースに書き込むファイルバスはPC Aでのファイルバスと思っていましたが、PC Bでは当然、パスが違います。たとえばPC A
C:\\My Documents\My Videos\abc.ts
に相当するファイルがPC Bでは
D:\\バックアップ\\My Documents\My Videos\abc.ts
になるとか。PC Bからも、同様にメディアへのバックアップを行い、同じデータベースを更新しなければならないので、これはまずいですね。
データベースに記録するファイルパスはバックアップ元フォルダで指定したフォルダ部分を省略した状態で保存した方が良さそうです。たとえば
バックアップ元フォルダが
C:\\My Documents
だったら、C:\\My Documents\My Videos\abc.tsのデータベース上での記述は
My Videos\abc.ts
にします。各PCでファイルを探す場合はバックアップ元フォルダ、あるいはバックアップ先フォルダで指定したフォルダを頭にくっつけてフルパスを復元します。

バックアップ先でのファイルの削除とそのパス(データベース形式に変換)の削除済みリストへの追加が終わったら、ファイルのコピーを行います。
仲介メディア中のバックアップ元フォルダ中のファイルをバックアップ先へコピーします。(データベースファイルも含まれていますが、もちろんこれは除外)
コピーは上書きモードですが、すでにバックアップ先にファイルがあって、そのファイルがコピーするファイルより新しい場合は、削除の際と同様、「前回のバックアップ以降更新されたファイルを上書きしない」とでもいうようなオプションを設定して、それに従って上書きするかどうかを決めるのがいいでしょう。上書きコピーしたら、そのパスとファイル情報をデータベース更新リストに追加します。
コピーが終わったら、バックアップ元フォルダ中のコピー済みファイルを削除して、データベースを更新しておきます。
削除済みリスト、データベース更新リストに基づいてデータベースを修正し、上書きします。

プレビューモード


プレビューモードの場合は、データベースを読み込んで、削除するファイルをインターフェース上に表示し、バックアップ元フォルダを検索してコピーするファイルも表示します。
削除ファイルも、コピーファイルもそれぞれリストにして、何らかの方法で記録しておきます。バックアップ実行ボタンが押されたら、そのデータに従って、ファイルの削除、コピー、コピーが済んだファイルのメディアからの削除、データベースの更新を行います。

CGIで試作


どんな感じになるのか、CGIで試作してみました。いちばんこの手の処理には向いていないプログラムかもしれませんが・・・。
自宅と会社の両方でApacheやPerlを入れて、ローカルでCGIが動く環境でないと使えないというのが一番の問題です。それこそUSBメモリにでも入れて、どこでも使えるようなプログラムにできるといいのですが。誰か作ってくれないかな。
このCGIは当然ながら、WEB上に設置することはできません。設置したら大変なことになります。なにしろ、サーバー内のファイルをごっそりコピーしたり、削除するCGIですから。

ローカル環境でCGIが稼働できる場合のみ使用可能(というかテスト可能?)で、その場合も使用には十分注意してください。
このCGIを使用したことにより、重要なファイルが削除されたり、あるいはOSが起動しなくなったとしても、当方は一切責任は持てません。自己責任でお願いします。

backup.cgi


ダウンロード backup.zip

試作版なので、いろいろ制限や問題があります。

  • いきなりバックアップモードは省略しています。プレビュー後、バックアップ実行のみです。
  • バックアップファイルの検索にけっこう時間がかかりますが、検索が終了するまでその前の画面が表示されたままなのが、芸がない感じです。
  • フォルダを指定する際、指定フォルダ内のサブフォルダを検索し、そのサブフォルダを選択するという方式になっていますが、ルートドライブを検出するのに時間がかかるので、再検索しないオプションを追加しています。エクスプローラーに表示されるフルパスをコピーペーストする方が速いかもしれません。
  • 日本語パスで読めない文字があります。
更新履歴
2008/7/17
ver.0.5 USBメモリへのバックアップの場合、フォルダ・ファイルごとにキャンセルできるチェックボックスを追加。プレビュー、バックアップが終了したらウインドウを「バックアップ実行」ボタンまでスクロールするよう変更。
使用法


設置については詳しくは説明しません。
この程度のCGIの設置は問題なくできる人対象と考えてください。
最初に起動すると、「新規バックアップ設定」というボタンが表示されますので、設定を行い「設定を保存」ボタンで保存してください。
「設定名」「バックアップ元フォルダ」「バックアップ先フォルダ」は必須です。
「参照」ボタンを押してフォルダを選ぶ場合は、先に「設定名」を決めてください。
「バックアップモード」のデフォルトは「パソコンからUSBメモリへ」です。
「除外フォルダ」「除外ファイル」はオプションです。
「更新日時」はこの時間以降に修正、追加されたファイルのみをバックアップ対象にするという日時です。
デフォルトでは現在時間になっていますので、この時間のままバックアップを行っても、対象ファイルは「なし」ということになります。
最初の実行時はちょっと過去の時間までさかのぼって行うのがいいでしょう。
あまりさかのぼりすぎるとバックアップファイルの数が増え、データ量も増えすぎることになるかもしれませんが。
過去にほかの方法でバックアップしたことがあるなら、その時間よりちょっと前ぐらいがいいと思います。



Plugin not found.


>>2010/02/25 01:26:00更新>>