MacのHDDサルベージ

知り合いに、起動しなくなったMacのハードディスクから写真データだけでも取り出せないか?という相談を受けました。

Mac本体はなくなったけど、大切な写真が入っていたので、HDDだけ取り出しておいた。オタクな知人にUSBのHDDケースに入れてもらって復旧を試みてもらったけどダメだった。という代物でした。

ひとまず見てみるけど、そういうのやったことないから期待しないで、ということで、見てみました。

Windows10に接続してみたら、案の定HDDとしては認識されるけど、マウントできませんでした。

早々に諦めて、Ubuntuのサーバに接続し、パーティション構成を確認。

# fdisk -l /dev/sdb
Disk /dev/sdb: 232.91 GiB, 250059350016 bytes, 488397168 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: gpt
Disk identifier: 9005C257-E8EF-4C41-8084-ABE433E26013

Device           Start       End   Sectors   Size Type
/dev/sdb1           40    409639    409600   200M EFI System
/dev/sdb2       409640 487127591 486717952 232.1G Apple HFS/HFS+
/dev/sdb3    487127592 488397127   1269536 619.9M Apple HFS/HFS+

1番目(sdb1)はEFI(ブートローダーなんかがあるところ)だから関係なし。2番目(sdb2)と3番目がHFSだけどサイズからすると2番目がお目当ての場所で、3番目はリカバリー領域かなんかと推測します。念のため、partedでも確認すると、

# parted -l
[...]
Model: TOSHIBA MK2555GSXF (scsi)
Disk /dev/sdb: 250GB
Sector size (logical/physical): 512B/4096B
Partition Table: gpt
Disk Flags:

Number  Start   End    Size   File system  Name                  Flags
 1      20.5kB  210MB  210MB  fat32        EFI System Partition  boot, esp
 2      210MB   249GB  249GB               Customer
 3      249GB   250GB  650MB  hfs+         Recovery HD

となっててビンゴ。

2番目の「File system」が空欄なので、ファイルシステムの異常があやしい、と推測しつつ、とりあえずマウントしてみました。

# mount -t hfsplus /dev/sdb2 /mnt/sdb
mount: /mnt/sdb: wrong fs type, bad option, bad superblock on /dev/sdb2, missing codepage or helper program, or other error.
# tail /var/log/syslog
[...]
Aug 28 17:39:23 host kernel: [611577.511062] hfsplus: Filesystem was not cleanly unmounted, running fsck.hfsplus is recommended.  mounting read-only.
Aug 28 17:39:23 host kernel: [611577.511400] hfsplus: invalid catalog max_key_len 122
Aug 28 17:39:23 host kernel: [611577.511712] hfsplus: failed to load catalog file

スーパーブロックが壊れているんでしょうね、マウント失敗です。

EXT2などはスーパーブロックのバックアップがあって、こんな状況になっても簡単に復活できる可能性があるみたいなんですが、man mkfs.hfsplus してもそれらしい記述はみつかりませんでした。

ということで、復活の方針は以下のように。

  1. dd でディスク丸ごと吸出し
  2. ダメ元でfsckを試みる
  3. スーパーブロックの復活を試みる
  4. ファイルシステムの復旧はあきらめ、レスキュー可能なファイルを拾い上げる

HDDがマウントできなくなった時にfsckすると、ほとんどのファイルが消えてしまったり、物理的に壊れてしまったり、と、あまりいい思い出がないので、ひとまずddで吸い出した後でゴニョゴニョします。

# dd bs=4096 conv=noerror,sync if=/dev/sdb of=HFS_HDD.img

しばらく待ってから別の端末で、

# kill -USR1 <PID of the dd> 

すると、dd を実行している端末に進捗状況が出力されるので、完了するまでどのくらいかかるかを計算します。300KB/sec しか出てなかったので、250GBは10日近くかかる計算になります。しばらくHDDのことは忘れることにしました。

数日後、思い出して kill してみると、だいたい想定通りの進捗でしたので、また忘れることに。

10日後、見てみると、終わってました。\(^o^)/

なお、サーバにはWindows 10のパソコンからWSL Terminalでsshして接続していますが、10日もWSL Terminalを立ち上げっぱなしではなく、サーバー上で screen を起動し、そこで dd を実行します。その後、screen をデタッチして ssh をログアウト、WSL Terminal を閉じますが、サーバー上では screen のターミナル上で dd が動き続けています。数日後、同じように WSL Terminal から ssh で接続し、screen をアタッチして状況確認ができるというわけです。

ということで、ダメ元の fsckを試みます。まずは HFS_HDD.img という普通のファイルをデバイスファイルにしないと fsck できません。こういうのは loopback デバイスを使うというのはわかってても、具体的にどうやるのかわからなかったので、調べてみたらおおむね2つの方法がありました。

  • losetup で2番目のパーティションのオフセットを指定してアタッチ
  • partx または kpartx で全パーティションをアタッチ

ということで、kpartx でアタッチしてみました。

# kpartx -a HFS_HDD.img
# ls -l /dev/mapper/
total 0
crw------- 1 root root 10, 236 Aug 28 15:46 control
lrwxrwxrwx 1 root root       7 Aug 28 17:11 loop4p1 -> ../dm-0
lrwxrwxrwx 1 root root       7 Aug 28 17:11 loop4p2 -> ../dm-1
lrwxrwxrwx 1 root root       7 Aug 28 17:11 loop4p3 -> ../dm-2

さっそくfsckしてみます。

# fsck.hfsplus -fr /dev/mapper/loop4p2
** /dev/mapper/loop4p2
** Checking HFS Plus volume.
   Invalid node structure
(4, 0)
** Volume check failed.

だめですね。次の作戦に移行します。

スーパーブロックの修復に使えるツールを探したら、TestDisk というのを見つけました。使い方がよくわからなかったんですが、こんな感じでリカバリーできなさそうな感じだったので、次の作戦に移行です。

TestDisk 7.1, Data Recovery Utility, July 2019
Christophe GRENIER <grenier@cgsecurity.org>
https://www.cgsecurity.org

Disk /dev/mapper/loop4p2 - 249 GB / 232 GiB - 486717952 sectors

The harddisk (249 GB / 232 GiB) seems too small! (< 249 GB / 232 GiB)
Check the harddisk size: HD jumper settings, BIOS detection...

The following partitions can't be recovered:
     Partition               Start        End    Size in sectors
   HFS                        35888  486753839  486717952
>  HFS                        43896  486761847  486717952
   HFS                        47656  486765607  486717952

最後の、レスキュー可能なファイルを拾うためのツールは、TestDisk の姉妹品の PhotoRec と、hfsprescue というのを見つけました。

どちらも同じような方式で、スーパーブロックが壊れていても、データブロックからファイルらしきものを見つけて救出するようです。PhotoRec はいろんなファイルシステムに対応してますが、hfsprescure はHFS+に特化しているみたいなので、hfsprescure を使ってみることにしました。

# hfsprescue_x64 -s1 /dev/mapper/loop4p2

出力をメモっておかなかったので詳細なメッセージなどは記載できないのですが、基本的にはステップ1(-s1)~ステップ6(-s6)まで、順に実行するだけです。各ステップ終了時に、インフォメーションと次に実行するコマンドが表示されます。

ステップ2が終わったときに、インフォメーションに、マルチバイト文字を使ってるなら「-utf8len 2」オプションをつけたほうがいいよ、てなぐあいにメッセージを出してくれたので、オプション追加してやり直しました。

ステップ2以降はこんなかんじ。

# hfsprescue_x64 -s2 --utf8len 2
# hfsprescue_x64 -s3 /dev/mapper/loop0p2
# hfsprescue_x64 -s5
# hfsprescue_x64 -s6

リカバリーしたファイルは restored/newroot/ 以下にできます。まずは、そこにある INFO.txt を読むと、概要がわかるようになっていました。

Files restored with hfsprescue 3.5-rc1 2020/04/26 https://www.plop.at

Directory description:
======================

recovered           - You find your recovered files here.

x_directory_problem - It was not possible to link the files and directories to their parent directory. You will find here files too.

x_unknown           - No valid parent directory has been found. Maybe you will find here already deleted files. The files in this directories can be invalid.


Additional info files:
======================

The contents of those files is just a list of the files in the corresponding directory.
Useful when you need an overview of the restored files.

recovered-files.txt, x_directory_problem-files.txt, x_unknown-files.txt

recovered はありませんでしたが、x_directory_problem と x_unknown には多くのファイルがリカバリーされていました。全部で約130GBありました。

x_directory_problem ディレクトリのファイルリストが x_directory_problem-files.txt にあったので、つらつらと眺めると、数字のディレクトリと「ù!」みたいな(実際はアクセント付きuの真ん中に点みたいなのがある字)ディレクトリがありました。数字のディレクトリには文字化けしたようなファイルばかりでしたが、「ù!」みたいなディレクトリには以下のディレクトリが存在していました。

# ls -Fa
 ./                    .DocumentRevisions-V100/   .Spotlight-V100/              .vol/
 ../                   .fseventsd/                System/                       Volumes/
'$RECYCLE.BIN'/        Library/                  'System Volume Information'/
'Adobe Updater.app'/   private/                   Users/
 Applications/         sbin/                      usr/

変なディレクトリ名は扱いにくいので、root にリネーム。Users 下に、写真と思われるファイルがあるのを確認しました。おそらくこれで、目的はた達成したかと思います。

x_unknown は空のディレクトリも多くあったので、ひとまず空のディレクトリを削除したら、かなりすっきりしました。

# find . -type d -empty -delete
# \ls -Fa
./  ../  18/  229104/  229266/  229386/  229457/  229838/  230042/

18 以外は *.cpp や *.hpp ファイルしかなかったので放置しました。18 には「iNode525393」といったファイル(“iNode”+数字)が20,926個ありました。画像ファイルだけ救ってあげようと思い、まず file コマンドでファイルフォーマットを調べました。

# file * > file_types.txt
# awk '{print $2}' file_types.txt |sort|uniq > types

types の中から画像ファイルを探すと、PNG, GIF, JPEGの3つでしたので、これらのファイルだけを別なディレクトリにコピーして、サフィックスを付けます。

# perl -ne 'print "cp -p  $1 ../../x_unknown-igames/$1.$2\n" if ($_ =~ /^([^:]*): *(GIF|PNG|JPEG) /);' file_types.txt | sh

x_directory_problem/root と x_unknown-images ディレクトリをUSBの外付けハードディスクにコピーして、依頼主に渡しました。

とっても喜んでもらえたけど、お目当ての写真があるかどうかはわからないからね、と伝えました。あるといいですが。。。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です