X-Git-Url: https://git.dogcows.com/gitweb?a=blobdiff_plain;f=src%2Fxheader.c;h=11b725e06622c082a0255a2fbf5c8cd3419c39cd;hb=8e3f3adf9888cca4acedfe005d277867c999fcb3;hp=3eb1505890f68b207c5c1a66d2f3b306521239af;hpb=1ecd6672e1631d7fb02141c13b4e07b7fdbf9d41;p=chaz%2Ftar diff --git a/src/xheader.c b/src/xheader.c index 3eb1505..11b725e 100644 --- a/src/xheader.c +++ b/src/xheader.c @@ -225,7 +225,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 +264,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 +331,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--; @@ -430,7 +430,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; }; @@ -484,7 +484,8 @@ decode_record (char **ptr, { char *start = *ptr; char *p = start; - unsigned long int len; + uintmax_t u; + size_t len; char *len_lim; char const *keyword; char *nextp; @@ -501,7 +502,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 +557,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,7 +573,7 @@ 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)); @@ -641,12 +647,10 @@ void xheader_read (union block *p, size_t size) { size_t j = 0; - size_t nblocks; free (extended_header.buffer); size += BLOCKSIZE; extended_header.size = size; - nblocks = (size + BLOCKSIZE - 1) / BLOCKSIZE; extended_header.buffer = xmalloc (size + 1); extended_header.buffer[size] = '\0'; @@ -746,18 +750,19 @@ xheader_string_add (char const *s) x_obstack_grow (&extended_header, s, strlen (s)); } -void +bool xheader_string_end (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; + return false; extended_header_init (); len = strlen (keyword) + string_length + 3; /* ' ' + '=' + '\n' */ @@ -771,6 +776,15 @@ xheader_string_end (char const *keyword) while (n != p); p = strlen (keyword) + n + 2; + size = p; + if (size != p) + { + ERROR ((0, 0, + _("Generated keyword/value pair is too long (keyword=%s, length=%s)"), + keyword, nbuf)); + obstack_free (extended_header.stk, obstack_finish (extended_header.stk)); + return false; + } x_obstack_blank (&extended_header, p); x_obstack_1grow (&extended_header, '\n'); cp = obstack_next_free (extended_header.stk) - string_length - p - 1; @@ -779,6 +793,7 @@ xheader_string_end (char const *keyword) *cp++ = ' '; cp = stpcpy (cp, keyword); *cp++ = '='; + return true; } @@ -939,7 +954,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 +998,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 +1012,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 +1030,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 +1048,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 +1064,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 +1080,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 +1117,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 +1135,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 +1153,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 +1171,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 +1187,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 +1206,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 +1229,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 +1254,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 +1350,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 +1367,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 +1379,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,25 +1398,64 @@ 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); } - + +static void +sparse_major_coder (struct tar_stat_info const *st, char const *keyword, + struct xheader *xhdr, void const *data) +{ + code_num (st->sparse_major, keyword, xhdr); +} + +static void +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), 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); +} + +static void +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), keyword)) + st->sparse_minor = u; +} struct xhdr_tab const xhdr_tab[] = { { "atime", atime_coder, atime_decoder, false }, @@ -1380,11 +1472,19 @@ struct xhdr_tab const xhdr_tab[] = { { "uname", uname_coder, uname_decoder, false }, /* Sparse file handling */ - { "GNU.sparse.size", sparse_size_coder, sparse_size_decoder, true }, - { "GNU.sparse.numblocks", sparse_numblocks_coder, sparse_numblocks_decoder, - true }, { "GNU.sparse.name", path_coder, path_decoder, true }, + { "GNU.sparse.major", sparse_major_coder, sparse_major_decoder, + true }, + { "GNU.sparse.minor", sparse_minor_coder, sparse_minor_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 @@ -1393,7 +1493,7 @@ struct xhdr_tab const xhdr_tab[] = { true }, { "GNU.sparse.numbytes", sparse_numbytes_coder, sparse_numbytes_decoder, true }, - /* tar >=1.16 keyword, introduced to remove the above-mentioned conflict. */ + /* tar 1.15.90 keyword, introduced to remove the above-mentioned conflict. */ { "GNU.sparse.map", NULL /* Unused, see pax_dump_header() */, sparse_map_decoder, false },