• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

systemd / systemd / 12838801276

17 Jan 2025 09:12PM UTC coverage: 0.117%. Remained the same
12838801276

push

github

web-flow
udev: add --verbose option for 'udevadm test' and add more verbose logs (#36021)

split out of #35968.

0 of 380 new or added lines in 2 files covered. (0.0%)

713 existing lines in 8 files now uncovered.

478 of 407707 relevant lines covered (0.12%)

1.45 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/src/basic/hexdecoct.c
1
/* SPDX-License-Identifier: LGPL-2.1-or-later */
2

3
#include <ctype.h>
4
#include <errno.h>
5
#include <stdint.h>
6
#include <stdlib.h>
7

8
#include "alloc-util.h"
9
#include "hexdecoct.h"
10
#include "macro.h"
11
#include "memory-util.h"
12
#include "string-util.h"
13

14
char octchar(int x) {
×
15
        return '0' + (x & 7);
×
16
}
17

18
int unoctchar(char c) {
×
19

20
        if (c >= '0' && c <= '7')
×
21
                return c - '0';
×
22

23
        return -EINVAL;
24
}
25

26
char decchar(int x) {
×
27
        return '0' + (x % 10);
×
28
}
29

30
int undecchar(char c) {
×
31

32
        if (c >= '0' && c <= '9')
×
33
                return c - '0';
×
34

35
        return -EINVAL;
36
}
37

38
char hexchar(int x) {
×
39
        static const char table[] = "0123456789abcdef";
×
40

41
        return table[x & 15];
×
42
}
43

44
int unhexchar(char c) {
×
45

46
        if (c >= '0' && c <= '9')
×
47
                return c - '0';
×
48

49
        if (c >= 'a' && c <= 'f')
×
50
                return c - 'a' + 10;
×
51

52
        if (c >= 'A' && c <= 'F')
×
53
                return c - 'A' + 10;
×
54

55
        return -EINVAL;
56
}
57

58
char* hexmem(const void *p, size_t l) {
×
59
        const uint8_t *x;
×
60
        char *r, *z;
×
61

62
        assert(p || l == 0);
×
63

64
        z = r = new(char, l * 2 + 1);
×
65
        if (!r)
×
66
                return NULL;
67

68
        for (x = p; x && x < (const uint8_t*) p + l; x++) {
×
69
                *(z++) = hexchar(*x >> 4);
×
70
                *(z++) = hexchar(*x & 15);
×
71
        }
72

73
        *z = 0;
×
74
        return r;
×
75
}
76

77
static int unhex_next(const char **p, size_t *l) {
×
78
        int r;
×
79

80
        assert(p);
×
81
        assert(l);
×
82

83
        /* Find the next non-whitespace character, and decode it. We
84
         * greedily skip all preceding and all following whitespace. */
85

86
        for (;;) {
×
87
                if (*l == 0)
×
88
                        return -EPIPE;
89

90
                if (!strchr(WHITESPACE, **p))
×
91
                        break;
92

93
                /* Skip leading whitespace */
94
                (*p)++, (*l)--;
×
95
        }
96

97
        r = unhexchar(**p);
×
98
        if (r < 0)
×
99
                return r;
100

101
        for (;;) {
×
102
                (*p)++, (*l)--;
×
103

104
                if (*l == 0 || !strchr(WHITESPACE, **p))
×
105
                        break;
106

107
                /* Skip following whitespace */
108
        }
109

110
        return r;
111
}
112

113
int unhexmem_full(
×
114
                const char *p,
115
                size_t l,
116
                bool secure,
117
                void **ret_data,
118
                size_t *ret_len) {
119

120
        _cleanup_free_ uint8_t *buf = NULL;
×
121
        size_t buf_size;
×
122
        const char *x;
×
123
        uint8_t *z;
×
124

125
        assert(p || l == 0);
×
126

127
        if (l == SIZE_MAX)
×
128
                l = strlen(p);
×
129

130
        /* Note that the calculation of memory size is an upper boundary, as we ignore whitespace while decoding */
131
        buf_size = (l + 1) / 2 + 1;
×
132
        buf = malloc(buf_size);
×
133
        if (!buf)
×
134
                return -ENOMEM;
135

136
        CLEANUP_ERASE_PTR(secure ? &buf : NULL, buf_size);
×
137

138
        for (x = p, z = buf;;) {
×
139
                int a, b;
×
140

141
                a = unhex_next(&x, &l);
×
142
                if (a == -EPIPE) /* End of string */
×
143
                        break;
144
                if (a < 0)
×
145
                        return a;
146

147
                b = unhex_next(&x, &l);
×
148
                if (b < 0)
×
149
                        return b;
150

151
                *(z++) = (uint8_t) a << 4 | (uint8_t) b;
×
152
        }
153

154
        *z = 0;
×
155

156
        if (ret_len)
×
157
                *ret_len = (size_t) (z - buf);
×
158
        if (ret_data)
×
159
                *ret_data = TAKE_PTR(buf);
×
160

161
        return 0;
162
}
163

164
/* https://tools.ietf.org/html/rfc4648#section-6
165
 * Notice that base32hex differs from base32 in the alphabet it uses.
166
 * The distinction is that the base32hex representation preserves the
167
 * order of the underlying data when compared as bytestrings, this is
168
 * useful when representing NSEC3 hashes, as one can then verify the
169
 * order of hashes directly from their representation. */
170
char base32hexchar(int x) {
×
171
        static const char table[] = "0123456789"
×
172
                                    "ABCDEFGHIJKLMNOPQRSTUV";
173

174
        return table[x & 31];
×
175
}
176

177
int unbase32hexchar(char c) {
×
178
        unsigned offset;
×
179

180
        if (c >= '0' && c <= '9')
×
181
                return c - '0';
×
182

183
        offset = '9' - '0' + 1;
×
184

185
        if (c >= 'A' && c <= 'V')
×
186
                return c - 'A' + offset;
×
187

188
        return -EINVAL;
189
}
190

191
char* base32hexmem(const void *p, size_t l, bool padding) {
×
192
        char *r, *z;
×
193
        const uint8_t *x;
×
194
        size_t len;
×
195

196
        assert(p || l == 0);
×
197

198
        if (padding)
×
199
                /* five input bytes makes eight output bytes, padding is added so we must round up */
200
                len = 8 * (l + 4) / 5;
×
201
        else {
202
                /* same, but round down as there is no padding */
203
                len = 8 * l / 5;
×
204

205
                switch (l % 5) {
×
206
                case 4:
×
207
                        len += 7;
×
208
                        break;
×
209
                case 3:
×
210
                        len += 5;
×
211
                        break;
×
212
                case 2:
×
213
                        len += 4;
×
214
                        break;
×
215
                case 1:
×
216
                        len += 2;
×
217
                        break;
×
218
                }
219
        }
220

221
        z = r = malloc(len + 1);
×
222
        if (!r)
×
223
                return NULL;
224

225
        for (x = p; x < (const uint8_t*) p + (l / 5) * 5; x += 5) {
×
226
                /* x[0] == XXXXXXXX; x[1] == YYYYYYYY; x[2] == ZZZZZZZZ
227
                 * x[3] == QQQQQQQQ; x[4] == WWWWWWWW */
228
                *(z++) = base32hexchar(x[0] >> 3);                    /* 000XXXXX */
×
229
                *(z++) = base32hexchar((x[0] & 7) << 2 | x[1] >> 6);  /* 000XXXYY */
×
230
                *(z++) = base32hexchar((x[1] & 63) >> 1);             /* 000YYYYY */
×
231
                *(z++) = base32hexchar((x[1] & 1) << 4 | x[2] >> 4);  /* 000YZZZZ */
×
232
                *(z++) = base32hexchar((x[2] & 15) << 1 | x[3] >> 7); /* 000ZZZZQ */
×
233
                *(z++) = base32hexchar((x[3] & 127) >> 2);            /* 000QQQQQ */
×
234
                *(z++) = base32hexchar((x[3] & 3) << 3 | x[4] >> 5);  /* 000QQWWW */
×
235
                *(z++) = base32hexchar((x[4] & 31));                  /* 000WWWWW */
×
236
        }
237

238
        switch (l % 5) {
×
239
        case 4:
×
240
                *(z++) = base32hexchar(x[0] >> 3);                    /* 000XXXXX */
×
241
                *(z++) = base32hexchar((x[0] & 7) << 2 | x[1] >> 6);  /* 000XXXYY */
×
242
                *(z++) = base32hexchar((x[1] & 63) >> 1);             /* 000YYYYY */
×
243
                *(z++) = base32hexchar((x[1] & 1) << 4 | x[2] >> 4);   /* 000YZZZZ */
×
244
                *(z++) = base32hexchar((x[2] & 15) << 1 | x[3] >> 7); /* 000ZZZZQ */
×
245
                *(z++) = base32hexchar((x[3] & 127) >> 2);            /* 000QQQQQ */
×
246
                *(z++) = base32hexchar((x[3] & 3) << 3);              /* 000QQ000 */
×
247
                if (padding)
×
248
                        *(z++) = '=';
×
249

250
                break;
251

252
        case 3:
×
253
                *(z++) = base32hexchar(x[0] >> 3);                   /* 000XXXXX */
×
254
                *(z++) = base32hexchar((x[0] & 7) << 2 | x[1] >> 6); /* 000XXXYY */
×
255
                *(z++) = base32hexchar((x[1] & 63) >> 1);            /* 000YYYYY */
×
256
                *(z++) = base32hexchar((x[1] & 1) << 4 | x[2] >> 4); /* 000YZZZZ */
×
257
                *(z++) = base32hexchar((x[2] & 15) << 1);            /* 000ZZZZ0 */
×
258
                if (padding) {
×
259
                        *(z++) = '=';
×
260
                        *(z++) = '=';
×
261
                        *(z++) = '=';
×
262
                }
263

264
                break;
265

266
        case 2:
×
267
                *(z++) = base32hexchar(x[0] >> 3);                   /* 000XXXXX */
×
268
                *(z++) = base32hexchar((x[0] & 7) << 2 | x[1] >> 6); /* 000XXXYY */
×
269
                *(z++) = base32hexchar((x[1] & 63) >> 1);            /* 000YYYYY */
×
270
                *(z++) = base32hexchar((x[1] & 1) << 4);             /* 000Y0000 */
×
271
                if (padding) {
×
272
                        *(z++) = '=';
×
273
                        *(z++) = '=';
×
274
                        *(z++) = '=';
×
275
                        *(z++) = '=';
×
276
                }
277

278
                break;
279

280
        case 1:
×
281
                *(z++) = base32hexchar(x[0] >> 3);       /* 000XXXXX */
×
282
                *(z++) = base32hexchar((x[0] & 7) << 2); /* 000XXX00 */
×
283
                if (padding) {
×
284
                        *(z++) = '=';
×
285
                        *(z++) = '=';
×
286
                        *(z++) = '=';
×
287
                        *(z++) = '=';
×
288
                        *(z++) = '=';
×
289
                        *(z++) = '=';
×
290
                }
291

292
                break;
293
        }
294

295
        *z = 0;
×
296
        return r;
×
297
}
298

299
int unbase32hexmem(const char *p, size_t l, bool padding, void **mem, size_t *_len) {
×
300
        _cleanup_free_ uint8_t *r = NULL;
×
301
        int a, b, c, d, e, f, g, h;
×
302
        uint8_t *z;
×
303
        const char *x;
×
304
        size_t len;
×
305
        unsigned pad = 0;
×
306

307
        assert(p || l == 0);
×
308
        assert(mem);
×
309
        assert(_len);
×
310

311
        if (l == SIZE_MAX)
×
312
                l = strlen(p);
×
313

314
        /* padding ensures any base32hex input has input divisible by 8 */
315
        if (padding && l % 8 != 0)
×
316
                return -EINVAL;
317

318
        if (padding) {
319
                /* strip the padding */
320
                while (l > 0 && p[l - 1] == '=' && pad < 7) {
×
321
                        pad++;
×
322
                        l--;
×
323
                }
324
        }
325

326
        /* a group of eight input bytes needs five output bytes, in case of
327
         * padding we need to add some extra bytes */
328
        len = (l / 8) * 5;
×
329

330
        switch (l % 8) {
×
331
        case 7:
×
332
                len += 4;
×
333
                break;
×
334
        case 5:
×
335
                len += 3;
×
336
                break;
×
337
        case 4:
×
338
                len += 2;
×
339
                break;
×
340
        case 2:
×
341
                len += 1;
×
342
                break;
×
343
        case 0:
344
                break;
345
        default:
346
                return -EINVAL;
347
        }
348

349
        z = r = malloc(len + 1);
×
350
        if (!r)
×
351
                return -ENOMEM;
352

353
        for (x = p; x < p + (l / 8) * 8; x += 8) {
×
354
                /* a == 000XXXXX; b == 000YYYYY; c == 000ZZZZZ; d == 000WWWWW
355
                 * e == 000SSSSS; f == 000QQQQQ; g == 000VVVVV; h == 000RRRRR */
356
                a = unbase32hexchar(x[0]);
×
357
                if (a < 0)
×
358
                        return -EINVAL;
359

360
                b = unbase32hexchar(x[1]);
×
361
                if (b < 0)
×
362
                        return -EINVAL;
363

364
                c = unbase32hexchar(x[2]);
×
365
                if (c < 0)
×
366
                        return -EINVAL;
367

368
                d = unbase32hexchar(x[3]);
×
369
                if (d < 0)
×
370
                        return -EINVAL;
371

372
                e = unbase32hexchar(x[4]);
×
373
                if (e < 0)
×
374
                        return -EINVAL;
375

376
                f = unbase32hexchar(x[5]);
×
377
                if (f < 0)
×
378
                        return -EINVAL;
379

380
                g = unbase32hexchar(x[6]);
×
381
                if (g < 0)
×
382
                        return -EINVAL;
383

384
                h = unbase32hexchar(x[7]);
×
385
                if (h < 0)
×
386
                        return -EINVAL;
387

388
                *(z++) = (uint8_t) a << 3 | (uint8_t) b >> 2;                    /* XXXXXYYY */
×
389
                *(z++) = (uint8_t) b << 6 | (uint8_t) c << 1 | (uint8_t) d >> 4; /* YYZZZZZW */
×
390
                *(z++) = (uint8_t) d << 4 | (uint8_t) e >> 1;                    /* WWWWSSSS */
×
391
                *(z++) = (uint8_t) e << 7 | (uint8_t) f << 2 | (uint8_t) g >> 3; /* SQQQQQVV */
×
392
                *(z++) = (uint8_t) g << 5 | (uint8_t) h;                         /* VVVRRRRR */
×
393
        }
394

395
        switch (l % 8) {
×
396
        case 7:
×
397
                a = unbase32hexchar(x[0]);
×
398
                if (a < 0)
×
399
                        return -EINVAL;
400

401
                b = unbase32hexchar(x[1]);
×
402
                if (b < 0)
×
403
                        return -EINVAL;
404

405
                c = unbase32hexchar(x[2]);
×
406
                if (c < 0)
×
407
                        return -EINVAL;
408

409
                d = unbase32hexchar(x[3]);
×
410
                if (d < 0)
×
411
                        return -EINVAL;
412

413
                e = unbase32hexchar(x[4]);
×
414
                if (e < 0)
×
415
                        return -EINVAL;
416

417
                f = unbase32hexchar(x[5]);
×
418
                if (f < 0)
×
419
                        return -EINVAL;
420

421
                g = unbase32hexchar(x[6]);
×
422
                if (g < 0)
×
423
                        return -EINVAL;
424

425
                /* g == 000VV000 */
426
                if (g & 7)
×
427
                        return -EINVAL;
428

429
                *(z++) = (uint8_t) a << 3 | (uint8_t) b >> 2;                    /* XXXXXYYY */
×
430
                *(z++) = (uint8_t) b << 6 | (uint8_t) c << 1 | (uint8_t) d >> 4; /* YYZZZZZW */
×
431
                *(z++) = (uint8_t) d << 4 | (uint8_t) e >> 1;                    /* WWWWSSSS */
×
432
                *(z++) = (uint8_t) e << 7 | (uint8_t) f << 2 | (uint8_t) g >> 3; /* SQQQQQVV */
×
433

434
                break;
×
435
        case 5:
×
436
                a = unbase32hexchar(x[0]);
×
437
                if (a < 0)
×
438
                        return -EINVAL;
439

440
                b = unbase32hexchar(x[1]);
×
441
                if (b < 0)
×
442
                        return -EINVAL;
443

444
                c = unbase32hexchar(x[2]);
×
445
                if (c < 0)
×
446
                        return -EINVAL;
447

448
                d = unbase32hexchar(x[3]);
×
449
                if (d < 0)
×
450
                        return -EINVAL;
451

452
                e = unbase32hexchar(x[4]);
×
453
                if (e < 0)
×
454
                        return -EINVAL;
455

456
                /* e == 000SSSS0 */
457
                if (e & 1)
×
458
                        return -EINVAL;
459

460
                *(z++) = (uint8_t) a << 3 | (uint8_t) b >> 2;                    /* XXXXXYYY */
×
461
                *(z++) = (uint8_t) b << 6 | (uint8_t) c << 1 | (uint8_t) d >> 4; /* YYZZZZZW */
×
462
                *(z++) = (uint8_t) d << 4 | (uint8_t) e >> 1;                    /* WWWWSSSS */
×
463

464
                break;
×
465
        case 4:
×
466
                a = unbase32hexchar(x[0]);
×
467
                if (a < 0)
×
468
                        return -EINVAL;
469

470
                b = unbase32hexchar(x[1]);
×
471
                if (b < 0)
×
472
                        return -EINVAL;
473

474
                c = unbase32hexchar(x[2]);
×
475
                if (c < 0)
×
476
                        return -EINVAL;
477

478
                d = unbase32hexchar(x[3]);
×
479
                if (d < 0)
×
480
                        return -EINVAL;
481

482
                /* d == 000W0000 */
483
                if (d & 15)
×
484
                        return -EINVAL;
485

486
                *(z++) = (uint8_t) a << 3 | (uint8_t) b >> 2;                    /* XXXXXYYY */
×
487
                *(z++) = (uint8_t) b << 6 | (uint8_t) c << 1 | (uint8_t) d >> 4; /* YYZZZZZW */
×
488

489
                break;
×
490
        case 2:
×
491
                a = unbase32hexchar(x[0]);
×
492
                if (a < 0)
×
493
                        return -EINVAL;
494

495
                b = unbase32hexchar(x[1]);
×
496
                if (b < 0)
×
497
                        return -EINVAL;
498

499
                /* b == 000YYY00 */
500
                if (b & 3)
×
501
                        return -EINVAL;
502

503
                *(z++) = (uint8_t) a << 3 | (uint8_t) b >> 2; /* XXXXXYYY */
×
504

505
                break;
×
506
        case 0:
507
                break;
508
        default:
509
                return -EINVAL;
510
        }
511

512
        *z = 0;
×
513

514
        *mem = TAKE_PTR(r);
×
515
        *_len = len;
×
516

517
        return 0;
×
518
}
519

520
/* https://tools.ietf.org/html/rfc4648#section-4 */
521
char base64char(int x) {
×
522
        static const char table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
×
523
                                    "abcdefghijklmnopqrstuvwxyz"
524
                                    "0123456789+/";
525
        return table[x & 63];
×
526
}
527

528
/* This is almost base64char(), but not entirely, as it uses the "url and filename safe" alphabet,
529
 * since we don't want "/" appear in interface names (since interfaces appear in sysfs as filenames).
530
 * See section #5 of RFC 4648. */
531
char urlsafe_base64char(int x) {
×
532
        static const char table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
×
533
                                    "abcdefghijklmnopqrstuvwxyz"
534
                                    "0123456789-_";
535
        return table[x & 63];
×
536
}
537

538
int unbase64char(char c) {
×
539
        unsigned offset;
×
540

541
        if (c >= 'A' && c <= 'Z')
×
542
                return c - 'A';
×
543

544
        offset = 'Z' - 'A' + 1;
×
545

546
        if (c >= 'a' && c <= 'z')
×
547
                return c - 'a' + offset;
×
548

549
        offset += 'z' - 'a' + 1;
×
550

551
        if (c >= '0' && c <= '9')
×
552
                return c - '0' + offset;
×
553

554
        offset += '9' - '0' + 1;
×
555

556
        if (IN_SET(c, '+', '-')) /* Support both the regular and the URL safe character set (see above) */
×
557
                return offset;
558

559
        offset++;
×
560

561
        if (IN_SET(c, '/', '_')) /* ditto */
×
562
                return offset;
×
563

564
        return -EINVAL;
565
}
566

567
static void maybe_line_break(char **x, char *start, size_t line_break) {
×
568
        size_t n;
×
569

570
        assert(x);
×
571
        assert(*x);
×
572
        assert(start);
×
573
        assert(*x >= start);
×
574

575
        if (line_break == SIZE_MAX)
×
576
                return;
577

578
        n = *x - start;
×
579

580
        if (n % (line_break + 1) == line_break)
×
581
                *((*x)++) = '\n';
×
582
}
583

584
ssize_t base64mem_full(
×
585
                const void *p,
586
                size_t l,
587
                size_t line_break,
588
                char **ret) {
589

590
        const uint8_t *x;
×
591
        char *b, *z;
×
592
        size_t m;
×
593

594
        assert(p || l == 0);
×
595
        assert(line_break > 0);
×
596
        assert(ret);
×
597

598
        /* three input bytes makes four output bytes, padding is added so we must round up */
599
        m = 4 * (l + 2) / 3 + 1;
×
600
        if (line_break != SIZE_MAX)
×
601
                m += m / line_break;
×
602

603
        z = b = malloc(m);
×
604
        if (!b)
×
605
                return -ENOMEM;
×
606

607
        for (x = p; x && x < (const uint8_t*) p + (l / 3) * 3; x += 3) {
×
608
                /* x[0] == XXXXXXXX; x[1] == YYYYYYYY; x[2] == ZZZZZZZZ */
609
                maybe_line_break(&z, b, line_break);
×
610
                *(z++) = base64char(x[0] >> 2);                    /* 00XXXXXX */
×
611
                maybe_line_break(&z, b, line_break);
×
612
                *(z++) = base64char((x[0] & 3) << 4 | x[1] >> 4);  /* 00XXYYYY */
×
613
                maybe_line_break(&z, b, line_break);
×
614
                *(z++) = base64char((x[1] & 15) << 2 | x[2] >> 6); /* 00YYYYZZ */
×
615
                maybe_line_break(&z, b, line_break);
×
616
                *(z++) = base64char(x[2] & 63);                    /* 00ZZZZZZ */
×
617
        }
618

619
        switch (l % 3) {
×
620
        case 2:
×
621
                maybe_line_break(&z, b, line_break);
×
622
                *(z++) = base64char(x[0] >> 2);                   /* 00XXXXXX */
×
623
                maybe_line_break(&z, b, line_break);
×
624
                *(z++) = base64char((x[0] & 3) << 4 | x[1] >> 4); /* 00XXYYYY */
×
625
                maybe_line_break(&z, b, line_break);
×
626
                *(z++) = base64char((x[1] & 15) << 2);            /* 00YYYY00 */
×
627
                maybe_line_break(&z, b, line_break);
×
628
                *(z++) = '=';
×
629
                break;
×
630

631
        case 1:
×
632
                maybe_line_break(&z, b, line_break);
×
633
                *(z++) = base64char(x[0] >> 2);        /* 00XXXXXX */
×
634
                maybe_line_break(&z, b, line_break);
×
635
                *(z++) = base64char((x[0] & 3) << 4);  /* 00XX0000 */
×
636
                maybe_line_break(&z, b, line_break);
×
637
                *(z++) = '=';
×
638
                maybe_line_break(&z, b, line_break);
×
639
                *(z++) = '=';
×
640
                break;
×
641
        }
642

643
        *z = 0;
×
644
        *ret = b;
×
645

646
        assert(z >= b); /* Let static analyzers know that the answer is non-negative. */
×
647
        return z - b;
×
648
}
649

650
static ssize_t base64_append_width(
×
651
                char **prefix,
652
                size_t plen,
653
                char sep,
654
                size_t indent,
655
                const void *p,
656
                size_t l,
657
                size_t width) {
658

659
        _cleanup_free_ char *x = NULL;
×
660
        char *t, *s;
×
661
        size_t lines;
×
662
        ssize_t len;
×
663

664
        assert(prefix);
×
665
        assert(*prefix || plen == 0);
×
666
        assert(p || l == 0);
×
667

668
        len = base64mem(p, l, &x);
×
669
        if (len < 0)
×
670
                return len;
671
        if (len == 0)
×
672
                return plen;
×
673

674
        lines = DIV_ROUND_UP(len, width);
×
675

676
        if (plen >= SSIZE_MAX - 1 - 1 ||
×
677
            lines > (SSIZE_MAX - plen - 1 - 1) / (indent + width + 1))
×
678
                return -ENOMEM;
679

680
        t = realloc(*prefix, plen + 1 + 1 + (indent + width + 1) * lines);
×
681
        if (!t)
×
682
                return -ENOMEM;
683

684
        s = t + plen;
×
685
        for (size_t line = 0; line < lines; line++) {
×
686
                size_t act = MIN(width, (size_t) len);
×
687

688
                if (line > 0)
×
689
                        sep = '\n';
×
690

691
                if (s > t) {
×
692
                        *s++ = sep;
×
693
                        if (sep == '\n')
×
694
                                s = mempset(s, ' ', indent);
×
695
                }
696

697
                s = mempcpy(s, x + width * line, act);
×
698
                len -= act;
×
699
        }
700
        assert(len == 0);
×
701

702
        *s = '\0';
×
703
        *prefix = t;
×
704
        return s - t;
×
705
}
706

707
ssize_t base64_append(
×
708
                char **prefix,
709
                size_t plen,
710
                const void *p,
711
                size_t l,
712
                size_t indent,
713
                size_t width) {
714

715
        if (plen > width / 2 || plen + indent > width)
×
716
                /* leave indent on the left, keep last column free */
717
                return base64_append_width(prefix, plen, '\n', indent, p, l, width - indent);
×
718
        else
719
                /* leave plen on the left, keep last column free */
720
                return base64_append_width(prefix, plen, ' ', plen + 1, p, l, width - plen - 1);
×
721
}
722

723
static int unbase64_next(const char **p, size_t *l) {
×
724
        int ret;
×
725

726
        assert(p);
×
727
        assert(l);
×
728

729
        /* Find the next non-whitespace character, and decode it. If we find padding, we return it as INT_MAX. We
730
         * greedily skip all preceding and all following whitespace. */
731

732
        for (;;) {
×
733
                if (*l == 0)
×
734
                        return -EPIPE;
735

736
                if (!strchr(WHITESPACE, **p))
×
737
                        break;
738

739
                /* Skip leading whitespace */
740
                (*p)++, (*l)--;
×
741
        }
742

743
        if (**p == '=')
×
744
                ret = INT_MAX; /* return padding as INT_MAX */
×
745
        else {
746
                ret = unbase64char(**p);
×
747
                if (ret < 0)
×
748
                        return ret;
749
        }
750

751
        for (;;) {
×
752
                (*p)++, (*l)--;
×
753

754
                if (*l == 0)
×
755
                        break;
756
                if (!strchr(WHITESPACE, **p))
×
757
                        break;
758

759
                /* Skip following whitespace */
760
        }
761

762
        return ret;
763
}
764

765
int unbase64mem_full(
×
766
                const char *p,
767
                size_t l,
768
                bool secure,
769
                void **ret_data,
770
                size_t *ret_size) {
771

772
        _cleanup_free_ uint8_t *buf = NULL;
×
773
        const char *x;
×
774
        uint8_t *z;
×
775
        size_t len;
×
776

777
        assert(p || l == 0);
×
778

779
        if (l == SIZE_MAX)
×
780
                l = strlen(p);
×
781

782
        /* A group of four input bytes needs three output bytes, in case of padding we need to add two or three extra
783
         * bytes. Note that this calculation is an upper boundary, as we ignore whitespace while decoding */
784
        len = (l / 4) * 3 + (l % 4 != 0 ? (l % 4) - 1 : 0);
×
785

786
        buf = malloc(len + 1);
×
787
        if (!buf)
×
788
                return -ENOMEM;
789

790
        CLEANUP_ERASE_PTR(secure ? &buf : NULL, len);
×
791

792
        for (x = p, z = buf;;) {
×
793
                int a, b, c, d; /* a == 00XXXXXX; b == 00YYYYYY; c == 00ZZZZZZ; d == 00WWWWWW */
×
794

795
                a = unbase64_next(&x, &l);
×
796
                if (a == -EPIPE) /* End of string */
×
797
                        break;
798
                if (a < 0)
×
799
                        return a;
800
                if (a == INT_MAX) /* Padding is not allowed at the beginning of a 4ch block */
×
801
                        return -EINVAL;
802

803
                b = unbase64_next(&x, &l);
×
804
                if (b < 0)
×
805
                        return b;
806
                if (b == INT_MAX) /* Padding is not allowed at the second character of a 4ch block either */
×
807
                        return -EINVAL;
808

809
                c = unbase64_next(&x, &l);
×
810
                if (c < 0)
×
811
                        return c;
812

813
                d = unbase64_next(&x, &l);
×
814
                if (d < 0)
×
815
                        return d;
816

817
                if (c == INT_MAX) { /* Padding at the third character */
×
818

819
                        if (d != INT_MAX) /* If the third character is padding, the fourth must be too */
×
820
                                return -EINVAL;
821

822
                        /* b == 00YY0000 */
823
                        if (b & 15)
×
824
                                return -EINVAL;
825

826
                        if (l > 0) /* Trailing rubbish? */
×
827
                                return -ENAMETOOLONG;
828

829
                        *(z++) = (uint8_t) a << 2 | (uint8_t) (b >> 4); /* XXXXXXYY */
×
830
                        break;
×
831
                }
832

833
                if (d == INT_MAX) {
×
834
                        /* c == 00ZZZZ00 */
835
                        if (c & 3)
×
836
                                return -EINVAL;
837

838
                        if (l > 0) /* Trailing rubbish? */
×
839
                                return -ENAMETOOLONG;
840

841
                        *(z++) = (uint8_t) a << 2 | (uint8_t) b >> 4; /* XXXXXXYY */
×
842
                        *(z++) = (uint8_t) b << 4 | (uint8_t) c >> 2; /* YYYYZZZZ */
×
843
                        break;
×
844
                }
845

846
                *(z++) = (uint8_t) a << 2 | (uint8_t) b >> 4; /* XXXXXXYY */
×
847
                *(z++) = (uint8_t) b << 4 | (uint8_t) c >> 2; /* YYYYZZZZ */
×
848
                *(z++) = (uint8_t) c << 6 | (uint8_t) d;      /* ZZWWWWWW */
×
849
        }
850

851
        *z = 0;
×
852

853
        assert((size_t) (z - buf) <= len);
×
854

855
        if (ret_size)
×
856
                *ret_size = (size_t) (z - buf);
×
857
        if (ret_data)
×
858
                *ret_data = TAKE_PTR(buf);
×
859

860
        return 0;
861
}
862

863
void hexdump(FILE *f, const void *p, size_t s) {
×
864
        const uint8_t *b = p;
×
865
        unsigned n = 0;
×
866

867
        assert(b || s == 0);
×
868

869
        if (s == SIZE_MAX)
×
870
                s = strlen(p);
×
871

872
        if (!f)
×
873
                f = stdout;
×
874

875
        while (s > 0) {
×
UNCOV
876
                size_t i;
×
877

UNCOV
878
                fprintf(f, "%04x  ", n);
×
879

880
                for (i = 0; i < 16; i++) {
×
881

882
                        if (i >= s)
×
UNCOV
883
                                fputs("   ", f);
×
884
                        else
885
                                fprintf(f, "%02x ", b[i]);
×
886

UNCOV
887
                        if (i == 7)
×
888
                                fputc(' ', f);
×
889
                }
890

UNCOV
891
                fputc(' ', f);
×
892

893
                for (i = 0; i < 16; i++) {
×
894

895
                        if (i >= s)
×
UNCOV
896
                                fputc(' ', f);
×
897
                        else
898
                                fputc(isprint(b[i]) ? (char) b[i] : '.', f);
×
899
                }
900

UNCOV
901
                fputc('\n', f);
×
902

903
                if (s < 16)
×
904
                        break;
905

UNCOV
906
                n += 16;
×
907
                b += 16;
×
UNCOV
908
                s -= 16;
×
909
        }
UNCOV
910
}
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc