| 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 |