Merge "Add functions in recovery/minzip to libziparchive" am: 4bc51d1ea4
am: b2ca85184b
Change-Id: Iabe3e2e2f02e3d6f6325c929684e64db09063c1f
This commit is contained in:
commit
34486c5d2b
6 changed files with 321 additions and 79 deletions
|
|
@ -130,6 +130,8 @@ int32_t OpenArchive(const char* fileName, ZipArchiveHandle* handle);
|
||||||
int32_t OpenArchiveFd(const int fd, const char* debugFileName,
|
int32_t OpenArchiveFd(const int fd, const char* debugFileName,
|
||||||
ZipArchiveHandle *handle, bool assume_ownership = true);
|
ZipArchiveHandle *handle, bool assume_ownership = true);
|
||||||
|
|
||||||
|
int32_t OpenArchiveFromMemory(void* address, size_t length, const char* debugFileName,
|
||||||
|
ZipArchiveHandle *handle);
|
||||||
/*
|
/*
|
||||||
* Close archive, releasing resources associated with it. This will
|
* Close archive, releasing resources associated with it. This will
|
||||||
* unmap the central directory of the zipfile and free all internal
|
* unmap the central directory of the zipfile and free all internal
|
||||||
|
|
@ -214,6 +216,17 @@ int GetFileDescriptor(const ZipArchiveHandle handle);
|
||||||
|
|
||||||
const char* ErrorCodeString(int32_t error_code);
|
const char* ErrorCodeString(int32_t error_code);
|
||||||
|
|
||||||
|
#if !defined(_WIN32)
|
||||||
|
typedef bool (*ProcessZipEntryFunction)(const uint8_t* buf, size_t buf_size, void* cookie);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Stream the uncompressed data through the supplied function,
|
||||||
|
* passing cookie to it each time it gets called.
|
||||||
|
*/
|
||||||
|
int32_t ProcessZipEntryContents(ZipArchiveHandle handle, ZipEntry* entry,
|
||||||
|
ProcessZipEntryFunction func, void* cookie);
|
||||||
|
#endif
|
||||||
|
|
||||||
__END_DECLS
|
__END_DECLS
|
||||||
|
|
||||||
#endif // LIBZIPARCHIVE_ZIPARCHIVE_H_
|
#endif // LIBZIPARCHIVE_ZIPARCHIVE_H_
|
||||||
|
|
|
||||||
BIN
libziparchive/testdata/dummy-update.zip
vendored
Normal file
BIN
libziparchive/testdata/dummy-update.zip
vendored
Normal file
Binary file not shown.
|
|
@ -215,19 +215,14 @@ static int32_t AddToHash(ZipString *hash_table, const uint64_t hash_table_size,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int32_t MapCentralDirectory0(int fd, const char* debug_file_name,
|
static int32_t MapCentralDirectory0(const char* debug_file_name, ZipArchive* archive,
|
||||||
ZipArchive* archive, off64_t file_length,
|
off64_t file_length, off64_t read_amount,
|
||||||
off64_t read_amount, uint8_t* scan_buffer) {
|
uint8_t* scan_buffer) {
|
||||||
const off64_t search_start = file_length - read_amount;
|
const off64_t search_start = file_length - read_amount;
|
||||||
|
|
||||||
if (lseek64(fd, search_start, SEEK_SET) != search_start) {
|
if(!archive->mapped_zip.ReadAtOffset(scan_buffer, read_amount, search_start)) {
|
||||||
ALOGW("Zip: seek %" PRId64 " failed: %s", static_cast<int64_t>(search_start),
|
ALOGE("Zip: read %" PRId64 " from offset %" PRId64 " failed",
|
||||||
strerror(errno));
|
static_cast<int64_t>(read_amount), static_cast<int64_t>(search_start));
|
||||||
return kIoError;
|
|
||||||
}
|
|
||||||
if (!android::base::ReadFully(fd, scan_buffer, static_cast<size_t>(read_amount))) {
|
|
||||||
ALOGW("Zip: read %" PRId64 " failed: %s", static_cast<int64_t>(read_amount),
|
|
||||||
strerror(errno));
|
|
||||||
return kIoError;
|
return kIoError;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -292,9 +287,11 @@ 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
|
* It all looks good. Create a mapping for the CD, and set the fields
|
||||||
* in archive.
|
* in archive.
|
||||||
*/
|
*/
|
||||||
if (!archive->directory_map.create(debug_file_name, fd,
|
|
||||||
static_cast<off64_t>(eocd->cd_start_offset),
|
if (!archive->InitializeCentralDirectory(debug_file_name,
|
||||||
static_cast<size_t>(eocd->cd_size), true /* read only */) ) {
|
static_cast<off64_t>(eocd->cd_start_offset),
|
||||||
|
static_cast<size_t>(eocd->cd_size))) {
|
||||||
|
ALOGE("Zip: failed to intialize central directory.\n");
|
||||||
return kMmapFailed;
|
return kMmapFailed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -309,18 +306,16 @@ static int32_t MapCentralDirectory0(int fd, const char* debug_file_name,
|
||||||
*
|
*
|
||||||
* On success, returns 0 after populating fields from the EOCD area:
|
* On success, returns 0 after populating fields from the EOCD area:
|
||||||
* directory_offset
|
* directory_offset
|
||||||
* directory_map
|
* directory_ptr
|
||||||
* num_entries
|
* num_entries
|
||||||
*/
|
*/
|
||||||
static int32_t MapCentralDirectory(int fd, const char* debug_file_name,
|
static int32_t MapCentralDirectory(const char* debug_file_name, ZipArchive* archive) {
|
||||||
ZipArchive* archive) {
|
|
||||||
|
|
||||||
// Test file length. We use lseek64 to make sure the file
|
// Test file length. We use lseek64 to make sure the file
|
||||||
// is small enough to be a zip file (Its size must be less than
|
// is small enough to be a zip file (Its size must be less than
|
||||||
// 0xffffffff bytes).
|
// 0xffffffff bytes).
|
||||||
off64_t file_length = lseek64(fd, 0, SEEK_END);
|
off64_t file_length = archive->mapped_zip.GetFileLength();
|
||||||
if (file_length == -1) {
|
if (file_length == -1) {
|
||||||
ALOGV("Zip: lseek on fd %d failed", fd);
|
|
||||||
return kInvalidFile;
|
return kInvalidFile;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -351,11 +346,9 @@ static int32_t MapCentralDirectory(int fd, const char* debug_file_name,
|
||||||
read_amount = file_length;
|
read_amount = file_length;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t* scan_buffer = reinterpret_cast<uint8_t*>(malloc(read_amount));
|
std::vector<uint8_t> scan_buffer(read_amount);
|
||||||
int32_t result = MapCentralDirectory0(fd, debug_file_name, archive,
|
int32_t result = MapCentralDirectory0(debug_file_name, archive, file_length, read_amount,
|
||||||
file_length, read_amount, scan_buffer);
|
scan_buffer.data());
|
||||||
|
|
||||||
free(scan_buffer);
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -366,9 +359,8 @@ static int32_t MapCentralDirectory(int fd, const char* debug_file_name,
|
||||||
* Returns 0 on success.
|
* Returns 0 on success.
|
||||||
*/
|
*/
|
||||||
static int32_t ParseZipArchive(ZipArchive* archive) {
|
static int32_t ParseZipArchive(ZipArchive* archive) {
|
||||||
const uint8_t* const cd_ptr =
|
const uint8_t* const cd_ptr = archive->central_directory.GetBasePtr();
|
||||||
reinterpret_cast<const uint8_t*>(archive->directory_map.getDataPtr());
|
const size_t cd_length = archive->central_directory.GetMapLength();
|
||||||
const size_t cd_length = archive->directory_map.getDataLength();
|
|
||||||
const uint16_t num_entries = archive->num_entries;
|
const uint16_t num_entries = archive->num_entries;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -442,7 +434,7 @@ static int32_t ParseZipArchive(ZipArchive* archive) {
|
||||||
static int32_t OpenArchiveInternal(ZipArchive* archive,
|
static int32_t OpenArchiveInternal(ZipArchive* archive,
|
||||||
const char* debug_file_name) {
|
const char* debug_file_name) {
|
||||||
int32_t result = -1;
|
int32_t result = -1;
|
||||||
if ((result = MapCentralDirectory(archive->fd, debug_file_name, archive))) {
|
if ((result = MapCentralDirectory(debug_file_name, archive)) != 0) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -473,6 +465,13 @@ int32_t OpenArchive(const char* fileName, ZipArchiveHandle* handle) {
|
||||||
return OpenArchiveInternal(archive, fileName);
|
return OpenArchiveInternal(archive, fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int32_t OpenArchiveFromMemory(void* address, size_t length, const char* debug_file_name,
|
||||||
|
ZipArchiveHandle *handle) {
|
||||||
|
ZipArchive* archive = new ZipArchive(address, length);
|
||||||
|
*handle = archive;
|
||||||
|
return OpenArchiveInternal(archive, debug_file_name);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Close a ZipArchive, closing the file and freeing the contents.
|
* Close a ZipArchive, closing the file and freeing the contents.
|
||||||
*/
|
*/
|
||||||
|
|
@ -482,10 +481,10 @@ void CloseArchive(ZipArchiveHandle handle) {
|
||||||
delete archive;
|
delete archive;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int32_t UpdateEntryFromDataDescriptor(int fd,
|
static int32_t UpdateEntryFromDataDescriptor(MappedZipFile& mapped_zip,
|
||||||
ZipEntry *entry) {
|
ZipEntry *entry) {
|
||||||
uint8_t ddBuf[sizeof(DataDescriptor) + sizeof(DataDescriptor::kOptSignature)];
|
uint8_t ddBuf[sizeof(DataDescriptor) + sizeof(DataDescriptor::kOptSignature)];
|
||||||
if (!android::base::ReadFully(fd, ddBuf, sizeof(ddBuf))) {
|
if (!mapped_zip.ReadData(ddBuf, sizeof(ddBuf))) {
|
||||||
return kIoError;
|
return kIoError;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -500,23 +499,6 @@ static int32_t UpdateEntryFromDataDescriptor(int fd,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Attempts to read |len| bytes into |buf| at offset |off|.
|
|
||||||
// On non-Windows platforms, callers are guaranteed that the |fd|
|
|
||||||
// offset is unchanged and there is no side effect to this call.
|
|
||||||
//
|
|
||||||
// On Windows platforms this is not thread-safe.
|
|
||||||
static inline bool ReadAtOffset(int fd, uint8_t* buf, size_t len, off64_t off) {
|
|
||||||
#if !defined(_WIN32)
|
|
||||||
return TEMP_FAILURE_RETRY(pread64(fd, buf, len, off));
|
|
||||||
#else
|
|
||||||
if (lseek64(fd, off, SEEK_SET) != off) {
|
|
||||||
ALOGW("Zip: failed seek to offset %" PRId64, off);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return android::base::ReadFully(fd, buf, len);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
static int32_t FindEntry(const ZipArchive* archive, const int ent,
|
static int32_t FindEntry(const ZipArchive* archive, const int ent,
|
||||||
ZipEntry* data) {
|
ZipEntry* data) {
|
||||||
const uint16_t nameLen = archive->hash_table[ent].name_length;
|
const uint16_t nameLen = archive->hash_table[ent].name_length;
|
||||||
|
|
@ -530,9 +512,8 @@ static int32_t FindEntry(const ZipArchive* archive, const int ent,
|
||||||
// This is the base of our mmapped region, we have to sanity check that
|
// 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
|
// the name that's in the hash table is a pointer to a location within
|
||||||
// this mapped region.
|
// this mapped region.
|
||||||
const uint8_t* base_ptr = reinterpret_cast<const uint8_t*>(
|
const uint8_t* base_ptr = archive->central_directory.GetBasePtr();
|
||||||
archive->directory_map.getDataPtr());
|
if (ptr < base_ptr || ptr > base_ptr + archive->central_directory.GetMapLength()) {
|
||||||
if (ptr < base_ptr || ptr > base_ptr + archive->directory_map.getDataLength()) {
|
|
||||||
ALOGW("Zip: Invalid entry pointer");
|
ALOGW("Zip: Invalid entry pointer");
|
||||||
return kInvalidOffset;
|
return kInvalidOffset;
|
||||||
}
|
}
|
||||||
|
|
@ -564,7 +545,7 @@ static int32_t FindEntry(const ZipArchive* archive, const int ent,
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t lfh_buf[sizeof(LocalFileHeader)];
|
uint8_t lfh_buf[sizeof(LocalFileHeader)];
|
||||||
if (!ReadAtOffset(archive->fd, lfh_buf, sizeof(lfh_buf), local_header_offset)) {
|
if (!archive->mapped_zip.ReadAtOffset(lfh_buf, sizeof(lfh_buf), local_header_offset)) {
|
||||||
ALOGW("Zip: failed reading lfh name from offset %" PRId64,
|
ALOGW("Zip: failed reading lfh name from offset %" PRId64,
|
||||||
static_cast<int64_t>(local_header_offset));
|
static_cast<int64_t>(local_header_offset));
|
||||||
return kIoError;
|
return kIoError;
|
||||||
|
|
@ -604,19 +585,16 @@ static int32_t FindEntry(const ZipArchive* archive, const int ent,
|
||||||
return kInvalidOffset;
|
return kInvalidOffset;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t* name_buf = reinterpret_cast<uint8_t*>(malloc(nameLen));
|
std::vector<uint8_t> name_buf(nameLen);
|
||||||
if (!ReadAtOffset(archive->fd, name_buf, nameLen, name_offset)) {
|
if (!archive->mapped_zip.ReadAtOffset(name_buf.data(), nameLen, name_offset)) {
|
||||||
ALOGW("Zip: failed reading lfh name from offset %" PRId64, static_cast<int64_t>(name_offset));
|
ALOGW("Zip: failed reading lfh name from offset %" PRId64, static_cast<int64_t>(name_offset));
|
||||||
free(name_buf);
|
|
||||||
return kIoError;
|
return kIoError;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (memcmp(archive->hash_table[ent].name, name_buf, nameLen)) {
|
if (memcmp(archive->hash_table[ent].name, name_buf.data(), nameLen)) {
|
||||||
free(name_buf);
|
|
||||||
return kInconsistentInformation;
|
return kInconsistentInformation;
|
||||||
}
|
}
|
||||||
|
|
||||||
free(name_buf);
|
|
||||||
} else {
|
} else {
|
||||||
ALOGW("Zip: lfh name did not match central directory.");
|
ALOGW("Zip: lfh name did not match central directory.");
|
||||||
return kInconsistentInformation;
|
return kInconsistentInformation;
|
||||||
|
|
@ -886,7 +864,7 @@ static inline int zlib_inflateInit2(z_stream* stream, int window_bits) {
|
||||||
}
|
}
|
||||||
#pragma GCC diagnostic pop
|
#pragma GCC diagnostic pop
|
||||||
|
|
||||||
static int32_t InflateEntryToWriter(int fd, const ZipEntry* entry,
|
static int32_t InflateEntryToWriter(MappedZipFile& mapped_zip, const ZipEntry* entry,
|
||||||
Writer* writer, uint64_t* crc_out) {
|
Writer* writer, uint64_t* crc_out) {
|
||||||
const size_t kBufSize = 32768;
|
const size_t kBufSize = 32768;
|
||||||
std::vector<uint8_t> read_buf(kBufSize);
|
std::vector<uint8_t> read_buf(kBufSize);
|
||||||
|
|
@ -936,7 +914,7 @@ static int32_t InflateEntryToWriter(int fd, const ZipEntry* entry,
|
||||||
/* read as much as we can */
|
/* read as much as we can */
|
||||||
if (zstream.avail_in == 0) {
|
if (zstream.avail_in == 0) {
|
||||||
const size_t getSize = (compressed_length > kBufSize) ? kBufSize : compressed_length;
|
const size_t getSize = (compressed_length > kBufSize) ? kBufSize : compressed_length;
|
||||||
if (!android::base::ReadFully(fd, read_buf.data(), getSize)) {
|
if (!mapped_zip.ReadData(read_buf.data(), getSize)) {
|
||||||
ALOGW("Zip: inflate read failed, getSize = %zu: %s", getSize, strerror(errno));
|
ALOGW("Zip: inflate read failed, getSize = %zu: %s", getSize, strerror(errno));
|
||||||
return kIoError;
|
return kIoError;
|
||||||
}
|
}
|
||||||
|
|
@ -984,7 +962,7 @@ static int32_t InflateEntryToWriter(int fd, const ZipEntry* entry,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int32_t CopyEntryToWriter(int fd, const ZipEntry* entry, Writer* writer,
|
static int32_t CopyEntryToWriter(MappedZipFile& mapped_zip, const ZipEntry* entry, Writer* writer,
|
||||||
uint64_t *crc_out) {
|
uint64_t *crc_out) {
|
||||||
static const uint32_t kBufSize = 32768;
|
static const uint32_t kBufSize = 32768;
|
||||||
std::vector<uint8_t> buf(kBufSize);
|
std::vector<uint8_t> buf(kBufSize);
|
||||||
|
|
@ -998,7 +976,7 @@ static int32_t CopyEntryToWriter(int fd, const ZipEntry* entry, Writer* writer,
|
||||||
// Safe conversion because kBufSize is narrow enough for a 32 bit signed
|
// Safe conversion because kBufSize is narrow enough for a 32 bit signed
|
||||||
// value.
|
// value.
|
||||||
const size_t block_size = (remaining > kBufSize) ? kBufSize : remaining;
|
const size_t block_size = (remaining > kBufSize) ? kBufSize : remaining;
|
||||||
if (!android::base::ReadFully(fd, buf.data(), block_size)) {
|
if (!mapped_zip.ReadData(buf.data(), block_size)) {
|
||||||
ALOGW("CopyFileToFile: copy read failed, block_size = %zu: %s", block_size, strerror(errno));
|
ALOGW("CopyFileToFile: copy read failed, block_size = %zu: %s", block_size, strerror(errno));
|
||||||
return kIoError;
|
return kIoError;
|
||||||
}
|
}
|
||||||
|
|
@ -1021,7 +999,7 @@ int32_t ExtractToWriter(ZipArchiveHandle handle,
|
||||||
const uint16_t method = entry->method;
|
const uint16_t method = entry->method;
|
||||||
off64_t data_offset = entry->offset;
|
off64_t data_offset = entry->offset;
|
||||||
|
|
||||||
if (lseek64(archive->fd, data_offset, SEEK_SET) != data_offset) {
|
if (!archive->mapped_zip.SeekToOffset(data_offset)) {
|
||||||
ALOGW("Zip: lseek to data at %" PRId64 " failed", static_cast<int64_t>(data_offset));
|
ALOGW("Zip: lseek to data at %" PRId64 " failed", static_cast<int64_t>(data_offset));
|
||||||
return kIoError;
|
return kIoError;
|
||||||
}
|
}
|
||||||
|
|
@ -1030,13 +1008,13 @@ int32_t ExtractToWriter(ZipArchiveHandle handle,
|
||||||
int32_t return_value = -1;
|
int32_t return_value = -1;
|
||||||
uint64_t crc = 0;
|
uint64_t crc = 0;
|
||||||
if (method == kCompressStored) {
|
if (method == kCompressStored) {
|
||||||
return_value = CopyEntryToWriter(archive->fd, entry, writer, &crc);
|
return_value = CopyEntryToWriter(archive->mapped_zip, entry, writer, &crc);
|
||||||
} else if (method == kCompressDeflated) {
|
} else if (method == kCompressDeflated) {
|
||||||
return_value = InflateEntryToWriter(archive->fd, entry, writer, &crc);
|
return_value = InflateEntryToWriter(archive->mapped_zip, entry, writer, &crc);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!return_value && entry->has_data_descriptor) {
|
if (!return_value && entry->has_data_descriptor) {
|
||||||
return_value = UpdateEntryFromDataDescriptor(archive->fd, entry);
|
return_value = UpdateEntryFromDataDescriptor(archive->mapped_zip, entry);
|
||||||
if (return_value) {
|
if (return_value) {
|
||||||
return return_value;
|
return return_value;
|
||||||
}
|
}
|
||||||
|
|
@ -1077,7 +1055,7 @@ const char* ErrorCodeString(int32_t error_code) {
|
||||||
}
|
}
|
||||||
|
|
||||||
int GetFileDescriptor(const ZipArchiveHandle handle) {
|
int GetFileDescriptor(const ZipArchiveHandle handle) {
|
||||||
return reinterpret_cast<ZipArchive*>(handle)->fd;
|
return reinterpret_cast<ZipArchive*>(handle)->mapped_zip.GetFileDescriptor();
|
||||||
}
|
}
|
||||||
|
|
||||||
ZipString::ZipString(const char* entry_name)
|
ZipString::ZipString(const char* entry_name)
|
||||||
|
|
@ -1086,3 +1064,143 @@ ZipString::ZipString(const char* entry_name)
|
||||||
CHECK_LE(len, static_cast<size_t>(UINT16_MAX));
|
CHECK_LE(len, static_cast<size_t>(UINT16_MAX));
|
||||||
name_length = static_cast<uint16_t>(len);
|
name_length = static_cast<uint16_t>(len);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if !defined(_WIN32)
|
||||||
|
class ProcessWriter : public Writer {
|
||||||
|
public:
|
||||||
|
ProcessWriter(ProcessZipEntryFunction func, void* cookie) : Writer(),
|
||||||
|
proc_function_(func),
|
||||||
|
cookie_(cookie) {
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool Append(uint8_t* buf, size_t buf_size) override {
|
||||||
|
return proc_function_(buf, buf_size, cookie_);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
ProcessZipEntryFunction proc_function_;
|
||||||
|
void* cookie_;
|
||||||
|
};
|
||||||
|
|
||||||
|
int32_t ProcessZipEntryContents(ZipArchiveHandle handle, ZipEntry* entry,
|
||||||
|
ProcessZipEntryFunction func, void* cookie) {
|
||||||
|
ProcessWriter writer(func, cookie);
|
||||||
|
return ExtractToWriter(handle, entry, &writer);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif //!defined(_WIN32)
|
||||||
|
|
||||||
|
int MappedZipFile::GetFileDescriptor() const {
|
||||||
|
if (!has_fd_) {
|
||||||
|
ALOGW("Zip: MappedZipFile doesn't have a file descriptor.");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return fd_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void* MappedZipFile::GetBasePtr() const {
|
||||||
|
if (has_fd_) {
|
||||||
|
ALOGW("Zip: MappedZipFile doesn't have a base pointer.");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
return base_ptr_;
|
||||||
|
}
|
||||||
|
|
||||||
|
off64_t MappedZipFile::GetFileLength() const {
|
||||||
|
if (has_fd_) {
|
||||||
|
off64_t result = lseek64(fd_, 0, SEEK_END);
|
||||||
|
if (result == -1) {
|
||||||
|
ALOGE("Zip: lseek on fd %d failed: %s", fd_, strerror(errno));
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
} else {
|
||||||
|
if (base_ptr_ == nullptr) {
|
||||||
|
ALOGE("Zip: invalid file map\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return static_cast<off64_t>(data_length_);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MappedZipFile::SeekToOffset(off64_t offset) {
|
||||||
|
if (has_fd_) {
|
||||||
|
if (lseek64(fd_, offset, SEEK_SET) != offset) {
|
||||||
|
ALOGE("Zip: lseek to %" PRId64 " failed: %s\n", offset, strerror(errno));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
if (offset < 0 || offset > static_cast<off64_t>(data_length_)) {
|
||||||
|
ALOGE("Zip: invalid offset: %" PRId64 ", data length: %" PRId64 "\n" , offset,
|
||||||
|
data_length_);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
read_pos_ = offset;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MappedZipFile::ReadData(uint8_t* buffer, size_t read_amount) {
|
||||||
|
if (has_fd_) {
|
||||||
|
if(!android::base::ReadFully(fd_, buffer, read_amount)) {
|
||||||
|
ALOGE("Zip: read from %d failed\n", fd_);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
memcpy(buffer, static_cast<uint8_t*>(base_ptr_) + read_pos_, read_amount);
|
||||||
|
read_pos_ += read_amount;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Attempts to read |len| bytes into |buf| at offset |off|.
|
||||||
|
bool MappedZipFile::ReadAtOffset(uint8_t* buf, size_t len, off64_t off) {
|
||||||
|
#if !defined(_WIN32)
|
||||||
|
if (has_fd_) {
|
||||||
|
if (static_cast<size_t>(TEMP_FAILURE_RETRY(pread64(fd_, buf, len, off))) != len) {
|
||||||
|
ALOGE("Zip: failed to read at offset %" PRId64 "\n", off);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
if (!SeekToOffset(off)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return ReadData(buf, len);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void CentralDirectory::Initialize(void* map_base_ptr, off64_t cd_start_offset, size_t cd_size) {
|
||||||
|
base_ptr_ = static_cast<uint8_t*>(map_base_ptr) + cd_start_offset;
|
||||||
|
length_ = cd_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ZipArchive::InitializeCentralDirectory(const char* debug_file_name, off64_t cd_start_offset,
|
||||||
|
size_t cd_size) {
|
||||||
|
if (mapped_zip.HasFd()) {
|
||||||
|
if (!directory_map->create(debug_file_name, mapped_zip.GetFileDescriptor(),
|
||||||
|
cd_start_offset, cd_size, true /* read only */)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
CHECK_EQ(directory_map->getDataLength(), cd_size);
|
||||||
|
central_directory.Initialize(directory_map->getDataPtr(), 0/*offset*/, cd_size);
|
||||||
|
} else {
|
||||||
|
if (mapped_zip.GetBasePtr() == nullptr) {
|
||||||
|
ALOGE("Zip: Failed to map central directory, bad mapped_zip base pointer\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (static_cast<off64_t>(cd_start_offset) + static_cast<off64_t>(cd_size) >
|
||||||
|
mapped_zip.GetFileLength()) {
|
||||||
|
ALOGE("Zip: Failed to map central directory, offset exceeds mapped memory region ("
|
||||||
|
"start_offset %" PRId64 ", cd_size %zu, mapped_region_size %" PRId64 ")",
|
||||||
|
static_cast<int64_t>(cd_start_offset), cd_size, mapped_zip.GetFileLength());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
central_directory.Initialize(mapped_zip.GetBasePtr(), cd_start_offset, cd_size);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -21,17 +21,83 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#include <utils/FileMap.h>
|
#include <utils/FileMap.h>
|
||||||
#include <ziparchive/zip_archive.h>
|
#include <ziparchive/zip_archive.h>
|
||||||
|
|
||||||
|
class MappedZipFile {
|
||||||
|
public:
|
||||||
|
explicit MappedZipFile(const int fd) :
|
||||||
|
has_fd_(true),
|
||||||
|
fd_(fd),
|
||||||
|
base_ptr_(nullptr),
|
||||||
|
data_length_(0),
|
||||||
|
read_pos_(0) {}
|
||||||
|
|
||||||
|
explicit MappedZipFile(void* address, size_t length) :
|
||||||
|
has_fd_(false),
|
||||||
|
fd_(-1),
|
||||||
|
base_ptr_(address),
|
||||||
|
data_length_(static_cast<off64_t>(length)),
|
||||||
|
read_pos_(0) {}
|
||||||
|
|
||||||
|
bool HasFd() const {return has_fd_;}
|
||||||
|
|
||||||
|
int GetFileDescriptor() const;
|
||||||
|
|
||||||
|
void* GetBasePtr() const;
|
||||||
|
|
||||||
|
off64_t GetFileLength() const;
|
||||||
|
|
||||||
|
bool SeekToOffset(off64_t offset);
|
||||||
|
|
||||||
|
bool ReadData(uint8_t* buffer, size_t read_amount);
|
||||||
|
|
||||||
|
bool ReadAtOffset(uint8_t* buf, size_t len, off64_t off);
|
||||||
|
|
||||||
|
private:
|
||||||
|
// If has_fd_ is true, fd is valid and we'll read contents of a zip archive
|
||||||
|
// from the file. Otherwise, we're opening the archive from a memory mapped
|
||||||
|
// file. In that case, base_ptr_ points to the start of the memory region and
|
||||||
|
// data_length_ defines the file length.
|
||||||
|
const bool has_fd_;
|
||||||
|
|
||||||
|
const int fd_;
|
||||||
|
|
||||||
|
void* const base_ptr_;
|
||||||
|
const off64_t data_length_;
|
||||||
|
// read_pos_ is the offset to the base_ptr_ where we read data from.
|
||||||
|
size_t read_pos_;
|
||||||
|
};
|
||||||
|
|
||||||
|
class CentralDirectory {
|
||||||
|
public:
|
||||||
|
CentralDirectory(void) :
|
||||||
|
base_ptr_(nullptr),
|
||||||
|
length_(0) {}
|
||||||
|
|
||||||
|
const uint8_t* GetBasePtr() const {return base_ptr_;}
|
||||||
|
|
||||||
|
size_t GetMapLength() const {return length_;}
|
||||||
|
|
||||||
|
void Initialize(void* map_base_ptr, off64_t cd_start_offset, size_t cd_size);
|
||||||
|
|
||||||
|
private:
|
||||||
|
const uint8_t* base_ptr_;
|
||||||
|
size_t length_;
|
||||||
|
};
|
||||||
|
|
||||||
struct ZipArchive {
|
struct ZipArchive {
|
||||||
// open Zip archive
|
// open Zip archive
|
||||||
const int fd;
|
mutable MappedZipFile mapped_zip;
|
||||||
const bool close_file;
|
const bool close_file;
|
||||||
|
|
||||||
// mapped central directory area
|
// mapped central directory area
|
||||||
off64_t directory_offset;
|
off64_t directory_offset;
|
||||||
android::FileMap directory_map;
|
CentralDirectory central_directory;
|
||||||
|
std::unique_ptr<android::FileMap> directory_map;
|
||||||
|
|
||||||
// number of entries in the Zip archive
|
// number of entries in the Zip archive
|
||||||
uint16_t num_entries;
|
uint16_t num_entries;
|
||||||
|
|
@ -44,20 +110,36 @@ struct ZipArchive {
|
||||||
ZipString* hash_table;
|
ZipString* hash_table;
|
||||||
|
|
||||||
ZipArchive(const int fd, bool assume_ownership) :
|
ZipArchive(const int fd, bool assume_ownership) :
|
||||||
fd(fd),
|
mapped_zip(fd),
|
||||||
close_file(assume_ownership),
|
close_file(assume_ownership),
|
||||||
directory_offset(0),
|
directory_offset(0),
|
||||||
num_entries(0),
|
central_directory(),
|
||||||
hash_table_size(0),
|
directory_map(new android::FileMap()),
|
||||||
hash_table(NULL) {}
|
num_entries(0),
|
||||||
|
hash_table_size(0),
|
||||||
|
hash_table(nullptr) {}
|
||||||
|
|
||||||
|
ZipArchive(void* address, size_t length) :
|
||||||
|
mapped_zip(address, length),
|
||||||
|
close_file(false),
|
||||||
|
directory_offset(0),
|
||||||
|
central_directory(),
|
||||||
|
directory_map(new android::FileMap()),
|
||||||
|
num_entries(0),
|
||||||
|
hash_table_size(0),
|
||||||
|
hash_table(nullptr) {}
|
||||||
|
|
||||||
~ZipArchive() {
|
~ZipArchive() {
|
||||||
if (close_file && fd >= 0) {
|
if (close_file && mapped_zip.GetFileDescriptor() >= 0) {
|
||||||
close(fd);
|
close(mapped_zip.GetFileDescriptor());
|
||||||
}
|
}
|
||||||
|
|
||||||
free(hash_table);
|
free(hash_table);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool InitializeCentralDirectory(const char* debug_file_name, off64_t cd_start_offset,
|
||||||
|
size_t cd_size);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // LIBZIPARCHIVE_ZIPARCHIVE_PRIVATE_H_
|
#endif // LIBZIPARCHIVE_ZIPARCHIVE_PRIVATE_H_
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,7 @@ static constexpr size_t kBufSize = 65535;
|
||||||
bool ZipArchiveStreamEntry::Init(const ZipEntry& entry) {
|
bool ZipArchiveStreamEntry::Init(const ZipEntry& entry) {
|
||||||
ZipArchive* archive = reinterpret_cast<ZipArchive*>(handle_);
|
ZipArchive* archive = reinterpret_cast<ZipArchive*>(handle_);
|
||||||
off64_t data_offset = entry.offset;
|
off64_t data_offset = entry.offset;
|
||||||
if (lseek64(archive->fd, data_offset, SEEK_SET) != data_offset) {
|
if (!archive->mapped_zip.SeekToOffset(data_offset)) {
|
||||||
ALOGW("lseek to data at %" PRId64 " failed: %s", data_offset, strerror(errno));
|
ALOGW("lseek to data at %" PRId64 " failed: %s", data_offset, strerror(errno));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
@ -88,7 +88,7 @@ const std::vector<uint8_t>* ZipArchiveStreamEntryUncompressed::Read() {
|
||||||
size_t bytes = (length_ > data_.size()) ? data_.size() : length_;
|
size_t bytes = (length_ > data_.size()) ? data_.size() : length_;
|
||||||
ZipArchive* archive = reinterpret_cast<ZipArchive*>(handle_);
|
ZipArchive* archive = reinterpret_cast<ZipArchive*>(handle_);
|
||||||
errno = 0;
|
errno = 0;
|
||||||
if (!android::base::ReadFully(archive->fd, data_.data(), bytes)) {
|
if (!archive->mapped_zip.ReadData(data_.data(), bytes)) {
|
||||||
if (errno != 0) {
|
if (errno != 0) {
|
||||||
ALOGE("Error reading from archive fd: %s", strerror(errno));
|
ALOGE("Error reading from archive fd: %s", strerror(errno));
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -209,7 +209,7 @@ const std::vector<uint8_t>* ZipArchiveStreamEntryCompressed::Read() {
|
||||||
size_t bytes = (compressed_length_ > in_.size()) ? in_.size() : compressed_length_;
|
size_t bytes = (compressed_length_ > in_.size()) ? in_.size() : compressed_length_;
|
||||||
ZipArchive* archive = reinterpret_cast<ZipArchive*>(handle_);
|
ZipArchive* archive = reinterpret_cast<ZipArchive*>(handle_);
|
||||||
errno = 0;
|
errno = 0;
|
||||||
if (!android::base::ReadFully(archive->fd, in_.data(), bytes)) {
|
if (!archive->mapped_zip.ReadData(in_.data(), bytes)) {
|
||||||
if (errno != 0) {
|
if (errno != 0) {
|
||||||
ALOGE("Error reading from archive fd: %s", strerror(errno));
|
ALOGE("Error reading from archive fd: %s", strerror(errno));
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,9 @@
|
||||||
|
|
||||||
#include <android-base/file.h>
|
#include <android-base/file.h>
|
||||||
#include <android-base/test_utils.h>
|
#include <android-base/test_utils.h>
|
||||||
|
#include <android-base/unique_fd.h>
|
||||||
#include <gtest/gtest.h>
|
#include <gtest/gtest.h>
|
||||||
|
#include <utils/FileMap.h>
|
||||||
#include <ziparchive/zip_archive.h>
|
#include <ziparchive/zip_archive.h>
|
||||||
#include <ziparchive/zip_archive_stream_entry.h>
|
#include <ziparchive/zip_archive_stream_entry.h>
|
||||||
|
|
||||||
|
|
@ -36,6 +38,7 @@ static const std::string kMissingZip = "missing.zip";
|
||||||
static const std::string kValidZip = "valid.zip";
|
static const std::string kValidZip = "valid.zip";
|
||||||
static const std::string kLargeZip = "large.zip";
|
static const std::string kLargeZip = "large.zip";
|
||||||
static const std::string kBadCrcZip = "bad_crc.zip";
|
static const std::string kBadCrcZip = "bad_crc.zip";
|
||||||
|
static const std::string kUpdateZip = "dummy-update.zip";
|
||||||
|
|
||||||
static const std::vector<uint8_t> kATxtContents {
|
static const std::vector<uint8_t> kATxtContents {
|
||||||
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
|
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
|
||||||
|
|
@ -494,6 +497,32 @@ TEST(ziparchive, ExtractToFile) {
|
||||||
lseek64(tmp_file.fd, 0, SEEK_END));
|
lseek64(tmp_file.fd, 0, SEEK_END));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if !defined(_WIN32)
|
||||||
|
TEST(ziparchive, OpenFromMemory) {
|
||||||
|
const std::string zip_path = test_data_dir + "/" + kUpdateZip;
|
||||||
|
android::base::unique_fd fd(open(zip_path.c_str(), O_RDONLY | O_BINARY));
|
||||||
|
ASSERT_NE(-1, fd);
|
||||||
|
struct stat sb;
|
||||||
|
ASSERT_EQ(0, fstat(fd, &sb));
|
||||||
|
|
||||||
|
// Memory map the file first and open the archive from the memory region.
|
||||||
|
android::FileMap file_map;
|
||||||
|
file_map.create(zip_path.c_str(), fd, 0/*offset*/, sb.st_size, true);
|
||||||
|
ZipArchiveHandle handle;
|
||||||
|
ASSERT_EQ(0, OpenArchiveFromMemory(file_map.getDataPtr(), file_map.getDataLength(),
|
||||||
|
zip_path.c_str(), &handle));
|
||||||
|
|
||||||
|
// Assert one entry can be found and extracted correctly.
|
||||||
|
std::string BINARY_PATH("META-INF/com/google/android/update-binary");
|
||||||
|
ZipString binary_path(BINARY_PATH.c_str());
|
||||||
|
ZipEntry binary_entry;
|
||||||
|
ASSERT_EQ(0, FindEntry(handle, binary_path, &binary_entry));
|
||||||
|
TemporaryFile tmp_binary;
|
||||||
|
ASSERT_NE(-1, tmp_binary.fd);
|
||||||
|
ASSERT_EQ(0, ExtractEntryToFile(handle, &binary_entry, tmp_binary.fd));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static void ZipArchiveStreamTest(
|
static void ZipArchiveStreamTest(
|
||||||
ZipArchiveHandle& handle, const std::string& entry_name, bool raw,
|
ZipArchiveHandle& handle, const std::string& entry_name, bool raw,
|
||||||
bool verified, ZipEntry* entry, std::vector<uint8_t>* read_data) {
|
bool verified, ZipEntry* entry, std::vector<uint8_t>* read_data) {
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue