178 lines
7.8 KiB
C++
178 lines
7.8 KiB
C++
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
#include "FileSystemManagerParentFactory.h"
|
|
|
|
#include "mozilla/OriginAttributes.h"
|
|
#include "mozilla/StaticPrefs_dom.h"
|
|
#include "mozilla/dom/FileSystemDataManager.h"
|
|
#include "mozilla/dom/FileSystemLog.h"
|
|
#include "mozilla/dom/FileSystemManagerParent.h"
|
|
#include "mozilla/dom/FileSystemTypes.h"
|
|
#include "mozilla/dom/quota/PrincipalUtils.h"
|
|
#include "mozilla/dom/quota/QuotaCommon.h"
|
|
#include "mozilla/dom/quota/QuotaManager.h"
|
|
#include "mozilla/dom/quota/ResultExtensions.h"
|
|
#include "mozilla/ipc/Endpoint.h"
|
|
#include "mozilla/ipc/PBackgroundParent.h"
|
|
#include "nsIScriptObjectPrincipal.h"
|
|
#include "nsString.h"
|
|
|
|
namespace mozilla::dom {
|
|
mozilla::ipc::IPCResult CreateFileSystemManagerParent(
|
|
RefPtr<mozilla::ipc::PBackgroundParent> aBackgroundActor,
|
|
const mozilla::ipc::PrincipalInfo& aPrincipalInfo,
|
|
mozilla::ipc::Endpoint<PFileSystemManagerParent>&& aParentEndpoint,
|
|
std::function<void(const nsresult&)>&& aResolver) {
|
|
using CreateActorPromise =
|
|
MozPromise<RefPtr<FileSystemManagerParent>, nsresult, true>;
|
|
|
|
QM_TRY(OkIf(StaticPrefs::dom_fs_enabled()), IPC_OK(),
|
|
[aResolver](const auto&) { aResolver(NS_ERROR_DOM_NOT_ALLOWED_ERR); });
|
|
|
|
QM_TRY(OkIf(aParentEndpoint.IsValid()), IPC_OK(),
|
|
[aResolver](const auto&) { aResolver(NS_ERROR_INVALID_ARG); });
|
|
|
|
// This blocks Null and Expanded principals
|
|
QM_TRY(OkIf(quota::IsPrincipalInfoValid(aPrincipalInfo)), IPC_OK(),
|
|
[aResolver](const auto&) { aResolver(NS_ERROR_DOM_SECURITY_ERR); });
|
|
|
|
QM_TRY(quota::QuotaManager::EnsureCreated(), IPC_OK(),
|
|
[aResolver](const auto rv) { aResolver(rv); });
|
|
|
|
auto* const quotaManager = quota::QuotaManager::Get();
|
|
MOZ_ASSERT(quotaManager);
|
|
|
|
QM_TRY_UNWRAP(
|
|
auto principalMetadata,
|
|
quota::GetInfoFromValidatedPrincipalInfo(*quotaManager, aPrincipalInfo),
|
|
IPC_OK(), [aResolver](const auto rv) { aResolver(rv); });
|
|
|
|
quota::OriginMetadata originMetadata(std::move(principalMetadata),
|
|
quota::PERSISTENCE_TYPE_DEFAULT);
|
|
|
|
// Block use for now in PrivateBrowsing
|
|
QM_TRY(OkIf(!OriginAttributes::IsPrivateBrowsing(originMetadata.mOrigin)),
|
|
IPC_OK(),
|
|
[aResolver](const auto&) { aResolver(NS_ERROR_DOM_NOT_ALLOWED_ERR); });
|
|
|
|
LOG(("CreateFileSystemManagerParent, origin: %s",
|
|
originMetadata.mOrigin.get()));
|
|
|
|
RefPtr<mozilla::ipc::PBackgroundParent> backgroundActor =
|
|
std::move(aBackgroundActor);
|
|
|
|
// This creates the file system data manager, which has to be done on
|
|
// PBackground
|
|
fs::data::FileSystemDataManager::GetOrCreateFileSystemDataManager(
|
|
originMetadata)
|
|
->Then(
|
|
GetCurrentSerialEventTarget(), __func__,
|
|
[origin = originMetadata.mOrigin,
|
|
parentEndpoint = std::move(aParentEndpoint), backgroundActor,
|
|
aResolver](const fs::Registered<fs::data::FileSystemDataManager>&
|
|
dataManager) mutable {
|
|
QM_TRY_UNWRAP(fs::EntryId rootId, fs::data::GetRootHandle(origin),
|
|
QM_VOID,
|
|
([backgroundActor, aResolver](const auto& aRv) {
|
|
if (!backgroundActor->CanSend()) {
|
|
return;
|
|
}
|
|
|
|
aResolver(ToNSResult(aRv));
|
|
}));
|
|
|
|
InvokeAsync(
|
|
dataManager->MutableIOTaskQueuePtr(), __func__,
|
|
[dataManager = dataManager, rootId,
|
|
parentEndpoint = std::move(parentEndpoint)]() mutable {
|
|
RefPtr<FileSystemManagerParent> parent =
|
|
new FileSystemManagerParent(dataManager.inspect(),
|
|
rootId);
|
|
|
|
auto autoProxyDestroyFileSystemDataManagerHandle =
|
|
MakeScopeExit([&dataManager] {
|
|
nsCOMPtr<nsISerialEventTarget> target =
|
|
dataManager->MutableBackgroundTargetPtr();
|
|
|
|
MOZ_ALWAYS_SUCCEEDS(target->Dispatch(
|
|
NS_NewRunnableFunction(
|
|
"DestroyFileSystemDataManagerHandle",
|
|
[dataManager = std::move(dataManager)]() {}),
|
|
NS_DISPATCH_NORMAL));
|
|
});
|
|
|
|
LOG(("Binding parent endpoint"));
|
|
if (!parentEndpoint.Bind(parent)) {
|
|
return CreateActorPromise::CreateAndReject(NS_ERROR_FAILURE,
|
|
__func__);
|
|
}
|
|
|
|
return CreateActorPromise::CreateAndResolve(std::move(parent),
|
|
__func__);
|
|
})
|
|
->Then(GetCurrentSerialEventTarget(), __func__,
|
|
[dataManager = dataManager](
|
|
CreateActorPromise::ResolveOrRejectValue&& aValue) {
|
|
if (aValue.IsReject()) {
|
|
return BoolPromise::CreateAndReject(
|
|
aValue.RejectValue(), __func__);
|
|
}
|
|
|
|
RefPtr<FileSystemManagerParent> parent =
|
|
std::move(aValue.ResolveValue());
|
|
|
|
if (!parent->IsAlive()) {
|
|
return BoolPromise::CreateAndReject(NS_ERROR_ABORT,
|
|
__func__);
|
|
}
|
|
|
|
dataManager->RegisterActor(WrapNotNull(parent));
|
|
|
|
return BoolPromise::CreateAndResolve(true, __func__);
|
|
})
|
|
->Then(dataManager->MutableIOTaskQueuePtr(), __func__,
|
|
[](const BoolPromise::ResolveOrRejectValue& aValue) {
|
|
// Hopping to the I/O task queue is needed to avoid
|
|
// a potential race triggered by
|
|
// FileSystemManagerParent::SendCloseAll called by
|
|
// FileSystemManagerParent::RequestAllowToClose called
|
|
// by FileSystemDataManager::RegisterActor when the
|
|
// directory lock has been invalidated in the
|
|
// meantime. The race would cause that the child side
|
|
// could sometimes use the child actor for sending
|
|
// messages and sometimes not. This extra hop
|
|
// guarantees that the created child actor will always
|
|
// refuse to send messages.
|
|
return BoolPromise::CreateAndResolveOrReject(aValue,
|
|
__func__);
|
|
})
|
|
->Then(GetCurrentSerialEventTarget(), __func__,
|
|
[backgroundActor, aResolver](
|
|
const BoolPromise::ResolveOrRejectValue& aValue) {
|
|
if (!backgroundActor->CanSend()) {
|
|
return;
|
|
}
|
|
|
|
if (aValue.IsReject()) {
|
|
aResolver(aValue.RejectValue());
|
|
} else {
|
|
aResolver(NS_OK);
|
|
}
|
|
});
|
|
},
|
|
[backgroundActor, aResolver](nsresult aRejectValue) {
|
|
if (!backgroundActor->CanSend()) {
|
|
return;
|
|
}
|
|
|
|
aResolver(aRejectValue);
|
|
});
|
|
|
|
return IPC_OK();
|
|
}
|
|
|
|
} // namespace mozilla::dom
|