Get a list of unmountable drives using Cocoa

cocoa, macos, objective-c, osx-lion

Solution

You can use `diskArbitration` framework.

#import <DiskArbitration/DiskArbitration.h>
   +(NSMutableArray *)getListOfEjectableMedia
{
    NSArray *mountedRemovableMedia = [[NSFileManager defaultManager] mountedVolumeURLsIncludingResourceValuesForKeys:nil options:NSVolumeEnumerationSkipHiddenVolumes];
    NSMutableArray *result = [NSMutableArray array];
    for(NSURL *volURL in mountedRemovableMedia)
    {
        int                 err = 0;
        DADiskRef           disk;
        DASessionRef        session;
        CFDictionaryRef     descDict;
        session = DASessionCreate(NULL);
        if (session == NULL) {
            err = EINVAL;
        }
        if (err == 0) {
            disk = DADiskCreateFromVolumePath(NULL,session,(CFURLRef)volURL);
            if (session == NULL) {
                err = EINVAL;
            }
        }
        if (err == 0) {
            descDict = DADiskCopyDescription(disk);
            if (descDict == NULL) {
                err = EINVAL;
            }
        }
        if (err == 0) {
            CFTypeRef mediaEjectableKey = CFDictionaryGetValue(descDict,kDADiskDescriptionMediaEjectableKey);
            CFTypeRef deviceProtocolName = CFDictionaryGetValue(descDict,kDADiskDescriptionDeviceProtocolKey);
            if (mediaEjectableKey != NULL)
            {
                BOOL op = CFEqual(mediaEjectableKey, CFSTR("0")) || CFEqual(deviceProtocolName, CFSTR("USB"));
                if (op) {
                    [result addObject:volURL];
                }
            }
        }
        if (descDict != NULL) {
            CFRelease(descDict);
        }
        if (disk != NULL) {
            CFRelease(disk);
        }
        if (session != NULL) {
            CFRelease(session);
        }
    }
    return result;
}

Update:

+ (NSMutableArray *)getListOfEjectableMedia {
    NSArray *mountedRemovableMedia = [[NSFileManager defaultManager] mountedVolumeURLsIncludingResourceValuesForKeys:nil options:NSVolumeEnumerationSkipHiddenVolumes];
    NSMutableArray *result = [NSMutableArray array];
    DASessionRef session = DASessionCreate(NULL); // Create the DASessionRef object outside the loop.
    for (NSURL *volURL in mountedRemovableMedia) {
        DADiskRef disk = DADiskCreateFromVolumePath(NULL, session, (__bridge CFURLRef)volURL); // Use the same session object for each disk.
        if (disk != NULL) {
            CFDictionaryRef descDict = DADiskCopyDescription(disk);
            if (descDict != NULL) {
                CFTypeRef mediaEjectableKey = CFDictionaryGetValue(descDict,kDADiskDescriptionMediaEjectableKey);
                CFTypeRef deviceProtocolName = CFDictionaryGetValue(descDict,kDADiskDescriptionDeviceProtocolKey);
                if (mediaEjectableKey != NULL) {
                    BOOL op = CFEqual(mediaEjectableKey, CFSTR("0")) || CFEqual(deviceProtocolName, CFSTR("USB"));
                    if (op) {
                        [result addObject:volURL];
                    }
                }
                CFRelease(descDict);
            }
            CFRelease(disk);
        }
    }
    CFRelease(session); // Release the DASessionRef object after the loop.
    return result;
}

Problem

I would like to obtain a list of drives that are unmountable/ejectable using Cocoa/Objective-C under OS X. I was hoping that NSWorkspace getFileSystemInfoForPath::::: would help me: ``` NSArray* listOfMedia = [[NSWorkspace sharedWorkspace] mountedLocalVolumePaths]; NSLog(@"%@", listOfMedia); for (NSString* volumePath in listOfMedia) { BOOL isRemovable = NO; BOOL isWritable = NO; BOOL isUnmountable = NO; NSString* description = [NSString string]; NSString* type = [NSString string]; BOOL result = [[NSWorkspace sharedWorkspace] getFileSystemInfoForPath:volumePath isRemovable:&isRemovable isWritable:&isWritable isUnmountable:&isUnmountable description:&description type:&type]; NSLog(@"Result:%i Volume: %@, Removable:%i, W:%i, Unmountable:%i, Desc:%@, type:%@", result, volumePath, isRemovable, isWritable, isUnmountable, description, type); } ``` Output: ``` ... Result:1 Volume: /Volumes/LR Photos, Removable:0, W:1, Unmountable:0, Desc:hfs, type:hfs ... ``` "LR Photos" is an external drive (connected via Thunderbolt) that should be removable and/or unmountable (or, at least I think it should be). :) Should I be going about this a different way? Thanks in advance!

Original source