summaryrefslogtreecommitdiffstats
path: root/dom/fs/child
diff options
context:
space:
mode:
Diffstat (limited to 'dom/fs/child')
-rw-r--r--dom/fs/child/FileSystemAccessHandleChild.cpp34
-rw-r--r--dom/fs/child/FileSystemAccessHandleChild.h41
-rw-r--r--dom/fs/child/FileSystemBackgroundRequestHandler.cpp142
-rw-r--r--dom/fs/child/FileSystemBackgroundRequestHandler.h73
-rw-r--r--dom/fs/child/FileSystemChildFactory.cpp19
-rw-r--r--dom/fs/child/FileSystemDirectoryIteratorFactory.cpp238
-rw-r--r--dom/fs/child/FileSystemDirectoryIteratorFactory.h24
-rw-r--r--dom/fs/child/FileSystemEntryMetadataArray.h26
-rw-r--r--dom/fs/child/FileSystemManagerChild.cpp103
-rw-r--r--dom/fs/child/FileSystemManagerChild.h58
-rw-r--r--dom/fs/child/FileSystemRequestHandler.cpp648
-rw-r--r--dom/fs/child/FileSystemWritableFileStreamChild.cpp39
-rw-r--r--dom/fs/child/FileSystemWritableFileStreamChild.h42
-rw-r--r--dom/fs/child/moz.build29
14 files changed, 1516 insertions, 0 deletions
diff --git a/dom/fs/child/FileSystemAccessHandleChild.cpp b/dom/fs/child/FileSystemAccessHandleChild.cpp
new file mode 100644
index 0000000000..b32d9b2dc6
--- /dev/null
+++ b/dom/fs/child/FileSystemAccessHandleChild.cpp
@@ -0,0 +1,34 @@
+/* -*- 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 "FileSystemAccessHandleChild.h"
+
+#include "mozilla/dom/FileSystemSyncAccessHandle.h"
+#include "private/pprio.h"
+
+namespace mozilla::dom {
+
+FileSystemAccessHandleChild::FileSystemAccessHandleChild()
+ : mAccessHandle(nullptr) {}
+
+FileSystemAccessHandleChild::~FileSystemAccessHandleChild() = default;
+
+void FileSystemAccessHandleChild::SetAccessHandle(
+ FileSystemSyncAccessHandle* aAccessHandle) {
+ MOZ_ASSERT(aAccessHandle);
+ MOZ_ASSERT(!mAccessHandle);
+
+ mAccessHandle = aAccessHandle;
+}
+
+void FileSystemAccessHandleChild::ActorDestroy(ActorDestroyReason aWhy) {
+ if (mAccessHandle) {
+ mAccessHandle->ClearActor();
+ mAccessHandle = nullptr;
+ }
+}
+
+} // namespace mozilla::dom
diff --git a/dom/fs/child/FileSystemAccessHandleChild.h b/dom/fs/child/FileSystemAccessHandleChild.h
new file mode 100644
index 0000000000..d616178646
--- /dev/null
+++ b/dom/fs/child/FileSystemAccessHandleChild.h
@@ -0,0 +1,41 @@
+/* -*- 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_FILESYSTEMACCESSHANDLECHILD_H_
+#define DOM_FS_CHILD_FILESYSTEMACCESSHANDLECHILD_H_
+
+#include "mozilla/dom/PFileSystemAccessHandleChild.h"
+
+namespace mozilla::dom {
+
+class FileSystemSyncAccessHandle;
+
+class FileSystemAccessHandleChild : public PFileSystemAccessHandleChild {
+ public:
+ FileSystemAccessHandleChild();
+
+ NS_INLINE_DECL_REFCOUNTING(FileSystemAccessHandleChild, override)
+
+ FileSystemSyncAccessHandle* MutableAccessHandlePtr() const {
+ MOZ_ASSERT(mAccessHandle);
+ return mAccessHandle;
+ }
+
+ void SetAccessHandle(FileSystemSyncAccessHandle* aAccessHandle);
+
+ void ActorDestroy(ActorDestroyReason aWhy) override;
+
+ private:
+ virtual ~FileSystemAccessHandleChild();
+
+ // Use a weak ref so actor does not hold DOM object alive past content use.
+ // The weak reference is cleared in FileSystemSyncAccessHandle::LastRelease.
+ FileSystemSyncAccessHandle* MOZ_NON_OWNING_REF mAccessHandle;
+};
+
+} // namespace mozilla::dom
+
+#endif // DOM_FS_CHILD_FILESYSTEMACCESSHANDLECHILD_H_
diff --git a/dom/fs/child/FileSystemBackgroundRequestHandler.cpp b/dom/fs/child/FileSystemBackgroundRequestHandler.cpp
new file mode 100644
index 0000000000..d88ec05a8c
--- /dev/null
+++ b/dom/fs/child/FileSystemBackgroundRequestHandler.cpp
@@ -0,0 +1,142 @@
+/* -*- 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 "FileSystemBackgroundRequestHandler.h"
+
+#include "fs/FileSystemChildFactory.h"
+#include "mozilla/dom/FileSystemManagerChild.h"
+#include "mozilla/dom/PFileSystemManager.h"
+#include "mozilla/ipc/BackgroundChild.h"
+#include "mozilla/ipc/Endpoint.h"
+#include "mozilla/ipc/PBackgroundChild.h"
+
+namespace mozilla::dom {
+
+FileSystemBackgroundRequestHandler::FileSystemBackgroundRequestHandler(
+ fs::FileSystemChildFactory* aChildFactory)
+ : mChildFactory(aChildFactory), mCreatingFileSystemManagerChild(false) {}
+
+FileSystemBackgroundRequestHandler::FileSystemBackgroundRequestHandler(
+ RefPtr<FileSystemManagerChild> aFileSystemManagerChild)
+ : mFileSystemManagerChild(std::move(aFileSystemManagerChild)),
+ mCreatingFileSystemManagerChild(false) {}
+
+FileSystemBackgroundRequestHandler::FileSystemBackgroundRequestHandler()
+ : FileSystemBackgroundRequestHandler(new fs::FileSystemChildFactory()) {}
+
+FileSystemBackgroundRequestHandler::~FileSystemBackgroundRequestHandler() =
+ default;
+
+void FileSystemBackgroundRequestHandler::ClearActor() {
+ MOZ_ASSERT(mFileSystemManagerChild);
+
+ mFileSystemManagerChild = nullptr;
+}
+
+void FileSystemBackgroundRequestHandler::Shutdown() {
+ mShutdown.Flip();
+
+ if (mFileSystemManagerChild) {
+ MOZ_ASSERT(!mCreatingFileSystemManagerChild);
+
+ mFileSystemManagerChild->Shutdown();
+
+ mFileSystemManagerChild = nullptr;
+
+ return;
+ }
+
+ if (mCreatingFileSystemManagerChild) {
+ MOZ_ASSERT(!mFileSystemManagerChild);
+
+ mCreateFileSystemManagerParentPromiseRequestHolder.Disconnect();
+
+ mCreatingFileSystemManagerChild = false;
+
+ // We must either resolve/reject the promise or steal the internal promise
+ // before the holder is destroyed. The former isn't possible during
+ // shutdown.
+ Unused << mCreateFileSystemManagerChildPromiseHolder.Steal();
+ }
+}
+
+const RefPtr<FileSystemManagerChild>&
+FileSystemBackgroundRequestHandler::FileSystemManagerChildStrongRef() const {
+ return mFileSystemManagerChild;
+}
+
+RefPtr<BoolPromise>
+FileSystemBackgroundRequestHandler::CreateFileSystemManagerChild(
+ const mozilla::ipc::PrincipalInfo& aPrincipalInfo) {
+ MOZ_ASSERT(!mFileSystemManagerChild);
+ MOZ_ASSERT(!mShutdown);
+
+ using mozilla::ipc::BackgroundChild;
+ using mozilla::ipc::Endpoint;
+ using mozilla::ipc::PBackgroundChild;
+
+ if (!mCreatingFileSystemManagerChild) {
+ PBackgroundChild* backgroundChild =
+ BackgroundChild::GetOrCreateForCurrentThread();
+ if (NS_WARN_IF(!backgroundChild)) {
+ return BoolPromise::CreateAndReject(NS_ERROR_FAILURE, __func__);
+ }
+
+ // Create a new IPC connection
+ Endpoint<PFileSystemManagerParent> parentEndpoint;
+ Endpoint<PFileSystemManagerChild> childEndpoint;
+ MOZ_ALWAYS_SUCCEEDS(
+ PFileSystemManager::CreateEndpoints(&parentEndpoint, &childEndpoint));
+
+ RefPtr<FileSystemManagerChild> child = mChildFactory->Create();
+ if (!childEndpoint.Bind(child)) {
+ return BoolPromise::CreateAndReject(NS_ERROR_FAILURE, __func__);
+ }
+
+ mCreatingFileSystemManagerChild = true;
+
+ backgroundChild
+ ->SendCreateFileSystemManagerParent(aPrincipalInfo,
+ std::move(parentEndpoint))
+ ->Then(
+ GetCurrentSerialEventTarget(), __func__,
+ [self = RefPtr<FileSystemBackgroundRequestHandler>(this),
+ child](nsresult rv) {
+ self->mCreateFileSystemManagerParentPromiseRequestHolder
+ .Complete();
+
+ self->mCreatingFileSystemManagerChild = false;
+
+ if (NS_FAILED(rv)) {
+ self->mCreateFileSystemManagerChildPromiseHolder.RejectIfExists(
+ rv, __func__);
+ } else {
+ self->mFileSystemManagerChild = child;
+
+ self->mFileSystemManagerChild->SetBackgroundRequestHandler(
+ self);
+
+ self->mCreateFileSystemManagerChildPromiseHolder
+ .ResolveIfExists(true, __func__);
+ }
+ },
+ [self = RefPtr<FileSystemBackgroundRequestHandler>(this)](
+ const mozilla::ipc::ResponseRejectReason&) {
+ self->mCreateFileSystemManagerParentPromiseRequestHolder
+ .Complete();
+
+ self->mCreatingFileSystemManagerChild = false;
+
+ self->mCreateFileSystemManagerChildPromiseHolder.RejectIfExists(
+ NS_ERROR_FAILURE, __func__);
+ })
+ ->Track(mCreateFileSystemManagerParentPromiseRequestHolder);
+ }
+
+ return mCreateFileSystemManagerChildPromiseHolder.Ensure(__func__);
+}
+
+} // namespace mozilla::dom
diff --git a/dom/fs/child/FileSystemBackgroundRequestHandler.h b/dom/fs/child/FileSystemBackgroundRequestHandler.h
new file mode 100644
index 0000000000..a206375384
--- /dev/null
+++ b/dom/fs/child/FileSystemBackgroundRequestHandler.h
@@ -0,0 +1,73 @@
+/* -*- 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_FILESYSTEMBACKGROUNDREQUESTHANDLER_H_
+#define DOM_FS_CHILD_FILESYSTEMBACKGROUNDREQUESTHANDLER_H_
+
+#include "mozilla/MozPromise.h"
+#include "mozilla/UniquePtr.h"
+#include "mozilla/dom/quota/ForwardDecls.h"
+#include "mozilla/ipc/PBackgroundChild.h"
+
+template <class T>
+class RefPtr;
+
+namespace mozilla {
+
+namespace ipc {
+class PrincipalInfo;
+} // namespace ipc
+
+namespace dom {
+
+class FileSystemManagerChild;
+
+namespace fs {
+class FileSystemChildFactory;
+}
+
+class FileSystemBackgroundRequestHandler {
+ public:
+ explicit FileSystemBackgroundRequestHandler(
+ fs::FileSystemChildFactory* aChildFactory);
+
+ explicit FileSystemBackgroundRequestHandler(
+ RefPtr<FileSystemManagerChild> aFileSystemManagerChild);
+
+ FileSystemBackgroundRequestHandler();
+
+ NS_INLINE_DECL_REFCOUNTING(FileSystemBackgroundRequestHandler)
+
+ void ClearActor();
+
+ void Shutdown();
+
+ const RefPtr<FileSystemManagerChild>& FileSystemManagerChildStrongRef() const;
+
+ virtual RefPtr<mozilla::BoolPromise> CreateFileSystemManagerChild(
+ const mozilla::ipc::PrincipalInfo& aPrincipalInfo);
+
+ protected:
+ virtual ~FileSystemBackgroundRequestHandler();
+
+ const UniquePtr<fs::FileSystemChildFactory> mChildFactory;
+
+ MozPromiseRequestHolder<
+ mozilla::ipc::PBackgroundChild::CreateFileSystemManagerParentPromise>
+ mCreateFileSystemManagerParentPromiseRequestHolder;
+ MozPromiseHolder<BoolPromise> mCreateFileSystemManagerChildPromiseHolder;
+
+ RefPtr<FileSystemManagerChild> mFileSystemManagerChild;
+
+ FlippedOnce<false> mShutdown;
+
+ bool mCreatingFileSystemManagerChild;
+}; // class FileSystemBackgroundRequestHandler
+
+} // namespace dom
+} // namespace mozilla
+
+#endif // DOM_FS_CHILD_FILESYSTEMBACKGROUNDREQUESTHANDLER_H_
diff --git a/dom/fs/child/FileSystemChildFactory.cpp b/dom/fs/child/FileSystemChildFactory.cpp
new file mode 100644
index 0000000000..bf4c493dd8
--- /dev/null
+++ b/dom/fs/child/FileSystemChildFactory.cpp
@@ -0,0 +1,19 @@
+/* -*- 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 "fs/FileSystemChildFactory.h"
+
+#include "mozilla/RefPtr.h"
+#include "mozilla/dom/FileSystemManagerChild.h"
+
+namespace mozilla::dom::fs {
+
+already_AddRefed<FileSystemManagerChild> FileSystemChildFactory::Create()
+ const {
+ return MakeAndAddRef<FileSystemManagerChild>();
+}
+
+} // namespace mozilla::dom::fs
diff --git a/dom/fs/child/FileSystemDirectoryIteratorFactory.cpp b/dom/fs/child/FileSystemDirectoryIteratorFactory.cpp
new file mode 100644
index 0000000000..5bb3e13255
--- /dev/null
+++ b/dom/fs/child/FileSystemDirectoryIteratorFactory.cpp
@@ -0,0 +1,238 @@
+/* -*- 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 "FileSystemDirectoryIteratorFactory.h"
+
+#include "FileSystemEntryMetadataArray.h"
+#include "fs/FileSystemRequestHandler.h"
+#include "jsapi.h"
+#include "mozilla/dom/FileSystemDirectoryHandle.h"
+#include "mozilla/dom/FileSystemDirectoryIterator.h"
+#include "mozilla/dom/FileSystemFileHandle.h"
+#include "mozilla/dom/FileSystemHandle.h"
+#include "mozilla/dom/FileSystemLog.h"
+#include "mozilla/dom/FileSystemManager.h"
+#include "mozilla/dom/IterableIterator.h"
+#include "mozilla/dom/Promise.h"
+#include "mozilla/dom/PromiseNativeHandler.h"
+
+namespace mozilla::dom::fs {
+
+namespace {
+
+template <IterableIteratorBase::IteratorType Type>
+struct ValueResolver;
+
+template <>
+struct ValueResolver<IterableIteratorBase::Keys> {
+ void operator()(nsIGlobalObject* aGlobal, RefPtr<FileSystemManager>& aManager,
+ const FileSystemEntryMetadata& aValue,
+ const RefPtr<Promise>& aPromise) {
+ aPromise->MaybeResolve(aValue.entryName());
+ }
+};
+
+template <>
+struct ValueResolver<IterableIteratorBase::Values> {
+ void operator()(nsIGlobalObject* aGlobal, RefPtr<FileSystemManager>& aManager,
+ const FileSystemEntryMetadata& aValue,
+ const RefPtr<Promise>& aPromise) {
+ RefPtr<FileSystemHandle> handle;
+
+ if (aValue.directory()) {
+ handle = new FileSystemDirectoryHandle(aGlobal, aManager, aValue);
+ } else {
+ handle = new FileSystemFileHandle(aGlobal, aManager, aValue);
+ }
+
+ aPromise->MaybeResolve(std::move(handle));
+ }
+};
+
+template <>
+struct ValueResolver<IterableIteratorBase::Entries> {
+ void operator()(nsIGlobalObject* aGlobal, RefPtr<FileSystemManager>& aManager,
+ const FileSystemEntryMetadata& aValue,
+ const RefPtr<Promise>& aPromise) {
+ RefPtr<FileSystemHandle> handle;
+
+ if (aValue.directory()) {
+ handle = new FileSystemDirectoryHandle(aGlobal, aManager, aValue);
+ } else {
+ handle = new FileSystemFileHandle(aGlobal, aManager, aValue);
+ }
+
+ iterator_utils::ResolvePromiseWithKeyAndValue(aPromise, aValue.entryName(),
+ handle);
+ }
+};
+
+// TODO: PageSize could be compile-time shared between content and parent
+template <class ValueResolver, size_t PageSize = 1024u>
+class DoubleBufferQueueImpl
+ : public mozilla::dom::FileSystemDirectoryIterator::Impl {
+ static_assert(PageSize > 0u);
+
+ public:
+ using DataType = FileSystemEntryMetadata;
+ explicit DoubleBufferQueueImpl(const FileSystemEntryMetadata& aMetadata)
+ : mEntryId(aMetadata.entryId()),
+ mData(),
+ mWithinPageEnd(0u),
+ mWithinPageIndex(0u),
+ mCurrentPageIsLastPage(true),
+ mPageNumber(0u) {}
+
+ // XXX This doesn't have to be public
+ void ResolveValue(nsIGlobalObject* aGlobal,
+ RefPtr<FileSystemManager>& aManager,
+ const Maybe<DataType>& aValue, RefPtr<Promise> aPromise) {
+ MOZ_ASSERT(aPromise);
+ MOZ_ASSERT(aPromise.get());
+
+ if (!aValue) {
+ iterator_utils::ResolvePromiseForFinished(aPromise);
+ return;
+ }
+
+ ValueResolver{}(aGlobal, aManager, *aValue, aPromise);
+ }
+
+ already_AddRefed<Promise> Next(nsIGlobalObject* aGlobal,
+ RefPtr<FileSystemManager>& aManager,
+ ErrorResult& aError) override {
+ RefPtr<Promise> promise = Promise::Create(aGlobal, aError);
+ if (aError.Failed()) {
+ return nullptr;
+ }
+
+ next(aGlobal, aManager, promise, aError);
+ if (aError.Failed()) {
+ return nullptr;
+ }
+
+ return promise.forget();
+ }
+
+ ~DoubleBufferQueueImpl() = default;
+
+ protected:
+ void next(nsIGlobalObject* aGlobal, RefPtr<FileSystemManager>& aManager,
+ RefPtr<Promise> aResult, ErrorResult& aError) {
+ LOG_VERBOSE(("next"));
+ MOZ_ASSERT(aResult);
+
+ Maybe<DataType> rawValue;
+
+ // TODO: Would it be better to prefetch the items before
+ // we hit the end of a page?
+ // How likely it is that it would that lead to wasted fetch operations?
+ if (0u == mWithinPageIndex) {
+ RefPtr<Promise> promise = Promise::Create(aGlobal, aError);
+ if (aError.Failed()) {
+ return;
+ }
+
+ auto newPage = MakeRefPtr<FileSystemEntryMetadataArray>();
+
+ RefPtr<DomPromiseListener> listener = new DomPromiseListener(
+ [global = nsCOMPtr<nsIGlobalObject>(aGlobal),
+ manager = RefPtr<FileSystemManager>(aManager), newPage, aResult,
+ this](JSContext* aCx, JS::Handle<JS::Value> aValue) mutable {
+ MOZ_ASSERT(0u == mWithinPageIndex);
+
+ // XXX Do we need this extra copy ?
+ nsTArray<DataType> batch;
+ for (const auto& it : *newPage) {
+ batch.AppendElement(it);
+ }
+
+ const size_t batchSize = std::min(PageSize, newPage->Length());
+ mData.InsertElementsAt(
+ PageSize * static_cast<size_t>(!mCurrentPageIsLastPage),
+ batch.Elements(), batchSize);
+ mWithinPageEnd += batchSize;
+
+ Maybe<DataType> value;
+ if (0 != newPage->Length()) {
+ nextInternal(value);
+ }
+
+ ResolveValue(global, manager, value, aResult);
+ },
+ [aResult](nsresult aRv) { aResult->MaybeReject(aRv); });
+ promise->AppendNativeHandler(listener);
+
+ FileSystemRequestHandler{}.GetEntries(aManager, mEntryId, mPageNumber,
+ promise, newPage, aError);
+ if (aError.Failed()) {
+ return;
+ }
+
+ ++mPageNumber;
+ return;
+ }
+
+ nextInternal(rawValue);
+
+ ResolveValue(aGlobal, aManager, rawValue, aResult);
+ }
+
+ bool nextInternal(Maybe<DataType>& aNext) {
+ if (mWithinPageIndex >= mWithinPageEnd) {
+ return false;
+ }
+
+ const auto previous =
+ static_cast<size_t>(!mCurrentPageIsLastPage) * PageSize +
+ mWithinPageIndex;
+ MOZ_ASSERT(2u * PageSize > previous);
+ MOZ_ASSERT(previous < mData.Length());
+
+ ++mWithinPageIndex;
+
+ if (mWithinPageIndex == PageSize) {
+ // Page end reached
+ mWithinPageIndex = 0u;
+ mCurrentPageIsLastPage = !mCurrentPageIsLastPage;
+ }
+
+ aNext = Some(mData[previous]);
+ return true;
+ }
+
+ const EntryId mEntryId;
+
+ nsTArray<DataType> mData; // TODO: Fixed size above one page?
+
+ size_t mWithinPageEnd = 0u;
+ size_t mWithinPageIndex = 0u;
+ bool mCurrentPageIsLastPage = true; // In the beginning, first page is free
+ PageNumber mPageNumber = 0u;
+};
+
+template <IterableIteratorBase::IteratorType Type>
+using UnderlyingQueue = DoubleBufferQueueImpl<ValueResolver<Type>>;
+
+} // namespace
+
+UniquePtr<mozilla::dom::FileSystemDirectoryIterator::Impl>
+FileSystemDirectoryIteratorFactory::Create(
+ const FileSystemEntryMetadata& aMetadata,
+ IterableIteratorBase::IteratorType aType) {
+ if (IterableIteratorBase::Entries == aType) {
+ return MakeUnique<UnderlyingQueue<IterableIteratorBase::Entries>>(
+ aMetadata);
+ }
+
+ if (IterableIteratorBase::Values == aType) {
+ return MakeUnique<UnderlyingQueue<IterableIteratorBase::Values>>(aMetadata);
+ }
+
+ return MakeUnique<UnderlyingQueue<IterableIteratorBase::Keys>>(aMetadata);
+}
+
+} // namespace mozilla::dom::fs
diff --git a/dom/fs/child/FileSystemDirectoryIteratorFactory.h b/dom/fs/child/FileSystemDirectoryIteratorFactory.h
new file mode 100644
index 0000000000..278f0a9ef0
--- /dev/null
+++ b/dom/fs/child/FileSystemDirectoryIteratorFactory.h
@@ -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_FILESYSTEMDIRECTORYITERATORFACTORY_H_
+#define DOM_FS_CHILD_FILESYSTEMDIRECTORYITERATORFACTORY_H_
+
+#include "mozilla/dom/FileSystemDirectoryIterator.h"
+
+namespace mozilla::dom::fs {
+
+class FileSystemEntryMetadata;
+
+struct FileSystemDirectoryIteratorFactory {
+ static UniquePtr<mozilla::dom::FileSystemDirectoryIterator::Impl> Create(
+ const FileSystemEntryMetadata& aMetadata,
+ IterableIteratorBase::IteratorType aType);
+};
+
+} // namespace mozilla::dom::fs
+
+#endif // DOM_FS_CHILD_FILESYSTEMDIRECTORYITERATORFACTORY_H_
diff --git a/dom/fs/child/FileSystemEntryMetadataArray.h b/dom/fs/child/FileSystemEntryMetadataArray.h
new file mode 100644
index 0000000000..cd5370846a
--- /dev/null
+++ b/dom/fs/child/FileSystemEntryMetadataArray.h
@@ -0,0 +1,26 @@
+/* -*- 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_FILESYSTEMENTRYMETADATAARRAY_H_
+#define DOM_FS_CHILD_FILESYSTEMENTRYMETADATAARRAY_H_
+
+#include "nsTArray.h"
+
+namespace mozilla::dom::fs {
+
+class FileSystemEntryMetadata;
+
+class FileSystemEntryMetadataArray : public nsTArray<FileSystemEntryMetadata> {
+ public:
+ NS_INLINE_DECL_REFCOUNTING(FileSystemEntryMetadataArray);
+
+ private:
+ ~FileSystemEntryMetadataArray() = default;
+};
+
+} // namespace mozilla::dom::fs
+
+#endif // DOM_FS_CHILD_FILESYSTEMENTRYMETADATAARRAY_H_
diff --git a/dom/fs/child/FileSystemManagerChild.cpp b/dom/fs/child/FileSystemManagerChild.cpp
new file mode 100644
index 0000000000..045f50cf7f
--- /dev/null
+++ b/dom/fs/child/FileSystemManagerChild.cpp
@@ -0,0 +1,103 @@
+/* -*- 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 "FileSystemManagerChild.h"
+
+#include "FileSystemAccessHandleChild.h"
+#include "FileSystemBackgroundRequestHandler.h"
+#include "FileSystemWritableFileStreamChild.h"
+#include "mozilla/dom/FileSystemSyncAccessHandle.h"
+#include "mozilla/dom/FileSystemWritableFileStream.h"
+
+namespace mozilla::dom {
+
+void FileSystemManagerChild::SetBackgroundRequestHandler(
+ FileSystemBackgroundRequestHandler* aBackgroundRequestHandler) {
+ MOZ_ASSERT(aBackgroundRequestHandler);
+ MOZ_ASSERT(!mBackgroundRequestHandler);
+
+ mBackgroundRequestHandler = aBackgroundRequestHandler;
+}
+
+#ifdef DEBUG
+bool FileSystemManagerChild::AllSyncAccessHandlesClosed() const {
+ for (const auto& item : ManagedPFileSystemAccessHandleChild()) {
+ auto* child = static_cast<FileSystemAccessHandleChild*>(item);
+ auto* handle = child->MutableAccessHandlePtr();
+
+ if (!handle->IsClosed()) {
+ return false;
+ }
+ }
+
+ return true;
+}
+#endif
+
+void FileSystemManagerChild::CloseAllWritableFileStreams() {
+ for (const auto& item : ManagedPFileSystemWritableFileStreamChild()) {
+ auto* child = static_cast<FileSystemWritableFileStreamChild*>(item);
+
+ child->MutableWritableFileStreamPtr()->Close();
+ }
+}
+
+void FileSystemManagerChild::Shutdown() {
+ if (!CanSend()) {
+ return;
+ }
+
+ Close();
+}
+
+already_AddRefed<PFileSystemAccessHandleChild>
+FileSystemManagerChild::AllocPFileSystemAccessHandleChild() {
+ return MakeAndAddRef<FileSystemAccessHandleChild>();
+}
+
+already_AddRefed<PFileSystemWritableFileStreamChild>
+FileSystemManagerChild::AllocPFileSystemWritableFileStreamChild() {
+ return MakeAndAddRef<FileSystemWritableFileStreamChild>();
+}
+
+::mozilla::ipc::IPCResult FileSystemManagerChild::RecvCloseAll(
+ CloseAllResolver&& aResolver) {
+ nsTArray<RefPtr<BoolPromise>> promises;
+
+ // NOTE: getFile() creates blobs that read the data from the child;
+ // we'll need to abort any reads and resolve this call only when all
+ // blobs are closed.
+
+ for (const auto& item : ManagedPFileSystemAccessHandleChild()) {
+ auto* child = static_cast<FileSystemAccessHandleChild*>(item);
+ auto* handle = child->MutableAccessHandlePtr();
+
+ if (handle->IsOpen()) {
+ promises.AppendElement(handle->BeginClose());
+ } else if (handle->IsClosing()) {
+ promises.AppendElement(handle->OnClose());
+ }
+ }
+
+ CloseAllWritableFileStreams();
+
+ BoolPromise::AllSettled(GetCurrentSerialEventTarget(), promises)
+ ->Then(GetCurrentSerialEventTarget(), __func__,
+ [resolver = std::move(aResolver)](
+ const BoolPromise::AllSettledPromiseType::ResolveOrRejectValue&
+ aValues) { resolver(NS_OK); });
+
+ return IPC_OK();
+}
+
+void FileSystemManagerChild::ActorDestroy(ActorDestroyReason aWhy) {
+ if (mBackgroundRequestHandler) {
+ mBackgroundRequestHandler->ClearActor();
+ mBackgroundRequestHandler = nullptr;
+ }
+}
+
+} // namespace mozilla::dom
diff --git a/dom/fs/child/FileSystemManagerChild.h b/dom/fs/child/FileSystemManagerChild.h
new file mode 100644
index 0000000000..7000dfab67
--- /dev/null
+++ b/dom/fs/child/FileSystemManagerChild.h
@@ -0,0 +1,58 @@
+/* -*- 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_FILESYSTEMMANAGERCHILD_H_
+#define DOM_FS_CHILD_FILESYSTEMMANAGERCHILD_H_
+
+#include "mozilla/dom/PFileSystemManagerChild.h"
+#include "nsISupportsImpl.h"
+
+namespace mozilla::dom {
+
+class FileSystemBackgroundRequestHandler;
+
+class FileSystemManagerChild : public PFileSystemManagerChild {
+ public:
+ NS_INLINE_DECL_REFCOUNTING_WITH_DESTROY(FileSystemManagerChild, Destroy(),
+ override)
+
+ void SetBackgroundRequestHandler(
+ FileSystemBackgroundRequestHandler* aBackgroundRequestHandler);
+
+#ifdef DEBUG
+ virtual bool AllSyncAccessHandlesClosed() const;
+#endif
+
+ virtual void CloseAllWritableFileStreams();
+
+ virtual void Shutdown();
+
+ already_AddRefed<PFileSystemAccessHandleChild>
+ AllocPFileSystemAccessHandleChild();
+
+ already_AddRefed<PFileSystemWritableFileStreamChild>
+ AllocPFileSystemWritableFileStreamChild();
+
+ ::mozilla::ipc::IPCResult RecvCloseAll(CloseAllResolver&& aResolver);
+
+ void ActorDestroy(ActorDestroyReason aWhy) override;
+
+ protected:
+ virtual ~FileSystemManagerChild() = default;
+
+ virtual void Destroy() {
+ Shutdown();
+ delete this;
+ }
+
+ // The weak reference is cleared in ActorDestroy.
+ FileSystemBackgroundRequestHandler* MOZ_NON_OWNING_REF
+ mBackgroundRequestHandler;
+};
+
+} // namespace mozilla::dom
+
+#endif // DOM_FS_CHILD_FILESYSTEMMANAGERCHILD_H_
diff --git a/dom/fs/child/FileSystemRequestHandler.cpp b/dom/fs/child/FileSystemRequestHandler.cpp
new file mode 100644
index 0000000000..87c06e409a
--- /dev/null
+++ b/dom/fs/child/FileSystemRequestHandler.cpp
@@ -0,0 +1,648 @@
+/* -*- 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 "fs/FileSystemRequestHandler.h"
+
+#include "FileSystemEntryMetadataArray.h"
+#include "fs/FileSystemConstants.h"
+#include "mozilla/ResultVariant.h"
+#include "mozilla/StaticPrefs_dom.h"
+#include "mozilla/dom/BlobImpl.h"
+#include "mozilla/dom/File.h"
+#include "mozilla/dom/FileSystemAccessHandleChild.h"
+#include "mozilla/dom/FileSystemDirectoryHandle.h"
+#include "mozilla/dom/FileSystemFileHandle.h"
+#include "mozilla/dom/FileSystemHandle.h"
+#include "mozilla/dom/FileSystemHelpers.h"
+#include "mozilla/dom/FileSystemLog.h"
+#include "mozilla/dom/FileSystemManager.h"
+#include "mozilla/dom/FileSystemManagerChild.h"
+#include "mozilla/dom/FileSystemSyncAccessHandle.h"
+#include "mozilla/dom/FileSystemWritableFileStream.h"
+#include "mozilla/dom/FileSystemWritableFileStreamChild.h"
+#include "mozilla/dom/IPCBlobUtils.h"
+#include "mozilla/dom/Promise.h"
+#include "mozilla/dom/quota/QuotaCommon.h"
+
+namespace mozilla::dom::fs {
+
+using mozilla::ipc::RejectCallback;
+
+namespace {
+
+void HandleFailedStatus(nsresult aError, const RefPtr<Promise>& aPromise) {
+ switch (aError) {
+ case NS_ERROR_FILE_ACCESS_DENIED:
+ aPromise->MaybeRejectWithNotAllowedError("Permission denied");
+ break;
+ case NS_ERROR_DOM_NOT_FOUND_ERR:
+ aPromise->MaybeRejectWithNotFoundError("Entry not found");
+ break;
+ case NS_ERROR_DOM_FILESYSTEM_NO_MODIFICATION_ALLOWED_ERR:
+ aPromise->MaybeRejectWithInvalidModificationError("Disallowed by system");
+ break;
+ case NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR:
+ aPromise->MaybeRejectWithNoModificationAllowedError(
+ "No modification allowed");
+ break;
+ case NS_ERROR_DOM_TYPE_MISMATCH_ERR:
+ aPromise->MaybeRejectWithTypeMismatchError("Wrong type");
+ break;
+ case NS_ERROR_DOM_INVALID_MODIFICATION_ERR:
+ aPromise->MaybeRejectWithInvalidModificationError("Invalid modification");
+ break;
+ default:
+ if (NS_FAILED(aError)) {
+ aPromise->MaybeRejectWithUnknownError("Unknown failure");
+ } else {
+ aPromise->MaybeResolveWithUndefined();
+ }
+ break;
+ }
+}
+
+bool MakeResolution(nsIGlobalObject* aGlobal,
+ FileSystemGetEntriesResponse&& aResponse,
+ const bool& /* aResult */,
+ RefPtr<FileSystemEntryMetadataArray>& aSink) {
+ // TODO: Add page size to FileSystemConstants, preallocate and handle overflow
+ const auto& listing = aResponse.get_FileSystemDirectoryListing();
+
+ for (const auto& it : listing.files()) {
+ aSink->AppendElement(it);
+ }
+
+ for (const auto& it : listing.directories()) {
+ aSink->AppendElement(it);
+ }
+
+ return true;
+}
+
+RefPtr<FileSystemDirectoryHandle> MakeResolution(
+ nsIGlobalObject* aGlobal, FileSystemGetHandleResponse&& aResponse,
+ const RefPtr<FileSystemDirectoryHandle>& /* aResult */,
+ RefPtr<FileSystemManager>& aManager) {
+ RefPtr<FileSystemDirectoryHandle> result = new FileSystemDirectoryHandle(
+ aGlobal, aManager,
+ FileSystemEntryMetadata(aResponse.get_EntryId(), kRootName,
+ /* directory */ true));
+ return result;
+}
+
+RefPtr<FileSystemDirectoryHandle> MakeResolution(
+ nsIGlobalObject* aGlobal, FileSystemGetHandleResponse&& aResponse,
+ const RefPtr<FileSystemDirectoryHandle>& /* aResult */, const Name& aName,
+ RefPtr<FileSystemManager>& aManager) {
+ RefPtr<FileSystemDirectoryHandle> result = new FileSystemDirectoryHandle(
+ aGlobal, aManager,
+ FileSystemEntryMetadata(aResponse.get_EntryId(), aName,
+ /* directory */ true));
+
+ return result;
+}
+
+RefPtr<FileSystemFileHandle> MakeResolution(
+ nsIGlobalObject* aGlobal, FileSystemGetHandleResponse&& aResponse,
+ const RefPtr<FileSystemFileHandle>& /* aResult */, const Name& aName,
+ RefPtr<FileSystemManager>& aManager) {
+ RefPtr<FileSystemFileHandle> result = new FileSystemFileHandle(
+ aGlobal, aManager,
+ FileSystemEntryMetadata(aResponse.get_EntryId(), aName,
+ /* directory */ false));
+ return result;
+}
+
+RefPtr<FileSystemSyncAccessHandle> MakeResolution(
+ nsIGlobalObject* aGlobal, FileSystemGetAccessHandleResponse&& aResponse,
+ const RefPtr<FileSystemSyncAccessHandle>& /* aReturns */,
+ const FileSystemEntryMetadata& aMetadata,
+ RefPtr<FileSystemManager>& aManager) {
+ auto& properties = aResponse.get_FileSystemAccessHandleProperties();
+
+ auto* const actor =
+ static_cast<FileSystemAccessHandleChild*>(properties.accessHandleChild());
+
+ QM_TRY_UNWRAP(RefPtr<FileSystemSyncAccessHandle> result,
+ FileSystemSyncAccessHandle::Create(
+ aGlobal, aManager, actor,
+ std::move(properties.streamParams()), aMetadata),
+ nullptr);
+
+ return result;
+}
+
+RefPtr<FileSystemWritableFileStream> MakeResolution(
+ nsIGlobalObject* aGlobal,
+ FileSystemGetWritableFileStreamResponse&& aResponse,
+ const RefPtr<FileSystemWritableFileStream>& /* aReturns */,
+ const FileSystemEntryMetadata& aMetadata,
+ RefPtr<FileSystemManager>& aManager) {
+ const auto& properties =
+ aResponse.get_FileSystemWritableFileStreamProperties();
+
+ auto* const actor = static_cast<FileSystemWritableFileStreamChild*>(
+ properties.writableFileStreamChild());
+
+ RefPtr<FileSystemWritableFileStream> result =
+ FileSystemWritableFileStream::Create(
+ aGlobal, aManager, actor, properties.fileDescriptor(), aMetadata);
+
+ return result;
+}
+
+RefPtr<File> MakeResolution(nsIGlobalObject* aGlobal,
+ FileSystemGetFileResponse&& aResponse,
+ const RefPtr<File>& /* aResult */,
+ const Name& aName,
+ RefPtr<FileSystemManager>& aManager) {
+ auto& fileProperties = aResponse.get_FileSystemFileProperties();
+
+ RefPtr<BlobImpl> blobImpl = IPCBlobUtils::Deserialize(fileProperties.file());
+ MOZ_ASSERT(blobImpl);
+ RefPtr<File> result = File::Create(aGlobal, blobImpl);
+ return result;
+}
+
+template <class TResponse, class... Args>
+void ResolveCallback(
+ TResponse&& aResponse,
+ RefPtr<Promise> aPromise, // NOLINT(performance-unnecessary-value-param)
+ Args&&... args) {
+ MOZ_ASSERT(aPromise);
+ QM_TRY(OkIf(Promise::PromiseState::Pending == aPromise->State()), QM_VOID);
+
+ if (TResponse::Tnsresult == aResponse.type()) {
+ HandleFailedStatus(aResponse.get_nsresult(), aPromise);
+ return;
+ }
+
+ auto resolution = MakeResolution(aPromise->GetParentObject(),
+ std::forward<TResponse>(aResponse),
+ std::forward<Args>(args)...);
+ if (!resolution) {
+ aPromise->MaybeRejectWithUnknownError("Could not complete request");
+ return;
+ }
+
+ aPromise->MaybeResolve(resolution);
+}
+
+template <>
+void ResolveCallback(
+ FileSystemRemoveEntryResponse&& aResponse,
+ RefPtr<Promise> aPromise) { // NOLINT(performance-unnecessary-value-param)
+ MOZ_ASSERT(aPromise);
+ QM_TRY(OkIf(Promise::PromiseState::Pending == aPromise->State()), QM_VOID);
+
+ if (FileSystemRemoveEntryResponse::Tvoid_t == aResponse.type()) {
+ aPromise->MaybeResolveWithUndefined();
+ return;
+ }
+
+ MOZ_ASSERT(FileSystemRemoveEntryResponse::Tnsresult == aResponse.type());
+ HandleFailedStatus(aResponse.get_nsresult(), aPromise);
+}
+
+template <>
+void ResolveCallback(
+ FileSystemMoveEntryResponse&& aResponse,
+ RefPtr<Promise> aPromise) { // NOLINT(performance-unnecessary-value-param)
+ MOZ_ASSERT(aPromise);
+ QM_TRY(OkIf(Promise::PromiseState::Pending == aPromise->State()), QM_VOID);
+
+ MOZ_ASSERT(FileSystemMoveEntryResponse::Tnsresult == aResponse.type());
+ const auto& status = aResponse.get_nsresult();
+ if (NS_OK == status) {
+ aPromise->MaybeResolveWithUndefined();
+ return;
+ }
+ HandleFailedStatus(status, aPromise);
+}
+
+template <>
+void ResolveCallback(FileSystemResolveResponse&& aResponse,
+ // NOLINTNEXTLINE(performance-unnecessary-value-param)
+ RefPtr<Promise> aPromise) {
+ MOZ_ASSERT(aPromise);
+ QM_TRY(OkIf(Promise::PromiseState::Pending == aPromise->State()), QM_VOID);
+
+ if (FileSystemResolveResponse::Tnsresult == aResponse.type()) {
+ HandleFailedStatus(aResponse.get_nsresult(), aPromise);
+ return;
+ }
+
+ auto& maybePath = aResponse.get_MaybeFileSystemPath();
+ if (maybePath.isSome()) {
+ aPromise->MaybeResolve(maybePath.value().path());
+ return;
+ }
+
+ // Spec says if there is no parent/child relationship, return null
+ aPromise->MaybeResolve(JS::NullHandleValue);
+}
+
+template <class TResponse, class TReturns, class... Args,
+ std::enable_if_t<std::is_same<TReturns, void>::value, bool> = true>
+mozilla::ipc::ResolveCallback<TResponse> SelectResolveCallback(
+ RefPtr<Promise> aPromise, // NOLINT(performance-unnecessary-value-param)
+ Args&&... args) {
+ using TOverload = void (*)(TResponse&&, RefPtr<Promise>, Args...);
+ return static_cast<std::function<void(TResponse &&)>>(
+ // NOLINTNEXTLINE(modernize-avoid-bind)
+ std::bind(static_cast<TOverload>(ResolveCallback), std::placeholders::_1,
+ aPromise, std::forward<Args>(args)...));
+}
+
+template <class TResponse, class TReturns, class... Args,
+ std::enable_if_t<!std::is_same<TReturns, void>::value, bool> = true>
+mozilla::ipc::ResolveCallback<TResponse> SelectResolveCallback(
+ RefPtr<Promise> aPromise, // NOLINT(performance-unnecessary-value-param)
+ Args&&... args) {
+ using TOverload =
+ void (*)(TResponse&&, RefPtr<Promise>, const TReturns&, Args...);
+ return static_cast<std::function<void(TResponse &&)>>(
+ // NOLINTNEXTLINE(modernize-avoid-bind)
+ std::bind(static_cast<TOverload>(ResolveCallback), std::placeholders::_1,
+ aPromise, TReturns(), std::forward<Args>(args)...));
+}
+
+// TODO: Find a better way to deal with these errors
+void IPCRejectReporter(mozilla::ipc::ResponseRejectReason aReason) {
+ switch (aReason) {
+ case mozilla::ipc::ResponseRejectReason::ActorDestroyed:
+ // This is ok
+ break;
+ case mozilla::ipc::ResponseRejectReason::HandlerRejected:
+ QM_TRY(OkIf(false), QM_VOID);
+ break;
+ case mozilla::ipc::ResponseRejectReason::ChannelClosed:
+ QM_TRY(OkIf(false), QM_VOID);
+ break;
+ case mozilla::ipc::ResponseRejectReason::ResolverDestroyed:
+ QM_TRY(OkIf(false), QM_VOID);
+ break;
+ case mozilla::ipc::ResponseRejectReason::SendError:
+ QM_TRY(OkIf(false), QM_VOID);
+ break;
+ default:
+ QM_TRY(OkIf(false), QM_VOID);
+ break;
+ }
+}
+
+void RejectCallback(
+ RefPtr<Promise> aPromise, // NOLINT(performance-unnecessary-value-param)
+ mozilla::ipc::ResponseRejectReason aReason) {
+ IPCRejectReporter(aReason);
+ QM_TRY(OkIf(Promise::PromiseState::Pending == aPromise->State()), QM_VOID);
+ aPromise->MaybeRejectWithUndefined();
+}
+
+mozilla::ipc::RejectCallback GetRejectCallback(
+ RefPtr<Promise> aPromise) { // NOLINT(performance-unnecessary-value-param)
+ return static_cast<mozilla::ipc::RejectCallback>(
+ // NOLINTNEXTLINE(modernize-avoid-bind)
+ std::bind(RejectCallback, aPromise, std::placeholders::_1));
+}
+
+struct BeginRequestFailureCallback {
+ explicit BeginRequestFailureCallback(RefPtr<Promise> aPromise)
+ : mPromise(std::move(aPromise)) {}
+
+ void operator()(nsresult aRv) const {
+ if (aRv == NS_ERROR_DOM_SECURITY_ERR) {
+ mPromise->MaybeRejectWithSecurityError(
+ "Security error when calling GetDirectory");
+ return;
+ }
+ mPromise->MaybeRejectWithUnknownError("Could not create actor");
+ }
+
+ RefPtr<Promise> mPromise;
+};
+
+} // namespace
+
+void FileSystemRequestHandler::GetRootHandle(
+ RefPtr<FileSystemManager>
+ aManager, // NOLINT(performance-unnecessary-value-param)
+ RefPtr<Promise> aPromise, // NOLINT(performance-unnecessary-value-param)
+ ErrorResult& aError) {
+ MOZ_ASSERT(aManager);
+ MOZ_ASSERT(aPromise);
+ LOG(("GetRootHandle"));
+
+ if (aManager->IsShutdown()) {
+ aError.Throw(NS_ERROR_ILLEGAL_DURING_SHUTDOWN);
+ return;
+ }
+
+ aManager->BeginRequest(
+ [onResolve = SelectResolveCallback<FileSystemGetHandleResponse,
+ RefPtr<FileSystemDirectoryHandle>>(
+ aPromise, aManager),
+ onReject = GetRejectCallback(aPromise)](const auto& actor) mutable {
+ actor->SendGetRootHandle(std::move(onResolve), std::move(onReject));
+ },
+ BeginRequestFailureCallback(aPromise));
+}
+
+void FileSystemRequestHandler::GetDirectoryHandle(
+ RefPtr<FileSystemManager>& aManager,
+ const FileSystemChildMetadata& aDirectory, bool aCreate,
+ RefPtr<Promise> aPromise, // NOLINT(performance-unnecessary-value-param)
+ ErrorResult& aError) {
+ MOZ_ASSERT(aManager);
+ MOZ_ASSERT(!aDirectory.parentId().IsEmpty());
+ MOZ_ASSERT(aPromise);
+ LOG(("GetDirectoryHandle"));
+
+ if (aManager->IsShutdown()) {
+ aError.Throw(NS_ERROR_ILLEGAL_DURING_SHUTDOWN);
+ return;
+ }
+
+ if (!IsValidName(aDirectory.childName())) {
+ aPromise->MaybeRejectWithTypeError("Invalid directory name");
+ return;
+ }
+
+ aManager->BeginRequest(
+ [request = FileSystemGetHandleRequest(aDirectory, aCreate),
+ onResolve = SelectResolveCallback<FileSystemGetHandleResponse,
+ RefPtr<FileSystemDirectoryHandle>>(
+ aPromise, aDirectory.childName(), aManager),
+ onReject = GetRejectCallback(aPromise)](const auto& actor) mutable {
+ actor->SendGetDirectoryHandle(request, std::move(onResolve),
+ std::move(onReject));
+ },
+ BeginRequestFailureCallback(aPromise));
+}
+
+void FileSystemRequestHandler::GetFileHandle(
+ RefPtr<FileSystemManager>& aManager, const FileSystemChildMetadata& aFile,
+ bool aCreate,
+ RefPtr<Promise> aPromise, // NOLINT(performance-unnecessary-value-param)
+ ErrorResult& aError) {
+ MOZ_ASSERT(aManager);
+ MOZ_ASSERT(!aFile.parentId().IsEmpty());
+ MOZ_ASSERT(aPromise);
+ LOG(("GetFileHandle"));
+
+ if (aManager->IsShutdown()) {
+ aError.Throw(NS_ERROR_ILLEGAL_DURING_SHUTDOWN);
+ return;
+ }
+
+ if (!IsValidName(aFile.childName())) {
+ aPromise->MaybeRejectWithTypeError("Invalid filename");
+ return;
+ }
+
+ aManager->BeginRequest(
+ [request = FileSystemGetHandleRequest(aFile, aCreate),
+ onResolve = SelectResolveCallback<FileSystemGetHandleResponse,
+ RefPtr<FileSystemFileHandle>>(
+ aPromise, aFile.childName(), aManager),
+ onReject = GetRejectCallback(aPromise)](const auto& actor) mutable {
+ actor->SendGetFileHandle(request, std::move(onResolve),
+ std::move(onReject));
+ },
+ BeginRequestFailureCallback(aPromise));
+}
+
+void FileSystemRequestHandler::GetAccessHandle(
+ RefPtr<FileSystemManager>& aManager, const FileSystemEntryMetadata& aFile,
+ const RefPtr<Promise>& aPromise, ErrorResult& aError) {
+ MOZ_ASSERT(aManager);
+ MOZ_ASSERT(aPromise);
+ LOG(("GetAccessHandle %s", NS_ConvertUTF16toUTF8(aFile.entryName()).get()));
+
+ if (aManager->IsShutdown()) {
+ aError.Throw(NS_ERROR_ILLEGAL_DURING_SHUTDOWN);
+ return;
+ }
+
+ aManager->BeginRequest(
+ [request = FileSystemGetAccessHandleRequest(aFile.entryId()),
+ onResolve = SelectResolveCallback<FileSystemGetAccessHandleResponse,
+ RefPtr<FileSystemSyncAccessHandle>>(
+ aPromise, aFile, aManager),
+ onReject = GetRejectCallback(aPromise)](const auto& actor) mutable {
+ actor->SendGetAccessHandle(request, std::move(onResolve),
+ std::move(onReject));
+ },
+ BeginRequestFailureCallback(aPromise));
+}
+
+void FileSystemRequestHandler::GetWritable(RefPtr<FileSystemManager>& aManager,
+ const FileSystemEntryMetadata& aFile,
+ bool aKeepData,
+ const RefPtr<Promise>& aPromise,
+ ErrorResult& aError) {
+ MOZ_ASSERT(aManager);
+ MOZ_ASSERT(aPromise);
+ LOG(("GetWritable %s keep %d", NS_ConvertUTF16toUTF8(aFile.entryName()).get(),
+ aKeepData));
+
+ // XXX This should be removed once bug 1798513 is fixed.
+ if (!StaticPrefs::dom_fs_writable_file_stream_enabled()) {
+ aError.Throw(NS_ERROR_NOT_IMPLEMENTED);
+ return;
+ }
+
+ if (aManager->IsShutdown()) {
+ aError.Throw(NS_ERROR_ILLEGAL_DURING_SHUTDOWN);
+ return;
+ }
+
+ aManager->BeginRequest(
+ [request = FileSystemGetWritableRequest(aFile.entryId(), aKeepData),
+ onResolve =
+ SelectResolveCallback<FileSystemGetWritableFileStreamResponse,
+ RefPtr<FileSystemWritableFileStream>>(
+ aPromise, aFile, aManager),
+ onReject = GetRejectCallback(aPromise)](const auto& actor) mutable {
+ actor->SendGetWritable(request, std::move(onResolve),
+ std::move(onReject));
+ },
+ [promise = aPromise](const auto&) {
+ promise->MaybeRejectWithUnknownError("Could not create actor");
+ });
+}
+
+void FileSystemRequestHandler::GetFile(
+ RefPtr<FileSystemManager>& aManager, const FileSystemEntryMetadata& aFile,
+ RefPtr<Promise> aPromise, // NOLINT(performance-unnecessary-value-param)
+ ErrorResult& aError) {
+ MOZ_ASSERT(aManager);
+ MOZ_ASSERT(!aFile.entryId().IsEmpty());
+ MOZ_ASSERT(aPromise);
+ LOG(("GetFile %s", NS_ConvertUTF16toUTF8(aFile.entryName()).get()));
+
+ if (aManager->IsShutdown()) {
+ aError.Throw(NS_ERROR_ILLEGAL_DURING_SHUTDOWN);
+ return;
+ }
+
+ aManager->BeginRequest(
+ [request = FileSystemGetFileRequest(aFile.entryId()),
+ onResolve =
+ SelectResolveCallback<FileSystemGetFileResponse, RefPtr<File>>(
+ aPromise, aFile.entryName(), aManager),
+ onReject = GetRejectCallback(aPromise)](const auto& actor) mutable {
+ actor->SendGetFile(request, std::move(onResolve), std::move(onReject));
+ },
+ BeginRequestFailureCallback(aPromise));
+}
+
+void FileSystemRequestHandler::GetEntries(
+ RefPtr<FileSystemManager>& aManager, const EntryId& aDirectory,
+ PageNumber aPage,
+ RefPtr<Promise> aPromise, // NOLINT(performance-unnecessary-value-param)
+ RefPtr<FileSystemEntryMetadataArray>& aSink, ErrorResult& aError) {
+ MOZ_ASSERT(aManager);
+ MOZ_ASSERT(!aDirectory.IsEmpty());
+ MOZ_ASSERT(aPromise);
+ LOG(("GetEntries, page %u", aPage));
+
+ if (aManager->IsShutdown()) {
+ aError.Throw(NS_ERROR_ILLEGAL_DURING_SHUTDOWN);
+ return;
+ }
+
+ aManager->BeginRequest(
+ [request = FileSystemGetEntriesRequest(aDirectory, aPage),
+ onResolve = SelectResolveCallback<FileSystemGetEntriesResponse, bool>(
+ aPromise, aSink),
+ onReject = GetRejectCallback(aPromise)](const auto& actor) mutable {
+ actor->SendGetEntries(request, std::move(onResolve),
+ std::move(onReject));
+ },
+ BeginRequestFailureCallback(aPromise));
+}
+
+void FileSystemRequestHandler::RemoveEntry(
+ RefPtr<FileSystemManager>& aManager, const FileSystemChildMetadata& aEntry,
+ bool aRecursive,
+ RefPtr<Promise> aPromise, // NOLINT(performance-unnecessary-value-param)
+ ErrorResult& aError) {
+ MOZ_ASSERT(aManager);
+ MOZ_ASSERT(!aEntry.parentId().IsEmpty());
+ MOZ_ASSERT(aPromise);
+ LOG(("RemoveEntry"));
+
+ if (aManager->IsShutdown()) {
+ aError.Throw(NS_ERROR_ILLEGAL_DURING_SHUTDOWN);
+ return;
+ }
+
+ if (!IsValidName(aEntry.childName())) {
+ aPromise->MaybeRejectWithTypeError("Invalid name");
+ return;
+ }
+
+ aManager->BeginRequest(
+ [request = FileSystemRemoveEntryRequest(aEntry, aRecursive),
+ onResolve =
+ SelectResolveCallback<FileSystemRemoveEntryResponse, void>(aPromise),
+ onReject = GetRejectCallback(aPromise)](const auto& actor) mutable {
+ actor->SendRemoveEntry(request, std::move(onResolve),
+ std::move(onReject));
+ },
+ BeginRequestFailureCallback(aPromise));
+}
+
+void FileSystemRequestHandler::MoveEntry(
+ RefPtr<FileSystemManager>& aManager, FileSystemHandle* aHandle,
+ const FileSystemEntryMetadata& aEntry,
+ const FileSystemChildMetadata& aNewEntry,
+ RefPtr<Promise> aPromise, // NOLINT(performance-unnecessary-value-param)
+ ErrorResult& aError) {
+ MOZ_ASSERT(aPromise);
+ LOG(("MoveEntry"));
+
+ if (aManager->IsShutdown()) {
+ aError.Throw(NS_ERROR_ILLEGAL_DURING_SHUTDOWN);
+ return;
+ }
+
+ // reject invalid names: empty, path separators, current & parent directories
+ if (!IsValidName(aNewEntry.childName())) {
+ aPromise->MaybeRejectWithTypeError("Invalid name");
+ return;
+ }
+
+ aManager->BeginRequest(
+ [request = FileSystemMoveEntryRequest(aEntry, aNewEntry),
+ onResolve =
+ SelectResolveCallback<FileSystemMoveEntryResponse, void>(aPromise),
+ onReject = GetRejectCallback(aPromise)](const auto& actor) mutable {
+ actor->SendMoveEntry(request, std::move(onResolve),
+ std::move(onReject));
+ },
+ BeginRequestFailureCallback(aPromise));
+}
+
+void FileSystemRequestHandler::RenameEntry(
+ RefPtr<FileSystemManager>& aManager, FileSystemHandle* aHandle,
+ const FileSystemEntryMetadata& aEntry, const Name& aName,
+ RefPtr<Promise> aPromise, // NOLINT(performance-unnecessary-value-param)
+ ErrorResult& aError) {
+ MOZ_ASSERT(!aEntry.entryId().IsEmpty());
+ MOZ_ASSERT(aPromise);
+ LOG(("RenameEntry"));
+
+ if (aManager->IsShutdown()) {
+ aError.Throw(NS_ERROR_ILLEGAL_DURING_SHUTDOWN);
+ return;
+ }
+
+ // reject invalid names: empty, path separators, current & parent directories
+ if (!IsValidName(aName)) {
+ aPromise->MaybeRejectWithTypeError("Invalid name");
+ return;
+ }
+
+ aManager->BeginRequest(
+ [request = FileSystemRenameEntryRequest(aEntry, aName),
+ onResolve =
+ SelectResolveCallback<FileSystemMoveEntryResponse, void>(aPromise),
+ onReject = GetRejectCallback(aPromise)](const auto& actor) mutable {
+ actor->SendRenameEntry(request, std::move(onResolve),
+ std::move(onReject));
+ },
+ BeginRequestFailureCallback(aPromise));
+}
+
+void FileSystemRequestHandler::Resolve(
+ RefPtr<FileSystemManager>& aManager,
+ // NOLINTNEXTLINE(performance-unnecessary-value-param)
+ const FileSystemEntryPair& aEndpoints, RefPtr<Promise> aPromise,
+ ErrorResult& aError) {
+ MOZ_ASSERT(aManager);
+ MOZ_ASSERT(!aEndpoints.parentId().IsEmpty());
+ MOZ_ASSERT(!aEndpoints.childId().IsEmpty());
+ MOZ_ASSERT(aPromise);
+ LOG(("Resolve"));
+
+ if (aManager->IsShutdown()) {
+ aError.Throw(NS_ERROR_ILLEGAL_DURING_SHUTDOWN);
+ return;
+ }
+
+ aManager->BeginRequest(
+ [request = FileSystemResolveRequest(aEndpoints),
+ onResolve =
+ SelectResolveCallback<FileSystemResolveResponse, void>(aPromise),
+ onReject = GetRejectCallback(aPromise)](const auto& actor) mutable {
+ actor->SendResolve(request, std::move(onResolve), std::move(onReject));
+ },
+ BeginRequestFailureCallback(aPromise));
+}
+
+} // namespace mozilla::dom::fs
diff --git a/dom/fs/child/FileSystemWritableFileStreamChild.cpp b/dom/fs/child/FileSystemWritableFileStreamChild.cpp
new file mode 100644
index 0000000000..862e8f345e
--- /dev/null
+++ b/dom/fs/child/FileSystemWritableFileStreamChild.cpp
@@ -0,0 +1,39 @@
+/* -*- 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 "FileSystemWritableFileStreamChild.h"
+
+#include "mozilla/dom/FileSystemLog.h"
+#include "mozilla/dom/FileSystemWritableFileStream.h"
+
+namespace mozilla::dom {
+
+FileSystemWritableFileStreamChild::FileSystemWritableFileStreamChild()
+ : mStream(nullptr) {
+ LOG(("Created new WritableFileStreamChild %p", this));
+}
+
+FileSystemWritableFileStreamChild::~FileSystemWritableFileStreamChild() =
+ default;
+
+void FileSystemWritableFileStreamChild::SetStream(
+ FileSystemWritableFileStream* aStream) {
+ MOZ_ASSERT(aStream);
+ MOZ_ASSERT(!mStream);
+
+ mStream = aStream;
+}
+
+void FileSystemWritableFileStreamChild::ActorDestroy(ActorDestroyReason aWhy) {
+ LOG(("Destroy WritableFileStreamChild %p", this));
+
+ if (mStream) {
+ mStream->ClearActor();
+ mStream = nullptr;
+ }
+}
+
+} // namespace mozilla::dom
diff --git a/dom/fs/child/FileSystemWritableFileStreamChild.h b/dom/fs/child/FileSystemWritableFileStreamChild.h
new file mode 100644
index 0000000000..9728fc4c78
--- /dev/null
+++ b/dom/fs/child/FileSystemWritableFileStreamChild.h
@@ -0,0 +1,42 @@
+/* -*- 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_FILESYSTEMWRITABLEFILESTREAM_H_
+#define DOM_FS_CHILD_FILESYSTEMWRITABLEFILESTREAM_H_
+
+#include "mozilla/dom/PFileSystemWritableFileStreamChild.h"
+
+namespace mozilla::dom {
+
+class FileSystemWritableFileStream;
+
+class FileSystemWritableFileStreamChild
+ : public PFileSystemWritableFileStreamChild {
+ public:
+ FileSystemWritableFileStreamChild();
+
+ NS_INLINE_DECL_REFCOUNTING(FileSystemWritableFileStreamChild, override)
+
+ FileSystemWritableFileStream* MutableWritableFileStreamPtr() const {
+ MOZ_ASSERT(mStream);
+ return mStream;
+ }
+
+ void SetStream(FileSystemWritableFileStream* aStream);
+
+ void ActorDestroy(ActorDestroyReason aWhy) override;
+
+ private:
+ virtual ~FileSystemWritableFileStreamChild();
+
+ // Use a weak ref so actor does not hold DOM object alive past content use.
+ // The weak reference is cleared in FileSystemWritableFileStream::LastRelease.
+ FileSystemWritableFileStream* MOZ_NON_OWNING_REF mStream;
+};
+
+} // namespace mozilla::dom
+
+#endif // DOM_FS_CHILD_FILESYSTEMWRITABLEFILESTREAM_H_
diff --git a/dom/fs/child/moz.build b/dom/fs/child/moz.build
new file mode 100644
index 0000000000..7cff598101
--- /dev/null
+++ b/dom/fs/child/moz.build
@@ -0,0 +1,29 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# 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/.
+
+EXPORTS.mozilla.dom += [
+ "FileSystemAccessHandleChild.h",
+ "FileSystemManagerChild.h",
+ "FileSystemWritableFileStreamChild.h",
+]
+
+UNIFIED_SOURCES += [
+ "FileSystemAccessHandleChild.cpp",
+ "FileSystemBackgroundRequestHandler.cpp",
+ "FileSystemChildFactory.cpp",
+ "FileSystemDirectoryIteratorFactory.cpp",
+ "FileSystemManagerChild.cpp",
+ "FileSystemRequestHandler.cpp",
+ "FileSystemWritableFileStreamChild.cpp",
+]
+
+LOCAL_INCLUDES += [
+ "/dom/fs/include",
+]
+
+FINAL_LIBRARY = "xul"
+
+include("/ipc/chromium/chromium-config.mozbuild")