Select the drive that was actually requested on macOS#330
Merged
Conversation
GetSCSITaskInterface() derives the BSD name from the drive argument but never
compares it against anything. The loop takes the first SCSITaskAuthoringDevice
IOKit hands out and breaks; the name is then used only for the
"diskutil unmountDisk" call. DiscImageCreator therefore unmounts the drive the
user asked for and dumps whichever drive happened to be enumerated first - it
runs to the end, reports no error, and writes files named after the requested
drive that hold the contents of a different disc.
Collect the authoring devices and pick the requested one out of them:
- By BSD name ("disk4") when a disc is loaded. The BSD name is not a property of
the SCSI peripheral device; it belongs to the IOMedia object that the block
storage stack publishes below it, so it has to be searched for recursively.
- By drive name ("PX-760A", "PLEXTOR", case insensitive) otherwise. macOS gives a
drive no BSD name while it holds no disc, so eject/close/start/stop would have
nothing left to address an empty drive by. The vendor and product from the
device characteristics are there either way. A name that fits more than one
drive is refused rather than guessed.
When nothing matches, report the drives that are there instead of falling back to
an arbitrary one, so the user can see what to ask for:
Not found the drive: disk1
Available drive:
disk4 PLEXTOR DVDR PX-760A
Unmount the drive that is about to be opened rather than the string that was
passed in. Unmounting the wrong drive left the opened one mounted, and
ObtainExclusiveAccess then failed with kIOReturnBusy.
Only the __APPLE__ branch is touched; Linux and Windows are unaffected.
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
On macOS,
GetSCSITaskInterface()(_linux/defineForLinux.cpp) derives the BSD name from the drive argument but never compares it against anything. The loop takes the firstSCSITaskAuthoringDeviceIOKit hands out and breaks; the name is then used only for thediskutil unmountDiskcall further down. DiscImageCreator unmounts the drive that was asked for and opens whichever drive happened to be enumerated first.The other platforms cannot do this.
GetHandle()opens the named device directly -CreateFile("\\\\.\\%c:")on Windows,open(pDevice->drivepath)on Linux - so the drive that was named is the drive that is used, and when it cannot be used the run fails on that drive. Only the macOS path enumerates, and it enumerates without looking at the name.The argument is unused, not merely mismatched
A drive name that exists nowhere on the machine:
Linux fails on the drive it was given. macOS opens a different one - here the USB Plextor.
What that costs
The test machine has two optical drives:
SCSITaskAuthoringDevicedisk1MPFTEST, 8.8 MB, one data trackdisk4PhotoCD Portfolio, 310.6 MB, data + audio trackAsking for
disk1on currentmasterunmountsdisk1, opens the Plextor, and then runs with no error and no warning. The files named afterdisk1describe a disc that is not indisk1:That is the mixed-mode PhotoCD sitting in
disk4. The disc indisk1is a single 8.8 MB data track.When the wrongly opened drive still holds a mounted volume the failure is loud but misleading instead:
ObtainExclusiveAccessreturnse00002d5(kIOReturnBusy) and the run aborts withGetLastError: 2, No such file or directory, because the unmount went to the drive that was not opened. A disc macOS cannot mount - audio, console, damaged - is never mounted, so in that case nothing stops the wrong dump.This does not make an unsupported drive dumpable
disk1is an emulated drive that macOS does not publish as aSCSITaskAuthoringDevice. It cannot be dumped, and it should not be. The problem is what happens instead of saying so. After this change DiscImageCreator does say so, and shows what is there:Which drives are supported and how they are dumped is untouched. Only the choice of which IOKit service gets opened changes.
Change
Collect the authoring devices and pick the requested one out of them, by BSD name when a disc is loaded and by drive name otherwise.
The BSD name is not a property of the SCSI peripheral device. It belongs to the
IOMediaobject that the block storage stack publishes below it, so it is searched for withIORegistryEntrySearchCFProperty()andkIORegistryIterateRecursivelyrather than read from the device node. This is the same lookup redumper uses on macOS.macOS assigns that name only while a disc is loaded, so it cannot address an empty drive - and
eject,close,startandstopneed exactly that. Vendor and product from the device characteristics are there with or without a disc, so they serve as the name in that case (PX-760A,PLEXTOR, case insensitive). A name that fits more than one drive is refused rather than guessed.diskutil unmountDisknow runs on the drive that is about to be opened rather than on the string that was passed in, and is skipped when that drive holds no disc.Before / after
disk1disk4(Plextor)Not found the drive: disk1, listsdisk4disk99disk4(Plextor)Not found the drive: disk99, listsdisk4disk4disk4disk4, dump runs (VendorId: PLEXTOR, TOC and disc info read)PX-760Adisk4by luckdisk4plextordisk4by luckdisk4With the disc ejected, so the drive has no BSD name at all:
disk4Not found the drive: disk4, lists(no disc) PLEXTOR DVDR PX-760APX-760Aclosecloses the trayTesting
macOS 26.5.2, x86_64, built with meson/ninja and Homebrew
libarchive+openssl@3. Real USB PLEXTOR PX-760A with a mixed-mode disc, plus a second optical drive that is not an authoring device. Every row of both tables above was run on that machine, and a fullcddump still reads the disc through the new selection.The machine has only one authoring device, so the case of two of them - where the first one enumerated wins and the second is unreachable - is not something I was able to run. What is shown above is the same defect from the other side: the name is never compared, so any name lands on the same drive.
Compiler warnings are unchanged (71 before, 71 after,
-Wall -Wextra). The patched tree also builds on Linux (Fedora, 0 warnings); only the__APPLE__branch is touched, so Linux and Windows are unaffected.Prepared with AI assistance (Claude Opus 4.8) and reviewed before submission.