Branch data Line data Source code
1 : : /*
2 : : * dpkg - main program for package management
3 : : * filters.c - filtering routines for excluding bits of packages
4 : : *
5 : : * Copyright © 2007, 2008 Tollef Fog Heen <tfheen@err.no>
6 : : * Copyright © 2008, 2010, 2012-2014 Guillem Jover <guillem@debian.org>
7 : : * Copyright © 2010 Canonical Ltd.
8 : : * written by Martin Pitt <martin.pitt@canonical.com>
9 : : *
10 : : * This is free software; you can redistribute it and/or modify
11 : : * it under the terms of the GNU General Public License as published by
12 : : * the Free Software Foundation; either version 2 of the License, or
13 : : * (at your option) any later version.
14 : : *
15 : : * This is distributed in the hope that it will be useful,
16 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 : : * GNU General Public License for more details.
19 : : *
20 : : * You should have received a copy of the GNU General Public License
21 : : * along with this program. If not, see <https://www.gnu.org/licenses/>.
22 : : */
23 : :
24 : : #include <config.h>
25 : : #include <compat.h>
26 : :
27 : : #include <fnmatch.h>
28 : :
29 : : #include <dpkg/i18n.h>
30 : : #include <dpkg/dpkg.h>
31 : : #include <dpkg/dpkg-db.h>
32 : : #include <dpkg/db-fsys.h>
33 : :
34 : : #include "main.h"
35 : : #include "filters.h"
36 : :
37 : : struct filter_node {
38 : : struct filter_node *next;
39 : : char *pattern;
40 : : bool include;
41 : : };
42 : :
43 : : static struct filter_node *filter_head = NULL;
44 : : static struct filter_node **filter_tail = &filter_head;
45 : :
46 : : void
47 : 0 : filter_add(const char *pattern, bool include)
48 : : {
49 : : struct filter_node *filter;
50 : :
51 [ # # ]: 0 : debug(dbg_general, "adding %s filter for '%s'",
52 : : include ? "include" : "exclude", pattern);
53 : :
54 : 0 : filter = m_malloc(sizeof(*filter));
55 : 0 : filter->pattern = m_strdup(pattern);
56 : 0 : filter->include = include;
57 : 0 : filter->next = NULL;
58 : :
59 : 0 : *filter_tail = filter;
60 : 0 : filter_tail = &filter->next;
61 : 0 : }
62 : :
63 : : bool
64 : 0 : filter_should_skip(struct tar_entry *ti)
65 : : {
66 : : struct filter_node *f;
67 : 0 : bool skip = false;
68 : :
69 [ # # ]: 0 : if (!filter_head)
70 : 0 : return false;
71 : :
72 : : /* Last match wins. */
73 [ # # ]: 0 : for (f = filter_head; f != NULL; f = f->next) {
74 : 0 : debug(dbg_eachfile, "filter comparing '%s' and '%s'",
75 : 0 : &ti->name[1], f->pattern);
76 : :
77 [ # # ]: 0 : if (fnmatch(f->pattern, &ti->name[1], 0) == 0) {
78 [ # # ]: 0 : if (f->include) {
79 : 0 : skip = false;
80 : 0 : debug(dbg_eachfile, "filter including %s",
81 : : ti->name);
82 : : } else {
83 : 0 : skip = true;
84 : 0 : debug(dbg_eachfile, "filter removing %s",
85 : : ti->name);
86 : : }
87 : : }
88 : : }
89 : :
90 : : /* We need to keep directories (or symlinks to directories) if a
91 : : * glob excludes them, but a more specific include glob brings back
92 : : * files; XXX the current implementation will probably include more
93 : : * directories than necessary, but better err on the side of caution
94 : : * than failing with “no such file or directory” (which would leave
95 : : * the package in a very bad state). */
96 [ # # # # ]: 0 : if (skip && (ti->type == TAR_FILETYPE_DIR ||
97 [ # # ]: 0 : ti->type == TAR_FILETYPE_SYMLINK)) {
98 : 0 : debug(dbg_eachfile,
99 : : "filter seeing if '%s' needs to be reincluded",
100 : 0 : &ti->name[1]);
101 : :
102 [ # # ]: 0 : for (f = filter_head; f != NULL; f = f->next) {
103 : : const char *wildcard;
104 : : int path_len;
105 : :
106 [ # # ]: 0 : if (!f->include)
107 : 0 : continue;
108 : :
109 : : /* Calculate the offset of the first wildcard
110 : : * character in the pattern. */
111 : 0 : wildcard = strpbrk(f->pattern, "*?[\\");
112 [ # # ]: 0 : if (wildcard)
113 : 0 : path_len = wildcard - f->pattern;
114 : : else
115 : 0 : path_len = strlen(f->pattern);
116 : :
117 : : /* Ignore any trailing slash for the comparison. */
118 [ # # # # ]: 0 : while (path_len && f->pattern[path_len - 1] == '/')
119 : 0 : path_len--;
120 : :
121 : 0 : debug(dbg_eachfiledetail,
122 : : "filter subpattern '%.*s'", path_len, f->pattern);
123 : :
124 [ # # ]: 0 : if (strncmp(&ti->name[1], f->pattern, path_len) == 0) {
125 : 0 : debug(dbg_eachfile, "filter reincluding %s",
126 : : ti->name);
127 : 0 : return false;
128 : : }
129 : : }
130 : : }
131 : :
132 : 0 : return skip;
133 : : }
|