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