struct archive_string_conv *opt_sconv;
struct archive_string_conv *sconv_default;
enum compression requested_compression;
++ int deflate_compression_level;
int init_default_conversion;
+ enum encryption encryption_type;
#define ZIP_FLAG_AVOID_ZIP64 1
#define ZIP_FLAG_FORCE_ZIP64 2
ret = ARCHIVE_OK;
}
return (ret);
- }
-
+ } else if (strcmp(key, "compression-level") == 0) {
+ if (val == NULL || !(val[0] >= '0' && val[0] <= '9') || val[1] != '\0') {
+ return ARCHIVE_WARN;
+ }
+
+ if (val[0] == '0') {
+ zip->requested_compression = COMPRESSION_STORE;
+ return ARCHIVE_OK;
- zip->requested_compression = val[0] - '0';
- return ARCHIVE_OK;
++ } else {
+ #ifdef HAVE_ZLIB_H
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "deflate compression not supported");
++ zip->requested_compression = COMPRESSION_DEFLATE;
++ zip->deflate_compression_level = val[0] - '0';
++ return ARCHIVE_OK;
+ #else
++ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
++ "deflate compression not supported");
+ #endif
++ }
+ } else if (strcmp(key, "encryption") == 0) {
+ if (val == NULL) {
+ zip->encryption_type = ENCRYPTION_NONE;
+ ret = ARCHIVE_OK;
+ } else if (val[0] == '1' || strcmp(val, "traditional") == 0
+ || strcmp(val, "zipcrypt") == 0
+ || strcmp(val, "ZipCrypt") == 0) {
+ if (is_traditional_pkware_encryption_supported()) {
+ zip->encryption_type = ENCRYPTION_TRADITIONAL;
+ ret = ARCHIVE_OK;
+ } else {
+ archive_set_error(&a->archive,
+ ARCHIVE_ERRNO_MISC,
+ "encryption not supported");
+ }
+ } else if (strcmp(val, "aes128") == 0) {
+ if (is_winzip_aes_encryption_supported(
+ ENCRYPTION_WINZIP_AES128)) {
+ zip->encryption_type = ENCRYPTION_WINZIP_AES128;
+ ret = ARCHIVE_OK;
+ } else {
+ archive_set_error(&a->archive,
+ ARCHIVE_ERRNO_MISC,
+ "encryption not supported");
+ }
+ } else if (strcmp(val, "aes256") == 0) {
+ if (is_winzip_aes_encryption_supported(
+ ENCRYPTION_WINZIP_AES256)) {
+ zip->encryption_type = ENCRYPTION_WINZIP_AES256;
+ ret = ARCHIVE_OK;
+ } else {
+ archive_set_error(&a->archive,
+ ARCHIVE_ERRNO_MISC,
+ "encryption not supported");
+ }
+ } else {
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+ "%s: unknown encryption '%s'",
+ a->format_name, val);
+ }
+ return (ret);
} else if (strcmp(key, "experimental") == 0) {
if (val == NULL || val[0] == 0) {
zip->flags &= ~ ZIP_FLAG_EXPERIMENT_xl;
/* "Unspecified" lets us choose the appropriate compression. */
zip->requested_compression = COMPRESSION_UNSPECIFIED;
++#ifdef HAVE_ZLIB_H
++ zip->deflate_compression_level = Z_DEFAULT_COMPRESSION;
++#endif
zip->crc32func = real_crc32;
-#ifdef HAVE_ZLIB_H
+ /* A buffer used for both compression and encryption. */
zip->len_buf = 65536;
zip->buf = malloc(zip->len_buf);
if (zip->buf == NULL) {
zip->stream.opaque = Z_NULL;
zip->stream.next_out = zip->buf;
zip->stream.avail_out = (uInt)zip->len_buf;
-- if (deflateInit2(&zip->stream, Z_DEFAULT_COMPRESSION,
++ if (deflateInit2(&zip->stream, zip->deflate_compression_level,
Z_DEFLATED, -15, 8, Z_DEFAULT_STRATEGY) != Z_OK) {
archive_set_error(&a->archive, ENOMEM,
"Can't init deflate compressor");
#include "test.h"
__FBSDID("$FreeBSD: head/lib/libarchive/test/test_write_format_zip_no_compression.c 201247 2009-12-30 05:59:21Z kientzle $");
++/* File data */
++static const char file_name[] = "file";
++static const char file_data1[] = {'1', '2', '3', '4', '5'};
++static const char file_data2[] = {'6', '7', '8', '9', '0'};
++static const int file_perm = 00644;
++static const short file_uid = 10;
++static const short file_gid = 20;
++
++/* Folder data */
++static const char folder_name[] = "folder/";
++static const int folder_perm = 00755;
++static const short folder_uid = 30;
++static const short folder_gid = 40;
++
++static time_t now;
++
static unsigned long
--bitcrc32(unsigned long c, void *_p, size_t s)
++bitcrc32(unsigned long c, const void *_p, size_t s)
{
/* This is a drop-in replacement for crc32() from zlib.
* Libarchive should be able to correctly generate
return (c);
}
--/* Quick and dirty: Read 2-byte and 4-byte integers from Zip file. */
--static int i2(const char *p) { return ((p[0] & 0xff) | ((p[1] & 0xff) << 8)); }
--static int i4(const char *p) { return (i2(p) | (i2(p + 2) << 16)); }
--
--DEFINE_TEST(test_write_format_zip_compression_store)
++static void verify_write_uncompressed(struct archive *a)
{
-- /* Buffer data */
-- struct archive *a;
struct archive_entry *entry;
-- char buff[100000];
-- const char *buffend;
-- /* p is the pointer to walk over the central directory,
-- * q walks over the local headers, the data and the data descriptors. */
-- const char *p, *q, *local_header, *extra_start;
-- size_t used;
--
-- /* File data */
-- char file_name[] = "file";
-- char file_data1[] = {'1', '2', '3', '4', '5'};
-- char file_data2[] = {'6', '7', '8', '9', '0'};
-- int file_perm = 00644;
-- short file_uid = 10;
-- short file_gid = 20;
--
-- /* Folder data */
-- char folder_name[] = "folder/";
-- int folder_perm = 00755;
-- short folder_uid = 30;
-- short folder_gid = 40;
--
-- /* Time data */
-- time_t t = time(NULL);
-- struct tm *tm = localtime(&t);
--
-- /* Misc variables */
-- unsigned long crc;
--
-- /* Create new ZIP archive in memory without padding. */
-- assert((a = archive_write_new()) != NULL);
-- assertEqualIntA(a, ARCHIVE_OK, archive_write_set_format_zip(a));
-- assertEqualIntA(a, ARCHIVE_OK,
-- archive_write_set_options(a, "zip:compression=store"));
-- assertEqualIntA(a, ARCHIVE_OK,
-- archive_write_set_options(a, "zip:experimental"));
-- assertEqualIntA(a, ARCHIVE_OK, archive_write_add_filter_none(a));
-- assertEqualIntA(a, ARCHIVE_OK, archive_write_set_bytes_per_block(a, 1));
-- assertEqualIntA(a, ARCHIVE_OK, archive_write_set_bytes_in_last_block(a, 1));
-- assertEqualIntA(a, ARCHIVE_OK, archive_write_open_memory(a, buff, sizeof(buff), &used));
/* Write entries. */
archive_entry_set_size(entry, sizeof(file_data1) + sizeof(file_data2));
archive_entry_set_uid(entry, file_uid);
archive_entry_set_gid(entry, file_gid);
-- archive_entry_set_mtime(entry, t, 0);
-- archive_entry_set_atime(entry, t + 3, 0);
++ archive_entry_set_mtime(entry, now, 0);
++ archive_entry_set_atime(entry, now + 3, 0);
assertEqualIntA(a, 0, archive_write_header(a, entry));
assertEqualIntA(a, sizeof(file_data1), archive_write_data(a, file_data1, sizeof(file_data1)));
assertEqualIntA(a, sizeof(file_data2), archive_write_data(a, file_data2, sizeof(file_data2)));
archive_entry_set_size(entry, 0);
archive_entry_set_uid(entry, folder_uid);
archive_entry_set_gid(entry, folder_gid);
-- archive_entry_set_mtime(entry, t, 0);
-- archive_entry_set_ctime(entry, t + 5, 0);
++ archive_entry_set_mtime(entry, now, 0);
++ archive_entry_set_ctime(entry, now + 5, 0);
assertEqualIntA(a, 0, archive_write_header(a, entry));
archive_entry_free(entry);
++}
-- /* Close the archive . */
-- assertEqualIntA(a, ARCHIVE_OK, archive_write_close(a));
-- assertEqualInt(ARCHIVE_OK, archive_write_free(a));
++/* Quick and dirty: Read 2-byte and 4-byte integers from Zip file. */
++static int i2(const char *p) { return ((p[0] & 0xff) | ((p[1] & 0xff) << 8)); }
++static int i4(const char *p) { return (i2(p) | (i2(p + 2) << 16)); }
-- dumpfile("constructed.zip", buff, used);
++static void verify_uncompressed_contents(const char *buff, size_t used)
++{
++ const char *buffend;
++
++ /* Misc variables */
++ unsigned long crc;
++ struct tm *tm = localtime(&now);
++
++ /* p is the pointer to walk over the central directory,
++ * q walks over the local headers, the data and the data descriptors. */
++ const char *p, *q, *local_header, *extra_start;
/* Remember the end of the archive in memory. */
buffend = buff + used;
assertEqualInt(i2(p), 0x5455); /* 'UT' extension header */
assertEqualInt(i2(p + 2), 9); /* 'UT' size */
assertEqualInt(p[4], 3); /* 'UT' flags */
-- assertEqualInt(i4(p + 5), t); /* 'UT' mtime */
-- assertEqualInt(i4(p + 9), t + 3); /* 'UT' atime */
++ assertEqualInt(i4(p + 5), now); /* 'UT' mtime */
++ assertEqualInt(i4(p + 9), now + 3); /* 'UT' atime */
p = p + 4 + i2(p + 2);
assertEqualInt(i2(p), 0x7875); /* 'ux' extension header */
assertEqualInt(i2(p + 2), 11); /* 'ux' size */
assertEqualInt(i2(q), 0x5455); /* 'UT' extension header */
assertEqualInt(i2(q + 2), 9); /* 'UT' size */
assertEqualInt(q[4], 3); /* 'UT' flags */
-- assertEqualInt(i4(q + 5), t); /* 'UT' mtime */
-- assertEqualInt(i4(q + 9), t + 3); /* 'UT' atime */
++ assertEqualInt(i4(q + 5), now); /* 'UT' mtime */
++ assertEqualInt(i4(q + 9), now + 3); /* 'UT' atime */
q = q + 4 + i2(q + 2);
assertEqualInt(i2(q), 0x7875); /* 'ux' extension header */
assertEqualInt(i2(p), 0x5455); /* 'UT' extension header */
assertEqualInt(i2(p + 2), 9); /* 'UT' size */
assertEqualInt(p[4], 5); /* 'UT' flags */
-- assertEqualInt(i4(p + 5), t); /* 'UT' mtime */
-- assertEqualInt(i4(p + 9), t + 5); /* 'UT' atime */
++ assertEqualInt(i4(p + 5), now); /* 'UT' mtime */
++ assertEqualInt(i4(p + 9), now + 5); /* 'UT' atime */
p = p + 4 + i2(p + 2);
assertEqualInt(i2(p), 0x7875); /* 'ux' extension header */
assertEqualInt(i2(p + 2), 11); /* 'ux' size */
assertEqualInt(i2(q), 0x5455); /* 'UT' extension header */
assertEqualInt(i2(q + 2), 9); /* 'UT' size */
assertEqualInt(q[4], 5); /* 'UT' flags */
-- assertEqualInt(i4(q + 5), t); /* 'UT' mtime */
-- assertEqualInt(i4(q + 9), t + 5); /* 'UT' atime */
++ assertEqualInt(i4(q + 5), now); /* 'UT' mtime */
++ assertEqualInt(i4(q + 9), now + 5); /* 'UT' atime */
q = q + 4 + i2(q + 2);
assertEqualInt(i2(q), 0x7875); /* 'ux' extension header */
assertEqualInt(i2(q + 2), 11); /* 'ux' size */
* so the first central directory entry should be next: */
assertEqualMem(q, "PK\001\002", 4); /* Signature */
}
++
++DEFINE_TEST(test_write_format_zip_compression_store)
++{
++ /* Buffer data */
++ struct archive *a;
++ char buff[100000];
++ size_t used;
++
++ /* Time data */
++ now = time(NULL);
++
++ /* Create new ZIP archive in memory without padding. */
++ /* Use compression=store to disable compression. */
++ assert((a = archive_write_new()) != NULL);
++ assertEqualIntA(a, ARCHIVE_OK, archive_write_set_format_zip(a));
++ assertEqualIntA(a, ARCHIVE_OK,
++ archive_write_set_options(a, "zip:compression=store"));
++ assertEqualIntA(a, ARCHIVE_OK,
++ archive_write_set_options(a, "zip:experimental"));
++ assertEqualIntA(a, ARCHIVE_OK, archive_write_add_filter_none(a));
++ assertEqualIntA(a, ARCHIVE_OK, archive_write_set_bytes_per_block(a, 1));
++ assertEqualIntA(a, ARCHIVE_OK, archive_write_set_bytes_in_last_block(a, 1));
++ assertEqualIntA(a, ARCHIVE_OK, archive_write_open_memory(a, buff, sizeof(buff), &used));
++
++ verify_write_uncompressed(a);
++
++ /* Close the archive . */
++ assertEqualIntA(a, ARCHIVE_OK, archive_write_close(a));
++ assertEqualInt(ARCHIVE_OK, archive_write_free(a));
++ dumpfile("constructed.zip", buff, used);
++
++ verify_uncompressed_contents(buff, used);
++
++ /* Create new ZIP archive in memory without padding. */
++ /* Use compression-level=0 to disable compression. */
++ assert((a = archive_write_new()) != NULL);
++ assertEqualIntA(a, ARCHIVE_OK, archive_write_set_format_zip(a));
++ assertEqualIntA(a, ARCHIVE_OK,
++ archive_write_set_options(a, "zip:compression-level=0"));
++ assertEqualIntA(a, ARCHIVE_OK,
++ archive_write_set_options(a, "zip:experimental"));
++ assertEqualIntA(a, ARCHIVE_OK, archive_write_add_filter_none(a));
++ assertEqualIntA(a, ARCHIVE_OK, archive_write_set_bytes_per_block(a, 1));
++ assertEqualIntA(a, ARCHIVE_OK, archive_write_set_bytes_in_last_block(a, 1));
++ assertEqualIntA(a, ARCHIVE_OK, archive_write_open_memory(a, buff, sizeof(buff), &used));
++
++ verify_write_uncompressed(a);
++
++ /* Close the archive . */
++ assertEqualIntA(a, ARCHIVE_OK, archive_write_close(a));
++ assertEqualInt(ARCHIVE_OK, archive_write_free(a));
++ dumpfile("constructed.zip", buff, used);
++
++ verify_uncompressed_contents(buff, used);
++
++}