diff --git a/.gitignore b/.gitignore
index 15fd059..8f299b4 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,4 @@
tar-1.23.tar.bz2
tar-1.23.tar.bz2.sig
+/tar-1.24.tar.xz
+/tar-1.24.tar.xz.sig
diff --git a/sources b/sources
index b4da6d4..6ed60e5 100644
--- a/sources
+++ b/sources
@@ -1,2 +1,2 @@
-41e2ca4b924ec7860e51b43ad06cdb7e tar-1.23.tar.bz2
-d7a3e49d66c50a046c536b987f25e891 tar-1.23.tar.bz2.sig
+debae443de7e1c61cd24c2d53bca50c6 tar-1.24.tar.xz
+c4beee21bbab83cd022093825371eed5 tar-1.24.tar.xz.sig
diff --git a/tar-1.14-loneZeroWarning.patch b/tar-1.14-loneZeroWarning.patch
index 5fa4fdc..cefa83d 100644
--- a/tar-1.14-loneZeroWarning.patch
+++ b/tar-1.14-loneZeroWarning.patch
@@ -15,7 +15,7 @@ diff -ruNp tar-1.22.orig/src/list.c tar-1.22/src/list.c
+
char buf[UINTMAX_STRSIZE_BOUND];
- status = read_header (¤t_header, ¤t_stat_info,
+ status = read_header (¤t_header, ¤t_stat_info,
@@ -147,6 +155,9 @@ read_and (void (*do_something) (void))
WARNOPT (WARN_ALONE_ZERO_BLOCK,
(0, 0, _("A lone zero block at %s"),
diff --git a/tar-1.17-wildcards.patch b/tar-1.17-wildcards.patch
index 7f97970..0ea5269 100644
--- a/tar-1.17-wildcards.patch
+++ b/tar-1.17-wildcards.patch
@@ -61,7 +61,7 @@
--- tar-1.17/src/names.c.wildcards 2007-04-03 14:17:13.000000000 +0200
+++ tar-1.17/src/names.c 2007-06-28 13:30:48.000000000 +0200
@@ -812,10 +812,7 @@ collect_and_sort_names (void)
- {
+
if (name->found_count || name->directory)
continue;
- if (name->matching_flags & EXCLUDE_WILDCARDS)
diff --git a/tar-1.22-atime-rofs.patch b/tar-1.22-atime-rofs.patch
index 38c7582..c9f3b08 100644
--- a/tar-1.22-atime-rofs.patch
+++ b/tar-1.22-atime-rofs.patch
@@ -5,8 +5,8 @@ diff -urNp tar-1.22-orig/src/create.c tar-1.22/src/create.c
set_exit_status (TAREXIT_DIFFERS);
}
else if (atime_preserve_option == replace_atime_preserve
-- && set_file_atime (fd, p, restore_times) != 0)
-+ && set_file_atime (fd, p, restore_times) != 0
+- && set_file_atime (fd, parentfd, name, st->atime) != 0)
++ && set_file_atime (fd, parentfd, name, st->atime) != 0
+ && errno != EROFS )
utime_error (p);
}
diff --git a/tar-1.23-listedincremental.patch b/tar-1.23-listedincremental.patch
deleted file mode 100644
index 983b73b..0000000
--- a/tar-1.23-listedincremental.patch
+++ /dev/null
@@ -1,18 +0,0 @@
-diff --git a/src/incremen.c b/src/incremen.c
-index dc880cd..3da1349 100644
---- a/src/incremen.c
-+++ b/src/incremen.c
-@@ -894,8 +894,11 @@ append_incremental_renames (struct directory *dir)
- if (obstack_object_size (&stk) != size)
- {
- obstack_1grow (&stk, 0);
-- dumpdir_free (dir->dump);
-- dir->dump = dumpdir_create (obstack_finish (&stk));
-+ if (dir)
-+ {
-+ dumpdir_free (dir->dump);
-+ dir->dump = dumpdir_create (obstack_finish (&stk));
-+ }
- }
- obstack_free (&stk, NULL);
- }
diff --git a/tar-1.23-longnames.patch b/tar-1.23-longnames.patch
deleted file mode 100644
index f7f2840..0000000
--- a/tar-1.23-longnames.patch
+++ /dev/null
@@ -1,142 +0,0 @@
- src/compare.c | 1 -
- src/extract.c | 2 +-
- src/list.c | 7 ++-----
- tests/Makefile.am | 1 +
- tests/exclude06.at | 47 +++++++++++++++++++++++++++++++++++++++++++++++
- tests/testsuite.at | 1 +
- 6 files changed, 52 insertions(+), 7 deletions(-)
-
-diff --git a/src/compare.c b/src/compare.c
-index f4e92da..437ffb3 100644
---- a/src/compare.c
-+++ b/src/compare.c
-@@ -452,7 +452,6 @@ diff_archive (void)
- {
-
- set_next_block_after (current_header);
-- decode_header (current_header, ¤t_stat_info, ¤t_format, 1);
-
- /* Print the block from current_header and current_stat_info. */
-
-diff --git a/src/extract.c b/src/extract.c
-index 947e3ed..71f4e4f 100644
---- a/src/extract.c
-+++ b/src/extract.c
-@@ -1349,7 +1349,7 @@ extract_archive (void)
- priv_set_remove_linkdir ();
-
- set_next_block_after (current_header);
-- decode_header (current_header, ¤t_stat_info, ¤t_format, 1);
-+
- if (!current_stat_info.file_name[0]
- || (interactive_option
- && !confirm ("extract", current_stat_info.file_name)))
-diff --git a/src/list.c b/src/list.c
-index 6e1971f..1edd504 100644
---- a/src/list.c
-+++ b/src/list.c
-@@ -90,7 +90,8 @@ read_and (void (*do_something) (void))
-
- /* Valid header. We should decode next field (mode) first.
- Ensure incoming names are null terminated. */
--
-+ decode_header (current_header, ¤t_stat_info,
-+ ¤t_format, 1);
- if (! name_match (current_stat_info.file_name)
- || (NEWER_OPTION_INITIALIZED (newer_mtime_option)
- /* FIXME: We get mtime now, and again later; this causes
-@@ -116,8 +117,6 @@ read_and (void (*do_something) (void))
- quotearg_colon (current_stat_info.file_name)));
- /* Fall through. */
- default:
-- decode_header (current_header,
-- ¤t_stat_info, ¤t_format, 0);
- skip_member ();
- continue;
- }
-@@ -221,8 +220,6 @@ list_archive (void)
- off_t block_ordinal = current_block_ordinal ();
-
- /* Print the header block. */
--
-- decode_header (current_header, ¤t_stat_info, ¤t_format, 0);
- if (verbose_option)
- print_header (¤t_stat_info, current_header, block_ordinal);
-
-diff --git a/tests/Makefile.am b/tests/Makefile.am
-index e9b753c..fe2535a 100644
---- a/tests/Makefile.am
-+++ b/tests/Makefile.am
-@@ -66,6 +66,7 @@ TESTSUITE_AT = \
- exclude03.at\
- exclude04.at\
- exclude05.at\
-+ exclude06.at\
- extrac01.at\
- extrac02.at\
- extrac03.at\
-diff --git a/tests/exclude06.at b/tests/exclude06.at
-new file mode 100644
-index 0000000..f7ab141
---- /dev/null
-+++ b/tests/exclude06.at
-@@ -0,0 +1,47 @@
-+# Process this file with autom4te to create testsuite. -*- Autotest -*-
-+# Copyright (C) 2010 Free Software Foundation, Inc.
-+
-+# This program is free software; you can redistribute it and/or modify
-+# it under the terms of the GNU General Public License as published by
-+# the Free Software Foundation; either version 3, or (at your option)
-+# any later version.
-+
-+# This program is distributed in the hope that it will be useful,
-+# but WITHOUT ANY WARRANTY; without even the implied warranty of
-+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+# GNU General Public License for more details.
-+
-+# You should have received a copy of the GNU General Public License
-+# along with this program. If not, see .
-+
-+# Tar 1.23 would fail to exclude names longer that 100 characters from
-+# pax format archives.
-+#
-+# Reported-by: Matthew Peterson
-+# References:
-+# http://lists.gnu.org/archive/html/help-tar/2010-06/msg00000.html
-+
-+AT_SETUP([exclude: long files in pax archives])
-+AT_KEYWORDS([exclude exclude06])
-+
-+m4_define([test_base_dir],[one/two/three/four/five/six/seven/eight/nine/ten/eleven/twelve/thirteen/fourteen/fifteen/sixteen/seventeen])
-+
-+AT_TAR_CHECK([
-+AT_TAR_MKHIER(test_base_dir)
-+genfile --length 20 -f test_base_dir[/1.txt]
-+genfile --length 20 -f test_base_dir[/1.c]
-+
-+tar cf archive.tar test_base_dir
-+mkdir out
-+tar -C out -xf archive.tar --exclude='*.txt'
-+find out -type f
-+],
-+[0],
-+[[out/]test_base_dir[/1.c]
-+],
-+[],
-+[],
-+[],
-+[pax])
-+
-+AT_CLEANUP
-diff --git a/tests/testsuite.at b/tests/testsuite.at
-index f581071..ef70b99 100644
---- a/tests/testsuite.at
-+++ b/tests/testsuite.at
-@@ -130,6 +130,7 @@ m4_include([exclude02.at])
- m4_include([exclude03.at])
- m4_include([exclude04.at])
- m4_include([exclude05.at])
-+m4_include([exclude06.at])
-
- m4_include([delete01.at])
- m4_include([delete02.at])
diff --git a/tar-1.23-oldarchive.patch b/tar-1.23-oldarchive.patch
index 1cd369c..6163916 100644
--- a/tar-1.23-oldarchive.patch
+++ b/tar-1.23-oldarchive.patch
@@ -9,15 +9,6 @@ diff -urNp tar-1.23-orig/src/tar.c tar-1.23/src/tar.c
+ case OLD_ARCHIVE_OPTION:
+ set_archive_format ("v7");
+ break;
-
+
case OVERWRITE_DIR_OPTION:
old_files_option = DEFAULT_OLD_FILES;
-@@ -1955,7 +1959,7 @@ parse_opt (int key, char *arg, struct ar
- case POSIX_OPTION:
- set_archive_format ("posix");
- break;
--
-+
- case PRESERVE_OPTION:
- /* FIXME: What it is good for? */
- same_permissions_option = true;
diff --git a/tar-1.23-stripcomponents.patch b/tar-1.23-stripcomponents.patch
index 4a247bb..2f80f16 100644
--- a/tar-1.23-stripcomponents.patch
+++ b/tar-1.23-stripcomponents.patch
@@ -31,7 +31,7 @@ index 4cadab9..3a36b9b 100644
+void transform_name_from_header(union block *header, struct tar_stat_info *);
char const *tartime (struct timespec t, bool full_time);
- #define GID_FROM_HEADER(where) gid_from_header (where, sizeof (where))
+ #define OFF_FROM_HEADER(where) off_from_header (where, sizeof (where))
diff --git a/src/list.c b/src/list.c
index 1edd504..4e0e1a0 100644
--- a/src/list.c
@@ -66,11 +66,11 @@ index 1edd504..4e0e1a0 100644
switch (current_header->header.typeflag)
{
@@ -659,7 +663,11 @@ decode_header (union block *header, struct tar_stat_info *stat_info,
- || stat_info->dumpdir)
- stat_info->is_dumpdir = true;
- }
+ if (header->header.typeflag == GNUTYPE_VOLHDR)
+ /* Name transformations don't apply to volume headers. */
+ return;
+}
-
+
+void
+transform_name_from_header(union block *header, struct tar_stat_info *stat_info)
+{
@@ -86,7 +86,7 @@ index 1edd504..4e0e1a0 100644
simple_print_header (&vstat, &vblk, 0);
tar_stat_destroy (&vstat);
@@ -1431,6 +1440,7 @@ test_archive_label ()
-
+ {
decode_header (current_header,
¤t_stat_info, ¤t_format, 0);
+ transform_name_from_header (current_header, ¤t_stat_info);
@@ -177,3 +177,15 @@ index ef70b99..8b533ed 100644
m4_include([delete01.at])
m4_include([delete02.at])
+diff -urNp tar-1.24-orig/tests/xform01.at tar-1.24/tests/xform01.at
+--- tar-1.24-orig/tests/xform01.at 2010-10-24 20:07:47.000000000 +0200
++++ tar-1.24/tests/xform01.at 2010-10-25 15:49:42.866904079 +0200
+@@ -29,7 +29,7 @@ AT_KEYWORDS([transform xform xform01 vol
+ AT_TAR_CHECK([
+ genfile --file file
+ tar -cf archive.tar -V /label/ file
+-tar tf archive.tar
++tar Ptf archive.tar
+ ],
+ [0],
+ [/label/
diff --git a/tar-1.23-xattrs.patch b/tar-1.23-xattrs.patch
deleted file mode 100644
index 4f982d6..0000000
--- a/tar-1.23-xattrs.patch
+++ /dev/null
@@ -1,1603 +0,0 @@
-diff -urNp tar-1.23-orig/configure.ac tar-1.23/configure.ac
---- tar-1.23-orig/configure.ac 2010-03-10 11:47:54.000000000 +0100
-+++ tar-1.23/configure.ac 2010-08-16 14:32:11.448178888 +0200
-@@ -44,7 +44,7 @@ AC_CHECK_HEADERS_ONCE(fcntl.h linux/fd.h
- sys/param.h sys/device.h sys/filio.h sys/gentape.h \
- sys/inet.h sys/io/trioctl.h \
- sys/mtio.h sys/time.h sys/tprintf.h sys/tape.h \
-- unistd.h locale.h)
-+ unistd.h locale.h attr/xattr.h sys/acl.h)
-
- AC_CHECK_HEADERS([sys/buf.h], [], [],
- [#if HAVE_SYS_PARAM_H
-@@ -91,6 +91,12 @@ gl_INIT
- tar_PAXUTILS
-
- AC_CHECK_FUNCS(fsync getdtablesize lstat mkfifo readlink 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(acl, acl_get_fd)
-+
- AC_CHECK_DECLS([getgrgid],,, [#include ])
- AC_CHECK_DECLS([getpwuid],,, [#include ])
- AC_CHECK_DECLS([time],,, [#include ])
-@@ -214,6 +220,7 @@ AC_DEFINE_UNQUOTED(DEFAULT_QUOTING_STYLE
- # Iconv
- AM_ICONV
- AC_CHECK_HEADERS(iconv.h)
-+AC_CHECK_HEADERS(attr/xattr.h)
- AC_CHECK_TYPE(iconv_t,:,
- AC_DEFINE(iconv_t, int,
- [Conversion descriptor type]),
-@@ -223,6 +230,17 @@ AC_CHECK_TYPE(iconv_t,:,
- #endif
- ])
-
-+AC_ARG_ENABLE(selinux,
-+ AC_HELP_STRING([--enable-selinux],
-+ [enable SELinux support (disabled by default)]),
-+ [selinux_enabled=$enableval],
-+ [selinux_enabled=no])
-+
-+if test "x$selinux_enabled" = xyes; then
-+ AC_CHECK_LIB(selinux, getfilecon)
-+ AC_CHECK_HEADERS(selinux/selinux.h)
-+fi
-+
- # Gettext.
- AM_GNU_GETTEXT([external], [need-formatstring-macros])
- AM_GNU_GETTEXT_VERSION([0.16])
-diff -urNp tar-1.23-orig/doc/tar.texi tar-1.23/doc/tar.texi
---- tar-1.23-orig/doc/tar.texi 2010-08-16 14:29:00.421912230 +0200
-+++ tar-1.23/doc/tar.texi 2010-08-16 14:32:11.459923196 +0200
-@@ -2364,6 +2364,10 @@ Normally when creating an archive, @comm
- @samp{/} from member names. This option disables that behavior.
- @xref{absolute}.
-
-+@opsummary{acl}
-+@item --acls
-+Causes @command{tar} to store ACL's. @xref{Attributes}.
-+
- @opsummary{after-date}
- @item --after-date
-
-@@ -2885,6 +2889,10 @@ contents have changed (as opposed to jus
- also back up files for which any status information has
- changed). @xref{after}.
-
-+@opsummary{no-acl}
-+@item --no-acls
-+Causes @command{tar} not to store and not to extract ACL's. @xref{Attributes}.
-+
- @opsummary{no-anchored}
- @item --no-anchored
- An exclude pattern can match any subsequence of the name's components.
-@@ -2968,11 +2976,21 @@ locations. Usually @command{tar} determ
- the archive can be seeked or not. Use this option to disable this
- mechanism.
-
-+@opsummary{no-selinux}
-+@item --no-selinux
-+Causes @command{tar} not to store and not to extract SELinux security context.
-+@xref{Attributes}.
-+
- @opsummary{no-unquote}
- @item --no-unquote
- Treat all input file or member names literally, do not interpret
- escape sequences. @xref{input name quoting}.
-
-+@opsummary{no-xattrs}
-+@item --no-xattrs
-+Causes @command{tar} not to store and not to extract xattrs. This option also
-+enables @option{--no-selinux} and @option{--no-acls}. @xref{Attributes}.
-+
- @opsummary{no-wildcards}
- @item --no-wildcards
- Do not use wildcards.
-@@ -3202,6 +3220,11 @@ in cases when such recognition fails. I
- archive is open for reading (e.g. with @option{--list} or
- @option{--extract} options).
-
-+@opsummary{selinux}
-+@item --selinux
-+Causes @command{tar} to store SElinux security context. @xref{Attributes}.
-+
-+
- @opsummary{show-defaults}
- @item --show-defaults
-
-@@ -3411,6 +3434,11 @@ Enable or disable warning messages ident
- messages are suppressed if @var{keyword} is prefixed with @samp{no-}.
- @xref{warnings}.
-
-+@opsummary{xattrs}
-+@item --xattrs
-+Causes @command{tar} to store xattrs. This option also enables
-+@option{--selinux} and @option{--acls}. @xref{Attributes}.
-+
- @opsummary{wildcards}
- @item --wildcards
- Use wildcards when matching member names with patterns.
-@@ -8599,6 +8627,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{}.
-@@ -9160,6 +9190,51 @@ Same as both @option{--same-permissions}
-
- This option is deprecated, and will be removed in @GNUTAR{} version 1.23.
-
-+@opindex acls
-+@item --acls
-+This option causes @command{tar} to store the current ACL in the archive.
-+
-+The @option{--acls} option has no equivalent short option name.
-+
-+@opindex selinux
-+@item --selinux
-+This option causes @command{tar} to store the current 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 the current extended attributes in
-+the 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.
-+
-+@opindex no-acls
-+@item --no-acls
-+This option causes @command{tar} not to store the current ACL in the archive
-+and not to extract any ACL information in an archive.
-+
-+The @option{--no-acls} option has no equivalent short option name.
-+
-+@opindex no-selinux
-+@item --no-selinux
-+This option causes @command{tar} not to store the current SELinux security
-+context information in the archive and not to extract any SELinux information in
-+an archive.
-+
-+The @option{--no-selinux} option has no equivalent short option name.
-+
-+@opindex no-xattrs
-+@item --no-xattrs
-+This option causes @command{tar} not to store the current extended attributes in
-+the archive and not to extract any extended attributes in an archive. This
-+option also enables @option{--no-acls} and @option{--no-selinux} if
-+they haven't been set already.
-+
-+The @option{--no-xattrs} option has no equivalent short option name.
-+
- @end table
-
- @node Portability
-diff -urNp tar-1.23-orig/src/common.h tar-1.23/src/common.h
---- tar-1.23-orig/src/common.h 2010-01-26 13:21:18.000000000 +0100
-+++ tar-1.23/src/common.h 2010-08-16 14:32:11.464922567 +0200
-@@ -251,6 +251,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;
-@@ -732,6 +741,9 @@ extern char *output_start;
-
- void update_archive (void);
-
-+/* Module attrs.c. */
-+#include "xattrs.h"
-+
- /* Module xheader.c. */
-
- void xheader_init (struct xheader *xhdr);
-@@ -753,6 +765,12 @@ bool xheader_string_end (struct xheader
- 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 */
-
-diff -urNp tar-1.23-orig/src/create.c tar-1.23/src/create.c
---- tar-1.23-orig/src/create.c 2010-08-16 14:29:00.431912370 +0200
-+++ tar-1.23/src/create.c 2010-08-16 14:32:11.465912091 +0200
-@@ -24,6 +24,7 @@
- #include
-
- #include "common.h"
-+
- #include
-
- struct link
-@@ -954,6 +955,30 @@ start_header (struct tar_stat_info *st)
- GNAME_TO_CHARS (st->gname, header->header.gname);
- }
-
-+ if (archive_format == POSIX_FORMAT)
-+ {
-+ if (acls_option > 0)
-+ {
-+ if (st->acls_a_ptr)
-+ xheader_store ("SCHILY.acl.access", st, NULL);
-+ if (st->acls_d_ptr)
-+ xheader_store ("SCHILY.acl.default", st, NULL);
-+ }
-+ if ((selinux_context_option > 0) && st->cntx_name)
-+ xheader_store ("RHT.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;
- }
-
-@@ -1587,6 +1612,10 @@ dump_file0 (struct tar_stat_info *st, co
- }
- }
-
-+ xattrs_acls_get(st, p, fd, !is_dir);
-+ xattrs_selinux_get(st, p, fd);
-+ xattrs_xattrs_get(st, p, fd);
-+
- if (is_dir)
- {
- const char *tag_file_name;
-@@ -1710,6 +1739,9 @@ dump_file0 (struct tar_stat_info *st, co
- if (NAME_FIELD_SIZE - (archive_format == OLDGNU_FORMAT) < size)
- write_long_link (st);
-
-+ xattrs_selinux_get(st, p, -1);
-+ xattrs_xattrs_get(st, p, -1);
-+
- block_ordinal = current_block_ordinal ();
- st->stat.st_size = 0; /* force 0 size on symlink */
- header = start_header (st);
-@@ -1728,11 +1760,23 @@ dump_file0 (struct tar_stat_info *st, co
- }
- #endif
- else if (S_ISCHR (st->stat.st_mode))
-- type = CHRTYPE;
-+ {
-+ type = CHRTYPE;
-+ xattrs_selinux_get(st, p, -1);
-+ xattrs_xattrs_get(st, p, -1);
-+ }
- else if (S_ISBLK (st->stat.st_mode))
-- type = BLKTYPE;
-+ {
-+ type = BLKTYPE;
-+ xattrs_selinux_get(st, p, -1);
-+ xattrs_xattrs_get(st, p, -1);
-+ }
- else if (S_ISFIFO (st->stat.st_mode))
-- type = FIFOTYPE;
-+ {
-+ type = FIFOTYPE;
-+ xattrs_selinux_get(st, p, -1);
-+ xattrs_xattrs_get(st, p, -1);
-+ }
- else if (S_ISSOCK (st->stat.st_mode))
- {
- WARNOPT (WARN_FILE_IGNORED,
-diff -urNp tar-1.23-orig/src/extract.c tar-1.23/src/extract.c
---- tar-1.23-orig/src/extract.c 2010-01-26 12:28:09.000000000 +0100
-+++ tar-1.23/src/extract.c 2010-08-16 14:32:11.467922288 +0200
-@@ -70,6 +70,13 @@ struct delayed_set_stat
- mode_t invert_permissions;
- enum permstatus permstatus;
- bool after_links;
-+ char *cntx_name;
-+ char *acls_a_ptr;
-+ size_t acls_a_len;
-+ char *acls_d_ptr;
-+ size_t acls_d_len;
-+ size_t xattr_map_size; /* Size of the xattr map */
-+ struct xattr_array *xattr_map;
- char file_name[1];
- };
-
-@@ -97,6 +104,18 @@ struct delayed_link
- hard-linked together. */
- struct string_list *sources;
-
-+ /* SELinux context */
-+ char *cntx_name;
-+
-+ /* ACLs */
-+ char *acls_a_ptr;
-+ size_t acls_a_len;
-+ char *acls_d_ptr;
-+ size_t acls_d_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];
- };
-@@ -290,6 +309,10 @@ set_stat (char const *file_name,
- give files away. */
- }
-
-+ 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
-@@ -366,6 +389,29 @@ 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_a_ptr)
-+ {
-+ data->acls_a_ptr = xmemdup(st->acls_a_ptr, st->acls_a_len + 1);
-+ data->acls_a_len = st->acls_a_len;
-+ }
-+ else
-+ {
-+ data->acls_a_ptr = NULL;
-+ data->acls_a_len = 0;
-+ }
-+ if (st->acls_d_ptr)
-+ {
-+ data->acls_d_ptr = xmemdup(st->acls_d_ptr, st->acls_d_len + 1);
-+ data->acls_d_len = st->acls_d_len;
-+ }
-+ else
-+ {
-+ data->acls_d_ptr = NULL;
-+ data->acls_d_len = 0;
-+ }
-+ xheader_xattr_copy (st, &data->xattr_map, &data->xattr_map_size);
- strcpy (data->file_name, file_name);
- delayed_set_stat_head = data;
- }
-@@ -571,6 +617,31 @@ maybe_recoverable (char *file_name, int
- }
- }
-
-+/* Restore stat extended attributes (xattr) for FILE_NAME, using information
-+ given in *ST. Restore before extraction because they may affect layout.
-+ If not restoring permissions, invert the
-+ INVERT_PERMISSIONS bits from the file's current permissions.
-+ TYPEFLAG specifies the type of the file.
-+ FILE_CREATED indicates set_xattr has created the file */
-+static int
-+set_xattr (char const *file_name, struct tar_stat_info const *st,
-+ mode_t invert_permissions, char typeflag, int *file_created)
-+{
-+ int status = 0;
-+ int interdir_made = 0;
-+
-+ if ((xattrs_option >= 0) && st->xattr_map_size) {
-+ mode_t mode = current_stat_info.stat.st_mode & MODE_RWX & ~ current_umask;
-+
-+ do
-+ status = mknod (file_name, mode ^ invert_permissions, 0);
-+ while (status && maybe_recoverable ((char *)file_name, &interdir_made));
-+ xattrs_xattrs_set(st, file_name, typeflag);
-+ *file_created = 1;
-+ }
-+ return(status);
-+}
-+
- /* Fix the statuses of all directories whose statuses need fixing, and
- which are not ancestors of FILE_NAME. If AFTER_LINKS is
- nonzero, do this for all such directories; otherwise, stop at the
-@@ -624,11 +695,22 @@ apply_nonancestor_delayed_set_stat (char
- sb.stat.st_gid = data->gid;
- sb.atime = data->atime;
- sb.mtime = data->mtime;
-+ sb.cntx_name = data->cntx_name;
-+ sb.acls_a_ptr = data->acls_a_ptr;
-+ sb.acls_a_len = data->acls_a_len;
-+ sb.acls_d_ptr = data->acls_d_ptr;
-+ sb.acls_d_len = data->acls_d_len;
-+ sb.xattr_map = data->xattr_map;
-+ sb.xattr_map_size = data->xattr_map_size;
- set_stat (data->file_name, &sb, 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_a_ptr);
-+ free (data->acls_d_ptr);
- free (data);
- }
- }
-@@ -730,7 +812,7 @@ extract_dir (char *file_name, int typefl
-
-
- static int
--open_output_file (char *file_name, int typeflag, mode_t mode)
-+open_output_file (char *file_name, int typeflag, mode_t mode, int file_created)
- {
- int fd;
- int openflag = (O_WRONLY | O_BINARY | O_CREAT
-@@ -738,6 +820,10 @@ open_output_file (char *file_name, int t
- ? O_TRUNC
- : O_EXCL));
-
-+ /* File might be created in set_xattr. So clear O_EXCL to avoid open() failure */
-+ if (file_created)
-+ openflag = openflag & ~O_EXCL;
-+
- #if O_CTG
- /* Contiguous files (on the Masscomp) have to specify the size in
- the open call that creates them. */
-@@ -796,8 +882,18 @@ extract_file (char *file_name, int typef
- else
- {
- int recover = RECOVER_NO;
-+ int file_created = 0;
-+ if (set_xattr (file_name, ¤t_stat_info, invert_permissions,
-+ typeflag, &file_created))
-+ {
-+ skip_member ();
-+ open_error (file_name);
-+ return 1;
-+ }
-+
- do
-- fd = open_output_file (file_name, typeflag, mode ^ invert_permissions);
-+ fd = open_output_file (file_name, typeflag, mode ^ invert_permissions,
-+ file_created);
- while (fd < 0
- && (recover = maybe_recoverable (file_name, &interdir_made))
- == RECOVER_OK);
-@@ -922,6 +1018,13 @@ create_placeholder_file (char *file_name
- + strlen (file_name) + 1);
- p->sources->next = 0;
- strcpy (p->sources->string, file_name);
-+ p->cntx_name = NULL;
-+ assign_string (&p->cntx_name, current_stat_info.cntx_name);
-+ p->acls_a_ptr = NULL;
-+ p->acls_a_len = 0;
-+ p->acls_d_ptr = NULL;
-+ p->acls_d_len = 0;
-+ xheader_xattr_copy (¤t_stat_info, &p->xattr_map, &p->xattr_map_size);
- strcpy (p->target, current_stat_info.link_name);
-
- h = delayed_set_stat_head;
-@@ -1335,6 +1438,13 @@ 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_a_ptr = ds->acls_a_ptr;
-+ st1.acls_a_len = ds->acls_a_len;
-+ st1.acls_d_ptr = ds->acls_d_ptr;
-+ st1.acls_d_len = ds->acls_d_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;
- }
-@@ -1348,6 +1458,9 @@ apply_delayed_links (void)
- sources = next;
- }
-
-+ xheader_xattr_free (ds->xattr_map, ds->xattr_map_size);
-+ free (ds->cntx_name);
-+
- {
- struct delayed_link *next = ds->next;
- free (ds);
-diff -urNp tar-1.23-orig/src/list.c tar-1.23/src/list.c
---- tar-1.23-orig/src/list.c 2010-08-16 14:29:00.411912161 +0200
-+++ tar-1.23/src/list.c 2010-08-16 14:32:11.468912021 +0200
-@@ -586,6 +586,13 @@ decode_header (union block *header, stru
- assign_string (&stat_info->gname,
- header->header.gname[0] ? header->header.gname : NULL);
-
-+ stat_info->acls_a_ptr = NULL;
-+ stat_info->acls_a_len = 0;
-+ stat_info->acls_d_ptr = NULL;
-+ stat_info->acls_d_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);
-diff -urNp tar-1.23-orig/src/Makefile.am tar-1.23/src/Makefile.am
---- tar-1.23-orig/src/Makefile.am 2010-01-26 12:30:20.000000000 +0100
-+++ tar-1.23/src/Makefile.am 2010-08-16 14:32:11.469911951 +0200
-@@ -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\
- checkpoint.c\
-@@ -42,10 +42,11 @@ tar_SOURCES = \
- unlink.c\
- update.c\
- utf8.c\
-- warning.c
-+ warning.c\
-+ xattrs.c
-
- INCLUDES = -I$(top_srcdir)/gnu -I../ -I../gnu -I$(top_srcdir)/lib -I../lib
-
- LDADD = ../lib/libtar.a ../gnu/libgnu.a $(LIBINTL) $(LIBICONV)
-
--tar_LDADD = $(LDADD) $(LIB_CLOCK_GETTIME)
-+tar_LDADD = $(LIBS) $(LDADD) $(LIB_CLOCK_GETTIME)
-diff -urNp tar-1.23-orig/src/tar.c tar-1.23/src/tar.c
---- tar-1.23-orig/src/tar.c 2010-08-16 14:29:00.433923894 +0200
-+++ tar-1.23/src/tar.c 2010-08-16 14:32:11.472912580 +0200
-@@ -255,7 +255,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,
- CHECK_DEVICE_OPTION,
-@@ -287,6 +288,7 @@ enum
- MODE_OPTION,
- MTIME_OPTION,
- NEWER_MTIME_OPTION,
-+ NO_ACLS_OPTION,
- NO_ANCHORED_OPTION,
- NO_AUTO_COMPRESS_OPTION,
- NO_CHECK_DEVICE_OPTION,
-@@ -300,9 +302,11 @@ enum
- NO_SAME_OWNER_OPTION,
- NO_SAME_PERMISSIONS_OPTION,
- NO_SEEK_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,
-@@ -324,6 +328,7 @@ enum
- RMT_COMMAND_OPTION,
- RSH_COMMAND_OPTION,
- SAME_OWNER_OPTION,
-+ SELINUX_CONTEXT_OPTION,
- SHOW_DEFAULTS_OPTION,
- SHOW_OMITTED_DIRS_OPTION,
- SHOW_TRANSFORMED_NAMES_OPTION,
-@@ -339,7 +344,8 @@ enum
- VOLNO_FILE_OPTION,
- WARNING_OPTION,
- WILDCARDS_MATCH_SLASH_OPTION,
-- WILDCARDS_OPTION
-+ WILDCARDS_OPTION,
-+ XATTR_OPTION
- };
-
- const char *argp_program_version = "tar (" PACKAGE_NAME ") " VERSION;
-@@ -485,6 +491,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,
-@@ -515,6 +525,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,
-@@ -2063,6 +2081,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;
-@@ -2445,6 +2494,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;
-@@ -2665,11 +2737,15 @@ 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_a_ptr);
-+ free (st->acls_d_ptr);
- free (st->sparse_map);
- free (st->dumpdir);
- xheader_destroy (&st->xhdr);
-diff -urNp tar-1.23-orig/src/tar.h tar-1.23/src/tar.h
---- tar-1.23-orig/src/tar.h 2010-01-26 12:30:20.000000000 +0100
-+++ tar-1.23/src/tar.h 2010-08-16 14:32:11.473924383 +0200
-@@ -276,6 +276,14 @@ struct xheader
- uintmax_t string_length;
- };
-
-+/* 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 */
-@@ -287,6 +295,15 @@ 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_a_ptr; /* Access ACLs for the current archive entry. */
-+ size_t acls_a_len; /* Access ACLs for the current archive entry. */
-+
-+ char *acls_d_ptr; /* Default ACLs for the current archive entry. */
-+ size_t acls_d_len; /* Default ACLs for the current archive entry. */
-+
- struct stat stat; /* regular filesystem stat */
-
- /* STAT doesn't always have access, data modification, and status
-@@ -309,6 +326,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;
-+
- /* Extended headers */
- struct xheader xhdr;
-
-diff -urNp tar-1.23-orig/src/xattrs.c tar-1.23/src/xattrs.c
---- tar-1.23-orig/src/xattrs.c 1970-01-01 01:00:00.000000000 +0100
-+++ tar-1.23/src/xattrs.c 2010-08-16 14:34:12.554509938 +0200
-@@ -0,0 +1,489 @@
-+/* 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
-+
-+#include
-+
-+#include "common.h"
-+
-+
-+#ifndef HAVE_SELINUX_SELINUX_H
-+# undef HAVE_LIBSELINUX
-+#endif
-+
-+#ifndef HAVE_ATTR_XATTR_H
-+# undef HAVE_XATTRS
-+#endif
-+
-+#ifndef HAVE_SYS_ACL_H
-+# undef HAVE_LIBACL
-+#endif
-+
-+#ifdef HAVE_SELINUX_SELINUX_H
-+# include
-+#endif
-+
-+#ifdef HAVE_ATTR_XATTR_H
-+# include
-+#endif
-+
-+#ifdef HAVE_SYS_ACL_H
-+# include
-+#endif
-+
-+
-+#if 0 /* unused by xattr's atm. */
-+static void xattrs__fd_get(struct tar_stat_info *st,
-+ char const *file_name, int fd, const char *attr,
-+ char **ret_ptr, size_t *ret_len)
-+{
-+#ifdef HAVE_XATTRS
-+ static ssize_t asz = 1024;
-+ ssize_t ret = 0;
-+ static char *val = NULL;
-+
-+ if (!val) val = xmalloc (asz);
-+
-+ while (((ret = fgetxattr (fd, attr, val, asz)) == -1) &&
-+ (errno == ERANGE))
-+ {
-+ asz <<= 1;
-+ val = xrealloc (val, asz);
-+ }
-+
-+ if (ret != -1)
-+ {
-+ *ret_ptr = xmemdup (val, ret + 1);
-+ *ret_len = ret;
-+ }
-+ else if (errno != ENOATTR)
-+ call_arg_warn ("fgetxattr", file_name);
-+#endif
-+}
-+#endif
-+
-+static void xattrs__acls_get_a(struct tar_stat_info *st,
-+ char const *file_name, int fd,
-+ char **ret_ptr, size_t *ret_len)
-+{ /* "system.posix_acl_access" */
-+#ifdef HAVE_LIBACL
-+ char *val = NULL;
-+ ssize_t len;
-+ acl_t acl;
-+
-+ if (fd != -1)
-+ {
-+ if ((acl = acl_get_fd (fd)) == (acl_t)NULL)
-+ {
-+ if (errno != ENOTSUP)
-+ call_arg_warn ("acl_get_fd", file_name);
-+ return;
-+ }
-+ }
-+ else if ((acl = acl_get_file (file_name, ACL_TYPE_ACCESS)) == (acl_t)NULL)
-+ {
-+ if (errno != ENOTSUP)
-+ call_arg_warn ("acl_get_file", file_name);
-+ return;
-+ }
-+
-+
-+ val = acl_to_text(acl, &len);
-+ acl_free (acl);
-+
-+ if (val == NULL)
-+ {
-+ call_arg_warn ("acl_to_text", file_name);
-+ return;
-+ }
-+
-+ *ret_ptr = xstrdup (val);
-+ *ret_len = len;
-+
-+ acl_free (val);
-+#endif
-+}
-+
-+static void xattrs__acls_get_d(struct tar_stat_info *st,
-+ char const *file_name,
-+ char **ret_ptr, size_t *ret_len)
-+{ /* "system.posix_acl_default" */
-+#ifdef HAVE_LIBACL
-+ char *val = NULL;
-+ ssize_t len;
-+ acl_t acl;
-+
-+ if ((acl = acl_get_file (file_name, ACL_TYPE_DEFAULT)) == (acl_t)NULL)
-+ {
-+ if (errno != ENOTSUP)
-+ call_arg_warn ("acl_get_file", file_name);
-+ return;
-+ }
-+
-+ val = acl_to_text(acl, &len);
-+ acl_free (acl);
-+
-+ if (val == NULL)
-+ {
-+ call_arg_warn ("acl_to_text", file_name);
-+ return;
-+ }
-+
-+ *ret_ptr = xstrdup (val);
-+ *ret_len = len;
-+
-+ acl_free (val);
-+#endif
-+}
-+
-+void xattrs_acls_get(struct tar_stat_info *st, char const *file_name, int fd,
-+ int xisfile)
-+{
-+ if (acls_option > 0)
-+ {
-+#ifndef HAVE_LIBACL
-+ static int done = 0;
-+ if (!done)
-+ WARN ((0, 0, _("ACL support requested, but not available")));
-+ done = 1;
-+#endif
-+ xattrs__acls_get_a (st, file_name, fd,
-+ &st->acls_a_ptr, &st->acls_a_len);
-+ if (!xisfile)
-+ xattrs__acls_get_d (st, file_name,
-+ &st->acls_d_ptr, &st->acls_d_len);
-+ }
-+}
-+
-+void xattrs_selinux_get(struct tar_stat_info *st, char const *file_name, int fd)
-+{
-+ if (selinux_context_option > 0)
-+ {
-+#ifndef HAVE_LIBSELINUX
-+ static int done = 0;
-+ if (!done)
-+ WARN ((0, 0, _("SELinux support requested, but not available")));
-+ done = 1;
-+#else
-+ if (fd == -1)
-+ {
-+ if ((lgetfilecon (file_name, &st->cntx_name) == -1) && (errno != ENOTSUP) && (errno != ENODATA))
-+ call_arg_warn ("lgetfilecon", file_name);
-+ }
-+ else if ((fgetfilecon (fd, &st->cntx_name) == -1) && (errno != ENOTSUP) && (errno != ENODATA))
-+ call_arg_warn ("fgetfilecon", file_name);
-+#endif
-+ }
-+}
-+
-+void xattrs_xattrs_get(struct tar_stat_info *st, char const *file_name, int fd)
-+{
-+ 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;
-+
-+#ifndef HAVE_XATTRS
-+ static int done = 0;
-+ if ((xattrs_option > 0) && !done)
-+ WARN ((0, 0, _("Xattr support requested, but not available")));
-+ done = 1;
-+#else
-+
-+ if (!xatrs) xatrs = xmalloc (xsz);
-+
-+ while (((fd == -1) ?
-+ ((xret = llistxattr (file_name, xatrs, xsz)) == -1) :
-+ ((xret = flistxattr (fd, xatrs, xsz)) == -1)) &&
-+ (errno == ERANGE))
-+ {
-+ xsz <<= 1;
-+ xatrs = xrealloc (xatrs, xsz);
-+ }
-+
-+ if (xret == -1)
-+ call_arg_warn ((fd == -1) ? "llistxattrs" : "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;
-+
-+ /* Archive all xattrs during creation, decide at extraction time
-+ * which ones are of interest/use for the target filesystem. */
-+ while (((fd == -1) ?
-+ ((aret = lgetxattr (file_name, attr, val, asz)) == -1) :
-+ ((aret = fgetxattr (fd, attr, val, asz)) == -1)) &&
-+ (errno == ERANGE))
-+ {
-+ asz <<= 1;
-+ val = xrealloc (val, asz);
-+ }
-+
-+ if (aret != -1)
-+ xheader_xattr_add (st, attr, val, aret);
-+ else if (errno != ENOATTR)
-+ call_arg_warn ((fd==-1) ? "lgetxattr" : "fgetxattr", file_name);
-+
-+ attr += len + 1;
-+ xret -= len + 1;
-+ }
-+ }
-+#endif
-+ }
-+}
-+
-+static void xattrs__fd_set(struct tar_stat_info const *st,
-+ char const *file_name, char typeflag,
-+ const char *attr,
-+ const char *ptr, size_t len)
-+{
-+#ifdef HAVE_XATTRS
-+ if (ptr)
-+ {
-+ const char *sysname = "setxattr";
-+ int ret = -1;
-+
-+ if (typeflag != SYMTYPE)
-+ ret = setxattr (file_name, attr, ptr, len, 0);
-+ else
-+ {
-+ sysname = "lsetxattr";
-+ ret = lsetxattr (file_name, attr, ptr, len, 0);
-+ }
-+
-+ /* do not print warnings when SELinux is disabled */
-+ if ((ret == -1) && (errno != EPERM) && (errno != ENOTSUP))
-+ call_arg_error(sysname, file_name);
-+ }
-+#endif
-+}
-+
-+/* convert unix permissions into an ACL ... needed due to "default" ACLs */
-+#ifdef HAVE_LIBACL
-+static acl_t perms2acl(int perms)
-+{
-+ char val[] = "user::---,group::---,other::---";
-+ /* 0123456789 123456789 123456789 123456789 */
-+
-+ /* user */
-+ if (perms & 0400) val[ 6] = 'r';
-+ if (perms & 0200) val[ 7] = 'w';
-+ if (perms & 0100) val[ 8] = 'x';
-+
-+ /* group */
-+ if (perms & 0040) val[17] = 'r';
-+ if (perms & 0020) val[18] = 'w';
-+ if (perms & 0010) val[19] = 'x';
-+
-+ /* other */
-+ if (perms & 0004) val[28] = 'r';
-+ if (perms & 0002) val[29] = 'w';
-+ if (perms & 0001) val[30] = 'x';
-+
-+ return (acl_from_text (val));
-+}
-+#endif
-+
-+static char *skip_to_ext_fields(char *ptr)
-+{
-+ ptr += strcspn(ptr, ":,\n"); /* skip tag name. Ie. user/group/default/mask */
-+
-+ if (*ptr != ':')
-+ return (ptr); /* error? no user/group field */
-+ ++ptr;
-+
-+ ptr += strcspn(ptr, ":,\n"); /* skip user/group name */
-+
-+ if (*ptr != ':')
-+ return (ptr); /* error? no perms field */
-+ ++ptr;
-+
-+ ptr += strcspn(ptr, ":,\n"); /* skip perms */
-+
-+ if (*ptr != ':')
-+ return (ptr); /* no extra fields */
-+
-+ return (ptr);
-+}
-+
-+/* The POSIX draft allows extra fields after the three main ones. Star
-+ uses this to add a fourth field for user/group which is the numeric ID.
-+ We just skip all extra fields atm. */
-+static const char *fixup_extra_acl_fields(const char *ptr)
-+{
-+ char *src = (char *)ptr;
-+ char *dst = (char *)ptr;
-+
-+ while (*src)
-+ {
-+ const char *old = src;
-+ size_t len = 0;
-+
-+ src = skip_to_ext_fields(src);
-+ len = src - old;
-+ if (old != dst) memmove(dst, old, len);
-+ dst += len;
-+
-+ if (*src == ':') /* We have extra fields, skip them all */
-+ src += strcspn(src, "\n,");
-+
-+ if ((*src == '\n') || (*src == ','))
-+ *dst++ = *src++; /* also done when dst == src, but that's ok */
-+ }
-+ if (src != dst)
-+ *dst = 0;
-+
-+ return ptr;
-+}
-+
-+static void xattrs__acls_set(struct tar_stat_info const *st,
-+ char const *file_name, int type,
-+ const char *ptr, size_t len)
-+{ /* "system.posix_acl_access" */
-+#ifdef HAVE_LIBACL
-+ acl_t acl;
-+
-+ if (ptr)
-+ {
-+ /* assert (strlen (ptr) == len); */
-+ ptr = fixup_extra_acl_fields(ptr);
-+
-+ acl = acl_from_text (ptr);
-+ acls_option = 1;
-+ }
-+ else if (acls_option > 0)
-+ acl = perms2acl (st->stat.st_mode);
-+ else
-+ return; /* don't call acl functions unless we first hit an ACL, or
-+ --acls was passed explicitly */
-+
-+ if (acl == (acl_t)NULL)
-+ {
-+ call_arg_warn ("acl_from_text", file_name);
-+ return;
-+ }
-+
-+ if (acl_set_file (file_name, type, acl) == -1)
-+ {
-+ if (errno != ENOTSUP)
-+ call_arg_warn ("acl_set_file", file_name);
-+ }
-+ acl_free (acl);
-+#endif
-+}
-+
-+void xattrs_acls_set(struct tar_stat_info const *st,
-+ char const *file_name, char typeflag)
-+{
-+ if ((acls_option >= 0) && (typeflag != SYMTYPE))
-+ {
-+#ifndef HAVE_LIBACL
-+ static int done = 0;
-+ if (!done)
-+ WARN ((0, 0, _("ACL support requested, but not available")));
-+ done = 1;
-+#else
-+ xattrs__acls_set (st, file_name, ACL_TYPE_ACCESS,
-+ st->acls_a_ptr, st->acls_a_len);
-+ if ((typeflag == DIRTYPE) || (typeflag == GNUTYPE_DUMPDIR))
-+ xattrs__acls_set (st, file_name, ACL_TYPE_DEFAULT,
-+ st->acls_d_ptr, st->acls_d_len);
-+#endif
-+ }
-+}
-+
-+void xattrs_selinux_set(struct tar_stat_info const *st,
-+ char const *file_name, char typeflag)
-+{
-+ if ((selinux_context_option >= 0) && st->cntx_name)
-+ {
-+ const char *sysname = "setfilecon";
-+ int ret = -1;
-+
-+#ifndef HAVE_LIBSELINUX
-+ static int done = 0;
-+ if (!done)
-+ WARN ((0, 0, _("SELinux support requested, but not available")));
-+ done = 1;
-+#else
-+ 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)
-+{
-+ if ((xattrs_option >= 0) && st->xattr_map_size)
-+ {
-+ size_t scan = 0;
-+
-+#ifndef HAVE_XATTRS
-+ static int done = 0;
-+ if (!done)
-+ WARN ((0, 0, _("Xattr support requested, but not available")));
-+ done = 1;
-+#else
-+ 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, "lustre.", strlen("lustre.")) &&
-+ strncmp (keyword, "trusted.", strlen("trusted.")) &&
-+ strncmp (keyword, "security.NTACL", strlen("security.NTACL")))
-+ continue; /* don't try and set anything but normal xattrs */
-+
-+ xattrs__fd_set (st, file_name, typeflag, keyword,
-+ st->xattr_map[scan].xval_ptr,
-+ st->xattr_map[scan].xval_len);
-+
-+ ++scan;
-+ }
-+#endif
-+ }
-+}
-diff -urNp tar-1.23-orig/src/xattrs.h tar-1.23/src/xattrs.h
---- tar-1.23-orig/src/xattrs.h 1970-01-01 01:00:00.000000000 +0100
-+++ tar-1.23/src/xattrs.h 2010-08-16 14:32:11.475920821 +0200
-@@ -0,0 +1,14 @@
-+
-+extern void xattrs_acls_get(struct tar_stat_info *st,
-+ char const *file_name, int fd, int xisfile);
-+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);
-diff -urNp tar-1.23-orig/src/xheader.c tar-1.23/src/xheader.c
---- tar-1.23-orig/src/xheader.c 2010-02-12 11:03:09.000000000 +0100
-+++ tar-1.23/src/xheader.c 2010-08-16 14:38:39.480912020 +0200
-@@ -459,6 +459,74 @@ xheader_write_global (struct xheader *xh
- }
- }
-
-+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 + 1);
-+ (*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 */
-
-@@ -472,6 +540,7 @@ struct xhdr_tab
- struct xheader *, void const *data);
- void (*decoder) (struct tar_stat_info *, char const *, char const *, size_t);
- int flags;
-+ bool prefix;
- };
-
- /* This declaration must be extern, because ISO C99 section 6.9.2
-@@ -488,8 +557,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;
- }
-
-@@ -499,7 +577,7 @@ xheader_protected_pattern_p (const char
- struct xhdr_tab const *p;
-
- for (p = xhdr_tab; p->keyword; p++)
-- if ((p->flags & XHDR_PROTECTED) && fnmatch (pattern, p->keyword, 0) == 0)
-+ if (!p->prefix && (p->flags & XHDR_PROTECTED) && fnmatch (pattern, p->keyword, 0) == 0)
- return true;
- return false;
- }
-@@ -510,7 +588,7 @@ xheader_protected_keyword_p (const char
- struct xhdr_tab const *p;
-
- for (p = xhdr_tab; p->keyword; p++)
-- if ((p->flags & XHDR_PROTECTED) && strcmp (p->keyword, keyword) == 0)
-+ if (!p->prefix && (p->flags & XHDR_PROTECTED) && strcmp (p->keyword, keyword) == 0)
- return true;
- return false;
- }
-@@ -1469,6 +1547,71 @@ volume_filename_decoder (struct tar_stat
- }
-
- static void
-+xattr_selinux_coder (struct tar_stat_info const *st, char const *keyword,
-+ struct xheader *xhdr, void const *data)
-+{
-+ code_string (st->cntx_name, keyword, xhdr);
-+}
-+
-+static void
-+xattr_selinux_decoder (struct tar_stat_info *st,
-+ char const *keyword, char const *arg, size_t size)
-+{
-+ decode_string (&st->cntx_name, arg);
-+}
-+
-+static void
-+xattr_acls_a_coder (struct tar_stat_info const *st , char const *keyword,
-+ struct xheader *xhdr, void const *data)
-+{
-+ xheader_print_n (xhdr, keyword, st->acls_a_ptr, st->acls_a_len);
-+}
-+
-+static void
-+xattr_acls_a_decoder (struct tar_stat_info *st,
-+ char const *keyword, char const *arg, size_t size)
-+{
-+ st->acls_a_ptr = xmemdup (arg, size + 1);
-+ st->acls_a_len = size;
-+}
-+
-+static void
-+xattr_acls_d_coder (struct tar_stat_info const *st , char const *keyword,
-+ struct xheader *xhdr, void const *data)
-+{
-+ xheader_print_n (xhdr, keyword, st->acls_d_ptr, st->acls_d_len);
-+}
-+
-+static void
-+xattr_acls_d_decoder (struct tar_stat_info *st,
-+ char const *keyword, char const *arg, size_t size)
-+{
-+ st->acls_d_ptr = xmemdup (arg, size + 1);
-+ st->acls_d_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);
-+}
-+
-+static void
- sparse_major_coder (struct tar_stat_info const *st, char const *keyword,
- struct xheader *xhdr, void const *data)
- {
-@@ -1505,53 +1648,53 @@ sparse_minor_decoder (struct tar_stat_in
- }
-
- struct xhdr_tab const xhdr_tab[] = {
-- { "atime", atime_coder, atime_decoder, 0 },
-- { "comment", dummy_coder, dummy_decoder, 0 },
-- { "charset", dummy_coder, dummy_decoder, 0 },
-- { "ctime", ctime_coder, ctime_decoder, 0 },
-- { "gid", gid_coder, gid_decoder, 0 },
-- { "gname", gname_coder, gname_decoder, 0 },
-- { "linkpath", linkpath_coder, linkpath_decoder, 0 },
-- { "mtime", mtime_coder, mtime_decoder, 0 },
-- { "path", path_coder, path_decoder, 0 },
-- { "size", size_coder, size_decoder, 0 },
-- { "uid", uid_coder, uid_decoder, 0 },
-- { "uname", uname_coder, uname_decoder, 0 },
-+ { "atime", atime_coder, atime_decoder, 0, false },
-+ { "comment", dummy_coder, dummy_decoder, 0, false },
-+ { "charset", dummy_coder, dummy_decoder, 0, false },
-+ { "ctime", ctime_coder, ctime_decoder, 0, false },
-+ { "gid", gid_coder, gid_decoder, 0, false },
-+ { "gname", gname_coder, gname_decoder, 0, false },
-+ { "linkpath", linkpath_coder, linkpath_decoder, 0, false },
-+ { "mtime", mtime_coder, mtime_decoder, 0, false },
-+ { "path", path_coder, path_decoder, 0, false },
-+ { "size", size_coder, size_decoder, 0, false },
-+ { "uid", uid_coder, uid_decoder, 0, false },
-+ { "uname", uname_coder, uname_decoder, 0, false },
-
- /* Sparse file handling */
- { "GNU.sparse.name", path_coder, path_decoder,
-- XHDR_PROTECTED },
-+ XHDR_PROTECTED, false },
- { "GNU.sparse.major", sparse_major_coder, sparse_major_decoder,
-- XHDR_PROTECTED },
-+ XHDR_PROTECTED, false },
- { "GNU.sparse.minor", sparse_minor_coder, sparse_minor_decoder,
-- XHDR_PROTECTED },
-+ XHDR_PROTECTED, false },
- { "GNU.sparse.realsize", sparse_size_coder, sparse_size_decoder,
-- XHDR_PROTECTED },
-+ XHDR_PROTECTED, false },
- { "GNU.sparse.numblocks", sparse_numblocks_coder, sparse_numblocks_decoder,
-- XHDR_PROTECTED },
-+ XHDR_PROTECTED, false },
-
- /* tar 1.14 - 1.15.90 keywords. */
- { "GNU.sparse.size", sparse_size_coder, sparse_size_decoder,
-- XHDR_PROTECTED },
-+ XHDR_PROTECTED, false },
- /* tar 1.14 - 1.15.1 keywords. Multiple 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,
-- XHDR_PROTECTED },
-+ XHDR_PROTECTED, false },
- { "GNU.sparse.numbytes", sparse_numbytes_coder, sparse_numbytes_decoder,
-- XHDR_PROTECTED },
-+ XHDR_PROTECTED, false },
- /* tar 1.15.90 keyword, introduced to remove the above-mentioned conflict. */
- { "GNU.sparse.map", NULL /* Unused, see pax_dump_header() */,
-- sparse_map_decoder, 0 },
-+ sparse_map_decoder, 0, false },
-
- { "GNU.dumpdir", dumpdir_coder, dumpdir_decoder,
-- XHDR_PROTECTED },
-+ XHDR_PROTECTED, 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,
-- XHDR_PROTECTED | XHDR_GLOBAL },
-+ XHDR_PROTECTED | XHDR_GLOBAL, false },
-
- /* These may be present in a first global header of the archive.
- They provide the same functionality as GNUTYPE_MULTIVOL header.
-@@ -1560,11 +1703,41 @@ 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,
-- XHDR_PROTECTED | XHDR_GLOBAL },
-+ XHDR_PROTECTED | XHDR_GLOBAL, false },
- { "GNU.volume.size", volume_size_coder, volume_size_decoder,
-- XHDR_PROTECTED | XHDR_GLOBAL },
-+ XHDR_PROTECTED | XHDR_GLOBAL, false },
- { "GNU.volume.offset", volume_offset_coder, volume_offset_decoder,
-- XHDR_PROTECTED | XHDR_GLOBAL },
-+ XHDR_PROTECTED | XHDR_GLOBAL, false },
-+
-+ /* We get the SELinux value from filecon, so add a namespace for SELinux
-+ instead of storing it in SCHILY.xattr.* (which would be RAW). */
-+ { "RHT.security.selinux",
-+ xattr_selinux_coder, xattr_selinux_decoder, 0, false },
-+
-+ /* ACLs, use the star format... */
-+ { "SCHILY.acl.access",
-+ xattr_acls_a_coder, xattr_acls_a_decoder, 0, false },
-+
-+ { "SCHILY.acl.default",
-+ xattr_acls_d_coder, xattr_acls_d_decoder, 0, false },
-+
-+ /* FIXME: These are compat. for FC-6 ... we shipped a tar using the generic
-+ header names by accident. */
-+ { "SCHILY.xattr.security.selinux",
-+ xattr_selinux_coder, xattr_selinux_decoder, 0, false },
-+ { "SCHILY.xattr.system.posix_acl_access",
-+ xattr_acls_a_coder, xattr_acls_a_decoder, 0, false },
-+ { "SCHILY.xattr.system.posix_acl_default",
-+ xattr_acls_d_coder, xattr_acls_d_decoder, 0, false },
-+
-+ /* xattrs use the star format. note we only save some variants... */
-+ { "SCHILY.xattr.user", xattr_coder, xattr_decoder, 0, true },
-+ { "SCHILY.xattr.trusted", xattr_coder, xattr_decoder, 0, true },
-+ { "SCHILY.xattr.lustre", xattr_coder, xattr_decoder, 0, true },
-+ { "SCHILY.xattr.security.NTACL", xattr_coder, xattr_decoder, 0, true },
-+
-+ /* ignore everything else in the xattr namespaces... */
-+ { "SCHILY.xattr", dummy_coder, dummy_decoder, 0, true },
-
-- { NULL, NULL, NULL, 0 }
-+ { NULL, NULL, NULL, 0, false }
- };
diff --git a/tar-1.24-extractingdirs.patch b/tar-1.24-extractingdirs.patch
new file mode 100644
index 0000000..848d8cd
--- /dev/null
+++ b/tar-1.24-extractingdirs.patch
@@ -0,0 +1,98 @@
+tar: fix bug with -C and extracting directories
+
+Problem reported by Denis Excoffier in
+.
+
+* src/extract.c (extract_dir): Use mkdirat, not mkdir.
+* tests/extrac16.at: New file, to test for this bug.
+* tests/Makefile.am (TESTSUITE_AT): Add it.
+* tests/testsuite.at: Include it.
+---
+ src/extract.c | 2 +-
+ tests/Makefile.am | 1 +
+ tests/extrac16.at | 36 ++++++++++++++++++++++++++++++++++++
+ tests/testsuite.at | 1 +
+ 4 files changed, 39 insertions(+), 1 deletions(-)
+ create mode 100644 tests/extrac16.at
+
+diff --git a/src/extract.c b/src/extract.c
+index 0d23d4a..98236ac 100644
+--- a/src/extract.c
++++ b/src/extract.c
+@@ -777,7 +777,7 @@ extract_dir (char *file_name, int typeflag)
+
+ for (;;)
+ {
+- status = mkdir (file_name, mode);
++ status = mkdirat (chdir_fd, file_name, mode);
+ if (status == 0)
+ {
+ current_mode = mode & ~ current_umask;
+diff --git a/tests/Makefile.am b/tests/Makefile.am
+index d29563a..b71e83c 100644
+--- a/tests/Makefile.am
++++ b/tests/Makefile.am
+@@ -82,6 +82,7 @@ TESTSUITE_AT = \
+ extrac13.at\
+ extrac14.at\
+ extrac15.at\
++ extrac16.at\
+ filerem01.at\
+ filerem02.at\
+ gzip.at\
+diff --git a/tests/extrac16.at b/tests/extrac16.at
+new file mode 100644
+index 0000000..625e579
+--- /dev/null
++++ b/tests/extrac16.at
+@@ -0,0 +1,36 @@
++# Process this file with autom4te to create testsuite. -*- Autotest -*-
++
++# Test suite for GNU tar.
++# Copyright (C) 2010 Free Software Foundation, Inc.
++
++# This program is free software; you can redistribute it and/or modify
++# it under the terms of the GNU General Public License as published by
++# the Free Software Foundation; either version 3, or (at your option)
++# any later version.
++
++# This program is distributed in the hope that it will be useful,
++# but WITHOUT ANY WARRANTY; without even the implied warranty of
++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++# GNU General Public License for more details.
++
++# You should have received a copy of the GNU General Public License
++# along with this program. If not, see .
++
++# written by Paul Eggert from a bug report by Denis Excoffier
++#
++
++# Check extraction of empty directory with -C.
++
++AT_SETUP([extract empty directory with -C])
++AT_KEYWORDS([extract extrac16])
++
++AT_TAR_CHECK([
++mkdir src src/a src/a/b dest
++touch src/a/c
++
++tar -cf archive.tar -C src a &&
++tar -xf archive.tar -C dest
++],
++[0],[],[],[],[],[gnu])
++
++AT_CLEANUP
+diff --git a/tests/testsuite.at b/tests/testsuite.at
+index c386892..40f0e41 100644
+--- a/tests/testsuite.at
++++ b/tests/testsuite.at
+@@ -154,6 +154,7 @@ m4_include([extrac12.at])
+ m4_include([extrac13.at])
+ m4_include([extrac14.at])
+ m4_include([extrac15.at])
++m4_include([extrac16.at])
+
+ m4_include([label01.at])
+ m4_include([label02.at])
+--
+1.7.2
diff --git a/tar-1.24-xattrs.patch b/tar-1.24-xattrs.patch
new file mode 100644
index 0000000..f93e64f
--- /dev/null
+++ b/tar-1.24-xattrs.patch
@@ -0,0 +1,1610 @@
+diff -urNp tar-1.24-orig/configure.ac tar-1.24/configure.ac
+--- tar-1.24-orig/configure.ac 2010-10-24 23:35:35.000000000 +0200
++++ tar-1.24/configure.ac 2010-10-25 10:24:52.548214037 +0200
+@@ -44,7 +44,7 @@ AC_CHECK_HEADERS_ONCE(fcntl.h linux/fd.h
+ sys/param.h sys/device.h sys/gentape.h \
+ sys/inet.h sys/io/trioctl.h \
+ sys/mtio.h sys/time.h sys/tprintf.h sys/tape.h \
+- unistd.h locale.h)
++ unistd.h locale.h attr/xattr.h sys/acl.h)
+
+ AC_CHECK_HEADERS([sys/buf.h], [], [],
+ [#if HAVE_SYS_PARAM_H
+@@ -91,6 +91,12 @@ gl_INIT
+ tar_PAXUTILS
+
+ AC_CHECK_FUNCS_ONCE([fchmod fchown fsync lstat mkfifo readlink symlink])
++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(acl, acl_get_fd)
++
+ AC_CHECK_DECLS([getgrgid],,, [#include ])
+ AC_CHECK_DECLS([getpwuid],,, [#include ])
+ AC_CHECK_DECLS([time],,, [#include ])
+@@ -214,6 +220,7 @@ AC_DEFINE_UNQUOTED(DEFAULT_QUOTING_STYLE
+ # Iconv
+ AM_ICONV
+ AC_CHECK_HEADERS(iconv.h)
++AC_CHECK_HEADERS(attr/xattr.h)
+ AC_CHECK_TYPE(iconv_t,:,
+ AC_DEFINE(iconv_t, int,
+ [Conversion descriptor type]),
+@@ -223,6 +230,17 @@ AC_CHECK_TYPE(iconv_t,:,
+ #endif
+ ])
+
++AC_ARG_ENABLE(selinux,
++ AC_HELP_STRING([--enable-selinux],
++ [enable SELinux support (disabled by default)]),
++ [selinux_enabled=$enableval],
++ [selinux_enabled=no])
++
++if test "x$selinux_enabled" = xyes; then
++ AC_CHECK_LIB(selinux, getfilecon)
++ AC_CHECK_HEADERS(selinux/selinux.h)
++fi
++
+ # Gettext.
+ AM_GNU_GETTEXT([external], [need-formatstring-macros])
+ AM_GNU_GETTEXT_VERSION([0.16])
+diff -urNp tar-1.24-orig/doc/tar.texi tar-1.24/doc/tar.texi
+--- tar-1.24-orig/doc/tar.texi 2010-10-24 20:07:54.000000000 +0200
++++ tar-1.24/doc/tar.texi 2010-10-25 10:24:52.554213688 +0200
+@@ -2370,6 +2370,10 @@ Normally when creating an archive, @comm
+ @samp{/} from member names. This option disables that behavior.
+ @xref{absolute}.
+
++@opsummary{acl}
++@item --acls
++Causes @command{tar} to store ACL's. @xref{Attributes}.
++
+ @opsummary{after-date}
+ @item --after-date
+
+@@ -2915,6 +2919,10 @@ contents have changed (as opposed to jus
+ also back up files for which any status information has
+ changed). @xref{after}.
+
++@opsummary{no-acl}
++@item --no-acls
++Causes @command{tar} not to store and not to extract ACL's. @xref{Attributes}.
++
+ @opsummary{no-anchored}
+ @item --no-anchored
+ An exclude pattern can match any subsequence of the name's components.
+@@ -2998,11 +3006,21 @@ locations. Usually @command{tar} determ
+ the archive can be seeked or not. Use this option to disable this
+ mechanism.
+
++@opsummary{no-selinux}
++@item --no-selinux
++Causes @command{tar} not to store and not to extract SELinux security context.
++@xref{Attributes}.
++
+ @opsummary{no-unquote}
+ @item --no-unquote
+ Treat all input file or member names literally, do not interpret
+ escape sequences. @xref{input name quoting}.
+
++@opsummary{no-xattrs}
++@item --no-xattrs
++Causes @command{tar} not to store and not to extract xattrs. This option also
++enables @option{--no-selinux} and @option{--no-acls}. @xref{Attributes}.
++
+ @opsummary{no-wildcards}
+ @item --no-wildcards
+ Do not use wildcards.
+@@ -3235,6 +3253,11 @@ in cases when such recognition fails. I
+ archive is open for reading (e.g. with @option{--list} or
+ @option{--extract} options).
+
++@opsummary{selinux}
++@item --selinux
++Causes @command{tar} to store SElinux security context. @xref{Attributes}.
++
++
+ @opsummary{show-defaults}
+ @item --show-defaults
+
+@@ -3448,6 +3471,11 @@ Enable or disable warning messages ident
+ messages are suppressed if @var{keyword} is prefixed with @samp{no-}.
+ @xref{warnings}.
+
++@opsummary{xattrs}
++@item --xattrs
++Causes @command{tar} to store xattrs. This option also enables
++@option{--selinux} and @option{--acls}. @xref{Attributes}.
++
+ @opsummary{wildcards}
+ @item --wildcards
+ Use wildcards when matching member names with patterns.
+@@ -8643,6 +8671,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{}.
+@@ -9259,6 +9289,51 @@ Same as both @option{--same-permissions}
+
+ This option is deprecated, and will be removed in @GNUTAR{} version 1.23.
+
++@opindex acls
++@item --acls
++This option causes @command{tar} to store the current ACL in the archive.
++
++The @option{--acls} option has no equivalent short option name.
++
++@opindex selinux
++@item --selinux
++This option causes @command{tar} to store the current 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 the current extended attributes in
++the 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.
++
++@opindex no-acls
++@item --no-acls
++This option causes @command{tar} not to store the current ACL in the archive
++and not to extract any ACL information in an archive.
++
++The @option{--no-acls} option has no equivalent short option name.
++
++@opindex no-selinux
++@item --no-selinux
++This option causes @command{tar} not to store the current SELinux security
++context information in the archive and not to extract any SELinux information in
++an archive.
++
++The @option{--no-selinux} option has no equivalent short option name.
++
++@opindex no-xattrs
++@item --no-xattrs
++This option causes @command{tar} not to store the current extended attributes in
++the archive and not to extract any extended attributes in an archive. This
++option also enables @option{--no-acls} and @option{--no-selinux} if
++they haven't been set already.
++
++The @option{--no-xattrs} option has no equivalent short option name.
++
+ @end table
+
+ @node Portability
+diff -urNp tar-1.24-orig/src/common.h tar-1.24/src/common.h
+--- tar-1.24-orig/src/common.h 2010-10-24 20:07:54.000000000 +0200
++++ tar-1.24/src/common.h 2010-10-25 10:24:52.558475456 +0200
+@@ -253,6 +253,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;
+@@ -706,6 +715,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 *stat);
+@@ -726,6 +738,12 @@ bool xheader_string_end (struct xheader
+ 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 */
+
+diff -urNp tar-1.24-orig/src/create.c tar-1.24/src/create.c
+--- tar-1.24-orig/src/create.c 2010-10-24 20:07:54.000000000 +0200
++++ tar-1.24/src/create.c 2010-10-25 10:24:52.560213618 +0200
+@@ -24,6 +24,7 @@
+ #include
+
+ #include "common.h"
++
+ #include
+
+ /* Error number to use when an impostor is discovered.
+@@ -934,6 +935,30 @@ start_header (struct tar_stat_info *st)
+ GNAME_TO_CHARS (st->gname, header->header.gname);
+ }
+
++ if (archive_format == POSIX_FORMAT)
++ {
++ if (acls_option > 0)
++ {
++ if (st->acls_a_ptr)
++ xheader_store ("SCHILY.acl.access", st, NULL);
++ if (st->acls_d_ptr)
++ xheader_store ("SCHILY.acl.default", st, NULL);
++ }
++ if ((selinux_context_option > 0) && st->cntx_name)
++ xheader_store ("RHT.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;
+ }
+
+@@ -1709,6 +1734,10 @@ dump_file0 (struct tar_stat_info *st, ch
+ bool ok;
+ struct stat final_stat;
+
++ xattrs_acls_get(st, p, fd, !is_dir);
++ xattrs_selinux_get(st, p, fd);
++ xattrs_xattrs_get(st, p, fd);
++
+ if (is_dir)
+ {
+ const char *tag_file_name;
+@@ -1826,6 +1855,9 @@ dump_file0 (struct tar_stat_info *st, ch
+ if (NAME_FIELD_SIZE - (archive_format == OLDGNU_FORMAT) < size)
+ write_long_link (st);
+
++ xattrs_selinux_get(st, p, -1);
++ xattrs_xattrs_get(st, p, -1);
++
+ block_ordinal = current_block_ordinal ();
+ st->stat.st_size = 0; /* force 0 size on symlink */
+ header = start_header (st);
+@@ -1844,11 +1876,23 @@ dump_file0 (struct tar_stat_info *st, ch
+ }
+ #endif
+ else if (S_ISCHR (st->stat.st_mode))
+- type = CHRTYPE;
++ {
++ type = CHRTYPE;
++ xattrs_selinux_get(st, p, -1);
++ xattrs_xattrs_get(st, p, -1);
++ }
+ else if (S_ISBLK (st->stat.st_mode))
+- type = BLKTYPE;
++ {
++ type = BLKTYPE;
++ xattrs_selinux_get(st, p, -1);
++ xattrs_xattrs_get(st, p, -1);
++ }
+ else if (S_ISFIFO (st->stat.st_mode))
+- type = FIFOTYPE;
++ {
++ type = FIFOTYPE;
++ xattrs_selinux_get(st, p, -1);
++ xattrs_xattrs_get(st, p, -1);
++ }
+ else if (S_ISSOCK (st->stat.st_mode))
+ {
+ WARNOPT (WARN_FILE_IGNORED,
+diff -urNp tar-1.24-orig/src/extract.c tar-1.24/src/extract.c
+--- tar-1.24-orig/src/extract.c 2010-10-24 20:07:54.000000000 +0200
++++ tar-1.24/src/extract.c 2010-10-25 10:35:10.903214037 +0200
+@@ -97,6 +97,14 @@ struct delayed_set_stat
+ /* Directory that the name is relative to. */
+ int change_dir;
+
++ /* extended attributes*/
++ char *cntx_name;
++ char *acls_a_ptr;
++ size_t acls_a_len;
++ char *acls_d_ptr;
++ size_t acls_d_len;
++ size_t xattr_map_size; /* Size of the xattr map */
++ struct xattr_array *xattr_map;
+ /* Length and contents of name. */
+ size_t file_name_len;
+ char file_name[1];
+@@ -134,6 +142,18 @@ struct delayed_link
+ hard-linked together. */
+ struct string_list *sources;
+
++ /* SELinux context */
++ char *cntx_name;
++
++ /* ACLs */
++ char *acls_a_ptr;
++ size_t acls_a_len;
++ char *acls_d_ptr;
++ size_t acls_d_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];
+ };
+@@ -335,6 +355,10 @@ set_stat (char const *file_name,
+ utime_error (file_name);
+ }
+
++ 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 && ! interdir)
+ {
+ /* Some systems allow non-root users to give files away. Once this
+@@ -431,6 +455,29 @@ delay_set_stat (char const *file_name, s
+ data->atflag = atflag;
+ data->after_links = 0;
+ data->change_dir = chdir_current;
++ data->cntx_name = NULL;
++ assign_string (&data->cntx_name, st->cntx_name);
++ if (st->acls_a_ptr)
++ {
++ data->acls_a_ptr = xmemdup(st->acls_a_ptr, st->acls_a_len + 1);
++ data->acls_a_len = st->acls_a_len;
++ }
++ else
++ {
++ data->acls_a_ptr = NULL;
++ data->acls_a_len = 0;
++ }
++ if (st->acls_d_ptr)
++ {
++ data->acls_d_ptr = xmemdup(st->acls_d_ptr, st->acls_d_len + 1);
++ data->acls_d_len = st->acls_d_len;
++ }
++ else
++ {
++ data->acls_d_ptr = NULL;
++ data->acls_d_len = 0;
++ }
++ xheader_xattr_copy (st, &data->xattr_map, &data->xattr_map_size);
+ strcpy (data->file_name, file_name);
+ delayed_set_stat_head = data;
+ if (must_be_dot_or_slash (file_name))
+@@ -661,6 +708,31 @@ maybe_recoverable (char *file_name, bool
+ return RECOVER_NO;
+ }
+
++/* Restore stat extended attributes (xattr) for FILE_NAME, using information
++ given in *ST. Restore before extraction because they may affect layout.
++ If not restoring permissions, invert the
++ INVERT_PERMISSIONS bits from the file's current permissions.
++ TYPEFLAG specifies the type of the file.
++ FILE_CREATED indicates set_xattr has created the file */
++static int
++set_xattr (char const *file_name, struct tar_stat_info const *st,
++ mode_t invert_permissions, char typeflag, int *file_created)
++{
++ int status = 0;
++ int interdir_made = 0;
++
++ if ((xattrs_option >= 0) && st->xattr_map_size) {
++ mode_t mode = current_stat_info.stat.st_mode & MODE_RWX & ~ current_umask;
++
++ do
++ status = mknod (file_name, mode ^ invert_permissions, 0);
++ while (status && maybe_recoverable ((char *)file_name, false, &interdir_made));
++ xattrs_xattrs_set(st, file_name, typeflag);
++ *file_created = 1;
++ }
++ return(status);
++}
++
+ /* Fix the statuses of all directories whose statuses need fixing, and
+ which are not ancestors of FILE_NAME. If AFTER_LINKS is
+ nonzero, do this for all such directories; otherwise, stop at the
+@@ -721,12 +793,23 @@ apply_nonancestor_delayed_set_stat (char
+ sb.stat.st_gid = data->gid;
+ sb.atime = data->atime;
+ sb.mtime = data->mtime;
++ sb.cntx_name = data->cntx_name;
++ sb.acls_a_ptr = data->acls_a_ptr;
++ sb.acls_a_len = data->acls_a_len;
++ sb.acls_d_ptr = data->acls_d_ptr;
++ sb.acls_d_len = data->acls_d_len;
++ sb.xattr_map = data->xattr_map;
++ sb.xattr_map_size = data->xattr_map_size;
+ set_stat (data->file_name, &sb,
+ -1, current_mode, current_mode_mask,
+ DIRTYPE, data->interdir, data->atflag);
+ }
+
+ delayed_set_stat_head = data->next;
++ xheader_xattr_free (data->xattr_map, data->xattr_map_size);
++ free (data->cntx_name);
++ free (data->acls_a_ptr);
++ free (data->acls_d_ptr);
+ free (data);
+ }
+ }
+@@ -842,6 +925,7 @@ extract_dir (char *file_name, int typefl
+
+ static int
+ open_output_file (char const *file_name, int typeflag, mode_t mode,
++ int file_created,
+ mode_t *current_mode, mode_t *current_mode_mask)
+ {
+ int fd;
+@@ -852,6 +936,10 @@ open_output_file (char const *file_name,
+ ? O_TRUNC | (dereference_option ? 0 : O_NOFOLLOW)
+ : O_EXCL));
+
++ /* File might be created in set_xattr. So clear O_EXCL to avoid open() failure */
++ if (file_created)
++ openflag = openflag & ~O_EXCL;
++
+ if (typeflag == CONTTYPE)
+ {
+ static int conttype_diagnosed;
+@@ -908,6 +996,7 @@ extract_file (char *file_name, int typef
+ bool interdir_made = false;
+ mode_t mode = (current_stat_info.stat.st_mode & MODE_RWX
+ & ~ (0 < same_owner_option ? S_IRWXG | S_IRWXO : 0));
++ mode_t invert_permissions = 0 < same_owner_option ? mode & (S_IRWXG | S_IRWXO) : 0;
+ mode_t current_mode = 0;
+ mode_t current_mode_mask = 0;
+
+@@ -924,7 +1013,17 @@ extract_file (char *file_name, int typef
+ }
+ else
+ {
++ int file_created = 0;
++ if (set_xattr (file_name, ¤t_stat_info, invert_permissions,
++ typeflag, &file_created))
++ {
++ skip_member ();
++ open_error (file_name);
++ return 1;
++ }
++
+ while ((fd = open_output_file (file_name, typeflag, mode,
++ file_created,
+ ¤t_mode, ¤t_mode_mask))
+ < 0)
+ {
+@@ -1065,6 +1164,13 @@ create_placeholder_file (char *file_name
+ + strlen (file_name) + 1);
+ p->sources->next = 0;
+ strcpy (p->sources->string, file_name);
++ p->cntx_name = NULL;
++ assign_string (&p->cntx_name, current_stat_info.cntx_name);
++ p->acls_a_ptr = NULL;
++ p->acls_a_len = 0;
++ p->acls_d_ptr = NULL;
++ p->acls_d_len = 0;
++ xheader_xattr_copy (¤t_stat_info, &p->xattr_map, &p->xattr_map_size);
+ strcpy (p->target, current_stat_info.link_name);
+
+ h = delayed_set_stat_head;
+@@ -1499,6 +1605,13 @@ apply_delayed_links (void)
+ st1.stat.st_gid = ds->gid;
+ st1.atime = ds->atime;
+ st1.mtime = ds->mtime;
++ st1.cntx_name = ds->cntx_name;
++ st1.acls_a_ptr = ds->acls_a_ptr;
++ st1.acls_a_len = ds->acls_a_len;
++ st1.acls_d_ptr = ds->acls_d_ptr;
++ st1.acls_d_len = ds->acls_d_len;
++ st1.xattr_map = ds->xattr_map;
++ st1.xattr_map_size = ds->xattr_map_size;
+ set_stat (source, &st1, -1, 0, 0, SYMTYPE,
+ false, AT_SYMLINK_NOFOLLOW);
+ valid_source = source;
+@@ -1513,6 +1626,9 @@ apply_delayed_links (void)
+ sources = next;
+ }
+
++ xheader_xattr_free (ds->xattr_map, ds->xattr_map_size);
++ free (ds->cntx_name);
++
+ {
+ struct delayed_link *next = ds->next;
+ free (ds);
+diff -urNp tar-1.24-orig/src/list.c tar-1.24/src/list.c
+--- tar-1.24-orig/src/list.c 2010-10-25 09:15:14.216463863 +0200
++++ tar-1.24/src/list.c 2010-10-25 10:24:52.563213968 +0200
+@@ -597,6 +597,13 @@ decode_header (union block *header, stru
+ assign_string (&stat_info->gname,
+ header->header.gname[0] ? header->header.gname : NULL);
+
++ stat_info->acls_a_ptr = NULL;
++ stat_info->acls_a_len = 0;
++ stat_info->acls_d_ptr = NULL;
++ stat_info->acls_d_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);
+diff -urNp tar-1.24-orig/src/Makefile.am tar-1.24/src/Makefile.am
+--- tar-1.24-orig/src/Makefile.am 2010-10-24 20:07:54.000000000 +0200
++++ tar-1.24/src/Makefile.am 2010-10-25 10:24:52.564214456 +0200
+@@ -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\
+ checkpoint.c\
+@@ -42,10 +42,11 @@ tar_SOURCES = \
+ unlink.c\
+ update.c\
+ utf8.c\
+- warning.c
++ warning.c\
++ xattrs.c
+
+ INCLUDES = -I$(top_srcdir)/gnu -I../ -I../gnu -I$(top_srcdir)/lib -I../lib
+
+ LDADD = ../lib/libtar.a ../gnu/libgnu.a $(LIBINTL) $(LIBICONV)
+
+-tar_LDADD = $(LDADD) $(LIB_CLOCK_GETTIME) $(LIB_EACCESS)
++tar_LDADD = $(LIBS) $(LDADD) $(LIB_CLOCK_GETTIME) $(LIB_EACCESS)
+diff -urNp tar-1.24-orig/src/tar.c tar-1.24/src/tar.c
+--- tar-1.24-orig/src/tar.c 2010-10-24 20:07:55.000000000 +0200
++++ tar-1.24/src/tar.c 2010-10-25 10:24:52.565223676 +0200
+@@ -255,7 +255,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,
+ CHECK_DEVICE_OPTION,
+@@ -288,6 +289,7 @@ enum
+ MODE_OPTION,
+ MTIME_OPTION,
+ NEWER_MTIME_OPTION,
++ NO_ACLS_OPTION,
+ NO_ANCHORED_OPTION,
+ NO_AUTO_COMPRESS_OPTION,
+ NO_CHECK_DEVICE_OPTION,
+@@ -301,9 +303,11 @@ enum
+ NO_SAME_OWNER_OPTION,
+ NO_SAME_PERMISSIONS_OPTION,
+ NO_SEEK_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,
+@@ -325,6 +329,7 @@ enum
+ RMT_COMMAND_OPTION,
+ RSH_COMMAND_OPTION,
+ SAME_OWNER_OPTION,
++ SELINUX_CONTEXT_OPTION,
+ SHOW_DEFAULTS_OPTION,
+ SHOW_OMITTED_DIRS_OPTION,
+ SHOW_TRANSFORMED_NAMES_OPTION,
+@@ -340,7 +345,8 @@ enum
+ VOLNO_FILE_OPTION,
+ WARNING_OPTION,
+ WILDCARDS_MATCH_SLASH_OPTION,
+- WILDCARDS_OPTION
++ WILDCARDS_OPTION,
++ XATTR_OPTION
+ };
+
+ const char *argp_program_version = "tar (" PACKAGE_NAME ") " VERSION;
+@@ -486,6 +492,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,
+@@ -516,6 +526,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,
+@@ -2079,6 +2097,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;
+@@ -2461,6 +2510,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;
+@@ -2713,11 +2785,15 @@ void
+ tar_stat_destroy (struct tar_stat_info *st)
+ {
+ tar_stat_close (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_a_ptr);
++ free (st->acls_d_ptr);
+ free (st->sparse_map);
+ free (st->dumpdir);
+ xheader_destroy (&st->xhdr);
+diff -urNp tar-1.24-orig/src/tar.h tar-1.24/src/tar.h
+--- tar-1.24-orig/src/tar.h 2010-10-24 20:07:46.000000000 +0200
++++ tar-1.24/src/tar.h 2010-10-25 10:24:52.567223606 +0200
+@@ -276,6 +276,14 @@ struct xheader
+ uintmax_t string_length;
+ };
+
++/* 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 */
+@@ -287,6 +295,15 @@ 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_a_ptr; /* Access ACLs for the current archive entry. */
++ size_t acls_a_len; /* Access ACLs for the current archive entry. */
++
++ char *acls_d_ptr; /* Default ACLs for the current archive entry. */
++ size_t acls_d_len; /* Default ACLs for the current archive entry. */
++
+ struct stat stat; /* regular filesystem stat */
+
+ /* STAT doesn't always have access, data modification, and status
+@@ -309,6 +326,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;
++
+ /* Extended headers */
+ struct xheader xhdr;
+
+diff -urNp tar-1.24-orig/src/xattrs.c tar-1.24/src/xattrs.c
+--- tar-1.24-orig/src/xattrs.c 1970-01-01 01:00:00.000000000 +0100
++++ tar-1.24/src/xattrs.c 2010-10-25 10:24:52.568214736 +0200
+@@ -0,0 +1,489 @@
++/* 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
++
++#include
++
++#include "common.h"
++
++
++#ifndef HAVE_SELINUX_SELINUX_H
++# undef HAVE_LIBSELINUX
++#endif
++
++#ifndef HAVE_ATTR_XATTR_H
++# undef HAVE_XATTRS
++#endif
++
++#ifndef HAVE_SYS_ACL_H
++# undef HAVE_LIBACL
++#endif
++
++#ifdef HAVE_SELINUX_SELINUX_H
++# include
++#endif
++
++#ifdef HAVE_ATTR_XATTR_H
++# include
++#endif
++
++#ifdef HAVE_SYS_ACL_H
++# include
++#endif
++
++
++#if 0 /* unused by xattr's atm. */
++static void xattrs__fd_get(struct tar_stat_info *st,
++ char const *file_name, int fd, const char *attr,
++ char **ret_ptr, size_t *ret_len)
++{
++#ifdef HAVE_XATTRS
++ static ssize_t asz = 1024;
++ ssize_t ret = 0;
++ static char *val = NULL;
++
++ if (!val) val = xmalloc (asz);
++
++ while (((ret = fgetxattr (fd, attr, val, asz)) == -1) &&
++ (errno == ERANGE))
++ {
++ asz <<= 1;
++ val = xrealloc (val, asz);
++ }
++
++ if (ret != -1)
++ {
++ *ret_ptr = xmemdup (val, ret + 1);
++ *ret_len = ret;
++ }
++ else if (errno != ENOATTR)
++ call_arg_warn ("fgetxattr", file_name);
++#endif
++}
++#endif
++
++static void xattrs__acls_get_a(struct tar_stat_info *st,
++ char const *file_name, int fd,
++ char **ret_ptr, size_t *ret_len)
++{ /* "system.posix_acl_access" */
++#ifdef HAVE_LIBACL
++ char *val = NULL;
++ ssize_t len;
++ acl_t acl;
++
++ if (fd != -1)
++ {
++ if ((acl = acl_get_fd (fd)) == (acl_t)NULL)
++ {
++ if (errno != ENOTSUP)
++ call_arg_warn ("acl_get_fd", file_name);
++ return;
++ }
++ }
++ else if ((acl = acl_get_file (file_name, ACL_TYPE_ACCESS)) == (acl_t)NULL)
++ {
++ if (errno != ENOTSUP)
++ call_arg_warn ("acl_get_file", file_name);
++ return;
++ }
++
++
++ val = acl_to_text(acl, &len);
++ acl_free (acl);
++
++ if (val == NULL)
++ {
++ call_arg_warn ("acl_to_text", file_name);
++ return;
++ }
++
++ *ret_ptr = xstrdup (val);
++ *ret_len = len;
++
++ acl_free (val);
++#endif
++}
++
++static void xattrs__acls_get_d(struct tar_stat_info *st,
++ char const *file_name,
++ char **ret_ptr, size_t *ret_len)
++{ /* "system.posix_acl_default" */
++#ifdef HAVE_LIBACL
++ char *val = NULL;
++ ssize_t len;
++ acl_t acl;
++
++ if ((acl = acl_get_file (file_name, ACL_TYPE_DEFAULT)) == (acl_t)NULL)
++ {
++ if (errno != ENOTSUP)
++ call_arg_warn ("acl_get_file", file_name);
++ return;
++ }
++
++ val = acl_to_text(acl, &len);
++ acl_free (acl);
++
++ if (val == NULL)
++ {
++ call_arg_warn ("acl_to_text", file_name);
++ return;
++ }
++
++ *ret_ptr = xstrdup (val);
++ *ret_len = len;
++
++ acl_free (val);
++#endif
++}
++
++void xattrs_acls_get(struct tar_stat_info *st, char const *file_name, int fd,
++ int xisfile)
++{
++ if (acls_option > 0)
++ {
++#ifndef HAVE_LIBACL
++ static int done = 0;
++ if (!done)
++ WARN ((0, 0, _("ACL support requested, but not available")));
++ done = 1;
++#endif
++ xattrs__acls_get_a (st, file_name, fd,
++ &st->acls_a_ptr, &st->acls_a_len);
++ if (!xisfile)
++ xattrs__acls_get_d (st, file_name,
++ &st->acls_d_ptr, &st->acls_d_len);
++ }
++}
++
++void xattrs_selinux_get(struct tar_stat_info *st, char const *file_name, int fd)
++{
++ if (selinux_context_option > 0)
++ {
++#ifndef HAVE_LIBSELINUX
++ static int done = 0;
++ if (!done)
++ WARN ((0, 0, _("SELinux support requested, but not available")));
++ done = 1;
++#else
++ if (fd == -1)
++ {
++ if ((lgetfilecon (file_name, &st->cntx_name) == -1) && (errno != ENOTSUP) && (errno != ENODATA))
++ call_arg_warn ("lgetfilecon", file_name);
++ }
++ else if ((fgetfilecon (fd, &st->cntx_name) == -1) && (errno != ENOTSUP) && (errno != ENODATA))
++ call_arg_warn ("fgetfilecon", file_name);
++#endif
++ }
++}
++
++void xattrs_xattrs_get(struct tar_stat_info *st, char const *file_name, int fd)
++{
++ 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;
++
++#ifndef HAVE_XATTRS
++ static int done = 0;
++ if ((xattrs_option > 0) && !done)
++ WARN ((0, 0, _("Xattr support requested, but not available")));
++ done = 1;
++#else
++
++ if (!xatrs) xatrs = xmalloc (xsz);
++
++ while (((fd == -1) ?
++ ((xret = llistxattr (file_name, xatrs, xsz)) == -1) :
++ ((xret = flistxattr (fd, xatrs, xsz)) == -1)) &&
++ (errno == ERANGE))
++ {
++ xsz <<= 1;
++ xatrs = xrealloc (xatrs, xsz);
++ }
++
++ if (xret == -1)
++ call_arg_warn ((fd == -1) ? "llistxattrs" : "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;
++
++ /* Archive all xattrs during creation, decide at extraction time
++ * which ones are of interest/use for the target filesystem. */
++ while (((fd == -1) ?
++ ((aret = lgetxattr (file_name, attr, val, asz)) == -1) :
++ ((aret = fgetxattr (fd, attr, val, asz)) == -1)) &&
++ (errno == ERANGE))
++ {
++ asz <<= 1;
++ val = xrealloc (val, asz);
++ }
++
++ if (aret != -1)
++ xheader_xattr_add (st, attr, val, aret);
++ else if (errno != ENOATTR)
++ call_arg_warn ((fd==-1) ? "lgetxattr" : "fgetxattr", file_name);
++
++ attr += len + 1;
++ xret -= len + 1;
++ }
++ }
++#endif
++ }
++}
++
++static void xattrs__fd_set(struct tar_stat_info const *st,
++ char const *file_name, char typeflag,
++ const char *attr,
++ const char *ptr, size_t len)
++{
++#ifdef HAVE_XATTRS
++ if (ptr)
++ {
++ const char *sysname = "setxattr";
++ int ret = -1;
++
++ if (typeflag != SYMTYPE)
++ ret = setxattr (file_name, attr, ptr, len, 0);
++ else
++ {
++ sysname = "lsetxattr";
++ ret = lsetxattr (file_name, attr, ptr, len, 0);
++ }
++
++ /* do not print warnings when SELinux is disabled */
++ if ((ret == -1) && (errno != EPERM) && (errno != ENOTSUP))
++ call_arg_error(sysname, file_name);
++ }
++#endif
++}
++
++/* convert unix permissions into an ACL ... needed due to "default" ACLs */
++#ifdef HAVE_LIBACL
++static acl_t perms2acl(int perms)
++{
++ char val[] = "user::---,group::---,other::---";
++ /* 0123456789 123456789 123456789 123456789 */
++
++ /* user */
++ if (perms & 0400) val[ 6] = 'r';
++ if (perms & 0200) val[ 7] = 'w';
++ if (perms & 0100) val[ 8] = 'x';
++
++ /* group */
++ if (perms & 0040) val[17] = 'r';
++ if (perms & 0020) val[18] = 'w';
++ if (perms & 0010) val[19] = 'x';
++
++ /* other */
++ if (perms & 0004) val[28] = 'r';
++ if (perms & 0002) val[29] = 'w';
++ if (perms & 0001) val[30] = 'x';
++
++ return (acl_from_text (val));
++}
++#endif
++
++static char *skip_to_ext_fields(char *ptr)
++{
++ ptr += strcspn(ptr, ":,\n"); /* skip tag name. Ie. user/group/default/mask */
++
++ if (*ptr != ':')
++ return (ptr); /* error? no user/group field */
++ ++ptr;
++
++ ptr += strcspn(ptr, ":,\n"); /* skip user/group name */
++
++ if (*ptr != ':')
++ return (ptr); /* error? no perms field */
++ ++ptr;
++
++ ptr += strcspn(ptr, ":,\n"); /* skip perms */
++
++ if (*ptr != ':')
++ return (ptr); /* no extra fields */
++
++ return (ptr);
++}
++
++/* The POSIX draft allows extra fields after the three main ones. Star
++ uses this to add a fourth field for user/group which is the numeric ID.
++ We just skip all extra fields atm. */
++static const char *fixup_extra_acl_fields(const char *ptr)
++{
++ char *src = (char *)ptr;
++ char *dst = (char *)ptr;
++
++ while (*src)
++ {
++ const char *old = src;
++ size_t len = 0;
++
++ src = skip_to_ext_fields(src);
++ len = src - old;
++ if (old != dst) memmove(dst, old, len);
++ dst += len;
++
++ if (*src == ':') /* We have extra fields, skip them all */
++ src += strcspn(src, "\n,");
++
++ if ((*src == '\n') || (*src == ','))
++ *dst++ = *src++; /* also done when dst == src, but that's ok */
++ }
++ if (src != dst)
++ *dst = 0;
++
++ return ptr;
++}
++
++static void xattrs__acls_set(struct tar_stat_info const *st,
++ char const *file_name, int type,
++ const char *ptr, size_t len)
++{ /* "system.posix_acl_access" */
++#ifdef HAVE_LIBACL
++ acl_t acl;
++
++ if (ptr)
++ {
++ /* assert (strlen (ptr) == len); */
++ ptr = fixup_extra_acl_fields(ptr);
++
++ acl = acl_from_text (ptr);
++ acls_option = 1;
++ }
++ else if (acls_option > 0)
++ acl = perms2acl (st->stat.st_mode);
++ else
++ return; /* don't call acl functions unless we first hit an ACL, or
++ --acls was passed explicitly */
++
++ if (acl == (acl_t)NULL)
++ {
++ call_arg_warn ("acl_from_text", file_name);
++ return;
++ }
++
++ if (acl_set_file (file_name, type, acl) == -1)
++ {
++ if (errno != ENOTSUP)
++ call_arg_warn ("acl_set_file", file_name);
++ }
++ acl_free (acl);
++#endif
++}
++
++void xattrs_acls_set(struct tar_stat_info const *st,
++ char const *file_name, char typeflag)
++{
++ if ((acls_option >= 0) && (typeflag != SYMTYPE))
++ {
++#ifndef HAVE_LIBACL
++ static int done = 0;
++ if (!done)
++ WARN ((0, 0, _("ACL support requested, but not available")));
++ done = 1;
++#else
++ xattrs__acls_set (st, file_name, ACL_TYPE_ACCESS,
++ st->acls_a_ptr, st->acls_a_len);
++ if ((typeflag == DIRTYPE) || (typeflag == GNUTYPE_DUMPDIR))
++ xattrs__acls_set (st, file_name, ACL_TYPE_DEFAULT,
++ st->acls_d_ptr, st->acls_d_len);
++#endif
++ }
++}
++
++void xattrs_selinux_set(struct tar_stat_info const *st,
++ char const *file_name, char typeflag)
++{
++ if ((selinux_context_option >= 0) && st->cntx_name)
++ {
++ const char *sysname = "setfilecon";
++ int ret = -1;
++
++#ifndef HAVE_LIBSELINUX
++ static int done = 0;
++ if (!done)
++ WARN ((0, 0, _("SELinux support requested, but not available")));
++ done = 1;
++#else
++ 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)
++{
++ if ((xattrs_option >= 0) && st->xattr_map_size)
++ {
++ size_t scan = 0;
++
++#ifndef HAVE_XATTRS
++ static int done = 0;
++ if (!done)
++ WARN ((0, 0, _("Xattr support requested, but not available")));
++ done = 1;
++#else
++ 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, "lustre.", strlen("lustre.")) &&
++ strncmp (keyword, "trusted.", strlen("trusted.")) &&
++ strncmp (keyword, "security.NTACL", strlen("security.NTACL")))
++ continue; /* don't try and set anything but normal xattrs */
++
++ xattrs__fd_set (st, file_name, typeflag, keyword,
++ st->xattr_map[scan].xval_ptr,
++ st->xattr_map[scan].xval_len);
++
++ ++scan;
++ }
++#endif
++ }
++}
+diff -urNp tar-1.24-orig/src/xattrs.h tar-1.24/src/xattrs.h
+--- tar-1.24-orig/src/xattrs.h 1970-01-01 01:00:00.000000000 +0100
++++ tar-1.24/src/xattrs.h 2010-10-25 10:24:52.569214526 +0200
+@@ -0,0 +1,14 @@
++
++extern void xattrs_acls_get(struct tar_stat_info *st,
++ char const *file_name, int fd, int xisfile);
++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);
+diff -urNp tar-1.24-orig/src/xheader.c tar-1.24/src/xheader.c
+--- tar-1.24-orig/src/xheader.c 2010-10-24 20:07:46.000000000 +0200
++++ tar-1.24/src/xheader.c 2010-10-25 10:24:52.570223396 +0200
+@@ -460,6 +460,74 @@ xheader_write_global (struct xheader *xh
+ }
+ }
+
++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 + 1);
++ (*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 */
+
+@@ -473,6 +541,7 @@ struct xhdr_tab
+ struct xheader *, void const *data);
+ void (*decoder) (struct tar_stat_info *, char const *, char const *, size_t);
+ int flags;
++ bool prefix;
+ };
+
+ /* This declaration must be extern, because ISO C99 section 6.9.2
+@@ -489,8 +558,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;
+ }
+
+@@ -500,7 +578,7 @@ xheader_protected_pattern_p (const char
+ struct xhdr_tab const *p;
+
+ for (p = xhdr_tab; p->keyword; p++)
+- if ((p->flags & XHDR_PROTECTED) && fnmatch (pattern, p->keyword, 0) == 0)
++ if (!p->prefix && (p->flags & XHDR_PROTECTED) && fnmatch (pattern, p->keyword, 0) == 0)
+ return true;
+ return false;
+ }
+@@ -511,7 +589,7 @@ xheader_protected_keyword_p (const char
+ struct xhdr_tab const *p;
+
+ for (p = xhdr_tab; p->keyword; p++)
+- if ((p->flags & XHDR_PROTECTED) && strcmp (p->keyword, keyword) == 0)
++ if (!p->prefix && (p->flags & XHDR_PROTECTED) && strcmp (p->keyword, keyword) == 0)
+ return true;
+ return false;
+ }
+@@ -1470,6 +1548,71 @@ volume_filename_decoder (struct tar_stat
+ }
+
+ static void
++xattr_selinux_coder (struct tar_stat_info const *st, char const *keyword,
++ struct xheader *xhdr, void const *data)
++{
++ code_string (st->cntx_name, keyword, xhdr);
++}
++
++static void
++xattr_selinux_decoder (struct tar_stat_info *st,
++ char const *keyword, char const *arg, size_t size)
++{
++ decode_string (&st->cntx_name, arg);
++}
++
++static void
++xattr_acls_a_coder (struct tar_stat_info const *st , char const *keyword,
++ struct xheader *xhdr, void const *data)
++{
++ xheader_print_n (xhdr, keyword, st->acls_a_ptr, st->acls_a_len);
++}
++
++static void
++xattr_acls_a_decoder (struct tar_stat_info *st,
++ char const *keyword, char const *arg, size_t size)
++{
++ st->acls_a_ptr = xmemdup (arg, size + 1);
++ st->acls_a_len = size;
++}
++
++static void
++xattr_acls_d_coder (struct tar_stat_info const *st , char const *keyword,
++ struct xheader *xhdr, void const *data)
++{
++ xheader_print_n (xhdr, keyword, st->acls_d_ptr, st->acls_d_len);
++}
++
++static void
++xattr_acls_d_decoder (struct tar_stat_info *st,
++ char const *keyword, char const *arg, size_t size)
++{
++ st->acls_d_ptr = xmemdup (arg, size + 1);
++ st->acls_d_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);
++}
++
++static void
+ sparse_major_coder (struct tar_stat_info const *st, char const *keyword,
+ struct xheader *xhdr, void const *data)
+ {
+@@ -1506,53 +1649,53 @@ sparse_minor_decoder (struct tar_stat_in
+ }
+
+ struct xhdr_tab const xhdr_tab[] = {
+- { "atime", atime_coder, atime_decoder, 0 },
+- { "comment", dummy_coder, dummy_decoder, 0 },
+- { "charset", dummy_coder, dummy_decoder, 0 },
+- { "ctime", ctime_coder, ctime_decoder, 0 },
+- { "gid", gid_coder, gid_decoder, 0 },
+- { "gname", gname_coder, gname_decoder, 0 },
+- { "linkpath", linkpath_coder, linkpath_decoder, 0 },
+- { "mtime", mtime_coder, mtime_decoder, 0 },
+- { "path", path_coder, path_decoder, 0 },
+- { "size", size_coder, size_decoder, 0 },
+- { "uid", uid_coder, uid_decoder, 0 },
+- { "uname", uname_coder, uname_decoder, 0 },
++ { "atime", atime_coder, atime_decoder, 0, false },
++ { "comment", dummy_coder, dummy_decoder, 0, false },
++ { "charset", dummy_coder, dummy_decoder, 0, false },
++ { "ctime", ctime_coder, ctime_decoder, 0, false },
++ { "gid", gid_coder, gid_decoder, 0, false },
++ { "gname", gname_coder, gname_decoder, 0, false },
++ { "linkpath", linkpath_coder, linkpath_decoder, 0, false },
++ { "mtime", mtime_coder, mtime_decoder, 0, false },
++ { "path", path_coder, path_decoder, 0, false },
++ { "size", size_coder, size_decoder, 0, false },
++ { "uid", uid_coder, uid_decoder, 0, false },
++ { "uname", uname_coder, uname_decoder, 0, false },
+
+ /* Sparse file handling */
+ { "GNU.sparse.name", path_coder, path_decoder,
+- XHDR_PROTECTED },
++ XHDR_PROTECTED, false },
+ { "GNU.sparse.major", sparse_major_coder, sparse_major_decoder,
+- XHDR_PROTECTED },
++ XHDR_PROTECTED, false },
+ { "GNU.sparse.minor", sparse_minor_coder, sparse_minor_decoder,
+- XHDR_PROTECTED },
++ XHDR_PROTECTED, false },
+ { "GNU.sparse.realsize", sparse_size_coder, sparse_size_decoder,
+- XHDR_PROTECTED },
++ XHDR_PROTECTED, false },
+ { "GNU.sparse.numblocks", sparse_numblocks_coder, sparse_numblocks_decoder,
+- XHDR_PROTECTED },
++ XHDR_PROTECTED, false },
+
+ /* tar 1.14 - 1.15.90 keywords. */
+ { "GNU.sparse.size", sparse_size_coder, sparse_size_decoder,
+- XHDR_PROTECTED },
++ XHDR_PROTECTED, false },
+ /* tar 1.14 - 1.15.1 keywords. Multiple 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,
+- XHDR_PROTECTED },
++ XHDR_PROTECTED, false },
+ { "GNU.sparse.numbytes", sparse_numbytes_coder, sparse_numbytes_decoder,
+- XHDR_PROTECTED },
++ XHDR_PROTECTED, false },
+ /* tar 1.15.90 keyword, introduced to remove the above-mentioned conflict. */
+ { "GNU.sparse.map", NULL /* Unused, see pax_dump_header() */,
+- sparse_map_decoder, 0 },
++ sparse_map_decoder, 0, false },
+
+ { "GNU.dumpdir", dumpdir_coder, dumpdir_decoder,
+- XHDR_PROTECTED },
++ XHDR_PROTECTED, 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,
+- XHDR_PROTECTED | XHDR_GLOBAL },
++ XHDR_PROTECTED | XHDR_GLOBAL, false },
+
+ /* These may be present in a first global header of the archive.
+ They provide the same functionality as GNUTYPE_MULTIVOL header.
+@@ -1561,11 +1704,41 @@ 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,
+- XHDR_PROTECTED | XHDR_GLOBAL },
++ XHDR_PROTECTED | XHDR_GLOBAL, false },
+ { "GNU.volume.size", volume_size_coder, volume_size_decoder,
+- XHDR_PROTECTED | XHDR_GLOBAL },
++ XHDR_PROTECTED | XHDR_GLOBAL, false },
+ { "GNU.volume.offset", volume_offset_coder, volume_offset_decoder,
+- XHDR_PROTECTED | XHDR_GLOBAL },
++ XHDR_PROTECTED | XHDR_GLOBAL, false },
++
++ /* We get the SELinux value from filecon, so add a namespace for SELinux
++ instead of storing it in SCHILY.xattr.* (which would be RAW). */
++ { "RHT.security.selinux",
++ xattr_selinux_coder, xattr_selinux_decoder, 0, false },
++
++ /* ACLs, use the star format... */
++ { "SCHILY.acl.access",
++ xattr_acls_a_coder, xattr_acls_a_decoder, 0, false },
++
++ { "SCHILY.acl.default",
++ xattr_acls_d_coder, xattr_acls_d_decoder, 0, false },
++
++ /* FIXME: These are compat. for FC-6 ... we shipped a tar using the generic
++ header names by accident. */
++ { "SCHILY.xattr.security.selinux",
++ xattr_selinux_coder, xattr_selinux_decoder, 0, false },
++ { "SCHILY.xattr.system.posix_acl_access",
++ xattr_acls_a_coder, xattr_acls_a_decoder, 0, false },
++ { "SCHILY.xattr.system.posix_acl_default",
++ xattr_acls_d_coder, xattr_acls_d_decoder, 0, false },
++
++ /* xattrs use the star format. note we only save some variants... */
++ { "SCHILY.xattr.user", xattr_coder, xattr_decoder, 0, true },
++ { "SCHILY.xattr.trusted", xattr_coder, xattr_decoder, 0, true },
++ { "SCHILY.xattr.lustre", xattr_coder, xattr_decoder, 0, true },
++ { "SCHILY.xattr.security.NTACL", xattr_coder, xattr_decoder, 0, true },
++
++ /* ignore everything else in the xattr namespaces... */
++ { "SCHILY.xattr", dummy_coder, dummy_decoder, 0, true },
+
+- { NULL, NULL, NULL, 0 }
++ { NULL, NULL, NULL, 0, false }
+ };
diff --git a/tar.spec b/tar.spec
index a10372a..d6df3ac 100644
--- a/tar.spec
+++ b/tar.spec
@@ -4,13 +4,13 @@
Summary: A GNU file archiving program
Name: tar
Epoch: 2
-Version: 1.23
-Release: 8%{?dist}
+Version: 1.24
+Release: 1%{?dist}
License: GPLv3+
Group: Applications/Archiving
URL: http://www.gnu.org/software/tar/
-Source0: ftp://ftp.gnu.org/pub/gnu/tar/tar-%{version}.tar.bz2
-Source1: ftp://ftp.gnu.org/pub/gnu/tar/tar-%{version}.tar.bz2.sig
+Source0: ftp://ftp.gnu.org/pub/gnu/tar/tar-%{version}.tar.xz
+Source1: ftp://ftp.gnu.org/pub/gnu/tar/tar-%{version}.tar.xz.sig
#Manpage for tar and gtar, a bit modified help2man generated manpage
Source2: tar.1
#Stop issuing lone zero block warnings
@@ -19,7 +19,7 @@ Patch1: tar-1.14-loneZeroWarning.patch
#when ftruncate may fail to grow the size of a file.(#179507)
Patch2: tar-1.15.1-vfatTruncate.patch
#Add support for selinux, acl and extended attributes
-Patch3: tar-1.23-xattrs.patch
+Patch3: tar-1.24-xattrs.patch
#change inclusion defaults of tar to "--wildcards --anchored
#--wildcards-match-slash" for compatibility reasons (#206841)
Patch4: tar-1.17-wildcards.patch
@@ -31,12 +31,10 @@ Patch5: tar-1.22-atime-rofs.patch
Patch6: tar-1.22-fortifysourcessigabrt.patch
#oldarchive option was not working(#594044)
Patch7: tar-1.23-oldarchive.patch
-#fix exclusion of long file names with --xattrs (#634866)
-Patch8: tar-1.23-longnames.patch
-#do not crash with --listed-incremental (#635318)
-Patch9: tar-1.23-listedincremental.patch
#match non-stripped file names (#637085)
-Patch10: tar-1.23-stripcomponents.patch
+Patch8: tar-1.23-stripcomponents.patch
+#fix bug with -C and extracting directories
+Patch9: tar-1.24-extractingdirs.patch
Requires: info
BuildRequires: autoconf automake gzip texinfo gettext libacl-devel gawk rsh
%if %{WITH_SELINUX}
@@ -67,9 +65,8 @@ the rmt package.
%patch5 -p1 -b .rofs
%patch6 -p1 -b .fortify
%patch7 -p1 -b .oldarchive
-%patch8 -p1 -b .longnames
-%patch9 -p1 -b .listedincremental
-%patch10 -p1 -b .stripcomponents
+%patch8 -p1 -b .stripcomponents
+%patch9 -p1 -b .extractC
autoreconf
@@ -131,6 +128,9 @@ fi
%{_infodir}/tar.info*
%changelog
+* Mon Oct 25 2010 Ondrej Vasik 2:1.24-1
+- new upstream release 1.24, use .xz archive
+
* Wed Sep 29 2010 jkeating - 2:1.23-8
- Rebuilt for gcc bug 634757