mcsheffrey
mcsheffrey

Reputation: 548

How can I prevent ejection of a disk during an operation on Mac OS X?

I have a long-running task that performs a series of file operations on mounted USB drives and I want to prevent users from ejecting the drive from Finder (or elsewhere) while this happens. There is a Cancel button that allows the task to be ended at any time.

I had assumed that keeping a file handle open on the mounted volume for the duration of the task would do the trick, but it hasn't worked.

This is what I tried (error handling removed):

NSString *tempFilePath = @"/Volumes/myVolume/.myTempFile";
if ([[NSFileManager defaultManager] fileExistsAtPath:tempFilePath] == NO) {
    [[NSFileManager defaultManager] createFileAtPath:tempFilePath contents:nil attributes:nil]
}

_tempFile = [NSFileHandle fileHandleForWritingAtPath:tempFilePath];

Any ideas about what I can do to ensure that the volume is prevented from ejecting?

Upvotes: 6

Views: 2226

Answers (2)

Kaelin Colclasure
Kaelin Colclasure

Reputation: 3975

You are looking for the Disk Arbitration (or DiskArb) framework APIs.

Upvotes: 0

bobDevil
bobDevil

Reputation: 29468

You'll need to use the Disk Arbitration API, more specifically the DARegisterDiskUnmountApprovalCallback.

You can create a DADiskRef via the functions avaliable in DADisk.h

When the callback is called, you can then decide whether you want to block the unmount or not. For a contrived example:

DADissenterRef myUnmountApprovalCallback(DADiskRef disk, void *context)
{
    DADissenterRef result = NULL; // NULL means approval
    if (stillWorking) {
        // This is released by the caller, according to the docs
        result = DADissenterCreate(kCFAllocatorDefault, kDAReturnBusy, CFSTR("<Your App> is busy writing to this device. Please cancel the operation first.");
    }
    return result;
}

As noted in the comments, this doesn't prevent anyone from just pulling the plug, but it will give you notification of explicit unmounts.

Upvotes: 10

Related Questions