matching.c 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284
  1. /*-
  2. * Copyright (c) 2003-2007 Tim Kientzle
  3. * All rights reserved.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions
  7. * are met:
  8. * 1. Redistributions of source code must retain the above copyright
  9. * notice, this list of conditions and the following disclaimer.
  10. * 2. Redistributions in binary form must reproduce the above copyright
  11. * notice, this list of conditions and the following disclaimer in the
  12. * documentation and/or other materials provided with the distribution.
  13. *
  14. * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
  15. * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  16. * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  17. * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
  18. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  19. * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  20. * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  21. * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  22. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  23. * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  24. */
  25. #include "lafe_platform.h"
  26. __FBSDID("$FreeBSD: src/usr.bin/cpio/matching.c,v 1.2 2008/06/21 02:20:20 kientzle Exp $");
  27. #ifdef HAVE_ERRNO_H
  28. #include <errno.h>
  29. #endif
  30. #ifdef HAVE_STDLIB_H
  31. #include <stdlib.h>
  32. #endif
  33. #ifdef HAVE_STRING_H
  34. #include <string.h>
  35. #endif
  36. #include "err.h"
  37. #include "line_reader.h"
  38. #include "matching.h"
  39. #include "pathmatch.h"
  40. struct match {
  41. struct match *next;
  42. int matches;
  43. char pattern[1];
  44. };
  45. struct lafe_matching {
  46. struct match *exclusions;
  47. int exclusions_count;
  48. struct match *inclusions;
  49. int inclusions_count;
  50. int inclusions_unmatched_count;
  51. };
  52. static void add_pattern(struct match **list, const char *pattern);
  53. static void initialize_matching(struct lafe_matching **);
  54. static int match_exclusion(struct match *, const char *pathname);
  55. static int match_inclusion(struct match *, const char *pathname);
  56. /*
  57. * The matching logic here needs to be re-thought. I started out to
  58. * try to mimic gtar's matching logic, but it's not entirely
  59. * consistent. In particular 'tar -t' and 'tar -x' interpret patterns
  60. * on the command line as anchored, but --exclude doesn't.
  61. */
  62. /*
  63. * Utility functions to manage exclusion/inclusion patterns
  64. */
  65. int
  66. lafe_exclude(struct lafe_matching **matching, const char *pattern)
  67. {
  68. if (*matching == NULL)
  69. initialize_matching(matching);
  70. add_pattern(&((*matching)->exclusions), pattern);
  71. (*matching)->exclusions_count++;
  72. return (0);
  73. }
  74. int
  75. lafe_exclude_from_file(struct lafe_matching **matching, const char *pathname)
  76. {
  77. struct lafe_line_reader *lr;
  78. const char *p;
  79. int ret = 0;
  80. lr = lafe_line_reader(pathname, '\n');
  81. while ((p = lafe_line_reader_next(lr)) != NULL) {
  82. if (lafe_exclude(matching, p) != 0)
  83. ret = -1;
  84. }
  85. lafe_line_reader_free(lr);
  86. return (ret);
  87. }
  88. int
  89. lafe_include(struct lafe_matching **matching, const char *pattern)
  90. {
  91. if (*matching == NULL)
  92. initialize_matching(matching);
  93. add_pattern(&((*matching)->inclusions), pattern);
  94. (*matching)->inclusions_count++;
  95. (*matching)->inclusions_unmatched_count++;
  96. return (0);
  97. }
  98. int
  99. lafe_include_from_file(struct lafe_matching **matching, const char *pathname,
  100. int nullSeparator)
  101. {
  102. struct lafe_line_reader *lr;
  103. const char *p;
  104. int ret = 0;
  105. lr = lafe_line_reader(pathname, nullSeparator);
  106. while ((p = lafe_line_reader_next(lr)) != NULL) {
  107. if (lafe_include(matching, p) != 0)
  108. ret = -1;
  109. }
  110. lafe_line_reader_free(lr);
  111. return (ret);
  112. }
  113. static void
  114. add_pattern(struct match **list, const char *pattern)
  115. {
  116. struct match *match;
  117. size_t len;
  118. len = strlen(pattern);
  119. match = malloc(sizeof(*match) + len + 1);
  120. if (match == NULL)
  121. lafe_errc(1, errno, "Out of memory");
  122. strcpy(match->pattern, pattern);
  123. /* Both "foo/" and "foo" should match "foo/bar". */
  124. if (len && match->pattern[len - 1] == '/')
  125. match->pattern[strlen(match->pattern)-1] = '\0';
  126. match->next = *list;
  127. *list = match;
  128. match->matches = 0;
  129. }
  130. int
  131. lafe_excluded(struct lafe_matching *matching, const char *pathname)
  132. {
  133. struct match *match;
  134. struct match *matched;
  135. if (matching == NULL)
  136. return (0);
  137. /* Exclusions take priority */
  138. for (match = matching->exclusions; match != NULL; match = match->next){
  139. if (match_exclusion(match, pathname))
  140. return (1);
  141. }
  142. /* Then check for inclusions */
  143. matched = NULL;
  144. for (match = matching->inclusions; match != NULL; match = match->next){
  145. if (match_inclusion(match, pathname)) {
  146. /*
  147. * If this pattern has never been matched,
  148. * then we're done.
  149. */
  150. if (match->matches == 0) {
  151. match->matches++;
  152. matching->inclusions_unmatched_count--;
  153. return (0);
  154. }
  155. /*
  156. * Otherwise, remember the match but keep checking
  157. * in case we can tick off an unmatched pattern.
  158. */
  159. matched = match;
  160. }
  161. }
  162. /*
  163. * We didn't find a pattern that had never been matched, but
  164. * we did find a match, so count it and exit.
  165. */
  166. if (matched != NULL) {
  167. matched->matches++;
  168. return (0);
  169. }
  170. /* If there were inclusions, default is to exclude. */
  171. if (matching->inclusions != NULL)
  172. return (1);
  173. /* No explicit inclusions, default is to match. */
  174. return (0);
  175. }
  176. /*
  177. * This is a little odd, but it matches the default behavior of
  178. * gtar. In particular, 'a*b' will match 'foo/a1111/222b/bar'
  179. *
  180. */
  181. static int
  182. match_exclusion(struct match *match, const char *pathname)
  183. {
  184. return (lafe_pathmatch(match->pattern,
  185. pathname,
  186. PATHMATCH_NO_ANCHOR_START | PATHMATCH_NO_ANCHOR_END));
  187. }
  188. /*
  189. * Again, mimic gtar: inclusions are always anchored (have to match
  190. * the beginning of the path) even though exclusions are not anchored.
  191. */
  192. static int
  193. match_inclusion(struct match *match, const char *pathname)
  194. {
  195. #if 0
  196. return (lafe_pathmatch(match->pattern, pathname, 0));
  197. #else
  198. return (lafe_pathmatch(match->pattern, pathname, PATHMATCH_NO_ANCHOR_END));
  199. #endif
  200. }
  201. void
  202. lafe_cleanup_exclusions(struct lafe_matching **matching)
  203. {
  204. struct match *p, *q;
  205. if (*matching == NULL)
  206. return;
  207. for (p = (*matching)->inclusions; p != NULL; ) {
  208. q = p;
  209. p = p->next;
  210. free(q);
  211. }
  212. for (p = (*matching)->exclusions; p != NULL; ) {
  213. q = p;
  214. p = p->next;
  215. free(q);
  216. }
  217. free(*matching);
  218. *matching = NULL;
  219. }
  220. static void
  221. initialize_matching(struct lafe_matching **matching)
  222. {
  223. *matching = calloc(sizeof(**matching), 1);
  224. if (*matching == NULL)
  225. lafe_errc(1, errno, "No memory");
  226. }
  227. int
  228. lafe_unmatched_inclusions(struct lafe_matching *matching)
  229. {
  230. if (matching == NULL)
  231. return (0);
  232. return (matching->inclusions_unmatched_count);
  233. }
  234. int
  235. lafe_unmatched_inclusions_warn(struct lafe_matching *matching, const char *msg)
  236. {
  237. struct match *p;
  238. if (matching == NULL)
  239. return (0);
  240. for (p = matching->inclusions; p != NULL; p = p->next) {
  241. if (p->matches == 0)
  242. lafe_warnc(0, "%s: %s", p->pattern, msg);
  243. }
  244. return (matching->inclusions_unmatched_count);
  245. }