> 2. Apply the 0002-*.patch - this patch is adding support for extended > attributes into tar. This is slightly modified version of Red Hat > patch that is deployed in Fedora distribution of tar for many years. > AFAIK, very similar patch is also compiled in Gentoo's tar. > > It is possible to disable this feature during ./configure phase using > the --without-xattrs option. It will disable the possibility for > archiving/restoring of extended attributes -- but it still allows tar > to read (list) the archive contents (including tar --xattrs -tvvf) > and do not print the "unknown extended header keyword" warning on > error output when extended attributes are present in an archive. > > Inside this patch are also basic tests for this feature. Note that > this will need probably some improvements from the portability > perspective -- now these tests are simply skipped when utilities > needed for proper testing are missing on system. > > When this feature is compiled and tar is unable to write extended > attributes onto file system, the ENOTSUP warning may be silenced by > using '--warning=no-xattr-write'. > > As is documented (patch #5), default behaviour of tar will be that > it will store all extended attributes by default when '--xattrs' > option is present but it restores only 'user.*' domain by default. > Anyway, this may be controlled by --xattrs-include/--xattrs-exclude > patterns. These options have non-state validity (when these are > used they are valid for whole list of files that is going to be > stored/restored/listed). > > The --no-xattrs is also present just for the situation that on some > systems may be --xattrs option enabled by default (hardwired or in > set in $TAR_OPTIONS). (slightly different semantics against > --wildcards/--no-wildcards options that has state behaviour)
I'm attaching another fix. Now the GNU tar would be able to store/extract extended attributes having the '=' character inside keyword. E.g. $ touch file $ setfattr -n user.%3D=N=A=M=E -v VALUE file $ # this ^^ is there just to make sure everything is ok .. $ tar --xattrs -cf test.tar file file $ tar --xattrs -tvf test.tar -rw-rw-r--* praiskup/praiskup 0 2012-10-09 15:41 file x: 5 user.%3D=N=A=M=E Attached patch includes test-case to tar's testsuite also. For more info see this thread: http://lists.gnu.org/archive/html/bug-tar/2012-10/msg00017.html Pavel
>From c2afa4fd0a3e71b7a069af5d14b61db217563f3c Mon Sep 17 00:00:00 2001 From: Pavel Raiskup <prais...@redhat.com> Date: Tue, 9 Oct 2012 15:38:38 +0200 Subject: [PATCH] Allow to store/extract '=' character in xattr keyword --- src/xheader.c | 113 ++++++++++++++++++++++++++++++++++++++++++++++--- tests/Makefile.am | 1 + tests/testsuite.at | 1 + tests/xattr/xattr05.at | 49 +++++++++++++++++++++ 4 files changed, 158 insertions(+), 6 deletions(-) create mode 100644 tests/xattr/xattr05.at diff --git a/src/xheader.c b/src/xheader.c index e785248..de47388 100644 --- a/src/xheader.c +++ b/src/xheader.c @@ -499,6 +499,43 @@ 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 +844,70 @@ 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 +919,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 +1705,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 diff --git a/tests/Makefile.am b/tests/Makefile.am index 88942b3..449bbb4 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -177,6 +177,7 @@ TESTSUITE_AT = \ xattr/xattr02.at\ xattr/xattr03.at\ xattr/xattr04.at\ + xattr/xattr05.at\ xattr/acls01.at\ xattr/acls02.at\ xattr/selnx01.at\ diff --git a/tests/testsuite.at b/tests/testsuite.at index 63be9f0..d943e1f 100644 --- a/tests/testsuite.at +++ b/tests/testsuite.at @@ -343,6 +343,7 @@ m4_include([xattr/xattr01.at]) m4_include([xattr/xattr02.at]) m4_include([xattr/xattr03.at]) m4_include([xattr/xattr04.at]) +m4_include([xattr/xattr05.at]) m4_include([xattr/acls01.at]) m4_include([xattr/acls02.at]) diff --git a/tests/xattr/xattr05.at b/tests/xattr/xattr05.at new file mode 100644 index 0000000..27dc469 --- /dev/null +++ b/tests/xattr/xattr05.at @@ -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 -- 1.7.11.4