]> CyberLeo.Net >> Repos - FreeBSD/stable/10.git/blob - contrib/libarchive/tar/creation_set.c
MFH r324148:
[FreeBSD/stable/10.git] / contrib / libarchive / tar / creation_set.c
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 }