summaryrefslogtreecommitdiff
path: root/src/inode2filename/inode.h
blob: f336a1405bb9e08d89e50763cfc4fa8f2fcfa628 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
// Copyright (C) 2018 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#ifndef IORAP_SRC_INODE2FILENAME_INODE_H_
#define IORAP_SRC_INODE2FILENAME_INODE_H_

#include <functional>
#include <ostream>
#include <string>

#include <stddef.h>

namespace iorap::inode2filename {

// Avoid polluting headers.
#if defined(__ANDROID__)
#  if !defined(__LP64__)
/* This historical accident means that we had a 32-bit dev_t on 32-bit architectures. */
using dev_t = uint32_t;
#  else
using dev_t = uint64_t;
#  endif
using ino_t = unsigned long;
#else
#  if !defined(__x86_64__)
using dev_t = unsigned long long;
using ino_t = unsigned long long;
#  else
using dev_t = unsigned long;
using ino_t = unsigned long;
#  endif
#endif

#ifdef makedev
#undef makedev
#endif

/** Combines `major` and `minor` into a device number. */
constexpr inline dev_t makedev(unsigned int major, unsigned int minor) {
  return
      (((major) & 0xfffff000ULL) << 32) | (((major) & 0xfffULL) << 8) |
      (((minor) & 0xffffff00ULL) << 12) | (((minor) & 0xffULL));
}

#ifdef major
#undef major
#endif

/** Extracts the major part of a device number. */
constexpr inline unsigned int major(dev_t dev) {
  return
      ((unsigned) ((((unsigned long long) (dev) >> 32) & 0xfffff000) | (((dev) >> 8) & 0xfff)));
}

#ifdef minor
#undef minor
#endif

/** Extracts the minor part of a device number. */
constexpr inline unsigned int minor(dev_t dev) {
  return
      ((unsigned) ((((dev) >> 12) & 0xffffff00) | ((dev) & 0xff)));
};
// Note: above definitions copied from sysmacros.h, to avoid polluting global namespace in a header.

/*
 * A convenient datum representing a (dev_t, ino_t) tuple.
 *
 * ino_t values may be reused across different devices (e.g. different partitions),
 * so we need the full tuple to uniquely identify an inode on a system.
 */
struct Inode {
  size_t device_major;  // dev_t = makedev(major, minor)
  size_t device_minor;
  size_t inode;         // ino_t = inode

  // "Major:minor:inode" OR "dev_t@inode"
  static bool Parse(const std::string& str, /*out*/Inode* out, /*out*/std::string* error_msg);

  constexpr bool operator==(const Inode& rhs) const {
    return device_major == rhs.device_major &&
        device_minor == rhs.device_minor &&
        inode == rhs.inode;
  }

  constexpr bool operator!=(const Inode& rhs) const {
    return !(*this == rhs);
  }

  Inode() = default;
  constexpr Inode(size_t device_major, size_t device_minor, size_t inode)
    : device_major{device_major}, device_minor{device_minor}, inode{inode} {
  }

  static constexpr Inode FromDeviceAndInode(dev_t dev, ino_t inode) {
    return Inode{major(dev), minor(dev), static_cast<size_t>(inode)};
  }

  constexpr dev_t GetDevice() const {
    return makedev(device_major, device_minor);
  }

  constexpr ino_t GetInode() const {
    return static_cast<ino_t>(inode);
  }
};

inline std::ostream& operator<<(std::ostream& os, const Inode& inode) {
  os << inode.device_major << ":" << inode.device_minor << ":" << inode.inode;
  return os;
}

}  // namespace iorap::inode2filename

namespace std {
  template <>
  struct hash<iorap::inode2filename::Inode> {
      using argument_type = iorap::inode2filename::Inode;
      using result_type = size_t;
      result_type operator()(argument_type const& s) const noexcept {
        // Hash the inode by using only the inode#. Ignore devices, we are extremely unlikely
        // to ever collide on the devices.
        result_type const h1 = std::hash<size_t>{}(s.inode);
        return h1;
      }
  };
}  // namespace std

namespace rxcpp {
template <class T, typename>
struct filtered_hash;

// support for the 'distinct' rx operator.
template <>
struct filtered_hash<iorap::inode2filename::Inode, void> : std::hash<iorap::inode2filename::Inode> {
};
}  // namespace rxcpp

#endif  // IORAP_SRC_INODE2FILENAME_INODE_H_