GCC Code Coverage Report


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