From ee015d6df41eb1184aefe5cb3deeca6ca7053a97 Mon Sep 17 00:00:00 2001 From: Sasha Smundak Date: Mon, 29 Aug 2016 17:31:43 +0000 Subject: Remove entries' Unix timestamp extra fields when --normalize is present. RELNOTES: -- MOS_MIGRATED_REVID=131607358 --- src/tools/singlejar/output_jar.cc | 61 +++++++++++++++++++++++---- src/tools/singlejar/output_jar_simple_test.cc | 5 +++ src/tools/singlejar/zip_headers.h | 2 +- 3 files changed, 59 insertions(+), 9 deletions(-) (limited to 'src/tools') diff --git a/src/tools/singlejar/output_jar.cc b/src/tools/singlejar/output_jar.cc index 29a18efeac..cf36db0698 100644 --- a/src/tools/singlejar/output_jar.cc +++ b/src/tools/singlejar/output_jar.cc @@ -387,17 +387,40 @@ bool OutputJar::AddJar(int jar_path_index) { jar_entry->last_mod_file_time() != normalized_time; } if (fix_timestamp) { - LH lh_new; - memcpy(&lh_new, lh, sizeof(lh_new)); - lh_new.last_mod_file_date(33); - lh_new.last_mod_file_time(normalized_time); + uint8_t lh_buffer[512]; + size_t lh_size = lh->size(); + LH *lh_new = lh_size > sizeof(lh_buffer) + ? reinterpret_cast(malloc(lh_size)) + : reinterpret_cast(lh_buffer); + // Remove Unix timestamp field. + auto field_to_remove = lh->unix_time_extra_field(); + if (field_to_remove != nullptr) { + auto from_end = byte_ptr(lh) + lh->size(); + size_t removed_size = field_to_remove->size(); + size_t chunk1_size = byte_ptr(field_to_remove) - byte_ptr(lh); + size_t chunk2_size = lh->size() - (chunk1_size + removed_size); + memcpy(lh_new, lh, chunk1_size); + if (chunk2_size) { + memcpy(reinterpret_cast(lh_new) + chunk1_size, + from_end - chunk2_size, chunk2_size); + } + lh_new->extra_fields(lh_new->extra_fields(), + lh->extra_fields_length() - removed_size); + } else { + memcpy(lh_new, lh, lh_size); + } + lh_new->last_mod_file_date(33); + lh_new->last_mod_file_time(normalized_time); // Now write these few bytes and adjust read/write positions accordingly. - if (!WriteBytes(reinterpret_cast(&lh_new), sizeof(lh_new))) { + if (!WriteBytes(reinterpret_cast(lh_new), lh_new->size())) { diag_err(1, "%s:%d: Cannot copy modified local header for %.*s", __FILE__, __LINE__, file_name_length, file_name); } - copy_from += sizeof(lh_new); - num_bytes -= sizeof(lh_new); + copy_from += lh_size; + num_bytes -= lh_size; + if (reinterpret_cast(lh_new) != lh_buffer) { + free(lh_buffer); + } } // Do the actual copy. Use sendfile, avoiding copying the data to user @@ -415,7 +438,29 @@ bool OutputJar::AddJar(int jar_path_index) { // Append central directory header for this file to the output central // directory we are building. TODO(output_position < 0xFFFFFFFF, "Handle Zip64"); - CDH *out_cdh = AppendToDirectoryBuffer(jar_entry); + + CDH *out_cdh; + auto field_to_remove = + fix_timestamp ? jar_entry->unix_time_extra_field() : nullptr; + if (field_to_remove != nullptr) { + // Remove extra fields. + auto from_start = byte_ptr(jar_entry); + auto from_end = from_start + jar_entry->size(); + size_t removed_size = field_to_remove->size(); + size_t chunk1_size = byte_ptr(field_to_remove) - from_start; + size_t chunk2_size = jar_entry->size() - (chunk1_size + removed_size); + out_cdh = + reinterpret_cast(ReserveCdr(jar_entry->size() - removed_size)); + memcpy(out_cdh, jar_entry, chunk1_size); + if (chunk2_size) { + memcpy(reinterpret_cast(out_cdh) + chunk1_size, + from_end - chunk2_size, chunk2_size); + } + out_cdh->extra_fields(out_cdh->extra_fields(), + jar_entry->extra_fields_length() - removed_size); + } else { + out_cdh = AppendToDirectoryBuffer(jar_entry); + } out_cdh->local_header_offset32(output_position); if (fix_timestamp) { out_cdh->last_mod_file_time(normalized_time); diff --git a/src/tools/singlejar/output_jar_simple_test.cc b/src/tools/singlejar/output_jar_simple_test.cc index 2dd933ae7f..a3808b3437 100644 --- a/src/tools/singlejar/output_jar_simple_test.cc +++ b/src/tools/singlejar/output_jar_simple_test.cc @@ -424,6 +424,11 @@ TEST_F(OutputJarSimpleTest, Normalize) { << entry_name << " modification time for non .class entry should be 00:00:00"; } + // Zip creates Unix timestamps, too. Check that normalization removes them. + ASSERT_EQ(nullptr, cdh->unix_time_extra_field()) + << entry_name << ": CDH should not have Unix Time extra field"; + ASSERT_EQ(nullptr, lh->unix_time_extra_field()) + << entry_name << ": LH should not have Unix Time extra field"; } input_jar.Close(); } diff --git a/src/tools/singlejar/zip_headers.h b/src/tools/singlejar/zip_headers.h index 91dd59af09..7698d9c414 100644 --- a/src/tools/singlejar/zip_headers.h +++ b/src/tools/singlejar/zip_headers.h @@ -374,7 +374,7 @@ class CDH { } void extra_fields(const uint8_t *data, uint16_t data_length) { extra_fields_length_ = htole16(data_length); - if (data_length) { + if (data_length && data != extra_fields()) { memcpy(extra_fields(), data, data_length); } } -- cgit v1.2.3