]> Dogcows Code - chaz/tar/commitdiff
Support exclusion patterns from various VCS ignore lists.
authorSergey Poznyakoff <gray@gnu.org.ua>
Fri, 21 Feb 2014 15:57:26 +0000 (17:57 +0200)
committerSergey Poznyakoff <gray@gnu.org.ua>
Sat, 22 Feb 2014 06:13:30 +0000 (08:13 +0200)
* src/Makefile.am (tar_SOURCES): Add exclist.c
* src/common.h (EXCL_DEFAULT, EXCL_RECURSIVE)
(EXCL_NON_RECURSIVE): New flags.
(excfile_add, info_attach_exclist)
(info_cleanup_exclist,info_free_exclist)
(exclude_vcs_ignores): New prototypes.
* src/create.c (dump_dir0): Call info_attach_exclist.
* src/exclist.c: New file.
* src/incremen.c (scan_directory): Call info_attach_exclist.
* src/names.c (excluded_name): Moved to exclist.c. Change signature.
All uses updated.
* src/tar.c: New options: --exclude-ignore, --exclude-ignore-recursive
and --exclude-vcs-ignores.
(tar_stat_destroy): Free exclist.
* src/tar.h (tar_stat_info): New member exclude_list.

* NEWS: Document new exclusion options.
* doc/tar.texi: Likewise.
* doc/tar.1: Likewise.

13 files changed:
NEWS
doc/tar.1
doc/tar.texi
src/Makefile.am
src/common.h
src/create.c
src/exclist.c [new file with mode: 0644]
src/incremen.c
src/list.c
src/names.c
src/tar.c
src/tar.h
src/update.c

diff --git a/NEWS b/NEWS
index ec9c8a75fb5c994a020e8ff8728d44031269a536..fa241425be910da0966db3aa1426cf969cf1b24f 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -1,4 +1,4 @@
-GNU tar NEWS - User visible changes. 2014-02-14
+GNU tar NEWS - User visible changes. 2014-02-21
 Please send GNU tar bug reports to <bug-tar@gnu.org>
 
 \f
@@ -48,6 +48,20 @@ is uniform and reproducible.  Using --sort=inode reduces the number
 of disk seeks made when creating the archive and thus can considerably
 speed up archivation.
 
+* New exclusion options
+
+  --exclude-ignore=FILE   Before dumping a directory check if it
+                          contains FILE, and if so read exclude
+                          patterns for this directory from FILE.
+  --exclude-ignore-recursive=FILE
+                          Same as above, but the exclusion patterns
+                          read from FILE remain in effect for any
+                         subdirectory, recursively.
+  --exclude-vcs-ignores   Read exclude tags from VCS ignore files,
+                          where such files exist.  Supported VCS's
+                          are: CVS, Git, Bazaar, Mercurial.
+                         
+
 * Manpages
 
 This release includes official tar(1) and rmt(8) manpages.
index b33f55b9060e27887fdf6e94c25c60023ddcd347..cd133d9ed858d8e904651d0dc4b3b72749df0d00 100644 (file)
--- a/doc/tar.1
+++ b/doc/tar.1
@@ -13,7 +13,7 @@
 .\"
 .\" You should have received a copy of the GNU General Public License
 .\" along with this program.  If not, see <http://www.gnu.org/licenses/>.
-.TH TAR 1 "February 14, 2014" "TAR" "GNU TAR Manual"
+.TH TAR 1 "February 22, 2014" "TAR" "GNU TAR Manual"
 .SH NAME
 tar \- an archiving utility
 .SH SYNOPSIS
@@ -788,6 +788,15 @@ Exclude directories containing file \fBCACHEDIR.TAG\fR and the file itself.
 \fB\-\-exclude\-caches\-under\fR
 Exclude everything under directories containing \fBCACHEDIR.TAG\fR
 .TP
+\fB\-\-exclude\-ignore=\fIFILE\fR
+Before dumping a directory, see if it contains \fIFILE\fR.
+If so, read exclusion patterns from this file.  The patterns affect
+only the directory itself.
+.TP
+\fB\-\-exclude\-ignore\-recursive=\fIFILE\fR
+Same as \fB\-\-exclude\-ignore\fR, except that patterns from
+\fIFILE\fR affect both the directory and all its subdirectories.
+.TP
 \fB\-\-exclude\-tag\fR=\fIFILE\fR
 Exclude contents of directories containing \fIFILE\fR, except for
 \fIFILE\fR itself.
@@ -801,6 +810,14 @@ Exclude everything under directories containing \fIFILE\fR.
 \fB\-\-exclude\-vcs\fR
 Exclude version control system directories.
 .TP
+\fB\-\-exclude\-vcs\-ignores\fR
+Exclude files that match patterns read from VCS-specific ignore
+files.  Supported files are:
+.BR .cvsignore ,
+.BR .gitignore ,
+.BR .bzrignore ", and"
+.BR .hgignore .
+.TP
 \fB\-h\fR, \fB\-\-dereference\fR
 Follow symlinks; archive and dump the files they point to.
 .TP
index 9bb5a833c8c4c0d09d6f8012c13c44ab52dfc1d4..e3df0c98b238cfd2326452888048598a91de80ad 100644 (file)
@@ -2608,6 +2608,19 @@ tag file, but still dump the directory node itself.
 Exclude from dump any directory containing a valid cache directory
 tag file.  @xref{exclude}.
 
+@opsummary{exclude-ignore}
+@item --exclude-ignore=@var{file}
+Before dumping a directory, @command{tar} checks if it contains
+@var{file}.  If so, exclusion patterns are read from this file.
+The patterns affect only the directory itself.  @xref{exclude}.
+
+@opsummary{exclude-ignore-recursive}
+@item --exclude-ignore-recursive=@var{file}
+Before dumping a directory, @command{tar} checks if it contains
+@var{file}.  If so, exclusion patterns are read from this file.
+The patterns affect the directory and all itssubdirectories.
+@xref{exclude}.
+
 @opsummary{exclude-tag}
 @item --exclude-tag=@var{file}
 
@@ -2633,7 +2646,16 @@ Exclude from dump any directory containing file named @var{file}.
 Exclude from dump directories and files, that are internal for some
 widely used version control systems.
 
-@xref{exclude,,exclude-vcs}.
+@xref{exclude-vcs}.
+
+@opsummary{exclude-vcs-ignores}
+@item --exclude-vcs-ignores
+Exclude files that match patterns read from VCS-specific ignore
+files.  Supported files are: @file{.cvsignore}, @file{.gitignore},
+@file{.bzrignore}, and @file{.hgignore}.  The semantics of each file
+is the same as for the corresponding VCS, e.g. patterns read from
+@file{.gitignore} affect the directory and all its subdirectories.
+@xref{exclude-vcs-ignores}.
 
 @opsummary{file}
 @item --file=@var{archive}
@@ -7381,6 +7403,77 @@ which is difficult to catch using text editors.
 
 However, empty lines are OK.
 
+@cindex VCS, excluding patterns from ignore files
+@cindex VCS, ignore files
+@cindex CVS, ignore files
+@cindex Git, ignore files
+@cindex Bazaar, ignore files
+@cindex Mercurial, ignore files
+When archiving directories that are under some version control system (VCS), 
+it is often convenient to read exclusion patterns from this VCS'
+ignore files (e.g. @file{.cvsignore}, @file{.gitignore}, etc.)  The
+following options provide such possibilty:
+
+@table @option
+@anchor{exclude-vcs-ignores}
+@opindex exclude-vcs-ignores
+@item --exclude-vcs-ignores
+Before archiving a directory, see if it contains any of the following
+files: @file{cvsignore}, @file{.gitignore}, @file{.bzrignore}, or
+@file{.hgignore}.  If so, read ignore patterns from these files.
+
+The patterns are treated much as the corresponding VCS would treat
+them, i.e.:
+
+@table @file
+@findex .cvsignore
+@item .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.
+
+@findex .gitignore
+@item .gitignore
+Contains shell-style globbing patterns.  Applies to the directory
+where @file{.gitfile} is located and all its subdirectories.
+
+Any line beginning with a @samp{#} is a comment.  Backslash escapes
+the comment character.
+
+@findex .bzrignore
+@item .bzrignore
+Contains shell globbing-patterns and regular expressions (if prefixed
+with @samp{RE:}@footnote{According to the Bazaar docs,
+globbing-patterns are Korn-shell style and regular expressions are
+perl-style.  As of @GNUTAR{} version @value{VERSION}, these are
+treated as shell-style globs and posix extended regexps.  This will be
+fixed in future releases.}.  Patterns affect the directory and all its
+subdirectories.
+
+Any line beginning with a @samp{#} is a comment.
+
+@findex .hgignore
+@item .hgignore
+Contains posix regular expressions@footnote{Support for perl-style
+regexps will appear in future releases.}.  The line @samp{syntax:
+glob} switches to shell globbing patterns.  The line @samp{syntax:
+regexp} switches back.  Comments begin with a @samp{#}.  Patterns
+affect the directory and all its subdirectories.
+@end table
+
+@opindex exclude-ignore
+@item --exclude-ignore=@var{file}
+Before dumping a directory, @command{tar} checks if it contains
+@var{file}.  If so, exclusion patterns are read from this file.
+The patterns affect only the directory itself.
+
+@opindex exclude-ignore-recursive
+@item --exclude-ignore-recursive=@var{file}
+Same as @option{--exclude-ignore}, except that the patterns read
+affect both the directory where @var{file} resides and all its
+subdirectories.
+@end table
+
 @table @option
 @cindex version control system, excluding files
 @cindex VCS, excluding files
@@ -7393,6 +7486,7 @@ However, empty lines are OK.
 @cindex Arch, excluding files
 @cindex Mercurial, excluding files
 @cindex Darcs, excluding files
+@anchor{exclude-vcs}
 @opindex exclude-vcs
 @item --exclude-vcs
 Exclude files and directories used by following version control
index a9d25efa4ba997bda1aa7473b1af3ecee0007d75..82b2d4628510754d0283141a3c2ffc186ae2f000 100644 (file)
@@ -28,6 +28,7 @@ tar_SOURCES = \
  create.c\
  delete.c\
  exit.c\
+ exclist.c\
  extract.c\
  xheader.c\
  incremen.c\
index 4d2c3994181051b6bfa95b537ee3219dfb80e2fe..edf787c8316f98c3a4e9c696b8b26d26bff8baf9 100644 (file)
@@ -743,8 +743,6 @@ char *new_name (const char *dir_name, const char *name);
 size_t stripped_prefix_len (char const *file_name, size_t num);
 bool all_names_found (struct tar_stat_info *st);
 
-bool excluded_name (char const *name);
-
 void add_avoided_name (char const *name);
 bool is_avoided_name (char const *name);
 
@@ -921,4 +919,16 @@ void finish_deferred_unlinks (void);
 /* Module exit.c */
 extern void (*fatal_exit_hook) (void);
 
+/* Module exclist.c */
+#define EXCL_DEFAULT       0x00
+#define EXCL_RECURSIVE     0x01
+#define EXCL_NON_RECURSIVE 0x02
+
+void excfile_add (const char *name, int flags);
+void info_attach_exclist (struct tar_stat_info *dir);
+void info_cleanup_exclist (struct tar_stat_info *dir);
+void info_free_exclist (struct tar_stat_info *dir);
+bool excluded_name (char const *name, struct tar_stat_info *st);
+void exclude_vcs_ignores (void);
+
 _GL_INLINE_HEADER_END
index 3455bddc60c74016bcad238e0e416ee1f2ad5895..e2f4ede6b8d12c1200c931f9f425c9537a72906b 100644 (file)
@@ -1113,6 +1113,8 @@ dump_dir0 (struct tar_stat_info *st, char const *directory)
   if (!blk)
     return;
 
+  info_attach_exclist (st);
+  
   if (incremental_option && archive_format != POSIX_FORMAT)
     blk->header.typeflag = GNUTYPE_DUMPDIR;
   else /* if (standard_option) */
@@ -1196,7 +1198,7 @@ dump_dir0 (struct tar_stat_info *st, char const *directory)
            char const *entry;
            size_t entry_len;
            size_t name_len;
-
+           
            name_buf = xstrdup (st->orig_file_name);
            name_size = name_len = strlen (name_buf);
 
@@ -1210,7 +1212,7 @@ dump_dir0 (struct tar_stat_info *st, char const *directory)
                    name_buf = xrealloc (name_buf, name_size + 1);
                  }
                strcpy (name_buf + name_len, entry);
-               if (!excluded_name (name_buf))
+               if (!excluded_name (name_buf, st))
                  dump_file (st, entry, name_buf);
              }
 
@@ -1339,12 +1341,12 @@ create_archive (void)
       collect_and_sort_names ();
 
       while ((p = name_from_list ()) != NULL)
-       if (!excluded_name (p->name))
+       if (!excluded_name (p->name, NULL))
          dump_file (0, p->name, p->name);
 
       blank_name_list ();
       while ((p = name_from_list ()) != NULL)
-       if (!excluded_name (p->name))
+       if (!excluded_name (p->name, NULL))
          {
            struct tar_stat_info st;
            size_t plen = strlen (p->name);
@@ -1358,7 +1360,7 @@ create_archive (void)
            if (! ISSLASH (buffer[plen - 1]))
              buffer[plen++] = DIRECTORY_SEPARATOR;
            tar_stat_init (&st);
-           q = directory_contents (gnu_list_name->directory);
+           q = directory_contents (p->directory);
            if (q)
              while (*q)
                {
@@ -1401,7 +1403,7 @@ create_archive (void)
     {
       const char *name;
       while ((name = name_next (1)) != NULL)
-       if (!excluded_name (name))
+       if (!excluded_name (name, NULL))
          dump_file (0, name, name);
     }
 
diff --git a/src/exclist.c b/src/exclist.c
new file mode 100644 (file)
index 0000000..7cccc74
--- /dev/null
@@ -0,0 +1,361 @@
+/* Per-directory exclusion files for tar.
+
+   Copyright 2014 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 <http://www.gnu.org/licenses/>.
+*/
+#include <system.h>
+#include <quotearg.h>
+#include <fnmatch.h>
+#include <wordsplit.h>
+#include "common.h"
+
+typedef void (*add_fn) (struct exclude *, char const *, int, void *);
+
+struct vcs_ignore_file
+{
+  char const *filename;
+  int flags;
+  add_fn addfn;
+  void *(*initfn) (void *);
+  void *data;
+};
+
+static struct vcs_ignore_file *get_vcs_ignore_file (const char *name);
+\f
+struct excfile
+{
+  struct excfile *next;
+  int flags;
+  char name[1];
+};
+
+struct excfile *excfile_head, *excfile_tail;
+
+void
+excfile_add (const char *name, int flags)
+{
+  struct excfile *p = xmalloc (sizeof (*p) + strlen (name));
+  p->next = NULL;
+  p->flags = flags;
+  strcpy (p->name, name);
+  if (excfile_tail)
+    excfile_tail->next = p;
+  else
+    excfile_head = p;
+  excfile_tail = p;
+}
+
+struct exclist
+{
+  struct exclist *next, *prev;
+  int flags;
+  struct exclude *excluded;
+};
+
+void
+info_attach_exclist (struct tar_stat_info *dir)
+{
+  struct excfile *file;
+  struct exclist *head = NULL, *tail = NULL, *ent;
+  struct vcs_ignore_file *vcsfile;
+    
+  if (dir->exclude_list)
+    return;
+  for (file = excfile_head; file; file = file->next)
+    {
+      if (faccessat (dir ? dir->fd : chdir_fd, file->name, F_OK, 0) == 0)
+       {
+         FILE *fp;
+         struct exclude *ex = NULL;
+         int fd = subfile_open (dir, file->name, O_RDONLY);
+         if (fd == -1)
+           {
+             open_error (file->name);
+             continue;
+           }
+         fp = fdopen (fd, "r");
+         if (!fp)
+           {
+             ERROR ((0, errno, _("%s: fdopen failed"), file->name));
+             close (fd);
+             continue;
+           }
+
+         if (!ex)
+           ex = new_exclude ();
+
+         vcsfile = get_vcs_ignore_file (file->name);
+
+         if (vcsfile->initfn)
+           vcsfile->data = vcsfile->initfn (vcsfile->data);
+         
+         if (add_exclude_fp (vcsfile->addfn, ex, fp,
+                             EXCLUDE_WILDCARDS|EXCLUDE_ANCHORED, '\n',
+                             vcsfile->data))
+           {
+             int e = errno;
+             FATAL_ERROR ((0, e, "%s", quotearg_colon (file->name)));
+           }
+         fclose (fp);
+         
+         ent = xmalloc (sizeof (*ent));
+         ent->excluded = ex;
+         ent->flags = file->flags == EXCL_DEFAULT
+                      ? file->flags : vcsfile->flags;
+         ent->prev = tail;
+         ent->next = NULL;
+
+         if (tail)
+           tail->next = ent;
+         else
+           head = ent;
+         tail = ent;
+       }
+    }
+  dir->exclude_list = head;
+}
+
+void
+info_cleanup_exclist (struct tar_stat_info *dir)
+{
+  struct exclist *ep = dir->exclude_list;
+
+  while (ep)
+    {
+      struct exclist *next = ep->next;
+      
+      if (ep->flags & EXCL_NON_RECURSIVE)
+       {
+         
+         /* Remove the entry */
+         if (ep->prev)
+           ep->prev->next = ep->next;
+         else
+           dir->exclude_list = ep->next;
+
+         if (ep->next)
+           ep->next->prev = ep->prev;
+
+         free_exclude (ep->excluded);
+         free (ep);
+       }
+      ep = next;
+    }
+}
+
+void
+info_free_exclist (struct tar_stat_info *dir)
+{
+  struct exclist *ep = dir->exclude_list;
+
+  while (ep)
+    {
+      struct exclist *next = ep->next;
+      free_exclude (ep->excluded);
+      free (ep);
+      ep = next;
+    }
+
+  dir->exclude_list = NULL;
+}
+  
+
+/* Return nonzero if file NAME is excluded.  */
+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;
+  
+  name += FILE_SYSTEM_PREFIX_LEN (name);
+
+  /* Try global exclusion list first */
+  if (excluded_file_name (excluded, name))
+    return true;
+
+  if (!st)
+    return false;
+  
+  for (result = false; st && !result; st = st->parent, nr = EXCL_NON_RECURSIVE)
+    {
+      for (ep = st->exclude_list; ep; ep = ep->next)
+       {
+         if (ep->flags & nr)
+           continue;
+         if ((result = excluded_file_name (ep->excluded, name)))
+           break;
+         
+         if (!rname)
+           {
+             rname = name;
+             /* Skip leading ./ */
+             while (*rname == '.' && ISSLASH (rname[1]))
+               rname += 2;
+           }
+         if ((result = excluded_file_name (ep->excluded, rname)))
+           break;
+
+         if (!bname)
+           bname = base_name (name);
+         if ((result = excluded_file_name (ep->excluded, bname)))
+           break;
+       }
+    }
+
+  free (bname);
+
+  return result;
+}
+\f
+static void
+cvs_addfn (struct exclude *ex, char const *pattern, int options, void *data)
+{
+  struct wordsplit ws;
+  size_t i;
+    
+  if (wordsplit (pattern, &ws, 
+                WRDSF_NOVAR | WRDSF_NOCMD | WRDSF_SQUEEZE_DELIMS))
+    return;
+  for (i = 0; i < ws.ws_wordc; i++)
+    add_exclude (ex, ws.ws_wordv[i], options);
+  wordsplit_free (&ws);
+}
+
+static void
+git_addfn (struct exclude *ex, char const *pattern, int options, void *data)
+{
+  while (isspace (*pattern))
+    ++pattern;
+  if (*pattern == 0 || *pattern == '#')
+    return;
+  if (*pattern == '\\' && pattern[1] == '#')
+    ++pattern;
+  add_exclude (ex, pattern, options);
+}
+
+static void
+bzr_addfn (struct exclude *ex, char const *pattern, int options, void *data)
+{
+  while (isspace (*pattern))
+    ++pattern;
+  if (*pattern == 0 || *pattern == '#')
+    return;
+  if (*pattern == '!')
+    {
+      if (*++pattern == '!')
+       ++pattern;
+      else
+       options |= EXCLUDE_INCLUDE;
+    }
+  /* FIXME: According to the docs, globbing patterns are rsync-style,
+            and regexps are perl-style. */
+  if (strncmp (pattern, "RE:", 3) == 0)
+    {
+      pattern += 3;
+      options &= ~EXCLUDE_WILDCARDS;
+      options |= EXCLUDE_REGEX;
+    }
+  add_exclude (ex, pattern, options);
+}
+
+static void *
+hg_initfn (void *data)
+{
+  int *hgopt;
+  static int hg_options;
+  
+  if (!data)
+    hgopt = &hg_options;
+
+  *hgopt = EXCLUDE_REGEX;
+  return hgopt;
+}
+  
+static void
+hg_addfn (struct exclude *ex, char const *pattern, int options, void *data)
+{
+  int *hgopt = data;
+  size_t len;
+  
+  while (isspace (*pattern))
+    ++pattern;
+  if (*pattern == 0 || *pattern == '#')
+    return;
+  if (strncmp (pattern, "syntax:", 7) == 0)
+    {
+      for (pattern += 7; isspace (*pattern); ++pattern)
+       ;
+      if (strcmp (pattern, "regexp") == 0)
+       /* FIXME: Regexps must be perl-style */
+       *hgopt = EXCLUDE_REGEX;
+      else if (strcmp (pattern, "glob") == 0)
+       *hgopt = EXCLUDE_WILDCARDS;
+      /* Ignore unknown syntax */
+      return;
+    }
+
+  len = strlen(pattern);
+  if (pattern[len-1] == '/')
+    {
+      char *p;
+
+      --len;
+      p = xmalloc (len+1);
+      memcpy (p, pattern, len); 
+      p[len] = 0;
+      pattern = p;
+      exclude_add_pattern_buffer (ex, p);
+      options |= FNM_LEADING_DIR|EXCLUDE_ALLOC;
+    }
+  
+  add_exclude (ex, pattern,
+              ((*hgopt == EXCLUDE_REGEX)
+               ? (options & ~EXCLUDE_WILDCARDS)
+               : (options & ~EXCLUDE_REGEX)) | *hgopt);
+}
+\f
+struct vcs_ignore_file vcs_ignore_files[] = {
+  { ".cvsignore", EXCL_NON_RECURSIVE, cvs_addfn, NULL, NULL },
+  { ".gitignore", 0, git_addfn, NULL, NULL },
+  { ".bzrignore", 0, bzr_addfn, NULL, NULL },
+  { ".hgignore",  0, hg_addfn, hg_initfn , NULL },
+  { NULL, 0, git_addfn, NULL, NULL }
+};
+  
+static struct vcs_ignore_file *
+get_vcs_ignore_file (const char *name)
+{
+  struct vcs_ignore_file *p;
+
+  for (p = vcs_ignore_files; p->filename; p++)
+    if (strcmp (p->filename, name) == 0)
+      break;
+
+  return p;
+}
+\f
+void
+exclude_vcs_ignores (void)
+{
+  struct vcs_ignore_file *p;
+
+  for (p = vcs_ignore_files; p->filename; p++)
+    excfile_add (p->filename, EXCL_DEFAULT);
+}
index 884d2fa2865831ad3a8ffec73aa617872324fa33..b1b70ba41764b04049853d12834cf520d12f0254 100644 (file)
@@ -734,6 +734,8 @@ scan_directory (struct tar_stat_info *st)
   if (! dirp)
     savedir_error (dir);
 
+  info_attach_exclist (st);
+  
   tmp = xstrdup (dir);
   zap_slashes (tmp);
 
@@ -762,7 +764,7 @@ scan_directory (struct tar_stat_info *st)
 
              if (*entry == 'I') /* Ignored entry */
                *entry = 'N';
-             else if (excluded_name (full_name))
+             else if (excluded_name (full_name, st))
                *entry = 'N';
              else
                {
index d46be651cb3752b0f1fe2d0fc29d79a8a256feb3..b4277e028e59f9672fbb5b247574fcad5c8e41c9 100644 (file)
@@ -203,7 +203,8 @@ read_and (void (*do_something) (void))
                      mtime.tv_nsec = 0,
                      current_stat_info.mtime = mtime,
                      OLDER_TAR_STAT_TIME (current_stat_info, m)))
-             || excluded_name (current_stat_info.file_name))
+             || excluded_name (current_stat_info.file_name,
+                               current_stat_info.parent))
            {
              switch (current_header->header.typeflag)
                {
index 60a5f700c3acaa3412e14b4da7cf6c3b900c96a7..9fc0ad5888ccc0f75e5c4d8da6925d807d4b1f66 100644 (file)
@@ -1373,12 +1373,6 @@ new_name (const char *file_name, const char *name)
   return buffer;
 }
 
-/* Return nonzero if file NAME is excluded.  */
-bool
-excluded_name (char const *name)
-{
-  return excluded_file_name (excluded, name + FILE_SYSTEM_PREFIX_LEN (name));
-}
 \f
 
 /* Return the size of the prefix of FILE_NAME that is removed after
index 08f334f554f50f0376576baaf51aa2199549f9de..ac32f97c02ea78bd1b396887d912109a84754914 100644 (file)
--- a/src/tar.c
+++ b/src/tar.c
@@ -284,10 +284,13 @@ enum
   EXCLUDE_CACHES_UNDER_OPTION,
   EXCLUDE_CACHES_ALL_OPTION,
   EXCLUDE_OPTION,
+  EXCLUDE_IGNORE_OPTION,
+  EXCLUDE_IGNORE_RECURSIVE_OPTION,
   EXCLUDE_TAG_OPTION,
   EXCLUDE_TAG_UNDER_OPTION,
   EXCLUDE_TAG_ALL_OPTION,
   EXCLUDE_VCS_OPTION,
+  EXCLUDE_VCS_IGNORES_OPTION,
   FORCE_LOCAL_OPTION,
   FULL_TIME_OPTION,
   GROUP_OPTION,
@@ -732,12 +735,20 @@ static struct argp_option options[] = {
   {"exclude-tag", EXCLUDE_TAG_OPTION, N_("FILE"), 0,
    N_("exclude contents of directories containing FILE, except"
       " for FILE itself"), GRID+1 },
+  {"exclude-ignore", EXCLUDE_IGNORE_OPTION, N_("FILE"), 0,
+    N_("read exclude patterns for each directory from FILE, if it exists"),
+   GRID+1 }, 
+  {"exclude-ignore-recursive", EXCLUDE_IGNORE_RECURSIVE_OPTION, N_("FILE"), 0,
+    N_("read exclude patterns for each directory and its subdirectories "
+       "from FILE, if it exists"), GRID+1 },
   {"exclude-tag-under", EXCLUDE_TAG_UNDER_OPTION, N_("FILE"), 0,
    N_("exclude everything under directories containing FILE"), GRID+1 },
   {"exclude-tag-all", EXCLUDE_TAG_ALL_OPTION, N_("FILE"), 0,
    N_("exclude directories containing FILE"), GRID+1 },
   {"exclude-vcs", EXCLUDE_VCS_OPTION, NULL, 0,
    N_("exclude version control system directories"), GRID+1 },
+  {"exclude-vcs-ignores", EXCLUDE_VCS_IGNORES_OPTION, NULL, 0,
+   N_("read exclude patterns from the VCS ignore files"), GRID+1 },
   {"exclude-backups", EXCLUDE_BACKUPS_OPTION, NULL, 0,
    N_("exclude backup and lock files"), GRID+1 },
   {"no-recursion", NO_RECURSION_OPTION, 0, 0,
@@ -1776,6 +1787,14 @@ parse_opt (int key, char *arg, struct argp_state *state)
                         cachedir_file_p);
       break;
 
+    case EXCLUDE_IGNORE_OPTION:
+      excfile_add (arg, EXCL_NON_RECURSIVE);
+      break;
+
+    case EXCLUDE_IGNORE_RECURSIVE_OPTION:
+      excfile_add (arg, EXCL_RECURSIVE);
+      break;
+      
     case EXCLUDE_TAG_OPTION:
       add_exclusion_tag (arg, exclusion_tag_contents, NULL);
       break;
@@ -1792,6 +1811,10 @@ parse_opt (int key, char *arg, struct argp_state *state)
       add_exclude_array (vcs_file_table, 0);
       break;
 
+    case EXCLUDE_VCS_IGNORES_OPTION:
+      exclude_vcs_ignores ();
+      break;
+      
     case FORCE_LOCAL_OPTION:
       force_local_option = true;
       break;
@@ -2304,6 +2327,7 @@ decode_options (int argc, char **argv)
   blocking_factor = DEFAULT_BLOCKING;
   record_size = DEFAULT_BLOCKING * BLOCKSIZE;
   excluded = new_exclude ();
+  
   newer_mtime_option.tv_sec = TYPE_MINIMUM (time_t);
   newer_mtime_option.tv_nsec = -1;
   recursion_option = FNM_LEADING_DIR;
@@ -2849,6 +2873,7 @@ tar_stat_destroy (struct tar_stat_info *st)
   free (st->sparse_map);
   free (st->dumpdir);
   xheader_destroy (&st->xhdr);
+  info_free_exclist (st);
   memset (st, 0, sizeof (*st));
 }
 
index cb7d70cf62534c268b5e1b04f85d985ae6e78f31..3d6939948ba5ae10b10816a53d72b652d1ef6fad 100644 (file)
--- a/src/tar.h
+++ b/src/tar.h
@@ -358,6 +358,9 @@ struct tar_stat_info
      It is negative if it could not be reopened after it was closed.
      Negate it to find out what errno was when the reopen failed.  */
   int fd;
+
+  /* Exclusion list */
+  struct exclist *exclude_list;
 };
 
 union block
index e9fad3f2ae48ab6a196c9b6aa85d4a76da9192ad..c8fca0c5a7c79da702d1bac53dff862d187fc2ff 100644 (file)
@@ -216,7 +216,7 @@ update_archive (void)
     while ((p = name_from_list ()) != NULL)
       {
        char *file_name = p->name;
-       if (excluded_name (file_name))
+       if (excluded_name (file_name, NULL))
          continue;
        if (interactive_option && !confirm ("add", file_name))
          continue;
This page took 0.047905 seconds and 4 git commands to generate.