6a0e236
diff -urNp tar-1.22-orig/configure.ac tar-1.22/configure.ac
2de9cec
--- tar-1.22-orig/configure.ac	2009-03-05 08:01:58.000000000 +0100
6a0e236
+++ tar-1.22/configure.ac	2009-11-23 14:48:00.000000000 +0100
Radek Brich fc86677
@@ -40,7 +40,7 @@ AC_CHECK_HEADERS_ONCE(fcntl.h linux/fd.h
Radek Brich fc86677
   sys/param.h sys/device.h sys/filio.h sys/gentape.h \
Radek Brich fc86677
   sys/inet.h sys/io/trioctl.h \
Radek Brich fc86677
   sys/mtio.h sys/time.h sys/tprintf.h sys/tape.h \
Radek Brich fc86677
-  unistd.h locale.h)
Radek Brich fc86677
+  unistd.h locale.h selinux/selinux.h attr/xattr.h sys/acl.h)
Radek Brich fc86677
 
Radek Brich fc86677
 AC_CHECK_HEADERS([sys/buf.h], [], [],
Radek Brich fc86677
 [#if HAVE_SYS_PARAM_H
Radek Brich fc86677
@@ -88,6 +88,13 @@ gl_INIT
Radek Brich fc86677
 tar_PAXUTILS
Radek Brich fc86677
 
045face
 AC_CHECK_FUNCS(fsync getdtablesize lstat mkfifo readlink symlink setlocale utimes)
Radek Brich fc86677
+AC_CHECK_FUNCS(getxattr  fgetxattr  lgetxattr \
Radek Brich fc86677
+               setxattr  fsetxattr  lsetxattr \
Radek Brich fc86677
+               listxattr flistxattr llistxattr,
Radek Brich fc86677
+               AC_DEFINE(HAVE_XATTRS,,[Define if we have a working extended attributes]),)
Radek Brich fc86677
+AC_CHECK_LIB(selinux, getfilecon)
Radek Brich fc86677
+AC_CHECK_LIB(acl, acl_get_fd)
Radek Brich fc86677
+
Radek Brich fc86677
 AC_CHECK_DECLS([getgrgid],,, [#include <grp.h>])
Radek Brich fc86677
 AC_CHECK_DECLS([getpwuid],,, [#include <pwd.h>])
Radek Brich fc86677
 AC_CHECK_DECLS([time],,, [#include <time.h>])
Radek Brich fc86677
@@ -203,6 +210,8 @@ AC_DEFINE_UNQUOTED(DEFAULT_QUOTING_STYLE
Radek Brich fc86677
 # Iconv
Radek Brich fc86677
 AM_ICONV
Radek Brich fc86677
 AC_CHECK_HEADERS(iconv.h)
Radek Brich fc86677
+AC_CHECK_HEADERS(selinux/selinux.h)
Radek Brich fc86677
+AC_CHECK_HEADERS(attr/xattr.h)
Radek Brich fc86677
 AC_CHECK_TYPE(iconv_t,:,
Radek Brich fc86677
               AC_DEFINE(iconv_t, int,
Radek Brich fc86677
                         [Conversion descriptor type]),
6a0e236
diff -urNp tar-1.22-orig/doc/tar.texi tar-1.22/doc/tar.texi
2de9cec
--- tar-1.22-orig/doc/tar.texi	2009-03-05 08:04:13.000000000 +0100
6a0e236
+++ tar-1.22/doc/tar.texi	2009-11-23 14:48:00.000000000 +0100
0aec5e9
@@ -2345,6 +2345,10 @@ Normally when creating an archive, @comm
0aec5e9
 @samp{/} from member names.  This option disables that behavior.
0aec5e9
 @xref{absolute}.
0aec5e9
 
0aec5e9
+@opsummary{acl}
0aec5e9
+@item --acls
0aec5e9
+Causes @command{tar} to store ACL's.  @xref{Attributes}.
0aec5e9
+
0aec5e9
 @opsummary{after-date}
0aec5e9
 @item --after-date
0aec5e9
 
2de9cec
@@ -2844,6 +2848,10 @@ contents have changed (as opposed to jus
0aec5e9
 also back up files for which any status information has
0aec5e9
 changed).  @xref{after}.
0aec5e9
 
0aec5e9
+@opsummary{no-acl}
0aec5e9
+@item --no-acls
0aec5e9
+Causes @command{tar} not to store and not to extract ACL's.  @xref{Attributes}.
0aec5e9
+
0aec5e9
 @opsummary{no-anchored}
0aec5e9
 @item --no-anchored
0aec5e9
 An exclude pattern can match any subsequence of the name's components.
2de9cec
@@ -2919,11 +2927,21 @@ When extracting an archive, subtract the
0aec5e9
 the permissions specified in the archive.  This is the default behavior
0aec5e9
 for ordinary users.
0aec5e9
 
0aec5e9
+@opsummary{no-selinux}
0aec5e9
+@item --no-selinux
0aec5e9
+Causes @command{tar} not to store and not to extract SELinux security context.
0aec5e9
+@xref{Attributes}.
0aec5e9
+
0aec5e9
 @opsummary{no-unquote}
0aec5e9
 @item --no-unquote
0aec5e9
 Treat all input file or member names literally, do not interpret
0aec5e9
 escape sequences.  @xref{input name quoting}.
0aec5e9
 
0aec5e9
+@opsummary{no-xattrs}
0aec5e9
+@item --no-xattrs
0aec5e9
+Causes @command{tar} not to store and not to extract xattrs. This option also
0aec5e9
+enables @option{--no-selinux} and @option{--no-acls}.  @xref{Attributes}.
0aec5e9
+
0aec5e9
 @opsummary{no-wildcards}
0aec5e9
 @item --no-wildcards
0aec5e9
 Do not use wildcards.
2de9cec
@@ -3151,6 +3169,11 @@ locations.  Usually @command{tar} determ
0aec5e9
 the archive can be seeked or not.  This option is intended for use
0aec5e9
 in cases when such recognition fails.
0aec5e9
 
0aec5e9
+@opsummary{selinux}
0aec5e9
+@item --selinux
0aec5e9
+Causes @command{tar} to store SElinux security context.  @xref{Attributes}.
0aec5e9
+
0aec5e9
+
0aec5e9
 @opsummary{show-defaults}
0aec5e9
 @item --show-defaults
0aec5e9
 
2de9cec
@@ -3349,6 +3372,11 @@ Used in conjunction with @option{--multi
0aec5e9
 keep track of which volume of a multi-volume archive it is working in
0aec5e9
 @var{file}.  @xref{volno-file}.
0aec5e9
 
0aec5e9
+@opsummary{xattrs}
0aec5e9
+@item --xattrs
0aec5e9
+Causes @command{tar} to store xattrs. This option also enables
0aec5e9
+@option{--selinux} and @option{--acls}.  @xref{Attributes}.
0aec5e9
+
0aec5e9
 @opsummary{wildcards}
0aec5e9
 @item --wildcards
0aec5e9
 Use wildcards when matching member names with patterns.
2de9cec
@@ -8350,6 +8378,8 @@ implementation able to read @samp{ustar}
Radek Brich fc86677
 most @samp{posix} archives as well, with the only exception that any
Radek Brich fc86677
 additional information (such as long file names etc.) will in such
Radek Brich fc86677
 case be extracted as plain text files along with the files it refers to.
Radek Brich fc86677
+This is the only format that can store ACLs, SELinux context and extended
Radek Brich fc86677
+attributes.
Radek Brich fc86677
 
Radek Brich fc86677
 This archive format will be the default format for future versions
Radek Brich fc86677
 of @GNUTAR{}.
2de9cec
@@ -8902,6 +8932,51 @@ Same as both @option{--same-permissions}
2de9cec
 
2de9cec
 This option is deprecated, and will be removed in @GNUTAR{} version 1.23.
Radek Brich fc86677
 
Radek Brich fc86677
+@opindex acls
Radek Brich fc86677
+@item --acls
Radek Brich fc86677
+This option causes @command{tar} to store the current ACL in the archive.
Radek Brich fc86677
+
Radek Brich fc86677
+The @option{--acls} option has no equivalent short option name.
Radek Brich fc86677
+
Radek Brich fc86677
+@opindex selinux
Radek Brich fc86677
+@item --selinux
Radek Brich fc86677
+This option causes @command{tar} to store the current SELinux security context
Radek Brich fc86677
+information in the archive.
Radek Brich fc86677
+
Radek Brich fc86677
+The @option{--selinux} option has no equivalent short option name.
Radek Brich fc86677
+
Radek Brich fc86677
+@opindex xattrs
Radek Brich fc86677
+@item --xattrs
Radek Brich fc86677
+This option causes @command{tar} to store the current extended attributes in
Radek Brich fc86677
+the archive. This option also enables @option{--acls} and @option{--selinux} if
Radek Brich fc86677
+they haven't been set already.
Radek Brich fc86677
+
Radek Brich fc86677
+The @option{--xattrs} option has no equivalent short option name.
Radek Brich fc86677
+
Radek Brich fc86677
+@opindex no-acls
Radek Brich fc86677
+@item --no-acls
Radek Brich fc86677
+This option causes @command{tar} not to store the current ACL in the archive
Radek Brich fc86677
+and not to extract any ACL information in an archive.
Radek Brich fc86677
+
0aec5e9
+The @option{--no-acls} option has no equivalent short option name.
Radek Brich fc86677
+
Radek Brich fc86677
+@opindex no-selinux
Radek Brich fc86677
+@item --no-selinux
Radek Brich fc86677
+This option causes @command{tar} not to store the current SELinux security
Radek Brich fc86677
+context information in the archive and not to extract any SELinux information in
Radek Brich fc86677
+an archive.
Radek Brich fc86677
+
0aec5e9
+The @option{--no-selinux} option has no equivalent short option name.
Radek Brich fc86677
+
0aec5e9
+@opindex no-xattrs
0aec5e9
+@item --no-xattrs
Radek Brich fc86677
+This option causes @command{tar} not to store the current extended attributes in
Radek Brich fc86677
+the archive and not to extract any extended attributes in an archive. This
0aec5e9
+option also enables @option{--no-acls} and @option{--no-selinux} if
Radek Brich fc86677
+they haven't been set already.
Radek Brich fc86677
+
0aec5e9
+The @option{--no-xattrs} option has no equivalent short option name.
Radek Brich fc86677
+
Radek Brich fc86677
 @end table
Radek Brich fc86677
 
Radek Brich fc86677
 @node Portability
6a0e236
diff -urNp tar-1.22-orig/src/common.h tar-1.22/src/common.h
2de9cec
--- tar-1.22-orig/src/common.h	2008-11-30 13:30:29.000000000 +0100
6a0e236
+++ tar-1.22/src/common.h	2009-11-23 14:48:00.000000000 +0100
2de9cec
@@ -248,6 +248,15 @@ GLOBAL int same_owner_option;
Radek Brich fc86677
 /* If positive, preserve permissions when extracting.  */
Radek Brich fc86677
 GLOBAL int same_permissions_option;
Radek Brich fc86677
 
Radek Brich fc86677
+/* If positive, save the SELinux context.  */
Radek Brich fc86677
+GLOBAL int selinux_context_option;
Radek Brich fc86677
+
Radek Brich fc86677
+/* If positive, save the ACLs.  */
Radek Brich fc86677
+GLOBAL int acls_option;
Radek Brich fc86677
+
Radek Brich fc86677
+/* If positive, save the user and root xattrs.  */
Radek Brich fc86677
+GLOBAL int xattrs_option;
Radek Brich fc86677
+
Radek Brich fc86677
 /* When set, strip the given number of file name components from the file name
Radek Brich fc86677
    before extracting */
Radek Brich fc86677
 GLOBAL size_t strip_name_components;
2de9cec
@@ -673,6 +682,9 @@ extern char *output_start;
Radek Brich fc86677
 
Radek Brich fc86677
 void update_archive (void);
Radek Brich fc86677
 
Radek Brich fc86677
+/* Module attrs.c.  */
Radek Brich fc86677
+#include "xattrs.h"
Radek Brich fc86677
+
Radek Brich fc86677
 /* Module xheader.c.  */
Radek Brich fc86677
 
Radek Brich fc86677
 void xheader_init (struct xheader *xhdr);
2de9cec
@@ -694,6 +706,12 @@ bool xheader_string_end (struct xheader 
Radek Brich fc86677
 bool xheader_keyword_deleted_p (const char *kw);
Radek Brich fc86677
 char *xheader_format_name (struct tar_stat_info *st, const char *fmt,
Radek Brich fc86677
 			   size_t n);
Radek Brich fc86677
+void xheader_xattr_init(struct tar_stat_info *st);
Radek Brich fc86677
+void xheader_xattr_free(struct xattr_array *vals, size_t sz);
Radek Brich fc86677
+void xheader_xattr_copy(const struct tar_stat_info *st,
Radek Brich fc86677
+                        struct xattr_array **vals, size_t *sz);
Radek Brich fc86677
+void xheader_xattr_add(struct tar_stat_info *st,
Radek Brich fc86677
+                       const char *key, const char *val, size_t len);
Radek Brich fc86677
 
Radek Brich fc86677
 /* Module system.c */
Radek Brich fc86677
 
6a0e236
diff -urNp tar-1.22-orig/src/create.c tar-1.22/src/create.c
2de9cec
--- tar-1.22-orig/src/create.c	2008-10-30 11:58:04.000000000 +0100
6a0e236
+++ tar-1.22/src/create.c	2009-11-23 14:48:33.000000000 +0100
2de9cec
@@ -24,6 +24,7 @@
2de9cec
 #include <quotearg.h>
2de9cec
 
2de9cec
 #include "common.h"
Radek Brich fc86677
+
2de9cec
 #include <hash.h>
2de9cec
 
2de9cec
 struct link
2de9cec
@@ -944,6 +945,30 @@ start_header (struct tar_stat_info *st)
2de9cec
       GNAME_TO_CHARS (st->gname, header->header.gname);
2de9cec
     }
2de9cec
 
2de9cec
+  if (archive_format == POSIX_FORMAT)
2de9cec
+    {
2de9cec
+      if (acls_option > 0)
2de9cec
+        {
2de9cec
+          if (st->acls_a_ptr)
2de9cec
+            xheader_store ("SCHILY.acl.access", st, NULL);
2de9cec
+          if (st->acls_d_ptr)
2de9cec
+            xheader_store ("SCHILY.acl.default", st, NULL);
2de9cec
+        }
2de9cec
+      if ((selinux_context_option > 0) && st->cntx_name)
2de9cec
+        xheader_store ("RHT.security.selinux", st, NULL);
2de9cec
+      if (xattrs_option > 0)
2de9cec
+        {
2de9cec
+          size_t scan_xattr = 0;
2de9cec
+          struct xattr_array *xattr_map = st->xattr_map;
2de9cec
+          
2de9cec
+          while (scan_xattr < st->xattr_map_size)
2de9cec
+            {
2de9cec
+              xheader_store (xattr_map[scan_xattr].xkey, st, &scan_xattr);
2de9cec
+              ++scan_xattr;
2de9cec
+            }
2de9cec
+        }
2de9cec
+    }
Radek Brich fc86677
+
2de9cec
   return header;
2de9cec
 }
2de9cec
 
2de9cec
@@ -1578,6 +1603,10 @@ dump_file0 (struct tar_stat_info *st, co
2de9cec
 	    }
2de9cec
 	}
2de9cec
 
2de9cec
+      xattrs_acls_get(st, p, fd, !is_dir);
2de9cec
+      xattrs_selinux_get(st, p, fd);
2de9cec
+      xattrs_xattrs_get(st, p, fd);
Radek Brich fc86677
+
2de9cec
       if (is_dir)
2de9cec
 	{
2de9cec
 	  const char *tag_file_name;
6a0e236
@@ -1709,6 +1738,9 @@ dump_file0 (struct tar_stat_info *st, co
6a0e236
       if (NAME_FIELD_SIZE - (archive_format == OLDGNU_FORMAT) < size)
6a0e236
 	write_long_link (st);
6a0e236
 
6a0e236
+      xattrs_selinux_get(st, p, -1);
6a0e236
+      xattrs_xattrs_get(st, p, -1);
6a0e236
+
6a0e236
       block_ordinal = current_block_ordinal ();
6a0e236
       st->stat.st_size = 0;	/* force 0 size on symlink */
6a0e236
       header = start_header (st);
6a0e236
diff -urNp tar-1.22-orig/src/extract.c tar-1.22/src/extract.c
2de9cec
--- tar-1.22-orig/src/extract.c	2008-10-30 15:10:28.000000000 +0100
6a0e236
+++ tar-1.22/src/extract.c	2009-11-23 14:48:33.000000000 +0100
2de9cec
@@ -69,6 +69,13 @@ struct delayed_set_stat
2de9cec
     mode_t invert_permissions;
2de9cec
     enum permstatus permstatus;
2de9cec
     bool after_links;
2de9cec
+    char *cntx_name;
2de9cec
+    char *acls_a_ptr;
2de9cec
+    size_t acls_a_len;
2de9cec
+    char *acls_d_ptr;
2de9cec
+    size_t acls_d_len;
2de9cec
+    size_t xattr_map_size;   /* Size of the xattr map */
2de9cec
+    struct xattr_array *xattr_map;
2de9cec
     char file_name[1];
2de9cec
   };
2de9cec
 
2de9cec
@@ -96,6 +103,18 @@ struct delayed_link
2de9cec
        hard-linked together.  */
2de9cec
     struct string_list *sources;
2de9cec
 
2de9cec
+    /* SELinux context */
2de9cec
+    char *cntx_name;
2de9cec
+   
2de9cec
+    /* ACLs */
2de9cec
+    char *acls_a_ptr;
2de9cec
+    size_t acls_a_len;
2de9cec
+    char *acls_d_ptr;
2de9cec
+    size_t acls_d_len;
2de9cec
+   
2de9cec
+    size_t xattr_map_size;   /* Size of the xattr map */
2de9cec
+    struct xattr_array *xattr_map;
2de9cec
+   
2de9cec
     /* The desired target of the desired link.  */
2de9cec
     char target[1];
2de9cec
   };
2de9cec
@@ -276,6 +295,10 @@ set_stat (char const *file_name,
2de9cec
 	 give files away.  */
2de9cec
     }
2de9cec
 
2de9cec
+  xattrs_acls_set(st, file_name, typeflag);
2de9cec
+  xattrs_selinux_set(st, file_name, typeflag);
2de9cec
+  xattrs_xattrs_set(st, file_name, typeflag);
Radek Brich fc86677
+
2de9cec
   if (0 < same_owner_option && permstatus != INTERDIR_PERMSTATUS)
2de9cec
     {
2de9cec
       /* When lchown exists, it should be used to change the attributes of
2de9cec
@@ -352,6 +375,29 @@ delay_set_stat (char const *file_name, s
2de9cec
   data->invert_permissions = invert_permissions;
2de9cec
   data->permstatus = permstatus;
2de9cec
   data->after_links = 0;
2de9cec
+  data->cntx_name = NULL;
2de9cec
+  assign_string (&data->cntx_name, st->cntx_name);
2de9cec
+  if (st->acls_a_ptr)
Radek Brich fc86677
+    {
2de9cec
+      data->acls_a_ptr = xmemdup(st->acls_a_ptr, st->acls_a_len + 1);
2de9cec
+      data->acls_a_len = st->acls_a_len;
Radek Brich fc86677
+    }
2de9cec
+  else
Radek Brich fc86677
+    {
2de9cec
+      data->acls_a_ptr = NULL;
2de9cec
+      data->acls_a_len = 0;
Radek Brich fc86677
+    }
2de9cec
+  if (st->acls_d_ptr)
Radek Brich fc86677
+    {
2de9cec
+      data->acls_d_ptr = xmemdup(st->acls_d_ptr, st->acls_d_len + 1);
2de9cec
+      data->acls_d_len = st->acls_d_len;
Radek Brich fc86677
+    }
2de9cec
+  else
Radek Brich fc86677
+    {
2de9cec
+      data->acls_d_ptr = NULL;
2de9cec
+      data->acls_d_len = 0;
Radek Brich fc86677
+    }
2de9cec
+  xheader_xattr_copy (st, &data->xattr_map, &data->xattr_map_size);
2de9cec
   strcpy (data->file_name, file_name);
2de9cec
   delayed_set_stat_head = data;
2de9cec
 }
2de9cec
@@ -599,11 +645,22 @@ apply_nonancestor_delayed_set_stat (char
2de9cec
 	  sb.stat.st_gid = data->gid;
2de9cec
 	  sb.atime = data->atime;
2de9cec
 	  sb.mtime = data->mtime;
2de9cec
+          sb.cntx_name = data->cntx_name;
2de9cec
+          sb.acls_a_ptr = data->acls_a_ptr;
2de9cec
+          sb.acls_a_len = data->acls_a_len;
2de9cec
+          sb.acls_d_ptr = data->acls_d_ptr;
2de9cec
+          sb.acls_d_len = data->acls_d_len;
2de9cec
+          sb.xattr_map = data->xattr_map;
2de9cec
+          sb.xattr_map_size = data->xattr_map_size;
2de9cec
 	  set_stat (data->file_name, &sb, cur_info,
2de9cec
 		    data->invert_permissions, data->permstatus, DIRTYPE);
2de9cec
 	}
2de9cec
 
2de9cec
       delayed_set_stat_head = data->next;
2de9cec
+      xheader_xattr_free (data->xattr_map, data->xattr_map_size);
2de9cec
+      free (data->cntx_name);
2de9cec
+      free (data->acls_a_ptr);
2de9cec
+      free (data->acls_d_ptr);
2de9cec
       free (data);
2de9cec
     }
2de9cec
 }
2de9cec
@@ -882,6 +939,13 @@ create_placeholder_file (char *file_name
2de9cec
 			    + strlen (file_name) + 1);
2de9cec
       p->sources->next = 0;
2de9cec
       strcpy (p->sources->string, file_name);
2de9cec
+      p->cntx_name = NULL;
6a0e236
+      assign_string (&p->cntx_name, current_stat_info.cntx_name);
2de9cec
+      p->acls_a_ptr = NULL;
2de9cec
+      p->acls_a_len = 0;
2de9cec
+      p->acls_d_ptr = NULL;
2de9cec
+      p->acls_d_len = 0;
6a0e236
+      xheader_xattr_copy (&current_stat_info, &p->xattr_map, &p->xattr_map_size);
2de9cec
       strcpy (p->target, current_stat_info.link_name);
2de9cec
 
2de9cec
       h = delayed_set_stat_head;
2de9cec
@@ -1288,6 +1352,13 @@ apply_delayed_links (void)
2de9cec
 		  struct tar_stat_info st1;
2de9cec
 		  st1.stat.st_uid = ds->uid;
2de9cec
 		  st1.stat.st_gid = ds->gid;
2de9cec
+                  st1.cntx_name = ds->cntx_name;
2de9cec
+                  st1.acls_a_ptr = ds->acls_a_ptr;
2de9cec
+                  st1.acls_a_len = ds->acls_a_len;
2de9cec
+                  st1.acls_d_ptr = ds->acls_d_ptr;
2de9cec
+                  st1.acls_d_len = ds->acls_d_len;
2de9cec
+                  st1.xattr_map = ds->xattr_map;
2de9cec
+                  st1.xattr_map_size = ds->xattr_map_size;
2de9cec
 		  set_stat (source, &st1, NULL, 0, 0, SYMTYPE);
2de9cec
 		  valid_source = source;
2de9cec
 		}
6a0e236
@@ -1301,6 +1372,9 @@ apply_delayed_links (void)
6a0e236
 	  sources = next;
6a0e236
 	}
6a0e236
 
6a0e236
+   xheader_xattr_free (ds->xattr_map, ds->xattr_map_size);
6a0e236
+   free (ds->cntx_name);
6a0e236
+
6a0e236
       {
6a0e236
 	struct delayed_link *next = ds->next;
6a0e236
 	free (ds);
6a0e236
diff -urNp tar-1.22-orig/src/list.c tar-1.22/src/list.c
6a0e236
--- tar-1.22-orig/src/list.c	2009-11-23 14:47:03.000000000 +0100
6a0e236
+++ tar-1.22/src/list.c	2009-11-23 14:48:00.000000000 +0100
6a0e236
@@ -568,6 +568,13 @@ decode_header (union block *header, stru
2de9cec
   assign_string (&stat_info->gname,
2de9cec
 		 header->header.gname[0] ? header->header.gname : NULL);
2de9cec
 
2de9cec
+  stat_info->acls_a_ptr = NULL;
2de9cec
+  stat_info->acls_a_len = 0;
2de9cec
+  stat_info->acls_d_ptr = NULL;
2de9cec
+  stat_info->acls_d_len = 0;
2de9cec
+  stat_info->cntx_name = NULL;
2de9cec
+  xheader_xattr_init(stat_info);
2de9cec
+  
2de9cec
   if (format == OLDGNU_FORMAT && incremental_option)
2de9cec
     {
2de9cec
       stat_info->atime.tv_sec = TIME_FROM_HEADER (header->oldgnu_header.atime);
6a0e236
diff -urNp tar-1.22-orig/src/Makefile.am tar-1.22/src/Makefile.am
2de9cec
--- tar-1.22-orig/src/Makefile.am	2007-10-29 18:53:06.000000000 +0100
6a0e236
+++ tar-1.22/src/Makefile.am	2009-11-23 14:48:00.000000000 +0100
2de9cec
@@ -20,7 +20,7 @@
2de9cec
 
2de9cec
 bin_PROGRAMS = tar
2de9cec
 
2de9cec
-noinst_HEADERS = arith.h common.h tar.h
2de9cec
+noinst_HEADERS = arith.h common.h tar.h xattrs.h
2de9cec
 tar_SOURCES = \
2de9cec
  buffer.c\
2de9cec
  checkpoint.c\
2de9cec
@@ -39,10 +39,11 @@ tar_SOURCES = \
2de9cec
  tar.c\
2de9cec
  transform.c\
2de9cec
  update.c\
2de9cec
- utf8.c
2de9cec
+ utf8.c\
2de9cec
+ xattrs.c
2de9cec
 
2de9cec
 INCLUDES = -I$(top_srcdir)/lib -I../ -I../lib
2de9cec
 
2de9cec
 LDADD = ../lib/libtar.a $(LIBINTL) $(LIBICONV)
2de9cec
 
2de9cec
-tar_LDADD = $(LDADD) $(LIB_CLOCK_GETTIME)
2de9cec
+tar_LDADD = $(LIBS) $(LDADD) $(LIB_CLOCK_GETTIME)
6a0e236
diff -urNp tar-1.22-orig/src/tar.c tar-1.22/src/tar.c
2de9cec
--- tar-1.22-orig/src/tar.c	2009-03-05 08:04:13.000000000 +0100
6a0e236
+++ tar-1.22/src/tar.c	2009-11-23 14:48:00.000000000 +0100
2de9cec
@@ -246,7 +246,8 @@ tar_set_quoting_style (char *arg)
2de9cec
 
2de9cec
 enum
2de9cec
 {
2de9cec
-  ANCHORED_OPTION = CHAR_MAX + 1,
2de9cec
+  ACLS_OPTION = CHAR_MAX + 1,
2de9cec
+  ANCHORED_OPTION,
2de9cec
   ATIME_PRESERVE_OPTION,
2de9cec
   BACKUP_OPTION,
2de9cec
   CHECK_DEVICE_OPTION,
2de9cec
@@ -276,6 +277,7 @@ enum
2de9cec
   MODE_OPTION,
2de9cec
   MTIME_OPTION,
2de9cec
   NEWER_MTIME_OPTION,
2de9cec
+  NO_ACLS_OPTION,
2de9cec
   NO_ANCHORED_OPTION,
2de9cec
   NO_AUTO_COMPRESS_OPTION,
2de9cec
   NO_CHECK_DEVICE_OPTION,
2de9cec
@@ -288,9 +290,11 @@ enum
2de9cec
   NO_RECURSION_OPTION,
2de9cec
   NO_SAME_OWNER_OPTION,
2de9cec
   NO_SAME_PERMISSIONS_OPTION,
2de9cec
+  NO_SELINUX_CONTEXT_OPTION,
2de9cec
   NO_UNQUOTE_OPTION,
2de9cec
   NO_WILDCARDS_MATCH_SLASH_OPTION,
2de9cec
   NO_WILDCARDS_OPTION,
2de9cec
+  NO_XATTR_OPTION,
2de9cec
   NULL_OPTION,
2de9cec
   NUMERIC_OWNER_OPTION,
2de9cec
   OCCURRENCE_OPTION,
2de9cec
@@ -312,6 +316,7 @@ enum
2de9cec
   RMT_COMMAND_OPTION,
2de9cec
   RSH_COMMAND_OPTION,
2de9cec
   SAME_OWNER_OPTION,
2de9cec
+  SELINUX_CONTEXT_OPTION,
2de9cec
   SHOW_DEFAULTS_OPTION,
2de9cec
   SHOW_OMITTED_DIRS_OPTION,
2de9cec
   SHOW_TRANSFORMED_NAMES_OPTION,
2de9cec
@@ -328,7 +333,8 @@ enum
2de9cec
   VERSION_OPTION,
2de9cec
   VOLNO_FILE_OPTION,
2de9cec
   WILDCARDS_MATCH_SLASH_OPTION,
2de9cec
-  WILDCARDS_OPTION
2de9cec
+  WILDCARDS_OPTION,
2de9cec
+  XATTR_OPTION
2de9cec
 };
2de9cec
 
2de9cec
 const char *argp_program_version = "tar (" PACKAGE_NAME ") " VERSION;
2de9cec
@@ -465,6 +471,10 @@ static struct argp_option options[] = {
2de9cec
   {NULL, 0, NULL, 0,
2de9cec
    N_("Handling of file attributes:"), GRID },
2de9cec
 
2de9cec
+  {"acls", ACLS_OPTION, 0, 0, 
2de9cec
+   N_("Save the ACLs to the archive"), GRID+1 },
2de9cec
+  {"no-acls", NO_ACLS_OPTION, 0, 0, 
2de9cec
+   N_("Don't extract the ACLs from the archive"), GRID+1 },
2de9cec
   {"owner", OWNER_OPTION, N_("NAME"), 0,
2de9cec
    N_("force NAME as owner for added files"), GRID+1 },
2de9cec
   {"group", GROUP_OPTION, N_("NAME"), 0,
2de9cec
@@ -495,6 +505,14 @@ static struct argp_option options[] = {
2de9cec
   {"preserve-order", 's', 0, 0,
2de9cec
    N_("sort names to extract to match archive"), GRID+1 },
2de9cec
   {"same-order", 0, 0, OPTION_ALIAS, NULL, GRID+1 },
2de9cec
+  {"selinux", SELINUX_CONTEXT_OPTION, 0, 0, 
2de9cec
+   N_("Save the SELinux context to the archive"), GRID+1 },
2de9cec
+  {"no-selinux", NO_SELINUX_CONTEXT_OPTION, 0, 0, 
2de9cec
+   N_("Don't extract the SELinux context from the archive"), GRID+1 },
2de9cec
+  {"xattrs", XATTR_OPTION, 0, 0, 
2de9cec
+   N_("Save the user/root xattrs to the archive"), GRID+1 },
2de9cec
+  {"no-xattrs", NO_XATTR_OPTION, 0, 0, 
2de9cec
+   N_("Don't extract the user/root xattrs from the archive"), GRID+1 },
2de9cec
   {"preserve", PRESERVE_OPTION, 0, 0,
2de9cec
    N_("same as both -p and -s"), GRID+1 },
2de9cec
   {"delay-directory-restore", DELAY_DIRECTORY_RESTORE_OPTION, 0, 0,
2de9cec
@@ -1932,6 +1950,37 @@ parse_opt (int key, char *arg, struct ar
2de9cec
       same_permissions_option = -1;
2de9cec
       break;
2de9cec
 
2de9cec
+    case ACLS_OPTION:
2de9cec
+      set_archive_format ("posix");
2de9cec
+      acls_option = 1;
2de9cec
+      break;
Radek Brich fc86677
+
2de9cec
+    case NO_ACLS_OPTION:
2de9cec
+      acls_option = -1;
2de9cec
+      break;
Radek Brich fc86677
+
2de9cec
+    case SELINUX_CONTEXT_OPTION:
2de9cec
+      set_archive_format ("posix");
2de9cec
+      selinux_context_option = 1;
2de9cec
+      break;
Radek Brich fc86677
+
2de9cec
+    case NO_SELINUX_CONTEXT_OPTION:
2de9cec
+      selinux_context_option = -1;
2de9cec
+      break;
Radek Brich 7254d79
+
2de9cec
+    case XATTR_OPTION:
2de9cec
+      set_archive_format ("posix");
2de9cec
+      if (!acls_option) acls_option = 1;
2de9cec
+      if (!selinux_context_option) selinux_context_option = 1;
2de9cec
+      xattrs_option = 1;
2de9cec
+      break;
Radek Brich fc86677
+
2de9cec
+    case NO_XATTR_OPTION:
2de9cec
+      if (!acls_option) acls_option = -1;
2de9cec
+      if (!selinux_context_option) selinux_context_option = -1;
2de9cec
+      xattrs_option = -1;
2de9cec
+      break;
2de9cec
+
2de9cec
     case RECURSION_OPTION:
2de9cec
       recursion_option = FNM_LEADING_DIR;
2de9cec
       break;
2de9cec
@@ -2330,6 +2379,29 @@ decode_options (int argc, char **argv)
2de9cec
 	  || subcommand_option != LIST_SUBCOMMAND))
2de9cec
     USAGE_ERROR ((0, 0, _("--pax-option can be used only on POSIX archives")));
2de9cec
 
2de9cec
+  /* star create's non-POSIX typed archives with xattr support, so allow the
2de9cec
+     extra headers */
2de9cec
+  if ((acls_option > 0)
2de9cec
+      && archive_format != POSIX_FORMAT
2de9cec
+      && (subcommand_option != EXTRACT_SUBCOMMAND
2de9cec
+	  || subcommand_option != DIFF_SUBCOMMAND
2de9cec
+	  || subcommand_option != LIST_SUBCOMMAND))
2de9cec
+    USAGE_ERROR ((0, 0, _("--acls can be used only on POSIX archives")));
2de9cec
+
2de9cec
+  if ((selinux_context_option > 0)
2de9cec
+      && archive_format != POSIX_FORMAT
2de9cec
+      && (subcommand_option != EXTRACT_SUBCOMMAND
2de9cec
+	  || subcommand_option != DIFF_SUBCOMMAND
2de9cec
+	  || subcommand_option != LIST_SUBCOMMAND))
2de9cec
+    USAGE_ERROR ((0, 0, _("--selinux can be used only on POSIX archives")));
2de9cec
+
2de9cec
+  if ((xattrs_option > 0)
2de9cec
+      && archive_format != POSIX_FORMAT
2de9cec
+      && (subcommand_option != EXTRACT_SUBCOMMAND
2de9cec
+	  || subcommand_option != DIFF_SUBCOMMAND
2de9cec
+	  || subcommand_option != LIST_SUBCOMMAND))
2de9cec
+    USAGE_ERROR ((0, 0, _("--xattrs can be used only on POSIX archives")));
2de9cec
+
2de9cec
   /* If ready to unlink hierarchies, so we are for simpler files.  */
2de9cec
   if (recursive_unlink_option)
2de9cec
     old_files_option = UNLINK_FIRST_OLD_FILES;
2de9cec
@@ -2544,11 +2616,15 @@ tar_stat_init (struct tar_stat_info *st)
2de9cec
 void
2de9cec
 tar_stat_destroy (struct tar_stat_info *st)
2de9cec
 {
2de9cec
+  xheader_xattr_free (st->xattr_map, st->xattr_map_size);
2de9cec
   free (st->orig_file_name);
2de9cec
   free (st->file_name);
2de9cec
   free (st->link_name);
2de9cec
   free (st->uname);
2de9cec
   free (st->gname);
2de9cec
+  free (st->cntx_name);
2de9cec
+  free (st->acls_a_ptr);
2de9cec
+  free (st->acls_d_ptr);
2de9cec
   free (st->sparse_map);
2de9cec
   free (st->dumpdir);
2de9cec
   xheader_destroy (&st->xhdr);
6a0e236
diff -urNp tar-1.22-orig/src/tar.h tar-1.22/src/tar.h
2de9cec
--- tar-1.22-orig/src/tar.h	2007-06-27 15:30:32.000000000 +0200
6a0e236
+++ tar-1.22/src/tar.h	2009-11-23 14:48:00.000000000 +0100
2de9cec
@@ -276,6 +276,14 @@ struct xheader
2de9cec
   uintmax_t string_length;
2de9cec
 };
2de9cec
 
2de9cec
+/* Information about xattrs for a file.  */
2de9cec
+struct xattr_array
2de9cec
+  {
2de9cec
+    char *xkey;
2de9cec
+    char *xval_ptr;
2de9cec
+    size_t xval_len;
2de9cec
+  };
Radek Brich fc86677
+
2de9cec
 struct tar_stat_info
2de9cec
 {
2de9cec
   char *orig_file_name;     /* name of file read from the archive header */
2de9cec
@@ -287,6 +295,15 @@ struct tar_stat_info
2de9cec
 
2de9cec
   char          *uname;     /* user name of owner */
2de9cec
   char          *gname;     /* group name of owner */
Radek Brich fc86677
+
2de9cec
+  char *cntx_name;          /* SELinux context for the current archive entry. */
Radek Brich fc86677
+
2de9cec
+  char *acls_a_ptr;         /* Access ACLs for the current archive entry. */
2de9cec
+  size_t acls_a_len;        /* Access ACLs for the current archive entry. */
2de9cec
+ 
2de9cec
+  char *acls_d_ptr;         /* Default ACLs for the current archive entry. */
2de9cec
+  size_t acls_d_len;        /* Default ACLs for the current archive entry. */
2de9cec
+
2de9cec
   struct stat   stat;       /* regular filesystem stat */
2de9cec
 
2de9cec
   /* STAT doesn't always have access, data modification, and status
2de9cec
@@ -309,6 +326,9 @@ struct tar_stat_info
2de9cec
   size_t sparse_map_size;   /* Size of the sparse map */
2de9cec
   struct sp_array *sparse_map;
2de9cec
 
2de9cec
+  size_t xattr_map_size;   /* Size of the xattr map */
2de9cec
+  struct xattr_array *xattr_map;
2de9cec
+
2de9cec
   /* Extended headers */
2de9cec
   struct xheader xhdr;
2de9cec
   
6a0e236
diff -urNp tar-1.22-orig/src/xattrs.c tar-1.22/src/xattrs.c
6a0e236
--- tar-1.22-orig/src/xattrs.c	1970-01-01 01:00:00.000000000 +0100
6a0e236
+++ tar-1.22/src/xattrs.c	2009-11-23 14:48:33.000000000 +0100
6a0e236
@@ -0,0 +1,491 @@
6a0e236
+/* Create a tar archive.
Radek Brich fc86677
+
6a0e236
+   Copyright (C) 2006 Free Software Foundation, Inc.
Radek Brich fc86677
+
6a0e236
+   Written by James Antill, on 2006-07-27.
Radek Brich fc86677
+
6a0e236
+   This program is free software; you can redistribute it and/or modify it
6a0e236
+   under the terms of the GNU General Public License as published by the
6a0e236
+   Free Software Foundation; either version 2, or (at your option) any later
6a0e236
+   version.
Radek Brich fc86677
+
6a0e236
+   This program is distributed in the hope that it will be useful, but
6a0e236
+   WITHOUT ANY WARRANTY; without even the implied warranty of
6a0e236
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
6a0e236
+   Public License for more details.
Radek Brich fc86677
+
6a0e236
+   You should have received a copy of the GNU General Public License along
6a0e236
+   with this program; if not, write to the Free Software Foundation, Inc.,
6a0e236
+   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
Radek Brich fc86677
+
6a0e236
+#include <system.h>
Radek Brich fc86677
+
6a0e236
+#include <quotearg.h>
Radek Brich fc86677
+
6a0e236
+#include "common.h"
Radek Brich fc86677
+
2de9cec
+
6a0e236
+#ifndef HAVE_SELINUX_SELINUX_H
6a0e236
+# undef HAVE_LIBSELINUX
6a0e236
+#endif
2de9cec
+
6a0e236
+#ifndef HAVE_ATTR_XATTR_H
6a0e236
+# undef HAVE_XATTRS
6a0e236
+#endif
2de9cec
+
6a0e236
+#ifndef HAVE_SYS_ACL_H
6a0e236
+# undef HAVE_LIBACL
6a0e236
+#endif
Radek Brich fc86677
+
6a0e236
+#ifdef HAVE_SELINUX_SELINUX_H
6a0e236
+# include <selinux/selinux.h>
6a0e236
+#endif
Radek Brich fc86677
+
6a0e236
+#ifdef HAVE_ATTR_XATTR_H
6a0e236
+# include <attr/xattr.h>
6a0e236
+#endif
Radek Brich fc86677
+
6a0e236
+#ifdef HAVE_SYS_ACL_H
6a0e236
+# include <sys/acl.h>
6a0e236
+#endif
Radek Brich fc86677
+
Radek Brich 7254d79
+
6a0e236
+#if 0 /* unused by xattr's atm. */
6a0e236
+static void xattrs__fd_get(struct tar_stat_info *st,
6a0e236
+                           char const *file_name, int fd, const char *attr,
6a0e236
+                           char **ret_ptr, size_t *ret_len)
2de9cec
+{
6a0e236
+#ifdef HAVE_XATTRS
6a0e236
+  static ssize_t asz = 1024;
6a0e236
+  ssize_t ret = 0;
6a0e236
+  static char *val = NULL;
6a0e236
+  
6a0e236
+  if (!val) val = xmalloc (asz);
6a0e236
+  
6a0e236
+  while (((ret = fgetxattr (fd, attr, val, asz)) == -1) &&
6a0e236
+         (errno == ERANGE))
6a0e236
+    {
6a0e236
+      asz <<= 1;
6a0e236
+      val = xrealloc (val, asz);
6a0e236
+    }
6a0e236
+  
6a0e236
+  if (ret != -1)
6a0e236
+    {
6a0e236
+      *ret_ptr = xmemdup (val, ret + 1);
6a0e236
+      *ret_len = ret;
6a0e236
+    }
6a0e236
+  else if (errno != ENOATTR)
6a0e236
+    call_arg_warn ("fgetxattr", file_name);
6a0e236
+#endif
2de9cec
+}
6a0e236
+#endif
Radek Brich fc86677
+
6a0e236
+static void xattrs__acls_get_a(struct tar_stat_info *st,
6a0e236
+                               char const *file_name, int fd,
6a0e236
+                               char **ret_ptr, size_t *ret_len)
6a0e236
+{ /* "system.posix_acl_access" */
6a0e236
+#ifdef HAVE_LIBACL
6a0e236
+  char *val = NULL;
6a0e236
+  ssize_t len;
6a0e236
+  acl_t acl;
2de9cec
+
2de9cec
+  if (fd != -1)
2de9cec
+  {
2de9cec
+    if ((acl = acl_get_fd (fd)) == (acl_t)NULL)
2de9cec
+    {
2de9cec
+      if (errno != ENOTSUP)
2de9cec
+        call_arg_warn ("acl_get_fd", file_name);
2de9cec
+      return;
2de9cec
+    }
2de9cec
+  }
2de9cec
+  else if ((acl = acl_get_file (file_name, ACL_TYPE_ACCESS)) == (acl_t)NULL)
2de9cec
+  {
2de9cec
+    if (errno != ENOTSUP)
2de9cec
+      call_arg_warn ("acl_get_file", file_name);
2de9cec
+    return;
2de9cec
+  }
2de9cec
+  
2de9cec
+  
2de9cec
+  val = acl_to_text(acl, &len;;
2de9cec
+  acl_free (acl);
2de9cec
+  
2de9cec
+  if (val == NULL)
2de9cec
+  {
2de9cec
+    call_arg_warn ("acl_to_text", file_name);
2de9cec
+    return;
2de9cec
+  }
2de9cec
+  
2de9cec
+  *ret_ptr = xstrdup (val);
2de9cec
+  *ret_len = len;
2de9cec
+  
2de9cec
+  acl_free (val);
2de9cec
+#endif
2de9cec
+}
2de9cec
+
2de9cec
+static void xattrs__acls_get_d(struct tar_stat_info *st,
2de9cec
+                               char const *file_name,
2de9cec
+                               char **ret_ptr, size_t *ret_len)
2de9cec
+{ /* "system.posix_acl_default" */
2de9cec
+#ifdef HAVE_LIBACL
2de9cec
+  char *val = NULL;
2de9cec
+  ssize_t len;
2de9cec
+  acl_t acl;
2de9cec
+  
2de9cec
+  if ((acl = acl_get_file (file_name, ACL_TYPE_DEFAULT)) == (acl_t)NULL)
2de9cec
+  {
2de9cec
+    if (errno != ENOTSUP)
2de9cec
+      call_arg_warn ("acl_get_file", file_name);
2de9cec
+    return;
2de9cec
+  }
2de9cec
+  
2de9cec
+  val = acl_to_text(acl, &len;;
2de9cec
+  acl_free (acl);
2de9cec
+  
2de9cec
+  if (val == NULL)
2de9cec
+  {
2de9cec
+    call_arg_warn ("acl_to_text", file_name);
2de9cec
+    return;
2de9cec
+  }
2de9cec
+  
2de9cec
+  *ret_ptr = xstrdup (val);
2de9cec
+  *ret_len = len;
2de9cec
+  
2de9cec
+  acl_free (val);
2de9cec
+#endif
2de9cec
+}
2de9cec
+
2de9cec
+void xattrs_acls_get(struct tar_stat_info *st, char const *file_name, int fd,
2de9cec
+                     int xisfile)
2de9cec
+{
2de9cec
+  if (acls_option > 0)
2de9cec
+    {
2de9cec
+#ifndef HAVE_LIBACL
2de9cec
+      static int done = 0;
2de9cec
+      if (!done)
2de9cec
+          WARN ((0, 0, _("ACL support requested, but not available")));
2de9cec
+      done = 1;
2de9cec
+#endif
2de9cec
+      xattrs__acls_get_a (st, file_name, fd,
2de9cec
+                          &st->acls_a_ptr, &st->acls_a_len);
2de9cec
+      if (!xisfile)
2de9cec
+        xattrs__acls_get_d (st, file_name,
2de9cec
+                            &st->acls_d_ptr, &st->acls_d_len);
2de9cec
+    }
Radek Brich fc86677
+}
Radek Brich fc86677
+
2de9cec
+void xattrs_selinux_get(struct tar_stat_info *st, char const *file_name, int fd)
Radek Brich fc86677
+{
2de9cec
+  if (selinux_context_option > 0)
2de9cec
+  {
2de9cec
+#ifndef HAVE_LIBSELINUX
2de9cec
+      static int done = 0;
2de9cec
+      if (!done)
2de9cec
+          WARN ((0, 0, _("SELinux support requested, but not available")));
2de9cec
+      done = 1;
2de9cec
+#else
2de9cec
+    if (fd == -1)
Radek Brich fc86677
+    {
2de9cec
+      if ((lgetfilecon (file_name, &st->cntx_name) == -1) && (errno != ENOTSUP) && (errno != ENODATA))
2de9cec
+        call_arg_warn ("lgetfilecon", file_name);
Radek Brich fc86677
+    }
2de9cec
+    else if ((fgetfilecon (fd, &st->cntx_name) == -1) && (errno != ENOTSUP) && (errno != ENODATA))
2de9cec
+      call_arg_warn ("fgetfilecon", file_name);
2de9cec
+#endif
2de9cec
+  }
Radek Brich fc86677
+}
Radek Brich fc86677
+
2de9cec
+void xattrs_xattrs_get(struct tar_stat_info *st, char const *file_name, int fd)
Radek Brich fc86677
+{
2de9cec
+  if (xattrs_option > 0)
2de9cec
+    { /* get all xattrs ... this include security.* and system.* if
2de9cec
+         available. We filter them here, but we have to filter them
2de9cec
+         in xattrs_xattrs_set() anyway.
2de9cec
+      */
2de9cec
+      static ssize_t xsz = 1024;
2de9cec
+      static char *xatrs = NULL;
2de9cec
+      ssize_t xret = -1;
Radek Brich fc86677
+
2de9cec
+#ifndef HAVE_XATTRS
2de9cec
+      static int done = 0;
2de9cec
+      if ((xattrs_option > 0) && !done)
2de9cec
+          WARN ((0, 0, _("Xattr support requested, but not available")));
2de9cec
+      done = 1;
2de9cec
+#else
Radek Brich fc86677
+
2de9cec
+      if (!xatrs) xatrs = xmalloc (xsz);
2de9cec
+              
2de9cec
+      while (((fd == -1) ? 
6a0e236
+              ((xret = llistxattr (file_name, xatrs, xsz)) == -1) :
2de9cec
+              ((xret = flistxattr (fd, xatrs, xsz)) == -1)) &&
2de9cec
+             (errno == ERANGE))
2de9cec
+        {
2de9cec
+          xsz <<= 1;
2de9cec
+          xatrs = xrealloc (xatrs, xsz);
2de9cec
+        }
Radek Brich fc86677
+
2de9cec
+      if (xret == -1)
6a0e236
+        call_arg_warn ((fd == -1) ? "llistxattrs" : "flistxattrs", file_name);
2de9cec
+      else
2de9cec
+        {
2de9cec
+          const char *attr = xatrs;
2de9cec
+          static ssize_t asz = 1024;
2de9cec
+          static char *val = NULL;
2de9cec
+          
2de9cec
+          if (!val) val = xmalloc (asz);
2de9cec
+          
2de9cec
+          while (xret > 0)
2de9cec
+            {
2de9cec
+              size_t len = strlen (attr);
2de9cec
+              ssize_t aret = 0;
2de9cec
+              
2de9cec
+              if (strncmp (attr, "user.", strlen("user.")) &&
2de9cec
+                  strncmp (attr, "trusted.", strlen("trusted.")))
2de9cec
+                goto next_attr; /* only store normal xattrs */
2de9cec
+              
6a0e236
+              while (((fd == -1) ?
6a0e236
+                      ((aret = lgetxattr (file_name, attr, val, asz)) == -1) :
2de9cec
+                      ((aret = fgetxattr (fd, attr, val, asz)) == -1)) &&
2de9cec
+                     (errno == ERANGE))
2de9cec
+                {
2de9cec
+                  asz <<= 1;
2de9cec
+                  val = xrealloc (val, asz);
2de9cec
+                }
2de9cec
+              
2de9cec
+              if (aret != -1)
2de9cec
+                xheader_xattr_add (st, attr, val, aret);
2de9cec
+              else if (errno != ENOATTR)
6a0e236
+                call_arg_warn ((fd==-1) ? "lgetxattr" : "fgetxattr", file_name);
2de9cec
+              
2de9cec
+             next_attr:
2de9cec
+              attr += len + 1;
2de9cec
+              xret -= len + 1;
2de9cec
+            }
2de9cec
+        }
2de9cec
+#endif
2de9cec
+    }
Radek Brich fc86677
+}
Radek Brich fc86677
+
2de9cec
+static void xattrs__fd_set(struct tar_stat_info const *st,
2de9cec
+                           char const *file_name, char typeflag,
2de9cec
+                           const char *attr,
2de9cec
+                           const char *ptr, size_t len)
Radek Brich fc86677
+{
2de9cec
+#ifdef HAVE_XATTRS
2de9cec
+  if (ptr)
Radek Brich fc86677
+    {
2de9cec
+      const char *sysname = "setxattr";
2de9cec
+      int ret = -1;
Radek Brich fc86677
+
2de9cec
+      if (typeflag != SYMTYPE)
2de9cec
+        ret = setxattr (file_name, attr, ptr, len, 0);
2de9cec
+      else
2de9cec
+        {
2de9cec
+          sysname = "lsetxattr";
2de9cec
+          ret = lsetxattr (file_name, attr, ptr, len, 0);
2de9cec
+        }
Radek Brich fc86677
+
2de9cec
+      /* do not print warnings when SELinux is disabled */
2de9cec
+      if ((ret == -1) && (errno != EPERM) && (errno != ENOTSUP))
2de9cec
+        call_arg_error(sysname, file_name);
2de9cec
+    }
2de9cec
+#endif
Radek Brich fc86677
+}
Radek Brich fc86677
+
2de9cec
+/* convert unix permissions into an ACL ... needed due to "default" ACLs */
2de9cec
+#ifdef HAVE_LIBACL
2de9cec
+static acl_t perms2acl(int perms)
Radek Brich fc86677
+{
2de9cec
+  char val[] = "user::---,group::---,other::---";
2de9cec
+  /*            0123456789 123456789 123456789 123456789 */
Radek Brich fc86677
+
2de9cec
+   /* user */
2de9cec
+  if (perms & 0400) val[ 6] = 'r';
2de9cec
+  if (perms & 0200) val[ 7] = 'w';
2de9cec
+  if (perms & 0100) val[ 8] = 'x';
Radek Brich fc86677
+
2de9cec
+  /* group */
2de9cec
+  if (perms & 0040) val[17] = 'r';
2de9cec
+  if (perms & 0020) val[18] = 'w';
2de9cec
+  if (perms & 0010) val[19] = 'x';
Radek Brich fc86677
+
2de9cec
+  /* other */
2de9cec
+  if (perms & 0004) val[28] = 'r';
2de9cec
+  if (perms & 0002) val[29] = 'w';
2de9cec
+  if (perms & 0001) val[30] = 'x';
2de9cec
+  
2de9cec
+  return (acl_from_text (val));
Radek Brich fc86677
+}
2de9cec
+#endif
Radek Brich fc86677
+
2de9cec
+static char *skip_to_ext_fields(char *ptr)
Radek Brich fc86677
+{
2de9cec
+  ptr += strcspn(ptr, ":,\n"); /* skip tag name. Ie. user/group/default/mask */
Radek Brich fc86677
+
2de9cec
+  if (*ptr != ':')
2de9cec
+    return (ptr); /* error? no user/group field */
2de9cec
+  ++ptr;
2de9cec
+  
2de9cec
+  ptr += strcspn(ptr, ":,\n"); /* skip user/group name */
Radek Brich fc86677
+
2de9cec
+  if (*ptr != ':')
2de9cec
+    return (ptr); /* error? no perms field */
2de9cec
+  ++ptr;
2de9cec
+  
2de9cec
+  ptr += strcspn(ptr, ":,\n"); /* skip perms */
Radek Brich fc86677
+
2de9cec
+  if (*ptr != ':')
2de9cec
+    return (ptr); /* no extra fields */
Radek Brich fc86677
+
2de9cec
+  return (ptr);
2de9cec
+}
Radek Brich fc86677
+
2de9cec
+/* The POSIX draft allows extra fields after the three main ones. Star
2de9cec
+   uses this to add a fourth field for user/group which is the numeric ID.
2de9cec
+   We just skip all extra fields atm. */
2de9cec
+static const char *fixup_extra_acl_fields(const char *ptr)
2de9cec
+{
2de9cec
+  char *src = (char *)ptr;
2de9cec
+  char *dst = (char *)ptr;
Radek Brich fc86677
+
2de9cec
+  while (*src)
2de9cec
+  {
2de9cec
+    const char *old = src;
2de9cec
+    size_t len = 0;
Radek Brich fc86677
+
2de9cec
+    src = skip_to_ext_fields(src);
2de9cec
+    len = src - old;
2de9cec
+    if (old != dst) memmove(dst, old, len);
2de9cec
+    dst += len;
Radek Brich fc86677
+
2de9cec
+    if (*src == ':') /* We have extra fields, skip them all */
2de9cec
+      src += strcspn(src, "\n,");
2de9cec
+    
2de9cec
+    if ((*src == '\n') || (*src == ','))
2de9cec
+      *dst++ = *src++; /* also done when dst == src, but that's ok */
2de9cec
+  }
2de9cec
+  if (src != dst)
2de9cec
+    *dst = 0;
2de9cec
+  
2de9cec
+  return ptr;
2de9cec
+}
Radek Brich fc86677
+
2de9cec
+static void xattrs__acls_set(struct tar_stat_info const *st,
2de9cec
+                             char const *file_name, int type,
2de9cec
+                             const char *ptr, size_t len)
2de9cec
+{ /* "system.posix_acl_access" */
2de9cec
+#ifdef HAVE_LIBACL
2de9cec
+  acl_t acl;
2de9cec
+
2de9cec
+  if (ptr)
2de9cec
+    {
2de9cec
+      /* assert (strlen (ptr) == len); */
2de9cec
+      ptr = fixup_extra_acl_fields(ptr);
2de9cec
+      
2de9cec
+      acl = acl_from_text (ptr);
2de9cec
+      acls_option = 1;
2de9cec
+    }
2de9cec
+  else if (acls_option > 0)
2de9cec
+    acl = perms2acl (st->stat.st_mode);
2de9cec
+  else
2de9cec
+    return; /* don't call acl functions unless we first hit an ACL, or
2de9cec
+               --acls was passed explicitly */
Radek Brich fc86677
+  
2de9cec
+  if (acl == (acl_t)NULL)
2de9cec
+    {
2de9cec
+      call_arg_warn ("acl_from_text", file_name);
2de9cec
+      return;
2de9cec
+    }
Radek Brich fc86677
+  
2de9cec
+  if (acl_set_file (file_name, type, acl) == -1)
2de9cec
+    {
2de9cec
+      if (errno != ENOTSUP)
2de9cec
+        call_arg_warn ("acl_set_file", file_name);
2de9cec
+    }
2de9cec
+  acl_free (acl);
2de9cec
+#endif
2de9cec
+}
Radek Brich fc86677
+
2de9cec
+void xattrs_acls_set(struct tar_stat_info const *st,
2de9cec
+                     char const *file_name, char typeflag)
2de9cec
+{
2de9cec
+  if ((acls_option >= 0) && (typeflag != SYMTYPE))
2de9cec
+    {
2de9cec
+#ifndef HAVE_LIBACL
2de9cec
+      static int done = 0;
2de9cec
+      if (!done)
2de9cec
+        WARN ((0, 0, _("ACL support requested, but not available")));
2de9cec
+      done = 1;
2de9cec
+#else
2de9cec
+      xattrs__acls_set (st, file_name, ACL_TYPE_ACCESS,
2de9cec
+                        st->acls_a_ptr, st->acls_a_len);
f6da44a
+      if ((typeflag == DIRTYPE) || (typeflag == GNUTYPE_DUMPDIR))
2de9cec
+        xattrs__acls_set (st, file_name, ACL_TYPE_DEFAULT,
2de9cec
+                          st->acls_d_ptr, st->acls_d_len);
2de9cec
+#endif
2de9cec
+    }
2de9cec
+}
2de9cec
+
2de9cec
+void xattrs_selinux_set(struct tar_stat_info const *st,
2de9cec
+                        char const *file_name, char typeflag)
2de9cec
+{
2de9cec
+  if ((selinux_context_option >= 0) && st->cntx_name)
Radek Brich fc86677
+    {
2de9cec
+      const char *sysname = "setfilecon";
2de9cec
+      int ret = -1;
2de9cec
+
2de9cec
+#ifndef HAVE_LIBSELINUX
2de9cec
+      static int done = 0;
2de9cec
+      if (!done)
2de9cec
+          WARN ((0, 0, _("SELinux support requested, but not available")));
2de9cec
+      done = 1;
2de9cec
+#else
2de9cec
+      if (typeflag != SYMTYPE)
2de9cec
+        ret = setfilecon (file_name, st->cntx_name);
2de9cec
+      else
Radek Brich fc86677
+        {
2de9cec
+          sysname = "lsetfilecon";
2de9cec
+          ret = lsetfilecon (file_name, st->cntx_name);
Radek Brich fc86677
+        }
2de9cec
+
2de9cec
+      if ((ret == -1) && (errno == EPERM))
2de9cec
+        call_arg_warn(sysname, file_name);
2de9cec
+      else if ((ret == -1) && (errno != EOPNOTSUPP))
2de9cec
+        call_arg_error(sysname, file_name);
2de9cec
+#endif
2de9cec
+    }
2de9cec
+}
2de9cec
+
2de9cec
+void xattrs_xattrs_set(struct tar_stat_info const *st,
2de9cec
+                       char const *file_name, char typeflag)
2de9cec
+{
2de9cec
+  if ((xattrs_option >= 0) && st->xattr_map_size)
2de9cec
+    {
2de9cec
+      size_t scan = 0;
2de9cec
+
2de9cec
+#ifndef HAVE_XATTRS
2de9cec
+      static int done = 0;
2de9cec
+      if (!done)
2de9cec
+          WARN ((0, 0, _("Xattr support requested, but not available")));
2de9cec
+      done = 1;
2de9cec
+#else
2de9cec
+      while (scan < st->xattr_map_size)
Radek Brich fc86677
+        {
2de9cec
+          char *keyword = st->xattr_map[scan].xkey;
2de9cec
+
2de9cec
+          /* assert (!memcpy (keyword, "SCHILY.xattr.", strlen("SCHILY.xattr."))); */
2de9cec
+          keyword += strlen("SCHILY.xattr.");
2de9cec
+
2de9cec
+          if (strncmp (keyword, "user.", strlen("user.")) &&
2de9cec
+              strncmp (keyword, "trusted.", strlen("trusted.")))
2de9cec
+            continue; /* don't try and set anything but normal xattrs */
2de9cec
+            
2de9cec
+          /* should we ignore trusted.* EPERM errors when not root ? */
2de9cec
+          xattrs__fd_set (st, file_name, typeflag, keyword,
2de9cec
+                          st->xattr_map[scan].xval_ptr,
2de9cec
+                          st->xattr_map[scan].xval_len);
2de9cec
+      
2de9cec
+          ++scan;
Radek Brich fc86677
+        }
2de9cec
+#endif
Radek Brich fc86677
+    }
2de9cec
+}
6a0e236
diff -urNp tar-1.22-orig/src/xattrs.h tar-1.22/src/xattrs.h
6a0e236
--- tar-1.22-orig/src/xattrs.h	1970-01-01 01:00:00.000000000 +0100
6a0e236
+++ tar-1.22/src/xattrs.h	2009-11-23 14:48:00.000000000 +0100
Radek Brich fc86677
@@ -0,0 +1,14 @@
Radek Brich fc86677
+
Radek Brich fc86677
+extern void xattrs_acls_get(struct tar_stat_info *st,
Radek Brich fc86677
+                            char const *file_name, int fd, int xisfile);
Radek Brich fc86677
+extern void xattrs_selinux_get(struct tar_stat_info *st,
Radek Brich fc86677
+                               char const *file_name, int fd);
Radek Brich fc86677
+extern void xattrs_xattrs_get(struct tar_stat_info *st,
Radek Brich fc86677
+                              char const *file_name, int fd);
Radek Brich fc86677
+
Radek Brich fc86677
+extern void xattrs_acls_set(struct tar_stat_info const *st,
Radek Brich fc86677
+                            char const *file_name, char typeflag);
Radek Brich fc86677
+extern void xattrs_selinux_set(struct tar_stat_info const *st,
Radek Brich fc86677
+                               char const *file_name, char typeflag);
Radek Brich fc86677
+extern void xattrs_xattrs_set(struct tar_stat_info const *st,
Radek Brich fc86677
+                              char const *file_name, char typeflag);
6a0e236
diff -urNp tar-1.22-orig/src/xheader.c tar-1.22/src/xheader.c
6a0e236
--- tar-1.22-orig/src/xheader.c	2008-11-30 13:30:54.000000000 +0100
6a0e236
+++ tar-1.22/src/xheader.c	2009-11-23 14:48:00.000000000 +0100
6a0e236
@@ -417,6 +417,74 @@ xheader_write_global (struct xheader *xh
6a0e236
   free (name);
6a0e236
 }
6a0e236
 
6a0e236
+void xheader_xattr_init(struct tar_stat_info *st)
6a0e236
+{
6a0e236
+  st->xattr_map = NULL;
6a0e236
+  st->xattr_map_size = 0;
6a0e236
+}
6a0e236
+
6a0e236
+void xheader_xattr_free(struct xattr_array *xattr_map, size_t xattr_map_size)
6a0e236
+{
6a0e236
+  size_t scan = 0;
6a0e236
+
6a0e236
+  while (scan < xattr_map_size)
6a0e236
+    {
6a0e236
+      free (xattr_map[scan].xkey);
6a0e236
+      free (xattr_map[scan].xval_ptr);
6a0e236
+
6a0e236
+      ++scan;
6a0e236
+    }
6a0e236
+  free (xattr_map);
6a0e236
+}
6a0e236
+
6a0e236
+static void xheader_xattr__add(struct xattr_array **xattr_map,
6a0e236
+                               size_t *xattr_map_size,
6a0e236
+                               const char *key, const char *val, size_t len)
6a0e236
+{
6a0e236
+  size_t pos = (*xattr_map_size)++;
6a0e236
+  
6a0e236
+  *xattr_map = xrealloc (*xattr_map,
6a0e236
+                         *xattr_map_size * sizeof(struct xattr_array));
6a0e236
+  (*xattr_map)[pos].xkey = xstrdup (key);
6a0e236
+  (*xattr_map)[pos].xval_ptr = xmemdup (val, len + 1);
6a0e236
+  (*xattr_map)[pos].xval_len = len;
6a0e236
+}
6a0e236
+
6a0e236
+void xheader_xattr_add(struct tar_stat_info *st,
6a0e236
+                       const char *key, const char *val, size_t len)
6a0e236
+{
6a0e236
+  size_t klen = strlen (key);
6a0e236
+  char *xkey = xmalloc (strlen("SCHILY.xattr.") + klen + 1);
6a0e236
+  char *tmp = xkey;
6a0e236
+
6a0e236
+  tmp = stpcpy (tmp, "SCHILY.xattr.");
6a0e236
+  tmp = stpcpy (tmp, key);
6a0e236
+  
6a0e236
+  xheader_xattr__add (&st->xattr_map, &st->xattr_map_size, xkey, val, len);
6a0e236
+
6a0e236
+  free (xkey);
6a0e236
+}
6a0e236
+
6a0e236
+void xheader_xattr_copy(const struct tar_stat_info *st,
6a0e236
+                        struct xattr_array **xattr_map, size_t *xattr_map_size)
6a0e236
+{
6a0e236
+  size_t scan = 0;
6a0e236
+
6a0e236
+  *xattr_map = NULL;
6a0e236
+  *xattr_map_size = 0;
6a0e236
+  
6a0e236
+  while (scan < st->xattr_map_size)
6a0e236
+    {
6a0e236
+      char  *key = st->xattr_map[scan].xkey;
6a0e236
+      char  *val = st->xattr_map[scan].xval_ptr;
6a0e236
+      size_t len = st->xattr_map[scan].xval_len;
6a0e236
+      
6a0e236
+      xheader_xattr__add(xattr_map, xattr_map_size, key, val, len);
6a0e236
+
6a0e236
+      ++scan;
6a0e236
+    }
6a0e236
+}
6a0e236
+
6a0e236
 
6a0e236
 /* General Interface */
6a0e236
 
6a0e236
@@ -427,6 +495,7 @@ struct xhdr_tab
6a0e236
 		 struct xheader *, void const *data);
6a0e236
   void (*decoder) (struct tar_stat_info *, char const *, char const *, size_t);
6a0e236
   bool protect;
6a0e236
+  bool prefix;
6a0e236
 };
6a0e236
 
6a0e236
 /* This declaration must be extern, because ISO C99 section 6.9.2
6a0e236
@@ -443,8 +512,17 @@ locate_handler (char const *keyword)
6a0e236
   struct xhdr_tab const *p;
6a0e236
 
6a0e236
   for (p = xhdr_tab; p->keyword; p++)
6a0e236
-    if (strcmp (p->keyword, keyword) == 0)
6a0e236
-      return p;
6a0e236
+    if (p->prefix)
6a0e236
+      {
6a0e236
+        if (strncmp (p->keyword, keyword, strlen(p->keyword)) == 0)
6a0e236
+          return p;
6a0e236
+      }
6a0e236
+  else
6a0e236
+      {
6a0e236
+        if (strcmp (p->keyword, keyword) == 0)
6a0e236
+          return p;
6a0e236
+      }
6a0e236
+  
6a0e236
   return NULL;
6a0e236
 }
6a0e236
 
6a0e236
@@ -454,7 +532,7 @@ xheader_protected_pattern_p (const char 
6a0e236
   struct xhdr_tab const *p;
6a0e236
 
6a0e236
   for (p = xhdr_tab; p->keyword; p++)
6a0e236
-    if (p->protect && fnmatch (pattern, p->keyword, 0) == 0)
6a0e236
+    if (!p->prefix && p->protect && fnmatch (pattern, p->keyword, 0) == 0)
6a0e236
       return true;
6a0e236
   return false;
6a0e236
 }
6a0e236
@@ -465,7 +543,7 @@ xheader_protected_keyword_p (const char 
6a0e236
   struct xhdr_tab const *p;
6a0e236
 
6a0e236
   for (p = xhdr_tab; p->keyword; p++)
6a0e236
-    if (p->protect && strcmp (p->keyword, keyword) == 0)
6a0e236
+    if (!p->prefix && p->protect && strcmp (p->keyword, keyword) == 0)
6a0e236
       return true;
6a0e236
   return false;
6a0e236
 }
6a0e236
@@ -1417,6 +1495,71 @@ volume_filename_decoder (struct tar_stat
6a0e236
 }
6a0e236
 
6a0e236
 static void
6a0e236
+xattr_selinux_coder (struct tar_stat_info const *st, char const *keyword,
6a0e236
+                     struct xheader *xhdr, void const *data)
6a0e236
+{
6a0e236
+  code_string (st->cntx_name, keyword, xhdr);
6a0e236
+}
6a0e236
+
6a0e236
+static void
6a0e236
+xattr_selinux_decoder (struct tar_stat_info *st,
6a0e236
+                       char const *keyword, char const *arg, size_t size)
6a0e236
+{
6a0e236
+  decode_string (&st->cntx_name, arg);
6a0e236
+}
6a0e236
+
6a0e236
+static void
6a0e236
+xattr_acls_a_coder (struct tar_stat_info const *st , char const *keyword,
6a0e236
+                    struct xheader *xhdr, void const *data)
6a0e236
+{
6a0e236
+  xheader_print_n (xhdr, keyword, st->acls_a_ptr, st->acls_a_len);
6a0e236
+}
6a0e236
+
6a0e236
+static void
6a0e236
+xattr_acls_a_decoder (struct tar_stat_info *st,
6a0e236
+                      char const *keyword, char const *arg, size_t size)
6a0e236
+{
6a0e236
+  st->acls_a_ptr = xmemdup (arg, size + 1);
6a0e236
+  st->acls_a_len = size;
6a0e236
+}
6a0e236
+
6a0e236
+static void
6a0e236
+xattr_acls_d_coder (struct tar_stat_info const *st , char const *keyword,
6a0e236
+                    struct xheader *xhdr, void const *data)
6a0e236
+{
6a0e236
+  xheader_print_n (xhdr, keyword, st->acls_d_ptr, st->acls_d_len);
6a0e236
+}
6a0e236
+
6a0e236
+static void
6a0e236
+xattr_acls_d_decoder (struct tar_stat_info *st,
6a0e236
+                      char const *keyword, char const *arg, size_t size)
6a0e236
+{
6a0e236
+  st->acls_d_ptr = xmemdup (arg, size + 1);
6a0e236
+  st->acls_d_len = size;
6a0e236
+}
6a0e236
+
6a0e236
+static void
6a0e236
+xattr_coder (struct tar_stat_info const *st , char const *keyword,
6a0e236
+             struct xheader *xhdr, void const *data)
6a0e236
+{
6a0e236
+  struct xattr_array *xattr_map = st->xattr_map;
6a0e236
+  const size_t *off = data;
6a0e236
+  xheader_print_n (xhdr, keyword,
6a0e236
+                   xattr_map[*off].xval_ptr, xattr_map[*off].xval_len);
6a0e236
+}
6a0e236
+
6a0e236
+static void
6a0e236
+xattr_decoder (struct tar_stat_info *st,
6a0e236
+               char const *keyword, char const *arg, size_t size)
6a0e236
+{
6a0e236
+  char *xstr = NULL;
6a0e236
+
6a0e236
+  xstr = xmemdup(arg, size + 1);
6a0e236
+  xheader_xattr_add(st, keyword + strlen("SCHILY.xattr."), xstr, size);
6a0e236
+  free(xstr);
6a0e236
+}
6a0e236
+
6a0e236
+static void
6a0e236
 sparse_major_coder (struct tar_stat_info const *st, char const *keyword,
6a0e236
 		    struct xheader *xhdr, void const *data)
6a0e236
 {
6a0e236
@@ -1453,18 +1596,18 @@ sparse_minor_decoder (struct tar_stat_in
6a0e236
 }
6a0e236
 
6a0e236
 struct xhdr_tab const xhdr_tab[] = {
6a0e236
-  { "atime",	atime_coder,	atime_decoder,	  false },
6a0e236
-  { "comment",	dummy_coder,	dummy_decoder,	  false },
6a0e236
-  { "charset",	dummy_coder,	dummy_decoder,	  false },
6a0e236
-  { "ctime",	ctime_coder,	ctime_decoder,	  false },
6a0e236
-  { "gid",	gid_coder,	gid_decoder,	  false },
6a0e236
-  { "gname",	gname_coder,	gname_decoder,	  false },
6a0e236
-  { "linkpath", linkpath_coder, linkpath_decoder, false },
6a0e236
-  { "mtime",	mtime_coder,	mtime_decoder,	  false },
6a0e236
-  { "path",	path_coder,	path_decoder,	  false },
6a0e236
-  { "size",	size_coder,	size_decoder,	  false },
6a0e236
-  { "uid",	uid_coder,	uid_decoder,	  false },
6a0e236
-  { "uname",	uname_coder,	uname_decoder,	  false },
6a0e236
+  { "atime",   atime_coder,    atime_decoder,    false, false },
6a0e236
+  { "comment", dummy_coder,    dummy_decoder,    false, false },
6a0e236
+  { "charset", dummy_coder,    dummy_decoder,    false, false },
6a0e236
+  { "ctime",   ctime_coder,    ctime_decoder,    false, false },
6a0e236
+  { "gid",     gid_coder,      gid_decoder,      false, false },
6a0e236
+  { "gname",   gname_coder,    gname_decoder,    false, false },
6a0e236
+  { "linkpath", linkpath_coder, linkpath_decoder, false, false },
6a0e236
+  { "mtime",   mtime_coder,    mtime_decoder,    false, false },
6a0e236
+  { "path",    path_coder,     path_decoder,     false, false },
6a0e236
+  { "size",    size_coder,     size_decoder,     false, false },
6a0e236
+  { "uid",     uid_coder,      uid_decoder,      false, false },
6a0e236
+  { "uname",   uname_coder,    uname_decoder,    false, false },
6a0e236
 
6a0e236
   /* Sparse file handling */
6a0e236
   { "GNU.sparse.name",       path_coder, path_decoder,
6a0e236
@@ -1479,25 +1622,25 @@ struct xhdr_tab const xhdr_tab[] = {
6a0e236
     true },
6a0e236
 
6a0e236
   /* tar 1.14 - 1.15.90 keywords. */
6a0e236
-  { "GNU.sparse.size",       sparse_size_coder, sparse_size_decoder, true },
6a0e236
+  { "GNU.sparse.size",       sparse_size_coder, sparse_size_decoder, true, false },
6a0e236
   /* tar 1.14 - 1.15.1 keywords. Multiple instances of these appeared in 'x'
6a0e236
      headers, and each of them was meaningful. It confilcted with POSIX specs,
6a0e236
      which requires that "when extended header records conflict, the last one
6a0e236
      given in the header shall take precedence." */
6a0e236
   { "GNU.sparse.offset",     sparse_offset_coder, sparse_offset_decoder,
6a0e236
-    true },
6a0e236
+    true, false },
6a0e236
   { "GNU.sparse.numbytes",   sparse_numbytes_coder, sparse_numbytes_decoder,
6a0e236
-    true },
6a0e236
+    true, false },
6a0e236
   /* tar 1.15.90 keyword, introduced to remove the above-mentioned conflict. */
6a0e236
   { "GNU.sparse.map",        NULL /* Unused, see pax_dump_header() */,
6a0e236
-    sparse_map_decoder, false },
6a0e236
+    sparse_map_decoder, false, false },
6a0e236
 
6a0e236
   { "GNU.dumpdir",           dumpdir_coder, dumpdir_decoder,
6a0e236
-    true },
6a0e236
+    true, false },
6a0e236
 
6a0e236
   /* Keeps the tape/volume label. May be present only in the global headers.
6a0e236
      Equivalent to GNUTYPE_VOLHDR.  */
6a0e236
-  { "GNU.volume.label", volume_label_coder, volume_label_decoder, true },
6a0e236
+  { "GNU.volume.label", volume_label_coder, volume_label_decoder, true, false },
6a0e236
 
6a0e236
   /* These may be present in a first global header of the archive.
6a0e236
      They provide the same functionality as GNUTYPE_MULTIVOL header.
6a0e236
@@ -1506,9 +1649,38 @@ struct xhdr_tab const xhdr_tab[] = {
6a0e236
      GNU.volume.offset keeps the offset of the start of this volume,
6a0e236
      otherwise kept in oldgnu_header.offset.  */
6a0e236
   { "GNU.volume.filename", volume_label_coder, volume_filename_decoder,
6a0e236
-    true },
6a0e236
-  { "GNU.volume.size", volume_size_coder, volume_size_decoder, true },
6a0e236
-  { "GNU.volume.offset", volume_offset_coder, volume_offset_decoder, true },
6a0e236
-
6a0e236
+    true, false },
6a0e236
+  { "GNU.volume.size", volume_size_coder, volume_size_decoder, true, false },
6a0e236
+  { "GNU.volume.offset", volume_offset_coder, volume_offset_decoder,
6a0e236
+    true, false },
6a0e236
+
6a0e236
+  /* We get the SELinux value from filecon, so add a namespace for SELinux
6a0e236
+     instead of storing it in SCHILY.xattr.* (which would be RAW). */
6a0e236
+  { "RHT.security.selinux",
6a0e236
+    xattr_selinux_coder, xattr_selinux_decoder, false, false },
6a0e236
+
6a0e236
+  /* ACLs, use the star format... */
6a0e236
+  { "SCHILY.acl.access",
6a0e236
+    xattr_acls_a_coder, xattr_acls_a_decoder, false, false },
6a0e236
+
6a0e236
+  { "SCHILY.acl.default",
6a0e236
+    xattr_acls_d_coder, xattr_acls_d_decoder, false, false },
6a0e236
+
6a0e236
+  /* FIXME: These are compat. for FC-6 ... we shipped a tar using the generic
6a0e236
+     header names by accident. */
6a0e236
+  { "SCHILY.xattr.security.selinux",
6a0e236
+    xattr_selinux_coder, xattr_selinux_decoder, false, false },
6a0e236
+  { "SCHILY.xattr.system.posix_acl_access",
6a0e236
+    xattr_acls_a_coder, xattr_acls_a_decoder, false, false },
6a0e236
+  { "SCHILY.xattr.system.posix_acl_default",
6a0e236
+    xattr_acls_d_coder, xattr_acls_d_decoder, false, false },
6a0e236
+
6a0e236
+  /* xattr's, use the star format note we only save the user/trusted varients... */
6a0e236
+  { "SCHILY.xattr.user",    xattr_coder, xattr_decoder, false, true },
6a0e236
+  { "SCHILY.xattr.trusted", xattr_coder, xattr_decoder, false, true },
6a0e236
+
6a0e236
+  /* ignore everything else in the xattr namespaces... */
6a0e236
+  { "SCHILY.xattr",         dummy_coder, dummy_decoder, false, true },
6a0e236
+  
6a0e236
   { NULL, NULL, NULL, false }
6a0e236
 };