I have a task to implement disk formatting functionality in my code.
I am against the use of command line wrappers (e.g. diskutil
), as they are slow and unreliable.
I'm importing this private framework: /System/Library/PrivateFrameworks/DiskManagement.framework
And the following headers: DMManager.h, DMEraseDisk.h, DMFilesystem.h (GitHub Repo)
I have almost everything ready, but there is one problem that I can not overcome:
Calling the eraseDisk
method in DMEraseDisk
freezes the application.
At the same time, the disk is formatted successfully, I just need to mount it manually.
#import <Foundation/Foundation.h>
#import <DiskArbitration/DiskArbitration.h>
#import "DiskManagement/DMManager.h"
#import "DiskManagement/DMEraseDisk.h"
#import "DiskManagement/DMFilesystem.h"
int main(int argc, const char * argv[]) {
@autoreleasepool {
/* From the public DiskArbitration.h */
DASessionRef diskSession = DASessionCreate(nil);
DADiskRef currentDisk = DADiskCreateFromBSDName(NULL, diskSession, "disk9s1");
/* From DiskManagement.framework private headers (DMManager.h, DMEraseDisk.h, DMFilesystem.h) */
DMManager *dmManager = [DMManager sharedManager];
DMEraseDisk *diskEraser = [[DMEraseDisk alloc] initWithManager:dmManager];
/* Getting available file systems for a given device */
NSArray *availableFilesystems = [DMEraseDisk eraseTypesForDisk:currentDisk];
printf("Available File Systems for this device:\n");
for (DMFilesystem *availableFilesystem in availableFilesystems) {
printf("[Type:] %s\n", [[availableFilesystem filesystemType] UTF8String]);
printf("[Personality:] %s\n", [[availableFilesystem filesystemPersonality] UTF8String]);
printf("---\n");
}
/* (Type: msdos, Personality: MS-DOS FAT32) */
DMFilesystem *selectedFilesystem = [availableFilesystems objectAtIndex:2];
/*
(Formatting this device to MS-DOS FAT32)
Formats successfully, but stops here
and the code after this function is not executed further
*/
[diskEraser
eraseDisk: currentDisk
synchronous: YES // Won't work if set to NO (even with CFRunLoopRun())
filesystem: selectedFilesystem
bootable: YES
name: @"RESOPHIE"
doNewfs: YES
doBooterCleanup: NO
];
printf("I will never show up :(\n");
}
return 0;
}
How can I make the code continue to execute after calling eraseDisk
method?
I returned to solve the problem a year later.
I migrated to Swift for personal reasons. But the logic will be the same for Objective-C, if someone actually needs this.
The steps I have taken to solve the problem:
DiskManagement.framework
binary from Mac OS X Mavericks.(Newer versions of macOS moved away from binary frameworks, as I can see.)
eraseDisk:currentDisk:synchronous:filesystem:bootable:name:doNewfs:
method logic onDMManager
object.- (bool)checkClientDelegate;
(ifsynchronous == NO
).SwiftDiskManager
.diskManager.setDelegate(self)
anddiskManager.setClientDelegate(self)
in order to send all messages to theSwiftDiskManager
object.func responds(to aSelector: Selector!) -> Bool
method in order to track which methodsDMManager
is trying to access and then implemented them.- (bool)checkClientDelegate;
method.SwiftDiskManager.swift
main.swift
LanguageBridgingHeader.h
Console Output
Disk Utility
At the end, it works as expected, so the issue was solved.
Important notice: I made this class synchronous, but you're always free to remove the
CFRunLoop
and add your corrections.