diff --git a/src/misc.c b/src/misc.c index ad9d8335..3988aa5a 100644 --- a/src/misc.c +++ b/src/misc.c @@ -1377,14 +1377,19 @@ fdbase_opendir (char const *file_name, bool alternate, int child_oflags) } } + /* Remove any old directory info, and add new info if the new + directory can be opened. */ + if (0 < c->subdirlen && !chdirable (fd)) + close (fd); + int newfd = open_subdir (chdir_fd, c->subdir, child_oflags); if (newfd < 0) - fd = BADFD == -1 ? newfd : BADFD; + { + c->subdirlen = 0; + fd = BADFD == -1 ? newfd : BADFD; + } else { - /* Remove any old directory info, and add new info. */ - if (0 < c->subdirlen && !chdirable (fd)) - close (fd); c->chdir_current = chdir_current; c->fd = fd = newfd; c->subdirlen = subdirlen; diff --git a/tests/Makefile.am b/tests/Makefile.am index 6583ba1b..b68fd83c 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -144,6 +144,7 @@ TESTSUITE_AT = \ extrac32.at\ extrac33.at\ extrac34.at\ + extrac35.at\ filerem01.at\ filerem02.at\ filerem03.at\ diff --git a/tests/extrac35.at b/tests/extrac35.at new file mode 100644 index 00000000..2a536afe --- /dev/null +++ b/tests/extrac35.at @@ -0,0 +1,37 @@ +# Check failed parent lookup does not corrupt the directory cache. -*- Autotest -*- + +# Copyright 2026 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 . + +AT_SETUP([failed parent lookup and directory cache]) +AT_KEYWORDS([extract extrac35 chdir]) + +AT_TAR_CHECK([ +mkdir -p src/a src/b dest +printf 'one\n' > src/a/one +printf 'two\n' > src/b/two + +tar -cf archive.tar -C src --no-recursion a/one b/two && +tar -xf archive.tar -C dest && +test -f dest/a/one && +test -f dest/b/two && +test ! -e dest/a/two && +cmp src/a/one dest/a/one && +cmp src/b/two dest/b/two +]) + +AT_CLEANUP diff --git a/tests/testsuite.at b/tests/testsuite.at index 9eb0d11c..29982cd1 100644 --- a/tests/testsuite.at +++ b/tests/testsuite.at @@ -361,6 +361,7 @@ m4_include([extrac31.at]) m4_include([extrac32.at]) m4_include([extrac33.at]) m4_include([extrac34.at]) +m4_include([extrac35.at]) m4_include([backup01.at])