From: Sergey Poznyakoff Date: Mon, 7 Nov 2005 02:52:58 +0000 (+0000) Subject: (xheader_keyword_deleted_p): Remove static X-Git-Url: https://git.brokenzipper.com/gitweb?a=commitdiff_plain;ds=sidebyside;h=374ae10d39e9e52789a00202c831a1c7c45e1610;p=chaz%2Ftar (xheader_keyword_deleted_p): Remove static qualifier. (struct xhdr_tab.decoder): Change prototype. POSIX allows string values to contain embedded nulls, so take an extra argument specifying the length of the string. (decx,decg,dummy_decoder,atime_decoder,gid_decoder) (gname_decoder,linkpath_decoder,ctime_decoder,mtime_decoder) (path_decoder,size_decoder,uid_decoder,uname_decoder) (sparse_size_decoder,sparse_numblocks_decoder) (sparse_offset_decoder,sparse_numbytes_decoder): Likewise. (decode_record): Pass value length to the handler (run_override_list): Pass value length to the decoder (xheader_print_n): New function (xheader_print): Rewritten using xheader_print_n (xheader_finish): Do not rely om strlen to compute the length of the collected string: it can contain embedded nulls (xheader_string_begin,xheader_string_add,xheader_string_end): New functions. (sparse_map_decoder,dumpdir_coder,dumpdir_decoder): New functions. Handle GNU.sparse.map and GNU.dumpdir variables. (xhdr_tab): Add new variables. --- diff --git a/src/xheader.c b/src/xheader.c index b8d4bfb..029bebf 100644 --- a/src/xheader.c +++ b/src/xheader.c @@ -50,6 +50,30 @@ static size_t global_header_count; However it should wait until buffer.c is finally rewritten */ + +/* Interface functions to obstacks */ + +static void +x_obstack_grow (struct xheader *xhdr, const char *ptr, size_t length) +{ + obstack_grow (xhdr->stk, ptr, length); + xhdr->size += length; +} + +static void +x_obstack_1grow (struct xheader *xhdr, char c) +{ + obstack_1grow (xhdr->stk, c); + xhdr->size++; +} + +static void +x_obstack_blank (struct xheader *xhdr, size_t length) +{ + obstack_blank (xhdr->stk, length); + xhdr->size += length; +} + /* Keyword options */ @@ -79,7 +103,7 @@ static char *exthdr_name; /* Template for the name field of a 'g' type header */ static char *globexthdr_name; -static bool +bool xheader_keyword_deleted_p (const char *kw) { struct keyword_list *kp; @@ -401,7 +425,7 @@ struct xhdr_tab char const *keyword; void (*coder) (struct tar_stat_info const *, char const *, struct xheader *, void *data); - void (*decoder) (struct tar_stat_info *, char const *); + void (*decoder) (struct tar_stat_info *, char const *, size_t); bool protect; }; @@ -450,7 +474,7 @@ xheader_protected_keyword_p (const char *keyword) Return true on success, false otherwise. */ static bool decode_record (char **ptr, - void (*handler) (void *, char const *, char const *), + void (*handler) (void *, char const *, char const *, size_t), void *data) { char *start = *ptr; @@ -508,7 +532,7 @@ decode_record (char **ptr, } *p = nextp[-1] = '\0'; - handler (data, keyword, p + 1); + handler (data, keyword, p + 1, nextp - p - 2); /* '=' + trailing '\n' */ *p = '='; nextp[-1] = '\n'; *ptr = nextp; @@ -522,12 +546,12 @@ 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); + t->decoder (st, kp->value, strlen (kp->value)); } } static void -decx (void *data, char const *keyword, char const *value) +decx (void *data, char const *keyword, char const *value, size_t size) { struct xhdr_tab const *t; struct tar_stat_info *st = data; @@ -538,7 +562,10 @@ decx (void *data, char const *keyword, char const *value) t = locate_handler (keyword); if (t) - t->decoder (st, value); + t->decoder (st, value, size); + else + ERROR((0, 0, _("Ignoring unknown extended header keyword `%s'"), + keyword)); } void @@ -557,7 +584,8 @@ xheader_decode (struct tar_stat_info *st) } static void -decg (void *data, char const *keyword, char const *value) +decg (void *data, char const *keyword, char const *value, + size_t size __attribute__((unused))) { struct keyword_list **kwl = data; xheader_list_append (kwl, keyword, value); @@ -594,7 +622,7 @@ xheader_store (char const *keyword, struct tar_stat_info const *st, void *data) if (extended_header.buffer) return; t = locate_handler (keyword); - if (!t) + if (!t || !t->coder) return; if (xheader_keyword_deleted_p (keyword) || xheader_keyword_override_p (keyword)) @@ -635,9 +663,10 @@ xheader_read (union block *p, size_t size) } static void -xheader_print (struct xheader *xhdr, char const *keyword, char const *value) +xheader_print_n (struct xheader *xhdr, char const *keyword, + char const *value, size_t vsize) { - size_t len = strlen (keyword) + strlen (value) + 3; /* ' ' + '=' + '\n' */ + size_t len = strlen (keyword) + vsize + 3; /* ' ' + '=' + '\n' */ size_t p; size_t n = 0; char nbuf[UINTMAX_STRSIZE_BOUND]; @@ -651,12 +680,18 @@ xheader_print (struct xheader *xhdr, char const *keyword, char const *value) } while (n != p); - obstack_grow (xhdr->stk, np, n); - obstack_1grow (xhdr->stk, ' '); - obstack_grow (xhdr->stk, keyword, strlen (keyword)); - obstack_1grow (xhdr->stk, '='); - obstack_grow (xhdr->stk, value, strlen (value)); - obstack_1grow (xhdr->stk, '\n'); + x_obstack_grow (xhdr, np, n); + x_obstack_1grow (xhdr, ' '); + x_obstack_grow (xhdr, keyword, strlen (keyword)); + x_obstack_1grow (xhdr, '='); + x_obstack_grow (xhdr, value, vsize); + x_obstack_1grow (xhdr, '\n'); +} + +static void +xheader_print (struct xheader *xhdr, char const *keyword, char const *value) +{ + xheader_print_n (xhdr, keyword, value, strlen (value)); } void @@ -667,9 +702,7 @@ xheader_finish (struct xheader *xhdr) for (kp = keyword_override_list; kp; kp = kp->next) code_string (kp->value, kp->pattern, xhdr); - obstack_1grow (xhdr->stk, 0); xhdr->buffer = obstack_finish (xhdr->stk); - xhdr->size = strlen (xhdr->buffer); } void @@ -687,6 +720,61 @@ xheader_destroy (struct xheader *xhdr) xhdr->size = 0; } + +/* Buildable strings */ +static uintmax_t string_length; + +void +xheader_string_begin () +{ + string_length = 0; +} + +void +xheader_string_add (char const *s) +{ + if (extended_header.buffer) + return; + extended_header_init (); + string_length += strlen (s); + x_obstack_grow (&extended_header, s, strlen (s)); +} + +void +xheader_string_end (char const *keyword) +{ + size_t len; + size_t p; + size_t n = 0; + char nbuf[UINTMAX_STRSIZE_BOUND]; + char const *np; + char *cp; + + if (extended_header.buffer) + return; + extended_header_init (); + + len = strlen (keyword) + string_length + 3; /* ' ' + '=' + '\n' */ + + do + { + p = n; + np = umaxtostr (len + p, nbuf); + n = nbuf + sizeof nbuf - 1 - np; + } + 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); + cp = stpcpy (cp, np); + *cp++ = ' '; + cp = stpcpy (cp, keyword); + *cp++ = '='; +} + /* Implementations */ @@ -868,7 +956,8 @@ dummy_coder (struct tar_stat_info const *st __attribute__ ((unused)), static void dummy_decoder (struct tar_stat_info *st __attribute__ ((unused)), - char const *arg __attribute__ ((unused))) + char const *arg __attribute__ ((unused)), + size_t size __attribute__((unused))) { } @@ -880,7 +969,8 @@ 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 *arg, + size_t size __attribute__((unused))) { struct timespec ts; if (decode_time (&ts, arg, "atime")) @@ -895,7 +985,8 @@ 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 *arg, + size_t size __attribute__((unused))) { uintmax_t u; if (decode_num (&u, arg, TYPE_MAXIMUM (gid_t), "gid")) @@ -910,7 +1001,8 @@ 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 *arg, + size_t size __attribute__((unused))) { decode_string (&st->gname, arg); } @@ -923,7 +1015,8 @@ 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 *arg, + size_t size __attribute__((unused))) { decode_string (&st->link_name, arg); } @@ -936,7 +1029,8 @@ 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 *arg, + size_t size __attribute__((unused))) { struct timespec ts; if (decode_time (&ts, arg, "ctime")) @@ -951,7 +1045,8 @@ mtime_coder (struct tar_stat_info const *st, char const *keyword, } static void -mtime_decoder (struct tar_stat_info *st, char const *arg) +mtime_decoder (struct tar_stat_info *st, char const *arg, + size_t size __attribute__((unused))) { struct timespec ts; if (decode_time (&ts, arg, "mtime")) @@ -966,7 +1061,8 @@ 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 *arg, + size_t size __attribute__((unused))) { decode_string (&st->orig_file_name, arg); decode_string (&st->file_name, arg); @@ -981,7 +1077,8 @@ 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 *arg, + size_t size __attribute__((unused))) { uintmax_t u; if (decode_num (&u, arg, TYPE_MAXIMUM (off_t), "size")) @@ -996,7 +1093,8 @@ 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 *arg, + size_t size __attribute__((unused))) { uintmax_t u; if (decode_num (&u, arg, TYPE_MAXIMUM (uid_t), "uid")) @@ -1011,7 +1109,8 @@ 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 *arg, + size_t size __attribute__((unused))) { decode_string (&st->uname, arg); } @@ -1024,7 +1123,8 @@ 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 *arg, + size_t size __attribute__((unused))) { uintmax_t u; if (decode_num (&u, arg, TYPE_MAXIMUM (off_t), "GNU.sparse.size")) @@ -1040,7 +1140,8 @@ 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 *arg, + size_t size __attribute__((unused))) { uintmax_t u; if (decode_num (&u, arg, SIZE_MAX, "GNU.sparse.numblocks")) @@ -1060,7 +1161,8 @@ 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 *arg, + size_t size __attribute__((unused))) { uintmax_t u; if (decode_num (&u, arg, TYPE_MAXIMUM (off_t), "GNU.sparse.offset")) @@ -1075,14 +1177,15 @@ sparse_offset_decoder (struct tar_stat_info *st, char const *arg) static void sparse_numbytes_coder (struct tar_stat_info const *st, char const *keyword, - struct xheader *xhdr, void *data) + struct xheader *xhdr, void *data) { size_t *pi = data; code_num (st->sparse_map[*pi].numbytes, keyword, xhdr); } static void -sparse_numbytes_decoder (struct tar_stat_info *st, char const *arg) +sparse_numbytes_decoder (struct tar_stat_info *st, char const *arg, + size_t size __attribute__((unused))) { uintmax_t u; if (decode_num (&u, arg, SIZE_MAX, "GNU.sparse.numbytes")) @@ -1095,6 +1198,92 @@ sparse_numbytes_decoder (struct tar_stat_info *st, char const *arg) } } +static void +sparse_map_decoder (struct tar_stat_info *st, char const *arg, + size_t size __attribute__((unused))) +{ + int offset = 1; + static char *keyword = "GNU.sparse.map"; + + st->sparse_map_avail = 0; + while (1) + { + uintmax_t u; + char *delim; + struct sp_array e; + + if (!ISDIGIT (*arg)) + { + ERROR ((0, 0, _("Malformed extended header: invalid %s=%s"), + keyword, arg)); + return; + } + + errno = 0; + u = strtoumax (arg, &delim, 10); + if (offset) + { + e.offset = u; + if (!(u == e.offset && errno != ERANGE)) + { + out_of_range_header (keyword, arg, 0, TYPE_MAXIMUM (off_t)); + return; + } + } + else + { + e.numbytes = u; + if (!(u == e.numbytes && errno != ERANGE)) + { + out_of_range_header (keyword, arg, 0, TYPE_MAXIMUM (size_t)); + return; + } + if (st->sparse_map_avail < st->sparse_map_size) + st->sparse_map[st->sparse_map_avail++] = e; + else + { + ERROR ((0, 0, _("Malformed extended header: excess %s=%s"), + "GNU.sparse.numbytes", arg)); + return; + } + } + + offset = !offset; + + if (*delim == 0) + break; + else if (*delim != ',') + { + ERROR ((0, 0, + _("Malformed extended header: invalid %s: unexpected delimiter %c"), + keyword, *delim)); + return; + } + + arg = delim + 1; + } + + if (!offset) + ERROR ((0, 0, + _("Malformed extended header: invalid %s: odd number of values"), + keyword)); +} + +static void +dumpdir_coder (struct tar_stat_info const *st, char const *keyword, + struct xheader *xhdr, void *data) +{ + xheader_print_n (xhdr, keyword, data, dumpdir_size (data)); +} + +static void +dumpdir_decoder (struct tar_stat_info *st, char const *arg, + size_t size) +{ + st->dumpdir = xmalloc (size); + memcpy (st->dumpdir, arg, size); +} + struct xhdr_tab const xhdr_tab[] = { { "atime", atime_coder, atime_decoder, false }, { "comment", dummy_coder, dummy_decoder, false }, @@ -1113,19 +1302,23 @@ struct xhdr_tab const xhdr_tab[] = { { "GNU.sparse.size", sparse_size_coder, sparse_size_decoder, true }, { "GNU.sparse.numblocks", sparse_numblocks_coder, sparse_numblocks_decoder, true }, + /* tar 1.14 - 1.15.1 keywords. Multiplse 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 + given in the header shall take precedence." */ { "GNU.sparse.offset", sparse_offset_coder, sparse_offset_decoder, true }, { "GNU.sparse.numbytes", sparse_numbytes_coder, sparse_numbytes_decoder, true }, + /* tar >=1.16 keyword, introduced to remove the above-mentioned conflict. */ + { "GNU.sparse.map", NULL /* Unused, see pax_dump_header() */, + sparse_map_decoder, false }, + { "GNU.dumpdir", dumpdir_coder, dumpdir_decoder, + true }, + #if 0 /* GNU private keywords (not yet implemented) */ - /* 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.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, false },