creation_set.c revision 303975
1251881Speter/*- 2251881Speter * Copyright (c) 2012 Michihiro NAKAJIMA 3251881Speter * All rights reserved. 4251881Speter * 5251881Speter * Redistribution and use in source and binary forms, with or without 6251881Speter * modification, are permitted provided that the following conditions 7251881Speter * are met: 8251881Speter * 1. Redistributions of source code must retain the above copyright 9251881Speter * notice, this list of conditions and the following disclaimer. 10251881Speter * 2. Redistributions in binary form must reproduce the above copyright 11251881Speter * notice, this list of conditions and the following disclaimer in the 12251881Speter * documentation and/or other materials provided with the distribution. 13251881Speter * 14251881Speter * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR 15251881Speter * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16251881Speter * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17251881Speter * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, 18251881Speter * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 19251881Speter * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 20251881Speter * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 21251881Speter * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22251881Speter * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 23251881Speter * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24251881Speter */ 25251881Speter 26251881Speter#include "bsdtar_platform.h" 27251881Speter__FBSDID("$FreeBSD$"); 28251881Speter 29251881Speter#ifdef HAVE_STDLIB_H 30251881Speter#include <stdlib.h> 31251881Speter#endif 32251881Speter#ifdef HAVE_STRING_H 33251881Speter#include <string.h> 34251881Speter#endif 35251881Speter 36251881Speter#include "bsdtar.h" 37251881Speter#include "err.h" 38251881Speter 39251881Speterstruct creation_set { 40251881Speter char *create_format; 41251881Speter struct filter_set { 42251881Speter int program; /* Set 1 if filter is a program name */ 43251881Speter char *filter_name; 44251881Speter } *filters; 45251881Speter int filter_count; 46251881Speter}; 47251881Speter 48251881Speterstruct suffix_code_t { 49251881Speter const char *suffix; 50251881Speter const char *form; 51251881Speter}; 52251881Speter 53251881Speterstatic const char * 54251881Speterget_suffix_code(const struct suffix_code_t *tbl, const char *suffix) 55251881Speter{ 56251881Speter int i; 57251881Speter 58251881Speter if (suffix == NULL) 59251881Speter return (NULL); 60251881Speter for (i = 0; tbl[i].suffix != NULL; i++) { 61251881Speter if (strcmp(tbl[i].suffix, suffix) == 0) 62251881Speter return (tbl[i].form); 63251881Speter } 64251881Speter return (NULL); 65251881Speter} 66251881Speter 67251881Speterstatic const char * 68251881Speterget_filter_code(const char *suffix) 69251881Speter{ 70251881Speter /* A pair of suffix and compression/filter. */ 71251881Speter static const struct suffix_code_t filters[] = { 72251881Speter { ".Z", "compress" }, 73251881Speter { ".bz2", "bzip2" }, 74251881Speter { ".gz", "gzip" }, 75251881Speter { ".grz", "grzip" }, 76251881Speter { ".lrz", "lrzip" }, 77251881Speter { ".lz", "lzip" }, 78251881Speter { ".lz4", "lz4" }, 79251881Speter { ".lzo", "lzop" }, 80251881Speter { ".lzma", "lzma" }, 81251881Speter { ".uu", "uuencode" }, 82251881Speter { ".xz", "xz" }, 83251881Speter { NULL, NULL } 84251881Speter }; 85251881Speter 86251881Speter return get_suffix_code(filters, suffix); 87251881Speter} 88251881Speter 89251881Speterstatic const char * 90251881Speterget_format_code(const char *suffix) 91251881Speter{ 92251881Speter /* A pair of suffix and format. */ 93251881Speter static const struct suffix_code_t formats[] = { 94251881Speter { ".7z", "7zip" }, 95251881Speter { ".ar", "arbsd" }, 96251881Speter { ".cpio", "cpio" }, 97251881Speter { ".iso", "iso9960" }, 98251881Speter { ".mtree", "mtree" }, 99251881Speter { ".shar", "shar" }, 100251881Speter { ".tar", "paxr" }, 101251881Speter { ".warc", "warc" }, 102251881Speter { ".xar", "xar" }, 103251881Speter { ".zip", "zip" }, 104251881Speter { NULL, NULL } 105251881Speter }; 106251881Speter 107251881Speter return get_suffix_code(formats, suffix); 108251881Speter} 109251881Speter 110251881Speterstatic const char * 111251881Speterdecompose_alias(const char *suffix) 112251881Speter{ 113251881Speter static const struct suffix_code_t alias[] = { 114251881Speter { ".taz", ".tar.gz" }, 115251881Speter { ".tgz", ".tar.gz" }, 116251881Speter { ".tbz", ".tar.bz2" }, 117251881Speter { ".tbz2", ".tar.bz2" }, 118251881Speter { ".tz2", ".tar.bz2" }, 119251881Speter { ".tlz", ".tar.lzma" }, 120251881Speter { ".txz", ".tar.xz" }, 121251881Speter { ".tzo", ".tar.lzo" }, 122251881Speter { ".taZ", ".tar.Z" }, 123251881Speter { ".tZ", ".tar.Z" }, 124251881Speter { NULL, NULL } 125251881Speter }; 126251881Speter 127251881Speter return get_suffix_code(alias, suffix); 128251881Speter} 129251881Speter 130251881Speterstatic void 131251881Speter_cset_add_filter(struct creation_set *cset, int program, const char *filter) 132251881Speter{ 133251881Speter struct filter_set *new_ptr; 134251881Speter char *new_filter; 135251881Speter 136251881Speter new_ptr = (struct filter_set *)realloc(cset->filters, 137251881Speter sizeof(*cset->filters) * (cset->filter_count + 1)); 138251881Speter if (new_ptr == NULL) 139251881Speter lafe_errc(1, 0, "No memory"); 140251881Speter new_filter = strdup(filter); 141251881Speter if (new_filter == NULL) 142251881Speter lafe_errc(1, 0, "No memory"); 143251881Speter cset->filters = new_ptr; 144251881Speter cset->filters[cset->filter_count].program = program; 145251881Speter cset->filters[cset->filter_count].filter_name = new_filter; 146251881Speter cset->filter_count++; 147251881Speter} 148251881Speter 149251881Spetervoid 150251881Spetercset_add_filter(struct creation_set *cset, const char *filter) 151251881Speter{ 152251881Speter _cset_add_filter(cset, 0, filter); 153251881Speter} 154251881Speter 155251881Spetervoid 156251881Spetercset_add_filter_program(struct creation_set *cset, const char *filter) 157251881Speter{ 158251881Speter _cset_add_filter(cset, 1, filter); 159251881Speter} 160251881Speter 161251881Speterint 162251881Spetercset_read_support_filter_program(struct creation_set *cset, struct archive *a) 163251881Speter{ 164251881Speter int cnt = 0, i; 165251881Speter 166251881Speter for (i = 0; i < cset->filter_count; i++) { 167251881Speter if (cset->filters[i].program) { 168251881Speter archive_read_support_filter_program(a, 169251881Speter cset->filters[i].filter_name); 170251881Speter ++cnt; 171251881Speter } 172251881Speter } 173251881Speter return (cnt); 174251881Speter} 175251881Speter 176251881Speterint 177251881Spetercset_write_add_filters(struct creation_set *cset, struct archive *a, 178251881Speter const void **filter_name) 179251881Speter{ 180251881Speter int cnt = 0, i, r; 181251881Speter 182251881Speter for (i = 0; i < cset->filter_count; i++) { 183251881Speter if (cset->filters[i].program) 184251881Speter r = archive_write_add_filter_program(a, 185251881Speter cset->filters[i].filter_name); 186251881Speter else 187251881Speter r = archive_write_add_filter_by_name(a, 188251881Speter cset->filters[i].filter_name); 189251881Speter if (r < ARCHIVE_WARN) { 190251881Speter *filter_name = cset->filters[i].filter_name; 191251881Speter return (r); 192251881Speter } 193251881Speter ++cnt; 194251881Speter } 195251881Speter return (cnt); 196251881Speter} 197251881Speter 198251881Spetervoid 199251881Spetercset_set_format(struct creation_set *cset, const char *format) 200251881Speter{ 201251881Speter char *f; 202251881Speter 203251881Speter f = strdup(format); 204251881Speter if (f == NULL) 205251881Speter lafe_errc(1, 0, "No memory"); 206251881Speter free(cset->create_format); 207251881Speter cset->create_format = f; 208251881Speter} 209251881Speter 210251881Speterconst char * 211251881Spetercset_get_format(struct creation_set *cset) 212251881Speter{ 213251881Speter return (cset->create_format); 214251881Speter} 215251881Speter 216251881Speterstatic void 217251881Speter_cleanup_filters(struct filter_set *filters, int count) 218251881Speter{ 219251881Speter int i; 220251881Speter 221251881Speter for (i = 0; i < count; i++) 222251881Speter free(filters[i].filter_name); 223251881Speter free(filters); 224251881Speter} 225251881Speter 226251881Speter/* 227251881Speter * Clean up a creation set. 228251881Speter */ 229251881Spetervoid 230251881Spetercset_free(struct creation_set *cset) 231251881Speter{ 232251881Speter _cleanup_filters(cset->filters, cset->filter_count); 233251881Speter free(cset->create_format); 234251881Speter free(cset); 235251881Speter} 236251881Speter 237251881Speterstruct creation_set * 238251881Spetercset_new(void) 239251881Speter{ 240251881Speter return calloc(1, sizeof(struct creation_set)); 241251881Speter} 242251881Speter 243251881Speter/* 244251881Speter * Build a creation set by a file name suffix. 245251881Speter */ 246251881Speterint 247251881Spetercset_auto_compress(struct creation_set *cset, const char *filename) 248251881Speter{ 249251881Speter struct filter_set *old_filters; 250251881Speter char *name, *p; 251251881Speter const char *code; 252251881Speter int old_filter_count; 253251881Speter 254251881Speter name = strdup(filename); 255251881Speter if (name == NULL) 256251881Speter lafe_errc(1, 0, "No memory"); 257251881Speter /* Save previous filters. */ 258251881Speter old_filters = cset->filters; 259251881Speter old_filter_count = cset->filter_count; 260251881Speter cset->filters = NULL; 261251881Speter cset->filter_count = 0; 262251881Speter 263251881Speter for (;;) { 264251881Speter /* Get the suffix. */ 265251881Speter p = strrchr(name, '.'); 266251881Speter if (p == NULL) 267251881Speter break; 268251881Speter /* Suppose it indicates compression/filter type 269251881Speter * such as ".gz". */ 270251881Speter code = get_filter_code(p); 271251881Speter if (code != NULL) { 272251881Speter cset_add_filter(cset, code); 273251881Speter *p = '\0'; 274251881Speter continue; 275251881Speter } 276251881Speter /* Suppose it indicates format type such as ".tar". */ 277251881Speter code = get_format_code(p); 278251881Speter if (code != NULL) { 279251881Speter cset_set_format(cset, code); 280251881Speter break; 281251881Speter } 282251881Speter /* Suppose it indicates alias such as ".tgz". */ 283251881Speter code = decompose_alias(p); 284251881Speter if (code == NULL) 285251881Speter break; 286251881Speter /* Replace the suffix. */ 287251881Speter *p = '\0'; 288251881Speter name = realloc(name, strlen(name) + strlen(code) + 1); 289251881Speter if (name == NULL) 290251881Speter lafe_errc(1, 0, "No memory"); 291251881Speter strcat(name, code); 292251881Speter } 293251881Speter free(name); 294251881Speter if (cset->filters) { 295251881Speter struct filter_set *v; 296251881Speter int i, r; 297251881Speter 298251881Speter /* Release previos filters. */ 299251881Speter _cleanup_filters(old_filters, old_filter_count); 300251881Speter 301251881Speter v = malloc(sizeof(*v) * cset->filter_count); 302251881Speter if (v == NULL) 303251881Speter lafe_errc(1, 0, "No memory"); 304251881Speter /* Reverse filter sequence. */ 305251881Speter for (i = 0, r = cset->filter_count; r > 0; ) 306251881Speter v[i++] = cset->filters[--r]; 307251881Speter free(cset->filters); 308251881Speter cset->filters = v; 309251881Speter return (1); 310251881Speter } else { 311251881Speter /* Put previos filters back. */ 312251881Speter cset->filters = old_filters; 313251881Speter cset->filter_count = old_filter_count; 314251881Speter return (0); 315251881Speter } 316251881Speter} 317251881Speter