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
->check_signature
) {
18 if (full_read(xstate
->src_fd
, &magic2
, 2) != 2 || magic2
!= magic16
) {
19 bb_error_msg("invalid magic");
20 #if 0 /* possible future extension */
21 if (xstate
->check_signature
> 1)
30 ssize_t FAST_FUNC
transformer_write(transformer_state_t
*xstate
, const void *buf
, size_t bufsize
)
34 if (xstate
->mem_output_size_max
!= 0) {
35 size_t pos
= xstate
->mem_output_size
;
38 size
= (xstate
->mem_output_size
+= bufsize
);
39 if (size
> xstate
->mem_output_size_max
) {
40 free(xstate
->mem_output_buf
);
41 xstate
->mem_output_buf
= NULL
;
42 bb_perror_msg("buffer %u too small", (unsigned)xstate
->mem_output_size_max
);
46 xstate
->mem_output_buf
= xrealloc(xstate
->mem_output_buf
, size
+ 1);
47 memcpy(xstate
->mem_output_buf
+ pos
, buf
, bufsize
);
48 xstate
->mem_output_buf
[size
] = '\0';
51 nwrote
= full_write(xstate
->dst_fd
, buf
, bufsize
);
52 if (nwrote
!= (ssize_t
)bufsize
) {
53 bb_perror_msg("write");
62 ssize_t FAST_FUNC
xtransformer_write(transformer_state_t
*xstate
, const void *buf
, size_t bufsize
)
64 ssize_t nwrote
= transformer_write(xstate
, buf
, bufsize
);
65 if (nwrote
!= (ssize_t
)bufsize
) {
71 void check_errors_in_children(int signo
)
76 /* block waiting for any child */
77 if (wait(&status
) < 0)
79 return; /* probably there are no children */
83 /* Wait for any child without blocking */
85 if (wait_any_nohang(&status
) < 0)
87 /* wait failed?! I'm confused... */
90 /*if (WIFEXITED(status) && WEXITSTATUS(status) == 0)*/
91 /* On Linux, the above can be checked simply as: */
93 /* this child exited with 0 */
96 if (!WIFSIGNALED(status) && !WIFEXITED(status)) ???;
102 /* transformer(), more than meets the eye */
104 void FAST_FUNC
fork_transformer(int fd
,
106 IF_DESKTOP(long long) int FAST_FUNC (*transformer
)(transformer_state_t
*xstate
)
109 void FAST_FUNC
fork_transformer(int fd
, const char *transform_prog
)
112 struct fd_pair fd_pipe
;
115 xpiped_pair(fd_pipe
);
116 pid
= BB_MMU
? xfork() : xvfork();
119 close(fd_pipe
.rd
); /* we don't want to read from the parent */
120 // FIXME: error check?
123 IF_DESKTOP(long long) int r
;
124 transformer_state_t xstate
;
125 init_transformer_state(&xstate
);
126 xstate
.check_signature
= check_signature
;
128 xstate
.dst_fd
= fd_pipe
.wr
;
129 r
= transformer(&xstate
);
130 if (ENABLE_FEATURE_CLEAN_UP
) {
131 close(fd_pipe
.wr
); /* send EOF */
134 /* must be _exit! bug was actually seen here */
135 _exit(/*error if:*/ r
< 0);
141 xmove_fd(fd_pipe
.wr
, 1);
142 argv
[0] = (char*)transform_prog
;
143 argv
[1] = (char*)"-cf";
144 argv
[2] = (char*)"-";
146 BB_EXECVP(transform_prog
, argv
);
147 bb_perror_msg_and_die("can't execute '%s'", transform_prog
);
154 close(fd_pipe
.wr
); /* don't want to write to the child */
155 xmove_fd(fd_pipe
.rd
, fd
);
159 #if SEAMLESS_COMPRESSION
161 /* Used by e.g. rpm which gives us a fd without filename,
162 * thus we can't guess the format from filename's extension.
164 static transformer_state_t
*setup_transformer_on_fd(int fd
, int fail_if_not_compressed
)
172 transformer_state_t
*xstate
;
175 xstate
= xzalloc(sizeof(*xstate
));
178 /* .gz and .bz2 both have 2-byte signature, and their
179 * unpack_XXX_stream wants this header skipped. */
180 xread(fd
, magic
.b16
, sizeof(magic
.b16
[0]));
181 if (ENABLE_FEATURE_SEAMLESS_GZ
182 && magic
.b16
[0] == GZIP_MAGIC
184 xstate
->xformer
= unpack_gz_stream
;
185 USE_FOR_NOMMU(xstate
->xformer_prog
= "gunzip";)
188 if (ENABLE_FEATURE_SEAMLESS_BZ2
189 && magic
.b16
[0] == BZIP2_MAGIC
191 xstate
->xformer
= unpack_bz2_stream
;
192 USE_FOR_NOMMU(xstate
->xformer_prog
= "bunzip2";)
195 if (ENABLE_FEATURE_SEAMLESS_XZ
196 && magic
.b16
[0] == XZ_MAGIC1
199 xread(fd
, magic
.b32
, sizeof(magic
.b32
[0]));
200 if (magic
.b32
[0] == XZ_MAGIC2
) {
201 xstate
->xformer
= unpack_xz_stream
;
202 USE_FOR_NOMMU(xstate
->xformer_prog
= "unxz";)
207 /* No known magic seen */
208 if (fail_if_not_compressed
)
209 bb_error_msg_and_die("no gzip"
210 IF_FEATURE_SEAMLESS_BZ2("/bzip2")
211 IF_FEATURE_SEAMLESS_XZ("/xz")
214 /* Some callers expect this function to "consume" fd
215 * even if data is not compressed. In this case,
216 * we return a state with trivial transformer.
218 // USE_FOR_MMU(xstate->xformer = copy_stream;)
219 // USE_FOR_NOMMU(xstate->xformer_prog = "cat";)
220 /* fall through to seeking bck over bytes we read earlier */
222 USE_FOR_NOMMU(found_magic
:)
223 /* NOMMU version of fork_transformer execs
224 * an external unzipper that wants
225 * file position at the start of the file.
227 xlseek(fd
, offset
, SEEK_CUR
);
229 USE_FOR_MMU(found_magic
:)
230 /* In MMU case, if magic was found, seeking back is not necessary */
235 /* Used by e.g. rpm which gives us a fd without filename,
236 * thus we can't guess the format from filename's extension.
238 int FAST_FUNC
setup_unzip_on_fd(int fd
, int fail_if_not_compressed
)
240 transformer_state_t
*xstate
= setup_transformer_on_fd(fd
, fail_if_not_compressed
);
242 if (!xstate
|| !xstate
->xformer
) {
248 fork_transformer_with_no_sig(xstate
->src_fd
, xstate
->xformer
);
250 fork_transformer_with_sig(xstate
->src_fd
, xstate
->xformer
, xstate
->xformer_prog
);
256 static transformer_state_t
*open_transformer(const char *fname
, int fail_if_not_compressed
)
258 transformer_state_t
*xstate
;
261 fd
= open(fname
, O_RDONLY
);
265 if (ENABLE_FEATURE_SEAMLESS_LZMA
) {
266 /* .lzma has no header/signature, can only detect it by extension */
267 char *sfx
= strrchr(fname
, '.');
268 if (sfx
&& strcmp(sfx
+1, "lzma") == 0) {
269 xstate
= xzalloc(sizeof(*xstate
));
271 xstate
->xformer
= unpack_lzma_stream
;
272 USE_FOR_NOMMU(xstate
->xformer_prog
= "unlzma";)
277 xstate
= setup_transformer_on_fd(fd
, fail_if_not_compressed
);
282 int FAST_FUNC
open_zipped(const char *fname
, int fail_if_not_compressed
)
285 transformer_state_t
*xstate
;
287 xstate
= open_transformer(fname
, fail_if_not_compressed
);
292 if (xstate
->xformer
) {
294 fork_transformer_with_no_sig(xstate
->src_fd
, xstate
->xformer
);
296 fork_transformer_with_sig(xstate
->src_fd
, xstate
->xformer
, xstate
->xformer_prog
);
299 /* else: the file is not compressed */
305 void* FAST_FUNC
xmalloc_open_zipped_read_close(const char *fname
, size_t *maxsz_p
)
308 transformer_state_t
*xstate
;
311 xstate
= open_transformer(fname
, /*fail_if_not_compressed:*/ 0);
312 if (!xstate
) /* file open error */
316 if (xstate
->xformer
) {
317 /* In-memory decompression */
318 xstate
->mem_output_size_max
= maxsz_p
? *maxsz_p
: (size_t)(INT_MAX
- 4095);
319 xstate
->xformer(xstate
);
320 if (xstate
->mem_output_buf
) {
321 image
= xstate
->mem_output_buf
;
323 *maxsz_p
= xstate
->mem_output_size
;
326 /* File is not compressed */
327 image
= xmalloc_read(xstate
->src_fd
, maxsz_p
);
331 bb_perror_msg("read error from '%s'", fname
);
332 close(xstate
->src_fd
);
336 /* This version forks a subprocess - much more expensive */
340 fd
= open_zipped(fname
, /*fail_if_not_compressed:*/ 0);
344 image
= xmalloc_read(fd
, maxsz_p
);
346 bb_perror_msg("read error from '%s'", fname
);
352 #endif /* SEAMLESS_COMPRESSION */