/////////////////////////////////////////////////////////////////////////////// UFS2 text undelete (C)2004/12/10 nabe@abk (E-mail: nabe(at)abk.nu) License : GPL /////////////////////////////////////////////////////////////////////////////// [ja_JP.eucJP] ■概要  "rm -rf *" してしまったファイルを復活させるため、諸事情により作成したテキ ストファイル専用のファイル復活ツールです。専門的なツールであるため、あまり 知識のない方は使用しないでください(危険はありませんが……)。使用する場合 もこのテキストをよく読んでからにしてください。  動作確認は FreeBSD 5.3 にて行いましたが、UFS2 ファイルシステムであれば、 おそらく問題なく使用出来ます。テキストファイルは、Shift-JIS、EUC-JP、JIS に 対応しています。テキストファイル以外は復活できません。 ■原理と制約 ・ファイルシステムの解釈は、カーネルソースから適当に行いました。  もし仕様書の在処を知っている方が居ましたら、教えてください。 ・FreeBSD Kernel はファイル削除時、inode に削除というフラグを立てるのではなく、  inode のほぼすべての情報を消去します。よってファイルの情報(所有者、サイズ、  ディスク上での実体データの繋がり)は完全に消えており、FAT のような undelete  は原理上不可能です。 ・このツールでは、一つのファイルはディスク上の連続した領域を使用すると仮定し、  すべてのクラスタをスキャンしています。そして、あるサイズ(100byte に設定)を  越えた連続したテキストデータをファイルとして出力します。 ・上記の機能を持ったファイル復元ツールは沢山ありますが、このツール独自の機能  としてディレクトリ構造を解析しています。ディレクトリエントリの直後に、その  ディレクトリ内のファイルが存在するという仮定の元、ディレクトリ構造の復元を  試みます(あまりアテにはなりませんが、無いよりはマシなようです)。 ■使い方  UFS2 のイメージファイルが必要です。デバイスの「ディスクラベル」を丸ごと ダンプしてください(mount できる単位を dump してください)。こちらでは、 $ cat /dev/ad0s1d >imgfile.bin  などとしました(言うまでもないことですが、復活させたい領域にイメージファ イル出力しませんように)。  本ツールを $ gcc -O2 -o ut_undelete ut_undelete.c  としてコンパイルした後、空き容量が十分にあるディレクトリで、 $ ./ut_undelte /[path]/imgfile.bin  としてください。"__out" 以下に復元したファイルが現れます。ディレクトリ構 造の復元を試みますが、どこのディレクトリに所属するか推測出来なかったファイ ルについては "__out/__nofullpath/" 内に展開されます。 imgfile.bin.dir imgfile.bin.name  の二つのファイルはディレクトリ構造の解析結果を格納したキャッシュです。必 要ないので消してください(パラメーターを変更し何度も実行する場合や、プログ ラムを改造しながらテストする場合は使用すると便利です)。 ■詳しい原理  テキストファイル判別は説明することがないぐらい単純ですので、ディレクトリ 構造の解析について簡単に説明しておきます。 $ ls -ial 117764 drwxr-xr-x 4 root wheel 512 12 2 16:18 ./ 117763 drwxr-xr-x 3 root wheel 512 11 27 01:34 ../ 117768 -rw-r--r-- 1 root wheel 423 11 5 10:27 PROTO.localhost-v6.rev 117767 -rw-r--r-- 1 root wheel 423 11 5 10:27 PROTO.localhost.rev 117771 -rw-r--r-- 1 root wheel 1093 11 5 10:27 make-localhost 117765 drwxr-xr-x 2 root wheel 512 12 2 16:18 master/ 117769 -rw-r--r-- 1 root wheel 3839 12 2 16:18 named.conf 117791 -rw-r--r-- 1 root wheel 3754 8 26 22:40 named.conf.old 117770 -rw-r--r-- 1 root wheel 2600 11 5 10:27 named.root 117766 drwxr-xr-x 2 bind wheel 512 12 2 16:17 slave/  という感じで一番左に表示される値が、右のファイルの実体である inode 番号を 示しています。ディレクトリエントリには、この inode 番号と名前のみが記録され ていて(struct direct)、本来はその inode から得られるディスクブロック番号 のリストを辿ることでファイル内容を得ることができます。  このディレクトリ情報自体は普通のファイルとして、データ領域に存在します。 inode ではないので消去されません。"." のエントリと ".." のエントリが必ず存 在することを利用して、ディレクトリファイルを判別しています。エントリは可変 長のデータの連なりとなっています。ファイルを削除したりすると、そのエントリ を読み飛ばすように一つ前のエントリのレコード長が長くなったりします。これで はディレクトリ内のファイルエントリ発見が困難であるため、一つ一つファイル名 の長さから区切りを見つけています。  さて、master というディレクトリ以下にどんなファイルが存在するか知りたい とき、通常ならば inode の 117765 みればよいのですが、この情報は抹消されて います。しかし、もし master というディレクトリファイルが残っていれば、 $ ls -ial master/ 117765 drwxr-xr-x 2 root wheel 512 12 2 16:18 ./ 117764 drwxr-xr-x 4 root wheel 512 12 2 16:18 ../ 117798 -rw-r--r-- 1 root wheel 409 12 2 16:17 any.dom 117799 -rw-r--r-- 1 root wheel 425 12 2 16:19 localhost-v6.rev 117800 -rw-r--r-- 1 root wheel 425 12 2 16:19 localhost.rev  という情報が得られ、ここから inode 番号を比較することによって、このディ レクトリは master ディレクトリ内に位置することが判明します。全クラスタに対 してこの処理を繰り返すことで、可能な限りディレクトリ情報の復元を試みます。  また、ルートの inode は常に 2 番であることも利用しています。  このルーチンはかなりうまく動作しています。しかしながら、ディレクトリエン トリの後に実際のファイルがあるという仮定がなかなか満たされないらしく、あま りアテになりません。  例えば、tar.gz のようなファイルを展開したり、どこからかファイルをコピーし た直後に消去したならばまだしも、使い込んだディスクほどこの仮定が満たされる ことは少ないでしょう。ですから、おまけ程度の機能と思ってください。 ■テキストファイル以外への対応 ・テキストファイル以外への対応は、ファイルヘッダの解析ルーチンを増やせば  いくらでも可能です。そんなに難しくはないのでぜひ挑戦して、再配布するな  り送りつけるなりしてください。  ソースは C で平易に書いたつもりです。そんなに難しく書いてはいないと思 いますが、疑問点があれば掲示板なりで質問してください。(ディレクトリ構造 解析は多少難しいかも知れませんが)。 ■制約 ・ファイルシステムは UFS2 決め打ちです。 ・ディレクトリ情報がディスクのブロックサイズ(フラグメーテーションサイズ)  を越えた場合、その先は無視されます(対応は容易ですが必要なかったので)。 以下4つの制約は、ソースの定義文を変更することで可能です。 ・スーパーブロックは領域先頭から 64KB にあると仮定しています。 ・すべてのファイルの名前を全てトータルした長さは 1MB までです。 ・一つのファイル名は 1024 byte までです(パス含む)。 ・ディレクトリの階層は 256 階層までです。 ■一言  inode をあそこまで綺麗に消すことないじゃん……(涙)