1 /* vi: set sw=4 ts=4: */
3 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
7 #include "bb_archive.h"
9 void FAST_FUNC
init_transformer_state(transformer_state_t
*xstate
)
11 memset(xstate
, 0, sizeof(*xstate
));
14 int FAST_FUNC
check_signature16(transformer_state_t
*xstate
, unsigned magic16
)
16 if (!xstate
->signature_skipped
) {
18 if (full_read(xstate
->src_fd
, &magic2
, 2) != 2 || magic2
!= magic16
) {
19 bb_error_msg("invalid magic");
22 xstate
->signature_skipped
= 2;
27 ssize_t FAST_FUNC
transformer_write(transformer_state_t
*xstate
, const void *buf
, size_t bufsize
)
31 if (xstate
->mem_output_size_max
!= 0) {
32 size_t pos
= xstate
->mem_output_size
;
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
);
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';
48 nwrote
= full_write(xstate
->dst_fd
, buf
, bufsize
);
49 if (nwrote
!= (ssize_t
)bufsize
) {
50 bb_perror_msg("write");
59 ssize_t FAST_FUNC
xtransformer_write(transformer_state_t
*xstate
, const void *buf
, size_t bufsize
)
61 ssize_t nwrote
= transformer_write(xstate
, buf
, bufsize
);
62 if (nwrote
!= (ssize_t
)bufsize
) {
68 void check_errors_in_children(int signo
)
73 /* block waiting for any child */
74 if (wait(&status
) < 0)
76 return; /* probably there are no children */
80 /* Wait for any child without blocking */
82 if (wait_any_nohang(&status
) < 0)
84 /* wait failed?! I'm confused... */
87 /*if (WIFEXITED(status) && WEXITSTATUS(status) == 0)*/
88 /* On Linux, the above can be checked simply as: */
90 /* this child exited with 0 */
93 if (!WIFSIGNALED(status) && !WIFEXITED(status)) ???;
99 /* transformer(), more than meets the eye */
101 void FAST_FUNC
fork_transformer(int fd
,
102 int signature_skipped
,
103 IF_DESKTOP(long long) int FAST_FUNC (*transformer
)(transformer_state_t
*xstate
)
106 void FAST_FUNC
fork_transformer(int fd
, const char *transform_prog
)
109 struct fd_pair fd_pipe
;
112 xpiped_pair(fd_pipe
);
113 pid
= BB_MMU
? xfork() : xvfork();
116 close(fd_pipe
.rd
); /* we don't want to read from the parent */
117 // FIXME: error check?
120 IF_DESKTOP(long long) int r
;
121 transformer_state_t xstate
;
122 init_transformer_state(&xstate
);
123 xstate
.signature_skipped
= signature_skipped
;
125 xstate
.dst_fd
= fd_pipe
.wr
;
126 r
= transformer(&xstate
);
127 if (ENABLE_FEATURE_CLEAN_UP
) {
128 close(fd_pipe
.wr
); /* send EOF */
131 /* must be _exit! bug was actually seen here */
132 _exit(/*error if:*/ r
< 0);
138 xmove_fd(fd_pipe
.wr
, 1);
139 argv
[0] = (char*)transform_prog
;
140 argv
[1] = (char*)"-cf";
141 argv
[2] = (char*)"-";
143 BB_EXECVP(transform_prog
, argv
);
144 bb_perror_msg_and_die("can't execute '%s'", transform_prog
);
151 close(fd_pipe
.wr
); /* don't want to write to the child */
152 xmove_fd(fd_pipe
.rd
, fd
);
156 #if SEAMLESS_COMPRESSION
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.
161 static transformer_state_t
*setup_transformer_on_fd(int fd
, int fail_if_not_compressed
)
168 transformer_state_t
*xstate
;
170 xstate
= xzalloc(sizeof(*xstate
));
172 xstate
->signature_skipped
= 2;
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
180 xstate
->xformer
= unpack_gz_stream
;
181 USE_FOR_NOMMU(xstate
->xformer_prog
= "gunzip";)
184 if (ENABLE_FEATURE_SEAMLESS_Z
185 && magic
.b16
[0] == COMPRESS_MAGIC
187 xstate
->xformer
= unpack_Z_stream
;
188 USE_FOR_NOMMU(xstate
->xformer_prog
= "uncompress";)
191 if (ENABLE_FEATURE_SEAMLESS_BZ2
192 && magic
.b16
[0] == BZIP2_MAGIC
194 xstate
->xformer
= unpack_bz2_stream
;
195 USE_FOR_NOMMU(xstate
->xformer_prog
= "bunzip2";)
198 if (ENABLE_FEATURE_SEAMLESS_XZ
199 && magic
.b16
[0] == XZ_MAGIC1
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";)
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")
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.
221 // USE_FOR_MMU(xstate->xformer = copy_stream;)
222 // USE_FOR_NOMMU(xstate->xformer_prog = "cat";)
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.
231 int FAST_FUNC
setup_unzip_on_fd(int fd
, int fail_if_not_compressed
)
233 transformer_state_t
*xstate
= setup_transformer_on_fd(fd
, fail_if_not_compressed
);
235 if (!xstate
|| !xstate
->xformer
) {
241 fork_transformer_with_no_sig(xstate
->src_fd
, xstate
->xformer
);
243 /* NOMMU version of fork_transformer execs
244 * an external unzipper that wants
245 * file position at the start of the file.
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
);
255 static transformer_state_t
*open_transformer(const char *fname
, int fail_if_not_compressed
)
257 transformer_state_t
*xstate
;
260 fd
= open(fname
, O_RDONLY
);
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
));
270 xstate
->xformer
= unpack_lzma_stream
;
271 USE_FOR_NOMMU(xstate
->xformer_prog
= "unlzma";)
276 xstate
= setup_transformer_on_fd(fd
, fail_if_not_compressed
);
281 int FAST_FUNC
open_zipped(const char *fname
, int fail_if_not_compressed
)
284 transformer_state_t
*xstate
;
286 xstate
= open_transformer(fname
, fail_if_not_compressed
);
292 if (xstate
->xformer
) {
293 fork_transformer_with_no_sig(fd
, xstate
->xformer
);
295 /* the file is not compressed */
296 xlseek(fd
, - xstate
->signature_skipped
, SEEK_CUR
);
297 xstate
->signature_skipped
= 0;
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 */
312 void* FAST_FUNC
xmalloc_open_zipped_read_close(const char *fname
, size_t *maxsz_p
)
315 transformer_state_t
*xstate
;
318 xstate
= open_transformer(fname
, /*fail_if_not_compressed:*/ 0);
319 if (!xstate
) /* file open error */
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
;
330 *maxsz_p
= xstate
->mem_output_size
;
333 /* File is not compressed */
335 xlseek(xstate
->src_fd
, - xstate
->signature_skipped
, SEEK_CUR
);
336 xstate
->signature_skipped
= 0;
337 image
= xmalloc_read(xstate
->src_fd
, maxsz_p
);
341 bb_perror_msg("read error from '%s'", fname
);
342 close(xstate
->src_fd
);
346 /* This version forks a subprocess - much more expensive */
350 fd
= open_zipped(fname
, /*fail_if_not_compressed:*/ 0);
354 image
= xmalloc_read(fd
, maxsz_p
);
356 bb_perror_msg("read error from '%s'", fname
);
362 #endif /* SEAMLESS_COMPRESSION */