Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/libarchive/tar/creation_set.c
39478 views
1
/*-
2
* SPDX-License-Identifier: BSD-2-Clause
3
*
4
* Copyright (c) 2012 Michihiro NAKAJIMA
5
* All rights reserved.
6
*/
7
8
#include "bsdtar_platform.h"
9
10
#ifdef HAVE_STDLIB_H
11
#include <stdlib.h>
12
#endif
13
#ifdef HAVE_STRING_H
14
#include <string.h>
15
#endif
16
17
#include "bsdtar.h"
18
#include "err.h"
19
20
struct creation_set {
21
char *create_format;
22
struct filter_set {
23
int program; /* Set 1 if filter is a program name */
24
char *filter_name;
25
} *filters;
26
int filter_count;
27
};
28
29
struct suffix_code_t {
30
const char *suffix;
31
const char *form;
32
};
33
34
static const char *
35
get_suffix_code(const struct suffix_code_t *tbl, const char *suffix)
36
{
37
int i;
38
39
if (suffix == NULL)
40
return (NULL);
41
for (i = 0; tbl[i].suffix != NULL; i++) {
42
if (strcmp(tbl[i].suffix, suffix) == 0)
43
return (tbl[i].form);
44
}
45
return (NULL);
46
}
47
48
static const char *
49
get_filter_code(const char *suffix)
50
{
51
/* A pair of suffix and compression/filter. */
52
static const struct suffix_code_t filters[] = {
53
{ ".Z", "compress" },
54
{ ".bz2", "bzip2" },
55
{ ".gz", "gzip" },
56
{ ".grz", "grzip" },
57
{ ".lrz", "lrzip" },
58
{ ".lz", "lzip" },
59
{ ".lz4", "lz4" },
60
{ ".lzo", "lzop" },
61
{ ".lzma", "lzma" },
62
{ ".uu", "uuencode" },
63
{ ".xz", "xz" },
64
{ ".zst", "zstd"},
65
{ NULL, NULL }
66
};
67
68
return get_suffix_code(filters, suffix);
69
}
70
71
static const char *
72
get_format_code(const char *suffix)
73
{
74
/* A pair of suffix and format. */
75
static const struct suffix_code_t formats[] = {
76
{ ".7z", "7zip" },
77
{ ".ar", "arbsd" },
78
{ ".cpio", "cpio" },
79
{ ".iso", "iso9660" },
80
{ ".mtree", "mtree" },
81
{ ".shar", "shar" },
82
{ ".tar", "paxr" },
83
{ ".warc", "warc" },
84
{ ".xar", "xar" },
85
{ ".zip", "zip" },
86
{ NULL, NULL }
87
};
88
89
return get_suffix_code(formats, suffix);
90
}
91
92
static const char *
93
decompose_alias(const char *suffix)
94
{
95
static const struct suffix_code_t alias[] = {
96
{ ".taz", ".tar.gz" },
97
{ ".tgz", ".tar.gz" },
98
{ ".tbz", ".tar.bz2" },
99
{ ".tbz2", ".tar.bz2" },
100
{ ".tz2", ".tar.bz2" },
101
{ ".tlz", ".tar.lzma" },
102
{ ".txz", ".tar.xz" },
103
{ ".tzo", ".tar.lzo" },
104
{ ".taZ", ".tar.Z" },
105
{ ".tZ", ".tar.Z" },
106
{ ".tzst", ".tar.zst" },
107
{ NULL, NULL }
108
};
109
110
return get_suffix_code(alias, suffix);
111
}
112
113
static void
114
_cset_add_filter(struct creation_set *cset, int program, const char *filter)
115
{
116
struct filter_set *new_ptr;
117
char *new_filter;
118
119
new_ptr = realloc(cset->filters,
120
sizeof(*cset->filters) * (cset->filter_count + 1));
121
if (new_ptr == NULL)
122
lafe_errc(1, 0, "No memory");
123
new_filter = strdup(filter);
124
if (new_filter == NULL)
125
lafe_errc(1, 0, "No memory");
126
cset->filters = new_ptr;
127
cset->filters[cset->filter_count].program = program;
128
cset->filters[cset->filter_count].filter_name = new_filter;
129
cset->filter_count++;
130
}
131
132
void
133
cset_add_filter(struct creation_set *cset, const char *filter)
134
{
135
_cset_add_filter(cset, 0, filter);
136
}
137
138
void
139
cset_add_filter_program(struct creation_set *cset, const char *filter)
140
{
141
_cset_add_filter(cset, 1, filter);
142
}
143
144
int
145
cset_read_support_filter_program(struct creation_set *cset, struct archive *a)
146
{
147
int cnt = 0, i;
148
149
for (i = 0; i < cset->filter_count; i++) {
150
if (cset->filters[i].program) {
151
archive_read_support_filter_program(a,
152
cset->filters[i].filter_name);
153
++cnt;
154
}
155
}
156
return (cnt);
157
}
158
159
int
160
cset_write_add_filters(struct creation_set *cset, struct archive *a,
161
const void **filter_name)
162
{
163
int cnt = 0, i, r;
164
165
for (i = 0; i < cset->filter_count; i++) {
166
if (cset->filters[i].program)
167
r = archive_write_add_filter_program(a,
168
cset->filters[i].filter_name);
169
else
170
r = archive_write_add_filter_by_name(a,
171
cset->filters[i].filter_name);
172
if (r < ARCHIVE_WARN) {
173
*filter_name = cset->filters[i].filter_name;
174
return (r);
175
}
176
++cnt;
177
}
178
return (cnt);
179
}
180
181
void
182
cset_set_format(struct creation_set *cset, const char *format)
183
{
184
char *f;
185
186
f = strdup(format);
187
if (f == NULL)
188
lafe_errc(1, 0, "No memory");
189
free(cset->create_format);
190
cset->create_format = f;
191
}
192
193
const char *
194
cset_get_format(struct creation_set *cset)
195
{
196
return (cset->create_format);
197
}
198
199
static void
200
_cleanup_filters(struct filter_set *filters, int count)
201
{
202
int i;
203
204
for (i = 0; i < count; i++)
205
free(filters[i].filter_name);
206
free(filters);
207
}
208
209
/*
210
* Clean up a creation set.
211
*/
212
void
213
cset_free(struct creation_set *cset)
214
{
215
_cleanup_filters(cset->filters, cset->filter_count);
216
free(cset->create_format);
217
free(cset);
218
}
219
220
struct creation_set *
221
cset_new(void)
222
{
223
return calloc(1, sizeof(struct creation_set));
224
}
225
226
/*
227
* Build a creation set by a file name suffix.
228
*/
229
int
230
cset_auto_compress(struct creation_set *cset, const char *filename)
231
{
232
struct filter_set *old_filters;
233
char *name, *p;
234
const char *code;
235
int old_filter_count;
236
237
name = strdup(filename);
238
if (name == NULL)
239
lafe_errc(1, 0, "No memory");
240
/* Save previous filters. */
241
old_filters = cset->filters;
242
old_filter_count = cset->filter_count;
243
cset->filters = NULL;
244
cset->filter_count = 0;
245
246
for (;;) {
247
/* Get the suffix. */
248
p = strrchr(name, '.');
249
if (p == NULL)
250
break;
251
/* Suppose it indicates compression/filter type
252
* such as ".gz". */
253
code = get_filter_code(p);
254
if (code != NULL) {
255
cset_add_filter(cset, code);
256
*p = '\0';
257
continue;
258
}
259
/* Suppose it indicates format type such as ".tar". */
260
code = get_format_code(p);
261
if (code != NULL) {
262
cset_set_format(cset, code);
263
break;
264
}
265
/* Suppose it indicates alias such as ".tgz". */
266
code = decompose_alias(p);
267
if (code == NULL)
268
break;
269
/* Replace the suffix. */
270
*p = '\0';
271
name = realloc(name, strlen(name) + strlen(code) + 1);
272
if (name == NULL)
273
lafe_errc(1, 0, "No memory");
274
strcat(name, code);
275
}
276
free(name);
277
if (cset->filters) {
278
struct filter_set *v;
279
int i, r;
280
281
/* Release previous filters. */
282
_cleanup_filters(old_filters, old_filter_count);
283
284
v = malloc(sizeof(*v) * cset->filter_count);
285
if (v == NULL)
286
lafe_errc(1, 0, "No memory");
287
/* Reverse filter sequence. */
288
for (i = 0, r = cset->filter_count; r > 0; )
289
v[i++] = cset->filters[--r];
290
free(cset->filters);
291
cset->filters = v;
292
return (1);
293
} else {
294
/* Put previous filters back. */
295
cset->filters = old_filters;
296
cset->filter_count = old_filter_count;
297
return (0);
298
}
299
}
300
301