f = calloc(1, sizeof(*f));
f->archive = _a;
+ f->state = ARCHIVE_WRITE_FILTER_STATE_NEW;
if (a->filter_first == NULL)
a->filter_first = f;
else
const void *buff, size_t length)
{
int r;
+ /* Never write to non-open filters */
+ if (f->state != ARCHIVE_WRITE_FILTER_STATE_OPEN)
+ return(ARCHIVE_FATAL);
if (length == 0)
return(ARCHIVE_OK);
if (f->write == NULL)
}
/*
- * Open a filter.
+ * Recursive function for opening the filter chain
+ * Last filter is opened first
*/
-int
+static int
__archive_write_open_filter(struct archive_write_filter *f)
{
- if (f->open == NULL)
+ int ret;
+
+ ret = ARCHIVE_OK;
+ if (f->next_filter != NULL)
+ ret = __archive_write_open_filter(f->next_filter);
+ if (ret != ARCHIVE_OK)
+ return (ret);
+ if (f->state != ARCHIVE_WRITE_FILTER_STATE_NEW)
+ return (ARCHIVE_FATAL);
+ if (f->open == NULL) {
+ f->state = ARCHIVE_WRITE_FILTER_STATE_OPEN;
return (ARCHIVE_OK);
- return (f->open)(f);
+ }
+ ret = (f->open)(f);
+ if (ret == ARCHIVE_OK)
+ f->state = ARCHIVE_WRITE_FILTER_STATE_OPEN;
+ else
+ f->state = ARCHIVE_WRITE_FILTER_STATE_FATAL;
+ return (ret);
}
/*
- * Close a filter.
+ * Open all filters
*/
-int
-__archive_write_close_filter(struct archive_write *a)
+static int
+__archive_write_filters_open(struct archive_write *a)
+{
+ return (__archive_write_open_filter(a->filter_first));
+}
+
+/*
+ * Close all filtes
+ */
+static int
+__archive_write_filters_close(struct archive_write *a)
{
struct archive_write_filter *f;
int ret, ret1;
ret = ARCHIVE_OK;
for (f = a->filter_first; f != NULL; f = f->next_filter) {
- if (f->close != NULL) {
- ret1 = (f->close)(f);
- if (ret1 < ret)
- ret = ret1;
+ /* Do not close filters that are not open */
+ if (f->state == ARCHIVE_WRITE_FILTER_STATE_OPEN) {
+ if (f->close != NULL) {
+ ret1 = (f->close)(f);
+ if (ret1 < ret)
+ ret = ret1;
+ if (ret1 == ARCHIVE_OK) {
+ f->state =
+ ARCHIVE_WRITE_FILTER_STATE_CLOSED;
+ } else {
+ f->state =
+ ARCHIVE_WRITE_FILTER_STATE_FATAL;
+ }
+ } else
+ f->state = ARCHIVE_WRITE_FILTER_STATE_CLOSED;
}
}
return (ret);
free(state->buffer);
free(state);
/* Clear the close handler myself not to be called again. */
- f->close = NULL;
+ f->state = ARCHIVE_WRITE_FILTER_STATE_CLOSED;
a->client_data = NULL;
/* Clear passphrase. */
if (a->passphrase != NULL) {
client_filter->write = archive_write_client_write;
client_filter->close = archive_write_client_close;
- ret = __archive_write_open_filter(a->filter_first);
+ ret = __archive_write_filters_open(a);
if (ret < ARCHIVE_WARN) {
- r1 = __archive_write_close_filter(a);
+ r1 = __archive_write_filters_close(a);
__archive_write_filters_free(_a);
return (r1 < ret ? r1 : ret);
}
}
/* Finish the compression and close the stream. */
- r1 = __archive_write_close_filter(a);
+ r1 = __archive_write_filters_close(a);
if (r1 < r)
r = r1;
{
struct private_b64encode *state = (struct private_b64encode *)f->data;
size_t bs = 65536, bpb;
- int ret;
-
- ret = __archive_write_open_filter(f->next_filter);
- if (ret != ARCHIVE_OK)
- return (ret);
if (f->archive->magic == ARCHIVE_WRITE_MAGIC) {
/* Buffer size should be a multiple number of the of bytes
struct private_data *data = (struct private_data *)f->data;
int ret;
- ret = __archive_write_open_filter(f->next_filter);
- if (ret != 0)
- return (ret);
-
if (data->compressed == NULL) {
size_t bs = 65536, bpb;
if (f->archive->magic == ARCHIVE_WRITE_MAGIC) {
static int
archive_compressor_compress_open(struct archive_write_filter *f)
{
- int ret;
struct private_data *state;
size_t bs = 65536, bpb;
f->code = ARCHIVE_FILTER_COMPRESS;
f->name = "compress";
- ret = __archive_write_open_filter(f->next_filter);
- if (ret != ARCHIVE_OK)
- return (ret);
-
state = (struct private_data *)calloc(1, sizeof(*state));
if (state == NULL) {
archive_set_error(f->archive, ENOMEM,
struct private_data *data = (struct private_data *)f->data;
int ret;
- ret = __archive_write_open_filter(f->next_filter);
- if (ret != ARCHIVE_OK)
- return (ret);
-
if (data->compressed == NULL) {
size_t bs = 65536, bpb;
if (f->archive->magic == ARCHIVE_WRITE_MAGIC) {
archive_filter_lz4_open(struct archive_write_filter *f)
{
struct private_data *data = (struct private_data *)f->data;
- int ret;
size_t required_size;
static size_t const bkmap[] = { 64 * 1024, 256 * 1024, 1 * 1024 * 1024,
4 * 1024 * 1024 };
size_t pre_block_size;
- ret = __archive_write_open_filter(f->next_filter);
- if (ret != 0)
- return (ret);
-
if (data->block_maximum_size < 4)
data->block_size = bkmap[0];
else
archive_write_lzop_open(struct archive_write_filter *f)
{
struct write_lzop *data = (struct write_lzop *)f->data;
- int ret;
-
- ret = __archive_write_open_filter(f->next_filter);
- if (ret != ARCHIVE_OK)
- return (ret);
switch (data->compression_level) {
case 1:
struct archive_write_program_data *data, const char *cmd)
{
pid_t child;
- int ret;
-
- ret = __archive_write_open_filter(f->next_filter);
- if (ret != ARCHIVE_OK)
- return (ret);
if (data->child_buf == NULL) {
data->child_buf_len = 65536;
{
struct private_uuencode *state = (struct private_uuencode *)f->data;
size_t bs = 65536, bpb;
- int ret;
-
- ret = __archive_write_open_filter(f->next_filter);
- if (ret != ARCHIVE_OK)
- return (ret);
if (f->archive->magic == ARCHIVE_WRITE_MAGIC) {
/* Buffer size should be a multiple number of the of bytes
struct private_data *data = f->data;
int ret;
- ret = __archive_write_open_filter(f->next_filter);
- if (ret != ARCHIVE_OK)
- return (ret);
-
if (data->compressed == NULL) {
size_t bs = 65536, bpb;
if (f->archive->magic == ARCHIVE_WRITE_MAGIC) {
archive_compressor_zstd_open(struct archive_write_filter *f)
{
struct private_data *data = (struct private_data *)f->data;
- int ret;
-
- ret = __archive_write_open_filter(f->next_filter);
- if (ret != ARCHIVE_OK)
- return (ret);
if (data->out.dst == NULL) {
size_t bs = ZSTD_CStreamOutSize(), bpb;
#include "archive_string.h"
#include "archive_private.h"
+#define ARCHIVE_WRITE_FILTER_STATE_NEW 1U
+#define ARCHIVE_WRITE_FILTER_STATE_OPEN 2U
+#define ARCHIVE_WRITE_FILTER_STATE_CLOSED 4U
+#define ARCHIVE_WRITE_FILTER_STATE_FATAL 0x8000U
+
struct archive_write;
struct archive_write_filter {
int code;
int bytes_per_block;
int bytes_in_last_block;
+ int state;
};
#if ARCHIVE_VERSION < 4000000
int __archive_write_output(struct archive_write *, const void *, size_t);
int __archive_write_nulls(struct archive_write *, size_t);
int __archive_write_filter(struct archive_write_filter *, const void *, size_t);
-int __archive_write_open_filter(struct archive_write_filter *);
-int __archive_write_close_filter(struct archive_write *);
struct archive_write {
struct archive archive;
archive_write_open(a, &private, my_open, my_write, my_close));
assertEqualInt(1, private.open_called);
assertEqualInt(0, private.write_called);
- assertEqualInt(1, private.close_called);
+ assertEqualInt(0, private.close_called);
assertEqualInt(ARCHIVE_OK, archive_write_free(a));
assertEqualInt(1, private.open_called);
assertEqualInt(0, private.write_called);
- assertEqualInt(1, private.close_called);
+ assertEqualInt(0, private.close_called);
memset(&private, 0, sizeof(private));
private.magic = MAGIC;
archive_write_open(a, &private, my_open, my_write, my_close));
assertEqualInt(1, private.open_called);
assertEqualInt(0, private.write_called);
- assertEqualInt(1, private.close_called);
+ assertEqualInt(0, private.close_called);
assertEqualInt(ARCHIVE_OK, archive_write_free(a));
assertEqualInt(1, private.open_called);
assertEqualInt(0, private.write_called);
- assertEqualInt(1, private.close_called);
+ assertEqualInt(0, private.close_called);
memset(&private, 0, sizeof(private));
private.magic = MAGIC;
archive_write_open(a, &private, my_open, my_write, my_close));
assertEqualInt(1, private.open_called);
assertEqualInt(0, private.write_called);
- assertEqualInt(1, private.close_called);
+ assertEqualInt(0, private.close_called);
assertEqualInt(ARCHIVE_OK, archive_write_free(a));
assertEqualInt(1, private.open_called);
assertEqualInt(0, private.write_called);
- assertEqualInt(1, private.close_called);
+ assertEqualInt(0, private.close_called);
memset(&private, 0, sizeof(private));
private.magic = MAGIC;
archive_write_open(a, &private, my_open, my_write, my_close));
assertEqualInt(1, private.open_called);
assertEqualInt(0, private.write_called);
- assertEqualInt(1, private.close_called);
+ assertEqualInt(0, private.close_called);
assertEqualInt(ARCHIVE_OK, archive_write_free(a));
assertEqualInt(1, private.open_called);
assertEqualInt(0, private.write_called);
- assertEqualInt(1, private.close_called);
+ assertEqualInt(0, private.close_called);
}