I have a special disk image format (compressed and with extra information such as bad blocks) and would like to make that available as a block device (e.g. under /dev/rdisk
) in macOS.
I am looking for pointers on how to write a read-only block level userspace driver.
I believe I need to do this with IOKit, but the docs are quite sparse in that area, and provide no sample code for this as far as I can tell.
I've had a look at Amit Singh's Mac OS Internals, but that only goes about filerting existing blocks that get routed through the added driver. But I need to read the data from a separate file, i.e. I need to use the file system, and I also want to do this in a userspace app if possible because making a kext is both hard to debug and is getting deprecated now, too.
Ideally, this should work on current macOS versions, including 10.15, but I'd also be happy with a solution that only works on older macOS versions, starting at 10.6.
Maybe I am still misunderstanding some things here. I was under the impression that it was possible even before 10.15 to write userspace IOKit drivers. But maybe that's not possible with Block Storage devices? Any clarifications would be welcome. I feel quite lost.
Update June 22, 2020
I also asked the question on the OSXFUSE support forum, and got a negative reply there.
Maybe I am still misunderstanding some things here. I was under the impression that it was possible even before 10.15 to write userspace IOKit drivers.
This is a true statement, but it does not mean it's possible to write all types of drivers in userspace, even with 10.15. The confusion likely stems from the fact that "IOKit" is used to mean subtly different things in different contexts:
IOKit.framework
a.k.a. IOKitLib + various IOCFPlugins) These provide a view of the kernel's I/O Registry to user space programs, and allow them to perform certain interactions with IOKit objects. This is essentially limited to:
IOUserClient
subclasses, and only if the parent object specfically permits it.To answer the question of your specific case:
IOStorage
or one of its subclasses (typically IOBlockStorageDevice
).IOKit.framework
allows you to create user space drivers which will only be used by that user space process or other user space processes. It is therefore not possible to use it to create drivers that will be used by some part of the kernel. For example, it is not possible to create a block device driver which will be used by the kernel's VFS system.IOBlockStorageDevice
subclass, as well as a service which offers a user client interface for some user space process to connect to for creating instances of block devices, and which will handle the I/O requests for the device. This is a sort of analog to the FUSE mechanism which works at the VFS layer instead of the block layer.I'm not currently aware of an existing open source system that does this, but I haven't looked very hard. Especially for read-only access, it shouldn't be terribly hard to do if you know what you're doing, but it comes with the usual downsides of developing and distributing kexts.
Note that you could also use FUSE to open your disk image if the block device it represents hosts a file system you wish to mount, and a FUSE implementation for that file system exists.