/* -*- 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 "FileSystemAccessHandle.h" #include "FileSystemDatabaseManager.h" #include "mozilla/Result.h" #include "mozilla/dom/FileSystemDataManager.h" #include "mozilla/dom/FileSystemHelpers.h" #include "mozilla/dom/FileSystemLog.h" #include "mozilla/dom/quota/FileStreams.h" #include "mozilla/dom/quota/QuotaCommon.h" #include "mozilla/dom/quota/RemoteQuotaObjectParent.h" #include "mozilla/dom/quota/ResultExtensions.h" #include "mozilla/ipc/RandomAccessStreamParams.h" #include "mozilla/ipc/RandomAccessStreamUtils.h" #include "nsIFileStreams.h" namespace mozilla::dom { FileSystemAccessHandle::FileSystemAccessHandle( RefPtr aDataManager, const fs::EntryId& aEntryId, MovingNotNull> aIOTaskQueue) : mEntryId(aEntryId), mDataManager(std::move(aDataManager)), mIOTaskQueue(std::move(aIOTaskQueue)), mActor(nullptr), mControlActor(nullptr), mRegCount(0), mLocked(false), mRegistered(false), mClosed(false) {} FileSystemAccessHandle::~FileSystemAccessHandle() { MOZ_DIAGNOSTIC_ASSERT(mClosed); } // static RefPtr FileSystemAccessHandle::Create( RefPtr aDataManager, const fs::EntryId& aEntryId) { MOZ_ASSERT(aDataManager); aDataManager->AssertIsOnIOTarget(); RefPtr ioTaskQueue = TaskQueue::Create( do_AddRef(aDataManager->MutableIOTargetPtr()), "FileSystemAccessHandle"); RefPtr accessHandle = new FileSystemAccessHandle( std::move(aDataManager), aEntryId, WrapMovingNotNull(ioTaskQueue)); return accessHandle->BeginInit()->Then( GetCurrentSerialEventTarget(), __func__, [accessHandle = fs::Registered(accessHandle)]( InitPromise::ResolveOrRejectValue&& value) mutable { if (value.IsReject()) { return CreatePromise::CreateAndReject(value.RejectValue(), __func__); } mozilla::ipc::RandomAccessStreamParams streamParams = std::move(value.ResolveValue()); return CreatePromise::CreateAndResolve( std::pair(std::move(accessHandle), std::move(streamParams)), __func__); }); } NS_IMPL_ISUPPORTS_INHERITED0(FileSystemAccessHandle, FileSystemStreamCallbacks) void FileSystemAccessHandle::Register() { ++mRegCount; } void FileSystemAccessHandle::Unregister() { MOZ_ASSERT(mRegCount > 0); --mRegCount; if (IsInactive() && IsOpen()) { BeginClose(); } } void FileSystemAccessHandle::RegisterActor( NotNull aActor) { MOZ_ASSERT(!mActor); mActor = aActor; } void FileSystemAccessHandle::UnregisterActor( NotNull aActor) { MOZ_ASSERT(mActor); MOZ_ASSERT(mActor == aActor); mActor = nullptr; if (IsInactive() && IsOpen()) { BeginClose(); } } void FileSystemAccessHandle::RegisterControlActor( NotNull aControlActor) { MOZ_ASSERT(!mControlActor); mControlActor = aControlActor; } void FileSystemAccessHandle::UnregisterControlActor( NotNull aControlActor) { MOZ_ASSERT(mControlActor); MOZ_ASSERT(mControlActor == aControlActor); mControlActor = nullptr; if (IsInactive() && IsOpen()) { BeginClose(); } } bool FileSystemAccessHandle::IsOpen() const { return !mClosed; } RefPtr FileSystemAccessHandle::BeginClose() { MOZ_ASSERT(IsOpen()); LOG(("Closing AccessHandle")); mClosed = true; return InvokeAsync(mIOTaskQueue.get(), __func__, [self = RefPtr(this)]() { if (self->mRemoteQuotaObjectParent) { self->mRemoteQuotaObjectParent->Close(); } return BoolPromise::CreateAndResolve(true, __func__); }) ->Then(GetCurrentSerialEventTarget(), __func__, [self = RefPtr(this)](const BoolPromise::ResolveOrRejectValue&) { return self->mIOTaskQueue->BeginShutdown(); }) ->Then( GetCurrentSerialEventTarget(), __func__, [self = RefPtr(this)](const ShutdownPromise::ResolveOrRejectValue&) { if (self->mLocked) { self->mDataManager->UnlockExclusive(self->mEntryId); } return BoolPromise::CreateAndResolve(true, __func__); }) ->Then(mDataManager->MutableBackgroundTargetPtr(), __func__, [self = RefPtr(this)](const BoolPromise::ResolveOrRejectValue&) { if (self->mRegistered) { self->mDataManager->UnregisterAccessHandle(WrapNotNull(self)); } self->mDataManager = nullptr; return BoolPromise::CreateAndResolve(true, __func__); }); } bool FileSystemAccessHandle::IsInactive() const { return !mRegCount && !mActor && !mControlActor; } RefPtr FileSystemAccessHandle::BeginInit() { QM_TRY(MOZ_TO_RESULT(mDataManager->LockExclusive(mEntryId)), [](const nsresult aRv) { return InitPromise::CreateAndReject(aRv, __func__); }); mLocked = true; auto CreateAndRejectInitPromise = [](const char* aFunc, nsresult aRv) { return CreateAndRejectMozPromise(aFunc, aRv); }; fs::ContentType type; fs::TimeStamp lastModifiedMilliSeconds; fs::Path path; nsCOMPtr file; QM_TRY(MOZ_TO_RESULT(mDataManager->MutableDatabaseManagerPtr()->GetFile( mEntryId, type, lastModifiedMilliSeconds, path, file)), CreateAndRejectInitPromise); if (LOG_ENABLED()) { nsAutoString path; if (NS_SUCCEEDED(file->GetPath(path))) { LOG(("Opening SyncAccessHandle %s", NS_ConvertUTF16toUTF8(path).get())); } } return InvokeAsync( mDataManager->MutableBackgroundTargetPtr(), __func__, [self = RefPtr(this)]() { self->mDataManager->RegisterAccessHandle(WrapNotNull(self)); self->mRegistered = true; return BoolPromise::CreateAndResolve(true, __func__); }) ->Then(mIOTaskQueue.get(), __func__, [self = RefPtr(this), CreateAndRejectInitPromise, file = std::move(file)]( const BoolPromise::ResolveOrRejectValue& value) { if (value.IsReject()) { return InitPromise::CreateAndReject(value.RejectValue(), __func__); } QM_TRY_UNWRAP(nsCOMPtr stream, CreateFileRandomAccessStream( quota::PERSISTENCE_TYPE_DEFAULT, self->mDataManager->OriginMetadataRef(), quota::Client::FILESYSTEM, file, -1, -1, nsIFileRandomAccessStream::DEFER_OPEN), CreateAndRejectInitPromise); mozilla::ipc::RandomAccessStreamParams streamParams = mozilla::ipc::SerializeRandomAccessStream( WrapMovingNotNullUnchecked(std::move(stream)), self); return InitPromise::CreateAndResolve(std::move(streamParams), __func__); }); } } // namespace mozilla::dom