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

Side by Side Diff: chrome/utility/image_writer/image_writer_mac.cc

Issue 294163008: Adds USB writing for OS X. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@list-devices
Patch Set: Cleanup in DiskUnmounterMac. Created 6 years, 6 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 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 <sys/socket.h>
6 #include <IOKit/storage/IOStorageProtocolCharacteristics.h>
7
8 #include "base/message_loop/message_loop_proxy.h"
9 #include "base/message_loop/message_pump_mac.h"
10 #include "base/posix/eintr_wrapper.h"
11 #include "chrome/utility/image_writer/disk_unmounter_mac.h"
12 #include "chrome/utility/image_writer/error_messages.h"
13 #include "chrome/utility/image_writer/image_writer.h"
14
15 namespace image_writer {
16
17 bool ImageWriter::IsValidDevice() {
18 base::ScopedCFTypeRef<DASessionRef> session(DASessionCreate(NULL));
19 DADiskRef disk = DADiskCreateFromBSDName(
20 kCFAllocatorDefault, session, device_path_.value().c_str());
21
22 if (!disk)
23 return false;
24
25 base::ScopedCFTypeRef<CFDictionaryRef> dict(DADiskCopyDescription(disk));
26
27 CFBooleanRef internal = base::mac::GetValueFromDictionary<CFBooleanRef>(
28 dict, kDADiskDescriptionDeviceInternalKey);
29 CFStringRef protocol = base::mac::GetValueFromDictionary<CFStringRef>(
30 dict, kDADiskDescriptionDeviceProtocolKey);
31 CFStringRef io_reg_path = base::mac::GetValueFromDictionary<CFStringRef>(
32 dict, kDADiskDescriptionDevicePathKey);
33 CFBooleanRef ejectable = base::mac::GetValueFromDictionary<CFBooleanRef>(
34 dict, kDADiskDescriptionMediaEjectableKey);
35 CFBooleanRef removable = base::mac::GetValueFromDictionary<CFBooleanRef>(
36 dict, kDADiskDescriptionMediaRemovableKey);
37 CFBooleanRef whole = base::mac::GetValueFromDictionary<CFBooleanRef>(
38 dict, kDADiskDescriptionMediaWholeKey);
39 CFStringRef kind = base::mac::GetValueFromDictionary<CFStringRef>(
40 dict, kDADiskDescriptionMediaKindKey);
41
42 // A drive is a USB stick iff:
43 // - it is not internal
44 // - it is attached to the USB bus
45 // - it is ejectable (because it will be ejected after written to)
46 // - it is removable
47 // - it is the whole drive (although the use of
48 // kDADiskDescriptionMatchMediaWhole should have ensured this)
49 // - it is of type IOMedia (external DVD drives and the like are IOCDMedia
50 // or
51 // IODVDMedia)
52 bool is_usb_stick =
53 !CFBooleanGetValue(internal) &&
54 CFEqual(protocol, CFSTR(kIOPropertyPhysicalInterconnectTypeUSB)) &&
55 CFBooleanGetValue(ejectable) && CFBooleanGetValue(removable) &&
56 CFBooleanGetValue(whole) &&
57 CFStringCompare(kind, CFSTR("IOMedia"), 0) == kCFCompareEqualTo;
58
59 // A drive is an SD card iff:
60 // - it is attached to the USB bus
61 // - it is ejectable (because it will be ejected after written to)
62 // - it is removable
63 // - it is the whole drive (although the use of
64 // kDADiskDescriptionMatchMediaWhole should have ensured this)
65 // - it is of type IOMedia (external DVD drives and the like are IOCDMedia
66 // or
67 // IODVDMedia)
68 // - the IORegistry device path contains "AppleUSBCardReader"
69 bool is_sd_card =
70 CFEqual(protocol, CFSTR(kIOPropertyPhysicalInterconnectTypeUSB)) &&
71 CFBooleanGetValue(ejectable) && CFBooleanGetValue(removable) &&
72 CFBooleanGetValue(whole) &&
73 CFStringCompare(kind, CFSTR("IOMedia"), 0) == kCFCompareEqualTo &&
74 CFStringFind(io_reg_path, CFSTR("AppleUSBCardReader"), 0).location !=
75 kCFNotFound;
76
77 return is_usb_stick || is_sd_card;
78 }
79
80 void ImageWriter::UnmountVolumes(const base::Closure& continuation) {
81 if (unmounter_ == NULL) {
82 unmounter_.reset(new DiskUnmounterMac(AsWeakPtr()));
83 }
84
85 unmounter_->Unmount(device_path_.value(), continuation);
86 }
87
88 bool ImageWriter::OpenDevice() {
89 int sockets[2]; // [parent's end, child's end]
90 int result = socketpair(AF_UNIX, SOCK_STREAM, 0, sockets);
91 if (result == -1) {
92 LOG(ERROR) << "Unable to allocate socket pair.";
93 return false;
94 }
95
96 char rdwr[10];
97 snprintf(rdwr, sizeof(rdwr), "%d", O_RDWR);
98
99 pid_t childPid = fork();
100 if (childPid == -1) {
101 LOG(ERROR) << "Fork failed.";
102 return false;
103 }
104
105 if (childPid == 0) { // child
106 HANDLE_EINTR(dup2(sockets[1], STDOUT_FILENO));
107 close(sockets[0]);
108 close(sockets[1]);
109
110 base::FilePath real_device_path;
111 if (device_path_.IsAbsolute()) {
112 real_device_path = device_path_;
113 } else {
114 real_device_path = base::FilePath("/dev").Append(device_path_);
115 }
116
117 const char authopenPath[] = "/usr/libexec/authopen";
118 execl(authopenPath,
119 authopenPath,
120 "-stdoutpipe",
121 "-o",
122 rdwr,
123 real_device_path.value().c_str(),
124 NULL);
125 _exit(errno);
126 } else { // parent
127 close(sockets[1]);
128 int fd = -1;
129
130 msghdr message = {0};
131 const size_t kDataBufferSize = 1024;
132 char dataBuffer[kDataBufferSize];
133 iovec ioVec[1];
134 ioVec[0].iov_base = dataBuffer;
135 ioVec[0].iov_len = kDataBufferSize;
136 message.msg_iov = ioVec;
137 message.msg_iovlen = 1;
138 const socklen_t kCmsgSocketSize = (socklen_t)CMSG_SPACE(sizeof(int));
139 char cmsgSocket[kCmsgSocketSize];
140 message.msg_control = cmsgSocket;
141 message.msg_controllen = kCmsgSocketSize;
142 ssize_t size = HANDLE_EINTR(recvmsg(sockets[0], &message, 0));
143 if (size > 0) {
144 cmsghdr* cmsgSocketHeader = CMSG_FIRSTHDR(&message);
145 // Paranoia.
146 if (cmsgSocketHeader && cmsgSocketHeader->cmsg_level == SOL_SOCKET &&
147 cmsgSocketHeader->cmsg_type == SCM_RIGHTS)
148 fd = *((int*)CMSG_DATA(cmsgSocketHeader));
149 }
150
151 int childStat;
152 result = HANDLE_EINTR(waitpid(childPid, &childStat, 0));
153 close(sockets[0]);
154
155 if (result != -1 && WIFEXITED(childStat)) {
156 int exitStatus = WEXITSTATUS(childStat);
157 if (exitStatus) {
158 LOG(ERROR) << "Child process returned failure.";
159 return false;
160 }
161 }
162
163 device_file_ = base::File(fd);
164
165 return device_file_.IsValid();
166 }
167 }
168
169 } // namespace image_writer
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698