ずーっと昔に tar.bz2 で固めたバックアップファイル。ハードディスク内に何年か放っておいて、 ときどき容量が足りなくなったときにあっちこっちに移動させたりしているうちに、なんかおかしくなってしまった。
$ ls -la ariel-home.tar.bz2 -r-xrw-r-- 1 t users 3581694796 Jan 13 2002 ariel-home.tar.bz2 $ tar jxf ariel-home.tar.bz2 bzip2: Data integrity error when decompressing. Input file = (stdin), output file = (stdout) It is possible that the compressed file(s) have become corrupted. You can use the -tvv option to test integrity of such files. You can use the `bzip2recover' program to attempt to recover data from undamaged sections of corrupted files. tar: Unexpected EOF in archive tar: Error is not recoverable: exiting now
言われたとおり、 素直に bzip2recover をかけると、ファイルの中の圧縮ブロックがひとつひとつ切り出されて rec00001ariel-home.tar.bz2, rec00002ariel-home.tar.bz2, ... と 4903 個のファイルができた。 こいつを解凍するには、まとめて bzcat に放り込めばいいはずだ。
$ bzcat rec*ariel-home.tar.bz2 | tar xvf - bash: /bin/bzcat: Argument list too long
ありゃー。というわけでもうすこし頭を使う。xargs に -n1 することで、エラーのブロックがあっても続きを解凍し続けるはず。
$ find . -name "rec*.bz2" | sort | xargs -n1 bzcat | tar xvf -
これでなにやら解凍が始まった。しかし、エラーのブロックのあとには、
tar: Skipping to next header tar: Archive contains obsolescent base-64 headers
と表示され、その後はうんともすんともいわないまま終わってしまう。おかしいなぁ。途中が抜けたら残りが解凍できないようではテープアーカイブの意味がないじゃん。
どうも、tar はデフォルトだと512バイトのブロック単位で情報を格納するらしく、それがずれると解凍できなくなるらしい。 厄介なことですこと。
しょうがないのでダンプして解析。
$ bzcat rec00001ariel-home.tar.bz2 | hexcat | head -20 00000000 - 68 6f 6d 65 2f 00 00 00 00 00 00 00 00 00 00 00 home/........... 00000010 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000020 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000030 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000040 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000050 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000060 - 00 00 00 00 30 30 34 32 37 37 35 00 30 30 30 30 ....0042775.0000 00000070 - 30 30 30 00 30 30 30 30 30 36 32 00 30 30 30 30 000.0000062.0000 00000080 - 30 30 30 30 30 30 30 00 30 37 33 33 32 33 37 31 0000000.07332371 00000090 - 31 31 30 00 30 31 30 36 34 31 00 20 35 00 00 00 110.010641. 5... 000000a0 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 000000b0 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 000000c0 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 000000d0 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 000000e0 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 000000f0 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000100 - 00 75 73 74 61 72 20 20 00 72 6f 6f 74 00 00 00 .ustar .root... 00000110 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000120 - 00 00 00 00 00 00 00 00 00 73 74 61 66 66 00 00 .........staff.. 00000130 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
ヘッダそのものは 0 バイト目からのファイル名からはじまっている様子。 少なくとも GNU tar だと、0x101 バイトからの ustar というのがヘッダの目印になるらしい。
とりあえず壊れているブロックと、その前まで (正しく解凍できる分) の rec*.bz2 は削除して、 残りを解凍したなかからヘッダを探してみる。
$ find . -name "rec*.bz2" | sort | xargs -n1 bzcat | hexcat | grep ustar 00046f50 - 00 00 00 75 73 74 61 72 20 20 00 74 00 00 00 00 ...ustar .t.... 00108f49 - 00 00 00 00 00 00 00 00 00 00 75 73 74 61 72 20 ..........ustar 001c474d - 00 00 00 00 00 00 75 73 74 61 72 20 20 00 74 00 ......ustar .t. ... $ find . -name "rec*.bz2" | sort | xargs -n1 bzcat | hexcat | grep home/t 00046e50 - 00 00 68 6f 6d 65 2f 74 2f 44 43 49 4d 2f 32 30 ..home/t/DCIM/20 00108e49 - 00 00 00 00 00 00 00 00 00 68 6f 6d 65 2f 74 2f .........home/t/ 001c464d - 00 00 00 00 00 68 6f 6d 65 2f 74 2f 44 43 49 4d .....home/t/DCIM ...
こんな探し方だと、ヘキサダンプの改行をまたぐと発見できないので、ちゃんとバイナリエディタを使いましょう。 それと、tar の中に tar が入っていたりとか、極悪な可能性はいろいろあるが、全部無視。 ヘッダの場所から tar に食わせてやる。
$ printf "%d\n" 0x46e52 290386 $ find . -name "rec*.bz2" | sort | xargs -n1 bzcat | dd bs=1 skip=290386 | tar xvf - home/t/DCIM/20010402/DSCF1152.JPG home/t/DCIM/20010402/DSCF1153.JPG ...
なにやら解凍しはじめた様子。しかし遅い。dd のブロックサイズが1などという設定が悪い。 別にtar 的にはブロック単位にそろっていればヘッダー前のごみを全部除去する必要もないので、ブロックサイズをでかくしてみる。
$ printf "%d\n" 0x452 1106 $ find . -name "rec*.bz2" | sort | xargs -n1 bzcat | dd bs=1106 skip=1 | tar xvf - tar: This does not look like a tar archive tar: Skipping to next header tar: Archive contains obsolescent base-64 headers home/t/DCIM/20010402/DSCF1152.JPG home/t/DCIM/20010402/DSCF1153.JPG ...
これでなんとか解凍できそう。ほかにもいくつか壊れたブロックがあったが、同じプロセスの繰り返しで回避成功。 壊れた部分のファイルは、たまたま別のところにも保存してあったので、問題なし。よかったよかった。
と、いいたいところだが、このバックアップの中に探していたファイルはなかったのであった。 あーあ、なんだかなぁ・・・。やっぱり13日の金曜日なのか・・・。