> 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 <[email protected]>
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