OLD | NEW |
| (Empty) |
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. | |
4 | |
5 #include "chrome/browser/metrics/drive_metrics_provider.h" | |
6 | |
7 #include <windows.h> | |
8 #include <ntddscsi.h> | |
9 #include <winioctl.h> | |
10 #include <vector> | |
11 | |
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" | |
17 | |
18 namespace { | |
19 | |
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]; | |
25 }; | |
26 COMPILE_ASSERT(sizeof(IDENTIFY_DEVICE_DATA) == 512, IdentifyDeviceDataSize); | |
27 | |
28 struct AtaRequest { | |
29 ATA_PASS_THROUGH_EX query; | |
30 IDENTIFY_DEVICE_DATA result; | |
31 }; | |
32 | |
33 } // namespace | |
34 | |
35 // static | |
36 bool DriveMetricsProvider::HasSeekPenalty(const base::FilePath& path, | |
37 bool* has_seek_penalty) { | |
38 std::vector<base::FilePath::StringType> components; | |
39 path.GetComponents(&components); | |
40 | |
41 int flags = base::File::FLAG_OPEN; | |
42 bool win7_or_higher = base::win::GetVersion() >= base::win::VERSION_WIN7; | |
43 if (!win7_or_higher) | |
44 flags |= base::File::FLAG_READ | base::File::FLAG_WRITE; | |
45 | |
46 base::File volume(base::FilePath(L"\\\\.\\" + components[0]), flags); | |
47 if (!volume.IsValid()) | |
48 return false; | |
49 | |
50 if (win7_or_higher) { | |
51 STORAGE_PROPERTY_QUERY query = {}; | |
52 query.QueryType = PropertyStandardQuery; | |
53 query.PropertyId = StorageDeviceSeekPenaltyProperty; | |
54 | |
55 DEVICE_SEEK_PENALTY_DESCRIPTOR result; | |
56 DWORD bytes_returned; | |
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)) | |
63 return false; | |
64 | |
65 *has_seek_penalty = result.IncursSeekPenalty != FALSE; | |
66 } else { | |
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; | |
74 | |
75 DWORD bytes_returned; | |
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]) { | |
83 return false; | |
84 } | |
85 | |
86 *has_seek_penalty = request.result.NominalMediaRotationRate != 1; | |
87 } | |
88 | |
89 return true; | |
90 } | |
OLD | NEW |