creation_set.c revision 302408
1153761Swollman/*-
2192886Sedwin * Copyright (c) 2012 Michihiro NAKAJIMA
3192886Sedwin * All rights reserved.
4153761Swollman *
52742Swollman * Redistribution and use in source and binary forms, with or without
686464Swollman * modification, are permitted provided that the following conditions
72742Swollman * are met:
82742Swollman * 1. Redistributions of source code must retain the above copyright
92742Swollman *    notice, this list of conditions and the following disclaimer.
102742Swollman * 2. Redistributions in binary form must reproduce the above copyright
112742Swollman *    notice, this list of conditions and the following disclaimer in the
122742Swollman *    documentation and/or other materials provided with the distribution.
1386222Swollman *
1486222Swollman * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
152742Swollman * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1658787Sru * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
172742Swollman * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
182742Swollman * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
192742Swollman * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
202742Swollman * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
212742Swollman * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
222742Swollman * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2358787Sru * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2458787Sru */
2558787Sru
262742Swollman#include "bsdtar_platform.h"
272742Swollman__FBSDID("$FreeBSD$");
289908Swollman
292742Swollman#ifdef HAVE_STDLIB_H
3030711Swollman#include <stdlib.h>
312742Swollman#endif
329908Swollman#ifdef HAVE_STRING_H
33169811Swollman#include <string.h>
34169811Swollman#endif
35169811Swollman
36169811Swollman#include "bsdtar.h"
37169811Swollman#include "err.h"
38169811Swollman
39169811Swollmanstruct creation_set {
40169811Swollman	char		 *create_format;
41169811Swollman	struct filter_set {
42169811Swollman		int	  program;	/* Set 1 if filter is a program name */
43169811Swollman		char	 *filter_name;
442742Swollman	}		 *filters;
4558787Sru	int		  filter_count;
46169811Swollman};
47169811Swollman
48169811Swollmanstruct suffix_code_t {
49169811Swollman	const char *suffix;
50169811Swollman	const char *form;
519908Swollman};
5220094Swollman
53149514Swollmanstatic const char *
5420094Swollmanget_suffix_code(const struct suffix_code_t *tbl, const char *suffix)
5520094Swollman{
5620094Swollman	int i;
5720094Swollman
5820094Swollman	if (suffix == NULL)
5920094Swollman		return (NULL);
6020094Swollman	for (i = 0; tbl[i].suffix != NULL; i++) {
6120094Swollman		if (strcmp(tbl[i].suffix, suffix) == 0)
6220094Swollman			return (tbl[i].form);
6320094Swollman	}
6420094Swollman	return (NULL);
6558787Sru}
6658787Sru
6721217Swollmanstatic const char *
6821217Swollmanget_filter_code(const char *suffix)
6958787Sru{
7058787Sru	/* A pair of suffix and compression/filter. */
712742Swollman	static const struct suffix_code_t filters[] = {
7258787Sru		{ ".Z",		"compress" },
7321217Swollman		{ ".bz2",	"bzip2" },
7420094Swollman		{ ".gz",	"gzip" },
7558787Sru		{ ".grz",	"grzip" },
7658787Sru		{ ".lrz",	"lrzip" },
7720094Swollman		{ ".lz",	"lzip" },
782742Swollman		{ ".lz4",	"lz4" },
799908Swollman		{ ".lzo",	"lzop" },
802742Swollman		{ ".lzma",	"lzma" },
8114343Swollman		{ ".uu",	"uuencode" },
8214343Swollman		{ ".xz",	"xz" },
83171948Sedwin		{ NULL,		NULL }
8414343Swollman	};
8514343Swollman
86218122Sedwin	return get_suffix_code(filters, suffix);
87218122Sedwin}
88218122Sedwin
89218122Sedwinstatic const char *
90218122Sedwinget_format_code(const char *suffix)
91149514Swollman{
92218122Sedwin	/* A pair of suffix and format. */
93171948Sedwin	static const struct suffix_code_t formats[] = {
94171948Sedwin		{ ".7z",	"7zip" },
95171948Sedwin		{ ".ar",	"arbsd" },
962742Swollman		{ ".cpio",	"cpio" },
972742Swollman		{ ".iso",	"iso9960" },
982742Swollman		{ ".mtree",	"mtree" },
9958787Sru		{ ".shar",	"shar" },
1002742Swollman		{ ".tar",	"paxr" },
1012742Swollman		{ ".warc",	"warc" },
1029908Swollman		{ ".xar",	"xar" },
103149514Swollman		{ ".zip",	"zip" },
104149514Swollman		{ NULL,		NULL }
105149514Swollman	};
106149514Swollman
107149514Swollman	return get_suffix_code(formats, suffix);
1082742Swollman}
10958787Sru
11058787Srustatic const char *
11114343Swollmandecompose_alias(const char *suffix)
11214343Swollman{
11358787Sru	static const struct suffix_code_t alias[] = {
11414343Swollman		{ ".taz",	".tar.gz" },
11514343Swollman		{ ".tgz",	".tar.gz" },
11614343Swollman		{ ".tbz",	".tar.bz2" },
11758787Sru		{ ".tbz2",	".tar.bz2" },
11814343Swollman		{ ".tz2",	".tar.bz2" },
11958787Sru		{ ".tlz",	".tar.lzma" },
12058787Sru		{ ".txz",	".tar.xz" },
12158787Sru		{ ".tzo",	".tar.lzo" },
122149514Swollman		{ ".taZ",	".tar.Z" },
12358787Sru		{ ".tZ",	".tar.Z" },
12458787Sru		{ NULL,		NULL }
125149514Swollman	};
126171948Sedwin
127171948Sedwin	return get_suffix_code(alias, suffix);
1282742Swollman}
1292742Swollman
13058787Srustatic void
13158787Sru_cset_add_filter(struct creation_set *cset, int program, const char *filter)
13258787Sru{
1332742Swollman	struct filter_set *new_ptr;
134149514Swollman	char *new_filter;
135149514Swollman
136149514Swollman	new_ptr = (struct filter_set *)realloc(cset->filters,
137149514Swollman	    sizeof(*cset->filters) * (cset->filter_count + 1));
138149514Swollman	if (new_ptr == NULL)
1392742Swollman		lafe_errc(1, 0, "No memory");
1409908Swollman	new_filter = strdup(filter);
1412742Swollman	if (new_filter == NULL)
14214343Swollman		lafe_errc(1, 0, "No memory");
14358787Sru	cset->filters = new_ptr;
14414343Swollman	cset->filters[cset->filter_count].program = program;
14514343Swollman	cset->filters[cset->filter_count].filter_name = new_filter;
14658787Sru	cset->filter_count++;
14758787Sru}
14814343Swollman
149149514Swollmanvoid
15058787Srucset_add_filter(struct creation_set *cset, const char *filter)
151171948Sedwin{
152149514Swollman	_cset_add_filter(cset, 0, filter);
153171948Sedwin}
154171948Sedwin
155171948Sedwinvoid
1562742Swollmancset_add_filter_program(struct creation_set *cset, const char *filter)
1572742Swollman{
15858787Sru	_cset_add_filter(cset, 1, filter);
1592742Swollman}
1602742Swollman
1619908Swollmanint
1622742Swollmancset_read_support_filter_program(struct creation_set *cset, struct archive *a)
16314343Swollman{
16414343Swollman	int cnt = 0, i;
16514343Swollman
16614343Swollman	for (i = 0; i < cset->filter_count; i++) {
16714343Swollman		if (cset->filters[i].program) {
16814343Swollman			archive_read_support_filter_program(a,
16914343Swollman			    cset->filters[i].filter_name);
17043543Swollman			++cnt;
17114343Swollman		}
172149514Swollman	}
17358787Sru	return (cnt);
174171948Sedwin}
175149514Swollman
176171948Sedwinint
177171948Sedwincset_write_add_filters(struct creation_set *cset, struct archive *a,
178171948Sedwin    const void **filter_name)
1792742Swollman{
1802742Swollman	int cnt = 0, i, r;
18158787Sru
1822742Swollman	for (i = 0; i < cset->filter_count; i++) {
1832742Swollman		if (cset->filters[i].program)
1842742Swollman			r = archive_write_add_filter_program(a,
1852742Swollman				cset->filters[i].filter_name);
18658787Sru		else
18758787Sru			r = archive_write_add_filter_by_name(a,
18858787Sru				cset->filters[i].filter_name);
1898029Swollman		if (r < ARCHIVE_WARN) {
19014343Swollman			*filter_name = cset->filters[i].filter_name;
19114343Swollman			return (r);
19275267Swollman		}
19375267Swollman		++cnt;
19475267Swollman	}
19575267Swollman	return (cnt);
19675267Swollman}
19775267Swollman
19875267Swollmanvoid
199149514Swollmancset_set_format(struct creation_set *cset, const char *format)
20075267Swollman{
201171948Sedwin	char *f;
202149514Swollman
203171948Sedwin	f = strdup(format);
204171948Sedwin	if (f == NULL)
205171948Sedwin		lafe_errc(1, 0, "No memory");
2062742Swollman	free(cset->create_format);
2072742Swollman	cset->create_format = f;
20814343Swollman}
2098029Swollman
21014343Swollmanconst char *
2112742Swollmancset_get_format(struct creation_set *cset)
2122742Swollman{
21314343Swollman	return (cset->create_format);
214169811Swollman}
2152742Swollman
21614343Swollmanstatic void
21714343Swollman_cleanup_filters(struct filter_set *filters, int count)
218169811Swollman{
21914343Swollman	int i;
22030711Swollman
22130711Swollman	for (i = 0; i < count; i++)
22258787Sru		free(filters[i].filter_name);
223169811Swollman	free(filters);
2242742Swollman}
22543014Swollman
22643014Swollman/*
22743014Swollman * Clean up a creation set.
22843014Swollman */
2292742Swollmanvoid
2302742Swollmancset_free(struct creation_set *cset)
231158421Swollman{
2322742Swollman	_cleanup_filters(cset->filters, cset->filter_count);
23319878Swollman	free(cset->create_format);
23443014Swollman	free(cset);
23543014Swollman}
2362742Swollman
2372742Swollmanstruct creation_set *
23819878Swollmancset_new(void)
23919878Swollman{
2402742Swollman	return calloc(1, sizeof(struct creation_set));
2412742Swollman}
242149514Swollman
243149514Swollman/*
2442742Swollman * Build a creation set by a file name suffix.
245149514Swollman */
246149514Swollmanint
2472742Swollmancset_auto_compress(struct creation_set *cset, const char *filename)
2482742Swollman{
249199336Sedwin	struct filter_set *old_filters;
250199336Sedwin	char *name, *p;
251199336Sedwin	const char *code;
252199336Sedwin	int old_filter_count;
253199336Sedwin
254199336Sedwin	name = strdup(filename);
255199336Sedwin	if (name == NULL)
256199336Sedwin		lafe_errc(1, 0, "No memory");
257199336Sedwin	/* Save previous filters. */
258199336Sedwin	old_filters = cset->filters;
259199336Sedwin	old_filter_count = cset->filter_count;
260199336Sedwin	cset->filters = NULL;
261199336Sedwin	cset->filter_count = 0;
262199336Sedwin
263199336Sedwin	for (;;) {
264199336Sedwin		/* Get the suffix. */
265199336Sedwin		p = strrchr(name, '.');
266199336Sedwin		if (p == NULL)
267199336Sedwin			break;
268204887Sedwin		/* Suppose it indicates compression/filter type
269204887Sedwin		 * such as ".gz". */
270204887Sedwin		code = get_filter_code(p);
271204887Sedwin		if (code != NULL) {
272204887Sedwin			cset_add_filter(cset, code);
273204887Sedwin			*p = '\0';
274204887Sedwin			continue;
275204887Sedwin		}
276204887Sedwin		/* Suppose it indicates format type such as ".tar". */
277204887Sedwin		code = get_format_code(p);
278204887Sedwin		if (code != NULL) {
279204887Sedwin			cset_set_format(cset, code);
280204887Sedwin			break;
281204887Sedwin		}
282204887Sedwin		/* Suppose it indicates alias such as ".tgz". */
283204887Sedwin		code = decompose_alias(p);
284204887Sedwin		if (code == NULL)
285214722Sedwin			break;
286240457Sedwin		/* Replace the suffix. */
287214722Sedwin		*p = '\0';
288240457Sedwin		name = realloc(name, strlen(name) + strlen(code) + 1);
289214722Sedwin		if (name == NULL)
290214722Sedwin			lafe_errc(1, 0, "No memory");
291214722Sedwin		strcat(name, code);
292214722Sedwin	}
293214722Sedwin	free(name);
294214722Sedwin	if (cset->filters) {
295214722Sedwin		struct filter_set *v;
296214722Sedwin		int i, r;
297214722Sedwin
298226289Sedwin		/* Release previos filters. */
299240457Sedwin		_cleanup_filters(old_filters, old_filter_count);
300226289Sedwin
301226289Sedwin		v = malloc(sizeof(*v) * cset->filter_count);
302226289Sedwin		if (v == NULL)
303226289Sedwin			lafe_errc(1, 0, "No memory");
304226289Sedwin		/* Reverse filter sequence. */
305226289Sedwin		for (i = 0, r = cset->filter_count; r > 0; )
306240457Sedwin			v[i++] = cset->filters[--r];
307240457Sedwin		free(cset->filters);
308226289Sedwin		cset->filters = v;
309226289Sedwin		return (1);
310226976Sedwin	} else {
311226976Sedwin		/* Put previos filters back. */
312226976Sedwin		cset->filters = old_filters;
313226976Sedwin		cset->filter_count = old_filter_count;
314226976Sedwin		return (0);
315226976Sedwin	}
316226976Sedwin}
317226976Sedwin