壊れたファイルシステムから重要なファイルを救い(掬い)出す

ディスクの分割を誤ってうっかり失くしたファイルを復活させる方法を試しています。
再度の話題で恐縮ながら要約すると、 かつて 180GiB を割り当てていた /home ディレクトリ用のパーティション /dev/ad0s1f を、 およそ 55GiB 程度に切り詰めてしまう事故を起こしました。 disklabel を操作してこのパーティションをマウント可能なところまで戻したものの、 自分のホームディレクトリ /home/liangtai が謎のファイル名として残されている以外はどこにもファイルアクセスできない空間と成り果てました。 git.gnome.org のソースツリーに更新データを送るさいに不可欠な認証のための公開鍵/秘密鍵ファイルをこの中に納めているので、 それだけでも何とかして取り戻せないかと思案しておりました。 もちろん抉り取られた約 125GiB の領域に入れていたとしたら諦めて newfs するしかありませんが、 ディスクを新調してまもなく鍵を生成したので運がよければこちら側 (ディスク前方) に残っている可能性があります。

鍵ファイルのすがた

RSA 認証鍵にしているので、 ファイルの先頭は

-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: DES-EDE3-CBC,4FB97B9171332B0E

ではじまっています。 -----BEGIN や RSA を探せばよさそうです。

od コマンドを使ってみる

古い BSD magazine を読み返してみたところ、 disklabel が壊れてしまったディスクを読む苦肉の策について下川英敏氏の囲み記事が目にとまりました。 *1 disklabel を直す必要はないのでこの記事は残念ながら私の事例とは異なっていますが、 ファイルシステムに載せられないディスクも /usr/bin/od -X /dev/BROKEN_DISK とやって内容に探りを入れる手順が示されておりこれを使ってみます。
探さなければならないファイルはテキスト形式なので文字表示つきが最適であろうと考えて od -c で読みます。

 od -c /dev/ad0s1f | grep -n -A1 -- "-   -   -   -   -" | \
 grep -E -B1 -A3 "B   E   G   I   N|R   S   A" | tee ~/dump.txt

これでめぼしいデータにあたりをつけあとからバイト位置や行番号をもとに再度読み出して利用しようという目論見です。 しかしこれではかなりの時間がかかることがわかります。 結局まる2日にわたり 10GiB 程度のところまでこの出力を追い成果を得ぬまま別の方法に乗り換えました。 dd コマンドです。

dd コマンドを使う

dd で小さなファイルにしてから strings と grep の併用で探った方がはるかに速く読めるとわかりました。

for block in `jot -w%04d 50 0 200 4`
	do
		echo ${block}
		offset=`echo ${block} | sed 's,^0*,,'`
		dd if=/dev/ad0s1f of=dump.raw skip=${offset}0000 count=40000 && \
		strings dump.raw > ${block}.txt && \
		getresult=`grep -E -- "-----BEGIN | RSA " ${block}.txt` && \
		if [ "" != "${getresult}" ]; then
			echo "${getresult}"
			cp dump.raw ${block}.raw
		fi
	done

こんなふうに 20MiB に小分けしては内容をテキスト化して保存し検索までを行う工程で、 1GiB ずつ読んでも 10 分とかかりません。 すでに 21GiB 程度まで読み進めました。 残念ながら現時点ではまだ肝心のファイルが見付かっていません。 どうかうまくいきますように。

*1:BSD magazine No.10, p.091, 「特集2 ファイルシステムをハックする」の「消えたdisklabelを復活させる」 amazon:BSD magazine No.10