// /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef nsFileStreams_h__ #define nsFileStreams_h__ #include "nsAutoPtr.h" #include "nsIFileStreams.h" #include "nsIFile.h" #include "nsICloneableInputStream.h" #include "nsIInputStream.h" #include "nsIOutputStream.h" #include "nsISafeOutputStream.h" #include "nsISeekableStream.h" #include "nsILineInputStream.h" #include "nsCOMPtr.h" #include "nsIIPCSerializableInputStream.h" #include "nsReadLine.h" #include //////////////////////////////////////////////////////////////////////////////// class nsFileStreamBase : public nsISeekableStream, public nsIFileMetadata { public: // Record refcount changes to ensure that streams are destroyed on // consistent threads when recording/replaying. NS_DECL_THREADSAFE_ISUPPORTS_WITH_RECORDING(mozilla::recordreplay::Behavior::Preserve) NS_DECL_NSISEEKABLESTREAM NS_DECL_NSITELLABLESTREAM NS_DECL_NSIFILEMETADATA nsFileStreamBase(); protected: virtual ~nsFileStreamBase(); nsresult Close(); nsresult Available(uint64_t* _retval); nsresult Read(char* aBuf, uint32_t aCount, uint32_t* _retval); nsresult ReadSegments(nsWriteSegmentFun aWriter, void* aClosure, uint32_t aCount, uint32_t* _retval); nsresult IsNonBlocking(bool* _retval); nsresult Flush(); nsresult Write(const char* aBuf, uint32_t aCount, uint32_t* _retval); nsresult WriteFrom(nsIInputStream* aFromStream, uint32_t aCount, uint32_t* _retval); nsresult WriteSegments(nsReadSegmentFun aReader, void* aClosure, uint32_t aCount, uint32_t* _retval); PRFileDesc* mFD; /** * Flags describing our behavior. See the IDL file for possible values. */ int32_t mBehaviorFlags; enum { // This is the default value. It will be changed by Deserialize or Init. eUnitialized, // The opening has been deferred. See DEFER_OPEN. eDeferredOpen, // The file has been opened. mFD is not null. eOpened, // The file has been closed. mFD is null. eClosed, // Something bad happen in the Open() or in Deserialize(). The actual // error value is stored in mErrorValue. eError } mState; struct OpenParams { nsCOMPtr localFile; int32_t ioFlags; int32_t perm; }; /** * Data we need to do an open. */ OpenParams mOpenParams; nsresult mErrorValue; /** * Prepares the data we need to open the file, and either does the open now * by calling DoOpen(), or leaves it to be opened later by a call to * DoPendingOpen(). */ nsresult MaybeOpen(nsIFile* aFile, int32_t aIoFlags, int32_t aPerm, bool aDeferred); /** * Cleans up data prepared in MaybeOpen. */ void CleanUpOpen(); /** * Open the file. This is called either from MaybeOpen (during Init) * or from DoPendingOpen (if DEFER_OPEN is used when initializing this * stream). The default behavior of DoOpen is to open the file and save the * file descriptor. */ virtual nsresult DoOpen(); /** * Based on mState, this method does the opening, return an error, or do * nothing. If the return value is not NS_OK, please, return it back to the * callee. */ inline nsresult DoPendingOpen(); }; //////////////////////////////////////////////////////////////////////////////// // nsFileInputStream is cloneable only on the parent process because only there // it can open the same file multiple times. class nsFileInputStream : public nsFileStreamBase , public nsIFileInputStream , public nsILineInputStream , public nsIIPCSerializableInputStream , public nsICloneableInputStream { public: NS_DECL_ISUPPORTS_INHERITED NS_DECL_NSIFILEINPUTSTREAM NS_DECL_NSILINEINPUTSTREAM NS_DECL_NSIIPCSERIALIZABLEINPUTSTREAM NS_DECL_NSICLONEABLEINPUTSTREAM NS_IMETHOD Close() override; NS_IMETHOD Tell(int64_t *aResult) override; NS_IMETHOD Available(uint64_t* _retval) override; NS_IMETHOD Read(char* aBuf, uint32_t aCount, uint32_t* _retval) override; NS_IMETHOD ReadSegments(nsWriteSegmentFun aWriter, void *aClosure, uint32_t aCount, uint32_t* _retval) override { return nsFileStreamBase::ReadSegments(aWriter, aClosure, aCount, _retval); } NS_IMETHOD IsNonBlocking(bool* _retval) override { return nsFileStreamBase::IsNonBlocking(_retval); } // Overrided from nsFileStreamBase NS_IMETHOD Seek(int32_t aWhence, int64_t aOffset) override; nsFileInputStream() : mLineBuffer(nullptr), mIOFlags(0), mPerm(0), mCachedPosition(0) {} static nsresult Create(nsISupports *aOuter, REFNSIID aIID, void **aResult); protected: virtual ~nsFileInputStream() = default; nsresult SeekInternal(int32_t aWhence, int64_t aOffset, bool aClearBuf=true); nsAutoPtr > mLineBuffer; /** * The file being opened. */ nsCOMPtr mFile; /** * The IO flags passed to Init() for the file open. */ int32_t mIOFlags; /** * The permissions passed to Init() for the file open. */ int32_t mPerm; /** * Cached position for Tell for automatically reopening streams. */ int64_t mCachedPosition; protected: /** * Internal, called to open a file. Parameters are the same as their * Init() analogues. */ nsresult Open(nsIFile* file, int32_t ioFlags, int32_t perm); bool IsCloneable() const; }; //////////////////////////////////////////////////////////////////////////////// class nsFileOutputStream : public nsFileStreamBase, public nsIFileOutputStream { public: NS_DECL_ISUPPORTS_INHERITED NS_DECL_NSIFILEOUTPUTSTREAM NS_FORWARD_NSIOUTPUTSTREAM(nsFileStreamBase::) static nsresult Create(nsISupports *aOuter, REFNSIID aIID, void **aResult); protected: virtual ~nsFileOutputStream() = default; }; //////////////////////////////////////////////////////////////////////////////// /** * A safe file output stream that overwrites the destination file only * once writing is complete. This protects against incomplete writes * due to the process or the thread being interrupted or crashed. */ class nsAtomicFileOutputStream : public nsFileOutputStream, public nsISafeOutputStream { public: NS_DECL_ISUPPORTS_INHERITED NS_DECL_NSISAFEOUTPUTSTREAM nsAtomicFileOutputStream() : mTargetFileExists(true), mWriteResult(NS_OK) {} virtual nsresult DoOpen() override; NS_IMETHOD Close() override; NS_IMETHOD Write(const char *buf, uint32_t count, uint32_t *result) override; NS_IMETHOD Init(nsIFile* file, int32_t ioFlags, int32_t perm, int32_t behaviorFlags) override; protected: virtual ~nsAtomicFileOutputStream() = default; nsCOMPtr mTargetFile; nsCOMPtr mTempFile; bool mTargetFileExists; nsresult mWriteResult; // Internally set in Write() }; //////////////////////////////////////////////////////////////////////////////// /** * A safe file output stream that overwrites the destination file only * once writing + flushing is complete. This protects against more * classes of software/hardware errors than nsAtomicFileOutputStream, * at the expense of being more costly to the disk, OS and battery. */ class nsSafeFileOutputStream : public nsAtomicFileOutputStream { public: NS_IMETHOD Finish() override; }; //////////////////////////////////////////////////////////////////////////////// class nsFileStream : public nsFileStreamBase, public nsIInputStream, public nsIOutputStream, public nsIFileStream { public: NS_DECL_ISUPPORTS_INHERITED NS_DECL_NSIFILESTREAM NS_FORWARD_NSIINPUTSTREAM(nsFileStreamBase::) // Can't use NS_FORWARD_NSIOUTPUTSTREAM due to overlapping methods // Close() and IsNonBlocking() NS_IMETHOD Flush() override { return nsFileStreamBase::Flush(); } NS_IMETHOD Write(const char* aBuf, uint32_t aCount, uint32_t* _retval) override { return nsFileStreamBase::Write(aBuf, aCount, _retval); } NS_IMETHOD WriteFrom(nsIInputStream* aFromStream, uint32_t aCount, uint32_t* _retval) override { return nsFileStreamBase::WriteFrom(aFromStream, aCount, _retval); } NS_IMETHOD WriteSegments(nsReadSegmentFun aReader, void* aClosure, uint32_t aCount, uint32_t* _retval) override { return nsFileStreamBase::WriteSegments(aReader, aClosure, aCount, _retval); } protected: virtual ~nsFileStream() = default; }; //////////////////////////////////////////////////////////////////////////////// #endif // nsFileStreams_h__