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 "chrome/browser/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"
20 // Semi-copy of similarly named struct from ata.h in WinDDK.
21 struct IDENTIFY_DEVICE_DATA
{
22 USHORT UnusedWords
[217];
23 USHORT NominalMediaRotationRate
;
24 USHORT MoreUnusedWords
[38];
26 COMPILE_ASSERT(sizeof(IDENTIFY_DEVICE_DATA
) == 512, IdentifyDeviceDataSize
);
29 ATA_PASS_THROUGH_EX query
;
30 IDENTIFY_DEVICE_DATA result
;
36 bool DriveMetricsProvider::HasSeekPenalty(const base::FilePath
& path
,
37 bool* has_seek_penalty
) {
38 std::vector
<base::FilePath::StringType
> components
;
39 path
.GetComponents(&components
);
41 int flags
= base::File::FLAG_OPEN
;
42 bool win7_or_higher
= base::win::GetVersion() >= base::win::VERSION_WIN7
;
44 flags
|= base::File::FLAG_READ
| base::File::FLAG_WRITE
;
46 base::File
volume(base::FilePath(L
"\\\\.\\" + components
[0]), flags
);
47 if (!volume
.IsValid())
51 STORAGE_PROPERTY_QUERY query
= {};
52 query
.QueryType
= PropertyStandardQuery
;
53 query
.PropertyId
= StorageDeviceSeekPenaltyProperty
;
55 DEVICE_SEEK_PENALTY_DESCRIPTOR result
;
57 BOOL success
= DeviceIoControl(volume
.GetPlatformFile(),
58 IOCTL_STORAGE_QUERY_PROPERTY
,
59 &query
, sizeof(query
),
60 &result
, sizeof(result
),
61 &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(volume
.GetPlatformFile(),
77 IOCTL_ATA_PASS_THROUGH
,
78 &request
, sizeof(request
),
79 &request
, sizeof(request
),
80 &bytes_returned
, NULL
);
81 if (success
== FALSE
|| bytes_returned
< sizeof(request
) ||
82 request
.query
.CurrentTaskFile
[0]) {
86 *has_seek_penalty
= request
.result
.NominalMediaRotationRate
!= 1;