]> git.ipfire.org Git - thirdparty/libarchive.git/commitdiff
Merge branch 'patch-1' of https://github.com/vlovich/libarchive into vlovich-patch-1
authorTim Kientzle <kientzle@acm.org>
Sun, 14 Dec 2014 18:50:09 +0000 (10:50 -0800)
committerTim Kientzle <kientzle@acm.org>
Sun, 14 Dec 2014 18:50:09 +0000 (10:50 -0800)
Conflicts:
libarchive/archive_write_set_format_zip.c

This was originally submitted as:
   https://github.com/libarchive/libarchive/pull/84

I've made the following corrections:
   * Added a new variable for the deflate compression level (the submitted patch mis-used the requested_compression variable)
   * Extended the Zip store format test to also verify correct results with compression-level=0

TODO: This really needs a new test to exercises non-zero compression-level options.

1  2 
libarchive/archive_write_set_format_zip.c
libarchive/test/test_write_format_zip_compression_store.c

index 00463fac898303128ebc384b69ea78c0c9427b7e,c161c738e830fb8bf8fb56e682e8c16b8a44f6b6..0399b7b793db1fbd7a0e349866b16ea2e1e2323e
@@@ -153,8 -111,7 +153,9 @@@ struct zip 
        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
@@@ -273,47 -223,23 +274,65 @@@ archive_write_zip_options(struct archiv
                        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;
@@@ -444,9 -370,9 +463,12 @@@ archive_write_set_format_zip(struct arc
  
        /* "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) {
@@@ -948,7 -771,7 +970,7 @@@ archive_write_zip_header(struct archive
                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");
index c6761f9dfbf19237546d97713e8bd7537481a479,c6761f9dfbf19237546d97713e8bd7537481a479..9d703a1df25304adc066d112cb1c03035a76d584
  #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);
++
++}