mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-02-12 18:50:08 +00:00
Bug 1258221 - patch 2 - Port FileSystem API and DeviceStorage API to PBackground, r=smaug
This commit is contained in:
parent
c6067c0a80
commit
9345155089
@ -9,13 +9,22 @@
|
||||
#include "mozilla/dom/Directory.h"
|
||||
#include "mozilla/dom/FileSystemBase.h"
|
||||
#include "mozilla/dom/FileSystemUtils.h"
|
||||
#include "mozilla/dom/PFileSystemParams.h"
|
||||
#include "mozilla/dom/Promise.h"
|
||||
#include "mozilla/ipc/BackgroundParent.h"
|
||||
#include "nsIFile.h"
|
||||
#include "nsStringGlue.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
using namespace ipc;
|
||||
|
||||
namespace dom {
|
||||
|
||||
/**
|
||||
* CreateDirectoryTask
|
||||
*/
|
||||
|
||||
/* static */ already_AddRefed<CreateDirectoryTask>
|
||||
CreateDirectoryTask::Create(FileSystemBase* aFileSystem,
|
||||
nsIFile* aTargetPath,
|
||||
@ -44,28 +53,6 @@ CreateDirectoryTask::Create(FileSystemBase* aFileSystem,
|
||||
return task.forget();
|
||||
}
|
||||
|
||||
/* static */ already_AddRefed<CreateDirectoryTask>
|
||||
CreateDirectoryTask::Create(FileSystemBase* aFileSystem,
|
||||
const FileSystemCreateDirectoryParams& aParam,
|
||||
FileSystemRequestParent* aParent,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
MOZ_ASSERT(XRE_IsParentProcess(), "Only call from parent process!");
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
MOZ_ASSERT(aFileSystem);
|
||||
|
||||
RefPtr<CreateDirectoryTask> task =
|
||||
new CreateDirectoryTask(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();
|
||||
}
|
||||
|
||||
CreateDirectoryTask::CreateDirectoryTask(FileSystemBase* aFileSystem,
|
||||
nsIFile* aTargetPath)
|
||||
: FileSystemTaskBase(aFileSystem)
|
||||
@ -75,20 +62,9 @@ CreateDirectoryTask::CreateDirectoryTask(FileSystemBase* aFileSystem,
|
||||
MOZ_ASSERT(aFileSystem);
|
||||
}
|
||||
|
||||
CreateDirectoryTask::CreateDirectoryTask(FileSystemBase* aFileSystem,
|
||||
const FileSystemCreateDirectoryParams& aParam,
|
||||
FileSystemRequestParent* aParent)
|
||||
: FileSystemTaskBase(aFileSystem, aParam, aParent)
|
||||
{
|
||||
MOZ_ASSERT(XRE_IsParentProcess(), "Only call from parent process!");
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
MOZ_ASSERT(aFileSystem);
|
||||
}
|
||||
|
||||
CreateDirectoryTask::~CreateDirectoryTask()
|
||||
{
|
||||
MOZ_ASSERT(!mPromise || NS_IsMainThread(),
|
||||
"mPromise should be released on main thread!");
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
}
|
||||
|
||||
already_AddRefed<Promise>
|
||||
@ -113,11 +89,92 @@ CreateDirectoryTask::GetRequestParams(const nsString& aSerializedDOMPath,
|
||||
return FileSystemCreateDirectoryParams(aSerializedDOMPath, path);
|
||||
}
|
||||
|
||||
FileSystemResponseValue
|
||||
CreateDirectoryTask::GetSuccessRequestResult(ErrorResult& aRv) const
|
||||
void
|
||||
CreateDirectoryTask::SetSuccessRequestResult(const FileSystemResponseValue& aValue,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
|
||||
const FileSystemDirectoryResponse& r =
|
||||
aValue.get_FileSystemDirectoryResponse();
|
||||
|
||||
aRv = NS_NewNativeLocalFile(NS_ConvertUTF16toUTF8(r.realPath()), true,
|
||||
getter_AddRefs(mTargetPath));
|
||||
NS_WARN_IF(aRv.Failed());
|
||||
}
|
||||
|
||||
void
|
||||
CreateDirectoryTask::HandlerCallback()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
if (mFileSystem->IsShutdown()) {
|
||||
mPromise = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
if (HasError()) {
|
||||
mPromise->MaybeReject(mErrorValue);
|
||||
mPromise = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
RefPtr<Directory> dir = Directory::Create(mFileSystem->GetParentObject(),
|
||||
mTargetPath,
|
||||
Directory::eNotDOMRootDirectory,
|
||||
mFileSystem);
|
||||
MOZ_ASSERT(dir);
|
||||
|
||||
mPromise->MaybeResolve(dir);
|
||||
mPromise = nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
CreateDirectoryTask::GetPermissionAccessType(nsCString& aAccess) const
|
||||
{
|
||||
aAccess.AssignLiteral(CREATE_DIRECTORY_TASK_PERMISSION);
|
||||
}
|
||||
|
||||
/**
|
||||
* CreateDirectoryTaskParent
|
||||
*/
|
||||
|
||||
/* static */ already_AddRefed<CreateDirectoryTaskParent>
|
||||
CreateDirectoryTaskParent::Create(FileSystemBase* aFileSystem,
|
||||
const FileSystemCreateDirectoryParams& aParam,
|
||||
FileSystemRequestParent* aParent,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
MOZ_ASSERT(XRE_IsParentProcess(), "Only call from parent process!");
|
||||
AssertIsOnBackgroundThread();
|
||||
MOZ_ASSERT(aFileSystem);
|
||||
|
||||
RefPtr<CreateDirectoryTaskParent> task =
|
||||
new CreateDirectoryTaskParent(aFileSystem, aParam, aParent);
|
||||
|
||||
aRv = NS_NewNativeLocalFile(NS_ConvertUTF16toUTF8(aParam.realPath()), true,
|
||||
getter_AddRefs(task->mTargetPath));
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return task.forget();
|
||||
}
|
||||
|
||||
CreateDirectoryTaskParent::CreateDirectoryTaskParent(FileSystemBase* aFileSystem,
|
||||
const FileSystemCreateDirectoryParams& aParam,
|
||||
FileSystemRequestParent* aParent)
|
||||
: FileSystemTaskParentBase(aFileSystem, aParam, aParent)
|
||||
{
|
||||
MOZ_ASSERT(XRE_IsParentProcess(), "Only call from parent process!");
|
||||
AssertIsOnBackgroundThread();
|
||||
MOZ_ASSERT(aFileSystem);
|
||||
}
|
||||
|
||||
FileSystemResponseValue
|
||||
CreateDirectoryTaskParent::GetSuccessRequestResult(ErrorResult& aRv) const
|
||||
{
|
||||
AssertIsOnBackgroundThread();
|
||||
|
||||
nsAutoString path;
|
||||
aRv = mTargetPath->GetPath(path);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
@ -127,20 +184,8 @@ CreateDirectoryTask::GetSuccessRequestResult(ErrorResult& aRv) const
|
||||
return FileSystemDirectoryResponse(path);
|
||||
}
|
||||
|
||||
void
|
||||
CreateDirectoryTask::SetSuccessRequestResult(const FileSystemResponseValue& aValue,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
FileSystemDirectoryResponse r = aValue;
|
||||
|
||||
NS_ConvertUTF16toUTF8 path(r.realPath());
|
||||
aRv = NS_NewNativeLocalFile(path, true, getter_AddRefs(mTargetPath));
|
||||
NS_WARN_IF(aRv.Failed());
|
||||
}
|
||||
|
||||
nsresult
|
||||
CreateDirectoryTask::Work()
|
||||
CreateDirectoryTaskParent::IOWork()
|
||||
{
|
||||
MOZ_ASSERT(XRE_IsParentProcess(),
|
||||
"Only call from parent process!");
|
||||
@ -169,33 +214,9 @@ CreateDirectoryTask::Work()
|
||||
}
|
||||
|
||||
void
|
||||
CreateDirectoryTask::HandlerCallback()
|
||||
CreateDirectoryTaskParent::GetPermissionAccessType(nsCString& aAccess) const
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
if (mFileSystem->IsShutdown()) {
|
||||
mPromise = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
if (HasError()) {
|
||||
mPromise->MaybeReject(mErrorValue);
|
||||
mPromise = nullptr;
|
||||
return;
|
||||
}
|
||||
RefPtr<Directory> dir = Directory::Create(mFileSystem->GetParentObject(),
|
||||
mTargetPath,
|
||||
Directory::eNotDOMRootDirectory,
|
||||
mFileSystem);
|
||||
MOZ_ASSERT(dir);
|
||||
|
||||
mPromise->MaybeResolve(dir);
|
||||
mPromise = nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
CreateDirectoryTask::GetPermissionAccessType(nsCString& aAccess) const
|
||||
{
|
||||
aAccess.AssignLiteral("create");
|
||||
aAccess.AssignLiteral(CREATE_DIRECTORY_TASK_PERMISSION);
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
|
@ -11,9 +11,12 @@
|
||||
#include "nsAutoPtr.h"
|
||||
#include "mozilla/ErrorResult.h"
|
||||
|
||||
#define CREATE_DIRECTORY_TASK_PERMISSION "create"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class FileSystemCreateDirectoryParams;
|
||||
class Promise;
|
||||
|
||||
class CreateDirectoryTask final : public FileSystemTaskBase
|
||||
@ -24,12 +27,6 @@ public:
|
||||
nsIFile* aTargetPath,
|
||||
ErrorResult& aRv);
|
||||
|
||||
static already_AddRefed<CreateDirectoryTask>
|
||||
Create(FileSystemBase* aFileSystem,
|
||||
const FileSystemCreateDirectoryParams& aParam,
|
||||
FileSystemRequestParent* aParent,
|
||||
ErrorResult& aRv);
|
||||
|
||||
virtual
|
||||
~CreateDirectoryTask();
|
||||
|
||||
@ -39,36 +36,54 @@ public:
|
||||
virtual void
|
||||
GetPermissionAccessType(nsCString& aAccess) const override;
|
||||
|
||||
virtual void
|
||||
HandlerCallback() override;
|
||||
|
||||
protected:
|
||||
virtual FileSystemParams
|
||||
GetRequestParams(const nsString& aSerializedDOMPath,
|
||||
ErrorResult& aRv) const override;
|
||||
|
||||
virtual FileSystemResponseValue
|
||||
GetSuccessRequestResult(ErrorResult& aRv) const override;
|
||||
|
||||
virtual void
|
||||
SetSuccessRequestResult(const FileSystemResponseValue& aValue,
|
||||
ErrorResult& aRv) override;
|
||||
|
||||
virtual nsresult
|
||||
Work() override;
|
||||
|
||||
virtual void
|
||||
HandlerCallback() override;
|
||||
|
||||
private:
|
||||
CreateDirectoryTask(FileSystemBase* aFileSystem,
|
||||
nsIFile* aTargetPath);
|
||||
|
||||
CreateDirectoryTask(FileSystemBase* aFileSystem,
|
||||
const FileSystemCreateDirectoryParams& aParam,
|
||||
FileSystemRequestParent* aParent);
|
||||
|
||||
RefPtr<Promise> mPromise;
|
||||
nsCOMPtr<nsIFile> mTargetPath;
|
||||
};
|
||||
|
||||
class CreateDirectoryTaskParent final : public FileSystemTaskParentBase
|
||||
{
|
||||
public:
|
||||
static already_AddRefed<CreateDirectoryTaskParent>
|
||||
Create(FileSystemBase* aFileSystem,
|
||||
const FileSystemCreateDirectoryParams& aParam,
|
||||
FileSystemRequestParent* aParent,
|
||||
ErrorResult& aRv);
|
||||
|
||||
virtual void
|
||||
GetPermissionAccessType(nsCString& aAccess) const override;
|
||||
|
||||
protected:
|
||||
virtual nsresult
|
||||
IOWork() override;
|
||||
|
||||
virtual FileSystemResponseValue
|
||||
GetSuccessRequestResult(ErrorResult& aRv) const override;
|
||||
|
||||
private:
|
||||
CreateDirectoryTaskParent(FileSystemBase* aFileSystem,
|
||||
const FileSystemCreateDirectoryParams& aParam,
|
||||
FileSystemRequestParent* aParent);
|
||||
|
||||
nsCOMPtr<nsIFile> mTargetPath;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
|
@ -5,6 +5,8 @@
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "CreateFileTask.h"
|
||||
#include "CreateDirectoryTask.h"
|
||||
#include "RemoveTask.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
@ -12,18 +14,30 @@
|
||||
#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 "mozilla/ipc/BackgroundChild.h"
|
||||
#include "mozilla/ipc/PBackgroundChild.h"
|
||||
#include "nsIFile.h"
|
||||
#include "nsNetUtil.h"
|
||||
#include "nsIOutputStream.h"
|
||||
#include "nsStringGlue.h"
|
||||
|
||||
#define GET_PERMISSION_ACCESS_TYPE(aAccess) \
|
||||
if (mReplace) { \
|
||||
aAccess.AssignLiteral(REMOVE_TASK_PERMISSION); \
|
||||
return; \
|
||||
} \
|
||||
aAccess.AssignLiteral(CREATE_DIRECTORY_TASK_PERMISSION);
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
uint32_t CreateFileTask::sOutputBufferSize = 0;
|
||||
/**
|
||||
*CreateFileTask
|
||||
*/
|
||||
|
||||
/* static */ already_AddRefed<CreateFileTask>
|
||||
CreateFileTask::Create(FileSystemBase* aFileSystem,
|
||||
@ -41,17 +55,8 @@ CreateFileTask::Create(FileSystemBase* aFileSystem,
|
||||
|
||||
// aTargetPath can be null. In this case SetError will be called.
|
||||
|
||||
task->GetOutputBufferSize();
|
||||
|
||||
if (aBlobData) {
|
||||
if (XRE_IsParentProcess()) {
|
||||
aBlobData->GetInternalStream(getter_AddRefs(task->mBlobStream), aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
} else {
|
||||
task->mBlobData = aBlobData;
|
||||
}
|
||||
task->mBlobImpl = aBlobData->Impl();
|
||||
}
|
||||
|
||||
task->mArrayData.SwapElements(aArrayData);
|
||||
@ -71,49 +76,6 @@ CreateFileTask::Create(FileSystemBase* aFileSystem,
|
||||
return task.forget();
|
||||
}
|
||||
|
||||
/* static */ already_AddRefed<CreateFileTask>
|
||||
CreateFileTask::Create(FileSystemBase* aFileSystem,
|
||||
const FileSystemCreateFileParams& aParam,
|
||||
FileSystemRequestParent* aParent,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
MOZ_ASSERT(XRE_IsParentProcess(), "Only call from parent process!");
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
MOZ_ASSERT(aFileSystem);
|
||||
|
||||
RefPtr<CreateFileTask> task =
|
||||
new CreateFileTask(aFileSystem, aParam, aParent);
|
||||
|
||||
task->GetOutputBufferSize();
|
||||
|
||||
NS_ConvertUTF16toUTF8 path(aParam.realPath());
|
||||
aRv = NS_NewNativeLocalFile(path, true, getter_AddRefs(task->mTargetPath));
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
task->mReplace = aParam.replace();
|
||||
|
||||
auto& data = aParam.data();
|
||||
|
||||
if (data.type() == FileSystemFileDataValue::TArrayOfuint8_t) {
|
||||
task->mArrayData = data;
|
||||
return task.forget();
|
||||
}
|
||||
|
||||
BlobParent* bp = static_cast<BlobParent*>(static_cast<PBlobParent*>(data));
|
||||
RefPtr<BlobImpl> blobImpl = bp->GetBlobImpl();
|
||||
MOZ_ASSERT(blobImpl, "blobData should not be null.");
|
||||
|
||||
ErrorResult rv;
|
||||
blobImpl->GetInternalStream(getter_AddRefs(task->mBlobStream), rv);
|
||||
if (NS_WARN_IF(rv.Failed())) {
|
||||
rv.SuppressException();
|
||||
}
|
||||
|
||||
return task.forget();
|
||||
}
|
||||
|
||||
CreateFileTask::CreateFileTask(FileSystemBase* aFileSystem,
|
||||
nsIFile* aTargetPath,
|
||||
bool aReplace)
|
||||
@ -125,25 +87,9 @@ CreateFileTask::CreateFileTask(FileSystemBase* aFileSystem,
|
||||
MOZ_ASSERT(aFileSystem);
|
||||
}
|
||||
|
||||
CreateFileTask::CreateFileTask(FileSystemBase* aFileSystem,
|
||||
const FileSystemCreateFileParams& aParam,
|
||||
FileSystemRequestParent* aParent)
|
||||
: FileSystemTaskBase(aFileSystem, aParam, aParent)
|
||||
, mReplace(false)
|
||||
{
|
||||
MOZ_ASSERT(XRE_IsParentProcess(), "Only call from parent process!");
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
MOZ_ASSERT(aFileSystem);
|
||||
}
|
||||
|
||||
CreateFileTask::~CreateFileTask()
|
||||
{
|
||||
MOZ_ASSERT((!mPromise && !mBlobData) || NS_IsMainThread(),
|
||||
"mPromise and mBlobData should be released on main thread!");
|
||||
|
||||
if (mBlobStream) {
|
||||
mBlobStream->Close();
|
||||
}
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
}
|
||||
|
||||
already_AddRefed<Promise>
|
||||
@ -166,12 +112,21 @@ CreateFileTask::GetRequestParams(const nsString& aSerializedDOMPath,
|
||||
return param;
|
||||
}
|
||||
|
||||
// If we are here, PBackground must be up and running: this method is called
|
||||
// when the task has been already started by FileSystemPermissionRequest
|
||||
// class and this happens only when PBackground actor has already been
|
||||
// created.
|
||||
PBackgroundChild* actor =
|
||||
mozilla::ipc::BackgroundChild::GetForCurrentThread();
|
||||
MOZ_ASSERT(actor);
|
||||
|
||||
param.replace() = mReplace;
|
||||
if (mBlobData) {
|
||||
BlobChild* actor =
|
||||
ContentChild::GetSingleton()->GetOrCreateActorForBlob(mBlobData);
|
||||
if (actor) {
|
||||
param.data() = actor;
|
||||
if (mBlobImpl) {
|
||||
PBlobChild* blobActor =
|
||||
mozilla::ipc::BackgroundChild::GetOrCreateActorForBlobImpl(actor,
|
||||
mBlobImpl);
|
||||
if (blobActor) {
|
||||
param.data() = blobActor;
|
||||
}
|
||||
} else {
|
||||
param.data() = mArrayData;
|
||||
@ -179,11 +134,108 @@ CreateFileTask::GetRequestParams(const nsString& aSerializedDOMPath,
|
||||
return param;
|
||||
}
|
||||
|
||||
FileSystemResponseValue
|
||||
CreateFileTask::GetSuccessRequestResult(ErrorResult& aRv) const
|
||||
void
|
||||
CreateFileTask::SetSuccessRequestResult(const FileSystemResponseValue& aValue,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
|
||||
const FileSystemFileResponse& r = aValue.get_FileSystemFileResponse();
|
||||
|
||||
NS_ConvertUTF16toUTF8 path(r.realPath());
|
||||
aRv = NS_NewNativeLocalFile(path, true, getter_AddRefs(mTargetPath));
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CreateFileTask::HandlerCallback()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
|
||||
if (mFileSystem->IsShutdown()) {
|
||||
mPromise = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
if (HasError()) {
|
||||
mPromise->MaybeReject(mErrorValue);
|
||||
mPromise = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
RefPtr<File> file = File::CreateFromFile(mFileSystem->GetParentObject(),
|
||||
mTargetPath);
|
||||
mPromise->MaybeResolve(file);
|
||||
mPromise = nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
CreateFileTask::GetPermissionAccessType(nsCString& aAccess) const
|
||||
{
|
||||
GET_PERMISSION_ACCESS_TYPE(aAccess)
|
||||
}
|
||||
|
||||
/**
|
||||
* CreateFileTaskParent
|
||||
*/
|
||||
|
||||
uint32_t CreateFileTaskParent::sOutputBufferSize = 0;
|
||||
|
||||
/* static */ already_AddRefed<CreateFileTaskParent>
|
||||
CreateFileTaskParent::Create(FileSystemBase* aFileSystem,
|
||||
const FileSystemCreateFileParams& aParam,
|
||||
FileSystemRequestParent* aParent,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
MOZ_ASSERT(XRE_IsParentProcess(), "Only call from parent process!");
|
||||
AssertIsOnBackgroundThread();
|
||||
MOZ_ASSERT(aFileSystem);
|
||||
|
||||
RefPtr<CreateFileTaskParent> task =
|
||||
new CreateFileTaskParent(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;
|
||||
}
|
||||
|
||||
task->mReplace = aParam.replace();
|
||||
|
||||
const FileSystemFileDataValue& data = aParam.data();
|
||||
|
||||
if (data.type() == FileSystemFileDataValue::TArrayOfuint8_t) {
|
||||
task->mArrayData = data;
|
||||
return task.forget();
|
||||
}
|
||||
|
||||
MOZ_ASSERT(data.type() == FileSystemFileDataValue::TPBlobParent);
|
||||
|
||||
BlobParent* bp = static_cast<BlobParent*>(static_cast<PBlobParent*>(data));
|
||||
task->mBlobImpl = bp->GetBlobImpl();
|
||||
MOZ_ASSERT(task->mBlobImpl, "blobData should not be null.");
|
||||
|
||||
return task.forget();
|
||||
}
|
||||
|
||||
CreateFileTaskParent::CreateFileTaskParent(FileSystemBase* aFileSystem,
|
||||
const FileSystemCreateFileParams& aParam,
|
||||
FileSystemRequestParent* aParent)
|
||||
: FileSystemTaskParentBase(aFileSystem, aParam, aParent)
|
||||
, mReplace(false)
|
||||
{
|
||||
MOZ_ASSERT(XRE_IsParentProcess(), "Only call from parent process!");
|
||||
AssertIsOnBackgroundThread();
|
||||
MOZ_ASSERT(aFileSystem);
|
||||
}
|
||||
|
||||
FileSystemResponseValue
|
||||
CreateFileTaskParent::GetSuccessRequestResult(ErrorResult& aRv) const
|
||||
{
|
||||
AssertIsOnBackgroundThread();
|
||||
|
||||
nsAutoString path;
|
||||
aRv = mTargetPath->GetPath(path);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
@ -193,22 +245,8 @@ CreateFileTask::GetSuccessRequestResult(ErrorResult& aRv) const
|
||||
return FileSystemFileResponse(path);
|
||||
}
|
||||
|
||||
void
|
||||
CreateFileTask::SetSuccessRequestResult(const FileSystemResponseValue& aValue,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
FileSystemFileResponse r = aValue;
|
||||
|
||||
NS_ConvertUTF16toUTF8 path(r.realPath());
|
||||
aRv = NS_NewNativeLocalFile(path, true, getter_AddRefs(mTargetPath));
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
nsresult
|
||||
CreateFileTask::Work()
|
||||
CreateFileTaskParent::IOWork()
|
||||
{
|
||||
class MOZ_RAII AutoClose final
|
||||
{
|
||||
@ -280,6 +318,7 @@ CreateFileTask::Work()
|
||||
}
|
||||
|
||||
AutoClose acOutputStream(outputStream);
|
||||
MOZ_ASSERT(sOutputBufferSize);
|
||||
|
||||
nsCOMPtr<nsIOutputStream> bufferedOutputStream;
|
||||
rv = NS_NewBufferedOutputStream(getter_AddRefs(bufferedOutputStream),
|
||||
@ -291,11 +330,17 @@ CreateFileTask::Work()
|
||||
|
||||
AutoClose acBufferedOutputStream(bufferedOutputStream);
|
||||
|
||||
if (mBlobStream) {
|
||||
// Write the file content from blob data.
|
||||
// Write the file content from blob data.
|
||||
if (mBlobImpl) {
|
||||
ErrorResult error;
|
||||
nsCOMPtr<nsIInputStream> blobStream;
|
||||
mBlobImpl->GetInternalStream(getter_AddRefs(blobStream), error);
|
||||
if (NS_WARN_IF(error.Failed())) {
|
||||
return error.StealNSResult();
|
||||
}
|
||||
|
||||
uint64_t bufSize = 0;
|
||||
rv = mBlobStream->Available(&bufSize);
|
||||
rv = blobStream->Available(&bufSize);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
@ -303,15 +348,14 @@ CreateFileTask::Work()
|
||||
while (bufSize && !mFileSystem->IsShutdown()) {
|
||||
uint32_t written = 0;
|
||||
uint32_t writeSize = bufSize < UINT32_MAX ? bufSize : UINT32_MAX;
|
||||
rv = bufferedOutputStream->WriteFrom(mBlobStream, writeSize, &written);
|
||||
rv = bufferedOutputStream->WriteFrom(blobStream, writeSize, &written);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
bufSize -= written;
|
||||
}
|
||||
|
||||
mBlobStream->Close();
|
||||
mBlobStream = nullptr;
|
||||
blobStream->Close();
|
||||
|
||||
if (mFileSystem->IsShutdown()) {
|
||||
return NS_ERROR_FAILURE;
|
||||
@ -338,49 +382,23 @@ CreateFileTask::Work()
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
CreateFileTask::HandlerCallback()
|
||||
nsresult
|
||||
CreateFileTaskParent::MainThreadWork()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
if (mFileSystem->IsShutdown()) {
|
||||
mPromise = nullptr;
|
||||
mBlobData = nullptr;
|
||||
return;
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (!sOutputBufferSize) {
|
||||
sOutputBufferSize =
|
||||
mozilla::Preferences::GetUint("dom.filesystem.outputBufferSize", 4096 * 4);
|
||||
}
|
||||
|
||||
if (HasError()) {
|
||||
mPromise->MaybeReject(mErrorValue);
|
||||
mPromise = nullptr;
|
||||
mBlobData = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
RefPtr<File> file = File::CreateFromFile(mFileSystem->GetParentObject(),
|
||||
mTargetPath);
|
||||
mPromise->MaybeResolve(file);
|
||||
mPromise = nullptr;
|
||||
mBlobData = nullptr;
|
||||
return FileSystemTaskParentBase::MainThreadWork();
|
||||
}
|
||||
|
||||
void
|
||||
CreateFileTask::GetPermissionAccessType(nsCString& aAccess) const
|
||||
CreateFileTaskParent::GetPermissionAccessType(nsCString& aAccess) const
|
||||
{
|
||||
if (mReplace) {
|
||||
aAccess.AssignLiteral("write");
|
||||
return;
|
||||
}
|
||||
|
||||
aAccess.AssignLiteral("create");
|
||||
}
|
||||
|
||||
void
|
||||
CreateFileTask::GetOutputBufferSize() const
|
||||
{
|
||||
if (sOutputBufferSize || !XRE_IsParentProcess()) {
|
||||
return;
|
||||
}
|
||||
sOutputBufferSize =
|
||||
mozilla::Preferences::GetUint("dom.filesystem.outputBufferSize", 4096 * 4);
|
||||
GET_PERMISSION_ACCESS_TYPE(aAccess)
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
|
@ -31,12 +31,6 @@ public:
|
||||
bool replace,
|
||||
ErrorResult& aRv);
|
||||
|
||||
static already_AddRefed<CreateFileTask>
|
||||
Create(FileSystemBase* aFileSystem,
|
||||
const FileSystemCreateFileParams& aParam,
|
||||
FileSystemRequestParent* aParent,
|
||||
ErrorResult& aRv);
|
||||
|
||||
virtual
|
||||
~CreateFileTask();
|
||||
|
||||
@ -51,16 +45,10 @@ protected:
|
||||
GetRequestParams(const nsString& aSerializedDOMPath,
|
||||
ErrorResult& aRv) const override;
|
||||
|
||||
virtual FileSystemResponseValue
|
||||
GetSuccessRequestResult(ErrorResult& aRv) const override;
|
||||
|
||||
virtual void
|
||||
SetSuccessRequestResult(const FileSystemResponseValue& aValue,
|
||||
ErrorResult& aRv) override;
|
||||
|
||||
virtual nsresult
|
||||
Work() override;
|
||||
|
||||
virtual void
|
||||
HandlerCallback() override;
|
||||
|
||||
@ -69,22 +57,58 @@ private:
|
||||
nsIFile* aFile,
|
||||
bool aReplace);
|
||||
|
||||
CreateFileTask(FileSystemBase* aFileSystem,
|
||||
const FileSystemCreateFileParams& aParam,
|
||||
FileSystemRequestParent* aParent);
|
||||
|
||||
void
|
||||
GetOutputBufferSize() const;
|
||||
|
||||
static uint32_t sOutputBufferSize;
|
||||
RefPtr<Promise> mPromise;
|
||||
nsCOMPtr<nsIFile> mTargetPath;
|
||||
|
||||
// Not thread-safe and should be released on main thread.
|
||||
RefPtr<Blob> mBlobData;
|
||||
RefPtr<BlobImpl> mBlobImpl;
|
||||
|
||||
nsCOMPtr<nsIInputStream> mBlobStream;
|
||||
// This is going to be the content of the file, received by createFile()
|
||||
// params.
|
||||
InfallibleTArray<uint8_t> mArrayData;
|
||||
|
||||
bool mReplace;
|
||||
};
|
||||
|
||||
class CreateFileTaskParent final : public FileSystemTaskParentBase
|
||||
{
|
||||
public:
|
||||
static already_AddRefed<CreateFileTaskParent>
|
||||
Create(FileSystemBase* aFileSystem,
|
||||
const FileSystemCreateFileParams& aParam,
|
||||
FileSystemRequestParent* aParent,
|
||||
ErrorResult& aRv);
|
||||
|
||||
virtual bool
|
||||
NeedToGoToMainThread() const override { return true; }
|
||||
|
||||
virtual nsresult
|
||||
MainThreadWork() override;
|
||||
|
||||
virtual void
|
||||
GetPermissionAccessType(nsCString& aAccess) const override;
|
||||
|
||||
protected:
|
||||
virtual FileSystemResponseValue
|
||||
GetSuccessRequestResult(ErrorResult& aRv) const override;
|
||||
|
||||
virtual nsresult
|
||||
IOWork() override;
|
||||
|
||||
private:
|
||||
CreateFileTaskParent(FileSystemBase* aFileSystem,
|
||||
const FileSystemCreateFileParams& aParam,
|
||||
FileSystemRequestParent* aParent);
|
||||
|
||||
static uint32_t sOutputBufferSize;
|
||||
|
||||
nsCOMPtr<nsIFile> mTargetPath;
|
||||
|
||||
RefPtr<BlobImpl> mBlobImpl;
|
||||
|
||||
// This is going to be the content of the file, received by createFile()
|
||||
// params.
|
||||
InfallibleTArray<uint8_t> mArrayData;
|
||||
|
||||
bool mReplace;
|
||||
};
|
||||
|
||||
|
@ -23,15 +23,21 @@ namespace dom {
|
||||
|
||||
DeviceStorageFileSystem::DeviceStorageFileSystem(const nsAString& aStorageType,
|
||||
const nsAString& aStorageName)
|
||||
: mWindowId(0)
|
||||
: mStorageType(aStorageType)
|
||||
, mStorageName(aStorageName)
|
||||
, mWindowId(0)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
mPermissionCheckType = ePermissionCheckByTestingPref;
|
||||
|
||||
mStorageType = aStorageType;
|
||||
mStorageName = aStorageName;
|
||||
|
||||
mRequiresPermissionChecks =
|
||||
!mozilla::Preferences::GetBool("device.storage.prompt.testing", false);
|
||||
if (NS_IsMainThread()) {
|
||||
if (mozilla::Preferences::GetBool("device.storage.prompt.testing", false)) {
|
||||
mPermissionCheckType = ePermissionCheckNotRequired;
|
||||
} else {
|
||||
mPermissionCheckType = ePermissionCheckRequired;
|
||||
}
|
||||
} else {
|
||||
AssertIsOnBackgroundThread();
|
||||
}
|
||||
|
||||
// Get the permission name required to access the file system.
|
||||
nsresult rv =
|
||||
@ -53,18 +59,23 @@ DeviceStorageFileSystem::DeviceStorageFileSystem(const nsAString& aStorageType,
|
||||
// DeviceStorageTypeChecker is a singleton object and must be initialized on
|
||||
// the main thread. We initialize it here so that we can use it on the worker
|
||||
// thread.
|
||||
DebugOnly<DeviceStorageTypeChecker*> typeChecker
|
||||
= DeviceStorageTypeChecker::CreateOrGet();
|
||||
MOZ_ASSERT(typeChecker);
|
||||
if (NS_IsMainThread()) {
|
||||
DebugOnly<DeviceStorageTypeChecker*> typeChecker =
|
||||
DeviceStorageTypeChecker::CreateOrGet();
|
||||
MOZ_ASSERT(typeChecker);
|
||||
}
|
||||
}
|
||||
|
||||
DeviceStorageFileSystem::~DeviceStorageFileSystem()
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
}
|
||||
|
||||
already_AddRefed<FileSystemBase>
|
||||
DeviceStorageFileSystem::Clone()
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
RefPtr<DeviceStorageFileSystem> fs =
|
||||
new DeviceStorageFileSystem(mStorageType, mStorageName);
|
||||
|
||||
@ -77,7 +88,9 @@ void
|
||||
DeviceStorageFileSystem::Init(nsDOMDeviceStorage* aDeviceStorage)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
AssertIsOnOwningThread();
|
||||
MOZ_ASSERT(aDeviceStorage);
|
||||
|
||||
nsCOMPtr<nsPIDOMWindowInner> window = aDeviceStorage->GetOwner();
|
||||
MOZ_ASSERT(window->IsInnerWindow());
|
||||
mWindowId = window->WindowID();
|
||||
@ -86,7 +99,7 @@ DeviceStorageFileSystem::Init(nsDOMDeviceStorage* aDeviceStorage)
|
||||
void
|
||||
DeviceStorageFileSystem::Shutdown()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
AssertIsOnOwningThread();
|
||||
mShutdown = true;
|
||||
}
|
||||
|
||||
@ -94,6 +107,8 @@ nsISupports*
|
||||
DeviceStorageFileSystem::GetParentObject() const
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
nsGlobalWindow* window = nsGlobalWindow::GetInnerWindowWithId(mWindowId);
|
||||
MOZ_ASSERT_IF(!mShutdown, window);
|
||||
return window ? window->AsInner() : nullptr;
|
||||
@ -102,14 +117,15 @@ DeviceStorageFileSystem::GetParentObject() const
|
||||
void
|
||||
DeviceStorageFileSystem::GetRootName(nsAString& aRetval) const
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
aRetval = mStorageName;
|
||||
}
|
||||
|
||||
bool
|
||||
DeviceStorageFileSystem::IsSafeFile(nsIFile* aFile) const
|
||||
{
|
||||
MOZ_ASSERT(XRE_IsParentProcess(),
|
||||
"Should be on parent process!");
|
||||
MOZ_ASSERT(XRE_IsParentProcess(), "Should be on parent process!");
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
MOZ_ASSERT(aFile);
|
||||
|
||||
nsCOMPtr<nsIFile> rootPath;
|
||||
@ -134,7 +150,7 @@ DeviceStorageFileSystem::IsSafeFile(nsIFile* aFile) const
|
||||
bool
|
||||
DeviceStorageFileSystem::IsSafeDirectory(Directory* aDir) const
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
AssertIsOnOwningThread();
|
||||
MOZ_ASSERT(aDir);
|
||||
|
||||
ErrorResult rv;
|
||||
@ -157,6 +173,8 @@ DeviceStorageFileSystem::IsSafeDirectory(Directory* aDir) const
|
||||
void
|
||||
DeviceStorageFileSystem::SerializeDOMPath(nsAString& aString) const
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
// Generate the string representation of the file system.
|
||||
aString.AssignLiteral("devicestorage-");
|
||||
aString.Append(mStorageType);
|
||||
@ -164,5 +182,16 @@ DeviceStorageFileSystem::SerializeDOMPath(nsAString& aString) const
|
||||
aString.Append(mStorageName);
|
||||
}
|
||||
|
||||
nsresult
|
||||
DeviceStorageFileSystem::MainThreadWork()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
DebugOnly<DeviceStorageTypeChecker*> typeChecker =
|
||||
DeviceStorageTypeChecker::CreateOrGet();
|
||||
MOZ_ASSERT(typeChecker);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
@ -48,6 +48,12 @@ public:
|
||||
virtual void
|
||||
SerializeDOMPath(nsAString& aSerializedString) const override;
|
||||
|
||||
virtual bool
|
||||
NeedToGoToMainThread() const override { return true; }
|
||||
|
||||
virtual nsresult
|
||||
MainThreadWork() override;
|
||||
|
||||
private:
|
||||
virtual
|
||||
~DeviceStorageFileSystem();
|
||||
|
@ -17,6 +17,9 @@ namespace dom {
|
||||
already_AddRefed<FileSystemBase>
|
||||
FileSystemBase::DeserializeDOMPath(const nsAString& aString)
|
||||
{
|
||||
MOZ_ASSERT(XRE_IsParentProcess(), "Only call from parent process!");
|
||||
AssertIsOnBackgroundThread();
|
||||
|
||||
if (StringBeginsWith(aString, NS_LITERAL_STRING("devicestorage-"))) {
|
||||
// The string representation of devicestorage file system is of the format:
|
||||
// devicestorage-StorageType-StorageName
|
||||
@ -39,34 +42,41 @@ FileSystemBase::DeserializeDOMPath(const nsAString& aString)
|
||||
return f.forget();
|
||||
}
|
||||
|
||||
return RefPtr<OSFileSystem>(new OSFileSystem(aString)).forget();
|
||||
return RefPtr<OSFileSystemParent>(new OSFileSystemParent(aString)).forget();
|
||||
}
|
||||
|
||||
FileSystemBase::FileSystemBase()
|
||||
: mShutdown(false)
|
||||
, mRequiresPermissionChecks(true)
|
||||
, mPermissionCheckType(eNotSet)
|
||||
#ifdef DEBUG
|
||||
, mOwningThread(PR_GetCurrentThread())
|
||||
#endif
|
||||
{
|
||||
}
|
||||
|
||||
FileSystemBase::~FileSystemBase()
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
}
|
||||
|
||||
void
|
||||
FileSystemBase::Shutdown()
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
mShutdown = true;
|
||||
}
|
||||
|
||||
nsISupports*
|
||||
FileSystemBase::GetParentObject() const
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool
|
||||
FileSystemBase::GetRealPath(BlobImpl* aFile, nsIFile** aPath) const
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
MOZ_ASSERT(aFile, "aFile Should not be null.");
|
||||
MOZ_ASSERT(aPath);
|
||||
|
||||
@ -89,12 +99,14 @@ FileSystemBase::GetRealPath(BlobImpl* aFile, nsIFile** aPath) const
|
||||
bool
|
||||
FileSystemBase::IsSafeFile(nsIFile* aFile) const
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
FileSystemBase::IsSafeDirectory(Directory* aDir) const
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -104,6 +116,7 @@ FileSystemBase::GetDOMPath(nsIFile* aFile,
|
||||
nsAString& aRetval,
|
||||
ErrorResult& aRv) const
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
MOZ_ASSERT(aFile);
|
||||
|
||||
if (aType == Directory::eDOMRootDirectory) {
|
||||
@ -171,5 +184,12 @@ FileSystemBase::GetDOMPath(nsIFile* aFile,
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
FileSystemBase::AssertIsOnOwningThread() const
|
||||
{
|
||||
MOZ_ASSERT(mOwningThread);
|
||||
MOZ_ASSERT(PR_GetCurrentThread() == mOwningThread);
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
@ -18,8 +18,8 @@ class BlobImpl;
|
||||
|
||||
class FileSystemBase
|
||||
{
|
||||
NS_INLINE_DECL_REFCOUNTING(FileSystemBase)
|
||||
public:
|
||||
NS_INLINE_DECL_REFCOUNTING(FileSystemBase)
|
||||
|
||||
// Create file system object from its string representation.
|
||||
static already_AddRefed<FileSystemBase>
|
||||
@ -87,16 +87,53 @@ public:
|
||||
return mPermission;
|
||||
}
|
||||
|
||||
bool
|
||||
RequiresPermissionChecks() const
|
||||
// The decision about doing or not doing the permission check cannot be done
|
||||
// everywhere because, for some FileSystemBase implementation, this depends on
|
||||
// a preference.
|
||||
// This enum describes all the possible decisions. The implementation will do
|
||||
// the check on the main-thread in the child and in the parent process when
|
||||
// needed.
|
||||
// Note: the permission check should not fail in PBackground because that
|
||||
// means that the child has been compromised. If this happens the child
|
||||
// process is killed.
|
||||
enum ePermissionCheckType {
|
||||
// When on the main-thread, we must check if we have
|
||||
// device.storage.prompt.testing set to true.
|
||||
ePermissionCheckByTestingPref,
|
||||
|
||||
// No permission check must be done.
|
||||
ePermissionCheckNotRequired,
|
||||
|
||||
// Permission check is required.
|
||||
ePermissionCheckRequired,
|
||||
|
||||
// This is the default value. We crash if this is let like this.
|
||||
eNotSet
|
||||
};
|
||||
|
||||
ePermissionCheckType
|
||||
PermissionCheckType() const
|
||||
{
|
||||
return mRequiresPermissionChecks;
|
||||
MOZ_ASSERT(mPermissionCheckType != eNotSet);
|
||||
return mPermissionCheckType;
|
||||
}
|
||||
|
||||
// IPC initialization
|
||||
// See how these 2 methods are used in FileSystemTaskBase.
|
||||
|
||||
virtual bool
|
||||
NeedToGoToMainThread() const { return false; }
|
||||
|
||||
virtual nsresult
|
||||
MainThreadWork() { return NS_ERROR_FAILURE; }
|
||||
|
||||
// CC methods
|
||||
virtual void Unlink() {}
|
||||
virtual void Traverse(nsCycleCollectionTraversalCallback &cb) {}
|
||||
|
||||
void
|
||||
AssertIsOnOwningThread() const;
|
||||
|
||||
protected:
|
||||
virtual ~FileSystemBase();
|
||||
|
||||
@ -119,7 +156,11 @@ protected:
|
||||
// The permission name required to access the file system.
|
||||
nsCString mPermission;
|
||||
|
||||
bool mRequiresPermissionChecks;
|
||||
ePermissionCheckType mPermissionCheckType;
|
||||
|
||||
#ifdef DEBUG
|
||||
PRThread* mOwningThread;
|
||||
#endif
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
|
@ -8,6 +8,8 @@
|
||||
#include "mozilla/dom/FileSystemBase.h"
|
||||
#include "mozilla/dom/FileSystemTaskBase.h"
|
||||
#include "mozilla/dom/FileSystemUtils.h"
|
||||
#include "mozilla/ipc/BackgroundChild.h"
|
||||
#include "mozilla/ipc/PBackgroundChild.h"
|
||||
#include "nsIDocument.h"
|
||||
#include "nsPIDOMWindow.h"
|
||||
#include "nsContentPermissionHelper.h"
|
||||
@ -16,14 +18,15 @@ namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
NS_IMPL_ISUPPORTS(FileSystemPermissionRequest, nsIRunnable,
|
||||
nsIContentPermissionRequest)
|
||||
nsIContentPermissionRequest,
|
||||
nsIIPCBackgroundChildCreateCallback)
|
||||
|
||||
// static
|
||||
void
|
||||
/* static */ void
|
||||
FileSystemPermissionRequest::RequestForTask(FileSystemTaskBase* aTask)
|
||||
{
|
||||
MOZ_ASSERT(aTask, "aTask should not be null!");
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
RefPtr<FileSystemPermissionRequest> request =
|
||||
new FileSystemPermissionRequest(aTask);
|
||||
NS_DispatchToCurrentThread(request);
|
||||
@ -98,7 +101,7 @@ FileSystemPermissionRequest::Cancel()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
mTask->SetError(NS_ERROR_DOM_SECURITY_ERR);
|
||||
mTask->Start();
|
||||
ScheduleTask();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -107,7 +110,7 @@ FileSystemPermissionRequest::Allow(JS::HandleValue aChoices)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(aChoices.isUndefined());
|
||||
mTask->Start();
|
||||
ScheduleTask();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -122,7 +125,13 @@ FileSystemPermissionRequest::Run()
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (!filesystem->RequiresPermissionChecks()) {
|
||||
if (filesystem->PermissionCheckType() == FileSystemBase::ePermissionCheckNotRequired) {
|
||||
Allow(JS::UndefinedHandleValue);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (filesystem->PermissionCheckType() == FileSystemBase::ePermissionCheckByTestingPref &&
|
||||
mozilla::Preferences::GetBool("device.storage.prompt.testing", false)) {
|
||||
Allow(JS::UndefinedHandleValue);
|
||||
return NS_OK;
|
||||
}
|
||||
@ -146,5 +155,32 @@ FileSystemPermissionRequest::GetRequester(nsIContentPermissionRequester** aReque
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
FileSystemPermissionRequest::ActorFailed()
|
||||
{
|
||||
MOZ_CRASH("Failed to create a PBackgroundChild actor!");
|
||||
}
|
||||
|
||||
void
|
||||
FileSystemPermissionRequest::ActorCreated(mozilla::ipc::PBackgroundChild* aActor)
|
||||
{
|
||||
mTask->Start();
|
||||
}
|
||||
|
||||
void
|
||||
FileSystemPermissionRequest::ScheduleTask()
|
||||
{
|
||||
PBackgroundChild* actor =
|
||||
mozilla::ipc::BackgroundChild::GetForCurrentThread();
|
||||
if (actor) {
|
||||
ActorCreated(actor);
|
||||
} else {
|
||||
if (NS_WARN_IF(
|
||||
!mozilla::ipc::BackgroundChild::GetOrCreateForCurrentThread(this))) {
|
||||
MOZ_CRASH();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} /* namespace dom */
|
||||
} /* namespace mozilla */
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsIRunnable.h"
|
||||
#include "nsIContentPermissionPrompt.h"
|
||||
#include "nsIIPCBackgroundChildCreateCallback.h"
|
||||
#include "nsString.h"
|
||||
|
||||
class nsPIDOMWindowInner;
|
||||
@ -22,6 +23,7 @@ class FileSystemTaskBase;
|
||||
class FileSystemPermissionRequest final
|
||||
: public nsIContentPermissionRequest
|
||||
, public nsIRunnable
|
||||
, public nsIIPCBackgroundChildCreateCallback
|
||||
{
|
||||
public:
|
||||
// Request permission for the given task.
|
||||
@ -31,12 +33,19 @@ public:
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
NS_DECL_NSICONTENTPERMISSIONREQUEST
|
||||
NS_DECL_NSIRUNNABLE
|
||||
NS_DECL_NSIIPCBACKGROUNDCHILDCREATECALLBACK
|
||||
|
||||
private:
|
||||
explicit FileSystemPermissionRequest(FileSystemTaskBase* aTask);
|
||||
|
||||
virtual
|
||||
~FileSystemPermissionRequest();
|
||||
|
||||
// Once the permission check has been done, we must run the task using IPC and
|
||||
// PBackground. This method checks if the PBackground thread is ready to
|
||||
// receive the task and in case waits for ActorCreated() to be called.
|
||||
void
|
||||
ScheduleTask();
|
||||
|
||||
nsCString mPermissionType;
|
||||
nsCString mPermissionAccess;
|
||||
RefPtr<FileSystemTaskBase> mTask;
|
||||
|
@ -18,18 +18,22 @@ namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
FileSystemRequestParent::FileSystemRequestParent()
|
||||
: mDestroyed(false)
|
||||
{
|
||||
AssertIsOnBackgroundThread();
|
||||
}
|
||||
|
||||
FileSystemRequestParent::~FileSystemRequestParent()
|
||||
{
|
||||
AssertIsOnBackgroundThread();
|
||||
}
|
||||
|
||||
#define FILESYSTEM_REQUEST_PARENT_DISPATCH_ENTRY(name) \
|
||||
case FileSystemParams::TFileSystem##name##Params: { \
|
||||
const FileSystem##name##Params& p = aParams; \
|
||||
mFileSystem = FileSystemBase::DeserializeDOMPath(p.filesystem()); \
|
||||
task = name##Task::Create(mFileSystem, p, this, rv); \
|
||||
MOZ_ASSERT(mFileSystem); \
|
||||
mTask = name##TaskParent::Create(mFileSystem, p, this, rv); \
|
||||
if (NS_WARN_IF(rv.Failed())) { \
|
||||
return false; \
|
||||
} \
|
||||
@ -37,11 +41,10 @@ FileSystemRequestParent::~FileSystemRequestParent()
|
||||
}
|
||||
|
||||
bool
|
||||
FileSystemRequestParent::Dispatch(ContentParent* aParent,
|
||||
const FileSystemParams& aParams)
|
||||
FileSystemRequestParent::Initialize(const FileSystemParams& aParams)
|
||||
{
|
||||
MOZ_ASSERT(aParent, "aParent should not be null.");
|
||||
RefPtr<FileSystemTaskBase> task;
|
||||
AssertIsOnBackgroundThread();
|
||||
|
||||
ErrorResult rv;
|
||||
|
||||
switch (aParams.type()) {
|
||||
@ -58,39 +61,47 @@ FileSystemRequestParent::Dispatch(ContentParent* aParent,
|
||||
}
|
||||
}
|
||||
|
||||
if (NS_WARN_IF(!task || !mFileSystem)) {
|
||||
if (NS_WARN_IF(!mTask || !mFileSystem)) {
|
||||
// Should never reach here.
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mFileSystem->RequiresPermissionChecks()) {
|
||||
// Check the content process permission.
|
||||
if (mFileSystem->PermissionCheckType() != FileSystemBase::ePermissionCheckNotRequired) {
|
||||
nsAutoCString access;
|
||||
mTask->GetPermissionAccessType(access);
|
||||
|
||||
nsCString access;
|
||||
task->GetPermissionAccessType(access);
|
||||
|
||||
nsAutoCString permissionName;
|
||||
permissionName = mFileSystem->GetPermission();
|
||||
permissionName.Append('-');
|
||||
permissionName.Append(access);
|
||||
|
||||
if (!AssertAppProcessPermission(aParent, permissionName.get())) {
|
||||
return false;
|
||||
}
|
||||
mPermissionName = mFileSystem->GetPermission();
|
||||
mPermissionName.Append('-');
|
||||
mPermissionName.Append(access);
|
||||
}
|
||||
|
||||
task->Start();
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
FileSystemRequestParent::ActorDestroy(ActorDestroyReason why)
|
||||
FileSystemRequestParent::Start()
|
||||
{
|
||||
MOZ_ASSERT(!mDestroyed);
|
||||
MOZ_ASSERT(mFileSystem);
|
||||
MOZ_ASSERT(mTask);
|
||||
|
||||
mTask->Start();
|
||||
}
|
||||
|
||||
void
|
||||
FileSystemRequestParent::ActorDestroy(ActorDestroyReason aWhy)
|
||||
{
|
||||
AssertIsOnBackgroundThread();
|
||||
MOZ_ASSERT(!mDestroyed);
|
||||
|
||||
if (!mFileSystem) {
|
||||
return;
|
||||
}
|
||||
|
||||
mFileSystem->Shutdown();
|
||||
mFileSystem = nullptr;
|
||||
mTask = nullptr;
|
||||
mDestroyed = true;
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
|
@ -8,39 +8,57 @@
|
||||
#define mozilla_dom_FileSystemRequestParent_h
|
||||
|
||||
#include "mozilla/dom/PFileSystemRequestParent.h"
|
||||
#include "mozilla/dom/ContentChild.h"
|
||||
#include "mozilla/dom/ContentParent.h"
|
||||
#include "mozilla/dom/FileSystemBase.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class FileSystemBase;
|
||||
class FileSystemParams;
|
||||
class FileSystemTaskParentBase;
|
||||
|
||||
class FileSystemRequestParent final
|
||||
: public PFileSystemRequestParent
|
||||
class FileSystemRequestParent final : public PFileSystemRequestParent
|
||||
{
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(FileSystemRequestParent)
|
||||
|
||||
public:
|
||||
FileSystemRequestParent();
|
||||
|
||||
bool
|
||||
IsRunning()
|
||||
const nsCString&
|
||||
PermissionName() const
|
||||
{
|
||||
return state() == PFileSystemRequest::__Start;
|
||||
return mPermissionName;
|
||||
}
|
||||
|
||||
FileSystemBase::ePermissionCheckType
|
||||
PermissionCheckType() const
|
||||
{
|
||||
return mFileSystem ? mFileSystem->PermissionCheckType()
|
||||
: FileSystemBase::eNotSet;
|
||||
}
|
||||
|
||||
bool
|
||||
Dispatch(ContentParent* aParent, const FileSystemParams& aParams);
|
||||
Initialize(const FileSystemParams& aParams);
|
||||
|
||||
void
|
||||
Start();
|
||||
|
||||
bool Destroyed() const
|
||||
{
|
||||
return mDestroyed;
|
||||
}
|
||||
|
||||
virtual void
|
||||
ActorDestroy(ActorDestroyReason why) override;
|
||||
|
||||
private:
|
||||
// Private destructor, to discourage deletion outside of Release():
|
||||
virtual
|
||||
~FileSystemRequestParent();
|
||||
|
||||
RefPtr<FileSystemBase> mFileSystem;
|
||||
RefPtr<FileSystemTaskParentBase> mTask;
|
||||
|
||||
nsCString mPermissionName;
|
||||
|
||||
bool mDestroyed;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
|
@ -7,14 +7,13 @@
|
||||
#include "mozilla/dom/FileSystemTaskBase.h"
|
||||
|
||||
#include "nsNetCID.h"
|
||||
#include "mozilla/dom/ContentChild.h"
|
||||
#include "mozilla/dom/File.h"
|
||||
#include "mozilla/dom/FileSystemBase.h"
|
||||
#include "mozilla/dom/FileSystemRequestParent.h"
|
||||
#include "mozilla/dom/FileSystemUtils.h"
|
||||
#include "mozilla/dom/Promise.h"
|
||||
#include "mozilla/dom/PContent.h"
|
||||
#include "mozilla/dom/ipc/BlobParent.h"
|
||||
#include "mozilla/ipc/BackgroundParent.h"
|
||||
#include "mozilla/unused.h"
|
||||
#include "nsProxyRelease.h"
|
||||
|
||||
@ -23,27 +22,65 @@ namespace dom {
|
||||
|
||||
namespace {
|
||||
|
||||
class FileSystemReleaseRunnable final : public nsRunnable
|
||||
nsresult
|
||||
FileSystemErrorFromNsError(const nsresult& aErrorValue)
|
||||
{
|
||||
public:
|
||||
explicit FileSystemReleaseRunnable(RefPtr<FileSystemBase>& aDoomed)
|
||||
: mDoomed(nullptr)
|
||||
{
|
||||
aDoomed.swap(mDoomed);
|
||||
uint16_t module = NS_ERROR_GET_MODULE(aErrorValue);
|
||||
if (module == NS_ERROR_MODULE_DOM_FILESYSTEM ||
|
||||
module == NS_ERROR_MODULE_DOM_FILE ||
|
||||
module == NS_ERROR_MODULE_DOM) {
|
||||
return aErrorValue;
|
||||
}
|
||||
|
||||
NS_IMETHOD Run()
|
||||
{
|
||||
mDoomed->Release();
|
||||
return NS_OK;
|
||||
}
|
||||
switch (aErrorValue) {
|
||||
case NS_OK:
|
||||
return NS_OK;
|
||||
|
||||
private:
|
||||
FileSystemBase* MOZ_OWNING_REF mDoomed;
|
||||
};
|
||||
case NS_ERROR_FILE_INVALID_PATH:
|
||||
case NS_ERROR_FILE_UNRECOGNIZED_PATH:
|
||||
return NS_ERROR_DOM_FILESYSTEM_INVALID_PATH_ERR;
|
||||
|
||||
case NS_ERROR_FILE_DESTINATION_NOT_DIR:
|
||||
return NS_ERROR_DOM_FILESYSTEM_INVALID_MODIFICATION_ERR;
|
||||
|
||||
case NS_ERROR_FILE_ACCESS_DENIED:
|
||||
case NS_ERROR_FILE_DIR_NOT_EMPTY:
|
||||
return NS_ERROR_DOM_FILESYSTEM_NO_MODIFICATION_ALLOWED_ERR;
|
||||
|
||||
case NS_ERROR_FILE_TARGET_DOES_NOT_EXIST:
|
||||
case NS_ERROR_NOT_AVAILABLE:
|
||||
return NS_ERROR_DOM_FILE_NOT_FOUND_ERR;
|
||||
|
||||
case NS_ERROR_FILE_ALREADY_EXISTS:
|
||||
return NS_ERROR_DOM_FILESYSTEM_PATH_EXISTS_ERR;
|
||||
|
||||
case NS_ERROR_FILE_NOT_DIRECTORY:
|
||||
return NS_ERROR_DOM_FILESYSTEM_TYPE_MISMATCH_ERR;
|
||||
|
||||
case NS_ERROR_UNEXPECTED:
|
||||
default:
|
||||
return NS_ERROR_DOM_FILESYSTEM_UNKNOWN_ERR;
|
||||
}
|
||||
}
|
||||
|
||||
nsresult
|
||||
DispatchToIOThread(nsIRunnable* aRunnable)
|
||||
{
|
||||
MOZ_ASSERT(aRunnable);
|
||||
|
||||
nsCOMPtr<nsIEventTarget> target
|
||||
= do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID);
|
||||
MOZ_ASSERT(target);
|
||||
|
||||
return target->Dispatch(aRunnable, NS_DISPATCH_NORMAL);
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
/**
|
||||
* FileSystemTaskBase class
|
||||
*/
|
||||
|
||||
FileSystemTaskBase::FileSystemTaskBase(FileSystemBase* aFileSystem)
|
||||
: mErrorValue(NS_OK)
|
||||
, mFileSystem(aFileSystem)
|
||||
@ -52,56 +89,30 @@ FileSystemTaskBase::FileSystemTaskBase(FileSystemBase* aFileSystem)
|
||||
MOZ_ASSERT(aFileSystem, "aFileSystem should not be null.");
|
||||
}
|
||||
|
||||
FileSystemTaskBase::FileSystemTaskBase(FileSystemBase* aFileSystem,
|
||||
const FileSystemParams& aParam,
|
||||
FileSystemRequestParent* aParent)
|
||||
: mErrorValue(NS_OK)
|
||||
, mFileSystem(aFileSystem)
|
||||
, mRequestParent(aParent)
|
||||
{
|
||||
MOZ_ASSERT(XRE_IsParentProcess(),
|
||||
"Only call from parent process!");
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
MOZ_ASSERT(aFileSystem, "aFileSystem should not be null.");
|
||||
}
|
||||
|
||||
FileSystemTaskBase::~FileSystemTaskBase()
|
||||
{
|
||||
if (!NS_IsMainThread()) {
|
||||
RefPtr<FileSystemReleaseRunnable> runnable =
|
||||
new FileSystemReleaseRunnable(mFileSystem);
|
||||
MOZ_ASSERT(!mFileSystem);
|
||||
NS_DispatchToMainThread(runnable);
|
||||
}
|
||||
mFileSystem->AssertIsOnOwningThread();
|
||||
}
|
||||
|
||||
FileSystemBase*
|
||||
FileSystemTaskBase::GetFileSystem() const
|
||||
{
|
||||
mFileSystem->AssertIsOnOwningThread();
|
||||
return mFileSystem.get();
|
||||
}
|
||||
|
||||
void
|
||||
FileSystemTaskBase::Start()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
mFileSystem->AssertIsOnOwningThread();
|
||||
|
||||
if (HasError()) {
|
||||
NS_DispatchToMainThread(this);
|
||||
nsCOMPtr<nsIRunnable> runnable =
|
||||
NS_NewRunnableMethod(this, &FileSystemTaskBase::HandlerCallback);
|
||||
NS_DispatchToMainThread(runnable);
|
||||
return;
|
||||
}
|
||||
|
||||
if (XRE_IsParentProcess()) {
|
||||
// Run in parent process.
|
||||
// Start worker thread.
|
||||
nsCOMPtr<nsIEventTarget> target
|
||||
= do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID);
|
||||
NS_ASSERTION(target, "Must have stream transport service.");
|
||||
target->Dispatch(this, NS_DISPATCH_NORMAL);
|
||||
return;
|
||||
}
|
||||
|
||||
// Run in child process.
|
||||
if (mFileSystem->IsShutdown()) {
|
||||
return;
|
||||
}
|
||||
@ -117,72 +128,24 @@ FileSystemTaskBase::Start()
|
||||
|
||||
// Retain a reference so the task object isn't deleted without IPDL's
|
||||
// knowledge. The reference will be released by
|
||||
// mozilla::dom::ContentChild::DeallocPFileSystemRequestChild.
|
||||
// mozilla::ipc::BackgroundChildImpl::DeallocPFileSystemRequestChild.
|
||||
NS_ADDREF_THIS();
|
||||
|
||||
ContentChild::GetSingleton()->SendPFileSystemRequestConstructor(this,
|
||||
params);
|
||||
}
|
||||
// If we are here, PBackground must be up and running, because Start() is
|
||||
// called only by FileSystemPermissionRequest, and that class takes care of
|
||||
// PBackground initialization.
|
||||
PBackgroundChild* actor =
|
||||
mozilla::ipc::BackgroundChild::GetForCurrentThread();
|
||||
MOZ_ASSERT(actor);
|
||||
|
||||
NS_IMETHODIMP
|
||||
FileSystemTaskBase::Run()
|
||||
{
|
||||
if (!NS_IsMainThread()) {
|
||||
// Run worker thread tasks
|
||||
nsresult rv = Work();
|
||||
if (NS_FAILED(rv)) {
|
||||
SetError(rv);
|
||||
}
|
||||
// Dispatch itself to main thread
|
||||
NS_DispatchToMainThread(this);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Run main thread tasks
|
||||
HandleResult();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
FileSystemTaskBase::HandleResult()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
if (mFileSystem->IsShutdown()) {
|
||||
return;
|
||||
}
|
||||
if (mRequestParent && mRequestParent->IsRunning()) {
|
||||
Unused << mRequestParent->Send__delete__(mRequestParent,
|
||||
GetRequestResult());
|
||||
} else {
|
||||
HandlerCallback();
|
||||
}
|
||||
}
|
||||
|
||||
FileSystemResponseValue
|
||||
FileSystemTaskBase::GetRequestResult() const
|
||||
{
|
||||
MOZ_ASSERT(XRE_IsParentProcess(),
|
||||
"Only call from parent process!");
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
if (!HasError()) {
|
||||
ErrorResult rv;
|
||||
FileSystemResponseValue value = GetSuccessRequestResult(rv);
|
||||
if (NS_WARN_IF(rv.Failed())) {
|
||||
return FileSystemErrorResponse(rv.StealNSResult());
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
return FileSystemErrorResponse(mErrorValue);
|
||||
actor->SendPFileSystemRequestConstructor(this, params);
|
||||
}
|
||||
|
||||
void
|
||||
FileSystemTaskBase::SetRequestResult(const FileSystemResponseValue& aValue)
|
||||
{
|
||||
MOZ_ASSERT(!XRE_IsParentProcess(),
|
||||
"Only call from child process!");
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
mFileSystem->AssertIsOnOwningThread();
|
||||
|
||||
if (aValue.type() == FileSystemResponseValue::TFileSystemErrorResponse) {
|
||||
FileSystemErrorResponse r = aValue;
|
||||
mErrorValue = r.error();
|
||||
@ -196,6 +159,8 @@ FileSystemTaskBase::SetRequestResult(const FileSystemResponseValue& aValue)
|
||||
bool
|
||||
FileSystemTaskBase::Recv__delete__(const FileSystemResponseValue& aValue)
|
||||
{
|
||||
mFileSystem->AssertIsOnOwningThread();
|
||||
|
||||
SetRequestResult(aValue);
|
||||
HandlerCallback();
|
||||
return true;
|
||||
@ -204,51 +169,160 @@ FileSystemTaskBase::Recv__delete__(const FileSystemResponseValue& aValue)
|
||||
void
|
||||
FileSystemTaskBase::SetError(const nsresult& aErrorValue)
|
||||
{
|
||||
uint16_t module = NS_ERROR_GET_MODULE(aErrorValue);
|
||||
if (module == NS_ERROR_MODULE_DOM_FILESYSTEM ||
|
||||
module == NS_ERROR_MODULE_DOM_FILE ||
|
||||
module == NS_ERROR_MODULE_DOM) {
|
||||
mErrorValue = aErrorValue;
|
||||
mErrorValue = FileSystemErrorFromNsError(aErrorValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* FileSystemTaskParentBase class
|
||||
*/
|
||||
|
||||
FileSystemTaskParentBase::FileSystemTaskParentBase(FileSystemBase* aFileSystem,
|
||||
const FileSystemParams& aParam,
|
||||
FileSystemRequestParent* aParent)
|
||||
: mErrorValue(NS_OK)
|
||||
, mFileSystem(aFileSystem)
|
||||
, mRequestParent(aParent)
|
||||
, mBackgroundEventTarget(NS_GetCurrentThread())
|
||||
{
|
||||
MOZ_ASSERT(XRE_IsParentProcess(),
|
||||
"Only call from parent process!");
|
||||
MOZ_ASSERT(aFileSystem, "aFileSystem should not be null.");
|
||||
MOZ_ASSERT(aParent);
|
||||
MOZ_ASSERT(mBackgroundEventTarget);
|
||||
AssertIsOnBackgroundThread();
|
||||
}
|
||||
|
||||
FileSystemTaskParentBase::~FileSystemTaskParentBase()
|
||||
{
|
||||
// This task can be released on different threads because we dispatch it (as
|
||||
// runnable) to main-thread, I/O and then back to the PBackground thread.
|
||||
NS_ProxyRelease(mBackgroundEventTarget, mFileSystem.forget());
|
||||
NS_ProxyRelease(mBackgroundEventTarget, mRequestParent.forget());
|
||||
}
|
||||
|
||||
void
|
||||
FileSystemTaskParentBase::Start()
|
||||
{
|
||||
AssertIsOnBackgroundThread();
|
||||
mFileSystem->AssertIsOnOwningThread();
|
||||
|
||||
if (NeedToGoToMainThread()) {
|
||||
nsresult rv = NS_DispatchToMainThread(this, NS_DISPATCH_NORMAL);
|
||||
NS_WARN_IF(NS_FAILED(rv));
|
||||
return;
|
||||
}
|
||||
|
||||
switch (aErrorValue) {
|
||||
case NS_OK:
|
||||
mErrorValue = NS_OK;
|
||||
return;
|
||||
nsresult rv = DispatchToIOThread(this);
|
||||
NS_WARN_IF(NS_FAILED(rv));
|
||||
}
|
||||
|
||||
case NS_ERROR_FILE_INVALID_PATH:
|
||||
case NS_ERROR_FILE_UNRECOGNIZED_PATH:
|
||||
mErrorValue = NS_ERROR_DOM_FILESYSTEM_INVALID_PATH_ERR;
|
||||
return;
|
||||
void
|
||||
FileSystemTaskParentBase::HandleResult()
|
||||
{
|
||||
AssertIsOnBackgroundThread();
|
||||
mFileSystem->AssertIsOnOwningThread();
|
||||
|
||||
case NS_ERROR_FILE_DESTINATION_NOT_DIR:
|
||||
mErrorValue = NS_ERROR_DOM_FILESYSTEM_INVALID_MODIFICATION_ERR;
|
||||
return;
|
||||
|
||||
case NS_ERROR_FILE_ACCESS_DENIED:
|
||||
case NS_ERROR_FILE_DIR_NOT_EMPTY:
|
||||
mErrorValue = NS_ERROR_DOM_FILESYSTEM_NO_MODIFICATION_ALLOWED_ERR;
|
||||
return;
|
||||
|
||||
case NS_ERROR_FILE_TARGET_DOES_NOT_EXIST:
|
||||
case NS_ERROR_NOT_AVAILABLE:
|
||||
mErrorValue = NS_ERROR_DOM_FILE_NOT_FOUND_ERR;
|
||||
return;
|
||||
|
||||
case NS_ERROR_FILE_ALREADY_EXISTS:
|
||||
mErrorValue = NS_ERROR_DOM_FILESYSTEM_PATH_EXISTS_ERR;
|
||||
return;
|
||||
|
||||
case NS_ERROR_FILE_NOT_DIRECTORY:
|
||||
mErrorValue = NS_ERROR_DOM_FILESYSTEM_TYPE_MISMATCH_ERR;
|
||||
return;
|
||||
|
||||
case NS_ERROR_UNEXPECTED:
|
||||
default:
|
||||
mErrorValue = NS_ERROR_DOM_FILESYSTEM_UNKNOWN_ERR;
|
||||
return;
|
||||
if (mFileSystem->IsShutdown()) {
|
||||
return;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(mRequestParent);
|
||||
Unused << mRequestParent->Send__delete__(mRequestParent, GetRequestResult());
|
||||
}
|
||||
|
||||
FileSystemResponseValue
|
||||
FileSystemTaskParentBase::GetRequestResult() const
|
||||
{
|
||||
AssertIsOnBackgroundThread();
|
||||
mFileSystem->AssertIsOnOwningThread();
|
||||
|
||||
if (HasError()) {
|
||||
return FileSystemErrorResponse(mErrorValue);
|
||||
}
|
||||
|
||||
ErrorResult rv;
|
||||
FileSystemResponseValue value = GetSuccessRequestResult(rv);
|
||||
if (NS_WARN_IF(rv.Failed())) {
|
||||
return FileSystemErrorResponse(rv.StealNSResult());
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
void
|
||||
FileSystemTaskParentBase::SetError(const nsresult& aErrorValue)
|
||||
{
|
||||
mErrorValue = FileSystemErrorFromNsError(aErrorValue);
|
||||
}
|
||||
|
||||
bool
|
||||
FileSystemTaskParentBase::NeedToGoToMainThread() const
|
||||
{
|
||||
return mFileSystem->NeedToGoToMainThread();
|
||||
}
|
||||
|
||||
nsresult
|
||||
FileSystemTaskParentBase::MainThreadWork()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
return mFileSystem->MainThreadWork();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
FileSystemTaskParentBase::Run()
|
||||
{
|
||||
// This method can run in 3 different threads. Here why:
|
||||
// 1. if we are on the main-thread it's because the task must do something
|
||||
// here. If no errors are returned we go the step 2.
|
||||
// 2. We can be here directly if the task doesn't have nothing to do on the
|
||||
// main-thread. We are are on the I/O thread and we call IOWork().
|
||||
// 3. Both step 1 (in case of error) and step 2 end up here where return the
|
||||
// value back to the PBackground thread.
|
||||
if (NS_IsMainThread()) {
|
||||
MOZ_ASSERT(NeedToGoToMainThread());
|
||||
|
||||
nsresult rv = MainThreadWork();
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
SetError(rv);
|
||||
|
||||
// Something when wrong. Let's go to the Background thread directly
|
||||
// skipping the I/O thread step.
|
||||
rv = mBackgroundEventTarget->Dispatch(this, NS_DISPATCH_NORMAL);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
// Next step must happen on the I/O thread.
|
||||
rv = DispatchToIOThread(this);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Run I/O thread tasks
|
||||
if (!IsOnBackgroundThread()) {
|
||||
nsresult rv = IOWork();
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
SetError(rv);
|
||||
}
|
||||
|
||||
// Let's go back to PBackground thread to finish the work.
|
||||
rv = mBackgroundEventTarget->Dispatch(this, NS_DISPATCH_NORMAL);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// If we are here, it's because the I/O work has been done and we have to
|
||||
// handle the result back via IPC.
|
||||
AssertIsOnBackgroundThread();
|
||||
HandleResult();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
|
@ -10,111 +10,115 @@
|
||||
#include "mozilla/ErrorResult.h"
|
||||
#include "mozilla/dom/FileSystemRequestParent.h"
|
||||
#include "mozilla/dom/PFileSystemRequestChild.h"
|
||||
#include "nsThreadUtils.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class BlobImpl;
|
||||
class BlobParent;
|
||||
class FileSystemBase;
|
||||
class FileSystemParams;
|
||||
class PBlobParent;
|
||||
|
||||
/*
|
||||
* The base class to implement a Task class.
|
||||
* The task is used to handle the OOP (out of process) operations.
|
||||
* The file system operations can only be performed in the parent process. When
|
||||
* performing such a parent-process-only operation, a task will delivered the
|
||||
* operation to the parent process if needed.
|
||||
* The file system operations can only be performed in the parent process. In
|
||||
* order to avoid duplicated code, we used PBackground for child-parent and
|
||||
* parent-parent communications.
|
||||
*
|
||||
* The following diagram illustrates the how a API call from the content page
|
||||
* starts a task and gets call back results.
|
||||
*
|
||||
* The left block is the call sequence inside the child process, while the
|
||||
* right block is the call sequence inside the parent process.
|
||||
* The left block is the call sequence inside any process loading content, while
|
||||
* the right block is the call sequence only inside the parent process.
|
||||
*
|
||||
* There are two types of API call. One is from the content page of the child
|
||||
* process and we mark the steps as (1) to (8). The other is from the content
|
||||
* page of the parent process and we mark the steps as (1') to (4').
|
||||
* Page
|
||||
* |
|
||||
* | (1)
|
||||
* ______|_______________________ | __________________________________
|
||||
* | | | | | |
|
||||
* | V | IPC | PBackground thread on |
|
||||
* | [new FileSystemTaskBase()] | | | the parent process |
|
||||
* | | | | | |
|
||||
* | | (2) | | | |
|
||||
* | V | | | |
|
||||
* | [FileSystemPermissionRequest------------------\ |
|
||||
* | ::RequestForTask()] <------------------------/ |
|
||||
* | | | | | |
|
||||
* | | (3) | | |
|
||||
* | V | (4) | |
|
||||
* | [GetRequestParams]------------------->[new FileSystemTaskParentBase()] |
|
||||
* | | | | |
|
||||
* | | | | | (5) _____________ |
|
||||
* | | | | | | | |
|
||||
* | | | | | | I/O Thread | |
|
||||
* | | | | | | | |
|
||||
* | | | | ---------> [IOWork] | |
|
||||
* | | IPC | | | | |
|
||||
* | | | | | | (6) | |
|
||||
* | | | | -------------- | |
|
||||
* | | | | | |_____________| |
|
||||
* | | | | | |
|
||||
* | | | | V |
|
||||
* | | | | [HandleResult] |
|
||||
* | | | | | |
|
||||
* | | | | (7) |
|
||||
* | | (8) | V |
|
||||
* | [SetRequestResult]<--------------------[GetRequestResult] |
|
||||
* | | | | |
|
||||
* | | (9) | | | |
|
||||
* | V | | | |
|
||||
* |[HandlerCallback] | IPC | |
|
||||
* |_______|______________________| | |__________________________________|
|
||||
* | |
|
||||
* V
|
||||
* Page
|
||||
*
|
||||
* Page Page
|
||||
* | |
|
||||
* | (1) | (1')
|
||||
* ______|________________ | _____________________|_____________
|
||||
* | | | | | | |
|
||||
* | | Task in | | | Task in | |
|
||||
* | | Child Process | | | Parent Process | |
|
||||
* | V | IPC | V |
|
||||
* [new FileSystemTaskBase()] | | [new FileSystemTaskBase()] |
|
||||
* | | | | | | |
|
||||
* | | (2) | | | (2') |
|
||||
* | V | (3) | | |
|
||||
* | [GetRequestParams]------------->[new FileSystemTaskBase(...)] |
|
||||
* | | | | | |
|
||||
* | | | | | (4) | |
|
||||
* | | | | | V |
|
||||
* | | | | -----------> [Work] |
|
||||
* | | IPC | | |
|
||||
* | | | | (5) | (3') |
|
||||
* | | | | V |
|
||||
* | | | | --------[HandleResult] |
|
||||
* | | | | | | |
|
||||
* | | | | (6) | |
|
||||
* | | (7) | V | |
|
||||
* | [SetRequestResult]<-------------[GetRequestResult] | |
|
||||
* | | | | | (4') |
|
||||
* | | (8) | | | | |
|
||||
* | V | | | V |
|
||||
* |[HandlerCallback] | IPC | [HandlerCallback] |
|
||||
* |_______|_______________| | |_________________________|_________|
|
||||
* | | |
|
||||
* V V
|
||||
* Page Page
|
||||
*
|
||||
* 1. From child process page
|
||||
* Child:
|
||||
* 1. From the process that is handling the request
|
||||
* Child/Parent (it can be in any process):
|
||||
* (1) Call FileSystem API from content page with JS. Create a task and run.
|
||||
* The base constructor [FileSystemTaskBase()] of the task should be called.
|
||||
* (2) Forward the task to the parent process through the IPC and call
|
||||
* (2) The FileSystemTaskBase object is given to
|
||||
* [FileSystemPermissionRequest::RequestForTask()] that will perform a
|
||||
* permission check step if needed (See ePermissionCheckType enum). The real
|
||||
* operation is done on the parent process but it's hidden by
|
||||
* [nsContentPermissionUtils::AskPermission()]. If the permission check is not
|
||||
* needed or if the page has the right permission, the
|
||||
* FileSystemPermissionRequest will start the task (only once PBackground
|
||||
* actor is fully initialized).
|
||||
* (3) Forward the task to the parent process through the IPC and call
|
||||
* [GetRequestParams] to prepare the parameters of the IPC.
|
||||
* Parent:
|
||||
* (3) The parent process receives IPC and handle it in
|
||||
* FileystemRequestParent.
|
||||
* Get the IPC parameters and create a task to run the IPC task. The base
|
||||
* constructor [FileSystemTaskBase(aParam, aParent)] of the task should be
|
||||
* called to set the task as an IPC task.
|
||||
* (4) The task operation will be performed in the member function of [Work].
|
||||
* A worker thread will be created to run that function. If error occurs
|
||||
* (4) The parent process receives IPC and handle it in
|
||||
* FileystemRequestParent. Get the IPC parameters and create a task to run the
|
||||
* IPC task. The base constructor [FileSystemTaskParentBase(aParam, aParent)]
|
||||
* For security reasons, we do an additional permission check if needed. In
|
||||
* the check fails, the child process will be killed.
|
||||
* of the task should be called to set the task as an IPC task.
|
||||
* (5) The task operation will be performed in the member function of [IOWork].
|
||||
* A I/O thread will be created to run that function. If error occurs
|
||||
* during the operation, call [SetError] to record the error and then abort.
|
||||
* (5) After finishing the task operation, call [HandleResult] to send the
|
||||
* (6) After finishing the task operation, call [HandleResult] to send the
|
||||
* result back to the child process though the IPC.
|
||||
* (6) Call [GetRequestResult] request result to prepare the parameters of the
|
||||
* (7) Call [GetRequestResult] request result to prepare the parameters of the
|
||||
* IPC. Because the formats of the error result for different task are the
|
||||
* same, FileSystemTaskBase can handle the error message without interfering.
|
||||
* Each task only needs to implement its specific success result preparation
|
||||
* function -[GetSuccessRequestResult].
|
||||
* Child:
|
||||
* (7) The child process receives IPC and calls [SetRequestResult] to get the
|
||||
* Child/Parent:
|
||||
* (8) The process receives IPC and calls [SetRequestResult] to get the
|
||||
* task result. Each task needs to implement its specific success result
|
||||
* parsing function [SetSuccessRequestResult] to get the success result.
|
||||
* (8) Call [HandlerCallback] to send the task result to the content page.
|
||||
* 2. From parent process page
|
||||
* We don't need to send the task parameters and result to other process. So
|
||||
* there are less steps, but their functions are the same. The correspondence
|
||||
* between the two types of steps is:
|
||||
* (1') = (1),
|
||||
* (2') = (4),
|
||||
* (3') = (5),
|
||||
* (4') = (8).
|
||||
* (9) Call [HandlerCallback] to send the task result to the content page.
|
||||
*/
|
||||
class FileSystemTaskBase
|
||||
: public nsRunnable
|
||||
, public PFileSystemRequestChild
|
||||
class FileSystemTaskBase : public PFileSystemRequestChild
|
||||
{
|
||||
public:
|
||||
NS_INLINE_DECL_REFCOUNTING(FileSystemTaskBase)
|
||||
|
||||
/*
|
||||
* Start the task. If the task is running the child process, it will be
|
||||
* forwarded to parent process by IPC, or else, creates a worker thread to
|
||||
* do the task work.
|
||||
* Start the task. It will dispatch all the information to the parent process,
|
||||
* PBackground thread. This method must be called from the owning thread.
|
||||
*/
|
||||
void
|
||||
Start();
|
||||
@ -135,104 +139,156 @@ public:
|
||||
virtual void
|
||||
GetPermissionAccessType(nsCString& aAccess) const = 0;
|
||||
|
||||
NS_DECL_NSIRUNNABLE
|
||||
/*
|
||||
* After the task is completed, this function will be called to pass the task
|
||||
* result to the content page. This method is called in the owning thread.
|
||||
* Override this function to handle the call back to the content page.
|
||||
*/
|
||||
virtual void
|
||||
HandlerCallback() = 0;
|
||||
|
||||
bool
|
||||
HasError() const { return NS_FAILED(mErrorValue); }
|
||||
|
||||
protected:
|
||||
/*
|
||||
* To create a task to handle the page content request.
|
||||
*/
|
||||
explicit FileSystemTaskBase(FileSystemBase* aFileSystem);
|
||||
|
||||
/*
|
||||
* To create a parent process task delivered from the child process through
|
||||
* IPC.
|
||||
*/
|
||||
FileSystemTaskBase(FileSystemBase* aFileSystem,
|
||||
const FileSystemParams& aParam,
|
||||
FileSystemRequestParent* aParent);
|
||||
|
||||
virtual
|
||||
~FileSystemTaskBase();
|
||||
|
||||
/*
|
||||
* The function to perform task operation. It will be run on the worker
|
||||
* thread of the parent process.
|
||||
* Overrides this function to define the task operation for individual task.
|
||||
*/
|
||||
virtual nsresult
|
||||
Work() = 0;
|
||||
|
||||
/*
|
||||
* After the task is completed, this function will be called to pass the task
|
||||
* result to the content page.
|
||||
* Override this function to handle the call back to the content page.
|
||||
*/
|
||||
virtual void
|
||||
HandlerCallback() = 0;
|
||||
|
||||
/*
|
||||
* Wrap the task parameter to FileSystemParams for sending it through IPC.
|
||||
* It will be called when we need to forward a task from the child process to
|
||||
* the prarent process.
|
||||
* the parent process. This method runs in the owning thread.
|
||||
* @param filesystem The string representation of the file system.
|
||||
*/
|
||||
virtual FileSystemParams
|
||||
GetRequestParams(const nsString& aSerializedDOMPath,
|
||||
ErrorResult& aRv) const = 0;
|
||||
|
||||
/*
|
||||
* Unwrap the IPC message to get the task success result.
|
||||
* It will be called when the task is completed successfully and an IPC
|
||||
* message is received in the child process and we want to get the task
|
||||
* success result. This method runs in the owning thread.
|
||||
*/
|
||||
virtual void
|
||||
SetSuccessRequestResult(const FileSystemResponseValue& aValue,
|
||||
ErrorResult& aRv) = 0;
|
||||
|
||||
// Overrides PFileSystemRequestChild
|
||||
virtual bool
|
||||
Recv__delete__(const FileSystemResponseValue& value) override;
|
||||
|
||||
nsresult mErrorValue;
|
||||
RefPtr<FileSystemBase> mFileSystem;
|
||||
|
||||
private:
|
||||
|
||||
/*
|
||||
* Unwrap the IPC message to get the task result.
|
||||
* It will be called when the task is completed and an IPC message is received
|
||||
* in the content process and we want to get the task result. This runs on the
|
||||
* owning thread.
|
||||
*/
|
||||
void
|
||||
SetRequestResult(const FileSystemResponseValue& aValue);
|
||||
};
|
||||
|
||||
// This class is the 'alter ego' of FileSystemTaskBase in the PBackground world.
|
||||
class FileSystemTaskParentBase : public nsRunnable
|
||||
{
|
||||
public:
|
||||
/*
|
||||
* Start the task. This must be called from the PBackground thread only.
|
||||
*/
|
||||
void
|
||||
Start();
|
||||
|
||||
/*
|
||||
* The error codes are defined in xpcom/base/ErrorList.h and their
|
||||
* corresponding error name and message are defined in dom/base/domerr.msg.
|
||||
*/
|
||||
void
|
||||
SetError(const nsresult& aErrorCode);
|
||||
|
||||
/*
|
||||
* The function to perform task operation. It will be run on the I/O
|
||||
* thread of the parent process.
|
||||
* Overrides this function to define the task operation for individual task.
|
||||
*/
|
||||
virtual nsresult
|
||||
IOWork() = 0;
|
||||
|
||||
/*
|
||||
* Wrap the task success result to FileSystemResponseValue for sending it
|
||||
* through IPC.
|
||||
* through IPC. This method runs in the PBackground thread.
|
||||
* It will be called when the task is completed successfully and we need to
|
||||
* send the task success result back to the child process.
|
||||
*/
|
||||
virtual FileSystemResponseValue
|
||||
GetSuccessRequestResult(ErrorResult& aRv) const = 0;
|
||||
|
||||
/*
|
||||
* Unwrap the IPC message to get the task success result.
|
||||
* It will be called when the task is completed successfully and an IPC
|
||||
* message is received in the child process and we want to get the task
|
||||
* success result.
|
||||
*/
|
||||
virtual void
|
||||
SetSuccessRequestResult(const FileSystemResponseValue& aValue,
|
||||
ErrorResult& aRv) = 0;
|
||||
|
||||
bool
|
||||
HasError() const { return mErrorValue != NS_OK; }
|
||||
|
||||
// Overrides PFileSystemRequestChild
|
||||
virtual bool
|
||||
Recv__delete__(const FileSystemResponseValue& value) override;
|
||||
|
||||
nsresult mErrorValue;
|
||||
|
||||
RefPtr<FileSystemBase> mFileSystem;
|
||||
RefPtr<FileSystemRequestParent> mRequestParent;
|
||||
private:
|
||||
/*
|
||||
* After finishing the task operation, handle the task result.
|
||||
* If it is an IPC task, send back the IPC result. Or else, send the result
|
||||
* to the content page.
|
||||
* If it is an IPC task, send back the IPC result. It runs on the PBackground
|
||||
* thread.
|
||||
*/
|
||||
void
|
||||
HandleResult();
|
||||
|
||||
// If this task must do something on the main-thread before IOWork(), it must
|
||||
// overwrite this method. Otherwise it returns true if the FileSystem must be
|
||||
// initialized on the main-thread. It's called from the Background thread.
|
||||
virtual bool
|
||||
NeedToGoToMainThread() const;
|
||||
|
||||
// This method is called only if NeedToGoToMainThread() returns true.
|
||||
// Of course, it runs on the main-thread.
|
||||
virtual nsresult
|
||||
MainThreadWork();
|
||||
|
||||
/*
|
||||
* Get the type of permission access required to perform this task.
|
||||
*/
|
||||
virtual void
|
||||
GetPermissionAccessType(nsCString& aAccess) const = 0;
|
||||
|
||||
bool
|
||||
HasError() const { return NS_FAILED(mErrorValue); }
|
||||
|
||||
NS_IMETHOD
|
||||
Run() override;
|
||||
|
||||
private:
|
||||
/*
|
||||
* Wrap the task result to FileSystemResponseValue for sending it through IPC.
|
||||
* It will be called when the task is completed and we need to
|
||||
* send the task result back to the child process.
|
||||
* send the task result back to the content. This runs on the PBackground
|
||||
* thread.
|
||||
*/
|
||||
FileSystemResponseValue
|
||||
GetRequestResult() const;
|
||||
|
||||
protected:
|
||||
/*
|
||||
* Unwrap the IPC message to get the task result.
|
||||
* It will be called when the task is completed and an IPC message is received
|
||||
* in the child process and we want to get the task result.
|
||||
* To create a parent process task delivered from the child process through
|
||||
* IPC.
|
||||
*/
|
||||
void
|
||||
SetRequestResult(const FileSystemResponseValue& aValue);
|
||||
FileSystemTaskParentBase(FileSystemBase* aFileSystem,
|
||||
const FileSystemParams& aParam,
|
||||
FileSystemRequestParent* aParent);
|
||||
|
||||
virtual
|
||||
~FileSystemTaskParentBase();
|
||||
|
||||
nsresult mErrorValue;
|
||||
RefPtr<FileSystemBase> mFileSystem;
|
||||
RefPtr<FileSystemRequestParent> mRequestParent;
|
||||
nsCOMPtr<nsIEventTarget> mBackgroundEventTarget;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
|
@ -11,15 +11,22 @@
|
||||
#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"
|
||||
|
||||
#define GET_DIRECTORY_LISTING_PERMISSION "read"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
/**
|
||||
* GetDirectoryListingTask
|
||||
*/
|
||||
|
||||
/* static */ already_AddRefed<GetDirectoryListingTask>
|
||||
GetDirectoryListingTask::Create(FileSystemBase* aFileSystem,
|
||||
nsIFile* aTargetPath,
|
||||
@ -50,30 +57,6 @@ GetDirectoryListingTask::Create(FileSystemBase* aFileSystem,
|
||||
return task.forget();
|
||||
}
|
||||
|
||||
/* static */ already_AddRefed<GetDirectoryListingTask>
|
||||
GetDirectoryListingTask::Create(FileSystemBase* aFileSystem,
|
||||
const FileSystemGetDirectoryListingParams& aParam,
|
||||
FileSystemRequestParent* aParent,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
MOZ_ASSERT(XRE_IsParentProcess(), "Only call from parent process!");
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
MOZ_ASSERT(aFileSystem);
|
||||
|
||||
RefPtr<GetDirectoryListingTask> task =
|
||||
new GetDirectoryListingTask(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;
|
||||
}
|
||||
|
||||
task->mType = aParam.isRoot()
|
||||
? Directory::eDOMRootDirectory : Directory::eNotDOMRootDirectory;
|
||||
return task.forget();
|
||||
}
|
||||
|
||||
GetDirectoryListingTask::GetDirectoryListingTask(FileSystemBase* aFileSystem,
|
||||
nsIFile* aTargetPath,
|
||||
Directory::DirectoryType aType,
|
||||
@ -87,21 +70,9 @@ GetDirectoryListingTask::GetDirectoryListingTask(FileSystemBase* aFileSystem,
|
||||
MOZ_ASSERT(aFileSystem);
|
||||
}
|
||||
|
||||
GetDirectoryListingTask::GetDirectoryListingTask(FileSystemBase* aFileSystem,
|
||||
const FileSystemGetDirectoryListingParams& aParam,
|
||||
FileSystemRequestParent* aParent)
|
||||
: FileSystemTaskBase(aFileSystem, aParam, aParent)
|
||||
, mFilters(aParam.filters())
|
||||
{
|
||||
MOZ_ASSERT(XRE_IsParentProcess(), "Only call from parent process!");
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
MOZ_ASSERT(aFileSystem);
|
||||
}
|
||||
|
||||
GetDirectoryListingTask::~GetDirectoryListingTask()
|
||||
{
|
||||
MOZ_ASSERT(!mPromise || NS_IsMainThread(),
|
||||
"mPromise should be released on main thread!");
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
}
|
||||
|
||||
already_AddRefed<Promise>
|
||||
@ -128,33 +99,6 @@ GetDirectoryListingTask::GetRequestParams(const nsString& aSerializedDOMPath,
|
||||
mFilters);
|
||||
}
|
||||
|
||||
FileSystemResponseValue
|
||||
GetDirectoryListingTask::GetSuccessRequestResult(ErrorResult& aRv) const
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
|
||||
InfallibleTArray<PBlobParent*> blobs;
|
||||
|
||||
nsTArray<FileSystemDirectoryListingResponseData> inputs;
|
||||
|
||||
for (unsigned i = 0; i < mTargetData.Length(); i++) {
|
||||
if (mTargetData[i].mType == Directory::FileOrDirectoryPath::eFilePath) {
|
||||
FileSystemDirectoryListingResponseFile fileData;
|
||||
fileData.fileRealPath() = mTargetData[i].mPath;
|
||||
inputs.AppendElement(fileData);
|
||||
} else {
|
||||
MOZ_ASSERT(mTargetData[i].mType == Directory::FileOrDirectoryPath::eDirectoryPath);
|
||||
FileSystemDirectoryListingResponseDirectory directoryData;
|
||||
directoryData.directoryRealPath() = mTargetData[i].mPath;
|
||||
inputs.AppendElement(directoryData);
|
||||
}
|
||||
}
|
||||
|
||||
FileSystemDirectoryListingResponse response;
|
||||
response.data().SwapElements(inputs);
|
||||
return response;
|
||||
}
|
||||
|
||||
void
|
||||
GetDirectoryListingTask::SetSuccessRequestResult(const FileSystemResponseValue& aValue,
|
||||
ErrorResult& aRv)
|
||||
@ -186,8 +130,152 @@ GetDirectoryListingTask::SetSuccessRequestResult(const FileSystemResponseValue&
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
GetDirectoryListingTask::HandlerCallback()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
if (mFileSystem->IsShutdown()) {
|
||||
mPromise = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
if (HasError()) {
|
||||
mPromise->MaybeReject(mErrorValue);
|
||||
mPromise = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
size_t count = mTargetData.Length();
|
||||
|
||||
Sequence<OwningFileOrDirectory> 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].mPath);
|
||||
nsresult rv = NS_NewNativeLocalFile(fullPath, true, getter_AddRefs(path));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
mPromise->MaybeReject(rv);
|
||||
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(rv);
|
||||
mPromise = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(FileSystemUtils::IsDescendantPath(rootPath, path));
|
||||
#endif
|
||||
|
||||
if (mTargetData[i].mType == Directory::FileOrDirectoryPath::eDirectoryPath) {
|
||||
RefPtr<Directory> directory =
|
||||
Directory::Create(mFileSystem->GetParentObject(), path,
|
||||
Directory::eNotDOMRootDirectory, mFileSystem);
|
||||
MOZ_ASSERT(directory);
|
||||
|
||||
// Propogate mFilter onto sub-Directory object:
|
||||
directory->SetContentFilters(mFilters);
|
||||
listing[i].SetAsDirectory() = directory;
|
||||
} else {
|
||||
MOZ_ASSERT(mTargetData[i].mType == Directory::FileOrDirectoryPath::eFilePath);
|
||||
|
||||
RefPtr<File> file =
|
||||
File::CreateFromFile(mFileSystem->GetParentObject(), path);
|
||||
MOZ_ASSERT(file);
|
||||
|
||||
listing[i].SetAsFile() = file;
|
||||
}
|
||||
}
|
||||
|
||||
mPromise->MaybeResolve(listing);
|
||||
mPromise = nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
GetDirectoryListingTask::GetPermissionAccessType(nsCString& aAccess) const
|
||||
{
|
||||
aAccess.AssignLiteral(GET_DIRECTORY_LISTING_PERMISSION);
|
||||
}
|
||||
|
||||
/**
|
||||
* GetDirectoryListingTaskParent
|
||||
*/
|
||||
|
||||
/* static */ already_AddRefed<GetDirectoryListingTaskParent>
|
||||
GetDirectoryListingTaskParent::Create(FileSystemBase* aFileSystem,
|
||||
const FileSystemGetDirectoryListingParams& aParam,
|
||||
FileSystemRequestParent* aParent,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
MOZ_ASSERT(XRE_IsParentProcess(), "Only call from parent process!");
|
||||
AssertIsOnBackgroundThread();
|
||||
MOZ_ASSERT(aFileSystem);
|
||||
|
||||
RefPtr<GetDirectoryListingTaskParent> task =
|
||||
new GetDirectoryListingTaskParent(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;
|
||||
}
|
||||
|
||||
task->mType = aParam.isRoot()
|
||||
? Directory::eDOMRootDirectory : Directory::eNotDOMRootDirectory;
|
||||
return task.forget();
|
||||
}
|
||||
|
||||
GetDirectoryListingTaskParent::GetDirectoryListingTaskParent(FileSystemBase* aFileSystem,
|
||||
const FileSystemGetDirectoryListingParams& aParam,
|
||||
FileSystemRequestParent* aParent)
|
||||
: FileSystemTaskParentBase(aFileSystem, aParam, aParent)
|
||||
, mFilters(aParam.filters())
|
||||
{
|
||||
MOZ_ASSERT(XRE_IsParentProcess(), "Only call from parent process!");
|
||||
AssertIsOnBackgroundThread();
|
||||
MOZ_ASSERT(aFileSystem);
|
||||
}
|
||||
|
||||
FileSystemResponseValue
|
||||
GetDirectoryListingTaskParent::GetSuccessRequestResult(ErrorResult& aRv) const
|
||||
{
|
||||
AssertIsOnBackgroundThread();
|
||||
|
||||
InfallibleTArray<PBlobParent*> blobs;
|
||||
|
||||
nsTArray<FileSystemDirectoryListingResponseData> inputs;
|
||||
|
||||
for (unsigned i = 0; i < mTargetData.Length(); i++) {
|
||||
if (mTargetData[i].mType == Directory::FileOrDirectoryPath::eFilePath) {
|
||||
FileSystemDirectoryListingResponseFile fileData;
|
||||
fileData.fileRealPath() = mTargetData[i].mPath;
|
||||
inputs.AppendElement(fileData);
|
||||
} else {
|
||||
MOZ_ASSERT(mTargetData[i].mType == Directory::FileOrDirectoryPath::eDirectoryPath);
|
||||
FileSystemDirectoryListingResponseDirectory directoryData;
|
||||
directoryData.directoryRealPath() = mTargetData[i].mPath;
|
||||
inputs.AppendElement(directoryData);
|
||||
}
|
||||
}
|
||||
|
||||
FileSystemDirectoryListingResponse response;
|
||||
response.data().SwapElements(inputs);
|
||||
return response;
|
||||
}
|
||||
|
||||
nsresult
|
||||
GetDirectoryListingTask::Work()
|
||||
GetDirectoryListingTaskParent::IOWork()
|
||||
{
|
||||
MOZ_ASSERT(XRE_IsParentProcess(),
|
||||
"Only call from parent process!");
|
||||
@ -303,81 +391,9 @@ GetDirectoryListingTask::Work()
|
||||
}
|
||||
|
||||
void
|
||||
GetDirectoryListingTask::HandlerCallback()
|
||||
GetDirectoryListingTaskParent::GetPermissionAccessType(nsCString& aAccess) const
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
if (mFileSystem->IsShutdown()) {
|
||||
mPromise = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
if (HasError()) {
|
||||
mPromise->MaybeReject(mErrorValue);
|
||||
mPromise = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
size_t count = mTargetData.Length();
|
||||
|
||||
Sequence<OwningFileOrDirectory> 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].mPath);
|
||||
nsresult rv = NS_NewNativeLocalFile(fullPath, true, getter_AddRefs(path));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
mPromise->MaybeReject(rv);
|
||||
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(rv);
|
||||
mPromise = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(FileSystemUtils::IsDescendantPath(rootPath, path));
|
||||
#endif
|
||||
|
||||
if (mTargetData[i].mType == Directory::FileOrDirectoryPath::eDirectoryPath) {
|
||||
RefPtr<Directory> directory =
|
||||
Directory::Create(mFileSystem->GetParentObject(), path,
|
||||
Directory::eNotDOMRootDirectory, mFileSystem);
|
||||
MOZ_ASSERT(directory);
|
||||
|
||||
// Propogate mFilter onto sub-Directory object:
|
||||
directory->SetContentFilters(mFilters);
|
||||
listing[i].SetAsDirectory() = directory;
|
||||
} else {
|
||||
MOZ_ASSERT(mTargetData[i].mType == Directory::FileOrDirectoryPath::eFilePath);
|
||||
|
||||
RefPtr<File> file =
|
||||
File::CreateFromFile(mFileSystem->GetParentObject(), path);
|
||||
MOZ_ASSERT(file);
|
||||
|
||||
listing[i].SetAsFile() = file;
|
||||
}
|
||||
}
|
||||
|
||||
mPromise->MaybeResolve(listing);
|
||||
mPromise = nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
GetDirectoryListingTask::GetPermissionAccessType(nsCString& aAccess) const
|
||||
{
|
||||
aAccess.AssignLiteral("read");
|
||||
aAccess.AssignLiteral(GET_DIRECTORY_LISTING_PERMISSION);
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
|
@ -27,12 +27,6 @@ public:
|
||||
const nsAString& aFilters,
|
||||
ErrorResult& aRv);
|
||||
|
||||
static already_AddRefed<GetDirectoryListingTask>
|
||||
Create(FileSystemBase* aFileSystem,
|
||||
const FileSystemGetDirectoryListingParams& aParam,
|
||||
FileSystemRequestParent* aParent,
|
||||
ErrorResult& aRv);
|
||||
|
||||
virtual
|
||||
~GetDirectoryListingTask();
|
||||
|
||||
@ -49,24 +43,14 @@ private:
|
||||
Directory::DirectoryType aType,
|
||||
const nsAString& aFilters);
|
||||
|
||||
GetDirectoryListingTask(FileSystemBase* aFileSystem,
|
||||
const FileSystemGetDirectoryListingParams& aParam,
|
||||
FileSystemRequestParent* aParent);
|
||||
|
||||
virtual FileSystemParams
|
||||
GetRequestParams(const nsString& aSerializedDOMPath,
|
||||
ErrorResult& aRv) const override;
|
||||
|
||||
virtual FileSystemResponseValue
|
||||
GetSuccessRequestResult(ErrorResult& aRv) const override;
|
||||
|
||||
virtual void
|
||||
SetSuccessRequestResult(const FileSystemResponseValue& aValue,
|
||||
ErrorResult& aRv) override;
|
||||
|
||||
virtual nsresult
|
||||
Work() override;
|
||||
|
||||
virtual void
|
||||
HandlerCallback() override;
|
||||
|
||||
@ -80,6 +64,38 @@ private:
|
||||
FallibleTArray<Directory::FileOrDirectoryPath> mTargetData;
|
||||
};
|
||||
|
||||
class GetDirectoryListingTaskParent final : public FileSystemTaskParentBase
|
||||
{
|
||||
public:
|
||||
static already_AddRefed<GetDirectoryListingTaskParent>
|
||||
Create(FileSystemBase* aFileSystem,
|
||||
const FileSystemGetDirectoryListingParams& aParam,
|
||||
FileSystemRequestParent* aParent,
|
||||
ErrorResult& aRv);
|
||||
|
||||
virtual void
|
||||
GetPermissionAccessType(nsCString& aAccess) const override;
|
||||
|
||||
private:
|
||||
GetDirectoryListingTaskParent(FileSystemBase* aFileSystem,
|
||||
const FileSystemGetDirectoryListingParams& aParam,
|
||||
FileSystemRequestParent* aParent);
|
||||
|
||||
virtual FileSystemResponseValue
|
||||
GetSuccessRequestResult(ErrorResult& aRv) const override;
|
||||
|
||||
virtual nsresult
|
||||
IOWork() override;
|
||||
|
||||
nsCOMPtr<nsIFile> mTargetPath;
|
||||
nsString mFilters;
|
||||
Directory::DirectoryType mType;
|
||||
|
||||
// We cannot store File or Directory objects bacause this object is created
|
||||
// on a different thread and File and Directory are not thread-safe.
|
||||
FallibleTArray<Directory::FileOrDirectoryPath> mTargetData;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
|
@ -10,15 +10,22 @@
|
||||
#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"
|
||||
|
||||
#define GET_FILE_OR_DIRECTORY_PERMISSION "read"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
/**
|
||||
* GetFileOrDirectoryTask
|
||||
*/
|
||||
|
||||
/* static */ already_AddRefed<GetFileOrDirectoryTask>
|
||||
GetFileOrDirectoryTask::Create(FileSystemBase* aFileSystem,
|
||||
nsIFile* aTargetPath,
|
||||
@ -49,30 +56,6 @@ GetFileOrDirectoryTask::Create(FileSystemBase* aFileSystem,
|
||||
return task.forget();
|
||||
}
|
||||
|
||||
/* static */ already_AddRefed<GetFileOrDirectoryTask>
|
||||
GetFileOrDirectoryTask::Create(FileSystemBase* aFileSystem,
|
||||
const FileSystemGetFileOrDirectoryParams& aParam,
|
||||
FileSystemRequestParent* aParent,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
MOZ_ASSERT(XRE_IsParentProcess(), "Only call from parent process!");
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
MOZ_ASSERT(aFileSystem);
|
||||
|
||||
RefPtr<GetFileOrDirectoryTask> task =
|
||||
new GetFileOrDirectoryTask(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;
|
||||
}
|
||||
|
||||
task->mType = aParam.isRoot()
|
||||
? Directory::eDOMRootDirectory : Directory::eNotDOMRootDirectory;
|
||||
return task.forget();
|
||||
}
|
||||
|
||||
GetFileOrDirectoryTask::GetFileOrDirectoryTask(FileSystemBase* aFileSystem,
|
||||
nsIFile* aTargetPath,
|
||||
Directory::DirectoryType aType,
|
||||
@ -86,21 +69,9 @@ GetFileOrDirectoryTask::GetFileOrDirectoryTask(FileSystemBase* aFileSystem,
|
||||
MOZ_ASSERT(aFileSystem);
|
||||
}
|
||||
|
||||
GetFileOrDirectoryTask::GetFileOrDirectoryTask(FileSystemBase* aFileSystem,
|
||||
const FileSystemGetFileOrDirectoryParams& aParam,
|
||||
FileSystemRequestParent* aParent)
|
||||
: FileSystemTaskBase(aFileSystem, aParam, aParent)
|
||||
, mIsDirectory(false)
|
||||
{
|
||||
MOZ_ASSERT(XRE_IsParentProcess(), "Only call from parent process!");
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
MOZ_ASSERT(aFileSystem);
|
||||
}
|
||||
|
||||
GetFileOrDirectoryTask::~GetFileOrDirectoryTask()
|
||||
{
|
||||
MOZ_ASSERT(!mPromise || NS_IsMainThread(),
|
||||
"mPromise should be released on main thread!");
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
}
|
||||
|
||||
already_AddRefed<Promise>
|
||||
@ -126,23 +97,6 @@ GetFileOrDirectoryTask::GetRequestParams(const nsString& aSerializedDOMPath,
|
||||
mType == Directory::eDOMRootDirectory);
|
||||
}
|
||||
|
||||
FileSystemResponseValue
|
||||
GetFileOrDirectoryTask::GetSuccessRequestResult(ErrorResult& aRv) const
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
nsAutoString path;
|
||||
aRv = mTargetPath->GetPath(path);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return FileSystemDirectoryResponse();
|
||||
}
|
||||
|
||||
if (mIsDirectory) {
|
||||
return FileSystemDirectoryResponse(path);
|
||||
}
|
||||
|
||||
return FileSystemFileResponse(path);
|
||||
}
|
||||
|
||||
void
|
||||
GetFileOrDirectoryTask::SetSuccessRequestResult(const FileSystemResponseValue& aValue,
|
||||
ErrorResult& aRv)
|
||||
@ -180,8 +134,104 @@ GetFileOrDirectoryTask::SetSuccessRequestResult(const FileSystemResponseValue& a
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
GetFileOrDirectoryTask::HandlerCallback()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
if (mFileSystem->IsShutdown()) {
|
||||
mPromise = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
if (HasError()) {
|
||||
mPromise->MaybeReject(mErrorValue);
|
||||
mPromise = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
if (mIsDirectory) {
|
||||
RefPtr<Directory> dir = Directory::Create(mFileSystem->GetParentObject(),
|
||||
mTargetPath,
|
||||
mType,
|
||||
mFileSystem);
|
||||
MOZ_ASSERT(dir);
|
||||
|
||||
mPromise->MaybeResolve(dir);
|
||||
mPromise = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
RefPtr<File> file = File::CreateFromFile(mFileSystem->GetParentObject(),
|
||||
mTargetPath);
|
||||
mPromise->MaybeResolve(file);
|
||||
mPromise = nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
GetFileOrDirectoryTask::GetPermissionAccessType(nsCString& aAccess) const
|
||||
{
|
||||
aAccess.AssignLiteral(GET_FILE_OR_DIRECTORY_PERMISSION);
|
||||
}
|
||||
|
||||
/**
|
||||
* GetFileOrDirectoryTaskParent
|
||||
*/
|
||||
|
||||
/* static */ already_AddRefed<GetFileOrDirectoryTaskParent>
|
||||
GetFileOrDirectoryTaskParent::Create(FileSystemBase* aFileSystem,
|
||||
const FileSystemGetFileOrDirectoryParams& aParam,
|
||||
FileSystemRequestParent* aParent,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
MOZ_ASSERT(XRE_IsParentProcess(), "Only call from parent process!");
|
||||
AssertIsOnBackgroundThread();
|
||||
MOZ_ASSERT(aFileSystem);
|
||||
|
||||
RefPtr<GetFileOrDirectoryTaskParent> task =
|
||||
new GetFileOrDirectoryTaskParent(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;
|
||||
}
|
||||
|
||||
task->mType = aParam.isRoot()
|
||||
? Directory::eDOMRootDirectory : Directory::eNotDOMRootDirectory;
|
||||
return task.forget();
|
||||
}
|
||||
|
||||
GetFileOrDirectoryTaskParent::GetFileOrDirectoryTaskParent(FileSystemBase* aFileSystem,
|
||||
const FileSystemGetFileOrDirectoryParams& aParam,
|
||||
FileSystemRequestParent* aParent)
|
||||
: FileSystemTaskParentBase(aFileSystem, aParam, aParent)
|
||||
, mIsDirectory(false)
|
||||
{
|
||||
MOZ_ASSERT(XRE_IsParentProcess(), "Only call from parent process!");
|
||||
AssertIsOnBackgroundThread();
|
||||
MOZ_ASSERT(aFileSystem);
|
||||
}
|
||||
|
||||
FileSystemResponseValue
|
||||
GetFileOrDirectoryTaskParent::GetSuccessRequestResult(ErrorResult& aRv) const
|
||||
{
|
||||
AssertIsOnBackgroundThread();
|
||||
|
||||
nsAutoString path;
|
||||
aRv = mTargetPath->GetPath(path);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return FileSystemDirectoryResponse();
|
||||
}
|
||||
|
||||
if (mIsDirectory) {
|
||||
return FileSystemDirectoryResponse(path);
|
||||
}
|
||||
|
||||
return FileSystemFileResponse(path);
|
||||
}
|
||||
|
||||
nsresult
|
||||
GetFileOrDirectoryTask::Work()
|
||||
GetFileOrDirectoryTaskParent::IOWork()
|
||||
{
|
||||
MOZ_ASSERT(XRE_IsParentProcess(),
|
||||
"Only call from parent process!");
|
||||
@ -245,42 +295,9 @@ GetFileOrDirectoryTask::Work()
|
||||
}
|
||||
|
||||
void
|
||||
GetFileOrDirectoryTask::HandlerCallback()
|
||||
GetFileOrDirectoryTaskParent::GetPermissionAccessType(nsCString& aAccess) const
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
if (mFileSystem->IsShutdown()) {
|
||||
mPromise = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
if (HasError()) {
|
||||
mPromise->MaybeReject(mErrorValue);
|
||||
mPromise = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
if (mIsDirectory) {
|
||||
RefPtr<Directory> dir = Directory::Create(mFileSystem->GetParentObject(),
|
||||
mTargetPath,
|
||||
mType,
|
||||
mFileSystem);
|
||||
MOZ_ASSERT(dir);
|
||||
|
||||
mPromise->MaybeResolve(dir);
|
||||
mPromise = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
RefPtr<File> file = File::CreateFromFile(mFileSystem->GetParentObject(),
|
||||
mTargetPath);
|
||||
mPromise->MaybeResolve(file);
|
||||
mPromise = nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
GetFileOrDirectoryTask::GetPermissionAccessType(nsCString& aAccess) const
|
||||
{
|
||||
aAccess.AssignLiteral("read");
|
||||
aAccess.AssignLiteral(GET_FILE_OR_DIRECTORY_PERMISSION);
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
|
@ -27,12 +27,6 @@ public:
|
||||
bool aDirectoryOnly,
|
||||
ErrorResult& aRv);
|
||||
|
||||
static already_AddRefed<GetFileOrDirectoryTask>
|
||||
Create(FileSystemBase* aFileSystem,
|
||||
const FileSystemGetFileOrDirectoryParams& aParam,
|
||||
FileSystemRequestParent* aParent,
|
||||
ErrorResult& aRv);
|
||||
|
||||
virtual
|
||||
~GetFileOrDirectoryTask();
|
||||
|
||||
@ -41,21 +35,15 @@ public:
|
||||
|
||||
virtual void
|
||||
GetPermissionAccessType(nsCString& aAccess) const override;
|
||||
|
||||
protected:
|
||||
virtual FileSystemParams
|
||||
GetRequestParams(const nsString& aSerializedDOMPath,
|
||||
ErrorResult& aRv) const override;
|
||||
|
||||
virtual FileSystemResponseValue
|
||||
GetSuccessRequestResult(ErrorResult& aRv) const override;
|
||||
|
||||
virtual void
|
||||
SetSuccessRequestResult(const FileSystemResponseValue& aValue,
|
||||
ErrorResult& aRv) override;
|
||||
|
||||
virtual nsresult
|
||||
Work() override;
|
||||
|
||||
virtual void
|
||||
HandlerCallback() override;
|
||||
|
||||
@ -66,10 +54,6 @@ private:
|
||||
Directory::DirectoryType aType,
|
||||
bool aDirectoryOnly);
|
||||
|
||||
GetFileOrDirectoryTask(FileSystemBase* aFileSystem,
|
||||
const FileSystemGetFileOrDirectoryParams& aParam,
|
||||
FileSystemRequestParent* aParent);
|
||||
|
||||
RefPtr<Promise> mPromise;
|
||||
nsCOMPtr<nsIFile> mTargetPath;
|
||||
|
||||
@ -78,6 +62,37 @@ private:
|
||||
Directory::DirectoryType mType;
|
||||
};
|
||||
|
||||
class GetFileOrDirectoryTaskParent final : public FileSystemTaskParentBase
|
||||
{
|
||||
public:
|
||||
static already_AddRefed<GetFileOrDirectoryTaskParent>
|
||||
Create(FileSystemBase* aFileSystem,
|
||||
const FileSystemGetFileOrDirectoryParams& aParam,
|
||||
FileSystemRequestParent* aParent,
|
||||
ErrorResult& aRv);
|
||||
|
||||
virtual void
|
||||
GetPermissionAccessType(nsCString& aAccess) const override;
|
||||
|
||||
protected:
|
||||
virtual FileSystemResponseValue
|
||||
GetSuccessRequestResult(ErrorResult& aRv) const override;
|
||||
|
||||
virtual nsresult
|
||||
IOWork() override;
|
||||
|
||||
private:
|
||||
GetFileOrDirectoryTaskParent(FileSystemBase* aFileSystem,
|
||||
const FileSystemGetFileOrDirectoryParams& aParam,
|
||||
FileSystemRequestParent* aParent);
|
||||
|
||||
nsCOMPtr<nsIFile> mTargetPath;
|
||||
|
||||
// Whether we get a directory.
|
||||
bool mIsDirectory;
|
||||
Directory::DirectoryType mType;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
|
@ -20,10 +20,7 @@ namespace dom {
|
||||
OSFileSystem::OSFileSystem(const nsAString& aRootDir)
|
||||
{
|
||||
mLocalOrDeviceStorageRootPath = aRootDir;
|
||||
|
||||
// Non-mobile devices don't have the concept of separate permissions to
|
||||
// access different parts of devices storage like Pictures, or Videos, etc.
|
||||
mRequiresPermissionChecks = false;
|
||||
mPermissionCheckType = ePermissionCheckNotRequired;
|
||||
|
||||
#ifdef DEBUG
|
||||
mPermission.AssignLiteral("never-used");
|
||||
@ -33,6 +30,8 @@ OSFileSystem::OSFileSystem(const nsAString& aRootDir)
|
||||
already_AddRefed<FileSystemBase>
|
||||
OSFileSystem::Clone()
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
RefPtr<OSFileSystem> fs = new OSFileSystem(mLocalOrDeviceStorageRootPath);
|
||||
if (mParent) {
|
||||
fs->Init(mParent);
|
||||
@ -44,9 +43,11 @@ OSFileSystem::Clone()
|
||||
void
|
||||
OSFileSystem::Init(nsISupports* aParent)
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
MOZ_ASSERT(!mParent, "No duple Init() calls");
|
||||
MOZ_ASSERT(aParent);
|
||||
|
||||
mParent = aParent;
|
||||
|
||||
#ifdef DEBUG
|
||||
@ -58,6 +59,7 @@ OSFileSystem::Init(nsISupports* aParent)
|
||||
nsISupports*
|
||||
OSFileSystem::GetParentObject() const
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
return mParent;
|
||||
}
|
||||
@ -65,6 +67,7 @@ OSFileSystem::GetParentObject() const
|
||||
void
|
||||
OSFileSystem::GetRootName(nsAString& aRetval) const
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
aRetval.AssignLiteral(FILESYSTEM_DOM_PATH_SEPARATOR_LITERAL);
|
||||
}
|
||||
|
||||
@ -91,12 +94,18 @@ OSFileSystem::IsSafeDirectory(Directory* aDir) const
|
||||
void
|
||||
OSFileSystem::Unlink()
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
|
||||
mParent = nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
OSFileSystem::Traverse(nsCycleCollectionTraversalCallback &cb)
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
|
||||
OSFileSystem* tmp = this;
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mParent);
|
||||
}
|
||||
@ -104,8 +113,23 @@ OSFileSystem::Traverse(nsCycleCollectionTraversalCallback &cb)
|
||||
void
|
||||
OSFileSystem::SerializeDOMPath(nsAString& aOutput) const
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
aOutput = mLocalOrDeviceStorageRootPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* OSFileSystemParent
|
||||
*/
|
||||
|
||||
OSFileSystemParent::OSFileSystemParent(const nsAString& aRootDir)
|
||||
{
|
||||
mLocalOrDeviceStorageRootPath = aRootDir;
|
||||
mPermissionCheckType = ePermissionCheckNotRequired;
|
||||
|
||||
#ifdef DEBUG
|
||||
mPermission.AssignLiteral("never-used");
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
@ -47,7 +47,71 @@ public:
|
||||
private:
|
||||
virtual ~OSFileSystem() {}
|
||||
|
||||
nsCOMPtr<nsISupports> mParent;
|
||||
nsCOMPtr<nsISupports> mParent;
|
||||
};
|
||||
|
||||
class OSFileSystemParent final : public FileSystemBase
|
||||
{
|
||||
public:
|
||||
explicit OSFileSystemParent(const nsAString& aRootDir);
|
||||
|
||||
// Overrides FileSystemBase
|
||||
|
||||
virtual already_AddRefed<FileSystemBase>
|
||||
Clone() override
|
||||
{
|
||||
MOZ_CRASH("This should not be called on the PBackground thread.");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
virtual nsISupports*
|
||||
GetParentObject() const override
|
||||
{
|
||||
MOZ_CRASH("This should not be called on the PBackground thread.");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
virtual void
|
||||
GetRootName(nsAString& aRetval) const override
|
||||
{
|
||||
MOZ_CRASH("This should not be called on the PBackground thread.");
|
||||
}
|
||||
|
||||
virtual bool
|
||||
IsSafeFile(nsIFile* aFile) const override
|
||||
{
|
||||
MOZ_CRASH("This should not be called on the PBackground thread.");
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual bool
|
||||
IsSafeDirectory(Directory* aDir) const override
|
||||
{
|
||||
MOZ_CRASH("This should not be called on the PBackground thread.");
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual void
|
||||
SerializeDOMPath(nsAString& aOutput) const override
|
||||
{
|
||||
MOZ_CRASH("This should not be called on the PBackground thread.");
|
||||
}
|
||||
|
||||
// CC methods
|
||||
virtual void
|
||||
Unlink() override
|
||||
{
|
||||
MOZ_CRASH("This should not be called on the PBackground thread.");
|
||||
}
|
||||
|
||||
virtual void
|
||||
Traverse(nsCycleCollectionTraversalCallback &cb) override
|
||||
{
|
||||
MOZ_CRASH("This should not be called on the PBackground thread.");
|
||||
}
|
||||
|
||||
private:
|
||||
virtual ~OSFileSystemParent() {}
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
|
72
dom/filesystem/PFileSystemParams.ipdlh
Normal file
72
dom/filesystem/PFileSystemParams.ipdlh
Normal file
@ -0,0 +1,72 @@
|
||||
/* 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 protocol PBlob;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
struct FileSystemCreateDirectoryParams
|
||||
{
|
||||
nsString filesystem;
|
||||
nsString realPath;
|
||||
};
|
||||
|
||||
union FileSystemFileDataValue
|
||||
{
|
||||
uint8_t[];
|
||||
PBlob;
|
||||
};
|
||||
|
||||
struct FileSystemCreateFileParams
|
||||
{
|
||||
nsString filesystem;
|
||||
nsString realPath;
|
||||
FileSystemFileDataValue data;
|
||||
bool replace;
|
||||
};
|
||||
|
||||
struct FileSystemGetDirectoryListingParams
|
||||
{
|
||||
nsString filesystem;
|
||||
nsString realPath;
|
||||
bool isRoot;
|
||||
// 'filters' could be an array rather than a semicolon separated string
|
||||
// (we'd then use InfallibleTArray<nsString> internally), but that is
|
||||
// wasteful. E10s requires us to pass the filters over as a string anyway,
|
||||
// so avoiding using an array avoids serialization on the side passing the
|
||||
// filters. Since an nsString can share its buffer when copied,
|
||||
// using that instead of InfallibleTArray<nsString> makes copying the filters
|
||||
// around in any given process a bit more efficient too, since copying a
|
||||
// single nsString is cheaper than copying InfallibleTArray member data and
|
||||
// each nsString that it contains.
|
||||
nsString filters;
|
||||
};
|
||||
|
||||
struct FileSystemGetFileOrDirectoryParams
|
||||
{
|
||||
nsString filesystem;
|
||||
nsString realPath;
|
||||
bool isRoot;
|
||||
};
|
||||
|
||||
struct FileSystemRemoveParams
|
||||
{
|
||||
nsString filesystem;
|
||||
nsString directory;
|
||||
nsString targetDirectory;
|
||||
bool recursive;
|
||||
};
|
||||
|
||||
union FileSystemParams
|
||||
{
|
||||
FileSystemCreateDirectoryParams;
|
||||
FileSystemCreateFileParams;
|
||||
FileSystemGetDirectoryListingParams;
|
||||
FileSystemGetFileOrDirectoryParams;
|
||||
FileSystemRemoveParams;
|
||||
};
|
||||
|
||||
} // dom namespace
|
||||
} // mozilla namespace
|
@ -4,8 +4,8 @@
|
||||
* 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 protocol PBackground;
|
||||
include protocol PBlob;
|
||||
include protocol PContent;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
@ -62,9 +62,9 @@ union FileSystemResponseValue
|
||||
FileSystemErrorResponse;
|
||||
};
|
||||
|
||||
sync protocol PFileSystemRequest
|
||||
protocol PFileSystemRequest
|
||||
{
|
||||
manager PContent;
|
||||
manager PBackground;
|
||||
|
||||
child:
|
||||
async __delete__(FileSystemResponseValue response);
|
||||
|
@ -9,6 +9,7 @@
|
||||
#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"
|
||||
@ -18,6 +19,10 @@
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
/**
|
||||
* RemoveTask
|
||||
*/
|
||||
|
||||
/* static */ already_AddRefed<RemoveTask>
|
||||
RemoveTask::Create(FileSystemBase* aFileSystem,
|
||||
nsIFile* aDirPath,
|
||||
@ -50,42 +55,6 @@ RemoveTask::Create(FileSystemBase* aFileSystem,
|
||||
return task.forget();
|
||||
}
|
||||
|
||||
/* static */ already_AddRefed<RemoveTask>
|
||||
RemoveTask::Create(FileSystemBase* aFileSystem,
|
||||
const FileSystemRemoveParams& aParam,
|
||||
FileSystemRequestParent* aParent,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
MOZ_ASSERT(XRE_IsParentProcess(), "Only call from parent process!");
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
MOZ_ASSERT(aFileSystem);
|
||||
|
||||
RefPtr<RemoveTask> task =
|
||||
new RemoveTask(aFileSystem, aParam, aParent);
|
||||
|
||||
NS_ConvertUTF16toUTF8 directoryPath(aParam.directory());
|
||||
aRv = NS_NewNativeLocalFile(directoryPath, true,
|
||||
getter_AddRefs(task->mDirPath));
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
task->mRecursive = aParam.recursive();
|
||||
|
||||
NS_ConvertUTF16toUTF8 path(aParam.targetDirectory());
|
||||
aRv = NS_NewNativeLocalFile(path, true, getter_AddRefs(task->mTargetPath));
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!FileSystemUtils::IsDescendantPath(task->mDirPath, task->mTargetPath)) {
|
||||
aRv.Throw(NS_ERROR_DOM_FILESYSTEM_NO_MODIFICATION_ALLOWED_ERR);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return task.forget();
|
||||
}
|
||||
|
||||
RemoveTask::RemoveTask(FileSystemBase* aFileSystem,
|
||||
nsIFile* aDirPath,
|
||||
nsIFile* aTargetPath,
|
||||
@ -102,22 +71,9 @@ RemoveTask::RemoveTask(FileSystemBase* aFileSystem,
|
||||
MOZ_ASSERT(aTargetPath);
|
||||
}
|
||||
|
||||
RemoveTask::RemoveTask(FileSystemBase* aFileSystem,
|
||||
const FileSystemRemoveParams& aParam,
|
||||
FileSystemRequestParent* aParent)
|
||||
: FileSystemTaskBase(aFileSystem, aParam, aParent)
|
||||
, mRecursive(false)
|
||||
, mReturnValue(false)
|
||||
{
|
||||
MOZ_ASSERT(XRE_IsParentProcess(), "Only call from parent process!");
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
MOZ_ASSERT(aFileSystem);
|
||||
}
|
||||
|
||||
RemoveTask::~RemoveTask()
|
||||
{
|
||||
MOZ_ASSERT(!mPromise || NS_IsMainThread(),
|
||||
"mPromise should be released on main thread!");
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
}
|
||||
|
||||
already_AddRefed<Promise>
|
||||
@ -153,24 +109,104 @@ RemoveTask::GetRequestParams(const nsString& aSerializedDOMPath,
|
||||
return param;
|
||||
}
|
||||
|
||||
FileSystemResponseValue
|
||||
RemoveTask::GetSuccessRequestResult(ErrorResult& aRv) const
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
return FileSystemBooleanResponse(mReturnValue);
|
||||
}
|
||||
|
||||
void
|
||||
RemoveTask::SetSuccessRequestResult(const FileSystemResponseValue& aValue,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
|
||||
FileSystemBooleanResponse r = aValue;
|
||||
mReturnValue = r.success();
|
||||
}
|
||||
|
||||
void
|
||||
RemoveTask::HandlerCallback()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
|
||||
if (mFileSystem->IsShutdown()) {
|
||||
mPromise = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
if (HasError()) {
|
||||
mPromise->MaybeReject(mErrorValue);
|
||||
mPromise = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
mPromise->MaybeResolve(mReturnValue);
|
||||
mPromise = nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
RemoveTask::GetPermissionAccessType(nsCString& aAccess) const
|
||||
{
|
||||
aAccess.AssignLiteral(REMOVE_TASK_PERMISSION);
|
||||
}
|
||||
|
||||
/**
|
||||
* RemoveTaskParent
|
||||
*/
|
||||
|
||||
/* static */ already_AddRefed<RemoveTaskParent>
|
||||
RemoveTaskParent::Create(FileSystemBase* aFileSystem,
|
||||
const FileSystemRemoveParams& aParam,
|
||||
FileSystemRequestParent* aParent,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
MOZ_ASSERT(XRE_IsParentProcess(), "Only call from parent process!");
|
||||
AssertIsOnBackgroundThread();
|
||||
MOZ_ASSERT(aFileSystem);
|
||||
|
||||
RefPtr<RemoveTaskParent> task =
|
||||
new RemoveTaskParent(aFileSystem, aParam, aParent);
|
||||
|
||||
NS_ConvertUTF16toUTF8 directoryPath(aParam.directory());
|
||||
aRv = NS_NewNativeLocalFile(directoryPath, true,
|
||||
getter_AddRefs(task->mDirPath));
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
task->mRecursive = aParam.recursive();
|
||||
|
||||
NS_ConvertUTF16toUTF8 path(aParam.targetDirectory());
|
||||
aRv = NS_NewNativeLocalFile(path, true, getter_AddRefs(task->mTargetPath));
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!FileSystemUtils::IsDescendantPath(task->mDirPath, task->mTargetPath)) {
|
||||
aRv.Throw(NS_ERROR_DOM_FILESYSTEM_NO_MODIFICATION_ALLOWED_ERR);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return task.forget();
|
||||
}
|
||||
|
||||
RemoveTaskParent::RemoveTaskParent(FileSystemBase* aFileSystem,
|
||||
const FileSystemRemoveParams& aParam,
|
||||
FileSystemRequestParent* aParent)
|
||||
: FileSystemTaskParentBase(aFileSystem, aParam, aParent)
|
||||
, mRecursive(false)
|
||||
, mReturnValue(false)
|
||||
{
|
||||
MOZ_ASSERT(XRE_IsParentProcess(), "Only call from parent process!");
|
||||
AssertIsOnBackgroundThread();
|
||||
MOZ_ASSERT(aFileSystem);
|
||||
}
|
||||
|
||||
FileSystemResponseValue
|
||||
RemoveTaskParent::GetSuccessRequestResult(ErrorResult& aRv) const
|
||||
{
|
||||
AssertIsOnBackgroundThread();
|
||||
|
||||
return FileSystemBooleanResponse(mReturnValue);
|
||||
}
|
||||
|
||||
nsresult
|
||||
RemoveTask::Work()
|
||||
RemoveTaskParent::IOWork()
|
||||
{
|
||||
MOZ_ASSERT(XRE_IsParentProcess(),
|
||||
"Only call from parent process!");
|
||||
@ -214,28 +250,9 @@ RemoveTask::Work()
|
||||
}
|
||||
|
||||
void
|
||||
RemoveTask::HandlerCallback()
|
||||
RemoveTaskParent::GetPermissionAccessType(nsCString& aAccess) const
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
if (mFileSystem->IsShutdown()) {
|
||||
mPromise = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
if (HasError()) {
|
||||
mPromise->MaybeReject(mErrorValue);
|
||||
mPromise = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
mPromise->MaybeResolve(mReturnValue);
|
||||
mPromise = nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
RemoveTask::GetPermissionAccessType(nsCString& aAccess) const
|
||||
{
|
||||
aAccess.AssignLiteral("write");
|
||||
aAccess.AssignLiteral(REMOVE_TASK_PERMISSION);
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
|
@ -11,6 +11,8 @@
|
||||
#include "nsAutoPtr.h"
|
||||
#include "mozilla/ErrorResult.h"
|
||||
|
||||
#define REMOVE_TASK_PERMISSION "write"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
@ -27,12 +29,6 @@ public:
|
||||
bool aRecursive,
|
||||
ErrorResult& aRv);
|
||||
|
||||
static already_AddRefed<RemoveTask>
|
||||
Create(FileSystemBase* aFileSystem,
|
||||
const FileSystemRemoveParams& aParam,
|
||||
FileSystemRequestParent* aParent,
|
||||
ErrorResult& aRv);
|
||||
|
||||
virtual
|
||||
~RemoveTask();
|
||||
|
||||
@ -47,16 +43,10 @@ protected:
|
||||
GetRequestParams(const nsString& aSerializedDOMPath,
|
||||
ErrorResult& aRv) const override;
|
||||
|
||||
virtual FileSystemResponseValue
|
||||
GetSuccessRequestResult(ErrorResult& aRv) const override;
|
||||
|
||||
virtual void
|
||||
SetSuccessRequestResult(const FileSystemResponseValue& aValue,
|
||||
ErrorResult& aRv) override;
|
||||
|
||||
virtual nsresult
|
||||
Work() override;
|
||||
|
||||
virtual void
|
||||
HandlerCallback() override;
|
||||
|
||||
@ -66,10 +56,6 @@ private:
|
||||
nsIFile* aTargetPath,
|
||||
bool aRecursive);
|
||||
|
||||
RemoveTask(FileSystemBase* aFileSystem,
|
||||
const FileSystemRemoveParams& aParam,
|
||||
FileSystemRequestParent* aParent);
|
||||
|
||||
RefPtr<Promise> mPromise;
|
||||
|
||||
// This path is the Directory::mFile.
|
||||
@ -82,6 +68,40 @@ private:
|
||||
bool mReturnValue;
|
||||
};
|
||||
|
||||
class RemoveTaskParent final : public FileSystemTaskParentBase
|
||||
{
|
||||
public:
|
||||
static already_AddRefed<RemoveTaskParent>
|
||||
Create(FileSystemBase* aFileSystem,
|
||||
const FileSystemRemoveParams& aParam,
|
||||
FileSystemRequestParent* aParent,
|
||||
ErrorResult& aRv);
|
||||
|
||||
virtual void
|
||||
GetPermissionAccessType(nsCString& aAccess) const override;
|
||||
|
||||
protected:
|
||||
virtual FileSystemResponseValue
|
||||
GetSuccessRequestResult(ErrorResult& aRv) const override;
|
||||
|
||||
virtual nsresult
|
||||
IOWork() override;
|
||||
|
||||
private:
|
||||
RemoveTaskParent(FileSystemBase* aFileSystem,
|
||||
const FileSystemRemoveParams& aParam,
|
||||
FileSystemRequestParent* aParent);
|
||||
|
||||
// This path is the Directory::mFile.
|
||||
nsCOMPtr<nsIFile> mDirPath;
|
||||
|
||||
// This is what we want to remove. mTargetPath is discendant path of mDirPath.
|
||||
nsCOMPtr<nsIFile> mTargetPath;
|
||||
|
||||
bool mRecursive;
|
||||
bool mReturnValue;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
|
@ -35,6 +35,7 @@ UNIFIED_SOURCES += [
|
||||
FINAL_LIBRARY = 'xul'
|
||||
|
||||
IPDL_SOURCES += [
|
||||
'PFileSystemParams.ipdlh',
|
||||
'PFileSystemRequest.ipdl',
|
||||
]
|
||||
|
||||
|
@ -176,8 +176,6 @@
|
||||
#include "mozilla/dom/mobileconnection/MobileConnectionChild.h"
|
||||
#include "mozilla/dom/mobilemessage/SmsChild.h"
|
||||
#include "mozilla/dom/devicestorage/DeviceStorageRequestChild.h"
|
||||
#include "mozilla/dom/PFileSystemRequestChild.h"
|
||||
#include "mozilla/dom/FileSystemTaskBase.h"
|
||||
#include "mozilla/dom/bluetooth/PBluetoothChild.h"
|
||||
#include "mozilla/dom/PFMRadioChild.h"
|
||||
#include "mozilla/dom/PPresentationChild.h"
|
||||
@ -1828,24 +1826,6 @@ ContentChild::DeallocPDeviceStorageRequestChild(PDeviceStorageRequestChild* aDev
|
||||
return true;
|
||||
}
|
||||
|
||||
PFileSystemRequestChild*
|
||||
ContentChild::AllocPFileSystemRequestChild(const FileSystemParams& aParams)
|
||||
{
|
||||
MOZ_CRASH("Should never get here!");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool
|
||||
ContentChild::DeallocPFileSystemRequestChild(PFileSystemRequestChild* aFileSystem)
|
||||
{
|
||||
mozilla::dom::FileSystemTaskBase* child =
|
||||
static_cast<mozilla::dom::FileSystemTaskBase*>(aFileSystem);
|
||||
// The reference is increased in FileSystemTaskBase::Start of
|
||||
// FileSystemTaskBase.cpp. We should decrease it after IPC.
|
||||
NS_RELEASE(child);
|
||||
return true;
|
||||
}
|
||||
|
||||
PMobileConnectionChild*
|
||||
ContentChild::SendPMobileConnectionConstructor(PMobileConnectionChild* aActor,
|
||||
const uint32_t& aClientId)
|
||||
|
@ -191,12 +191,6 @@ public:
|
||||
virtual bool
|
||||
DeallocPDeviceStorageRequestChild(PDeviceStorageRequestChild*) override;
|
||||
|
||||
virtual PFileSystemRequestChild*
|
||||
AllocPFileSystemRequestChild(const FileSystemParams&) override;
|
||||
|
||||
virtual bool
|
||||
DeallocPFileSystemRequestChild(PFileSystemRequestChild*) override;
|
||||
|
||||
virtual PBlobChild*
|
||||
AllocPBlobChild(const BlobConstructorParams& aParams) override;
|
||||
|
||||
|
@ -47,7 +47,6 @@
|
||||
#include "mozilla/dom/Element.h"
|
||||
#include "mozilla/dom/File.h"
|
||||
#include "mozilla/dom/ExternalHelperAppParent.h"
|
||||
#include "mozilla/dom/FileSystemRequestParent.h"
|
||||
#include "mozilla/dom/GeolocationBinding.h"
|
||||
#ifdef MOZ_EME
|
||||
#include "mozilla/dom/MediaKeySystemAccess.h"
|
||||
@ -3521,24 +3520,6 @@ ContentParent::DeallocPDeviceStorageRequestParent(PDeviceStorageRequestParent* d
|
||||
return true;
|
||||
}
|
||||
|
||||
PFileSystemRequestParent*
|
||||
ContentParent::AllocPFileSystemRequestParent(const FileSystemParams& aParams)
|
||||
{
|
||||
RefPtr<FileSystemRequestParent> result = new FileSystemRequestParent();
|
||||
if (!result->Dispatch(this, aParams)) {
|
||||
return nullptr;
|
||||
}
|
||||
return result.forget().take();
|
||||
}
|
||||
|
||||
bool
|
||||
ContentParent::DeallocPFileSystemRequestParent(PFileSystemRequestParent* doomed)
|
||||
{
|
||||
FileSystemRequestParent* parent = static_cast<FileSystemRequestParent*>(doomed);
|
||||
NS_RELEASE(parent);
|
||||
return true;
|
||||
}
|
||||
|
||||
PBlobParent*
|
||||
ContentParent::AllocPBlobParent(const BlobConstructorParams& aParams)
|
||||
{
|
||||
|
@ -737,12 +737,6 @@ private:
|
||||
virtual bool
|
||||
DeallocPDeviceStorageRequestParent(PDeviceStorageRequestParent*) override;
|
||||
|
||||
virtual PFileSystemRequestParent*
|
||||
AllocPFileSystemRequestParent(const FileSystemParams&) override;
|
||||
|
||||
virtual bool
|
||||
DeallocPFileSystemRequestParent(PFileSystemRequestParent*) override;
|
||||
|
||||
virtual PBlobParent*
|
||||
AllocPBlobParent(const BlobConstructorParams& aParams) override;
|
||||
|
||||
|
@ -21,7 +21,6 @@ include protocol PHandlerService;
|
||||
include protocol PDeviceStorageRequest;
|
||||
include protocol PFileDescriptorSet;
|
||||
include protocol PFMRadio;
|
||||
include protocol PFileSystemRequest;
|
||||
include protocol PHal;
|
||||
include protocol PHeapSnapshotTempFileHelper;
|
||||
include protocol PIcc;
|
||||
@ -267,67 +266,6 @@ union FMRadioRequestParams
|
||||
FMRadioRequestCancelSeekParams;
|
||||
};
|
||||
|
||||
struct FileSystemCreateDirectoryParams
|
||||
{
|
||||
nsString filesystem;
|
||||
nsString realPath;
|
||||
};
|
||||
|
||||
union FileSystemFileDataValue
|
||||
{
|
||||
uint8_t[];
|
||||
PBlob;
|
||||
};
|
||||
|
||||
struct FileSystemCreateFileParams
|
||||
{
|
||||
nsString filesystem;
|
||||
nsString realPath;
|
||||
FileSystemFileDataValue data;
|
||||
bool replace;
|
||||
};
|
||||
|
||||
struct FileSystemGetDirectoryListingParams
|
||||
{
|
||||
nsString filesystem;
|
||||
nsString realPath;
|
||||
bool isRoot;
|
||||
// 'filters' could be an array rather than a semicolon separated string
|
||||
// (we'd then use InfallibleTArray<nsString> internally), but that is
|
||||
// wasteful. E10s requires us to pass the filters over as a string anyway,
|
||||
// so avoiding using an array avoids serialization on the side passing the
|
||||
// filters. Since an nsString can share its buffer when copied,
|
||||
// using that instead of InfallibleTArray<nsString> makes copying the filters
|
||||
// around in any given process a bit more efficient too, since copying a
|
||||
// single nsString is cheaper than copying InfallibleTArray member data and
|
||||
// each nsString that it contains.
|
||||
nsString filters;
|
||||
};
|
||||
|
||||
struct FileSystemGetFileOrDirectoryParams
|
||||
{
|
||||
nsString filesystem;
|
||||
nsString realPath;
|
||||
bool isRoot;
|
||||
};
|
||||
|
||||
struct FileSystemRemoveParams
|
||||
{
|
||||
nsString filesystem;
|
||||
nsString directory;
|
||||
nsString targetDirectory;
|
||||
bool recursive;
|
||||
};
|
||||
|
||||
union FileSystemParams
|
||||
{
|
||||
FileSystemCreateDirectoryParams;
|
||||
FileSystemCreateFileParams;
|
||||
FileSystemGetDirectoryListingParams;
|
||||
FileSystemGetFileOrDirectoryParams;
|
||||
FileSystemRemoveParams;
|
||||
};
|
||||
|
||||
union PrefValue {
|
||||
nsCString;
|
||||
int32_t;
|
||||
@ -474,7 +412,6 @@ prio(normal upto urgent) sync protocol PContent
|
||||
manages PCrashReporter;
|
||||
manages PCycleCollectWithLogs;
|
||||
manages PDeviceStorageRequest;
|
||||
manages PFileSystemRequest;
|
||||
manages PPSMContentDownloader;
|
||||
manages PExternalHelperApp;
|
||||
manages PFileDescriptorSet;
|
||||
@ -825,8 +762,6 @@ parent:
|
||||
async PRemoteSpellcheckEngine();
|
||||
async PDeviceStorageRequest(DeviceStorageParams params);
|
||||
|
||||
async PFileSystemRequest(FileSystemParams params);
|
||||
|
||||
sync PCrashReporter(NativeThreadId tid, uint32_t processType);
|
||||
|
||||
async GetSystemMemory(uint64_t getterId);
|
||||
|
@ -14,6 +14,8 @@
|
||||
#include "mozilla/media/MediaChild.h"
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/dom/PBlobChild.h"
|
||||
#include "mozilla/dom/PFileSystemRequestChild.h"
|
||||
#include "mozilla/dom/FileSystemTaskBase.h"
|
||||
#include "mozilla/dom/asmjscache/AsmJSCache.h"
|
||||
#include "mozilla/dom/cache/ActorUtils.h"
|
||||
#include "mozilla/dom/indexedDB/PBackgroundIDBFactoryChild.h"
|
||||
@ -449,6 +451,23 @@ BackgroundChildImpl::DeallocPQuotaChild(PQuotaChild* aActor)
|
||||
return true;
|
||||
}
|
||||
|
||||
dom::PFileSystemRequestChild*
|
||||
BackgroundChildImpl::AllocPFileSystemRequestChild(const FileSystemParams& aParams)
|
||||
{
|
||||
MOZ_CRASH("Should never get here!");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool
|
||||
BackgroundChildImpl::DeallocPFileSystemRequestChild(PFileSystemRequestChild* aActor)
|
||||
{
|
||||
// The reference is increased in FileSystemTaskBase::Start of
|
||||
// FileSystemTaskBase.cpp. We should decrease it after IPC.
|
||||
RefPtr<dom::FileSystemTaskBase> child =
|
||||
dont_AddRef(static_cast<dom::FileSystemTaskBase*>(aActor));
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace ipc
|
||||
} // namespace mozilla
|
||||
|
||||
|
@ -158,6 +158,13 @@ protected:
|
||||
|
||||
virtual bool
|
||||
DeallocPQuotaChild(PQuotaChild* aActor) override;
|
||||
|
||||
virtual PFileSystemRequestChild*
|
||||
AllocPFileSystemRequestChild(const FileSystemParams&) override;
|
||||
|
||||
virtual bool
|
||||
DeallocPFileSystemRequestChild(PFileSystemRequestChild*) override;
|
||||
|
||||
};
|
||||
|
||||
class BackgroundChildImpl::ThreadLocal final
|
||||
|
@ -14,6 +14,8 @@
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/dom/ContentParent.h"
|
||||
#include "mozilla/dom/DOMTypes.h"
|
||||
#include "mozilla/dom/FileSystemBase.h"
|
||||
#include "mozilla/dom/FileSystemRequestParent.h"
|
||||
#include "mozilla/dom/NuwaParent.h"
|
||||
#include "mozilla/dom/PBlobParent.h"
|
||||
#include "mozilla/dom/MessagePortParent.h"
|
||||
@ -29,9 +31,11 @@
|
||||
#include "mozilla/ipc/PBackgroundTestParent.h"
|
||||
#include "mozilla/layout/VsyncParent.h"
|
||||
#include "mozilla/dom/network/UDPSocketParent.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "nsIAppsService.h"
|
||||
#include "nsNetUtil.h"
|
||||
#include "nsIScriptSecurityManager.h"
|
||||
#include "nsProxyRelease.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "nsTraceRefcnt.h"
|
||||
@ -49,10 +53,12 @@ using mozilla::dom::asmjscache::PAsmJSCacheEntryParent;
|
||||
using mozilla::dom::cache::PCacheParent;
|
||||
using mozilla::dom::cache::PCacheStorageParent;
|
||||
using mozilla::dom::cache::PCacheStreamControlParent;
|
||||
using mozilla::dom::FileSystemBase;
|
||||
using mozilla::dom::FileSystemRequestParent;
|
||||
using mozilla::dom::MessagePortParent;
|
||||
using mozilla::dom::NuwaParent;
|
||||
using mozilla::dom::PMessagePortParent;
|
||||
using mozilla::dom::PNuwaParent;
|
||||
using mozilla::dom::NuwaParent;
|
||||
using mozilla::dom::UDPSocketParent;
|
||||
|
||||
namespace {
|
||||
@ -455,6 +461,20 @@ BackgroundParentImpl::AllocPBroadcastChannelParent(
|
||||
|
||||
namespace {
|
||||
|
||||
struct MOZ_STACK_CLASS NullifyContentParentRAII
|
||||
{
|
||||
explicit NullifyContentParentRAII(RefPtr<ContentParent>& aContentParent)
|
||||
: mContentParent(aContentParent)
|
||||
{}
|
||||
|
||||
~NullifyContentParentRAII()
|
||||
{
|
||||
mContentParent = nullptr;
|
||||
}
|
||||
|
||||
RefPtr<ContentParent>& mContentParent;
|
||||
};
|
||||
|
||||
class CheckPrincipalRunnable final : public nsRunnable
|
||||
{
|
||||
public:
|
||||
@ -475,21 +495,7 @@ public:
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
struct MOZ_STACK_CLASS RunRAII
|
||||
{
|
||||
explicit RunRAII(RefPtr<ContentParent>& aContentParent)
|
||||
: mContentParent(aContentParent)
|
||||
{}
|
||||
|
||||
~RunRAII()
|
||||
{
|
||||
mContentParent = nullptr;
|
||||
}
|
||||
|
||||
RefPtr<ContentParent>& mContentParent;
|
||||
};
|
||||
|
||||
RunRAII raii(mContentParent);
|
||||
NullifyContentParentRAII raii(mContentParent);
|
||||
|
||||
nsCOMPtr<nsIPrincipal> principal = PrincipalInfoToPrincipal(mPrincipalInfo);
|
||||
AssertAppPrincipal(mContentParent, principal);
|
||||
@ -522,6 +528,87 @@ private:
|
||||
nsCString mOrigin;
|
||||
};
|
||||
|
||||
class CheckPermissionRunnable final : public nsRunnable
|
||||
{
|
||||
public:
|
||||
CheckPermissionRunnable(already_AddRefed<ContentParent> aParent,
|
||||
FileSystemRequestParent* aActor,
|
||||
FileSystemBase::ePermissionCheckType aPermissionCheckType,
|
||||
const nsCString& aPermissionName)
|
||||
: mContentParent(aParent)
|
||||
, mActor(aActor)
|
||||
, mPermissionCheckType(aPermissionCheckType)
|
||||
, mPermissionName(aPermissionName)
|
||||
, mBackgroundEventTarget(NS_GetCurrentThread())
|
||||
{
|
||||
AssertIsInMainProcess();
|
||||
AssertIsOnBackgroundThread();
|
||||
|
||||
MOZ_ASSERT(mContentParent);
|
||||
MOZ_ASSERT(mBackgroundEventTarget);
|
||||
MOZ_ASSERT(mPermissionCheckType == FileSystemBase::ePermissionCheckRequired ||
|
||||
mPermissionCheckType == FileSystemBase::ePermissionCheckByTestingPref);
|
||||
}
|
||||
|
||||
NS_IMETHOD
|
||||
Run() override
|
||||
{
|
||||
if (NS_IsMainThread()) {
|
||||
NullifyContentParentRAII raii(mContentParent);
|
||||
|
||||
// If the permission is granted, we go back to the background thread to
|
||||
// dispatch this task.
|
||||
if (CheckPermission()) {
|
||||
return mBackgroundEventTarget->Dispatch(this, NS_DISPATCH_NORMAL);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
AssertIsOnBackgroundThread();
|
||||
|
||||
// It can happen that this actor has been destroyed in the meantime we were
|
||||
// on the main-thread.
|
||||
if (!mActor->Destroyed()) {
|
||||
mActor->Start();
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
~CheckPermissionRunnable()
|
||||
{
|
||||
NS_ProxyRelease(mBackgroundEventTarget, mActor.forget());
|
||||
}
|
||||
|
||||
bool
|
||||
CheckPermission()
|
||||
{
|
||||
if (mPermissionCheckType == FileSystemBase::ePermissionCheckByTestingPref &&
|
||||
mozilla::Preferences::GetBool("device.storage.prompt.testing", false)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!AssertAppProcessPermission(mContentParent.get(),
|
||||
mPermissionName.get())) {
|
||||
mContentParent->KillHard("PBackground actor killed: permission denied.");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
RefPtr<ContentParent> mContentParent;
|
||||
|
||||
RefPtr<FileSystemRequestParent> mActor;
|
||||
|
||||
FileSystemBase::ePermissionCheckType mPermissionCheckType;
|
||||
nsCString mPermissionName;
|
||||
|
||||
nsCOMPtr<nsIEventTarget> mBackgroundEventTarget;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
bool
|
||||
@ -736,6 +823,73 @@ BackgroundParentImpl::DeallocPQuotaParent(PQuotaParent* aActor)
|
||||
return mozilla::dom::quota::DeallocPQuotaParent(aActor);
|
||||
}
|
||||
|
||||
dom::PFileSystemRequestParent*
|
||||
BackgroundParentImpl::AllocPFileSystemRequestParent(
|
||||
const FileSystemParams& aParams)
|
||||
{
|
||||
AssertIsInMainProcess();
|
||||
AssertIsOnBackgroundThread();
|
||||
|
||||
RefPtr<FileSystemRequestParent> result = new FileSystemRequestParent();
|
||||
|
||||
if (NS_WARN_IF(!result->Initialize(aParams))) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return result.forget().take();
|
||||
}
|
||||
|
||||
bool
|
||||
BackgroundParentImpl::RecvPFileSystemRequestConstructor(
|
||||
PFileSystemRequestParent* aActor,
|
||||
const FileSystemParams& aParams)
|
||||
{
|
||||
AssertIsInMainProcess();
|
||||
AssertIsOnBackgroundThread();
|
||||
|
||||
RefPtr<FileSystemRequestParent> actor = static_cast<FileSystemRequestParent*>(aActor);
|
||||
|
||||
if (actor->PermissionCheckType() == FileSystemBase::ePermissionCheckNotRequired) {
|
||||
actor->Start();
|
||||
return true;
|
||||
}
|
||||
|
||||
RefPtr<ContentParent> parent = BackgroundParent::GetContentParent(this);
|
||||
|
||||
// If the ContentParent is null we are dealing with a same-process actor.
|
||||
if (!parent) {
|
||||
actor->Start();
|
||||
return true;
|
||||
}
|
||||
|
||||
const nsCString& permissionName = actor->PermissionName();
|
||||
MOZ_ASSERT(!permissionName.IsEmpty());
|
||||
|
||||
// At this point we should have the right permission but we do the last check
|
||||
// with this runnable. If the app doesn't have the permission, we kill the
|
||||
// child process.
|
||||
RefPtr<CheckPermissionRunnable> runnable =
|
||||
new CheckPermissionRunnable(parent.forget(), actor,
|
||||
actor->PermissionCheckType(), permissionName);
|
||||
|
||||
nsresult rv = NS_DispatchToMainThread(runnable);
|
||||
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(rv));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
BackgroundParentImpl::DeallocPFileSystemRequestParent(
|
||||
PFileSystemRequestParent* aDoomed)
|
||||
{
|
||||
AssertIsInMainProcess();
|
||||
AssertIsOnBackgroundThread();
|
||||
|
||||
RefPtr<FileSystemRequestParent> parent =
|
||||
dont_AddRef(static_cast<FileSystemRequestParent*>(aDoomed));
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace ipc
|
||||
} // namespace mozilla
|
||||
|
||||
|
@ -186,6 +186,17 @@ protected:
|
||||
|
||||
virtual bool
|
||||
DeallocPQuotaParent(PQuotaParent* aActor) override;
|
||||
|
||||
virtual PFileSystemRequestParent*
|
||||
AllocPFileSystemRequestParent(const FileSystemParams&) override;
|
||||
|
||||
virtual bool
|
||||
RecvPFileSystemRequestConstructor(PFileSystemRequestParent* aActor,
|
||||
const FileSystemParams& aParams) override;
|
||||
|
||||
virtual bool
|
||||
DeallocPFileSystemRequestParent(PFileSystemRequestParent*) override;
|
||||
|
||||
};
|
||||
|
||||
} // namespace ipc
|
||||
|
@ -12,6 +12,7 @@ include protocol PCache;
|
||||
include protocol PCacheStorage;
|
||||
include protocol PCacheStreamControl;
|
||||
include protocol PFileDescriptorSet;
|
||||
include protocol PFileSystemRequest;
|
||||
include protocol PMessagePort;
|
||||
include protocol PCameras;
|
||||
include protocol PNuwa;
|
||||
@ -23,6 +24,7 @@ include protocol PVsync;
|
||||
include DOMTypes;
|
||||
include PBackgroundSharedTypes;
|
||||
include PBackgroundIDBSharedTypes;
|
||||
include PFileSystemParams;
|
||||
|
||||
include "mozilla/dom/cache/IPCUtils.h";
|
||||
|
||||
@ -50,6 +52,7 @@ sync protocol PBackground
|
||||
manages PCacheStorage;
|
||||
manages PCacheStreamControl;
|
||||
manages PFileDescriptorSet;
|
||||
manages PFileSystemRequest;
|
||||
manages PMessagePort;
|
||||
manages PCameras;
|
||||
manages PNuwa;
|
||||
@ -95,6 +98,8 @@ parent:
|
||||
|
||||
async PQuota();
|
||||
|
||||
async PFileSystemRequest(FileSystemParams params);
|
||||
|
||||
child:
|
||||
async PCache();
|
||||
async PCacheStreamControl();
|
||||
|
Loading…
x
Reference in New Issue
Block a user