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