summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTim Kientzle <kientzle@FreeBSD.org>2009-04-17 00:42:45 +0000
committerTim Kientzle <kientzle@FreeBSD.org>2009-04-17 00:42:45 +0000
commit895272938177dc158627225b0745f722f40b2dd0 (patch)
treec0500748e75cb0cbf40bc51246e3edb6e03f5b75
parent625683944d4a681081b6fd02c61d3c825dff70c3 (diff)
Notes
-rw-r--r--lib/libarchive/archive_write.376
-rw-r--r--lib/libarchive/archive_write.c56
-rw-r--r--lib/libarchive/archive_write_set_compression_bzip2.c198
-rw-r--r--lib/libarchive/archive_write_set_compression_gzip.c262
4 files changed, 360 insertions, 232 deletions
diff --git a/lib/libarchive/archive_write.3 b/lib/libarchive/archive_write.3
index 41d0b03adadd..8228903dc176 100644
--- a/lib/libarchive/archive_write.3
+++ b/lib/libarchive/archive_write.3
@@ -43,6 +43,9 @@
.Nm archive_write_set_compression_gzip ,
.Nm archive_write_set_compression_none ,
.Nm archive_write_set_compression_program ,
+.Nm archive_write_set_compressor_options ,
+.Nm archive_write_set_format_options ,
+.Nm archive_write_set_options ,
.Nm archive_write_open ,
.Nm archive_write_open_fd ,
.Nm archive_write_open_FILE ,
@@ -73,10 +76,7 @@
.Ft int
.Fn archive_write_set_compression_none "struct archive *"
.Ft int
-.Fo archive_write_set_compression_program
-.Fa "struct archive *"
-.Fa "const char * cmd"
-.Fc
+.Fn archive_write_set_compression_program "struct archive *" "const char * cmd"
.Ft int
.Fn archive_write_set_format_cpio "struct archive *"
.Ft int
@@ -90,6 +90,12 @@
.Ft int
.Fn archive_write_set_format_ustar "struct archive *"
.Ft int
+.Fn archive_write_set_format_options "struct archive *" "const char *"
+.Ft int
+.Fn archive_write_set_compressor_options "struct archive *" "const char *"
+.Ft int
+.Fn archive_write_set_options "struct archive *" "const char *"
+.Ft int
.Fo archive_write_open
.Fa "struct archive *"
.Fa "void *client_data"
@@ -210,6 +216,68 @@ Note that the compressed output is always properly blocked.
The archive will be fed into the specified compression program.
The output of that program is blocked and written to the client
write callbacks.
+.It Xo
+.Fn archive_write_set_compressor_options ,
+.Fn archive_write_set_format_options ,
+.Fn archive_write_set_options
+.Xc
+Specifies options that will be passed to the currently-enabled
+compressor and/or format writer.
+The argument is a comma-separated list of individual options.
+Individual options have one of the following forms:
+.Bl -tag -compact -width indent
+.It Ar option=value
+The option/value pair will be provided to every module.
+Modules that do not accept an option with this name will ignore it.
+.It Ar option
+The option will be provided to every module with a value of
+.Dq 1 .
+.It Ar !option
+The option will be provided to every module with a NULL value.
+.It Ar module:option=value , Ar module:option , Ar module:!option
+As above, but the corresponding option and value will be provided
+only to modules whose name matches
+.Ar module .
+.El
+The return value will be
+.Cm ARCHIVE_OK
+if any module accepts the option, or
+.Cm ARCHIVE_WARN
+if no module accepted the option, or
+.Cm ARCHIVE_FATAL
+if there was a fatal error while attempting to process the option.
+.Pp
+The currently supported options are:
+.Bl -tag -compact -width indent
+.It Compressor gzip
+.Bl -tag -compact -width indent
+.It Cm compression-level
+The value is interpreted as a decimal integer specifying the
+gzip compression level.
+.El
+.It Compressor xz
+.Bl -tag -compact -width indent
+.It Cm compression-level
+The value is interpreted as a decimal integer specifying the
+compression level.
+.El
+.It Format mtree
+.Bl -tag -compact -width indent
+.It Cm cksum , Cm device , Cm flags , Cm gid , Cm gname , Cm indent , Cm link , Cm md5 , Cm mode , Cm nlink , Cm rmd160 , Cm sha1 , Cm sha256 , Cm sha384 , Cm sha512 , Cm size , Cm time , Cm uid , Cm uname
+Enable a particular keyword in the mtree output.
+Prefix with an exclamation mark to disable the corresponding keyword.
+The default is equivalent to
+.Dq device, flags, gid, gname, link, mode, nlink, size, time, type, uid, uname .
+.It Cm all
+Enables all of the above keywords.
+.It Cm use-set
+Enables generation of
+.Cm /set
+lines that specify default values for the following files and/or directories.
+.It Cm indent
+XXX needs explanation XXX
+.El
+.El
.It Fn archive_write_open
Freeze the settings, open the archive, and prepare for writing entries.
This is the most generic form of this function, which accepts
diff --git a/lib/libarchive/archive_write.c b/lib/libarchive/archive_write.c
index 54018e7a116f..ef3492918486 100644
--- a/lib/libarchive/archive_write.c
+++ b/lib/libarchive/archive_write.c
@@ -132,8 +132,14 @@ archive_write_set_format_options(struct archive *_a, const char *s)
{
struct archive_write *a = (struct archive_write *)_a;
char key[64], val[64];
- int len, r;
+ int len, r, ret = ARCHIVE_OK;
+ __archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC,
+ ARCHIVE_STATE_NEW, "archive_write_set_format_options");
+ archive_clear_error(&a->archive);
+
+ if (s == NULL || *s == '\0')
+ return (ARCHIVE_OK);
if (a->format_options == NULL)
/* This format does not support option. */
return (ARCHIVE_OK);
@@ -146,14 +152,19 @@ archive_write_set_format_options(struct archive *_a, const char *s)
r = a->format_options(a, key, val);
if (r == ARCHIVE_FATAL)
return (r);
+ if (r < ARCHIVE_OK) { /* This key was not handled. */
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+ "Unsupported option ``%s''", key);
+ ret = ARCHIVE_WARN;
+ }
s += len;
}
if (len < 0) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "Illegal format options.");
+ "Malformed options string.");
return (ARCHIVE_WARN);
}
- return (ARCHIVE_OK);
+ return (ret);
}
/*
@@ -165,10 +176,20 @@ archive_write_set_compressor_options(struct archive *_a, const char *s)
struct archive_write *a = (struct archive_write *)_a;
char key[64], val[64];
int len, r;
+ int ret = ARCHIVE_OK;
- if (a->compressor.options == NULL)
- /* This compressor does not support option. */
+ __archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC,
+ ARCHIVE_STATE_NEW, "archive_write_set_compressor_options");
+ archive_clear_error(&a->archive);
+
+ if (s == NULL || *s == '\0')
return (ARCHIVE_OK);
+ if (a->compressor.options == NULL) {
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+ "Unsupported option ``%s''", s);
+ /* This compressor does not support option. */
+ return (ARCHIVE_WARN);
+ }
while ((len = __archive_parse_options(s, a->archive.compression_name,
sizeof(key), key, sizeof(val), val)) > 0) {
@@ -178,6 +199,11 @@ archive_write_set_compressor_options(struct archive *_a, const char *s)
r = a->compressor.options(a, key, val);
if (r == ARCHIVE_FATAL)
return (r);
+ if (r < ARCHIVE_OK) {
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+ "Unsupported option ``%s''", key);
+ ret = ARCHIVE_WARN;
+ }
s += len;
}
if (len < 0) {
@@ -185,7 +211,7 @@ archive_write_set_compressor_options(struct archive *_a, const char *s)
"Illegal format options.");
return (ARCHIVE_WARN);
}
- return (ARCHIVE_OK);
+ return (ret);
}
/*
@@ -194,14 +220,16 @@ archive_write_set_compressor_options(struct archive *_a, const char *s)
int
archive_write_set_options(struct archive *_a, const char *s)
{
- int r;
-
- r = archive_write_set_format_options(_a, s);
- if (r != ARCHIVE_OK)
- return (r);
- r = archive_write_set_compressor_options(_a, s);
- if (r != ARCHIVE_OK)
- return (r);
+ int r1, r2;
+
+ r1 = archive_write_set_format_options(_a, s);
+ if (r1 < ARCHIVE_WARN)
+ return (r1);
+ r2 = archive_write_set_compressor_options(_a, s);
+ if (r2 < ARCHIVE_WARN)
+ return (r2);
+ if (r1 == ARCHIVE_WARN && r2 == ARCHIVE_WARN)
+ return (ARCHIVE_WARN);
return (ARCHIVE_OK);
}
diff --git a/lib/libarchive/archive_write_set_compression_bzip2.c b/lib/libarchive/archive_write_set_compression_bzip2.c
index 592c52682611..ccf2229d6d97 100644
--- a/lib/libarchive/archive_write_set_compression_bzip2.c
+++ b/lib/libarchive/archive_write_set_compression_bzip2.c
@@ -47,9 +47,10 @@ __FBSDID("$FreeBSD$");
#ifndef HAVE_BZLIB_H
int
-archive_write_set_compression_bzip2(struct archive *_a)
+archive_write_set_compression_bzip2(struct archive *a)
{
- /* Unsupported bzip2 compression, we don't have bzlib */
+ archive_set_error(a, ARCHIVE_ERRNO_MISC,
+ "bzip2 compression not supported on this platform");
return (ARCHIVE_FATAL);
}
#else
@@ -62,6 +63,9 @@ struct private_data {
size_t compressed_buffer_size;
};
+struct private_config {
+ int compression_level;
+};
/*
* Yuck. bzlib.h is not const-correct, so I need this one bit
@@ -72,6 +76,8 @@ struct private_data {
static int archive_compressor_bzip2_finish(struct archive_write *);
static int archive_compressor_bzip2_init(struct archive_write *);
+static int archive_compressor_bzip2_options(struct archive_write *,
+ const char *, const char *);
static int archive_compressor_bzip2_write(struct archive_write *,
const void *, size_t);
static int drive_compressor(struct archive_write *, struct private_data *,
@@ -84,9 +90,21 @@ int
archive_write_set_compression_bzip2(struct archive *_a)
{
struct archive_write *a = (struct archive_write *)_a;
+ struct private_config *config;
__archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC,
ARCHIVE_STATE_NEW, "archive_write_set_compression_bzip2");
+ config = malloc(sizeof(*config));
+ if (config == NULL) {
+ archive_set_error(&a->archive, ENOMEM, "Out of memory");
+ return (ARCHIVE_FATAL);
+ }
+ a->compressor.config = config;
+ a->compressor.finish = archive_compressor_bzip2_finish;
+ config->compression_level = 9; /* default */
a->compressor.init = &archive_compressor_bzip2_init;
+ a->compressor.options = &archive_compressor_bzip2_options;
+ a->archive.compression_code = ARCHIVE_COMPRESSION_BZIP2;
+ a->archive.compression_name = "bzip2";
return (ARCHIVE_OK);
}
@@ -98,10 +116,9 @@ archive_compressor_bzip2_init(struct archive_write *a)
{
int ret;
struct private_data *state;
+ struct private_config *config;
- a->archive.compression_code = ARCHIVE_COMPRESSION_BZIP2;
- a->archive.compression_name = "bzip2";
-
+ config = (struct private_config *)a->compressor.config;
if (a->client_opener != NULL) {
ret = (a->client_opener)(&a->archive, a->client_data);
if (ret != 0)
@@ -129,10 +146,10 @@ archive_compressor_bzip2_init(struct archive_write *a)
state->stream.next_out = state->compressed;
state->stream.avail_out = state->compressed_buffer_size;
a->compressor.write = archive_compressor_bzip2_write;
- a->compressor.finish = archive_compressor_bzip2_finish;
/* Initialize compression library */
- ret = BZ2_bzCompressInit(&(state->stream), 9, 0, 30);
+ ret = BZ2_bzCompressInit(&(state->stream),
+ config->compression_level, 0, 30);
if (ret == BZ_OK) {
a->compressor.data = state;
return (ARCHIVE_OK);
@@ -168,6 +185,32 @@ archive_compressor_bzip2_init(struct archive_write *a)
}
/*
+ * Set write options.
+ */
+static int
+archive_compressor_bzip2_options(struct archive_write *a, const char *key,
+ const char *value)
+{
+ struct private_config *config;
+
+ config = (struct private_config *)a->compressor.config;
+ if (strcmp(key, "compression-level") == 0) {
+ if (value == NULL || !(value[0] >= '0' && value[0] <= '9') ||
+ value[1] != '\0')
+ return (ARCHIVE_WARN);
+ config->compression_level = value[0] - '0';
+ /* Make '0' be a synonym for '1'. */
+ /* This way, bzip2 compressor supports the same 0..9
+ * range of levels as gzip. */
+ if (config->compression_level < 1)
+ config->compression_level = 1;
+ return (ARCHIVE_OK);
+ }
+
+ return (ARCHIVE_WARN);
+}
+
+/*
* Write data to the compressed stream.
*
* Returns ARCHIVE_OK if all data written, error otherwise.
@@ -212,83 +255,88 @@ archive_compressor_bzip2_finish(struct archive_write *a)
ssize_t bytes_written;
unsigned tocopy;
- state = (struct private_data *)a->compressor.data;
ret = ARCHIVE_OK;
- if (a->client_writer == NULL) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,
- "No write callback is registered?\n"
- "This is probably an internal programming error.");
- ret = ARCHIVE_FATAL;
- goto cleanup;
- }
+ state = (struct private_data *)a->compressor.data;
+ if (state != NULL) {
+ if (a->client_writer == NULL) {
+ archive_set_error(&a->archive,
+ ARCHIVE_ERRNO_PROGRAMMER,
+ "No write callback is registered?\n"
+ "This is probably an internal programming error.");
+ ret = ARCHIVE_FATAL;
+ goto cleanup;
+ }
- /* By default, always pad the uncompressed data. */
- if (a->pad_uncompressed) {
- tocopy = a->bytes_per_block -
- (state->total_in % a->bytes_per_block);
- while (tocopy > 0 && tocopy < (unsigned)a->bytes_per_block) {
- SET_NEXT_IN(state, a->nulls);
- state->stream.avail_in = tocopy < a->null_length ?
- tocopy : a->null_length;
- state->total_in += state->stream.avail_in;
- tocopy -= state->stream.avail_in;
- ret = drive_compressor(a, state, 0);
- if (ret != ARCHIVE_OK)
- goto cleanup;
+ /* By default, always pad the uncompressed data. */
+ if (a->pad_uncompressed) {
+ tocopy = a->bytes_per_block -
+ (state->total_in % a->bytes_per_block);
+ while (tocopy > 0 && tocopy < (unsigned)a->bytes_per_block) {
+ SET_NEXT_IN(state, a->nulls);
+ state->stream.avail_in = tocopy < a->null_length ?
+ tocopy : a->null_length;
+ state->total_in += state->stream.avail_in;
+ tocopy -= state->stream.avail_in;
+ ret = drive_compressor(a, state, 0);
+ if (ret != ARCHIVE_OK)
+ goto cleanup;
+ }
}
- }
- /* Finish compression cycle. */
- if ((ret = drive_compressor(a, state, 1)))
- goto cleanup;
-
- /* Optionally, pad the final compressed block. */
- block_length = state->stream.next_out - state->compressed;
-
-
- /* Tricky calculation to determine size of last block. */
- target_block_length = block_length;
- if (a->bytes_in_last_block <= 0)
- /* Default or Zero: pad to full block */
- target_block_length = a->bytes_per_block;
- else
- /* Round length 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->stream.next_out, 0,
- target_block_length - block_length);
- block_length = target_block_length;
- }
+ /* Finish compression cycle. */
+ if ((ret = drive_compressor(a, state, 1)))
+ goto cleanup;
+
+ /* Optionally, pad the final compressed block. */
+ block_length = state->stream.next_out - state->compressed;
+
+ /* Tricky calculation to determine size of last block. */
+ target_block_length = block_length;
+ if (a->bytes_in_last_block <= 0)
+ /* Default or Zero: pad to full block */
+ target_block_length = a->bytes_per_block;
+ else
+ /* Round length 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->stream.next_out, 0,
+ target_block_length - block_length);
+ block_length = target_block_length;
+ }
- /* Write the last block */
- bytes_written = (a->client_writer)(&a->archive, a->client_data,
- state->compressed, block_length);
+ /* Write the last block */
+ bytes_written = (a->client_writer)(&a->archive, a->client_data,
+ state->compressed, block_length);
- /* TODO: Handle short write of final block. */
- if (bytes_written <= 0)
- ret = ARCHIVE_FATAL;
- else {
- a->archive.raw_position += ret;
- ret = ARCHIVE_OK;
- }
+ /* TODO: Handle short write of final block. */
+ if (bytes_written <= 0)
+ ret = ARCHIVE_FATAL;
+ else {
+ a->archive.raw_position += ret;
+ ret = ARCHIVE_OK;
+ }
- /* Cleanup: shut down compressor, release memory, etc. */
+ /* Cleanup: shut down compressor, release memory, etc. */
cleanup:
- switch (BZ2_bzCompressEnd(&(state->stream))) {
- case BZ_OK:
- break;
- default:
- archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,
- "Failed to clean up compressor");
- ret = ARCHIVE_FATAL;
- }
+ switch (BZ2_bzCompressEnd(&(state->stream))) {
+ case BZ_OK:
+ break;
+ default:
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,
+ "Failed to clean up compressor");
+ ret = ARCHIVE_FATAL;
+ }
- free(state->compressed);
- free(state);
+ free(state->compressed);
+ free(state);
+ }
+ /* Free configuration data even if we were never fully initialized. */
+ free(a->compressor.config);
+ a->compressor.config = NULL;
return (ret);
}
diff --git a/lib/libarchive/archive_write_set_compression_gzip.c b/lib/libarchive/archive_write_set_compression_gzip.c
index 1588c9eeacb3..701d6a8d9dae 100644
--- a/lib/libarchive/archive_write_set_compression_gzip.c
+++ b/lib/libarchive/archive_write_set_compression_gzip.c
@@ -47,9 +47,10 @@ __FBSDID("$FreeBSD$");
#ifndef HAVE_ZLIB_H
int
-archive_write_set_compression_gzip(struct archive *_a)
+archive_write_set_compression_gzip(struct archive *a)
{
- /* Unsupported gzip compression, we don't have zlib */
+ archive_set_error(a, ARCHIVE_ERRNO_MISC,
+ "gzip compression not supported on this platform");
return (ARCHIVE_FATAL);
}
#else
@@ -61,7 +62,9 @@ struct private_data {
unsigned char *compressed;
size_t compressed_buffer_size;
unsigned long crc;
- /* Options */
+};
+
+struct private_config {
int compression_level;
};
@@ -90,9 +93,19 @@ int
archive_write_set_compression_gzip(struct archive *_a)
{
struct archive_write *a = (struct archive_write *)_a;
+ struct private_config *config;
__archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC,
ARCHIVE_STATE_NEW, "archive_write_set_compression_gzip");
+ config = malloc(sizeof(*config));
+ if (config == NULL) {
+ archive_set_error(&a->archive, ENOMEM, "Out of memory");
+ return (ARCHIVE_FATAL);
+ }
+ a->compressor.config = config;
+ a->compressor.finish = &archive_compressor_gzip_finish;
+ config->compression_level = Z_DEFAULT_COMPRESSION;
a->compressor.init = &archive_compressor_gzip_init;
+ a->compressor.options = &archive_compressor_gzip_options;
a->archive.compression_code = ARCHIVE_COMPRESSION_GZIP;
a->archive.compression_name = "gzip";
return (ARCHIVE_OK);
@@ -106,10 +119,10 @@ archive_compressor_gzip_init(struct archive_write *a)
{
int ret;
struct private_data *state;
+ struct private_config *config;
time_t t;
- a->archive.compression_code = ARCHIVE_COMPRESSION_GZIP;
- a->archive.compression_name = "gzip";
+ config = (struct private_config *)a->compressor.config;
if (a->client_opener != NULL) {
ret = (a->client_opener)(&a->archive, a->client_data);
@@ -147,7 +160,6 @@ archive_compressor_gzip_init(struct archive_write *a)
state->compressed_buffer_size = a->bytes_per_block;
state->compressed = (unsigned char *)malloc(state->compressed_buffer_size);
state->crc = crc32(0L, NULL, 0);
- state->compression_level = Z_DEFAULT_COMPRESSION;
if (state->compressed == NULL) {
archive_set_error(&a->archive, ENOMEM,
@@ -174,13 +186,11 @@ archive_compressor_gzip_init(struct archive_write *a)
state->stream.next_out += 10;
state->stream.avail_out -= 10;
- a->compressor.options = archive_compressor_gzip_options;
a->compressor.write = archive_compressor_gzip_write;
- a->compressor.finish = archive_compressor_gzip_finish;
/* Initialize compression library. */
ret = deflateInit2(&(state->stream),
- state->compression_level,
+ config->compression_level,
Z_DEFLATED,
-15 /* < 0 to suppress zlib header */,
8,
@@ -225,45 +235,15 @@ static int
archive_compressor_gzip_options(struct archive_write *a, const char *key,
const char *value)
{
- struct private_data *state;
- int ret;
+ struct private_config *config;
- state = (struct private_data *)a->compressor.data;
+ config = (struct private_config *)a->compressor.config;
if (strcmp(key, "compression-level") == 0) {
- int level;
-
if (value == NULL || !(value[0] >= '0' && value[0] <= '9') ||
value[1] != '\0')
return (ARCHIVE_WARN);
- level = value[0] - '0';
- if (level == state->compression_level)
- return (ARCHIVE_OK);
-
- ret = deflateParams(&(state->stream), level,
- Z_DEFAULT_STRATEGY);
- if (ret == Z_OK) {
- state->compression_level = level;
- return (ARCHIVE_OK);
- }
- switch (ret) {
- case Z_STREAM_ERROR:
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "Internal error updating params "
- "compression library: state was inconsistent "
- "or parameter was invalid");
- break;
- case Z_BUF_ERROR:
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "Internal error updating params "
- "compression library: out buffer was zero");
- break;
- default:
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "Internal error updatng params "
- "compression library");
- break;
- }
- return (ARCHIVE_FATAL);
+ config->compression_level = value[0] - '0';
+ return (ARCHIVE_OK);
}
return (ARCHIVE_WARN);
@@ -301,7 +281,6 @@ archive_compressor_gzip_write(struct archive_write *a, const void *buff,
return (ARCHIVE_OK);
}
-
/*
* Finish the compression...
*/
@@ -316,113 +295,118 @@ archive_compressor_gzip_finish(struct archive_write *a)
state = (struct private_data *)a->compressor.data;
ret = 0;
- if (a->client_writer == NULL) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,
- "No write callback is registered? "
- "This is probably an internal programming error.");
- ret = ARCHIVE_FATAL;
- goto cleanup;
- }
+ if (state != NULL) {
+ if (a->client_writer == NULL) {
+ archive_set_error(&a->archive,
+ ARCHIVE_ERRNO_PROGRAMMER,
+ "No write callback is registered? "
+ "This is probably an internal programming error.");
+ ret = ARCHIVE_FATAL;
+ goto cleanup;
+ }
+
+ /* By default, always pad the uncompressed data. */
+ if (a->pad_uncompressed) {
+ tocopy = a->bytes_per_block -
+ (state->total_in % a->bytes_per_block);
+ while (tocopy > 0 && tocopy < (unsigned)a->bytes_per_block) {
+ SET_NEXT_IN(state, a->nulls);
+ state->stream.avail_in = tocopy < a->null_length ?
+ tocopy : a->null_length;
+ state->crc = crc32(state->crc, a->nulls,
+ state->stream.avail_in);
+ state->total_in += state->stream.avail_in;
+ tocopy -= state->stream.avail_in;
+ ret = drive_compressor(a, state, 0);
+ if (ret != ARCHIVE_OK)
+ goto cleanup;
+ }
+ }
+
+ /* Finish compression cycle */
+ if (((ret = drive_compressor(a, state, 1))) != ARCHIVE_OK)
+ goto cleanup;
- /* By default, always pad the uncompressed data. */
- if (a->pad_uncompressed) {
- tocopy = a->bytes_per_block -
- (state->total_in % a->bytes_per_block);
- while (tocopy > 0 && tocopy < (unsigned)a->bytes_per_block) {
- SET_NEXT_IN(state, a->nulls);
- state->stream.avail_in = tocopy < a->null_length ?
- tocopy : a->null_length;
- state->crc = crc32(state->crc, a->nulls,
- state->stream.avail_in);
- state->total_in += state->stream.avail_in;
- tocopy -= state->stream.avail_in;
- ret = drive_compressor(a, state, 0);
- if (ret != ARCHIVE_OK)
+ /* Build trailer: 4-byte CRC and 4-byte length. */
+ trailer[0] = (state->crc)&0xff;
+ trailer[1] = (state->crc >> 8)&0xff;
+ trailer[2] = (state->crc >> 16)&0xff;
+ trailer[3] = (state->crc >> 24)&0xff;
+ trailer[4] = (state->total_in)&0xff;
+ trailer[5] = (state->total_in >> 8)&0xff;
+ trailer[6] = (state->total_in >> 16)&0xff;
+ trailer[7] = (state->total_in >> 24)&0xff;
+
+ /* Add trailer to current block. */
+ tocopy = 8;
+ if (tocopy > state->stream.avail_out)
+ tocopy = state->stream.avail_out;
+ memcpy(state->stream.next_out, trailer, tocopy);
+ state->stream.next_out += tocopy;
+ state->stream.avail_out -= tocopy;
+
+ /* If it overflowed, flush and start a new block. */
+ if (tocopy < 8) {
+ bytes_written = (a->client_writer)(&a->archive, a->client_data,
+ state->compressed, state->compressed_buffer_size);
+ if (bytes_written <= 0) {
+ ret = ARCHIVE_FATAL;
goto cleanup;
+ }
+ a->archive.raw_position += bytes_written;
+ state->stream.next_out = state->compressed;
+ state->stream.avail_out = state->compressed_buffer_size;
+ memcpy(state->stream.next_out, trailer + tocopy, 8-tocopy);
+ state->stream.next_out += 8-tocopy;
+ state->stream.avail_out -= 8-tocopy;
}
- }
- /* Finish compression cycle */
- if (((ret = drive_compressor(a, state, 1))) != ARCHIVE_OK)
- goto cleanup;
-
- /* Build trailer: 4-byte CRC and 4-byte length. */
- trailer[0] = (state->crc)&0xff;
- trailer[1] = (state->crc >> 8)&0xff;
- trailer[2] = (state->crc >> 16)&0xff;
- trailer[3] = (state->crc >> 24)&0xff;
- trailer[4] = (state->total_in)&0xff;
- trailer[5] = (state->total_in >> 8)&0xff;
- trailer[6] = (state->total_in >> 16)&0xff;
- trailer[7] = (state->total_in >> 24)&0xff;
-
- /* Add trailer to current block. */
- tocopy = 8;
- if (tocopy > state->stream.avail_out)
- tocopy = state->stream.avail_out;
- memcpy(state->stream.next_out, trailer, tocopy);
- state->stream.next_out += tocopy;
- state->stream.avail_out -= tocopy;
-
- /* If it overflowed, flush and start a new block. */
- if (tocopy < 8) {
+ /* Optionally, pad the final compressed block. */
+ block_length = state->stream.next_out - state->compressed;
+
+ /* Tricky calculation to determine size of last block. */
+ target_block_length = block_length;
+ if (a->bytes_in_last_block <= 0)
+ /* Default or Zero: pad to full block */
+ target_block_length = a->bytes_per_block;
+ else
+ /* Round length 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->stream.next_out, 0,
+ target_block_length - block_length);
+ block_length = target_block_length;
+ }
+
+ /* Write the last block */
bytes_written = (a->client_writer)(&a->archive, a->client_data,
- state->compressed, state->compressed_buffer_size);
+ state->compressed, block_length);
if (bytes_written <= 0) {
ret = ARCHIVE_FATAL;
goto cleanup;
}
a->archive.raw_position += bytes_written;
- state->stream.next_out = state->compressed;
- state->stream.avail_out = state->compressed_buffer_size;
- memcpy(state->stream.next_out, trailer + tocopy, 8-tocopy);
- state->stream.next_out += 8-tocopy;
- state->stream.avail_out -= 8-tocopy;
- }
- /* Optionally, pad the final compressed block. */
- block_length = state->stream.next_out - state->compressed;
-
-
- /* Tricky calculation to determine size of last block. */
- target_block_length = block_length;
- if (a->bytes_in_last_block <= 0)
- /* Default or Zero: pad to full block */
- target_block_length = a->bytes_per_block;
- else
- /* Round length 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->stream.next_out, 0,
- target_block_length - block_length);
- block_length = target_block_length;
- }
-
- /* Write the last block */
- bytes_written = (a->client_writer)(&a->archive, a->client_data,
- state->compressed, block_length);
- if (bytes_written <= 0) {
- ret = ARCHIVE_FATAL;
- goto cleanup;
- }
- a->archive.raw_position += bytes_written;
-
- /* Cleanup: shut down compressor, release memory, etc. */
-cleanup:
- switch (deflateEnd(&(state->stream))) {
- case Z_OK:
- break;
- default:
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "Failed to clean up compressor");
- ret = ARCHIVE_FATAL;
+ /* Cleanup: shut down compressor, release memory, etc. */
+ cleanup:
+ switch (deflateEnd(&(state->stream))) {
+ case Z_OK:
+ break;
+ default:
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+ "Failed to clean up compressor");
+ ret = ARCHIVE_FATAL;
+ }
+ free(state->compressed);
+ free(state);
}
- free(state->compressed);
- free(state);
+ /* Clean up config area even if we never initialized. */
+ free(a->compressor.config);
+ a->compressor.config = NULL;
return (ret);
}