diff options
author | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2022-09-29 16:16:15 +0200 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2022-11-09 10:04:06 +0000 |
commit | a95a7417ad456115a1ef2da4bb8320531c0821f1 (patch) | |
tree | edcd59279e486d2fd4a8f88a7ed025bcf925c6e6 /chromium/storage | |
parent | 33fc33aa94d4add0878ec30dc818e34e1dd3cc2a (diff) | |
download | qtwebengine-chromium-a95a7417ad456115a1ef2da4bb8320531c0821f1.tar.gz |
BASELINE: Update Chromium to 106.0.5249.126
Change-Id: Ib0bb21c437a7d1686e21c33f2d329f2ac425b7ab
Reviewed-on: https://codereview.qt-project.org/c/qt/qtwebengine-chromium/+/438936
Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
Diffstat (limited to 'chromium/storage')
70 files changed, 1856 insertions, 2447 deletions
diff --git a/chromium/storage/browser/BUILD.gn b/chromium/storage/browser/BUILD.gn index f6fabb8c1f3..9c1badd60e5 100644 --- a/chromium/storage/browser/BUILD.gn +++ b/chromium/storage/browser/BUILD.gn @@ -145,8 +145,6 @@ component("browser") { "file_system/obfuscated_file_util_memory_delegate.cc", "file_system/obfuscated_file_util_memory_delegate.h", "file_system/open_file_system_mode.h", - "file_system/plugin_private_file_system_backend.cc", - "file_system/plugin_private_file_system_backend.h", "file_system/quota/open_file_handle.cc", "file_system/quota/open_file_handle.h", "file_system/quota/open_file_handle_context.cc", @@ -320,7 +318,6 @@ source_set("unittests") { "file_system/native_file_util_unittest.cc", "file_system/obfuscated_file_util_memory_delegate_unittest.cc", "file_system/obfuscated_file_util_unittest.cc", - "file_system/plugin_private_file_system_backend_unittest.cc", "file_system/quota/quota_backend_impl_unittest.cc", "file_system/quota/quota_reservation_manager_unittest.cc", "file_system/recursive_operation_delegate_unittest.cc", diff --git a/chromium/storage/browser/blob/README.md b/chromium/storage/browser/blob/README.md index 3543ed45e10..2e346f0a4a9 100644 --- a/chromium/storage/browser/blob/README.md +++ b/chromium/storage/browser/blob/README.md @@ -97,7 +97,7 @@ system partition. **Minimum Disk Availability** -We limit our disk limit to accomidate a minimum disk availability. The equation +We limit our disk limit to accommodate a minimum disk availability. The equation we use is: `min_disk_availability = in_memory_limit * 2` diff --git a/chromium/storage/browser/blob/blob_memory_controller.cc b/chromium/storage/browser/blob/blob_memory_controller.cc index f5d1e16a3b5..87c87f83d83 100644 --- a/chromium/storage/browser/blob/blob_memory_controller.cc +++ b/chromium/storage/browser/blob/blob_memory_controller.cc @@ -82,11 +82,11 @@ File::Error CreateBlobDirectory(const FilePath& blob_storage_dir) { BlobStorageLimits CalculateBlobStorageLimitsImpl( const FilePath& storage_dir, bool disk_enabled, - absl::optional<int64_t> optional_memory_size_for_testing) { + absl::optional<uint64_t> optional_memory_size_for_testing) { int64_t disk_size = 0ull; - int64_t memory_size = optional_memory_size_for_testing - ? optional_memory_size_for_testing.value() - : base::SysInfo::AmountOfPhysicalMemory(); + uint64_t memory_size = optional_memory_size_for_testing + ? optional_memory_size_for_testing.value() + : base::SysInfo::AmountOfPhysicalMemory(); if (disk_enabled && CreateBlobDirectory(storage_dir) == base::File::FILE_OK) disk_size = base::SysInfo::AmountOfTotalDiskSpace(storage_dir); @@ -99,9 +99,9 @@ BlobStorageLimits CalculateBlobStorageLimitsImpl( constexpr size_t kTwoGigabytes = 2ull * 1024 * 1024 * 1024; limits.max_blob_in_memory_space = kTwoGigabytes; #elif BUILDFLAG(IS_ANDROID) - limits.max_blob_in_memory_space = static_cast<size_t>(memory_size / 100ll); + limits.max_blob_in_memory_space = static_cast<size_t>(memory_size / 100); #else - limits.max_blob_in_memory_space = static_cast<size_t>(memory_size / 5ll); + limits.max_blob_in_memory_space = static_cast<size_t>(memory_size / 5); #endif } // Devices just on the edge (RAM == 256MB) should not fail because diff --git a/chromium/storage/browser/blob/blob_memory_controller.h b/chromium/storage/browser/blob/blob_memory_controller.h index ecb449b88b7..168c100e2ef 100644 --- a/chromium/storage/browser/blob/blob_memory_controller.h +++ b/chromium/storage/browser/blob/blob_memory_controller.h @@ -204,7 +204,7 @@ class COMPONENT_EXPORT(STORAGE_BROWSER) BlobMemoryController { // synchronously. void CallWhenStorageLimitsAreKnown(base::OnceClosure callback); - void set_amount_of_physical_memory_for_testing(int64_t amount_of_memory) { + void set_amount_of_physical_memory_for_testing(uint64_t amount_of_memory) { amount_of_memory_for_testing_ = amount_of_memory; } @@ -283,7 +283,7 @@ class COMPONENT_EXPORT(STORAGE_BROWSER) BlobMemoryController { bool did_calculate_storage_limits_ = false; std::vector<base::OnceClosure> on_calculate_limits_callbacks_; - absl::optional<int64_t> amount_of_memory_for_testing_; + absl::optional<uint64_t> amount_of_memory_for_testing_; // Memory bookkeeping. These numbers are all disjoint. // This is the amount of memory we're using for blobs in RAM, including the diff --git a/chromium/storage/browser/blob/blob_registry_impl.cc b/chromium/storage/browser/blob/blob_registry_impl.cc index 5285bab2d36..9388dc90a66 100644 --- a/chromium/storage/browser/blob/blob_registry_impl.cc +++ b/chromium/storage/browser/blob/blob_registry_impl.cc @@ -51,7 +51,6 @@ class BlobRegistryImpl::BlobUnderConstruction { ElementEntry& operator=(ElementEntry&& other) = default; blink::mojom::DataElementPtr element; - FileSystemURL filesystem_url; mojo::Remote<blink::mojom::BytesProvider> bytes_provider; mojo::Remote<blink::mojom::Blob> blob; }; @@ -385,13 +384,6 @@ void BlobRegistryImpl::BlobUnderConstruction::ResolvedAllBlobDependencies() { builder_->AppendFile( f->path, f->offset, f->length, f->expected_modification_time.value_or(base::Time())); - } else if (element->is_file_filesystem()) { - DCHECK(entry.filesystem_url.is_valid()); - const auto& f = element->get_file_filesystem(); - builder_->AppendFileSystemFile( - entry.filesystem_url, f->offset, f->length, - f->expected_modification_time.value_or(base::Time()), - blob_registry_->file_system_context_); } else if (element->is_blob()) { DCHECK(blob_uuid_it != referenced_blob_uuids_.end()); const std::string& blob_uuid = *blob_uuid_it++; @@ -501,10 +493,8 @@ bool BlobRegistryImpl::BlobUnderConstruction::ContainsCycles( BlobRegistryImpl::BlobRegistryImpl( base::WeakPtr<BlobStorageContext> context, base::WeakPtr<BlobUrlRegistry> url_registry, - scoped_refptr<base::TaskRunner> url_registry_runner, - scoped_refptr<FileSystemContext> file_system_context) + scoped_refptr<base::TaskRunner> url_registry_runner) : context_(std::move(context)), - file_system_context_(std::move(file_system_context)), url_registry_(std::move(url_registry)), url_registry_runner_(std::move(url_registry_runner)) {} @@ -558,25 +548,6 @@ void BlobRegistryImpl::Register( std::move(callback).Run(); return; } - } else if (entry.element->is_file_filesystem()) { - const GURL crack_url = entry.element->get_file_filesystem()->url; - // TODO(https://crbug.com/1221308): determine whether StorageKey should be - // replaced with a more meaningful value - const blink::StorageKey crack_storage_key = - blink::StorageKey(url::Origin::Create(crack_url)); - entry.filesystem_url = - file_system_context_->CrackURL(crack_url, crack_storage_key); - if (!entry.filesystem_url.is_valid() || - !file_system_context_->GetFileSystemBackend( - entry.filesystem_url.type()) || - !delegate->CanReadFileSystemFile(entry.filesystem_url)) { - std::unique_ptr<BlobDataHandle> handle = context_->AddBrokenBlob( - uuid, content_type, content_disposition, - BlobStatus::ERR_REFERENCED_FILE_UNAVAILABLE); - BlobImpl::Create(std::move(handle), std::move(blob)); - std::move(callback).Run(); - return; - } } element_entries.push_back(std::move(entry)); } diff --git a/chromium/storage/browser/blob/blob_registry_impl.h b/chromium/storage/browser/blob/blob_registry_impl.h index 866dac0921d..1ce62bd0e62 100644 --- a/chromium/storage/browser/blob/blob_registry_impl.h +++ b/chromium/storage/browser/blob/blob_registry_impl.h @@ -12,16 +12,18 @@ #include "mojo/public/cpp/bindings/receiver_set.h" #include "mojo/public/cpp/bindings/self_owned_associated_receiver.h" #include "storage/browser/blob/blob_url_registry.h" -#include "storage/browser/file_system/file_system_context.h" #include "third_party/blink/public/mojom/blob/blob_registry.mojom.h" #include "url/origin.h" +namespace base { +class FilePath; +} + namespace storage { class BlobBuilderFromStream; class BlobDataHandle; class BlobStorageContext; -class FileSystemURL; class COMPONENT_EXPORT(STORAGE_BROWSER) BlobRegistryImpl : public blink::mojom::BlobRegistry { @@ -32,14 +34,12 @@ class COMPONENT_EXPORT(STORAGE_BROWSER) BlobRegistryImpl public: virtual ~Delegate() {} virtual bool CanReadFile(const base::FilePath& file) = 0; - virtual bool CanReadFileSystemFile(const FileSystemURL& url) = 0; virtual bool CanAccessDataForOrigin(const url::Origin& origin) = 0; }; BlobRegistryImpl(base::WeakPtr<BlobStorageContext> context, base::WeakPtr<BlobUrlRegistry> url_registry, - scoped_refptr<base::TaskRunner> url_registry_runner, - scoped_refptr<FileSystemContext> file_system_context); + scoped_refptr<base::TaskRunner> url_registry_runner); BlobRegistryImpl(const BlobRegistryImpl&) = delete; BlobRegistryImpl& operator=(const BlobRegistryImpl&) = delete; @@ -96,7 +96,6 @@ class COMPONENT_EXPORT(STORAGE_BROWSER) BlobRegistryImpl std::unique_ptr<BlobDataHandle> result); base::WeakPtr<BlobStorageContext> context_; - scoped_refptr<FileSystemContext> file_system_context_; // `url_registry_` should only be accessed on `url_registry_runner_`. base::WeakPtr<BlobUrlRegistry> url_registry_; diff --git a/chromium/storage/browser/blob/blob_registry_impl_unittest.cc b/chromium/storage/browser/blob/blob_registry_impl_unittest.cc index 112ef4099b3..30d8db2563e 100644 --- a/chromium/storage/browser/blob/blob_registry_impl_unittest.cc +++ b/chromium/storage/browser/blob/blob_registry_impl_unittest.cc @@ -74,19 +74,9 @@ class BlobRegistryImplTest : public testing::Test { data_dir_.GetPath(), data_dir_.GetPath(), base::ThreadPool::CreateTaskRunner({base::MayBlock()})); auto storage_policy = base::MakeRefCounted<MockSpecialStoragePolicy>(); - file_system_context_ = FileSystemContext::Create( - base::ThreadTaskRunnerHandle::Get(), - base::ThreadTaskRunnerHandle::Get(), - /*external_mount_points=*/nullptr, std::move(storage_policy), - /*quota_manager_proxy=*/nullptr, - std::vector<std::unique_ptr<FileSystemBackend>>(), - std::vector<URLRequestAutoMountHandler>(), data_dir_.GetPath(), - FileSystemOptions(FileSystemOptions::PROFILE_MODE_INCOGNITO, - /*force_in_memory=*/false, - std::vector<std::string>())); registry_impl_ = std::make_unique<BlobRegistryImpl>( context_->AsWeakPtr(), url_registry_.AsWeakPtr(), - base::SequencedTaskRunnerHandle::Get(), file_system_context_); + base::SequencedTaskRunnerHandle::Get()); auto delegate = std::make_unique<MockBlobRegistryDelegate>(); delegate_ptr_ = delegate.get(); registry_impl_->Bind(registry_.BindNewPipeAndPassReceiver(), @@ -194,7 +184,6 @@ class BlobRegistryImplTest : public testing::Test { base::test::TaskEnvironment task_environment_; absl::optional<base::ScopedDisallowBlocking> disallow_blocking_; std::unique_ptr<BlobStorageContext> context_; - scoped_refptr<FileSystemContext> file_system_context_; BlobUrlRegistry url_registry_; std::unique_ptr<BlobRegistryImpl> registry_impl_; mojo::Remote<blink::mojom::BlobRegistry> registry_; @@ -630,82 +619,6 @@ TEST_F(BlobRegistryImplTest, Register_ValidFile) { EXPECT_EQ(0u, BlobsUnderConstruction()); } -TEST_F(BlobRegistryImplTest, Register_FileSystemFile_InvalidScheme) { - const std::string kId = "id"; - - std::vector<blink::mojom::DataElementPtr> elements; - elements.push_back(blink::mojom::DataElement::NewFileFilesystem( - blink::mojom::DataElementFilesystemURL::New(GURL("http://foobar.com/"), 0, - 16, absl::nullopt))); - - mojo::PendingRemote<blink::mojom::Blob> blob; - EXPECT_TRUE(registry_->Register(blob.InitWithNewPipeAndPassReceiver(), kId, - "", "", std::move(elements))); - EXPECT_TRUE(bad_messages_.empty()); - - std::unique_ptr<BlobDataHandle> handle = context_->GetBlobDataFromUUID(kId); - WaitForBlobCompletion(handle.get()); - - EXPECT_TRUE(handle->IsBroken()); - EXPECT_EQ(BlobStatus::ERR_REFERENCED_FILE_UNAVAILABLE, - handle->GetBlobStatus()); - EXPECT_EQ(0u, BlobsUnderConstruction()); -} - -TEST_F(BlobRegistryImplTest, Register_FileSystemFile_UnreadableFile) { - delegate_ptr_->can_read_file_system_file_result = false; - - const std::string kId = "id"; - const GURL url("filesystem:http://example.com/temporary/myfile.png"); - - std::vector<blink::mojom::DataElementPtr> elements; - elements.push_back(blink::mojom::DataElement::NewFileFilesystem( - blink::mojom::DataElementFilesystemURL::New(url, 0, 16, absl::nullopt))); - - mojo::PendingRemote<blink::mojom::Blob> blob; - EXPECT_TRUE(registry_->Register(blob.InitWithNewPipeAndPassReceiver(), kId, - "", "", std::move(elements))); - EXPECT_TRUE(bad_messages_.empty()); - - std::unique_ptr<BlobDataHandle> handle = context_->GetBlobDataFromUUID(kId); - WaitForBlobCompletion(handle.get()); - - EXPECT_TRUE(handle->IsBroken()); - EXPECT_EQ(BlobStatus::ERR_REFERENCED_FILE_UNAVAILABLE, - handle->GetBlobStatus()); - EXPECT_EQ(0u, BlobsUnderConstruction()); -} - -TEST_F(BlobRegistryImplTest, Register_FileSystemFile_Valid) { - delegate_ptr_->can_read_file_system_file_result = true; - - const std::string kId = "id"; - const GURL url("filesystem:http://example.com/temporary/myfile.png"); - - std::vector<blink::mojom::DataElementPtr> elements; - elements.push_back(blink::mojom::DataElement::NewFileFilesystem( - blink::mojom::DataElementFilesystemURL::New(url, 0, 16, absl::nullopt))); - - mojo::PendingRemote<blink::mojom::Blob> blob; - EXPECT_TRUE(registry_->Register(blob.InitWithNewPipeAndPassReceiver(), kId, - "", "", std::move(elements))); - EXPECT_TRUE(bad_messages_.empty()); - - std::unique_ptr<BlobDataHandle> handle = context_->GetBlobDataFromUUID(kId); - WaitForBlobCompletion(handle.get()); - - EXPECT_FALSE(handle->IsBroken()); - ASSERT_EQ(BlobStatus::DONE, handle->GetBlobStatus()); - - BlobDataBuilder expected_blob_data(kId); - expected_blob_data.AppendFileSystemFile( - file_system_context_->CrackURLInFirstPartyContext(url), 0, 16, - base::Time(), file_system_context_); - - EXPECT_EQ(expected_blob_data, *handle->CreateSnapshot()); - EXPECT_EQ(0u, BlobsUnderConstruction()); -} - TEST_F(BlobRegistryImplTest, Register_BytesInvalidEmbeddedData) { const std::string kId = "id"; diff --git a/chromium/storage/browser/blob/blob_transport_strategy.h b/chromium/storage/browser/blob/blob_transport_strategy.h index 1985be83ce3..ee3b4216a43 100644 --- a/chromium/storage/browser/blob/blob_transport_strategy.h +++ b/chromium/storage/browser/blob/blob_transport_strategy.h @@ -51,7 +51,7 @@ class COMPONENT_EXPORT(STORAGE_BROWSER) BlobTransportStrategy { BlobTransportStrategy(BlobDataBuilder* builder, ResultCallback result_callback); - raw_ptr<BlobDataBuilder> builder_; + raw_ptr<BlobDataBuilder, DanglingUntriaged> builder_; ResultCallback result_callback_; }; diff --git a/chromium/storage/browser/file_system/README.md b/chromium/storage/browser/file_system/README.md index ed65fa5bb4e..f09da8339db 100644 --- a/chromium/storage/browser/file_system/README.md +++ b/chromium/storage/browser/file_system/README.md @@ -78,9 +78,9 @@ It owns: specific "sync" file system. - Via `scoped_refptr` a bunch of `FileSystemBackend` instances. These - are either created by the `FileSystemContext` itself (for sandbox, plugin - private, and isolated file systems) or passed in to constructor after - requesting the additional backends from the content embedder via + are either created by the `FileSystemContext` itself (for sandbox and + isolated file systems) or passed in to constructor after requesting the + additional backends from the content embedder via `ContentBrowserClient::GetAdditionalFileSystemBackends`. And further more it references: diff --git a/chromium/storage/browser/file_system/copy_or_move_file_validator_unittest.cc b/chromium/storage/browser/file_system/copy_or_move_file_validator_unittest.cc index b09f6497a44..33965975dc8 100644 --- a/chromium/storage/browser/file_system/copy_or_move_file_validator_unittest.cc +++ b/chromium/storage/browser/file_system/copy_or_move_file_validator_unittest.cc @@ -24,8 +24,9 @@ #include "storage/browser/file_system/file_system_context.h" #include "storage/browser/file_system/file_system_url.h" #include "storage/browser/file_system/isolated_context.h" -#include "storage/browser/quota/quota_manager_proxy.h" #include "storage/browser/test/async_file_test_helper.h" +#include "storage/browser/test/mock_quota_manager.h" +#include "storage/browser/test/mock_quota_manager_proxy.h" #include "storage/browser/test/mock_special_storage_policy.h" #include "storage/browser/test/test_file_system_backend.h" #include "storage/browser/test/test_file_system_context.h" @@ -71,8 +72,14 @@ class CopyOrMoveFileValidatorTestHelper { ASSERT_TRUE(base_.CreateUniqueTempDir()); base::FilePath base_dir = base_.GetPath(); - file_system_context_ = CreateFileSystemContextForTesting( - /*quota_manager_proxy=*/nullptr, base_dir); + quota_manager_ = base::MakeRefCounted<storage::MockQuotaManager>( + /*is_incognito=*/false, base_dir, base::ThreadTaskRunnerHandle::Get(), + base::MakeRefCounted<storage::MockSpecialStoragePolicy>()); + quota_manager_proxy_ = base::MakeRefCounted<storage::MockQuotaManagerProxy>( + quota_manager_.get(), base::ThreadTaskRunnerHandle::Get()); + // Prepare file system. + file_system_context_ = storage::CreateFileSystemContextForTesting( + quota_manager_proxy_.get(), base_dir); // Set up TestFileSystemBackend to require CopyOrMoveFileValidator. FileSystemBackend* test_file_system_backend = @@ -187,6 +194,8 @@ class CopyOrMoveFileValidatorTestHelper { std::string dest_fsid_; base::test::TaskEnvironment task_environment_; + scoped_refptr<storage::MockQuotaManager> quota_manager_; + scoped_refptr<storage::MockQuotaManagerProxy> quota_manager_proxy_; scoped_refptr<FileSystemContext> file_system_context_; FileSystemURL copy_src_; diff --git a/chromium/storage/browser/file_system/copy_or_move_operation_delegate.cc b/chromium/storage/browser/file_system/copy_or_move_operation_delegate.cc index b7d0cbd0649..eb8f73fa1dd 100644 --- a/chromium/storage/browser/file_system/copy_or_move_operation_delegate.cc +++ b/chromium/storage/browser/file_system/copy_or_move_operation_delegate.cc @@ -1204,8 +1204,11 @@ FileSystemURL CopyOrMoveOperationDelegate::CreateDestURL( base::FilePath relative = dest_root_.virtual_path(); src_root_.virtual_path().AppendRelativePath(src_url.virtual_path(), &relative); - return file_system_context()->CreateCrackedFileSystemURL( + FileSystemURL dest_url = file_system_context()->CreateCrackedFileSystemURL( dest_root_.storage_key(), dest_root_.mount_type(), relative); + if (dest_root_.bucket().has_value()) + dest_url.SetBucket(dest_root_.bucket().value()); + return dest_url; } } // namespace storage diff --git a/chromium/storage/browser/file_system/copy_or_move_operation_delegate_unittest.cc b/chromium/storage/browser/file_system/copy_or_move_operation_delegate_unittest.cc index cfb4b552cb2..d351e279b99 100644 --- a/chromium/storage/browser/file_system/copy_or_move_operation_delegate_unittest.cc +++ b/chromium/storage/browser/file_system/copy_or_move_operation_delegate_unittest.cc @@ -629,8 +629,9 @@ class CopyOrMoveOperationTestHelper { private: void GetUsageAndQuota(FileSystemType type, int64_t* usage, int64_t* quota) { blink::mojom::QuotaStatusCode status = - AsyncFileTestHelper::GetUsageAndQuota(quota_manager_->proxy(), origin_, - type, usage, quota); + AsyncFileTestHelper::GetUsageAndQuota(quota_manager_->proxy(), + blink::StorageKey(origin_), type, + usage, quota); ASSERT_EQ(blink::mojom::QuotaStatusCode::kOk, status); } @@ -684,7 +685,6 @@ TEST_P(LocalFileSystemCopyOrMoveOperationTest, SingleFile) { FileSystemURL src = helper.SourceURL("a"); FileSystemURL dest = helper.DestURL("b"); int64_t src_initial_usage = helper.GetSourceUsage(); - int64_t dest_initial_usage = helper.GetDestUsage(); // Set up a source file. ASSERT_EQ(base::File::FILE_OK, helper.CreateFile(src, 10)); @@ -716,20 +716,11 @@ TEST_P(LocalFileSystemCopyOrMoveOperationTest, SingleFile) { ASSERT_EQ(src_should_exist, helper.FileExists(src, 10)); ASSERT_EQ(dest_should_exist, helper.FileExists(dest, 10)); - if (IsLocal()) { - int64_t src_new_usage = helper.GetSourceUsage(); - if (IsMove() || BlockingEnabled()) { - EXPECT_EQ(src_new_usage, src_initial_usage + src_increase); - } else { - EXPECT_EQ(src_new_usage, src_initial_usage + 2 * src_increase); - } + int64_t src_new_usage = helper.GetSourceUsage(); + if (IsMove() || BlockingEnabled()) { + EXPECT_EQ(src_new_usage, src_initial_usage + src_increase); } else { - int64_t src_new_usage = helper.GetSourceUsage(); - ASSERT_EQ(src_new_usage, - src_initial_usage + (src_should_exist ? src_increase : 0)); - int64_t dest_new_usage = helper.GetDestUsage(); - ASSERT_EQ(dest_new_usage, - dest_initial_usage + (dest_should_exist ? src_increase : 0)); + EXPECT_EQ(src_new_usage, src_initial_usage + 2 * src_increase); } } @@ -742,7 +733,6 @@ TEST_P(LocalFileSystemCopyOrMoveOperationTest, EmptyDirectory) { FileSystemURL src = helper.SourceURL("a"); FileSystemURL dest = helper.DestURL("b"); int64_t src_initial_usage = helper.GetSourceUsage(); - int64_t dest_initial_usage = helper.GetDestUsage(); // Set up a source directory. ASSERT_EQ(base::File::FILE_OK, helper.CreateDirectory(src)); @@ -774,20 +764,11 @@ TEST_P(LocalFileSystemCopyOrMoveOperationTest, EmptyDirectory) { ASSERT_EQ(src_should_exist, helper.DirectoryExists(src)); ASSERT_EQ(dest_should_exist, helper.DirectoryExists(dest)); - if (IsLocal()) { - int64_t src_new_usage = helper.GetSourceUsage(); - if (IsMove() || BlockingEnabled()) { - EXPECT_EQ(src_new_usage, src_initial_usage + src_increase); - } else { - EXPECT_EQ(src_new_usage, src_initial_usage + 2 * src_increase); - } + int64_t src_new_usage = helper.GetSourceUsage(); + if (IsMove() || BlockingEnabled()) { + EXPECT_EQ(src_new_usage, src_initial_usage + src_increase); } else { - int64_t src_new_usage = helper.GetSourceUsage(); - int64_t dest_new_usage = helper.GetDestUsage(); - ASSERT_EQ(src_new_usage, - src_initial_usage + (src_should_exist ? src_increase : 0)); - ASSERT_EQ(dest_new_usage, - dest_initial_usage + (dest_should_exist ? src_increase : 0)); + EXPECT_EQ(src_new_usage, src_initial_usage + 2 * src_increase); } } @@ -800,7 +781,6 @@ TEST_P(LocalFileSystemCopyOrMoveOperationTest, FilesAndDirectories) { FileSystemURL src = helper.SourceURL("a"); FileSystemURL dest = helper.DestURL("b"); int64_t src_initial_usage = helper.GetSourceUsage(); - int64_t dest_initial_usage = helper.GetDestUsage(); // Set up a source directory. ASSERT_EQ(base::File::FILE_OK, helper.CreateDirectory(src)); @@ -873,37 +853,15 @@ TEST_P(LocalFileSystemCopyOrMoveOperationTest, FilesAndDirectories) { CopyOrMoveOperationTestHelper::VerifyDirectoryState::ALL_FILES_EXIST); } - if (IsLocal()) { - // For local operations we can only check the size if there is no blocking - // involved. - if (!BlockingEnabled()) { - int64_t src_new_usage = helper.GetSourceUsage(); - if (IsMove()) { - ASSERT_EQ(src_initial_usage + src_increase, src_new_usage); - } else { - // Copies duplicate used size on common file system. - ASSERT_EQ(src_initial_usage + 2 * src_increase, src_new_usage); - } - } - } else { + // For local operations we can only check the size if there is no blocking + // involved. + if (!BlockingEnabled()) { int64_t src_new_usage = helper.GetSourceUsage(); - if (!IsMove()) { - // For copies, all source files should remain. + if (IsMove()) { ASSERT_EQ(src_initial_usage + src_increase, src_new_usage); - } else if (!BlockingEnabled()) { - // For moves without blocking, additional source size should be zero. - ASSERT_EQ(src_initial_usage, src_new_usage); } else { - // For moves with blocking, some files should be blocked and remain on the - // source file system. - ASSERT_LT(src_initial_usage, src_new_usage); - } - - int64_t dest_increase = helper.GetDestUsage() - dest_initial_usage; - if (!BlockingEnabled()) { - ASSERT_EQ(src_increase, dest_increase); - } else { - ASSERT_GT(src_increase, dest_increase); + // Copies duplicate used size on common file system. + ASSERT_EQ(src_initial_usage + 2 * src_increase, src_new_usage); } } } @@ -1348,8 +1306,14 @@ class CopyOrMoveOperationDelegateTestHelper { void SetUp() { ASSERT_TRUE(base_.CreateUniqueTempDir()); base::FilePath base_dir = base_.GetPath(); - file_system_context_ = - storage::CreateFileSystemContextForTesting(nullptr, base_dir); + quota_manager_ = base::MakeRefCounted<storage::MockQuotaManager>( + /*is_incognito=*/false, base_dir, base::ThreadTaskRunnerHandle::Get(), + base::MakeRefCounted<storage::MockSpecialStoragePolicy>()); + quota_manager_proxy_ = base::MakeRefCounted<storage::MockQuotaManagerProxy>( + quota_manager_.get(), base::ThreadTaskRunnerHandle::Get()); + // Prepare file system. + file_system_context_ = storage::CreateFileSystemContextForTesting( + quota_manager_proxy_.get(), base_dir); // Prepare the origin's root directory. FileSystemBackend* backend = @@ -1452,6 +1416,8 @@ class CopyOrMoveOperationDelegateTestHelper { FileSystemURL error_url_; base::test::TaskEnvironment task_environment_; + scoped_refptr<storage::MockQuotaManager> quota_manager_; + scoped_refptr<storage::MockQuotaManagerProxy> quota_manager_proxy_; scoped_refptr<FileSystemContext> file_system_context_; }; diff --git a/chromium/storage/browser/file_system/dragged_file_util_unittest.cc b/chromium/storage/browser/file_system/dragged_file_util_unittest.cc index e1020fed841..b40a59149ca 100644 --- a/chromium/storage/browser/file_system/dragged_file_util_unittest.cc +++ b/chromium/storage/browser/file_system/dragged_file_util_unittest.cc @@ -29,6 +29,9 @@ #include "storage/browser/quota/quota_manager_proxy.h" #include "storage/browser/test/async_file_test_helper.h" #include "storage/browser/test/file_system_test_file_set.h" +#include "storage/browser/test/mock_quota_manager.h" +#include "storage/browser/test/mock_quota_manager_proxy.h" +#include "storage/browser/test/mock_special_storage_policy.h" #include "storage/browser/test/test_file_system_context.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" @@ -107,8 +110,16 @@ class DraggedFileUtilTest : public testing::Test { // root paths) as dropped files. SimulateDropFiles(); - file_system_context_ = CreateFileSystemContextForTesting( - /*quota_manager_proxy=*/nullptr, partition_dir_.GetPath()); + base::FilePath partition_path = partition_dir_.GetPath(); + quota_manager_ = base::MakeRefCounted<storage::MockQuotaManager>( + /*is_incognito=*/false, partition_path, + base::ThreadTaskRunnerHandle::Get(), + base::MakeRefCounted<storage::MockSpecialStoragePolicy>()); + quota_manager_proxy_ = base::MakeRefCounted<storage::MockQuotaManagerProxy>( + quota_manager_.get(), base::ThreadTaskRunnerHandle::Get()); + // Prepare file system. + file_system_context_ = storage::CreateFileSystemContextForTesting( + quota_manager_proxy_.get(), partition_path); isolated_context()->AddReference(filesystem_id_); } @@ -274,9 +285,11 @@ class DraggedFileUtilTest : public testing::Test { base::ScopedTempDir data_dir_; base::ScopedTempDir partition_dir_; - base::test::SingleThreadTaskEnvironment task_environment_{ - base::test::SingleThreadTaskEnvironment::MainThreadType::IO}; + base::test::TaskEnvironment task_environment_{ + base::test::TaskEnvironment::MainThreadType::IO}; std::string filesystem_id_; + scoped_refptr<storage::MockQuotaManager> quota_manager_; + scoped_refptr<storage::MockQuotaManagerProxy> quota_manager_proxy_; scoped_refptr<FileSystemContext> file_system_context_; std::map<base::FilePath, base::FilePath> toplevel_root_map_; std::unique_ptr<DraggedFileUtil> file_util_; diff --git a/chromium/storage/browser/file_system/file_system_context.cc b/chromium/storage/browser/file_system/file_system_context.cc index 7ec5dc2f0e9..ed0dedf339d 100644 --- a/chromium/storage/browser/file_system/file_system_context.cc +++ b/chromium/storage/browser/file_system/file_system_context.cc @@ -125,7 +125,6 @@ int FileSystemContext::GetPermissionPolicy(FileSystemType type) { // don't have their own permission policies. case kFileSystemTypeDragged: case kFileSystemTypeForTransientFile: - case kFileSystemTypePluginPrivate: return FILE_PERMISSION_ALWAYS_DENY; // Following types only appear as mount_type, and will not be @@ -205,12 +204,6 @@ FileSystemContext::FileSystemContext( env_override_.get())), sandbox_backend_( std::make_unique<SandboxFileSystemBackend>(sandbox_delegate_.get())), - plugin_private_backend_(std::make_unique<PluginPrivateFileSystemBackend>( - default_file_task_runner_, - partition_path, - std::move(special_storage_policy), - options, - env_override_.get())), additional_backends_(std::move(additional_backends)), auto_mount_handlers_(auto_mount_handlers), external_mount_points_(std::move(external_mount_points)), @@ -223,7 +216,6 @@ FileSystemContext::FileSystemContext( std::make_unique<mojo::Receiver<mojom::QuotaClient>>( quota_client_wrapper_.get())) { RegisterBackend(sandbox_backend_.get()); - RegisterBackend(plugin_private_backend_.get()); for (const auto& backend : additional_backends_) RegisterBackend(backend.get()); @@ -242,7 +234,6 @@ FileSystemContext::FileSystemContext( void FileSystemContext::Initialize() { sandbox_backend_->Initialize(this); isolated_backend_->Initialize(this); - plugin_private_backend_->Initialize(this); for (const auto& backend : additional_backends_) backend->Initialize(this); @@ -646,18 +637,6 @@ bool FileSystemContext::CanServeURLRequest(const FileSystemURL& url) const { return !is_incognito_ || !FileSystemContext::IsSandboxFileSystem(url.type()); } -void FileSystemContext::OpenPluginPrivateFileSystem( - const url::Origin& origin, - FileSystemType type, - const std::string& filesystem_id, - const std::string& plugin_id, - OpenFileSystemMode mode, - StatusCallback callback) { - DCHECK(plugin_private_backend_); - plugin_private_backend_->OpenPrivateFileSystem( - origin, type, filesystem_id, plugin_id, mode, std::move(callback)); -} - FileSystemContext::~FileSystemContext() { // TODO(crbug.com/823854) This is a leak. Delete env after the backends have // been deleted. @@ -676,7 +655,7 @@ FileSystemContext::QuotaManagedStorageTypes() { // to call GetQuotaUtil() on backends. Unfortunately, the method assumes the // backends are initialized. if (storage_type == blink::mojom::StorageType::kUnknown || - storage_type == blink::mojom::StorageType::kQuotaNotManaged) { + storage_type == blink::mojom::StorageType::kDeprecatedQuotaNotManaged) { continue; } diff --git a/chromium/storage/browser/file_system/file_system_context.h b/chromium/storage/browser/file_system/file_system_context.h index cf2d5325392..cc80a12b0a1 100644 --- a/chromium/storage/browser/file_system/file_system_context.h +++ b/chromium/storage/browser/file_system/file_system_context.h @@ -28,7 +28,6 @@ #include "storage/browser/file_system/file_system_request_info.h" #include "storage/browser/file_system/file_system_url.h" #include "storage/browser/file_system/open_file_system_mode.h" -#include "storage/browser/file_system/plugin_private_file_system_backend.h" #include "storage/browser/file_system/sandbox_file_system_backend_delegate.h" #include "storage/browser/file_system/task_runner_bound_observer_list.h" #include "storage/common/file_system/file_system_types.h" @@ -230,7 +229,7 @@ class COMPONENT_EXPORT(STORAGE_BROWSER) FileSystemContext const base::FilePath& file_path, ResolvedEntryType type)>; - // Used for DeleteFileSystem and OpenPluginPrivateFileSystem. + // Used for DeleteFileSystem. using StatusCallback = base::OnceCallback<void(base::File::Error result)>; // Opens the filesystem for the given `storage_key` and `type`, and dispatches @@ -334,27 +333,8 @@ class COMPONENT_EXPORT(STORAGE_BROWSER) FileSystemContext // (E.g. this returns false if the context is created for incognito mode) bool CanServeURLRequest(const FileSystemURL& url) const; - // This must be used to open 'plugin private' filesystem. - // See "plugin_private_file_system_backend.h" for more details. - // - // TODO(https://crbug.com/1231162): determine whether EME/CDM/plugin private - // file system will be partitioned; if so, replace the url::Origin parameter - // with blink::StorageKey - void OpenPluginPrivateFileSystem(const url::Origin& origin, - FileSystemType type, - const std::string& filesystem_id, - const std::string& plugin_id, - OpenFileSystemMode mode, - StatusCallback callback); - bool is_incognito() { return is_incognito_; } - // TODO(com/1231162): Remove this. Used only by test code and to migrate media - // license data to the new backend. - PluginPrivateFileSystemBackend* plugin_private_backend() const { - return plugin_private_backend_.get(); - } - void ResolveURLOnOpenFileSystemForTesting( const blink::StorageKey& storage_key, const absl::optional<storage::BucketLocator>& bucket, @@ -372,9 +352,6 @@ class COMPONENT_EXPORT(STORAGE_BROWSER) FileSystemContext // For sandbox_backend(). friend class SandboxFileSystemTestHelper; - // For plugin_private_backend(). - friend class PluginPrivateFileSystemBackendTest; - // Deleters. friend class base::DeleteHelper<FileSystemContext>; friend class base::RefCountedDeleteOnSequence<FileSystemContext>; @@ -464,7 +441,6 @@ class COMPONENT_EXPORT(STORAGE_BROWSER) FileSystemContext std::unique_ptr<IsolatedFileSystemBackend> isolated_backend_; // Additional file system backends. - const std::unique_ptr<PluginPrivateFileSystemBackend> plugin_private_backend_; const std::vector<std::unique_ptr<FileSystemBackend>> additional_backends_; std::vector<URLRequestAutoMountHandler> auto_mount_handlers_; diff --git a/chromium/storage/browser/file_system/file_system_operation_impl_unittest.cc b/chromium/storage/browser/file_system/file_system_operation_impl_unittest.cc index ed25bd361ad..ea97c810220 100644 --- a/chromium/storage/browser/file_system/file_system_operation_impl_unittest.cc +++ b/chromium/storage/browser/file_system/file_system_operation_impl_unittest.cc @@ -239,8 +239,7 @@ class FileSystemOperationImplTest : public testing::Test { void GetUsageAndQuota(int64_t* usage, int64_t* quota) { blink::mojom::QuotaStatusCode status = AsyncFileTestHelper::GetUsageAndQuota( - quota_manager_->proxy(), - sandbox_file_system_.storage_key().origin(), + quota_manager_->proxy(), sandbox_file_system_.storage_key(), sandbox_file_system_.type(), usage, quota); task_environment_.RunUntilIdle(); ASSERT_EQ(blink::mojom::QuotaStatusCode::kOk, status); diff --git a/chromium/storage/browser/file_system/file_system_operation_impl_write_unittest.cc b/chromium/storage/browser/file_system/file_system_operation_impl_write_unittest.cc index 4bff94324f5..bf75e8b9cf6 100644 --- a/chromium/storage/browser/file_system/file_system_operation_impl_write_unittest.cc +++ b/chromium/storage/browser/file_system/file_system_operation_impl_write_unittest.cc @@ -14,6 +14,7 @@ #include "base/memory/weak_ptr.h" #include "base/run_loop.h" #include "base/test/task_environment.h" +#include "base/test/test_future.h" #include "base/threading/thread_task_runner_handle.h" #include "net/url_request/url_request.h" #include "storage/browser/blob/blob_storage_context.h" @@ -43,10 +44,6 @@ namespace { const char kOrigin[] = "http://example.com"; const FileSystemType kFileSystemType = kFileSystemTypeTest; -void AssertStatusEq(base::File::Error expected, base::File::Error actual) { - ASSERT_EQ(expected, actual); -} - } // namespace class FileSystemOperationImplWriteTest : public testing::Test { @@ -79,9 +76,10 @@ class FileSystemOperationImplWriteTest : public testing::Test { quota_manager_->proxy(), data_dir_.GetPath()); blob_storage_context_ = std::make_unique<BlobStorageContext>(); + base::test::TestFuture<base::File::Error> future; file_system_context_->operation_runner()->CreateFile( - URLForPath(virtual_path_), true /* exclusive */, - base::BindOnce(&AssertStatusEq, base::File::FILE_OK)); + URLForPath(virtual_path_), true /* exclusive */, future.GetCallback()); + ASSERT_EQ(base::File::FILE_OK, future.Get()); static_cast<TestFileSystemBackend*>( file_system_context_->GetFileSystemBackend(kFileSystemType)) @@ -233,9 +231,12 @@ TEST_F(FileSystemOperationImplWriteTest, TestWriteInvalidFile) { TEST_F(FileSystemOperationImplWriteTest, TestWriteDir) { base::FilePath virtual_dir_path(FILE_PATH_LITERAL("d")); + + base::test::TestFuture<base::File::Error> future; file_system_context_->operation_runner()->CreateDirectory( URLForPath(virtual_dir_path), true /* exclusive */, false /* recursive */, - base::BindOnce(&AssertStatusEq, base::File::FILE_OK)); + future.GetCallback()); + ASSERT_EQ(base::File::FILE_OK, future.Get()); ScopedTextBlob blob(blob_storage_context(), "blob:writedir", "It\'ll not be written, too."); diff --git a/chromium/storage/browser/file_system/file_system_quota_client.cc b/chromium/storage/browser/file_system/file_system_quota_client.cc index fa2ad05238f..95da4364f7a 100644 --- a/chromium/storage/browser/file_system/file_system_quota_client.cc +++ b/chromium/storage/browser/file_system/file_system_quota_client.cc @@ -14,7 +14,6 @@ #include "base/bind.h" #include "base/check.h" #include "base/containers/span.h" -#include "base/feature_list.h" #include "base/files/file.h" #include "base/location.h" #include "base/sequence_checker.h" @@ -64,8 +63,7 @@ base::span<const FileSystemType> QuotaStorageTypeToFileSystemTypes( blink::mojom::StorageType storage_type) { using StorageType = blink::mojom::StorageType; - if (base::FeatureList::IsEnabled( - blink::features::kPersistentQuotaIsTemporaryQuota)) { + if (blink::features::IsPersistentQuotaIsTemporaryQuota()) { DCHECK_NE(storage_type, StorageType::kPersistent); if (storage_type == StorageType::kTemporary) return kTemporaryAndPersistent; @@ -77,7 +75,7 @@ base::span<const FileSystemType> QuotaStorageTypeToFileSystemTypes( return kPersistent; case StorageType::kSyncable: return kSyncable; - case StorageType::kQuotaNotManaged: + case StorageType::kDeprecatedQuotaNotManaged: case StorageType::kUnknown: NOTREACHED(); return {}; @@ -93,16 +91,16 @@ std::vector<blink::StorageKey> GetStorageKeysForTypeOnFileTaskRunner( return quota_util->GetStorageKeysForTypeOnFileTaskRunner(type); } -blink::mojom::QuotaStatusCode DeleteStorageKeyOnFileTaskRunner( +blink::mojom::QuotaStatusCode DeleteBucketOnFileTaskRunner( FileSystemContext* context, - const blink::StorageKey& storage_key, + const BucketLocator& bucket_locator, FileSystemType type) { FileSystemBackend* provider = context->GetFileSystemBackend(type); if (!provider || !provider->GetQuotaUtil()) return blink::mojom::QuotaStatusCode::kErrorNotSupported; base::File::Error result = - provider->GetQuotaUtil()->DeleteStorageKeyDataOnFileTaskRunner( - context, context->quota_manager_proxy().get(), storage_key, type); + provider->GetQuotaUtil()->DeleteBucketDataOnFileTaskRunner( + context, context->quota_manager_proxy().get(), bucket_locator, type); if (result == base::File::FILE_OK) return blink::mojom::QuotaStatusCode::kOk; return blink::mojom::QuotaStatusCode::kErrorInvalidModification; @@ -135,14 +133,6 @@ void FileSystemQuotaClient::GetBucketUsage(const BucketLocator& bucket, DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK(!callback.is_null()); - // Skip non-default buckets until Storage Buckets are supported for - // FileSystem. - // TODO(crbug.com/1218100): Integrate with StorageBuckets. - if (!bucket.is_default) { - std::move(callback).Run(0); - return; - } - base::span<const FileSystemType> types = QuotaStorageTypeToFileSystemTypes(bucket.type); @@ -159,11 +149,10 @@ void FileSystemQuotaClient::GetBucketUsage(const BucketLocator& bucket, file_task_runner()->PostTaskAndReplyWithResult( FROM_HERE, // It is safe to pass Unretained(quota_util) since context owns it. - base::BindOnce( - &FileSystemQuotaUtil::GetStorageKeyUsageOnFileTaskRunner, - base::Unretained(quota_util), - base::RetainedRef(file_system_context_.get()), bucket.storage_key, - type), + base::BindOnce(&FileSystemQuotaUtil::GetBucketUsageOnFileTaskRunner, + base::Unretained(quota_util), + base::RetainedRef(file_system_context_.get()), bucket, + type), barrier); } else { barrier.Run(0); @@ -201,14 +190,6 @@ void FileSystemQuotaClient::DeleteBucketData( DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK(!callback.is_null()); - // Skip non-default buckets until Storage Buckets are supported for - // FileSystem. - // TODO(crbug.com/1218100): Integrate with StorageBuckets. - if (!bucket.is_default) { - std::move(callback).Run(blink::mojom::QuotaStatusCode::kOk); - return; - } - base::span<const FileSystemType> fs_types = QuotaStorageTypeToFileSystemTypes(bucket.type); @@ -227,9 +208,9 @@ void FileSystemQuotaClient::DeleteBucketData( for (const auto fs_type : fs_types) { file_task_runner()->PostTaskAndReplyWithResult( FROM_HERE, - base::BindOnce(&DeleteStorageKeyOnFileTaskRunner, - base::RetainedRef(file_system_context_.get()), - bucket.storage_key, fs_type), + base::BindOnce(&DeleteBucketOnFileTaskRunner, + base::RetainedRef(file_system_context_.get()), bucket, + fs_type), barrier); } } diff --git a/chromium/storage/browser/file_system/file_system_quota_client_unittest.cc b/chromium/storage/browser/file_system/file_system_quota_client_unittest.cc index 407f5daef9a..f29c9f5ebde 100644 --- a/chromium/storage/browser/file_system/file_system_quota_client_unittest.cc +++ b/chromium/storage/browser/file_system/file_system_quota_client_unittest.cc @@ -550,9 +550,6 @@ TEST_P(FileSystemQuotaClientTest, DeleteOriginTest) { const int64_t file_paths_cost_temporary_foo_https = ComputeFilePathsCostForOriginAndType(kFiles, "https://foo.com/", kFileSystemTypeTemporary); - const int64_t file_paths_cost_persistent_foo = - ComputeFilePathsCostForOriginAndType(kFiles, "http://foo.com/", - kFileSystemTypePersistent); const int64_t file_paths_cost_temporary_bar = ComputeFilePathsCostForOriginAndType(kFiles, "http://bar.com/", kFileSystemTypeTemporary); @@ -603,22 +600,6 @@ TEST_P(FileSystemQuotaClientTest, DeleteOriginTest) { ? 32 + file_paths_cost_persistent_bar_https : 0), GetBucketUsage(quota_client, bar_https_temp_bucket)); - - if (!persistent_quota_is_temporary_quota()) { - auto bar_perm_bucket = - GetBucket("http://bar.com/", kDefaultBucketName, kPersistent); - EXPECT_EQ(0, GetBucketUsage(quota_client, bar_perm_bucket)); - - auto foo_perm_bucket = - GetBucket("http://foo.com/", kDefaultBucketName, kPersistent); - EXPECT_EQ(4 + file_paths_cost_persistent_foo, - GetBucketUsage(quota_client, foo_perm_bucket)); - - auto bar_https_perm_bucket = - GetBucket("https://bar.com/", kDefaultBucketName, kPersistent); - EXPECT_EQ(32 + file_paths_cost_persistent_bar_https, - GetBucketUsage(quota_client, bar_https_perm_bucket)); - } } INSTANTIATE_TEST_SUITE_P(FileSystemQuotaClientTests, diff --git a/chromium/storage/browser/file_system/file_system_quota_util.h b/chromium/storage/browser/file_system/file_system_quota_util.h index dd34c1e1ee0..89d8f31843c 100644 --- a/chromium/storage/browser/file_system/file_system_quota_util.h +++ b/chromium/storage/browser/file_system/file_system_quota_util.h @@ -20,6 +20,7 @@ class StorageKey; namespace storage { +struct BucketLocator; class FileSystemContext; class QuotaManagerProxy; class QuotaReservation; @@ -32,7 +33,7 @@ class COMPONENT_EXPORT(STORAGE_BROWSER) FileSystemQuotaUtil { public: virtual ~FileSystemQuotaUtil() = default; - // Deletes the data on the origin and reports the amount of deleted data + // Deletes the data on the StorageKey and reports the amount of deleted data // to the quota manager via |proxy|. virtual base::File::Error DeleteStorageKeyDataOnFileTaskRunner( FileSystemContext* context, @@ -40,6 +41,14 @@ class COMPONENT_EXPORT(STORAGE_BROWSER) FileSystemQuotaUtil { const blink::StorageKey& storage_key, FileSystemType type) = 0; + // Deletes the data on the bucket and reports the amount of deleted data + // to the quota manager via |proxy|. + virtual base::File::Error DeleteBucketDataOnFileTaskRunner( + FileSystemContext* context, + QuotaManagerProxy* proxy, + const BucketLocator& bucket_locator, + FileSystemType type) = 0; + virtual void PerformStorageCleanupOnFileTaskRunner(FileSystemContext* context, QuotaManagerProxy* proxy, FileSystemType type) = 0; @@ -53,6 +62,13 @@ class COMPONENT_EXPORT(STORAGE_BROWSER) FileSystemQuotaUtil { const blink::StorageKey& storage_key, FileSystemType type) = 0; + // Returns the amount of data used for the `bucket_locator` for usage + // tracking. + virtual int64_t GetBucketUsageOnFileTaskRunner( + FileSystemContext* file_system_context, + const BucketLocator& bucket_locator, + FileSystemType type) = 0; + // Creates new reservation object for the `storage_key` and the `type`. virtual scoped_refptr<QuotaReservation> CreateQuotaReservationOnFileTaskRunner(const blink::StorageKey& storage_key, diff --git a/chromium/storage/browser/file_system/file_system_usage_cache.cc b/chromium/storage/browser/file_system/file_system_usage_cache.cc index 5b165353f01..515b1a2ad7f 100644 --- a/chromium/storage/browser/file_system/file_system_usage_cache.cc +++ b/chromium/storage/browser/file_system/file_system_usage_cache.cc @@ -36,7 +36,7 @@ FileSystemUsageCache::~FileSystemUsageCache() { const base::FilePath::CharType FileSystemUsageCache::kUsageFileName[] = FILE_PATH_LITERAL(".usage"); const char FileSystemUsageCache::kUsageFileHeader[] = "FSU5"; -const int FileSystemUsageCache::kUsageFileHeaderSize = 4; +const size_t FileSystemUsageCache::kUsageFileHeaderSize = 4; // Pickle::{Read,Write}Bool treat bool as int const int FileSystemUsageCache::kUsageFileSize = diff --git a/chromium/storage/browser/file_system/file_system_usage_cache.h b/chromium/storage/browser/file_system/file_system_usage_cache.h index ef048677824..75bdd0f740b 100644 --- a/chromium/storage/browser/file_system/file_system_usage_cache.h +++ b/chromium/storage/browser/file_system/file_system_usage_cache.h @@ -61,7 +61,7 @@ class COMPONENT_EXPORT(STORAGE_BROWSER) FileSystemUsageCache { static const base::FilePath::CharType kUsageFileName[]; static const char kUsageFileHeader[]; static const int kUsageFileSize; - static const int kUsageFileHeaderSize; + static const size_t kUsageFileHeaderSize; private: // Read the size, validity and the "dirty" entry described in the .usage file. diff --git a/chromium/storage/browser/file_system/file_system_util.cc b/chromium/storage/browser/file_system/file_system_util.cc index a32a53f2676..450fbf32115 100644 --- a/chromium/storage/browser/file_system/file_system_util.cc +++ b/chromium/storage/browser/file_system/file_system_util.cc @@ -4,7 +4,6 @@ #include "storage/browser/file_system/file_system_util.h" -#include "base/feature_list.h" #include "storage/common/file_system/file_system_types.h" #include "third_party/blink/public/common/features.h" #include "third_party/blink/public/mojom/quota/quota_types.mojom.h" @@ -13,8 +12,7 @@ namespace storage { blink::mojom::StorageType FileSystemTypeToQuotaStorageType( FileSystemType type) { - if (base::FeatureList::IsEnabled( - blink::features::kPersistentQuotaIsTemporaryQuota) && + if (blink::features::IsPersistentQuotaIsTemporaryQuota() && (type == kFileSystemTypeTemporary || type == kFileSystemTypePersistent)) { return blink::mojom::StorageType::kTemporary; } @@ -26,8 +24,6 @@ blink::mojom::StorageType FileSystemTypeToQuotaStorageType( case kFileSystemTypeSyncable: case kFileSystemTypeSyncableForInternalSync: return blink::mojom::StorageType::kSyncable; - case kFileSystemTypePluginPrivate: - return blink::mojom::StorageType::kQuotaNotManaged; default: return blink::mojom::StorageType::kUnknown; } diff --git a/chromium/storage/browser/file_system/obfuscated_file_util.cc b/chromium/storage/browser/file_system/obfuscated_file_util.cc index f3463199d34..b238431f5fa 100644 --- a/chromium/storage/browser/file_system/obfuscated_file_util.cc +++ b/chromium/storage/browser/file_system/obfuscated_file_util.cc @@ -29,6 +29,7 @@ #include "storage/browser/file_system/file_observers.h" #include "storage/browser/file_system/file_system_context.h" #include "storage/browser/file_system/file_system_operation_context.h" +#include "storage/browser/file_system/file_system_util.h" #include "storage/browser/file_system/obfuscated_file_util_disk_delegate.h" #include "storage/browser/file_system/obfuscated_file_util_memory_delegate.h" #include "storage/browser/file_system/quota/quota_limit_type.h" @@ -74,8 +75,6 @@ const int64_t kPathCreationQuotaCost = 146; // Bytes per inode, basically. const int64_t kPathByteQuotaCost = 2; // Bytes per byte of path length in UTF-8. -const char kDirectoryDatabaseKeySeparator = ' '; - int64_t UsageForPath(size_t length) { return kPathCreationQuotaCost + static_cast<int64_t>(length) * kPathByteQuotaCost; @@ -113,15 +112,41 @@ enum IsolatedOriginStatus { } // namespace -// TODO(https://crbug.com/1248104): This class will eventually interface with -// Storage Buckets instead of directly interfacing with LevelDB. Thus, the below -// functions were converted from url::Origin to blink::StorageKey to prepare for -// Storage Partitioning of the FileSystem APIs. However, it is important to note -// that, until the refactor to use Storage Buckets, the LevelDB structure above -// is still used, and the entries are still keyed per-origin (achieved by -// storage_key.origin()) and per-type. Going forward, OriginRecords will be -// retrieved from the database and converted into StorageKey values until -// Storage Buckets are implemented instead. +// Implementing the DatabaseKey for the directories_ map. +DatabaseKey::DatabaseKey() = default; +DatabaseKey::~DatabaseKey() = default; + +// Copyable and moveable +DatabaseKey::DatabaseKey(const DatabaseKey& other) = default; +DatabaseKey& DatabaseKey::operator=(const DatabaseKey& other) = default; +DatabaseKey::DatabaseKey(DatabaseKey&& other) = default; +DatabaseKey& DatabaseKey::operator=(DatabaseKey&& other) = default; + +DatabaseKey::DatabaseKey(const blink::StorageKey& storage_key, + const absl::optional<BucketLocator>& bucket, + const std::string& type) { + storage_key_ = storage_key; + bucket_ = bucket; + type_ = type; +} + +bool DatabaseKey::operator==(const DatabaseKey& other) const { + return std::tie(storage_key_, bucket_, type_) == + std::tie(other.storage_key_, other.bucket_, other.type_); +} + +bool DatabaseKey::operator!=(const DatabaseKey& other) const { + return std::tie(storage_key_, bucket_, type_) != + std::tie(other.storage_key_, other.bucket_, other.type_); +} + +bool DatabaseKey::operator<(const DatabaseKey& other) const { + return std::tie(storage_key_, bucket_, type_) < + std::tie(other.storage_key_, other.bucket_, other.type_); +} + +// end DatabaseKey implementation. + class ObfuscatedFileEnumerator final : public FileSystemFileUtil::AbstractFileEnumerator { public: @@ -206,7 +231,8 @@ class ObfuscatedFileEnumerator final } raw_ptr<SandboxDirectoryDatabase> db_; - raw_ptr<FileSystemOperationContext> context_; + // TODO(crbug.com/1298696): Breaks storage_unittests. + raw_ptr<FileSystemOperationContext, DegradeToNoOpWhenMTE> context_; raw_ptr<ObfuscatedFileUtil> obfuscated_file_util_; FileSystemURL root_url_; bool recursive_; @@ -219,6 +245,14 @@ class ObfuscatedFileEnumerator final base::File::Info current_platform_file_info_; }; +// NOTE: currently, ObfuscatedFileUtil still relies on SandboxOriginDatabases +// for first-party StorageKeys/default buckets. The AbstractStorageKeyEnumerator +// class is only used in these cases. While this class stores and iterates +// through StorageKeys types, it works by retrieving OriginRecords from the +// SandboxOriginDatabase and converting those origins into first-party +// StorageKey values (e.g. blink::StorageKey(origin)). The goal is to eventually +// deprecate SandboxOriginDatabases and AbstractStorageKeyEnumerators and rely +// entirely on Storage Buckets. class ObfuscatedStorageKeyEnumerator : public ObfuscatedFileUtil::AbstractStorageKeyEnumerator { public: @@ -272,30 +306,34 @@ class ObfuscatedStorageKeyEnumerator base::WeakPtr<ObfuscatedFileUtilMemoryDelegate> memory_file_util_; }; +const base::FilePath::CharType ObfuscatedFileUtil::kFileSystemDirectory[] = + FILE_PATH_LITERAL("File System"); + ObfuscatedFileUtil::ObfuscatedFileUtil( scoped_refptr<SpecialStoragePolicy> special_storage_policy, - const base::FilePath& file_system_directory, + const base::FilePath& profile_path, leveldb::Env* env_override, - GetTypeStringForURLCallback get_type_string_for_url, const std::set<std::string>& known_type_strings, SandboxFileSystemBackendDelegate* sandbox_delegate, bool is_incognito) : special_storage_policy_(std::move(special_storage_policy)), - file_system_directory_(file_system_directory), env_override_(env_override), is_incognito_(is_incognito), db_flush_delay_seconds_(10 * 60), // 10 mins. - get_type_string_for_url_(std::move(get_type_string_for_url)), known_type_strings_(known_type_strings), sandbox_delegate_(sandbox_delegate) { - DCHECK(!get_type_string_for_url_.is_null()); DETACH_FROM_SEQUENCE(sequence_checker_); DCHECK(!is_incognito_ || (env_override && leveldb_chrome::IsMemEnv(env_override))); + file_system_directory_ = profile_path.Append(kFileSystemDirectory); if (is_incognito_) { - delegate_ = std::make_unique<ObfuscatedFileUtilMemoryDelegate>( - file_system_directory_); + // profile_path is passed here, so that the delegate is able to accommodate + // both codepaths of {{profile_path}}/File System (first-party) and + // {{profile_path}}/WebStorage (buckets-based). + // See https://crrev.com/c/3817542 for more context. + delegate_ = + std::make_unique<ObfuscatedFileUtilMemoryDelegate>(profile_path); } else { delegate_ = std::make_unique<ObfuscatedFileUtilDiskDelegate>(); } @@ -867,19 +905,15 @@ bool ObfuscatedFileUtil::IsDirectoryEmpty(FileSystemOperationContext* context, } base::FileErrorOr<base::FilePath> -ObfuscatedFileUtil::GetDirectoryForBucketAndType(const BucketLocator& bucket, - const std::string& type_string, - bool create) { +ObfuscatedFileUtil::GetDirectoryForBucketAndType( + const BucketLocator& bucket, + const absl::optional<FileSystemType>& type, + bool create) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); // A default bucket in a first-party context uses // GetDirectoryForStorageKeyAndType() to determine its file path. if (bucket.storage_key.IsFirstPartyContext() && bucket.is_default) { - base::File::Error error = base::File::FILE_OK; - base::FilePath path = GetDirectoryForStorageKeyAndType( - bucket.storage_key, type_string, create, &error); - if (error != base::File::FILE_OK) - return error; - return path; + return GetDirectoryForStorageKeyAndType(bucket.storage_key, type, create); } // All other contexts use the provided bucket information to construct the // file path. @@ -887,63 +921,64 @@ ObfuscatedFileUtil::GetDirectoryForBucketAndType(const BucketLocator& bucket, sandbox_delegate_->quota_manager_proxy()->GetClientBucketPath( bucket, QuotaClientType::kFileSystem); // Append the file system type and verify the path is valid. - path = path.AppendASCII(type_string); + if (type) { + path = path.AppendASCII( + SandboxFileSystemBackendDelegate::GetTypeString(type.value())); + } base::File::Error error = GetDirectoryHelper(path, create); if (error != base::File::FILE_OK) return error; return path; } -// TODO(https://crbug.com/1310361): refactor GetDirectoryForStorageKeyAndType -// and its callers to return a base::FileErrorOr<base::FilePath>. -base::FilePath ObfuscatedFileUtil::GetDirectoryForStorageKeyAndType( +base::FileErrorOr<base::FilePath> +ObfuscatedFileUtil::GetDirectoryForStorageKeyAndType( const blink::StorageKey& storage_key, - const std::string& type_string, - bool create, - base::File::Error* error_code) { + const absl::optional<FileSystemType>& type, + bool create) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - base::FileErrorOr<base::FilePath> origin_dir = + base::FileErrorOr<base::FilePath> dir = GetDirectoryForStorageKey(storage_key, create); - if (origin_dir.is_error()) { - *error_code = origin_dir.error(); - return base::FilePath(); + if (dir.is_error()) { + return dir; } - if (origin_dir->empty()) { - *error_code = base::File::FILE_OK; - return base::FilePath(); - } - if (type_string.empty()) { - *error_code = base::File::FILE_OK; - return origin_dir.value(); + DCHECK(!dir->empty()); + if (!type) { + return dir; } // Append the file system type and verify the path is valid. - base::FilePath path = origin_dir->AppendASCII(type_string); + base::FilePath path = dir.value(); + if (type) { + path = path.AppendASCII( + SandboxFileSystemBackendDelegate::GetTypeString(type.value())); + } base::File::Error error = GetDirectoryHelper(path, create); - if (error_code) - *error_code = error; + if (error != base::File::FILE_OK) + return error; return path; } bool ObfuscatedFileUtil::DeleteDirectoryForStorageKeyAndType( const blink::StorageKey& storage_key, - const std::string& type_string) { + const absl::optional<FileSystemType>& type) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - DestroyDirectoryDatabase(storage_key, type_string); + DestroyDirectoryDatabaseForStorageKey(storage_key, type); base::FileErrorOr<base::FilePath> origin_path = GetDirectoryForStorageKey(storage_key, false); if (origin_path.is_error() || origin_path->empty()) return true; - if (!type_string.empty()) { + if (type) { // Delete the filesystem type directory. - base::File::Error error = base::File::FILE_OK; - const base::FilePath origin_type_path = GetDirectoryForStorageKeyAndType( - storage_key, type_string, false, &error); - if (error == base::File::FILE_ERROR_FAILED) + const base::FileErrorOr<base::FilePath> origin_type_path = + GetDirectoryForStorageKeyAndType(storage_key, type.value(), false); + if (origin_type_path.is_error() && + origin_type_path.error() == base::File::FILE_ERROR_FAILED) { return false; - if (error == base::File::FILE_OK && !origin_type_path.empty() && - !delegate_->DeleteFileOrDirectory(origin_type_path, + } + if (!origin_type_path.is_error() && !origin_type_path->empty() && + !delegate_->DeleteFileOrDirectory(origin_type_path.value(), true /* recursive */)) { return false; } @@ -951,10 +986,12 @@ bool ObfuscatedFileUtil::DeleteDirectoryForStorageKeyAndType( // At this point we are sure we had successfully deleted the origin/type // directory (i.e. we're ready to just return true). // See if we have other directories in this origin directory. - for (const std::string& type : known_type_strings_) { - if (type == type_string) + const std::string type_string = + SandboxFileSystemBackendDelegate::GetTypeString(type.value()); + for (const std::string& known_type : known_type_strings_) { + if (known_type == type_string) continue; - if (delegate_->DirectoryExists(origin_path->AppendASCII(type))) { + if (delegate_->DirectoryExists(origin_path->AppendASCII(known_type))) { // Other type's directory exists; just return true here. return true; } @@ -974,21 +1011,56 @@ bool ObfuscatedFileUtil::DeleteDirectoryForStorageKeyAndType( true /* recursive */); } -void ObfuscatedFileUtil::CloseFileSystemForStorageKeyAndType( - const blink::StorageKey& storage_key, - const std::string& type_string) { +bool ObfuscatedFileUtil::DeleteDirectoryForBucketAndType( + const BucketLocator& bucket_locator, + const absl::optional<FileSystemType>& type) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + if (bucket_locator.is_default && + bucket_locator.storage_key.IsFirstPartyContext()) + return DeleteDirectoryForStorageKeyAndType(bucket_locator.storage_key, + type); - const std::string key_prefix = - GetDirectoryDatabaseKey(storage_key, type_string); - for (auto iter = directories_.lower_bound(key_prefix); - iter != directories_.end();) { - if (!base::StartsWith(iter->first, key_prefix, - base::CompareCase::SENSITIVE)) - break; - DCHECK(type_string.empty() || iter->first == key_prefix); - directories_.erase(iter++); + DestroyDirectoryDatabaseForBucket(bucket_locator, type); + + // Get the base path for the bucket without the type string appended. + base::FilePath path = + sandbox_delegate_->quota_manager_proxy()->GetClientBucketPath( + bucket_locator, QuotaClientType::kFileSystem); + base::File::Error error = GetDirectoryHelper(path, /*create=*/false); + if (error != base::File::FILE_OK || path.empty()) + return true; + + if (type) { + // Delete the filesystem type directory. + const base::FileErrorOr<base::FilePath> path_with_type = + GetDirectoryForBucketAndType(bucket_locator, type.value(), false); + if (path_with_type.is_error()) + return false; + if (!path_with_type->empty() && + !delegate_->DeleteFileOrDirectory(path_with_type.value(), + true /* recursive */)) { + return false; + } + + // At this point we are sure we had successfully deleted the bucket/type + // directory. Now we need to see if we have other sub-type-directories under + // the higher-level `path` directory. If so, we need to return early to + // avoid deleting the higher-level `path` directory. + const std::string type_string = + SandboxFileSystemBackendDelegate::GetTypeString(type.value()); + for (const std::string& known_type : known_type_strings_) { + if (known_type == type_string) + continue; + if (delegate_->DirectoryExists(path.AppendASCII(known_type))) { + // Other type's directory exists; return to avoid deleting the higher + // level directory. + return true; + } + } } + + // Delete the higher-level directory. + return delegate_->DeleteFileOrDirectory(path, true /* recursive */); } std::unique_ptr<ObfuscatedFileUtil::AbstractStorageKeyEnumerator> @@ -1006,27 +1078,67 @@ ObfuscatedFileUtil::CreateStorageKeyEnumerator() { origin_database_.get(), file_util_delegate, file_system_directory_); } -void ObfuscatedFileUtil::DestroyDirectoryDatabase( +void ObfuscatedFileUtil::DestroyDirectoryDatabaseForStorageKey( const blink::StorageKey& storage_key, - const std::string& type_string) { + const absl::optional<FileSystemType>& type) { + DestroyDirectoryDatabaseHelper(absl::nullopt, storage_key, type); +} + +void ObfuscatedFileUtil::DestroyDirectoryDatabaseForBucket( + const BucketLocator& bucket_locator, + const absl::optional<FileSystemType>& type) { + DestroyDirectoryDatabaseHelper(bucket_locator, bucket_locator.storage_key, + type); +} + +void ObfuscatedFileUtil::DestroyDirectoryDatabaseHelper( + const absl::optional<BucketLocator>& bucket_locator, + const blink::StorageKey& storage_key, + const absl::optional<FileSystemType>& type) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - // If `type_string` is empty, delete all filesystem types under `storage_key`. - const std::string key_prefix = - GetDirectoryDatabaseKey(storage_key, type_string); + DatabaseKey key_prefix; + const std::string type_string = + type ? SandboxFileSystemBackendDelegate::GetTypeString(type.value()) + : std::string(); + // `key.bucket()` is absl::nullopt for all non-kTemporary types. + if (type && (FileSystemTypeToQuotaStorageType(type.value()) == + ::blink::mojom::StorageType::kTemporary)) { + if (bucket_locator.has_value()) { + key_prefix = + DatabaseKey(bucket_locator->storage_key, bucket_locator, type_string); + } else { + // If we are not provided a custom bucket value we must find the default + // bucket corresponding to the StorageKey. + QuotaErrorOr<BucketLocator> default_bucket = + GetOrCreateDefaultBucket(storage_key); + // If there is no default bucket for a given StorageKey, there is not a + // valid FileSystem to close, so we return. + if (!default_bucket.ok()) + return; + key_prefix = + DatabaseKey(storage_key, default_bucket.value(), type_string); + } + } else { // All other storage types. + key_prefix = DatabaseKey(storage_key, absl::nullopt, type_string); + } + + // If `type` is empty, delete all filesystem types under `storage_key`. for (auto iter = directories_.lower_bound(key_prefix); iter != directories_.end();) { - if (!base::StartsWith(iter->first, key_prefix, - base::CompareCase::SENSITIVE)) + // If the key matches exactly or `type` is absl::nullopt and just the + // StorageKey and BucketLocator match exactly, delete the database. + if (iter->first == key_prefix || + (type == absl::nullopt && + iter->first.storage_key() == key_prefix.storage_key() && + iter->first.bucket() == key_prefix.bucket())) { + std::unique_ptr<SandboxDirectoryDatabase> database = + std::move(iter->second); + directories_.erase(iter++); + database->DestroyDatabase(); + } else { break; - DCHECK(type_string.empty() || iter->first == key_prefix); - std::unique_ptr<SandboxDirectoryDatabase> database = - std::move(iter->second); - directories_.erase(iter++); - - // Continue to destroy databases even if it failed because it doesn't affect - // the final result. - database->DestroyDatabase(); + } } } @@ -1041,24 +1153,38 @@ base::FileErrorOr<base::FilePath> ObfuscatedFileUtil::GetDirectoryForURL( DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); if (!url.bucket().has_value()) { // Access the SandboxDirectoryDatabase to construct the file path. - // TODO(https://crbug.com/1310361): refactor GetDirectoryForStorageKey and - // its related functions to return a base::FileErrorOr<base::FilePath>. - base::File::Error error = base::File::FILE_OK; - base::FilePath path = GetDirectoryForStorageKeyAndType( - url.storage_key(), CallGetTypeStringForURL(url), create, &error); - if (error != base::File::FILE_OK) - return error; - return path; + return GetDirectoryForStorageKeyAndType(url.storage_key(), url.type(), + create); } // Construct the file path using the provided bucket information. - return GetDirectoryForBucketAndType(url.bucket().value(), - CallGetTypeStringForURL(url), create); + return GetDirectoryForBucketAndType(url.bucket().value(), url.type(), create); } -std::string ObfuscatedFileUtil::CallGetTypeStringForURL( - const FileSystemURL& url) { - DCHECK(!get_type_string_for_url_.is_null()); - return get_type_string_for_url_.Run(url); +QuotaErrorOr<BucketLocator> ObfuscatedFileUtil::GetOrCreateDefaultBucket( + const blink::StorageKey& storage_key) { + // If we have already looked up this default bucket for this StorageKey, + // return the cached value. + auto iter = default_buckets_.find(storage_key); + if (iter != default_buckets_.end()) { + return iter->second; + } + // GetOrCreateBucketSync() called below requires the use of the + // base::WaitableEvent sync primitive. We must explicitly declare the usage + // of this primitive to avoid thread restriction errors. + base::ScopedAllowBaseSyncPrimitives allow_wait; + // Instead of crashing, return a QuotaError if the proxy is a nullptr. + if (!sandbox_delegate_->quota_manager_proxy()) { + LOG(WARNING) << "Failed to GetOrCreateBucket: QuotaManagerProxy is null"; + return QuotaError::kUnknownError; + } + // Retrieve or create the default bucket for this StorageKey. + QuotaErrorOr<BucketInfo> bucket = + sandbox_delegate_->quota_manager_proxy()->GetOrCreateBucketSync( + BucketInitParams::ForDefaultBucket(storage_key)); + if (!bucket.ok()) + return bucket.error(); + default_buckets_[storage_key] = bucket->ToBucketLocator(); + return bucket->ToBucketLocator(); } base::File::Error ObfuscatedFileUtil::GetFileInfoInternal( @@ -1230,14 +1356,6 @@ base::FilePath ObfuscatedFileUtil::DataPathToLocalPath( return root.value().Append(data_path); } -std::string ObfuscatedFileUtil::GetDirectoryDatabaseKey( - const blink::StorageKey& storage_key, - const std::string& type_string) { - // For isolated origin we just use a type string as a key. - return GetIdentifierFromOrigin(storage_key.origin()) + - kDirectoryDatabaseKeySeparator + type_string; -} - // TODO(ericu): How to do the whole validation-without-creation thing? // We may not have quota even to create the database. // Ah, in that case don't even get here? @@ -1247,10 +1365,26 @@ SandboxDirectoryDatabase* ObfuscatedFileUtil::GetDirectoryDatabase( bool create) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - std::string key = - GetDirectoryDatabaseKey(url.storage_key(), CallGetTypeStringForURL(url)); - if (key.empty()) - return nullptr; + DatabaseKey key; + const std::string type_string = + SandboxFileSystemBackendDelegate::GetTypeString(url.type()); + // `key.bucket()` is absl::nullopt for all non-kTemporary types. + if (FileSystemTypeToQuotaStorageType(url.type()) == + ::blink::mojom::StorageType::kTemporary) { + if (url.bucket().has_value()) { + key = DatabaseKey(url.storage_key(), url.bucket().value(), type_string); + } else { + // If we are not provided a custom bucket value we must find the default + // bucket corresponding to the url's StorageKey. + QuotaErrorOr<BucketLocator> default_bucket = + GetOrCreateDefaultBucket(url.storage_key()); + if (!default_bucket.ok()) + return nullptr; + key = DatabaseKey(url.storage_key(), default_bucket.value(), type_string); + } + } else { // All other storage types. + key = DatabaseKey(url.storage_key(), absl::nullopt, type_string); + } auto iter = directories_.find(key); if (iter != directories_.end()) { @@ -1276,20 +1410,14 @@ base::FileErrorOr<base::FilePath> ObfuscatedFileUtil::GetDirectoryForStorageKey( DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); if (storage_key.IsThirdPartyContext()) { - // GetOrCreateBucketSync() called below requires the use of the - // base::WaitableEvent sync primitive. We must explicitly declare the usage - // of this primitive to avoid thread restriction errors. - base::ScopedAllowBaseSyncPrimitives allow_wait; - // Retrieve the bucket information for third-party StorageKey. - QuotaErrorOr<BucketInfo> bucket = - sandbox_delegate_->quota_manager_proxy()->GetOrCreateBucketSync( - BucketInitParams::ForDefaultBucket(storage_key)); + // Retrieve the default bucket value for `storage_key`. + QuotaErrorOr<BucketLocator> bucket = GetOrCreateDefaultBucket(storage_key); if (!bucket.ok()) return base::File::FILE_ERROR_FAILED; // Get the path and verify it is valid. base::FileErrorOr<base::FilePath> path = sandbox_delegate_->quota_manager_proxy()->GetClientBucketPath( - bucket->ToBucketLocator(), QuotaClientType::kFileSystem); + bucket.value(), QuotaClientType::kFileSystem); if (path.is_error()) return path.error(); base::File::Error error = GetDirectoryHelper(path.value(), create); @@ -1374,6 +1502,45 @@ void ObfuscatedFileUtil::RewriteDatabases() { origin_database_->RewriteDatabase(); } +void ObfuscatedFileUtil::DeleteDefaultBucketForStorageKey( + const blink::StorageKey& storage_key) { + auto default_bucket_iter = default_buckets_.find(storage_key); + // If we are not already caching the bucket for that StorageKey, it does not + // need to be deleted. + if (default_bucket_iter == default_buckets_.end()) + return; + BucketLocator default_bucket = default_buckets_[storage_key]; + // Ensure that all directories with that StorageKey and bucket have been + // erased. + DCHECK(directories_.find( + DatabaseKey(storage_key, default_bucket, + SandboxFileSystemBackendDelegate::GetTypeString( + FileSystemType::kFileSystemTypeTemporary))) == + directories_.end()); + default_buckets_.erase(default_bucket_iter); +} + +void ObfuscatedFileUtil::DeleteDefaultBucket( + const BucketLocator& bucket_locator) { + blink::StorageKey storage_key = bucket_locator.storage_key; + auto default_bucket_iter = default_buckets_.find(storage_key); + // If we are not already caching the bucket for that StorageKey, it does not + // need to be deleted. + if (default_bucket_iter == default_buckets_.end()) + return; + BucketLocator default_bucket = default_buckets_[storage_key]; + // Ensure that `default_bucket` matches `bucket_locator` + DCHECK(default_bucket == bucket_locator); + // Ensure that all directories with that StorageKey and bucket have been + // erased. + DCHECK(directories_.find( + DatabaseKey(storage_key, default_bucket, + SandboxFileSystemBackendDelegate::GetTypeString( + FileSystemType::kFileSystemTypeTemporary))) == + directories_.end()); + default_buckets_.erase(default_bucket_iter); +} + bool ObfuscatedFileUtil::InitOriginDatabase(const url::Origin& origin_hint, bool create) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); diff --git a/chromium/storage/browser/file_system/obfuscated_file_util.h b/chromium/storage/browser/file_system/obfuscated_file_util.h index 32bcb0ecec1..81187361e58 100644 --- a/chromium/storage/browser/file_system/obfuscated_file_util.h +++ b/chromium/storage/browser/file_system/obfuscated_file_util.h @@ -34,10 +34,6 @@ namespace blink { class StorageKey; } // namespace blink -namespace url { -class Origin; -} // namespace url - namespace storage { class FileSystemOperationContext; @@ -46,20 +42,68 @@ class QuotaBackendImplTest; class SandboxOriginDatabaseInterface; class SpecialStoragePolicy; -// This file util stores directory information in LevelDB to obfuscate -// and to neutralize virtual file paths given by arbitrary apps. -// Files are stored with two-level isolation: per-origin and per-type. -// The isolation is done by storing data in separate directory partitions. -// For example, a file in Temporary file system for origin 'www.example.com' -// is stored in a different partition for a file in Persistent file system -// for the same origin, or for Temporary file system for another origin. +// Class representing the key for directories_. NOTE: The `bucket` value is +// optional due to usage of ObfuscatedFileUtil where the type is not kTemporary +// (i.e. kPersistent or kSyncable). For all non-temporary types, expect the +// bucket member value to be absl::nullopt. The class is implemented as such to +// avoid mapping the same StorageKey to potentially different bucket values, +// which would cause directories_ lookup errors. NOTE: The `type_string` value +// is empty when designating a "top-level directory" or a directory that +// contains one or more subdirectories with a non-empty type. This class stores +// a string rather than the FileSystemType itself because multiple +// FileSystemTypes can map to the same `type_string`, and preserving this +// behavior is necessary to retrieving and deleting ObfuscatedFilePaths +// correctly. +class DatabaseKey { + public: + DatabaseKey(); + ~DatabaseKey(); + + // Copyable and movable + DatabaseKey(const DatabaseKey& other); + DatabaseKey& operator=(const DatabaseKey& other); + DatabaseKey(DatabaseKey&& other); + DatabaseKey& operator=(DatabaseKey&& other); + + DatabaseKey(const blink::StorageKey& storage_key, + const absl::optional<BucketLocator>& bucket, + const std::string& type_string); + + const blink::StorageKey& storage_key() const { return storage_key_; } + const absl::optional<BucketLocator>& bucket() const { return bucket_; } + const std::string& type() const { return type_; } + + bool operator==(const DatabaseKey& other) const; + bool operator!=(const DatabaseKey& other) const; + bool operator<(const DatabaseKey& other) const; + + private: + blink::StorageKey storage_key_; + absl::optional<BucketLocator> bucket_; + std::string type_; +}; + +// This file util stores directory information in either LevelDB or +// StorageBuckets to obfuscate and to neutralize virtual file paths given by +// arbitrary apps. Files are stored with three-level isolation: (1) +// per-StorageKey, (2) per-bucket, and (3) per-type. The isolation is done by +// storing data in separate directory partitions. For example, a file in +// Temporary file system for origin 'www.example.com' is stored in a different +// partition from a file in Persistent file system for the same origin, or from +// a file in a Temporary file system for another origin. Similarly, a file in a +// Temporary file system for origin 'www.foo.com' with a default bucket is +// stored in a different partition from a non-default bucket for the same origin +// and Temporary file system. // -// * Per-origin directory name information is stored in a separate LevelDB, -// which is maintained by SandboxOriginDatabase. -// * Per-type directory name information is given by -// GetTypeStringForURLCallback that is given in CTOR. -// We use a small static mapping (e.g. 't' for Temporary type) for -// regular sandbox filesystems. +// * For default first-party StorageKeys, per-origin directory name information +// is stored in a separate LevelDB, which is maintained by +// SandboxOriginDatabase. For per-type information, we use a small static +// mapping (e.g. 't' for Temporary type) for regular sandbox filesystems. +// NOTE/TODO(https://crbug.com/1349156): the goal is to eventually deprecate +// SandboxOriginDatabase and rely entirely on Storage Buckets. +// * For all other StorageKeys, we rely on quota management of Storage Buckets +// in addition to the same static mapping of per-type information described +// above. // // The overall implementation philosophy of this class is that partial failures // should leave us with an intact database; we'd prefer to leak the occasional @@ -69,21 +113,16 @@ class SpecialStoragePolicy; // // This class must be deleted on the FILE thread, because that's where // DropDatabases needs to be called. -// -// TODO(https://crbug.com/1248104): This class will eventually use Storage -// Buckets instead of LevelDB. Thus, the below functions were converted from -// url::Origin to blink::StorageKey to prepare for Storage Partitioning of the -// FileSystem APIs. However, it is important to note that, until the refactor to -// use Storage Buckets, the LevelDB structure above is still used, and the -// entries are still keyed per-origin (achieved by storage_key.origin()) and -// per-type. Going forward, comments will refer to the DB as "origin database" -// or the directory as "origin directory", but the origin will come from a -// larger StorageKey object. class COMPONENT_EXPORT(STORAGE_BROWSER) ObfuscatedFileUtil : public FileSystemFileUtil { public: // StorageKey enumerator interface. // An instance of this interface is assumed to be called on the file thread. + // NOTE: currently, ObfuscatedFileUtil still relies on SandboxOriginDatabases + // for first-party StorageKeys/default buckets. The + // AbstractStorageKeyEnumerator is only used in these cases. While this class + // stores StorageKeys, it ultimately relies on only the origin information to + // access the appropriate SandboxOriginDatabase. class AbstractStorageKeyEnumerator { public: virtual ~AbstractStorageKeyEnumerator() = default; @@ -92,28 +131,26 @@ class COMPONENT_EXPORT(STORAGE_BROWSER) ObfuscatedFileUtil // StorageKeys. virtual absl::optional<blink::StorageKey> Next() = 0; - // Returns the current origin's information. + // Returns the current StorageKey's information. // `type_string` must be ascii string. virtual bool HasTypeDirectory(const std::string& type_string) const = 0; }; - using GetTypeStringForURLCallback = - base::RepeatingCallback<std::string(const FileSystemURL&)>; - - // `get_type_string_for_url` is user-defined callback that should return - // a type string for the given FileSystemURL. The type string is used - // to provide per-type isolation in the sandboxed filesystem directory. - // - // `known_type_strings` are known type string names that this file system - // should care about. - // This info is used to determine whether we could delete the entire - // origin directory or not in DeleteDirectoryForStorageKeyAndType. If no - // directory for any known type exists the origin directory may get - // deleted when one StorageKey/type pair is deleted. + // The FileSystem directory component. + static const base::FilePath::CharType kFileSystemDirectory[]; + + // The type string is used to provide per-type isolation in the sandboxed + // filesystem directory. `known_type_strings` are known type string names that + // this file system should care about. This info is used to determine whether + // we could delete the entire origin directory or not in + // DeleteDirectoryForStorageKeyAndType. If no directory for any known type + // exists the origin directory may get deleted when one StorageKey/type pair + // is deleted. NOTE: type strings are not mapped 1-to-1 with FileSystemType, + // and as a result, directories should only be directly compared using type + // string values. ObfuscatedFileUtil(scoped_refptr<SpecialStoragePolicy> special_storage_policy, - const base::FilePath& file_system_directory, + const base::FilePath& profile_path, leveldb::Env* env_override, - GetTypeStringForURLCallback get_type_string_for_url, const std::set<std::string>& known_type_strings, SandboxFileSystemBackendDelegate* sandbox_delegate, bool is_incognito); @@ -177,47 +214,56 @@ class COMPONENT_EXPORT(STORAGE_BROWSER) ObfuscatedFileUtil // Gets the topmost directory specific to this BucketLocator and type. This // will contain both the directory database's files and all the backing file // subdirectories. - // Returns the topmost origin directory if `type_string` is empty. + // Returns the topmost origin directory if `type` is empty. // Returns a base::FileError if the directory is undefined. base::FileErrorOr<base::FilePath> GetDirectoryForBucketAndType( const BucketLocator& bucket_locator, - const std::string& type_string, + const absl::optional<FileSystemType>& type, bool create); // Gets the topmost directory specific to this StorageKey and type. This will // contain both the directory database's files and all the backing file // subdirectories. - // Returns the topmost origin directory if `type_string` is empty. + // Returns the topmost origin directory if `type` is empty. // Returns an empty path if the directory is undefined. // If the directory is defined, it will be returned, even if // there is a file system error (e.g. the directory doesn't exist on disk and - // `create` is false). Callers should always check `error_code` to make sure - // the returned path is usable. - base::FilePath GetDirectoryForStorageKeyAndType( + // `create` is false). + base::FileErrorOr<base::FilePath> GetDirectoryForStorageKeyAndType( const blink::StorageKey& storage_key, - const std::string& type_string, - bool create, - base::File::Error* error_code); + const absl::optional<FileSystemType>& type, + bool create); - // Deletes the topmost directory specific to this StorageKey and type. This - // will delete its directory database. Deletes the topmost origin - // directory if `type_string` is empty. - bool DeleteDirectoryForStorageKeyAndType(const blink::StorageKey& storage_key, - const std::string& type_string); + // Deletes the topmost directory specific to this StorageKey and type. This + // will delete its directory database. Deletes the topmost StorageKey + // directory if `type` is absl::nullopt. + bool DeleteDirectoryForStorageKeyAndType( + const blink::StorageKey& storage_key, + const absl::optional<FileSystemType>& type); - // Frees resources used by a StorageKey's filesystem. - void CloseFileSystemForStorageKeyAndType(const blink::StorageKey& storage_key, - const std::string& type_string); + // Deletes the topmost directory specific to this BucketLocator and type. This + // will delete its directory database. Deletes the topmost bucket + // directory if `type` is absl::nullopt. + bool DeleteDirectoryForBucketAndType( + const BucketLocator& bucket_locator, + const absl::optional<FileSystemType>& type); // This method and all methods of its returned class must be called only on // the FILE thread. The caller is responsible for deleting the returned // object. std::unique_ptr<AbstractStorageKeyEnumerator> CreateStorageKeyEnumerator(); - // Deletes a directory database from the database list in the ObfuscatedFSFU - // and destroys the database on the disk. - void DestroyDirectoryDatabase(const blink::StorageKey& storage_key, - const std::string& type_string); + // Deletes a directory database from the database list and destroys the + // database on the disk corresponding to the provided StorageKey and type. + void DestroyDirectoryDatabaseForStorageKey( + const blink::StorageKey& storage_key, + const absl::optional<FileSystemType>& type); + + // Deletes a directory database from the database list and destroys the + // database on the disk corresponding to the provided bucket locator and type. + void DestroyDirectoryDatabaseForBucket( + const BucketLocator& bucket_locator, + const absl::optional<FileSystemType>& type); // Computes a cost for storing a given file in the obfuscated FSFU. // As the cost of a file is independent of the cost of its parent directories, @@ -229,6 +275,18 @@ class COMPONENT_EXPORT(STORAGE_BROWSER) ObfuscatedFileUtil // This will rewrite the databases to remove traces of deleted data from disk. void RewriteDatabases(); + // This function removes the key-value pair from default_buckets_ keyed at + // `storage_key`. Called when a default bucket is deleted from Quota + // management and the default_buckets_ cache needs to be updated to reflect + // that change in state. + void DeleteDefaultBucketForStorageKey(const blink::StorageKey& storage_key); + + // This function removes the key-value pair(s) from default_buckets_ with the + // value `bucket_locator`. Called when a default bucket is deleted from Quota + // management and the default_buckets_ cache needs to be updated to reflect + // that change in state. + void DeleteDefaultBucket(const BucketLocator& bucket_locator); + bool is_incognito() { return is_incognito_; } ObfuscatedFileUtilDelegate* delegate() { return delegate_.get(); } @@ -244,6 +302,7 @@ class COMPONENT_EXPORT(STORAGE_BROWSER) ObfuscatedFileUtil friend class ObfuscatedFileEnumerator; friend class ObfuscatedFileUtilTest; friend class QuotaBackendImplTest; + friend class SandboxFileSystemBackendDelegate; // Helper method to create an obfuscated file util for regular // (temporary, persistent) file systems. Used only for testing. @@ -257,9 +316,6 @@ class COMPONENT_EXPORT(STORAGE_BROWSER) ObfuscatedFileUtil base::FileErrorOr<base::FilePath> GetDirectoryForURL(const FileSystemURL& url, bool create); - // This just calls get_type_string_for_url_ callback that is given in ctor. - std::string CallGetTypeStringForURL(const FileSystemURL& url); - base::File::Error GetFileInfoInternal(SandboxDirectoryDatabase* db, FileSystemOperationContext* context, const FileSystemURL& url, @@ -301,8 +357,12 @@ class COMPONENT_EXPORT(STORAGE_BROWSER) ObfuscatedFileUtil base::FilePath DataPathToLocalPath(const FileSystemURL& url, const base::FilePath& data_file_path); - std::string GetDirectoryDatabaseKey(const blink::StorageKey& storage_key, - const std::string& type_string); + // Deletes a directory database from the database list and destroys the + // database on the disk. + void DestroyDirectoryDatabaseHelper( + const absl::optional<BucketLocator>& bucket_locator, + const blink::StorageKey& storage_key, + const absl::optional<FileSystemType>& type); // This returns nullptr if `create` flag is false and a filesystem does not // exist for the given `url`. @@ -327,6 +387,14 @@ class COMPONENT_EXPORT(STORAGE_BROWSER) ObfuscatedFileUtil const blink::StorageKey& storage_key, FileSystemType type); + // Given a StorageKey, retrieve its default bucket either from the + // default_buckets_ in-memory structure or via GetOrCreateBucketSync(). NOTE: + // this function may use base::ScopedAllowBaseSyncPrimitives and call + // QuotaManagerProxy::GetOrCreateBucketSync() which relies on a blocking + // base::WaitableEvent. + QuotaErrorOr<BucketLocator> GetOrCreateDefaultBucket( + const blink::StorageKey& storage_key); + void MarkUsed(); void DropDatabases(); @@ -348,7 +416,10 @@ class COMPONENT_EXPORT(STORAGE_BROWSER) ObfuscatedFileUtil SEQUENCE_CHECKER(sequence_checker_); - std::map<std::string, std::unique_ptr<SandboxDirectoryDatabase>> directories_; + // Keeps tracks of previously-seen default buckets mapped to their + // corresponding StorageKey. Should remain in parallel with directories_. + std::map<blink::StorageKey, BucketLocator> default_buckets_; + std::map<DatabaseKey, std::unique_ptr<SandboxDirectoryDatabase>> directories_; std::unique_ptr<SandboxOriginDatabaseInterface> origin_database_; scoped_refptr<SpecialStoragePolicy> special_storage_policy_; base::FilePath file_system_directory_; @@ -360,7 +431,6 @@ class COMPONENT_EXPORT(STORAGE_BROWSER) ObfuscatedFileUtil base::OneShotTimer timer_; - GetTypeStringForURLCallback get_type_string_for_url_; std::set<std::string> known_type_strings_; // Not owned. diff --git a/chromium/storage/browser/file_system/obfuscated_file_util_memory_delegate.cc b/chromium/storage/browser/file_system/obfuscated_file_util_memory_delegate.cc index 326e9d85df9..e9db5bb939b 100644 --- a/chromium/storage/browser/file_system/obfuscated_file_util_memory_delegate.cc +++ b/chromium/storage/browser/file_system/obfuscated_file_util_memory_delegate.cc @@ -10,6 +10,7 @@ #include "base/allocator/partition_allocator/partition_alloc_constants.h" #include "base/files/file_util.h" #include "base/numerics/checked_math.h" +#include "base/numerics/safe_conversions.h" #include "base/system/sys_info.h" #include "build/build_config.h" #include "net/base/io_buffer.h" @@ -26,14 +27,14 @@ namespace { // crash possibility. // Note that quota assignment is the same for on-disk filesystem and the // assigned quota is not guaranteed to be allocatable later. -bool IsMemoryAvailable(int64_t required_memory) { +bool IsMemoryAvailable(size_t required_memory) { #if BUILDFLAG(IS_FUCHSIA) // This function is not implemented on FUCHSIA, yet. (crbug.com/986608) return true; #else - int64_t max_allocatable = + uint64_t max_allocatable = std::min(base::SysInfo::AmountOfAvailablePhysicalMemory(), - static_cast<int64_t>(partition_alloc::MaxDirectMapped())); + static_cast<uint64_t>(partition_alloc::MaxDirectMapped())); return max_allocatable >= required_memory; #endif @@ -335,12 +336,13 @@ base::File::Error ObfuscatedFileUtilMemoryDelegate::Truncate( return base::File::FILE_ERROR_NOT_FOUND; // Fail if enough memory is not available. - if (static_cast<size_t>(length) > dp->entry->file_content.capacity() && - !IsMemoryAvailable(length)) { + if (!base::IsValueInRangeForNumericType<size_t>(length) || + (static_cast<size_t>(length) > dp->entry->file_content.capacity() && + !IsMemoryAvailable(static_cast<size_t>(length)))) { return base::File::FILE_ERROR_NO_SPACE; } - dp->entry->file_content.resize(length); + dp->entry->file_content.resize(static_cast<size_t>(length)); return base::File::FILE_OK; } @@ -620,7 +622,7 @@ base::File::Error ObfuscatedFileUtilMemoryDelegate::CopyInForeignFile( } // Fail if enough memory is not available. - if (!IsMemoryAvailable(source_info.size)) + if (!IsMemoryAvailable(static_cast<size_t>(source_info.size))) return base::File::FILE_ERROR_NO_SPACE; // Create file. diff --git a/chromium/storage/browser/file_system/obfuscated_file_util_unittest.cc b/chromium/storage/browser/file_system/obfuscated_file_util_unittest.cc index 2335c0dd625..09174f73c3a 100644 --- a/chromium/storage/browser/file_system/obfuscated_file_util_unittest.cc +++ b/chromium/storage/browser/file_system/obfuscated_file_util_unittest.cc @@ -27,10 +27,12 @@ #include "base/test/bind.h" #include "base/test/scoped_feature_list.h" #include "base/test/task_environment.h" +#include "base/test/test_future.h" #include "base/threading/thread_restrictions.h" #include "base/threading/thread_task_runner_handle.h" #include "build/build_config.h" #include "components/services/filesystem/public/mojom/types.mojom.h" +#include "net/base/features.h" #include "net/base/io_buffer.h" #include "storage/browser/file_system/external_mount_points.h" #include "storage/browser/file_system/file_system_backend.h" @@ -53,7 +55,6 @@ #include "storage/common/database/database_identifier.h" #include "storage/common/file_system/file_system_types.h" #include "testing/gtest/include/gtest/gtest.h" -#include "third_party/blink/public/common/features.h" #include "third_party/blink/public/common/storage_key/storage_key.h" #include "third_party/leveldatabase/leveldb_chrome.h" #include "url/gurl.h" @@ -64,7 +65,16 @@ namespace storage { namespace { -enum TestMode { kRegular, kIncognito }; +enum TestMode { + kRegularFirstParty, + kRegularFirstPartyNonDefaultBucket, + kRegularThirdParty, + kRegularThirdPartyNonDefaultBucket, + kIncognitoFirstParty, + kIncognitoFirstPartyNonDefaultBucket, + kIncognitoThirdParty, + kIncognitoThirdPartyNonDefaultBucket +}; bool FileExists(const base::FilePath& path) { return base::PathExists(path) && !base::DirectoryExists(path); @@ -124,20 +134,30 @@ const OriginEnumerationTestRecord kOriginEnumerationTestRecords[] = { FileSystemURL FileSystemURLAppend(const FileSystemURL& url, const base::FilePath::StringType& child) { - return FileSystemURL::CreateForTest(url.storage_key(), url.mount_type(), - url.virtual_path().Append(child)); + FileSystemURL new_url = FileSystemURL::CreateForTest( + url.storage_key(), url.mount_type(), url.virtual_path().Append(child)); + if (url.bucket().has_value()) + new_url.SetBucket(url.bucket().value()); + return new_url; } FileSystemURL FileSystemURLAppendUTF8(const FileSystemURL& url, const std::string& child) { - return FileSystemURL::CreateForTest( + FileSystemURL new_url = FileSystemURL::CreateForTest( url.storage_key(), url.mount_type(), url.virtual_path().Append(base::FilePath::FromUTF8Unsafe(child))); + if (url.bucket().has_value()) + new_url.SetBucket(url.bucket().value()); + return new_url; } FileSystemURL FileSystemURLDirName(const FileSystemURL& url) { - return FileSystemURL::CreateForTest(url.storage_key(), url.mount_type(), - VirtualPath::DirName(url.virtual_path())); + FileSystemURL new_url = + FileSystemURL::CreateForTest(url.storage_key(), url.mount_type(), + VirtualPath::DirName(url.virtual_path())); + if (url.bucket().has_value()) + new_url.SetBucket(url.bucket().value()); + return new_url; } std::string GetTypeString(FileSystemType type) { @@ -166,14 +186,42 @@ class ObfuscatedFileUtilTest : public testing::Test, type_(kFileSystemTypeTemporary), sandbox_file_system_(storage_key_, type_), quota_status_(blink::mojom::QuotaStatusCode::kUnknown), - usage_(-1) {} + usage_(-1) { + if (is_third_party_context()) { + scoped_feature_list_.InitAndEnableFeature( + net::features::kThirdPartyStoragePartitioning); + // Once we enable third-party storage partitioning, we can create a + // third-party StorageKey and re-assign the StorageKey value in the + // SandboxFileSystem with this value in SetUp for default buckets. + storage_key_ = blink::StorageKey::CreateWithOptionalNonce( + storage_key_.origin(), storage_key_.top_level_site(), nullptr, + blink::mojom::AncestorChainBit::kCrossSite); + } + } ObfuscatedFileUtilTest(const ObfuscatedFileUtilTest&) = delete; ObfuscatedFileUtilTest& operator=(const ObfuscatedFileUtilTest&) = delete; ~ObfuscatedFileUtilTest() override = default; - bool is_incognito() { return GetParam() == TestMode::kIncognito; } + bool is_incognito() { + return GetParam() == TestMode::kIncognitoFirstParty || + (GetParam() == TestMode::kIncognitoFirstPartyNonDefaultBucket) || + (GetParam() == TestMode::kIncognitoThirdParty) || + (GetParam() == TestMode::kIncognitoThirdPartyNonDefaultBucket); + } + bool is_third_party_context() { + return GetParam() == TestMode::kRegularThirdParty || + (GetParam() == TestMode::kRegularThirdPartyNonDefaultBucket) || + (GetParam() == TestMode::kIncognitoThirdParty) || + (GetParam() == TestMode::kIncognitoThirdPartyNonDefaultBucket); + } + bool is_non_default_bucket() { + return GetParam() == TestMode::kRegularFirstPartyNonDefaultBucket || + (GetParam() == TestMode::kRegularThirdPartyNonDefaultBucket) || + (GetParam() == TestMode::kIncognitoFirstPartyNonDefaultBucket) || + (GetParam() == TestMode::kIncognitoThirdPartyNonDefaultBucket); + } void SetUp() override { ASSERT_TRUE(data_dir_.CreateUniqueTempDir()); @@ -212,7 +260,42 @@ class ObfuscatedFileUtilTest : public testing::Test, : CreateFileSystemContextForTesting( quota_manager_->proxy(), data_dir_.GetPath()); - sandbox_file_system_.SetUp(file_system_context_); + // Create the default bucket member corresponding to the StorageKey member + // we created. + base::test::TestFuture<QuotaErrorOr<BucketInfo>> default_future; + quota_manager_->proxy()->UpdateOrCreateBucket( + BucketInitParams::ForDefaultBucket(storage_key()), + base::SequencedTaskRunnerHandle::Get(), default_future.GetCallback()); + QuotaErrorOr<BucketInfo> default_bucket = default_future.Take(); + CHECK(default_bucket.ok()); + default_bucket_ = default_bucket.value().ToBucketLocator(); + + // Create a non-default bucket member corresponding to the StorageKey + // member we created. + base::test::TestFuture<QuotaErrorOr<BucketInfo>> custom_future; + BucketInitParams params = BucketInitParams::ForDefaultBucket(storage_key()); + params.name = "non-default bucket"; + quota_manager_->proxy()->UpdateOrCreateBucket( + params, base::SequencedTaskRunnerHandle::Get(), + custom_future.GetCallback()); + QuotaErrorOr<BucketInfo> custom_bucket = custom_future.Take(); + CHECK(custom_bucket.ok()); + custom_bucket_ = custom_bucket.value().ToBucketLocator(); + + // Create an alternate non-default bucket member corresponding to the + // StorageKey member we created. + base::test::TestFuture<QuotaErrorOr<BucketInfo>> alternate_future; + params.name = "alternate non-default bucket"; + quota_manager_->proxy()->UpdateOrCreateBucket( + params, base::SequencedTaskRunnerHandle::Get(), + alternate_future.GetCallback()); + QuotaErrorOr<BucketInfo> alternate_bucket = alternate_future.Take(); + CHECK(alternate_bucket.ok()); + alternate_custom_bucket_ = alternate_bucket.value().ToBucketLocator(); + + is_non_default_bucket() + ? sandbox_file_system_.SetUp(file_system_context_, custom_bucket_) + : sandbox_file_system_.SetUp(file_system_context_, storage_key_); change_observers_ = MockFileChangeObserver::CreateList(&change_observer_); @@ -263,17 +346,28 @@ class ObfuscatedFileUtilTest : public testing::Test, // This can only be used after SetUp has run and created file_system_context_ // and obfuscated_file_util_. - // Use this for tests which need to run in multiple origins; we need a test - // helper per origin. + // Use this for tests which need to run in multiple StorageKeys; we need a + // test helper per StorageKey. + std::unique_ptr<SandboxFileSystemTestHelper> NewFileSystem( + const blink::StorageKey& storage_key, + FileSystemType type) { + auto file_system = + std::make_unique<SandboxFileSystemTestHelper>(storage_key, type); + file_system->SetUp(file_system_context_); + return file_system; + } + + // This can only be used after SetUp has run and created file_system_context_ + // and obfuscated_file_util_. + // Use this for tests which need to run in multiple BucketLocators; we need a + // test helper per BucketLocator. std::unique_ptr<SandboxFileSystemTestHelper> NewFileSystem( - const Origin& origin, + const BucketLocator& bucket_locator, FileSystemType type) { - // TODO(https://crbug.com/1245710): Refactor ObfuscatedFileSystem to use - // StorageKey instead of origin and replace in-line conversion below. auto file_system = std::make_unique<SandboxFileSystemTestHelper>( - blink::StorageKey(origin), type); + bucket_locator.storage_key, type); - file_system->SetUp(file_system_context_); + file_system->SetUp(file_system_context_, bucket_locator); return file_system; } @@ -307,8 +401,8 @@ class ObfuscatedFileUtilTest : public testing::Test, void GetUsageFromQuotaManager() { int64_t quota = -1; quota_status_ = AsyncFileTestHelper::GetUsageAndQuota( - quota_manager_->proxy(), origin(), sandbox_file_system_.type(), &usage_, - "a); + quota_manager_->proxy(), storage_key(), sandbox_file_system_.type(), + &usage_, "a); EXPECT_EQ(blink::mojom::QuotaStatusCode::kOk, quota_status_); } @@ -321,7 +415,10 @@ class ObfuscatedFileUtilTest : public testing::Test, sandbox_file_system->storage_type()); }, quota_manager_, &sandbox_file_system_)); - usage_cache()->Delete(sandbox_file_system_.GetUsageCachePath()); + base::FileErrorOr<base::FilePath> path = + sandbox_file_system_.GetUsageCachePath(); + if (!path.is_error()) + usage_cache()->Delete(path.value()); } int64_t SizeByQuotaUtil() { return sandbox_file_system_.GetCachedUsage(); } @@ -329,10 +426,11 @@ class ObfuscatedFileUtilTest : public testing::Test, int64_t SizeInUsageFile() { task_environment_.RunUntilIdle(); int64_t usage = 0; - return usage_cache()->GetUsage(sandbox_file_system_.GetUsageCachePath(), - &usage) - ? usage - : -1; + base::FileErrorOr<base::FilePath> path = + sandbox_file_system_.GetUsageCachePath(); + if (path.is_error()) + return -1; + return usage_cache()->GetUsage(path.value(), &usage) ? usage : -1; } bool PathExists(const FileSystemURL& url) { @@ -363,18 +461,24 @@ class ObfuscatedFileUtilTest : public testing::Test, return sandbox_file_system_.usage_cache(); } + FileSystemURL CreateURL(const base::FilePath& path) { + FileSystemURL test_url = sandbox_file_system_.CreateURL(path); + if (is_non_default_bucket()) + test_url.SetBucket(custom_bucket_); + return test_url; + } + FileSystemURL CreateURLFromUTF8(const std::string& path) { - return sandbox_file_system_.CreateURLFromUTF8(path); + FileSystemURL test_url = sandbox_file_system_.CreateURLFromUTF8(path); + if (is_non_default_bucket()) + test_url.SetBucket(custom_bucket_); + return test_url; } int64_t PathCost(const FileSystemURL& url) { return ObfuscatedFileUtil::ComputeFilePathCost(url.path()); } - FileSystemURL CreateURL(const base::FilePath& path) { - return sandbox_file_system_.CreateURL(path); - } - void CheckFile(const FileSystemURL& url) { std::unique_ptr<FileSystemOperationContext> context = NewContext(nullptr); base::FilePath local_path; @@ -757,42 +861,45 @@ class ObfuscatedFileUtilTest : public testing::Test, } void DestroyDirectoryDatabase_IsolatedTestBody() { - storage_policy_->AddIsolated(storage_key_.origin().GetURL()); - std::unique_ptr<ObfuscatedFileUtil> file_util = - CreateObfuscatedFileUtil(/*storage_policy=*/storage_policy_); - const FileSystemURL url = FileSystemURL::CreateForTest( - storage_key_, kFileSystemTypePersistent, base::FilePath()); + storage_policy_->AddIsolated(origin().GetURL()); + FileSystemURL url = FileSystemURL::CreateForTest( + storage_key(), kFileSystemTypePersistent, base::FilePath()); + if (is_non_default_bucket()) + url.SetBucket(custom_bucket_); // Create DirectoryDatabase for isolated origin. SandboxDirectoryDatabase* db = - file_util->GetDirectoryDatabase(url, true /* create */); + ofu()->GetDirectoryDatabase(url, true /* create */); ASSERT_TRUE(db != nullptr); // Destroy it. - file_util->DestroyDirectoryDatabase(url.storage_key(), - GetTypeString(url.type())); - ASSERT_TRUE(file_util->directories_.empty()); + (is_non_default_bucket()) ? ofu()->DestroyDirectoryDatabaseForBucket( + url.bucket().value(), url.type()) + : ofu()->DestroyDirectoryDatabaseForStorageKey( + url.storage_key(), url.type()); + ASSERT_TRUE(ofu()->directories_.empty()); } void GetDirectoryDatabase_IsolatedTestBody() { - storage_policy_->AddIsolated(storage_key_.origin().GetURL()); - std::unique_ptr<ObfuscatedFileUtil> file_util = - CreateObfuscatedFileUtil(storage_policy_); - const FileSystemURL url = FileSystemURL::CreateForTest( - storage_key_, kFileSystemTypePersistent, base::FilePath()); + storage_policy_->AddIsolated(origin().GetURL()); + FileSystemURL url = FileSystemURL::CreateForTest( + blink::StorageKey(origin()), kFileSystemTypePersistent, + base::FilePath()); + if (is_non_default_bucket()) + url.SetBucket(custom_bucket_); // Create DirectoryDatabase for isolated origin. SandboxDirectoryDatabase* db = - file_util->GetDirectoryDatabase(url, true /* create */); + ofu()->GetDirectoryDatabase(url, true /* create */); ASSERT_TRUE(db != nullptr); - ASSERT_EQ(1U, file_util->directories_.size()); + ASSERT_EQ(1U, ofu()->directories_.size()); // Remove isolated. storage_policy_->RemoveIsolated(url.origin().GetURL()); // This should still get the same database. SandboxDirectoryDatabase* db2 = - file_util->GetDirectoryDatabase(url, false /* create */); + ofu()->GetDirectoryDatabase(url, false /* create */); ASSERT_EQ(db, db2); } @@ -816,6 +923,7 @@ class ObfuscatedFileUtilTest : public testing::Test, } protected: + base::test::ScopedFeatureList scoped_feature_list_; std::unique_ptr<leveldb::Env> incognito_leveldb_environment_; base::test::TaskEnvironment task_environment_; base::ScopedTempDir data_dir_; @@ -824,6 +932,9 @@ class ObfuscatedFileUtilTest : public testing::Test, scoped_refptr<base::SingleThreadTaskRunner> quota_manager_task_runner_; scoped_refptr<FileSystemContext> file_system_context_; blink::StorageKey storage_key_; + BucketLocator default_bucket_; + BucketLocator custom_bucket_; + BucketLocator alternate_custom_bucket_; FileSystemType type_; SandboxFileSystemTestHelper sandbox_file_system_; blink::mojom::QuotaStatusCode quota_status_; @@ -833,10 +944,17 @@ class ObfuscatedFileUtilTest : public testing::Test, base::WeakPtrFactory<ObfuscatedFileUtilTest> weak_factory_{this}; }; -INSTANTIATE_TEST_SUITE_P(All, - ObfuscatedFileUtilTest, - testing::Values(TestMode::kRegular, - TestMode::kIncognito)); +INSTANTIATE_TEST_SUITE_P( + All, + ObfuscatedFileUtilTest, + testing::Values(TestMode::kRegularFirstParty, + TestMode::kRegularFirstPartyNonDefaultBucket, + TestMode::kRegularThirdParty, + TestMode::kRegularThirdPartyNonDefaultBucket, + TestMode::kIncognitoFirstParty, + TestMode::kIncognitoFirstPartyNonDefaultBucket, + TestMode::kIncognitoThirdParty, + TestMode::kIncognitoThirdPartyNonDefaultBucket)); TEST_P(ObfuscatedFileUtilTest, TestCreateAndDeleteFile) { FileSystemURL url = CreateURLFromUTF8("fake/file"); @@ -1602,6 +1720,14 @@ TEST_P(ObfuscatedFileUtilTest, TestStorageKeyEnumerator) { ofu()->CreateStorageKeyEnumerator(); // The test helper starts out with a single filesystem. EXPECT_TRUE(enumerator.get()); + // This test is not relevant for third-party or non-default buckets code paths + // because these paths do not add to the OriginDatabase, the structure that + // populates the enumerator being tested. So in a test environment, this + // enumerator should not have any additional StorageKeys to access via Next(). + if (is_third_party_context() || is_non_default_bucket()) { + EXPECT_EQ(absl::nullopt, enumerator->Next()); + return; + } EXPECT_EQ(storage_key(), enumerator->Next()); ASSERT_TRUE(type() == kFileSystemTypeTemporary); EXPECT_TRUE(HasFileSystemType(enumerator.get(), kFileSystemTypeTemporary)); @@ -1623,7 +1749,7 @@ TEST_P(ObfuscatedFileUtilTest, TestStorageKeyEnumerator) { storage_keys_expected.insert(storage_key); if (record.has_temporary) { std::unique_ptr<SandboxFileSystemTestHelper> file_system = - NewFileSystem(storage_key.origin(), kFileSystemTypeTemporary); + NewFileSystem(storage_key, kFileSystemTypeTemporary); std::unique_ptr<FileSystemOperationContext> context( NewContext(file_system.get())); bool created = false; @@ -1635,7 +1761,7 @@ TEST_P(ObfuscatedFileUtilTest, TestStorageKeyEnumerator) { } if (record.has_persistent) { std::unique_ptr<SandboxFileSystemTestHelper> file_system = - NewFileSystem(storage_key.origin(), kFileSystemTypePersistent); + NewFileSystem(storage_key, kFileSystemTypePersistent); std::unique_ptr<FileSystemOperationContext> context( NewContext(file_system.get())); bool created = false; @@ -1752,7 +1878,9 @@ TEST_P(ObfuscatedFileUtilTest, TestInconsistency) { EXPECT_EQ(10, file_info.size); // Destroy database to make inconsistency between database and filesystem. - ofu()->DestroyDirectoryDatabase(storage_key(), type_string()); + (is_non_default_bucket()) + ? ofu()->DestroyDirectoryDatabaseForBucket(custom_bucket_, type()) + : ofu()->DestroyDirectoryDatabaseForStorageKey(storage_key(), type()); // Try to get file info of broken file. EXPECT_FALSE(PathExists(kPath1)); @@ -1772,7 +1900,9 @@ TEST_P(ObfuscatedFileUtilTest, TestInconsistency) { EXPECT_TRUE(created); // Destroy again. - ofu()->DestroyDirectoryDatabase(storage_key(), type_string()); + (is_non_default_bucket()) + ? ofu()->DestroyDirectoryDatabaseForBucket(custom_bucket_, type()) + : ofu()->DestroyDirectoryDatabaseForStorageKey(storage_key(), type()); // Repair broken `kPath1`. context = NewContext(nullptr); @@ -1790,7 +1920,9 @@ TEST_P(ObfuscatedFileUtilTest, TestInconsistency) { FileSystemOperation::CopyOrMoveOptionSet(), true /* copy */)); - ofu()->DestroyDirectoryDatabase(storage_key(), type_string()); + (is_non_default_bucket()) + ? ofu()->DestroyDirectoryDatabaseForBucket(custom_bucket_, type()) + : ofu()->DestroyDirectoryDatabaseForStorageKey(storage_key(), type()); context = NewContext(nullptr); created = false; EXPECT_EQ(base::File::FILE_OK, @@ -2051,12 +2183,12 @@ TEST_P(ObfuscatedFileUtilTest, TestFileEnumeratorTimestamp) { while (!(file_path_each = file_enum->Next()).empty()) { context = NewContext(nullptr); base::File::Info file_info; - EXPECT_EQ(base::File::FILE_OK, - ofu()->GetFileInfo( - context.get(), - FileSystemURL::CreateForTest( - dir.storage_key(), dir.mount_type(), file_path_each), - &file_info, &file_path)); + FileSystemURL new_url = FileSystemURL::CreateForTest( + dir.storage_key(), dir.mount_type(), file_path_each); + if (dir.bucket().has_value()) + new_url.SetBucket(dir.bucket().value()); + EXPECT_EQ(base::File::FILE_OK, ofu()->GetFileInfo(context.get(), new_url, + &file_info, &file_path)); EXPECT_EQ(file_info.is_directory, file_enum->IsDirectory()); EXPECT_EQ(file_info.last_modified, file_enum->LastModifiedTime()); EXPECT_EQ(file_info.size, file_enum->Size()); @@ -2421,7 +2553,80 @@ TEST_P(ObfuscatedFileUtilTest, CreateDirectory_NotADirectoryInRecursive) { false /* exclusive */, true /* recursive */)); } -TEST_P(ObfuscatedFileUtilTest, DeleteDirectoryForOriginAndType) { +TEST_P(ObfuscatedFileUtilTest, DeleteDirectoryForBucketAndType) { + // Create directories. + std::unique_ptr<SandboxFileSystemTestHelper> fs1 = + NewFileSystem(default_bucket_, kFileSystemTypeTemporary); + std::unique_ptr<SandboxFileSystemTestHelper> fs2 = + NewFileSystem(default_bucket_, kFileSystemTypePersistent); + std::unique_ptr<SandboxFileSystemTestHelper> fs3 = + NewFileSystem(custom_bucket_, kFileSystemTypeTemporary); + std::unique_ptr<SandboxFileSystemTestHelper> fs4 = + NewFileSystem(custom_bucket_, kFileSystemTypePersistent); + + // Make sure directories for default_bucket_ exist. + ASSERT_FALSE(ofu() + ->GetDirectoryForBucketAndType(default_bucket_, + kFileSystemTypeTemporary, + /*create=*/false) + .is_error()); + ASSERT_FALSE(ofu() + ->GetDirectoryForBucketAndType(default_bucket_, + kFileSystemTypePersistent, + /*create=*/false) + .is_error()); + + // Make sure directories for custom_bucket_ exist. + ASSERT_FALSE(ofu() + ->GetDirectoryForBucketAndType(custom_bucket_, + kFileSystemTypeTemporary, + /*create=*/false) + .is_error()); + ASSERT_FALSE(ofu() + ->GetDirectoryForBucketAndType(custom_bucket_, + kFileSystemTypePersistent, + /*create=*/false) + .is_error()); + + // Delete a directory for default_bucket_'s persistent filesystem. + ASSERT_TRUE(ofu()->DeleteDirectoryForBucketAndType( + default_bucket_, kFileSystemTypePersistent)); + + // The directory for default_bucket_'s temporary filesystem should not be + // removed. + ASSERT_FALSE(ofu() + ->GetDirectoryForBucketAndType(default_bucket_, + kFileSystemTypeTemporary, + /*create=*/false) + .is_error()); + + // The directory for default_bucket_'s persistent filesystem should be + // removed. + ASSERT_EQ(ofu() + ->GetDirectoryForBucketAndType(default_bucket_, + kFileSystemTypePersistent, + /*create=*/false) + .error(), + base::File::FILE_ERROR_NOT_FOUND); + + // The directories for custom_bucket_ should not be removed. + ASSERT_FALSE(ofu() + ->GetDirectoryForBucketAndType(custom_bucket_, + kFileSystemTypeTemporary, + /*create=*/false) + .is_error()); + ASSERT_FALSE(ofu() + ->GetDirectoryForBucketAndType(custom_bucket_, + kFileSystemTypePersistent, + /*create=*/false) + .is_error()); + + // Deleting directories which don't exist is not an error. + ASSERT_TRUE(ofu()->DeleteDirectoryForBucketAndType( + alternate_custom_bucket_, kFileSystemTypePersistent)); +} + +TEST_P(ObfuscatedFileUtilTest, DeleteDirectoryForStorageKeyAndType) { const blink::StorageKey storage_key1 = blink::StorageKey::CreateFromStringForTesting( "http://www.example.com:12"); @@ -2433,79 +2638,157 @@ TEST_P(ObfuscatedFileUtilTest, DeleteDirectoryForOriginAndType) { // Create origin directories. std::unique_ptr<SandboxFileSystemTestHelper> fs1 = - NewFileSystem(storage_key1.origin(), kFileSystemTypeTemporary); + NewFileSystem(storage_key1, kFileSystemTypeTemporary); std::unique_ptr<SandboxFileSystemTestHelper> fs2 = - NewFileSystem(storage_key1.origin(), kFileSystemTypePersistent); + NewFileSystem(storage_key1, kFileSystemTypePersistent); std::unique_ptr<SandboxFileSystemTestHelper> fs3 = - NewFileSystem(storage_key2.origin(), kFileSystemTypeTemporary); + NewFileSystem(storage_key2, kFileSystemTypeTemporary); std::unique_ptr<SandboxFileSystemTestHelper> fs4 = - NewFileSystem(storage_key2.origin(), kFileSystemTypePersistent); + NewFileSystem(storage_key2, kFileSystemTypePersistent); // Make sure directories for storage_key1 exist. - base::File::Error error = base::File::FILE_ERROR_FAILED; - ofu()->GetDirectoryForStorageKeyAndType( - storage_key1, GetTypeString(kFileSystemTypeTemporary), false, &error); - ASSERT_EQ(base::File::FILE_OK, error); - error = base::File::FILE_ERROR_FAILED; - ofu()->GetDirectoryForStorageKeyAndType( - storage_key1, GetTypeString(kFileSystemTypePersistent), false, &error); - ASSERT_EQ(base::File::FILE_OK, error); + ASSERT_FALSE(ofu() + ->GetDirectoryForStorageKeyAndType(storage_key1, + kFileSystemTypeTemporary, + /*create=*/false) + .is_error()); + ASSERT_FALSE(ofu() + ->GetDirectoryForStorageKeyAndType(storage_key1, + kFileSystemTypePersistent, + /*create=*/false) + .is_error()); // Make sure directories for storage_key2 exist. - error = base::File::FILE_ERROR_FAILED; - ofu()->GetDirectoryForStorageKeyAndType( - storage_key2, GetTypeString(kFileSystemTypeTemporary), false, &error); - ASSERT_EQ(base::File::FILE_OK, error); - error = base::File::FILE_ERROR_FAILED; - ofu()->GetDirectoryForStorageKeyAndType( - storage_key2, GetTypeString(kFileSystemTypePersistent), false, &error); - ASSERT_EQ(base::File::FILE_OK, error); + ASSERT_FALSE(ofu() + ->GetDirectoryForStorageKeyAndType(storage_key2, + kFileSystemTypeTemporary, + /*create=*/false) + .is_error()); + ASSERT_FALSE(ofu() + ->GetDirectoryForStorageKeyAndType(storage_key2, + kFileSystemTypePersistent, + /*create=*/false) + .is_error()); // Delete a directory for storage_key1's persistent filesystem. ASSERT_TRUE(ofu()->DeleteDirectoryForStorageKeyAndType( - storage_key1, GetTypeString(kFileSystemTypePersistent))); + storage_key1, kFileSystemTypePersistent)); // The directory for storage_key1's temporary filesystem should not be // removed. - error = base::File::FILE_ERROR_FAILED; - ofu()->GetDirectoryForStorageKeyAndType( - storage_key1, GetTypeString(kFileSystemTypeTemporary), false, &error); - ASSERT_EQ(base::File::FILE_OK, error); + ASSERT_FALSE(ofu() + ->GetDirectoryForStorageKeyAndType(storage_key1, + kFileSystemTypeTemporary, + /*create=*/false) + .is_error()); // The directory for storage_key1's persistent filesystem should be removed. - error = base::File::FILE_ERROR_FAILED; - ofu()->GetDirectoryForStorageKeyAndType( - storage_key1, GetTypeString(kFileSystemTypePersistent), false, &error); - ASSERT_EQ(base::File::FILE_ERROR_NOT_FOUND, error); + ASSERT_EQ(ofu() + ->GetDirectoryForStorageKeyAndType(storage_key1, + kFileSystemTypePersistent, + /*create=*/false) + .error(), + base::File::FILE_ERROR_NOT_FOUND); // The directories for storage_key2 should not be removed. - error = base::File::FILE_ERROR_FAILED; - ofu()->GetDirectoryForStorageKeyAndType( - storage_key2, GetTypeString(kFileSystemTypeTemporary), false, &error); - ASSERT_EQ(base::File::FILE_OK, error); - error = base::File::FILE_ERROR_FAILED; - ofu()->GetDirectoryForStorageKeyAndType( - storage_key2, GetTypeString(kFileSystemTypePersistent), false, &error); - ASSERT_EQ(base::File::FILE_OK, error); + ASSERT_FALSE(ofu() + ->GetDirectoryForStorageKeyAndType(storage_key2, + kFileSystemTypeTemporary, + /*create=*/false) + .is_error()); + ASSERT_FALSE(ofu() + ->GetDirectoryForStorageKeyAndType(storage_key2, + kFileSystemTypePersistent, + /*create=*/false) + .is_error()); // Make sure storage_key3's directories don't exist. - error = base::File::FILE_ERROR_FAILED; - ofu()->GetDirectoryForStorageKeyAndType( - storage_key3, GetTypeString(kFileSystemTypeTemporary), false, &error); - ASSERT_EQ(base::File::FILE_ERROR_NOT_FOUND, error); - error = base::File::FILE_ERROR_FAILED; - ofu()->GetDirectoryForStorageKeyAndType( - storage_key3, GetTypeString(kFileSystemTypePersistent), false, &error); - ASSERT_EQ(base::File::FILE_ERROR_NOT_FOUND, error); + ASSERT_EQ(ofu() + ->GetDirectoryForStorageKeyAndType(storage_key3, + kFileSystemTypeTemporary, + /*create=*/false) + .error(), + base::File::FILE_ERROR_NOT_FOUND); + ASSERT_EQ(ofu() + ->GetDirectoryForStorageKeyAndType(storage_key3, + kFileSystemTypePersistent, + /*create=*/false) + .error(), + base::File::FILE_ERROR_NOT_FOUND); // Deleting directories which don't exist is not an error. ASSERT_TRUE(ofu()->DeleteDirectoryForStorageKeyAndType( - storage_key3, GetTypeString(kFileSystemTypeTemporary))); + storage_key3, kFileSystemTypeTemporary)); ASSERT_TRUE(ofu()->DeleteDirectoryForStorageKeyAndType( - storage_key3, GetTypeString(kFileSystemTypePersistent))); + storage_key3, kFileSystemTypePersistent)); +} + +TEST_P(ObfuscatedFileUtilTest, DeleteDirectoryForBucketAndType_DeleteAll) { + // Create origin directories. + std::unique_ptr<SandboxFileSystemTestHelper> fs1 = + NewFileSystem(default_bucket_, kFileSystemTypeTemporary); + std::unique_ptr<SandboxFileSystemTestHelper> fs2 = + NewFileSystem(default_bucket_, kFileSystemTypePersistent); + std::unique_ptr<SandboxFileSystemTestHelper> fs3 = + NewFileSystem(custom_bucket_, kFileSystemTypeTemporary); + std::unique_ptr<SandboxFileSystemTestHelper> fs4 = + NewFileSystem(custom_bucket_, kFileSystemTypePersistent); + + // Make sure directories for default_bucket_ exist. + ASSERT_FALSE(ofu() + ->GetDirectoryForBucketAndType(default_bucket_, + kFileSystemTypeTemporary, + /*create=*/false) + .is_error()); + ASSERT_FALSE(ofu() + ->GetDirectoryForBucketAndType(default_bucket_, + kFileSystemTypePersistent, + /*create=*/false) + .is_error()); + + // Make sure directories for custom_bucket_ exist. + ASSERT_FALSE(ofu() + ->GetDirectoryForBucketAndType(custom_bucket_, + kFileSystemTypeTemporary, + /*create=*/false) + .is_error()); + ASSERT_FALSE(ofu() + ->GetDirectoryForBucketAndType(custom_bucket_, + kFileSystemTypePersistent, + /*create=*/false) + .is_error()); + + // Delete all directories for default_bucket_. + ofu()->DeleteDirectoryForBucketAndType(default_bucket_, absl::nullopt); + + // The directories for default_bucket_ should be removed. + ASSERT_EQ(ofu() + ->GetDirectoryForBucketAndType(default_bucket_, + kFileSystemTypeTemporary, + /*create=*/false) + .error(), + base::File::FILE_ERROR_NOT_FOUND); + ASSERT_EQ(ofu() + ->GetDirectoryForBucketAndType(default_bucket_, + kFileSystemTypePersistent, + /*create=*/false) + .error(), + base::File::FILE_ERROR_NOT_FOUND); + + // The directories for custom_bucket_ should not be removed. + ASSERT_FALSE(ofu() + ->GetDirectoryForBucketAndType(custom_bucket_, + kFileSystemTypeTemporary, + /*create=*/false) + .is_error()); + ASSERT_FALSE(ofu() + ->GetDirectoryForBucketAndType(custom_bucket_, + kFileSystemTypePersistent, + /*create=*/false) + .is_error()); } -TEST_P(ObfuscatedFileUtilTest, DeleteDirectoryForOriginAndType_DeleteAll) { +TEST_P(ObfuscatedFileUtilTest, DeleteDirectoryForStorageKeyAndType_DeleteAll) { const blink::StorageKey storage_key1 = blink::StorageKey::CreateFromStringForTesting( "http://www.example.com:12"); @@ -2515,56 +2798,66 @@ TEST_P(ObfuscatedFileUtilTest, DeleteDirectoryForOriginAndType_DeleteAll) { // Create origin directories. std::unique_ptr<SandboxFileSystemTestHelper> fs1 = - NewFileSystem(storage_key1.origin(), kFileSystemTypeTemporary); + NewFileSystem(storage_key1, kFileSystemTypeTemporary); std::unique_ptr<SandboxFileSystemTestHelper> fs2 = - NewFileSystem(storage_key1.origin(), kFileSystemTypePersistent); + NewFileSystem(storage_key1, kFileSystemTypePersistent); std::unique_ptr<SandboxFileSystemTestHelper> fs3 = - NewFileSystem(storage_key2.origin(), kFileSystemTypeTemporary); + NewFileSystem(storage_key2, kFileSystemTypeTemporary); std::unique_ptr<SandboxFileSystemTestHelper> fs4 = - NewFileSystem(storage_key2.origin(), kFileSystemTypePersistent); + NewFileSystem(storage_key2, kFileSystemTypePersistent); // Make sure directories for storage_key1 exist. - base::File::Error error = base::File::FILE_ERROR_FAILED; - ofu()->GetDirectoryForStorageKeyAndType( - storage_key1, GetTypeString(kFileSystemTypeTemporary), false, &error); - ASSERT_EQ(base::File::FILE_OK, error); - error = base::File::FILE_ERROR_FAILED; - ofu()->GetDirectoryForStorageKeyAndType( - storage_key1, GetTypeString(kFileSystemTypePersistent), false, &error); - ASSERT_EQ(base::File::FILE_OK, error); + ASSERT_FALSE(ofu() + ->GetDirectoryForStorageKeyAndType(storage_key1, + kFileSystemTypeTemporary, + /*create=*/false) + .is_error()); + ASSERT_FALSE(ofu() + ->GetDirectoryForStorageKeyAndType(storage_key1, + kFileSystemTypePersistent, + /*create=*/false) + .is_error()); // Make sure directories for storage_key2 exist. - error = base::File::FILE_ERROR_FAILED; - ofu()->GetDirectoryForStorageKeyAndType( - storage_key2, GetTypeString(kFileSystemTypeTemporary), false, &error); - ASSERT_EQ(base::File::FILE_OK, error); - error = base::File::FILE_ERROR_FAILED; - ofu()->GetDirectoryForStorageKeyAndType( - storage_key2, GetTypeString(kFileSystemTypePersistent), false, &error); - ASSERT_EQ(base::File::FILE_OK, error); + ASSERT_FALSE(ofu() + ->GetDirectoryForStorageKeyAndType(storage_key2, + kFileSystemTypeTemporary, + /*create=*/false) + .is_error()); + ASSERT_FALSE(ofu() + ->GetDirectoryForStorageKeyAndType(storage_key2, + kFileSystemTypePersistent, + /*create=*/false) + .is_error()); // Delete all directories for storage_key1. - ofu()->DeleteDirectoryForStorageKeyAndType(storage_key1, std::string()); + ofu()->DeleteDirectoryForStorageKeyAndType(storage_key1, absl::nullopt); // The directories for storage_key1 should be removed. - error = base::File::FILE_ERROR_FAILED; - ofu()->GetDirectoryForStorageKeyAndType( - storage_key1, GetTypeString(kFileSystemTypeTemporary), false, &error); - ASSERT_EQ(base::File::FILE_ERROR_NOT_FOUND, error); - error = base::File::FILE_ERROR_FAILED; - ofu()->GetDirectoryForStorageKeyAndType( - storage_key1, GetTypeString(kFileSystemTypePersistent), false, &error); - ASSERT_EQ(base::File::FILE_ERROR_NOT_FOUND, error); + ASSERT_EQ(ofu() + ->GetDirectoryForStorageKeyAndType(storage_key1, + kFileSystemTypeTemporary, + /*create=*/false) + .error(), + base::File::FILE_ERROR_NOT_FOUND); + ASSERT_EQ(ofu() + ->GetDirectoryForStorageKeyAndType(storage_key1, + kFileSystemTypePersistent, + /*create=*/false) + .error(), + base::File::FILE_ERROR_NOT_FOUND); // The directories for storage_key2 should not be removed. - error = base::File::FILE_ERROR_FAILED; - ofu()->GetDirectoryForStorageKeyAndType( - storage_key2, GetTypeString(kFileSystemTypeTemporary), false, &error); - ASSERT_EQ(base::File::FILE_OK, error); - error = base::File::FILE_ERROR_FAILED; - ofu()->GetDirectoryForStorageKeyAndType( - storage_key2, GetTypeString(kFileSystemTypePersistent), false, &error); - ASSERT_EQ(base::File::FILE_OK, error); + ASSERT_FALSE(ofu() + ->GetDirectoryForStorageKeyAndType(storage_key2, + kFileSystemTypeTemporary, + /*create=*/false) + .is_error()); + ASSERT_FALSE(ofu() + ->GetDirectoryForStorageKeyAndType(storage_key2, + kFileSystemTypePersistent, + /*create=*/false) + .is_error()); } } // namespace storage diff --git a/chromium/storage/browser/file_system/plugin_private_file_system_backend.cc b/chromium/storage/browser/file_system/plugin_private_file_system_backend.cc deleted file mode 100644 index faf7a36fb92..00000000000 --- a/chromium/storage/browser/file_system/plugin_private_file_system_backend.cc +++ /dev/null @@ -1,466 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "storage/browser/file_system/plugin_private_file_system_backend.h" - -#include <stdint.h> - -#include <map> -#include <memory> -#include <utility> -#include <vector> - -#include "base/bind.h" -#include "base/containers/contains.h" -#include "base/files/file_enumerator.h" -#include "base/files/file_path.h" -#include "base/memory/scoped_refptr.h" -#include "base/synchronization/lock.h" -#include "base/task/task_runner_util.h" -#include "base/threading/thread_task_runner_handle.h" -#include "base/time/time.h" -#include "storage/browser/file_system/async_file_util_adapter.h" -#include "storage/browser/file_system/file_system_context.h" -#include "storage/browser/file_system/file_system_operation.h" -#include "storage/browser/file_system/file_system_operation_context.h" -#include "storage/browser/file_system/isolated_context.h" -#include "storage/browser/file_system/obfuscated_file_util.h" -#include "storage/browser/file_system/obfuscated_file_util_memory_delegate.h" -#include "storage/browser/file_system/quota/quota_reservation.h" -#include "storage/browser/file_system/sandbox_file_stream_reader.h" -#include "storage/browser/file_system/sandbox_file_stream_writer.h" -#include "storage/browser/quota/special_storage_policy.h" -#include "storage/common/file_system/file_system_util.h" -#include "third_party/blink/public/common/storage_key/storage_key.h" -#include "url/origin.h" - -namespace storage { - -class PluginPrivateFileSystemBackend::FileSystemIDToPluginMap { - public: - explicit FileSystemIDToPluginMap( - scoped_refptr<base::SequencedTaskRunner> task_runner) - : task_runner_(std::move(task_runner)) {} - ~FileSystemIDToPluginMap() = default; - - std::string GetPluginIDForURL(const FileSystemURL& url) { - DCHECK(task_runner_->RunsTasksInCurrentSequence()); - auto found = map_.find(url.filesystem_id()); - if (url.type() != kFileSystemTypePluginPrivate || found == map_.end()) { - NOTREACHED() << "Unsupported url is given: " << url.DebugString(); - return std::string(); - } - return found->second; - } - - void RegisterFileSystem(const std::string& filesystem_id, - const std::string& plugin_id) { - DCHECK(task_runner_->RunsTasksInCurrentSequence()); - DCHECK(!filesystem_id.empty()); - DCHECK(!base::Contains(map_, filesystem_id)) << filesystem_id; - map_[filesystem_id] = plugin_id; - } - - void RemoveFileSystem(const std::string& filesystem_id) { - DCHECK(task_runner_->RunsTasksInCurrentSequence()); - map_.erase(filesystem_id); - } - - private: - using Map = std::map<std::string, std::string>; - const scoped_refptr<base::SequencedTaskRunner> task_runner_; - Map map_; -}; - -namespace { - -const base::FilePath::CharType* kFileSystemDirectory = - SandboxFileSystemBackendDelegate::kFileSystemDirectory; -const base::FilePath::CharType* kPluginPrivateDirectory = - FILE_PATH_LITERAL("Plugins"); - -base::File::Error OpenFileSystemOnFileTaskRunner( - ObfuscatedFileUtil* file_util, - PluginPrivateFileSystemBackend::FileSystemIDToPluginMap* plugin_map, - const url::Origin& origin, - const std::string& filesystem_id, - const std::string& plugin_id, - OpenFileSystemMode mode) { - base::File::Error error = base::File::FILE_ERROR_FAILED; - const bool create = (mode == OPEN_FILE_SYSTEM_CREATE_IF_NONEXISTENT); - // TODO(https://crbug.com/1231162): determine whether EME/CDM/plugin private - // file system will be partitioned; if so, replace the in-line conversion with - // the correct third-party StorageKey. - file_util->GetDirectoryForStorageKeyAndType(blink::StorageKey(origin), - plugin_id, create, &error); - if (error == base::File::FILE_OK) - plugin_map->RegisterFileSystem(filesystem_id, plugin_id); - return error; -} - -} // namespace - -PluginPrivateFileSystemBackend::CdmFileInfo::CdmFileInfo( - const std::string& name, - const std::string& legacy_file_system_id) - : name(name), legacy_file_system_id(legacy_file_system_id) {} -PluginPrivateFileSystemBackend::CdmFileInfo::CdmFileInfo(const CdmFileInfo&) = - default; -PluginPrivateFileSystemBackend::CdmFileInfo::CdmFileInfo(CdmFileInfo&&) = - default; -PluginPrivateFileSystemBackend::CdmFileInfo::~CdmFileInfo() = default; - -PluginPrivateFileSystemBackend::PluginPrivateFileSystemBackend( - scoped_refptr<base::SequencedTaskRunner> file_task_runner, - const base::FilePath& profile_path, - scoped_refptr<SpecialStoragePolicy> special_storage_policy, - const FileSystemOptions& file_system_options, - leveldb::Env* env_override) - : file_task_runner_(std::move(file_task_runner)), - file_system_options_(file_system_options), - base_path_(profile_path.Append(kFileSystemDirectory) - .Append(kPluginPrivateDirectory)), - plugin_map_(new FileSystemIDToPluginMap(file_task_runner_)) { - file_util_ = std::make_unique<AsyncFileUtilAdapter>( - std::make_unique<ObfuscatedFileUtil>( - std::move(special_storage_policy), base_path_, env_override, - base::BindRepeating(&FileSystemIDToPluginMap::GetPluginIDForURL, - base::Owned(plugin_map_.get())), - std::set<std::string>(), nullptr, - file_system_options.is_incognito())); -} - -PluginPrivateFileSystemBackend::~PluginPrivateFileSystemBackend() { - if (!file_task_runner_->RunsTasksInCurrentSequence()) { - AsyncFileUtil* file_util = file_util_.release(); - if (!file_task_runner_->DeleteSoon(FROM_HERE, file_util)) - delete file_util; - } -} - -void PluginPrivateFileSystemBackend::OpenPrivateFileSystem( - const url::Origin& origin, - FileSystemType type, - const std::string& filesystem_id, - const std::string& plugin_id, - OpenFileSystemMode mode, - StatusCallback callback) { - if (!CanHandleType(type)) { - base::ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, - base::BindOnce(std::move(callback), base::File::FILE_ERROR_SECURITY)); - return; - } - - PostTaskAndReplyWithResult( - file_task_runner_.get(), FROM_HERE, - base::BindOnce(&OpenFileSystemOnFileTaskRunner, obfuscated_file_util(), - plugin_map_, origin, filesystem_id, plugin_id, mode), - std::move(callback)); -} - -bool PluginPrivateFileSystemBackend::CanHandleType(FileSystemType type) const { - return type == kFileSystemTypePluginPrivate; -} - -void PluginPrivateFileSystemBackend::Initialize(FileSystemContext* context) {} - -void PluginPrivateFileSystemBackend::ResolveURL(const FileSystemURL& url, - OpenFileSystemMode mode, - ResolveURLCallback callback) { - // We never allow opening a new plugin-private filesystem via usual - // ResolveURL. - base::ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, base::BindOnce(std::move(callback), GURL(), std::string(), - base::File::FILE_ERROR_SECURITY)); -} - -AsyncFileUtil* PluginPrivateFileSystemBackend::GetAsyncFileUtil( - FileSystemType type) { - return file_util_.get(); -} - -WatcherManager* PluginPrivateFileSystemBackend::GetWatcherManager( - FileSystemType type) { - return nullptr; -} - -CopyOrMoveFileValidatorFactory* -PluginPrivateFileSystemBackend::GetCopyOrMoveFileValidatorFactory( - FileSystemType type, - base::File::Error* error_code) { - DCHECK(error_code); - *error_code = base::File::FILE_OK; - return nullptr; -} - -std::unique_ptr<FileSystemOperation> -PluginPrivateFileSystemBackend::CreateFileSystemOperation( - const FileSystemURL& url, - FileSystemContext* context, - base::File::Error* error_code) const { - auto operation_context = - std::make_unique<FileSystemOperationContext>(context); - return FileSystemOperation::Create(url, context, - std::move(operation_context)); -} - -bool PluginPrivateFileSystemBackend::SupportsStreaming( - const FileSystemURL& url) const { - // Streaming is required for incognito file systems in order to access - // memory-backed files. - DCHECK(CanHandleType(url.type())); - return file_system_options_.is_incognito(); -} - -bool PluginPrivateFileSystemBackend::HasInplaceCopyImplementation( - FileSystemType type) const { - return false; -} - -std::unique_ptr<FileStreamReader> -PluginPrivateFileSystemBackend::CreateFileStreamReader( - const FileSystemURL& url, - int64_t offset, - int64_t max_bytes_to_read, - const base::Time& expected_modification_time, - FileSystemContext* context) const { - DCHECK(CanHandleType(url.type())); - return std::make_unique<SandboxFileStreamReader>(context, url, offset, - expected_modification_time); -} - -std::unique_ptr<FileStreamWriter> -PluginPrivateFileSystemBackend::CreateFileStreamWriter( - const FileSystemURL& url, - int64_t offset, - FileSystemContext* context) const { - DCHECK(CanHandleType(url.type())); - - // Observers not supported by PluginPrivateFileSystemBackend. - return std::make_unique<SandboxFileStreamWriter>(context, url, offset, - UpdateObserverList()); -} - -FileSystemQuotaUtil* PluginPrivateFileSystemBackend::GetQuotaUtil() { - return this; -} - -base::File::Error -PluginPrivateFileSystemBackend::DeleteStorageKeyDataOnFileTaskRunner( - FileSystemContext* context, - QuotaManagerProxy* proxy, - const blink::StorageKey& storage_key, - FileSystemType type) { - if (!CanHandleType(type)) - return base::File::FILE_ERROR_SECURITY; - bool result = obfuscated_file_util()->DeleteDirectoryForStorageKeyAndType( - storage_key, std::string()); - if (result) - return base::File::FILE_OK; - return base::File::FILE_ERROR_FAILED; -} - -void PluginPrivateFileSystemBackend::PerformStorageCleanupOnFileTaskRunner( - FileSystemContext* context, - QuotaManagerProxy* proxy, - FileSystemType type) { - if (!CanHandleType(type)) - return; - obfuscated_file_util()->RewriteDatabases(); -} - -std::vector<blink::StorageKey> -PluginPrivateFileSystemBackend::GetStorageKeysForTypeOnFileTaskRunner( - FileSystemType type) { - if (!CanHandleType(type)) - return std::vector<blink::StorageKey>(); - std::unique_ptr<ObfuscatedFileUtil::AbstractStorageKeyEnumerator> enumerator( - obfuscated_file_util()->CreateStorageKeyEnumerator()); - std::vector<blink::StorageKey> storage_keys; - absl::optional<blink::StorageKey> storage_key; - while ((storage_key = enumerator->Next()).has_value()) - storage_keys.push_back(std::move(storage_key).value()); - return storage_keys; -} - -int64_t PluginPrivateFileSystemBackend::GetStorageKeyUsageOnFileTaskRunner( - FileSystemContext* context, - const blink::StorageKey& storage_key, - FileSystemType type) { - DCHECK(file_task_runner_->RunsTasksInCurrentSequence()); - - if (!CanHandleType(type)) - return 0; - - int64_t total_size; - base::Time last_modified_time; - GetOriginDetailsOnFileTaskRunner(context, storage_key.origin(), &total_size, - &last_modified_time); - return total_size; -} - -void PluginPrivateFileSystemBackend::GetOriginDetailsOnFileTaskRunner( - FileSystemContext* context, - const url::Origin& origin, - int64_t* total_size, - base::Time* last_modified_time) { - DCHECK(file_task_runner_->RunsTasksInCurrentSequence()); - - *total_size = 0; - *last_modified_time = base::Time::UnixEpoch(); - std::string fsid = - IsolatedContext::GetInstance()->RegisterFileSystemForVirtualPath( - kFileSystemTypePluginPrivate, kPluginPrivateRootName, - base::FilePath()); - DCHECK(ValidateIsolatedFileSystemId(fsid)); - - std::string root = GetIsolatedFileSystemRootURIString(origin.GetURL(), fsid, - kPluginPrivateRootName); - - std::unique_ptr<FileSystemOperationContext> operation_context( - std::make_unique<FileSystemOperationContext>(context)); - - // Determine the available plugin private filesystem directories for this - // origin. Currently the plugin private filesystem is only used by Encrypted - // Media Content Decryption Modules. Each CDM gets a directory based on the - // mimetype (e.g. plugin application/x-ppapi-widevine-cdm uses directory - // application_x-ppapi-widevine-cdm). Enumerate through the set of - // directories so that data from any CDM used by this origin is counted. - base::File::Error error; - // TODO(https://crbug.com/1231162): determine whether EME/CDM/plugin private - // file system will be partitioned; if so, replace the in-line conversion with - // the correct third-party StorageKey. - base::FilePath path = - obfuscated_file_util()->GetDirectoryForStorageKeyAndType( - blink::StorageKey(origin), "", false, &error); - if (error != base::File::FILE_OK) { - DLOG(ERROR) << "Unable to read directory for " << origin; - return; - } - - base::FileEnumerator directory_enumerator(path, false, - base::FileEnumerator::DIRECTORIES); - base::FilePath plugin_path; - while (!(plugin_path = directory_enumerator.Next()).empty()) { - std::string plugin_name = plugin_path.BaseName().MaybeAsASCII(); - if (OpenFileSystemOnFileTaskRunner( - obfuscated_file_util(), plugin_map_, origin, fsid, plugin_name, - OPEN_FILE_SYSTEM_FAIL_IF_NONEXISTENT) != base::File::FILE_OK) { - continue; - } - - // TODO(https://crbug.com/1231162): determine whether EME/CDM/plugin private - // file system will be partitioned and use the appropriate StorageKey - std::unique_ptr<FileSystemFileUtil::AbstractFileEnumerator> enumerator( - obfuscated_file_util()->CreateFileEnumerator( - operation_context.get(), - context->CrackURL( - GURL(root), blink::StorageKey(url::Origin::Create(GURL(root)))), - true)); - - while (!enumerator->Next().empty()) { - *total_size += enumerator->Size(); - if (enumerator->LastModifiedTime() > *last_modified_time) - *last_modified_time = enumerator->LastModifiedTime(); - } - } -} - -std::vector<PluginPrivateFileSystemBackend::CdmFileInfo> -PluginPrivateFileSystemBackend::GetMediaLicenseFilesForOriginOnFileTaskRunner( - FileSystemContext* context, - const url::Origin& origin) { - DCHECK(file_task_runner_->RunsTasksInCurrentSequence()); - - std::unique_ptr<FileSystemOperationContext> operation_context( - std::make_unique<FileSystemOperationContext>(context)); - - // Determine the available plugin private filesystem directories for this - // origin. Currently the plugin private filesystem is only used by Encrypted - // Media Content Decryption Modules. Each CDM gets a directory based on the - // mimetype (e.g. plugin application/x-ppapi-widevine-cdm uses directory - // application_x-ppapi-widevine-cdm). Enumerate through the set of - // directories so that data from any CDM used by this origin is counted. - base::File::Error error; - base::FilePath path = - obfuscated_file_util()->GetDirectoryForStorageKeyAndType( - blink::StorageKey(origin), "", false, &error); - if (error != base::File::FILE_OK) - return {}; - - std::vector<CdmFileInfo> cdm_files; - base::FileEnumerator directory_enumerator(path, false, - base::FileEnumerator::DIRECTORIES); - base::FilePath plugin_path; - while (!(plugin_path = directory_enumerator.Next()).empty()) { - std::string plugin_name = plugin_path.BaseName().MaybeAsASCII(); - - std::string fsid = - IsolatedContext::GetInstance()->RegisterFileSystemForVirtualPath( - kFileSystemTypePluginPrivate, kPluginPrivateRootName, - base::FilePath()); - DCHECK(ValidateIsolatedFileSystemId(fsid)); - std::string root = GetIsolatedFileSystemRootURIString( - origin.GetURL(), fsid, kPluginPrivateRootName); - - if (OpenFileSystemOnFileTaskRunner( - obfuscated_file_util(), plugin_map_, origin, fsid, plugin_name, - OPEN_FILE_SYSTEM_FAIL_IF_NONEXISTENT) != base::File::FILE_OK) { - continue; - } - std::unique_ptr<FileSystemFileUtil::AbstractFileEnumerator> enumerator( - obfuscated_file_util()->CreateFileEnumerator( - operation_context.get(), - context->CrackURL( - GURL(root), blink::StorageKey(url::Origin::Create(GURL(root)))), - true)); - - base::FilePath cdm_file_path; - while (!(cdm_file_path = enumerator->Next()).empty()) { - cdm_files.emplace_back(cdm_file_path.BaseName().AsUTF8Unsafe(), - plugin_path.BaseName().AsUTF8Unsafe()); - } - } - - return cdm_files; -} - -scoped_refptr<QuotaReservation> -PluginPrivateFileSystemBackend::CreateQuotaReservationOnFileTaskRunner( - const blink::StorageKey& storage_key, - FileSystemType type) { - // We don't track usage on this filesystem. - NOTREACHED(); - return scoped_refptr<QuotaReservation>(); -} - -const UpdateObserverList* PluginPrivateFileSystemBackend::GetUpdateObservers( - FileSystemType type) const { - return nullptr; -} - -const ChangeObserverList* PluginPrivateFileSystemBackend::GetChangeObservers( - FileSystemType type) const { - return nullptr; -} - -const AccessObserverList* PluginPrivateFileSystemBackend::GetAccessObservers( - FileSystemType type) const { - return nullptr; -} - -ObfuscatedFileUtil* PluginPrivateFileSystemBackend::obfuscated_file_util() { - return static_cast<ObfuscatedFileUtil*>( - static_cast<AsyncFileUtilAdapter*>(file_util_.get())->sync_file_util()); -} - -ObfuscatedFileUtilMemoryDelegate* -PluginPrivateFileSystemBackend::obfuscated_file_util_memory_delegate() { - auto* file_util = obfuscated_file_util(); - DCHECK(file_util->is_incognito()); - return static_cast<ObfuscatedFileUtilMemoryDelegate*>(file_util->delegate()); -} - -} // namespace storage diff --git a/chromium/storage/browser/file_system/plugin_private_file_system_backend.h b/chromium/storage/browser/file_system/plugin_private_file_system_backend.h deleted file mode 100644 index 29c7ecc1f8a..00000000000 --- a/chromium/storage/browser/file_system/plugin_private_file_system_backend.h +++ /dev/null @@ -1,184 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef STORAGE_BROWSER_FILE_SYSTEM_PLUGIN_PRIVATE_FILE_SYSTEM_BACKEND_H_ -#define STORAGE_BROWSER_FILE_SYSTEM_PLUGIN_PRIVATE_FILE_SYSTEM_BACKEND_H_ - -#include <stdint.h> - -#include <memory> -#include <string> -#include <vector> - -#include "base/component_export.h" -#include "base/memory/raw_ptr.h" -#include "base/memory/ref_counted.h" -#include "base/memory/weak_ptr.h" -#include "storage/browser/file_system/file_system_backend.h" -#include "storage/browser/file_system/file_system_options.h" -#include "storage/browser/file_system/file_system_quota_util.h" -#include "storage/browser/file_system/task_runner_bound_observer_list.h" - -namespace base { -class SequencedTaskRunner; -} // namespace base - -namespace blink { -class StorageKey; -} // namespace blink - -namespace leveldb { -class Env; -} // namespace leveldb - -namespace url { -class Origin; -} // namespace url - -namespace storage { - -class ObfuscatedFileUtil; -class ObfuscatedFileUtilMemoryDelegate; -class SpecialStoragePolicy; -class WatcherManager; - -// TODO(crbug.com/1231162): Remove this when removing the plugin private FS. -// Name of the root directory in the plugin private file system. -const char kPluginPrivateRootName[] = "pluginprivate"; - -class COMPONENT_EXPORT(STORAGE_BROWSER) PluginPrivateFileSystemBackend - : public FileSystemBackend, - public FileSystemQuotaUtil { - public: - class FileSystemIDToPluginMap; - using StatusCallback = base::OnceCallback<void(base::File::Error result)>; - - // Used to migrate media license data to the new backend. - struct COMPONENT_EXPORT(STORAGE_BROWSER) CdmFileInfo { - CdmFileInfo(const std::string& name, - const std::string& legacy_file_system_id); - CdmFileInfo(const CdmFileInfo&); - CdmFileInfo(CdmFileInfo&&); - ~CdmFileInfo(); - - const std::string name; - const std::string legacy_file_system_id; - }; - - PluginPrivateFileSystemBackend( - scoped_refptr<base::SequencedTaskRunner> file_task_runner, - const base::FilePath& profile_path, - scoped_refptr<SpecialStoragePolicy> special_storage_policy, - const FileSystemOptions& file_system_options, - leveldb::Env* env_override); - - PluginPrivateFileSystemBackend(const PluginPrivateFileSystemBackend&) = - delete; - PluginPrivateFileSystemBackend& operator=( - const PluginPrivateFileSystemBackend&) = delete; - - ~PluginPrivateFileSystemBackend() override; - - // This must be used to open 'private' filesystem instead of regular - // OpenFileSystem. - // |plugin_id| must be an identifier string for per-plugin - // isolation, e.g. name, MIME type etc. - // NOTE: |plugin_id| must be sanitized ASCII string that doesn't - // include *any* dangerous character like '/'. - void OpenPrivateFileSystem(const url::Origin& origin, - FileSystemType type, - const std::string& filesystem_id, - const std::string& plugin_id, - OpenFileSystemMode mode, - StatusCallback callback); - - // FileSystemBackend overrides. - bool CanHandleType(FileSystemType type) const override; - void Initialize(FileSystemContext* context) override; - void ResolveURL(const FileSystemURL& url, - OpenFileSystemMode mode, - ResolveURLCallback callback) override; - AsyncFileUtil* GetAsyncFileUtil(FileSystemType type) override; - WatcherManager* GetWatcherManager(FileSystemType type) override; - CopyOrMoveFileValidatorFactory* GetCopyOrMoveFileValidatorFactory( - FileSystemType type, - base::File::Error* error_code) override; - std::unique_ptr<FileSystemOperation> CreateFileSystemOperation( - const FileSystemURL& url, - FileSystemContext* context, - base::File::Error* error_code) const override; - bool SupportsStreaming(const FileSystemURL& url) const override; - bool HasInplaceCopyImplementation(FileSystemType type) const override; - std::unique_ptr<FileStreamReader> CreateFileStreamReader( - const FileSystemURL& url, - int64_t offset, - int64_t max_bytes_to_read, - const base::Time& expected_modification_time, - FileSystemContext* context) const override; - std::unique_ptr<FileStreamWriter> CreateFileStreamWriter( - const FileSystemURL& url, - int64_t offset, - FileSystemContext* context) const override; - FileSystemQuotaUtil* GetQuotaUtil() override; - const UpdateObserverList* GetUpdateObservers( - FileSystemType type) const override; - const ChangeObserverList* GetChangeObservers( - FileSystemType type) const override; - const AccessObserverList* GetAccessObservers( - FileSystemType type) const override; - - // FileSystemQuotaUtil overrides. - base::File::Error DeleteStorageKeyDataOnFileTaskRunner( - FileSystemContext* context, - QuotaManagerProxy* proxy, - const blink::StorageKey& storage_key, - FileSystemType type) override; - void PerformStorageCleanupOnFileTaskRunner(FileSystemContext* context, - QuotaManagerProxy* proxy, - FileSystemType type) override; - std::vector<blink::StorageKey> GetStorageKeysForTypeOnFileTaskRunner( - FileSystemType type) override; - int64_t GetStorageKeyUsageOnFileTaskRunner( - FileSystemContext* context, - const blink::StorageKey& storage_key, - FileSystemType type) override; - scoped_refptr<QuotaReservation> CreateQuotaReservationOnFileTaskRunner( - const blink::StorageKey& storage_key, - FileSystemType type) override; - - // Get details on the files saved for the specified |origin_url|. Returns - // the total size and last modified time for the set of all files stored - // for the particular origin. |total_size| = 0 and |last_modified_time| = - // base::Time::UnixEpoch() if no files found. - void GetOriginDetailsOnFileTaskRunner(FileSystemContext* context, - const url::Origin& origin, - int64_t* total_size, - base::Time* last_modified_time); - - // Used to migrate media license data to the new backend. - // TODO(crbug.com/1231162): Once all media license data has been migrated, the - // PPFS will have no more consumers and we can remove it entirely. - std::vector<CdmFileInfo> GetMediaLicenseFilesForOriginOnFileTaskRunner( - FileSystemContext* context, - const url::Origin& origin); - - ObfuscatedFileUtilMemoryDelegate* obfuscated_file_util_memory_delegate(); - const base::FilePath& base_path() const { return base_path_; } - - private: - friend class PluginPrivateFileSystemBackendTest; - - ObfuscatedFileUtil* obfuscated_file_util(); - - const scoped_refptr<base::SequencedTaskRunner> file_task_runner_; - const FileSystemOptions file_system_options_; - const base::FilePath base_path_; - std::unique_ptr<AsyncFileUtil> file_util_; - raw_ptr<FileSystemIDToPluginMap> plugin_map_; // Owned by file_util_. - base::WeakPtrFactory<PluginPrivateFileSystemBackend> weak_factory_{this}; -}; - -} // namespace storage - -#endif // STORAGE_BROWSER_FILE_SYSTEM_PLUGIN_PRIVATE_FILE_SYSTEM_BACKEND_H_ diff --git a/chromium/storage/browser/file_system/plugin_private_file_system_backend_unittest.cc b/chromium/storage/browser/file_system/plugin_private_file_system_backend_unittest.cc deleted file mode 100644 index f162888f09a..00000000000 --- a/chromium/storage/browser/file_system/plugin_private_file_system_backend_unittest.cc +++ /dev/null @@ -1,268 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include <memory> - -#include "base/bind.h" -#include "base/files/file_util.h" -#include "base/files/scoped_temp_dir.h" -#include "base/run_loop.h" -#include "base/test/task_environment.h" -#include "storage/browser/file_system/file_system_context.h" -#include "storage/browser/file_system/isolated_context.h" -#include "storage/browser/file_system/obfuscated_file_util.h" -#include "storage/browser/file_system/plugin_private_file_system_backend.h" -#include "storage/browser/quota/quota_manager_proxy.h" -#include "storage/browser/test/async_file_test_helper.h" -#include "storage/browser/test/test_file_system_context.h" -#include "storage/browser/test/test_file_system_options.h" -#include "storage/common/file_system/file_system_util.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "third_party/blink/public/common/storage_key/storage_key.h" -#include "url/gurl.h" -#include "url/origin.h" - -using url::Origin; - -namespace storage { - -namespace { - -const FileSystemType kType = kFileSystemTypePluginPrivate; - -void DidOpenFileSystem(base::File::Error* error_out, base::File::Error error) { - *error_out = error; -} - -} // namespace - -class PluginPrivateFileSystemBackendTest : public testing::Test { - protected: - void SetUp() override { - ASSERT_TRUE(data_dir_.CreateUniqueTempDir()); - context_ = CreateFileSystemContextForTesting( - /*quota_manager_proxy=*/nullptr, data_dir_.GetPath()); - } - - // TODO(https://crbug.com/1231162): determine whether EME/CDM/plugin private - // file system will be partitioned and use the appropriate StorageKey - FileSystemURL CreateURL(const GURL& root_url, const std::string& relative) { - FileSystemURL root = context_->CrackURL( - root_url, blink::StorageKey(url::Origin::Create(root_url))); - return context_->CreateCrackedFileSystemURL( - root.storage_key(), root.mount_type(), - root.virtual_path().AppendASCII(relative)); - } - - PluginPrivateFileSystemBackend* backend() const { - return context_->plugin_private_backend(); - } - - std::string RegisterFileSystem() { - return IsolatedContext::GetInstance()->RegisterFileSystemForVirtualPath( - kType, kRootName, base::FilePath()); - } - - const base::FilePath& base_path() const { return backend()->base_path(); } - - const std::string kPlugin1 = "plugin1"; - const std::string kPlugin2 = "plugin2"; - const std::string kRootName = "pluginprivate"; - - base::ScopedTempDir data_dir_; - base::test::SingleThreadTaskEnvironment task_environment_; - scoped_refptr<FileSystemContext> context_; -}; - -// TODO(kinuko,nhiroki): There are a lot of duplicate code in these tests. Write -// helper functions to simplify the tests. - -TEST_F(PluginPrivateFileSystemBackendTest, OpenFileSystemBasic) { - const Origin kOrigin = Origin::Create(GURL("http://www.example.com")); - - const std::string filesystem_id1 = RegisterFileSystem(); - base::File::Error error = base::File::FILE_ERROR_FAILED; - backend()->OpenPrivateFileSystem(kOrigin, kType, filesystem_id1, kPlugin1, - OPEN_FILE_SYSTEM_CREATE_IF_NONEXISTENT, - base::BindOnce(&DidOpenFileSystem, &error)); - base::RunLoop().RunUntilIdle(); - ASSERT_EQ(base::File::FILE_OK, error); - - // Run this again with FAIL_IF_NONEXISTENT to see if it succeeds. - const std::string filesystem_id2 = RegisterFileSystem(); - error = base::File::FILE_ERROR_FAILED; - backend()->OpenPrivateFileSystem(kOrigin, kType, filesystem_id2, kPlugin1, - OPEN_FILE_SYSTEM_FAIL_IF_NONEXISTENT, - base::BindOnce(&DidOpenFileSystem, &error)); - base::RunLoop().RunUntilIdle(); - ASSERT_EQ(base::File::FILE_OK, error); - - const GURL root_url(GetIsolatedFileSystemRootURIString( - kOrigin.GetURL(), filesystem_id1, kRootName)); - FileSystemURL file = CreateURL(root_url, "foo"); - base::FilePath platform_path; - EXPECT_EQ(base::File::FILE_OK, - AsyncFileTestHelper::CreateFile(context_.get(), file)); - EXPECT_EQ(base::File::FILE_OK, AsyncFileTestHelper::GetPlatformPath( - context_.get(), file, &platform_path)); - EXPECT_TRUE(base_path().AppendASCII("000").AppendASCII(kPlugin1).IsParent( - platform_path)); -} - -TEST_F(PluginPrivateFileSystemBackendTest, PluginIsolation) { - const Origin kOrigin = Origin::Create(GURL("http://www.example.com")); - - // Open filesystem for kPlugin1 and kPlugin2. - const std::string filesystem_id1 = RegisterFileSystem(); - base::File::Error error = base::File::FILE_ERROR_FAILED; - backend()->OpenPrivateFileSystem(kOrigin, kType, filesystem_id1, kPlugin1, - OPEN_FILE_SYSTEM_CREATE_IF_NONEXISTENT, - base::BindOnce(&DidOpenFileSystem, &error)); - base::RunLoop().RunUntilIdle(); - ASSERT_EQ(base::File::FILE_OK, error); - - const std::string filesystem_id2 = RegisterFileSystem(); - error = base::File::FILE_ERROR_FAILED; - backend()->OpenPrivateFileSystem(kOrigin, kType, filesystem_id2, kPlugin2, - OPEN_FILE_SYSTEM_CREATE_IF_NONEXISTENT, - base::BindOnce(&DidOpenFileSystem, &error)); - base::RunLoop().RunUntilIdle(); - ASSERT_EQ(base::File::FILE_OK, error); - - // Create 'foo' in kPlugin1. - const GURL root_url1(GetIsolatedFileSystemRootURIString( - kOrigin.GetURL(), filesystem_id1, kRootName)); - FileSystemURL file1 = CreateURL(root_url1, "foo"); - EXPECT_EQ(base::File::FILE_OK, - AsyncFileTestHelper::CreateFile(context_.get(), file1)); - EXPECT_TRUE(AsyncFileTestHelper::FileExists( - context_.get(), file1, AsyncFileTestHelper::kDontCheckSize)); - - // See the same path is not available in kPlugin2. - const GURL root_url2(GetIsolatedFileSystemRootURIString( - kOrigin.GetURL(), filesystem_id2, kRootName)); - FileSystemURL file2 = CreateURL(root_url2, "foo"); - EXPECT_FALSE(AsyncFileTestHelper::FileExists( - context_.get(), file2, AsyncFileTestHelper::kDontCheckSize)); -} - -TEST_F(PluginPrivateFileSystemBackendTest, OriginIsolation) { - const Origin kOrigin1 = Origin::Create(GURL("http://www.example.com")); - const Origin kOrigin2 = Origin::Create(GURL("https://www.example.com")); - - // Open filesystem for kOrigin1 and kOrigin2. - const std::string filesystem_id1 = RegisterFileSystem(); - base::File::Error error = base::File::FILE_ERROR_FAILED; - backend()->OpenPrivateFileSystem(kOrigin1, kType, filesystem_id1, kPlugin1, - OPEN_FILE_SYSTEM_CREATE_IF_NONEXISTENT, - base::BindOnce(&DidOpenFileSystem, &error)); - base::RunLoop().RunUntilIdle(); - ASSERT_EQ(base::File::FILE_OK, error); - - const std::string filesystem_id2 = RegisterFileSystem(); - error = base::File::FILE_ERROR_FAILED; - backend()->OpenPrivateFileSystem(kOrigin2, kType, filesystem_id2, kPlugin1, - OPEN_FILE_SYSTEM_CREATE_IF_NONEXISTENT, - base::BindOnce(&DidOpenFileSystem, &error)); - base::RunLoop().RunUntilIdle(); - ASSERT_EQ(base::File::FILE_OK, error); - - // Create 'foo' in kOrigin1. - const GURL root_url1(GetIsolatedFileSystemRootURIString( - kOrigin1.GetURL(), filesystem_id1, kRootName)); - FileSystemURL file1 = CreateURL(root_url1, "foo"); - EXPECT_EQ(base::File::FILE_OK, - AsyncFileTestHelper::CreateFile(context_.get(), file1)); - EXPECT_TRUE(AsyncFileTestHelper::FileExists( - context_.get(), file1, AsyncFileTestHelper::kDontCheckSize)); - - // See the same path is not available in kOrigin2. - const GURL root_url2(GetIsolatedFileSystemRootURIString( - kOrigin2.GetURL(), filesystem_id2, kRootName)); - FileSystemURL file2 = CreateURL(root_url2, "foo"); - EXPECT_FALSE(AsyncFileTestHelper::FileExists( - context_.get(), file2, AsyncFileTestHelper::kDontCheckSize)); -} - -TEST_F(PluginPrivateFileSystemBackendTest, DeleteOriginDirectory) { - const blink::StorageKey kStorageKey1 = - blink::StorageKey::CreateFromStringForTesting("http://www.example.com"); - const blink::StorageKey kStorageKey2 = - blink::StorageKey::CreateFromStringForTesting("https://www.example.com"); - - // Open filesystem for kStorageKey1.origin() and kStorageKey2.origin(). - const std::string filesystem_id1 = RegisterFileSystem(); - base::File::Error error = base::File::FILE_ERROR_FAILED; - backend()->OpenPrivateFileSystem(kStorageKey1.origin(), kType, filesystem_id1, - kPlugin1, - OPEN_FILE_SYSTEM_CREATE_IF_NONEXISTENT, - base::BindOnce(&DidOpenFileSystem, &error)); - base::RunLoop().RunUntilIdle(); - ASSERT_EQ(base::File::FILE_OK, error); - - const std::string filesystem_id2 = RegisterFileSystem(); - error = base::File::FILE_ERROR_FAILED; - backend()->OpenPrivateFileSystem(kStorageKey2.origin(), kType, filesystem_id2, - kPlugin1, - OPEN_FILE_SYSTEM_CREATE_IF_NONEXISTENT, - base::BindOnce(&DidOpenFileSystem, &error)); - base::RunLoop().RunUntilIdle(); - ASSERT_EQ(base::File::FILE_OK, error); - - // Create 'foo' in kStorageKey1.origin(). - const GURL root_url1(GetIsolatedFileSystemRootURIString( - kStorageKey1.origin().GetURL(), filesystem_id1, kRootName)); - FileSystemURL file1 = CreateURL(root_url1, "foo"); - EXPECT_EQ(base::File::FILE_OK, - AsyncFileTestHelper::CreateFile(context_.get(), file1)); - EXPECT_TRUE(AsyncFileTestHelper::FileExists( - context_.get(), file1, AsyncFileTestHelper::kDontCheckSize)); - - // Create 'foo' in kStorageKey2.origin(). - const GURL root_url2(GetIsolatedFileSystemRootURIString( - kStorageKey2.origin().GetURL(), filesystem_id2, kRootName)); - FileSystemURL file2 = CreateURL(root_url2, "foo"); - EXPECT_EQ(base::File::FILE_OK, - AsyncFileTestHelper::CreateFile(context_.get(), file2)); - EXPECT_TRUE(AsyncFileTestHelper::FileExists( - context_.get(), file2, AsyncFileTestHelper::kDontCheckSize)); - - // Delete data for kStorageKey1.origin(). - error = backend()->DeleteStorageKeyDataOnFileTaskRunner( - context_.get(), nullptr, kStorageKey1, kType); - EXPECT_EQ(base::File::FILE_OK, error); - - // Confirm 'foo' in kStorageKey1.origin() is deleted. - EXPECT_FALSE(AsyncFileTestHelper::FileExists( - context_.get(), file1, AsyncFileTestHelper::kDontCheckSize)); - - // Confirm 'foo' in kStorageKey2.origin() is NOT deleted. - EXPECT_TRUE(AsyncFileTestHelper::FileExists( - context_.get(), file2, AsyncFileTestHelper::kDontCheckSize)); - - // Re-open filesystem for kStorageKey1.origin(). - const std::string filesystem_id3 = RegisterFileSystem(); - error = base::File::FILE_ERROR_FAILED; - backend()->OpenPrivateFileSystem(kStorageKey1.origin(), kType, filesystem_id3, - kPlugin1, - OPEN_FILE_SYSTEM_CREATE_IF_NONEXISTENT, - base::BindOnce(&DidOpenFileSystem, &error)); - base::RunLoop().RunUntilIdle(); - ASSERT_EQ(base::File::FILE_OK, error); - - // Re-create 'foo' in kStorageKey1.origin(). - const GURL root_url3(GetIsolatedFileSystemRootURIString( - kStorageKey1.origin().GetURL(), filesystem_id3, kRootName)); - FileSystemURL file3 = CreateURL(root_url3, "foo"); - EXPECT_EQ(base::File::FILE_OK, - AsyncFileTestHelper::CreateFile(context_.get(), file3)); - EXPECT_TRUE(AsyncFileTestHelper::FileExists( - context_.get(), file3, AsyncFileTestHelper::kDontCheckSize)); - - // Confirm 'foo' in kStorageKey1.origin() is re-created. - EXPECT_TRUE(AsyncFileTestHelper::FileExists( - context_.get(), file3, AsyncFileTestHelper::kDontCheckSize)); -} - -} // namespace storage diff --git a/chromium/storage/browser/file_system/quota/quota_backend_impl.cc b/chromium/storage/browser/file_system/quota/quota_backend_impl.cc index 618bc3a7978..b6e7e81b5ea 100644 --- a/chromium/storage/browser/file_system/quota/quota_backend_impl.cc +++ b/chromium/storage/browser/file_system/quota/quota_backend_impl.cc @@ -13,6 +13,7 @@ #include "base/bind.h" #include "base/callback.h" #include "base/check_op.h" +#include "base/files/file_error_or.h" #include "base/numerics/safe_conversions.h" #include "base/task/sequenced_task_runner.h" #include "storage/browser/file_system/file_system_usage_cache.h" @@ -76,10 +77,11 @@ void QuotaBackendImpl::CommitQuotaUsage(const url::Origin& origin, if (!delta) return; ReserveQuotaInternal(QuotaReservationInfo(origin, type, delta)); - base::FilePath path; - if (GetUsageCachePath(origin, type, &path) != base::File::FILE_OK) + base::FileErrorOr<base::FilePath> path = GetUsageCachePath(origin, type); + if (path.is_error()) return; - bool result = file_system_usage_cache_->AtomicUpdateUsageByDelta(path, delta); + bool result = + file_system_usage_cache_->AtomicUpdateUsageByDelta(path.value(), delta); DCHECK(result); } @@ -87,22 +89,22 @@ void QuotaBackendImpl::IncrementDirtyCount(const url::Origin& origin, FileSystemType type) { DCHECK(file_task_runner_->RunsTasksInCurrentSequence()); DCHECK(!origin.opaque()); - base::FilePath path; - if (GetUsageCachePath(origin, type, &path) != base::File::FILE_OK) + base::FileErrorOr<base::FilePath> path = GetUsageCachePath(origin, type); + if (path.is_error()) return; DCHECK(file_system_usage_cache_); - file_system_usage_cache_->IncrementDirty(path); + file_system_usage_cache_->IncrementDirty(path.value()); } void QuotaBackendImpl::DecrementDirtyCount(const url::Origin& origin, FileSystemType type) { DCHECK(file_task_runner_->RunsTasksInCurrentSequence()); DCHECK(!origin.opaque()); - base::FilePath path; - if (GetUsageCachePath(origin, type, &path) != base::File::FILE_OK) + base::FileErrorOr<base::FilePath> path = GetUsageCachePath(origin, type); + if (path.is_error()) return; DCHECK(file_system_usage_cache_); - file_system_usage_cache_->DecrementDirty(path); + file_system_usage_cache_->DecrementDirty(path.value()); } void QuotaBackendImpl::DidGetUsageAndQuotaForReserveQuota( @@ -149,18 +151,14 @@ void QuotaBackendImpl::ReserveQuotaInternal(const QuotaReservationInfo& info) { base::DoNothing()); } -base::File::Error QuotaBackendImpl::GetUsageCachePath( +base::FileErrorOr<base::FilePath> QuotaBackendImpl::GetUsageCachePath( const url::Origin& origin, - FileSystemType type, - base::FilePath* usage_file_path) { + FileSystemType type) { DCHECK(file_task_runner_->RunsTasksInCurrentSequence()); DCHECK(!origin.opaque()); - DCHECK(usage_file_path); - base::File::Error error = base::File::FILE_OK; - *usage_file_path = - SandboxFileSystemBackendDelegate::GetUsageCachePathForStorageKeyAndType( - obfuscated_file_util_, blink::StorageKey(origin), type, &error); - return error; + return SandboxFileSystemBackendDelegate:: + GetUsageCachePathForStorageKeyAndType(obfuscated_file_util_, + blink::StorageKey(origin), type); } QuotaBackendImpl::QuotaReservationInfo::QuotaReservationInfo( diff --git a/chromium/storage/browser/file_system/quota/quota_backend_impl.h b/chromium/storage/browser/file_system/quota/quota_backend_impl.h index 7b3415dd6d7..8bb50a14b66 100644 --- a/chromium/storage/browser/file_system/quota/quota_backend_impl.h +++ b/chromium/storage/browser/file_system/quota/quota_backend_impl.h @@ -8,6 +8,7 @@ #include <stdint.h> #include "base/component_export.h" +#include "base/files/file_error_or.h" #include "base/memory/raw_ptr.h" #include "base/memory/ref_counted.h" #include "base/memory/weak_ptr.h" @@ -79,9 +80,8 @@ class COMPONENT_EXPORT(STORAGE_BROWSER) QuotaBackendImpl int64_t quota); void ReserveQuotaInternal(const QuotaReservationInfo& info); - base::File::Error GetUsageCachePath(const url::Origin& origin, - FileSystemType type, - base::FilePath* usage_file_path); + base::FileErrorOr<base::FilePath> GetUsageCachePath(const url::Origin& origin, + FileSystemType type); const scoped_refptr<base::SequencedTaskRunner> file_task_runner_; diff --git a/chromium/storage/browser/file_system/quota/quota_backend_impl_unittest.cc b/chromium/storage/browser/file_system/quota/quota_backend_impl_unittest.cc index abc4b126e1f..6d40b5d2394 100644 --- a/chromium/storage/browser/file_system/quota/quota_backend_impl_unittest.cc +++ b/chromium/storage/browser/file_system/quota/quota_backend_impl_unittest.cc @@ -12,6 +12,7 @@ #include "base/bind.h" #include "base/check.h" +#include "base/files/file_error_or.h" #include "base/files/scoped_temp_dir.h" #include "base/memory/scoped_refptr.h" #include "base/run_loop.h" @@ -137,12 +138,10 @@ class QuotaBackendImplTest : public testing::Test, ASSERT_TRUE(file_util_->InitOriginDatabase(origin, true /* create */)); ASSERT_TRUE(file_util_->origin_database_ != nullptr); - std::string type_string = - SandboxFileSystemBackendDelegate::GetTypeString(type); - base::File::Error error = base::File::FILE_ERROR_FAILED; - base::FilePath path = file_util_->GetDirectoryForStorageKeyAndType( - blink::StorageKey(origin), type_string, true /* create */, &error); - ASSERT_EQ(base::File::FILE_OK, error); + base::FileErrorOr<base::FilePath> path = + file_util_->GetDirectoryForStorageKeyAndType(blink::StorageKey(origin), + type, true /* create */); + ASSERT_FALSE(path.is_error()); ASSERT_TRUE(file_system_usage_cache_.UpdateUsage( GetUsageCachePath(origin, type), 0)); @@ -154,11 +153,11 @@ class QuotaBackendImplTest : public testing::Test, base::FilePath GetUsageCachePath(const url::Origin& origin, FileSystemType type) { - base::FilePath path; - base::File::Error error = backend_->GetUsageCachePath(origin, type, &path); - EXPECT_EQ(base::File::FILE_OK, error); - EXPECT_FALSE(path.empty()); - return path; + base::FileErrorOr<base::FilePath> path = + backend_->GetUsageCachePath(origin, type); + EXPECT_FALSE(path.is_error()); + EXPECT_FALSE(path->empty()); + return path.value(); } base::test::SingleThreadTaskEnvironment task_environment_; diff --git a/chromium/storage/browser/file_system/recursive_operation_delegate.cc b/chromium/storage/browser/file_system/recursive_operation_delegate.cc index 925cd2ac08b..079908861e1 100644 --- a/chromium/storage/browser/file_system/recursive_operation_delegate.cc +++ b/chromium/storage/browser/file_system/recursive_operation_delegate.cc @@ -121,6 +121,8 @@ void RecursiveOperationDelegate::DidReadDirectory(const FileSystemURL& parent, FileSystemURL url = file_system_context_->CreateCrackedFileSystemURL( parent.storage_key(), parent.mount_type(), parent.virtual_path().Append(entries[i].name)); + if (parent.bucket().has_value()) + url.SetBucket(parent.bucket().value()); if (entries[i].type == filesystem::mojom::FsFileType::DIRECTORY) pending_directory_stack_.top().push(url); else diff --git a/chromium/storage/browser/file_system/recursive_operation_delegate.h b/chromium/storage/browser/file_system/recursive_operation_delegate.h index 72b28fa2708..9b99b0dd4c6 100644 --- a/chromium/storage/browser/file_system/recursive_operation_delegate.h +++ b/chromium/storage/browser/file_system/recursive_operation_delegate.h @@ -150,7 +150,7 @@ class COMPONENT_EXPORT(STORAGE_BROWSER) RecursiveOperationDelegate // Called when all recursive operation is done (or an error occurs). void Done(base::File::Error error); - raw_ptr<FileSystemContext> file_system_context_; + raw_ptr<FileSystemContext, DanglingUntriaged> file_system_context_; StatusCallback callback_; base::stack<FileSystemURL> pending_directories_; base::stack<base::queue<FileSystemURL>> pending_directory_stack_; diff --git a/chromium/storage/browser/file_system/recursive_operation_delegate_unittest.cc b/chromium/storage/browser/file_system/recursive_operation_delegate_unittest.cc index 5a9827959e8..82eb5ed1ac3 100644 --- a/chromium/storage/browser/file_system/recursive_operation_delegate_unittest.cc +++ b/chromium/storage/browser/file_system/recursive_operation_delegate_unittest.cc @@ -21,6 +21,9 @@ #include "storage/browser/file_system/file_system_file_util.h" #include "storage/browser/file_system/file_system_operation.h" #include "storage/browser/file_system/file_system_operation_runner.h" +#include "storage/browser/test/mock_quota_manager.h" +#include "storage/browser/test/mock_quota_manager_proxy.h" +#include "storage/browser/test/mock_special_storage_policy.h" #include "storage/browser/test/sandbox_file_system_test_helper.h" #include "testing/gtest/include/gtest/gtest.h" @@ -145,7 +148,13 @@ class RecursiveOperationDelegateTest : public testing::Test { protected: void SetUp() override { EXPECT_TRUE(base_.CreateUniqueTempDir()); - sandbox_file_system_.SetUp(base_.GetPath().AppendASCII("filesystem")); + base::FilePath base_dir = base_.GetPath().AppendASCII("filesystem"); + quota_manager_ = base::MakeRefCounted<storage::MockQuotaManager>( + /*is_incognito=*/false, base_dir, base::ThreadTaskRunnerHandle::Get(), + base::MakeRefCounted<storage::MockSpecialStoragePolicy>()); + quota_manager_proxy_ = base::MakeRefCounted<storage::MockQuotaManagerProxy>( + quota_manager_.get(), base::ThreadTaskRunnerHandle::Get()); + sandbox_file_system_.SetUp(base_dir, quota_manager_proxy_); } void TearDown() override { sandbox_file_system_.TearDown(); } @@ -186,6 +195,8 @@ class RecursiveOperationDelegateTest : public testing::Test { // Common temp base for nondestructive uses. base::ScopedTempDir base_; SandboxFileSystemTestHelper sandbox_file_system_; + scoped_refptr<storage::MockQuotaManager> quota_manager_; + scoped_refptr<storage::MockQuotaManagerProxy> quota_manager_proxy_; }; TEST_F(RecursiveOperationDelegateTest, RootIsFile) { diff --git a/chromium/storage/browser/file_system/sandbox_file_stream_reader.cc b/chromium/storage/browser/file_system/sandbox_file_stream_reader.cc index cf8b331be8d..41cf7f07604 100644 --- a/chromium/storage/browser/file_system/sandbox_file_stream_reader.cc +++ b/chromium/storage/browser/file_system/sandbox_file_stream_reader.cc @@ -18,7 +18,6 @@ #include "storage/browser/file_system/file_system_operation_runner.h" #include "storage/browser/file_system/memory_file_stream_reader.h" #include "storage/browser/file_system/obfuscated_file_util_memory_delegate.h" -#include "storage/browser/file_system/plugin_private_file_system_backend.h" // TODO(kinuko): Remove this temporary namespace hack after we move both // blob and fileapi into content namespace. @@ -92,17 +91,8 @@ void SandboxFileStreamReader::DidCreateSnapshot( snapshot_ref_ = std::move(file_ref); if (file_system_context_->is_incognito()) { - base::WeakPtr<ObfuscatedFileUtilMemoryDelegate> memory_file_util_delegate; - if (url_.type() == kFileSystemTypePluginPrivate) { - auto* backend = static_cast<PluginPrivateFileSystemBackend*>( - file_system_context_->GetFileSystemBackend( - kFileSystemTypePluginPrivate)); - memory_file_util_delegate = - backend->obfuscated_file_util_memory_delegate()->GetWeakPtr(); - } else { - memory_file_util_delegate = - file_system_context_->sandbox_delegate()->memory_file_util_delegate(); - } + base::WeakPtr<ObfuscatedFileUtilMemoryDelegate> memory_file_util_delegate = + file_system_context_->sandbox_delegate()->memory_file_util_delegate(); file_reader_ = std::make_unique<MemoryFileStreamReader>( file_system_context_->default_file_task_runner(), memory_file_util_delegate, platform_path, initial_offset_, diff --git a/chromium/storage/browser/file_system/sandbox_file_stream_reader.h b/chromium/storage/browser/file_system/sandbox_file_stream_reader.h index 5e815b1050f..fa5efcfd37c 100644 --- a/chromium/storage/browser/file_system/sandbox_file_stream_reader.h +++ b/chromium/storage/browser/file_system/sandbox_file_stream_reader.h @@ -66,7 +66,7 @@ class COMPONENT_EXPORT(STORAGE_BROWSER) SandboxFileStreamReader void OnRead(int rv); void OnGetLength(int64_t rv); - raw_ptr<net::IOBuffer> read_buf_; + raw_ptr<net::IOBuffer, DanglingUntriaged> read_buf_; int read_buf_len_; net::CompletionOnceCallback read_callback_; net::Int64CompletionOnceCallback get_length_callback_; diff --git a/chromium/storage/browser/file_system/sandbox_file_stream_writer.cc b/chromium/storage/browser/file_system/sandbox_file_stream_writer.cc index f82f43bb54a..27f568fc748 100644 --- a/chromium/storage/browser/file_system/sandbox_file_stream_writer.cc +++ b/chromium/storage/browser/file_system/sandbox_file_stream_writer.cc @@ -22,7 +22,6 @@ #include "storage/browser/file_system/file_system_util.h" #include "storage/browser/file_system/memory_file_stream_writer.h" #include "storage/browser/file_system/obfuscated_file_util_memory_delegate.h" -#include "storage/browser/file_system/plugin_private_file_system_backend.h" #include "storage/browser/quota/quota_manager_proxy.h" #include "storage/common/file_system/file_system_util.h" #include "third_party/blink/public/common/storage_key/storage_key.h" @@ -147,17 +146,8 @@ void SandboxFileStreamWriter::DidCreateSnapshotFile( DCHECK(!file_writer_.get()); if (file_system_context_->is_incognito()) { - base::WeakPtr<ObfuscatedFileUtilMemoryDelegate> memory_file_util_delegate; - if (url_.type() == kFileSystemTypePluginPrivate) { - auto* backend = static_cast<PluginPrivateFileSystemBackend*>( - file_system_context_->GetFileSystemBackend( - kFileSystemTypePluginPrivate)); - memory_file_util_delegate = - backend->obfuscated_file_util_memory_delegate()->GetWeakPtr(); - } else { - memory_file_util_delegate = - file_system_context_->sandbox_delegate()->memory_file_util_delegate(); - } + base::WeakPtr<ObfuscatedFileUtilMemoryDelegate> memory_file_util_delegate = + file_system_context_->sandbox_delegate()->memory_file_util_delegate(); file_writer_ = std::make_unique<MemoryFileStreamWriter>( file_system_context_->default_file_task_runner(), memory_file_util_delegate, platform_path, initial_offset_); diff --git a/chromium/storage/browser/file_system/sandbox_file_stream_writer_unittest.cc b/chromium/storage/browser/file_system/sandbox_file_stream_writer_unittest.cc index 756a1260636..d854c07364f 100644 --- a/chromium/storage/browser/file_system/sandbox_file_stream_writer_unittest.cc +++ b/chromium/storage/browser/file_system/sandbox_file_stream_writer_unittest.cc @@ -3,7 +3,7 @@ // found in the LICENSE file. #include "storage/browser/file_system/sandbox_file_stream_writer.h" -#include "base/test/bind.h" +#include "base/test/test_future.h" #include "storage/browser/file_system/file_stream_writer_test.h" #include <stdint.h> @@ -157,16 +157,16 @@ class SandboxFileStreamWriterTest : public FileStreamWriterTest { } quota_usage_and_info GetUsageAndQuotaSync() { - quota_usage_and_info info; + base::test::TestFuture<blink::mojom::QuotaStatusCode, int64_t, int64_t> + future; quota_manager_->GetUsageAndQuota( blink::StorageKey::CreateFromStringForTesting(kURLOrigin), - blink::mojom::StorageType::kTemporary, - base::BindLambdaForTesting([&](blink::mojom::QuotaStatusCode status, - int64_t usage, int64_t quota) { - info.status = status; - info.usage = usage; - info.quota = quota; - })); + blink::mojom::StorageType::kTemporary, future.GetCallback()); + + quota_usage_and_info info; + info.status = future.Get<0>(); + info.usage = future.Get<1>(); + info.quota = future.Get<2>(); return info; } diff --git a/chromium/storage/browser/file_system/sandbox_file_system_backend.cc b/chromium/storage/browser/file_system/sandbox_file_system_backend.cc index 1717a4e12d3..b16792cfcef 100644 --- a/chromium/storage/browser/file_system/sandbox_file_system_backend.cc +++ b/chromium/storage/browser/file_system/sandbox_file_system_backend.cc @@ -73,7 +73,7 @@ void SandboxFileSystemBackend::ResolveURL(const FileSystemURL& url, } delegate_->OpenFileSystem( - url.storage_key(), url.type(), mode, std::move(callback), + url.storage_key(), url.bucket(), url.type(), mode, std::move(callback), GetFileSystemRootURI(url.origin().GetURL(), url.type())); } diff --git a/chromium/storage/browser/file_system/sandbox_file_system_backend_delegate.cc b/chromium/storage/browser/file_system/sandbox_file_system_backend_delegate.cc index e3a11138341..eaccad9a816 100644 --- a/chromium/storage/browser/file_system/sandbox_file_system_backend_delegate.cc +++ b/chromium/storage/browser/file_system/sandbox_file_system_backend_delegate.cc @@ -14,6 +14,7 @@ #include "base/callback_helpers.h" #include "base/command_line.h" #include "base/containers/contains.h" +#include "base/files/file_error_or.h" #include "base/files/file_util.h" #include "base/metrics/histogram_macros.h" #include "base/task/task_runner_util.h" @@ -81,10 +82,6 @@ const base::FilePath::CharType kRestrictedChars[] = { FILE_PATH_LITERAL('\\'), }; -std::string GetTypeStringForURL(const FileSystemURL& url) { - return SandboxFileSystemBackendDelegate::GetTypeString(url.type()); -} - std::set<std::string> GetKnownTypeStrings() { std::set<std::string> known_type_strings; known_type_strings.insert(kTemporaryDirectoryName); @@ -116,13 +113,22 @@ class SandboxObfuscatedStorageKeyEnumerator base::File::Error OpenSandboxFileSystemOnFileTaskRunner( ObfuscatedFileUtil* file_util, const GURL& origin_url, + const absl::optional<BucketLocator>& bucket_locator, FileSystemType type, OpenFileSystemMode mode) { const bool create = (mode == OPEN_FILE_SYSTEM_CREATE_IF_NONEXISTENT); base::File::Error error; - file_util->GetDirectoryForStorageKeyAndType( - blink::StorageKey(url::Origin::Create(origin_url)), - SandboxFileSystemBackendDelegate::GetTypeString(type), create, &error); + if (bucket_locator.has_value()) { + base::FileErrorOr<base::FilePath> path = + file_util->GetDirectoryForBucketAndType(bucket_locator.value(), type, + create); + error = (path.is_error()) ? path.error() : base::File::FILE_OK; + } else { + base::FileErrorOr<base::FilePath> path = + file_util->GetDirectoryForStorageKeyAndType( + blink::StorageKey(url::Origin::Create(origin_url)), type, create); + error = (path.is_error()) ? path.error() : base::File::FILE_OK; + } if (error != base::File::FILE_OK) { UMA_HISTOGRAM_ENUMERATION(kOpenFileSystemLabel, kCreateDirectoryError, kFileSystemErrorMax); @@ -156,10 +162,6 @@ void DeleteSoon(base::SequencedTaskRunner* runner, T* ptr) { } // namespace -const base::FilePath::CharType - SandboxFileSystemBackendDelegate::kFileSystemDirectory[] = - FILE_PATH_LITERAL("File System"); - // static std::string SandboxFileSystemBackendDelegate::GetTypeString( FileSystemType type) { @@ -190,9 +192,8 @@ SandboxFileSystemBackendDelegate::SandboxFileSystemBackendDelegate( sandbox_file_util_(std::make_unique<AsyncFileUtilAdapter>( std::make_unique<ObfuscatedFileUtil>( special_storage_policy, - profile_path.Append(kFileSystemDirectory), + profile_path, env_override, - base::BindRepeating(&GetTypeStringForURL), GetKnownTypeStrings(), this, file_system_options.is_incognito()))), @@ -217,8 +218,12 @@ SandboxFileSystemBackendDelegate::~SandboxFileSystemBackendDelegate() { if (!file_task_runner_->RunsTasksInCurrentSequence()) { DeleteSoon(file_task_runner_.get(), quota_reservation_manager_.release()); - DeleteSoon(file_task_runner_.get(), sandbox_file_util_.release()); + // `quota_observer_` depends on `sandbox_file_util_` and + // `file_system_usage_cache_` so it must be released first. DeleteSoon(file_task_runner_.get(), quota_observer_.release()); + // Clear pointer to |this| to avoid holding a dangling ptr. + obfuscated_file_util()->sandbox_delegate_ = nullptr; + DeleteSoon(file_task_runner_.get(), sandbox_file_util_.release()); DeleteSoon(file_task_runner_.get(), file_system_usage_cache_.release()); } } @@ -233,13 +238,12 @@ SandboxFileSystemBackendDelegate::GetBaseDirectoryForStorageKeyAndType( const blink::StorageKey& storage_key, FileSystemType type, bool create) { - base::File::Error error = base::File::FILE_OK; - base::FilePath path = - obfuscated_file_util()->GetDirectoryForStorageKeyAndType( - storage_key, GetTypeString(type), create, &error); - if (error != base::File::FILE_OK) + base::FileErrorOr<base::FilePath> path = + obfuscated_file_util()->GetDirectoryForStorageKeyAndType(storage_key, + type, create); + if (path.is_error()) return base::FilePath(); - return path; + return path.value(); } base::FilePath @@ -248,8 +252,8 @@ SandboxFileSystemBackendDelegate::GetBaseDirectoryForBucketAndType( FileSystemType type, bool create) { base::FileErrorOr<base::FilePath> path = - obfuscated_file_util()->GetDirectoryForBucketAndType( - bucket_locator, GetTypeString(type), create); + obfuscated_file_util()->GetDirectoryForBucketAndType(bucket_locator, type, + create); if (path.is_error()) return base::FilePath(); return path.value(); @@ -257,6 +261,7 @@ SandboxFileSystemBackendDelegate::GetBaseDirectoryForBucketAndType( void SandboxFileSystemBackendDelegate::OpenFileSystem( const blink::StorageKey& storage_key, + const absl::optional<BucketLocator>& bucket_locator, FileSystemType type, OpenFileSystemMode mode, ResolveURLCallback callback, @@ -270,19 +275,25 @@ void SandboxFileSystemBackendDelegate::OpenFileSystem( std::string name = GetFileSystemName(storage_key.origin().GetURL(), type); // |quota_manager_proxy_| may be null in unit tests. - base::OnceClosure quota_callback = - (quota_manager_proxy_.get()) - ? base::BindOnce(&QuotaManagerProxy::NotifyStorageAccessed, - quota_manager_proxy_, storage_key, - FileSystemTypeToQuotaStorageType(type), - base::Time::Now()) - : base::DoNothing(); + base::OnceClosure quota_callback; + if (quota_manager_proxy_.get()) { + quota_callback = + (bucket_locator.has_value()) + ? base::BindOnce(&QuotaManagerProxy::NotifyBucketAccessed, + quota_manager_proxy_, bucket_locator->id, + base::Time::Now()) + : base::BindOnce(&QuotaManagerProxy::NotifyStorageAccessed, + quota_manager_proxy_, storage_key, + FileSystemTypeToQuotaStorageType(type), + base::Time::Now()); + } else + quota_callback = base::DoNothing(); file_task_runner_->PostTaskAndReplyWithResult( FROM_HERE, base::BindOnce(&OpenSandboxFileSystemOnFileTaskRunner, obfuscated_file_util(), storage_key.origin().GetURL(), - type, mode), + bucket_locator, type, mode), base::BindOnce(&DidOpenFileSystem, weak_factory_.GetWeakPtr(), std::move(quota_callback), base::BindOnce(std::move(callback), root_url, name))); @@ -351,7 +362,7 @@ SandboxFileSystemBackendDelegate::DeleteStorageKeyDataOnFileTaskRunner( storage_key, type); usage_cache()->CloseCacheFiles(); bool result = obfuscated_file_util()->DeleteDirectoryForStorageKeyAndType( - storage_key, GetTypeString(type)); + storage_key, type); if (result && proxy && usage) { proxy->NotifyStorageModified( QuotaClientType::kFileSystem, storage_key, @@ -359,6 +370,51 @@ SandboxFileSystemBackendDelegate::DeleteStorageKeyDataOnFileTaskRunner( base::SequencedTaskRunnerHandle::Get(), base::DoNothing()); } + // If obfuscated_file_util() was caching the default bucket for this + // StorageKey, it should be deleted as well. If it was not cached, result is a + // no-op. NOTE: one StorageKey may map to many BucketLocators depending on the + // type. We only want to cache and delete kFileSystemTypeTemporary buckets. + // Otherwise, we may accidentally delete the wrong databases. + if (FileSystemTypeToQuotaStorageType(type) == + blink::mojom::StorageType::kTemporary) { + obfuscated_file_util()->DeleteDefaultBucketForStorageKey(storage_key); + } + + if (result) + return base::File::FILE_OK; + return base::File::FILE_ERROR_FAILED; +} + +base::File::Error +SandboxFileSystemBackendDelegate::DeleteBucketDataOnFileTaskRunner( + FileSystemContext* file_system_context, + QuotaManagerProxy* proxy, + const BucketLocator& bucket_locator, + FileSystemType type) { + DCHECK(file_task_runner_->RunsTasksInCurrentSequence()); + int64_t usage = (proxy) ? GetBucketUsageOnFileTaskRunner(file_system_context, + bucket_locator, type) + : 0; + usage_cache()->CloseCacheFiles(); + bool result = obfuscated_file_util()->DeleteDirectoryForBucketAndType( + bucket_locator, type); + if (result && proxy && usage) { + proxy->NotifyBucketModified(QuotaClientType::kFileSystem, bucket_locator.id, + -usage, base::Time::Now(), + base::SequencedTaskRunnerHandle::Get(), + base::DoNothing()); + } + + // If obfuscated_file_util() was caching this default bucket, it should be + // deleted as well. If it was not cached, result is a no-op. NOTE: We only + // want to cache and delete kTemporary buckets. Otherwise, we may accidentally + // delete the wrong databases. + if (FileSystemTypeToQuotaStorageType(type) == + blink::mojom::StorageType::kTemporary && + bucket_locator.is_default) { + obfuscated_file_util()->DeleteDefaultBucket(bucket_locator); + } + if (result) return base::File::FILE_OK; return base::File::FILE_ERROR_FAILED; @@ -547,12 +603,12 @@ void SandboxFileSystemBackendDelegate::RegisterQuotaUpdateObserver( void SandboxFileSystemBackendDelegate::InvalidateUsageCache( const blink::StorageKey& storage_key, FileSystemType type) { - base::File::Error error = base::File::FILE_OK; - base::FilePath usage_file_path = GetUsageCachePathForStorageKeyAndType( - obfuscated_file_util(), storage_key, type, &error); - if (error != base::File::FILE_OK) + base::FileErrorOr<base::FilePath> usage_file_path = + GetUsageCachePathForStorageKeyAndType(obfuscated_file_util(), storage_key, + type); + if (usage_file_path.is_error()) return; - usage_cache()->IncrementDirty(usage_file_path); + usage_cache()->IncrementDirty(usage_file_path.value()); } void SandboxFileSystemBackendDelegate::StickyInvalidateUsageCache( @@ -616,62 +672,48 @@ bool SandboxFileSystemBackendDelegate::IsAllowedScheme(const GURL& url) const { return false; } -base::FilePath +base::FileErrorOr<base::FilePath> SandboxFileSystemBackendDelegate::GetUsageCachePathForStorageKeyAndType( const blink::StorageKey& storage_key, FileSystemType type) { - base::File::Error error; - base::FilePath path = GetUsageCachePathForStorageKeyAndType( - obfuscated_file_util(), storage_key, type, &error); - if (error != base::File::FILE_OK) - return base::FilePath(); - return path; + return GetUsageCachePathForStorageKeyAndType(obfuscated_file_util(), + storage_key, type); } // static -base::FilePath +base::FileErrorOr<base::FilePath> SandboxFileSystemBackendDelegate::GetUsageCachePathForStorageKeyAndType( ObfuscatedFileUtil* sandbox_file_util, const blink::StorageKey& storage_key, - FileSystemType type, - base::File::Error* error_out) { - DCHECK(error_out); - *error_out = base::File::FILE_OK; - base::FilePath base_path = - sandbox_file_util->GetDirectoryForStorageKeyAndType( - storage_key, GetTypeString(type), false /* create */, error_out); - if (*error_out != base::File::FILE_OK) - return base::FilePath(); - return base_path.Append(FileSystemUsageCache::kUsageFileName); + FileSystemType type) { + base::FileErrorOr<base::FilePath> base_path = + sandbox_file_util->GetDirectoryForStorageKeyAndType(storage_key, type, + false /* create */); + if (base_path.is_error()) { + return base_path; + } + return base_path->Append(FileSystemUsageCache::kUsageFileName); } -base::FilePath +base::FileErrorOr<base::FilePath> SandboxFileSystemBackendDelegate::GetUsageCachePathForBucketAndType( const BucketLocator& bucket_locator, FileSystemType type) { - base::File::Error error; - base::FilePath path = GetUsageCachePathForBucketAndType( - obfuscated_file_util(), bucket_locator, type, &error); - if (error != base::File::FILE_OK) - return base::FilePath(); - return path; + return GetUsageCachePathForBucketAndType(obfuscated_file_util(), + bucket_locator, type); } // static -base::FilePath +base::FileErrorOr<base::FilePath> SandboxFileSystemBackendDelegate::GetUsageCachePathForBucketAndType( ObfuscatedFileUtil* sandbox_file_util, const BucketLocator& bucket_locator, - FileSystemType type, - base::File::Error* error_out) { - DCHECK(error_out); - *error_out = base::File::FILE_OK; + FileSystemType type) { base::FileErrorOr<base::FilePath> base_path = - sandbox_file_util->GetDirectoryForBucketAndType( - bucket_locator, GetTypeString(type), /*create=*/false); + sandbox_file_util->GetDirectoryForBucketAndType(bucket_locator, type, + /*create=*/false); if (base_path.is_error()) { - *error_out = base_path.error(); - return base::FilePath(); + return base_path; } return base_path->Append(FileSystemUsageCache::kUsageFileName); } @@ -752,13 +794,12 @@ SandboxFileSystemBackendDelegate::memory_file_util_delegate() { // static std::unique_ptr<ObfuscatedFileUtil> ObfuscatedFileUtil::CreateForTesting( scoped_refptr<SpecialStoragePolicy> special_storage_policy, - const base::FilePath& file_system_directory, + const base::FilePath& profile_path, leveldb::Env* env_override, bool is_incognito) { return std::make_unique<ObfuscatedFileUtil>( - std::move(special_storage_policy), file_system_directory, env_override, - base::BindRepeating(&GetTypeStringForURL), GetKnownTypeStrings(), - /*sandbox_delegate=*/nullptr, is_incognito); + std::move(special_storage_policy), profile_path, env_override, + GetKnownTypeStrings(), /*sandbox_delegate=*/nullptr, is_incognito); } } // namespace storage diff --git a/chromium/storage/browser/file_system/sandbox_file_system_backend_delegate.h b/chromium/storage/browser/file_system/sandbox_file_system_backend_delegate.h index 4bff8911206..30fef5ca0a1 100644 --- a/chromium/storage/browser/file_system/sandbox_file_system_backend_delegate.h +++ b/chromium/storage/browser/file_system/sandbox_file_system_backend_delegate.h @@ -15,6 +15,7 @@ #include <vector> #include "base/component_export.h" +#include "base/files/file_error_or.h" #include "base/files/file_path.h" #include "base/memory/ref_counted.h" #include "base/memory/weak_ptr.h" @@ -72,9 +73,6 @@ class COMPONENT_EXPORT(STORAGE_BROWSER) SandboxFileSystemBackendDelegate using OpenFileSystemCallback = FileSystemBackend::OpenFileSystemCallback; using ResolveURLCallback = FileSystemBackend::ResolveURLCallback; - // The FileSystem directory name. - static const base::FilePath::CharType kFileSystemDirectory[]; - // StorageKey enumerator interface. // An instance of this interface is assumed to be called on the file thread. class StorageKeyEnumerator { @@ -136,6 +134,7 @@ class COMPONENT_EXPORT(STORAGE_BROWSER) SandboxFileSystemBackendDelegate // FileSystemBackend helpers. void OpenFileSystem(const blink::StorageKey& storage_key, + const absl::optional<BucketLocator>& bucket_locator, FileSystemType type, OpenFileSystemMode mode, ResolveURLCallback callback, @@ -161,6 +160,11 @@ class COMPONENT_EXPORT(STORAGE_BROWSER) SandboxFileSystemBackendDelegate QuotaManagerProxy* proxy, const blink::StorageKey& storage_key, FileSystemType type) override; + base::File::Error DeleteBucketDataOnFileTaskRunner( + FileSystemContext* context, + QuotaManagerProxy* proxy, + const BucketLocator& bucket_locator, + FileSystemType type) override; void PerformStorageCleanupOnFileTaskRunner(FileSystemContext* context, QuotaManagerProxy* proxy, FileSystemType type) override; @@ -172,7 +176,7 @@ class COMPONENT_EXPORT(STORAGE_BROWSER) SandboxFileSystemBackendDelegate FileSystemType type) override; int64_t GetBucketUsageOnFileTaskRunner(FileSystemContext* context, const BucketLocator& bucket_locator, - FileSystemType type); + FileSystemType type) override; scoped_refptr<QuotaReservation> CreateQuotaReservationOnFileTaskRunner( const blink::StorageKey& storage_key, FileSystemType type) override; @@ -246,29 +250,27 @@ class COMPONENT_EXPORT(STORAGE_BROWSER) SandboxFileSystemBackendDelegate bool IsAllowedScheme(const GURL& url) const; // Returns a path to the usage cache file. - base::FilePath GetUsageCachePathForStorageKeyAndType( + base::FileErrorOr<base::FilePath> GetUsageCachePathForStorageKeyAndType( const blink::StorageKey& storage_key, FileSystemType type); // Returns a path to the usage cache file (static version). - static base::FilePath GetUsageCachePathForStorageKeyAndType( - ObfuscatedFileUtil* sandbox_file_util, - const blink::StorageKey& storage_key, - FileSystemType type, - base::File::Error* error_out); + static base::FileErrorOr<base::FilePath> + GetUsageCachePathForStorageKeyAndType(ObfuscatedFileUtil* sandbox_file_util, + const blink::StorageKey& storage_key, + FileSystemType type); // Returns a path to the usage cache file for a given bucket and type. - base::FilePath GetUsageCachePathForBucketAndType( + base::FileErrorOr<base::FilePath> GetUsageCachePathForBucketAndType( const BucketLocator& bucket_locator, FileSystemType type); // Returns a path to the usage cache file for a given bucket and type(static // version). - static base::FilePath GetUsageCachePathForBucketAndType( + static base::FileErrorOr<base::FilePath> GetUsageCachePathForBucketAndType( ObfuscatedFileUtil* sandbox_file_util, const BucketLocator& bucket_locator, - FileSystemType type, - base::File::Error* error_out); + FileSystemType type); // Helper function to obtain usage for a StorageKey value and optionally a // BucketLocator value. `storage_key` and `bucket_locator->storage_key` should diff --git a/chromium/storage/browser/file_system/sandbox_file_system_backend_delegate_unittest.cc b/chromium/storage/browser/file_system/sandbox_file_system_backend_delegate_unittest.cc index c6fb104ae60..19a4a5e5b5d 100644 --- a/chromium/storage/browser/file_system/sandbox_file_system_backend_delegate_unittest.cc +++ b/chromium/storage/browser/file_system/sandbox_file_system_backend_delegate_unittest.cc @@ -49,10 +49,11 @@ class SandboxFileSystemBackendDelegateTest : public testing::Test { } void OpenFileSystem(const blink::StorageKey& storage_key, + const absl::optional<BucketLocator>& bucket_locator, FileSystemType type, OpenFileSystemMode mode) { delegate_->OpenFileSystem( - storage_key, type, mode, + storage_key, bucket_locator, type, mode, base::BindOnce( &SandboxFileSystemBackendDelegateTest::OpenFileSystemCallback, base::Unretained(this)), @@ -126,7 +127,10 @@ TEST_F(SandboxFileSystemBackendDelegateTest, OpenFileSystemAccessesStorage) { const blink::StorageKey& storage_key = blink::StorageKey::CreateFromStringForTesting("http://example.com"); - OpenFileSystem(storage_key, kFileSystemTypeTemporary, + // TODO(https://crbug.com/1330608): ensure that this test suite properly + // integrates non-default BucketLocators into OpenFileSystem. + OpenFileSystem(storage_key, /*bucket_locator=*/absl::nullopt, + kFileSystemTypeTemporary, OPEN_FILE_SYSTEM_CREATE_IF_NONEXISTENT); EXPECT_EQ(callback_count(), 1); diff --git a/chromium/storage/browser/file_system/sandbox_file_system_backend_unittest.cc b/chromium/storage/browser/file_system/sandbox_file_system_backend_unittest.cc index 2290b355129..fd43d573af4 100644 --- a/chromium/storage/browser/file_system/sandbox_file_system_backend_unittest.cc +++ b/chromium/storage/browser/file_system/sandbox_file_system_backend_unittest.cc @@ -23,6 +23,7 @@ #include "storage/browser/file_system/file_system_backend.h" #include "storage/browser/file_system/file_system_features.h" #include "storage/browser/file_system/file_system_url.h" +#include "storage/browser/file_system/obfuscated_file_util.h" #include "storage/browser/file_system/sandbox_file_system_backend_delegate.h" #include "storage/browser/quota/quota_manager.h" #include "storage/browser/quota/quota_manager_proxy.h" @@ -203,8 +204,7 @@ class SandboxFileSystemBackendTest } base::FilePath file_system_path() const { - return data_dir_.GetPath().Append( - SandboxFileSystemBackendDelegate::kFileSystemDirectory); + return data_dir_.GetPath().Append(ObfuscatedFileUtil::kFileSystemDirectory); } base::FilePath file_system_path_for_buckets() const { diff --git a/chromium/storage/browser/file_system/sandbox_quota_observer.cc b/chromium/storage/browser/file_system/sandbox_quota_observer.cc index 706c47fc6ad..3b98154e5ec 100644 --- a/chromium/storage/browser/file_system/sandbox_quota_observer.cc +++ b/chromium/storage/browser/file_system/sandbox_quota_observer.cc @@ -7,6 +7,7 @@ #include <stdint.h> #include "base/bind.h" +#include "base/files/file_error_or.h" #include "base/memory/scoped_refptr.h" #include "base/task/sequenced_task_runner.h" #include "storage/browser/file_system/file_system_usage_cache.h" @@ -33,10 +34,10 @@ SandboxQuotaObserver::~SandboxQuotaObserver() = default; void SandboxQuotaObserver::OnStartUpdate(const FileSystemURL& url) { DCHECK(update_notify_runner_->RunsTasksInCurrentSequence()); - base::FilePath usage_file_path = GetUsageCachePath(url); - if (usage_file_path.empty()) + base::FileErrorOr<base::FilePath> usage_file_path = GetUsageCachePath(url); + if (usage_file_path.is_error() || usage_file_path->empty()) return; - file_system_usage_cache_->IncrementDirty(usage_file_path); + file_system_usage_cache_->IncrementDirty(usage_file_path.value()); } void SandboxQuotaObserver::OnUpdate(const FileSystemURL& url, int64_t delta) { @@ -49,11 +50,11 @@ void SandboxQuotaObserver::OnUpdate(const FileSystemURL& url, int64_t delta) { base::SequencedTaskRunnerHandle::Get(), base::DoNothing()); } - base::FilePath usage_file_path = GetUsageCachePath(url); - if (usage_file_path.empty()) + base::FileErrorOr<base::FilePath> usage_file_path = GetUsageCachePath(url); + if (usage_file_path.is_error() || usage_file_path->empty()) return; - pending_update_notification_[usage_file_path] += delta; + pending_update_notification_[usage_file_path.value()] += delta; if (!delayed_cache_update_helper_.IsRunning()) { delayed_cache_update_helper_.Start( FROM_HERE, @@ -66,17 +67,17 @@ void SandboxQuotaObserver::OnUpdate(const FileSystemURL& url, int64_t delta) { void SandboxQuotaObserver::OnEndUpdate(const FileSystemURL& url) { DCHECK(update_notify_runner_->RunsTasksInCurrentSequence()); - base::FilePath usage_file_path = GetUsageCachePath(url); - if (usage_file_path.empty()) + base::FileErrorOr<base::FilePath> usage_file_path = GetUsageCachePath(url); + if (usage_file_path.is_error() || usage_file_path->empty()) return; - auto found = pending_update_notification_.find(usage_file_path); + auto found = pending_update_notification_.find(usage_file_path.value()); if (found != pending_update_notification_.end()) { UpdateUsageCacheFile(found->first, found->second); pending_update_notification_.erase(found); } - file_system_usage_cache_->DecrementDirty(usage_file_path); + file_system_usage_cache_->DecrementDirty(usage_file_path.value()); } void SandboxQuotaObserver::OnAccess(const FileSystemURL& url) { @@ -97,22 +98,20 @@ void SandboxQuotaObserver::SetUsageCacheEnabled(const url::Origin& origin, } } -base::FilePath SandboxQuotaObserver::GetUsageCachePath( +base::FileErrorOr<base::FilePath> SandboxQuotaObserver::GetUsageCachePath( const FileSystemURL& url) { DCHECK(sandbox_file_util_); - base::File::Error error = base::File::FILE_OK; - base::FilePath path; + base::FileErrorOr<base::FilePath> path = base::FilePath(); if (url.bucket().has_value()) { path = SandboxFileSystemBackendDelegate::GetUsageCachePathForBucketAndType( - sandbox_file_util_, url.bucket().value(), url.type(), &error); + sandbox_file_util_, url.bucket().value(), url.type()); } else { path = SandboxFileSystemBackendDelegate::GetUsageCachePathForStorageKeyAndType( - sandbox_file_util_, url.storage_key(), url.type(), &error); + sandbox_file_util_, url.storage_key(), url.type()); } - if (error != base::File::FILE_OK) { + if (path.is_error()) { LOG(WARNING) << "Could not get usage cache path for: " << url.DebugString(); - return base::FilePath(); } return path; } diff --git a/chromium/storage/browser/file_system/sandbox_quota_observer.h b/chromium/storage/browser/file_system/sandbox_quota_observer.h index 59be57fbb44..3231d1a7eb3 100644 --- a/chromium/storage/browser/file_system/sandbox_quota_observer.h +++ b/chromium/storage/browser/file_system/sandbox_quota_observer.h @@ -10,6 +10,7 @@ #include <map> #include "base/compiler_specific.h" +#include "base/files/file_error_or.h" #include "base/files/file_path.h" #include "base/memory/raw_ptr.h" #include "base/memory/ref_counted.h" @@ -65,7 +66,7 @@ class SandboxQuotaObserver : public FileUpdateObserver, void UpdateUsageCacheFile(const base::FilePath& usage_file_path, int64_t delta); - base::FilePath GetUsageCachePath(const FileSystemURL& url); + base::FileErrorOr<base::FilePath> GetUsageCachePath(const FileSystemURL& url); const scoped_refptr<QuotaManagerProxy> quota_manager_proxy_; const scoped_refptr<base::SequencedTaskRunner> update_notify_runner_; diff --git a/chromium/storage/browser/quota/OWNERS b/chromium/storage/browser/quota/OWNERS index 22981a38b9a..97011b2f221 100644 --- a/chromium/storage/browser/quota/OWNERS +++ b/chromium/storage/browser/quota/OWNERS @@ -4,7 +4,6 @@ ayui@chromium.org # Secondary asully@chromium.org estade@chromium.org -jarrydg@chromium.org jsbell@chromium.org per-file *.mojom=set noparent diff --git a/chromium/storage/browser/quota/README.md b/chromium/storage/browser/quota/README.md index c94d182ac3c..7997cdf5c8c 100644 --- a/chromium/storage/browser/quota/README.md +++ b/chromium/storage/browser/quota/README.md @@ -51,7 +51,7 @@ Storage Buckets. The currently stored information is a usage count, last-modified-time, and last-accessed-time for each origin (used to implement LRU eviction on storage pressure, and Clear Site Data with a time filter), and quota granted via the deprecated API -webkitStorageInfo.requestQuota(PERSISTENT,...). +navigator.webkitPersistentStorage.requestQuota(1000, ...). ### QuotaTemporaryStorageEvictor Handles eviction and records stats about eviction rounds. diff --git a/chromium/storage/browser/quota/quota_database.cc b/chromium/storage/browser/quota/quota_database.cc index fd8b3b8262f..792b909cc94 100644 --- a/chromium/storage/browser/quota/quota_database.cc +++ b/chromium/storage/browser/quota/quota_database.cc @@ -27,6 +27,7 @@ #include "sql/statement.h" #include "sql/transaction.h" #include "storage/browser/quota/quota_database_migrations.h" +#include "storage/browser/quota/quota_internals.mojom.h" #include "storage/browser/quota/special_storage_policy.h" #include "url/gurl.h" @@ -104,6 +105,25 @@ void BindBucketInitParamsToInsertStatement(const BucketInitParams& params, statement.BindInt(10, durability); } +// Fields to be retrieved from the database and stored in a +// `BucketTableEntryPtr`. +#define BUCKET_TABLE_ENTRY_FIELDS_SELECTOR \ + "id, storage_key, type, name, use_count, last_accessed, last_modified " + +mojom::BucketTableEntryPtr BucketTableEntryFromSqlStatement( + sql::Statement& statement) { + mojom::BucketTableEntryPtr entry = mojom::BucketTableEntry::New(); + entry->bucket_id = statement.ColumnInt64(0); + entry->storage_key = statement.ColumnString(1); + entry->type = + static_cast<storage::mojom::StorageType>(statement.ColumnInt(2)); + entry->name = statement.ColumnString(3); + entry->use_count = statement.ColumnInt(4); + entry->last_accessed = statement.ColumnTime(5); + entry->last_modified = statement.ColumnTime(6); + return entry; +} + // Fields to be retrieved from the database and stored in a `BucketInfo`. #define BUCKET_INFO_FIELDS_SELECTOR \ " id, storage_key, type, name, expiration, quota, persistent, durability " @@ -127,6 +147,16 @@ QuotaErrorOr<BucketInfo> BucketInfoFromSqlStatement(sql::Statement& statement) { static_cast<blink::mojom::BucketDurability>(statement.ColumnInt(7))); } +std::set<BucketInfo> BucketInfosFromSqlStatement(sql::Statement& statement) { + std::set<BucketInfo> result; + QuotaErrorOr<BucketInfo> bucket; + while ((bucket = BucketInfoFromSqlStatement(statement)).ok()) { + result.insert(bucket.value()); + } + + return result; +} + } // anonymous namespace const QuotaDatabase::TableSchema QuotaDatabase::kTables[] = { @@ -162,31 +192,6 @@ const QuotaDatabase::IndexSchema QuotaDatabase::kIndexes[] = { }; const size_t QuotaDatabase::kIndexCount = std::size(QuotaDatabase::kIndexes); -QuotaDatabase::BucketTableEntry::BucketTableEntry() = default; - -QuotaDatabase::BucketTableEntry::~BucketTableEntry() = default; - -QuotaDatabase::BucketTableEntry::BucketTableEntry(const BucketTableEntry&) = - default; -QuotaDatabase::BucketTableEntry& QuotaDatabase::BucketTableEntry::operator=( - const QuotaDatabase::BucketTableEntry&) = default; - -QuotaDatabase::BucketTableEntry::BucketTableEntry( - BucketId bucket_id, - StorageKey storage_key, - StorageType type, - std::string name, - int use_count, - const base::Time& last_accessed, - const base::Time& last_modified) - : bucket_id(std::move(bucket_id)), - storage_key(std::move(storage_key)), - type(type), - name(std::move(name)), - use_count(use_count), - last_accessed(last_accessed), - last_modified(last_modified) {} - // QuotaDatabase ------------------------------------------------------------ QuotaDatabase::QuotaDatabase(const base::FilePath& profile_path) : storage_directory_( @@ -410,7 +415,7 @@ QuotaErrorOr<BucketInfo> QuotaDatabase::GetBucketById(BucketId bucket_id) { return BucketInfoFromSqlStatement(statement); } -QuotaErrorOr<std::set<BucketLocator>> QuotaDatabase::GetBucketsForType( +QuotaErrorOr<std::set<BucketInfo>> QuotaDatabase::GetBucketsForType( StorageType type) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); QuotaError open_error = EnsureOpened(); @@ -418,53 +423,39 @@ QuotaErrorOr<std::set<BucketLocator>> QuotaDatabase::GetBucketsForType( return open_error; static constexpr char kSql[] = - "SELECT id, storage_key, name FROM buckets WHERE type = ?"; - + // clang-format off + "SELECT " BUCKET_INFO_FIELDS_SELECTOR + "FROM buckets " + "WHERE type = ?"; + // clang-format on sql::Statement statement(db_->GetCachedStatement(SQL_FROM_HERE, kSql)); statement.BindInt(0, static_cast<int>(type)); - std::set<BucketLocator> buckets; - while (statement.Step()) { - absl::optional<StorageKey> read_storage_key = - StorageKey::Deserialize(statement.ColumnString(1)); - if (!read_storage_key.has_value()) - continue; - buckets.emplace(BucketId(statement.ColumnInt64(0)), - read_storage_key.value(), type, - statement.ColumnString(2) == kDefaultBucketName); - } - return buckets; + return BucketInfosFromSqlStatement(statement); } -QuotaErrorOr<std::set<BucketLocator>> QuotaDatabase::GetBucketsForHost( +QuotaErrorOr<std::set<BucketInfo>> QuotaDatabase::GetBucketsForHost( const std::string& host, - blink::mojom::StorageType storage_type) { + StorageType type) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); QuotaError open_error = EnsureOpened(); if (open_error != QuotaError::kNone) return open_error; static constexpr char kSql[] = - "SELECT id, storage_key, name FROM buckets WHERE host = ? AND type = ?"; - + // clang-format off + "SELECT " BUCKET_INFO_FIELDS_SELECTOR + "FROM buckets " + "WHERE host = ? AND type = ?"; + // clang-format on sql::Statement statement(db_->GetCachedStatement(SQL_FROM_HERE, kSql)); statement.BindString(0, host); - statement.BindInt(1, static_cast<int>(storage_type)); + statement.BindInt(1, static_cast<int>(type)); - std::set<BucketLocator> buckets; - while (statement.Step()) { - absl::optional<StorageKey> read_storage_key = - StorageKey::Deserialize(statement.ColumnString(1)); - if (!read_storage_key.has_value()) - continue; - buckets.emplace(BucketId(statement.ColumnInt64(0)), - read_storage_key.value(), storage_type, - statement.ColumnString(2) == kDefaultBucketName); - } - return buckets; + return BucketInfosFromSqlStatement(statement); } -QuotaErrorOr<std::set<BucketLocator>> QuotaDatabase::GetBucketsForStorageKey( +QuotaErrorOr<std::set<BucketInfo>> QuotaDatabase::GetBucketsForStorageKey( const StorageKey& storage_key, StorageType type) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); @@ -473,18 +464,16 @@ QuotaErrorOr<std::set<BucketLocator>> QuotaDatabase::GetBucketsForStorageKey( return open_error; static constexpr char kSql[] = - "SELECT id, name FROM buckets WHERE storage_key = ? AND type = ?"; - + // clang-format off + "SELECT " BUCKET_INFO_FIELDS_SELECTOR + "FROM buckets " + "WHERE storage_key = ? AND type = ?"; + // clang-format on sql::Statement statement(db_->GetCachedStatement(SQL_FROM_HERE, kSql)); statement.BindString(0, storage_key.Serialize()); statement.BindInt(1, static_cast<int>(type)); - std::set<BucketLocator> buckets; - while (statement.Step()) { - buckets.emplace(BucketId(statement.ColumnInt64(0)), storage_key, type, - statement.ColumnString(1) == kDefaultBucketName); - } - return buckets; + return BucketInfosFromSqlStatement(statement); } QuotaError QuotaDatabase::SetStorageKeyLastAccessTime( @@ -589,7 +578,7 @@ QuotaError QuotaDatabase::RegisterInitialStorageKeyInfo( return QuotaError::kNone; } -QuotaErrorOr<QuotaDatabase::BucketTableEntry> QuotaDatabase::GetBucketInfo( +QuotaErrorOr<mojom::BucketTableEntryPtr> QuotaDatabase::GetBucketInfo( BucketId bucket_id) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK(!bucket_id.is_null()); @@ -599,13 +588,7 @@ QuotaErrorOr<QuotaDatabase::BucketTableEntry> QuotaDatabase::GetBucketInfo( static constexpr char kSql[] = // clang-format off - "SELECT " - "storage_key," - "type," - "name," - "use_count," - "last_accessed," - "last_modified " + "SELECT " BUCKET_TABLE_ENTRY_FIELDS_SELECTOR "FROM buckets " "WHERE id = ?"; // clang-format on @@ -618,14 +601,13 @@ QuotaErrorOr<QuotaDatabase::BucketTableEntry> QuotaDatabase::GetBucketInfo( } absl::optional<StorageKey> storage_key = - StorageKey::Deserialize(statement.ColumnString(0)); + StorageKey::Deserialize(statement.ColumnString(1)); if (!storage_key.has_value()) return QuotaError::kNotFound; - return BucketTableEntry(bucket_id, std::move(storage_key).value(), - static_cast<StorageType>(statement.ColumnInt(1)), - statement.ColumnString(2), statement.ColumnInt(3), - statement.ColumnTime(4), statement.ColumnTime(5)); + mojom::BucketTableEntryPtr entry = + BucketTableEntryFromSqlStatement(statement); + return entry; } QuotaError QuotaDatabase::DeleteHostQuota(const std::string& host, @@ -874,6 +856,10 @@ void QuotaDatabase::SetClockForTesting(base::Clock* clock) { g_clock_for_testing = clock; } +void QuotaDatabase::CommitNow() { + Commit(); +} + void QuotaDatabase::Commit() { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); if (!db_) @@ -1142,30 +1128,20 @@ QuotaError QuotaDatabase::DumpBucketTable(const BucketTableCallback& callback) { static constexpr char kSql[] = // clang-format off - "SELECT " - "id," - "storage_key," - "type," - "name," - "use_count," - "last_accessed," - "last_modified " + "SELECT " BUCKET_TABLE_ENTRY_FIELDS_SELECTOR "FROM buckets"; // clang-format on sql::Statement statement(db_->GetCachedStatement(SQL_FROM_HERE, kSql)); while (statement.Step()) { - BucketId bucket_id = BucketId(statement.ColumnInt64(0)); absl::optional<StorageKey> storage_key = StorageKey::Deserialize(statement.ColumnString(1)); if (!storage_key.has_value()) continue; - BucketTableEntry entry(std::move(bucket_id), std::move(storage_key).value(), - static_cast<StorageType>(statement.ColumnInt(2)), - statement.ColumnString(3), statement.ColumnInt(4), - statement.ColumnTime(5), statement.ColumnTime(6)); - if (!callback.Run(entry)) + auto entry = BucketTableEntryFromSqlStatement(statement); + + if (!callback.Run(std::move(entry))) return QuotaError::kNone; } return statement.Succeeded() ? QuotaError::kNone : QuotaError::kDatabaseError; @@ -1204,10 +1180,4 @@ QuotaErrorOr<BucketInfo> QuotaDatabase::CreateBucketInternal( return result; } -bool operator<(const QuotaDatabase::BucketTableEntry& lhs, - const QuotaDatabase::BucketTableEntry& rhs) { - return std::tie(lhs.storage_key, lhs.type, lhs.use_count, lhs.last_accessed) < - std::tie(rhs.storage_key, rhs.type, rhs.use_count, rhs.last_accessed); -} - } // namespace storage diff --git a/chromium/storage/browser/quota/quota_database.h b/chromium/storage/browser/quota/quota_database.h index 9f5f365c7fa..0bdbe80735d 100644 --- a/chromium/storage/browser/quota/quota_database.h +++ b/chromium/storage/browser/quota/quota_database.h @@ -26,6 +26,7 @@ #include "components/services/storage/public/cpp/buckets/bucket_locator.h" #include "components/services/storage/public/cpp/buckets/constants.h" #include "components/services/storage/public/cpp/quota_error_or.h" +#include "storage/browser/quota/quota_internals.mojom-forward.h" #include "storage/browser/quota/storage_directory.h" #include "third_party/abseil-cpp/absl/types/optional.h" #include "third_party/blink/public/common/storage_key/storage_key.h" @@ -38,7 +39,7 @@ class Clock; namespace sql { class Database; class MetaTable; -} +} // namespace sql namespace storage { @@ -65,34 +66,6 @@ enum class DatabaseResetReason { // constructor, must called on the DB thread. class COMPONENT_EXPORT(STORAGE_BROWSER) QuotaDatabase { public: - struct COMPONENT_EXPORT(STORAGE_BROWSER) BucketTableEntry { - BucketTableEntry(); - BucketTableEntry(BucketId bucket_id, - blink::StorageKey storage_key, - blink::mojom::StorageType type, - std::string name, - int use_count, - const base::Time& last_accessed, - const base::Time& last_modified); - ~BucketTableEntry(); - - BucketTableEntry(const BucketTableEntry&); - BucketTableEntry& operator=(const BucketTableEntry&); - - BucketLocator ToBucketLocator() const { - return BucketLocator(bucket_id, storage_key, type, - name == kDefaultBucketName); - } - - BucketId bucket_id; - blink::StorageKey storage_key; - blink::mojom::StorageType type = blink::mojom::StorageType::kUnknown; - std::string name; - int use_count = 0; - base::Time last_accessed; - base::Time last_modified; - }; - static constexpr char kDatabaseName[] = "QuotaManager"; // If `profile_path` is empty, an in-memory database will be used. @@ -153,18 +126,18 @@ class COMPONENT_EXPORT(STORAGE_BROWSER) QuotaDatabase { // Returns all buckets for `type` in the buckets table. Returns a QuotaError // if the operation has failed. - QuotaErrorOr<std::set<BucketLocator>> GetBucketsForType( + QuotaErrorOr<std::set<BucketInfo>> GetBucketsForType( blink::mojom::StorageType type); // Retrieves all buckets for `host` and `type`. Returns a QuotaError if the // operation has failed. - QuotaErrorOr<std::set<BucketLocator>> GetBucketsForHost( + QuotaErrorOr<std::set<BucketInfo>> GetBucketsForHost( const std::string& host, blink::mojom::StorageType type); // Returns all buckets for `storage_key` in the buckets table. Returns a // QuotaError if the operation has failed. - QuotaErrorOr<std::set<BucketLocator>> GetBucketsForStorageKey( + QuotaErrorOr<std::set<BucketInfo>> GetBucketsForStorageKey( const blink::StorageKey& storage_key, blink::mojom::StorageType type); @@ -203,7 +176,7 @@ class COMPONENT_EXPORT(STORAGE_BROWSER) QuotaDatabase { // Returns the BucketTableEntry for `bucket` if one exists. Returns a // QuotaError if not found or the operation has failed. - QuotaErrorOr<BucketTableEntry> GetBucketInfo(BucketId bucket_id); + QuotaErrorOr<mojom::BucketTableEntryPtr> GetBucketInfo(BucketId bucket_id); // Deletes the bucket from the database as well as the bucket directory in the // storage directory. @@ -242,6 +215,9 @@ class COMPONENT_EXPORT(STORAGE_BROWSER) QuotaDatabase { // one doesn't exist. QuotaError RazeAndReopen(); + // Flushes previously scheduled commits. + void CommitNow(); + // Testing support for database corruption handling. // // Runs `corrupter` on the same sequence used to do database I/O, @@ -273,9 +249,6 @@ class COMPONENT_EXPORT(STORAGE_BROWSER) QuotaDatabase { friend COMPONENT_EXPORT(STORAGE_BROWSER) bool operator<( const QuotaTableEntry& lhs, const QuotaTableEntry& rhs); - friend COMPONENT_EXPORT(STORAGE_BROWSER) bool operator<( - const BucketTableEntry& lhs, - const BucketTableEntry& rhs); // Structures used for CreateSchema. struct TableSchema { @@ -292,7 +265,7 @@ class COMPONENT_EXPORT(STORAGE_BROWSER) QuotaDatabase { using QuotaTableCallback = base::RepeatingCallback<bool(const QuotaTableEntry&)>; using BucketTableCallback = - base::RepeatingCallback<bool(const BucketTableEntry&)>; + base::RepeatingCallback<bool(mojom::BucketTableEntryPtr)>; // For long-running transactions support. We always keep a transaction open // so that multiple transactions can be batched. They are flushed diff --git a/chromium/storage/browser/quota/quota_database_unittest.cc b/chromium/storage/browser/quota/quota_database_unittest.cc index 11ba7b3edea..bc6b36ad493 100644 --- a/chromium/storage/browser/quota/quota_database_unittest.cc +++ b/chromium/storage/browser/quota/quota_database_unittest.cc @@ -32,6 +32,7 @@ #include "sql/test/test_helpers.h" #include "storage/browser/quota/quota_client_type.h" #include "storage/browser/quota/quota_database.h" +#include "storage/browser/quota/quota_internals.mojom.h" #include "storage/browser/quota/storage_directory_util.h" #include "storage/browser/test/mock_special_storage_policy.h" #include "testing/gtest/include/gtest/gtest.h" @@ -50,6 +51,11 @@ static const blink::mojom::StorageType kTemp = static const blink::mojom::StorageType kPerm = blink::mojom::StorageType::kPersistent; +static const storage::mojom::StorageType kStorageTemp = + storage::mojom::StorageType::kTemporary; +static const storage::mojom::StorageType kStoragePerm = + storage::mojom::StorageType::kPersistent; + static constexpr char kDatabaseName[] = "QuotaManager"; bool ContainsBucket(const std::set<BucketLocator>& buckets, @@ -64,7 +70,7 @@ bool ContainsBucket(const std::set<BucketLocator>& buckets, // mode. True will create the database in memory. class QuotaDatabaseTest : public testing::TestWithParam<bool> { protected: - using BucketTableEntry = QuotaDatabase::BucketTableEntry; + using BucketTableEntry = mojom::BucketTableEntry; void SetUp() override { ASSERT_TRUE(temp_directory_.CreateUniqueTempDir()); } @@ -93,12 +99,15 @@ class QuotaDatabaseTest : public testing::TestWithParam<bool> { struct EntryVerifier { std::set<EntryType> table; - template <typename Iterator> - EntryVerifier(Iterator itr, Iterator end) - : table(itr, end) {} + template <size_t length> + explicit EntryVerifier(const EntryType (&entries)[length]) { + for (size_t i = 0; i < length; ++i) { + table.insert(entries[i]->Clone()); + } + } - bool Run(const EntryType& entry) { - EXPECT_EQ(1u, table.erase(entry)); + bool Run(EntryType entry) { + EXPECT_EQ(1u, table.erase(std::move(entry))); return true; } }; @@ -163,14 +172,18 @@ class QuotaDatabaseTest : public testing::TestWithParam<bool> { quota_database->db_->GetCachedStatement(SQL_FROM_HERE, kSql)); ASSERT_TRUE(statement.is_valid()); - statement.BindInt64(0, entry.bucket_id.value()); - statement.BindString(1, entry.storage_key.Serialize()); - statement.BindString(2, entry.storage_key.origin().host()); - statement.BindInt(3, static_cast<int>(entry.type)); - statement.BindString(4, entry.name); - statement.BindInt(5, entry.use_count); - statement.BindTime(6, entry.last_accessed); - statement.BindTime(7, entry.last_modified); + absl::optional<StorageKey> storage_key = + StorageKey::Deserialize(entry->storage_key); + ASSERT_TRUE(storage_key.has_value()); + + statement.BindInt64(0, entry->bucket_id); + statement.BindString(1, entry->storage_key); + statement.BindString(2, std::move(storage_key).value().origin().host()); + statement.BindInt(3, static_cast<int>(entry->type)); + statement.BindString(4, entry->name); + statement.BindInt(5, static_cast<int>(entry->use_count)); + statement.BindTime(6, entry->last_accessed); + statement.BindTime(7, entry->last_modified); EXPECT_TRUE(statement.Run()); } quota_database->Commit(); @@ -459,16 +472,16 @@ TEST_P(QuotaDatabaseTest, GetBucketsForType) { ASSERT_TRUE(bucket_result.ok()); BucketInfo perm_bucket2 = bucket_result.value(); - QuotaErrorOr<std::set<BucketLocator>> result = db->GetBucketsForType(kTemp); + QuotaErrorOr<std::set<BucketInfo>> result = db->GetBucketsForType(kTemp); ASSERT_TRUE(result.ok()); - std::set<BucketLocator> buckets = result.value(); + std::set<BucketLocator> buckets = BucketInfosToBucketLocators(result.value()); ASSERT_EQ(2U, buckets.size()); EXPECT_TRUE(ContainsBucket(buckets, temp_bucket1)); EXPECT_TRUE(ContainsBucket(buckets, temp_bucket2)); result = db->GetBucketsForType(kPerm); ASSERT_TRUE(result.ok()); - buckets = result.value(); + buckets = BucketInfosToBucketLocators(result.value()); ASSERT_EQ(2U, buckets.size()); EXPECT_TRUE(ContainsBucket(buckets, perm_bucket1)); EXPECT_TRUE(ContainsBucket(buckets, perm_bucket2)); @@ -491,12 +504,12 @@ TEST_P(QuotaDatabaseTest, GetBucketsForHost) { StorageKey::CreateFromStringForTesting("http://google.com:123/"), "default", kTemp); - QuotaErrorOr<std::set<BucketLocator>> result = + QuotaErrorOr<std::set<BucketInfo>> result = db->GetBucketsForHost("example.com", kTemp); ASSERT_TRUE(result.ok()); ASSERT_EQ(result->size(), 2U); - EXPECT_TRUE(ContainsBucket(result.value(), temp_example_bucket1.value())); - EXPECT_TRUE(ContainsBucket(result.value(), temp_example_bucket2.value())); + EXPECT_TRUE(base::Contains(result.value(), temp_example_bucket1.value())); + EXPECT_TRUE(base::Contains(result.value(), temp_example_bucket2.value())); result = db->GetBucketsForHost("example.com", kPerm); ASSERT_TRUE(result.ok()); @@ -505,12 +518,12 @@ TEST_P(QuotaDatabaseTest, GetBucketsForHost) { result = db->GetBucketsForHost("google.com", kPerm); ASSERT_TRUE(result.ok()); ASSERT_EQ(result->size(), 1U); - EXPECT_TRUE(ContainsBucket(result.value(), perm_google_bucket1.value())); + EXPECT_TRUE(base::Contains(result.value(), perm_google_bucket1.value())); result = db->GetBucketsForHost("google.com", kTemp); ASSERT_TRUE(result.ok()); ASSERT_EQ(result->size(), 1U); - EXPECT_TRUE(ContainsBucket(result.value(), temp_google_bucket2.value())); + EXPECT_TRUE(base::Contains(result.value(), temp_google_bucket2.value())); } TEST_P(QuotaDatabaseTest, GetBucketsForStorageKey) { @@ -539,17 +552,17 @@ TEST_P(QuotaDatabaseTest, GetBucketsForStorageKey) { ASSERT_TRUE(bucket_result.ok()); BucketInfo perm_bucket2 = bucket_result.value(); - QuotaErrorOr<std::set<BucketLocator>> result = + QuotaErrorOr<std::set<BucketInfo>> result = db->GetBucketsForStorageKey(storage_key1, kTemp); ASSERT_TRUE(result.ok()); - std::set<BucketLocator> buckets = result.value(); + std::set<BucketLocator> buckets = BucketInfosToBucketLocators(result.value()); ASSERT_EQ(2U, buckets.size()); EXPECT_TRUE(ContainsBucket(buckets, temp_bucket1)); EXPECT_TRUE(ContainsBucket(buckets, temp_bucket2)); result = db->GetBucketsForStorageKey(storage_key2, kPerm); ASSERT_TRUE(result.ok()); - buckets = result.value(); + buckets = BucketInfosToBucketLocators(result.value()); ASSERT_EQ(1U, buckets.size()); EXPECT_TRUE(ContainsBucket(buckets, perm_bucket2)); } @@ -566,37 +579,52 @@ TEST_P(QuotaDatabaseTest, BucketLastAccessTimeLRU) { // Insert bucket entries into BucketTable. base::Time now = base::Time::Now(); - using Entry = QuotaDatabase::BucketTableEntry; - Entry bucket1 = Entry( - BucketId(1), StorageKey::CreateFromStringForTesting("http://example-a/"), - kTemp, kDefaultBucketName, 99, now, now); - Entry bucket2 = Entry( - BucketId(2), StorageKey::CreateFromStringForTesting("http://example-b/"), - kTemp, kDefaultBucketName, 0, now, now); - Entry bucket3 = Entry( - BucketId(3), StorageKey::CreateFromStringForTesting("http://example-c/"), - kTemp, "bucket_c", 1, now, now); - Entry bucket4 = Entry( - BucketId(4), StorageKey::CreateFromStringForTesting("http://example-d/"), - kPerm, "bucket_d", 5, now, now); - Entry kTableEntries[] = {bucket1, bucket2, bucket3, bucket4}; + using Entry = mojom::BucketTableEntryPtr; + StorageKey storage_key1 = + StorageKey::CreateFromStringForTesting("http://example-a/"); + StorageKey storage_key2 = + StorageKey::CreateFromStringForTesting("http://example-b/"); + StorageKey storage_key3 = + StorageKey::CreateFromStringForTesting("http://example-c/"); + StorageKey storage_key4 = + StorageKey::CreateFromStringForTesting("http://example-d/"); + + BucketId bucket_id1 = BucketId(1); + BucketId bucket_id2 = BucketId(2); + BucketId bucket_id3 = BucketId(3); + BucketId bucket_id4 = BucketId(4); + + Entry bucket1 = mojom::BucketTableEntry::New( + bucket_id1.value(), storage_key1.Serialize(), kStorageTemp, + kDefaultBucketName, -1, 99, now, now); + Entry bucket2 = mojom::BucketTableEntry::New( + bucket_id2.value(), storage_key2.Serialize(), kStorageTemp, + kDefaultBucketName, -1, 0, now, now); + Entry bucket3 = + mojom::BucketTableEntry::New(bucket_id3.value(), storage_key3.Serialize(), + kStorageTemp, "bucket_c", -1, 1, now, now); + Entry bucket4 = + mojom::BucketTableEntry::New(bucket_id4.value(), storage_key4.Serialize(), + kStoragePerm, "bucket_d", -1, 5, now, now); + Entry kTableEntries[] = {bucket1->Clone(), bucket2->Clone(), bucket3->Clone(), + bucket4->Clone()}; AssignBucketTable(db.get(), kTableEntries); // Update access time for three temporary storages, and - EXPECT_EQ(db->SetBucketLastAccessTime(bucket1.bucket_id, - base::Time::FromJavaTime(10)), - QuotaError::kNone); - EXPECT_EQ(db->SetBucketLastAccessTime(bucket2.bucket_id, - base::Time::FromJavaTime(20)), - QuotaError::kNone); - EXPECT_EQ(db->SetBucketLastAccessTime(bucket3.bucket_id, - base::Time::FromJavaTime(30)), - QuotaError::kNone); + EXPECT_EQ( + db->SetBucketLastAccessTime(bucket_id1, base::Time::FromJavaTime(10)), + QuotaError::kNone); + EXPECT_EQ( + db->SetBucketLastAccessTime(bucket_id2, base::Time::FromJavaTime(20)), + QuotaError::kNone); + EXPECT_EQ( + db->SetBucketLastAccessTime(bucket_id3, base::Time::FromJavaTime(30)), + QuotaError::kNone); // One persistent. - EXPECT_EQ(db->SetBucketLastAccessTime(bucket4.bucket_id, - base::Time::FromJavaTime(40)), - QuotaError::kNone); + EXPECT_EQ( + db->SetBucketLastAccessTime(bucket_id4, base::Time::FromJavaTime(40)), + QuotaError::kNone); // One non-existent. EXPECT_EQ( @@ -605,53 +633,58 @@ TEST_P(QuotaDatabaseTest, BucketLastAccessTimeLRU) { result = db->GetLruEvictableBucket(kTemp, bucket_exceptions, nullptr); EXPECT_TRUE(result.ok()); - EXPECT_EQ(bucket1.bucket_id, result.value().id); + EXPECT_EQ(bucket_id1, result.value().id); // Test that unlimited origins are excluded from eviction, but // protected origins are not excluded. auto policy = base::MakeRefCounted<MockSpecialStoragePolicy>(); - policy->AddUnlimited(bucket1.storage_key.origin().GetURL()); - policy->AddProtected(bucket2.storage_key.origin().GetURL()); + policy->AddUnlimited(storage_key1.origin().GetURL()); + policy->AddProtected(storage_key2.origin().GetURL()); result = db->GetLruEvictableBucket(kTemp, bucket_exceptions, policy.get()); EXPECT_TRUE(result.ok()); - EXPECT_EQ(bucket2.bucket_id, result.value().id); + EXPECT_EQ(bucket_id2, result.value().id); // Test that durable origins are excluded from eviction. - policy->AddDurable(bucket2.storage_key.origin().GetURL()); + policy->AddDurable(storage_key2.origin().GetURL()); result = db->GetLruEvictableBucket(kTemp, bucket_exceptions, policy.get()); EXPECT_TRUE(result.ok()); - EXPECT_EQ(bucket3.bucket_id, result.value().id); + EXPECT_EQ(bucket_id3, result.value().id); // Bucket exceptions exclude specified buckets. - bucket_exceptions.insert(bucket1.bucket_id); + bucket_exceptions.insert(bucket_id1); result = db->GetLruEvictableBucket(kTemp, bucket_exceptions, nullptr); EXPECT_TRUE(result.ok()); - EXPECT_EQ(bucket2.bucket_id, result.value().id); + EXPECT_EQ(bucket_id2, result.value().id); - bucket_exceptions.insert(bucket2.bucket_id); + bucket_exceptions.insert(bucket_id2); result = db->GetLruEvictableBucket(kTemp, bucket_exceptions, nullptr); EXPECT_TRUE(result.ok()); - EXPECT_EQ(bucket3.bucket_id, result.value().id); + EXPECT_EQ(bucket_id3, result.value().id); - bucket_exceptions.insert(bucket3.bucket_id); + bucket_exceptions.insert(bucket_id3); result = db->GetLruEvictableBucket(kTemp, bucket_exceptions, nullptr); EXPECT_FALSE(result.ok()); EXPECT_EQ(result.error(), QuotaError::kNotFound); - EXPECT_EQ(db->SetBucketLastAccessTime(bucket1.bucket_id, base::Time::Now()), + EXPECT_EQ(db->SetBucketLastAccessTime(bucket_id1, base::Time::Now()), QuotaError::kNone); + BucketLocator bucketLocator = + BucketLocator(bucket_id3, storage_key3, + static_cast<blink::mojom::StorageType>(bucket3->type), + bucket3->name == kDefaultBucketName); + // Delete storage_key/type last access time information. - EXPECT_EQ(db->DeleteBucketData(bucket3.ToBucketLocator()), QuotaError::kNone); + EXPECT_EQ(db->DeleteBucketData(bucketLocator), QuotaError::kNone); // Querying again to see if the deletion has worked. bucket_exceptions.clear(); result = db->GetLruEvictableBucket(kTemp, bucket_exceptions, nullptr); EXPECT_TRUE(result.ok()); - EXPECT_EQ(bucket2.bucket_id, result.value().id); + EXPECT_EQ(bucket_id2, result.value().id); - bucket_exceptions.insert(bucket1.bucket_id); - bucket_exceptions.insert(bucket2.bucket_id); + bucket_exceptions.insert(bucket_id1); + bucket_exceptions.insert(bucket_id2); result = db->GetLruEvictableBucket(kTemp, bucket_exceptions, nullptr); EXPECT_FALSE(result.ok()); EXPECT_EQ(result.error(), QuotaError::kNotFound); @@ -669,31 +702,40 @@ TEST_P(QuotaDatabaseTest, BucketPersistence) { // Insert bucket entries into BucketTable. base::Time now = base::Time::Now(); - using Entry = QuotaDatabase::BucketTableEntry; - Entry bucket1 = Entry( - BucketId(1), StorageKey::CreateFromStringForTesting("http://example-a/"), - kTemp, kDefaultBucketName, 99, now, now); - Entry bucket2 = Entry( - BucketId(2), StorageKey::CreateFromStringForTesting("http://example-b/"), - kTemp, kDefaultBucketName, 0, now, now); - Entry kTableEntries[] = {bucket1, bucket2}; + using Entry = mojom::BucketTableEntryPtr; + + StorageKey storage_key1 = + StorageKey::CreateFromStringForTesting("http://example-a/"); + StorageKey storage_key2 = + StorageKey::CreateFromStringForTesting("http://example-b/"); + + BucketId bucket_id1 = BucketId(1); + BucketId bucket_id2 = BucketId(2); + + Entry bucket1 = mojom::BucketTableEntry::New( + bucket_id1.value(), storage_key1.Serialize(), kStorageTemp, + kDefaultBucketName, -1, 99, now, now); + Entry bucket2 = mojom::BucketTableEntry::New( + bucket_id2.value(), storage_key2.Serialize(), kStorageTemp, + kDefaultBucketName, -1, 0, now, now); + Entry kTableEntries[] = {bucket1->Clone(), bucket2->Clone()}; AssignBucketTable(db.get(), kTableEntries); - EXPECT_EQ(db->SetBucketLastAccessTime(bucket1.bucket_id, - base::Time::FromJavaTime(10)), - QuotaError::kNone); - EXPECT_EQ(db->SetBucketLastAccessTime(bucket2.bucket_id, - base::Time::FromJavaTime(20)), - QuotaError::kNone); + EXPECT_EQ( + db->SetBucketLastAccessTime(bucket_id1, base::Time::FromJavaTime(10)), + QuotaError::kNone); + EXPECT_EQ( + db->SetBucketLastAccessTime(bucket_id2, base::Time::FromJavaTime(20)), + QuotaError::kNone); result = db->GetLruEvictableBucket(kTemp, bucket_exceptions, nullptr); EXPECT_TRUE(result.ok()); - EXPECT_EQ(bucket1.bucket_id, result.value().id); + EXPECT_EQ(bucket_id1, result.value().id); - ASSERT_TRUE(db->UpdateBucketPersistence(bucket1.bucket_id, true).ok()); + ASSERT_TRUE(db->UpdateBucketPersistence(bucket_id1, true).ok()); result = db->GetLruEvictableBucket(kTemp, bucket_exceptions, nullptr); EXPECT_TRUE(result.ok()); - EXPECT_EQ(bucket2.bucket_id, result.value().id); + EXPECT_EQ(bucket_id2, result.value().id); } TEST_P(QuotaDatabaseTest, SetStorageKeyLastAccessTime) { @@ -714,11 +756,10 @@ TEST_P(QuotaDatabaseTest, SetStorageKeyLastAccessTime) { EXPECT_EQ(db->SetStorageKeyLastAccessTime(storage_key, kTemp, now), QuotaError::kNone); - QuotaErrorOr<QuotaDatabase::BucketTableEntry> info = - db->GetBucketInfo(bucket->id); + QuotaErrorOr<mojom::BucketTableEntryPtr> info = db->GetBucketInfo(bucket->id); EXPECT_TRUE(info.ok()); - EXPECT_EQ(now, info->last_accessed); - EXPECT_EQ(1, info->use_count); + EXPECT_EQ(now, info.value()->last_accessed); + EXPECT_EQ(1, info.value()->use_count); } TEST_P(QuotaDatabaseTest, GetStorageKeysForType) { @@ -889,10 +930,10 @@ TEST_P(QuotaDatabaseTest, RegisterInitialStorageKeyInfo) { kDefaultBucketName, kTemp); ASSERT_TRUE(bucket_result.ok()); - QuotaErrorOr<QuotaDatabase::BucketTableEntry> info = + QuotaErrorOr<mojom::BucketTableEntryPtr> info = db->GetBucketInfo(bucket_result->id); EXPECT_TRUE(info.ok()); - EXPECT_EQ(0, info->use_count); + EXPECT_EQ(0, info.value()->use_count); EXPECT_EQ(db->SetStorageKeyLastAccessTime( StorageKey::CreateFromStringForTesting("http://a/"), kTemp, @@ -900,26 +941,35 @@ TEST_P(QuotaDatabaseTest, RegisterInitialStorageKeyInfo) { QuotaError::kNone); info = db->GetBucketInfo(bucket_result->id); EXPECT_TRUE(info.ok()); - EXPECT_EQ(1, info->use_count); + EXPECT_EQ(1, info.value()->use_count); EXPECT_EQ(db->RegisterInitialStorageKeyInfo(storage_keys_by_type), QuotaError::kNone); info = db->GetBucketInfo(bucket_result->id); EXPECT_TRUE(info.ok()); - EXPECT_EQ(1, info->use_count); + EXPECT_EQ(1, info.value()->use_count); } TEST_P(QuotaDatabaseTest, DumpBucketTable) { base::Time now = base::Time::Now(); - using Entry = QuotaDatabase::BucketTableEntry; + using Entry = mojom::BucketTableEntryPtr; + + StorageKey storage_key1 = + StorageKey::CreateFromStringForTesting("http://go/"); + StorageKey storage_key2 = + StorageKey::CreateFromStringForTesting("http://oo/"); + StorageKey storage_key3 = + StorageKey::CreateFromStringForTesting("http://gle/"); + Entry kTableEntries[] = { - Entry(BucketId(1), StorageKey::CreateFromStringForTesting("http://go/"), - kTemp, kDefaultBucketName, 2147483647, now, now), - Entry(BucketId(2), StorageKey::CreateFromStringForTesting("http://oo/"), - kTemp, kDefaultBucketName, 0, now, now), - Entry(BucketId(3), StorageKey::CreateFromStringForTesting("http://gle/"), - kTemp, kDefaultBucketName, 1, now, now), + mojom::BucketTableEntry::New(1, storage_key1.Serialize(), kStorageTemp, + kDefaultBucketName, -1, 2147483647, now, + now), + mojom::BucketTableEntry::New(2, storage_key2.Serialize(), kStorageTemp, + kDefaultBucketName, -1, 0, now, now), + mojom::BucketTableEntry::New(3, storage_key3.Serialize(), kStorageTemp, + kDefaultBucketName, -1, 1, now, now), }; auto db = CreateDatabase(use_in_memory_db()); @@ -927,7 +977,7 @@ TEST_P(QuotaDatabaseTest, DumpBucketTable) { AssignBucketTable(db.get(), kTableEntries); using Verifier = EntryVerifier<Entry>; - Verifier verifier(kTableEntries, std::end(kTableEntries)); + Verifier verifier(kTableEntries); EXPECT_EQ(DumpBucketTable(db.get(), base::BindRepeating(&Verifier::Run, base::Unretained(&verifier))), @@ -936,32 +986,34 @@ TEST_P(QuotaDatabaseTest, DumpBucketTable) { } TEST_P(QuotaDatabaseTest, GetBucketInfo) { - using Entry = QuotaDatabase::BucketTableEntry; - Entry kTableEntries[] = { - Entry(BucketId(123), StorageKey::CreateFromStringForTesting("http://go/"), - kTemp, "test_bucket", 100, base::Time(), base::Time())}; + using Entry = mojom::BucketTableEntryPtr; + StorageKey storage_key = StorageKey::CreateFromStringForTesting("http://go/"); + BucketId bucket_id = BucketId(123); + storage::mojom::StorageType type = kStorageTemp; + + Entry kTableEntries[] = {mojom::BucketTableEntry::New( + bucket_id.value(), storage_key.Serialize(), type, "test_bucket", -1, 100, + base::Time(), base::Time())}; auto db = CreateDatabase(use_in_memory_db()); EXPECT_TRUE(EnsureOpened(db.get())); AssignBucketTable(db.get(), kTableEntries); { - QuotaErrorOr<QuotaDatabase::BucketTableEntry> entry = - db->GetBucketInfo(kTableEntries[0].bucket_id); + QuotaErrorOr<Entry> entry = db->GetBucketInfo(bucket_id); EXPECT_TRUE(entry.ok()); - EXPECT_EQ(kTableEntries[0].bucket_id, entry->bucket_id); - EXPECT_EQ(kTableEntries[0].type, entry->type); - EXPECT_EQ(kTableEntries[0].storage_key, entry->storage_key); - EXPECT_EQ(kTableEntries[0].name, entry->name); - EXPECT_EQ(kTableEntries[0].use_count, entry->use_count); - EXPECT_EQ(kTableEntries[0].last_accessed, entry->last_accessed); - EXPECT_EQ(kTableEntries[0].last_modified, entry->last_modified); + EXPECT_EQ(bucket_id.value(), entry.value()->bucket_id); + EXPECT_EQ(type, entry.value()->type); + EXPECT_EQ(storage_key.Serialize(), entry.value()->storage_key); + EXPECT_EQ(kTableEntries[0]->name, entry.value()->name); + EXPECT_EQ(kTableEntries[0]->use_count, entry.value()->use_count); + EXPECT_EQ(kTableEntries[0]->last_accessed, entry.value()->last_accessed); + EXPECT_EQ(kTableEntries[0]->last_modified, entry.value()->last_modified); } { // BucketId 456 is not in the database. - QuotaErrorOr<QuotaDatabase::BucketTableEntry> entry = - db->GetBucketInfo(BucketId(456)); + QuotaErrorOr<Entry> entry = db->GetBucketInfo(BucketId(456)); EXPECT_FALSE(entry.ok()); } } diff --git a/chromium/storage/browser/quota/quota_device_info_helper.cc b/chromium/storage/browser/quota/quota_device_info_helper.cc index 8f415442983..cf12c20ac81 100644 --- a/chromium/storage/browser/quota/quota_device_info_helper.cc +++ b/chromium/storage/browser/quota/quota_device_info_helper.cc @@ -17,7 +17,7 @@ int64_t QuotaDeviceInfoHelper::AmountOfTotalDiskSpace( return disk_space; } -int64_t QuotaDeviceInfoHelper::AmountOfPhysicalMemory() const { +uint64_t QuotaDeviceInfoHelper::AmountOfPhysicalMemory() const { return base::SysInfo::AmountOfPhysicalMemory(); } diff --git a/chromium/storage/browser/quota/quota_device_info_helper.h b/chromium/storage/browser/quota/quota_device_info_helper.h index 2ce8b16f8ee..1f865d87d4f 100644 --- a/chromium/storage/browser/quota/quota_device_info_helper.h +++ b/chromium/storage/browser/quota/quota_device_info_helper.h @@ -25,7 +25,7 @@ class COMPONENT_EXPORT(STORAGE_BROWSER) QuotaDeviceInfoHelper { virtual int64_t AmountOfTotalDiskSpace(const base::FilePath& path) const; - virtual int64_t AmountOfPhysicalMemory() const; + virtual uint64_t AmountOfPhysicalMemory() const; }; // class QuotaDeviceInfoHelper } // namespace storage diff --git a/chromium/storage/browser/quota/quota_internals.mojom b/chromium/storage/browser/quota/quota_internals.mojom index 5db2a565bb7..39d676f10fb 100644 --- a/chromium/storage/browser/quota/quota_internals.mojom +++ b/chromium/storage/browser/quota/quota_internals.mojom @@ -11,10 +11,9 @@ import "url/mojom/origin.mojom"; struct BucketTableEntry { int64 bucket_id; string storage_key; - string host; - string type; + StorageType type; string name; - int64 usage; + int64 usage = -1; int64 use_count; mojo_base.mojom.Time last_accessed; mojo_base.mojom.Time last_modified; @@ -49,10 +48,6 @@ interface QuotaInternalsHandler { // Returns an array of Storage Bucket entries stored in the QuotaDatabase. RetrieveBucketsTable() => (array<BucketTableEntry> entries); - // Returns a host's usage for a given storage type. - GetHostUsageForInternals(string host, StorageType storage_type) => - (int64 host_usage); - // Returns the global usage and unlimited usage for a given storage type. GetGlobalUsageForInternals(StorageType storage_type) => (int64 usage, int64 unlimited_usage); diff --git a/chromium/storage/browser/quota/quota_manager_impl.cc b/chromium/storage/browser/quota/quota_manager_impl.cc index 361e9927580..d3f076074e8 100644 --- a/chromium/storage/browser/quota/quota_manager_impl.cc +++ b/chromium/storage/browser/quota/quota_manager_impl.cc @@ -14,6 +14,7 @@ #include <memory> #include <utility> +#include "base/barrier_callback.h" #include "base/barrier_closure.h" #include "base/bind.h" #include "base/callback.h" @@ -85,14 +86,6 @@ int64_t RandomizeByPercent(int64_t value, int percent) { double random_percent = (base::RandDouble() - 0.5) * percent * 2; return value * (1 + (random_percent / 100.0)); } -} // namespace - -// Heuristics: assuming average cloud server allows a few Gigs storage -// on the server side and the storage needs to be shared for user data -// and by multiple apps. -int64_t QuotaManagerImpl::kSyncableStorageDefaultHostQuota = 500 * kMBytes; - -namespace { bool IsSupportedType(StorageType type) { return type == StorageType::kTemporary || type == StorageType::kPersistent || @@ -103,21 +96,6 @@ bool IsSupportedIncognitoType(StorageType type) { return type == StorageType::kTemporary || type == StorageType::kPersistent; } -std::string StorageTypeEnumToString(StorageType type) { - switch (type) { - case StorageType::kTemporary: - return "temporary"; - case StorageType::kPersistent: - return "persistent"; - case StorageType::kSyncable: - return "syncable"; - case StorageType::kQuotaNotManaged: - return "quota-not-managed"; - case StorageType::kUnknown: - return "unknown"; - } -} - StorageType GetBlinkStorageType(storage::mojom::StorageType type) { switch (type) { case storage::mojom::StorageType::kTemporary: @@ -152,6 +130,11 @@ void DidGetUsageAndQuotaStripOverride( } // namespace +// Heuristics: assuming average cloud server allows a few Gigs storage +// on the server side and the storage needs to be shared for user data +// and by multiple apps. +int64_t QuotaManagerImpl::kSyncableStorageDefaultHostQuota = 500 * kMBytes; + constexpr int64_t QuotaManagerImpl::kGBytes; constexpr int64_t QuotaManagerImpl::kNoLimit; constexpr int64_t QuotaManagerImpl::kPerHostPersistentQuotaLimit; @@ -664,11 +647,13 @@ class QuotaManagerImpl::BucketDataDeleter { QuotaManagerImpl* manager, const BucketLocator& bucket, QuotaClientTypes quota_client_types, + bool commit_immediately, base::OnceCallback<void(BucketDataDeleter*, blink::mojom::QuotaStatusCode)> callback) : manager_(manager), bucket_(bucket), quota_client_types_(std::move(quota_client_types)), + commit_immediately_(commit_immediately), callback_(std::move(callback)) { DCHECK(manager_); // TODO(crbug/1292216): Convert back into DCHECKs once issue is resolved. @@ -754,7 +739,7 @@ class QuotaManagerImpl::BucketDataDeleter { // types. if (skipped_clients_ == 0 && error_count_ == 0) { manager_->DeleteBucketFromDatabase( - bucket_, + bucket_, commit_immediately_, base::BindOnce(&BucketDataDeleter::DidDeleteBucketFromDatabase, weak_factory_.GetWeakPtr())); return; @@ -786,6 +771,9 @@ class QuotaManagerImpl::BucketDataDeleter { GUARDED_BY_CONTEXT(sequence_checker_); const BucketLocator bucket_; const QuotaClientTypes quota_client_types_; + // Whether the update to the database should be committed immediately (if not, + // it will be scheduled to be committed as part of a batch). + const bool commit_immediately_; int error_count_ GUARDED_BY_CONTEXT(sequence_checker_) = 0; size_t remaining_clients_ GUARDED_BY_CONTEXT(sequence_checker_) = 0; int skipped_clients_ GUARDED_BY_CONTEXT(sequence_checker_) = 0; @@ -848,14 +836,14 @@ class QuotaManagerImpl::HostDataDeleter { } private: - void DidGetBucketsForHost(QuotaErrorOr<std::set<BucketLocator>> result) { + void DidGetBucketsForHost(QuotaErrorOr<std::set<BucketInfo>> result) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); if (!result.ok()) { Complete(/*success=*/false); return; } - buckets_ = result.value(); + buckets_ = BucketInfosToBucketLocators(result.value()); if (!buckets_.empty()) { ScheduleBucketsDeletion(); return; @@ -871,7 +859,7 @@ class QuotaManagerImpl::HostDataDeleter { // BucketDataDeleter created here, which guarantees it will only use the // callback when it's alive. auto bucket_deleter = std::make_unique<BucketDataDeleter>( - manager_, bucket, AllQuotaClientTypes(), + manager_, bucket, AllQuotaClientTypes(), /*commit_immediately=*/false, base::BindOnce(&HostDataDeleter::DidDeleteBucketData, base::Unretained(this))); auto* bucket_deleter_ptr = bucket_deleter.get(); @@ -1008,12 +996,12 @@ class QuotaManagerImpl::DumpBucketTableHelper { return; } manager->DidDatabaseWork(error != QuotaError::kDatabaseError); - std::move(callback).Run(entries_); + std::move(callback).Run(std::move(entries_)); } private: - bool AppendEntry(const BucketTableEntry& entry) { - entries_.push_back(entry); + bool AppendEntry(mojom::BucketTableEntryPtr entry) { + entries_.push_back(std::move(entry)); return true; } @@ -1209,7 +1197,7 @@ void QuotaManagerImpl::GetStorageKeysForType(blink::mojom::StorageType type, void QuotaManagerImpl::GetBucketsForType( blink::mojom::StorageType type, - base::OnceCallback<void(QuotaErrorOr<std::set<BucketLocator>>)> callback) { + base::OnceCallback<void(QuotaErrorOr<std::set<BucketInfo>>)> callback) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK(callback); EnsureDatabaseOpened(); @@ -1232,7 +1220,7 @@ void QuotaManagerImpl::GetBucketsForType( void QuotaManagerImpl::GetBucketsForHost( const std::string& host, blink::mojom::StorageType type, - base::OnceCallback<void(QuotaErrorOr<std::set<BucketLocator>>)> callback) { + base::OnceCallback<void(QuotaErrorOr<std::set<BucketInfo>>)> callback) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK(callback); EnsureDatabaseOpened(); @@ -1256,7 +1244,8 @@ void QuotaManagerImpl::GetBucketsForHost( void QuotaManagerImpl::GetBucketsForStorageKey( const StorageKey& storage_key, blink::mojom::StorageType type, - base::OnceCallback<void(QuotaErrorOr<std::set<BucketLocator>>)> callback) { + base::OnceCallback<void(QuotaErrorOr<std::set<BucketInfo>>)> callback, + bool delete_expired) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK(callback); EnsureDatabaseOpened(); @@ -1265,6 +1254,16 @@ void QuotaManagerImpl::GetBucketsForStorageKey( std::move(callback).Run(QuotaError::kDatabaseError); return; } + + base::OnceCallback<void(QuotaErrorOr<std::set<BucketInfo>>)> reply; + if (delete_expired) { + reply = base::BindOnce(&QuotaManagerImpl::DidGetBucketsCheckExpiration, + weak_factory_.GetWeakPtr(), std::move(callback)); + } else { + reply = base::BindOnce(&QuotaManagerImpl::DidGetBuckets, + weak_factory_.GetWeakPtr(), std::move(callback)); + } + PostTaskAndReplyWithResultForDBThread( base::BindOnce( [](const StorageKey& storage_key, StorageType type, @@ -1273,8 +1272,7 @@ void QuotaManagerImpl::GetBucketsForStorageKey( return database->GetBucketsForStorageKey(storage_key, type); }, storage_key, type), - base::BindOnce(&QuotaManagerImpl::DidGetBuckets, - weak_factory_.GetWeakPtr(), std::move(callback))); + std::move(reply)); } void QuotaManagerImpl::GetUsageInfo(GetUsageInfoCallback callback) { @@ -1729,22 +1727,6 @@ void QuotaManagerImpl::GetBucketUsageWithBreakdown( usage_tracker->GetBucketUsageWithBreakdown(bucket, std::move(callback)); } -void QuotaManagerImpl::GetHostUsageForInternals( - const std::string& host, - storage::mojom::StorageType storage_type, - GetHostUsageForInternalsCallback callback) { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - EnsureDatabaseOpened(); - - StorageType type = GetBlinkStorageType(storage_type); - UsageTracker* usage_tracker = GetUsageTracker(type); - DCHECK(usage_tracker); - - usage_tracker->GetHostUsageWithBreakdown( - host, base::BindOnce(&QuotaManagerImpl::OnGetHostUsageForInternals, - weak_factory_.GetWeakPtr(), std::move(callback))); -} - bool QuotaManagerImpl::IsSessionOnly(const StorageKey& storage_key, StorageType type) const { return type == StorageType::kTemporary && special_storage_policy_ && @@ -1760,7 +1742,7 @@ bool QuotaManagerImpl::IsStorageUnlimited(const StorageKey& storage_key, // quota must be capped by the server limit). if (type == StorageType::kSyncable) return false; - if (type == StorageType::kQuotaNotManaged) + if (type == StorageType::kDeprecatedQuotaNotManaged) return true; return special_storage_policy_.get() && special_storage_policy_->IsStorageUnlimited( @@ -1822,7 +1804,7 @@ QuotaManagerImpl::~QuotaManagerImpl() { proxy_->InvalidateQuotaManagerImpl(base::PassKey<QuotaManagerImpl>()); if (database_) - db_runner_->DeleteSoon(FROM_HERE, database_.get()); + db_runner_->DeleteSoon(FROM_HERE, database_.ExtractAsDangling().get()); } QuotaManagerImpl::EvictionContext::EvictionContext() = default; @@ -1968,7 +1950,7 @@ UsageTracker* QuotaManagerImpl::GetUsageTracker(StorageType type) const { return persistent_usage_tracker_.get(); case StorageType::kSyncable: return syncable_usage_tracker_.get(); - case StorageType::kQuotaNotManaged: + case StorageType::kDeprecatedQuotaNotManaged: return nullptr; case StorageType::kUnknown: NOTREACHED(); @@ -1976,16 +1958,6 @@ UsageTracker* QuotaManagerImpl::GetUsageTracker(StorageType type) const { return nullptr; } -void QuotaManagerImpl::OnGetHostUsageForInternals( - GetHostUsageForInternalsCallback callback, - int64_t usage, - blink::mojom::UsageBreakdownPtr usage_breakdown) { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - DCHECK_GE(usage, -1); - - std::move(callback).Run(usage); -} - void QuotaManagerImpl::NotifyStorageAccessed(const StorageKey& storage_key, StorageType type, base::Time access_time) { @@ -2121,52 +2093,44 @@ void QuotaManagerImpl::RetrieveBucketsTable( void QuotaManagerImpl::RetrieveBucketUsageForBucketTable( RetrieveBucketsTableCallback callback, - const BucketTableEntries& entries) { + BucketTableEntries entries) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - auto* buckets = new std::vector<storage::mojom::BucketTableEntryPtr>; - - base::RepeatingClosure barrier = base::BarrierClosure( - entries.size(), - base::BindOnce( - [](RetrieveBucketsTableCallback callback, - std::vector<storage::mojom::BucketTableEntryPtr>* buckets) { - std::move(callback).Run(std::move(*buckets)); - }, - std::move(callback), base::Owned(buckets))); + base::RepeatingCallback<void(mojom::BucketTableEntryPtr)> barrier = + base::BarrierCallback<mojom::BucketTableEntryPtr>(entries.size(), + std::move(callback)); for (auto& entry : entries) { - DCHECK(IsSupportedType(entry.type)); + StorageType type = static_cast<StorageType>(entry->type); + DCHECK(IsSupportedType(type)); + + absl::optional<StorageKey> storage_key = + StorageKey::Deserialize(entry->storage_key); + DCHECK(storage_key.has_value()); + + BucketId bucket_id = BucketId(entry->bucket_id); + + BucketLocator bucket_locator = + BucketLocator(bucket_id, std::move(storage_key).value(), type, + entry->name == kDefaultBucketName); GetBucketUsageWithBreakdown( - entry.ToBucketLocator(), + bucket_locator, base::BindOnce(&QuotaManagerImpl::AddBucketTableEntry, - weak_factory_.GetWeakPtr(), entry, barrier, buckets)); + weak_factory_.GetWeakPtr(), std::move(entry), barrier)); } } void QuotaManagerImpl::AddBucketTableEntry( - const BucketTableEntry& entry, - base::OnceClosure barrier_callback, - std::vector<storage::mojom::BucketTableEntryPtr>* buckets, + mojom::BucketTableEntryPtr entry, + base::OnceCallback<void(mojom::BucketTableEntryPtr)> barrier_callback, int64_t usage, - blink::mojom::UsageBreakdownPtr bucketUsageBreakdown) { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - - storage::mojom::BucketTableEntryPtr mojo_entry = - storage::mojom::BucketTableEntry::New(); - mojo_entry->bucket_id = entry.bucket_id.value(); - mojo_entry->storage_key = entry.storage_key.Serialize(); - mojo_entry->host = entry.storage_key.origin().host(); - mojo_entry->type = StorageTypeEnumToString(entry.type); - mojo_entry->name = entry.name; - mojo_entry->use_count = entry.use_count; - mojo_entry->last_accessed = entry.last_accessed; - mojo_entry->last_modified = entry.last_modified; - mojo_entry->usage = usage; - - buckets->emplace_back(std::move(mojo_entry)); - std::move(barrier_callback).Run(); + blink::mojom::UsageBreakdownPtr bucket_usage_breakdown) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + + entry->usage = usage; + + std::move(barrier_callback).Run(std::move(entry)); } void QuotaManagerImpl::StartEviction() { @@ -2182,6 +2146,7 @@ void QuotaManagerImpl::StartEviction() { void QuotaManagerImpl::DeleteBucketFromDatabase( const BucketLocator& bucket, + bool commit_immediately, base::OnceCallback<void(QuotaError)> callback) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK(callback); @@ -2194,16 +2159,21 @@ void QuotaManagerImpl::DeleteBucketFromDatabase( PostTaskAndReplyWithResultForDBThread( base::BindOnce( - [](const BucketLocator& bucket, QuotaDatabase* database) { + [](const BucketLocator& bucket, bool commit_immediately, + QuotaDatabase* database) { DCHECK(database); - return database->DeleteBucketData(bucket); + auto result = database->DeleteBucketData(bucket); + if (commit_immediately && result == QuotaError::kNone) + database->CommitNow(); + + return result; }, - bucket), + bucket, commit_immediately), std::move(callback)); } void QuotaManagerImpl::DidBucketDataEvicted( - QuotaDatabase::BucketTableEntry entry, + mojom::BucketTableEntryPtr entry, blink::mojom::QuotaStatusCode status) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK(io_thread_->BelongsToCurrentThread()); @@ -2219,10 +2189,10 @@ void QuotaManagerImpl::DidBucketDataEvicted( base::Time now = QuotaDatabase::GetNow(); base::UmaHistogramCounts1M( QuotaManagerImpl::kEvictedBucketAccessedCountHistogram, - entry.use_count); + entry->use_count); base::UmaHistogramCounts1000( QuotaManagerImpl::kEvictedBucketDaysSinceAccessHistogram, - (now - entry.last_accessed).InDays()); + (now - entry->last_accessed).InDays()); } std::move(eviction_context_.evict_bucket_data_callback).Run(status); @@ -2241,7 +2211,7 @@ void QuotaManagerImpl::DeleteBucketDataInternal( return; } auto bucket_deleter = std::make_unique<BucketDataDeleter>( - this, bucket, std::move(quota_client_types), + this, bucket, std::move(quota_client_types), /*commit_immediately=*/true, base::BindOnce(&QuotaManagerImpl::DidDeleteBucketData, weak_factory_.GetWeakPtr(), std::move(callback))); auto* bucket_deleter_ptr = bucket_deleter.get(); @@ -2473,32 +2443,33 @@ void QuotaManagerImpl::DidGetPersistentGlobalUsageForHistogram( } void QuotaManagerImpl::DidDumpBucketTableForHistogram( - const BucketTableEntries& entries) { + BucketTableEntries entries) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); std::map<StorageKey, int64_t> usage_map = GetUsageTracker(StorageType::kTemporary)->GetCachedStorageKeysUsage(); base::Time now = QuotaDatabase::GetNow(); for (const auto& info : entries) { - if (info.type != StorageType::kTemporary) + if (info->type != storage::mojom::StorageType::kTemporary) continue; + absl::optional<StorageKey> storage_key = + StorageKey::Deserialize(info->storage_key); + // Ignore stale database entries. If there is no map entry, the storage // key's data has been deleted. - auto it = usage_map.find(info.storage_key); + auto it = usage_map.find(*storage_key); if (it == usage_map.end() || it->second == 0) continue; base::TimeDelta age = - now - std::max(info.last_accessed, info.last_modified); + now - std::max(info->last_accessed, info->last_modified); UMA_HISTOGRAM_COUNTS_1000("Quota.AgeOfOriginInDays", age.InDays()); int64_t kilobytes = std::max(it->second / int64_t{1024}, int64_t{1}); - base::Histogram::FactoryGet( - "Quota.AgeOfDataInDays", 1, 1000, 50, - base::HistogramBase::kUmaTargetedHistogramFlag)-> - AddCount(age.InDays(), - base::saturated_cast<int>(kilobytes)); + base::Histogram::FactoryGet("Quota.AgeOfDataInDays", 1, 1000, 50, + base::HistogramBase::kUmaTargetedHistogramFlag) + ->AddCount(age.InDays(), base::saturated_cast<int>(kilobytes)); } } @@ -2580,7 +2551,7 @@ void QuotaManagerImpl::EvictBucketData(const BucketLocator& bucket, void QuotaManagerImpl::DidGetBucketInfoForEviction( const BucketLocator& bucket, - QuotaErrorOr<QuotaDatabase::BucketTableEntry> result) { + QuotaErrorOr<mojom::BucketTableEntryPtr> result) { DidDatabaseWork(result.ok() || result.error() != QuotaError::kDatabaseError); if (!result.ok()) { @@ -2592,7 +2563,7 @@ void QuotaManagerImpl::DidGetBucketInfoForEviction( DeleteBucketDataInternal( bucket, AllQuotaClientTypes(), base::BindOnce(&QuotaManagerImpl::DidBucketDataEvicted, - weak_factory_.GetWeakPtr(), result.value())); + weak_factory_.GetWeakPtr(), std::move(result.value()))); } void QuotaManagerImpl::GetEvictionRoundInfo( @@ -2947,8 +2918,8 @@ void QuotaManagerImpl::DidGetStorageKeys( } void QuotaManagerImpl::DidGetBuckets( - base::OnceCallback<void(QuotaErrorOr<std::set<BucketLocator>>)> callback, - QuotaErrorOr<std::set<BucketLocator>> result) { + base::OnceCallback<void(QuotaErrorOr<std::set<BucketInfo>>)> callback, + QuotaErrorOr<std::set<BucketInfo>> result) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK(callback); @@ -2956,6 +2927,48 @@ void QuotaManagerImpl::DidGetBuckets( std::move(callback).Run(std::move(result)); } +void QuotaManagerImpl::DidGetBucketsCheckExpiration( + base::OnceCallback<void(QuotaErrorOr<std::set<BucketInfo>>)> callback, + QuotaErrorOr<std::set<BucketInfo>> result) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + DCHECK(callback); + + DidDatabaseWork(result.ok() || result.error() != QuotaError::kDatabaseError); + + if (!result.ok()) { + std::move(callback).Run(std::move(result)); + return; + } + + std::set<BucketInfo> kept_buckets; + std::set<BucketInfo> buckets_to_delete; + for (const BucketInfo& bucket : result.value()) { + if (!bucket.expiration.is_null() && + bucket.expiration <= QuotaDatabase::GetNow()) { + buckets_to_delete.insert(bucket); + } else { + kept_buckets.insert(bucket); + } + } + + if (buckets_to_delete.empty()) { + std::move(callback).Run(kept_buckets); + return; + } + + base::RepeatingClosure barrier = + base::BarrierClosure(buckets_to_delete.size(), + base::BindOnce(std::move(callback), kept_buckets)); + for (const BucketInfo& bucket : buckets_to_delete) { + StatusCallback on_delete_done = + base::BindOnce([](base::RepeatingClosure barrier, + blink::mojom::QuotaStatusCode) { barrier.Run(); }, + barrier); + DeleteBucketDataInternal(bucket.ToBucketLocator(), AllQuotaClientTypes(), + std::move(on_delete_done)); + } +} + void QuotaManagerImpl::DidGetModifiedBetween( GetBucketsCallback callback, StorageType type, @@ -3047,7 +3060,8 @@ std::tuple<int64_t, int64_t> QuotaManagerImpl::CallGetVolumeInfo( UMA_HISTOGRAM_MBYTES("Quota.TotalDiskSpace", total); UMA_HISTOGRAM_MBYTES("Quota.AvailableDiskSpace", available); if (total > 0) { - UMA_HISTOGRAM_PERCENTAGE("Quota.PercentDiskAvailable", + UMA_HISTOGRAM_PERCENTAGE( + "Quota.PercentDiskAvailable", std::min(100, static_cast<int>((available * 100) / total))); } return std::make_tuple(total, available); diff --git a/chromium/storage/browser/quota/quota_manager_impl.h b/chromium/storage/browser/quota/quota_manager_impl.h index 9ccba1d1577..e15fff7270f 100644 --- a/chromium/storage/browser/quota/quota_manager_impl.h +++ b/chromium/storage/browser/quota/quota_manager_impl.h @@ -235,21 +235,23 @@ class COMPONENT_EXPORT(STORAGE_BROWSER) QuotaManagerImpl // Used for retrieving global usage data in the UsageTracker. void GetBucketsForType( blink::mojom::StorageType type, - base::OnceCallback<void(QuotaErrorOr<std::set<BucketLocator>>)> callback); + base::OnceCallback<void(QuotaErrorOr<std::set<BucketInfo>>)> callback); // Retrieves all buckets for `host` and `type` that are in the buckets table. // Used for retrieving host usage data in the UsageTracker. void GetBucketsForHost( const std::string& host, blink::mojom::StorageType type, - base::OnceCallback<void(QuotaErrorOr<std::set<BucketLocator>>)> callback); + base::OnceCallback<void(QuotaErrorOr<std::set<BucketInfo>>)> callback); // Retrieves all buckets for `storage_key` and `type` that are in the buckets - // table. Used for retrieving storage key usage data in the UsageTracker. - void GetBucketsForStorageKey( + // table. When `delete_expired` is true, the expired buckets will be filtered + // out of the reply and also deleted from disk. + virtual void GetBucketsForStorageKey( const blink::StorageKey& storage_key, blink::mojom::StorageType type, - base::OnceCallback<void(QuotaErrorOr<std::set<BucketLocator>>)> callback); + base::OnceCallback<void(QuotaErrorOr<std::set<BucketInfo>>)> callback, + bool delete_expired = false); // Called by clients or webapps. Returns usage per host. void GetUsageInfo(GetUsageInfoCallback callback); @@ -385,10 +387,6 @@ class COMPONENT_EXPORT(STORAGE_BROWSER) QuotaManagerImpl GetDiskAvailabilityAndTempPoolSizeCallback callback) override; void GetStatistics(GetStatisticsCallback callback) override; void RetrieveBucketsTable(RetrieveBucketsTableCallback callback) override; - void GetHostUsageForInternals( - const std::string& host, - storage::mojom::StorageType storage_type, - GetHostUsageForInternalsCallback callback) override; void GetGlobalUsageForInternals( storage::mojom::StorageType storage_type, GetGlobalUsageForInternalsCallback callback) override; @@ -533,15 +531,13 @@ class COMPONENT_EXPORT(STORAGE_BROWSER) QuotaManagerImpl std::set<int> active_override_session_ids; }; - using BucketTableEntry = QuotaDatabase::BucketTableEntry; - using BucketTableEntries = std::vector<BucketTableEntry>; + using BucketTableEntries = std::vector<mojom::BucketTableEntryPtr>; using StorageKeysByType = base::flat_map<blink::mojom::StorageType, std::set<blink::StorageKey>>; using QuotaSettingsCallback = base::OnceCallback<void(const QuotaSettings&)>; - using DumpBucketTableCallback = - base::OnceCallback<void(const BucketTableEntries&)>; + using DumpBucketTableCallback = base::OnceCallback<void(BucketTableEntries)>; // The values returned total_space, available_space. using StorageCapacityCallback = base::OnceCallback<void(int64_t, int64_t)>; @@ -582,10 +578,6 @@ class COMPONENT_EXPORT(STORAGE_BROWSER) QuotaManagerImpl UsageTracker* GetUsageTracker(blink::mojom::StorageType type) const; void DumpBucketTable(DumpBucketTableCallback callback); - void OnGetHostUsageForInternals( - GetHostUsageForInternalsCallback callback, - int64_t usage, - blink::mojom::UsageBreakdownPtr usage_breakdown); void UpdateQuotaInternalsDiskAvailability(base::OnceClosure barrier_callback, AccumulateQuotaInternalsInfo* info, int64_t total_space, @@ -597,13 +589,12 @@ class COMPONENT_EXPORT(STORAGE_BROWSER) QuotaManagerImpl GetDiskAvailabilityAndTempPoolSizeCallback callback, std::unique_ptr<AccumulateQuotaInternalsInfo> info); void RetrieveBucketUsageForBucketTable(RetrieveBucketsTableCallback callback, - const BucketTableEntries& entries); + BucketTableEntries entries); void AddBucketTableEntry( - const BucketTableEntry& entry, - base::OnceClosure barrier_callback, - std::vector<storage::mojom::BucketTableEntryPtr>* buckets, + mojom::BucketTableEntryPtr entry, + base::OnceCallback<void(mojom::BucketTableEntryPtr)> barrier_callback, int64_t usage, - blink::mojom::UsageBreakdownPtr bucketUsageBreakdown); + blink::mojom::UsageBreakdownPtr bucket_usage_breakdown); // Runs BucketDataDeleter which calls QuotaClients to clear data for the // bucket. Once the task is complete, calls the QuotaDatabase to delete the @@ -642,9 +633,10 @@ class COMPONENT_EXPORT(STORAGE_BROWSER) QuotaManagerImpl // Methods for eviction logic. void StartEviction(); void DeleteBucketFromDatabase(const BucketLocator& bucket, + bool commit_immediately, base::OnceCallback<void(QuotaError)> callback); - void DidBucketDataEvicted(QuotaDatabase::BucketTableEntry entry, + void DidBucketDataEvicted(mojom::BucketTableEntryPtr entry, blink::mojom::QuotaStatusCode status); void ReportHistogram(); @@ -655,7 +647,7 @@ class COMPONENT_EXPORT(STORAGE_BROWSER) QuotaManagerImpl int64_t available_space); void DidGetPersistentGlobalUsageForHistogram(int64_t usage, int64_t unlimited_usage); - void DidDumpBucketTableForHistogram(const BucketTableEntries& entries); + void DidDumpBucketTableForHistogram(BucketTableEntries entries); // Returns the list of bucket ids that should be excluded from eviction due to // consistent errors after multiple attempts. @@ -672,7 +664,7 @@ class COMPONENT_EXPORT(STORAGE_BROWSER) QuotaManagerImpl void DidGetBucketInfoForEviction( const BucketLocator& bucket, - QuotaErrorOr<QuotaDatabase::BucketTableEntry> result); + QuotaErrorOr<mojom::BucketTableEntryPtr> result); void DidGetEvictionRoundInfo(); @@ -713,8 +705,11 @@ class COMPONENT_EXPORT(STORAGE_BROWSER) QuotaManagerImpl void DidGetStorageKeys(GetStorageKeysCallback callback, QuotaErrorOr<std::set<blink::StorageKey>> result); void DidGetBuckets( - base::OnceCallback<void(QuotaErrorOr<std::set<BucketLocator>>)> callback, - QuotaErrorOr<std::set<BucketLocator>> result); + base::OnceCallback<void(QuotaErrorOr<std::set<BucketInfo>>)> callback, + QuotaErrorOr<std::set<BucketInfo>> result); + void DidGetBucketsCheckExpiration( + base::OnceCallback<void(QuotaErrorOr<std::set<BucketInfo>>)> callback, + QuotaErrorOr<std::set<BucketInfo>> result); void DidGetModifiedBetween(GetBucketsCallback callback, blink::mojom::StorageType type, QuotaErrorOr<std::set<BucketLocator>> result); diff --git a/chromium/storage/browser/quota/quota_manager_proxy.cc b/chromium/storage/browser/quota/quota_manager_proxy.cc index 90a46f95420..393d4d1e5ce 100644 --- a/chromium/storage/browser/quota/quota_manager_proxy.cc +++ b/chromium/storage/browser/quota/quota_manager_proxy.cc @@ -252,6 +252,37 @@ void QuotaManagerProxy::GetBucket( std::move(respond)); } +void QuotaManagerProxy::GetBucketsForStorageKey( + const blink::StorageKey& storage_key, + blink::mojom::StorageType type, + bool delete_expired, + scoped_refptr<base::SequencedTaskRunner> callback_task_runner, + base::OnceCallback<void(QuotaErrorOr<std::set<BucketInfo>>)> callback) { + DCHECK(callback_task_runner); + DCHECK(callback); + + if (!quota_manager_impl_task_runner_->RunsTasksInCurrentSequence()) { + quota_manager_impl_task_runner_->PostTask( + FROM_HERE, + base::BindOnce(&QuotaManagerProxy::GetBucketsForStorageKey, this, + storage_key, type, delete_expired, + std::move(callback_task_runner), std::move(callback))); + return; + } + + DCHECK_CALLED_ON_VALID_SEQUENCE(quota_manager_impl_sequence_checker_); + + auto respond = + base::BindPostTask(std::move(callback_task_runner), std::move(callback)); + if (!quota_manager_impl_) { + std::move(respond).Run(QuotaError::kUnknownError); + return; + } + + quota_manager_impl_->GetBucketsForStorageKey( + storage_key, type, std::move(respond), delete_expired); +} + void QuotaManagerProxy::GetBucketById( const BucketId& bucket_id, scoped_refptr<base::SequencedTaskRunner> callback_task_runner, diff --git a/chromium/storage/browser/quota/quota_manager_proxy.h b/chromium/storage/browser/quota/quota_manager_proxy.h index c5ab07ca576..efb9691dd5c 100644 --- a/chromium/storage/browser/quota/quota_manager_proxy.h +++ b/chromium/storage/browser/quota/quota_manager_proxy.h @@ -101,7 +101,7 @@ class COMPONENT_EXPORT(STORAGE_BROWSER) QuotaManagerProxy // quota_manager_impl_task_runner. Additionally, the asychonrous version of // this method `GetOrCreateBucket` is preferred; only use this synchronous // version where asynchronous bucket retrieval is not possible. - QuotaErrorOr<BucketInfo> GetOrCreateBucketSync( + virtual QuotaErrorOr<BucketInfo> GetOrCreateBucketSync( const BucketInitParams& params); // Same as GetOrCreateBucket but takes in StorageType. This should only be @@ -145,6 +145,16 @@ class COMPONENT_EXPORT(STORAGE_BROWSER) QuotaManagerProxy scoped_refptr<base::SequencedTaskRunner> callback_task_runner, base::OnceCallback<void(QuotaErrorOr<BucketInfo>)> callback); + // Retrieves all buckets for `storage_key` and `type` that are in the buckets + // table. If `delete_expired` is true, expired buckets will be filtered out of + // the reply and also deleted from disk. + virtual void GetBucketsForStorageKey( + const blink::StorageKey& storage_key, + blink::mojom::StorageType type, + bool delete_expired, + scoped_refptr<base::SequencedTaskRunner> callback_task_runner, + base::OnceCallback<void(QuotaErrorOr<std::set<BucketInfo>>)> callback); + // Deletes bucket with `bucket_name` for `storage_key` for // StorageType::kTemporary for all registered QuotaClients if a bucket exists. // Will return QuotaStatusCode to the callback. Called by Storage Buckets API @@ -183,8 +193,8 @@ class COMPONENT_EXPORT(STORAGE_BROWSER) QuotaManagerProxy // updated. If a `callback` is provided then `callback_task_runner` must // also be provided. If the quota manager runs on `callback_task_runner`, // then the `callback` may be invoked synchronously. - // TODO(crbug.com/1208141): Remove when all usages have updated to use - // NotifyBucketModified. + // TODO(https://crbug.com/1202167): Remove when all usages have updated to use + // `NotifyBucketModified()`. virtual void NotifyStorageModified( QuotaClientType client_id, const blink::StorageKey& storage_key, diff --git a/chromium/storage/browser/quota/quota_manager_proxy_unittest.cc b/chromium/storage/browser/quota/quota_manager_proxy_unittest.cc index 92394a05604..402365ecfc9 100644 --- a/chromium/storage/browser/quota/quota_manager_proxy_unittest.cc +++ b/chromium/storage/browser/quota/quota_manager_proxy_unittest.cc @@ -91,11 +91,14 @@ TEST_F(QuotaManagerProxyTest, GetClientBucketPath) { bucket->ToBucketLocator(), QuotaClientType::kIndexedDatabase), expected_path); - // BackgroundFetch/CacheStorage - expected_path = bucket_path.AppendASCII("CacheStorage"); + // BackgroundFetch + expected_path = bucket_path.AppendASCII("BackgroundFetch"); EXPECT_EQ(quota_manager_proxy_->GetClientBucketPath( bucket->ToBucketLocator(), QuotaClientType::kBackgroundFetch), expected_path); + + // CacheStorage + expected_path = bucket_path.AppendASCII("CacheStorage"); EXPECT_EQ( quota_manager_proxy_->GetClientBucketPath( bucket->ToBucketLocator(), QuotaClientType::kServiceWorkerCache), diff --git a/chromium/storage/browser/quota/quota_manager_unittest.cc b/chromium/storage/browser/quota/quota_manager_unittest.cc index 97d986d3a2d..5464dd6fe96 100644 --- a/chromium/storage/browser/quota/quota_manager_unittest.cc +++ b/chromium/storage/browser/quota/quota_manager_unittest.cc @@ -67,6 +67,11 @@ const StorageType kTemp = StorageType::kTemporary; const StorageType kPerm = StorageType::kPersistent; const StorageType kSync = StorageType::kSyncable; +const storage::mojom::StorageType kStorageTemp = + storage::mojom::StorageType::kTemporary; +const storage::mojom::StorageType kStoragePerm = + storage::mojom::StorageType::kPersistent; + // Values in bytes. const int64_t kAvailableSpaceForApp = 13377331U; const int64_t kMustRemainAvailableForSystem = kAvailableSpaceForApp / 2; @@ -132,10 +137,11 @@ const storage::mojom::BucketTableEntry* FindBucketTableEntry( } MATCHER_P3(MatchesBucketTableEntry, storage_key, type, use_count, "") { - return testing::ExplainMatchResult(storage_key, arg.storage_key, + return testing::ExplainMatchResult(storage_key, arg->storage_key, result_listener) && - testing::ExplainMatchResult(type, arg.type, result_listener) && - testing::ExplainMatchResult(use_count, arg.use_count, result_listener); + testing::ExplainMatchResult(type, arg->type, result_listener) && + testing::ExplainMatchResult(use_count, arg->use_count, + result_listener); } } // namespace @@ -257,28 +263,29 @@ class QuotaManagerImplTest : public testing::Test { return future.Take(); } - QuotaErrorOr<std::set<BucketLocator>> GetBucketsForType( + QuotaErrorOr<std::set<BucketInfo>> GetBucketsForType( blink::mojom::StorageType storage_type) { - base::test::TestFuture<QuotaErrorOr<std::set<BucketLocator>>> future; + base::test::TestFuture<QuotaErrorOr<std::set<BucketInfo>>> future; quota_manager_impl_->GetBucketsForType(storage_type, future.GetCallback()); return future.Take(); } - QuotaErrorOr<std::set<BucketLocator>> GetBucketsForHost( + QuotaErrorOr<std::set<BucketInfo>> GetBucketsForHost( const std::string& host, blink::mojom::StorageType storage_type) { - base::test::TestFuture<QuotaErrorOr<std::set<BucketLocator>>> future; + base::test::TestFuture<QuotaErrorOr<std::set<BucketInfo>>> future; quota_manager_impl_->GetBucketsForHost(host, storage_type, future.GetCallback()); return future.Take(); } - QuotaErrorOr<std::set<BucketLocator>> GetBucketsForStorageKey( + QuotaErrorOr<std::set<BucketInfo>> GetBucketsForStorageKey( const StorageKey& storage_key, - blink::mojom::StorageType storage_type) { - base::test::TestFuture<QuotaErrorOr<std::set<BucketLocator>>> future; - quota_manager_impl_->GetBucketsForStorageKey(storage_key, storage_type, - future.GetCallback()); + blink::mojom::StorageType storage_type, + bool delete_expired = false) { + base::test::TestFuture<QuotaErrorOr<std::set<BucketInfo>>> future; + quota_manager_impl_->GetBucketsForStorageKey( + storage_key, storage_type, future.GetCallback(), delete_expired); return future.Take(); } @@ -455,9 +462,8 @@ class QuotaManagerImplTest : public testing::Test { BucketTableEntries DumpBucketTable() { base::test::TestFuture<BucketTableEntries> future; - quota_manager_impl_->DumpBucketTable( - future.GetCallback<const BucketTableEntries&>()); - return future.Get(); + quota_manager_impl_->DumpBucketTable(future.GetCallback()); + return future.Take(); } std::vector<storage::mojom::BucketTableEntryPtr> RetrieveBucketsTable() { @@ -961,18 +967,18 @@ TEST_F(QuotaManagerImplTest, GetBucketsForType) { EXPECT_TRUE(bucket.ok()); BucketInfo bucket_c = bucket.value(); - QuotaErrorOr<std::set<BucketLocator>> result = GetBucketsForType(kTemp); + QuotaErrorOr<std::set<BucketInfo>> result = GetBucketsForType(kTemp); EXPECT_TRUE(result.ok()); - std::set<BucketLocator> buckets = result.value(); + std::set<BucketInfo> buckets = result.value(); EXPECT_EQ(2U, buckets.size()); - EXPECT_THAT(buckets, testing::Contains(bucket_a.ToBucketLocator())); - EXPECT_THAT(buckets, testing::Contains(bucket_b.ToBucketLocator())); + EXPECT_THAT(buckets, testing::Contains(bucket_a)); + EXPECT_THAT(buckets, testing::Contains(bucket_b)); result = GetBucketsForType(kPerm); buckets = result.value(); EXPECT_EQ(1U, buckets.size()); - EXPECT_THAT(buckets, testing::Contains(bucket_c.ToBucketLocator())); + EXPECT_THAT(buckets, testing::Contains(bucket_c)); } TEST_F(QuotaManagerImplTest, GetBucketsForHost) { @@ -994,19 +1000,18 @@ TEST_F(QuotaManagerImplTest, GetBucketsForHost) { EXPECT_TRUE(bucket.ok()); BucketInfo host_b_bucket = bucket.value(); - QuotaErrorOr<std::set<BucketLocator>> result = - GetBucketsForHost("a.com", kTemp); + QuotaErrorOr<std::set<BucketInfo>> result = GetBucketsForHost("a.com", kTemp); EXPECT_TRUE(result.ok()); - std::set<BucketLocator> buckets = result.value(); + std::set<BucketInfo> buckets = result.value(); EXPECT_EQ(2U, buckets.size()); - EXPECT_THAT(buckets, testing::Contains(host_a_bucket_1.ToBucketLocator())); - EXPECT_THAT(buckets, testing::Contains(host_a_bucket_2.ToBucketLocator())); + EXPECT_THAT(buckets, testing::Contains(host_a_bucket_1)); + EXPECT_THAT(buckets, testing::Contains(host_a_bucket_2)); result = GetBucketsForHost("b.com", kPerm); buckets = result.value(); EXPECT_EQ(1U, buckets.size()); - EXPECT_THAT(buckets, testing::Contains(host_b_bucket.ToBucketLocator())); + EXPECT_THAT(buckets, testing::Contains(host_b_bucket)); } TEST_F(QuotaManagerImplTest, GetBucketsForStorageKey) { @@ -1030,14 +1035,14 @@ TEST_F(QuotaManagerImplTest, GetBucketsForStorageKey) { EXPECT_TRUE(bucket.ok()); BucketInfo bucket_c = bucket.value(); - QuotaErrorOr<std::set<BucketLocator>> result = + QuotaErrorOr<std::set<BucketInfo>> result = GetBucketsForStorageKey(storage_key_a, kTemp); EXPECT_TRUE(result.ok()); - std::set<BucketLocator> buckets = result.value(); + std::set<BucketInfo> buckets = result.value(); EXPECT_EQ(2U, buckets.size()); - EXPECT_THAT(buckets, testing::Contains(bucket_a1.ToBucketLocator())); - EXPECT_THAT(buckets, testing::Contains(bucket_a2.ToBucketLocator())); + EXPECT_THAT(buckets, testing::Contains(bucket_a1)); + EXPECT_THAT(buckets, testing::Contains(bucket_a2)); result = GetBucketsForStorageKey(storage_key_a, kPerm); EXPECT_TRUE(result.ok()); @@ -1048,7 +1053,43 @@ TEST_F(QuotaManagerImplTest, GetBucketsForStorageKey) { buckets = result.value(); EXPECT_EQ(1U, buckets.size()); - EXPECT_THAT(buckets, testing::Contains(bucket_c.ToBucketLocator())); + EXPECT_THAT(buckets, testing::Contains(bucket_c)); +} + +TEST_F(QuotaManagerImplTest, GetBucketsForStorageKey_Expiration) { + StorageKey storage_key = ToStorageKey("http://a.com/"); + + auto clock = std::make_unique<base::SimpleTestClock>(); + QuotaDatabase::SetClockForTesting(clock.get()); + clock->SetNow(base::Time::Now()); + + BucketInitParams params(storage_key, "bucket_1"); + auto bucket = UpdateOrCreateBucket(params); + EXPECT_TRUE(bucket.ok()); + BucketInfo bucket_1 = bucket.value(); + + params.name = "bucket_2"; + params.expiration = clock->Now() + base::Days(1); + bucket = UpdateOrCreateBucket(params); + EXPECT_TRUE(bucket.ok()); + BucketInfo bucket_2 = bucket.value(); + + params.name = "bucket_3"; + bucket = UpdateOrCreateBucket(params); + EXPECT_TRUE(bucket.ok()); + BucketInfo bucket_3 = bucket.value(); + + clock->Advance(base::Days(2)); + + QuotaErrorOr<std::set<BucketInfo>> result = + GetBucketsForStorageKey(storage_key, kTemp, /*delete_expired=*/true); + EXPECT_TRUE(result.ok()); + + std::set<BucketInfo> buckets = result.value(); + ASSERT_EQ(1U, buckets.size()); + EXPECT_EQ(*buckets.begin(), bucket_1); + + QuotaDatabase::SetClockForTesting(nullptr); } TEST_F(QuotaManagerImplTest, GetUsageAndQuota_Simple) { @@ -2433,17 +2474,21 @@ TEST_F(QuotaManagerImplTest, DeleteHostDataMultiple) { const BucketTableEntries& entries = DumpBucketTable(); for (const auto& entry : entries) { - if (entry.type != kTemp) + if (entry->type != kStorageTemp) continue; + absl::optional<StorageKey> storage_key = + StorageKey::Deserialize(entry->storage_key); + ASSERT_TRUE(storage_key.has_value()); + EXPECT_NE(std::string("http://foo.com/"), - entry.storage_key.origin().GetURL().spec()); + storage_key.value().origin().GetURL().spec()); EXPECT_NE(std::string("http://foo.com:1/"), - entry.storage_key.origin().GetURL().spec()); + storage_key.value().origin().GetURL().spec()); EXPECT_NE(std::string("https://foo.com/"), - entry.storage_key.origin().GetURL().spec()); + storage_key.value().origin().GetURL().spec()); EXPECT_NE(std::string("http://bar.com/"), - entry.storage_key.origin().GetURL().spec()); + std::move(storage_key).value().origin().GetURL().spec()); } global_usage_result = GetGlobalUsage(kTemp); @@ -2525,17 +2570,21 @@ TEST_F(QuotaManagerImplTest, DeleteHostDataMultipleClientsDifferentTypes) { const BucketTableEntries& entries = DumpBucketTable(); for (const auto& entry : entries) { - if (entry.type != kPerm) + if (entry->type != kStoragePerm) continue; + absl::optional<StorageKey> storage_key = + StorageKey::Deserialize(entry->storage_key); + ASSERT_TRUE(storage_key.has_value()); + EXPECT_NE(std::string("http://foo.com/"), - entry.storage_key.origin().GetURL().spec()); + storage_key.value().origin().GetURL().spec()); EXPECT_NE(std::string("http://foo.com:1/"), - entry.storage_key.origin().GetURL().spec()); + storage_key.value().origin().GetURL().spec()); EXPECT_NE(std::string("https://foo.com/"), - entry.storage_key.origin().GetURL().spec()); + storage_key.value().origin().GetURL().spec()); EXPECT_NE(std::string("http://bar.com/"), - entry.storage_key.origin().GetURL().spec()); + std::move(storage_key).value().origin().GetURL().spec()); } global_usage_result = GetGlobalUsage(kTemp); @@ -2891,32 +2940,6 @@ TEST_F(QuotaManagerImplTest, FindAndDeleteBucketDataWithDBError) { .usage); } -TEST_F(QuotaManagerImplTest, GetHostUsageForInternals) { - static const ClientBucketData kData[] = { - {"http://example.com/", kDefaultBucketName, kTemp, 400}, - {"http://example.com/", kDefaultBucketName, kPerm, 2}, - }; - MockQuotaClient* client = - CreateAndRegisterClient(QuotaClientType::kFileSystem, {kTemp, kPerm}); - RegisterClientBucketData(client, kData); - - base::test::TestFuture<int64_t> temp_future; - quota_manager_impl()->GetHostUsageForInternals( - "example.com", storage::mojom::StorageType::kTemporary, - temp_future.GetCallback()); - int64_t temp_result = temp_future.Take(); - - EXPECT_EQ(400, temp_result); - - base::test::TestFuture<int64_t> perm_future; - quota_manager_impl()->GetHostUsageForInternals( - "example.com", storage::mojom::StorageType::kPersistent, - perm_future.GetCallback()); - int64_t perm_result = perm_future.Take(); - - EXPECT_EQ(2, perm_result); -} - TEST_F(QuotaManagerImplTest, GetDiskAvailabilityAndTempPoolSize) { const int kPoolSize = 1000; const int kPerHostQuota = kPoolSize / 5; @@ -3101,9 +3124,11 @@ TEST_F(QuotaManagerImplTest, DumpBucketTable) { task_environment_.RunUntilIdle(); const BucketTableEntries& entries = DumpBucketTable(); - EXPECT_THAT(entries, testing::UnorderedElementsAre( - MatchesBucketTableEntry(kStorageKey, kTemp, 1), - MatchesBucketTableEntry(kStorageKey, kPerm, 2))); + EXPECT_THAT( + entries, + testing::UnorderedElementsAre( + MatchesBucketTableEntry(kStorageKey.Serialize(), kStorageTemp, 1), + MatchesBucketTableEntry(kStorageKey.Serialize(), kStoragePerm, 2))); } TEST_F(QuotaManagerImplTest, RetrieveBucketsTable) { @@ -3122,18 +3147,7 @@ TEST_F(QuotaManagerImplTest, RetrieveBucketsTable) { quota_manager_impl()->NotifyStorageAccessed(kStorageKey, kTemp, kAccessTime); quota_manager_impl()->NotifyStorageAccessed(kStorageKey, kPerm, kAccessTime); - - base::RunLoop run_loop; - base::Time time1 = client->IncrementMockTime(); - client->ModifyStorageKeyAndNotify(ToStorageKey("http://example.com/"), kTemp, - 10); - client->ModifyStorageKeyAndNotify(ToStorageKey("http://example.com/"), kPerm, - 10); - base::Time time2 = client->IncrementMockTime(); - client->ModifyStorageKeyAndNotify(ToStorageKey("http://example.com/"), kTemp, - 10, run_loop.QuitClosure()); - base::Time time3 = client->IncrementMockTime(); - run_loop.Run(); + const base::Time time1 = base::Time::Now(); auto temp_bucket = GetBucket(kStorageKey, kDefaultBucketName, kTemp); auto perm_bucket = GetBucket(kStorageKey, kDefaultBucketName, kPerm); @@ -3145,27 +3159,25 @@ TEST_F(QuotaManagerImplTest, RetrieveBucketsTable) { FindBucketTableEntry(bucket_table_entries, temp_bucket->id); EXPECT_TRUE(temp_entry); EXPECT_EQ(temp_entry->storage_key, kSerializedStorageKey); - EXPECT_EQ(temp_entry->host, "example.com"); - EXPECT_EQ(temp_entry->type, "temporary"); + EXPECT_EQ(temp_entry->type, kStorageTemp); EXPECT_EQ(temp_entry->name, kDefaultBucketName); EXPECT_EQ(temp_entry->use_count, 1); EXPECT_EQ(temp_entry->last_accessed, kAccessTime); - EXPECT_GE(temp_entry->last_modified, time2); - EXPECT_LE(temp_entry->last_modified, time3); - EXPECT_EQ(temp_entry->usage, 143); + EXPECT_GE(temp_entry->last_modified, kAccessTime); + EXPECT_LE(temp_entry->last_modified, time1); + EXPECT_EQ(temp_entry->usage, 123); auto* perm_entry = FindBucketTableEntry(bucket_table_entries, perm_bucket->id); EXPECT_TRUE(perm_entry); EXPECT_EQ(perm_entry->storage_key, kSerializedStorageKey); - EXPECT_EQ(perm_entry->host, "example.com"); - EXPECT_EQ(perm_entry->type, "persistent"); + EXPECT_EQ(perm_entry->type, kStoragePerm); EXPECT_EQ(perm_entry->name, kDefaultBucketName); EXPECT_EQ(perm_entry->use_count, 1); EXPECT_EQ(perm_entry->last_accessed, kAccessTime); - EXPECT_GE(perm_entry->last_modified, time1); - EXPECT_LE(perm_entry->last_modified, time2); - EXPECT_EQ(perm_entry->usage, 466); + EXPECT_GE(temp_entry->last_modified, kAccessTime); + EXPECT_LE(temp_entry->last_modified, time1); + EXPECT_EQ(perm_entry->usage, 456); } TEST_F(QuotaManagerImplTest, QuotaForEmptyHost) { diff --git a/chromium/storage/browser/quota/quota_settings.cc b/chromium/storage/browser/quota/quota_settings.cc index c2a5a209635..718e6cf09e4 100644 --- a/chromium/storage/browser/quota/quota_settings.cc +++ b/chromium/storage/browser/quota/quota_settings.cc @@ -37,7 +37,7 @@ int64_t RandomizeByPercent(int64_t value, int percent) { } QuotaSettings CalculateIncognitoDynamicSettings( - int64_t physical_memory_amount) { + uint64_t physical_memory_amount) { // The incognito pool size is a fraction of the amount of system memory. double incognito_pool_size_ratio = kIncognitoQuotaRatioLowerBound + diff --git a/chromium/storage/browser/quota/quota_settings_unittest.cc b/chromium/storage/browser/quota/quota_settings_unittest.cc index ef2bf9a1c64..84e03cb5cd6 100644 --- a/chromium/storage/browser/quota/quota_settings_unittest.cc +++ b/chromium/storage/browser/quota/quota_settings_unittest.cc @@ -8,6 +8,7 @@ #include "base/bind.h" #include "base/callback.h" #include "base/files/scoped_temp_dir.h" +#include "base/numerics/safe_conversions.h" #include "base/run_loop.h" #include "base/test/bind.h" #include "base/test/scoped_feature_list.h" @@ -22,8 +23,8 @@ using ::testing::_; namespace { -constexpr int64_t kLowPhysicalMemory = 1024 * 1024; -constexpr int64_t kHighPhysicalMemory = 65536 * kLowPhysicalMemory; +constexpr uint64_t kLowPhysicalMemory = 1024 * 1024; +constexpr uint64_t kHighPhysicalMemory = 65536 * kLowPhysicalMemory; } // namespace @@ -33,7 +34,7 @@ class MockQuotaDeviceInfoHelper : public QuotaDeviceInfoHelper { public: MockQuotaDeviceInfoHelper() = default; MOCK_CONST_METHOD1(AmountOfTotalDiskSpace, int64_t(const base::FilePath&)); - MOCK_CONST_METHOD0(AmountOfPhysicalMemory, int64_t()); + MOCK_CONST_METHOD0(AmountOfPhysicalMemory, uint64_t()); }; class QuotaSettingsTest : public testing::Test { @@ -71,23 +72,25 @@ class QuotaSettingsIncognitoTest : public QuotaSettingsTest { protected: void SetUpDeviceInfoHelper(const int expected_calls, - const int64_t physical_memory_amount) { + const uint64_t physical_memory_amount) { ON_CALL(device_info_helper_, AmountOfPhysicalMemory()) .WillByDefault(::testing::Return(physical_memory_amount)); EXPECT_CALL(device_info_helper_, AmountOfPhysicalMemory()) .Times(expected_calls); } - void GetAndTestSettings(const int64_t physical_memory_amount) { + void GetAndTestSettings(const uint64_t physical_memory_amount) { absl::optional<QuotaSettings> settings = GetSettings(true, &device_info_helper_); ASSERT_TRUE(settings.has_value()); + const uint64_t pool_size = + base::checked_cast<uint64_t>(settings->pool_size); EXPECT_LE( physical_memory_amount * GetIncognitoQuotaRatioLowerBound_ForTesting(), - settings->pool_size); + pool_size); EXPECT_GE( physical_memory_amount * GetIncognitoQuotaRatioUpperBound_ForTesting(), - settings->pool_size); + pool_size); } private: diff --git a/chromium/storage/browser/quota/special_storage_policy.h b/chromium/storage/browser/quota/special_storage_policy.h index f59e384cdbc..2d3015e4aed 100644 --- a/chromium/storage/browser/quota/special_storage_policy.h +++ b/chromium/storage/browser/quota/special_storage_policy.h @@ -9,7 +9,6 @@ #include "base/memory/ref_counted.h" #include "base/observer_list.h" #include "base/sequence_checker.h" -#include "services/network/public/cpp/session_cookie_delete_predicate.h" class GURL; @@ -80,16 +79,6 @@ class COMPONENT_EXPORT(STORAGE_BROWSER) SpecialStoragePolicy // Returns true if some origins are only allowed session-only storage. virtual bool HasSessionOnlyOrigins() = 0; - // Returns a predicate that takes the domain of a cookie and a bool whether - // the cookie is secure and returns true if the cookie should be deleted on - // exit. - // If |HasSessionOnlyOrigins()| is true a non-null callback is returned. - // It uses domain matching as described in section 5.1.3 of RFC 6265 to - // identify content setting rules that could have influenced the cookie - // when it was created. - virtual network::DeleteCookiePredicate - CreateDeleteCookieOnExitPredicate() = 0; - // Adds/removes an observer, the policy does not take // ownership of the observer. Should only be called on the IO thread. void AddObserver(Observer* observer); diff --git a/chromium/storage/browser/quota/storage_directory_util.cc b/chromium/storage/browser/quota/storage_directory_util.cc index 3e3837d9c95..e818ca06d04 100644 --- a/chromium/storage/browser/quota/storage_directory_util.cc +++ b/chromium/storage/browser/quota/storage_directory_util.cc @@ -25,6 +25,7 @@ base::FilePath CreateClientBucketPath(const base::FilePath& profile_path, case QuotaClientType::kIndexedDatabase: return bucket_directory.Append(kIndexedDbDirectory); case QuotaClientType::kBackgroundFetch: + return bucket_directory.Append(kBackgroundFetchDirectory); case QuotaClientType::kServiceWorkerCache: return bucket_directory.Append(kCacheStorageDirectory); case QuotaClientType::kServiceWorker: diff --git a/chromium/storage/browser/quota/usage_tracker.cc b/chromium/storage/browser/quota/usage_tracker.cc index bacec98ed25..ddf43af85b1 100644 --- a/chromium/storage/browser/quota/usage_tracker.cc +++ b/chromium/storage/browser/quota/usage_tracker.cc @@ -58,22 +58,6 @@ void UsageTracker::GetGlobalUsage(UsageCallback callback) { weak_factory_.GetWeakPtr())); } -void UsageTracker::GetHostUsageWithBreakdown( - const std::string& host, - UsageWithBreakdownCallback callback) { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - std::vector<UsageWithBreakdownCallback>& host_callbacks = - host_usage_callbacks_[host]; - host_callbacks.emplace_back(std::move(callback)); - if (host_callbacks.size() > 1) - return; - - quota_manager_impl_->GetBucketsForHost( - host, type_, - base::BindOnce(&UsageTracker::DidGetBucketsForHost, - weak_factory_.GetWeakPtr(), host)); -} - void UsageTracker::GetStorageKeyUsageWithBreakdown( const blink::StorageKey& storage_key, UsageWithBreakdownCallback callback) { @@ -193,7 +177,7 @@ void UsageTracker::SetUsageCacheEnabled(QuotaClientType client_type, } void UsageTracker::DidGetBucketsForType( - QuotaErrorOr<std::set<BucketLocator>> result) { + QuotaErrorOr<std::set<BucketInfo>> result) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); auto info = std::make_unique<AccumulateInfo>(); if (!result.ok()) { @@ -204,12 +188,15 @@ void UsageTracker::DidGetBucketsForType( return; } - const std::set<BucketLocator>& buckets = result.value(); + const std::set<BucketInfo>& buckets = result.value(); if (buckets.empty()) { FinallySendGlobalUsage(std::move(info)); return; } + std::set<BucketLocator> bucket_locators = + BucketInfosToBucketLocators(buckets); + auto* info_ptr = info.get(); base::RepeatingClosure barrier = base::BarrierClosure( client_tracker_count_, @@ -219,7 +206,7 @@ void UsageTracker::DidGetBucketsForType( for (const auto& client_type_and_trackers : client_tracker_map_) { for (const auto& client_tracker : client_type_and_trackers.second) { client_tracker->GetBucketsUsage( - buckets, + bucket_locators, // base::Unretained usage is safe here because BarrierClosure holds // the std::unque_ptr that keeps AccumulateInfo alive, and the // BarrierClosure will outlive all the AccumulateClientGlobalUsage @@ -231,50 +218,9 @@ void UsageTracker::DidGetBucketsForType( } } -void UsageTracker::DidGetBucketsForHost( - const std::string& host, - QuotaErrorOr<std::set<BucketLocator>> result) { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - auto info = std::make_unique<AccumulateInfo>(); - if (!result.ok()) { - // Return with invalid values on error. - info->usage = -1; - info->unlimited_usage = -1; - FinallySendHostUsageWithBreakdown(std::move(info), host); - return; - } - - const std::set<BucketLocator>& buckets = result.value(); - if (buckets.empty()) { - FinallySendHostUsageWithBreakdown(std::move(info), host); - return; - } - - auto* info_ptr = info.get(); - base::RepeatingClosure barrier = base::BarrierClosure( - client_tracker_count_, - base::BindOnce(&UsageTracker::FinallySendHostUsageWithBreakdown, - weak_factory_.GetWeakPtr(), std::move(info), host)); - - for (const auto& client_type_and_trackers : client_tracker_map_) { - for (const auto& client_tracker : client_type_and_trackers.second) { - client_tracker->GetBucketsUsage( - buckets, - // base::Unretained usage is safe here because BarrierClosure holds - // the std::unque_ptr that keeps AccumulateInfo alive, and the - // BarrierClosure will outlive all the AccumulateClientGlobalUsage - // closures. - base::BindOnce(&UsageTracker::AccumulateClientUsageWithBreakdown, - weak_factory_.GetWeakPtr(), barrier, - base::Unretained(info_ptr), - client_type_and_trackers.first)); - } - } -} - void UsageTracker::DidGetBucketsForStorageKey( const blink::StorageKey& storage_key, - QuotaErrorOr<std::set<BucketLocator>> result) { + QuotaErrorOr<std::set<BucketInfo>> result) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); auto info = std::make_unique<AccumulateInfo>(); if (!result.ok()) { @@ -285,12 +231,15 @@ void UsageTracker::DidGetBucketsForStorageKey( return; } - const std::set<BucketLocator>& buckets = result.value(); + const std::set<BucketInfo>& buckets = result.value(); if (buckets.empty()) { FinallySendStorageKeyUsageWithBreakdown(std::move(info), storage_key); return; } + std::set<BucketLocator> bucket_locators = + BucketInfosToBucketLocators(buckets); + auto* info_ptr = info.get(); base::RepeatingClosure barrier = base::BarrierClosure( client_tracker_count_, @@ -300,7 +249,7 @@ void UsageTracker::DidGetBucketsForStorageKey( for (const auto& client_type_and_trackers : client_tracker_map_) { for (const auto& client_tracker : client_type_and_trackers.second) { client_tracker->GetBucketsUsage( - buckets, + bucket_locators, // base::Unretained usage is safe here because BarrierClosure holds // the std::unque_ptr that keeps AccumulateInfo alive, and the // BarrierClosure will outlive all the AccumulateClientGlobalUsage @@ -388,24 +337,6 @@ void UsageTracker::FinallySendGlobalUsage( std::move(callback).Run(info->usage, info->unlimited_usage); } -void UsageTracker::FinallySendHostUsageWithBreakdown( - std::unique_ptr<AccumulateInfo> info, - const std::string& host) { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - auto it = host_usage_callbacks_.find(host); - if (it == host_usage_callbacks_.end()) - return; - - std::vector<UsageWithBreakdownCallback> pending_callbacks; - pending_callbacks.swap(it->second); - DCHECK(pending_callbacks.size() > 0) - << "host_usage_callbacks_ should only have non-empty callback lists"; - host_usage_callbacks_.erase(it); - - for (auto& callback : pending_callbacks) - std::move(callback).Run(info->usage, info->usage_breakdown->Clone()); -} - void UsageTracker::FinallySendStorageKeyUsageWithBreakdown( std::unique_ptr<AccumulateInfo> info, const blink::StorageKey& storage_key) { diff --git a/chromium/storage/browser/quota/usage_tracker.h b/chromium/storage/browser/quota/usage_tracker.h index 10dc50e1306..5ddf0144af5 100644 --- a/chromium/storage/browser/quota/usage_tracker.h +++ b/chromium/storage/browser/quota/usage_tracker.h @@ -64,14 +64,6 @@ class COMPONENT_EXPORT(STORAGE_BROWSER) UsageTracker // a bucket. void GetGlobalUsage(UsageCallback callback); - // Retrieves all buckets for host from QuotaDatabase and requests bucket usage - // from each registered client. Returns cached bucket usage if one exists for - // a bucket. - // TODO(crbug/1202325): Remove once all usages move to - // GetStorageKeyUsageWithBreakdown. - void GetHostUsageWithBreakdown(const std::string& host, - UsageWithBreakdownCallback callback); - // Retrieves all buckets for a `storage_key` from QuotaDatabase and requests // bucket usage from each registered client. Returns cached bucket usage if // one exists for a bucket. @@ -105,11 +97,13 @@ class COMPONENT_EXPORT(STORAGE_BROWSER) UsageTracker // recording. std::map<blink::StorageKey, int64_t> GetCachedStorageKeysUsage() const; - // Checks if there are ongoing tasks to get global or host usage. Used to - // prevent a UsageTracker reset from happening before a task is complete. + // Checks if there are ongoing tasks to get usage. Used to prevent a + // UsageTracker reset from happening before a task is complete. bool IsWorking() const { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - return !global_usage_callbacks_.empty() || !host_usage_callbacks_.empty(); + return !global_usage_callbacks_.empty() || + !storage_key_usage_callbacks_.empty() || + !bucket_usage_callbacks_.empty(); } // Sets if a `storage_key` for `client_type` should / should not be excluded @@ -122,11 +116,9 @@ class COMPONENT_EXPORT(STORAGE_BROWSER) UsageTracker struct AccumulateInfo; friend class ClientUsageTracker; - void DidGetBucketsForType(QuotaErrorOr<std::set<BucketLocator>> result); - void DidGetBucketsForHost(const std::string& host, - QuotaErrorOr<std::set<BucketLocator>> result); + void DidGetBucketsForType(QuotaErrorOr<std::set<BucketInfo>> result); void DidGetBucketsForStorageKey(const blink::StorageKey& storage_key, - QuotaErrorOr<std::set<BucketLocator>> result); + QuotaErrorOr<std::set<BucketInfo>> result); void DidGetBucketForUsage(QuotaClientType client_type, int64_t delta, QuotaErrorOr<BucketInfo> result); @@ -142,8 +134,6 @@ class COMPONENT_EXPORT(STORAGE_BROWSER) UsageTracker int64_t unlimited_usage); void FinallySendGlobalUsage(std::unique_ptr<AccumulateInfo> info); - void FinallySendHostUsageWithBreakdown(std::unique_ptr<AccumulateInfo> info, - const std::string& host); void FinallySendStorageKeyUsageWithBreakdown( std::unique_ptr<AccumulateInfo> info, const blink::StorageKey& storage_key); @@ -162,8 +152,6 @@ class COMPONENT_EXPORT(STORAGE_BROWSER) UsageTracker int client_tracker_count_ = 0; std::vector<UsageCallback> global_usage_callbacks_; - std::map<std::string, std::vector<UsageWithBreakdownCallback>> - host_usage_callbacks_; std::map<blink::StorageKey, std::vector<UsageWithBreakdownCallback>> storage_key_usage_callbacks_; std::map<BucketLocator, std::vector<UsageWithBreakdownCallback>> diff --git a/chromium/storage/browser/quota/usage_tracker_unittest.cc b/chromium/storage/browser/quota/usage_tracker_unittest.cc index 1cf26dbc740..054c4b41088 100644 --- a/chromium/storage/browser/quota/usage_tracker_unittest.cc +++ b/chromium/storage/browser/quota/usage_tracker_unittest.cc @@ -135,14 +135,6 @@ class UsageTrackerTest : public testing::Test { *unlimited_usage = future.Get<1>(); } - std::pair<int64_t, blink::mojom::UsageBreakdownPtr> GetHostUsageWithBreakdown( - const std::string& host) { - base::test::TestFuture<int64_t, blink::mojom::UsageBreakdownPtr> future; - usage_tracker_->GetHostUsageWithBreakdown(host, future.GetCallback()); - return std::make_pair(future.Get<0>(), - std::move(std::get<1>(future.Take()))); - } - std::pair<int64_t, blink::mojom::UsageBreakdownPtr> GetStorageKeyUsageWithBreakdown(const blink::StorageKey& storage_key) { base::test::TestFuture<int64_t, blink::mojom::UsageBreakdownPtr> future; @@ -210,6 +202,8 @@ class UsageTrackerTest : public testing::Test { quota_manager_->SetBootstrapDisabledForTesting(disable); } + UsageTracker* usage_tracker() { return usage_tracker_.get(); } + private: base::flat_map<mojom::QuotaClient*, QuotaClientType> GetQuotaClientMap() { base::flat_map<mojom::QuotaClient*, QuotaClientType> client_map; @@ -231,8 +225,6 @@ class UsageTrackerTest : public testing::Test { TEST_F(UsageTrackerTest, GrantAndRevokeUnlimitedStorage) { int64_t usage = 0; int64_t unlimited_usage = 0; - blink::mojom::UsageBreakdownPtr host_usage_breakdown_expected = - blink::mojom::UsageBreakdown::New(); blink::mojom::UsageBreakdownPtr storage_key_usage_breakdown_expected = blink::mojom::UsageBreakdown::New(); blink::mojom::UsageBreakdownPtr bucket_usage_breakdown_expected = @@ -243,7 +235,6 @@ TEST_F(UsageTrackerTest, GrantAndRevokeUnlimitedStorage) { const StorageKey storage_key = StorageKey::CreateFromStringForTesting("http://example.com"); - const std::string& host = storage_key.origin().host(); BucketLocator bucket = CreateBucket(storage_key, kDefaultBucketName); @@ -251,11 +242,6 @@ TEST_F(UsageTrackerTest, GrantAndRevokeUnlimitedStorage) { GetGlobalUsage(&usage, &unlimited_usage); EXPECT_EQ(100, usage); EXPECT_EQ(0, unlimited_usage); - host_usage_breakdown_expected->fileSystem = 100; - std::pair<int64_t, blink::mojom::UsageBreakdownPtr> host_usage_breakdown = - GetHostUsageWithBreakdown(host); - EXPECT_EQ(100, host_usage_breakdown.first); - EXPECT_EQ(host_usage_breakdown_expected, host_usage_breakdown.second); storage_key_usage_breakdown_expected->fileSystem = 100; std::pair<int64_t, blink::mojom::UsageBreakdownPtr> storage_key_usage_breakdown = @@ -273,9 +259,6 @@ TEST_F(UsageTrackerTest, GrantAndRevokeUnlimitedStorage) { GetGlobalUsage(&usage, &unlimited_usage); EXPECT_EQ(100, usage); EXPECT_EQ(100, unlimited_usage); - host_usage_breakdown = GetHostUsageWithBreakdown(host); - EXPECT_EQ(100, host_usage_breakdown.first); - EXPECT_EQ(host_usage_breakdown_expected, host_usage_breakdown.second); storage_key_usage_breakdown = GetStorageKeyUsageWithBreakdown(storage_key); EXPECT_EQ(100, storage_key_usage_breakdown.first); EXPECT_EQ(storage_key_usage_breakdown_expected, @@ -288,9 +271,6 @@ TEST_F(UsageTrackerTest, GrantAndRevokeUnlimitedStorage) { GetGlobalUsage(&usage, &unlimited_usage); EXPECT_EQ(100, usage); EXPECT_EQ(0, unlimited_usage); - GetHostUsageWithBreakdown(host); - EXPECT_EQ(100, host_usage_breakdown.first); - EXPECT_EQ(host_usage_breakdown_expected, host_usage_breakdown.second); GetStorageKeyUsageWithBreakdown(storage_key); EXPECT_EQ(100, storage_key_usage_breakdown.first); EXPECT_EQ(storage_key_usage_breakdown_expected, @@ -303,8 +283,6 @@ TEST_F(UsageTrackerTest, GrantAndRevokeUnlimitedStorage) { TEST_F(UsageTrackerTest, CacheDisabledClientTest) { int64_t usage = 0; int64_t unlimited_usage = 0; - blink::mojom::UsageBreakdownPtr host_usage_breakdown_expected = - blink::mojom::UsageBreakdown::New(); blink::mojom::UsageBreakdownPtr storage_key_usage_breakdown_expected = blink::mojom::UsageBreakdown::New(); blink::mojom::UsageBreakdownPtr bucket_usage_breakdown_expected = @@ -312,7 +290,6 @@ TEST_F(UsageTrackerTest, CacheDisabledClientTest) { const StorageKey storage_key = StorageKey::CreateFromStringForTesting("http://example.com"); - const std::string& host = storage_key.origin().host(); BucketLocator bucket = CreateBucket(storage_key, kDefaultBucketName); @@ -320,11 +297,6 @@ TEST_F(UsageTrackerTest, CacheDisabledClientTest) { GetGlobalUsage(&usage, &unlimited_usage); EXPECT_EQ(100, usage); EXPECT_EQ(0, unlimited_usage); - host_usage_breakdown_expected->fileSystem = 100; - std::pair<int64_t, blink::mojom::UsageBreakdownPtr> host_usage_breakdown = - GetHostUsageWithBreakdown(host); - EXPECT_EQ(100, host_usage_breakdown.first); - EXPECT_EQ(host_usage_breakdown_expected, host_usage_breakdown.second); storage_key_usage_breakdown_expected->fileSystem = 100; std::pair<int64_t, blink::mojom::UsageBreakdownPtr> storage_key_usage_breakdown = @@ -342,9 +314,6 @@ TEST_F(UsageTrackerTest, CacheDisabledClientTest) { GetGlobalUsage(&usage, &unlimited_usage); EXPECT_EQ(100, usage); EXPECT_EQ(0, unlimited_usage); - host_usage_breakdown = GetHostUsageWithBreakdown(host); - EXPECT_EQ(100, host_usage_breakdown.first); - EXPECT_EQ(host_usage_breakdown_expected, host_usage_breakdown.second); storage_key_usage_breakdown = GetStorageKeyUsageWithBreakdown(storage_key); EXPECT_EQ(100, storage_key_usage_breakdown.first); EXPECT_EQ(storage_key_usage_breakdown_expected, @@ -361,10 +330,6 @@ TEST_F(UsageTrackerTest, CacheDisabledClientTest) { GetGlobalUsage(&usage, &unlimited_usage); EXPECT_EQ(400, usage); EXPECT_EQ(400, unlimited_usage); - host_usage_breakdown = GetHostUsageWithBreakdown(host); - host_usage_breakdown_expected->fileSystem = 400; - EXPECT_EQ(400, host_usage_breakdown.first); - EXPECT_EQ(host_usage_breakdown_expected, host_usage_breakdown.second); storage_key_usage_breakdown = GetStorageKeyUsageWithBreakdown(storage_key); storage_key_usage_breakdown_expected->fileSystem = 400; EXPECT_EQ(400, storage_key_usage_breakdown.first); @@ -379,15 +344,11 @@ TEST_F(UsageTrackerTest, CacheDisabledClientTest) { GetGlobalUsage(&usage, &unlimited_usage); EXPECT_EQ(400, usage); EXPECT_EQ(0, unlimited_usage); - host_usage_breakdown = GetHostUsageWithBreakdown(host); - EXPECT_EQ(400, host_usage_breakdown.first); - EXPECT_EQ(host_usage_breakdown_expected, host_usage_breakdown.second); storage_key_usage_breakdown = GetStorageKeyUsageWithBreakdown(storage_key); EXPECT_EQ(400, storage_key_usage_breakdown.first); EXPECT_EQ(storage_key_usage_breakdown_expected, storage_key_usage_breakdown.second); bucket_usage_breakdown = GetBucketUsageWithBreakdown(bucket); - EXPECT_EQ(400, host_usage_breakdown.first); EXPECT_EQ(bucket_usage_breakdown_expected, bucket_usage_breakdown.second); SetUsageCacheEnabled(storage_key, true); @@ -396,10 +357,6 @@ TEST_F(UsageTrackerTest, CacheDisabledClientTest) { GetGlobalUsage(&usage, &unlimited_usage); EXPECT_EQ(500, usage); EXPECT_EQ(0, unlimited_usage); - host_usage_breakdown = GetHostUsageWithBreakdown(host); - host_usage_breakdown_expected->fileSystem = 500; - EXPECT_EQ(500, host_usage_breakdown.first); - EXPECT_EQ(host_usage_breakdown_expected, host_usage_breakdown.second); storage_key_usage_breakdown = GetStorageKeyUsageWithBreakdown(storage_key); storage_key_usage_breakdown_expected->fileSystem = 500; EXPECT_EQ(500, storage_key_usage_breakdown.first); @@ -577,10 +534,52 @@ TEST_F(UsageTrackerTest, QuotaDatabaseDisabled) { const StorageKey kStorageKey = StorageKey::CreateFromStringForTesting("http://example.com"); - std::pair<int64_t, blink::mojom::UsageBreakdownPtr> host_usage_breakdown = - GetHostUsageWithBreakdown(kStorageKey.origin().host()); - EXPECT_EQ(host_usage_breakdown.first, -1); - EXPECT_EQ(host_usage_breakdown.second, blink::mojom::UsageBreakdown::New()); + std::pair<int64_t, blink::mojom::UsageBreakdownPtr> + storage_key_usage_breakdown = + GetStorageKeyUsageWithBreakdown(kStorageKey); + EXPECT_EQ(storage_key_usage_breakdown.first, -1); + EXPECT_EQ(storage_key_usage_breakdown.second, + blink::mojom::UsageBreakdown::New()); +} + +TEST_F(UsageTrackerTest, IsWorking) { + const StorageKey kStorageKey = + StorageKey::CreateFromStringForTesting("http://example.com"); + BucketLocator bucket = CreateBucket(kStorageKey, kDefaultBucketName); + UpdateUsageWithoutNotification(bucket, 100); + + EXPECT_FALSE(usage_tracker()->IsWorking()); + + // UsageTracker::GetBucketUsage task. + base::test::TestFuture<int64_t, blink::mojom::UsageBreakdownPtr> + bucket_usage_future; + usage_tracker()->GetBucketUsageWithBreakdown( + bucket, bucket_usage_future.GetCallback()); + + EXPECT_TRUE(usage_tracker()->IsWorking()); + + ASSERT_TRUE(bucket_usage_future.Wait()); + EXPECT_FALSE(usage_tracker()->IsWorking()); + + // UsageTracker::GetStorageKeyUsage task. + base::test::TestFuture<int64_t, blink::mojom::UsageBreakdownPtr> + storage_key_usage_future; + usage_tracker()->GetStorageKeyUsageWithBreakdown( + kStorageKey, storage_key_usage_future.GetCallback()); + + EXPECT_TRUE(usage_tracker()->IsWorking()); + + ASSERT_TRUE(storage_key_usage_future.Wait()); + EXPECT_FALSE(usage_tracker()->IsWorking()); + + // UsageTracker::GetGlobalUsage task. + base::test::TestFuture<int64_t, int64_t> global_usage_future; + usage_tracker()->GetGlobalUsage(global_usage_future.GetCallback()); + + EXPECT_TRUE(usage_tracker()->IsWorking()); + + ASSERT_TRUE(global_usage_future.Wait()); + EXPECT_FALSE(usage_tracker()->IsWorking()); } } // namespace storage diff --git a/chromium/storage/common/file_system/file_system_types.h b/chromium/storage/common/file_system/file_system_types.h index e5630d1279f..4df4497e1d9 100644 --- a/chromium/storage/common/file_system/file_system_types.h +++ b/chromium/storage/common/file_system/file_system_types.h @@ -98,11 +98,6 @@ enum FileSystemType { // file which must go away when the blob's last reference is dropped. kFileSystemTypeForTransientFile, - // Sandboxed private filesystem. This filesystem cannot be opened - // via regular OpenFileSystem, and provides private filesystem space for - // given identifier in each origin. - kFileSystemTypePluginPrivate, - // A filesystem that is mounted via the FileSystemProvider API. kFileSystemTypeProvided, diff --git a/chromium/storage/common/file_system/file_system_util.cc b/chromium/storage/common/file_system/file_system_util.cc index 1dd214bda56..bb541ce4612 100644 --- a/chromium/storage/common/file_system/file_system_util.cc +++ b/chromium/storage/common/file_system/file_system_util.cc @@ -263,8 +263,6 @@ std::string GetFileSystemTypeString(FileSystemType type) { return "LocalForPlatformApp"; case kFileSystemTypeForTransientFile: return "TransientFile"; - case kFileSystemTypePluginPrivate: - return "PluginPrivate"; case kFileSystemTypeProvided: return "Provided"; case kFileSystemTypeDeviceMediaAsFileStorage: |