(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.
This commit is contained in:
Sergey Poznyakoff
2005-11-07 02:52:58 +00:00
parent 4d22cbd47c
commit 374ae10d39

View File

@@ -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 },