Permalink
Browse files

Enable bzip2 compression to use an external bzip2 program when

libbz2 is unavailable.
  • Loading branch information...
1 parent 9dd48a7 commit d28e6ae9bc1305ca975d3b61babb5d3dc83c0adf @ggcueroad ggcueroad committed Oct 13, 2012
@@ -1,5 +1,6 @@
/*-
* Copyright (c) 2003-2007 Tim Kientzle
+ * Copyright (c) 2012 Michihiro NAKAJIMA
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -54,39 +55,63 @@ archive_write_set_compression_bzip2(struct archive *a)
}
#endif
-#if !defined(HAVE_BZLIB_H) || !defined(BZ_CONFIG_ERROR)
-int
-archive_write_add_filter_bzip2(struct archive *a)
-{
- archive_set_error(a, ARCHIVE_ERRNO_MISC,
- "bzip2 compression not supported on this platform");
- return (ARCHIVE_FATAL);
-}
-#else
-/* Don't compile this if we don't have bzlib. */
-
struct private_data {
int compression_level;
+#if defined(HAVE_BZLIB_H) && defined(BZ_CONFIG_ERROR)
bz_stream stream;
int64_t total_in;
char *compressed;
size_t compressed_buffer_size;
+#else
+ struct archive_write_program_data *pdata;
+#endif
};
-/*
- * Yuck. bzlib.h is not const-correct, so I need this one bit
- * of ugly hackery to convert a const * pointer to a non-const pointer.
- */
-#define SET_NEXT_IN(st,src) \
- (st)->stream.next_in = (char *)(uintptr_t)(const void *)(src)
-
static int archive_compressor_bzip2_close(struct archive_write_filter *);
static int archive_compressor_bzip2_free(struct archive_write_filter *);
static int archive_compressor_bzip2_open(struct archive_write_filter *);
static int archive_compressor_bzip2_options(struct archive_write_filter *,
const char *, const char *);
static int archive_compressor_bzip2_write(struct archive_write_filter *,
const void *, size_t);
+
+/*
+ * Set write options.
+ */
+static int
+archive_compressor_bzip2_options(struct archive_write_filter *f,
+ const char *key, const char *value)
+{
+ struct private_data *data = (struct private_data *)f->data;
+
+ if (strcmp(key, "compression-level") == 0) {
+ if (value == NULL || !(value[0] >= '0' && value[0] <= '9') ||
+ value[1] != '\0')
+ return (ARCHIVE_WARN);
+ data->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 (data->compression_level < 1)
+ data->compression_level = 1;
+ return (ARCHIVE_OK);
+ }
+
+ /* Note: The "warn" return is just to inform the options
+ * supervisor that we didn't handle it. It will generate
+ * a suitable error if no one used this option. */
+ return (ARCHIVE_WARN);
+}
+
+#if defined(HAVE_BZLIB_H) && defined(BZ_CONFIG_ERROR)
+/* Don't compile this if we don't have bzlib. */
+
+/*
+ * Yuck. bzlib.h is not const-correct, so I need this one bit
+ * of ugly hackery to convert a const * pointer to a non-const pointer.
+ */
+#define SET_NEXT_IN(st,src) \
+ (st)->stream.next_in = (char *)(uintptr_t)(const void *)(src)
static int drive_compressor(struct archive_write_filter *,
struct private_data *, int finishing);
@@ -195,34 +220,6 @@ archive_compressor_bzip2_open(struct archive_write_filter *f)
}
/*
- * Set write options.
- */
-static int
-archive_compressor_bzip2_options(struct archive_write_filter *f,
- const char *key, const char *value)
-{
- struct private_data *data = (struct private_data *)f->data;
-
- if (strcmp(key, "compression-level") == 0) {
- if (value == NULL || !(value[0] >= '0' && value[0] <= '9') ||
- value[1] != '\0')
- return (ARCHIVE_WARN);
- data->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 (data->compression_level < 1)
- data->compression_level = 1;
- return (ARCHIVE_OK);
- }
-
- /* Note: The "warn" return is just to inform the options
- * supervisor that we didn't handle it. It will generate
- * a suitable error if no one used this option. */
- return (ARCHIVE_WARN);
-}
-
-/*
* Write data to the compressed stream.
*
* Returns ARCHIVE_OK if all data written, error otherwise.
@@ -343,4 +340,49 @@ drive_compressor(struct archive_write_filter *f,
}
}
+#else /* HAVE_BZLIB_H && BZ_CONFIG_ERROR */
+
+static int
+archive_compressor_bzip2_open(struct archive_write_filter *f)
+{
+ struct private_data *data = (struct private_data *)f->data;
+ struct archive_string as;
+ int r;
+
+ archive_string_init(&as);
+ archive_strcpy(&as, "bzip2");
+
+ /* Specify compression level. */
+ if (data->compression_level > 0) {
+ archive_strcat(&as, " -");
+ archive_strappend_char(&as, '0' + data->compression_level);
+ }
+ r = __archive_write_program_set_cmd(data->pdata, as.s);
+ archive_string_free(&as);
+ if (r != ARCHIVE_OK) {
+ archive_set_error(f->archive, ENOMEM, "Can't allocate memory");
+ return (ARCHIVE_FATAL);
+ }
+ f->write = archive_compressor_bzip2_write;
+
+ return __archive_write_program_open(f, data->pdata);
+}
+
+static int
+archive_compressor_bzip2_write(struct archive_write_filter *f, const void *buff,
+ size_t length)
+{
+ struct private_data *data = (struct private_data *)f->data;
+
+ return __archive_write_program_write(f, data->pdata, buff, length);
+}
+
+static int
+archive_compressor_bzip2_close(struct archive_write_filter *f)
+{
+ struct private_data *data = (struct private_data *)f->data;
+
+ return __archive_write_program_close(f, data->pdata);
+}
+
#endif /* HAVE_BZLIB_H && BZ_CONFIG_ERROR */
@@ -75,7 +75,7 @@ DEFINE_TEST(test_empty_write)
assert((a = archive_write_new()) != NULL);
assertA(0 == archive_write_set_format_ustar(a));
r = archive_write_add_filter_bzip2(a);
- if (r == ARCHIVE_FATAL) {
+ if (r != ARCHIVE_OK && !canBzip2()) {
skipping("Empty write to bzip2-compressed archive");
} else {
assertEqualIntA(a, ARCHIVE_OK, r);
@@ -32,7 +32,10 @@ static void
read_test(const char *name)
{
struct archive* a = archive_read_new();
- if(ARCHIVE_OK != archive_read_support_filter_bzip2(a)) {
+ int r;
+
+ r = archive_read_support_filter_bzip2(a);
+ if((ARCHIVE_WARN == r && !canBzip2()) || ARCHIVE_WARN > r) {
skipping("bzip2 unsupported");
return;
}
@@ -52,11 +55,13 @@ write_test(void)
{
char buff[4096];
struct archive* a = archive_write_new();
+ int r;
assertEqualIntA(a, ARCHIVE_OK, archive_write_set_format_ustar(a));
assertEqualIntA(a, ARCHIVE_OK, archive_write_set_bytes_per_block(a, 10));
- if(ARCHIVE_OK != archive_write_add_filter_bzip2(a)) {
+ r = archive_write_add_filter_bzip2(a);
+ if((ARCHIVE_WARN == r && !canBzip2()) || ARCHIVE_WARN > r) {
skipping("bzip2 unsupported");
return;
}
@@ -131,7 +131,7 @@ test_truncation(const char *compression,
DEFINE_TEST(test_read_truncated_filter)
{
- test_truncation("bzip2", archive_write_add_filter_bzip2, 0);
+ test_truncation("bzip2", archive_write_add_filter_bzip2, canBzip2());
test_truncation("compress", archive_write_add_filter_compress, 0);
test_truncation("gzip", archive_write_add_filter_gzip, canGzip());
test_truncation("lzip", archive_write_add_filter_lzip, 0);
@@ -41,7 +41,7 @@ DEFINE_TEST(test_write_filter_bzip2)
size_t buffsize, datasize;
char path[16];
size_t used1, used2;
- int i, r;
+ int i, r, use_prog;
buffsize = 2000000;
assert(NULL != (buff = (char *)malloc(buffsize)));
@@ -56,16 +56,19 @@ DEFINE_TEST(test_write_filter_bzip2)
assert((a = archive_write_new()) != NULL);
assertEqualIntA(a, ARCHIVE_OK, archive_write_set_format_ustar(a));
r = archive_write_add_filter_bzip2(a);
- if (r == ARCHIVE_FATAL) {
+ use_prog = (r == ARCHIVE_WARN && canBzip2());
+ if (r != ARCHIVE_OK && !use_prog) {
skipping("bzip2 writing not supported on this platform");
assertEqualInt(ARCHIVE_OK, archive_write_free(a));
return;
}
+
assertEqualIntA(a, ARCHIVE_OK,
archive_write_set_bytes_per_block(a, 10));
assertEqualInt(ARCHIVE_FILTER_BZIP2, archive_filter_code(a, 0));
assertEqualString("bzip2", archive_filter_name(a, 0));
- assertEqualIntA(a, ARCHIVE_OK, archive_write_open_memory(a, buff, buffsize, &used1));
+ assertEqualIntA(a, ARCHIVE_OK,
+ archive_write_open_memory(a, buff, buffsize, &used1));
assertEqualInt(ARCHIVE_FILTER_BZIP2, archive_filter_code(a, 0));
assertEqualString("bzip2", archive_filter_name(a, 0));
assert((ae = archive_entry_new()) != NULL);
@@ -85,7 +88,8 @@ DEFINE_TEST(test_write_filter_bzip2)
assert((a = archive_read_new()) != NULL);
assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a));
assertEqualIntA(a, ARCHIVE_OK, archive_read_support_filter_all(a));
- assertEqualIntA(a, ARCHIVE_OK, archive_read_open_memory(a, buff, used1));
+ assertEqualIntA(a, ARCHIVE_OK,
+ archive_read_open_memory(a, buff, used1));
for (i = 0; i < 999; i++) {
sprintf(path, "file%03d", i);
if (!assertEqualInt(0, archive_read_next_header(a, &ae)))
@@ -104,24 +108,31 @@ DEFINE_TEST(test_write_filter_bzip2)
assertEqualIntA(a, ARCHIVE_OK, archive_write_set_format_ustar(a));
assertEqualIntA(a, ARCHIVE_OK,
archive_write_set_bytes_per_block(a, 10));
- assertEqualIntA(a, ARCHIVE_OK, archive_write_add_filter_bzip2(a));
- assertEqualIntA(a, ARCHIVE_FAILED,
- archive_write_set_filter_option(a, NULL, "nonexistent-option", "0"));
- assertEqualIntA(a, ARCHIVE_FAILED,
- archive_write_set_filter_option(a, NULL, "compression-level", "abc"));
- assertEqualIntA(a, ARCHIVE_FAILED,
- archive_write_set_filter_option(a, NULL, "compression-level", "99"));
+ if (use_prog)
+ assertEqualIntA(a, ARCHIVE_WARN,
+ archive_write_add_filter_bzip2(a));
+ else
+ assertEqualIntA(a, ARCHIVE_OK,
+ archive_write_add_filter_bzip2(a));
+ assertEqualIntA(a, ARCHIVE_FAILED, archive_write_set_filter_option(a,
+ NULL, "nonexistent-option", "0"));
+ assertEqualIntA(a, ARCHIVE_FAILED, archive_write_set_filter_option(a,
+ NULL, "compression-level", "abc"));
+ assertEqualIntA(a, ARCHIVE_FAILED, archive_write_set_filter_option(a,
+ NULL, "compression-level", "99"));
+ assertEqualIntA(a, ARCHIVE_OK, archive_write_set_filter_option(a,
+ NULL, "compression-level", "9"));
assertEqualIntA(a, ARCHIVE_OK,
- archive_write_set_filter_option(a, NULL, "compression-level", "9"));
- assertEqualIntA(a, ARCHIVE_OK, archive_write_open_memory(a, buff, buffsize, &used2));
+ archive_write_open_memory(a, buff, buffsize, &used2));
for (i = 0; i < 999; i++) {
sprintf(path, "file%03d", i);
assert((ae = archive_entry_new()) != NULL);
archive_entry_copy_pathname(ae, path);
archive_entry_set_size(ae, datasize);
archive_entry_set_filetype(ae, AE_IFREG);
assertEqualIntA(a, ARCHIVE_OK, archive_write_header(a, ae));
- assertA(datasize == (size_t)archive_write_data(a, data, datasize));
+ assertA(datasize == (size_t)archive_write_data(a, data,
+ datasize));
archive_entry_free(ae);
}
assertEqualIntA(a, ARCHIVE_OK, archive_write_close(a));
@@ -138,7 +149,8 @@ DEFINE_TEST(test_write_filter_bzip2)
assert((a = archive_read_new()) != NULL);
assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a));
assertEqualIntA(a, ARCHIVE_OK, archive_read_support_filter_all(a));
- assertEqualIntA(a, ARCHIVE_OK, archive_read_open_memory(a, buff, used2));
+ assertEqualIntA(a, ARCHIVE_OK,
+ archive_read_open_memory(a, buff, used2));
for (i = 0; i < 999; i++) {
sprintf(path, "file%03d", i);
if (!assertEqualInt(0, archive_read_next_header(a, &ae)))
@@ -156,10 +168,16 @@ DEFINE_TEST(test_write_filter_bzip2)
assertEqualIntA(a, ARCHIVE_OK, archive_write_set_format_ustar(a));
assertEqualIntA(a, ARCHIVE_OK,
archive_write_set_bytes_per_block(a, 10));
- assertEqualIntA(a, ARCHIVE_OK, archive_write_add_filter_bzip2(a));
+ if (use_prog)
+ assertEqualIntA(a, ARCHIVE_WARN,
+ archive_write_add_filter_bzip2(a));
+ else
+ assertEqualIntA(a, ARCHIVE_OK,
+ archive_write_add_filter_bzip2(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_write_set_filter_option(a,
+ NULL, "compression-level", "1"));
assertEqualIntA(a, ARCHIVE_OK,
- archive_write_set_filter_option(a, NULL, "compression-level", "1"));
- assertEqualIntA(a, ARCHIVE_OK, archive_write_open_memory(a, buff, buffsize, &used2));
+ archive_write_open_memory(a, buff, buffsize, &used2));
for (i = 0; i < 999; i++) {
sprintf(path, "file%03d", i);
assert((ae = archive_entry_new()) != NULL);
@@ -183,7 +201,8 @@ DEFINE_TEST(test_write_filter_bzip2)
assert((a = archive_read_new()) != NULL);
assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a));
assertEqualIntA(a, ARCHIVE_OK, archive_read_support_filter_all(a));
- assertEqualIntA(a, ARCHIVE_OK, archive_read_open_memory(a, buff, used2));
+ assertEqualIntA(a, ARCHIVE_OK,
+ archive_read_open_memory(a, buff, used2));
for (i = 0; i < 999; i++) {
sprintf(path, "file%03d", i);
if (!assertEqualInt(0, archive_read_next_header(a, &ae)))
@@ -199,24 +218,45 @@ DEFINE_TEST(test_write_filter_bzip2)
* don't crash or leak memory.
*/
assert((a = archive_write_new()) != NULL);
- assertEqualIntA(a, ARCHIVE_OK, archive_write_add_filter_bzip2(a));
+ if (use_prog)
+ assertEqualIntA(a, ARCHIVE_WARN,
+ archive_write_add_filter_bzip2(a));
+ else
+ assertEqualIntA(a, ARCHIVE_OK,
+ archive_write_add_filter_bzip2(a));
assertEqualInt(ARCHIVE_OK, archive_write_free(a));
assert((a = archive_write_new()) != NULL);
- assertEqualIntA(a, ARCHIVE_OK, archive_write_add_filter_bzip2(a));
+ if (use_prog)
+ assertEqualIntA(a, ARCHIVE_WARN,
+ archive_write_add_filter_bzip2(a));
+ else
+ assertEqualIntA(a, ARCHIVE_OK,
+ archive_write_add_filter_bzip2(a));
assertEqualInt(ARCHIVE_OK, archive_write_close(a));
assertEqualInt(ARCHIVE_OK, archive_write_free(a));
assert((a = archive_write_new()) != NULL);
assertEqualIntA(a, ARCHIVE_OK, archive_write_set_format_ustar(a));
- assertEqualIntA(a, ARCHIVE_OK, archive_write_add_filter_bzip2(a));
+ if (use_prog)
+ assertEqualIntA(a, ARCHIVE_WARN,
+ archive_write_add_filter_bzip2(a));
+ else
+ assertEqualIntA(a, ARCHIVE_OK,
+ archive_write_add_filter_bzip2(a));
assertEqualInt(ARCHIVE_OK, archive_write_close(a));
assertEqualInt(ARCHIVE_OK, archive_write_free(a));
assert((a = archive_write_new()) != NULL);
assertEqualIntA(a, ARCHIVE_OK, archive_write_set_format_ustar(a));
- assertEqualIntA(a, ARCHIVE_OK, archive_write_add_filter_bzip2(a));
- assertEqualIntA(a, ARCHIVE_OK, archive_write_open_memory(a, buff, buffsize, &used2));
+ if (use_prog)
+ assertEqualIntA(a, ARCHIVE_WARN,
+ archive_write_add_filter_bzip2(a));
+ else
+ assertEqualIntA(a, ARCHIVE_OK,
+ archive_write_add_filter_bzip2(a));
+ assertEqualIntA(a, ARCHIVE_OK,
+ archive_write_open_memory(a, buff, buffsize, &used2));
assertEqualInt(ARCHIVE_OK, archive_write_close(a));
assertEqualInt(ARCHIVE_OK, archive_write_free(a));

0 comments on commit d28e6ae

Please sign in to comment.