Hello!
I've previously posted this here in July 2020, but got no response at
all and the problems are still present, so I decided to remind about this.
I consider the issues to be important, because inadvertent omission of
files can be very damaging, e.g. to backups.
The original text follows.
I've found that --exclude-ignore option and --exclude-vcs-ignores with
.cvsignore act recursively, which contradicts the manual. A trivial
patch is attached.
The manual says
<https://www.gnu.org/software/tar/manual/html_section/tar_48.html> (6.4):
" `--exclude-vcs-ignores'
Before archiving a directory, see if it contains any of the
following files: `cvsignore', `.gitignore', `.bzrignore', or
`.hgignore'. If so, read ignore patterns from these files.
The patterns are treated much as the corresponding VCS would
treat them, i.e.:
`.cvsignore'
Contains shell-style globbing patterns that *apply only to
the directory where this file resides*. No comments are allowed in
the file. Empty lines are ignored.
<...>
`--exclude-ignore=file'
Before dumping a directory, tar checks if it contains file. If
so, exclusion patterns are read from this file. *The patterns affect
only the directory itself.*
`--exclude-ignore-recursive=file'
Same as `--exclude-ignore', except that the patterns read
affect both the directory where file resides and all its
subdirectories."
By the way, a dot is missing in front of cvsignore in the second line above.
Nevertheless, both options currently (in the latest git revision
01dd89c) act recursively.
How to reproduce for --exclude-ignore:
mkdir test test/a
touch test/b test/a/b
echo b > test/.ign
tar -cvf test.tar --exclude-ignore=.ign test
Current result:
test/
test/.ign
test/a/
Expected result: test/a/b must not be excluded.
The same for --exclude-vcs-ignores:
mkdir test test/a
touch test/b test/a/b
echo b > test/.cvsignore
tar -cvf test.tar --exclude-vcs-ignores test
Current result:
test/
test/a/
test/.cvsignore
Expected result: test/a/b must not be excluded.
I suspect a bug in info_attach_exclist() (exclist.c:116):
ent = xmalloc (sizeof (*ent));
ent->excluded = ex;
ent->flags = file->flags == EXCL_DEFAULT
? file->flags : vcsfile->flags;
ent->prev = tail;
ent->next = NULL;
Here file is an exclusion file added by some options. The currently
possible values of file->flags are as follows:
a) EXCL_DEFAULT corresponds to --exclude-vcs-ignores option and marks
standard VCS exclusion files. Such entries are created by
exclude_vcs_ignores();
b) EXCL_RECURSIVE corresponds to --exclude-ignore-recursive;
c) EXCL_NON_RECURSIVE corresponds to --exclude-ignore.
Currently neither EXCL_RECURSIVE nor EXCL_NON_RECURSIVE are propagated
from file->flags to ent->flags. Moreover, EXCL_NON_RECURSIVE flag in
vcsfile->flags of .cvsignore entry is dropped too, because for
.cvsignore file->flags == EXCL_DEFAULT.
It looks like the condition in the code above is just erroneously
inverted. I fixed this and the options started to work as expected.
--
WBR, Kirill Pushkaryov.
diff --git a/src/exclist.c b/src/exclist.c
index 297e27a..0000073 100644
--- a/src/exclist.c
+++ b/src/exclist.c
@@ -116,7 +116,7 @@ info_attach_exclist (struct tar_stat_info *dir)
ent = xmalloc (sizeof (*ent));
ent->excluded = ex;
ent->flags = file->flags == EXCL_DEFAULT
- ? file->flags : vcsfile->flags;
+ ? vcsfile->flags : file->flags;
ent->prev = tail;
ent->next = NULL;