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 "CallbackRunnables.h"
8 : #include "mozilla/dom/Directory.h"
9 : #include "mozilla/dom/DirectoryBinding.h"
10 : #include "mozilla/dom/DOMException.h"
11 : #include "mozilla/dom/File.h"
12 : #include "mozilla/dom/FileBinding.h"
13 : #include "mozilla/dom/FileSystemDirectoryReaderBinding.h"
14 : #include "mozilla/dom/FileSystemFileEntry.h"
15 : #include "mozilla/dom/FileSystemUtils.h"
16 : #include "mozilla/dom/Promise.h"
17 : #include "mozilla/Unused.h"
18 : #include "nsIGlobalObject.h"
19 : #include "nsIFile.h"
20 : #include "nsPIDOMWindow.h"
21 :
22 : #include "../GetFileOrDirectoryTask.h"
23 :
24 : namespace mozilla {
25 : namespace dom {
26 :
27 0 : EntryCallbackRunnable::EntryCallbackRunnable(FileSystemEntryCallback* aCallback,
28 0 : FileSystemEntry* aEntry)
29 : : Runnable("EntryCallbackRunnable")
30 : , mCallback(aCallback)
31 0 : , mEntry(aEntry)
32 : {
33 0 : MOZ_ASSERT(aCallback);
34 0 : MOZ_ASSERT(aEntry);
35 0 : }
36 :
37 : NS_IMETHODIMP
38 0 : EntryCallbackRunnable::Run()
39 : {
40 0 : mCallback->HandleEvent(*mEntry);
41 0 : return NS_OK;
42 : }
43 :
44 0 : ErrorCallbackRunnable::ErrorCallbackRunnable(nsIGlobalObject* aGlobalObject,
45 : ErrorCallback* aCallback,
46 0 : nsresult aError)
47 : : Runnable("ErrorCallbackRunnable")
48 : , mGlobal(aGlobalObject)
49 : , mCallback(aCallback)
50 0 : , mError(aError)
51 : {
52 0 : MOZ_ASSERT(aGlobalObject);
53 0 : MOZ_ASSERT(aCallback);
54 0 : MOZ_ASSERT(NS_FAILED(aError));
55 0 : }
56 :
57 : NS_IMETHODIMP
58 0 : ErrorCallbackRunnable::Run()
59 : {
60 0 : RefPtr<DOMException> exception = DOMException::Create(mError);
61 0 : mCallback->HandleEvent(*exception);
62 0 : return NS_OK;
63 : }
64 :
65 0 : EmptyEntriesCallbackRunnable::EmptyEntriesCallbackRunnable(FileSystemEntriesCallback* aCallback)
66 : : Runnable("EmptyEntriesCallbackRunnable")
67 0 : , mCallback(aCallback)
68 : {
69 0 : MOZ_ASSERT(aCallback);
70 0 : }
71 :
72 : NS_IMETHODIMP
73 0 : EmptyEntriesCallbackRunnable::Run()
74 : {
75 0 : Sequence<OwningNonNull<FileSystemEntry>> sequence;
76 0 : mCallback->HandleEvent(sequence);
77 0 : return NS_OK;
78 : }
79 :
80 0 : GetEntryHelper::GetEntryHelper(FileSystemDirectoryEntry* aParentEntry,
81 : Directory* aDirectory,
82 : nsTArray<nsString>& aParts,
83 : FileSystem* aFileSystem,
84 : FileSystemEntryCallback* aSuccessCallback,
85 : ErrorCallback* aErrorCallback,
86 0 : FileSystemDirectoryEntry::GetInternalType aType)
87 : : mParentEntry(aParentEntry)
88 : , mDirectory(aDirectory)
89 : , mParts(aParts)
90 : , mFileSystem(aFileSystem)
91 : , mSuccessCallback(aSuccessCallback)
92 : , mErrorCallback(aErrorCallback)
93 0 : , mType(aType)
94 : {
95 0 : MOZ_ASSERT(aParentEntry);
96 0 : MOZ_ASSERT(aDirectory);
97 0 : MOZ_ASSERT(!aParts.IsEmpty());
98 0 : MOZ_ASSERT(aFileSystem);
99 0 : MOZ_ASSERT(aSuccessCallback || aErrorCallback);
100 0 : }
101 :
102 0 : GetEntryHelper::~GetEntryHelper()
103 0 : {}
104 :
105 : namespace {
106 :
107 : nsresult
108 0 : DOMPathToRealPath(Directory* aDirectory, const nsAString& aPath,
109 : nsIFile** aFile)
110 : {
111 0 : nsString relativePath;
112 0 : relativePath = aPath;
113 :
114 : // Trim white spaces.
115 : static const char kWhitespace[] = "\b\t\r\n ";
116 0 : relativePath.Trim(kWhitespace);
117 :
118 0 : nsTArray<nsString> parts;
119 0 : if (!FileSystemUtils::IsValidRelativeDOMPath(relativePath, parts)) {
120 0 : return NS_ERROR_DOM_FILESYSTEM_INVALID_PATH_ERR;
121 : }
122 :
123 0 : nsCOMPtr<nsIFile> file;
124 0 : nsresult rv = aDirectory->GetInternalNsIFile()->Clone(getter_AddRefs(file));
125 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
126 0 : return rv;
127 : }
128 :
129 0 : for (uint32_t i = 0; i < parts.Length(); ++i) {
130 0 : rv = file->AppendRelativePath(parts[i]);
131 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
132 0 : return rv;
133 : }
134 : }
135 :
136 0 : file.forget(aFile);
137 0 : return NS_OK;
138 : }
139 :
140 : } // anonymous
141 :
142 : void
143 0 : GetEntryHelper::Run()
144 : {
145 0 : MOZ_ASSERT(!mParts.IsEmpty());
146 :
147 0 : nsCOMPtr<nsIFile> realPath;
148 0 : nsresult error = DOMPathToRealPath(mDirectory, mParts[0],
149 0 : getter_AddRefs(realPath));
150 :
151 0 : ErrorResult rv;
152 0 : RefPtr<FileSystemBase> fs = mDirectory->GetFileSystem(rv);
153 0 : if (NS_WARN_IF(rv.Failed())) {
154 0 : rv.SuppressException();
155 0 : Error(NS_ERROR_DOM_INVALID_STATE_ERR);
156 0 : return;
157 : }
158 :
159 : RefPtr<GetFileOrDirectoryTaskChild> task =
160 0 : GetFileOrDirectoryTaskChild::Create(fs, realPath, rv);
161 0 : if (NS_WARN_IF(rv.Failed())) {
162 0 : rv.SuppressException();
163 0 : Error(NS_ERROR_DOM_INVALID_STATE_ERR);
164 0 : return;
165 : }
166 :
167 0 : task->SetError(error);
168 0 : task->Start();
169 :
170 0 : RefPtr<Promise> promise = task->GetPromise();
171 :
172 0 : mParts.RemoveElementAt(0);
173 0 : promise->AppendNativeHandler(this);
174 : }
175 :
176 : void
177 0 : GetEntryHelper::ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue)
178 : {
179 0 : if(NS_WARN_IF(!aValue.isObject())) {
180 0 : return;
181 : }
182 :
183 0 : JS::Rooted<JSObject*> obj(aCx, &aValue.toObject());
184 :
185 : // This is not the last part of the path.
186 0 : if (!mParts.IsEmpty()) {
187 0 : ContinueRunning(obj);
188 0 : return;
189 : }
190 :
191 0 : CompleteOperation(obj);
192 : }
193 :
194 : void
195 0 : GetEntryHelper::CompleteOperation(JSObject* aObj)
196 : {
197 0 : MOZ_ASSERT(mParts.IsEmpty());
198 :
199 0 : if (mType == FileSystemDirectoryEntry::eGetFile) {
200 0 : RefPtr<File> file;
201 0 : if (NS_FAILED(UNWRAP_OBJECT(File, aObj, file))) {
202 0 : Error(NS_ERROR_DOM_TYPE_MISMATCH_ERR);
203 0 : return;
204 : }
205 :
206 : RefPtr<FileSystemFileEntry> entry =
207 0 : new FileSystemFileEntry(mParentEntry->GetParentObject(), file,
208 0 : mParentEntry, mFileSystem);
209 0 : mSuccessCallback->HandleEvent(*entry);
210 0 : return;
211 : }
212 :
213 0 : MOZ_ASSERT(mType == FileSystemDirectoryEntry::eGetDirectory);
214 :
215 0 : RefPtr<Directory> directory;
216 0 : if (NS_FAILED(UNWRAP_OBJECT(Directory, aObj, directory))) {
217 0 : Error(NS_ERROR_DOM_TYPE_MISMATCH_ERR);
218 0 : return;
219 : }
220 :
221 : RefPtr<FileSystemDirectoryEntry> entry =
222 0 : new FileSystemDirectoryEntry(mParentEntry->GetParentObject(), directory,
223 0 : mParentEntry, mFileSystem);
224 0 : mSuccessCallback->HandleEvent(*entry);
225 : }
226 :
227 : void
228 0 : GetEntryHelper::ContinueRunning(JSObject* aObj)
229 : {
230 0 : MOZ_ASSERT(!mParts.IsEmpty());
231 :
232 0 : RefPtr<Directory> directory;
233 0 : if (NS_FAILED(UNWRAP_OBJECT(Directory, aObj, directory))) {
234 0 : Error(NS_ERROR_DOM_TYPE_MISMATCH_ERR);
235 0 : return;
236 : }
237 :
238 : RefPtr<FileSystemDirectoryEntry> entry =
239 0 : new FileSystemDirectoryEntry(mParentEntry->GetParentObject(), directory,
240 0 : mParentEntry, mFileSystem);
241 :
242 : // Update the internal values.
243 0 : mParentEntry = entry;
244 0 : mDirectory = directory;
245 :
246 0 : Run();
247 : }
248 :
249 : void
250 0 : GetEntryHelper::RejectedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue)
251 : {
252 0 : Error(NS_ERROR_DOM_NOT_FOUND_ERR);
253 0 : }
254 :
255 : void
256 0 : GetEntryHelper::Error(nsresult aError)
257 : {
258 0 : MOZ_ASSERT(NS_FAILED(aError));
259 :
260 0 : if (mErrorCallback) {
261 : RefPtr<ErrorCallbackRunnable> runnable =
262 0 : new ErrorCallbackRunnable(mParentEntry->GetParentObject(),
263 0 : mErrorCallback, aError);
264 :
265 0 : FileSystemUtils::DispatchRunnable(mParentEntry->GetParentObject(),
266 0 : runnable.forget());
267 : }
268 0 : }
269 :
270 0 : NS_IMPL_ISUPPORTS0(GetEntryHelper);
271 :
272 : /* static */ void
273 0 : FileSystemEntryCallbackHelper::Call(nsIGlobalObject* aGlobalObject,
274 : const Optional<OwningNonNull<FileSystemEntryCallback>>& aEntryCallback,
275 : FileSystemEntry* aEntry)
276 : {
277 0 : MOZ_ASSERT(aGlobalObject);
278 0 : MOZ_ASSERT(aEntry);
279 :
280 0 : if (aEntryCallback.WasPassed()) {
281 : RefPtr<EntryCallbackRunnable> runnable =
282 0 : new EntryCallbackRunnable(&aEntryCallback.Value(), aEntry);
283 :
284 0 : FileSystemUtils::DispatchRunnable(aGlobalObject, runnable.forget());
285 : }
286 0 : }
287 :
288 : /* static */ void
289 0 : ErrorCallbackHelper::Call(nsIGlobalObject* aGlobal,
290 : const Optional<OwningNonNull<ErrorCallback>>& aErrorCallback,
291 : nsresult aError)
292 : {
293 0 : MOZ_ASSERT(aGlobal);
294 0 : MOZ_ASSERT(NS_FAILED(aError));
295 :
296 0 : if (aErrorCallback.WasPassed()) {
297 : RefPtr<ErrorCallbackRunnable> runnable =
298 0 : new ErrorCallbackRunnable(aGlobal, &aErrorCallback.Value(), aError);
299 :
300 0 : FileSystemUtils::DispatchRunnable(aGlobal, runnable.forget());
301 : }
302 0 : }
303 :
304 : } // dom namespace
305 : } // mozilla namespace
306 :
|