From 692cbd0079658a8eb048c9b00dadec2d69d28b14 Mon Sep 17 00:00:00 2001 From: David Oberhollenzer Date: Mon, 18 May 2020 14:00:31 +0200 Subject: libtar: fix size computation of PAX line length This commit attempts to fix the following two problems: - The number of digits computation returning an off-by-one result if the number is 10, or the resulting digit string starts with "10". This results in one-too-many padding bytes, corrupting the rest of the archive since the headers now don't start at multiples of 512 anymore. - Adding the line length prefix affects the line length (duh). If it grows far enough to require more digits, the result is a similar problem. This is a converging series that we need to compute the limit of. Unit tests for this still need to be added. Or maybe I can convince a bored undergrad student to provide an induction proof. Signed-off-by: David Oberhollenzer --- lib/tar/write_header.c | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/lib/tar/write_header.c b/lib/tar/write_header.c index cd65f59..aaf9f08 100644 --- a/lib/tar/write_header.c +++ b/lib/tar/write_header.c @@ -116,7 +116,7 @@ static size_t num_digits(size_t num) { size_t i = 1; - while (num > 10) { + while (num >= 10) { num /= 10; ++i; } @@ -124,6 +124,18 @@ static size_t num_digits(size_t num) return i; } +static size_t prefix_digit_len(size_t len) +{ + size_t old_ndigit, ndigit = 0; + + do { + old_ndigit = ndigit; + ndigit = num_digits(len + ndigit); + } while (old_ndigit != ndigit); + + return ndigit; +} + static int write_schily_xattr(FILE *fp, const struct stat *orig, const char *name, const tar_xattr_t *xattr) { @@ -133,9 +145,9 @@ 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) + it->value_len + 2; + len = strlen(prefix) + strlen(it->key) + it->value_len + 3; - total_size += num_digits(len) + 1 + len; + total_size += len + prefix_digit_len(len); } sb = *orig; @@ -146,8 +158,8 @@ 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) + it->value_len + 2; - len += num_digits(len) + 1; + len = strlen(prefix) + strlen(it->key) + it->value_len + 3; + len += prefix_digit_len(len); fprintf(fp, PRI_SZ " %s%s=", len, prefix, it->key); fwrite(it->value, 1, it->value_len, fp); -- cgit v1.2.3