summaryrefslogtreecommitdiffstats
path: root/dom/fs/parent/datamodel/FileSystemFileManager.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'dom/fs/parent/datamodel/FileSystemFileManager.cpp')
-rw-r--r--dom/fs/parent/datamodel/FileSystemFileManager.cpp267
1 files changed, 267 insertions, 0 deletions
diff --git a/dom/fs/parent/datamodel/FileSystemFileManager.cpp b/dom/fs/parent/datamodel/FileSystemFileManager.cpp
new file mode 100644
index 0000000000..4a70e634e4
--- /dev/null
+++ b/dom/fs/parent/datamodel/FileSystemFileManager.cpp
@@ -0,0 +1,267 @@
+/* -*- 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 "FileSystemFileManager.h"
+
+#include "FileSystemDataManager.h"
+#include "FileSystemHashSource.h"
+#include "mozilla/Assertions.h"
+#include "mozilla/NotNull.h"
+#include "mozilla/Result.h"
+#include "mozilla/ResultVariant.h"
+#include "mozilla/Unused.h"
+#include "mozilla/dom/quota/QuotaManager.h"
+#include "mozilla/dom/quota/ResultExtensions.h"
+#include "nsCOMPtr.h"
+#include "nsIFile.h"
+#include "nsIFileProtocolHandler.h"
+#include "nsIFileURL.h"
+#include "nsIURIMutator.h"
+#include "nsXPCOM.h"
+
+namespace mozilla::dom::fs::data {
+
+namespace {
+
+constexpr nsLiteralString kDatabaseFileName = u"metadata.sqlite"_ns;
+
+Result<nsCOMPtr<nsIFile>, QMResult> GetFileDestination(
+ const nsCOMPtr<nsIFile>& aTopDirectory, const EntryId& aEntryId) {
+ MOZ_ASSERT(32u == aEntryId.Length());
+
+ nsCOMPtr<nsIFile> destination;
+
+ // nsIFile Clone is not a constant method
+ QM_TRY(QM_TO_RESULT(aTopDirectory->Clone(getter_AddRefs(destination))));
+
+ QM_TRY_UNWRAP(Name encoded, FileSystemHashSource::EncodeHash(aEntryId));
+
+ MOZ_ALWAYS_TRUE(IsAscii(encoded));
+
+ nsString relativePath;
+ relativePath.Append(Substring(encoded, 0, 2));
+
+ QM_TRY(QM_TO_RESULT(destination->AppendRelativePath(relativePath)));
+
+ QM_TRY(QM_TO_RESULT(destination->AppendRelativePath(encoded)));
+
+ return destination;
+}
+
+Result<nsCOMPtr<nsIFile>, QMResult> GetOrCreateFileImpl(
+ const nsAString& aFilePath) {
+ MOZ_ASSERT(!aFilePath.IsEmpty());
+
+ nsCOMPtr<nsIFile> result;
+ QM_TRY(QM_TO_RESULT(NS_NewLocalFile(aFilePath,
+ /* aFollowLinks */ false,
+ getter_AddRefs(result))));
+
+ bool exists = true;
+ QM_TRY(QM_TO_RESULT(result->Exists(&exists)));
+
+ if (!exists) {
+ QM_TRY(QM_TO_RESULT(result->Create(nsIFile::NORMAL_FILE_TYPE, 0644)));
+
+ return result;
+ }
+
+ bool isDirectory = true;
+ QM_TRY(QM_TO_RESULT(result->IsDirectory(&isDirectory)));
+ QM_TRY(OkIf(!isDirectory), Err(QMResult(NS_ERROR_FILE_IS_DIRECTORY)));
+
+ return result;
+}
+
+Result<nsCOMPtr<nsIFile>, QMResult> GetFile(
+ const nsCOMPtr<nsIFile>& aTopDirectory, const EntryId& aEntryId) {
+ MOZ_ASSERT(!aEntryId.IsEmpty());
+
+ QM_TRY_UNWRAP(nsCOMPtr<nsIFile> pathObject,
+ GetFileDestination(aTopDirectory, aEntryId));
+
+ nsString desiredPath;
+ QM_TRY(QM_TO_RESULT(pathObject->GetPath(desiredPath)));
+
+ nsCOMPtr<nsIFile> result;
+ QM_TRY(QM_TO_RESULT(NS_NewLocalFile(desiredPath,
+ /* aFollowLinks */ false,
+ getter_AddRefs(result))));
+
+ return result;
+}
+
+Result<nsCOMPtr<nsIFile>, QMResult> GetOrCreateFile(
+ const nsCOMPtr<nsIFile>& aTopDirectory, const EntryId& aEntryId) {
+ MOZ_ASSERT(!aEntryId.IsEmpty());
+
+ QM_TRY_UNWRAP(nsCOMPtr<nsIFile> pathObject,
+ GetFileDestination(aTopDirectory, aEntryId));
+
+ nsString desiredPath;
+ QM_TRY(QM_TO_RESULT(pathObject->GetPath(desiredPath)));
+
+ QM_TRY_UNWRAP(nsCOMPtr<nsIFile> result, GetOrCreateFileImpl(desiredPath));
+
+ return result;
+}
+
+} // namespace
+
+Result<nsCOMPtr<nsIFile>, QMResult> GetFileSystemDirectory(
+ const Origin& aOrigin) {
+ quota::QuotaManager* quotaManager = quota::QuotaManager::Get();
+ MOZ_ASSERT(quotaManager);
+
+ QM_TRY_UNWRAP(nsCOMPtr<nsIFile> fileSystemDirectory,
+ QM_TO_RESULT_TRANSFORM(quotaManager->GetDirectoryForOrigin(
+ quota::PERSISTENCE_TYPE_DEFAULT, aOrigin)));
+
+ QM_TRY(QM_TO_RESULT(fileSystemDirectory->AppendRelativePath(
+ NS_LITERAL_STRING_FROM_CSTRING(FILESYSTEM_DIRECTORY_NAME))));
+
+ return fileSystemDirectory;
+}
+
+nsresult EnsureFileSystemDirectory(
+ const quota::OriginMetadata& aOriginMetadata) {
+ quota::QuotaManager* quotaManager = quota::QuotaManager::Get();
+ MOZ_ASSERT(quotaManager);
+
+ QM_TRY(MOZ_TO_RESULT(quotaManager->EnsureStorageIsInitialized()));
+
+ QM_TRY(MOZ_TO_RESULT(quotaManager->EnsureTemporaryStorageIsInitialized()));
+
+ QM_TRY_INSPECT(const auto& fileSystemDirectory,
+ quotaManager
+ ->EnsureTemporaryOriginIsInitialized(
+ quota::PERSISTENCE_TYPE_DEFAULT, aOriginMetadata)
+ .map([](const auto& aPair) { return aPair.first; }));
+
+ QM_TRY(QM_TO_RESULT(fileSystemDirectory->AppendRelativePath(
+ NS_LITERAL_STRING_FROM_CSTRING(FILESYSTEM_DIRECTORY_NAME))));
+
+ bool exists = true;
+ QM_TRY(QM_TO_RESULT(fileSystemDirectory->Exists(&exists)));
+
+ if (!exists) {
+ QM_TRY(QM_TO_RESULT(
+ fileSystemDirectory->Create(nsIFile::DIRECTORY_TYPE, 0755)));
+
+ return NS_OK;
+ }
+
+ bool isDirectory = true;
+ QM_TRY(QM_TO_RESULT(fileSystemDirectory->IsDirectory(&isDirectory)));
+ QM_TRY(OkIf(isDirectory), NS_ERROR_FILE_NOT_DIRECTORY);
+
+ return NS_OK;
+}
+
+Result<nsCOMPtr<nsIFile>, QMResult> GetDatabaseFile(const Origin& aOrigin) {
+ MOZ_ASSERT(!aOrigin.IsEmpty());
+
+ QM_TRY_UNWRAP(nsCOMPtr<nsIFile> databaseFile,
+ GetFileSystemDirectory(aOrigin));
+
+ QM_TRY(QM_TO_RESULT(databaseFile->AppendRelativePath(kDatabaseFileName)));
+
+ return databaseFile;
+}
+
+/**
+ * TODO: This is almost identical to the corresponding function of IndexedDB
+ */
+Result<nsCOMPtr<nsIFileURL>, QMResult> GetDatabaseFileURL(
+ const Origin& aOrigin, const int64_t aDirectoryLockId) {
+ MOZ_ASSERT(aDirectoryLockId >= 0);
+
+ QM_TRY_UNWRAP(nsCOMPtr<nsIFile> databaseFile, GetDatabaseFile(aOrigin));
+
+ QM_TRY_INSPECT(
+ const auto& protocolHandler,
+ QM_TO_RESULT_TRANSFORM(MOZ_TO_RESULT_GET_TYPED(
+ nsCOMPtr<nsIProtocolHandler>, MOZ_SELECT_OVERLOAD(do_GetService),
+ NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "file")));
+
+ QM_TRY_INSPECT(const auto& fileHandler,
+ QM_TO_RESULT_TRANSFORM(MOZ_TO_RESULT_GET_TYPED(
+ nsCOMPtr<nsIFileProtocolHandler>,
+ MOZ_SELECT_OVERLOAD(do_QueryInterface), protocolHandler)));
+
+ QM_TRY_INSPECT(const auto& mutator,
+ QM_TO_RESULT_TRANSFORM(MOZ_TO_RESULT_INVOKE_MEMBER_TYPED(
+ nsCOMPtr<nsIURIMutator>, fileHandler, NewFileURIMutator,
+ databaseFile)));
+
+ nsCString directoryLockIdClause = "&directoryLockId="_ns;
+ directoryLockIdClause.AppendInt(aDirectoryLockId);
+
+ nsCOMPtr<nsIFileURL> result;
+ QM_TRY(QM_TO_RESULT(
+ NS_MutateURI(mutator).SetQuery(directoryLockIdClause).Finalize(result)));
+
+ return result;
+}
+
+/* static */
+Result<FileSystemFileManager, QMResult>
+FileSystemFileManager::CreateFileSystemFileManager(
+ nsCOMPtr<nsIFile>&& topDirectory) {
+ return FileSystemFileManager(std::move(topDirectory));
+}
+
+/* static */
+Result<FileSystemFileManager, QMResult>
+FileSystemFileManager::CreateFileSystemFileManager(const Origin& aOrigin) {
+ QM_TRY_UNWRAP(nsCOMPtr<nsIFile> topDirectory,
+ GetFileSystemDirectory(aOrigin));
+
+ return FileSystemFileManager(std::move(topDirectory));
+}
+
+FileSystemFileManager::FileSystemFileManager(nsCOMPtr<nsIFile>&& aTopDirectory)
+ : mTopDirectory(std::move(aTopDirectory)) {}
+
+Result<nsCOMPtr<nsIFile>, QMResult> FileSystemFileManager::GetFile(
+ const EntryId& aEntryId) const {
+ return data::GetFile(mTopDirectory, aEntryId);
+}
+
+Result<nsCOMPtr<nsIFile>, QMResult> FileSystemFileManager::GetOrCreateFile(
+ const EntryId& aEntryId) {
+ return data::GetOrCreateFile(mTopDirectory, aEntryId);
+}
+
+Result<int64_t, QMResult> FileSystemFileManager::RemoveFile(
+ const EntryId& aEntryId) {
+ MOZ_ASSERT(!aEntryId.IsEmpty());
+ QM_TRY_UNWRAP(nsCOMPtr<nsIFile> pathObject,
+ GetFileDestination(mTopDirectory, aEntryId));
+
+ bool exists = false;
+ QM_TRY(QM_TO_RESULT(pathObject->Exists(&exists)));
+
+ if (!exists) {
+ return 0;
+ }
+
+ bool isFile = false;
+ QM_TRY(QM_TO_RESULT(pathObject->IsFile(&isFile)));
+
+ if (!isFile) {
+ return Err(QMResult(NS_ERROR_FILE_IS_DIRECTORY));
+ }
+
+ QM_TRY_UNWRAP(int64_t fileSize,
+ QM_TO_RESULT_INVOKE_MEMBER(pathObject, GetFileSize));
+
+ QM_TRY(QM_TO_RESULT(pathObject->Remove(/* recursive */ false)));
+
+ return fileSize;
+}
+
+} // namespace mozilla::dom::fs::data