summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTim Kientzle <kientzle@gmail.com>2010-02-21 03:25:42 -0500
committerTim Kientzle <kientzle@gmail.com>2010-02-21 03:25:42 -0500
commit992610f1dd74565cda8df166f70f0d8abf4abda7 (patch)
tree08da3d98240104f98ec0fb50cd6ac5a7c349cc20
parent0eb2fe95fbb65e82759f9fd1a0aef553981cae74 (diff)
downloadlibarchive-992610f1dd74565cda8df166f70f0d8abf4abda7.tar.gz
The only place blocking is really needed is just before calling
the client write functions. So I've moved all of the blocking code (that used to be duplicated in every compression filter) into archive_write.c in the code that wraps the client callbacks. As a result, add_filter_none is a true no-op. SVN-Revision: 1936
-rw-r--r--libarchive/archive_write.c154
-rw-r--r--libarchive/archive_write_add_filter_bzip2.c14
-rw-r--r--libarchive/archive_write_add_filter_compress.c1
-rw-r--r--libarchive/archive_write_add_filter_gzip.c41
-rw-r--r--libarchive/archive_write_add_filter_none.c210
-rw-r--r--libarchive/archive_write_add_filter_program.c5
-rw-r--r--libarchive/archive_write_add_filter_xz.c7
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