【问题标题】:How to read plain data sectors (Mode1) from a CD on OS X如何在 OS X 上从 CD 读取纯数据扇区 (Mode1)
【发布时间】:2017-01-29 13:01:55
【问题描述】:

我正在尝试从 OS X 上的数据 CD 中读取 2048 字节大小的普通数据扇区。

但是当我打开诸如“/dev/disk8”之类的设备时,我得到大小为 2352 的扇区,每个扇区的实际 Mode1 数据之前有一个 16 字节的标头。

即使使用 hexdump 等 BSD 工具,在读取 Apple 制作的较旧 CD 时也可以看到:

$ 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  |................|

实际扇区的数据从偏移量 0x10 开始,带有“ER”。但是“ER”应该在偏移量 0 处。

如何在我自己的应用程序中进行这项工作,而无需在单独的步骤中删除额外的数据?

我查看了“IOCDMediaBSDClient.h”和“IOCDTypes.h”中的各种ioctl 函数,但我找不到一个可以让我指定我只想从扇区中获取纯数据内容的函数。

我也相信我大约 15 年前编写的现有代码当时能够按需要处理这个问题,但从那时起 OS X 发生了一些变化,破坏了我的旧代码。现在我无法弄清楚如何解决这个问题。该代码使用ioctlDKIOCCDREAD,参数sectorArea=kCDSectorAreaUsersectorType=kCDSectorTypeMode1。但这给了我 16 字节的标头,就像普通的 read 调用一样,尽管据我了解,模式 1 意味着我应该得到没有任何标头的 2048 字节扇区。

【问题讨论】:

  • 您是否尝试过使用rdisk 设备节点而不是disk 节点? (即/dev/rdisk8
  • 奇怪的是,hexdump -n 512 -C /dev/rdisk8 给出了一个错误(“无效参数”)。但是当我在“rdisk”上使用 open() 时,它可以与 ioctl 函数一起使用。所以,事实证明我的旧代码没有任何问题,我只是搞砸了使用正确的磁盘名称(我最初使用 rdisk 但后来将其更改为磁盘,因为我在访问“普通”磁盘时没有发现任何区别)。你喜欢写一个正确的答案吗?否则,我会做的。
  • 酷,很高兴一切顺利。很高兴写一个答案。 :-)
  • hexdump -n 512 可能给出“无效参数”错误的原因是读取不是块对齐的。您需要使用块大小的倍数。 (如果无法说服 hexdump 使用特定的块大小,则可能通过 dd bs= 管道)
  • dd if=/dev/rdisk8 ibs=2352 obs=2048 count=1 | hexdump -C 有点工作 - 它读取 CD 扇区但不会将它们转换为 2048,而且它似乎也无法跳过每个 2352 字节扇区的前 16 个字节,无论如何。因此,使用像dd 这样的 cmd 复制 CD 数据扇区似乎仍然是不可能的,但这并不是这个问题的一部分。

标签: macos disk iokit raw-disk


【解决方案1】:

如 cmets 部分所述,答案似乎是使用字符设备 (rdisk),而不是块设备 (disk) 节点。据我所知,这种区别没有得到很好的记录,而且对于硬盘驱动器和 SSD 实际上很小——在大多数情况下,您可以使用其中任何一种。对于光盘而言,无论出于何种原因,它都有很大的不同。

我前段时间研究过这个,但不幸的是我忘记了它的细节。如果您对此感兴趣,可以在 Apple 的 https://opensource.apple.com/ 网站上的“IOStorageFamily”和“IOCDStorageFamily”源代码包中找到实现。

您需要的代码文件是与“BSD 客户端”相关的代码文件 - IOStorageFamily 中的 IOMediaBSDClient.cpp/.h,以及专门用于 CD 的 IOMediaBSDClient.cpp/.h。块(“磁盘”)设备的 ioctl 首先在dkioctl_bdev() 中处理,然后转发到通用dkioctl(),后者又调用IOCDMediaBSDClient::ioctl() 方法。字符设备(“rdisk”)改用dkioctl_cdev()

【讨论】:

  • 还需要使用ioctl(DKIOCCDREAD) 调用从磁盘读取,而不是read(),因为后者只会导致返回错误。这也意味着不能使用hexdumpdd 从CD 复制数据扇区,我猜。关于磁盘与 rdisk 的问题 - 我的印象是 rdisk 绕过了操作系统的磁盘块缓存,而磁盘没有。不过,不确定。 (另见superuser.com/a/631601/41872
  • 实际上,这条评论更好地解释了 rdisk 的作用(即可能需要正确对齐的无缓冲访问):superuser.com/a/892768/41872
猜你喜欢
  • 1970-01-01
  • 2012-03-29
  • 2014-09-16
  • 1970-01-01
  • 2014-10-16
  • 1970-01-01
  • 2011-01-14
  • 2016-02-15
  • 2011-10-31
相关资源
最近更新 更多