From 4e742fc8674064a9fa00d4483d06aca48d5b0463 Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Sat, 26 Jul 2025 21:41:23 -0700 Subject: [PATCH] --no-overwrite-dir no overwrite even temporarily Problem and fix reported by Pavel Cahyna in https://lists.gnu.org/r/bug-tar/2025-01/msg00000.html * src/extract.c (extract_dir): With --no-overwrite-dir, skip the chmod if the directory already exists. * tests/extrac23.at (--no-overwrite-dir on empty directory): Move the part of the test that looks at a nonempty directory ... * tests/extrac30.at: ... to this new file, because the test now must be run as non-root. Adjust the test to match the new behavior. * tests/Makefile.am (TESTSUITE_AT), tests/testsuite.at: Add it. --- NEWS | 6 +++++- src/extract.c | 25 ------------------------ tests/Makefile.am | 1 + tests/extrac23.at | 16 +--------------- tests/extrac30.at | 47 ++++++++++++++++++++++++++++++++++++++++++++++ tests/testsuite.at | 1 + 6 files changed, 55 insertions(+), 41 deletions(-) create mode 100644 tests/extrac30.at diff --git a/NEWS b/NEWS index e12fff27..9a10b8b8 100644 --- a/NEWS +++ b/NEWS @@ -1,4 +1,4 @@ -GNU tar NEWS - User visible changes. 2025-07-25 +GNU tar NEWS - User visible changes. 2025-07-26 Please send GNU tar bug reports to version TBD @@ -45,6 +45,10 @@ option. ** Transformations that change case (e.g., --transform='s/.*/\L&/') now work correctly with multi-byte characters. +** --no-overwrite-dir no longer changes permissions of existing directories, + not even temporarily. This matches the documentation better and avoids + some permissions glitches. + ** tar now works better in strict debugging environments that do not allow pointer arithmetic to escape from a sub-element of an array. diff --git a/src/extract.c b/src/extract.c index 304e1f79..3b913c54 100644 --- a/src/extract.c +++ b/src/extract.c @@ -1158,31 +1158,6 @@ extract_dir (char *file_name, char typeflag) repair_delayed_set_stat (file_name, &st); return true; } - else if (old_files_option == NO_OVERWRITE_DIR_OLD_FILES) - { - /* Temporarily change the directory mode to a safe - value, to be able to create files in it, should - the need be. - */ - mode = safe_dir_mode (&st); - status = fd_chmod (-1, file_name, mode, - AT_SYMLINK_NOFOLLOW, DIRTYPE); - if (status == 0) - { - /* Store the actual directory mode, to be restored - later. - */ - current_stat_info.stat = st; - current_mode = mode & ~ current_umask; - current_mode_mask = MODE_RWX; - atflag = AT_SYMLINK_NOFOLLOW; - break; - } - else - { - chmod_error_details (file_name, mode); - } - } break; } } diff --git a/tests/Makefile.am b/tests/Makefile.am index bd13bfb2..cd879361 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -139,6 +139,7 @@ TESTSUITE_AT = \ extrac27.at\ extrac28.at\ extrac29.at\ + extrac30.at\ filerem01.at\ filerem02.at\ grow.at\ diff --git a/tests/extrac23.at b/tests/extrac23.at index c8943a73..9714ba59 100644 --- a/tests/extrac23.at +++ b/tests/extrac23.at @@ -15,15 +15,12 @@ # # You should have received a copy of the GNU General Public License # along with this program. If not, see . -AT_SETUP([--no-overwrite-dir]) +AT_SETUP([--no-overwrite-dir on empty directory]) AT_KEYWORDS([extract extrac23 no-overwrite-dir]) # Description: Implementation of the --no-overwrite-dir option was flawed in # tar versions up to 1.32.90. This option is intended to preserve metadata # of existing directories. In fact it worked only for non-empty directories. -# Moreover, if the actual directory was owned by the user tar runs as and the -# S_IWUSR bit was not set in its actual permissions, tar failed to create files -# in it. # # Reported by: Michael Kaufmann # References: <20200207112934.Horde.anXzYhAj2CHiwUrw5CuT0G-@webmail.michael-kaufmann.ch>, @@ -38,21 +35,10 @@ chmod 777 dir tar -xf a.tar --no-overwrite-dir genfile --stat=mode.777 dir -# Test if temporary permissions are set correctly to allow the owner -# to write to the directory. -genfile --file dir/file -tar cf a.tar dir -rm dir/file -chmod 400 dir -tar -xf a.tar --no-overwrite-dir -genfile --stat=mode.777 dir -chmod 700 dir find dir ], [0], [777 -400 dir -dir/file ]) AT_CLEANUP diff --git a/tests/extrac30.at b/tests/extrac30.at new file mode 100644 index 00000000..8c879c95 --- /dev/null +++ b/tests/extrac30.at @@ -0,0 +1,47 @@ +# Test suite for GNU tar. -*- Autotest -*- +# Copyright 2020-2025 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([--no-overwrite-dir on unwritable directory]) +AT_KEYWORDS([extract extrac30 no-overwrite-dir]) + +# Make sure that tar does not change permissions on directories if +# --no-overwrite-dir tells it not to, not even temporarily. + +AT_TAR_CHECK([ +AT_UNPRIVILEGED_PREREQ + +# Test that the user cannot write to a unwritable directory +# if --no-overwrite-dir is used. +mkdir dir +chmod 755 dir +genfile --file dir/file +tar cf a.tar dir +rm dir/file +chmod 555 dir +tar -xf a.tar --no-overwrite-dir +genfile --stat=mode.777 dir +chmod 755 dir +find dir +], +[0], +[555 +dir +], +[tar: dir/file: Cannot open: Permission denied +tar: Exiting with failure status due to previous errors +]) +AT_CLEANUP diff --git a/tests/testsuite.at b/tests/testsuite.at index 701f0389..e7e54f1e 100644 --- a/tests/testsuite.at +++ b/tests/testsuite.at @@ -356,6 +356,7 @@ m4_include([extrac26.at]) m4_include([extrac27.at]) m4_include([extrac28.at]) m4_include([extrac29.at]) +m4_include([extrac30.at]) m4_include([backup01.at]) -- 2.47.2