diff -rup tar-1.15.90-orig/configure.ac tar-1.15.90/configure.ac
--- tar-1.15.90-orig/configure.ac	2006-02-19 14:29:18.000000000 -0500
+++ tar-1.15.90/configure.ac	2006-08-28 02:59:01.000000000 -0400
@@ -89,6 +89,11 @@ tar_GNULIB
 tar_PAXUTILS
 
 AC_CHECK_FUNCS(fsync lstat mkfifo readlink strerror symlink setlocale utimes)
+AC_CHECK_FUNCS(getxattr  fgetxattr  lgetxattr \
+               setxattr  fsetxattr  lsetxattr \
+               listxattr flistxattr llistxattr,
+               AC_DEFINE(HAVE_XATTRS,,[Define if we have a working extended attributes]),)
+AC_CHECK_LIB(selinux, getfilecon)
 AC_CHECK_DECLS([getgrgid],,, [#include <grp.h>])
 AC_CHECK_DECLS([getpwuid],,, [#include <pwd.h>])
 AC_CHECK_DECLS([time],,, [#include <time.h>])
@@ -204,6 +209,8 @@ AC_DEFINE_UNQUOTED(DEFAULT_QUOTING_STYLE
 # Iconv
 AM_ICONV
 AC_CHECK_HEADERS(iconv.h)
+AC_CHECK_HEADERS(selinux/selinux.h)
+AC_CHECK_HEADERS(attr/xattr.h)
 AC_CHECK_TYPE(iconv_t,:,
               AC_DEFINE(iconv_t, int,
                         [Conversion descriptor type]),
Only in tar-1.15.90/: configure.ac.incompatibility
diff -rup tar-1.15.90-orig/doc/tar.texi tar-1.15.90/doc/tar.texi
--- tar-1.15.90-orig/doc/tar.texi	2006-02-19 14:29:18.000000000 -0500
+++ tar-1.15.90/doc/tar.texi	2006-08-28 03:06:32.000000000 -0400
@@ -6929,6 +6929,8 @@ implementation able to read @samp{ustar}
 most @samp{posix} archives as well, with the only exception that any
 additional information (such as long file names etc.) will in such
 case be extracted as plain text files along with the files it refers to.
+This is the only format that can store ACLs, SELinux context and extended
+attributes.
 
 This archive format will be the default format for future versions
 of @GNUTAR{}.
@@ -7620,6 +7622,53 @@ It is equivalent to @option{--same-permi
 
 @FIXME{I do not see the purpose of such an option.  (Neither I.  FP.)}
 
+@opindex acls
+@item --acls
+This option causes @command{tar} to store each file's ACLs in the archive.
+
+The @option{--acls} option has no equivalent short option name.
+@FIXME{This does not currently store/get the default ACL for directories}
+
+@opindex selinux
+@item --selinux
+This option causes @command{tar} to store each file's SELinux security context
+information in the archive.
+
+The @option{--selinux} option has no equivalent short option name.
+
+@opindex xattrs
+@item --xattrs
+This option causes @command{tar} to store each file's extended attributes in
+the archive. This option also enables @option{--acls} and @option{--selinux} if
+they haven't been set already, due to the fact that the data for those are
+stored in special xattrs.
+
+The @option{--xattrs} option has no equivalent short option name.
+
+@opindex no-acls
+@item --no-acls
+This option causes @command{tar} not to store each file's ACLs in the archive
+and not to extract any ACL information in an archive.
+
+The @option{--acls} option has no equivalent short option name.
+
+@opindex no-selinux
+@item --no-selinux
+This option causes @command{tar} not to store each file's SELinux security
+context information in the archive and not to extract any SELinux information in
+an archive.
+
+The @option{--selinux} option has no equivalent short option name.
+
+@opindex no-xattrs
+@item --no-xattrs
+This option causes @command{tar} not to store each file's extended attributes in
+the archive and not to extract any extended attributes in an archive. This
+option also enables @option{--acls} and @option{--selinux} if
+they haven't been set already.
+
+The @option{--xattrs} option has no equivalent short option name.
+
 @end table
 
 @node Standard
Only in tar-1.15.90/doc: tar.texi~
Only in tar-1.15.90/doc: tar.texi.incompatibility
diff -rup tar-1.15.90-orig/src/common.h tar-1.15.90/src/common.h
--- tar-1.15.90-orig/src/common.h	2006-02-19 14:29:18.000000000 -0500
+++ tar-1.15.90/src/common.h	2006-08-28 02:59:01.000000000 -0400
@@ -232,6 +232,15 @@ GLOBAL int same_owner_option;
 /* If positive, preserve permissions when extracting.  */
 GLOBAL int same_permissions_option;
 
+/* If positive, save the SELinux context.  */
+GLOBAL int selinux_context_option;
+
+/* If positive, save the ACLs.  */
+GLOBAL int acls_option;
+
+/* If positive, save the user and root xattrs.  */
+GLOBAL int xattrs_option;
+
 /* When set, strip the given number of file name components from the file name
    before extracting */
 GLOBAL size_t strip_name_components;
@@ -637,6 +646,9 @@ extern char *output_start;
 
 void update_archive (void);
 
+/* Module attrs.c.  */
+#include "xattrs.h"
+
 /* Module xheader.c.  */
 
 void xheader_decode (struct tar_stat_info *);
@@ -658,6 +670,12 @@ void xheader_string_end (char const *key
 bool xheader_keyword_deleted_p (const char *kw);
 char *xheader_format_name (struct tar_stat_info *st, const char *fmt,
 			   size_t n);
+void xheader_xattr_init(struct tar_stat_info *st);
+void xheader_xattr_free(struct xattr_array *vals, size_t sz);
+void xheader_xattr_copy(const struct tar_stat_info *st,
+                        struct xattr_array **vals, size_t *sz);
+void xheader_xattr_add(struct tar_stat_info *st,
+                       const char *key, const char *val, size_t len);
 
 /* Module system.c */
 
Only in tar-1.15.90/src: common.h.incompatibility
diff -rup tar-1.15.90-orig/src/create.c tar-1.15.90/src/create.c
--- tar-1.15.90-orig/src/create.c	2006-07-27 15:04:48.000000000 -0400
+++ tar-1.15.90/src/create.c	2006-08-28 02:59:01.000000000 -0400
@@ -24,6 +24,7 @@
 #include <quotearg.h>
 
 #include "common.h"
+
 #include <hash.h>
 
 struct link
@@ -833,6 +834,25 @@ start_header (struct tar_stat_info *st)
       GNAME_TO_CHARS (st->gname, header->header.gname);
     }
 
+  if (archive_format == POSIX_FORMAT)
+    {
+      if (acls_option > 0)
+        xheader_store ("SCHILY.xattr.system.posix_acl_access", st, NULL);
+      if (selinux_context_option > 0)
+        xheader_store ("SCHILY.xattr.security.selinux", st, NULL);
+      if (xattrs_option > 0)
+        {
+          size_t scan_xattr = 0;
+          struct xattr_array *xattr_map = st->xattr_map;
+          
+          while (scan_xattr < st->xattr_map_size)
+            {
+              xheader_store (xattr_map[scan_xattr].xkey, st, &scan_xattr);
+              ++scan_xattr;
+            }
+        }
+    }
+
   return header;
 }
 
@@ -1484,6 +1504,10 @@ dump_file0 (struct tar_stat_info *st, ch
 		open_diag (p);
 	      return;
 	    }
+
+          xattrs_acls_get(st, p, fd);
+          xattrs_selinux_get(st, p, fd);
+          xattrs_xattrs_get(st, p, fd);
 	}
 
       if (is_dir)
Only in tar-1.15.90/src: create.c.incompatibility
diff -rup tar-1.15.90-orig/src/extract.c tar-1.15.90/src/extract.c
--- tar-1.15.90-orig/src/extract.c	2006-07-27 15:04:48.000000000 -0400
+++ tar-1.15.90/src/extract.c	2006-08-28 02:59:01.000000000 -0400
@@ -68,6 +68,11 @@ struct delayed_set_stat
     mode_t invert_permissions;
     enum permstatus permstatus;
     bool after_links;
+    char *cntx_name;
+    char *acls_ptr;
+    size_t acls_len;
+    size_t xattr_map_size;   /* Size of the xattr map */
+    struct xattr_array *xattr_map;
     char file_name[1];
   };
 
@@ -95,6 +100,16 @@ struct delayed_link
        hard-linked together.  */
     struct string_list *sources;
 
+    /* SELinux context */
+    char *cntx_name;
+   
+    /* ACLs */
+    char *acls_ptr;
+    size_t acls_len;
+   
+    size_t xattr_map_size;   /* Size of the xattr map */
+    struct xattr_array *xattr_map;
+   
     /* The desired target of the desired link.  */
     char target[1];
   };
@@ -272,6 +287,10 @@ set_stat (char const *file_name,
 		invert_permissions, permstatus, typeflag);
     }
 
+  xattrs_acls_set(st, file_name, typeflag);
+  xattrs_selinux_set(st, file_name, typeflag);
+  xattrs_xattrs_set(st, file_name, typeflag);
+
   if (0 < same_owner_option && permstatus != INTERDIR_PERMSTATUS)
     {
       /* When lchown exists, it should be used to change the attributes of
@@ -341,6 +360,16 @@ delay_set_stat (char const *file_name, s
   data->invert_permissions = invert_permissions;
   data->permstatus = permstatus;
   data->after_links = 0;
+  data->cntx_name = NULL;
+  assign_string (&data->cntx_name, st->cntx_name);
+  if (st->acls_ptr)
+    data->acls_ptr = xmemdup(st->acls_ptr, st->acls_len);
+  else
+    {
+      data->acls_ptr = NULL;
+      data->acls_len = 0;
+    }
+  xheader_xattr_copy (st, &data->xattr_map, &data->xattr_map_size);
   strcpy (data->file_name, file_name);
   delayed_set_stat_head = data;
 }
@@ -588,11 +617,19 @@ apply_nonancestor_delayed_set_stat (char
 	  st.stat.st_gid = data->gid;
 	  st.atime = data->atime;
 	  st.mtime = data->mtime;
+          st.cntx_name = data->cntx_name;
+          st.acls_ptr = data->acls_ptr;
+          st.acls_len = data->acls_len;
+          st.xattr_map = data->xattr_map;
+          st.xattr_map_size = data->xattr_map_size;
 	  set_stat (data->file_name, &st, cur_info,
 		    data->invert_permissions, data->permstatus, DIRTYPE);
 	}
 
       delayed_set_stat_head = data->next;
+      xheader_xattr_free (data->xattr_map, data->xattr_map_size);
+      free (data->cntx_name);
+      free (data->acls_ptr);
       free (data);
     }
 }
@@ -866,6 +903,11 @@ create_placeholder_file (char *file_name
 			    + strlen (file_name) + 1);
       p->sources->next = 0;
       strcpy (p->sources->string, file_name);
+      p->cntx_name = NULL;
+      p->acls_ptr = NULL;
+      p->acls_len = 0;
+      p->xattr_map = NULL;
+      p->xattr_map_size = 0;
       strcpy (p->target, current_stat_info.link_name);
 
       h = delayed_set_stat_head;
@@ -1284,6 +1326,11 @@ apply_delayed_links (void)
 		  struct tar_stat_info st1;
 		  st1.stat.st_uid = ds->uid;
 		  st1.stat.st_gid = ds->gid;
+                  st1.cntx_name = ds->cntx_name;
+                  st1.acls_ptr = ds->acls_ptr;
+                  st1.acls_len = ds->acls_len;
+                  st1.xattr_map = ds->xattr_map;
+                  st1.xattr_map_size = ds->xattr_map_size;
 		  set_stat (source, &st1, NULL, 0, 0, SYMTYPE);
 		  valid_source = source;
 		}
Only in tar-1.15.90/src: extract.c.incompatibility
diff -rup tar-1.15.90-orig/src/list.c tar-1.15.90/src/list.c
--- tar-1.15.90-orig/src/list.c	2006-07-27 15:04:48.000000000 -0400
+++ tar-1.15.90/src/list.c	2006-08-28 02:59:01.000000000 -0400
@@ -519,6 +519,11 @@ decode_header (union block *header, stru
   assign_string (&stat_info->gname,
 		 header->header.gname[0] ? header->header.gname : NULL);
 
+  stat_info->acls_ptr = NULL;
+  stat_info->acls_len = 0;
+  stat_info->cntx_name = NULL;
+  xheader_xattr_init(stat_info);
+  
   if (format == OLDGNU_FORMAT && incremental_option)
     {
       stat_info->atime.tv_sec = TIME_FROM_HEADER (header->oldgnu_header.atime);
Only in tar-1.15.90/src: list.c.incompatibility
diff -rup tar-1.15.90-orig/src/Makefile.am tar-1.15.90/src/Makefile.am
--- tar-1.15.90-orig/src/Makefile.am	2005-05-18 08:23:49.000000000 -0400
+++ tar-1.15.90/src/Makefile.am	2006-08-28 02:59:01.000000000 -0400
@@ -20,7 +20,7 @@
 
 bin_PROGRAMS = tar
 
-noinst_HEADERS = arith.h common.h tar.h
+noinst_HEADERS = arith.h common.h tar.h xattrs.h
 tar_SOURCES = \
  buffer.c\
  compare.c\
@@ -37,7 +37,8 @@ tar_SOURCES = \
  system.c\
  tar.c\
  update.c\
- utf8.c
+ utf8.c\
+ xattrs.c
 
 INCLUDES = -I$(top_srcdir)/lib -I../ -I../lib 
 
@@ -45,4 +46,4 @@ tar.o: ../lib/localedir.h
 
 LDADD = ../lib/libtar.a $(LIBINTL) $(LIBICONV)
 
-tar_LDADD = $(LDADD) $(LIB_CLOCK_GETTIME)
+tar_LDADD = $(LIBS) $(LDADD) $(LIB_CLOCK_GETTIME)
Only in tar-1.15.90/src: Makefile.am.incompatibility
diff -rup tar-1.15.90-orig/src/Makefile.in tar-1.15.90/src/Makefile.in
--- tar-1.15.90-orig/src/Makefile.in	2006-02-19 15:44:43.000000000 -0500
+++ tar-1.15.90/src/Makefile.in	2006-08-28 02:59:01.000000000 -0400
@@ -285,7 +285,7 @@ tar_SOURCES = \
 
 INCLUDES = -I$(top_srcdir)/lib -I../ -I../lib 
 LDADD = ../lib/libtar.a $(LIBINTL) $(LIBICONV)
-tar_LDADD = $(LDADD) $(LIB_CLOCK_GETTIME)
+tar_LDADD = $(LDADD) $(LIB_CLOCK_GETTIME) -lselinux
 all: all-am
 
 .SUFFIXES:
Only in tar-1.15.90/src: Makefile.in.incompatibility
diff -rup tar-1.15.90-orig/src/tar.c tar-1.15.90/src/tar.c
--- tar-1.15.90-orig/src/tar.c	2006-02-19 14:29:18.000000000 -0500
+++ tar-1.15.90/src/tar.c	2006-08-28 02:59:01.000000000 -0400
@@ -244,7 +244,8 @@ tar_set_quoting_style (char *arg)
 
 enum
 {
-  ANCHORED_OPTION = CHAR_MAX + 1,
+  ACLS_OPTION = CHAR_MAX + 1,
+  ANCHORED_OPTION,
   ATIME_PRESERVE_OPTION,
   BACKUP_OPTION,
   CHECKPOINT_OPTION,
@@ -263,6 +264,7 @@ enum
   KEEP_NEWER_FILES_OPTION,
   MODE_OPTION,
   NEWER_MTIME_OPTION,
+  NO_ACLS_OPTION,
   NO_ANCHORED_OPTION,
   NO_DELAY_DIRECTORY_RESTORE_OPTION,
   NO_IGNORE_CASE_OPTION,
@@ -272,9 +274,11 @@ enum
   NO_RECURSION_OPTION,
   NO_SAME_OWNER_OPTION,
   NO_SAME_PERMISSIONS_OPTION,
+  NO_SELINUX_CONTEXT_OPTION,
   NO_UNQUOTE_OPTION,
   NO_WILDCARDS_MATCH_SLASH_OPTION,
   NO_WILDCARDS_OPTION,
+  NO_XATTR_OPTION,
   NULL_OPTION,
   NUMERIC_OWNER_OPTION,
   OCCURRENCE_OPTION,
@@ -295,6 +299,7 @@ enum
   RMT_COMMAND_OPTION,
   RSH_COMMAND_OPTION,
   SAME_OWNER_OPTION,
+  SELINUX_CONTEXT_OPTION,
   SHOW_DEFAULTS_OPTION,
   SHOW_OMITTED_DIRS_OPTION,
   SHOW_STORED_NAMES_OPTION,
@@ -310,7 +315,8 @@ enum
   VERSION_OPTION,
   VOLNO_FILE_OPTION,
   WILDCARDS_MATCH_SLASH_OPTION,
-  WILDCARDS_OPTION
+  WILDCARDS_OPTION,
+  XATTR_OPTION
 };
 
 const char *argp_program_version = "tar (" PACKAGE_NAME ") " VERSION;
@@ -430,6 +436,10 @@ static struct argp_option options[] = {
   {NULL, 0, NULL, 0,
    N_("Handling of file attributes:"), GRID },
 
+  {"acls", ACLS_OPTION, 0, 0, 
+   N_("Save the ACLs to the archive"), GRID+1 },
+  {"no-acls", NO_ACLS_OPTION, 0, 0, 
+   N_("Don't extract the ACLs from the archive"), GRID+1 },
   {"owner", OWNER_OPTION, N_("NAME"), 0,
    N_("force NAME as owner for added files"), GRID+1 },
   {"group", GROUP_OPTION, N_("NAME"), 0,
@@ -458,6 +468,14 @@ static struct argp_option options[] = {
   {"preserve-order", 's', 0, 0,
    N_("sort names to extract to match archive"), GRID+1 },
   {"same-order", 0, 0, OPTION_ALIAS, NULL, GRID+1 },
+  {"selinux", SELINUX_CONTEXT_OPTION, 0, 0, 
+   N_("Save the SELinux context to the archive"), GRID+1 },
+  {"no-selinux", NO_SELINUX_CONTEXT_OPTION, 0, 0, 
+   N_("Don't extract the SELinux context from the archive"), GRID+1 },
+  {"xattrs", XATTR_OPTION, 0, 0, 
+   N_("Save the user/root xattrs to the archive"), GRID+1 },
+  {"no-xattrs", NO_XATTR_OPTION, 0, 0, 
+   N_("Don't extract the user/root xattrs from the archive"), GRID+1 },
   {"preserve", PRESERVE_OPTION, 0, 0,
    N_("same as both -p and -s"), GRID+1 },
   {"delay-directory-restore", DELAY_DIRECTORY_RESTORE_OPTION, 0, 0,
@@ -1513,6 +1531,37 @@ parse_opt (int key, char *arg, struct ar
       same_permissions_option = -1;
       break;
 
+    case ACLS_OPTION:
+      set_archive_format ("posix");
+      acls_option = 1;
+      break;
+
+    case NO_ACLS_OPTION:
+      acls_option = -1;
+      break;
+
+    case SELINUX_CONTEXT_OPTION:
+      set_archive_format ("posix");
+      selinux_context_option = 1;
+      break;
+
+    case NO_SELINUX_CONTEXT_OPTION:
+      selinux_context_option = -1;
+      break;
+
+    case XATTR_OPTION:
+      set_archive_format ("posix");
+      if (!acls_option) acls_option = 1;
+      if (!selinux_context_option) selinux_context_option = 1;
+      xattrs_option = 1;
+      break;
+
+    case NO_XATTR_OPTION:
+      if (!acls_option) acls_option = -1;
+      if (!selinux_context_option) selinux_context_option = -1;
+      xattrs_option = -1;
+      break;
+
     case RECURSION_OPTION:
       recursion_option = FNM_LEADING_DIR;
       break;
@@ -1921,6 +1970,29 @@ decode_options (int argc, char **argv)
 	  || subcommand_option != LIST_SUBCOMMAND))
     USAGE_ERROR ((0, 0, _("--pax-option can be used only on POSIX archives")));
 
+  /* star create's non-POSIX typed archives with xattr support, so allow the
+     extra headers */
+  if ((acls_option > 0)
+      && archive_format != POSIX_FORMAT
+      && (subcommand_option != EXTRACT_SUBCOMMAND
+	  || subcommand_option != DIFF_SUBCOMMAND
+	  || subcommand_option != LIST_SUBCOMMAND))
+    USAGE_ERROR ((0, 0, _("--acls can be used only on POSIX archives")));
+
+  if ((selinux_context_option > 0)
+      && archive_format != POSIX_FORMAT
+      && (subcommand_option != EXTRACT_SUBCOMMAND
+	  || subcommand_option != DIFF_SUBCOMMAND
+	  || subcommand_option != LIST_SUBCOMMAND))
+    USAGE_ERROR ((0, 0, _("--selinux can be used only on POSIX archives")));
+
+  if ((xattrs_option > 0)
+      && archive_format != POSIX_FORMAT
+      && (subcommand_option != EXTRACT_SUBCOMMAND
+	  || subcommand_option != DIFF_SUBCOMMAND
+	  || subcommand_option != LIST_SUBCOMMAND))
+    USAGE_ERROR ((0, 0, _("--xattrs can be used only on POSIX archives")));
+
   /* If ready to unlink hierarchies, so we are for simpler files.  */
   if (recursive_unlink_option)
     old_files_option = UNLINK_FIRST_OLD_FILES;
@@ -2116,11 +2188,14 @@ tar_stat_init (struct tar_stat_info *st)
 void
 tar_stat_destroy (struct tar_stat_info *st)
 {
+  xheader_xattr_free (st->xattr_map, st->xattr_map_size);
   free (st->orig_file_name);
   free (st->file_name);
   free (st->link_name);
   free (st->uname);
   free (st->gname);
+  free (st->cntx_name);
+  free (st->acls_ptr);
   free (st->sparse_map);
   free (st->dumpdir);
   memset (st, 0, sizeof (*st));
Only in tar-1.15.90/src: tar.c.incompatibility
diff -rup tar-1.15.90-orig/src/tar.h tar-1.15.90/src/tar.h
--- tar-1.15.90-orig/src/tar.h	2006-02-19 14:29:18.000000000 -0500
+++ tar-1.15.90/src/tar.h	2006-08-28 02:59:01.000000000 -0400
@@ -268,6 +268,14 @@ struct sp_array
     size_t numbytes;
   };
 
+/* Information about xattrs for a file.  */
+struct xattr_array
+  {
+    char *xkey;
+    char *xval_ptr;
+    size_t xval_len;
+  };
+
 struct tar_stat_info
 {
   char *orig_file_name;     /* name of file read from the archive header */
@@ -279,6 +287,12 @@ struct tar_stat_info
 
   char          *uname;     /* user name of owner */
   char          *gname;     /* group name of owner */
+
+  char *cntx_name;          /* SELinux context for the current archive entry. */
+
+  char *acls_ptr;           /* ACLs for the current archive entry. */
+  size_t acls_len;          /* ACLs for the current archive entry. */
+
   struct stat   stat;       /* regular filesystem stat */
 
   /* STAT doesn't always have access, data modification, and status
@@ -299,6 +313,9 @@ struct tar_stat_info
   size_t sparse_map_size;   /* Size of the sparse map */
   struct sp_array *sparse_map;
 
+  size_t xattr_map_size;   /* Size of the xattr map */
+  struct xattr_array *xattr_map;
+ 
   /* For dumpdirs */
   bool is_dumpdir;          /* Is the member a dumpdir? */
   bool skipped;             /* The member contents is already read
Only in tar-1.15.90/src: tar.h.incompatibility
Only in tar-1.15.90/src: xattrs.c
Only in tar-1.15.90/src: xattrs.c~
Only in tar-1.15.90/src: xattrs.c.incompatibility
Only in tar-1.15.90/src: xattrs.h
Only in tar-1.15.90/src: xattrs.h.incompatibility
diff -rup tar-1.15.90-orig/src/xheader.c tar-1.15.90/src/xheader.c
--- tar-1.15.90-orig/src/xheader.c	2006-02-19 14:29:18.000000000 -0500
+++ tar-1.15.90/src/xheader.c	2006-08-28 02:59:01.000000000 -0400
@@ -422,6 +422,74 @@ xheader_write_global (void)
   free (name);
 }
 
+void xheader_xattr_init(struct tar_stat_info *st)
+{
+  st->xattr_map = NULL;
+  st->xattr_map_size = 0;
+}
+
+void xheader_xattr_free(struct xattr_array *xattr_map, size_t xattr_map_size)
+{
+  size_t scan = 0;
+
+  while (scan < xattr_map_size)
+    {
+      free (xattr_map[scan].xkey);
+      free (xattr_map[scan].xval_ptr);
+
+      ++scan;
+    }
+  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)
+{
+  size_t pos = (*xattr_map_size)++;
+  
+  *xattr_map = xrealloc (*xattr_map,
+                         *xattr_map_size * sizeof(struct xattr_array));
+  (*xattr_map)[pos].xkey = xstrdup (key);
+  (*xattr_map)[pos].xval_ptr = xmemdup (val, len);
+  (*xattr_map)[pos].xval_len = len;
+}
+
+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);
+  char *tmp = xkey;
+
+  tmp = stpcpy (tmp, "SCHILY.xattr.");
+  tmp = stpcpy (tmp, key);
+  
+  xheader_xattr__add (&st->xattr_map, &st->xattr_map_size, xkey, val, len);
+
+  free (xkey);
+}
+
+void xheader_xattr_copy(const struct tar_stat_info *st,
+                        struct xattr_array **xattr_map, size_t *xattr_map_size)
+{
+  size_t scan = 0;
+
+  *xattr_map = NULL;
+  *xattr_map_size = 0;
+  
+  while (scan < st->xattr_map_size)
+    {
+      char  *key = st->xattr_map[scan].xkey;
+      char  *val = st->xattr_map[scan].xval_ptr;
+      size_t len = st->xattr_map[scan].xval_len;
+      
+      xheader_xattr__add(xattr_map, xattr_map_size, key, val, len);
+
+      ++scan;
+    }
+}
+
 
 /* General Interface */
 
@@ -430,8 +498,9 @@ struct xhdr_tab
   char const *keyword;
   void (*coder) (struct tar_stat_info const *, char const *,
 		 struct xheader *, void const *data);
-  void (*decoder) (struct tar_stat_info *, char const *, size_t);
+  void (*decoder) (struct tar_stat_info *, char const *, char const *, size_t);
   bool protect;
+  bool prefix;
 };
 
 /* This declaration must be extern, because ISO C99 section 6.9.2
@@ -448,8 +517,17 @@ locate_handler (char const *keyword)
   struct xhdr_tab const *p;
 
   for (p = xhdr_tab; p->keyword; p++)
-    if (strcmp (p->keyword, keyword) == 0)
-      return p;
+    if (p->prefix)
+      {
+        if (strncmp (p->keyword, keyword, strlen(p->keyword)) == 0)
+          return p;
+      }
+  else
+      {
+        if (strcmp (p->keyword, keyword) == 0)
+          return p;
+      }
+  
   return NULL;
 }
 
@@ -459,7 +537,7 @@ xheader_protected_pattern_p (const char 
   struct xhdr_tab const *p;
 
   for (p = xhdr_tab; p->keyword; p++)
-    if (p->protect && fnmatch (pattern, p->keyword, 0) == 0)
+    if (!p->prefix && p->protect && fnmatch (pattern, p->keyword, 0) == 0)
       return true;
   return false;
 }
@@ -470,7 +548,7 @@ xheader_protected_keyword_p (const char 
   struct xhdr_tab const *p;
 
   for (p = xhdr_tab; p->keyword; p++)
-    if (p->protect && strcmp (p->keyword, keyword) == 0)
+    if (!p->prefix && p->protect && strcmp (p->keyword, keyword) == 0)
       return true;
   return false;
 }
@@ -551,7 +629,7 @@ run_override_list (struct keyword_list *
     {
       struct xhdr_tab const *t = locate_handler (kp->pattern);
       if (t)
-	t->decoder (st, kp->value, strlen (kp->value));
+	t->decoder (st, t->keyword, kp->value, strlen (kp->value));
     }
 }
 
@@ -567,7 +645,7 @@ decx (void *data, char const *keyword, c
 
   t = locate_handler (keyword);
   if (t)
-    t->decoder (st, value, size);
+    t->decoder (st, keyword, value, size);
   else
     ERROR((0, 0, _("Ignoring unknown extended header keyword `%s'"),
 	   keyword));
@@ -962,6 +1040,7 @@ dummy_coder (struct tar_stat_info const 
 
 static void
 dummy_decoder (struct tar_stat_info *st __attribute__ ((unused)),
+	       char const *keyword __attribute__ ((unused)),
 	       char const *arg __attribute__ ((unused)),
 	       size_t size __attribute__((unused)))
 {
@@ -975,11 +1054,13 @@ atime_coder (struct tar_stat_info const 
 }
 
 static void
-atime_decoder (struct tar_stat_info *st, char const *arg,
+atime_decoder (struct tar_stat_info *st,
+	       char const *keyword,
+               char const *arg,
 	       size_t size __attribute__((unused)))
 {
   struct timespec ts;
-  if (decode_time (&ts, arg, "atime"))
+  if (decode_time (&ts, arg, keyword))
     st->atime = ts;
 }
 
@@ -991,11 +1072,12 @@ gid_coder (struct tar_stat_info const *s
 }
 
 static void
-gid_decoder (struct tar_stat_info *st, char const *arg,
+gid_decoder (struct tar_stat_info *st,
+             char const *keyword, char const *arg,
 	     size_t size __attribute__((unused)))
 {
   uintmax_t u;
-  if (decode_num (&u, arg, TYPE_MAXIMUM (gid_t), "gid"))
+  if (decode_num (&u, arg, TYPE_MAXIMUM (gid_t), keyword))
     st->stat.st_gid = u;
 }
 
@@ -1007,7 +1089,9 @@ gname_coder (struct tar_stat_info const 
 }
 
 static void
-gname_decoder (struct tar_stat_info *st, char const *arg,
+gname_decoder (struct tar_stat_info *st,
+               char const *keyword __attribute__ ((unused)),
+               char const *arg,
 	       size_t size __attribute__((unused)))
 {
   decode_string (&st->gname, arg);
@@ -1021,7 +1105,9 @@ linkpath_coder (struct tar_stat_info con
 }
 
 static void
-linkpath_decoder (struct tar_stat_info *st, char const *arg,
+linkpath_decoder (struct tar_stat_info *st,
+                  char const *keyword __attribute__ ((unused)),
+                  char const *arg,
 		  size_t size __attribute__((unused)))
 {
   decode_string (&st->link_name, arg);
@@ -1035,11 +1121,12 @@ ctime_coder (struct tar_stat_info const 
 }
 
 static void
-ctime_decoder (struct tar_stat_info *st, char const *arg,
+ctime_decoder (struct tar_stat_info *st,
+               char const *keyword, char const *arg,
 	       size_t size __attribute__((unused)))
 {
   struct timespec ts;
-  if (decode_time (&ts, arg, "ctime"))
+  if (decode_time (&ts, arg, keyword))
     st->ctime = ts;
 }
 
@@ -1051,11 +1138,12 @@ mtime_coder (struct tar_stat_info const 
 }
 
 static void
-mtime_decoder (struct tar_stat_info *st, char const *arg,
+mtime_decoder (struct tar_stat_info *st,
+               char const *keyword, char const *arg,
 	       size_t size __attribute__((unused)))
 {
   struct timespec ts;
-  if (decode_time (&ts, arg, "mtime"))
+  if (decode_time (&ts, arg, keyword))
     st->mtime = ts;
 }
 
@@ -1067,7 +1155,9 @@ path_coder (struct tar_stat_info const *
 }
 
 static void
-path_decoder (struct tar_stat_info *st, char const *arg,
+path_decoder (struct tar_stat_info *st,
+              char const *keyword __attribute__ ((unused)),
+              char const *arg,
 	      size_t size __attribute__((unused)))
 {
   decode_string (&st->orig_file_name, arg);
@@ -1083,11 +1173,12 @@ size_coder (struct tar_stat_info const *
 }
 
 static void
-size_decoder (struct tar_stat_info *st, char const *arg,
+size_decoder (struct tar_stat_info *st,
+              char const *keyword, char const *arg,
 	      size_t size __attribute__((unused)))
 {
   uintmax_t u;
-  if (decode_num (&u, arg, TYPE_MAXIMUM (off_t), "size"))
+  if (decode_num (&u, arg, TYPE_MAXIMUM (off_t), keyword))
     st->stat.st_size = u;
 }
 
@@ -1099,11 +1190,12 @@ uid_coder (struct tar_stat_info const *s
 }
 
 static void
-uid_decoder (struct tar_stat_info *st, char const *arg,
+uid_decoder (struct tar_stat_info *st,
+             char const *keyword, char const *arg,
 	     size_t size __attribute__((unused)))
 {
   uintmax_t u;
-  if (decode_num (&u, arg, TYPE_MAXIMUM (uid_t), "uid"))
+  if (decode_num (&u, arg, TYPE_MAXIMUM (uid_t), keyword))
     st->stat.st_uid = u;
 }
 
@@ -1115,7 +1207,9 @@ uname_coder (struct tar_stat_info const 
 }
 
 static void
-uname_decoder (struct tar_stat_info *st, char const *arg,
+uname_decoder (struct tar_stat_info *st,
+               char const *keyword __attribute__ ((unused)),
+               char const *arg,
 	       size_t size __attribute__((unused)))
 {
   decode_string (&st->uname, arg);
@@ -1129,11 +1223,12 @@ sparse_size_coder (struct tar_stat_info 
 }
 
 static void
-sparse_size_decoder (struct tar_stat_info *st, char const *arg,
+sparse_size_decoder (struct tar_stat_info *st,
+                     char const *keyword, char const *arg,
 		     size_t size __attribute__((unused)))
 {
   uintmax_t u;
-  if (decode_num (&u, arg, TYPE_MAXIMUM (off_t), "GNU.sparse.size"))
+  if (decode_num (&u, arg, TYPE_MAXIMUM (off_t), keyword))
     st->stat.st_size = u;
 }
 
@@ -1146,11 +1241,12 @@ sparse_numblocks_coder (struct tar_stat_
 }
 
 static void
-sparse_numblocks_decoder (struct tar_stat_info *st, char const *arg,
+sparse_numblocks_decoder (struct tar_stat_info *st,
+                          char const *keyword, char const *arg,
 			  size_t size __attribute__((unused)))
 {
   uintmax_t u;
-  if (decode_num (&u, arg, SIZE_MAX, "GNU.sparse.numblocks"))
+  if (decode_num (&u, arg, SIZE_MAX, keyword))
     {
       st->sparse_map_size = u;
       st->sparse_map = xcalloc (u, sizeof st->sparse_map[0]);
@@ -1167,11 +1263,12 @@ sparse_offset_coder (struct tar_stat_inf
 }
 
 static void
-sparse_offset_decoder (struct tar_stat_info *st, char const *arg,
+sparse_offset_decoder (struct tar_stat_info *st,
+                       char const *keyword, char const *arg,
 		       size_t size __attribute__((unused)))
 {
   uintmax_t u;
-  if (decode_num (&u, arg, TYPE_MAXIMUM (off_t), "GNU.sparse.offset"))
+  if (decode_num (&u, arg, TYPE_MAXIMUM (off_t), keyword))
     {
       if (st->sparse_map_avail < st->sparse_map_size)
 	st->sparse_map[st->sparse_map_avail].offset = u;
@@ -1190,11 +1287,12 @@ sparse_numbytes_coder (struct tar_stat_i
 }
 
 static void
-sparse_numbytes_decoder (struct tar_stat_info *st, char const *arg,
+sparse_numbytes_decoder (struct tar_stat_info *st,
+                         char const *keyword, char const *arg,
 			 size_t size __attribute__((unused)))
 {
   uintmax_t u;
-  if (decode_num (&u, arg, SIZE_MAX, "GNU.sparse.numbytes"))
+  if (decode_num (&u, arg, SIZE_MAX, keyword))
     {
       if (st->sparse_map_avail < st->sparse_map_size)
 	st->sparse_map[st->sparse_map_avail++].numbytes = u;
@@ -1205,11 +1303,11 @@ sparse_numbytes_decoder (struct tar_stat
 }
 
 static void
-sparse_map_decoder (struct tar_stat_info *st, char const *arg,
+sparse_map_decoder (struct tar_stat_info *st,
+                    char const *keyword, char const *arg,
 		    size_t size __attribute__((unused)))
 {
   int offset = 1;
-  static char *keyword = "GNU.sparse.map";
 
   st->sparse_map_avail = 0;
   while (1)
@@ -1283,8 +1381,9 @@ dumpdir_coder (struct tar_stat_info cons
 }
 
 static void
-dumpdir_decoder (struct tar_stat_info *st, char const *arg,
-		 size_t size)
+dumpdir_decoder (struct tar_stat_info *st,
+                 char const *keyword __attribute__ ((unused)),
+                 char const *arg, size_t size)
 {
   st->dumpdir = xmalloc (size);
   memcpy (st->dumpdir, arg, size);
@@ -1298,7 +1397,9 @@ volume_label_coder (struct tar_stat_info
 }
 
 static void
-volume_label_decoder (struct tar_stat_info *st, char const *arg, size_t size)
+volume_label_decoder (struct tar_stat_info *st,
+                      char const *keyword __attribute__ ((unused)),
+                      char const *arg, size_t size)
 {
   decode_string (&volume_label, arg);
 }
@@ -1312,10 +1413,11 @@ volume_size_coder (struct tar_stat_info 
 }
 
 static void
-volume_size_decoder (struct tar_stat_info *st, char const *arg, size_t size)
+volume_size_decoder (struct tar_stat_info *st,
+                     char const *keyword, char const *arg, size_t size)
 {
   uintmax_t u;
-  if (decode_num (&u, arg, TYPE_MAXIMUM (uintmax_t), "GNU.volume.size"))
+  if (decode_num (&u, arg, TYPE_MAXIMUM (uintmax_t), keyword))
     continued_file_size = u;
 }
 
@@ -1329,57 +1431,110 @@ volume_offset_coder (struct tar_stat_inf
 }
 
 static void
-volume_offset_decoder (struct tar_stat_info *st, char const *arg, size_t size)
+volume_offset_decoder (struct tar_stat_info *st,
+                       char const *keyword, char const *arg, size_t size)
 {
   uintmax_t u;
-  if (decode_num (&u, arg, TYPE_MAXIMUM (uintmax_t), "GNU.volume.offset"))
+  if (decode_num (&u, arg, TYPE_MAXIMUM (uintmax_t), keyword))
     continued_file_offset = u;
 }
 
 static void
-volume_filename_decoder (struct tar_stat_info *st, char const *arg,
-			 size_t size)
+volume_filename_decoder (struct tar_stat_info *st,
+                         char const *keyword __attribute__ ((unused)),
+                         char const *arg, size_t size)
 {
   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_coder (struct tar_stat_info const *st , char const *keyword,
+                  struct xheader *xhdr, void const *data)
+{
+  xheader_print_n (xhdr, keyword, st->acls_ptr, st->acls_len);
+}
+
+static void
+xattr_acls_decoder (struct tar_stat_info *st,
+                    char const *keyword, char const *arg, size_t size)
+{
+  st->acls_ptr = xmemdup (arg, size);
+  st->acls_len = size;
+}
+
+static void
+xattr_coder (struct tar_stat_info const *st , char const *keyword,
+             struct xheader *xhdr, void const *data)
+{
+  struct xattr_array *xattr_map = st->xattr_map;
+  const size_t *off = data;
   
+  xheader_print_n (xhdr, keyword,
+                   xattr_map[*off].xval_ptr, xattr_map[*off].xval_len);
+}
+
+static void
+xattr_decoder (struct tar_stat_info *st,
+               char const *keyword, char const *arg, size_t size)
+{
+  char *xstr = NULL;
+  
+  xstr = xmemdup(arg, size + 1);
+  xheader_xattr_add(st, keyword + strlen("SCHILY.xattr."), xstr, size);
+  free(xstr);
+}
 
 struct xhdr_tab const xhdr_tab[] = {
-  { "atime",	atime_coder,	atime_decoder,	  false },
-  { "comment",	dummy_coder,	dummy_decoder,	  false },
-  { "charset",	dummy_coder,	dummy_decoder,	  false },
-  { "ctime",	ctime_coder,	ctime_decoder,	  false },
-  { "gid",	gid_coder,	gid_decoder,	  false },
-  { "gname",	gname_coder,	gname_decoder,	  false },
-  { "linkpath", linkpath_coder, linkpath_decoder, false },
-  { "mtime",	mtime_coder,	mtime_decoder,	  false },
-  { "path",	path_coder,	path_decoder,	  false },
-  { "size",	size_coder,	size_decoder,	  false },
-  { "uid",	uid_coder,	uid_decoder,	  false },
-  { "uname",	uname_coder,	uname_decoder,	  false },
+  { "atime",	atime_coder,	atime_decoder,	  false, false },
+  { "comment",	dummy_coder,	dummy_decoder,	  false, false },
+  { "charset",	dummy_coder,	dummy_decoder,	  false, false },
+  { "ctime",	ctime_coder,	ctime_decoder,	  false, false },
+  { "gid",	gid_coder,	gid_decoder,	  false, false },
+  { "gname",	gname_coder,	gname_decoder,	  false, false },
+  { "linkpath", linkpath_coder, linkpath_decoder, false, false },
+  { "mtime",	mtime_coder,	mtime_decoder,	  false, false },
+  { "path",	path_coder,	path_decoder,	  false, false },
+  { "size",	size_coder,	size_decoder,	  false, false },
+  { "uid",	uid_coder,	uid_decoder,	  false, false },
+  { "uname",	uname_coder,	uname_decoder,	  false, false },
 
   /* Sparse file handling */
-  { "GNU.sparse.size",       sparse_size_coder, sparse_size_decoder, true },
+  { "GNU.sparse.size",       sparse_size_coder, sparse_size_decoder,
+    true, false },
   { "GNU.sparse.numblocks",  sparse_numblocks_coder, sparse_numblocks_decoder,
-    true },
+    true, false },
   /* tar 1.14 - 1.15.1 keywords. Multiplse instances of these appeared in 'x'
      headers, and each of them was meaningful. It confilcted with POSIX specs,
      which requires that "when extended header records conflict, the last one
      given in the header shall take precedence." */
   { "GNU.sparse.offset",     sparse_offset_coder, sparse_offset_decoder,
-    true },
+    true, false },
   { "GNU.sparse.numbytes",   sparse_numbytes_coder, sparse_numbytes_decoder,
-    true },
+    true, false },
   /* tar >=1.16 keyword, introduced to remove the above-mentioned conflict. */
   { "GNU.sparse.map",        NULL /* Unused, see pax_dump_header() */,
-    sparse_map_decoder, false },
+    sparse_map_decoder, false, false },
 
   { "GNU.dumpdir",           dumpdir_coder, dumpdir_decoder,
-    true },
+    true, false },
 
   /* Keeps the tape/volume label. May be present only in the global headers.
      Equivalent to GNUTYPE_VOLHDR.  */
-  { "GNU.volume.label", volume_label_coder, volume_label_decoder, true },
+  { "GNU.volume.label", volume_label_coder, volume_label_decoder, true, false },
 
   /* These may be present in a first global header of the archive.
      They provide the same functionality as GNUTYPE_MULTIVOL header.
@@ -1388,9 +1543,23 @@ struct xhdr_tab const xhdr_tab[] = {
      GNU.volume.offset keeps the offset of the start of this volume,
      otherwise kept in oldgnu_header.offset.  */
   { "GNU.volume.filename", volume_label_coder, volume_filename_decoder,
-    true },
-  { "GNU.volume.size", volume_size_coder, volume_size_decoder, true },
-  { "GNU.volume.offset", volume_offset_coder, volume_offset_decoder, true },
-
+    true, false },
+  { "GNU.volume.size", volume_size_coder, volume_size_decoder, true, false },
+  { "GNU.volume.offset", volume_offset_coder, volume_offset_decoder,
+    true, false },
+
+  /* SELinux, use the star format... */
+  { "SCHILY.xattr.security.selinux",
+    xattr_selinux_coder, xattr_selinux_decoder, false, false },
+
+  /* ACLs, use the star format... */
+  { "SCHILY.xattr.system.posix_acl_access",
+    xattr_acls_coder, xattr_acls_decoder, false, false },
+
+  /* xattr's, use the star format note we only save the user/root varients... */
+  { "SCHILY.xattr.user",  xattr_coder, xattr_decoder, false, true },
+  { "SCHILY.xattr.root",  xattr_coder, xattr_decoder, false, true },
+  { "SCHILY.xattr",       dummy_coder, dummy_decoder, false, true },
+  
   { NULL, NULL, NULL, false }
 };
Only in tar-1.15.90/src: xheader.c.incompatibility
--- tar-1.15.90-orig/src/xattrs.c	1969-12-31 19:00:00.000000000 -0500
+++ tar-1.15.90/src/xattrs.c	2006-08-28 03:03:54.000000000 -0400
@@ -0,0 +1,231 @@
+/* Create a tar archive.
+
+   Copyright (C) 2006 Free Software Foundation, Inc.
+
+   Written by James Antill, on 2006-07-27.
+
+   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 2, 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, write to the Free Software Foundation, Inc.,
+   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
+
+#include <system.h>
+
+#include <quotearg.h>
+
+#include "common.h"
+
+
+#ifndef HAVE_SELINUX_SELINUX_H
+# undef HAVE_LIBSELINUX
+#endif
+
+#ifndef HAVE_ATTR_XATTR_H
+# undef HAVE_XATTRS
+#endif
+
+#ifdef HAVE_SELINUX_SELINUX_H
+# include <selinux/selinux.h>
+#endif
+
+#ifdef HAVE_ATTR_XATTR_H
+# include <attr/xattr.h>
+#endif
+
+
+void xattrs_acls_get(struct tar_stat_info *st, char const *file_name, int fd)
+{
+#ifdef HAVE_XATTRS
+  if (acls_option > 0)
+    {
+      const char *attr = "system.posix_acl_access";
+      static char *val = NULL;
+      static ssize_t asz = 1024;
+      ssize_t ret = 0;
+      
+      if (!val) val = xmalloc (asz);
+          
+      while (((ret = fgetxattr (fd, attr, val, asz)) == -1) &&
+             (errno == ERANGE))
+        val = x2nrealloc (val, &asz);
+              
+      if (ret != -1)
+        {
+          st->acls_ptr = xmemdup (val, ret);
+          st->acls_len = ret;
+        }
+      else if (errno != ENOATTR)
+        call_arg_warn ("fgetxattr", file_name);
+    }
+#endif
+}
+
+void xattrs_selinux_get(struct tar_stat_info *st, char const *file_name, int fd)
+{
+#ifdef HAVE_LIBSELINUX
+  if (selinux_context_option > 0)
+    if (fgetfilecon (fd, &st->cntx_name) == -1)
+      call_arg_warn ("fgetfilecon", file_name);
+#endif
+}
+
+void xattrs_xattrs_get(struct tar_stat_info *st, char const *file_name, int fd)
+{
+#ifdef HAVE_XATTRS
+  if (xattrs_option > 0)
+    { /* get all xattrs ... this include security.* and system.* if
+         available. We filter them here, but we have to filter them
+         in xattrs_xattrs_set() anyway.
+      */
+      static ssize_t xsz = 1024;
+      static char *xatrs = NULL;
+      ssize_t xret = -1;
+
+      if (!xatrs) xatrs = xmalloc (xsz);
+              
+      while (((xret = flistxattr (fd, xatrs, xsz)) == -1) &&
+             (errno == ERANGE))
+        xatrs = x2nrealloc (xatrs, &xsz);
+
+      if (xret == -1)
+        call_arg_warn ("flistxattrs", file_name);
+      else
+        {
+          const char *attr = xatrs;
+          static ssize_t asz = 1024;
+          static char *val = NULL;
+          
+          if (!val) val = xmalloc (asz);
+          
+          while (xret > 0)
+            {
+              size_t len = strlen (attr);
+              ssize_t aret = 0;
+              
+              if (strncmp (attr, "user.", strlen("user.")) &&
+                  strncmp (attr, "root.", strlen("root.")))
+                goto next_attr; /* only store normal xattrs */
+              
+              while (((aret = fgetxattr (fd, attr, val, asz)) == -1) &&
+                     (errno == ERANGE))
+                val = x2nrealloc (val, &asz);
+              
+              if (aret != -1)
+                xheader_xattr_add (st, attr, val, aret);
+              else if (errno != ENOATTR)
+                call_arg_warn ("fgetxattr", file_name);
+              
+             next_attr:
+              attr += len + 1;
+              xret -= len + 1;
+            }
+        }
+    }
+#endif
+}
+
+void xattrs_acls_set(struct tar_stat_info const *st,
+                     char const *file_name, char typeflag)
+{
+#ifdef HAVE_XATTRS
+  if ((acls_option >= 0) && st->acls_ptr)
+    {
+      const char *sysname = "setxattr";
+      char *keyword = "system.posix_acl_access";
+      int ret = -1;
+
+      if (typeflag != SYMTYPE)
+        ret = setxattr (file_name, keyword, st->acls_ptr, st->acls_len, 0);
+      else
+        {
+          sysname = "lsetxattr";
+          ret = lsetxattr (file_name, keyword, st->acls_ptr, st->acls_len, 0);
+        }
+
+      if ((ret == -1) && (errno == EPERM))
+        call_arg_warn(sysname, file_name);
+      else if ((ret == -1) && (errno != EOPNOTSUPP))
+        call_arg_error(sysname, file_name);
+    }
+#endif
+}
+
+void xattrs_selinux_set(struct tar_stat_info const *st,
+                        char const *file_name, char typeflag)
+{
+#ifdef HAVE_LIBSELINUX
+  if ((selinux_context_option >= 0) && st->cntx_name)
+    {
+      const char *sysname = "setfilecon";
+      int ret = -1;
+      
+      if (typeflag != SYMTYPE)
+        ret = setfilecon (file_name, st->cntx_name);
+      else
+        {
+          sysname = "lsetfilecon";
+          ret = lsetfilecon (file_name, st->cntx_name);
+        }
+
+      if ((ret == -1) && (errno == EPERM))
+        call_arg_warn(sysname, file_name);
+      else if ((ret == -1) && (errno != EOPNOTSUPP))
+        call_arg_error(sysname, file_name);
+    }
+#endif
+}
+
+void xattrs_xattrs_set(struct tar_stat_info const *st,
+                       char const *file_name, char typeflag)
+{
+#ifdef HAVE_XATTRS
+  if ((xattrs_option >= 0) && st->xattr_map_size)
+    {
+      const char *sysname = "setxattr";
+      size_t scan = 0;
+      int ret = -1;
+      
+      while (scan < st->xattr_map_size)
+        {
+          char *keyword = st->xattr_map[scan].xkey;
+
+          // assert (!memcpy (keyword, "SCHILY.xattr.", strlen("SCHILY.xattr.")));
+          keyword += strlen("SCHILY.xattr.");
+
+          if (strncmp (keyword, "user.", strlen("user.")) &&
+              strncmp (keyword, "root.", strlen("root.")))
+            continue; /* don't try and set anything but normal xattrs */
+            
+          if (typeflag != SYMTYPE)
+            ret = setxattr (file_name, keyword,
+                            st->xattr_map[scan].xval_ptr,
+                            st->xattr_map[scan].xval_len, 0);
+          else
+            {
+              sysname = "lsetxattr";
+              ret = lsetxattr (file_name, keyword,
+                               st->xattr_map[scan].xval_ptr,
+                               st->xattr_map[scan].xval_len, 0);
+            }
+
+          /* should we ignore root.* xattrs when not root ? */
+          if ((ret == -1) && (errno == EPERM))
+            call_arg_warn(sysname, file_name);
+          else if ((ret == -1) && (errno != EOPNOTSUPP))
+            call_arg_error(sysname, file_name);
+      
+          ++scan;
+        }
+    }
+#endif
+}
+
--- tar-1.15.90-orig/src/xattrs.h	1969-12-31 19:00:00.000000000 -0500
+++ tar-1.15.90/src/xattrs.h	2006-08-28 02:59:01.000000000 -0400
@@ -0,0 +1,14 @@
+
+extern void xattrs_acls_get(struct tar_stat_info *st,
+                            char const *file_name, int fd);
+extern void xattrs_selinux_get(struct tar_stat_info *st,
+                               char const *file_name, int fd);
+extern void xattrs_xattrs_get(struct tar_stat_info *st,
+                              char const *file_name, int fd);
+
+extern void xattrs_acls_set(struct tar_stat_info const *st,
+                            char const *file_name, char typeflag);
+extern void xattrs_selinux_set(struct tar_stat_info const *st,
+                               char const *file_name, char typeflag);
+extern void xattrs_xattrs_set(struct tar_stat_info const *st,
+                              char const *file_name, char typeflag);
