X-Git-Url: https://git.dogcows.com/gitweb?a=blobdiff_plain;f=src%2Fxheader.c;h=c779c0ad47c6aad23b4011e4a007879bb4e2a5e3;hb=df59690240b9a41d59ebe9e809faffd93f340020;hp=089604347ceab7c916b588a8e46172ceb760a7e9;hpb=19a63e523dddd8e9fb0f4f510594172103404a74;p=chaz%2Ftar diff --git a/src/xheader.c b/src/xheader.c index 0896043..c779c0a 100644 --- a/src/xheader.c +++ b/src/xheader.c @@ -1,10 +1,10 @@ /* POSIX extended headers for tar. - Copyright (C) 2003, 2004, 2005, 2006 Free Software Foundation, Inc. + Copyright (C) 2003, 2004, 2005, 2006, 2007, 2009 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 - Free Software Foundation; either version 2, or (at your option) any later + Free Software Foundation; either version 3, or (at your option) any later version. This program is distributed in the hope that it will be useful, but @@ -22,12 +22,9 @@ #include #include #include -#include #include "common.h" -#include - 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)); @@ -35,7 +32,6 @@ 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 (void); /* Number of global headers written so far. */ static size_t global_header_count; @@ -172,12 +168,12 @@ xheader_set_keyword_equal (char *kw, char *eq) global = false; } - while (p > kw && isspace (*p)) + while (p > kw && isspace ((unsigned char) *p)) p--; *p = 0; - for (p = eq + 1; *p && isspace (*p); p++) + for (p = eq + 1; *p && isspace ((unsigned char) *p); p++) ; if (strcmp (kw, "delete") == 0) @@ -225,7 +221,7 @@ xheader_set_option (char *string) to the result of the basename utility on the translated file name. %p The process ID of the pax process. - %n The value of the 3rd argument. + %n The value of the 3rd argument. %% A '%' character. */ char * @@ -264,7 +260,7 @@ xheader_format_name (struct tar_stat_info *st, const char *fmt, size_t n) case 'f': if (st) { - base = base_name (st->orig_file_name); + base = last_component (st->orig_file_name); len += strlen (base) - 2; } break; @@ -331,7 +327,7 @@ xheader_format_name (struct tar_stat_info *st, const char *fmt, size_t n) } free (dirp); - + /* Do not allow it to end in a slash */ while (q > buf && ISSLASH (q[-1])) q--; @@ -405,7 +401,7 @@ xheader_write (char type, char *name, struct xheader *xhdr) } void -xheader_write_global (void) +xheader_write_global (struct xheader *xhdr) { char *name; struct keyword_list *kp; @@ -413,12 +409,11 @@ xheader_write_global (void) if (!keyword_global_override_list) return; - extended_header_init (); + xheader_init (xhdr); for (kp = keyword_global_override_list; kp; kp = kp->next) - code_string (kp->value, kp->pattern, &extended_header); - xheader_finish (&extended_header); - xheader_write (XGLTYPE, name = xheader_ghdr_name (), - &extended_header); + code_string (kp->value, kp->pattern, xhdr); + xheader_finish (xhdr); + xheader_write (XGLTYPE, name = xheader_ghdr_name (), xhdr); free (name); } @@ -430,7 +425,7 @@ struct xhdr_tab char const *keyword; void (*coder) (struct tar_stat_info const *, char const *, struct xheader *, void const *data); - void (*decoder) (struct tar_stat_info *, char const *, size_t); + void (*decoder) (struct tar_stat_info *, char const *, char const *, size_t); bool protect; }; @@ -478,17 +473,19 @@ xheader_protected_keyword_p (const char *keyword) /* Decode a single extended header record, advancing *PTR to the next record. Return true on success, false otherwise. */ static bool -decode_record (char **ptr, +decode_record (struct xheader *xhdr, + char **ptr, void (*handler) (void *, char const *, char const *, size_t), void *data) { char *start = *ptr; char *p = start; - unsigned long int len; + uintmax_t u; + size_t len; char *len_lim; char const *keyword; char *nextp; - size_t len_max = extended_header.buffer + extended_header.size - start; + size_t len_max = xhdr->buffer + xhdr->size - start; while (*p == ' ' || *p == '\t') p++; @@ -501,7 +498,12 @@ decode_record (char **ptr, } errno = 0; - len = strtoul (p, &len_lim, 10); + len = u = strtoumax (p, &len_lim, 10); + if (len != u || errno == ERANGE) + { + ERROR ((0, 0, _("Extended header length is out of allowed range"))); + return false; + } if (len_max < len) { @@ -551,7 +553,7 @@ run_override_list (struct keyword_list *kp, struct tar_stat_info *st) { struct xhdr_tab const *t = locate_handler (kp->pattern); if (t) - t->decoder (st, kp->value, strlen (kp->value)); + t->decoder (st, t->keyword, kp->value, strlen (kp->value)); } } @@ -567,10 +569,11 @@ decx (void *data, char const *keyword, char const *value, size_t size) t = locate_handler (keyword); if (t) - t->decoder (st, value, size); + t->decoder (st, keyword, value, size); else - ERROR((0, 0, _("Ignoring unknown extended header keyword `%s'"), - keyword)); + WARNOPT (WARN_UNKNOWN_KEYWORD, + (0, 0, _("Ignoring unknown extended header keyword `%s'"), + keyword)); } void @@ -579,10 +582,10 @@ 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) + if (st->xhdr.size) { - char *p = extended_header.buffer + BLOCKSIZE; - while (decode_record (&p, decx, st)) + char *p = st->xhdr.buffer + BLOCKSIZE; + while (decode_record (&st->xhdr, &p, decx, st)) continue; } run_override_list (keyword_override_list, st); @@ -597,35 +600,35 @@ decg (void *data, char const *keyword, char const *value, } void -xheader_decode_global (void) +xheader_decode_global (struct xheader *xhdr) { - if (extended_header.size) + if (xhdr->size) { - char *p = extended_header.buffer + BLOCKSIZE; + char *p = xhdr->buffer + BLOCKSIZE; xheader_list_destroy (&global_header_override_list); - while (decode_record (&p, decg, &global_header_override_list)) + while (decode_record (xhdr, &p, decg, &global_header_override_list)) continue; } } -static void -extended_header_init (void) +void +xheader_init (struct xheader *xhdr) { - if (!extended_header.stk) + if (!xhdr->stk) { - extended_header.stk = xmalloc (sizeof *extended_header.stk); - obstack_init (extended_header.stk); + xhdr->stk = xmalloc (sizeof *xhdr->stk); + obstack_init (xhdr->stk); } } void -xheader_store (char const *keyword, struct tar_stat_info const *st, +xheader_store (char const *keyword, struct tar_stat_info *st, void const *data) { struct xhdr_tab const *t; - if (extended_header.buffer) + if (st->xhdr.buffer) return; t = locate_handler (keyword); if (!t || !t->coder) @@ -633,22 +636,20 @@ xheader_store (char const *keyword, struct tar_stat_info const *st, if (xheader_keyword_deleted_p (keyword) || xheader_keyword_override_p (keyword)) return; - extended_header_init (); - t->coder (st, keyword, &extended_header, data); + xheader_init (&st->xhdr); + t->coder (st, keyword, &st->xhdr, data); } void -xheader_read (union block *p, size_t size) +xheader_read (struct xheader *xhdr, union block *p, size_t size) { size_t j = 0; - size_t nblocks; - free (extended_header.buffer); + xheader_init (xhdr); size += BLOCKSIZE; - extended_header.size = size; - nblocks = (size + BLOCKSIZE - 1) / BLOCKSIZE; - extended_header.buffer = xmalloc (size + 1); - extended_header.buffer[size] = '\0'; + xhdr->size = size; + xhdr->buffer = xmalloc (size + 1); + xhdr->buffer[size] = '\0'; do { @@ -657,7 +658,7 @@ xheader_read (union block *p, size_t size) if (len > BLOCKSIZE) len = BLOCKSIZE; - memcpy (&extended_header.buffer[j], p->buffer, len); + memcpy (&xhdr->buffer[j], p->buffer, len); set_next_block_after (p); p = find_next_block (); @@ -728,39 +729,39 @@ xheader_destroy (struct xheader *xhdr) /* Buildable strings */ -static uintmax_t string_length; void -xheader_string_begin () +xheader_string_begin (struct xheader *xhdr) { - string_length = 0; + xhdr->string_length = 0; } void -xheader_string_add (char const *s) +xheader_string_add (struct xheader *xhdr, char const *s) { - if (extended_header.buffer) + if (xhdr->buffer) return; - extended_header_init (); - string_length += strlen (s); - x_obstack_grow (&extended_header, s, strlen (s)); + xheader_init (xhdr); + xhdr->string_length += strlen (s); + x_obstack_grow (xhdr, s, strlen (s)); } -void -xheader_string_end (char const *keyword) +bool +xheader_string_end (struct xheader *xhdr, char const *keyword) { - size_t len; - size_t p; - size_t n = 0; + uintmax_t len; + uintmax_t p; + uintmax_t n = 0; + size_t size; char nbuf[UINTMAX_STRSIZE_BOUND]; char const *np; char *cp; - if (extended_header.buffer) - return; - extended_header_init (); + if (xhdr->buffer) + return false; + xheader_init (xhdr); - len = strlen (keyword) + string_length + 3; /* ' ' + '=' + '\n' */ + len = strlen (keyword) + xhdr->string_length + 3; /* ' ' + '=' + '\n' */ do { @@ -771,14 +772,24 @@ xheader_string_end (char const *keyword) while (n != p); p = strlen (keyword) + n + 2; - x_obstack_blank (&extended_header, p); - x_obstack_1grow (&extended_header, '\n'); - cp = obstack_next_free (extended_header.stk) - string_length - p - 1; - memmove (cp + p, cp, string_length); + size = p; + if (size != p) + { + ERROR ((0, 0, + _("Generated keyword/value pair is too long (keyword=%s, length=%s)"), + keyword, nbuf)); + obstack_free (xhdr->stk, obstack_finish (xhdr->stk)); + return false; + } + x_obstack_blank (xhdr, p); + x_obstack_1grow (xhdr, '\n'); + cp = obstack_next_free (xhdr->stk) - xhdr->string_length - p - 1; + memmove (cp + p, cp, xhdr->string_length); cp = stpcpy (cp, np); *cp++ = ' '; cp = stpcpy (cp, keyword); *cp++ = '='; + return true; } @@ -939,7 +950,7 @@ decode_time (struct timespec *ts, char const *arg, char const *keyword) return true; } - + static void code_num (uintmax_t value, char const *keyword, struct xheader *xhdr) @@ -983,6 +994,7 @@ dummy_coder (struct tar_stat_info const *st __attribute__ ((unused)), static void dummy_decoder (struct tar_stat_info *st __attribute__ ((unused)), + char const *keyword __attribute__ ((unused)), char const *arg __attribute__ ((unused)), size_t size __attribute__((unused))) { @@ -996,11 +1008,13 @@ atime_coder (struct tar_stat_info const *st, char const *keyword, } static void -atime_decoder (struct tar_stat_info *st, char const *arg, +atime_decoder (struct tar_stat_info *st, + char const *keyword, + char const *arg, size_t size __attribute__((unused))) { struct timespec ts; - if (decode_time (&ts, arg, "atime")) + if (decode_time (&ts, arg, keyword)) st->atime = ts; } @@ -1012,11 +1026,13 @@ gid_coder (struct tar_stat_info const *st, char const *keyword, } static void -gid_decoder (struct tar_stat_info *st, char const *arg, +gid_decoder (struct tar_stat_info *st, + char const *keyword, + char const *arg, size_t size __attribute__((unused))) { uintmax_t u; - if (decode_num (&u, arg, TYPE_MAXIMUM (gid_t), "gid")) + if (decode_num (&u, arg, TYPE_MAXIMUM (gid_t), keyword)) st->stat.st_gid = u; } @@ -1028,7 +1044,9 @@ gname_coder (struct tar_stat_info const *st, char const *keyword, } static void -gname_decoder (struct tar_stat_info *st, char const *arg, +gname_decoder (struct tar_stat_info *st, + char const *keyword __attribute__((unused)), + char const *arg, size_t size __attribute__((unused))) { decode_string (&st->gname, arg); @@ -1042,7 +1060,9 @@ linkpath_coder (struct tar_stat_info const *st, char const *keyword, } static void -linkpath_decoder (struct tar_stat_info *st, char const *arg, +linkpath_decoder (struct tar_stat_info *st, + char const *keyword __attribute__((unused)), + char const *arg, size_t size __attribute__((unused))) { decode_string (&st->link_name, arg); @@ -1056,27 +1076,32 @@ ctime_coder (struct tar_stat_info const *st, char const *keyword, } static void -ctime_decoder (struct tar_stat_info *st, char const *arg, +ctime_decoder (struct tar_stat_info *st, + char const *keyword, + char const *arg, size_t size __attribute__((unused))) { struct timespec ts; - if (decode_time (&ts, arg, "ctime")) + if (decode_time (&ts, arg, keyword)) st->ctime = ts; } static void mtime_coder (struct tar_stat_info const *st, char const *keyword, - struct xheader *xhdr, void const *data __attribute__ ((unused))) + struct xheader *xhdr, void const *data) { - code_time (st->mtime, keyword, xhdr); + struct timespec const *mtime = data; + code_time (mtime ? *mtime : st->mtime, keyword, xhdr); } static void -mtime_decoder (struct tar_stat_info *st, char const *arg, +mtime_decoder (struct tar_stat_info *st, + char const *keyword, + char const *arg, size_t size __attribute__((unused))) { struct timespec ts; - if (decode_time (&ts, arg, "mtime")) + if (decode_time (&ts, arg, keyword)) st->mtime = ts; } @@ -1088,7 +1113,9 @@ path_coder (struct tar_stat_info const *st, char const *keyword, } static void -path_decoder (struct tar_stat_info *st, char const *arg, +path_decoder (struct tar_stat_info *st, + char const *keyword __attribute__((unused)), + char const *arg, size_t size __attribute__((unused))) { decode_string (&st->orig_file_name, arg); @@ -1104,11 +1131,13 @@ size_coder (struct tar_stat_info const *st, char const *keyword, } static void -size_decoder (struct tar_stat_info *st, char const *arg, +size_decoder (struct tar_stat_info *st, + char const *keyword, + char const *arg, size_t size __attribute__((unused))) { uintmax_t u; - if (decode_num (&u, arg, TYPE_MAXIMUM (off_t), "size")) + if (decode_num (&u, arg, TYPE_MAXIMUM (off_t), keyword)) st->stat.st_size = u; } @@ -1120,11 +1149,13 @@ uid_coder (struct tar_stat_info const *st, char const *keyword, } static void -uid_decoder (struct tar_stat_info *st, char const *arg, +uid_decoder (struct tar_stat_info *st, + char const *keyword, + char const *arg, size_t size __attribute__((unused))) { uintmax_t u; - if (decode_num (&u, arg, TYPE_MAXIMUM (uid_t), "uid")) + if (decode_num (&u, arg, TYPE_MAXIMUM (uid_t), keyword)) st->stat.st_uid = u; } @@ -1136,7 +1167,9 @@ uname_coder (struct tar_stat_info const *st, char const *keyword, } static void -uname_decoder (struct tar_stat_info *st, char const *arg, +uname_decoder (struct tar_stat_info *st, + char const *keyword __attribute__((unused)), + char const *arg, size_t size __attribute__((unused))) { decode_string (&st->uname, arg); @@ -1150,11 +1183,13 @@ sparse_size_coder (struct tar_stat_info const *st, char const *keyword, } static void -sparse_size_decoder (struct tar_stat_info *st, char const *arg, +sparse_size_decoder (struct tar_stat_info *st, + char const *keyword, + char const *arg, size_t size __attribute__((unused))) { uintmax_t u; - if (decode_num (&u, arg, TYPE_MAXIMUM (off_t), "GNU.sparse.size")) + if (decode_num (&u, arg, TYPE_MAXIMUM (off_t), keyword)) st->stat.st_size = u; } @@ -1167,11 +1202,13 @@ sparse_numblocks_coder (struct tar_stat_info const *st, char const *keyword, } static void -sparse_numblocks_decoder (struct tar_stat_info *st, char const *arg, +sparse_numblocks_decoder (struct tar_stat_info *st, + char const *keyword, + char const *arg, size_t size __attribute__((unused))) { uintmax_t u; - if (decode_num (&u, arg, SIZE_MAX, "GNU.sparse.numblocks")) + if (decode_num (&u, arg, SIZE_MAX, keyword)) { st->sparse_map_size = u; st->sparse_map = xcalloc (u, sizeof st->sparse_map[0]); @@ -1188,11 +1225,13 @@ sparse_offset_coder (struct tar_stat_info const *st, char const *keyword, } static void -sparse_offset_decoder (struct tar_stat_info *st, char const *arg, +sparse_offset_decoder (struct tar_stat_info *st, + char const *keyword, + char const *arg, size_t size __attribute__((unused))) { uintmax_t u; - if (decode_num (&u, arg, TYPE_MAXIMUM (off_t), "GNU.sparse.offset")) + if (decode_num (&u, arg, TYPE_MAXIMUM (off_t), keyword)) { if (st->sparse_map_avail < st->sparse_map_size) st->sparse_map[st->sparse_map_avail].offset = u; @@ -1211,26 +1250,29 @@ sparse_numbytes_coder (struct tar_stat_info const *st, char const *keyword, } static void -sparse_numbytes_decoder (struct tar_stat_info *st, char const *arg, +sparse_numbytes_decoder (struct tar_stat_info *st, + char const *keyword, + char const *arg, size_t size __attribute__((unused))) { uintmax_t u; - if (decode_num (&u, arg, SIZE_MAX, "GNU.sparse.numbytes")) + if (decode_num (&u, arg, SIZE_MAX, keyword)) { if (st->sparse_map_avail < st->sparse_map_size) st->sparse_map[st->sparse_map_avail++].numbytes = u; else ERROR ((0, 0, _("Malformed extended header: excess %s=%s"), - "GNU.sparse.numbytes", arg)); + keyword, arg)); } } static void -sparse_map_decoder (struct tar_stat_info *st, char const *arg, +sparse_map_decoder (struct tar_stat_info *st, + char const *keyword, + char const *arg, size_t size __attribute__((unused))) { int offset = 1; - static char *keyword = "GNU.sparse.map"; st->sparse_map_avail = 0; while (1) @@ -1304,7 +1346,9 @@ dumpdir_coder (struct tar_stat_info const *st, char const *keyword, } static void -dumpdir_decoder (struct tar_stat_info *st, char const *arg, +dumpdir_decoder (struct tar_stat_info *st, + char const *keyword __attribute__((unused)), + char const *arg, size_t size) { st->dumpdir = xmalloc (size); @@ -1319,7 +1363,10 @@ volume_label_coder (struct tar_stat_info const *st, char const *keyword, } static void -volume_label_decoder (struct tar_stat_info *st, char const *arg, size_t size) +volume_label_decoder (struct tar_stat_info *st, + char const *keyword __attribute__((unused)), + char const *arg, + size_t size __attribute__((unused))) { decode_string (&volume_label, arg); } @@ -1328,15 +1375,17 @@ static void volume_size_coder (struct tar_stat_info const *st, char const *keyword, struct xheader *xhdr, void const *data) { - off_t v = *(off_t*)data; - code_num (v, keyword, xhdr); + off_t const *v = data; + code_num (*v, keyword, xhdr); } static void -volume_size_decoder (struct tar_stat_info *st, char const *arg, size_t size) +volume_size_decoder (struct tar_stat_info *st, + char const *keyword, + char const *arg, size_t size) { uintmax_t u; - if (decode_num (&u, arg, TYPE_MAXIMUM (uintmax_t), "GNU.volume.size")) + if (decode_num (&u, arg, TYPE_MAXIMUM (uintmax_t), keyword)) continued_file_size = u; } @@ -1345,21 +1394,25 @@ static void volume_offset_coder (struct tar_stat_info const *st, char const *keyword, struct xheader *xhdr, void const *data) { - off_t v = *(off_t*)data; - code_num (v, keyword, xhdr); + off_t const *v = data; + code_num (*v, keyword, xhdr); } static void -volume_offset_decoder (struct tar_stat_info *st, char const *arg, size_t size) +volume_offset_decoder (struct tar_stat_info *st, + char const *keyword, + char const *arg, size_t size) { uintmax_t u; - if (decode_num (&u, arg, TYPE_MAXIMUM (uintmax_t), "GNU.volume.offset")) + if (decode_num (&u, arg, TYPE_MAXIMUM (uintmax_t), keyword)) continued_file_offset = u; } static void -volume_filename_decoder (struct tar_stat_info *st, char const *arg, - size_t size) +volume_filename_decoder (struct tar_stat_info *st, + char const *keyword __attribute__((unused)), + char const *arg, + size_t size __attribute__((unused))) { decode_string (&continued_file_name, arg); } @@ -1372,30 +1425,34 @@ sparse_major_coder (struct tar_stat_info const *st, char const *keyword, } static void -sparse_major_decoder (struct tar_stat_info *st, char const *arg, +sparse_major_decoder (struct tar_stat_info *st, + char const *keyword, + char const *arg, size_t size) { uintmax_t u; - if (decode_num (&u, arg, TYPE_MAXIMUM (unsigned), "GNU.sparse.major")) + if (decode_num (&u, arg, TYPE_MAXIMUM (unsigned), keyword)) st->sparse_major = u; } - + static void sparse_minor_coder (struct tar_stat_info const *st, char const *keyword, struct xheader *xhdr, void const *data) { - code_num (st->sparse_minor, keyword, xhdr); + code_num (st->sparse_minor, keyword, xhdr); } static void -sparse_minor_decoder (struct tar_stat_info *st, char const *arg, +sparse_minor_decoder (struct tar_stat_info *st, + char const *keyword, + char const *arg, size_t size) { uintmax_t u; - if (decode_num (&u, arg, TYPE_MAXIMUM (unsigned), "GNU.sparse.minor")) + if (decode_num (&u, arg, TYPE_MAXIMUM (unsigned), keyword)) st->sparse_minor = u; } - + struct xhdr_tab const xhdr_tab[] = { { "atime", atime_coder, atime_decoder, false }, { "comment", dummy_coder, dummy_decoder, false }, @@ -1417,11 +1474,13 @@ struct xhdr_tab const xhdr_tab[] = { true }, { "GNU.sparse.minor", sparse_minor_coder, sparse_minor_decoder, true }, - { "GNU.sparse.realsize", sparse_size_coder, sparse_size_decoder, true }, - - { "GNU.sparse.size", sparse_size_coder, sparse_size_decoder, true }, + { "GNU.sparse.realsize", sparse_size_coder, sparse_size_decoder, + true }, { "GNU.sparse.numblocks", sparse_numblocks_coder, sparse_numblocks_decoder, true }, + + /* tar 1.14 - 1.15.90 keywords. */ + { "GNU.sparse.size", sparse_size_coder, sparse_size_decoder, true }, /* tar 1.14 - 1.15.1 keywords. Multiple instances of these appeared in 'x' headers, and each of them was meaningful. It confilcted with POSIX specs, which requires that "when extended header records conflict, the last one