Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/libarchive/tar/subst.c
39478 views
1
/*-
2
* SPDX-License-Identifier: BSD-2-Clause
3
*
4
* Copyright (c) 2008 Joerg Sonnenberger
5
* All rights reserved.
6
*/
7
8
#include "bsdtar_platform.h"
9
10
#if defined(HAVE_REGEX_H) || defined(HAVE_PCREPOSIX_H) || defined(HAVE_PCRE2POSIX_H)
11
#include "bsdtar.h"
12
13
#include <errno.h>
14
#if defined(HAVE_PCREPOSIX_H)
15
#include <pcreposix.h>
16
#elif defined(HAVE_PCRE2POSIX_H)
17
#include <pcre2posix.h>
18
#else
19
#include <regex.h>
20
#endif
21
#include <stdlib.h>
22
#include <string.h>
23
24
#ifndef REG_BASIC
25
#define REG_BASIC 0
26
#endif
27
28
#include "err.h"
29
30
struct subst_rule {
31
struct subst_rule *next;
32
regex_t re;
33
char *result;
34
unsigned int global:1, print:1, regular:1, symlink:1, hardlink:1, from_begin:1;
35
};
36
37
struct substitution {
38
struct subst_rule *first_rule, *last_rule;
39
};
40
41
static void
42
init_substitution(struct bsdtar *bsdtar)
43
{
44
struct substitution *subst;
45
46
bsdtar->substitution = subst = malloc(sizeof(*subst));
47
if (subst == NULL)
48
lafe_errc(1, errno, "Out of memory");
49
subst->first_rule = subst->last_rule = NULL;
50
}
51
52
void
53
add_substitution(struct bsdtar *bsdtar, const char *rule_text)
54
{
55
struct subst_rule *rule;
56
struct substitution *subst;
57
const char *end_pattern, *start_subst;
58
char *pattern;
59
int r;
60
61
if ((subst = bsdtar->substitution) == NULL) {
62
init_substitution(bsdtar);
63
subst = bsdtar->substitution;
64
}
65
66
rule = malloc(sizeof(*rule));
67
if (rule == NULL)
68
lafe_errc(1, errno, "Out of memory");
69
rule->next = NULL;
70
rule->result = NULL;
71
72
if (subst->last_rule == NULL)
73
subst->first_rule = rule;
74
else
75
subst->last_rule->next = rule;
76
subst->last_rule = rule;
77
78
if (*rule_text == '\0')
79
lafe_errc(1, 0, "Empty replacement string");
80
end_pattern = strchr(rule_text + 1, *rule_text);
81
if (end_pattern == NULL)
82
lafe_errc(1, 0, "Invalid replacement string");
83
84
pattern = malloc(end_pattern - rule_text);
85
if (pattern == NULL)
86
lafe_errc(1, errno, "Out of memory");
87
memcpy(pattern, rule_text + 1, end_pattern - rule_text - 1);
88
pattern[end_pattern - rule_text - 1] = '\0';
89
90
if ((r = regcomp(&rule->re, pattern, REG_BASIC)) != 0) {
91
char buf[80];
92
regerror(r, &rule->re, buf, sizeof(buf));
93
lafe_errc(1, 0, "Invalid regular expression: %s", buf);
94
}
95
free(pattern);
96
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
102
rule->result = malloc(end_pattern - start_subst + 1);
103
if (rule->result == NULL)
104
lafe_errc(1, errno, "Out of memory");
105
memcpy(rule->result, start_subst, end_pattern - start_subst);
106
rule->result[end_pattern - start_subst] = '\0';
107
108
/* Defaults */
109
rule->global = 0; /* Don't do multiple replacements. */
110
rule->print = 0; /* Don't print. */
111
rule->regular = 1; /* Rewrite regular filenames. */
112
rule->symlink = 1; /* Rewrite symlink targets. */
113
rule->hardlink = 1; /* Rewrite hardlink targets. */
114
rule->from_begin = 0; /* Don't match from start. */
115
116
while (*++end_pattern) {
117
switch (*end_pattern) {
118
case 'b':
119
case 'B':
120
rule->from_begin = 1;
121
break;
122
case 'g':
123
case 'G':
124
rule->global = 1;
125
break;
126
case 'h':
127
rule->hardlink = 1;
128
break;
129
case 'H':
130
rule->hardlink = 0;
131
break;
132
case 'p':
133
case 'P':
134
rule->print = 1;
135
break;
136
case 'r':
137
rule->regular = 1;
138
break;
139
case 'R':
140
rule->regular = 0;
141
break;
142
case 's':
143
rule->symlink = 1;
144
break;
145
case 'S':
146
rule->symlink = 0;
147
break;
148
default:
149
lafe_errc(1, 0, "Invalid replacement flag %c", *end_pattern);
150
/* NOTREACHED */
151
}
152
}
153
}
154
155
static void
156
realloc_strncat(char **str, const char *append, size_t len)
157
{
158
char *new_str;
159
size_t old_len;
160
161
if (*str == NULL)
162
old_len = 0;
163
else
164
old_len = strlen(*str);
165
166
new_str = malloc(old_len + len + 1);
167
if (new_str == NULL)
168
lafe_errc(1, errno, "Out of memory");
169
if (*str != NULL)
170
memcpy(new_str, *str, old_len);
171
memcpy(new_str + old_len, append, len);
172
new_str[old_len + len] = '\0';
173
free(*str);
174
*str = new_str;
175
}
176
177
static void
178
realloc_strcat(char **str, const char *append)
179
{
180
char *new_str;
181
size_t old_len;
182
183
if (*str == NULL)
184
old_len = 0;
185
else
186
old_len = strlen(*str);
187
188
new_str = malloc(old_len + strlen(append) + 1);
189
if (new_str == NULL)
190
lafe_errc(1, errno, "Out of memory");
191
if (*str != NULL)
192
memcpy(new_str, *str, old_len);
193
strcpy(new_str + old_len, append);
194
free(*str);
195
*str = new_str;
196
}
197
198
int
199
apply_substitution(struct bsdtar *bsdtar, const char *name, char **result,
200
int symlink_target, int hardlink_target)
201
{
202
const char *path = name;
203
regmatch_t matches[10];
204
char* buffer = NULL;
205
size_t i, j;
206
struct subst_rule *rule;
207
struct substitution *subst;
208
int c, got_match, print_match;
209
210
*result = NULL;
211
212
if ((subst = bsdtar->substitution) == NULL)
213
return 0;
214
215
got_match = 0;
216
print_match = 0;
217
218
for (rule = subst->first_rule; rule != NULL; rule = rule->next) {
219
if (symlink_target) {
220
if (!rule->symlink)
221
continue;
222
} else if (hardlink_target) {
223
if (!rule->hardlink)
224
continue;
225
} else { /* Regular filename. */
226
if (!rule->regular)
227
continue;
228
}
229
230
if (rule->from_begin && *result) {
231
realloc_strcat(result, name);
232
if (buffer) buffer[0] = 0;
233
realloc_strcat(&buffer, *result);
234
name = buffer;
235
(*result)[0] = 0;
236
}
237
238
while (1) {
239
if (regexec(&rule->re, name, 10, matches, 0))
240
break;
241
242
got_match = 1;
243
print_match |= rule->print;
244
realloc_strncat(result, name, matches[0].rm_so);
245
246
for (i = 0, j = 0; rule->result[i] != '\0'; ++i) {
247
if (rule->result[i] == '~') {
248
realloc_strncat(result, rule->result + j, i - j);
249
realloc_strncat(result,
250
name + matches[0].rm_so,
251
matches[0].rm_eo - matches[0].rm_so);
252
j = i + 1;
253
continue;
254
}
255
if (rule->result[i] != '\\')
256
continue;
257
258
++i;
259
c = rule->result[i];
260
switch (c) {
261
case '~':
262
case '\\':
263
realloc_strncat(result, rule->result + j, i - j - 1);
264
j = i;
265
break;
266
case '1':
267
case '2':
268
case '3':
269
case '4':
270
case '5':
271
case '6':
272
case '7':
273
case '8':
274
case '9':
275
realloc_strncat(result, rule->result + j, i - j - 1);
276
if ((size_t)(c - '0') > (size_t)(rule->re.re_nsub)) {
277
free(buffer);
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
free(buffer);
305
306
if (print_match)
307
fprintf(stderr, "%s >> %s\n", path, *result);
308
309
return got_match;
310
}
311
312
void
313
cleanup_substitution(struct bsdtar *bsdtar)
314
{
315
struct subst_rule *rule;
316
struct substitution *subst;
317
318
if ((subst = bsdtar->substitution) == NULL)
319
return;
320
321
while ((rule = subst->first_rule) != NULL) {
322
subst->first_rule = rule->next;
323
free(rule->result);
324
regfree(&rule->re);
325
free(rule);
326
}
327
free(subst);
328
}
329
#endif /* defined(HAVE_REGEX_H) || defined(HAVE_PCREPOSIX_H) || defined(HAVE_PCRE2POSIX_H) */
330
331