| /* |
| * dpkg - main program for package management |
| * filters.c - filtering routines for excluding bits of packages |
| * |
| * Copyright © 2007, 2008 Tollef Fog Heen <tfheen@err.no> |
| * Copyright © 2008, 2010 Guillem Jover <guillem@debian.org> |
| * Copyright © 2010 Canonical Ltd. |
| * written by Martin Pitt <martin.pitt@canonical.com> |
| * |
| * This 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 2 of the License, or |
| * (at your option) any later version. |
| * |
| * This 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 <config.h> |
| #include <compat.h> |
| |
| #include <fnmatch.h> |
| |
| #include <dpkg/i18n.h> |
| #include <dpkg/dpkg.h> |
| #include <dpkg/dpkg-db.h> |
| |
| #include "main.h" |
| #include "filesdb.h" |
| #include "filters.h" |
| |
| struct filter_node { |
| struct filter_node *next; |
| char *pattern; |
| bool include; |
| }; |
| |
| static struct filter_node *filter_head = NULL; |
| static struct filter_node **filter_tail = &filter_head; |
| |
| void |
| filter_add(const char *pattern, bool include) |
| { |
| struct filter_node *filter; |
| |
| debug(dbg_general, "adding %s filter for '%s'\n", |
| include ? "include" : "exclude", pattern); |
| |
| filter = m_malloc(sizeof(*filter)); |
| filter->pattern = m_strdup(pattern); |
| filter->include = include; |
| filter->next = NULL; |
| |
| *filter_tail = filter; |
| filter_tail = &filter->next; |
| } |
| |
| bool |
| filter_should_skip(struct tar_entry *ti) |
| { |
| struct filter_node *f; |
| bool skip = false; |
| |
| if (!filter_head) |
| return false; |
| |
| /* Last match wins. */ |
| for (f = filter_head; f != NULL; f = f->next) { |
| debug(dbg_eachfile, "filter comparing '%s' and '%s'", |
| &ti->name[1], f->pattern); |
| |
| if (fnmatch(f->pattern, &ti->name[1], 0) == 0) { |
| if (f->include) { |
| skip = false; |
| debug(dbg_eachfile, "filter including %s", |
| ti->name); |
| } else { |
| skip = true; |
| debug(dbg_eachfile, "filter removing %s", |
| ti->name); |
| } |
| } |
| } |
| |
| /* We need to keep directories (or symlinks to directories) if a |
| * glob excludes them, but a more specific include glob brings back |
| * files; XXX the current implementation will probably include more |
| * directories than necessary, but better err on the side of caution |
| * than failing with “no such file or directory” (which would leave |
| * the package in a very bad state). */ |
| if (skip && (ti->type == tar_filetype_dir || |
| ti->type == tar_filetype_symlink)) { |
| debug(dbg_eachfile, |
| "filter seeing if '%s' needs to be reincluded", |
| &ti->name[1]); |
| |
| for (f = filter_head; f != NULL; f = f->next) { |
| const char *wildcard; |
| int path_len; |
| |
| if (!f->include) |
| continue; |
| |
| /* Calculate the offset of the first wildcard |
| * character in the pattern. */ |
| wildcard = strpbrk(f->pattern, "*?[\\"); |
| if (wildcard) |
| path_len = wildcard - f->pattern; |
| else |
| path_len = strlen(f->pattern); |
| |
| debug(dbg_eachfiledetail, |
| "filter subpattern '%*.s'", path_len, f->pattern); |
| |
| if (strncmp(&ti->name[1], f->pattern, path_len) == 0) { |
| debug(dbg_eachfile, "filter reincluding %s", |
| ti->name); |
| return false; |
| } |
| } |
| } |
| |
| return skip; |
| } |