]> Dogcows Code - chaz/tar/commitdiff
Allow to store/extract '=' character in xattr keyword
authorPavel Raiskup <praiskup@redhat.com>
Mon, 19 Nov 2012 21:25:49 +0000 (23:25 +0200)
committerSergey Poznyakoff <gray@gnu.org.ua>
Mon, 19 Nov 2012 21:25:49 +0000 (23:25 +0200)
* 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.

src/xheader.c
tests/Makefile.am
tests/testsuite.at
tests/xattr05.at [new file with mode: 0644]

index 559e60adb22be629b6e9a01c12b2400e0325b5e1..d68aa2e0cef7f087551f30a4ca9f235d232185f3 100644 (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;
+
+  /* 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
index 4a7970ec3f937371f5093d5c4b3d924d0b26d8a7..dfe1f8ab7f73f055adeb7c48e2da6e69f4af7029 100644 (file)
@@ -178,6 +178,7 @@ TESTSUITE_AT = \
  xattr02.at\
  xattr03.at\
  xattr04.at\
+ xattr05.at\
  acls01.at\
  acls02.at\
  selnx01.at\
index d8ee991adfcf5dc6fa95e00597cd8f757828a839..9ec848f947b134f2f625c48659ffe050fd6f9bef 100644 (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])
diff --git a/tests/xattr05.at b/tests/xattr05.at
new file mode 100644 (file)
index 0000000..27dc469
--- /dev/null
@@ -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
This page took 0.028075 seconds and 4 git commands to generate.