subst.c revision 228763
1139790Simp/*- 243412Snewton * Copyright (c) 2008 Joerg Sonnenberger 343412Snewton * All rights reserved. 443412Snewton * 543412Snewton * Redistribution and use in source and binary forms, with or without 643412Snewton * modification, are permitted provided that the following conditions 743412Snewton * are met: 843412Snewton * 1. Redistributions of source code must retain the above copyright 943412Snewton * notice, this list of conditions and the following disclaimer. 1043412Snewton * 2. Redistributions in binary form must reproduce the above copyright 1143412Snewton * notice, this list of conditions and the following disclaimer in the 1243412Snewton * documentation and/or other materials provided with the distribution. 1343412Snewton * 1443412Snewton * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR 1543412Snewton * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 1643412Snewton * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 1743412Snewton * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, 1843412Snewton * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 1943412Snewton * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2043412Snewton * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2143412Snewton * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2243412Snewton * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 2343412Snewton * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2443412Snewton */ 2543412Snewton 2643412Snewton#include "bsdtar_platform.h" 2743412Snewton__FBSDID("$FreeBSD: head/contrib/libarchive/tar/subst.c 228763 2011-12-21 11:13:29Z mm $"); 2843412Snewton 29116145Sobrien#if HAVE_REGEX_H 30116145Sobrien#include "bsdtar.h" 31116145Sobrien 3243412Snewton#include <errno.h> 3343412Snewton#include <regex.h> 3443412Snewton#include <stdlib.h> 3543412Snewton#include <string.h> 3676166Smarkm 3743412Snewton#ifndef REG_BASIC 3876166Smarkm#define REG_BASIC 0 3976166Smarkm#endif 4043412Snewton 4143412Snewton#include "err.h" 4243412Snewton 4343412Snewtonstruct subst_rule { 4443412Snewton struct subst_rule *next; 4543412Snewton regex_t re; 4643412Snewton char *result; 4743412Snewton unsigned int global:1, print:1, symlink:1; 4843412Snewton}; 4943412Snewton 5043412Snewtonstruct substitution { 5143412Snewton struct subst_rule *first_rule, *last_rule; 5276166Smarkm}; 5376166Smarkm 5476166Smarkmstatic void 5565302Sobrieninit_substitution(struct bsdtar *bsdtar) 5665302Sobrien{ 5765302Sobrien struct substitution *subst; 5843412Snewton 5965302Sobrien bsdtar->substitution = subst = malloc(sizeof(*subst)); 6065302Sobrien if (subst == NULL) 6165302Sobrien lafe_errc(1, errno, "Out of memory"); 6243412Snewton subst->first_rule = subst->last_rule = NULL; 6343412Snewton} 6443412Snewton 6543412Snewtonvoid 6643412Snewtonadd_substitution(struct bsdtar *bsdtar, const char *rule_text) 6743412Snewton{ 6843412Snewton struct subst_rule *rule; 6992765Salfred struct substitution *subst; 7043412Snewton const char *end_pattern, *start_subst; 7143412Snewton char *pattern; 7243412Snewton int r; 7343412Snewton 7443412Snewton if ((subst = bsdtar->substitution) == NULL) { 7543412Snewton init_substitution(bsdtar); 7643412Snewton subst = bsdtar->substitution; 7743412Snewton } 7843412Snewton 7943412Snewton rule = malloc(sizeof(*rule)); 8083366Sjulian if (rule == NULL) 8183366Sjulian lafe_errc(1, errno, "Out of memory"); 8243412Snewton rule->next = NULL; 8343412Snewton 8443412Snewton if (subst->last_rule == NULL) 8583366Sjulian subst->first_rule = rule; 8643412Snewton else 8743412Snewton subst->last_rule->next = rule; 8883366Sjulian subst->last_rule = rule; 8943412Snewton 9043412Snewton if (*rule_text == '\0') 9143412Snewton lafe_errc(1, 0, "Empty replacement string"); 9243412Snewton end_pattern = strchr(rule_text + 1, *rule_text); 9383366Sjulian if (end_pattern == NULL) 9483366Sjulian lafe_errc(1, 0, "Invalid replacement string"); 9543412Snewton 9651793Smarcel pattern = malloc(end_pattern - rule_text); 9751793Smarcel if (pattern == NULL) 9843412Snewton lafe_errc(1, errno, "Out of memory"); 9983366Sjulian memcpy(pattern, rule_text + 1, end_pattern - rule_text - 1); 10083366Sjulian pattern[end_pattern - rule_text - 1] = '\0'; 10143412Snewton 10243412Snewton if ((r = regcomp(&rule->re, pattern, REG_BASIC)) != 0) { 10356044Snewton char buf[80]; 10471495Sjhb regerror(r, &rule->re, buf, sizeof(buf)); 10571495Sjhb lafe_errc(1, 0, "Invalid regular expression: %s", buf); 10649270Snewton } 10743412Snewton free(pattern); 10883641Sjhb 10971495Sjhb start_subst = end_pattern + 1; 11071495Sjhb end_pattern = strchr(start_subst, *rule_text); 11171495Sjhb if (end_pattern == NULL) 11271495Sjhb lafe_errc(1, 0, "Invalid replacement string"); 11371495Sjhb 11443412Snewton rule->result = malloc(end_pattern - start_subst + 1); 11543412Snewton if (rule->result == NULL) 11644270Snewton lafe_errc(1, errno, "Out of memory"); 11743412Snewton memcpy(rule->result, start_subst, end_pattern - start_subst); 11843412Snewton rule->result[end_pattern - start_subst] = '\0'; 11943412Snewton 12047694Snewton rule->global = 0; 12143412Snewton rule->print = 0; 12243412Snewton rule->symlink = 0; 12343412Snewton 12443412Snewton while (*++end_pattern) { 12543412Snewton switch (*end_pattern) { 12683366Sjulian case 'g': 12743412Snewton case 'G': 12847694Snewton rule->global = 1; 12943412Snewton break; 13046129Sluoqi case 'p': 13143412Snewton case 'P': 13243412Snewton rule->print = 1; 13346129Sluoqi break; 13446129Sluoqi case 's': 13546129Sluoqi case 'S': 13646129Sluoqi rule->symlink = 1; 13743412Snewton break; 13843412Snewton default: 13943412Snewton lafe_errc(1, 0, "Invalid replacement flag %c", *end_pattern); 14043412Snewton } 14143412Snewton } 14243412Snewton} 14343412Snewton 14443412Snewtonstatic void 14543412Snewtonrealloc_strncat(char **str, const char *append, size_t len) 14643412Snewton{ 14743412Snewton char *new_str; 14843412Snewton size_t old_len; 14944270Snewton 15044270Snewton if (*str == NULL) 15143412Snewton old_len = 0; 15243412Snewton else 15343412Snewton old_len = strlen(*str); 15443412Snewton 15543412Snewton new_str = malloc(old_len + len + 1); 15643412Snewton if (new_str == NULL) 15743412Snewton lafe_errc(1, errno, "Out of memory"); 15843412Snewton memcpy(new_str, *str, old_len); 15956044Snewton memcpy(new_str + old_len, append, len); 16043412Snewton new_str[old_len + len] = '\0'; 16144270Snewton free(*str); 162298433Spfg *str = new_str; 16344270Snewton} 16444270Snewton 16544270Snewtonstatic void 16683641Sjhbrealloc_strcat(char **str, const char *append) 16743412Snewton{ 16843412Snewton char *new_str; 16943412Snewton size_t old_len; 17043412Snewton 17151793Smarcel if (*str == NULL) 17243412Snewton old_len = 0; 17343412Snewton else 17443412Snewton old_len = strlen(*str); 17543412Snewton 17656044Snewton new_str = malloc(old_len + strlen(append) + 1); 17743412Snewton if (new_str == NULL) 17843412Snewton lafe_errc(1, errno, "Out of memory"); 17943412Snewton memcpy(new_str, *str, old_len); 18043412Snewton strcpy(new_str + old_len, append); 18156044Snewton free(*str); 18243412Snewton *str = new_str; 18343412Snewton} 18443412Snewton 18543412Snewtonint 18643412Snewtonapply_substitution(struct bsdtar *bsdtar, const char *name, char **result, int symlink_only) 18743412Snewton{ 18843412Snewton const char *path = name; 18943412Snewton regmatch_t matches[10]; 19083366Sjulian size_t i, j; 19183366Sjulian struct subst_rule *rule; 19243412Snewton struct substitution *subst; 19343412Snewton int c, got_match, print_match; 19456044Snewton 19571495Sjhb *result = NULL; 19656044Snewton 19783366Sjulian if ((subst = bsdtar->substitution) == NULL) 19843412Snewton return 0; 19943412Snewton 20043412Snewton got_match = 0; 20171495Sjhb print_match = 0; 20251793Smarcel 20343412Snewton for (rule = subst->first_rule; rule != NULL; rule = rule->next) { 20483641Sjhb if (symlink_only && !rule->symlink) 20571495Sjhb continue; 20683641Sjhb if (regexec(&rule->re, name, 10, matches, 0)) 20771495Sjhb continue; 208124141Sobrien 20971495Sjhb got_match = 1; 21043412Snewton print_match |= rule->print; 21143412Snewton realloc_strncat(result, name, matches[0].rm_so); 21243412Snewton 21343412Snewton for (i = 0, j = 0; rule->result[i] != '\0'; ++i) { 21443412Snewton if (rule->result[i] == '~') { 21543412Snewton realloc_strncat(result, rule->result + j, i - j); 21643412Snewton realloc_strncat(result, name, matches[0].rm_eo); 21743412Snewton j = i + 1; 21843412Snewton continue; 219113623Sjhb } 220113623Sjhb if (rule->result[i] != '\\') 22144270Snewton continue; 222113623Sjhb 22344270Snewton ++i; 22456044Snewton c = rule->result[i]; 22556044Snewton switch (c) { 22683366Sjulian case '~': 22743412Snewton case '\\': 22843412Snewton realloc_strncat(result, rule->result + j, i - j - 1); 22943412Snewton j = i; 23043412Snewton break; 23147694Snewton case '1': 23256044Snewton case '2': 23343412Snewton case '3': 23443412Snewton case '4': 23543412Snewton case '5': 23643412Snewton case '6': 23743412Snewton case '7': 23883366Sjulian case '8': 23943412Snewton case '9': 24047694Snewton realloc_strncat(result, rule->result + j, i - j - 1); 24143412Snewton if ((size_t)(c - '0') > (size_t)(rule->re.re_nsub)) { 24243412Snewton free(*result); 24343412Snewton *result = NULL; 24443412Snewton return -1; 24543412Snewton } 24643412Snewton realloc_strncat(result, name + matches[c - '0'].rm_so, matches[c - '0'].rm_eo - matches[c - '0'].rm_so); 24743412Snewton j = i + 1; 24843412Snewton break; 249113623Sjhb default: 250113623Sjhb /* Just continue; */ 25143412Snewton break; 252113623Sjhb } 25343412Snewton 25446129Sluoqi } 25543412Snewton 25646129Sluoqi realloc_strcat(result, rule->result + j); 25746129Sluoqi 25846129Sluoqi name += matches[0].rm_eo; 25946129Sluoqi 26043412Snewton if (!rule->global) 26143412Snewton break; 26243412Snewton } 26343412Snewton 26443412Snewton if (got_match) 26543412Snewton realloc_strcat(result, name); 26643412Snewton 26743412Snewton if (print_match) 26843412Snewton fprintf(stderr, "%s >> %s\n", path, *result); 26943412Snewton 27043412Snewton return got_match; 27144270Snewton} 27244270Snewton 27343412Snewtonvoid 27443412Snewtoncleanup_substitution(struct bsdtar *bsdtar) 27543412Snewton{ 27643412Snewton struct subst_rule *rule; 27743412Snewton struct substitution *subst; 27844270Snewton 27943412Snewton if ((subst = bsdtar->substitution) == NULL) 28043412Snewton return; 28143412Snewton 28244270Snewton while ((rule = subst->first_rule) != NULL) { 28344270Snewton subst->first_rule = rule->next; 28444270Snewton free(rule->result); 28543412Snewton free(rule); 28643412Snewton } 28743412Snewton free(subst); 28843412Snewton} 28944270Snewton#endif /* HAVE_REGEX_H */ 29056044Snewton