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 "GetDirectoryListingTask.h"
8 :
9 : #include "HTMLSplitOnSpacesTokenizer.h"
10 : #include "js/Value.h"
11 : #include "mozilla/dom/FileBlobImpl.h"
12 : #include "mozilla/dom/FileSystemBase.h"
13 : #include "mozilla/dom/FileSystemUtils.h"
14 : #include "mozilla/dom/IPCBlobUtils.h"
15 : #include "mozilla/dom/PFileSystemParams.h"
16 : #include "mozilla/dom/Promise.h"
17 : #include "mozilla/dom/UnionTypes.h"
18 : #include "nsIFile.h"
19 : #include "nsISimpleEnumerator.h"
20 : #include "nsStringGlue.h"
21 :
22 : namespace mozilla {
23 : namespace dom {
24 :
25 : /**
26 : * GetDirectoryListingTaskChild
27 : */
28 :
29 : /* static */ already_AddRefed<GetDirectoryListingTaskChild>
30 0 : GetDirectoryListingTaskChild::Create(FileSystemBase* aFileSystem,
31 : Directory* aDirectory,
32 : nsIFile* aTargetPath,
33 : const nsAString& aFilters,
34 : ErrorResult& aRv)
35 : {
36 0 : MOZ_ASSERT(aFileSystem);
37 0 : MOZ_ASSERT(aDirectory);
38 0 : aFileSystem->AssertIsOnOwningThread();
39 :
40 : nsCOMPtr<nsIGlobalObject> globalObject =
41 0 : do_QueryInterface(aFileSystem->GetParentObject());
42 0 : if (NS_WARN_IF(!globalObject)) {
43 0 : aRv.Throw(NS_ERROR_FAILURE);
44 0 : return nullptr;
45 : }
46 :
47 : RefPtr<GetDirectoryListingTaskChild> task =
48 : new GetDirectoryListingTaskChild(globalObject, aFileSystem, aDirectory,
49 0 : aTargetPath, aFilters);
50 :
51 : // aTargetPath can be null. In this case SetError will be called.
52 :
53 0 : task->mPromise = Promise::Create(globalObject, aRv);
54 0 : if (NS_WARN_IF(aRv.Failed())) {
55 0 : return nullptr;
56 : }
57 :
58 0 : return task.forget();
59 : }
60 :
61 0 : GetDirectoryListingTaskChild::GetDirectoryListingTaskChild(nsIGlobalObject* aGlobalObject,
62 : FileSystemBase* aFileSystem,
63 : Directory* aDirectory,
64 : nsIFile* aTargetPath,
65 0 : const nsAString& aFilters)
66 : : FileSystemTaskChildBase(aGlobalObject, aFileSystem)
67 : , mDirectory(aDirectory)
68 : , mTargetPath(aTargetPath)
69 0 : , mFilters(aFilters)
70 : {
71 0 : MOZ_ASSERT(aFileSystem);
72 0 : aFileSystem->AssertIsOnOwningThread();
73 0 : }
74 :
75 0 : GetDirectoryListingTaskChild::~GetDirectoryListingTaskChild()
76 : {
77 0 : mFileSystem->AssertIsOnOwningThread();
78 0 : }
79 :
80 : already_AddRefed<Promise>
81 0 : GetDirectoryListingTaskChild::GetPromise()
82 : {
83 0 : mFileSystem->AssertIsOnOwningThread();
84 0 : return RefPtr<Promise>(mPromise).forget();
85 : }
86 :
87 : FileSystemParams
88 0 : GetDirectoryListingTaskChild::GetRequestParams(const nsString& aSerializedDOMPath,
89 : ErrorResult& aRv) const
90 : {
91 0 : mFileSystem->AssertIsOnOwningThread();
92 :
93 : // this is the real path.
94 0 : nsAutoString path;
95 0 : aRv = mTargetPath->GetPath(path);
96 0 : if (NS_WARN_IF(aRv.Failed())) {
97 0 : return FileSystemGetDirectoryListingParams();
98 : }
99 :
100 : // this is the dom path.
101 0 : nsAutoString directoryPath;
102 0 : mDirectory->GetPath(directoryPath, aRv);
103 0 : if (NS_WARN_IF(aRv.Failed())) {
104 0 : return FileSystemGetDirectoryListingParams();
105 : }
106 :
107 0 : return FileSystemGetDirectoryListingParams(aSerializedDOMPath, path,
108 0 : directoryPath, mFilters);
109 : }
110 :
111 : void
112 0 : GetDirectoryListingTaskChild::SetSuccessRequestResult(const FileSystemResponseValue& aValue,
113 : ErrorResult& aRv)
114 : {
115 0 : mFileSystem->AssertIsOnOwningThread();
116 0 : MOZ_ASSERT(aValue.type() ==
117 : FileSystemResponseValue::TFileSystemDirectoryListingResponse);
118 :
119 0 : FileSystemDirectoryListingResponse r = aValue;
120 0 : for (uint32_t i = 0; i < r.data().Length(); ++i) {
121 0 : const FileSystemDirectoryListingResponseData& data = r.data()[i];
122 :
123 0 : OwningFileOrDirectory* ofd = mTargetData.AppendElement(fallible);
124 0 : if (!ofd) {
125 0 : aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
126 0 : return;
127 : }
128 :
129 0 : if (data.type() == FileSystemDirectoryListingResponseData::TFileSystemDirectoryListingResponseFile) {
130 : const FileSystemDirectoryListingResponseFile& d =
131 0 : data.get_FileSystemDirectoryListingResponseFile();
132 :
133 0 : RefPtr<BlobImpl> blobImpl = IPCBlobUtils::Deserialize(d.blob());
134 0 : MOZ_ASSERT(blobImpl);
135 :
136 0 : RefPtr<File> file = File::Create(mFileSystem->GetParentObject(), blobImpl);
137 0 : MOZ_ASSERT(file);
138 :
139 0 : ofd->SetAsFile() = file;
140 : } else {
141 0 : MOZ_ASSERT(data.type() == FileSystemDirectoryListingResponseData::TFileSystemDirectoryListingResponseDirectory);
142 : const FileSystemDirectoryListingResponseDirectory& d =
143 0 : data.get_FileSystemDirectoryListingResponseDirectory();
144 :
145 0 : nsCOMPtr<nsIFile> path;
146 0 : aRv = NS_NewLocalFile(d.directoryRealPath(), true, getter_AddRefs(path));
147 0 : if (NS_WARN_IF(aRv.Failed())) {
148 0 : return;
149 : }
150 :
151 : RefPtr<Directory> directory =
152 0 : Directory::Create(mFileSystem->GetParentObject(), path, mFileSystem);
153 0 : MOZ_ASSERT(directory);
154 :
155 0 : ofd->SetAsDirectory() = directory;
156 : }
157 : }
158 : }
159 :
160 : void
161 0 : GetDirectoryListingTaskChild::HandlerCallback()
162 : {
163 0 : mFileSystem->AssertIsOnOwningThread();
164 :
165 0 : if (mFileSystem->IsShutdown()) {
166 0 : mPromise = nullptr;
167 0 : return;
168 : }
169 :
170 0 : if (HasError()) {
171 0 : mPromise->MaybeReject(mErrorValue);
172 0 : mPromise = nullptr;
173 0 : return;
174 : }
175 :
176 0 : mPromise->MaybeResolve(mTargetData);
177 0 : mPromise = nullptr;
178 : }
179 :
180 : /**
181 : * GetDirectoryListingTaskParent
182 : */
183 :
184 : /* static */ already_AddRefed<GetDirectoryListingTaskParent>
185 0 : GetDirectoryListingTaskParent::Create(FileSystemBase* aFileSystem,
186 : const FileSystemGetDirectoryListingParams& aParam,
187 : FileSystemRequestParent* aParent,
188 : ErrorResult& aRv)
189 : {
190 0 : MOZ_ASSERT(XRE_IsParentProcess(), "Only call from parent process!");
191 0 : AssertIsOnBackgroundThread();
192 0 : MOZ_ASSERT(aFileSystem);
193 :
194 : RefPtr<GetDirectoryListingTaskParent> task =
195 0 : new GetDirectoryListingTaskParent(aFileSystem, aParam, aParent);
196 :
197 0 : aRv = NS_NewLocalFile(aParam.realPath(), true,
198 0 : getter_AddRefs(task->mTargetPath));
199 0 : if (NS_WARN_IF(aRv.Failed())) {
200 0 : return nullptr;
201 : }
202 :
203 0 : return task.forget();
204 : }
205 :
206 0 : GetDirectoryListingTaskParent::GetDirectoryListingTaskParent(FileSystemBase* aFileSystem,
207 : const FileSystemGetDirectoryListingParams& aParam,
208 0 : FileSystemRequestParent* aParent)
209 : : FileSystemTaskParentBase(aFileSystem, aParam, aParent)
210 0 : , mDOMPath(aParam.domPath())
211 0 : , mFilters(aParam.filters())
212 : {
213 0 : MOZ_ASSERT(XRE_IsParentProcess(), "Only call from parent process!");
214 0 : AssertIsOnBackgroundThread();
215 0 : MOZ_ASSERT(aFileSystem);
216 0 : }
217 :
218 : FileSystemResponseValue
219 0 : GetDirectoryListingTaskParent::GetSuccessRequestResult(ErrorResult& aRv) const
220 : {
221 0 : AssertIsOnBackgroundThread();
222 :
223 0 : nsTArray<FileSystemDirectoryListingResponseData> inputs;
224 :
225 0 : for (unsigned i = 0; i < mTargetData.Length(); i++) {
226 0 : if (mTargetData[i].mType == FileOrDirectoryPath::eFilePath) {
227 0 : nsCOMPtr<nsIFile> path;
228 0 : nsresult rv = NS_NewLocalFile(mTargetData[i].mPath, true,
229 0 : getter_AddRefs(path));
230 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
231 0 : continue;
232 : }
233 :
234 0 : FileSystemDirectoryListingResponseFile fileData;
235 0 : RefPtr<BlobImpl> blobImpl = new FileBlobImpl(path);
236 :
237 0 : nsAutoString filePath;
238 0 : filePath.Assign(mDOMPath);
239 :
240 : // This is specific for unix root filesystem.
241 0 : if (!mDOMPath.EqualsLiteral(FILESYSTEM_DOM_PATH_SEPARATOR_LITERAL)) {
242 0 : filePath.AppendLiteral(FILESYSTEM_DOM_PATH_SEPARATOR_LITERAL);
243 : }
244 :
245 0 : nsAutoString name;
246 0 : blobImpl->GetName(name);
247 0 : filePath.Append(name);
248 0 : blobImpl->SetDOMPath(filePath);
249 :
250 0 : IPCBlob ipcBlob;
251 : rv =
252 0 : IPCBlobUtils::Serialize(blobImpl, mRequestParent->Manager(), ipcBlob);
253 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
254 0 : continue;
255 : }
256 :
257 0 : fileData.blob() = ipcBlob;
258 0 : inputs.AppendElement(fileData);
259 : } else {
260 0 : MOZ_ASSERT(mTargetData[i].mType == FileOrDirectoryPath::eDirectoryPath);
261 0 : FileSystemDirectoryListingResponseDirectory directoryData;
262 0 : directoryData.directoryRealPath() = mTargetData[i].mPath;
263 0 : inputs.AppendElement(directoryData);
264 : }
265 : }
266 :
267 0 : FileSystemDirectoryListingResponse response;
268 0 : response.data().SwapElements(inputs);
269 0 : return response;
270 : }
271 :
272 : nsresult
273 0 : GetDirectoryListingTaskParent::IOWork()
274 : {
275 0 : MOZ_ASSERT(XRE_IsParentProcess(),
276 : "Only call from parent process!");
277 0 : MOZ_ASSERT(!NS_IsMainThread(), "Only call on worker thread!");
278 :
279 0 : if (mFileSystem->IsShutdown()) {
280 0 : return NS_ERROR_FAILURE;
281 : }
282 :
283 : bool exists;
284 0 : nsresult rv = mTargetPath->Exists(&exists);
285 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
286 0 : return rv;
287 : }
288 :
289 0 : if (!exists) {
290 0 : if (!mFileSystem->ShouldCreateDirectory()) {
291 0 : return NS_ERROR_DOM_FILE_NOT_FOUND_ERR;
292 : }
293 :
294 0 : rv = mTargetPath->Create(nsIFile::DIRECTORY_TYPE, 0777);
295 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
296 0 : return rv;
297 : }
298 : }
299 :
300 : // Get isDirectory.
301 : bool isDir;
302 0 : rv = mTargetPath->IsDirectory(&isDir);
303 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
304 0 : return rv;
305 : }
306 :
307 0 : if (!isDir) {
308 0 : return NS_ERROR_DOM_FILESYSTEM_TYPE_MISMATCH_ERR;
309 : }
310 :
311 0 : nsCOMPtr<nsISimpleEnumerator> entries;
312 0 : rv = mTargetPath->GetDirectoryEntries(getter_AddRefs(entries));
313 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
314 0 : return rv;
315 : }
316 :
317 0 : bool filterOutSensitive = false;
318 : {
319 0 : HTMLSplitOnSpacesTokenizer tokenizer(mFilters, ';');
320 0 : nsAutoString token;
321 0 : while (tokenizer.hasMoreTokens()) {
322 0 : token = tokenizer.nextToken();
323 0 : if (token.EqualsLiteral("filter-out-sensitive")) {
324 0 : filterOutSensitive = true;
325 : } else {
326 0 : MOZ_CRASH("Unrecognized filter");
327 : }
328 : }
329 : }
330 :
331 : for (;;) {
332 0 : bool hasMore = false;
333 0 : if (NS_WARN_IF(NS_FAILED(entries->HasMoreElements(&hasMore))) || !hasMore) {
334 0 : break;
335 : }
336 0 : nsCOMPtr<nsISupports> supp;
337 0 : if (NS_WARN_IF(NS_FAILED(entries->GetNext(getter_AddRefs(supp))))) {
338 0 : break;
339 : }
340 :
341 0 : nsCOMPtr<nsIFile> currFile = do_QueryInterface(supp);
342 0 : MOZ_ASSERT(currFile);
343 :
344 : bool isSpecial, isFile;
345 0 : if (NS_WARN_IF(NS_FAILED(currFile->IsSpecial(&isSpecial))) ||
346 : isSpecial) {
347 0 : continue;
348 : }
349 0 : if (NS_WARN_IF(NS_FAILED(currFile->IsFile(&isFile)) ||
350 0 : NS_FAILED(currFile->IsDirectory(&isDir))) ||
351 0 : !(isFile || isDir)) {
352 0 : continue;
353 : }
354 :
355 0 : if (filterOutSensitive) {
356 : bool isHidden;
357 0 : if (NS_WARN_IF(NS_FAILED(currFile->IsHidden(&isHidden))) || isHidden) {
358 0 : continue;
359 : }
360 0 : nsAutoString leafName;
361 0 : if (NS_WARN_IF(NS_FAILED(currFile->GetLeafName(leafName)))) {
362 0 : continue;
363 : }
364 0 : if (leafName[0] == char16_t('.')) {
365 0 : continue;
366 : }
367 : }
368 :
369 0 : nsAutoString path;
370 0 : if (NS_WARN_IF(NS_FAILED(currFile->GetPath(path)))) {
371 0 : continue;
372 : }
373 :
374 0 : FileOrDirectoryPath element;
375 0 : element.mPath = path;
376 0 : element.mType = isDir ? FileOrDirectoryPath::eDirectoryPath
377 : : FileOrDirectoryPath::eFilePath;
378 :
379 0 : if (!mTargetData.AppendElement(element, fallible)) {
380 0 : return NS_ERROR_OUT_OF_MEMORY;
381 : }
382 0 : }
383 0 : return NS_OK;
384 : }
385 :
386 : nsresult
387 0 : GetDirectoryListingTaskParent::GetTargetPath(nsAString& aPath) const
388 : {
389 0 : return mTargetPath->GetPath(aPath);
390 : }
391 :
392 : } // namespace dom
393 : } // namespace mozilla
|