Chromium Code Reviews| 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 |