2 * Copyright (c) 2008 Joerg Sonnenberger
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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.
26 #include "bsdtar_platform.h"
27 __FBSDID("$FreeBSD: src/usr.bin/tar/subst.c,v 1.4 2008/06/15 10:08:16 kientzle Exp $");
29 #if defined(HAVE_REGEX_H) || defined(HAVE_PCREPOSIX_H)
33 #ifdef HAVE_PCREPOSIX_H
34 #include <pcreposix.h>
48 struct subst_rule
*next
;
51 unsigned int global
:1, print
:1, regular
:1, symlink
:1, hardlink
:1;
55 struct subst_rule
*first_rule
, *last_rule
;
59 init_substitution(struct bsdtar
*bsdtar
)
61 struct substitution
*subst
;
63 bsdtar
->substitution
= subst
= malloc(sizeof(*subst
));
65 lafe_errc(1, errno
, "Out of memory");
66 subst
->first_rule
= subst
->last_rule
= NULL
;
70 add_substitution(struct bsdtar
*bsdtar
, const char *rule_text
)
72 struct subst_rule
*rule
;
73 struct substitution
*subst
;
74 const char *end_pattern
, *start_subst
;
78 if ((subst
= bsdtar
->substitution
) == NULL
) {
79 init_substitution(bsdtar
);
80 subst
= bsdtar
->substitution
;
83 rule
= malloc(sizeof(*rule
));
85 lafe_errc(1, errno
, "Out of memory");
88 if (subst
->last_rule
== NULL
)
89 subst
->first_rule
= rule
;
91 subst
->last_rule
->next
= rule
;
92 subst
->last_rule
= rule
;
94 if (*rule_text
== '\0')
95 lafe_errc(1, 0, "Empty replacement string");
96 end_pattern
= strchr(rule_text
+ 1, *rule_text
);
97 if (end_pattern
== NULL
)
98 lafe_errc(1, 0, "Invalid replacement string");
100 pattern
= malloc(end_pattern
- rule_text
);
102 lafe_errc(1, errno
, "Out of memory");
103 memcpy(pattern
, rule_text
+ 1, end_pattern
- rule_text
- 1);
104 pattern
[end_pattern
- rule_text
- 1] = '\0';
106 if ((r
= regcomp(&rule
->re
, pattern
, REG_BASIC
)) != 0) {
108 regerror(r
, &rule
->re
, buf
, sizeof(buf
));
109 lafe_errc(1, 0, "Invalid regular expression: %s", buf
);
113 start_subst
= end_pattern
+ 1;
114 end_pattern
= strchr(start_subst
, *rule_text
);
115 if (end_pattern
== NULL
)
116 lafe_errc(1, 0, "Invalid replacement string");
118 rule
->result
= malloc(end_pattern
- start_subst
+ 1);
119 if (rule
->result
== NULL
)
120 lafe_errc(1, errno
, "Out of memory");
121 memcpy(rule
->result
, start_subst
, end_pattern
- start_subst
);
122 rule
->result
[end_pattern
- start_subst
] = '\0';
125 rule
->global
= 0; /* Don't do multiple replacements. */
126 rule
->print
= 0; /* Don't print. */
127 rule
->regular
= 1; /* Rewrite regular filenames. */
128 rule
->symlink
= 1; /* Rewrite symlink targets. */
129 rule
->hardlink
= 1; /* Rewrite hardlink targets. */
131 while (*++end_pattern
) {
132 switch (*end_pattern
) {
160 lafe_errc(1, 0, "Invalid replacement flag %c", *end_pattern
);
166 realloc_strncat(char **str
, const char *append
, size_t len
)
174 old_len
= strlen(*str
);
176 new_str
= malloc(old_len
+ len
+ 1);
178 lafe_errc(1, errno
, "Out of memory");
180 memcpy(new_str
, *str
, old_len
);
181 memcpy(new_str
+ old_len
, append
, len
);
182 new_str
[old_len
+ len
] = '\0';
188 realloc_strcat(char **str
, const char *append
)
196 old_len
= strlen(*str
);
198 new_str
= malloc(old_len
+ strlen(append
) + 1);
200 lafe_errc(1, errno
, "Out of memory");
202 memcpy(new_str
, *str
, old_len
);
203 strcpy(new_str
+ old_len
, append
);
209 apply_substitution(struct bsdtar
*bsdtar
, const char *name
, char **result
,
210 int symlink_target
, int hardlink_target
)
212 const char *path
= name
;
213 regmatch_t matches
[10];
215 struct subst_rule
*rule
;
216 struct substitution
*subst
;
217 int c
, got_match
, print_match
;
221 if ((subst
= bsdtar
->substitution
) == NULL
)
227 for (rule
= subst
->first_rule
; rule
!= NULL
; rule
= rule
->next
) {
228 if (symlink_target
) {
231 } else if (hardlink_target
) {
234 } else { /* Regular filename. */
240 if (regexec(&rule
->re
, name
, 10, matches
, 0))
244 print_match
|= rule
->print
;
245 realloc_strncat(result
, name
, matches
[0].rm_so
);
247 for (i
= 0, j
= 0; rule
->result
[i
] != '\0'; ++i
) {
248 if (rule
->result
[i
] == '~') {
249 realloc_strncat(result
, rule
->result
+ j
, i
- j
);
250 realloc_strncat(result
,
251 name
+ matches
[0].rm_so
,
252 matches
[0].rm_eo
- matches
[0].rm_so
);
256 if (rule
->result
[i
] != '\\')
264 realloc_strncat(result
, rule
->result
+ j
, i
- j
- 1);
276 realloc_strncat(result
, rule
->result
+ j
, i
- j
- 1);
277 if ((size_t)(c
- '0') > (size_t)(rule
->re
.re_nsub
)) {
282 realloc_strncat(result
, name
+ matches
[c
- '0'].rm_so
, matches
[c
- '0'].rm_eo
- matches
[c
- '0'].rm_so
);
292 realloc_strcat(result
, rule
->result
+ j
);
294 name
+= matches
[0].rm_eo
;
302 realloc_strcat(result
, name
);
305 fprintf(stderr
, "%s >> %s\n", path
, *result
);
311 cleanup_substitution(struct bsdtar
*bsdtar
)
313 struct subst_rule
*rule
;
314 struct substitution
*subst
;
316 if ((subst
= bsdtar
->substitution
) == NULL
)
319 while ((rule
= subst
->first_rule
) != NULL
) {
320 subst
->first_rule
= rule
->next
;
326 #endif /* defined(HAVE_REGEX_H) || defined(HAVE_PCREPOSIX_H) */