Blame tar/creation_set.c

Packit 08bd4c
/*-
Packit 08bd4c
 * Copyright (c) 2012 Michihiro NAKAJIMA
Packit 08bd4c
 * All rights reserved.
Packit 08bd4c
 *
Packit 08bd4c
 * Redistribution and use in source and binary forms, with or without
Packit 08bd4c
 * modification, are permitted provided that the following conditions
Packit 08bd4c
 * are met:
Packit 08bd4c
 * 1. Redistributions of source code must retain the above copyright
Packit 08bd4c
 *    notice, this list of conditions and the following disclaimer.
Packit 08bd4c
 * 2. Redistributions in binary form must reproduce the above copyright
Packit 08bd4c
 *    notice, this list of conditions and the following disclaimer in the
Packit 08bd4c
 *    documentation and/or other materials provided with the distribution.
Packit 08bd4c
 *
Packit 08bd4c
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
Packit 08bd4c
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
Packit 08bd4c
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
Packit 08bd4c
 * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
Packit 08bd4c
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
Packit 08bd4c
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
Packit 08bd4c
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
Packit 08bd4c
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
Packit 08bd4c
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
Packit 08bd4c
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Packit 08bd4c
 */
Packit 08bd4c
Packit 08bd4c
#include "bsdtar_platform.h"
Packit 08bd4c
__FBSDID("$FreeBSD$");
Packit 08bd4c
Packit 08bd4c
#ifdef HAVE_STDLIB_H
Packit 08bd4c
#include <stdlib.h>
Packit 08bd4c
#endif
Packit 08bd4c
#ifdef HAVE_STRING_H
Packit 08bd4c
#include <string.h>
Packit 08bd4c
#endif
Packit 08bd4c
Packit 08bd4c
#include "bsdtar.h"
Packit 08bd4c
#include "err.h"
Packit 08bd4c
Packit 08bd4c
struct creation_set {
Packit 08bd4c
	char		 *create_format;
Packit 08bd4c
	struct filter_set {
Packit 08bd4c
		int	  program;	/* Set 1 if filter is a program name */
Packit 08bd4c
		char	 *filter_name;
Packit 08bd4c
	}		 *filters;
Packit 08bd4c
	int		  filter_count;
Packit 08bd4c
};
Packit 08bd4c
Packit 08bd4c
struct suffix_code_t {
Packit 08bd4c
	const char *suffix;
Packit 08bd4c
	const char *form;
Packit 08bd4c
};
Packit 08bd4c
Packit 08bd4c
static const char *
Packit 08bd4c
get_suffix_code(const struct suffix_code_t *tbl, const char *suffix)
Packit 08bd4c
{
Packit 08bd4c
	int i;
Packit 08bd4c
Packit 08bd4c
	if (suffix == NULL)
Packit 08bd4c
		return (NULL);
Packit 08bd4c
	for (i = 0; tbl[i].suffix != NULL; i++) {
Packit 08bd4c
		if (strcmp(tbl[i].suffix, suffix) == 0)
Packit 08bd4c
			return (tbl[i].form);
Packit 08bd4c
	}
Packit 08bd4c
	return (NULL);
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
static const char *
Packit 08bd4c
get_filter_code(const char *suffix)
Packit 08bd4c
{
Packit 08bd4c
	/* A pair of suffix and compression/filter. */
Packit 08bd4c
	static const struct suffix_code_t filters[] = {
Packit 08bd4c
		{ ".Z",		"compress" },
Packit 08bd4c
		{ ".bz2",	"bzip2" },
Packit 08bd4c
		{ ".gz",	"gzip" },
Packit 08bd4c
		{ ".grz",	"grzip" },
Packit 08bd4c
		{ ".lrz",	"lrzip" },
Packit 08bd4c
		{ ".lz",	"lzip" },
Packit 08bd4c
		{ ".lz4",	"lz4" },
Packit 08bd4c
		{ ".lzo",	"lzop" },
Packit 08bd4c
		{ ".lzma",	"lzma" },
Packit 08bd4c
		{ ".uu",	"uuencode" },
Packit 08bd4c
		{ ".xz",	"xz" },
Packit 08bd4c
		{ NULL,		NULL }
Packit 08bd4c
	};
Packit 08bd4c
	
Packit 08bd4c
	return get_suffix_code(filters, suffix);
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
static const char *
Packit 08bd4c
get_format_code(const char *suffix)
Packit 08bd4c
{
Packit 08bd4c
	/* A pair of suffix and format. */
Packit 08bd4c
	static const struct suffix_code_t formats[] = {
Packit 08bd4c
		{ ".7z",	"7zip" },
Packit 08bd4c
		{ ".ar",	"arbsd" },
Packit 08bd4c
		{ ".cpio",	"cpio" },
Packit 08bd4c
		{ ".iso",	"iso9960" },
Packit 08bd4c
		{ ".mtree",	"mtree" },
Packit 08bd4c
		{ ".shar",	"shar" },
Packit 08bd4c
		{ ".tar",	"paxr" },
Packit 08bd4c
		{ ".warc",	"warc" },
Packit 08bd4c
		{ ".xar",	"xar" },
Packit 08bd4c
		{ ".zip",	"zip" },
Packit 08bd4c
		{ NULL,		NULL }
Packit 08bd4c
	};
Packit 08bd4c
Packit 08bd4c
	return get_suffix_code(formats, suffix);
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
static const char *
Packit 08bd4c
decompose_alias(const char *suffix)
Packit 08bd4c
{
Packit 08bd4c
	static const struct suffix_code_t alias[] = {
Packit 08bd4c
		{ ".taz",	".tar.gz" },
Packit 08bd4c
		{ ".tgz",	".tar.gz" },
Packit 08bd4c
		{ ".tbz",	".tar.bz2" },
Packit 08bd4c
		{ ".tbz2",	".tar.bz2" },
Packit 08bd4c
		{ ".tz2",	".tar.bz2" },
Packit 08bd4c
		{ ".tlz",	".tar.lzma" },
Packit 08bd4c
		{ ".txz",	".tar.xz" },
Packit 08bd4c
		{ ".tzo",	".tar.lzo" },
Packit 08bd4c
		{ ".taZ",	".tar.Z" },
Packit 08bd4c
		{ ".tZ",	".tar.Z" },
Packit 08bd4c
		{ NULL,		NULL }
Packit 08bd4c
	};
Packit 08bd4c
Packit 08bd4c
	return get_suffix_code(alias, suffix);
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
static void
Packit 08bd4c
_cset_add_filter(struct creation_set *cset, int program, const char *filter)
Packit 08bd4c
{
Packit 08bd4c
	struct filter_set *new_ptr;
Packit 08bd4c
	char *new_filter;
Packit 08bd4c
Packit 08bd4c
	new_ptr = (struct filter_set *)realloc(cset->filters,
Packit 08bd4c
	    sizeof(*cset->filters) * (cset->filter_count + 1));
Packit 08bd4c
	if (new_ptr == NULL)
Packit 08bd4c
		lafe_errc(1, 0, "No memory");
Packit 08bd4c
	new_filter = strdup(filter);
Packit 08bd4c
	if (new_filter == NULL)
Packit 08bd4c
		lafe_errc(1, 0, "No memory");
Packit 08bd4c
	cset->filters = new_ptr;
Packit 08bd4c
	cset->filters[cset->filter_count].program = program;
Packit 08bd4c
	cset->filters[cset->filter_count].filter_name = new_filter;
Packit 08bd4c
	cset->filter_count++;
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
void
Packit 08bd4c
cset_add_filter(struct creation_set *cset, const char *filter)
Packit 08bd4c
{
Packit 08bd4c
	_cset_add_filter(cset, 0, filter);
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
void
Packit 08bd4c
cset_add_filter_program(struct creation_set *cset, const char *filter)
Packit 08bd4c
{
Packit 08bd4c
	_cset_add_filter(cset, 1, filter);
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
int
Packit 08bd4c
cset_read_support_filter_program(struct creation_set *cset, struct archive *a)
Packit 08bd4c
{
Packit 08bd4c
	int cnt = 0, i;
Packit 08bd4c
Packit 08bd4c
	for (i = 0; i < cset->filter_count; i++) {
Packit 08bd4c
		if (cset->filters[i].program) {
Packit 08bd4c
			archive_read_support_filter_program(a,
Packit 08bd4c
			    cset->filters[i].filter_name);
Packit 08bd4c
			++cnt;
Packit 08bd4c
		}
Packit 08bd4c
	}
Packit 08bd4c
	return (cnt);
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
int
Packit 08bd4c
cset_write_add_filters(struct creation_set *cset, struct archive *a,
Packit 08bd4c
    const void **filter_name)
Packit 08bd4c
{
Packit 08bd4c
	int cnt = 0, i, r;
Packit 08bd4c
Packit 08bd4c
	for (i = 0; i < cset->filter_count; i++) {
Packit 08bd4c
		if (cset->filters[i].program)
Packit 08bd4c
			r = archive_write_add_filter_program(a,
Packit 08bd4c
				cset->filters[i].filter_name);
Packit 08bd4c
		else
Packit 08bd4c
			r = archive_write_add_filter_by_name(a,
Packit 08bd4c
				cset->filters[i].filter_name);
Packit 08bd4c
		if (r < ARCHIVE_WARN) {
Packit 08bd4c
			*filter_name = cset->filters[i].filter_name;
Packit 08bd4c
			return (r);
Packit 08bd4c
		}
Packit 08bd4c
		++cnt;
Packit 08bd4c
	}
Packit 08bd4c
	return (cnt);
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
void
Packit 08bd4c
cset_set_format(struct creation_set *cset, const char *format)
Packit 08bd4c
{
Packit 08bd4c
	char *f;
Packit 08bd4c
Packit 08bd4c
	f = strdup(format);
Packit 08bd4c
	if (f == NULL)
Packit 08bd4c
		lafe_errc(1, 0, "No memory");
Packit 08bd4c
	free(cset->create_format);
Packit 08bd4c
	cset->create_format = f;
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
const char *
Packit 08bd4c
cset_get_format(struct creation_set *cset)
Packit 08bd4c
{
Packit 08bd4c
	return (cset->create_format);
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
static void
Packit 08bd4c
_cleanup_filters(struct filter_set *filters, int count)
Packit 08bd4c
{
Packit 08bd4c
	int i;
Packit 08bd4c
Packit 08bd4c
	for (i = 0; i < count; i++)
Packit 08bd4c
		free(filters[i].filter_name);
Packit 08bd4c
	free(filters);
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
/*
Packit 08bd4c
 * Clean up a creation set.
Packit 08bd4c
 */
Packit 08bd4c
void
Packit 08bd4c
cset_free(struct creation_set *cset)
Packit 08bd4c
{
Packit 08bd4c
	_cleanup_filters(cset->filters, cset->filter_count);
Packit 08bd4c
	free(cset->create_format);
Packit 08bd4c
	free(cset);
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
struct creation_set *
Packit 08bd4c
cset_new(void)
Packit 08bd4c
{
Packit 08bd4c
	return calloc(1, sizeof(struct creation_set));
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
/*
Packit 08bd4c
 * Build a creation set by a file name suffix.
Packit 08bd4c
 */
Packit 08bd4c
int
Packit 08bd4c
cset_auto_compress(struct creation_set *cset, const char *filename)
Packit 08bd4c
{
Packit 08bd4c
	struct filter_set *old_filters;
Packit 08bd4c
	char *name, *p;
Packit 08bd4c
	const char *code;
Packit 08bd4c
	int old_filter_count;
Packit 08bd4c
Packit 08bd4c
	name = strdup(filename);
Packit 08bd4c
	if (name == NULL)
Packit 08bd4c
		lafe_errc(1, 0, "No memory");
Packit 08bd4c
	/* Save previous filters. */
Packit 08bd4c
	old_filters = cset->filters;
Packit 08bd4c
	old_filter_count = cset->filter_count;
Packit 08bd4c
	cset->filters = NULL;
Packit 08bd4c
	cset->filter_count = 0;
Packit 08bd4c
Packit 08bd4c
	for (;;) {
Packit 08bd4c
		/* Get the suffix. */
Packit 08bd4c
		p = strrchr(name, '.');
Packit 08bd4c
		if (p == NULL)
Packit 08bd4c
			break;
Packit 08bd4c
		/* Suppose it indicates compression/filter type
Packit 08bd4c
		 * such as ".gz". */
Packit 08bd4c
		code = get_filter_code(p);
Packit 08bd4c
		if (code != NULL) {
Packit 08bd4c
			cset_add_filter(cset, code);
Packit 08bd4c
			*p = '\0';
Packit 08bd4c
			continue;
Packit 08bd4c
		}
Packit 08bd4c
		/* Suppose it indicates format type such as ".tar". */
Packit 08bd4c
		code = get_format_code(p);
Packit 08bd4c
		if (code != NULL) {
Packit 08bd4c
			cset_set_format(cset, code);
Packit 08bd4c
			break;
Packit 08bd4c
		}
Packit 08bd4c
		/* Suppose it indicates alias such as ".tgz". */
Packit 08bd4c
		code = decompose_alias(p);
Packit 08bd4c
		if (code == NULL)
Packit 08bd4c
			break;
Packit 08bd4c
		/* Replace the suffix. */
Packit 08bd4c
		*p = '\0';
Packit 08bd4c
		name = realloc(name, strlen(name) + strlen(code) + 1);
Packit 08bd4c
		if (name == NULL)
Packit 08bd4c
			lafe_errc(1, 0, "No memory");
Packit 08bd4c
		strcat(name, code);
Packit 08bd4c
	}
Packit 08bd4c
	free(name);
Packit 08bd4c
	if (cset->filters) {
Packit 08bd4c
		struct filter_set *v;
Packit 08bd4c
		int i, r;
Packit 08bd4c
Packit 08bd4c
		/* Release previous filters. */
Packit 08bd4c
		_cleanup_filters(old_filters, old_filter_count);
Packit 08bd4c
Packit 08bd4c
		v = malloc(sizeof(*v) * cset->filter_count);
Packit 08bd4c
		if (v == NULL)
Packit 08bd4c
			lafe_errc(1, 0, "No memory");
Packit 08bd4c
		/* Reverse filter sequence. */
Packit 08bd4c
		for (i = 0, r = cset->filter_count; r > 0; )
Packit 08bd4c
			v[i++] = cset->filters[--r];
Packit 08bd4c
		free(cset->filters);
Packit 08bd4c
		cset->filters = v;
Packit 08bd4c
		return (1);
Packit 08bd4c
	} else {
Packit 08bd4c
		/* Put previous filters back. */
Packit 08bd4c
		cset->filters = old_filters;
Packit 08bd4c
		cset->filter_count = old_filter_count;
Packit 08bd4c
		return (0);
Packit 08bd4c
	}
Packit 08bd4c
}