Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(201)

Side by Side Diff: chrome/installer/mac/app/Unpacker.m

Issue 2203583002: Added unpacking step (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Addressed all comments, rearranged app logic, rewrote test, a bit more error handling Created 4 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(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 NSURL* temporaryDirectoryURL_;
17 NSString* mountPath_;
18 }
19 - (void)didFinishEjectingDisk:(DADiskRef)disk
20 WithDissenter:(DADissenterRef)dissenter;
Sidney San Martín 2016/08/17 22:09:06 W → w
Anna Zeng 2016/08/18 19:41:09 Done
21 @end
22
23 static void eject_callback(DADiskRef disk,
24 DADissenterRef dissenter,
25 void* context) {
26 Unpacker* unpacker = (__bridge Unpacker*)context;
27 [unpacker didFinishEjectingDisk:disk WithDissenter:dissenter];
28 }
29
30 static void unmount_callback(DADiskRef disk,
31 DADissenterRef dissenter,
32 void* context) {
33 if (dissenter) {
34 Unpacker* unpacker = (__bridge Unpacker*)context;
35 [unpacker didFinishEjectingDisk:disk WithDissenter:dissenter];
36 } else {
37 DADiskEject(disk, kDADiskEjectOptionDefault, eject_callback, context);
38 }
39 }
40
41 @implementation Unpacker
42
43 @synthesize delegate = delegate_;
44 @synthesize appPath = appPath_;
45
46 // TODO: presumably we'd pass in the authenticated/unauthenticated path in here;
47 // however we will change this to a different model that will allow for a
48 // separate authenticated process to run
49 - (id)initWithFinalAppPath:(NSString*)appPath {
50 if ((self = [super init])) {
51 appPath_ = appPath;
52 }
53 return self;
54 }
55
56 // TODO: the failure delegate methods need to be revised to be more meaningfully
57 // deal with the errors (pipe in stderr / stdout)
58 - (void)mountDMGFromURL:(NSURL*)fileURL {
59 NSError* error = nil;
60 temporaryDirectoryURL_ = [[NSFileManager defaultManager]
61 URLForDirectory:NSItemReplacementDirectory
62 inDomain:NSUserDomainMask
63 appropriateForURL:[NSURL fileURLWithPath:@"/" isDirectory:YES]
64 create:YES
65 error:&error];
66 if (error) {
67 if ([delegate_ respondsToSelector:@selector(unpacker:onMountFailure:)]) {
68 [delegate_ unpacker:self onMountFailure:error];
69 } else if ([delegate_ respondsToSelector:@selector(unpacker:onFailure:)]) {
70 [delegate_ unpacker:self onFailure:error];
71 } else {
72 NSLog(@"no methods to catch failure implemented");
73 }
74 }
75
76 NSURL* temporaryDiskImageURL =
77 [temporaryDirectoryURL_ URLByAppendingPathComponent:@"GoogleChrome.dmg"];
78 mountPath_ = [[temporaryDirectoryURL_ URLByAppendingPathComponent:@"mnt"
79 isDirectory:YES] path];
80 [[NSFileManager defaultManager] createDirectoryAtPath:mountPath_
81 withIntermediateDirectories:YES
82 attributes:nil
83 error:&error];
84 if (error) {
85 if ([delegate_ respondsToSelector:@selector(unpacker:onMountFailure:)]) {
86 [delegate_ unpacker:self onMountFailure:error];
87 } else if ([delegate_ respondsToSelector:@selector(unpacker:onFailure:)]) {
88 [delegate_ unpacker:self onFailure:error];
89 } else {
90 NSLog(@"no methods to catch failure implemented");
91 }
92 }
93
94 [[NSFileManager defaultManager] moveItemAtURL:fileURL
95 toURL:temporaryDiskImageURL
96 error:nil];
97
98 dispatch_semaphore_t mount_semaphore = dispatch_semaphore_create(0);
99 NSString* path = @"/usr/bin/hdiutil";
100 NSArray* args = @[
101 @"attach", temporaryDiskImageURL, @"-nobrowse", @"-mountpoint", mountPath_
102 ];
103
104 // TODO: how can we make sure this task quits if the user exits the app early?
105 NSTask* mountTask = [[NSTask alloc] init];
106 mountTask.launchPath = path;
107 mountTask.arguments = args;
108 mountTask.terminationHandler = ^void(NSTask* task) {
109 dispatch_semaphore_signal(mount_semaphore);
110 };
111 [mountTask launch];
112 dispatch_semaphore_wait(mount_semaphore, DISPATCH_TIME_FOREVER);
113
114 if ([delegate_ respondsToSelector:@selector(unpacker:onMountSuccess:)]) {
115 [delegate_ unpacker:self onMountSuccess:mountPath_];
116 } else {
117 [self extractChrome];
118 }
119 }
120
121 - (void)extractChrome {
122 NSString* diskAppPath =
123 [NSString pathWithComponents:@[ mountPath_, @"Google Chrome.app" ]];
124 if (![[NSFileManager defaultManager] fileExistsAtPath:diskAppPath]) {
125 NSLog(@"File in DMG doesn't exist");
126 [delegate_ unpacker:self onFailure:nil];
127 }
128
129 // TODO: add progress
130 NSError* error = nil;
131 if (![[NSFileManager defaultManager] copyItemAtPath:diskAppPath
132 toPath:appPath_
133 error:&error]) {
134 NSLog(@"%@", error);
135 [delegate_ unpacker:self onFailure:error];
136 } else {
137 [delegate_ unpacker:self onSuccess:appPath_];
138 }
139 }
140
141 - (void)unmountDMG {
142 session_ = DASessionCreate(nil);
143 unpack_dq_ =
144 dispatch_queue_create("com.google.chrome.unpack", DISPATCH_QUEUE_SERIAL);
145 DASessionSetDispatchQueue(session_, unpack_dq_);
146 DADiskRef child_disk = DADiskCreateFromVolumePath(
147 nil, session_,
148 (CFURLRef)[NSURL fileURLWithPath:mountPath_ isDirectory:YES]);
149 DADiskRef whole_disk = DADiskCopyWholeDisk(child_disk);
150
151 DADiskUnmount(whole_disk,
152 kDADiskUnmountOptionWhole | kDADiskUnmountOptionForce,
153 unmount_callback, (void*)self);
154
155 CFRelease(whole_disk);
156 CFRelease(child_disk);
157 }
158
159 - (void)didFinishEjectingDisk:(DADiskRef)disk
160 WithDissenter:(DADissenterRef)dissenter {
161 DASessionSetDispatchQueue(session_, NULL);
162 dispatch_release(unpack_dq_);
163 CFRelease(session_);
164 NSError* error = nil;
165 if (dissenter) {
166 DAReturn status = DADissenterGetStatus(dissenter);
167 error = [NSError
168 errorWithDomain:@"ChromeErrorDomain"
169 code:err_get_code(status)
170 userInfo:@{
171 NSLocalizedDescriptionKey :
172 (__bridge NSString*)DADissenterGetStatusString(dissenter)
173 }];
174 [delegate_ unpacker:self onUnmountFailure:error];
175 } else {
176 [[NSFileManager defaultManager] removeItemAtURL:temporaryDirectoryURL_
177 error:&error];
178 if (error) {
179 [delegate_ unpacker:self onUnmountFailure:error];
180 } else {
181 [delegate_ unpacker:self onUnmountSuccess:mountPath_];
182 }
183 }
184 }
185
186 @end
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698