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.2 2007/07/20 01:28:50 kientzle Exp $");
30 /* This capability is only available on POSIX systems. */
31 #if !defined(HAVE_PIPE) || !defined(HAVE_VFORK) || !defined(HAVE_FCNTL)
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
;
181 ret
= write(state
->child_stdin
, state
->child_in_buf
,
182 state
->child_in_buf_avail
);
183 } while (ret
== -1 && errno
== EINTR
);
186 state
->child_in_buf
+= ret
;
187 state
->child_in_buf_avail
-= ret
;
189 } else if (ret
== -1 && errno
== EAGAIN
) {
190 __archive_check_child(state
->child_stdin
, state
->child_stdout
);
192 } else if (ret
== 0 || (ret
== -1 && errno
== EPIPE
)) {
193 close(state
->child_stdin
);
194 state
->child_stdout
= -1;
195 fcntl(state
->child_stdout
, F_SETFL
, 0);
198 close(state
->child_stdin
);
199 state
->child_stdin
= -1;
200 fcntl(state
->child_stdout
, F_SETFL
, 0);
206 archive_decompressor_program_init(struct archive_read
*a
, const void *buff
, size_t n
)
208 struct archive_decompress_program
*state
;
209 const char *cmd
= a
->decompressor
->config
;
210 const char *prefix
= "Program: ";
213 state
= (struct archive_decompress_program
*)malloc(sizeof(*state
));
215 archive_set_error(&a
->archive
, ENOMEM
,
216 "Can't allocate input data");
217 return (ARCHIVE_FATAL
);
220 a
->archive
.compression_code
= ARCHIVE_COMPRESSION_PROGRAM
;
221 state
->description
= (char *)malloc(strlen(prefix
) + strlen(cmd
) + 1);
222 strcpy(state
->description
, prefix
);
223 strcat(state
->description
, cmd
);
224 a
->archive
.compression_name
= state
->description
;
226 state
->child_out_buf_next
= state
->child_out_buf
= malloc(65536);
227 if (!state
->child_out_buf
) {
229 archive_set_error(&a
->archive
, ENOMEM
,
230 "Can't allocate filter buffer");
231 return (ARCHIVE_FATAL
);
233 state
->child_out_buf_len
= 65536;
234 state
->child_out_buf_avail
= 0;
236 state
->child_in_buf
= buff
;
237 state
->child_in_buf_avail
= n
;
239 if ((state
->child
= __archive_create_child(cmd
,
240 &state
->child_stdin
, &state
->child_stdout
)) == -1) {
241 free(state
->child_out_buf
);
243 archive_set_error(&a
->archive
, EINVAL
,
244 "Can't initialise filter");
245 return (ARCHIVE_FATAL
);
248 a
->decompressor
->data
= state
;
249 a
->decompressor
->read_ahead
= archive_decompressor_program_read_ahead
;
250 a
->decompressor
->consume
= archive_decompressor_program_read_consume
;
251 a
->decompressor
->skip
= NULL
;
252 a
->decompressor
->finish
= archive_decompressor_program_finish
;
254 /* XXX Check that we can read at least one byte? */
259 archive_decompressor_program_read_ahead(struct archive_read
*a
, const void **buff
,
262 struct archive_decompress_program
*state
;
265 state
= (struct archive_decompress_program
*)a
->decompressor
->data
;
267 if (min
> state
->child_out_buf_len
)
268 min
= state
->child_out_buf_len
;
270 while (state
->child_stdout
!= -1 && min
> state
->child_out_buf_avail
) {
271 if (state
->child_out_buf
!= state
->child_out_buf_next
) {
272 memmove(state
->child_out_buf
, state
->child_out_buf_next
,
273 state
->child_out_buf_avail
);
274 state
->child_out_buf_next
= state
->child_out_buf
;
277 bytes_read
= child_read(a
,
278 state
->child_out_buf
+ state
->child_out_buf_avail
,
279 state
->child_out_buf_len
- state
->child_out_buf_avail
);
280 if (bytes_read
== -1)
284 state
->child_out_buf_avail
+= bytes_read
;
285 a
->archive
.raw_position
+= bytes_read
;
288 *buff
= state
->child_out_buf_next
;
289 return (state
->child_out_buf_avail
);
293 archive_decompressor_program_read_consume(struct archive_read
*a
, size_t request
)
295 struct archive_decompress_program
*state
;
297 state
= (struct archive_decompress_program
*)a
->decompressor
->data
;
299 state
->child_out_buf_next
+= request
;
300 state
->child_out_buf_avail
-= request
;
302 a
->archive
.file_position
+= request
;
307 archive_decompressor_program_finish(struct archive_read
*a
)
309 struct archive_decompress_program
*state
;
312 state
= (struct archive_decompress_program
*)a
->decompressor
->data
;
314 /* Release our configuration data. */
315 free(a
->decompressor
->config
);
316 a
->decompressor
->config
= NULL
;
318 /* Shut down the child. */
319 if (state
->child_stdin
!= -1)
320 close(state
->child_stdin
);
321 if (state
->child_stdout
!= -1)
322 close(state
->child_stdout
);
323 while (waitpid(state
->child
, &status
, 0) == -1 && errno
== EINTR
)
326 /* Release our private data. */
327 free(state
->child_out_buf
);
328 free(state
->description
);
330 a
->decompressor
->data
= NULL
;
335 #endif /* !defined(HAVE_PIPE) || !defined(HAVE_VFORK) || !defined(HAVE_FCNTL) */