diff options
| author | Tim Kientzle <kientzle@FreeBSD.org> | 2008-12-06 06:45:15 +0000 |
|---|---|---|
| committer | Tim Kientzle <kientzle@FreeBSD.org> | 2008-12-06 06:45:15 +0000 |
| commit | b1ff9c25b85752421491eb42f56c4cf65f451f98 (patch) | |
| tree | 07033908f13a75f6e70696ff70c73d1160bb8e74 /lib/libarchive/archive_read_support_compression_program.c | |
| parent | 72a4c788ff73a4cbfc61c85335d8d42004822e03 (diff) | |
Notes
Diffstat (limited to 'lib/libarchive/archive_read_support_compression_program.c')
| -rw-r--r-- | lib/libarchive/archive_read_support_compression_program.c | 218 |
1 files changed, 116 insertions, 102 deletions
diff --git a/lib/libarchive/archive_read_support_compression_program.c b/lib/libarchive/archive_read_support_compression_program.c index 0bea78dfeb2c..a9d6c5fc95ad 100644 --- a/lib/libarchive/archive_read_support_compression_program.c +++ b/lib/libarchive/archive_read_support_compression_program.c @@ -75,64 +75,94 @@ archive_read_support_compression_program(struct archive *_a, const char *cmd) #include "filter_fork.h" -struct archive_decompress_program { +struct program_reader { + char *cmd; + int bid; +}; + +struct program_source { char *description; pid_t child; int child_stdin, child_stdout; - char *child_out_buf; - char *child_out_buf_next; - size_t child_out_buf_len, child_out_buf_avail; + char *out_buf; + size_t out_buf_len; const char *child_in_buf; size_t child_in_buf_avail; }; -static int archive_decompressor_program_bid(const void *, size_t); -static int archive_decompressor_program_finish(struct archive_read *); -static int archive_decompressor_program_init(struct archive_read *, +static int program_reader_bid(struct archive_reader *, const void *, size_t); -static ssize_t archive_decompressor_program_read_ahead(struct archive_read *, - const void **, size_t); -static ssize_t archive_decompressor_program_read_consume(struct archive_read *, - size_t); +static struct archive_read_source *program_reader_init(struct archive_read *, + struct archive_reader *, struct archive_read_source *, + const void *, size_t); +static int program_reader_free(struct archive_reader *); + +static ssize_t program_source_read(struct archive_read_source *, + const void **); +static int program_source_close(struct archive_read_source *); + int archive_read_support_compression_program(struct archive *_a, const char *cmd) { struct archive_read *a = (struct archive_read *)_a; - struct decompressor_t *decompressor; + struct archive_reader *reader = __archive_read_get_reader(a); + struct program_reader *state; + + state = (struct program_reader *)calloc(sizeof (*state), 1); - if (cmd == NULL || *cmd == '\0') - return (ARCHIVE_WARN); + if (state == NULL) + return (ARCHIVE_FATAL); + if (reader == NULL) + return (ARCHIVE_FATAL); + + state->cmd = strdup(cmd); + state->bid = INT_MAX; - decompressor = __archive_read_register_compression(a, - archive_decompressor_program_bid, - archive_decompressor_program_init); - if (decompressor == NULL) - return (ARCHIVE_WARN); + reader->data = state; + reader->bid = program_reader_bid; + reader->init = program_reader_init; + reader->free = program_reader_free; + return (ARCHIVE_OK); +} - decompressor->config = strdup(cmd); +static int +program_reader_free(struct archive_reader *self) +{ + free(self->data); return (ARCHIVE_OK); } /* * If the user used us to register, they must really want us to - * handle it, so this module always bids INT_MAX. + * handle it, so we always bid INT_MAX the first time we're called. + * After that, we always return zero, lest we end up instantiating + * an infinite pipeline. */ static int -archive_decompressor_program_bid(const void *buff, size_t len) +program_reader_bid(struct archive_reader *self, const void *buff, size_t len) { + struct program_reader *state = self->data; + int bid = state->bid; + (void)buff; /* UNUSED */ (void)len; /* UNUSED */ - return (INT_MAX); /* Default: We'll take it. */ + state->bid = 0; /* Don't bid again on this pipeline. */ + + return (bid); /* Default: We'll take it if we haven't yet bid. */ } +/* + * Use select() to decide whether the child is ready for read or write. + */ + static ssize_t -child_read(struct archive_read *a, char *buf, size_t buf_len) +child_read(struct archive_read_source *self, char *buf, size_t buf_len) { - struct archive_decompress_program *state = a->decompressor->data; + struct program_source *state = self->data; ssize_t ret, requested; const void *child_buf; @@ -161,8 +191,7 @@ restart_read: if (state->child_in_buf_avail == 0) { child_buf = state->child_in_buf; - ret = (a->client_reader)(&a->archive, - a->client_data,&child_buf); + ret = (self->upstream->read)(self->upstream, &child_buf); state->child_in_buf = (const char *)child_buf; if (ret < 0) { @@ -211,118 +240,103 @@ restart_read: } } -static int -archive_decompressor_program_init(struct archive_read *a, const void *buff, size_t n) +static struct archive_read_source * +program_reader_init(struct archive_read *a, struct archive_reader *reader, + struct archive_read_source *upstream, const void *buff, size_t n) { - struct archive_decompress_program *state; - const char *cmd = a->decompressor->config; + struct program_source *state; + struct program_reader *reader_state; + struct archive_read_source *self; + static const size_t out_buf_len = 65536; + char *out_buf; + char *description; const char *prefix = "Program: "; - state = (struct archive_decompress_program *)malloc(sizeof(*state)); - if (!state) { + reader_state = (struct program_reader *)reader->data; + + self = (struct archive_read_source *)malloc(sizeof(*self)); + state = (struct program_source *)malloc(sizeof(*state)); + out_buf = (char *)malloc(out_buf_len); + description = (char *)malloc(strlen(prefix) + strlen(reader_state->cmd) + 1); + if (self == NULL + || state == NULL + || out_buf == NULL + || description == NULL) + { archive_set_error(&a->archive, ENOMEM, "Can't allocate input data"); - return (ARCHIVE_FATAL); + free(self); + free(state); + free(out_buf); + free(description); + return (NULL); } a->archive.compression_code = ARCHIVE_COMPRESSION_PROGRAM; - state->description = (char *)malloc(strlen(prefix) + strlen(cmd) + 1); + state->description = description; strcpy(state->description, prefix); - strcat(state->description, cmd); + strcat(state->description, reader_state->cmd); a->archive.compression_name = state->description; - state->child_out_buf_next = state->child_out_buf = malloc(65536); - if (!state->child_out_buf) { - free(state); - archive_set_error(&a->archive, ENOMEM, - "Can't allocate filter buffer"); - return (ARCHIVE_FATAL); - } - state->child_out_buf_len = 65536; - state->child_out_buf_avail = 0; + state->out_buf = out_buf; + state->out_buf_len = out_buf_len; state->child_in_buf = buff; state->child_in_buf_avail = n; - if ((state->child = __archive_create_child(cmd, + if ((state->child = __archive_create_child(reader_state->cmd, &state->child_stdin, &state->child_stdout)) == -1) { - free(state->child_out_buf); + free(state->out_buf); free(state); archive_set_error(&a->archive, EINVAL, "Can't initialise filter"); - return (ARCHIVE_FATAL); + return (NULL); } - a->decompressor->data = state; - a->decompressor->read_ahead = archive_decompressor_program_read_ahead; - a->decompressor->consume = archive_decompressor_program_read_consume; - a->decompressor->skip = NULL; - a->decompressor->finish = archive_decompressor_program_finish; + self->data = state; + self->read = program_source_read; + self->skip = NULL; + self->close = program_source_close; + self->upstream = upstream; + self->archive = a; /* XXX Check that we can read at least one byte? */ - return (ARCHIVE_OK); + return (self); } static ssize_t -archive_decompressor_program_read_ahead(struct archive_read *a, const void **buff, - size_t min) +program_source_read(struct archive_read_source *self, const void **buff) { - struct archive_decompress_program *state; - ssize_t bytes_read; - - state = (struct archive_decompress_program *)a->decompressor->data; + struct program_source *state; + ssize_t bytes, total; + char *p; - if (min > state->child_out_buf_len) - min = state->child_out_buf_len; - - while (state->child_stdout != -1 && min > state->child_out_buf_avail) { - if (state->child_out_buf != state->child_out_buf_next) { - memmove(state->child_out_buf, state->child_out_buf_next, - state->child_out_buf_avail); - state->child_out_buf_next = state->child_out_buf; - } + state = (struct program_source *)self->data; - bytes_read = child_read(a, - state->child_out_buf + state->child_out_buf_avail, - state->child_out_buf_len - state->child_out_buf_avail); - if (bytes_read == -1) - return (-1); - if (bytes_read == 0) + total = 0; + p = state->out_buf; + while (state->child_stdout != -1) { + bytes = child_read(self, p, state->out_buf_len - total); + if (bytes < 0) + return (bytes); + if (bytes == 0) break; - state->child_out_buf_avail += bytes_read; - a->archive.raw_position += bytes_read; + total += bytes; +/* TODO: fix this */ /* a->archive.raw_position += bytes_read; */ } - *buff = state->child_out_buf_next; - return (state->child_out_buf_avail); -} - -static ssize_t -archive_decompressor_program_read_consume(struct archive_read *a, size_t request) -{ - struct archive_decompress_program *state; - - state = (struct archive_decompress_program *)a->decompressor->data; - - state->child_out_buf_next += request; - state->child_out_buf_avail -= request; - - a->archive.file_position += request; - return (request); + *buff = state->out_buf; + return (total); } static int -archive_decompressor_program_finish(struct archive_read *a) +program_source_close(struct archive_read_source *self) { - struct archive_decompress_program *state; + struct program_source *state; int status; - state = (struct archive_decompress_program *)a->decompressor->data; - - /* Release our configuration data. */ - free(a->decompressor->config); - a->decompressor->config = NULL; + state = (struct program_source *)self->data; /* Shut down the child. */ if (state->child_stdin != -1) @@ -333,10 +347,10 @@ archive_decompressor_program_finish(struct archive_read *a) continue; /* Release our private data. */ - free(state->child_out_buf); + free(state->out_buf); free(state->description); free(state); - a->decompressor->data = NULL; + free(self); return (ARCHIVE_OK); } |
