mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 504864 - mmap io for JARs; r=benjamin
This commit is contained in:
parent
7b5cd072e9
commit
ed2f94b3a5
@ -122,7 +122,6 @@ nsJAR::nsJAR(): mManifestData(nsnull, nsnull, DeleteManifestEntry, nsnull, 10),
|
||||
mReleaseTime(PR_INTERVAL_NO_TIMEOUT),
|
||||
mCache(nsnull),
|
||||
mLock(nsnull),
|
||||
mMtime(0),
|
||||
mTotalItemsInManifest(0)
|
||||
{
|
||||
}
|
||||
@ -167,8 +166,6 @@ nsJAR::Open(nsIFile* zipFile)
|
||||
if (mLock) return NS_ERROR_FAILURE; // Already open!
|
||||
|
||||
mZipFile = zipFile;
|
||||
nsresult rv = zipFile->GetLastModifiedTime(&mMtime);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
mLock = PR_NewLock();
|
||||
NS_ENSURE_TRUE(mLock, NS_ERROR_OUT_OF_MEMORY);
|
||||
@ -176,7 +173,7 @@ nsJAR::Open(nsIFile* zipFile)
|
||||
PRFileDesc *fd = OpenFile();
|
||||
NS_ENSURE_TRUE(fd, NS_ERROR_FAILURE);
|
||||
|
||||
rv = mZip.OpenArchive(fd);
|
||||
nsresult rv = mZip.OpenArchive(fd);
|
||||
if (NS_FAILED(rv)) Close();
|
||||
|
||||
return rv;
|
||||
@ -340,19 +337,9 @@ nsJAR::GetInputStreamWithSpec(const nsACString& aJarDirSpec,
|
||||
|
||||
nsresult rv = NS_OK;
|
||||
if (!item || item->isDirectory) {
|
||||
rv = jis->InitDirectory(&mZip, aJarDirSpec, aEntryName);
|
||||
rv = jis->InitDirectory(this, aJarDirSpec, aEntryName);
|
||||
} else {
|
||||
// Open jarfile, to get its own filedescriptor for the stream
|
||||
// XXX The file may have been overwritten, so |item| might not be
|
||||
// valid. We really want to work from inode rather than file name.
|
||||
PRFileDesc *fd = nsnull;
|
||||
fd = OpenFile();
|
||||
if (fd) {
|
||||
rv = jis->InitFile(&mZip, item, fd);
|
||||
// |jis| now owns |fd|
|
||||
} else {
|
||||
rv = NS_ERROR_FAILURE;
|
||||
}
|
||||
rv = jis->InitFile(mZip.GetFD(item), item);
|
||||
}
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_RELEASE(*result);
|
||||
@ -1113,13 +1100,9 @@ nsZipReaderCache::GetZip(nsIFile* zipFile, nsIZipReader* *result)
|
||||
rv = zipFile->GetNativePath(path);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
PRInt64 Mtime;
|
||||
rv = zipFile->GetLastModifiedTime(&Mtime);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
nsCStringKey key(path);
|
||||
nsJAR* zip = static_cast<nsJAR*>(static_cast<nsIZipReader*>(mZips.Get(&key))); // AddRefs
|
||||
if (zip && Mtime == zip->GetMtime()) {
|
||||
if (zip) {
|
||||
#ifdef ZIP_CACHE_HIT_RATE
|
||||
mZipCacheHits++;
|
||||
#endif
|
||||
|
@ -133,10 +133,6 @@ class nsJAR : public nsIZipReader, public nsIJAR
|
||||
mCache = cache;
|
||||
}
|
||||
|
||||
PRInt64 GetMtime() {
|
||||
return mMtime;
|
||||
}
|
||||
|
||||
protected:
|
||||
//-- Private data members
|
||||
nsCOMPtr<nsIFile> mZipFile; // The zip/jar file on disk
|
||||
|
@ -23,6 +23,7 @@
|
||||
*
|
||||
* Contributor(s):
|
||||
* Mitch Stoltz <mstoltz@netscape.com>
|
||||
* Taras Glek <tglek@mozilla.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
@ -45,6 +46,7 @@
|
||||
#include "nsNetUtil.h"
|
||||
#include "nsEscape.h"
|
||||
#include "nsIFile.h"
|
||||
#include "nsDebug.h"
|
||||
|
||||
/*---------------------------------------------
|
||||
* nsISupports implementation
|
||||
@ -57,20 +59,14 @@ NS_IMPL_THREADSAFE_ISUPPORTS1(nsJARInputStream, nsIInputStream)
|
||||
*--------------------------------------------------------*/
|
||||
|
||||
nsresult
|
||||
nsJARInputStream::InitFile(nsZipArchive* aZip, nsZipItem *item, PRFileDesc *fd)
|
||||
nsJARInputStream::InitFile(nsZipHandle *aFd, nsZipItem *item)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
// Keep the file handle, even on failure
|
||||
mFd = fd;
|
||||
|
||||
NS_ENSURE_ARG_POINTER(aZip);
|
||||
NS_ENSURE_ARG_POINTER(item);
|
||||
NS_ENSURE_ARG_POINTER(fd);
|
||||
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 = PR_TRUE;
|
||||
|
||||
// Keep the important bits of nsZipItem only
|
||||
mInSize = item->size;
|
||||
|
||||
@ -96,8 +92,7 @@ nsJARInputStream::InitFile(nsZipArchive* aZip, nsZipItem *item, PRFileDesc *fd)
|
||||
}
|
||||
|
||||
//-- Set filepointer to start of item
|
||||
rv = aZip->SeekToItem(item, mFd);
|
||||
NS_ENSURE_SUCCESS(rv, NS_ERROR_FILE_CORRUPTED);
|
||||
mFd.Open(aFd, item->dataOffset, item->size);
|
||||
|
||||
// Open for reading
|
||||
mClosed = PR_FALSE;
|
||||
@ -106,19 +101,19 @@ nsJARInputStream::InitFile(nsZipArchive* aZip, nsZipItem *item, PRFileDesc *fd)
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsJARInputStream::InitDirectory(nsZipArchive* aZip,
|
||||
nsJARInputStream::InitDirectory(nsJAR* aJar,
|
||||
const nsACString& aJarDirSpec,
|
||||
const char* aDir)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aZip);
|
||||
NS_ENSURE_ARG_POINTER(aDir);
|
||||
NS_ABORT_IF_FALSE(aJar, "Argument may not be null");
|
||||
NS_ABORT_IF_FALSE(aDir, "Argument may not be null");
|
||||
|
||||
// Mark it as closed, in case something fails in initialisation
|
||||
mClosed = PR_TRUE;
|
||||
mDirectory = PR_TRUE;
|
||||
|
||||
// Keep the zipReader for getting the actual zipItems
|
||||
mZip = aZip;
|
||||
mJar = aJar;
|
||||
nsZipFind *find;
|
||||
nsresult rv;
|
||||
// We can get aDir's contents as strings via FindEntries
|
||||
@ -156,7 +151,7 @@ nsJARInputStream::InitDirectory(nsZipArchive* aZip,
|
||||
}
|
||||
nsCAutoString pattern = escDirName + NS_LITERAL_CSTRING("?*~") +
|
||||
escDirName + NS_LITERAL_CSTRING("?*/?*");
|
||||
rv = aZip->FindInit(pattern.get(), &find);
|
||||
rv = mJar->mZip.FindInit(pattern.get(), &find);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
const char *name;
|
||||
@ -220,27 +215,25 @@ nsJARInputStream::Read(char* aBuffer, PRUint32 aCount, PRUint32 *aBytesRead)
|
||||
PRInt32 bytesRead = 0;
|
||||
aCount = PR_MIN(aCount, mInSize - mCurPos);
|
||||
if (aCount) {
|
||||
bytesRead = PR_Read(mFd, aBuffer, aCount);
|
||||
bytesRead = mFd.Read(aBuffer, aCount);
|
||||
if (bytesRead < 0)
|
||||
return NS_ERROR_FILE_CORRUPTED;
|
||||
mCurPos += bytesRead;
|
||||
if (bytesRead != aCount) {
|
||||
if ((PRUint32)bytesRead != aCount) {
|
||||
// file is truncated or was lying about size, we're done
|
||||
PR_Close(mFd);
|
||||
mFd = nsnull;
|
||||
Close();
|
||||
return NS_ERROR_FILE_CORRUPTED;
|
||||
}
|
||||
}
|
||||
*aBytesRead = bytesRead;
|
||||
}
|
||||
|
||||
// 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.
|
||||
if (mCurPos >= mInSize && mFd) {
|
||||
PR_Close(mFd);
|
||||
mFd = nsnull;
|
||||
// It is ok to close the fd multiple times (also in nsJARInputStream::Close())
|
||||
if (mCurPos >= mInSize) {
|
||||
mFd.Close();
|
||||
}
|
||||
}
|
||||
return rv;
|
||||
@ -265,11 +258,8 @@ NS_IMETHODIMP
|
||||
nsJARInputStream::Close()
|
||||
{
|
||||
PR_FREEIF(mInflate);
|
||||
if (mFd) {
|
||||
PR_Close(mFd);
|
||||
mFd = nsnull;
|
||||
}
|
||||
mClosed = PR_TRUE;
|
||||
mFd.Close();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -297,8 +287,7 @@ nsJARInputStream::ContinueInflate(char* aBuffer, PRUint32 aCount,
|
||||
// time to fill the buffer!
|
||||
PRUint32 bytesToRead = PR_MIN(mInSize - mCurPos, ZIP_BUFLEN);
|
||||
|
||||
NS_ASSERTION(mFd, "File handle missing");
|
||||
PRInt32 bytesRead = PR_Read(mFd, mInflate->mReadBuf, bytesToRead);
|
||||
PRInt32 bytesRead = mFd.Read(mInflate->mReadBuf, bytesToRead);
|
||||
if (bytesRead < 0) {
|
||||
zerr = Z_ERRNO;
|
||||
break;
|
||||
@ -362,7 +351,7 @@ nsJARInputStream::ReadDirectory(char* aBuffer, PRUint32 aCount, PRUint32 *aBytes
|
||||
|
||||
const char * entryName = mArray[mArrPos].get();
|
||||
PRUint32 entryNameLen = mArray[mArrPos].Length();
|
||||
nsZipItem* ze = mZip->GetItem(entryName);
|
||||
nsZipItem* ze = mJar->mZip.GetItem(entryName);
|
||||
NS_ENSURE_TRUE(ze, NS_ERROR_FILE_TARGET_DOES_NOT_EXIST);
|
||||
|
||||
// Last Modified Time
|
||||
|
@ -53,23 +53,24 @@ class nsJARInputStream : public nsIInputStream
|
||||
{
|
||||
public:
|
||||
nsJARInputStream() :
|
||||
mFd(nsnull), mInSize(0), mCurPos(0),
|
||||
mInflate(nsnull), mDirectory(0), mClosed(PR_FALSE) { }
|
||||
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(nsZipArchive* aZip, nsZipItem *item, PRFileDesc *fd);
|
||||
nsresult InitFile(nsZipHandle *aFd, nsZipItem *item);
|
||||
|
||||
nsresult InitDirectory(nsZipArchive* aZip,
|
||||
nsresult InitDirectory(nsJAR *aJar,
|
||||
const nsACString& aJarDirSpec,
|
||||
const char* aDir);
|
||||
|
||||
private:
|
||||
PRFileDesc* mFd; // My own file handle, for reading
|
||||
PRUint32 mInSize; // Size in original file
|
||||
PRUint32 mCurPos; // Current position in input
|
||||
|
||||
@ -83,14 +84,14 @@ class nsJARInputStream : public nsIInputStream
|
||||
struct InflateStruct * mInflate;
|
||||
|
||||
/* For directory reading */
|
||||
nsZipArchive* mZip; // the zipReader
|
||||
nsRefPtr<nsJAR> mJar; // string reference to zipreader
|
||||
PRUint32 mNameLen; // length of dirname
|
||||
nsCAutoString mBuffer; // storage for generated text of stream
|
||||
PRUint32 mArrPos; // current position within mArray
|
||||
nsTArray<nsCString> mArray; // array of names in (zip) directory
|
||||
|
||||
PRPackedBool mDirectory;
|
||||
PRPackedBool 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);
|
||||
|
@ -26,6 +26,7 @@
|
||||
* Mitch Stoltz <mstoltz@netscape.com>
|
||||
* Jeroen Dobbelaere <jeroen.dobbelaere@acunia.com>
|
||||
* Jeff Walden <jwalden+code@mit.edu>
|
||||
* Taras Glek <tglek@mozilla.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
@ -49,17 +50,19 @@
|
||||
*/
|
||||
|
||||
|
||||
#include "nsWildCard.h"
|
||||
#include "nscore.h"
|
||||
#include "prmem.h"
|
||||
#include "prio.h"
|
||||
#include "plstr.h"
|
||||
#include "prlog.h"
|
||||
#define ZFILE_CREATE PR_WRONLY | PR_CREATE_FILE
|
||||
#define READTYPE PRInt32
|
||||
#include "zlib.h"
|
||||
#include "nsISupportsUtils.h"
|
||||
#include "nsRecyclingAllocator.h"
|
||||
#include "prio.h"
|
||||
#include "plstr.h"
|
||||
#include "prlog.h"
|
||||
#include "stdlib.h"
|
||||
#include "nsWildCard.h"
|
||||
#include "zipfile.h"
|
||||
#include "zipstruct.h"
|
||||
#include "nsZipArchive.h"
|
||||
|
||||
/**
|
||||
* Globals
|
||||
@ -205,6 +208,60 @@ nsresult gZlibInit(z_stream *zs)
|
||||
return ZIP_OK;
|
||||
}
|
||||
|
||||
nsZipHandle::nsZipHandle()
|
||||
: mFd(nsnull)
|
||||
, mFileData(nsnull)
|
||||
, mLen(0)
|
||||
, mMap(nsnull)
|
||||
, mRefCnt(1)
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMPL_THREADSAFE_ADDREF(nsZipHandle)
|
||||
NS_IMPL_THREADSAFE_RELEASE(nsZipHandle)
|
||||
|
||||
nsresult nsZipHandle::Init(PRFileDesc *fd, nsZipHandle **ret)
|
||||
{
|
||||
PRInt64 size = PR_Available64(fd);
|
||||
if (size >= PR_INT32_MAX)
|
||||
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)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
handle->mFd = fd;
|
||||
handle->mMap = map;
|
||||
handle->mLen = (PRUint32) size;
|
||||
handle->mFileData = (PRUint8*) PR_MemMap(map, 0, handle->mLen);
|
||||
*ret = handle;
|
||||
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 (mFd) {
|
||||
PR_MemUnmap(mFileData, mLen);
|
||||
PR_CloseFileMap(mMap);
|
||||
PR_Close(mFd);
|
||||
mFd = 0;
|
||||
}
|
||||
}
|
||||
|
||||
//***********************************************************
|
||||
// nsZipArchive -- public methods
|
||||
//***********************************************************
|
||||
@ -215,15 +272,13 @@ nsresult gZlibInit(z_stream *zs)
|
||||
//---------------------------------------------
|
||||
nsresult nsZipArchive::OpenArchive(PRFileDesc * fd)
|
||||
{
|
||||
if (!fd)
|
||||
return ZIP_ERR_PARAM;
|
||||
nsresult rv = nsZipHandle::Init(fd, getter_AddRefs(mFd));
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
// Initialize our arena
|
||||
PL_INIT_ARENA_POOL(&mArena, "ZipArena", ZIP_ARENABLOCKSIZE);
|
||||
|
||||
//-- Keep the filedescriptor for further reading...
|
||||
mFd = fd;
|
||||
|
||||
//-- get table of contents for archive
|
||||
return BuildFileList();
|
||||
}
|
||||
@ -280,10 +335,7 @@ nsresult nsZipArchive::CloseArchive()
|
||||
for (int i = 0; i < ZIP_TABSIZE; i++) {
|
||||
mFiles[i] = 0;
|
||||
}
|
||||
if (mFd) {
|
||||
PR_Close(mFd);
|
||||
mFd = 0;
|
||||
}
|
||||
mFd = NULL;
|
||||
mBuiltSynthetics = PR_FALSE;
|
||||
return ZIP_OK;
|
||||
}
|
||||
@ -334,7 +386,11 @@ nsresult nsZipArchive::ExtractFile(nsZipItem *item, const char *outname,
|
||||
PR_ASSERT(!item->isDirectory);
|
||||
|
||||
//-- move to the start of file's data
|
||||
if (SeekToItem(item, mFd) != ZIP_OK)
|
||||
if (MaybeReadItem(item) != ZIP_OK)
|
||||
return ZIP_ERR_CORRUPT;
|
||||
|
||||
nsSeekableZipHandle fd;
|
||||
if (!fd.Open(mFd.get(), item->headerOffset, item->size))
|
||||
return ZIP_ERR_CORRUPT;
|
||||
|
||||
nsresult rv;
|
||||
@ -343,11 +399,11 @@ nsresult nsZipArchive::ExtractFile(nsZipItem *item, const char *outname,
|
||||
switch(item->compression)
|
||||
{
|
||||
case STORED:
|
||||
rv = CopyItemToDisk(item->size, item->crc32, aFd);
|
||||
rv = CopyItemToDisk(item->size, item->crc32, fd, aFd);
|
||||
break;
|
||||
|
||||
case DEFLATED:
|
||||
rv = InflateItem(item, aFd);
|
||||
rv = InflateItem(item, fd, aFd);
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -509,29 +565,22 @@ nsZipItem* nsZipArchive::CreateZipItem(PRUint16 namelen)
|
||||
//---------------------------------------------
|
||||
nsresult nsZipArchive::BuildFileList()
|
||||
{
|
||||
PRUint8 buf[4*BR_BUF_SIZE];
|
||||
|
||||
PRUint8 *buf;
|
||||
//-----------------------------------------------------------------------
|
||||
// locate the central directory via the End record
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
//-- get archive size using end pos
|
||||
PRInt32 pos = PR_Seek(mFd, 0, PR_SEEK_END);
|
||||
if (pos <= 0)
|
||||
return ZIP_ERR_CORRUPT;
|
||||
PRInt32 pos = (PRInt32) mFd->mLen;
|
||||
|
||||
PRBool bEndsigFound = PR_FALSE;
|
||||
while (!bEndsigFound)
|
||||
PRInt32 central = -1;
|
||||
while (central == -1)
|
||||
{
|
||||
//-- read backwards in 1K-sized chunks (unless file is less than 1K)
|
||||
PRInt32 bufsize = pos > BR_BUF_SIZE ? BR_BUF_SIZE : pos;
|
||||
pos -= bufsize;
|
||||
|
||||
if (!ZIP_Seek(mFd, pos, PR_SEEK_SET))
|
||||
return ZIP_ERR_CORRUPT;
|
||||
|
||||
if (PR_Read(mFd, buf, bufsize) != (READTYPE)bufsize)
|
||||
return ZIP_ERR_CORRUPT;
|
||||
buf = mFd->mFileData + pos;
|
||||
|
||||
//-- scan for ENDSIG
|
||||
PRUint8 *endp = buf + bufsize;
|
||||
@ -540,16 +589,12 @@ nsresult nsZipArchive::BuildFileList()
|
||||
if (xtolong(endp) == ENDSIG)
|
||||
{
|
||||
//-- Seek to start of central directory
|
||||
PRInt32 central = xtolong(((ZipEnd *) endp)->offset_central_dir);
|
||||
if (!ZIP_Seek(mFd, central, PR_SEEK_SET))
|
||||
return ZIP_ERR_CORRUPT;
|
||||
|
||||
bEndsigFound = PR_TRUE;
|
||||
central = xtolong(((ZipEnd *) endp)->offset_central_dir);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (bEndsigFound)
|
||||
if (central != -1)
|
||||
break;
|
||||
|
||||
if (pos <= 0)
|
||||
@ -566,7 +611,8 @@ nsresult nsZipArchive::BuildFileList()
|
||||
//-------------------------------------------------------
|
||||
// read the central directory headers
|
||||
//-------------------------------------------------------
|
||||
PRInt32 byteCount = PR_Read(mFd, &buf, sizeof(buf));
|
||||
PRInt32 byteCount = mFd->mLen - central;
|
||||
buf = mFd->mFileData + central;
|
||||
pos = 0;
|
||||
PRUint32 sig = xtolong(buf);
|
||||
while (sig == CENTRALSIG) {
|
||||
@ -613,31 +659,11 @@ nsresult nsZipArchive::BuildFileList()
|
||||
#endif
|
||||
|
||||
pos += ZIPCENTRAL_SIZE;
|
||||
|
||||
//-------------------------------------------------------
|
||||
// Make sure that remainder of this record (name, comments, extra)
|
||||
// and the next ZipCentral is all in the buffer
|
||||
//-------------------------------------------------------
|
||||
PRInt32 leftover = byteCount - pos;
|
||||
if (leftover < (namelen + extralen + commentlen + ZIPCENTRAL_SIZE)) {
|
||||
//-- not enough data left to process at top of loop.
|
||||
//-- move leftover and read more
|
||||
memcpy(buf, buf+pos, leftover);
|
||||
byteCount = leftover + PR_Read(mFd, buf+leftover, sizeof(buf)-leftover);
|
||||
pos = 0;
|
||||
|
||||
if (byteCount < (namelen + extralen + commentlen + sizeof(sig))) {
|
||||
// truncated file
|
||||
return ZIP_ERR_CORRUPT;
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------
|
||||
// get the item name
|
||||
//-------------------------------------------------------
|
||||
memcpy(item->name, buf+pos, namelen);
|
||||
item->name[namelen] = 0;
|
||||
|
||||
//-- an item whose name ends with '/' is a directory
|
||||
item->isDirectory = ('/' == item->name[namelen - 1]);
|
||||
|
||||
@ -758,11 +784,17 @@ nsresult nsZipArchive::BuildSynthetics()
|
||||
return ZIP_OK;
|
||||
}
|
||||
|
||||
nsZipHandle* nsZipArchive::GetFD(nsZipItem* aItem)
|
||||
{
|
||||
if (!mFd || !MaybeReadItem(aItem))
|
||||
return NULL;
|
||||
return mFd.get();
|
||||
}
|
||||
|
||||
//---------------------------------------------
|
||||
// nsZipArchive::SeekToItem
|
||||
// nsZipArchive::MaybeReadItem
|
||||
//---------------------------------------------
|
||||
nsresult nsZipArchive::SeekToItem(nsZipItem* aItem, PRFileDesc* aFd)
|
||||
bool nsZipArchive::MaybeReadItem(nsZipItem* aItem)
|
||||
{
|
||||
PR_ASSERT (aItem);
|
||||
|
||||
@ -775,36 +807,33 @@ nsresult nsZipArchive::SeekToItem(nsZipItem* aItem, PRFileDesc* aFd)
|
||||
//-- 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 (!ZIP_Seek(aFd, aItem->headerOffset, PR_SEEK_SET))
|
||||
return ZIP_ERR_CORRUPT;
|
||||
if (!mFd || !mFd->mLen > aItem->headerOffset + ZIPLOCAL_SIZE)
|
||||
return false;
|
||||
|
||||
ZipLocal Local;
|
||||
if ((PR_Read(aFd, (char*)&Local, ZIPLOCAL_SIZE) != (READTYPE) ZIPLOCAL_SIZE) ||
|
||||
(xtolong(Local.signature) != LOCALSIG))
|
||||
ZipLocal *Local = (ZipLocal*)(mFd->mFileData + aItem->headerOffset);
|
||||
//check limits here
|
||||
if ((xtolong(Local->signature) != LOCALSIG))
|
||||
{
|
||||
//-- read error or local header not found
|
||||
return ZIP_ERR_CORRUPT;
|
||||
return false;
|
||||
}
|
||||
|
||||
aItem->dataOffset = aItem->headerOffset +
|
||||
ZIPLOCAL_SIZE +
|
||||
xtoint(Local.filename_len) +
|
||||
xtoint(Local.extrafield_len);
|
||||
xtoint(Local->filename_len) +
|
||||
xtoint(Local->extrafield_len);
|
||||
aItem->hasDataOffset = PR_TRUE;
|
||||
}
|
||||
|
||||
//-- move to start of file in archive
|
||||
if (!ZIP_Seek(aFd, aItem->dataOffset, PR_SEEK_SET))
|
||||
return ZIP_ERR_CORRUPT;
|
||||
|
||||
return ZIP_OK;
|
||||
return true;
|
||||
}
|
||||
|
||||
//---------------------------------------------
|
||||
// nsZipArchive::CopyItemToDisk
|
||||
//---------------------------------------------
|
||||
nsresult
|
||||
nsZipArchive::CopyItemToDisk(PRUint32 itemSize, PRUint32 itemCrc, 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
|
||||
@ -822,7 +851,7 @@ nsZipArchive::CopyItemToDisk(PRUint32 itemSize, PRUint32 itemCrc, PRFileDesc* ou
|
||||
{
|
||||
chunk = (itemSize - pos < ZIP_BUFLEN) ? (itemSize - pos) : ZIP_BUFLEN;
|
||||
|
||||
if (PR_Read(mFd, buf, chunk) != (READTYPE)chunk)
|
||||
if (fd.Read(buf, chunk) != (READTYPE)chunk)
|
||||
{
|
||||
//-- unexpected end of data in archive
|
||||
return ZIP_ERR_CORRUPT;
|
||||
@ -849,7 +878,7 @@ nsZipArchive::CopyItemToDisk(PRUint32 itemSize, PRUint32 itemCrc, PRFileDesc* ou
|
||||
//---------------------------------------------
|
||||
// nsZipArchive::InflateItem
|
||||
//---------------------------------------------
|
||||
nsresult nsZipArchive::InflateItem(const nsZipItem* aItem, 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
|
||||
@ -887,7 +916,7 @@ nsresult nsZipArchive::InflateItem(const nsZipItem* aItem, PRFileDesc* outFD)
|
||||
//-- read another chunk of compressed data
|
||||
PRUint32 chunk = (size-zs.total_in < ZIP_BUFLEN) ? size-zs.total_in : ZIP_BUFLEN;
|
||||
|
||||
if (PR_Read(mFd, inbuf, chunk) != (READTYPE)chunk)
|
||||
if (fd.Read(inbuf, chunk) != (READTYPE)chunk)
|
||||
{
|
||||
//-- unexpected end of data
|
||||
status = ZIP_ERR_CORRUPT;
|
||||
@ -966,8 +995,7 @@ cleanup:
|
||||
//------------------------------------------
|
||||
|
||||
nsZipArchive::nsZipArchive() :
|
||||
mFd(0),
|
||||
mBuiltSynthetics(PR_FALSE)
|
||||
mBuiltSynthetics(PR_FALSE)
|
||||
{
|
||||
MOZ_COUNT_CTOR(nsZipArchive);
|
||||
|
||||
@ -1075,4 +1103,3 @@ static PRBool IsSymlink(unsigned char *ll)
|
||||
return ((xtoint(ll+2) & S_IFMT) == S_IFLNK);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -24,6 +24,7 @@
|
||||
* Daniel Veditz <dveditz@netscape.com>
|
||||
* Samir Gehani <sgehani@netscape.com>
|
||||
* Mitch Stoltz <mstoltz@netscape.com>
|
||||
* Taras Glek <tglek@mozilla.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
@ -53,6 +54,7 @@
|
||||
#define ZIP_Seek(fd,p,m) (PR_Seek((fd),((PROffset32)p),(m))==((PROffset32)p))
|
||||
|
||||
#include "zlib.h"
|
||||
#include "nsAutoPtr.h"
|
||||
|
||||
class nsZipFind;
|
||||
class nsZipReadState;
|
||||
@ -111,6 +113,8 @@ struct nsZipItem
|
||||
char name[1]; // actually, bigger than 1
|
||||
};
|
||||
|
||||
class nsZipHandle;
|
||||
class nsSeekableZipHandle;
|
||||
/**
|
||||
* nsZipArchive -- a class for reading the PKZIP file format.
|
||||
*
|
||||
@ -186,12 +190,10 @@ public:
|
||||
*/
|
||||
PRInt32 FindInit(const char * aPattern, nsZipFind** aFind);
|
||||
|
||||
/**
|
||||
* Moves the filepointer aFd to the start of data of the aItem.
|
||||
* @param aItem Pointer to nsZipItem
|
||||
* @param aFd The filepointer to move
|
||||
/* Gets an undependent handle to the jar
|
||||
* Also ensures that aItem is fully filled
|
||||
*/
|
||||
nsresult SeekToItem(nsZipItem* aItem, PRFileDesc* aFd);
|
||||
nsZipHandle* GetFD(nsZipItem* aItem);
|
||||
|
||||
private:
|
||||
//--- private members ---
|
||||
@ -199,12 +201,18 @@ private:
|
||||
nsZipItem* mFiles[ZIP_TABSIZE];
|
||||
PLArenaPool mArena;
|
||||
|
||||
// Used for central directory reading, and for Test and Extract
|
||||
PRFileDesc *mFd;
|
||||
/**
|
||||
* Fills in nsZipItem fields that were not filled in by BuildFileList
|
||||
* @param aItem Pointer to nsZipItem
|
||||
* returns true if the item was filled in successfully
|
||||
*/
|
||||
bool MaybeReadItem(nsZipItem* aItem);
|
||||
|
||||
// Whether we synthesized the directory entries
|
||||
PRPackedBool mBuiltSynthetics;
|
||||
|
||||
// file handle
|
||||
nsRefPtr<nsZipHandle> mFd;
|
||||
//--- private methods ---
|
||||
|
||||
nsZipArchive& operator=(const nsZipArchive& rhs); // prevent assignments
|
||||
@ -214,8 +222,92 @@ private:
|
||||
nsresult BuildFileList();
|
||||
nsresult BuildSynthetics();
|
||||
|
||||
nsresult CopyItemToDisk(PRUint32 size, PRUint32 crc, PRFileDesc* outFD);
|
||||
nsresult InflateItem(const nsZipItem* aItem, PRFileDesc* outFD);
|
||||
nsresult CopyItemToDisk(PRUint32 size, PRUint32 crc, nsSeekableZipHandle &fd, PRFileDesc* outFD);
|
||||
nsresult InflateItem(const nsZipItem* aItem, nsSeekableZipHandle &fd, PRFileDesc* outFD);
|
||||
};
|
||||
|
||||
class nsZipHandle {
|
||||
friend class nsZipArchive;
|
||||
friend class nsSeekableZipHandle;
|
||||
public:
|
||||
static nsresult Init(PRFileDesc *fd, nsZipHandle **ret NS_OUTPARAM);
|
||||
|
||||
/**
|
||||
* Reads data at a certain point
|
||||
* @param aPosition seek ofset
|
||||
* @param aBuffer buffer
|
||||
* @param aCount number of bytes to read */
|
||||
PRInt32 Read(PRUint32 aPosition, void *aBuffer, PRUint32 aCount);
|
||||
|
||||
nsrefcnt AddRef(void);
|
||||
nsrefcnt Release(void);
|
||||
|
||||
protected:
|
||||
PRFileDesc *mFd; // OS file-descriptor
|
||||
PRUint8 *mFileData; // pointer to mmaped file
|
||||
PRUint32 mLen; // length of file and memory mapped area
|
||||
|
||||
private:
|
||||
nsZipHandle();
|
||||
~nsZipHandle();
|
||||
|
||||
PRFileMap *mMap; // nspr datastructure for mmap
|
||||
nsrefcnt mRefCnt; // ref count
|
||||
};
|
||||
|
||||
|
||||
/** nsSeekableZipHandle acts as a container for nsZipHandle,
|
||||
emulates sequential file io */
|
||||
class nsSeekableZipHandle {
|
||||
// stick nsZipItem in here
|
||||
public:
|
||||
nsSeekableZipHandle()
|
||||
: mOffset(0)
|
||||
, mRemaining(0)
|
||||
{
|
||||
}
|
||||
|
||||
/** Initializes nsSeekableZipHandle with
|
||||
* @param aOffset byte offset of the file to start reading at
|
||||
* @param length of this descriptor
|
||||
*/
|
||||
bool Open(nsZipHandle *aHandle, PRUint32 aOffset, PRUint32 aLength) {
|
||||
NS_ABORT_IF_FALSE (aHandle, "Argument must not be NULL");
|
||||
if (aOffset > aHandle->mLen)
|
||||
return false;
|
||||
mFd = aHandle;
|
||||
mOffset = aOffset;
|
||||
mRemaining = aLength;
|
||||
return true;
|
||||
}
|
||||
|
||||
/** Releases the file handle. It is safe to call multiple times. */
|
||||
void Close()
|
||||
{
|
||||
mFd = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads data at a certain point
|
||||
* @param aBuffer input buffer
|
||||
* @param aCount number of bytes to read */
|
||||
PRInt32 Read(void *aBuffer, PRUint32 aCount)
|
||||
{
|
||||
if (!mFd.get())
|
||||
return -1;
|
||||
aCount = PR_MIN(mRemaining, aCount);
|
||||
PRInt32 ret = mFd->Read(mOffset, aBuffer, aCount);
|
||||
if (ret > 0) {
|
||||
mOffset += ret;
|
||||
mRemaining -= ret;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
private:
|
||||
nsRefPtr<nsZipHandle> mFd; // file handle
|
||||
PRUint32 mOffset; // current reading offset
|
||||
PRUint32 mRemaining; // bytes remaining
|
||||
};
|
||||
|
||||
|
||||
|
@ -0,0 +1,66 @@
|
||||
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et: */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Taras Glek <tglek@mozilla.com>
|
||||
* Portions created by the Initial Developer are Copyright (C) 2006
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
function wrapInputStream(input)
|
||||
{
|
||||
var nsIScriptableInputStream = Components.interfaces.nsIScriptableInputStream;
|
||||
var factory = Components.classes["@mozilla.org/scriptableinputstream;1"];
|
||||
var wrapper = factory.createInstance(nsIScriptableInputStream);
|
||||
wrapper.init(input);
|
||||
return wrapper;
|
||||
}
|
||||
|
||||
// Check that files can be read from after closing zipreader
|
||||
function run_test() {
|
||||
const Cc = Components.classes;
|
||||
const Ci = Components.interfaces;
|
||||
|
||||
// the build script have created the zip we can test on in the current dir.
|
||||
var file = do_get_file("data/test_bug333423.zip");
|
||||
|
||||
var zipreader = Cc["@mozilla.org/libjar/zip-reader;1"].
|
||||
createInstance(Ci.nsIZipReader);
|
||||
zipreader.open(file);
|
||||
var entries = zipreader.findEntries(null);
|
||||
var stream = wrapInputStream(zipreader.getInputStream("modules/libjar/test/Makefile.in"))
|
||||
var dirstream= wrapInputStream(zipreader.getInputStream("modules/libjar/test/"))
|
||||
zipreader.close();
|
||||
zipreader = null;
|
||||
Components.utils.forceGC();
|
||||
do_check_true(stream.read(1024).length > 0);
|
||||
do_check_true(dirstream.read(100).length > 0);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user