subst.c revision 299529
1126596Sbms/*- 2126596Sbms * Copyright (c) 2008 Joerg Sonnenberger 3126596Sbms * All rights reserved. 4126596Sbms * 5126596Sbms * Redistribution and use in source and binary forms, with or without 6126596Sbms * modification, are permitted provided that the following conditions 7126596Sbms * are met: 8126596Sbms * 1. Redistributions of source code must retain the above copyright 9126596Sbms * notice, this list of conditions and the following disclaimer. 10126596Sbms * 2. Redistributions in binary form must reproduce the above copyright 11126596Sbms * notice, this list of conditions and the following disclaimer in the 12126596Sbms * documentation and/or other materials provided with the distribution. 13126596Sbms * 14126596Sbms * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR 15126596Sbms * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16126596Sbms * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17126596Sbms * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, 18126596Sbms * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 19126596Sbms * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 20126596Sbms * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 21126596Sbms * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22126596Sbms * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 23126596Sbms * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24126596Sbms */ 25126596Sbms 26126596Sbms#include "bsdtar_platform.h" 27126596Sbms__FBSDID("$FreeBSD: head/contrib/libarchive/tar/subst.c 299529 2016-05-12 10:16:16Z mm $"); 28126596Sbms 29207325Srpaulo#if defined(HAVE_REGEX_H) || defined(HAVE_PCREPOSIX_H) 30131738Sru#include "bsdtar.h" 31126596Sbms 32126596Sbms#include <errno.h> 33196155Ssam#ifdef HAVE_PCREPOSIX_H 34126596Sbms#include <pcreposix.h> 35126596Sbms#else 36126596Sbms#include <regex.h> 37196155Ssam#endif 38196155Ssam#include <stdlib.h> 39196155Ssam#include <string.h> 40196155Ssam 41196155Ssam#ifndef REG_BASIC 42131738Sru#define REG_BASIC 0 43196155Ssam#endif 44126596Sbms 45196155Ssam#include "err.h" 46196155Ssam 47196155Ssamstruct subst_rule { 48196155Ssam struct subst_rule *next; 49196155Ssam regex_t re; 50196155Ssam char *result; 51126596Sbms unsigned int global:1, print:1, regular:1, symlink:1, hardlink:1; 52196155Ssam}; 53196155Ssam 54126596Sbmsstruct substitution { 55196155Ssam struct subst_rule *first_rule, *last_rule; 56196155Ssam}; 57126596Sbms 58196155Ssamstatic void 59196155Ssaminit_substitution(struct bsdtar *bsdtar) 60126596Sbms{ 61131738Sru struct substitution *subst; 62196155Ssam 63196155Ssam bsdtar->substitution = subst = malloc(sizeof(*subst)); 64196155Ssam if (subst == NULL) 65131738Sru lafe_errc(1, errno, "Out of memory"); 66131583Sbms subst->first_rule = subst->last_rule = NULL; 67196155Ssam} 68196155Ssam 69196155Ssamvoid 70233648Seadleradd_substitution(struct bsdtar *bsdtar, const char *rule_text) 71131583Sbms{ 72196155Ssam struct subst_rule *rule; 73196155Ssam struct substitution *subst; 74196155Ssam const char *end_pattern, *start_subst; 75233648Seadler char *pattern; 76196155Ssam int r; 77131583Sbms 78196155Ssam if ((subst = bsdtar->substitution) == NULL) { 79196155Ssam init_substitution(bsdtar); 80196155Ssam subst = bsdtar->substitution; 81233648Seadler } 82196155Ssam 83196155Ssam rule = malloc(sizeof(*rule)); 84196155Ssam if (rule == NULL) 85196155Ssam lafe_errc(1, errno, "Out of memory"); 86196155Ssam rule->next = NULL; 87196155Ssam 88196155Ssam if (subst->last_rule == NULL) 89196155Ssam subst->first_rule = rule; 90196155Ssam else 91196155Ssam subst->last_rule->next = rule; 92196155Ssam subst->last_rule = rule; 93196155Ssam 94196155Ssam if (*rule_text == '\0') 95196155Ssam lafe_errc(1, 0, "Empty replacement string"); 96196155Ssam end_pattern = strchr(rule_text + 1, *rule_text); 97196155Ssam if (end_pattern == NULL) 98196155Ssam lafe_errc(1, 0, "Invalid replacement string"); 99131583Sbms 100196155Ssam pattern = malloc(end_pattern - rule_text); 101196155Ssam if (pattern == NULL) 102196155Ssam lafe_errc(1, errno, "Out of memory"); 103196155Ssam memcpy(pattern, rule_text + 1, end_pattern - rule_text - 1); 104211936Sbrucec pattern[end_pattern - rule_text - 1] = '\0'; 105196155Ssam 106196155Ssam if ((r = regcomp(&rule->re, pattern, REG_BASIC)) != 0) { 107196155Ssam char buf[80]; 108196155Ssam regerror(r, &rule->re, buf, sizeof(buf)); 109131583Sbms lafe_errc(1, 0, "Invalid regular expression: %s", buf); 110196155Ssam } 111196155Ssam free(pattern); 112196155Ssam 113196155Ssam start_subst = end_pattern + 1; 114196155Ssam end_pattern = strchr(start_subst, *rule_text); 115196155Ssam if (end_pattern == NULL) 116196155Ssam lafe_errc(1, 0, "Invalid replacement string"); 117196155Ssam 118196155Ssam rule->result = malloc(end_pattern - start_subst + 1); 119131583Sbms if (rule->result == NULL) 120196155Ssam lafe_errc(1, errno, "Out of memory"); 121196155Ssam memcpy(rule->result, start_subst, end_pattern - start_subst); 122196155Ssam rule->result[end_pattern - start_subst] = '\0'; 123196155Ssam 124196155Ssam /* Defaults */ 125196155Ssam rule->global = 0; /* Don't do multiple replacements. */ 126196155Ssam rule->print = 0; /* Don't print. */ 127196155Ssam rule->regular = 1; /* Rewrite regular filenames. */ 128233648Seadler rule->symlink = 1; /* Rewrite symlink targets. */ 129196155Ssam rule->hardlink = 1; /* Rewrite hardlink targets. */ 130196155Ssam 131196155Ssam while (*++end_pattern) { 132196155Ssam switch (*end_pattern) { 133196155Ssam case 'g': 134196155Ssam case 'G': 135196155Ssam rule->global = 1; 136131583Sbms break; 137196155Ssam case 'h': 138196155Ssam rule->hardlink = 1; 139196155Ssam break; 140196155Ssam case 'H': 141196155Ssam rule->hardlink = 0; 142233648Seadler break; 143196155Ssam case 'p': 144196155Ssam case 'P': 145196155Ssam rule->print = 1; 146196155Ssam break; 147131583Sbms case 'r': 148196155Ssam rule->regular = 1; 149196155Ssam break; 150196155Ssam case 'R': 151196155Ssam rule->regular = 0; 152196155Ssam break; 153196155Ssam case 's': 154196155Ssam rule->symlink = 1; 155207325Srpaulo break; 156196155Ssam case 'S': 157196155Ssam rule->symlink = 0; 158196155Ssam break; 159196155Ssam default: 160196155Ssam lafe_errc(1, 0, "Invalid replacement flag %c", *end_pattern); 161196155Ssam } 162196155Ssam } 163196155Ssam} 164196155Ssam 165196155Ssamstatic void 166196155Ssamrealloc_strncat(char **str, const char *append, size_t len) 167196155Ssam{ 168196155Ssam char *new_str; 169196155Ssam size_t old_len; 170196155Ssam 171196155Ssam if (*str == NULL) 172196155Ssam old_len = 0; 173196155Ssam else 174196155Ssam old_len = strlen(*str); 175196155Ssam 176196155Ssam new_str = malloc(old_len + len + 1); 177196155Ssam if (new_str == NULL) 178196155Ssam lafe_errc(1, errno, "Out of memory"); 179131583Sbms if (*str != NULL) 180196155Ssam memcpy(new_str, *str, old_len); 181196155Ssam memcpy(new_str + old_len, append, len); 182196155Ssam new_str[old_len + len] = '\0'; 183196155Ssam free(*str); 184196155Ssam *str = new_str; 185196155Ssam} 186196155Ssam 187196155Ssamstatic void 188238542Skevlorealloc_strcat(char **str, const char *append) 189196155Ssam{ 190196155Ssam char *new_str; 191196155Ssam size_t old_len; 192196155Ssam 193196155Ssam if (*str == NULL) 194196155Ssam old_len = 0; 195196155Ssam else 196131583Sbms old_len = strlen(*str); 197196155Ssam 198196155Ssam new_str = malloc(old_len + strlen(append) + 1); 199196155Ssam if (new_str == NULL) 200196155Ssam lafe_errc(1, errno, "Out of memory"); 201196155Ssam if (*str != NULL) 202196155Ssam memcpy(new_str, *str, old_len); 203196155Ssam strcpy(new_str + old_len, append); 204196155Ssam free(*str); 205196155Ssam *str = new_str; 206196155Ssam} 207196155Ssam 208196155Ssamint 209233648Seadlerapply_substitution(struct bsdtar *bsdtar, const char *name, char **result, 210196155Ssam int symlink_target, int hardlink_target) 211196155Ssam{ 212196155Ssam const char *path = name; 213196155Ssam regmatch_t matches[10]; 214196155Ssam size_t i, j; 215131583Sbms struct subst_rule *rule; 216196155Ssam struct substitution *subst; 217196155Ssam int c, got_match, print_match; 218196155Ssam 219196155Ssam *result = NULL; 220196155Ssam 221196155Ssam if ((subst = bsdtar->substitution) == NULL) 222196155Ssam return 0; 223196155Ssam 224196155Ssam got_match = 0; 225196155Ssam print_match = 0; 226196155Ssam 227196155Ssam for (rule = subst->first_rule; rule != NULL; rule = rule->next) { 228196155Ssam if (symlink_target) { 229196155Ssam if (!rule->symlink) 230196155Ssam continue; 231196155Ssam } else if (hardlink_target) { 232196155Ssam if (!rule->hardlink) 233196155Ssam continue; 234196155Ssam } else { /* Regular filename. */ 235196155Ssam if (!rule->regular) 236196155Ssam continue; 237196155Ssam } 238196155Ssam 239196155Ssam while (1) { 240196155Ssam if (regexec(&rule->re, name, 10, matches, 0)) 241196155Ssam break; 242196155Ssam 243196155Ssam got_match = 1; 244196155Ssam print_match |= rule->print; 245196155Ssam realloc_strncat(result, name, matches[0].rm_so); 246196155Ssam 247196155Ssam for (i = 0, j = 0; rule->result[i] != '\0'; ++i) { 248126596Sbms if (rule->result[i] == '~') { 249205846Strasz realloc_strncat(result, rule->result + j, i - j); 250126596Sbms realloc_strncat(result, 251197300Sbrueffer name + matches[0].rm_so, 252 matches[0].rm_eo - matches[0].rm_so); 253 j = i + 1; 254 continue; 255 } 256 if (rule->result[i] != '\\') 257 continue; 258 259 ++i; 260 c = rule->result[i]; 261 switch (c) { 262 case '~': 263 case '\\': 264 realloc_strncat(result, rule->result + j, i - j - 1); 265 j = i; 266 break; 267 case '1': 268 case '2': 269 case '3': 270 case '4': 271 case '5': 272 case '6': 273 case '7': 274 case '8': 275 case '9': 276 realloc_strncat(result, rule->result + j, i - j - 1); 277 if ((size_t)(c - '0') > (size_t)(rule->re.re_nsub)) { 278 free(*result); 279 *result = NULL; 280 return -1; 281 } 282 realloc_strncat(result, name + matches[c - '0'].rm_so, matches[c - '0'].rm_eo - matches[c - '0'].rm_so); 283 j = i + 1; 284 break; 285 default: 286 /* Just continue; */ 287 break; 288 } 289 290 } 291 292 realloc_strcat(result, rule->result + j); 293 294 name += matches[0].rm_eo; 295 296 if (!rule->global) 297 break; 298 } 299 } 300 301 if (got_match) 302 realloc_strcat(result, name); 303 304 if (print_match) 305 fprintf(stderr, "%s >> %s\n", path, *result); 306 307 return got_match; 308} 309 310void 311cleanup_substitution(struct bsdtar *bsdtar) 312{ 313 struct subst_rule *rule; 314 struct substitution *subst; 315 316 if ((subst = bsdtar->substitution) == NULL) 317 return; 318 319 while ((rule = subst->first_rule) != NULL) { 320 subst->first_rule = rule->next; 321 free(rule->result); 322 free(rule); 323 } 324 free(subst); 325} 326#endif /* defined(HAVE_REGEX_H) || defined(HAVE_PCREPOSIX_H) */ 327