1
2
3
4
5
6
7
8#include "libbb.h"
9#include "unarchive.h"
10
11enum {
12 OPT_STDOUT = 0x1,
13 OPT_FORCE = 0x2,
14
15 OPT_VERBOSE = 0x4,
16 OPT_DECOMPRESS = 0x8,
17 OPT_TEST = 0x10,
18};
19
20static
21int open_to_or_warn(int to_fd, const char *filename, int flags, int mode)
22{
23 int fd = open3_or_warn(filename, flags, mode);
24 if (fd < 0) {
25 return 1;
26 }
27 xmove_fd(fd, to_fd);
28 return 0;
29}
30
31int FAST_FUNC bbunpack(char **argv,
32 char* (*make_new_name)(char *filename),
33 IF_DESKTOP(long long) int (*unpacker)(unpack_info_t *info)
34)
35{
36 struct stat stat_buf;
37 IF_DESKTOP(long long) int status;
38 char *filename, *new_name;
39 smallint exitcode = 0;
40 unpack_info_t info;
41
42 do {
43
44 new_name = NULL;
45 filename = *argv;
46
47 if (filename && LONE_DASH(filename))
48 filename = NULL;
49
50
51 if (filename) {
52 if (stat(filename, &stat_buf) != 0) {
53 bb_simple_perror_msg(filename);
54 err:
55 exitcode = 1;
56 goto free_name;
57 }
58 if (open_to_or_warn(STDIN_FILENO, filename, O_RDONLY, 0))
59 goto err;
60 }
61
62
63 if (option_mask32 & (OPT_STDOUT|OPT_TEST)) {
64 if (option_mask32 & OPT_TEST)
65 if (open_to_or_warn(STDOUT_FILENO, bb_dev_null, O_WRONLY, 0))
66 goto err;
67 filename = NULL;
68 }
69
70
71 if (filename) {
72 new_name = make_new_name(filename);
73 if (!new_name) {
74 bb_error_msg("%s: unknown suffix - ignored", filename);
75 goto err;
76 }
77
78
79 if (option_mask32 & OPT_FORCE) {
80 unlink(new_name);
81 }
82
83
84
85 if (open_to_or_warn(STDOUT_FILENO, new_name, O_WRONLY | O_CREAT | O_EXCL,
86 stat_buf.st_mode))
87 goto err;
88 }
89
90
91 if (isatty(STDIN_FILENO) && (option_mask32 & OPT_FORCE) == 0) {
92 bb_error_msg_and_die("compressed data not read from terminal, "
93 "use -f to force it");
94 }
95
96
97 info.mtime = 0;
98 status = unpacker(&info);
99 if (status < 0)
100 exitcode = 1;
101
102 if (filename) {
103 char *del = new_name;
104 if (status >= 0) {
105
106 if (info.mtime) {
107 struct utimbuf times;
108
109 times.actime = info.mtime;
110 times.modtime = info.mtime;
111
112
113
114 close(STDOUT_FILENO);
115
116 utime(new_name, ×);
117 }
118
119
120 del = filename;
121
122 if (new_name == filename)
123 filename[strlen(filename)] = '.';
124 }
125 xunlink(del);
126
127#if 0
128
129 if (ENABLE_DESKTOP && (option_mask32 & OPT_VERBOSE) && status >= 0) {
130 fprintf(stderr, "%s: %u%% - replaced with %s\n",
131 filename, (unsigned)(stat_buf.st_size*100 / (status+1)), new_name);
132 }
133#endif
134
135 free_name:
136 if (new_name != filename)
137 free(new_name);
138 }
139 } while (*argv && *++argv);
140
141 return exitcode;
142}
143
144#if ENABLE_BUNZIP2 || ENABLE_UNLZMA || ENABLE_UNCOMPRESS
145
146static
147char* make_new_name_generic(char *filename, const char *expected_ext)
148{
149 char *extension = strrchr(filename, '.');
150 if (!extension || strcmp(extension + 1, expected_ext) != 0) {
151
152
153 return NULL;
154 }
155 *extension = '\0';
156 return filename;
157}
158
159#endif
160
161
162
163
164
165
166
167
168
169#if ENABLE_BUNZIP2
170
171static
172char* make_new_name_bunzip2(char *filename)
173{
174 return make_new_name_generic(filename, "bz2");
175}
176
177static
178IF_DESKTOP(long long) int unpack_bunzip2(unpack_info_t *info UNUSED_PARAM)
179{
180 return unpack_bz2_stream_prime(STDIN_FILENO, STDOUT_FILENO);
181}
182
183int bunzip2_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
184int bunzip2_main(int argc UNUSED_PARAM, char **argv)
185{
186 getopt32(argv, "cfvdt");
187 argv += optind;
188 if (applet_name[2] == 'c')
189 option_mask32 |= OPT_STDOUT;
190
191 return bbunpack(argv, make_new_name_bunzip2, unpack_bunzip2);
192}
193
194#endif
195
196
197
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#if ENABLE_GUNZIP
226
227static
228char* make_new_name_gunzip(char *filename)
229{
230 char *extension = strrchr(filename, '.');
231
232 if (!extension)
233 return NULL;
234
235 extension++;
236 if (strcmp(extension, "tgz" + 1) == 0
237#if ENABLE_FEATURE_SEAMLESS_Z
238 || (extension[0] == 'Z' && extension[1] == '\0')
239#endif
240 ) {
241 extension[-1] = '\0';
242 } else if (strcmp(extension, "tgz") == 0) {
243 filename = xstrdup(filename);
244 extension = strrchr(filename, '.');
245 extension[2] = 'a';
246 extension[3] = 'r';
247 } else {
248 return NULL;
249 }
250 return filename;
251}
252
253static
254IF_DESKTOP(long long) int unpack_gunzip(unpack_info_t *info)
255{
256 IF_DESKTOP(long long) int status = -1;
257
258
259 if (xread_char(STDIN_FILENO) == 0x1f) {
260 unsigned char magic2;
261
262 magic2 = xread_char(STDIN_FILENO);
263 if (ENABLE_FEATURE_SEAMLESS_Z && magic2 == 0x9d) {
264 status = unpack_Z_stream(STDIN_FILENO, STDOUT_FILENO);
265 } else if (magic2 == 0x8b) {
266 status = unpack_gz_stream_with_info(STDIN_FILENO, STDOUT_FILENO, info);
267 } else {
268 goto bad_magic;
269 }
270 if (status < 0) {
271 bb_error_msg("error inflating");
272 }
273 } else {
274 bad_magic:
275 bb_error_msg("invalid magic");
276
277 }
278 return status;
279}
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295int gunzip_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
296int gunzip_main(int argc UNUSED_PARAM, char **argv)
297{
298 getopt32(argv, "cfvdtn");
299 argv += optind;
300
301 if (applet_name[1] == 'c')
302 option_mask32 |= OPT_STDOUT;
303
304 return bbunpack(argv, make_new_name_gunzip, unpack_gunzip);
305}
306
307#endif
308
309
310
311
312
313
314
315
316
317
318
319#if ENABLE_UNLZMA
320
321static
322char* make_new_name_unlzma(char *filename)
323{
324 return make_new_name_generic(filename, "lzma");
325}
326
327static
328IF_DESKTOP(long long) int unpack_unlzma(unpack_info_t *info UNUSED_PARAM)
329{
330 return unpack_lzma_stream(STDIN_FILENO, STDOUT_FILENO);
331}
332
333int unlzma_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
334int unlzma_main(int argc UNUSED_PARAM, char **argv)
335{
336 getopt32(argv, "cf");
337 argv += optind;
338
339 if (applet_name[4] == 'c')
340 option_mask32 |= OPT_STDOUT;
341
342 return bbunpack(argv, make_new_name_unlzma, unpack_unlzma);
343}
344
345#endif
346
347
348
349
350
351
352
353
354#if ENABLE_UNCOMPRESS
355
356static
357char* make_new_name_uncompress(char *filename)
358{
359 return make_new_name_generic(filename, "Z");
360}
361
362static
363IF_DESKTOP(long long) int unpack_uncompress(unpack_info_t *info UNUSED_PARAM)
364{
365 IF_DESKTOP(long long) int status = -1;
366
367 if ((xread_char(STDIN_FILENO) != 0x1f) || (xread_char(STDIN_FILENO) != 0x9d)) {
368 bb_error_msg("invalid magic");
369 } else {
370 status = unpack_Z_stream(STDIN_FILENO, STDOUT_FILENO);
371 }
372 return status;
373}
374
375int uncompress_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
376int uncompress_main(int argc UNUSED_PARAM, char **argv)
377{
378 getopt32(argv, "cf");
379 argv += optind;
380
381 return bbunpack(argv, make_new_name_uncompress, unpack_uncompress);
382}
383
384#endif
385