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;
 

Reply via email to