summaryrefslogtreecommitdiffstats
path: root/libziparchive/zip_archive.cc
diff options
context:
space:
mode:
Diffstat (limited to 'libziparchive/zip_archive.cc')
-rw-r--r--libziparchive/zip_archive.cc326
1 files changed, 173 insertions, 153 deletions
diff --git a/libziparchive/zip_archive.cc b/libziparchive/zip_archive.cc
index 87dac0e..8582344 100644
--- a/libziparchive/zip_archive.cc
+++ b/libziparchive/zip_archive.cc
@@ -23,29 +23,31 @@
#include <fcntl.h>
#include <inttypes.h>
#include <limits.h>
-#include <log/log.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
-#include <utils/Compat.h>
-#include <utils/FileMap.h>
-#include <zlib.h>
-#include <JNIHelp.h> // TEMP_FAILURE_RETRY may or may not be in unistd
+#include <memory>
+#include <vector>
+#include "base/macros.h" // TEMP_FAILURE_RETRY may or may not be in unistd
+#include "base/memory.h"
+#include "log/log.h"
+#include "utils/Compat.h"
+#include "utils/FileMap.h"
+#include "zlib.h"
+
+#include "entry_name_utils-inl.h"
#include "ziparchive/zip_archive.h"
+using android::base::get_unaligned;
+
// This is for windows. If we don't open a file in binary mode, weird
// things will happen.
#ifndef O_BINARY
#define O_BINARY 0
#endif
-#define DISALLOW_IMPLICIT_CONSTRUCTORS(TypeName) \
- TypeName(); \
- TypeName(const TypeName&); \
- void operator=(const TypeName&)
-
// The "end of central directory" (EOCD) record. Each archive
// contains exactly once such record which appears at the end of
// the archive. It contains archive wide information like the
@@ -193,7 +195,6 @@ struct DataDescriptor {
#undef DISALLOW_IMPLICIT_CONSTRUCTORS
static const uint32_t kGPBDDFlagMask = 0x0008; // mask value that signifies that the entry has a DD
-static const uint32_t kMaxErrorLen = 1024;
// The maximum size of a central directory or a file
// comment in bytes.
@@ -288,10 +289,11 @@ static const char kTempMappingFileName[] = "zip: ExtractFileToFile";
struct ZipArchive {
/* open Zip archive */
const int fd;
+ const bool close_file;
/* mapped central directory area */
off64_t directory_offset;
- android::FileMap* directory_map;
+ android::FileMap directory_map;
/* number of entries in the Zip archive */
uint16_t num_entries;
@@ -305,40 +307,23 @@ struct ZipArchive {
uint32_t hash_table_size;
ZipEntryName* hash_table;
- ZipArchive(const int fd) :
+ ZipArchive(const int fd, bool assume_ownership) :
fd(fd),
+ close_file(assume_ownership),
directory_offset(0),
- directory_map(NULL),
num_entries(0),
hash_table_size(0),
hash_table(NULL) {}
~ZipArchive() {
- if (fd >= 0) {
+ if (close_file && fd >= 0) {
close(fd);
}
- if (directory_map != NULL) {
- directory_map->release();
- }
free(hash_table);
}
};
-// Returns 0 on success and negative values on failure.
-static android::FileMap* MapFileSegment(const int fd, const off64_t start,
- const size_t length, const bool read_only,
- const char* debug_file_name) {
- android::FileMap* file_map = new android::FileMap;
- const bool success = file_map->create(debug_file_name, fd, start, length, read_only);
- if (!success) {
- file_map->release();
- return NULL;
- }
-
- return file_map;
-}
-
static int32_t CopyFileToFile(int fd, uint8_t* begin, const uint32_t length, uint64_t *crc_out) {
static const uint32_t kBufSize = 32768;
uint8_t buf[kBufSize];
@@ -385,8 +370,10 @@ static uint32_t RoundUpPower2(uint32_t val) {
return val;
}
-static uint32_t ComputeHash(const char* str, uint16_t len) {
+static uint32_t ComputeHash(const ZipEntryName& name) {
uint32_t hash = 0;
+ uint16_t len = name.name_length;
+ const uint8_t* str = name.name;
while (len--) {
hash = hash * 31 + *str++;
@@ -401,21 +388,21 @@ static uint32_t ComputeHash(const char* str, uint16_t len) {
*/
static int64_t EntryToIndex(const ZipEntryName* hash_table,
const uint32_t hash_table_size,
- const char* name, uint16_t length) {
- const uint32_t hash = ComputeHash(name, length);
+ const ZipEntryName& name) {
+ const uint32_t hash = ComputeHash(name);
// NOTE: (hash_table_size - 1) is guaranteed to be non-negative.
uint32_t ent = hash & (hash_table_size - 1);
while (hash_table[ent].name != NULL) {
- if (hash_table[ent].name_length == length &&
- memcmp(hash_table[ent].name, name, length) == 0) {
+ if (hash_table[ent].name_length == name.name_length &&
+ memcmp(hash_table[ent].name, name.name, name.name_length) == 0) {
return ent;
}
ent = (ent + 1) & (hash_table_size - 1);
}
- ALOGV("Zip: Unable to find entry %.*s", length, name);
+ ALOGV("Zip: Unable to find entry %.*s", name.name_length, name.name);
return kEntryNotFound;
}
@@ -423,8 +410,8 @@ static int64_t EntryToIndex(const ZipEntryName* hash_table,
* Add a new entry to the hash table.
*/
static int32_t AddToHash(ZipEntryName *hash_table, const uint64_t hash_table_size,
- const char* name, uint16_t length) {
- const uint64_t hash = ComputeHash(name, length);
+ const ZipEntryName& name) {
+ const uint64_t hash = ComputeHash(name);
uint32_t ent = hash & (hash_table_size - 1);
/*
@@ -432,17 +419,17 @@ static int32_t AddToHash(ZipEntryName *hash_table, const uint64_t hash_table_siz
* Further, we guarantee that the hashtable size is not 0.
*/
while (hash_table[ent].name != NULL) {
- if (hash_table[ent].name_length == length &&
- memcmp(hash_table[ent].name, name, length) == 0) {
+ if (hash_table[ent].name_length == name.name_length &&
+ memcmp(hash_table[ent].name, name.name, name.name_length) == 0) {
// We've found a duplicate entry. We don't accept it
- ALOGW("Zip: Found duplicate entry %.*s", length, name);
+ ALOGW("Zip: Found duplicate entry %.*s", name.name_length, name.name);
return kDuplicateEntry;
}
ent = (ent + 1) & (hash_table_size - 1);
}
- hash_table[ent].name = name;
- hash_table[ent].name_length = length;
+ hash_table[ent].name = name.name;
+ hash_table[ent].name_length = name.name_length;
return 0;
}
@@ -472,10 +459,12 @@ static int32_t MapCentralDirectory0(int fd, const char* debug_file_name,
*/
int i = read_amount - sizeof(EocdRecord);
for (; i >= 0; i--) {
- if (scan_buffer[i] == 0x50 &&
- ((*reinterpret_cast<uint32_t*>(&scan_buffer[i])) == EocdRecord::kSignature)) {
- ALOGV("+++ Found EOCD at buf+%d", i);
- break;
+ if (scan_buffer[i] == 0x50) {
+ uint32_t* sig_addr = reinterpret_cast<uint32_t*>(&scan_buffer[i]);
+ if (get_unaligned<uint32_t>(sig_addr) == EocdRecord::kSignature) {
+ ALOGV("+++ Found EOCD at buf+%d", i);
+ break;
+ }
}
}
if (i < 0) {
@@ -518,16 +507,12 @@ static int32_t MapCentralDirectory0(int fd, const char* debug_file_name,
* It all looks good. Create a mapping for the CD, and set the fields
* in archive.
*/
- android::FileMap* map = MapFileSegment(fd,
- static_cast<off64_t>(eocd->cd_start_offset),
- static_cast<size_t>(eocd->cd_size),
- true /* read only */, debug_file_name);
- if (map == NULL) {
- archive->directory_map = NULL;
+ if (!archive->directory_map.create(debug_file_name, fd,
+ static_cast<off64_t>(eocd->cd_start_offset),
+ static_cast<size_t>(eocd->cd_size), true /* read only */) ) {
return kMmapFailed;
}
- archive->directory_map = map;
archive->num_entries = eocd->num_records;
archive->directory_offset = eocd->cd_start_offset;
@@ -554,7 +539,7 @@ static int32_t MapCentralDirectory(int fd, const char* debug_file_name,
return kInvalidFile;
}
- if (file_length > (off64_t) 0xffffffff) {
+ if (file_length > static_cast<off64_t>(0xffffffff)) {
ALOGV("Zip: zip file too long %" PRId64, static_cast<int64_t>(file_length));
return kInvalidFile;
}
@@ -596,9 +581,9 @@ static int32_t MapCentralDirectory(int fd, const char* debug_file_name,
* Returns 0 on success.
*/
static int32_t ParseZipArchive(ZipArchive* archive) {
- int32_t result = -1;
- const uint8_t* const cd_ptr = (const uint8_t*) archive->directory_map->getDataPtr();
- const size_t cd_length = archive->directory_map->getDataLength();
+ const uint8_t* const cd_ptr =
+ reinterpret_cast<const uint8_t*>(archive->directory_map.getDataPtr());
+ const size_t cd_length = archive->directory_map.getDataLength();
const uint16_t num_entries = archive->num_entries;
/*
@@ -607,8 +592,8 @@ static int32_t ParseZipArchive(ZipArchive* archive) {
* least one unused entry to avoid an infinite loop during creation.
*/
archive->hash_table_size = RoundUpPower2(1 + (num_entries * 4) / 3);
- archive->hash_table = (ZipEntryName*) calloc(archive->hash_table_size,
- sizeof(ZipEntryName));
+ archive->hash_table = reinterpret_cast<ZipEntryName*>(calloc(archive->hash_table_size,
+ sizeof(ZipEntryName)));
/*
* Walk through the central directory, adding entries to the hash
@@ -621,53 +606,52 @@ static int32_t ParseZipArchive(ZipArchive* archive) {
reinterpret_cast<const CentralDirectoryRecord*>(ptr);
if (cdr->record_signature != CentralDirectoryRecord::kSignature) {
ALOGW("Zip: missed a central dir sig (at %" PRIu16 ")", i);
- goto bail;
+ return -1;
}
if (ptr + sizeof(CentralDirectoryRecord) > cd_end) {
ALOGW("Zip: ran off the end (at %" PRIu16 ")", i);
- goto bail;
+ return -1;
}
const off64_t local_header_offset = cdr->local_file_header_offset;
if (local_header_offset >= archive->directory_offset) {
- ALOGW("Zip: bad LFH offset %" PRId64 " at entry %" PRIu16, (int64_t)local_header_offset, i);
- goto bail;
+ ALOGW("Zip: bad LFH offset %" PRId64 " at entry %" PRIu16,
+ static_cast<int64_t>(local_header_offset), i);
+ return -1;
}
const uint16_t file_name_length = cdr->file_name_length;
const uint16_t extra_length = cdr->extra_field_length;
const uint16_t comment_length = cdr->comment_length;
- const char* file_name = reinterpret_cast<const char*>(ptr + sizeof(CentralDirectoryRecord));
+ const uint8_t* file_name = ptr + sizeof(CentralDirectoryRecord);
- /* check that file name doesn't contain \0 character */
- if (memchr(file_name, 0, file_name_length) != NULL) {
- ALOGW("Zip: entry name can't contain \\0 character");
- goto bail;
+ /* check that file name is valid UTF-8 and doesn't contain NUL (U+0000) characters */
+ if (!IsValidEntryName(file_name, file_name_length)) {
+ return -1;
}
/* add the CDE filename to the hash table */
+ ZipEntryName entry_name;
+ entry_name.name = file_name;
+ entry_name.name_length = file_name_length;
const int add_result = AddToHash(archive->hash_table,
- archive->hash_table_size, file_name, file_name_length);
- if (add_result) {
+ archive->hash_table_size, entry_name);
+ if (add_result != 0) {
ALOGW("Zip: Error adding entry to hash table %d", add_result);
- result = add_result;
- goto bail;
+ return add_result;
}
ptr += sizeof(CentralDirectoryRecord) + file_name_length + extra_length + comment_length;
if ((ptr - cd_ptr) > static_cast<int64_t>(cd_length)) {
ALOGW("Zip: bad CD advance (%tu vs %zu) at entry %" PRIu16,
ptr - cd_ptr, cd_length, i);
- goto bail;
+ return -1;
}
}
ALOGV("+++ zip good scan %" PRIu16 " entries", num_entries);
- result = 0;
-
-bail:
- return result;
+ return 0;
}
static int32_t OpenArchiveInternal(ZipArchive* archive,
@@ -685,21 +669,22 @@ static int32_t OpenArchiveInternal(ZipArchive* archive,
}
int32_t OpenArchiveFd(int fd, const char* debug_file_name,
- ZipArchiveHandle* handle) {
- ZipArchive* archive = new ZipArchive(fd);
+ ZipArchiveHandle* handle, bool assume_ownership) {
+ ZipArchive* archive = new ZipArchive(fd, assume_ownership);
*handle = archive;
return OpenArchiveInternal(archive, debug_file_name);
}
int32_t OpenArchive(const char* fileName, ZipArchiveHandle* handle) {
const int fd = open(fileName, O_RDONLY | O_BINARY, 0);
- ZipArchive* archive = new ZipArchive(fd);
+ ZipArchive* archive = new ZipArchive(fd, true);
*handle = archive;
if (fd < 0) {
ALOGW("Unable to open '%s': %s", fileName, strerror(errno));
return kIoError;
}
+
return OpenArchiveInternal(archive, fileName);
}
@@ -707,7 +692,7 @@ int32_t OpenArchive(const char* fileName, ZipArchiveHandle* handle) {
* Close a ZipArchive, closing the file and freeing the contents.
*/
void CloseArchive(ZipArchiveHandle handle) {
- ZipArchive* archive = (ZipArchive*) handle;
+ ZipArchive* archive = reinterpret_cast<ZipArchive*>(handle);
ALOGV("Closing archive %p", archive);
delete archive;
}
@@ -739,7 +724,7 @@ static int32_t UpdateEntryFromDataDescriptor(int fd,
// as a side effect of this call.
static inline ssize_t ReadAtOffset(int fd, uint8_t* buf, size_t len,
off64_t off) {
-#ifdef HAVE_PREAD
+#if !defined(_WIN32)
return TEMP_FAILURE_RETRY(pread64(fd, buf, len, off));
#else
// The only supported platform that doesn't support pread at the moment
@@ -751,26 +736,25 @@ static inline ssize_t ReadAtOffset(int fd, uint8_t* buf, size_t len,
}
return TEMP_FAILURE_RETRY(read(fd, buf, len));
-#endif // HAVE_PREAD
+#endif
}
static int32_t FindEntry(const ZipArchive* archive, const int ent,
ZipEntry* data) {
const uint16_t nameLen = archive->hash_table[ent].name_length;
- const char* name = archive->hash_table[ent].name;
// 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.
- const uint8_t* ptr = reinterpret_cast<const uint8_t*>(name);
+ const uint8_t* ptr = archive->hash_table[ent].name;
ptr -= sizeof(CentralDirectoryRecord);
// This is the base of our mmapped region, we have to sanity check that
// the name that's in the hash table is a pointer to a location within
// this mapped region.
const uint8_t* base_ptr = reinterpret_cast<const uint8_t*>(
- archive->directory_map->getDataPtr());
- if (ptr < base_ptr || ptr > base_ptr + archive->directory_map->getDataLength()) {
+ archive->directory_map.getDataPtr());
+ if (ptr < base_ptr || ptr > base_ptr + archive->directory_map.getDataLength()) {
ALOGW("Zip: Invalid entry pointer");
return kInvalidOffset;
}
@@ -805,7 +789,8 @@ static int32_t FindEntry(const ZipArchive* archive, const int ent,
ssize_t actual = ReadAtOffset(archive->fd, lfh_buf, sizeof(lfh_buf),
local_header_offset);
if (actual != sizeof(lfh_buf)) {
- ALOGW("Zip: failed reading lfh name from offset %" PRId64, (int64_t)local_header_offset);
+ ALOGW("Zip: failed reading lfh name from offset %" PRId64,
+ static_cast<int64_t>(local_header_offset));
return kIoError;
}
@@ -838,22 +823,22 @@ static int32_t FindEntry(const ZipArchive* archive, const int ent,
// name in the central directory.
if (lfh->file_name_length == nameLen) {
const off64_t name_offset = local_header_offset + sizeof(LocalFileHeader);
- if (name_offset + lfh->file_name_length >= cd_offset) {
+ if (name_offset + lfh->file_name_length > cd_offset) {
ALOGW("Zip: Invalid declared length");
return kInvalidOffset;
}
- uint8_t* name_buf = (uint8_t*) malloc(nameLen);
+ uint8_t* name_buf = reinterpret_cast<uint8_t*>(malloc(nameLen));
ssize_t actual = ReadAtOffset(archive->fd, name_buf, nameLen,
name_offset);
if (actual != nameLen) {
- ALOGW("Zip: failed reading lfh name from offset %" PRId64, (int64_t)name_offset);
+ ALOGW("Zip: failed reading lfh name from offset %" PRId64, static_cast<int64_t>(name_offset));
free(name_buf);
return kIoError;
}
- if (memcmp(name, name_buf, nameLen)) {
+ if (memcmp(archive->hash_table[ent].name, name_buf, nameLen)) {
free(name_buf);
return kInconsistentInformation;
}
@@ -867,20 +852,21 @@ static int32_t FindEntry(const ZipArchive* archive, const int ent,
const off64_t data_offset = local_header_offset + sizeof(LocalFileHeader)
+ lfh->file_name_length + lfh->extra_field_length;
if (data_offset > cd_offset) {
- ALOGW("Zip: bad data offset %" PRId64 " in zip", (int64_t)data_offset);
+ ALOGW("Zip: bad data offset %" PRId64 " in zip", static_cast<int64_t>(data_offset));
return kInvalidOffset;
}
- if ((off64_t)(data_offset + data->compressed_length) > cd_offset) {
+ if (static_cast<off64_t>(data_offset + data->compressed_length) > cd_offset) {
ALOGW("Zip: bad compressed length in zip (%" PRId64 " + %" PRIu32 " > %" PRId64 ")",
- (int64_t)data_offset, data->compressed_length, (int64_t)cd_offset);
+ static_cast<int64_t>(data_offset), data->compressed_length, static_cast<int64_t>(cd_offset));
return kInvalidOffset;
}
if (data->method == kCompressStored &&
- (off64_t)(data_offset + data->uncompressed_length) > cd_offset) {
+ static_cast<off64_t>(data_offset + data->uncompressed_length) > cd_offset) {
ALOGW("Zip: bad uncompressed length in zip (%" PRId64 " + %" PRIu32 " > %" PRId64 ")",
- (int64_t)data_offset, data->uncompressed_length, (int64_t)cd_offset);
+ static_cast<int64_t>(data_offset), data->uncompressed_length,
+ static_cast<int64_t>(cd_offset));
return kInvalidOffset;
}
@@ -890,45 +876,61 @@ static int32_t FindEntry(const ZipArchive* archive, const int ent,
struct IterationHandle {
uint32_t position;
- const char* prefix;
+ // We're not using vector here because this code is used in the Windows SDK
+ // where the STL is not available.
+ const uint8_t* prefix;
uint16_t prefix_len;
ZipArchive* archive;
+
+ IterationHandle() : prefix(NULL), prefix_len(0) {}
+
+ IterationHandle(const ZipEntryName& prefix_name)
+ : prefix_len(prefix_name.name_length) {
+ uint8_t* prefix_copy = new uint8_t[prefix_len];
+ memcpy(prefix_copy, prefix_name.name, prefix_len);
+ prefix = prefix_copy;
+ }
+
+ ~IterationHandle() {
+ delete[] prefix;
+ }
};
-int32_t StartIteration(ZipArchiveHandle handle, void** cookie_ptr, const char* prefix) {
- ZipArchive* archive = (ZipArchive *) handle;
+int32_t StartIteration(ZipArchiveHandle handle, void** cookie_ptr,
+ const ZipEntryName* optional_prefix) {
+ ZipArchive* archive = reinterpret_cast<ZipArchive*>(handle);
if (archive == NULL || archive->hash_table == NULL) {
ALOGW("Zip: Invalid ZipArchiveHandle");
return kInvalidHandle;
}
- IterationHandle* cookie = (IterationHandle*) malloc(sizeof(IterationHandle));
+ IterationHandle* cookie =
+ optional_prefix != NULL ? new IterationHandle(*optional_prefix) : new IterationHandle();
cookie->position = 0;
- cookie->prefix = prefix;
cookie->archive = archive;
- if (prefix != NULL) {
- cookie->prefix_len = strlen(prefix);
- }
*cookie_ptr = cookie ;
return 0;
}
-int32_t FindEntry(const ZipArchiveHandle handle, const char* entryName,
+void EndIteration(void* cookie) {
+ delete reinterpret_cast<IterationHandle*>(cookie);
+}
+
+int32_t FindEntry(const ZipArchiveHandle handle, const ZipEntryName& entryName,
ZipEntry* data) {
- const ZipArchive* archive = (ZipArchive*) handle;
- const int nameLen = strlen(entryName);
- if (nameLen == 0 || nameLen > 65535) {
- ALOGW("Zip: Invalid filename %s", entryName);
+ const ZipArchive* archive = reinterpret_cast<ZipArchive*>(handle);
+ if (entryName.name_length == 0) {
+ ALOGW("Zip: Invalid filename %.*s", entryName.name_length, entryName.name);
return kInvalidEntryName;
}
const int64_t ent = EntryToIndex(archive->hash_table,
- archive->hash_table_size, entryName, nameLen);
+ archive->hash_table_size, entryName);
if (ent < 0) {
- ALOGV("Zip: Could not find entry %.*s", nameLen, entryName);
+ ALOGV("Zip: Could not find entry %.*s", entryName.name_length, entryName.name);
return ent;
}
@@ -936,7 +938,7 @@ int32_t FindEntry(const ZipArchiveHandle handle, const char* entryName,
}
int32_t Next(void* cookie, ZipEntry* data, ZipEntryName* name) {
- IterationHandle* handle = (IterationHandle *) cookie;
+ IterationHandle* handle = reinterpret_cast<IterationHandle*>(cookie);
if (handle == NULL) {
return kInvalidHandle;
}
@@ -953,7 +955,7 @@ int32_t Next(void* cookie, ZipEntry* data, ZipEntryName* name) {
for (uint32_t i = currentOffset; i < hash_table_length; ++i) {
if (hash_table[i].name != NULL &&
- (handle->prefix == NULL ||
+ (handle->prefix_len == 0 ||
(memcmp(handle->prefix, hash_table[i].name, handle->prefix_len) == 0))) {
handle->position = (i + 1);
const int error = FindEntry(archive, i, data);
@@ -970,13 +972,20 @@ int32_t Next(void* cookie, ZipEntry* data, ZipEntryName* name) {
return kIterationEnd;
}
+// This method is using libz macros with old-style-casts
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wold-style-cast"
+static inline int zlib_inflateInit2(z_stream* stream, int window_bits) {
+ return inflateInit2(stream, window_bits);
+}
+#pragma GCC diagnostic pop
+
static int32_t InflateToFile(int fd, const ZipEntry* entry,
uint8_t* begin, uint32_t length,
uint64_t* crc_out) {
- int32_t result = -1;
- const uint32_t kBufSize = 32768;
- uint8_t read_buf[kBufSize];
- uint8_t write_buf[kBufSize];
+ const size_t kBufSize = 32768;
+ std::vector<uint8_t> read_buf(kBufSize);
+ std::vector<uint8_t> write_buf(kBufSize);
z_stream zstream;
int zerr;
@@ -989,7 +998,7 @@ static int32_t InflateToFile(int fd, const ZipEntry* entry,
zstream.opaque = Z_NULL;
zstream.next_in = NULL;
zstream.avail_in = 0;
- zstream.next_out = (Bytef*) write_buf;
+ zstream.next_out = &write_buf[0];
zstream.avail_out = kBufSize;
zstream.data_type = Z_UNKNOWN;
@@ -997,7 +1006,7 @@ static int32_t InflateToFile(int fd, const ZipEntry* entry,
* Use the undocumented "negative window bits" feature to tell zlib
* that there's no zlib header waiting for it.
*/
- zerr = inflateInit2(&zstream, -MAX_WBITS);
+ zerr = zlib_inflateInit2(&zstream, -MAX_WBITS);
if (zerr != Z_OK) {
if (zerr == Z_VERSION_ERROR) {
ALOGE("Installed zlib is not compatible with linked version (%s)",
@@ -1009,6 +1018,12 @@ static int32_t InflateToFile(int fd, const ZipEntry* entry,
return kZlibError;
}
+ auto zstream_deleter = [](z_stream* stream) {
+ inflateEnd(stream); /* free up any allocated structures */
+ };
+
+ std::unique_ptr<z_stream, decltype(zstream_deleter)> zstream_guard(&zstream, zstream_deleter);
+
const uint32_t uncompressed_length = entry->uncompressed_length;
uint32_t compressed_length = entry->compressed_length;
@@ -1017,16 +1032,15 @@ static int32_t InflateToFile(int fd, const ZipEntry* entry,
/* read as much as we can */
if (zstream.avail_in == 0) {
const ZD_TYPE getSize = (compressed_length > kBufSize) ? kBufSize : compressed_length;
- const ZD_TYPE actual = TEMP_FAILURE_RETRY(read(fd, read_buf, getSize));
+ const ZD_TYPE actual = TEMP_FAILURE_RETRY(read(fd, &read_buf[0], getSize));
if (actual != getSize) {
ALOGW("Zip: inflate read failed (" ZD " vs " ZD ")", actual, getSize);
- result = kIoError;
- goto z_bail;
+ return kIoError;
}
compressed_length -= getSize;
- zstream.next_in = read_buf;
+ zstream.next_in = &read_buf[0];
zstream.avail_in = getSize;
}
@@ -1036,22 +1050,21 @@ static int32_t InflateToFile(int fd, const ZipEntry* entry,
ALOGW("Zip: inflate zerr=%d (nIn=%p aIn=%u nOut=%p aOut=%u)",
zerr, zstream.next_in, zstream.avail_in,
zstream.next_out, zstream.avail_out);
- result = kZlibError;
- goto z_bail;
+ return kZlibError;
}
/* write when we're full or when we're done */
if (zstream.avail_out == 0 ||
(zerr == Z_STREAM_END && zstream.avail_out != kBufSize)) {
- const size_t write_size = zstream.next_out - write_buf;
+ const size_t write_size = zstream.next_out - &write_buf[0];
// The file might have declared a bogus length.
if (write_size + write_count > length) {
- goto z_bail;
+ return -1;
}
- memcpy(begin + write_count, write_buf, write_size);
+ memcpy(begin + write_count, &write_buf[0], write_size);
write_count += write_size;
- zstream.next_out = write_buf;
+ zstream.next_out = &write_buf[0];
zstream.avail_out = kBufSize;
}
} while (zerr == Z_OK);
@@ -1064,26 +1077,20 @@ static int32_t InflateToFile(int fd, const ZipEntry* entry,
if (zstream.total_out != uncompressed_length || compressed_length != 0) {
ALOGW("Zip: size mismatch on inflated file (%lu vs %" PRIu32 ")",
zstream.total_out, uncompressed_length);
- result = kInconsistentInformation;
- goto z_bail;
+ return kInconsistentInformation;
}
- result = 0;
-
-z_bail:
- inflateEnd(&zstream); /* free up any allocated structures */
-
- return result;
+ return 0;
}
int32_t ExtractToMemory(ZipArchiveHandle handle,
ZipEntry* entry, uint8_t* begin, uint32_t size) {
- ZipArchive* archive = (ZipArchive*) handle;
+ ZipArchive* archive = reinterpret_cast<ZipArchive*>(handle);
const uint16_t method = entry->method;
off64_t data_offset = entry->offset;
if (lseek64(archive->fd, data_offset, SEEK_SET) != data_offset) {
- ALOGW("Zip: lseek to data at %" PRId64 " failed", (int64_t)data_offset);
+ ALOGW("Zip: lseek to data at %" PRId64 " failed", static_cast<int64_t>(data_offset));
return kIoError;
}
@@ -1115,7 +1122,7 @@ int32_t ExtractToMemory(ZipArchiveHandle handle,
int32_t ExtractEntryToFile(ZipArchiveHandle handle,
ZipEntry* entry, int fd) {
- const int32_t declared_length = entry->uncompressed_length;
+ const uint32_t declared_length = entry->uncompressed_length;
const off64_t current_offset = lseek64(fd, 0, SEEK_CUR);
if (current_offset == -1) {
@@ -1124,10 +1131,25 @@ int32_t ExtractEntryToFile(ZipArchiveHandle handle,
return kIoError;
}
- int result = TEMP_FAILURE_RETRY(ftruncate(fd, declared_length + current_offset));
+ int result = 0;
+#if defined(__linux__)
+ // Make sure we have enough space on the volume to extract the compressed
+ // entry. Note that the call to ftruncate below will change the file size but
+ // will not allocate space on disk.
+ if (declared_length > 0) {
+ result = TEMP_FAILURE_RETRY(fallocate(fd, 0, current_offset, declared_length));
+ if (result == -1) {
+ ALOGW("Zip: unable to allocate space for file to %" PRId64 ": %s",
+ static_cast<int64_t>(declared_length + current_offset), strerror(errno));
+ return kIoError;
+ }
+ }
+#endif // defined(__linux__)
+
+ result = TEMP_FAILURE_RETRY(ftruncate(fd, declared_length + current_offset));
if (result == -1) {
ALOGW("Zip: unable to truncate file to %" PRId64 ": %s",
- (int64_t)(declared_length + current_offset), strerror(errno));
+ static_cast<int64_t>(declared_length + current_offset), strerror(errno));
return kIoError;
}
@@ -1138,16 +1160,14 @@ int32_t ExtractEntryToFile(ZipArchiveHandle handle,
return 0;
}
- android::FileMap* map = MapFileSegment(fd, current_offset, declared_length,
- false, kTempMappingFileName);
- if (map == NULL) {
+ android::FileMap map;
+ if (!map.create(kTempMappingFileName, fd, current_offset, declared_length, false)) {
return kMmapFailed;
}
const int32_t error = ExtractToMemory(handle, entry,
- reinterpret_cast<uint8_t*>(map->getDataPtr()),
- map->getDataLength());
- map->release();
+ reinterpret_cast<uint8_t*>(map.getDataPtr()),
+ map.getDataLength());
return error;
}
@@ -1160,6 +1180,6 @@ const char* ErrorCodeString(int32_t error_code) {
}
int GetFileDescriptor(const ZipArchiveHandle handle) {
- return ((ZipArchive*) handle)->fd;
+ return reinterpret_cast<ZipArchive*>(handle)->fd;
}