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.
This commit is contained in:
Sergey Poznyakoff
2015-04-16 13:02:10 +03:00
parent 0c4aa85e6c
commit 15c02c2b9d
6 changed files with 107 additions and 6 deletions

View File

@@ -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);

View File

@@ -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_delayed_set_stat (data);
free (data->cntx_name);
free (data->acls_a_ptr);
free (data->acls_d_ptr);
free (data);
} }
} }

View File

@@ -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,

View File

@@ -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
tests/incr10.at Normal file
View File

@@ -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

View File

@@ -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])