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.
9 #include "chrome/utility/image_writer/error_messages.h"
10 #include "chrome/utility/image_writer/image_writer.h"
12 namespace image_writer
{
14 const size_t kStorageQueryBufferSize
= 1024;
16 bool ImageWriter::IsValidDevice() {
17 base::win::ScopedHandle
device_handle(
18 CreateFile(device_path_
.value().c_str(),
19 GENERIC_READ
| GENERIC_WRITE
,
20 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
23 FILE_FLAG_NO_BUFFERING
| FILE_FLAG_WRITE_THROUGH
,
25 if (!device_handle
.IsValid()) {
26 Error(error::kOpenDevice
);
30 STORAGE_PROPERTY_QUERY query
= STORAGE_PROPERTY_QUERY();
31 query
.PropertyId
= StorageDeviceProperty
;
32 query
.QueryType
= PropertyStandardQuery
;
35 scoped_ptr
<char[]> output_buf(new char[kStorageQueryBufferSize
]);
36 BOOL status
= DeviceIoControl(
37 device_handle
.Get(), // Device handle.
38 IOCTL_STORAGE_QUERY_PROPERTY
, // Flag to request device properties.
39 &query
, // Query parameters.
40 sizeof(STORAGE_PROPERTY_QUERY
), // query parameters size.
41 output_buf
.get(), // output buffer.
42 kStorageQueryBufferSize
, // Size of buffer.
43 &bytes_returned
, // Number of bytes returned.
45 NULL
); // Optional unused overlapped perameter.
48 PLOG(ERROR
) << "Storage property query failed";
52 STORAGE_DEVICE_DESCRIPTOR
* device_descriptor
=
53 reinterpret_cast<STORAGE_DEVICE_DESCRIPTOR
*>(output_buf
.get());
55 return device_descriptor
->RemovableMedia
== TRUE
||
56 device_descriptor
->BusType
== BusTypeUsb
;
59 bool ImageWriter::OpenDevice() {
60 // Windows requires that device files be opened with FILE_FLAG_NO_BUFFERING
61 // and FILE_FLAG_WRITE_THROUGH. These two flags are not part of base::File.
63 base::File(CreateFile(device_path_
.value().c_str(),
64 GENERIC_READ
| GENERIC_WRITE
,
65 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
68 FILE_FLAG_NO_BUFFERING
| FILE_FLAG_WRITE_THROUGH
,
70 return device_file_
.IsValid();
73 void ImageWriter::UnmountVolumes(const base::Closure
& continuation
) {
74 if (!InitializeFiles()) {
78 STORAGE_DEVICE_NUMBER sdn
= {0};
81 BOOL status
= DeviceIoControl(
82 device_file_
.GetPlatformFile(),
83 IOCTL_STORAGE_GET_DEVICE_NUMBER
,
84 NULL
, // Unused, must be NULL.
85 0, // Unused, must be 0.
86 &sdn
, // An input buffer to hold the STORAGE_DEVICE_NUMBER
87 sizeof(sdn
), // The size of the input buffer.
88 &bytes_returned
, // the actual number of bytes returned.
89 NULL
); // Unused overlap.
91 PLOG(ERROR
) << "Unable to get device number.";
95 ULONG device_number
= sdn
.DeviceNumber
;
97 TCHAR volume_path
[MAX_PATH
+ 1];
98 HANDLE volume_finder
= FindFirstVolume(volume_path
, MAX_PATH
+ 1);
99 if (volume_finder
== INVALID_HANDLE_VALUE
) {
103 HANDLE volume_handle
;
104 bool first_volume
= true;
107 while (first_volume
||
108 FindNextVolume(volume_finder
, volume_path
, MAX_PATH
+ 1)) {
109 first_volume
= false;
111 size_t length
= wcsnlen(volume_path
, MAX_PATH
+ 1);
115 volume_path
[length
- 1] = L
'\0';
117 volume_handle
= CreateFile(volume_path
,
118 GENERIC_READ
| GENERIC_WRITE
,
119 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
124 if (volume_handle
== INVALID_HANDLE_VALUE
) {
125 PLOG(ERROR
) << "Opening volume handle failed.";
130 volume_handles_
.push_back(volume_handle
);
132 VOLUME_DISK_EXTENTS disk_extents
= {0};
133 status
= DeviceIoControl(volume_handle
,
134 IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS
,
138 sizeof(disk_extents
),
143 DWORD error
= GetLastError();
144 if (error
== ERROR_MORE_DATA
|| error
== ERROR_INVALID_FUNCTION
||
145 error
== ERROR_NOT_READY
) {
148 PLOG(ERROR
) << "Unable to get volume disk extents.";
154 if (disk_extents
.NumberOfDiskExtents
!= 1 ||
155 disk_extents
.Extents
[0].DiskNumber
!= device_number
) {
159 status
= DeviceIoControl(volume_handle
,
168 PLOG(ERROR
) << "Unable to lock volume.";
173 status
= DeviceIoControl(volume_handle
,
174 FSCTL_DISMOUNT_VOLUME
,
182 DWORD error
= GetLastError();
183 if (error
!= ERROR_NOT_SUPPORTED
) {
184 PLOG(ERROR
) << "Unable to dismount volume.";
191 if (volume_finder
!= INVALID_HANDLE_VALUE
) {
192 FindVolumeClose(volume_finder
);
199 } // namespace image_writer