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