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 | |
9 #import "Downloader.h" | |
10 | |
11 // TODO: make paths not depend on location of executable | |
12 // cocoa temporary folders: nstemporarydirectory | |
13 #define PATH_FROM_EXECUTABLE(x) \ | |
14 [[[[NSBundle mainBundle] bundlePath] stringByAppendingPathComponent:x] \ | |
15 stringByResolvingSymlinksInPath] | |
Sidney San Martín
2016/08/05 20:35:04
This should be a pretty quick change, any reason n
Anna Zeng
2016/08/05 21:48:40
I plan to include progress on this in the other re
| |
16 | |
17 @implementation Unpacker | |
18 | |
19 @synthesize delegate = delegate_; | |
20 | |
21 DASessionRef session; | |
22 | |
23 // TODO: make testing more convenient | |
24 | |
25 - (void)unpackDMG { | |
26 // TODO: how to find this from the PATH env variable? | |
27 NSString* path = @"/usr/bin/hdiutil"; | |
28 NSArray* args = @[ | |
29 // TODO: break getDownloadsFilePath out of the downloader file | |
30 @"mount", [Downloader getDownloadsFilePath], @"-nobrowse", @"-mountpoint", | |
31 PATH_FROM_EXECUTABLE(@"tmp") | |
32 ]; | |
33 | |
34 NSTask* unmountTask = [[NSTask alloc] init]; | |
35 unmountTask.launchPath = path; | |
36 unmountTask.arguments = args; | |
37 unmountTask.terminationHandler = ^void(NSTask* task) { | |
Mark Mentovai
2016/08/02 19:01:32
Aha! This is what’s causing all of the trouble wit
Anna Zeng
2016/08/02 23:58:22
Awesome! This helped immensely. I ended up using a
| |
38 [self extractChrome]; | |
39 }; | |
40 [unmountTask launch]; | |
41 } | |
42 | |
43 - (void)extractChrome { | |
44 NSLog(@"extracting chrome"); | |
45 NSFileManager* fileManager = [NSFileManager defaultManager]; | |
46 if (![fileManager | |
47 fileExistsAtPath:PATH_FROM_EXECUTABLE(@"tmp/Google Chrome.app")]) { | |
48 NSLog(@"File in DMG doesn't exist"); | |
49 } | |
50 | |
51 // TODO: make async | |
52 NSError* err; | |
53 if (![fileManager | |
54 copyItemAtPath:PATH_FROM_EXECUTABLE(@"tmp/Google Chrome.app") | |
55 toPath:@"/Applications/Google Chromo.app" | |
56 error:&err]) { | |
57 NSLog(@"%@", err); | |
58 } | |
59 | |
60 [self cleanUp]; | |
61 } | |
62 - (void)cleanUp { | |
63 NSFileManager* fileManager = [NSFileManager defaultManager]; | |
64 if ([fileManager removeItemAtPath:[Downloader getDownloadsFilePath] | |
65 error:nil]) { | |
66 NSLog(@"Disk image removed!"); | |
67 } | |
68 | |
69 // TODO: run the app instead of removing it every time | |
70 if ([fileManager removeItemAtPath:@"/Applications/Google Chromo.app" | |
71 error:nil]) { | |
72 NSLog(@"Application removed!"); | |
73 } | |
74 | |
75 session = DASessionCreate(nil); | |
76 DASessionScheduleWithRunLoop(session, CFRunLoopGetCurrent(), | |
77 kCFRunLoopCommonModes); | |
78 // TODO: how can we make the run loop run using the nsrunloop? | |
79 // DASessionScheduleWithRunLoop(session, [[NSRunLoop currentRunLoop] | |
80 // getCFRunLoop], | |
81 // (CFStringRef)NSDefaultRunLoopMode); | |
82 DADiskRef child_disk = DADiskCreateFromVolumePath( | |
83 nil, session, | |
84 (CFURLRef)[NSURL URLWithString:PATH_FROM_EXECUTABLE(@"tmp")]); | |
85 DADiskRef whole_disk = DADiskCopyWholeDisk(child_disk); | |
86 DADiskUnmount(whole_disk, kDADiskUnmountOptionWhole, unmount_callback, | |
87 (void*)self); | |
88 NSLog(@"Releasing disk"); | |
89 CFRelease(whole_disk); | |
90 CFRelease(child_disk); | |
91 | |
92 // TODO: when ivan's cr lands eliminate this bandaid | |
93 CFRunLoopRun(); | |
94 } | |
95 | |
96 void unmount_callback(DADiskRef disk, DADissenterRef dissenter, void* context) { | |
97 NSLog(@"reached unmount callback"); | |
98 if (dissenter) { | |
99 DAReturn status = DADissenterGetStatus(dissenter); | |
100 if (unix_err(status)) { | |
101 int code = err_get_code(status); | |
102 NSLog(@"Error code %d", code); | |
103 } | |
104 } else { | |
105 DADiskEject(disk, kDADiskEjectOptionDefault, eject_callback, context); | |
106 } | |
107 } | |
108 | |
109 void eject_callback(DADiskRef disk, DADissenterRef dissenter, void* context) { | |
110 NSLog(@"reached eject callback"); | |
111 if (dissenter) { | |
112 DAReturn status = DADissenterGetStatus(dissenter); | |
113 if (unix_err(status)) { | |
114 int code = err_get_code(status); | |
115 NSLog(@"Error code %d", code); | |
116 } | |
117 } | |
118 Unpacker* obj_self = (__bridge Unpacker*)context; | |
Sidney San Martín
2016/08/05 20:35:04
These functions aren't really part of Unpacker, so
Sidney San Martín
2016/08/05 21:13:40
You should also use `static` on these functions to
Anna Zeng
2016/08/05 21:48:40
Done.
Anna Zeng
2016/08/05 21:48:40
Done.
| |
119 [obj_self callbackFollowDisk:disk]; | |
Sidney San Martín
2016/08/05 20:35:04
Could you include error info in the callback?
Anna Zeng
2016/08/05 21:48:40
Done, with more progress to come!
| |
120 } | |
121 | |
122 - (void)callbackFollowDisk:(DADiskRef)disk { | |
123 NSLog(@"Unscheduling session"); | |
124 DASessionUnscheduleFromRunLoop( | |
125 session, CFRunLoopGetCurrent(), | |
126 kCFRunLoopCommonModes); // kCFRunLoopDefaultMode); | |
127 | |
128 [delegate_ onUnpackSuccess]; | |
129 } | |
130 | |
131 @end | |
OLD | NEW |