Manipulating Disks and Volumes
In addition to watching for changes in volumes and refusing mount, unmount, and eject calls, the Disk Arbitration framework provides the ability to get various pieces of information about a volume, mount and unmount volumes, and so on. This chapter describes how to do this.
Obtaining a Disk Object
Before you can manipulate a disk or volume, you must obtain a DADiskRef object for that disk or volume. You can obtain a DADiskRef object in four ways:
As a parameter passed to your event callback (described in Using Disk Arbitration Notification and Approval Callbacks)
From an
io_service_tuser-space reference to anIOMediaobject for a valid device slice by callingDADiskCreateFromIOMediaYou can obtain an
io_service_tuser-space reference to anIOMediaobject by callingIOServiceGetMatchingServiceorIOServiceGetMatchingServices. To learn about working with the I/O Registry, read IOKit Fundamentals.From a BSD device name (
disk1s1, for example) usingDADiskCreateFromBSDNameFrom a mount point by calling
DADiskCreateFromVolumePath
If you have either an io_service_t object or a BSD device name, your app can create a DADiskRef object as follows:
Create a
DASessionRefobject as described in Creating a Session.Schedule it as described in Scheduling the Session with the Run Loop or Dispatch Queue. Be sure your dispatch queue or run loop is running.
Create the disk objects.
Manipulate them as desired.
Obtaining Information About a Disk
Disk arbitration provides three functions to get additional information about disks and partitions: DADiskCopyDescription, DADiskGetBSDName, and DADiskCopyIOMedia. As a rule, you can obtain almost any information about a particular disk by calling DADiskCopyDescription. For some fairly esoteric pieces of information, however, you may have to obtain an IOMedia object for the disk and query that object.
If you need the BSD device name of the disk or partition (
disk1s1, for example) as a C string (commonly used when working with POSIX-level APIs), callDADiskGetBSDName.For most other information, call
DADiskCopyDescription, as described in Obtaining a Description Dictionary.If the information you need is not available through
DADiskCopyDescription, callDADiskCopyIOMedia.
Obtaining a Description Dictionary
The DADiskCopyDescription method returns a CFDictionaryRef object containing several dozen pieces of information about a disk or partition. Some commonly used data includes:
Mount point and volume name
BSD device node name and major and minor numbers
Information about the hardware (device ID, vendor ID, GUID, and so on)
Connection info (bus name and path)
You can find a complete list of properties in the DADisk.h header in the Disk Arbitration Framework, along with a description of the expected data types for the values of each key.
For example, to print the mount point path for a volume:
DADiskRef disk; |
CFDictionaryRef *diskinfo; |
... |
diskinfo = DADiskCopyDescription(disk); |
CFURLRef fspath = CFDictionaryGetValue(dict, |
kDADiskDescriptionVolumePathKey); |
char buf[MAXPATHLEN]; |
if (CFURLGetFileSystemRepresentation(fspath, false, (UInt8 *)buf, sizeof(buf))) { |
printf("Disk %s mounted at %s\n", |
DADiskGetBSDName(disk), |
buf); |
/* Print the complete dictionary for debugging. */ |
CFShow(diskinfo); |
} else { |
/* Something is *really* wrong. */ |
} |
For a complete list of dictionary keys, see the Constants section in DADisk.h Reference.
Obtaining Additional Information from I/O Kit
In some rare situations, you may need to obtain additional information about a disk beyond what is available from Disk Arbitration. If you do, you can call DADiskCopyIOMedia to obtain an io_service_t object, which is the user-space representation of an IOMedia object. You can manipulate this object just as you would any I/O Registry object.
For example, you can obtain a Core Foundation dictionary with the media’s I/O Registry properties by calling IORegistryEntryCreateCFProperties on the resulting object.
The properties in an I/O Registry dictionary are defined in the I/O Kit Framework. For more information, see I/O Kit Framework Reference.
Mounting and Unmounting Volumes
To mount or unmount a volume, call DADiskMount or DADiskUnmount. If you care whether the mount or unmount was successful, you must also provide a callback to handle the result.
Alternatively, you can call DADiskMountWithArguments if you need to pass additional options to the mount command. This command takes a null-terminated array of CFStringRef values, each of which becomes an argument to the mount command. You can find the most common options in the manual page for mount. For additional volume-format-specific options, see the manual page for specific mount commands, such as mount_hfs.
For each of these functions, the callback function takes three parameters: a DADiskRef object, a DADissenterRef object, and a context pointer (passed as a parameter when you register the callback). If the operation was successful, the dissenter object is NULL. Otherwise, it provides information about why the operation failed.
For example, the following snippet unmounts a volume:
void unmount_done(DADiskRef disk, |
DADissenterRef dissenter, |
void *context); |
... |
DADiskUnmount(disk, kDADiskUnmountOptionDefault, |
unmount_done, NULL); |
... |
void unmount_done(DADiskRef disk, |
DADissenterRef dissenter, |
void *context) |
{ |
if (dissenter) { |
/* Unmount failed. */ |
char buf[MAXPATHLEN]; |
if (CFURLGetFileSystemRepresentation(fspath, false, (UInt8 *)buf, sizeof(buf))) { |
fprintf(stderr, "Unmount failed (Error: 0x%x Reason: %s). Retrying.\n", |
DADissenterGetStatus(dissenter), |
buf); |
} else { |
/* Something is *really* wrong. */ |
} |
} else { |
/* Do something. */ |
} |
} |
The most common error code values (errors specific to disk arbitration) are described in the DAReturn enumeration. However, this function can also potentially return any other error code in the mach_error_t space (UNIX errors, and so on).
Mounting a volume is similar except that you can specify a CFURLRef object with the mount point path (or pass NULL to mount the volume at the standard location). For example:
unsigned char *mppath = "/mnt/mydisk"; |
path = CFURLCreateFromFileSystemRepresentation( |
kCFAllocatorDefault, |
mppath, |
strlen(mppath), |
true); |
DADiskMountWithArguments(disk, path, kDADiskMountOptionDefault, |
mount_complete_callback, NULL, |
NULL); |
Ejecting a Disk
Ejecting a disk is similar to unmounting a volume. There are two key differences:
You can eject only a whole-disk partition (
/dev/disk0, for example), not a leaf partition (/dev/disk0s3, for example). If you are starting from a leaf partition, you must first obtain the whole disk partition that contains it.You must unmount all volumes on a disk before ejecting it. To ensure that all volumes are unmounted (if possible), first call
DADiskUnmount, passing the whole disk partition as the disk argument, and setting thekDADiskUnmountOptionWholeflag in the unmount options.
To get the whole disk partition that contains a given leaf partition, use DADiskCopyWholeDisk. For example:
DADiskRef wholedisk = DADiskCopyWholeDisk(disk); |
The following snippet, given a DADiskRef object associated with a single partition (called partition), unmounts all volumes on the underlying disk, then ejects the disk:
void unmount_done(DADiskRef disk, |
DADissenterRef dissenter, |
void *context); |
void eject_done(DADiskRef disk, |
DADissenterRef dissenter, |
void *context); |
... |
/* Unmount all volumes */ |
DADiskRef wholedisk = DADiskCopyWholeDisk(partition); |
DADiskUnmount(wholedisk, kDADiskUnmountOptionWhole, |
unmount_done, NULL); |
CFRelease(wholedisk); |
... |
/* In the unmount callback, eject the volume. */ |
void unmount_done(DADiskRef disk, |
DADissenterRef dissenter, |
void *context) |
{ |
if (dissenter) { |
... |
} else { |
DADiskEject(disk, kDADiskEjectOptionDefault, |
eject_done, NULL); |
} |
} |
/* Eject callback. */ |
void eject_done(DADiskRef disk, |
DADissenterRef dissenter, |
void *context) |
{ |
if (dissenter) { |
... |
} else { |
... |
} |
} |
Copyright © 2013 Apple Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2013-09-17