Implement HFS disk scavenging
If the system crashes while disk writes are pending on an HFS volume, the filesystem can be left in an inconsistent state. HFS sets a "was unmounted" flag in the MDB whenever it unmounts a volume cleanly. If the bit is not set when a volume is mounted, Mac OS performs "disk scavenging".
There are two aspects to this process:
- Use the list of extents to regenerate the block-in-use bitmaps and free block count.
- Identify the highest-numbered CNID and set the MDB's "next CNID" field.
Because these structures only matter when files are created or modified, the steps are not required when accessing a volume that is mounted read-only. This is not a full disk scan, and will not identify or correct other types of disk corruption.
The current implementation of HFS in CP2 does a full filesystem scan when the volume is opened, unless the --fast-scan option is used, in which case the scan is skipped completely. The "was unmounted" bit is not examined. The filesystem scan is a bit more thorough than scavenging, and will cause the volume to be mounted read-only if any inconsistencies are found. It does not attempt to correct them.
The new behavior should be:
- Do the scan when the volume is opened. If the "was unmounted" bit is not set, do the scan even if
--fast-scanis specified. - Rewrite the block use bitmaps and CNID values with what we compute.
- If other corruption is detected, discard any changes and mount the volume read-only.
It feels a little weird to be modifying the filesystem without being prompted to do so by the user, but this is what the operating system and hfsutils utilities do. The alternative is to have a separate "repair disk" feature that can be invoked manually by the user, either as a "do you want to fix this" pop-up or as a separate command / menu item.
It should be possible to generate "bad" filesystems for testing by crashing emulators while files are being modified, unless the emulators perform additional disk I/O caching (e.g. holding the entire disk image in memory).