Forráskód Böngészése

Fix extraction from concatenated incremental archives with renamed directories.

Complements 15c02c2b.

* src/extract.c (delayed_set_stat): Change type of file_name.
(delay_set_stat): Allocate file_name member.
(free_delayed_set_stat): Free file_name.
(fixup_delayed_set_stat): New function.
(rename_directory): Call fixup_delayed_set_stat on success.

* tests/incr11.at: New testcase.
* tests/incr10.at: Improve description.
* tests/Makefile.am: Add incr11.at
* tests/testsuite.at: Add incr11.at
Sergey Poznyakoff 9 éve
szülő
commit
d02c81df15
5 módosított fájl, 102 hozzáadás és 6 törlés
  1. 24 5
      src/extract.c
  2. 1 0
      tests/Makefile.am
  3. 1 1
      tests/incr10.at
  4. 75 0
      tests/incr11.at
  5. 1 0
      tests/testsuite.at

+ 24 - 5
src/extract.c

@@ -109,7 +109,7 @@ struct delayed_set_stat
     struct xattr_array *xattr_map;
     struct xattr_array *xattr_map;
     /* Length and contents of name.  */
     /* Length and contents of name.  */
     size_t file_name_len;
     size_t file_name_len;
-    char file_name[1];
+    char *file_name;
   };
   };
 
 
 static struct delayed_set_stat *delayed_set_stat_head;
 static struct delayed_set_stat *delayed_set_stat_head;
@@ -441,9 +441,7 @@ delay_set_stat (char const *file_name, struct tar_stat_info const *st,
 		mode_t mode, int atflag)
 		mode_t mode, int atflag)
 {
 {
   size_t file_name_len = strlen (file_name);
   size_t file_name_len = strlen (file_name);
-  struct delayed_set_stat *data =
-    xmalloc (offsetof (struct delayed_set_stat, file_name)
-	     + file_name_len + 1);
+  struct delayed_set_stat *data = xmalloc (sizeof (*data));
   data->next = delayed_set_stat_head;
   data->next = delayed_set_stat_head;
   data->mode = mode;
   data->mode = mode;
   if (st)
   if (st)
@@ -456,6 +454,7 @@ delay_set_stat (char const *file_name, struct tar_stat_info const *st,
       data->mtime = st->mtime;
       data->mtime = st->mtime;
     }
     }
   data->file_name_len = file_name_len;
   data->file_name_len = file_name_len;
+  data->file_name = xstrdup (file_name);
   data->current_mode = current_mode;
   data->current_mode = current_mode;
   data->current_mode_mask = current_mode_mask;
   data->current_mode_mask = current_mode_mask;
   data->interdir = ! st;
   data->interdir = ! st;
@@ -540,6 +539,7 @@ repair_delayed_set_stat (char const *dir,
 static void
 static void
 free_delayed_set_stat (struct delayed_set_stat *data)
 free_delayed_set_stat (struct delayed_set_stat *data)
 {
 {
+  free (data->file_name);
   xheader_xattr_free (data->xattr_map, data->xattr_map_size);
   xheader_xattr_free (data->xattr_map, data->xattr_map_size);
   free (data->cntx_name);
   free (data->cntx_name);
   free (data->acls_a_ptr);
   free (data->acls_a_ptr);
@@ -569,6 +569,23 @@ remove_delayed_set_stat (const char *fname)
     }
     }
 }
 }
 
 
+static void
+fixup_delayed_set_stat (char const *src, char const *dst)
+{
+  struct delayed_set_stat *data;
+  for (data = delayed_set_stat_head; data; data = data->next)
+    {
+      if (chdir_current == data->change_dir
+	  && strcmp (data->file_name, src) == 0)
+	{
+	  free (data->file_name);
+	  data->file_name = xstrdup (dst);
+	  data->file_name_len = strlen (dst);
+	  return;
+	}
+    }
+}
+
 /* 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
@@ -1769,7 +1786,9 @@ extract_finish (void)
 bool
 bool
 rename_directory (char *src, char *dst)
 rename_directory (char *src, char *dst)
 {
 {
-  if (renameat (chdir_fd, src, chdir_fd, dst) != 0)
+  if (renameat (chdir_fd, src, chdir_fd, dst) == 0)
+    fixup_delayed_set_stat (src, dst);
+  else
     {
     {
       int e = errno;
       int e = errno;
       bool interdir_made;
       bool interdir_made;

+ 1 - 0
tests/Makefile.am

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

+ 1 - 1
tests/incr10.at

@@ -15,7 +15,7 @@
 # You should have received a copy of the GNU General Public License
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 
-AT_SETUP([concatenated incremental archives])
+AT_SETUP([concatenated incremental archives (deletes)])
 AT_KEYWORDS([incremental concat cat incr10])
 AT_KEYWORDS([incremental concat cat incr10])
 
 
 # Description: Extraction from concatenated incremental archives
 # Description: Extraction from concatenated incremental archives

+ 75 - 0
tests/incr11.at

@@ -0,0 +1,75 @@
+# 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/>.
+
+# Description: Extraction from concatenated incremental archives
+# produced spurious error messages when trying to set file ownership
+# and permissions on renamed directories
+# Reported by: Alex Efros <[email protected]>
+# References: <[email protected]>
+#             http://lists.gnu.org/archive/html/bug-tar/2015-11/msg00033.html
+
+AT_SETUP([concatenated incremental archives (renames)])
+AT_KEYWORDS([incremental concat cat incr11])
+
+AT_TAR_CHECK([
+AT_SORT_PREREQ
+AT_TAR_MKHIER([data/dir],[file])
+decho Level 0
+tar -cvf full.tar -g snap -C data .
+decho Level 1
+mv data/dir data/dir2
+tar -cvf incr.tar -g snap -C data .
+decho Concat
+cp full.tar full2.tar
+tar -A -f full2.tar incr.tar
+decho Extract
+mkdir out
+tar -xvf full2.tar -g /dev/null -C out
+decho List
+find out | sort
+],
+[0],
+[Level 0
+./
+./dir/
+./dir/file
+Level 1
+./
+./dir2/
+Concat
+Extract
+./
+./dir/
+./dir/file
+./
+./dir2/
+List
+out
+out/dir2
+out/dir2/file
+],
+[Level 0
+tar: .: Directory is new
+tar: ./dir: Directory is new
+Level 1
+tar: ./dir2: Directory has been renamed from './dir'
+Concat
+Extract
+List
+],[],[],[gnu])
+
+AT_CLEANUP

+ 1 - 0
tests/testsuite.at

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