Merge "Allow parsing zip entries larger than 4GiB" am: 148f7af18a
Change-Id: I49368fc835c7a4d01771bf3d3b2d480b423d3038
This commit is contained in:
commit
cf14d38562
8 changed files with 308 additions and 141 deletions
|
|
@ -25,6 +25,7 @@
|
|||
#include <sys/cdefs.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <functional>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
|
|
@ -36,10 +37,10 @@ enum {
|
|||
kCompressDeflated = 8, // standard deflate
|
||||
};
|
||||
|
||||
/*
|
||||
* Represents information about a zip entry in a zip file.
|
||||
*/
|
||||
struct ZipEntry {
|
||||
// This struct holds the common information of a zip entry other than the
|
||||
// the entry size. The compressed and uncompressed length will be handled
|
||||
// separately in the derived class.
|
||||
struct ZipEntryCommon {
|
||||
// Compression method. One of kCompressStored or kCompressDeflated.
|
||||
// See also `gpbf` for deflate subtypes.
|
||||
uint16_t method;
|
||||
|
|
@ -67,16 +68,6 @@ struct ZipEntry {
|
|||
// Data descriptor footer at the end of the file entry.
|
||||
uint32_t crc32;
|
||||
|
||||
// Compressed length of this ZipEntry. Might be present
|
||||
// either in the local file header or in the data descriptor
|
||||
// footer.
|
||||
uint32_t compressed_length;
|
||||
|
||||
// Uncompressed length of this ZipEntry. Might be present
|
||||
// either in the local file header or in the data descriptor
|
||||
// footer.
|
||||
uint32_t uncompressed_length;
|
||||
|
||||
// If the value of uncompressed length and compressed length are stored in
|
||||
// the zip64 extended info of the extra field.
|
||||
bool zip64_format_size{false};
|
||||
|
|
@ -97,6 +88,52 @@ struct ZipEntry {
|
|||
bool is_text;
|
||||
};
|
||||
|
||||
struct ZipEntry64;
|
||||
// Many users of the library assume the entry size is capped at UNIT32_MAX. So we keep
|
||||
// the interface for the old ZipEntry here; and we could switch them over to the new
|
||||
// ZipEntry64 later.
|
||||
struct ZipEntry : public ZipEntryCommon {
|
||||
// Compressed length of this ZipEntry. The maximum value is UNIT32_MAX.
|
||||
// Might be present either in the local file header or in the data
|
||||
// descriptor footer.
|
||||
uint32_t compressed_length{0};
|
||||
|
||||
// Uncompressed length of this ZipEntry. The maximum value is UNIT32_MAX.
|
||||
// Might be present either in the local file header or in the data
|
||||
// descriptor footer.
|
||||
uint32_t uncompressed_length{0};
|
||||
|
||||
// Copies the contents of a ZipEntry64 object to a 32 bits ZipEntry. Returns 0 if the
|
||||
// size of the entry fits into uint32_t, returns a negative error code
|
||||
// (kUnsupportedEntrySize) otherwise.
|
||||
static int32_t CopyFromZipEntry64(ZipEntry* dst, const ZipEntry64* src);
|
||||
|
||||
private:
|
||||
ZipEntry& operator=(const ZipEntryCommon& other) {
|
||||
ZipEntryCommon::operator=(other);
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
// Represents information about a zip entry in a zip file.
|
||||
struct ZipEntry64 : public ZipEntryCommon {
|
||||
// Compressed length of this ZipEntry. The maximum value is UNIT64_MAX.
|
||||
// Might be present either in the local file header, the zip64 extended field,
|
||||
// or in the data descriptor footer.
|
||||
uint64_t compressed_length{0};
|
||||
|
||||
// Uncompressed length of this ZipEntry. The maximum value is UNIT64_MAX.
|
||||
// Might be present either in the local file header, the zip64 extended field,
|
||||
// or in the data descriptor footer.
|
||||
uint64_t uncompressed_length{0};
|
||||
|
||||
explicit ZipEntry64() = default;
|
||||
explicit ZipEntry64(const ZipEntry& zip_entry) : ZipEntryCommon(zip_entry) {
|
||||
compressed_length = zip_entry.compressed_length;
|
||||
uncompressed_length = zip_entry.uncompressed_length;
|
||||
}
|
||||
};
|
||||
|
||||
struct ZipArchive;
|
||||
typedef ZipArchive* ZipArchiveHandle;
|
||||
|
||||
|
|
@ -172,7 +209,8 @@ ZipArchiveInfo GetArchiveInfo(ZipArchiveHandle archive);
|
|||
* On non-Windows platforms this method does not modify internal state and
|
||||
* can be called concurrently.
|
||||
*/
|
||||
int32_t FindEntry(const ZipArchiveHandle archive, const std::string_view entryName, ZipEntry* data);
|
||||
int32_t FindEntry(const ZipArchiveHandle archive, const std::string_view entryName,
|
||||
ZipEntry64* data);
|
||||
|
||||
/*
|
||||
* Start iterating over all entries of a zip file. The order of iteration
|
||||
|
|
@ -206,8 +244,8 @@ int32_t StartIteration(ZipArchiveHandle archive, void** cookie_ptr,
|
|||
* Returns 0 on success, -1 if there are no more elements in this
|
||||
* archive and lower negative values on failure.
|
||||
*/
|
||||
int32_t Next(void* cookie, ZipEntry* data, std::string* name);
|
||||
int32_t Next(void* cookie, ZipEntry* data, std::string_view* name);
|
||||
int32_t Next(void* cookie, ZipEntry64* data, std::string_view* name);
|
||||
int32_t Next(void* cookie, ZipEntry64* data, std::string* name);
|
||||
|
||||
/*
|
||||
* End iteration over all entries of a zip file and frees the memory allocated
|
||||
|
|
@ -224,7 +262,7 @@ void EndIteration(void* cookie);
|
|||
*
|
||||
* Returns 0 on success and negative values on failure.
|
||||
*/
|
||||
int32_t ExtractEntryToFile(ZipArchiveHandle archive, ZipEntry* entry, int fd);
|
||||
int32_t ExtractEntryToFile(ZipArchiveHandle archive, const ZipEntry64* entry, int fd);
|
||||
|
||||
/**
|
||||
* Uncompress a given zip entry to the memory region at |begin| and of
|
||||
|
|
@ -234,7 +272,8 @@ int32_t ExtractEntryToFile(ZipArchiveHandle archive, ZipEntry* entry, int fd);
|
|||
*
|
||||
* Returns 0 on success and negative values on failure.
|
||||
*/
|
||||
int32_t ExtractToMemory(ZipArchiveHandle archive, ZipEntry* entry, uint8_t* begin, uint32_t size);
|
||||
int32_t ExtractToMemory(ZipArchiveHandle archive, const ZipEntry64* entry, uint8_t* begin,
|
||||
size_t size);
|
||||
|
||||
int GetFileDescriptor(const ZipArchiveHandle archive);
|
||||
|
||||
|
|
@ -246,6 +285,16 @@ off64_t GetFileDescriptorOffset(const ZipArchiveHandle archive);
|
|||
|
||||
const char* ErrorCodeString(int32_t error_code);
|
||||
|
||||
// Many users of libziparchive assume the entry size to be 32 bits long. So we keep these
|
||||
// interfaces that use 32 bit ZipEntry to make old code work. TODO(xunchang) Remove the 32 bit
|
||||
// wrapper functions once we switch all users to recognize ZipEntry64.
|
||||
int32_t FindEntry(const ZipArchiveHandle archive, const std::string_view entryName, ZipEntry* data);
|
||||
int32_t Next(void* cookie, ZipEntry* data, std::string* name);
|
||||
int32_t Next(void* cookie, ZipEntry* data, std::string_view* name);
|
||||
int32_t ExtractEntryToFile(ZipArchiveHandle archive, const ZipEntry* entry, int fd);
|
||||
int32_t ExtractToMemory(ZipArchiveHandle archive, const ZipEntry* entry, uint8_t* begin,
|
||||
size_t size);
|
||||
|
||||
#if !defined(_WIN32)
|
||||
typedef bool (*ProcessZipEntryFunction)(const uint8_t* buf, size_t buf_size, void* cookie);
|
||||
|
||||
|
|
@ -253,7 +302,9 @@ typedef bool (*ProcessZipEntryFunction)(const uint8_t* buf, size_t buf_size, voi
|
|||
* Stream the uncompressed data through the supplied function,
|
||||
* passing cookie to it each time it gets called.
|
||||
*/
|
||||
int32_t ProcessZipEntryContents(ZipArchiveHandle archive, ZipEntry* entry,
|
||||
int32_t ProcessZipEntryContents(ZipArchiveHandle archive, const ZipEntry* entry,
|
||||
ProcessZipEntryFunction func, void* cookie);
|
||||
int32_t ProcessZipEntryContents(ZipArchiveHandle archive, const ZipEntry64* entry,
|
||||
ProcessZipEntryFunction func, void* cookie);
|
||||
#endif
|
||||
|
||||
|
|
@ -274,7 +325,7 @@ class Writer {
|
|||
|
||||
class Reader {
|
||||
public:
|
||||
virtual bool ReadAtOffset(uint8_t* buf, size_t len, uint32_t offset) const = 0;
|
||||
virtual bool ReadAtOffset(uint8_t* buf, size_t len, off64_t offset) const = 0;
|
||||
virtual ~Reader();
|
||||
|
||||
protected:
|
||||
|
|
@ -296,6 +347,6 @@ class Reader {
|
|||
* If |crc_out| is not nullptr, it is set to the crc32 checksum of the
|
||||
* uncompressed data.
|
||||
*/
|
||||
int32_t Inflate(const Reader& reader, const uint32_t compressed_length,
|
||||
const uint32_t uncompressed_length, Writer* writer, uint64_t* crc_out);
|
||||
int32_t Inflate(const Reader& reader, const uint64_t compressed_length,
|
||||
const uint64_t uncompressed_length, Writer* writer, uint64_t* crc_out);
|
||||
} // namespace zip_archive
|
||||
|
|
|
|||
|
|
@ -83,7 +83,7 @@ class Zip64Test(unittest.TestCase):
|
|||
self._ExtractEntries(zip_path.name)
|
||||
|
||||
|
||||
def test_largeCompressedEntries(self):
|
||||
def test_largeCompressedEntriesSmallerThan4G(self):
|
||||
zip_path = tempfile.NamedTemporaryFile(suffix='.zip')
|
||||
with zipfile.ZipFile(zip_path, 'w', compression=zipfile.ZIP_DEFLATED,
|
||||
allowZip64=True) as output_zip:
|
||||
|
|
@ -99,8 +99,7 @@ class Zip64Test(unittest.TestCase):
|
|||
|
||||
def test_forceDataDescriptor(self):
|
||||
file_path = tempfile.NamedTemporaryFile(suffix='.txt')
|
||||
# TODO create the entry > 4GiB.
|
||||
self._WriteFile(file_path.name, 1024)
|
||||
self._WriteFile(file_path.name, 5000 * 1024)
|
||||
|
||||
zip_path = tempfile.NamedTemporaryFile(suffix='.zip')
|
||||
with zipfile.ZipFile(zip_path, 'w', allowZip64=True) as output_zip:
|
||||
|
|
@ -113,6 +112,35 @@ class Zip64Test(unittest.TestCase):
|
|||
self.assertEquals([file_path.name[1:]], read_names)
|
||||
self._ExtractEntries(zip_path.name)
|
||||
|
||||
|
||||
def test_largeUncompressedEntriesLargerThan4G(self):
|
||||
zip_path = tempfile.NamedTemporaryFile(suffix='.zip')
|
||||
with zipfile.ZipFile(zip_path, 'w', compression=zipfile.ZIP_STORED,
|
||||
allowZip64=True) as output_zip:
|
||||
# Add entries close to 4GiB in size. Somehow the python library will put the (un)compressed
|
||||
# sizes in the extra field. Test if our ziptool should be able to parse it.
|
||||
entry_dict = {'g.txt': 5000 * 1024, 'h.txt': 6000 * 1024}
|
||||
self._AddEntriesToZip(output_zip, entry_dict)
|
||||
|
||||
read_names = self._getEntryNames(zip_path.name)
|
||||
self.assertEquals(sorted(entry_dict.keys()), sorted(read_names))
|
||||
self._ExtractEntries(zip_path.name)
|
||||
|
||||
|
||||
def test_largeCompressedEntriesLargerThan4G(self):
|
||||
zip_path = tempfile.NamedTemporaryFile(suffix='.zip')
|
||||
with zipfile.ZipFile(zip_path, 'w', compression=zipfile.ZIP_DEFLATED,
|
||||
allowZip64=True) as output_zip:
|
||||
# Add entries close to 4GiB in size. Somehow the python library will put the (un)compressed
|
||||
# sizes in the extra field. Test if our ziptool should be able to parse it.
|
||||
entry_dict = {'i.txt': 4096 * 1024, 'j.txt': 7000 * 1024}
|
||||
self._AddEntriesToZip(output_zip, entry_dict)
|
||||
|
||||
read_names = self._getEntryNames(zip_path.name)
|
||||
self.assertEquals(sorted(entry_dict.keys()), sorted(read_names))
|
||||
self._ExtractEntries(zip_path.name)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
testsuite = unittest.TestLoader().discover(
|
||||
os.path.dirname(os.path.realpath(__file__)))
|
||||
|
|
|
|||
|
|
@ -406,15 +406,6 @@ static ZipError ParseZip64ExtendedInfoInExtraField(
|
|||
return kInvalidFile;
|
||||
}
|
||||
|
||||
// TODO(xunchang) Support handling file large than UINT32_MAX. It's theoretically possible
|
||||
// for libz to (de)compressing file larger than UINT32_MAX. But we should use our own
|
||||
// bytes counter to replace stream.total_out.
|
||||
if ((uncompressedFileSize.has_value() && uncompressedFileSize.value() > UINT32_MAX) ||
|
||||
(compressedFileSize.has_value() && compressedFileSize.value() > UINT32_MAX)) {
|
||||
ALOGW("Zip: File size larger than UINT32_MAX isn't supported yet");
|
||||
return kInvalidFile;
|
||||
}
|
||||
|
||||
zip64Info->uncompressed_file_size = uncompressedFileSize;
|
||||
zip64Info->compressed_file_size = compressedFileSize;
|
||||
zip64Info->local_header_offset = localHeaderOffset;
|
||||
|
|
@ -613,7 +604,7 @@ void CloseArchive(ZipArchiveHandle archive) {
|
|||
delete archive;
|
||||
}
|
||||
|
||||
static int32_t ValidateDataDescriptor(MappedZipFile& mapped_zip, ZipEntry* entry) {
|
||||
static int32_t ValidateDataDescriptor(MappedZipFile& mapped_zip, const ZipEntry64* entry) {
|
||||
// Maximum possible size for data descriptor: 2 * 4 + 2 * 8 = 24 bytes
|
||||
uint8_t ddBuf[24];
|
||||
off64_t offset = entry->offset;
|
||||
|
|
@ -644,7 +635,7 @@ static int32_t ValidateDataDescriptor(MappedZipFile& mapped_zip, ZipEntry* entry
|
|||
if (entry->compressed_length != descriptor.compressed_size ||
|
||||
entry->uncompressed_length != descriptor.uncompressed_size ||
|
||||
entry->crc32 != descriptor.crc32) {
|
||||
ALOGW("Zip: size/crc32 mismatch. expected {%" PRIu32 ", %" PRIu32 ", %" PRIx32
|
||||
ALOGW("Zip: size/crc32 mismatch. expected {%" PRIu64 ", %" PRIu64 ", %" PRIx32
|
||||
"}, was {%" PRIu64 ", %" PRIu64 ", %" PRIx32 "}",
|
||||
entry->compressed_length, entry->uncompressed_length, entry->crc32,
|
||||
descriptor.compressed_size, descriptor.uncompressed_size, descriptor.crc32);
|
||||
|
|
@ -655,7 +646,7 @@ static int32_t ValidateDataDescriptor(MappedZipFile& mapped_zip, ZipEntry* entry
|
|||
}
|
||||
|
||||
static int32_t FindEntry(const ZipArchive* archive, std::string_view entryName,
|
||||
const uint64_t nameOffset, ZipEntry* data) {
|
||||
const uint64_t nameOffset, ZipEntry64* data) {
|
||||
// Recover the start of the central directory entry from the filename
|
||||
// pointer. The filename is the first entry past the fixed-size data,
|
||||
// so we can just subtract back from that.
|
||||
|
|
@ -704,11 +695,8 @@ static int32_t FindEntry(const ZipArchive* archive, std::string_view entryName,
|
|||
return status;
|
||||
}
|
||||
|
||||
// TODO(xunchang) remove the size limit and support entry length > UINT32_MAX.
|
||||
data->uncompressed_length =
|
||||
static_cast<uint32_t>(zip64_info.uncompressed_file_size.value_or(cdr->uncompressed_size));
|
||||
data->compressed_length =
|
||||
static_cast<uint32_t>(zip64_info.compressed_file_size.value_or(cdr->compressed_size));
|
||||
data->uncompressed_length = zip64_info.uncompressed_file_size.value_or(cdr->uncompressed_size);
|
||||
data->compressed_length = zip64_info.compressed_file_size.value_or(cdr->compressed_size);
|
||||
local_header_offset = zip64_info.local_header_offset.value_or(local_header_offset);
|
||||
data->zip64_format_size =
|
||||
cdr->uncompressed_size == UINT32_MAX || cdr->compressed_size == UINT32_MAX;
|
||||
|
|
@ -822,7 +810,7 @@ static int32_t FindEntry(const ZipArchive* archive, std::string_view entryName,
|
|||
data->has_data_descriptor = 0;
|
||||
if (data->compressed_length != lfh_compressed_size ||
|
||||
data->uncompressed_length != lfh_uncompressed_size || data->crc32 != lfh->crc32) {
|
||||
ALOGW("Zip: size/crc32 mismatch. expected {%" PRIu32 ", %" PRIu32 ", %" PRIx32
|
||||
ALOGW("Zip: size/crc32 mismatch. expected {%" PRIu64 ", %" PRIu64 ", %" PRIx32
|
||||
"}, was {%" PRIu64 ", %" PRIu64 ", %" PRIx32 "}",
|
||||
data->compressed_length, data->uncompressed_length, data->crc32, lfh_compressed_size,
|
||||
lfh_uncompressed_size, lfh->crc32);
|
||||
|
|
@ -855,16 +843,15 @@ static int32_t FindEntry(const ZipArchive* archive, std::string_view entryName,
|
|||
return kInvalidOffset;
|
||||
}
|
||||
|
||||
if (static_cast<off64_t>(data_offset + data->compressed_length) > cd_offset) {
|
||||
ALOGW("Zip: bad compressed length in zip (%" PRId64 " + %" PRIu32 " > %" PRId64 ")",
|
||||
if (data->compressed_length > cd_offset - data_offset) {
|
||||
ALOGW("Zip: bad compressed length in zip (%" PRId64 " + %" PRIu64 " > %" PRId64 ")",
|
||||
static_cast<int64_t>(data_offset), data->compressed_length,
|
||||
static_cast<int64_t>(cd_offset));
|
||||
return kInvalidOffset;
|
||||
}
|
||||
|
||||
if (data->method == kCompressStored &&
|
||||
static_cast<off64_t>(data_offset + data->uncompressed_length) > cd_offset) {
|
||||
ALOGW("Zip: bad uncompressed length in zip (%" PRId64 " + %" PRIu32 " > %" PRId64 ")",
|
||||
if (data->method == kCompressStored && data->uncompressed_length > cd_offset - data_offset) {
|
||||
ALOGW("Zip: bad uncompressed length in zip (%" PRId64 " + %" PRIu64 " > %" PRId64 ")",
|
||||
static_cast<int64_t>(data_offset), data->uncompressed_length,
|
||||
static_cast<int64_t>(cd_offset));
|
||||
return kInvalidOffset;
|
||||
|
|
@ -918,8 +905,33 @@ void EndIteration(void* cookie) {
|
|||
delete reinterpret_cast<IterationHandle*>(cookie);
|
||||
}
|
||||
|
||||
int32_t ZipEntry::CopyFromZipEntry64(ZipEntry* dst, const ZipEntry64* src) {
|
||||
if (src->compressed_length > UINT32_MAX || src->uncompressed_length > UINT32_MAX) {
|
||||
ALOGW(
|
||||
"Zip: the entry size is too large to fit into the 32 bits ZipEntry, uncompressed "
|
||||
"length %" PRIu64 ", compressed length %" PRIu64,
|
||||
src->uncompressed_length, src->compressed_length);
|
||||
return kUnsupportedEntrySize;
|
||||
}
|
||||
|
||||
*dst = *src;
|
||||
dst->uncompressed_length = static_cast<uint32_t>(src->uncompressed_length);
|
||||
dst->compressed_length = static_cast<uint32_t>(src->compressed_length);
|
||||
return kSuccess;
|
||||
}
|
||||
|
||||
int32_t FindEntry(const ZipArchiveHandle archive, const std::string_view entryName,
|
||||
ZipEntry* data) {
|
||||
ZipEntry64 entry64;
|
||||
if (auto status = FindEntry(archive, entryName, &entry64); status != kSuccess) {
|
||||
return status;
|
||||
}
|
||||
|
||||
return ZipEntry::CopyFromZipEntry64(data, &entry64);
|
||||
}
|
||||
|
||||
int32_t FindEntry(const ZipArchiveHandle archive, const std::string_view entryName,
|
||||
ZipEntry64* data) {
|
||||
if (entryName.empty() || entryName.size() > static_cast<size_t>(UINT16_MAX)) {
|
||||
ALOGW("Zip: Invalid filename of length %zu", entryName.size());
|
||||
return kInvalidEntryName;
|
||||
|
|
@ -936,6 +948,24 @@ int32_t FindEntry(const ZipArchiveHandle archive, const std::string_view entryNa
|
|||
}
|
||||
|
||||
int32_t Next(void* cookie, ZipEntry* data, std::string* name) {
|
||||
ZipEntry64 entry64;
|
||||
if (auto status = Next(cookie, &entry64, name); status != kSuccess) {
|
||||
return status;
|
||||
}
|
||||
|
||||
return ZipEntry::CopyFromZipEntry64(data, &entry64);
|
||||
}
|
||||
|
||||
int32_t Next(void* cookie, ZipEntry* data, std::string_view* name) {
|
||||
ZipEntry64 entry64;
|
||||
if (auto status = Next(cookie, &entry64, name); status != kSuccess) {
|
||||
return status;
|
||||
}
|
||||
|
||||
return ZipEntry::CopyFromZipEntry64(data, &entry64);
|
||||
}
|
||||
|
||||
int32_t Next(void* cookie, ZipEntry64* data, std::string* name) {
|
||||
std::string_view sv;
|
||||
int32_t result = Next(cookie, data, &sv);
|
||||
if (result == 0 && name) {
|
||||
|
|
@ -944,7 +974,7 @@ int32_t Next(void* cookie, ZipEntry* data, std::string* name) {
|
|||
return result;
|
||||
}
|
||||
|
||||
int32_t Next(void* cookie, ZipEntry* data, std::string_view* name) {
|
||||
int32_t Next(void* cookie, ZipEntry64* data, std::string_view* name) {
|
||||
IterationHandle* handle = reinterpret_cast<IterationHandle*>(cookie);
|
||||
if (handle == nullptr) {
|
||||
ALOGW("Zip: Null ZipArchiveHandle");
|
||||
|
|
@ -979,10 +1009,21 @@ int32_t Next(void* cookie, ZipEntry* data, std::string_view* name) {
|
|||
// the data appended to it.
|
||||
class MemoryWriter : public zip_archive::Writer {
|
||||
public:
|
||||
MemoryWriter(uint8_t* buf, size_t size) : Writer(), buf_(buf), size_(size), bytes_written_(0) {}
|
||||
static MemoryWriter Create(uint8_t* buf, size_t size, const ZipEntry64* entry) {
|
||||
const uint64_t declared_length = entry->uncompressed_length;
|
||||
if (declared_length > size) {
|
||||
ALOGW("Zip: file size %" PRIu64 " is larger than the buffer size %zu.", declared_length,
|
||||
size);
|
||||
return MemoryWriter{nullptr, 0};
|
||||
}
|
||||
|
||||
return MemoryWriter(buf, size);
|
||||
}
|
||||
|
||||
bool IsValid() const { return buf_ != nullptr; }
|
||||
|
||||
virtual bool Append(uint8_t* buf, size_t buf_size) override {
|
||||
if (bytes_written_ + buf_size > size_) {
|
||||
if (size_ < buf_size || bytes_written_ > size_ - buf_size) {
|
||||
ALOGW("Zip: Unexpected size %zu (declared) vs %zu (actual)", size_,
|
||||
bytes_written_ + buf_size);
|
||||
return false;
|
||||
|
|
@ -994,7 +1035,9 @@ class MemoryWriter : public zip_archive::Writer {
|
|||
}
|
||||
|
||||
private:
|
||||
uint8_t* const buf_;
|
||||
MemoryWriter(uint8_t* buf, size_t size) : Writer(), buf_(buf), size_(size), bytes_written_(0) {}
|
||||
|
||||
uint8_t* const buf_{nullptr};
|
||||
const size_t size_;
|
||||
size_t bytes_written_;
|
||||
};
|
||||
|
|
@ -1010,14 +1053,19 @@ class FileWriter : public zip_archive::Writer {
|
|||
// block device).
|
||||
//
|
||||
// Returns a valid FileWriter on success, |nullptr| if an error occurred.
|
||||
static FileWriter Create(int fd, const ZipEntry* entry) {
|
||||
const uint32_t declared_length = entry->uncompressed_length;
|
||||
static FileWriter Create(int fd, const ZipEntry64* entry) {
|
||||
const uint64_t declared_length = entry->uncompressed_length;
|
||||
const off64_t current_offset = lseek64(fd, 0, SEEK_CUR);
|
||||
if (current_offset == -1) {
|
||||
ALOGW("Zip: unable to seek to current location on fd %d: %s", fd, strerror(errno));
|
||||
return FileWriter{};
|
||||
}
|
||||
|
||||
if (declared_length > SIZE_MAX || declared_length > INT64_MAX) {
|
||||
ALOGW("Zip: file size %" PRIu64 " is too large to extract.", declared_length);
|
||||
return FileWriter{};
|
||||
}
|
||||
|
||||
#if defined(__linux__)
|
||||
if (declared_length > 0) {
|
||||
// Make sure we have enough space on the volume to extract the compressed
|
||||
|
|
@ -1031,9 +1079,8 @@ class FileWriter : public zip_archive::Writer {
|
|||
// disk does not have enough space.
|
||||
long result = TEMP_FAILURE_RETRY(fallocate(fd, 0, current_offset, declared_length));
|
||||
if (result == -1 && errno == ENOSPC) {
|
||||
ALOGW("Zip: unable to allocate %" PRId64 " bytes at offset %" PRId64 ": %s",
|
||||
static_cast<int64_t>(declared_length), static_cast<int64_t>(current_offset),
|
||||
strerror(errno));
|
||||
ALOGW("Zip: unable to allocate %" PRIu64 " bytes at offset %" PRId64 ": %s",
|
||||
declared_length, static_cast<int64_t>(current_offset), strerror(errno));
|
||||
return FileWriter{};
|
||||
}
|
||||
}
|
||||
|
|
@ -1068,8 +1115,8 @@ class FileWriter : public zip_archive::Writer {
|
|||
bool IsValid() const { return fd_ != -1; }
|
||||
|
||||
virtual bool Append(uint8_t* buf, size_t buf_size) override {
|
||||
if (total_bytes_written_ + buf_size > declared_length_) {
|
||||
ALOGW("Zip: Unexpected size %zu (declared) vs %zu (actual)", declared_length_,
|
||||
if (declared_length_ < buf_size || total_bytes_written_ > declared_length_ - buf_size) {
|
||||
ALOGW("Zip: Unexpected size %zu (declared) vs %zu (actual)", declared_length_,
|
||||
total_bytes_written_ + buf_size);
|
||||
return false;
|
||||
}
|
||||
|
|
@ -1085,8 +1132,13 @@ class FileWriter : public zip_archive::Writer {
|
|||
}
|
||||
|
||||
private:
|
||||
explicit FileWriter(const int fd = -1, const size_t declared_length = 0)
|
||||
: Writer(), fd_(fd), declared_length_(declared_length), total_bytes_written_(0) {}
|
||||
explicit FileWriter(const int fd = -1, const uint64_t declared_length = 0)
|
||||
: Writer(),
|
||||
fd_(fd),
|
||||
declared_length_(static_cast<size_t>(declared_length)),
|
||||
total_bytes_written_(0) {
|
||||
CHECK_LE(declared_length, SIZE_MAX);
|
||||
}
|
||||
|
||||
int fd_;
|
||||
const size_t declared_length_;
|
||||
|
|
@ -1095,10 +1147,10 @@ class FileWriter : public zip_archive::Writer {
|
|||
|
||||
class EntryReader : public zip_archive::Reader {
|
||||
public:
|
||||
EntryReader(const MappedZipFile& zip_file, const ZipEntry* entry)
|
||||
EntryReader(const MappedZipFile& zip_file, const ZipEntry64* entry)
|
||||
: Reader(), zip_file_(zip_file), entry_(entry) {}
|
||||
|
||||
virtual bool ReadAtOffset(uint8_t* buf, size_t len, uint32_t offset) const {
|
||||
virtual bool ReadAtOffset(uint8_t* buf, size_t len, off64_t offset) const {
|
||||
return zip_file_.ReadAtOffset(buf, len, entry_->offset + offset);
|
||||
}
|
||||
|
||||
|
|
@ -1106,7 +1158,7 @@ class EntryReader : public zip_archive::Reader {
|
|||
|
||||
private:
|
||||
const MappedZipFile& zip_file_;
|
||||
const ZipEntry* entry_;
|
||||
const ZipEntry64* entry_;
|
||||
};
|
||||
|
||||
// This method is using libz macros with old-style-casts
|
||||
|
|
@ -1123,8 +1175,8 @@ namespace zip_archive {
|
|||
Reader::~Reader() {}
|
||||
Writer::~Writer() {}
|
||||
|
||||
int32_t Inflate(const Reader& reader, const uint32_t compressed_length,
|
||||
const uint32_t uncompressed_length, Writer* writer, uint64_t* crc_out) {
|
||||
int32_t Inflate(const Reader& reader, const uint64_t compressed_length,
|
||||
const uint64_t uncompressed_length, Writer* writer, uint64_t* crc_out) {
|
||||
const size_t kBufSize = 32768;
|
||||
std::vector<uint8_t> read_buf(kBufSize);
|
||||
std::vector<uint8_t> write_buf(kBufSize);
|
||||
|
|
@ -1167,12 +1219,14 @@ int32_t Inflate(const Reader& reader, const uint32_t compressed_length,
|
|||
|
||||
const bool compute_crc = (crc_out != nullptr);
|
||||
uLong crc = 0;
|
||||
uint32_t remaining_bytes = compressed_length;
|
||||
uint64_t remaining_bytes = compressed_length;
|
||||
uint64_t total_output = 0;
|
||||
do {
|
||||
/* read as much as we can */
|
||||
if (zstream.avail_in == 0) {
|
||||
const uint32_t read_size = (remaining_bytes > kBufSize) ? kBufSize : remaining_bytes;
|
||||
const uint32_t offset = (compressed_length - remaining_bytes);
|
||||
const uint32_t read_size =
|
||||
(remaining_bytes > kBufSize) ? kBufSize : static_cast<uint32_t>(remaining_bytes);
|
||||
const off64_t offset = (compressed_length - remaining_bytes);
|
||||
// Make sure to read at offset to ensure concurrent access to the fd.
|
||||
if (!reader.ReadAtOffset(read_buf.data(), read_size, offset)) {
|
||||
ALOGW("Zip: inflate read failed, getSize = %u: %s", read_size, strerror(errno));
|
||||
|
|
@ -1203,6 +1257,7 @@ int32_t Inflate(const Reader& reader, const uint32_t compressed_length,
|
|||
crc = crc32(crc, &write_buf[0], static_cast<uint32_t>(write_size));
|
||||
}
|
||||
|
||||
total_output += kBufSize - zstream.avail_out;
|
||||
zstream.next_out = &write_buf[0];
|
||||
zstream.avail_out = kBufSize;
|
||||
}
|
||||
|
|
@ -1219,9 +1274,8 @@ int32_t Inflate(const Reader& reader, const uint32_t compressed_length,
|
|||
if (compute_crc) {
|
||||
*crc_out = crc;
|
||||
}
|
||||
|
||||
if (zstream.total_out != uncompressed_length || remaining_bytes != 0) {
|
||||
ALOGW("Zip: size mismatch on inflated file (%lu vs %" PRIu32 ")", zstream.total_out,
|
||||
if (total_output != uncompressed_length || remaining_bytes != 0) {
|
||||
ALOGW("Zip: size mismatch on inflated file (%lu vs %" PRIu64 ")", zstream.total_out,
|
||||
uncompressed_length);
|
||||
return kInconsistentInformation;
|
||||
}
|
||||
|
|
@ -1230,7 +1284,7 @@ int32_t Inflate(const Reader& reader, const uint32_t compressed_length,
|
|||
}
|
||||
} // namespace zip_archive
|
||||
|
||||
static int32_t InflateEntryToWriter(MappedZipFile& mapped_zip, const ZipEntry* entry,
|
||||
static int32_t InflateEntryToWriter(MappedZipFile& mapped_zip, const ZipEntry64* entry,
|
||||
zip_archive::Writer* writer, uint64_t* crc_out) {
|
||||
const EntryReader reader(mapped_zip, entry);
|
||||
|
||||
|
|
@ -1238,20 +1292,21 @@ static int32_t InflateEntryToWriter(MappedZipFile& mapped_zip, const ZipEntry* e
|
|||
crc_out);
|
||||
}
|
||||
|
||||
static int32_t CopyEntryToWriter(MappedZipFile& mapped_zip, const ZipEntry* entry,
|
||||
static int32_t CopyEntryToWriter(MappedZipFile& mapped_zip, const ZipEntry64* entry,
|
||||
zip_archive::Writer* writer, uint64_t* crc_out) {
|
||||
static const uint32_t kBufSize = 32768;
|
||||
std::vector<uint8_t> buf(kBufSize);
|
||||
|
||||
const uint32_t length = entry->uncompressed_length;
|
||||
uint32_t count = 0;
|
||||
const uint64_t length = entry->uncompressed_length;
|
||||
uint64_t count = 0;
|
||||
uLong crc = 0;
|
||||
while (count < length) {
|
||||
uint32_t remaining = length - count;
|
||||
uint64_t remaining = length - count;
|
||||
off64_t offset = entry->offset + count;
|
||||
|
||||
// Safe conversion because kBufSize is narrow enough for a 32 bit signed value.
|
||||
const uint32_t block_size = (remaining > kBufSize) ? kBufSize : remaining;
|
||||
const uint32_t block_size =
|
||||
(remaining > kBufSize) ? kBufSize : static_cast<uint32_t>(remaining);
|
||||
|
||||
// Make sure to read at offset to ensure concurrent access to the fd.
|
||||
if (!mapped_zip.ReadAtOffset(buf.data(), block_size, offset)) {
|
||||
|
|
@ -1272,20 +1327,21 @@ static int32_t CopyEntryToWriter(MappedZipFile& mapped_zip, const ZipEntry* entr
|
|||
return 0;
|
||||
}
|
||||
|
||||
int32_t ExtractToWriter(ZipArchiveHandle archive, ZipEntry* entry, zip_archive::Writer* writer) {
|
||||
int32_t ExtractToWriter(ZipArchiveHandle handle, const ZipEntry64* entry,
|
||||
zip_archive::Writer* writer) {
|
||||
const uint16_t method = entry->method;
|
||||
|
||||
// this should default to kUnknownCompressionMethod.
|
||||
int32_t return_value = -1;
|
||||
uint64_t crc = 0;
|
||||
if (method == kCompressStored) {
|
||||
return_value = CopyEntryToWriter(archive->mapped_zip, entry, writer, &crc);
|
||||
return_value = CopyEntryToWriter(handle->mapped_zip, entry, writer, &crc);
|
||||
} else if (method == kCompressDeflated) {
|
||||
return_value = InflateEntryToWriter(archive->mapped_zip, entry, writer, &crc);
|
||||
return_value = InflateEntryToWriter(handle->mapped_zip, entry, writer, &crc);
|
||||
}
|
||||
|
||||
if (!return_value && entry->has_data_descriptor) {
|
||||
return_value = ValidateDataDescriptor(archive->mapped_zip, entry);
|
||||
return_value = ValidateDataDescriptor(handle->mapped_zip, entry);
|
||||
if (return_value) {
|
||||
return return_value;
|
||||
}
|
||||
|
|
@ -1300,12 +1356,28 @@ int32_t ExtractToWriter(ZipArchiveHandle archive, ZipEntry* entry, zip_archive::
|
|||
return return_value;
|
||||
}
|
||||
|
||||
int32_t ExtractToMemory(ZipArchiveHandle archive, ZipEntry* entry, uint8_t* begin, uint32_t size) {
|
||||
MemoryWriter writer(begin, size);
|
||||
int32_t ExtractToMemory(ZipArchiveHandle archive, const ZipEntry* entry, uint8_t* begin,
|
||||
size_t size) {
|
||||
ZipEntry64 entry64(*entry);
|
||||
return ExtractToMemory(archive, &entry64, begin, size);
|
||||
}
|
||||
|
||||
int32_t ExtractToMemory(ZipArchiveHandle archive, const ZipEntry64* entry, uint8_t* begin,
|
||||
size_t size) {
|
||||
auto writer = MemoryWriter::Create(begin, size, entry);
|
||||
if (!writer.IsValid()) {
|
||||
return kIoError;
|
||||
}
|
||||
|
||||
return ExtractToWriter(archive, entry, &writer);
|
||||
}
|
||||
|
||||
int32_t ExtractEntryToFile(ZipArchiveHandle archive, ZipEntry* entry, int fd) {
|
||||
int32_t ExtractEntryToFile(ZipArchiveHandle archive, const ZipEntry* entry, int fd) {
|
||||
ZipEntry64 entry64(*entry);
|
||||
return ExtractEntryToFile(archive, &entry64, fd);
|
||||
}
|
||||
|
||||
int32_t ExtractEntryToFile(ZipArchiveHandle archive, const ZipEntry64* entry, int fd) {
|
||||
auto writer = FileWriter::Create(fd, entry);
|
||||
if (!writer.IsValid()) {
|
||||
return kIoError;
|
||||
|
|
@ -1337,7 +1409,13 @@ class ProcessWriter : public zip_archive::Writer {
|
|||
void* cookie_;
|
||||
};
|
||||
|
||||
int32_t ProcessZipEntryContents(ZipArchiveHandle archive, ZipEntry* entry,
|
||||
int32_t ProcessZipEntryContents(ZipArchiveHandle archive, const ZipEntry* entry,
|
||||
ProcessZipEntryFunction func, void* cookie) {
|
||||
ZipEntry64 entry64(*entry);
|
||||
return ProcessZipEntryContents(archive, &entry64, func, cookie);
|
||||
}
|
||||
|
||||
int32_t ProcessZipEntryContents(ZipArchiveHandle archive, const ZipEntry64* entry,
|
||||
ProcessZipEntryFunction func, void* cookie) {
|
||||
ProcessWriter writer(func, cookie);
|
||||
return ExtractToWriter(archive, entry, &writer);
|
||||
|
|
@ -1466,7 +1544,7 @@ bool ZipArchive::InitializeCentralDirectory(off64_t cd_start_offset, size_t cd_s
|
|||
return true;
|
||||
}
|
||||
|
||||
tm ZipEntry::GetModificationTime() const {
|
||||
tm ZipEntryCommon::GetModificationTime() const {
|
||||
tm t = {};
|
||||
|
||||
t.tm_hour = (mod_time >> 11) & 0x1f;
|
||||
|
|
|
|||
|
|
@ -106,7 +106,8 @@ struct ZipArchive {
|
|||
bool InitializeCentralDirectory(off64_t cd_start_offset, size_t cd_size);
|
||||
};
|
||||
|
||||
int32_t ExtractToWriter(ZipArchiveHandle handle, ZipEntry* entry, zip_archive::Writer* writer);
|
||||
int32_t ExtractToWriter(ZipArchiveHandle handle, const ZipEntry64* entry,
|
||||
zip_archive::Writer* writer);
|
||||
|
||||
// Reads the unaligned data of type |T| and auto increment the offset.
|
||||
template <typename T>
|
||||
|
|
|
|||
|
|
@ -217,7 +217,7 @@ TEST(ziparchive, Iteration_std_string_view) {
|
|||
void* iteration_cookie;
|
||||
ASSERT_EQ(0, StartIteration(handle, &iteration_cookie));
|
||||
|
||||
ZipEntry data;
|
||||
ZipEntry64 data;
|
||||
std::vector<std::string_view> names;
|
||||
std::string_view name;
|
||||
while (Next(iteration_cookie, &data, &name) == 0) names.push_back(name);
|
||||
|
|
@ -232,12 +232,12 @@ TEST(ziparchive, Iteration_std_string_view) {
|
|||
|
||||
static void AssertIterationNames(void* iteration_cookie,
|
||||
const std::vector<std::string>& expected_names_sorted) {
|
||||
ZipEntry data;
|
||||
ZipEntry64 data;
|
||||
std::vector<std::string> names;
|
||||
std::string name;
|
||||
std::string_view name;
|
||||
for (size_t i = 0; i < expected_names_sorted.size(); ++i) {
|
||||
ASSERT_EQ(0, Next(iteration_cookie, &data, &name));
|
||||
names.push_back(name);
|
||||
names.push_back(std::string(name));
|
||||
}
|
||||
// End of iteration.
|
||||
ASSERT_EQ(-1, Next(iteration_cookie, &data, &name));
|
||||
|
|
@ -325,8 +325,8 @@ TEST(ziparchive, IterationWithBadPrefixAndSuffix) {
|
|||
void* iteration_cookie;
|
||||
ASSERT_EQ(0, StartIteration(handle, &iteration_cookie, "x", "y"));
|
||||
|
||||
ZipEntry data;
|
||||
std::string name;
|
||||
ZipEntry64 data;
|
||||
std::string_view name;
|
||||
|
||||
// End of iteration.
|
||||
ASSERT_EQ(-1, Next(iteration_cookie, &data, &name));
|
||||
|
|
@ -338,7 +338,7 @@ TEST(ziparchive, FindEntry) {
|
|||
ZipArchiveHandle handle;
|
||||
ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));
|
||||
|
||||
ZipEntry data;
|
||||
ZipEntry64 data;
|
||||
ASSERT_EQ(0, FindEntry(handle, "a.txt", &data));
|
||||
|
||||
// Known facts about a.txt, from zipinfo -v.
|
||||
|
|
@ -359,7 +359,7 @@ TEST(ziparchive, FindEntry_empty) {
|
|||
ZipArchiveHandle handle;
|
||||
ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));
|
||||
|
||||
ZipEntry data;
|
||||
ZipEntry64 data;
|
||||
ASSERT_EQ(kInvalidEntryName, FindEntry(handle, "", &data));
|
||||
|
||||
CloseArchive(handle);
|
||||
|
|
@ -370,7 +370,7 @@ TEST(ziparchive, FindEntry_too_long) {
|
|||
ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));
|
||||
|
||||
std::string very_long_name(65536, 'x');
|
||||
ZipEntry data;
|
||||
ZipEntry64 data;
|
||||
ASSERT_EQ(kInvalidEntryName, FindEntry(handle, very_long_name, &data));
|
||||
|
||||
CloseArchive(handle);
|
||||
|
|
@ -383,8 +383,8 @@ TEST(ziparchive, TestInvalidDeclaredLength) {
|
|||
void* iteration_cookie;
|
||||
ASSERT_EQ(0, StartIteration(handle, &iteration_cookie));
|
||||
|
||||
std::string name;
|
||||
ZipEntry data;
|
||||
std::string_view name;
|
||||
ZipEntry64 data;
|
||||
|
||||
ASSERT_EQ(Next(iteration_cookie, &data, &name), 0);
|
||||
ASSERT_EQ(Next(iteration_cookie, &data, &name), 0);
|
||||
|
|
@ -415,9 +415,9 @@ TEST(ziparchive, OpenArchiveFdRange) {
|
|||
static_cast<off64_t>(leading_garbage.size())));
|
||||
|
||||
// An entry that's deflated.
|
||||
ZipEntry data;
|
||||
ZipEntry64 data;
|
||||
ASSERT_EQ(0, FindEntry(handle, "a.txt", &data));
|
||||
const uint32_t a_size = data.uncompressed_length;
|
||||
const auto a_size = static_cast<size_t>(data.uncompressed_length);
|
||||
ASSERT_EQ(a_size, kATxtContents.size());
|
||||
auto buffer = std::unique_ptr<uint8_t[]>(new uint8_t[a_size]);
|
||||
ASSERT_EQ(0, ExtractToMemory(handle, &data, buffer.get(), a_size));
|
||||
|
|
@ -425,7 +425,7 @@ TEST(ziparchive, OpenArchiveFdRange) {
|
|||
|
||||
// An entry that's stored.
|
||||
ASSERT_EQ(0, FindEntry(handle, "b.txt", &data));
|
||||
const uint32_t b_size = data.uncompressed_length;
|
||||
const auto b_size = static_cast<size_t>(data.uncompressed_length);
|
||||
ASSERT_EQ(b_size, kBTxtContents.size());
|
||||
buffer = std::unique_ptr<uint8_t[]>(new uint8_t[b_size]);
|
||||
ASSERT_EQ(0, ExtractToMemory(handle, &data, buffer.get(), b_size));
|
||||
|
|
@ -439,9 +439,9 @@ TEST(ziparchive, ExtractToMemory) {
|
|||
ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));
|
||||
|
||||
// An entry that's deflated.
|
||||
ZipEntry data;
|
||||
ZipEntry64 data;
|
||||
ASSERT_EQ(0, FindEntry(handle, "a.txt", &data));
|
||||
const uint32_t a_size = data.uncompressed_length;
|
||||
const auto a_size = static_cast<size_t>(data.uncompressed_length);
|
||||
ASSERT_EQ(a_size, kATxtContents.size());
|
||||
uint8_t* buffer = new uint8_t[a_size];
|
||||
ASSERT_EQ(0, ExtractToMemory(handle, &data, buffer, a_size));
|
||||
|
|
@ -450,7 +450,7 @@ TEST(ziparchive, ExtractToMemory) {
|
|||
|
||||
// An entry that's stored.
|
||||
ASSERT_EQ(0, FindEntry(handle, "b.txt", &data));
|
||||
const uint32_t b_size = data.uncompressed_length;
|
||||
const auto b_size = static_cast<size_t>(data.uncompressed_length);
|
||||
ASSERT_EQ(b_size, kBTxtContents.size());
|
||||
buffer = new uint8_t[b_size];
|
||||
ASSERT_EQ(0, ExtractToMemory(handle, &data, buffer, b_size));
|
||||
|
|
@ -503,7 +503,7 @@ TEST(ziparchive, EmptyEntries) {
|
|||
ZipArchiveHandle handle;
|
||||
ASSERT_EQ(0, OpenArchiveFd(tmp_file.fd, "EmptyEntriesTest", &handle, false));
|
||||
|
||||
ZipEntry entry;
|
||||
ZipEntry64 entry;
|
||||
ASSERT_EQ(0, FindEntry(handle, "empty.txt", &entry));
|
||||
ASSERT_EQ(static_cast<uint32_t>(0), entry.uncompressed_length);
|
||||
uint8_t buffer[1];
|
||||
|
|
@ -526,7 +526,7 @@ TEST(ziparchive, EntryLargerThan32K) {
|
|||
ZipArchiveHandle handle;
|
||||
ASSERT_EQ(0, OpenArchiveFd(tmp_file.fd, "EntryLargerThan32KTest", &handle, false));
|
||||
|
||||
ZipEntry entry;
|
||||
ZipEntry64 entry;
|
||||
ASSERT_EQ(0, FindEntry(handle, kAbTxtName, &entry));
|
||||
ASSERT_EQ(kAbUncompressedSize, entry.uncompressed_length);
|
||||
|
||||
|
|
@ -583,7 +583,7 @@ TEST(ziparchive, ExtractToFile) {
|
|||
ZipArchiveHandle handle;
|
||||
ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));
|
||||
|
||||
ZipEntry entry;
|
||||
ZipEntry64 entry;
|
||||
ASSERT_EQ(0, FindEntry(handle, "a.txt", &entry));
|
||||
ASSERT_EQ(0, ExtractEntryToFile(handle, &entry, tmp_file.fd));
|
||||
|
||||
|
|
@ -594,9 +594,9 @@ TEST(ziparchive, ExtractToFile) {
|
|||
ASSERT_EQ(0, memcmp(read_buffer, data, data_size));
|
||||
|
||||
// Assert that the remainder of the file contains the incompressed data.
|
||||
std::vector<uint8_t> uncompressed_data(entry.uncompressed_length);
|
||||
ASSERT_TRUE(
|
||||
android::base::ReadFully(tmp_file.fd, uncompressed_data.data(), entry.uncompressed_length));
|
||||
std::vector<uint8_t> uncompressed_data(static_cast<size_t>(entry.uncompressed_length));
|
||||
ASSERT_TRUE(android::base::ReadFully(tmp_file.fd, uncompressed_data.data(),
|
||||
static_cast<size_t>(entry.uncompressed_length)));
|
||||
ASSERT_EQ(0, memcmp(&uncompressed_data[0], kATxtContents.data(), kATxtContents.size()));
|
||||
|
||||
// Assert that the total length of the file is sane
|
||||
|
|
@ -620,7 +620,7 @@ TEST(ziparchive, OpenFromMemory) {
|
|||
OpenArchiveFromMemory(file_map->data(), file_map->size(), zip_path.c_str(), &handle));
|
||||
|
||||
// Assert one entry can be found and extracted correctly.
|
||||
ZipEntry binary_entry;
|
||||
ZipEntry64 binary_entry;
|
||||
ASSERT_EQ(0, FindEntry(handle, "META-INF/com/google/android/update-binary", &binary_entry));
|
||||
TemporaryFile tmp_binary;
|
||||
ASSERT_NE(-1, tmp_binary.fd);
|
||||
|
|
@ -635,13 +635,13 @@ static void ZipArchiveStreamTest(ZipArchiveHandle& handle, const std::string& en
|
|||
if (raw) {
|
||||
stream.reset(ZipArchiveStreamEntry::CreateRaw(handle, *entry));
|
||||
if (entry->method == kCompressStored) {
|
||||
read_data->resize(entry->uncompressed_length);
|
||||
read_data->resize(static_cast<size_t>(entry->uncompressed_length));
|
||||
} else {
|
||||
read_data->resize(entry->compressed_length);
|
||||
read_data->resize(static_cast<size_t>(entry->compressed_length));
|
||||
}
|
||||
} else {
|
||||
stream.reset(ZipArchiveStreamEntry::Create(handle, *entry));
|
||||
read_data->resize(entry->uncompressed_length);
|
||||
read_data->resize(static_cast<size_t>(entry->uncompressed_length));
|
||||
}
|
||||
uint8_t* read_data_ptr = read_data->data();
|
||||
ASSERT_TRUE(stream.get() != nullptr);
|
||||
|
|
@ -681,7 +681,7 @@ static void ZipArchiveStreamTestUsingMemory(const std::string& zip_file,
|
|||
std::vector<uint8_t> read_data;
|
||||
ZipArchiveStreamTest(handle, entry_name, false, true, &entry, &read_data);
|
||||
|
||||
std::vector<uint8_t> cmp_data(entry.uncompressed_length);
|
||||
std::vector<uint8_t> cmp_data(static_cast<size_t>(entry.uncompressed_length));
|
||||
ASSERT_EQ(entry.uncompressed_length, read_data.size());
|
||||
ASSERT_EQ(
|
||||
0, ExtractToMemory(handle, &entry, cmp_data.data(), static_cast<uint32_t>(cmp_data.size())));
|
||||
|
|
@ -741,8 +741,8 @@ TEST(ziparchive, StreamUncompressedBadCrc) {
|
|||
// FileOutputStream fos = new
|
||||
// FileOutputStream("/tmp/data_descriptor.zip");
|
||||
// ZipOutputStream zos = new ZipOutputStream(fos);
|
||||
// ZipEntry ze = new ZipEntry("name");
|
||||
// ze.setMethod(ZipEntry.DEFLATED);
|
||||
// ZipEntry64 ze = new ZipEntry64("name");
|
||||
// ze.setMethod(ZipEntry64.DEFLATED);
|
||||
// zos.putNextEntry(ze);
|
||||
// zos.write("abdcdefghijk".getBytes());
|
||||
// zos.closeEntry();
|
||||
|
|
@ -780,7 +780,7 @@ static void ExtractEntryToMemory(const std::vector<uint8_t>& zip_data,
|
|||
// This function expects a variant of kDataDescriptorZipFile, for look for
|
||||
// an entry whose name is "name" and whose size is 12 (contents =
|
||||
// "abdcdefghijk").
|
||||
ZipEntry entry;
|
||||
ZipEntry64 entry;
|
||||
ASSERT_EQ(0, FindEntry(handle, "name", &entry));
|
||||
ASSERT_EQ(static_cast<uint32_t>(12), entry.uncompressed_length);
|
||||
|
||||
|
|
@ -887,12 +887,12 @@ class VectorReader : public zip_archive::Reader {
|
|||
public:
|
||||
VectorReader(const std::vector<uint8_t>& input) : Reader(), input_(input) {}
|
||||
|
||||
bool ReadAtOffset(uint8_t* buf, size_t len, uint32_t offset) const {
|
||||
bool ReadAtOffset(uint8_t* buf, size_t len, off64_t offset) const {
|
||||
if ((offset + len) < input_.size()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
memcpy(buf, &input_[offset], len);
|
||||
memcpy(buf, &input_[static_cast<size_t>(offset)], len);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -919,7 +919,7 @@ class BadReader : public zip_archive::Reader {
|
|||
public:
|
||||
BadReader() : Reader() {}
|
||||
|
||||
bool ReadAtOffset(uint8_t*, size_t, uint32_t) const { return false; }
|
||||
bool ReadAtOffset(uint8_t*, size_t, off64_t) const { return false; }
|
||||
};
|
||||
|
||||
class BadWriter : public zip_archive::Writer {
|
||||
|
|
@ -1222,7 +1222,7 @@ TEST_F(Zip64ParseTest, findEntry) {
|
|||
ZipArchiveHandle handle;
|
||||
ASSERT_EQ(
|
||||
0, OpenArchiveFromMemory(zip_content_.data(), zip_content_.size(), "debug_zip64", &handle));
|
||||
ZipEntry entry;
|
||||
ZipEntry64 entry;
|
||||
ASSERT_EQ(0, FindEntry(handle, "a.txt", &entry));
|
||||
ASSERT_EQ(200, entry.uncompressed_length);
|
||||
ASSERT_EQ(200, entry.compressed_length);
|
||||
|
|
@ -1245,7 +1245,7 @@ TEST_F(Zip64ParseTest, openFileIncorrectDataSizeInLocalExtendedField) {
|
|||
ZipArchiveHandle handle;
|
||||
ASSERT_EQ(
|
||||
0, OpenArchiveFromMemory(zip_content_.data(), zip_content_.size(), "debug_zip64", &handle));
|
||||
ZipEntry entry;
|
||||
ZipEntry64 entry;
|
||||
ASSERT_NE(0, FindEntry(handle, "a.txt", &entry));
|
||||
|
||||
CloseArchive(handle);
|
||||
|
|
@ -1267,7 +1267,7 @@ TEST_F(Zip64ParseTest, iterates) {
|
|||
ASSERT_EQ(0, StartIteration(handle, &iteration_cookie));
|
||||
std::set<std::string_view> result;
|
||||
std::string_view name;
|
||||
ZipEntry entry;
|
||||
ZipEntry64 entry;
|
||||
while (Next(iteration_cookie, &entry, &name) == 0) result.emplace(name);
|
||||
ASSERT_EQ(names, result);
|
||||
|
||||
|
|
@ -1297,7 +1297,7 @@ TEST_F(Zip64ParseTest, extract) {
|
|||
ZipArchiveHandle handle;
|
||||
ASSERT_EQ(
|
||||
0, OpenArchiveFromMemory(zip_content_.data(), zip_content_.size(), "debug_zip64", &handle));
|
||||
ZipEntry entry;
|
||||
ZipEntry64 entry;
|
||||
ASSERT_EQ(0, FindEntry(handle, "a.txt", &entry));
|
||||
|
||||
VectorWriter writer;
|
||||
|
|
@ -1315,7 +1315,7 @@ TEST_F(Zip64ParseTest, extractWithDataDescriptor) {
|
|||
ZipArchiveHandle handle;
|
||||
ASSERT_EQ(
|
||||
0, OpenArchiveFromMemory(zip_content_.data(), zip_content_.size(), "debug_zip64", &handle));
|
||||
ZipEntry entry;
|
||||
ZipEntry64 entry;
|
||||
ASSERT_EQ(0, FindEntry(handle, "b.txt", &entry));
|
||||
|
||||
VectorWriter writer;
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ static const char* kErrorMessages[] = {
|
|||
"I/O error",
|
||||
"File mapping failed",
|
||||
"Allocation failed",
|
||||
"Unsupported zip entry size",
|
||||
};
|
||||
|
||||
const char* ErrorCodeString(int32_t error_code) {
|
||||
|
|
|
|||
|
|
@ -66,5 +66,9 @@ enum ZipError : int32_t {
|
|||
// An allocation failed.
|
||||
kAllocationFailed = -13,
|
||||
|
||||
kLastErrorCode = kAllocationFailed,
|
||||
// The compressed or uncompressed size is larger than UINT32_MAX and
|
||||
// doesn't fit into the 32 bits zip entry.
|
||||
kUnsupportedEntrySize = -14,
|
||||
|
||||
kLastErrorCode = kUnsupportedEntrySize,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -193,21 +193,25 @@ static bool PromptOverwrite(const std::string& dst) {
|
|||
}
|
||||
}
|
||||
|
||||
static void ExtractToPipe(ZipArchiveHandle zah, ZipEntry& entry, const std::string& name) {
|
||||
static void ExtractToPipe(ZipArchiveHandle zah, const ZipEntry64& entry, const std::string& name) {
|
||||
// We need to extract to memory because ExtractEntryToFile insists on
|
||||
// being able to seek and truncate, and you can't do that with stdout.
|
||||
uint8_t* buffer = new uint8_t[entry.uncompressed_length];
|
||||
int err = ExtractToMemory(zah, &entry, buffer, entry.uncompressed_length);
|
||||
if (entry.uncompressed_length > SIZE_MAX) {
|
||||
die(0, "entry size %" PRIu64 " is too large to extract.", entry.uncompressed_length);
|
||||
}
|
||||
auto uncompressed_length = static_cast<size_t>(entry.uncompressed_length);
|
||||
uint8_t* buffer = new uint8_t[uncompressed_length];
|
||||
int err = ExtractToMemory(zah, &entry, buffer, uncompressed_length);
|
||||
if (err < 0) {
|
||||
die(0, "failed to extract %s: %s", name.c_str(), ErrorCodeString(err));
|
||||
}
|
||||
if (!android::base::WriteFully(1, buffer, entry.uncompressed_length)) {
|
||||
if (!android::base::WriteFully(1, buffer, uncompressed_length)) {
|
||||
die(errno, "failed to write %s to stdout", name.c_str());
|
||||
}
|
||||
delete[] buffer;
|
||||
}
|
||||
|
||||
static void ExtractOne(ZipArchiveHandle zah, ZipEntry& entry, const std::string& name) {
|
||||
static void ExtractOne(ZipArchiveHandle zah, const ZipEntry64& entry, const std::string& name) {
|
||||
// Bad filename?
|
||||
if (StartsWith(name, "/") || StartsWith(name, "../") || name.find("/../") != std::string::npos) {
|
||||
die(0, "bad filename %s", name.c_str());
|
||||
|
|
@ -253,22 +257,22 @@ static void ExtractOne(ZipArchiveHandle zah, ZipEntry& entry, const std::string&
|
|||
close(fd);
|
||||
}
|
||||
|
||||
static void ListOne(const ZipEntry& entry, const std::string& name) {
|
||||
static void ListOne(const ZipEntry64& entry, const std::string& name) {
|
||||
tm t = entry.GetModificationTime();
|
||||
char time[32];
|
||||
snprintf(time, sizeof(time), "%04d-%02d-%02d %02d:%02d", t.tm_year + 1900, t.tm_mon + 1,
|
||||
t.tm_mday, t.tm_hour, t.tm_min);
|
||||
if (flag_v) {
|
||||
printf("%8d %s %7d %3.0f%% %s %08x %s\n", entry.uncompressed_length,
|
||||
printf("%8" PRIu64 " %s %8" PRIu64 " %3.0f%% %s %08x %s\n", entry.uncompressed_length,
|
||||
(entry.method == kCompressStored) ? "Stored" : "Defl:N", entry.compressed_length,
|
||||
CompressionRatio(entry.uncompressed_length, entry.compressed_length), time, entry.crc32,
|
||||
name.c_str());
|
||||
} else {
|
||||
printf("%9d %s %s\n", entry.uncompressed_length, time, name.c_str());
|
||||
printf("%9" PRIu64 " %s %s\n", entry.uncompressed_length, time, name.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
static void InfoOne(const ZipEntry& entry, const std::string& name) {
|
||||
static void InfoOne(const ZipEntry64& entry, const std::string& name) {
|
||||
if (flag_1) {
|
||||
// "android-ndk-r19b/sources/android/NOTICE"
|
||||
printf("%s\n", name.c_str());
|
||||
|
|
@ -323,12 +327,12 @@ static void InfoOne(const ZipEntry& entry, const std::string& name) {
|
|||
t.tm_mday, t.tm_hour, t.tm_min);
|
||||
|
||||
// "-rw-r--r-- 3.0 unx 577 t- defX 19-Feb-12 16:09 android-ndk-r19b/sources/android/NOTICE"
|
||||
printf("%s %2d.%d %s %8d %c%c %s %s %s\n", mode, version / 10, version % 10, src_fs,
|
||||
printf("%s %2d.%d %s %8" PRIu64 " %c%c %s %s %s\n", mode, version / 10, version % 10, src_fs,
|
||||
entry.uncompressed_length, entry.is_text ? 't' : 'b',
|
||||
entry.has_data_descriptor ? 'X' : 'x', method, time, name.c_str());
|
||||
}
|
||||
|
||||
static void ProcessOne(ZipArchiveHandle zah, ZipEntry& entry, const std::string& name) {
|
||||
static void ProcessOne(ZipArchiveHandle zah, const ZipEntry64& entry, const std::string& name) {
|
||||
if (role == kUnzip) {
|
||||
if (flag_l || flag_v) {
|
||||
// -l or -lv or -lq or -v.
|
||||
|
|
@ -361,7 +365,7 @@ static void ProcessAll(ZipArchiveHandle zah) {
|
|||
die(0, "couldn't iterate %s: %s", archive_name, ErrorCodeString(err));
|
||||
}
|
||||
|
||||
ZipEntry entry;
|
||||
ZipEntry64 entry;
|
||||
std::string name;
|
||||
while ((err = Next(cookie, &entry, &name)) >= 0) {
|
||||
if (ShouldInclude(name)) ProcessOne(zah, entry, name);
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue