diff options
-rw-r--r-- | NEWS | 7 | ||||
-rw-r--r-- | src/extract.c | 24 | ||||
-rw-r--r-- | tests/Makefile.am | 1 | ||||
-rw-r--r-- | tests/extrac21.at | 59 | ||||
-rw-r--r-- | tests/testsuite.at | 2 |
5 files changed, 87 insertions, 6 deletions
@@ -1,4 +1,4 @@ -GNU tar NEWS - User visible changes. 2017-04-06 +GNU tar NEWS - User visible changes. 2017-11-16 Please send GNU tar bug reports to <bug-tar@gnu.org> @@ -32,6 +32,11 @@ issued the following error message * --numeric-owner now affects private headers too. This helps the output of 'tar' to be more deterministic. +* Fixed the --delay-directory-restore option + +In some cases tar would restore the directory permissions too early, +causing subsequent link extractions in that directory to fail. + version 1.29 - Sergey Poznyakoff, 2016-05-16 diff --git a/src/extract.c b/src/extract.c index 6f5ba08d..36919dac 100644 --- a/src/extract.c +++ b/src/extract.c @@ -393,6 +393,24 @@ set_stat (char const *file_name, xattrs_selinux_set (st, file_name, typeflag); } +/* Find the direct ancestor of FILE_NAME in the delayed_set_stat list. + */ +static struct delayed_set_stat * +find_direct_ancestor (char const *file_name) +{ + struct delayed_set_stat *h = delayed_set_stat_head; + while (h) + { + if (h && ! h->after_links + && strncmp (file_name, h->file_name, h->file_name_len) == 0 + && ISSLASH (file_name[h->file_name_len]) + && (last_component (file_name) == file_name + h->file_name_len + 1)) + break; + h = h->next; + } + return h; +} + /* For each entry H in the leading prefix of entries in HEAD that do not have after_links marked, mark H and fill in its dev and ino members. Assume HEAD && ! HEAD->after_links. */ @@ -1304,11 +1322,7 @@ create_placeholder_file (char *file_name, bool is_symlink, bool *interdir_made) 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; - if (h && ! h->after_links - && strncmp (file_name, h->file_name, h->file_name_len) == 0 - && ISSLASH (file_name[h->file_name_len]) - && (last_component (file_name) == file_name + h->file_name_len + 1)) + if ((h = find_direct_ancestor (file_name)) != NULL) mark_after_links (h); return 0; diff --git a/tests/Makefile.am b/tests/Makefile.am index 88d183b0..2d7939d5 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -109,6 +109,7 @@ TESTSUITE_AT = \ extrac18.at\ extrac19.at\ extrac20.at\ + extrac21.at\ filerem01.at\ filerem02.at\ dirrem01.at\ diff --git a/tests/extrac21.at b/tests/extrac21.at new file mode 100644 index 00000000..671b1010 --- /dev/null +++ b/tests/extrac21.at @@ -0,0 +1,59 @@ +# Test suite for GNU tar. -*- Autotest -*- +# Copyright 2017 Free Software Foundation, Inc. +# +# This file is part of GNU tar. +# +# 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/>. + +# When called with the --delay-directory-restore option, tar would +# in some cases restore the directory permissions too early, before +# attempting to replace softlink placeholders with the actual link. +# This caused failure if the permissions forbade writing. +# +# The bug was caused by incorrect assumption about delayed_set_stat +# ordering in create_placeholder_file. +# +# Reported by: Giuseppe Scrivano <gscrivano@gnu.org> +# References: <878tfa17ti.fsf@redhat.com>, +# <http://lists.gnu.org/archive/html/bug-tar/2017-11/msg00009.html> + +AT_SETUP([delay-directory-restore]) +AT_KEYWORDS([extract extract21 read-only symlink delay-directory-restore]) +AT_TAR_CHECK([ +AT_UNPRIVILEGED_PREREQ + +mkdir a a/b a/c +genfile --file a/b/D +genfile --file a/c/A +cd a/b +ln -sf ../c/A +cd ../.. +chmod a-w a/b +tar --no-recurs -c -f A.tar a a/b a/b/D a/c a/b/A a/c/A +mkdir out +tar -C out -v -x -f A.tar --delay-directory-restore +], +[0], +[a/ +a/b/ +a/b/D +a/c/ +a/b/A +a/c/A +], +[],[],[],[ustar]) # Testing one format is enough + +AT_CLEANUP + + diff --git a/tests/testsuite.at b/tests/testsuite.at index 1f2c4ce9..2a837576 100644 --- a/tests/testsuite.at +++ b/tests/testsuite.at @@ -308,6 +308,8 @@ m4_include([extrac17.at]) m4_include([extrac18.at]) m4_include([extrac19.at]) m4_include([extrac20.at]) +m4_include([extrac21.at]) + m4_include([backup01.at]) AT_BANNER([Comparing]) |