Make sure link counting works for file names supplied with -T
[tar.git] / src / exclist.c
blob297e27a4cf6f47e38ae09052304d9e680bac2168
1 /* Per-directory exclusion files for tar.
3 Copyright 2014-2020 Free Software Foundation, Inc.
5 This file is part of GNU tar.
7 GNU tar is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
12 GNU tar is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>.
20 #include <system.h>
21 #include <quotearg.h>
22 #include <fnmatch.h>
23 #include <wordsplit.h>
24 #include "common.h"
26 typedef void (*add_fn) (struct exclude *, char const *, int, void *);
28 struct vcs_ignore_file
30 char const *filename;
31 int flags;
32 add_fn addfn;
33 void *(*initfn) (void *);
34 void *data;
37 static struct vcs_ignore_file *get_vcs_ignore_file (const char *name);
39 struct excfile
41 struct excfile *next;
42 int flags;
43 char name[1];
46 static struct excfile *excfile_head, *excfile_tail;
48 void
49 excfile_add (const char *name, int flags)
51 struct excfile *p = xmalloc (sizeof (*p) + strlen (name));
52 p->next = NULL;
53 p->flags = flags;
54 strcpy (p->name, name);
55 if (excfile_tail)
56 excfile_tail->next = p;
57 else
58 excfile_head = p;
59 excfile_tail = p;
62 struct exclist
64 struct exclist *next, *prev;
65 int flags;
66 struct exclude *excluded;
69 void
70 info_attach_exclist (struct tar_stat_info *dir)
72 struct excfile *file;
73 struct exclist *head = NULL, *tail = NULL, *ent;
74 struct vcs_ignore_file *vcsfile;
76 if (dir->exclude_list)
77 return;
78 for (file = excfile_head; file; file = file->next)
80 if (faccessat (dir ? dir->fd : chdir_fd, file->name, F_OK, 0) == 0)
82 FILE *fp;
83 struct exclude *ex = NULL;
84 int fd = subfile_open (dir, file->name, O_RDONLY);
85 if (fd == -1)
87 open_error (file->name);
88 continue;
90 fp = fdopen (fd, "r");
91 if (!fp)
93 ERROR ((0, errno, _("%s: fdopen failed"), file->name));
94 close (fd);
95 continue;
98 if (!ex)
99 ex = new_exclude ();
101 vcsfile = get_vcs_ignore_file (file->name);
103 if (vcsfile->initfn)
104 vcsfile->data = vcsfile->initfn (vcsfile->data);
106 if (add_exclude_fp (vcsfile->addfn, ex, fp,
107 FNM_FILE_NAME|EXCLUDE_WILDCARDS|EXCLUDE_ANCHORED,
108 '\n',
109 vcsfile->data))
111 int e = errno;
112 FATAL_ERROR ((0, e, "%s", quotearg_colon (file->name)));
114 fclose (fp);
116 ent = xmalloc (sizeof (*ent));
117 ent->excluded = ex;
118 ent->flags = file->flags == EXCL_DEFAULT
119 ? file->flags : vcsfile->flags;
120 ent->prev = tail;
121 ent->next = NULL;
123 if (tail)
124 tail->next = ent;
125 else
126 head = ent;
127 tail = ent;
130 dir->exclude_list = head;
133 void
134 info_free_exclist (struct tar_stat_info *dir)
136 struct exclist *ep = dir->exclude_list;
138 while (ep)
140 struct exclist *next = ep->next;
141 free_exclude (ep->excluded);
142 free (ep);
143 ep = next;
146 dir->exclude_list = NULL;
150 /* Return nonzero if file NAME is excluded. */
151 bool
152 excluded_name (char const *name, struct tar_stat_info *st)
154 struct exclist *ep;
155 const char *rname = NULL;
156 char *bname = NULL;
157 bool result;
158 int nr = 0;
160 name += FILE_SYSTEM_PREFIX_LEN (name);
162 /* Try global exclusion list first */
163 if (excluded_file_name (excluded, name))
164 return true;
166 if (!st)
167 return false;
169 for (result = false; st && !result; st = st->parent, nr = EXCL_NON_RECURSIVE)
171 for (ep = st->exclude_list; ep; ep = ep->next)
173 if (ep->flags & nr)
174 continue;
175 if ((result = excluded_file_name (ep->excluded, name)))
176 break;
178 if (!rname)
180 rname = name;
181 /* Skip leading ./ */
182 while (*rname == '.' && ISSLASH (rname[1]))
183 rname += 2;
185 if ((result = excluded_file_name (ep->excluded, rname)))
186 break;
188 if (!bname)
189 bname = base_name (name);
190 if ((result = excluded_file_name (ep->excluded, bname)))
191 break;
195 free (bname);
197 return result;
200 static void
201 cvs_addfn (struct exclude *ex, char const *pattern, int options, void *data)
203 struct wordsplit ws;
204 size_t i;
206 if (wordsplit (pattern, &ws,
207 WRDSF_NOVAR | WRDSF_NOCMD | WRDSF_SQUEEZE_DELIMS))
208 return;
209 for (i = 0; i < ws.ws_wordc; i++)
210 add_exclude (ex, ws.ws_wordv[i], options);
211 wordsplit_free (&ws);
214 static void
215 git_addfn (struct exclude *ex, char const *pattern, int options, void *data)
217 while (isspace (*pattern))
218 ++pattern;
219 if (*pattern == 0 || *pattern == '#')
220 return;
221 if (*pattern == '\\' && pattern[1] == '#')
222 ++pattern;
223 add_exclude (ex, pattern, options);
226 static void
227 bzr_addfn (struct exclude *ex, char const *pattern, int options, void *data)
229 while (isspace (*pattern))
230 ++pattern;
231 if (*pattern == 0 || *pattern == '#')
232 return;
233 if (*pattern == '!')
235 if (*++pattern == '!')
236 ++pattern;
237 else
238 options |= EXCLUDE_INCLUDE;
240 /* FIXME: According to the docs, globbing patterns are rsync-style,
241 and regexps are perl-style. */
242 if (strncmp (pattern, "RE:", 3) == 0)
244 pattern += 3;
245 options &= ~EXCLUDE_WILDCARDS;
246 options |= EXCLUDE_REGEX;
248 add_exclude (ex, pattern, options);
251 static void *
252 hg_initfn (void *data)
254 static int hg_options;
255 int *hgopt = data ? data : &hg_options;
256 *hgopt = EXCLUDE_REGEX;
257 return hgopt;
260 static void
261 hg_addfn (struct exclude *ex, char const *pattern, int options, void *data)
263 int *hgopt = data;
264 size_t len;
266 while (isspace (*pattern))
267 ++pattern;
268 if (*pattern == 0 || *pattern == '#')
269 return;
270 if (strncmp (pattern, "syntax:", 7) == 0)
272 for (pattern += 7; isspace (*pattern); ++pattern)
274 if (strcmp (pattern, "regexp") == 0)
275 /* FIXME: Regexps must be perl-style */
276 *hgopt = EXCLUDE_REGEX;
277 else if (strcmp (pattern, "glob") == 0)
278 *hgopt = EXCLUDE_WILDCARDS;
279 /* Ignore unknown syntax */
280 return;
283 len = strlen(pattern);
284 if (pattern[len-1] == '/')
286 char *p;
288 --len;
289 p = xmalloc (len+1);
290 memcpy (p, pattern, len);
291 p[len] = 0;
292 pattern = p;
293 exclude_add_pattern_buffer (ex, p);
294 options |= FNM_LEADING_DIR|EXCLUDE_ALLOC;
297 add_exclude (ex, pattern,
298 ((*hgopt == EXCLUDE_REGEX)
299 ? (options & ~EXCLUDE_WILDCARDS)
300 : (options & ~EXCLUDE_REGEX)) | *hgopt);
303 static struct vcs_ignore_file vcs_ignore_files[] = {
304 { ".cvsignore", EXCL_NON_RECURSIVE, cvs_addfn, NULL, NULL },
305 { ".gitignore", 0, git_addfn, NULL, NULL },
306 { ".bzrignore", 0, bzr_addfn, NULL, NULL },
307 { ".hgignore", 0, hg_addfn, hg_initfn, NULL },
308 { NULL, 0, git_addfn, NULL, NULL }
311 static struct vcs_ignore_file *
312 get_vcs_ignore_file (const char *name)
314 struct vcs_ignore_file *p;
316 for (p = vcs_ignore_files; p->filename; p++)
317 if (strcmp (p->filename, name) == 0)
318 break;
320 return p;
323 void
324 exclude_vcs_ignores (void)
326 struct vcs_ignore_file *p;
328 for (p = vcs_ignore_files; p->filename; p++)
329 excfile_add (p->filename, EXCL_DEFAULT);