diff options
author | David Oberhollenzer <david.oberhollenzer@sigma-star.at> | 2019-07-01 13:23:36 +0200 |
---|---|---|
committer | David Oberhollenzer <david.oberhollenzer@sigma-star.at> | 2019-07-01 13:23:36 +0200 |
commit | 8aea2d1dc437b5b497170ef9c1b6854aee8f5dcf (patch) | |
tree | 0999ed4664c74cf90896d8b11f7f4a9dc06e8d48 /lib/tar/number.c | |
parent | f0d18050d832498c8e230c04084675455fef391f (diff) |
cleanup: split tar code up, remove some duplications
This commit attempts to split some of the monolitic tar parsing code up
into multiple functions in seperate files. Also, some code duplication
(like reading a record into memory which was implemented twice) is
removed.
Signed-off-by: David Oberhollenzer <david.oberhollenzer@sigma-star.at>
Diffstat (limited to 'lib/tar/number.c')
-rw-r--r-- | lib/tar/number.c | 94 |
1 files changed, 94 insertions, 0 deletions
diff --git a/lib/tar/number.c b/lib/tar/number.c new file mode 100644 index 0000000..e85866d --- /dev/null +++ b/lib/tar/number.c @@ -0,0 +1,94 @@ +/* SPDX-License-Identifier: GPL-3.0-or-later */ +#include "internal.h" + +int read_octal(const char *str, int digits, uint64_t *out) +{ + uint64_t result = 0; + + while (digits > 0 && isspace(*str)) { + ++str; + --digits; + } + + while (digits > 0 && *str >= '0' && *str <= '7') { + if (result > 0x1FFFFFFFFFFFFFFFUL) { + fputs("numeric overflow parsing tar header\n", stderr); + return -1; + } + + result = (result << 3) | (*(str++) - '0'); + --digits; + } + + *out = result; + return 0; +} + +int read_binary(const char *str, int digits, uint64_t *out) +{ + uint64_t x, ov, result = 0; + bool first = true; + + while (digits > 0) { + x = *((const unsigned char *)str++); + --digits; + + if (first) { + first = false; + if (x == 0xFF) { + result = 0xFFFFFFFFFFFFFFFFUL; + } else { + x &= 0x7F; + result = 0; + if (digits > 7 && x != 0) + goto fail_ov; + } + } + + ov = (result >> 56) & 0xFF; + + if (ov != 0 && ov != 0xFF) + goto fail_ov; + + result = (result << 8) | x; + } + + *out = result; + return 0; +fail_ov: + fputs("numeric overflow parsing tar header\n", stderr); + return -1; +} + +int read_number(const char *str, int digits, uint64_t *out) +{ + if (*((unsigned char *)str) & 0x80) + return read_binary(str, digits, out); + + return read_octal(str, digits, out); +} + +int pax_read_decimal(const char *str, uint64_t *out) +{ + uint64_t result = 0; + + while (*str >= '0' && *str <= '9') { + if (result > 0xFFFFFFFFFFFFFFFFUL / 10) { + fputs("numeric overflow parsing pax header\n", stderr); + return -1; + } + + result = (result * 10) + (*(str++) - '0'); + } + + *out = result; + return 0; +} + +void write_octal(char *dst, unsigned int value, int digits) +{ + char temp[64]; + + sprintf(temp, "%0*o ", digits, value); + memcpy(dst, temp, strlen(temp)); +} |