Line data Source code
1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 : /* This Source Code Form is subject to the terms of the Mozilla Public
4 : * License, v. 2.0. If a copy of the MPL was not distributed with this file,
5 : * You can obtain one at http://mozilla.org/MPL/2.0/. */
6 :
7 : #include "IDBMutableFile.h"
8 :
9 : #include "ActorsChild.h"
10 : #include "FileInfo.h"
11 : #include "IDBDatabase.h"
12 : #include "IDBFactory.h"
13 : #include "IDBFileHandle.h"
14 : #include "IDBFileRequest.h"
15 : #include "IndexedDatabaseManager.h"
16 : #include "MainThreadUtils.h"
17 : #include "mozilla/Assertions.h"
18 : #include "mozilla/ErrorResult.h"
19 : #include "mozilla/dom/File.h"
20 : #include "mozilla/dom/IDBMutableFileBinding.h"
21 : #include "mozilla/dom/indexedDB/PBackgroundIDBSharedTypes.h"
22 : #include "mozilla/dom/quota/FileStreams.h"
23 : #include "mozilla/dom/quota/QuotaManager.h"
24 : #include "mozilla/ipc/BackgroundUtils.h"
25 : #include "mozilla/ipc/PBackgroundSharedTypes.h"
26 : #include "nsContentUtils.h"
27 : #include "nsDebug.h"
28 : #include "nsError.h"
29 : #include "nsIInputStream.h"
30 : #include "nsIPrincipal.h"
31 : #include "ReportInternalError.h"
32 :
33 : namespace mozilla {
34 : namespace dom {
35 :
36 : using namespace mozilla::dom::indexedDB;
37 : using namespace mozilla::dom::quota;
38 :
39 0 : IDBMutableFile::IDBMutableFile(IDBDatabase* aDatabase,
40 : BackgroundMutableFileChild* aActor,
41 : const nsAString& aName,
42 0 : const nsAString& aType)
43 : : DOMEventTargetHelper(aDatabase)
44 : , mDatabase(aDatabase)
45 : , mBackgroundActor(aActor)
46 : , mName(aName)
47 : , mType(aType)
48 0 : , mInvalidated(false)
49 : {
50 0 : MOZ_ASSERT(aDatabase);
51 0 : aDatabase->AssertIsOnOwningThread();
52 0 : MOZ_ASSERT(aActor);
53 :
54 0 : mDatabase->NoteLiveMutableFile(this);
55 0 : }
56 :
57 0 : IDBMutableFile::~IDBMutableFile()
58 : {
59 0 : AssertIsOnOwningThread();
60 :
61 0 : mDatabase->NoteFinishedMutableFile(this);
62 :
63 0 : if (mBackgroundActor) {
64 0 : mBackgroundActor->SendDeleteMeInternal();
65 0 : MOZ_ASSERT(!mBackgroundActor, "SendDeleteMeInternal should have cleared!");
66 : }
67 0 : }
68 :
69 : #ifdef DEBUG
70 :
71 : void
72 0 : IDBMutableFile::AssertIsOnOwningThread() const
73 : {
74 0 : MOZ_ASSERT(mDatabase);
75 0 : mDatabase->AssertIsOnOwningThread();
76 0 : }
77 :
78 : #endif // DEBUG
79 :
80 : int64_t
81 0 : IDBMutableFile::GetFileId() const
82 : {
83 0 : AssertIsOnOwningThread();
84 :
85 : int64_t fileId;
86 0 : if (!mBackgroundActor ||
87 0 : NS_WARN_IF(!mBackgroundActor->SendGetFileId(&fileId))) {
88 0 : return -1;
89 : }
90 :
91 0 : return fileId;
92 : }
93 :
94 : void
95 0 : IDBMutableFile::Invalidate()
96 : {
97 0 : AssertIsOnOwningThread();
98 0 : MOZ_ASSERT(!mInvalidated);
99 :
100 0 : mInvalidated = true;
101 :
102 0 : AbortFileHandles();
103 0 : }
104 :
105 : void
106 0 : IDBMutableFile::RegisterFileHandle(IDBFileHandle* aFileHandle)
107 : {
108 0 : AssertIsOnOwningThread();
109 0 : MOZ_ASSERT(aFileHandle);
110 0 : aFileHandle->AssertIsOnOwningThread();
111 0 : MOZ_ASSERT(!mFileHandles.Contains(aFileHandle));
112 :
113 0 : mFileHandles.PutEntry(aFileHandle);
114 0 : }
115 :
116 : void
117 0 : IDBMutableFile::UnregisterFileHandle(IDBFileHandle* aFileHandle)
118 : {
119 0 : AssertIsOnOwningThread();
120 0 : MOZ_ASSERT(aFileHandle);
121 0 : aFileHandle->AssertIsOnOwningThread();
122 0 : MOZ_ASSERT(mFileHandles.Contains(aFileHandle));
123 :
124 0 : mFileHandles.RemoveEntry(aFileHandle);
125 0 : }
126 :
127 : void
128 0 : IDBMutableFile::AbortFileHandles()
129 : {
130 0 : AssertIsOnOwningThread();
131 :
132 : class MOZ_STACK_CLASS Helper final
133 : {
134 : public:
135 : static void
136 0 : AbortFileHandles(nsTHashtable<nsPtrHashKey<IDBFileHandle>>& aTable)
137 : {
138 0 : if (!aTable.Count()) {
139 0 : return;
140 : }
141 :
142 0 : nsTArray<RefPtr<IDBFileHandle>> fileHandlesToAbort;
143 0 : fileHandlesToAbort.SetCapacity(aTable.Count());
144 :
145 0 : for (auto iter = aTable.Iter(); !iter.Done(); iter.Next()) {
146 0 : IDBFileHandle* fileHandle = iter.Get()->GetKey();
147 0 : MOZ_ASSERT(fileHandle);
148 :
149 0 : fileHandle->AssertIsOnOwningThread();
150 :
151 0 : if (!fileHandle->IsDone()) {
152 0 : fileHandlesToAbort.AppendElement(iter.Get()->GetKey());
153 : }
154 : }
155 0 : MOZ_ASSERT(fileHandlesToAbort.Length() <= aTable.Count());
156 :
157 0 : if (fileHandlesToAbort.IsEmpty()) {
158 0 : return;
159 : }
160 :
161 0 : for (RefPtr<IDBFileHandle>& fileHandle : fileHandlesToAbort) {
162 0 : MOZ_ASSERT(fileHandle);
163 :
164 0 : fileHandle->Abort();
165 : }
166 : }
167 : };
168 :
169 0 : Helper::AbortFileHandles(mFileHandles);
170 0 : }
171 :
172 : IDBDatabase*
173 0 : IDBMutableFile::Database() const
174 : {
175 0 : AssertIsOnOwningThread();
176 :
177 0 : return mDatabase;
178 : }
179 :
180 : already_AddRefed<IDBFileHandle>
181 0 : IDBMutableFile::Open(FileMode aMode, ErrorResult& aError)
182 : {
183 0 : AssertIsOnOwningThread();
184 :
185 0 : if (QuotaManager::IsShuttingDown() ||
186 0 : mDatabase->IsClosed() ||
187 0 : !GetOwner()) {
188 0 : aError.Throw(NS_ERROR_DOM_FILEHANDLE_UNKNOWN_ERR);
189 0 : return nullptr;
190 : }
191 :
192 : RefPtr<IDBFileHandle> fileHandle =
193 0 : IDBFileHandle::Create(this, aMode);
194 0 : if (NS_WARN_IF(!fileHandle)) {
195 0 : aError.Throw(NS_ERROR_DOM_FILEHANDLE_UNKNOWN_ERR);
196 0 : return nullptr;
197 : }
198 :
199 0 : BackgroundFileHandleChild* actor = new BackgroundFileHandleChild(fileHandle);
200 :
201 0 : MOZ_ALWAYS_TRUE(
202 : mBackgroundActor->SendPBackgroundFileHandleConstructor(actor, aMode));
203 :
204 0 : fileHandle->SetBackgroundActor(actor);
205 :
206 0 : return fileHandle.forget();
207 : }
208 :
209 : already_AddRefed<DOMRequest>
210 0 : IDBMutableFile::GetFile(ErrorResult& aError)
211 : {
212 0 : RefPtr<IDBFileHandle> fileHandle = Open(FileMode::Readonly, aError);
213 0 : if (NS_WARN_IF(aError.Failed())) {
214 0 : return nullptr;
215 : }
216 :
217 0 : FileRequestGetFileParams params;
218 :
219 : RefPtr<IDBFileRequest> request =
220 0 : IDBFileRequest::Create(fileHandle, /* aWrapAsDOMRequest */ true);
221 :
222 0 : fileHandle->StartRequest(request, params);
223 :
224 0 : return request.forget();
225 : }
226 :
227 0 : NS_IMPL_ADDREF_INHERITED(IDBMutableFile, DOMEventTargetHelper)
228 0 : NS_IMPL_RELEASE_INHERITED(IDBMutableFile, DOMEventTargetHelper)
229 :
230 0 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(IDBMutableFile)
231 0 : NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
232 :
233 : NS_IMPL_CYCLE_COLLECTION_CLASS(IDBMutableFile)
234 :
235 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(IDBMutableFile,
236 : DOMEventTargetHelper)
237 0 : tmp->AssertIsOnOwningThread();
238 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDatabase)
239 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
240 :
241 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(IDBMutableFile,
242 : DOMEventTargetHelper)
243 0 : tmp->AssertIsOnOwningThread();
244 :
245 : // Don't unlink mDatabase!
246 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_END
247 :
248 : JSObject*
249 0 : IDBMutableFile::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
250 : {
251 0 : return IDBMutableFileBinding::Wrap(aCx, this, aGivenProto);
252 : }
253 :
254 : } // namespace dom
255 : } // namespace mozilla
|