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"
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"
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
);
32 ATA_PASS_THROUGH_EX query
;
33 IDENTIFY_DEVICE_DATA result
;
36 struct PaddedAtaRequest
{
37 DWORD bytes_returned
; // Intentionally above |request| for alignment.
40 // Prevents some crashes from bad drivers. http://crbug.com/514822
41 BYTE kUnusedBadDriverSpace
[256] ALLOW_UNUSED_TYPE
;
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
;
55 flags
|= base::File::FLAG_READ
| base::File::FLAG_WRITE
;
57 base::File
volume(base::FilePath(L
"\\\\.\\" + components
[0]), flags
);
58 if (!volume
.IsValid())
62 STORAGE_PROPERTY_QUERY query
= {};
63 query
.QueryType
= PropertyStandardQuery
;
64 query
.PropertyId
= StorageDeviceSeekPenaltyProperty
;
66 DEVICE_SEEK_PENALTY_DESCRIPTOR result
;
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
))
76 *has_seek_penalty
= result
.IncursSeekPenalty
!= FALSE
;
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]) {
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;
109 } // namespace metrics