Bug 1768050: Move OPFS operations off PBackground r=janv,nika

Depends on D149260

Differential Revision: https://phabricator.services.mozilla.com/D147273
This commit is contained in:
Randell Jesup 2022-07-06 18:00:04 +00:00
parent 3a75178002
commit 3a934f66ac
26 changed files with 856 additions and 412 deletions

View File

@ -11,18 +11,21 @@
#include "mozilla/dom/FileSystemDirectoryHandleBinding.h"
#include "mozilla/dom/FileSystemDirectoryIterator.h"
#include "mozilla/dom/FileSystemHandleBinding.h"
#include "mozilla/dom/POriginPrivateFileSystem.h"
#include "mozilla/dom/Promise.h"
namespace mozilla::dom {
FileSystemDirectoryHandle::FileSystemDirectoryHandle(
nsIGlobalObject* aGlobal, const fs::FileSystemEntryMetadata& aMetadata,
nsIGlobalObject* aGlobal, RefPtr<FileSystemActorHolder>& aActor,
const fs::FileSystemEntryMetadata& aMetadata,
fs::FileSystemRequestHandler* aRequestHandler)
: FileSystemHandle(aGlobal, aMetadata, aRequestHandler) {}
: FileSystemHandle(aGlobal, aActor, aMetadata, aRequestHandler) {}
FileSystemDirectoryHandle::FileSystemDirectoryHandle(
nsIGlobalObject* aGlobal, const fs::FileSystemEntryMetadata& aMetadata)
: FileSystemDirectoryHandle(aGlobal, aMetadata,
nsIGlobalObject* aGlobal, RefPtr<FileSystemActorHolder>& aActor,
const fs::FileSystemEntryMetadata& aMetadata)
: FileSystemDirectoryHandle(aGlobal, aActor, aMetadata,
new fs::FileSystemRequestHandler()) {}
NS_IMPL_ISUPPORTS_CYCLE_COLLECTION_INHERITED_0(FileSystemDirectoryHandle,

View File

@ -23,10 +23,12 @@ struct FileSystemRemoveOptions;
class FileSystemDirectoryHandle final : public FileSystemHandle {
public:
FileSystemDirectoryHandle(nsIGlobalObject* aGlobal,
RefPtr<FileSystemActorHolder>& aActor,
const fs::FileSystemEntryMetadata& aMetadata,
fs::FileSystemRequestHandler* aRequestHandler);
FileSystemDirectoryHandle(nsIGlobalObject* aGlobal,
RefPtr<FileSystemActorHolder>& aActor,
const fs::FileSystemEntryMetadata& aMetadata);
NS_DECL_ISUPPORTS_INHERITED

View File

@ -10,6 +10,7 @@
#include "mozilla/ErrorResult.h"
#include "mozilla/dom/FileSystemFileHandleBinding.h"
#include "mozilla/dom/FileSystemHandleBinding.h"
#include "mozilla/dom/POriginPrivateFileSystem.h"
#include "mozilla/dom/Promise.h"
namespace mozilla::dom {
@ -19,13 +20,15 @@ NS_IMPL_ISUPPORTS_CYCLE_COLLECTION_INHERITED_0(FileSystemFileHandle,
NS_IMPL_CYCLE_COLLECTION_INHERITED(FileSystemFileHandle, FileSystemHandle)
FileSystemFileHandle::FileSystemFileHandle(
nsIGlobalObject* aGlobal, const fs::FileSystemEntryMetadata& aMetadata,
nsIGlobalObject* aGlobal, RefPtr<FileSystemActorHolder>& aActor,
const fs::FileSystemEntryMetadata& aMetadata,
fs::FileSystemRequestHandler* aRequestHandler)
: FileSystemHandle(aGlobal, aMetadata, aRequestHandler) {}
: FileSystemHandle(aGlobal, aActor, aMetadata, aRequestHandler) {}
FileSystemFileHandle::FileSystemFileHandle(
nsIGlobalObject* aGlobal, const fs::FileSystemEntryMetadata& aMetadata)
: FileSystemFileHandle(aGlobal, aMetadata,
nsIGlobalObject* aGlobal, RefPtr<FileSystemActorHolder>& aActor,
const fs::FileSystemEntryMetadata& aMetadata)
: FileSystemFileHandle(aGlobal, aActor, aMetadata,
new fs::FileSystemRequestHandler()) {}
// WebIDL Boilerplate

View File

@ -20,10 +20,12 @@ struct FileSystemCreateWritableOptions;
class FileSystemFileHandle final : public FileSystemHandle {
public:
FileSystemFileHandle(nsIGlobalObject* aGlobal,
RefPtr<FileSystemActorHolder>& aActor,
const fs::FileSystemEntryMetadata& aMetadata,
fs::FileSystemRequestHandler* aRequestHandler);
FileSystemFileHandle(nsIGlobalObject* aGlobal,
RefPtr<FileSystemActorHolder>& aActor,
const fs::FileSystemEntryMetadata& aMetadata);
NS_DECL_ISUPPORTS_INHERITED

View File

@ -9,6 +9,7 @@
#include "mozilla/ErrorResult.h"
#include "mozilla/dom/FileSystemHandleBinding.h"
#include "mozilla/dom/OriginPrivateFileSystemChild.h"
#include "mozilla/dom/Promise.h"
namespace mozilla::dom {
@ -22,11 +23,15 @@ NS_IMPL_CYCLE_COLLECTING_RELEASE(FileSystemHandle);
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(FileSystemHandle, mGlobal);
FileSystemHandle::FileSystemHandle(
nsIGlobalObject* aGlobal, const fs::FileSystemEntryMetadata& aMetadata,
nsIGlobalObject* aGlobal, RefPtr<FileSystemActorHolder>& aActor,
const fs::FileSystemEntryMetadata& aMetadata,
fs::FileSystemRequestHandler* aRequestHandler)
: mGlobal(aGlobal),
mActor(aActor),
mMetadata(aMetadata),
mRequestHandler(aRequestHandler) {}
mRequestHandler(aRequestHandler) {
MOZ_ASSERT(!mMetadata.entryId().IsEmpty());
}
// WebIDL Boilerplate
@ -55,4 +60,8 @@ already_AddRefed<Promise> FileSystemHandle::IsSameEntry(
return promise.forget();
}
OriginPrivateFileSystemChild* FileSystemHandle::Actor() const {
return mActor->Actor();
}
} // namespace mozilla::dom

View File

@ -7,7 +7,9 @@
#ifndef DOM_FS_FILESYSTEMHANDLE_H_
#define DOM_FS_FILESYSTEMHANDLE_H_
#include "mozilla/dom/PBackgroundFileSystem.h"
#include "mozilla/dom/FileSystemActorHolder.h"
#include "mozilla/dom/POriginPrivateFileSystem.h"
#include "mozilla/Logging.h"
#include "nsCOMPtr.h"
#include "nsISupports.h"
#include "nsWrapperCache.h"
@ -16,12 +18,20 @@ class nsIGlobalObject;
namespace mozilla {
extern LazyLogModule gOPFSLog;
#define LOG(args) MOZ_LOG(mozilla::gOPFSLog, mozilla::LogLevel::Verbose, args)
#define LOG_DEBUG(args) \
MOZ_LOG(mozilla::gOPFSLog, mozilla::LogLevel::Debug, args)
class ErrorResult;
namespace dom {
class DOMString;
enum class FileSystemHandleKind : uint8_t;
class OriginPrivateFileSystemChild;
class Promise;
namespace fs {
@ -31,6 +41,7 @@ class FileSystemRequestHandler;
class FileSystemHandle : public nsISupports, public nsWrapperCache {
public:
FileSystemHandle(nsIGlobalObject* aGlobal,
RefPtr<FileSystemActorHolder>& aActor,
const fs::FileSystemEntryMetadata& aMetadata,
fs::FileSystemRequestHandler* aRequestHandler);
@ -51,10 +62,13 @@ class FileSystemHandle : public nsISupports, public nsWrapperCache {
already_AddRefed<Promise> IsSameEntry(FileSystemHandle& aOther,
ErrorResult& aError) const;
OriginPrivateFileSystemChild* Actor() const;
protected:
virtual ~FileSystemHandle() = default;
nsCOMPtr<nsIGlobalObject> mGlobal;
RefPtr<FileSystemActorHolder> mActor;
const fs::FileSystemEntryMetadata mMetadata;

View File

@ -9,6 +9,7 @@
#include "nsIScriptObjectPrincipal.h"
#include "mozilla/dom/BackgroundFileSystemChild.h"
#include "mozilla/dom/OriginPrivateFileSystemChild.h"
#include "mozilla/dom/File.h"
#include "mozilla/dom/FileSystemFileHandle.h"
#include "mozilla/dom/FileSystemDirectoryHandle.h"
@ -16,17 +17,23 @@
#include "mozilla/dom/WorkerPrivate.h"
#include "mozilla/ipc/BackgroundChild.h"
#include "mozilla/ipc/BackgroundUtils.h"
#include "mozilla/ipc/Endpoint.h"
#include "mozilla/ipc/PBackgroundChild.h"
using namespace mozilla::ipc;
namespace mozilla::dom::fs {
using mozilla::ipc::RejectCallback;
namespace {
// Not static: BackgroundFileSystemChild must be owned by calling thread
RefPtr<mozilla::dom::BackgroundFileSystemChild> GetRootProvider(
nsIGlobalObject* aGlobal) {
using mozilla::dom::BackgroundFileSystemChild;
using mozilla::ipc::BackgroundChild;
using mozilla::ipc::PBackgroundChild;
using mozilla::ipc::PrincipalInfo;
// TODO: It would be nice to convert all error checks to QM_TRY some time
// later.
@ -61,7 +68,7 @@ RefPtr<mozilla::dom::BackgroundFileSystemChild> GetRootProvider(
return nullptr;
}
BackgroundFileSystemChild* actor = new BackgroundFileSystemChild();
auto* actor = new BackgroundFileSystemChild();
result = static_cast<BackgroundFileSystemChild*>(
backgroundActor->SendPBackgroundFileSystemConstructor(actor,
@ -88,11 +95,11 @@ RefPtr<mozilla::dom::BackgroundFileSystemChild> GetRootProvider(
}
// TODO: This is just a dummy implementation
RefPtr<File> MakeGetFileResult(const nsString& aName, const nsString& aType,
RefPtr<File> MakeGetFileResult(nsIGlobalObject* aGlobal, const nsString& aName,
const nsString& aType,
int64_t aLastModifiedMilliSeconds,
nsTArray<Name>&& aPath,
mozilla::ipc::FileDescriptor&& aFile,
nsIGlobalObject* aGlobal) {
nsTArray<Name>&& aPath, IPCBlob&& /* aFile */,
RefPtr<FileSystemActorHolder>& aActor) {
// TODO: Replace with a real implementation
RefPtr<File> result = File::CreateMemoryFileWithCustomLastModified(
aGlobal, static_cast<void*>(new uint8_t[1]), sizeof(uint8_t), aName,
@ -102,30 +109,40 @@ RefPtr<File> MakeGetFileResult(const nsString& aName, const nsString& aType,
}
void GetDirectoryContentsResponseHandler(
RefPtr<FileSystemActorHolder>& /* aActor */,
FileSystemDirectoryListing&& aResponse, nsIGlobalObject* aGlobal,
ArrayAppendable& /* aSink */) {
nsIGlobalObject* aGlobal, FileSystemDirectoryListing&& aResponse,
ArrayAppendable& /* aSink */, RefPtr<FileSystemActorHolder>& aActor) {
// TODO: Add page size to FileSystemConstants, preallocate and handle overflow
nsTArray<RefPtr<FileSystemHandle>> batch;
for (const auto& it : aResponse.files()) {
RefPtr<FileSystemHandle> handle = new FileSystemFileHandle(aGlobal, it);
RefPtr<FileSystemHandle> handle =
new FileSystemFileHandle(aGlobal, aActor, it);
batch.AppendElement(handle);
}
for (const auto& it : aResponse.directories()) {
RefPtr<FileSystemHandle> handle =
new FileSystemDirectoryHandle(aGlobal, it);
new FileSystemDirectoryHandle(aGlobal, aActor, it);
batch.AppendElement(handle);
}
}
RefPtr<FileSystemDirectoryHandle> MakeResolution(
nsIGlobalObject* aGlobal, FileSystemGetRootResponse&& aResponse,
const RefPtr<FileSystemDirectoryHandle>& /* aResolution */,
const Name& aName, RefPtr<FileSystemActorHolder>& aActor) {
RefPtr<FileSystemDirectoryHandle> result = new FileSystemDirectoryHandle(
aGlobal, aActor, FileSystemEntryMetadata(aResponse.get_EntryId(), aName));
return result;
}
RefPtr<FileSystemDirectoryHandle> MakeResolution(
nsIGlobalObject* aGlobal, FileSystemGetHandleResponse&& aResponse,
const RefPtr<FileSystemDirectoryHandle>& /* aResolution */,
const Name& aName, RefPtr<FileSystemActorHolder>& aActor) {
RefPtr<FileSystemDirectoryHandle> result = new FileSystemDirectoryHandle(
aGlobal, FileSystemEntryMetadata(aResponse.get_EntryId(), aName));
aGlobal, aActor, FileSystemEntryMetadata(aResponse.get_EntryId(), aName));
return result;
}
@ -134,7 +151,7 @@ RefPtr<FileSystemFileHandle> MakeResolution(
const RefPtr<FileSystemFileHandle>& /* aResolution */, const Name& aName,
RefPtr<FileSystemActorHolder>& aActor) {
RefPtr<FileSystemFileHandle> result = new FileSystemFileHandle(
aGlobal, FileSystemEntryMetadata(aResponse.get_EntryId(), aName));
aGlobal, aActor, FileSystemEntryMetadata(aResponse.get_EntryId(), aName));
return result;
}
@ -144,10 +161,10 @@ RefPtr<File> MakeResolution(nsIGlobalObject* aGlobal,
const Name& aName,
RefPtr<FileSystemActorHolder>& aActor) {
auto& fileProperties = aResponse.get_FileSystemFileProperties();
return MakeGetFileResult(aName, fileProperties.type(),
return MakeGetFileResult(aGlobal, aName, fileProperties.type(),
fileProperties.last_modified_ms(),
std::move(fileProperties.path()),
std::move(fileProperties.file()), aGlobal);
std::move(fileProperties.file()), aActor);
}
template <class TResponse, class... Args>
@ -204,10 +221,10 @@ void ResolveCallback(FileSystemGetEntriesResponse&& aResponse,
}
GetDirectoryContentsResponseHandler(
aActor,
aPromise->GetParentObject(),
std::forward<FileSystemDirectoryListing>(
aResponse.get_FileSystemDirectoryListing()),
aPromise->GetParentObject(), aSink);
aSink, aActor);
// TODO: Remove this when sink is ready
aPromise->MaybeReject(NS_ERROR_NOT_IMPLEMENTED);
@ -281,16 +298,26 @@ mozilla::ipc::RejectCallback GetRejectCallback(
void FileSystemRequestHandler::GetRoot(
RefPtr<Promise> aPromise) { // NOLINT(performance-unnecessary-value-param)
using mozilla::ipc::Endpoint;
MOZ_ASSERT(aPromise);
RefPtr<FileSystemActorHolder> dummyActor =
MakeAndAddRef<FileSystemActorHolder>();
// Create a new IPC connection
Endpoint<POriginPrivateFileSystemParent> parentEp;
Endpoint<POriginPrivateFileSystemChild> childEp;
MOZ_ALWAYS_SUCCEEDS(
POriginPrivateFileSystem::CreateEndpoints(&parentEp, &childEp));
Name name = kRootName;
auto&& onResolve = SelectResolveCallback<FileSystemGetHandleResponse,
RefPtr<FileSystemActorHolder> actor =
MakeAndAddRef<FileSystemActorHolder>(new OriginPrivateFileSystemChild());
if (!childEp.Bind(actor->Actor())) {
aPromise->MaybeRejectWithUndefined();
return;
}
auto&& onResolve = SelectResolveCallback<FileSystemGetRootResponse,
RefPtr<FileSystemDirectoryHandle>>(
aPromise, name, dummyActor);
aPromise, kRootName, actor);
auto&& onReject = GetRejectCallback(aPromise);
// XXX do something (register with global?) so that we can Close() the actor
@ -302,7 +329,8 @@ void FileSystemRequestHandler::GetRoot(
aPromise->MaybeRejectWithUnknownError("Could not access the file system");
return;
}
rootProvider->SendGetRoot(std::move(onResolve), std::move(onReject));
rootProvider->SendGetRoot(std::move(parentEp), std::move(onResolve),
std::move(onReject));
}
void FileSystemRequestHandler::GetDirectoryHandle(
@ -320,10 +348,9 @@ void FileSystemRequestHandler::GetDirectoryHandle(
auto&& onReject = GetRejectCallback(aPromise);
auto actor = GetRootProvider(aPromise->GetGlobalObject());
QM_TRY(OkIf(actor), QM_VOID);
actor->SendGetDirectoryHandle(request, std::move(onResolve),
std::move(onReject));
QM_TRY(OkIf(aActor), QM_VOID);
aActor->Actor()->SendGetDirectoryHandle(request, std::move(onResolve),
std::move(onReject));
}
void FileSystemRequestHandler::GetFileHandle(
@ -341,9 +368,9 @@ void FileSystemRequestHandler::GetFileHandle(
auto&& onReject = GetRejectCallback(aPromise);
auto actor = GetRootProvider(aPromise->GetGlobalObject());
QM_TRY(OkIf(actor), QM_VOID);
actor->SendGetFileHandle(request, std::move(onResolve), std::move(onReject));
QM_TRY(OkIf(aActor), QM_VOID);
aActor->Actor()->SendGetFileHandle(request, std::move(onResolve),
std::move(onReject));
}
void FileSystemRequestHandler::GetFile(
@ -360,9 +387,9 @@ void FileSystemRequestHandler::GetFile(
auto&& onReject = GetRejectCallback(aPromise);
auto actor = GetRootProvider(aPromise->GetGlobalObject());
QM_TRY(OkIf(actor), QM_VOID);
actor->SendGetFile(request, std::move(onResolve), std::move(onReject));
QM_TRY(OkIf(aActor), QM_VOID);
aActor->Actor()->SendGetFile(request, std::move(onResolve),
std::move(onReject));
}
void FileSystemRequestHandler::GetEntries(
@ -387,13 +414,13 @@ void FileSystemRequestHandler::GetEntries(
auto&& onReject = GetRejectCallback(aPromise);
auto actor = GetRootProvider(aPromise->GetGlobalObject());
QM_TRY(OkIf(actor), QM_VOID);
actor->SendGetEntries(request, std::move(onResolve), std::move(onReject));
QM_TRY(OkIf(aActor), QM_VOID);
aActor->Actor()->SendGetEntries(request, std::move(onResolve),
std::move(onReject));
}
void FileSystemRequestHandler::RemoveEntry(
RefPtr<FileSystemActorHolder>& /* aActor */,
RefPtr<FileSystemActorHolder>& aActor,
const FileSystemChildMetadata& aEntry, bool aRecursive,
RefPtr<Promise> aPromise) { // NOLINT(performance-unnecessary-value-param)
MOZ_ASSERT(!aEntry.parentId().IsEmpty());
@ -406,9 +433,9 @@ void FileSystemRequestHandler::RemoveEntry(
auto&& onReject = GetRejectCallback(aPromise);
auto actor = GetRootProvider(aPromise->GetGlobalObject());
QM_TRY(OkIf(actor), QM_VOID);
actor->SendRemoveEntry(request, std::move(onResolve), std::move(onReject));
QM_TRY(OkIf(aActor), QM_VOID);
aActor->Actor()->SendRemoveEntry(request, std::move(onResolve),
std::move(onReject));
}
} // namespace mozilla::dom::fs

View File

@ -0,0 +1,24 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef DOM_FS_CHILD_ORIGINPRIVATEFILESYSTEMCHILD_H_
#define DOM_FS_CHILD_ORIGINPRIVATEFILESYSTEMCHILD_H_
#include "mozilla/dom/POriginPrivateFileSystemChild.h"
#include "nsISupports.h"
namespace mozilla::dom {
class OriginPrivateFileSystemChild : public POriginPrivateFileSystemChild {
NS_INLINE_DECL_REFCOUNTING(OriginPrivateFileSystemChild);
protected:
virtual ~OriginPrivateFileSystemChild() = default;
};
} // namespace mozilla::dom
#endif // DOM_FS_CHILD_ORIGINPRIVATEFILESYSTEMCHILD_H_

View File

@ -6,6 +6,7 @@
EXPORTS.mozilla.dom += [
"BackgroundFileSystemChild.h",
"OriginPrivateFileSystemChild.h",
]
UNIFIED_SOURCES += [

View File

@ -8,6 +8,7 @@
#define DOM_FS_CHILD_FILESYSTEMREQUESTHANDLER_H_
#include "nsStringFwd.h"
#include "mozilla/dom/FileSystemActorHolder.h"
#include "mozilla/dom/FileSystemTypes.h"
#include "mozilla/dom/FileSystemHandle.h"
@ -16,13 +17,6 @@ class RefPtr;
namespace mozilla::dom {
// TODO: Replace this dummy class with real implementation
class FileSystemActorHolder {
NS_INLINE_DECL_REFCOUNTING(FileSystemActorHolder)
protected:
virtual ~FileSystemActorHolder() = default;
};
class FileSystemHandle;
class Promise;
class OriginPrivateFileSystemChild;

View File

@ -5,64 +5,110 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "BackgroundFileSystemParent.h"
#include "mozilla/dom/FileSystemTypes.h"
#include "OriginPrivateFileSystemParent.h"
using IPCResult = mozilla::ipc::IPCResult;
#include "nsNetCID.h"
#include "mozilla/dom/FileSystemTypes.h"
#include "mozilla/dom/quota/QuotaManager.h"
#include "mozilla/ipc/Endpoint.h"
#include "mozilla/ipc/FileDescriptorUtils.h"
#include "mozilla/Maybe.h"
#include "mozilla/MozPromise.h"
#include "mozilla/StaticPrefs_dom.h"
#include "nsServiceManagerUtils.h"
namespace mozilla {
LazyLogModule gOPFSLog("OPFS");
}
#define LOG(args) MOZ_LOG(mozilla::gOPFSLog, mozilla::LogLevel::Verbose, args)
#define LOG_DEBUG(args) \
MOZ_LOG(mozilla::gOPFSLog, mozilla::LogLevel::Debug, args)
namespace mozilla::dom {
IPCResult BackgroundFileSystemParent::RecvGetRoot(GetRootResolver&& aResolver) {
FileSystemGetHandleResponse response(NS_ERROR_NOT_IMPLEMENTED);
aResolver(response);
namespace fs::data {
return IPC_OK();
EntryId GetRootHandle(const Origin& aOrigin) { return "not implemented"_ns; }
// TODO: Replace with real FileSystemDataManager
class FileSystemDataManager : public FileSystemDataManagerBase {
public:
using result_t = Result<FileSystemDataManager*, nsresult>;
static FileSystemDataManager::result_t CreateFileSystemDataManager(
const fs::Origin& aOrigin);
};
FileSystemDataManager::result_t
FileSystemDataManager::CreateFileSystemDataManager(
const fs::Origin& /*aOrigin*/) {
return nullptr;
}
IPCResult BackgroundFileSystemParent::RecvGetDirectoryHandle(
FileSystemGetHandleRequest&& /* aRequest */,
GetDirectoryHandleResolver&& aResolver) {
FileSystemGetHandleResponse response(NS_ERROR_NOT_IMPLEMENTED);
aResolver(response);
} // namespace fs::data
return IPC_OK();
}
using RootPromise = MozPromise<fs::FileSystemGetRootResponse, nsresult, false>;
IPCResult BackgroundFileSystemParent::RecvGetFileHandle(
FileSystemGetHandleRequest&& aRequest, GetFileHandleResolver&& aResolver) {
FileSystemGetHandleResponse response(NS_ERROR_NOT_IMPLEMENTED);
aResolver(response);
mozilla::ipc::IPCResult BackgroundFileSystemParent::RecvGetRoot(
Endpoint<POriginPrivateFileSystemParent>&& aParentEp,
GetRootResolver&& aResolver) {
if (!StaticPrefs::dom_fs_enabled()) {
return IPC_FAIL(this, "OPFS is disabled");
}
if (!aParentEp.IsValid()) {
return IPC_FAIL(this, "Invalid endpoint");
}
return IPC_OK();
}
nsAutoCString origin =
quota::QuotaManager::GetOriginFromValidatedPrincipalInfo(mPrincipalInfo);
IPCResult BackgroundFileSystemParent::RecvGetFile(
FileSystemGetFileRequest&& aRequest, GetFileResolver&& aResolver) {
FileSystemGetFileResponse response(NS_ERROR_NOT_IMPLEMENTED);
aResolver(response);
// This opens the quota manager, which has to be done on PBackground
auto res =
fs::data::FileSystemDataManager::CreateFileSystemDataManager(origin);
if (NS_WARN_IF(res.isErr())) {
MOZ_ASSERT(false, "Can't create FileSystemDataManager");
aResolver(fs::FileSystemGetRootResponse(NS_ERROR_FAILURE));
return IPC_OK();
}
return IPC_OK();
}
nsCOMPtr<nsIThread> pbackground = NS_GetCurrentThread();
IPCResult BackgroundFileSystemParent::RecvResolve(
FileSystemResolveRequest&& aRequest, ResolveResolver&& aResolver) {
FileSystemResolveResponse response(NS_ERROR_NOT_IMPLEMENTED);
aResolver(response);
nsCOMPtr<nsIEventTarget> target =
do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID);
MOZ_ASSERT(target);
return IPC_OK();
}
nsCString name("OPFS ");
name += origin;
RefPtr<TaskQueue> taskqueue =
TaskQueue::Create(target.forget(), PromiseFlatCString(name).get());
// We'll have to thread-hop back to this thread to respond. We could
// just have the create be one-way, then send the actual request on the
// new channel, but that's an extra IPC instead.
InvokeAsync(
taskqueue, __func__,
[origin, parentEp = std::move(aParentEp), aResolver, data = res.unwrap(),
taskqueue, pbackground]() mutable {
RefPtr<OriginPrivateFileSystemParent> parent =
new OriginPrivateFileSystemParent(taskqueue);
if (!parentEp.Bind(parent)) {
auto response = fs::FileSystemGetRootResponse(NS_ERROR_FAILURE);
return RootPromise::CreateAndReject(response, __func__);
}
IPCResult BackgroundFileSystemParent::RecvGetEntries(
FileSystemGetEntriesRequest&& aRequest, GetEntriesResolver&& aResolver) {
FileSystemGetEntriesResponse response(NS_ERROR_NOT_IMPLEMENTED);
aResolver(response);
return IPC_OK();
}
IPCResult BackgroundFileSystemParent::RecvRemoveEntry(
FileSystemRemoveEntryRequest&& aRequest, RemoveEntryResolver&& aResolver) {
FileSystemRemoveEntryResponse response(NS_ERROR_NOT_IMPLEMENTED);
aResolver(response);
// Send response back to pbackground to send to child
auto response =
fs::FileSystemGetRootResponse(fs::data::GetRootHandle(origin));
return RootPromise::CreateAndResolve(response, __func__);
})
->Then(GetCurrentSerialEventTarget(), __func__,
[aResolver](const RootPromise::ResolveOrRejectValue& aValue) {
if (aValue.IsReject()) {
aResolver(aValue.RejectValue());
} else {
aResolver(aValue.ResolveValue());
}
});
return IPC_OK();
}

View File

@ -10,7 +10,8 @@
#include "mozilla/ipc/BackgroundUtils.h"
#include "mozilla/dom/PBackgroundFileSystemParent.h"
#include "mozilla/ipc/PBackgroundSharedTypes.h"
#include "mozilla/ipc/ProtocolUtils.h"
#include "mozilla/dom/POriginPrivateFileSystemParent.h"
#include "mozilla/TaskQueue.h"
#include "nsISupports.h"
namespace mozilla::dom {
@ -21,26 +22,9 @@ class BackgroundFileSystemParent : public PBackgroundFileSystemParent {
const mozilla::ipc::PrincipalInfo& aPrincipalInfo)
: mPrincipalInfo(aPrincipalInfo) {}
mozilla::ipc::IPCResult RecvGetRoot(GetRootResolver&& aResolver);
mozilla::ipc::IPCResult RecvGetDirectoryHandle(
FileSystemGetHandleRequest&& aRequest,
GetDirectoryHandleResolver&& aResolver);
mozilla::ipc::IPCResult RecvGetFileHandle(
FileSystemGetHandleRequest&& aRequest, GetFileHandleResolver&& aResolver);
mozilla::ipc::IPCResult RecvGetFile(FileSystemGetFileRequest&& aRequest,
GetFileResolver&& aResolver);
mozilla::ipc::IPCResult RecvResolve(FileSystemResolveRequest&& aRequest,
ResolveResolver&& aResolver);
mozilla::ipc::IPCResult RecvGetEntries(FileSystemGetEntriesRequest&& aRequest,
GetEntriesResolver&& aResolver);
mozilla::ipc::IPCResult RecvRemoveEntry(
FileSystemRemoveEntryRequest&& aRequest, RemoveEntryResolver&& aResolver);
mozilla::ipc::IPCResult RecvGetRoot(
Endpoint<POriginPrivateFileSystemParent>&& aParentEp,
GetRootResolver&& aResolver);
NS_INLINE_DECL_REFCOUNTING(BackgroundFileSystemParent)

View File

@ -0,0 +1,111 @@
/* -*- 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 "OriginPrivateFileSystemParent.h"
#include "nsNetCID.h"
#include "mozilla/dom/FileSystemTypes.h"
#include "mozilla/ipc/Endpoint.h"
using IPCResult = mozilla::ipc::IPCResult;
namespace mozilla {
extern LazyLogModule gOPFSLog;
}
#define LOG(args) MOZ_LOG(mozilla::gOPFSLog, mozilla::LogLevel::Verbose, args)
#define LOG_DEBUG(args) \
MOZ_LOG(mozilla::gOPFSLog, mozilla::LogLevel::Debug, args)
namespace mozilla::dom {
IPCResult OriginPrivateFileSystemParent::RecvGetDirectoryHandle(
FileSystemGetHandleRequest&& /* aRequest */,
GetDirectoryHandleResolver&& aResolver) {
FileSystemGetHandleResponse response(NS_ERROR_NOT_IMPLEMENTED);
aResolver(response);
return IPC_OK();
}
IPCResult OriginPrivateFileSystemParent::RecvGetFileHandle(
FileSystemGetHandleRequest&& aRequest, GetFileHandleResolver&& aResolver) {
FileSystemGetHandleResponse response(NS_ERROR_NOT_IMPLEMENTED);
aResolver(response);
return IPC_OK();
}
IPCResult OriginPrivateFileSystemParent::RecvGetFile(
FileSystemGetFileRequest&& aRequest, GetFileResolver&& aResolver) {
FileSystemGetFileResponse response(NS_ERROR_NOT_IMPLEMENTED);
aResolver(response);
return IPC_OK();
}
IPCResult OriginPrivateFileSystemParent::RecvResolve(
FileSystemResolveRequest&& aRequest, ResolveResolver&& aResolver) {
FileSystemResolveResponse response(NS_ERROR_NOT_IMPLEMENTED);
aResolver(response);
return IPC_OK();
}
IPCResult OriginPrivateFileSystemParent::RecvGetEntries(
FileSystemGetEntriesRequest&& aRequest, GetEntriesResolver&& aResolver) {
FileSystemGetEntriesResponse response(NS_ERROR_NOT_IMPLEMENTED);
aResolver(response);
return IPC_OK();
}
IPCResult OriginPrivateFileSystemParent::RecvRemoveEntry(
FileSystemRemoveEntryRequest&& aRequest, RemoveEntryResolver&& aResolver) {
FileSystemRemoveEntryResponse response(NS_ERROR_NOT_IMPLEMENTED);
aResolver(response);
return IPC_OK();
}
IPCResult OriginPrivateFileSystemParent::RecvCloseFile(
FileSystemGetFileRequest&& aRequest) {
LOG(("Closing file")); // painful to print out the id
return IPC_OK();
}
IPCResult OriginPrivateFileSystemParent::RecvGetAccessHandle(
FileSystemGetFileRequest&& aRequest, GetAccessHandleResolver&& aResolver) {
FileSystemGetAccessHandleResponse response(NS_ERROR_NOT_IMPLEMENTED);
aResolver(response);
return IPC_OK();
}
IPCResult OriginPrivateFileSystemParent::RecvGetWritable(
FileSystemGetFileRequest&& aRequest, GetWritableResolver&& aResolver) {
FileSystemGetAccessHandleResponse response(NS_ERROR_NOT_IMPLEMENTED);
aResolver(response);
return IPC_OK();
}
IPCResult OriginPrivateFileSystemParent::RecvNeedQuota(
FileSystemQuotaRequest&& aRequest, NeedQuotaResolver&& aResolver) {
aResolver(0u);
return IPC_OK();
}
OriginPrivateFileSystemParent::~OriginPrivateFileSystemParent() {
LOG(("Destroying OPFS Parent %p", this));
if (mTaskQueue) {
mTaskQueue->BeginShutdown();
}
}
} // namespace mozilla::dom

View File

@ -0,0 +1,80 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef DOM_FS_PARENT_ORIGINPRIVATEFILESYSTEMPARENT_H_
#define DOM_FS_PARENT_ORIGINPRIVATEFILESYSTEMPARENT_H_
#include "ErrorList.h"
#include "mozilla/dom/PBackgroundFileSystemParent.h"
#include "mozilla/dom/POriginPrivateFileSystemParent.h"
#include "mozilla/TaskQueue.h"
#include "nsISupports.h"
namespace mozilla {
extern LazyLogModule gOPFSLog;
}
#define LOG(args) MOZ_LOG(mozilla::gOPFSLog, mozilla::LogLevel::Verbose, args)
#define LOG_DEBUG(args) \
MOZ_LOG(mozilla::gOPFSLog, mozilla::LogLevel::Debug, args)
namespace mozilla::dom {
namespace fs::data {
// TODO: Replace dummy with real FileSystemDataManager
class FileSystemDataManagerBase {};
} // namespace fs::data
class OriginPrivateFileSystemParent : public POriginPrivateFileSystemParent {
public:
explicit OriginPrivateFileSystemParent(TaskQueue* aTaskQueue)
: mTaskQueue(aTaskQueue), mData() {}
mozilla::ipc::IPCResult RecvGetDirectoryHandle(
FileSystemGetHandleRequest&& aRequest,
GetDirectoryHandleResolver&& aResolver);
mozilla::ipc::IPCResult RecvGetFileHandle(
FileSystemGetHandleRequest&& aRequest, GetFileHandleResolver&& aResolver);
mozilla::ipc::IPCResult RecvGetFile(FileSystemGetFileRequest&& aRequest,
GetFileResolver&& aResolver);
mozilla::ipc::IPCResult RecvResolve(FileSystemResolveRequest&& aRequest,
ResolveResolver&& aResolver);
mozilla::ipc::IPCResult RecvGetEntries(FileSystemGetEntriesRequest&& aRequest,
GetEntriesResolver&& aResolver);
mozilla::ipc::IPCResult RecvRemoveEntry(
FileSystemRemoveEntryRequest&& aRequest, RemoveEntryResolver&& aResolver);
mozilla::ipc::IPCResult RecvCloseFile(FileSystemGetFileRequest&& aRequest);
mozilla::ipc::IPCResult RecvGetAccessHandle(
FileSystemGetFileRequest&& aRequest, GetAccessHandleResolver&& aResolver);
mozilla::ipc::IPCResult RecvGetWritable(FileSystemGetFileRequest&& aRequest,
GetWritableResolver&& aResolver);
mozilla::ipc::IPCResult RecvNeedQuota(FileSystemQuotaRequest&& aRequest,
NeedQuotaResolver&& aResolver);
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(OriginPrivateFileSystemParent)
protected:
virtual ~OriginPrivateFileSystemParent();
private:
RefPtr<TaskQueue> mTaskQueue;
UniquePtr<fs::data::FileSystemDataManagerBase> mData;
};
} // namespace mozilla::dom
#endif // DOM_FS_PARENT_ORIGINPRIVATEFILESYSTEMPARENT_H_

View File

@ -6,10 +6,12 @@
EXPORTS.mozilla.dom += [
"BackgroundFileSystemParent.h",
"OriginPrivateFileSystemParent.h",
]
UNIFIED_SOURCES += [
"BackgroundFileSystemParent.cpp",
"OriginPrivateFileSystemParent.cpp",
]
FINAL_LIBRARY = "xul"

View File

@ -0,0 +1,15 @@
/* -*- 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 "mozilla/dom/OriginPrivateFileSystemChild.h"
#include "mozilla/ipc/ActorHolder.h"
namespace mozilla::dom {
using FileSystemActorHolder =
mozilla::ipc::TopLevelActorHolder<OriginPrivateFileSystemChild>;
} // namespace mozilla::dom

View File

@ -21,6 +21,7 @@ using Origin = nsCString;
using PageNumber = uint32_t;
using Path = nsTArray<Name>;
using TimeStamp = int64_t;
using Usage = int64_t;
} // namespace mozilla::dom::fs

View File

@ -3,170 +3,22 @@
* You can obtain one at http://mozilla.org/MPL/2.0/. */
include protocol PBackground;
include protocol POriginPrivateFileSystem;
using mozilla::dom::fs::ContentType from "mozilla/dom/FileSystemTypes.h";
using mozilla::dom::fs::EntryId from "mozilla/dom/FileSystemTypes.h";
using mozilla::dom::fs::Name from "mozilla/dom/FileSystemTypes.h";
using mozilla::dom::fs::PageNumber from "mozilla/dom/FileSystemTypes.h";
using mozilla::dom::fs::TimeStamp from "mozilla/dom/FileSystemTypes.h";
using struct mozilla::void_t from "mozilla/ipc/IPCCore.h";
namespace mozilla {
namespace dom {
namespace fs {
/**
* Identifies a file or a directory and contains its user provided name.
*/
struct FileSystemEntryMetadata
{
EntryId entryId;
Name entryName;
};
/**
* Identifies a file or a directory with its parent identifier and user provided name.
*/
struct FileSystemChildMetadata
{
EntryId parentId;
Name childName;
};
/**
* Identifies a file with its parent directory and name, and
* indicates whether the file may be created if it is missing.
*/
struct FileSystemGetHandleRequest
{
FileSystemChildMetadata handle;
bool create;
};
/**
* Contains a file or directory or an error.
*/
union FileSystemGetHandleResponse
union FileSystemGetRootResponse
{
nsresult;
EntryId;
};
/**
* Contains an identifier for a parent directory and a page number
* which is used to fetch the next set of entries when the directory
* contains so many items that communicating all of them in one message
* is an impractical.
*/
struct FileSystemGetEntriesRequest
{
EntryId parentId;
PageNumber page;
};
/**
* Contains a set of directories and files
* under the same parent directory.
*/
struct FileSystemDirectoryListing
{
FileSystemEntryMetadata[] directories;
FileSystemEntryMetadata[] files;
};
/**
* Contains a set of entries or an error.
*/
union FileSystemGetEntriesResponse
{
nsresult;
FileSystemDirectoryListing;
};
/**
* Contains entry handle information.
*/
struct FileSystemGetFileRequest
{
EntryId entryId;
};
/**
* Contains the properties of a file and a file descriptor.
* The properties may differ from the properties of the
* underlying object of the file descriptor.
*/
struct FileSystemFileProperties
{
TimeStamp last_modified_ms;
FileDescriptor file;
ContentType type;
Name[] path;
};
/**
* Contains file properties or an error.
*/
union FileSystemGetFileResponse
{
nsresult;
FileSystemFileProperties;
};
/**
* Represents a pair of file system entries which
* are not necessarily connected by a path.
*/
struct FileSystemEntryPair
{
EntryId parentId;
EntryId childId;
};
/**
* Contains a pair of file system entries.
*/
struct FileSystemResolveRequest
{
FileSystemEntryPair endpoints;
};
/**
* Contains a file system path.
*/
struct FileSystemPath
{
Name[] path;
};
/**
* Contains a potentially empty path or an error.
*/
union FileSystemResolveResponse
{
nsresult;
FileSystemPath?;
};
/**
* Identifies a file with its parent directory and name, and
* indicates whether all the children of a directory may be removed.
*/
struct FileSystemRemoveEntryRequest
{
FileSystemChildMetadata handle;
bool recursive;
};
/**
* Contains an error or nothing.
*/
union FileSystemRemoveEntryResponse
{
nsresult;
void_t;
};
} // namespace fs
async protocol PBackgroundFileSystem
@ -176,115 +28,12 @@ async protocol PBackgroundFileSystem
parent:
/**
* Initiates an asynchronous request for the directory handle of
* the file system's root level. On first call, may conduct initialization
* activities.
*
* @returns error or entry handle
* This will set up a POriginPrivateFileSystem IPC connection
*/
async GetRoot() returns(FileSystemGetHandleResponse handle);
/**
* Initiates an asynchronous request for the handle of
* a subdirectory with a given name under the current directory.
*
* Invalid names are rejected with an appropriate error.
*
* If the subdirectory exists, a handle to it is always returned.
*
* If no child of any kind with the given name exists and
* the create-flag of the input is set, the subdirectory will be created,
* otherwise an appropriate error is returned.
*
* @param[in] handle request containing a create flag
*
* @returns error or entry handle
*/
async GetDirectoryHandle(FileSystemGetHandleRequest request) returns(FileSystemGetHandleResponse handle);
/**
* Initiates an asynchronous request for the handle to
* a file with a given name under the current directory.
*
* Invalid names are rejected with an appropriate error.
*
* If the file exists, a handle to it is always returned.
*
* If no child of any kind with the given name exists and
* the create-flag of the input is set, the file will be created,
* otherwise an appropriate error is returned.
*
* @param[in] handle request containing a create flag
*
* @returns error or entry handle
*/
async GetFileHandle(FileSystemGetHandleRequest request) returns(FileSystemGetHandleResponse handle);
/**
* Initiates an asynchronous request for a read-only object representing the
* file corresponding to the current file handle.
*
* The returned object provides read-only access.
*
* If the underlying file object is modified through a mutable interface,
* the returned value is considered stale. Concurrent changes are not
* guaranteed to be visible or invisible. Using a stale object
* returns appropriate errors when the results are unpredictable.
*
* @param[in] request for a file object
*
* @returns error or file object
*/
async GetFile(FileSystemGetFileRequest request) returns(FileSystemGetFileResponse response);
/**
* Initiates an asynchronous request for the file system path
* associated with a file system entry.
*
* @param[in] request identifying a file object
*
* @returns error or file system path
*/
async Resolve(FileSystemResolveRequest request) returns(FileSystemResolveResponse response);
/**
* Initiates an asynchronous request for an iterator to the child entries under
* the current directory handle.
*
* If the directory item names or the directory structure is modified while the iterator
* is in use, the iterator remains safe to use but no guarantees are made regarding
* the visibility of the concurrent changes. It is possible that a file which is added after
* the iteration has begun will not be returned, or that among the values there
* are invalid file handles whose underlying objects have been removed
* after the iteration started.
*
* @param[in] request for a iterator
*
* @returns error or iterator
*/
async GetEntries(FileSystemGetEntriesRequest request) returns(FileSystemGetEntriesResponse entries);
/**
* Initiates an asynchronous request to delete a directory or file with a given name
* under the current directory handle.
*
* If recursive flag of the request is not set, a request to remove a non-empty
* directory returns an appropriate error, otherwise all the child files and
* directories are made to vanish.
*
* The recursive flag has no impact on files.
*
* @param[in] request containing a recursive flag
*
* @returns error information
*/
async RemoveEntry(FileSystemRemoveEntryRequest request) returns(FileSystemRemoveEntryResponse response);
async GetRoot(Endpoint<POriginPrivateFileSystemParent> aParentEP) returns(FileSystemGetRootResponse handle);
child:
/**
* Mandatory IPC managed lifecycle request.
*/
async __delete__();
};

View File

@ -0,0 +1,321 @@
/* 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 IPCBlob;
using mozilla::dom::fs::ContentType from "mozilla/dom/FileSystemTypes.h";
using mozilla::dom::fs::EntryId from "mozilla/dom/FileSystemTypes.h";
using mozilla::dom::fs::Name from "mozilla/dom/FileSystemTypes.h";
using mozilla::dom::fs::Origin from "mozilla/dom/FileSystemTypes.h";
using mozilla::dom::fs::PageNumber from "mozilla/dom/FileSystemTypes.h";
using mozilla::dom::fs::TimeStamp from "mozilla/dom/FileSystemTypes.h";
using struct mozilla::void_t from "mozilla/ipc/IPCCore.h";
namespace mozilla {
namespace dom {
namespace fs {
/**
* Identifies a file or a directory and contains its user provided name.
*/
struct FileSystemEntryMetadata
{
EntryId entryId;
Name entryName;
};
/**
* Identifies a file or a directory with its parent identifier and user provided name.
*/
struct FileSystemChildMetadata
{
EntryId parentId;
Name childName;
};
/**
* Identifies a file with its parent directory and name, and
* indicates whether the file may be created if it is missing.
*/
struct FileSystemGetHandleRequest
{
FileSystemChildMetadata handle;
bool create;
};
/**
* Contains a file or directory or an error.
*/
union FileSystemGetHandleResponse
{
nsresult;
EntryId;
};
/**
* Contains an identifier for a parent directory and a page number
* which is used to fetch the next set of entries when the directory
* contains so many items that communicating all of them in one message
* is an impractical.
*/
struct FileSystemGetEntriesRequest
{
EntryId parentId;
PageNumber page;
};
/**
* Contains a set of directories and files
* under the same parent directory.
*/
struct FileSystemDirectoryListing
{
FileSystemEntryMetadata[] directories;
FileSystemEntryMetadata[] files;
};
/**
* Contains a set of entries or an error.
*/
union FileSystemGetEntriesResponse
{
nsresult;
FileSystemDirectoryListing;
};
/**
* Contains entry handle information.
*/
struct FileSystemGetFileRequest
{
EntryId entryId;
};
/**
* Contains the properties of a file and a file descriptor.
* The properties may differ from the properties of the
* underlying object of the file descriptor.
*/
struct FileSystemFileProperties
{
TimeStamp last_modified_ms;
IPCBlob file;
ContentType type;
Name[] path;
};
/**
* Contains file properties or an error.
*/
union FileSystemGetFileResponse
{
nsresult;
FileSystemFileProperties;
};
struct FileSystemGetAccessHandleData
{
FileDescriptor file;
};
union FileSystemGetAccessHandleResponse
{
FileSystemGetAccessHandleData;
nsresult;
};
/**
* Represents a pair of file system entries which
* are not necessarily connected by a path.
*/
struct FileSystemEntryPair
{
EntryId parentId;
EntryId childId;
};
/**
* Contains a pair of file system entries.
*/
struct FileSystemResolveRequest
{
FileSystemEntryPair endpoints;
};
/**
* Contains a file system path.
*/
struct FileSystemPath
{
Name[] path;
};
/**
* Contains a potentially empty path or an error.
*/
union FileSystemResolveResponse
{
nsresult;
FileSystemPath?;
};
/**
* Identifies a file with its parent directory and name, and
* indicates whether all the children of a directory may be removed.
*/
struct FileSystemRemoveEntryRequest
{
FileSystemChildMetadata handle;
bool recursive;
};
/**
* Contains an error or nothing.
*/
union FileSystemRemoveEntryResponse
{
nsresult;
void_t;
};
struct FileSystemQuotaRequest
{
FileSystemChildMetadata handle;
uint64_t quotaNeeded;
};
} // namespace fs
async protocol POriginPrivateFileSystem
{
parent:
/**
* Initiates an asynchronous request for the handle of
* a subdirectory with a given name under the current directory.
*
* Invalid names are rejected with an appropriate error.
*
* If the subdirectory exists, a handle to it is always returned.
*
* If no child of any kind with the given name exists and
* the create-flag of the input is set, the subdirectory will be created,
* otherwise an appropriate error is returned.
*
* @param[in] handle request containing a create flag
*
* @returns error or entry handle
*/
async GetDirectoryHandle(FileSystemGetHandleRequest request) returns(FileSystemGetHandleResponse handle);
/**
* Initiates an asynchronous request for the handle to
* a file with a given name under the current directory.
*
* Invalid names are rejected with an appropriate error.
*
* If the file exists, a handle to it is always returned.
*
* If no child of any kind with the given name exists and
* the create-flag of the input is set, the file will be created,
* otherwise an appropriate error is returned.
*
* @param[in] handle request containing a create flag
*
* @returns error or entry handle
*/
async GetFileHandle(FileSystemGetHandleRequest request) returns(FileSystemGetHandleResponse handle);
/**
* Initiates an asynchronous request for a read-only object representing the
* file corresponding to the current file handle.
*
* The returned object provides read-only access.
*
* If the underlying file object is modified through a mutable interface,
* the returned value is considered stale. Concurrent changes are not
* guaranteed to be visible or invisible. Using a stale object
* returns appropriate errors when the results are unpredictable.
*
* @param[in] request for a file object
*
* @returns error or file object
*/
async GetFile(FileSystemGetFileRequest request) returns(FileSystemGetFileResponse response);
/**
* TODO: documentation
*/
async GetAccessHandle(FileSystemGetFileRequest request) returns(FileSystemGetAccessHandleResponse fileData);
/**
* TODO: documentation
*/
async GetWritable(FileSystemGetFileRequest request) returns(FileSystemGetAccessHandleResponse fileData);
/**
* Initiates an asynchronous request for the file system path
* associated with a file system entry.
*
* @param[in] request identifying a file object
*
* @returns error or file system path
*/
async Resolve(FileSystemResolveRequest request) returns(FileSystemResolveResponse response);
/**
* Initiates an asynchronous request for an iterator to the child entries under
* the current directory handle.
*
* If the directory item names or the directory structure is modified while the iterator
* is in use, the iterator remains safe to use but no guarantees are made regarding
* the visibility of the concurrent changes. It is possible that a file which is added after
* the iteration has begun will not be returned, or that among the values there
* are invalid file handles whose underlying objects have been removed
* after the iteration started.
*
* @param[in] request for a iterator
*
* @returns error or iterator
*/
async GetEntries(FileSystemGetEntriesRequest request) returns(FileSystemGetEntriesResponse entries);
/**
* Initiates an asynchronous request to delete a directory or file with a given name
* under the current directory handle.
*
* If recursive flag of the request is not set, a request to remove a non-empty
* directory returns an appropriate error, otherwise all the child files and
* directories are made to vanish.
*
* The recursive flag has no impact on files.
*
* @param[in] request containing a recursive flag
*
* @returns error information
*/
async RemoveEntry(FileSystemRemoveEntryRequest request) returns(FileSystemRemoveEntryResponse response);
/**
* TODO: documentation
* So we can implement exclusive access
*/
async CloseFile(FileSystemGetFileRequest request);
/**
* Request for quota needed to finish a write, beyond the amount preallocated at creation of the AccessHandle.
* While officially async, this is used in a sync manner from write() by spinning an event loop.
*/
async NeedQuota(FileSystemQuotaRequest aRequest) returns (uint64_t aQuotaGranted);
child:
/**
* Mandatory IPC managed lifecycle request.
*/
async __delete__();
};
} // namespace dom
} // namespace mozilla

View File

@ -5,6 +5,7 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
EXPORTS.mozilla.dom += [
"FileSystemActorHolder.h",
"FileSystemTypes.h",
]
@ -12,6 +13,7 @@ FINAL_LIBRARY = "xul"
IPDL_SOURCES += [
"PBackgroundFileSystem.ipdl",
"POriginPrivateFileSystem.ipdl",
]
include("/ipc/chromium/chromium-config.mozbuild")

View File

@ -13,6 +13,7 @@
#include "mozilla/dom/FileSystemDirectoryIterator.h"
#include "mozilla/dom/FileSystemHandle.h"
#include "mozilla/dom/FileSystemHandleBinding.h"
#include "mozilla/dom/OriginPrivateFileSystemChild.h"
#include "mozilla/UniquePtr.h"
#include "nsIGlobalObject.h"
@ -25,24 +26,26 @@ class TestFileSystemDirectoryHandle : public ::testing::Test {
mRequestHandler = MakeUnique<MockFileSystemRequestHandler>();
mMetadata = FileSystemEntryMetadata("dir"_ns, u"Directory"_ns);
mName = u"testDir"_ns;
mActor = MakeAndAddRef<FileSystemActorHolder>(nullptr);
}
nsIGlobalObject* mGlobal = GetGlobal();
UniquePtr<MockFileSystemRequestHandler> mRequestHandler;
FileSystemEntryMetadata mMetadata;
nsString mName;
RefPtr<FileSystemActorHolder> mActor;
};
TEST_F(TestFileSystemDirectoryHandle, constructDirectoryHandleRefPointer) {
RefPtr<FileSystemDirectoryHandle> dirHandle =
MakeAndAddRef<FileSystemDirectoryHandle>(mGlobal, mMetadata);
MakeAndAddRef<FileSystemDirectoryHandle>(mGlobal, mActor, mMetadata);
ASSERT_TRUE(dirHandle);
}
TEST_F(TestFileSystemDirectoryHandle, areEntriesReturned) {
RefPtr<FileSystemDirectoryHandle> dirHandle =
MakeAndAddRef<FileSystemDirectoryHandle>(mGlobal, mMetadata,
MakeAndAddRef<FileSystemDirectoryHandle>(mGlobal, mActor, mMetadata,
mRequestHandler.release());
ASSERT_TRUE(dirHandle);
@ -53,7 +56,7 @@ TEST_F(TestFileSystemDirectoryHandle, areEntriesReturned) {
TEST_F(TestFileSystemDirectoryHandle, areKeysReturned) {
RefPtr<FileSystemDirectoryHandle> dirHandle =
MakeAndAddRef<FileSystemDirectoryHandle>(mGlobal, mMetadata,
MakeAndAddRef<FileSystemDirectoryHandle>(mGlobal, mActor, mMetadata,
mRequestHandler.release());
ASSERT_TRUE(dirHandle);
@ -64,7 +67,7 @@ TEST_F(TestFileSystemDirectoryHandle, areKeysReturned) {
TEST_F(TestFileSystemDirectoryHandle, areValuesReturned) {
RefPtr<FileSystemDirectoryHandle> dirHandle =
MakeAndAddRef<FileSystemDirectoryHandle>(mGlobal, mMetadata,
MakeAndAddRef<FileSystemDirectoryHandle>(mGlobal, mActor, mMetadata,
mRequestHandler.release());
ASSERT_TRUE(dirHandle);
@ -75,7 +78,7 @@ TEST_F(TestFileSystemDirectoryHandle, areValuesReturned) {
TEST_F(TestFileSystemDirectoryHandle, isHandleKindDirectory) {
RefPtr<FileSystemDirectoryHandle> dirHandle =
MakeAndAddRef<FileSystemDirectoryHandle>(mGlobal, mMetadata,
MakeAndAddRef<FileSystemDirectoryHandle>(mGlobal, mActor, mMetadata,
mRequestHandler.release());
ASSERT_TRUE(dirHandle);
@ -85,7 +88,7 @@ TEST_F(TestFileSystemDirectoryHandle, isHandleKindDirectory) {
TEST_F(TestFileSystemDirectoryHandle, isFileHandleReturned) {
RefPtr<FileSystemDirectoryHandle> dirHandle =
MakeAndAddRef<FileSystemDirectoryHandle>(mGlobal, mMetadata,
MakeAndAddRef<FileSystemDirectoryHandle>(mGlobal, mActor, mMetadata,
mRequestHandler.release());
ASSERT_TRUE(dirHandle);
@ -100,7 +103,7 @@ TEST_F(TestFileSystemDirectoryHandle, isFileHandleReturned) {
TEST_F(TestFileSystemDirectoryHandle, doesGetFileHandleFailOnNullGlobal) {
mGlobal = nullptr;
RefPtr<FileSystemDirectoryHandle> dirHandle =
MakeAndAddRef<FileSystemDirectoryHandle>(mGlobal, mMetadata);
MakeAndAddRef<FileSystemDirectoryHandle>(mGlobal, mActor, mMetadata);
ASSERT_TRUE(dirHandle);
@ -113,7 +116,7 @@ TEST_F(TestFileSystemDirectoryHandle, doesGetFileHandleFailOnNullGlobal) {
TEST_F(TestFileSystemDirectoryHandle, isDirectoryHandleReturned) {
RefPtr<FileSystemDirectoryHandle> dirHandle =
MakeAndAddRef<FileSystemDirectoryHandle>(mGlobal, mMetadata,
MakeAndAddRef<FileSystemDirectoryHandle>(mGlobal, mActor, mMetadata,
mRequestHandler.release());
ASSERT_TRUE(dirHandle);
@ -128,7 +131,7 @@ TEST_F(TestFileSystemDirectoryHandle, isDirectoryHandleReturned) {
TEST_F(TestFileSystemDirectoryHandle, doesGetDirectoryHandleFailOnNullGlobal) {
mGlobal = nullptr;
RefPtr<FileSystemDirectoryHandle> dirHandle =
MakeAndAddRef<FileSystemDirectoryHandle>(mGlobal, mMetadata);
MakeAndAddRef<FileSystemDirectoryHandle>(mGlobal, mActor, mMetadata);
ASSERT_TRUE(dirHandle);
@ -141,7 +144,7 @@ TEST_F(TestFileSystemDirectoryHandle, doesGetDirectoryHandleFailOnNullGlobal) {
TEST_F(TestFileSystemDirectoryHandle, isRemoveEntrySuccessful) {
RefPtr<FileSystemDirectoryHandle> dirHandle =
MakeAndAddRef<FileSystemDirectoryHandle>(mGlobal, mMetadata,
MakeAndAddRef<FileSystemDirectoryHandle>(mGlobal, mActor, mMetadata,
mRequestHandler.release());
ASSERT_TRUE(dirHandle);
@ -156,7 +159,7 @@ TEST_F(TestFileSystemDirectoryHandle, isRemoveEntrySuccessful) {
TEST_F(TestFileSystemDirectoryHandle, doesRemoveEntryFailOnNullGlobal) {
mGlobal = nullptr;
RefPtr<FileSystemDirectoryHandle> dirHandle =
MakeAndAddRef<FileSystemDirectoryHandle>(mGlobal, mMetadata);
MakeAndAddRef<FileSystemDirectoryHandle>(mGlobal, mActor, mMetadata);
ASSERT_TRUE(dirHandle);
@ -169,7 +172,7 @@ TEST_F(TestFileSystemDirectoryHandle, doesRemoveEntryFailOnNullGlobal) {
TEST_F(TestFileSystemDirectoryHandle, isResolveSuccessful) {
RefPtr<FileSystemDirectoryHandle> dirHandle =
MakeAndAddRef<FileSystemDirectoryHandle>(mGlobal, mMetadata,
MakeAndAddRef<FileSystemDirectoryHandle>(mGlobal, mActor, mMetadata,
mRequestHandler.release());
ASSERT_TRUE(dirHandle);
@ -183,7 +186,7 @@ TEST_F(TestFileSystemDirectoryHandle, isResolveSuccessful) {
TEST_F(TestFileSystemDirectoryHandle, doesResolveFailOnNullGlobal) {
mGlobal = nullptr;
RefPtr<FileSystemDirectoryHandle> dirHandle =
MakeAndAddRef<FileSystemDirectoryHandle>(mGlobal, mMetadata);
MakeAndAddRef<FileSystemDirectoryHandle>(mGlobal, mActor, mMetadata);
ASSERT_TRUE(dirHandle);

View File

@ -24,23 +24,25 @@ class TestFileSystemFileHandle : public ::testing::Test {
void SetUp() override {
mRequestHandler = MakeUnique<MockFileSystemRequestHandler>();
mMetadata = FileSystemEntryMetadata("file"_ns, u"File"_ns);
mActor = MakeAndAddRef<FileSystemActorHolder>(nullptr);
}
nsIGlobalObject* mGlobal = GetGlobal();
UniquePtr<MockFileSystemRequestHandler> mRequestHandler;
FileSystemEntryMetadata mMetadata;
RefPtr<FileSystemActorHolder> mActor;
};
TEST_F(TestFileSystemFileHandle, constructFileHandleRefPointer) {
RefPtr<FileSystemFileHandle> fileHandle = MakeAndAddRef<FileSystemFileHandle>(
mGlobal, mMetadata, mRequestHandler.release());
mGlobal, mActor, mMetadata, mRequestHandler.release());
ASSERT_TRUE(fileHandle);
}
TEST_F(TestFileSystemFileHandle, isHandleKindFile) {
RefPtr<FileSystemFileHandle> fileHandle = MakeAndAddRef<FileSystemFileHandle>(
mGlobal, mMetadata, mRequestHandler.release());
mGlobal, mActor, mMetadata, mRequestHandler.release());
ASSERT_TRUE(fileHandle);
@ -49,7 +51,7 @@ TEST_F(TestFileSystemFileHandle, isHandleKindFile) {
TEST_F(TestFileSystemFileHandle, isFileReturned) {
RefPtr<FileSystemFileHandle> fileHandle = MakeAndAddRef<FileSystemFileHandle>(
mGlobal, mMetadata, mRequestHandler.release());
mGlobal, mActor, mMetadata, mRequestHandler.release());
ASSERT_TRUE(fileHandle);
@ -62,7 +64,7 @@ TEST_F(TestFileSystemFileHandle, isFileReturned) {
TEST_F(TestFileSystemFileHandle, doesGetFileFailOnNullGlobal) {
mGlobal = nullptr;
RefPtr<FileSystemFileHandle> fileHandle = MakeAndAddRef<FileSystemFileHandle>(
mGlobal, mMetadata, mRequestHandler.release());
mGlobal, mActor, mMetadata, mRequestHandler.release());
ASSERT_TRUE(fileHandle);
@ -74,7 +76,7 @@ TEST_F(TestFileSystemFileHandle, doesGetFileFailOnNullGlobal) {
TEST_F(TestFileSystemFileHandle, isWritableReturned) {
RefPtr<FileSystemFileHandle> fileHandle = MakeAndAddRef<FileSystemFileHandle>(
mGlobal, mMetadata, mRequestHandler.release());
mGlobal, mActor, mMetadata, mRequestHandler.release());
ASSERT_TRUE(fileHandle);
@ -88,7 +90,7 @@ TEST_F(TestFileSystemFileHandle, isWritableReturned) {
TEST_F(TestFileSystemFileHandle, doesCreateWritableFailOnNullGlobal) {
mGlobal = nullptr;
RefPtr<FileSystemFileHandle> fileHandle = MakeAndAddRef<FileSystemFileHandle>(
mGlobal, mMetadata, mRequestHandler.release());
mGlobal, mActor, mMetadata, mRequestHandler.release());
ASSERT_TRUE(fileHandle);
@ -101,7 +103,7 @@ TEST_F(TestFileSystemFileHandle, doesCreateWritableFailOnNullGlobal) {
TEST_F(TestFileSystemFileHandle, isSyncAccessHandleReturned) {
RefPtr<FileSystemFileHandle> fileHandle = MakeAndAddRef<FileSystemFileHandle>(
mGlobal, mMetadata, mRequestHandler.release());
mGlobal, mActor, mMetadata, mRequestHandler.release());
ASSERT_TRUE(fileHandle);
@ -114,7 +116,7 @@ TEST_F(TestFileSystemFileHandle, isSyncAccessHandleReturned) {
TEST_F(TestFileSystemFileHandle, doesCreateSyncAccessHandleFailOnNullGlobal) {
mGlobal = nullptr;
RefPtr<FileSystemFileHandle> fileHandle = MakeAndAddRef<FileSystemFileHandle>(
mGlobal, mMetadata, mRequestHandler.release());
mGlobal, mActor, mMetadata, mRequestHandler.release());
ASSERT_TRUE(fileHandle);

View File

@ -21,18 +21,20 @@ class TestFileSystemHandle : public ::testing::Test {
void SetUp() override {
mDirMetadata = FileSystemEntryMetadata("dir"_ns, u"Directory"_ns);
mFileMetadata = FileSystemEntryMetadata("file"_ns, u"File"_ns);
mActor = MakeAndAddRef<FileSystemActorHolder>(nullptr);
}
nsIGlobalObject* mGlobal = GetGlobal();
FileSystemEntryMetadata mDirMetadata;
FileSystemEntryMetadata mFileMetadata;
RefPtr<FileSystemActorHolder> mActor;
};
TEST_F(TestFileSystemHandle, createAndDestroyHandles) {
RefPtr<FileSystemHandle> dirHandle =
new FileSystemDirectoryHandle(mGlobal, mDirMetadata);
new FileSystemDirectoryHandle(mGlobal, mActor, mDirMetadata);
RefPtr<FileSystemHandle> fileHandle =
new FileSystemFileHandle(mGlobal, mFileMetadata);
new FileSystemFileHandle(mGlobal, mActor, mFileMetadata);
EXPECT_TRUE(dirHandle);
EXPECT_TRUE(fileHandle);
@ -40,9 +42,9 @@ TEST_F(TestFileSystemHandle, createAndDestroyHandles) {
TEST_F(TestFileSystemHandle, areFileNamesAsExpected) {
RefPtr<FileSystemHandle> dirHandle =
new FileSystemDirectoryHandle(mGlobal, mDirMetadata);
new FileSystemDirectoryHandle(mGlobal, mActor, mDirMetadata);
RefPtr<FileSystemHandle> fileHandle =
new FileSystemFileHandle(mGlobal, mFileMetadata);
new FileSystemFileHandle(mGlobal, mActor, mFileMetadata);
auto GetEntryName = [](const RefPtr<FileSystemHandle>& aHandle) {
DOMString domName;
@ -62,16 +64,16 @@ TEST_F(TestFileSystemHandle, areFileNamesAsExpected) {
TEST_F(TestFileSystemHandle, isParentObjectReturned) {
ASSERT_TRUE(mGlobal);
RefPtr<FileSystemHandle> dirHandle =
new FileSystemDirectoryHandle(mGlobal, mDirMetadata);
new FileSystemDirectoryHandle(mGlobal, mActor, mDirMetadata);
ASSERT_EQ(mGlobal, dirHandle->GetParentObject());
}
TEST_F(TestFileSystemHandle, areHandleKindsAsExpected) {
RefPtr<FileSystemHandle> dirHandle =
new FileSystemDirectoryHandle(mGlobal, mDirMetadata);
new FileSystemDirectoryHandle(mGlobal, mActor, mDirMetadata);
RefPtr<FileSystemHandle> fileHandle =
new FileSystemFileHandle(mGlobal, mFileMetadata);
new FileSystemFileHandle(mGlobal, mActor, mFileMetadata);
EXPECT_EQ(FileSystemHandleKind::Directory, dirHandle->Kind());
EXPECT_EQ(FileSystemHandleKind::File, fileHandle->Kind());
@ -79,9 +81,9 @@ TEST_F(TestFileSystemHandle, areHandleKindsAsExpected) {
TEST_F(TestFileSystemHandle, isDifferentEntry) {
RefPtr<FileSystemHandle> dirHandle =
new FileSystemDirectoryHandle(mGlobal, mDirMetadata);
new FileSystemDirectoryHandle(mGlobal, mActor, mDirMetadata);
RefPtr<FileSystemHandle> fileHandle =
new FileSystemFileHandle(mGlobal, mFileMetadata);
new FileSystemFileHandle(mGlobal, mActor, mFileMetadata);
IgnoredErrorResult rv;
RefPtr<Promise> promise = dirHandle->IsSameEntry(*fileHandle, rv);
@ -92,7 +94,7 @@ TEST_F(TestFileSystemHandle, isDifferentEntry) {
TEST_F(TestFileSystemHandle, isSameEntry) {
RefPtr<FileSystemHandle> fileHandle =
new FileSystemFileHandle(mGlobal, mFileMetadata);
new FileSystemFileHandle(mGlobal, mActor, mFileMetadata);
IgnoredErrorResult rv;
RefPtr<Promise> promise = fileHandle->IsSameEntry(*fileHandle, rv);

View File

@ -8,6 +8,7 @@
#include "FileSystemMocks.h"
#include "fs/FileSystemRequestHandler.h"
#include "mozilla/dom/OriginPrivateFileSystemChild.h"
#include "mozilla/SpinEventLoopUntil.h"
#include "mozilla/UniquePtr.h"
@ -23,7 +24,7 @@ class TestFileSystemRequestHandler : public ::testing::Test {
mChild = FileSystemChildMetadata("parent"_ns, u"ChildName"_ns);
mEntry = FileSystemEntryMetadata("myid"_ns, u"EntryName"_ns);
mName = u"testDir"_ns;
mActor = MakeAndAddRef<FileSystemActorHolder>();
mActor = MakeAndAddRef<FileSystemActorHolder>(nullptr);
}
already_AddRefed<Promise> GetDefaultPromise() {

45
ipc/glue/ActorHolder.h Normal file
View File

@ -0,0 +1,45 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef MOZILLA_IPC_ACTORHOLDER_H
#define MOZILLA_IPC_ACTORHOLDER_H
#include "nsISupports.h"
namespace mozilla::ipc {
// Class to let us close the actor when we're not using it anymore. You
// should create a single instance of this, and when you have no more
// references it will be destroyed and will Close() the underlying
// top-level channel.
// When you want to send something, you use something like
// aActor->Actor()->SendFoo()
// You can avoid calling Close() on an un-connected Actor (for example if
// Bind() fails) by calling RemoveActor();
template <typename T>
class TopLevelActorHolder final {
public:
NS_INLINE_DECL_REFCOUNTING_ONEVENTTARGET(TopLevelActorHolder)
explicit TopLevelActorHolder(T* aActor) : mActor(aActor) {}
constexpr T* Actor() const { return mActor; }
inline void RemoveActor() { mActor = nullptr; }
private:
inline ~TopLevelActorHolder() {
if (mActor) {
mActor->Close();
}
}
RefPtr<T> mActor;
};
} // namespace mozilla::ipc
#endif // MOZILLA_IPC_ACTORHOLDER_H

View File

@ -10,6 +10,7 @@ EXPORTS += [
]
EXPORTS.mozilla.ipc += [
"ActorHolder.h",
"AsyncBlockers.h",
"BackgroundChild.h",
"BackgroundParent.h",