/* POSIX extended headers for tar.
- Copyright (C) 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
+ Copyright (C) 2003, 2004, 2005, 2006, 2007 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
#include <hash.h>
#include <inttostr.h>
#include <quotearg.h>
-#include <stpcpy.h>
#include "common.h"
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 *
case 'f':
if (st)
{
- base = base_name (st->orig_file_name);
+ base = last_component (st->orig_file_name);
len += strlen (base) - 2;
}
break;
}
free (dirp);
-
+
/* Do not allow it to end in a slash */
while (q > buf && ISSLASH (q[-1]))
q--;
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;
};
{
char *start = *ptr;
char *p = start;
- unsigned long int len;
+ uintmax_t u;
+ size_t len;
char *len_lim;
char const *keyword;
char *nextp;
}
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)
{
{
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));
}
}
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));
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';
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' */
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;
*cp++ = ' ';
cp = stpcpy (cp, keyword);
*cp++ = '=';
+ return true;
}
\f
return true;
}
-
+
static void
code_num (uintmax_t value, char const *keyword, struct xheader *xhdr)
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)))
{
}
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;
}
}
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;
}
}
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);
}
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);
}
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;
}
}
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);
}
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;
}
}
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;
}
}
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);
}
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;
}
}
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]);
}
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;
}
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)
}
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);
}
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);
}
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;
}
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_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 },
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