Loading modules/libjar/nsJAR.cpp +1 −1 Original line number Diff line number Diff line Loading @@ -339,7 +339,7 @@ nsJAR::GetInputStreamWithSpec(const nsACString& aJarDirSpec, if (!item || item->isDirectory) { rv = jis->InitDirectory(this, aJarDirSpec, aEntryName); } else { rv = jis->InitFile(this, item); rv = jis->InitFile(mZip.GetFD(item), item); } if (NS_FAILED(rv)) { NS_RELEASE(*result); Loading modules/libjar/nsJARInputStream.cpp +85 −51 Original line number Diff line number Diff line Loading @@ -59,42 +59,43 @@ NS_IMPL_THREADSAFE_ISUPPORTS1(nsJARInputStream, nsIInputStream) *--------------------------------------------------------*/ nsresult nsJARInputStream::InitFile(nsJAR *aJar, nsZipItem *item) nsJARInputStream::InitFile(nsZipHandle *aFd, nsZipItem *item) { nsresult rv = NS_OK; NS_ABORT_IF_FALSE(aJar, "Argument may not be null"); nsresult rv; NS_ABORT_IF_FALSE(aFd, "Argument may not be null"); NS_ABORT_IF_FALSE(item, "Argument may not be null"); // Mark it as closed, in case something fails in initialisation mClosed = true; mClosed = PR_TRUE; // Keep the important bits of nsZipItem only mInSize = item->size; //-- prepare for the compression type switch (item->compression) { case STORED: mCompressed = false; break; case DEFLATED: mCompressed = true; rv = gZlibInit(&mZs); mInflate = (InflateStruct *) PR_Malloc(sizeof(InflateStruct)); NS_ENSURE_TRUE(mInflate, NS_ERROR_OUT_OF_MEMORY); rv = gZlibInit(&(mInflate->mZs)); NS_ENSURE_SUCCESS(rv, NS_ERROR_OUT_OF_MEMORY); mOutSize = item->realsize; mInCrc = item->crc32; mOutCrc = crc32(0L, Z_NULL, 0); mInflate->mOutSize = item->realsize; mInflate->mInCrc = item->crc32; mInflate->mOutCrc = crc32(0L, Z_NULL, 0); break; default: return NS_ERROR_NOT_IMPLEMENTED; } // Must keep handle to filepointer and mmap structure as long as we need access to the mmapped data mFd = aJar->mZip.GetFD(); mZs.next_in = aJar->mZip.GetData(item); mZs.avail_in = item->size; mOutSize = item->realsize; mDirectory = false; //-- Set filepointer to start of item mFd.Open(aFd, item->dataOffset, item->size); // Open for reading mClosed = false; mClosed = PR_FALSE; mCurPos = 0; return NS_OK; } Loading @@ -108,9 +109,8 @@ nsJARInputStream::InitDirectory(nsJAR* aJar, NS_ABORT_IF_FALSE(aDir, "Argument may not be null"); // Mark it as closed, in case something fails in initialisation mClosed = true; mDirectory = true; mCompressed = false; mClosed = PR_TRUE; mDirectory = PR_TRUE; // Keep the zipReader for getting the actual zipItems mJar = aJar; Loading Loading @@ -173,7 +173,7 @@ nsJARInputStream::InitDirectory(nsJAR* aJar, mBuffer.AppendLiteral("\n200: filename content-length last-modified file-type\n"); // Open for reading mClosed = false; mClosed = PR_FALSE; mCurPos = 0; mArrPos = 0; return NS_OK; Loading @@ -187,10 +187,10 @@ nsJARInputStream::Available(PRUint32 *_retval) if (mDirectory) *_retval = mBuffer.Length(); else if (mCompressed) *_retval = mOutSize - mZs.total_out; else if (mInflate) *_retval = mInflate->mOutSize - mInflate->mZs.total_out; else *_retval = mOutSize - mCurPos; *_retval = mInSize - mCurPos; return NS_OK; } Loading @@ -202,30 +202,41 @@ nsJARInputStream::Read(char* aBuffer, PRUint32 aCount, PRUint32 *aBytesRead) *aBytesRead = 0; nsresult rv = NS_OK; if (mClosed) return NS_OK; return rv; if (mDirectory) { return ReadDirectory(aBuffer, aCount, aBytesRead); rv = ReadDirectory(aBuffer, aCount, aBytesRead); } else { if (mInflate) { rv = ContinueInflate(aBuffer, aCount, aBytesRead); } else { PRInt32 bytesRead = 0; aCount = PR_MIN(aCount, mInSize - mCurPos); if (aCount) { bytesRead = mFd.Read(aBuffer, aCount); if (bytesRead < 0) return NS_ERROR_FILE_CORRUPTED; mCurPos += bytesRead; if ((PRUint32)bytesRead != aCount) { // file is truncated or was lying about size, we're done Close(); return NS_ERROR_FILE_CORRUPTED; } } if (mCompressed) { return ContinueInflate(aBuffer, aCount, aBytesRead); *aBytesRead = bytesRead; } if (mFd) { PRUint32 count = PR_MIN(aCount, mOutSize - mCurPos); memcpy(aBuffer, mZs.next_in + mCurPos, count); mCurPos += count; *aBytesRead = count; // be aggressive about closing! // note that sometimes, we will close mFd before we've finished // deflating - this is because zlib buffers the input // So, don't free the ReadBuf/InflateStruct yet. // It is ok to close the fd multiple times (also in nsJARInputStream::Close()) if (mCurPos >= mZs.avail_in) { mFd = nsnull; if (mCurPos >= mInSize) { mFd.Close(); } } return NS_OK; return rv; } NS_IMETHODIMP Loading @@ -246,9 +257,9 @@ nsJARInputStream::IsNonBlocking(PRBool *aNonBlocking) NS_IMETHODIMP nsJARInputStream::Close() { mClosed = true; mFd = nsnull; mJar = nsnull; PR_FREEIF(mInflate); mClosed = PR_TRUE; mFd.Close(); return NS_OK; } Loading @@ -257,33 +268,56 @@ nsJARInputStream::ContinueInflate(char* aBuffer, PRUint32 aCount, PRUint32* aBytesRead) { // No need to check the args, ::Read did that, but assert them at least NS_ASSERTION(mInflate,"inflate data structure missing"); NS_ASSERTION(aBuffer,"aBuffer parameter must not be null"); NS_ASSERTION(aBytesRead,"aBytesRead parameter must not be null"); // Keep old total_out count const PRUint32 oldTotalOut = mZs.total_out; const PRUint32 oldTotalOut = mInflate->mZs.total_out; // make sure we aren't reading too much mZs.avail_out = PR_MIN(aCount, (mOutSize-oldTotalOut)); mZs.next_out = (unsigned char*)aBuffer; mInflate->mZs.avail_out = (mInflate->mOutSize-oldTotalOut > aCount) ? aCount : mInflate->mOutSize-oldTotalOut; mInflate->mZs.next_out = (unsigned char*)aBuffer; int zerr = Z_OK; //-- inflate loop while (mInflate->mZs.avail_out > 0 && zerr == Z_OK) { if (mInflate->mZs.avail_in == 0 && mCurPos < mInSize) { // time to fill the buffer! PRUint32 bytesToRead = PR_MIN(mInSize - mCurPos, ZIP_BUFLEN); PRInt32 bytesRead = mFd.Read(mInflate->mReadBuf, bytesToRead); if (bytesRead < 0) { zerr = Z_ERRNO; break; } mCurPos += bytesRead; // now set the state for 'inflate' mInflate->mZs.next_in = mInflate->mReadBuf; mInflate->mZs.avail_in = bytesRead; } // now inflate int zerr = inflate(&mZs, Z_SYNC_FLUSH); zerr = inflate(&(mInflate->mZs), Z_SYNC_FLUSH); } if ((zerr != Z_OK) && (zerr != Z_STREAM_END)) return NS_ERROR_FILE_CORRUPTED; *aBytesRead = (mZs.total_out - oldTotalOut); *aBytesRead = (mInflate->mZs.total_out - oldTotalOut); // Calculate the CRC on the output mOutCrc = crc32(mOutCrc, (unsigned char*)aBuffer, *aBytesRead); mInflate->mOutCrc = crc32(mInflate->mOutCrc, (unsigned char*)aBuffer, *aBytesRead); // be aggressive about ending the inflation // for some reason we don't always get Z_STREAM_END if (zerr == Z_STREAM_END || mZs.total_out == mOutSize) { inflateEnd(&mZs); if (zerr == Z_STREAM_END || mInflate->mZs.total_out == mInflate->mOutSize) { inflateEnd(&(mInflate->mZs)); // stop returning valid data as soon as we know we have a bad CRC if (mOutCrc != mInCrc) { if (mInflate->mOutCrc != mInflate->mInCrc) { // asserting because while this rarely happens, you definitely // want to catch it in debug builds! NS_NOTREACHED(0); Loading modules/libjar/nsJARInputStream.h +25 −19 Original line number Diff line number Diff line Loading @@ -53,39 +53,45 @@ class nsJARInputStream : public nsIInputStream { public: nsJARInputStream() : mCurPos(0), mCompressed(false), mDirectory(false), mClosed(true) mInSize(0), mCurPos(0), mInflate(nsnull), mDirectory(0), mClosed(PR_FALSE) { } ~nsJARInputStream() { Close(); } ~nsJARInputStream() { Close(); } NS_DECL_ISUPPORTS NS_DECL_NSIINPUTSTREAM // takes ownership of |fd|, even on failure nsresult InitFile(nsJAR *aJar, nsZipItem *item); nsresult InitFile(nsZipHandle *aFd, nsZipItem *item); nsresult InitDirectory(nsJAR *aJar, const nsACString& aJarDirSpec, const char* aDir); private: nsRefPtr<nsZipHandle> mFd; // handle for reading PRUint32 mInSize; // Size in original file PRUint32 mCurPos; // Current position in input struct InflateStruct { PRUint32 mOutSize; // inflated size PRUint32 mInCrc; // CRC as provided by the zipentry PRUint32 mOutCrc; // CRC as calculated by me z_stream mZs; // zip data structure unsigned char mReadBuf[ZIP_BUFLEN]; // Readbuffer to inflate from }; struct InflateStruct * mInflate; /* For directory reading */ nsRefPtr<nsJAR> mJar; // string reference to zipreader PRUint32 mNameLen; // length of dirname nsCString mBuffer; // storage for generated text of stream nsCAutoString mBuffer; // storage for generated text of stream PRUint32 mArrPos; // current position within mArray nsTArray<nsCString> mArray; // array of names in (zip) directory bool mCompressed; // is this compressed? bool mDirectory; // is this a directory? bool mClosed; // Whether the stream is closed PRPackedBool mDirectory; // is this a directory? PRPackedBool mClosed; // Whether the stream is closed nsSeekableZipHandle mFd; // handle for reading nsresult ContinueInflate(char* aBuf, PRUint32 aCount, PRUint32* aBytesRead); nsresult ReadDirectory(char* aBuf, PRUint32 aCount, PRUint32* aBytesRead); Loading modules/libjar/nsZipArchive.cpp +169 −76 Original line number Diff line number Diff line Loading @@ -50,6 +50,7 @@ */ #define ZFILE_CREATE PR_WRONLY | PR_CREATE_FILE #define READTYPE PRInt32 #include "zlib.h" #include "nsISupportsUtils.h" Loading Loading @@ -227,14 +228,13 @@ nsresult nsZipHandle::Init(PRFileDesc *fd, nsZipHandle **ret) return NS_ERROR_FILE_TOO_BIG; PRFileMap *map = PR_CreateFileMap(fd, size, PR_PROT_READONLY); if (!map) return NS_ERROR_FAILURE; nsZipHandle *handle = new nsZipHandle(); if (!handle) { PR_CloseFileMap(map); if (!handle) return NS_ERROR_OUT_OF_MEMORY; } handle->mFd = fd; handle->mMap = map; Loading @@ -245,17 +245,22 @@ nsresult nsZipHandle::Init(PRFileDesc *fd, nsZipHandle **ret) return NS_OK; } PRInt32 nsZipHandle::Read(PRUint32 aPosition, void *aBuffer, PRUint32 aCount) { if (mLen < 0 || aPosition+aCount > (PRUint32) mLen) return -1; PRInt32 count = PR_MIN(aCount, mLen - aPosition); memcpy(aBuffer, mFileData + aPosition, count); return count; } nsZipHandle::~nsZipHandle() { if (mFileData) { if (mFd) { PR_MemUnmap(mFileData, mLen); PR_CloseFileMap(mMap); mFileData = nsnull; mMap = nsnull; } if (mFd) { PR_Close(mFd); mFd = nsnull; mFd = 0; } MOZ_COUNT_DTOR(nsZipHandle); } Loading Loading @@ -321,7 +326,6 @@ nsresult nsZipArchive::CloseArchive() { if (mFd) { PL_FinishArenaPool(&mArena); mFd = NULL; } // CAUTION: Loading @@ -331,8 +335,11 @@ nsresult nsZipArchive::CloseArchive() // for all the nsZipItem in one shot. But if the ~nsZipItem is doing // anything more than cleaning up memory, we should start calling it. // Let us also cleanup the mFiles table for re-use on the next 'open' call memset(mFiles, 0, sizeof(mFiles)); mBuiltSynthetics = false; for (int i = 0; i < ZIP_TABSIZE; i++) { mFiles[i] = 0; } mFd = NULL; mBuiltSynthetics = PR_FALSE; return ZIP_OK; } Loading Loading @@ -381,17 +388,25 @@ nsresult nsZipArchive::ExtractFile(nsZipItem *item, const char *outname, // so the item to be extracted should never be a directory PR_ASSERT(!item->isDirectory); //-- move to the start of file's data if (!MaybeReadItem(item)) return ZIP_ERR_CORRUPT; nsSeekableZipHandle fd; if (!fd.Open(mFd.get(), item->dataOffset, item->size)) return ZIP_ERR_CORRUPT; nsresult rv; //-- extract the file using the appropriate method switch(item->compression) { case STORED: rv = CopyItemToDisk(item, aFd); rv = CopyItemToDisk(item->size, item->crc32, fd, aFd); break; case DEFLATED: rv = InflateItem(item, aFd); rv = InflateItem(item, fd, aFd); break; default: Loading Loading @@ -592,12 +607,14 @@ nsresult nsZipArchive::BuildFileList() return ZIP_ERR_MEMORY; item->headerOffset = xtolong(central->localhdr_offset); item->dataOffset = 0; item->size = xtolong(central->size); item->realsize = xtolong(central->orglen); item->crc32 = xtolong(central->crc32); item->time = xtoint(central->time); item->date = xtoint(central->date); item->isSynthetic = PR_FALSE; item->hasDataOffset = PR_FALSE; item->compression = PR_MIN(xtoint(central->method), UNSUPPORTED); item->mode = ExtractMode(central->external_attributes); #if defined(XP_UNIX) || defined(XP_BEOS) Loading Loading @@ -635,7 +652,7 @@ nsresult nsZipArchive::BuildSynthetics() { if (mBuiltSynthetics) return ZIP_OK; mBuiltSynthetics = true; mBuiltSynthetics = PR_TRUE; // Create synthetic entries for any missing directories. // Do this when all ziptable has scanned to prevent double entries. Loading Loading @@ -720,68 +737,91 @@ nsresult nsZipArchive::BuildSynthetics() return ZIP_OK; } nsZipHandle* nsZipArchive::GetFD() nsZipHandle* nsZipArchive::GetFD(nsZipItem* aItem) { if (!mFd) if (!mFd || !MaybeReadItem(aItem)) return NULL; return mFd.get(); } //--------------------------------------------- // nsZipArchive::GetData // nsZipArchive::MaybeReadItem //--------------------------------------------- PRUint8* nsZipArchive::GetData(nsZipItem* aItem) bool nsZipArchive::MaybeReadItem(nsZipItem* aItem) { PR_ASSERT (aItem); //-- the first time an item is used we need to calculate its offset if (!aItem->hasDataOffset) { //-- read local header to get variable length values and calculate //-- the real data offset if (aItem->headerOffset + ZIPLOCAL_SIZE > mFd->mLen) return nsnull; //-- //-- NOTE: extralen is different in central header and local header //-- for archives created using the Unix "zip" utility. To set //-- the offset accurately we need the _local_ extralen. if (!mFd || !mFd->mLen > aItem->headerOffset + ZIPLOCAL_SIZE) return false; // -- check signature before using the structure, in case the zip file is corrupt ZipLocal *Local = (ZipLocal*)(mFd->mFileData + aItem->headerOffset); //check limits here if ((xtolong(Local->signature) != LOCALSIG)) return nsnull; { //-- read error or local header not found return false; } //-- NOTE: extralen is different in central header and local header //-- for archives created using the Unix "zip" utility. To set //-- the offset accurately we need the _local_ extralen. PRUint32 dataOffset = aItem->headerOffset + aItem->dataOffset = aItem->headerOffset + ZIPLOCAL_SIZE + xtoint(Local->filename_len) + xtoint(Local->extrafield_len); aItem->hasDataOffset = PR_TRUE; } // -- check if there is enough source data in the file if (dataOffset + aItem->size > mFd->mLen) return nsnull; return mFd->mFileData + dataOffset; return true; } //--------------------------------------------- // nsZipArchive::CopyItemToDisk //--------------------------------------------- nsresult nsZipArchive::CopyItemToDisk(nsZipItem *item, PRFileDesc* outFD) nsZipArchive::CopyItemToDisk(PRUint32 itemSize, PRUint32 itemCrc, nsSeekableZipHandle &fd, PRFileDesc* outFD) /* * This function copies an archive item to disk, to the * file specified by outFD. If outFD is zero, the extracted data is * not written, only checked for CRC, so this is in effect same as 'Test'. */ { PR_ASSERT(item); PRUint32 chunk, pos, crc; char buf[ZIP_BUFLEN]; //-- initialize crc crc = crc32(0L, Z_NULL, 0); //-- get to the start of file's data const PRUint8* itemData = GetData(item); if (!itemData) //-- copy chunks until file is done for (pos = 0; pos < itemSize; pos += chunk) { chunk = (itemSize - pos < ZIP_BUFLEN) ? (itemSize - pos) : ZIP_BUFLEN; if (fd.Read(buf, chunk) != (READTYPE)chunk) { //-- unexpected end of data in archive return ZIP_ERR_CORRUPT; } //-- incrementally update crc32 crc = crc32(crc, (const unsigned char*)buf, chunk); if (outFD && PR_Write(outFD, itemData, item->size) < (READTYPE)item->size) if (outFD && PR_Write(outFD, buf, chunk) < (READTYPE)chunk) { //-- Couldn't write all the data (disk full?) return ZIP_ERR_DISK; } } //-- Calculate crc PRUint32 crc = crc32(0L, (const unsigned char*)itemData, item->size); //-- verify crc32 if (crc != item->crc32) if (crc != itemCrc) return ZIP_ERR_CORRUPT; return ZIP_OK; Loading @@ -791,15 +831,17 @@ nsZipArchive::CopyItemToDisk(nsZipItem *item, PRFileDesc* outFD) //--------------------------------------------- // nsZipArchive::InflateItem //--------------------------------------------- nsresult nsZipArchive::InflateItem(nsZipItem * item, PRFileDesc* outFD) nsresult nsZipArchive::InflateItem(const nsZipItem* aItem, nsSeekableZipHandle &fd, PRFileDesc* outFD) /* * This function inflates an archive item to disk, to the * file specified by outFD. If outFD is zero, the extracted data is * not written, only checked for CRC, so this is in effect same as 'Test'. */ { PR_ASSERT(item); PR_ASSERT(aItem); //-- allocate deflation buffers Bytef inbuf[ZIP_BUFLEN]; Bytef outbuf[ZIP_BUFLEN]; //-- set up the inflate Loading @@ -809,44 +851,95 @@ nsresult nsZipArchive::InflateItem(nsZipItem * item, PRFileDesc* outFD) return ZIP_ERR_GENERAL; //-- inflate loop zs.avail_in = item->size; zs.next_in = (Bytef*)GetData(item); if (!zs.next_in) return ZIP_ERR_CORRUPT; zs.next_out = outbuf; zs.avail_out = ZIP_BUFLEN; PRUint32 size = aItem->size; PRUint32 outpos = 0; PRUint32 crc = crc32(0L, Z_NULL, 0); int zerr = Z_OK; while (zerr == Z_OK) { zs.next_out = outbuf; zs.avail_out = ZIP_BUFLEN; PRBool bRead = PR_FALSE; PRBool bWrote= PR_FALSE; zerr = inflate(&zs, Z_PARTIAL_FLUSH); if (zerr != Z_OK && zerr != Z_STREAM_END) if (zs.avail_in == 0 && zs.total_in < size) { status = (zerr == Z_MEM_ERROR) ? ZIP_ERR_MEMORY : ZIP_ERR_CORRUPT; //-- no data to inflate yet still more in file: //-- read another chunk of compressed data PRUint32 chunk = (size-zs.total_in < ZIP_BUFLEN) ? size-zs.total_in : ZIP_BUFLEN; if (fd.Read(inbuf, chunk) != (READTYPE)chunk) { //-- unexpected end of data status = ZIP_ERR_CORRUPT; break; } PRUint32 count = zs.next_out - outbuf; //-- incrementally update crc32 crc = crc32(crc, (const unsigned char*)outbuf, count); zs.next_in = inbuf; zs.avail_in = chunk; bRead = PR_TRUE; } if (outFD && PR_Write(outFD, outbuf, count) < (READTYPE)count) if (zs.avail_out == 0) { //-- write inflated buffer to disk and make space if (outFD && PR_Write(outFD, outbuf, ZIP_BUFLEN) < ZIP_BUFLEN) { //-- Couldn't write all the data (disk full?) status = ZIP_ERR_DISK; break; } } // while //-- free zlib internal state inflateEnd(&zs); outpos = zs.total_out; zs.next_out = outbuf; zs.avail_out = ZIP_BUFLEN; bWrote = PR_TRUE; } if(bRead || bWrote) { Bytef* old_next_out = zs.next_out; zerr = inflate(&zs, Z_PARTIAL_FLUSH); //-- incrementally update crc32 crc = crc32(crc, (const unsigned char*)old_next_out, zs.next_out - old_next_out); } else zerr = Z_STREAM_END; } // while //-- verify crc32 if ((status == ZIP_OK) && (crc != item->crc32)) if ((status == ZIP_OK) && (crc != aItem->crc32)) { status = ZIP_ERR_CORRUPT; goto cleanup; } //-- write last inflated bit to disk if (zerr == Z_STREAM_END && outpos < zs.total_out) { PRUint32 chunk = zs.total_out - outpos; if (outFD && PR_Write(outFD, outbuf, chunk) < (READTYPE)chunk) status = ZIP_ERR_DISK; } //-- convert zlib error to return value if (status == ZIP_OK && zerr != Z_OK && zerr != Z_STREAM_END) { status = (zerr == Z_MEM_ERROR) ? ZIP_ERR_MEMORY : ZIP_ERR_CORRUPT; } //-- if found no errors make sure we've converted the whole thing PR_ASSERT(status != ZIP_OK || zs.total_in == aItem->size); PR_ASSERT(status != ZIP_OK || zs.total_out == aItem->realsize); cleanup: //-- free zlib internal state inflateEnd(&zs); return status; } Loading @@ -855,12 +948,12 @@ nsresult nsZipArchive::InflateItem(nsZipItem * item, PRFileDesc* outFD) //------------------------------------------ nsZipArchive::nsZipArchive() : mBuiltSynthetics(false) mBuiltSynthetics(PR_FALSE) { MOZ_COUNT_CTOR(nsZipArchive); // initialize the table to NULL memset(mFiles, 0, sizeof(mFiles)); memset(mFiles, 0, sizeof mFiles); } nsZipArchive::~nsZipArchive() Loading modules/libjar/nsZipArchive.h +97 −26 File changed.Preview size limit exceeded, changes collapsed. Show changes Loading
modules/libjar/nsJAR.cpp +1 −1 Original line number Diff line number Diff line Loading @@ -339,7 +339,7 @@ nsJAR::GetInputStreamWithSpec(const nsACString& aJarDirSpec, if (!item || item->isDirectory) { rv = jis->InitDirectory(this, aJarDirSpec, aEntryName); } else { rv = jis->InitFile(this, item); rv = jis->InitFile(mZip.GetFD(item), item); } if (NS_FAILED(rv)) { NS_RELEASE(*result); Loading
modules/libjar/nsJARInputStream.cpp +85 −51 Original line number Diff line number Diff line Loading @@ -59,42 +59,43 @@ NS_IMPL_THREADSAFE_ISUPPORTS1(nsJARInputStream, nsIInputStream) *--------------------------------------------------------*/ nsresult nsJARInputStream::InitFile(nsJAR *aJar, nsZipItem *item) nsJARInputStream::InitFile(nsZipHandle *aFd, nsZipItem *item) { nsresult rv = NS_OK; NS_ABORT_IF_FALSE(aJar, "Argument may not be null"); nsresult rv; NS_ABORT_IF_FALSE(aFd, "Argument may not be null"); NS_ABORT_IF_FALSE(item, "Argument may not be null"); // Mark it as closed, in case something fails in initialisation mClosed = true; mClosed = PR_TRUE; // Keep the important bits of nsZipItem only mInSize = item->size; //-- prepare for the compression type switch (item->compression) { case STORED: mCompressed = false; break; case DEFLATED: mCompressed = true; rv = gZlibInit(&mZs); mInflate = (InflateStruct *) PR_Malloc(sizeof(InflateStruct)); NS_ENSURE_TRUE(mInflate, NS_ERROR_OUT_OF_MEMORY); rv = gZlibInit(&(mInflate->mZs)); NS_ENSURE_SUCCESS(rv, NS_ERROR_OUT_OF_MEMORY); mOutSize = item->realsize; mInCrc = item->crc32; mOutCrc = crc32(0L, Z_NULL, 0); mInflate->mOutSize = item->realsize; mInflate->mInCrc = item->crc32; mInflate->mOutCrc = crc32(0L, Z_NULL, 0); break; default: return NS_ERROR_NOT_IMPLEMENTED; } // Must keep handle to filepointer and mmap structure as long as we need access to the mmapped data mFd = aJar->mZip.GetFD(); mZs.next_in = aJar->mZip.GetData(item); mZs.avail_in = item->size; mOutSize = item->realsize; mDirectory = false; //-- Set filepointer to start of item mFd.Open(aFd, item->dataOffset, item->size); // Open for reading mClosed = false; mClosed = PR_FALSE; mCurPos = 0; return NS_OK; } Loading @@ -108,9 +109,8 @@ nsJARInputStream::InitDirectory(nsJAR* aJar, NS_ABORT_IF_FALSE(aDir, "Argument may not be null"); // Mark it as closed, in case something fails in initialisation mClosed = true; mDirectory = true; mCompressed = false; mClosed = PR_TRUE; mDirectory = PR_TRUE; // Keep the zipReader for getting the actual zipItems mJar = aJar; Loading Loading @@ -173,7 +173,7 @@ nsJARInputStream::InitDirectory(nsJAR* aJar, mBuffer.AppendLiteral("\n200: filename content-length last-modified file-type\n"); // Open for reading mClosed = false; mClosed = PR_FALSE; mCurPos = 0; mArrPos = 0; return NS_OK; Loading @@ -187,10 +187,10 @@ nsJARInputStream::Available(PRUint32 *_retval) if (mDirectory) *_retval = mBuffer.Length(); else if (mCompressed) *_retval = mOutSize - mZs.total_out; else if (mInflate) *_retval = mInflate->mOutSize - mInflate->mZs.total_out; else *_retval = mOutSize - mCurPos; *_retval = mInSize - mCurPos; return NS_OK; } Loading @@ -202,30 +202,41 @@ nsJARInputStream::Read(char* aBuffer, PRUint32 aCount, PRUint32 *aBytesRead) *aBytesRead = 0; nsresult rv = NS_OK; if (mClosed) return NS_OK; return rv; if (mDirectory) { return ReadDirectory(aBuffer, aCount, aBytesRead); rv = ReadDirectory(aBuffer, aCount, aBytesRead); } else { if (mInflate) { rv = ContinueInflate(aBuffer, aCount, aBytesRead); } else { PRInt32 bytesRead = 0; aCount = PR_MIN(aCount, mInSize - mCurPos); if (aCount) { bytesRead = mFd.Read(aBuffer, aCount); if (bytesRead < 0) return NS_ERROR_FILE_CORRUPTED; mCurPos += bytesRead; if ((PRUint32)bytesRead != aCount) { // file is truncated or was lying about size, we're done Close(); return NS_ERROR_FILE_CORRUPTED; } } if (mCompressed) { return ContinueInflate(aBuffer, aCount, aBytesRead); *aBytesRead = bytesRead; } if (mFd) { PRUint32 count = PR_MIN(aCount, mOutSize - mCurPos); memcpy(aBuffer, mZs.next_in + mCurPos, count); mCurPos += count; *aBytesRead = count; // be aggressive about closing! // note that sometimes, we will close mFd before we've finished // deflating - this is because zlib buffers the input // So, don't free the ReadBuf/InflateStruct yet. // It is ok to close the fd multiple times (also in nsJARInputStream::Close()) if (mCurPos >= mZs.avail_in) { mFd = nsnull; if (mCurPos >= mInSize) { mFd.Close(); } } return NS_OK; return rv; } NS_IMETHODIMP Loading @@ -246,9 +257,9 @@ nsJARInputStream::IsNonBlocking(PRBool *aNonBlocking) NS_IMETHODIMP nsJARInputStream::Close() { mClosed = true; mFd = nsnull; mJar = nsnull; PR_FREEIF(mInflate); mClosed = PR_TRUE; mFd.Close(); return NS_OK; } Loading @@ -257,33 +268,56 @@ nsJARInputStream::ContinueInflate(char* aBuffer, PRUint32 aCount, PRUint32* aBytesRead) { // No need to check the args, ::Read did that, but assert them at least NS_ASSERTION(mInflate,"inflate data structure missing"); NS_ASSERTION(aBuffer,"aBuffer parameter must not be null"); NS_ASSERTION(aBytesRead,"aBytesRead parameter must not be null"); // Keep old total_out count const PRUint32 oldTotalOut = mZs.total_out; const PRUint32 oldTotalOut = mInflate->mZs.total_out; // make sure we aren't reading too much mZs.avail_out = PR_MIN(aCount, (mOutSize-oldTotalOut)); mZs.next_out = (unsigned char*)aBuffer; mInflate->mZs.avail_out = (mInflate->mOutSize-oldTotalOut > aCount) ? aCount : mInflate->mOutSize-oldTotalOut; mInflate->mZs.next_out = (unsigned char*)aBuffer; int zerr = Z_OK; //-- inflate loop while (mInflate->mZs.avail_out > 0 && zerr == Z_OK) { if (mInflate->mZs.avail_in == 0 && mCurPos < mInSize) { // time to fill the buffer! PRUint32 bytesToRead = PR_MIN(mInSize - mCurPos, ZIP_BUFLEN); PRInt32 bytesRead = mFd.Read(mInflate->mReadBuf, bytesToRead); if (bytesRead < 0) { zerr = Z_ERRNO; break; } mCurPos += bytesRead; // now set the state for 'inflate' mInflate->mZs.next_in = mInflate->mReadBuf; mInflate->mZs.avail_in = bytesRead; } // now inflate int zerr = inflate(&mZs, Z_SYNC_FLUSH); zerr = inflate(&(mInflate->mZs), Z_SYNC_FLUSH); } if ((zerr != Z_OK) && (zerr != Z_STREAM_END)) return NS_ERROR_FILE_CORRUPTED; *aBytesRead = (mZs.total_out - oldTotalOut); *aBytesRead = (mInflate->mZs.total_out - oldTotalOut); // Calculate the CRC on the output mOutCrc = crc32(mOutCrc, (unsigned char*)aBuffer, *aBytesRead); mInflate->mOutCrc = crc32(mInflate->mOutCrc, (unsigned char*)aBuffer, *aBytesRead); // be aggressive about ending the inflation // for some reason we don't always get Z_STREAM_END if (zerr == Z_STREAM_END || mZs.total_out == mOutSize) { inflateEnd(&mZs); if (zerr == Z_STREAM_END || mInflate->mZs.total_out == mInflate->mOutSize) { inflateEnd(&(mInflate->mZs)); // stop returning valid data as soon as we know we have a bad CRC if (mOutCrc != mInCrc) { if (mInflate->mOutCrc != mInflate->mInCrc) { // asserting because while this rarely happens, you definitely // want to catch it in debug builds! NS_NOTREACHED(0); Loading
modules/libjar/nsJARInputStream.h +25 −19 Original line number Diff line number Diff line Loading @@ -53,39 +53,45 @@ class nsJARInputStream : public nsIInputStream { public: nsJARInputStream() : mCurPos(0), mCompressed(false), mDirectory(false), mClosed(true) mInSize(0), mCurPos(0), mInflate(nsnull), mDirectory(0), mClosed(PR_FALSE) { } ~nsJARInputStream() { Close(); } ~nsJARInputStream() { Close(); } NS_DECL_ISUPPORTS NS_DECL_NSIINPUTSTREAM // takes ownership of |fd|, even on failure nsresult InitFile(nsJAR *aJar, nsZipItem *item); nsresult InitFile(nsZipHandle *aFd, nsZipItem *item); nsresult InitDirectory(nsJAR *aJar, const nsACString& aJarDirSpec, const char* aDir); private: nsRefPtr<nsZipHandle> mFd; // handle for reading PRUint32 mInSize; // Size in original file PRUint32 mCurPos; // Current position in input struct InflateStruct { PRUint32 mOutSize; // inflated size PRUint32 mInCrc; // CRC as provided by the zipentry PRUint32 mOutCrc; // CRC as calculated by me z_stream mZs; // zip data structure unsigned char mReadBuf[ZIP_BUFLEN]; // Readbuffer to inflate from }; struct InflateStruct * mInflate; /* For directory reading */ nsRefPtr<nsJAR> mJar; // string reference to zipreader PRUint32 mNameLen; // length of dirname nsCString mBuffer; // storage for generated text of stream nsCAutoString mBuffer; // storage for generated text of stream PRUint32 mArrPos; // current position within mArray nsTArray<nsCString> mArray; // array of names in (zip) directory bool mCompressed; // is this compressed? bool mDirectory; // is this a directory? bool mClosed; // Whether the stream is closed PRPackedBool mDirectory; // is this a directory? PRPackedBool mClosed; // Whether the stream is closed nsSeekableZipHandle mFd; // handle for reading nsresult ContinueInflate(char* aBuf, PRUint32 aCount, PRUint32* aBytesRead); nsresult ReadDirectory(char* aBuf, PRUint32 aCount, PRUint32* aBytesRead); Loading
modules/libjar/nsZipArchive.cpp +169 −76 Original line number Diff line number Diff line Loading @@ -50,6 +50,7 @@ */ #define ZFILE_CREATE PR_WRONLY | PR_CREATE_FILE #define READTYPE PRInt32 #include "zlib.h" #include "nsISupportsUtils.h" Loading Loading @@ -227,14 +228,13 @@ nsresult nsZipHandle::Init(PRFileDesc *fd, nsZipHandle **ret) return NS_ERROR_FILE_TOO_BIG; PRFileMap *map = PR_CreateFileMap(fd, size, PR_PROT_READONLY); if (!map) return NS_ERROR_FAILURE; nsZipHandle *handle = new nsZipHandle(); if (!handle) { PR_CloseFileMap(map); if (!handle) return NS_ERROR_OUT_OF_MEMORY; } handle->mFd = fd; handle->mMap = map; Loading @@ -245,17 +245,22 @@ nsresult nsZipHandle::Init(PRFileDesc *fd, nsZipHandle **ret) return NS_OK; } PRInt32 nsZipHandle::Read(PRUint32 aPosition, void *aBuffer, PRUint32 aCount) { if (mLen < 0 || aPosition+aCount > (PRUint32) mLen) return -1; PRInt32 count = PR_MIN(aCount, mLen - aPosition); memcpy(aBuffer, mFileData + aPosition, count); return count; } nsZipHandle::~nsZipHandle() { if (mFileData) { if (mFd) { PR_MemUnmap(mFileData, mLen); PR_CloseFileMap(mMap); mFileData = nsnull; mMap = nsnull; } if (mFd) { PR_Close(mFd); mFd = nsnull; mFd = 0; } MOZ_COUNT_DTOR(nsZipHandle); } Loading Loading @@ -321,7 +326,6 @@ nsresult nsZipArchive::CloseArchive() { if (mFd) { PL_FinishArenaPool(&mArena); mFd = NULL; } // CAUTION: Loading @@ -331,8 +335,11 @@ nsresult nsZipArchive::CloseArchive() // for all the nsZipItem in one shot. But if the ~nsZipItem is doing // anything more than cleaning up memory, we should start calling it. // Let us also cleanup the mFiles table for re-use on the next 'open' call memset(mFiles, 0, sizeof(mFiles)); mBuiltSynthetics = false; for (int i = 0; i < ZIP_TABSIZE; i++) { mFiles[i] = 0; } mFd = NULL; mBuiltSynthetics = PR_FALSE; return ZIP_OK; } Loading Loading @@ -381,17 +388,25 @@ nsresult nsZipArchive::ExtractFile(nsZipItem *item, const char *outname, // so the item to be extracted should never be a directory PR_ASSERT(!item->isDirectory); //-- move to the start of file's data if (!MaybeReadItem(item)) return ZIP_ERR_CORRUPT; nsSeekableZipHandle fd; if (!fd.Open(mFd.get(), item->dataOffset, item->size)) return ZIP_ERR_CORRUPT; nsresult rv; //-- extract the file using the appropriate method switch(item->compression) { case STORED: rv = CopyItemToDisk(item, aFd); rv = CopyItemToDisk(item->size, item->crc32, fd, aFd); break; case DEFLATED: rv = InflateItem(item, aFd); rv = InflateItem(item, fd, aFd); break; default: Loading Loading @@ -592,12 +607,14 @@ nsresult nsZipArchive::BuildFileList() return ZIP_ERR_MEMORY; item->headerOffset = xtolong(central->localhdr_offset); item->dataOffset = 0; item->size = xtolong(central->size); item->realsize = xtolong(central->orglen); item->crc32 = xtolong(central->crc32); item->time = xtoint(central->time); item->date = xtoint(central->date); item->isSynthetic = PR_FALSE; item->hasDataOffset = PR_FALSE; item->compression = PR_MIN(xtoint(central->method), UNSUPPORTED); item->mode = ExtractMode(central->external_attributes); #if defined(XP_UNIX) || defined(XP_BEOS) Loading Loading @@ -635,7 +652,7 @@ nsresult nsZipArchive::BuildSynthetics() { if (mBuiltSynthetics) return ZIP_OK; mBuiltSynthetics = true; mBuiltSynthetics = PR_TRUE; // Create synthetic entries for any missing directories. // Do this when all ziptable has scanned to prevent double entries. Loading Loading @@ -720,68 +737,91 @@ nsresult nsZipArchive::BuildSynthetics() return ZIP_OK; } nsZipHandle* nsZipArchive::GetFD() nsZipHandle* nsZipArchive::GetFD(nsZipItem* aItem) { if (!mFd) if (!mFd || !MaybeReadItem(aItem)) return NULL; return mFd.get(); } //--------------------------------------------- // nsZipArchive::GetData // nsZipArchive::MaybeReadItem //--------------------------------------------- PRUint8* nsZipArchive::GetData(nsZipItem* aItem) bool nsZipArchive::MaybeReadItem(nsZipItem* aItem) { PR_ASSERT (aItem); //-- the first time an item is used we need to calculate its offset if (!aItem->hasDataOffset) { //-- read local header to get variable length values and calculate //-- the real data offset if (aItem->headerOffset + ZIPLOCAL_SIZE > mFd->mLen) return nsnull; //-- //-- NOTE: extralen is different in central header and local header //-- for archives created using the Unix "zip" utility. To set //-- the offset accurately we need the _local_ extralen. if (!mFd || !mFd->mLen > aItem->headerOffset + ZIPLOCAL_SIZE) return false; // -- check signature before using the structure, in case the zip file is corrupt ZipLocal *Local = (ZipLocal*)(mFd->mFileData + aItem->headerOffset); //check limits here if ((xtolong(Local->signature) != LOCALSIG)) return nsnull; { //-- read error or local header not found return false; } //-- NOTE: extralen is different in central header and local header //-- for archives created using the Unix "zip" utility. To set //-- the offset accurately we need the _local_ extralen. PRUint32 dataOffset = aItem->headerOffset + aItem->dataOffset = aItem->headerOffset + ZIPLOCAL_SIZE + xtoint(Local->filename_len) + xtoint(Local->extrafield_len); aItem->hasDataOffset = PR_TRUE; } // -- check if there is enough source data in the file if (dataOffset + aItem->size > mFd->mLen) return nsnull; return mFd->mFileData + dataOffset; return true; } //--------------------------------------------- // nsZipArchive::CopyItemToDisk //--------------------------------------------- nsresult nsZipArchive::CopyItemToDisk(nsZipItem *item, PRFileDesc* outFD) nsZipArchive::CopyItemToDisk(PRUint32 itemSize, PRUint32 itemCrc, nsSeekableZipHandle &fd, PRFileDesc* outFD) /* * This function copies an archive item to disk, to the * file specified by outFD. If outFD is zero, the extracted data is * not written, only checked for CRC, so this is in effect same as 'Test'. */ { PR_ASSERT(item); PRUint32 chunk, pos, crc; char buf[ZIP_BUFLEN]; //-- initialize crc crc = crc32(0L, Z_NULL, 0); //-- get to the start of file's data const PRUint8* itemData = GetData(item); if (!itemData) //-- copy chunks until file is done for (pos = 0; pos < itemSize; pos += chunk) { chunk = (itemSize - pos < ZIP_BUFLEN) ? (itemSize - pos) : ZIP_BUFLEN; if (fd.Read(buf, chunk) != (READTYPE)chunk) { //-- unexpected end of data in archive return ZIP_ERR_CORRUPT; } //-- incrementally update crc32 crc = crc32(crc, (const unsigned char*)buf, chunk); if (outFD && PR_Write(outFD, itemData, item->size) < (READTYPE)item->size) if (outFD && PR_Write(outFD, buf, chunk) < (READTYPE)chunk) { //-- Couldn't write all the data (disk full?) return ZIP_ERR_DISK; } } //-- Calculate crc PRUint32 crc = crc32(0L, (const unsigned char*)itemData, item->size); //-- verify crc32 if (crc != item->crc32) if (crc != itemCrc) return ZIP_ERR_CORRUPT; return ZIP_OK; Loading @@ -791,15 +831,17 @@ nsZipArchive::CopyItemToDisk(nsZipItem *item, PRFileDesc* outFD) //--------------------------------------------- // nsZipArchive::InflateItem //--------------------------------------------- nsresult nsZipArchive::InflateItem(nsZipItem * item, PRFileDesc* outFD) nsresult nsZipArchive::InflateItem(const nsZipItem* aItem, nsSeekableZipHandle &fd, PRFileDesc* outFD) /* * This function inflates an archive item to disk, to the * file specified by outFD. If outFD is zero, the extracted data is * not written, only checked for CRC, so this is in effect same as 'Test'. */ { PR_ASSERT(item); PR_ASSERT(aItem); //-- allocate deflation buffers Bytef inbuf[ZIP_BUFLEN]; Bytef outbuf[ZIP_BUFLEN]; //-- set up the inflate Loading @@ -809,44 +851,95 @@ nsresult nsZipArchive::InflateItem(nsZipItem * item, PRFileDesc* outFD) return ZIP_ERR_GENERAL; //-- inflate loop zs.avail_in = item->size; zs.next_in = (Bytef*)GetData(item); if (!zs.next_in) return ZIP_ERR_CORRUPT; zs.next_out = outbuf; zs.avail_out = ZIP_BUFLEN; PRUint32 size = aItem->size; PRUint32 outpos = 0; PRUint32 crc = crc32(0L, Z_NULL, 0); int zerr = Z_OK; while (zerr == Z_OK) { zs.next_out = outbuf; zs.avail_out = ZIP_BUFLEN; PRBool bRead = PR_FALSE; PRBool bWrote= PR_FALSE; zerr = inflate(&zs, Z_PARTIAL_FLUSH); if (zerr != Z_OK && zerr != Z_STREAM_END) if (zs.avail_in == 0 && zs.total_in < size) { status = (zerr == Z_MEM_ERROR) ? ZIP_ERR_MEMORY : ZIP_ERR_CORRUPT; //-- no data to inflate yet still more in file: //-- read another chunk of compressed data PRUint32 chunk = (size-zs.total_in < ZIP_BUFLEN) ? size-zs.total_in : ZIP_BUFLEN; if (fd.Read(inbuf, chunk) != (READTYPE)chunk) { //-- unexpected end of data status = ZIP_ERR_CORRUPT; break; } PRUint32 count = zs.next_out - outbuf; //-- incrementally update crc32 crc = crc32(crc, (const unsigned char*)outbuf, count); zs.next_in = inbuf; zs.avail_in = chunk; bRead = PR_TRUE; } if (outFD && PR_Write(outFD, outbuf, count) < (READTYPE)count) if (zs.avail_out == 0) { //-- write inflated buffer to disk and make space if (outFD && PR_Write(outFD, outbuf, ZIP_BUFLEN) < ZIP_BUFLEN) { //-- Couldn't write all the data (disk full?) status = ZIP_ERR_DISK; break; } } // while //-- free zlib internal state inflateEnd(&zs); outpos = zs.total_out; zs.next_out = outbuf; zs.avail_out = ZIP_BUFLEN; bWrote = PR_TRUE; } if(bRead || bWrote) { Bytef* old_next_out = zs.next_out; zerr = inflate(&zs, Z_PARTIAL_FLUSH); //-- incrementally update crc32 crc = crc32(crc, (const unsigned char*)old_next_out, zs.next_out - old_next_out); } else zerr = Z_STREAM_END; } // while //-- verify crc32 if ((status == ZIP_OK) && (crc != item->crc32)) if ((status == ZIP_OK) && (crc != aItem->crc32)) { status = ZIP_ERR_CORRUPT; goto cleanup; } //-- write last inflated bit to disk if (zerr == Z_STREAM_END && outpos < zs.total_out) { PRUint32 chunk = zs.total_out - outpos; if (outFD && PR_Write(outFD, outbuf, chunk) < (READTYPE)chunk) status = ZIP_ERR_DISK; } //-- convert zlib error to return value if (status == ZIP_OK && zerr != Z_OK && zerr != Z_STREAM_END) { status = (zerr == Z_MEM_ERROR) ? ZIP_ERR_MEMORY : ZIP_ERR_CORRUPT; } //-- if found no errors make sure we've converted the whole thing PR_ASSERT(status != ZIP_OK || zs.total_in == aItem->size); PR_ASSERT(status != ZIP_OK || zs.total_out == aItem->realsize); cleanup: //-- free zlib internal state inflateEnd(&zs); return status; } Loading @@ -855,12 +948,12 @@ nsresult nsZipArchive::InflateItem(nsZipItem * item, PRFileDesc* outFD) //------------------------------------------ nsZipArchive::nsZipArchive() : mBuiltSynthetics(false) mBuiltSynthetics(PR_FALSE) { MOZ_COUNT_CTOR(nsZipArchive); // initialize the table to NULL memset(mFiles, 0, sizeof(mFiles)); memset(mFiles, 0, sizeof mFiles); } nsZipArchive::~nsZipArchive() Loading
modules/libjar/nsZipArchive.h +97 −26 File changed.Preview size limit exceeded, changes collapsed. Show changes