/* -*- 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/FileSystemManager.h" #include "FileSystemBackgroundRequestHandler.h" #include "fs/FileSystemRequestHandler.h" #include "mozilla/ErrorResult.h" #include "mozilla/dom/FileSystemManagerChild.h" #include "mozilla/dom/Promise.h" #include "mozilla/dom/StorageManager.h" #include "mozilla/dom/fs/ManagedMozPromiseRequestHolder.h" #include "mozilla/dom/quota/QuotaCommon.h" #include "mozilla/dom/quota/ResultExtensions.h" namespace mozilla::dom { FileSystemManager::FileSystemManager( nsIGlobalObject* aGlobal, RefPtr aStorageManager, RefPtr aBackgroundRequestHandler) : mGlobal(aGlobal), mStorageManager(std::move(aStorageManager)), mBackgroundRequestHandler(std::move(aBackgroundRequestHandler)), mRequestHandler(new fs::FileSystemRequestHandler()) {} FileSystemManager::FileSystemManager(nsIGlobalObject* aGlobal, RefPtr aStorageManager) : FileSystemManager(aGlobal, std::move(aStorageManager), MakeRefPtr()) {} FileSystemManager::~FileSystemManager() { MOZ_ASSERT(mShutdown); } NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(FileSystemManager) NS_INTERFACE_MAP_ENTRY(nsISupports) NS_INTERFACE_MAP_END NS_IMPL_CYCLE_COLLECTING_ADDREF(FileSystemManager); NS_IMPL_CYCLE_COLLECTING_RELEASE(FileSystemManager); NS_IMPL_CYCLE_COLLECTION(FileSystemManager, mGlobal, mStorageManager); void FileSystemManager::Shutdown() { mShutdown.Flip(); auto shutdownAndDisconnect = [self = RefPtr(this)]() { self->mBackgroundRequestHandler->Shutdown(); for (RefPtr> holder : self->mPromiseRequestHolders.ForwardRange()) { holder->DisconnectIfExists(); } }; if (NS_IsMainThread()) { if (mBackgroundRequestHandler->FileSystemManagerChildStrongRef()) { mBackgroundRequestHandler->FileSystemManagerChildStrongRef() ->CloseAllWritables( [shutdownAndDisconnect = std::move(shutdownAndDisconnect)]() { shutdownAndDisconnect(); }); } else { shutdownAndDisconnect(); } } else { if (mBackgroundRequestHandler->FileSystemManagerChildStrongRef()) { // FileSystemAccessHandles and FileSystemWritableFileStreams prevent // shutdown until they are full closed, so at this point, they all should // be closed. MOZ_ASSERT(mBackgroundRequestHandler->FileSystemManagerChildStrongRef() ->AllSyncAccessHandlesClosed()); MOZ_ASSERT(mBackgroundRequestHandler->FileSystemManagerChildStrongRef() ->AllWritableFileStreamsClosed()); } shutdownAndDisconnect(); } } const RefPtr& FileSystemManager::ActorStrongRef() const { return mBackgroundRequestHandler->FileSystemManagerChildStrongRef(); } void FileSystemManager::RegisterPromiseRequestHolder( PromiseRequestHolder* aHolder) { mPromiseRequestHolders.AppendElement(aHolder); } void FileSystemManager::UnregisterPromiseRequestHolder( PromiseRequestHolder* aHolder) { mPromiseRequestHolders.RemoveElement(aHolder); } void FileSystemManager::BeginRequest( std::function&)>&& aSuccess, std::function&& aFailure) { MOZ_ASSERT(!mShutdown); MOZ_ASSERT(mGlobal); // Check if we're allowed to use storage if (mGlobal->GetStorageAccess() < StorageAccess::eSessionScoped) { aFailure(NS_ERROR_DOM_SECURITY_ERR); return; } if (mBackgroundRequestHandler->FileSystemManagerChildStrongRef()) { aSuccess(mBackgroundRequestHandler->FileSystemManagerChildStrongRef()); return; } QM_TRY_INSPECT(const auto& principalInfo, mGlobal->GetStorageKey(), QM_VOID, [&aFailure](nsresult rv) { aFailure(rv); }); auto holder = MakeRefPtr>(this); mBackgroundRequestHandler->CreateFileSystemManagerChild(principalInfo) ->Then(GetCurrentSerialEventTarget(), __func__, [self = RefPtr(this), holder, success = std::move(aSuccess), failure = std::move(aFailure)]( const BoolPromise::ResolveOrRejectValue& aValue) { holder->Complete(); if (aValue.IsResolve()) { success(self->mBackgroundRequestHandler ->FileSystemManagerChildStrongRef()); } else { failure(aValue.RejectValue()); } }) ->Track(*holder); } already_AddRefed FileSystemManager::GetDirectory(ErrorResult& aError) { MOZ_ASSERT(mGlobal); RefPtr promise = Promise::Create(mGlobal, aError); if (NS_WARN_IF(aError.Failed())) { return nullptr; } MOZ_ASSERT(promise); mRequestHandler->GetRootHandle(this, promise, aError); if (NS_WARN_IF(aError.Failed())) { return nullptr; } return promise.forget(); } } // namespace mozilla::dom