1 /* vi: set sw=4 ts=4: */
3 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
10 #include "bb/private/config.h"
11 #include "bb/archival/libarchive/private.h"
13 #include "bb/lib/public.h"
14 #include "bb/archival/libarchive/public.h"
16 BB_STATIC
void bb_archive_init_transformer_state(bb_archive_transformer_state_t
*xstate
)
18 memset(xstate
, 0, sizeof(*xstate
));
21 BB_STATIC
int bb_archive_check_signature16(bb_archive_transformer_state_t
*xstate
, unsigned magic16
)
23 if (!xstate
->signature_skipped
) {
25 if (bb_full_read(xstate
->src_fd
, &magic2
, 2) != 2 || magic2
!= magic16
) {
26 bb_simple_error_msg("invalid magic");
29 xstate
->signature_skipped
= 2;
34 BB_STATIC ssize_t
bb_archive_transformer_write(bb_archive_transformer_state_t
*xstate
,
35 const void *buf
, size_t bufsize
)
39 if (xstate
->mem_output_size_max
!= 0) {
40 size_t pos
= xstate
->mem_output_size
;
43 size
= (xstate
->mem_output_size
+= bufsize
);
44 if (size
> xstate
->mem_output_size_max
) {
45 free(xstate
->mem_output_buf
);
46 xstate
->mem_output_buf
= NULL
;
47 bb_perror_msg("buffer %u too small", (unsigned)xstate
->mem_output_size_max
);
51 xstate
->mem_output_buf
= bb_xrealloc(xstate
->mem_output_buf
, size
+ 1);
52 memcpy(xstate
->mem_output_buf
+ pos
, buf
, bufsize
);
53 xstate
->mem_output_buf
[size
] = '\0';
56 nwrote
= bb_full_write(xstate
->dst_fd
, buf
, bufsize
);
57 if (nwrote
!= (ssize_t
)bufsize
) {
58 bb_simple_perror_msg("write");
67 BB_STATIC ssize_t
bb_archive_xtransformer_write(bb_archive_transformer_state_t
*xstate
,
68 const void *buf
, size_t bufsize
)
70 ssize_t nwrote
= bb_archive_transformer_write(xstate
, buf
, bufsize
);
71 if (nwrote
!= (ssize_t
)bufsize
) {
77 /* transformer(), more than meets the eye */
78 BB_STATIC
void bb_archive_fork_transformer(int fd
, int signature_skipped
,
79 long (*transformer
)(bb_archive_transformer_state_t
*xstate
))
81 struct bb_fd_pair fd_pipe
;
84 bb_xpiped_pair(fd_pipe
);
88 bb_archive_transformer_state_t xstate
;
90 close(fd_pipe
.rd
); /* we don't want to read from the parent */
91 // FIXME: error check?
93 bb_archive_init_transformer_state(&xstate
);
94 xstate
.signature_skipped
= signature_skipped
;
96 xstate
.dst_fd
= fd_pipe
.wr
;
97 r
= transformer(&xstate
);
98 /* must be _exit! bug was actually seen here */
99 _exit(/*error if:*/ r
< 0);
104 close(fd_pipe
.wr
); /* don't want to write to the child */
105 bb_xmove_fd(fd_pipe
.rd
, fd
);
107 /* Used by e.g. rpm which gives us a fd without filename,
108 * thus we can't guess the format from filename's extension.
110 BB_STATIC bb_archive_transformer_state_t
*bb_archive_setup_transformer_on_fd(int fd
, int fail_if_not_compressed
)
112 bb_archive_transformer_state_t
*xstate
;
114 xstate
= bb_xzalloc(sizeof(*xstate
));
117 /* .gz and .bz2 both have 2-byte signature, and their
118 * unpack_XXX_stream wants this header skipped. */
119 xstate
->signature_skipped
= 2;
120 bb_xread(fd
, xstate
->magic
.b16
, 2);
121 if (xstate
->magic
.b16
[0] == BB_GZIP_MAGIC
) {
122 xstate
->xformer
= bb_archive_unpack_gz_stream
;
125 if (xstate
->magic
.b16
[0] == BB_COMPRESS_MAGIC
) {
126 xstate
->xformer
= bb_archive_unpack_Z_stream
;
129 if (xstate
->magic
.b16
[0] == BB_BZIP2_MAGIC
) {
130 xstate
->xformer
= bb_archive_unpack_bz2_stream
;
133 if (xstate
->magic
.b16
[0] == BB_XZ_MAGIC1
) {
135 xstate
->signature_skipped
= 6;
136 bb_xread(fd
, &xstate
->magic
.b16
[1], 4);
137 v32
= *(uint32_t*)(&xstate
->magic
.b16
[1]);
138 if (v32
== BB_XZ_MAGIC2
) {
139 xstate
->xformer
= bb_archive_unpack_xz_stream
;
144 /* No known magic seen */
145 if (fail_if_not_compressed
)
146 bb_simple_error_msg_and_die("no gzip"
151 /* Some callers expect this function to "consume" fd
152 * even if data is not compressed. In this case,
153 * we return a state with trivial transformer.
155 // USE_FOR_MMU(xstate->xformer = copy_stream;)
156 // USE_FOR_NOMMU(xstate->xformer_prog = "cat";)
162 BB_STATIC bb_archive_transformer_state_t
*bb_archive_open_transformer(const char *fname
,
163 int fail_if_not_compressed
)
165 bb_archive_transformer_state_t
*xstate
;
168 fd
= open(fname
, O_RDONLY
);
172 /* .lzma has no header/signature, can only detect it by extension */
173 if (bb_is_suffixed_with(fname
, ".lzma")) {
174 xstate
= bb_xzalloc(sizeof(*xstate
));
176 xstate
->xformer
= bb_archive_unpack_lzma_stream
;
180 xstate
= bb_archive_setup_transformer_on_fd(fd
, fail_if_not_compressed
);
185 BB_STATIC
void bb_archive_fork_transformer_and_free(bb_archive_transformer_state_t
*xstate
)
187 bb_archive_fork_transformer_with_no_sig(xstate
->src_fd
, xstate
->xformer
);
191 /* Used by e.g. rpm which gives us a fd without filename,
192 * thus we can't guess the format from filename's extension.
194 BB_STATIC
int bb_archive_setup_unzip_on_fd(int fd
, int fail_if_not_compressed
)
196 bb_archive_transformer_state_t
*xstate
= bb_archive_setup_transformer_on_fd(fd
,
197 fail_if_not_compressed
);
199 if (!xstate
->xformer
) {
204 bb_archive_fork_transformer_and_free(xstate
);
208 BB_STATIC
int bb_archive_open_zipped(const char *fname
, int fail_if_not_compressed
)
211 bb_archive_transformer_state_t
*xstate
;
213 xstate
= bb_archive_open_transformer(fname
, fail_if_not_compressed
);
219 if (xstate
->xformer
) {
220 bb_archive_fork_transformer_with_no_sig(fd
, xstate
->xformer
);
222 /* the file is not compressed */
223 bb_xlseek(fd
, - xstate
->signature_skipped
, SEEK_CUR
);
224 xstate
->signature_skipped
= 0;