Path: blob/main/contrib/libarchive/tar/creation_set.c
39478 views
/*-1* SPDX-License-Identifier: BSD-2-Clause2*3* Copyright (c) 2012 Michihiro NAKAJIMA4* All rights reserved.5*/67#include "bsdtar_platform.h"89#ifdef HAVE_STDLIB_H10#include <stdlib.h>11#endif12#ifdef HAVE_STRING_H13#include <string.h>14#endif1516#include "bsdtar.h"17#include "err.h"1819struct creation_set {20char *create_format;21struct filter_set {22int program; /* Set 1 if filter is a program name */23char *filter_name;24} *filters;25int filter_count;26};2728struct suffix_code_t {29const char *suffix;30const char *form;31};3233static const char *34get_suffix_code(const struct suffix_code_t *tbl, const char *suffix)35{36int i;3738if (suffix == NULL)39return (NULL);40for (i = 0; tbl[i].suffix != NULL; i++) {41if (strcmp(tbl[i].suffix, suffix) == 0)42return (tbl[i].form);43}44return (NULL);45}4647static const char *48get_filter_code(const char *suffix)49{50/* A pair of suffix and compression/filter. */51static const struct suffix_code_t filters[] = {52{ ".Z", "compress" },53{ ".bz2", "bzip2" },54{ ".gz", "gzip" },55{ ".grz", "grzip" },56{ ".lrz", "lrzip" },57{ ".lz", "lzip" },58{ ".lz4", "lz4" },59{ ".lzo", "lzop" },60{ ".lzma", "lzma" },61{ ".uu", "uuencode" },62{ ".xz", "xz" },63{ ".zst", "zstd"},64{ NULL, NULL }65};6667return get_suffix_code(filters, suffix);68}6970static const char *71get_format_code(const char *suffix)72{73/* A pair of suffix and format. */74static const struct suffix_code_t formats[] = {75{ ".7z", "7zip" },76{ ".ar", "arbsd" },77{ ".cpio", "cpio" },78{ ".iso", "iso9660" },79{ ".mtree", "mtree" },80{ ".shar", "shar" },81{ ".tar", "paxr" },82{ ".warc", "warc" },83{ ".xar", "xar" },84{ ".zip", "zip" },85{ NULL, NULL }86};8788return get_suffix_code(formats, suffix);89}9091static const char *92decompose_alias(const char *suffix)93{94static const struct suffix_code_t alias[] = {95{ ".taz", ".tar.gz" },96{ ".tgz", ".tar.gz" },97{ ".tbz", ".tar.bz2" },98{ ".tbz2", ".tar.bz2" },99{ ".tz2", ".tar.bz2" },100{ ".tlz", ".tar.lzma" },101{ ".txz", ".tar.xz" },102{ ".tzo", ".tar.lzo" },103{ ".taZ", ".tar.Z" },104{ ".tZ", ".tar.Z" },105{ ".tzst", ".tar.zst" },106{ NULL, NULL }107};108109return get_suffix_code(alias, suffix);110}111112static void113_cset_add_filter(struct creation_set *cset, int program, const char *filter)114{115struct filter_set *new_ptr;116char *new_filter;117118new_ptr = realloc(cset->filters,119sizeof(*cset->filters) * (cset->filter_count + 1));120if (new_ptr == NULL)121lafe_errc(1, 0, "No memory");122new_filter = strdup(filter);123if (new_filter == NULL)124lafe_errc(1, 0, "No memory");125cset->filters = new_ptr;126cset->filters[cset->filter_count].program = program;127cset->filters[cset->filter_count].filter_name = new_filter;128cset->filter_count++;129}130131void132cset_add_filter(struct creation_set *cset, const char *filter)133{134_cset_add_filter(cset, 0, filter);135}136137void138cset_add_filter_program(struct creation_set *cset, const char *filter)139{140_cset_add_filter(cset, 1, filter);141}142143int144cset_read_support_filter_program(struct creation_set *cset, struct archive *a)145{146int cnt = 0, i;147148for (i = 0; i < cset->filter_count; i++) {149if (cset->filters[i].program) {150archive_read_support_filter_program(a,151cset->filters[i].filter_name);152++cnt;153}154}155return (cnt);156}157158int159cset_write_add_filters(struct creation_set *cset, struct archive *a,160const void **filter_name)161{162int cnt = 0, i, r;163164for (i = 0; i < cset->filter_count; i++) {165if (cset->filters[i].program)166r = archive_write_add_filter_program(a,167cset->filters[i].filter_name);168else169r = archive_write_add_filter_by_name(a,170cset->filters[i].filter_name);171if (r < ARCHIVE_WARN) {172*filter_name = cset->filters[i].filter_name;173return (r);174}175++cnt;176}177return (cnt);178}179180void181cset_set_format(struct creation_set *cset, const char *format)182{183char *f;184185f = strdup(format);186if (f == NULL)187lafe_errc(1, 0, "No memory");188free(cset->create_format);189cset->create_format = f;190}191192const char *193cset_get_format(struct creation_set *cset)194{195return (cset->create_format);196}197198static void199_cleanup_filters(struct filter_set *filters, int count)200{201int i;202203for (i = 0; i < count; i++)204free(filters[i].filter_name);205free(filters);206}207208/*209* Clean up a creation set.210*/211void212cset_free(struct creation_set *cset)213{214_cleanup_filters(cset->filters, cset->filter_count);215free(cset->create_format);216free(cset);217}218219struct creation_set *220cset_new(void)221{222return calloc(1, sizeof(struct creation_set));223}224225/*226* Build a creation set by a file name suffix.227*/228int229cset_auto_compress(struct creation_set *cset, const char *filename)230{231struct filter_set *old_filters;232char *name, *p;233const char *code;234int old_filter_count;235236name = strdup(filename);237if (name == NULL)238lafe_errc(1, 0, "No memory");239/* Save previous filters. */240old_filters = cset->filters;241old_filter_count = cset->filter_count;242cset->filters = NULL;243cset->filter_count = 0;244245for (;;) {246/* Get the suffix. */247p = strrchr(name, '.');248if (p == NULL)249break;250/* Suppose it indicates compression/filter type251* such as ".gz". */252code = get_filter_code(p);253if (code != NULL) {254cset_add_filter(cset, code);255*p = '\0';256continue;257}258/* Suppose it indicates format type such as ".tar". */259code = get_format_code(p);260if (code != NULL) {261cset_set_format(cset, code);262break;263}264/* Suppose it indicates alias such as ".tgz". */265code = decompose_alias(p);266if (code == NULL)267break;268/* Replace the suffix. */269*p = '\0';270name = realloc(name, strlen(name) + strlen(code) + 1);271if (name == NULL)272lafe_errc(1, 0, "No memory");273strcat(name, code);274}275free(name);276if (cset->filters) {277struct filter_set *v;278int i, r;279280/* Release previous filters. */281_cleanup_filters(old_filters, old_filter_count);282283v = malloc(sizeof(*v) * cset->filter_count);284if (v == NULL)285lafe_errc(1, 0, "No memory");286/* Reverse filter sequence. */287for (i = 0, r = cset->filter_count; r > 0; )288v[i++] = cset->filters[--r];289free(cset->filters);290cset->filters = v;291return (1);292} else {293/* Put previous filters back. */294cset->filters = old_filters;295cset->filter_count = old_filter_count;296return (0);297}298}299300301