creation_set.c revision 303975
1251881Speter/*-
2251881Speter * Copyright (c) 2012 Michihiro NAKAJIMA
3251881Speter * All rights reserved.
4251881Speter *
5251881Speter * Redistribution and use in source and binary forms, with or without
6251881Speter * modification, are permitted provided that the following conditions
7251881Speter * are met:
8251881Speter * 1. Redistributions of source code must retain the above copyright
9251881Speter *    notice, this list of conditions and the following disclaimer.
10251881Speter * 2. Redistributions in binary form must reproduce the above copyright
11251881Speter *    notice, this list of conditions and the following disclaimer in the
12251881Speter *    documentation and/or other materials provided with the distribution.
13251881Speter *
14251881Speter * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
15251881Speter * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16251881Speter * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17251881Speter * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
18251881Speter * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19251881Speter * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20251881Speter * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21251881Speter * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22251881Speter * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23251881Speter * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24251881Speter */
25251881Speter
26251881Speter#include "bsdtar_platform.h"
27251881Speter__FBSDID("$FreeBSD$");
28251881Speter
29251881Speter#ifdef HAVE_STDLIB_H
30251881Speter#include <stdlib.h>
31251881Speter#endif
32251881Speter#ifdef HAVE_STRING_H
33251881Speter#include <string.h>
34251881Speter#endif
35251881Speter
36251881Speter#include "bsdtar.h"
37251881Speter#include "err.h"
38251881Speter
39251881Speterstruct creation_set {
40251881Speter	char		 *create_format;
41251881Speter	struct filter_set {
42251881Speter		int	  program;	/* Set 1 if filter is a program name */
43251881Speter		char	 *filter_name;
44251881Speter	}		 *filters;
45251881Speter	int		  filter_count;
46251881Speter};
47251881Speter
48251881Speterstruct suffix_code_t {
49251881Speter	const char *suffix;
50251881Speter	const char *form;
51251881Speter};
52251881Speter
53251881Speterstatic const char *
54251881Speterget_suffix_code(const struct suffix_code_t *tbl, const char *suffix)
55251881Speter{
56251881Speter	int i;
57251881Speter
58251881Speter	if (suffix == NULL)
59251881Speter		return (NULL);
60251881Speter	for (i = 0; tbl[i].suffix != NULL; i++) {
61251881Speter		if (strcmp(tbl[i].suffix, suffix) == 0)
62251881Speter			return (tbl[i].form);
63251881Speter	}
64251881Speter	return (NULL);
65251881Speter}
66251881Speter
67251881Speterstatic const char *
68251881Speterget_filter_code(const char *suffix)
69251881Speter{
70251881Speter	/* A pair of suffix and compression/filter. */
71251881Speter	static const struct suffix_code_t filters[] = {
72251881Speter		{ ".Z",		"compress" },
73251881Speter		{ ".bz2",	"bzip2" },
74251881Speter		{ ".gz",	"gzip" },
75251881Speter		{ ".grz",	"grzip" },
76251881Speter		{ ".lrz",	"lrzip" },
77251881Speter		{ ".lz",	"lzip" },
78251881Speter		{ ".lz4",	"lz4" },
79251881Speter		{ ".lzo",	"lzop" },
80251881Speter		{ ".lzma",	"lzma" },
81251881Speter		{ ".uu",	"uuencode" },
82251881Speter		{ ".xz",	"xz" },
83251881Speter		{ NULL,		NULL }
84251881Speter	};
85251881Speter
86251881Speter	return get_suffix_code(filters, suffix);
87251881Speter}
88251881Speter
89251881Speterstatic const char *
90251881Speterget_format_code(const char *suffix)
91251881Speter{
92251881Speter	/* A pair of suffix and format. */
93251881Speter	static const struct suffix_code_t formats[] = {
94251881Speter		{ ".7z",	"7zip" },
95251881Speter		{ ".ar",	"arbsd" },
96251881Speter		{ ".cpio",	"cpio" },
97251881Speter		{ ".iso",	"iso9960" },
98251881Speter		{ ".mtree",	"mtree" },
99251881Speter		{ ".shar",	"shar" },
100251881Speter		{ ".tar",	"paxr" },
101251881Speter		{ ".warc",	"warc" },
102251881Speter		{ ".xar",	"xar" },
103251881Speter		{ ".zip",	"zip" },
104251881Speter		{ NULL,		NULL }
105251881Speter	};
106251881Speter
107251881Speter	return get_suffix_code(formats, suffix);
108251881Speter}
109251881Speter
110251881Speterstatic const char *
111251881Speterdecompose_alias(const char *suffix)
112251881Speter{
113251881Speter	static const struct suffix_code_t alias[] = {
114251881Speter		{ ".taz",	".tar.gz" },
115251881Speter		{ ".tgz",	".tar.gz" },
116251881Speter		{ ".tbz",	".tar.bz2" },
117251881Speter		{ ".tbz2",	".tar.bz2" },
118251881Speter		{ ".tz2",	".tar.bz2" },
119251881Speter		{ ".tlz",	".tar.lzma" },
120251881Speter		{ ".txz",	".tar.xz" },
121251881Speter		{ ".tzo",	".tar.lzo" },
122251881Speter		{ ".taZ",	".tar.Z" },
123251881Speter		{ ".tZ",	".tar.Z" },
124251881Speter		{ NULL,		NULL }
125251881Speter	};
126251881Speter
127251881Speter	return get_suffix_code(alias, suffix);
128251881Speter}
129251881Speter
130251881Speterstatic void
131251881Speter_cset_add_filter(struct creation_set *cset, int program, const char *filter)
132251881Speter{
133251881Speter	struct filter_set *new_ptr;
134251881Speter	char *new_filter;
135251881Speter
136251881Speter	new_ptr = (struct filter_set *)realloc(cset->filters,
137251881Speter	    sizeof(*cset->filters) * (cset->filter_count + 1));
138251881Speter	if (new_ptr == NULL)
139251881Speter		lafe_errc(1, 0, "No memory");
140251881Speter	new_filter = strdup(filter);
141251881Speter	if (new_filter == NULL)
142251881Speter		lafe_errc(1, 0, "No memory");
143251881Speter	cset->filters = new_ptr;
144251881Speter	cset->filters[cset->filter_count].program = program;
145251881Speter	cset->filters[cset->filter_count].filter_name = new_filter;
146251881Speter	cset->filter_count++;
147251881Speter}
148251881Speter
149251881Spetervoid
150251881Spetercset_add_filter(struct creation_set *cset, const char *filter)
151251881Speter{
152251881Speter	_cset_add_filter(cset, 0, filter);
153251881Speter}
154251881Speter
155251881Spetervoid
156251881Spetercset_add_filter_program(struct creation_set *cset, const char *filter)
157251881Speter{
158251881Speter	_cset_add_filter(cset, 1, filter);
159251881Speter}
160251881Speter
161251881Speterint
162251881Spetercset_read_support_filter_program(struct creation_set *cset, struct archive *a)
163251881Speter{
164251881Speter	int cnt = 0, i;
165251881Speter
166251881Speter	for (i = 0; i < cset->filter_count; i++) {
167251881Speter		if (cset->filters[i].program) {
168251881Speter			archive_read_support_filter_program(a,
169251881Speter			    cset->filters[i].filter_name);
170251881Speter			++cnt;
171251881Speter		}
172251881Speter	}
173251881Speter	return (cnt);
174251881Speter}
175251881Speter
176251881Speterint
177251881Spetercset_write_add_filters(struct creation_set *cset, struct archive *a,
178251881Speter    const void **filter_name)
179251881Speter{
180251881Speter	int cnt = 0, i, r;
181251881Speter
182251881Speter	for (i = 0; i < cset->filter_count; i++) {
183251881Speter		if (cset->filters[i].program)
184251881Speter			r = archive_write_add_filter_program(a,
185251881Speter				cset->filters[i].filter_name);
186251881Speter		else
187251881Speter			r = archive_write_add_filter_by_name(a,
188251881Speter				cset->filters[i].filter_name);
189251881Speter		if (r < ARCHIVE_WARN) {
190251881Speter			*filter_name = cset->filters[i].filter_name;
191251881Speter			return (r);
192251881Speter		}
193251881Speter		++cnt;
194251881Speter	}
195251881Speter	return (cnt);
196251881Speter}
197251881Speter
198251881Spetervoid
199251881Spetercset_set_format(struct creation_set *cset, const char *format)
200251881Speter{
201251881Speter	char *f;
202251881Speter
203251881Speter	f = strdup(format);
204251881Speter	if (f == NULL)
205251881Speter		lafe_errc(1, 0, "No memory");
206251881Speter	free(cset->create_format);
207251881Speter	cset->create_format = f;
208251881Speter}
209251881Speter
210251881Speterconst char *
211251881Spetercset_get_format(struct creation_set *cset)
212251881Speter{
213251881Speter	return (cset->create_format);
214251881Speter}
215251881Speter
216251881Speterstatic void
217251881Speter_cleanup_filters(struct filter_set *filters, int count)
218251881Speter{
219251881Speter	int i;
220251881Speter
221251881Speter	for (i = 0; i < count; i++)
222251881Speter		free(filters[i].filter_name);
223251881Speter	free(filters);
224251881Speter}
225251881Speter
226251881Speter/*
227251881Speter * Clean up a creation set.
228251881Speter */
229251881Spetervoid
230251881Spetercset_free(struct creation_set *cset)
231251881Speter{
232251881Speter	_cleanup_filters(cset->filters, cset->filter_count);
233251881Speter	free(cset->create_format);
234251881Speter	free(cset);
235251881Speter}
236251881Speter
237251881Speterstruct creation_set *
238251881Spetercset_new(void)
239251881Speter{
240251881Speter	return calloc(1, sizeof(struct creation_set));
241251881Speter}
242251881Speter
243251881Speter/*
244251881Speter * Build a creation set by a file name suffix.
245251881Speter */
246251881Speterint
247251881Spetercset_auto_compress(struct creation_set *cset, const char *filename)
248251881Speter{
249251881Speter	struct filter_set *old_filters;
250251881Speter	char *name, *p;
251251881Speter	const char *code;
252251881Speter	int old_filter_count;
253251881Speter
254251881Speter	name = strdup(filename);
255251881Speter	if (name == NULL)
256251881Speter		lafe_errc(1, 0, "No memory");
257251881Speter	/* Save previous filters. */
258251881Speter	old_filters = cset->filters;
259251881Speter	old_filter_count = cset->filter_count;
260251881Speter	cset->filters = NULL;
261251881Speter	cset->filter_count = 0;
262251881Speter
263251881Speter	for (;;) {
264251881Speter		/* Get the suffix. */
265251881Speter		p = strrchr(name, '.');
266251881Speter		if (p == NULL)
267251881Speter			break;
268251881Speter		/* Suppose it indicates compression/filter type
269251881Speter		 * such as ".gz". */
270251881Speter		code = get_filter_code(p);
271251881Speter		if (code != NULL) {
272251881Speter			cset_add_filter(cset, code);
273251881Speter			*p = '\0';
274251881Speter			continue;
275251881Speter		}
276251881Speter		/* Suppose it indicates format type such as ".tar". */
277251881Speter		code = get_format_code(p);
278251881Speter		if (code != NULL) {
279251881Speter			cset_set_format(cset, code);
280251881Speter			break;
281251881Speter		}
282251881Speter		/* Suppose it indicates alias such as ".tgz". */
283251881Speter		code = decompose_alias(p);
284251881Speter		if (code == NULL)
285251881Speter			break;
286251881Speter		/* Replace the suffix. */
287251881Speter		*p = '\0';
288251881Speter		name = realloc(name, strlen(name) + strlen(code) + 1);
289251881Speter		if (name == NULL)
290251881Speter			lafe_errc(1, 0, "No memory");
291251881Speter		strcat(name, code);
292251881Speter	}
293251881Speter	free(name);
294251881Speter	if (cset->filters) {
295251881Speter		struct filter_set *v;
296251881Speter		int i, r;
297251881Speter
298251881Speter		/* Release previos filters. */
299251881Speter		_cleanup_filters(old_filters, old_filter_count);
300251881Speter
301251881Speter		v = malloc(sizeof(*v) * cset->filter_count);
302251881Speter		if (v == NULL)
303251881Speter			lafe_errc(1, 0, "No memory");
304251881Speter		/* Reverse filter sequence. */
305251881Speter		for (i = 0, r = cset->filter_count; r > 0; )
306251881Speter			v[i++] = cset->filters[--r];
307251881Speter		free(cset->filters);
308251881Speter		cset->filters = v;
309251881Speter		return (1);
310251881Speter	} else {
311251881Speter		/* Put previos filters back. */
312251881Speter		cset->filters = old_filters;
313251881Speter		cset->filter_count = old_filter_count;
314251881Speter		return (0);
315251881Speter	}
316251881Speter}
317251881Speter