mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-02-12 18:50:08 +00:00
Bug 1258694 - Implement Directory::GetFiles(), r=smaug
This commit is contained in:
parent
11ea1f64cc
commit
e3a78f6247
@ -131,7 +131,7 @@ CreateDirectoryTaskChild::HandlerCallback()
|
||||
void
|
||||
CreateDirectoryTaskChild::GetPermissionAccessType(nsCString& aAccess) const
|
||||
{
|
||||
aAccess.AssignLiteral(CREATE_DIRECTORY_TASK_PERMISSION);
|
||||
aAccess.AssignLiteral(DIRECTORY_CREATE_PERMISSION);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -216,7 +216,7 @@ CreateDirectoryTaskParent::IOWork()
|
||||
void
|
||||
CreateDirectoryTaskParent::GetPermissionAccessType(nsCString& aAccess) const
|
||||
{
|
||||
aAccess.AssignLiteral(CREATE_DIRECTORY_TASK_PERMISSION);
|
||||
aAccess.AssignLiteral(DIRECTORY_CREATE_PERMISSION);
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
|
@ -11,8 +11,6 @@
|
||||
#include "nsAutoPtr.h"
|
||||
#include "mozilla/ErrorResult.h"
|
||||
|
||||
#define CREATE_DIRECTORY_TASK_PERMISSION "create"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
|
@ -5,8 +5,6 @@
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "CreateFileTask.h"
|
||||
#include "CreateDirectoryTask.h"
|
||||
#include "RemoveTask.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
@ -27,10 +25,10 @@
|
||||
|
||||
#define GET_PERMISSION_ACCESS_TYPE(aAccess) \
|
||||
if (mReplace) { \
|
||||
aAccess.AssignLiteral(REMOVE_TASK_PERMISSION); \
|
||||
aAccess.AssignLiteral(DIRECTORY_WRITE_PERMISSION); \
|
||||
return; \
|
||||
} \
|
||||
aAccess.AssignLiteral(CREATE_DIRECTORY_TASK_PERMISSION);
|
||||
aAccess.AssignLiteral(DIRECTORY_CREATE_PERMISSION);
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include "FileSystemPermissionRequest.h"
|
||||
#include "GetDirectoryListingTask.h"
|
||||
#include "GetFileOrDirectoryTask.h"
|
||||
#include "GetFilesTask.h"
|
||||
#include "RemoveTask.h"
|
||||
|
||||
#include "nsCharSeparatedTokenizer.h"
|
||||
@ -446,6 +447,27 @@ Directory::GetFilesAndDirectories(ErrorResult& aRv)
|
||||
return task->GetPromise();
|
||||
}
|
||||
|
||||
already_AddRefed<Promise>
|
||||
Directory::GetFiles(bool aRecursiveFlag, ErrorResult& aRv)
|
||||
{
|
||||
ErrorResult rv;
|
||||
RefPtr<FileSystemBase> fs = GetFileSystem(rv);
|
||||
if (NS_WARN_IF(rv.Failed())) {
|
||||
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RefPtr<GetFilesTaskChild> task =
|
||||
GetFilesTaskChild::Create(fs, mFile, aRecursiveFlag, rv);
|
||||
if (NS_WARN_IF(rv.Failed())) {
|
||||
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
FileSystemPermissionRequest::RequestForTask(task);
|
||||
return task->GetPromise();
|
||||
}
|
||||
|
||||
void
|
||||
Directory::SetContentFilters(const nsAString& aFilters)
|
||||
{
|
||||
|
@ -112,6 +112,9 @@ public:
|
||||
already_AddRefed<Promise>
|
||||
GetFilesAndDirectories(ErrorResult& aRv);
|
||||
|
||||
already_AddRefed<Promise>
|
||||
GetFiles(bool aRecursiveFlag, ErrorResult& aRv);
|
||||
|
||||
// =========== End WebIDL bindings.============
|
||||
|
||||
/**
|
||||
|
@ -53,6 +53,7 @@ FileSystemRequestParent::Initialize(const FileSystemParams& aParams)
|
||||
FILESYSTEM_REQUEST_PARENT_DISPATCH_ENTRY(CreateFile)
|
||||
FILESYSTEM_REQUEST_PARENT_DISPATCH_ENTRY(GetDirectoryListing)
|
||||
FILESYSTEM_REQUEST_PARENT_DISPATCH_ENTRY(GetFileOrDirectory)
|
||||
FILESYSTEM_REQUEST_PARENT_DISPATCH_ENTRY(GetFiles)
|
||||
FILESYSTEM_REQUEST_PARENT_DISPATCH_ENTRY(Remove)
|
||||
|
||||
default: {
|
||||
|
@ -20,6 +20,10 @@ class FileSystemBase;
|
||||
class FileSystemParams;
|
||||
class PBlobParent;
|
||||
|
||||
#define DIRECTORY_READ_PERMISSION "read"
|
||||
#define DIRECTORY_WRITE_PERMISSION "write"
|
||||
#define DIRECTORY_CREATE_PERMISSION "create"
|
||||
|
||||
/*
|
||||
* The base class to implement a Task class.
|
||||
* The file system operations can only be performed in the parent process. In
|
||||
|
@ -18,8 +18,6 @@
|
||||
#include "nsIFile.h"
|
||||
#include "nsStringGlue.h"
|
||||
|
||||
#define GET_DIRECTORY_LISTING_PERMISSION "read"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
@ -206,7 +204,7 @@ GetDirectoryListingTaskChild::HandlerCallback()
|
||||
void
|
||||
GetDirectoryListingTaskChild::GetPermissionAccessType(nsCString& aAccess) const
|
||||
{
|
||||
aAccess.AssignLiteral(GET_DIRECTORY_LISTING_PERMISSION);
|
||||
aAccess.AssignLiteral(DIRECTORY_READ_PERMISSION);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -394,7 +392,7 @@ GetDirectoryListingTaskParent::IOWork()
|
||||
void
|
||||
GetDirectoryListingTaskParent::GetPermissionAccessType(nsCString& aAccess) const
|
||||
{
|
||||
aAccess.AssignLiteral(GET_DIRECTORY_LISTING_PERMISSION);
|
||||
aAccess.AssignLiteral(DIRECTORY_READ_PERMISSION);
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
|
@ -17,8 +17,6 @@
|
||||
#include "nsIFile.h"
|
||||
#include "nsStringGlue.h"
|
||||
|
||||
#define GET_FILE_OR_DIRECTORY_PERMISSION "read"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
@ -171,7 +169,7 @@ GetFileOrDirectoryTaskChild::HandlerCallback()
|
||||
void
|
||||
GetFileOrDirectoryTaskChild::GetPermissionAccessType(nsCString& aAccess) const
|
||||
{
|
||||
aAccess.AssignLiteral(GET_FILE_OR_DIRECTORY_PERMISSION);
|
||||
aAccess.AssignLiteral(DIRECTORY_READ_PERMISSION);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -298,7 +296,7 @@ GetFileOrDirectoryTaskParent::IOWork()
|
||||
void
|
||||
GetFileOrDirectoryTaskParent::GetPermissionAccessType(nsCString& aAccess) const
|
||||
{
|
||||
aAccess.AssignLiteral(GET_FILE_OR_DIRECTORY_PERMISSION);
|
||||
aAccess.AssignLiteral(DIRECTORY_READ_PERMISSION);
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
|
359
dom/filesystem/GetFilesTask.cpp
Normal file
359
dom/filesystem/GetFilesTask.cpp
Normal file
@ -0,0 +1,359 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "GetFilesTask.h"
|
||||
|
||||
#include "HTMLSplitOnSpacesTokenizer.h"
|
||||
#include "js/Value.h"
|
||||
#include "mozilla/dom/File.h"
|
||||
#include "mozilla/dom/FileSystemBase.h"
|
||||
#include "mozilla/dom/FileSystemUtils.h"
|
||||
#include "mozilla/dom/PFileSystemParams.h"
|
||||
#include "mozilla/dom/Promise.h"
|
||||
#include "mozilla/dom/ipc/BlobChild.h"
|
||||
#include "mozilla/dom/ipc/BlobParent.h"
|
||||
#include "nsIFile.h"
|
||||
#include "nsStringGlue.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
/**
|
||||
* GetFilesTaskChild
|
||||
*/
|
||||
|
||||
/* static */ already_AddRefed<GetFilesTaskChild>
|
||||
GetFilesTaskChild::Create(FileSystemBase* aFileSystem,
|
||||
nsIFile* aTargetPath,
|
||||
bool aRecursiveFlag,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
MOZ_ASSERT(aFileSystem);
|
||||
aFileSystem->AssertIsOnOwningThread();
|
||||
|
||||
nsCOMPtr<nsIGlobalObject> globalObject =
|
||||
do_QueryInterface(aFileSystem->GetParentObject());
|
||||
if (NS_WARN_IF(!globalObject)) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RefPtr<GetFilesTaskChild> task =
|
||||
new GetFilesTaskChild(aFileSystem, aTargetPath, aRecursiveFlag);
|
||||
|
||||
// aTargetPath can be null. In this case SetError will be called.
|
||||
|
||||
task->mPromise = Promise::Create(globalObject, aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return task.forget();
|
||||
}
|
||||
|
||||
GetFilesTaskChild::GetFilesTaskChild(FileSystemBase* aFileSystem,
|
||||
nsIFile* aTargetPath,
|
||||
bool aRecursiveFlag)
|
||||
: FileSystemTaskChildBase(aFileSystem)
|
||||
, mTargetPath(aTargetPath)
|
||||
, mRecursiveFlag(aRecursiveFlag)
|
||||
{
|
||||
MOZ_ASSERT(aFileSystem);
|
||||
aFileSystem->AssertIsOnOwningThread();
|
||||
}
|
||||
|
||||
GetFilesTaskChild::~GetFilesTaskChild()
|
||||
{
|
||||
mFileSystem->AssertIsOnOwningThread();
|
||||
}
|
||||
|
||||
already_AddRefed<Promise>
|
||||
GetFilesTaskChild::GetPromise()
|
||||
{
|
||||
mFileSystem->AssertIsOnOwningThread();
|
||||
return RefPtr<Promise>(mPromise).forget();
|
||||
}
|
||||
|
||||
FileSystemParams
|
||||
GetFilesTaskChild::GetRequestParams(const nsString& aSerializedDOMPath,
|
||||
ErrorResult& aRv) const
|
||||
{
|
||||
mFileSystem->AssertIsOnOwningThread();
|
||||
|
||||
nsAutoString path;
|
||||
aRv = mTargetPath->GetPath(path);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return FileSystemGetFilesParams();
|
||||
}
|
||||
|
||||
return FileSystemGetFilesParams(aSerializedDOMPath, path, mRecursiveFlag);
|
||||
}
|
||||
|
||||
void
|
||||
GetFilesTaskChild::SetSuccessRequestResult(const FileSystemResponseValue& aValue,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
mFileSystem->AssertIsOnOwningThread();
|
||||
MOZ_ASSERT(aValue.type() ==
|
||||
FileSystemResponseValue::TFileSystemFilesResponse);
|
||||
|
||||
FileSystemFilesResponse r = aValue;
|
||||
|
||||
if (!mTargetData.SetLength(r.data().Length(), mozilla::fallible_t())) {
|
||||
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
|
||||
return;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < r.data().Length(); ++i) {
|
||||
const FileSystemFileResponse& data = r.data()[i];
|
||||
mTargetData[i] = data.realPath();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
GetFilesTaskChild::HandlerCallback()
|
||||
{
|
||||
mFileSystem->AssertIsOnOwningThread();
|
||||
if (mFileSystem->IsShutdown()) {
|
||||
mPromise = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
if (HasError()) {
|
||||
mPromise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
mPromise = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
size_t count = mTargetData.Length();
|
||||
|
||||
Sequence<RefPtr<File>> listing;
|
||||
|
||||
if (!listing.SetLength(count, mozilla::fallible_t())) {
|
||||
mPromise->MaybeReject(NS_ERROR_OUT_OF_MEMORY);
|
||||
mPromise = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
for (unsigned i = 0; i < count; i++) {
|
||||
nsCOMPtr<nsIFile> path;
|
||||
NS_ConvertUTF16toUTF8 fullPath(mTargetData[i]);
|
||||
nsresult rv = NS_NewNativeLocalFile(fullPath, true, getter_AddRefs(path));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
mPromise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
mPromise = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
nsCOMPtr<nsIFile> rootPath;
|
||||
rv = NS_NewLocalFile(mFileSystem->LocalOrDeviceStorageRootPath(), false,
|
||||
getter_AddRefs(rootPath));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
mPromise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
mPromise = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(FileSystemUtils::IsDescendantPath(rootPath, path));
|
||||
#endif
|
||||
|
||||
RefPtr<File> file =
|
||||
File::CreateFromFile(mFileSystem->GetParentObject(), path);
|
||||
MOZ_ASSERT(file);
|
||||
|
||||
listing[i] = file;
|
||||
}
|
||||
|
||||
mPromise->MaybeResolve(listing);
|
||||
mPromise = nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
GetFilesTaskChild::GetPermissionAccessType(nsCString& aAccess) const
|
||||
{
|
||||
aAccess.AssignLiteral("read");
|
||||
}
|
||||
|
||||
/**
|
||||
* GetFilesTaskParent
|
||||
*/
|
||||
|
||||
/* static */ already_AddRefed<GetFilesTaskParent>
|
||||
GetFilesTaskParent::Create(FileSystemBase* aFileSystem,
|
||||
const FileSystemGetFilesParams& aParam,
|
||||
FileSystemRequestParent* aParent,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
MOZ_ASSERT(XRE_IsParentProcess(), "Only call from parent process!");
|
||||
AssertIsOnBackgroundThread();
|
||||
MOZ_ASSERT(aFileSystem);
|
||||
|
||||
RefPtr<GetFilesTaskParent> task =
|
||||
new GetFilesTaskParent(aFileSystem, aParam, aParent);
|
||||
|
||||
NS_ConvertUTF16toUTF8 path(aParam.realPath());
|
||||
aRv = NS_NewNativeLocalFile(path, true, getter_AddRefs(task->mTargetPath));
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return task.forget();
|
||||
}
|
||||
|
||||
GetFilesTaskParent::GetFilesTaskParent(FileSystemBase* aFileSystem,
|
||||
const FileSystemGetFilesParams& aParam,
|
||||
FileSystemRequestParent* aParent)
|
||||
: FileSystemTaskParentBase(aFileSystem, aParam, aParent)
|
||||
, mRecursiveFlag(aParam.recursiveFlag())
|
||||
{
|
||||
MOZ_ASSERT(XRE_IsParentProcess(), "Only call from parent process!");
|
||||
AssertIsOnBackgroundThread();
|
||||
MOZ_ASSERT(aFileSystem);
|
||||
}
|
||||
|
||||
FileSystemResponseValue
|
||||
GetFilesTaskParent::GetSuccessRequestResult(ErrorResult& aRv) const
|
||||
{
|
||||
AssertIsOnBackgroundThread();
|
||||
|
||||
InfallibleTArray<PBlobParent*> blobs;
|
||||
|
||||
FallibleTArray<FileSystemFileResponse> inputs;
|
||||
if (!inputs.SetLength(mTargetData.Length(), mozilla::fallible_t())) {
|
||||
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
|
||||
FileSystemFilesResponse response;
|
||||
return response;
|
||||
}
|
||||
|
||||
for (unsigned i = 0; i < mTargetData.Length(); i++) {
|
||||
FileSystemFileResponse fileData;
|
||||
fileData.realPath() = mTargetData[i];
|
||||
inputs[i] = fileData;
|
||||
}
|
||||
|
||||
FileSystemFilesResponse response;
|
||||
response.data().SwapElements(inputs);
|
||||
return response;
|
||||
}
|
||||
|
||||
nsresult
|
||||
GetFilesTaskParent::IOWork()
|
||||
{
|
||||
MOZ_ASSERT(XRE_IsParentProcess(),
|
||||
"Only call from parent process!");
|
||||
MOZ_ASSERT(!NS_IsMainThread(), "Only call on I/O thread!");
|
||||
|
||||
if (mFileSystem->IsShutdown()) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
bool exists;
|
||||
nsresult rv = mTargetPath->Exists(&exists);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (!exists) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Get isDirectory.
|
||||
rv = ExploreDirectory(mTargetPath);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
GetFilesTaskParent::ExploreDirectory(nsIFile* aPath)
|
||||
{
|
||||
MOZ_ASSERT(XRE_IsParentProcess(),
|
||||
"Only call from parent process!");
|
||||
MOZ_ASSERT(!NS_IsMainThread(), "Only call on worker thread!");
|
||||
MOZ_ASSERT(aPath);
|
||||
|
||||
bool isDir;
|
||||
nsresult rv = aPath->IsDirectory(&isDir);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (!isDir) {
|
||||
return NS_ERROR_DOM_FILESYSTEM_TYPE_MISMATCH_ERR;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsISimpleEnumerator> entries;
|
||||
rv = aPath->GetDirectoryEntries(getter_AddRefs(entries));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
bool hasMore = false;
|
||||
if (NS_WARN_IF(NS_FAILED(entries->HasMoreElements(&hasMore))) || !hasMore) {
|
||||
break;
|
||||
}
|
||||
nsCOMPtr<nsISupports> supp;
|
||||
if (NS_WARN_IF(NS_FAILED(entries->GetNext(getter_AddRefs(supp))))) {
|
||||
break;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIFile> currFile = do_QueryInterface(supp);
|
||||
MOZ_ASSERT(currFile);
|
||||
|
||||
bool isLink, isSpecial, isFile;
|
||||
if (NS_WARN_IF(NS_FAILED(currFile->IsSymlink(&isLink)) ||
|
||||
NS_FAILED(currFile->IsSpecial(&isSpecial))) ||
|
||||
isLink || isSpecial) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (NS_WARN_IF(NS_FAILED(currFile->IsFile(&isFile)) ||
|
||||
NS_FAILED(currFile->IsDirectory(&isDir))) ||
|
||||
!(isFile || isDir)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (isFile) {
|
||||
nsAutoString path;
|
||||
if (NS_WARN_IF(NS_FAILED(currFile->GetPath(path)))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!mTargetData.AppendElement(path, fallible)) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(isDir);
|
||||
|
||||
if (!mRecursiveFlag) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Recursive.
|
||||
rv = ExploreDirectory(currFile);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
GetFilesTaskParent::GetPermissionAccessType(nsCString& aAccess) const
|
||||
{
|
||||
aAccess.AssignLiteral(DIRECTORY_READ_PERMISSION);
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
99
dom/filesystem/GetFilesTask.h
Normal file
99
dom/filesystem/GetFilesTask.h
Normal file
@ -0,0 +1,99 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_dom_GetFilesTask_h
|
||||
#define mozilla_dom_GetFilesTask_h
|
||||
|
||||
#include "mozilla/dom/Directory.h"
|
||||
#include "mozilla/dom/FileSystemTaskBase.h"
|
||||
#include "mozilla/ErrorResult.h"
|
||||
#include "nsAutoPtr.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class BlobImpl;
|
||||
|
||||
class GetFilesTaskChild final : public FileSystemTaskChildBase
|
||||
{
|
||||
public:
|
||||
static already_AddRefed<GetFilesTaskChild>
|
||||
Create(FileSystemBase* aFileSystem,
|
||||
nsIFile* aTargetPath,
|
||||
bool aRecursiveFlag,
|
||||
ErrorResult& aRv);
|
||||
|
||||
virtual
|
||||
~GetFilesTaskChild();
|
||||
|
||||
already_AddRefed<Promise>
|
||||
GetPromise();
|
||||
|
||||
virtual void
|
||||
GetPermissionAccessType(nsCString& aAccess) const override;
|
||||
|
||||
private:
|
||||
// If aDirectoryOnly is set, we should ensure that the target is a directory.
|
||||
GetFilesTaskChild(FileSystemBase* aFileSystem,
|
||||
nsIFile* aTargetPath,
|
||||
bool aRecursiveFlag);
|
||||
|
||||
virtual FileSystemParams
|
||||
GetRequestParams(const nsString& aSerializedDOMPath,
|
||||
ErrorResult& aRv) const override;
|
||||
|
||||
virtual void
|
||||
SetSuccessRequestResult(const FileSystemResponseValue& aValue,
|
||||
ErrorResult& aRv) override;
|
||||
|
||||
virtual void
|
||||
HandlerCallback() override;
|
||||
|
||||
RefPtr<Promise> mPromise;
|
||||
nsCOMPtr<nsIFile> mTargetPath;
|
||||
bool mRecursiveFlag;
|
||||
|
||||
// We store the fullpath of Files.
|
||||
FallibleTArray<nsString> mTargetData;
|
||||
};
|
||||
|
||||
class GetFilesTaskParent final : public FileSystemTaskParentBase
|
||||
{
|
||||
public:
|
||||
static already_AddRefed<GetFilesTaskParent>
|
||||
Create(FileSystemBase* aFileSystem,
|
||||
const FileSystemGetFilesParams& aParam,
|
||||
FileSystemRequestParent* aParent,
|
||||
ErrorResult& aRv);
|
||||
|
||||
virtual void
|
||||
GetPermissionAccessType(nsCString& aAccess) const override;
|
||||
|
||||
private:
|
||||
GetFilesTaskParent(FileSystemBase* aFileSystem,
|
||||
const FileSystemGetFilesParams& aParam,
|
||||
FileSystemRequestParent* aParent);
|
||||
|
||||
virtual FileSystemResponseValue
|
||||
GetSuccessRequestResult(ErrorResult& aRv) const override;
|
||||
|
||||
virtual nsresult
|
||||
IOWork() override;
|
||||
|
||||
nsresult
|
||||
ExploreDirectory(nsIFile* aPath);
|
||||
|
||||
nsCOMPtr<nsIFile> mTargetPath;
|
||||
bool mRecursiveFlag;
|
||||
|
||||
// We store the fullpath of Files.
|
||||
FallibleTArray<nsString> mTargetData;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_dom_GetFilesTask_h
|
@ -44,6 +44,13 @@ struct FileSystemGetDirectoryListingParams
|
||||
nsString filters;
|
||||
};
|
||||
|
||||
struct FileSystemGetFilesParams
|
||||
{
|
||||
nsString filesystem;
|
||||
nsString realPath;
|
||||
bool recursiveFlag;
|
||||
};
|
||||
|
||||
struct FileSystemGetFileOrDirectoryParams
|
||||
{
|
||||
nsString filesystem;
|
||||
@ -64,6 +71,7 @@ union FileSystemParams
|
||||
FileSystemCreateDirectoryParams;
|
||||
FileSystemCreateFileParams;
|
||||
FileSystemGetDirectoryListingParams;
|
||||
FileSystemGetFilesParams;
|
||||
FileSystemGetFileOrDirectoryParams;
|
||||
FileSystemRemoveParams;
|
||||
};
|
||||
|
@ -43,6 +43,11 @@ struct FileSystemDirectoryListingResponse
|
||||
FileSystemDirectoryListingResponseData[] data;
|
||||
};
|
||||
|
||||
struct FileSystemFilesResponse
|
||||
{
|
||||
FileSystemFileResponse[] data;
|
||||
};
|
||||
|
||||
struct FileSystemErrorResponse
|
||||
{
|
||||
nsresult error;
|
||||
@ -59,6 +64,7 @@ union FileSystemResponseValue
|
||||
FileSystemDirectoryResponse;
|
||||
FileSystemDirectoryListingResponse;
|
||||
FileSystemFileResponse;
|
||||
FileSystemFilesResponse;
|
||||
FileSystemErrorResponse;
|
||||
};
|
||||
|
||||
|
@ -142,7 +142,7 @@ RemoveTaskChild::HandlerCallback()
|
||||
void
|
||||
RemoveTaskChild::GetPermissionAccessType(nsCString& aAccess) const
|
||||
{
|
||||
aAccess.AssignLiteral(REMOVE_TASK_PERMISSION);
|
||||
aAccess.AssignLiteral(DIRECTORY_WRITE_PERMISSION);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -252,7 +252,7 @@ RemoveTaskParent::IOWork()
|
||||
void
|
||||
RemoveTaskParent::GetPermissionAccessType(nsCString& aAccess) const
|
||||
{
|
||||
aAccess.AssignLiteral(REMOVE_TASK_PERMISSION);
|
||||
aAccess.AssignLiteral(DIRECTORY_WRITE_PERMISSION);
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
|
@ -11,8 +11,6 @@
|
||||
#include "nsAutoPtr.h"
|
||||
#include "mozilla/ErrorResult.h"
|
||||
|
||||
#define REMOVE_TASK_PERMISSION "write"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
|
@ -28,6 +28,7 @@ UNIFIED_SOURCES += [
|
||||
'FileSystemUtils.cpp',
|
||||
'GetDirectoryListingTask.cpp',
|
||||
'GetFileOrDirectoryTask.cpp',
|
||||
'GetFilesTask.cpp',
|
||||
'OSFileSystem.cpp',
|
||||
'RemoveTask.cpp',
|
||||
]
|
||||
|
75
dom/filesystem/tests/filesystem_commons.js
Normal file
75
dom/filesystem/tests/filesystem_commons.js
Normal file
@ -0,0 +1,75 @@
|
||||
function test_basic(aDirectory, aNext) {
|
||||
ok(aDirectory, "Directory exists.");
|
||||
ok(aDirectory instanceof Directory, "We have a directory.");
|
||||
is(aDirectory.name, '/', "directory.name must be '/'");
|
||||
is(aDirectory.path, '/', "directory.path must be '/'");
|
||||
aNext();
|
||||
}
|
||||
|
||||
function test_getFilesAndDirectories(aDirectory, aRecursive, aNext) {
|
||||
function checkSubDir(dir) {
|
||||
return dir.getFilesAndDirectories().then(
|
||||
function(data) {
|
||||
for (var i = 0; i < data.length; ++i) {
|
||||
ok (data[i] instanceof File || data[i] instanceof Directory, "Just Files or Directories");
|
||||
if (data[i] instanceof Directory) {
|
||||
isnot(data[i].name, '/', "Subdirectory should be called with the leafname");
|
||||
isnot(data[i].path, '/', "Subdirectory path should be called with the leafname");
|
||||
isnot(data[i].path, dir.path, "Subdirectory path should contain the parent path.");
|
||||
is(data[i].path,dir.path + '/' + data[i].name, "Subdirectory path should be called parentdir.path + '/' + leafname");
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
aDirectory.getFilesAndDirectories().then(
|
||||
function(data) {
|
||||
ok(data.length, "We should have some data.");
|
||||
var promises = [];
|
||||
for (var i = 0; i < data.length; ++i) {
|
||||
ok (data[i] instanceof File || data[i] instanceof Directory, "Just Files or Directories: " + data[i].name);
|
||||
if (data[i] instanceof Directory) {
|
||||
isnot(data[i].name, '/', "Subdirectory should be called with the leafname");
|
||||
is(data[i].path, '/' + data[i].name, "Subdirectory path should be called '/' + leafname");
|
||||
if (aRecursive) {
|
||||
promises.push(checkSubDir(data[i]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Promise.all(promises);
|
||||
},
|
||||
function() {
|
||||
ok(false, "Something when wrong");
|
||||
}
|
||||
).then(aNext);
|
||||
}
|
||||
|
||||
function test_getFiles(aDirectory, aRecursive, aNext) {
|
||||
aDirectory.getFiles(aRecursive).then(
|
||||
function(data) {
|
||||
for (var i = 0; i < data.length; ++i) {
|
||||
ok (data[i] instanceof File, "File: " + data[i].name);
|
||||
}
|
||||
},
|
||||
function() {
|
||||
ok(false, "Something when wrong");
|
||||
}
|
||||
).then(aNext);
|
||||
}
|
||||
|
||||
function test_getFiles_recursiveComparison(aDirectory, aNext) {
|
||||
aDirectory.getFiles(true).then(function(data) {
|
||||
is(data.length, 2, "Only 2 files for this test.");
|
||||
ok(data[0].name == 'foo.txt' || data[0].name == 'bar.txt', "First filename matches");
|
||||
ok(data[1].name == 'foo.txt' || data[1].name == 'bar.txt', "Second filename matches");
|
||||
}).then(function() {
|
||||
return aDirectory.getFiles(false);
|
||||
}).then(function(data) {
|
||||
is(data.length, 1, "Only 1 file for this test.");
|
||||
ok(data[0].name == 'foo.txt' || data[0].name == 'bar.txt', "First filename matches");
|
||||
}).catch(function() {
|
||||
ok(false, "Something when wrong");
|
||||
}).then(aNext);
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
[DEFAULT]
|
||||
support-files =
|
||||
filesystem_commons.js
|
||||
script_fileList.js
|
||||
worker_basic.js
|
||||
|
||||
|
@ -1,22 +1,67 @@
|
||||
var { classes: Cc, interfaces: Ci, utils: Cu } = Components;
|
||||
Cu.importGlobalProperties(["File"]);
|
||||
|
||||
addMessageListener("dir.open", function (e) {
|
||||
var testFile = Cc["@mozilla.org/file/directory_service;1"]
|
||||
.getService(Ci.nsIDirectoryService)
|
||||
.QueryInterface(Ci.nsIProperties)
|
||||
.get(e.path == 'root' ? 'ProfD' : e.path, Ci.nsIFile);
|
||||
function createProfDFile() {
|
||||
return Cc["@mozilla.org/file/directory_service;1"]
|
||||
.getService(Ci.nsIDirectoryService)
|
||||
.QueryInterface(Ci.nsIProperties)
|
||||
.get('ProfD', Ci.nsIFile);
|
||||
}
|
||||
|
||||
function createRootFile() {
|
||||
var testFile = createProfDFile();
|
||||
|
||||
// Let's go back to the root of the FileSystem
|
||||
if (e.path == 'root') {
|
||||
while (true) {
|
||||
var parent = testFile.parent;
|
||||
if (!parent) {
|
||||
break;
|
||||
}
|
||||
|
||||
testFile = parent;
|
||||
while (true) {
|
||||
var parent = testFile.parent;
|
||||
if (!parent) {
|
||||
break;
|
||||
}
|
||||
|
||||
testFile = parent;
|
||||
}
|
||||
|
||||
return testFile;
|
||||
}
|
||||
|
||||
function createTestFile() {
|
||||
var tmpFile = Cc["@mozilla.org/file/directory_service;1"]
|
||||
.getService(Ci.nsIDirectoryService)
|
||||
.QueryInterface(Ci.nsIProperties)
|
||||
.get('TmpD', Ci.nsIFile)
|
||||
tmpFile.append('dir-test');
|
||||
tmpFile.createUnique(Components.interfaces.nsIFile.DIRECTORY_TYPE, 0o700);
|
||||
|
||||
var file1 = tmpFile.clone();
|
||||
file1.append('foo.txt');
|
||||
file1.create(Components.interfaces.nsIFile.NORMAL_FILE_TYPE, 0o600);
|
||||
|
||||
var dir = tmpFile.clone();
|
||||
dir.append('subdir');
|
||||
dir.create(Components.interfaces.nsIFile.DIRECTORY_TYPE, 0o700);
|
||||
|
||||
var file2 = dir.clone();
|
||||
file2.append('bar.txt');
|
||||
file2.create(Components.interfaces.nsIFile.NORMAL_FILE_TYPE, 0o600);
|
||||
|
||||
return tmpFile;
|
||||
}
|
||||
|
||||
addMessageListener("dir.open", function (e) {
|
||||
var testFile;
|
||||
|
||||
switch (e.path) {
|
||||
case 'ProfD':
|
||||
testFile = createProfDFile();
|
||||
break;
|
||||
|
||||
case 'root':
|
||||
testFile = createRootFile();
|
||||
break;
|
||||
|
||||
case 'test':
|
||||
testFile = createTestFile();
|
||||
break;
|
||||
}
|
||||
|
||||
sendAsyncMessage("dir.opened", {
|
||||
|
@ -3,6 +3,7 @@
|
||||
<head>
|
||||
<title>Test for Directory API</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="filesystem_commons.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
|
||||
@ -34,63 +35,20 @@ function create_fileList(aPath) {
|
||||
script.sendAsyncMessage("dir.open", { path: aPath });
|
||||
}
|
||||
|
||||
function test_basic() {
|
||||
ok(directory, "Directory exists.");
|
||||
ok(directory instanceof Directory, "We have a directory.");
|
||||
is(directory.name, '/', "directory.name must be '/'");
|
||||
is(directory.path, '/', "directory.path must be '/'");
|
||||
next();
|
||||
}
|
||||
|
||||
function checkSubDir(dir) {
|
||||
return dir.getFilesAndDirectories().then(
|
||||
function(data) {
|
||||
for (var i = 0; i < data.length; ++i) {
|
||||
ok (data[i] instanceof File || data[i] instanceof Directory, "Just Files or Directories");
|
||||
if (data[i] instanceof Directory) {
|
||||
isnot(data[i].name, '/', "Subdirectory should be called with the leafname: " + data[i].name);
|
||||
isnot(data[i].path, '/', "Subdirectory path should be called with the leafname:" + data[i].path);
|
||||
isnot(data[i].path, dir.path, "Subdirectory path should contain the parent path.");
|
||||
is(data[i].path,dir.path + '/' + data[i].name, "Subdirectory path should be called parentdir.path + '/' + leafname");
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
function getFilesAndDirectories(aRecursive) {
|
||||
directory.getFilesAndDirectories().then(
|
||||
function(data) {
|
||||
ok(data.length, "We should have some data.");
|
||||
var promises = [];
|
||||
for (var i = 0; i < data.length; ++i) {
|
||||
ok (data[i] instanceof File || data[i] instanceof Directory, "Just Files or Directories");
|
||||
if (data[i] instanceof Directory) {
|
||||
isnot(data[i].name, '/', "Subdirectory should be called with the leafname");
|
||||
is(data[i].path, '/' + data[i].name, "Subdirectory path should be called '/' + leafname");
|
||||
|
||||
if (aRecursive) {
|
||||
promises.push(checkSubDir(data[i]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Promise.all(promises);
|
||||
},
|
||||
function() {
|
||||
ok(false, "Something when wrong");
|
||||
}
|
||||
).then(next);
|
||||
}
|
||||
|
||||
var tests = [
|
||||
function() { create_fileList('ProfD') },
|
||||
test_basic,
|
||||
function() { getFilesAndDirectories(true) },
|
||||
function() { test_basic(directory, next); },
|
||||
function() { test_getFilesAndDirectories(directory, true, next); },
|
||||
function() { test_getFiles(directory, false, next); },
|
||||
function() { test_getFiles(directory, true, next); },
|
||||
|
||||
function() { create_fileList('root') },
|
||||
test_basic,
|
||||
function() { getFilesAndDirectories(false) },
|
||||
function() { create_fileList('test') },
|
||||
function() { test_getFiles_recursiveComparison(directory, next); },
|
||||
|
||||
function() { create_fileList('root'); },
|
||||
function() { test_basic(directory, next); },
|
||||
function() { test_getFilesAndDirectories(directory, false, next); },
|
||||
function() { test_getFiles(directory, false, next); },
|
||||
];
|
||||
|
||||
function next() {
|
||||
|
@ -1,3 +1,5 @@
|
||||
importScripts('filesystem_commons.js');
|
||||
|
||||
function finish() {
|
||||
postMessage({ type: 'finish' });
|
||||
}
|
||||
@ -14,43 +16,26 @@ function isnot(a, b, msg) {
|
||||
ok(a != b, msg);
|
||||
}
|
||||
|
||||
function checkSubDir(dir) {
|
||||
return dir.getFilesAndDirectories().then(
|
||||
function(data) {
|
||||
for (var i = 0; i < data.length; ++i) {
|
||||
ok (data[i] instanceof File || data[i] instanceof Directory, "Just Files or Directories");
|
||||
if (data[i] instanceof Directory) {
|
||||
isnot(data[i].name, '/', "Subdirectory should be called with the leafname");
|
||||
isnot(data[i].path, '/', "Subdirectory path should be called with the leafname");
|
||||
isnot(data[i].path, dir.path, "Subdirectory path should contain the parent path.");
|
||||
is(data[i].path,dir.path + '/' + data[i].name, "Subdirectory path should be called parentdir.path + '/' + leafname");
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
var tests = [
|
||||
function() { test_basic(directory, next); },
|
||||
function() { test_getFilesAndDirectories(directory, true, next); },
|
||||
function() { test_getFiles(directory, false, next); },
|
||||
function() { test_getFiles(directory, true, next); },
|
||||
];
|
||||
|
||||
function next() {
|
||||
if (!tests.length) {
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
|
||||
var test = tests.shift();
|
||||
test();
|
||||
}
|
||||
|
||||
var directory;
|
||||
|
||||
onmessage = function(e) {
|
||||
var directory = e.data;
|
||||
ok(directory instanceof Directory, "This is a directory.");
|
||||
|
||||
directory.getFilesAndDirectories().then(
|
||||
function(data) {
|
||||
ok(data.length, "We should have some data.");
|
||||
var promises = [];
|
||||
for (var i = 0; i < data.length; ++i) {
|
||||
ok (data[i] instanceof File || data[i] instanceof Directory, "Just Files or Directories");
|
||||
if (data[i] instanceof Directory) {
|
||||
isnot(data[i].name, '/', "Subdirectory should be called with the leafname");
|
||||
is(data[i].path, '/' + data[i].name, "Subdirectory path should be called '/' + leafname");
|
||||
promises.push(checkSubDir(data[i]));
|
||||
}
|
||||
}
|
||||
|
||||
return Promise.all(promises);
|
||||
},
|
||||
function() {
|
||||
ok(false, "Something when wrong");
|
||||
}
|
||||
).then(finish);
|
||||
directory = e.data;
|
||||
next();
|
||||
}
|
||||
|
@ -114,6 +114,9 @@ partial interface Directory {
|
||||
*/
|
||||
[Throws]
|
||||
Promise<sequence<(File or Directory)>> getFilesAndDirectories();
|
||||
|
||||
[Throws]
|
||||
Promise<sequence<File>> getFiles(optional boolean recursiveFlag = false);
|
||||
};
|
||||
|
||||
enum CreateIfExistsMode { "replace", "fail" };
|
||||
|
Loading…
x
Reference in New Issue
Block a user