2 * Copyright (c) 2007 Joerg Sonnenberger
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17 * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
18 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 #include "archive_platform.h"
27 __FBSDID("$FreeBSD: src/lib/libarchive/archive_read_support_compression_program.c,v 1.4 2008/06/15 10:45:57 kientzle Exp $");
29 /* This capability is only available on POSIX systems. */
30 #if !defined(HAVE_PIPE) || !defined(HAVE_FCNTL) || \
31 !(defined(HAVE_FORK) || defined(HAVE_VFORK))
34 * On non-Posix systems, allow the program to build, but choke if
35 * this function is actually invoked.
38 archive_read_support_compression_program(struct archive
*_a
, const char *cmd
)
40 archive_set_error(_a
, -1,
41 "External compression programs not supported on this platform");
42 return (ARCHIVE_FATAL
);
47 #ifdef HAVE_SYS_WAIT_H
48 # include <sys/wait.h>
70 #include "archive_private.h"
71 #include "archive_read_private.h"
73 #include "filter_fork.h"
75 struct archive_decompress_program
{
78 int child_stdin
, child_stdout
;
81 char *child_out_buf_next
;
82 size_t child_out_buf_len
, child_out_buf_avail
;
84 const char *child_in_buf
;
85 size_t child_in_buf_avail
;
88 static int archive_decompressor_program_bid(const void *, size_t);
89 static int archive_decompressor_program_finish(struct archive_read
*);
90 static int archive_decompressor_program_init(struct archive_read
*,
91 const void *, size_t);
92 static ssize_t
archive_decompressor_program_read_ahead(struct archive_read
*,
93 const void **, size_t);
94 static ssize_t
archive_decompressor_program_read_consume(struct archive_read
*,
98 archive_read_support_compression_program(struct archive
*_a
, const char *cmd
)
100 struct archive_read
*a
= (struct archive_read
*)_a
;
101 struct decompressor_t
*decompressor
;
103 if (cmd
== NULL
|| *cmd
== '\0')
104 return (ARCHIVE_WARN
);
106 decompressor
= __archive_read_register_compression(a
,
107 archive_decompressor_program_bid
,
108 archive_decompressor_program_init
);
109 if (decompressor
== NULL
)
110 return (ARCHIVE_WARN
);
112 decompressor
->config
= strdup(cmd
);
117 * If the user used us to register, they must really want us to
118 * handle it, so this module always bids INT_MAX.
121 archive_decompressor_program_bid(const void *buff
, size_t len
)
123 (void)buff
; /* UNUSED */
124 (void)len
; /* UNUSED */
126 return (INT_MAX
); /* Default: We'll take it. */
130 child_read(struct archive_read
*a
, char *buf
, size_t buf_len
)
132 struct archive_decompress_program
*state
= a
->decompressor
->data
;
133 ssize_t ret
, requested
;
134 const void *child_buf
;
136 if (state
->child_stdout
== -1)
143 requested
= buf_len
> SSIZE_MAX
? SSIZE_MAX
: buf_len
;
146 ret
= read(state
->child_stdout
, buf
, requested
);
147 } while (ret
== -1 && errno
== EINTR
);
151 if (ret
== 0 || (ret
== -1 && errno
== EPIPE
)) {
152 close(state
->child_stdout
);
153 state
->child_stdout
= -1;
156 if (ret
== -1 && errno
!= EAGAIN
)
159 if (state
->child_in_buf_avail
== 0) {
160 child_buf
= state
->child_in_buf
;
161 ret
= (a
->client_reader
)(&a
->archive
,
162 a
->client_data
,&child_buf
);
163 state
->child_in_buf
= (const char *)child_buf
;
166 close(state
->child_stdin
);
167 state
->child_stdin
= -1;
168 fcntl(state
->child_stdout
, F_SETFL
, 0);
172 close(state
->child_stdin
);
173 state
->child_stdin
= -1;
174 fcntl(state
->child_stdout
, F_SETFL
, 0);
177 state
->child_in_buf_avail
= ret
;
180 if (state
->child_stdin
== -1) {
181 fcntl(state
->child_stdout
, F_SETFL
, 0);
182 __archive_check_child(state
->child_stdin
, state
->child_stdout
);
187 ret
= write(state
->child_stdin
, state
->child_in_buf
,
188 state
->child_in_buf_avail
);
189 } while (ret
== -1 && errno
== EINTR
);
192 state
->child_in_buf
+= ret
;
193 state
->child_in_buf_avail
-= ret
;
195 } else if (ret
== -1 && errno
== EAGAIN
) {
196 __archive_check_child(state
->child_stdin
, state
->child_stdout
);
198 } else if (ret
== 0 || (ret
== -1 && errno
== EPIPE
)) {
199 close(state
->child_stdin
);
200 state
->child_stdin
= -1;
201 fcntl(state
->child_stdout
, F_SETFL
, 0);
204 close(state
->child_stdin
);
205 state
->child_stdin
= -1;
206 fcntl(state
->child_stdout
, F_SETFL
, 0);
212 archive_decompressor_program_init(struct archive_read
*a
, const void *buff
, size_t n
)
214 struct archive_decompress_program
*state
;
215 const char *cmd
= a
->decompressor
->config
;
216 const char *prefix
= "Program: ";
219 state
= (struct archive_decompress_program
*)malloc(sizeof(*state
));
221 archive_set_error(&a
->archive
, ENOMEM
,
222 "Can't allocate input data");
223 return (ARCHIVE_FATAL
);
226 a
->archive
.compression_code
= ARCHIVE_COMPRESSION_PROGRAM
;
227 state
->description
= (char *)malloc(strlen(prefix
) + strlen(cmd
) + 1);
228 strcpy(state
->description
, prefix
);
229 strcat(state
->description
, cmd
);
230 a
->archive
.compression_name
= state
->description
;
232 state
->child_out_buf_next
= state
->child_out_buf
= malloc(65536);
233 if (!state
->child_out_buf
) {
235 archive_set_error(&a
->archive
, ENOMEM
,
236 "Can't allocate filter buffer");
237 return (ARCHIVE_FATAL
);
239 state
->child_out_buf_len
= 65536;
240 state
->child_out_buf_avail
= 0;
242 state
->child_in_buf
= buff
;
243 state
->child_in_buf_avail
= n
;
245 if ((state
->child
= __archive_create_child(cmd
,
246 &state
->child_stdin
, &state
->child_stdout
)) == -1) {
247 free(state
->child_out_buf
);
249 archive_set_error(&a
->archive
, EINVAL
,
250 "Can't initialise filter");
251 return (ARCHIVE_FATAL
);
254 a
->decompressor
->data
= state
;
255 a
->decompressor
->read_ahead
= archive_decompressor_program_read_ahead
;
256 a
->decompressor
->consume
= archive_decompressor_program_read_consume
;
257 a
->decompressor
->skip
= NULL
;
258 a
->decompressor
->finish
= archive_decompressor_program_finish
;
260 /* XXX Check that we can read at least one byte? */
265 archive_decompressor_program_read_ahead(struct archive_read
*a
, const void **buff
,
268 struct archive_decompress_program
*state
;
271 state
= (struct archive_decompress_program
*)a
->decompressor
->data
;
273 if (min
> state
->child_out_buf_len
)
274 min
= state
->child_out_buf_len
;
276 while (state
->child_stdout
!= -1 && min
> state
->child_out_buf_avail
) {
277 if (state
->child_out_buf
!= state
->child_out_buf_next
) {
278 memmove(state
->child_out_buf
, state
->child_out_buf_next
,
279 state
->child_out_buf_avail
);
280 state
->child_out_buf_next
= state
->child_out_buf
;
283 bytes_read
= child_read(a
,
284 state
->child_out_buf
+ state
->child_out_buf_avail
,
285 state
->child_out_buf_len
- state
->child_out_buf_avail
);
286 if (bytes_read
== -1)
290 state
->child_out_buf_avail
+= bytes_read
;
291 a
->archive
.raw_position
+= bytes_read
;
294 *buff
= state
->child_out_buf_next
;
295 return (state
->child_out_buf_avail
);
299 archive_decompressor_program_read_consume(struct archive_read
*a
, size_t request
)
301 struct archive_decompress_program
*state
;
303 state
= (struct archive_decompress_program
*)a
->decompressor
->data
;
305 state
->child_out_buf_next
+= request
;
306 state
->child_out_buf_avail
-= request
;
308 a
->archive
.file_position
+= request
;
313 archive_decompressor_program_finish(struct archive_read
*a
)
315 struct archive_decompress_program
*state
;
318 state
= (struct archive_decompress_program
*)a
->decompressor
->data
;
320 /* Release our configuration data. */
321 free(a
->decompressor
->config
);
322 a
->decompressor
->config
= NULL
;
324 /* Shut down the child. */
325 if (state
->child_stdin
!= -1)
326 close(state
->child_stdin
);
327 if (state
->child_stdout
!= -1)
328 close(state
->child_stdout
);
329 while (waitpid(state
->child
, &status
, 0) == -1 && errno
== EINTR
)
332 /* Release our private data. */
333 free(state
->child_out_buf
);
334 free(state
->description
);
336 a
->decompressor
->data
= NULL
;
341 #endif /* !defined(HAVE_PIPE) || !defined(HAVE_VFORK) || !defined(HAVE_FCNTL) */