ActorsParent.cpp 59 KB

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