]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - lib/libarchive/archive_read_support_compression_program.c
add -n option to suppress clearing the build tree and add -DNO_CLEAN
[FreeBSD/FreeBSD.git] / lib / libarchive / archive_read_support_compression_program.c
1 /*-
2  * Copyright (c) 2007 Joerg Sonnenberger
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
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.
13  *
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.
24  */
25
26 #include "archive_platform.h"
27 __FBSDID("$FreeBSD$");
28
29
30 /* This capability is only available on POSIX systems. */
31 #if !defined(HAVE_PIPE) || !defined(HAVE_FCNTL) || \
32     !(defined(HAVE_FORK) || defined(HAVE_VFORK))
33
34 #include "archive.h"
35
36 /*
37  * On non-Posix systems, allow the program to build, but choke if
38  * this function is actually invoked.
39  */
40 int
41 archive_read_support_compression_program(struct archive *_a, const char *cmd)
42 {
43         archive_set_error(_a, -1,
44             "External compression programs not supported on this platform");
45         return (ARCHIVE_FATAL);
46 }
47
48 #else
49
50 #ifdef HAVE_SYS_WAIT_H
51 #  include <sys/wait.h>
52 #endif
53 #ifdef HAVE_ERRNO_H
54 #  include <errno.h>
55 #endif
56 #ifdef HAVE_FCNTL_H
57 #  include <fcntl.h>
58 #endif
59 #ifdef HAVE_LIMITS_H
60 #  include <limits.h>
61 #endif
62 #ifdef HAVE_STDLIB_H
63 #  include <stdlib.h>
64 #endif
65 #ifdef HAVE_STRING_H
66 #  include <string.h>
67 #endif
68 #ifdef HAVE_UNISTD_H
69 #  include <unistd.h>
70 #endif
71
72 #include "archive.h"
73 #include "archive_private.h"
74 #include "archive_read_private.h"
75
76 #include "filter_fork.h"
77
78 struct archive_decompress_program {
79         char            *description;
80         pid_t            child;
81         int              child_stdin, child_stdout;
82
83         char            *child_out_buf;
84         char            *child_out_buf_next;
85         size_t           child_out_buf_len, child_out_buf_avail;
86
87         const char      *child_in_buf;
88         size_t           child_in_buf_avail;
89 };
90
91 static int      archive_decompressor_program_bid(const void *, size_t);
92 static int      archive_decompressor_program_finish(struct archive_read *);
93 static int      archive_decompressor_program_init(struct archive_read *,
94                     const void *, size_t);
95 static ssize_t  archive_decompressor_program_read_ahead(struct archive_read *,
96                     const void **, size_t);
97 static ssize_t  archive_decompressor_program_read_consume(struct archive_read *,
98                     size_t);
99
100 int
101 archive_read_support_compression_program(struct archive *_a, const char *cmd)
102 {
103         struct archive_read *a = (struct archive_read *)_a;
104         struct decompressor_t *decompressor;
105
106         if (cmd == NULL || *cmd == '\0')
107                 return (ARCHIVE_WARN);
108
109         decompressor = __archive_read_register_compression(a,
110                     archive_decompressor_program_bid,
111                     archive_decompressor_program_init);
112         if (decompressor == NULL)
113                 return (ARCHIVE_WARN);
114
115         decompressor->config = strdup(cmd);
116         return (ARCHIVE_OK);
117 }
118
119 /*
120  * If the user used us to register, they must really want us to
121  * handle it, so this module always bids INT_MAX.
122  */
123 static int
124 archive_decompressor_program_bid(const void *buff, size_t len)
125 {
126         (void)buff; /* UNUSED */
127         (void)len; /* UNUSED */
128
129         return (INT_MAX); /* Default: We'll take it. */
130 }
131
132 static ssize_t
133 child_read(struct archive_read *a, char *buf, size_t buf_len)
134 {
135         struct archive_decompress_program *state = a->decompressor->data;
136         ssize_t ret, requested;
137         const void *child_buf;
138
139         if (state->child_stdout == -1)
140                 return (-1);
141
142         if (buf_len == 0)
143                 return (-1);
144
145 restart_read:
146         requested = buf_len > SSIZE_MAX ? SSIZE_MAX : buf_len;
147
148         do {
149                 ret = read(state->child_stdout, buf, requested);
150         } while (ret == -1 && errno == EINTR);
151
152         if (ret > 0)
153                 return (ret);
154         if (ret == 0 || (ret == -1 && errno == EPIPE)) {
155                 close(state->child_stdout);
156                 state->child_stdout = -1;
157                 return (0);
158         }
159         if (ret == -1 && errno != EAGAIN)
160                 return (-1);
161
162         if (state->child_in_buf_avail == 0) {
163                 child_buf = state->child_in_buf;
164                 ret = (a->client_reader)(&a->archive,
165                     a->client_data,&child_buf);
166                 state->child_in_buf = (const char *)child_buf;
167
168                 if (ret < 0) {
169                         close(state->child_stdin);
170                         state->child_stdin = -1;
171                         fcntl(state->child_stdout, F_SETFL, 0);
172                         return (-1);
173                 }
174                 if (ret == 0) {
175                         close(state->child_stdin);
176                         state->child_stdin = -1;
177                         fcntl(state->child_stdout, F_SETFL, 0);
178                         goto restart_read;
179                 }
180                 state->child_in_buf_avail = ret;
181         }
182
183         if (state->child_stdin == -1) {
184                 fcntl(state->child_stdout, F_SETFL, 0);
185                 __archive_check_child(state->child_stdin, state->child_stdout);
186                 goto restart_read;
187         }
188
189         do {
190                 ret = write(state->child_stdin, state->child_in_buf,
191                     state->child_in_buf_avail);
192         } while (ret == -1 && errno == EINTR);
193
194         if (ret > 0) {
195                 state->child_in_buf += ret;
196                 state->child_in_buf_avail -= ret;
197                 goto restart_read;
198         } else if (ret == -1 && errno == EAGAIN) {
199                 __archive_check_child(state->child_stdin, state->child_stdout);
200                 goto restart_read;
201         } else if (ret == 0 || (ret == -1 && errno == EPIPE)) {
202                 close(state->child_stdin);
203                 state->child_stdin = -1;
204                 fcntl(state->child_stdout, F_SETFL, 0);
205                 goto restart_read;
206         } else {
207                 close(state->child_stdin);
208                 state->child_stdin = -1;
209                 fcntl(state->child_stdout, F_SETFL, 0);
210                 return (-1);
211         }
212 }
213
214 static int
215 archive_decompressor_program_init(struct archive_read *a, const void *buff, size_t n)
216 {
217         struct archive_decompress_program       *state;
218         const char *cmd = a->decompressor->config;
219         const char *prefix = "Program: ";
220
221
222         state = (struct archive_decompress_program *)malloc(sizeof(*state));
223         if (!state) {
224                 archive_set_error(&a->archive, ENOMEM,
225                     "Can't allocate input data");
226                 return (ARCHIVE_FATAL);
227         }
228
229         a->archive.compression_code = ARCHIVE_COMPRESSION_PROGRAM;
230         state->description = (char *)malloc(strlen(prefix) + strlen(cmd) + 1);
231         strcpy(state->description, prefix);
232         strcat(state->description, cmd);
233         a->archive.compression_name = state->description;
234
235         state->child_out_buf_next = state->child_out_buf = malloc(65536);
236         if (!state->child_out_buf) {
237                 free(state);
238                 archive_set_error(&a->archive, ENOMEM,
239                     "Can't allocate filter buffer");
240                 return (ARCHIVE_FATAL);
241         }
242         state->child_out_buf_len = 65536;
243         state->child_out_buf_avail = 0;
244
245         state->child_in_buf = buff;
246         state->child_in_buf_avail = n;
247
248         if ((state->child = __archive_create_child(cmd,
249                  &state->child_stdin, &state->child_stdout)) == -1) {
250                 free(state->child_out_buf);
251                 free(state);
252                 archive_set_error(&a->archive, EINVAL,
253                     "Can't initialise filter");
254                 return (ARCHIVE_FATAL);
255         }
256
257         a->decompressor->data = state;
258         a->decompressor->read_ahead = archive_decompressor_program_read_ahead;
259         a->decompressor->consume = archive_decompressor_program_read_consume;
260         a->decompressor->skip = NULL;
261         a->decompressor->finish = archive_decompressor_program_finish;
262
263         /* XXX Check that we can read at least one byte? */
264         return (ARCHIVE_OK);
265 }
266
267 static ssize_t
268 archive_decompressor_program_read_ahead(struct archive_read *a, const void **buff,
269     size_t min)
270 {
271         struct archive_decompress_program *state;
272         ssize_t bytes_read;
273
274         state = (struct archive_decompress_program *)a->decompressor->data;
275
276         if (min > state->child_out_buf_len)
277                 min = state->child_out_buf_len;
278
279         while (state->child_stdout != -1 && min > state->child_out_buf_avail) {
280                 if (state->child_out_buf != state->child_out_buf_next) {
281                         memmove(state->child_out_buf, state->child_out_buf_next,
282                             state->child_out_buf_avail);
283                         state->child_out_buf_next = state->child_out_buf;
284                 }
285
286                 bytes_read = child_read(a,
287                     state->child_out_buf + state->child_out_buf_avail,
288                     state->child_out_buf_len - state->child_out_buf_avail);
289                 if (bytes_read == -1)
290                         return (-1);
291                 if (bytes_read == 0)
292                         break;
293                 state->child_out_buf_avail += bytes_read;
294                 a->archive.raw_position += bytes_read;
295         }
296
297         *buff = state->child_out_buf_next;
298         return (state->child_out_buf_avail);
299 }
300
301 static ssize_t
302 archive_decompressor_program_read_consume(struct archive_read *a, size_t request)
303 {
304         struct archive_decompress_program *state;
305
306         state = (struct archive_decompress_program *)a->decompressor->data;
307
308         state->child_out_buf_next += request;
309         state->child_out_buf_avail -= request;
310
311         a->archive.file_position += request;
312         return (request);
313 }
314
315 static int
316 archive_decompressor_program_finish(struct archive_read *a)
317 {
318         struct archive_decompress_program       *state;
319         int status;
320
321         state = (struct archive_decompress_program *)a->decompressor->data;
322
323         /* Release our configuration data. */
324         free(a->decompressor->config);
325         a->decompressor->config = NULL;
326
327         /* Shut down the child. */
328         if (state->child_stdin != -1)
329                 close(state->child_stdin);
330         if (state->child_stdout != -1)
331                 close(state->child_stdout);
332         while (waitpid(state->child, &status, 0) == -1 && errno == EINTR)
333                 continue;
334
335         /* Release our private data. */
336         free(state->child_out_buf);
337         free(state->description);
338         free(state);
339         a->decompressor->data = NULL;
340
341         return (ARCHIVE_OK);
342 }
343
344 #endif /* !defined(HAVE_PIPE) || !defined(HAVE_VFORK) || !defined(HAVE_FCNTL) */