1
2
3
4
5
6
7#include "libbb.h"
8#include "bb_archive.h"
9
10enum {
11 OPT_STDOUT = 1 << 0,
12 OPT_FORCE = 1 << 1,
13
14 OPT_VERBOSE = 1 << 2,
15 OPT_DECOMPRESS = 1 << 3,
16 OPT_TEST = 1 << 4,
17};
18
19static
20int open_to_or_warn(int to_fd, const char *filename, int flags, int mode)
21{
22 int fd = open3_or_warn(filename, flags, mode);
23 if (fd < 0) {
24 return 1;
25 }
26 xmove_fd(fd, to_fd);
27 return 0;
28}
29
30char* FAST_FUNC append_ext(char *filename, const char *expected_ext)
31{
32 return xasprintf("%s.%s", filename, expected_ext);
33}
34
35int FAST_FUNC bbunpack(char **argv,
36 IF_DESKTOP(long long) int FAST_FUNC (*unpacker)(transformer_aux_data_t *aux),
37 char* FAST_FUNC (*make_new_name)(char *filename, const char *expected_ext),
38 const char *expected_ext
39)
40{
41 struct stat stat_buf;
42 IF_DESKTOP(long long) int status;
43 char *filename, *new_name;
44 smallint exitcode = 0;
45 transformer_aux_data_t aux;
46
47 do {
48
49 new_name = NULL;
50 filename = *argv;
51
52 if (filename && LONE_DASH(filename))
53 filename = NULL;
54
55
56 if (filename) {
57 if (stat(filename, &stat_buf) != 0) {
58 bb_simple_perror_msg(filename);
59 err:
60 exitcode = 1;
61 goto free_name;
62 }
63 if (open_to_or_warn(STDIN_FILENO, filename, O_RDONLY, 0))
64 goto err;
65 }
66
67
68 if (option_mask32 & (OPT_STDOUT|OPT_TEST)) {
69 if (option_mask32 & OPT_TEST)
70 if (open_to_or_warn(STDOUT_FILENO, bb_dev_null, O_WRONLY, 0))
71 goto err;
72 filename = NULL;
73 }
74
75
76 if (filename) {
77 new_name = make_new_name(filename, expected_ext);
78 if (!new_name) {
79 bb_error_msg("%s: unknown suffix - ignored", filename);
80 goto err;
81 }
82
83
84 if (option_mask32 & OPT_FORCE) {
85 unlink(new_name);
86 }
87
88
89
90 if (open_to_or_warn(STDOUT_FILENO, new_name, O_WRONLY | O_CREAT | O_EXCL,
91 stat_buf.st_mode))
92 goto err;
93 }
94
95
96 if (isatty(STDIN_FILENO) && (option_mask32 & OPT_FORCE) == 0) {
97 bb_error_msg_and_die("compressed data not read from terminal, "
98 "use -f to force it");
99 }
100
101 init_transformer_aux_data(&aux);
102 aux.check_signature = 1;
103 status = unpacker(&aux);
104 if (status < 0)
105 exitcode = 1;
106
107 if (!(option_mask32 & OPT_STDOUT))
108 xclose(STDOUT_FILENO);
109
110 if (filename) {
111 char *del = new_name;
112 if (status >= 0) {
113
114 if (aux.mtime != 0) {
115 struct timeval times[2];
116
117 times[1].tv_sec = times[0].tv_sec = aux.mtime;
118 times[1].tv_usec = times[0].tv_usec = 0;
119
120
121
122
123 utimes(new_name, times);
124 }
125
126
127 del = filename;
128
129 if (new_name == filename)
130 filename[strlen(filename)] = '.';
131 }
132 xunlink(del);
133
134#if 0
135
136 if (ENABLE_DESKTOP && (option_mask32 & OPT_VERBOSE) && status >= 0) {
137 fprintf(stderr, "%s: %u%% - replaced with %s\n",
138 filename, (unsigned)(stat_buf.st_size*100 / (status+1)), new_name);
139 }
140#endif
141
142 free_name:
143 if (new_name != filename)
144 free(new_name);
145 }
146 } while (*argv && *++argv);
147
148 if (option_mask32 & OPT_STDOUT)
149 xclose(STDOUT_FILENO);
150
151 return exitcode;
152}
153
154#if ENABLE_UNCOMPRESS || ENABLE_BUNZIP2 || ENABLE_UNLZMA || ENABLE_UNXZ
155static
156char* FAST_FUNC make_new_name_generic(char *filename, const char *expected_ext)
157{
158 char *extension = strrchr(filename, '.');
159 if (!extension || strcmp(extension + 1, expected_ext) != 0) {
160
161
162 return NULL;
163 }
164 *extension = '\0';
165 return filename;
166}
167#endif
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183#if ENABLE_UNCOMPRESS
184static
185IF_DESKTOP(long long) int FAST_FUNC unpack_uncompress(transformer_aux_data_t *aux)
186{
187 return unpack_Z_stream(aux, STDIN_FILENO, STDOUT_FILENO);
188}
189int uncompress_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
190int uncompress_main(int argc UNUSED_PARAM, char **argv)
191{
192 getopt32(argv, "cf");
193 argv += optind;
194
195 return bbunpack(argv, unpack_uncompress, make_new_name_generic, "Z");
196}
197#endif
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248#if ENABLE_GUNZIP
249static
250char* FAST_FUNC make_new_name_gunzip(char *filename, const char *expected_ext UNUSED_PARAM)
251{
252 char *extension = strrchr(filename, '.');
253
254 if (!extension)
255 return NULL;
256
257 extension++;
258 if (strcmp(extension, "tgz" + 1) == 0
259#if ENABLE_FEATURE_SEAMLESS_Z
260 || (extension[0] == 'Z' && extension[1] == '\0')
261#endif
262 ) {
263 extension[-1] = '\0';
264 } else if (strcmp(extension, "tgz") == 0) {
265 filename = xstrdup(filename);
266 extension = strrchr(filename, '.');
267 extension[2] = 'a';
268 extension[3] = 'r';
269 } else {
270 return NULL;
271 }
272 return filename;
273}
274static
275IF_DESKTOP(long long) int FAST_FUNC unpack_gunzip(transformer_aux_data_t *aux)
276{
277 return unpack_gz_stream(aux, STDIN_FILENO, STDOUT_FILENO);
278}
279
280
281
282
283
284
285
286
287
288
289
290
291
292int gunzip_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
293int gunzip_main(int argc UNUSED_PARAM, char **argv)
294{
295 getopt32(argv, "cfvdtn");
296 argv += optind;
297
298 if (applet_name[1] == 'c')
299 option_mask32 |= OPT_STDOUT;
300
301 return bbunpack(argv, unpack_gunzip, make_new_name_gunzip, NULL);
302}
303#endif
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324#if ENABLE_BUNZIP2
325static
326IF_DESKTOP(long long) int FAST_FUNC unpack_bunzip2(transformer_aux_data_t *aux)
327{
328 return unpack_bz2_stream(aux, STDIN_FILENO, STDOUT_FILENO);
329}
330int bunzip2_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
331int bunzip2_main(int argc UNUSED_PARAM, char **argv)
332{
333 getopt32(argv, "cfvdt");
334 argv += optind;
335 if (applet_name[2] == 'c')
336 option_mask32 |= OPT_STDOUT;
337
338 return bbunpack(argv, unpack_bunzip2, make_new_name_generic, "bz2");
339}
340#endif
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392#if ENABLE_UNLZMA
393static
394IF_DESKTOP(long long) int FAST_FUNC unpack_unlzma(transformer_aux_data_t *aux)
395{
396 return unpack_lzma_stream(aux, STDIN_FILENO, STDOUT_FILENO);
397}
398int unlzma_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
399int unlzma_main(int argc UNUSED_PARAM, char **argv)
400{
401 IF_LZMA(int opts =) getopt32(argv, "cfvdt");
402# if ENABLE_LZMA
403
404 if (applet_name[2] == 'm' && !(opts & (OPT_DECOMPRESS|OPT_TEST)))
405 bb_show_usage();
406# endif
407
408 if (applet_name[2] == 'c')
409 option_mask32 |= OPT_STDOUT;
410
411 argv += optind;
412 return bbunpack(argv, unpack_unlzma, make_new_name_generic, "lzma");
413}
414#endif
415
416
417#if ENABLE_UNXZ
418static
419IF_DESKTOP(long long) int FAST_FUNC unpack_unxz(transformer_aux_data_t *aux)
420{
421 return unpack_xz_stream(aux, STDIN_FILENO, STDOUT_FILENO);
422}
423int unxz_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
424int unxz_main(int argc UNUSED_PARAM, char **argv)
425{
426 IF_XZ(int opts =) getopt32(argv, "cfvdt");
427# if ENABLE_XZ
428
429 if (applet_name[2] == '\0' && !(opts & (OPT_DECOMPRESS|OPT_TEST)))
430 bb_show_usage();
431# endif
432
433 if (applet_name[2] == 'c')
434 option_mask32 |= OPT_STDOUT;
435
436 argv += optind;
437 return bbunpack(argv, unpack_unxz, make_new_name_generic, "xz");
438}
439#endif
440