| 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 |