123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667 |
- /* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
- #include "ActorsParent.h"
- #include "mozilla/Assertions.h"
- #include "mozilla/Atomics.h"
- #include "mozilla/Attributes.h"
- #include "mozilla/Unused.h"
- #include "mozilla/dom/File.h"
- #include "mozilla/dom/FileHandleCommon.h"
- #include "mozilla/dom/PBackgroundFileHandleParent.h"
- #include "mozilla/dom/PBackgroundFileRequestParent.h"
- #include "mozilla/dom/indexedDB/ActorsParent.h"
- #include "mozilla/dom/ipc/BlobParent.h"
- #include "nsAutoPtr.h"
- #include "nsComponentManagerUtils.h"
- #include "nsDebug.h"
- #include "nsError.h"
- #include "nsIEventTarget.h"
- #include "nsIFileStreams.h"
- #include "nsIInputStream.h"
- #include "nsIOutputStream.h"
- #include "nsIRunnable.h"
- #include "nsISeekableStream.h"
- #include "nsIThread.h"
- #include "nsIThreadPool.h"
- #include "nsNetUtil.h"
- #include "nsStreamUtils.h"
- #include "nsStringStream.h"
- #include "nsTArray.h"
- #include "nsThreadPool.h"
- #include "nsThreadUtils.h"
- #include "nsXPCOMCIDInternal.h"
- #define DISABLE_ASSERTS_FOR_FUZZING 0
- #if DISABLE_ASSERTS_FOR_FUZZING
- #define ASSERT_UNLESS_FUZZING(...) do { } while (0)
- #else
- #define ASSERT_UNLESS_FUZZING(...) MOZ_ASSERT(false, __VA_ARGS__)
- #endif
- namespace mozilla {
- namespace dom {
- using namespace mozilla::ipc;
- namespace {
- /******************************************************************************
- * Constants
- ******************************************************************************/
- const uint32_t kThreadLimit = 5;
- const uint32_t kIdleThreadLimit = 1;
- const uint32_t kIdleThreadTimeoutMs = 30000;
- const uint32_t kStreamCopyBlockSize = 32768;
- } // namespace
- class FileHandleThreadPool::FileHandleQueue final
- : public Runnable
- {
- friend class FileHandleThreadPool;
- RefPtr<FileHandleThreadPool> mOwningFileHandleThreadPool;
- RefPtr<FileHandle> mFileHandle;
- nsTArray<RefPtr<FileHandleOp>> mQueue;
- RefPtr<FileHandleOp> mCurrentOp;
- bool mShouldFinish;
- public:
- explicit
- FileHandleQueue(FileHandleThreadPool* aFileHandleThreadPool,
- FileHandle* aFileHandle);
- void
- Enqueue(FileHandleOp* aFileHandleOp);
- void
- Finish();
- void
- ProcessQueue();
- private:
- ~FileHandleQueue() {}
- NS_DECL_NSIRUNNABLE
- };
- struct FileHandleThreadPool::DelayedEnqueueInfo
- {
- RefPtr<FileHandle> mFileHandle;
- RefPtr<FileHandleOp> mFileHandleOp;
- bool mFinish;
- };
- class FileHandleThreadPool::DirectoryInfo
- {
- friend class FileHandleThreadPool;
- RefPtr<FileHandleThreadPool> mOwningFileHandleThreadPool;
- nsTArray<RefPtr<FileHandleQueue>> mFileHandleQueues;
- nsTArray<DelayedEnqueueInfo> mDelayedEnqueueInfos;
- nsTHashtable<nsStringHashKey> mFilesReading;
- nsTHashtable<nsStringHashKey> mFilesWriting;
- public:
- FileHandleQueue*
- CreateFileHandleQueue(FileHandle* aFileHandle);
- FileHandleQueue*
- GetFileHandleQueue(FileHandle* aFileHandle);
- void
- RemoveFileHandleQueue(FileHandle* aFileHandle);
- bool
- HasRunningFileHandles()
- {
- return !mFileHandleQueues.IsEmpty();
- }
- DelayedEnqueueInfo*
- CreateDelayedEnqueueInfo(FileHandle* aFileHandle,
- FileHandleOp* aFileHandleOp,
- bool aFinish);
- void
- LockFileForReading(const nsAString& aFileName)
- {
- mFilesReading.PutEntry(aFileName);
- }
- void
- LockFileForWriting(const nsAString& aFileName)
- {
- mFilesWriting.PutEntry(aFileName);
- }
- bool
- IsFileLockedForReading(const nsAString& aFileName)
- {
- return mFilesReading.Contains(aFileName);
- }
- bool
- IsFileLockedForWriting(const nsAString& aFileName)
- {
- return mFilesWriting.Contains(aFileName);
- }
- private:
- explicit DirectoryInfo(FileHandleThreadPool* aFileHandleThreadPool)
- : mOwningFileHandleThreadPool(aFileHandleThreadPool)
- { }
- };
- struct FileHandleThreadPool::StoragesCompleteCallback final
- {
- friend class nsAutoPtr<StoragesCompleteCallback>;
- nsTArray<nsCString> mDirectoryIds;
- nsCOMPtr<nsIRunnable> mCallback;
- StoragesCompleteCallback(nsTArray<nsCString>&& aDatabaseIds,
- nsIRunnable* aCallback);
- private:
- ~StoragesCompleteCallback();
- };
- /******************************************************************************
- * Actor class declarations
- ******************************************************************************/
- class FileHandle
- : public PBackgroundFileHandleParent
- {
- friend class BackgroundMutableFileParentBase;
- class FinishOp;
- RefPtr<BackgroundMutableFileParentBase> mMutableFile;
- nsCOMPtr<nsISupports> mStream;
- uint64_t mActiveRequestCount;
- FileHandleStorage mStorage;
- Atomic<bool> mInvalidatedOnAnyThread;
- FileMode mMode;
- bool mHasBeenActive;
- bool mActorDestroyed;
- bool mInvalidated;
- bool mAborted;
- bool mFinishOrAbortReceived;
- bool mFinishedOrAborted;
- bool mForceAborted;
- DEBUGONLY(nsCOMPtr<nsIEventTarget> mThreadPoolEventTarget;)
- public:
- void
- AssertIsOnThreadPool() const;
- bool
- IsActorDestroyed() const
- {
- AssertIsOnBackgroundThread();
- return mActorDestroyed;
- }
- // Must be called on the background thread.
- bool
- IsInvalidated() const
- {
- MOZ_ASSERT(IsOnBackgroundThread(), "Use IsInvalidatedOnAnyThread()");
- MOZ_ASSERT_IF(mInvalidated, mAborted);
- return mInvalidated;
- }
- // May be called on any thread, but is more expensive than IsInvalidated().
- bool
- IsInvalidatedOnAnyThread() const
- {
- return mInvalidatedOnAnyThread;
- }
- void
- SetActive()
- {
- AssertIsOnBackgroundThread();
- mHasBeenActive = true;
- }
- NS_INLINE_DECL_THREADSAFE_REFCOUNTING(mozilla::dom::FileHandle)
- nsresult
- GetOrCreateStream(nsISupports** aStream);
- void
- Abort(bool aForce);
- FileHandleStorage
- Storage() const
- {
- return mStorage;
- }
- FileMode
- Mode() const
- {
- return mMode;
- }
- BackgroundMutableFileParentBase*
- GetMutableFile() const
- {
- AssertIsOnBackgroundThread();
- MOZ_ASSERT(mMutableFile);
- return mMutableFile;
- }
- bool
- IsAborted() const
- {
- AssertIsOnBackgroundThread();
- return mAborted;
- }
- PBackgroundParent*
- GetBackgroundParent() const
- {
- AssertIsOnBackgroundThread();
- MOZ_ASSERT(!IsActorDestroyed());
- return GetMutableFile()->GetBackgroundParent();
- }
- void
- NoteActiveRequest();
- void
- NoteFinishedRequest();
- void
- Invalidate();
- private:
- // This constructor is only called by BackgroundMutableFileParentBase.
- FileHandle(BackgroundMutableFileParentBase* aMutableFile,
- FileMode aMode);
- // Reference counted.
- ~FileHandle();
- void
- MaybeFinishOrAbort()
- {
- AssertIsOnBackgroundThread();
- // If we've already finished or aborted then there's nothing else to do.
- if (mFinishedOrAborted) {
- return;
- }
- // If there are active requests then we have to wait for those requests to
- // complete (see NoteFinishedRequest).
- if (mActiveRequestCount) {
- return;
- }
- // If we haven't yet received a finish or abort message then there could be
- // additional requests coming so we should wait unless we're being forced to
- // abort.
- if (!mFinishOrAbortReceived && !mForceAborted) {
- return;
- }
- FinishOrAbort();
- }
- void
- SendCompleteNotification(bool aAborted);
- bool
- VerifyRequestParams(const FileRequestParams& aParams) const;
- bool
- VerifyRequestData(const FileRequestData& aData) const;
- void
- FinishOrAbort();
- // IPDL methods are only called by IPDL.
- virtual void
- ActorDestroy(ActorDestroyReason aWhy) override;
- virtual bool
- RecvDeleteMe() override;
- virtual bool
- RecvFinish() override;
- virtual bool
- RecvAbort() override;
- virtual PBackgroundFileRequestParent*
- AllocPBackgroundFileRequestParent(const FileRequestParams& aParams) override;
- virtual bool
- RecvPBackgroundFileRequestConstructor(PBackgroundFileRequestParent* aActor,
- const FileRequestParams& aParams)
- override;
- virtual bool
- DeallocPBackgroundFileRequestParent(PBackgroundFileRequestParent* aActor)
- override;
- };
- class FileHandleOp
- {
- protected:
- nsCOMPtr<nsIEventTarget> mOwningThread;
- RefPtr<FileHandle> mFileHandle;
- public:
- NS_INLINE_DECL_THREADSAFE_REFCOUNTING(FileHandleOp)
- void
- AssertIsOnOwningThread() const
- {
- AssertIsOnBackgroundThread();
- MOZ_ASSERT(mOwningThread);
- DebugOnly<bool> current;
- MOZ_ASSERT(NS_SUCCEEDED(mOwningThread->IsOnCurrentThread(¤t)));
- MOZ_ASSERT(current);
- }
- nsIEventTarget*
- OwningThread() const
- {
- return mOwningThread;
- }
- void
- AssertIsOnThreadPool() const
- {
- MOZ_ASSERT(mFileHandle);
- mFileHandle->AssertIsOnThreadPool();
- }
- void
- Enqueue();
- virtual void
- RunOnThreadPool() = 0;
- virtual void
- RunOnOwningThread() = 0;
- protected:
- FileHandleOp(FileHandle* aFileHandle)
- : mOwningThread(NS_GetCurrentThread())
- , mFileHandle(aFileHandle)
- {
- AssertIsOnOwningThread();
- MOZ_ASSERT(aFileHandle);
- }
- virtual
- ~FileHandleOp()
- { }
- };
- class FileHandle::FinishOp
- : public FileHandleOp
- {
- friend class FileHandle;
- bool mAborted;
- private:
- FinishOp(FileHandle* aFileHandle,
- bool aAborted)
- : FileHandleOp(aFileHandle)
- , mAborted(aAborted)
- {
- MOZ_ASSERT(aFileHandle);
- }
- ~FinishOp()
- { }
- virtual void
- RunOnThreadPool() override;
- virtual void
- RunOnOwningThread() override;
- };
- class NormalFileHandleOp
- : public FileHandleOp
- , public PBackgroundFileRequestParent
- {
- nsresult mResultCode;
- Atomic<bool> mOperationMayProceed;
- bool mActorDestroyed;
- const bool mFileHandleIsAborted;
- DEBUGONLY(bool mResponseSent;)
- protected:
- nsCOMPtr<nsISupports> mFileStream;
- public:
- void
- NoteActorDestroyed()
- {
- AssertIsOnOwningThread();
- mActorDestroyed = true;
- mOperationMayProceed = false;
- }
- bool
- IsActorDestroyed() const
- {
- AssertIsOnOwningThread();
- return mActorDestroyed;
- }
- // May be called on any thread, but you should call IsActorDestroyed() if
- // you know you're on the background thread because it is slightly faster.
- bool
- OperationMayProceed() const
- {
- return mOperationMayProceed;
- }
- // May be overridden by subclasses if they need to perform work on the
- // background thread before being enqueued. Returning false will kill the
- // child actors and prevent enqueue.
- virtual bool
- Init(FileHandle* aFileHandle);
- // This callback will be called on the background thread before releasing the
- // final reference to this request object. Subclasses may perform any
- // additional cleanup here but must always call the base class implementation.
- virtual void
- Cleanup();
- protected:
- NormalFileHandleOp(FileHandle* aFileHandle)
- : FileHandleOp(aFileHandle)
- , mResultCode(NS_OK)
- , mOperationMayProceed(true)
- , mActorDestroyed(false)
- , mFileHandleIsAborted(aFileHandle->IsAborted())
- DEBUGONLY(, mResponseSent(false))
- {
- MOZ_ASSERT(aFileHandle);
- }
- virtual
- ~NormalFileHandleOp();
- // Must be overridden in subclasses. Called on the target thread to allow the
- // subclass to perform necessary file operations. A successful return value
- // will trigger a SendSuccessResult callback on the background thread while
- // a failure value will trigger a SendFailureResult callback.
- virtual nsresult
- DoFileWork(FileHandle* aFileHandle) = 0;
- // Subclasses use this override to set the IPDL response value.
- virtual void
- GetResponse(FileRequestResponse& aResponse) = 0;
- private:
- nsresult
- SendSuccessResult();
- bool
- SendFailureResult(nsresult aResultCode);
- virtual void
- RunOnThreadPool() override;
- virtual void
- RunOnOwningThread() override;
- // IPDL methods.
- virtual void
- ActorDestroy(ActorDestroyReason aWhy) override;
- };
- class CopyFileHandleOp
- : public NormalFileHandleOp
- {
- class ProgressRunnable;
- protected:
- nsCOMPtr<nsISupports> mBufferStream;
- uint64_t mOffset;
- uint64_t mSize;
- bool mRead;
- protected:
- CopyFileHandleOp(FileHandle* aFileHandle)
- : NormalFileHandleOp(aFileHandle)
- , mOffset(0)
- , mSize(0)
- , mRead(true)
- { }
- virtual nsresult
- DoFileWork(FileHandle* aFileHandle) override;
- virtual void
- Cleanup() override;
- };
- class CopyFileHandleOp::ProgressRunnable final
- : public Runnable
- {
- RefPtr<CopyFileHandleOp> mCopyFileHandleOp;
- uint64_t mProgress;
- uint64_t mProgressMax;
- public:
- ProgressRunnable(CopyFileHandleOp* aCopyFileHandleOp,
- uint64_t aProgress,
- uint64_t aProgressMax)
- : mCopyFileHandleOp(aCopyFileHandleOp)
- , mProgress(aProgress)
- , mProgressMax(aProgressMax)
- { }
- private:
- ~ProgressRunnable() {}
- NS_DECL_NSIRUNNABLE
- };
- class GetMetadataOp
- : public NormalFileHandleOp
- {
- friend class FileHandle;
- const FileRequestGetMetadataParams mParams;
- protected:
- FileRequestMetadata mMetadata;
- protected:
- // Only created by FileHandle.
- GetMetadataOp(FileHandle* aFileHandle,
- const FileRequestParams& aParams);
- ~GetMetadataOp()
- { }
- virtual nsresult
- DoFileWork(FileHandle* aFileHandle) override;
- virtual void
- GetResponse(FileRequestResponse& aResponse) override;
- };
- class ReadOp final
- : public CopyFileHandleOp
- {
- friend class FileHandle;
- class MemoryOutputStream;
- const FileRequestReadParams mParams;
- private:
- // Only created by FileHandle.
- ReadOp(FileHandle* aFileHandle,
- const FileRequestParams& aParams);
- ~ReadOp()
- { }
- virtual bool
- Init(FileHandle* aFileHandle) override;
- virtual void
- GetResponse(FileRequestResponse& aResponse) override;
- };
- class ReadOp::MemoryOutputStream final
- : public nsIOutputStream
- {
- nsCString mData;
- uint64_t mOffset;
- public:
- static already_AddRefed<MemoryOutputStream>
- Create(uint64_t aSize);
- const nsCString&
- Data() const
- {
- return mData;
- }
- private:
- MemoryOutputStream()
- : mOffset(0)
- { }
- virtual ~MemoryOutputStream()
- { }
- NS_DECL_THREADSAFE_ISUPPORTS
- NS_DECL_NSIOUTPUTSTREAM
- };
- class WriteOp final
- : public CopyFileHandleOp
- {
- friend class FileHandle;
- const FileRequestWriteParams mParams;
- private:
- // Only created by FileHandle.
- WriteOp(FileHandle* aFileHandle,
- const FileRequestParams& aParams);
- ~WriteOp()
- { }
- virtual bool
- Init(FileHandle* aFileHandle) override;
- virtual void
- GetResponse(FileRequestResponse& aResponse) override;
- };
- class TruncateOp final
- : public NormalFileHandleOp
- {
- friend class FileHandle;
- const FileRequestTruncateParams mParams;
- private:
- // Only created by FileHandle.
- TruncateOp(FileHandle* aFileHandle,
- const FileRequestParams& aParams);
- ~TruncateOp()
- { }
- virtual nsresult
- DoFileWork(FileHandle* aFileHandle) override;
- virtual void
- GetResponse(FileRequestResponse& aResponse) override;
- };
- class FlushOp final
- : public NormalFileHandleOp
- {
- friend class FileHandle;
- const FileRequestFlushParams mParams;
- private:
- // Only created by FileHandle.
- FlushOp(FileHandle* aFileHandle,
- const FileRequestParams& aParams);
- ~FlushOp()
- { }
- virtual nsresult
- DoFileWork(FileHandle* aFileHandle) override;
- virtual void
- GetResponse(FileRequestResponse& aResponse) override;
- };
- class GetFileOp final
- : public GetMetadataOp
- {
- friend class FileHandle;
- PBackgroundParent* mBackgroundParent;
- private:
- // Only created by FileHandle.
- GetFileOp(FileHandle* aFileHandle,
- const FileRequestParams& aParams);
- ~GetFileOp()
- { }
- virtual void
- GetResponse(FileRequestResponse& aResponse) override;
- };
- namespace {
- /*******************************************************************************
- * Helper Functions
- ******************************************************************************/
- FileHandleThreadPool*
- GetFileHandleThreadPoolFor(FileHandleStorage aStorage)
- {
- switch (aStorage) {
- case FILE_HANDLE_STORAGE_IDB:
- return mozilla::dom::indexedDB::GetFileHandleThreadPool();
- default:
- MOZ_CRASH("Bad file handle storage value!");
- }
- }
- } // namespace
- /*******************************************************************************
- * FileHandleThreadPool implementation
- ******************************************************************************/
- FileHandleThreadPool::FileHandleThreadPool()
- : mOwningThread(NS_GetCurrentThread())
- , mShutdownRequested(false)
- , mShutdownComplete(false)
- {
- AssertIsOnBackgroundThread();
- MOZ_ASSERT(mOwningThread);
- AssertIsOnOwningThread();
- }
- FileHandleThreadPool::~FileHandleThreadPool()
- {
- AssertIsOnOwningThread();
- MOZ_ASSERT(!mDirectoryInfos.Count());
- MOZ_ASSERT(mCompleteCallbacks.IsEmpty());
- MOZ_ASSERT(mShutdownRequested);
- MOZ_ASSERT(mShutdownComplete);
- }
- // static
- already_AddRefed<FileHandleThreadPool>
- FileHandleThreadPool::Create()
- {
- AssertIsOnBackgroundThread();
- RefPtr<FileHandleThreadPool> fileHandleThreadPool =
- new FileHandleThreadPool();
- fileHandleThreadPool->AssertIsOnOwningThread();
- if (NS_WARN_IF(NS_FAILED(fileHandleThreadPool->Init()))) {
- return nullptr;
- }
- return fileHandleThreadPool.forget();
- }
- #ifdef DEBUG
- void
- FileHandleThreadPool::AssertIsOnOwningThread() const
- {
- MOZ_ASSERT(mOwningThread);
- bool current;
- MOZ_ALWAYS_SUCCEEDS(mOwningThread->IsOnCurrentThread(¤t));
- MOZ_ASSERT(current);
- }
- nsIEventTarget*
- FileHandleThreadPool::GetThreadPoolEventTarget() const
- {
- AssertIsOnOwningThread();
- MOZ_ASSERT(mThreadPool);
- return mThreadPool;
- }
- #endif // DEBUG
- void
- FileHandleThreadPool::Enqueue(FileHandle* aFileHandle,
- FileHandleOp* aFileHandleOp,
- bool aFinish)
- {
- AssertIsOnOwningThread();
- MOZ_ASSERT(aFileHandle);
- MOZ_ASSERT(!mShutdownRequested);
- BackgroundMutableFileParentBase* mutableFile = aFileHandle->GetMutableFile();
- const nsACString& directoryId = mutableFile->DirectoryId();
- const nsAString& fileName = mutableFile->FileName();
- bool modeIsWrite = aFileHandle->Mode() == FileMode::Readwrite;
- DirectoryInfo* directoryInfo;
- if (!mDirectoryInfos.Get(directoryId, &directoryInfo)) {
- nsAutoPtr<DirectoryInfo> newDirectoryInfo(new DirectoryInfo(this));
- mDirectoryInfos.Put(directoryId, newDirectoryInfo);
- directoryInfo = newDirectoryInfo.forget();
- }
- FileHandleQueue* existingFileHandleQueue =
- directoryInfo->GetFileHandleQueue(aFileHandle);
- if (existingFileHandleQueue) {
- existingFileHandleQueue->Enqueue(aFileHandleOp);
- if (aFinish) {
- existingFileHandleQueue->Finish();
- }
- return;
- }
- bool lockedForReading = directoryInfo->IsFileLockedForReading(fileName);
- bool lockedForWriting = directoryInfo->IsFileLockedForWriting(fileName);
- if (modeIsWrite) {
- if (!lockedForWriting) {
- directoryInfo->LockFileForWriting(fileName);
- }
- }
- else {
- if (!lockedForReading) {
- directoryInfo->LockFileForReading(fileName);
- }
- }
- if (lockedForWriting || (lockedForReading && modeIsWrite)) {
- directoryInfo->CreateDelayedEnqueueInfo(aFileHandle,
- aFileHandleOp,
- aFinish);
- }
- else {
- FileHandleQueue* fileHandleQueue =
- directoryInfo->CreateFileHandleQueue(aFileHandle);
- if (aFileHandleOp) {
- fileHandleQueue->Enqueue(aFileHandleOp);
- if (aFinish) {
- fileHandleQueue->Finish();
- }
- }
- }
- }
- void
- FileHandleThreadPool::WaitForDirectoriesToComplete(
- nsTArray<nsCString>&& aDirectoryIds,
- nsIRunnable* aCallback)
- {
- AssertIsOnOwningThread();
- MOZ_ASSERT(!aDirectoryIds.IsEmpty());
- MOZ_ASSERT(aCallback);
- nsAutoPtr<StoragesCompleteCallback> callback(
- new StoragesCompleteCallback(Move(aDirectoryIds), aCallback));
- if (!MaybeFireCallback(callback)) {
- mCompleteCallbacks.AppendElement(callback.forget());
- }
- }
- void
- FileHandleThreadPool::Shutdown()
- {
- AssertIsOnOwningThread();
- MOZ_ASSERT(!mShutdownRequested);
- MOZ_ASSERT(!mShutdownComplete);
- mShutdownRequested = true;
- if (!mThreadPool) {
- MOZ_ASSERT(!mDirectoryInfos.Count());
- MOZ_ASSERT(mCompleteCallbacks.IsEmpty());
- mShutdownComplete = true;
- return;
- }
- if (!mDirectoryInfos.Count()) {
- Cleanup();
- MOZ_ASSERT(mShutdownComplete);
- return;
- }
- nsIThread* currentThread = NS_GetCurrentThread();
- MOZ_ASSERT(currentThread);
- while (!mShutdownComplete) {
- MOZ_ALWAYS_TRUE(NS_ProcessNextEvent(currentThread));
- }
- }
- nsresult
- FileHandleThreadPool::Init()
- {
- AssertIsOnOwningThread();
- mThreadPool = new nsThreadPool();
- nsresult rv = mThreadPool->SetName(NS_LITERAL_CSTRING("FileHandles"));
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
- rv = mThreadPool->SetThreadLimit(kThreadLimit);
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
- rv = mThreadPool->SetIdleThreadLimit(kIdleThreadLimit);
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
- rv = mThreadPool->SetIdleThreadTimeout(kIdleThreadTimeoutMs);
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
- return NS_OK;
- }
- void
- FileHandleThreadPool::Cleanup()
- {
- AssertIsOnOwningThread();
- MOZ_ASSERT(mThreadPool);
- MOZ_ASSERT(mShutdownRequested);
- MOZ_ASSERT(!mShutdownComplete);
- MOZ_ASSERT(!mDirectoryInfos.Count());
- MOZ_ALWAYS_SUCCEEDS(mThreadPool->Shutdown());
- if (!mCompleteCallbacks.IsEmpty()) {
- // Run all callbacks manually now.
- for (uint32_t count = mCompleteCallbacks.Length(), index = 0;
- index < count;
- index++) {
- nsAutoPtr<StoragesCompleteCallback> completeCallback(
- mCompleteCallbacks[index].forget());
- MOZ_ASSERT(completeCallback);
- MOZ_ASSERT(completeCallback->mCallback);
- Unused << completeCallback->mCallback->Run();
- }
- mCompleteCallbacks.Clear();
- // And make sure they get processed.
- nsIThread* currentThread = NS_GetCurrentThread();
- MOZ_ASSERT(currentThread);
- MOZ_ALWAYS_SUCCEEDS(NS_ProcessPendingEvents(currentThread));
- }
- mShutdownComplete = true;
- }
- void
- FileHandleThreadPool::FinishFileHandle(FileHandle* aFileHandle)
- {
- AssertIsOnOwningThread();
- MOZ_ASSERT(aFileHandle);
- BackgroundMutableFileParentBase* mutableFile = aFileHandle->GetMutableFile();
- const nsACString& directoryId = mutableFile->DirectoryId();
- DirectoryInfo* directoryInfo;
- if (!mDirectoryInfos.Get(directoryId, &directoryInfo)) {
- NS_ERROR("We don't know anyting about this directory?!");
- return;
- }
- directoryInfo->RemoveFileHandleQueue(aFileHandle);
- if (!directoryInfo->HasRunningFileHandles()) {
- mDirectoryInfos.Remove(directoryId);
- // See if we need to fire any complete callbacks.
- uint32_t index = 0;
- while (index < mCompleteCallbacks.Length()) {
- if (MaybeFireCallback(mCompleteCallbacks[index])) {
- mCompleteCallbacks.RemoveElementAt(index);
- }
- else {
- index++;
- }
- }
- if (mShutdownRequested && !mDirectoryInfos.Count()) {
- Cleanup();
- }
- }
- }
- bool
- FileHandleThreadPool::MaybeFireCallback(StoragesCompleteCallback* aCallback)
- {
- AssertIsOnOwningThread();
- MOZ_ASSERT(aCallback);
- MOZ_ASSERT(!aCallback->mDirectoryIds.IsEmpty());
- MOZ_ASSERT(aCallback->mCallback);
- for (uint32_t count = aCallback->mDirectoryIds.Length(), index = 0;
- index < count;
- index++) {
- const nsCString& directoryId = aCallback->mDirectoryIds[index];
- MOZ_ASSERT(!directoryId.IsEmpty());
- if (mDirectoryInfos.Get(directoryId, nullptr)) {
- return false;
- }
- }
- aCallback->mCallback->Run();
- return true;
- }
- FileHandleThreadPool::
- FileHandleQueue::FileHandleQueue(FileHandleThreadPool* aFileHandleThreadPool,
- FileHandle* aFileHandle)
- : mOwningFileHandleThreadPool(aFileHandleThreadPool)
- , mFileHandle(aFileHandle)
- , mShouldFinish(false)
- {
- MOZ_ASSERT(aFileHandleThreadPool);
- aFileHandleThreadPool->AssertIsOnOwningThread();
- MOZ_ASSERT(aFileHandle);
- }
- void
- FileHandleThreadPool::
- FileHandleQueue::Enqueue(FileHandleOp* aFileHandleOp)
- {
- MOZ_ASSERT(!mShouldFinish, "Enqueue called after Finish!");
- mQueue.AppendElement(aFileHandleOp);
- ProcessQueue();
- }
- void
- FileHandleThreadPool::
- FileHandleQueue::Finish()
- {
- MOZ_ASSERT(!mShouldFinish, "Finish called more than once!");
- mShouldFinish = true;
- }
- void
- FileHandleThreadPool::
- FileHandleQueue::ProcessQueue()
- {
- if (mCurrentOp) {
- return;
- }
- if (mQueue.IsEmpty()) {
- if (mShouldFinish) {
- mOwningFileHandleThreadPool->FinishFileHandle(mFileHandle);
- // Make sure this is released on this thread.
- mOwningFileHandleThreadPool = nullptr;
- }
- return;
- }
- mCurrentOp = mQueue[0];
- mQueue.RemoveElementAt(0);
- nsCOMPtr<nsIThreadPool> threadPool = mOwningFileHandleThreadPool->mThreadPool;
- MOZ_ASSERT(threadPool);
- MOZ_ALWAYS_SUCCEEDS(threadPool->Dispatch(this, NS_DISPATCH_NORMAL));
- }
- NS_IMETHODIMP
- FileHandleThreadPool::
- FileHandleQueue::Run()
- {
- MOZ_ASSERT(mCurrentOp);
- if (IsOnBackgroundThread()) {
- RefPtr<FileHandleOp> currentOp;
- mCurrentOp.swap(currentOp);
- ProcessQueue();
- currentOp->RunOnOwningThread();
- } else {
- mCurrentOp->RunOnThreadPool();
- nsCOMPtr<nsIEventTarget> backgroundThread = mCurrentOp->OwningThread();
- MOZ_ALWAYS_SUCCEEDS(
- backgroundThread->Dispatch(this, NS_DISPATCH_NORMAL));
- }
- return NS_OK;
- }
- auto
- FileHandleThreadPool::
- DirectoryInfo::CreateFileHandleQueue(FileHandle* aFileHandle)
- -> FileHandleQueue*
- {
- RefPtr<FileHandleQueue>* fileHandleQueue =
- mFileHandleQueues.AppendElement();
- *fileHandleQueue = new FileHandleQueue(mOwningFileHandleThreadPool,
- aFileHandle);
- return fileHandleQueue->get();
- }
- auto
- FileHandleThreadPool::
- DirectoryInfo::GetFileHandleQueue(FileHandle* aFileHandle) -> FileHandleQueue*
- {
- uint32_t count = mFileHandleQueues.Length();
- for (uint32_t index = 0; index < count; index++) {
- RefPtr<FileHandleQueue>& fileHandleQueue = mFileHandleQueues[index];
- if (fileHandleQueue->mFileHandle == aFileHandle) {
- return fileHandleQueue;
- }
- }
- return nullptr;
- }
- void
- FileHandleThreadPool::
- DirectoryInfo::RemoveFileHandleQueue(FileHandle* aFileHandle)
- {
- for (uint32_t index = 0; index < mDelayedEnqueueInfos.Length(); index++) {
- if (mDelayedEnqueueInfos[index].mFileHandle == aFileHandle) {
- MOZ_ASSERT(!mDelayedEnqueueInfos[index].mFileHandleOp, "Should be null!");
- mDelayedEnqueueInfos.RemoveElementAt(index);
- return;
- }
- }
- uint32_t fileHandleCount = mFileHandleQueues.Length();
- // We can't just remove entries from lock hash tables, we have to rebuild
- // them instead. Multiple FileHandle objects may lock the same file
- // (one entry can represent multiple locks).
- mFilesReading.Clear();
- mFilesWriting.Clear();
- for (uint32_t index = 0, count = fileHandleCount; index < count; index++) {
- FileHandle* fileHandle = mFileHandleQueues[index]->mFileHandle;
- if (fileHandle == aFileHandle) {
- MOZ_ASSERT(count == fileHandleCount, "More than one match?!");
- mFileHandleQueues.RemoveElementAt(index);
- index--;
- count--;
- continue;
- }
- const nsAString& fileName = fileHandle->GetMutableFile()->FileName();
- if (fileHandle->Mode() == FileMode::Readwrite) {
- if (!IsFileLockedForWriting(fileName)) {
- LockFileForWriting(fileName);
- }
- }
- else {
- if (!IsFileLockedForReading(fileName)) {
- LockFileForReading(fileName);
- }
- }
- }
- MOZ_ASSERT(mFileHandleQueues.Length() == fileHandleCount - 1,
- "Didn't find the file handle we were looking for!");
- nsTArray<DelayedEnqueueInfo> delayedEnqueueInfos;
- delayedEnqueueInfos.SwapElements(mDelayedEnqueueInfos);
- for (uint32_t index = 0; index < delayedEnqueueInfos.Length(); index++) {
- DelayedEnqueueInfo& delayedEnqueueInfo = delayedEnqueueInfos[index];
- mOwningFileHandleThreadPool->Enqueue(delayedEnqueueInfo.mFileHandle,
- delayedEnqueueInfo.mFileHandleOp,
- delayedEnqueueInfo.mFinish);
- }
- }
- auto
- FileHandleThreadPool::
- DirectoryInfo::CreateDelayedEnqueueInfo(FileHandle* aFileHandle,
- FileHandleOp* aFileHandleOp,
- bool aFinish) -> DelayedEnqueueInfo*
- {
- DelayedEnqueueInfo* info = mDelayedEnqueueInfos.AppendElement();
- info->mFileHandle = aFileHandle;
- info->mFileHandleOp = aFileHandleOp;
- info->mFinish = aFinish;
- return info;
- }
- FileHandleThreadPool::
- StoragesCompleteCallback::StoragesCompleteCallback(
- nsTArray<nsCString>&& aDirectoryIds,
- nsIRunnable* aCallback)
- : mDirectoryIds(Move(aDirectoryIds))
- , mCallback(aCallback)
- {
- AssertIsOnBackgroundThread();
- MOZ_ASSERT(!mDirectoryIds.IsEmpty());
- MOZ_ASSERT(aCallback);
- MOZ_COUNT_CTOR(FileHandleThreadPool::StoragesCompleteCallback);
- }
- FileHandleThreadPool::
- StoragesCompleteCallback::~StoragesCompleteCallback()
- {
- AssertIsOnBackgroundThread();
- MOZ_COUNT_DTOR(FileHandleThreadPool::StoragesCompleteCallback);
- }
- /*******************************************************************************
- * BackgroundMutableFileParentBase
- ******************************************************************************/
- BackgroundMutableFileParentBase::BackgroundMutableFileParentBase(
- FileHandleStorage aStorage,
- const nsACString& aDirectoryId,
- const nsAString& aFileName,
- nsIFile* aFile)
- : mDirectoryId(aDirectoryId)
- , mFileName(aFileName)
- , mStorage(aStorage)
- , mInvalidated(false)
- , mActorWasAlive(false)
- , mActorDestroyed(false)
- , mFile(aFile)
- {
- AssertIsOnBackgroundThread();
- MOZ_ASSERT(aStorage != FILE_HANDLE_STORAGE_MAX);
- MOZ_ASSERT(!aDirectoryId.IsEmpty());
- MOZ_ASSERT(!aFileName.IsEmpty());
- MOZ_ASSERT(aFile);
- }
- BackgroundMutableFileParentBase::~BackgroundMutableFileParentBase()
- {
- MOZ_ASSERT_IF(mActorWasAlive, mActorDestroyed);
- }
- void
- BackgroundMutableFileParentBase::Invalidate()
- {
- AssertIsOnBackgroundThread();
- class MOZ_STACK_CLASS Helper final
- {
- public:
- static bool
- InvalidateFileHandles(nsTHashtable<nsPtrHashKey<FileHandle>>& aTable)
- {
- AssertIsOnBackgroundThread();
- const uint32_t count = aTable.Count();
- if (!count) {
- return true;
- }
- FallibleTArray<RefPtr<FileHandle>> fileHandles;
- if (NS_WARN_IF(!fileHandles.SetCapacity(count, fallible))) {
- return false;
- }
- for (auto iter = aTable.Iter(); !iter.Done(); iter.Next()) {
- if (NS_WARN_IF(!fileHandles.AppendElement(iter.Get()->GetKey(),
- fallible))) {
- return false;
- }
- }
- if (count) {
- for (uint32_t index = 0; index < count; index++) {
- RefPtr<FileHandle> fileHandle = fileHandles[index].forget();
- MOZ_ASSERT(fileHandle);
- fileHandle->Invalidate();
- }
- }
- return true;
- }
- };
- if (mInvalidated) {
- return;
- }
- mInvalidated = true;
- if (!Helper::InvalidateFileHandles(mFileHandles)) {
- NS_WARNING("Failed to abort all file handles!");
- }
- }
- bool
- BackgroundMutableFileParentBase::RegisterFileHandle(FileHandle* aFileHandle)
- {
- AssertIsOnBackgroundThread();
- MOZ_ASSERT(aFileHandle);
- MOZ_ASSERT(!mFileHandles.GetEntry(aFileHandle));
- MOZ_ASSERT(!mInvalidated);
- if (NS_WARN_IF(!mFileHandles.PutEntry(aFileHandle, fallible))) {
- return false;
- }
- if (mFileHandles.Count() == 1) {
- NoteActiveState();
- }
- return true;
- }
- void
- BackgroundMutableFileParentBase::UnregisterFileHandle(FileHandle* aFileHandle)
- {
- AssertIsOnBackgroundThread();
- MOZ_ASSERT(aFileHandle);
- MOZ_ASSERT(mFileHandles.GetEntry(aFileHandle));
- mFileHandles.RemoveEntry(aFileHandle);
- if (!mFileHandles.Count()) {
- NoteInactiveState();
- }
- }
- void
- BackgroundMutableFileParentBase::SetActorAlive()
- {
- AssertIsOnBackgroundThread();
- MOZ_ASSERT(!mActorWasAlive);
- MOZ_ASSERT(!mActorDestroyed);
- mActorWasAlive = true;
- // This reference will be absorbed by IPDL and released when the actor is
- // destroyed.
- AddRef();
- }
- already_AddRefed<nsISupports>
- BackgroundMutableFileParentBase::CreateStream(bool aReadOnly)
- {
- AssertIsOnBackgroundThread();
- nsresult rv;
- if (aReadOnly) {
- nsCOMPtr<nsIInputStream> stream;
- rv = NS_NewLocalFileInputStream(getter_AddRefs(stream), mFile, -1, -1,
- nsIFileInputStream::DEFER_OPEN);
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return nullptr;
- }
- return stream.forget();
- }
- nsCOMPtr<nsIFileStream> stream;
- rv = NS_NewLocalFileStream(getter_AddRefs(stream), mFile, -1, -1,
- nsIFileStream::DEFER_OPEN);
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return nullptr;
- }
- return stream.forget();
- }
- void
- BackgroundMutableFileParentBase::ActorDestroy(ActorDestroyReason aWhy)
- {
- AssertIsOnBackgroundThread();
- MOZ_ASSERT(!mActorDestroyed);
- mActorDestroyed = true;
- if (!IsInvalidated()) {
- Invalidate();
- }
- }
- PBackgroundFileHandleParent*
- BackgroundMutableFileParentBase::AllocPBackgroundFileHandleParent(
- const FileMode& aMode)
- {
- AssertIsOnBackgroundThread();
- if (NS_WARN_IF(aMode != FileMode::Readonly &&
- aMode != FileMode::Readwrite)) {
- ASSERT_UNLESS_FUZZING();
- return nullptr;
- }
- RefPtr<FileHandle> fileHandle = new FileHandle(this, aMode);
- return fileHandle.forget().take();
- }
- bool
- BackgroundMutableFileParentBase::RecvPBackgroundFileHandleConstructor(
- PBackgroundFileHandleParent* aActor,
- const FileMode& aMode)
- {
- AssertIsOnBackgroundThread();
- MOZ_ASSERT(aActor);
- MOZ_ASSERT(aMode == FileMode::Readonly || aMode == FileMode::Readwrite);
- FileHandleThreadPool* fileHandleThreadPool =
- GetFileHandleThreadPoolFor(mStorage);
- MOZ_ASSERT(fileHandleThreadPool);
- auto* fileHandle = static_cast<FileHandle*>(aActor);
- // Add a placeholder for this file handle immediately.
- fileHandleThreadPool->Enqueue(fileHandle, nullptr, false);
- fileHandle->SetActive();
- if (NS_WARN_IF(!RegisterFileHandle(fileHandle))) {
- fileHandle->Abort(/* aForce */ false);
- return true;
- }
- return true;
- }
- bool
- BackgroundMutableFileParentBase::DeallocPBackgroundFileHandleParent(
- PBackgroundFileHandleParent* aActor)
- {
- AssertIsOnBackgroundThread();
- MOZ_ASSERT(aActor);
- RefPtr<FileHandle> fileHandle =
- dont_AddRef(static_cast<FileHandle*>(aActor));
- return true;
- }
- bool
- BackgroundMutableFileParentBase::RecvDeleteMe()
- {
- AssertIsOnBackgroundThread();
- MOZ_ASSERT(!mActorDestroyed);
- return PBackgroundMutableFileParent::Send__delete__(this);
- }
- bool
- BackgroundMutableFileParentBase::RecvGetFileId(int64_t* aFileId)
- {
- AssertIsOnBackgroundThread();
- *aFileId = -1;
- return true;
- }
- /*******************************************************************************
- * FileHandle
- ******************************************************************************/
- FileHandle::FileHandle(BackgroundMutableFileParentBase* aMutableFile,
- FileMode aMode)
- : mMutableFile(aMutableFile)
- , mActiveRequestCount(0)
- , mStorage(aMutableFile->Storage())
- , mInvalidatedOnAnyThread(false)
- , mMode(aMode)
- , mHasBeenActive(false)
- , mActorDestroyed(false)
- , mInvalidated(false)
- , mAborted(false)
- , mFinishOrAbortReceived(false)
- , mFinishedOrAborted(false)
- , mForceAborted(false)
- {
- AssertIsOnBackgroundThread();
- MOZ_ASSERT(aMutableFile);
- #ifdef DEBUG
- FileHandleThreadPool* fileHandleThreadPool =
- GetFileHandleThreadPoolFor(mStorage);
- MOZ_ASSERT(fileHandleThreadPool);
- mThreadPoolEventTarget = fileHandleThreadPool->GetThreadPoolEventTarget();
- #endif
- }
- FileHandle::~FileHandle()
- {
- MOZ_ASSERT(!mActiveRequestCount);
- MOZ_ASSERT(mActorDestroyed);
- MOZ_ASSERT_IF(mHasBeenActive, mFinishedOrAborted);
- }
- void
- FileHandle::AssertIsOnThreadPool() const
- {
- MOZ_ASSERT(mThreadPoolEventTarget);
- DebugOnly<bool> current;
- MOZ_ASSERT(NS_SUCCEEDED(mThreadPoolEventTarget->IsOnCurrentThread(¤t)));
- MOZ_ASSERT(current);
- }
- nsresult
- FileHandle::GetOrCreateStream(nsISupports** aStream)
- {
- AssertIsOnBackgroundThread();
- if (!mStream) {
- nsCOMPtr<nsISupports> stream =
- mMutableFile->CreateStream(mMode == FileMode::Readonly);
- if (NS_WARN_IF(!stream)) {
- return NS_ERROR_FAILURE;
- }
- stream.swap(mStream);
- }
- nsCOMPtr<nsISupports> stream(mStream);
- stream.forget(aStream);
- return NS_OK;
- }
- void
- FileHandle::Abort(bool aForce)
- {
- AssertIsOnBackgroundThread();
- mAborted = true;
- if (aForce) {
- mForceAborted = true;
- }
- MaybeFinishOrAbort();
- }
- void
- FileHandle::NoteActiveRequest()
- {
- AssertIsOnBackgroundThread();
- MOZ_ASSERT(mActiveRequestCount < UINT64_MAX);
- mActiveRequestCount++;
- }
- void
- FileHandle::NoteFinishedRequest()
- {
- AssertIsOnBackgroundThread();
- MOZ_ASSERT(mActiveRequestCount);
- mActiveRequestCount--;
- MaybeFinishOrAbort();
- }
- void
- FileHandle::Invalidate()
- {
- AssertIsOnBackgroundThread();
- MOZ_ASSERT(mInvalidated == mInvalidatedOnAnyThread);
- if (!mInvalidated) {
- mInvalidated = true;
- mInvalidatedOnAnyThread = true;
- Abort(/* aForce */ true);
- }
- }
- void
- FileHandle::SendCompleteNotification(bool aAborted)
- {
- AssertIsOnBackgroundThread();
- if (!IsActorDestroyed()) {
- Unused << SendComplete(aAborted);
- }
- }
- bool
- FileHandle::VerifyRequestParams(const FileRequestParams& aParams) const
- {
- AssertIsOnBackgroundThread();
- MOZ_ASSERT(aParams.type() != FileRequestParams::T__None);
- switch (aParams.type()) {
- case FileRequestParams::TFileRequestGetMetadataParams: {
- const FileRequestGetMetadataParams& params =
- aParams.get_FileRequestGetMetadataParams();
- if (NS_WARN_IF(!params.size() && !params.lastModified())) {
- ASSERT_UNLESS_FUZZING();
- return false;
- }
- break;
- }
- case FileRequestParams::TFileRequestReadParams: {
- const FileRequestReadParams& params =
- aParams.get_FileRequestReadParams();
- if (NS_WARN_IF(params.offset() == UINT64_MAX)) {
- ASSERT_UNLESS_FUZZING();
- return false;
- }
- if (NS_WARN_IF(!params.size())) {
- ASSERT_UNLESS_FUZZING();
- return false;
- }
- break;
- }
- case FileRequestParams::TFileRequestWriteParams: {
- if (NS_WARN_IF(mMode != FileMode::Readwrite)) {
- ASSERT_UNLESS_FUZZING();
- return false;
- }
- const FileRequestWriteParams& params =
- aParams.get_FileRequestWriteParams();
- if (NS_WARN_IF(!params.dataLength())) {
- ASSERT_UNLESS_FUZZING();
- return false;
- }
- if (NS_WARN_IF(!VerifyRequestData(params.data()))) {
- ASSERT_UNLESS_FUZZING();
- return false;
- }
- break;
- }
- case FileRequestParams::TFileRequestTruncateParams: {
- if (NS_WARN_IF(mMode != FileMode::Readwrite)) {
- ASSERT_UNLESS_FUZZING();
- return false;
- }
- const FileRequestTruncateParams& params =
- aParams.get_FileRequestTruncateParams();
- if (NS_WARN_IF(params.offset() == UINT64_MAX)) {
- ASSERT_UNLESS_FUZZING();
- return false;
- }
- break;
- }
- case FileRequestParams::TFileRequestFlushParams: {
- if (NS_WARN_IF(mMode != FileMode::Readwrite)) {
- ASSERT_UNLESS_FUZZING();
- return false;
- }
- break;
- }
- case FileRequestParams::TFileRequestGetFileParams: {
- break;
- }
- default:
- MOZ_CRASH("Should never get here!");
- }
- return true;
- }
- bool
- FileHandle::VerifyRequestData(const FileRequestData& aData) const
- {
- AssertIsOnBackgroundThread();
- MOZ_ASSERT(aData.type() != FileRequestData::T__None);
- switch (aData.type()) {
- case FileRequestData::TFileRequestStringData: {
- const FileRequestStringData& data =
- aData.get_FileRequestStringData();
- if (NS_WARN_IF(data.string().IsEmpty())) {
- ASSERT_UNLESS_FUZZING();
- return false;
- }
- break;
- }
- case FileRequestData::TFileRequestBlobData: {
- const FileRequestBlobData& data =
- aData.get_FileRequestBlobData();
- if (NS_WARN_IF(data.blobChild())) {
- ASSERT_UNLESS_FUZZING();
- return false;
- }
- if (NS_WARN_IF(!data.blobParent())) {
- ASSERT_UNLESS_FUZZING();
- return false;
- }
- break;
- }
- default:
- MOZ_CRASH("Should never get here!");
- }
- return true;
- }
- void
- FileHandle::FinishOrAbort()
- {
- AssertIsOnBackgroundThread();
- MOZ_ASSERT(!mFinishedOrAborted);
- mFinishedOrAborted = true;
- if (!mHasBeenActive) {
- return;
- }
- RefPtr<FinishOp> finishOp = new FinishOp(this, mAborted);
- FileHandleThreadPool* fileHandleThreadPool =
- GetFileHandleThreadPoolFor(mStorage);
- MOZ_ASSERT(fileHandleThreadPool);
- fileHandleThreadPool->Enqueue(this, finishOp, true);
- }
- void
- FileHandle::ActorDestroy(ActorDestroyReason aWhy)
- {
- AssertIsOnBackgroundThread();
- MOZ_ASSERT(!mActorDestroyed);
- mActorDestroyed = true;
- if (!mFinishedOrAborted) {
- mAborted = true;
- mForceAborted = true;
- MaybeFinishOrAbort();
- }
- }
- bool
- FileHandle::RecvDeleteMe()
- {
- AssertIsOnBackgroundThread();
- MOZ_ASSERT(!IsActorDestroyed());
- return PBackgroundFileHandleParent::Send__delete__(this);
- }
- bool
- FileHandle::RecvFinish()
- {
- AssertIsOnBackgroundThread();
- if (NS_WARN_IF(mFinishOrAbortReceived)) {
- ASSERT_UNLESS_FUZZING();
- return false;
- }
- mFinishOrAbortReceived = true;
- MaybeFinishOrAbort();
- return true;
- }
- bool
- FileHandle::RecvAbort()
- {
- AssertIsOnBackgroundThread();
- if (NS_WARN_IF(mFinishOrAbortReceived)) {
- ASSERT_UNLESS_FUZZING();
- return false;
- }
- mFinishOrAbortReceived = true;
- Abort(/* aForce */ false);
- return true;
- }
- PBackgroundFileRequestParent*
- FileHandle::AllocPBackgroundFileRequestParent(const FileRequestParams& aParams)
- {
- AssertIsOnBackgroundThread();
- MOZ_ASSERT(aParams.type() != FileRequestParams::T__None);
- #ifdef DEBUG
- // Always verify parameters in DEBUG builds!
- bool trustParams = false;
- #else
- PBackgroundParent* backgroundActor = GetBackgroundParent();
- MOZ_ASSERT(backgroundActor);
- bool trustParams = !BackgroundParent::IsOtherProcessActor(backgroundActor);
- #endif
- if (NS_WARN_IF(!trustParams && !VerifyRequestParams(aParams))) {
- ASSERT_UNLESS_FUZZING();
- return nullptr;
- }
- if (NS_WARN_IF(mFinishOrAbortReceived)) {
- ASSERT_UNLESS_FUZZING();
- return nullptr;
- }
- RefPtr<NormalFileHandleOp> actor;
- switch (aParams.type()) {
- case FileRequestParams::TFileRequestGetMetadataParams:
- actor = new GetMetadataOp(this, aParams);
- break;
- case FileRequestParams::TFileRequestReadParams:
- actor = new ReadOp(this, aParams);
- break;
- case FileRequestParams::TFileRequestWriteParams:
- actor = new WriteOp(this, aParams);
- break;
- case FileRequestParams::TFileRequestTruncateParams:
- actor = new TruncateOp(this, aParams);
- break;
- case FileRequestParams::TFileRequestFlushParams:
- actor = new FlushOp(this, aParams);
- break;
- case FileRequestParams::TFileRequestGetFileParams:
- actor = new GetFileOp(this, aParams);
- break;
- default:
- MOZ_CRASH("Should never get here!");
- }
- MOZ_ASSERT(actor);
- // Transfer ownership to IPDL.
- return actor.forget().take();
- }
- bool
- FileHandle::RecvPBackgroundFileRequestConstructor(
- PBackgroundFileRequestParent* aActor,
- const FileRequestParams& aParams)
- {
- AssertIsOnBackgroundThread();
- MOZ_ASSERT(aActor);
- MOZ_ASSERT(aParams.type() != FileRequestParams::T__None);
- auto* op = static_cast<NormalFileHandleOp*>(aActor);
- if (NS_WARN_IF(!op->Init(this))) {
- op->Cleanup();
- return false;
- }
- op->Enqueue();
- return true;
- }
- bool
- FileHandle::DeallocPBackgroundFileRequestParent(
- PBackgroundFileRequestParent* aActor)
- {
- AssertIsOnBackgroundThread();
- MOZ_ASSERT(aActor);
- // Transfer ownership back from IPDL.
- RefPtr<NormalFileHandleOp> actor =
- dont_AddRef(static_cast<NormalFileHandleOp*>(aActor));
- return true;
- }
- /*******************************************************************************
- * Local class implementations
- ******************************************************************************/
- void
- FileHandleOp::Enqueue()
- {
- AssertIsOnOwningThread();
- FileHandleThreadPool* fileHandleThreadPool =
- GetFileHandleThreadPoolFor(mFileHandle->Storage());
- MOZ_ASSERT(fileHandleThreadPool);
- fileHandleThreadPool->Enqueue(mFileHandle, this, false);
- mFileHandle->NoteActiveRequest();
- }
- void
- FileHandle::
- FinishOp::RunOnThreadPool()
- {
- AssertIsOnThreadPool();
- MOZ_ASSERT(mFileHandle);
- nsCOMPtr<nsISupports>& stream = mFileHandle->mStream;
- if (!stream) {
- return;
- }
- nsCOMPtr<nsIInputStream> inputStream = do_QueryInterface(stream);
- MOZ_ASSERT(inputStream);
- MOZ_ALWAYS_SUCCEEDS(inputStream->Close());
- stream = nullptr;
- }
- void
- FileHandle::
- FinishOp::RunOnOwningThread()
- {
- AssertIsOnOwningThread();
- MOZ_ASSERT(mFileHandle);
- mFileHandle->SendCompleteNotification(mAborted);
- mFileHandle->GetMutableFile()->UnregisterFileHandle(mFileHandle);
- mFileHandle = nullptr;
- }
- NormalFileHandleOp::~NormalFileHandleOp()
- {
- MOZ_ASSERT(!mFileHandle,
- "NormalFileHandleOp::Cleanup() was not called by a subclass!");
- }
- bool
- NormalFileHandleOp::Init(FileHandle* aFileHandle)
- {
- AssertIsOnOwningThread();
- MOZ_ASSERT(aFileHandle);
- nsresult rv = aFileHandle->GetOrCreateStream(getter_AddRefs(mFileStream));
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return false;
- }
- return true;
- }
- void
- NormalFileHandleOp::Cleanup()
- {
- AssertIsOnOwningThread();
- MOZ_ASSERT(mFileHandle);
- MOZ_ASSERT_IF(!IsActorDestroyed(), mResponseSent);
- mFileHandle = nullptr;
- }
- nsresult
- NormalFileHandleOp::SendSuccessResult()
- {
- AssertIsOnOwningThread();
- if (!IsActorDestroyed()) {
- FileRequestResponse response;
- GetResponse(response);
- MOZ_ASSERT(response.type() != FileRequestResponse::T__None);
- if (response.type() == FileRequestResponse::Tnsresult) {
- MOZ_ASSERT(NS_FAILED(response.get_nsresult()));
- return response.get_nsresult();
- }
- if (NS_WARN_IF(!PBackgroundFileRequestParent::Send__delete__(this,
- response))) {
- return NS_ERROR_DOM_FILEHANDLE_UNKNOWN_ERR;
- }
- }
- DEBUGONLY(mResponseSent = true;)
- return NS_OK;
- }
- bool
- NormalFileHandleOp::SendFailureResult(nsresult aResultCode)
- {
- AssertIsOnBackgroundThread();
- MOZ_ASSERT(NS_FAILED(aResultCode));
- bool result = false;
- if (!IsActorDestroyed()) {
- result =
- PBackgroundFileRequestParent::Send__delete__(this, aResultCode);
- }
- DEBUGONLY(mResponseSent = true;)
- return result;
- }
- void
- NormalFileHandleOp::RunOnThreadPool()
- {
- AssertIsOnThreadPool();
- MOZ_ASSERT(mFileHandle);
- MOZ_ASSERT(NS_SUCCEEDED(mResultCode));
- // There are several cases where we don't actually have to to any work here.
- if (mFileHandleIsAborted) {
- // This transaction is already set to be aborted.
- mResultCode = NS_ERROR_DOM_FILEHANDLE_ABORT_ERR;
- } else if (mFileHandle->IsInvalidatedOnAnyThread()) {
- // This file handle is being invalidated.
- mResultCode = NS_ERROR_DOM_FILEHANDLE_UNKNOWN_ERR;
- } else if (!OperationMayProceed()) {
- // The operation was canceled in some way, likely because the child process
- // has crashed.
- mResultCode = NS_ERROR_DOM_FILEHANDLE_UNKNOWN_ERR;
- } else {
- nsresult rv = DoFileWork(mFileHandle);
- if (NS_FAILED(rv)) {
- mResultCode = rv;
- }
- }
- }
- void
- NormalFileHandleOp::RunOnOwningThread()
- {
- AssertIsOnOwningThread();
- MOZ_ASSERT(mFileHandle);
- if (NS_WARN_IF(IsActorDestroyed())) {
- // Don't send any notifications if the actor was destroyed already.
- if (NS_SUCCEEDED(mResultCode)) {
- mResultCode = NS_ERROR_DOM_FILEHANDLE_UNKNOWN_ERR;
- }
- } else {
- if (mFileHandle->IsInvalidated()) {
- mResultCode = NS_ERROR_DOM_FILEHANDLE_UNKNOWN_ERR;
- } else if (mFileHandle->IsAborted()) {
- // Aborted file handles always see their requests fail with ABORT_ERR,
- // even if the request succeeded or failed with another error.
- mResultCode = NS_ERROR_DOM_FILEHANDLE_ABORT_ERR;
- } else if (NS_SUCCEEDED(mResultCode)) {
- // This may release the IPDL reference.
- mResultCode = SendSuccessResult();
- }
- if (NS_FAILED(mResultCode)) {
- // This should definitely release the IPDL reference.
- if (!SendFailureResult(mResultCode)) {
- // Abort the file handle.
- mFileHandle->Abort(/* aForce */ false);
- }
- }
- }
- mFileHandle->NoteFinishedRequest();
- Cleanup();
- }
- void
- NormalFileHandleOp::ActorDestroy(ActorDestroyReason aWhy)
- {
- AssertIsOnOwningThread();
- NoteActorDestroyed();
- }
- nsresult
- CopyFileHandleOp::DoFileWork(FileHandle* aFileHandle)
- {
- AssertIsOnThreadPool();
- nsCOMPtr<nsIInputStream> inputStream;
- nsCOMPtr<nsIOutputStream> outputStream;
- if (mRead) {
- inputStream = do_QueryInterface(mFileStream);
- outputStream = do_QueryInterface(mBufferStream);
- } else {
- inputStream = do_QueryInterface(mBufferStream);
- outputStream = do_QueryInterface(mFileStream);
- }
- MOZ_ASSERT(inputStream);
- MOZ_ASSERT(outputStream);
- nsCOMPtr<nsISeekableStream> seekableStream =
- do_QueryInterface(mFileStream);
- nsresult rv;
- if (seekableStream) {
- if (mOffset == UINT64_MAX) {
- rv = seekableStream->Seek(nsISeekableStream::NS_SEEK_END, 0);
- }
- else {
- rv = seekableStream->Seek(nsISeekableStream::NS_SEEK_SET, mOffset);
- }
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
- }
- mOffset = 0;
- do {
- char copyBuffer[kStreamCopyBlockSize];
- uint64_t max = mSize - mOffset;
- if (max == 0) {
- break;
- }
- uint32_t count = sizeof(copyBuffer);
- if (count > max) {
- count = max;
- }
- uint32_t numRead;
- rv = inputStream->Read(copyBuffer, count, &numRead);
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
- if (!numRead) {
- break;
- }
- uint32_t numWrite;
- rv = outputStream->Write(copyBuffer, numRead, &numWrite);
- if (rv == NS_ERROR_FILE_NO_DEVICE_SPACE) {
- rv = NS_ERROR_DOM_FILEHANDLE_QUOTA_ERR;
- }
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
- if (NS_WARN_IF(numWrite != numRead)) {
- return NS_ERROR_FAILURE;
- }
- mOffset += numWrite;
- nsCOMPtr<nsIRunnable> runnable =
- new ProgressRunnable(this, mOffset, mSize);
- mOwningThread->Dispatch(runnable, NS_DISPATCH_NORMAL);
- } while (true);
- MOZ_ASSERT(mOffset == mSize);
- if (mRead) {
- MOZ_ALWAYS_SUCCEEDS(outputStream->Close());
- } else {
- MOZ_ALWAYS_SUCCEEDS(inputStream->Close());
- }
- return NS_OK;
- }
- void
- CopyFileHandleOp::Cleanup()
- {
- AssertIsOnOwningThread();
- mBufferStream = nullptr;
- NormalFileHandleOp::Cleanup();
- }
- NS_IMETHODIMP
- CopyFileHandleOp::
- ProgressRunnable::Run()
- {
- AssertIsOnBackgroundThread();
- Unused << mCopyFileHandleOp->SendProgress(mProgress, mProgressMax);
- mCopyFileHandleOp = nullptr;
- return NS_OK;
- }
- GetMetadataOp::GetMetadataOp(FileHandle* aFileHandle,
- const FileRequestParams& aParams)
- : NormalFileHandleOp(aFileHandle)
- , mParams(aParams.get_FileRequestGetMetadataParams())
- {
- MOZ_ASSERT(aParams.type() ==
- FileRequestParams::TFileRequestGetMetadataParams);
- }
- nsresult
- GetMetadataOp::DoFileWork(FileHandle* aFileHandle)
- {
- AssertIsOnThreadPool();
- nsresult rv;
- if (mFileHandle->Mode() == FileMode::Readwrite) {
- // Force a flush (so all pending writes are flushed to the disk and file
- // metadata is updated too).
- nsCOMPtr<nsIOutputStream> ostream = do_QueryInterface(mFileStream);
- MOZ_ASSERT(ostream);
- rv = ostream->Flush();
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
- }
- nsCOMPtr<nsIFileMetadata> metadata = do_QueryInterface(mFileStream);
- MOZ_ASSERT(metadata);
- if (mParams.size()) {
- int64_t size;
- rv = metadata->GetSize(&size);
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
- if (NS_WARN_IF(size < 0)) {
- return NS_ERROR_FAILURE;
- }
- mMetadata.size() = uint64_t(size);
- } else {
- mMetadata.size() = void_t();
- }
- if (mParams.lastModified()) {
- int64_t lastModified;
- rv = metadata->GetLastModified(&lastModified);
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
- mMetadata.lastModified() = lastModified;
- } else {
- mMetadata.lastModified() = void_t();
- }
- return NS_OK;
- }
- void
- GetMetadataOp::GetResponse(FileRequestResponse& aResponse)
- {
- AssertIsOnOwningThread();
- aResponse = FileRequestGetMetadataResponse(mMetadata);
- }
- ReadOp::ReadOp(FileHandle* aFileHandle,
- const FileRequestParams& aParams)
- : CopyFileHandleOp(aFileHandle)
- , mParams(aParams.get_FileRequestReadParams())
- {
- MOZ_ASSERT(aParams.type() == FileRequestParams::TFileRequestReadParams);
- }
- bool
- ReadOp::Init(FileHandle* aFileHandle)
- {
- AssertIsOnOwningThread();
- MOZ_ASSERT(aFileHandle);
- if (NS_WARN_IF(!NormalFileHandleOp::Init(aFileHandle))) {
- return false;
- }
- mBufferStream = MemoryOutputStream::Create(mParams.size());
- if (NS_WARN_IF(!mBufferStream)) {
- return false;
- }
- mOffset = mParams.offset();
- mSize = mParams.size();
- mRead = true;
- return true;
- }
- void
- ReadOp::GetResponse(FileRequestResponse& aResponse)
- {
- AssertIsOnOwningThread();
- auto* stream = static_cast<MemoryOutputStream*>(mBufferStream.get());
- aResponse = FileRequestReadResponse(stream->Data());
- }
- // static
- already_AddRefed<ReadOp::MemoryOutputStream>
- ReadOp::
- MemoryOutputStream::Create(uint64_t aSize)
- {
- MOZ_ASSERT(aSize, "Passed zero size!");
- if (NS_WARN_IF(aSize > UINT32_MAX)) {
- return nullptr;
- }
- RefPtr<MemoryOutputStream> stream = new MemoryOutputStream();
- char* dummy;
- uint32_t length = stream->mData.GetMutableData(&dummy, aSize, fallible);
- if (NS_WARN_IF(length != aSize)) {
- return nullptr;
- }
- return stream.forget();
- }
- NS_IMPL_ISUPPORTS(ReadOp::MemoryOutputStream, nsIOutputStream)
- NS_IMETHODIMP
- ReadOp::
- MemoryOutputStream::Close()
- {
- mData.Truncate(mOffset);
- return NS_OK;
- }
- NS_IMETHODIMP
- ReadOp::
- MemoryOutputStream::Write(const char* aBuf, uint32_t aCount, uint32_t* _retval)
- {
- return WriteSegments(NS_CopySegmentToBuffer, (char*)aBuf, aCount, _retval);
- }
- NS_IMETHODIMP
- ReadOp::
- MemoryOutputStream::Flush()
- {
- return NS_OK;
- }
- NS_IMETHODIMP
- ReadOp::
- MemoryOutputStream::WriteFrom(nsIInputStream* aFromStream, uint32_t aCount,
- uint32_t* _retval)
- {
- return NS_ERROR_NOT_IMPLEMENTED;
- }
- NS_IMETHODIMP
- ReadOp::
- MemoryOutputStream::WriteSegments(nsReadSegmentFun aReader, void* aClosure,
- uint32_t aCount, uint32_t* _retval)
- {
- NS_ASSERTION(mData.Length() >= mOffset, "Bad stream state!");
- uint32_t maxCount = mData.Length() - mOffset;
- if (maxCount == 0) {
- *_retval = 0;
- return NS_OK;
- }
- if (aCount > maxCount) {
- aCount = maxCount;
- }
- nsresult rv = aReader(this, aClosure, mData.BeginWriting() + mOffset, 0,
- aCount, _retval);
- if (NS_SUCCEEDED(rv)) {
- NS_ASSERTION(*_retval <= aCount,
- "Reader should not read more than we asked it to read!");
- mOffset += *_retval;
- }
- return NS_OK;
- }
- NS_IMETHODIMP
- ReadOp::
- MemoryOutputStream::IsNonBlocking(bool* _retval)
- {
- *_retval = false;
- return NS_OK;
- }
- WriteOp::WriteOp(FileHandle* aFileHandle,
- const FileRequestParams& aParams)
- : CopyFileHandleOp(aFileHandle)
- , mParams(aParams.get_FileRequestWriteParams())
- {
- MOZ_ASSERT(aParams.type() == FileRequestParams::TFileRequestWriteParams);
- }
- bool
- WriteOp::Init(FileHandle* aFileHandle)
- {
- AssertIsOnOwningThread();
- MOZ_ASSERT(aFileHandle);
- if (NS_WARN_IF(!NormalFileHandleOp::Init(aFileHandle))) {
- return false;
- }
- nsCOMPtr<nsIInputStream> inputStream;
- const FileRequestData& data = mParams.data();
- switch (data.type()) {
- case FileRequestData::TFileRequestStringData: {
- const FileRequestStringData& stringData =
- data.get_FileRequestStringData();
- const nsCString& string = stringData.string();
- nsresult rv =
- NS_NewCStringInputStream(getter_AddRefs(inputStream), string);
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return false;
- }
- break;
- }
- case FileRequestData::TFileRequestBlobData: {
- const FileRequestBlobData& blobData =
- data.get_FileRequestBlobData();
- auto blobActor = static_cast<BlobParent*>(blobData.blobParent());
- RefPtr<BlobImpl> blobImpl = blobActor->GetBlobImpl();
- ErrorResult rv;
- blobImpl->GetInternalStream(getter_AddRefs(inputStream), rv);
- if (NS_WARN_IF(rv.Failed())) {
- rv.SuppressException();
- return false;
- }
- break;
- }
- default:
- MOZ_CRASH("Should never get here!");
- }
- mBufferStream = inputStream;
- mOffset = mParams.offset();
- mSize = mParams.dataLength();
- mRead = false;
- return true;
- }
- void
- WriteOp::GetResponse(FileRequestResponse& aResponse)
- {
- AssertIsOnOwningThread();
- aResponse = FileRequestWriteResponse();
- }
- TruncateOp::TruncateOp(FileHandle* aFileHandle,
- const FileRequestParams& aParams)
- : NormalFileHandleOp(aFileHandle)
- , mParams(aParams.get_FileRequestTruncateParams())
- {
- MOZ_ASSERT(aParams.type() == FileRequestParams::TFileRequestTruncateParams);
- }
- nsresult
- TruncateOp::DoFileWork(FileHandle* aFileHandle)
- {
- AssertIsOnThreadPool();
- nsCOMPtr<nsISeekableStream> sstream = do_QueryInterface(mFileStream);
- MOZ_ASSERT(sstream);
- nsresult rv = sstream->Seek(nsISeekableStream::NS_SEEK_SET, mParams.offset());
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
- rv = sstream->SetEOF();
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
- return NS_OK;
- }
- void
- TruncateOp::GetResponse(FileRequestResponse& aResponse)
- {
- AssertIsOnOwningThread();
- aResponse = FileRequestTruncateResponse();
- }
- FlushOp::FlushOp(FileHandle* aFileHandle,
- const FileRequestParams& aParams)
- : NormalFileHandleOp(aFileHandle)
- , mParams(aParams.get_FileRequestFlushParams())
- {
- MOZ_ASSERT(aParams.type() == FileRequestParams::TFileRequestFlushParams);
- }
- nsresult
- FlushOp::DoFileWork(FileHandle* aFileHandle)
- {
- AssertIsOnThreadPool();
- nsCOMPtr<nsIOutputStream> ostream = do_QueryInterface(mFileStream);
- MOZ_ASSERT(ostream);
- nsresult rv = ostream->Flush();
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
- return NS_OK;
- }
- void
- FlushOp::GetResponse(FileRequestResponse& aResponse)
- {
- AssertIsOnOwningThread();
- aResponse = FileRequestFlushResponse();
- }
- GetFileOp::GetFileOp(FileHandle* aFileHandle,
- const FileRequestParams& aParams)
- : GetMetadataOp(aFileHandle,
- FileRequestGetMetadataParams(true, true))
- , mBackgroundParent(aFileHandle->GetBackgroundParent())
- {
- MOZ_ASSERT(aParams.type() == FileRequestParams::TFileRequestGetFileParams);
- MOZ_ASSERT(mBackgroundParent);
- }
- void
- GetFileOp::GetResponse(FileRequestResponse& aResponse)
- {
- AssertIsOnOwningThread();
- RefPtr<BlobImpl> blobImpl = mFileHandle->GetMutableFile()->CreateBlobImpl();
- MOZ_ASSERT(blobImpl);
- PBlobParent* actor =
- BackgroundParent::GetOrCreateActorForBlobImpl(mBackgroundParent, blobImpl);
- if (NS_WARN_IF(!actor)) {
- // This can only fail if the child has crashed.
- aResponse = NS_ERROR_DOM_FILEHANDLE_UNKNOWN_ERR;
- return;
- }
- FileRequestGetFileResponse response;
- response.fileParent() = actor;
- response.metadata() = mMetadata;
- aResponse = response;
- }
- } // namespace dom
- } // namespace mozilla
|