1248590Smm/*- 2248590Smm * Copyright (c) 2012 Michihiro NAKAJIMA 3248590Smm * All rights reserved. 4248590Smm * 5248590Smm * Redistribution and use in source and binary forms, with or without 6248590Smm * modification, are permitted provided that the following conditions 7248590Smm * are met: 8248590Smm * 1. Redistributions of source code must retain the above copyright 9248590Smm * notice, this list of conditions and the following disclaimer. 10248590Smm * 2. Redistributions in binary form must reproduce the above copyright 11248590Smm * notice, this list of conditions and the following disclaimer in the 12248590Smm * documentation and/or other materials provided with the distribution. 13248590Smm * 14248590Smm * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR 15248590Smm * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16248590Smm * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17248590Smm * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, 18248590Smm * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 19248590Smm * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 20248590Smm * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 21248590Smm * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22248590Smm * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 23248590Smm * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24248590Smm */ 25248590Smm 26248590Smm#include "bsdtar_platform.h" 27248590Smm__FBSDID("$FreeBSD$"); 28248590Smm 29248590Smm#ifdef HAVE_STDLIB_H 30248590Smm#include <stdlib.h> 31248590Smm#endif 32248590Smm#ifdef HAVE_STRING_H 33248590Smm#include <string.h> 34248590Smm#endif 35248590Smm 36248590Smm#include "bsdtar.h" 37248590Smm#include "err.h" 38248590Smm 39248590Smmstruct creation_set { 40248590Smm char *create_format; 41248590Smm struct filter_set { 42248590Smm int program; /* Set 1 if filter is a program name */ 43248590Smm char *filter_name; 44248590Smm } *filters; 45248590Smm int filter_count; 46248590Smm}; 47248590Smm 48248590Smmstruct suffix_code_t { 49248590Smm const char *suffix; 50248590Smm const char *form; 51248590Smm}; 52248590Smm 53248590Smmstatic const char * 54248590Smmget_suffix_code(const struct suffix_code_t *tbl, const char *suffix) 55248590Smm{ 56248590Smm int i; 57248590Smm 58248590Smm if (suffix == NULL) 59248590Smm return (NULL); 60248590Smm for (i = 0; tbl[i].suffix != NULL; i++) { 61248590Smm if (strcmp(tbl[i].suffix, suffix) == 0) 62248590Smm return (tbl[i].form); 63248590Smm } 64248590Smm return (NULL); 65248590Smm} 66248590Smm 67248590Smmstatic const char * 68248590Smmget_filter_code(const char *suffix) 69248590Smm{ 70248590Smm /* A pair of suffix and compression/filter. */ 71248590Smm static const struct suffix_code_t filters[] = { 72248590Smm { ".Z", "compress" }, 73248590Smm { ".bz2", "bzip2" }, 74248590Smm { ".gz", "gzip" }, 75248590Smm { ".grz", "grzip" }, 76248590Smm { ".lrz", "lrzip" }, 77248590Smm { ".lz", "lzip" }, 78299529Smm { ".lz4", "lz4" }, 79248590Smm { ".lzo", "lzop" }, 80248590Smm { ".lzma", "lzma" }, 81248590Smm { ".uu", "uuencode" }, 82248590Smm { ".xz", "xz" }, 83324417Smm { ".zst", "zstd"}, 84248590Smm { NULL, NULL } 85248590Smm }; 86324417Smm 87248590Smm return get_suffix_code(filters, suffix); 88248590Smm} 89248590Smm 90248590Smmstatic const char * 91248590Smmget_format_code(const char *suffix) 92248590Smm{ 93248590Smm /* A pair of suffix and format. */ 94248590Smm static const struct suffix_code_t formats[] = { 95248590Smm { ".7z", "7zip" }, 96248590Smm { ".ar", "arbsd" }, 97248590Smm { ".cpio", "cpio" }, 98248590Smm { ".iso", "iso9960" }, 99248590Smm { ".mtree", "mtree" }, 100248590Smm { ".shar", "shar" }, 101248590Smm { ".tar", "paxr" }, 102299529Smm { ".warc", "warc" }, 103248590Smm { ".xar", "xar" }, 104248590Smm { ".zip", "zip" }, 105248590Smm { NULL, NULL } 106248590Smm }; 107248590Smm 108248590Smm return get_suffix_code(formats, suffix); 109248590Smm} 110248590Smm 111248590Smmstatic const char * 112248590Smmdecompose_alias(const char *suffix) 113248590Smm{ 114248590Smm static const struct suffix_code_t alias[] = { 115248590Smm { ".taz", ".tar.gz" }, 116248590Smm { ".tgz", ".tar.gz" }, 117248590Smm { ".tbz", ".tar.bz2" }, 118248590Smm { ".tbz2", ".tar.bz2" }, 119248590Smm { ".tz2", ".tar.bz2" }, 120248590Smm { ".tlz", ".tar.lzma" }, 121248590Smm { ".txz", ".tar.xz" }, 122248590Smm { ".tzo", ".tar.lzo" }, 123248590Smm { ".taZ", ".tar.Z" }, 124248590Smm { ".tZ", ".tar.Z" }, 125324417Smm { ".tzst", ".tar.zst" }, 126248590Smm { NULL, NULL } 127248590Smm }; 128248590Smm 129248590Smm return get_suffix_code(alias, suffix); 130248590Smm} 131248590Smm 132248590Smmstatic void 133248590Smm_cset_add_filter(struct creation_set *cset, int program, const char *filter) 134248590Smm{ 135248590Smm struct filter_set *new_ptr; 136248590Smm char *new_filter; 137248590Smm 138248590Smm new_ptr = (struct filter_set *)realloc(cset->filters, 139248590Smm sizeof(*cset->filters) * (cset->filter_count + 1)); 140248590Smm if (new_ptr == NULL) 141248590Smm lafe_errc(1, 0, "No memory"); 142248590Smm new_filter = strdup(filter); 143248590Smm if (new_filter == NULL) 144248590Smm lafe_errc(1, 0, "No memory"); 145248590Smm cset->filters = new_ptr; 146248590Smm cset->filters[cset->filter_count].program = program; 147248590Smm cset->filters[cset->filter_count].filter_name = new_filter; 148248590Smm cset->filter_count++; 149248590Smm} 150248590Smm 151248590Smmvoid 152248590Smmcset_add_filter(struct creation_set *cset, const char *filter) 153248590Smm{ 154248590Smm _cset_add_filter(cset, 0, filter); 155248590Smm} 156248590Smm 157248590Smmvoid 158248590Smmcset_add_filter_program(struct creation_set *cset, const char *filter) 159248590Smm{ 160248590Smm _cset_add_filter(cset, 1, filter); 161248590Smm} 162248590Smm 163248590Smmint 164248590Smmcset_read_support_filter_program(struct creation_set *cset, struct archive *a) 165248590Smm{ 166248590Smm int cnt = 0, i; 167248590Smm 168248590Smm for (i = 0; i < cset->filter_count; i++) { 169248590Smm if (cset->filters[i].program) { 170248590Smm archive_read_support_filter_program(a, 171248590Smm cset->filters[i].filter_name); 172248590Smm ++cnt; 173248590Smm } 174248590Smm } 175248590Smm return (cnt); 176248590Smm} 177248590Smm 178248590Smmint 179248590Smmcset_write_add_filters(struct creation_set *cset, struct archive *a, 180248590Smm const void **filter_name) 181248590Smm{ 182248590Smm int cnt = 0, i, r; 183248590Smm 184248590Smm for (i = 0; i < cset->filter_count; i++) { 185248590Smm if (cset->filters[i].program) 186248590Smm r = archive_write_add_filter_program(a, 187248590Smm cset->filters[i].filter_name); 188248590Smm else 189248590Smm r = archive_write_add_filter_by_name(a, 190248590Smm cset->filters[i].filter_name); 191248590Smm if (r < ARCHIVE_WARN) { 192248590Smm *filter_name = cset->filters[i].filter_name; 193248590Smm return (r); 194248590Smm } 195248590Smm ++cnt; 196248590Smm } 197248590Smm return (cnt); 198248590Smm} 199248590Smm 200248590Smmvoid 201248590Smmcset_set_format(struct creation_set *cset, const char *format) 202248590Smm{ 203248590Smm char *f; 204248590Smm 205248590Smm f = strdup(format); 206248590Smm if (f == NULL) 207248590Smm lafe_errc(1, 0, "No memory"); 208248590Smm free(cset->create_format); 209248590Smm cset->create_format = f; 210248590Smm} 211248590Smm 212248590Smmconst char * 213248590Smmcset_get_format(struct creation_set *cset) 214248590Smm{ 215248590Smm return (cset->create_format); 216248590Smm} 217248590Smm 218248590Smmstatic void 219248590Smm_cleanup_filters(struct filter_set *filters, int count) 220248590Smm{ 221248590Smm int i; 222248590Smm 223248590Smm for (i = 0; i < count; i++) 224248590Smm free(filters[i].filter_name); 225248590Smm free(filters); 226248590Smm} 227248590Smm 228248590Smm/* 229248590Smm * Clean up a creation set. 230248590Smm */ 231248590Smmvoid 232248590Smmcset_free(struct creation_set *cset) 233248590Smm{ 234248590Smm _cleanup_filters(cset->filters, cset->filter_count); 235248590Smm free(cset->create_format); 236248590Smm free(cset); 237248590Smm} 238248590Smm 239248590Smmstruct creation_set * 240248590Smmcset_new(void) 241248590Smm{ 242248590Smm return calloc(1, sizeof(struct creation_set)); 243248590Smm} 244248590Smm 245248590Smm/* 246248590Smm * Build a creation set by a file name suffix. 247248590Smm */ 248248590Smmint 249248590Smmcset_auto_compress(struct creation_set *cset, const char *filename) 250248590Smm{ 251248590Smm struct filter_set *old_filters; 252248590Smm char *name, *p; 253248590Smm const char *code; 254248590Smm int old_filter_count; 255248590Smm 256248590Smm name = strdup(filename); 257248590Smm if (name == NULL) 258248590Smm lafe_errc(1, 0, "No memory"); 259248590Smm /* Save previous filters. */ 260248590Smm old_filters = cset->filters; 261248590Smm old_filter_count = cset->filter_count; 262248590Smm cset->filters = NULL; 263248590Smm cset->filter_count = 0; 264248590Smm 265248590Smm for (;;) { 266248590Smm /* Get the suffix. */ 267248590Smm p = strrchr(name, '.'); 268248590Smm if (p == NULL) 269248590Smm break; 270248590Smm /* Suppose it indicates compression/filter type 271248590Smm * such as ".gz". */ 272248590Smm code = get_filter_code(p); 273248590Smm if (code != NULL) { 274248590Smm cset_add_filter(cset, code); 275248590Smm *p = '\0'; 276248590Smm continue; 277248590Smm } 278248590Smm /* Suppose it indicates format type such as ".tar". */ 279248590Smm code = get_format_code(p); 280248590Smm if (code != NULL) { 281248590Smm cset_set_format(cset, code); 282248590Smm break; 283248590Smm } 284248590Smm /* Suppose it indicates alias such as ".tgz". */ 285248590Smm code = decompose_alias(p); 286248590Smm if (code == NULL) 287248590Smm break; 288248590Smm /* Replace the suffix. */ 289248590Smm *p = '\0'; 290248590Smm name = realloc(name, strlen(name) + strlen(code) + 1); 291248590Smm if (name == NULL) 292248590Smm lafe_errc(1, 0, "No memory"); 293248590Smm strcat(name, code); 294248590Smm } 295248590Smm free(name); 296248590Smm if (cset->filters) { 297248590Smm struct filter_set *v; 298248590Smm int i, r; 299248590Smm 300311041Smm /* Release previous filters. */ 301248590Smm _cleanup_filters(old_filters, old_filter_count); 302248590Smm 303248590Smm v = malloc(sizeof(*v) * cset->filter_count); 304248590Smm if (v == NULL) 305248590Smm lafe_errc(1, 0, "No memory"); 306248590Smm /* Reverse filter sequence. */ 307248590Smm for (i = 0, r = cset->filter_count; r > 0; ) 308248590Smm v[i++] = cset->filters[--r]; 309248590Smm free(cset->filters); 310248590Smm cset->filters = v; 311248590Smm return (1); 312248590Smm } else { 313311041Smm /* Put previous filters back. */ 314248590Smm cset->filters = old_filters; 315248590Smm cset->filter_count = old_filter_count; 316248590Smm return (0); 317248590Smm } 318248590Smm} 319