Revert 168224 - Update V8 to version 3.15.4.
[chromium-blink-merge.git] / chrome / browser / system_monitor / volume_mount_watcher_win.cc
blob94c13ccb70a60e17b979cc2640425a2b9d628b61
1 // Copyright (c) 2012 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.
5 #include "chrome/browser/system_monitor/volume_mount_watcher_win.h"
7 #include <windows.h>
8 #include <dbt.h>
9 #include <fileapi.h>
11 #include "base/string_number_conversions.h"
12 #include "base/string_util.h"
13 #include "base/utf_string_conversions.h"
14 #include "chrome/browser/system_monitor/media_device_notifications_utils.h"
15 #include "chrome/browser/system_monitor/media_storage_util.h"
16 #include "content/public/browser/browser_thread.h"
18 using base::SystemMonitor;
19 using content::BrowserThread;
21 namespace {
23 const DWORD kMaxPathBufLen = MAX_PATH + 1;
25 bool IsRemovable(const char16* mount_point) {
26 if (GetDriveType(mount_point) != DRIVE_REMOVABLE)
27 return false;
29 // We don't consider floppy disks as removable, so check for that.
30 string16 device = mount_point;
31 if (EndsWith(device, L"\\", false))
32 device = device.substr(0, device.length() - 1);
33 char16 device_path[kMaxPathBufLen];
34 if (!QueryDosDevice(device.c_str(), device_path, kMaxPathBufLen))
35 return true;
36 return string16(device_path).find(L"Floppy") == string16::npos;
39 // Returns 0 if the devicetype is not volume.
40 uint32 GetVolumeBitMaskFromBroadcastHeader(LPARAM data) {
41 DEV_BROADCAST_VOLUME* dev_broadcast_volume =
42 reinterpret_cast<DEV_BROADCAST_VOLUME*>(data);
43 if (dev_broadcast_volume->dbcv_devicetype == DBT_DEVTYP_VOLUME)
44 return dev_broadcast_volume->dbcv_unitmask;
45 return 0;
48 FilePath DriveNumberToFilePath(int drive_number) {
49 DCHECK_LT(drive_number, 26);
50 string16 path(L"_:\\");
51 path[0] = L'A' + drive_number;
52 return FilePath(path);
55 // Returns true if |data| represents a logical volume structure.
56 bool IsLogicalVolumeStructure(LPARAM data) {
57 DEV_BROADCAST_HDR* broadcast_hdr =
58 reinterpret_cast<DEV_BROADCAST_HDR*>(data);
59 return broadcast_hdr != NULL &&
60 broadcast_hdr->dbch_devicetype == DBT_DEVTYP_VOLUME;
63 // Gets mass storage device information given a |device_path|. On success,
64 // returns true and fills in |device_location|, |unique_id|, |name| and
65 // |removable|.
66 // The following msdn blog entry is helpful for understanding disk volumes
67 // and how they are treated in Windows:
68 // http://blogs.msdn.com/b/adioltean/archive/2005/04/16/408947.aspx.
69 bool GetDeviceDetails(const FilePath& device_path, string16* device_location,
70 std::string* unique_id, string16* name, bool* removable) {
71 char16 mount_point[kMaxPathBufLen];
72 if (!GetVolumePathName(device_path.value().c_str(), mount_point,
73 kMaxPathBufLen)) {
74 return false;
76 if (device_location)
77 *device_location = string16(mount_point);
79 if (unique_id) {
80 char16 guid[kMaxPathBufLen];
81 if (!GetVolumeNameForVolumeMountPoint(mount_point, guid, kMaxPathBufLen))
82 return false;
83 // In case it has two GUID's (see above mentioned blog), do it again.
84 if (!GetVolumeNameForVolumeMountPoint(guid, guid, kMaxPathBufLen))
85 return false;
86 WideToUTF8(guid, wcslen(guid), unique_id);
89 if (name)
90 *name = device_path.LossyDisplayName();
92 if (removable)
93 *removable = IsRemovable(mount_point);
95 return true;
98 } // namespace
100 namespace chrome {
102 VolumeMountWatcherWin::VolumeMountWatcherWin() {
105 void VolumeMountWatcherWin::Init() {
106 // When VolumeMountWatcherWin is created, the message pumps are not running
107 // so a posted task from the constructor would never run. Therefore, do all
108 // the initializations here.
110 // This should call AddExistingDevicesOnFileThread. The call is disabled
111 // until a fix for http://crbug.com/155910 can land.
112 // BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, base::Bind(
113 // &VolumeMountWatcherWin::AddExistingDevicesOnFileThread, this));
116 bool VolumeMountWatcherWin::GetDeviceInfo(const FilePath& device_path,
117 string16* device_location, std::string* unique_id, string16* name,
118 bool* removable) {
119 return GetDeviceDetails(device_path, device_location, unique_id, name,
120 removable);
123 void VolumeMountWatcherWin::OnWindowMessage(UINT event_type, LPARAM data) {
124 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
125 switch (event_type) {
126 case DBT_DEVICEARRIVAL: {
127 if (IsLogicalVolumeStructure(data)) {
128 DWORD unitmask = GetVolumeBitMaskFromBroadcastHeader(data);
129 for (int i = 0; unitmask; ++i, unitmask >>= 1) {
130 if (!(unitmask & 0x01))
131 continue;
132 AddNewDevice(DriveNumberToFilePath(i));
135 break;
137 case DBT_DEVICEREMOVECOMPLETE: {
138 if (IsLogicalVolumeStructure(data)) {
139 DWORD unitmask = GetVolumeBitMaskFromBroadcastHeader(data);
140 for (int i = 0; unitmask; ++i, unitmask >>= 1) {
141 if (!(unitmask & 0x01))
142 continue;
143 HandleDeviceDetachEventOnUIThread(DriveNumberToFilePath(i).value());
146 break;
151 VolumeMountWatcherWin::~VolumeMountWatcherWin() {
154 std::vector<FilePath> VolumeMountWatcherWin::GetAttachedDevices() {
155 std::vector<FilePath> result;
156 char16 volume_name[kMaxPathBufLen];
157 HANDLE find_handle = FindFirstVolume(volume_name, kMaxPathBufLen);
158 if (find_handle == INVALID_HANDLE_VALUE)
159 return result;
161 while (true) {
162 char16 volume_path[kMaxPathBufLen];
163 DWORD return_count;
164 if (GetVolumePathNamesForVolumeName(volume_name, volume_path,
165 kMaxPathBufLen, &return_count)) {
166 if (IsRemovable(volume_path))
167 result.push_back(FilePath(volume_path));
168 } else {
169 DPLOG(ERROR);
171 if (!FindNextVolume(find_handle, volume_name, kMaxPathBufLen)) {
172 if (GetLastError() != ERROR_NO_MORE_FILES)
173 DPLOG(ERROR);
174 break;
178 FindVolumeClose(find_handle);
179 return result;
182 void VolumeMountWatcherWin::AddNewDevice(const FilePath& device_path) {
183 std::string unique_id;
184 string16 device_name;
185 bool removable;
186 if (!GetDeviceInfo(device_path, NULL, &unique_id, &device_name, &removable))
187 return;
189 if (!removable)
190 return;
192 BrowserThread::PostTask(
193 BrowserThread::FILE, FROM_HERE,
194 base::Bind(&VolumeMountWatcherWin::CheckDeviceTypeOnFileThread, this,
195 unique_id, device_name, device_path));
198 void VolumeMountWatcherWin::AddExistingDevicesOnFileThread() {
199 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
200 std::vector<FilePath> removable_devices = GetAttachedDevices();
201 for (size_t i = 0; i < removable_devices.size(); i++)
202 AddNewDevice(removable_devices[i]);
205 void VolumeMountWatcherWin::CheckDeviceTypeOnFileThread(
206 const std::string& unique_id, const string16& device_name,
207 const FilePath& device) {
208 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
210 MediaStorageUtil::Type type =
211 MediaStorageUtil::REMOVABLE_MASS_STORAGE_NO_DCIM;
212 if (IsMediaDevice(device.value()))
213 type = MediaStorageUtil::REMOVABLE_MASS_STORAGE_WITH_DCIM;
214 std::string device_id = MediaStorageUtil::MakeDeviceId(type, unique_id);
216 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, base::Bind(
217 &VolumeMountWatcherWin::HandleDeviceAttachEventOnUIThread, this,
218 device_id, device_name, device.value()));
221 void VolumeMountWatcherWin::HandleDeviceAttachEventOnUIThread(
222 const std::string& device_id, const string16& device_name,
223 const string16& device_location) {
224 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
226 device_ids_[device_location] = device_id;
227 SystemMonitor* monitor = SystemMonitor::Get();
228 if (monitor) {
229 monitor->ProcessRemovableStorageAttached(device_id, device_name,
230 device_location);
234 void VolumeMountWatcherWin::HandleDeviceDetachEventOnUIThread(
235 const string16& device_location) {
236 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
237 MountPointDeviceIdMap::const_iterator device_info =
238 device_ids_.find(device_location);
239 // If the devices isn't type removable (like a CD), it won't be there.
240 if (device_info == device_ids_.end())
241 return;
243 SystemMonitor* monitor = SystemMonitor::Get();
244 if (monitor)
245 monitor->ProcessRemovableStorageDetached(device_info->second);
246 device_ids_.erase(device_info);
249 } // namespace chrome