6

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?

Quinn Taylor
  • 44,553
  • 16
  • 113
  • 131
mcsheffrey
  • 508
  • 4
  • 16
  • Don't want to burst your bubble, but what if someone just unplugs their USB drive? If the drive is hardware driven it's impossible to not prevent it to be ejected. Why can't you just give the user a very stern warning that they shouldn't eject the drive or else the operation will fail? – Jaime Garcia Sep 15 '10 at 18:22
  • I do realize that we can't completely prevent an inadvertent disconnect. As much as possible I'd like the user to be forced into the conscious decision to stop the operation so that they might understand why some functionality isn't working for them later. – mcsheffrey Sep 15 '10 at 18:27
  • @ferrari fan: what mcsheffrey wants is useful because the user might forget that this task is not finished and "retaining" the disk in some way would help with accidental ejects. – mohsenr Sep 15 '10 at 18:29
  • @ferrarifan if someone "just unplugs" their USB drive, Finder will present a scary alert message warning that some data might have been lost and never to do that again. – Abhi Beckert Dec 03 '12 at 22:41

2 Answers2

10

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.

bobDevil
  • 27,758
  • 3
  • 32
  • 30
0

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

Kaelin Colclasure
  • 3,925
  • 1
  • 26
  • 36