Update V8 to version 4.6.62.
[chromium-blink-merge.git] / components / metrics / drive_metrics_provider_win.cc
blob0256be12771d1e1b2f5d050a65e6520202abaf22
1 // Copyright 2015 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 "components/metrics/drive_metrics_provider.h"
7 #include <windows.h>
8 #include <ntddscsi.h>
9 #include <winioctl.h>
10 #include <vector>
12 #include "base/compiler_specific.h"
13 #include "base/files/file.h"
14 #include "base/files/file_path.h"
15 #include "base/macros.h"
16 #include "base/strings/stringprintf.h"
17 #include "base/win/windows_version.h"
19 namespace metrics {
21 namespace {
23 // Semi-copy of similarly named struct from ata.h in WinDDK.
24 struct IDENTIFY_DEVICE_DATA {
25 USHORT UnusedWords[217];
26 USHORT NominalMediaRotationRate;
27 USHORT MoreUnusedWords[38];
29 COMPILE_ASSERT(sizeof(IDENTIFY_DEVICE_DATA) == 512, IdentifyDeviceDataSize);
31 struct AtaRequest {
32 ATA_PASS_THROUGH_EX query;
33 IDENTIFY_DEVICE_DATA result;
36 struct PaddedAtaRequest {
37 DWORD bytes_returned; // Intentionally above |request| for alignment.
38 AtaRequest request;
39 private:
40 // Prevents some crashes from bad drivers. http://crbug.com/514822
41 BYTE kUnusedBadDriverSpace[256] ALLOW_UNUSED_TYPE;
44 } // namespace
46 // static
47 bool DriveMetricsProvider::HasSeekPenalty(const base::FilePath& path,
48 bool* has_seek_penalty) {
49 std::vector<base::FilePath::StringType> components;
50 path.GetComponents(&components);
52 int flags = base::File::FLAG_OPEN;
53 bool win7_or_higher = base::win::GetVersion() >= base::win::VERSION_WIN7;
54 if (!win7_or_higher)
55 flags |= base::File::FLAG_READ | base::File::FLAG_WRITE;
57 base::File volume(base::FilePath(L"\\\\.\\" + components[0]), flags);
58 if (!volume.IsValid())
59 return false;
61 if (win7_or_higher) {
62 STORAGE_PROPERTY_QUERY query = {};
63 query.QueryType = PropertyStandardQuery;
64 query.PropertyId = StorageDeviceSeekPenaltyProperty;
66 DEVICE_SEEK_PENALTY_DESCRIPTOR result;
67 DWORD bytes_returned;
69 BOOL success = DeviceIoControl(
70 volume.GetPlatformFile(), IOCTL_STORAGE_QUERY_PROPERTY, &query,
71 sizeof(query), &result, sizeof(result), &bytes_returned, NULL);
73 if (success == FALSE || bytes_returned < sizeof(result))
74 return false;
76 *has_seek_penalty = result.IncursSeekPenalty != FALSE;
77 } else {
78 PaddedAtaRequest padded = {};
80 AtaRequest* request = &padded.request;
81 request->query.AtaFlags = ATA_FLAGS_DATA_IN;
82 request->query.CurrentTaskFile[6] = ID_CMD;
83 request->query.DataBufferOffset = sizeof(request->query);
84 request->query.DataTransferLength = sizeof(request->result);
85 request->query.Length = sizeof(request->query);
86 request->query.TimeOutValue = 10;
88 DWORD* bytes_returned = &padded.bytes_returned;
90 BOOL success = DeviceIoControl(
91 volume.GetPlatformFile(), IOCTL_ATA_PASS_THROUGH, request,
92 sizeof(*request), request, sizeof(*request), bytes_returned, NULL);
94 if (success == FALSE || *bytes_returned < sizeof(*request) ||
95 request->query.CurrentTaskFile[0]) {
96 return false;
99 // Detect device driver writes further than request + bad driver space.
100 // http://crbug.com/514822
101 CHECK_LE(*bytes_returned, sizeof(padded) - sizeof(*bytes_returned));
103 *has_seek_penalty = request->result.NominalMediaRotationRate != 1;
106 return true;
109 } // namespace metrics