diff --git a/content/xul/document/src/nsXULPrototypeCache.cpp b/content/xul/document/src/nsXULPrototypeCache.cpp index 4b2c2341c66e..e6b4d13728d3 100644 --- a/content/xul/document/src/nsXULPrototypeCache.cpp +++ b/content/xul/document/src/nsXULPrototypeCache.cpp @@ -610,7 +610,7 @@ class nsXULFastLoadFileIO : public nsIFastLoadFileIO { public: nsXULFastLoadFileIO(nsIFile* aFile) - : mFile(aFile) { + : mFile(aFile), mTruncateOutputFile(true) { } virtual ~nsXULFastLoadFileIO() { @@ -622,6 +622,7 @@ class nsXULFastLoadFileIO : public nsIFastLoadFileIO nsCOMPtr mFile; nsCOMPtr mInputStream; nsCOMPtr mOutputStream; + bool mTruncateOutputFile; }; @@ -653,7 +654,7 @@ nsXULFastLoadFileIO::GetOutputStream(nsIOutputStream** aResult) { if (! mOutputStream) { PRInt32 ioFlags = PR_WRONLY; - if (! mInputStream) + if (mTruncateOutputFile) ioFlags |= PR_CREATE_FILE | PR_TRUNCATE; nsresult rv; @@ -672,6 +673,13 @@ nsXULFastLoadFileIO::GetOutputStream(nsIOutputStream** aResult) return NS_OK; } +NS_IMETHODIMP +nsXULFastLoadFileIO::DisableTruncate() +{ + mTruncateOutputFile = false; + return NS_OK; +} + nsresult nsXULPrototypeCache::StartFastLoad(nsIURI* aURI) { @@ -766,13 +774,8 @@ nsXULPrototypeCache::StartFastLoad(nsIURI* aURI) // Try to read an existent FastLoad file. PRBool exists = PR_FALSE; if (NS_SUCCEEDED(file->Exists(&exists)) && exists) { - nsCOMPtr input; - rv = io->GetInputStream(getter_AddRefs(input)); - if (NS_FAILED(rv)) - return rv; - nsCOMPtr objectInput; - rv = fastLoadService->NewInputStream(input, getter_AddRefs(objectInput)); + rv = fastLoadService->NewInputStream(file, getter_AddRefs(objectInput)); if (NS_SUCCEEDED(rv)) { if (gChecksumXULFastLoadFile) { @@ -836,8 +839,6 @@ nsXULPrototypeCache::StartFastLoad(nsIURI* aURI) // that can't do open-unlink. if (objectInput) objectInput->Close(); - else - input->Close(); xio->mInputStream = nsnull; #ifdef DEBUG diff --git a/js/src/xpconnect/loader/mozJSComponentLoader.cpp b/js/src/xpconnect/loader/mozJSComponentLoader.cpp index 0d62a55cd3ee..3b3aaff353e1 100644 --- a/js/src/xpconnect/loader/mozJSComponentLoader.cpp +++ b/js/src/xpconnect/loader/mozJSComponentLoader.cpp @@ -394,6 +394,7 @@ nsXPCFastLoadIO::GetInputStream(nsIInputStream **_retval) fileInput, XPC_DESERIALIZATION_BUFFER_SIZE); NS_ENSURE_SUCCESS(rv, rv); + mTruncateOutputFile = false; } NS_ADDREF(*_retval = mInputStream); @@ -405,7 +406,7 @@ nsXPCFastLoadIO::GetOutputStream(nsIOutputStream **_retval) { if (! mOutputStream) { PRInt32 ioFlags = PR_WRONLY; - if (! mInputStream) { + if (mTruncateOutputFile) { ioFlags |= PR_CREATE_FILE | PR_TRUNCATE; } @@ -424,6 +425,13 @@ nsXPCFastLoadIO::GetOutputStream(nsIOutputStream **_retval) return NS_OK; } +NS_IMETHODIMP +nsXPCFastLoadIO::DisableTruncate() +{ + mTruncateOutputFile = false; + return NS_OK; +} + static nsresult ReadScriptFromStream(JSContext *cx, nsIObjectInputStream *stream, JSScript **script) @@ -945,11 +953,7 @@ mozJSComponentLoader::StartFastLoad(nsIFastLoadService *flSvc) if (exists) { LOG(("trying to use existing fastload file\n")); - nsCOMPtr input; - rv = mFastLoadIO->GetInputStream(getter_AddRefs(input)); - NS_ENSURE_SUCCESS(rv, rv); - - rv = flSvc->NewInputStream(input, getter_AddRefs(mFastLoadInput)); + rv = flSvc->NewInputStream(mFastLoadFile, getter_AddRefs(mFastLoadInput)); if (NS_SUCCEEDED(rv)) { LOG(("opened fastload file for reading\n")); @@ -987,9 +991,7 @@ mozJSComponentLoader::StartFastLoad(nsIFastLoadService *flSvc) if (mFastLoadInput) { mFastLoadInput->Close(); mFastLoadInput = nsnull; - } else { - input->Close(); - } + } mFastLoadIO->SetInputStream(nsnull); mFastLoadFile->Remove(PR_FALSE); exists = PR_FALSE; diff --git a/js/src/xpconnect/loader/mozJSComponentLoader.h b/js/src/xpconnect/loader/mozJSComponentLoader.h index 026e2601fe25..922db6fc7f12 100644 --- a/js/src/xpconnect/loader/mozJSComponentLoader.h +++ b/js/src/xpconnect/loader/mozJSComponentLoader.h @@ -74,7 +74,7 @@ class nsXPCFastLoadIO : public nsIFastLoadFileIO NS_DECL_ISUPPORTS NS_DECL_NSIFASTLOADFILEIO - nsXPCFastLoadIO(nsIFile *file) : mFile(file) {} + nsXPCFastLoadIO(nsIFile *file) : mFile(file), mTruncateOutputFile(true) {} void SetInputStream(nsIInputStream *stream) { mInputStream = stream; } void SetOutputStream(nsIOutputStream *stream) { mOutputStream = stream; } @@ -85,6 +85,7 @@ class nsXPCFastLoadIO : public nsIFastLoadFileIO nsCOMPtr mFile; nsCOMPtr mInputStream; nsCOMPtr mOutputStream; + bool mTruncateOutputFile; }; diff --git a/xpcom/io/nsFastLoadFile.cpp b/xpcom/io/nsFastLoadFile.cpp index eaadfda4dd6d..0bcc11aeb747 100644 --- a/xpcom/io/nsFastLoadFile.cpp +++ b/xpcom/io/nsFastLoadFile.cpp @@ -57,6 +57,9 @@ #include "nsBinaryStream.h" #include "nsFastLoadFile.h" #include "nsInt64.h" +#ifdef XP_UNIX +#include +#endif #ifdef DEBUG_brendan # define METERING @@ -299,13 +302,6 @@ nsFastLoadFileReader::GetChecksum(PRUint32 *aChecksum) return NS_OK; } -NS_IMETHODIMP -nsFastLoadFileReader::SetChecksum(PRUint32 aChecksum) -{ - mHeader.mChecksum = aChecksum; - return NS_OK; -} - struct nsStringMapEntry : public PLDHashEntryHdr { const char* mString; // key, must come first nsISupports* mURI; // for SelectMuxedDocument return value @@ -530,17 +526,11 @@ nsFastLoadFileReader::EndMuxedDocument(nsISupports* aURI) NS_IMETHODIMP nsFastLoadFileReader::Read(char* aBuffer, PRUint32 aCount, PRUint32 *aBytesRead) { - nsresult rv; - nsDocumentMapReadEntry* entry = mCurrentDocumentMapEntry; if (entry) { // Don't call our Seek wrapper, as it clears mCurrentDocumentMapEntry. if (entry->mNeedToSeek) { - rv = mSeekableInput->Seek(nsISeekableStream::NS_SEEK_SET, - entry->mSaveOffset); - if (NS_FAILED(rv)) - return rv; - + SeekTo(entry->mSaveOffset); entry->mNeedToSeek = PR_FALSE; } @@ -555,15 +545,11 @@ nsFastLoadFileReader::Read(char* aBuffer, PRUint32 aCount, PRUint32 *aBytesRead) if (entry->mNextSegmentOffset == 0) return NS_ERROR_UNEXPECTED; - rv = mSeekableInput->Seek(nsISeekableStream::NS_SEEK_SET, - entry->mNextSegmentOffset); - if (NS_FAILED(rv)) - return rv; - + SeekTo(entry->mNextSegmentOffset); // Clear mCurrentDocumentMapEntry temporarily to avoid recursion. mCurrentDocumentMapEntry = nsnull; - rv = Read32(&entry->mNextSegmentOffset); + nsresult rv = Read32(&entry->mNextSegmentOffset); if (NS_SUCCEEDED(rv)) { PRUint32 bytesLeft = 0; rv = Read32(&bytesLeft); @@ -578,10 +564,11 @@ nsFastLoadFileReader::Read(char* aBuffer, PRUint32 aCount, PRUint32 *aBytesRead) entry->mBytesLeft -= 8; } } - - rv = nsBinaryInputStream::Read(aBuffer, aCount, aBytesRead); - - if (NS_SUCCEEDED(rv) && entry) { + PRUint32 count = PR_MIN(mFileLen - mFilePos, aCount); + memcpy(aBuffer, mFileData+mFilePos, count); + *aBytesRead = count; + mFilePos += count; + if (entry) { NS_ASSERTION(entry->mBytesLeft >= *aBytesRead, "demux Read underflow!"); entry->mBytesLeft -= *aBytesRead; @@ -591,7 +578,7 @@ nsFastLoadFileReader::Read(char* aBuffer, PRUint32 aCount, PRUint32 *aBytesRead) entry->mSaveOffset = 0; #endif } - return rv; + return NS_OK; } NS_IMETHODIMP @@ -603,9 +590,13 @@ nsFastLoadFileReader::ReadSegments(nsWriteSegmentFun aWriter, void* aClosure, NS_ASSERTION(!entry || (!entry->mNeedToSeek && entry->mBytesLeft != 0), "ReadSegments called from above nsFastLoadFileReader layer?!"); - nsresult rv = nsBinaryInputStream::ReadSegments(aWriter, aClosure, aCount, - aResult); - if (NS_SUCCEEDED(rv) && entry) { + PRUint32 count = PR_MIN(mFileLen - mFilePos, aCount); + + // Errors returned from the writer get ignored. + aWriter(this, aClosure, (char*)(mFileData + mFilePos), 0, + count, aResult); + mFilePos += count; + if (entry) { NS_ASSERTION(entry->mBytesLeft >= *aResult, "demux ReadSegments underflow!"); entry->mBytesLeft -= *aResult; @@ -616,90 +607,19 @@ nsFastLoadFileReader::ReadSegments(nsWriteSegmentFun aWriter, void* aClosure, entry->mSaveOffset = 0; #endif } - return rv; + return NS_OK; } -NS_IMETHODIMP -nsFastLoadFileReader::SetInputStream(nsIInputStream *aInputStream) -{ - nsresult rv = nsBinaryInputStream::SetInputStream(aInputStream); - mSeekableInput = do_QueryInterface(aInputStream); - NS_ASSERTION(!mInputStream || mSeekableInput, - "FastLoad requires a seekable input stream"); - return rv; -} - -/** - * FIXME: bug #411579 (tune this macro!) Last updated: Jan 2008 - */ -#define MFL_CHECKSUM_BUFSIZE (6 * 8192) - NS_IMETHODIMP nsFastLoadFileReader::ComputeChecksum(PRUint32 *aResult) { - nsCOMPtr stream = mInputStream; - nsCOMPtr seekable = mSeekableInput; - - PRInt64 saveOffset; - nsresult rv = seekable->Tell(&saveOffset); - if (NS_FAILED(rv)) - return rv; - - if (mBufferAccess) { - rv = mBufferAccess->GetUnbufferedStream(getter_AddRefs(stream)); - if (NS_FAILED(rv)) - return rv; - - seekable = do_QueryInterface(stream); - if (!seekable) - return NS_ERROR_UNEXPECTED; - } - - rv = seekable->Seek(nsISeekableStream::NS_SEEK_SET, 0); - if (NS_FAILED(rv)) - return rv; - - char buf[MFL_CHECKSUM_BUFSIZE]; - PRUint32 len, rem; - - rem = offsetof(nsFastLoadHeader, mChecksum); - rv = stream->Read(buf, rem, &len); - if (NS_FAILED(rv)) - return rv; - if (len != rem) - return NS_ERROR_UNEXPECTED; - - rv = seekable->Seek(nsISeekableStream::NS_SEEK_CUR, 4); - if (NS_FAILED(rv)) - return rv; - memset(buf + rem, 0, 4); - rem += 4; - PRUint32 checksum = 0; - while (NS_SUCCEEDED(rv = stream->Read(buf + rem, sizeof buf - rem, &len)) && - len) { - len += rem; - rem = NS_AccumulateFastLoadChecksum(&checksum, - reinterpret_cast(buf), - len, - PR_FALSE); - if (rem) - memcpy(buf, buf + len - rem, rem); - } - if (NS_FAILED(rv)) - return rv; - - if (rem) { - NS_AccumulateFastLoadChecksum(&checksum, - reinterpret_cast(buf), - rem, - PR_TRUE); - } - - rv = seekable->Seek(nsISeekableStream::NS_SEEK_SET, saveOffset); - if (NS_FAILED(rv)) - return rv; - + // Skip first 2 fields. + PRUint32 pos = offsetof(nsFastLoadHeader, mVersion); + NS_AccumulateFastLoadChecksum(&checksum, + mFileData + pos, + mFileLen - pos, + PR_TRUE); *aResult = checksum; return NS_OK; } @@ -938,49 +858,49 @@ nsresult nsFastLoadFileReader::Open() { nsresult rv; + nsCOMPtr localFile = do_QueryInterface(mFile, &rv); + if (NS_FAILED(rv)) + return rv; + rv = localFile->OpenNSPRFileDesc(PR_RDONLY, 0, &mFd); + if (NS_FAILED(rv)) + return rv; - // Don't bother buffering the header, as we immediately seek to EOF. - if (mBufferAccess) - mBufferAccess->DisableBuffering(); + PRInt64 size = PR_Available64(mFd); + if (size >= PR_INT32_MAX) + return NS_ERROR_FILE_TOO_BIG; + + mFileLen = (PRUint32) size; + + PRFileMap *mFileMap = PR_CreateFileMap(mFd, mFileLen, PR_PROT_READONLY); + if (!mFileMap) + return NS_ERROR_FAILURE; + + mFileData = (PRUint8*) PR_MemMap(mFileMap, 0, mFileLen); + + if (mFileLen < sizeof(nsFastLoadHeader)) + return NS_ERROR_FAILURE; + +#ifdef XP_UNIX + madvise(mFileData, mFileLen, MADV_WILLNEED); +#endif rv = ReadHeader(&mHeader); - - if (mBufferAccess) - mBufferAccess->EnableBuffering(); if (NS_FAILED(rv)) return rv; - if (mHeader.mVersion != MFL_FILE_VERSION) + if (mHeader.mVersion != MFL_FILE_VERSION || + mHeader.mFooterOffset == 0 || + memcmp(mHeader.mMagic, magic, MFL_FILE_MAGIC_SIZE)) return NS_ERROR_UNEXPECTED; - if (mHeader.mFooterOffset == 0) - return NS_ERROR_UNEXPECTED; - - rv = mSeekableInput->Seek(nsISeekableStream::NS_SEEK_END, 0); - if (NS_FAILED(rv)) - return rv; - - PRInt64 fileSize; - rv = mSeekableInput->Tell(&fileSize); - if (NS_FAILED(rv)) - return rv; - - nsInt64 fileSize64 = fileSize; - const nsInt64 maxUint32 = PR_UINT32_MAX; - NS_ASSERTION(fileSize64 <= maxUint32, "fileSize must fit in 32 bits"); - if ((PRUint32) fileSize64 != mHeader.mFileSize) - return NS_ERROR_UNEXPECTED; - - rv = mSeekableInput->Seek(nsISeekableStream::NS_SEEK_SET, - PRInt32(mHeader.mFooterOffset)); - if (NS_FAILED(rv)) - return rv; + + SeekTo(mHeader.mFooterOffset); rv = ReadFooter(&mFooter); if (NS_FAILED(rv)) return rv; - return mSeekableInput->Seek(nsISeekableStream::NS_SEEK_SET, - sizeof(nsFastLoadHeader)); + SeekTo(sizeof(nsFastLoadHeader)); + return NS_OK; } NS_IMETHODIMP @@ -995,13 +915,22 @@ nsFastLoadFileReader::Close() // a session not so much for reading objects as for its footer information, // which primes the updater's tables so that after the update completes, the // FastLoad file has a superset footer. - + if (mFd) { + if (mFileData) + PR_MemUnmap(mFileData, mFileLen); + mFileData = nsnull; + if (mFileMap) + PR_CloseFileMap(mFileMap); + mFileMap = nsnull; + PR_Close(mFd); + mFd = nsnull; + } for (PRUint32 i = 0, n = mFooter.mNumSharpObjects; i < n; i++) { nsObjectMapEntry* entry = &mFooter.mObjectMap[i]; entry->mReadObject = nsnull; } - return mInputStream->Close(); + return NS_OK; } nsresult @@ -1062,14 +991,9 @@ nsFastLoadFileReader::ReadObject(PRBool aIsStrongRef, nsISupports* *aObject) // Check whether we've already deserialized the object for this OID. object = entry->mReadObject; if (!object) { - PRInt64 saveOffset; nsDocumentMapReadEntry* saveDocMapEntry = nsnull; - rv = mSeekableInput->Tell(&saveOffset); - if (NS_FAILED(rv)) - return rv; - - PRUint32 saveOffset32 = saveOffset; + PRUint32 saveOffset32 = mFilePos; if (entry->mCIDOffset != saveOffset32) { // We skipped deserialization of this object from its position // earlier in the input stream, presumably due to the reference @@ -1085,10 +1009,7 @@ nsFastLoadFileReader::ReadObject(PRBool aIsStrongRef, nsISupports* *aObject) // or more multiplexed documents in the FastLoad file. saveDocMapEntry = mCurrentDocumentMapEntry; mCurrentDocumentMapEntry = nsnull; - rv = mSeekableInput->Seek(nsISeekableStream::NS_SEEK_SET, - entry->mCIDOffset); - if (NS_FAILED(rv)) - return rv; + SeekTo(entry->mCIDOffset); } rv = DeserializeObject(getter_AddRefs(object)); @@ -1098,17 +1019,11 @@ nsFastLoadFileReader::ReadObject(PRBool aIsStrongRef, nsISupports* *aObject) if (entry->mCIDOffset != saveOffset32) { // Save the "skip offset" in case we need to skip this object // definition when reading forward, later on. - rv = mSeekableInput->Tell(&entry->mSkipOffset); - if (NS_FAILED(rv)) - return rv; - + entry->mSkipOffset = mFilePos; // Restore stream offset and mCurrentDocumentMapEntry in case // we're still reading forward through a part of the multiplex // to get object definitions eagerly. - rv = mSeekableInput->Seek(nsISeekableStream::NS_SEEK_SET, - saveOffset); - if (NS_FAILED(rv)) - return rv; + SeekTo(saveOffset32); mCurrentDocumentMapEntry = saveDocMapEntry; } @@ -1125,11 +1040,7 @@ nsFastLoadFileReader::ReadObject(PRBool aIsStrongRef, nsISupports* *aObject) // Since we are seeking within a muxed segment, we must adjust // mBytesLeft, so that Seek called from Read will be triggered // when mBytesLeft goes to zero. - PRInt64 currentOffset; - rv = mSeekableInput->Tell(¤tOffset); - if (NS_FAILED(rv)) - return rv; - + PRUint32 currentOffset = mFilePos; NS_ASSERTION(entry->mSkipOffset > (PRUint32)currentOffset, "skipping backwards from object?!"); NS_ASSERTION(mCurrentDocumentMapEntry->mBytesLeft >= @@ -1139,10 +1050,7 @@ nsFastLoadFileReader::ReadObject(PRBool aIsStrongRef, nsISupports* *aObject) mCurrentDocumentMapEntry->mBytesLeft -= entry->mSkipOffset - (PRUint32)currentOffset; - rv = mSeekableInput->Seek(nsISeekableStream::NS_SEEK_SET, - entry->mSkipOffset); - if (NS_FAILED(rv)) - return rv; + SeekTo(entry->mSkipOffset); } } @@ -1195,27 +1103,30 @@ nsFastLoadFileReader::ReadID(nsID *aResult) NS_IMETHODIMP nsFastLoadFileReader::Seek(PRInt32 aWhence, PRInt64 aOffset) { + NS_ASSERTION(aWhence == nsISeekableStream::NS_SEEK_SET, "Only NS_SEEK_SET seeks are supported"); mCurrentDocumentMapEntry = nsnull; - return mSeekableInput->Seek(aWhence, aOffset); + SeekTo(aOffset); + return NS_OK; } NS_IMETHODIMP nsFastLoadFileReader::Tell(PRInt64 *aResult) { - return mSeekableInput->Tell(aResult); + *aResult = mFilePos; + return NS_OK; } NS_IMETHODIMP nsFastLoadFileReader::SetEOF() { - return mSeekableInput->SetEOF(); + NS_ERROR("Refusing to truncate a memory-mapped file"); + return NS_ERROR_NOT_IMPLEMENTED; } NS_COM nsresult -NS_NewFastLoadFileReader(nsIObjectInputStream* *aResult, - nsIInputStream* aSrcStream) +NS_NewFastLoadFileReader(nsIObjectInputStream* *aResult, nsIFile *aFile) { - nsFastLoadFileReader* reader = new nsFastLoadFileReader(aSrcStream); + nsFastLoadFileReader* reader = new nsFastLoadFileReader(aFile); if (!reader) return NS_ERROR_OUT_OF_MEMORY; @@ -1336,13 +1247,6 @@ nsFastLoadFileWriter::GetChecksum(PRUint32 *aChecksum) return NS_OK; } -NS_IMETHODIMP -nsFastLoadFileWriter::SetChecksum(PRUint32 aChecksum) -{ - mHeader.mChecksum = aChecksum; - return NS_OK; -} - struct nsDocumentMapWriteEntry : public nsDocumentMapEntry { PRUint32 mCurrentSegmentOffset; // last written segment's offset }; @@ -1925,6 +1829,8 @@ nsFastLoadFileWriter::Open() return Init(); } +#define MFL_CHECKSUM_BUFSIZE (6 * 8192) + NS_IMETHODIMP nsFastLoadFileWriter::Close() { @@ -1996,20 +1902,11 @@ nsFastLoadFileWriter::Close() rv = mFileIO->GetInputStream(getter_AddRefs(input)); if (NS_FAILED(rv)) return rv; - - // Get the unbuffered input stream, to avoid copying overhead and to - // keep our view of the file coherent with the writer -- we don't want - // to hit a stale buffer in the reader's underlying stream. - nsCOMPtr bufferAccess = - do_QueryInterface(input); - rv = bufferAccess->GetUnbufferedStream(getter_AddRefs(input)); - if (NS_FAILED(rv) || !input) - return NS_ERROR_UNEXPECTED; - - // Seek the input stream to offset 0, in case it's a reader who has - // already been used to consume some of the FastLoad file. + + // Seek the input stream to right after checksum/magic. nsCOMPtr seekable = do_QueryInterface(input); - rv = seekable->Seek(nsISeekableStream::NS_SEEK_SET, 0); + rv = seekable->Seek(nsISeekableStream::NS_SEEK_SET, + offsetof(nsFastLoadHeader, mVersion)); if (NS_FAILED(rv)) return rv; @@ -2317,24 +2214,8 @@ NS_NewFastLoadFileWriter(nsIObjectOutputStream* *aResult, // -------------------------- nsFastLoadFileUpdater -------------------------- -NS_IMPL_ISUPPORTS_INHERITED1(nsFastLoadFileUpdater, - nsFastLoadFileWriter, - nsIFastLoadFileIO) - -NS_IMETHODIMP -nsFastLoadFileUpdater::GetInputStream(nsIInputStream** aResult) -{ - *aResult = mInputStream; - NS_IF_ADDREF(*aResult); - return NS_OK; -} - -NS_IMETHODIMP -nsFastLoadFileUpdater::GetOutputStream(nsIOutputStream** aResult) -{ - *aResult = nsnull; - return NS_OK; -} +NS_IMPL_ISUPPORTS_INHERITED0(nsFastLoadFileUpdater, + nsFastLoadFileWriter) PLDHashOperator nsFastLoadFileUpdater::CopyReadDocumentMapEntryToUpdater(PLDHashTable *aTable, @@ -2397,7 +2278,6 @@ nsFastLoadFileUpdater::Open(nsFastLoadFileReader* aReader) // Prepare to save aReader state in case we need to seek back and read a // singleton object that might otherwise get written by this updater. nsDocumentMapReadEntry* saveDocMapEntry = nsnull; - nsISeekableStream* inputSeekable = nsnull; PRInt64 saveOffset = 0; for (i = 0, n = aReader->mFooter.mNumSharpObjects; i < n; i++) { @@ -2415,8 +2295,7 @@ nsFastLoadFileUpdater::Open(nsFastLoadFileReader* aReader) nsISupports* obj = readEntry->mReadObject; if (!obj && MFL_GET_SINGLETON_FLAG(readEntry)) { if (!saveDocMapEntry) { - inputSeekable = aReader->mSeekableInput; - rv = inputSeekable->Tell(&saveOffset); + rv = aReader->Tell(&saveOffset); if (NS_FAILED(rv)) return rv; @@ -2424,7 +2303,7 @@ nsFastLoadFileUpdater::Open(nsFastLoadFileReader* aReader) aReader->mCurrentDocumentMapEntry = nsnull; } - rv = inputSeekable->Seek(nsISeekableStream::NS_SEEK_SET, + rv = aReader->Seek(nsISeekableStream::NS_SEEK_SET, readEntry->mCIDOffset); if (NS_FAILED(rv)) return rv; @@ -2450,7 +2329,7 @@ nsFastLoadFileUpdater::Open(nsFastLoadFileReader* aReader) // the system principal's serialized data, because the updater for // messenger.xul being opened here has already read it. - rv = inputSeekable->Tell(&readEntry->mSkipOffset); + rv = aReader->Tell(&readEntry->mSkipOffset); if (NS_FAILED(rv)) return rv; } @@ -2479,7 +2358,7 @@ nsFastLoadFileUpdater::Open(nsFastLoadFileReader* aReader) // If we had to read any singletons, restore aReader's saved state. if (saveDocMapEntry) { - rv = inputSeekable->Seek(nsISeekableStream::NS_SEEK_SET, saveOffset); + rv = aReader->Seek(nsISeekableStream::NS_SEEK_SET, saveOffset); if (NS_FAILED(rv)) return rv; @@ -2530,13 +2409,6 @@ nsFastLoadFileUpdater::Open(nsFastLoadFileReader* aReader) if (NS_FAILED(rv)) return rv; - // Avoid creating yet another object by implementing nsIFastLoadFileIO on - // this updater, and save aReader's input stream so it can be returned by - // GetInputStream called from nsFastLoadFileWriter::Close. This requires - // that we override Close to break the resulting zero-length cycle. - mFileIO = this; - mInputStream = aReader->mInputStream; - mSeekableInput = aReader->mSeekableInput; return NS_OK; } @@ -2553,7 +2425,7 @@ nsFastLoadFileUpdater::Close() NS_COM nsresult NS_NewFastLoadFileUpdater(nsIObjectOutputStream* *aResult, - nsIOutputStream* aOutputStream, + nsIFastLoadFileIO *aFileIO, nsIObjectInputStream* aReaderAsStream) { // Make sure that aReaderAsStream is an nsFastLoadFileReader. @@ -2561,15 +2433,19 @@ NS_NewFastLoadFileUpdater(nsIObjectOutputStream* *aResult, if (!reader) return NS_ERROR_UNEXPECTED; - nsFastLoadFileUpdater* updater = new nsFastLoadFileUpdater(aOutputStream); + nsCOMPtr output; + nsresult rv = aFileIO->GetOutputStream(getter_AddRefs(output)); + if (NS_FAILED(rv)) + return rv; + + nsFastLoadFileUpdater* updater = new nsFastLoadFileUpdater(output, aFileIO); if (!updater) return NS_ERROR_OUT_OF_MEMORY; // Stabilize updater's refcnt. nsCOMPtr stream(updater); - nsresult rv = updater->Open(static_cast - (aReaderAsStream)); + rv = updater->Open(static_cast(aReaderAsStream)); if (NS_FAILED(rv)) return rv; diff --git a/xpcom/io/nsFastLoadFile.h b/xpcom/io/nsFastLoadFile.h index 3325828f92cd..01c395eb8b4a 100644 --- a/xpcom/io/nsFastLoadFile.h +++ b/xpcom/io/nsFastLoadFile.h @@ -262,9 +262,10 @@ class nsFastLoadFileReader public nsIFastLoadFileReader { public: - nsFastLoadFileReader(nsIInputStream *aStream) - : mCurrentDocumentMapEntry(nsnull) { - SetInputStream(aStream); + nsFastLoadFileReader(nsIFile *aFile) + : mCurrentDocumentMapEntry(nsnull), mFile(aFile), mFd(nsnull), + mFileLen(0), mFilePos(0), mFileMap(nsnull), mFileData(nsnull) + { MOZ_COUNT_CTOR(nsFastLoadFileReader); } @@ -280,6 +281,11 @@ class nsFastLoadFileReader NS_IMETHOD ReadObject(PRBool aIsStrongRef, nsISupports* *_retval); NS_IMETHOD ReadID(nsID *aResult); + void SeekTo(PRInt64 aOffset) { + mFilePos = PR_MAX(0, PR_MIN(aOffset, mFileLen)); + NS_ASSERTION(aOffset == mFilePos, "Attempt to seek out of bounds"); + } + // nsIFastLoadFileControl methods NS_DECL_NSIFASTLOADFILECONTROL @@ -291,16 +297,6 @@ class nsFastLoadFileReader // Override Read so we can demultiplex a document interleaved with others. NS_IMETHOD Read(char* aBuffer, PRUint32 aCount, PRUint32 *aBytesRead); - - // Override ReadSegments too, as nsBinaryInputStream::ReadSegments does - // not call through our overridden Read method -- it calls directly into - // the underlying input stream. - NS_IMETHODIMP ReadSegments(nsWriteSegmentFun aWriter, void* aClosure, - PRUint32 aCount, PRUint32 *aResult); - - // Override SetInputStream so we can update mSeekableInput - NS_IMETHOD SetInputStream(nsIInputStream* aInputStream); - nsresult ReadHeader(nsFastLoadHeader *aHeader); /** @@ -313,6 +309,9 @@ class nsFastLoadFileReader PRUint16 mSaveWeakRefCnt; // after a Read }; + NS_IMETHODIMP ReadSegments(nsWriteSegmentFun aWriter, void* aClosure, + PRUint32 aCount, PRUint32 *aResult); + /** * In-memory representation of the FastLoad file footer. */ @@ -389,20 +388,23 @@ class nsFastLoadFileReader NS_IMETHOD Close(); protected: - // Kept in sync with mInputStream to avoid repeated QI - nsCOMPtr mSeekableInput; - nsFastLoadHeader mHeader; nsFastLoadFooter mFooter; nsDocumentMapReadEntry* mCurrentDocumentMapEntry; friend class nsFastLoadFileUpdater; + nsIFile *mFile; // .mfasl file + PRFileDesc *mFd; // OS file-descriptor + PRUint32 mFileLen; // length of file + PRUint32 mFilePos; // current position within file + PRFileMap *mFileMap;// nspr datastructure for mmap + PRUint8 *mFileData; // pointer to mmaped file }; NS_COM nsresult NS_NewFastLoadFileReader(nsIObjectInputStream* *aResult NS_OUTPARAM, - nsIInputStream* aSrcStream); + nsIFile* aFile); /** * Inherit from the concrete class nsBinaryInputStream, which inherits from @@ -537,12 +539,11 @@ NS_NewFastLoadFileWriter(nsIObjectOutputStream* *aResult NS_OUTPARAM, * that maps all data on Close. */ class nsFastLoadFileUpdater - : public nsFastLoadFileWriter, - private nsIFastLoadFileIO + : public nsFastLoadFileWriter { public: - nsFastLoadFileUpdater(nsIOutputStream* aOutputStream) - : nsFastLoadFileWriter(aOutputStream, nsnull) { + nsFastLoadFileUpdater(nsIOutputStream* aOutputStream, nsIFastLoadFileIO *aFileIO) + : nsFastLoadFileWriter(aOutputStream, aFileIO) { MOZ_COUNT_CTOR(nsFastLoadFileUpdater); } @@ -554,9 +555,6 @@ class nsFastLoadFileUpdater // nsISupports methods NS_DECL_ISUPPORTS_INHERITED - // nsIFastLoadFileIO methods - NS_DECL_NSIFASTLOADFILEIO - nsresult Open(nsFastLoadFileReader* aReader); NS_IMETHOD Close(); @@ -577,7 +575,7 @@ class nsFastLoadFileUpdater NS_COM nsresult NS_NewFastLoadFileUpdater(nsIObjectOutputStream* *aResult NS_OUTPARAM, - nsIOutputStream* aOutputStream, + nsIFastLoadFileIO* aFileIO, nsIObjectInputStream* aReaderAsStream); #endif // nsFastLoadFile_h___ diff --git a/xpcom/io/nsFastLoadService.cpp b/xpcom/io/nsFastLoadService.cpp index 4ad093dab6fe..e3099fbbdecd 100644 --- a/xpcom/io/nsFastLoadService.cpp +++ b/xpcom/io/nsFastLoadService.cpp @@ -163,16 +163,16 @@ nsFastLoadService::NewFastLoadFile(const char* aBaseName, nsIFile* *aResult) } NS_IMETHODIMP -nsFastLoadService::NewInputStream(nsIInputStream* aSrcStream, - nsIObjectInputStream* *aResult) +nsFastLoadService::NewInputStream(nsIFile *aFile, nsIObjectInputStream* *aResult) { nsAutoLock lock(mLock); nsCOMPtr stream; - nsresult rv = NS_NewFastLoadFileReader(getter_AddRefs(stream), aSrcStream); + nsresult rv = NS_NewFastLoadFileReader(getter_AddRefs(stream), aFile); if (NS_FAILED(rv)) return rv; + mFileIO->DisableTruncate(); *aResult = stream; NS_ADDREF(*aResult); return NS_OK; @@ -285,15 +285,9 @@ nsFastLoadService::StartMuxedDocument(nsISupports* aURI, const char* aURISpec, // Ok, aURISpec is not in the existing mux. If we have no output // stream yet, wrap the reader with a FastLoad file updater. if (!mOutputStream && mFileIO) { - nsCOMPtr output; - rv = mFileIO->GetOutputStream(getter_AddRefs(output)); - if (NS_FAILED(rv)) - return rv; - // NB: mInputStream must be an nsFastLoadFileReader! rv = NS_NewFastLoadFileUpdater(getter_AddRefs(mOutputStream), - output, - mInputStream); + mFileIO, mInputStream); if (NS_FAILED(rv)) return rv; } diff --git a/xpcom/io/nsIFastLoadFileControl.idl b/xpcom/io/nsIFastLoadFileControl.idl index 99f5a2875a86..6ad366b2b72c 100644 --- a/xpcom/io/nsIFastLoadFileControl.idl +++ b/xpcom/io/nsIFastLoadFileControl.idl @@ -54,13 +54,13 @@ interface nsISimpleEnumerator; * implementation may still be useful for object serialization, but it can't be * used to read or write a Mozilla FastLoad file. */ -[scriptable, uuid(8a1e2c63-af50-4147-af7e-26289dc180dd)] +[scriptable, uuid(e7c8c14f-c273-4e70-826f-b85864303dc6)] interface nsIFastLoadFileControl : nsISupports { /** - * Get and set the recorded checksum value from the FastLoad file header. + * Get the recorded checksum value from the FastLoad file header. */ - attribute PRUint32 checksum; + readonly attribute PRUint32 checksum; /** * Multiplexed document control methods. A FastLoad file may contain diff --git a/xpcom/io/nsIFastLoadService.idl b/xpcom/io/nsIFastLoadService.idl index dbde0bad8889..b5b65ffdddc5 100644 --- a/xpcom/io/nsIFastLoadService.idl +++ b/xpcom/io/nsIFastLoadService.idl @@ -46,19 +46,23 @@ interface nsIOutputStream; interface nsIObjectInputStream; interface nsIObjectOutputStream; -[scriptable, uuid(715577db-d9c5-464a-a32e-0a40c29b22d4)] +[scriptable, uuid(61cd17e0-b07a-4158-9817-36a206b100e9)] interface nsIFastLoadFileIO : nsISupports { readonly attribute nsIInputStream inputStream; readonly attribute nsIOutputStream outputStream; + /** + * Causes outputStream to be created in non-truncating mode + */ + [noscript] void disableTruncate(); }; -[scriptable, uuid(759e475e-0c23-4dbf-b1b8-78c9369e3072)] +[scriptable, uuid(c18df300-c2e4-4115-a61c-9110655f7dd8)] interface nsIFastLoadService : nsISupports { nsIFile newFastLoadFile(in string aBaseName); - nsIObjectInputStream newInputStream(in nsIInputStream aSrcStream); + nsIObjectInputStream newInputStream(in nsIFile aFile); nsIObjectOutputStream newOutputStream(in nsIOutputStream aDestStream); // Flag values for the direction attribute and the aDirectionFlags