diff options
-rw-r--r-- | libarchive/archive_write.c | 154 | ||||
-rw-r--r-- | libarchive/archive_write_add_filter_bzip2.c | 14 | ||||
-rw-r--r-- | libarchive/archive_write_add_filter_compress.c | 1 | ||||
-rw-r--r-- | libarchive/archive_write_add_filter_gzip.c | 41 | ||||
-rw-r--r-- | libarchive/archive_write_add_filter_none.c | 210 | ||||
-rw-r--r-- | libarchive/archive_write_add_filter_program.c | 5 | ||||
-rw-r--r-- | libarchive/archive_write_add_filter_xz.c | 7 |
7 files changed, 169 insertions, 263 deletions
diff --git a/libarchive/archive_write.c b/libarchive/archive_write.c index ddb509ff..b62b0d72 100644 --- a/libarchive/archive_write.c +++ b/libarchive/archive_write.c @@ -37,6 +37,9 @@ __FBSDID("$FreeBSD: head/lib/libarchive/archive_write.c 201099 2009-12-28 03:03: #ifdef HAVE_SYS_WAIT_H #include <sys/wait.h> #endif +#ifdef HAVE_ERRNO_H +#include <errno.h> +#endif #ifdef HAVE_LIMITS_H #include <limits.h> #endif @@ -68,6 +71,13 @@ static int _archive_write_header(struct archive *, struct archive_entry *); static int _archive_write_finish_entry(struct archive *); static ssize_t _archive_write_data(struct archive *, const void *, size_t); +struct archive_none { + size_t buffer_size; + size_t avail; + char *buffer; + char *next; +}; + static struct archive_vtable * archive_write_vtable(void) { @@ -366,9 +376,34 @@ static int archive_write_client_open(struct archive_write_filter *f) { struct archive_write *a = (struct archive_write *)f->archive; + struct archive_none *state; + void *buffer; + size_t buffer_size; + + f->bytes_per_block = archive_write_get_bytes_per_block(f->archive); + f->bytes_in_last_block = + archive_write_get_bytes_in_last_block(f->archive); + buffer_size = f->bytes_per_block; + + state = (struct archive_none *)calloc(1, sizeof(*state)); + buffer = (char *)malloc(buffer_size); + if (state == NULL || buffer == NULL) { + free(state); + free(buffer); + archive_set_error(f->archive, ENOMEM, + "Can't allocate data for output buffering"); + return (ARCHIVE_FATAL); + } + + state->buffer_size = buffer_size; + state->buffer = buffer; + state->next = state->buffer; + state->avail = state->buffer_size; + f->data = state; + if (a->client_opener == NULL) return (ARCHIVE_OK); - return (a->client_opener(f->archive, f->data)); + return (a->client_opener(f->archive, a->client_data)); } static int @@ -376,28 +411,111 @@ archive_write_client_write(struct archive_write_filter *f, const void *_buff, size_t length) { struct archive_write *a = (struct archive_write *)f->archive; - const char *buff = _buff; - - while (length > 0) { - ssize_t written - = (a->client_writer(f->archive, f->data, buff, length)); - if (written < 0) - return ((int)written); - if (written == 0) - return (ARCHIVE_FATAL); - buff += written; - length -= written; - } - return (ARCHIVE_OK); + struct archive_none *state = (struct archive_none *)f->data; + const char *buff = (const char *)_buff; + ssize_t remaining, to_copy; + ssize_t bytes_written; + + remaining = length; + + /* + * If there is no buffer for blocking, just pass the data + * straight through to the client write callback. In + * particular, this supports "no write delay" operation for + * special applications. Just set the block size to zero. + */ + if (state->buffer_size == 0) { + while (remaining > 0) { + bytes_written = (a->client_writer)(&a->archive, + a->client_data, buff, remaining); + if (bytes_written <= 0) + return (ARCHIVE_FATAL); + remaining -= bytes_written; + buff += bytes_written; + } + return (ARCHIVE_OK); + } + + /* If the copy buffer isn't empty, try to fill it. */ + if (state->avail < state->buffer_size) { + /* If buffer is not empty... */ + /* ... copy data into buffer ... */ + to_copy = (remaining > state->avail) ? + state->avail : remaining; + memcpy(state->next, buff, to_copy); + state->next += to_copy; + state->avail -= to_copy; + buff += to_copy; + remaining -= to_copy; + /* ... if it's full, write it out. */ + if (state->avail == 0) { + bytes_written = (a->client_writer)(&a->archive, + a->client_data, state->buffer, state->buffer_size); + if (bytes_written <= 0) + return (ARCHIVE_FATAL); + /* XXX TODO: if bytes_written < state->buffer_size */ + state->next = state->buffer; + state->avail = state->buffer_size; + } + } + + while (remaining > state->buffer_size) { + /* Write out full blocks directly to client. */ + bytes_written = (a->client_writer)(&a->archive, + a->client_data, buff, state->buffer_size); + if (bytes_written <= 0) + return (ARCHIVE_FATAL); + buff += bytes_written; + remaining -= bytes_written; + } + + if (remaining > 0) { + /* Copy last bit into copy buffer. */ + memcpy(state->next, buff, remaining); + state->next += remaining; + state->avail -= remaining; + } + return (ARCHIVE_OK); } static int archive_write_client_close(struct archive_write_filter *f) { struct archive_write *a = (struct archive_write *)f->archive; - if (a->client_closer == NULL) - return (ARCHIVE_OK); - return (a->client_closer(f->archive, f->data)); + struct archive_none *state = (struct archive_none *)f->data; + ssize_t block_length; + ssize_t target_block_length; + ssize_t bytes_written; + int ret = ARCHIVE_OK; + + /* If there's pending data, pad and write the last block */ + if (state->next != state->buffer) { + block_length = state->buffer_size - state->avail; + + /* Tricky calculation to determine size of last block */ + if (a->bytes_in_last_block <= 0) + /* Default or Zero: pad to full block */ + target_block_length = a->bytes_per_block; + else + /* Round to next multiple of bytes_in_last_block. */ + target_block_length = a->bytes_in_last_block * + ( (block_length + a->bytes_in_last_block - 1) / + a->bytes_in_last_block); + if (target_block_length > a->bytes_per_block) + target_block_length = a->bytes_per_block; + if (block_length < target_block_length) { + memset(state->next, 0, + target_block_length - block_length); + block_length = target_block_length; + } + bytes_written = (a->client_writer)(&a->archive, + a->client_data, state->buffer, block_length); + ret = bytes_written <= 0 ? ARCHIVE_FATAL : ARCHIVE_OK; + } + free(state->buffer); + free(state); + a->client_data = NULL; + return (ret); } /* @@ -422,9 +540,9 @@ archive_write_open(struct archive *_a, void *client_data, a->client_writer = writer; a->client_opener = opener; a->client_closer = closer; + a->client_data = client_data; client_filter = __archive_write_allocate_filter(_a); - client_filter->data = client_data; client_filter->open = archive_write_client_open; client_filter->write = archive_write_client_write; client_filter->close = archive_write_client_close; diff --git a/libarchive/archive_write_add_filter_bzip2.c b/libarchive/archive_write_add_filter_bzip2.c index 9bb19082..6d1b3567 100644 --- a/libarchive/archive_write_add_filter_bzip2.c +++ b/libarchive/archive_write_add_filter_bzip2.c @@ -241,21 +241,15 @@ static int archive_compressor_bzip2_close(struct archive_write_filter *f) { struct private_data *data = (struct private_data *)f->data; - ssize_t bytes_written; - int ret; - - if (data == NULL) - return (ARCHIVE_OK); + int ret, r1; /* Finish compression cycle. */ ret = drive_compressor(f, data, 1); if (ret == ARCHIVE_OK) { /* Write the last block */ - bytes_written = __archive_write_filter(f->next_filter, + ret = __archive_write_filter(f->next_filter, data->compressed, data->compressed_buffer_size - data->stream.avail_out); - if (bytes_written <= 0) - ret = ARCHIVE_FATAL; } switch (BZ2_bzCompressEnd(&(data->stream))) { @@ -266,7 +260,9 @@ archive_compressor_bzip2_close(struct archive_write_filter *f) "Failed to clean up compressor"); ret = ARCHIVE_FATAL; } - return (ARCHIVE_OK); + + r1 = __archive_write_close_filter(f->next_filter); + return (r1 < ret ? r1 : ret); } static int diff --git a/libarchive/archive_write_add_filter_compress.c b/libarchive/archive_write_add_filter_compress.c index e8d6344f..7e3ef6bb 100644 --- a/libarchive/archive_write_add_filter_compress.c +++ b/libarchive/archive_write_add_filter_compress.c @@ -430,6 +430,7 @@ archive_compressor_compress_close(struct archive_write_filter *f) ret = __archive_write_filter(f->next_filter, state->compressed, state->compressed_offset); cleanup: + ret = __archive_write_close_filter(f->next_filter); free(state->compressed); free(state); return (ret); diff --git a/libarchive/archive_write_add_filter_gzip.c b/libarchive/archive_write_add_filter_gzip.c index 0499bd1f..23dabe53 100644 --- a/libarchive/archive_write_add_filter_gzip.c +++ b/libarchive/archive_write_add_filter_gzip.c @@ -254,24 +254,17 @@ archive_compressor_gzip_close(struct archive_write_filter *f) { unsigned char trailer[8]; struct private_data *data = (struct private_data *)f->data; - int ret; - - ret = 0; - if (data != NULL) { - /* Finish compression cycle */ - ret = drive_compressor(f, data, 1); - if (ret != ARCHIVE_OK) - goto cleanup; + int ret, r1; + /* Finish compression cycle */ + ret = drive_compressor(f, data, 1); + if (ret == ARCHIVE_OK) { /* Write the last compressed data. */ ret = __archive_write_filter(f->next_filter, data->compressed, data->compressed_buffer_size - data->stream.avail_out); - if (ret != ARCHIVE_OK) { - ret = ARCHIVE_FATAL; - goto cleanup; - } - + } + if (ret == ARCHIVE_OK) { /* Build and write out 8-byte trailer. */ trailer[0] = (data->crc)&0xff; trailer[1] = (data->crc >> 8)&0xff; @@ -282,20 +275,18 @@ archive_compressor_gzip_close(struct archive_write_filter *f) trailer[6] = (data->total_in >> 16)&0xff; trailer[7] = (data->total_in >> 24)&0xff; ret = __archive_write_filter(f->next_filter, trailer, 8); - if (ret != ARCHIVE_OK) - ret = ARCHIVE_FATAL; + } - cleanup: - switch (deflateEnd(&(data->stream))) { - case Z_OK: - break; - default: - archive_set_error(f->archive, ARCHIVE_ERRNO_MISC, - "Failed to clean up compressor"); - ret = ARCHIVE_FATAL; - } + switch (deflateEnd(&(data->stream))) { + case Z_OK: + break; + default: + archive_set_error(f->archive, ARCHIVE_ERRNO_MISC, + "Failed to clean up compressor"); + ret = ARCHIVE_FATAL; } - return (ret); + r1 = __archive_write_close_filter(f->next_filter); + return (r1 < ret ? r1 : ret); } static int diff --git a/libarchive/archive_write_add_filter_none.c b/libarchive/archive_write_add_filter_none.c index 80747a4c..3c06c642 100644 --- a/libarchive/archive_write_add_filter_none.c +++ b/libarchive/archive_write_add_filter_none.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2003-2007 Tim Kientzle + * Copyright (c) 2003-2010 Tim Kientzle * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -26,218 +26,18 @@ #include "archive_platform.h" __FBSDID("$FreeBSD: head/lib/libarchive/archive_write_set_compression_none.c 201080 2009-12-28 02:03:54Z kientzle $"); -#ifdef HAVE_ERRNO_H -#include <errno.h> -#endif -#ifdef HAVE_STDLIB_H -#include <stdlib.h> -#endif -#ifdef HAVE_STRING_H -#include <string.h> -#endif - #include "archive.h" -#include "archive_private.h" -#include "archive_write_private.h" - int archive_write_set_compression_none(struct archive *a) { - __archive_write_filters_free(a); - return (archive_write_add_filter_none(a)); -} - - -static int archive_compressor_none_open(struct archive_write_filter *); -static int archive_compressor_none_write(struct archive_write_filter *, - const void *, size_t); -static int archive_compressor_none_close(struct archive_write_filter *); -static int archive_compressor_none_free(struct archive_write_filter *); - -struct archive_none { - char *buffer; - ssize_t buffer_size; - char *next; /* Current insert location */ - ssize_t avail; /* Free space left in buffer */ -}; - -/* - * TODO: A little refactoring will turn this into a true no-op. - */ -int -archive_write_add_filter_none(struct archive *_a) -{ - struct archive_write *a = (struct archive_write *)_a; - struct archive_write_filter *f = __archive_write_allocate_filter(_a); - __archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC, - ARCHIVE_STATE_NEW, "archive_write_set_compression_none"); - f->open = &archive_compressor_none_open; - f->code = ARCHIVE_COMPRESSION_NONE; - f->name = "none"; - - return (ARCHIVE_OK); -} - -/* - * Setup callback. - */ -static int -archive_compressor_none_open(struct archive_write_filter *f) -{ - int ret; - struct archive_none *state; - - ret = __archive_write_open_filter(f->next_filter); - if (ret != 0) - return (ret); - - f->bytes_per_block = archive_write_get_bytes_per_block(f->archive); - f->bytes_in_last_block = archive_write_get_bytes_in_last_block(f->archive); - - state = (struct archive_none *)calloc(1, sizeof(*state)); - if (state == NULL) { - archive_set_error(f->archive, ENOMEM, - "Can't allocate data for output buffering"); - return (ARCHIVE_FATAL); - } - - state->buffer_size = f->bytes_per_block; - if (state->buffer_size != 0) { - state->buffer = (char *)malloc(state->buffer_size); - if (state->buffer == NULL) { - archive_set_error(f->archive, ENOMEM, - "Can't allocate output buffer"); - free(state); - return (ARCHIVE_FATAL); - } - } - - state->next = state->buffer; - state->avail = state->buffer_size; - - f->data = state; - f->write = archive_compressor_none_write; - f->close = archive_compressor_none_close; - f->free = archive_compressor_none_free; + (void)a; /* UNUSED */ return (ARCHIVE_OK); } -/* - * Write data to the stream. - */ -static int -archive_compressor_none_write(struct archive_write_filter *f, - const void *vbuff, size_t length) -{ - struct archive_none *state = (struct archive_none *)f->data; - const char *buff; - ssize_t remaining, to_copy; - int ret; - - /* - * If there is no buffer for blocking, just pass the data - * straight through to the client write callback. In - * particular, this supports "no write delay" operation for - * special applications. Just set the block size to zero. - */ - if (state->buffer_size == 0) - return (__archive_write_filter(f->next_filter, - vbuff, length)); - - buff = (const char *)vbuff; - remaining = length; - - /* If the copy buffer isn't empty, try to fill it. */ - if (state->avail < state->buffer_size) { - /* If buffer is not empty... */ - /* ... copy data into buffer ... */ - to_copy = (remaining > state->avail) ? - state->avail : remaining; - memcpy(state->next, buff, to_copy); - state->next += to_copy; - state->avail -= to_copy; - buff += to_copy; - remaining -= to_copy; - /* ... if it's full, write it out. */ - if (state->avail == 0) { - ret = __archive_write_filter(f->next_filter, - state->buffer, state->buffer_size); - if (ret != ARCHIVE_OK) - return (ARCHIVE_FATAL); - state->next = state->buffer; - state->avail = state->buffer_size; - } - } - - /* Write out full blocks directly to client. */ - while (remaining > state->buffer_size) { - ret = __archive_write_filter(f->next_filter, - buff, state->buffer_size); - if (ret != ARCHIVE_OK) - return (ARCHIVE_FATAL); - buff += state->buffer_size; - remaining -= state->buffer_size; - } - - if (remaining > 0) { - /* Copy last bit into copy buffer. */ - memcpy(state->next, buff, remaining); - state->next += remaining; - state->avail -= remaining; - } - - return (ARCHIVE_OK); -} - - -/* - * Finish the compression. - */ -static int -archive_compressor_none_close(struct archive_write_filter *f) -{ - struct archive_none *state = (struct archive_none *)f->data; - ssize_t block_length; - ssize_t target_block_length; - int ret; - - ret = ARCHIVE_OK; - - /* If there's pending data, pad and write the last block */ - if (state->next != state->buffer) { - block_length = state->buffer_size - state->avail; - - /* Tricky calculation to determine size of last block */ - if (f->bytes_in_last_block <= 0) - /* Default or Zero: pad to full block */ - target_block_length = f->bytes_per_block; - else - /* Round to next multiple of bytes_in_last_block. */ - target_block_length = f->bytes_in_last_block * - ( (block_length + f->bytes_in_last_block - 1) / - f->bytes_in_last_block); - if (target_block_length > f->bytes_per_block) - target_block_length = f->bytes_per_block; - if (block_length < target_block_length) { - memset(state->next, 0, - target_block_length - block_length); - block_length = target_block_length; - } - ret = __archive_write_filter(f->next_filter, - state->buffer, block_length); - } - if (state->buffer) - free(state->buffer); - free(state); - f->data = NULL; - - return (ret); -} - -static int -archive_compressor_none_free(struct archive_write_filter *f) +int +archive_write_add_filter_none(struct archive *a) { - (void)f; /* UNUSED */ + (void)a; /* UNUSED */ return (ARCHIVE_OK); } diff --git a/libarchive/archive_write_add_filter_program.c b/libarchive/archive_write_add_filter_program.c index 0efeb7c4..90c5f11d 100644 --- a/libarchive/archive_write_add_filter_program.c +++ b/libarchive/archive_write_add_filter_program.c @@ -259,7 +259,7 @@ static int archive_compressor_program_close(struct archive_write_filter *f) { struct private_data *data = (struct private_data *)f->data; - int ret, status; + int ret, r1, status; ssize_t bytes_read; ret = 0; @@ -308,7 +308,8 @@ cleanup: "Filter exited with failure."); ret = ARCHIVE_FATAL; } - return (ret); + r1 = __archive_write_close_filter(f->next_filter); + return (r1 < ret ? r1 : ret); } static int diff --git a/libarchive/archive_write_add_filter_xz.c b/libarchive/archive_write_add_filter_xz.c index a54d3a4c..2e21c60a 100644 --- a/libarchive/archive_write_add_filter_xz.c +++ b/libarchive/archive_write_add_filter_xz.c @@ -279,10 +279,8 @@ static int archive_compressor_xz_close(struct archive_write_filter *f) { struct private_data *data = (struct private_data *)f->data; - int ret; + int ret, r1; - if (data == NULL) - return (ARCHIVE_OK); ret = drive_compressor(f, data, 1); if (ret == ARCHIVE_OK) { ret = __archive_write_filter(f->next_filter, @@ -290,7 +288,8 @@ archive_compressor_xz_close(struct archive_write_filter *f) data->compressed_buffer_size - data->stream.avail_out); } lzma_end(&(data->stream)); - return (ret); + r1 = __archive_write_close_filter(f->next_filter); + return (r1 < ret ? r1 : ret); } static int |