1

I am trying to read the plain 2048 byte sized data sectors from a data CD on OS X.

But when I open a device such as "/dev/disk8", I get sectors of 2352 in size, with a 16 byte header before each sector's actual Mode1 data.

Even with the BSD tools such as hexdump this can be seen, when reading an older CD made by Apple:

$ hexdump -n 512 -C /dev/disk8
00000000  00 ff ff ff ff ff ff ff  ff ff ff 00 00 02 00 01  |................|
00000010  45 52 08 00 00 05 00 00  00 01 00 01 00 00 00 00  |ER..............|
00000020  00 04 00 00 00 10 00 05  00 01 00 00 00 1e 00 19  |................|
00000030  ff ff 00 00 00 41 00 05  07 01 00 00 00 4f 00 1f  |.....A.......O..|
00000040  f8 ff 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000050  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|

The actual sector's data starts here at offset 0x10 with "ER". But the "ER" should be at offset 0.

How can I make this work in my own application without having to remove the extra data in a separate step?

I looked at the various ioctl functions in "IOCDMediaBSDClient.h" and "IOCDTypes.h", but I could not find one that lets me specify that I want to get only the plain data content from the sectors.

I also believe that my existing code which I wrote about 15 years ago, was able to handle this as desired back then, but something has changed in OS X since then, breaking my old code. And now I cannot figure out how to fix that. That code uses ioctl with DKIOCCDREAD, with parameters sectorArea=kCDSectorAreaUser and sectorType=kCDSectorTypeMode1. But that gives me the 16 byte header just like a normal read call does, even though Mode1 means that I should be getting 2048 byte sectors without any headers, as far as I understand it.

Thomas Tempelmann
  • 11,045
  • 8
  • 74
  • 149
  • 1
    Have you tried using the `rdisk` device node instead of the `disk` node? (i.e. `/dev/rdisk8`) – pmdj Sep 21 '16 at 18:46
  • 1
    Oddly, `hexdump -n 512 -C /dev/rdisk8` gives an error ("Invalid argument"). But when I use open() on "rdisk", it works with the `ioctl` function. So, it turns out that nothing broke in my old code, I just messed up using the correct disk name (I had used rdisk originally but later changed it to disk because I saw no difference when accessing "normal" disks). Do you like to write a proper answer? Otherwise, I'll do it. – Thomas Tempelmann Sep 22 '16 at 08:46
  • Cool, glad that worked out OK. Happy to write an answer. :-) – pmdj Sep 22 '16 at 09:08
  • The reason hexdump -n 512 likely gives an error of "invalid argument" is that the read is not block aligned. You'll need to use a multiple of the block size. (possibly by piping via `dd bs=` if `hexdump` can't be persuaded to use a specific block size) – pmdj Sep 22 '16 at 09:22
  • `dd if=/dev/rdisk8 ibs=2352 obs=2048 count=1 | hexdump -C` works somewhat - it reads the CD sectors but doesn't convert them to 2048, and it also seems unable to skip over the first 16 byte of each 2352 byte sector, regardless. So, copying CD data sectors with a cmd like `dd` seems still not possible, but that's not really part of this question. – Thomas Tempelmann Sep 22 '16 at 09:39

1 Answers1

1

As established in the comments section, the answer seems to be to to use the character device (rdisk), not the block device (disk) node. The distinction is not well documented as far as I'm aware, and for hard drives and SSDs is actually quite small - in most cases you can use either. For optical discs it's significantly different, for whatever reason.

I looked into this some time ago, but I forget the details of it, unfortunately. If you're interested in this, you'll find the implementation in the "IOStorageFamily" and "IOCDStorageFamily" source code bundles on Apple's https://opensource.apple.com/ site.

The code files you're after are the ones relating to "BSD clients" - IOMediaBSDClient.cpp/.h in IOStorageFamily, and IOMediaBSDClient.cpp/.h for CDs specifically. The block ("disk") device's ioctls are first handled in dkioctl_bdev() and then forwarded on to the generic dkioctl(), which in turn calls the IOCDMediaBSDClient::ioctl() method. The character device ("rdisk") uses dkioctl_cdev() instead.

pmdj
  • 22,018
  • 3
  • 52
  • 103
  • It's also necessary to use the `ioctl(DKIOCCDREAD)` call to read from the disk, not `read()`, as the latter simply results in an error being returned. Which also means that one cannot use `hexdump` nor `dd` to copy data sectors from a CD, I guess. On the question disk vs rdisk - I had gotten the impression that rdisk circumvents the OS' disk block cache, whereas disk doesn't. Not sure on that, though. (See also http://superuser.com/a/631601/41872) – Thomas Tempelmann Sep 22 '16 at 09:26
  • 1
    Actually, this comment explains better what rdisk does (i.e. unbuffered access that may require proper aligning): http://superuser.com/a/892768/41872 – Thomas Tempelmann Sep 22 '16 at 09:44