1 /*- 2 * Copyright (c) 2012 Michihiro NAKAJIMA 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR 15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17 * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, 18 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 19 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 20 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 21 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26 #include "bsdtar_platform.h" 27 __FBSDID("$FreeBSD$"); 28 29 #ifdef HAVE_STDLIB_H 30 #include <stdlib.h> 31 #endif 32 #ifdef HAVE_STRING_H 33 #include <string.h> 34 #endif 35 36 #include "bsdtar.h" 37 #include "err.h" 38 39 struct creation_set { 40 char *create_format; 41 struct filter_set { 42 int program; /* Set 1 if filter is a program name */ 43 char *filter_name; 44 } *filters; 45 int filter_count; 46 }; 47 48 struct suffix_code_t { 49 const char *suffix; 50 const char *form; 51 }; 52 53 static const char * 54 get_suffix_code(const struct suffix_code_t *tbl, const char *suffix) 55 { 56 int i; 57 58 if (suffix == NULL) 59 return (NULL); 60 for (i = 0; tbl[i].suffix != NULL; i++) { 61 if (strcmp(tbl[i].suffix, suffix) == 0) 62 return (tbl[i].form); 63 } 64 return (NULL); 65 } 66 67 static const char * 68 get_filter_code(const char *suffix) 69 { 70 /* A pair of suffix and compression/filter. */ 71 static const struct suffix_code_t filters[] = { 72 { ".Z", "compress" }, 73 { ".bz2", "bzip2" }, 74 { ".gz", "gzip" }, 75 { ".grz", "grzip" }, 76 { ".lrz", "lrzip" }, 77 { ".lz", "lzip" }, 78 { ".lz4", "lz4" }, 79 { ".lzo", "lzop" }, 80 { ".lzma", "lzma" }, 81 { ".uu", "uuencode" }, 82 { ".xz", "xz" }, 83 { ".zst", "zstd"}, 84 { NULL, NULL } 85 }; 86 87 return get_suffix_code(filters, suffix); 88 } 89 90 static const char * 91 get_format_code(const char *suffix) 92 { 93 /* A pair of suffix and format. */ 94 static const struct suffix_code_t formats[] = { 95 { ".7z", "7zip" }, 96 { ".ar", "arbsd" }, 97 { ".cpio", "cpio" }, 98 { ".iso", "iso9960" }, 99 { ".mtree", "mtree" }, 100 { ".shar", "shar" }, 101 { ".tar", "paxr" }, 102 { ".warc", "warc" }, 103 { ".xar", "xar" }, 104 { ".zip", "zip" }, 105 { NULL, NULL } 106 }; 107 108 return get_suffix_code(formats, suffix); 109 } 110 111 static const char * 112 decompose_alias(const char *suffix) 113 { 114 static const struct suffix_code_t alias[] = { 115 { ".taz", ".tar.gz" }, 116 { ".tgz", ".tar.gz" }, 117 { ".tbz", ".tar.bz2" }, 118 { ".tbz2", ".tar.bz2" }, 119 { ".tz2", ".tar.bz2" }, 120 { ".tlz", ".tar.lzma" }, 121 { ".txz", ".tar.xz" }, 122 { ".tzo", ".tar.lzo" }, 123 { ".taZ", ".tar.Z" }, 124 { ".tZ", ".tar.Z" }, 125 { ".tzst", ".tar.zst" }, 126 { NULL, NULL } 127 }; 128 129 return get_suffix_code(alias, suffix); 130 } 131 132 static void 133 _cset_add_filter(struct creation_set *cset, int program, const char *filter) 134 { 135 struct filter_set *new_ptr; 136 char *new_filter; 137 138 new_ptr = (struct filter_set *)realloc(cset->filters, 139 sizeof(*cset->filters) * (cset->filter_count + 1)); 140 if (new_ptr == NULL) 141 lafe_errc(1, 0, "No memory"); 142 new_filter = strdup(filter); 143 if (new_filter == NULL) 144 lafe_errc(1, 0, "No memory"); 145 cset->filters = new_ptr; 146 cset->filters[cset->filter_count].program = program; 147 cset->filters[cset->filter_count].filter_name = new_filter; 148 cset->filter_count++; 149 } 150 151 void 152 cset_add_filter(struct creation_set *cset, const char *filter) 153 { 154 _cset_add_filter(cset, 0, filter); 155 } 156 157 void 158 cset_add_filter_program(struct creation_set *cset, const char *filter) 159 { 160 _cset_add_filter(cset, 1, filter); 161 } 162 163 int 164 cset_read_support_filter_program(struct creation_set *cset, struct archive *a) 165 { 166 int cnt = 0, i; 167 168 for (i = 0; i < cset->filter_count; i++) { 169 if (cset->filters[i].program) { 170 archive_read_support_filter_program(a, 171 cset->filters[i].filter_name); 172 ++cnt; 173 } 174 } 175 return (cnt); 176 } 177 178 int 179 cset_write_add_filters(struct creation_set *cset, struct archive *a, 180 const void **filter_name) 181 { 182 int cnt = 0, i, r; 183 184 for (i = 0; i < cset->filter_count; i++) { 185 if (cset->filters[i].program) 186 r = archive_write_add_filter_program(a, 187 cset->filters[i].filter_name); 188 else 189 r = archive_write_add_filter_by_name(a, 190 cset->filters[i].filter_name); 191 if (r < ARCHIVE_WARN) { 192 *filter_name = cset->filters[i].filter_name; 193 return (r); 194 } 195 ++cnt; 196 } 197 return (cnt); 198 } 199 200 void 201 cset_set_format(struct creation_set *cset, const char *format) 202 { 203 char *f; 204 205 f = strdup(format); 206 if (f == NULL) 207 lafe_errc(1, 0, "No memory"); 208 free(cset->create_format); 209 cset->create_format = f; 210 } 211 212 const char * 213 cset_get_format(struct creation_set *cset) 214 { 215 return (cset->create_format); 216 } 217 218 static void 219 _cleanup_filters(struct filter_set *filters, int count) 220 { 221 int i; 222 223 for (i = 0; i < count; i++) 224 free(filters[i].filter_name); 225 free(filters); 226 } 227 228 /* 229 * Clean up a creation set. 230 */ 231 void 232 cset_free(struct creation_set *cset) 233 { 234 _cleanup_filters(cset->filters, cset->filter_count); 235 free(cset->create_format); 236 free(cset); 237 } 238 239 struct creation_set * 240 cset_new(void) 241 { 242 return calloc(1, sizeof(struct creation_set)); 243 } 244 245 /* 246 * Build a creation set by a file name suffix. 247 */ 248 int 249 cset_auto_compress(struct creation_set *cset, const char *filename) 250 { 251 struct filter_set *old_filters; 252 char *name, *p; 253 const char *code; 254 int old_filter_count; 255 256 name = strdup(filename); 257 if (name == NULL) 258 lafe_errc(1, 0, "No memory"); 259 /* Save previous filters. */ 260 old_filters = cset->filters; 261 old_filter_count = cset->filter_count; 262 cset->filters = NULL; 263 cset->filter_count = 0; 264 265 for (;;) { 266 /* Get the suffix. */ 267 p = strrchr(name, '.'); 268 if (p == NULL) 269 break; 270 /* Suppose it indicates compression/filter type 271 * such as ".gz". */ 272 code = get_filter_code(p); 273 if (code != NULL) { 274 cset_add_filter(cset, code); 275 *p = '\0'; 276 continue; 277 } 278 /* Suppose it indicates format type such as ".tar". */ 279 code = get_format_code(p); 280 if (code != NULL) { 281 cset_set_format(cset, code); 282 break; 283 } 284 /* Suppose it indicates alias such as ".tgz". */ 285 code = decompose_alias(p); 286 if (code == NULL) 287 break; 288 /* Replace the suffix. */ 289 *p = '\0'; 290 name = realloc(name, strlen(name) + strlen(code) + 1); 291 if (name == NULL) 292 lafe_errc(1, 0, "No memory"); 293 strcat(name, code); 294 } 295 free(name); 296 if (cset->filters) { 297 struct filter_set *v; 298 int i, r; 299 300 /* Release previous filters. */ 301 _cleanup_filters(old_filters, old_filter_count); 302 303 v = malloc(sizeof(*v) * cset->filter_count); 304 if (v == NULL) 305 lafe_errc(1, 0, "No memory"); 306 /* Reverse filter sequence. */ 307 for (i = 0, r = cset->filter_count; r > 0; ) 308 v[i++] = cset->filters[--r]; 309 free(cset->filters); 310 cset->filters = v; 311 return (1); 312 } else { 313 /* Put previous filters back. */ 314 cset->filters = old_filters; 315 cset->filter_count = old_filter_count; 316 return (0); 317 } 318 } 319