PageRenderTime 46ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/contrib/libarchive/tar/subst.c

https://bitbucket.org/freebsd/freebsd-base
C | 327 lines | 256 code | 45 blank | 26 comment | 63 complexity | eb51fcf90c3d3a40e8e5ed1735fa26dd MD5 | raw file
  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$");
  27. #if defined(HAVE_REGEX_H) || defined(HAVE_PCREPOSIX_H)
  28. #include "bsdtar.h"
  29. #include <errno.h>
  30. #ifdef HAVE_PCREPOSIX_H
  31. #include <pcreposix.h>
  32. #else
  33. #include <regex.h>
  34. #endif
  35. #include <stdlib.h>
  36. #include <string.h>
  37. #ifndef REG_BASIC
  38. #define REG_BASIC 0
  39. #endif
  40. #include "err.h"
  41. struct subst_rule {
  42. struct subst_rule *next;
  43. regex_t re;
  44. char *result;
  45. unsigned int global:1, print:1, regular:1, symlink:1, hardlink:1;
  46. };
  47. struct substitution {
  48. struct subst_rule *first_rule, *last_rule;
  49. };
  50. static void
  51. init_substitution(struct bsdtar *bsdtar)
  52. {
  53. struct substitution *subst;
  54. bsdtar->substitution = subst = malloc(sizeof(*subst));
  55. if (subst == NULL)
  56. lafe_errc(1, errno, "Out of memory");
  57. subst->first_rule = subst->last_rule = NULL;
  58. }
  59. void
  60. add_substitution(struct bsdtar *bsdtar, const char *rule_text)
  61. {
  62. struct subst_rule *rule;
  63. struct substitution *subst;
  64. const char *end_pattern, *start_subst;
  65. char *pattern;
  66. int r;
  67. if ((subst = bsdtar->substitution) == NULL) {
  68. init_substitution(bsdtar);
  69. subst = bsdtar->substitution;
  70. }
  71. rule = malloc(sizeof(*rule));
  72. if (rule == NULL)
  73. lafe_errc(1, errno, "Out of memory");
  74. rule->next = NULL;
  75. rule->result = NULL;
  76. if (subst->last_rule == NULL)
  77. subst->first_rule = rule;
  78. else
  79. subst->last_rule->next = rule;
  80. subst->last_rule = rule;
  81. if (*rule_text == '\0')
  82. lafe_errc(1, 0, "Empty replacement string");
  83. end_pattern = strchr(rule_text + 1, *rule_text);
  84. if (end_pattern == NULL)
  85. lafe_errc(1, 0, "Invalid replacement string");
  86. pattern = malloc(end_pattern - rule_text);
  87. if (pattern == NULL)
  88. lafe_errc(1, errno, "Out of memory");
  89. memcpy(pattern, rule_text + 1, end_pattern - rule_text - 1);
  90. pattern[end_pattern - rule_text - 1] = '\0';
  91. if ((r = regcomp(&rule->re, pattern, REG_BASIC)) != 0) {
  92. char buf[80];
  93. regerror(r, &rule->re, buf, sizeof(buf));
  94. lafe_errc(1, 0, "Invalid regular expression: %s", buf);
  95. }
  96. free(pattern);
  97. start_subst = end_pattern + 1;
  98. end_pattern = strchr(start_subst, *rule_text);
  99. if (end_pattern == NULL)
  100. lafe_errc(1, 0, "Invalid replacement string");
  101. rule->result = malloc(end_pattern - start_subst + 1);
  102. if (rule->result == NULL)
  103. lafe_errc(1, errno, "Out of memory");
  104. memcpy(rule->result, start_subst, end_pattern - start_subst);
  105. rule->result[end_pattern - start_subst] = '\0';
  106. /* Defaults */
  107. rule->global = 0; /* Don't do multiple replacements. */
  108. rule->print = 0; /* Don't print. */
  109. rule->regular = 1; /* Rewrite regular filenames. */
  110. rule->symlink = 1; /* Rewrite symlink targets. */
  111. rule->hardlink = 1; /* Rewrite hardlink targets. */
  112. while (*++end_pattern) {
  113. switch (*end_pattern) {
  114. case 'g':
  115. case 'G':
  116. rule->global = 1;
  117. break;
  118. case 'h':
  119. rule->hardlink = 1;
  120. break;
  121. case 'H':
  122. rule->hardlink = 0;
  123. break;
  124. case 'p':
  125. case 'P':
  126. rule->print = 1;
  127. break;
  128. case 'r':
  129. rule->regular = 1;
  130. break;
  131. case 'R':
  132. rule->regular = 0;
  133. break;
  134. case 's':
  135. rule->symlink = 1;
  136. break;
  137. case 'S':
  138. rule->symlink = 0;
  139. break;
  140. default:
  141. lafe_errc(1, 0, "Invalid replacement flag %c", *end_pattern);
  142. }
  143. }
  144. }
  145. static void
  146. realloc_strncat(char **str, const char *append, size_t len)
  147. {
  148. char *new_str;
  149. size_t old_len;
  150. if (*str == NULL)
  151. old_len = 0;
  152. else
  153. old_len = strlen(*str);
  154. new_str = malloc(old_len + len + 1);
  155. if (new_str == NULL)
  156. lafe_errc(1, errno, "Out of memory");
  157. if (*str != NULL)
  158. memcpy(new_str, *str, old_len);
  159. memcpy(new_str + old_len, append, len);
  160. new_str[old_len + len] = '\0';
  161. free(*str);
  162. *str = new_str;
  163. }
  164. static void
  165. realloc_strcat(char **str, const char *append)
  166. {
  167. char *new_str;
  168. size_t old_len;
  169. if (*str == NULL)
  170. old_len = 0;
  171. else
  172. old_len = strlen(*str);
  173. new_str = malloc(old_len + strlen(append) + 1);
  174. if (new_str == NULL)
  175. lafe_errc(1, errno, "Out of memory");
  176. if (*str != NULL)
  177. memcpy(new_str, *str, old_len);
  178. strcpy(new_str + old_len, append);
  179. free(*str);
  180. *str = new_str;
  181. }
  182. int
  183. apply_substitution(struct bsdtar *bsdtar, const char *name, char **result,
  184. int symlink_target, int hardlink_target)
  185. {
  186. const char *path = name;
  187. regmatch_t matches[10];
  188. size_t i, j;
  189. struct subst_rule *rule;
  190. struct substitution *subst;
  191. int c, got_match, print_match;
  192. *result = NULL;
  193. if ((subst = bsdtar->substitution) == NULL)
  194. return 0;
  195. got_match = 0;
  196. print_match = 0;
  197. for (rule = subst->first_rule; rule != NULL; rule = rule->next) {
  198. if (symlink_target) {
  199. if (!rule->symlink)
  200. continue;
  201. } else if (hardlink_target) {
  202. if (!rule->hardlink)
  203. continue;
  204. } else { /* Regular filename. */
  205. if (!rule->regular)
  206. continue;
  207. }
  208. while (1) {
  209. if (regexec(&rule->re, name, 10, matches, 0))
  210. break;
  211. got_match = 1;
  212. print_match |= rule->print;
  213. realloc_strncat(result, name, matches[0].rm_so);
  214. for (i = 0, j = 0; rule->result[i] != '\0'; ++i) {
  215. if (rule->result[i] == '~') {
  216. realloc_strncat(result, rule->result + j, i - j);
  217. realloc_strncat(result,
  218. name + matches[0].rm_so,
  219. matches[0].rm_eo - matches[0].rm_so);
  220. j = i + 1;
  221. continue;
  222. }
  223. if (rule->result[i] != '\\')
  224. continue;
  225. ++i;
  226. c = rule->result[i];
  227. switch (c) {
  228. case '~':
  229. case '\\':
  230. realloc_strncat(result, rule->result + j, i - j - 1);
  231. j = i;
  232. break;
  233. case '1':
  234. case '2':
  235. case '3':
  236. case '4':
  237. case '5':
  238. case '6':
  239. case '7':
  240. case '8':
  241. case '9':
  242. realloc_strncat(result, rule->result + j, i - j - 1);
  243. if ((size_t)(c - '0') > (size_t)(rule->re.re_nsub)) {
  244. free(*result);
  245. *result = NULL;
  246. return -1;
  247. }
  248. realloc_strncat(result, name + matches[c - '0'].rm_so, matches[c - '0'].rm_eo - matches[c - '0'].rm_so);
  249. j = i + 1;
  250. break;
  251. default:
  252. /* Just continue; */
  253. break;
  254. }
  255. }
  256. realloc_strcat(result, rule->result + j);
  257. name += matches[0].rm_eo;
  258. if (!rule->global)
  259. break;
  260. }
  261. }
  262. if (got_match)
  263. realloc_strcat(result, name);
  264. if (print_match)
  265. fprintf(stderr, "%s >> %s\n", path, *result);
  266. return got_match;
  267. }
  268. void
  269. cleanup_substitution(struct bsdtar *bsdtar)
  270. {
  271. struct subst_rule *rule;
  272. struct substitution *subst;
  273. if ((subst = bsdtar->substitution) == NULL)
  274. return;
  275. while ((rule = subst->first_rule) != NULL) {
  276. subst->first_rule = rule->next;
  277. free(rule->result);
  278. free(rule);
  279. }
  280. free(subst);
  281. }
  282. #endif /* defined(HAVE_REGEX_H) || defined(HAVE_PCREPOSIX_H) */