GCC Code Coverage Report


Directory: cvmfs/
File: cvmfs/util/string.cc
Date: 2026-10-25 02:40:14
Exec Total Coverage
Lines: 319 332 96.1%
Branches: 273 392 69.6%

Line Branch Exec Source
1 /**
2 * This file is part of the CernVM File System.
3 *
4 * Some common functions.
5 */
6
7 #include "string.h"
8
9 #include <cctype>
10 #include <cstdio>
11 #include <cstdlib>
12 #include <cstring>
13 #include <ctime>
14 #include <algorithm>
15 #include <vector>
16 #include <map>
17 #include <stdio.h>
18 #include <errno.h>
19 #include <fcntl.h>
20 #include <inttypes.h>
21 #include <stdint.h>
22 #include <time.h>
23 #include <string>
24 #include <unistd.h>
25
26
27 using namespace std; // NOLINT
28
29 #ifdef CVMFS_NAMESPACE_GUARD
30 namespace CVMFS_NAMESPACE_GUARD {
31 #endif
32
33 const char b64_table[] = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K',
34 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
35 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g',
36 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r',
37 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2',
38 '3', '4', '5', '6', '7', '8', '9', '+', '/'};
39
40 /**
41 * Decode Base64 and Base64Url
42 */
43 const int8_t db64_table[] = {
44 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
45 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
46 -1, -1, -1, -1, -1, 62, -1, 62, -1, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60,
47 61, -1, -1, -1, 0, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
48 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1,
49 63, -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42,
50 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1,
51
52 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
53 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
54 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
55 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
56 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
57 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
58 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
59 };
60
61 namespace {
62
63 /**
64 * Used for cas insensitive HasSuffix
65 */
66 struct IgnoreCaseComperator {
67 11993 IgnoreCaseComperator() { }
68 700 bool operator()(const std::string::value_type a,
69 const std::string::value_type b) const {
70 700 return std::tolower(a) == std::tolower(b);
71 }
72 };
73
74 } // anonymous namespace
75
76
3/4
✓ Branch 1 taken 76 times.
✓ Branch 2 taken 2868 times.
✓ Branch 4 taken 2944 times.
✗ Branch 5 not taken.
2944 string StringifyBool(const bool value) { return value ? "yes" : "no"; }
77
78 14152000 string StringifyInt(const int64_t value) {
79 char buffer[48];
80 14152000 snprintf(buffer, sizeof(buffer), "%" PRId64, value);
81
1/2
✓ Branch 2 taken 14148421 times.
✗ Branch 3 not taken.
14152000 return string(buffer);
82 }
83
84 3301045 std::string StringifyUint(const uint64_t value) {
85 char buffer[48];
86 3301045 snprintf(buffer, sizeof(buffer), "%" PRIu64, value);
87
1/2
✓ Branch 2 taken 3301045 times.
✗ Branch 3 not taken.
3301045 return string(buffer);
88 }
89
90 44 string StringifyByteAsHex(const unsigned char value) {
91 char buffer[3];
92 44 snprintf(buffer, sizeof(buffer), "%02x", value);
93
1/2
✓ Branch 2 taken 44 times.
✗ Branch 3 not taken.
44 return string(buffer);
94 }
95
96 118 string StringifyDouble(const double value) {
97 char buffer[64];
98 118 snprintf(buffer, sizeof(buffer), "%.03f", value);
99
1/2
✓ Branch 2 taken 118 times.
✗ Branch 3 not taken.
118 return string(buffer);
100 }
101
102 /**
103 * Converts seconds since UTC 0 into something readable
104 */
105 2580 string StringifyTime(const time_t seconds, const bool utc) {
106 struct tm timestamp;
107
2/2
✓ Branch 0 taken 1412 times.
✓ Branch 1 taken 1168 times.
2580 if (utc) {
108 1412 localtime_r(&seconds, &timestamp);
109 } else {
110 1168 gmtime_r(&seconds, &timestamp);
111 }
112
113 2580 const char *months[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
114 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
115 char buffer[21];
116 2580 snprintf(buffer, sizeof(buffer), "%d %s %d %02d:%02d:%02d", timestamp.tm_mday,
117 2580 months[timestamp.tm_mon], timestamp.tm_year + 1900,
118 timestamp.tm_hour, timestamp.tm_min, timestamp.tm_sec);
119
120
1/2
✓ Branch 2 taken 2580 times.
✗ Branch 3 not taken.
2580 return string(buffer);
121 }
122
123 /**
124 * Converts seconds since UTC 0 into something like 12 Sep 14:59:37 CDT
125 */
126 1008 string StringifyLocalTime(const time_t seconds) {
127 struct tm timestamp;
128 1008 localtime_r(&seconds, &timestamp);
129
130 1008 const char *months[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
131 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
132 char buffer[26];
133 (void)/* cast to void ignores return and placates clang-tidy */
134 1008 snprintf(buffer, sizeof(buffer), "%d %s %d %02d:%02d:%02d %s",
135 1008 timestamp.tm_mday, months[timestamp.tm_mon],
136 1008 timestamp.tm_year + 1900, timestamp.tm_hour, timestamp.tm_min,
137 timestamp.tm_sec, timestamp.tm_zone);
138
139
1/2
✓ Branch 2 taken 1008 times.
✗ Branch 3 not taken.
1008 return string(buffer);
140 }
141
142
143 /**
144 * Current time in format Wed, 01 Mar 2006 12:00:00 GMT
145 */
146 18268 std::string RfcTimestamp() {
147 18268 const char *months[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
148 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
149 18268 const char *day_of_week[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
150
151 struct tm timestamp;
152 18268 const time_t now = time(NULL);
153 18268 gmtime_r(&now, &timestamp);
154
155 char buffer[30];
156 18268 snprintf(buffer, sizeof(buffer), "%s, %02d %s %d %02d:%02d:%02d %s",
157 18268 day_of_week[timestamp.tm_wday], timestamp.tm_mday,
158 18268 months[timestamp.tm_mon], timestamp.tm_year + 1900,
159 timestamp.tm_hour, timestamp.tm_min, timestamp.tm_sec,
160 timestamp.tm_zone);
161
1/2
✓ Branch 2 taken 18268 times.
✗ Branch 3 not taken.
18268 return string(buffer);
162 }
163
164
165 /**
166 * Current time in format YYYYMMDDTHHMMSSZ. Used in AWS4 requests.
167 */
168 11 std::string IsoTimestamp() {
169 struct tm timestamp;
170 11 const time_t now = time(NULL);
171 11 gmtime_r(&now, &timestamp);
172
173 char buffer[17];
174 11 snprintf(buffer, sizeof(buffer), "%04d%02d%02dT%02d%02d%02dZ",
175 11 timestamp.tm_year + 1900, timestamp.tm_mon + 1, timestamp.tm_mday,
176 timestamp.tm_hour, timestamp.tm_min, timestamp.tm_sec);
177
1/2
✓ Branch 2 taken 11 times.
✗ Branch 3 not taken.
11 return string(buffer);
178 }
179
180
181 /**
182 * UTC time in format YYYYMMDDHHMMSS. Used in cvmfs whitelists.
183 */
184 231 std::string WhitelistTimestamp(time_t when) {
185 struct tm timestamp;
186 231 gmtime_r(&when, &timestamp);
187
188 char buffer[15];
189 231 snprintf(buffer, sizeof(buffer), "%04d%02d%02d%02d%02d%02d",
190 231 timestamp.tm_year + 1900, timestamp.tm_mon + 1, timestamp.tm_mday,
191 timestamp.tm_hour, timestamp.tm_min, timestamp.tm_sec);
192
1/2
✓ Branch 2 taken 231 times.
✗ Branch 3 not taken.
231 return string(buffer);
193 }
194
195
196 1117929 string StringifyTimeval(const timeval value) {
197 char buffer[64];
198 1117929 int64_t msec = value.tv_sec * 1000;
199 1117929 msec += value.tv_usec / 1000;
200 1117929 snprintf(buffer, sizeof(buffer), "%" PRId64 ".%03d", msec,
201 1117929 static_cast<int>(value.tv_usec % 1000));
202
1/2
✓ Branch 2 taken 1117929 times.
✗ Branch 3 not taken.
1117929 return string(buffer);
203 }
204
205 /**
206 * Parses a timestamp of the form YYYY-MM-DDTHH:MM:SSZ
207 * Return 0 on error
208 */
209 4221 time_t IsoTimestamp2UtcTime(const std::string &iso8601) {
210 4221 time_t utc_time = 0;
211 4221 const unsigned length = iso8601.length();
212
213
2/2
✓ Branch 0 taken 28 times.
✓ Branch 1 taken 4193 times.
4221 if (length != 20)
214 28 return utc_time;
215
2/4
✓ Branch 2 taken 4193 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 4193 times.
✗ Branch 6 not taken.
8386 if ((iso8601[4] != '-') || (iso8601[7] != '-') || (iso8601[10] != 'T')
216
5/10
✓ Branch 0 taken 4193 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 4193 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 4193 times.
✗ Branch 7 not taken.
✗ Branch 9 not taken.
✓ Branch 10 taken 4193 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 4193 times.
8386 || (iso8601[13] != ':') || (iso8601[16] != ':') || (iso8601[19] != 'Z')) {
217 ✗ return utc_time;
218 }
219
220 struct tm tm_wl;
221 4193 memset(&tm_wl, 0, sizeof(struct tm));
222
2/4
✓ Branch 1 taken 4193 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 4193 times.
✗ Branch 5 not taken.
4193 tm_wl.tm_year = static_cast<int>(String2Int64(iso8601.substr(0, 4))) - 1900;
223
2/4
✓ Branch 1 taken 4193 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 4193 times.
✗ Branch 5 not taken.
4193 tm_wl.tm_mon = static_cast<int>(String2Int64(iso8601.substr(5, 2))) - 1;
224
2/4
✓ Branch 1 taken 4193 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 4193 times.
✗ Branch 5 not taken.
4193 tm_wl.tm_mday = static_cast<int>(String2Int64(iso8601.substr(8, 2)));
225
2/4
✓ Branch 1 taken 4193 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 4193 times.
✗ Branch 5 not taken.
4193 tm_wl.tm_hour = static_cast<int>(String2Int64(iso8601.substr(11, 2)));
226
2/4
✓ Branch 1 taken 4193 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 4193 times.
✗ Branch 5 not taken.
4193 tm_wl.tm_min = static_cast<int>(String2Int64(iso8601.substr(14, 2)));
227
2/4
✓ Branch 1 taken 4193 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 4193 times.
✗ Branch 5 not taken.
4193 tm_wl.tm_sec = static_cast<int>(String2Int64(iso8601.substr(17, 2)));
228 4193 utc_time = timegm(&tm_wl);
229
2/2
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 4179 times.
4193 if (utc_time < 0)
230 14 return 0;
231
232 4179 return utc_time;
233 }
234
235 38415 int64_t String2Int64(const string &value) {
236 int64_t result;
237 38415 sscanf(value.c_str(), "%" PRId64, &result);
238 38415 return result;
239 }
240
241 395588 uint64_t String2Uint64(const string &value) {
242 uint64_t result;
243
2/2
✓ Branch 1 taken 395552 times.
✓ Branch 2 taken 36 times.
395588 if (sscanf(value.c_str(), "%" PRIu64, &result) == 1) {
244 395552 return result;
245 }
246 36 return 0;
247 }
248
249 /**
250 * Parse a string into a a uint64_t.
251 *
252 * Unlike String2Uint64, this:
253 * - Checks to make sure the full string is parsed
254 * - Can indicate an error occurred.
255 *
256 * If an error occurs, this returns false and sets errno appropriately.
257 */
258 5156 bool String2Uint64Parse(const std::string &value, uint64_t *result) {
259 5156 char *endptr = NULL;
260 5156 errno = 0;
261 5156 long long myval = strtoll(value.c_str(), &endptr, 10); // NOLINT
262
2/2
✓ Branch 3 taken 4576 times.
✓ Branch 4 taken 544 times.
10276 if ((value.size() == 0) || (endptr != (value.c_str() + value.size()))
263
6/6
✓ Branch 0 taken 5120 times.
✓ Branch 1 taken 36 times.
✓ Branch 2 taken 28 times.
✓ Branch 3 taken 4548 times.
✓ Branch 4 taken 608 times.
✓ Branch 5 taken 4548 times.
10276 || (myval < 0)) {
264 608 errno = EINVAL;
265 608 return false;
266 }
267
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4548 times.
4548 if (errno) {
268 ✗ return false;
269 }
270
2/2
✓ Branch 0 taken 4520 times.
✓ Branch 1 taken 28 times.
4548 if (result) {
271 4520 *result = myval;
272 }
273 4548 return true;
274 }
275
276 96 void String2Uint64Pair(const string &value, uint64_t *a, uint64_t *b) {
277 96 sscanf(value.c_str(), "%" PRIu64 " %" PRIu64, a, b);
278 96 }
279
280 184357 bool HasPrefix(const string &str, const string &prefix,
281 const bool ignore_case) {
282
2/2
✓ Branch 2 taken 27869 times.
✓ Branch 3 taken 156488 times.
184357 if (prefix.length() > str.length())
283 27869 return false;
284
285
2/2
✓ Branch 1 taken 628458 times.
✓ Branch 2 taken 48281 times.
676739 for (unsigned i = 0, l = prefix.length(); i < l; ++i) {
286
2/2
✓ Branch 0 taken 138963 times.
✓ Branch 1 taken 489495 times.
628458 if (ignore_case) {
287
2/2
✓ Branch 2 taken 69945 times.
✓ Branch 3 taken 69018 times.
138963 if (toupper(str[i]) != toupper(prefix[i]))
288 69945 return false;
289 } else {
290
2/2
✓ Branch 2 taken 38262 times.
✓ Branch 3 taken 451233 times.
489495 if (str[i] != prefix[i])
291 38262 return false;
292 }
293 }
294 48281 return true;
295 }
296
297 12292 bool HasSuffix(const std::string &str, const std::string &suffix,
298 const bool ignore_case) {
299
2/2
✓ Branch 2 taken 299 times.
✓ Branch 3 taken 11993 times.
12292 if (suffix.size() > str.size())
300 299 return false;
301 11993 const IgnoreCaseComperator icmp;
302 return (ignore_case)
303
3/4
✓ Branch 0 taken 376 times.
✓ Branch 1 taken 11617 times.
✓ Branch 6 taken 376 times.
✗ Branch 7 not taken.
11993 ? std::equal(suffix.rbegin(), suffix.rend(), str.rbegin(), icmp)
304
1/2
✓ Branch 4 taken 11617 times.
✗ Branch 5 not taken.
11993 : std::equal(suffix.rbegin(), suffix.rend(), str.rbegin());
305 }
306
307 54951 vector<string> SplitString(const string &str, char delim) {
308 54951 return SplitStringBounded(0, str, delim);
309 }
310
311 55083 vector<string> SplitStringBounded(unsigned max_chunks, const string &str,
312 char delim) {
313 55083 vector<string> result;
314
315 // edge case... one chunk is always the whole string
316
2/2
✓ Branch 0 taken 22 times.
✓ Branch 1 taken 55061 times.
55083 if (1 == max_chunks) {
317
1/2
✓ Branch 1 taken 22 times.
✗ Branch 2 not taken.
22 result.push_back(str);
318 22 return result;
319 }
320
321 // split the string
322 55061 const unsigned size = str.size();
323 55061 unsigned marker = 0;
324 55061 unsigned chunks = 1;
325 unsigned i;
326
2/2
✓ Branch 0 taken 1127349 times.
✓ Branch 1 taken 55017 times.
1182366 for (i = 0; i < size; ++i) {
327
2/2
✓ Branch 1 taken 78023 times.
✓ Branch 2 taken 1049326 times.
1127349 if (str[i] == delim) {
328
2/4
✓ Branch 1 taken 78023 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 78023 times.
✗ Branch 5 not taken.
78023 result.push_back(str.substr(marker, i - marker));
329 78023 marker = i + 1;
330
331 // we got what we want... good bye
332
2/2
✓ Branch 0 taken 44 times.
✓ Branch 1 taken 77979 times.
78023 if (++chunks == max_chunks)
333 44 break;
334 }
335 }
336
337 // push the remainings of the string and return
338
2/4
✓ Branch 1 taken 55061 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 55061 times.
✗ Branch 5 not taken.
55061 result.push_back(str.substr(marker));
339 55061 return result;
340 }
341
342 99 vector<string> SplitStringMultiChar(const string &str, const string &delim) {
343 99 size_t pos_start = 0, pos_end = 0, delim_len = delim.length();
344 99 std::string substring;
345 99 std::vector<std::string> result;
346
347
2/2
✓ Branch 1 taken 273 times.
✓ Branch 2 taken 99 times.
372 while ((pos_end = str.find(delim, pos_start)) != string::npos) {
348
1/2
✓ Branch 1 taken 273 times.
✗ Branch 2 not taken.
273 substring = str.substr(pos_start, pos_end - pos_start);
349 273 pos_start = pos_end + delim_len;
350
1/2
✓ Branch 1 taken 273 times.
✗ Branch 2 not taken.
273 result.push_back(substring);
351 }
352
353
2/4
✓ Branch 1 taken 99 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 99 times.
✗ Branch 5 not taken.
99 result.push_back(str.substr(pos_start));
354 198 return result;
355 99 }
356
357 11830 string JoinStrings(const vector<string> &strings, const string &joint) {
358
1/2
✓ Branch 2 taken 11830 times.
✗ Branch 3 not taken.
11830 string result = "";
359 11830 const unsigned size = strings.size();
360
361
2/2
✓ Branch 0 taken 8793 times.
✓ Branch 1 taken 3037 times.
11830 if (size > 0) {
362
1/2
✓ Branch 2 taken 8793 times.
✗ Branch 3 not taken.
8793 result = strings[0];
363
2/2
✓ Branch 0 taken 756 times.
✓ Branch 1 taken 8793 times.
9549 for (unsigned i = 1; i < size; ++i)
364
2/4
✓ Branch 2 taken 756 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 756 times.
✗ Branch 6 not taken.
756 result += joint + strings[i];
365 }
366
367 11830 return result;
368 }
369
370 4709 void ParseKeyvalMem(const unsigned char *buffer, const unsigned buffer_size,
371 map<char, string> *content) {
372 4709 string line;
373 4709 unsigned pos = 0;
374
2/2
✓ Branch 0 taken 324370 times.
✓ Branch 1 taken 180 times.
324550 while (pos < buffer_size) {
375
2/2
✓ Branch 0 taken 28144 times.
✓ Branch 1 taken 296226 times.
324370 if (static_cast<char>(buffer[pos]) == '\n') {
376
2/2
✓ Branch 1 taken 4529 times.
✓ Branch 2 taken 23615 times.
28144 if (line == "--")
377 4529 return;
378
379
1/2
✓ Branch 1 taken 23615 times.
✗ Branch 2 not taken.
23615 if (line != "") {
380
3/11
✗ Branch 1 not taken.
✓ Branch 2 taken 23615 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 23615 times.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✓ Branch 11 taken 23615 times.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
23615 const string tail = (line.length() == 1) ? "" : line.substr(1);
381 // Special handling of 'Z' key because it can exist multiple times
382
3/4
✓ Branch 1 taken 23615 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 23571 times.
✓ Branch 4 taken 44 times.
23615 if (line[0] != 'Z') {
383
3/6
✓ Branch 1 taken 23571 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 23571 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 23571 times.
✗ Branch 8 not taken.
23571 (*content)[line[0]] = tail;
384 } else {
385
4/7
✓ Branch 2 taken 44 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 44 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 22 times.
✓ Branch 9 taken 22 times.
44 if (content->find(line[0]) == content->end()) {
386
3/6
✓ Branch 1 taken 22 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 22 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 22 times.
✗ Branch 8 not taken.
22 (*content)[line[0]] = tail;
387 } else {
388
6/12
✓ Branch 1 taken 22 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 22 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 22 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 22 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 22 times.
✗ Branch 14 not taken.
✓ Branch 16 taken 22 times.
✗ Branch 17 not taken.
22 (*content)[line[0]] = (*content)[line[0]] + "|" + tail;
389 }
390 }
391 23615 }
392
1/2
✓ Branch 1 taken 23615 times.
✗ Branch 2 not taken.
23615 line = "";
393 } else {
394
1/2
✓ Branch 1 taken 296226 times.
✗ Branch 2 not taken.
296226 line += static_cast<char>(buffer[pos]);
395 }
396 319841 pos++;
397 }
398
2/2
✓ Branch 1 taken 180 times.
✓ Branch 2 taken 4529 times.
4709 }
399
400 220 bool ParseKeyvalPath(const string &filename, map<char, string> *content) {
401
1/2
✓ Branch 2 taken 220 times.
✗ Branch 3 not taken.
220 const int fd = open(filename.c_str(), O_RDONLY);
402
2/2
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 209 times.
220 if (fd < 0)
403 11 return false;
404
405 unsigned char buffer[4096];
406
1/2
✓ Branch 1 taken 209 times.
✗ Branch 2 not taken.
209 const ssize_t num_bytes = read(fd, buffer, sizeof(buffer));
407
1/2
✓ Branch 1 taken 209 times.
✗ Branch 2 not taken.
209 close(fd);
408
409
3/4
✓ Branch 0 taken 198 times.
✓ Branch 1 taken 11 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 198 times.
209 if ((num_bytes <= 0) || (unsigned(num_bytes) >= sizeof(buffer)))
410 11 return false;
411
412
1/2
✓ Branch 1 taken 198 times.
✗ Branch 2 not taken.
198 ParseKeyvalMem(buffer, unsigned(num_bytes), content);
413 198 return true;
414 }
415
416 317996 string GetLineMem(const char *text, const int text_size) {
417 317996 int pos = 0;
418
4/4
✓ Branch 0 taken 13329755 times.
✓ Branch 1 taken 692 times.
✓ Branch 2 taken 13012451 times.
✓ Branch 3 taken 317304 times.
13330447 while ((pos < text_size) && (text[pos] != '\n'))
419 13012451 pos++;
420
1/2
✓ Branch 2 taken 317996 times.
✗ Branch 3 not taken.
317996 return string(text, pos);
421 }
422
423 1151321 bool GetLineFile(FILE *f, std::string *line) {
424 int retval;
425 1151321 line->clear();
426 while (true) {
427 80885944 retval = fgetc(f);
428
2/6
✗ Branch 1 not taken.
✓ Branch 2 taken 80885944 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 80885944 times.
80885944 if (ferror(f) && (errno == EINTR)) {
429 ✗ clearerr(f);
430 ✗ continue;
431
2/2
✓ Branch 0 taken 5063 times.
✓ Branch 1 taken 80880881 times.
80885944 } else if (retval == EOF) {
432 5063 break;
433 }
434 80880881 const char c = static_cast<char>(retval);
435
2/2
✓ Branch 0 taken 1146258 times.
✓ Branch 1 taken 79734623 times.
80880881 if (c == '\n')
436 1146258 break;
437 79734623 line->push_back(c);
438 79734623 }
439
4/4
✓ Branch 0 taken 5063 times.
✓ Branch 1 taken 1146258 times.
✓ Branch 3 taken 819 times.
✓ Branch 4 taken 4244 times.
1151321 return (retval != EOF) || !line->empty();
440 }
441
442 4803 bool GetLineFd(const int fd, std::string *line) {
443 ssize_t retval;
444 char c;
445 4803 line->clear();
446 while (true) {
447
1/2
✓ Branch 1 taken 124733 times.
✗ Branch 2 not taken.
124733 retval = read(fd, &c, 1);
448
2/2
✓ Branch 0 taken 53 times.
✓ Branch 1 taken 124680 times.
124733 if (retval == 0) {
449 53 break;
450 }
451
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 124680 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
124680 if ((retval == -1) && (errno == EINTR)) {
452 ✗ continue;
453 }
454
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 124680 times.
124680 if (retval == -1) {
455 ✗ break;
456 }
457
2/2
✓ Branch 0 taken 4750 times.
✓ Branch 1 taken 119930 times.
124680 if (c == '\n')
458 4750 break;
459
1/2
✓ Branch 1 taken 119930 times.
✗ Branch 2 not taken.
119930 line->push_back(c);
460 }
461
4/4
✓ Branch 0 taken 53 times.
✓ Branch 1 taken 4750 times.
✓ Branch 3 taken 31 times.
✓ Branch 4 taken 22 times.
4803 return (retval == 1) || !line->empty();
462 }
463
464 /**
465 * Removes leading and trailing whitespaces.
466 */
467 45135 string Trim(const string &raw, bool trim_newline) {
468
2/2
✓ Branch 1 taken 3758 times.
✓ Branch 2 taken 41377 times.
45135 if (raw.empty())
469
1/2
✓ Branch 2 taken 3758 times.
✗ Branch 3 not taken.
3758 return "";
470
471 41377 unsigned start_pos = 0;
472 46273 for (; (start_pos < raw.length())
473
7/8
✓ Branch 0 taken 45877 times.
✓ Branch 1 taken 396 times.
✓ Branch 3 taken 41784 times.
✓ Branch 4 taken 4093 times.
✓ Branch 6 taken 41784 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 4896 times.
✓ Branch 9 taken 41377 times.
88057 && (raw[start_pos] == ' ' || raw[start_pos] == '\t'
474
2/2
✓ Branch 0 taken 11865 times.
✓ Branch 1 taken 29919 times.
41784 || (trim_newline
475
4/4
✓ Branch 1 taken 11469 times.
✓ Branch 2 taken 396 times.
✓ Branch 4 taken 407 times.
✓ Branch 5 taken 11062 times.
11865 && (raw[start_pos] == '\n' || raw[start_pos] == '\r')));
476 ++start_pos) {
477 }
478 41377 unsigned end_pos = raw.length() - 1; // at least one character in raw
479 56000 for (;
480 (end_pos >= start_pos)
481
7/8
✓ Branch 0 taken 55604 times.
✓ Branch 1 taken 396 times.
✓ Branch 3 taken 53991 times.
✓ Branch 4 taken 1613 times.
✓ Branch 6 taken 53991 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 14623 times.
✓ Branch 9 taken 41377 times.
109991 && (raw[end_pos] == ' ' || raw[end_pos] == '\t'
482
6/6
✓ Branch 0 taken 24072 times.
✓ Branch 1 taken 29919 times.
✓ Branch 3 taken 13097 times.
✓ Branch 4 taken 10975 times.
✓ Branch 6 taken 2035 times.
✓ Branch 7 taken 11062 times.
53991 || (trim_newline && (raw[end_pos] == '\n' || raw[end_pos] == '\r')));
483 --end_pos) {
484 }
485
486 41377 return raw.substr(start_pos, end_pos - start_pos + 1);
487 }
488
489 40 std::string TrimString(const std::string &path,
490 const std::string &toTrim,
491 const int trimMode) {
492 40 std::string trimmed = path;
493
1/2
✓ Branch 1 taken 40 times.
✗ Branch 2 not taken.
40 if (trimmed != toTrim) {
494
3/4
✓ Branch 1 taken 80 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 60 times.
✓ Branch 4 taken 20 times.
120 while ((trimMode & kTrimLeading) && HasPrefix(trimmed, toTrim, true)
495
5/6
✓ Branch 0 taken 80 times.
✓ Branch 1 taken 20 times.
✓ Branch 4 taken 60 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 60 times.
✓ Branch 7 taken 40 times.
180 && (trimmed.size() > toTrim.size())) {
496
1/2
✓ Branch 2 taken 60 times.
✗ Branch 3 not taken.
60 trimmed = trimmed.substr(toTrim.size());
497 }
498
3/4
✓ Branch 1 taken 60 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 40 times.
✓ Branch 4 taken 20 times.
100 while ((trimMode & kTrimTrailing) && HasSuffix(trimmed, toTrim, true)
499
5/6
✓ Branch 0 taken 60 times.
✓ Branch 1 taken 20 times.
✓ Branch 4 taken 40 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 40 times.
✓ Branch 7 taken 40 times.
140 && (trimmed.size() > toTrim.size())) {
500
1/2
✓ Branch 3 taken 40 times.
✗ Branch 4 not taken.
40 trimmed = trimmed.substr(0, trimmed.size() - toTrim.size());
501 }
502 }
503 40 return trimmed;
504 }
505
506 /**
507 * Converts all characters to upper case
508 */
509 4395 string ToUpper(const string &mixed_case) {
510 4395 string result(mixed_case);
511
2/2
✓ Branch 1 taken 10110 times.
✓ Branch 2 taken 4395 times.
14505 for (unsigned i = 0, l = result.length(); i < l; ++i) {
512
2/4
✓ Branch 1 taken 10110 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 10110 times.
✗ Branch 5 not taken.
10110 result[i] = static_cast<char>(toupper(result[i]));
513 }
514 4395 return result;
515 }
516
517 3962 string ReplaceAll(const string &haystack, const string &needle,
518 const string &replace_by) {
519 3962 string result(haystack);
520 3962 size_t pos = 0;
521 3962 const unsigned needle_size = needle.size();
522
2/2
✓ Branch 1 taken 13 times.
✓ Branch 2 taken 3949 times.
3962 if (needle == "")
523 13 return result;
524
525
2/2
✓ Branch 1 taken 2293 times.
✓ Branch 2 taken 3949 times.
6242 while ((pos = result.find(needle, pos)) != string::npos)
526
1/2
✓ Branch 1 taken 2293 times.
✗ Branch 2 not taken.
2293 result.replace(pos, needle_size, replace_by);
527 3949 return result;
528 }
529
530 284930 static inline void Base64Block(const unsigned char input[3], const char *table,
531 char output[4]) {
532 284930 output[0] = table[(input[0] & 0xFD) >> 2];
533 284930 output[1] = table[((input[0] & 0x03) << 4) | ((input[1] & 0xF0) >> 4)];
534 284930 output[2] = table[((input[1] & 0x0F) << 2) | ((input[2] & 0xD0) >> 6)];
535 284930 output[3] = table[input[2] & 0x3F];
536 284930 }
537
538 19934 string Base64(const string &data) {
539 19934 string result;
540
1/2
✓ Branch 2 taken 19934 times.
✗ Branch 3 not taken.
19934 result.reserve((data.length() + 3) * 4 / 3);
541 19934 unsigned pos = 0;
542 const unsigned char *data_ptr = reinterpret_cast<const unsigned char *>(
543 19934 data.data());
544 19934 const unsigned length = data.length();
545
2/2
✓ Branch 0 taken 265534 times.
✓ Branch 1 taken 19934 times.
285468 while (pos + 2 < length) {
546 char encoded_block[4];
547 265534 Base64Block(data_ptr + pos, b64_table, encoded_block);
548
1/2
✓ Branch 1 taken 265534 times.
✗ Branch 2 not taken.
265534 result.append(encoded_block, 4);
549 265534 pos += 3;
550 }
551
2/2
✓ Branch 0 taken 19396 times.
✓ Branch 1 taken 538 times.
19934 if (length % 3 != 0) {
552 unsigned char input[3];
553 19396 input[0] = data_ptr[pos];
554
2/2
✓ Branch 0 taken 12846 times.
✓ Branch 1 taken 6550 times.
19396 input[1] = ((length % 3) == 2) ? data_ptr[pos + 1] : 0;
555 19396 input[2] = 0;
556 char encoded_block[4];
557 19396 Base64Block(input, b64_table, encoded_block);
558
1/2
✓ Branch 1 taken 19396 times.
✗ Branch 2 not taken.
19396 result.append(encoded_block, 2);
559
3/4
✓ Branch 0 taken 12846 times.
✓ Branch 1 taken 6550 times.
✓ Branch 3 taken 19396 times.
✗ Branch 4 not taken.
19396 result.push_back(((length % 3) == 2) ? encoded_block[2] : '=');
560
1/2
✓ Branch 1 taken 19396 times.
✗ Branch 2 not taken.
19396 result.push_back('=');
561 }
562
563 19934 return result;
564 }
565
566 /**
567 * Safe encoding for URIs and path names: replace + by - and / by _
568 */
569 226 string Base64Url(const string &data) {
570 226 string base64 = Base64(data);
571
2/2
✓ Branch 1 taken 15400 times.
✓ Branch 2 taken 226 times.
15626 for (unsigned i = 0, l = base64.length(); i < l; ++i) {
572
3/4
✓ Branch 1 taken 15400 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 204 times.
✓ Branch 4 taken 15196 times.
15400 if (base64[i] == '+') {
573
1/2
✓ Branch 1 taken 204 times.
✗ Branch 2 not taken.
204 base64[i] = '-';
574
3/4
✓ Branch 1 taken 15196 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 136 times.
✓ Branch 4 taken 15060 times.
15196 } else if (base64[i] == '/') {
575
1/2
✓ Branch 1 taken 136 times.
✗ Branch 2 not taken.
136 base64[i] = '_';
576 }
577 }
578 226 return base64;
579 }
580
581 483375 static bool Debase64Block(const unsigned char input[4],
582 unsigned char output[3]) {
583 int32_t dec[4];
584
2/2
✓ Branch 0 taken 1933398 times.
✓ Branch 1 taken 483341 times.
2416739 for (int i = 0; i < 4; ++i) {
585 1933398 dec[i] = db64_table[input[i]];
586
2/2
✓ Branch 0 taken 34 times.
✓ Branch 1 taken 1933364 times.
1933398 if (dec[i] < 0)
587 34 return false;
588 }
589
590 483341 output[0] = (dec[0] << 2) | (dec[1] >> 4);
591 483341 output[1] = ((dec[1] & 0x0F) << 4) | (dec[2] >> 2);
592 483341 output[2] = ((dec[2] & 0x03) << 6) | dec[3];
593 483341 return true;
594 }
595
596 /**
597 * Can decode both base64 and base64url
598 */
599 2491 bool Debase64(const string &data, string *decoded) {
600 2491 decoded->clear();
601 2491 decoded->reserve((data.length() + 4) * 3 / 4);
602 2491 unsigned pos = 0;
603 const unsigned char *data_ptr = reinterpret_cast<const unsigned char *>(
604 2491 data.data());
605 2491 const unsigned length = data.length();
606
2/2
✓ Branch 0 taken 34 times.
✓ Branch 1 taken 2457 times.
2491 if (length == 0)
607 34 return true;
608
2/2
✓ Branch 0 taken 68 times.
✓ Branch 1 taken 2389 times.
2457 if ((length % 4) != 0)
609 68 return false;
610
611
2/2
✓ Branch 0 taken 483375 times.
✓ Branch 1 taken 2355 times.
485730 while (pos < length) {
612 unsigned char decoded_block[3];
613 483375 const bool retval = Debase64Block(data_ptr + pos, decoded_block);
614
2/2
✓ Branch 0 taken 34 times.
✓ Branch 1 taken 483341 times.
483375 if (!retval)
615 34 return false;
616
1/2
✓ Branch 1 taken 483341 times.
✗ Branch 2 not taken.
483341 decoded->append(reinterpret_cast<char *>(decoded_block), 3);
617 483341 pos += 4;
618 }
619
620
2/2
✓ Branch 0 taken 4710 times.
✓ Branch 1 taken 2355 times.
7065 for (int i = 0; i < 2; ++i) {
621 4710 pos--;
622
2/2
✓ Branch 1 taken 878 times.
✓ Branch 2 taken 3832 times.
4710 if (data[pos] == '=')
623 878 decoded->erase(decoded->length() - 1);
624 }
625 2355 return true;
626 }
627
628 /**
629 * Assumes that source is terminated by a newline
630 */
631 98 string Tail(const string &source, unsigned num_lines) {
632
6/6
✓ Branch 1 taken 70 times.
✓ Branch 2 taken 28 times.
✓ Branch 3 taken 14 times.
✓ Branch 4 taken 56 times.
✓ Branch 5 taken 42 times.
✓ Branch 6 taken 56 times.
98 if (source.empty() || (num_lines == 0))
633
1/2
✓ Branch 2 taken 42 times.
✗ Branch 3 not taken.
42 return "";
634
635 56 const int l = static_cast<int>(source.length());
636 56 int i = l - 1;
637
2/2
✓ Branch 0 taken 224 times.
✓ Branch 1 taken 42 times.
266 for (; i >= 0; --i) {
638 224 const char c = source.data()[i];
639
2/2
✓ Branch 0 taken 70 times.
✓ Branch 1 taken 154 times.
224 if (c == '\n') {
640
2/2
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 56 times.
70 if (num_lines == 0) {
641 14 return source.substr(i + 1);
642 }
643 56 num_lines--;
644 }
645 }
646 42 return source;
647 }
648
649 /**
650 * Get UTC Time.
651 *
652 * @param format format if timestamp (YYYY-MM-DD HH:MM:SS by default)
653 * @return a timestamp string on success, empty string on failure
654 */
655 ✗ std::string GetGMTimestamp(const std::string &format) {
656 struct tm time_ptr;
657 char date_and_time[100];
658 ✗ const time_t t = time(NULL);
659 ✗ gmtime_r(&t, &time_ptr); // take UTC
660 // return empty string if formatting fails
661 ✗ if (!strftime(date_and_time, 100, format.c_str(), &time_ptr)) {
662 ✗ return "";
663 }
664 ✗ std::string timestamp(date_and_time);
665 ✗ return timestamp;
666 }
667
668 #ifdef CVMFS_NAMESPACE_GUARD
669 } // namespace CVMFS_NAMESPACE_GUARD
670 #endif
671