1228753Smm/*- 2228753Smm * Copyright (c) 2008 Joerg Sonnenberger 3228753Smm * All rights reserved. 4228753Smm * 5228753Smm * Redistribution and use in source and binary forms, with or without 6228753Smm * modification, are permitted provided that the following conditions 7228753Smm * are met: 8228753Smm * 1. Redistributions of source code must retain the above copyright 9228753Smm * notice, this list of conditions and the following disclaimer. 10228753Smm * 2. Redistributions in binary form must reproduce the above copyright 11228753Smm * notice, this list of conditions and the following disclaimer in the 12228753Smm * documentation and/or other materials provided with the distribution. 13228753Smm * 14228753Smm * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR 15228753Smm * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16228753Smm * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17228753Smm * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, 18228753Smm * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 19228753Smm * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 20228753Smm * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 21228753Smm * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22228753Smm * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 23228753Smm * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24228753Smm */ 25228753Smm 26228753Smm#include "bsdtar_platform.h" 27228763Smm__FBSDID("$FreeBSD: stable/11/contrib/libarchive/tar/subst.c 307138 2016-10-12 10:28:22Z mm $"); 28228753Smm 29248616Smm#if defined(HAVE_REGEX_H) || defined(HAVE_PCREPOSIX_H) 30228753Smm#include "bsdtar.h" 31228753Smm 32228753Smm#include <errno.h> 33248616Smm#ifdef HAVE_PCREPOSIX_H 34248616Smm#include <pcreposix.h> 35248616Smm#else 36228753Smm#include <regex.h> 37248616Smm#endif 38228753Smm#include <stdlib.h> 39228753Smm#include <string.h> 40228753Smm 41228753Smm#ifndef REG_BASIC 42228753Smm#define REG_BASIC 0 43228753Smm#endif 44228753Smm 45228753Smm#include "err.h" 46228753Smm 47228753Smmstruct subst_rule { 48228753Smm struct subst_rule *next; 49228753Smm regex_t re; 50228753Smm char *result; 51232153Smm unsigned int global:1, print:1, regular:1, symlink:1, hardlink:1; 52228753Smm}; 53228753Smm 54228753Smmstruct substitution { 55228753Smm struct subst_rule *first_rule, *last_rule; 56228753Smm}; 57228753Smm 58228753Smmstatic void 59228753Smminit_substitution(struct bsdtar *bsdtar) 60228753Smm{ 61228753Smm struct substitution *subst; 62228753Smm 63228753Smm bsdtar->substitution = subst = malloc(sizeof(*subst)); 64228753Smm if (subst == NULL) 65228753Smm lafe_errc(1, errno, "Out of memory"); 66228753Smm subst->first_rule = subst->last_rule = NULL; 67228753Smm} 68228753Smm 69228753Smmvoid 70228753Smmadd_substitution(struct bsdtar *bsdtar, const char *rule_text) 71228753Smm{ 72228753Smm struct subst_rule *rule; 73228753Smm struct substitution *subst; 74228753Smm const char *end_pattern, *start_subst; 75228753Smm char *pattern; 76228753Smm int r; 77228753Smm 78228753Smm if ((subst = bsdtar->substitution) == NULL) { 79228753Smm init_substitution(bsdtar); 80228753Smm subst = bsdtar->substitution; 81228753Smm } 82228753Smm 83228753Smm rule = malloc(sizeof(*rule)); 84228753Smm if (rule == NULL) 85228753Smm lafe_errc(1, errno, "Out of memory"); 86228753Smm rule->next = NULL; 87307138Smm rule->result = NULL; 88228753Smm 89228753Smm if (subst->last_rule == NULL) 90228753Smm subst->first_rule = rule; 91228753Smm else 92228753Smm subst->last_rule->next = rule; 93228753Smm subst->last_rule = rule; 94228753Smm 95228753Smm if (*rule_text == '\0') 96228753Smm lafe_errc(1, 0, "Empty replacement string"); 97228753Smm end_pattern = strchr(rule_text + 1, *rule_text); 98228753Smm if (end_pattern == NULL) 99228753Smm lafe_errc(1, 0, "Invalid replacement string"); 100228753Smm 101228753Smm pattern = malloc(end_pattern - rule_text); 102228753Smm if (pattern == NULL) 103228753Smm lafe_errc(1, errno, "Out of memory"); 104228753Smm memcpy(pattern, rule_text + 1, end_pattern - rule_text - 1); 105228753Smm pattern[end_pattern - rule_text - 1] = '\0'; 106228753Smm 107228753Smm if ((r = regcomp(&rule->re, pattern, REG_BASIC)) != 0) { 108228753Smm char buf[80]; 109228753Smm regerror(r, &rule->re, buf, sizeof(buf)); 110228753Smm lafe_errc(1, 0, "Invalid regular expression: %s", buf); 111228753Smm } 112228753Smm free(pattern); 113228753Smm 114228753Smm start_subst = end_pattern + 1; 115228753Smm end_pattern = strchr(start_subst, *rule_text); 116228753Smm if (end_pattern == NULL) 117228753Smm lafe_errc(1, 0, "Invalid replacement string"); 118228753Smm 119228753Smm rule->result = malloc(end_pattern - start_subst + 1); 120228753Smm if (rule->result == NULL) 121228753Smm lafe_errc(1, errno, "Out of memory"); 122228753Smm memcpy(rule->result, start_subst, end_pattern - start_subst); 123228753Smm rule->result[end_pattern - start_subst] = '\0'; 124228753Smm 125232153Smm /* Defaults */ 126232153Smm rule->global = 0; /* Don't do multiple replacements. */ 127232153Smm rule->print = 0; /* Don't print. */ 128232153Smm rule->regular = 1; /* Rewrite regular filenames. */ 129232153Smm rule->symlink = 1; /* Rewrite symlink targets. */ 130232153Smm rule->hardlink = 1; /* Rewrite hardlink targets. */ 131228753Smm 132228753Smm while (*++end_pattern) { 133228753Smm switch (*end_pattern) { 134228753Smm case 'g': 135228753Smm case 'G': 136228753Smm rule->global = 1; 137228753Smm break; 138232153Smm case 'h': 139232153Smm rule->hardlink = 1; 140232153Smm break; 141232153Smm case 'H': 142232153Smm rule->hardlink = 0; 143232153Smm break; 144228753Smm case 'p': 145228753Smm case 'P': 146228753Smm rule->print = 1; 147228753Smm break; 148232153Smm case 'r': 149232153Smm rule->regular = 1; 150232153Smm break; 151232153Smm case 'R': 152232153Smm rule->regular = 0; 153232153Smm break; 154228753Smm case 's': 155228753Smm rule->symlink = 1; 156228753Smm break; 157232153Smm case 'S': 158232153Smm rule->symlink = 0; 159232153Smm break; 160228753Smm default: 161228753Smm lafe_errc(1, 0, "Invalid replacement flag %c", *end_pattern); 162228753Smm } 163228753Smm } 164228753Smm} 165228753Smm 166228753Smmstatic void 167228753Smmrealloc_strncat(char **str, const char *append, size_t len) 168228753Smm{ 169228753Smm char *new_str; 170228753Smm size_t old_len; 171228753Smm 172228753Smm if (*str == NULL) 173228753Smm old_len = 0; 174228753Smm else 175228753Smm old_len = strlen(*str); 176228753Smm 177228753Smm new_str = malloc(old_len + len + 1); 178228753Smm if (new_str == NULL) 179228753Smm lafe_errc(1, errno, "Out of memory"); 180232153Smm if (*str != NULL) 181232153Smm memcpy(new_str, *str, old_len); 182228753Smm memcpy(new_str + old_len, append, len); 183228753Smm new_str[old_len + len] = '\0'; 184228753Smm free(*str); 185228753Smm *str = new_str; 186228753Smm} 187228753Smm 188228753Smmstatic void 189228753Smmrealloc_strcat(char **str, const char *append) 190228753Smm{ 191228753Smm char *new_str; 192228753Smm size_t old_len; 193228753Smm 194228753Smm if (*str == NULL) 195228753Smm old_len = 0; 196228753Smm else 197228753Smm old_len = strlen(*str); 198228753Smm 199228753Smm new_str = malloc(old_len + strlen(append) + 1); 200228753Smm if (new_str == NULL) 201228753Smm lafe_errc(1, errno, "Out of memory"); 202232153Smm if (*str != NULL) 203232153Smm memcpy(new_str, *str, old_len); 204228753Smm strcpy(new_str + old_len, append); 205228753Smm free(*str); 206228753Smm *str = new_str; 207228753Smm} 208228753Smm 209228753Smmint 210232153Smmapply_substitution(struct bsdtar *bsdtar, const char *name, char **result, 211232153Smm int symlink_target, int hardlink_target) 212228753Smm{ 213228753Smm const char *path = name; 214228753Smm regmatch_t matches[10]; 215228753Smm size_t i, j; 216228753Smm struct subst_rule *rule; 217228753Smm struct substitution *subst; 218228753Smm int c, got_match, print_match; 219228753Smm 220228753Smm *result = NULL; 221228753Smm 222228753Smm if ((subst = bsdtar->substitution) == NULL) 223228753Smm return 0; 224228753Smm 225228753Smm got_match = 0; 226228753Smm print_match = 0; 227228753Smm 228228753Smm for (rule = subst->first_rule; rule != NULL; rule = rule->next) { 229232153Smm if (symlink_target) { 230232153Smm if (!rule->symlink) 231232153Smm continue; 232232153Smm } else if (hardlink_target) { 233232153Smm if (!rule->hardlink) 234232153Smm continue; 235232153Smm } else { /* Regular filename. */ 236232153Smm if (!rule->regular) 237232153Smm continue; 238232153Smm } 239232153Smm 240299529Smm while (1) { 241299529Smm if (regexec(&rule->re, name, 10, matches, 0)) 242299529Smm break; 243228753Smm 244299529Smm got_match = 1; 245299529Smm print_match |= rule->print; 246299529Smm realloc_strncat(result, name, matches[0].rm_so); 247228753Smm 248299529Smm for (i = 0, j = 0; rule->result[i] != '\0'; ++i) { 249299529Smm if (rule->result[i] == '~') { 250299529Smm realloc_strncat(result, rule->result + j, i - j); 251299529Smm realloc_strncat(result, 252299529Smm name + matches[0].rm_so, 253299529Smm matches[0].rm_eo - matches[0].rm_so); 254299529Smm j = i + 1; 255299529Smm continue; 256299529Smm } 257299529Smm if (rule->result[i] != '\\') 258299529Smm continue; 259228753Smm 260299529Smm ++i; 261299529Smm c = rule->result[i]; 262299529Smm switch (c) { 263299529Smm case '~': 264299529Smm case '\\': 265299529Smm realloc_strncat(result, rule->result + j, i - j - 1); 266299529Smm j = i; 267299529Smm break; 268299529Smm case '1': 269299529Smm case '2': 270299529Smm case '3': 271299529Smm case '4': 272299529Smm case '5': 273299529Smm case '6': 274299529Smm case '7': 275299529Smm case '8': 276299529Smm case '9': 277299529Smm realloc_strncat(result, rule->result + j, i - j - 1); 278299529Smm if ((size_t)(c - '0') > (size_t)(rule->re.re_nsub)) { 279299529Smm free(*result); 280299529Smm *result = NULL; 281299529Smm return -1; 282299529Smm } 283299529Smm realloc_strncat(result, name + matches[c - '0'].rm_so, matches[c - '0'].rm_eo - matches[c - '0'].rm_so); 284299529Smm j = i + 1; 285299529Smm break; 286299529Smm default: 287299529Smm /* Just continue; */ 288299529Smm break; 289228753Smm } 290299529Smm 291228753Smm } 292228753Smm 293299529Smm realloc_strcat(result, rule->result + j); 294228753Smm 295299529Smm name += matches[0].rm_eo; 296228753Smm 297299529Smm if (!rule->global) 298299529Smm break; 299299529Smm } 300228753Smm } 301228753Smm 302228753Smm if (got_match) 303228753Smm realloc_strcat(result, name); 304228753Smm 305228753Smm if (print_match) 306228753Smm fprintf(stderr, "%s >> %s\n", path, *result); 307228753Smm 308228753Smm return got_match; 309228753Smm} 310228753Smm 311228753Smmvoid 312228753Smmcleanup_substitution(struct bsdtar *bsdtar) 313228753Smm{ 314228753Smm struct subst_rule *rule; 315228753Smm struct substitution *subst; 316228753Smm 317228753Smm if ((subst = bsdtar->substitution) == NULL) 318228753Smm return; 319228753Smm 320228753Smm while ((rule = subst->first_rule) != NULL) { 321228753Smm subst->first_rule = rule->next; 322228753Smm free(rule->result); 323228753Smm free(rule); 324228753Smm } 325228753Smm free(subst); 326228753Smm} 327248616Smm#endif /* defined(HAVE_REGEX_H) || defined(HAVE_PCREPOSIX_H) */ 328