subst.c 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293
  1. /*-
  2. * Copyright (c) 2008 Joerg Sonnenberger
  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 "bsdtar_platform.h"
  26. __FBSDID("$FreeBSD: src/usr.bin/tar/subst.c,v 1.4 2008/06/15 10:08:16 kientzle Exp $");
  27. #if HAVE_REGEX_H
  28. #include "bsdtar.h"
  29. #include <errno.h>
  30. #include <regex.h>
  31. #include <stdlib.h>
  32. #include <string.h>
  33. #ifndef REG_BASIC
  34. #define REG_BASIC 0
  35. #endif
  36. struct subst_rule {
  37. struct subst_rule *next;
  38. regex_t re;
  39. char *result;
  40. unsigned int global:1, print:1, symlink:1;
  41. };
  42. struct substitution {
  43. struct subst_rule *first_rule, *last_rule;
  44. };
  45. static void
  46. init_substitution(struct bsdtar *bsdtar)
  47. {
  48. struct substitution *subst;
  49. bsdtar->substitution = subst = malloc(sizeof(*subst));
  50. if (subst == NULL)
  51. bsdtar_errc(bsdtar, 1, errno, "Out of memory");
  52. subst->first_rule = subst->last_rule = NULL;
  53. }
  54. void
  55. add_substitution(struct bsdtar *bsdtar, const char *rule_text)
  56. {
  57. struct subst_rule *rule;
  58. struct substitution *subst;
  59. const char *end_pattern, *start_subst;
  60. char *pattern;
  61. int r;
  62. if ((subst = bsdtar->substitution) == NULL) {
  63. init_substitution(bsdtar);
  64. subst = bsdtar->substitution;
  65. }
  66. rule = malloc(sizeof(*rule));
  67. if (rule == NULL)
  68. bsdtar_errc(bsdtar, 1, errno, "Out of memory");
  69. rule->next = NULL;
  70. rule->result = NULL;
  71. if (subst->last_rule == NULL)
  72. subst->first_rule = rule;
  73. else
  74. subst->last_rule->next = rule;
  75. subst->last_rule = rule;
  76. if (*rule_text == '\0')
  77. bsdtar_errc(bsdtar, 1, 0, "Empty replacement string");
  78. end_pattern = strchr(rule_text + 1, *rule_text);
  79. if (end_pattern == NULL)
  80. bsdtar_errc(bsdtar, 1, 0, "Invalid replacement string");
  81. pattern = malloc(end_pattern - rule_text);
  82. if (pattern == NULL)
  83. bsdtar_errc(bsdtar, 1, errno, "Out of memory");
  84. memcpy(pattern, rule_text + 1, end_pattern - rule_text - 1);
  85. pattern[end_pattern - rule_text - 1] = '\0';
  86. if ((r = regcomp(&rule->re, pattern, REG_BASIC)) != 0) {
  87. char buf[80];
  88. regerror(r, &rule->re, buf, sizeof(buf));
  89. bsdtar_errc(bsdtar, 1, 0, "Invalid regular expression: %s", buf);
  90. }
  91. free(pattern);
  92. start_subst = end_pattern + 1;
  93. end_pattern = strchr(start_subst, *rule_text);
  94. if (end_pattern == NULL)
  95. bsdtar_errc(bsdtar, 1, 0, "Invalid replacement string");
  96. rule->result = malloc(end_pattern - start_subst + 1);
  97. if (rule->result == NULL)
  98. bsdtar_errc(bsdtar, 1, errno, "Out of memory");
  99. memcpy(rule->result, start_subst, end_pattern - start_subst);
  100. rule->result[end_pattern - start_subst] = '\0';
  101. rule->global = 0;
  102. rule->print = 0;
  103. rule->symlink = 0;
  104. while (*++end_pattern) {
  105. switch (*end_pattern) {
  106. case 'g':
  107. case 'G':
  108. rule->global = 1;
  109. break;
  110. case 'p':
  111. case 'P':
  112. rule->print = 1;
  113. break;
  114. case 's':
  115. case 'S':
  116. rule->symlink = 1;
  117. break;
  118. default:
  119. bsdtar_errc(bsdtar, 1, 0, "Invalid replacement flag %c", *end_pattern);
  120. }
  121. }
  122. }
  123. static void
  124. realloc_strncat(struct bsdtar *bsdtar, char **str, const char *append, size_t len)
  125. {
  126. char *new_str;
  127. size_t old_len;
  128. if (*str == NULL)
  129. old_len = 0;
  130. else
  131. old_len = strlen(*str);
  132. new_str = malloc(old_len + len + 1);
  133. if (new_str == NULL)
  134. bsdtar_errc(bsdtar, 1, errno, "Out of memory");
  135. if (*str != NULL)
  136. memcpy(new_str, *str, old_len);
  137. memcpy(new_str + old_len, append, len);
  138. new_str[old_len + len] = '\0';
  139. free(*str);
  140. *str = new_str;
  141. }
  142. static void
  143. realloc_strcat(struct bsdtar *bsdtar, char **str, const char *append)
  144. {
  145. char *new_str;
  146. size_t old_len;
  147. if (*str == NULL)
  148. old_len = 0;
  149. else
  150. old_len = strlen(*str);
  151. new_str = malloc(old_len + strlen(append) + 1);
  152. if (new_str == NULL)
  153. bsdtar_errc(bsdtar, 1, errno, "Out of memory");
  154. if (*str != NULL)
  155. memcpy(new_str, *str, old_len);
  156. strcpy(new_str + old_len, append);
  157. free(*str);
  158. *str = new_str;
  159. }
  160. int
  161. apply_substitution(struct bsdtar *bsdtar, const char *name, char **result, int symlink_only)
  162. {
  163. const char *path = name;
  164. regmatch_t matches[10];
  165. size_t i, j;
  166. struct subst_rule *rule;
  167. struct substitution *subst;
  168. int c, got_match, print_match;
  169. *result = NULL;
  170. if ((subst = bsdtar->substitution) == NULL)
  171. return 0;
  172. got_match = 0;
  173. print_match = 0;
  174. for (rule = subst->first_rule; rule != NULL; rule = rule->next) {
  175. if (symlink_only && !rule->symlink)
  176. continue;
  177. if (regexec(&rule->re, name, 10, matches, 0))
  178. continue;
  179. got_match = 1;
  180. print_match |= rule->print;
  181. realloc_strncat(bsdtar, result, name, matches[0].rm_so);
  182. for (i = 0, j = 0; rule->result[i] != '\0'; ++i) {
  183. if (rule->result[i] == '~') {
  184. realloc_strncat(bsdtar, result, rule->result + j, i - j);
  185. realloc_strncat(bsdtar, result,
  186. name + matches[0].rm_so,
  187. matches[0].rm_eo - matches[0].rm_so);
  188. j = i + 1;
  189. continue;
  190. }
  191. if (rule->result[i] != '\\')
  192. continue;
  193. ++i;
  194. c = rule->result[i];
  195. switch (c) {
  196. case '~':
  197. case '\\':
  198. realloc_strncat(bsdtar, result, rule->result + j, i - j - 1);
  199. j = i;
  200. break;
  201. case '1':
  202. case '2':
  203. case '3':
  204. case '4':
  205. case '5':
  206. case '6':
  207. case '7':
  208. case '8':
  209. case '9':
  210. realloc_strncat(bsdtar, result, rule->result + j, i - j - 1);
  211. if ((size_t)(c - '0') > (size_t)(rule->re.re_nsub)) {
  212. free(*result);
  213. *result = NULL;
  214. return -1;
  215. }
  216. realloc_strncat(bsdtar, result, name + matches[c - '0'].rm_so, matches[c - '0'].rm_eo - matches[c - '0'].rm_so);
  217. j = i + 1;
  218. break;
  219. default:
  220. /* Just continue; */
  221. break;
  222. }
  223. }
  224. realloc_strcat(bsdtar, result, rule->result + j);
  225. name += matches[0].rm_eo;
  226. if (!rule->global)
  227. break;
  228. }
  229. if (got_match)
  230. realloc_strcat(bsdtar, result, name);
  231. if (print_match)
  232. fprintf(stderr, "%s >> %s\n", path, *result);
  233. return got_match;
  234. }
  235. void
  236. cleanup_substitution(struct bsdtar *bsdtar)
  237. {
  238. struct subst_rule *rule;
  239. struct substitution *subst;
  240. if ((subst = bsdtar->substitution) == NULL)
  241. return;
  242. while ((rule = subst->first_rule) != NULL) {
  243. subst->first_rule = rule->next;
  244. free(rule->result);
  245. free(rule);
  246. }
  247. free(subst);
  248. }
  249. #endif /* HAVE_REGEX_H */