source: MondoRescue/branches/3.3/mindi-busybox/archival/libarchive/open_transformer.c@ 3626

Last change on this file since 3626 was 3621, checked in by Bruno Cornec, 10 years ago

New 3?3 banch for incorporation of latest busybox 1.25. Changing minor version to handle potential incompatibilities.

  • Property svn:eol-style set to native
File size: 8.8 KB
Line 
1/* vi: set sw=4 ts=4: */
2/*
3 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
4 */
5
6#include "libbb.h"
7#include "bb_archive.h"
8
9void FAST_FUNC init_transformer_state(transformer_state_t *xstate)
10{
11 memset(xstate, 0, sizeof(*xstate));
12}
13
14int FAST_FUNC check_signature16(transformer_state_t *xstate, unsigned magic16)
15{
16 if (!xstate->signature_skipped) {
17 uint16_t magic2;
18 if (full_read(xstate->src_fd, &magic2, 2) != 2 || magic2 != magic16) {
19 bb_error_msg("invalid magic");
20 return -1;
21 }
22 xstate->signature_skipped = 2;
23 }
24 return 0;
25}
26
27ssize_t FAST_FUNC transformer_write(transformer_state_t *xstate, const void *buf, size_t bufsize)
28{
29 ssize_t nwrote;
30
31 if (xstate->mem_output_size_max != 0) {
32 size_t pos = xstate->mem_output_size;
33 size_t size;
34
35 size = (xstate->mem_output_size += bufsize);
36 if (size > xstate->mem_output_size_max) {
37 free(xstate->mem_output_buf);
38 xstate->mem_output_buf = NULL;
39 bb_perror_msg("buffer %u too small", (unsigned)xstate->mem_output_size_max);
40 nwrote = -1;
41 goto ret;
42 }
43 xstate->mem_output_buf = xrealloc(xstate->mem_output_buf, size + 1);
44 memcpy(xstate->mem_output_buf + pos, buf, bufsize);
45 xstate->mem_output_buf[size] = '\0';
46 nwrote = bufsize;
47 } else {
48 nwrote = full_write(xstate->dst_fd, buf, bufsize);
49 if (nwrote != (ssize_t)bufsize) {
50 bb_perror_msg("write");
51 nwrote = -1;
52 goto ret;
53 }
54 }
55 ret:
56 return nwrote;
57}
58
59ssize_t FAST_FUNC xtransformer_write(transformer_state_t *xstate, const void *buf, size_t bufsize)
60{
61 ssize_t nwrote = transformer_write(xstate, buf, bufsize);
62 if (nwrote != (ssize_t)bufsize) {
63 xfunc_die();
64 }
65 return nwrote;
66}
67
68void check_errors_in_children(int signo)
69{
70 int status;
71
72 if (!signo) {
73 /* block waiting for any child */
74 if (wait(&status) < 0)
75//FIXME: check EINTR?
76 return; /* probably there are no children */
77 goto check_status;
78 }
79
80 /* Wait for any child without blocking */
81 for (;;) {
82 if (wait_any_nohang(&status) < 0)
83//FIXME: check EINTR?
84 /* wait failed?! I'm confused... */
85 return;
86 check_status:
87 /*if (WIFEXITED(status) && WEXITSTATUS(status) == 0)*/
88 /* On Linux, the above can be checked simply as: */
89 if (status == 0)
90 /* this child exited with 0 */
91 continue;
92 /* Cannot happen:
93 if (!WIFSIGNALED(status) && !WIFEXITED(status)) ???;
94 */
95 bb_got_signal = 1;
96 }
97}
98
99/* transformer(), more than meets the eye */
100#if BB_MMU
101void FAST_FUNC fork_transformer(int fd,
102 int signature_skipped,
103 IF_DESKTOP(long long) int FAST_FUNC (*transformer)(transformer_state_t *xstate)
104)
105#else
106void FAST_FUNC fork_transformer(int fd, const char *transform_prog)
107#endif
108{
109 struct fd_pair fd_pipe;
110 int pid;
111
112 xpiped_pair(fd_pipe);
113 pid = BB_MMU ? xfork() : xvfork();
114 if (pid == 0) {
115 /* Child */
116 close(fd_pipe.rd); /* we don't want to read from the parent */
117 // FIXME: error check?
118#if BB_MMU
119 {
120 IF_DESKTOP(long long) int r;
121 transformer_state_t xstate;
122 init_transformer_state(&xstate);
123 xstate.signature_skipped = signature_skipped;
124 xstate.src_fd = fd;
125 xstate.dst_fd = fd_pipe.wr;
126 r = transformer(&xstate);
127 if (ENABLE_FEATURE_CLEAN_UP) {
128 close(fd_pipe.wr); /* send EOF */
129 close(fd);
130 }
131 /* must be _exit! bug was actually seen here */
132 _exit(/*error if:*/ r < 0);
133 }
134#else
135 {
136 char *argv[4];
137 xmove_fd(fd, 0);
138 xmove_fd(fd_pipe.wr, 1);
139 argv[0] = (char*)transform_prog;
140 argv[1] = (char*)"-cf";
141 argv[2] = (char*)"-";
142 argv[3] = NULL;
143 BB_EXECVP(transform_prog, argv);
144 bb_perror_msg_and_die("can't execute '%s'", transform_prog);
145 }
146#endif
147 /* notreached */
148 }
149
150 /* parent process */
151 close(fd_pipe.wr); /* don't want to write to the child */
152 xmove_fd(fd_pipe.rd, fd);
153}
154
155
156#if SEAMLESS_COMPRESSION
157
158/* Used by e.g. rpm which gives us a fd without filename,
159 * thus we can't guess the format from filename's extension.
160 */
161static transformer_state_t *setup_transformer_on_fd(int fd, int fail_if_not_compressed)
162{
163 union {
164 uint8_t b[4];
165 uint16_t b16[2];
166 uint32_t b32[1];
167 } magic;
168 transformer_state_t *xstate;
169
170 xstate = xzalloc(sizeof(*xstate));
171 xstate->src_fd = fd;
172 xstate->signature_skipped = 2;
173
174 /* .gz and .bz2 both have 2-byte signature, and their
175 * unpack_XXX_stream wants this header skipped. */
176 xread(fd, magic.b16, sizeof(magic.b16[0]));
177 if (ENABLE_FEATURE_SEAMLESS_GZ
178 && magic.b16[0] == GZIP_MAGIC
179 ) {
180 xstate->xformer = unpack_gz_stream;
181 USE_FOR_NOMMU(xstate->xformer_prog = "gunzip";)
182 goto found_magic;
183 }
184 if (ENABLE_FEATURE_SEAMLESS_Z
185 && magic.b16[0] == COMPRESS_MAGIC
186 ) {
187 xstate->xformer = unpack_Z_stream;
188 USE_FOR_NOMMU(xstate->xformer_prog = "uncompress";)
189 goto found_magic;
190 }
191 if (ENABLE_FEATURE_SEAMLESS_BZ2
192 && magic.b16[0] == BZIP2_MAGIC
193 ) {
194 xstate->xformer = unpack_bz2_stream;
195 USE_FOR_NOMMU(xstate->xformer_prog = "bunzip2";)
196 goto found_magic;
197 }
198 if (ENABLE_FEATURE_SEAMLESS_XZ
199 && magic.b16[0] == XZ_MAGIC1
200 ) {
201 xstate->signature_skipped = 6;
202 xread(fd, magic.b32, sizeof(magic.b32[0]));
203 if (magic.b32[0] == XZ_MAGIC2) {
204 xstate->xformer = unpack_xz_stream;
205 USE_FOR_NOMMU(xstate->xformer_prog = "unxz";)
206 goto found_magic;
207 }
208 }
209
210 /* No known magic seen */
211 if (fail_if_not_compressed)
212 bb_error_msg_and_die("no gzip"
213 IF_FEATURE_SEAMLESS_BZ2("/bzip2")
214 IF_FEATURE_SEAMLESS_XZ("/xz")
215 " magic");
216
217 /* Some callers expect this function to "consume" fd
218 * even if data is not compressed. In this case,
219 * we return a state with trivial transformer.
220 */
221// USE_FOR_MMU(xstate->xformer = copy_stream;)
222// USE_FOR_NOMMU(xstate->xformer_prog = "cat";)
223
224 found_magic:
225 return xstate;
226}
227
228/* Used by e.g. rpm which gives us a fd without filename,
229 * thus we can't guess the format from filename's extension.
230 */
231int FAST_FUNC setup_unzip_on_fd(int fd, int fail_if_not_compressed)
232{
233 transformer_state_t *xstate = setup_transformer_on_fd(fd, fail_if_not_compressed);
234
235 if (!xstate || !xstate->xformer) {
236 free(xstate);
237 return 1;
238 }
239
240# if BB_MMU
241 fork_transformer_with_no_sig(xstate->src_fd, xstate->xformer);
242# else
243 /* NOMMU version of fork_transformer execs
244 * an external unzipper that wants
245 * file position at the start of the file.
246 */
247 xlseek(fd, - xstate->signature_skipped, SEEK_CUR);
248 xstate->signature_skipped = 0;
249 fork_transformer_with_sig(xstate->src_fd, xstate->xformer, xstate->xformer_prog);
250# endif
251 free(xstate);
252 return 0;
253}
254
255static transformer_state_t *open_transformer(const char *fname, int fail_if_not_compressed)
256{
257 transformer_state_t *xstate;
258 int fd;
259
260 fd = open(fname, O_RDONLY);
261 if (fd < 0)
262 return NULL;
263
264 if (ENABLE_FEATURE_SEAMLESS_LZMA) {
265 /* .lzma has no header/signature, can only detect it by extension */
266 char *sfx = strrchr(fname, '.');
267 if (sfx && strcmp(sfx+1, "lzma") == 0) {
268 xstate = xzalloc(sizeof(*xstate));
269 xstate->src_fd = fd;
270 xstate->xformer = unpack_lzma_stream;
271 USE_FOR_NOMMU(xstate->xformer_prog = "unlzma";)
272 return xstate;
273 }
274 }
275
276 xstate = setup_transformer_on_fd(fd, fail_if_not_compressed);
277
278 return xstate;
279}
280
281int FAST_FUNC open_zipped(const char *fname, int fail_if_not_compressed)
282{
283 int fd;
284 transformer_state_t *xstate;
285
286 xstate = open_transformer(fname, fail_if_not_compressed);
287 if (!xstate)
288 return -1;
289
290 fd = xstate->src_fd;
291# if BB_MMU
292 if (xstate->xformer) {
293 fork_transformer_with_no_sig(fd, xstate->xformer);
294 } else {
295 /* the file is not compressed */
296 xlseek(fd, - xstate->signature_skipped, SEEK_CUR);
297 xstate->signature_skipped = 0;
298 }
299# else
300 /* NOMMU can't avoid the seek :( */
301 xlseek(fd, - xstate->signature_skipped, SEEK_CUR);
302 xstate->signature_skipped = 0;
303 if (xstate->xformer) {
304 fork_transformer_with_sig(fd, xstate->xformer, xstate->xformer_prog);
305 } /* else: the file is not compressed */
306# endif
307
308 free(xstate);
309 return fd;
310}
311
312void* FAST_FUNC xmalloc_open_zipped_read_close(const char *fname, size_t *maxsz_p)
313{
314# if 1
315 transformer_state_t *xstate;
316 char *image;
317
318 xstate = open_transformer(fname, /*fail_if_not_compressed:*/ 0);
319 if (!xstate) /* file open error */
320 return NULL;
321
322 image = NULL;
323 if (xstate->xformer) {
324 /* In-memory decompression */
325 xstate->mem_output_size_max = maxsz_p ? *maxsz_p : (size_t)(INT_MAX - 4095);
326 xstate->xformer(xstate);
327 if (xstate->mem_output_buf) {
328 image = xstate->mem_output_buf;
329 if (maxsz_p)
330 *maxsz_p = xstate->mem_output_size;
331 }
332 } else {
333 /* File is not compressed */
334//FIXME: avoid seek
335 xlseek(xstate->src_fd, - xstate->signature_skipped, SEEK_CUR);
336 xstate->signature_skipped = 0;
337 image = xmalloc_read(xstate->src_fd, maxsz_p);
338 }
339
340 if (!image)
341 bb_perror_msg("read error from '%s'", fname);
342 close(xstate->src_fd);
343 free(xstate);
344 return image;
345# else
346 /* This version forks a subprocess - much more expensive */
347 int fd;
348 char *image;
349
350 fd = open_zipped(fname, /*fail_if_not_compressed:*/ 0);
351 if (fd < 0)
352 return NULL;
353
354 image = xmalloc_read(fd, maxsz_p);
355 if (!image)
356 bb_perror_msg("read error from '%s'", fname);
357 close(fd);
358 return image;
359# endif
360}
361
362#endif /* SEAMLESS_COMPRESSION */
Note: See TracBrowser for help on using the repository browser.