From e6a19ba1a05f77f051187a6b1a828ee6d39ce052 Mon Sep 17 00:00:00 2001 From: David Oberhollenzer Date: Wed, 29 Jun 2022 18:21:58 +0200 Subject: Cleanup: split libtar header, move to sub directory Some of the on-disk format internals are moved to a separate header and some of the stuff from internal.h is moved to that format header. C++ guards are added in addtion. Everything PAX related is moved to pax_header.c, some internal functions are marked as static. Signed-off-by: David Oberhollenzer --- lib/tar/Makemodule.am | 6 +- lib/tar/base64.c | 59 ---------------- lib/tar/checksum.c | 4 +- lib/tar/cleanup.c | 2 + lib/tar/internal.h | 36 +--------- lib/tar/number.c | 24 ++----- lib/tar/padd_file.c | 3 +- lib/tar/pax_header.c | 161 ++++++++++++++++++++++++++++++++++++++++-- lib/tar/read_header.c | 2 + lib/tar/read_sparse_map.c | 54 -------------- lib/tar/read_sparse_map_new.c | 5 +- lib/tar/read_sparse_map_old.c | 4 +- lib/tar/record_to_memory.c | 3 +- lib/tar/urldecode.c | 38 ---------- lib/tar/write_header.c | 1 + 15 files changed, 183 insertions(+), 219 deletions(-) delete mode 100644 lib/tar/base64.c delete mode 100644 lib/tar/read_sparse_map.c delete mode 100644 lib/tar/urldecode.c (limited to 'lib') diff --git a/lib/tar/Makemodule.am b/lib/tar/Makemodule.am index 414aca1..7f93d13 100644 --- a/lib/tar/Makemodule.am +++ b/lib/tar/Makemodule.am @@ -1,10 +1,10 @@ libtar_a_SOURCES = lib/tar/read_header.c lib/tar/write_header.c libtar_a_SOURCES += lib/tar/number.c lib/tar/checksum.c lib/tar/cleanup.c -libtar_a_SOURCES += lib/tar/read_sparse_map.c lib/tar/read_sparse_map_old.c -libtar_a_SOURCES += lib/tar/base64.c lib/tar/urldecode.c lib/tar/internal.h +libtar_a_SOURCES += lib/tar/read_sparse_map_old.c +libtar_a_SOURCES += lib/tar/internal.h libtar_a_SOURCES += lib/tar/padd_file.c lib/tar/record_to_memory.c libtar_a_SOURCES += lib/tar/pax_header.c lib/tar/read_sparse_map_new.c -libtar_a_SOURCES += include/tar.h +libtar_a_SOURCES += include/tar/tar.h include/tar/format.h libtar_a_CFLAGS = $(AM_CFLAGS) libtar_a_CPPFLAGS = $(AM_CPPFLAGS) diff --git a/lib/tar/base64.c b/lib/tar/base64.c deleted file mode 100644 index f88444a..0000000 --- a/lib/tar/base64.c +++ /dev/null @@ -1,59 +0,0 @@ -/* SPDX-License-Identifier: GPL-3.0-or-later */ -/* - * base64.c - * - * Copyright (C) 2019 David Oberhollenzer - */ -#include "config.h" - -#include "internal.h" - -static sqfs_u8 convert(char in) -{ - if (isupper(in)) - return in - 'A'; - if (islower(in)) - return in - 'a' + 26; - if (isdigit(in)) - return in - '0' + 52; - if (in == '+') - return 62; - if (in == '/' || in == '-') - return 63; - return 0; -} - -size_t base64_decode(sqfs_u8 *out, const char *in, size_t len) -{ - sqfs_u8 *start = out; - - while (len > 0) { - unsigned int diff = 0, value = 0; - - while (diff < 4 && len > 0) { - if (*in == '=' || *in == '_' || *in == '\0') { - len = 0; - } else { - value = (value << 6) | convert(*(in++)); - --len; - ++diff; - } - } - - if (diff < 2) - break; - - value <<= 6 * (4 - diff); - - switch (diff) { - case 4: out[2] = value & 0xff; /* fall-through */ - case 3: out[1] = (value >> 8) & 0xff; /* fall-through */ - default: out[0] = (value >> 16) & 0xff; - } - - out += (diff * 3) / 4; - } - - *out = '\0'; - return out - start; -} diff --git a/lib/tar/checksum.c b/lib/tar/checksum.c index 144ba43..6541373 100644 --- a/lib/tar/checksum.c +++ b/lib/tar/checksum.c @@ -6,7 +6,9 @@ */ #include "config.h" -#include "internal.h" +#include "tar/format.h" + +#include static unsigned int get_checksum(const tar_header_t *hdr) { diff --git a/lib/tar/cleanup.c b/lib/tar/cleanup.c index 2f814bf..9f33336 100644 --- a/lib/tar/cleanup.c +++ b/lib/tar/cleanup.c @@ -7,6 +7,8 @@ #include "config.h" #include "internal.h" +#include +#include void free_sparse_list(sparse_map_t *sparse) { diff --git a/lib/tar/internal.h b/lib/tar/internal.h index b7c4c34..cfbb938 100644 --- a/lib/tar/internal.h +++ b/lib/tar/internal.h @@ -9,13 +9,8 @@ #include "config.h" -#include "tar.h" - -#include -#include -#include -#include -#include +#include "tar/tar.h" +#include "tar/format.h" enum { PAX_SIZE = 0x001, @@ -38,37 +33,10 @@ enum { ETV_POSIX, }; - -#define TAR_MAX_SYMLINK_LEN (65536) -#define TAR_MAX_PATH_LEN (65536) -#define TAR_MAX_PAX_LEN (65536) -#define TAR_MAX_SPARSE_ENT (65536) - - -int read_octal(const char *str, int digits, sqfs_u64 *out); - -int read_binary(const char *str, int digits, sqfs_u64 *out); - -int read_number(const char *str, int digits, sqfs_u64 *out); - -int pax_read_decimal(const char *str, sqfs_u64 *out); - -void update_checksum(tar_header_t *hdr); - -bool is_checksum_valid(const tar_header_t *hdr); - -sparse_map_t *read_sparse_map(const char *line); - sparse_map_t *read_gnu_old_sparse(istream_t *fp, tar_header_t *hdr); sparse_map_t *read_gnu_new_sparse(istream_t *fp, tar_header_decoded_t *out); -void free_sparse_list(sparse_map_t *sparse); - -size_t base64_decode(sqfs_u8 *out, const char *in, size_t len); - -void urldecode(char *str); - char *record_to_memory(istream_t *fp, size_t size); int read_pax_header(istream_t *fp, sqfs_u64 entsize, unsigned int *set_by_pax, diff --git a/lib/tar/number.c b/lib/tar/number.c index 50cb658..2f179df 100644 --- a/lib/tar/number.c +++ b/lib/tar/number.c @@ -6,7 +6,10 @@ */ #include "config.h" -#include "internal.h" +#include "tar/format.h" + +#include +#include int read_octal(const char *str, int digits, sqfs_u64 *out) { @@ -31,7 +34,7 @@ int read_octal(const char *str, int digits, sqfs_u64 *out) return 0; } -int read_binary(const char *str, int digits, sqfs_u64 *out) +static int read_binary(const char *str, int digits, sqfs_u64 *out) { sqfs_u64 x, ov, result = 0; bool first = true; @@ -74,20 +77,3 @@ int read_number(const char *str, int digits, sqfs_u64 *out) return read_octal(str, digits, out); } - -int pax_read_decimal(const char *str, sqfs_u64 *out) -{ - sqfs_u64 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; -} diff --git a/lib/tar/padd_file.c b/lib/tar/padd_file.c index 1173096..6a1ca05 100644 --- a/lib/tar/padd_file.c +++ b/lib/tar/padd_file.c @@ -5,7 +5,8 @@ * Copyright (C) 2019 David Oberhollenzer */ #include "config.h" -#include "tar.h" +#include "tar/tar.h" +#include "tar/format.h" #include #include diff --git a/lib/tar/pax_header.c b/lib/tar/pax_header.c index d24def0..8a1b077 100644 --- a/lib/tar/pax_header.c +++ b/lib/tar/pax_header.c @@ -7,6 +7,105 @@ #include "config.h" #include "internal.h" +#include +#include +#include + +static sqfs_u8 base64_convert(char in) +{ + if (isupper(in)) + return in - 'A'; + if (islower(in)) + return in - 'a' + 26; + if (isdigit(in)) + return in - '0' + 52; + if (in == '+') + return 62; + if (in == '/' || in == '-') + return 63; + return 0; +} + +static int xdigit(int x) +{ + if (isupper(x)) + return x - 'A' + 0x0A; + if (islower(x)) + return x - 'a' + 0x0A; + return x - '0'; +} + +static size_t base64_decode(sqfs_u8 *out, const char *in, size_t len) +{ + sqfs_u8 *start = out; + + while (len > 0) { + unsigned int diff = 0, value = 0; + + while (diff < 4 && len > 0) { + if (*in == '=' || *in == '_' || *in == '\0') { + len = 0; + } else { + value = (value << 6) | base64_convert(*(in++)); + --len; + ++diff; + } + } + + if (diff < 2) + break; + + value <<= 6 * (4 - diff); + + switch (diff) { + case 4: out[2] = value & 0xff; /* fall-through */ + case 3: out[1] = (value >> 8) & 0xff; /* fall-through */ + default: out[0] = (value >> 16) & 0xff; + } + + out += (diff * 3) / 4; + } + + *out = '\0'; + return out - start; +} + +static int pax_read_decimal(const char *str, sqfs_u64 *out) +{ + sqfs_u64 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; +} + +static void urldecode(char *str) +{ + unsigned char *out = (unsigned char *)str; + char *in = str; + int x; + + while (*in != '\0') { + x = *(in++); + + if (x == '%' && isxdigit(in[0]) && isxdigit(in[1])) { + x = xdigit(*(in++)) << 4; + x |= xdigit(*(in++)); + } + + *(out++) = x; + } + + *out = '\0'; +} static int pax_uid(tar_header_decoded_t *out, sqfs_u64 id) { @@ -52,6 +151,55 @@ static int pax_slink(tar_header_decoded_t *out, char *path) return 0; } +static int pax_sparse_map(tar_header_decoded_t *out, const char *line) +{ + sparse_map_t *last = NULL, *list = NULL, *ent = NULL; + + free_sparse_list(out->sparse); + out->sparse = NULL; + + do { + ent = calloc(1, sizeof(*ent)); + if (ent == NULL) + goto fail_errno; + + if (pax_read_decimal(line, &ent->offset)) + goto fail_format; + + while (isdigit(*line)) + ++line; + + if (*(line++) != ',') + goto fail_format; + + if (pax_read_decimal(line, &ent->count)) + goto fail_format; + + while (isdigit(*line)) + ++line; + + if (last == NULL) { + list = last = ent; + } else { + last->next = ent; + last = ent; + } + } while (*(line++) == ','); + + out->sparse = list; + return 0; +fail_errno: + perror("parsing GNU pax sparse file record"); + goto fail; +fail_format: + fputs("malformed GNU pax sparse file record\n", stderr); + goto fail; +fail: + free_sparse_list(list); + free(ent); + return -1; +} + static int pax_xattr_schily(tar_header_decoded_t *out, tar_xattr_t *xattr) { @@ -76,6 +224,7 @@ enum { PAX_TYPE_SINT = 0, PAX_TYPE_UINT, PAX_TYPE_STRING, + PAX_TYPE_CONST_STRING, PAX_TYPE_PREFIXED_XATTR, PAX_TYPE_IGNORE, }; @@ -88,6 +237,7 @@ static const struct pax_handler_t { int (*sint)(tar_header_decoded_t *out, sqfs_s64 sval); int (*uint)(tar_header_decoded_t *out, sqfs_u64 uval); int (*str)(tar_header_decoded_t *out, char *str); + int (*cstr)(tar_header_decoded_t *out, const char *str); int (*xattr)(tar_header_decoded_t *out, tar_xattr_t *xattr); } cb; } pax_fields[] = { @@ -110,6 +260,8 @@ static const struct pax_handler_t { { .xattr = pax_xattr_schily } }, { "LIBARCHIVE.xattr", 0, PAX_TYPE_PREFIXED_XATTR, { .xattr = pax_xattr_libarchive } }, + { "GNU.sparse.map", 0, PAX_TYPE_CONST_STRING, + { .cstr = pax_sparse_map } }, }; static const struct pax_handler_t *find_handler(const char *key) @@ -183,6 +335,8 @@ static int apply_handler(tar_header_decoded_t *out, if (pax_read_decimal(value, &uval)) return -1; return field->cb.uint(out, uval); + case PAX_TYPE_CONST_STRING: + return field->cb.cstr(out, value); case PAX_TYPE_STRING: copy = strdup(value); if (copy == NULL) { @@ -264,13 +418,6 @@ int read_pax_header(istream_t *fp, sqfs_u64 entsize, unsigned int *set_by_pax, } *set_by_pax |= field->flag; - } else if (!strcmp(key, "GNU.sparse.map")) { - free_sparse_list(out->sparse); - sparse_last = NULL; - - out->sparse = read_sparse_map(value); - if (out->sparse == NULL) - goto fail; } else if (!strcmp(key, "GNU.sparse.offset")) { if (pax_read_decimal(value, &offset)) goto fail; diff --git a/lib/tar/read_header.c b/lib/tar/read_header.c index d1790de..ea4873b 100644 --- a/lib/tar/read_header.c +++ b/lib/tar/read_header.c @@ -7,6 +7,8 @@ #include "config.h" #include "internal.h" +#include +#include static bool is_zero_block(const tar_header_t *hdr) { diff --git a/lib/tar/read_sparse_map.c b/lib/tar/read_sparse_map.c deleted file mode 100644 index 0779b96..0000000 --- a/lib/tar/read_sparse_map.c +++ /dev/null @@ -1,54 +0,0 @@ -/* SPDX-License-Identifier: GPL-3.0-or-later */ -/* - * read_sparse_map.c - * - * Copyright (C) 2019 David Oberhollenzer - */ -#include "config.h" - -#include "internal.h" - -sparse_map_t *read_sparse_map(const char *line) -{ - sparse_map_t *last = NULL, *list = NULL, *ent = NULL; - - do { - ent = calloc(1, sizeof(*ent)); - if (ent == NULL) - goto fail_errno; - - if (pax_read_decimal(line, &ent->offset)) - goto fail_format; - - while (isdigit(*line)) - ++line; - - if (*(line++) != ',') - goto fail_format; - - if (pax_read_decimal(line, &ent->count)) - goto fail_format; - - while (isdigit(*line)) - ++line; - - if (last == NULL) { - list = last = ent; - } else { - last->next = ent; - last = ent; - } - } while (*(line++) == ','); - - return list; -fail_errno: - perror("parsing GNU pax sparse file record"); - goto fail; -fail_format: - fputs("malformed GNU pax sparse file record\n", stderr); - goto fail; -fail: - free_sparse_list(list); - free(ent); - return NULL; -} diff --git a/lib/tar/read_sparse_map_new.c b/lib/tar/read_sparse_map_new.c index d9f6c6e..de1b6a4 100644 --- a/lib/tar/read_sparse_map_new.c +++ b/lib/tar/read_sparse_map_new.c @@ -5,9 +5,12 @@ * Copyright (C) 2019 David Oberhollenzer */ #include "config.h" - #include "internal.h" +#include +#include +#include + static int decode(const char *str, size_t len, size_t *out) { size_t count = 0; diff --git a/lib/tar/read_sparse_map_old.c b/lib/tar/read_sparse_map_old.c index cd7177d..3dd3300 100644 --- a/lib/tar/read_sparse_map_old.c +++ b/lib/tar/read_sparse_map_old.c @@ -5,9 +5,11 @@ * Copyright (C) 2019 David Oberhollenzer */ #include "config.h" - #include "internal.h" +#include +#include + sparse_map_t *read_gnu_old_sparse(istream_t *fp, tar_header_t *hdr) { sparse_map_t *list = NULL, *end = NULL, *node; diff --git a/lib/tar/record_to_memory.c b/lib/tar/record_to_memory.c index 822608c..ba422de 100644 --- a/lib/tar/record_to_memory.c +++ b/lib/tar/record_to_memory.c @@ -6,8 +6,9 @@ */ #include "config.h" -#include "tar.h" +#include "tar/tar.h" #include "internal.h" +#include char *record_to_memory(istream_t *fp, size_t size) { diff --git a/lib/tar/urldecode.c b/lib/tar/urldecode.c deleted file mode 100644 index 6fac4d3..0000000 --- a/lib/tar/urldecode.c +++ /dev/null @@ -1,38 +0,0 @@ -/* SPDX-License-Identifier: GPL-3.0-or-later */ -/* - * urldecode.c - * - * Copyright (C) 2019 David Oberhollenzer - */ -#include "config.h" - -#include "internal.h" - -static int xdigit(int x) -{ - if (isupper(x)) - return x - 'A' + 0x0A; - if (islower(x)) - return x - 'a' + 0x0A; - return x - '0'; -} - -void urldecode(char *str) -{ - unsigned char *out = (unsigned char *)str; - char *in = str; - int x; - - while (*in != '\0') { - x = *(in++); - - if (x == '%' && isxdigit(in[0]) && isxdigit(in[1])) { - x = xdigit(*(in++)) << 4; - x |= xdigit(*(in++)); - } - - *(out++) = x; - } - - *out = '\0'; -} diff --git a/lib/tar/write_header.c b/lib/tar/write_header.c index a337b74..b0711b3 100644 --- a/lib/tar/write_header.c +++ b/lib/tar/write_header.c @@ -7,6 +7,7 @@ #include "config.h" #include "internal.h" +#include static void write_binary(char *dst, sqfs_u64 value, int digits) { -- cgit v1.2.3