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