X-Git-Url: https://git.dogcows.com/gitweb?a=blobdiff_plain;f=src%2Fxheader.c;h=087cb1baca957928f07bd1fda2c6b7f1f9f7e5b4;hb=e86e864544a87003ac900d60135a3ca9424cfb95;hp=dadaf5430276c39ae731d1a78a24fb177d72f943;hpb=040b5ab5f969f9ee6c69a54bc284e2ff57b86556;p=chaz%2Ftar diff --git a/src/xheader.c b/src/xheader.c index dadaf54..087cb1b 100644 --- a/src/xheader.c +++ b/src/xheader.c @@ -1,6 +1,6 @@ /* POSIX extended headers for tar. - Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc. + Copyright (C) 2003, 2004, 2005, 2006 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 @@ -28,13 +28,6 @@ #include -#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)); @@ -57,7 +50,29 @@ static size_t global_header_count; However it should wait until buffer.c is finally rewritten */ -enum { BILLION = 1000000000, LOG10_BILLION = 9 }; + +/* 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 */ @@ -88,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; @@ -210,15 +225,17 @@ 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. %% A '%' character. */ -static char * -xheader_format_name (struct tar_stat_info *st, const char *fmt, bool allow_n) +char * +xheader_format_name (struct tar_stat_info *st, const char *fmt, size_t n) { char *buf; size_t len = strlen (fmt); char *q; const char *p; + char *dirp = NULL; char *dir = NULL; char *base = NULL; char pidbuf[UINTMAX_STRSIZE_BOUND]; @@ -237,9 +254,10 @@ xheader_format_name (struct tar_stat_info *st, const char *fmt, bool allow_n) case 'd': if (st) { - dir = safer_name_suffix (dir_name (st->orig_file_name), - false, absolute_names_option); - len += strlen (dir) - 1; + if (!dirp) + dirp = dir_name (st->orig_file_name); + dir = safer_name_suffix (dirp, false, absolute_names_option); + len += strlen (dir) - 2; } break; @@ -247,21 +265,18 @@ xheader_format_name (struct tar_stat_info *st, const char *fmt, bool allow_n) if (st) { base = base_name (st->orig_file_name); - len += strlen (base) - 1; + len += strlen (base) - 2; } break; case 'p': pptr = umaxtostr (getpid (), pidbuf); - len += pidbuf + sizeof pidbuf - 1 - pptr - 1; + len += pidbuf + sizeof pidbuf - 1 - pptr - 2; break; case 'n': - if (allow_n) - { - nptr = umaxtostr (global_header_count + 1, nbuf); - len += nbuf + sizeof nbuf - 1 - nptr - 1; - } + nptr = umaxtostr (n, nbuf); + len += nbuf + sizeof nbuf - 1 - nptr - 2; break; } p++; @@ -301,6 +316,7 @@ xheader_format_name (struct tar_stat_info *st, const char *fmt, bool allow_n) { q = stpcpy (q, nptr); p += 2; + break; } /* else fall through */ @@ -314,6 +330,8 @@ xheader_format_name (struct tar_stat_info *st, const char *fmt, bool allow_n) *q++ = *p++; } + free (dirp); + /* Do not allow it to end in a slash */ while (q > buf && ISSLASH (q[-1])) q--; @@ -326,7 +344,7 @@ xheader_xhdr_name (struct tar_stat_info *st) { if (!exthdr_name) assign_string (&exthdr_name, "%d/PaxHeaders.%p/%f"); - return xheader_format_name (st, exthdr_name, false); + return xheader_format_name (st, exthdr_name, 0); } #define GLOBAL_HEADER_TEMPLATE "/GlobalHead.%p.%n" @@ -346,7 +364,7 @@ xheader_ghdr_name (void) strcat(globexthdr_name, GLOBAL_HEADER_TEMPLATE); } - return xheader_format_name (NULL, globexthdr_name, true); + return xheader_format_name (NULL, globexthdr_name, global_header_count + 1); } void @@ -381,6 +399,9 @@ xheader_write (char type, char *name, struct xheader *xhdr) } while (size > 0); xheader_destroy (xhdr); + + if (type == XGLTYPE) + global_header_count++; } void @@ -399,7 +420,6 @@ xheader_write_global (void) xheader_write (XGLTYPE, name = xheader_ghdr_name (), &extended_header); free (name); - global_header_count++; } @@ -409,8 +429,8 @@ 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 *); + struct xheader *, void const *data); + void (*decoder) (struct tar_stat_info *, char const *, size_t); bool protect; }; @@ -459,7 +479,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; @@ -517,7 +537,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; @@ -531,12 +551,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; @@ -547,7 +567,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 @@ -566,7 +589,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); @@ -596,14 +620,15 @@ extended_header_init (void) } void -xheader_store (char const *keyword, struct tar_stat_info const *st, void *data) +xheader_store (char const *keyword, struct tar_stat_info const *st, + void const *data) { struct xhdr_tab const *t; 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)) @@ -644,9 +669,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]; @@ -660,12 +686,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 @@ -676,9 +708,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 @@ -696,6 +726,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 */ @@ -747,23 +832,8 @@ decode_string (char **string, char const *arg) static void code_time (struct timespec t, char const *keyword, struct xheader *xhdr) { - 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); + char buf[TIMESPEC_STRSIZE_BOUND]; + xheader_print (xhdr, keyword, code_timespec (t, buf)); } static bool @@ -886,40 +956,43 @@ static void dummy_coder (struct tar_stat_info const *st __attribute__ ((unused)), char const *keyword __attribute__ ((unused)), struct xheader *xhdr __attribute__ ((unused)), - void *data __attribute__ ((unused))) + void const *data __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))) { } static void atime_coder (struct tar_stat_info const *st, char const *keyword, - struct xheader *xhdr, void *data __attribute__ ((unused))) + struct xheader *xhdr, void const *data __attribute__ ((unused))) { - code_time (get_stat_atime (&st->stat), keyword, xhdr); + code_time (st->atime, keyword, xhdr); } 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")) - set_stat_atime (&st->stat, ts); + st->atime = ts; } static void gid_coder (struct tar_stat_info const *st, char const *keyword, - struct xheader *xhdr, void *data __attribute__ ((unused))) + struct xheader *xhdr, void const *data __attribute__ ((unused))) { code_num (st->stat.st_gid, keyword, xhdr); } 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")) @@ -928,69 +1001,74 @@ gid_decoder (struct tar_stat_info *st, char const *arg) static void gname_coder (struct tar_stat_info const *st, char const *keyword, - struct xheader *xhdr, void *data __attribute__ ((unused))) + struct xheader *xhdr, void const *data __attribute__ ((unused))) { code_string (st->gname, keyword, xhdr); } 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); } static void linkpath_coder (struct tar_stat_info const *st, char const *keyword, - struct xheader *xhdr, void *data __attribute__ ((unused))) + struct xheader *xhdr, void const *data __attribute__ ((unused))) { code_string (st->link_name, keyword, xhdr); } 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); } static void ctime_coder (struct tar_stat_info const *st, char const *keyword, - struct xheader *xhdr, void *data __attribute__ ((unused))) + struct xheader *xhdr, void const *data __attribute__ ((unused))) { - code_time (get_stat_ctime (&st->stat), keyword, xhdr); + code_time (st->ctime, keyword, xhdr); } 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")) - set_stat_ctime (&st->stat, ts); + st->ctime = ts; } static void mtime_coder (struct tar_stat_info const *st, char const *keyword, - struct xheader *xhdr, void *data __attribute__ ((unused))) + struct xheader *xhdr, void const *data __attribute__ ((unused))) { - code_time (get_stat_mtime (&st->stat), keyword, xhdr); + code_time (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 *arg, + size_t size __attribute__((unused))) { struct timespec ts; if (decode_time (&ts, arg, "mtime")) - set_stat_mtime (&st->stat, ts); + st->mtime = ts; } static void path_coder (struct tar_stat_info const *st, char const *keyword, - struct xheader *xhdr, void *data __attribute__ ((unused))) + struct xheader *xhdr, void const *data __attribute__ ((unused))) { code_string (st->file_name, keyword, xhdr); } 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); @@ -999,28 +1077,30 @@ path_decoder (struct tar_stat_info *st, char const *arg) static void size_coder (struct tar_stat_info const *st, char const *keyword, - struct xheader *xhdr, void *data __attribute__ ((unused))) + struct xheader *xhdr, void const *data __attribute__ ((unused))) { code_num (st->stat.st_size, keyword, xhdr); } 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")) - st->archive_file_size = st->stat.st_size = u; + st->stat.st_size = u; } static void uid_coder (struct tar_stat_info const *st, char const *keyword, - struct xheader *xhdr, void *data __attribute__ ((unused))) + struct xheader *xhdr, void const *data __attribute__ ((unused))) { code_num (st->stat.st_uid, keyword, xhdr); } 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")) @@ -1029,26 +1109,28 @@ uid_decoder (struct tar_stat_info *st, char const *arg) static void uname_coder (struct tar_stat_info const *st, char const *keyword, - struct xheader *xhdr, void *data __attribute__ ((unused))) + struct xheader *xhdr, void const *data __attribute__ ((unused))) { code_string (st->uname, keyword, xhdr); } 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); } static void sparse_size_coder (struct tar_stat_info const *st, char const *keyword, - struct xheader *xhdr, void *data) + struct xheader *xhdr, void const *data) { size_coder (st, keyword, xhdr, data); } 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")) @@ -1058,13 +1140,14 @@ sparse_size_decoder (struct tar_stat_info *st, char const *arg) static void sparse_numblocks_coder (struct tar_stat_info const *st, char const *keyword, struct xheader *xhdr, - void *data __attribute__ ((unused))) + void const *data __attribute__ ((unused))) { code_num (st->sparse_map_avail, keyword, xhdr); } 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")) @@ -1077,14 +1160,15 @@ sparse_numblocks_decoder (struct tar_stat_info *st, char const *arg) static void sparse_offset_coder (struct tar_stat_info const *st, char const *keyword, - struct xheader *xhdr, void *data) + struct xheader *xhdr, void const *data) { - size_t *pi = data; + size_t const *pi = data; code_num (st->sparse_map[*pi].offset, keyword, xhdr); } 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")) @@ -1099,14 +1183,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 const *data) { - size_t *pi = data; + size_t const *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")) @@ -1119,6 +1204,146 @@ 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"), + keyword, 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 const *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); +} + +static void +volume_label_coder (struct tar_stat_info const *st, char const *keyword, + struct xheader *xhdr, void const *data) +{ + code_string (data, keyword, xhdr); +} + +static void +volume_label_decoder (struct tar_stat_info *st, char const *arg, size_t size) +{ + decode_string (&volume_label, arg); +} + +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); +} + +static void +volume_size_decoder (struct tar_stat_info *st, char const *arg, size_t size) +{ + uintmax_t u; + if (decode_num (&u, arg, TYPE_MAXIMUM (uintmax_t), "GNU.volume.size")) + continued_file_size = u; +} + +/* FIXME: Merge with volume_size_coder */ +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); +} + +static void +volume_offset_decoder (struct tar_stat_info *st, char const *arg, size_t size) +{ + uintmax_t u; + if (decode_num (&u, arg, TYPE_MAXIMUM (uintmax_t), "GNU.volume.offset")) + continued_file_offset = u; +} + +static void +volume_filename_decoder (struct tar_stat_info *st, char const *arg, + size_t size) +{ + decode_string (&continued_file_name, arg); +} + + struct xhdr_tab const xhdr_tab[] = { { "atime", atime_coder, atime_decoder, false }, { "comment", dummy_coder, dummy_decoder, false }, @@ -1137,22 +1362,24 @@ 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 }, -#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 }, + { "GNU.dumpdir", dumpdir_coder, dumpdir_decoder, + true }, - /* Keeps the tape/volume header. May be present only in the global headers. + /* Keeps the tape/volume label. May be present only in the global headers. Equivalent to GNUTYPE_VOLHDR. */ - { "GNU.volume.header", volume_header_coder, volume_header_decoder, false }, + { "GNU.volume.label", volume_label_coder, volume_label_decoder, true }, /* These may be present in a first global header of the archive. They provide the same functionality as GNUTYPE_MULTIVOL header. @@ -1160,9 +1387,10 @@ 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, false }, - { "GNU.volume.offset", volume_offset_coder, volume_offset_decoder, false }, -#endif + { "GNU.volume.filename", volume_label_coder, volume_filename_decoder, + true }, + { "GNU.volume.size", volume_size_coder, volume_size_decoder, true }, + { "GNU.volume.offset", volume_offset_coder, volume_offset_decoder, true }, { NULL, NULL, NULL, false } };