diff --git a/mozilla/caps/src/nsScriptSecurityManager.cpp b/mozilla/caps/src/nsScriptSecurityManager.cpp index e03bd3ce6d8..76ec0bac06e 100644 --- a/mozilla/caps/src/nsScriptSecurityManager.cpp +++ b/mozilla/caps/src/nsScriptSecurityManager.cpp @@ -2633,8 +2633,7 @@ nsScriptSecurityManager::SetCanEnableCapability(const nsACString& certFingerprin if (NS_FAILED(rv)) return NS_ERROR_FAILURE; nsCOMPtr systemCertZip = do_CreateInstance(kZipReaderCID, &rv); if (NS_FAILED(rv)) return NS_ERROR_FAILURE; - systemCertZip->Init(systemCertFile); - rv = systemCertZip->Open(); + rv = systemCertZip->Open(systemCertFile); if (NS_SUCCEEDED(rv)) { nsCOMPtr systemCertJar(do_QueryInterface(systemCertZip, &rv)); diff --git a/mozilla/modules/libjar/nsIJAR.idl b/mozilla/modules/libjar/nsIJAR.idl index c5b16318678..8ac04713dbb 100644 --- a/mozilla/modules/libjar/nsIJAR.idl +++ b/mozilla/modules/libjar/nsIJAR.idl @@ -77,15 +77,6 @@ interface nsIPrincipal; [uuid(04501DB2-0409-11d3-BCF8-00805F0E1353)] interface nsIJAR : nsISupports { - - const short NOT_SIGNED = 0; - const short VALID = 1; - const short INVALID_SIG = 2; - const short INVALID_UNKNOWN_CA = 3; - const short INVALID_MANIFEST = 4; - const short INVALID_ENTRY = 5; - const short NO_MANIFEST = 6; - /** * Returns an object describing the entity which signed * an entry. parseManifest must be called first. If aEntryName is an diff --git a/mozilla/modules/libjar/nsIZipReader.idl b/mozilla/modules/libjar/nsIZipReader.idl index d49d8eb602d..c7afd76e350 100644 --- a/mozilla/modules/libjar/nsIZipReader.idl +++ b/mozilla/modules/libjar/nsIZipReader.idl @@ -44,17 +44,13 @@ #include "nsISupports.idl" -interface nsISimpleEnumerator; +interface nsIUTF8StringEnumerator; interface nsIInputStream; interface nsIFile; -[scriptable, uuid(ea950fff-aa64-49f9-879c-a830034786f8)] +[scriptable, uuid(e1c028bc-c478-11da-95a8-00e08161165f)] interface nsIZipEntry : nsISupports { - /** - * The name (including path) of the entry. - */ - readonly attribute string name; /** * The type of compression used for the item. The possible values and * their meanings are defined in the zip file specification at @@ -94,13 +90,15 @@ interface nsIZipEntry : nsISupports readonly attribute boolean isSynthetic; }; -[scriptable, uuid(6ff6a966-9632-11d3-8cd9-0060b0fc14a3)] +[scriptable, uuid(08fa7e4b-4eec-4cae-b7fe-a3c1d1e9aed2)] interface nsIZipReader : nsISupports { /** - * Initializes a zip reader after construction. + * Opens a zip file for reading. + * It is allowed to open with another file, + * but it needs to be closed first with close(). */ - void init(in nsIFile zipFile); + void open(in nsIFile zipFile); /** * The file that represents the zip with which this zip reader was @@ -108,11 +106,6 @@ interface nsIZipReader : nsISupports */ readonly attribute nsIFile file; - /** - * Opens a zip reader. - */ - void open(); - /** * Closes a zip reader. Subsequent attempts to extract files or read from * its input stream will result in an error. @@ -142,7 +135,12 @@ interface nsIZipReader : nsISupports nsIZipEntry getEntry(in string zipEntry); /** - * Returns a simple enumerator whose elements are of type nsIZipEntry. + * Checks whether the zipfile contains an entry specified by entryName. + */ + boolean hasEntry(in AUTF8String zipEntry); + + /** + * Returns a string enumerator containing the matching entry names. * * @param aPattern * A regular expression used to find matching entries in the zip file. @@ -183,7 +181,7 @@ interface nsIZipReader : nsISupports * @throws NS_ERROR_ILLEGAL_VALUE on many but not all invalid aPattern * values. */ - nsISimpleEnumerator/**/ findEntries(in string aPattern); + nsIUTF8StringEnumerator findEntries(in string aPattern); /** * Returns an input stream containing the contents of the specified zip diff --git a/mozilla/modules/libjar/nsJAR.cpp b/mozilla/modules/libjar/nsJAR.cpp index 722f5a39fad..80e5c471c37 100644 --- a/mozilla/modules/libjar/nsJAR.cpp +++ b/mozilla/modules/libjar/nsJAR.cpp @@ -44,14 +44,9 @@ #include "nsJARInputStream.h" #include "nsJAR.h" #include "nsILocalFile.h" -#include "nsXPIDLString.h" -#include "nsReadableUtils.h" -#include "nsIServiceManager.h" -#include "plbase64.h" #include "nsIConsoleService.h" -#include "nscore.h" -#include "nsCRT.h" #include "nsICryptoHash.h" +#include "prprf.h" #ifdef XP_UNIX #include @@ -59,28 +54,7 @@ #include #endif -static nsresult -ziperr2nsresult(PRInt32 ziperr) -{ - switch (ziperr) { - case ZIP_OK: return NS_OK; - case ZIP_ERR_MEMORY: return NS_ERROR_OUT_OF_MEMORY; - case ZIP_ERR_DISK: return NS_ERROR_FILE_DISK_FULL; - case ZIP_ERR_CORRUPT: return NS_ERROR_FILE_CORRUPTED; - case ZIP_ERR_PARAM: return NS_ERROR_ILLEGAL_VALUE; - case ZIP_ERR_FNF: return NS_ERROR_FILE_TARGET_DOES_NOT_EXIST; - case ZIP_ERR_UNSUPPORTED: return NS_ERROR_NOT_IMPLEMENTED; - default: return NS_ERROR_FAILURE; - } -} - -//-- PR_Free doesn't null the pointer. -// This macro takes care of that. -#define JAR_NULLFREE(_ptr) \ - { \ - PR_FREEIF(_ptr); \ - _ptr = nsnull; \ - } +static PRTime GetModTime(PRUint16 aDate, PRUint16 aTime); //---------------------------------------------- // nsJARManifestItem declaration @@ -124,7 +98,7 @@ public: //------------------------------------------------- nsJARManifestItem::nsJARManifestItem(): mType(JAR_INTERNAL), entryVerified(PR_FALSE), - status(nsIJAR::NOT_SIGNED), + status(JAR_NOT_SIGNED), calculatedSectionDigest(nsnull), storedEntryDigest(nsnull) { @@ -150,20 +124,18 @@ DeleteManifestEntry(nsHashKey* aKey, void* aData, void* closure) // The following initialization makes a guess of 10 entries per jarfile. nsJAR::nsJAR(): mManifestData(nsnull, nsnull, DeleteManifestEntry, nsnull, 10), - mParsedManifest(PR_FALSE), mGlobalStatus(nsIJAR::NOT_SIGNED), + mParsedManifest(PR_FALSE), + mGlobalStatus(JAR_MANIFEST_NOT_PARSED), mReleaseTime(PR_INTERVAL_NO_TIMEOUT), mCache(nsnull), mLock(nsnull), - mTotalItemsInManifest(0), - mFd(nsnull) + mTotalItemsInManifest(0) { } nsJAR::~nsJAR() { Close(); - if (mLock) - PR_DestroyLock(mLock); } NS_IMPL_THREADSAFE_QUERY_INTERFACE2(nsJAR, nsIZipReader, nsIJAR) @@ -195,11 +167,18 @@ nsrefcnt nsJAR::Release(void) //---------------------------------------------- NS_IMETHODIMP -nsJAR::Init(nsIFile* zipFile) +nsJAR::Open(nsIFile* zipFile) { + if (mLock) return NS_ERROR_FAILURE; // Already open! + mZipFile = zipFile; mLock = PR_NewLock(); - return mLock ? NS_OK : NS_ERROR_OUT_OF_MEMORY; + NS_ENSURE_TRUE(mLock, NS_ERROR_OUT_OF_MEMORY); + + PRFileDesc *fd = OpenFile(); + NS_ENSURE_TRUE(fd, NS_ERROR_FAILURE); + + return mZip.OpenArchive(fd); } NS_IMETHODIMP @@ -210,44 +189,25 @@ nsJAR::GetFile(nsIFile* *result) return NS_OK; } -NS_IMETHODIMP -nsJAR::Open() -{ - NS_ENSURE_TRUE(!mFd, NS_ERROR_ALREADY_INITIALIZED); - - nsresult rv; - nsCOMPtr localFile = do_QueryInterface(mZipFile, &rv); - if (NS_FAILED(rv)) return rv; - - rv = localFile->OpenNSPRFileDesc(PR_RDONLY, 0000, &mFd); - if (NS_FAILED(rv)) return rv; - - PRInt32 err = mZip.OpenArchiveWithFileDesc(mFd); - - return ziperr2nsresult(err); -} - NS_IMETHODIMP nsJAR::Close() { -#ifdef STANDALONE - // nsZipReadState::CloseArchive closes the file descriptor -#else - if (mFd) - PR_Close(mFd); -#endif - mFd = nsnull; - PRInt32 err = mZip.CloseArchive(); - return ziperr2nsresult(err); + if (mLock) { + PR_DestroyLock(mLock); + mLock = nsnull; + } + + mParsedManifest = PR_FALSE; + mGlobalStatus = JAR_MANIFEST_NOT_PARSED; + mTotalItemsInManifest = 0; + + return mZip.CloseArchive(); } NS_IMETHODIMP nsJAR::Test(const char *aEntryName) { - NS_ASSERTION(mFd, "File isn't open!"); - - PRInt32 err = mZip.Test(aEntryName, mFd); - return ziperr2nsresult(err); + return mZip.Test(aEntryName); } NS_IMETHODIMP @@ -261,10 +221,8 @@ nsJAR::Extract(const char *zipEntry, nsIFile* outFile) nsCOMPtr localFile = do_QueryInterface(outFile, &rv); if (NS_FAILED(rv)) return rv; - nsZipItem *item = 0; - PRInt32 err = mZip.GetItem(zipEntry, &item); - if (err != ZIP_OK) - return ziperr2nsresult(err); + nsZipItem *item = mZip.GetItem(zipEntry); + NS_ENSURE_TRUE(item, NS_ERROR_FILE_TARGET_DOES_NOT_EXIST); // Remove existing file or directory so we set permissions correctly. // If it's a directory that already exists and contains files, throw @@ -283,7 +241,6 @@ nsJAR::Extract(const char *zipEntry, nsIFile* outFile) if (item->isDirectory) { rv = localFile->Create(nsIFile::DIRECTORY_TYPE, item->mode); - if (NS_FAILED(rv)) return rv; //XXX Do this in nsZipArchive? It would be nice to keep extraction //XXX code completely there, but that would require a way to get a //XXX PRDir from localFile. @@ -294,96 +251,91 @@ nsJAR::Extract(const char *zipEntry, nsIFile* outFile) rv = localFile->OpenNSPRFileDesc(PR_WRONLY | PR_CREATE_FILE, item->mode, &fd); if (NS_FAILED(rv)) return rv; - err = mZip.ExtractItemToFileDesc(item, fd, mFd); - PR_Close(fd); + // ExtractFile also closes the fd handle and resolves the symlink if needed + nsCAutoString path; + rv = outFile->GetNativePath(path); + if (NS_FAILED(rv)) return rv; + + rv = mZip.ExtractFile(item, path.get(), fd); } + if (NS_FAILED(rv)) return rv; - if (err != ZIP_OK) - outFile->Remove(PR_FALSE); - else - { -#if defined(XP_UNIX) || defined(XP_BEOS) - if (item->flags & ZIFLAG_SYMLINK) - { - nsCAutoString path; - rv = outFile->GetNativePath(path); - if (NS_SUCCEEDED(rv)) - { - err = mZip.ResolveSymlink(path.get(),item); - } - } -#endif + PRTime prtime = GetModTime(item->date, item->time); + // nsIFile needs milliseconds, while prtime is in microseconds. + PRTime conversion = LL_ZERO; + PRTime newTime = LL_ZERO; + LL_I2L(conversion, PR_USEC_PER_MSEC); + LL_DIV(newTime, prtime, conversion); + // non-fatal if this fails, ignore errors + outFile->SetLastModifiedTime(newTime); - PRTime prtime = item->GetModTime(); - // nsIFile needs usecs. - PRTime conversion = LL_ZERO; - PRTime newTime = LL_ZERO; - LL_I2L(conversion, PR_USEC_PER_MSEC); - LL_DIV(newTime, prtime, conversion); - // non-fatal if this fails, ignore errors - outFile->SetLastModifiedTime(newTime); - } - - return ziperr2nsresult(err); -} - -NS_IMETHODIMP -nsJAR::GetEntry(const char *zipEntry, nsIZipEntry* *result) -{ - nsZipItem* zipItem; - PRInt32 err = mZip.GetItem(zipEntry, &zipItem); - if (err != ZIP_OK) return ziperr2nsresult(err); - - nsJARItem* jarItem = new nsJARItem(); - if (jarItem == nsnull) - return NS_ERROR_OUT_OF_MEMORY; - NS_ADDREF(jarItem); - jarItem->Init(zipItem); - *result = jarItem; return NS_OK; } NS_IMETHODIMP -nsJAR::FindEntries(const char *aPattern, nsISimpleEnumerator **result) +nsJAR::GetEntry(const char *aEntryName, nsIZipEntry* *result) { - if (!result) - return NS_ERROR_INVALID_POINTER; + nsZipItem* zipItem = mZip.GetItem(aEntryName); + NS_ENSURE_TRUE(zipItem, NS_ERROR_FILE_TARGET_DOES_NOT_EXIST); + + nsJARItem* jarItem = new nsJARItem(zipItem); + NS_ENSURE_TRUE(jarItem, NS_ERROR_OUT_OF_MEMORY); + + NS_ADDREF(*result = jarItem); + return NS_OK; +} + +NS_IMETHODIMP +nsJAR::HasEntry(const nsACString &aEntryName, PRBool *result) +{ + *result = mZip.GetItem(PromiseFlatCString(aEntryName).get()) != nsnull; + return NS_OK; +} + +NS_IMETHODIMP +nsJAR::FindEntries(const char *aPattern, nsIUTF8StringEnumerator **result) +{ + NS_ENSURE_ARG_POINTER(result); nsZipFind *find; - PRInt32 rv = mZip.FindInit(aPattern, &find); - if (rv != ZIP_OK) - return ziperr2nsresult(rv); + nsresult rv = mZip.FindInit(aPattern, &find); + NS_ENSURE_SUCCESS(rv, rv); - nsISimpleEnumerator *zipEnum = new nsJAREnumerator(find); - if (!zipEnum) + nsIUTF8StringEnumerator *zipEnum = new nsJAREnumerator(find); + if (!zipEnum) { + delete find; return NS_ERROR_OUT_OF_MEMORY; - NS_ADDREF( zipEnum ); + } - *result = zipEnum; + NS_ADDREF(*result = zipEnum); return NS_OK; } NS_IMETHODIMP nsJAR::GetInputStream(const char* aFilename, nsIInputStream** result) { - // nsZipArchive and zlib are not thread safe - // we need to use a lock to prevent bug #51267 - nsAutoLock lock(mLock); - NS_ENSURE_ARG_POINTER(result); + + // First check if item exists in jar + nsZipItem *item = mZip.GetItem(aFilename); + if (!item) return NS_ERROR_FILE_TARGET_DOES_NOT_EXIST; + + // Open jarfile, to get its own filedescriptor for the stream + PRFileDesc *fd = OpenFile(); + if (!fd) return NS_ERROR_FAILURE; + nsJARInputStream* jis = new nsJARInputStream(); if (!jis) return NS_ERROR_OUT_OF_MEMORY; // addref now so we can call Init() *result = jis; NS_ADDREF(*result); - - nsresult rv = jis->Init(this, aFilename); + + nsresult rv = jis->Init(this, item, fd); if (NS_FAILED(rv)) { NS_RELEASE(*result); return rv; } - return NS_OK; } @@ -409,7 +361,7 @@ nsJAR::GetCertificatePrincipal(const char* aFilename, nsIPrincipal** aPrincipal) //-- Parse the manifest rv = ParseManifest(verifier); if (NS_FAILED(rv)) return rv; - if (mGlobalStatus == nsIJAR::NO_MANIFEST) + if (mGlobalStatus == JAR_NO_MANIFEST) return NS_OK; PRInt16 requestedStatus; @@ -427,7 +379,7 @@ nsJAR::GetCertificatePrincipal(const char* aFilename, nsIPrincipal** aPrincipal) PRUint32 entryDataLen; rv = LoadEntry(aFilename, getter_Copies(entryData), &entryDataLen); if (NS_FAILED(rv)) return rv; - rv = VerifyEntry(verifier, manItem, entryData, entryDataLen); + rv = VerifyEntry(manItem, entryData, entryDataLen); if (NS_FAILED(rv)) return rv; } requestedStatus = manItem->status; @@ -435,7 +387,7 @@ nsJAR::GetCertificatePrincipal(const char* aFilename, nsIPrincipal** aPrincipal) else // User wants identity of signer w/o verifying any entries requestedStatus = mGlobalStatus; - if (requestedStatus != nsIJAR::VALID) + if (requestedStatus != JAR_VALID_MANIFEST) ReportError(aFilename, requestedStatus); else // Valid signature { @@ -452,6 +404,14 @@ nsJAR::GetManifestEntriesCount(PRUint32* count) return NS_OK; } +nsresult +nsJAR::GetJarPath(nsACString& aResult) +{ + NS_ENSURE_ARG_POINTER(mZipFile); + + return mZipFile->GetNativePath(aResult); +} + PRFileDesc* nsJAR::OpenFile() { @@ -546,39 +506,42 @@ nsJAR::ParseManifest(nsISignatureVerifier* verifier) if (mParsedManifest) return NS_OK; //-- (1)Manifest (MF) file - nsresult rv; - nsCOMPtr files; - rv = FindEntries(JAR_MF_SEARCH_STRING, getter_AddRefs(files)); + nsCOMPtr files; + nsresult rv = FindEntries(JAR_MF_SEARCH_STRING, getter_AddRefs(files)); if (!files) rv = NS_ERROR_FAILURE; if (NS_FAILED(rv)) return rv; //-- Load the file into memory - nsCOMPtr file; - rv = files->GetNext(getter_AddRefs(file)); - if (NS_FAILED(rv)) return rv; - if (!file) + PRBool more; + rv = files->HasMore(&more); + NS_ENSURE_SUCCESS(rv, rv); + if (!more) { - mGlobalStatus = nsIJAR::NO_MANIFEST; + mGlobalStatus = JAR_NO_MANIFEST; mParsedManifest = PR_TRUE; return NS_OK; } - PRBool more; - rv = files->HasMoreElements(&more); + + nsCAutoString manifestFilename; + rv = files->GetNext(manifestFilename); + NS_ENSURE_SUCCESS(rv, rv); + + // Check if there is more than one manifest, if so then error! + rv = files->HasMore(&more); if (NS_FAILED(rv)) return rv; if (more) { mParsedManifest = PR_TRUE; return NS_ERROR_FILE_CORRUPTED; // More than one MF file } - nsXPIDLCString manifestFilename; - rv = file->GetName(getter_Copies(manifestFilename)); - if (!manifestFilename || NS_FAILED(rv)) return rv; + nsXPIDLCString manifestBuffer; - rv = LoadEntry(manifestFilename, getter_Copies(manifestBuffer)); + PRUint32 manifestLen; + rv = LoadEntry(manifestFilename.get(), getter_Copies(manifestBuffer), &manifestLen); if (NS_FAILED(rv)) return rv; //-- Parse it - rv = ParseOneFile(verifier, manifestBuffer, JAR_MF); + rv = ParseOneFile(manifestBuffer, JAR_MF); if (NS_FAILED(rv)) return rv; //-- (2)Signature (SF) file @@ -587,23 +550,22 @@ nsJAR::ParseManifest(nsISignatureVerifier* verifier) if (!files) rv = NS_ERROR_FAILURE; if (NS_FAILED(rv)) return rv; //-- Get an SF file - rv = files->GetNext(getter_AddRefs(file)); + rv = files->HasMore(&more); if (NS_FAILED(rv)) return rv; - if (!file) + if (!more) { - mGlobalStatus = nsIJAR::NO_MANIFEST; + mGlobalStatus = JAR_NO_MANIFEST; mParsedManifest = PR_TRUE; return NS_OK; } - rv = file->GetName(getter_Copies(manifestFilename)); + rv = files->GetNext(manifestFilename); if (NS_FAILED(rv)) return rv; - PRUint32 manifestLen; - rv = LoadEntry(manifestFilename, getter_Copies(manifestBuffer), &manifestLen); + rv = LoadEntry(manifestFilename.get(), getter_Copies(manifestBuffer), &manifestLen); if (NS_FAILED(rv)) return rv; //-- Get its corresponding signature file - nsCAutoString sigFilename( NS_STATIC_CAST(const char*, manifestFilename) ); + nsCAutoString sigFilename(manifestFilename); PRInt32 extension = sigFilename.RFindChar('.') + 1; NS_ASSERTION(extension != 0, "Manifest Parser: Missing file extension."); (void)sigFilename.Cut(extension, 2); @@ -620,7 +582,7 @@ nsJAR::ParseManifest(nsISignatureVerifier* verifier) } if (NS_FAILED(rv)) { - mGlobalStatus = nsIJAR::NO_MANIFEST; + mGlobalStatus = JAR_NO_MANIFEST; mParsedManifest = PR_TRUE; return NS_OK; } @@ -631,25 +593,24 @@ nsJAR::ParseManifest(nsISignatureVerifier* verifier) &verifyError, getter_AddRefs(mPrincipal)); if (NS_FAILED(rv)) return rv; if (mPrincipal && verifyError == 0) - mGlobalStatus = nsIJAR::VALID; + mGlobalStatus = JAR_VALID_MANIFEST; else if (verifyError == nsISignatureVerifier::VERIFY_ERROR_UNKNOWN_CA) - mGlobalStatus = nsIJAR::INVALID_UNKNOWN_CA; + mGlobalStatus = JAR_INVALID_UNKNOWN_CA; else - mGlobalStatus = nsIJAR::INVALID_SIG; + mGlobalStatus = JAR_INVALID_SIG; //-- Parse the SF file. If the verification above failed, principal // is null, and ParseOneFile will mark the relevant entries as invalid. // if ParseOneFile fails, then it has no effect, and we can safely // continue to the next SF file, or return. - ParseOneFile(verifier, manifestBuffer, JAR_SF); + ParseOneFile(manifestBuffer, JAR_SF); mParsedManifest = PR_TRUE; return NS_OK; } nsresult -nsJAR::ParseOneFile(nsISignatureVerifier* verifier, - const char* filebuf, PRInt16 aFileType) +nsJAR::ParseOneFile(const char* filebuf, PRInt16 aFileType) { //-- Check file header const char* nextLineStart = filebuf; @@ -698,13 +659,13 @@ nsJAR::ParseOneFile(nsISignatureVerifier* verifier, curItemMF->mType = JAR_INVALID; else { - if (curItemMF->mType == JAR_INTERNAL) - { //-- If it's an internal item, it must correspond // to a valid jar entry - nsIZipEntry* entry; - PRInt32 result = GetEntry(curItemName.get(), &entry); - if (result != ZIP_OK || !entry) + if (curItemMF->mType == JAR_INTERNAL) + { + PRBool exists; + PRInt32 result = HasEntry(curItemName, &exists); + if (result != ZIP_OK || !exists) curItemMF->mType = JAR_INVALID; } //-- Check for duplicates @@ -743,18 +704,18 @@ nsJAR::ParseOneFile(nsISignatureVerifier* verifier, curItemSF = (nsJARManifestItem*)mManifestData.Get(&key); if(curItemSF) { - NS_ASSERTION(curItemSF->status == nsJAR::NOT_SIGNED, + NS_ASSERTION(curItemSF->status == JAR_NOT_SIGNED, "SECURITY ERROR: nsJARManifestItem not correctly initialized"); curItemSF->status = mGlobalStatus; - if (curItemSF->status == nsIJAR::VALID) + if (curItemSF->status == JAR_VALID_MANIFEST) { // Compare digests if (storedSectionDigest.IsEmpty()) - curItemSF->status = nsIJAR::NOT_SIGNED; + curItemSF->status = JAR_NOT_SIGNED; else { if (!storedSectionDigest.Equals((const char*)curItemSF->calculatedSectionDigest)) - curItemSF->status = nsIJAR::INVALID_MANIFEST; - JAR_NULLFREE(curItemSF->calculatedSectionDigest) + curItemSF->status = JAR_INVALID_MANIFEST; + PR_FREEIF(curItemSF->calculatedSectionDigest) storedSectionDigest = ""; } } // (aPrincipal != nsnull) @@ -835,24 +796,23 @@ nsJAR::ParseOneFile(nsISignatureVerifier* verifier, } //ParseOneFile() nsresult -nsJAR::VerifyEntry(nsISignatureVerifier* verifier, - nsJARManifestItem* aManItem, const char* aEntryData, +nsJAR::VerifyEntry(nsJARManifestItem* aManItem, const char* aEntryData, PRUint32 aLen) { - if (aManItem->status == nsIJAR::VALID) + if (aManItem->status == JAR_VALID_MANIFEST) { if(!aManItem->storedEntryDigest) // No entry digests in manifest file. Entry is unsigned. - aManItem->status = nsIJAR::NOT_SIGNED; + aManItem->status = JAR_NOT_SIGNED; else { //-- Calculate and compare digests char* calculatedEntryDigest; nsresult rv = CalculateDigest(aEntryData, aLen, &calculatedEntryDigest); if (NS_FAILED(rv)) return NS_ERROR_FAILURE; if (PL_strcmp(aManItem->storedEntryDigest, calculatedEntryDigest) != 0) - aManItem->status = nsIJAR::INVALID_ENTRY; - JAR_NULLFREE(calculatedEntryDigest) - JAR_NULLFREE(aManItem->storedEntryDigest) + aManItem->status = JAR_INVALID_ENTRY; + PR_FREEIF(calculatedEntryDigest) + PR_FREEIF(aManItem->storedEntryDigest) } } aManItem->entryVerified = PR_TRUE; @@ -871,21 +831,24 @@ void nsJAR::ReportError(const char* aFilename, PRInt16 errorCode) message.AppendLiteral(" is invalid because "); switch(errorCode) { - case nsIJAR::NOT_SIGNED: + case JAR_NOT_SIGNED: message.AppendLiteral("the archive did not contain a valid PKCS7 signature."); break; - case nsIJAR::INVALID_SIG: - message.Append(NS_LITERAL_STRING("the digital signature (*.RSA) file is not a valid signature of the signature instruction file (*.SF).")); + case JAR_INVALID_SIG: + message.AppendLiteral("the digital signature (*.RSA) file is not a valid signature of the signature instruction file (*.SF)."); break; - case nsIJAR::INVALID_UNKNOWN_CA: + case JAR_INVALID_UNKNOWN_CA: message.AppendLiteral("the certificate used to sign this file has an unrecognized issuer."); break; - case nsIJAR::INVALID_MANIFEST: - message.Append(NS_LITERAL_STRING("the signature instruction file (*.SF) does not contain a valid hash of the MANIFEST.MF file.")); + case JAR_INVALID_MANIFEST: + message.AppendLiteral("the signature instruction file (*.SF) does not contain a valid hash of the MANIFEST.MF file."); break; - case nsIJAR::INVALID_ENTRY: + case JAR_INVALID_ENTRY: message.AppendLiteral("the MANIFEST.MF file does not contain a valid hash of the file being verified."); break; + case JAR_NO_MANIFEST: + message.AppendLiteral("the archive did not contain a manifest."); + break; default: message.AppendLiteral("of an unknown problem."); } @@ -930,85 +893,23 @@ nsresult nsJAR::CalculateDigest(const char* aInBuf, PRUint32 aLen, return *digest ? NS_OK : NS_ERROR_OUT_OF_MEMORY; } +NS_IMPL_THREADSAFE_ISUPPORTS1(nsJAREnumerator, nsIUTF8StringEnumerator) + //---------------------------------------------- -// Debugging functions -//---------------------------------------------- -#if 0 -PR_STATIC_CALLBACK(PRBool) -PrintManItem(nsHashKey* aKey, void* aData, void* closure) -{ - nsJARManifestItem* manItem = (nsJARManifestItem*)aData; - if (manItem) - { - nsCStringKey* key2 = (nsCStringKey*)aKey; - char* name = ToNewCString(key2->GetString()); - if (!(PL_strcmp(name, "") == 0)) - printf("%s s=%i\n",name, manItem->status); - } - return PR_TRUE; -} -#endif - -void nsJAR::DumpMetadata(const char* aMessage) -{ -#if 0 - printf("### nsJAR::DumpMetadata at %s ###\n", aMessage); - if (mPrincipal) - { - char* toStr; - mPrincipal->ToString(&toStr); - printf("Principal: %s.\n", toStr); - PR_FREEIF(toStr); - } - else - printf("No Principal. \n"); - mManifestData.Enumerate(PrintManItem); - printf("\n"); -#endif -} - -//---------------------------------------------- -// nsJAREnumerator constructor and destructor -//---------------------------------------------- -nsJAREnumerator::nsJAREnumerator(nsZipFind *aFind) -: mFind(aFind), - mCurr(nsnull), - mIsCurrStale(PR_TRUE) -{ - mArchive = mFind->GetArchive(); -} - -nsJAREnumerator::~nsJAREnumerator() -{ - mArchive->FindFree(mFind); -} - -NS_IMPL_ISUPPORTS1(nsJAREnumerator, nsISimpleEnumerator) - -//---------------------------------------------- -// nsJAREnumerator::HasMoreElements +// nsJAREnumerator::HasMore //---------------------------------------------- NS_IMETHODIMP -nsJAREnumerator::HasMoreElements(PRBool* aResult) +nsJAREnumerator::HasMore(PRBool* aResult) { - PRInt32 err; - - if (!mFind) - return NS_ERROR_NOT_INITIALIZED; - // try to get the next element - if (mIsCurrStale) - { - err = mArchive->FindNext( mFind, &mCurr ); - if (err == ZIP_ERR_FNF) - { - *aResult = PR_FALSE; + if (!mCurr) { + NS_ASSERTION(mFind, "nsJAREnumerator: Missing zipFind."); + nsresult rv = mFind->FindNext( &mCurr ); + if (rv == NS_ERROR_FILE_TARGET_DOES_NOT_EXIST) { + *aResult = PR_FALSE; // No more matches available return NS_OK; } - if (err != ZIP_OK) - return NS_ERROR_FAILURE; // no error translation - - mIsCurrStale = PR_FALSE; + NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE); // no error translation } *aResult = PR_TRUE; @@ -1019,75 +920,33 @@ nsJAREnumerator::HasMoreElements(PRBool* aResult) // nsJAREnumerator::GetNext //---------------------------------------------- NS_IMETHODIMP -nsJAREnumerator::GetNext(nsISupports** aResult) +nsJAREnumerator::GetNext(nsACString& aResult) { - nsresult rv; - PRBool bMore; - // check if the current item is "stale" - if (mIsCurrStale) - { - rv = HasMoreElements( &bMore ); - if (NS_FAILED(rv)) - return rv; - if (bMore == PR_FALSE) - { - *aResult = nsnull; // null return value indicates no more elements - return NS_OK; - } + if (!mCurr) { + PRBool bMore; + nsresult rv = HasMore(&bMore); + if (NS_FAILED(rv) || !bMore) + return NS_ERROR_FAILURE; // no error translation } - - // pack into an nsIJARItem - nsJARItem* jarItem = new nsJARItem(); - if(jarItem) - { - NS_ADDREF(jarItem); - jarItem->Init(mCurr); - *aResult = jarItem; - mIsCurrStale = PR_TRUE; // we just gave this one away - return NS_OK; - } - else - return NS_ERROR_OUT_OF_MEMORY; + aResult = mCurr; + mCurr = 0; // we just gave this one away + return NS_OK; } -//------------------------------------------------- -// nsJARItem constructors and destructor -//------------------------------------------------- -nsJARItem::nsJARItem() -{ -} - -nsJARItem::~nsJARItem() -{ -} NS_IMPL_THREADSAFE_ISUPPORTS1(nsJARItem, nsIZipEntry) -void nsJARItem::Init(nsZipItem* aZipItem) +nsJARItem::nsJARItem(nsZipItem* aZipItem) + : mSize(aZipItem->size), + mRealsize(aZipItem->realsize), + mCrc32(aZipItem->crc32), + mDate(aZipItem->date), + mTime(aZipItem->time), + mCompression(aZipItem->compression), + mIsDirectory(aZipItem->isDirectory), + mIsSynthetic(aZipItem->isSynthetic) { - mZipItem = aZipItem; -} - -//------------------------------------------ -// nsJARItem::GetName -//------------------------------------------ -NS_IMETHODIMP -nsJARItem::GetName(char * *aName) -{ - char *namedup; - - if ( !aName ) - return NS_ERROR_NULL_POINTER; - if ( !mZipItem->name ) - return NS_ERROR_FAILURE; - - namedup = PL_strdup( mZipItem->name ); - if ( !namedup ) - return NS_ERROR_OUT_OF_MEMORY; - - *aName = namedup; - return NS_OK; } //------------------------------------------ @@ -1096,10 +955,9 @@ nsJARItem::GetName(char * *aName) NS_IMETHODIMP nsJARItem::GetCompression(PRUint16 *aCompression) { - if (!aCompression) - return NS_ERROR_NULL_POINTER; + NS_ENSURE_ARG_POINTER(aCompression); - *aCompression = mZipItem->compression; + *aCompression = mCompression; return NS_OK; } @@ -1109,10 +967,9 @@ nsJARItem::GetCompression(PRUint16 *aCompression) NS_IMETHODIMP nsJARItem::GetSize(PRUint32 *aSize) { - if (!aSize) - return NS_ERROR_NULL_POINTER; + NS_ENSURE_ARG_POINTER(aSize); - *aSize = mZipItem->size; + *aSize = mSize; return NS_OK; } @@ -1122,10 +979,9 @@ nsJARItem::GetSize(PRUint32 *aSize) NS_IMETHODIMP nsJARItem::GetRealSize(PRUint32 *aRealsize) { - if (!aRealsize) - return NS_ERROR_NULL_POINTER; + NS_ENSURE_ARG_POINTER(aRealsize); - *aRealsize = mZipItem->realsize; + *aRealsize = mRealsize; return NS_OK; } @@ -1135,10 +991,9 @@ nsJARItem::GetRealSize(PRUint32 *aRealsize) NS_IMETHODIMP nsJARItem::GetCRC32(PRUint32 *aCrc32) { - if (!aCrc32) - return NS_ERROR_NULL_POINTER; + NS_ENSURE_ARG_POINTER(aCrc32); - *aCrc32 = mZipItem->crc32; + *aCrc32 = mCrc32; return NS_OK; } @@ -1148,23 +1003,21 @@ nsJARItem::GetCRC32(PRUint32 *aCrc32) NS_IMETHODIMP nsJARItem::GetIsDirectory(PRBool *aIsDirectory) { - if (!aIsDirectory) - return NS_ERROR_NULL_POINTER; + NS_ENSURE_ARG_POINTER(aIsDirectory); - *aIsDirectory = mZipItem->isDirectory; + *aIsDirectory = mIsDirectory; return NS_OK; } //------------------------------------------ // nsJARItem::GetIsSynthetic //------------------------------------------ -NS_IMETHODIMP +NS_IMETHODIMP nsJARItem::GetIsSynthetic(PRBool *aIsSynthetic) { - if (!aIsSynthetic) - return NS_ERROR_NULL_POINTER; + NS_ENSURE_ARG_POINTER(aIsSynthetic); - *aIsSynthetic = mZipItem->isSynthetic; + *aIsSynthetic = mIsSynthetic; return NS_OK; } @@ -1174,10 +1027,9 @@ nsJARItem::GetIsSynthetic(PRBool *aIsSynthetic) NS_IMETHODIMP nsJARItem::GetLastModifiedTime(PRTime* aLastModTime) { - if (!aLastModTime) - return NS_ERROR_NULL_POINTER; + NS_ENSURE_ARG_POINTER(aLastModTime); - *aLastModTime = mZipItem->GetModTime(); + *aLastModTime = GetModTime(mDate, mTime); return NS_OK; } @@ -1269,12 +1121,7 @@ nsZipReaderCache::GetZip(nsIFile* zipFile, nsIZipReader* *result) NS_ADDREF(zip); zip->SetZipReaderCache(this); - rv = zip->Init(zipFile); - if (NS_FAILED(rv)) { - NS_RELEASE(zip); - return rv; - } - rv = zip->Open(); + rv = zip->Open(zipFile); if (NS_FAILED(rv)) { NS_RELEASE(zip); return rv; @@ -1370,12 +1217,8 @@ nsZipReaderCache::ReleaseZip(nsJAR* zip) oldest->SetZipReaderCache(nsnull); // remove from hashtable - nsCOMPtr zipFile; - rv = oldest->GetFile(getter_AddRefs(zipFile)); - if (NS_FAILED(rv)) return rv; - nsCAutoString path; - rv = zipFile->GetNativePath(path); + rv = oldest->GetJarPath(path); if (NS_FAILED(rv)) return rv; nsCStringKey key(path); @@ -1426,4 +1269,17 @@ nsZipReaderCache::Observe(nsISupports *aSubject, return NS_OK; } +static PRTime GetModTime(PRUint16 aDate, PRUint16 aTime) +{ + char buffer[17]; + + PR_snprintf(buffer, sizeof(buffer), "%02d/%02d/%04d %02d:%02d", + ((aDate >> 5) & 0x0F), (aDate & 0x1F), (aDate >> 9) + 1980, + ((aTime >> 11) & 0x1F), ((aTime >> 5) & 0x3F)); + + PRTime result; + PR_ParseTimeString(buffer, PR_FALSE, &result); + return result; +} + //////////////////////////////////////////////////////////////////////////////// diff --git a/mozilla/modules/libjar/nsJAR.h b/mozilla/modules/libjar/nsJAR.h index 734e1af326c..a3caec936aa 100644 --- a/mozilla/modules/libjar/nsJAR.h +++ b/mozilla/modules/libjar/nsJAR.h @@ -56,8 +56,7 @@ #include "nsCOMPtr.h" #include "nsString.h" #include "nsIFile.h" -#include "nsIEnumerator.h" -#include "nsVoidArray.h" +#include "nsStringEnumerator.h" #include "nsHashtable.h" #include "nsAutoLock.h" #include "nsIZipReader.h" @@ -74,6 +73,19 @@ class nsIInputStream; class nsJARManifestItem; class nsZipReaderCache; +/* For mManifestStatus */ +typedef enum +{ + JAR_MANIFEST_NOT_PARSED = 0, + JAR_VALID_MANIFEST = 1, + JAR_INVALID_SIG = 2, + JAR_INVALID_UNKNOWN_CA = 3, + JAR_INVALID_MANIFEST = 4, + JAR_INVALID_ENTRY = 5, + JAR_NO_MANIFEST = 6, + JAR_NOT_SIGNED = 7 +} JARManifestStatusType; + /*------------------------------------------------------------------------- * Class nsJAR declaration. * nsJAR serves as an XPCOM wrapper for nsZipArchive with the addition of @@ -97,6 +109,8 @@ class nsJAR : public nsIZipReader, public nsIJAR NS_DECL_NSIJAR + nsresult GetJarPath(nsACString& aResult); + PRIntervalTime GetReleaseTime() { return mReleaseTime; } @@ -117,8 +131,6 @@ class nsJAR : public nsIZipReader, public nsIJAR mCache = cache; } - PRFileDesc* OpenFile(); - protected: //-- Private data members nsCOMPtr mZipFile; // The zip/jar file on disk @@ -129,20 +141,19 @@ class nsJAR : public nsIZipReader, public nsIJAR PRInt16 mGlobalStatus; // Global signature verification status PRIntervalTime mReleaseTime; // used by nsZipReaderCache for flushing entries nsZipReaderCache* mCache; // if cached, this points to the cache it's contained in - PRLock* mLock; + PRLock* mLock; PRInt32 mTotalItemsInManifest; - PRFileDesc* mFd; //-- Private functions + PRFileDesc* OpenFile(); + nsresult ParseManifest(nsISignatureVerifier* verifier); void ReportError(const char* aFilename, PRInt16 errorCode); nsresult LoadEntry(const char* aFilename, char** aBuf, PRUint32* aBufLen = nsnull); PRInt32 ReadLine(const char** src); - nsresult ParseOneFile(nsISignatureVerifier* verifier, - const char* filebuf, PRInt16 aFileType); - nsresult VerifyEntry(nsISignatureVerifier* verifier, - nsJARManifestItem* aEntry, const char* aEntryData, + nsresult ParseOneFile(const char* filebuf, PRInt16 aFileType); + nsresult VerifyEntry(nsJARManifestItem* aEntry, const char* aEntryData, PRUint32 aLen); nsresult CalculateDigest(const char* aInBuf, PRUint32 aInBufLen, @@ -164,13 +175,18 @@ public: NS_DECL_ISUPPORTS NS_DECL_NSIZIPENTRY - void Init(nsZipItem* aZipItem); + nsJARItem(nsZipItem* aZipItem); + virtual ~nsJARItem() {}; - nsJARItem(); - virtual ~nsJARItem(); - - private: - nsZipItem* mZipItem; +private: + PRUint32 mSize; /* size in original file */ + PRUint32 mRealsize; /* inflated size */ + PRUint32 mCrc32; + PRUint16 mTime; + PRUint16 mDate; + PRUint8 mCompression; + PRPackedBool mIsDirectory; + PRPackedBool mIsSynthetic; }; /** @@ -179,20 +195,21 @@ public: * Enumerates a list of files in a zip archive * (based on a pattern match in its member nsZipFind). */ -class nsJAREnumerator : public nsISimpleEnumerator +class nsJAREnumerator : public nsIUTF8StringEnumerator { public: NS_DECL_ISUPPORTS - NS_DECL_NSISIMPLEENUMERATOR + NS_DECL_NSIUTF8STRINGENUMERATOR - nsJAREnumerator(nsZipFind *aFind); - virtual ~nsJAREnumerator(); + nsJAREnumerator(nsZipFind *aFind) : mFind(aFind), mCurr(nsnull) { + NS_ASSERTION(mFind, "nsJAREnumerator: Missing zipFind."); + } -protected: - nsZipArchive *mArchive; // pointer extracted from mFind for efficiency +private: nsZipFind *mFind; - nsZipItem *mCurr; // raw pointer to an nsZipItem owned by mArchive -- DON'T delete - PRBool mIsCurrStale; + const char* mCurr; // pointer to an name owned by mArchive -- DON'T delete + + ~nsJAREnumerator() { delete mFind; } }; //////////////////////////////////////////////////////////////////////////////// diff --git a/mozilla/modules/libjar/nsJARChannel.cpp b/mozilla/modules/libjar/nsJARChannel.cpp index 9f9ccf2f130..fc4ce29403d 100644 --- a/mozilla/modules/libjar/nsJARChannel.cpp +++ b/mozilla/modules/libjar/nsJARChannel.cpp @@ -140,10 +140,7 @@ nsJARInputThunk::EnsureJarStream() mJarReader = do_CreateInstance(kZipReaderCID, &rv); if (NS_FAILED(rv)) return rv; - rv = mJarReader->Init(mJarFile); - if (NS_FAILED(rv)) return rv; - - rv = mJarReader->Open(); + rv = mJarReader->Open(mJarFile); } if (NS_FAILED(rv)) return rv; diff --git a/mozilla/modules/libjar/nsJARDirectoryInputStream.cpp b/mozilla/modules/libjar/nsJARDirectoryInputStream.cpp index 5475bc5dbe9..3f96f541d1f 100644 --- a/mozilla/modules/libjar/nsJARDirectoryInputStream.cpp +++ b/mozilla/modules/libjar/nsJARDirectoryInputStream.cpp @@ -42,20 +42,6 @@ #include "nsEscape.h" #include "nsIFile.h" -/** - * Sorting function which sorts nsIZipEntry items into alphabetical order. - */ -static int PR_CALLBACK compare(nsIZipEntry* aElement1, - nsIZipEntry* aElement2, - void* aData) -{ - //XXX not i18n, but names in zips have no defined charset, so we can't win - nsXPIDLCString name1, name2; - aElement1->GetName(getter_Copies(name1)); - aElement2->GetName(getter_Copies(name2)); - - return Compare(name1, name2); -} /*--------------------------------------------- * nsISupports implementation @@ -98,43 +84,31 @@ nsJARDirectoryInputStream::Read(char* buf, PRUint32 count, PRUint32 *bytesRead) mBuffer.Truncate(); mBufPos = 0; PRUint32 arrayLen = mArray.Count(); - while (count > mBuffer.Length()) { + for ( ;count > mBuffer.Length(); mArrPos++) { // have we consumed all the directory contents? if (arrayLen <= mArrPos) break; - // Don't addref, for speed -- the object was addrefed when - // it was added to the array, so it won't become stale until - // the array dies - nsIZipEntry* ze = mArray.ObjectAt(mArrPos++); + // Name + const char * entryName = mArray[mArrPos]->get(); + PRUint32 entryNameLen = mArray[mArrPos]->Length(); + const char * relativeName = entryName + mDirNameLen; + PRUint32 relativeNameLen = entryNameLen - mDirNameLen; + + nsCOMPtr ze; + rv = mZip->GetEntry(entryName, getter_AddRefs(ze)); + if (NS_FAILED(rv)) return rv; // Type - PRBool isDir; + PRBool isDir = PR_FALSE; rv = ze->GetIsDirectory(&isDir); if (NS_FAILED(rv)) return rv; - const char* itemType; - if (isDir) { - itemType = "DIRECTORY\n"; - } else { - itemType = "FILE\n"; - } // Size (real, not compressed) PRUint32 itemRealSize = 0; rv = ze->GetRealSize(&itemRealSize); if (NS_FAILED(rv)) return rv; - // Name (escaped, relative) - nsXPIDLCString entryName; - rv = ze->GetName(getter_Copies(entryName)); - if (NS_FAILED(rv)) return rv; - - // names must be relative, so use the pre-calculated length - // of the directory name as the offset into the string - nsCAutoString itemName; - entryName.Cut(0, mDirNameLen); - NS_EscapeURL(entryName, esc_Minimal | esc_AlwaysCopy, itemName); - // Last Modified Time PRTime lmt = LL_Zero(); rv = ze->GetLastModifiedTime(&lmt); @@ -151,11 +125,17 @@ nsJARDirectoryInputStream::Read(char* buf, PRUint32 count, PRUint32 *bytesRead) // write a 201: line to the buffer for this item // 200: filename content-length last-modified file-type mBuffer.AppendLiteral("201: "); - mBuffer.Append(itemName); + + // Names must be escaped and relative, so use the pre-calculated length + // of the directory name as the offset into the string + // NS_EscapeURL adds the escaped URL to the give string buffer + NS_EscapeURL(relativeName, relativeNameLen, + esc_Minimal | esc_AlwaysCopy, mBuffer); + mBuffer.AppendLiteral(" "); mBuffer.AppendInt(itemRealSize, 10); mBuffer.Append(itemLastModTime); // starts/ends with ' ' - mBuffer.Append(itemType); // '\n'-terminated + mBuffer.Append(isDir ? "DIRECTORY\n" : "FILE\n"); } // Copy up to the desired amount of data to buffer @@ -220,6 +200,10 @@ nsJARDirectoryInputStream::Init(nsIZipReader* aZip, // Watch out for the jar:foo.zip!/ (aDir is empty) top-level // special case! nsresult rv; + + // Keep the zipReader for getting the actual zipItems + mZip = aZip; + if (*aDir) { nsCOMPtr ze; rv = aZip->GetEntry(aDir, getter_AddRefs(ze)); @@ -233,7 +217,7 @@ nsJARDirectoryInputStream::Init(nsIZipReader* aZip, return NS_ERROR_ILLEGAL_VALUE; } - // We can get aDir's contents as nsIZipEntry items via FindEntries + // We can get aDir's contents as strings via FindEntries // with the following pattern (see nsIZipReader.findEntries docs) // assuming dirName is properly escaped: // @@ -270,23 +254,21 @@ nsJARDirectoryInputStream::Init(nsIZipReader* aZip, nsCAutoString pattern = escDirName + NS_LITERAL_CSTRING("?*~") + escDirName + NS_LITERAL_CSTRING("?*/?*"); - nsCOMPtr dirEnum; + nsCOMPtr dirEnum; rv = aZip->FindEntries(pattern.get(), getter_AddRefs(dirEnum)); if (NS_FAILED(rv)) return rv; PRBool more; - nsCOMPtr item; - while (NS_SUCCEEDED(dirEnum->HasMoreElements(&more)) && more) { - rv = dirEnum->GetNext(getter_AddRefs(item)); + nsCAutoString entryName; + while (NS_SUCCEEDED(dirEnum->HasMore(&more)) && more) { + rv = dirEnum->GetNext(entryName); if (NS_SUCCEEDED(rv)) { - nsCOMPtr ze = do_QueryInterface(item); - if (ze) - mArray.AppendObject(ze); // addrefs + mArray.AppendCString(entryName); } } // Sort it - mArray.Sort(compare, nsnull); + mArray.Sort(); mBuffer.AppendLiteral("300: "); mBuffer.Append(aJarDirSpec); diff --git a/mozilla/modules/libjar/nsJARDirectoryInputStream.h b/mozilla/modules/libjar/nsJARDirectoryInputStream.h index dd01d4e8b1f..4e9247f1aec 100644 --- a/mozilla/modules/libjar/nsJARDirectoryInputStream.h +++ b/mozilla/modules/libjar/nsJARDirectoryInputStream.h @@ -70,12 +70,13 @@ class nsJARDirectoryInputStream : public nsIInputStream PRUint32 CopyDataToBuffer(char* &aBuffer, PRUint32 &aCount); protected: + nsIZipReader* mZip; // the zipReader nsresult mStatus; // current status of the stream PRUint32 mDirNameLen; // length of dirname nsCAutoString mBuffer; // storage for generated text of stream PRUint32 mArrPos; // current position within mArray PRUint32 mBufPos; // current position within mBuffer - nsCOMArray mArray; // array of nsIZipEntrys in directory + nsCStringArray mArray; // array of names in (zip) directory }; #endif /* nsJARDIRECTORYINPUTSTREAM_h__ */ diff --git a/mozilla/modules/libjar/nsJARInputStream.cpp b/mozilla/modules/libjar/nsJARInputStream.cpp index 5925635d97a..2672e1cdcde 100644 --- a/mozilla/modules/libjar/nsJARInputStream.cpp +++ b/mozilla/modules/libjar/nsJARInputStream.cpp @@ -39,7 +39,7 @@ * ***** END LICENSE BLOCK ***** */ #include "nsJARInputStream.h" -#include "zipfile.h" // defines ZIP error codes +#include "zipstruct.h" // defines ZIP compression codes #include "nsZipArchive.h" @@ -53,26 +53,103 @@ NS_IMPL_THREADSAFE_ISUPPORTS1(nsJARInputStream, nsIInputStream) * nsJARInputStream implementation *--------------------------------------------------------*/ +nsresult +nsJARInputStream::Init(nsJAR* aJAR, nsZipItem *item, PRFileDesc *fd) +{ + nsresult rv; + + NS_ENSURE_ARG_POINTER(aJAR); + NS_ENSURE_ARG_POINTER(item); + NS_ENSURE_ARG_POINTER(fd); + + // Mark it as closed, in case something fails in initialisation + mClosed = PR_TRUE; + + // Keep the file handle + mFd = fd; + + // Keep the important bits of nsZipItem only + mInSize = item->size; + + //-- prepare for the compression type + switch (item->compression) { + case STORED: + break; + + case DEFLATED: + 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); + + mInflate->mOutSize = item->realsize; + mInflate->mInCrc = item->crc32; + mInflate->mOutCrc = crc32(0L, Z_NULL, 0); + break; + + default: + return NS_ERROR_NOT_IMPLEMENTED; + } + + //-- Set filepointer to start of item + rv = aJAR->mZip.SeekToItem(item, mFd); + NS_ENSURE_SUCCESS(rv, NS_ERROR_FILE_CORRUPTED); + + // Open for reading + mClosed = PR_FALSE; + return NS_OK; +} + NS_IMETHODIMP nsJARInputStream::Available(PRUint32 *_retval) { - if (!mJAR) + if (mClosed) return NS_BASE_STREAM_CLOSED; - *_retval = mReadInfo.Available(); + if (mInflate) + *_retval = mInflate->mOutSize - mInflate->mZs.total_out; + else + *_retval = mInSize - mCurPos; return NS_OK; } NS_IMETHODIMP -nsJARInputStream::Read(char* buf, PRUint32 count, PRUint32 *bytesRead) +nsJARInputStream::Read(char* aBuffer, PRUint32 aCount, PRUint32 *aBytesRead) { - if (!mJAR) { - *bytesRead = 0; - return NS_OK; + NS_ENSURE_ARG_POINTER(aBuffer); + NS_ENSURE_ARG_POINTER(aBytesRead); + + *aBytesRead = 0; + + nsresult rv = NS_OK; + if (mClosed) + return rv; + + if (mInflate) { + rv = ContinueInflate(aBuffer, aCount, aBytesRead); + } else { + PRInt32 bytesRead = 0; + if (aCount > mInSize - mCurPos) + aCount = mInSize - mCurPos; + if (aCount) { + bytesRead = PR_Read(mFd, aBuffer, aCount); + if (bytesRead < 0) + return NS_ERROR_FILE_CORRUPTED; + mCurPos += bytesRead; + } + *aBytesRead = bytesRead; } - PRInt32 err = mReadInfo.Read(buf, count, bytesRead); - return err == ZIP_OK ? NS_OK : NS_ERROR_FAILURE; + // 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; + } + return rv; } NS_IMETHODIMP @@ -93,40 +170,77 @@ nsJARInputStream::IsNonBlocking(PRBool *aNonBlocking) NS_IMETHODIMP nsJARInputStream::Close() { - mJAR = nsnull; + PR_FREEIF(mInflate); + if (mFd) { + PR_Close(mFd); + mFd = nsnull; + } + mClosed = PR_TRUE; return NS_OK; } nsresult -nsJARInputStream::Init(nsJAR* aJAR, const char* aFilename) +nsJARInputStream::ContinueInflate(char* aBuffer, PRUint32 aCount, + PRUint32* aBytesRead) { - NS_ENSURE_ARG_POINTER(aJAR); - NS_ENSURE_ARG_POINTER(aFilename); + // 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"); - mJAR = aJAR; + // Keep old total_out count + const PRUint32 oldTotalOut = mInflate->mZs.total_out; + + // make sure we aren't reading too much + mInflate->mZs.avail_out = (mInflate->mOutSize-oldTotalOut > aCount) ? aCount : mInflate->mOutSize-oldTotalOut; + mInflate->mZs.next_out = (unsigned char*)aBuffer; - // Don't assert if !fd, because it's possible that aJAR comes - // from a cache and aJAR's file has been deled - PRFileDesc* fd = aJAR->OpenFile(); - if (!fd) - return NS_ERROR_UNEXPECTED; + int zerr = Z_OK; + //-- inflate loop + while (mInflate->mZs.avail_out > 0 && zerr == Z_OK) { - // mReadInfo takes ownership of fd here - PRInt32 result = aJAR->mZip.ReadInit(aFilename, &mReadInfo, fd); - if (result != ZIP_OK) - return NS_ERROR_FAILURE; - return NS_OK; -} - -//---------------------------------------------- -// nsJARInputStream constructor and destructor -//---------------------------------------------- - -nsJARInputStream::nsJARInputStream() -{ -} - -nsJARInputStream::~nsJARInputStream() -{ - Close(); + if (mInflate->mZs.avail_in == 0 && mCurPos < mInSize) { + // time to fill the buffer! + PRUint32 bytesToRead = (mInSize-mCurPos < ZIP_BUFLEN) ? mInSize-mCurPos : ZIP_BUFLEN; + + NS_ASSERTION(mFd, "File handle missing"); + PRInt32 bytesRead = PR_Read(mFd, 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 + zerr = inflate(&(mInflate->mZs), Z_SYNC_FLUSH); + } + + if ((zerr != Z_OK) && (zerr != Z_STREAM_END)) + return NS_ERROR_FILE_CORRUPTED; + + *aBytesRead = (mInflate->mZs.total_out - oldTotalOut); + + // Calculate the CRC on the output + 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 || mInflate->mZs.total_out == mInflate->mOutSize) { + inflateEnd(&(mInflate->mZs)); + + // stop returning valid data as soon as we know we have a bad CRC + if (mInflate->mOutCrc != mInflate->mInCrc) { + // asserting because while this rarely happens, you definitely + // want to catch it in debug builds! + NS_NOTREACHED(0); + return NS_ERROR_FILE_CORRUPTED; + } + } + + return NS_OK; } diff --git a/mozilla/modules/libjar/nsJARInputStream.h b/mozilla/modules/libjar/nsJARInputStream.h index d90443ff24f..ec8249dc97d 100644 --- a/mozilla/modules/libjar/nsJARInputStream.h +++ b/mozilla/modules/libjar/nsJARInputStream.h @@ -40,12 +40,6 @@ #ifndef nsJARINPUTSTREAM_h__ #define nsJARINPUTSTREAM_h__ -// {a756724a-1dd1-11b2-90d8-9c98fc2b7ac0} -#define NS_JARINPUTSTREAM_CID \ - {0xa756724a, 0x1dd1, 0x11b2, \ - {0x90, 0xd8, 0x9c, 0x98, 0xfc, 0x2b, 0x7a, 0xc0}} - -#include "nsAutoPtr.h" #include "nsIInputStream.h" #include "nsJAR.h" @@ -57,21 +51,33 @@ class nsJARInputStream : public nsIInputStream { public: - - nsJARInputStream(); - virtual ~nsJARInputStream(); + nsJARInputStream() : + mFd(nsnull), mInSize(0), mCurPos(0), + mClosed(PR_FALSE), mInflate(nsnull) { } - NS_DEFINE_STATIC_CID_ACCESSOR( NS_JARINPUTSTREAM_CID ); - NS_DECL_ISUPPORTS NS_DECL_NSIINPUTSTREAM - nsresult - Init(nsJAR* jar, const char* aFilename); + nsresult Init(nsJAR* jar, nsZipItem *item, PRFileDesc *fd); - protected: - nsZipReadState mReadInfo; - nsRefPtr mJAR; + private: + PRFileDesc* mFd; // My own file handle, for reading + PRUint32 mInSize; // Size in original file + PRUint32 mCurPos; // Current position in input + PRPackedBool mClosed; // Whether the stream is closed + + 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; + + ~nsJARInputStream() { Close(); } + nsresult ContinueInflate(char* aBuf, PRUint32 aCount, PRUint32* aBytesRead); }; #endif /* nsJARINPUTSTREAM_h__ */ + diff --git a/mozilla/modules/libjar/nsWildCard.h b/mozilla/modules/libjar/nsWildCard.h index 79fcb14b67b..1267c826004 100644 --- a/mozilla/modules/libjar/nsWildCard.h +++ b/mozilla/modules/libjar/nsWildCard.h @@ -89,16 +89,4 @@ extern int NS_WildCardValid(char *expr); extern int NS_WildCardMatch(char *str, char *expr, PRBool case_insensitive); -/* - * Same as above, but validates the exp first. 0 on match, 1 on non-match, - * -1 on invalid exp. - */ - -extern int NS_WildCardSearch(char *str, char *expr); - -/* - * Same as above but uses case insensitive search. - */ -extern int NS_WildCardCaseSearch(char *str, char *expr); - #endif /* nsWildCard_h__ */ diff --git a/mozilla/modules/libjar/nsXPTZipLoader.cpp b/mozilla/modules/libjar/nsXPTZipLoader.cpp index 3a3b0aed50d..02fe27baea1 100644 --- a/mozilla/modules/libjar/nsXPTZipLoader.cpp +++ b/mozilla/modules/libjar/nsXPTZipLoader.cpp @@ -41,7 +41,8 @@ #include "nsXPTZipLoader.h" #include "nsIZipReader.h" #include "nsXPIDLString.h" -#include "nsISimpleEnumerator.h" +#include "nsString.h" +#include "nsStringEnumerator.h" static const char gCacheContractID[] = "@mozilla.org/libjar/zip-reader-cache;1"; @@ -76,36 +77,26 @@ nsXPTZipLoader::EnumerateEntries(nsILocalFile* aFile, return NS_OK; } - nsCOMPtr entries; + nsCOMPtr entries; if (NS_FAILED(zip->FindEntries("*.xpt", getter_AddRefs(entries))) || !entries) { // no problem, just no .xpt files in this archive return NS_OK; } - PRBool hasMore; - while (NS_SUCCEEDED(entries->HasMoreElements(&hasMore)) && hasMore) { - int index=0; - - nsCOMPtr sup; - if (NS_FAILED(entries->GetNext(getter_AddRefs(sup))) || !sup) - return NS_ERROR_UNEXPECTED; - - nsCOMPtr entry = do_QueryInterface(sup); - if (!entry) - return NS_ERROR_UNEXPECTED; - - nsXPIDLCString itemName; - if (NS_FAILED(entry->GetName(getter_Copies(itemName)))) + int index = 0; + while (NS_SUCCEEDED(entries->HasMore(&hasMore)) && hasMore) { + nsCAutoString itemName; + if (NS_FAILED(entries->GetNext(itemName))) return NS_ERROR_UNEXPECTED; nsCOMPtr stream; - if (NS_FAILED(zip->GetInputStream(itemName, getter_AddRefs(stream)))) + if (NS_FAILED(zip->GetInputStream(itemName.get(), getter_AddRefs(stream)))) return NS_ERROR_FAILURE; // ignore the result - aSink->FoundEntry(itemName, index++, stream); + aSink->FoundEntry(itemName.get(), index++, stream); } return NS_OK; diff --git a/mozilla/modules/libjar/nsZipArchive.cpp b/mozilla/modules/libjar/nsZipArchive.cpp index c0607482695..762aeb60809 100644 --- a/mozilla/modules/libjar/nsZipArchive.cpp +++ b/mozilla/modules/libjar/nsZipArchive.cpp @@ -57,13 +57,12 @@ #include "prio.h" #include "plstr.h" #include "prlog.h" -#include "prprf.h" #define ZFILE_CREATE PR_WRONLY | PR_CREATE_FILE #define READTYPE PRInt32 #include "zlib.h" #include "nsISupportsUtils.h" #include "nsRecyclingAllocator.h" -#include "nsPrintfCString.h" + /** * Globals * @@ -75,6 +74,7 @@ nsRecyclingAllocator *gZlibAllocator = NULL; // For placement new used for arena allocations of zip file list #include NEW_H +#define ZIP_ARENABLOCKSIZE (1*1024) #else /* STANDALONE */ @@ -134,8 +134,12 @@ char * strdup(const char *src) static PRUint16 xtoint(unsigned char *ii); static PRUint32 xtolong(unsigned char *ll); -static PRUint16 ExtractMode(PRUint32 ext_attr); -static PRBool IsSymlink(PRUint32 ext_attr); +static PRUint16 ExtractMode(unsigned char *ll); +static PRUint32 HashName(const char* aName); +#if defined(XP_UNIX) || defined(XP_BEOS) +static PRBool IsSymlink(unsigned char *ll); +static nsresult ResolveSymlink(const char *path); +#endif /*--------------------------------------------- * C API wrapper for nsZipArchive @@ -169,12 +173,15 @@ PR_PUBLIC_API(PRInt32) ZIP_OpenArchive(const char * zipname, void** hZip) if (zip == 0) return ZIP_ERR_MEMORY; - status = zip->OpenArchive(zipname); + PRFileDesc * fd = PR_Open(zipname, PR_RDONLY, 0400); + if (!fd) + return ZIP_ERR_DISK; + status = zip->OpenArchive(fd); if (status == ZIP_OK) *hZip = NS_STATIC_CAST(void*,zip); else - delete zip; + delete zip; return status; } @@ -201,7 +208,7 @@ PR_PUBLIC_API(PRInt32) ZIP_TestArchive(void *hZip) return ZIP_ERR_PARAM; /* whatever it is isn't one of ours! */ /*--- test the archive ---*/ - return zip->Test(NULL, zip->GetFd()); + return zip->Test(NULL); } @@ -250,8 +257,31 @@ PR_PUBLIC_API(PRInt32) ZIP_ExtractFile(void* hZip, const char * filename, const if (zip->kMagic != ZIP_MAGIC) return ZIP_ERR_PARAM; /* whatever it is isn't one of ours! */ - /*--- extract the file ---*/ - return zip->ExtractFile(filename, outname, zip->GetFd()); + //-- Find item in archive + nsZipItem* item = zip->GetItem(filename); + if (!item) + return ZIP_ERR_FNF; + + // Can't extract a directory + if (item->isDirectory) + return ZIP_ERR_PARAM; + + // delete any existing file so that we overwrite the file permissions + PR_Delete(outname); + + PRFileDesc* fOut = PR_Open(outname, ZFILE_CREATE, item->mode); + if (!fOut) + return ZIP_ERR_DISK; + +#if defined(XP_UNIX) && defined(STANDALONE) + // When STANDALONE is defined, PR_Open ignores its 3d argument. + mode_t msk = umask(0); + umask(msk); + chmod(outname, (item->mode | S_IRUSR) & ~msk); +#endif + + // ExtractFile also closes the fOut handle and resolves the symlink if needed + return zip->ExtractFile(item, outname, fOut); } @@ -310,15 +340,15 @@ PR_PUBLIC_API(PRInt32) ZIP_FindNext(void* hFind, char * outbuf, PRUint16 bufsize return ZIP_ERR_PARAM; /* whatever it is isn't one of ours! */ /*--- return next filename file ---*/ - nsZipItem* item; - status = find->GetArchive()->FindNext(find, &item); + const char* itemName; + status = find->FindNext(&itemName); if (status == ZIP_OK) { - PRUint16 namelen = (PRUint16)PL_strlen(item->name); + PRUint16 namelen = (PRUint16)PL_strlen(itemName); if (bufsize > namelen) { - PL_strcpy(outbuf, item->name); + PL_strcpy(outbuf, itemName); } else status = ZIP_ERR_SMALLBUF; @@ -347,7 +377,8 @@ PR_PUBLIC_API(PRInt32) ZIP_FindFree(void* hFind) return ZIP_ERR_PARAM; /* whatever it is isn't one of ours! */ /* free the find structure */ - return find->GetArchive()->FindFree(find); + delete find; + return ZIP_OK; } #if defined XP_WIN @@ -438,37 +469,24 @@ zlibFree(void *opaque, void *ptr) } #endif /* STANDALONE */ -//*********************************************************** -// nsZipReadState -- public methods -//*********************************************************** - -void nsZipReadState::Init(nsZipItem* aZipItem, PRFileDesc* aFd) +nsresult gZlibInit(z_stream *zs) { - PR_ASSERT(aFd); - mItem = aZipItem; - mCurPos = 0; + memset(zs, 0, sizeof(z_stream)); #ifndef STANDALONE - // take ownership of the file descriptor - mFd = aFd; -#endif + //-- ensure we have our zlib allocator for better performance + if (!gZlibAllocator) { + gZlibAllocator = new nsRecyclingAllocator(NBUCKETS, NS_DEFAULT_RECYCLE_TIMEOUT, "libjar"); + } + if (gZlibAllocator) { + zs->zalloc = zlibAlloc; + zs->zfree = zlibFree; + zs->opaque = gZlibAllocator; + } +#endif /* STANDALONE */ + int zerr = inflateInit2(zs, -MAX_WBITS); + if (zerr != Z_OK) return ZIP_ERR_MEMORY; - if (mItem->compression != STORED) { - memset(&mZs, 0, sizeof(mZs)); - -#ifndef STANDALONE - //-- ensure we have our zlib allocator for better performance - if (!gZlibAllocator) { - gZlibAllocator = new nsRecyclingAllocator(NBUCKETS, NS_DEFAULT_RECYCLE_TIMEOUT, "libjar"); - } - - mZs.zalloc = zlibAlloc; - mZs.zfree = zlibFree; - mZs.opaque = gZlibAllocator; -#endif - int zerr = inflateInit2(&mZs, -MAX_WBITS); - PR_ASSERT(zerr == Z_OK); - } - mCrc = crc32(0L, Z_NULL, 0); + return ZIP_OK; } //*********************************************************** @@ -476,84 +494,69 @@ void nsZipReadState::Init(nsZipItem* aZipItem, PRFileDesc* aFd) //*********************************************************** -#ifdef STANDALONE //--------------------------------------------- // nsZipArchive::OpenArchive //--------------------------------------------- -PRInt32 nsZipArchive::OpenArchive(const char * aArchiveName) +nsresult nsZipArchive::OpenArchive(PRFileDesc * fd) { - //-- validate arguments - if (aArchiveName == 0 || *aArchiveName == '\0') + if (!fd) return ZIP_ERR_PARAM; - //-- open the physical file - mFd = PR_Open(aArchiveName, PR_RDONLY, 0000); - if (mFd == 0) - return ZIP_ERR_DISK; - - //-- get table of contents for archive - return BuildFileList(GetFd()); -} - -#else -PRInt32 nsZipArchive::OpenArchiveWithFileDesc(PRFileDesc* fd) -{ - //-- validate arguments - if (fd == 0) - return ZIP_ERR_PARAM; - - //-- get table of contents for archive - return BuildFileList(fd); -} +#ifndef STANDALONE + // Initialize our arena + PL_INIT_ARENA_POOL(&mArena, "ZipArena", ZIP_ARENABLOCKSIZE); #endif + //-- Keep the filedescriptor for further reading... + mFd = fd; + + //-- get table of contents for archive + return BuildFileList(); +} + //--------------------------------------------- // nsZipArchive::Test //--------------------------------------------- -PRInt32 nsZipArchive::Test(const char *aEntryName, PRFileDesc* aFd) +nsresult nsZipArchive::Test(const char *aEntryName) { - PRInt32 rv = ZIP_OK; - nsZipItem *currItem = 0; + nsZipItem* currItem; if (aEntryName) // only test specified item { - currItem = GetFileItem(aEntryName); - if(!currItem) + currItem = GetItem(aEntryName); + if (!currItem) return ZIP_ERR_FNF; - - rv = TestItem(currItem, aFd); + //-- don't test synthetic items -- I think for a normal zip + //-- you actually *can* get away with testing a synthetic + //-- with no ill results except some unnecessary work, but + //-- for a zip which doesn't start with a zip entry (e.g., + //-- a self-extracting zip) it'll fail + if (currItem->isSynthetic) + return ZIP_OK; + return ExtractFile(currItem, 0, 0); } - else // test all items in archive - { - nsZipFind *iterator; - rv = FindInit(NULL, &iterator); - if (rv != ZIP_OK) - return rv; - // iterate over items in list - while (ZIP_OK == FindNext(iterator, &currItem)) - { - rv = TestItem(currItem, aFd); - - // check if crc check failed + // test all items in archive + for (int i = 0; i < ZIP_TABSIZE; i++) { + for (currItem = mFiles[i]; currItem; currItem = currItem->next) { + if (currItem->isSynthetic) + continue; + nsresult rv = ExtractFile(currItem, 0, 0); if (rv != ZIP_OK) - break; - + return rv; #if defined STANDALONE && defined XP_WIN ProcessWindowsMessages(); #endif } - - FindFree(iterator); } - return rv; + return ZIP_OK; } //--------------------------------------------- // nsZipArchive::CloseArchive //--------------------------------------------- -PRInt32 nsZipArchive::CloseArchive() +nsresult nsZipArchive::CloseArchive() { #ifndef STANDALONE PL_FinishArenaPool(&mArena); @@ -564,6 +567,10 @@ PRInt32 nsZipArchive::CloseArchive() // Hence, destroying the Arena is like destroying all the memory // 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 + for (int i = 0; i < ZIP_TABSIZE; i++) { + mFiles[i] = 0; + } #else // delete nsZipItems in table nsZipItem* pItem; @@ -573,167 +580,89 @@ PRInt32 nsZipArchive::CloseArchive() while (pItem != 0) { mFiles[i] = pItem->next; - delete pItem; + free(pItem); pItem = mFiles[i]; } mFiles[i] = 0; // make sure we don't double-delete } +#endif if (mFd) { PR_Close(mFd); mFd = 0; } -#endif - return ZIP_OK; } //--------------------------------------------- // nsZipArchive::GetItem //--------------------------------------------- -PRInt32 nsZipArchive::GetItem(const char * aFilename, nsZipItem **result) +nsZipItem* nsZipArchive::GetItem(const char * aEntryName) { - //-- Parameter validity check - if (aFilename == 0) - return ZIP_ERR_PARAM; - - nsZipItem* item; - - //-- find file information - item = GetFileItem(aFilename); - if (item == 0) - { - return ZIP_ERR_FNF; + if (aEntryName) { + nsZipItem* item = mFiles[ HashName(aEntryName) ]; + while (item) { + if (!strcmp(aEntryName, item->name)) + return item; //-- found it + item = item->next; } - - *result = item; // Return a pointer to the struct - return ZIP_OK; -} - -//--------------------------------------------- -// nsZipArchive::ReadInit -//--------------------------------------------- -PRInt32 nsZipArchive::ReadInit(const char* zipEntry, nsZipReadState* aRead, - PRFileDesc* aFd) -{ - - //-- Parameter validity check - if (zipEntry == 0 || aRead == 0) - return ZIP_ERR_PARAM; - - //-- find item - nsZipItem* item = GetFileItem(zipEntry); - if (!item) { - PR_Close(aFd); - return ZIP_ERR_FNF; } - - //-- verify we can handle the compression type - if (item->compression != DEFLATED && item->compression != STORED) { - PR_Close(aFd); - return ZIP_ERR_UNSUPPORTED; - } - - SeekToItem(item, aFd); - -#ifdef STANDALONE - // in standalone, nsZipArchive owns the file descriptor - mFd = aFd; -#endif - - // in non-standalone builds, the nsZipReadState will take ownership - // of the file descriptor - aRead->Init(item, aFd); - - return ZIP_OK; -} - -//--------------------------------------------- -// nsZipReadState::Available -//--------------------------------------------- -PRUint32 nsZipReadState::Available() -{ - if (mItem->compression == DEFLATED) - return (mItem->realsize - mZs.total_out); - - return mItem->size - mCurPos; + return 0; } //--------------------------------------------- // nsZipArchive::ExtractFile +// This extracts the item to the filehandle provided. +// If 'aFd' is null, it only tests the extraction. +// On extraction error(s) it removes the file. +// When needed, it also resolves the symlink. //--------------------------------------------- -PRInt32 nsZipArchive::ExtractFile(const char* zipEntry, const char* aOutname, - PRFileDesc* aFd) +nsresult nsZipArchive::ExtractFile(nsZipItem *item, const char *outname, + PRFileDesc* aFd) { - //-- Find item in archive - nsZipItem* item = GetFileItem(zipEntry); if (!item) - return ZIP_ERR_FNF; + return ZIP_ERR_PARAM; + if (!mFd) + return ZIP_ERR_GENERAL; // Directory extraction is handled in nsJAR::Extract, // so the item to be extracted should never be a directory PR_ASSERT(!item->isDirectory); - // delete any existing file so that we overwrite the file permissions - PR_Delete(aOutname); + //-- move to the start of file's data + if (SeekToItem(item, mFd) != ZIP_OK) + return ZIP_ERR_CORRUPT; - PRFileDesc* fOut = PR_Open(aOutname, ZFILE_CREATE, item->mode); - if (fOut == 0) - return ZIP_ERR_DISK; - -#if defined(XP_UNIX) && defined(STANDALONE) - // When STANDALONE is defined, PR_Open ignores its 3d argument. - mode_t msk = umask(0); - umask(msk); - chmod(aOutname, item->mode & ~msk); -#endif - - PRInt32 status = ExtractItemToFileDesc(item, fOut, aFd); - PR_Close(fOut); - - if (status != ZIP_OK) - { - PR_Delete(aOutname); - } -#if defined(XP_UNIX) || defined(XP_BEOS) - else - { - if (ZIFLAG_SYMLINK & item->flags) - { - status = ResolveSymlink(aOutname, item); - } - } -#endif - return status; -} - -PRInt32 -nsZipArchive::ExtractItemToFileDesc(nsZipItem* item, PRFileDesc* outFD, - PRFileDesc* aFd) -{ - //-- sanity check arguments - if (item == 0 || outFD == 0 || item->isDirectory) - return ZIP_ERR_PARAM; - - PRInt32 status; + nsresult rv; //-- extract the file using the appropriate method switch(item->compression) { case STORED: - status = CopyItemToDisk(item, outFD, aFd); + rv = CopyItemToDisk(item->size, item->crc32, aFd); break; case DEFLATED: - status = InflateItem(item, outFD, aFd); + rv = InflateItem(item, aFd); break; default: //-- unsupported compression type - return ZIP_ERR_UNSUPPORTED; + rv = ZIP_ERR_UNSUPPORTED; } - return status; + //-- delete the file on errors, or resolve symlink if needed + if (aFd) { + PR_Close(aFd); + if (rv != ZIP_OK) + PR_Delete(outname); +#if defined(XP_UNIX) || defined(XP_BEOS) + else if (item->isSymlink) + rv = ResolveSymlink(outname); +#endif + } + + return rv; } //--------------------------------------------- @@ -775,7 +704,7 @@ nsZipArchive::FindInit(const char * aPattern, nsZipFind **aFind) pattern = PL_strdup(aPattern); if (!pattern) - return ZIP_ERR_PARAM; + return ZIP_ERR_MEMORY; } *aFind = new nsZipFind(this, pattern, regExp); @@ -788,41 +717,35 @@ nsZipArchive::FindInit(const char * aPattern, nsZipFind **aFind) //--------------------------------------------- -// nsZipArchive::FindNext +// nsZipFind::FindNext //--------------------------------------------- -PRInt32 nsZipArchive::FindNext(nsZipFind* aFind, nsZipItem** aResult) +nsresult nsZipFind::FindNext(const char ** aResult) { - PRInt32 status; - PRBool found = PR_FALSE; - PRUint16 slot = aFind->mSlot; - nsZipItem* item = aFind->mItem; + PRBool found = PR_FALSE; - if (aFind->mArchive != this) + if (!mArchive || !aResult) return ZIP_ERR_PARAM; - // we start from last match, look for next - while (slot < ZIP_TABSIZE && !found) - { - if (item != 0) - item = item->next; // move to next in current chain - else - item = mFiles[slot]; // starting a new slot + *aResult = 0; - if (item == 0) - { // no more in this chain, move to next slot - ++slot; - continue; - } - else if (aFind->mPattern == 0) + // we start from last match, look for next + while (mSlot < ZIP_TABSIZE && !found) + { + // move to next in current chain, or move to new slot + mItem = mItem ? mItem->next : mArchive->mFiles[mSlot]; + + if (!mItem) + ++mSlot; // no more in this chain, move to next slot + else if (!mPattern) found = PR_TRUE; // always match - else if (aFind->mRegExp) - found = (NS_WildCardMatch(item->name, aFind->mPattern, PR_FALSE) == MATCH); + else if (mRegExp) + found = (NS_WildCardMatch(mItem->name, mPattern, PR_FALSE) == MATCH); else #if defined(STANDALONE) && defined(XP_MAC) // simulate * matches - found = (strncmp(item->name, aFind->mPattern, strlen(aFind->mPattern)) == 0); + found = (strncmp(mItem->name, mPattern, strlen(mPattern)) == 0); #else - found = (PL_strcmp(item->name, aFind->mPattern) == 0); + found = (PL_strcmp(mItem->name, mPattern) == 0); #endif // The way that the actual zip entry for a directory overrides a synthetic @@ -840,13 +763,11 @@ PRInt32 nsZipArchive::FindNext(nsZipFind* aFind, nsZipItem** aResult) // We test whether a prior item is a directory before comparing names // because name comparison involves function call overhead and because // the typical zip contains more files than directories. - if (found && item->isSynthetic) + if (found && mItem->isSynthetic) { - for (nsZipItem* curr = mFiles[slot]; curr != item; curr = curr->next) + for (nsZipItem* curr = mArchive->mFiles[mSlot]; curr != mItem; curr = curr->next) { - if (!curr->isDirectory) - continue; - if (0 == strcmp(item->name, curr->name)) + if (curr->isDirectory && (0 == strcmp(mItem->name, curr->name))) { // we already found the real item with this name -- skip this item found = PR_FALSE; @@ -856,65 +777,34 @@ PRInt32 nsZipArchive::FindNext(nsZipFind* aFind, nsZipItem** aResult) } } - if (found) - { - *aResult = item; - aFind->mSlot = slot; - aFind->mItem = item; - status = ZIP_OK; - } - else - status = ZIP_ERR_FNF; + if (!found) + return ZIP_ERR_FNF; - return status; -} - - - -//--------------------------------------------- -// nsZipArchive::FindFree -//--------------------------------------------- -PRInt32 nsZipArchive::FindFree(nsZipFind* aFind) -{ - if (aFind->mArchive != this) - return ZIP_ERR_PARAM; - - delete aFind; + *aResult = mItem->name; return ZIP_OK; } #if defined(XP_UNIX) || defined(XP_BEOS) //--------------------------------------------- -// nsZipArchive::ResolveSymlink +// ResolveSymlink //--------------------------------------------- -PRInt32 nsZipArchive::ResolveSymlink(const char *path, nsZipItem *item) +static nsresult ResolveSymlink(const char *path) { - PRInt32 status = ZIP_OK; - if (item->flags & ZIFLAG_SYMLINK) + PRFileDesc * fIn = PR_Open(path, PR_RDONLY, 0000); + if (!fIn) + return ZIP_ERR_DISK; + + char buf[PATH_MAX+1]; + PRInt32 length = PR_Read(fIn, (void*)buf, PATH_MAX); + PR_Close(fIn); + + if ( (length <= 0) + || ((buf[length] = 0, PR_Delete(path)) != 0) + || (symlink(buf, path) != 0)) { - char buf[PATH_MAX+1]; - PRFileDesc * fIn = PR_Open(path, PR_RDONLY, 0000); - if (fIn) - { - PRInt32 length = PATH_MAX; - length = PR_Read(fIn,(void*)buf,length); - PR_Close(fIn); - fIn = 0; - if ( length <= 0 - || (buf[length] = 0, PR_Delete(path)) != 0 - || symlink(buf, path) != 0) - { - status = ZIP_ERR_DISK; - } - } else { - status = ZIP_ERR_DISK; - } - if (fIn) - { - PR_Close(fIn); - } + return ZIP_ERR_DISK; } - return status; + return ZIP_OK; } #endif @@ -927,97 +817,75 @@ PRInt32 nsZipArchive::ResolveSymlink(const char *path, nsZipItem *item) //--------------------------------------------- // nsZipArchive::CreateZipItem //--------------------------------------------- -nsZipItem* nsZipArchive::CreateZipItem() +nsZipItem* nsZipArchive::CreateZipItem(PRUint16 namelen) { - nsZipItem* item; - + // sizeof(nsZipItem) includes space for name's null byte #ifndef STANDALONE // Arena allocate the nsZipItem void *mem; - PL_ARENA_ALLOCATE(mem, &mArena, sizeof(nsZipItem)); - // Use placement new to arena allocate the nsZipItem - item = mem ? new (mem) nsZipItem() : nsnull; + PL_ARENA_ALLOCATE(mem, &mArena, sizeof(nsZipItem)+namelen); + return (nsZipItem*)mem; #else - item = new nsZipItem(); + return (nsZipItem*)malloc(sizeof(nsZipItem)+namelen); #endif - - return item; } //--------------------------------------------- // nsZipArchive::BuildFileList //--------------------------------------------- -PRInt32 nsZipArchive::BuildFileList(PRFileDesc* aFd) +nsresult nsZipArchive::BuildFileList() { - PRInt32 status = ZIP_OK; PRUint8 buf[4*BR_BUF_SIZE]; - ZipEnd *End; - //----------------------------------------------------------------------- // locate the central directory via the End record //----------------------------------------------------------------------- - PRInt32 pos = 0L; - PRInt32 bufsize = 0; //-- get archive size using end pos - pos = PR_Seek(aFd, 0, PR_SEEK_END); + PRInt32 pos = PR_Seek(mFd, 0, PR_SEEK_END); #ifndef STANDALONE if (pos <= 0) #else - if (pos || ((pos = ftell(aFd)) <= 0)) + if (pos || ((pos = ftell(mFd)) <= 0)) #endif - status = ZIP_ERR_CORRUPT; + return ZIP_ERR_CORRUPT; - while (status == ZIP_OK) + PRBool bEndsigFound = PR_FALSE; + while (!bEndsigFound) { //-- read backwards in 1K-sized chunks (unless file is less than 1K) - pos > BR_BUF_SIZE ? bufsize = BR_BUF_SIZE : bufsize = pos; + PRInt32 bufsize = pos > BR_BUF_SIZE ? BR_BUF_SIZE : pos; pos -= bufsize; - if (!ZIP_Seek(aFd, pos, PR_SEEK_SET)) - { - status = ZIP_ERR_CORRUPT; - break; - } + if (!ZIP_Seek(mFd, pos, PR_SEEK_SET)) + return ZIP_ERR_CORRUPT; - if (PR_Read(aFd, buf, bufsize) != (READTYPE)bufsize) - { - status = ZIP_ERR_CORRUPT; - break; - } + if (PR_Read(mFd, buf, bufsize) != (READTYPE)bufsize) + return ZIP_ERR_CORRUPT; //-- scan for ENDSIG PRUint8 *endp = buf + bufsize; - PRUint32 endsig; - PRBool bEndsigFound = PR_FALSE; - for (endp -= ZIPEND_SIZE; endp >= buf; endp--) { - endsig = xtolong(endp); - if (endsig == ENDSIG) - { + 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; break; } } if (bEndsigFound) - { - End = (ZipEnd *) endp; - - //-- set pos to start of central directory - pos = xtolong(End->offset_central_dir); - if (!ZIP_Seek(aFd, pos, PR_SEEK_SET)) - status = ZIP_ERR_CORRUPT; - break; - } - if(pos <= 0) + if (pos <= 0) //-- We're at the beginning of the file, and still no sign //-- of the end signature. File must be corrupted! - status = ZIP_ERR_CORRUPT; + return ZIP_ERR_CORRUPT; //-- backward read must overlap ZipEnd length pos += ZIPEND_SIZE; @@ -1028,47 +896,26 @@ PRInt32 nsZipArchive::BuildFileList(PRFileDesc* aFd) //------------------------------------------------------- // read the central directory headers //------------------------------------------------------- - if (status == ZIP_OK) - { - //-- we think we found the central directory, read in the first chunk - pos = 0; - bufsize = PR_Read(aFd, &buf, sizeof(buf)); - if (bufsize < (PRInt32)(ZIPCENTRAL_SIZE + ZIPEND_SIZE)) - { - // We know we read the end sig and got pointed at the central - // directory--there should be at least this much - // - // (technically there can be a completely empty archive with only a - // ZipEnd structure; that's pointless and might as well be an error.) - status = ZIP_ERR_DISK; - } + PRInt32 byteCount = PR_Read(mFd, &buf, sizeof(buf)); + pos = 0; + PRUint32 sig = xtolong(buf); + while (sig == CENTRALSIG) { + //-- make sure we've read enough + if (byteCount - pos < ZIPCENTRAL_SIZE) + return ZIP_ERR_CORRUPT; - //-- verify it's a central directory record - if (xtolong(buf) != CENTRALSIG) - status = ZIP_ERR_CORRUPT; - } - - //-- loop through directory records - // - //-- we enter the loop positioned at a central directory record - //-- with enough valid data in the buffer to contain one - while (status == ZIP_OK) - { //------------------------------------------------------- // read the fixed-size data //------------------------------------------------------- ZipCentral* central = (ZipCentral*)(buf+pos); - PRUint32 namelen = xtoint(central->filename_len); - PRUint32 extralen = xtoint(central->extrafield_len); - PRUint32 commentlen = xtoint(central->commentfield_len); + PRUint16 namelen = xtoint(central->filename_len); + PRUint16 extralen = xtoint(central->extrafield_len); + PRUint16 commentlen = xtoint(central->commentfield_len); - nsZipItem* item = CreateZipItem(); + nsZipItem* item = CreateZipItem(namelen); if (!item) - { - status = ZIP_ERR_MEMORY; - break; - } + return ZIP_ERR_MEMORY; item->offset = xtolong(central->localhdr_offset); item->size = xtolong(central->size); @@ -1077,60 +924,37 @@ PRInt32 nsZipArchive::BuildFileList(PRFileDesc* aFd) item->time = xtoint(central->time); item->date = xtoint(central->date); item->isSynthetic = PR_FALSE; + item->hasDataOffset = PR_FALSE; item->compression = (PRUint8)xtoint(central->method); #if defined(DEBUG) /* Make sure our space optimization is non lossy. */ PR_ASSERT(xtoint(central->method) == (PRUint16)item->compression); #endif - PRUint32 external_attributes = xtolong(central->external_attributes); - item->mode = ExtractMode(external_attributes); - if (IsSymlink(external_attributes)) - { - item->flags |= ZIFLAG_SYMLINK; - } + + item->mode = ExtractMode(central->external_attributes); +#if defined(XP_UNIX) || defined(XP_BEOS) + // Check if item is a symlink + item->isSymlink = IsSymlink(central->external_attributes); +#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; + } + //------------------------------------------------------- // get the item name //------------------------------------------------------- -#ifndef STANDALONE - void* mem; - PL_ARENA_ALLOCATE(mem, &mArena, (namelen + 1)); - item->name = (char *) mem; - if (!item->name) - { - status = ZIP_ERR_MEMORY; - // No need to delete name. It gets deleted only when the entire arena - // goes away. - break; - } -#else - item->name = new char[namelen + 1]; - if (!item->name) - { - status = ZIP_ERR_MEMORY; - delete item; - break; - } -#endif - - PRUint32 leftover = (PRUint32)(bufsize - pos); - if (leftover < namelen) - { - //-- not enough data left in buffer for the name. - //-- move leftover to top of buffer and read more - memcpy(buf, buf+pos, leftover); - bufsize = leftover + PR_Read(aFd, buf+leftover, bufsize-leftover); - pos = 0; - - //-- make sure we were able to read enough - if ((PRUint32)bufsize < namelen) - { - status = ZIP_ERR_CORRUPT; - break; - } - } memcpy(item->name, buf+pos, namelen); item->name[namelen] = 0; @@ -1149,8 +973,6 @@ PRInt32 nsZipArchive::BuildFileList(PRFileDesc* aFd) item->next = mFiles[hash]; mFiles[hash] = item; - pos += namelen; - //-- add entries for directories in the current item's path //-- go from end to beginning, because then we can stop trying //-- to create diritems if we find that the diritem we want to @@ -1195,37 +1017,12 @@ PRInt32 nsZipArchive::BuildFileList(PRFileDesc* aFd) if (done) break; - nsZipItem* diritem = CreateZipItem(); + nsZipItem* diritem = CreateZipItem(dirnamelen); if (!diritem) - { - status = ZIP_ERR_MEMORY; - break; - } + return ZIP_ERR_MEMORY; -#ifndef STANDALONE - void* mem; - PL_ARENA_ALLOCATE(mem, &mArena, (dirnamelen + 1)); - char* dirname = (char *) mem; - if (!dirname) - { - status = ZIP_ERR_MEMORY; - // No need to delete name. It gets deleted only when the entire arena - // goes away. - break; - } -#else - char* dirname = new char[dirnamelen + 1]; - if (!dirname) - { - status = ZIP_ERR_MEMORY; - delete diritem; - break; - } -#endif - - memcpy(dirname, item->name, dirnamelen); - dirname[dirnamelen] = 0; - diritem->name = dirname; + memcpy(diritem->name, item->name, dirnamelen); + diritem->name[dirnamelen] = 0; diritem->isDirectory = PR_TRUE; diritem->isSynthetic = PR_TRUE; @@ -1249,92 +1046,26 @@ PRInt32 nsZipArchive::BuildFileList(PRFileDesc* aFd) //------------------------------------------------------- // set up to process the next item at the top of loop //------------------------------------------------------- - leftover = (PRUint32)(bufsize - pos); - if (leftover < (extralen + commentlen + ZIPCENTRAL_SIZE)) - { - //-- not enough data left to process at top of loop. - //-- move leftover and read more - memcpy(buf, buf+pos, leftover); - bufsize = leftover + PR_Read(aFd, buf+leftover, bufsize-leftover); - pos = 0; - } - //-- set position to start of next ZipCentral record - pos += extralen + commentlen; - - PRUint32 sig = xtolong(buf+pos); - if (sig != CENTRALSIG) - { - //-- we must be done or else archive is corrupt - if (sig != ENDSIG) - status = ZIP_ERR_CORRUPT; - break; - } - - //-- make sure we've read enough - if (bufsize < pos + ZIPCENTRAL_SIZE) - { - status = ZIP_ERR_CORRUPT; - break; - } + pos += namelen + extralen + commentlen; + sig = xtolong(buf+pos); } /* while reading central directory records */ -#if defined(DEBUG) - if (status != ZIP_OK) { - const char* msgs[] = { "ZIP_OK", "ZIP_ERR_GENERAL", "ZIP_ERR_MEMORY", "ZIP_ERR_DISK", "ZIP_ERR_CORRUPT", "ZIP_ERR_PARAM", "ZIP_ERR_FNF", "ZIP_ERR_UNSUPPORTED", "ZIP_ERR_SMALLBUF", "UNKNOWN" }; - printf("nsZipArchive::BuildFileList status = %d '%s'\n", (int)status, msgs[(status <= 0 && status >= -8) ? -status : 9]); - } -#endif + if (sig != ENDSIG) + return ZIP_ERR_CORRUPT; - return status; + return ZIP_OK; } -//--------------------------------------------- -// nsZipArchive::GetFileItem -//--------------------------------------------- -nsZipItem* nsZipArchive::GetFileItem(const char * zipEntry) -{ - PR_ASSERT(zipEntry != 0); - - nsZipItem* item = mFiles[ HashName(zipEntry) ]; - - for (; item != 0; item = item->next) - { - if (0 == PL_strcmp(zipEntry, item->name)) - break; //-- found it - } - - return item; -} - - -//--------------------------------------------- -// nsZipArchive::HashName -//--------------------------------------------- -PRUint32 nsZipArchive::HashName(const char* aName) -{ - PRUint32 val = 0; - PRUint8* c; - - PR_ASSERT(aName != 0); - - for (c = (PRUint8*)aName; *c != 0; c++) { - val = val*37 + *c; - } - - return (val % ZIP_TABSIZE); -} //--------------------------------------------- // nsZipArchive::SeekToItem //--------------------------------------------- -PRInt32 nsZipArchive::SeekToItem(const nsZipItem* aItem, PRFileDesc* aFd) +nsresult nsZipArchive::SeekToItem(nsZipItem* aItem, PRFileDesc* aFd) { PR_ASSERT (aItem); - PRFileDesc* fd = aFd; - //-- the first time an item is used we need to calculate its offset - if (!(aItem->flags & ZIFLAG_DATAOFFSET)) + if (!aItem->hasDataOffset) { //-- aItem->offset contains the header offset, not the data offset. //-- read local header to get variable length values and calculate @@ -1343,25 +1074,25 @@ PRInt32 nsZipArchive::SeekToItem(const 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(fd, aItem->offset, PR_SEEK_SET)) + if (!ZIP_Seek(aFd, aItem->offset, PR_SEEK_SET)) return ZIP_ERR_CORRUPT; ZipLocal Local; - if (PR_Read(fd, (char*)&Local, ZIPLOCAL_SIZE) != (READTYPE) ZIPLOCAL_SIZE - || xtolong(Local.signature) != LOCALSIG) + if ((PR_Read(aFd, (char*)&Local, ZIPLOCAL_SIZE) != (READTYPE) ZIPLOCAL_SIZE) || + (xtolong(Local.signature) != LOCALSIG)) { //-- read error or local header not found return ZIP_ERR_CORRUPT; } - ((nsZipItem*)aItem)->offset += ZIPLOCAL_SIZE + - xtoint(Local.filename_len) + - xtoint(Local.extrafield_len); - ((nsZipItem*)aItem)->flags |= ZIFLAG_DATAOFFSET; + aItem->offset += ZIPLOCAL_SIZE + + xtoint(Local.filename_len) + + xtoint(Local.extrafield_len); + aItem->hasDataOffset = PR_TRUE; } //-- move to start of file in archive - if (!ZIP_Seek(fd, aItem->offset, PR_SEEK_SET)) + if (!ZIP_Seek(aFd, aItem->offset, PR_SEEK_SET)) return ZIP_ERR_CORRUPT; return ZIP_OK; @@ -1370,284 +1101,91 @@ PRInt32 nsZipArchive::SeekToItem(const nsZipItem* aItem, PRFileDesc* aFd) //--------------------------------------------- // nsZipArchive::CopyItemToDisk //--------------------------------------------- -PRInt32 -nsZipArchive::CopyItemToDisk(const nsZipItem* aItem, - PRFileDesc* fOut, PRFileDesc* aFd) +nsresult +nsZipArchive::CopyItemToDisk(PRUint32 itemSize, PRUint32 itemCrc, 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'. + */ { - PRInt32 status = ZIP_OK; - PRUint32 chunk, pos, size, crc; - - PR_ASSERT(aItem != 0 && fOut != 0); - - PRFileDesc* fd = aFd; - - //-- move to the start of file's data - if (SeekToItem(aItem, aFd) != ZIP_OK) - return ZIP_ERR_CORRUPT; - + PRUint32 chunk, pos, crc; char buf[ZIP_BUFLEN]; //-- initialize crc crc = crc32(0L, Z_NULL, 0); //-- copy chunks until file is done - size = aItem->size; - for (pos=0; pos < size; pos += chunk) + for (pos = 0; pos < itemSize; pos += chunk) { - chunk = (pos+ZIP_BUFLEN <= size) ? ZIP_BUFLEN : size - pos; - - if (PR_Read(fd, buf, chunk) != (READTYPE)chunk) + chunk = (itemSize - pos < ZIP_BUFLEN) ? (itemSize - pos) : ZIP_BUFLEN; + + if (PR_Read(mFd, buf, chunk) != (READTYPE)chunk) { //-- unexpected end of data in archive - status = ZIP_ERR_CORRUPT; - break; + return ZIP_ERR_CORRUPT; } //-- incrementally update crc32 crc = crc32(crc, (const unsigned char*)buf, chunk); - if (PR_Write(fOut, buf, chunk) < (READTYPE)chunk) + if (outFD && PR_Write(outFD, buf, chunk) < (READTYPE)chunk) { //-- Couldn't write all the data (disk full?) - status = ZIP_ERR_DISK; - break; + return ZIP_ERR_DISK; } } //-- verify crc32 - if ((status == ZIP_OK) && (crc != aItem->crc32)) - status = ZIP_ERR_CORRUPT; - - return status; -} - -#ifndef STANDALONE -//------------------------------------------ -// nsZipReadState::Read -//------------------------------------------ -PRInt32 -nsZipReadState::Read(char* aBuffer, PRUint32 aCount, - PRUint32* aBytesRead) -{ - if (!aBuffer) - return ZIP_ERR_GENERAL; - - PRInt32 result; - - if (!Available()) { - *aBytesRead = 0; - return ZIP_OK; - } - - switch (mItem->compression) { - case DEFLATED: - result = ContinueInflate(aBuffer, aCount, aBytesRead); - break; - case STORED: - result = ContinueCopy(aBuffer, aCount, aBytesRead); - break; - default: - result = ZIP_ERR_UNSUPPORTED; - } - - // be aggressive about closing! - // note that sometimes, we will close mFd before we've finished - // deflating - this is because zlib buffers the input - if (mCurPos >= mItem->size && mFd) { - PR_Close(mFd); - mFd = NULL; - } - - return result; -} - -PRInt32 -nsZipReadState::ContinueInflate(char* aBuffer, PRUint32 aCount, - PRUint32* aBytesRead) -{ - - // just some stuff that will be helpful later - const PRUint32 inSize = mItem->size; - const PRUint32 outSize = mItem->realsize; - - int zerr = Z_OK; - //-- inflate loop - - const PRUint32 oldTotalOut = mZs.total_out; - - mZs.next_out = (unsigned char*)aBuffer; - mZs.avail_out = ((mZs.total_out + aCount) < outSize) ? - aCount : (outSize - mZs.total_out); - - // make sure we aren't reading too much - PR_ASSERT(mZs.avail_out <= aCount); - - *aBytesRead = 0; - while (mZs.avail_out != 0 && zerr == Z_OK) { - - if (mZs.avail_in == 0 && mCurPos < inSize) { - // time to fill the buffer! - PRUint32 bytesToRead = ((mCurPos + ZIP_BUFLEN) < inSize) ? - ZIP_BUFLEN : inSize - mCurPos; - - PR_ASSERT(mFd); - PRInt32 bytesRead = PR_Read(mFd, mReadBuf, bytesToRead); - if (bytesRead < 0) { - zerr = Z_ERRNO; - break; - } - - mCrc = crc32(mCrc, mReadBuf, bytesRead); - mCurPos += bytesRead; - - // now reset the state - mZs.next_in = mReadBuf; - mZs.avail_in = bytesRead; - } - -#if 0 - // stop returning valid data as soon as we know we have a bad CRC - if (mCurPos >= inSize && - mCrc != mItem->crc32) { - // asserting because while this rarely happens, you definitely - // want to catch it in debug builds! - PR_ASSERT(0); + if (crc != itemCrc) return ZIP_ERR_CORRUPT; - } -#endif - - // now inflate - zerr = inflate(&mZs, Z_PARTIAL_FLUSH); - } - - if ((zerr != Z_OK) && (zerr != Z_STREAM_END)) - return ZIP_ERR_CORRUPT; - - *aBytesRead = (mZs.total_out - oldTotalOut); - - // be aggressive about closing the stream - // for some reason we don't always get Z_STREAM_END - if (zerr == Z_STREAM_END || mZs.total_out == mItem->realsize) { - inflateEnd(&mZs); - } return ZIP_OK; } -PRInt32 nsZipReadState::ContinueCopy(char* aBuf, - PRUint32 aCount, - PRUint32* aBytesRead) -{ - // we still use the fields of mZs, we just use memcpy rather than inflate - - if (mCurPos + aCount > mItem->realsize) - aCount = (mItem->realsize - mCurPos); - - PR_ASSERT(mFd); - PRInt32 bytesRead = PR_Read(mFd, aBuf, aCount); - if (bytesRead < 0) - return ZIP_ERR_DISK; - - mCurPos += bytesRead; - - *aBytesRead = bytesRead; - - return ZIP_OK; -} - -#endif //--------------------------------------------- // nsZipArchive::InflateItem //--------------------------------------------- -PRInt32 nsZipArchive::InflateItem(const nsZipItem* aItem, PRFileDesc* fOut, PRFileDesc* aFd) +nsresult nsZipArchive::InflateItem(const nsZipItem* aItem, PRFileDesc* outFD) /* - * This function either inflates an archive item to disk, to the - * file specified by aOutname, or into a buffer specified by - * bigBuf. bigBuf then gets copied into the "real" output - * buffer a chunk at a time by ReadInflatedItem(). Memory-wise, - * this is inefficient, since it stores an entire copy of the - * decompressed item in memory, then copies it to the caller's - * buffer. A more memory-efficient implementation is possible, - * in which the outbuf in this function could be returned - * directly, but implementing it would be complex. + * 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'. */ { - PRInt32 status = ZIP_OK; - PRUint32 chunk, inpos, outpos, size, crc; - PRUint32 bigBufSize=0; - z_stream zs; - int zerr; - PRBool bInflating = PR_FALSE; - PRBool bRead; - PRBool bWrote; - PRBool bToFile; - Bytef* old_next_out; - - // -- if aOutname is null, we'll be writing to a buffer instead of a file - if (fOut != 0) - { - PR_ASSERT(aItem != 0); - bToFile = PR_TRUE; - } - else - { - // -- Writing to a buffer, so bigBuf must not be null. - PR_ASSERT(aItem); - bToFile = PR_FALSE; - bigBufSize = aItem->realsize; - } - - //-- move to the start of file's data - if (SeekToItem(aItem, aFd) != ZIP_OK) - return ZIP_ERR_CORRUPT; + PR_ASSERT(aItem); //-- allocate deflation buffers Bytef inbuf[ZIP_BUFLEN]; Bytef outbuf[ZIP_BUFLEN]; //-- set up the inflate - memset(&zs, 0, sizeof(zs)); -#ifndef STANDALONE - //-- ensure we have our zlib allocator for better performance - if (!gZlibAllocator) { - gZlibAllocator = new nsRecyclingAllocator(NBUCKETS, NS_DEFAULT_RECYCLE_TIMEOUT, "libjar"); - } - - zs.zalloc = zlibAlloc; - zs.zfree = zlibFree; - zs.opaque = gZlibAllocator; -#endif - - zerr = inflateInit2(&zs, -MAX_WBITS); - if (zerr != Z_OK) - { - status = ZIP_ERR_GENERAL; - goto cleanup; - } - bInflating = PR_TRUE; - + z_stream zs; + nsresult status = gZlibInit(&zs); + if (status != ZIP_OK) + return ZIP_ERR_GENERAL; //-- inflate loop - size = aItem->size; - outpos = inpos = 0; zs.next_out = outbuf; zs.avail_out = ZIP_BUFLEN; - crc = crc32(0L, Z_NULL, 0); + + PRUint32 size = aItem->size; + PRUint32 outpos = 0; + PRUint32 crc = crc32(0L, Z_NULL, 0); + int zerr = Z_OK; while (zerr == Z_OK) { - bRead = PR_FALSE; - bWrote = PR_FALSE; + PRBool bRead = PR_FALSE; + PRBool bWrote= PR_FALSE; if (zs.avail_in == 0 && zs.total_in < size) { //-- 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; - inpos = zs.total_in; // input position - chunk = (inpos + ZIP_BUFLEN <= size) ? ZIP_BUFLEN : size - inpos; - - if (PR_Read(aFd, inbuf, chunk) != (READTYPE)chunk) + if (PR_Read(mFd, inbuf, chunk) != (READTYPE)chunk) { //-- unexpected end of data status = ZIP_ERR_CORRUPT; @@ -1662,7 +1200,7 @@ PRInt32 nsZipArchive::InflateItem(const nsZipItem* aItem, PRFileDesc* fOut, PRFi if (zs.avail_out == 0) { //-- write inflated buffer to disk and make space - if (PR_Write(fOut, outbuf, ZIP_BUFLEN) < ZIP_BUFLEN) + if (outFD && PR_Write(outFD, outbuf, ZIP_BUFLEN) < ZIP_BUFLEN) { //-- Couldn't write all the data (disk full?) status = ZIP_ERR_DISK; @@ -1677,7 +1215,7 @@ PRInt32 nsZipArchive::InflateItem(const nsZipItem* aItem, PRFileDesc* fOut, PRFi if(bRead || bWrote) { - old_next_out = zs.next_out; + Bytef* old_next_out = zs.next_out; zerr = inflate(&zs, Z_PARTIAL_FLUSH); @@ -1702,8 +1240,8 @@ PRInt32 nsZipArchive::InflateItem(const nsZipItem* aItem, PRFileDesc* fOut, PRFi //-- write last inflated bit to disk if (zerr == Z_STREAM_END && outpos < zs.total_out) { - chunk = zs.total_out - outpos; - if (PR_Write(fOut, outbuf, chunk) < (READTYPE)chunk) + PRUint32 chunk = zs.total_out - outpos; + if (outFD && PR_Write(outFD, outbuf, chunk) < (READTYPE)chunk) status = ZIP_ERR_DISK; } @@ -1718,175 +1256,8 @@ PRInt32 nsZipArchive::InflateItem(const nsZipItem* aItem, PRFileDesc* fOut, PRFi PR_ASSERT(status != ZIP_OK || zs.total_out == aItem->realsize); cleanup: - if (bInflating) - { - //-- free zlib internal state - inflateEnd(&zs); - } - - return status; -} - -//--------------------------------------------- -// nsZipArchive::TestItem -//--------------------------------------------- -PRInt32 nsZipArchive::TestItem(const nsZipItem* aItem, PRFileDesc* aFd) -{ - Bytef inbuf[ZIP_BUFLEN], outbuf[ZIP_BUFLEN], *old_next_out; - PRUint32 size, chunk=0, inpos, crc; - PRInt32 status = ZIP_OK; - int zerr = Z_OK; - z_stream zs; - PRBool bInflating = PR_FALSE; - PRBool bRead; - PRBool bWrote; - - //-- param checks - if (!aItem) - return ZIP_ERR_PARAM; - if (aItem->compression != STORED && aItem->compression != DEFLATED) - return ZIP_ERR_UNSUPPORTED; - - //-- don't test synthetic items -- I think for a normal zip - //-- you actually *can* get away with testing a synthetic - //-- with no ill results except some unnecessary work, but - //-- for a zip which doesn't start with a zip entry (e.g., - //-- a self-extracting zip) it'll fail - if (aItem->isSynthetic) - return ZIP_OK; - - //-- move to the start of file's data - if (SeekToItem(aItem, aFd) != ZIP_OK) - return ZIP_ERR_CORRUPT; - - //-- set up the inflate if DEFLATED - if (aItem->compression == DEFLATED) - { - memset(&zs, 0, sizeof(zs)); - zerr = inflateInit2(&zs, -MAX_WBITS); - if (zerr != Z_OK) - { - status = ZIP_ERR_GENERAL; - goto cleanup; - } - else - { - zs.next_out = outbuf; - zs.avail_out = ZIP_BUFLEN; - } - bInflating = PR_TRUE; - } - - //-- initialize crc checksum - crc = crc32(0L, Z_NULL, 0); - - size = aItem->size; - inpos = 0; - - //-- read in ZIP_BUFLEN-sized chunks of item - //-- inflating if item is DEFLATED - while (zerr == Z_OK) - { - bRead = PR_FALSE; // used to check if new data to inflate - bWrote = PR_FALSE; // used to reset zs.next_out to outbuf - // when outbuf fills up - - //-- read to inbuf - if (aItem->compression == DEFLATED) - { - if (zs.avail_in == 0 && zs.total_in < size) - { - //-- no data to inflate yet still more in file: - //-- read another chunk of compressed data - - inpos = zs.total_in; // input position - chunk = (inpos + ZIP_BUFLEN <= size) ? ZIP_BUFLEN : size - inpos; - - if (PR_Read(aFd, inbuf, chunk) != (READTYPE)chunk) - { - //-- unexpected end of data - status = ZIP_ERR_CORRUPT; - break; - } - - zs.next_in = inbuf; - zs.avail_in = chunk; - bRead = PR_TRUE; - } - - if (zs.avail_out == 0) - { - //-- reuse output buffer - zs.next_out = outbuf; - zs.avail_out = ZIP_BUFLEN; - bWrote = PR_TRUE; // mimic writing to disk/memory - } - } - else - { - if (inpos < size) - { - //-- read a chunk in - chunk = (inpos + ZIP_BUFLEN <= size) ? ZIP_BUFLEN : size - inpos; - - if (PR_Read(aFd, inbuf, chunk) != (READTYPE)chunk) - { - //-- unexpected end of data - status = ZIP_ERR_CORRUPT; - break; - } - - inpos += chunk; - } - else - { - //-- finished reading STORED item - break; - } - } - - //-- inflate if item is DEFLATED - if (aItem->compression == DEFLATED) - { - if (bRead || bWrote) - { - old_next_out = zs.next_out; - - zerr = inflate(&zs, Z_PARTIAL_FLUSH); - - //-- incrementally update crc checksum - crc = crc32(crc, (const unsigned char*)old_next_out, zs.next_out - old_next_out); - } - else - zerr = Z_STREAM_END; - } - //-- else just use input buffer containing data from STORED item - else - { - //-- incrementally update crc checksum - crc = crc32(crc, (const unsigned char*)inbuf, chunk); - } - } - - //-- 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; - goto cleanup; - } - - //-- verify computed crc checksum against header info crc - if (status == ZIP_OK && crc != aItem->crc32) - { - status = ZIP_ERR_CORRUPT; - } - -cleanup: - if (bInflating) - { - //-- free zlib internal state - inflateEnd(&zs); - } + //-- free zlib internal state + inflateEnd(&zs); return status; } @@ -1895,21 +1266,16 @@ cleanup: // nsZipArchive constructor and destructor //------------------------------------------ -nsZipArchive::nsZipArchive() - : kMagic(ZIP_MAGIC), kArenaBlockSize(1*1024) #ifdef STANDALONE - , mFd(0) +nsZipArchive::nsZipArchive() : kMagic(ZIP_MAGIC), mFd(0) +#else +nsZipArchive::nsZipArchive() : mFd(0) #endif { MOZ_COUNT_CTOR(nsZipArchive); // initialize the table to NULL memset(mFiles, 0, sizeof mFiles); - -#ifndef STANDALONE - // Initialize our arena - PL_INIT_ARENA_POOL(&mArena, "ZipArena", kArenaBlockSize); -#endif } nsZipArchive::~nsZipArchive() @@ -1920,41 +1286,18 @@ nsZipArchive::~nsZipArchive() } - - -//------------------------------------------ -// nsZipItem constructor and destructor -//------------------------------------------ - -nsZipItem::nsZipItem() : name(0), offset(0), next(0), flags(0) -{ -} - -nsZipItem::~nsZipItem() -{ -#ifdef STANDALONE - if (name != 0) - { - delete [] name; - name = 0; - } -#endif -} - -//------------------------------------------ -// nsZipReadState -//------------------------------------------ - //------------------------------------------ // nsZipFind constructor and destructor //------------------------------------------ -nsZipFind::nsZipFind(nsZipArchive* aZip, char* aPattern, PRBool aRegExp) -: kMagic(ZIPFIND_MAGIC), +nsZipFind::nsZipFind(nsZipArchive* aZip, char* aPattern, PRBool aRegExp) : +#ifdef STANDALONE + kMagic(ZIPFIND_MAGIC), +#endif mArchive(aZip), mPattern(aPattern), - mSlot(0), mItem(0), + mSlot(0), mRegExp(aRegExp) { MOZ_COUNT_CTOR(nsZipFind); @@ -1962,28 +1305,32 @@ nsZipFind::nsZipFind(nsZipArchive* aZip, char* aPattern, PRBool aRegExp) nsZipFind::~nsZipFind() { - if (mPattern != 0) - PL_strfree(mPattern); + PR_FREEIF(mPattern); MOZ_COUNT_DTOR(nsZipFind); } -//------------------------------------------ -// nsZipFind::GetArchive -//------------------------------------------ -nsZipArchive* nsZipFind::GetArchive() -{ - if (!mArchive) - return NULL; - - return mArchive; -} - - //------------------------------------------ // helper functions //------------------------------------------ +/* + * HashName + * + * returns a hash key for the entry name + */ +static PRUint32 HashName(const char* aName) +{ + PR_ASSERT(aName != 0); + + PRUint32 val = 0; + for (PRUint8* c = (PRUint8*)aName; *c != 0; c++) { + val = val*37 + *c; + } + + return (val % ZIP_TABSIZE); +} + /* * x t o i n t * @@ -2003,16 +1350,10 @@ static PRUint16 xtoint (unsigned char *ii) */ static PRUint32 xtolong (unsigned char *ll) { - PRUint32 ret; - - ret = ( - (((PRUint32) ll [0]) << 0) | - (((PRUint32) ll [1]) << 8) | - (((PRUint32) ll [2]) << 16) | - (((PRUint32) ll [3]) << 24) - ); - - return ret; + return (PRUint32)( (ll [0] << 0) | + (ll [1] << 8) | + (ll [2] << 16) | + (ll [3] << 24) ); } /* @@ -2023,42 +1364,21 @@ static PRUint32 xtolong (unsigned char *ll) * Subsequently it tacks on the implicit user-read * bit. */ -static PRUint16 ExtractMode(PRUint32 ext_attr) +static PRUint16 ExtractMode(unsigned char *ll) { - ext_attr &= 0x00FF0000; - ext_attr >>= 16; - ext_attr |= 0x00000100; - - return (PRUint16) ext_attr; + return ((PRUint16)(ll[2])) | 0x0100; } - +#if defined(XP_UNIX) || defined(XP_BEOS) /* * * Return true if the attributes are for a symbolic link * */ -static PRBool IsSymlink(PRUint32 ext_attr) +static PRBool IsSymlink(unsigned char *ll) { - return (((ext_attr>>16) & S_IFMT) == S_IFLNK) ? PR_TRUE : PR_FALSE; -} - -#ifndef STANDALONE -PRTime -nsZipItem::GetModTime() -{ - char buffer[17]; - - PRUint16 aDate = this->date; - PRUint16 aTime = this->time; - - PR_snprintf(buffer, sizeof(buffer), "%02d/%02d/%04d %02d:%02d", - ((aDate >> 5) & 0x0F), (aDate & 0x1F), (aDate >> 9) + 1980, - ((aTime >> 11) & 0x1F), ((aTime >> 5) & 0x3F)); - - PRTime result; - PR_ParseTimeString(buffer, PR_FALSE, &result); - return result; + return ((xtoint(ll+2) & S_IFMT) == S_IFLNK); } #endif + diff --git a/mozilla/modules/libjar/nsZipArchive.h b/mozilla/modules/libjar/nsZipArchive.h index 7386f7a8ab2..0bec9de3ccf 100644 --- a/mozilla/modules/libjar/nsZipArchive.h +++ b/mozilla/modules/libjar/nsZipArchive.h @@ -61,9 +61,6 @@ #endif -#define ZIFLAG_SYMLINK 0x01 /* zip item is a symlink */ -#define ZIFLAG_DATAOFFSET 0x02 /* zip item offset points to file data */ - #include "zlib.h" class nsZipFind; @@ -78,12 +75,10 @@ struct PRFileDesc; * This file defines some of the basic structures used by libjar to * read Zip files. It makes use of zlib in order to do the decompression. * - * A few notes on the classes: + * A few notes on the classes/structs: * nsZipArchive represents a single Zip file, and maintains an index * of all the items in the file. * nsZipItem represents a single item (file) in the Zip archive. - * nsZipReadState represents a read-in-progress, and maintains all - * zlib state * nsZipFind represents the metadata involved in doing a search, * and current state of the iteration of found objects. * @@ -94,74 +89,48 @@ struct PRFileDesc; * as NS_ASSERTION(). Instead, use the basic NSPR equivalents. * * There is one key difference in the way that this code behaves in - * STANDALONE mode. In STANDALONE mode, the nsZipArchive owns the - * single file descriptor and that is used to read the ZIP file. Since - * there is only one nsZipArchive per file, you can only read one file - * at a time from the Zip file. - * - * In non-STANDALONE mode, nsZipReadState owns the file descriptor. - * Since there can be multiple nsZipReadStates in existence at the - * same time, there can be multiple reads from the same nsZipArchive - * happening at the same time. + * STANDALONE mode. The nsZipArchive owns a single file descriptor and + * that is used to read the ZIP file index, and for 'Test' and 'Extract'. + * Since there is only one nsZipArchive per file, you can only Test/Extract + * one file at a time from the Zip file. + * 'MT''safe' reading from the zipfile is performed through JARInputStream, + * which maintains its own file descriptor, allowing for multiple reads + * concurrently from the same zip file. */ /** - * nsZipItem -- a helper class for nsZipArchive + * nsZipItem -- a helper struct for nsZipArchive * * each nsZipItem represents one file in the archive and all the * information needed to manipulate it. */ -class nsZipItem +struct nsZipItem { -public: - char* name; /* '\0' terminated */ + nsZipItem* next; - PRUint32 offset; - PRUint32 size; /* size in original file */ - PRUint32 realsize; /* inflated size */ - PRUint32 crc32; - PRPackedBool isDirectory; - PRPackedBool isSynthetic; /* whether item is an actual zip entry or was + PRUint32 offset; + PRUint32 size; /* size in original file */ + PRUint32 realsize; /* inflated size */ + PRUint32 crc32; + + /* + * Keep small items together, to avoid overhead. + */ + PRUint16 time; + PRUint16 date; + PRUint16 mode; + PRUint8 compression; + PRPackedBool hasDataOffset : 1; + PRPackedBool isDirectory : 1; + PRPackedBool isSynthetic : 1; /* whether item is an actual zip entry or was generated as part of a real entry's path, e.g. foo/ in a zip containing only foo/a.txt and no foo/ entry is synthetic */ - - nsZipItem* next; - - /* - * Keep small items together, to avoid overhead. - */ - PRUint16 mode; - PRUint16 time; - PRUint16 date; - - /* - * Keep small items together, to avoid overhead. - */ - PRUint8 compression; - PRUint8 flags; - -#ifndef STANDALONE - /** - * GetModTime - * - * Utility to get an NSPR-friendly formatted string - * representing the last modified time of this item. - * - * @return nsprstr The modification time in PRTime - */ - PRTime GetModTime(); +#if defined(XP_UNIX) || defined(XP_BEOS) + PRPackedBool isSymlink : 1; #endif - nsZipItem(); - ~nsZipItem(); - - -private: - //-- prevent copies and assignments - nsZipItem& operator=(const nsZipItem& rhs); - nsZipItem(const nsZipItem& rhs); - + char name[1]; // actually, bigger than 1 }; /** @@ -170,12 +139,13 @@ private: */ class nsZipArchive { + friend class nsZipFind; + public: +#ifdef STANDALONE /** cookie used to validate supposed objects passed from C code */ const PRInt32 kMagic; - - /** Block size by which Arena grows. Arena used by filelists */ - const PRUint32 kArenaBlockSize; +#endif /** constructing does not open the archive. See OpenArchive() */ nsZipArchive(); @@ -183,12 +153,6 @@ public: /** destructing the object closes the archive */ ~nsZipArchive(); -#ifdef STANDALONE - /** helper routine for passing around mFd - */ - PRFileDesc* GetFd() { return mFd; } -#endif - /** * OpenArchive * @@ -196,14 +160,10 @@ public: * object. If we were allowed to use exceptions this would have been * part of the constructor * - * @param aArchiveName full pathname of archive + * @param fd File descriptor of file to open * @return status code */ -#ifdef STANDALONE - PRInt32 OpenArchive(const char * aArchiveName); -#else - PRInt32 OpenArchiveWithFileDesc(PRFileDesc* fd); -#endif + nsresult OpenArchive(PRFileDesc* fd); /** * Test the integrity of items in this archive by running @@ -214,53 +174,35 @@ public: * * @return status code */ - PRInt32 Test(const char *aEntryName, PRFileDesc* aFd); + nsresult Test(const char *aEntryName); /** * Closes an open archive. */ - PRInt32 CloseArchive(); + nsresult CloseArchive(); /** * GetItem - * - * @param aFilename Name of file in the archive - * @return status code + * @param aEntryName Name of file in the archive + * @return pointer to nsZipItem */ - PRInt32 GetItem(const char * aFilename, nsZipItem** result); + nsZipItem* GetItem(const char * aEntryName); /** - * ReadInit - * - * Prepare to read from an item in the archive. Takes ownership of - * the file descriptor, and will retain responsibility for closing - * it property upon destruction. + * ExtractFile * - * @param zipEntry name of item in file - * @param aRead is filled with appropriate values + * @param zipEntry Name of file in archive to extract + * @param outFD Filedescriptor to write contents to + * @param outname Name of file to write to * @return status code */ - PRInt32 ReadInit(const char* zipEntry, nsZipReadState* aRead, PRFileDesc* aFd); - - - /** - * ExtractFile - * - * @param zipEntry name of file in archive to extract - * @param aOutname where to extract on disk - * @return status code - */ - PRInt32 ExtractFile(const char * zipEntry, const char * aOutname, - PRFileDesc* aFd); - - PRInt32 ExtractItemToFileDesc(nsZipItem* item, PRFileDesc* outFD, - PRFileDesc* aFd); + nsresult ExtractFile(nsZipItem * zipEntry, const char *outname, PRFileDesc * outFD); /** * FindInit * * Initializes a search for files in the archive. FindNext() returns - * the actual matches. FindFree() must be called when you're done + * the actual matches. The nsZipFind must be deleted when you're done * * @param aPattern a string or RegExp pattern to search for * (may be NULL to find all files in archive) @@ -272,23 +214,11 @@ public: PRInt32 FindInit(const char * aPattern, nsZipFind** aFind); /** - * FindNext - * - * @param aFind the Find structure returned by FindInit - * @param aResult the next item that matches the pattern + * Moves the filepointer aFd to the start of data of the aItem. + * @param aItem Pointer to nsZipItem + * @param aFd The filepointer to move */ - PRInt32 FindNext(nsZipFind* aFind, nsZipItem** aResult); - - PRInt32 FindFree(nsZipFind *aFind); - -#if defined(XP_UNIX) || defined(XP_BEOS) - /** - * ResolveSymLinks - * @param path where the file is located - * @param zipItem the zipItem related to "path" - */ - PRInt32 ResolveSymlink(const char *path, nsZipItem *zipItem); -#endif + nsresult SeekToItem(nsZipItem* aItem, PRFileDesc* aFd); private: //--- private members --- @@ -296,110 +226,23 @@ private: nsZipItem* mFiles[ZIP_TABSIZE]; #ifndef STANDALONE PLArenaPool mArena; -#else - // in standalone, each nsZipArchive has its own mFd - PRFileDesc *mFd; #endif + // Used for central directory reading, and for Test and Extract + PRFileDesc *mFd; + //--- private methods --- nsZipArchive& operator=(const nsZipArchive& rhs); // prevent assignments nsZipArchive(const nsZipArchive& rhs); // prevent copies - nsZipItem* CreateZipItem(); - PRInt32 BuildFileList(PRFileDesc* aFd); - nsZipItem* GetFileItem(const char * zipEntry); - PRUint32 HashName(const char* aName); - - PRInt32 SeekToItem(const nsZipItem* aItem, - PRFileDesc* aFd); - PRInt32 CopyItemToDisk(const nsZipItem* aItem, PRFileDesc* outFD, - PRFileDesc* aFd); - PRInt32 InflateItem(const nsZipItem* aItem, PRFileDesc* outFD, - PRFileDesc* aFd); - PRInt32 TestItem(const nsZipItem *aItem, - PRFileDesc* aFd); + nsZipItem* CreateZipItem(PRUint16 namelen); + nsresult BuildFileList(); + nsresult CopyItemToDisk(PRUint32 size, PRUint32 crc, PRFileDesc* outFD); + nsresult InflateItem(const nsZipItem* aItem, PRFileDesc* outFD); }; -/** - * nsZipReadState - * - * a helper class for nsZipArchive, representing a read in progress - */ - -class nsZipReadState -{ -public: - - nsZipReadState() : -#ifndef STANDALONE - mFd(0), -#endif - mCurPos(0) - { MOZ_COUNT_CTOR(nsZipReadState); } - ~nsZipReadState() - { -#ifndef STANDALONE - if (mFd) - PR_Close(mFd); -#endif - MOZ_COUNT_DTOR(nsZipReadState); - } - - void Init(nsZipItem* aZipItem, PRFileDesc* aFd); - -#ifndef STANDALONE - /** - * Read - * - * Read from the item specified to ReadInit. ReadInit must be - * called first. - * - * @param aRead the structure returned by ReadInit - * @param buf buffer to write data into. - * @param count number of bytes to read - * @param actual (out) number of bytes read - * @return status code - */ - PRInt32 Read(char* buf, PRUint32 count, PRUint32* actual); -#endif - - /** - * Available - * - * Returns the number of bytes left to be read from the - * item specified to ReadInit. ReadInit must be called first. - * - * @param aRead the structure returned by ReadInit - * @return the number of bytes still to be read - */ - PRUint32 Available(); - -#ifndef STANDALONE - PRFileDesc* mFd; -#endif - - nsZipItem* mItem; - PRUint32 mCurPos; - unsigned char mReadBuf[ZIP_BUFLEN]; - z_stream mZs; - PRUint32 mCrc; - -private: -#ifndef STANDALONE - PRInt32 ContinueInflate(char* aBuf, - PRUint32 aCount, - PRUint32* aBytesRead); - PRInt32 ContinueCopy(char* aBuf, - PRUint32 aCount, - PRUint32* aBytesRead); -#endif - - //-- prevent copies and assignments - nsZipReadState& operator=(const nsZipReadState& rhs); - nsZipReadState(const nsZipFind& rhs); -}; /** * nsZipFind @@ -408,26 +251,28 @@ private: */ class nsZipFind { - friend class nsZipArchive; - public: +#ifdef STANDALONE const PRInt32 kMagic; +#endif nsZipFind(nsZipArchive* aZip, char* aPattern, PRBool regExp); ~nsZipFind(); - nsZipArchive* GetArchive(); + nsresult FindNext(const char ** aResult); private: nsZipArchive* mArchive; char* mPattern; - PRUint16 mSlot; nsZipItem* mItem; - PRBool mRegExp; + PRUint16 mSlot; + PRPackedBool mRegExp; //-- prevent copies and assignments nsZipFind& operator=(const nsZipFind& rhs); nsZipFind(const nsZipFind& rhs); }; +nsresult gZlibInit(z_stream *zs); + #endif /* nsZipArchive_h_ */ diff --git a/mozilla/modules/libjar/zipfile.h b/mozilla/modules/libjar/zipfile.h index ab3f05fb5f8..291c2a4bb1f 100644 --- a/mozilla/modules/libjar/zipfile.h +++ b/mozilla/modules/libjar/zipfile.h @@ -48,6 +48,7 @@ * Currently only compression mode 8 (or none) is supported. */ +#ifdef STANDALONE #define ZIP_OK 0 #define ZIP_ERR_GENERAL -1 @@ -59,8 +60,6 @@ #define ZIP_ERR_UNSUPPORTED -7 #define ZIP_ERR_SMALLBUF -8 -#ifdef STANDALONE - PR_BEGIN_EXTERN_C /* Open and close the archive @@ -103,10 +102,19 @@ PR_EXTERN(void*) ZIP_FindInit( void* hZip, const char * pattern ); PR_EXTERN(PRInt32) ZIP_FindNext( void* hFind, char * outbuf, PRUint16 bufsize ); PR_EXTERN(PRInt32) ZIP_FindFree( void* hFind ); - PR_END_EXTERN_C +#else + +#define ZIP_OK NS_OK +#define ZIP_ERR_MEMORY NS_ERROR_OUT_OF_MEMORY +#define ZIP_ERR_DISK NS_ERROR_FILE_DISK_FULL +#define ZIP_ERR_CORRUPT NS_ERROR_FILE_CORRUPTED +#define ZIP_ERR_PARAM NS_ERROR_ILLEGAL_VALUE +#define ZIP_ERR_FNF NS_ERROR_FILE_TARGET_DOES_NOT_EXIST +#define ZIP_ERR_UNSUPPORTED NS_ERROR_NOT_IMPLEMENTED +#define ZIP_ERR_GENERAL NS_ERROR_FAILURE + #endif /* STANDALONE */ - #endif /* _zipfile_h */ diff --git a/mozilla/modules/libjar/zipstub.h b/mozilla/modules/libjar/zipstub.h index ef1c1422f97..76184e884c9 100644 --- a/mozilla/modules/libjar/zipstub.h +++ b/mozilla/modules/libjar/zipstub.h @@ -47,6 +47,8 @@ #include #endif +#define NS_ASSERTION(c,m) + #define PR_ASSERT assert #define PR_Malloc malloc #define PR_Free free @@ -100,6 +102,7 @@ typedef unsigned short PRUint16; typedef char PRBool; typedef unsigned char PRUint8; typedef PRUint8 PRPackedBool; +typedef PRInt32 nsresult; #define PR_TRUE 1 #define PR_FALSE 0 diff --git a/mozilla/rdf/chrome/src/nsChromeRegistry.cpp b/mozilla/rdf/chrome/src/nsChromeRegistry.cpp index 487757ff096..2d1b666618c 100644 --- a/mozilla/rdf/chrome/src/nsChromeRegistry.cpp +++ b/mozilla/rdf/chrome/src/nsChromeRegistry.cpp @@ -680,15 +680,13 @@ nsChromeRegistry::GetOverrideURL(const nsACString& aPackage, aResult += aPath; - nsCOMPtr zipEntry; - rv = mOverrideJAR->GetEntry(PromiseFlatCString(aResult).get(), - getter_AddRefs(zipEntry)); - if (NS_FAILED(rv)) { + // Check if the item exists in the JAR + PRBool ok; + rv = mOverrideJAR->HasEntry(aResult, &ok); + if (NS_FAILED(rv) || !ok) { aResult.Truncate(); - return rv; } - - return NS_OK; + return rv; } nsresult diff --git a/mozilla/toolkit/mozapps/extensions/src/nsExtensionManager.js.in b/mozilla/toolkit/mozapps/extensions/src/nsExtensionManager.js.in index 33dddc4ade5..9bc90c22951 100644 --- a/mozilla/toolkit/mozapps/extensions/src/nsExtensionManager.js.in +++ b/mozilla/toolkit/mozapps/extensions/src/nsExtensionManager.js.in @@ -801,8 +801,7 @@ function getZipReaderForFile(zipFile) { try { var zipReader = Components.classes["@mozilla.org/libjar/zip-reader;1"] .createInstance(Components.interfaces.nsIZipReader); - zipReader.init(zipFile); - zipReader.open(); + zipReader.open(zipFile); } catch (e) { zipReader.close(); @@ -826,7 +825,6 @@ function extractRDFFileToTempDir(zipFile, fileName, suppressErrors) { var file = getFile(KEY_TEMPDIR, [getRandomFileName(fileName)]); try { var zipReader = getZipReaderForFile(zipFile); - zipReader.getEntry(fileName); zipReader.extract(fileName, file); zipReader.close(); } @@ -1520,9 +1518,9 @@ Installer.prototype = { // create directories first var entries = zipReader.findEntries("*/"); - while (entries.hasMoreElements()) { - var entry = entries.getNext().QueryInterface(Components.interfaces.nsIZipEntry); - var target = installLocation.getItemFile(extensionID, entry.name); + while (entries.hasMore()) { + var entryName = entries.getNext(); + var target = installLocation.getItemFile(extensionID, entryName); if (!target.exists()) { try { target.create(nsILocalFile.DIRECTORY_TYPE, PERMS_DIRECTORY); @@ -1534,10 +1532,10 @@ Installer.prototype = { } } - entries = zipReader.findEntries("*"); - while (entries.hasMoreElements()) { - entry = entries.getNext().QueryInterface(Components.interfaces.nsIZipEntry); - target = installLocation.getItemFile(extensionID, entry.name); + entries = zipReader.findEntries(null); + while (entries.hasMore()) { + var entryName = entries.getNext(); + target = installLocation.getItemFile(extensionID, entryName); if (target.exists()) continue; @@ -1548,7 +1546,7 @@ Installer.prototype = { LOG("extractExtensionsFiles: failed to create target file for extraction " + " file = " + target.path + ", exception = " + e + "\n"); } - zipReader.extract(entry.name, target); + zipReader.extract(entryName, target); } zipReader.close(); } @@ -1574,7 +1572,6 @@ Installer.prototype = { "preview.png", "icon.png"]; for (var i = 0; i < rootFiles.length; ++i) { try { - var entry = zipReader.getEntry(rootFiles[i]); var target = installLocation.getItemFile(id, rootFiles[i]); zipReader.extract(rootFiles[i], target); } @@ -1586,11 +1583,11 @@ Installer.prototype = { // new theme structure requires a chrome.manifest file if (manifestFile.exists()) { var entries = zipReader.findEntries(DIR_CHROME + "/*"); - while (entries.hasMoreElements()) { - entry = entries.getNext().QueryInterface(Components.interfaces.nsIZipEntry); - if (entry.name.substr(entry.name.length - 1, 1) == "/") + while (entries.hasMore()) { + var entryName = entries.getNext(); + if (entryName.charAt(entryName.length - 1) == "/") continue; - target = installLocation.getItemFile(id, entry.name); + target = installLocation.getItemFile(id, entryName); try { target.create(nsILocalFile.NORMAL_FILE_TYPE, PERMS_FILE); } @@ -1598,13 +1595,12 @@ Installer.prototype = { LOG("extractThemeFiles: failed to create target file for extraction " + " file = " + target.path + ", exception = " + e + "\n"); } - zipReader.extract(entry.name, target); + zipReader.extract(entryName, target); } zipReader.close(); } else { // old theme structure requires only an install.rdf try { - var entry = zipReader.getEntry(FILE_CONTENTS_MANIFEST); var contentsManifestFile = installLocation.getItemFile(id, FILE_CONTENTS_MANIFEST); contentsManifestFile.create(nsILocalFile.NORMAL_FILE_TYPE, PERMS_FILE); zipReader.extract(FILE_CONTENTS_MANIFEST, contentsManifestFile); @@ -3188,10 +3184,9 @@ ExtensionManager.prototype = { var zipReader = Components.classes["@mozilla.org/libjar/zip-reader;1"] .createInstance(Components.interfaces.nsIZipReader); - zipReader.init(entry); + zipReader.open(entry); var prettyName = ""; try { - var jar = zipReader.QueryInterface(Components.interfaces.nsIJAR); var principal = { }; var certPrincipal = zipReader.getCertificatePrincipal(null, principal); // XXXbz This string could be empty. This needs better @@ -4283,9 +4278,9 @@ ExtensionManager.prototype = { var files = []; for (var i = 0; i < searchForEntries.length; ++i) { var entries = zipReader.findEntries(searchForEntries[i]); - while (entries.hasMoreElements()) { - var entry = entries.getNext().QueryInterface(Components.interfaces.nsIZipEntry); - var target = getFile(KEY_TEMPDIR, [entry.name]); + while (entries.hasMore()) { + var entryName = entries.getNext(); + var target = getFile(KEY_TEMPDIR, [entryName]); try { target.createUnique(nsILocalFile.NORMAL_FILE_TYPE, PERMS_FILE); } @@ -4293,7 +4288,7 @@ ExtensionManager.prototype = { LOG("installMultiXPI: failed to create target file for extraction " + " file = " + target.path + ", exception = " + e + "\n"); } - zipReader.extract(entry.name, target); + zipReader.extract(entryName, target); files.push(target); } } diff --git a/mozilla/xpinstall/src/nsInstall.cpp b/mozilla/xpinstall/src/nsInstall.cpp index 32ac1181ef9..a5621aa03a0 100644 --- a/mozilla/xpinstall/src/nsInstall.cpp +++ b/mozilla/xpinstall/src/nsInstall.cpp @@ -45,6 +45,7 @@ #include "nsIFactory.h" #include "nsISupports.h" #include "nsNativeCharsetUtils.h" +#include "nsStringEnumerator.h" #include "nsIComponentManager.h" #include "nsIServiceManager.h" @@ -459,20 +460,14 @@ nsInstall::AddDirectory(const nsString& aRegName, return NS_OK; } + // Default subName = location in jar file nsString qualifiedRegName; + result = GetQualifiedRegName( aRegName.IsEmpty() ? aJarSource : aRegName, + qualifiedRegName); - if ( aRegName.IsEmpty()) - { - // Default subName = location in jar file - *aReturn = GetQualifiedRegName( aJarSource, qualifiedRegName); - } - else - { - *aReturn = GetQualifiedRegName( aRegName, qualifiedRegName ); - } - - if (*aReturn != SUCCESS) + if (result != nsInstall::SUCCESS) { + *aReturn = SaveError( result ); return NS_OK; } @@ -489,47 +484,47 @@ nsInstall::AddDirectory(const nsString& aRegName, } } - nsString subdirectory(aSubdir); - + nsAutoString subdirectory(aSubdir); if (!subdirectory.IsEmpty()) - { subdirectory.AppendLiteral("/"); - } + nsAutoString prefix(aJarSource + NS_LITERAL_STRING("/")); + const PRInt32 prefix_length = prefix.Length(); + NS_LossyConvertUTF16toASCII pattern(prefix + NS_LITERAL_STRING("*")); - nsVoidArray *paths = new nsVoidArray(); - - if (paths == nsnull) + nsCOMPtr jarEnum; + nsresult rv = mJarFileData->FindEntries(pattern.get(), + getter_AddRefs(jarEnum) ); + if (NS_FAILED(rv) || !jarEnum) { - *aReturn = SaveError(nsInstall::OUT_OF_MEMORY); + *aReturn = SaveError( nsInstall::EXTRACTION_FAILED ); return NS_OK; } PRInt32 count = 0; - result = ExtractDirEntries(aJarSource, paths); - if (result == nsInstall::SUCCESS) + PRBool bMore = PR_FALSE; + while (NS_SUCCEEDED(jarEnum->HasMore(&bMore)) && bMore) { - count = paths->Count(); - if (count == 0) - result = nsInstall::DOES_NOT_EXIST; - } - - for (PRInt32 i=0; i < count && result == nsInstall::SUCCESS; i++) - { - nsString *thisPath = (nsString *)paths->ElementAt(i); - - nsString newJarSource = aJarSource; - newJarSource.AppendLiteral("/"); - newJarSource += *thisPath; - - nsString newSubDir; - - if (!subdirectory.IsEmpty()) + nsCAutoString name; + rv = jarEnum->GetNext(name); + if (NS_FAILED(rv)) { - newSubDir = subdirectory; + result = nsInstall::EXTRACTION_FAILED; + break; } - newSubDir += *thisPath; + if ( name.Last() == '/' ) + { + // Skip the directory entries + continue; + } + const PRInt32 namelen = name.Length(); + NS_ASSERTION( prefix_length <= namelen, "Match must be longer than pattern!" ); + NS_ConvertASCIItoUTF16 fileName(Substring(name, + prefix_length, + namelen - prefix_length)); + nsAutoString newJarSource(prefix + fileName); + nsAutoString newSubDir(subdirectory + fileName); ie = new nsInstallFile( this, qualifiedRegName, @@ -538,7 +533,7 @@ nsInstall::AddDirectory(const nsString& aRegName, aFolder, newSubDir, aMode, - (i == 0), // register the first one only + (count == 0), // register the first one only &result); if (ie == nsnull) @@ -552,10 +547,12 @@ nsInstall::AddDirectory(const nsString& aRegName, else { result = ScheduleForInstall( ie ); + count++; } } - DeleteVector(paths); + if (result == nsInstall::SUCCESS && count == 0) + result = nsInstall::DOES_NOT_EXIST; *aReturn = SaveError( result ); return NS_OK; @@ -657,19 +654,13 @@ nsInstall::AddSubcomponent(const nsString& aRegName, if (qualifiedVersion.IsEmpty()) qualifiedVersion.AssignLiteral("0.0.0.0"); + // Default subName = location in jar file + result = GetQualifiedRegName( aRegName.IsEmpty() ? aJarSource : aRegName, + qualifiedRegName); - if ( aRegName.IsEmpty() ) - { - // Default subName = location in jar file - *aReturn = GetQualifiedRegName( aJarSource, qualifiedRegName); - } - else - { - *aReturn = GetQualifiedRegName( aRegName, qualifiedRegName ); - } - - if (*aReturn != SUCCESS) + if (result != nsInstall::SUCCESS) { + *aReturn = SaveError( result ); return NS_OK; } @@ -687,7 +678,7 @@ nsInstall::AddSubcomponent(const nsString& aRegName, if (ie == nsnull) { *aReturn = SaveError(nsInstall::OUT_OF_MEMORY); - return NS_OK; + return NS_OK; } if (errcode == nsInstall::SUCCESS) @@ -2805,80 +2796,3 @@ nsInstall::GetResourcedString(const nsAString& aResName) return nsCRT::strdup(nsInstallResources::GetDefaultVal( NS_LossyConvertUTF16toASCII(aResName).get())); } - - -PRInt32 -nsInstall::ExtractDirEntries(const nsString& directory, nsVoidArray *paths) -{ - char *buf; - nsISimpleEnumerator *jarEnum = nsnull; - nsIZipEntry *currZipEntry = nsnull; - - if ( paths ) - { - nsString pattern(directory + NS_LITERAL_STRING("/*")); - PRInt32 prefix_length = directory.Length()+1; // account for slash - - nsresult rv = mJarFileData->FindEntries( - NS_LossyConvertUTF16toASCII(pattern).get(), - &jarEnum ); - if (NS_FAILED(rv) || !jarEnum) - goto handle_err; - - PRBool bMore; - rv = jarEnum->HasMoreElements(&bMore); - while (bMore && NS_SUCCEEDED(rv)) - { - rv = jarEnum->GetNext( (nsISupports**) &currZipEntry ); - if (currZipEntry) - { - // expensive 'buf' callee malloc per iteration! - rv = currZipEntry->GetName(&buf); - if (NS_FAILED(rv)) - goto handle_err; - if (buf) - { - PRInt32 namelen = PL_strlen(buf); - NS_ASSERTION( prefix_length <= namelen, "Match must be longer than pattern!" ); - - if ( buf[namelen-1] != '/' ) - { - // XXX manipulation should be in caller - nsString* tempString = new nsString; tempString->AssignWithConversion(buf+prefix_length); - paths->AppendElement(tempString); - } - - PR_FREEIF( buf ); - } - NS_IF_RELEASE(currZipEntry); - } - rv = jarEnum->HasMoreElements(&bMore); - } - } - - NS_IF_RELEASE(jarEnum); - return SUCCESS; - -handle_err: - NS_IF_RELEASE(jarEnum); - NS_IF_RELEASE(currZipEntry); - return EXTRACTION_FAILED; -} - -void -nsInstall::DeleteVector(nsVoidArray* vector) -{ - if (vector != nsnull) - { - for (PRInt32 i=0; i < vector->Count(); i++) - { - nsString* element = (nsString*)vector->ElementAt(i); - if (element != nsnull) - delete element; - } - - vector->Clear(); - delete (vector); - vector = nsnull; - } -} diff --git a/mozilla/xpinstall/src/nsInstall.h b/mozilla/xpinstall/src/nsInstall.h index 65b91d427da..13c166c7013 100644 --- a/mozilla/xpinstall/src/nsInstall.h +++ b/mozilla/xpinstall/src/nsInstall.h @@ -396,9 +396,6 @@ class nsInstall void CleanUp(); - PRInt32 ExtractDirEntries(const nsString& directory, nsVoidArray *paths); - - static void DeleteVector(nsVoidArray* vector); }; nsresult MakeUnique(nsILocalFile* file); diff --git a/mozilla/xpinstall/src/nsSoftwareUpdateRun.cpp b/mozilla/xpinstall/src/nsSoftwareUpdateRun.cpp index 988149a2ef9..342ea27a582 100644 --- a/mozilla/xpinstall/src/nsSoftwareUpdateRun.cpp +++ b/mozilla/xpinstall/src/nsSoftwareUpdateRun.cpp @@ -69,6 +69,7 @@ #include "nsInstallTrigger.h" #include "nsIConsoleService.h" #include "nsIScriptError.h" +#include "nsStringEnumerator.h" #include "nsIJAR.h" #include "nsIPrincipal.h" @@ -120,22 +121,19 @@ nsresult VerifySigning(nsIZipReader* hZip, nsIPrincipal* aPrincipal) PRUint32 entryCount = 0; // first verify all files in the jar are also in the manifest. - nsCOMPtr entries; + nsCOMPtr entries; rv = hZip->FindEntries(nsnull, getter_AddRefs(entries)); if (NS_FAILED(rv)) return rv; PRBool more; - nsXPIDLCString name; - while (NS_SUCCEEDED(entries->HasMoreElements(&more)) && more) + nsCAutoString name; + while (NS_SUCCEEDED(entries->HasMore(&more)) && more) { - nsCOMPtr file; - rv = entries->GetNext(getter_AddRefs(file)); + rv = entries->GetNext(name); if (NS_FAILED(rv)) return rv; - file->GetName(getter_Copies(name)); - - if ( PL_strncasecmp("META-INF/", name.get(), 9) == 0) + if (PL_strncasecmp("META-INF/", name.get(), 9) == 0) continue; // libjar creates fake entries for directories which are @@ -143,8 +141,14 @@ nsresult VerifySigning(nsIZipReader* hZip, nsIPrincipal* aPrincipal) // entry within the zip, e.g. foo/ in a zip containing // only foo/bar.txt -- skip those, because they shouldn't // be in the manifest + + // This is pretty inefficient, but maybe that's okay. + nsCOMPtr entry; + rv = hZip->GetEntry(name.get(), getter_AddRefs(entry)); + if (NS_FAILED(rv)) return rv; + PRBool isSynthetic; - rv = file->GetIsSynthetic(&isSynthetic); + rv = entry->GetIsSynthetic(&isSynthetic); if (NS_FAILED(rv)) return rv; if (isSynthetic) continue; @@ -154,10 +158,10 @@ nsresult VerifySigning(nsIZipReader* hZip, nsIPrincipal* aPrincipal) entryCount++; // Each entry must be signed - PRBool equal; - rv = jar->GetCertificatePrincipal(name, getter_AddRefs(principal)); + rv = jar->GetCertificatePrincipal(name.get(), getter_AddRefs(principal)); if (NS_FAILED(rv) || !principal) return NS_ERROR_FAILURE; + PRBool equal; rv = principal->Equals(aPrincipal, &equal); if (NS_FAILED(rv) || !equal) return NS_ERROR_FAILURE; } @@ -274,15 +278,11 @@ OpenAndValidateArchive(nsIZipReader* hZip, nsIFile* jarFile, nsIPrincipal* aPrin nsCOMPtr jFile; nsresult rv =jarFile->Clone(getter_AddRefs(jFile)); if (NS_SUCCEEDED(rv)) - rv = hZip->Init(jFile); + rv = hZip->Open(jFile); if (NS_FAILED(rv)) return nsInstall::CANT_READ_ARCHIVE; - rv = hZip->Open(); - if (NS_FAILED(rv)) - return nsInstall::CANT_READ_ARCHIVE; - // CRC check the integrity of all items in this archive rv = hZip->Test(nsnull); if (NS_FAILED(rv)) @@ -654,21 +654,19 @@ extern "C" void RunChromeInstallOnThread(void *data) if (info->GetType() == CHROME_SKIN) { static NS_DEFINE_CID(kZipReaderCID, NS_ZIPREADER_CID); nsCOMPtr hZip = do_CreateInstance(kZipReaderCID, &rv); - if (hZip) - rv = hZip->Init(info->GetFile()); - if (NS_SUCCEEDED(rv)) - rv = hZip->Open(); - - if (NS_SUCCEEDED(rv)) - { - rv = hZip->Test("install.rdf"); - nsIExtensionManager* em = info->GetExtensionManager(); - if (NS_SUCCEEDED(rv) && em) { - rv = em->InstallItemFromFile(info->GetFile(), - NS_INSTALL_LOCATION_APPPROFILE); + if (NS_SUCCEEDED(rv) && hZip) { + rv = hZip->Open(info->GetFile()); + if (NS_SUCCEEDED(rv)) + { + rv = hZip->Test("install.rdf"); + nsIExtensionManager* em = info->GetExtensionManager(); + if (NS_SUCCEEDED(rv) && em) { + rv = em->InstallItemFromFile(info->GetFile(), + NS_INSTALL_LOCATION_APPPROFILE); + } } + hZip->Close(); } - hZip->Close(); // Extension Manager copies the theme .jar file to // a different location, so remove the temporary file. info->GetFile()->Remove(PR_FALSE);