Browse Source

Fix extraction from concatenated incremental archives.

* src/common.h (remove_delayed_set_stat): New proto.
* src/extract.c (free_delayed_set_stat)
(remove_delayed_set_stat): New function.
(apply_nonancestor_delayed_set_stat): Use free_delayed_set_stat.
* src/misc.c (safer_rmdir): Remove delayed_set_stat entry
corresponding to the removed directory.
* tests/incr10.at: New test case.
* tests/Makefile.am: Add new test.
* tests/testsuite.at: Likewise.
Sergey Poznyakoff 10 years ago
parent
commit
15c02c2b9d
6 changed files with 107 additions and 6 deletions
  1. 2 0
      src/common.h
  2. 33 5
      src/extract.c
  3. 6 1
      src/misc.c
  4. 1 0
      tests/Makefile.am
  5. 64 0
      tests/incr10.at
  6. 1 0
      tests/testsuite.at

+ 2 - 0
src/common.h

@@ -523,6 +523,8 @@ void extract_archive (void);
 void extract_finish (void);
 void extract_finish (void);
 bool rename_directory (char *src, char *dst);
 bool rename_directory (char *src, char *dst);
 
 
+void remove_delayed_set_stat (const char *fname);
+
 /* Module delete.c.  */
 /* Module delete.c.  */
 
 
 void delete_archive_members (void);
 void delete_archive_members (void);

+ 33 - 5
src/extract.c

@@ -537,6 +537,38 @@ repair_delayed_set_stat (char const *dir,
 	  quotearg_colon (dir)));
 	  quotearg_colon (dir)));
 }
 }
 
 
+static void
+free_delayed_set_stat (struct delayed_set_stat *data)
+{
+  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);
+}
+
+void
+remove_delayed_set_stat (const char *fname)
+{
+  struct delayed_set_stat *data, *next, *prev = NULL;
+  for (data = delayed_set_stat_head; data; data = next)
+    {
+      next = data->next;
+      if (chdir_current == data->change_dir
+	  && strcmp (data->file_name, fname) == 0)
+	{
+	  free_delayed_set_stat (data);
+	  if (prev)
+	    prev->next = next;
+	  else
+	    delayed_set_stat_head = next;
+	  return;
+	}
+      else
+	prev = data;
+    }
+}
+
 /* After a file/link/directory creation has failed, see if
 /* After a file/link/directory creation has failed, see if
    it's because some required directory was not present, and if so,
    it's because some required directory was not present, and if so,
    create all required directories.  Return zero if all the required
    create all required directories.  Return zero if all the required
@@ -846,11 +878,7 @@ apply_nonancestor_delayed_set_stat (char const *file_name, bool after_links)
 	}
 	}
 
 
       delayed_set_stat_head = data->next;
       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);
+      free_delayed_set_stat (data);
     }
     }
 }
 }
 
 

+ 6 - 1
src/misc.c

@@ -586,7 +586,12 @@ safer_rmdir (const char *file_name)
       return -1;
       return -1;
     }
     }
 
 
-  return unlinkat (chdir_fd, file_name, AT_REMOVEDIR);
+  if (unlinkat (chdir_fd, file_name, AT_REMOVEDIR) == 0)
+    {
+      remove_delayed_set_stat (file_name);
+      return 0;
+    }
+  return -1;
 }
 }
 
 
 /* Remove FILE_NAME, returning 1 on success.  If FILE_NAME is a directory,
 /* Remove FILE_NAME, returning 1 on success.  If FILE_NAME is a directory,

+ 1 - 0
tests/Makefile.am

@@ -116,6 +116,7 @@ TESTSUITE_AT = \
  incr07.at\
  incr07.at\
  incr08.at\
  incr08.at\
  incr09.at\
  incr09.at\
+ incr10.at\
  indexfile.at\
  indexfile.at\
  ignfail.at\
  ignfail.at\
  iotty.at\
  iotty.at\

+ 64 - 0
tests/incr10.at

@@ -0,0 +1,64 @@
+# Process this file with autom4te to create testsuite. -*- Autotest -*-
+# Test suite for GNU tar.
+# Copyright 2015 Free Software Foundation, Inc.
+#
+# GNU tar 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 of the License, or
+# (at your option) any later version.
+#
+# GNU tar 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 <http://www.gnu.org/licenses/>.
+
+AT_SETUP([concatenated incremental archives])
+AT_KEYWORDS([incremental concat cat incr10])
+
+# Description: Extraction from concatenated incremental archives
+# produced spurious error messages when trying to set file ownership
+# and permissions on deleted directories.
+# Reported by: Alex Efros <powerman@powerman.name>
+# References: <20150411224008.GO24600@home.power>
+#             http://lists.gnu.org/archive/html/bug-tar/2015-04/msg00003.html
+
+AT_TAR_CHECK([
+mkdir in
+mkdir in/dir
+decho Level 0
+tar -cvf 1.tar -g snap -C in .
+rmdir in/dir 
+decho Level 1
+tar -cvf 2.tar -g snap -C in .
+cp 1.tar full.tar 
+decho Concat
+tar -A 2.tar -f full.tar -g /dev/null
+decho Extract
+mkdir out
+tar -xvf full.tar -g /dev/null -C out
+],
+[0],
+[Level 0
+./
+./dir/
+Level 1
+./
+Concat
+Extract
+./
+./dir/
+./
+tar: Deleting './dir'
+],
+[Level 0
+tar: .: Directory is new
+tar: ./dir: Directory is new
+Level 1
+Concat
+Extract
+],[],[],[gnu])
+
+AT_CLEANUP

+ 1 - 0
tests/testsuite.at

@@ -303,6 +303,7 @@ m4_include([incr06.at])
 m4_include([incr07.at])
 m4_include([incr07.at])
 m4_include([incr08.at])
 m4_include([incr08.at])
 m4_include([incr09.at])
 m4_include([incr09.at])
+m4_include([incr10.at])
 
 
 AT_BANNER([Files removed while archiving])
 AT_BANNER([Files removed while archiving])
 m4_include([filerem01.at])
 m4_include([filerem01.at])