X-Git-Url: https://git.dogcows.com/gitweb?a=blobdiff_plain;f=src%2Fxheader.c;h=c94c6d39f1e2437a3caa8ea577d436cd77275143;hb=46da9968df4bad8ce3899f98000aa5612375d29f;hp=061d44887d554dc2aff893f20075ad1e556b4d56;hpb=696338043e52f440853e1143c52b81b41cd59723;p=chaz%2Ftar
diff --git a/src/xheader.c b/src/xheader.c
index 061d448..c94c6d3 100644
--- a/src/xheader.c
+++ b/src/xheader.c
@@ -1,21 +1,22 @@
/* POSIX extended headers for tar.
- Copyright (C) 2003, 2004, 2005, 2006, 2007, 2009, 2010, 2012
- Free Software Foundation, Inc.
+ Copyright (C) 2003-2007, 2009-2010, 2012-2014 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
- Free Software Foundation; either version 3, or (at your option) any later
- version.
+ This file is part of GNU tar.
- This program is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
- Public License for more details.
+ GNU tar is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
- You should have received a copy of the GNU General Public License along
- with this program; if not, write to the Free Software Foundation, Inc.,
- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+ GNU tar is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see . */
#include
@@ -167,14 +168,13 @@ xheader_set_single_keyword (char *kw)
static void
assign_time_option (char **sval, time_t *tval, const char *input)
{
- uintmax_t u;
char *p;
- time_t t = u = strtoumax (input, &p, 10);
- if (t != u || *p || errno == ERANGE)
+ struct timespec t = decode_timespec (input, &p, false);
+ if (! valid_timespec (t) || *p)
ERROR ((0, 0, _("Time stamp is out of allowed range")));
else
{
- *tval = t;
+ *tval = t.tv_sec;
assign_string (sval, input);
}
}
@@ -262,7 +262,7 @@ xheader_format_name (struct tar_stat_info *st, const char *fmt, size_t n)
char *dir = NULL;
char *base = NULL;
char pidbuf[UINTMAX_STRSIZE_BOUND];
- char const *pptr;
+ char const *pptr = NULL;
char nbuf[UINTMAX_STRSIZE_BOUND];
char const *nptr = NULL;
@@ -335,13 +335,10 @@ xheader_format_name (struct tar_stat_info *st, const char *fmt, size_t n)
break;
case 'n':
- if (nptr)
- {
- q = stpcpy (q, nptr);
- p += 2;
- break;
- }
- /* else fall through */
+ q = stpcpy (q, nptr);
+ p += 2;
+ break;
+
default:
*q++ = *p++;
@@ -455,18 +452,27 @@ xheader_write_global (struct xheader *xhdr)
char *name;
xheader_finish (xhdr);
- xheader_write (XGLTYPE, name = xheader_ghdr_name (), time (NULL), xhdr);
+ name = xheader_ghdr_name ();
+ xheader_write (XGLTYPE, name, start_time.tv_sec, xhdr);
free (name);
}
}
-void xheader_xattr_init (struct tar_stat_info *st)
+void
+xheader_xattr_init (struct tar_stat_info *st)
{
st->xattr_map = NULL;
st->xattr_map_size = 0;
+
+ st->acls_a_ptr = NULL;
+ st->acls_a_len = 0;
+ st->acls_d_ptr = NULL;
+ st->acls_d_len = 0;
+ st->cntx_name = NULL;
}
-void xheader_xattr_free (struct xattr_array *xattr_map, size_t xattr_map_size)
+void
+xheader_xattr_free (struct xattr_array *xattr_map, size_t xattr_map_size)
{
size_t scan = 0;
@@ -480,9 +486,10 @@ void xheader_xattr_free (struct xattr_array *xattr_map, size_t xattr_map_size)
free (xattr_map);
}
-static void xheader_xattr__add (struct xattr_array **xattr_map,
- size_t *xattr_map_size,
- const char *key, const char *val, size_t len)
+static void
+xheader_xattr__add (struct xattr_array **xattr_map,
+ size_t *xattr_map_size,
+ const char *key, const char *val, size_t len)
{
size_t pos = (*xattr_map_size)++;
@@ -493,8 +500,47 @@ static void xheader_xattr__add (struct xattr_array **xattr_map,
(*xattr_map)[pos].xval_len = len;
}
-void xheader_xattr_add(struct tar_stat_info *st,
- const char *key, const char *val, size_t len)
+/* This is reversal function for xattr_encode_keyword. See comment for
+ xattr_encode_keyword() for more info. */
+static void
+xattr_decode_keyword (char *keyword)
+{
+ char *kpr, *kpl; /* keyword pointer left/right */
+ kpr = kpl = keyword;
+
+ for (;;)
+ {
+ if (*kpr == '%')
+ {
+ if (kpr[1] == '3' && kpr[2] == 'D')
+ {
+ *kpl = '=';
+ kpr += 3;
+ kpl ++;
+ continue;
+ }
+ else if (kpr[1] == '2' && kpr[2] == '5')
+ {
+ *kpl = '%';
+ kpr += 3;
+ kpl ++;
+ continue;
+ }
+ }
+
+ *kpl = *kpr;
+
+ if (*kpr == 0)
+ break;
+
+ kpr++;
+ kpl++;
+ }
+}
+
+void
+xheader_xattr_add (struct tar_stat_info *st,
+ const char *key, const char *val, size_t len)
{
size_t klen = strlen (key);
char *xkey = xmalloc (strlen("SCHILY.xattr.") + klen + 1);
@@ -508,8 +554,9 @@ void xheader_xattr_add(struct tar_stat_info *st,
free (xkey);
}
-void xheader_xattr_copy(const struct tar_stat_info *st,
- struct xattr_array **xattr_map, size_t *xattr_map_size)
+void
+xheader_xattr_copy (const struct tar_stat_info *st,
+ struct xattr_array **xattr_map, size_t *xattr_map_size)
{
size_t scan = 0;
@@ -606,7 +653,6 @@ decode_record (struct xheader *xhdr,
{
char *start = *ptr;
char *p = start;
- uintmax_t u;
size_t len;
char *len_lim;
char const *keyword;
@@ -623,13 +669,7 @@ decode_record (struct xheader *xhdr,
return false;
}
- errno = 0;
- 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;
- }
+ len = strtoumax (p, &len_lim, 10);
if (len_max < len)
{
@@ -771,10 +811,16 @@ xheader_store (char const *keyword, struct tar_stat_info *st,
}
void
-xheader_read (struct xheader *xhdr, union block *p, size_t size)
+xheader_read (struct xheader *xhdr, union block *p, off_t size)
{
size_t j = 0;
+ if (size < 0)
+ size = 0; /* Already diagnosed. */
+
+ if (SIZE_MAX - BLOCKSIZE <= size)
+ xalloc_die ();
+
size += BLOCKSIZE;
xhdr->size = size;
xhdr->buffer = xmalloc (size + 1);
@@ -801,15 +847,71 @@ xheader_read (struct xheader *xhdr, union block *p, size_t size)
while (size > 0);
}
+/* xattr_encode_keyword() substitutes '=' ~~> '%3D' and '%' ~~> '%25'
+ in extended attribute keywords. This is needed because the '=' character
+ has special purpose in extended attribute header - it splits keyword and
+ value part of header. If there was the '=' occurrence allowed inside
+ keyword, there would be no unambiguous way how to decode this extended
+ attribute.
+
+ (http://lists.gnu.org/archive/html/bug-tar/2012-10/msg00017.html)
+ */
+static char *
+xattr_encode_keyword(const char *keyword)
+{
+ static char *encode_buffer = NULL;
+ static size_t encode_buffer_size = 0;
+ size_t bp; /* keyword/buffer pointers */
+
+ if (!encode_buffer)
+ {
+ encode_buffer_size = 256;
+ encode_buffer = xmalloc (encode_buffer_size);
+ }
+ else
+ *encode_buffer = 0;
+
+ for (bp = 0; *keyword != 0; ++bp, ++keyword)
+ {
+ char c = *keyword;
+
+ if (bp + 2 /* enough for URL encoding also.. */ >= encode_buffer_size)
+ {
+ encode_buffer = x2realloc (encode_buffer, &encode_buffer_size);
+ }
+
+ if (c == '%')
+ {
+ strcpy (encode_buffer + bp, "%25");
+ bp += 2;
+ }
+ else if (c == '=')
+ {
+ strcpy (encode_buffer + bp, "%3D");
+ bp += 2;
+ }
+ else
+ encode_buffer[bp] = c;
+ }
+
+ encode_buffer[bp] = 0;
+
+ return encode_buffer;
+}
+
static void
xheader_print_n (struct xheader *xhdr, char const *keyword,
char const *value, size_t vsize)
{
- size_t len = strlen (keyword) + vsize + 3; /* ' ' + '=' + '\n' */
size_t p;
size_t n = 0;
char nbuf[UINTMAX_STRSIZE_BOUND];
char const *np;
+ size_t len, klen;
+
+ keyword = xattr_encode_keyword (keyword);
+ klen = strlen (keyword);
+ len = klen + vsize + 3; /* ' ' + '=' + '\n' */
do
{
@@ -821,7 +923,7 @@ xheader_print_n (struct xheader *xhdr, char const *keyword,
x_obstack_grow (xhdr, np, n);
x_obstack_1grow (xhdr, ' ');
- x_obstack_grow (xhdr, keyword, strlen (keyword));
+ x_obstack_grow (xhdr, keyword, klen);
x_obstack_1grow (xhdr, '=');
x_obstack_grow (xhdr, value, vsize);
x_obstack_1grow (xhdr, '\n');
@@ -929,14 +1031,12 @@ xheader_string_end (struct xheader *xhdr, char const *keyword)
static void
out_of_range_header (char const *keyword, char const *value,
- uintmax_t minus_minval, uintmax_t maxval)
+ intmax_t minval, uintmax_t maxval)
{
- char minval_buf[UINTMAX_STRSIZE_BOUND + 1];
+ char minval_buf[INT_BUFSIZE_BOUND (intmax_t)];
char maxval_buf[UINTMAX_STRSIZE_BOUND];
- char *minval_string = umaxtostr (minus_minval, minval_buf + 1);
+ char *minval_string = imaxtostr (minval, minval_buf);
char *maxval_string = umaxtostr (maxval, maxval_buf);
- if (minus_minval)
- *--minval_string = '-';
/* TRANSLATORS: The first %s is the pax extended header keyword
(atime, gid, etc.). */
@@ -979,136 +1079,59 @@ code_time (struct timespec t, char const *keyword, struct xheader *xhdr)
xheader_print (xhdr, keyword, code_timespec (t, buf));
}
-enum decode_time_status
- {
- decode_time_success,
- decode_time_range,
- decode_time_bad_header
- };
-
-static enum decode_time_status
-_decode_time (struct timespec *ts, char const *arg, char const *keyword)
+static bool
+decode_time (struct timespec *ts, char const *arg, char const *keyword)
{
- time_t s;
- unsigned long int ns = 0;
- char *p;
char *arg_lim;
- bool negative = *arg == '-';
-
- errno = 0;
+ struct timespec t = decode_timespec (arg, &arg_lim, true);
- if (ISDIGIT (arg[negative]))
+ if (! valid_timespec (t))
{
- if (negative)
- {
- intmax_t i = strtoimax (arg, &arg_lim, 10);
- if (TYPE_SIGNED (time_t) ? i < TYPE_MINIMUM (time_t) : i < 0)
- return decode_time_range;
- s = i;
- }
+ if (arg < arg_lim && !*arg_lim)
+ out_of_range_header (keyword, arg, TYPE_MINIMUM (time_t),
+ TYPE_MAXIMUM (time_t));
else
- {
- uintmax_t i = strtoumax (arg, &arg_lim, 10);
- if (TYPE_MAXIMUM (time_t) < i)
- return decode_time_range;
- s = i;
- }
-
- p = arg_lim;
-
- if (errno == ERANGE)
- return decode_time_range;
-
- if (*p == '.')
- {
- int digits = 0;
- bool trailing_nonzero = false;
-
- while (ISDIGIT (*++p))
- if (digits < LOG10_BILLION)
- {
- ns = 10 * ns + (*p - '0');
- digits++;
- }
- else
- trailing_nonzero |= *p != '0';
-
- while (digits++ < LOG10_BILLION)
- ns *= 10;
-
- if (negative)
- {
- /* Convert "-1.10000000000001" to s == -2, ns == 89999999.
- I.e., truncate time stamps towards minus infinity while
- converting them to internal form. */
- ns += trailing_nonzero;
- if (ns != 0)
- {
- if (s == TYPE_MINIMUM (time_t))
- return decode_time_range;
- s--;
- ns = BILLION - ns;
- }
- }
- }
-
- if (! *p)
- {
- ts->tv_sec = s;
- ts->tv_nsec = ns;
- return decode_time_success;
- }
+ ERROR ((0, 0, _("Malformed extended header: invalid %s=%s"),
+ keyword, arg));
+ return false;
}
- return decode_time_bad_header;
+ *ts = t;
+ return true;
}
-static bool
-decode_time (struct timespec *ts, char const *arg, char const *keyword)
+static void
+code_signed_num (uintmax_t value, char const *keyword,
+ intmax_t minval, uintmax_t maxval, struct xheader *xhdr)
{
- switch (_decode_time (ts, arg, keyword))
- {
- case decode_time_success:
- return true;
- case decode_time_bad_header:
- ERROR ((0, 0, _("Malformed extended header: invalid %s=%s"),
- keyword, arg));
- return false;
- case decode_time_range:
- out_of_range_header (keyword, arg, - (uintmax_t) TYPE_MINIMUM (time_t),
- TYPE_MAXIMUM (time_t));
- return false;
- }
- return true;
+ char sbuf[SYSINT_BUFSIZE];
+ xheader_print (xhdr, keyword, sysinttostr (value, minval, maxval, sbuf));
}
-
-
static void
code_num (uintmax_t value, char const *keyword, struct xheader *xhdr)
{
- char sbuf[UINTMAX_STRSIZE_BOUND];
- xheader_print (xhdr, keyword, umaxtostr (value, sbuf));
+ code_signed_num (value, keyword, 0, UINTMAX_MAX, xhdr);
}
static bool
-decode_num (uintmax_t *num, char const *arg, uintmax_t maxval,
- char const *keyword)
+decode_signed_num (intmax_t *num, char const *arg,
+ intmax_t minval, uintmax_t maxval,
+ char const *keyword)
{
- uintmax_t u;
char *arg_lim;
+ intmax_t u = strtosysint (arg, &arg_lim, minval, maxval);
- if (! (ISDIGIT (*arg)
- && (errno = 0, u = strtoumax (arg, &arg_lim, 10), !*arg_lim)))
+ if (errno == EINVAL || *arg_lim)
{
ERROR ((0, 0, _("Malformed extended header: invalid %s=%s"),
keyword, arg));
return false;
}
- if (! (u <= maxval && errno != ERANGE))
+ if (errno == ERANGE)
{
- out_of_range_header (keyword, arg, 0, maxval);
+ out_of_range_header (keyword, arg, minval, maxval);
return false;
}
@@ -1116,6 +1139,17 @@ decode_num (uintmax_t *num, char const *arg, uintmax_t maxval,
return true;
}
+static bool
+decode_num (uintmax_t *num, char const *arg, uintmax_t maxval,
+ char const *keyword)
+{
+ intmax_t i;
+ if (! decode_signed_num (&i, arg, 0, maxval, keyword))
+ return false;
+ *num = i;
+ return true;
+}
+
static void
dummy_coder (struct tar_stat_info const *st __attribute__ ((unused)),
char const *keyword __attribute__ ((unused)),
@@ -1154,7 +1188,8 @@ static void
gid_coder (struct tar_stat_info const *st, char const *keyword,
struct xheader *xhdr, void const *data __attribute__ ((unused)))
{
- code_num (st->stat.st_gid, keyword, xhdr);
+ code_signed_num (st->stat.st_gid, keyword,
+ TYPE_MINIMUM (gid_t), TYPE_MAXIMUM (gid_t), xhdr);
}
static void
@@ -1163,8 +1198,9 @@ 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), keyword))
+ intmax_t u;
+ if (decode_signed_num (&u, arg, TYPE_MINIMUM (gid_t),
+ TYPE_MAXIMUM (gid_t), keyword))
st->stat.st_gid = u;
}
@@ -1277,7 +1313,8 @@ static void
uid_coder (struct tar_stat_info const *st, char const *keyword,
struct xheader *xhdr, void const *data __attribute__ ((unused)))
{
- code_num (st->stat.st_uid, keyword, xhdr);
+ code_signed_num (st->stat.st_uid, keyword,
+ TYPE_MINIMUM (uid_t), TYPE_MAXIMUM (uid_t), xhdr);
}
static void
@@ -1286,8 +1323,9 @@ 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), keyword))
+ intmax_t u;
+ if (decode_signed_num (&u, arg, TYPE_MINIMUM (uid_t),
+ TYPE_MAXIMUM (uid_t), keyword))
st->stat.st_uid = u;
}
@@ -1409,7 +1447,7 @@ sparse_map_decoder (struct tar_stat_info *st,
st->sparse_map_avail = 0;
while (1)
{
- uintmax_t u;
+ intmax_t u;
char *delim;
struct sp_array e;
@@ -1421,11 +1459,16 @@ sparse_map_decoder (struct tar_stat_info *st,
}
errno = 0;
- u = strtoumax (arg, &delim, 10);
+ u = strtoimax (arg, &delim, 10);
+ if (TYPE_MAXIMUM (off_t) < u)
+ {
+ u = TYPE_MAXIMUM (off_t);
+ errno = ERANGE;
+ }
if (offset)
{
e.offset = u;
- if (!(u == e.offset && errno != ERANGE))
+ if (errno == ERANGE)
{
out_of_range_header (keyword, arg, 0, TYPE_MAXIMUM (off_t));
return;
@@ -1434,7 +1477,7 @@ sparse_map_decoder (struct tar_stat_info *st,
else
{
e.numbytes = u;
- if (!(u == e.numbytes && errno != ERANGE))
+ if (errno == ERANGE)
{
out_of_range_header (keyword, arg, 0, TYPE_MAXIMUM (off_t));
return;
@@ -1548,6 +1591,51 @@ volume_filename_decoder (struct tar_stat_info *st,
{
decode_string (&continued_file_name, arg);
}
+
+static void
+xattr_selinux_coder (struct tar_stat_info const *st, char const *keyword,
+ struct xheader *xhdr, void const *data)
+{
+ code_string (st->cntx_name, keyword, xhdr);
+}
+
+static void
+xattr_selinux_decoder (struct tar_stat_info *st,
+ char const *keyword, char const *arg, size_t size)
+{
+ decode_string (&st->cntx_name, arg);
+}
+
+static void
+xattr_acls_a_coder (struct tar_stat_info const *st , char const *keyword,
+ struct xheader *xhdr, void const *data)
+{
+ xheader_print_n (xhdr, keyword, st->acls_a_ptr, st->acls_a_len);
+}
+
+static void
+xattr_acls_a_decoder (struct tar_stat_info *st,
+ char const *keyword, char const *arg, size_t size)
+{
+ st->acls_a_ptr = xmemdup (arg, size + 1);
+ st->acls_a_len = size;
+}
+
+static void
+xattr_acls_d_coder (struct tar_stat_info const *st , char const *keyword,
+ struct xheader *xhdr, void const *data)
+{
+ xheader_print_n (xhdr, keyword, st->acls_d_ptr, st->acls_d_len);
+}
+
+static void
+xattr_acls_d_decoder (struct tar_stat_info *st,
+ char const *keyword, char const *arg, size_t size)
+{
+ st->acls_d_ptr = xmemdup (arg, size + 1);
+ st->acls_d_len = size;
+}
+
static void
xattr_coder (struct tar_stat_info const *st, char const *keyword,
struct xheader *xhdr, void const *data)
@@ -1562,11 +1650,20 @@ static void
xattr_decoder (struct tar_stat_info *st,
char const *keyword, char const *arg, size_t size)
{
- char *xstr = NULL;
+ char *xstr, *xkey;
+
+ /* copy keyword */
+ size_t klen_raw = strlen (keyword);
+ xkey = alloca (klen_raw + 1);
+ memcpy (xkey, keyword, klen_raw + 1) /* including null-terminating */;
+
+ /* copy value */
+ xstr = alloca (size + 1);
+ memcpy (xstr, arg, size + 1); /* separator included, for GNU tar '\n' */;
+
+ xattr_decode_keyword (xkey);
- xstr = xmemdup(arg, size + 1);
- xheader_xattr_add(st, keyword + strlen("SCHILY.xattr."), xstr, size);
- free(xstr);
+ xheader_xattr_add (st, xkey + strlen("SCHILY.xattr."), xstr, size);
}
static void
@@ -1667,6 +1764,18 @@ struct xhdr_tab const xhdr_tab[] = {
{ "GNU.volume.offset", volume_offset_coder, volume_offset_decoder,
XHDR_PROTECTED | XHDR_GLOBAL, false },
+ /* We get the SELinux value from filecon, so add a namespace for SELinux
+ instead of storing it in SCHILY.xattr.* (which would be RAW). */
+ { "RHT.security.selinux",
+ xattr_selinux_coder, xattr_selinux_decoder, 0, false },
+
+ /* ACLs, use the star format... */
+ { "SCHILY.acl.access",
+ xattr_acls_a_coder, xattr_acls_a_decoder, 0, false },
+
+ { "SCHILY.acl.default",
+ xattr_acls_d_coder, xattr_acls_d_decoder, 0, false },
+
/* We are storing all extended attributes using this rule even if some of them
were stored by some previous rule (duplicates) -- we just have to make sure
they are restored *only once* during extraction later on. */