Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 207 lines (173 sloc) 6.978 kb
93ea93d @andymatuschak Fixes 236695
andymatuschak authored
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"
43a0a7d @uliwitness Merge of changes from SVN repository:
uliwitness authored
12 #import "SULog.h"
2fc1b66 @andymatuschak Fixing:
andymatuschak authored
13 #import <CoreServices/CoreServices.h>
43a0a7d @uliwitness Merge of changes from SVN repository:
uliwitness authored
14
93ea93d @andymatuschak Fixes 236695
andymatuschak authored
15 @implementation SUDiskImageUnarchiver
16
dab8a36 renamed all methods that start with underscore, since that's reserved by...
Sean McBride authored
17 + (BOOL)canUnarchivePath:(NSString *)path
93ea93d @andymatuschak Fixes 236695
andymatuschak authored
18 {
58a05e2 @andymatuschak Fixes 243533 (for real this time, I hope)
andymatuschak authored
19 return [[path pathExtension] isEqualToString:@"dmg"];
93ea93d @andymatuschak Fixes 236695
andymatuschak authored
20 }
21
d3f9758 @andymatuschak Delegated password prompting to the update driver.
andymatuschak authored
22 // Called on a non-main thread.
dab8a36 renamed all methods that start with underscore, since that's reserved by...
Sean McBride authored
23 - (void)extractDMG
d3f9758 @andymatuschak Delegated password prompting to the update driver.
andymatuschak authored
24 {
43a0a7d @uliwitness Merge of changes from SVN repository:
uliwitness authored
25
93ea93d @andymatuschak Fixes 236695
andymatuschak authored
26 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
d3f9758 @andymatuschak Delegated password prompting to the update driver.
andymatuschak authored
27
28 NSData *result = [NTSynchronousTask task:@"/usr/bin/hdiutil" directory:@"/" withArgs:[NSArray arrayWithObjects: @"isencrypted", archivePath, nil] input:NULL];
29 if([self isEncrypted:result] && [delegate respondsToSelector:@selector(unarchiver:requiresPasswordReturnedViaInvocation:)]) {
30 [self performSelectorOnMainThread:@selector(requestPasswordFromDelegate) withObject:nil waitUntilDone:NO];
31 } else {
32 [self extractDMGWithPassword:nil];
33 }
34
35 [pool release];
36 }
37
38 // Called on a non-main thread.
39 - (void)extractDMGWithPassword:(NSString *)password
40 {
41
42 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
43
93ea93d @andymatuschak Fixes 236695
andymatuschak authored
44 BOOL mountedSuccessfully = NO;
45
43a0a7d @uliwitness Merge of changes from SVN repository:
uliwitness authored
46 SULog(@"Extracting %@ as a DMG", archivePath);
47
93ea93d @andymatuschak Fixes 236695
andymatuschak authored
48 // get a unique mount point path
2fc1b66 @andymatuschak Fixing:
andymatuschak authored
49 NSString *mountPointName = nil;
50 NSString *mountPoint = nil;
51 FSRef tmpRef;
52 do
53 {
54 CFUUIDRef uuid = CFUUIDCreate(NULL);
d7774c0 performed a code review, specifically:
Sean McBride authored
55 if (uuid)
56 {
57 CFStringRef uuidString = CFUUIDCreateString(NULL, uuid);
756b37d code review of CFRelease usage, minor changes
Sean McBride authored
58 if (uuidString)
59 {
60 mountPoint = [@"/Volumes" stringByAppendingPathComponent:(NSString*)uuidString];
61 CFRelease(uuidString);
62 }
d7774c0 performed a code review, specifically:
Sean McBride authored
63 CFRelease(uuid);
64 }
2fc1b66 @andymatuschak Fixing:
andymatuschak authored
65 }
66 while (noErr == FSPathMakeRefWithOptions((UInt8 *)[mountPoint fileSystemRepresentation], kFSPathMakeRefDoNotFollowLeafSymlink, &tmpRef, NULL));
4ba453f @rudyrichter support for encrypted disk images
rudyrichter authored
67
d3f9758 @andymatuschak Delegated password prompting to the update driver.
andymatuschak authored
68 NSData *promptData = nil;
69 if (password) {
70 NSString *data = [NSString stringWithFormat:@"%@\nyes\n", password];
71 const char *bytes = [data cStringUsingEncoding:NSUTF8StringEncoding];
72 NSUInteger length = [data lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
73 promptData = [NSData dataWithBytes:bytes length:length];
4ba453f @rudyrichter support for encrypted disk images
rudyrichter authored
74 }
75 else
76 promptData = [NSData dataWithBytes:"yes\n" length:4];
77
d3f9758 @andymatuschak Delegated password prompting to the update driver.
andymatuschak authored
78 NSArray* arguments = [NSArray arrayWithObjects:@"attach", archivePath, @"-mountpoint", mountPoint, /*@"-noverify",*/ @"-nobrowse", @"-noautoopen", nil];
79
4ba453f @rudyrichter support for encrypted disk images
rudyrichter authored
80 NSData *output = nil;
81 NSInteger taskResult = -1;
82 @try
83 {
84 NTSynchronousTask* task = [[NTSynchronousTask alloc] init];
85
86 [task run:@"/usr/bin/hdiutil" directory:@"/" withArgs:arguments input:promptData];
87
88 taskResult = [task result];
89 output = [[[task output] copy] autorelease];
90 [task release];
91 }
d3f9758 @andymatuschak Delegated password prompting to the update driver.
andymatuschak authored
92 @catch (NSException *localException)
4ba453f @rudyrichter support for encrypted disk images
rudyrichter authored
93 {
94 goto reportError;
95 }
93ea93d @andymatuschak Fixes 236695
andymatuschak authored
96
4ba453f @rudyrichter support for encrypted disk images
rudyrichter authored
97 if (taskResult != 0)
43a0a7d @uliwitness Merge of changes from SVN repository:
uliwitness authored
98 {
99 NSString* resultStr = output ? [[[NSString alloc] initWithData: output encoding: NSUTF8StringEncoding] autorelease] : nil;
69d471a @andymatuschak Allow the user to try reentering his password if authentication fails.
andymatuschak authored
100 if (password != nil && [resultStr rangeOfString:@"Authentication error"].location != NSNotFound && [delegate respondsToSelector:@selector(unarchiver:requiresPasswordReturnedViaInvocation:)]) {
101 [self performSelectorOnMainThread:@selector(requestPasswordFromDelegate) withObject:nil waitUntilDone:NO];
102 goto finally;
103 } else {
104 SULog( @"hdiutil failed with code: %d data: <<%@>>", taskResult, resultStr );
105 goto reportError;
106 }
43a0a7d @uliwitness Merge of changes from SVN repository:
uliwitness authored
107 }
93ea93d @andymatuschak Fixes 236695
andymatuschak authored
108 mountedSuccessfully = YES;
109
110 // Now that we've mounted it, we need to copy out its contents.
613b759 @cocoabythefire Fixed issues that led to crashes on Mac OS X 10.7 Lion.
cocoabythefire authored
111 if (floor(NSAppKitVersionNumber) > NSAppKitVersionNumber10_5) {
112 // On 10.6 and later we don't want to use the File Manager API and instead want to use NSFileManager (fixes #827357).
5457476 @andymatuschak Fixes #109: Error extracting dmg archives
andymatuschak authored
113 NSFileManager *manager = [[[NSFileManager alloc] init] autorelease];
114 NSError *error = nil;
115 NSArray *contents = [manager contentsOfDirectoryAtPath:mountPoint error:&error];
116 if (error)
117 {
118 SULog(@"Couldn't enumerate contents of archive mounted at %@: %@", mountPoint, error);
119 goto reportError;
120 }
121
d092ae9 @andymatuschak Resolved merge
andymatuschak authored
122 NSEnumerator *contentsEnumerator = [contents objectEnumerator];
123 NSString *item;
124 while ((item = [contentsEnumerator nextObject]))
5457476 @andymatuschak Fixes #109: Error extracting dmg archives
andymatuschak authored
125 {
d092ae9 @andymatuschak Resolved merge
andymatuschak authored
126 NSString *fromPath = [mountPoint stringByAppendingPathComponent:item];
127 NSString *toPath = [[archivePath stringByDeletingLastPathComponent] stringByAppendingPathComponent:item];
5457476 @andymatuschak Fixes #109: Error extracting dmg archives
andymatuschak authored
128
55eed9e @andymatuschak Fixes #113: Need to check isReadableFileAtPath: when copying out DMG con...
andymatuschak authored
129 // We skip any files in the DMG which are not readable.
130 if (![manager isReadableFileAtPath:fromPath])
131 continue;
132
5457476 @andymatuschak Fixes #109: Error extracting dmg archives
andymatuschak authored
133 SULog(@"copyItemAtPath:%@ toPath:%@", fromPath, toPath);
134
135 if (![manager copyItemAtPath:fromPath toPath:toPath error:&error])
136 {
137 SULog(@"Couldn't copy item: %@", error);
138 goto reportError;
139 }
140 }
613b759 @cocoabythefire Fixed issues that led to crashes on Mac OS X 10.7 Lion.
cocoabythefire authored
141 }
142 else {
143 FSRef srcRef, dstRef;
144 OSStatus err;
145 err = FSPathMakeRef((UInt8 *)[mountPoint fileSystemRepresentation], &srcRef, NULL);
146 if (err != noErr) goto reportError;
147 err = FSPathMakeRef((UInt8 *)[[archivePath stringByDeletingLastPathComponent] fileSystemRepresentation], &dstRef, NULL);
148 if (err != noErr) goto reportError;
149
150 err = FSCopyObjectSync(&srcRef, &dstRef, (CFStringRef)mountPointName, NULL, kFSFileOperationSkipSourcePermissionErrors);
151 if (err != noErr) goto reportError;
152 }
93ea93d @andymatuschak Fixes 236695
andymatuschak authored
153
dab8a36 renamed all methods that start with underscore, since that's reserved by...
Sean McBride authored
154 [self performSelectorOnMainThread:@selector(notifyDelegateOfSuccess) withObject:nil waitUntilDone:NO];
93ea93d @andymatuschak Fixes 236695
andymatuschak authored
155 goto finally;
156
157 reportError:
dab8a36 renamed all methods that start with underscore, since that's reserved by...
Sean McBride authored
158 [self performSelectorOnMainThread:@selector(notifyDelegateOfFailure) withObject:nil waitUntilDone:NO];
93ea93d @andymatuschak Fixes 236695
andymatuschak authored
159
160 finally:
161 if (mountedSuccessfully)
dc249c1 @andymatuschak Fixes 246805
andymatuschak authored
162 [NSTask launchedTaskWithLaunchPath:@"/usr/bin/hdiutil" arguments:[NSArray arrayWithObjects:@"detach", mountPoint, @"-force", nil]];
43a0a7d @uliwitness Merge of changes from SVN repository:
uliwitness authored
163 else
164 SULog(@"Can't mount DMG %@",archivePath);
93ea93d @andymatuschak Fixes 236695
andymatuschak authored
165 [pool drain];
166 }
167
d726066 fixed warning by moving private methods higher in the source file
Sean McBride authored
168 - (void)start
169 {
dab8a36 renamed all methods that start with underscore, since that's reserved by...
Sean McBride authored
170 [NSThread detachNewThreadSelector:@selector(extractDMG) toTarget:self withObject:nil];
d726066 fixed warning by moving private methods higher in the source file
Sean McBride authored
171 }
172
93ea93d @andymatuschak Fixes 236695
andymatuschak authored
173 + (void)load
174 {
dab8a36 renamed all methods that start with underscore, since that's reserved by...
Sean McBride authored
175 [self registerImplementation:self];
93ea93d @andymatuschak Fixes 236695
andymatuschak authored
176 }
177
4ba453f @rudyrichter support for encrypted disk images
rudyrichter authored
178 - (BOOL)isEncrypted:(NSData*)resultData
179 {
180 BOOL result = NO;
181 if(resultData)
182 {
183 NSString *data = [NSString stringWithCString:(char*)[resultData bytes] encoding:NSUTF8StringEncoding];
184 if (!NSEqualRanges([data rangeOfString:@"passphrase-count"], NSMakeRange(NSNotFound, 0)))
185 {
186 result = YES;
187 }
188 }
189 return result;
190 }
191
d3f9758 @andymatuschak Delegated password prompting to the update driver.
andymatuschak authored
192 - (void)requestPasswordFromDelegate
193 {
194 NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[self methodSignatureForSelector:@selector(continueWithPassword:)]];
195 [invocation setSelector:@selector(continueWithPassword:)];
196 [invocation setTarget:self];
197 [invocation retainArguments];
198 [delegate unarchiver:self requiresPasswordReturnedViaInvocation:invocation];
199 }
200
201 - (void)continueWithPassword:(NSString *)password
202 {
203 [NSThread detachNewThreadSelector:@selector(extractDMGWithPassword:) toTarget:self withObject:password];
204 }
205
93ea93d @andymatuschak Fixes 236695
andymatuschak authored
206 @end
Something went wrong with that request. Please try again.