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/files/file.h"
13 #include "base/files/file_path.h"
14 #include "base/macros.h"
15 #include "base/strings/stringprintf.h"
16 #include "base/win/windows_version.h"
22 // Semi-copy of similarly named struct from ata.h in WinDDK.
23 struct IDENTIFY_DEVICE_DATA
{
24 USHORT UnusedWords
[217];
25 USHORT NominalMediaRotationRate
;
26 USHORT MoreUnusedWords
[38];
28 COMPILE_ASSERT(sizeof(IDENTIFY_DEVICE_DATA
) == 512, IdentifyDeviceDataSize
);
31 ATA_PASS_THROUGH_EX query
;
32 IDENTIFY_DEVICE_DATA result
;
38 bool DriveMetricsProvider::HasSeekPenalty(const base::FilePath
& path
,
39 bool* has_seek_penalty
) {
40 std::vector
<base::FilePath::StringType
> components
;
41 path
.GetComponents(&components
);
43 int flags
= base::File::FLAG_OPEN
;
44 bool win7_or_higher
= base::win::GetVersion() >= base::win::VERSION_WIN7
;
46 flags
|= base::File::FLAG_READ
| base::File::FLAG_WRITE
;
48 base::File
volume(base::FilePath(L
"\\\\.\\" + components
[0]), flags
);
49 if (!volume
.IsValid())
53 STORAGE_PROPERTY_QUERY query
= {};
54 query
.QueryType
= PropertyStandardQuery
;
55 query
.PropertyId
= StorageDeviceSeekPenaltyProperty
;
57 DEVICE_SEEK_PENALTY_DESCRIPTOR result
;
59 BOOL success
= DeviceIoControl(
60 volume
.GetPlatformFile(), IOCTL_STORAGE_QUERY_PROPERTY
, &query
,
61 sizeof(query
), &result
, sizeof(result
), &bytes_returned
, NULL
);
62 if (success
== FALSE
|| bytes_returned
< sizeof(result
))
65 *has_seek_penalty
= result
.IncursSeekPenalty
!= FALSE
;
67 AtaRequest request
= {};
68 request
.query
.AtaFlags
= ATA_FLAGS_DATA_IN
;
69 request
.query
.CurrentTaskFile
[6] = ID_CMD
;
70 request
.query
.DataBufferOffset
= sizeof(request
.query
);
71 request
.query
.DataTransferLength
= sizeof(request
.result
);
72 request
.query
.Length
= sizeof(request
.query
);
73 request
.query
.TimeOutValue
= 10;
76 BOOL success
= DeviceIoControl(
77 volume
.GetPlatformFile(), IOCTL_ATA_PASS_THROUGH
, &request
,
78 sizeof(request
), &request
, sizeof(request
), &bytes_returned
, NULL
);
79 if (success
== FALSE
|| bytes_returned
< sizeof(request
) ||
80 request
.query
.CurrentTaskFile
[0]) {
84 *has_seek_penalty
= request
.result
.NominalMediaRotationRate
!= 1;
90 } // namespace metrics