From 262fc48eb9e246ddb7315f5a14e7f6f58ca987c1 Mon Sep 17 00:00:00 2001 From: David Oberhollenzer Date: Fri, 13 Dec 2019 15:47:35 +0100 Subject: Better support for reading/writing non-ASCII xattr values from/to tar Signed-off-by: David Oberhollenzer --- lib/tar/base64.c | 39 +++++++++++++++++++++++++++++---------- lib/tar/internal.h | 2 +- lib/tar/read_header.c | 9 ++++++--- lib/tar/write_header.c | 9 +++++---- 4 files changed, 41 insertions(+), 18 deletions(-) (limited to 'lib/tar') diff --git a/lib/tar/base64.c b/lib/tar/base64.c index 0ccf3c4..f88444a 100644 --- a/lib/tar/base64.c +++ b/lib/tar/base64.c @@ -23,18 +23,37 @@ static sqfs_u8 convert(char in) return 0; } -void base64_decode(sqfs_u8 *out, const char *in) +size_t base64_decode(sqfs_u8 *out, const char *in, size_t len) { - char temp[4]; + sqfs_u8 *start = out; - while (*in != '\0' && *in != '=') { - temp[0] = *in == '\0' ? 0 : convert(*(in++)); - temp[1] = *in == '\0' ? 0 : convert(*(in++)); - temp[2] = *in == '\0' ? 0 : convert(*(in++)); - temp[3] = *in == '\0' ? 0 : convert(*(in++)); + while (len > 0) { + unsigned int diff = 0, value = 0; - *(out++) = ((temp[0] << 2) & 0xFC) | ((temp[1] >> 4) & 0x03); - *(out++) = ((temp[1] << 4) & 0xF0) | ((temp[2] >> 2) & 0x0F); - *(out++) = ((temp[2] << 6) & 0xC0) | ( temp[3] & 0x3F); + 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/internal.h b/lib/tar/internal.h index 055637a..0220f05 100644 --- a/lib/tar/internal.h +++ b/lib/tar/internal.h @@ -61,7 +61,7 @@ void free_sparse_list(sparse_map_t *sparse); void free_xattr_list(tar_xattr_t *list); -void base64_decode(sqfs_u8 *out, const char *in); +size_t base64_decode(sqfs_u8 *out, const char *in, size_t len); void urldecode(char *str); diff --git a/lib/tar/read_header.c b/lib/tar/read_header.c index 845afc3..20e7a9f 100644 --- a/lib/tar/read_header.c +++ b/lib/tar/read_header.c @@ -68,7 +68,8 @@ static tar_xattr_t *mkxattr(const char *key, size_t keylen, return NULL; xattr->key = xattr->data; - xattr->value = xattr->data + keylen + 1; + xattr->value = (sqfs_u8 *)xattr->data + keylen + 1; + xattr->value_len = valuelen; memcpy(xattr->key, key, keylen); memcpy(xattr->value, value, valuelen); return xattr; @@ -201,7 +202,8 @@ static int read_pax_header(FILE *fp, sqfs_u64 entsize, unsigned int *set_by_pax, value = ptr + 1; - xattr = mkxattr(key, ptr - key, value, strlen(value)); + xattr = mkxattr(key, ptr - key, + value, len - (value - line) - 1); if (xattr == NULL) goto fail_errno; @@ -221,7 +223,8 @@ static int read_pax_header(FILE *fp, sqfs_u64 entsize, unsigned int *set_by_pax, goto fail_errno; urldecode(xattr->key); - base64_decode((sqfs_u8 *)xattr->value, value); + xattr->value_len = base64_decode(xattr->value, value, + xattr->value_len); xattr->next = out->xattr; out->xattr = xattr; diff --git a/lib/tar/write_header.c b/lib/tar/write_header.c index c235014..acce280 100644 --- a/lib/tar/write_header.c +++ b/lib/tar/write_header.c @@ -133,7 +133,7 @@ static int write_schily_xattr(FILE *fp, const struct stat *orig, struct stat sb; for (it = xattr; it != NULL; it = it->next) { - len = strlen(prefix) + strlen(it->key) + strlen(it->value) + 2; + len = strlen(prefix) + strlen(it->key) + it->value_len + 2; total_size += num_digits(len) + 1 + len; } @@ -146,11 +146,12 @@ static int write_schily_xattr(FILE *fp, const struct stat *orig, return -1; for (it = xattr; it != NULL; it = it->next) { - len = strlen(prefix) + strlen(it->key) + strlen(it->value) + 2; + len = strlen(prefix) + strlen(it->key) + it->value_len + 2; len += num_digits(len) + 1; - fprintf(fp, PRI_SZ " %s%s=%s\n", len, - prefix, it->key, it->value); + fprintf(fp, PRI_SZ " %s%s=", len, prefix, it->key); + fwrite(it->value, 1, it->value_len, fp); + fputc('\n', fp); } return padd_file(fp, total_size); -- cgit v1.2.3