3

I'm trying to get a list of all ejectable disks using the Disk Arbitration framework. The problem is that the Ejectable property is always false (even when diskutil info says Ejectable: Yes). What's going on? Do I need to do a DADiskClaim first or something?

- (NSArray *)disks {
    NSMutableArray *disks = @[].mutableCopy;

    // Get a list of everything in /Volumes/
    NSArray *volumes = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:@"/Volumes/" error:NULL];

    DASessionRef session = DASessionCreate(kCFAllocatorDefault);

    // Use NSSet for easy object finding
    NSMutableSet *bsdNamesOfDisks = @[].mutableCopy;

    for (NSString *volume in volumes) {
        // Create the URL for the volume mount point
        NSURL *volumeURL = [NSURL URLWithString:[[NSString stringWithFormat:@"/Volumes/%@", volume] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];

        // Create DADisk for the volume
        DADiskRef volumeDisk = DADiskCreateFromVolumePath(kCFAllocatorDefault, session, (__bridge CFURLRef)volumeURL);

        // Filter out files/directories that aren't volumes
        if (volumeDisk) {
            // Get disk description
            NSDictionary *description = (__bridge_transfer NSDictionary *)DADiskCopyDescription(volumeDisk);

            // Get BSD name and ejectable property
            NSString *bsdName = description[(__bridge id)kDADiskDescriptionMediaBSDNameKey];
            CFBooleanRef ejectable = (__bridge CFBooleanRef)description[(__bridge id)kDADiskDescriptionMediaEjectableKey];

            // Check to see if this is a volume we're interested in
            if (bsdName && ejectable && CFBooleanGetValue(ejectable)) {
                // Deletes "disk" in "disk0s1" and separates the numbers
                NSArray *numbersInName = [[bsdName substringFromIndex:4] componentsSeparatedByCharactersInSet:[NSCharacterSet letterCharacterSet]];

                // Scan the first number
                NSScanner *scanner = [NSScanner scannerWithString:numbersInName[0]];

                NSInteger diskNumber;
                [scanner scanInteger:&diskNumber];

                // Construct BSD name for the whole disk
                NSString *bsdDiskName = [NSString stringWithFormat:@"disk%ld", diskNumber];

                // Check to see if we already added this disk to our array (e.g. disk0s1 and disk0s2 both give disk0)
                if (![bsdNamesOfDisks containsObject:bsdDiskName]) {
                    // Create DADisk for the whole disk
                    DADiskRef disk = DADiskCreateFromBSDName(kCFAllocatorDefault, session, bsdDiskName.UTF8String);

                    // Add DADisk to disk array and BSD name to name array
                    [disks addObject:(__bridge_transfer id)disk];
                    [bsdNamesOfDisks addObject:bsdDiskName];
                }
            }

            CFRelease(volumeDisk);
        }
    }

    CFRelease(session);

    return disks.copy;
}
fumoboy007
  • 5,345
  • 4
  • 32
  • 49
  • I ended up implementing this in a different (and better) way. I now check to see if the disk is external and whether the disk is physically or virtually attached (e.g. disk image or network share). I'm still curious though as to why DiskArbitration tells me a disk is not ejectable when diskutil tells me that it is. Any ideas? – fumoboy007 Dec 15 '12 at 05:12
  • 2
    “`NSMutableSet *bsdNamesOfDisks = @[].mutableCopy;`” First, `mutableCopy` isn't a property, so while this may work, it's dubious; second, `@[]` is not a set, so neither is a mutable copy of it. – Peter Hosey Dec 20 '12 at 18:39
  • 1. Oops...thanks =) (why wasn't this caught by the compiler??) 2. Oh sh*t...have I been doing it wrong this whole time...why didn't Apple make Xcode show only properties when I type '.'?!?!?!?! – fumoboy007 Jan 04 '13 at 19:21
  • possible duplicate of [How to identify a mounted device as removable?](http://stackoverflow.com/questions/16106878/how-to-identify-a-mounted-device-as-removable) – Monolo Apr 29 '13 at 11:08
  • 2
    Note that the dictionary key is about "removable media". This means the media can be removed from the drive, whether or not the drive itself can be removed from the system. Think floppy drives, optical drives, USB sticks, and SD cards. To detect removable drives I believe you have to check for internal vs external, though I haven't looked into that. – hippietrail Dec 14 '20 at 22:30

0 Answers0