I am trying to get a tree like structure of all volumes of my computer using Swift.
The simplest way to get all the mounted volumes is this code:
FileManager.default.mountedVolumeURLs(includingResourceValuesForKeys: nil)
Using this URL
, I can create a DADisk
object to get the BSD name:
if let session = DASessionCreate(kCFAllocatorDefault) {
if let disk = DADiskCreateFromVolumePath(kCFAllocatorDefault, session, url as CFURL) {
if let bsdName = DADiskGetBSDName(disk) {
volume.bsdName = String(cString : bsdName) // Volume is my own class.
}
}
}
Now for the "main" disk, I get "disk0". I want to get additional information about this disk. If I take a look at the Disk Utility, disk0 does not seem to do much, so I want to get all of the "sub" volumes of disk0. I tried to gather all disks, cut "disk" and then parse the remains number. Sometimes this works (if disk1 has sub volumes disk1s1 and disk1s2), but sometimes there is a root disk (let's call it disk2) and there is one (virtual?) Container. Underneath this container, there are additional disks called disk3 and disk3s1 (this is where my approach fails).
I have tried using IOKit
which prints all the disk names. However, I don't know how to build the tree like structure (I suppose I could hack something based on the path):
var iterator: io_iterator_t = 0
let matching: CFDictionary = IOServiceMatching(kIOServicePlane)
IOServiceGetMatchingServices(kIOMasterPortDefault, matching, &iterator)
var child: io_object_t = IOIteratorNext(iterator)
while child != 0
{
if let bsdName = IORegistryEntryCreateCFProperty(child, self.bsdNameKey as CFString, kCFAllocatorDefault, IOOptionBits(kIORegistryIterateRecursively))
{
Swift.print(bsdName)
}
child = IOIteratorNext(iterator)
}
Is there a reliable way to get a main disk and all of its volumes in some sort of hierarchy?
I managed to make a similar structure using an hacky and for now not very Sandbox-friendly way (it could be sandbox-friendly, continue reading for more info).
It's all based on the fact that the diskutil command actually returns a tree-like structure with all the details you might need about the disks present in a system, when you do the following terminal command: diskutil list -plist
So to use it to get a disk tree structure in my code i did the following:
I implemented a function using a Process Object to return the me the output of "diskutil list -plist" as a string (If you want to have your app sandbox-friendly, as far as i know, this part of the code needs to be inside an helper tool that needs to be embedded into your app's bundle)
I created some Codable structures and some protocols to go with them to have the plist string deserialised with minimum effort
I made my code perform some operations on the structure to have some stuff easyer to deal with like having APFS containers associated with their physical device into the tree-like structure
Copy-pasting all the code here will create a lot of mess (it's a lot of code), I prefer to link you the swift file in which I did most of this stuff in my open source project: https://github.com/ITzTravelInTime/TINU/blob/development/TINU/DiskutilListCodable.swift
Honestly i don't know what kind of dark magic the Diskutil executable uses to gather this info and generate the three structure, but for now it's the easyest way i foind to gather this info, i know that some developers (like the people working on some EFI Partition/ESP mounting tools) have managed to pull this off using system APIs, but i don't know how.