a63c5cb
From 6bd6bf244fb1b6bc07eb9cd1cd0bfdfd76576219 Mon Sep 17 00:00:00 2001
a63c5cb
From: Pavel Raiskup <praiskup@redhat.com>
a63c5cb
Date: Fri, 11 Nov 2016 12:30:35 +0200
a63c5cb
Subject: [PATCH] don't set xattrs when --skip-old-files is used
a63c5cb
a63c5cb
* src/extract.c (set_xattr): Properly handle maybe_recoverable()
a63c5cb
output.  Throw warnings to not complicate caller.
a63c5cb
(extract_file): Don't handle set_xattr's error.
a63c5cb
* tests/xattr07.at: New testcase.
a63c5cb
* tests/Makefile.am: Mention new testcase.
a63c5cb
* tests/testsuite.at: Likewise.
a63c5cb
* THANKS: Dawid.
a63c5cb
a63c5cb
Upstream commits 597b0ae509 and ca9399d4e.
a63c5cb
---
a63c5cb
 THANKS             |  1 +
a63c5cb
 src/extract.c      | 41 +++++++++++++++++++-----------
a63c5cb
 tests/Makefile.am  |  1 +
a63c5cb
 tests/testsuite.at |  1 +
a63c5cb
 tests/xattr07.at   | 73 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
a63c5cb
 5 files changed, 102 insertions(+), 15 deletions(-)
a63c5cb
 create mode 100644 tests/xattr07.at
a63c5cb
a63c5cb
diff --git a/THANKS b/THANKS
a63c5cb
index 3dda4cc..559f240 100644
a63c5cb
--- a/THANKS
a63c5cb
+++ b/THANKS
a63c5cb
@@ -138,6 +138,7 @@ David Nugent		davidn@blaze.net.au
a63c5cb
 David Shaw		david.shaw@alcatel.com.au
a63c5cb
 David Steiner		dsteiner@ispa.uni-osnabrueck.de
a63c5cb
 David Taylor		taylor@think.com
a63c5cb
+Dawid			dpc@dpc.pw
a63c5cb
 Dean Gaudet		dgaudet@watdragon.uwaterloo.ca
a63c5cb
 Demizu Noritoshi	nori-d@is.aist-nara.ac.jp
a63c5cb
 Denis Excoffier         denis.excoffier@free.fr
a63c5cb
diff --git a/src/extract.c b/src/extract.c
a63c5cb
index f982433..67885d7 100644
a63c5cb
--- a/src/extract.c
a63c5cb
+++ b/src/extract.c
a63c5cb
@@ -795,13 +795,13 @@ maybe_recoverable (char *file_name, bool regular, bool *interdir_made)
a63c5cb
    in advance dramatically improves the following  performance of reading and
a63c5cb
    writing a file).  If not restoring permissions, invert the INVERT_PERMISSIONS
a63c5cb
    bits from the file's current permissions.  TYPEFLAG specifies the type of the
a63c5cb
-   file.  FILE_CREATED indicates set_xattr has created the file */
a63c5cb
+   file.  Returns non-zero when error occurs (while un-available xattrs is not
a63c5cb
+   an error, rather no-op).  Non-zero FILE_CREATED indicates set_xattr has
a63c5cb
+   created the file. */
a63c5cb
 static int
a63c5cb
 set_xattr (char const *file_name, struct tar_stat_info const *st,
a63c5cb
            mode_t invert_permissions, char typeflag, int *file_created)
a63c5cb
 {
a63c5cb
-  int status = 0;
a63c5cb
-
a63c5cb
 #ifdef HAVE_XATTRS
a63c5cb
   bool interdir_made = false;
a63c5cb
 
a63c5cb
@@ -809,17 +809,32 @@ set_xattr (char const *file_name, struct tar_stat_info const *st,
a63c5cb
     {
a63c5cb
       mode_t mode = current_stat_info.stat.st_mode & MODE_RWX & ~ current_umask;
a63c5cb
 
a63c5cb
-      do
a63c5cb
-        status = mknodat (chdir_fd, file_name, mode ^ invert_permissions, 0);
a63c5cb
-      while (status && maybe_recoverable ((char *)file_name, false,
a63c5cb
-                                          &interdir_made));
a63c5cb
+      for (;;)
a63c5cb
+        {
a63c5cb
+          if (!mknodat (chdir_fd, file_name, mode ^ invert_permissions, 0))
a63c5cb
+            {
a63c5cb
+              /* Successfully created file */
a63c5cb
+              xattrs_xattrs_set (st, file_name, typeflag, 0);
a63c5cb
+              *file_created = 1;
a63c5cb
+              return 0;
a63c5cb
+            }
a63c5cb
 
a63c5cb
-      xattrs_xattrs_set (st, file_name, typeflag, 0);
a63c5cb
-      *file_created = 1;
a63c5cb
+          switch (maybe_recoverable ((char *)file_name, false, &interdir_made))
a63c5cb
+            {
a63c5cb
+              case RECOVER_OK:
a63c5cb
+                continue;
a63c5cb
+              case RECOVER_NO:
a63c5cb
+                skip_member ();
a63c5cb
+                open_error (file_name);
a63c5cb
+                return 1;
a63c5cb
+              case RECOVER_SKIP:
a63c5cb
+                return 0;
a63c5cb
+            }
a63c5cb
+        }
a63c5cb
     }
a63c5cb
 #endif
a63c5cb
 
a63c5cb
-  return(status);
a63c5cb
+  return 0;
a63c5cb
 }
a63c5cb
 
a63c5cb
 /* Fix the statuses of all directories whose statuses need fixing, and
a63c5cb
@@ -1136,11 +1151,7 @@ extract_file (char *file_name, int typeflag)
a63c5cb
       int file_created = 0;
a63c5cb
       if (set_xattr (file_name, &current_stat_info, invert_permissions,
a63c5cb
                      typeflag, &file_created))
a63c5cb
-        {
a63c5cb
-          skip_member ();
a63c5cb
-          open_error (file_name);
a63c5cb
-          return 1;
a63c5cb
-        }
a63c5cb
+        return 1;
a63c5cb
 
a63c5cb
       while ((fd = open_output_file (file_name, typeflag, mode,
a63c5cb
                                      file_created, &current_mode,
a63c5cb
diff --git a/tests/Makefile.am b/tests/Makefile.am
a63c5cb
index abc17a4..4f3b918 100644
a63c5cb
--- a/tests/Makefile.am
a63c5cb
+++ b/tests/Makefile.am
a63c5cb
@@ -243,6 +243,7 @@ TESTSUITE_AT = \
a63c5cb
  xattr04.at\
a63c5cb
  xattr05.at\
a63c5cb
  xattr06.at\
a63c5cb
+ xattr07.at\
a63c5cb
  acls01.at\
a63c5cb
  acls02.at\
a63c5cb
  acls03.at\
a63c5cb
diff --git a/tests/testsuite.at b/tests/testsuite.at
a63c5cb
index db83c80..9493641 100644
a63c5cb
--- a/tests/testsuite.at
a63c5cb
+++ b/tests/testsuite.at
a63c5cb
@@ -440,6 +440,7 @@ m4_include([xattr03.at])
a63c5cb
 m4_include([xattr04.at])
a63c5cb
 m4_include([xattr05.at])
a63c5cb
 m4_include([xattr06.at])
a63c5cb
+m4_include([xattr07.at])
a63c5cb
 
a63c5cb
 m4_include([acls01.at])
a63c5cb
 m4_include([acls02.at])
a63c5cb
diff --git a/tests/xattr07.at b/tests/xattr07.at
a63c5cb
new file mode 100644
a63c5cb
index 0000000..a834981
a63c5cb
--- /dev/null
a63c5cb
+++ b/tests/xattr07.at
a63c5cb
@@ -0,0 +1,73 @@
a63c5cb
+# Process this file with autom4te to create testsuite. -*- Autotest -*-
a63c5cb
+#
a63c5cb
+# Test suite for GNU tar.
a63c5cb
+# Copyright 2011, 2013-2014, 2016 Free Software Foundation, Inc.
a63c5cb
+
a63c5cb
+# This file is part of GNU tar.
a63c5cb
+
a63c5cb
+# GNU tar is free software; you can redistribute it and/or modify
a63c5cb
+# it under the terms of the GNU General Public License as published by
a63c5cb
+# the Free Software Foundation; either version 3 of the License, or
a63c5cb
+# (at your option) any later version.
a63c5cb
+
a63c5cb
+# GNU tar is distributed in the hope that it will be useful,
a63c5cb
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
a63c5cb
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
a63c5cb
+# GNU General Public License for more details.
a63c5cb
+
a63c5cb
+# You should have received a copy of the GNU General Public License
a63c5cb
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
a63c5cb
+#
a63c5cb
+# Test description:
a63c5cb
+# Test that --keep-old-files doesn't change xattrs of already existing file.
a63c5cb
+# Per report:
a63c5cb
+# https://lists.gnu.org/archive/html/bug-tar/2016-10/msg00001.html
a63c5cb
+
a63c5cb
+AT_SETUP([xattrs: xattrs and --skip-old-files])
a63c5cb
+AT_KEYWORDS([xattrs xattr07])
a63c5cb
+
a63c5cb
+AT_TAR_CHECK([
a63c5cb
+AT_XATTRS_PREREQ
a63c5cb
+mkdir dir
a63c5cb
+genfile --file dir/file
a63c5cb
+genfile --file dir/file2
a63c5cb
+
a63c5cb
+setfattr -n user.test -v OurDirValue dir
a63c5cb
+setfattr -n user.test -v OurFileValue dir/file
a63c5cb
+setfattr -n user.test -v OurFileValue dir/file2
a63c5cb
+
039b671
+tar --xattrs --no-recursion -cf archive.tar dir dir/file dir/file2
a63c5cb
+
a63c5cb
+setfattr -n user.test -v OurDirValue2 dir
a63c5cb
+setfattr -n user.test -v OurFileValue2 dir/file
a63c5cb
+setfattr -n user.test -v OurFileValue2 dir/file2
a63c5cb
+
a63c5cb
+# Check that tar continues to file2 too!
a63c5cb
+tar --xattrs -xvf archive.tar --skip-old-files
a63c5cb
+tar --xattrs -xvf archive.tar --keep-old-files
a63c5cb
+
a63c5cb
+getfattr -h -d dir         | grep -v -e '^#' -e ^$
a63c5cb
+getfattr -h -d dir/file    | grep -v -e '^#' -e ^$
a63c5cb
+getfattr -h -d dir/file2   | grep -v -e '^#' -e ^$
a63c5cb
+],
a63c5cb
+[0],
a63c5cb
+[dir/
a63c5cb
+dir/file
a63c5cb
+dir/file2
a63c5cb
+dir/
a63c5cb
+dir/file
a63c5cb
+dir/file2
a63c5cb
+user.test="OurDirValue2"
a63c5cb
+user.test="OurFileValue2"
a63c5cb
+user.test="OurFileValue2"
a63c5cb
+], [tar: dir: skipping existing file
a63c5cb
+tar: dir/file: skipping existing file
a63c5cb
+tar: dir/file: skipping existing file
a63c5cb
+tar: dir/file2: skipping existing file
a63c5cb
+tar: dir/file2: skipping existing file
a63c5cb
+tar: dir/file: Cannot open: File exists
a63c5cb
+tar: dir/file2: Cannot open: File exists
a63c5cb
+tar: Exiting with failure status due to previous errors
a63c5cb
+])
a63c5cb
+
a63c5cb
+AT_CLEANUP
a63c5cb
-- 
a63c5cb
2.9.3
a63c5cb