blob: 3586d313b1a65be28b310b67ab107d3bfed3b81e [file] [log] [blame]
/*
* 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;
}