OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 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 "components/storage_monitor/volume_mount_watcher_win.h" | 5 #include "components/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> |
(...skipping 235 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
246 base::Bind(callback, StorageMonitor::EJECT_FAILURE)); | 246 base::Bind(callback, StorageMonitor::EJECT_FAILURE)); |
247 return; | 247 return; |
248 } | 248 } |
249 | 249 |
250 DWORD bytes_returned = 0; // Unused, but necessary for ioctl's. | 250 DWORD bytes_returned = 0; // Unused, but necessary for ioctl's. |
251 | 251 |
252 // Lock the drive to be ejected (so that other processes can't open | 252 // Lock the drive to be ejected (so that other processes can't open |
253 // files on it). If this fails, it means some other process has files | 253 // files on it). If this fails, it means some other process has files |
254 // open on the device. Note that the lock is released when the volume | 254 // open on the device. Note that the lock is released when the volume |
255 // handle is closed, and this is done by the ScopedHandle above. | 255 // handle is closed, and this is done by the ScopedHandle above. |
256 BOOL locked = DeviceIoControl(volume_handle, FSCTL_LOCK_VOLUME, | 256 BOOL locked = DeviceIoControl(volume_handle.Get(), FSCTL_LOCK_VOLUME, |
257 NULL, 0, NULL, 0, &bytes_returned, NULL); | 257 NULL, 0, NULL, 0, &bytes_returned, NULL); |
258 UMA_HISTOGRAM_ENUMERATION("StorageMonitor.EjectWinLock", | 258 UMA_HISTOGRAM_ENUMERATION("StorageMonitor.EjectWinLock", |
259 LOCK_ATTEMPT, NUM_LOCK_OUTCOMES); | 259 LOCK_ATTEMPT, NUM_LOCK_OUTCOMES); |
260 if (!locked) { | 260 if (!locked) { |
261 UMA_HISTOGRAM_ENUMERATION("StorageMonitor.EjectWinLock", | 261 UMA_HISTOGRAM_ENUMERATION("StorageMonitor.EjectWinLock", |
262 iteration == 0 ? LOCK_TIMEOUT : LOCK_TIMEOUT2, | 262 iteration == 0 ? LOCK_TIMEOUT : LOCK_TIMEOUT2, |
263 NUM_LOCK_OUTCOMES); | 263 NUM_LOCK_OUTCOMES); |
264 const int kNumLockRetries = 1; | 264 const int kNumLockRetries = 1; |
265 const base::TimeDelta kLockRetryInterval = | 265 const base::TimeDelta kLockRetryInterval = |
266 base::TimeDelta::FromMilliseconds(500); | 266 base::TimeDelta::FromMilliseconds(500); |
267 if (iteration < kNumLockRetries) { | 267 if (iteration < kNumLockRetries) { |
268 // Try again -- the lock may have been a transient one. This happens on | 268 // Try again -- the lock may have been a transient one. This happens on |
269 // things like AV disk lock for some reason, or another process | 269 // things like AV disk lock for some reason, or another process |
270 // transient disk lock. | 270 // transient disk lock. |
271 task_runner->PostDelayedTask( | 271 task_runner->PostDelayedTask( |
272 FROM_HERE, | 272 FROM_HERE, |
273 base::Bind(&EjectDeviceInThreadPool, | 273 base::Bind(&EjectDeviceInThreadPool, |
274 device, callback, task_runner, iteration + 1), | 274 device, callback, task_runner, iteration + 1), |
275 kLockRetryInterval); | 275 kLockRetryInterval); |
276 return; | 276 return; |
277 } | 277 } |
278 | 278 |
279 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, | 279 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, |
280 base::Bind(callback, StorageMonitor::EJECT_IN_USE)); | 280 base::Bind(callback, StorageMonitor::EJECT_IN_USE)); |
281 return; | 281 return; |
282 } | 282 } |
283 | 283 |
284 // Unmount the device from the filesystem -- this will remove it from | 284 // Unmount the device from the filesystem -- this will remove it from |
285 // the file picker, drive enumerations, etc. | 285 // the file picker, drive enumerations, etc. |
286 BOOL dismounted = DeviceIoControl(volume_handle, FSCTL_DISMOUNT_VOLUME, | 286 BOOL dismounted = DeviceIoControl(volume_handle.Get(), FSCTL_DISMOUNT_VOLUME, |
287 NULL, 0, NULL, 0, &bytes_returned, NULL); | 287 NULL, 0, NULL, 0, &bytes_returned, NULL); |
288 | 288 |
289 // Reached if we acquired a lock, but could not dismount. This might | 289 // Reached if we acquired a lock, but could not dismount. This might |
290 // occur if another process unmounted without locking. Call this OK, | 290 // occur if another process unmounted without locking. Call this OK, |
291 // since the volume is now unreachable. | 291 // since the volume is now unreachable. |
292 if (!dismounted) { | 292 if (!dismounted) { |
293 DeviceIoControl(volume_handle, FSCTL_UNLOCK_VOLUME, | 293 DeviceIoControl(volume_handle.Get(), FSCTL_UNLOCK_VOLUME, |
294 NULL, 0, NULL, 0, &bytes_returned, NULL); | 294 NULL, 0, NULL, 0, &bytes_returned, NULL); |
295 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, | 295 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, |
296 base::Bind(callback, StorageMonitor::EJECT_OK)); | 296 base::Bind(callback, StorageMonitor::EJECT_OK)); |
297 return; | 297 return; |
298 } | 298 } |
299 | 299 |
300 PREVENT_MEDIA_REMOVAL pmr_buffer; | 300 PREVENT_MEDIA_REMOVAL pmr_buffer; |
301 pmr_buffer.PreventMediaRemoval = FALSE; | 301 pmr_buffer.PreventMediaRemoval = FALSE; |
302 // Mark the device as safe to remove. | 302 // Mark the device as safe to remove. |
303 if (!DeviceIoControl(volume_handle, IOCTL_STORAGE_MEDIA_REMOVAL, | 303 if (!DeviceIoControl(volume_handle.Get(), IOCTL_STORAGE_MEDIA_REMOVAL, |
304 &pmr_buffer, sizeof(PREVENT_MEDIA_REMOVAL), | 304 &pmr_buffer, sizeof(PREVENT_MEDIA_REMOVAL), |
305 NULL, 0, &bytes_returned, NULL)) { | 305 NULL, 0, &bytes_returned, NULL)) { |
306 BrowserThread::PostTask( | 306 BrowserThread::PostTask( |
307 BrowserThread::UI, FROM_HERE, | 307 BrowserThread::UI, FROM_HERE, |
308 base::Bind(callback, StorageMonitor::EJECT_FAILURE)); | 308 base::Bind(callback, StorageMonitor::EJECT_FAILURE)); |
309 return; | 309 return; |
310 } | 310 } |
311 | 311 |
312 // Physically eject or soft-eject the device. | 312 // Physically eject or soft-eject the device. |
313 if (!DeviceIoControl(volume_handle, IOCTL_STORAGE_EJECT_MEDIA, | 313 if (!DeviceIoControl(volume_handle.Get(), IOCTL_STORAGE_EJECT_MEDIA, |
314 NULL, 0, NULL, 0, &bytes_returned, NULL)) { | 314 NULL, 0, NULL, 0, &bytes_returned, NULL)) { |
315 BrowserThread::PostTask( | 315 BrowserThread::PostTask( |
316 BrowserThread::UI, FROM_HERE, | 316 BrowserThread::UI, FROM_HERE, |
317 base::Bind(callback, StorageMonitor::EJECT_FAILURE)); | 317 base::Bind(callback, StorageMonitor::EJECT_FAILURE)); |
318 return; | 318 return; |
319 } | 319 } |
320 | 320 |
321 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, | 321 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, |
322 base::Bind(callback, StorageMonitor::EJECT_OK)); | 322 base::Bind(callback, StorageMonitor::EJECT_OK)); |
323 } | 323 } |
(...skipping 223 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
547 callback.Run(StorageMonitor::EJECT_FAILURE); | 547 callback.Run(StorageMonitor::EJECT_FAILURE); |
548 return; | 548 return; |
549 } | 549 } |
550 | 550 |
551 task_runner_->PostTask( | 551 task_runner_->PostTask( |
552 FROM_HERE, | 552 FROM_HERE, |
553 base::Bind(&EjectDeviceInThreadPool, device, callback, task_runner_, 0)); | 553 base::Bind(&EjectDeviceInThreadPool, device, callback, task_runner_, 0)); |
554 } | 554 } |
555 | 555 |
556 } // namespace storage_monitor | 556 } // namespace storage_monitor |
OLD | NEW |