Merge "Avoid using data descriptors in ZIP files when possible." am: 69055b5a37
am: a589dd1e0a
Change-Id: I4831b3d78e9eb7424baf3164ebec3b64f5480599
This commit is contained in:
commit
353d0293c3
4 changed files with 39 additions and 2 deletions
|
|
@ -76,6 +76,10 @@ cc_defaults {
|
||||||
"liblog",
|
"liblog",
|
||||||
],
|
],
|
||||||
|
|
||||||
|
// for FRIEND_TEST
|
||||||
|
static_libs: ["libgtest_prod"],
|
||||||
|
export_static_lib_headers: ["libgtest_prod"],
|
||||||
|
|
||||||
export_include_dirs: ["include"],
|
export_include_dirs: ["include"],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <ctime>
|
#include <ctime>
|
||||||
|
|
||||||
|
#include <gtest/gtest_prod.h>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
|
|
@ -165,6 +166,7 @@ class ZipWriter {
|
||||||
int32_t StoreBytes(FileEntry* file, const void* data, uint32_t len);
|
int32_t StoreBytes(FileEntry* file, const void* data, uint32_t len);
|
||||||
int32_t CompressBytes(FileEntry* file, const void* data, uint32_t len);
|
int32_t CompressBytes(FileEntry* file, const void* data, uint32_t len);
|
||||||
int32_t FlushCompressedBytes(FileEntry* file);
|
int32_t FlushCompressedBytes(FileEntry* file);
|
||||||
|
bool ShouldUseDataDescriptor() const;
|
||||||
|
|
||||||
enum class State {
|
enum class State {
|
||||||
kWritingZip,
|
kWritingZip,
|
||||||
|
|
@ -182,4 +184,6 @@ class ZipWriter {
|
||||||
|
|
||||||
std::unique_ptr<z_stream, void (*)(z_stream*)> z_stream_;
|
std::unique_ptr<z_stream, void (*)(z_stream*)> z_stream_;
|
||||||
std::vector<uint8_t> buffer_;
|
std::vector<uint8_t> buffer_;
|
||||||
|
|
||||||
|
FRIEND_TEST(zipwriter, WriteToUnseekableFile);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -455,6 +455,11 @@ int32_t ZipWriter::FlushCompressedBytes(FileEntry* file) {
|
||||||
return kNoError;
|
return kNoError;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ZipWriter::ShouldUseDataDescriptor() const {
|
||||||
|
// Only use a trailing "data descriptor" if the output isn't seekable.
|
||||||
|
return !seekable_;
|
||||||
|
}
|
||||||
|
|
||||||
int32_t ZipWriter::FinishEntry() {
|
int32_t ZipWriter::FinishEntry() {
|
||||||
if (state_ != State::kWritingEntry) {
|
if (state_ != State::kWritingEntry) {
|
||||||
return kInvalidState;
|
return kInvalidState;
|
||||||
|
|
@ -467,7 +472,7 @@ int32_t ZipWriter::FinishEntry() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((current_file_entry_.compression_method & kCompressDeflated) || !seekable_) {
|
if (ShouldUseDataDescriptor()) {
|
||||||
// Some versions of ZIP don't allow STORED data to have a trailing DataDescriptor.
|
// Some versions of ZIP don't allow STORED data to have a trailing DataDescriptor.
|
||||||
// If this file is not seekable, or if the data is compressed, write a DataDescriptor.
|
// If this file is not seekable, or if the data is compressed, write a DataDescriptor.
|
||||||
const uint32_t sig = DataDescriptor::kOptSignature;
|
const uint32_t sig = DataDescriptor::kOptSignature;
|
||||||
|
|
@ -515,7 +520,7 @@ int32_t ZipWriter::Finish() {
|
||||||
for (FileEntry& file : files_) {
|
for (FileEntry& file : files_) {
|
||||||
CentralDirectoryRecord cdr = {};
|
CentralDirectoryRecord cdr = {};
|
||||||
cdr.record_signature = CentralDirectoryRecord::kSignature;
|
cdr.record_signature = CentralDirectoryRecord::kSignature;
|
||||||
if ((file.compression_method & kCompressDeflated) || !seekable_) {
|
if (ShouldUseDataDescriptor()) {
|
||||||
cdr.gpb_flags |= kGPBDDFlagMask;
|
cdr.gpb_flags |= kGPBDDFlagMask;
|
||||||
}
|
}
|
||||||
cdr.compression_method = file.compression_method;
|
cdr.compression_method = file.compression_method;
|
||||||
|
|
|
||||||
|
|
@ -243,6 +243,7 @@ TEST_F(zipwriter, WriteCompressedZipWithOneFile) {
|
||||||
ZipEntry data;
|
ZipEntry data;
|
||||||
ASSERT_EQ(0, FindEntry(handle, "file.txt", &data));
|
ASSERT_EQ(0, FindEntry(handle, "file.txt", &data));
|
||||||
EXPECT_EQ(kCompressDeflated, data.method);
|
EXPECT_EQ(kCompressDeflated, data.method);
|
||||||
|
EXPECT_EQ(0u, data.has_data_descriptor);
|
||||||
ASSERT_EQ(4u, data.uncompressed_length);
|
ASSERT_EQ(4u, data.uncompressed_length);
|
||||||
ASSERT_TRUE(AssertFileEntryContentsEq("helo", handle, &data));
|
ASSERT_TRUE(AssertFileEntryContentsEq("helo", handle, &data));
|
||||||
|
|
||||||
|
|
@ -351,6 +352,29 @@ TEST_F(zipwriter, BackupRemovesTheLastFile) {
|
||||||
CloseArchive(handle);
|
CloseArchive(handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(zipwriter, WriteToUnseekableFile) {
|
||||||
|
const char* expected = "hello";
|
||||||
|
ZipWriter writer(file_);
|
||||||
|
writer.seekable_ = false;
|
||||||
|
|
||||||
|
ASSERT_EQ(0, writer.StartEntry("file.txt", 0));
|
||||||
|
ASSERT_EQ(0, writer.WriteBytes(expected, strlen(expected)));
|
||||||
|
ASSERT_EQ(0, writer.FinishEntry());
|
||||||
|
ASSERT_EQ(0, writer.Finish());
|
||||||
|
ASSERT_GE(0, lseek(fd_, 0, SEEK_SET));
|
||||||
|
|
||||||
|
ZipArchiveHandle handle;
|
||||||
|
ASSERT_EQ(0, OpenArchiveFd(fd_, "temp", &handle, false));
|
||||||
|
ZipEntry data;
|
||||||
|
ASSERT_EQ(0, FindEntry(handle, "file.txt", &data));
|
||||||
|
EXPECT_EQ(kCompressStored, data.method);
|
||||||
|
EXPECT_EQ(1u, data.has_data_descriptor);
|
||||||
|
EXPECT_EQ(strlen(expected), data.compressed_length);
|
||||||
|
ASSERT_EQ(strlen(expected), data.uncompressed_length);
|
||||||
|
ASSERT_TRUE(AssertFileEntryContentsEq(expected, handle, &data));
|
||||||
|
CloseArchive(handle);
|
||||||
|
}
|
||||||
|
|
||||||
TEST_F(zipwriter, TruncateFileAfterBackup) {
|
TEST_F(zipwriter, TruncateFileAfterBackup) {
|
||||||
ZipWriter writer(file_);
|
ZipWriter writer(file_);
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue