From c6e35cb47a90a43b5a0009f526b695b2b5c87465 Mon Sep 17 00:00:00 2001 From: Kenny Root Date: Fri, 15 Feb 2013 09:37:11 -0800 Subject: StreamingZipInflater: fix mmap'd end of read When reaching the end of a mmap'd segment, it was erroneously trying to read more data. This is because we were reading data one character at a time, so we never reached the Z_STREAM_END result without going through the loop once more. Bug: https://code.google.com/p/android/issues/detail?id=39041 Change-Id: I6c53b8187384a42217c32112d6a0c2857f471109 --- libs/androidfw/StreamingZipInflater.cpp | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) (limited to 'libs/androidfw/StreamingZipInflater.cpp') diff --git a/libs/androidfw/StreamingZipInflater.cpp b/libs/androidfw/StreamingZipInflater.cpp index d3fb98d57fac..1dfec23cbe63 100644 --- a/libs/androidfw/StreamingZipInflater.cpp +++ b/libs/androidfw/StreamingZipInflater.cpp @@ -23,6 +23,23 @@ #include #include #include +#include +#include + +/* + * TEMP_FAILURE_RETRY is defined by some, but not all, versions of + * . (Alas, it is not as standard as we'd hoped!) So, if it's + * not already defined, then define it here. + */ +#ifndef TEMP_FAILURE_RETRY +/* Used to retry syscalls that can return EINTR. */ +#define TEMP_FAILURE_RETRY(exp) ({ \ + typeof (exp) _rc; \ + do { \ + _rc = (exp); \ + } while (_rc == -1 && errno == EINTR); \ + _rc; }) +#endif static inline size_t min_of(size_t a, size_t b) { return (a < b) ? a : b; } @@ -135,7 +152,7 @@ ssize_t StreamingZipInflater::read(void* outBuf, size_t count) { // if we don't have any data to decode, read some in. If we're working // from mmapped data this won't happen, because the clipping to total size // will prevent reading off the end of the mapped input chunk. - if (mInflateState.avail_in == 0) { + if ((mInflateState.avail_in == 0) && (mDataMap == NULL)) { int err = readNextChunk(); if (err < 0) { ALOGE("Unable to access asset data: %d", err); @@ -191,11 +208,10 @@ int StreamingZipInflater::readNextChunk() { if (mInNextChunkOffset < mInTotalSize) { size_t toRead = min_of(mInBufSize, mInTotalSize - mInNextChunkOffset); if (toRead > 0) { - ssize_t didRead = ::read(mFd, mInBuf, toRead); + ssize_t didRead = TEMP_FAILURE_RETRY(::read(mFd, mInBuf, toRead)); //ALOGV("Reading input chunk, size %08x didread %08x", toRead, didRead); if (didRead < 0) { - // TODO: error - ALOGE("Error reading asset data"); + ALOGE("Error reading asset data: %s", strerror(errno)); return didRead; } else { mInNextChunkOffset += didRead; -- cgit v1.2.3-59-g8ed1b