1 // Copyright 2024 The Chromium Authors
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 "base/files/drive_info.h"
6
7 #include <sys/stat.h>
8 #include <sys/types.h>
9
10 #include "base/files/file.h"
11 #include "base/files/file_path.h"
12 #include "base/files/file_util.h"
13 #include "base/files/scoped_file.h"
14 #include "base/strings/string_number_conversions.h"
15 #include "base/strings/stringprintf.h"
16 #include "build/build_config.h"
17
18 #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
19 #include <linux/kdev_t.h>
20 #endif
21
22 namespace base {
23
GetFileDriveInfo(const FilePath & file_path)24 std::optional<DriveInfo> GetFileDriveInfo(const FilePath& file_path) {
25 DriveInfo drive_info;
26 #if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_FUCHSIA)
27 drive_info.has_seek_penalty = false;
28 return drive_info;
29 #elif BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
30 constexpr char kRotationalFormat[] =
31 "/sys/dev/block/%lu:%lu/queue/rotational";
32 constexpr char kRemovableFormat[] = "/sys/dev/block/%lu:%lu/removable";
33 constexpr char kSizeFormat[] = "/sys/dev/block/%lu:%lu/size";
34 File file(file_path, File::FLAG_OPEN | File::FLAG_READ);
35 if (!file.IsValid()) {
36 return std::nullopt;
37 }
38
39 struct stat path_stat;
40 int error = File::Fstat(file.GetPlatformFile(), &path_stat);
41 if (error < 0) {
42 return std::nullopt;
43 }
44
45 std::string rotational_path = StringPrintf(
46 kRotationalFormat, MAJOR(path_stat.st_dev), MINOR(path_stat.st_dev));
47 std::string removable_path = StringPrintf(
48 kRemovableFormat, MAJOR(path_stat.st_dev), MINOR(path_stat.st_dev));
49 std::string size_path = StringPrintf(kSizeFormat, MAJOR(path_stat.st_dev),
50 MINOR(path_stat.st_dev));
51
52 std::string rotates;
53 if (ReadFileToString(base::FilePath(rotational_path), &rotates) &&
54 rotates.length() == 1 && (rotates[0] == '0' || rotates[0] == '1')) {
55 drive_info.has_seek_penalty = rotates[0] == '1';
56 }
57
58 std::string removable;
59 if (ReadFileToString(base::FilePath(removable_path), &removable) &&
60 removable.length() == 1 && (removable[0] == '0' || removable[0] == '1')) {
61 drive_info.is_removable = removable[0] == '1';
62 }
63
64 std::string size;
65 uint64_t bytes;
66 if (ReadFileToString(FilePath(size_path), &size) &&
67 StringToUint64(size, &bytes)) {
68 drive_info.size_bytes = bytes;
69 }
70
71 return drive_info;
72 #endif
73 }
74
75 } // namespace base
76