1// Copyright 2014 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#include "chrome/utility/image_writer/disk_unmounter_mac.h" 6 7#include <sys/socket.h> 8#include <IOKit/storage/IOStorageProtocolCharacteristics.h> 9 10#include "base/message_loop/message_loop_proxy.h" 11#include "base/message_loop/message_pump_mac.h" 12#include "base/posix/eintr_wrapper.h" 13#include "chrome/utility/image_writer/error_messages.h" 14#include "chrome/utility/image_writer/image_writer.h" 15 16namespace image_writer { 17 18DiskUnmounterMac::DiskUnmounterMac() : cf_thread_("ImageWriterDiskArb") { 19 base::Thread::Options options; 20 options.message_pump_factory = base::Bind(&CreateMessagePump); 21 22 cf_thread_.StartWithOptions(options); 23} 24 25DiskUnmounterMac::~DiskUnmounterMac() { 26 if (disk_) 27 DADiskUnclaim(disk_); 28} 29 30void DiskUnmounterMac::Unmount(const std::string& device_path, 31 const base::Closure& success_continuation, 32 const base::Closure& failure_continuation) { 33 // Should only be used once. 34 DCHECK(!original_thread_.get()); 35 original_thread_ = base::MessageLoopProxy::current(); 36 success_continuation_ = success_continuation; 37 failure_continuation_ = failure_continuation; 38 39 cf_thread_.message_loop()->PostTask( 40 FROM_HERE, 41 base::Bind(&DiskUnmounterMac::UnmountOnWorker, 42 base::Unretained(this), 43 device_path)); 44} 45 46// static 47void DiskUnmounterMac::DiskClaimed(DADiskRef disk, 48 DADissenterRef dissenter, 49 void* context) { 50 DiskUnmounterMac* disk_unmounter = static_cast<DiskUnmounterMac*>(context); 51 52 if (dissenter) { 53 LOG(ERROR) << "Unable to claim disk."; 54 disk_unmounter->Error(); 55 return; 56 } 57 58 DADiskUnmount(disk, 59 kDADiskUnmountOptionForce | kDADiskUnmountOptionWhole, 60 DiskUnmounted, 61 disk_unmounter); 62} 63 64// static 65DADissenterRef DiskUnmounterMac::DiskClaimRevoked(DADiskRef disk, 66 void* context) { 67 CFStringRef reason = CFSTR( 68 "Hi. Sorry to bother you, but I'm busy overwriting the entire disk " 69 "here. There's nothing to claim but the smoldering ruins of bytes " 70 "that were in flash memory. Trust me, it's nothing that you want. " 71 "All the best. Toodles!"); 72 return DADissenterCreate(kCFAllocatorDefault, kDAReturnBusy, reason); 73} 74 75// static 76void DiskUnmounterMac::DiskUnmounted(DADiskRef disk, 77 DADissenterRef dissenter, 78 void* context) { 79 DiskUnmounterMac* disk_unmounter = static_cast<DiskUnmounterMac*>(context); 80 81 if (dissenter) { 82 LOG(ERROR) << "Unable to unmount disk."; 83 disk_unmounter->Error(); 84 return; 85 } 86 87 disk_unmounter->original_thread_->PostTask( 88 FROM_HERE, disk_unmounter->success_continuation_); 89} 90 91// static 92scoped_ptr<base::MessagePump> DiskUnmounterMac::CreateMessagePump() { 93 return scoped_ptr<base::MessagePump>(new base::MessagePumpCFRunLoop); 94} 95 96void DiskUnmounterMac::UnmountOnWorker(const std::string& device_path) { 97 DCHECK(cf_thread_.message_loop() == base::MessageLoop::current()); 98 99 session_.reset(DASessionCreate(NULL)); 100 101 DASessionScheduleWithRunLoop( 102 session_, CFRunLoopGetCurrent(), kCFRunLoopCommonModes); 103 104 disk_.reset(DADiskCreateFromBSDName( 105 kCFAllocatorDefault, session_, device_path.c_str())); 106 107 if (!disk_) { 108 LOG(ERROR) << "Unable to get disk reference."; 109 Error(); 110 return; 111 } 112 113 DADiskClaim(disk_, 114 kDADiskClaimOptionDefault, 115 DiskClaimRevoked, 116 this, 117 DiskClaimed, 118 this); 119} 120 121void DiskUnmounterMac::Error() { 122 original_thread_->PostTask(FROM_HERE, failure_continuation_); 123} 124 125} // namespace image_writer 126