creation_set.c revision 299529
119370Spst/*- 219370Spst * Copyright (c) 2012 Michihiro NAKAJIMA 319370Spst * All rights reserved. 419370Spst * 519370Spst * Redistribution and use in source and binary forms, with or without 619370Spst * modification, are permitted provided that the following conditions 719370Spst * are met: 819370Spst * 1. Redistributions of source code must retain the above copyright 919370Spst * notice, this list of conditions and the following disclaimer. 1019370Spst * 2. Redistributions in binary form must reproduce the above copyright 1119370Spst * notice, this list of conditions and the following disclaimer in the 1219370Spst * documentation and/or other materials provided with the distribution. 1319370Spst * 1419370Spst * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR 1519370Spst * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 1619370Spst * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 1719370Spst * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, 1819370Spst * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 1919370Spst * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2019370Spst * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2119370Spst * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2219370Spst * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 2319370Spst * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2419370Spst */ 2519370Spst 2619370Spst#include "bsdtar_platform.h" 2719370Spst__FBSDID("$FreeBSD$"); 2819370Spst 2919370Spst#ifdef HAVE_STDLIB_H 3019370Spst#include <stdlib.h> 3119370Spst#endif 3219370Spst#ifdef HAVE_STRING_H 3319370Spst#include <string.h> 3419370Spst#endif 3519370Spst 3619370Spst#include "bsdtar.h" 3719370Spst#include "err.h" 3819370Spst 3919370Spststruct creation_set { 4019370Spst char *create_format; 4119370Spst struct filter_set { 4219370Spst int program; /* Set 1 if filter is a program name */ 4319370Spst char *filter_name; 4419370Spst } *filters; 4519370Spst int filter_count; 4619370Spst}; 4798944Sobrien 4898944Sobrienstruct suffix_code_t { 4998944Sobrien const char *suffix; 5098944Sobrien const char *form; 5198944Sobrien}; 5298944Sobrien 5398944Sobrienstatic const char * 5498944Sobrienget_suffix_code(const struct suffix_code_t *tbl, const char *suffix) 5519370Spst{ 5619370Spst int i; 5719370Spst 5819370Spst if (suffix == NULL) 5919370Spst return (NULL); 6019370Spst for (i = 0; tbl[i].suffix != NULL; i++) { 6119370Spst if (strcmp(tbl[i].suffix, suffix) == 0) 6219370Spst return (tbl[i].form); 6319370Spst } 6419370Spst return (NULL); 6519370Spst} 6619370Spst 6719370Spststatic const char * 6819370Spstget_filter_code(const char *suffix) 6919370Spst{ 7019370Spst /* A pair of suffix and compression/filter. */ 7119370Spst static const struct suffix_code_t filters[] = { 7219370Spst { ".Z", "compress" }, 7319370Spst { ".bz2", "bzip2" }, 7419370Spst { ".gz", "gzip" }, 7519370Spst { ".grz", "grzip" }, 7619370Spst { ".lrz", "lrzip" }, 7719370Spst { ".lz", "lzip" }, 7898944Sobrien { ".lz4", "lz4" }, 7919370Spst { ".lzo", "lzop" }, 8098944Sobrien { ".lzma", "lzma" }, 8198944Sobrien { ".uu", "uuencode" }, 8298944Sobrien { ".xz", "xz" }, 8398944Sobrien { NULL, NULL } 8498944Sobrien }; 8598944Sobrien 8698944Sobrien return get_suffix_code(filters, suffix); 8798944Sobrien} 8898944Sobrien 8919370Spststatic const char * 9019370Spstget_format_code(const char *suffix) 9119370Spst{ 9219370Spst /* A pair of suffix and format. */ 9319370Spst static const struct suffix_code_t formats[] = { 9419370Spst { ".7z", "7zip" }, 9519370Spst { ".ar", "arbsd" }, 9698944Sobrien { ".cpio", "cpio" }, 9798944Sobrien { ".iso", "iso9960" }, 9898944Sobrien { ".mtree", "mtree" }, 9919370Spst { ".shar", "shar" }, 10098944Sobrien { ".tar", "paxr" }, 10198944Sobrien { ".warc", "warc" }, 10298944Sobrien { ".xar", "xar" }, 10398944Sobrien { ".zip", "zip" }, 10419370Spst { NULL, NULL } 10598944Sobrien }; 10698944Sobrien 10719370Spst return get_suffix_code(formats, suffix); 10898944Sobrien} 10998944Sobrien 11098944Sobrienstatic const char * 11119370Spstdecompose_alias(const char *suffix) 11219370Spst{ 11319370Spst static const struct suffix_code_t alias[] = { 11419370Spst { ".taz", ".tar.gz" }, 11519370Spst { ".tgz", ".tar.gz" }, 11619370Spst { ".tbz", ".tar.bz2" }, 11719370Spst { ".tbz2", ".tar.bz2" }, 11819370Spst { ".tz2", ".tar.bz2" }, 11919370Spst { ".tlz", ".tar.lzma" }, 12019370Spst { ".txz", ".tar.xz" }, 12119370Spst { ".tzo", ".tar.lzo" }, 12219370Spst { ".taZ", ".tar.Z" }, 12319370Spst { ".tZ", ".tar.Z" }, 12419370Spst { NULL, NULL } 12519370Spst }; 12619370Spst 12719370Spst return get_suffix_code(alias, suffix); 12819370Spst} 12919370Spst 13019370Spststatic void 13119370Spst_cset_add_filter(struct creation_set *cset, int program, const char *filter) 13219370Spst{ 13319370Spst struct filter_set *new_ptr; 13419370Spst char *new_filter; 13519370Spst 13619370Spst new_ptr = (struct filter_set *)realloc(cset->filters, 13719370Spst sizeof(*cset->filters) * (cset->filter_count + 1)); 13819370Spst if (new_ptr == NULL) 139 lafe_errc(1, 0, "No memory"); 140 new_filter = strdup(filter); 141 if (new_filter == NULL) 142 lafe_errc(1, 0, "No memory"); 143 cset->filters = new_ptr; 144 cset->filters[cset->filter_count].program = program; 145 cset->filters[cset->filter_count].filter_name = new_filter; 146 cset->filter_count++; 147} 148 149void 150cset_add_filter(struct creation_set *cset, const char *filter) 151{ 152 _cset_add_filter(cset, 0, filter); 153} 154 155void 156cset_add_filter_program(struct creation_set *cset, const char *filter) 157{ 158 _cset_add_filter(cset, 1, filter); 159} 160 161int 162cset_read_support_filter_program(struct creation_set *cset, struct archive *a) 163{ 164 int cnt = 0, i; 165 166 for (i = 0; i < cset->filter_count; i++) { 167 if (cset->filters[i].program) { 168 archive_read_support_filter_program(a, 169 cset->filters[i].filter_name); 170 ++cnt; 171 } 172 } 173 return (cnt); 174} 175 176int 177cset_write_add_filters(struct creation_set *cset, struct archive *a, 178 const void **filter_name) 179{ 180 int cnt = 0, i, r; 181 182 for (i = 0; i < cset->filter_count; i++) { 183 if (cset->filters[i].program) 184 r = archive_write_add_filter_program(a, 185 cset->filters[i].filter_name); 186 else 187 r = archive_write_add_filter_by_name(a, 188 cset->filters[i].filter_name); 189 if (r < ARCHIVE_WARN) { 190 *filter_name = cset->filters[i].filter_name; 191 return (r); 192 } 193 ++cnt; 194 } 195 return (cnt); 196} 197 198void 199cset_set_format(struct creation_set *cset, const char *format) 200{ 201 char *f; 202 203 f = strdup(format); 204 if (f == NULL) 205 lafe_errc(1, 0, "No memory"); 206 free(cset->create_format); 207 cset->create_format = f; 208} 209 210const char * 211cset_get_format(struct creation_set *cset) 212{ 213 return (cset->create_format); 214} 215 216static void 217_cleanup_filters(struct filter_set *filters, int count) 218{ 219 int i; 220 221 for (i = 0; i < count; i++) 222 free(filters[i].filter_name); 223 free(filters); 224} 225 226/* 227 * Clean up a creation set. 228 */ 229void 230cset_free(struct creation_set *cset) 231{ 232 _cleanup_filters(cset->filters, cset->filter_count); 233 free(cset->create_format); 234 free(cset); 235} 236 237struct creation_set * 238cset_new(void) 239{ 240 return calloc(1, sizeof(struct creation_set)); 241} 242 243/* 244 * Build a creation set by a file name suffix. 245 */ 246int 247cset_auto_compress(struct creation_set *cset, const char *filename) 248{ 249 struct filter_set *old_filters; 250 char *name, *p; 251 const char *code; 252 int old_filter_count; 253 254 name = strdup(filename); 255 if (name == NULL) 256 lafe_errc(1, 0, "No memory"); 257 /* Save previous filters. */ 258 old_filters = cset->filters; 259 old_filter_count = cset->filter_count; 260 cset->filters = NULL; 261 cset->filter_count = 0; 262 263 for (;;) { 264 /* Get the suffix. */ 265 p = strrchr(name, '.'); 266 if (p == NULL) 267 break; 268 /* Suppose it indicates compression/filter type 269 * such as ".gz". */ 270 code = get_filter_code(p); 271 if (code != NULL) { 272 cset_add_filter(cset, code); 273 *p = '\0'; 274 continue; 275 } 276 /* Suppose it indicates format type such as ".tar". */ 277 code = get_format_code(p); 278 if (code != NULL) { 279 cset_set_format(cset, code); 280 break; 281 } 282 /* Suppose it indicates alias such as ".tgz". */ 283 code = decompose_alias(p); 284 if (code == NULL) 285 break; 286 /* Replace the suffix. */ 287 *p = '\0'; 288 name = realloc(name, strlen(name) + strlen(code) + 1); 289 if (name == NULL) 290 lafe_errc(1, 0, "No memory"); 291 strcat(name, code); 292 } 293 free(name); 294 if (cset->filters) { 295 struct filter_set *v; 296 int i, r; 297 298 /* Release previos filters. */ 299 _cleanup_filters(old_filters, old_filter_count); 300 301 v = malloc(sizeof(*v) * cset->filter_count); 302 if (v == NULL) 303 lafe_errc(1, 0, "No memory"); 304 /* Reverse filter sequence. */ 305 for (i = 0, r = cset->filter_count; r > 0; ) 306 v[i++] = cset->filters[--r]; 307 free(cset->filters); 308 cset->filters = v; 309 return (1); 310 } else { 311 /* Put previos filters back. */ 312 cset->filters = old_filters; 313 cset->filter_count = old_filter_count; 314 return (0); 315 } 316} 317