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 : : }