]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - lib/libarchive/archive_read_support_compression_program.c
Merge from libarchive.googlecode.com: Mostly a bunch of
[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 #ifdef HAVE_SYS_WAIT_H
30 #  include <sys/wait.h>
31 #endif
32 #ifdef HAVE_ERRNO_H
33 #  include <errno.h>
34 #endif
35 #ifdef HAVE_FCNTL_H
36 #  include <fcntl.h>
37 #endif
38 #ifdef HAVE_LIMITS_H
39 #  include <limits.h>
40 #endif
41 #ifdef HAVE_STDLIB_H
42 #  include <stdlib.h>
43 #endif
44 #ifdef HAVE_STRING_H
45 #  include <string.h>
46 #endif
47 #ifdef HAVE_UNISTD_H
48 #  include <unistd.h>
49 #endif
50
51 #include "archive.h"
52 #include "archive_private.h"
53 #include "archive_read_private.h"
54
55 int
56 archive_read_support_compression_program(struct archive *a, const char *cmd)
57 {
58         return (archive_read_support_compression_program_signature(a, cmd, NULL, 0));
59 }
60
61
62 /* This capability is only available on POSIX systems. */
63 #if (!defined(HAVE_PIPE) || !defined(HAVE_FCNTL) || \
64     !(defined(HAVE_FORK) || defined(HAVE_VFORK))) && (!defined(_WIN32) || defined(__CYGWIN__))
65
66 /*
67  * On non-Posix systems, allow the program to build, but choke if
68  * this function is actually invoked.
69  */
70 int
71 archive_read_support_compression_program_signature(struct archive *_a,
72     const char *cmd, void *signature, size_t signature_len)
73 {
74         (void)_a; /* UNUSED */
75         (void)cmd; /* UNUSED */
76         (void)signature; /* UNUSED */
77         (void)signature_len; /* UNUSED */
78
79         archive_set_error(_a, -1,
80             "External compression programs not supported on this platform");
81         return (ARCHIVE_FATAL);
82 }
83
84 int
85 __archive_read_program(struct archive_read_filter *self, const char *cmd)
86 {
87         (void)self; /* UNUSED */
88         (void)cmd; /* UNUSED */
89
90         archive_set_error(&self->archive->archive, -1,
91             "External compression programs not supported on this platform");
92         return (ARCHIVE_FATAL);
93 }
94
95 #else
96
97 #include "filter_fork.h"
98
99 /*
100  * The bidder object stores the command and the signature to watch for.
101  * The 'inhibit' entry here is used to ensure that unchecked filters never
102  * bid twice in the same pipeline.
103  */
104 struct program_bidder {
105         char *cmd;
106         void *signature;
107         size_t signature_len;
108         int inhibit;
109 };
110
111 static int      program_bidder_bid(struct archive_read_filter_bidder *,
112                     struct archive_read_filter *upstream);
113 static int      program_bidder_init(struct archive_read_filter *);
114 static int      program_bidder_free(struct archive_read_filter_bidder *);
115
116 /*
117  * The actual filter needs to track input and output data.
118  */
119 struct program_filter {
120         char            *description;
121         pid_t            child;
122         int              child_stdin, child_stdout;
123
124         char            *out_buf;
125         size_t           out_buf_len;
126 };
127
128 static ssize_t  program_filter_read(struct archive_read_filter *,
129                     const void **);
130 static int      program_filter_close(struct archive_read_filter *);
131
132 int
133 archive_read_support_compression_program_signature(struct archive *_a,
134     const char *cmd, const void *signature, size_t signature_len)
135 {
136         struct archive_read *a = (struct archive_read *)_a;
137         struct archive_read_filter_bidder *bidder;
138         struct program_bidder *state;
139
140         /*
141          * Get a bidder object from the read core.
142          */
143         bidder = __archive_read_get_bidder(a);
144         if (bidder == NULL)
145                 return (ARCHIVE_FATAL);
146
147         /*
148          * Allocate our private state.
149          */
150         state = (struct program_bidder *)calloc(sizeof (*state), 1);
151         if (state == NULL)
152                 return (ARCHIVE_FATAL);
153         state->cmd = strdup(cmd);
154         if (signature != NULL && signature_len > 0) {
155                 state->signature_len = signature_len;
156                 state->signature = malloc(signature_len);
157                 memcpy(state->signature, signature, signature_len);
158         }
159
160         /*
161          * Fill in the bidder object.
162          */
163         bidder->data = state;
164         bidder->bid = program_bidder_bid;
165         bidder->init = program_bidder_init;
166         bidder->options = NULL;
167         bidder->free = program_bidder_free;
168         return (ARCHIVE_OK);
169 }
170
171 static int
172 program_bidder_free(struct archive_read_filter_bidder *self)
173 {
174         struct program_bidder *state = (struct program_bidder *)self->data;
175         free(state->cmd);
176         free(state->signature);
177         free(self->data);
178         return (ARCHIVE_OK);
179 }
180
181 /*
182  * If we do have a signature, bid only if that matches.
183  *
184  * If there's no signature, we bid INT_MAX the first time
185  * we're called, then never bid again.
186  */
187 static int
188 program_bidder_bid(struct archive_read_filter_bidder *self,
189     struct archive_read_filter *upstream)
190 {
191         struct program_bidder *state = self->data;
192         const char *p;
193
194         /* If we have a signature, use that to match. */
195         if (state->signature_len > 0) {
196                 p = __archive_read_filter_ahead(upstream,
197                     state->signature_len, NULL);
198                 if (p == NULL)
199                         return (0);
200                 /* No match, so don't bid. */
201                 if (memcmp(p, state->signature, state->signature_len) != 0)
202                         return (0);
203                 return (state->signature_len * 8);
204         }
205
206         /* Otherwise, bid once and then never bid again. */
207         if (state->inhibit)
208                 return (0);
209         state->inhibit = 1;
210         return (INT_MAX);
211 }
212
213 /*
214  * Use select() to decide whether the child is ready for read or write.
215  */
216 static ssize_t
217 child_read(struct archive_read_filter *self, char *buf, size_t buf_len)
218 {
219         struct program_filter *state = self->data;
220         ssize_t ret, requested, avail;
221         const char *p;
222
223         requested = buf_len > SSIZE_MAX ? SSIZE_MAX : buf_len;
224
225         for (;;) {
226                 do {
227                         ret = read(state->child_stdout, buf, requested);
228                 } while (ret == -1 && errno == EINTR);
229
230                 if (ret > 0)
231                         return (ret);
232                 if (ret == 0 || (ret == -1 && errno == EPIPE)) {
233                         close(state->child_stdout);
234                         state->child_stdout = -1;
235                         return (0);
236                 }
237                 if (ret == -1 && errno != EAGAIN)
238                         return (-1);
239
240                 if (state->child_stdin == -1) {
241                         /* Block until child has some I/O ready. */
242                         __archive_check_child(state->child_stdin,
243                             state->child_stdout);
244                         continue;
245                 }
246
247                 /* Get some more data from upstream. */
248                 p = __archive_read_filter_ahead(self->upstream, 1, &avail);
249                 if (p == NULL) {
250                         close(state->child_stdin);
251                         state->child_stdin = -1;
252                         fcntl(state->child_stdout, F_SETFL, 0);
253                         if (avail < 0)
254                                 return (avail);
255                         continue;
256                 }
257
258                 do {
259                         ret = write(state->child_stdin, p, avail);
260                 } while (ret == -1 && errno == EINTR);
261
262                 if (ret > 0) {
263                         /* Consume whatever we managed to write. */
264                         __archive_read_filter_consume(self->upstream, ret);
265                 } else if (ret == -1 && errno == EAGAIN) {
266                         /* Block until child has some I/O ready. */
267                         __archive_check_child(state->child_stdin,
268                             state->child_stdout);
269                 } else {
270                         /* Write failed. */
271                         close(state->child_stdin);
272                         state->child_stdin = -1;
273                         fcntl(state->child_stdout, F_SETFL, 0);
274                         /* If it was a bad error, we're done; otherwise
275                          * it was EPIPE or EOF, and we can still read
276                          * from the child. */
277                         if (ret == -1 && errno != EPIPE)
278                                 return (-1);
279                 }
280         }
281 }
282
283 int
284 __archive_read_program(struct archive_read_filter *self, const char *cmd)
285 {
286         struct program_filter   *state;
287         static const size_t out_buf_len = 65536;
288         char *out_buf;
289         char *description;
290         const char *prefix = "Program: ";
291
292         state = (struct program_filter *)calloc(1, sizeof(*state));
293         out_buf = (char *)malloc(out_buf_len);
294         description = (char *)malloc(strlen(prefix) + strlen(cmd) + 1);
295         if (state == NULL || out_buf == NULL || description == NULL) {
296                 archive_set_error(&self->archive->archive, ENOMEM,
297                     "Can't allocate input data");
298                 free(state);
299                 free(out_buf);
300                 free(description);
301                 return (ARCHIVE_FATAL);
302         }
303
304         self->code = ARCHIVE_COMPRESSION_PROGRAM;
305         state->description = description;
306         strcpy(state->description, prefix);
307         strcat(state->description, cmd);
308         self->name = state->description;
309
310         state->out_buf = out_buf;
311         state->out_buf_len = out_buf_len;
312
313         if ((state->child = __archive_create_child(cmd,
314                  &state->child_stdin, &state->child_stdout)) == -1) {
315                 free(state->out_buf);
316                 free(state);
317                 archive_set_error(&self->archive->archive, EINVAL,
318                     "Can't initialise filter");
319                 return (ARCHIVE_FATAL);
320         }
321
322         self->data = state;
323         self->read = program_filter_read;
324         self->skip = NULL;
325         self->close = program_filter_close;
326
327         /* XXX Check that we can read at least one byte? */
328         return (ARCHIVE_OK);
329 }
330
331 static int
332 program_bidder_init(struct archive_read_filter *self)
333 {
334         struct program_bidder   *bidder_state;
335
336         bidder_state = (struct program_bidder *)self->bidder->data;
337         return (__archive_read_program(self, bidder_state->cmd));
338 }
339
340 static ssize_t
341 program_filter_read(struct archive_read_filter *self, const void **buff)
342 {
343         struct program_filter *state;
344         ssize_t bytes;
345         size_t total;
346         char *p;
347
348         state = (struct program_filter *)self->data;
349
350         total = 0;
351         p = state->out_buf;
352         while (state->child_stdout != -1 && total < state->out_buf_len) {
353                 bytes = child_read(self, p, state->out_buf_len - total);
354                 if (bytes < 0)
355                         return (bytes);
356                 if (bytes == 0)
357                         break;
358                 total += bytes;
359                 p += bytes;
360         }
361
362         *buff = state->out_buf;
363         return (total);
364 }
365
366 static int
367 program_filter_close(struct archive_read_filter *self)
368 {
369         struct program_filter   *state;
370         int status;
371
372         state = (struct program_filter *)self->data;
373
374         /* Shut down the child. */
375         if (state->child_stdin != -1)
376                 close(state->child_stdin);
377         if (state->child_stdout != -1)
378                 close(state->child_stdout);
379         while (waitpid(state->child, &status, 0) == -1 && errno == EINTR)
380                 continue;
381
382         /* Release our private data. */
383         free(state->out_buf);
384         free(state->description);
385         free(state);
386
387         return (ARCHIVE_OK);
388 }
389
390 #endif /* !defined(HAVE_PIPE) || !defined(HAVE_VFORK) || !defined(HAVE_FCNTL) */