Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(552)

Unified Diff: third_party/ijar/zip.cc

Issue 1901473003: 🐞 Update version of third_party/ijar (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 4 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « third_party/ijar/zip.h ('k') | third_party/ijar/zip_main.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: third_party/ijar/zip.cc
diff --git a/third_party/ijar/zip.cc b/third_party/ijar/zip.cc
index cb9d1cc9d776e6b311e983fdbaec579faaf7730e..44372f443bb5ae619585c5b8d565dfd21c28afc3 100644
--- a/third_party/ijar/zip.cc
+++ b/third_party/ijar/zip.cc
@@ -1,6 +1,4 @@
-// Copyright 2007 Alan Donovan. All rights reserved.
-//
-// Author: Alan Donovan <adonovan@google.com>
+// Copyright 2015 The Bazel Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -38,13 +36,24 @@
#include <limits>
#include <vector>
+#include "third_party/ijar/mapped_file.h"
#include "third_party/ijar/zip.h"
#include <zlib.h>
-#define LOCAL_FILE_HEADER_SIGNATURE 0x04034b50
-#define CENTRAL_FILE_HEADER_SIGNATURE 0x02014b50
-#define END_OF_CENTRAL_DIR_SIGNATURE 0x06054b50
-#define DATA_DESCRIPTOR_SIGNATURE 0x08074b50
+#define LOCAL_FILE_HEADER_SIGNATURE 0x04034b50
+#define CENTRAL_FILE_HEADER_SIGNATURE 0x02014b50
+#define DIGITAL_SIGNATURE 0x05054b50
+#define ZIP64_EOCD_SIGNATURE 0x06064b50
+#define ZIP64_EOCD_LOCATOR_SIGNATURE 0x07064b50
+#define EOCD_SIGNATURE 0x06054b50
+#define DATA_DESCRIPTOR_SIGNATURE 0x08074b50
+
+#define U2_MAX 0xffff
+#define U4_MAX 0xffffffffUL
+
+#define ZIP64_EOCD_LOCATOR_SIZE 20
+// zip64 eocd is fixed size in the absence of a zip64 extensible data sector
+#define ZIP64_EOCD_FIXED_SIZE 56
// version to extract: 1.0 - default value from APPNOTE.TXT.
// Output JAR files contain no extra ZIP features, so this is enough.
@@ -65,22 +74,13 @@ namespace devtools_ijar {
// http://www.info-zip.org/FAQ.html#limits
static const u8 kMaximumOutputSize = std::numeric_limits<uint32_t>::max();
-static bool ProcessCentralDirEntry(const u1 *&p,
- size_t *compressed_size,
- size_t *uncompressed_size,
- char *filename,
- size_t filename_size,
- u4 *attr,
- u4 *offset);
-
//
// A class representing a ZipFile for reading. Its public API is exposed
// using the ZipExtractor abstract class.
//
class InputZipFile : public ZipExtractor {
public:
- InputZipFile(ZipExtractorProcessor *processor, int fd, off_t in_length,
- off_t in_offset, const u1* zipdata_in, const u1* central_dir);
+ InputZipFile(ZipExtractorProcessor *processor, const char* filename);
virtual ~InputZipFile();
virtual const char* GetError() {
@@ -90,27 +90,32 @@ class InputZipFile : public ZipExtractor {
return errmsg;
}
+ bool Open();
virtual bool ProcessNext();
virtual void Reset();
virtual size_t GetSize() {
- return in_length_;
+ return input_file_->Length();
}
virtual u8 CalculateOutputLength();
+ virtual bool ProcessCentralDirEntry(const u1 *&p, size_t *compressed_size,
+ size_t *uncompressed_size, char *filename,
+ size_t filename_size, u4 *attr,
+ u4 *offset);
+
private:
ZipExtractorProcessor *processor;
-
- int fd_in; // Input file descripor
+ const char* filename_;
+ MappedInputFile *input_file_;
// InputZipFile is responsible for maintaining the following
// pointers. They are allocated by the Create() method before
// the object is actually created using mmap.
- const u1 * const zipdata_in_; // start of input file mmap
- const u1 * zipdata_in_mapped_; // start of still mapped region
- const u1 * const central_dir_; // central directory in input file
+ const u1 * zipdata_in_; // start of input file mmap
+ size_t bytes_unmapped_; // bytes that have already been unmapped
+ const u1 * central_dir_; // central directory in input file
- size_t in_length_; // size of the input file
size_t in_offset_; // offset the input file
const u1 *p; // input cursor
@@ -122,10 +127,10 @@ class InputZipFile : public ZipExtractor {
// not enough, we bail out. We only decompress class files, so they should
// be smaller than 64K anyway, but we give a little leeway.
// MAX_BUFFER_SIZE must be bigger than the size of the biggest file in the
- // ZIP. It is set to 128M here so we can uncompress the Bazel server with
- // this library.
+ // ZIP. It is set to 2GB here because no one has audited the code for 64-bit
+ // cleanliness.
static const size_t INITIAL_BUFFER_SIZE = 256 * 1024; // 256K
- static const size_t MAX_BUFFER_SIZE = 128 * 1024 * 1024;
+ static const size_t MAX_BUFFER_SIZE = std::numeric_limits<int32_t>::max();
static const size_t MAX_MAPPED_REGION = 32 * 1024 * 1024;
// These metadata fields are the fields of the ZIP header of the file being
@@ -168,7 +173,7 @@ class InputZipFile : public ZipExtractor {
// we're about to read, for diagnostics.
int EnsureRemaining(size_t n, const char *state) {
size_t in_offset = p - zipdata_in_;
- size_t remaining = in_length_ - in_offset;
+ size_t remaining = input_file_->Length() - in_offset;
if (n > remaining) {
return error("Premature end of file (at offset %zd, state=%s); "
"expected %zd more bytes but found %zd.\n",
@@ -197,10 +202,11 @@ class InputZipFile : public ZipExtractor {
//
class OutputZipFile : public ZipBuilder {
public:
- OutputZipFile(int fd, u1 * const zipdata_out) :
- fd_out(fd),
- zipdata_out_(zipdata_out),
- q(zipdata_out) {
+ OutputZipFile(const char* filename, u8 estimated_size) :
+ output_file_(NULL),
+ filename_(filename),
+ estimated_size_(estimated_size),
+ finished_(false) {
errmsg[0] = 0;
}
@@ -213,7 +219,8 @@ class OutputZipFile : public ZipBuilder {
virtual ~OutputZipFile() { Finish(); }
virtual u1* NewFile(const char* filename, const u4 attr);
- virtual int FinishFile(size_t filelength, bool compress = false);
+ virtual int FinishFile(size_t filelength, bool compress = false,
+ bool compute_crc = false);
virtual int WriteEmptyFile(const char *filename);
virtual size_t GetSize() {
return Offset(q);
@@ -222,6 +229,7 @@ class OutputZipFile : public ZipBuilder {
return entries_.size();
}
virtual int Finish();
+ bool Open();
private:
struct LocalFileEntry {
@@ -235,6 +243,9 @@ class OutputZipFile : public ZipBuilder {
// Compression method
u2 compression_method;
+ // CRC32
+ u4 crc32;
+
// external attributes field
u4 external_attr;
@@ -247,12 +258,15 @@ class OutputZipFile : public ZipBuilder {
u2 extra_field_length;
};
- int fd_out; // file descriptor for the output file
+ MappedOutputFile* output_file_;
+ const char* filename_;
+ u8 estimated_size_;
+ bool finished_;
// OutputZipFile is responsible for maintaining the following
// pointers. They are allocated by the Create() method before
// the object is actually created using mmap.
- u1 * const zipdata_out_; // start of output file mmap
+ u1 *zipdata_out_; // start of output file mmap
u1 *q; // output cursor
u1 *header_ptr; // Current pointer to "compression method" entry.
@@ -289,8 +303,10 @@ class OutputZipFile : public ZipBuilder {
// Fill in the "compressed size" and "uncompressed size" fields in a local
// file header previously written by WriteLocalFileHeader().
- size_t WriteFileSizeInLocalFileHeader(u1 *header_ptr, size_t out_length,
- bool compress = false);
+ size_t WriteFileSizeInLocalFileHeader(u1 *header_ptr,
+ size_t out_length,
+ bool compress = false,
+ const u4 crc = 0);
};
//
@@ -413,9 +429,10 @@ int InputZipFile::ProcessLocalFileEntry(
}
}
- if (p > zipdata_in_mapped_ + MAX_MAPPED_REGION) {
- munmap(const_cast<u1 *>(zipdata_in_mapped_), MAX_MAPPED_REGION);
- zipdata_in_mapped_ += MAX_MAPPED_REGION;
+ size_t bytes_processed = p - zipdata_in_;
+ if (bytes_processed > bytes_unmapped_ + MAX_MAPPED_REGION) {
+ input_file_->Discard(MAX_MAPPED_REGION);
+ bytes_unmapped_ += MAX_MAPPED_REGION;
}
return 0;
@@ -440,7 +457,7 @@ int InputZipFile::SkipFile(const bool compressed) {
u1* InputZipFile::UncompressFile() {
size_t in_offset = p - zipdata_in_;
- size_t remaining = in_length_ - in_offset;
+ size_t remaining = input_file_->Length() - in_offset;
z_stream stream;
stream.zalloc = Z_NULL;
@@ -547,11 +564,17 @@ int InputZipFile::ProcessFile(const bool compressed) {
// Of course, in the latter case, the size output variables are not changed.
// Note that the central directory is always followed by another data structure
// that has a signature, so parsing it this way is safe.
-static bool ProcessCentralDirEntry(
- const u1 *&p, size_t *compressed_size, size_t *uncompressed_size,
- char *filename, size_t filename_size, u4 *attr, u4 *offset) {
+bool InputZipFile::ProcessCentralDirEntry(const u1 *&p, size_t *compressed_size,
+ size_t *uncompressed_size,
+ char *filename, size_t filename_size,
+ u4 *attr, u4 *offset) {
u4 signature = get_u4le(p);
+
if (signature != CENTRAL_FILE_HEADER_SIGNATURE) {
+ if (signature != DIGITAL_SIGNATURE && signature != EOCD_SIGNATURE &&
+ signature != ZIP64_EOCD_SIGNATURE) {
+ error("invalid central file header signature: 0x%x\n", signature);
+ }
return false;
}
@@ -609,14 +632,132 @@ u8 InputZipFile::CalculateOutputLength() {
// The worst case is when the output is simply the input uncompressed. The
// metadata in the zip file will stay the same, so the file will grow by the
// difference between the compressed and uncompressed sizes.
- return (u8) in_length_ - skipped_compressed_size
+ return (u8) input_file_->Length() - skipped_compressed_size
+ (uncompressed_size - compressed_size);
}
+// An end of central directory record, sized for optional zip64 contents.
+struct EndOfCentralDirectoryRecord {
+ u4 number_of_this_disk;
+ u4 disk_with_central_dir;
+ u8 central_dir_entries_on_this_disk;
+ u8 central_dir_entries;
+ u8 central_dir_size;
+ u8 central_dir_offset;
+};
+
+// Checks for a zip64 end of central directory record. If a valid zip64 EOCD is
+// found, updates the original EOCD record and returns true.
+bool MaybeReadZip64CentralDirectory(const u1 *bytes, size_t in_length,
+ const u1 *current,
+ const u1 **end_of_central_dir,
+ EndOfCentralDirectoryRecord *cd) {
+ if (current < bytes) {
+ return false;
+ }
+ const u1 *candidate = current;
+ u4 zip64_directory_signature = get_u4le(current);
+ if (zip64_directory_signature != ZIP64_EOCD_SIGNATURE) {
+ return false;
+ }
+
+ // size of zip64 end of central directory record
+ // (fixed size unless there's a zip64 extensible data sector, which
+ // we don't need to read)
+ get_u8le(current);
+ get_u2be(current); // version made by
+ get_u2be(current); // version needed to extract
+
+ u4 number_of_this_disk = get_u4be(current);
+ u4 disk_with_central_dir = get_u4le(current);
+ u8 central_dir_entries_on_this_disk = get_u8le(current);
+ u8 central_dir_entries = get_u8le(current);
+ u8 central_dir_size = get_u8le(current);
+ u8 central_dir_offset = get_u8le(current);
+
+ // check for a zip64 EOCD that matches the regular EOCD
+ if (number_of_this_disk != cd->number_of_this_disk &&
+ cd->number_of_this_disk != U2_MAX) {
+ return false;
+ }
+ if (disk_with_central_dir != cd->disk_with_central_dir &&
+ cd->disk_with_central_dir != U2_MAX) {
+ return false;
+ }
+ if (central_dir_entries_on_this_disk !=
+ cd->central_dir_entries_on_this_disk &&
+ cd->central_dir_entries_on_this_disk != U2_MAX) {
+ return false;
+ }
+ if (central_dir_entries != cd->central_dir_entries &&
+ cd->central_dir_entries != U2_MAX) {
+ return false;
+ }
+ if (central_dir_size != cd->central_dir_size &&
+ cd->central_dir_size != U4_MAX) {
+ return false;
+ }
+ if (central_dir_offset != cd->central_dir_offset &&
+ cd->central_dir_offset != U4_MAX) {
+ return false;
+ }
+
+ *end_of_central_dir = candidate;
+ cd->number_of_this_disk = number_of_this_disk;
+ cd->disk_with_central_dir = disk_with_central_dir;
+ cd->central_dir_entries_on_this_disk = central_dir_entries_on_this_disk;
+ cd->central_dir_entries = central_dir_entries;
+ cd->central_dir_size = central_dir_size;
+ cd->central_dir_offset = central_dir_offset;
+ return true;
+}
+
+// Starting from the end of central directory record, attempts to locate a zip64
+// end of central directory record. If found, updates the given record and
+// offset with the zip64 data. Returns false on error.
+bool FindZip64CentralDirectory(const u1 *bytes, size_t in_length,
+ const u1 **end_of_central_dir,
+ EndOfCentralDirectoryRecord *cd) {
+ // In the absence of a zip64 extensible data sector, the zip64 EOCD is at a
+ // fixed offset from the regular central directory.
+ if (MaybeReadZip64CentralDirectory(
+ bytes, in_length,
+ *end_of_central_dir - ZIP64_EOCD_LOCATOR_SIZE - ZIP64_EOCD_FIXED_SIZE,
+ end_of_central_dir, cd)) {
+ return true;
+ }
+
+ // If we couldn't find a zip64 EOCD at a fixed offset, either it doesn't exist
+ // or there was a zip64 extensible data sector, so try going through the
+ // locator. This approach doesn't work if data was prepended to the archive
+ // without updating the offset in the locator.
+ const u1 *zip64_locator = *end_of_central_dir - ZIP64_EOCD_LOCATOR_SIZE;
+ if (zip64_locator - ZIP64_EOCD_FIXED_SIZE < bytes) {
+ return true;
+ }
+ u4 zip64_locator_signature = get_u4le(zip64_locator);
+ if (zip64_locator_signature != ZIP64_EOCD_LOCATOR_SIGNATURE) {
+ return true;
+ }
+ u4 disk_with_zip64_central_directory = get_u4le(zip64_locator);
+ u8 zip64_end_of_central_dir_offset = get_u8le(zip64_locator);
+ u4 zip64_total_disks = get_u4le(zip64_locator);
+ if (MaybeReadZip64CentralDirectory(bytes, in_length,
+ bytes + zip64_end_of_central_dir_offset,
+ end_of_central_dir, cd)) {
+ if (disk_with_zip64_central_directory != 0 || zip64_total_disks != 1) {
+ fprintf(stderr, "multi-disk JAR files are not supported\n");
+ return false;
+ }
+ return true;
+ }
+ return true;
+}
+
// Given the data in the zip file, returns the offset of the central directory
// and the number of files contained in it.
-bool FindZipCentralDirectory(const u1* bytes, size_t in_length,
- u4* offset, const u1** central_dir) {
+bool FindZipCentralDirectory(const u1 *bytes, size_t in_length, u4 *offset,
+ const u1 **central_dir) {
static const int MAX_COMMENT_LENGTH = 0xffff;
static const int CENTRAL_DIR_LOCATOR_SIZE = 22;
// Maximum distance of start of central dir locator from end of file
@@ -631,7 +772,7 @@ bool FindZipCentralDirectory(const u1* bytes, size_t in_length,
current >= last_pos_to_check;
current-- ) {
const u1* p = current;
- if (get_u4le(p) != END_OF_CENTRAL_DIR_SIGNATURE) {
+ if (get_u4le(p) != EOCD_SIGNATURE) {
continue;
}
@@ -655,36 +796,40 @@ bool FindZipCentralDirectory(const u1* bytes, size_t in_length,
return false;
}
+ EndOfCentralDirectoryRecord cd;
const u1* end_of_central_dir = current;
get_u4le(current); // central directory locator signature, already checked
- u2 number_of_this_disk = get_u2le(current);
- u2 disk_with_central_dir = get_u2le(current);
- u2 central_dir_entries_on_this_disk = get_u2le(current);
- u2 central_dir_entries = get_u2le(current);
- u4 central_dir_size = get_u4le(current);
- u4 central_dir_offset = get_u4le(current);
+ cd.number_of_this_disk = get_u2le(current);
+ cd.disk_with_central_dir = get_u2le(current);
+ cd.central_dir_entries_on_this_disk = get_u2le(current);
+ cd.central_dir_entries = get_u2le(current);
+ cd.central_dir_size = get_u4le(current);
+ cd.central_dir_offset = get_u4le(current);
u2 file_comment_length = get_u2le(current);
current += file_comment_length; // set current to the end of the central dir
- if (number_of_this_disk != 0
- || disk_with_central_dir != 0
- || central_dir_entries_on_this_disk != central_dir_entries) {
+ if (!FindZip64CentralDirectory(bytes, in_length, &end_of_central_dir, &cd)) {
+ return false;
+ }
+
+ if (cd.number_of_this_disk != 0 || cd.disk_with_central_dir != 0 ||
+ cd.central_dir_entries_on_this_disk != cd.central_dir_entries) {
fprintf(stderr, "multi-disk JAR files are not supported\n");
return false;
}
// Do not change output values before determining that they are OK.
- *offset = central_dir_offset;
+ *offset = cd.central_dir_offset;
// Central directory start can then be used to determine the actual
// starts of the zip file (which can be different in case of a non-zip
// header like for auto-extractable binaries).
- *central_dir = end_of_central_dir - central_dir_size;
+ *central_dir = end_of_central_dir - cd.central_dir_size;
return true;
}
void InputZipFile::Reset() {
central_dir_current_ = central_dir_;
- zipdata_in_mapped_ = zipdata_in_;
+ bytes_unmapped_ = 0;
p = zipdata_in_ + in_offset_;
}
@@ -698,55 +843,68 @@ int ZipExtractor::ProcessAll() {
ZipExtractor* ZipExtractor::Create(const char* filename,
ZipExtractorProcessor *processor) {
- int fd_in = open(filename, O_RDONLY);
- if (fd_in < 0) {
+ InputZipFile* result = new InputZipFile(processor, filename);
+ if (!result->Open()) {
+ fprintf(stderr, "%s\n", result->GetError());
+ delete result;
return NULL;
}
- off_t length = lseek(fd_in, 0, SEEK_END);
- if (length < 0) {
- return NULL;
- }
+ return result;
+}
- void *zipdata_in = mmap(NULL, length, PROT_READ, MAP_PRIVATE, fd_in, 0);
- if (zipdata_in == MAP_FAILED) {
- return NULL;
+// zipdata_in_, in_offset_, p, central_dir_current_
+
+InputZipFile::InputZipFile(ZipExtractorProcessor *processor,
+ const char* filename)
+ : processor(processor), filename_(filename), input_file_(NULL),
+ bytes_unmapped_(0) {
+ uncompressed_data_allocated_ = INITIAL_BUFFER_SIZE;
+ uncompressed_data_ =
+ reinterpret_cast<u1*>(malloc(uncompressed_data_allocated_));
+ errmsg[0] = 0;
+}
+
+bool InputZipFile::Open() {
+ MappedInputFile* input_file = new MappedInputFile(filename_);
+ if (!input_file->Opened()) {
+ snprintf(errmsg, sizeof(errmsg), "%s", input_file->Error());
+ delete input_file;
+ return false;
}
+ void *zipdata_in = input_file->Buffer();
u4 central_dir_offset;
const u1 *central_dir = NULL;
if (!devtools_ijar::FindZipCentralDirectory(
- static_cast<const u1*>(zipdata_in), length,
+ static_cast<const u1*>(zipdata_in), input_file->Length(),
&central_dir_offset, &central_dir)) {
errno = EIO; // we don't really have a good error number
- return NULL;
+ error("Cannot find central directory");
+ delete input_file;
+ return false;
}
const u1 *zipdata_start = static_cast<const u1*>(zipdata_in);
- off_t offset = - static_cast<off_t>(zipdata_start
- + central_dir_offset
- - central_dir);
-
- return new InputZipFile(processor, fd_in, length, offset,
- zipdata_start, central_dir);
-}
-
-InputZipFile::InputZipFile(ZipExtractorProcessor *processor, int fd,
- off_t in_length, off_t in_offset,
- const u1* zipdata_in, const u1* central_dir)
- : processor(processor), fd_in(fd),
- zipdata_in_(zipdata_in), zipdata_in_mapped_(zipdata_in),
- central_dir_(central_dir), in_length_(in_length), in_offset_(in_offset),
- p(zipdata_in + in_offset), central_dir_current_(central_dir) {
- uncompressed_data_allocated_ = INITIAL_BUFFER_SIZE;
- uncompressed_data_ =
- reinterpret_cast<u1*>(malloc(uncompressed_data_allocated_));
+ in_offset_ = - static_cast<off_t>(zipdata_start
+ + central_dir_offset
+ - central_dir);
+
+ input_file_ = input_file;
+ zipdata_in_ = zipdata_start;
+ central_dir_ = central_dir;
+ central_dir_current_ = central_dir;
+ p = zipdata_in_ + in_offset_;
errmsg[0] = 0;
+ return true;
}
InputZipFile::~InputZipFile() {
free(uncompressed_data_);
- close(fd_in);
+ if (input_file_ != NULL) {
+ input_file_->Close();
+ delete input_file_;
+ }
}
@@ -760,6 +918,7 @@ int OutputZipFile::WriteEmptyFile(const char *filename) {
LocalFileEntry *entry = new LocalFileEntry;
entry->local_header_offset = Offset(q);
entry->external_attr = 0;
+ entry->crc32 = 0;
// Output the ZIP local_file_header:
put_u4le(q, LOCAL_FILE_HEADER_SIGNATURE);
@@ -768,7 +927,7 @@ int OutputZipFile::WriteEmptyFile(const char *filename) {
put_u2le(q, 0); // compression_method
put_u2le(q, 0); // last_mod_file_time
put_u2le(q, 0); // last_mod_file_date
- put_u4le(q, 0); // crc32
+ put_u4le(q, entry->crc32); // crc32
put_u4le(q, 0); // compressed_size
put_u4le(q, 0); // uncompressed_size
put_u2le(q, file_name_length);
@@ -800,7 +959,7 @@ void OutputZipFile::WriteCentralDirectory() {
put_u2le(q, entry->compression_method); // compression method:
put_u2le(q, 0); // last_mod_file_time
put_u2le(q, 0); // last_mod_file_date
- put_u4le(q, 0); // crc32 (jar/javac tools don't care)
+ put_u4le(q, entry->crc32); // crc32
put_u4le(q, entry->compressed_length); // compressed_size
put_u4le(q, entry->uncompressed_length); // uncompressed_size
put_u2le(q, entry->file_name_length);
@@ -816,17 +975,60 @@ void OutputZipFile::WriteCentralDirectory() {
put_n(q, entry->file_name, entry->file_name_length);
put_n(q, entry->extra_field, entry->extra_field_length);
}
- u4 central_directory_size = q - central_directory_start;
-
- put_u4le(q, END_OF_CENTRAL_DIR_SIGNATURE);
- put_u2le(q, 0); // number of this disk
- put_u2le(q, 0); // number of the disk with the start of the central directory
- put_u2le(q, entries_.size()); // # central dir entries on this disk
- put_u2le(q, entries_.size()); // total # entries in the central directory
- put_u4le(q, central_directory_size); // size of the central directory
- put_u4le(q, Offset(central_directory_start)); // offset of start of central
- // directory wrt starting disk
- put_u2le(q, 0); // .ZIP file comment length
+ u8 central_directory_size = q - central_directory_start;
+
+ if (entries_.size() > U2_MAX || central_directory_size > U4_MAX ||
+ Offset(central_directory_start) > U4_MAX) {
+ u1 *zip64_end_of_central_directory_start = q;
+
+ put_u4le(q, ZIP64_EOCD_SIGNATURE);
+ // signature and size field doesn't count towards size
+ put_u8le(q, ZIP64_EOCD_FIXED_SIZE - 12);
+ put_u2le(q, 0); // version made by
+ put_u2le(q, 0); // version needed to extract
+ put_u4le(q, 0); // number of this disk
+ put_u4le(q, 0); // # of the disk with the start of the central directory
+ put_u8le(q, entries_.size()); // # central dir entries on this disk
+ put_u8le(q, entries_.size()); // total # entries in the central directory
+ put_u8le(q, central_directory_size); // size of the central directory
+ // offset of start of central directory wrt starting disk
+ put_u8le(q, Offset(central_directory_start));
+
+ put_u4le(q, ZIP64_EOCD_LOCATOR_SIGNATURE);
+ // number of the disk with the start of the zip64 end of central directory
+ put_u4le(q, 0);
+ // relative offset of the zip64 end of central directory record
+ put_u8le(q, Offset(zip64_end_of_central_directory_start));
+ // total number of disks
+ put_u4le(q, 1);
+
+ put_u4le(q, EOCD_SIGNATURE);
+ put_u2le(q, 0); // number of this disk
+ put_u2le(q, 0); // # of disk with the start of the central directory
+ // # central dir entries on this disk
+ put_u2le(q, entries_.size() > 0xffff ? 0xffff : entries_.size());
+ // total # entries in the central directory
+ put_u2le(q, entries_.size() > 0xffff ? 0xffff : entries_.size());
+ // size of the central directory
+ put_u4le(q,
+ central_directory_size > U4_MAX ? U4_MAX : central_directory_size);
+ // offset of start of central
+ put_u4le(q, Offset(central_directory_start) > U4_MAX
+ ? U4_MAX
+ : Offset(central_directory_start));
+ put_u2le(q, 0); // .ZIP file comment length
+
+ } else {
+ put_u4le(q, EOCD_SIGNATURE);
+ put_u2le(q, 0); // number of this disk
+ put_u2le(q, 0); // # of the disk with the start of the central directory
+ put_u2le(q, entries_.size()); // # central dir entries on this disk
+ put_u2le(q, entries_.size()); // total # entries in the central directory
+ put_u4le(q, central_directory_size); // size of the central directory
+ // offset of start of central directory wrt starting disk
+ put_u4le(q, Offset(central_directory_start));
+ put_u2le(q, 0); // .ZIP file comment length
+ }
}
u1* OutputZipFile::WriteLocalFileHeader(const char* filename, const u4 attr) {
@@ -848,7 +1050,7 @@ u1* OutputZipFile::WriteLocalFileHeader(const char* filename, const u4 attr) {
put_u2le(q, COMPRESSION_METHOD_STORED); // compression method = placeholder
put_u2le(q, 0); // last_mod_file_time
put_u2le(q, 0); // last_mod_file_date
- put_u4le(q, 0); // crc32 (jar/javac tools don't care)
+ put_u4le(q, entry->crc32); // crc32
put_u4le(q, 0); // compressed_size = placeholder
put_u4le(q, 0); // uncompressed_size = placeholder
put_u2le(q, entry->file_name_length);
@@ -880,7 +1082,9 @@ size_t TryDeflate(u1 *buf, size_t length) {
stream.next_in = buf;
stream.next_out = outbuf;
- if (deflateInit(&stream, Z_DEFAULT_COMPRESSION) != Z_OK) {
+ // deflateInit2 negative windows size prevent the zlib wrapper to be used.
+ if (deflateInit2(&stream, Z_DEFAULT_COMPRESSION, Z_DEFLATED,
+ -MAX_WBITS, 8, Z_DEFAULT_STRATEGY) != Z_OK) {
// Failure to compress => return the buffer uncompressed
free(outbuf);
return length;
@@ -901,7 +1105,8 @@ size_t TryDeflate(u1 *buf, size_t length) {
size_t OutputZipFile::WriteFileSizeInLocalFileHeader(u1 *header_ptr,
size_t out_length,
- bool compress) {
+ bool compress,
+ const u4 crc) {
size_t compressed_size = out_length;
if (compress) {
compressed_size = TryDeflate(q, out_length);
@@ -912,23 +1117,25 @@ size_t OutputZipFile::WriteFileSizeInLocalFileHeader(u1 *header_ptr,
} else {
put_u2le(header_ptr, COMPRESSION_METHOD_STORED);
}
- header_ptr += 8;
+ header_ptr += 4;
+ put_u4le(header_ptr, crc); // crc32
put_u4le(header_ptr, compressed_size); // compressed_size
put_u4le(header_ptr, out_length); // uncompressed_size
return compressed_size;
}
int OutputZipFile::Finish() {
- if (fd_out > 0) {
- WriteCentralDirectory();
- if (ftruncate(fd_out, GetSize()) < 0) {
- return error("ftruncate(fd_out, GetSize()): %s", strerror(errno));
- }
- if (close(fd_out) < 0) {
- return error("close(fd_out): %s", strerror(errno));
- }
- fd_out = -1;
+ if (finished_) {
+ return 0;
+ }
+
+ finished_ = true;
+ WriteCentralDirectory();
+ if (output_file_->Close(GetSize()) < 0) {
+ return error("%s", output_file_->Error());
}
+ delete output_file_;
+ output_file_ = NULL;
return 0;
}
@@ -937,9 +1144,15 @@ u1* OutputZipFile::NewFile(const char* filename, const u4 attr) {
return q;
}
-int OutputZipFile::FinishFile(size_t filelength, bool compress) {
+int OutputZipFile::FinishFile(size_t filelength, bool compress,
+ bool compute_crc) {
+ u4 crc = 0;
+ if (compute_crc) {
+ crc = crc32(crc, q, filelength);
+ }
size_t compressed_size =
- WriteFileSizeInLocalFileHeader(header_ptr, filelength, compress);
+ WriteFileSizeInLocalFileHeader(header_ptr, filelength, compress, crc);
+ entries_.back()->crc32 = crc;
entries_.back()->compressed_length = compressed_size;
entries_.back()->uncompressed_length = filelength;
if (compressed_size < filelength) {
@@ -951,39 +1164,39 @@ int OutputZipFile::FinishFile(size_t filelength, bool compress) {
return 0;
}
-ZipBuilder* ZipBuilder::Create(const char* zip_file, u8 estimated_size) {
- if (estimated_size > kMaximumOutputSize) {
+bool OutputZipFile::Open() {
+ if (estimated_size_ > kMaximumOutputSize) {
fprintf(stderr,
"Uncompressed input jar has size %llu, "
"which exceeds the maximum supported output size %llu.\n"
"Assuming that ijar will be smaller and hoping for the best.\n",
- estimated_size, kMaximumOutputSize);
- estimated_size = kMaximumOutputSize;
- }
-
- int fd_out = open(zip_file, O_CREAT|O_RDWR|O_TRUNC, 0644);
- if (fd_out < 0) {
- return NULL;
+ estimated_size_, kMaximumOutputSize);
+ estimated_size_ = kMaximumOutputSize;
}
- // Create mmap-able sparse file
- if (ftruncate(fd_out, estimated_size) < 0) {
- return NULL;
+ MappedOutputFile* output_file = new MappedOutputFile(
+ filename_, estimated_size_);
+ if (!output_file->Opened()) {
+ snprintf(errmsg, sizeof(errmsg), "%s", output_file->Error());
+ delete output_file;
+ return false;
}
- // Ensure that any buffer overflow in JarStripper will result in
- // SIGSEGV or SIGBUS by over-allocating beyond the end of the file.
- size_t mmap_length = std::min(estimated_size + sysconf(_SC_PAGESIZE),
- (u8) std::numeric_limits<size_t>::max());
+ output_file_ = output_file;
+ q = output_file->Buffer();
+ zipdata_out_ = output_file->Buffer();
+ return true;
+}
- void *zipdata_out = mmap(NULL, mmap_length, PROT_WRITE,
- MAP_SHARED, fd_out, 0);
- if (zipdata_out == MAP_FAILED) {
- fprintf(stderr, "output_length=%llu\n", estimated_size);
+ZipBuilder* ZipBuilder::Create(const char* zip_file, u8 estimated_size) {
+ OutputZipFile* result = new OutputZipFile(zip_file, estimated_size);
+ if (!result->Open()) {
+ fprintf(stderr, "%s\n", result->GetError());
+ delete result;
return NULL;
}
- return new OutputZipFile(fd_out, (u1*) zipdata_out);
+ return result;
}
u8 ZipBuilder::EstimateSize(char **files) {
« no previous file with comments | « third_party/ijar/zip.h ('k') | third_party/ijar/zip_main.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698