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_t
user-space reference to anIOMedia
object for a valid device slice by callingDADiskCreateFromIOMedia
You can obtain an
io_service_t
user-space reference to anIOMedia
object by callingIOServiceGetMatchingService
orIOServiceGetMatchingServices
. To learn about working with the I/O Registry, read IOKit Fundamentals.From a BSD device name (
disk1s1
, for example) usingDADiskCreateFromBSDName
From 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
DASessionRef
object 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 thekDADiskUnmountOptionWhole
flag 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