ブログ

【解決】Macで古いCDが読み込めない原因と、中身を取り出す方法

目次

最近の Mac に古い CD を入れたら、これが出ました。

The disk you attached was not readable by this computer.

The disk you attached was not readable by this computer.

日本語環境だと「セットしたディスクは、このコンピュータで読み取れないディスクでした。」と出ます。Ignore と Eject の 2 択です。

読めなくなった原因は Mac の側にあります。ディスクは無事なことがほとんどです。

  • 本や雑誌の付録 CD、昔焼いた CD を入れても読み込めない
  • デスクトップにも Finder のサイドバーにも出てこない
  • ドライブは動いていて、ディスクも回っているのに開けない
  • diskutil list にディスクは出てくるのに、中身が見えない
  • 別の Mac や別のドライブでも同じで、ディスクの故障を疑っている

「読めない」「読み込めない」「認識しない」「読み取れないディスクでした」と言い方は人によって違いますが、原因が同じならこの記事の手順で取り出せます。


原因と対処

古い Mac 用の CD は HFS Standard という 1985 年のファイルシステムで焼かれています。Apple は macOS 10.15 Catalina でこの形式の読み込みドライバを削除しました。ドライバが無いので、ディスクが無傷でもマウントできません。

古い機材だから読めないのではなく、新しい Mac ほど読めません。

状況やること
Mojave 以前の Mac があるそれに入れます。普通にマウントして普通にコピーできます。これが最短です
無いディスクをイメージ化して、中身を自前で取り出します。手順は下にあります

そう言える根拠を、この記事では実機で確かめています。

  • macOS の hfs.util が、このディスクに対して FSUR_UNRECOGNIZED を返すところまで実機で確認しました
  • 判定しているのはボリューム先頭 1024 バイト目の 2 バイトだけです。H+ なら読み、BD なら拒否します
  • Apple の一次情報は各セクションに置きました。TN1150Inside Macintosh: Files、macOS 同梱のヘッダ loadable_fs.hhfs_format.h です

古い Mac が手元にない場合

スクリプトを用意しました。手順もこの中にあります。

ringomax/hfs-cd-recovery

git clone https://github.com/ringomax/hfs-cd-recovery.git
cd hfs-cd-recovery
brew install ddrescue

drutil status                                    # ディスクを確認
DEV=/dev/rdisk62                                 # 実際の番号に置き換える
TOTAL=$(drutil status | awk '/blocks:/{print $3}')
SIZE=$(( TOTAL * 2352 ))

ddrescue -b 2352 -r3             $DEV disc.raw disc.map   # 吸い出す
ddrescue -b 2352 -r3 -R -s $SIZE $DEV disc.raw disc.map   # 逆順で仕上げる
./ripcd.py disc.raw ./out                        # ファイルを取り出す
./verify.py disc.raw --extracted ./out           # 正しく読めたか検算する

/dev/disk ではなく /dev/rdisk を指定してください。ここを間違えると、エラーを 1 件も出さないままデータが壊れます。理由は後述します。


検証環境

項目
機種MacBook Pro
チップApple M4 Max
macOS26.5.2 25F84
ドライブApple USB SuperDrive
対象CD-ROM 2 枚。386 MB と 688 MB

ドライブは Apple 純正で、すでに販売を終了しています。USB-A 接続なので、今の Mac につなぐには USB-C 変換かハブが要ります。USB-A のまま直挿しできないことが、後で 3 つ目の問題につながります。

ioreg 上では MacBook Air SuperDrive という USB Product Name で見えます。

2025 年以降の Mac と最新の macOS という組み合わせで起きています。


まずディスクの生死を確かめる

ダイアログは Ignore で閉じます。Eject を押すと排出されるので、調べるなら Ignore です。

drutil status
 Vendor   Product           Rev
 Apple    SuperDrive        2.03

           Type: CD-ROM               Name: /dev/disk62
       Sessions: 1                  Tracks: 1
     Space Used:   36:28:19         blocks:   164119 / 336.12MB / 320.54MiB

セッション数、トラック数、使用領域が返ってきました。まだファイルは 1 バイトも読んでいない段階でこれが出ます。

TOC とは何か

これは TOC から取れた情報です。Table of Contents、CD の目次にあたるデータです。

ディスクの最内周、レコードで言えば針を落とす側に「リードイン」という領域があり、そこに何トラック入っていてそれぞれどこから始まるかが記録されています。音楽 CD をプレイヤーに入れた瞬間に曲数と長さが出るのは、全曲を読んだのではなく TOC だけを読んでいるからです。

TOC はデータ領域とは別の場所に、サブチャンネルという別の信号系で書かれています。物理的にも内周は有利で、ディスクを掴む時に触るのも、ケースから出し入れする時に擦れるのも外側です。

TOC が読めると何が言えるか

  • TOC も読めない場合、ほぼ確実に物理的な問題です。ディスクかドライブのどちらかです
  • TOC が読める場合、少なくとも最内周は生きています。ディスク全体が死んではいません

「TOC が読めたから記録層は無事」とまでは言えません。TOC は最内周にあるので、外周が傷んでいても TOC は読めます。実際、2 枚目は TOC を普通に読めましたが、最外周の 28 MB は最後まで読めませんでした。

それでも診断としては意味があります。「ディスクが完全に死んだ」と「フォーマットが読めないだけ」を分けられます。

次にファイルシステムを見る

diskutil list disk62
/dev/disk62 (external, physical):
   #:                       TYPE NAME                    SIZE       IDENTIFIER
   0:        CD_partition_scheme                        *386.0 MB   disk62
   1:     Apple_partition_scheme                         336.1 MB   disk62s1
   2:        Apple_partition_map                         1.0 KB     disk62s1s1
   3:                  Apple_HFS                         334.4 MB   disk62s1s2
diskutil info disk62
   Volume Name:               Not applicable (no file system)
   File System:               None
   Device Block Size:         2352 Bytes

パーティションの型まで Apple_HFS と判定できています。それでいて File System: None です。ディスクの構造は読めているのに、中身のフォーマットだけが解釈できていません。


あのダイアログはどこから出ているのか

パーティションまで見えているのに、どの処理がどこで失敗しているのか。実機で追いかけると、止まっている場所がはっきりします。

flowchart TD
    A&#91;CD の記録面] --> B&#91;SuperDrive<br/>USB Mass Storage として応答]
    B --> C&#91;IOKit<br/>ブロック単位で読める IOMedia になる]
    C --> D&#91;"デバイスファイルが生える<br/>/dev/disk62 と /dev/rdisk62"]
    D --> E&#91;"パーティション認識<br/>disk62s1s2 = Apple_HFS"]
    E --> F&#91;diskarbitrationd<br/>担当するファイルシステムを探す]
    F --> G&#91;"hfs.util -p<br/>1024 バイト目のシグネチャを見る"]

    G -->|"H+ または HX → 255"| H&#91;"mount(2)"]
    G -->|"BD → 254 FSUR_UNRECOGNIZED"| X&#91;DiskArbitrationAgent]

    H --> I&#91;"/Volumes/ にマウント"]
    I --> J&#91;Finder に表示される]

    X --> Y&#91;"The disk you attached was not<br/>readable by this computer."]

ドライブが回転を上げ、TOC を読み、USB Mass Storage として応答します。IOKit が応答を受け、ブロック単位で読める抽象に変換します。

次にデバイスファイルが生えます。/dev/disk62/dev/rdisk62 の 2 本です。この 2 本があることが、後でデータを壊す分岐点になります。

続いてパーティションを切り出します。IOKit が先頭を読み、Apple Partition Map を見つけて子ノードを publish します。それぞれに Content Hint という型情報が付きます。diskutil listApple_HFS まで見えていたのはこの段階です。

ここで diskarbitrationd が検知します。/usr/libexec/diskarbitrationd という常駐プロセスが、新しいメディアの Content Hint に対応するファイルシステムを探します。

macOS が持っているファイルシステムは /System/Library/Filesystems/ に置かれています。

apfs.fs   cd9660.fs   exfat.fs   hfs.fs   msdos.fs   ntfs.fs   udf.fs  ...

それぞれの Info.plist に、どのメディア型を担当するかが書いてあります。hfs.fs を見ます。

hfs.fs が probe を名乗り出るメディア型:
  Apple_Boot
  Apple_HFS        ← これ
  Apple_HFSX
  CD_ROM_Mode_1
  Whole

Apple_HFS の担当は hfs.fs だけです。

そして probe を実行します。diskarbitrationdhfs.util -p disk62s1s2 を起動し、ボリュームが hfs.fs の対応形式かを問い合わせます。

失敗するのはこの probe です。


hfs.util -p を直接叩いてみる

このプログラムは macOS 本体に入っているので、自分で実行できます。HFS Standard のボリュームと HFS Plus のボリュームを、それぞれ渡してみました。

HFS Standard を渡した場合はこうなります。

--- signature ---
00000000: 4244   BD
--- probe ---
exit=254

HFS Plus を渡した場合はこうなります。

--- signature ---
00000000: 482b   H+
--- probe ---
PROBETESTexit=255

戻り値は Apple の loadable filesystem 規約で決まっています。

定数意味
255FSUR_RECOGNIZED自分の形式。ボリューム名を stdout に返す
254FSUR_UNRECOGNIZED自分の形式ではない
253FSUR_IO_SUCCESSmount、unmount、修復が成功
252FSUR_IO_FAIL回復不能な I/O エラー

戻り値の定義は macOS 本体に入っています。負の値で定義されていて、プロセスの終了コードとしては 256 から引いた値になります。

/* /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/sys/loadable_fs.h */

#define FSUR_RECOGNIZED    (-1)  /* response to FSUC_PROBE; implies that
                                  * a mount is possible */
#define FSUR_UNRECOGNIZED  (-2)  /* negative response to FSUC_PROBE */
#define FSUR_IO_SUCCESS    (-3)  /* mount, unmount, repair succeeded */
#define FSUR_IO_FAIL       (-4)  /* unrecoverable I/O error */

このファイルは Xcode Command Line Tools を入れた Mac なら手元にあります。FSUC_PROBE への否定的な応答、という一行が、あのダイアログの出発点になっています。

あのダイアログの正体はこの 254 でした。1024 バイト目の 2 バイトが H+BD かで分岐しています。

255 が返れば mount(2) が呼ばれ、/Volumes/<名前> にマウントされ、Finder がデスクトップとサイドバーに出します。254 なら他に担当がいないので、DiskArbitrationAgent がダイアログを出します。

BD とは何か

ファイルシステムには「自分が何者か」を名乗る仕組みが要ります。ディスクの中身はただのバイト列なので、外から見ても区別がつきません。そこで、決まった位置に決まった値を置きます。読む側はその値で形式を判断します。この目印を magic number と呼びます。

JPEG なら先頭が FF D8、PNG なら 89 50 4E 47、HFS なら 1024 バイト目が 42 44 です。

Apple 自身のヘッダに定義があります。macOS 26 の SDK に今も入っています。

/* /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/hfs/hfs_format.h */

kHFSSigWord      = 0x4244,   /* 'BD' in ASCII */
kHFSPlusSigWord  = 0x482B,   /* 'H+' in ASCII */
kHFSXSigWord     = 0x4858,   /* 'HX' in ASCII */

H+ は HFS Plus、HX は HFSX で、明らかに略語として選ばれています。一方 BD が何の略なのかは、Apple のヘッダにも Inside Macintosh にも書かれていません。確かな出典を見つけられなかったので、ここは不明としておきます。

なお、この BD は Blu-ray Disc とは無関係です。Blu-ray の規格発表は 2002 年で、HFS の BD は 1985 年です。光ディスクの中に、光ディスクより古い BD が入っています。

定数の定義は残っているのに、定数が表す形式を読むドライバは消えています。hfs_format.h には kHFSSigWord も MDB の構造体も B-tree ノードの定義も全部あります。それでいて hfs.utilBD を見た瞬間に 254 を返します。今回自前で解析できたのは、この定義が残っていたおかげでもあります。

調べていて引っかかったところ

担当は決まっているのに、この個体は読めません。hfs.fsApple_HFS の担当を名乗り出ています。担当者がいないのではなく、担当者が匙を投げています。だから他のファイルシステムに回されることもなく、そこで終わります。

ダイアログは「壊れている」と言っていません。

The disk you attached was not readable by this computer.

by this computer が正確な記述になっています。このコンピュータには読む手段が無い、という意味しかありません。ディスクの状態については何も主張していません。

画面を見ると「ディスクが壊れた」と受け取りやすいのですが、システムはそう言っていません。

診断情報も捨てられています。hfs.util は 254 を返しただけで、理由を返す口を持っていません。「シグネチャが BD だった」という情報は、この時点で確かに存在していたのに、diskarbitrationd には伝わりません。

もし「HFS Standard を検出しました。macOS 10.15 以降は非対応です」と出せていれば、誰もディスクを疑わずに済みました。規約の戻り値が 3 種類しかないことが、13 年前の本の付録 CD を捨てさせています。


HFS とは何か

HFS は Hierarchical File System の略で、Apple が 1985 年に作った Mac 用のファイルシステムです。

一次情報は 2 つあります。ファイルシステムとしての API と構造は Inside Macintosh: Files、HFS と HFS Plus の差分は Technical Note TN1150: HFS Plus Volume Format に載っています。どちらも Apple の archive に残っています。

前身の MFS には、本当の意味のフォルダがありませんでした。フォルダに見えるものはありましたが、実体は全ファイルが 1 枚のリストに並んでいるだけでした。フロッピー 400 KB 前提の設計です。HFS はハードディスク時代に合わせて、フォルダの入れ子を実データ構造として持たせました。階層化したところが名前の由来です。

形式主な変更
1984MFSフラット。フロッピー専用
1985HFS階層化。カタログ B-tree
1998HFS Plus32bit 化、Unicode ファイル名、大容量対応
2017APFSSSD 前提。現行

紛らわしいのは、「HFS」が 2 つの意味で使われることです。1985 年のオリジナルを指す場合と、HFS/HFS+ をまとめた総称の場合があります。区別する時は前者を HFS Standard と呼びます。Apple のパーティション型はどちらも Apple_HFS なので、型名では判別できません。

Apple は macOS 10.15 Catalina で HFS Standard の読み込みドライバを削除しました。書き込みではなく読み込みごとです。

ここは注意が要ります。Apple はこの削除を公式にアナウンスしていません。Catalina のリリースノートを読んでも HFS への言及は無く、Apple のコミュニティフォーラムで利用者が報告しているだけです。この記事で実測した hfs.util の挙動が、手元で確認できる唯一の証拠になります。

告知が無いので、古い CD を持っている人は壊れたと誤解したまま捨てることになります。

macOSHFS Standard
10.14 Mojave 以前読める
10.15 Catalina 以降読めない

16bit の壁

HFS の割り当てブロック数は 16bit で、最大 65,535 個しか持てません。

これは Apple 自身が TN1150 の "Efficient Use of Disk Space" で明記しています。

HFS divides the total space on a volume into equal-sized pieces called allocation blocks. It uses 16-bit fields to identify a particular allocation block, so there must be less than 2^16 (65,536) allocation blocks on an HFS volume.

同じ文書の "HFS and HFS Plus Compared" の表では、割り当てブロック数が HFS で 16 bits worth、HFS Plus で 32 bits worth と対比されています。

ディスクが大きくなるとブロック数を増やせないので、1 ブロックを大きくするしかありません。今回の 2 枚が実際にそうなっていました。

ディスク容量割り当てブロックサイズブロック数
1 枚目334 MB6,144 バイト54,422
2 枚目598 MB10,240 バイト58,370

どちらも 65,535 の手前に収まっています。512 バイト単位のままなら 1 枚目で 653,083 ブロック必要になり、上限を 10 倍振り切ります。

この制限が HFS の弱点でした。1 GB のディスクなら 1 ブロック 16 KB になり、1 バイトのファイルが 16 KB を占有します。HFS Plus が 32bit 化した主な理由は、この制限にあります。

CD-ROM の容量なら 16bit で足ります。古い Mac との互換性も確保できるので、Mac 用 CD-ROM のフォーマットとして HFS Standard は長く残りました。

「Sierra で終了」は半分間違い

この件を検索すると、「macOS Sierra でサポートが終了した」と書いてある記事が多く出てきます。出版社の FAQ にもそう書かれています。

半分正しくて、半分間違っています。実際には 3 段階ありました。

実際に起きたこと
Mac OS X 10.6 Snow Leopard書き込みが不可になった。読み込みは動き続けた
macOS 10.12 SierraApple がリリースノートに The HFS Standard filesystem is no longer supported と書いた。しかし読み込みは動き続けた
macOS 10.15 Catalina実際に読めなくなった

Sierra 説の出どころは、Apple 自身の告知文です。ところが告知の後も 3 年間、Mojave まで読み込みは普通に動いていました。告知と実挙動が 3 年ずれています。

このずれが実害を生みます。「Sierra 以降は無理」と思い込むと、手元の Mojave の Mac に挿せば 30 秒で終わるという一番簡単な解決策を捨ててしまいます。

時系列の出典は Wikipedia の HFS 記事にまとまっています。Snow Leopard の記述はこうです。

beginning with Mac OS X 10.6 (Snow Leopard), HFS Standard volumes are read-only and cannot be created or updated.

Catalina の記述はこうです。

Starting with macOS 10.15, HFS Standard disks can no longer be read.

イメージ化して開く回避策も、今は動かない

もう 1 つよく見かけるのが、ディスクユーティリティでディスクイメージを作って、それをマウントするという手順です。これも今は動きません。

イメージ化しても中身は HFS Standard のままで、macOS には読む手段がありません。実際に試しました。hdiutil attach でイメージを接続しても、diskutil info はこう返します。

   Volume Name:               Not applicable (no file system)
   File System:               None

hfs.util に直接聞いても 254 が返ります。入れ物を変えても、中身を解釈する部品が存在しません。この手順は Mojave までなら動いたはずで、そのまま残っているのだと思います。

押し入れに Mojave のまま止まっている古い Mac があるなら、そこに挿すのが最短です。今回は手元になかったので自力で解析しました。

/dev/disk/dev/rdisk

ディスクでもランダムでもないなら、読み方しか残りません。読み方を変えて比較しました。

読み方重複ノード
dd if=/dev/disk62 bs=2352264
dd if=/dev/disk62 bs=4816896333
hdiutil create -srcdevice /dev/disk620

hdiutil だけが正しく読めました。ブロックサイズを変えても dd からは壊れます。しかも回数ごとに数が変わります。

同じデバイスを指しているのに結果が違うなら、アクセス経路が違います。

Unix ではディスクが /dev/disk62 というファイルとして見えます。ここまではまだいいのですが、同じディスクに /dev/rdisk62 という別のファイルも生えています。

  • /dev/diskN — カーネルのバッファキャッシュを経由するブロックデバイス
  • /dev/rdiskN — キャッシュを通さない raw キャラクタデバイス

同じデバイスを指すファイルが 2 つあるのは、片方がキャッシュを通り、片方が通らないからです。普段は速い disk を使えばよく、rdisk の存在すら意識しないことが多いと思います。hdiutil は raw 側を使います。

試しました。

dd if=/dev/rdisk62 bs=4816896 count=1 of=head_rdisk.raw
/dev/rdisk62: leaf=1951 重複=0

重複ゼロです。さらに hdiutil の出力と比較しました。

cmp head_rdisk.raw head_hdiutil.raw && echo identical
identical

バイト単位で完全に一致しました。原因が確定です。

なぜ壊れるのか

ここまでが観測事実で、ここからは推測です。

重複の周期は 4096 バイトと 8192 バイトでした。ページサイズちょうどの倍数です。そして CD のセクタサイズは 2352 バイトで、4096 では割り切れません。

2352 × 1 = 2352      ページ 4096 に収まる
2352 × 2 = 4704      ページ境界をまたぐ
2352 × 8 = 18816     4096 × 4.59...  どこにも揃わない

2352 バイト単位のブロックを 4096 バイトのページにキャッシュする過程でずれが生じ、別セクタの内容が返っていると説明できます。ハードディスクや SSD のセクタは 512 か 4096 で、どちらもページサイズと整合します。2352 という半端な値を持つのは光学メディアだけで、この経路が日常的に踏まれないことと符合します。

ただしカーネル内部までは確認していません。確認するなら XNU のソースか dtrace で追うことになります。現時点で言えるのは、キャッシュを通す経路だけが壊れるという観測事実までです。

そして最初にずれていた 8192 バイトも、これで説明がつきます。あれは Toast の特殊な配置ではなく、同じ現象でした。


ツールのせいではなかった

原因が分かった後、正しく読めたイメージを hfsutils に渡してみました。

hmount IRYO_clean.hfs
hls
Volume name is "IRYO"
Volume was created on Thu Jan 17 17:51:50 2013
Volume was last modified on Wed Feb 20 13:41:08 2013
カラーJPEG   カラーPNG   白黒JPEG   白黒PNG

普通に動きました。

malformed b*-tree header node は、ツールが古いから出たのではありません。壊れたイメージを渡していたから出ていました。ヘッダノードが本来の位置になかったのは事実で、hfsutils はそれを正しく指摘していました。

読み方を先に直していれば、自前で解析する必要はありませんでした。ツールが失敗した時は、ツール自体より先に入力データを疑ったほうがよさそうです。

なお 7-Zip は HFS Plus 前提なので、こちらは正しく読めたイメージでも読めません。


エラーを出さない破損に気づけた理由

このバグには、失敗を知らせる仕組みが 1 つもありませんでした。

  • dd は終了コード 0 を返した
  • 読み取りエラーは 0 件
  • 転送バイト数はディスクサイズと一致
  • 2 回読んで md5 も一致した
  • 抽出も最後まで走り、3,363 個のファイルが出てきた
  • 画像も普通に開けた

すべての表面的な指標が正常を示していました。それでも 786 個のファイルが消えていました。

見つけられたのは、ファイルシステムが冗長なメタデータを持っていたからです。

drFilCntdrDirCnt は、ボリュームヘッダに書かれたファイル総数とディレクトリ総数です。カタログから計算されるものではなく、独立に記録された値です。1985 年の設計者が df を速くするために置いたのだと思いますが、結果として 41 年後のデバッグで検算材料になりました。

冗長性がなければ、3,363 個を全部だと信じて終わっていました。開けるファイルだけ見て、うまくいったと思い込んでいたはずです。

同じことは、ヘッダに書かれた長さ、末尾のマーカー、チェックサム、件数にも言えます。冗長な情報は、正常時には無駄に見えますが、異常時の検算に使えます。エラーを出さない異常に対しても、記録済みの値と実際の結果を比較できます。

最終的に、検算を 3 つ独立に持つようにしました。

  1. カタログを走査したファイル数とディレクトリ数が、ヘッダの申告と一致するか
  2. 葉ノードの md5 に重複がないか
  3. 抽出した全ファイルの識別子と終端マーカーが揃っているか

3 つとも通って初めて終わりにします。1 つでも欠けると、静かな破損を見逃します。

3 つ目には後から手を入れました。先頭のマジックバイトと終端マーカーだけでは、ファイルの中央が別のデータに置き換わっても通ってしまいます。両端は無傷のまま残るからです。

PNG はこれを自力で検出できます。PNG 仕様がチャンクごとに CRC-32 を義務付けています。

A four-byte CRC (Cyclic Redundancy Check) calculated on the preceding bytes in the chunk, including the chunk type field and chunk data fields, but not including the length field.

この検査を入れたことで、後に 2 つのイメージのどちらが正しいかを機械的に判定できました。JPEG には同等の仕組みが無いので、同じ判定はできません。

この 3 つは verify.py にまとめてあります。


ドライブが USB から消える

2 枚目でもう 1 つ別の問題にぶつかりました。読み込み中に落ちます。

hdiutil: create failed - Input/output error

drutil status が無反応になり、USB のツリーを見るとドライブそのものが消えていました。

+-o Root
  +-o AppleT8132USBXHCI@01000000
  | +-o USB2.0 Hub@01100000
  |   +-o USB-C Digital AV Multiport Adapter@01120000     ← SuperDrive がいない

ディスクの傷なら読み取りエラーが返るだけでドライブは残ります。デバイスごと消えるのは電力側の問題です。同時刻のログにも痕跡がありました。

usbpowerd&#91;421] terminated <private>

Apple USB SuperDrive はバスから電源を取ります。読みにくい領域でヘッドの位置決めをやり直し続けると電流が上がり、ハブを何段も経由していると電圧が落ちて脱落します。USB-A 機器なので今の Mac では変換かハブが要り、この構成を避けにくいところがあります。今回はディスク最外周で起きました。物理的に傷と汚れが集中する場所です。

物理側の対処は次のとおりです。

  • Mac 本体のポートへ USB-C 変換だけで直結します。ハブとドックは挟みません
  • それでも落ちるなら電源付きハブを使います
  • 落ちた直後は 10 秒以上抜いたままにします。放電しないと再認識しません
  • 記録面を中心から外周へ放射状に拭きます。円を描くように拭いてはいけません

落ちる前提で組む

hdiutil はこの状況に弱いです。1 回の長いトランザクションとして動くので、途中で失敗すると、それまで読めた分も含めて出力ファイルごと削除されます。95% で落ちると全部やり直しになります。

そこで分割読み込みに切り替え、次の 3 つの処理を入れました。

  1. チャンク単位で進捗を記録する。差し直して再実行すれば続きから走ります
  2. 残りを逆順に読む。不良領域の位置が固定なら、そこを最後に回して残りを先に確保できます
  3. 読めないチャンクは記録してスキップする。ドライブが生きている限り、同じ場所で毎回止まりません

実装は chunkrip.sh です。2 枚目は最後の 28 MB で 10 回以上脱落しました。

この 3 点は ddrescue にすべてある

後で気づいたのですが、分割読み込みに実装した 3 つの処理は、GNU ddrescue がすべて備えています。

自作したものddrescue
チャンク単位の進捗記録と再開mapfile
逆順読み-R
読めない領域のスキップ標準動作。しかも適応的に分割して再挑戦する

しかも ddrescue のほうが粒度が細かいです。自作のほうは 1.2 MB チャンク単位で、1 セクタでも失敗するとチャンク全体を捨てます。ddrescue は不良領域をセクタ単位で記録して、読める分だけを確実に残します。

この粒度の差が、最後まで読めるかどうかを分けます。

オプションの意味は GNU ddrescue の公式マニュアルにあります。mapfile の書式、-R の挙動、-b でセクタサイズを指定する意味も、すべてそこに書かれています。

brew install ddrescue
ddrescue -b 2352 -r3 /dev/rdisk62 disc.raw disc.map

-b は CD のセクタサイズに合わせます。-s-i で範囲を切る場合、その値も 2352 の倍数にしないと raw デバイスが読み取りを拒否します。

ddrescue: /dev/rdisk62: Unaligned read error. Is sector size correct?

そして逆順で読む時は -s が必須になります。ddrescue は raw 光学デバイスのサイズを取得できません。順方向は 0 から進んで終端で止まるので困りませんが、逆順は終端の位置を知らないと開始できません。-s なしだと mapfile がこうなり、何も読まずに終わります。

0x00000000  0x7FFFCCA9818BD890  ?

読み方を変えたら、諦めた分が戻ってきた

自作の分割リッパーで読んだ時、最外周がどうしても読めませんでした。10 回以上ドライブを抜き差ししても届かず、この 530 件はもう物理的に無理だろうと諦めました。

後から ddrescue で読み直したら、同じディスク、同じドライブで戻ってきました。

手段未回収
自作の分割リッパー530
ddrescue 1 回目109
ddrescue 再開 1 回目25
ddrescue 再開 2 回目3
ddrescue -R 9 秒 1 回0

差はチャンクの粒度と、読む方向でした。

自作のほうは 1.2 MB 単位で読み、1 セクタでも失敗するとチャンク全体を捨てていました。ddrescue は不良領域をセクタ単位で記録し、その周囲の読める分をすべて残します。

そして最後の 3 件を救ったのは逆順読みでした。順方向は必ず内周から外周へ進むので、最も劣化した最外周に到達する頃にはドライブが力尽きています。逆順は末尾から始まるので、ドライブが元気なうちにそこへ届きます。順方向 3 パスが届かなかった 25 セクタを、逆順は 9 秒で取りました。

読めない領域が残っても、ディスクが死んでいるとは限りません。粒度と方向を変えるだけで届くことがあります。このディスクから失われたデータは、結局ありませんでした。

ファイルサイズを進捗の指標にしない

出力ファイルのサイズが最終サイズに達しても、全域を読み終えたことにはなりません。ddrescue は読んだ位置に書き込むので、まだ埋まっていないセクタがあってもファイルサイズだけは先に最終値へ届きます。ここで打ち切ると 25 セクタが未読のまま残ります。

見るのは mapfile のほうです。

grep -v '^#' disc.map
0x00000000  0x28E7FDD0  +      取得済み
0x28E7FDD0  0x00000930  -      不良
0x28E80700  0x0000DC80  *      要再試行  ← ここが未読だった

+ が取得済み、* が要再試行、- が不良、? が未着手です。* が残っている間は終わっていません。


最後に

このダイアログだけでは、ディスクが壊れているとは判断できません。最近の macOS が HFS Standard を読めないだけなら、Mojave 以前の Mac か、冒頭の手順でデータを取り出せます。

読めないと言われても、まず疑うのはディスクではなく読み取り方の方でした。