From d4b98885d8bf3a1c585ddacf599156175206c856 Mon Sep 17 00:00:00 2001 From: Jan Varga Date: Wed, 23 May 2012 06:23:11 +0200 Subject: [PATCH] Bug 757507 - Implement read-write file streams. r=biesi --- netwerk/base/public/nsIFileStreams.idl | 65 ++++ netwerk/base/public/nsNetUtil.h | 24 +- netwerk/base/src/nsAsyncStreamCopier.cpp | 2 +- netwerk/base/src/nsFileStreams.cpp | 398 ++++++++++++++--------- netwerk/base/src/nsFileStreams.h | 104 +++++- netwerk/build/nsNetCID.h | 13 + netwerk/build/nsNetModule.cpp | 5 + 7 files changed, 430 insertions(+), 181 deletions(-) diff --git a/netwerk/base/public/nsIFileStreams.idl b/netwerk/base/public/nsIFileStreams.idl index 785a317e7ef1..1129facb16ff 100644 --- a/netwerk/base/public/nsIFileStreams.idl +++ b/netwerk/base/public/nsIFileStreams.idl @@ -56,6 +56,7 @@ interface nsIFileInputStream : nsIInputStream * or more specifically, when one of the following is called: * - Seek * - Tell + * - SetEOF * - Available * - Read * - ReadLine @@ -98,6 +99,7 @@ interface nsIFileOutputStream : nsIOutputStream * be performed when one of the following is called: * - Seek * - Tell + * - SetEOF * - Write * - Flush * @@ -140,3 +142,66 @@ interface nsIPartialFileInputStream : nsISupports in unsigned long long length, in long ioFlags, in long perm, in long behaviorFlags); }; + +/** + * A stream that allows you to read from a file or stream to a file. + */ +[scriptable, uuid(82cf605a-8393-4550-83ab-43cd5578e006)] +interface nsIFileStream : nsISupports +{ + /** + * @param file file to read from or stream to (must QI to + * nsILocalFile) + * @param ioFlags file open flags listed in prio.h (see + * PR_Open documentation) or -1 to open the + * file in default mode (PR_RDWR). + * @param perm file mode bits listed in prio.h or -1 to + * use the default value (0) + * @param behaviorFlags flags specifying various behaviors of the class + * (see enumerations in the class) + */ + void init(in nsIFile file, in long ioFlags, in long perm, + in long behaviorFlags); + + /** + * See the same constant in nsIFileInputStream. The deferred open will + * be performed when one of the following is called: + * - Seek + * - Tell + * - SetEOF + * - Available + * - Read + * - Flush + * - Write + * - GetSize + * - GetLastModified + * + * @note Using this flag results in the file not being opened + * during the call to Init. This means that any errors that might + * happen when this flag is not set would happen during the + * first read or write. The file is not locked when Init is called, + * so it might be deleted before we try to read from it and if the + * file is to be created, then it will not appear on the disk until + * the first write. + */ + const long DEFER_OPEN = 1<<0; +}; + +/** + * An interface that allows you to get some metadata like file size and + * file last modified time. + */ +[scriptable, uuid(07f679e4-9601-4bd1-b510-cd3852edb881)] +interface nsIFileMetadata : nsISupports +{ + /** + * File size in bytes; + */ + readonly attribute long long size; + + /** + * File last modified time in milliseconds from midnight (00:00:00), + * January 1, 1970 Greenwich Mean Time (GMT). + */ + readonly attribute long long lastModified; +}; diff --git a/netwerk/base/public/nsNetUtil.h b/netwerk/base/public/nsNetUtil.h index 2256d871bed2..6eed02a428d9 100644 --- a/netwerk/base/public/nsNetUtil.h +++ b/netwerk/base/public/nsNetUtil.h @@ -919,7 +919,7 @@ NS_NewLocalFileInputStream(nsIInputStream **result, if (NS_SUCCEEDED(rv)) { rv = in->Init(file, ioFlags, perm, behaviorFlags); if (NS_SUCCEEDED(rv)) - NS_ADDREF(*result = in); // cannot use nsCOMPtr::swap + in.forget(result); } return rv; } @@ -957,7 +957,7 @@ NS_NewLocalFileOutputStream(nsIOutputStream **result, if (NS_SUCCEEDED(rv)) { rv = out->Init(file, ioFlags, perm, behaviorFlags); if (NS_SUCCEEDED(rv)) - NS_ADDREF(*result = out); // cannot use nsCOMPtr::swap + out.forget(result); } return rv; } @@ -976,7 +976,25 @@ NS_NewSafeLocalFileOutputStream(nsIOutputStream **result, if (NS_SUCCEEDED(rv)) { rv = out->Init(file, ioFlags, perm, behaviorFlags); if (NS_SUCCEEDED(rv)) - NS_ADDREF(*result = out); // cannot use nsCOMPtr::swap + out.forget(result); + } + return rv; +} + +inline nsresult +NS_NewLocalFileStream(nsIFileStream **result, + nsIFile *file, + PRInt32 ioFlags = -1, + PRInt32 perm = -1, + PRInt32 behaviorFlags = 0) +{ + nsresult rv; + nsCOMPtr stream = + do_CreateInstance(NS_LOCALFILESTREAM_CONTRACTID, &rv); + if (NS_SUCCEEDED(rv)) { + rv = stream->Init(file, ioFlags, perm, behaviorFlags); + if (NS_SUCCEEDED(rv)) + stream.forget(result); } return rv; } diff --git a/netwerk/base/src/nsAsyncStreamCopier.cpp b/netwerk/base/src/nsAsyncStreamCopier.cpp index 4d8ce9dfdef4..26d4ae854335 100644 --- a/netwerk/base/src/nsAsyncStreamCopier.cpp +++ b/netwerk/base/src/nsAsyncStreamCopier.cpp @@ -240,7 +240,7 @@ nsAsyncStreamCopier::AsyncCopy(nsIRequestObserver *observer, nsISupports *ctx) if (NS_FAILED(rv)) Cancel(rv); } - + // we want to receive progress notifications; release happens in // OnAsyncCopyComplete. NS_ADDREF_THIS(); diff --git a/netwerk/base/src/nsFileStreams.cpp b/netwerk/base/src/nsFileStreams.cpp index c0d219eb6903..b727b77a2bff 100644 --- a/netwerk/base/src/nsFileStreams.cpp +++ b/netwerk/base/src/nsFileStreams.cpp @@ -33,38 +33,24 @@ #define NS_NO_INPUT_BUFFERING 1 // see http://bugzilla.mozilla.org/show_bug.cgi?id=41067 //////////////////////////////////////////////////////////////////////////////// -// nsFileStream +// nsFileStreamBase -nsFileStream::nsFileStream() +nsFileStreamBase::nsFileStreamBase() : mFD(nsnull) , mBehaviorFlags(0) , mDeferredOpen(false) { } -nsFileStream::~nsFileStream() +nsFileStreamBase::~nsFileStreamBase() { Close(); } -NS_IMPL_THREADSAFE_ISUPPORTS1(nsFileStream, nsISeekableStream) - -nsresult -nsFileStream::Close() -{ - CleanUpOpen(); - - nsresult rv = NS_OK; - if (mFD) { - if (PR_Close(mFD) == PR_FAILURE) - rv = NS_BASE_STREAM_OSERROR; - mFD = nsnull; - } - return rv; -} +NS_IMPL_THREADSAFE_ISUPPORTS1(nsFileStreamBase, nsISeekableStream) NS_IMETHODIMP -nsFileStream::Seek(PRInt32 whence, PRInt64 offset) +nsFileStreamBase::Seek(PRInt32 whence, PRInt64 offset) { nsresult rv = DoPendingOpen(); NS_ENSURE_SUCCESS(rv, rv); @@ -80,7 +66,7 @@ nsFileStream::Seek(PRInt32 whence, PRInt64 offset) } NS_IMETHODIMP -nsFileStream::Tell(PRInt64 *result) +nsFileStreamBase::Tell(PRInt64 *result) { nsresult rv = DoPendingOpen(); NS_ENSURE_SUCCESS(rv, rv); @@ -97,15 +83,18 @@ nsFileStream::Tell(PRInt64 *result) } NS_IMETHODIMP -nsFileStream::SetEOF() +nsFileStreamBase::SetEOF() { + nsresult rv = DoPendingOpen(); + NS_ENSURE_SUCCESS(rv, rv); + if (mFD == nsnull) return NS_BASE_STREAM_CLOSED; #if defined(XP_UNIX) || defined(XP_OS2) || defined(XP_BEOS) // Some system calls require an EOF offset. PRInt64 offset; - nsresult rv = Tell(&offset); + rv = Tell(&offset); if (NS_FAILED(rv)) return rv; #endif @@ -132,8 +121,138 @@ nsFileStream::SetEOF() } nsresult -nsFileStream::MaybeOpen(nsILocalFile* aFile, PRInt32 aIoFlags, PRInt32 aPerm, - bool aDeferred) +nsFileStreamBase::Close() +{ + CleanUpOpen(); + + nsresult rv = NS_OK; + if (mFD) { + if (PR_Close(mFD) == PR_FAILURE) + rv = NS_BASE_STREAM_OSERROR; + mFD = nsnull; + } + return rv; +} + +nsresult +nsFileStreamBase::Available(PRUint32* aResult) +{ + nsresult rv = DoPendingOpen(); + NS_ENSURE_SUCCESS(rv, rv); + + if (!mFD) { + return NS_BASE_STREAM_CLOSED; + } + + // PR_Available with files over 4GB returns an error, so we have to + // use the 64-bit version of PR_Available. + PRInt64 avail = PR_Available64(mFD); + if (avail == -1) { + return NS_ErrorAccordingToNSPR(); + } + + // If available is greater than 4GB, return 4GB + *aResult = avail > PR_UINT32_MAX ? PR_UINT32_MAX : (PRUint32)avail; + return NS_OK; +} + +nsresult +nsFileStreamBase::Read(char* aBuf, PRUint32 aCount, PRUint32* aResult) +{ + nsresult rv = DoPendingOpen(); + NS_ENSURE_SUCCESS(rv, rv); + + if (!mFD) { + *aResult = 0; + return NS_OK; + } + + PRInt32 bytesRead = PR_Read(mFD, aBuf, aCount); + if (bytesRead == -1) { + return NS_ErrorAccordingToNSPR(); + } + + *aResult = bytesRead; + return NS_OK; +} + +nsresult +nsFileStreamBase::ReadSegments(nsWriteSegmentFun aWriter, void* aClosure, + PRUint32 aCount, PRUint32* aResult) +{ + // ReadSegments is not implemented because it would be inefficient when + // the writer does not consume all data. If you want to call ReadSegments, + // wrap a BufferedInputStream around the file stream. That will call + // Read(). + + // If this is ever implemented you might need to modify + // nsPartialFileInputStream::ReadSegments + + return NS_ERROR_NOT_IMPLEMENTED; +} + +nsresult +nsFileStreamBase::IsNonBlocking(bool *aNonBlocking) +{ + *aNonBlocking = false; + return NS_OK; +} + +nsresult +nsFileStreamBase::Flush(void) +{ + nsresult rv = DoPendingOpen(); + NS_ENSURE_SUCCESS(rv, rv); + + if (mFD == nsnull) + return NS_BASE_STREAM_CLOSED; + + PRInt32 cnt = PR_Sync(mFD); + if (cnt == -1) { + return NS_ErrorAccordingToNSPR(); + } + return NS_OK; +} + +nsresult +nsFileStreamBase::Write(const char *buf, PRUint32 count, PRUint32 *result) +{ + nsresult rv = DoPendingOpen(); + NS_ENSURE_SUCCESS(rv, rv); + + if (mFD == nsnull) + return NS_BASE_STREAM_CLOSED; + + PRInt32 cnt = PR_Write(mFD, buf, count); + if (cnt == -1) { + return NS_ErrorAccordingToNSPR(); + } + *result = cnt; + return NS_OK; +} + +nsresult +nsFileStreamBase::WriteFrom(nsIInputStream *inStr, PRUint32 count, PRUint32 *_retval) +{ + NS_NOTREACHED("WriteFrom (see source comment)"); + return NS_ERROR_NOT_IMPLEMENTED; + // File streams intentionally do not support this method. + // If you need something like this, then you should wrap + // the file stream using nsIBufferedOutputStream +} + +nsresult +nsFileStreamBase::WriteSegments(nsReadSegmentFun reader, void * closure, PRUint32 count, PRUint32 *_retval) +{ + return NS_ERROR_NOT_IMPLEMENTED; + // File streams intentionally do not support this method. + // If you need something like this, then you should wrap + // the file stream using nsIBufferedOutputStream +} + +nsresult +nsFileStreamBase::MaybeOpen(nsILocalFile* aFile, PRInt32 aIoFlags, + PRInt32 aPerm, bool aDeferred) { mOpenParams.ioFlags = aIoFlags; mOpenParams.perm = aPerm; @@ -157,14 +276,14 @@ nsFileStream::MaybeOpen(nsILocalFile* aFile, PRInt32 aIoFlags, PRInt32 aPerm, } void -nsFileStream::CleanUpOpen() +nsFileStreamBase::CleanUpOpen() { mOpenParams.localFile = nsnull; mDeferredOpen = false; } nsresult -nsFileStream::DoOpen() +nsFileStreamBase::DoOpen() { NS_PRECONDITION(mOpenParams.localFile, "Must have a file to open"); @@ -178,7 +297,7 @@ nsFileStream::DoOpen() } nsresult -nsFileStream::DoPendingOpen() +nsFileStreamBase::DoPendingOpen() { if (!mDeferredOpen) { return NS_OK; @@ -190,20 +309,19 @@ nsFileStream::DoPendingOpen() //////////////////////////////////////////////////////////////////////////////// // nsFileInputStream -NS_IMPL_ADDREF_INHERITED(nsFileInputStream, nsFileStream) -NS_IMPL_RELEASE_INHERITED(nsFileInputStream, nsFileStream) +NS_IMPL_ADDREF_INHERITED(nsFileInputStream, nsFileStreamBase) +NS_IMPL_RELEASE_INHERITED(nsFileInputStream, nsFileStreamBase) NS_IMPL_CLASSINFO(nsFileInputStream, NULL, nsIClassInfo::THREADSAFE, NS_LOCALFILEINPUTSTREAM_CID) NS_INTERFACE_MAP_BEGIN(nsFileInputStream) - NS_INTERFACE_MAP_ENTRY(nsFileStream) NS_INTERFACE_MAP_ENTRY(nsIInputStream) NS_INTERFACE_MAP_ENTRY(nsIFileInputStream) NS_INTERFACE_MAP_ENTRY(nsILineInputStream) NS_INTERFACE_MAP_ENTRY(nsIIPCSerializable) NS_IMPL_QUERY_CLASSINFO(nsFileInputStream) -NS_INTERFACE_MAP_END_INHERITING(nsFileStream) +NS_INTERFACE_MAP_END_INHERITING(nsFileStreamBase) NS_IMPL_CI_INTERFACE_GETTER5(nsFileInputStream, nsIInputStream, @@ -286,7 +404,7 @@ nsFileInputStream::Close() { // null out mLineBuffer in case Close() is called again after failing PR_FREEIF(mLineBuffer); - nsresult rv = nsFileStream::Close(); + nsresult rv = nsFileStreamBase::Close(); if (NS_FAILED(rv)) return rv; if (mFile && (mBehaviorFlags & DELETE_ON_CLOSE)) { rv = mFile->Remove(false); @@ -300,50 +418,16 @@ nsFileInputStream::Close() } NS_IMETHODIMP -nsFileInputStream::Available(PRUint32* aResult) +nsFileInputStream::Read(char* aBuf, PRUint32 aCount, PRUint32* _retval) { - nsresult rv = DoPendingOpen(); + nsresult rv = nsFileStreamBase::Read(aBuf, aCount, _retval); NS_ENSURE_SUCCESS(rv, rv); - if (!mFD) { - return NS_BASE_STREAM_CLOSED; - } - - // PR_Available with files over 4GB returns an error, so we have to - // use the 64-bit version of PR_Available. - PRInt64 avail = PR_Available64(mFD); - if (avail == -1) { - return NS_ErrorAccordingToNSPR(); - } - - // If available is greater than 4GB, return 4GB - *aResult = avail > PR_UINT32_MAX ? PR_UINT32_MAX : (PRUint32)avail; - return NS_OK; -} - -NS_IMETHODIMP -nsFileInputStream::Read(char* aBuf, PRUint32 aCount, PRUint32* aResult) -{ - nsresult rv = DoPendingOpen(); - NS_ENSURE_SUCCESS(rv, rv); - - if (!mFD) { - *aResult = 0; - return NS_OK; - } - - PRInt32 bytesRead = PR_Read(mFD, aBuf, aCount); - if (bytesRead == -1) { - return NS_ErrorAccordingToNSPR(); - } // Check if we're at the end of file and need to close - if (mBehaviorFlags & CLOSE_ON_EOF) { - if (bytesRead == 0) { - Close(); - } + if (mBehaviorFlags & CLOSE_ON_EOF && *_retval == 0) { + Close(); } - *aResult = bytesRead; return NS_OK; } @@ -360,28 +444,6 @@ nsFileInputStream::ReadLine(nsACString& aLine, bool* aResult) return NS_ReadLine(this, mLineBuffer, aLine, aResult); } -NS_IMETHODIMP -nsFileInputStream::ReadSegments(nsWriteSegmentFun aWriter, void* aClosure, - PRUint32 aCount, PRUint32* aResult) -{ - // ReadSegments is not implemented because it would be inefficient when - // the writer does not consume all data. If you want to call ReadSegments, - // wrap a BufferedInputStream around the file stream. That will call - // Read(). - - // If this is ever implemented you might need to modify - // nsPartialFileInputStream::ReadSegments - - return NS_ERROR_NOT_IMPLEMENTED; -} - -NS_IMETHODIMP -nsFileInputStream::IsNonBlocking(bool *aNonBlocking) -{ - *aNonBlocking = false; - return NS_OK; -} - NS_IMETHODIMP nsFileInputStream::Seek(PRInt32 aWhence, PRInt64 aOffset) { @@ -400,7 +462,7 @@ nsFileInputStream::Seek(PRInt32 aWhence, PRInt64 aOffset) } } - return nsFileStream::Seek(aWhence, aOffset); + return nsFileStreamBase::Seek(aWhence, aOffset); } bool @@ -451,7 +513,7 @@ nsFileInputStream::Write(IPC::Message *aMsg) // Don't forward to nsFileInputStream as we don't want to QI to // nsIFileInputStream NS_IMPL_ISUPPORTS_INHERITED3(nsPartialFileInputStream, - nsFileStream, + nsFileStreamBase, nsIInputStream, nsIPartialFileInputStream, nsILineInputStream) @@ -557,8 +619,8 @@ nsPartialFileInputStream::Seek(PRInt32 aWhence, PRInt64 aOffset) //////////////////////////////////////////////////////////////////////////////// // nsFileOutputStream -NS_IMPL_ISUPPORTS_INHERITED2(nsFileOutputStream, - nsFileStream, +NS_IMPL_ISUPPORTS_INHERITED2(nsFileOutputStream, + nsFileStreamBase, nsIOutputStream, nsIFileOutputStream) @@ -597,75 +659,10 @@ nsFileOutputStream::Init(nsIFile* file, PRInt32 ioFlags, PRInt32 perm, mBehaviorFlags & nsIFileOutputStream::DEFER_OPEN); } -NS_IMETHODIMP -nsFileOutputStream::Close() -{ - return nsFileStream::Close(); -} - -NS_IMETHODIMP -nsFileOutputStream::Write(const char *buf, PRUint32 count, PRUint32 *result) -{ - nsresult rv = DoPendingOpen(); - NS_ENSURE_SUCCESS(rv, rv); - - if (mFD == nsnull) - return NS_BASE_STREAM_CLOSED; - - PRInt32 cnt = PR_Write(mFD, buf, count); - if (cnt == -1) { - return NS_ErrorAccordingToNSPR(); - } - *result = cnt; - return NS_OK; -} - -NS_IMETHODIMP -nsFileOutputStream::Flush(void) -{ - nsresult rv = DoPendingOpen(); - NS_ENSURE_SUCCESS(rv, rv); - - if (mFD == nsnull) - return NS_BASE_STREAM_CLOSED; - - PRInt32 cnt = PR_Sync(mFD); - if (cnt == -1) { - return NS_ErrorAccordingToNSPR(); - } - return NS_OK; -} - -NS_IMETHODIMP -nsFileOutputStream::WriteFrom(nsIInputStream *inStr, PRUint32 count, PRUint32 *_retval) -{ - NS_NOTREACHED("WriteFrom (see source comment)"); - return NS_ERROR_NOT_IMPLEMENTED; - // File streams intentionally do not support this method. - // If you need something like this, then you should wrap - // the file stream using nsIBufferedOutputStream -} - -NS_IMETHODIMP -nsFileOutputStream::WriteSegments(nsReadSegmentFun reader, void * closure, PRUint32 count, PRUint32 *_retval) -{ - return NS_ERROR_NOT_IMPLEMENTED; - // File streams intentionally do not support this method. - // If you need something like this, then you should wrap - // the file stream using nsIBufferedOutputStream -} - -NS_IMETHODIMP -nsFileOutputStream::IsNonBlocking(bool *aNonBlocking) -{ - *aNonBlocking = false; - return NS_OK; -} - //////////////////////////////////////////////////////////////////////////////// // nsSafeFileOutputStream -NS_IMPL_ISUPPORTS_INHERITED3(nsSafeFileOutputStream, +NS_IMPL_ISUPPORTS_INHERITED3(nsSafeFileOutputStream, nsFileOutputStream, nsISafeOutputStream, nsIOutputStream, @@ -810,3 +807,80 @@ nsSafeFileOutputStream::Write(const char *buf, PRUint32 count, PRUint32 *result) } //////////////////////////////////////////////////////////////////////////////// +// nsFileStream + +NS_IMPL_ISUPPORTS_INHERITED4(nsFileStream, + nsFileStreamBase, + nsIInputStream, + nsIOutputStream, + nsIFileStream, + nsIFileMetadata) + +NS_IMETHODIMP +nsFileStream::Init(nsIFile* file, PRInt32 ioFlags, PRInt32 perm, + PRInt32 behaviorFlags) +{ + NS_ENSURE_TRUE(mFD == nsnull, NS_ERROR_ALREADY_INITIALIZED); + NS_ENSURE_TRUE(!mDeferredOpen, NS_ERROR_ALREADY_INITIALIZED); + + mBehaviorFlags = behaviorFlags; + + nsresult rv; + nsCOMPtr localFile = do_QueryInterface(file, &rv); + if (NS_FAILED(rv)) return rv; + if (ioFlags == -1) + ioFlags = PR_RDWR; + if (perm <= 0) + perm = 0; + + return MaybeOpen(localFile, ioFlags, perm, + mBehaviorFlags & nsIFileStream::DEFER_OPEN); +} + +NS_IMETHODIMP +nsFileStream::GetSize(PRInt64* _retval) +{ + nsresult rv = DoPendingOpen(); + NS_ENSURE_SUCCESS(rv, rv); + + if (!mFD) { + return NS_BASE_STREAM_CLOSED; + } + + PRFileInfo64 info; + if (PR_GetOpenFileInfo64(mFD, &info) == PR_FAILURE) { + return NS_BASE_STREAM_OSERROR; + } + + *_retval = PRInt64(info.size); + + return NS_OK; +} + +NS_IMETHODIMP +nsFileStream::GetLastModified(PRInt64* _retval) +{ + nsresult rv = DoPendingOpen(); + NS_ENSURE_SUCCESS(rv, rv); + + if (!mFD) { + return NS_BASE_STREAM_CLOSED; + } + + PRFileInfo64 info; + if (PR_GetOpenFileInfo64(mFD, &info) == PR_FAILURE) { + return NS_BASE_STREAM_OSERROR; + } + + PRInt64 modTime = PRInt64(info.modifyTime); + if (modTime == 0) { + *_retval = 0; + } + else { + *_retval = modTime / PRInt64(PR_USEC_PER_MSEC); + } + + return NS_OK; +} + +//////////////////////////////////////////////////////////////////////////////// diff --git a/netwerk/base/src/nsFileStreams.h b/netwerk/base/src/nsFileStreams.h index 1b3d7e748571..cd5c5cfaab42 100644 --- a/netwerk/base/src/nsFileStreams.h +++ b/netwerk/base/src/nsFileStreams.h @@ -23,18 +23,29 @@ template class nsLineBuffer; //////////////////////////////////////////////////////////////////////////////// -class nsFileStream : public nsISeekableStream +class nsFileStreamBase : public nsISeekableStream { public: NS_DECL_ISUPPORTS NS_DECL_NSISEEKABLESTREAM - nsFileStream(); - virtual ~nsFileStream(); - - nsresult Close(); + nsFileStreamBase(); + virtual ~nsFileStreamBase(); protected: + nsresult Close(); + nsresult Available(PRUint32* _retval); + nsresult Read(char* aBuf, PRUint32 aCount, PRUint32* _retval); + nsresult ReadSegments(nsWriteSegmentFun aWriter, void* aClosure, + PRUint32 aCount, PRUint32* _retval); + nsresult IsNonBlocking(bool* _retval); + nsresult Flush(); + nsresult Write(const char* aBuf, PRUint32 aCount, PRUint32* _retval); + nsresult WriteFrom(nsIInputStream* aFromStream, PRUint32 aCount, + PRUint32* _retval); + nsresult WriteSegments(nsReadSegmentFun aReader, void* aClosure, + PRUint32 aCount, PRUint32* _retval); + PRFileDesc* mFD; /** @@ -88,22 +99,38 @@ protected: //////////////////////////////////////////////////////////////////////////////// -class nsFileInputStream : public nsFileStream, +class nsFileInputStream : public nsFileStreamBase, public nsIFileInputStream, public nsILineInputStream, public nsIIPCSerializable { public: NS_DECL_ISUPPORTS_INHERITED - NS_DECL_NSIINPUTSTREAM NS_DECL_NSIFILEINPUTSTREAM NS_DECL_NSILINEINPUTSTREAM NS_DECL_NSIIPCSERIALIZABLE + + NS_IMETHOD Close(); + NS_IMETHOD Available(PRUint32* _retval) + { + return nsFileStreamBase::Available(_retval); + } + NS_IMETHOD Read(char* aBuf, PRUint32 aCount, PRUint32* _retval); + NS_IMETHOD ReadSegments(nsWriteSegmentFun aWriter, void *aClosure, + PRUint32 aCount, PRUint32* _retval) + { + return nsFileStreamBase::ReadSegments(aWriter, aClosure, aCount, + _retval); + } + NS_IMETHOD IsNonBlocking(bool* _retval) + { + return nsFileStreamBase::IsNonBlocking(_retval); + } - // Overrided from nsFileStream + // Overrided from nsFileStreamBase NS_IMETHOD Seek(PRInt32 aWhence, PRInt64 aOffset); - nsFileInputStream() : nsFileStream() + nsFileInputStream() { mLineBuffer = nsnull; } @@ -172,17 +199,19 @@ private: //////////////////////////////////////////////////////////////////////////////// -class nsFileOutputStream : public nsFileStream, +class nsFileOutputStream : public nsFileStreamBase, public nsIFileOutputStream { public: NS_DECL_ISUPPORTS_INHERITED - NS_DECL_NSIOUTPUTSTREAM NS_DECL_NSIFILEOUTPUTSTREAM + NS_FORWARD_NSIOUTPUTSTREAM(nsFileStreamBase::) + + virtual ~nsFileOutputStream() + { + Close(); + } - nsFileOutputStream() : nsFileStream() {} - virtual ~nsFileOutputStream() { nsFileOutputStream::Close(); } - static nsresult Create(nsISupports *aOuter, REFNSIID aIID, void **aResult); }; @@ -200,7 +229,10 @@ public: mTargetFileExists(true), mWriteResult(NS_OK) {} - virtual ~nsSafeFileOutputStream() { nsSafeFileOutputStream::Close(); } + virtual ~nsSafeFileOutputStream() + { + Close(); + } virtual nsresult DoOpen(); @@ -218,4 +250,46 @@ protected: //////////////////////////////////////////////////////////////////////////////// +class nsFileStream : public nsFileStreamBase, + public nsIInputStream, + public nsIOutputStream, + public nsIFileStream, + public nsIFileMetadata +{ +public: + NS_DECL_ISUPPORTS_INHERITED + NS_DECL_NSIFILESTREAM + NS_DECL_NSIFILEMETADATA + NS_FORWARD_NSIINPUTSTREAM(nsFileStreamBase::) + + // Can't use NS_FORWARD_NSIOUTPUTSTREAM due to overlapping methods + // Close() and IsNonBlocking() + NS_IMETHOD Flush() + { + return nsFileStreamBase::Flush(); + } + NS_IMETHOD Write(const char* aBuf, PRUint32 aCount, PRUint32* _retval) + { + return nsFileStreamBase::Write(aBuf, aCount, _retval); + } + NS_IMETHOD WriteFrom(nsIInputStream* aFromStream, PRUint32 aCount, + PRUint32* _retval) + { + return nsFileStreamBase::WriteFrom(aFromStream, aCount, _retval); + } + NS_IMETHOD WriteSegments(nsReadSegmentFun aReader, void* aClosure, + PRUint32 aCount, PRUint32* _retval) + { + return nsFileStreamBase::WriteSegments(aReader, aClosure, aCount, + _retval); + } + + virtual ~nsFileStream() + { + Close(); + } +}; + +//////////////////////////////////////////////////////////////////////////////// + #endif // nsFileStreams_h__ diff --git a/netwerk/build/nsNetCID.h b/netwerk/build/nsNetCID.h index 652d445da9b8..081c2786a150 100644 --- a/netwerk/build/nsNetCID.h +++ b/netwerk/build/nsNetCID.h @@ -432,6 +432,19 @@ {0x94, 0xdb, 0xd4, 0xf8, 0x59, 0x05, 0x82, 0x15} \ } +// component implementing nsIFileStream +#define NS_LOCALFILESTREAM_CLASSNAME \ + "nsFileStream" +#define NS_LOCALFILESTREAM_CONTRACTID \ + "@mozilla.org/network/file-stream;1" +#define NS_LOCALFILESTREAM_CID \ +{ /* f8a69bd7-176c-4a60-9a05-b6d92f8f229a */ \ + 0xf8a69bd7, \ + 0x176c, \ + 0x4a60, \ + {0x9a, 0x05, 0xb6, 0xd9, 0x2f, 0x8f, 0x22, 0x9a} \ +} + // component implementing nsIPrivateBrowsingService #define NS_PRIVATE_BROWSING_SERVICE_CONTRACTID \ "@mozilla.org/privatebrowsing-wrapper;1" diff --git a/netwerk/build/nsNetModule.cpp b/netwerk/build/nsNetModule.cpp index a837e40b72ad..9e7c4ace338d 100644 --- a/netwerk/build/nsNetModule.cpp +++ b/netwerk/build/nsNetModule.cpp @@ -87,6 +87,8 @@ NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsSyncStreamListener, Init) NS_GENERIC_FACTORY_CONSTRUCTOR(nsSafeFileOutputStream) +NS_GENERIC_FACTORY_CONSTRUCTOR(nsFileStream) + NS_GENERIC_AGGREGATED_CONSTRUCTOR_INIT(nsLoadGroup, Init) #include "nsEffectiveTLDService.h" @@ -672,6 +674,7 @@ NS_DEFINE_NAMED_CID(NS_LOCALFILEINPUTSTREAM_CID); NS_DEFINE_NAMED_CID(NS_LOCALFILEOUTPUTSTREAM_CID); NS_DEFINE_NAMED_CID(NS_PARTIALLOCALFILEINPUTSTREAM_CID); NS_DEFINE_NAMED_CID(NS_SAFELOCALFILEOUTPUTSTREAM_CID); +NS_DEFINE_NAMED_CID(NS_LOCALFILESTREAM_CID); NS_DEFINE_NAMED_CID(NS_URICHECKER_CID); NS_DEFINE_NAMED_CID(NS_INCREMENTALDOWNLOAD_CID); NS_DEFINE_NAMED_CID(NS_STDURLPARSER_CID); @@ -806,6 +809,7 @@ static const mozilla::Module::CIDEntry kNeckoCIDs[] = { { &kNS_LOCALFILEOUTPUTSTREAM_CID, false, NULL, nsFileOutputStream::Create }, { &kNS_PARTIALLOCALFILEINPUTSTREAM_CID, false, NULL, nsPartialFileInputStream::Create }, { &kNS_SAFELOCALFILEOUTPUTSTREAM_CID, false, NULL, nsSafeFileOutputStreamConstructor }, + { &kNS_LOCALFILESTREAM_CID, false, NULL, nsFileStreamConstructor }, { &kNS_URICHECKER_CID, false, NULL, nsURICheckerConstructor }, { &kNS_INCREMENTALDOWNLOAD_CID, false, NULL, net_NewIncrementalDownload }, { &kNS_STDURLPARSER_CID, false, NULL, nsStdURLParserConstructor }, @@ -944,6 +948,7 @@ static const mozilla::Module::ContractIDEntry kNeckoContracts[] = { { NS_LOCALFILEOUTPUTSTREAM_CONTRACTID, &kNS_LOCALFILEOUTPUTSTREAM_CID }, { NS_PARTIALLOCALFILEINPUTSTREAM_CONTRACTID, &kNS_PARTIALLOCALFILEINPUTSTREAM_CID }, { NS_SAFELOCALFILEOUTPUTSTREAM_CONTRACTID, &kNS_SAFELOCALFILEOUTPUTSTREAM_CID }, + { NS_LOCALFILESTREAM_CONTRACTID, &kNS_LOCALFILESTREAM_CID }, { NS_URICHECKER_CONTRACT_ID, &kNS_URICHECKER_CID }, { NS_INCREMENTALDOWNLOAD_CONTRACTID, &kNS_INCREMENTALDOWNLOAD_CID }, { NS_STDURLPARSER_CONTRACTID, &kNS_STDURLPARSER_CID },