Commit | Line | Data |
---|---|---|
1479465f GJ |
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 | ||
33 | #include "main.h" | |
34 | #include "filesdb.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 | filter_add(const char *pattern, bool include) | |
48 | { | |
49 | struct filter_node *filter; | |
50 | ||
51 | debug(dbg_general, "adding %s filter for '%s'", | |
52 | include ? "include" : "exclude", pattern); | |
53 | ||
54 | filter = m_malloc(sizeof(*filter)); | |
55 | filter->pattern = m_strdup(pattern); | |
56 | filter->include = include; | |
57 | filter->next = NULL; | |
58 | ||
59 | *filter_tail = filter; | |
60 | filter_tail = &filter->next; | |
61 | } | |
62 | ||
63 | bool | |
64 | filter_should_skip(struct tar_entry *ti) | |
65 | { | |
66 | struct filter_node *f; | |
67 | bool skip = false; | |
68 | ||
69 | if (!filter_head) | |
70 | return false; | |
71 | ||
72 | /* Last match wins. */ | |
73 | for (f = filter_head; f != NULL; f = f->next) { | |
74 | debug(dbg_eachfile, "filter comparing '%s' and '%s'", | |
75 | &ti->name[1], f->pattern); | |
76 | ||
77 | if (fnmatch(f->pattern, &ti->name[1], 0) == 0) { | |
78 | if (f->include) { | |
79 | skip = false; | |
80 | debug(dbg_eachfile, "filter including %s", | |
81 | ti->name); | |
82 | } else { | |
83 | skip = true; | |
84 | 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 | if (skip && (ti->type == TAR_FILETYPE_DIR || | |
97 | ti->type == TAR_FILETYPE_SYMLINK)) { | |
98 | debug(dbg_eachfile, | |
99 | "filter seeing if '%s' needs to be reincluded", | |
100 | &ti->name[1]); | |
101 | ||
102 | for (f = filter_head; f != NULL; f = f->next) { | |
103 | const char *wildcard; | |
104 | int path_len; | |
105 | ||
106 | if (!f->include) | |
107 | continue; | |
108 | ||
109 | /* Calculate the offset of the first wildcard | |
110 | * character in the pattern. */ | |
111 | wildcard = strpbrk(f->pattern, "*?[\\"); | |
112 | if (wildcard) | |
113 | path_len = wildcard - f->pattern; | |
114 | else | |
115 | path_len = strlen(f->pattern); | |
116 | ||
117 | /* Ignore any trailing slash for the comparison. */ | |
118 | while (path_len && f->pattern[path_len - 1] == '/') | |
119 | path_len--; | |
120 | ||
121 | debug(dbg_eachfiledetail, | |
122 | "filter subpattern '%.*s'", path_len, f->pattern); | |
123 | ||
124 | if (strncmp(&ti->name[1], f->pattern, path_len) == 0) { | |
125 | debug(dbg_eachfile, "filter reincluding %s", | |
126 | ti->name); | |
127 | return false; | |
128 | } | |
129 | } | |
130 | } | |
131 | ||
132 | return skip; | |
133 | } |