Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / chrome / utility / image_writer / image_writer_win.cc
blob2d752a414b87e280d0269a5b1d13a6f51c78a9a6
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.
5 #include <windows.h>
6 #include <setupapi.h>
7 #include <winioctl.h>
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,
21 NULL,
22 OPEN_EXISTING,
23 FILE_FLAG_NO_BUFFERING | FILE_FLAG_WRITE_THROUGH,
24 NULL));
25 if (!device_handle.IsValid()) {
26 Error(error::kOpenDevice);
27 return false;
30 STORAGE_PROPERTY_QUERY query = STORAGE_PROPERTY_QUERY();
31 query.PropertyId = StorageDeviceProperty;
32 query.QueryType = PropertyStandardQuery;
33 DWORD bytes_returned;
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.
44 // Must not be null.
45 NULL); // Optional unused overlapped perameter.
47 if (!status) {
48 PLOG(ERROR) << "Storage property query failed";
49 return false;
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.
62 device_file_ =
63 base::File(CreateFile(device_path_.value().c_str(),
64 GENERIC_READ | GENERIC_WRITE,
65 FILE_SHARE_READ | FILE_SHARE_WRITE,
66 NULL,
67 OPEN_EXISTING,
68 FILE_FLAG_NO_BUFFERING | FILE_FLAG_WRITE_THROUGH,
69 NULL));
70 return device_file_.IsValid();
73 void ImageWriter::UnmountVolumes(const base::Closure& continuation) {
74 if (!InitializeFiles()) {
75 return;
78 STORAGE_DEVICE_NUMBER sdn = {0};
79 DWORD bytes_returned;
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.
90 if (!status) {
91 PLOG(ERROR) << "Unable to get device number.";
92 return;
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) {
100 return;
103 HANDLE volume_handle;
104 bool first_volume = true;
105 bool success = 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);
112 if (length < 1) {
113 continue;
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,
120 NULL,
121 OPEN_EXISTING,
123 NULL);
124 if (volume_handle == INVALID_HANDLE_VALUE) {
125 PLOG(ERROR) << "Opening volume handle failed.";
126 success = false;
127 break;
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,
135 NULL,
137 &disk_extents,
138 sizeof(disk_extents),
139 &bytes_returned,
140 NULL);
142 if (!status) {
143 DWORD error = GetLastError();
144 if (error == ERROR_MORE_DATA || error == ERROR_INVALID_FUNCTION ||
145 error == ERROR_NOT_READY) {
146 continue;
147 } else {
148 PLOG(ERROR) << "Unable to get volume disk extents.";
149 success = false;
150 break;
154 if (disk_extents.NumberOfDiskExtents != 1 ||
155 disk_extents.Extents[0].DiskNumber != device_number) {
156 continue;
159 status = DeviceIoControl(volume_handle,
160 FSCTL_LOCK_VOLUME,
161 NULL,
163 NULL,
165 &bytes_returned,
166 NULL);
167 if (!status) {
168 PLOG(ERROR) << "Unable to lock volume.";
169 success = false;
170 break;
173 status = DeviceIoControl(volume_handle,
174 FSCTL_DISMOUNT_VOLUME,
175 NULL,
177 NULL,
179 &bytes_returned,
180 NULL);
181 if (!status) {
182 DWORD error = GetLastError();
183 if (error != ERROR_NOT_SUPPORTED) {
184 PLOG(ERROR) << "Unable to dismount volume.";
185 success = false;
186 break;
191 if (volume_finder != INVALID_HANDLE_VALUE) {
192 FindVolumeClose(volume_finder);
195 if (success)
196 continuation.Run();
199 } // namespace image_writer