From c5c6440baeacc6f605cb4c5ecec074c419bc7cf9 Mon Sep 17 00:00:00 2001 From: Sergey Poznyakoff Date: Sun, 16 Aug 2026 11:20:55 +0300 Subject: [PATCH] Accept relative file names in recursive exclude files. This fixes bug #68616: exclude lists supplied with --exclude-ignore-recursive now specify file names irrespective of the actual name of the containing directory. This also fixes processing of the VCS ignore files. * src/exclist.c (struct exclist): New fields: prefix, prefix_len. (info_attach_exclist): Store original directory name as prefix. (info_free_exclist): Free prefix. (excluded_name): Recompute rname at each loop stripping off the directory prefix. * tests/exclude21.at: New test. * tests/exclude22.at: New test. * tests/Makefile.am: Add new tests. * tests/testsuite.at: Include new tests. --- gnulib | 2 +- src/exclist.c | 14 ++++++++++++-- tests/Makefile.am | 2 ++ tests/exclude21.at | 47 ++++++++++++++++++++++++++++++++++++++++++++++ tests/exclude22.at | 47 ++++++++++++++++++++++++++++++++++++++++++++++ tests/testsuite.at | 2 ++ 6 files changed, 111 insertions(+), 3 deletions(-) create mode 100644 tests/exclude21.at create mode 100644 tests/exclude22.at diff --git a/gnulib b/gnulib index 5da32b6e..8d8198fa 160000 --- a/gnulib +++ b/gnulib @@ -1 +1 @@ -Subproject commit 5da32b6e05e27c71fd042ef10a4970b10862bc88 +Subproject commit 8d8198fa1efa3e33f3712afff2e99f98d44db468 diff --git a/src/exclist.c b/src/exclist.c index eee27416..56f7e735 100644 --- a/src/exclist.c +++ b/src/exclist.c @@ -66,6 +66,8 @@ struct exclist { struct exclist *next, *prev; int flags; + char *prefix; + size_t prefix_len; struct exclude *excluded; }; @@ -111,6 +113,8 @@ info_attach_exclist (struct tar_stat_info *dir) struct exclist *ent = xmalloc (sizeof *ent); ent->excluded = ex; ent->flags = file->flags; + ent->prefix_len = strlen (dir->orig_file_name); + ent->prefix = xstrdup (dir->orig_file_name); ent->prev = tail; ent->next = NULL; @@ -133,6 +137,7 @@ info_free_exclist (struct tar_stat_info *dir) { struct exclist *next = ep->next; free_exclude (ep->excluded); + free (ep->prefix); free (ep); ep = next; } @@ -146,7 +151,6 @@ bool excluded_name (char const *name, struct tar_stat_info *st) { struct exclist *ep; - const char *rname = NULL; char *bname = NULL; bool result; int nr = 0; @@ -164,12 +168,18 @@ excluded_name (char const *name, struct tar_stat_info *st) { for (ep = st->exclude_list; ep; ep = ep->next) { + const char *rname; + if (ep->flags & nr) continue; + if ((result = excluded_file_name (ep->excluded, name))) break; - if (!rname) + if (ep->prefix_len && strlen (name) > ep->prefix_len && + memcmp (name, ep->prefix, ep->prefix_len) == 0) + rname = name + ep->prefix_len; + else rname = name + dotslashlen (name); if ((result = excluded_file_name (ep->excluded, rname))) break; diff --git a/tests/Makefile.am b/tests/Makefile.am index b68fd83c..869ebf9c 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -110,6 +110,8 @@ TESTSUITE_AT = \ exclude18.at\ exclude19.at\ exclude20.at\ + exclude21.at\ + exclude22.at\ extrac01.at\ extrac02.at\ extrac03.at\ diff --git a/tests/exclude21.at b/tests/exclude21.at new file mode 100644 index 00000000..ebc721bd --- /dev/null +++ b/tests/exclude21.at @@ -0,0 +1,47 @@ +# Process this file with autom4te to create testsuite. -*- Autotest -*- + +# Test suite for GNU tar. +# 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([--exclude-ignore-recursive relative names]) +AT_KEYWORDS([exclude exclude-ignore-recursive extract exclude21]) +AT_TAR_CHECK([ +AT_SORT_PREREQ +mkdir dir dir/subdir +touch dir/file1 dir/file.ext dir/subdir/file2.foo dir/subdir/file3 \ + dir/subdir/file4.txt dir/subdir/file5.ext +cat > dir/ignorefile <<\EOT +ignorefile +*.ext +EOT +cat > dir/subdir/ignorefile <<\EOT +file4.txt +*.foo +EOT +tar -cf archive.tar --exclude-ignore-recursive=ignorefile dir +rm -rf dir +tar xfv archive.tar | sort +], +[0], +[dir/ +dir/file1 +dir/subdir/ +dir/subdir/file3 +]) + +AT_CLEANUP diff --git a/tests/exclude22.at b/tests/exclude22.at new file mode 100644 index 00000000..4f0addde --- /dev/null +++ b/tests/exclude22.at @@ -0,0 +1,47 @@ +# Process this file with autom4te to create testsuite. -*- Autotest -*- + +# Test suite for GNU tar. +# 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([--exclude-ignore-recursive with transforms]) +AT_KEYWORDS([exclude exclude-ignore-recursive extract exclude22]) +AT_TAR_CHECK([ +mkdir dir dir/subdir +touch dir/file1 dir/file.ext dir/subdir/file2.foo dir/subdir/file3 \ + dir/subdir/file4.txt dir/subdir/file5.ext +cat > dir/ignorefile <<\EOT +ignorefile +*.ext +EOT +cat > dir/subdir/ignorefile <<\EOT +file4.txt +*.foo +EOT +tar -cf archive.tar --exclude-ignore-recursive=ignorefile \ + --transform='s/^dir/DIRECTORY/' dir +rm -rf dir +tar xfv archive.tar | sort +], +[0], +[DIRECTORY/ +DIRECTORY/file1 +DIRECTORY/subdir/ +DIRECTORY/subdir/file3 +]) + +AT_CLEANUP diff --git a/tests/testsuite.at b/tests/testsuite.at index 29982cd1..812472ce 100644 --- a/tests/testsuite.at +++ b/tests/testsuite.at @@ -317,6 +317,8 @@ m4_include([exclude17.at]) m4_include([exclude18.at]) m4_include([exclude19.at]) m4_include([exclude20.at]) +m4_include([exclude21.at]) +m4_include([exclude22.at]) AT_BANNER([Deletions]) m4_include([delete01.at])