X-Git-Url: https://git.dogcows.com/gitweb?a=blobdiff_plain;f=src%2Fxheader.c;h=e88934e85ec82823e8b6ee1ebcf55338b3feba46;hb=d659cbaccdc1f3279c49107cf15f15a639738529;hp=129ce8456fc324cac1f77c6224b7a26bfa23cd3b;hpb=f038194718845fe9ca9a596d3ee2e79484a5865a;p=chaz%2Ftar diff --git a/src/xheader.c b/src/xheader.c index 129ce84..e88934e 100644 --- a/src/xheader.c +++ b/src/xheader.c @@ -1,6 +1,6 @@ /* POSIX extended headers for tar. - Copyright (C) 2003, 2004 Free Software Foundation, Inc. + Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the @@ -14,27 +14,35 @@ You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., - 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#include "system.h" +#include +#include #include +#include #include -#include +#include #include "common.h" -#define obstack_chunk_alloc xmalloc -#define obstack_chunk_free free -#include +#include -bool xheader_protected_pattern_p (const char *pattern); -bool xheader_protected_keyword_p (const char *keyword); +#if !HAVE_DECL_STRTOIMAX && !defined strtoimax +intmax_t strtoimax (); +#endif +#if !HAVE_DECL_STRTOUMAX && !defined strtoumax +uintmax_t strtoumax (); +#endif + +static bool xheader_protected_pattern_p (char const *pattern); +static bool xheader_protected_keyword_p (char const *keyword); +static void xheader_set_single_keyword (char *) __attribute__ ((noreturn)); /* Used by xheader_finish() */ static void code_string (char const *string, char const *keyword, struct xheader *xhdr); -static void extended_header_init (); +static void extended_header_init (void); /* Number of global headers written so far. */ static size_t global_header_count; @@ -49,6 +57,8 @@ static size_t global_header_count; However it should wait until buffer.c is finally rewritten */ +enum { BILLION = 1000000000, LOG10_BILLION = 9 }; + /* Keyword options */ @@ -62,16 +72,23 @@ struct keyword_list /* List of keyword patterns set by delete= option */ static struct keyword_list *keyword_pattern_list; + /* List of keyword/value pairs set by `keyword=value' option */ static struct keyword_list *keyword_global_override_list; + /* List of keyword/value pairs set by `keyword:=value' option */ static struct keyword_list *keyword_override_list; + +/* List of keyword/value pairs decoded from the last 'g' type header */ +static struct keyword_list *global_header_override_list; + /* Template for the name field of an 'x' type header */ static char *exthdr_name; + /* Template for the name field of a 'g' type header */ static char *globexthdr_name; -bool +static bool xheader_keyword_deleted_p (const char *kw) { struct keyword_list *kp; @@ -82,7 +99,7 @@ xheader_keyword_deleted_p (const char *kw) return false; } -bool +static bool xheader_keyword_override_p (const char *keyword) { struct keyword_list *kp; @@ -93,8 +110,9 @@ xheader_keyword_override_p (const char *keyword) return false; } -void -xheader_list_append (struct keyword_list **root, char *kw, char *value) +static void +xheader_list_append (struct keyword_list **root, char const *kw, + char const *value) { struct keyword_list *kp = xmalloc (sizeof *kp); kp->pattern = xstrdup (kw); @@ -103,13 +121,31 @@ xheader_list_append (struct keyword_list **root, char *kw, char *value) *root = kp; } -void +static void +xheader_list_destroy (struct keyword_list **root) +{ + if (root) + { + struct keyword_list *kw = *root; + while (kw) + { + struct keyword_list *next = kw->next; + free (kw->pattern); + free (kw->value); + free (kw); + kw = next; + } + *root = NULL; + } +} + +static void xheader_set_single_keyword (char *kw) { - USAGE_ERROR ((0, 0, "Keyword %s is unknown or not yet imlemented", kw)); + USAGE_ERROR ((0, 0, _("Keyword %s is unknown or not yet imlemented"), kw)); } -void +static void xheader_set_keyword_equal (char *kw, char *eq) { bool global = true; @@ -128,11 +164,11 @@ xheader_set_keyword_equal (char *kw, char *eq) for (p = eq + 1; *p && isspace (*p); p++) ; - + if (strcmp (kw, "delete") == 0) { if (xheader_protected_pattern_p (p)) - USAGE_ERROR ((0, 0, "Pattern %s cannot be used", p)); + USAGE_ERROR ((0, 0, _("Pattern %s cannot be used"), quote (p))); xheader_list_append (&keyword_pattern_list, p, NULL); } else if (strcmp (kw, "exthdr.name") == 0) @@ -142,7 +178,7 @@ xheader_set_keyword_equal (char *kw, char *eq) else { if (xheader_protected_keyword_p (kw)) - USAGE_ERROR ((0, 0, "Keyword %s cannot be overridden", kw)); + USAGE_ERROR ((0, 0, _("Keyword %s cannot be overridden"), kw)); if (global) xheader_list_append (&keyword_global_override_list, kw, p); else @@ -169,10 +205,10 @@ xheader_set_option (char *string) %d The directory name of the file, equivalent to the result of the dirname utility on the translated - pathname. + file name. %f The filename of the file, equivalent to the result of the basename - utility on the translated pathname. + utility on the translated file name. %p The process ID of the pax process. %% A '%' character. */ @@ -183,11 +219,13 @@ xheader_format_name (struct tar_stat_info *st, const char *fmt, bool allow_n) size_t len = strlen (fmt); char *q; const char *p; - char *dirname = NULL; - char *basename = NULL; - char pidbuf[64]; - char nbuf[64]; - + char *dir = NULL; + char *base = NULL; + char pidbuf[UINTMAX_STRSIZE_BOUND]; + char const *pptr; + char nbuf[UINTMAX_STRSIZE_BOUND]; + char const *nptr = NULL; + for (p = fmt; *p && (p = strchr (p, '%')); ) { switch (p[1]) @@ -199,38 +237,36 @@ xheader_format_name (struct tar_stat_info *st, const char *fmt, bool allow_n) case 'd': if (st) { - dirname = safer_name_suffix (dir_name (st->orig_file_name), - false); - len += strlen (dirname) - 1; + dir = safer_name_suffix (dir_name (st->orig_file_name), + false, absolute_names_option); + len += strlen (dir) - 1; } break; - + case 'f': if (st) { - basename = base_name (st->orig_file_name); - len += strlen (basename) - 1; + base = base_name (st->orig_file_name); + len += strlen (base) - 1; } break; - + case 'p': - snprintf (pidbuf, sizeof pidbuf, "%lu", - (unsigned long) getpid ()); - len += strlen (pidbuf) - 1; + pptr = umaxtostr (getpid (), pidbuf); + len += pidbuf + sizeof pidbuf - 1 - pptr - 1; break; - + case 'n': if (allow_n) { - snprintf (nbuf, sizeof nbuf, "%lu", - (unsigned long) global_header_count + 1); - len += strlen (nbuf) - 1; + nptr = umaxtostr (global_header_count + 1, nbuf); + len += nbuf + sizeof nbuf - 1 - nptr - 1; } break; } p++; } - + buf = xmalloc (len + 1); for (q = buf, p = fmt; *p; ) { @@ -242,32 +278,32 @@ xheader_format_name (struct tar_stat_info *st, const char *fmt, bool allow_n) *q++ = *p++; p++; break; - + case 'd': - if (dirname) - q = stpcpy (q, dirname); + if (dir) + q = stpcpy (q, dir); p += 2; break; - + case 'f': - if (basename) - q = stpcpy (q, basename); + if (base) + q = stpcpy (q, base); p += 2; break; - + case 'p': - q = stpcpy (q, pidbuf); + q = stpcpy (q, pptr); p += 2; break; case 'n': - if (allow_n) + if (nptr) { - q = stpcpy (q, nbuf); + q = stpcpy (q, nptr); p += 2; } /* else fall through */ - + default: *q++ = *p++; if (*p) @@ -296,7 +332,7 @@ xheader_xhdr_name (struct tar_stat_info *st) #define GLOBAL_HEADER_TEMPLATE "/GlobalHead.%p.%n" char * -xheader_ghdr_name () +xheader_ghdr_name (void) { if (!globexthdr_name) { @@ -319,7 +355,7 @@ xheader_write (char type, char *name, struct xheader *xhdr) union block *header; size_t size; char *p; - + size = xhdr->size; header = start_private_header (name, size); header->header.typeflag = type; @@ -327,11 +363,11 @@ xheader_write (char type, char *name, struct xheader *xhdr) simple_finish_header (header); p = xhdr->buffer; - + do { size_t len; - + header = find_next_block (); len = BLOCKSIZE; if (len > size) @@ -345,17 +381,17 @@ xheader_write (char type, char *name, struct xheader *xhdr) } while (size > 0); xheader_destroy (xhdr); -} +} void -xheader_write_global () +xheader_write_global (void) { char *name; struct keyword_list *kp; if (!keyword_global_override_list) return; - + extended_header_init (); for (kp = keyword_global_override_list; kp; kp = kp->next) code_string (kp->value, kp->pattern, &extended_header); @@ -397,7 +433,7 @@ locate_handler (char const *keyword) return NULL; } -bool +static bool xheader_protected_pattern_p (const char *pattern) { struct xhdr_tab const *p; @@ -408,7 +444,7 @@ xheader_protected_pattern_p (const char *pattern) return false; } -bool +static bool xheader_protected_keyword_p (const char *keyword) { struct xhdr_tab const *p; @@ -419,61 +455,72 @@ xheader_protected_keyword_p (const char *keyword) return false; } -/* Decodes a single extended header record. Advances P to the next - record. - Returns true on success, false otherwise. */ +/* Decode a single extended header record, advancing *PTR to the next record. + Return true on success, false otherwise. */ static bool -decode_record (char **p, struct tar_stat_info *st) +decode_record (char **ptr, + void (*handler) (void *, char const *, char const *), + void *data) { - size_t len; + char *start = *ptr; + char *p = start; + unsigned long int len; + char *len_lim; char const *keyword; - char *eqp; - char *start = *p; - struct xhdr_tab const *t; + char *nextp; + size_t len_max = extended_header.buffer + extended_header.size - start; - if (**p == 0) - return false; + while (*p == ' ' || *p == '\t') + p++; - len = strtoul (*p, p, 10); - if (**p != ' ') + if (! ISDIGIT (*p)) { - ERROR ((0, 0, - _("Malformed extended header: missing whitespace after the length"))); + if (*p) + ERROR ((0, 0, _("Malformed extended header: missing length"))); return false; } - keyword = ++*p; - for (;*p < start + len; ++*p) - if (**p == '=') - break; + errno = 0; + len = strtoul (p, &len_lim, 10); - if (**p != '=') + if (len_max < len) { - ERROR ((0, 0, _("Malformed extended header: missing equal sign"))); + int len_len = len_lim - p; + ERROR ((0, 0, _("Extended header length %*s is out of range"), + len_len, p)); return false; } - eqp = *p; - **p = 0; + nextp = start + len; - if (xheader_keyword_deleted_p (keyword) - || xheader_keyword_override_p (keyword)) - return true; - t = locate_handler (keyword); - if (t) + for (p = len_lim; *p == ' ' || *p == '\t'; p++) + continue; + if (p == len_lim) { - char endc; - char *value; + ERROR ((0, 0, + _("Malformed extended header: missing blank after length"))); + return false; + } - value = ++*p; + keyword = p; + p = strchr (p, '='); + if (! (p && p < nextp)) + { + ERROR ((0, 0, _("Malformed extended header: missing equal sign"))); + return false; + } - endc = start[len-1]; - start[len-1] = 0; - t->decoder (st, value); - start[len-1] = endc; + if (nextp[-1] != '\n') + { + ERROR ((0, 0, _("Malformed extended header: missing newline"))); + return false; } - *eqp = '='; - *p = &start[len]; + + *p = nextp[-1] = '\0'; + handler (data, keyword, p + 1); + *p = '='; + nextp[-1] = '\n'; + *ptr = nextp; return true; } @@ -488,25 +535,58 @@ run_override_list (struct keyword_list *kp, struct tar_stat_info *st) } } +static void +decx (void *data, char const *keyword, char const *value) +{ + struct xhdr_tab const *t; + struct tar_stat_info *st = data; + + if (xheader_keyword_deleted_p (keyword) + || xheader_keyword_override_p (keyword)) + return; + + t = locate_handler (keyword); + if (t) + t->decoder (st, value); +} + void xheader_decode (struct tar_stat_info *st) { run_override_list (keyword_global_override_list, st); - + run_override_list (global_header_override_list, st); + if (extended_header.size) { char *p = extended_header.buffer + BLOCKSIZE; - char *endp = &extended_header.buffer[extended_header.size-1]; - - while (p < endp) - if (!decode_record (&p, st)) - break; + while (decode_record (&p, decx, st)) + continue; } run_override_list (keyword_override_list, st); } static void -extended_header_init () +decg (void *data, char const *keyword, char const *value) +{ + struct keyword_list **kwl = data; + xheader_list_append (kwl, keyword, value); +} + +void +xheader_decode_global (void) +{ + if (extended_header.size) + { + char *p = extended_header.buffer + BLOCKSIZE; + + xheader_list_destroy (&global_header_override_list); + while (decode_record (&p, decg, &global_header_override_list)) + continue; + } +} + +static void +extended_header_init (void) { if (!extended_header.stk) { @@ -519,8 +599,7 @@ void xheader_store (char const *keyword, struct tar_stat_info const *st, void *data) { struct xhdr_tab const *t; - char *value; - + if (extended_header.buffer) return; t = locate_handler (keyword); @@ -544,6 +623,7 @@ xheader_read (union block *p, size_t size) extended_header.size = size; nblocks = (size + BLOCKSIZE - 1) / BLOCKSIZE; extended_header.buffer = xmalloc (size + 1); + extended_header.buffer[size] = '\0'; do { @@ -551,7 +631,7 @@ xheader_read (union block *p, size_t size) if (len > BLOCKSIZE) len = BLOCKSIZE; - + memcpy (&extended_header.buffer[j], p->buffer, len); set_next_block_after (p); @@ -563,48 +643,24 @@ xheader_read (union block *p, size_t size) while (size > 0); } -static size_t -format_uintmax (uintmax_t val, char *buf, size_t s) -{ - if (!buf) - { - s = 0; - do - s++; - while ((val /= 10) != 0); - } - else - { - char *p = buf + s - 1; - - do - { - *p-- = val % 10 + '0'; - } - while ((val /= 10) != 0); - - while (p >= buf) - *p-- = '0'; - } - return s; -} - static void xheader_print (struct xheader *xhdr, char const *keyword, char const *value) { size_t len = strlen (keyword) + strlen (value) + 3; /* ' ' + '=' + '\n' */ - size_t p, n = 0; - char nbuf[100]; + size_t p; + size_t n = 0; + char nbuf[UINTMAX_STRSIZE_BOUND]; + char const *np; do { p = n; - n = format_uintmax (len + p, NULL, 0); + np = umaxtostr (len + p, nbuf); + n = nbuf + sizeof nbuf - 1 - np; } while (n != p); - format_uintmax (len + n, nbuf, n); - obstack_grow (xhdr->stk, nbuf, n); + obstack_grow (xhdr->stk, np, n); obstack_1grow (xhdr->stk, ' '); obstack_grow (xhdr->stk, keyword, strlen (keyword)); obstack_1grow (xhdr->stk, '='); @@ -642,77 +698,222 @@ xheader_destroy (struct xheader *xhdr) /* Implementations */ + +static void +out_of_range_header (char const *keyword, char const *value, + uintmax_t minus_minval, uintmax_t maxval) +{ + char minval_buf[UINTMAX_STRSIZE_BOUND + 1]; + char maxval_buf[UINTMAX_STRSIZE_BOUND]; + char *minval_string = umaxtostr (minus_minval, minval_buf + 1); + char *maxval_string = umaxtostr (maxval, maxval_buf); + if (minus_minval) + *--minval_string = '-'; + + /* TRANSLATORS: The first %s is the pax extended header keyword + (atime, gid, etc.). */ + ERROR ((0, 0, _("Extended header %s=%s is out of range %s..%s"), + keyword, value, minval_string, maxval_string)); +} + static void code_string (char const *string, char const *keyword, struct xheader *xhdr) { - xheader_print (xhdr, keyword, string); + char *outstr; + if (!utf8_convert (true, string, &outstr)) + { + /* FIXME: report error */ + outstr = xstrdup (string); + } + xheader_print (xhdr, keyword, outstr); + free (outstr); } static void -code_time (time_t t, unsigned long nano, - char const *keyword, struct xheader *xhdr) +decode_string (char **string, char const *arg) { - char sbuf[200]; - size_t s = format_uintmax (t, NULL, 0); - if (s + 11 >= sizeof sbuf) - return; - format_uintmax (t, sbuf, s); - sbuf[s++] = '.'; - s += format_uintmax (nano, sbuf + s, 9); - sbuf[s] = 0; - xheader_print (xhdr, keyword, sbuf); + if (*string) + { + free (*string); + *string = NULL; + } + if (!utf8_convert (false, arg, string)) + { + /* FIXME: report error and act accordingly to --pax invalid=UTF-8 */ + assign_string (string, arg); + } } static void -decode_time (char const *arg, time_t *secs, unsigned long *nsecs) +code_time (struct timespec t, char const *keyword, struct xheader *xhdr) { - uintmax_t u; + time_t s = t.tv_sec; + int ns = t.tv_nsec; + char sbuf[1/*"-"*/ + UINTMAX_STRSIZE_BOUND + 1/*"."*/ + LOG10_BILLION]; + char *np; + bool negative = s < 0; + + if (negative && ns != 0) + { + s++; + ns = BILLION - ns; + } + + np = umaxtostr (negative ? - (uintmax_t) s : (uintmax_t) s, sbuf + 1); + if (negative) + *--np = '-'; + code_ns_fraction (ns, sbuf + UINTMAX_STRSIZE_BOUND); + xheader_print (xhdr, keyword, np); +} + +static bool +decode_time (struct timespec *ts, char const *arg, char const *keyword) +{ + time_t s; + unsigned long int ns = 0; char *p; - if (xstrtoumax (arg, &p, 10, &u, "") == LONGINT_OK) + char *arg_lim; + bool negative = *arg == '-'; + + errno = 0; + + if (ISDIGIT (arg[negative])) { - *secs = u; - if (*p == '.' && xstrtoumax (p+1, NULL, 10, &u, "") == LONGINT_OK) - *nsecs = u; + if (negative) + { + intmax_t i = strtoimax (arg, &arg_lim, 10); + if (TYPE_SIGNED (time_t) ? i < TYPE_MINIMUM (time_t) : i < 0) + goto out_of_range; + s = i; + } + else + { + uintmax_t i = strtoumax (arg, &arg_lim, 10); + if (TYPE_MAXIMUM (time_t) < i) + goto out_of_range; + s = i; + } + + p = arg_lim; + + if (errno == ERANGE) + goto out_of_range; + + if (*p == '.') + { + int digits = 0; + bool trailing_nonzero = false; + + while (ISDIGIT (*++p)) + if (digits < LOG10_BILLION) + { + ns = 10 * ns + (*p - '0'); + digits++; + } + else + trailing_nonzero |= *p != '0'; + + while (digits++ < LOG10_BILLION) + ns *= 10; + + if (negative) + { + /* Convert "-1.10000000000001" to s == -2, ns == 89999999. + I.e., truncate time stamps towards minus infinity while + converting them to internal form. */ + ns += trailing_nonzero; + if (ns != 0) + { + if (s == TYPE_MINIMUM (time_t)) + goto out_of_range; + s--; + ns = BILLION - ns; + } + } + } + + if (! *p) + { + ts->tv_sec = s; + ts->tv_nsec = ns; + return true; + } } + + ERROR ((0, 0, _("Malformed extended header: invalid %s=%s"), + keyword, arg)); + return false; + + out_of_range: + out_of_range_header (keyword, arg, - (uintmax_t) TYPE_MINIMUM (time_t), + TYPE_MAXIMUM (time_t)); + return false; } static void code_num (uintmax_t value, char const *keyword, struct xheader *xhdr) { - char sbuf[100]; - size_t s = format_uintmax (value, NULL, 0); - format_uintmax (value, sbuf, s); - sbuf[s] = 0; - xheader_print (xhdr, keyword, sbuf); + char sbuf[UINTMAX_STRSIZE_BOUND]; + xheader_print (xhdr, keyword, umaxtostr (value, sbuf)); +} + +static bool +decode_num (uintmax_t *num, char const *arg, uintmax_t maxval, + char const *keyword) +{ + uintmax_t u; + char *arg_lim; + + if (! (ISDIGIT (*arg) + && (errno = 0, u = strtoumax (arg, &arg_lim, 10), !*arg_lim))) + { + ERROR ((0, 0, _("Malformed extended header: invalid %s=%s"), + keyword, arg)); + return false; + } + + if (! (u <= maxval && errno != ERANGE)) + { + out_of_range_header (keyword, arg, 0, maxval); + return false; + } + + *num = u; + return true; } static void -dummy_coder (struct tar_stat_info const *st, char const *keyword, - struct xheader *xhdr, void *data) +dummy_coder (struct tar_stat_info const *st __attribute__ ((unused)), + char const *keyword __attribute__ ((unused)), + struct xheader *xhdr __attribute__ ((unused)), + void *data __attribute__ ((unused))) { } static void -dummy_decoder (struct tar_stat_info *st, char const *arg) +dummy_decoder (struct tar_stat_info *st __attribute__ ((unused)), + char const *arg __attribute__ ((unused))) { } static void atime_coder (struct tar_stat_info const *st, char const *keyword, - struct xheader *xhdr, void *data) + struct xheader *xhdr, void *data __attribute__ ((unused))) { - code_time (st->stat.st_atime, st->atime_nsec, keyword, xhdr); + code_time (get_stat_atime (&st->stat), keyword, xhdr); } static void atime_decoder (struct tar_stat_info *st, char const *arg) { - decode_time (arg, &st->stat.st_atime, &st->atime_nsec); + struct timespec ts; + if (decode_time (&ts, arg, "atime")) + set_stat_atime (&st->stat, ts); } static void gid_coder (struct tar_stat_info const *st, char const *keyword, - struct xheader *xhdr, void *data) + struct xheader *xhdr, void *data __attribute__ ((unused))) { code_num (st->stat.st_gid, keyword, xhdr); } @@ -721,13 +922,13 @@ static void gid_decoder (struct tar_stat_info *st, char const *arg) { uintmax_t u; - if (xstrtoumax (arg, NULL, 10, &u, "") == LONGINT_OK) + if (decode_num (&u, arg, TYPE_MAXIMUM (gid_t), "gid")) st->stat.st_gid = u; } static void gname_coder (struct tar_stat_info const *st, char const *keyword, - struct xheader *xhdr, void *data) + struct xheader *xhdr, void *data __attribute__ ((unused))) { code_string (st->gname, keyword, xhdr); } @@ -735,12 +936,12 @@ gname_coder (struct tar_stat_info const *st, char const *keyword, static void gname_decoder (struct tar_stat_info *st, char const *arg) { - assign_string (&st->gname, arg); + decode_string (&st->gname, arg); } static void linkpath_coder (struct tar_stat_info const *st, char const *keyword, - struct xheader *xhdr, void *data) + struct xheader *xhdr, void *data __attribute__ ((unused))) { code_string (st->link_name, keyword, xhdr); } @@ -748,38 +949,42 @@ linkpath_coder (struct tar_stat_info const *st, char const *keyword, static void linkpath_decoder (struct tar_stat_info *st, char const *arg) { - assign_string (&st->link_name, arg); + decode_string (&st->link_name, arg); } static void ctime_coder (struct tar_stat_info const *st, char const *keyword, - struct xheader *xhdr, void *data) + struct xheader *xhdr, void *data __attribute__ ((unused))) { - code_time (st->stat.st_ctime, st->ctime_nsec, keyword, xhdr); + code_time (get_stat_ctime (&st->stat), keyword, xhdr); } static void ctime_decoder (struct tar_stat_info *st, char const *arg) { - decode_time (arg, &st->stat.st_ctime, &st->ctime_nsec); + struct timespec ts; + if (decode_time (&ts, arg, "ctime")) + set_stat_ctime (&st->stat, ts); } static void mtime_coder (struct tar_stat_info const *st, char const *keyword, - struct xheader *xhdr, void *data) + struct xheader *xhdr, void *data __attribute__ ((unused))) { - code_time (st->stat.st_mtime, st->mtime_nsec, keyword, xhdr); + code_time (get_stat_mtime (&st->stat), keyword, xhdr); } static void mtime_decoder (struct tar_stat_info *st, char const *arg) { - decode_time (arg, &st->stat.st_mtime, &st->mtime_nsec); + struct timespec ts; + if (decode_time (&ts, arg, "mtime")) + set_stat_mtime (&st->stat, ts); } static void path_coder (struct tar_stat_info const *st, char const *keyword, - struct xheader *xhdr, void *data) + struct xheader *xhdr, void *data __attribute__ ((unused))) { code_string (st->file_name, keyword, xhdr); } @@ -787,14 +992,14 @@ path_coder (struct tar_stat_info const *st, char const *keyword, static void path_decoder (struct tar_stat_info *st, char const *arg) { - assign_string (&st->orig_file_name, arg); - assign_string (&st->file_name, arg); + decode_string (&st->orig_file_name, arg); + decode_string (&st->file_name, arg); st->had_trailing_slash = strip_trailing_slashes (st->file_name); } static void size_coder (struct tar_stat_info const *st, char const *keyword, - struct xheader *xhdr, void *data) + struct xheader *xhdr, void *data __attribute__ ((unused))) { code_num (st->stat.st_size, keyword, xhdr); } @@ -803,13 +1008,13 @@ static void size_decoder (struct tar_stat_info *st, char const *arg) { uintmax_t u; - if (xstrtoumax (arg, NULL, 10, &u, "") == LONGINT_OK) - st->stat.st_size = u; + if (decode_num (&u, arg, TYPE_MAXIMUM (off_t), "size")) + st->archive_file_size = st->stat.st_size = u; } static void uid_coder (struct tar_stat_info const *st, char const *keyword, - struct xheader *xhdr, void *data) + struct xheader *xhdr, void *data __attribute__ ((unused))) { code_num (st->stat.st_uid, keyword, xhdr); } @@ -818,13 +1023,13 @@ static void uid_decoder (struct tar_stat_info *st, char const *arg) { uintmax_t u; - if (xstrtoumax (arg, NULL, 10, &u, "") == LONGINT_OK) + if (decode_num (&u, arg, TYPE_MAXIMUM (uid_t), "uid")) st->stat.st_uid = u; } static void uname_coder (struct tar_stat_info const *st, char const *keyword, - struct xheader *xhdr, void *data) + struct xheader *xhdr, void *data __attribute__ ((unused))) { code_string (st->uname, keyword, xhdr); } @@ -832,7 +1037,7 @@ uname_coder (struct tar_stat_info const *st, char const *keyword, static void uname_decoder (struct tar_stat_info *st, char const *arg) { - assign_string (&st->uname, arg); + decode_string (&st->uname, arg); } static void @@ -846,13 +1051,14 @@ static void sparse_size_decoder (struct tar_stat_info *st, char const *arg) { uintmax_t u; - if (xstrtoumax (arg, NULL, 10, &u, "") == LONGINT_OK) - st->archive_file_size = u; + if (decode_num (&u, arg, TYPE_MAXIMUM (off_t), "GNU.sparse.size")) + st->stat.st_size = u; } static void sparse_numblocks_coder (struct tar_stat_info const *st, char const *keyword, - struct xheader *xhdr, void *data) + struct xheader *xhdr, + void *data __attribute__ ((unused))) { code_num (st->sparse_map_avail, keyword, xhdr); } @@ -861,10 +1067,10 @@ static void sparse_numblocks_decoder (struct tar_stat_info *st, char const *arg) { uintmax_t u; - if (xstrtoumax (arg, NULL, 10, &u, "") == LONGINT_OK) + if (decode_num (&u, arg, SIZE_MAX, "GNU.sparse.numblocks")) { st->sparse_map_size = u; - st->sparse_map = calloc(st->sparse_map_size, sizeof(st->sparse_map[0])); + st->sparse_map = xcalloc (u, sizeof st->sparse_map[0]); st->sparse_map_avail = 0; } } @@ -881,7 +1087,7 @@ static void sparse_offset_decoder (struct tar_stat_info *st, char const *arg) { uintmax_t u; - if (xstrtoumax (arg, NULL, 10, &u, "") == LONGINT_OK) + if (decode_num (&u, arg, TYPE_MAXIMUM (off_t), "GNU.sparse.offset")) st->sparse_map[st->sparse_map_avail].offset = u; } @@ -897,32 +1103,29 @@ static void sparse_numbytes_decoder (struct tar_stat_info *st, char const *arg) { uintmax_t u; - if (xstrtoumax (arg, NULL, 10, &u, "") == LONGINT_OK) + if (decode_num (&u, arg, SIZE_MAX, "GNU.sparse.numbytes")) { if (st->sparse_map_avail == st->sparse_map_size) - { - size_t newsize = st->sparse_map_size *= 2; - st->sparse_map = xrealloc (st->sparse_map, - st->sparse_map_size - * sizeof st->sparse_map[0]); - } + st->sparse_map = x2nrealloc (st->sparse_map, + &st->sparse_map_size, + sizeof st->sparse_map[0]); st->sparse_map[st->sparse_map_avail++].numbytes = u; } } struct xhdr_tab const xhdr_tab[] = { - { "atime", atime_coder, atime_decoder }, - { "comment", dummy_coder, dummy_decoder }, - { "charset", dummy_coder, dummy_decoder }, - { "ctime", ctime_coder, ctime_decoder }, - { "gid", gid_coder, gid_decoder }, - { "gname", gname_coder, gname_decoder }, - { "linkpath", linkpath_coder, linkpath_decoder}, - { "mtime", mtime_coder, mtime_decoder }, - { "path", path_coder, path_decoder }, - { "size", size_coder, size_decoder }, - { "uid", uid_coder, uid_decoder }, - { "uname", uname_coder, uname_decoder }, + { "atime", atime_coder, atime_decoder, false }, + { "comment", dummy_coder, dummy_decoder, false }, + { "charset", dummy_coder, dummy_decoder, false }, + { "ctime", ctime_coder, ctime_decoder, false }, + { "gid", gid_coder, gid_decoder, false }, + { "gname", gname_coder, gname_decoder, false }, + { "linkpath", linkpath_coder, linkpath_decoder, false }, + { "mtime", mtime_coder, mtime_decoder, false }, + { "path", path_coder, path_decoder, false }, + { "size", size_coder, size_decoder, false }, + { "uid", uid_coder, uid_decoder, false }, + { "uname", uname_coder, uname_decoder, false }, /* Sparse file handling */ { "GNU.sparse.size", sparse_size_coder, sparse_size_decoder, true }, @@ -938,11 +1141,12 @@ struct xhdr_tab const xhdr_tab[] = { /* The next directory entry actually contains the names of files that were in the directory at the time the dump was made. Supersedes GNUTYPE_DUMPDIR header type. */ - { "GNU.dumpdir", dumpdir_coder, dumpdir_decoder }, + { "GNU.dump.name", dump_name_coder, dump_name_decoder, false }, + { "GNU.dump.status", dump_status_coder, dump_status_decoder, false }, /* Keeps the tape/volume header. May be present only in the global headers. Equivalent to GNUTYPE_VOLHDR. */ - { "GNU.volume.header", volume_header_coder, volume_header_decoder }, + { "GNU.volume.header", volume_header_coder, volume_header_decoder, false }, /* These may be present in a first global header of the archive. They provide the same functionality as GNUTYPE_MULTIVOL header. @@ -950,9 +1154,9 @@ struct xhdr_tab const xhdr_tab[] = { otherwise kept in the size field of a multivolume header. The GNU.volume.offset keeps the offset of the start of this volume, otherwise kept in oldgnu_header.offset. */ - { "GNU.volume.size", volume_size_coder, volume_size_decoder }, - { "GNU.volume.offset", volume_offset_coder, volume_offset_decoder }, + { "GNU.volume.size", volume_size_coder, volume_size_decoder, false }, + { "GNU.volume.offset", volume_offset_coder, volume_offset_decoder, false }, #endif - { NULL, NULL, NULL } + { NULL, NULL, NULL, false } };