]> git.ipfire.org Git - thirdparty/libarchive.git/commitdiff
The only place blocking is really needed is just before calling
authorTim Kientzle <kientzle@gmail.com>
Sun, 21 Feb 2010 08:25:42 +0000 (03:25 -0500)
committerTim Kientzle <kientzle@gmail.com>
Sun, 21 Feb 2010 08:25:42 +0000 (03:25 -0500)
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

libarchive/archive_write.c
libarchive/archive_write_add_filter_bzip2.c
libarchive/archive_write_add_filter_compress.c
libarchive/archive_write_add_filter_gzip.c
libarchive/archive_write_add_filter_none.c
libarchive/archive_write_add_filter_program.c
libarchive/archive_write_add_filter_xz.c

index ddb509ff7384fbcb3b51b55d068614574e7b7b19..b62b0d722e670a842bfc962fb136c5f152b3d1c8 100644 (file)
@@ -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;
index 9bb19082ce1934653c773e6a19276e453de13603..6d1b35679ae4ba71f356d94345706e2d054f805c 100644 (file)
@@ -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
index e8d6344fd74bd1f36fb23d60c8d8bff9bf195228..7e3ef6bbc637bd1489e0d43a7ef3a2b0c5895ecf 100644 (file)
@@ -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);
index 0499bd1f4266766d85108b300f34b5581db03f35..23dabe5387217c2463db23e2fc0c4a1b08dfd41e 100644 (file)
@@ -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
index 80747a4ccf75bfc129f133d972a9ba8c2884040e..3c06c642e735fdd1f02c7192d4908b2cb7a79378 100644 (file)
@@ -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
 #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);
 }
index 0efeb7c486c14023937e3103252b2d6c6747a5e1..90c5f11d47d8daba1e6d9c543b1566b14e5e59ae 100644 (file)
@@ -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
index a54d3a4caf96878ae5df72a4ec30d37cc2b009e9..2e21c60aeafa5023cedbb358cbe4e1537320f70c 100644 (file)
@@ -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