From 649aa3ae585af1ab7a564f1152efe91c3cf01945 Mon Sep 17 00:00:00 2001 From: Tim Kientzle Date: Thu, 2 Jan 2014 06:14:20 -0800 Subject: [PATCH] Add a bitmap to indicate which fields are included for compression and for future expansion --- libarchive/archive_read_support_format_zip.c | 59 +++++++++++++++++-- libarchive/archive_write_set_format_zip.c | 5 +- .../test_write_format_zip_compression_store.c | 22 +++---- libarchive/test/test_write_format_zip_file.c | 13 ++-- .../test/test_write_format_zip_file_zip64.c | 11 ++-- 5 files changed, 82 insertions(+), 28 deletions(-) diff --git a/libarchive/archive_read_support_format_zip.c b/libarchive/archive_read_support_format_zip.c index 3ac6085e8..1c653a608 100644 --- a/libarchive/archive_read_support_format_zip.c +++ b/libarchive/archive_read_support_format_zip.c @@ -340,21 +340,51 @@ process_extra(const char *p, size_t extra_length, struct zip_entry* zip_entry) break; } case 0x414C: + { /* Experimental 'LA' field */ - if (datasize >= 1) { - // 1 byte system identifier - zip_entry->system = p[offset]; + int bitmap, bitmap_last; + + if (datasize < 1) + break; + bitmap_last = bitmap = 0xff & p[offset]; + offset += 1; + datasize -= 1; + + /* We only support first 7 bits of bitmap; skip rest. */ + while ((bitmap_last & 0x80) != 0 + && datasize >= 1) { + bitmap_last = p[offset]; offset += 1; datasize -= 1; } - if (datasize >= 2) { + + if (bitmap & 1) { + // 2 byte "version made by" + if (datasize < 2) + break; + zip_entry->system + = archive_le16dec(p + offset) >> 8; + offset += 2; + datasize -= 2; + } + if (bitmap & 2) { // 2 byte "internal file attributes" + uint32_t internal_attributes; + if (datasize < 2) + break; + internal_attributes + = archive_le16dec(p + offset); + // Not used by libarchive at present. + (void)internal_attributes; /* UNUSED */ offset += 2; datasize -= 2; } - if (datasize >= 4) { + if (bitmap & 4) { // 4 byte "external file attributes" - uint32_t external_attributes + uint32_t external_attributes; + if (datasize < 4) + break; + external_attributes = archive_le32dec(p + offset); if (zip_entry->system == 3) { zip_entry->mode @@ -363,7 +393,24 @@ process_extra(const char *p, size_t extra_length, struct zip_entry* zip_entry) offset += 4; datasize -= 4; } + if (bitmap & 8) { + // 2 byte comment length + comment + uint32_t comment_length; + if (datasize < 2) + break; + comment_length + = archive_le16dec(p + offset); + offset += 2; + datasize -= 2; + + if (datasize < comment_length) + break; + // Comment is not supported by libarchive + offset += comment_length; + datasize -= comment_length; + } break; + } case 0x7855: /* Info-ZIP Unix Extra Field (type 2) "Ux". */ #ifdef DEBUG diff --git a/libarchive/archive_write_set_format_zip.c b/libarchive/archive_write_set_format_zip.c index ad4e6b058..32889e80d 100644 --- a/libarchive/archive_write_set_format_zip.c +++ b/libarchive/archive_write_set_format_zip.c @@ -645,8 +645,11 @@ archive_write_zip_header(struct archive_write *a, struct archive_entry *entry) unsigned char *external_info = e; memcpy(e, "LA\000\000", 4); // 0x414C + 2-byte length e += 4; - e[0] = 3; /* system */ + e[0] = 5; /* bitmap of included fields */ e += 1; + archive_le16enc(e, /* "Version created by" */ + 3 * 256 + version_needed); + e += 2; archive_le16enc(e, 0); /* internal file attributes */ e += 2; archive_le32enc(e, /* external file attributes */ diff --git a/libarchive/test/test_write_format_zip_compression_store.c b/libarchive/test/test_write_format_zip_compression_store.c index 1c4862064..69cedc442 100644 --- a/libarchive/test/test_write_format_zip_compression_store.c +++ b/libarchive/test/test_write_format_zip_compression_store.c @@ -209,7 +209,7 @@ DEFINE_TEST(test_write_format_zip_compression_store) assertEqualInt(i4(q + 18), sizeof(file_data1) + sizeof(file_data2)); /* Compressed size */ assertEqualInt(i4(q + 22), sizeof(file_data1) + sizeof(file_data2)); /* Uncompressed size */ assertEqualInt(i2(q + 26), strlen(file_name)); /* Pathname length */ - assertEqualInt(i2(q + 28), 39); /* Extra field length */ + assertEqualInt(i2(q + 28), 41); /* Extra field length */ assertEqualMem(q + 30, file_name, strlen(file_name)); /* Pathname */ extra_start = q = q + 30 + strlen(file_name); assertEqualInt(i2(q), 0x5455); /* 'UT' extension header */ @@ -229,10 +229,11 @@ DEFINE_TEST(test_write_format_zip_compression_store) q = q + 4 + i2(q + 2); assertEqualInt(i2(q), 0x414c); /* 'LA' experimental extension header */ - assertEqualInt(i2(q + 2), 7); /* size */ - assertEqualInt(q[4], 3); /* system */ - assertEqualInt(i2(q + 5), 0); /* internal file attributes */ - assertEqualInt(i4(q + 7) >> 16 & 01777, file_perm); /* external file attributes */ + assertEqualInt(i2(q + 2), 9); /* size */ + assertEqualInt(q[4], 7); /* Bitmap of fields included. */ + assertEqualInt(i2(q + 5) >> 8, 3); /* system & version made by */ + assertEqualInt(i2(q + 7), 0); /* internal file attributes */ + assertEqualInt(i4(q + 9) >> 16 & 01777, file_perm); /* external file attributes */ q = q + 4 + i2(q + 2); assert(q == extra_start + i2(local_header + 28)); @@ -298,7 +299,7 @@ DEFINE_TEST(test_write_format_zip_compression_store) assertEqualInt(i4(q + 18), 0); /* Compressed size */ assertEqualInt(i4(q + 22), 0); /* Uncompressed size */ assertEqualInt(i2(q + 26), strlen(folder_name)); /* Pathname length */ - assertEqualInt(i2(q + 28), 39); /* Extra field length */ + assertEqualInt(i2(q + 28), 41); /* Extra field length */ assertEqualMem(q + 30, folder_name, strlen(folder_name)); /* Pathname */ extra_start = q = q + 30 + strlen(folder_name); assertEqualInt(i2(q), 0x5455); /* 'UT' extension header */ @@ -317,10 +318,11 @@ DEFINE_TEST(test_write_format_zip_compression_store) q = q + 4 + i2(q + 2); assertEqualInt(i2(q), 0x414c); /* 'LA' experimental extension header */ - assertEqualInt(i2(q + 2), 7); /* size */ - assertEqualInt(q[4], 3); /* system */ - assertEqualInt(i2(q + 5), 0); /* internal file attributes */ - assertEqualInt(i4(q + 7) >> 16 & 01777, folder_perm); /* external file attributes */ + assertEqualInt(i2(q + 2), 9); /* size */ + assertEqualInt(q[4], 7); /* bitmap of fields */ + assertEqualInt(i2(q + 5) >> 8, 3); /* system & version made by */ + assertEqualInt(i2(q + 7), 0); /* internal file attributes */ + assertEqualInt(i4(q + 9) >> 16 & 01777, folder_perm); /* external file attributes */ q = q + 4 + i2(q + 2); assert(q == extra_start + i2(local_header + 28)); diff --git a/libarchive/test/test_write_format_zip_file.c b/libarchive/test/test_write_format_zip_file.c index 0216fef34..88a733fb5 100644 --- a/libarchive/test/test_write_format_zip_file.c +++ b/libarchive/test/test_write_format_zip_file.c @@ -196,7 +196,7 @@ DEFINE_TEST(test_write_format_zip_file) /* assertEqualInt(i4(p + 18), sizeof(file_data)); */ /* Compressed size */ /* assertEqualInt(i4(p + 22), sizeof(file_data)); */ /* Uncompressed size not stored because we're using length-at-end. */ assertEqualInt(i2(p + 26), strlen(file_name)); /* Pathname length */ - assertEqualInt(i2(p + 28), 35); /* Extra field length */ + assertEqualInt(i2(p + 28), 37); /* Extra field length */ assertEqualMem(p + 30, file_name, strlen(file_name)); /* Pathname */ p = extension_start = local_header + 30 + strlen(file_name); extension_end = extension_start + i2(local_header + 28); @@ -216,11 +216,12 @@ DEFINE_TEST(test_write_format_zip_file) assertEqualInt(i4(p + 11), file_gid); /* 'Ux' GID */ p += 4 + i2(p + 2); - assertEqualInt(i2(p), 0x414c); /* 'LA' experimental extension header */ - assertEqualInt(i2(p + 2), 7); /* 'at' size */ - assertEqualInt(p[4], 3); /* system */ - assertEqualInt(i2(p + 5), 0); /* internal file attributes */ - assertEqualInt(i4(p + 7) >> 16 & 01777, file_perm); /* external file attributes */ + assertEqualInt(i2(p), 0x414c); /* 'LA' experimental extension block */ + assertEqualInt(i2(p + 2), 9); /* size */ + assertEqualInt(p[4], 7); /* bitmap of fields in this block */ + assertEqualInt(i2(p + 5) >> 8, 3); /* System & version made by */ + assertEqualInt(i2(p + 7), 0); /* internal file attributes */ + assertEqualInt(i4(p + 9) >> 16 & 01777, file_perm); /* external file attributes */ p += 4 + i2(p + 2); /* Just in case: Report any extra extensions. */ diff --git a/libarchive/test/test_write_format_zip_file_zip64.c b/libarchive/test/test_write_format_zip_file_zip64.c index 3dc512ade..60770653d 100644 --- a/libarchive/test/test_write_format_zip_file_zip64.c +++ b/libarchive/test/test_write_format_zip_file_zip64.c @@ -223,7 +223,7 @@ DEFINE_TEST(test_write_format_zip_file_zip64) /* assertEqualInt(i4(p + 18), sizeof(file_data)); */ /* Compressed size */ /* assertEqualInt(i4(p + 22), sizeof(file_data)); */ /* Uncompressed size not stored because we're using length-at-end. */ assertEqualInt(i2(p + 26), strlen(file_name)); /* Pathname length */ - assertEqualInt(i2(p + 28), 55); /* Extra field length */ + assertEqualInt(i2(p + 28), 57); /* Extra field length */ assertEqualMem(p + 30, file_name, strlen(file_name)); /* Pathname */ p = extension_start = local_header + 30 + strlen(file_name); extension_end = extension_start + i2(local_header + 28); @@ -250,10 +250,11 @@ DEFINE_TEST(test_write_format_zip_file_zip64) p += 4 + i2(p + 2); assertEqualInt(i2(p), 0x414c); /* 'LA' experimental extension header */ - assertEqualInt(i2(p + 2), 7); /* 'at' size */ - assertEqualInt(p[4], 3); /* system */ - assertEqualInt(i2(p + 5), 0); /* internal file attributes */ - assertEqualInt(i4(p + 7) >> 16 & 01777, file_perm); /* external file attributes */ + assertEqualInt(i2(p + 2), 9); /* size */ + assertEqualInt(p[4], 7); /* bitmap of included fields */ + assertEqualInt(i2(p + 5) >> 8, 3); /* system & version made by */ + assertEqualInt(i2(p + 7), 0); /* internal file attributes */ + assertEqualInt(i4(p + 9) >> 16 & 01777, file_perm); /* external file attributes */ p += 4 + i2(p + 2); /* Just in case: Report any extra extensions. */ -- 2.47.2