Permalink
Browse files

Fix a bug in 7zip writer that the writer cannot correctly handle

large data(more than 60K bytes) in a writing request.
  • Loading branch information...
1 parent e00007f commit 1f5f0c47bb359faceb815cd8588f39905fdf744c @ggcueroad ggcueroad committed Dec 2, 2012
Showing with 142 additions and 2 deletions.
  1. +6 −2 libarchive/archive_write_set_format_7zip.c
  2. +136 −0 libarchive/test/test_write_format_7zip.c
@@ -566,7 +566,7 @@ compress_out(struct archive_write *a, const void *buff, size_t s,
(unsigned)s);
zip->stream.next_in = (const unsigned char *)buff;
zip->stream.avail_in = s;
- do {
+ for (;;) {
/* Compress file data. */
r = compression_code(&(a->archive), &(zip->stream), run);
if (r != ARCHIVE_OK && r != ARCHIVE_EOF)
@@ -580,8 +580,12 @@ compress_out(struct archive_write *a, const void *buff, size_t s,
if (zip->crc32flg & ENCODED_CRC32)
zip->encoded_crc32 = crc32(zip->encoded_crc32,
zip->wbuff, sizeof(zip->wbuff));
+ if (run == ARCHIVE_Z_FINISH && r != ARCHIVE_EOF)
+ continue;
}
- } while (zip->stream.avail_in);
+ if (zip->stream.avail_in == 0)
+ break;
+ }
if (run == ARCHIVE_Z_FINISH) {
uint64_t bytes = sizeof(zip->wbuff) - zip->stream.avail_out;
if (write_to_temp(a, zip->wbuff, (size_t)bytes) != ARCHIVE_OK)
@@ -789,6 +789,106 @@ test_only_empty_files(void)
free(buff);
}
+#define LARGE_SIZE (16*1024*1024)
+static void
+test_large(const char *compression_type)
+{
+ static char filedata[LARGE_SIZE];
+ static char filedata2[LARGE_SIZE];
+ struct archive_entry *ae;
+ struct archive *a;
+ size_t used;
+ size_t buffsize = LARGE_SIZE + 1024 * 256;
+ char *buff;
+ unsigned i;
+
+ buff = malloc(buffsize);
+
+ /* Create a new archive in memory. */
+ assert((a = archive_write_new()) != NULL);
+ assertEqualIntA(a, ARCHIVE_OK, archive_write_set_format_7zip(a));
+ if (compression_type != NULL &&
+ ARCHIVE_OK != archive_write_set_format_option(a, "7zip",
+ "compression", compression_type)) {
+ skipping("%s writing not fully supported on this platform",
+ compression_type);
+ assertEqualInt(ARCHIVE_OK, archive_write_free(a));
+ free(buff);
+ return;
+ }
+ assertEqualIntA(a, ARCHIVE_OK, archive_write_add_filter_none(a));
+ assertEqualIntA(a, ARCHIVE_OK,
+ archive_write_open_memory(a, buff, buffsize, &used));
+
+ /*
+ * Write a large file to it.
+ */
+ assert((ae = archive_entry_new()) != NULL);
+ archive_entry_set_mtime(ae, 1, 100);
+ assertEqualInt(1, archive_entry_mtime(ae));
+ assertEqualInt(100, archive_entry_mtime_nsec(ae));
+ archive_entry_copy_pathname(ae, "file");
+ assertEqualString("file", archive_entry_pathname(ae));
+ archive_entry_set_mode(ae, AE_IFREG | 0755);
+ assertEqualInt((AE_IFREG | 0755), archive_entry_mode(ae));
+ archive_entry_set_size(ae, sizeof(filedata));
+
+ assertEqualInt(0, archive_write_header(a, ae));
+ archive_entry_free(ae);
+ if (strcmp(compression_type, "ppmd") == 0) {
+ /* NOTE: PPMd cannot handle random data correctly.*/
+ memset(filedata, 'a', sizeof(filedata));
+ } else {
+ for (i = 0; i < sizeof(filedata); i++)
+ filedata[i] = (char)rand();
+ }
+ assertEqualInt(sizeof(filedata),
+ archive_write_data(a, filedata, sizeof(filedata)));
+
+ /* Close out the archive. */
+ assertEqualIntA(a, ARCHIVE_OK, archive_write_close(a));
+ assertEqualInt(ARCHIVE_OK, archive_write_free(a));
+
+ /* Verify the initial header. */
+ assertEqualMem(buff, "\x37\x7a\xbc\xaf\x27\x1c\x00\x03", 8);
+
+ /*
+ * Now, read the data back.
+ */
+ /* With the test memory reader -- seeking mode. */
+ 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, read_open_memory_seek(a, buff, used, 7));
+
+ /*
+ * Read and verify a large file.
+ */
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
+ assertEqualInt(1, archive_entry_mtime(ae));
+ assertEqualInt(100, archive_entry_mtime_nsec(ae));
+ assertEqualInt(0, archive_entry_atime(ae));
+ assertEqualInt(0, archive_entry_ctime(ae));
+ assertEqualString("file", archive_entry_pathname(ae));
+ assertEqualInt(AE_IFREG | 0755, archive_entry_mode(ae));
+ assertEqualInt(sizeof(filedata), archive_entry_size(ae));
+ assertEqualIntA(a, sizeof(filedata2),
+ archive_read_data(a, filedata2, sizeof(filedata2)));
+ assertEqualMem(filedata, filedata2, sizeof(filedata));
+
+ /* Verify the end of the archive. */
+ assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header(a, &ae));
+
+ /* Verify archive format. */
+ assertEqualIntA(a, ARCHIVE_FILTER_NONE, archive_filter_code(a, 0));
+ assertEqualIntA(a, ARCHIVE_FORMAT_7ZIP, archive_format(a));
+
+ assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+ assertEqualInt(ARCHIVE_OK, archive_read_free(a));
+
+ free(buff);
+}
+
DEFINE_TEST(test_write_format_7zip)
{
/* Test that making a 7-Zip archive file by default compression
@@ -814,3 +914,39 @@ DEFINE_TEST(test_write_format_7zip)
test_only_empty_file();
test_only_empty_files();
}
+
+DEFINE_TEST(test_write_format_7zip_large_copy)
+{
+ /* Test that making a 7-Zip archive file without compression. */
+ test_large("copy");
+}
+
+DEFINE_TEST(test_write_format_7zip_large_deflate)
+{
+ /* Test that making a 7-Zip archive file with deflate compression. */
+ test_large("deflate");
+}
+
+DEFINE_TEST(test_write_format_7zip_large_bzip2)
+{
+ /* Test that making a 7-Zip archive file with bzip2 compression. */
+ test_large("bzip2");
+}
+
+DEFINE_TEST(test_write_format_7zip_large_lzma1)
+{
+ /* Test that making a 7-Zip archive file with lzma1 compression. */
+ test_large("lzma1");
+}
+
+DEFINE_TEST(test_write_format_7zip_large_lzma2)
+{
+ /* Test that making a 7-Zip archive file with lzma2 compression. */
+ test_large("lzma2");
+}
+
+DEFINE_TEST(test_write_format_7zip_large_ppmd)
+{
+ /* Test that making a 7-Zip archive file with PPMd compression. */
+ test_large("ppmd");
+}

0 comments on commit 1f5f0c4

Please sign in to comment.