OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2016 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #import "Unpacker.h" | |
6 | |
7 #include <DiskArbitration/DiskArbitration.h> | |
8 #include <dispatch/dispatch.h> | |
9 | |
10 #import "Downloader.h" | |
11 | |
12 @interface Unpacker () { | |
13 DASessionRef session; | |
14 dispatch_queue_t unpack_dq; | |
15 | |
16 // TODO: narrow the scope for these variables | |
17 NSURL* temporaryDirectoryURL; | |
18 NSURL* temporaryDiskImageURL; | |
19 NSString* mountPath; | |
Sidney San Martín
2016/08/13 12:37:18
I believe instance variables should always have tr
Anna Zeng
2016/08/16 23:07:39
Done.
| |
20 } | |
21 @end | |
22 | |
23 @implementation Unpacker | |
24 | |
25 @synthesize delegate = delegate_; | |
26 @synthesize appPath = appPath_; | |
27 | |
28 // TODO: clean up error handling & pass up to appdelegate | |
29 static void unmount_callback(DADiskRef disk, | |
Sidney San Martín
2016/08/13 12:37:19
These functions should not be in the @implementati
Anna Zeng
2016/08/16 23:07:39
Done.
| |
30 DADissenterRef dissenter, | |
31 void* context) { | |
32 if (dissenter) { | |
Sidney San Martín
2016/08/13 12:37:19
There's a similar block of code in eject_callback.
Anna Zeng
2016/08/16 23:07:40
Done.
| |
33 DAReturn status = DADissenterGetStatus(dissenter); | |
34 if (unix_err(status)) { | |
35 int code = err_get_code(status); | |
36 NSLog(@"Unmount error code %d", code); | |
37 } | |
38 } else { | |
39 DADiskEject(disk, kDADiskEjectOptionDefault, eject_callback, context); | |
40 } | |
41 } | |
42 | |
43 static void eject_callback(DADiskRef disk, | |
44 DADissenterRef dissenter, | |
45 void* context) { | |
46 NSError* error = nil; | |
47 if (dissenter) { | |
48 DAReturn status = DADissenterGetStatus(dissenter); | |
49 if (unix_err(status)) { | |
50 int code = err_get_code(status); | |
51 NSLog(@"Eject error code %d", code); | |
52 error = [NSError | |
53 errorWithDomain:@"ChromeErrorDomain" | |
54 code:code | |
55 userInfo:@{ | |
56 NSLocalizedDescriptionKey : | |
57 (__bridge NSString*)DADissenterGetStatusString(dissenter) | |
58 }]; | |
59 } | |
60 } else { | |
61 Unpacker* unpacker = (__bridge Unpacker*)context; | |
62 [unpacker didFinishEjectingDisk:disk WithError:error]; | |
63 } | |
64 } | |
65 | |
66 // TODO: presumably we'd pass in the authenticated/unauthenticated path in here; | |
67 // however we will change this to a different model that will allow for a | |
68 // separate authenticated process to run | |
69 - (id)initWithFinalAppPath:(NSString*)appPath { | |
70 if ((self = [super init])) { | |
71 appPath_ = appPath; | |
72 } | |
73 return self; | |
74 } | |
75 | |
76 // TODO: the failure delegate methods need to be revised to be more meaningfully | |
77 // deal with the errors (pipe in stderr / stdout) | |
78 - (void)mountDMGFromURL:(NSURL*)fileURL { | |
79 NSError* error = nil; | |
80 temporaryDirectoryURL = [[NSFileManager defaultManager] | |
81 URLForDirectory:NSItemReplacementDirectory | |
82 inDomain:NSUserDomainMask | |
83 appropriateForURL:[NSURL fileURLWithPath:@"/" isDirectory:YES] | |
84 create:YES | |
85 error:&error]; | |
86 if (error) { | |
87 [delegate_ unpacker:self onMountFailure:nil]; | |
88 } | |
89 | |
90 temporaryDiskImageURL = | |
91 [temporaryDirectoryURL URLByAppendingPathComponent:@"GoogleChrome.dmg"]; | |
92 mountPath = [[temporaryDirectoryURL URLByAppendingPathComponent:@"mnt" | |
93 isDirectory:YES] path]; | |
94 [[NSFileManager defaultManager] createDirectoryAtPath:mountPath | |
95 withIntermediateDirectories:YES | |
96 attributes:nil | |
97 error:&error]; | |
98 if (error) { | |
99 [delegate_ unpacker:self onMountFailure:nil]; | |
100 } | |
101 | |
102 [[NSFileManager defaultManager] moveItemAtURL:fileURL | |
103 toURL:temporaryDiskImageURL | |
104 error:nil]; | |
105 | |
106 dispatch_semaphore_t mount_semaphore = dispatch_semaphore_create(0); | |
107 NSString* path = @"/usr/bin/hdiutil"; | |
108 NSArray* args = @[ | |
109 @"mount", temporaryDiskImageURL, @"-nobrowse", @"-mountpoint", mountPath | |
110 ]; | |
111 | |
112 NSTask* mountTask = [[NSTask alloc] init]; | |
113 mountTask.launchPath = path; | |
114 mountTask.arguments = args; | |
115 mountTask.terminationHandler = ^void(NSTask* task) { | |
116 // unpack_dq = dispatch_queue_create("com.google.chrome.unpack", | |
Elly Fong-Jones
2016/08/16 15:26:18
does this commented code need to be here?
Anna Zeng
2016/08/16 23:07:40
This code was not completely deleted in case I nee
| |
117 // DISPATCH_QUEUE_SERIAL); | |
118 // dispatch_async(unpack_dq, ^{ | |
119 dispatch_semaphore_signal(mount_semaphore); | |
120 // }); | |
121 }; | |
122 [mountTask launch]; | |
123 | |
124 dispatch_semaphore_wait(mount_semaphore, DISPATCH_TIME_FOREVER); | |
Elly Fong-Jones
2016/08/16 15:26:18
is this running on a work queue or somesuch? other
Anna Zeng
2016/08/16 23:07:40
Currently, it is not. Would you recommend running
| |
125 [delegate_ unpacker:self onMountSuccess:mountPath]; | |
126 } | |
127 | |
128 - (void)extractChrome { | |
129 NSString* diskAppPath = [[temporaryDirectoryURL | |
130 URLByAppendingPathComponent:@"mnt/Google Chrome.app" | |
131 isDirectory:YES] path]; | |
132 if (![[NSFileManager defaultManager] fileExistsAtPath:diskAppPath]) { | |
133 NSLog(@"File in DMG doesn't exist"); | |
134 [delegate_ unpacker:self onExtractFailure:appPath_]; | |
135 } | |
136 | |
137 // TODO: add progress | |
138 NSError* err; | |
139 if (![[NSFileManager defaultManager] copyItemAtPath:diskAppPath | |
140 toPath:appPath_ | |
141 error:&err]) { | |
142 NSLog(@"%@", err); | |
143 [delegate_ unpacker:self onExtractFailure:appPath_]; | |
144 } | |
145 [delegate_ unpacker:self onExtractSuccess:appPath_]; | |
146 } | |
147 | |
148 - (void)unmountDMG { | |
149 session = DASessionCreate(nil); | |
150 unpack_dq = | |
151 dispatch_queue_create("com.google.chrome.unpack", DISPATCH_QUEUE_SERIAL); | |
152 DASessionSetDispatchQueue(session, unpack_dq); | |
153 DADiskRef child_disk = DADiskCreateFromVolumePath( | |
154 nil, session, (CFURLRef)[NSURL URLWithString:mountPath]); | |
155 DADiskRef whole_disk = DADiskCopyWholeDisk(child_disk); | |
156 | |
157 DADiskUnmount(whole_disk, kDADiskUnmountOptionWhole, unmount_callback, | |
Sidney San Martín
2016/08/13 12:37:18
I might also pass `kDADiskUnmountOptionForce`. If
Anna Zeng
2016/08/16 23:07:40
Done.
| |
158 (void*)self); | |
159 | |
160 CFRelease(whole_disk); | |
161 CFRelease(child_disk); | |
162 } | |
163 | |
164 - (void)didFinishEjectingDisk:(DADiskRef)disk WithError:(NSError*)error { | |
165 DASessionSetDispatchQueue(session, NULL); | |
166 dispatch_release(unpack_dq); | |
167 if (error) { | |
168 [delegate_ unpacker:self onUnmountFailure:error]; | |
169 } else { | |
170 [delegate_ unpacker:self onUnmountSuccess:nil]; | |
171 } | |
172 } | |
173 | |
174 @end | |
OLD | NEW |