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