/* * Uncompress an entry, in its entirety, to an open file descriptor. * * TODO: this doesn't verify the data's CRC, but probably should (especially * for uncompressed data). */ bool dexZipExtractEntryToFile(const ZipArchive* pArchive, const ZipEntry entry, int fd) { bool result = false; int ent = entryToIndex(pArchive, entry); if (ent < 0) return -1; const unsigned char* basePtr = (const unsigned char*)pArchive->mMap.addr; int method; long uncompLen, compLen; off_t offset; if (!dexZipGetEntryInfo(pArchive, entry, &method, &uncompLen, &compLen, &offset, NULL, NULL)) { goto bail; } if (method == kCompressStored) { ssize_t actual; actual = write(fd, basePtr + offset, uncompLen); if (actual < 0) { LOGE("Write failed: %s\n", strerror(errno)); goto bail; } else if (actual != uncompLen) { LOGE("Partial write during uncompress (%d of %ld)\n", (int) actual, uncompLen); goto bail; } else { LOGI("+++ successful write\n"); } } else { if (!inflateToFile(fd, basePtr+offset, uncompLen, compLen)) goto bail; } result = true; bail: return result; }
/* * Uncompress an entry, in its entirety, to an open file descriptor. * * TODO: this doesn't verify the data's CRC, but probably should (especially * for uncompressed data). */ int dexZipExtractEntryToFile(const ZipArchive* pArchive, const ZipEntry entry, int fd) { int result = -1; int ent = entryToIndex(pArchive, entry); if (ent < 0) { LOGW("Zip: extract can't find entry %p\n", entry); goto bail; } int method; size_t uncompLen, compLen; off_t dataOffset; if (dexZipGetEntryInfo(pArchive, entry, &method, &uncompLen, &compLen, &dataOffset, NULL, NULL) != 0) { goto bail; } if (lseek(pArchive->mFd, dataOffset, SEEK_SET) != dataOffset) { LOGW("Zip: lseek to data at %ld failed\n", (long) dataOffset); goto bail; } if (method == kCompressStored) { if (copyFileToFile(pArchive->mFd, fd, uncompLen) != 0) goto bail; } else { if (inflateToFile(pArchive->mFd, fd, uncompLen, compLen) != 0) goto bail; } result = 0; bail: return result; }
// this is used by the drag-and-drop reordering void CWList::moveItem(CWListEntry * pEntry, int iNewLoc) { int iCurrentLoc = entryToIndex(pEntry); m_pEntries.RemoveAt(iCurrentLoc); m_pEntries.InsertAt(iNewLoc, pEntry); }
/* * Get the useful fields from the zip entry. * * Returns non-zero if the contents of the fields (particularly the data * offset) appear to be bogus. */ int dexZipGetEntryInfo(const ZipArchive* pArchive, ZipEntry entry, int* pMethod, size_t* pUncompLen, size_t* pCompLen, off_t* pOffset, long* pModWhen, long* pCrc32) { int ent = entryToIndex(pArchive, entry); if (ent < 0) return -1; /* * 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 unsigned char* basePtr = (const unsigned char*) pArchive->mDirectoryMap.addr; const unsigned char* ptr = (const unsigned char*) pArchive->mHashTable[ent].name; off_t cdOffset = pArchive->mDirectoryOffset; ptr -= kCDELen; int method = get2LE(ptr + kCDEMethod); if (pMethod != NULL) *pMethod = method; if (pModWhen != NULL) *pModWhen = get4LE(ptr + kCDEModWhen); if (pCrc32 != NULL) *pCrc32 = get4LE(ptr + kCDECRC); size_t compLen = get4LE(ptr + kCDECompLen); if (pCompLen != NULL) *pCompLen = compLen; size_t uncompLen = get4LE(ptr + kCDEUncompLen); if (pUncompLen != NULL) *pUncompLen = uncompLen; /* * If requested, determine the offset of the start of the data. All we * have is the offset to the Local File Header, which is variable size, * so we have to read the contents of the struct to figure out where * the actual data starts. * * We also need to make sure that the lengths are not so large that * somebody trying to map the compressed or uncompressed data runs * off the end of the mapped region. * * Note we don't verify compLen/uncompLen if they don't request the * dataOffset, because dataOffset is expensive to determine. However, * if they don't have the file offset, they're not likely to be doing * anything with the contents. */ if (pOffset != NULL) { long localHdrOffset = (long) get4LE(ptr + kCDELocalOffset); if (localHdrOffset + kLFHLen >= cdOffset) { LOGW("Zip: bad local hdr offset in zip\n"); return -1; } u1 lfhBuf[kLFHLen]; if (lseek(pArchive->mFd, localHdrOffset, SEEK_SET) != localHdrOffset) { LOGW("Zip: failed seeking to lfh at offset %ld\n", localHdrOffset); return -1; } ssize_t actual = TEMP_FAILURE_RETRY(read(pArchive->mFd, lfhBuf, sizeof(lfhBuf))); if (actual != sizeof(lfhBuf)) { LOGW("Zip: failed reading lfh from offset %ld\n", localHdrOffset); return -1; } if (get4LE(lfhBuf) != kLFHSignature) { LOGW("Zip: didn't find signature at start of lfh, offset=%ld\n", localHdrOffset); return -1; } off_t dataOffset = localHdrOffset + kLFHLen + get2LE(lfhBuf + kLFHNameLen) + get2LE(lfhBuf + kLFHExtraLen); if (dataOffset >= cdOffset) { LOGW("Zip: bad data offset %ld in zip\n", (long) dataOffset); return -1; } /* check lengths */ if ((off_t)(dataOffset + compLen) > cdOffset) { LOGW("Zip: bad compressed length in zip (%ld + %zd > %ld)\n", (long) dataOffset, compLen, (long) cdOffset); return -1; } if (method == kCompressStored && (off_t)(dataOffset + uncompLen) > cdOffset) { LOGW("Zip: bad uncompressed length in zip (%ld + %zd > %ld)\n", (long) dataOffset, uncompLen, (long) cdOffset); return -1; } *pOffset = dataOffset; } return 0; }
/* * Get the useful fields from the zip entry. * * Returns "false" if the offsets to the fields or the contents of the fields * appear to be bogus. */ bool dexZipGetEntryInfo(const ZipArchive* pArchive, ZipEntry entry, int* pMethod, long* pUncompLen, long* pCompLen, off_t* pOffset, long* pModWhen, long* pCrc32) { int ent = entryToIndex(pArchive, entry); if (ent < 0) return false; /* * Recover the start of the central directory entry from the filename * pointer. */ const unsigned char* basePtr = (const unsigned char*) pArchive->mMap.addr; const unsigned char* ptr = (const unsigned char*) pArchive->mHashTable[ent].name; size_t zipLength = pArchive->mMap.length; ptr -= kCDELen; int method = get2LE(ptr + kCDEMethod); if (pMethod != NULL) *pMethod = method; if (pModWhen != NULL) *pModWhen = get4LE(ptr + kCDEModWhen); if (pCrc32 != NULL) *pCrc32 = get4LE(ptr + kCDECRC); /* * We need to make sure that the lengths are not so large that somebody * trying to map the compressed or uncompressed data runs off the end * of the mapped region. */ unsigned long localHdrOffset = get4LE(ptr + kCDELocalOffset); if (localHdrOffset + kLFHLen >= zipLength) { LOGE("ERROR: bad local hdr offset in zip\n"); return false; } const unsigned char* localHdr = basePtr + localHdrOffset; off_t dataOffset = localHdrOffset + kLFHLen + get2LE(localHdr + kLFHNameLen) + get2LE(localHdr + kLFHExtraLen); if ((unsigned long) dataOffset >= zipLength) { LOGE("ERROR: bad data offset in zip\n"); return false; } if (pCompLen != NULL) { *pCompLen = get4LE(ptr + kCDECompLen); if (*pCompLen < 0 || (size_t)(dataOffset + *pCompLen) >= zipLength) { LOGE("ERROR: bad compressed length in zip\n"); return false; } } if (pUncompLen != NULL) { *pUncompLen = get4LE(ptr + kCDEUncompLen); if (*pUncompLen < 0) { LOGE("ERROR: negative uncompressed length in zip\n"); return false; } if (method == kCompressStored && (size_t)(dataOffset + *pUncompLen) >= zipLength) { LOGE("ERROR: bad uncompressed length in zip\n"); return false; } } if (pOffset != NULL) { *pOffset = dataOffset; } return true; }