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

Side by Side Diff: chrome/browser/storage_monitor/volume_mount_watcher_win.cc

Issue 16056002: Cleanup Various bits of Windows StorageMonitor classes. (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: Created 7 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 | Annotate | Revision Log
« no previous file with comments | « chrome/browser/storage_monitor/volume_mount_watcher_win.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/storage_monitor/volume_mount_watcher_win.h" 5 #include "chrome/browser/storage_monitor/volume_mount_watcher_win.h"
6 6
7 #include <windows.h> 7 #include <windows.h>
8 8
9 #include <dbt.h> 9 #include <dbt.h>
10 #include <fileapi.h> 10 #include <fileapi.h>
11 #include <winioctl.h> 11 #include <winioctl.h>
12 12
13 #include "base/bind_helpers.h" 13 #include "base/bind_helpers.h"
14 #include "base/metrics/histogram.h" 14 #include "base/metrics/histogram.h"
15 #include "base/stl_util.h" 15 #include "base/stl_util.h"
16 #include "base/string_util.h" 16 #include "base/string_util.h"
17 #include "base/stringprintf.h" 17 #include "base/stringprintf.h"
18 #include "base/strings/string_number_conversions.h" 18 #include "base/strings/string_number_conversions.h"
19 #include "base/task_runner_util.h" 19 #include "base/task_runner_util.h"
20 #include "base/time.h" 20 #include "base/time.h"
21 #include "base/utf_string_conversions.h" 21 #include "base/utf_string_conversions.h"
22 #include "base/win/scoped_handle.h" 22 #include "base/win/scoped_handle.h"
23 #include "chrome/browser/storage_monitor/media_storage_util.h" 23 #include "chrome/browser/storage_monitor/media_storage_util.h"
24 #include "chrome/browser/storage_monitor/storage_info.h" 24 #include "chrome/browser/storage_monitor/storage_info.h"
25 #include "content/public/browser/browser_thread.h" 25 #include "content/public/browser/browser_thread.h"
26 #include "content/public/browser/user_metrics.h" 26 #include "content/public/browser/user_metrics.h"
27 27
28 using content::BrowserThread; 28 using content::BrowserThread;
29 29
30 namespace chrome {
31
30 namespace { 32 namespace {
31 33
32 const DWORD kMaxPathBufLen = MAX_PATH + 1; 34 const DWORD kMaxPathBufLen = MAX_PATH + 1;
33 35
34 enum DeviceType { 36 enum DeviceType {
35 FLOPPY, 37 FLOPPY,
36 REMOVABLE, 38 REMOVABLE,
37 FIXED, 39 FIXED,
38 }; 40 };
39 41
40 // Histogram values for recording frequencies of eject attempts and 42 // Histogram values for recording frequencies of eject attempts and
41 // outcomes. 43 // outcomes.
42 enum EjectWinLockOutcomes { 44 enum EjectWinLockOutcomes {
43 LOCK_ATTEMPT, 45 LOCK_ATTEMPT,
44 LOCK_TIMEOUT, 46 LOCK_TIMEOUT,
45 LOCK_TIMEOUT2, 47 LOCK_TIMEOUT2,
46 NUM_LOCK_OUTCOMES, 48 NUM_LOCK_OUTCOMES,
47 }; 49 };
48 50
49 // We are trying to figure out whether the drive is a fixed volume, 51 // We are trying to figure out whether the drive is a fixed volume,
50 // a removable storage, or a floppy. A "floppy" here means "a volume we 52 // a removable storage, or a floppy. A "floppy" here means "a volume we
51 // want to basically ignore because it won't fit media and will spin 53 // want to basically ignore because it won't fit media and will spin
52 // if we touch it to get volume metadata." GetDriveType returns DRIVE_REMOVABLE 54 // if we touch it to get volume metadata." GetDriveType returns DRIVE_REMOVABLE
53 // on either floppy or removable volumes. The DRIVE_CDROM type is handled 55 // on either floppy or removable volumes. The DRIVE_CDROM type is handled
54 // as a floppy, as are DRIVE_UNKNOWN and DRIVE_NO_ROOT_DIR, as there are 56 // as a floppy, as are DRIVE_UNKNOWN and DRIVE_NO_ROOT_DIR, as there are
55 // reports that some floppy drives don't report as DRIVE_REMOVABLE. 57 // reports that some floppy drives don't report as DRIVE_REMOVABLE.
56 DeviceType GetDeviceType(const string16& mount_point) { 58 DeviceType GetDeviceType(const base::string16& mount_point) {
57 UINT drive_type = GetDriveType(mount_point.c_str()); 59 UINT drive_type = GetDriveType(mount_point.c_str());
58 if (drive_type == DRIVE_FIXED || drive_type == DRIVE_REMOTE || 60 if (drive_type == DRIVE_FIXED || drive_type == DRIVE_REMOTE ||
59 drive_type == DRIVE_RAMDISK) { 61 drive_type == DRIVE_RAMDISK) {
60 return FIXED; 62 return FIXED;
61 } 63 }
62 if (drive_type != DRIVE_REMOVABLE) 64 if (drive_type != DRIVE_REMOVABLE)
63 return FLOPPY; 65 return FLOPPY;
64 66
65 // Check device strings of the form "X:" and "\\.\X:" 67 // Check device strings of the form "X:" and "\\.\X:"
66 // For floppy drives, these will return strings like "/Device/Floppy0" 68 // For floppy drives, these will return strings like "/Device/Floppy0"
67 string16 device = mount_point; 69 base::string16 device = mount_point;
68 if (EndsWith(mount_point, L"\\", false)) 70 if (EndsWith(mount_point, L"\\", false))
69 device = mount_point.substr(0, mount_point.length() - 1); 71 device = mount_point.substr(0, mount_point.length() - 1);
70 string16 device_path; 72 base::string16 device_path;
71 string16 device_path_slash; 73 base::string16 device_path_slash;
72 DWORD dos_device = QueryDosDevice( 74 DWORD dos_device = QueryDosDevice(
73 device.c_str(), WriteInto(&device_path, kMaxPathBufLen), kMaxPathBufLen); 75 device.c_str(), WriteInto(&device_path, kMaxPathBufLen), kMaxPathBufLen);
74 string16 device_slash = string16(L"\\\\.\\"); 76 base::string16 device_slash = base::string16(L"\\\\.\\");
75 device_slash += device; 77 device_slash += device;
76 DWORD dos_device_slash = QueryDosDevice( 78 DWORD dos_device_slash = QueryDosDevice(
77 device_slash.c_str(), WriteInto(&device_path_slash, kMaxPathBufLen), 79 device_slash.c_str(), WriteInto(&device_path_slash, kMaxPathBufLen),
78 kMaxPathBufLen); 80 kMaxPathBufLen);
79 if (dos_device == 0 && dos_device_slash == 0) 81 if (dos_device == 0 && dos_device_slash == 0)
80 return FLOPPY; 82 return FLOPPY;
81 if (device_path.find(L"Floppy") != string16::npos || 83 if (device_path.find(L"Floppy") != base::string16::npos ||
82 device_path_slash.find(L"Floppy") != string16::npos) { 84 device_path_slash.find(L"Floppy") != base::string16::npos) {
83 return FLOPPY; 85 return FLOPPY;
84 } 86 }
85 87
86 return REMOVABLE; 88 return REMOVABLE;
87 } 89 }
88 90
89 // Returns 0 if the devicetype is not volume. 91 // Returns 0 if the devicetype is not volume.
90 uint32 GetVolumeBitMaskFromBroadcastHeader(LPARAM data) { 92 uint32 GetVolumeBitMaskFromBroadcastHeader(LPARAM data) {
91 DEV_BROADCAST_VOLUME* dev_broadcast_volume = 93 DEV_BROADCAST_VOLUME* dev_broadcast_volume =
92 reinterpret_cast<DEV_BROADCAST_VOLUME*>(data); 94 reinterpret_cast<DEV_BROADCAST_VOLUME*>(data);
93 if (dev_broadcast_volume->dbcv_devicetype == DBT_DEVTYP_VOLUME) 95 if (dev_broadcast_volume->dbcv_devicetype == DBT_DEVTYP_VOLUME)
94 return dev_broadcast_volume->dbcv_unitmask; 96 return dev_broadcast_volume->dbcv_unitmask;
95 return 0; 97 return 0;
96 } 98 }
97 99
98 // Returns true if |data| represents a logical volume structure. 100 // Returns true if |data| represents a logical volume structure.
99 bool IsLogicalVolumeStructure(LPARAM data) { 101 bool IsLogicalVolumeStructure(LPARAM data) {
100 DEV_BROADCAST_HDR* broadcast_hdr = 102 DEV_BROADCAST_HDR* broadcast_hdr =
101 reinterpret_cast<DEV_BROADCAST_HDR*>(data); 103 reinterpret_cast<DEV_BROADCAST_HDR*>(data);
102 return broadcast_hdr != NULL && 104 return broadcast_hdr != NULL &&
103 broadcast_hdr->dbch_devicetype == DBT_DEVTYP_VOLUME; 105 broadcast_hdr->dbch_devicetype == DBT_DEVTYP_VOLUME;
104 } 106 }
105 107
106 // Gets the total volume of the |mount_point| in bytes. 108 // Gets the total volume of the |mount_point| in bytes.
107 uint64 GetVolumeSize(const string16& mount_point) { 109 uint64 GetVolumeSize(const base::string16& mount_point) {
108 ULARGE_INTEGER total; 110 ULARGE_INTEGER total;
109 if (!GetDiskFreeSpaceExW(mount_point.c_str(), NULL, &total, NULL)) 111 if (!GetDiskFreeSpaceExW(mount_point.c_str(), NULL, &total, NULL))
110 return 0; 112 return 0;
111 return total.QuadPart; 113 return total.QuadPart;
112 } 114 }
113 115
114 // Gets mass storage device information given a |device_path|. On success, 116 // Gets mass storage device information given a |device_path|. On success,
115 // returns true and fills in |info|. 117 // returns true and fills in |info|.
116 // The following msdn blog entry is helpful for understanding disk volumes 118 // The following msdn blog entry is helpful for understanding disk volumes
117 // and how they are treated in Windows: 119 // and how they are treated in Windows:
118 // http://blogs.msdn.com/b/adioltean/archive/2005/04/16/408947.aspx. 120 // http://blogs.msdn.com/b/adioltean/archive/2005/04/16/408947.aspx.
119 bool GetDeviceDetails(const base::FilePath& device_path, 121 bool GetDeviceDetails(const base::FilePath& device_path, StorageInfo* info) {
120 chrome::StorageInfo* info) {
121 DCHECK(info); 122 DCHECK(info);
122 123
123 string16 mount_point; 124 base::string16 mount_point;
124 if (!GetVolumePathName(device_path.value().c_str(), 125 if (!GetVolumePathName(device_path.value().c_str(),
125 WriteInto(&mount_point, kMaxPathBufLen), 126 WriteInto(&mount_point, kMaxPathBufLen),
126 kMaxPathBufLen)) { 127 kMaxPathBufLen)) {
127 return false; 128 return false;
128 } 129 }
129 mount_point.resize(wcslen(mount_point.c_str())); 130 mount_point.resize(wcslen(mount_point.c_str()));
130 131
131 // Note: experimentally this code does not spin a floppy drive. It 132 // Note: experimentally this code does not spin a floppy drive. It
132 // returns a GUID associated with the device, not the volume. 133 // returns a GUID associated with the device, not the volume.
133 string16 guid; 134 base::string16 guid;
134 if (!GetVolumeNameForVolumeMountPoint(mount_point.c_str(), 135 if (!GetVolumeNameForVolumeMountPoint(mount_point.c_str(),
135 WriteInto(&guid, kMaxPathBufLen), 136 WriteInto(&guid, kMaxPathBufLen),
136 kMaxPathBufLen)) { 137 kMaxPathBufLen)) {
137 return false; 138 return false;
138 } 139 }
139 // In case it has two GUID's (see above mentioned blog), do it again. 140 // In case it has two GUID's (see above mentioned blog), do it again.
140 if (!GetVolumeNameForVolumeMountPoint(guid.c_str(), 141 if (!GetVolumeNameForVolumeMountPoint(guid.c_str(),
141 WriteInto(&guid, kMaxPathBufLen), 142 WriteInto(&guid, kMaxPathBufLen),
142 kMaxPathBufLen)) { 143 kMaxPathBufLen)) {
143 return false; 144 return false;
144 } 145 }
145 146
146 // If we're adding a floppy drive, return without querying any more 147 // If we're adding a floppy drive, return without querying any more
147 // drive metadata -- it will cause the floppy drive to seek. 148 // drive metadata -- it will cause the floppy drive to seek.
148 // Note: treats FLOPPY as FIXED_MASS_STORAGE. This is intentional. 149 // Note: treats FLOPPY as FIXED_MASS_STORAGE. This is intentional.
149 DeviceType device_type = GetDeviceType(mount_point); 150 DeviceType device_type = GetDeviceType(mount_point);
150 if (device_type == FLOPPY) { 151 if (device_type == FLOPPY) {
151 info->set_device_id(chrome::StorageInfo::MakeDeviceId( 152 info->set_device_id(StorageInfo::MakeDeviceId(
152 chrome::StorageInfo::FIXED_MASS_STORAGE, UTF16ToUTF8(guid))); 153 StorageInfo::FIXED_MASS_STORAGE, UTF16ToUTF8(guid)));
153 return true; 154 return true;
154 } 155 }
155 156
156 chrome::StorageInfo::Type type = chrome::StorageInfo::FIXED_MASS_STORAGE; 157 StorageInfo::Type type = StorageInfo::FIXED_MASS_STORAGE;
157 if (device_type == REMOVABLE) { 158 if (device_type == REMOVABLE) {
158 type = chrome::StorageInfo::REMOVABLE_MASS_STORAGE_NO_DCIM; 159 type = StorageInfo::REMOVABLE_MASS_STORAGE_NO_DCIM;
159 if (chrome::MediaStorageUtil::HasDcim(base::FilePath(mount_point))) 160 if (MediaStorageUtil::HasDcim(base::FilePath(mount_point)))
160 type = chrome::StorageInfo::REMOVABLE_MASS_STORAGE_WITH_DCIM; 161 type = StorageInfo::REMOVABLE_MASS_STORAGE_WITH_DCIM;
161 } 162 }
162 163
163 // NOTE: experimentally, this function returns false if there is no volume 164 // NOTE: experimentally, this function returns false if there is no volume
164 // name set. 165 // name set.
165 string16 volume_label; 166 base::string16 volume_label;
166 GetVolumeInformationW(device_path.value().c_str(), 167 GetVolumeInformationW(device_path.value().c_str(),
167 WriteInto(&volume_label, kMaxPathBufLen), 168 WriteInto(&volume_label, kMaxPathBufLen),
168 kMaxPathBufLen, NULL, NULL, NULL, NULL, 0); 169 kMaxPathBufLen, NULL, NULL, NULL, NULL, 0);
169 170
170 uint64 total_size_in_bytes = GetVolumeSize(mount_point); 171 uint64 total_size_in_bytes = GetVolumeSize(mount_point);
171 std::string device_id = 172 std::string device_id = StorageInfo::MakeDeviceId(type, UTF16ToUTF8(guid));
172 chrome::StorageInfo::MakeDeviceId(type, UTF16ToUTF8(guid));
173 173
174 // TODO(gbillock): if volume_label.empty(), get the vendor/model information 174 // TODO(gbillock): if volume_label.empty(), get the vendor/model information
175 // for the volume. 175 // for the volume.
176 *info = chrome::StorageInfo(device_id, string16(), mount_point, 176 *info = StorageInfo(device_id, base::string16(), mount_point,
177 volume_label, string16(), string16(), 177 volume_label, base::string16(), base::string16(),
178 total_size_in_bytes); 178 total_size_in_bytes);
179 return true; 179 return true;
180 } 180 }
181 181
182 // Returns a vector of all the removable mass storage devices that are 182 // Returns a vector of all the removable mass storage devices that are
183 // connected. 183 // connected.
184 std::vector<base::FilePath> GetAttachedDevices() { 184 std::vector<base::FilePath> GetAttachedDevices() {
185 std::vector<base::FilePath> result; 185 std::vector<base::FilePath> result;
186 string16 volume_name; 186 base::string16 volume_name;
187 HANDLE find_handle = FindFirstVolume(WriteInto(&volume_name, kMaxPathBufLen), 187 HANDLE find_handle = FindFirstVolume(WriteInto(&volume_name, kMaxPathBufLen),
188 kMaxPathBufLen); 188 kMaxPathBufLen);
189 if (find_handle == INVALID_HANDLE_VALUE) 189 if (find_handle == INVALID_HANDLE_VALUE)
190 return result; 190 return result;
191 191
192 while (true) { 192 while (true) {
193 string16 volume_path; 193 base::string16 volume_path;
194 DWORD return_count; 194 DWORD return_count;
195 if (GetVolumePathNamesForVolumeName(volume_name.c_str(), 195 if (GetVolumePathNamesForVolumeName(volume_name.c_str(),
196 WriteInto(&volume_path, kMaxPathBufLen), 196 WriteInto(&volume_path, kMaxPathBufLen),
197 kMaxPathBufLen, &return_count)) { 197 kMaxPathBufLen, &return_count)) {
198 result.push_back(base::FilePath(volume_path)); 198 result.push_back(base::FilePath(volume_path));
199 } 199 }
200 if (!FindNextVolume(find_handle, WriteInto(&volume_name, kMaxPathBufLen), 200 if (!FindNextVolume(find_handle, WriteInto(&volume_name, kMaxPathBufLen),
201 kMaxPathBufLen)) { 201 kMaxPathBufLen)) {
202 if (GetLastError() != ERROR_NO_MORE_FILES) 202 if (GetLastError() != ERROR_NO_MORE_FILES)
203 DPLOG(ERROR); 203 DPLOG(ERROR);
204 break; 204 break;
205 } 205 }
206 } 206 }
207 207
208 FindVolumeClose(find_handle); 208 FindVolumeClose(find_handle);
209 return result; 209 return result;
210 } 210 }
211 211
212 // Eject a removable volume at the specified |device| path. This works by 212 // Eject a removable volume at the specified |device| path. This works by
213 // 1) locking the volume, 213 // 1) locking the volume,
214 // 2) unmounting the volume, 214 // 2) unmounting the volume,
215 // 3) ejecting the volume. 215 // 3) ejecting the volume.
216 // If the lock fails, it will re-schedule itself. 216 // If the lock fails, it will re-schedule itself.
217 // See http://support.microsoft.com/kb/165721 217 // See http://support.microsoft.com/kb/165721
218 void EjectDeviceInThreadPool( 218 void EjectDeviceInThreadPool(
219 const base::FilePath& device, 219 const base::FilePath& device,
220 base::Callback<void(chrome::StorageMonitor::EjectStatus)> callback, 220 base::Callback<void(StorageMonitor::EjectStatus)> callback,
221 scoped_refptr<base::SequencedTaskRunner> task_runner, 221 scoped_refptr<base::SequencedTaskRunner> task_runner,
222 int iteration) { 222 int iteration) {
223 base::FilePath::StringType volume_name; 223 base::FilePath::StringType volume_name;
224 base::FilePath::CharType drive_letter = device.value()[0]; 224 base::FilePath::CharType drive_letter = device.value()[0];
225 // Don't try to eject if the path isn't a simple one -- we're not 225 // Don't try to eject if the path isn't a simple one -- we're not
226 // sure how to do that yet. Need to figure out how to eject volumes mounted 226 // sure how to do that yet. Need to figure out how to eject volumes mounted
227 // at not-just-drive-letter paths. 227 // at not-just-drive-letter paths.
228 if (drive_letter < L'A' || drive_letter > L'Z' || 228 if (drive_letter < L'A' || drive_letter > L'Z' ||
229 device != device.DirName()) { 229 device != device.DirName()) {
230 content::BrowserThread::PostTask( 230 BrowserThread::PostTask(
231 content::BrowserThread::UI, FROM_HERE, 231 BrowserThread::UI, FROM_HERE,
232 base::Bind(callback, chrome::StorageMonitor::EJECT_FAILURE)); 232 base::Bind(callback, StorageMonitor::EJECT_FAILURE));
233 return; 233 return;
234 } 234 }
235 base::SStringPrintf(&volume_name, L"\\\\.\\%lc:", drive_letter); 235 base::SStringPrintf(&volume_name, L"\\\\.\\%lc:", drive_letter);
236 236
237 base::win::ScopedHandle volume_handle(CreateFile( 237 base::win::ScopedHandle volume_handle(CreateFile(
238 volume_name.c_str(), 238 volume_name.c_str(),
239 GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, 239 GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE,
240 NULL, OPEN_EXISTING, 0, NULL)); 240 NULL, OPEN_EXISTING, 0, NULL));
241 241
242 if (!volume_handle.IsValid()) { 242 if (!volume_handle.IsValid()) {
243 content::BrowserThread::PostTask( 243 BrowserThread::PostTask(
244 content::BrowserThread::UI, FROM_HERE, 244 BrowserThread::UI, FROM_HERE,
245 base::Bind(callback, chrome::StorageMonitor::EJECT_FAILURE)); 245 base::Bind(callback, StorageMonitor::EJECT_FAILURE));
246 return; 246 return;
247 } 247 }
248 248
249 DWORD bytes_returned = 0; // Unused, but necessary for ioctl's. 249 DWORD bytes_returned = 0; // Unused, but necessary for ioctl's.
250 250
251 // Lock the drive to be ejected (so that other processes can't open 251 // Lock the drive to be ejected (so that other processes can't open
252 // files on it). If this fails, it means some other process has files 252 // files on it). If this fails, it means some other process has files
253 // open on the device. Note that the lock is released when the volume 253 // open on the device. Note that the lock is released when the volume
254 // handle is closed, and this is done by the ScopedHandle above. 254 // handle is closed, and this is done by the ScopedHandle above.
255 BOOL locked = DeviceIoControl(volume_handle, FSCTL_LOCK_VOLUME, 255 BOOL locked = DeviceIoControl(volume_handle, FSCTL_LOCK_VOLUME,
256 NULL, 0, NULL, 0, &bytes_returned, NULL); 256 NULL, 0, NULL, 0, &bytes_returned, NULL);
257 UMA_HISTOGRAM_ENUMERATION("StorageMonitor.EjectWinLock", 257 UMA_HISTOGRAM_ENUMERATION("StorageMonitor.EjectWinLock",
258 LOCK_ATTEMPT, NUM_LOCK_OUTCOMES); 258 LOCK_ATTEMPT, NUM_LOCK_OUTCOMES);
259 if (!locked) { 259 if (!locked) {
260 UMA_HISTOGRAM_ENUMERATION("StorageMonitor.EjectWinLock", 260 UMA_HISTOGRAM_ENUMERATION("StorageMonitor.EjectWinLock",
261 iteration == 0 ? LOCK_TIMEOUT : LOCK_TIMEOUT2, 261 iteration == 0 ? LOCK_TIMEOUT : LOCK_TIMEOUT2,
262 NUM_LOCK_OUTCOMES); 262 NUM_LOCK_OUTCOMES);
263 const int kNumLockRetries = 1; 263 const int kNumLockRetries = 1;
264 const base::TimeDelta kLockRetryInterval = 264 const base::TimeDelta kLockRetryInterval =
265 base::TimeDelta::FromMilliseconds(500); 265 base::TimeDelta::FromMilliseconds(500);
266 if (iteration < kNumLockRetries) { 266 if (iteration < kNumLockRetries) {
267 // Try again -- the lock may have been a transient one. This happens on 267 // Try again -- the lock may have been a transient one. This happens on
268 // things like AV disk lock for some reason, or another process 268 // things like AV disk lock for some reason, or another process
269 // transient disk lock. 269 // transient disk lock.
270 task_runner->PostDelayedTask(FROM_HERE, 270 task_runner->PostDelayedTask(
271 FROM_HERE,
271 base::Bind(&EjectDeviceInThreadPool, 272 base::Bind(&EjectDeviceInThreadPool,
272 device, callback, task_runner, iteration + 1), 273 device, callback, task_runner, iteration + 1),
273 kLockRetryInterval); 274 kLockRetryInterval);
274 return; 275 return;
275 } 276 }
276 277
277 content::BrowserThread::PostTask( 278 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
278 content::BrowserThread::UI, FROM_HERE, 279 base::Bind(callback, StorageMonitor::EJECT_IN_USE));
279 base::Bind(callback, chrome::StorageMonitor::EJECT_IN_USE));
280 return; 280 return;
281 } 281 }
282 282
283 // Unmount the device from the filesystem -- this will remove it from 283 // Unmount the device from the filesystem -- this will remove it from
284 // the file picker, drive enumerations, etc. 284 // the file picker, drive enumerations, etc.
285 BOOL dismounted = DeviceIoControl(volume_handle, FSCTL_DISMOUNT_VOLUME, 285 BOOL dismounted = DeviceIoControl(volume_handle, FSCTL_DISMOUNT_VOLUME,
286 NULL, 0, NULL, 0, &bytes_returned, NULL); 286 NULL, 0, NULL, 0, &bytes_returned, NULL);
287 287
288 // Reached if we acquired a lock, but could not dismount. This might 288 // Reached if we acquired a lock, but could not dismount. This might
289 // occur if another process unmounted without locking. Call this OK, 289 // occur if another process unmounted without locking. Call this OK,
290 // since the volume is now unreachable. 290 // since the volume is now unreachable.
291 if (!dismounted) { 291 if (!dismounted) {
292 DeviceIoControl(volume_handle, FSCTL_UNLOCK_VOLUME, 292 DeviceIoControl(volume_handle, FSCTL_UNLOCK_VOLUME,
293 NULL, 0, NULL, 0, &bytes_returned, NULL); 293 NULL, 0, NULL, 0, &bytes_returned, NULL);
294 content::BrowserThread::PostTask( 294 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
295 content::BrowserThread::UI, FROM_HERE, 295 base::Bind(callback, StorageMonitor::EJECT_OK));
296 base::Bind(callback, chrome::StorageMonitor::EJECT_OK));
297 return; 296 return;
298 } 297 }
299 298
300 PREVENT_MEDIA_REMOVAL pmr_buffer; 299 PREVENT_MEDIA_REMOVAL pmr_buffer;
301 pmr_buffer.PreventMediaRemoval = FALSE; 300 pmr_buffer.PreventMediaRemoval = FALSE;
302 // Mark the device as safe to remove. 301 // Mark the device as safe to remove.
303 if (!DeviceIoControl(volume_handle, IOCTL_STORAGE_MEDIA_REMOVAL, 302 if (!DeviceIoControl(volume_handle, IOCTL_STORAGE_MEDIA_REMOVAL,
304 &pmr_buffer, sizeof(PREVENT_MEDIA_REMOVAL), 303 &pmr_buffer, sizeof(PREVENT_MEDIA_REMOVAL),
305 NULL, 0, &bytes_returned, NULL)) { 304 NULL, 0, &bytes_returned, NULL)) {
306 content::BrowserThread::PostTask( 305 BrowserThread::PostTask(
307 content::BrowserThread::UI, FROM_HERE, 306 BrowserThread::UI, FROM_HERE,
308 base::Bind(callback, chrome::StorageMonitor::EJECT_FAILURE)); 307 base::Bind(callback, StorageMonitor::EJECT_FAILURE));
309 return; 308 return;
310 } 309 }
311 310
312 // Physically eject or soft-eject the device. 311 // Physically eject or soft-eject the device.
313 if (!DeviceIoControl(volume_handle, IOCTL_STORAGE_EJECT_MEDIA, 312 if (!DeviceIoControl(volume_handle, IOCTL_STORAGE_EJECT_MEDIA,
314 NULL, 0, NULL, 0, &bytes_returned, NULL)) { 313 NULL, 0, NULL, 0, &bytes_returned, NULL)) {
315 content::BrowserThread::PostTask( 314 BrowserThread::PostTask(
316 content::BrowserThread::UI, FROM_HERE, 315 BrowserThread::UI, FROM_HERE,
317 base::Bind(callback, chrome::StorageMonitor::EJECT_FAILURE)); 316 base::Bind(callback, StorageMonitor::EJECT_FAILURE));
318 return; 317 return;
319 } 318 }
320 319
321 content::BrowserThread::PostTask( 320 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
322 content::BrowserThread::UI, FROM_HERE, 321 base::Bind(callback, StorageMonitor::EJECT_OK));
323 base::Bind(callback, chrome::StorageMonitor::EJECT_OK));
324 } 322 }
325 323
326 } // namespace 324 } // namespace
327 325
328 namespace chrome {
329
330 const int kWorkerPoolNumThreads = 3; 326 const int kWorkerPoolNumThreads = 3;
331 const char* kWorkerPoolNamePrefix = "DeviceInfoPool"; 327 const char* kWorkerPoolNamePrefix = "DeviceInfoPool";
332 328
333 VolumeMountWatcherWin::VolumeMountWatcherWin() 329 VolumeMountWatcherWin::VolumeMountWatcherWin()
334 : device_info_worker_pool_(new base::SequencedWorkerPool( 330 : device_info_worker_pool_(new base::SequencedWorkerPool(
335 kWorkerPoolNumThreads, kWorkerPoolNamePrefix)), 331 kWorkerPoolNumThreads, kWorkerPoolNamePrefix)),
336 weak_factory_(this), 332 weak_factory_(this),
337 notifications_(NULL) { 333 notifications_(NULL) {
338 task_runner_ = 334 task_runner_ =
339 device_info_worker_pool_->GetSequencedTaskRunnerWithShutdownBehavior( 335 device_info_worker_pool_->GetSequencedTaskRunnerWithShutdownBehavior(
340 device_info_worker_pool_->GetSequenceToken(), 336 device_info_worker_pool_->GetSequenceToken(),
341 base::SequencedWorkerPool::CONTINUE_ON_SHUTDOWN); 337 base::SequencedWorkerPool::CONTINUE_ON_SHUTDOWN);
342 } 338 }
343 339
344 // static 340 // static
345 base::FilePath VolumeMountWatcherWin::DriveNumberToFilePath(int drive_number) { 341 base::FilePath VolumeMountWatcherWin::DriveNumberToFilePath(int drive_number) {
346 if (drive_number < 0 || drive_number > 25) 342 if (drive_number < 0 || drive_number > 25)
347 return base::FilePath(); 343 return base::FilePath();
348 string16 path(L"_:\\"); 344 base::string16 path(L"_:\\");
349 path[0] = L'A' + drive_number; 345 path[0] = L'A' + drive_number;
350 return base::FilePath(path); 346 return base::FilePath(path);
351 } 347 }
352 348
353 // In order to get all the weak pointers created on the UI thread, and doing 349 // In order to get all the weak pointers created on the UI thread, and doing
354 // synchronous Windows calls in the worker pool, this kicks off a chain of 350 // synchronous Windows calls in the worker pool, this kicks off a chain of
355 // events which will 351 // events which will
356 // a) Enumerate attached devices 352 // a) Enumerate attached devices
357 // b) Create weak pointers for which to send completion signals from 353 // b) Create weak pointers for which to send completion signals from
358 // c) Retrieve metadata on the volumes and then 354 // c) Retrieve metadata on the volumes and then
(...skipping 11 matching lines...) Expand all
370 } 366 }
371 367
372 void VolumeMountWatcherWin::AddDevicesOnUIThread( 368 void VolumeMountWatcherWin::AddDevicesOnUIThread(
373 std::vector<base::FilePath> removable_devices) { 369 std::vector<base::FilePath> removable_devices) {
374 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 370 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
375 371
376 for (size_t i = 0; i < removable_devices.size(); i++) { 372 for (size_t i = 0; i < removable_devices.size(); i++) {
377 if (ContainsKey(pending_device_checks_, removable_devices[i])) 373 if (ContainsKey(pending_device_checks_, removable_devices[i]))
378 continue; 374 continue;
379 pending_device_checks_.insert(removable_devices[i]); 375 pending_device_checks_.insert(removable_devices[i]);
380 task_runner_->PostTask(FROM_HERE, base::Bind( 376 task_runner_->PostTask(
381 &VolumeMountWatcherWin::RetrieveInfoForDeviceAndAdd, 377 FROM_HERE,
382 removable_devices[i], GetDeviceDetailsCallback(), 378 base::Bind(&VolumeMountWatcherWin::RetrieveInfoForDeviceAndAdd,
383 weak_factory_.GetWeakPtr())); 379 removable_devices[i], GetDeviceDetailsCallback(),
380 weak_factory_.GetWeakPtr()));
384 } 381 }
385 } 382 }
386 383
387 // static 384 // static
388 void VolumeMountWatcherWin::RetrieveInfoForDeviceAndAdd( 385 void VolumeMountWatcherWin::RetrieveInfoForDeviceAndAdd(
389 const base::FilePath& device_path, 386 const base::FilePath& device_path,
390 const GetDeviceDetailsCallbackType& get_device_details_callback, 387 const GetDeviceDetailsCallbackType& get_device_details_callback,
391 base::WeakPtr<chrome::VolumeMountWatcherWin> volume_watcher) { 388 base::WeakPtr<VolumeMountWatcherWin> volume_watcher) {
392 StorageInfo info; 389 StorageInfo info;
393 if (!get_device_details_callback.Run(device_path, &info)) { 390 if (!get_device_details_callback.Run(device_path, &info)) {
394 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, base::Bind( 391 BrowserThread::PostTask(
395 &chrome::VolumeMountWatcherWin::DeviceCheckComplete, 392 BrowserThread::UI, FROM_HERE,
396 volume_watcher, device_path)); 393 base::Bind(&VolumeMountWatcherWin::DeviceCheckComplete,
394 volume_watcher, device_path));
397 return; 395 return;
398 } 396 }
399 397
400 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, base::Bind( 398 BrowserThread::PostTask(
401 &chrome::VolumeMountWatcherWin::HandleDeviceAttachEventOnUIThread, 399 BrowserThread::UI, FROM_HERE,
402 volume_watcher, device_path, info)); 400 base::Bind(&VolumeMountWatcherWin::HandleDeviceAttachEventOnUIThread,
401 volume_watcher, device_path, info));
403 } 402 }
404 403
405 void VolumeMountWatcherWin::DeviceCheckComplete( 404 void VolumeMountWatcherWin::DeviceCheckComplete(
406 const base::FilePath& device_path) { 405 const base::FilePath& device_path) {
407 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 406 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
408 pending_device_checks_.erase(device_path); 407 pending_device_checks_.erase(device_path);
409 408
410 if (pending_device_checks_.size() == 0) { 409 if (pending_device_checks_.size() == 0) {
411 if (notifications_) 410 if (notifications_)
412 notifications_->MarkInitialized(); 411 notifications_->MarkInitialized();
413 } 412 }
414 } 413 }
415 414
416 VolumeMountWatcherWin::GetAttachedDevicesCallbackType 415 VolumeMountWatcherWin::GetAttachedDevicesCallbackType
417 VolumeMountWatcherWin::GetAttachedDevicesCallback() const { 416 VolumeMountWatcherWin::GetAttachedDevicesCallback() const {
418 return base::Bind(&GetAttachedDevices); 417 return base::Bind(&GetAttachedDevices);
419 } 418 }
420 419
421 VolumeMountWatcherWin::GetDeviceDetailsCallbackType 420 VolumeMountWatcherWin::GetDeviceDetailsCallbackType
422 VolumeMountWatcherWin::GetDeviceDetailsCallback() const { 421 VolumeMountWatcherWin::GetDeviceDetailsCallback() const {
423 return base::Bind(&GetDeviceDetails); 422 return base::Bind(&GetDeviceDetails);
424 } 423 }
425 424
426 bool VolumeMountWatcherWin::GetDeviceInfo(const base::FilePath& device_path, 425 bool VolumeMountWatcherWin::GetDeviceInfo(const base::FilePath& device_path,
427 StorageInfo* info) const { 426 StorageInfo* info) const {
428 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 427 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
428 DCHECK(info);
429 base::FilePath path(device_path); 429 base::FilePath path(device_path);
430 MountPointDeviceMetadataMap::const_iterator iter = 430 MountPointDeviceMetadataMap::const_iterator iter =
431 device_metadata_.find(path.value()); 431 device_metadata_.find(path.value());
432 while (iter == device_metadata_.end() && path.DirName() != path) { 432 while (iter == device_metadata_.end() && path.DirName() != path) {
433 path = path.DirName(); 433 path = path.DirName();
434 iter = device_metadata_.find(path.value()); 434 iter = device_metadata_.find(path.value());
435 } 435 }
436 436
437 if (iter == device_metadata_.end()) 437 if (iter == device_metadata_.end())
438 return false; 438 return false;
439 439
440 if (info) 440 *info = iter->second;
441 *info = iter->second;
442
443 return true; 441 return true;
444 } 442 }
445 443
446 void VolumeMountWatcherWin::OnWindowMessage(UINT event_type, LPARAM data) { 444 void VolumeMountWatcherWin::OnWindowMessage(UINT event_type, LPARAM data) {
447 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 445 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
448 switch (event_type) { 446 switch (event_type) {
449 case DBT_DEVICEARRIVAL: { 447 case DBT_DEVICEARRIVAL: {
450 if (IsLogicalVolumeStructure(data)) { 448 if (IsLogicalVolumeStructure(data)) {
451 DWORD unitmask = GetVolumeBitMaskFromBroadcastHeader(data); 449 DWORD unitmask = GetVolumeBitMaskFromBroadcastHeader(data);
452 std::vector<base::FilePath> paths; 450 std::vector<base::FilePath> paths;
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
494 492
495 // Don't call removable storage observers for fixed volumes. 493 // Don't call removable storage observers for fixed volumes.
496 if (!StorageInfo::IsRemovableDevice(info.device_id())) 494 if (!StorageInfo::IsRemovableDevice(info.device_id()))
497 return; 495 return;
498 496
499 if (notifications_) 497 if (notifications_)
500 notifications_->ProcessAttach(info); 498 notifications_->ProcessAttach(info);
501 } 499 }
502 500
503 void VolumeMountWatcherWin::HandleDeviceDetachEventOnUIThread( 501 void VolumeMountWatcherWin::HandleDeviceDetachEventOnUIThread(
504 const string16& device_location) { 502 const base::string16& device_location) {
505 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 503 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
506 504
507 MountPointDeviceMetadataMap::const_iterator device_info = 505 MountPointDeviceMetadataMap::const_iterator device_info =
508 device_metadata_.find(device_location); 506 device_metadata_.find(device_location);
509 // If the device isn't type removable (like a CD), it won't be there. 507 // If the device isn't type removable (like a CD), it won't be there.
510 if (device_info == device_metadata_.end()) 508 if (device_info == device_metadata_.end())
511 return; 509 return;
512 510
513 if (notifications_) 511 if (notifications_)
514 notifications_->ProcessDetach(device_info->second.device_id()); 512 notifications_->ProcessDetach(device_info->second.device_id());
515 device_metadata_.erase(device_info); 513 device_metadata_.erase(device_info);
516 } 514 }
517 515
518 void VolumeMountWatcherWin::EjectDevice( 516 void VolumeMountWatcherWin::EjectDevice(
519 const std::string& device_id, 517 const std::string& device_id,
520 base::Callback<void(StorageMonitor::EjectStatus)> callback) { 518 base::Callback<void(StorageMonitor::EjectStatus)> callback) {
521 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 519 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
522 base::FilePath device = 520 base::FilePath device = MediaStorageUtil::FindDevicePathById(device_id);
523 chrome::MediaStorageUtil::FindDevicePathById(device_id);
524 if (device.empty()) { 521 if (device.empty()) {
525 callback.Run(StorageMonitor::EJECT_FAILURE); 522 callback.Run(StorageMonitor::EJECT_FAILURE);
526 return; 523 return;
527 } 524 }
528 if (device_metadata_.erase(device.value()) == 0) { 525 if (device_metadata_.erase(device.value()) == 0) {
529 callback.Run(StorageMonitor::EJECT_FAILURE); 526 callback.Run(StorageMonitor::EJECT_FAILURE);
530 return; 527 return;
531 } 528 }
532 529
533 task_runner_->PostTask(FROM_HERE, 530 task_runner_->PostTask(
531 FROM_HERE,
534 base::Bind(&EjectDeviceInThreadPool, device, callback, task_runner_, 0)); 532 base::Bind(&EjectDeviceInThreadPool, device, callback, task_runner_, 0));
535 } 533 }
536 534
537 } // namespace chrome 535 } // namespace chrome
OLDNEW
« no previous file with comments | « chrome/browser/storage_monitor/volume_mount_watcher_win.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698