1acc60b03SMartin Matuska /*- 2*bd66c1b4SMartin Matuska * SPDX-License-Identifier: BSD-2-Clause 3*bd66c1b4SMartin Matuska * 4acc60b03SMartin Matuska * Copyright (c) 2012 Michihiro NAKAJIMA 5acc60b03SMartin Matuska * All rights reserved. 6acc60b03SMartin Matuska */ 7acc60b03SMartin Matuska 8acc60b03SMartin Matuska #include "bsdtar_platform.h" 9acc60b03SMartin Matuska 10acc60b03SMartin Matuska #ifdef HAVE_STDLIB_H 11acc60b03SMartin Matuska #include <stdlib.h> 12acc60b03SMartin Matuska #endif 13acc60b03SMartin Matuska #ifdef HAVE_STRING_H 14acc60b03SMartin Matuska #include <string.h> 15acc60b03SMartin Matuska #endif 16acc60b03SMartin Matuska 17acc60b03SMartin Matuska #include "bsdtar.h" 18acc60b03SMartin Matuska #include "err.h" 19acc60b03SMartin Matuska 20acc60b03SMartin Matuska struct creation_set { 21acc60b03SMartin Matuska char *create_format; 22acc60b03SMartin Matuska struct filter_set { 23acc60b03SMartin Matuska int program; /* Set 1 if filter is a program name */ 24acc60b03SMartin Matuska char *filter_name; 25acc60b03SMartin Matuska } *filters; 26acc60b03SMartin Matuska int filter_count; 27acc60b03SMartin Matuska }; 28acc60b03SMartin Matuska 29acc60b03SMartin Matuska struct suffix_code_t { 30acc60b03SMartin Matuska const char *suffix; 31acc60b03SMartin Matuska const char *form; 32acc60b03SMartin Matuska }; 33acc60b03SMartin Matuska 34acc60b03SMartin Matuska static const char * 35acc60b03SMartin Matuska get_suffix_code(const struct suffix_code_t *tbl, const char *suffix) 36acc60b03SMartin Matuska { 37acc60b03SMartin Matuska int i; 38acc60b03SMartin Matuska 39acc60b03SMartin Matuska if (suffix == NULL) 40acc60b03SMartin Matuska return (NULL); 41acc60b03SMartin Matuska for (i = 0; tbl[i].suffix != NULL; i++) { 42acc60b03SMartin Matuska if (strcmp(tbl[i].suffix, suffix) == 0) 43acc60b03SMartin Matuska return (tbl[i].form); 44acc60b03SMartin Matuska } 45acc60b03SMartin Matuska return (NULL); 46acc60b03SMartin Matuska } 47acc60b03SMartin Matuska 48acc60b03SMartin Matuska static const char * 49acc60b03SMartin Matuska get_filter_code(const char *suffix) 50acc60b03SMartin Matuska { 51acc60b03SMartin Matuska /* A pair of suffix and compression/filter. */ 52acc60b03SMartin Matuska static const struct suffix_code_t filters[] = { 53acc60b03SMartin Matuska { ".Z", "compress" }, 54acc60b03SMartin Matuska { ".bz2", "bzip2" }, 55acc60b03SMartin Matuska { ".gz", "gzip" }, 56acc60b03SMartin Matuska { ".grz", "grzip" }, 57acc60b03SMartin Matuska { ".lrz", "lrzip" }, 58acc60b03SMartin Matuska { ".lz", "lzip" }, 59cdf63a70SMartin Matuska { ".lz4", "lz4" }, 60acc60b03SMartin Matuska { ".lzo", "lzop" }, 61acc60b03SMartin Matuska { ".lzma", "lzma" }, 62acc60b03SMartin Matuska { ".uu", "uuencode" }, 63acc60b03SMartin Matuska { ".xz", "xz" }, 645c831a5bSMartin Matuska { ".zst", "zstd"}, 65acc60b03SMartin Matuska { NULL, NULL } 66acc60b03SMartin Matuska }; 67acc60b03SMartin Matuska 68acc60b03SMartin Matuska return get_suffix_code(filters, suffix); 69acc60b03SMartin Matuska } 70acc60b03SMartin Matuska 71acc60b03SMartin Matuska static const char * 72acc60b03SMartin Matuska get_format_code(const char *suffix) 73acc60b03SMartin Matuska { 74acc60b03SMartin Matuska /* A pair of suffix and format. */ 75acc60b03SMartin Matuska static const struct suffix_code_t formats[] = { 76acc60b03SMartin Matuska { ".7z", "7zip" }, 77acc60b03SMartin Matuska { ".ar", "arbsd" }, 78acc60b03SMartin Matuska { ".cpio", "cpio" }, 79833a452eSMartin Matuska { ".iso", "iso9660" }, 80acc60b03SMartin Matuska { ".mtree", "mtree" }, 81acc60b03SMartin Matuska { ".shar", "shar" }, 82acc60b03SMartin Matuska { ".tar", "paxr" }, 83cdf63a70SMartin Matuska { ".warc", "warc" }, 84acc60b03SMartin Matuska { ".xar", "xar" }, 85acc60b03SMartin Matuska { ".zip", "zip" }, 86acc60b03SMartin Matuska { NULL, NULL } 87acc60b03SMartin Matuska }; 88acc60b03SMartin Matuska 89acc60b03SMartin Matuska return get_suffix_code(formats, suffix); 90acc60b03SMartin Matuska } 91acc60b03SMartin Matuska 92acc60b03SMartin Matuska static const char * 93acc60b03SMartin Matuska decompose_alias(const char *suffix) 94acc60b03SMartin Matuska { 95acc60b03SMartin Matuska static const struct suffix_code_t alias[] = { 96acc60b03SMartin Matuska { ".taz", ".tar.gz" }, 97acc60b03SMartin Matuska { ".tgz", ".tar.gz" }, 98acc60b03SMartin Matuska { ".tbz", ".tar.bz2" }, 99acc60b03SMartin Matuska { ".tbz2", ".tar.bz2" }, 100acc60b03SMartin Matuska { ".tz2", ".tar.bz2" }, 101acc60b03SMartin Matuska { ".tlz", ".tar.lzma" }, 102acc60b03SMartin Matuska { ".txz", ".tar.xz" }, 103acc60b03SMartin Matuska { ".tzo", ".tar.lzo" }, 104acc60b03SMartin Matuska { ".taZ", ".tar.Z" }, 105acc60b03SMartin Matuska { ".tZ", ".tar.Z" }, 1065c831a5bSMartin Matuska { ".tzst", ".tar.zst" }, 107acc60b03SMartin Matuska { NULL, NULL } 108acc60b03SMartin Matuska }; 109acc60b03SMartin Matuska 110acc60b03SMartin Matuska return get_suffix_code(alias, suffix); 111acc60b03SMartin Matuska } 112acc60b03SMartin Matuska 113acc60b03SMartin Matuska static void 114acc60b03SMartin Matuska _cset_add_filter(struct creation_set *cset, int program, const char *filter) 115acc60b03SMartin Matuska { 116acc60b03SMartin Matuska struct filter_set *new_ptr; 117acc60b03SMartin Matuska char *new_filter; 118acc60b03SMartin Matuska 119*bd66c1b4SMartin Matuska new_ptr = realloc(cset->filters, 120acc60b03SMartin Matuska sizeof(*cset->filters) * (cset->filter_count + 1)); 121acc60b03SMartin Matuska if (new_ptr == NULL) 122acc60b03SMartin Matuska lafe_errc(1, 0, "No memory"); 123acc60b03SMartin Matuska new_filter = strdup(filter); 124acc60b03SMartin Matuska if (new_filter == NULL) 125acc60b03SMartin Matuska lafe_errc(1, 0, "No memory"); 126acc60b03SMartin Matuska cset->filters = new_ptr; 127acc60b03SMartin Matuska cset->filters[cset->filter_count].program = program; 128acc60b03SMartin Matuska cset->filters[cset->filter_count].filter_name = new_filter; 129acc60b03SMartin Matuska cset->filter_count++; 130acc60b03SMartin Matuska } 131acc60b03SMartin Matuska 132acc60b03SMartin Matuska void 133acc60b03SMartin Matuska cset_add_filter(struct creation_set *cset, const char *filter) 134acc60b03SMartin Matuska { 135acc60b03SMartin Matuska _cset_add_filter(cset, 0, filter); 136acc60b03SMartin Matuska } 137acc60b03SMartin Matuska 138acc60b03SMartin Matuska void 139acc60b03SMartin Matuska cset_add_filter_program(struct creation_set *cset, const char *filter) 140acc60b03SMartin Matuska { 141acc60b03SMartin Matuska _cset_add_filter(cset, 1, filter); 142acc60b03SMartin Matuska } 143acc60b03SMartin Matuska 144acc60b03SMartin Matuska int 145acc60b03SMartin Matuska cset_read_support_filter_program(struct creation_set *cset, struct archive *a) 146acc60b03SMartin Matuska { 147acc60b03SMartin Matuska int cnt = 0, i; 148acc60b03SMartin Matuska 149acc60b03SMartin Matuska for (i = 0; i < cset->filter_count; i++) { 150acc60b03SMartin Matuska if (cset->filters[i].program) { 151acc60b03SMartin Matuska archive_read_support_filter_program(a, 152acc60b03SMartin Matuska cset->filters[i].filter_name); 153acc60b03SMartin Matuska ++cnt; 154acc60b03SMartin Matuska } 155acc60b03SMartin Matuska } 156acc60b03SMartin Matuska return (cnt); 157acc60b03SMartin Matuska } 158acc60b03SMartin Matuska 159acc60b03SMartin Matuska int 160acc60b03SMartin Matuska cset_write_add_filters(struct creation_set *cset, struct archive *a, 161acc60b03SMartin Matuska const void **filter_name) 162acc60b03SMartin Matuska { 163acc60b03SMartin Matuska int cnt = 0, i, r; 164acc60b03SMartin Matuska 165acc60b03SMartin Matuska for (i = 0; i < cset->filter_count; i++) { 166acc60b03SMartin Matuska if (cset->filters[i].program) 167acc60b03SMartin Matuska r = archive_write_add_filter_program(a, 168acc60b03SMartin Matuska cset->filters[i].filter_name); 169acc60b03SMartin Matuska else 170acc60b03SMartin Matuska r = archive_write_add_filter_by_name(a, 171acc60b03SMartin Matuska cset->filters[i].filter_name); 172acc60b03SMartin Matuska if (r < ARCHIVE_WARN) { 173acc60b03SMartin Matuska *filter_name = cset->filters[i].filter_name; 174acc60b03SMartin Matuska return (r); 175acc60b03SMartin Matuska } 176acc60b03SMartin Matuska ++cnt; 177acc60b03SMartin Matuska } 178acc60b03SMartin Matuska return (cnt); 179acc60b03SMartin Matuska } 180acc60b03SMartin Matuska 181acc60b03SMartin Matuska void 182acc60b03SMartin Matuska cset_set_format(struct creation_set *cset, const char *format) 183acc60b03SMartin Matuska { 184acc60b03SMartin Matuska char *f; 185acc60b03SMartin Matuska 186acc60b03SMartin Matuska f = strdup(format); 187acc60b03SMartin Matuska if (f == NULL) 188acc60b03SMartin Matuska lafe_errc(1, 0, "No memory"); 189acc60b03SMartin Matuska free(cset->create_format); 190acc60b03SMartin Matuska cset->create_format = f; 191acc60b03SMartin Matuska } 192acc60b03SMartin Matuska 193acc60b03SMartin Matuska const char * 194acc60b03SMartin Matuska cset_get_format(struct creation_set *cset) 195acc60b03SMartin Matuska { 196acc60b03SMartin Matuska return (cset->create_format); 197acc60b03SMartin Matuska } 198acc60b03SMartin Matuska 199acc60b03SMartin Matuska static void 200acc60b03SMartin Matuska _cleanup_filters(struct filter_set *filters, int count) 201acc60b03SMartin Matuska { 202acc60b03SMartin Matuska int i; 203acc60b03SMartin Matuska 204acc60b03SMartin Matuska for (i = 0; i < count; i++) 205acc60b03SMartin Matuska free(filters[i].filter_name); 206acc60b03SMartin Matuska free(filters); 207acc60b03SMartin Matuska } 208acc60b03SMartin Matuska 209acc60b03SMartin Matuska /* 210acc60b03SMartin Matuska * Clean up a creation set. 211acc60b03SMartin Matuska */ 212acc60b03SMartin Matuska void 213acc60b03SMartin Matuska cset_free(struct creation_set *cset) 214acc60b03SMartin Matuska { 215acc60b03SMartin Matuska _cleanup_filters(cset->filters, cset->filter_count); 216acc60b03SMartin Matuska free(cset->create_format); 217acc60b03SMartin Matuska free(cset); 218acc60b03SMartin Matuska } 219acc60b03SMartin Matuska 220acc60b03SMartin Matuska struct creation_set * 221acc60b03SMartin Matuska cset_new(void) 222acc60b03SMartin Matuska { 223acc60b03SMartin Matuska return calloc(1, sizeof(struct creation_set)); 224acc60b03SMartin Matuska } 225acc60b03SMartin Matuska 226acc60b03SMartin Matuska /* 227acc60b03SMartin Matuska * Build a creation set by a file name suffix. 228acc60b03SMartin Matuska */ 229acc60b03SMartin Matuska int 230acc60b03SMartin Matuska cset_auto_compress(struct creation_set *cset, const char *filename) 231acc60b03SMartin Matuska { 232acc60b03SMartin Matuska struct filter_set *old_filters; 233acc60b03SMartin Matuska char *name, *p; 234acc60b03SMartin Matuska const char *code; 235acc60b03SMartin Matuska int old_filter_count; 236acc60b03SMartin Matuska 237acc60b03SMartin Matuska name = strdup(filename); 238acc60b03SMartin Matuska if (name == NULL) 239acc60b03SMartin Matuska lafe_errc(1, 0, "No memory"); 240acc60b03SMartin Matuska /* Save previous filters. */ 241acc60b03SMartin Matuska old_filters = cset->filters; 242acc60b03SMartin Matuska old_filter_count = cset->filter_count; 243acc60b03SMartin Matuska cset->filters = NULL; 244acc60b03SMartin Matuska cset->filter_count = 0; 245acc60b03SMartin Matuska 246acc60b03SMartin Matuska for (;;) { 247acc60b03SMartin Matuska /* Get the suffix. */ 248acc60b03SMartin Matuska p = strrchr(name, '.'); 249acc60b03SMartin Matuska if (p == NULL) 250acc60b03SMartin Matuska break; 251acc60b03SMartin Matuska /* Suppose it indicates compression/filter type 252acc60b03SMartin Matuska * such as ".gz". */ 253acc60b03SMartin Matuska code = get_filter_code(p); 254acc60b03SMartin Matuska if (code != NULL) { 255acc60b03SMartin Matuska cset_add_filter(cset, code); 256acc60b03SMartin Matuska *p = '\0'; 257acc60b03SMartin Matuska continue; 258acc60b03SMartin Matuska } 259acc60b03SMartin Matuska /* Suppose it indicates format type such as ".tar". */ 260acc60b03SMartin Matuska code = get_format_code(p); 261acc60b03SMartin Matuska if (code != NULL) { 262acc60b03SMartin Matuska cset_set_format(cset, code); 263acc60b03SMartin Matuska break; 264acc60b03SMartin Matuska } 265acc60b03SMartin Matuska /* Suppose it indicates alias such as ".tgz". */ 266acc60b03SMartin Matuska code = decompose_alias(p); 267acc60b03SMartin Matuska if (code == NULL) 268acc60b03SMartin Matuska break; 269acc60b03SMartin Matuska /* Replace the suffix. */ 270acc60b03SMartin Matuska *p = '\0'; 271acc60b03SMartin Matuska name = realloc(name, strlen(name) + strlen(code) + 1); 272acc60b03SMartin Matuska if (name == NULL) 273acc60b03SMartin Matuska lafe_errc(1, 0, "No memory"); 274acc60b03SMartin Matuska strcat(name, code); 275acc60b03SMartin Matuska } 276acc60b03SMartin Matuska free(name); 277acc60b03SMartin Matuska if (cset->filters) { 278acc60b03SMartin Matuska struct filter_set *v; 279acc60b03SMartin Matuska int i, r; 280acc60b03SMartin Matuska 281007dbc1fSMartin Matuska /* Release previous filters. */ 282acc60b03SMartin Matuska _cleanup_filters(old_filters, old_filter_count); 283acc60b03SMartin Matuska 284acc60b03SMartin Matuska v = malloc(sizeof(*v) * cset->filter_count); 285acc60b03SMartin Matuska if (v == NULL) 286acc60b03SMartin Matuska lafe_errc(1, 0, "No memory"); 287acc60b03SMartin Matuska /* Reverse filter sequence. */ 288acc60b03SMartin Matuska for (i = 0, r = cset->filter_count; r > 0; ) 289acc60b03SMartin Matuska v[i++] = cset->filters[--r]; 290acc60b03SMartin Matuska free(cset->filters); 291acc60b03SMartin Matuska cset->filters = v; 292acc60b03SMartin Matuska return (1); 293acc60b03SMartin Matuska } else { 294007dbc1fSMartin Matuska /* Put previous filters back. */ 295acc60b03SMartin Matuska cset->filters = old_filters; 296acc60b03SMartin Matuska cset->filter_count = old_filter_count; 297acc60b03SMartin Matuska return (0); 298acc60b03SMartin Matuska } 299acc60b03SMartin Matuska } 300