| 1 | // |
|---|
| 2 | // SUDiskImageUnarchiver.m |
|---|
| 3 | // Sparkle |
|---|
| 4 | // |
|---|
| 5 | // Created by Andy Matuschak on 6/16/08. |
|---|
| 6 | // Copyright 2008 Andy Matuschak. All rights reserved. |
|---|
| 7 | // |
|---|
| 8 | |
|---|
| 9 | #import "SUDiskImageUnarchiver.h" |
|---|
| 10 | #import "SUUnarchiver_Private.h" |
|---|
| 11 | #import "NTSynchronousTask.h" |
|---|
| 12 | |
|---|
| 13 | @implementation SUDiskImageUnarchiver |
|---|
| 14 | |
|---|
| 15 | + (BOOL)_canUnarchivePath:(NSString *)path |
|---|
| 16 | { |
|---|
| 17 | return [[path pathExtension] isEqualToString:@"dmg"]; |
|---|
| 18 | } |
|---|
| 19 | |
|---|
| 20 | - (void)start |
|---|
| 21 | { |
|---|
| 22 | [NSThread detachNewThreadSelector:@selector(_extractDMG) toTarget:self withObject:nil]; |
|---|
| 23 | } |
|---|
| 24 | |
|---|
| 25 | - (void)_extractDMG |
|---|
| 26 | { |
|---|
| 27 | NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; |
|---|
| 28 | BOOL mountedSuccessfully = NO; |
|---|
| 29 | |
|---|
| 30 | // get a unique mount point path |
|---|
| 31 | NSString *mountPoint = [@"/Volumes" stringByAppendingPathComponent:[[NSProcessInfo processInfo] globallyUniqueString]]; |
|---|
| 32 | |
|---|
| 33 | if ([[NSFileManager defaultManager] fileExistsAtPath:mountPoint]) goto reportError; |
|---|
| 34 | |
|---|
| 35 | // create mount point folder |
|---|
| 36 | [[NSFileManager defaultManager] createDirectoryAtPath:mountPoint attributes:nil]; |
|---|
| 37 | if (![[NSFileManager defaultManager] fileExistsAtPath:mountPoint]) goto reportError; |
|---|
| 38 | |
|---|
| 39 | NSArray* arguments = [NSArray arrayWithObjects:@"attach", archivePath, @"-mountpoint", mountPoint, @"-noverify", @"-nobrowse", @"-noautoopen", nil]; |
|---|
| 40 | // set up a pipe and push "yes" (y works too), this will accept any license agreement crap |
|---|
| 41 | // not every .dmg needs this, but this will make sure it works with everyone |
|---|
| 42 | NSData* yesData = [[[NSData alloc] initWithBytes:"yes\n" length:4] autorelease]; |
|---|
| 43 | |
|---|
| 44 | NSData *result = [NTSynchronousTask task:@"/usr/bin/hdiutil" directory:@"/" withArgs:arguments input:yesData]; |
|---|
| 45 | if (!result) goto reportError; |
|---|
| 46 | mountedSuccessfully = YES; |
|---|
| 47 | |
|---|
| 48 | // Now that we've mounted it, we need to copy out its contents. |
|---|
| 49 | NSString *targetPath = [[archivePath stringByDeletingLastPathComponent] stringByAppendingPathComponent:[mountPoint lastPathComponent]]; |
|---|
| 50 | if (![[NSFileManager defaultManager] createDirectoryAtPath:targetPath attributes:nil]) goto reportError; |
|---|
| 51 | |
|---|
| 52 | // We can't just copyPath: from the volume root because that always fails. Seems to be a bug. |
|---|
| 53 | id subpathEnumerator = [[[NSFileManager defaultManager] directoryContentsAtPath:mountPoint] objectEnumerator], currentSubpath; |
|---|
| 54 | while ((currentSubpath = [subpathEnumerator nextObject])) |
|---|
| 55 | { |
|---|
| 56 | NSString *currentFullPath = [mountPoint stringByAppendingPathComponent:currentSubpath]; |
|---|
| 57 | // Don't bother trying (and failing) to copy out files we can't read. That's not going to be the app anyway. |
|---|
| 58 | if (![[NSFileManager defaultManager] isReadableFileAtPath:currentFullPath]) continue; |
|---|
| 59 | if (![[NSFileManager defaultManager] copyPath:currentFullPath toPath:[targetPath stringByAppendingPathComponent:currentSubpath] handler:nil]) |
|---|
| 60 | goto reportError; |
|---|
| 61 | } |
|---|
| 62 | |
|---|
| 63 | [self performSelectorOnMainThread:@selector(_notifyDelegateOfSuccess) withObject:nil waitUntilDone:NO]; |
|---|
| 64 | goto finally; |
|---|
| 65 | |
|---|
| 66 | reportError: |
|---|
| 67 | [self performSelectorOnMainThread:@selector(_notifyDelegateOfFailure) withObject:nil waitUntilDone:NO]; |
|---|
| 68 | |
|---|
| 69 | finally: |
|---|
| 70 | if (mountedSuccessfully) |
|---|
| 71 | [NSTask launchedTaskWithLaunchPath:@"/usr/bin/hdiutil" arguments:[NSArray arrayWithObjects:@"detach", mountPoint, @"-force", nil]]; |
|---|
| 72 | else |
|---|
| 73 | [[NSFileManager defaultManager] removeFileAtPath:mountPoint handler:nil]; |
|---|
| 74 | [pool drain]; |
|---|
| 75 | } |
|---|
| 76 | |
|---|
| 77 | + (void)load |
|---|
| 78 | { |
|---|
| 79 | [self _registerImplementation:self]; |
|---|
| 80 | } |
|---|
| 81 | |
|---|
| 82 | @end |
|---|