HDDデータ復旧時にFAT32の制限に嵌ったメモ

2.5インチハードディスクをPCに接続しても認識しなくなったとのことで読めるようにならないか相談を受けました.

元々NotePCに内蔵されていたものをUSB接続の箱に入れて使っていたとのこと.
型番は TOSHIBA MK4058GSX で 約400GB のもの.
USB エンクロージャーは USB3.0 接続で USB A – micro B 3.0 久々に見ました.

復元したデータは一緒に渡された 3.5インチ外付けハードディスクに入れてほしいとのこと.
確認するとFAT32です.権限などは落ちてしまうよなーと確認するとファイルが救えさえすればいいとのこと.

まあディスク認識が出来れば吸い出してloopback mountしてコピーと言う感じかなと思っていたのですがFAT32のおかげで結構面倒でした.

今回は Debian sid amd64 環境でHDDから GNU ddrescue でイメージを吸い出してマウントしてからコピーすることにしました.

Linux環境がなければ SystemRescueCd とかをUSBメモリ起動したりするのがお手軽だと思います.

PCに接続するとキュルキュルカッコンといった異音がします.久々にこういう音をするハードディスクを触りました.

PCに接続して少し時間は掛かりましたが /dev/sdb として認識しました.

認識したところで GNU ddrescue でディスクイメージを吸い出してみます.rateがすごく変動して残り時間が数時間〜数十日で安定しません.幸い1日と少しで最後まで走りきって bad-sector/bad area も見つからなかったので恐らくデータの欠落もなかったようです.

ddrescue
$ time sudo ddrescue -n -v /dev/sdb ./disk.img ./disk.img.log
GNU ddrescue 1.23
About to copy 400088 MBytes from '/dev/sdb' to 'disk.img'
    Starting positions: infile = 0 B,  outfile = 0 B
    Copy block size: 128 sectors       Initial skip size: 7936 sectors
Sector size: 512 Bytes

Press Ctrl-C to interrupt
     ipos:  400088 MB, non-trimmed:        0 B,  current rate:  16015 kB/s
     opos:  400088 MB, non-scraped:        0 B,  average rate:   4225 kB/s
non-tried:        0 B,  bad-sector:        0 B,    error rate:       0 B/s
  rescued:  400088 MB,   bad areas:        0,        run time:  1d  2h 17m
pct rescued:  100.00%, read errors:        0,  remaining time:         n/a
                              time since last successful read:         n/a
Finished

real    1578m2.468s
user    0m35.744s
sys     10m24.384s

吸い出したディスクイメージのパーティションを見るとこんな感じで元PCのリカバリ領域なども残っているようです.

disk partition
$ fdisk -l ./disk.img
Disk ./disk.img: 372.63 GiB, 400088457216 bytes, 781422768 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0xcd22cd22

Device      Boot     Start       End   Sectors   Size Id Type
./disk.img1           2048   3074047   3072000   1.5G 27 Hidden NTFS WinRE
./disk.img2 *      3074048 653834239 650760192 310.3G  7 HPFS/NTFS/exFAT
./disk.img3      653834240 758691839 104857600    50G  f W95 Ext'd (LBA)
./disk.img4      758691840 781422591  22730752  10.9G 17 Hidden HPFS/NTFS
./disk.img5      653836288 758691839 104855552    50G  7 HPFS/NTFS/exFAT

Partition table entries are not in disk order.

mount コマンドの offset option で mount することも出来ますが面倒なので kpartx コマンドでデバイスマッピングをしておきます.
これで出来たループバックデバイスを指定してマウントできます.

デバイスマッピング
$ sudo kpartx -av ./disk.img
add map loop8p1 (253:3): 0 3072000 linear 7:8 2048
add map loop8p2 (253:4): 0 650760192 linear 7:8 3074048
add map loop8p3 (253:5): 0 2 linear 7:8 653834240
add map loop8p4 (253:6): 0 22730752 linear 7:8 758691840
add map loop8p5 (253:7): 0 104855552 linear 7:8 653836288
1つ目のパーティションを読み込み専用で /mnt/p1 にマウント
$ sudo mkdir -p /mnt/p1
$ sudo mount -o ro,loop /dev/mapper/loop8p1 /mnt/p1

rsync を使ってコピー.(--modify-window=2 はFAT32対策)

$ rsync -avvc --modify-window=2 --log-file=rsync.log コピー元 コピー先

数時間後.ログが止まってるけど大きいファイル転送中なのかな?
半日後……未だ終わらない.ログ変わってないような?メモしておく.
1日後.画面に変化がないので固まってる!

Ctrl+Cで中断.
再度実行すると同じところで止まる.

なんでだろう?といろいろ試すと転送先の該当ディレクトリにファイルを作成しようとするとエラーとなることがわかりました.

FAT32の問題で1ディレクトリ内のファイル数制限に引っかかったよう.

短いファイル名長で沢山ファイルを作ると65535個まで
$ n=1;while :;do if ! touch ${n};then echo ${n} ;break;fi ;n=$(( n + 1 ));done
touch: cannot touch '65534': No space left on device
65534
$ ls -1A|wc -l
65533
$ ls -1a|wc -l
65535
255文字のファイル名長だと3123個まで
$ n=1;while :;do if ! touch `printf %0255d ${n}`;then echo ${n} ;break;fi ;n=$(( n + 1 ));done
touch: cannot touch '000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003121': No space left on device
3121
$ ls -lA|wc -l
3121
$ ls -la|wc -l
3123

--exclude '除外' でとりあえずあとで対応.と --timeout=30 オプションを付けてエラー時に終了するようにして再度実行.

$ rsync -avvc --modify-window=2 --timeout=30 --log-file=rsync.log --exclude '除外' コピー元 コピー先

何度か同じエラーがでたので都度除外リストを伸ばしていく><

終わった後に該当ディレクトリはzipアーカイブ化した.4GBを超えるものについてはzipのSplit archives機能(zip 3.0以上)を利用.

$ zip -9rs 3800m /fat32/hoge.zip source_dir

同様にパーティーション2つ目以降もコピーしていく.

書き出しHDDの空き容量に余裕があったので吸い出したRAW Disk イメージもコピーしておく.
4GB制限があるのでsplitで分割してコピー.

$ split -b 4000000000 ./disk.img

これでとりあえず簡単なドキュメントと一緒に渡して終わりにしました.
その後返信ないけど返信がないってことは多分大丈夫なのかな?

てことでディスクはFAT32 は避けたほうがいいねという.デジカメなどでFAT32にしか対応していないものは仕方がないですが,PCに繋ぐ外付けHDDなどはNTFSやexFatなどにしたら今回のようなトラブルに会いにくいと思います.(Linuxでも読み書きできる)