LCOV - code coverage report
Current view: top level - dom/filehandle - ActorsParent.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 1031 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 162 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* This Source Code Form is subject to the terms of the Mozilla Public
       2             :  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
       3             :  * You can obtain one at http://mozilla.org/MPL/2.0/. */
       4             : 
       5             : #include "ActorsParent.h"
       6             : 
       7             : #include "mozilla/Assertions.h"
       8             : #include "mozilla/Atomics.h"
       9             : #include "mozilla/Attributes.h"
      10             : #include "mozilla/Unused.h"
      11             : #include "mozilla/dom/File.h"
      12             : #include "mozilla/dom/PBackgroundFileHandleParent.h"
      13             : #include "mozilla/dom/PBackgroundFileRequestParent.h"
      14             : #include "mozilla/dom/indexedDB/ActorsParent.h"
      15             : #include "mozilla/dom/indexedDB/PBackgroundIDBDatabaseParent.h"
      16             : #include "mozilla/dom/IPCBlobUtils.h"
      17             : #include "mozilla/dom/ipc/PendingIPCBlobParent.h"
      18             : #include "nsAutoPtr.h"
      19             : #include "nsComponentManagerUtils.h"
      20             : #include "nsDebug.h"
      21             : #include "nsError.h"
      22             : #include "nsIEventTarget.h"
      23             : #include "nsIFileStreams.h"
      24             : #include "nsIInputStream.h"
      25             : #include "nsIOutputStream.h"
      26             : #include "nsIRunnable.h"
      27             : #include "nsISeekableStream.h"
      28             : #include "nsIThread.h"
      29             : #include "nsIThreadPool.h"
      30             : #include "nsNetUtil.h"
      31             : #include "nsStreamUtils.h"
      32             : #include "nsStringStream.h"
      33             : #include "nsTArray.h"
      34             : #include "nsThreadPool.h"
      35             : #include "nsThreadUtils.h"
      36             : #include "nsXPCOMCIDInternal.h"
      37             : 
      38             : #define DISABLE_ASSERTS_FOR_FUZZING 0
      39             : 
      40             : #if DISABLE_ASSERTS_FOR_FUZZING
      41             : #define ASSERT_UNLESS_FUZZING(...) do { } while (0)
      42             : #else
      43             : #define ASSERT_UNLESS_FUZZING(...) MOZ_ASSERT(false, __VA_ARGS__)
      44             : #endif
      45             : 
      46             : namespace mozilla {
      47             : namespace dom {
      48             : 
      49             : using namespace mozilla::ipc;
      50             : 
      51             : namespace {
      52             : 
      53             : /******************************************************************************
      54             :  * Constants
      55             :  ******************************************************************************/
      56             : 
      57             : const uint32_t kThreadLimit = 5;
      58             : const uint32_t kIdleThreadLimit = 1;
      59             : const uint32_t kIdleThreadTimeoutMs = 30000;
      60             : 
      61             : const uint32_t kStreamCopyBlockSize = 32768;
      62             : 
      63             : } // namespace
      64             : 
      65             : class FileHandleThreadPool::FileHandleQueue final
      66             :   : public Runnable
      67             : {
      68             :   friend class FileHandleThreadPool;
      69             : 
      70             :   RefPtr<FileHandleThreadPool> mOwningFileHandleThreadPool;
      71             :   RefPtr<FileHandle> mFileHandle;
      72             :   nsTArray<RefPtr<FileHandleOp>> mQueue;
      73             :   RefPtr<FileHandleOp> mCurrentOp;
      74             :   bool mShouldFinish;
      75             : 
      76             : public:
      77             :   explicit
      78             :   FileHandleQueue(FileHandleThreadPool* aFileHandleThreadPool,
      79             :                   FileHandle* aFileHandle);
      80             : 
      81             :   void
      82             :   Enqueue(FileHandleOp* aFileHandleOp);
      83             : 
      84             :   void
      85             :   Finish();
      86             : 
      87             :   void
      88             :   ProcessQueue();
      89             : 
      90             : private:
      91           0 :   ~FileHandleQueue() {}
      92             : 
      93             :   NS_DECL_NSIRUNNABLE
      94             : };
      95             : 
      96           0 : struct FileHandleThreadPool::DelayedEnqueueInfo
      97             : {
      98             :   RefPtr<FileHandle> mFileHandle;
      99             :   RefPtr<FileHandleOp> mFileHandleOp;
     100             :   bool mFinish;
     101             : };
     102             : 
     103           0 : class FileHandleThreadPool::DirectoryInfo
     104             : {
     105             :   friend class FileHandleThreadPool;
     106             : 
     107             :   RefPtr<FileHandleThreadPool> mOwningFileHandleThreadPool;
     108             :   nsTArray<RefPtr<FileHandleQueue>> mFileHandleQueues;
     109             :   nsTArray<DelayedEnqueueInfo> mDelayedEnqueueInfos;
     110             :   nsTHashtable<nsStringHashKey> mFilesReading;
     111             :   nsTHashtable<nsStringHashKey> mFilesWriting;
     112             : 
     113             : public:
     114             :   FileHandleQueue*
     115             :   CreateFileHandleQueue(FileHandle* aFileHandle);
     116             : 
     117             :   FileHandleQueue*
     118             :   GetFileHandleQueue(FileHandle* aFileHandle);
     119             : 
     120             :   void
     121             :   RemoveFileHandleQueue(FileHandle* aFileHandle);
     122             : 
     123             :   bool
     124           0 :   HasRunningFileHandles()
     125             :   {
     126           0 :     return !mFileHandleQueues.IsEmpty();
     127             :   }
     128             : 
     129             :   DelayedEnqueueInfo*
     130             :   CreateDelayedEnqueueInfo(FileHandle* aFileHandle,
     131             :                            FileHandleOp* aFileHandleOp,
     132             :                            bool aFinish);
     133             : 
     134             :   void
     135           0 :   LockFileForReading(const nsAString& aFileName)
     136             :   {
     137           0 :     mFilesReading.PutEntry(aFileName);
     138           0 :   }
     139             : 
     140             :   void
     141           0 :   LockFileForWriting(const nsAString& aFileName)
     142             :   {
     143           0 :     mFilesWriting.PutEntry(aFileName);
     144           0 :   }
     145             : 
     146             :   bool
     147           0 :   IsFileLockedForReading(const nsAString& aFileName)
     148             :   {
     149           0 :     return mFilesReading.Contains(aFileName);
     150             :   }
     151             : 
     152             :   bool
     153           0 :   IsFileLockedForWriting(const nsAString& aFileName)
     154             :   {
     155           0 :     return mFilesWriting.Contains(aFileName);
     156             :   }
     157             : 
     158             : private:
     159           0 :   explicit DirectoryInfo(FileHandleThreadPool* aFileHandleThreadPool)
     160           0 :     : mOwningFileHandleThreadPool(aFileHandleThreadPool)
     161           0 :   { }
     162             : };
     163             : 
     164             : struct FileHandleThreadPool::StoragesCompleteCallback final
     165             : {
     166             :   friend class nsAutoPtr<StoragesCompleteCallback>;
     167             : 
     168             :   nsTArray<nsCString> mDirectoryIds;
     169             :   nsCOMPtr<nsIRunnable> mCallback;
     170             : 
     171             :   StoragesCompleteCallback(nsTArray<nsCString>&& aDatabaseIds,
     172             :                            nsIRunnable* aCallback);
     173             : 
     174             : private:
     175             :   ~StoragesCompleteCallback();
     176             : };
     177             : 
     178             : /******************************************************************************
     179             :  * Actor class declarations
     180             :  ******************************************************************************/
     181             : 
     182             : class FileHandle
     183             :   : public PBackgroundFileHandleParent
     184             : {
     185             :   friend class BackgroundMutableFileParentBase;
     186             : 
     187             :   class FinishOp;
     188             : 
     189             :   RefPtr<BackgroundMutableFileParentBase> mMutableFile;
     190             :   nsCOMPtr<nsISupports> mStream;
     191             :   uint64_t mActiveRequestCount;
     192             :   FileHandleStorage mStorage;
     193             :   Atomic<bool> mInvalidatedOnAnyThread;
     194             :   FileMode mMode;
     195             :   bool mHasBeenActive;
     196             :   bool mActorDestroyed;
     197             :   bool mInvalidated;
     198             :   bool mAborted;
     199             :   bool mFinishOrAbortReceived;
     200             :   bool mFinishedOrAborted;
     201             :   bool mForceAborted;
     202             : 
     203             : #ifdef DEBUG
     204             :   nsCOMPtr<nsIEventTarget> mThreadPoolEventTarget;
     205             : #endif
     206             : 
     207             : public:
     208             :   void
     209             :   AssertIsOnThreadPool() const;
     210             : 
     211             :   bool
     212           0 :   IsActorDestroyed() const
     213             :   {
     214           0 :     AssertIsOnBackgroundThread();
     215             : 
     216           0 :     return mActorDestroyed;
     217             :   }
     218             : 
     219             :   // Must be called on the background thread.
     220             :   bool
     221           0 :   IsInvalidated() const
     222             :   {
     223           0 :     MOZ_ASSERT(IsOnBackgroundThread(), "Use IsInvalidatedOnAnyThread()");
     224           0 :     MOZ_ASSERT_IF(mInvalidated, mAborted);
     225             : 
     226           0 :     return mInvalidated;
     227             :   }
     228             : 
     229             :   // May be called on any thread, but is more expensive than IsInvalidated().
     230             :   bool
     231           0 :   IsInvalidatedOnAnyThread() const
     232             :   {
     233           0 :     return mInvalidatedOnAnyThread;
     234             :   }
     235             : 
     236             :   void
     237           0 :   SetActive()
     238             :   {
     239           0 :     AssertIsOnBackgroundThread();
     240             : 
     241           0 :     mHasBeenActive = true;
     242           0 :   }
     243             : 
     244           0 :   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(mozilla::dom::FileHandle)
     245             : 
     246             :   nsresult
     247             :   GetOrCreateStream(nsISupports** aStream);
     248             : 
     249             :   void
     250             :   Abort(bool aForce);
     251             : 
     252             :   FileHandleStorage
     253           0 :   Storage() const
     254             :   {
     255           0 :     return mStorage;
     256             :   }
     257             : 
     258             :   FileMode
     259           0 :   Mode() const
     260             :   {
     261           0 :     return mMode;
     262             :   }
     263             : 
     264             :   BackgroundMutableFileParentBase*
     265           0 :   GetMutableFile() const
     266             :   {
     267           0 :     AssertIsOnBackgroundThread();
     268           0 :     MOZ_ASSERT(mMutableFile);
     269             : 
     270           0 :     return mMutableFile;
     271             :   }
     272             : 
     273             :   bool
     274           0 :   IsAborted() const
     275             :   {
     276           0 :     AssertIsOnBackgroundThread();
     277             : 
     278           0 :     return mAborted;
     279             :   }
     280             : 
     281             :   PBackgroundParent*
     282           0 :   GetBackgroundParent() const
     283             :   {
     284           0 :     AssertIsOnBackgroundThread();
     285           0 :     MOZ_ASSERT(!IsActorDestroyed());
     286             : 
     287           0 :     return GetMutableFile()->GetBackgroundParent();
     288             :   }
     289             : 
     290             :   void
     291             :   NoteActiveRequest();
     292             : 
     293             :   void
     294             :   NoteFinishedRequest();
     295             : 
     296             :   void
     297             :   Invalidate();
     298             : 
     299             : private:
     300             :   // This constructor is only called by BackgroundMutableFileParentBase.
     301             :   FileHandle(BackgroundMutableFileParentBase* aMutableFile,
     302             :              FileMode aMode);
     303             : 
     304             :   // Reference counted.
     305             :   ~FileHandle();
     306             : 
     307             :   void
     308           0 :   MaybeFinishOrAbort()
     309             :   {
     310           0 :     AssertIsOnBackgroundThread();
     311             : 
     312             :     // If we've already finished or aborted then there's nothing else to do.
     313           0 :     if (mFinishedOrAborted) {
     314           0 :       return;
     315             :     }
     316             : 
     317             :     // If there are active requests then we have to wait for those requests to
     318             :     // complete (see NoteFinishedRequest).
     319           0 :     if (mActiveRequestCount) {
     320           0 :       return;
     321             :     }
     322             : 
     323             :     // If we haven't yet received a finish or abort message then there could be
     324             :     // additional requests coming so we should wait unless we're being forced to
     325             :     // abort.
     326           0 :     if (!mFinishOrAbortReceived && !mForceAborted) {
     327           0 :       return;
     328             :     }
     329             : 
     330           0 :     FinishOrAbort();
     331             :   }
     332             : 
     333             :   void
     334             :   SendCompleteNotification(bool aAborted);
     335             : 
     336             :   bool
     337             :   VerifyRequestParams(const FileRequestParams& aParams) const;
     338             : 
     339             :   bool
     340             :   VerifyRequestData(const FileRequestData& aData) const;
     341             : 
     342             :   void
     343             :   FinishOrAbort();
     344             : 
     345             :   // IPDL methods are only called by IPDL.
     346             :   virtual void
     347             :   ActorDestroy(ActorDestroyReason aWhy) override;
     348             : 
     349             :   virtual mozilla::ipc::IPCResult
     350             :   RecvDeleteMe() override;
     351             : 
     352             :   virtual mozilla::ipc::IPCResult
     353             :   RecvFinish() override;
     354             : 
     355             :   virtual mozilla::ipc::IPCResult
     356             :   RecvAbort() override;
     357             : 
     358             :   virtual PBackgroundFileRequestParent*
     359             :   AllocPBackgroundFileRequestParent(const FileRequestParams& aParams) override;
     360             : 
     361             :   virtual mozilla::ipc::IPCResult
     362             :   RecvPBackgroundFileRequestConstructor(PBackgroundFileRequestParent* aActor,
     363             :                                         const FileRequestParams& aParams)
     364             :                                         override;
     365             : 
     366             :   virtual bool
     367             :   DeallocPBackgroundFileRequestParent(PBackgroundFileRequestParent* aActor)
     368             :                                       override;
     369             : };
     370             : 
     371             : class FileHandleOp
     372             : {
     373             : protected:
     374             :   nsCOMPtr<nsIEventTarget> mOwningEventTarget;
     375             :   RefPtr<FileHandle> mFileHandle;
     376             : 
     377             : public:
     378           0 :   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(FileHandleOp)
     379             : 
     380             :   void
     381           0 :   AssertIsOnOwningThread() const
     382             :   {
     383           0 :     AssertIsOnBackgroundThread();
     384           0 :     MOZ_ASSERT(mOwningEventTarget);
     385           0 :     DebugOnly<bool> current;
     386           0 :     MOZ_ASSERT(NS_SUCCEEDED(mOwningEventTarget->IsOnCurrentThread(&current)));
     387           0 :     MOZ_ASSERT(current);
     388           0 :   }
     389             : 
     390             :   nsIEventTarget*
     391           0 :   OwningThread() const
     392             :   {
     393           0 :     return mOwningEventTarget;
     394             :   }
     395             : 
     396             :   void
     397           0 :   AssertIsOnThreadPool() const
     398             :   {
     399           0 :     MOZ_ASSERT(mFileHandle);
     400           0 :     mFileHandle->AssertIsOnThreadPool();
     401           0 :   }
     402             : 
     403             :   void
     404             :   Enqueue();
     405             : 
     406             :   virtual void
     407             :   RunOnThreadPool() = 0;
     408             : 
     409             :   virtual void
     410             :   RunOnOwningThread() = 0;
     411             : 
     412             : protected:
     413           0 :   FileHandleOp(FileHandle* aFileHandle)
     414           0 :     : mOwningEventTarget(GetCurrentThreadSerialEventTarget())
     415           0 :     , mFileHandle(aFileHandle)
     416             :   {
     417           0 :     AssertIsOnOwningThread();
     418           0 :     MOZ_ASSERT(aFileHandle);
     419           0 :   }
     420             : 
     421             :   virtual
     422           0 :   ~FileHandleOp()
     423           0 :   { }
     424             : };
     425             : 
     426             : class FileHandle::FinishOp
     427             :   : public FileHandleOp
     428             : {
     429             :   friend class FileHandle;
     430             : 
     431             :   bool mAborted;
     432             : 
     433             : private:
     434           0 :   FinishOp(FileHandle* aFileHandle,
     435             :            bool aAborted)
     436           0 :     : FileHandleOp(aFileHandle)
     437           0 :     , mAborted(aAborted)
     438             :   {
     439           0 :     MOZ_ASSERT(aFileHandle);
     440           0 :   }
     441             : 
     442           0 :   ~FinishOp()
     443           0 :   { }
     444             : 
     445             :   virtual void
     446             :   RunOnThreadPool() override;
     447             : 
     448             :   virtual void
     449             :   RunOnOwningThread() override;
     450             : };
     451             : 
     452             : class NormalFileHandleOp
     453             :   : public FileHandleOp
     454             :   , public PBackgroundFileRequestParent
     455             : {
     456             :   nsresult mResultCode;
     457             :   Atomic<bool> mOperationMayProceed;
     458             :   bool mActorDestroyed;
     459             :   const bool mFileHandleIsAborted;
     460             : 
     461             : #ifdef DEBUG
     462             :   bool mResponseSent;
     463             : #endif
     464             : 
     465             : protected:
     466             :   nsCOMPtr<nsISupports> mFileStream;
     467             : 
     468             : public:
     469             :   void
     470           0 :   NoteActorDestroyed()
     471             :   {
     472           0 :     AssertIsOnOwningThread();
     473             : 
     474           0 :     mActorDestroyed = true;
     475           0 :     mOperationMayProceed = false;
     476           0 :   }
     477             : 
     478             :   bool
     479           0 :   IsActorDestroyed() const
     480             :   {
     481           0 :     AssertIsOnOwningThread();
     482             : 
     483           0 :     return mActorDestroyed;
     484             :   }
     485             : 
     486             :   // May be called on any thread, but you should call IsActorDestroyed() if
     487             :   // you know you're on the background thread because it is slightly faster.
     488             :   bool
     489           0 :   OperationMayProceed() const
     490             :   {
     491           0 :     return mOperationMayProceed;
     492             :   }
     493             : 
     494             :   // May be overridden by subclasses if they need to perform work on the
     495             :   // background thread before being enqueued. Returning false will kill the
     496             :   // child actors and prevent enqueue.
     497             :   virtual bool
     498             :   Init(FileHandle* aFileHandle);
     499             : 
     500             :   // This callback will be called on the background thread before releasing the
     501             :   // final reference to this request object. Subclasses may perform any
     502             :   // additional cleanup here but must always call the base class implementation.
     503             :   virtual void
     504             :   Cleanup();
     505             : 
     506             : protected:
     507           0 :   NormalFileHandleOp(FileHandle* aFileHandle)
     508           0 :     : FileHandleOp(aFileHandle)
     509             :     , mResultCode(NS_OK)
     510             :     , mOperationMayProceed(true)
     511             :     , mActorDestroyed(false)
     512           0 :     , mFileHandleIsAborted(aFileHandle->IsAborted())
     513             : #ifdef DEBUG
     514           0 :     , mResponseSent(false)
     515             : #endif
     516             :   {
     517           0 :     MOZ_ASSERT(aFileHandle);
     518           0 :   }
     519             : 
     520             :   virtual
     521             :   ~NormalFileHandleOp();
     522             : 
     523             :   // Must be overridden in subclasses. Called on the target thread to allow the
     524             :   // subclass to perform necessary file operations. A successful return value
     525             :   // will trigger a SendSuccessResult callback on the background thread while
     526             :   // a failure value will trigger a SendFailureResult callback.
     527             :   virtual nsresult
     528             :   DoFileWork(FileHandle* aFileHandle) = 0;
     529             : 
     530             :   // Subclasses use this override to set the IPDL response value.
     531             :   virtual void
     532             :   GetResponse(FileRequestResponse& aResponse) = 0;
     533             : 
     534             : private:
     535             :   nsresult
     536             :   SendSuccessResult();
     537             : 
     538             :   bool
     539             :   SendFailureResult(nsresult aResultCode);
     540             : 
     541             :   virtual void
     542             :   RunOnThreadPool() override;
     543             : 
     544             :   virtual void
     545             :   RunOnOwningThread() override;
     546             : 
     547             :   // IPDL methods.
     548             :   virtual void
     549             :   ActorDestroy(ActorDestroyReason aWhy) override;
     550             : };
     551             : 
     552           0 : class CopyFileHandleOp
     553             :   : public NormalFileHandleOp
     554             : {
     555             :   class ProgressRunnable;
     556             : 
     557             : protected:
     558             :   nsCOMPtr<nsISupports> mBufferStream;
     559             : 
     560             :   uint64_t mOffset;
     561             :   uint64_t mSize;
     562             : 
     563             :   bool mRead;
     564             : 
     565             : protected:
     566           0 :   CopyFileHandleOp(FileHandle* aFileHandle)
     567           0 :     : NormalFileHandleOp(aFileHandle)
     568             :     , mOffset(0)
     569             :     , mSize(0)
     570           0 :     , mRead(true)
     571           0 :   { }
     572             : 
     573             :   virtual nsresult
     574             :   DoFileWork(FileHandle* aFileHandle) override;
     575             : 
     576             :   virtual void
     577             :   Cleanup() override;
     578             : };
     579             : 
     580             : class CopyFileHandleOp::ProgressRunnable final
     581             :   : public Runnable
     582             : {
     583             :   RefPtr<CopyFileHandleOp> mCopyFileHandleOp;
     584             :   uint64_t mProgress;
     585             :   uint64_t mProgressMax;
     586             : 
     587             : public:
     588           0 :   ProgressRunnable(CopyFileHandleOp* aCopyFileHandleOp,
     589             :                    uint64_t aProgress,
     590             :                    uint64_t aProgressMax)
     591           0 :     : Runnable("dom::CopyFileHandleOp::ProgressRunnable")
     592             :     , mCopyFileHandleOp(aCopyFileHandleOp)
     593             :     , mProgress(aProgress)
     594           0 :     , mProgressMax(aProgressMax)
     595           0 :   { }
     596             : 
     597             : private:
     598           0 :   ~ProgressRunnable() {}
     599             : 
     600             :   NS_DECL_NSIRUNNABLE
     601             : };
     602             : 
     603             : class GetMetadataOp
     604             :   : public NormalFileHandleOp
     605             : {
     606             :   friend class FileHandle;
     607             : 
     608             :   const FileRequestGetMetadataParams mParams;
     609             : 
     610             : protected:
     611             :   FileRequestMetadata mMetadata;
     612             : 
     613             : protected:
     614             :   // Only created by FileHandle.
     615             :   GetMetadataOp(FileHandle* aFileHandle,
     616             :                 const FileRequestParams& aParams);
     617             : 
     618           0 :   ~GetMetadataOp()
     619           0 :   { }
     620             : 
     621             :   virtual nsresult
     622             :   DoFileWork(FileHandle* aFileHandle) override;
     623             : 
     624             :   virtual void
     625             :   GetResponse(FileRequestResponse& aResponse) override;
     626             : };
     627             : 
     628             : class ReadOp final
     629             :   : public CopyFileHandleOp
     630             : {
     631             :   friend class FileHandle;
     632             : 
     633             :   class MemoryOutputStream;
     634             : 
     635             :   const FileRequestReadParams mParams;
     636             : 
     637             : private:
     638             :   // Only created by FileHandle.
     639             :   ReadOp(FileHandle* aFileHandle,
     640             :          const FileRequestParams& aParams);
     641             : 
     642           0 :   ~ReadOp()
     643           0 :   { }
     644             : 
     645             :   virtual bool
     646             :   Init(FileHandle* aFileHandle) override;
     647             : 
     648             :   virtual void
     649             :   GetResponse(FileRequestResponse& aResponse) override;
     650             : };
     651             : 
     652             : class ReadOp::MemoryOutputStream final
     653             :   : public nsIOutputStream
     654             : {
     655             :   nsCString mData;
     656             :   uint64_t mOffset;
     657             : 
     658             : public:
     659             :   static already_AddRefed<MemoryOutputStream>
     660             :   Create(uint64_t aSize);
     661             : 
     662             :   const nsCString&
     663           0 :   Data() const
     664             :   {
     665           0 :     return mData;
     666             :   }
     667             : 
     668             : private:
     669           0 :   MemoryOutputStream()
     670           0 :   : mOffset(0)
     671           0 :   { }
     672             : 
     673           0 :   virtual ~MemoryOutputStream()
     674           0 :   { }
     675             : 
     676             :   NS_DECL_THREADSAFE_ISUPPORTS
     677             :   NS_DECL_NSIOUTPUTSTREAM
     678             : };
     679             : 
     680             : class WriteOp final
     681             :   : public CopyFileHandleOp
     682             : {
     683             :   friend class FileHandle;
     684             : 
     685             :   const FileRequestWriteParams mParams;
     686             : 
     687             : private:
     688             :   // Only created by FileHandle.
     689             :   WriteOp(FileHandle* aFileHandle,
     690             :           const FileRequestParams& aParams);
     691             : 
     692           0 :   ~WriteOp()
     693           0 :   { }
     694             : 
     695             :   virtual bool
     696             :   Init(FileHandle* aFileHandle) override;
     697             : 
     698             :   virtual void
     699             :   GetResponse(FileRequestResponse& aResponse) override;
     700             : };
     701             : 
     702             : class TruncateOp final
     703             :   : public NormalFileHandleOp
     704             : {
     705             :   friend class FileHandle;
     706             : 
     707             :   const FileRequestTruncateParams mParams;
     708             : 
     709             : private:
     710             :   // Only created by FileHandle.
     711             :   TruncateOp(FileHandle* aFileHandle,
     712             :                         const FileRequestParams& aParams);
     713             : 
     714           0 :   ~TruncateOp()
     715           0 :   { }
     716             : 
     717             :   virtual nsresult
     718             :   DoFileWork(FileHandle* aFileHandle) override;
     719             : 
     720             :   virtual void
     721             :   GetResponse(FileRequestResponse& aResponse) override;
     722             : };
     723             : 
     724             : class FlushOp final
     725             :   : public NormalFileHandleOp
     726             : {
     727             :   friend class FileHandle;
     728             : 
     729             :   const FileRequestFlushParams mParams;
     730             : 
     731             : private:
     732             :   // Only created by FileHandle.
     733             :   FlushOp(FileHandle* aFileHandle,
     734             :           const FileRequestParams& aParams);
     735             : 
     736           0 :   ~FlushOp()
     737           0 :   { }
     738             : 
     739             :   virtual nsresult
     740             :   DoFileWork(FileHandle* aFileHandle) override;
     741             : 
     742             :   virtual void
     743             :   GetResponse(FileRequestResponse& aResponse) override;
     744             : };
     745             : 
     746             : class GetFileOp final
     747             :   : public GetMetadataOp
     748             : {
     749             :   friend class FileHandle;
     750             : 
     751             :   PBackgroundParent* mBackgroundParent;
     752             : 
     753             : private:
     754             :   // Only created by FileHandle.
     755             :   GetFileOp(FileHandle* aFileHandle,
     756             :             const FileRequestParams& aParams);
     757             : 
     758           0 :   ~GetFileOp()
     759           0 :   { }
     760             : 
     761             :   virtual void
     762             :   GetResponse(FileRequestResponse& aResponse) override;
     763             : };
     764             : 
     765             : namespace {
     766             : 
     767             : /*******************************************************************************
     768             :  * Helper Functions
     769             :  ******************************************************************************/
     770             : 
     771             : FileHandleThreadPool*
     772           0 : GetFileHandleThreadPoolFor(FileHandleStorage aStorage)
     773             : {
     774           0 :   switch (aStorage) {
     775             :     case FILE_HANDLE_STORAGE_IDB:
     776           0 :       return mozilla::dom::indexedDB::GetFileHandleThreadPool();
     777             : 
     778             :     default:
     779           0 :       MOZ_CRASH("Bad file handle storage value!");
     780             :   }
     781             : }
     782             : 
     783             : } // namespace
     784             : 
     785             : /*******************************************************************************
     786             :  * FileHandleThreadPool implementation
     787             :  ******************************************************************************/
     788             : 
     789           0 : FileHandleThreadPool::FileHandleThreadPool()
     790           0 :   : mOwningEventTarget(GetCurrentThreadSerialEventTarget())
     791             :   , mShutdownRequested(false)
     792           0 :   , mShutdownComplete(false)
     793             : {
     794           0 :   AssertIsOnBackgroundThread();
     795           0 :   MOZ_ASSERT(mOwningEventTarget);
     796           0 :   AssertIsOnOwningThread();
     797           0 : }
     798             : 
     799           0 : FileHandleThreadPool::~FileHandleThreadPool()
     800             : {
     801           0 :   AssertIsOnOwningThread();
     802           0 :   MOZ_ASSERT(!mDirectoryInfos.Count());
     803           0 :   MOZ_ASSERT(mCompleteCallbacks.IsEmpty());
     804           0 :   MOZ_ASSERT(mShutdownRequested);
     805           0 :   MOZ_ASSERT(mShutdownComplete);
     806           0 : }
     807             : 
     808             : // static
     809             : already_AddRefed<FileHandleThreadPool>
     810           0 : FileHandleThreadPool::Create()
     811             : {
     812           0 :   AssertIsOnBackgroundThread();
     813             : 
     814             :   RefPtr<FileHandleThreadPool> fileHandleThreadPool =
     815           0 :     new FileHandleThreadPool();
     816           0 :   fileHandleThreadPool->AssertIsOnOwningThread();
     817             : 
     818           0 :   if (NS_WARN_IF(NS_FAILED(fileHandleThreadPool->Init()))) {
     819           0 :     return nullptr;
     820             :   }
     821             : 
     822           0 :   return fileHandleThreadPool.forget();
     823             : }
     824             : 
     825             : #ifdef DEBUG
     826             : 
     827             : void
     828           0 : FileHandleThreadPool::AssertIsOnOwningThread() const
     829             : {
     830           0 :   MOZ_ASSERT(mOwningEventTarget);
     831             : 
     832             :   bool current;
     833           0 :   MOZ_ALWAYS_SUCCEEDS(mOwningEventTarget->IsOnCurrentThread(&current));
     834           0 :   MOZ_ASSERT(current);
     835           0 : }
     836             : 
     837             : nsIEventTarget*
     838           0 : FileHandleThreadPool::GetThreadPoolEventTarget() const
     839             : {
     840           0 :   AssertIsOnOwningThread();
     841           0 :   MOZ_ASSERT(mThreadPool);
     842             : 
     843           0 :   return mThreadPool;
     844             : }
     845             : 
     846             : #endif // DEBUG
     847             : 
     848             : void
     849           0 : FileHandleThreadPool::Enqueue(FileHandle* aFileHandle,
     850             :                               FileHandleOp* aFileHandleOp,
     851             :                               bool aFinish)
     852             : {
     853           0 :   AssertIsOnOwningThread();
     854           0 :   MOZ_ASSERT(aFileHandle);
     855           0 :   MOZ_ASSERT(!mShutdownRequested);
     856             : 
     857           0 :   BackgroundMutableFileParentBase* mutableFile = aFileHandle->GetMutableFile();
     858             : 
     859           0 :   const nsACString& directoryId = mutableFile->DirectoryId();
     860           0 :   const nsAString& fileName = mutableFile->FileName();
     861           0 :   bool modeIsWrite = aFileHandle->Mode() == FileMode::Readwrite;
     862             : 
     863             :   DirectoryInfo* directoryInfo;
     864           0 :   if (!mDirectoryInfos.Get(directoryId, &directoryInfo)) {
     865           0 :     nsAutoPtr<DirectoryInfo> newDirectoryInfo(new DirectoryInfo(this));
     866             : 
     867           0 :     mDirectoryInfos.Put(directoryId, newDirectoryInfo);
     868             : 
     869           0 :     directoryInfo = newDirectoryInfo.forget();
     870             :   }
     871             : 
     872             :   FileHandleQueue* existingFileHandleQueue =
     873           0 :     directoryInfo->GetFileHandleQueue(aFileHandle);
     874             : 
     875           0 :   if (existingFileHandleQueue) {
     876           0 :     existingFileHandleQueue->Enqueue(aFileHandleOp);
     877           0 :     if (aFinish) {
     878           0 :       existingFileHandleQueue->Finish();
     879             :     }
     880           0 :     return;
     881             :   }
     882             : 
     883           0 :   bool lockedForReading = directoryInfo->IsFileLockedForReading(fileName);
     884           0 :   bool lockedForWriting = directoryInfo->IsFileLockedForWriting(fileName);
     885             : 
     886           0 :   if (modeIsWrite) {
     887           0 :     if (!lockedForWriting) {
     888           0 :       directoryInfo->LockFileForWriting(fileName);
     889             :     }
     890             :   }
     891             :   else {
     892           0 :     if (!lockedForReading) {
     893           0 :       directoryInfo->LockFileForReading(fileName);
     894             :     }
     895             :   }
     896             : 
     897           0 :   if (lockedForWriting || (lockedForReading && modeIsWrite)) {
     898           0 :     directoryInfo->CreateDelayedEnqueueInfo(aFileHandle,
     899             :                                             aFileHandleOp,
     900           0 :                                             aFinish);
     901             :   }
     902             :   else {
     903             :     FileHandleQueue* fileHandleQueue =
     904           0 :       directoryInfo->CreateFileHandleQueue(aFileHandle);
     905             : 
     906           0 :     if (aFileHandleOp) {
     907           0 :       fileHandleQueue->Enqueue(aFileHandleOp);
     908           0 :       if (aFinish) {
     909           0 :         fileHandleQueue->Finish();
     910             :       }
     911             :     }
     912             :   }
     913             : }
     914             : 
     915             : void
     916           0 : FileHandleThreadPool::WaitForDirectoriesToComplete(
     917             :                                              nsTArray<nsCString>&& aDirectoryIds,
     918             :                                              nsIRunnable* aCallback)
     919             : {
     920           0 :   AssertIsOnOwningThread();
     921           0 :   MOZ_ASSERT(!aDirectoryIds.IsEmpty());
     922           0 :   MOZ_ASSERT(aCallback);
     923             : 
     924             :   nsAutoPtr<StoragesCompleteCallback> callback(
     925           0 :     new StoragesCompleteCallback(Move(aDirectoryIds), aCallback));
     926             : 
     927           0 :   if (!MaybeFireCallback(callback)) {
     928           0 :     mCompleteCallbacks.AppendElement(callback.forget());
     929             :   }
     930           0 : }
     931             : 
     932             : void
     933           0 : FileHandleThreadPool::Shutdown()
     934             : {
     935           0 :   AssertIsOnOwningThread();
     936           0 :   MOZ_ASSERT(!mShutdownRequested);
     937           0 :   MOZ_ASSERT(!mShutdownComplete);
     938             : 
     939           0 :   mShutdownRequested = true;
     940             : 
     941           0 :   if (!mThreadPool) {
     942           0 :     MOZ_ASSERT(!mDirectoryInfos.Count());
     943           0 :     MOZ_ASSERT(mCompleteCallbacks.IsEmpty());
     944             : 
     945           0 :     mShutdownComplete = true;
     946           0 :     return;
     947             :   }
     948             : 
     949           0 :   if (!mDirectoryInfos.Count()) {
     950           0 :     Cleanup();
     951             : 
     952           0 :     MOZ_ASSERT(mShutdownComplete);
     953           0 :     return;
     954             :   }
     955             : 
     956           0 :   MOZ_ALWAYS_TRUE(SpinEventLoopUntil([&]() { return mShutdownComplete; }));
     957             : }
     958             : 
     959             : nsresult
     960           0 : FileHandleThreadPool::Init()
     961             : {
     962           0 :   AssertIsOnOwningThread();
     963             : 
     964           0 :   mThreadPool = new nsThreadPool();
     965             : 
     966           0 :   nsresult rv = mThreadPool->SetName(NS_LITERAL_CSTRING("FileHandles"));
     967           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
     968           0 :     return rv;
     969             :   }
     970             : 
     971           0 :   rv = mThreadPool->SetThreadLimit(kThreadLimit);
     972           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
     973           0 :     return rv;
     974             :   }
     975             : 
     976           0 :   rv = mThreadPool->SetIdleThreadLimit(kIdleThreadLimit);
     977           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
     978           0 :     return rv;
     979             :   }
     980             : 
     981           0 :   rv = mThreadPool->SetIdleThreadTimeout(kIdleThreadTimeoutMs);
     982           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
     983           0 :     return rv;
     984             :   }
     985             : 
     986           0 :   return NS_OK;
     987             : }
     988             : 
     989             : void
     990           0 : FileHandleThreadPool::Cleanup()
     991             : {
     992           0 :   AssertIsOnOwningThread();
     993           0 :   MOZ_ASSERT(mThreadPool);
     994           0 :   MOZ_ASSERT(mShutdownRequested);
     995           0 :   MOZ_ASSERT(!mShutdownComplete);
     996           0 :   MOZ_ASSERT(!mDirectoryInfos.Count());
     997             : 
     998           0 :   MOZ_ALWAYS_SUCCEEDS(mThreadPool->Shutdown());
     999             : 
    1000           0 :   if (!mCompleteCallbacks.IsEmpty()) {
    1001             :     // Run all callbacks manually now.
    1002           0 :     for (uint32_t count = mCompleteCallbacks.Length(), index = 0;
    1003           0 :          index < count;
    1004             :          index++) {
    1005             :       nsAutoPtr<StoragesCompleteCallback> completeCallback(
    1006           0 :         mCompleteCallbacks[index].forget());
    1007           0 :       MOZ_ASSERT(completeCallback);
    1008           0 :       MOZ_ASSERT(completeCallback->mCallback);
    1009             : 
    1010           0 :       Unused << completeCallback->mCallback->Run();
    1011             :     }
    1012             : 
    1013           0 :     mCompleteCallbacks.Clear();
    1014             : 
    1015             :     // And make sure they get processed.
    1016           0 :     nsIThread* currentThread = NS_GetCurrentThread();
    1017           0 :     MOZ_ASSERT(currentThread);
    1018             : 
    1019           0 :     MOZ_ALWAYS_SUCCEEDS(NS_ProcessPendingEvents(currentThread));
    1020             :   }
    1021             : 
    1022           0 :   mShutdownComplete = true;
    1023           0 : }
    1024             : 
    1025             : void
    1026           0 : FileHandleThreadPool::FinishFileHandle(FileHandle* aFileHandle)
    1027             : {
    1028           0 :   AssertIsOnOwningThread();
    1029           0 :   MOZ_ASSERT(aFileHandle);
    1030             : 
    1031           0 :   BackgroundMutableFileParentBase* mutableFile = aFileHandle->GetMutableFile();
    1032           0 :   const nsACString& directoryId = mutableFile->DirectoryId();
    1033             : 
    1034             :   DirectoryInfo* directoryInfo;
    1035           0 :   if (!mDirectoryInfos.Get(directoryId, &directoryInfo)) {
    1036           0 :     NS_ERROR("We don't know anyting about this directory?!");
    1037           0 :     return;
    1038             :   }
    1039             : 
    1040           0 :   directoryInfo->RemoveFileHandleQueue(aFileHandle);
    1041             : 
    1042           0 :   if (!directoryInfo->HasRunningFileHandles()) {
    1043           0 :     mDirectoryInfos.Remove(directoryId);
    1044             : 
    1045             :     // See if we need to fire any complete callbacks.
    1046           0 :     uint32_t index = 0;
    1047           0 :     while (index < mCompleteCallbacks.Length()) {
    1048           0 :       if (MaybeFireCallback(mCompleteCallbacks[index])) {
    1049           0 :         mCompleteCallbacks.RemoveElementAt(index);
    1050             :       }
    1051             :       else {
    1052           0 :         index++;
    1053             :       }
    1054             :     }
    1055             : 
    1056           0 :     if (mShutdownRequested && !mDirectoryInfos.Count()) {
    1057           0 :       Cleanup();
    1058             :     }
    1059             :   }
    1060             : }
    1061             : 
    1062             : bool
    1063           0 : FileHandleThreadPool::MaybeFireCallback(StoragesCompleteCallback* aCallback)
    1064             : {
    1065           0 :   AssertIsOnOwningThread();
    1066           0 :   MOZ_ASSERT(aCallback);
    1067           0 :   MOZ_ASSERT(!aCallback->mDirectoryIds.IsEmpty());
    1068           0 :   MOZ_ASSERT(aCallback->mCallback);
    1069             : 
    1070           0 :   for (uint32_t count = aCallback->mDirectoryIds.Length(), index = 0;
    1071           0 :        index < count;
    1072             :        index++) {
    1073           0 :     const nsCString& directoryId = aCallback->mDirectoryIds[index];
    1074           0 :     MOZ_ASSERT(!directoryId.IsEmpty());
    1075             : 
    1076           0 :     if (mDirectoryInfos.Get(directoryId, nullptr)) {
    1077           0 :       return false;
    1078             :     }
    1079             :   }
    1080             : 
    1081           0 :   aCallback->mCallback->Run();
    1082           0 :   return true;
    1083             : }
    1084             : 
    1085           0 : FileHandleThreadPool::FileHandleQueue::FileHandleQueue(
    1086             :   FileHandleThreadPool* aFileHandleThreadPool,
    1087           0 :   FileHandle* aFileHandle)
    1088             :   : Runnable("dom::FileHandleThreadPool::FileHandleQueue")
    1089             :   , mOwningFileHandleThreadPool(aFileHandleThreadPool)
    1090             :   , mFileHandle(aFileHandle)
    1091           0 :   , mShouldFinish(false)
    1092             : {
    1093           0 :   MOZ_ASSERT(aFileHandleThreadPool);
    1094           0 :   aFileHandleThreadPool->AssertIsOnOwningThread();
    1095           0 :   MOZ_ASSERT(aFileHandle);
    1096           0 : }
    1097             : 
    1098             : void
    1099           0 : FileHandleThreadPool::
    1100             : FileHandleQueue::Enqueue(FileHandleOp* aFileHandleOp)
    1101             : {
    1102           0 :   MOZ_ASSERT(!mShouldFinish, "Enqueue called after Finish!");
    1103             : 
    1104           0 :   mQueue.AppendElement(aFileHandleOp);
    1105             : 
    1106           0 :   ProcessQueue();
    1107           0 : }
    1108             : 
    1109             : void
    1110           0 : FileHandleThreadPool::
    1111             : FileHandleQueue::Finish()
    1112             : {
    1113           0 :   MOZ_ASSERT(!mShouldFinish, "Finish called more than once!");
    1114             : 
    1115           0 :   mShouldFinish = true;
    1116           0 : }
    1117             : 
    1118             : void
    1119           0 : FileHandleThreadPool::
    1120             : FileHandleQueue::ProcessQueue()
    1121             : {
    1122           0 :   if (mCurrentOp) {
    1123           0 :     return;
    1124             :   }
    1125             : 
    1126           0 :   if (mQueue.IsEmpty()) {
    1127           0 :     if (mShouldFinish) {
    1128           0 :       mOwningFileHandleThreadPool->FinishFileHandle(mFileHandle);
    1129             : 
    1130             :       // Make sure this is released on this thread.
    1131           0 :       mOwningFileHandleThreadPool = nullptr;
    1132             :     }
    1133             : 
    1134           0 :     return;
    1135             :   }
    1136             : 
    1137           0 :   mCurrentOp = mQueue[0];
    1138           0 :   mQueue.RemoveElementAt(0);
    1139             : 
    1140           0 :   nsCOMPtr<nsIThreadPool> threadPool = mOwningFileHandleThreadPool->mThreadPool;
    1141           0 :   MOZ_ASSERT(threadPool);
    1142             : 
    1143           0 :   MOZ_ALWAYS_SUCCEEDS(threadPool->Dispatch(this, NS_DISPATCH_NORMAL));
    1144             : }
    1145             : 
    1146             : NS_IMETHODIMP
    1147           0 : FileHandleThreadPool::
    1148             : FileHandleQueue::Run()
    1149             : {
    1150           0 :   MOZ_ASSERT(mCurrentOp);
    1151             : 
    1152           0 :   if (IsOnBackgroundThread()) {
    1153           0 :     RefPtr<FileHandleOp> currentOp;
    1154             : 
    1155           0 :     mCurrentOp.swap(currentOp);
    1156           0 :     ProcessQueue();
    1157             : 
    1158           0 :     currentOp->RunOnOwningThread();
    1159             :   } else {
    1160           0 :     mCurrentOp->RunOnThreadPool();
    1161             : 
    1162           0 :     nsCOMPtr<nsIEventTarget> backgroundThread = mCurrentOp->OwningThread();
    1163             : 
    1164           0 :     MOZ_ALWAYS_SUCCEEDS(
    1165             :       backgroundThread->Dispatch(this, NS_DISPATCH_NORMAL));
    1166             :   }
    1167             : 
    1168           0 :   return NS_OK;
    1169             : }
    1170             : 
    1171             : auto
    1172           0 : FileHandleThreadPool::
    1173             : DirectoryInfo::CreateFileHandleQueue(FileHandle* aFileHandle)
    1174             :   -> FileHandleQueue*
    1175             : {
    1176             :   RefPtr<FileHandleQueue>* fileHandleQueue =
    1177           0 :     mFileHandleQueues.AppendElement();
    1178             :   *fileHandleQueue = new FileHandleQueue(mOwningFileHandleThreadPool,
    1179           0 :                                          aFileHandle);
    1180           0 :   return fileHandleQueue->get();
    1181             : }
    1182             : 
    1183             : auto
    1184           0 : FileHandleThreadPool::
    1185             : DirectoryInfo::GetFileHandleQueue(FileHandle* aFileHandle) -> FileHandleQueue*
    1186             : {
    1187           0 :   uint32_t count = mFileHandleQueues.Length();
    1188           0 :   for (uint32_t index = 0; index < count; index++) {
    1189           0 :     RefPtr<FileHandleQueue>& fileHandleQueue = mFileHandleQueues[index];
    1190           0 :     if (fileHandleQueue->mFileHandle == aFileHandle) {
    1191           0 :       return fileHandleQueue;
    1192             :     }
    1193             :   }
    1194           0 :   return nullptr;
    1195             : }
    1196             : 
    1197             : void
    1198           0 : FileHandleThreadPool::
    1199             : DirectoryInfo::RemoveFileHandleQueue(FileHandle* aFileHandle)
    1200             : {
    1201           0 :   for (uint32_t index = 0; index < mDelayedEnqueueInfos.Length(); index++) {
    1202           0 :     if (mDelayedEnqueueInfos[index].mFileHandle == aFileHandle) {
    1203           0 :       MOZ_ASSERT(!mDelayedEnqueueInfos[index].mFileHandleOp, "Should be null!");
    1204           0 :       mDelayedEnqueueInfos.RemoveElementAt(index);
    1205           0 :       return;
    1206             :     }
    1207             :   }
    1208             : 
    1209           0 :   uint32_t fileHandleCount = mFileHandleQueues.Length();
    1210             : 
    1211             :   // We can't just remove entries from lock hash tables, we have to rebuild
    1212             :   // them instead. Multiple FileHandle objects may lock the same file
    1213             :   // (one entry can represent multiple locks).
    1214             : 
    1215           0 :   mFilesReading.Clear();
    1216           0 :   mFilesWriting.Clear();
    1217             : 
    1218           0 :   for (uint32_t index = 0, count = fileHandleCount; index < count; index++) {
    1219           0 :     FileHandle* fileHandle = mFileHandleQueues[index]->mFileHandle;
    1220           0 :     if (fileHandle == aFileHandle) {
    1221           0 :       MOZ_ASSERT(count == fileHandleCount, "More than one match?!");
    1222             : 
    1223           0 :       mFileHandleQueues.RemoveElementAt(index);
    1224           0 :       index--;
    1225           0 :       count--;
    1226             : 
    1227           0 :       continue;
    1228             :     }
    1229             : 
    1230           0 :     const nsAString& fileName = fileHandle->GetMutableFile()->FileName();
    1231             : 
    1232           0 :     if (fileHandle->Mode() == FileMode::Readwrite) {
    1233           0 :       if (!IsFileLockedForWriting(fileName)) {
    1234           0 :         LockFileForWriting(fileName);
    1235             :       }
    1236             :     }
    1237             :     else {
    1238           0 :       if (!IsFileLockedForReading(fileName)) {
    1239           0 :         LockFileForReading(fileName);
    1240             :       }
    1241             :     }
    1242             :   }
    1243             : 
    1244           0 :   MOZ_ASSERT(mFileHandleQueues.Length() == fileHandleCount - 1,
    1245             :              "Didn't find the file handle we were looking for!");
    1246             : 
    1247           0 :   nsTArray<DelayedEnqueueInfo> delayedEnqueueInfos;
    1248           0 :   delayedEnqueueInfos.SwapElements(mDelayedEnqueueInfos);
    1249             : 
    1250           0 :   for (uint32_t index = 0; index < delayedEnqueueInfos.Length(); index++) {
    1251           0 :     DelayedEnqueueInfo& delayedEnqueueInfo = delayedEnqueueInfos[index];
    1252           0 :     mOwningFileHandleThreadPool->Enqueue(delayedEnqueueInfo.mFileHandle,
    1253             :                                          delayedEnqueueInfo.mFileHandleOp,
    1254           0 :                                          delayedEnqueueInfo.mFinish);
    1255             :   }
    1256             : }
    1257             : 
    1258             : auto
    1259           0 : FileHandleThreadPool::
    1260             : DirectoryInfo::CreateDelayedEnqueueInfo(FileHandle* aFileHandle,
    1261             :                                         FileHandleOp* aFileHandleOp,
    1262             :                                         bool aFinish) -> DelayedEnqueueInfo*
    1263             : {
    1264           0 :   DelayedEnqueueInfo* info = mDelayedEnqueueInfos.AppendElement();
    1265           0 :   info->mFileHandle = aFileHandle;
    1266           0 :   info->mFileHandleOp = aFileHandleOp;
    1267           0 :   info->mFinish = aFinish;
    1268           0 :   return info;
    1269             : }
    1270             : 
    1271           0 : FileHandleThreadPool::
    1272             : StoragesCompleteCallback::StoragesCompleteCallback(
    1273             :                                              nsTArray<nsCString>&& aDirectoryIds,
    1274           0 :                                              nsIRunnable* aCallback)
    1275           0 :   : mDirectoryIds(Move(aDirectoryIds))
    1276           0 :   , mCallback(aCallback)
    1277             : {
    1278           0 :   AssertIsOnBackgroundThread();
    1279           0 :   MOZ_ASSERT(!mDirectoryIds.IsEmpty());
    1280           0 :   MOZ_ASSERT(aCallback);
    1281             : 
    1282           0 :   MOZ_COUNT_CTOR(FileHandleThreadPool::StoragesCompleteCallback);
    1283           0 : }
    1284             : 
    1285           0 : FileHandleThreadPool::
    1286           0 : StoragesCompleteCallback::~StoragesCompleteCallback()
    1287             : {
    1288           0 :   AssertIsOnBackgroundThread();
    1289             : 
    1290           0 :   MOZ_COUNT_DTOR(FileHandleThreadPool::StoragesCompleteCallback);
    1291           0 : }
    1292             : 
    1293             : /*******************************************************************************
    1294             :  * BackgroundMutableFileParentBase
    1295             :  ******************************************************************************/
    1296             : 
    1297           0 : BackgroundMutableFileParentBase::BackgroundMutableFileParentBase(
    1298             :                                                  FileHandleStorage aStorage,
    1299             :                                                  const nsACString& aDirectoryId,
    1300             :                                                  const nsAString& aFileName,
    1301           0 :                                                  nsIFile* aFile)
    1302             :   : mDirectoryId(aDirectoryId)
    1303             :   , mFileName(aFileName)
    1304             :   , mStorage(aStorage)
    1305             :   , mInvalidated(false)
    1306             :   , mActorWasAlive(false)
    1307             :   , mActorDestroyed(false)
    1308           0 :   , mFile(aFile)
    1309             : {
    1310           0 :   AssertIsOnBackgroundThread();
    1311           0 :   MOZ_ASSERT(aStorage != FILE_HANDLE_STORAGE_MAX);
    1312           0 :   MOZ_ASSERT(!aDirectoryId.IsEmpty());
    1313           0 :   MOZ_ASSERT(!aFileName.IsEmpty());
    1314           0 :   MOZ_ASSERT(aFile);
    1315           0 : }
    1316             : 
    1317           0 : BackgroundMutableFileParentBase::~BackgroundMutableFileParentBase()
    1318             : {
    1319           0 :   MOZ_ASSERT_IF(mActorWasAlive, mActorDestroyed);
    1320           0 : }
    1321             : 
    1322             : void
    1323           0 : BackgroundMutableFileParentBase::Invalidate()
    1324             : {
    1325           0 :   AssertIsOnBackgroundThread();
    1326             : 
    1327             :   class MOZ_STACK_CLASS Helper final
    1328             :   {
    1329             :   public:
    1330             :     static bool
    1331           0 :     InvalidateFileHandles(nsTHashtable<nsPtrHashKey<FileHandle>>& aTable)
    1332             :     {
    1333           0 :       AssertIsOnBackgroundThread();
    1334             : 
    1335           0 :       const uint32_t count = aTable.Count();
    1336           0 :       if (!count) {
    1337           0 :         return true;
    1338             :       }
    1339             : 
    1340           0 :       FallibleTArray<RefPtr<FileHandle>> fileHandles;
    1341           0 :       if (NS_WARN_IF(!fileHandles.SetCapacity(count, fallible))) {
    1342           0 :         return false;
    1343             :       }
    1344             : 
    1345           0 :       for (auto iter = aTable.Iter(); !iter.Done(); iter.Next()) {
    1346           0 :         if (NS_WARN_IF(!fileHandles.AppendElement(iter.Get()->GetKey(),
    1347             :                                                   fallible))) {
    1348           0 :           return false;
    1349             :         }
    1350             :       }
    1351             : 
    1352           0 :       if (count) {
    1353           0 :         for (uint32_t index = 0; index < count; index++) {
    1354           0 :           RefPtr<FileHandle> fileHandle = fileHandles[index].forget();
    1355           0 :           MOZ_ASSERT(fileHandle);
    1356             : 
    1357           0 :           fileHandle->Invalidate();
    1358             :         }
    1359             :       }
    1360             : 
    1361           0 :       return true;
    1362             :     }
    1363             :   };
    1364             : 
    1365           0 :   if (mInvalidated) {
    1366           0 :     return;
    1367             :   }
    1368             : 
    1369           0 :   mInvalidated = true;
    1370             : 
    1371           0 :   if (!Helper::InvalidateFileHandles(mFileHandles)) {
    1372           0 :     NS_WARNING("Failed to abort all file handles!");
    1373             :   }
    1374             : }
    1375             : 
    1376             : bool
    1377           0 : BackgroundMutableFileParentBase::RegisterFileHandle(FileHandle* aFileHandle)
    1378             : {
    1379           0 :   AssertIsOnBackgroundThread();
    1380           0 :   MOZ_ASSERT(aFileHandle);
    1381           0 :   MOZ_ASSERT(!mFileHandles.GetEntry(aFileHandle));
    1382           0 :   MOZ_ASSERT(!mInvalidated);
    1383             : 
    1384           0 :   if (NS_WARN_IF(!mFileHandles.PutEntry(aFileHandle, fallible))) {
    1385           0 :     return false;
    1386             :   }
    1387             : 
    1388           0 :   if (mFileHandles.Count() == 1) {
    1389           0 :     NoteActiveState();
    1390             :   }
    1391             : 
    1392           0 :   return true;
    1393             : }
    1394             : 
    1395             : void
    1396           0 : BackgroundMutableFileParentBase::UnregisterFileHandle(FileHandle* aFileHandle)
    1397             : {
    1398           0 :   AssertIsOnBackgroundThread();
    1399           0 :   MOZ_ASSERT(aFileHandle);
    1400           0 :   MOZ_ASSERT(mFileHandles.GetEntry(aFileHandle));
    1401             : 
    1402           0 :   mFileHandles.RemoveEntry(aFileHandle);
    1403             : 
    1404           0 :   if (!mFileHandles.Count()) {
    1405           0 :     NoteInactiveState();
    1406             :   }
    1407           0 : }
    1408             : 
    1409             : void
    1410           0 : BackgroundMutableFileParentBase::SetActorAlive()
    1411             : {
    1412           0 :   AssertIsOnBackgroundThread();
    1413           0 :   MOZ_ASSERT(!mActorWasAlive);
    1414           0 :   MOZ_ASSERT(!mActorDestroyed);
    1415             : 
    1416           0 :   mActorWasAlive = true;
    1417             : 
    1418             :   // This reference will be absorbed by IPDL and released when the actor is
    1419             :   // destroyed.
    1420           0 :   AddRef();
    1421           0 : }
    1422             : 
    1423             : already_AddRefed<nsISupports>
    1424           0 : BackgroundMutableFileParentBase::CreateStream(bool aReadOnly)
    1425             : {
    1426           0 :   AssertIsOnBackgroundThread();
    1427             : 
    1428             :   nsresult rv;
    1429             : 
    1430           0 :   if (aReadOnly) {
    1431           0 :     nsCOMPtr<nsIInputStream> stream;
    1432           0 :     rv = NS_NewLocalFileInputStream(getter_AddRefs(stream), mFile, -1, -1,
    1433           0 :                                     nsIFileInputStream::DEFER_OPEN);
    1434           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
    1435           0 :       return nullptr;
    1436             :     }
    1437           0 :     return stream.forget();
    1438             :   }
    1439             : 
    1440           0 :   nsCOMPtr<nsIFileStream> stream;
    1441           0 :   rv = NS_NewLocalFileStream(getter_AddRefs(stream), mFile, -1, -1,
    1442           0 :                              nsIFileStream::DEFER_OPEN);
    1443           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    1444           0 :     return nullptr;
    1445             :   }
    1446           0 :   return stream.forget();
    1447             : }
    1448             : 
    1449             : void
    1450           0 : BackgroundMutableFileParentBase::ActorDestroy(ActorDestroyReason aWhy)
    1451             : {
    1452           0 :   AssertIsOnBackgroundThread();
    1453           0 :   MOZ_ASSERT(!mActorDestroyed);
    1454             : 
    1455           0 :   mActorDestroyed = true;
    1456             : 
    1457           0 :   if (!IsInvalidated()) {
    1458           0 :     Invalidate();
    1459             :   }
    1460           0 : }
    1461             : 
    1462             : PBackgroundFileHandleParent*
    1463           0 : BackgroundMutableFileParentBase::AllocPBackgroundFileHandleParent(
    1464             :                                                           const FileMode& aMode)
    1465             : {
    1466           0 :   AssertIsOnBackgroundThread();
    1467             : 
    1468           0 :   if (NS_WARN_IF(aMode != FileMode::Readonly &&
    1469             :                  aMode != FileMode::Readwrite)) {
    1470           0 :     ASSERT_UNLESS_FUZZING();
    1471             :     return nullptr;
    1472             :   }
    1473             : 
    1474           0 :   RefPtr<FileHandle> fileHandle = new FileHandle(this, aMode);
    1475             : 
    1476           0 :   return fileHandle.forget().take();
    1477             : }
    1478             : 
    1479             : mozilla::ipc::IPCResult
    1480           0 : BackgroundMutableFileParentBase::RecvPBackgroundFileHandleConstructor(
    1481             :                                             PBackgroundFileHandleParent* aActor,
    1482             :                                             const FileMode& aMode)
    1483             : {
    1484           0 :   AssertIsOnBackgroundThread();
    1485           0 :   MOZ_ASSERT(aActor);
    1486           0 :   MOZ_ASSERT(aMode == FileMode::Readonly || aMode == FileMode::Readwrite);
    1487             : 
    1488             :   FileHandleThreadPool* fileHandleThreadPool =
    1489           0 :     GetFileHandleThreadPoolFor(mStorage);
    1490           0 :   MOZ_ASSERT(fileHandleThreadPool);
    1491             : 
    1492           0 :   auto* fileHandle = static_cast<FileHandle*>(aActor);
    1493             : 
    1494             :   // Add a placeholder for this file handle immediately.
    1495           0 :   fileHandleThreadPool->Enqueue(fileHandle, nullptr, false);
    1496             : 
    1497           0 :   fileHandle->SetActive();
    1498             : 
    1499           0 :   if (NS_WARN_IF(!RegisterFileHandle(fileHandle))) {
    1500           0 :     fileHandle->Abort(/* aForce */ false);
    1501           0 :     return IPC_OK();
    1502             :   }
    1503             : 
    1504           0 :   return IPC_OK();
    1505             : }
    1506             : 
    1507             : bool
    1508           0 : BackgroundMutableFileParentBase::DeallocPBackgroundFileHandleParent(
    1509             :                                             PBackgroundFileHandleParent* aActor)
    1510             : {
    1511           0 :   AssertIsOnBackgroundThread();
    1512           0 :   MOZ_ASSERT(aActor);
    1513             : 
    1514             :   RefPtr<FileHandle> fileHandle =
    1515           0 :     dont_AddRef(static_cast<FileHandle*>(aActor));
    1516           0 :   return true;
    1517             : }
    1518             : 
    1519             : mozilla::ipc::IPCResult
    1520           0 : BackgroundMutableFileParentBase::RecvDeleteMe()
    1521             : {
    1522           0 :   AssertIsOnBackgroundThread();
    1523           0 :   MOZ_ASSERT(!mActorDestroyed);
    1524             : 
    1525           0 :   IProtocol* mgr = Manager();
    1526           0 :   if (!PBackgroundMutableFileParent::Send__delete__(this)) {
    1527           0 :     return IPC_FAIL_NO_REASON(mgr);
    1528             :   }
    1529           0 :   return IPC_OK();
    1530             : }
    1531             : 
    1532             : mozilla::ipc::IPCResult
    1533           0 : BackgroundMutableFileParentBase::RecvGetFileId(int64_t* aFileId)
    1534             : {
    1535           0 :   AssertIsOnBackgroundThread();
    1536             : 
    1537           0 :   *aFileId = -1;
    1538           0 :   return IPC_OK();
    1539             : }
    1540             : 
    1541             : /*******************************************************************************
    1542             :  * FileHandle
    1543             :  ******************************************************************************/
    1544             : 
    1545           0 : FileHandle::FileHandle(BackgroundMutableFileParentBase* aMutableFile,
    1546           0 :                        FileMode aMode)
    1547             :   : mMutableFile(aMutableFile)
    1548             :   , mActiveRequestCount(0)
    1549           0 :   , mStorage(aMutableFile->Storage())
    1550             :   , mInvalidatedOnAnyThread(false)
    1551             :   , mMode(aMode)
    1552             :   , mHasBeenActive(false)
    1553             :   , mActorDestroyed(false)
    1554             :   , mInvalidated(false)
    1555             :   , mAborted(false)
    1556             :   , mFinishOrAbortReceived(false)
    1557             :   , mFinishedOrAborted(false)
    1558           0 :   , mForceAborted(false)
    1559             : {
    1560           0 :   AssertIsOnBackgroundThread();
    1561           0 :   MOZ_ASSERT(aMutableFile);
    1562             : 
    1563             : #ifdef DEBUG
    1564             :   FileHandleThreadPool* fileHandleThreadPool =
    1565           0 :     GetFileHandleThreadPoolFor(mStorage);
    1566           0 :   MOZ_ASSERT(fileHandleThreadPool);
    1567             : 
    1568           0 :   mThreadPoolEventTarget = fileHandleThreadPool->GetThreadPoolEventTarget();
    1569             : #endif
    1570           0 : }
    1571             : 
    1572           0 : FileHandle::~FileHandle()
    1573             : {
    1574           0 :   MOZ_ASSERT(!mActiveRequestCount);
    1575           0 :   MOZ_ASSERT(mActorDestroyed);
    1576           0 :   MOZ_ASSERT_IF(mHasBeenActive, mFinishedOrAborted);
    1577           0 : }
    1578             : 
    1579             : void
    1580           0 : FileHandle::AssertIsOnThreadPool() const
    1581             : {
    1582           0 :   MOZ_ASSERT(mThreadPoolEventTarget);
    1583           0 :   DebugOnly<bool> current;
    1584           0 :   MOZ_ASSERT(NS_SUCCEEDED(mThreadPoolEventTarget->IsOnCurrentThread(&current)));
    1585           0 :   MOZ_ASSERT(current);
    1586           0 : }
    1587             : 
    1588             : nsresult
    1589           0 : FileHandle::GetOrCreateStream(nsISupports** aStream)
    1590             : {
    1591           0 :   AssertIsOnBackgroundThread();
    1592             : 
    1593           0 :   if (!mStream) {
    1594             :     nsCOMPtr<nsISupports> stream =
    1595           0 :       mMutableFile->CreateStream(mMode == FileMode::Readonly);
    1596           0 :     if (NS_WARN_IF(!stream)) {
    1597           0 :       return NS_ERROR_FAILURE;
    1598             :     }
    1599             : 
    1600           0 :     stream.swap(mStream);
    1601             :   }
    1602             : 
    1603           0 :   nsCOMPtr<nsISupports> stream(mStream);
    1604           0 :   stream.forget(aStream);
    1605             : 
    1606           0 :   return NS_OK;
    1607             : }
    1608             : 
    1609             : void
    1610           0 : FileHandle::Abort(bool aForce)
    1611             : {
    1612           0 :   AssertIsOnBackgroundThread();
    1613             : 
    1614           0 :   mAborted = true;
    1615             : 
    1616           0 :   if (aForce) {
    1617           0 :     mForceAborted = true;
    1618             :   }
    1619             : 
    1620           0 :   MaybeFinishOrAbort();
    1621           0 : }
    1622             : 
    1623             : void
    1624           0 : FileHandle::NoteActiveRequest()
    1625             : {
    1626           0 :   AssertIsOnBackgroundThread();
    1627           0 :   MOZ_ASSERT(mActiveRequestCount < UINT64_MAX);
    1628             : 
    1629           0 :   mActiveRequestCount++;
    1630           0 : }
    1631             : 
    1632             : void
    1633           0 : FileHandle::NoteFinishedRequest()
    1634             : {
    1635           0 :   AssertIsOnBackgroundThread();
    1636           0 :   MOZ_ASSERT(mActiveRequestCount);
    1637             : 
    1638           0 :   mActiveRequestCount--;
    1639             : 
    1640           0 :   MaybeFinishOrAbort();
    1641           0 : }
    1642             : 
    1643             : void
    1644           0 : FileHandle::Invalidate()
    1645             : {
    1646           0 :   AssertIsOnBackgroundThread();
    1647           0 :   MOZ_ASSERT(mInvalidated == mInvalidatedOnAnyThread);
    1648             : 
    1649           0 :   if (!mInvalidated) {
    1650           0 :     mInvalidated = true;
    1651           0 :     mInvalidatedOnAnyThread = true;
    1652             : 
    1653           0 :     Abort(/* aForce */ true);
    1654             :   }
    1655           0 : }
    1656             : 
    1657             : void
    1658           0 : FileHandle::SendCompleteNotification(bool aAborted)
    1659             : {
    1660           0 :   AssertIsOnBackgroundThread();
    1661             : 
    1662           0 :   if (!IsActorDestroyed()) {
    1663           0 :     Unused << SendComplete(aAborted);
    1664             :   }
    1665           0 : }
    1666             : 
    1667             : bool
    1668           0 : FileHandle::VerifyRequestParams(const FileRequestParams& aParams) const
    1669             : {
    1670           0 :   AssertIsOnBackgroundThread();
    1671           0 :   MOZ_ASSERT(aParams.type() != FileRequestParams::T__None);
    1672             : 
    1673           0 :   switch (aParams.type()) {
    1674             :     case FileRequestParams::TFileRequestGetMetadataParams: {
    1675             :       const FileRequestGetMetadataParams& params =
    1676           0 :         aParams.get_FileRequestGetMetadataParams();
    1677             : 
    1678           0 :       if (NS_WARN_IF(!params.size() && !params.lastModified())) {
    1679           0 :         ASSERT_UNLESS_FUZZING();
    1680             :         return false;
    1681             :       }
    1682             : 
    1683           0 :       break;
    1684             :     }
    1685             : 
    1686             :     case FileRequestParams::TFileRequestReadParams: {
    1687             :       const FileRequestReadParams& params =
    1688           0 :         aParams.get_FileRequestReadParams();
    1689             : 
    1690           0 :       if (NS_WARN_IF(params.offset() == UINT64_MAX)) {
    1691           0 :         ASSERT_UNLESS_FUZZING();
    1692             :         return false;
    1693             :       }
    1694             : 
    1695           0 :       if (NS_WARN_IF(!params.size())) {
    1696           0 :         ASSERT_UNLESS_FUZZING();
    1697             :         return false;
    1698             :       }
    1699             : 
    1700           0 :       break;
    1701             :     }
    1702             : 
    1703             :     case FileRequestParams::TFileRequestWriteParams: {
    1704           0 :       if (NS_WARN_IF(mMode != FileMode::Readwrite)) {
    1705           0 :         ASSERT_UNLESS_FUZZING();
    1706             :         return false;
    1707             :       }
    1708             : 
    1709             :       const FileRequestWriteParams& params =
    1710           0 :         aParams.get_FileRequestWriteParams();
    1711             : 
    1712             : 
    1713           0 :       if (NS_WARN_IF(!params.dataLength())) {
    1714           0 :         ASSERT_UNLESS_FUZZING();
    1715             :         return false;
    1716             :       }
    1717             : 
    1718           0 :       if (NS_WARN_IF(!VerifyRequestData(params.data()))) {
    1719           0 :         ASSERT_UNLESS_FUZZING();
    1720             :         return false;
    1721             :       }
    1722             : 
    1723           0 :       break;
    1724             :     }
    1725             : 
    1726             :     case FileRequestParams::TFileRequestTruncateParams: {
    1727           0 :       if (NS_WARN_IF(mMode != FileMode::Readwrite)) {
    1728           0 :         ASSERT_UNLESS_FUZZING();
    1729             :         return false;
    1730             :       }
    1731             : 
    1732             :       const FileRequestTruncateParams& params =
    1733           0 :         aParams.get_FileRequestTruncateParams();
    1734             : 
    1735           0 :       if (NS_WARN_IF(params.offset() == UINT64_MAX)) {
    1736           0 :         ASSERT_UNLESS_FUZZING();
    1737             :         return false;
    1738             :       }
    1739             : 
    1740           0 :       break;
    1741             :     }
    1742             : 
    1743             :     case FileRequestParams::TFileRequestFlushParams: {
    1744           0 :       if (NS_WARN_IF(mMode != FileMode::Readwrite)) {
    1745           0 :         ASSERT_UNLESS_FUZZING();
    1746             :         return false;
    1747             :       }
    1748             : 
    1749           0 :       break;
    1750             :     }
    1751             : 
    1752             :     case FileRequestParams::TFileRequestGetFileParams: {
    1753           0 :       break;
    1754             :     }
    1755             : 
    1756             :     default:
    1757           0 :       MOZ_CRASH("Should never get here!");
    1758             :   }
    1759             : 
    1760           0 :   return true;
    1761             : }
    1762             : 
    1763             : bool
    1764           0 : FileHandle::VerifyRequestData(const FileRequestData& aData) const
    1765             : {
    1766           0 :   AssertIsOnBackgroundThread();
    1767           0 :   MOZ_ASSERT(aData.type() != FileRequestData::T__None);
    1768             : 
    1769           0 :   switch (aData.type()) {
    1770             :     case FileRequestData::TFileRequestStringData: {
    1771             :       const FileRequestStringData& data =
    1772           0 :         aData.get_FileRequestStringData();
    1773             : 
    1774           0 :       if (NS_WARN_IF(data.string().IsEmpty())) {
    1775           0 :         ASSERT_UNLESS_FUZZING();
    1776             :         return false;
    1777             :       }
    1778             : 
    1779           0 :       break;
    1780             :     }
    1781             : 
    1782             :     case FileRequestData::TFileRequestBlobData: {
    1783           0 :       break;
    1784             :     }
    1785             : 
    1786             :     default:
    1787           0 :       MOZ_CRASH("Should never get here!");
    1788             :   }
    1789             : 
    1790           0 :   return true;
    1791             : }
    1792             : 
    1793             : void
    1794           0 : FileHandle::FinishOrAbort()
    1795             : {
    1796           0 :   AssertIsOnBackgroundThread();
    1797           0 :   MOZ_ASSERT(!mFinishedOrAborted);
    1798             : 
    1799           0 :   mFinishedOrAborted = true;
    1800             : 
    1801           0 :   if (!mHasBeenActive) {
    1802           0 :     return;
    1803             :   }
    1804             : 
    1805           0 :   RefPtr<FinishOp> finishOp = new FinishOp(this, mAborted);
    1806             : 
    1807             :   FileHandleThreadPool* fileHandleThreadPool =
    1808           0 :     GetFileHandleThreadPoolFor(mStorage);
    1809           0 :   MOZ_ASSERT(fileHandleThreadPool);
    1810             : 
    1811           0 :   fileHandleThreadPool->Enqueue(this, finishOp, true);
    1812             : }
    1813             : 
    1814             : void
    1815           0 : FileHandle::ActorDestroy(ActorDestroyReason aWhy)
    1816             : {
    1817           0 :   AssertIsOnBackgroundThread();
    1818             : 
    1819           0 :   MOZ_ASSERT(!mActorDestroyed);
    1820             : 
    1821           0 :   mActorDestroyed = true;
    1822             : 
    1823           0 :   if (!mFinishedOrAborted) {
    1824           0 :     mAborted = true;
    1825             : 
    1826           0 :     mForceAborted = true;
    1827             : 
    1828           0 :     MaybeFinishOrAbort();
    1829             :   }
    1830           0 : }
    1831             : 
    1832             : mozilla::ipc::IPCResult
    1833           0 : FileHandle::RecvDeleteMe()
    1834             : {
    1835           0 :   AssertIsOnBackgroundThread();
    1836           0 :   MOZ_ASSERT(!IsActorDestroyed());
    1837             : 
    1838           0 :   IProtocol* mgr = Manager();
    1839           0 :   if (!PBackgroundFileHandleParent::Send__delete__(this)) {
    1840           0 :     return IPC_FAIL_NO_REASON(mgr);
    1841             :   }
    1842           0 :   return IPC_OK();
    1843             : }
    1844             : 
    1845             : mozilla::ipc::IPCResult
    1846           0 : FileHandle::RecvFinish()
    1847             : {
    1848           0 :   AssertIsOnBackgroundThread();
    1849             : 
    1850           0 :   if (NS_WARN_IF(mFinishOrAbortReceived)) {
    1851           0 :     ASSERT_UNLESS_FUZZING();
    1852             :     return IPC_FAIL_NO_REASON(this);
    1853             :   }
    1854             : 
    1855           0 :   mFinishOrAbortReceived = true;
    1856             : 
    1857           0 :   MaybeFinishOrAbort();
    1858           0 :   return IPC_OK();
    1859             : }
    1860             : 
    1861             : mozilla::ipc::IPCResult
    1862           0 : FileHandle::RecvAbort()
    1863             : {
    1864           0 :   AssertIsOnBackgroundThread();
    1865             : 
    1866           0 :   if (NS_WARN_IF(mFinishOrAbortReceived)) {
    1867           0 :     ASSERT_UNLESS_FUZZING();
    1868             :     return IPC_FAIL_NO_REASON(this);
    1869             :   }
    1870             : 
    1871           0 :   mFinishOrAbortReceived = true;
    1872             : 
    1873           0 :   Abort(/* aForce */ false);
    1874           0 :   return IPC_OK();
    1875             : }
    1876             : 
    1877             : PBackgroundFileRequestParent*
    1878           0 : FileHandle::AllocPBackgroundFileRequestParent(const FileRequestParams& aParams)
    1879             : {
    1880           0 :   AssertIsOnBackgroundThread();
    1881           0 :   MOZ_ASSERT(aParams.type() != FileRequestParams::T__None);
    1882             : 
    1883             : #ifdef DEBUG
    1884             :   // Always verify parameters in DEBUG builds!
    1885           0 :   bool trustParams = false;
    1886             : #else
    1887             :   PBackgroundParent* backgroundActor = GetBackgroundParent();
    1888             :   MOZ_ASSERT(backgroundActor);
    1889             : 
    1890             :   bool trustParams = !BackgroundParent::IsOtherProcessActor(backgroundActor);
    1891             : #endif
    1892             : 
    1893           0 :   if (NS_WARN_IF(!trustParams && !VerifyRequestParams(aParams))) {
    1894           0 :     ASSERT_UNLESS_FUZZING();
    1895             :     return nullptr;
    1896             :   }
    1897             : 
    1898           0 :   if (NS_WARN_IF(mFinishOrAbortReceived)) {
    1899           0 :     ASSERT_UNLESS_FUZZING();
    1900             :     return nullptr;
    1901             :   }
    1902             : 
    1903           0 :   RefPtr<NormalFileHandleOp> actor;
    1904             : 
    1905           0 :   switch (aParams.type()) {
    1906             :     case FileRequestParams::TFileRequestGetMetadataParams:
    1907           0 :       actor = new GetMetadataOp(this, aParams);
    1908           0 :       break;
    1909             : 
    1910             :     case FileRequestParams::TFileRequestReadParams:
    1911           0 :       actor = new ReadOp(this, aParams);
    1912           0 :       break;
    1913             : 
    1914             :     case FileRequestParams::TFileRequestWriteParams:
    1915           0 :       actor = new WriteOp(this, aParams);
    1916           0 :       break;
    1917             : 
    1918             :     case FileRequestParams::TFileRequestTruncateParams:
    1919           0 :       actor = new TruncateOp(this, aParams);
    1920           0 :       break;
    1921             : 
    1922             :     case FileRequestParams::TFileRequestFlushParams:
    1923           0 :       actor = new FlushOp(this, aParams);
    1924           0 :       break;
    1925             : 
    1926             :     case FileRequestParams::TFileRequestGetFileParams:
    1927           0 :       actor = new GetFileOp(this, aParams);
    1928           0 :       break;
    1929             : 
    1930             :     default:
    1931           0 :       MOZ_CRASH("Should never get here!");
    1932             :   }
    1933             : 
    1934           0 :   MOZ_ASSERT(actor);
    1935             : 
    1936             :   // Transfer ownership to IPDL.
    1937           0 :   return actor.forget().take();
    1938             : }
    1939             : 
    1940             : mozilla::ipc::IPCResult
    1941           0 : FileHandle::RecvPBackgroundFileRequestConstructor(
    1942             :                                            PBackgroundFileRequestParent* aActor,
    1943             :                                            const FileRequestParams& aParams)
    1944             : {
    1945           0 :   AssertIsOnBackgroundThread();
    1946           0 :   MOZ_ASSERT(aActor);
    1947           0 :   MOZ_ASSERT(aParams.type() != FileRequestParams::T__None);
    1948             : 
    1949           0 :   auto* op = static_cast<NormalFileHandleOp*>(aActor);
    1950             : 
    1951           0 :   if (NS_WARN_IF(!op->Init(this))) {
    1952           0 :     op->Cleanup();
    1953           0 :     return IPC_FAIL_NO_REASON(this);
    1954             :   }
    1955             : 
    1956           0 :   op->Enqueue();
    1957           0 :   return IPC_OK();
    1958             : }
    1959             : 
    1960             : bool
    1961           0 : FileHandle::DeallocPBackgroundFileRequestParent(
    1962             :                                            PBackgroundFileRequestParent* aActor)
    1963             : {
    1964           0 :   AssertIsOnBackgroundThread();
    1965           0 :   MOZ_ASSERT(aActor);
    1966             : 
    1967             :   // Transfer ownership back from IPDL.
    1968             :   RefPtr<NormalFileHandleOp> actor =
    1969           0 :     dont_AddRef(static_cast<NormalFileHandleOp*>(aActor));
    1970           0 :   return true;
    1971             : }
    1972             : 
    1973             : /*******************************************************************************
    1974             :  * Local class implementations
    1975             :  ******************************************************************************/
    1976             : 
    1977             : void
    1978           0 : FileHandleOp::Enqueue()
    1979             : {
    1980           0 :   AssertIsOnOwningThread();
    1981             : 
    1982             :   FileHandleThreadPool* fileHandleThreadPool =
    1983           0 :     GetFileHandleThreadPoolFor(mFileHandle->Storage());
    1984           0 :   MOZ_ASSERT(fileHandleThreadPool);
    1985             : 
    1986           0 :   fileHandleThreadPool->Enqueue(mFileHandle, this, false);
    1987             : 
    1988           0 :   mFileHandle->NoteActiveRequest();
    1989           0 : }
    1990             : 
    1991             : void
    1992           0 : FileHandle::
    1993             : FinishOp::RunOnThreadPool()
    1994             : {
    1995           0 :   AssertIsOnThreadPool();
    1996           0 :   MOZ_ASSERT(mFileHandle);
    1997             : 
    1998           0 :   nsCOMPtr<nsISupports>& stream = mFileHandle->mStream;
    1999             : 
    2000           0 :   if (!stream) {
    2001           0 :     return;
    2002             :   }
    2003             : 
    2004           0 :   nsCOMPtr<nsIInputStream> inputStream = do_QueryInterface(stream);
    2005           0 :   MOZ_ASSERT(inputStream);
    2006             : 
    2007           0 :   MOZ_ALWAYS_SUCCEEDS(inputStream->Close());
    2008             : 
    2009           0 :   stream = nullptr;
    2010             : }
    2011             : 
    2012             : void
    2013           0 : FileHandle::
    2014             : FinishOp::RunOnOwningThread()
    2015             : {
    2016           0 :   AssertIsOnOwningThread();
    2017           0 :   MOZ_ASSERT(mFileHandle);
    2018             : 
    2019           0 :   mFileHandle->SendCompleteNotification(mAborted);
    2020             : 
    2021           0 :   mFileHandle->GetMutableFile()->UnregisterFileHandle(mFileHandle);
    2022             : 
    2023           0 :   mFileHandle = nullptr;
    2024           0 : }
    2025             : 
    2026           0 : NormalFileHandleOp::~NormalFileHandleOp()
    2027             : {
    2028           0 :   MOZ_ASSERT(!mFileHandle,
    2029             :              "NormalFileHandleOp::Cleanup() was not called by a subclass!");
    2030           0 : }
    2031             : 
    2032             : bool
    2033           0 : NormalFileHandleOp::Init(FileHandle* aFileHandle)
    2034             : {
    2035           0 :   AssertIsOnOwningThread();
    2036           0 :   MOZ_ASSERT(aFileHandle);
    2037             : 
    2038           0 :   nsresult rv = aFileHandle->GetOrCreateStream(getter_AddRefs(mFileStream));
    2039           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    2040           0 :     return false;
    2041             :   }
    2042             : 
    2043           0 :   return true;
    2044             : }
    2045             : 
    2046             : void
    2047           0 : NormalFileHandleOp::Cleanup()
    2048             : {
    2049           0 :   AssertIsOnOwningThread();
    2050           0 :   MOZ_ASSERT(mFileHandle);
    2051           0 :   MOZ_ASSERT_IF(!IsActorDestroyed(), mResponseSent);
    2052             : 
    2053           0 :   mFileHandle = nullptr;
    2054           0 : }
    2055             : 
    2056             : nsresult
    2057           0 : NormalFileHandleOp::SendSuccessResult()
    2058             : {
    2059           0 :   AssertIsOnOwningThread();
    2060             : 
    2061           0 :   if (!IsActorDestroyed()) {
    2062           0 :     FileRequestResponse response;
    2063           0 :     GetResponse(response);
    2064             : 
    2065           0 :     MOZ_ASSERT(response.type() != FileRequestResponse::T__None);
    2066             : 
    2067           0 :     if (response.type() == FileRequestResponse::Tnsresult) {
    2068           0 :       MOZ_ASSERT(NS_FAILED(response.get_nsresult()));
    2069             : 
    2070           0 :       return response.get_nsresult();
    2071             :     }
    2072             : 
    2073           0 :     if (NS_WARN_IF(!PBackgroundFileRequestParent::Send__delete__(this,
    2074             :                                                                  response))) {
    2075           0 :       return NS_ERROR_DOM_FILEHANDLE_UNKNOWN_ERR;
    2076             :     }
    2077             :   }
    2078             : 
    2079             : #ifdef DEBUG
    2080           0 :   mResponseSent = true;
    2081             : #endif
    2082             : 
    2083           0 :   return NS_OK;
    2084             : }
    2085             : 
    2086             : bool
    2087           0 : NormalFileHandleOp::SendFailureResult(nsresult aResultCode)
    2088             : {
    2089           0 :   AssertIsOnBackgroundThread();
    2090           0 :   MOZ_ASSERT(NS_FAILED(aResultCode));
    2091             : 
    2092           0 :   bool result = false;
    2093             : 
    2094           0 :   if (!IsActorDestroyed()) {
    2095             :     result =
    2096           0 :       PBackgroundFileRequestParent::Send__delete__(this, aResultCode);
    2097             :   }
    2098             : 
    2099             : #ifdef DEBUG
    2100           0 :   mResponseSent = true;
    2101             : #endif
    2102             : 
    2103           0 :   return result;
    2104             : }
    2105             : 
    2106             : void
    2107           0 : NormalFileHandleOp::RunOnThreadPool()
    2108             : {
    2109           0 :   AssertIsOnThreadPool();
    2110           0 :   MOZ_ASSERT(mFileHandle);
    2111           0 :   MOZ_ASSERT(NS_SUCCEEDED(mResultCode));
    2112             : 
    2113             :   // There are several cases where we don't actually have to to any work here.
    2114             : 
    2115           0 :   if (mFileHandleIsAborted) {
    2116             :     // This transaction is already set to be aborted.
    2117           0 :     mResultCode = NS_ERROR_DOM_FILEHANDLE_ABORT_ERR;
    2118           0 :   } else if (mFileHandle->IsInvalidatedOnAnyThread()) {
    2119             :     // This file handle is being invalidated.
    2120           0 :     mResultCode = NS_ERROR_DOM_FILEHANDLE_UNKNOWN_ERR;
    2121           0 :   } else if (!OperationMayProceed()) {
    2122             :     // The operation was canceled in some way, likely because the child process
    2123             :     // has crashed.
    2124           0 :     mResultCode = NS_ERROR_DOM_FILEHANDLE_UNKNOWN_ERR;
    2125             :   } else {
    2126           0 :     nsresult rv = DoFileWork(mFileHandle);
    2127           0 :     if (NS_FAILED(rv)) {
    2128           0 :       mResultCode = rv;
    2129             :     }
    2130             :   }
    2131           0 : }
    2132             : 
    2133             : void
    2134           0 : NormalFileHandleOp::RunOnOwningThread()
    2135             : {
    2136           0 :   AssertIsOnOwningThread();
    2137           0 :   MOZ_ASSERT(mFileHandle);
    2138             : 
    2139           0 :   if (NS_WARN_IF(IsActorDestroyed())) {
    2140             :     // Don't send any notifications if the actor was destroyed already.
    2141           0 :     if (NS_SUCCEEDED(mResultCode)) {
    2142           0 :       mResultCode = NS_ERROR_DOM_FILEHANDLE_UNKNOWN_ERR;
    2143             :     }
    2144             :   } else {
    2145           0 :     if (mFileHandle->IsInvalidated()) {
    2146           0 :       mResultCode = NS_ERROR_DOM_FILEHANDLE_UNKNOWN_ERR;
    2147           0 :     } else if (mFileHandle->IsAborted()) {
    2148             :       // Aborted file handles always see their requests fail with ABORT_ERR,
    2149             :       // even if the request succeeded or failed with another error.
    2150           0 :       mResultCode = NS_ERROR_DOM_FILEHANDLE_ABORT_ERR;
    2151           0 :     } else if (NS_SUCCEEDED(mResultCode)) {
    2152             :       // This may release the IPDL reference.
    2153           0 :       mResultCode = SendSuccessResult();
    2154             :     }
    2155             : 
    2156           0 :     if (NS_FAILED(mResultCode)) {
    2157             :       // This should definitely release the IPDL reference.
    2158           0 :       if (!SendFailureResult(mResultCode)) {
    2159             :         // Abort the file handle.
    2160           0 :         mFileHandle->Abort(/* aForce */ false);
    2161             :       }
    2162             :     }
    2163             :   }
    2164             : 
    2165           0 :   mFileHandle->NoteFinishedRequest();
    2166             : 
    2167           0 :   Cleanup();
    2168           0 : }
    2169             : 
    2170             : void
    2171           0 : NormalFileHandleOp::ActorDestroy(ActorDestroyReason aWhy)
    2172             : {
    2173           0 :   AssertIsOnOwningThread();
    2174             : 
    2175           0 :   NoteActorDestroyed();
    2176           0 : }
    2177             : 
    2178             : nsresult
    2179           0 : CopyFileHandleOp::DoFileWork(FileHandle* aFileHandle)
    2180             : {
    2181           0 :   AssertIsOnThreadPool();
    2182             : 
    2183           0 :   nsCOMPtr<nsIInputStream> inputStream;
    2184           0 :   nsCOMPtr<nsIOutputStream> outputStream;
    2185             : 
    2186           0 :   if (mRead) {
    2187           0 :     inputStream = do_QueryInterface(mFileStream);
    2188           0 :     outputStream = do_QueryInterface(mBufferStream);
    2189             :   } else {
    2190           0 :     inputStream = do_QueryInterface(mBufferStream);
    2191           0 :     outputStream = do_QueryInterface(mFileStream);
    2192             :   }
    2193             : 
    2194           0 :   MOZ_ASSERT(inputStream);
    2195           0 :   MOZ_ASSERT(outputStream);
    2196             : 
    2197             :   nsCOMPtr<nsISeekableStream> seekableStream =
    2198           0 :     do_QueryInterface(mFileStream);
    2199             : 
    2200             :   nsresult rv;
    2201             : 
    2202           0 :   if (seekableStream) {
    2203           0 :     if (mOffset == UINT64_MAX) {
    2204           0 :       rv = seekableStream->Seek(nsISeekableStream::NS_SEEK_END, 0);
    2205             :     }
    2206             :     else {
    2207           0 :       rv = seekableStream->Seek(nsISeekableStream::NS_SEEK_SET, mOffset);
    2208             :     }
    2209           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
    2210           0 :       return rv;
    2211             :     }
    2212             :   }
    2213             : 
    2214           0 :   mOffset = 0;
    2215             : 
    2216             :   do {
    2217             :     char copyBuffer[kStreamCopyBlockSize];
    2218             : 
    2219           0 :     uint64_t max = mSize - mOffset;
    2220           0 :     if (max == 0) {
    2221           0 :       break;
    2222             :     }
    2223             : 
    2224           0 :     uint32_t count = sizeof(copyBuffer);
    2225           0 :     if (count > max) {
    2226           0 :       count = max;
    2227             :     }
    2228             : 
    2229             :     uint32_t numRead;
    2230           0 :     rv = inputStream->Read(copyBuffer, count, &numRead);
    2231           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
    2232           0 :       return rv;
    2233             :     }
    2234             : 
    2235           0 :     if (!numRead) {
    2236           0 :       break;
    2237             :     }
    2238             : 
    2239             :     uint32_t numWrite;
    2240           0 :     rv = outputStream->Write(copyBuffer, numRead, &numWrite);
    2241           0 :     if (rv == NS_ERROR_FILE_NO_DEVICE_SPACE) {
    2242           0 :       rv = NS_ERROR_DOM_FILEHANDLE_QUOTA_ERR;
    2243             :     }
    2244           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
    2245           0 :       return rv;
    2246             :     }
    2247             : 
    2248           0 :     if (NS_WARN_IF(numWrite != numRead)) {
    2249           0 :       return NS_ERROR_FAILURE;
    2250             :     }
    2251             : 
    2252           0 :     mOffset += numWrite;
    2253             : 
    2254             :     nsCOMPtr<nsIRunnable> runnable =
    2255           0 :       new ProgressRunnable(this, mOffset, mSize);
    2256             : 
    2257           0 :     mOwningEventTarget->Dispatch(runnable, NS_DISPATCH_NORMAL);
    2258             :   } while (true);
    2259             : 
    2260           0 :   MOZ_ASSERT(mOffset == mSize);
    2261             : 
    2262           0 :   if (mRead) {
    2263           0 :     MOZ_ALWAYS_SUCCEEDS(outputStream->Close());
    2264             :   } else {
    2265           0 :     MOZ_ALWAYS_SUCCEEDS(inputStream->Close());
    2266             :   }
    2267             : 
    2268           0 :   return NS_OK;
    2269             : }
    2270             : 
    2271             : void
    2272           0 : CopyFileHandleOp::Cleanup()
    2273             : {
    2274           0 :   AssertIsOnOwningThread();
    2275             : 
    2276           0 :   mBufferStream = nullptr;
    2277             : 
    2278           0 :   NormalFileHandleOp::Cleanup();
    2279           0 : }
    2280             : 
    2281             : NS_IMETHODIMP
    2282           0 : CopyFileHandleOp::
    2283             : ProgressRunnable::Run()
    2284             : {
    2285           0 :   AssertIsOnBackgroundThread();
    2286             : 
    2287           0 :   Unused << mCopyFileHandleOp->SendProgress(mProgress, mProgressMax);
    2288             : 
    2289           0 :   mCopyFileHandleOp = nullptr;
    2290             : 
    2291           0 :   return NS_OK;
    2292             : }
    2293             : 
    2294           0 : GetMetadataOp::GetMetadataOp(FileHandle* aFileHandle,
    2295           0 :                              const FileRequestParams& aParams)
    2296             :   : NormalFileHandleOp(aFileHandle)
    2297           0 :   , mParams(aParams.get_FileRequestGetMetadataParams())
    2298             : {
    2299           0 :   MOZ_ASSERT(aParams.type() ==
    2300             :              FileRequestParams::TFileRequestGetMetadataParams);
    2301           0 : }
    2302             : 
    2303             : nsresult
    2304           0 : GetMetadataOp::DoFileWork(FileHandle* aFileHandle)
    2305             : {
    2306           0 :   AssertIsOnThreadPool();
    2307             : 
    2308             :   nsresult rv;
    2309             : 
    2310           0 :   if (mFileHandle->Mode() == FileMode::Readwrite) {
    2311             :     // Force a flush (so all pending writes are flushed to the disk and file
    2312             :     // metadata is updated too).
    2313             : 
    2314           0 :     nsCOMPtr<nsIOutputStream> ostream = do_QueryInterface(mFileStream);
    2315           0 :     MOZ_ASSERT(ostream);
    2316             : 
    2317           0 :     rv = ostream->Flush();
    2318           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
    2319           0 :       return rv;
    2320             :     }
    2321             :   }
    2322             : 
    2323           0 :   nsCOMPtr<nsIFileMetadata> metadata = do_QueryInterface(mFileStream);
    2324           0 :   MOZ_ASSERT(metadata);
    2325             : 
    2326           0 :   if (mParams.size()) {
    2327             :     int64_t size;
    2328           0 :     rv = metadata->GetSize(&size);
    2329           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
    2330           0 :       return rv;
    2331             :     }
    2332             : 
    2333           0 :     if (NS_WARN_IF(size < 0)) {
    2334           0 :       return NS_ERROR_FAILURE;
    2335             :     }
    2336             : 
    2337           0 :     mMetadata.size() = uint64_t(size);
    2338             :   } else {
    2339           0 :     mMetadata.size() = void_t();
    2340             :   }
    2341             : 
    2342           0 :   if (mParams.lastModified()) {
    2343             :     int64_t lastModified;
    2344           0 :     rv = metadata->GetLastModified(&lastModified);
    2345           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
    2346           0 :       return rv;
    2347             :     }
    2348             : 
    2349           0 :     mMetadata.lastModified() = lastModified;
    2350             :   } else {
    2351           0 :     mMetadata.lastModified() = void_t();
    2352             :   }
    2353             : 
    2354           0 :   return NS_OK;
    2355             : }
    2356             : 
    2357             : void
    2358           0 : GetMetadataOp::GetResponse(FileRequestResponse& aResponse)
    2359             : {
    2360           0 :   AssertIsOnOwningThread();
    2361             : 
    2362           0 :   aResponse = FileRequestGetMetadataResponse(mMetadata);
    2363           0 : }
    2364             : 
    2365           0 : ReadOp::ReadOp(FileHandle* aFileHandle,
    2366           0 :                const FileRequestParams& aParams)
    2367             :   : CopyFileHandleOp(aFileHandle)
    2368           0 :   , mParams(aParams.get_FileRequestReadParams())
    2369             : {
    2370           0 :   MOZ_ASSERT(aParams.type() == FileRequestParams::TFileRequestReadParams);
    2371           0 : }
    2372             : 
    2373             : bool
    2374           0 : ReadOp::Init(FileHandle* aFileHandle)
    2375             : {
    2376           0 :   AssertIsOnOwningThread();
    2377           0 :   MOZ_ASSERT(aFileHandle);
    2378             : 
    2379           0 :   if (NS_WARN_IF(!NormalFileHandleOp::Init(aFileHandle))) {
    2380           0 :     return false;
    2381             :   }
    2382             : 
    2383           0 :   mBufferStream = MemoryOutputStream::Create(mParams.size());
    2384           0 :   if (NS_WARN_IF(!mBufferStream)) {
    2385           0 :     return false;
    2386             :   }
    2387             : 
    2388           0 :   mOffset = mParams.offset();
    2389           0 :   mSize = mParams.size();
    2390           0 :   mRead = true;
    2391             : 
    2392           0 :   return true;
    2393             : }
    2394             : 
    2395             : void
    2396           0 : ReadOp::GetResponse(FileRequestResponse& aResponse)
    2397             : {
    2398           0 :   AssertIsOnOwningThread();
    2399             : 
    2400           0 :   auto* stream = static_cast<MemoryOutputStream*>(mBufferStream.get());
    2401             : 
    2402           0 :   aResponse = FileRequestReadResponse(stream->Data());
    2403           0 : }
    2404             : 
    2405             : // static
    2406             : already_AddRefed<ReadOp::MemoryOutputStream>
    2407           0 : ReadOp::
    2408             : MemoryOutputStream::Create(uint64_t aSize)
    2409             : {
    2410           0 :   MOZ_ASSERT(aSize, "Passed zero size!");
    2411             : 
    2412           0 :   if (NS_WARN_IF(aSize > UINT32_MAX)) {
    2413           0 :     return nullptr;
    2414             :   }
    2415             : 
    2416           0 :   RefPtr<MemoryOutputStream> stream = new MemoryOutputStream();
    2417             : 
    2418             :   char* dummy;
    2419           0 :   uint32_t length = stream->mData.GetMutableData(&dummy, aSize, fallible);
    2420           0 :   if (NS_WARN_IF(length != aSize)) {
    2421           0 :     return nullptr;
    2422             :   }
    2423             : 
    2424           0 :   return stream.forget();
    2425             : }
    2426             : 
    2427           0 : NS_IMPL_ISUPPORTS(ReadOp::MemoryOutputStream, nsIOutputStream)
    2428             : 
    2429             : NS_IMETHODIMP
    2430           0 : ReadOp::
    2431             : MemoryOutputStream::Close()
    2432             : {
    2433           0 :   mData.Truncate(mOffset);
    2434           0 :   return NS_OK;
    2435             : }
    2436             : 
    2437             : NS_IMETHODIMP
    2438           0 : ReadOp::
    2439             : MemoryOutputStream::Write(const char* aBuf, uint32_t aCount, uint32_t* _retval)
    2440             : {
    2441           0 :   return WriteSegments(NS_CopySegmentToBuffer, (char*)aBuf, aCount, _retval);
    2442             : }
    2443             : 
    2444             : NS_IMETHODIMP
    2445           0 : ReadOp::
    2446             : MemoryOutputStream::Flush()
    2447             : {
    2448           0 :   return NS_OK;
    2449             : }
    2450             : 
    2451             : NS_IMETHODIMP
    2452           0 : ReadOp::
    2453             : MemoryOutputStream::WriteFrom(nsIInputStream* aFromStream, uint32_t aCount,
    2454             :                               uint32_t* _retval)
    2455             : {
    2456           0 :   return NS_ERROR_NOT_IMPLEMENTED;
    2457             : }
    2458             : 
    2459             : NS_IMETHODIMP
    2460           0 : ReadOp::
    2461             : MemoryOutputStream::WriteSegments(nsReadSegmentFun aReader, void* aClosure,
    2462             :                                   uint32_t aCount, uint32_t* _retval)
    2463             : {
    2464           0 :   NS_ASSERTION(mData.Length() >= mOffset, "Bad stream state!");
    2465             : 
    2466           0 :   uint32_t maxCount = mData.Length() - mOffset;
    2467           0 :   if (maxCount == 0) {
    2468           0 :     *_retval = 0;
    2469           0 :     return NS_OK;
    2470             :   }
    2471             : 
    2472           0 :   if (aCount > maxCount) {
    2473           0 :     aCount = maxCount;
    2474             :   }
    2475             : 
    2476           0 :   nsresult rv = aReader(this, aClosure, mData.BeginWriting() + mOffset, 0,
    2477           0 :                         aCount, _retval);
    2478           0 :   if (NS_SUCCEEDED(rv)) {
    2479           0 :     NS_ASSERTION(*_retval <= aCount,
    2480             :                  "Reader should not read more than we asked it to read!");
    2481           0 :     mOffset += *_retval;
    2482             :   }
    2483             : 
    2484           0 :   return NS_OK;
    2485             : }
    2486             : 
    2487             : NS_IMETHODIMP
    2488           0 : ReadOp::
    2489             : MemoryOutputStream::IsNonBlocking(bool* _retval)
    2490             : {
    2491           0 :   *_retval = false;
    2492           0 :   return NS_OK;
    2493             : }
    2494             : 
    2495           0 : WriteOp::WriteOp(FileHandle* aFileHandle,
    2496           0 :                  const FileRequestParams& aParams)
    2497             :   : CopyFileHandleOp(aFileHandle)
    2498           0 :   , mParams(aParams.get_FileRequestWriteParams())
    2499             : {
    2500           0 :   MOZ_ASSERT(aParams.type() == FileRequestParams::TFileRequestWriteParams);
    2501           0 : }
    2502             : 
    2503             : bool
    2504           0 : WriteOp::Init(FileHandle* aFileHandle)
    2505             : {
    2506           0 :   AssertIsOnOwningThread();
    2507           0 :   MOZ_ASSERT(aFileHandle);
    2508             : 
    2509           0 :   if (NS_WARN_IF(!NormalFileHandleOp::Init(aFileHandle))) {
    2510           0 :     return false;
    2511             :   }
    2512             : 
    2513           0 :   nsCOMPtr<nsIInputStream> inputStream;
    2514             : 
    2515           0 :   const FileRequestData& data = mParams.data();
    2516           0 :   switch (data.type()) {
    2517             :     case FileRequestData::TFileRequestStringData: {
    2518             :       const FileRequestStringData& stringData =
    2519           0 :         data.get_FileRequestStringData();
    2520             : 
    2521           0 :       const nsCString& string = stringData.string();
    2522             : 
    2523             :       nsresult rv =
    2524           0 :         NS_NewCStringInputStream(getter_AddRefs(inputStream), string);
    2525           0 :       if (NS_WARN_IF(NS_FAILED(rv))) {
    2526           0 :         return false;
    2527             :       }
    2528             : 
    2529           0 :       break;
    2530             :     }
    2531             :     case FileRequestData::TFileRequestBlobData: {
    2532             :       const FileRequestBlobData& blobData =
    2533           0 :         data.get_FileRequestBlobData();
    2534             : 
    2535           0 :       RefPtr<BlobImpl> blobImpl = IPCBlobUtils::Deserialize(blobData.blob());
    2536           0 :       if (NS_WARN_IF(!blobImpl)) {
    2537           0 :         return false;
    2538             :       }
    2539             : 
    2540           0 :       IgnoredErrorResult rv;
    2541           0 :       blobImpl->GetInternalStream(getter_AddRefs(inputStream), rv);
    2542           0 :       if (NS_WARN_IF(rv.Failed())) {
    2543           0 :         return false;
    2544             :       }
    2545             : 
    2546           0 :       break;
    2547             :     }
    2548             : 
    2549             :     default:
    2550           0 :       MOZ_CRASH("Should never get here!");
    2551             :   }
    2552             : 
    2553           0 :   mBufferStream = inputStream;
    2554           0 :   mOffset = mParams.offset();
    2555           0 :   mSize = mParams.dataLength();
    2556           0 :   mRead = false;
    2557             : 
    2558           0 :   return true;
    2559             : }
    2560             : 
    2561             : void
    2562           0 : WriteOp::GetResponse(FileRequestResponse& aResponse)
    2563             : {
    2564           0 :   AssertIsOnOwningThread();
    2565           0 :   aResponse = FileRequestWriteResponse();
    2566           0 : }
    2567             : 
    2568           0 : TruncateOp::TruncateOp(FileHandle* aFileHandle,
    2569           0 :                        const FileRequestParams& aParams)
    2570             :   : NormalFileHandleOp(aFileHandle)
    2571           0 :   , mParams(aParams.get_FileRequestTruncateParams())
    2572             : {
    2573           0 :   MOZ_ASSERT(aParams.type() == FileRequestParams::TFileRequestTruncateParams);
    2574           0 : }
    2575             : 
    2576             : nsresult
    2577           0 : TruncateOp::DoFileWork(FileHandle* aFileHandle)
    2578             : {
    2579           0 :   AssertIsOnThreadPool();
    2580             : 
    2581           0 :   nsCOMPtr<nsISeekableStream> sstream = do_QueryInterface(mFileStream);
    2582           0 :   MOZ_ASSERT(sstream);
    2583             : 
    2584           0 :   nsresult rv = sstream->Seek(nsISeekableStream::NS_SEEK_SET, mParams.offset());
    2585           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    2586           0 :     return rv;
    2587             :   }
    2588             : 
    2589           0 :   rv = sstream->SetEOF();
    2590           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    2591           0 :     return rv;
    2592             :   }
    2593             : 
    2594           0 :   return NS_OK;
    2595             : }
    2596             : 
    2597             : void
    2598           0 : TruncateOp::GetResponse(FileRequestResponse& aResponse)
    2599             : {
    2600           0 :   AssertIsOnOwningThread();
    2601           0 :   aResponse = FileRequestTruncateResponse();
    2602           0 : }
    2603             : 
    2604           0 : FlushOp::FlushOp(FileHandle* aFileHandle,
    2605           0 :                  const FileRequestParams& aParams)
    2606             :   : NormalFileHandleOp(aFileHandle)
    2607           0 :   , mParams(aParams.get_FileRequestFlushParams())
    2608             : {
    2609           0 :   MOZ_ASSERT(aParams.type() == FileRequestParams::TFileRequestFlushParams);
    2610           0 : }
    2611             : 
    2612             : nsresult
    2613           0 : FlushOp::DoFileWork(FileHandle* aFileHandle)
    2614             : {
    2615           0 :   AssertIsOnThreadPool();
    2616             : 
    2617           0 :   nsCOMPtr<nsIOutputStream> ostream = do_QueryInterface(mFileStream);
    2618           0 :   MOZ_ASSERT(ostream);
    2619             : 
    2620           0 :   nsresult rv = ostream->Flush();
    2621           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    2622           0 :     return rv;
    2623             :   }
    2624             : 
    2625           0 :   return NS_OK;
    2626             : }
    2627             : 
    2628             : void
    2629           0 : FlushOp::GetResponse(FileRequestResponse& aResponse)
    2630             : {
    2631           0 :   AssertIsOnOwningThread();
    2632           0 :   aResponse = FileRequestFlushResponse();
    2633           0 : }
    2634             : 
    2635           0 : GetFileOp::GetFileOp(FileHandle* aFileHandle,
    2636           0 :                      const FileRequestParams& aParams)
    2637             :   : GetMetadataOp(aFileHandle,
    2638           0 :                   FileRequestGetMetadataParams(true, true))
    2639           0 :   , mBackgroundParent(aFileHandle->GetBackgroundParent())
    2640             : {
    2641           0 :   MOZ_ASSERT(aParams.type() == FileRequestParams::TFileRequestGetFileParams);
    2642           0 :   MOZ_ASSERT(mBackgroundParent);
    2643           0 : }
    2644             : 
    2645             : void
    2646           0 : GetFileOp::GetResponse(FileRequestResponse& aResponse)
    2647             : {
    2648           0 :   AssertIsOnOwningThread();
    2649             : 
    2650           0 :   RefPtr<BlobImpl> blobImpl = mFileHandle->GetMutableFile()->CreateBlobImpl();
    2651           0 :   MOZ_ASSERT(blobImpl);
    2652             : 
    2653             :   PendingIPCBlobParent* actor =
    2654           0 :     PendingIPCBlobParent::Create(mBackgroundParent, blobImpl);
    2655           0 :   if (NS_WARN_IF(!actor)) {
    2656             :     // This can only fail if the child has crashed.
    2657           0 :     aResponse = NS_ERROR_DOM_FILEHANDLE_UNKNOWN_ERR;
    2658           0 :     return;
    2659             :   }
    2660             : 
    2661           0 :   FileRequestGetFileResponse response;
    2662           0 :   response.fileParent() = actor;
    2663           0 :   response.metadata() = mMetadata;
    2664             : 
    2665           0 :   aResponse = response;
    2666             : }
    2667             : 
    2668             : } // namespace dom
    2669             : } // namespace mozilla

Generated by: LCOV version 1.13