summaryrefslogtreecommitdiff
path: root/src/basic
diff options
context:
space:
mode:
Diffstat (limited to 'src/basic')
-rw-r--r--src/basic/bitmap.c197
-rw-r--r--src/basic/bitmap.h50
-rw-r--r--src/basic/macro.h8
-rw-r--r--src/basic/missing.h34
-rw-r--r--src/basic/path-util.c6
-rw-r--r--src/basic/util.c548
-rw-r--r--src/basic/util.h12
7 files changed, 840 insertions, 15 deletions
diff --git a/src/basic/bitmap.c b/src/basic/bitmap.c
new file mode 100644
index 0000000000..7e47c2d09f
--- /dev/null
+++ b/src/basic/bitmap.c
@@ -0,0 +1,197 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+ This file is part of systemd.
+
+ Copyright 2015 Tom Gundersen
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include "util.h"
+
+#include "bitmap.h"
+
+struct Bitmap {
+ long long unsigned *bitmaps;
+ size_t n_bitmaps;
+ size_t bitmaps_allocated;
+};
+
+/* Bitmaps are only meant to store relatively small numbers
+ * (corresponding to, say, an enum), so it is ok to limit
+ * the max entry. 64k should be plenty. */
+#define BITMAPS_MAX_ENTRY 0xffff
+
+/* This indicates that we reached the end of the bitmap */
+#define BITMAP_END ((unsigned) -1)
+
+#define BITMAP_NUM_TO_OFFSET(n) ((n) / (sizeof(long long unsigned) * 8))
+#define BITMAP_NUM_TO_REM(n) ((n) % (sizeof(long long unsigned) * 8))
+#define BITMAP_OFFSET_TO_NUM(offset, rem) ((offset) * sizeof(long long unsigned) * 8 + (rem))
+
+Bitmap *bitmap_new(void) {
+ return new0(Bitmap, 1);
+}
+
+void bitmap_free(Bitmap *b) {
+ if (!b)
+ return;
+
+ free(b->bitmaps);
+ free(b);
+}
+
+int bitmap_ensure_allocated(Bitmap **b) {
+ Bitmap *a;
+
+ if (*b)
+ return 0;
+
+ a = bitmap_new();
+ if (!a)
+ return -ENOMEM;
+
+ *b = a;
+
+ return 0;
+}
+
+int bitmap_set(Bitmap *b, unsigned n) {
+ long long unsigned bitmask;
+ unsigned offset;
+
+ assert(b);
+
+ /* we refuse to allocate huge bitmaps */
+ if (n > BITMAPS_MAX_ENTRY)
+ return -ERANGE;
+
+ offset = BITMAP_NUM_TO_OFFSET(n);
+
+ if (offset >= b->n_bitmaps) {
+ if (!GREEDY_REALLOC0(b->bitmaps, b->bitmaps_allocated, offset + 1))
+ return -ENOMEM;
+
+ b->n_bitmaps = offset + 1;
+ }
+
+ bitmask = 1ULL << BITMAP_NUM_TO_REM(n);
+
+ b->bitmaps[offset] |= bitmask;
+
+ return 0;
+}
+
+void bitmap_unset(Bitmap *b, unsigned n) {
+ long long unsigned bitmask;
+ unsigned offset;
+
+ assert(b);
+
+ offset = BITMAP_NUM_TO_OFFSET(n);
+
+ if (offset >= b->n_bitmaps)
+ return;
+
+ bitmask = 1ULL << BITMAP_NUM_TO_REM(n);
+
+ b->bitmaps[offset] &= ~bitmask;
+}
+
+bool bitmap_isset(Bitmap *b, unsigned n) {
+ long long unsigned bitmask;
+ unsigned offset;
+
+ if (!b || !b->bitmaps)
+ return false;
+
+ offset = BITMAP_NUM_TO_OFFSET(n);
+
+ if (offset >= b->n_bitmaps)
+ return false;
+
+ bitmask = 1ULL << BITMAP_NUM_TO_REM(n);
+
+ return !!(b->bitmaps[offset] & bitmask);
+}
+
+bool bitmap_isclear(Bitmap *b) {
+ unsigned i;
+
+ assert(b);
+
+ for (i = 0; i < b->n_bitmaps; i++)
+ if (b->bitmaps[i])
+ return false;
+
+ return true;
+}
+
+void bitmap_clear(Bitmap *b) {
+ assert(b);
+
+ b->n_bitmaps = 0;
+}
+
+bool bitmap_iterate(Bitmap *b, Iterator *i, unsigned *n) {
+ long long unsigned bitmask;
+ unsigned offset, rem;
+
+ if (!b || i->idx == BITMAP_END)
+ return false;
+
+ offset = BITMAP_NUM_TO_OFFSET(i->idx);
+ rem = BITMAP_NUM_TO_REM(i->idx);
+ bitmask = 1ULL << rem;
+
+ for (; offset < b->n_bitmaps; offset ++) {
+ if (b->bitmaps[offset]) {
+ for (; bitmask; bitmask <<= 1, rem ++) {
+ if (b->bitmaps[offset] & bitmask) {
+ *n = BITMAP_OFFSET_TO_NUM(offset, rem);
+ i->idx = *n + 1;
+
+ return true;
+ }
+ }
+ }
+
+ rem = 0;
+ bitmask = 1;
+ }
+
+ i->idx = BITMAP_END;
+
+ return false;
+}
+
+bool bitmap_equal(Bitmap *a, Bitmap *b) {
+ unsigned i;
+
+ if (!a ^ !b)
+ return false;
+
+ if (!a)
+ return true;
+
+ if (a->n_bitmaps != b->n_bitmaps)
+ return false;
+
+ for (i = 0; i < a->n_bitmaps; i++)
+ if (a->bitmaps[i] != b->bitmaps[i])
+ return false;
+
+ return true;
+}
diff --git a/src/basic/bitmap.h b/src/basic/bitmap.h
new file mode 100644
index 0000000000..2874bc99f7
--- /dev/null
+++ b/src/basic/bitmap.h
@@ -0,0 +1,50 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#pragma once
+
+/***
+ This file is part of systemd.
+
+ Copyright 2015 Tom Gundersen
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include "macro.h"
+#include "hashmap.h"
+
+typedef struct Bitmap Bitmap;
+
+Bitmap *bitmap_new(void);
+
+void bitmap_free(Bitmap *b);
+
+int bitmap_ensure_allocated(Bitmap **b);
+
+int bitmap_set(Bitmap *b, unsigned n);
+void bitmap_unset(Bitmap *b, unsigned n);
+bool bitmap_isset(Bitmap *b, unsigned n);
+bool bitmap_isclear(Bitmap *b);
+void bitmap_clear(Bitmap *b);
+
+bool bitmap_iterate(Bitmap *b, Iterator *i, unsigned *n);
+
+bool bitmap_equal(Bitmap *a, Bitmap *b);
+
+#define BITMAP_FOREACH(n, b, i) \
+ for ((i).idx = 0; bitmap_iterate((b), &(i), (unsigned*)&(n)); )
+
+DEFINE_TRIVIAL_CLEANUP_FUNC(Bitmap*, bitmap_free);
+
+#define _cleanup_bitmap_free_ _cleanup_(bitmap_freep)
diff --git a/src/basic/macro.h b/src/basic/macro.h
index 58530a3980..627d768b76 100644
--- a/src/basic/macro.h
+++ b/src/basic/macro.h
@@ -407,12 +407,12 @@ do { \
#define IN_SET(x, y, ...) \
({ \
- const typeof(y) _y = (y); \
- const typeof(_y) _x = (x); \
+ static const typeof(y) _array[] = { (y), __VA_ARGS__ }; \
+ const typeof(y) _x = (x); \
unsigned _i; \
bool _found = false; \
- for (_i = 0; _i < 1 + sizeof((const typeof(_x)[]) { __VA_ARGS__ })/sizeof(const typeof(_x)); _i++) \
- if (((const typeof(_x)[]) { _y, __VA_ARGS__ })[_i] == _x) { \
+ for (_i = 0; _i < ELEMENTSOF(_array); _i++) \
+ if (_array[_i] == _x) { \
_found = true; \
break; \
} \
diff --git a/src/basic/missing.h b/src/basic/missing.h
index be7f6186fc..bd49f10e76 100644
--- a/src/basic/missing.h
+++ b/src/basic/missing.h
@@ -772,7 +772,7 @@ static inline int setns(int fd, int nstype) {
#define IFLA_VXLAN_MAX (__IFLA_VXLAN_MAX - 1)
#endif
-#if !HAVE_DECL_IFLA_IPTUN_6RD_RELAY_PREFIXLEN
+#if !HAVE_DECL_IFLA_IPTUN_ENCAP_DPORT
#define IFLA_IPTUN_UNSPEC 0
#define IFLA_IPTUN_LINK 1
#define IFLA_IPTUN_LOCAL 2
@@ -788,11 +788,41 @@ static inline int setns(int fd, int nstype) {
#define IFLA_IPTUN_6RD_RELAY_PREFIX 12
#define IFLA_IPTUN_6RD_PREFIXLEN 13
#define IFLA_IPTUN_6RD_RELAY_PREFIXLEN 14
-#define __IFLA_IPTUN_MAX 15
+#define IFLA_IPTUN_ENCAP_TYPE 15
+#define IFLA_IPTUN_ENCAP_FLAGS 16
+#define IFLA_IPTUN_ENCAP_SPORT 17
+#define IFLA_IPTUN_ENCAP_DPORT 18
+
+#define __IFLA_IPTUN_MAX 19
#define IFLA_IPTUN_MAX (__IFLA_IPTUN_MAX - 1)
#endif
+#if !HAVE_DECL_IFLA_GRE_ENCAP_DPORT
+#define IFLA_GRE_UNSPEC 0
+#define IFLA_GRE_LINK 1
+#define IFLA_GRE_IFLAGS 2
+#define IFLA_GRE_OFLAGS 3
+#define IFLA_GRE_IKEY 4
+#define IFLA_GRE_OKEY 5
+#define IFLA_GRE_LOCAL 6
+#define IFLA_GRE_REMOTE 7
+#define IFLA_GRE_TTL 8
+#define IFLA_GRE_TOS 9
+#define IFLA_GRE_PMTUDISC 10
+#define IFLA_GRE_ENCAP_LIMIT 11
+#define IFLA_GRE_FLOWINFO 12
+#define IFLA_GRE_FLAGS 13
+#define IFLA_GRE_ENCAP_TYPE 14
+#define IFLA_GRE_ENCAP_FLAGS 15
+#define IFLA_GRE_ENCAP_SPORT 16
+#define IFLA_GRE_ENCAP_DPORT 17
+
+#define __IFLA_GRE_MAX 18
+
+#define IFLA_GRE_MAX (__IFLA_GRE_MAX - 1)
+#endif
+
#if !HAVE_DECL_IFLA_BRIDGE_VLAN_INFO
#define IFLA_BRIDGE_FLAGS 0
#define IFLA_BRIDGE_MODE 1
diff --git a/src/basic/path-util.c b/src/basic/path-util.c
index 8f49d65266..5cbfc145a4 100644
--- a/src/basic/path-util.c
+++ b/src/basic/path-util.c
@@ -656,9 +656,11 @@ int path_is_mount_point(const char *t, int flags) {
canonical = canonicalize_file_name(t);
if (!canonical)
return -errno;
+
+ t = canonical;
}
- r = path_get_parent(canonical ?: t, &parent);
+ r = path_get_parent(t, &parent);
if (r < 0)
return r;
@@ -666,7 +668,7 @@ int path_is_mount_point(const char *t, int flags) {
if (fd < 0)
return -errno;
- return fd_is_mount_point(fd, basename(canonical ?: t), flags);
+ return fd_is_mount_point(fd, basename(t), flags);
}
int path_is_read_only_fs(const char *path) {
diff --git a/src/basic/util.c b/src/basic/util.c
index c88cd1d38a..dc20fa9baf 100644
--- a/src/basic/util.c
+++ b/src/basic/util.c
@@ -916,32 +916,568 @@ char *hexmem(const void *p, size_t l) {
return r;
}
-void *unhexmem(const char *p, size_t l) {
- uint8_t *r, *z;
+int unhexmem(const char *p, size_t l, void **mem, size_t *len) {
+ _cleanup_free_ uint8_t *r = NULL;
+ uint8_t *z;
const char *x;
+ assert(mem);
+ assert(len);
assert(p);
z = r = malloc((l + 1) / 2 + 1);
if (!r)
- return NULL;
+ return -ENOMEM;
for (x = p; x < p + l; x += 2) {
int a, b;
a = unhexchar(x[0]);
- if (x+1 < p + l)
+ if (a < 0)
+ return a;
+ else if (x+1 < p + l) {
b = unhexchar(x[1]);
- else
+ if (b < 0)
+ return b;
+ } else
b = 0;
*(z++) = (uint8_t) a << 4 | (uint8_t) b;
}
*z = 0;
+
+ *mem = r;
+ r = NULL;
+ *len = (l + 1) / 2;
+
+ return 0;
+}
+
+/* https://tools.ietf.org/html/rfc4648#section-6 */
+char base32hexchar(int x) {
+ static const char table[32] = "0123456789"
+ "ABCDEFGHIJKLMNOPQRSTUV";
+
+ return table[x & 31];
+}
+
+int unbase32hexchar(char c) {
+ unsigned offset;
+
+ if (c >= '0' && c <= '9')
+ return c - '0';
+
+ offset = '9' - '0' + 1;
+
+ if (c >= 'A' && c <= 'V')
+ return c - 'A' + offset;
+
+ return -EINVAL;
+}
+
+char *base32hexmem(const void *p, size_t l, bool padding) {
+ char *r, *z;
+ const uint8_t *x;
+ size_t len;
+
+ if (padding)
+ /* five input bytes makes eight output bytes, padding is added so we must round up */
+ len = 8 * (l + 4) / 5;
+ else {
+ /* same, but round down as there is no padding */
+ len = 8 * l / 5;
+
+ switch (l % 5) {
+ case 4:
+ len += 7;
+ break;
+ case 3:
+ len += 5;
+ break;
+ case 2:
+ len += 4;
+ break;
+ case 1:
+ len += 2;
+ break;
+ }
+ }
+
+ z = r = malloc(len + 1);
+ if (!r)
+ return NULL;
+
+ for (x = p; x < (const uint8_t*) p + (l / 5) * 5; x += 5) {
+ /* x[0] == XXXXXXXX; x[1] == YYYYYYYY; x[2] == ZZZZZZZZ
+ x[3] == QQQQQQQQ; x[4] == WWWWWWWW */
+ *(z++) = base32hexchar(x[0] >> 3); /* 000XXXXX */
+ *(z++) = base32hexchar((x[0] & 7) << 2 | x[1] >> 6); /* 000XXXYY */
+ *(z++) = base32hexchar((x[1] & 63) >> 1); /* 000YYYYY */
+ *(z++) = base32hexchar((x[1] & 1) << 4 | x[2] >> 4); /* 000YZZZZ */
+ *(z++) = base32hexchar((x[2] & 15) << 1 | x[3] >> 7); /* 000ZZZZQ */
+ *(z++) = base32hexchar((x[3] & 127) >> 2); /* 000QQQQQ */
+ *(z++) = base32hexchar((x[3] & 3) << 3 | x[4] >> 5); /* 000QQWWW */
+ *(z++) = base32hexchar((x[4] & 31)); /* 000WWWWW */
+ }
+
+ switch (l % 5) {
+ case 4:
+ *(z++) = base32hexchar(x[0] >> 3); /* 000XXXXX */
+ *(z++) = base32hexchar((x[0] & 7) << 2 | x[1] >> 6); /* 000XXXYY */
+ *(z++) = base32hexchar((x[1] & 63) >> 1); /* 000YYYYY */
+ *(z++) = base32hexchar((x[1] & 1) << 4 | x[2] >> 4); /* 000YZZZZ */
+ *(z++) = base32hexchar((x[2] & 15) << 1 | x[3] >> 7); /* 000ZZZZQ */
+ *(z++) = base32hexchar((x[3] & 127) >> 2); /* 000QQQQQ */
+ *(z++) = base32hexchar((x[3] & 3) << 3); /* 000QQ000 */
+ if (padding)
+ *(z++) = '=';
+
+ break;
+
+ case 3:
+ *(z++) = base32hexchar(x[0] >> 3); /* 000XXXXX */
+ *(z++) = base32hexchar((x[0] & 7) << 2 | x[1] >> 6); /* 000XXXYY */
+ *(z++) = base32hexchar((x[1] & 63) >> 1); /* 000YYYYY */
+ *(z++) = base32hexchar((x[1] & 1) << 4 | x[2] >> 4); /* 000YZZZZ */
+ *(z++) = base32hexchar((x[2] & 15) << 1); /* 000ZZZZ0 */
+ if (padding) {
+ *(z++) = '=';
+ *(z++) = '=';
+ *(z++) = '=';
+ }
+
+ break;
+
+ case 2:
+ *(z++) = base32hexchar(x[0] >> 3); /* 000XXXXX */
+ *(z++) = base32hexchar((x[0] & 7) << 2 | x[1] >> 6); /* 000XXXYY */
+ *(z++) = base32hexchar((x[1] & 63) >> 1); /* 000YYYYY */
+ *(z++) = base32hexchar((x[1] & 1) << 4); /* 000Y0000 */
+ if (padding) {
+ *(z++) = '=';
+ *(z++) = '=';
+ *(z++) = '=';
+ *(z++) = '=';
+ }
+
+ break;
+
+ case 1:
+ *(z++) = base32hexchar(x[0] >> 3); /* 000XXXXX */
+ *(z++) = base32hexchar((x[0] & 7) << 2); /* 000XXX00 */
+ if (padding) {
+ *(z++) = '=';
+ *(z++) = '=';
+ *(z++) = '=';
+ *(z++) = '=';
+ *(z++) = '=';
+ *(z++) = '=';
+ }
+
+ break;
+ }
+
+ *z = 0;
+ return r;
+}
+
+int unbase32hexmem(const char *p, size_t l, bool padding, void **mem, size_t *_len) {
+ _cleanup_free_ uint8_t *r = NULL;
+ int a, b, c, d, e, f, g, h;
+ uint8_t *z;
+ const char *x;
+ size_t len;
+ unsigned pad = 0;
+
+ assert(p);
+
+ /* padding ensures any base32hex input has input divisible by 8 */
+ if (padding && l % 8 != 0)
+ return -EINVAL;
+
+ if (padding) {
+ /* strip the padding */
+ while (l > 0 && p[l - 1] == '=' && pad < 7) {
+ pad ++;
+ l --;
+ }
+ }
+
+ /* a group of eight input bytes needs five output bytes, in case of
+ padding we need to add some extra bytes */
+ len = (l / 8) * 5;
+
+ switch (l % 8) {
+ case 7:
+ len += 4;
+ break;
+ case 5:
+ len += 3;
+ break;
+ case 4:
+ len += 2;
+ break;
+ case 2:
+ len += 1;
+ break;
+ case 0:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ z = r = malloc(len + 1);
+ if (!r)
+ return -ENOMEM;
+
+ for (x = p; x < p + (l / 8) * 8; x += 8) {
+ /* a == 000XXXXX; b == 000YYYYY; c == 000ZZZZZ; d == 000WWWWW
+ e == 000SSSSS; f == 000QQQQQ; g == 000VVVVV; h == 000RRRRR */
+ a = unbase32hexchar(x[0]);
+ if (a < 0)
+ return -EINVAL;
+
+ b = unbase32hexchar(x[1]);
+ if (b < 0)
+ return -EINVAL;
+
+ c = unbase32hexchar(x[2]);
+ if (c < 0)
+ return -EINVAL;
+
+ d = unbase32hexchar(x[3]);
+ if (d < 0)
+ return -EINVAL;
+
+ e = unbase32hexchar(x[4]);
+ if (e < 0)
+ return -EINVAL;
+
+ f = unbase32hexchar(x[5]);
+ if (f < 0)
+ return -EINVAL;
+
+ g = unbase32hexchar(x[6]);
+ if (g < 0)
+ return -EINVAL;
+
+ h = unbase32hexchar(x[7]);
+ if (h < 0)
+ return -EINVAL;
+
+ *(z++) = (uint8_t) a << 3 | (uint8_t) b >> 2; /* XXXXXYYY */
+ *(z++) = (uint8_t) b << 6 | (uint8_t) c << 1 | (uint8_t) d >> 4; /* YYZZZZZW */
+ *(z++) = (uint8_t) d << 4 | (uint8_t) e >> 1; /* WWWWSSSS */
+ *(z++) = (uint8_t) e << 7 | (uint8_t) f << 2 | (uint8_t) g >> 3; /* SQQQQQVV */
+ *(z++) = (uint8_t) g << 5 | (uint8_t) h; /* VVVRRRRR */
+ }
+
+ switch (l % 8) {
+ case 7:
+ a = unbase32hexchar(x[0]);
+ if (a < 0)
+ return -EINVAL;
+
+ b = unbase32hexchar(x[1]);
+ if (b < 0)
+ return -EINVAL;
+
+ c = unbase32hexchar(x[2]);
+ if (c < 0)
+ return -EINVAL;
+
+ d = unbase32hexchar(x[3]);
+ if (d < 0)
+ return -EINVAL;
+
+ e = unbase32hexchar(x[4]);
+ if (e < 0)
+ return -EINVAL;
+
+ f = unbase32hexchar(x[5]);
+ if (f < 0)
+ return -EINVAL;
+
+ g = unbase32hexchar(x[6]);
+ if (g < 0)
+ return -EINVAL;
+
+ /* g == 000VV000 */
+ if (g & 7)
+ return -EINVAL;
+
+ *(z++) = (uint8_t) a << 3 | (uint8_t) b >> 2; /* XXXXXYYY */
+ *(z++) = (uint8_t) b << 6 | (uint8_t) c << 1 | (uint8_t) d >> 4; /* YYZZZZZW */
+ *(z++) = (uint8_t) d << 4 | (uint8_t) e >> 1; /* WWWWSSSS */
+ *(z++) = (uint8_t) e << 7 | (uint8_t) f << 2 | (uint8_t) g >> 3; /* SQQQQQVV */
+
+ break;
+ case 5:
+ a = unbase32hexchar(x[0]);
+ if (a < 0)
+ return -EINVAL;
+
+ b = unbase32hexchar(x[1]);
+ if (b < 0)
+ return -EINVAL;
+
+ c = unbase32hexchar(x[2]);
+ if (c < 0)
+ return -EINVAL;
+
+ d = unbase32hexchar(x[3]);
+ if (d < 0)
+ return -EINVAL;
+
+ e = unbase32hexchar(x[4]);
+ if (e < 0)
+ return -EINVAL;
+
+ /* e == 000SSSS0 */
+ if (e & 1)
+ return -EINVAL;
+
+ *(z++) = (uint8_t) a << 3 | (uint8_t) b >> 2; /* XXXXXYYY */
+ *(z++) = (uint8_t) b << 6 | (uint8_t) c << 1 | (uint8_t) d >> 4; /* YYZZZZZW */
+ *(z++) = (uint8_t) d << 4 | (uint8_t) e >> 1; /* WWWWSSSS */
+
+ break;
+ case 4:
+ a = unbase32hexchar(x[0]);
+ if (a < 0)
+ return -EINVAL;
+
+ b = unbase32hexchar(x[1]);
+ if (b < 0)
+ return -EINVAL;
+
+ c = unbase32hexchar(x[2]);
+ if (c < 0)
+ return -EINVAL;
+
+ d = unbase32hexchar(x[3]);
+ if (d < 0)
+ return -EINVAL;
+
+ /* d == 000W0000 */
+ if (d & 15)
+ return -EINVAL;
+
+ *(z++) = (uint8_t) a << 3 | (uint8_t) b >> 2; /* XXXXXYYY */
+ *(z++) = (uint8_t) b << 6 | (uint8_t) c << 1 | (uint8_t) d >> 4; /* YYZZZZZW */
+
+ break;
+ case 2:
+ a = unbase32hexchar(x[0]);
+ if (a < 0)
+ return -EINVAL;
+
+ b = unbase32hexchar(x[1]);
+ if (b < 0)
+ return -EINVAL;
+
+ /* b == 000YYY00 */
+ if (b & 3)
+ return -EINVAL;
+
+ *(z++) = (uint8_t) a << 3 | (uint8_t) b >> 2; /* XXXXXYYY */
+
+ break;
+ case 0:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ *z = 0;
+
+ *mem = r;
+ r = NULL;
+ *_len = len;
+
+ return 0;
+}
+
+/* https://tools.ietf.org/html/rfc4648#section-4 */
+char base64char(int x) {
+ static const char table[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "abcdefghijklmnopqrstuvwxyz"
+ "0123456789+/";
+ return table[x & 63];
+}
+
+int unbase64char(char c) {
+ unsigned offset;
+
+ if (c >= 'A' && c <= 'Z')
+ return c - 'A';
+
+ offset = 'Z' - 'A' + 1;
+
+ if (c >= 'a' && c <= 'z')
+ return c - 'a' + offset;
+
+ offset += 'z' - 'a' + 1;
+
+ if (c >= '0' && c <= '9')
+ return c - '0' + offset;
+
+ offset += '9' - '0' + 1;
+
+ if (c == '+')
+ return offset;
+
+ offset ++;
+
+ if (c == '/')
+ return offset;
+
+ return -EINVAL;
+}
+
+char *base64mem(const void *p, size_t l) {
+ char *r, *z;
+ const uint8_t *x;
+
+ /* three input bytes makes four output bytes, padding is added so we must round up */
+ z = r = malloc(4 * (l + 2) / 3 + 1);
+ if (!r)
+ return NULL;
+
+ for (x = p; x < (const uint8_t*) p + (l / 3) * 3; x += 3) {
+ /* x[0] == XXXXXXXX; x[1] == YYYYYYYY; x[2] == ZZZZZZZZ */
+ *(z++) = base64char(x[0] >> 2); /* 00XXXXXX */
+ *(z++) = base64char((x[0] & 3) << 4 | x[1] >> 4); /* 00XXYYYY */
+ *(z++) = base64char((x[1] & 15) << 2 | x[2] >> 6); /* 00YYYYZZ */
+ *(z++) = base64char(x[2] & 63); /* 00ZZZZZZ */
+ }
+
+ switch (l % 3) {
+ case 2:
+ *(z++) = base64char(x[0] >> 2); /* 00XXXXXX */
+ *(z++) = base64char((x[0] & 3) << 4 | x[1] >> 4); /* 00XXYYYY */
+ *(z++) = base64char((x[1] & 15) << 2); /* 00YYYY00 */
+ *(z++) = '=';
+
+ break;
+ case 1:
+ *(z++) = base64char(x[0] >> 2); /* 00XXXXXX */
+ *(z++) = base64char((x[0] & 3) << 4); /* 00XX0000 */
+ *(z++) = '=';
+ *(z++) = '=';
+
+ break;
+ }
+
+ *z = 0;
return r;
}
+int unbase64mem(const char *p, size_t l, void **mem, size_t *_len) {
+ _cleanup_free_ uint8_t *r = NULL;
+ int a, b, c, d;
+ uint8_t *z;
+ const char *x;
+ size_t len;
+
+ assert(p);
+
+ /* padding ensures any base63 input has input divisible by 4 */
+ if (l % 4 != 0)
+ return -EINVAL;
+
+ /* strip the padding */
+ if (l > 0 && p[l - 1] == '=')
+ l --;
+ if (l > 0 && p[l - 1] == '=')
+ l --;
+
+ /* a group of four input bytes needs three output bytes, in case of
+ padding we need to add two or three extra bytes */
+ len = (l / 4) * 3 + (l % 4 ? (l % 4) - 1 : 0);
+
+ z = r = malloc(len + 1);
+ if (!r)
+ return -ENOMEM;
+
+ for (x = p; x < p + (l / 4) * 4; x += 4) {
+ /* a == 00XXXXXX; b == 00YYYYYY; c == 00ZZZZZZ; d == 00WWWWWW */
+ a = unbase64char(x[0]);
+ if (a < 0)
+ return -EINVAL;
+
+ b = unbase64char(x[1]);
+ if (b < 0)
+ return -EINVAL;
+
+ c = unbase64char(x[2]);
+ if (c < 0)
+ return -EINVAL;
+
+ d = unbase64char(x[3]);
+ if (d < 0)
+ return -EINVAL;
+
+ *(z++) = (uint8_t) a << 2 | (uint8_t) b >> 4; /* XXXXXXYY */
+ *(z++) = (uint8_t) b << 4 | (uint8_t) c >> 2; /* YYYYZZZZ */
+ *(z++) = (uint8_t) c << 6 | (uint8_t) d; /* ZZWWWWWW */
+ }
+
+ switch (l % 4) {
+ case 3:
+ a = unbase64char(x[0]);
+ if (a < 0)
+ return -EINVAL;
+
+ b = unbase64char(x[1]);
+ if (b < 0)
+ return -EINVAL;
+
+ c = unbase64char(x[2]);
+ if (c < 0)
+ return -EINVAL;
+
+ /* c == 00ZZZZ00 */
+ if (c & 3)
+ return -EINVAL;
+
+ *(z++) = (uint8_t) a << 2 | (uint8_t) b >> 4; /* XXXXXXYY */
+ *(z++) = (uint8_t) b << 4 | (uint8_t) c >> 2; /* YYYYZZZZ */
+
+ break;
+ case 2:
+ a = unbase64char(x[0]);
+ if (a < 0)
+ return -EINVAL;
+
+ b = unbase64char(x[1]);
+ if (b < 0)
+ return -EINVAL;
+
+ /* b == 00YY0000 */
+ if (b & 15)
+ return -EINVAL;
+
+ *(z++) = (uint8_t) a << 2 | (uint8_t) (b >> 4); /* XXXXXXYY */
+
+ break;
+ case 0:
+
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ *z = 0;
+
+ *mem = r;
+ r = NULL;
+ *_len = len;
+
+ return 0;
+}
+
char octchar(int x) {
return '0' + (x & 7);
}
@@ -2533,7 +3069,7 @@ int fopen_temporary(const char *path, FILE **_f, char **_temp_path) {
f = fdopen(fd, "we");
if (!f) {
- unlink(t);
+ unlink_noerrno(t);
free(t);
safe_close(fd);
return -errno;
diff --git a/src/basic/util.h b/src/basic/util.h
index a1d1dd15c3..c2e5cc610b 100644
--- a/src/basic/util.h
+++ b/src/basic/util.h
@@ -240,6 +240,10 @@ char octchar(int x) _const_;
int unoctchar(char c) _const_;
char decchar(int x) _const_;
int undecchar(char c) _const_;
+char base32hexchar(int x) _const_;
+int unbase32hexchar(char c) _const_;
+char base64char(int x) _const_;
+int unbase64char(char c) _const_;
char *cescape(const char *s);
size_t cescape_char(char c, char *buf);
@@ -614,7 +618,13 @@ static inline void *mempset(void *s, int c, size_t n) {
}
char *hexmem(const void *p, size_t l);
-void *unhexmem(const char *p, size_t l);
+int unhexmem(const char *p, size_t l, void **mem, size_t *len);
+
+char *base32hexmem(const void *p, size_t l, bool padding);
+int unbase32hexmem(const char *p, size_t l, bool padding, void **mem, size_t *len);
+
+char *base64mem(const void *p, size_t l);
+int unbase64mem(const char *p, size_t l, void **mem, size_t *len);
char *strextend(char **x, ...) _sentinel_;
char *strrep(const char *s, unsigned n);