Allow to store/extract '=' character in xattr keyword

* src/xheader.c (xattr_decode_keyword)
(xattr_encode_keyword): New functions.
(xheader_print_n,xattr_decoder): Use them.
* tests/xattr05.at: New test case.
* tests/Makefile.am: Add new test case.
* tests/testsuite.at: Likewise.
This commit is contained in:
Pavel Raiskup
2012-11-19 23:25:49 +02:00
committed by Sergey Poznyakoff
parent 4a3564fe85
commit a974e9c997
4 changed files with 160 additions and 6 deletions

View File

@@ -499,6 +499,44 @@ static void xheader_xattr__add (struct xattr_array **xattr_map,
(*xattr_map)[pos].xval_len = 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)
{
@@ -807,15 +845,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
{
@@ -827,7 +921,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');
@@ -1613,11 +1707,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;
xstr = xmemdup(arg, size + 1);
xheader_xattr_add(st, keyword + strlen("SCHILY.xattr."), xstr, size);
free(xstr);
/* 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);
xheader_xattr_add (st, xkey + strlen("SCHILY.xattr."), xstr, size);
}
static void

View File

@@ -178,6 +178,7 @@ TESTSUITE_AT = \
xattr02.at\
xattr03.at\
xattr04.at\
xattr05.at\
acls01.at\
acls02.at\
selnx01.at\

View File

@@ -338,6 +338,7 @@ m4_include([xattr01.at])
m4_include([xattr02.at])
m4_include([xattr03.at])
m4_include([xattr04.at])
m4_include([xattr05.at])
m4_include([acls01.at])
m4_include([acls02.at])

49
tests/xattr05.at Normal file
View File

@@ -0,0 +1,49 @@
# Process this file with autom4te to create testsuite. -*- Autotest -*-
#
# Test suite for GNU tar.
# Copyright (C) 2012 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 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.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
# Test description: Test for archiving/extracting of extended attributes
# having the '=' character in its keyword.
#
# Relevant mailing list thread:
#
# http://lists.gnu.org/archive/html/bug-tar/2012-10/msg00017.html
AT_SETUP([xattrs: keywords with '=' and '%'])
AT_KEYWORDS([xattrs xattr05])
AT_TAR_CHECK([
AT_XATTRS_PREREQ
mkdir dir
mkdir output
genfile --file dir/file
setfattr -n user.=NAME%3D= -v value dir/file
getfattr -d dir/file | grep -v '# ' > before
# archive whole directory including binary xattrs
tar --xattrs -cf archive.tar -C dir .
tar --xattrs -xf archive.tar -C output
getfattr -d output/file | grep -v '# ' > after
diff before after
],
[0],
[])
AT_CLEANUP