]> Dogcows Code - chaz/tar/blobdiff - src/xheader.c
build: new configure option --enable-gcc-warnings
[chaz/tar] / src / xheader.c
index 6141748a7228dc01d4f1272147f340fb5857b358..291d9950dd3737325326ce73af26cfc7004267aa 100644 (file)
@@ -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++;
@@ -460,7 +457,8 @@ xheader_write_global (struct xheader *xhdr)
     }
 }
 
-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;
@@ -469,9 +467,11 @@ void xheader_xattr_init (struct tar_stat_info *st)
   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;
 
@@ -485,9 +485,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)++;
 
@@ -498,8 +499,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);
@@ -513,8 +553,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;
 
@@ -806,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
     {
@@ -826,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');
@@ -1087,8 +1184,6 @@ decode_time (struct timespec *ts, char const *arg, char const *keyword)
   return true;
 }
 
-
-
 static void
 code_num (uintmax_t value, char const *keyword, struct xheader *xhdr)
 {
@@ -1554,6 +1649,20 @@ 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)
@@ -1598,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' */;
 
-  xstr = xmemdup(arg, size + 1);
-  xheader_xattr_add(st, keyword + strlen("SCHILY.xattr."), xstr, size);
-  free(xstr);
+  xattr_decode_keyword (xkey);
+
+  xheader_xattr_add (st, xkey + strlen("SCHILY.xattr."), xstr, size);
 }
 
 static void
@@ -1703,6 +1821,11 @@ 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 },
This page took 0.030141 seconds and 4 git commands to generate.