GCC Code Coverage Report


Directory: cvmfs/
File: cvmfs/uid_map.h
Date: 2026-06-21 02:37:04
Exec Total Coverage
Lines: 62 63 98.4%
Branches: 60 85 70.6%

Line Branch Exec Source
1 /**
2 * This file is part of the CernVM File System.
3 */
4
5 #ifndef CVMFS_UID_MAP_H_
6 #define CVMFS_UID_MAP_H_
7
8 #include <sys/types.h>
9
10 #include <cassert>
11 #include <cerrno>
12 #include <map>
13 #include <string>
14 #include <vector>
15
16 #include "sanitizer.h"
17 #include "util/logging.h"
18 #include "util/string.h"
19
20 /**
21 * This reads a mapping file of (roughly) the following format:
22 * +-------------------------------------------------------------+
23 * | user_id.map |
24 * | ~~~~~~~~~~~ |
25 * | |
26 * | # map UIDs 137 and 138 to 1000 (I am a comment by the way) |
27 * | 137 1000 |
28 * | 138 1000 |
29 * | |
30 * | # swap two UIDs |
31 * | 101 5 |
32 * | 5 101 |
33 * | |
34 * | # map everything else to root (wildcard) |
35 * | * 0 |
36 * +-------------------------------------------------------------+
37 *
38 * These files are intended for the definition of UID and GID mappings both on
39 * the client and the server side of CernVM-FS.
40 *
41 * The class takes care of managing these mappings and can be initialised via
42 * a file read from disk or programmatically through the class's public API.
43 * When reading from a file, simple consistency checks are performed to ensure
44 * proper functionality.
45 */
46 template<typename T>
47 class IntegerMap {
48 public:
49 typedef T key_type;
50 typedef T value_type;
51 typedef typename std::map<key_type, value_type> map_type;
52
53 public:
54 3922 IntegerMap()
55 3922 : valid_(true), has_default_value_(false), default_value_(T(0)) { }
56
57 /**
58 * Define a mapping from k to v
59 * @param k map the given value to v
60 * @param v the value given in k is mapped to this
61 **/
62 336 void Set(const T k, const T v) { map_[k] = v; }
63
64 /**
65 * Sets a default (or fallback) value to be used if no other mapping rule fits
66 * Note: A previously defined default value is overwritten.
67 * @param v the value to be used as a fallback in Map()
68 */
69 140 void SetDefault(const T v) {
70 140 has_default_value_ = true;
71 140 default_value_ = v;
72 140 }
73
74 /**
75 * Reads mapping rules from a provided file path. The file format is discussed
76 * in the class description above.
77 * Note: If a read failure occurs the IntegerMap<> is declared invalid and
78 * must not be used anymore.
79 *
80 * @param path the file path to be read
81 * @return true if the file was successfully read
82 */
83 128 bool Read(const std::string &path) {
84 128 valid_ = ReadFromFile(path);
85 128 return IsValid();
86 }
87
88 /**
89 * Checks if a mapping rule for a given value is available
90 * @param k the value to be checked
91 * @return true if a mapping rule for k exists
92 */
93 224 bool Contains(const T k) const {
94
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 224 times.
224 assert(IsValid());
95
1/2
✓ Branch 2 taken 224 times.
✗ Branch 3 not taken.
224 return map_.find(k) != map_.end();
96 }
97
98 /**
99 * Applies the mapping rules inside this IntegerMap<> to the given value.
100 * @param k the value to be mapped
101 * @return the result of the mapping rule application (might be the default)
102 */
103 308 T Map(const T k) const {
104
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 308 times.
308 assert(IsValid());
105
1/2
✓ Branch 1 taken 308 times.
✗ Branch 2 not taken.
308 const typename map_type::const_iterator i = map_.find(k);
106
2/2
✓ Branch 2 taken 168 times.
✓ Branch 3 taken 140 times.
308 if (i != map_.end()) {
107 168 return i->second;
108 }
109
110
2/2
✓ Branch 1 taken 112 times.
✓ Branch 2 taken 28 times.
140 return (HasDefault()) ? default_value_ : k;
111 }
112
113
4/4
✓ Branch 1 taken 2768 times.
✓ Branch 2 taken 28 times.
✓ Branch 3 taken 28 times.
✓ Branch 4 taken 2740 times.
2796 bool HasEffect() const { return (map_.size() != 0) || has_default_value_; }
114
115 112 bool IsEmpty() const { return map_.size() == 0; }
116 856 bool IsValid() const { return valid_; }
117 252 bool HasDefault() const { return has_default_value_; }
118 112 size_t RuleCount() const { return map_.size(); }
119
120 56 T GetDefault() const {
121
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 56 times.
56 assert(has_default_value_);
122 56 return default_value_;
123 }
124 const map_type &GetRuleMap() const { return map_; }
125
126 protected:
127 128 bool ReadFromFile(const std::string &path) {
128
1/2
✓ Branch 2 taken 128 times.
✗ Branch 3 not taken.
128 FILE *fmap = fopen(path.c_str(), "r");
129
2/2
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 112 times.
128 if (!fmap) {
130
1/2
✓ Branch 1 taken 16 times.
✗ Branch 2 not taken.
16 LogCvmfs(kLogUtility, kLogDebug, "failed to open %s (errno: %d)",
131 16 path.c_str(), errno);
132 16 return false;
133 }
134
135
1/2
✓ Branch 1 taken 112 times.
✗ Branch 2 not taken.
112 const sanitizer::IntegerSanitizer int_sanitizer;
136
137 112 std::string line;
138 112 unsigned int line_number = 0;
139
6/7
✓ Branch 1 taken 112 times.
✓ Branch 2 taken 28 times.
✓ Branch 3 taken 84 times.
✓ Branch 5 taken 420 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 392 times.
✓ Branch 8 taken 28 times.
644 while (GetLineFile(fmap, &line)) {
140 392 ++line_number;
141
1/2
✓ Branch 1 taken 392 times.
✗ Branch 2 not taken.
392 line = Trim(line);
142
7/8
✓ Branch 1 taken 364 times.
✓ Branch 2 taken 28 times.
✓ Branch 4 taken 364 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 140 times.
✓ Branch 7 taken 224 times.
✓ Branch 8 taken 168 times.
✓ Branch 9 taken 224 times.
392 if (line.empty() || line[0] == '#') {
143 196 continue;
144 }
145
146
1/2
✓ Branch 1 taken 224 times.
✗ Branch 2 not taken.
224 std::vector<std::string> components = SplitString(line, ' ');
147
1/2
✓ Branch 1 taken 224 times.
✗ Branch 2 not taken.
224 FilterEmptyStrings(&components);
148
3/4
✓ Branch 3 taken 196 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 168 times.
✓ Branch 6 taken 28 times.
420 if (components.size() != 2 || !int_sanitizer.IsValid(components[1])
149
10/14
✓ Branch 0 taken 196 times.
✓ Branch 1 taken 28 times.
✓ Branch 4 taken 168 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 140 times.
✓ Branch 7 taken 28 times.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✓ Branch 10 taken 140 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 28 times.
✓ Branch 13 taken 112 times.
✓ Branch 14 taken 84 times.
✓ Branch 15 taken 140 times.
420 || (components[0] != "*" && !int_sanitizer.IsValid(components[0]))) {
150
1/2
✓ Branch 1 taken 84 times.
✗ Branch 2 not taken.
84 fclose(fmap);
151
1/2
✓ Branch 2 taken 84 times.
✗ Branch 3 not taken.
84 LogCvmfs(kLogUtility, kLogDebug, "failed to read line %d in %s",
152 line_number, path.c_str());
153 84 return false;
154 }
155
156
1/2
✓ Branch 2 taken 140 times.
✗ Branch 3 not taken.
140 value_type const to = String2Uint64(components[1]);
157
2/2
✓ Branch 2 taken 28 times.
✓ Branch 3 taken 112 times.
140 if (components[0] == "*") {
158 28 SetDefault(to);
159 28 continue;
160 }
161
162
1/2
✓ Branch 2 taken 112 times.
✗ Branch 3 not taken.
112 key_type const from = String2Uint64(components[0]);
163
1/2
✓ Branch 1 taken 112 times.
✗ Branch 2 not taken.
112 Set(from, to);
164 }
165
166
1/2
✓ Branch 1 taken 28 times.
✗ Branch 2 not taken.
28 fclose(fmap);
167 28 return true;
168 112 }
169
170 224 void FilterEmptyStrings(std::vector<std::string> *vec) const {
171 224 std::vector<std::string>::iterator i = vec->begin();
172
2/2
✓ Branch 2 taken 504 times.
✓ Branch 3 taken 224 times.
728 for (; i != vec->end();) {
173
3/4
✓ Branch 2 taken 84 times.
✓ Branch 3 taken 420 times.
✓ Branch 6 taken 84 times.
✗ Branch 7 not taken.
504 i = (i->empty()) ? vec->erase(i) : i + 1;
174 }
175 224 }
176
177 private:
178 bool valid_;
179 map_type map_;
180
181 bool has_default_value_;
182 T default_value_;
183 };
184
185 typedef IntegerMap<uid_t> UidMap;
186 typedef IntegerMap<gid_t> GidMap;
187
188 #endif // CVMFS_UID_MAP_H_
189