Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / chrome / utility / image_writer / image_writer_win.cc
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.
4
5 #include <windows.h>
6 #include <setupapi.h>
7 #include <winioctl.h>
8
9 #include "chrome/utility/image_writer/error_messages.h"
10 #include "chrome/utility/image_writer/image_writer.h"
11
12 namespace image_writer {
13
14 const size_t kStorageQueryBufferSize = 1024;
15
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 == INVALID_HANDLE_VALUE) {
26     Error(error::kOpenDevice);
27     return false;
28   }
29
30   STORAGE_PROPERTY_QUERY query = STORAGE_PROPERTY_QUERY();
31   query.PropertyId = StorageDeviceProperty;
32   query.QueryType = PropertyStandardQuery;
33   DWORD bytes_returned;
34
35   scoped_ptr<char[]> output_buf(new char[kStorageQueryBufferSize]);
36   BOOL status = DeviceIoControl(
37       device_handle,                   // 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.
46
47   if (!status) {
48     PLOG(ERROR) << "Storage property query failed";
49     return false;
50   }
51
52   STORAGE_DEVICE_DESCRIPTOR* device_descriptor =
53       reinterpret_cast<STORAGE_DEVICE_DESCRIPTOR*>(output_buf.get());
54
55   return device_descriptor->RemovableMedia == TRUE ||
56          device_descriptor->BusType == BusTypeUsb;
57 }
58
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();
71 }
72
73 void ImageWriter::UnmountVolumes(const base::Closure& continuation) {
74   if (!InitializeFiles()) {
75     return;
76   }
77
78   STORAGE_DEVICE_NUMBER sdn = {0};
79   DWORD bytes_returned;
80
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;
93   }
94
95   ULONG device_number = sdn.DeviceNumber;
96
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;
101   }
102
103   HANDLE volume_handle;
104   bool first_volume = true;
105   bool success = true;
106
107   while (first_volume ||
108          FindNextVolume(volume_finder, volume_path, MAX_PATH + 1)) {
109     first_volume = false;
110
111     size_t length = wcsnlen(volume_path, MAX_PATH + 1);
112     if (length < 1) {
113       continue;
114     }
115     volume_path[length - 1] = L'\0';
116
117     volume_handle = CreateFile(volume_path,
118                                GENERIC_READ | GENERIC_WRITE,
119                                FILE_SHARE_READ | FILE_SHARE_WRITE,
120                                NULL,
121                                OPEN_EXISTING,
122                                0,
123                                NULL);
124     if (volume_handle == INVALID_HANDLE_VALUE) {
125       PLOG(ERROR) << "Opening volume handle failed.";
126       success = false;
127       break;
128     }
129
130     volume_handles_.push_back(volume_handle);
131
132     VOLUME_DISK_EXTENTS disk_extents = {0};
133     status = DeviceIoControl(volume_handle,
134                              IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS,
135                              NULL,
136                              0,
137                              &disk_extents,
138                              sizeof(disk_extents),
139                              &bytes_returned,
140                              NULL);
141
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;
151       }
152     }
153
154     if (disk_extents.NumberOfDiskExtents != 1 ||
155         disk_extents.Extents[0].DiskNumber != device_number) {
156       continue;
157     }
158
159     status = DeviceIoControl(volume_handle,
160                              FSCTL_LOCK_VOLUME,
161                              NULL,
162                              0,
163                              NULL,
164                              0,
165                              &bytes_returned,
166                              NULL);
167     if (!status) {
168       PLOG(ERROR) << "Unable to lock volume.";
169       success = false;
170       break;
171     }
172
173     status = DeviceIoControl(volume_handle,
174                              FSCTL_DISMOUNT_VOLUME,
175                              NULL,
176                              0,
177                              NULL,
178                              0,
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;
187       }
188     }
189   }
190
191   if (volume_finder != INVALID_HANDLE_VALUE) {
192     FindVolumeClose(volume_finder);
193   }
194
195   if (success)
196     continuation.Run();
197 }
198
199 }  // namespace image_writer