extundeleteによる削除済みファイルの復元方法

概要 コマンドラインから rm コマンドで削除したファイルの復活方法を解説します.
検証環境 Ubuntu 12.04 x86_64
ファイルシステム: ext4
備考 ここで説明する方法は ext4 または ext3 のみに適用可能なものです. ext2 では mc(GNU Midnight Commander)というファイラーの Undelete files 機能を使うことで回復できる可能性があります.
参考:@IT 削除したファイルを復活するには

誤ってファイルを削除した直後にすべきこと

削除したファイルを格納していたパーティションを unmount するか read-only にしてください. [備考: これを容易にするため,OS本体とユーザーデータを格納するディレクトリ(homeディレクトリ)を別パーティションにしておくことをおすすめします. ルートディレクトリと /home が同じパーティションに格納されている場合,パーティションのアンマウントが難しくなり,ファイルを回復できる見込みは薄くなります.]

/homeunmount する場合,下記のとおりです. カレントディレクトリが /home の下になっていると devide is busy エラーになってしまいますので,この例では先にカレントディレクトリをルート(/)に移動しています.

$ cd /
$ sudo unmount /home

/home を read-only にする場合,下記のとおりです. 2つ目の mount コマンドは remount したパーティションが read-only になっていることを確認するためのものです. ro と表示されれば read-only になっています. read-only になっていることを確かめるために実際に書き込んでみるというような勝負をすべきではありません.

$ sudo mount -o remount,ro /home
$ mount
/dev/sdc2 on /home type ext4 (ro,errors=remount-ro)

ここまで実施すれば,ファイルが(ここで紹介する方法で)復活できるか,そうでないかは確定します. [復活させたいファイルが画像ファイルや音声ファイルなど“ある種の特徴”をもっている場合,ディスク上の全セクタを走査して“ある種の特徴”に合致するデータを見つけ出すというヒューリスティックな方法で復活できる可能性があります. 詳しくは「PhotoRecによる削除済みファイルの復元」を参照してください.]

復元: extundeleteの実行

復元したいファイルが /dev/sdc2 に格納されていた場合,下記のように実行します.

$ sudo extundelete /dev/sdc2 --restore-all
WARNING: Extended attributes are not restored.
Loading filesystem metadata ... 14905 groups loaded.
Loading journal descriptors ... 32420 descriptors loaded.
Searching for recoverable inodes in directory / ... 
7232 recoverable inodes found.
Looking through the directory structure for deleted files ... 

復元したファイルはデフォルトではカレントディレクトリの RECOVERED_FILES ディレクトリに格納されますので,十分な容量があるディレクトリで実行してください. この例では /dev/sdc2 上の復活可能な削除済みファイルすべてを復元しています. それでは多すぎる場合,オプションで,ある時刻以降に削除したファイルのみ,あるパスの下にあったファイルのみを復元するように指定してください.

日時指定の例
$ date --date='2012-01-01 00:00' '+%s'
Sun Jan  1 00:00:00 JST 2012
$ sudo extundelete /dev/sdc2 --after `date --date='2012-01-01 00:00' '+%s'`
パス指定の例 sudo extundelete /dev/sdc2 --restore-files 'home/hatai/f.txt'

より深い理解のために(上級者向け)

ext4/ext3 上のファイルの復元は ext2 の場合より格段に難しいです. ユーザーからファイル削除の指示がでるとファイル本体を格納していたブロックやその inode,ディレクトリエントリに“未割りあて”(unallocated)のマークがつきますが,ext2 では inode 上に記録されている,ファイル本体を格納していたブロックのアドレスやファイルサイズの情報は(まだその時点では)残っています. しかし,ext4/ext3 では inode 上のファイル本体を格納していたブロックのアドレスやファイルサイズの情報がすべてクリアされてしまうのです. したがって,未割りあてになっている inode を強引に読んで目的のファイルを復元してしまうという方法がとれません.

そのため,ext4/ext3 では,(1)ファイルの特性を使って復元するか[例えば JPEG ファイルは仕様上 0xFFD8 ではじまって 0xFFD9 で終わることがわかってるため,この情報を頼りに復元することができます],(2)ジャーナルのログエントリを利用して復元するかの2通りしかなく,かつ,いずれも ext2 の場合より復元できる確率も低く,精度も悪くなります.

(1)の手法をつかった復元方法については「PhotoRecによる削除済みファイルの復元」を参照してください. ここでは,extundeleteが使っている(2)のジャーナルを解析による復元方法を説明します(といってもたいした役にはたちませんが…).

debugfs で ls -d コマンドを実行すると,現在存在するファイル(allocated files)と削除済みのファイル(unallocated files)の情報が得られます. debugfs で見たときに <> で囲まれて表示されるのが削除されたファイルの inode です.

$ sudo debugfs /dev/sdc2
debugfs 1.42 (29-Nov-2011)
debugfs:  ls -d
 2  (12) .    2  (12) ..    11  (20) lost+found    18874369  (16) mirror   
 61865985  (32) bak   <14> (20) .f.txt.swp    12  (4004) f.txt   
(END)

ジャーナル ログをみるには logdump -i を使います. ここでは削除済みの <14> のログ エントリをみたいので下記のように指定します.

debugfs:  logdump -i <14>
Inode 14 is at group 0, block 1057, offset 1664
Journal starts at block 0, transaction 13933

上記のように素っ気なく表示された場合は,もうダメです.何も情報がなくて,これ以上進めないでしょう. 下記のように表示された場合は,いちおう情報は残っているのですが,この場合も inode の i_extra_isize が不正になっているため,過去の Blocks が取得できず,やはりダメです.

debugfs:  logdump -i <14>
Inode 14 is at group 0, block 1057, offset 1664
Journal starts at block 1, transaction 13934
  FS block 1057 logged at sequence 13934, journal block 3 (flags 0x2)
    (inode block for inode 14):
    Inode: 14   Type: bad type        Mode:  0034   Flags: 0x0
    Generation: 0    Version: 0x00010000:00000000
    User:     0   Group:     0   Size: 0
    File ACL: 0    Directory ACL: 0
    Links: 0   Blockcount: 0
    Fragment:  Address: 0    Number: 0    Size: 0
     ctime: 0x00000000:08000000 -- Thu Jan  1 09:00:00 1970
     atime: 0x00000000:4dc24c5f -- Thu Jan  1 09:00:00 1970
     mtime: 0x4e2f0607:4dc24c5f -- Wed Jul 27 03:23:03 2011
    crtime: 0x4dc24c5f:00000000 -- Thu May  5 16:06:07 2011
Size of extra inode fields: 33152
invalid inode->i_extra_isize (33152)
    Blocks:  
No magic number at block 9: end of journal.

私が試してみた限りでは extundelete による復元の成功率は極めて低いものでした. ext4 のジャーナルの理解が不十分なので結論は出せませんが extundelete で復元できる可能性は低いと考えてよさそうです.

参考: 少しひねったアプローチ

特殊な例になりますが,削除したファイルを開いているアプリケーションが残っている場合,そのアプリケーションがつかんでるファイルをコピーすることでファイルを救出する方法もあります. 例えば,動画が収録されている f.iso というファイルを再生中に f.isorm した場合,下記のように lsof(list open files)で開いているファイルの情報を得て,コピーすることができます. この例では gvfsd-arc というプログラムが開いている /home/unsync/f.iso をコピーしています.プロセス番号が 10764,ファイル ディスクリプターが 9 なので /proc/10764/fd/9 が目的のファイルになっています.

$ lsof |grep iso
gvfsd-arc 10764      hatai    9u      REG               8,34 2340454400       13 /home/unsync/f.iso (deleted)
$ cp /proc/10764/fd/9 x.iso

Links

[1] extundelete
[2] PhotoRecによる削除済みファイルの復元
[3] Why Recovering a Deleted Ext3 File Is Difficult...
[4] ext4の徹底調査(by IBM)