Source code

Revision control

Copy as Markdown

Other Tools

/* -*- 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 "FileSystemParentTypes.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<fs::data::FileSystemDataManager> aDataManager,
const fs::EntryId& aEntryId, MovingNotNull<RefPtr<TaskQueue>> 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::CreatePromise> FileSystemAccessHandle::Create(
RefPtr<fs::data::FileSystemDataManager> aDataManager,
const fs::EntryId& aEntryId) {
MOZ_ASSERT(aDataManager);
aDataManager->AssertIsOnIOTarget();
RefPtr<TaskQueue> ioTaskQueue = TaskQueue::Create(
do_AddRef(aDataManager->MutableIOTargetPtr()), "FileSystemAccessHandle");
RefPtr<FileSystemAccessHandle> accessHandle = new FileSystemAccessHandle(
std::move(aDataManager), aEntryId, WrapMovingNotNull(ioTaskQueue));
return accessHandle->BeginInit()->Then(
GetCurrentSerialEventTarget(), __func__,
[accessHandle = fs::Registered<FileSystemAccessHandle>(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<FileSystemAccessHandleParent*> aActor) {
MOZ_ASSERT(!mActor);
mActor = aActor;
}
void FileSystemAccessHandle::UnregisterActor(
NotNull<FileSystemAccessHandleParent*> aActor) {
MOZ_ASSERT(mActor);
MOZ_ASSERT(mActor == aActor);
mActor = nullptr;
if (IsInactive() && IsOpen()) {
BeginClose();
}
}
void FileSystemAccessHandle::RegisterControlActor(
NotNull<FileSystemAccessHandleControlParent*> aControlActor) {
MOZ_ASSERT(!mControlActor);
mControlActor = aControlActor;
}
void FileSystemAccessHandle::UnregisterControlActor(
NotNull<FileSystemAccessHandleControlParent*> aControlActor) {
MOZ_ASSERT(mControlActor);
MOZ_ASSERT(mControlActor == aControlActor);
mControlActor = nullptr;
if (IsInactive() && IsOpen()) {
BeginClose();
}
}
bool FileSystemAccessHandle::IsOpen() const { return !mClosed; }
RefPtr<BoolPromise> 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::InitPromise>
FileSystemAccessHandle::BeginInit() {
QM_TRY_UNWRAP(fs::FileId fileId, mDataManager->LockExclusive(mEntryId),
[](const auto& aRv) {
return InitPromise::CreateAndReject(ToNSResult(aRv),
__func__);
});
mLocked = true;
auto CreateAndRejectInitPromise = [](const char* aFunc, nsresult aRv) {
return CreateAndRejectMozPromise<InitPromise>(aFunc, aRv);
};
fs::ContentType type;
fs::TimeStamp lastModifiedMilliSeconds;
fs::Path path;
nsCOMPtr<nsIFile> file;
QM_TRY(MOZ_TO_RESULT(mDataManager->MutableDatabaseManagerPtr()->GetFile(
mEntryId, fileId, fs::FileMode::EXCLUSIVE, 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<nsIRandomAccessStream> 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