| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284 |
- /*-
- * Copyright (c) 2003-2007 Tim Kientzle
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
- #include "lafe_platform.h"
- __FBSDID("$FreeBSD: src/usr.bin/cpio/matching.c,v 1.2 2008/06/21 02:20:20 kientzle Exp $");
- #ifdef HAVE_ERRNO_H
- #include <errno.h>
- #endif
- #ifdef HAVE_STDLIB_H
- #include <stdlib.h>
- #endif
- #ifdef HAVE_STRING_H
- #include <string.h>
- #endif
- #include "err.h"
- #include "line_reader.h"
- #include "matching.h"
- #include "pathmatch.h"
- struct match {
- struct match *next;
- int matches;
- char pattern[1];
- };
- struct lafe_matching {
- struct match *exclusions;
- int exclusions_count;
- struct match *inclusions;
- int inclusions_count;
- int inclusions_unmatched_count;
- };
- static void add_pattern(struct match **list, const char *pattern);
- static void initialize_matching(struct lafe_matching **);
- static int match_exclusion(struct match *, const char *pathname);
- static int match_inclusion(struct match *, const char *pathname);
- /*
- * The matching logic here needs to be re-thought. I started out to
- * try to mimic gtar's matching logic, but it's not entirely
- * consistent. In particular 'tar -t' and 'tar -x' interpret patterns
- * on the command line as anchored, but --exclude doesn't.
- */
- /*
- * Utility functions to manage exclusion/inclusion patterns
- */
- int
- lafe_exclude(struct lafe_matching **matching, const char *pattern)
- {
- if (*matching == NULL)
- initialize_matching(matching);
- add_pattern(&((*matching)->exclusions), pattern);
- (*matching)->exclusions_count++;
- return (0);
- }
- int
- lafe_exclude_from_file(struct lafe_matching **matching, const char *pathname)
- {
- struct lafe_line_reader *lr;
- const char *p;
- int ret = 0;
- lr = lafe_line_reader(pathname, '\n');
- while ((p = lafe_line_reader_next(lr)) != NULL) {
- if (lafe_exclude(matching, p) != 0)
- ret = -1;
- }
- lafe_line_reader_free(lr);
- return (ret);
- }
- int
- lafe_include(struct lafe_matching **matching, const char *pattern)
- {
- if (*matching == NULL)
- initialize_matching(matching);
- add_pattern(&((*matching)->inclusions), pattern);
- (*matching)->inclusions_count++;
- (*matching)->inclusions_unmatched_count++;
- return (0);
- }
- int
- lafe_include_from_file(struct lafe_matching **matching, const char *pathname,
- int nullSeparator)
- {
- struct lafe_line_reader *lr;
- const char *p;
- int ret = 0;
- lr = lafe_line_reader(pathname, nullSeparator);
- while ((p = lafe_line_reader_next(lr)) != NULL) {
- if (lafe_include(matching, p) != 0)
- ret = -1;
- }
- lafe_line_reader_free(lr);
- return (ret);
- }
- static void
- add_pattern(struct match **list, const char *pattern)
- {
- struct match *match;
- size_t len;
- len = strlen(pattern);
- match = malloc(sizeof(*match) + len + 1);
- if (match == NULL)
- lafe_errc(1, errno, "Out of memory");
- strcpy(match->pattern, pattern);
- /* Both "foo/" and "foo" should match "foo/bar". */
- if (len && match->pattern[len - 1] == '/')
- match->pattern[strlen(match->pattern)-1] = '\0';
- match->next = *list;
- *list = match;
- match->matches = 0;
- }
- int
- lafe_excluded(struct lafe_matching *matching, const char *pathname)
- {
- struct match *match;
- struct match *matched;
- if (matching == NULL)
- return (0);
- /* Exclusions take priority */
- for (match = matching->exclusions; match != NULL; match = match->next){
- if (match_exclusion(match, pathname))
- return (1);
- }
- /* Then check for inclusions */
- matched = NULL;
- for (match = matching->inclusions; match != NULL; match = match->next){
- if (match_inclusion(match, pathname)) {
- /*
- * If this pattern has never been matched,
- * then we're done.
- */
- if (match->matches == 0) {
- match->matches++;
- matching->inclusions_unmatched_count--;
- return (0);
- }
- /*
- * Otherwise, remember the match but keep checking
- * in case we can tick off an unmatched pattern.
- */
- matched = match;
- }
- }
- /*
- * We didn't find a pattern that had never been matched, but
- * we did find a match, so count it and exit.
- */
- if (matched != NULL) {
- matched->matches++;
- return (0);
- }
- /* If there were inclusions, default is to exclude. */
- if (matching->inclusions != NULL)
- return (1);
- /* No explicit inclusions, default is to match. */
- return (0);
- }
- /*
- * This is a little odd, but it matches the default behavior of
- * gtar. In particular, 'a*b' will match 'foo/a1111/222b/bar'
- *
- */
- static int
- match_exclusion(struct match *match, const char *pathname)
- {
- return (lafe_pathmatch(match->pattern,
- pathname,
- PATHMATCH_NO_ANCHOR_START | PATHMATCH_NO_ANCHOR_END));
- }
- /*
- * Again, mimic gtar: inclusions are always anchored (have to match
- * the beginning of the path) even though exclusions are not anchored.
- */
- static int
- match_inclusion(struct match *match, const char *pathname)
- {
- #if 0
- return (lafe_pathmatch(match->pattern, pathname, 0));
- #else
- return (lafe_pathmatch(match->pattern, pathname, PATHMATCH_NO_ANCHOR_END));
- #endif
- }
- void
- lafe_cleanup_exclusions(struct lafe_matching **matching)
- {
- struct match *p, *q;
- if (*matching == NULL)
- return;
- for (p = (*matching)->inclusions; p != NULL; ) {
- q = p;
- p = p->next;
- free(q);
- }
- for (p = (*matching)->exclusions; p != NULL; ) {
- q = p;
- p = p->next;
- free(q);
- }
- free(*matching);
- *matching = NULL;
- }
- static void
- initialize_matching(struct lafe_matching **matching)
- {
- *matching = calloc(sizeof(**matching), 1);
- if (*matching == NULL)
- lafe_errc(1, errno, "No memory");
- }
- int
- lafe_unmatched_inclusions(struct lafe_matching *matching)
- {
- if (matching == NULL)
- return (0);
- return (matching->inclusions_unmatched_count);
- }
- int
- lafe_unmatched_inclusions_warn(struct lafe_matching *matching, const char *msg)
- {
- struct match *p;
- if (matching == NULL)
- return (0);
- for (p = matching->inclusions; p != NULL; p = p->next) {
- if (p->matches == 0)
- lafe_warnc(0, "%s: %s", p->pattern, msg);
- }
- return (matching->inclusions_unmatched_count);
- }
|