1 // Copyright (C) 2018 The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #ifndef IORAP_SRC_INODE2FILENAME_INODE_H_
16 #define IORAP_SRC_INODE2FILENAME_INODE_H_
17
18 #include <functional>
19 #include <ostream>
20 #include <string>
21
22 #include <stddef.h>
23
24 namespace iorap::inode2filename {
25
26 // Avoid polluting headers.
27 #if defined(__ANDROID__)
28 # if !defined(__LP64__)
29 /* This historical accident means that we had a 32-bit dev_t on 32-bit architectures. */
30 using dev_t = uint32_t;
31 # else
32 using dev_t = uint64_t;
33 # endif
34 using ino_t = unsigned long;
35 #else
36 # if !defined(__x86_64__)
37 using dev_t = unsigned long long;
38 using ino_t = unsigned long long;
39 # else
40 using dev_t = unsigned long;
41 using ino_t = unsigned long;
42 # endif
43 #endif
44
45 #ifdef makedev
46 #undef makedev
47 #endif
48
49 /** Combines `major` and `minor` into a device number. */
makedev(unsigned int major,unsigned int minor)50 constexpr inline dev_t makedev(unsigned int major, unsigned int minor) {
51 return
52 (((major) & 0xfffff000ULL) << 32) | (((major) & 0xfffULL) << 8) |
53 (((minor) & 0xffffff00ULL) << 12) | (((minor) & 0xffULL));
54 }
55
56 #ifdef major
57 #undef major
58 #endif
59
60 /** Extracts the major part of a device number. */
major(dev_t dev)61 constexpr inline unsigned int major(dev_t dev) {
62 return
63 ((unsigned) ((((unsigned long long) (dev) >> 32) & 0xfffff000) | (((dev) >> 8) & 0xfff)));
64 }
65
66 #ifdef minor
67 #undef minor
68 #endif
69
70 /** Extracts the minor part of a device number. */
minor(dev_t dev)71 constexpr inline unsigned int minor(dev_t dev) {
72 return
73 ((unsigned) ((((dev) >> 12) & 0xffffff00) | ((dev) & 0xff)));
74 };
75 // Note: above definitions copied from sysmacros.h, to avoid polluting global namespace in a header.
76
77 /*
78 * A convenient datum representing a (dev_t, ino_t) tuple.
79 *
80 * ino_t values may be reused across different devices (e.g. different partitions),
81 * so we need the full tuple to uniquely identify an inode on a system.
82 */
83 struct Inode {
84 size_t device_major; // dev_t = makedev(major, minor)
85 size_t device_minor;
86 size_t inode; // ino_t = inode
87
88 // "Major:minor:inode" OR "dev_t@inode"
89 static bool Parse(const std::string& str, /*out*/Inode* out, /*out*/std::string* error_msg);
90
91 constexpr bool operator==(const Inode& rhs) const {
92 return device_major == rhs.device_major &&
93 device_minor == rhs.device_minor &&
94 inode == rhs.inode;
95 }
96
97 constexpr bool operator!=(const Inode& rhs) const {
98 return !(*this == rhs);
99 }
100
101 Inode() = default;
InodeInode102 constexpr Inode(size_t device_major, size_t device_minor, size_t inode)
103 : device_major{device_major}, device_minor{device_minor}, inode{inode} {
104 }
105
FromDeviceAndInodeInode106 static constexpr Inode FromDeviceAndInode(dev_t dev, ino_t inode) {
107 return Inode{major(dev), minor(dev), static_cast<size_t>(inode)};
108 }
109
GetDeviceInode110 constexpr dev_t GetDevice() const {
111 return makedev(device_major, device_minor);
112 }
113
GetInodeInode114 constexpr ino_t GetInode() const {
115 return static_cast<ino_t>(inode);
116 }
117 };
118
119 inline std::ostream& operator<<(std::ostream& os, const Inode& inode) {
120 os << inode.device_major << ":" << inode.device_minor << ":" << inode.inode;
121 return os;
122 }
123
124 } // namespace iorap::inode2filename
125
126 namespace std {
127 template <>
128 struct hash<iorap::inode2filename::Inode> {
129 using argument_type = iorap::inode2filename::Inode;
130 using result_type = size_t;
131 result_type operator()(argument_type const& s) const noexcept {
132 // Hash the inode by using only the inode#. Ignore devices, we are extremely unlikely
133 // to ever collide on the devices.
134 result_type const h1 = std::hash<size_t>{}(s.inode);
135 return h1;
136 }
137 };
138 } // namespace std
139
140 namespace rxcpp {
141 template <class T, typename>
142 struct filtered_hash;
143
144 // support for the 'distinct' rx operator.
145 template <>
146 struct filtered_hash<iorap::inode2filename::Inode, void> : std::hash<iorap::inode2filename::Inode> {
147 };
148 } // namespace rxcpp
149
150 #endif // IORAP_SRC_INODE2FILENAME_INODE_H_
151