Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/dom/filesystem/GetDirectoryListingTask.cpp
Line
Count
Source (jump to first uncovered line)
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 "nsString.h"
21
22
namespace mozilla {
23
namespace dom {
24
25
/**
26
 * GetDirectoryListingTaskChild
27
 */
28
29
/* static */ already_AddRefed<GetDirectoryListingTaskChild>
30
GetDirectoryListingTaskChild::Create(FileSystemBase* aFileSystem,
31
                                     Directory* aDirectory,
32
                                     nsIFile* aTargetPath,
33
                                     const nsAString& aFilters,
34
                                     ErrorResult& aRv)
35
0
{
36
0
  MOZ_ASSERT(aFileSystem);
37
0
  MOZ_ASSERT(aDirectory);
38
0
  aFileSystem->AssertIsOnOwningThread();
39
0
40
0
  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
0
  }
46
0
47
0
  RefPtr<GetDirectoryListingTaskChild> task =
48
0
    new GetDirectoryListingTaskChild(globalObject, aFileSystem, aDirectory,
49
0
                                     aTargetPath, aFilters);
50
0
51
0
  // aTargetPath can be null. In this case SetError will be called.
52
0
53
0
  task->mPromise = Promise::Create(globalObject, aRv);
54
0
  if (NS_WARN_IF(aRv.Failed())) {
55
0
    return nullptr;
56
0
  }
57
0
58
0
  return task.forget();
59
0
}
60
61
GetDirectoryListingTaskChild::GetDirectoryListingTaskChild(nsIGlobalObject* aGlobalObject,
62
                                                           FileSystemBase* aFileSystem,
63
                                                           Directory* aDirectory,
64
                                                           nsIFile* aTargetPath,
65
                                                           const nsAString& aFilters)
66
  : FileSystemTaskChildBase(aGlobalObject, aFileSystem)
67
  , mDirectory(aDirectory)
68
  , mTargetPath(aTargetPath)
69
  , mFilters(aFilters)
70
0
{
71
0
  MOZ_ASSERT(aFileSystem);
72
0
  aFileSystem->AssertIsOnOwningThread();
73
0
}
74
75
GetDirectoryListingTaskChild::~GetDirectoryListingTaskChild()
76
0
{
77
0
  mFileSystem->AssertIsOnOwningThread();
78
0
}
79
80
already_AddRefed<Promise>
81
GetDirectoryListingTaskChild::GetPromise()
82
0
{
83
0
  mFileSystem->AssertIsOnOwningThread();
84
0
  return RefPtr<Promise>(mPromise).forget();
85
0
}
86
87
FileSystemParams
88
GetDirectoryListingTaskChild::GetRequestParams(const nsString& aSerializedDOMPath,
89
                                               ErrorResult& aRv) const
90
0
{
91
0
  mFileSystem->AssertIsOnOwningThread();
92
0
93
0
  // 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
0
  }
99
0
100
0
  // 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
0
  }
106
0
107
0
  return FileSystemGetDirectoryListingParams(aSerializedDOMPath, path,
108
0
                                             directoryPath, mFilters);
109
0
}
110
111
void
112
GetDirectoryListingTaskChild::SetSuccessRequestResult(const FileSystemResponseValue& aValue,
113
                                                      ErrorResult& aRv)
114
0
{
115
0
  mFileSystem->AssertIsOnOwningThread();
116
0
  MOZ_ASSERT(aValue.type() ==
117
0
               FileSystemResponseValue::TFileSystemDirectoryListingResponse);
118
0
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
0
123
0
    OwningFileOrDirectory* ofd = mTargetData.AppendElement(fallible);
124
0
    if (!ofd) {
125
0
      aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
126
0
      return;
127
0
    }
128
0
129
0
    if (data.type() == FileSystemDirectoryListingResponseData::TFileSystemDirectoryListingResponseFile) {
130
0
      const FileSystemDirectoryListingResponseFile& d =
131
0
        data.get_FileSystemDirectoryListingResponseFile();
132
0
133
0
      RefPtr<BlobImpl> blobImpl = IPCBlobUtils::Deserialize(d.blob());
134
0
      MOZ_ASSERT(blobImpl);
135
0
136
0
      RefPtr<File> file = File::Create(mFileSystem->GetParentObject(), blobImpl);
137
0
      MOZ_ASSERT(file);
138
0
139
0
      ofd->SetAsFile() = file;
140
0
    } else {
141
0
      MOZ_ASSERT(data.type() == FileSystemDirectoryListingResponseData::TFileSystemDirectoryListingResponseDirectory);
142
0
      const FileSystemDirectoryListingResponseDirectory& d =
143
0
        data.get_FileSystemDirectoryListingResponseDirectory();
144
0
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
0
      }
150
0
151
0
      RefPtr<Directory> directory =
152
0
        Directory::Create(mFileSystem->GetParentObject(), path, mFileSystem);
153
0
      MOZ_ASSERT(directory);
154
0
155
0
      ofd->SetAsDirectory() = directory;
156
0
    }
157
0
  }
158
0
}
159
160
void
161
GetDirectoryListingTaskChild::HandlerCallback()
162
0
{
163
0
  mFileSystem->AssertIsOnOwningThread();
164
0
165
0
  if (mFileSystem->IsShutdown()) {
166
0
    mPromise = nullptr;
167
0
    return;
168
0
  }
169
0
170
0
  if (HasError()) {
171
0
    mPromise->MaybeReject(mErrorValue);
172
0
    mPromise = nullptr;
173
0
    return;
174
0
  }
175
0
176
0
  mPromise->MaybeResolve(mTargetData);
177
0
  mPromise = nullptr;
178
0
}
179
180
/**
181
 * GetDirectoryListingTaskParent
182
 */
183
184
/* static */ already_AddRefed<GetDirectoryListingTaskParent>
185
GetDirectoryListingTaskParent::Create(FileSystemBase* aFileSystem,
186
                                      const FileSystemGetDirectoryListingParams& aParam,
187
                                      FileSystemRequestParent* aParent,
188
                                      ErrorResult& aRv)
189
0
{
190
0
  MOZ_ASSERT(XRE_IsParentProcess(), "Only call from parent process!");
191
0
  AssertIsOnBackgroundThread();
192
0
  MOZ_ASSERT(aFileSystem);
193
0
194
0
  RefPtr<GetDirectoryListingTaskParent> task =
195
0
    new GetDirectoryListingTaskParent(aFileSystem, aParam, aParent);
196
0
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
0
  }
202
0
203
0
  return task.forget();
204
0
}
205
206
GetDirectoryListingTaskParent::GetDirectoryListingTaskParent(FileSystemBase* aFileSystem,
207
                                                             const FileSystemGetDirectoryListingParams& aParam,
208
                                                             FileSystemRequestParent* aParent)
209
  : FileSystemTaskParentBase(aFileSystem, aParam, aParent)
210
  , mDOMPath(aParam.domPath())
211
  , mFilters(aParam.filters())
212
0
{
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
GetDirectoryListingTaskParent::GetSuccessRequestResult(ErrorResult& aRv) const
220
0
{
221
0
  AssertIsOnBackgroundThread();
222
0
223
0
  nsTArray<FileSystemDirectoryListingResponseData> inputs;
224
0
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
0
      }
233
0
234
0
      FileSystemDirectoryListingResponseFile fileData;
235
0
      RefPtr<BlobImpl> blobImpl = new FileBlobImpl(path);
236
0
237
0
      nsAutoString filePath;
238
0
      filePath.Assign(mDOMPath);
239
0
240
0
      // 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
0
      }
244
0
245
0
      nsAutoString name;
246
0
      blobImpl->GetName(name);
247
0
      filePath.Append(name);
248
0
      blobImpl->SetDOMPath(filePath);
249
0
250
0
      IPCBlob ipcBlob;
251
0
      rv =
252
0
        IPCBlobUtils::Serialize(blobImpl, mRequestParent->Manager(), ipcBlob);
253
0
      if (NS_WARN_IF(NS_FAILED(rv))) {
254
0
        continue;
255
0
      }
256
0
257
0
      fileData.blob() = ipcBlob;
258
0
      inputs.AppendElement(fileData);
259
0
    } 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
0
    }
265
0
  }
266
0
267
0
  FileSystemDirectoryListingResponse response;
268
0
  response.data().SwapElements(inputs);
269
0
  return response;
270
0
}
271
272
nsresult
273
GetDirectoryListingTaskParent::IOWork()
274
0
{
275
0
  MOZ_ASSERT(XRE_IsParentProcess(),
276
0
             "Only call from parent process!");
277
0
  MOZ_ASSERT(!NS_IsMainThread(), "Only call on worker thread!");
278
0
279
0
  if (mFileSystem->IsShutdown()) {
280
0
    return NS_ERROR_FAILURE;
281
0
  }
282
0
283
0
  bool exists;
284
0
  nsresult rv = mTargetPath->Exists(&exists);
285
0
  if (NS_WARN_IF(NS_FAILED(rv))) {
286
0
    return rv;
287
0
  }
288
0
289
0
  if (!exists) {
290
0
    if (!mFileSystem->ShouldCreateDirectory()) {
291
0
      return NS_ERROR_DOM_FILE_NOT_FOUND_ERR;
292
0
    }
293
0
294
0
    rv = mTargetPath->Create(nsIFile::DIRECTORY_TYPE, 0777);
295
0
    if (NS_WARN_IF(NS_FAILED(rv))) {
296
0
      return rv;
297
0
    }
298
0
  }
299
0
300
0
  // Get isDirectory.
301
0
  bool isDir;
302
0
  rv = mTargetPath->IsDirectory(&isDir);
303
0
  if (NS_WARN_IF(NS_FAILED(rv))) {
304
0
    return rv;
305
0
  }
306
0
307
0
  if (!isDir) {
308
0
    return NS_ERROR_DOM_FILESYSTEM_TYPE_MISMATCH_ERR;
309
0
  }
310
0
311
0
  nsCOMPtr<nsIDirectoryEnumerator> entries;
312
0
  rv = mTargetPath->GetDirectoryEntries(getter_AddRefs(entries));
313
0
  if (NS_WARN_IF(NS_FAILED(rv))) {
314
0
    return rv;
315
0
  }
316
0
317
0
  bool filterOutSensitive = false;
318
0
  {
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
0
      } else {
326
0
        MOZ_CRASH("Unrecognized filter");
327
0
      }
328
0
    }
329
0
  }
330
0
331
0
  for (;;) {
332
0
    nsCOMPtr<nsIFile> currFile;
333
0
    if (NS_WARN_IF(NS_FAILED(entries->GetNextFile(getter_AddRefs(currFile)))) || !currFile) {
334
0
      break;
335
0
    }
336
0
    bool isSpecial, isFile;
337
0
    if (NS_WARN_IF(NS_FAILED(currFile->IsSpecial(&isSpecial))) ||
338
0
        isSpecial) {
339
0
      continue;
340
0
    }
341
0
    if (NS_WARN_IF(NS_FAILED(currFile->IsFile(&isFile)) ||
342
0
                   NS_FAILED(currFile->IsDirectory(&isDir))) ||
343
0
        !(isFile || isDir)) {
344
0
      continue;
345
0
    }
346
0
347
0
    if (filterOutSensitive) {
348
0
      bool isHidden;
349
0
      if (NS_WARN_IF(NS_FAILED(currFile->IsHidden(&isHidden))) || isHidden) {
350
0
        continue;
351
0
      }
352
0
      nsAutoString leafName;
353
0
      if (NS_WARN_IF(NS_FAILED(currFile->GetLeafName(leafName)))) {
354
0
        continue;
355
0
      }
356
0
      if (leafName[0] == char16_t('.')) {
357
0
        continue;
358
0
      }
359
0
    }
360
0
361
0
    nsAutoString path;
362
0
    if (NS_WARN_IF(NS_FAILED(currFile->GetPath(path)))) {
363
0
      continue;
364
0
    }
365
0
366
0
    FileOrDirectoryPath element;
367
0
    element.mPath = path;
368
0
    element.mType = isDir ? FileOrDirectoryPath::eDirectoryPath
369
0
                          : FileOrDirectoryPath::eFilePath;
370
0
371
0
    if (!mTargetData.AppendElement(element, fallible)) {
372
0
      return NS_ERROR_OUT_OF_MEMORY;
373
0
    }
374
0
  }
375
0
  return NS_OK;
376
0
}
377
378
nsresult
379
GetDirectoryListingTaskParent::GetTargetPath(nsAString& aPath) const
380
0
{
381
0
  return mTargetPath->GetPath(aPath);
382
0
}
383
384
} // namespace dom
385
} // namespace mozilla