summaryrefslogtreecommitdiff
path: root/chromium/storage
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2022-05-17 17:24:03 +0200
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2022-06-22 07:51:41 +0000
commit774f54339e5db91f785733232d3950366db65d07 (patch)
tree068e1b47bd1af94d77094ed12b604a6b83d9c22a /chromium/storage
parentf7eaed5286974984ba5f9e3189d8f49d03e99f81 (diff)
downloadqtwebengine-chromium-774f54339e5db91f785733232d3950366db65d07.tar.gz
BASELINE: Update Chromium to 102.0.5005.57
Change-Id: I885f714bb40ee724c28f94ca6bd8dbdb39915158 Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
Diffstat (limited to 'chromium/storage')
-rw-r--r--chromium/storage/OWNERS9
-rw-r--r--chromium/storage/browser/BUILD.gn9
-rw-r--r--chromium/storage/browser/blob/OWNERS3
-rw-r--r--chromium/storage/browser/blob/blob_builder_from_stream.cc2
-rw-r--r--chromium/storage/browser/blob/blob_builder_from_stream_unittest.cc1
-rw-r--r--chromium/storage/browser/blob/blob_data_item.h1
-rw-r--r--chromium/storage/browser/blob/blob_impl.cc2
-rw-r--r--chromium/storage/browser/blob/blob_impl_unittest.cc1
-rw-r--r--chromium/storage/browser/blob/blob_reader.cc2
-rw-r--r--chromium/storage/browser/blob/blob_registry_impl.cc26
-rw-r--r--chromium/storage/browser/blob/blob_registry_impl.h6
-rw-r--r--chromium/storage/browser/blob/blob_registry_impl_unittest.cc5
-rw-r--r--chromium/storage/browser/blob/blob_storage_context.cc2
-rw-r--r--chromium/storage/browser/blob/blob_storage_context_mojo_unittest.cc2
-rw-r--r--chromium/storage/browser/blob/blob_transport_strategy_unittest.cc2
-rw-r--r--chromium/storage/browser/blob/write_blob_to_file.cc1
-rw-r--r--chromium/storage/browser/database/OWNERS4
-rw-r--r--chromium/storage/browser/database/database_quota_client_unittest.cc33
-rw-r--r--chromium/storage/browser/database/database_tracker.cc2
-rw-r--r--chromium/storage/browser/database/database_tracker.h4
-rw-r--r--chromium/storage/browser/database/database_tracker_unittest.cc3
-rw-r--r--chromium/storage/browser/file_system/async_file_util.h8
-rw-r--r--chromium/storage/browser/file_system/async_file_util_adapter.cc1
-rw-r--r--chromium/storage/browser/file_system/copy_or_move_hook_delegate.cc61
-rw-r--r--chromium/storage/browser/file_system/copy_or_move_hook_delegate.h160
-rw-r--r--chromium/storage/browser/file_system/copy_or_move_operation_delegate.cc227
-rw-r--r--chromium/storage/browser/file_system/copy_or_move_operation_delegate.h21
-rw-r--r--chromium/storage/browser/file_system/copy_or_move_operation_delegate_unittest.cc256
-rw-r--r--chromium/storage/browser/file_system/dragged_file_util_unittest.cc10
-rw-r--r--chromium/storage/browser/file_system/external_mount_points_unittest.cc7
-rw-r--r--chromium/storage/browser/file_system/file_stream_reader_test.h6
-rw-r--r--chromium/storage/browser/file_system/file_stream_writer_test.h5
-rw-r--r--chromium/storage/browser/file_system/file_system_context.cc13
-rw-r--r--chromium/storage/browser/file_system/file_system_context.h23
-rw-r--r--chromium/storage/browser/file_system/file_system_context_unittest.cc5
-rw-r--r--chromium/storage/browser/file_system/file_system_operation.h161
-rw-r--r--chromium/storage/browser/file_system/file_system_operation_impl.cc14
-rw-r--r--chromium/storage/browser/file_system/file_system_operation_impl.h4
-rw-r--r--chromium/storage/browser/file_system/file_system_operation_impl_unittest.cc32
-rw-r--r--chromium/storage/browser/file_system/file_system_operation_impl_write_unittest.cc22
-rw-r--r--chromium/storage/browser/file_system/file_system_operation_runner.cc50
-rw-r--r--chromium/storage/browser/file_system/file_system_operation_runner.h42
-rw-r--r--chromium/storage/browser/file_system/file_system_quota_client.cc4
-rw-r--r--chromium/storage/browser/file_system/file_system_quota_client_unittest.cc14
-rw-r--r--chromium/storage/browser/file_system/file_system_url_unittest.cc5
-rw-r--r--chromium/storage/browser/file_system/file_writer_delegate_unittest.cc7
-rw-r--r--chromium/storage/browser/file_system/filesystem_proxy_file_stream_reader_unittest.cc1
-rw-r--r--chromium/storage/browser/file_system/isolated_context_unittest.cc14
-rw-r--r--chromium/storage/browser/file_system/local_file_stream_reader_unittest.cc1
-rw-r--r--chromium/storage/browser/file_system/native_file_util.cc1
-rw-r--r--chromium/storage/browser/file_system/native_file_util_unittest.cc2
-rw-r--r--chromium/storage/browser/file_system/obfuscated_file_util.cc68
-rw-r--r--chromium/storage/browser/file_system/obfuscated_file_util.h17
-rw-r--r--chromium/storage/browser/file_system/obfuscated_file_util_unittest.cc22
-rw-r--r--chromium/storage/browser/file_system/plugin_private_file_system_backend.cc80
-rw-r--r--chromium/storage/browser/file_system/plugin_private_file_system_backend.h22
-rw-r--r--chromium/storage/browser/file_system/quota/quota_backend_impl_unittest.cc6
-rw-r--r--chromium/storage/browser/file_system/sandbox_directory_database.cc5
-rw-r--r--chromium/storage/browser/file_system/sandbox_file_stream_reader_unittest.cc15
-rw-r--r--chromium/storage/browser/file_system/sandbox_file_stream_writer.cc4
-rw-r--r--chromium/storage/browser/file_system/sandbox_file_stream_writer_unittest.cc12
-rw-r--r--chromium/storage/browser/file_system/sandbox_file_system_backend_delegate.cc8
-rw-r--r--chromium/storage/browser/file_system/sandbox_file_system_backend_delegate.h6
-rw-r--r--chromium/storage/browser/file_system/sandbox_file_system_backend_delegate_unittest.cc5
-rw-r--r--chromium/storage/browser/file_system/sandbox_file_system_backend_unittest.cc25
-rw-r--r--chromium/storage/browser/file_system/sandbox_origin_database_unittest.cc8
-rw-r--r--chromium/storage/browser/file_system/task_runner_bound_observer_list.h1
-rw-r--r--chromium/storage/browser/quota/OWNERS6
-rw-r--r--chromium/storage/browser/quota/quota_callbacks.h1
-rw-r--r--chromium/storage/browser/quota/quota_client_type.cc1
-rw-r--r--chromium/storage/browser/quota/quota_client_type.h1
-rw-r--r--chromium/storage/browser/quota/quota_database.cc294
-rw-r--r--chromium/storage/browser/quota/quota_database.h63
-rw-r--r--chromium/storage/browser/quota/quota_database_migrations.cc10
-rw-r--r--chromium/storage/browser/quota/quota_database_migrations_unittest.cc18
-rw-r--r--chromium/storage/browser/quota/quota_database_unittest.cc552
-rw-r--r--chromium/storage/browser/quota/quota_features.cc2
-rw-r--r--chromium/storage/browser/quota/quota_internals.mojom34
-rw-r--r--chromium/storage/browser/quota/quota_manager_impl.cc591
-rw-r--r--chromium/storage/browser/quota/quota_manager_impl.h51
-rw-r--r--chromium/storage/browser/quota/quota_manager_proxy.cc60
-rw-r--r--chromium/storage/browser/quota/quota_manager_proxy.h29
-rw-r--r--chromium/storage/browser/quota/quota_manager_proxy_unittest.cc109
-rw-r--r--chromium/storage/browser/quota/quota_manager_unittest.cc325
-rw-r--r--chromium/storage/browser/quota/quota_settings.cc1
-rw-r--r--chromium/storage/browser/quota/quota_settings.h6
-rw-r--r--chromium/storage/browser/quota/quota_temporary_storage_evictor.h1
-rw-r--r--chromium/storage/browser/quota/special_storage_policy.cc2
-rw-r--r--chromium/storage/browser/quota/storage_directory.cc62
-rw-r--r--chromium/storage/browser/quota/storage_directory.h51
-rw-r--r--chromium/storage/browser/quota/storage_directory_unittest.cc82
-rw-r--r--chromium/storage/browser/quota/storage_policy_observer.cc1
-rw-r--r--chromium/storage/browser/quota/usage_tracker.cc7
-rw-r--r--chromium/storage/browser/quota/usage_tracker_unittest.cc15
-rw-r--r--chromium/storage/common/database/database_identifier.cc3
-rw-r--r--chromium/storage/common/database/database_identifier_unittest.cc3
-rw-r--r--chromium/storage/common/file_system/OWNERS5
97 files changed, 2721 insertions, 1266 deletions
diff --git a/chromium/storage/OWNERS b/chromium/storage/OWNERS
index 7ccd317ff28..16d75f83b76 100644
--- a/chromium/storage/OWNERS
+++ b/chromium/storage/OWNERS
@@ -1,6 +1,9 @@
set noparent
+
+# Primary
+ayui@chromium.org
+
+# Secondary
+asully@chromium.org
dmurph@chromium.org
jsbell@chromium.org
-pwnall@chromium.org
-mek@chromium.org
-kinuko@chromium.org
diff --git a/chromium/storage/browser/BUILD.gn b/chromium/storage/browser/BUILD.gn
index 5e80213ac73..088adb899b0 100644
--- a/chromium/storage/browser/BUILD.gn
+++ b/chromium/storage/browser/BUILD.gn
@@ -75,6 +75,8 @@ component("browser") {
"file_system/async_file_util_adapter.cc",
"file_system/async_file_util_adapter.h",
"file_system/copy_or_move_file_validator.h",
+ "file_system/copy_or_move_hook_delegate.cc",
+ "file_system/copy_or_move_hook_delegate.h",
"file_system/copy_or_move_operation_delegate.cc",
"file_system/copy_or_move_operation_delegate.h",
"file_system/dragged_file_util.cc",
@@ -212,6 +214,8 @@ component("browser") {
"quota/quota_temporary_storage_evictor.h",
"quota/special_storage_policy.cc",
"quota/special_storage_policy.h",
+ "quota/storage_directory.cc",
+ "quota/storage_directory.h",
"quota/storage_policy_observer.cc",
"quota/storage_policy_observer.h",
"quota/usage_tracker.cc",
@@ -327,9 +331,11 @@ source_set("unittests") {
"file_system/transient_file_util_unittest.cc",
"quota/quota_database_migrations_unittest.cc",
"quota/quota_database_unittest.cc",
+ "quota/quota_manager_proxy_unittest.cc",
"quota/quota_manager_unittest.cc",
"quota/quota_settings_unittest.cc",
"quota/quota_temporary_storage_evictor_unittest.cc",
+ "quota/storage_directory_unittest.cc",
"quota/storage_policy_observer_unittest.cc",
"quota/usage_tracker_unittest.cc",
"test/mock_quota_manager_unittest.cc",
@@ -347,6 +353,7 @@ source_set("unittests") {
"//services/network/public/cpp",
"//services/network/public/mojom",
"//sql:test_support",
+ "//storage/browser/quota:mojo_bindings",
"//testing/gtest",
"//third_party/blink/public/common",
"//third_party/leveldatabase",
@@ -382,8 +389,6 @@ static_library("test_support") {
"test/mock_file_update_observer.h",
"test/mock_quota_client.cc",
"test/mock_quota_client.h",
- "test/mock_quota_database.cc",
- "test/mock_quota_database.h",
"test/mock_quota_manager.cc",
"test/mock_quota_manager.h",
"test/mock_quota_manager_proxy.cc",
diff --git a/chromium/storage/browser/blob/OWNERS b/chromium/storage/browser/blob/OWNERS
deleted file mode 100644
index 85cf2580291..00000000000
--- a/chromium/storage/browser/blob/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-dmurph@chromium.org
-mek@chromium.org
-jianli@chromium.org
diff --git a/chromium/storage/browser/blob/blob_builder_from_stream.cc b/chromium/storage/browser/blob/blob_builder_from_stream.cc
index a39af4e716c..8abde343d40 100644
--- a/chromium/storage/browser/blob/blob_builder_from_stream.cc
+++ b/chromium/storage/browser/blob/blob_builder_from_stream.cc
@@ -8,8 +8,8 @@
#include "base/containers/span.h"
#include "base/guid.h"
#include "base/metrics/histogram_macros.h"
-#include "base/task/post_task.h"
#include "base/task/thread_pool.h"
+#include "base/time/time.h"
#include "mojo/public/c/system/types.h"
#include "mojo/public/cpp/bindings/associated_remote.h"
#include "storage/browser/blob/blob_data_item.h"
diff --git a/chromium/storage/browser/blob/blob_builder_from_stream_unittest.cc b/chromium/storage/browser/blob/blob_builder_from_stream_unittest.cc
index 050db95440d..134a614c981 100644
--- a/chromium/storage/browser/blob/blob_builder_from_stream_unittest.cc
+++ b/chromium/storage/browser/blob/blob_builder_from_stream_unittest.cc
@@ -12,7 +12,6 @@
#include "base/files/scoped_temp_dir.h"
#include "base/rand_util.h"
#include "base/run_loop.h"
-#include "base/task/post_task.h"
#include "base/task/thread_pool.h"
#include "base/task/thread_pool/thread_pool_instance.h"
#include "base/test/bind.h"
diff --git a/chromium/storage/browser/blob/blob_data_item.h b/chromium/storage/browser/blob/blob_data_item.h
index aa681aceb61..138a038a5c5 100644
--- a/chromium/storage/browser/blob/blob_data_item.h
+++ b/chromium/storage/browser/blob/blob_data_item.h
@@ -15,6 +15,7 @@
#include "base/containers/span.h"
#include "base/files/file_path.h"
#include "base/memory/ref_counted.h"
+#include "base/time/time.h"
#include "components/services/storage/public/mojom/blob_storage_context.mojom.h"
#include "net/base/io_buffer.h"
#include "storage/browser/blob/shareable_file_reference.h"
diff --git a/chromium/storage/browser/blob/blob_impl.cc b/chromium/storage/browser/blob/blob_impl.cc
index d46565ac953..6b6590451de 100644
--- a/chromium/storage/browser/blob/blob_impl.cc
+++ b/chromium/storage/browser/blob/blob_impl.cc
@@ -12,8 +12,8 @@
#include "base/bind.h"
#include "base/containers/span.h"
#include "base/files/file_util.h"
-#include "base/task/post_task.h"
#include "base/task/thread_pool.h"
+#include "base/time/time.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "net/base/io_buffer.h"
#include "storage/browser/blob/blob_data_handle.h"
diff --git a/chromium/storage/browser/blob/blob_impl_unittest.cc b/chromium/storage/browser/blob/blob_impl_unittest.cc
index 3b88a924b7d..b67b6cfe563 100644
--- a/chromium/storage/browser/blob/blob_impl_unittest.cc
+++ b/chromium/storage/browser/blob/blob_impl_unittest.cc
@@ -12,7 +12,6 @@
#include "base/bind.h"
#include "base/memory/raw_ptr.h"
#include "base/run_loop.h"
-#include "base/task/post_task.h"
#include "base/test/task_environment.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "mojo/public/cpp/bindings/receiver.h"
diff --git a/chromium/storage/browser/blob/blob_reader.cc b/chromium/storage/browser/blob/blob_reader.cc
index 78a6fbd2fe2..a3eede480cd 100644
--- a/chromium/storage/browser/blob/blob_reader.cc
+++ b/chromium/storage/browser/blob/blob_reader.cc
@@ -15,9 +15,7 @@
#include "base/bind.h"
#include "base/callback_helpers.h"
#include "base/memory/ptr_util.h"
-#include "base/task/post_task.h"
#include "base/task/thread_pool.h"
-#include "base/time/time.h"
#include "base/trace_event/trace_event.h"
#include "net/base/io_buffer.h"
#include "net/base/net_errors.h"
diff --git a/chromium/storage/browser/blob/blob_registry_impl.cc b/chromium/storage/browser/blob/blob_registry_impl.cc
index 3d565c5aa08..4f73ddcf259 100644
--- a/chromium/storage/browser/blob/blob_registry_impl.cc
+++ b/chromium/storage/browser/blob/blob_registry_impl.cc
@@ -501,10 +501,12 @@ 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)
: context_(std::move(context)),
+ file_system_context_(std::move(file_system_context)),
url_registry_(std::move(url_registry)),
- file_system_context_(std::move(file_system_context)) {}
+ url_registry_runner_(std::move(url_registry_runner)) {}
BlobRegistryImpl::~BlobRegistryImpl() {
// BlobBuilderFromStream needs to be aborted before it can be destroyed, but
@@ -632,6 +634,7 @@ void BlobRegistryImpl::GetBlobFromUUID(
return;
}
if (!context_->registry().HasEntry(uuid)) {
+ LOG(ERROR) << "Invalid UUID: " << uuid;
// TODO(mek): Log histogram, old code logs Storage.Blob.InvalidReference
std::move(callback).Run();
return;
@@ -651,11 +654,22 @@ void BlobRegistryImpl::URLStoreForOrigin(
"BlobRegistryImpl::URLStoreForOrigin");
return;
}
- auto self_owned_associated_receiver = mojo::MakeSelfOwnedAssociatedReceiver(
- std::make_unique<BlobURLStoreImpl>(origin, url_registry_),
- std::move(receiver));
- if (g_url_store_creation_hook)
- g_url_store_creation_hook->Run(self_owned_associated_receiver);
+ url_registry_runner_->PostTask(
+ FROM_HERE,
+ base::BindOnce(
+ [](const url::Origin& origin,
+ mojo::PendingAssociatedReceiver<blink::mojom::BlobURLStore>
+ receiver,
+ base::WeakPtr<BlobUrlRegistry> url_registry) {
+ auto self_owned_associated_receiver =
+ mojo::MakeSelfOwnedAssociatedReceiver(
+ std::make_unique<BlobURLStoreImpl>(origin,
+ std::move(url_registry)),
+ std::move(receiver));
+ if (g_url_store_creation_hook)
+ g_url_store_creation_hook->Run(self_owned_associated_receiver);
+ },
+ origin, std::move(receiver), url_registry_));
}
// static
diff --git a/chromium/storage/browser/blob/blob_registry_impl.h b/chromium/storage/browser/blob/blob_registry_impl.h
index 35ae9b60213..866dac0921d 100644
--- a/chromium/storage/browser/blob/blob_registry_impl.h
+++ b/chromium/storage/browser/blob/blob_registry_impl.h
@@ -38,6 +38,7 @@ class COMPONENT_EXPORT(STORAGE_BROWSER) BlobRegistryImpl
BlobRegistryImpl(base::WeakPtr<BlobStorageContext> context,
base::WeakPtr<BlobUrlRegistry> url_registry,
+ scoped_refptr<base::TaskRunner> url_registry_runner,
scoped_refptr<FileSystemContext> file_system_context);
BlobRegistryImpl(const BlobRegistryImpl&) = delete;
@@ -95,9 +96,12 @@ class COMPONENT_EXPORT(STORAGE_BROWSER) BlobRegistryImpl
std::unique_ptr<BlobDataHandle> result);
base::WeakPtr<BlobStorageContext> context_;
- base::WeakPtr<BlobUrlRegistry> url_registry_;
scoped_refptr<FileSystemContext> file_system_context_;
+ // `url_registry_` should only be accessed on `url_registry_runner_`.
+ base::WeakPtr<BlobUrlRegistry> url_registry_;
+ scoped_refptr<base::TaskRunner> url_registry_runner_;
+
mojo::ReceiverSet<blink::mojom::BlobRegistry, std::unique_ptr<Delegate>>
receivers_;
diff --git a/chromium/storage/browser/blob/blob_registry_impl_unittest.cc b/chromium/storage/browser/blob/blob_registry_impl_unittest.cc
index 90a5b6b002d..6d84af4a8a8 100644
--- a/chromium/storage/browser/blob/blob_registry_impl_unittest.cc
+++ b/chromium/storage/browser/blob/blob_registry_impl_unittest.cc
@@ -17,7 +17,6 @@
#include "base/memory/raw_ptr.h"
#include "base/rand_util.h"
#include "base/run_loop.h"
-#include "base/task/post_task.h"
#include "base/task/sequenced_task_runner.h"
#include "base/task/thread_pool.h"
#include "base/test/bind.h"
@@ -82,11 +81,13 @@ class BlobRegistryImplTest : public testing::Test {
/*quota_manager_proxy=*/nullptr,
std::vector<std::unique_ptr<FileSystemBackend>>(),
std::vector<URLRequestAutoMountHandler>(), data_dir_.GetPath(),
+ 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(), file_system_context_);
+ context_->AsWeakPtr(), url_registry_.AsWeakPtr(),
+ base::SequencedTaskRunnerHandle::Get(), file_system_context_);
auto delegate = std::make_unique<MockBlobRegistryDelegate>();
delegate_ptr_ = delegate.get();
registry_impl_->Bind(registry_.BindNewPipeAndPassReceiver(),
diff --git a/chromium/storage/browser/blob/blob_storage_context.cc b/chromium/storage/browser/blob/blob_storage_context.cc
index f69576532bb..147e2adc554 100644
--- a/chromium/storage/browser/blob/blob_storage_context.cc
+++ b/chromium/storage/browser/blob/blob_storage_context.cc
@@ -21,10 +21,10 @@
#include "base/numerics/safe_conversions.h"
#include "base/numerics/safe_math.h"
#include "base/strings/stringprintf.h"
-#include "base/task/post_task.h"
#include "base/task/task_runner.h"
#include "base/task/thread_pool.h"
#include "base/threading/thread_task_runner_handle.h"
+#include "base/time/time.h"
#include "base/trace_event/memory_dump_manager.h"
#include "base/trace_event/trace_event.h"
#include "mojo/public/cpp/bindings/callback_helpers.h"
diff --git a/chromium/storage/browser/blob/blob_storage_context_mojo_unittest.cc b/chromium/storage/browser/blob/blob_storage_context_mojo_unittest.cc
index f2b5409b815..589378ffb75 100644
--- a/chromium/storage/browser/blob/blob_storage_context_mojo_unittest.cc
+++ b/chromium/storage/browser/blob/blob_storage_context_mojo_unittest.cc
@@ -12,13 +12,13 @@
#include "base/containers/span.h"
#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
-#include "base/task/post_task.h"
#include "base/task/task_traits.h"
#include "base/task/thread_pool.h"
#include "base/test/bind.h"
#include "base/test/task_environment.h"
#include "base/test/test_simple_task_runner.h"
#include "base/threading/thread_restrictions.h"
+#include "base/time/time.h"
#include "components/services/storage/public/mojom/blob_storage_context.mojom.h"
#include "mojo/public/cpp/base/big_buffer.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
diff --git a/chromium/storage/browser/blob/blob_transport_strategy_unittest.cc b/chromium/storage/browser/blob/blob_transport_strategy_unittest.cc
index 0f24c79baf3..ffda454761f 100644
--- a/chromium/storage/browser/blob/blob_transport_strategy_unittest.cc
+++ b/chromium/storage/browser/blob/blob_transport_strategy_unittest.cc
@@ -16,11 +16,11 @@
#include "base/files/scoped_temp_dir.h"
#include "base/rand_util.h"
#include "base/run_loop.h"
-#include "base/task/post_task.h"
#include "base/task/sequenced_task_runner.h"
#include "base/task/thread_pool.h"
#include "base/test/task_environment.h"
#include "base/threading/thread_restrictions.h"
+#include "base/time/time.h"
#include "mojo/public/cpp/bindings/self_owned_receiver.h"
#include "mojo/public/cpp/system/functions.h"
#include "storage/browser/blob/blob_data_builder.h"
diff --git a/chromium/storage/browser/blob/write_blob_to_file.cc b/chromium/storage/browser/blob/write_blob_to_file.cc
index 4fd0c3d3137..758c964e4e0 100644
--- a/chromium/storage/browser/blob/write_blob_to_file.cc
+++ b/chromium/storage/browser/blob/write_blob_to_file.cc
@@ -16,7 +16,6 @@
#include "base/files/file_util.h"
#include "base/numerics/checked_math.h"
#include "base/numerics/safe_conversions.h"
-#include "base/task/post_task.h"
#include "base/task/task_traits.h"
#include "base/task/thread_pool.h"
#include "storage/browser/blob/blob_data_handle.h"
diff --git a/chromium/storage/browser/database/OWNERS b/chromium/storage/browser/database/OWNERS
index dd55f956da2..e674dc93584 100644
--- a/chromium/storage/browser/database/OWNERS
+++ b/chromium/storage/browser/database/OWNERS
@@ -1,5 +1,5 @@
# Primary
-pwnall@chromium.org
+asully@chromium.org
# Seconday
-mek@chromium.org
+ayui@chromium.org
diff --git a/chromium/storage/browser/database/database_quota_client_unittest.cc b/chromium/storage/browser/database/database_quota_client_unittest.cc
index 17fe31dbd1b..168bcf88939 100644
--- a/chromium/storage/browser/database/database_quota_client_unittest.cc
+++ b/chromium/storage/browser/database/database_quota_client_unittest.cc
@@ -18,6 +18,7 @@
#include "base/location.h"
#include "base/memory/scoped_refptr.h"
#include "base/run_loop.h"
+#include "base/sequence_checker_impl.h"
#include "base/strings/utf_string_conversions.h"
#include "base/task/single_thread_task_runner.h"
#include "base/test/bind.h"
@@ -35,6 +36,7 @@
#include "storage/browser/quota/quota_manager.h"
#include "storage/browser/quota/quota_manager_proxy.h"
#include "storage/browser/quota/special_storage_policy.h"
+#include "storage/browser/test/mock_special_storage_policy.h"
#include "storage/common/database/database_identifier.h"
#include "testing/gmock/include/gmock/gmock-matchers.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -52,13 +54,15 @@ static const blink::mojom::StorageType kTemp =
// Mocks DatabaseTracker methods used by DatabaseQuotaClient.
class MockDatabaseTracker : public DatabaseTracker {
public:
- MockDatabaseTracker(const base::FilePath& path,
- bool is_incognito,
- scoped_refptr<QuotaManagerProxy> quota_manager_proxy)
+ MockDatabaseTracker(
+ const base::FilePath& path,
+ bool is_incognito,
+ scoped_refptr<QuotaManagerProxy> quota_manager_proxy,
+ scoped_refptr<SpecialStoragePolicy> special_storage_policy)
: DatabaseTracker(path,
is_incognito,
- /*special_storage_policy=*/nullptr,
- quota_manager_proxy,
+ std::move(special_storage_policy),
+ std::move(quota_manager_proxy),
DatabaseTracker::CreatePassKey()) {}
bool GetOriginInfo(const std::string& origin_identifier,
@@ -143,18 +147,24 @@ class DatabaseQuotaClientTest : public testing::TestWithParam<bool> {
: kStorageKeyA(
blink::StorageKey::CreateFromStringForTesting("http://host")),
kStorageKeyB(
- blink::StorageKey::CreateFromStringForTesting("http://host:8000")) {
- }
+ blink::StorageKey::CreateFromStringForTesting("http://host:8000")),
+ special_storage_policy_(
+ base::MakeRefCounted<MockSpecialStoragePolicy>()) {}
+ ~DatabaseQuotaClientTest() override = default;
+
+ DatabaseQuotaClientTest(const DatabaseQuotaClientTest&) = delete;
+ DatabaseQuotaClientTest& operator=(const DatabaseQuotaClientTest&) = delete;
void SetUp() override {
ASSERT_TRUE(data_dir_.CreateUniqueTempDir());
quota_manager_ = base::MakeRefCounted<QuotaManager>(
/*is_incognito_=*/false, data_dir_.GetPath(),
base::ThreadTaskRunnerHandle::Get(),
- /*quota_change_callback=*/base::DoNothing(),
- /*special_storage_policy=*/nullptr, GetQuotaSettingsFunc());
+ /*quota_change_callback=*/base::DoNothing(), special_storage_policy_,
+ GetQuotaSettingsFunc());
mock_tracker_ = base::MakeRefCounted<MockDatabaseTracker>(
- data_dir_.GetPath(), is_incognito(), quota_manager_->proxy());
+ data_dir_.GetPath(), is_incognito(), quota_manager_->proxy(),
+ special_storage_policy_);
}
void TearDown() override {
@@ -211,7 +221,10 @@ class DatabaseQuotaClientTest : public testing::TestWithParam<bool> {
return delete_future.Get();
}
+ scoped_refptr<MockSpecialStoragePolicy> special_storage_policy_;
+
base::ScopedTempDir data_dir_;
+
base::test::TaskEnvironment task_environment_;
scoped_refptr<MockDatabaseTracker> mock_tracker_;
scoped_refptr<QuotaManager> quota_manager_;
diff --git a/chromium/storage/browser/database/database_tracker.cc b/chromium/storage/browser/database/database_tracker.cc
index 74423c6f847..8abec7e8e4b 100644
--- a/chromium/storage/browser/database/database_tracker.cc
+++ b/chromium/storage/browser/database/database_tracker.cc
@@ -20,9 +20,9 @@
#include "base/location.h"
#include "base/memory/scoped_refptr.h"
#include "base/metrics/user_metrics.h"
+#include "base/observer_list.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/utf_string_conversions.h"
-#include "base/task/post_task.h"
#include "base/task/thread_pool.h"
#include "base/time/time.h"
#include "base/types/pass_key.h"
diff --git a/chromium/storage/browser/database/database_tracker.h b/chromium/storage/browser/database/database_tracker.h
index 63d2c3acc86..95a867e27ca 100644
--- a/chromium/storage/browser/database/database_tracker.h
+++ b/chromium/storage/browser/database/database_tracker.h
@@ -148,8 +148,8 @@ class COMPONENT_EXPORT(STORAGE_BROWSER) DatabaseTracker
virtual bool GetAllOriginsInfo(std::vector<OriginInfo>* origins_info);
// Thread-safe getter.
- QuotaManagerProxy* quota_manager_proxy() const {
- return quota_manager_proxy_.get();
+ const scoped_refptr<QuotaManagerProxy>& quota_manager_proxy() const {
+ return quota_manager_proxy_;
}
bool IsDatabaseScheduledForDeletion(const std::string& origin_identifier,
diff --git a/chromium/storage/browser/database/database_tracker_unittest.cc b/chromium/storage/browser/database/database_tracker_unittest.cc
index 32b315b90b9..aab6a5a2ea7 100644
--- a/chromium/storage/browser/database/database_tracker_unittest.cc
+++ b/chromium/storage/browser/database/database_tracker_unittest.cc
@@ -103,7 +103,8 @@ class TestQuotaManagerProxy : public QuotaManagerProxy {
TestQuotaManagerProxy()
: QuotaManagerProxy(
/*quota_manager_impl=*/nullptr,
- base::SequencedTaskRunnerHandle::Get()) {}
+ base::SequencedTaskRunnerHandle::Get(),
+ /*profile_path=*/base::FilePath()) {}
void RegisterClient(
mojo::PendingRemote<mojom::QuotaClient> client,
diff --git a/chromium/storage/browser/file_system/async_file_util.h b/chromium/storage/browser/file_system/async_file_util.h
index 3f1b41a5f62..7c6a896a4f8 100644
--- a/chromium/storage/browser/file_system/async_file_util.h
+++ b/chromium/storage/browser/file_system/async_file_util.h
@@ -49,9 +49,11 @@ class AsyncFileUtil {
public:
using StatusCallback = base::OnceCallback<void(base::File::Error result)>;
- // |on_close_callback| will be called after the |file| is closed in the
- // child process. |on_close_callback|.is_null() can be true, if no operation
- // is needed on closing the file.
+ // Used for CreateOrOpen(). File util implementations can specify an
+ // `on_close_callback` if an operation is needed after closing a file. If
+ // non-null, CreateOrOpen() callers must run the callback (on the IO thread)
+ // after the file closes. If the file is duped, the callback should not be run
+ // until all dups of the file have been closed.
using CreateOrOpenCallback =
base::OnceCallback<void(base::File file,
base::OnceClosure on_close_callback)>;
diff --git a/chromium/storage/browser/file_system/async_file_util_adapter.cc b/chromium/storage/browser/file_system/async_file_util_adapter.cc
index d1f31d8149f..a6e33abef35 100644
--- a/chromium/storage/browser/file_system/async_file_util_adapter.cc
+++ b/chromium/storage/browser/file_system/async_file_util_adapter.cc
@@ -12,6 +12,7 @@
#include <vector>
#include "base/bind.h"
+#include "base/callback.h"
#include "base/task/sequenced_task_runner.h"
#include "base/task/task_runner_util.h"
#include "base/threading/thread_task_runner_handle.h"
diff --git a/chromium/storage/browser/file_system/copy_or_move_hook_delegate.cc b/chromium/storage/browser/file_system/copy_or_move_hook_delegate.cc
new file mode 100644
index 00000000000..f65f4865524
--- /dev/null
+++ b/chromium/storage/browser/file_system/copy_or_move_hook_delegate.cc
@@ -0,0 +1,61 @@
+// Copyright 2022 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/copy_or_move_hook_delegate.h"
+
+#include "base/callback.h"
+#include "base/files/file.h"
+#include "base/sequence_checker.h"
+#include "storage/browser/file_system/file_system_url.h"
+
+namespace storage {
+
+CopyOrMoveHookDelegate::CopyOrMoveHookDelegate() {
+ DETACH_FROM_SEQUENCE(sequence_checker_);
+}
+
+void CopyOrMoveHookDelegate::OnBeginProcessFile(
+ const FileSystemURL& source_url,
+ const FileSystemURL& destination_url,
+ StatusCallback callback) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ std::move(callback).Run(base::File::FILE_OK);
+}
+
+void CopyOrMoveHookDelegate::OnBeginProcessDirectory(
+ const FileSystemURL& source_url,
+ const FileSystemURL& destination_url,
+ StatusCallback callback) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ std::move(callback).Run(base::File::FILE_OK);
+}
+
+void CopyOrMoveHookDelegate::OnProgress(const FileSystemURL& source_url,
+ const FileSystemURL& destination_url,
+ int64_t size) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+}
+
+void CopyOrMoveHookDelegate::OnError(const FileSystemURL& source_url,
+ const FileSystemURL& destination_url,
+ base::File::Error error) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+}
+
+void CopyOrMoveHookDelegate::OnEndCopy(const FileSystemURL& source_url,
+ const FileSystemURL& destination_url) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+}
+
+void CopyOrMoveHookDelegate::OnEndMove(const FileSystemURL& source_url,
+ const FileSystemURL& destination_url) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+}
+
+void CopyOrMoveHookDelegate::OnEndRemoveSource(
+ const FileSystemURL& source_url) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+}
+
+} // namespace storage
diff --git a/chromium/storage/browser/file_system/copy_or_move_hook_delegate.h b/chromium/storage/browser/file_system/copy_or_move_hook_delegate.h
new file mode 100644
index 00000000000..1c2937bfdfe
--- /dev/null
+++ b/chromium/storage/browser/file_system/copy_or_move_hook_delegate.h
@@ -0,0 +1,160 @@
+// Copyright 2022 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_COPY_OR_MOVE_HOOK_DELEGATE_H_
+#define STORAGE_BROWSER_FILE_SYSTEM_COPY_OR_MOVE_HOOK_DELEGATE_H_
+
+#include "base/callback_forward.h"
+#include "base/component_export.h"
+#include "base/files/file.h"
+#include "base/memory/weak_ptr.h"
+#include "base/sequence_checker.h"
+
+namespace storage {
+class FileSystemURL;
+
+// A delegate to handle different hooks of the CopyOrMove operation.
+// Its At* functions take a callback that is called when the function
+// finishes, potentially notifying of any errors during the execution of
+// the function.
+// The Notify* functions do not take a callback and can asynchronously notify of
+// any progress or errors.
+// Used for progress updates, etc. in FileSystemOperation::Copy() and Move().
+//
+// Note that Move() has both a same-filesystem (1) and a cross-filesystem (2)
+// implementation.
+// 1) Requires metadata updates. Depending on the underlying implementation:
+// - we either only update the metadata of (or in other words, rename) the
+// moving directory
+// - or the directories are recursively copied + deleted, while the files are
+// moved by having their metadata updated.
+// 2) Degrades into copy + delete: each entry is copied and deleted
+// recursively.
+//
+// OnBeginProcessFile, resp. OnBeginProcessDirectory is called at the start of
+// each copy or move operation for a file, resp. a directory. The `source_url`
+// and the `destination_url` are the URLs of the source and the destination
+// entries. Note that for the root directory, OnBeginProcessFile is called
+// instead of OnBeginProcessDirectory. This resembles the call order of the
+// RecursiveOperationDelegate.
+//
+// OnProgress is called periodically during file transfer (not called for
+// same-filesystem move and directory copy/move).
+// The `source_url` and the `destination_url` are the URLs of the source and
+// the destination entries. `size` is the number of cumulative copied bytes
+// for the currently copied file. Both at beginning and ending of file
+// transfer, PROGRESS event should be called. At beginning, `size` should be
+// 0. At ending, `size` should be the size of the file.
+//
+// NotifyError is called for any occurring error.
+// The `source_url` and the `destination_url` are the URLs of the source and
+// the destination entries. `error` is the base::File::Error that was noticed.
+// NotifyError is also called if an OnBeginProcessFile or
+// OnBeginProcessDirectory function passes an error to their respective
+// callbacks.
+//
+// OnEndCopy is called for each destination entry that has been successfully
+// copied (for both file and directory). The `source_url` and the
+// `destination_url` are the URLs of the source and the destination entries.
+//
+// OnEndMove is called for each entry that has been successfully moved (for
+// both file and directory), in the case of a same-filesystem move. The
+// `source_url` and the `destination_url` are the URLs of the source and the
+// destination entries.
+//
+// OnEndRemoveSource, applies in the Move() case only, and is called for
+// each source entry that has been successfully removed from its source location
+// (for both file and directory). The `source_url` is the URL of the source
+// entry.
+//
+// When moving files, the expected events are as follows.
+// Copy: OnBeginProcessFile -> OnProgress -> ... -> OnProgress ->
+// OnEndCopy. Move (same-filesystem): OnBeginProcessFile -> OnEndMove.
+// Move (cross-filesystem): OnBeginProcessFile -> OnProgress -> ... ->
+// OnProgress -> OnEndCopy -> OnEndRemoveSource.
+//
+// Here is an example callback sequence of for a copy or a cross-filesystem
+// move. Suppose there are a/b/c.txt (100 bytes) and a/b/d.txt (200 bytes),
+// and trying to transfer a to x recursively, then the progress update
+// sequence will be (Note that for the root directory, OnBeginProcessFile is
+// called instead of OnBeginProcessDirectory):
+//
+// OnBeginProcessFile a x/a (starting create "a" directory in x/).
+// OnEndCopy a x/a (creating "a" directory in x/ is finished).
+//
+// OnBeginProcessDirectory a/b x/a/b (starting create "b" directory in x/a).
+// OnEndCopy a/b x/a/b (creating "b" directory in x/a/ is finished).
+//
+// OnBeginProcessFile a/b/c.txt x/a/b/c.txt (starting to transfer "c.txt" in
+// x/a/b/).
+// OnProgress a/b/c.txt x/a/b/c.txt 0 (The first OnProgress's `size`
+// should be 0).
+// OnProgress a/b/c.txt x/a/b/c.txt 10
+// :
+// OnProgress a/b/c.txt x/a/b/c.txt 90
+// OnProgress a/b/c.txt x/a/b/c.txt 100 (The last OnProgress's `size`
+// should be the size of the file).
+// OnEndCopy a/b/c.txt x/a/b/c.txt (transferring "c.txt" is finished).
+// OnEndRemoveSource a/b/c.txt ("copy + delete" move case).
+//
+// OnBeginProcessFile a/b/d.txt x/a/b/d.txt (starting to transfer "d.txt" in
+// x/a/b).
+// OnProgress a/b/d.txt x/a/b/d.txt 0 (The first OnProgress's
+// `size` should be 0).
+// OnProgress a/b/d.txt x/a/b/d.txt 10
+// :
+// OnProgress a/b/d.txt x/a/b/d.txt 190
+// OnProgress a/b/d.txt x/a/b/d.txt 200 (The last OnProgress's `size`
+// should be the size of the file).
+// OnEndCopy a/b/d.txt x/a/b/d.txt (transferring "d.txt" is finished).
+// OnEndRemoveSource a/b/d.txt ("copy + delete" move case).
+//
+// OnEndRemoveSource a/b ("copy + delete" move case).
+//
+// OnEndRemoveSource a ("copy + delete" move case).
+//
+// Note that event sequence of a/b/c.txt and a/b/d.txt can be interlaced,
+// because they can be done in parallel. Also OnProgress events are
+// optional, so they may not appear. All the progress callback invocations
+// should be done before StatusCallback given to the Copy is called. Especially
+// if an error is found before the first progress callback invocation, the
+// progress callback may NOT be invoked for the copy.
+//
+class COMPONENT_EXPORT(STORAGE_BROWSER) CopyOrMoveHookDelegate
+ : public base::SupportsWeakPtr<CopyOrMoveHookDelegate> {
+ public:
+ using StatusCallback = base::OnceCallback<void(base::File::Error result)>;
+
+ CopyOrMoveHookDelegate();
+
+ virtual ~CopyOrMoveHookDelegate() = default;
+
+ virtual void OnBeginProcessFile(const FileSystemURL& source_url,
+ const FileSystemURL& destination_url,
+ StatusCallback callback);
+
+ virtual void OnBeginProcessDirectory(const FileSystemURL& source_url,
+ const FileSystemURL& destination_url,
+ StatusCallback callback);
+
+ virtual void OnProgress(const FileSystemURL& source_url,
+ const FileSystemURL& destination_url,
+ int64_t size);
+ virtual void OnError(const FileSystemURL& source_url,
+ const FileSystemURL& destination_url,
+ base::File::Error error);
+
+ virtual void OnEndCopy(const FileSystemURL& source_url,
+ const FileSystemURL& destination_url);
+ virtual void OnEndMove(const FileSystemURL& source_url,
+ const FileSystemURL& destination_url);
+ virtual void OnEndRemoveSource(const FileSystemURL& source_url);
+
+ protected:
+ SEQUENCE_CHECKER(sequence_checker_);
+};
+
+} // namespace storage
+
+#endif // STORAGE_BROWSER_FILE_SYSTEM_COPY_OR_MOVE_HOOK_DELEGATE_H_
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 05a61084e32..b7d0cbd0649 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
@@ -4,24 +4,28 @@
#include "storage/browser/file_system/copy_or_move_operation_delegate.h"
-#include <stdint.h>
-
+#include <cstdint>
#include <memory>
#include <tuple>
#include <utility>
+#include "base/auto_reset.h"
#include "base/bind.h"
#include "base/callback_helpers.h"
+#include "base/files/file.h"
#include "base/files/file_path.h"
#include "base/memory/raw_ptr.h"
+#include "base/memory/weak_ptr.h"
#include "net/base/io_buffer.h"
#include "net/base/net_errors.h"
#include "storage/browser/blob/shareable_file_reference.h"
#include "storage/browser/file_system/copy_or_move_file_validator.h"
+#include "storage/browser/file_system/copy_or_move_hook_delegate.h"
#include "storage/browser/file_system/file_observers.h"
#include "storage/browser/file_system/file_stream_reader.h"
#include "storage/browser/file_system/file_stream_writer.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_runner.h"
#include "storage/browser/file_system/file_system_url.h"
#include "storage/common/file_system/file_system_util.h"
@@ -50,38 +54,40 @@ class CopyOrMoveOperationDelegate::CopyOrMoveImpl {
const FileSystemURL& src_url,
const FileSystemURL& dest_url,
const CopyOrMoveOperationDelegate::CopyOrMoveOptionSet options,
- FileSystemOperation::CopyOrMoveProgressCallback progress_callback)
+ base::WeakPtr<storage::CopyOrMoveHookDelegate>
+ copy_or_move_hook_delegate_weak_ptr)
: operation_runner_(operation_runner),
operation_type_(operation_type),
src_url_(src_url),
dest_url_(dest_url),
options_(options),
- progress_callback_(std::move(progress_callback)) {}
+ copy_or_move_hook_delegate_weak_ptr_(
+ copy_or_move_hook_delegate_weak_ptr) {}
// Callback for sending progress events with the current number of processed
// bytes.
void OnCopyOrMoveFileProgress(int64_t size) {
- if (!progress_callback_.is_null()) {
- progress_callback_.Run(
- FileSystemOperation::CopyOrMoveProgressType::kProgress, src_url_,
- dest_url_, size);
- }
+ base::SequencedTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::BindOnce(&CopyOrMoveHookDelegate::OnProgress,
+ copy_or_move_hook_delegate_weak_ptr_,
+ src_url_, dest_url_, size));
}
// Callback for sending progress events notifying the end of a copy, for a
// copy operation or a cross-filesystem move.
void DidEndCopy(CopyOrMoveOperationDelegate::StatusCallback callback,
base::File::Error error) {
- if (!progress_callback_.is_null()) {
- if (error == base::File::FILE_OK) {
- progress_callback_.Run(
- FileSystemOperation::CopyOrMoveProgressType::kEndCopy, src_url_,
- dest_url_, 0);
- } else if (error != base::File::FILE_ERROR_NOT_A_FILE) {
- progress_callback_.Run(
- FileSystemOperation::CopyOrMoveProgressType::kError, src_url_,
- dest_url_, 0);
- }
+ if (error == base::File::FILE_OK) {
+ base::SequencedTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::BindOnce(&CopyOrMoveHookDelegate::OnEndCopy,
+ copy_or_move_hook_delegate_weak_ptr_,
+ src_url_, dest_url_));
+
+ } else if (error != base::File::FILE_ERROR_NOT_A_FILE) {
+ base::SequencedTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::BindOnce(&CopyOrMoveHookDelegate::OnError,
+ copy_or_move_hook_delegate_weak_ptr_,
+ src_url_, dest_url_, error));
}
if (options_.Has(FileSystemOperation::CopyOrMoveOption::
@@ -108,17 +114,18 @@ class CopyOrMoveOperationDelegate::CopyOrMoveImpl {
// in the case of a local (same-filesystem) move.
void DidEndMove(CopyOrMoveOperationDelegate::StatusCallback callback,
base::File::Error error) {
- if (!progress_callback_.is_null()) {
- if (error == base::File::FILE_OK) {
- progress_callback_.Run(
- FileSystemOperation::CopyOrMoveProgressType::kEndMove, src_url_,
- dest_url_, 0);
- } else {
- progress_callback_.Run(
- FileSystemOperation::CopyOrMoveProgressType::kError, src_url_,
- dest_url_, 0);
- }
+ if (error == base::File::FILE_OK) {
+ base::SequencedTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::BindOnce(&CopyOrMoveHookDelegate::OnEndMove,
+ copy_or_move_hook_delegate_weak_ptr_,
+ src_url_, dest_url_));
+ } else {
+ base::SequencedTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::BindOnce(&CopyOrMoveHookDelegate::OnError,
+ copy_or_move_hook_delegate_weak_ptr_,
+ src_url_, dest_url_, error));
}
+
std::move(callback).Run(error);
}
@@ -127,17 +134,18 @@ class CopyOrMoveOperationDelegate::CopyOrMoveImpl {
void DidEndRemoveSourceForMove(
CopyOrMoveOperationDelegate::StatusCallback callback,
base::File::Error error) {
- if (!progress_callback_.is_null()) {
- if (error == base::File::FILE_OK) {
- progress_callback_.Run(
- FileSystemOperation::CopyOrMoveProgressType::kEndRemoveSource,
- src_url_, FileSystemURL(), 0);
- } else {
- progress_callback_.Run(
- FileSystemOperation::CopyOrMoveProgressType::kError, src_url_,
- dest_url_, 0);
- }
+ if (error == base::File::FILE_OK) {
+ base::SequencedTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE,
+ base::BindOnce(&CopyOrMoveHookDelegate::OnEndRemoveSource,
+ copy_or_move_hook_delegate_weak_ptr_, src_url_));
+ } else {
+ base::SequencedTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::BindOnce(&CopyOrMoveHookDelegate::OnError,
+ copy_or_move_hook_delegate_weak_ptr_,
+ src_url_, dest_url_, error));
}
+
std::move(callback).Run(error);
}
@@ -165,7 +173,8 @@ class CopyOrMoveOperationDelegate::CopyOrMoveImpl {
bool force_error_for_test_ = false;
private:
- const FileSystemOperation::CopyOrMoveProgressCallback progress_callback_;
+ base::WeakPtr<storage::CopyOrMoveHookDelegate>
+ copy_or_move_hook_delegate_weak_ptr_;
base::WeakPtrFactory<CopyOrMoveImpl> weak_factory_{this};
};
@@ -182,13 +191,14 @@ class CopyOrMoveOnSameFileSystemImpl
const FileSystemURL& src_url,
const FileSystemURL& dest_url,
const CopyOrMoveOperationDelegate::CopyOrMoveOptionSet options,
- FileSystemOperation::CopyOrMoveProgressCallback progress_callback)
+ base::WeakPtr<storage::CopyOrMoveHookDelegate>
+ copy_or_move_hook_delegate_weak_ptr)
: CopyOrMoveImpl(operation_runner,
operation_type,
src_url,
dest_url,
options,
- progress_callback) {}
+ copy_or_move_hook_delegate_weak_ptr) {}
CopyOrMoveOnSameFileSystemImpl(const CopyOrMoveOnSameFileSystemImpl&) =
delete;
@@ -236,13 +246,14 @@ class SnapshotCopyOrMoveImpl
const FileSystemURL& dest_url,
CopyOrMoveOperationDelegate::CopyOrMoveOptionSet options,
CopyOrMoveFileValidatorFactory* validator_factory,
- FileSystemOperation::CopyOrMoveProgressCallback progress_callback)
+ base::WeakPtr<storage::CopyOrMoveHookDelegate>
+ copy_or_move_hook_delegate_weak_ptr)
: CopyOrMoveImpl(operation_runner,
operation_type,
src_url,
dest_url,
options,
- progress_callback),
+ copy_or_move_hook_delegate_weak_ptr),
validator_factory_(validator_factory),
cancel_requested_(false) {}
@@ -506,13 +517,14 @@ class StreamCopyOrMoveImpl
CopyOrMoveOperationDelegate::CopyOrMoveOptionSet options,
std::unique_ptr<FileStreamReader> reader,
std::unique_ptr<FileStreamWriter> writer,
- FileSystemOperation::CopyOrMoveProgressCallback progress_callback)
+ base::WeakPtr<storage::CopyOrMoveHookDelegate>
+ copy_or_move_hook_delegate_weak_ptr)
: CopyOrMoveImpl(operation_runner,
operation_type,
src_url,
dest_url,
options,
- progress_callback),
+ copy_or_move_hook_delegate_weak_ptr),
file_system_context_(file_system_context),
reader_(std::move(reader)),
writer_(std::move(writer)),
@@ -866,7 +878,7 @@ CopyOrMoveOperationDelegate::CopyOrMoveOperationDelegate(
OperationType operation_type,
CopyOrMoveOptionSet options,
ErrorBehavior error_behavior,
- const CopyOrMoveProgressCallback& progress_callback,
+ std::unique_ptr<CopyOrMoveHookDelegate> copy_or_move_hook_delegate,
StatusCallback callback)
: RecursiveOperationDelegate(file_system_context),
src_root_(src_root),
@@ -874,8 +886,9 @@ CopyOrMoveOperationDelegate::CopyOrMoveOperationDelegate(
operation_type_(operation_type),
options_(options),
error_behavior_(error_behavior),
- progress_callback_(progress_callback),
+ copy_or_move_hook_delegate_(std::move(copy_or_move_hook_delegate)),
callback_(std::move(callback)) {
+ DCHECK(copy_or_move_hook_delegate_);
// Force same_file_system_ = false if options include kForceCrossFilesystem.
same_file_system_ =
!options.Has(
@@ -915,16 +928,40 @@ void CopyOrMoveOperationDelegate::RunRecursively() {
// TODO(kinuko): This could be too expensive for same_file_system_==true
// and operation==MOVE case, probably we can just rename the root directory.
// http://crbug.com/172187
- StartRecursiveOperation(src_root_, error_behavior_, std::move(callback_));
+ StartRecursiveOperation(
+ src_root_, error_behavior_,
+ base::BindOnce(&CopyOrMoveOperationDelegate::FinishOperation,
+ weak_factory_.GetWeakPtr()));
+}
+
+void CopyOrMoveOperationDelegate::FinishOperation(base::File::Error error) {
+ // We post the callback as a task to ensure that other posted tasks are
+ // completed before finishing the operation.
+ PostTask(base::BindOnce(std::move(callback_), error));
}
void CopyOrMoveOperationDelegate::ProcessFile(const FileSystemURL& src_url,
StatusCallback callback) {
- FileSystemURL dest_url = CreateDestURL(src_url);
+ const FileSystemURL dest_url = CreateDestURL(src_url);
+
+ PostTask(base::BindOnce(
+ &CopyOrMoveHookDelegate::OnBeginProcessFile,
+ copy_or_move_hook_delegate_->AsWeakPtr(), src_url, dest_url,
+ base::BindOnce(&CopyOrMoveOperationDelegate::DoProcessFile,
+ weak_factory_.GetWeakPtr(), src_url, dest_url,
+ std::move(callback))));
+}
- if (!progress_callback_.is_null()) {
- progress_callback_.Run(FileSystemOperation::CopyOrMoveProgressType::kBegin,
- src_url, dest_url, 0);
+void CopyOrMoveOperationDelegate::DoProcessFile(const FileSystemURL& src_url,
+ FileSystemURL dest_url,
+ StatusCallback callback,
+ base::File::Error error) {
+ if (error != base::File::FILE_OK) {
+ PostTask(base::BindOnce(&CopyOrMoveHookDelegate::OnError,
+ copy_or_move_hook_delegate_->AsWeakPtr(), src_url,
+ dest_url, error));
+ std::move(callback).Run(error);
+ return;
}
std::unique_ptr<CopyOrMoveImpl> impl;
@@ -935,7 +972,7 @@ void CopyOrMoveOperationDelegate::ProcessFile(const FileSystemURL& src_url,
operation_type_ == OPERATION_MOVE)) {
impl = std::make_unique<CopyOrMoveOnSameFileSystemImpl>(
operation_runner(), operation_type_, src_url, dest_url, options_,
- progress_callback_);
+ copy_or_move_hook_delegate_->AsWeakPtr());
} else {
// Cross filesystem case.
base::File::Error error = base::File::FILE_ERROR_FAILED;
@@ -943,10 +980,9 @@ void CopyOrMoveOperationDelegate::ProcessFile(const FileSystemURL& src_url,
file_system_context()->GetCopyOrMoveFileValidatorFactory(
dest_root_.type(), &error);
if (error != base::File::FILE_OK) {
- if (!progress_callback_.is_null())
- progress_callback_.Run(
- FileSystemOperation::CopyOrMoveProgressType::kError, src_url,
- dest_url, 0);
+ PostTask(base::BindOnce(&CopyOrMoveHookDelegate::OnError,
+ copy_or_move_hook_delegate_->AsWeakPtr(), src_url,
+ dest_url, error));
std::move(callback).Run(error);
return;
@@ -962,14 +998,14 @@ void CopyOrMoveOperationDelegate::ProcessFile(const FileSystemURL& src_url,
impl = std::make_unique<StreamCopyOrMoveImpl>(
operation_runner(), file_system_context(), operation_type_, src_url,
dest_url, options_, std::move(reader), std::move(writer),
- progress_callback_);
+ copy_or_move_hook_delegate_->AsWeakPtr());
}
}
if (!impl) {
impl = std::make_unique<SnapshotCopyOrMoveImpl>(
operation_runner(), operation_type_, src_url, dest_url, options_,
- validator_factory, progress_callback_);
+ validator_factory, copy_or_move_hook_delegate_->AsWeakPtr());
}
}
@@ -999,14 +1035,14 @@ void CopyOrMoveOperationDelegate::ProcessDirectory(const FileSystemURL& src_url,
return;
}
- FileSystemURL dest_url = CreateDestURL(src_url);
-
- if (!progress_callback_.is_null()) {
- progress_callback_.Run(FileSystemOperation::CopyOrMoveProgressType::kBegin,
- src_url, dest_url, 0);
- }
+ const FileSystemURL dest_url = CreateDestURL(src_url);
- ProcessDirectoryInternal(src_url, dest_url, std::move(callback));
+ PostTask(base::BindOnce(
+ &CopyOrMoveHookDelegate::OnBeginProcessDirectory,
+ copy_or_move_hook_delegate_->AsWeakPtr(), src_url, dest_url,
+ base::BindOnce(&CopyOrMoveOperationDelegate::ProcessDirectoryInternal,
+ weak_factory_.GetWeakPtr(), src_url, dest_url,
+ std::move(callback))));
}
void CopyOrMoveOperationDelegate::PostProcessDirectory(
@@ -1025,16 +1061,20 @@ void CopyOrMoveOperationDelegate::PostProcessDirectory(
weak_factory_.GetWeakPtr(), src_url, std::move(callback)));
}
+void CopyOrMoveOperationDelegate::PostTask(base::OnceClosure closure) {
+ base::SequencedTaskRunnerHandle::Get()->PostTask(FROM_HERE,
+ std::move(closure));
+}
+
void CopyOrMoveOperationDelegate::OnCancel() {
// Request to cancel all running Copy/Move file.
for (auto& job : running_copy_set_)
job.first->Cancel();
}
-void CopyOrMoveOperationDelegate::DidCopyOrMoveFile(
- StatusCallback callback,
- CopyOrMoveImpl* impl,
- base::File::Error error) {
+void CopyOrMoveOperationDelegate::DidCopyOrMoveFile(StatusCallback callback,
+ CopyOrMoveImpl* impl,
+ base::File::Error error) {
running_copy_set_.erase(impl);
std::move(callback).Run(error);
@@ -1053,13 +1093,23 @@ void CopyOrMoveOperationDelegate::DidTryRemoveDestRoot(
return;
}
- ProcessDirectoryInternal(src_root_, dest_root_, std::move(callback));
+ ProcessDirectoryInternal(src_root_, dest_root_, std::move(callback),
+ base::File::FILE_OK);
}
void CopyOrMoveOperationDelegate::ProcessDirectoryInternal(
const FileSystemURL& src_url,
const FileSystemURL& dest_url,
- StatusCallback callback) {
+ StatusCallback callback,
+ base::File::Error error) {
+ if (error != base::File::FILE_OK) {
+ PostTask(base::BindOnce(&CopyOrMoveHookDelegate::OnError,
+ copy_or_move_hook_delegate_->AsWeakPtr(), src_url,
+ dest_url, error));
+ std::move(callback).Run(error);
+ return;
+ }
+
// If operation_type == Move we may need to record directories and
// restore directory timestamps in the end, though it may have
// negative performance impact.
@@ -1076,10 +1126,14 @@ void CopyOrMoveOperationDelegate::DidCreateDirectory(
const FileSystemURL& dest_url,
StatusCallback callback,
base::File::Error error) {
- if (!progress_callback_.is_null() && error == base::File::FILE_OK) {
- progress_callback_.Run(
- FileSystemOperation::CopyOrMoveProgressType::kEndCopy, src_url,
- dest_url, 0);
+ if (error == base::File::FILE_OK) {
+ PostTask(base::BindOnce(&CopyOrMoveHookDelegate::OnEndCopy,
+ copy_or_move_hook_delegate_->AsWeakPtr(), src_url,
+ dest_url));
+ } else {
+ PostTask(base::BindOnce(&CopyOrMoveHookDelegate::OnError,
+ copy_or_move_hook_delegate_->AsWeakPtr(), src_url,
+ dest_url, error));
}
std::move(callback).Run(error);
@@ -1130,17 +1184,14 @@ void CopyOrMoveOperationDelegate::DidRemoveSourceForMove(
const FileSystemURL& src_url,
StatusCallback callback,
base::File::Error error) {
- if (!progress_callback_.is_null()) {
- if (error == base::File::FILE_OK ||
- error == base::File::FILE_ERROR_NOT_FOUND) {
- progress_callback_.Run(
- FileSystemOperation::CopyOrMoveProgressType::kEndRemoveSource,
- src_url, FileSystemURL(), 0);
- } else {
- progress_callback_.Run(
- FileSystemOperation::CopyOrMoveProgressType::kError, src_url,
- FileSystemURL(), 0);
- }
+ if (error == base::File::FILE_OK ||
+ error == base::File::FILE_ERROR_NOT_FOUND) {
+ PostTask(base::BindOnce(&CopyOrMoveHookDelegate::OnEndRemoveSource,
+ copy_or_move_hook_delegate_->AsWeakPtr(), src_url));
+ } else {
+ PostTask(base::BindOnce(&CopyOrMoveHookDelegate::OnError,
+ copy_or_move_hook_delegate_->AsWeakPtr(), src_url,
+ FileSystemURL(), error));
}
std::move(callback).Run(error);
}
diff --git a/chromium/storage/browser/file_system/copy_or_move_operation_delegate.h b/chromium/storage/browser/file_system/copy_or_move_operation_delegate.h
index ec3a3db7965..eb87c43226b 100644
--- a/chromium/storage/browser/file_system/copy_or_move_operation_delegate.h
+++ b/chromium/storage/browser/file_system/copy_or_move_operation_delegate.h
@@ -10,9 +10,12 @@
#include <map>
#include <memory>
+#include "base/callback_forward.h"
#include "base/component_export.h"
#include "base/memory/ref_counted.h"
+#include "base/memory/weak_ptr.h"
#include "base/time/time.h"
+#include "storage/browser/file_system/copy_or_move_hook_delegate.h"
#include "storage/browser/file_system/recursive_operation_delegate.h"
namespace net {
@@ -31,8 +34,7 @@ class COMPONENT_EXPORT(STORAGE_BROWSER) CopyOrMoveOperationDelegate
: public RecursiveOperationDelegate {
public:
class CopyOrMoveImpl;
- using CopyOrMoveProgressCallback =
- FileSystemOperation::CopyOrMoveProgressCallback;
+
using CopyOrMoveOptionSet = FileSystemOperation::CopyOrMoveOptionSet;
using ErrorBehavior = FileSystemOperation::ErrorBehavior;
@@ -95,7 +97,7 @@ class COMPONENT_EXPORT(STORAGE_BROWSER) CopyOrMoveOperationDelegate
OperationType operation_type,
CopyOrMoveOptionSet options,
ErrorBehavior error_behavior,
- const CopyOrMoveProgressCallback& progress_callback,
+ std::unique_ptr<CopyOrMoveHookDelegate> copy_or_move_hook_delegate,
StatusCallback callback);
CopyOrMoveOperationDelegate(const CopyOrMoveOperationDelegate&) = delete;
@@ -118,17 +120,24 @@ class COMPONENT_EXPORT(STORAGE_BROWSER) CopyOrMoveOperationDelegate
error_url_for_test_ = url;
}
+ void PostTask(base::OnceClosure closure);
+
protected:
void OnCancel() override;
private:
+ void DoProcessFile(const FileSystemURL& url,
+ FileSystemURL dest,
+ StatusCallback callback,
+ base::File::Error error);
void DidCopyOrMoveFile(StatusCallback callback,
CopyOrMoveImpl* impl,
base::File::Error error);
void DidTryRemoveDestRoot(StatusCallback callback, base::File::Error error);
void ProcessDirectoryInternal(const FileSystemURL& src_url,
const FileSystemURL& dest_url,
- StatusCallback callback);
+ StatusCallback callback,
+ base::File::Error error);
void DidCreateDirectory(const FileSystemURL& src_url,
const FileSystemURL& dest_url,
StatusCallback callback,
@@ -144,6 +153,8 @@ class COMPONENT_EXPORT(STORAGE_BROWSER) CopyOrMoveOperationDelegate
StatusCallback callback,
base::File::Error error);
+ void FinishOperation(base::File::Error error);
+
FileSystemURL CreateDestURL(const FileSystemURL& src_url) const;
#if DCHECK_IS_ON()
@@ -156,7 +167,7 @@ class COMPONENT_EXPORT(STORAGE_BROWSER) CopyOrMoveOperationDelegate
const OperationType operation_type_;
const CopyOrMoveOptionSet options_;
const ErrorBehavior error_behavior_;
- const CopyOrMoveProgressCallback progress_callback_;
+ std::unique_ptr<CopyOrMoveHookDelegate> copy_or_move_hook_delegate_;
StatusCallback callback_;
FileSystemURL error_url_for_test_;
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 a5c5349b6a5..5718abe4063 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
@@ -6,6 +6,7 @@
#include <stdint.h>
#include <map>
+#include <memory>
#include <string>
#include <utility>
#include <vector>
@@ -22,9 +23,12 @@
#include "base/run_loop.h"
#include "base/task/single_thread_task_runner.h"
#include "base/test/task_environment.h"
+#include "base/threading/thread.h"
#include "base/threading/thread_task_runner_handle.h"
+#include "base/time/time.h"
#include "components/services/filesystem/public/mojom/types.mojom.h"
#include "storage/browser/file_system/copy_or_move_file_validator.h"
+#include "storage/browser/file_system/copy_or_move_hook_delegate.h"
#include "storage/browser/file_system/copy_or_move_operation_delegate.h"
#include "storage/browser/file_system/file_stream_reader.h"
#include "storage/browser/file_system/file_stream_writer.h"
@@ -38,6 +42,7 @@
#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_backend.h"
#include "storage/browser/test/test_file_system_context.h"
#include "storage/common/file_system/file_system_mount_option.h"
@@ -49,10 +54,10 @@
namespace storage {
-using FileEntryList = FileSystemOperation::FileEntryList;
-
namespace {
+using FileEntryList = FileSystemOperation::FileEntryList;
+
constexpr int64_t kDefaultFileSize = 10;
void ExpectOk(const GURL& origin_url,
@@ -116,26 +121,102 @@ class TestValidatorFactory : public CopyOrMoveFileValidatorFactory {
};
};
-// Records CopyOrMoveProgressCallback invocations.
-struct ProgressRecord {
- FileSystemOperation::CopyOrMoveProgressType type;
- FileSystemURL source_url;
- FileSystemURL dest_url;
- int64_t size;
-};
+class CopyOrMoveRecordDelegate : public CopyOrMoveHookDelegate {
+ public:
+ // Records method invocations.
+ struct ProgressRecord {
+ enum class Type {
+ kBeginFile = 0,
+ kBeginDirectory,
+ kProgress,
+ kEndCopy,
+ kEndMove,
+ kEndRemoveSource,
+ kError,
+ } type;
+ FileSystemURL source_url;
+ FileSystemURL dest_url;
+ int64_t size;
+ base::File::Error error;
+ };
-void RecordProgressCallback(std::vector<ProgressRecord>* records,
- FileSystemOperation::CopyOrMoveProgressType type,
- const FileSystemURL& source_url,
- const FileSystemURL& dest_url,
- int64_t size) {
- ProgressRecord record;
- record.type = type;
- record.source_url = source_url;
- record.dest_url = dest_url;
- record.size = size;
- records->push_back(record);
-}
+ using StatusCallback = FileSystemOperation::StatusCallback;
+
+ explicit CopyOrMoveRecordDelegate(std::vector<ProgressRecord>* records)
+ : records_(records) {
+ DCHECK(records_);
+ }
+
+ ~CopyOrMoveRecordDelegate() override = default;
+
+ void OnBeginProcessFile(const FileSystemURL& source_url,
+ const FileSystemURL& destination_url,
+ StatusCallback callback) override {
+ AddRecord(ProgressRecord::Type::kBeginFile, source_url, destination_url, 0,
+ base::File::FILE_OK);
+
+ std::move(callback).Run(base::File::FILE_OK);
+ }
+
+ void OnBeginProcessDirectory(const FileSystemURL& source_url,
+ const FileSystemURL& destination_url,
+ StatusCallback callback) override {
+ AddRecord(ProgressRecord::Type::kBeginDirectory, source_url,
+ destination_url, 0, base::File::FILE_OK);
+
+ std::move(callback).Run(base::File::FILE_OK);
+ }
+
+ void OnProgress(const FileSystemURL& source_url,
+ const FileSystemURL& destination_url,
+ int64_t size) override {
+ AddRecord(ProgressRecord::Type::kProgress, source_url, destination_url,
+ size, base::File::FILE_OK);
+ }
+
+ void OnError(const FileSystemURL& source_url,
+ const FileSystemURL& destination_url,
+ base::File::Error error) override {
+ AddRecord(ProgressRecord::Type::kError, source_url, destination_url, 0,
+ error);
+ }
+
+ void OnEndCopy(const FileSystemURL& source_url,
+ const FileSystemURL& destination_url) override {
+ AddRecord(ProgressRecord::Type::kEndCopy, source_url, destination_url, 0,
+ base::File::FILE_OK);
+ }
+
+ void OnEndMove(const FileSystemURL& source_url,
+ const FileSystemURL& destination_url) override {
+ AddRecord(ProgressRecord::Type::kEndMove, source_url, destination_url, 0,
+ base::File::FILE_OK);
+ }
+
+ void OnEndRemoveSource(const FileSystemURL& source_url) override {
+ AddRecord(ProgressRecord::Type::kEndRemoveSource, source_url,
+ FileSystemURL(), 0, base::File::FILE_OK);
+ }
+
+ private:
+ void AddRecord(ProgressRecord::Type type,
+ const FileSystemURL& source_url,
+ const FileSystemURL& dest_url,
+ int64_t size,
+ base::File::Error error) {
+ ProgressRecord record;
+ record.type = type;
+ record.source_url = source_url;
+ record.dest_url = dest_url;
+ record.size = size;
+ record.error = error;
+ records_->push_back(record);
+ }
+
+ // Raw ptr safe here, because the records will be destructed at end of test,
+ // i.e., after the CopyOrMove operation has finished.
+ base::raw_ptr<std::vector<ProgressRecord>> records_;
+};
void RecordFileProgressCallback(std::vector<int64_t>* records,
int64_t progress) {
@@ -183,6 +264,8 @@ class CopyOrMoveOperationTestHelper {
: origin_(url::Origin::Create(GURL(origin))),
src_type_(src_type),
dest_type_(dest_type),
+ special_storage_policy_(
+ base::MakeRefCounted<MockSpecialStoragePolicy>()),
task_environment_(base::test::TaskEnvironment::MainThreadType::IO) {}
CopyOrMoveOperationTestHelper(const CopyOrMoveOperationTestHelper&) = delete;
@@ -205,13 +288,12 @@ class CopyOrMoveOperationTestHelper {
ASSERT_TRUE(base_.CreateUniqueTempDir());
base::FilePath base_dir = base_.GetPath();
quota_manager_ = base::MakeRefCounted<MockQuotaManager>(
- false /* is_incognito */, base_dir,
- base::ThreadTaskRunnerHandle::Get().get(),
- nullptr /* special storage policy */);
+ false /* is_incognito */, base_dir, base::ThreadTaskRunnerHandle::Get(),
+ special_storage_policy_);
quota_manager_proxy_ = base::MakeRefCounted<MockQuotaManagerProxy>(
quota_manager_.get(), base::ThreadTaskRunnerHandle::Get());
file_system_context_ =
- CreateFileSystemContextForTesting(quota_manager_proxy_.get(), base_dir);
+ CreateFileSystemContextForTesting(quota_manager_proxy_, base_dir);
// Prepare the origin's root directory.
FileSystemBackend* backend =
@@ -274,26 +356,28 @@ class CopyOrMoveOperationTestHelper {
return AsyncFileTestHelper::Copy(file_system_context_.get(), src, dest);
}
- base::File::Error CopyWithProgress(
+ base::File::Error CopyWithHookDelegate(
const FileSystemURL& src,
const FileSystemURL& dest,
- const AsyncFileTestHelper::CopyOrMoveProgressCallback&
- progress_callback) {
- return AsyncFileTestHelper::CopyWithProgress(file_system_context_.get(),
- src, dest, progress_callback);
+ std::unique_ptr<storage::CopyOrMoveHookDelegate>
+ copy_or_move_hook_delegate) {
+ return AsyncFileTestHelper::CopyWithHookDelegate(
+ file_system_context_.get(), src, dest,
+ std::move(copy_or_move_hook_delegate));
}
base::File::Error Move(const FileSystemURL& src, const FileSystemURL& dest) {
return AsyncFileTestHelper::Move(file_system_context_.get(), src, dest);
}
- base::File::Error MoveWithProgress(
+ base::File::Error MoveWithHookDelegate(
const FileSystemURL& src,
const FileSystemURL& dest,
- const AsyncFileTestHelper::CopyOrMoveProgressCallback&
- progress_callback) {
- return AsyncFileTestHelper::MoveWithProgress(file_system_context_.get(),
- src, dest, progress_callback);
+ std::unique_ptr<storage::CopyOrMoveHookDelegate>
+ copy_or_move_hook_delegate) {
+ return AsyncFileTestHelper::MoveWithHookDelegate(
+ file_system_context_.get(), src, dest,
+ std::move(copy_or_move_hook_delegate));
}
base::File::Error SetUpTestCaseFiles(
@@ -397,13 +481,15 @@ class CopyOrMoveOperationTestHelper {
}
private:
- base::ScopedTempDir base_;
-
const url::Origin origin_;
const FileSystemType src_type_;
const FileSystemType dest_type_;
+ scoped_refptr<MockSpecialStoragePolicy> special_storage_policy_;
+
+ base::ScopedTempDir base_;
base::test::TaskEnvironment task_environment_;
+
scoped_refptr<FileSystemContext> file_system_context_;
scoped_refptr<MockQuotaManagerProxy> quota_manager_proxy_;
scoped_refptr<MockQuotaManager> quota_manager_;
@@ -578,8 +664,8 @@ TEST(LocalFileSystemCopyOrMoveOperationTest, CopyDirectory) {
// Copy it.
ASSERT_EQ(base::File::FILE_OK,
- helper.CopyWithProgress(
- src, dest, AsyncFileTestHelper::CopyOrMoveProgressCallback()));
+ helper.CopyWithHookDelegate(
+ src, dest, std::make_unique<CopyOrMoveHookDelegate>()));
// Verify.
ASSERT_TRUE(helper.DirectoryExists(src));
@@ -659,7 +745,7 @@ TEST(LocalFileSystemCopyOrMoveOperationTest,
};
helper.VerifyTestCaseFiles(dest, kMoveDirResultCases,
- base::size(kMoveDirResultCases));
+ std::size(kMoveDirResultCases));
}
TEST(LocalFileSystemCopyOrMoveOperationTest, CopySingleFileNoValidator) {
@@ -679,7 +765,7 @@ TEST(LocalFileSystemCopyOrMoveOperationTest, CopySingleFileNoValidator) {
ASSERT_EQ(base::File::FILE_ERROR_SECURITY, helper.Copy(src, dest));
}
-TEST(LocalFileSystemCopyOrMoveOperationTest, CopyProgressCallback) {
+TEST(LocalFileSystemCopyOrMoveOperationTest, CopyProgress) {
CopyOrMoveOperationTestHelper helper("http://foo", kFileSystemTypeTemporary,
kFileSystemTypePersistent);
helper.SetUp();
@@ -693,14 +779,22 @@ TEST(LocalFileSystemCopyOrMoveOperationTest, CopyProgressCallback) {
helper.SetUpTestCaseFiles(src, kRegularFileSystemTestCases,
kRegularFileSystemTestCaseSize));
- std::vector<ProgressRecord> records;
+ std::vector<CopyOrMoveRecordDelegate::ProgressRecord> records;
ASSERT_EQ(
base::File::FILE_OK,
- helper.CopyWithProgress(src, dest,
- base::BindRepeating(&RecordProgressCallback,
- base::Unretained(&records))));
+ helper.CopyWithHookDelegate(
+ src, dest, std::make_unique<CopyOrMoveRecordDelegate>(&records)));
+
+ // Verify that for `src` kBeginFile is called.
+ // This behavior is expected, because for the src entry, ProcessFile is always
+ // called independent of whether it is a directory or not.
+ // Note: This might change if the behavior of RecursiveOperationDelegate is
+ // changed.
+ EXPECT_EQ(CopyOrMoveRecordDelegate::ProgressRecord::Type::kBeginFile,
+ records[0].type);
+ EXPECT_EQ(dest, records[0].dest_url);
- // Verify progress callback.
+ // Verify progress records.
for (size_t i = 0; i < kRegularFileSystemTestCaseSize; ++i) {
const FileSystemTestCaseRecord& test_case = kRegularFileSystemTestCases[i];
@@ -725,10 +819,15 @@ TEST(LocalFileSystemCopyOrMoveOperationTest, CopyProgressCallback) {
ASSERT_NE(end_index, records.size());
ASSERT_NE(begin_index, end_index);
- EXPECT_EQ(FileSystemOperation::CopyOrMoveProgressType::kBegin,
- records[begin_index].type);
+ if (test_case.is_directory) {
+ EXPECT_EQ(CopyOrMoveRecordDelegate::ProgressRecord::Type::kBeginDirectory,
+ records[begin_index].type);
+ } else {
+ EXPECT_EQ(CopyOrMoveRecordDelegate::ProgressRecord::Type::kBeginFile,
+ records[begin_index].type);
+ }
EXPECT_EQ(dest_url, records[begin_index].dest_url);
- EXPECT_EQ(FileSystemOperation::CopyOrMoveProgressType::kEndCopy,
+ EXPECT_EQ(CopyOrMoveRecordDelegate::ProgressRecord::Type::kEndCopy,
records[end_index].type);
EXPECT_EQ(dest_url, records[end_index].dest_url);
@@ -740,7 +839,7 @@ TEST(LocalFileSystemCopyOrMoveOperationTest, CopyProgressCallback) {
int64_t current_size = 0;
for (size_t j = begin_index + 1; j < end_index; ++j) {
if (records[j].source_url == src_url) {
- EXPECT_EQ(FileSystemOperation::CopyOrMoveProgressType::kProgress,
+ EXPECT_EQ(CopyOrMoveRecordDelegate::ProgressRecord::Type::kProgress,
records[j].type);
EXPECT_EQ(dest_url, records[j].dest_url);
EXPECT_GE(records[j].size, current_size);
@@ -751,7 +850,7 @@ TEST(LocalFileSystemCopyOrMoveOperationTest, CopyProgressCallback) {
}
}
-TEST(LocalFileSystemCopyOrMoveOperationTest, MoveProgressCallback) {
+TEST(LocalFileSystemCopyOrMoveOperationTest, MoveProgress) {
CopyOrMoveOperationTestHelper helper("http://foo", kFileSystemTypeTemporary,
kFileSystemTypePersistent);
helper.SetUp();
@@ -765,14 +864,13 @@ TEST(LocalFileSystemCopyOrMoveOperationTest, MoveProgressCallback) {
helper.SetUpTestCaseFiles(src, kRegularFileSystemTestCases,
kRegularFileSystemTestCaseSize));
- std::vector<ProgressRecord> records;
+ std::vector<CopyOrMoveRecordDelegate::ProgressRecord> records;
ASSERT_EQ(
base::File::FILE_OK,
- helper.MoveWithProgress(src, dest,
- base::BindRepeating(&RecordProgressCallback,
- base::Unretained(&records))));
+ helper.MoveWithHookDelegate(
+ src, dest, std::make_unique<CopyOrMoveRecordDelegate>(&records)));
- // Verify progress callback.
+ // Verify progress records.
for (size_t i = 0; i < kRegularFileSystemTestCaseSize; ++i) {
const FileSystemTestCaseRecord& test_case = kRegularFileSystemTestCases[i];
@@ -799,27 +897,28 @@ TEST(LocalFileSystemCopyOrMoveOperationTest, MoveProgressCallback) {
if (test_case.is_directory) {
// A directory move starts with kBegin and kEndCopy.
- EXPECT_EQ(FileSystemOperation::CopyOrMoveProgressType::kBegin,
+ EXPECT_EQ(CopyOrMoveRecordDelegate::ProgressRecord::Type::kBeginDirectory,
records[begin_index].type);
EXPECT_EQ(dest_url, records[begin_index].dest_url);
- EXPECT_EQ(FileSystemOperation::CopyOrMoveProgressType::kEndCopy,
+ EXPECT_EQ(CopyOrMoveRecordDelegate::ProgressRecord::Type::kEndCopy,
records[begin_index + 1].type);
EXPECT_EQ(dest_url, records[begin_index + 1].dest_url);
// A directory move ends with kEndRemoveSource, after the contents of the
// directory has been copied.
- EXPECT_EQ(FileSystemOperation::CopyOrMoveProgressType::kEndRemoveSource,
- records[end_index].type);
+ EXPECT_EQ(
+ CopyOrMoveRecordDelegate::ProgressRecord::Type::kEndRemoveSource,
+ records[end_index].type);
EXPECT_FALSE(records[end_index].dest_url.is_valid());
} else {
- // A file move starts with kBegin.
- EXPECT_EQ(FileSystemOperation::CopyOrMoveProgressType::kBegin,
+ // A file move starts with kBeginFile.
+ EXPECT_EQ(CopyOrMoveRecordDelegate::ProgressRecord::Type::kBeginFile,
records[begin_index].type);
EXPECT_EQ(dest_url, records[begin_index].dest_url);
// PROGRESS event's size should be ascending order.
int64_t current_size = 0;
for (size_t j = begin_index + 1; j < end_index - 1; ++j) {
if (records[j].source_url == src_url) {
- EXPECT_EQ(FileSystemOperation::CopyOrMoveProgressType::kProgress,
+ EXPECT_EQ(CopyOrMoveRecordDelegate::ProgressRecord::Type::kProgress,
records[j].type);
EXPECT_EQ(dest_url, records[j].dest_url);
EXPECT_GE(records[j].size, current_size);
@@ -827,17 +926,18 @@ TEST(LocalFileSystemCopyOrMoveOperationTest, MoveProgressCallback) {
}
}
// A file move ends with kEndCopy and kEndRemoveSource.
- EXPECT_EQ(FileSystemOperation::CopyOrMoveProgressType::kEndCopy,
+ EXPECT_EQ(CopyOrMoveRecordDelegate::ProgressRecord::Type::kEndCopy,
records[end_index - 1].type);
EXPECT_EQ(dest_url, records[end_index - 1].dest_url);
- EXPECT_EQ(FileSystemOperation::CopyOrMoveProgressType::kEndRemoveSource,
- records[end_index].type);
+ EXPECT_EQ(
+ CopyOrMoveRecordDelegate::ProgressRecord::Type::kEndRemoveSource,
+ records[end_index].type);
EXPECT_FALSE(records[end_index].dest_url.is_valid());
}
}
}
-TEST(LocalFileSystemCopyOrMoveOperationTest, MoveFileLocalProgressCallback) {
+TEST(LocalFileSystemCopyOrMoveOperationTest, MoveFileLocalProgress) {
CopyOrMoveOperationTestHelper helper("http://foo", kFileSystemTypePersistent,
kFileSystemTypePersistent);
helper.SetUp();
@@ -848,22 +948,20 @@ TEST(LocalFileSystemCopyOrMoveOperationTest, MoveFileLocalProgressCallback) {
// Set up a source file.
ASSERT_EQ(base::File::FILE_OK, helper.CreateFile(src, 10));
- std::vector<ProgressRecord> records;
+ std::vector<CopyOrMoveRecordDelegate::ProgressRecord> records;
ASSERT_EQ(
base::File::FILE_OK,
- helper.MoveWithProgress(src, dest,
- base::BindRepeating(&RecordProgressCallback,
- base::Unretained(&records))));
-
- // There should be 2 records, for kBegin and kEndMove. No progress should be
- // reported.
- EXPECT_EQ(records.size(), (uint64_t)2);
+ helper.MoveWithHookDelegate(
+ src, dest, std::make_unique<CopyOrMoveRecordDelegate>(&records)));
+ // There should be 2 records, for kBeginFile and kEndMove. No progress should
+ // be reported.
+ EXPECT_EQ(records.size(), 2u);
- EXPECT_EQ(FileSystemOperation::CopyOrMoveProgressType::kBegin,
+ EXPECT_EQ(CopyOrMoveRecordDelegate::ProgressRecord::Type::kBeginFile,
records[0].type);
EXPECT_EQ(src, records[0].source_url);
EXPECT_EQ(dest, records[0].dest_url);
- EXPECT_EQ(FileSystemOperation::CopyOrMoveProgressType::kEndMove,
+ EXPECT_EQ(CopyOrMoveRecordDelegate::ProgressRecord::Type::kEndMove,
records[1].type);
EXPECT_EQ(src, records[1].source_url);
EXPECT_EQ(dest, records[1].dest_url);
@@ -1116,7 +1214,7 @@ class CopyOrMoveOperationDelegateTestHelper {
file_system_context_.get(), src, dest,
CopyOrMoveOperationDelegate::OPERATION_COPY, options_,
FileSystemOperation::ERROR_BEHAVIOR_ABORT,
- FileSystemOperation::CopyOrMoveProgressCallback(),
+ std::make_unique<storage::CopyOrMoveHookDelegate>(),
base::BindOnce(&AssignAndQuit, &run_loop, base::Unretained(&result)));
if (error_url_.is_valid()) {
copy_or_move_operation_delegate.SetErrorUrlForTest(error_url_);
@@ -1134,7 +1232,7 @@ class CopyOrMoveOperationDelegateTestHelper {
file_system_context_.get(), src, dest,
CopyOrMoveOperationDelegate::OPERATION_MOVE, options_,
FileSystemOperation::ERROR_BEHAVIOR_ABORT,
- FileSystemOperation::CopyOrMoveProgressCallback(),
+ std::make_unique<storage::CopyOrMoveHookDelegate>(),
base::BindOnce(&AssignAndQuit, &run_loop, base::Unretained(&result)));
if (error_url_.is_valid()) {
copy_or_move_operation_delegate.SetErrorUrlForTest(error_url_);
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 22681a159b1..a226ea684f5 100644
--- a/chromium/storage/browser/file_system/dragged_file_util_unittest.cc
+++ b/chromium/storage/browser/file_system/dragged_file_util_unittest.cc
@@ -2,6 +2,8 @@
// 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/dragged_file_util.h"
+
#include <stddef.h>
#include <map>
@@ -12,7 +14,6 @@
#include "base/check.h"
#include "base/containers/queue.h"
-#include "base/cxx17_backports.h"
#include "base/files/file_enumerator.h"
#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
@@ -20,7 +21,6 @@
#include "base/time/time.h"
#include "build/build_config.h"
#include "components/services/filesystem/public/mojom/types.mojom.h"
-#include "storage/browser/file_system/dragged_file_util.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/isolated_context.h"
@@ -260,7 +260,7 @@ class DraggedFileUtilTest : public testing::Test {
// to simulate a drop with multiple directories.
if (toplevel_root_map_.find(toplevel) == toplevel_root_map_.end()) {
base::FilePath root = root_path().Append(
- kRootPaths[(root_path_index++) % base::size(kRootPaths)]);
+ kRootPaths[(root_path_index++) % std::size(kRootPaths)]);
toplevel_root_map_[toplevel] = root;
toplevels.AddPath(root.Append(path), nullptr);
}
@@ -316,7 +316,7 @@ TEST_F(DraggedFileUtilTest, UnregisteredPathsTest) {
{false, FILE_PATH_LITERAL("bar"), 20},
};
- for (size_t i = 0; i < base::size(kUnregisteredCases); ++i) {
+ for (size_t i = 0; i < std::size(kUnregisteredCases); ++i) {
SCOPED_TRACE(testing::Message() << "Creating kUnregisteredCases " << i);
const FileSystemTestCaseRecord& test_case = kUnregisteredCases[i];
@@ -331,7 +331,7 @@ TEST_F(DraggedFileUtilTest, UnregisteredPathsTest) {
ASSERT_EQ(test_case.is_directory, info.is_directory);
}
- for (size_t i = 0; i < base::size(kUnregisteredCases); ++i) {
+ for (size_t i = 0; i < std::size(kUnregisteredCases); ++i) {
SCOPED_TRACE(testing::Message() << "Creating kUnregisteredCases " << i);
const FileSystemTestCaseRecord& test_case = kUnregisteredCases[i];
FileSystemURL url = GetFileSystemURL(base::FilePath(test_case.path));
diff --git a/chromium/storage/browser/file_system/external_mount_points_unittest.cc b/chromium/storage/browser/file_system/external_mount_points_unittest.cc
index c4f0b7fe4e9..16c3b81acf8 100644
--- a/chromium/storage/browser/file_system/external_mount_points_unittest.cc
+++ b/chromium/storage/browser/file_system/external_mount_points_unittest.cc
@@ -8,7 +8,6 @@
#include <string>
-#include "base/cxx17_backports.h"
#include "base/files/file_path.h"
#include "storage/browser/file_system/file_system_url.h"
#include "storage/common/file_system/file_system_mount_option.h"
@@ -121,7 +120,7 @@ TEST(ExternalMountPointsTest, AddMountPoint) {
}
// Test that final mount point presence state is as expected.
- for (size_t i = 0; i < base::size(kTestCases); ++i) {
+ for (size_t i = 0; i < std::size(kTestCases); ++i) {
base::FilePath found_path;
EXPECT_EQ(kTestCases[i].registered_path != nullptr,
mount_points->GetRegisteredPath(kTestCases[i].name, &found_path))
@@ -329,7 +328,7 @@ TEST(ExternalMountPointsTest, CreateCrackedFileSystemURL) {
#endif
};
- for (size_t i = 0; i < base::size(kTestCases); ++i) {
+ for (size_t i = 0; i < std::size(kTestCases); ++i) {
FileSystemURL cracked = mount_points->CreateCrackedFileSystemURL(
kTestStorageKey, kFileSystemTypeExternal,
base::FilePath(kTestCases[i].path));
@@ -412,7 +411,7 @@ TEST(ExternalMountPointsTest, CrackVirtualPath) {
#endif
};
- for (size_t i = 0; i < base::size(kTestCases); ++i) {
+ for (size_t i = 0; i < std::size(kTestCases); ++i) {
std::string cracked_name;
FileSystemType cracked_type;
std::string cracked_id;
diff --git a/chromium/storage/browser/file_system/file_stream_reader_test.h b/chromium/storage/browser/file_system/file_stream_reader_test.h
index 4517ced6992..0bb8057abe4 100644
--- a/chromium/storage/browser/file_system/file_stream_reader_test.h
+++ b/chromium/storage/browser/file_system/file_stream_reader_test.h
@@ -10,6 +10,7 @@
#include "base/task/single_thread_task_runner.h"
#include "base/test/task_environment.h"
#include "base/threading/thread.h"
+#include "base/time/time.h"
#include "net/base/io_buffer.h"
#include "net/base/net_errors.h"
#include "net/base/test_completion_callback.h"
@@ -52,7 +53,10 @@ class FileStreamReaderTest : public testing::Test {
static void NeverCalled(int unused) { ADD_FAILURE(); }
- private:
+ protected:
+ // Must be listed before base::test::TaskEnvironment.
+ base::ScopedTempDir dir_;
+
// FileSystemContext queries QuotaDatabase, and even with MockQuotaManager
// (which really fakes parts of QuotaManagerImpl), a thread pool is created
// that requires TaskEnvironment.
diff --git a/chromium/storage/browser/file_system/file_stream_writer_test.h b/chromium/storage/browser/file_system/file_stream_writer_test.h
index 9f4fcbdd3c6..21cda9254d2 100644
--- a/chromium/storage/browser/file_system/file_stream_writer_test.h
+++ b/chromium/storage/browser/file_system/file_stream_writer_test.h
@@ -39,7 +39,10 @@ class FileStreamWriterTest : public testing::Test {
static void NeverCalled(int unused) { ADD_FAILURE(); }
- private:
+ protected:
+ // Must be listed before base::test::TaskEnvironment.
+ base::ScopedTempDir dir_;
+
base::test::TaskEnvironment task_environment_{
base::test::TaskEnvironment::MainThreadType::IO};
};
diff --git a/chromium/storage/browser/file_system/file_system_context.cc b/chromium/storage/browser/file_system/file_system_context.cc
index 808295dbe43..afb79af2dea 100644
--- a/chromium/storage/browser/file_system/file_system_context.cc
+++ b/chromium/storage/browser/file_system/file_system_context.cc
@@ -154,6 +154,7 @@ scoped_refptr<FileSystemContext> FileSystemContext::Create(
std::vector<std::unique_ptr<FileSystemBackend>> additional_backends,
const std::vector<URLRequestAutoMountHandler>& auto_mount_handlers,
const base::FilePath& partition_path,
+ const base::FilePath& bucket_base_path,
const FileSystemOptions& options) {
bool force_override_incognito = base::FeatureList::IsEnabled(
features::kIncognitoFileSystemContextForTesting);
@@ -168,8 +169,8 @@ scoped_refptr<FileSystemContext> FileSystemContext::Create(
std::move(io_task_runner), std::move(file_task_runner),
std::move(external_mount_points), std::move(special_storage_policy),
std::move(quota_manager_proxy), std::move(additional_backends),
- auto_mount_handlers, partition_path, maybe_overridden_options,
- base::PassKey<FileSystemContext>());
+ auto_mount_handlers, partition_path, bucket_base_path,
+ maybe_overridden_options, base::PassKey<FileSystemContext>());
context->Initialize();
return context;
}
@@ -183,6 +184,7 @@ FileSystemContext::FileSystemContext(
std::vector<std::unique_ptr<FileSystemBackend>> additional_backends,
const std::vector<URLRequestAutoMountHandler>& auto_mount_handlers,
const base::FilePath& partition_path,
+ const base::FilePath& bucket_base_path,
const FileSystemOptions& options,
base::PassKey<FileSystemContext>)
: base::RefCountedDeleteOnSequence<FileSystemContext>(io_task_runner),
@@ -200,6 +202,7 @@ FileSystemContext::FileSystemContext(
quota_manager_proxy_.get(),
default_file_task_runner_.get(),
partition_path,
+ bucket_base_path,
special_storage_policy,
options,
env_override_.get())),
@@ -208,6 +211,7 @@ FileSystemContext::FileSystemContext(
plugin_private_backend_(std::make_unique<PluginPrivateFileSystemBackend>(
default_file_task_runner_,
partition_path,
+ bucket_base_path,
std::move(special_storage_policy),
options,
env_override_.get())),
@@ -215,6 +219,7 @@ FileSystemContext::FileSystemContext(
auto_mount_handlers_(auto_mount_handlers),
external_mount_points_(std::move(external_mount_points)),
partition_path_(partition_path),
+ bucket_base_path_(bucket_base_path),
is_incognito_(options.is_incognito()),
operation_runner_(std::make_unique<FileSystemOperationRunner>(
base::PassKey<FileSystemContext>(),
@@ -292,7 +297,7 @@ bool FileSystemContext::DeleteDataForStorageKeyOnFileTaskRunner(
if (!backend->GetQuotaUtil())
continue;
if (backend->GetQuotaUtil()->DeleteStorageKeyDataOnFileTaskRunner(
- this, quota_manager_proxy(), storage_key,
+ this, quota_manager_proxy().get(), storage_key,
type_backend_pair.first) != base::File::FILE_OK) {
// Continue the loop, but record the failure.
success = false;
@@ -553,7 +558,7 @@ void FileSystemContext::DeleteFileSystem(const blink::StorageKey& storage_key,
base::BindOnce(
&FileSystemQuotaUtil::DeleteStorageKeyDataOnFileTaskRunner,
base::Unretained(backend->GetQuotaUtil()), base::RetainedRef(this),
- base::Unretained(quota_manager_proxy()), storage_key, type),
+ base::Unretained(quota_manager_proxy().get()), storage_key, type),
std::move(callback));
}
diff --git a/chromium/storage/browser/file_system/file_system_context.h b/chromium/storage/browser/file_system/file_system_context.h
index 15b2f72ef95..a60757851a3 100644
--- a/chromium/storage/browser/file_system/file_system_context.h
+++ b/chromium/storage/browser/file_system/file_system_context.h
@@ -135,6 +135,7 @@ class COMPONENT_EXPORT(STORAGE_BROWSER) FileSystemContext
std::vector<std::unique_ptr<FileSystemBackend>> additional_backends,
const std::vector<URLRequestAutoMountHandler>& auto_mount_handlers,
const base::FilePath& partition_path,
+ const base::FilePath& bucket_base_path,
const FileSystemOptions& options);
// Exposed for base::MakeRefCounted(). Instances should be obtained from the
@@ -148,6 +149,7 @@ class COMPONENT_EXPORT(STORAGE_BROWSER) FileSystemContext
std::vector<std::unique_ptr<FileSystemBackend>> additional_backends,
const std::vector<URLRequestAutoMountHandler>& auto_mount_handlers,
const base::FilePath& partition_path,
+ const base::FilePath& bucket_base_path,
const FileSystemOptions& options,
base::PassKey<FileSystemContext>);
@@ -162,8 +164,8 @@ class COMPONENT_EXPORT(STORAGE_BROWSER) FileSystemContext
const blink::StorageKey& storage_key,
FileSystemType type);
- QuotaManagerProxy* quota_manager_proxy() const {
- return quota_manager_proxy_.get();
+ const scoped_refptr<QuotaManagerProxy>& quota_manager_proxy() const {
+ return quota_manager_proxy_;
}
// Discards inflight operations in the operation runner.
@@ -305,6 +307,8 @@ class COMPONENT_EXPORT(STORAGE_BROWSER) FileSystemContext
const base::FilePath& partition_path() const { return partition_path_; }
+ const base::FilePath& bucket_base_path() const { return bucket_base_path_; }
+
// Same as `CrackFileSystemURL`, but cracks FileSystemURL created from `url`
// and `storage_key`.
FileSystemURL CrackURL(const GURL& url,
@@ -346,6 +350,12 @@ class COMPONENT_EXPORT(STORAGE_BROWSER) FileSystemContext
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();
+ }
+
private:
// For CreateFileSystemOperation.
friend class FileSystemOperationRunner;
@@ -424,11 +434,6 @@ class COMPONENT_EXPORT(STORAGE_BROWSER) FileSystemContext
return sandbox_backend_.get();
}
- // Used only by test code.
- PluginPrivateFileSystemBackend* plugin_private_backend() const {
- return plugin_private_backend_.get();
- }
-
// Override the default leveldb Env with `env_override_` if set.
std::unique_ptr<leveldb::Env> env_override_;
@@ -470,6 +475,10 @@ class COMPONENT_EXPORT(STORAGE_BROWSER) FileSystemContext
// The base path of the storage partition for this context.
const base::FilePath partition_path_;
+ // The base path of the file directory where StorageBucket data is stored for
+ // this context.
+ const base::FilePath bucket_base_path_;
+
const bool is_incognito_;
const std::unique_ptr<FileSystemOperationRunner> operation_runner_;
diff --git a/chromium/storage/browser/file_system/file_system_context_unittest.cc b/chromium/storage/browser/file_system/file_system_context_unittest.cc
index 339ba57520b..8ada21dd10a 100644
--- a/chromium/storage/browser/file_system/file_system_context_unittest.cc
+++ b/chromium/storage/browser/file_system/file_system_context_unittest.cc
@@ -6,7 +6,6 @@
#include <stddef.h>
-#include "base/cxx17_backports.h"
#include "base/files/scoped_temp_dir.h"
#include "base/memory/scoped_refptr.h"
#include "base/strings/stringprintf.h"
@@ -68,7 +67,7 @@ class FileSystemContextTest : public testing::Test {
storage_policy_, mock_quota_manager_->proxy(),
std::vector<std::unique_ptr<FileSystemBackend>>(),
std::vector<URLRequestAutoMountHandler>(), data_dir_.GetPath(),
- CreateAllowFileAccessOptions());
+ data_dir_.GetPath(), CreateAllowFileAccessOptions());
}
// Verifies a *valid* filesystem url has expected values.
@@ -260,7 +259,7 @@ TEST_F(FileSystemContextTest, CrackFileSystemURL) {
kFileSystemTypeUnknown, kFileSystemTypeUnknown, FPL(""), std::string()},
};
- for (size_t i = 0; i < base::size(kTestCases); ++i) {
+ for (size_t i = 0; i < std::size(kTestCases); ++i) {
const base::FilePath virtual_path =
base::FilePath::FromASCII(kTestCases[i].root)
.Append(kVirtualPathNoRoot);
diff --git a/chromium/storage/browser/file_system/file_system_operation.h b/chromium/storage/browser/file_system/file_system_operation.h
index 5dc9c635da3..c3faa33578b 100644
--- a/chromium/storage/browser/file_system/file_system_operation.h
+++ b/chromium/storage/browser/file_system/file_system_operation.h
@@ -26,14 +26,12 @@ class Time;
}
namespace storage {
-class ShareableFileReference;
-}
-
-namespace storage {
+class CopyOrMoveHookDelegate;
class FileSystemContext;
class FileSystemURL;
class FileWriterDelegate;
+class ShareableFileReference;
// The interface class for FileSystemOperation implementations.
//
@@ -77,9 +75,11 @@ class FileSystemOperation {
base::OnceCallback<void(base::File::Error result,
const base::File::Info& file_info)>;
- // Used for OpenFile(). |on_close_callback| will be called after the file is
- // closed in the child process. It can be null, if no operation is needed on
- // closing a file.
+ // Used for OpenFile(). File system implementations can specify an
+ // `on_close_callback` if an operation is needed after closing a file. If
+ // non-null, OpenFile() callers must run the callback (on the IO thread)
+ // after the file closes. If the file is duped, the callback should not be run
+ // until all dups of the file have been closed.
using OpenFileCallback =
base::OnceCallback<void(base::File file,
base::OnceClosure on_close_callback)>;
@@ -127,115 +127,6 @@ class FileSystemOperation {
// fails some of the operations.
enum ErrorBehavior { ERROR_BEHAVIOR_ABORT, ERROR_BEHAVIOR_SKIP };
- // Used for progress update callback for Copy() and Move().
- //
- // Note that Move() has both a same-filesystem (1) and a cross-filesystem (2)
- // implementation.
- // 1) Requires metadata updates. Depending on the underlying implementation:
- // - we either only update the metadata of (or in other words, rename) the
- // moving directory
- // - or the directories are recursively copied + deleted, while the files are
- // moved by having their metadata updated.
- // 2) Degrades into copy + delete: each entry is copied and deleted
- // recursively.
- //
- // kBegin is fired at the start of each copy or move operation (for
- // both file and directory). The |source_url| and the |destination_url| are
- // the URLs of the source and the destination entries. |size| should not be
- // used.
- //
- // kProgress is fired periodically during file transfer (not fired for
- // same-filesystem move and directory copy/move).
- // The |source_url| and the |destination_url| are the URLs of the source and
- // the destination entries. |size| is the number of cumulative copied bytes
- // for the currently copied file. Both at beginning and ending of file
- // transfer, PROGRESS event should be called. At beginning, |size| should be
- // 0. At ending, |size| should be the size of the file.
- //
- // kEndCopy is fired for each destination entry that has been successfully
- // copied (for both file and directory). The |source_url| and the
- // |destination_url| are the URLs of the source and the destination entries.
- // |size| should not be used.
- //
- // kEndMove is fired for each entry that has been successfully moved (for both
- // file and directory), in the case of a same-filesystem move. The
- // |source_url| and the |destination_url| are the URLs of the source and the
- // destination entries. |size| should not be used.
- //
- // kEndRemoveSource, applies in the Move() case only, and is fired for each
- // source entry that has been successfully removed from its source location
- // (for both file and directory). The |source_url| is the URL of the source
- // entry. |destination_url| and |size| should not be used.
- //
- // When moving files, the expected events are as follows.
- // Copy: kBegin -> kProgress -> ... -> kProgress -> kEndCopy.
- // Move (same-filesystem): kBegin -> kEndMove.
- // Move (cross-filesystem): kBegin -> kProgress -> ... -> kProgress ->
- // kEndCopy -> kEndRemoveSource.
- //
- // Here is an example callback sequence of for a copy or a cross-filesystem
- // move. Suppose there are a/b/c.txt (100 bytes) and a/b/d.txt (200 bytes),
- // and trying to transfer a to x recursively, then the progress update
- // sequence will be:
- //
- // kBegin a x/a (starting create "a" directory in x/).
- // kEndCopy a x/a (creating "a" directory in x/ is finished).
- //
- // kBegin a/b x/a/b (starting create "b" directory in x/a).
- // kEndCopy a/b x/a/b (creating "b" directory in x/a/ is
- // finished).
- //
- // kBegin a/b/c.txt x/a/b/c.txt (starting to transfer "c.txt" in
- // x/a/b/).
- // kProgress a/b/c.txt x/a/b/c.txt 0 (The first kProgress's |size|
- // should be 0).
- // kProgress a/b/c.txt x/a/b/c.txt 10
- // :
- // kProgress a/b/c.txt x/a/b/c.txt 90
- // kProgress a/b/c.txt x/a/b/c.txt 100 (The last kProgress's |size| should be
- // the size of the file).
- // kEndCopy a/b/c.txt x/a/b/c.txt (transferring "c.txt" is
- // finished).
- // kEndRemoveSource a/b/c.txt ("copy + delete" move case).
- //
- // kBegin a/b/d.txt x/a/b/d.txt (starting to transfer "d.txt" in x/a/b).
- // kProgress a/b/d.txt x/a/b/d.txt 0 (The first kProgress's |size| should be
- // 0).
- // kProgress a/b/d.txt x/a/b/d.txt 10
- // :
- // kProgress a/b/d.txt x/a/b/d.txt 190
- // kProgress a/b/d.txt x/a/b/d.txt 200 (The last kProgress's |size| should be
- // the size of the file).
- // kEndCopy a/b/d.txt x/a/b/d.txt (transferring "d.txt" is
- // finished).
- // kEndRemoveSource a/b/d.txt ("copy + delete" move case).
- //
- // kEndRemoveSource a/b ("copy + delete" move case).
- //
- // kEndRemoveSource a ("copy + delete" move case).
- //
- // Note that event sequence of a/b/c.txt and a/b/d.txt can be interlaced,
- // because they can be done in parallel. Also kProgress events are optional,
- // so they may not be appeared.
- // All the progress callback invocation should be done before StatusCallback
- // given to the Copy is called. Especially if an error is found before first
- // progres callback invocation, the progress callback may NOT invoked for the
- // copy.
- //
- enum class CopyOrMoveProgressType {
- kBegin = 0,
- kProgress,
- kEndCopy,
- kEndMove,
- kEndRemoveSource,
- kError,
- };
- using CopyOrMoveProgressCallback =
- base::RepeatingCallback<void(CopyOrMoveProgressType type,
- const FileSystemURL& source_url,
- const FileSystemURL& destination_url,
- int64_t size)>;
-
// Used for CopyFileLocal() to report progress update.
// |size| is the cumulative copied bytes for the copy.
// At the beginning the progress callback should be called with |size| = 0,
@@ -326,9 +217,9 @@ class FileSystemOperation {
// comment for details.
// |error_behavior| specifies whether this continues operation after it
// failed an operation or not.
- // |progress_callback| is periodically called to report the progress
- // update. See also the comment of CopyOrMoveProgressCallback. This callback
- // is optional.
+ // |copy_or_move_hook_delegate|'s functions are periodically called to report
+ // the current state of the operation. See also the comments of
+ // CopyOrMoveHookDelegate. |copy_or_move_hook_delegate| is required.
//
// For recursive case this internally creates new FileSystemOperations and
// calls:
@@ -338,12 +229,13 @@ class FileSystemOperation {
// CopyInForeignFile and CreateDirectory on dest filesystem
// for cross-filesystem case.
//
- virtual void Copy(const FileSystemURL& src_path,
- const FileSystemURL& dest_path,
- CopyOrMoveOptionSet options,
- ErrorBehavior error_behavior,
- const CopyOrMoveProgressCallback& progress_callback,
- StatusCallback callback) = 0;
+ virtual void Copy(
+ const FileSystemURL& src_path,
+ const FileSystemURL& dest_path,
+ CopyOrMoveOptionSet options,
+ ErrorBehavior error_behavior,
+ std::unique_ptr<CopyOrMoveHookDelegate> copy_or_move_hook_delegate,
+ StatusCallback callback) = 0;
// Moves a file or directory from |src_path| to |dest_path|. A new file
// or directory is created at |dest_path| as needed.
@@ -351,9 +243,9 @@ class FileSystemOperation {
// comment for details.
// |error_behavior| specifies whether this continues operation after it
// failed an operation or not.
- // |progress_callback| is periodically called to report the progress
- // update. See also the comment of CopyProgressCallback. This callback is
- // optional.
+ // |copy_or_move_hook_delegate|'s functions are periodically called to report
+ // the current state of the operation. See also the comments of
+ // CopyOrMoveHookDelegate. |copy_or_move_hook_delegate| is required.
//
// For recursive case this internally creates new FileSystemOperations and
// calls:
@@ -365,12 +257,13 @@ class FileSystemOperation {
//
// TODO(crbug.com/171284): Restore directory timestamps after the Move
// operation.
- virtual void Move(const FileSystemURL& src_path,
- const FileSystemURL& dest_path,
- CopyOrMoveOptionSet options,
- ErrorBehavior error_behavior,
- const CopyOrMoveProgressCallback& progress_callback,
- StatusCallback callback) = 0;
+ virtual void Move(
+ const FileSystemURL& src_path,
+ const FileSystemURL& dest_path,
+ CopyOrMoveOptionSet options,
+ ErrorBehavior error_behavior,
+ std::unique_ptr<CopyOrMoveHookDelegate> copy_or_move_hook_delegate,
+ StatusCallback callback) = 0;
// Checks if a directory is present at |path|.
virtual void DirectoryExists(const FileSystemURL& path,
diff --git a/chromium/storage/browser/file_system/file_system_operation_impl.cc b/chromium/storage/browser/file_system/file_system_operation_impl.cc
index 14cc1980aba..97f5c14c452 100644
--- a/chromium/storage/browser/file_system/file_system_operation_impl.cc
+++ b/chromium/storage/browser/file_system/file_system_operation_impl.cc
@@ -12,6 +12,7 @@
#include <utility>
#include "base/bind.h"
+#include "base/callback.h"
#include "base/callback_helpers.h"
#include "base/task/single_thread_task_runner.h"
#include "base/threading/sequenced_task_runner_handle.h"
@@ -21,6 +22,7 @@
#include "net/url_request/url_request.h"
#include "storage/browser/blob/shareable_file_reference.h"
#include "storage/browser/file_system/async_file_util.h"
+#include "storage/browser/file_system/copy_or_move_hook_delegate.h"
#include "storage/browser/file_system/copy_or_move_operation_delegate.h"
#include "storage/browser/file_system/file_observers.h"
#include "storage/browser/file_system/file_system_backend.h"
@@ -103,15 +105,16 @@ void FileSystemOperationImpl::Copy(
const FileSystemURL& dest_url,
CopyOrMoveOptionSet options,
ErrorBehavior error_behavior,
- const CopyOrMoveProgressCallback& progress_callback,
+ std::unique_ptr<CopyOrMoveHookDelegate> copy_or_move_hook_delegate,
StatusCallback callback) {
+ DCHECK(copy_or_move_hook_delegate);
DCHECK(SetPendingOperationType(kOperationCopy));
DCHECK(!recursive_operation_delegate_);
recursive_operation_delegate_ = std::make_unique<CopyOrMoveOperationDelegate>(
file_system_context(), src_url, dest_url,
CopyOrMoveOperationDelegate::OPERATION_COPY, options, error_behavior,
- progress_callback,
+ std::move(copy_or_move_hook_delegate),
base::BindOnce(&FileSystemOperationImpl::DidFinishOperation,
weak_factory_.GetWeakPtr(), std::move(callback)));
recursive_operation_delegate_->RunRecursively();
@@ -122,14 +125,15 @@ void FileSystemOperationImpl::Move(
const FileSystemURL& dest_url,
CopyOrMoveOptionSet options,
ErrorBehavior error_behavior,
- const CopyOrMoveProgressCallback& progress_callback,
+ std::unique_ptr<CopyOrMoveHookDelegate> copy_or_move_hook_delegate,
StatusCallback callback) {
+ DCHECK(copy_or_move_hook_delegate);
DCHECK(SetPendingOperationType(kOperationMove));
DCHECK(!recursive_operation_delegate_);
recursive_operation_delegate_ = std::make_unique<CopyOrMoveOperationDelegate>(
file_system_context(), src_url, dest_url,
CopyOrMoveOperationDelegate::OPERATION_MOVE, options, error_behavior,
- progress_callback,
+ std::move(copy_or_move_hook_delegate),
base::BindOnce(&FileSystemOperationImpl::DidFinishOperation,
weak_factory_.GetWeakPtr(), std::move(callback)));
recursive_operation_delegate_->RunRecursively();
@@ -409,7 +413,7 @@ void FileSystemOperationImpl::GetUsageAndQuotaThenRunTask(
const FileSystemURL& url,
base::OnceClosure task,
base::OnceClosure error_callback) {
- QuotaManagerProxy* quota_manager_proxy =
+ const scoped_refptr<QuotaManagerProxy>& quota_manager_proxy =
file_system_context()->quota_manager_proxy();
if (!quota_manager_proxy ||
!file_system_context()->GetQuotaUtil(url.type())) {
diff --git a/chromium/storage/browser/file_system/file_system_operation_impl.h b/chromium/storage/browser/file_system/file_system_operation_impl.h
index 419d0b5b3fe..119d598a87b 100644
--- a/chromium/storage/browser/file_system/file_system_operation_impl.h
+++ b/chromium/storage/browser/file_system/file_system_operation_impl.h
@@ -58,13 +58,13 @@ class COMPONENT_EXPORT(STORAGE_BROWSER) FileSystemOperationImpl
const FileSystemURL& dest_url,
CopyOrMoveOptionSet options,
ErrorBehavior error_behavior,
- const CopyOrMoveProgressCallback& progress_callback,
+ std::unique_ptr<CopyOrMoveHookDelegate> copy_or_move_hook_delegate,
StatusCallback callback) override;
void Move(const FileSystemURL& src_url,
const FileSystemURL& dest_url,
CopyOrMoveOptionSet options,
ErrorBehavior error_behavior,
- const CopyOrMoveProgressCallback& progress_callback,
+ std::unique_ptr<CopyOrMoveHookDelegate> copy_or_move_hook_delegate,
StatusCallback callback) override;
void DirectoryExists(const FileSystemURL& url,
StatusCallback callback) override;
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 9cd93ac877b..ad8abd50bbc 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
@@ -12,7 +12,6 @@
#include <utility>
#include "base/bind.h"
-#include "base/cxx17_backports.h"
#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
#include "base/memory/ptr_util.h"
@@ -22,8 +21,10 @@
#include "base/strings/stringprintf.h"
#include "base/test/task_environment.h"
#include "base/threading/thread_task_runner_handle.h"
+#include "base/time/time.h"
#include "components/services/filesystem/public/mojom/types.mojom.h"
#include "storage/browser/blob/shareable_file_reference.h"
+#include "storage/browser/file_system/copy_or_move_hook_delegate.h"
#include "storage/browser/file_system/file_system_context.h"
#include "storage/browser/file_system/file_system_file_util.h"
#include "storage/browser/file_system/file_system_operation_context.h"
@@ -36,6 +37,7 @@
#include "storage/browser/test/mock_file_update_observer.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 "storage/common/file_system/file_system_util.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -47,13 +49,14 @@ namespace storage {
class FileSystemOperationImplTest : public testing::Test {
public:
FileSystemOperationImplTest()
- : task_environment_(base::test::TaskEnvironment::MainThreadType::IO) {}
+ : special_storage_policy_(
+ base::MakeRefCounted<MockSpecialStoragePolicy>()),
+ task_environment_(base::test::TaskEnvironment::MainThreadType::IO) {}
FileSystemOperationImplTest(const FileSystemOperationImplTest&) = delete;
FileSystemOperationImplTest& operator=(const FileSystemOperationImplTest&) =
delete;
- protected:
void SetUp() override {
EXPECT_TRUE(base_.CreateUniqueTempDir());
change_observers_ = MockFileChangeObserver::CreateList(&change_observer_);
@@ -62,8 +65,7 @@ class FileSystemOperationImplTest : public testing::Test {
base::FilePath base_dir = base_.GetPath().AppendASCII("filesystem");
quota_manager_ = base::MakeRefCounted<MockQuotaManager>(
/* is_incognito= */ false, base_dir,
- base::ThreadTaskRunnerHandle::Get().get(),
- /* special storage policy= */ nullptr);
+ base::ThreadTaskRunnerHandle::Get(), special_storage_policy_);
quota_manager_proxy_ = base::MakeRefCounted<MockQuotaManagerProxy>(
quota_manager(), base::ThreadTaskRunnerHandle::Get());
sandbox_file_system_.SetUp(base_dir, quota_manager_proxy_.get());
@@ -285,8 +287,8 @@ class FileSystemOperationImplTest : public testing::Test {
base::RunLoop run_loop;
update_observer_.Enable();
operation_runner()->Move(
- src, dest, options, storage::FileSystemOperation::ERROR_BEHAVIOR_ABORT,
- storage::FileSystemOperation::CopyOrMoveProgressCallback(),
+ src, dest, options, FileSystemOperation::ERROR_BEHAVIOR_ABORT,
+ std::make_unique<CopyOrMoveHookDelegate>(),
RecordStatusCallback(run_loop.QuitClosure(), &status));
run_loop.Run();
update_observer_.Disable();
@@ -301,7 +303,7 @@ class FileSystemOperationImplTest : public testing::Test {
update_observer_.Enable();
operation_runner()->Copy(
src, dest, options, FileSystemOperation::ERROR_BEHAVIOR_ABORT,
- FileSystemOperation::CopyOrMoveProgressCallback(),
+ std::make_unique<CopyOrMoveHookDelegate>(),
RecordStatusCallback(run_loop.QuitClosure(), &status));
run_loop.Run();
update_observer_.Disable();
@@ -436,15 +438,17 @@ class FileSystemOperationImplTest : public testing::Test {
return status;
}
+ protected:
+ scoped_refptr<MockSpecialStoragePolicy> special_storage_policy_;
+
+ // Common temp base for nondestructive uses.
+ base::ScopedTempDir base_;
+
base::test::TaskEnvironment task_environment_;
- private:
scoped_refptr<QuotaManager> quota_manager_;
scoped_refptr<QuotaManagerProxy> quota_manager_proxy_;
- // Common temp base for nondestructive uses.
- base::ScopedTempDir base_;
-
SandboxFileSystemTestHelper sandbox_file_system_;
// For post-operation status.
@@ -811,7 +815,7 @@ TEST_F(FileSystemOperationImplTest, TestCopyInForeignFileSuccess) {
base::FilePath src_local_disk_file_path;
base::CreateTemporaryFile(&src_local_disk_file_path);
const char test_data[] = "foo";
- int data_size = base::size(test_data);
+ int data_size = std::size(test_data);
base::WriteFile(src_local_disk_file_path, test_data, data_size);
FileSystemURL dest_dir(CreateDirectory("dest"));
@@ -841,7 +845,7 @@ TEST_F(FileSystemOperationImplTest, TestCopyInForeignFileFailureByQuota) {
base::FilePath src_local_disk_file_path;
base::CreateTemporaryFile(&src_local_disk_file_path);
const char test_data[] = "foo";
- base::WriteFile(src_local_disk_file_path, test_data, base::size(test_data));
+ base::WriteFile(src_local_disk_file_path, test_data, std::size(test_data));
FileSystemURL dest_dir(CreateDirectory("dest"));
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 55fe648ad22..4bff94324f5 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
@@ -27,6 +27,7 @@
#include "storage/browser/test/mock_blob_util.h"
#include "storage/browser/test/mock_file_change_observer.h"
#include "storage/browser/test/mock_quota_manager.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"
#include "storage/common/file_system/file_system_util.h"
@@ -51,7 +52,10 @@ void AssertStatusEq(base::File::Error expected, base::File::Error actual) {
class FileSystemOperationImplWriteTest : public testing::Test {
public:
FileSystemOperationImplWriteTest()
- : task_environment_(base::test::TaskEnvironment::MainThreadType::IO),
+ : special_storage_policy_(
+ base::MakeRefCounted<MockSpecialStoragePolicy>()),
+ task_environment_(base::test::TaskEnvironment::MainThreadType::IO),
+ virtual_path_(FILE_PATH_LITERAL("temporary file")),
status_(base::File::FILE_OK),
cancel_status_(base::File::FILE_ERROR_FAILED),
bytes_written_(0),
@@ -65,16 +69,14 @@ class FileSystemOperationImplWriteTest : public testing::Test {
const FileSystemOperationImplWriteTest&) = delete;
void SetUp() override {
- ASSERT_TRUE(dir_.CreateUniqueTempDir());
+ ASSERT_TRUE(data_dir_.CreateUniqueTempDir());
quota_manager_ = base::MakeRefCounted<MockQuotaManager>(
- /* is_incognito= */ false, dir_.GetPath(),
- base::ThreadTaskRunnerHandle::Get().get(),
- /* special storage policy= */ nullptr);
- virtual_path_ = base::FilePath(FILE_PATH_LITERAL("temporary file"));
+ /* is_incognito= */ false, data_dir_.GetPath(),
+ base::ThreadTaskRunnerHandle::Get(), special_storage_policy_);
file_system_context_ = CreateFileSystemContextForTesting(
- quota_manager_->proxy(), dir_.GetPath());
+ quota_manager_->proxy(), data_dir_.GetPath());
blob_storage_context_ = std::make_unique<BlobStorageContext>();
file_system_context_->operation_runner()->CreateFile(
@@ -147,13 +149,15 @@ class FileSystemOperationImplWriteTest : public testing::Test {
return blob_storage_context_.get();
}
+ scoped_refptr<MockSpecialStoragePolicy> special_storage_policy_;
+
+ base::ScopedTempDir data_dir_;
base::test::TaskEnvironment task_environment_;
scoped_refptr<FileSystemContext> file_system_context_;
scoped_refptr<MockQuotaManager> quota_manager_;
- base::ScopedTempDir dir_;
- base::FilePath virtual_path_;
+ const base::FilePath virtual_path_;
// For post-operation status.
base::File::Error status_;
diff --git a/chromium/storage/browser/file_system/file_system_operation_runner.cc b/chromium/storage/browser/file_system/file_system_operation_runner.cc
index c910fe401a9..70672c6f525 100644
--- a/chromium/storage/browser/file_system/file_system_operation_runner.cc
+++ b/chromium/storage/browser/file_system/file_system_operation_runner.cc
@@ -12,14 +12,17 @@
#include "base/auto_reset.h"
#include "base/bind.h"
+#include "base/callback.h"
#include "base/containers/contains.h"
#include "base/memory/ptr_util.h"
#include "base/threading/thread_task_runner_handle.h"
#include "net/url_request/url_request_context.h"
#include "storage/browser/blob/shareable_file_reference.h"
+#include "storage/browser/file_system/copy_or_move_hook_delegate.h"
#include "storage/browser/file_system/file_observers.h"
#include "storage/browser/file_system/file_stream_writer.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_writer_delegate.h"
namespace storage {
@@ -93,8 +96,9 @@ OperationID FileSystemOperationRunner::Copy(
const FileSystemURL& dest_url,
CopyOrMoveOptionSet options,
ErrorBehavior error_behavior,
- const CopyOrMoveProgressCallback& progress_callback,
+ std::unique_ptr<CopyOrMoveHookDelegate> copy_or_move_hook_delegate,
StatusCallback callback) {
+ DCHECK(copy_or_move_hook_delegate);
base::File::Error error = base::File::FILE_OK;
std::unique_ptr<FileSystemOperation> operation =
file_system_context_->CreateFileSystemOperation(dest_url, &error);
@@ -107,14 +111,10 @@ OperationID FileSystemOperationRunner::Copy(
}
PrepareForWrite(id, dest_url);
PrepareForRead(id, src_url);
- operation_raw->Copy(
- src_url, dest_url, options, error_behavior,
- progress_callback.is_null()
- ? CopyOrMoveProgressCallback()
- : base::BindRepeating(&FileSystemOperationRunner::OnCopyProgress,
- weak_ptr_, id, progress_callback),
- base::BindOnce(&FileSystemOperationRunner::DidFinish, weak_ptr_, id,
- std::move(callback)));
+ operation_raw->Copy(src_url, dest_url, options, error_behavior,
+ std::move(copy_or_move_hook_delegate),
+ base::BindOnce(&FileSystemOperationRunner::DidFinish,
+ weak_ptr_, id, std::move(callback)));
return id;
}
@@ -123,8 +123,9 @@ OperationID FileSystemOperationRunner::Move(
const FileSystemURL& dest_url,
CopyOrMoveOptionSet options,
ErrorBehavior error_behavior,
- const CopyOrMoveProgressCallback& progress_callback,
+ std::unique_ptr<CopyOrMoveHookDelegate> copy_or_move_hook_delegate,
StatusCallback callback) {
+ DCHECK(copy_or_move_hook_delegate);
base::File::Error error = base::File::FILE_OK;
std::unique_ptr<FileSystemOperation> operation =
file_system_context_->CreateFileSystemOperation(dest_url, &error);
@@ -137,14 +138,10 @@ OperationID FileSystemOperationRunner::Move(
}
PrepareForWrite(id, dest_url);
PrepareForWrite(id, src_url);
- operation_raw->Move(
- src_url, dest_url, options, error_behavior,
- progress_callback.is_null()
- ? CopyOrMoveProgressCallback()
- : base::BindRepeating(&FileSystemOperationRunner::OnCopyProgress,
- weak_ptr_, id, progress_callback),
- base::BindOnce(&FileSystemOperationRunner::DidFinish, weak_ptr_, id,
- std::move(callback)));
+ operation_raw->Move(src_url, dest_url, options, error_behavior,
+ std::move(copy_or_move_hook_delegate),
+ base::BindOnce(&FileSystemOperationRunner::DidFinish,
+ weak_ptr_, id, std::move(callback)));
return id;
}
@@ -696,23 +693,6 @@ void FileSystemOperationRunner::DidCreateSnapshot(
FinishOperation(id);
}
-void FileSystemOperationRunner::OnCopyProgress(
- const OperationID id,
- const CopyOrMoveProgressCallback& callback,
- FileSystemOperation::CopyOrMoveProgressType type,
- const FileSystemURL& source_url,
- const FileSystemURL& dest_url,
- int64_t size) {
- if (is_beginning_operation_) {
- base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE,
- base::BindOnce(&FileSystemOperationRunner::OnCopyProgress, weak_ptr_,
- id, callback, type, source_url, dest_url, size));
- return;
- }
- callback.Run(type, source_url, dest_url, size);
-}
-
void FileSystemOperationRunner::PrepareForWrite(OperationID id,
const FileSystemURL& url) {
if (file_system_context_->GetUpdateObservers(url.type())) {
diff --git a/chromium/storage/browser/file_system/file_system_operation_runner.h b/chromium/storage/browser/file_system/file_system_operation_runner.h
index 290f7b0c5b8..b93bfd24032 100644
--- a/chromium/storage/browser/file_system/file_system_operation_runner.h
+++ b/chromium/storage/browser/file_system/file_system_operation_runner.h
@@ -43,8 +43,6 @@ class COMPONENT_EXPORT(STORAGE_BROWSER) FileSystemOperationRunner {
using WriteCallback = FileSystemOperation::WriteCallback;
using OpenFileCallback = FileSystemOperation::OpenFileCallback;
using ErrorBehavior = FileSystemOperation::ErrorBehavior;
- using CopyOrMoveProgressCallback =
- FileSystemOperation::CopyOrMoveProgressCallback;
using CopyFileProgressCallback =
FileSystemOperation::CopyFileProgressCallback;
using CopyOrMoveOptionSet = FileSystemOperation::CopyOrMoveOptionSet;
@@ -84,24 +82,27 @@ class COMPONENT_EXPORT(STORAGE_BROWSER) FileSystemOperationRunner {
// |src_url| is a directory, the contents of |src_url| are copied to
// |dest_url| recursively. A new file or directory is created at
// |dest_url| as needed.
- // For |option| and |progress_callback|, see file_system_operation.h for
- // details.
- OperationID Copy(const FileSystemURL& src_url,
- const FileSystemURL& dest_url,
- CopyOrMoveOptionSet options,
- ErrorBehavior error_behavior,
- const CopyOrMoveProgressCallback& progress_callback,
- StatusCallback callback);
+ // For |option| and |copy_or_move_hook_delegate|, see file_system_operation.h
+ // for details.
+ OperationID Copy(
+ const FileSystemURL& src_url,
+ const FileSystemURL& dest_url,
+ CopyOrMoveOptionSet options,
+ ErrorBehavior error_behavior,
+ std::unique_ptr<CopyOrMoveHookDelegate> copy_or_move_hook_delegate,
+ StatusCallback callback);
// Moves a file or directory from |src_url| to |dest_url|. A new file
// or directory is created at |dest_url| as needed.
- // For |option|, see file_system_operation.h for details.
- OperationID Move(const FileSystemURL& src_url,
- const FileSystemURL& dest_url,
- CopyOrMoveOptionSet options,
- ErrorBehavior error_behavior,
- const CopyOrMoveProgressCallback& progress_callback,
- StatusCallback callback);
+ // For |option| and |copy_or_move_hook_delegate|, see file_system_operation.h
+ // for details.
+ OperationID Move(
+ const FileSystemURL& src_url,
+ const FileSystemURL& dest_url,
+ CopyOrMoveOptionSet options,
+ ErrorBehavior error_behavior,
+ std::unique_ptr<CopyOrMoveHookDelegate> copy_or_move_hook_delegate,
+ StatusCallback callback);
// Checks if a directory is present at |url|.
OperationID DirectoryExists(const FileSystemURL& url,
@@ -287,13 +288,6 @@ class COMPONENT_EXPORT(STORAGE_BROWSER) FileSystemOperationRunner {
const base::FilePath& platform_path,
scoped_refptr<ShareableFileReference> file_ref);
- void OnCopyProgress(const OperationID id,
- const CopyOrMoveProgressCallback& callback,
- FileSystemOperation::CopyOrMoveProgressType type,
- const FileSystemURL& source_url,
- const FileSystemURL& dest_url,
- int64_t size);
-
void PrepareForWrite(OperationID id, const FileSystemURL& url);
void PrepareForRead(OperationID id, const FileSystemURL& url);
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 7268996ae35..fa2ad05238f 100644
--- a/chromium/storage/browser/file_system/file_system_quota_client.cc
+++ b/chromium/storage/browser/file_system/file_system_quota_client.cc
@@ -102,7 +102,7 @@ blink::mojom::QuotaStatusCode DeleteStorageKeyOnFileTaskRunner(
return blink::mojom::QuotaStatusCode::kErrorNotSupported;
base::File::Error result =
provider->GetQuotaUtil()->DeleteStorageKeyDataOnFileTaskRunner(
- context, context->quota_manager_proxy(), storage_key, type);
+ context, context->quota_manager_proxy().get(), storage_key, type);
if (result == base::File::FILE_OK)
return blink::mojom::QuotaStatusCode::kOk;
return blink::mojom::QuotaStatusCode::kErrorInvalidModification;
@@ -114,7 +114,7 @@ void PerformStorageCleanupOnFileTaskRunner(FileSystemContext* context,
if (!provider || !provider->GetQuotaUtil())
return;
provider->GetQuotaUtil()->PerformStorageCleanupOnFileTaskRunner(
- context, context->quota_manager_proxy(), type);
+ context, context->quota_manager_proxy().get(), type);
}
} // namespace
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 b7bb5a5caec..d7840d136b1 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
@@ -28,6 +28,7 @@
#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_context.h"
#include "storage/common/file_system/file_system_types.h"
#include "storage/common/file_system/file_system_util.h"
@@ -57,7 +58,10 @@ const StorageType kPersistent = StorageType::kPersistent;
class FileSystemQuotaClientTest : public testing::TestWithParam<bool> {
public:
- FileSystemQuotaClientTest() = default;
+ FileSystemQuotaClientTest()
+ : special_storage_policy_(
+ base::MakeRefCounted<MockSpecialStoragePolicy>()),
+ task_environment_(base::test::TaskEnvironment::MainThreadType::IO) {}
~FileSystemQuotaClientTest() override = default;
void SetUp() override {
@@ -72,8 +76,7 @@ class FileSystemQuotaClientTest : public testing::TestWithParam<bool> {
quota_manager_ = base::MakeRefCounted<MockQuotaManager>(
/*is_incognito_=*/false, data_dir_.GetPath(),
- base::ThreadTaskRunnerHandle::Get(),
- /*special_storage_policy=*/nullptr);
+ base::ThreadTaskRunnerHandle::Get(), special_storage_policy_);
quota_manager_proxy_ = base::MakeRefCounted<storage::MockQuotaManagerProxy>(
quota_manager_.get(), base::ThreadTaskRunnerHandle::Get());
@@ -91,7 +94,6 @@ class FileSystemQuotaClientTest : public testing::TestWithParam<bool> {
FileSystemType type;
};
- protected:
storage::FileSystemContext* GetFileSystemContext() {
return file_system_context_.get();
}
@@ -256,9 +258,13 @@ class FileSystemQuotaClientTest : public testing::TestWithParam<bool> {
++additional_callback_count_;
}
+ protected:
+ scoped_refptr<MockSpecialStoragePolicy> special_storage_policy_;
+
base::test::ScopedFeatureList feature_list_;
base::ScopedTempDir data_dir_;
base::test::TaskEnvironment task_environment_;
+
scoped_refptr<FileSystemContext> file_system_context_;
scoped_refptr<MockQuotaManager> quota_manager_;
scoped_refptr<storage::MockQuotaManagerProxy> quota_manager_proxy_;
diff --git a/chromium/storage/browser/file_system/file_system_url_unittest.cc b/chromium/storage/browser/file_system/file_system_url_unittest.cc
index d0c85a6445e..3a818c4856e 100644
--- a/chromium/storage/browser/file_system/file_system_url_unittest.cc
+++ b/chromium/storage/browser/file_system/file_system_url_unittest.cc
@@ -8,7 +8,6 @@
#include <utility>
-#include "base/cxx17_backports.h"
#include "base/files/file_path.h"
#include "storage/common/file_system/file_system_types.h"
#include "storage/common/file_system/file_system_util.h"
@@ -111,8 +110,8 @@ TEST(FileSystemURLTest, CompareURLs) {
GURL("filesystem:https://chromium.org/temporary/dir a/file a")};
FileSystemURL::Comparator compare;
- for (size_t i = 0; i < base::size(urls); ++i) {
- for (size_t j = 0; j < base::size(urls); ++j) {
+ for (size_t i = 0; i < std::size(urls); ++i) {
+ for (size_t j = 0; j < std::size(urls); ++j) {
SCOPED_TRACE(testing::Message() << i << " < " << j);
EXPECT_EQ(urls[i] < urls[j],
compare(FileSystemURL::CreateForTest(urls[i]),
diff --git a/chromium/storage/browser/file_system/file_writer_delegate_unittest.cc b/chromium/storage/browser/file_system/file_writer_delegate_unittest.cc
index 6a1d9675e2a..e36d0fdf09c 100644
--- a/chromium/storage/browser/file_system/file_writer_delegate_unittest.cc
+++ b/chromium/storage/browser/file_system/file_writer_delegate_unittest.cc
@@ -2,7 +2,10 @@
// 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/file_writer_delegate.h"
+
#include <stdint.h>
+
#include <limits>
#include <string>
#include <utility>
@@ -10,7 +13,6 @@
#include "base/bind.h"
#include "base/callback_helpers.h"
-#include "base/cxx17_backports.h"
#include "base/files/scoped_temp_dir.h"
#include "base/location.h"
#include "base/memory/weak_ptr.h"
@@ -30,7 +32,6 @@
#include "storage/browser/blob/blob_storage_context.h"
#include "storage/browser/file_system/file_system_context.h"
#include "storage/browser/file_system/file_system_quota_util.h"
-#include "storage/browser/file_system/file_writer_delegate.h"
#include "storage/browser/file_system/sandbox_file_stream_writer.h"
#include "storage/browser/quota/quota_manager_proxy.h"
#include "storage/browser/test/async_file_test_helper.h"
@@ -49,7 +50,7 @@ const char kOrigin[] = "http://example.com";
const FileSystemType kFileSystemType = kFileSystemTypeTest;
const char kData[] = "The quick brown fox jumps over the lazy dog.\n";
-const int kDataSize = base::size(kData) - 1;
+const int kDataSize = std::size(kData) - 1;
class Result {
public:
diff --git a/chromium/storage/browser/file_system/filesystem_proxy_file_stream_reader_unittest.cc b/chromium/storage/browser/file_system/filesystem_proxy_file_stream_reader_unittest.cc
index 417b141dcc3..8d953bbf401 100644
--- a/chromium/storage/browser/file_system/filesystem_proxy_file_stream_reader_unittest.cc
+++ b/chromium/storage/browser/file_system/filesystem_proxy_file_stream_reader_unittest.cc
@@ -21,6 +21,7 @@
#include "base/task/single_thread_task_runner.h"
#include "base/test/task_environment.h"
#include "base/threading/thread.h"
+#include "base/time/time.h"
#include "net/base/io_buffer.h"
#include "net/base/net_errors.h"
#include "net/base/test_completion_callback.h"
diff --git a/chromium/storage/browser/file_system/isolated_context_unittest.cc b/chromium/storage/browser/file_system/isolated_context_unittest.cc
index 58f5fab2dee..1d2e9b58ccd 100644
--- a/chromium/storage/browser/file_system/isolated_context_unittest.cc
+++ b/chromium/storage/browser/file_system/isolated_context_unittest.cc
@@ -2,13 +2,13 @@
// 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/isolated_context.h"
+
#include <stddef.h>
#include <string>
-#include "base/cxx17_backports.h"
#include "storage/browser/file_system/file_system_url.h"
-#include "storage/browser/file_system/isolated_context.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/public/common/storage_key/storage_key.h"
@@ -91,7 +91,7 @@ TEST_F(IsolatedContextTest, RegisterAndRevokeTest) {
// See if the name of each registered kTestPaths (that is what we
// register in SetUp() by RegisterDraggedFileSystem) is properly cracked as
// a valid virtual path in the isolated filesystem.
- for (size_t i = 0; i < base::size(kTestPaths); ++i) {
+ for (size_t i = 0; i < std::size(kTestPaths); ++i) {
base::FilePath virtual_path =
isolated_context()->CreateVirtualRootPath(id_).AppendASCII(names_[i]);
std::string cracked_id;
@@ -191,8 +191,8 @@ TEST_F(IsolatedContextTest, CrackWithRelativePaths) {
{FPL("foo/..\\baz"), SHOULD_FAIL_WITH_WIN_SEPARATORS},
};
- for (size_t i = 0; i < base::size(kTestPaths); ++i) {
- for (size_t j = 0; j < base::size(relatives); ++j) {
+ for (size_t i = 0; i < std::size(kTestPaths); ++i) {
+ for (size_t j = 0; j < std::size(relatives); ++j) {
SCOPED_TRACE(testing::Message() << "Testing " << kTestPaths[i].value()
<< " " << relatives[j].path);
base::FilePath virtual_path = isolated_context()
@@ -244,8 +244,8 @@ TEST_F(IsolatedContextTest, CrackURLWithRelativePaths) {
{FPL("foo/..\\baz"), SHOULD_FAIL_WITH_WIN_SEPARATORS},
};
- for (size_t i = 0; i < base::size(kTestPaths); ++i) {
- for (size_t j = 0; j < base::size(relatives); ++j) {
+ for (size_t i = 0; i < std::size(kTestPaths); ++i) {
+ for (size_t j = 0; j < std::size(relatives); ++j) {
SCOPED_TRACE(testing::Message() << "Testing " << kTestPaths[i].value()
<< " " << relatives[j].path);
base::FilePath virtual_path = isolated_context()
diff --git a/chromium/storage/browser/file_system/local_file_stream_reader_unittest.cc b/chromium/storage/browser/file_system/local_file_stream_reader_unittest.cc
index 2e2ff8ead6c..c7396bdaf77 100644
--- a/chromium/storage/browser/file_system/local_file_stream_reader_unittest.cc
+++ b/chromium/storage/browser/file_system/local_file_stream_reader_unittest.cc
@@ -21,6 +21,7 @@
#include "base/task/single_thread_task_runner.h"
#include "base/test/task_environment.h"
#include "base/threading/thread.h"
+#include "base/time/time.h"
#include "net/base/io_buffer.h"
#include "net/base/net_errors.h"
#include "net/base/test_completion_callback.h"
diff --git a/chromium/storage/browser/file_system/native_file_util.cc b/chromium/storage/browser/file_system/native_file_util.cc
index 4d0f7df58e5..d2ea7638059 100644
--- a/chromium/storage/browser/file_system/native_file_util.cc
+++ b/chromium/storage/browser/file_system/native_file_util.cc
@@ -10,6 +10,7 @@
#include "base/files/file_enumerator.h"
#include "base/files/file_util.h"
+#include "base/time/time.h"
#include "build/build_config.h"
#include "build/chromeos_buildflags.h"
#include "storage/browser/file_system/file_system_operation_context.h"
diff --git a/chromium/storage/browser/file_system/native_file_util_unittest.cc b/chromium/storage/browser/file_system/native_file_util_unittest.cc
index 602751dcb45..4038989040c 100644
--- a/chromium/storage/browser/file_system/native_file_util_unittest.cc
+++ b/chromium/storage/browser/file_system/native_file_util_unittest.cc
@@ -507,6 +507,7 @@ TEST_F(NativeFileUtilTest, PreserveLastModified) {
EXPECT_EQ(file_info1.last_modified, file_info2.last_modified);
}
+// This test is disabled on Fuchsia because file permissions are not supported.
#if BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_WIN)
TEST_F(NativeFileUtilTest, PreserveDestinationPermissions) {
// Ensure both the src and dest files exist.
@@ -584,6 +585,7 @@ TEST_F(NativeFileUtilTest, PreserveDestinationPermissions) {
}
#endif // BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_WIN)
+// This test is disabled on Fuchsia because file permissions are not supported.
#if BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_WIN)
TEST_F(NativeFileUtilTest, PreserveLastModifiedAndDestinationPermissions) {
base::FilePath from_file = Path("fromfile");
diff --git a/chromium/storage/browser/file_system/obfuscated_file_util.cc b/chromium/storage/browser/file_system/obfuscated_file_util.cc
index a3840c4b0ba..df2a3a49d70 100644
--- a/chromium/storage/browser/file_system/obfuscated_file_util.cc
+++ b/chromium/storage/browser/file_system/obfuscated_file_util.cc
@@ -13,6 +13,7 @@
#include "base/bind.h"
#include "base/containers/queue.h"
+#include "base/files/file_error_or.h"
#include "base/files/file_util.h"
#include "base/format_macros.h"
#include "base/logging.h"
@@ -272,6 +273,7 @@ class ObfuscatedStorageKeyEnumerator
ObfuscatedFileUtil::ObfuscatedFileUtil(
scoped_refptr<SpecialStoragePolicy> special_storage_policy,
const base::FilePath& file_system_directory,
+ const base::FilePath& bucket_base_path,
leveldb::Env* env_override,
GetTypeStringForURLCallback get_type_string_for_url,
const std::set<std::string>& known_type_strings,
@@ -279,6 +281,7 @@ ObfuscatedFileUtil::ObfuscatedFileUtil(
bool is_incognito)
: special_storage_policy_(std::move(special_storage_policy)),
file_system_directory_(file_system_directory),
+ bucket_base_path_(bucket_base_path),
env_override_(env_override),
is_incognito_(is_incognito),
db_flush_delay_seconds_(10 * 60), // 10 mins.
@@ -997,13 +1000,24 @@ int64_t ObfuscatedFileUtil::ComputeFilePathCost(const base::FilePath& path) {
return UsageForPath(VirtualPath::BaseName(path).value().size());
}
-base::FilePath ObfuscatedFileUtil::GetDirectoryForURL(
+base::FileErrorOr<base::FilePath> ObfuscatedFileUtil::GetDirectoryForURL(
const FileSystemURL& url,
- bool create,
- base::File::Error* error_code) {
+ bool create) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- return GetDirectoryForStorageKeyAndType(
- url.storage_key(), CallGetTypeStringForURL(url), create, error_code);
+ if (!url.bucket().has_value() || url.storage_key().IsFirstPartyContext()) {
+ // 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;
+ }
+ // Construct the file path using non-default bucket information.
+ return GetDirectoryWithBucket(create, url.bucket().value(),
+ CallGetTypeStringForURL(url));
}
std::string ObfuscatedFileUtil::CallGetTypeStringForURL(
@@ -1175,11 +1189,10 @@ base::FilePath ObfuscatedFileUtil::DataPathToLocalPath(
const FileSystemURL& url,
const base::FilePath& data_path) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- base::File::Error error = base::File::FILE_OK;
- base::FilePath root = GetDirectoryForURL(url, false, &error);
- if (error != base::File::FILE_OK)
+ base::FileErrorOr<base::FilePath> root = GetDirectoryForURL(url, false);
+ if (root.is_error())
return base::FilePath();
- return root.Append(data_path);
+ return root.value().Append(data_path);
}
std::string ObfuscatedFileUtil::GetDirectoryDatabaseKey(
@@ -1210,16 +1223,15 @@ SandboxDirectoryDatabase* ObfuscatedFileUtil::GetDirectoryDatabase(
return iter->second.get();
}
- base::File::Error error = base::File::FILE_OK;
- base::FilePath path = GetDirectoryForURL(url, create, &error);
- if (error != base::File::FILE_OK) {
+ base::FileErrorOr<base::FilePath> path = GetDirectoryForURL(url, create);
+ if (path.is_error()) {
LOG(WARNING) << "Failed to get origin+type directory: " << url.DebugString()
- << " error:" << error;
+ << " error:" << path.error();
return nullptr;
}
MarkUsed();
directories_[key] =
- std::make_unique<SandboxDirectoryDatabase>(path, env_override_);
+ std::make_unique<SandboxDirectoryDatabase>(path.value(), env_override_);
return directories_[key].get();
}
@@ -1278,6 +1290,24 @@ base::FilePath ObfuscatedFileUtil::GetDirectoryForStorageKey(
return path;
}
+base::FileErrorOr<base::FilePath> ObfuscatedFileUtil::GetDirectoryWithBucket(
+ bool create,
+ BucketLocator bucket,
+ std::string file_type) {
+ base::FilePath path =
+ sandbox_delegate_->quota_manager_proxy()->GetClientBucketPath(
+ bucket, QuotaClientType::kFileSystem);
+ // Verify the directory is valid.
+ if (!delegate_->DirectoryExists(path) &&
+ (!create || delegate_->CreateDirectory(path, false /* exclusive */,
+ true /* recursive */) !=
+ base::File::FILE_OK)) {
+ return create ? base::File::FILE_ERROR_FAILED
+ : base::File::FILE_ERROR_NOT_FOUND;
+ }
+ return path;
+}
+
void ObfuscatedFileUtil::InvalidateUsageCache(
FileSystemOperationContext* context,
const blink::StorageKey& storage_key,
@@ -1343,16 +1373,18 @@ base::File::Error ObfuscatedFileUtil::GenerateNewLocalPath(
if (!db || !db->GetNextInteger(&number))
return base::File::FILE_ERROR_FAILED;
- base::File::Error error = base::File::FILE_OK;
- *root = GetDirectoryForURL(url, false, &error);
- if (error != base::File::FILE_OK)
- return error;
+ base::FileErrorOr<base::FilePath> directory_for_url =
+ GetDirectoryForURL(url, false);
+ if (directory_for_url.is_error())
+ return directory_for_url.error();
+ *root = directory_for_url.value();
// We use the third- and fourth-to-last digits as the directory.
int64_t directory_number = number % 10000 / 100;
base::FilePath new_local_path =
root->AppendASCII(base::StringPrintf("%02" PRId64, directory_number));
+ base::File::Error error = base::File::FILE_OK;
error = delegate_->CreateDirectory(new_local_path, false /* exclusive */,
false /* recursive */);
if (error != base::File::FILE_OK)
diff --git a/chromium/storage/browser/file_system/obfuscated_file_util.h b/chromium/storage/browser/file_system/obfuscated_file_util.h
index 69b70676251..ddede7e9eb7 100644
--- a/chromium/storage/browser/file_system/obfuscated_file_util.h
+++ b/chromium/storage/browser/file_system/obfuscated_file_util.h
@@ -16,6 +16,7 @@
#include "base/callback_forward.h"
#include "base/component_export.h"
#include "base/files/file.h"
+#include "base/files/file_error_or.h"
#include "base/files/file_path.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/scoped_refptr.h"
@@ -111,6 +112,7 @@ class COMPONENT_EXPORT(STORAGE_BROWSER) ObfuscatedFileUtil
// deleted when one StorageKey/type pair is deleted.
ObfuscatedFileUtil(scoped_refptr<SpecialStoragePolicy> special_storage_policy,
const base::FilePath& file_system_directory,
+ const base::FilePath& bucket_base_path,
leveldb::Env* env_override,
GetTypeStringForURLCallback get_type_string_for_url,
const std::set<std::string>& known_type_strings,
@@ -236,12 +238,12 @@ class COMPONENT_EXPORT(STORAGE_BROWSER) ObfuscatedFileUtil
static std::unique_ptr<ObfuscatedFileUtil> CreateForTesting(
scoped_refptr<SpecialStoragePolicy> special_storage_policy,
const base::FilePath& file_system_directory,
+ const base::FilePath& bucket_base_path,
leveldb::Env* env_override,
bool is_incognito);
- base::FilePath GetDirectoryForURL(const FileSystemURL& url,
- bool create,
- base::File::Error* error_code);
+ 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);
@@ -302,6 +304,14 @@ class COMPONENT_EXPORT(STORAGE_BROWSER) ObfuscatedFileUtil
bool create,
base::File::Error* error_code);
+ // Returns a valid file path to the directory corresponding to the specified
+ // non-default `bucket` and `file_type.` Will return a FileError if an invalid
+ // file path is found.
+ base::FileErrorOr<base::FilePath> GetDirectoryWithBucket(
+ bool create,
+ BucketLocator bucket,
+ std::string file_type);
+
void InvalidateUsageCache(FileSystemOperationContext* context,
const blink::StorageKey& storage_key,
FileSystemType type);
@@ -331,6 +341,7 @@ class COMPONENT_EXPORT(STORAGE_BROWSER) ObfuscatedFileUtil
std::unique_ptr<SandboxOriginDatabaseInterface> origin_database_;
scoped_refptr<SpecialStoragePolicy> special_storage_policy_;
base::FilePath file_system_directory_;
+ base::FilePath bucket_base_path_;
raw_ptr<leveldb::Env> env_override_;
bool is_incognito_;
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 604674b3d16..49f700b7ade 100644
--- a/chromium/storage/browser/file_system/obfuscated_file_util_unittest.cc
+++ b/chromium/storage/browser/file_system/obfuscated_file_util_unittest.cc
@@ -2,6 +2,8 @@
// 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/obfuscated_file_util.h"
+
#include <stddef.h>
#include <stdint.h>
@@ -14,7 +16,6 @@
#include "base/bind.h"
#include "base/callback_helpers.h"
-#include "base/cxx17_backports.h"
#include "base/files/file.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
@@ -33,7 +34,6 @@
#include "storage/browser/file_system/file_system_operation_context.h"
#include "storage/browser/file_system/file_system_url.h"
#include "storage/browser/file_system/file_system_usage_cache.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/sandbox_directory_database.h"
#include "storage/browser/file_system/sandbox_file_system_backend_delegate.h"
@@ -267,7 +267,7 @@ class ObfuscatedFileUtilTest : public testing::Test,
std::unique_ptr<ObfuscatedFileUtil> CreateObfuscatedFileUtil(
scoped_refptr<SpecialStoragePolicy> storage_policy) {
return ObfuscatedFileUtil::CreateForTesting(
- std::move(storage_policy), data_dir_path(),
+ std::move(storage_policy), data_dir_path(), data_dir_path(),
is_incognito() ? incognito_leveldb_environment_.get() : nullptr,
is_incognito());
}
@@ -372,7 +372,7 @@ class ObfuscatedFileUtilTest : public testing::Test,
EXPECT_EQ(!is_incognito(), FileExists(data_path));
const char data[] = "test data";
- const int length = base::size(data) - 1;
+ const int length = std::size(data) - 1;
base::File file = ofu()->CreateOrOpen(
context.get(), url, base::File::FLAG_WRITE | base::File::FLAG_OPEN);
@@ -1342,7 +1342,7 @@ TEST_P(ObfuscatedFileUtilTest, TestCopyOrMoveFileSuccess) {
const int64_t kSourceLength = 5;
const int64_t kDestLength = 50;
- for (size_t i = 0; i < base::size(kCopyMoveTestCases); ++i) {
+ for (size_t i = 0; i < std::size(kCopyMoveTestCases); ++i) {
SCOPED_TRACE(testing::Message() << "kCopyMoveTestCase " << i);
const CopyMoveTestCaseRecord& test_case = kCopyMoveTestCases[i];
SCOPED_TRACE(testing::Message()
@@ -1588,7 +1588,7 @@ TEST_P(ObfuscatedFileUtilTest, TestStorageKeyEnumerator) {
std::set<blink::StorageKey> storage_keys_expected;
storage_keys_expected.insert(storage_key());
- for (size_t i = 0; i < base::size(kOriginEnumerationTestRecords); ++i) {
+ for (size_t i = 0; i < std::size(kOriginEnumerationTestRecords); ++i) {
SCOPED_TRACE(testing::Message()
<< "Validating kOriginEnumerationTestRecords " << i);
const OriginEnumerationTestRecord& record =
@@ -1802,7 +1802,7 @@ TEST_P(ObfuscatedFileUtilTest, TestIncompleteDirectoryReading) {
EXPECT_EQ(base::File::FILE_OK,
AsyncFileTestHelper::ReadDirectory(file_system_context(),
empty_path, &entries));
- EXPECT_EQ(base::size(kPath) - 1, entries.size());
+ EXPECT_EQ(std::size(kPath) - 1, entries.size());
}
TEST_P(ObfuscatedFileUtilTest, TestDirectoryTimestampForCreation) {
@@ -2040,13 +2040,7 @@ TEST_P(ObfuscatedFileUtilTest, TestFileEnumeratorTimestamp) {
EXPECT_EQ(2, count);
}
-// crbug.com/176470
-#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_ANDROID)
-#define MAYBE_TestQuotaOnCopyFile DISABLED_TestQuotaOnCopyFile
-#else
-#define MAYBE_TestQuotaOnCopyFile TestQuotaOnCopyFile
-#endif
-TEST_P(ObfuscatedFileUtilTest, MAYBE_TestQuotaOnCopyFile) {
+TEST_P(ObfuscatedFileUtilTest, TestQuotaOnCopyFile) {
FileSystemURL from_file(CreateURLFromUTF8("fromfile"));
FileSystemURL obstacle_file(CreateURLFromUTF8("obstaclefile"));
FileSystemURL to_file1(CreateURLFromUTF8("tofile1"));
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
index c3f943b01a5..f64ae7f8ddb 100644
--- a/chromium/storage/browser/file_system/plugin_private_file_system_backend.cc
+++ b/chromium/storage/browser/file_system/plugin_private_file_system_backend.cc
@@ -9,6 +9,7 @@
#include <map>
#include <memory>
#include <utility>
+#include <vector>
#include "base/bind.h"
#include "base/containers/contains.h"
@@ -18,6 +19,7 @@
#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"
@@ -99,9 +101,20 @@ base::File::Error OpenFileSystemOnFileTaskRunner(
} // 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,
+ const base::FilePath& bucket_base_path,
scoped_refptr<SpecialStoragePolicy> special_storage_policy,
const FileSystemOptions& file_system_options,
leveldb::Env* env_override)
@@ -112,7 +125,8 @@ PluginPrivateFileSystemBackend::PluginPrivateFileSystemBackend(
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,
+ std::move(special_storage_policy), base_path_, bucket_base_path,
+ env_override,
base::BindRepeating(&FileSystemIDToPluginMap::GetPluginIDForURL,
base::Owned(plugin_map_.get())),
std::set<std::string>(), nullptr,
@@ -301,11 +315,12 @@ void PluginPrivateFileSystemBackend::GetOriginDetailsOnFileTaskRunner(
*last_modified_time = base::Time::UnixEpoch();
std::string fsid =
IsolatedContext::GetInstance()->RegisterFileSystemForVirtualPath(
- kFileSystemTypePluginPrivate, "pluginprivate", base::FilePath());
+ kFileSystemTypePluginPrivate, kPluginPrivateRootName,
+ base::FilePath());
DCHECK(ValidateIsolatedFileSystemId(fsid));
std::string root = GetIsolatedFileSystemRootURIString(origin.GetURL(), fsid,
- "pluginprivate");
+ kPluginPrivateRootName);
std::unique_ptr<FileSystemOperationContext> operation_context(
std::make_unique<FileSystemOperationContext>(context));
@@ -356,6 +371,65 @@ void PluginPrivateFileSystemBackend::GetOriginDetailsOnFileTaskRunner(
}
}
+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,
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
index 5b36b8826f4..9b1aab71334 100644
--- a/chromium/storage/browser/file_system/plugin_private_file_system_backend.h
+++ b/chromium/storage/browser/file_system/plugin_private_file_system_backend.h
@@ -54,9 +54,22 @@ class COMPONENT_EXPORT(STORAGE_BROWSER) PluginPrivateFileSystemBackend
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,
+ const base::FilePath& bucket_base_path,
scoped_refptr<SpecialStoragePolicy> special_storage_policy,
const FileSystemOptions& file_system_options,
leveldb::Env* env_override);
@@ -144,13 +157,20 @@ class COMPONENT_EXPORT(STORAGE_BROWSER) PluginPrivateFileSystemBackend
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 base::FilePath& base_path() const { return base_path_; }
const scoped_refptr<base::SequencedTaskRunner> file_task_runner_;
const FileSystemOptions file_system_options_;
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 f03a7b5b5e8..43ce6b8d6c8 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
@@ -44,7 +44,9 @@ bool DidReserveQuota(bool accepted,
class MockQuotaManagerProxy : public QuotaManagerProxy {
public:
MockQuotaManagerProxy()
- : QuotaManagerProxy(nullptr, base::ThreadTaskRunnerHandle::Get()),
+ : QuotaManagerProxy(/*quota_manager_impl=*/nullptr,
+ base::ThreadTaskRunnerHandle::Get(),
+ /*profile_path=*/base::FilePath()),
storage_modified_count_(0),
usage_(0),
quota_(0) {}
@@ -114,7 +116,7 @@ class QuotaBackendImplTest : public testing::Test,
in_memory_env_ = leveldb_chrome::NewMemEnv("quota");
file_util_ = ObfuscatedFileUtil::CreateForTesting(
/*special_storage_policy=*/nullptr, data_dir_.GetPath(),
- in_memory_env_.get(), is_incognito());
+ data_dir_.GetPath(), in_memory_env_.get(), is_incognito());
backend_ = std::make_unique<QuotaBackendImpl>(
file_task_runner(), file_util_.get(), &file_system_usage_cache_,
quota_manager_proxy_.get());
diff --git a/chromium/storage/browser/file_system/sandbox_directory_database.cc b/chromium/storage/browser/file_system/sandbox_directory_database.cc
index 9f6bb1bff35..7f6674348d8 100644
--- a/chromium/storage/browser/file_system/sandbox_directory_database.cc
+++ b/chromium/storage/browser/file_system/sandbox_directory_database.cc
@@ -13,7 +13,6 @@
#include <set>
#include "base/containers/stack.h"
-#include "base/cxx17_backports.h"
#include "base/files/file_enumerator.h"
#include "base/files/file_util.h"
#include "base/location.h"
@@ -305,8 +304,8 @@ bool DatabaseCheckHelper::ScanDirectory() {
if (!path_.AppendRelativePath(absolute_file_path, &relative_file_path))
return false;
- if (std::find(kExcludes, kExcludes + base::size(kExcludes),
- relative_file_path) != kExcludes + base::size(kExcludes))
+ if (std::find(kExcludes, kExcludes + std::size(kExcludes),
+ relative_file_path) != kExcludes + std::size(kExcludes))
continue;
if (find_info.IsDirectory()) {
diff --git a/chromium/storage/browser/file_system/sandbox_file_stream_reader_unittest.cc b/chromium/storage/browser/file_system/sandbox_file_stream_reader_unittest.cc
index 1aca0a236d1..b3763ad382f 100644
--- a/chromium/storage/browser/file_system/sandbox_file_stream_reader_unittest.cc
+++ b/chromium/storage/browser/file_system/sandbox_file_stream_reader_unittest.cc
@@ -13,6 +13,7 @@
#include "base/bind.h"
#include "base/files/scoped_temp_dir.h"
+#include "base/memory/scoped_refptr.h"
#include "base/run_loop.h"
#include "base/test/task_environment.h"
#include "net/base/io_buffer.h"
@@ -41,17 +42,18 @@ const char kURLOrigin[] = "http://remote/";
class SandboxFileStreamReaderTest : public FileStreamReaderTest {
public:
- SandboxFileStreamReaderTest() = default;
+ SandboxFileStreamReaderTest()
+ : special_storage_policy_(
+ base::MakeRefCounted<MockSpecialStoragePolicy>()) {}
void SetUp() override {
ASSERT_TRUE(dir_.CreateUniqueTempDir());
quota_manager_ = base::MakeRefCounted<storage::MockQuotaManager>(
/*is_incognito=*/false, dir_.GetPath(),
- base::ThreadTaskRunnerHandle::Get(),
- /*special_storage_policy=*/nullptr);
+ base::ThreadTaskRunnerHandle::Get(), special_storage_policy_);
quota_manager_proxy_ = base::MakeRefCounted<storage::MockQuotaManagerProxy>(
- quota_manager_.get(), base::ThreadTaskRunnerHandle::Get().get());
+ quota_manager_.get(), base::ThreadTaskRunnerHandle::Get());
file_system_context_ = CreateFileSystemContextForTesting(
quota_manager_proxy_.get(), dir_.GetPath());
@@ -114,8 +116,9 @@ class SandboxFileStreamReaderTest : public FileStreamReaderTest {
kFileSystemTypeTemporary, base::FilePath().AppendASCII(file_name));
}
- private:
- base::ScopedTempDir dir_;
+ protected:
+ scoped_refptr<MockSpecialStoragePolicy> special_storage_policy_;
+
scoped_refptr<FileSystemContext> file_system_context_;
scoped_refptr<MockQuotaManager> quota_manager_;
scoped_refptr<MockQuotaManagerProxy> quota_manager_proxy_;
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 e640397e0fa..f82f43bb54a 100644
--- a/chromium/storage/browser/file_system/sandbox_file_stream_writer.cc
+++ b/chromium/storage/browser/file_system/sandbox_file_stream_writer.cc
@@ -167,7 +167,7 @@ void SandboxFileStreamWriter::DidCreateSnapshotFile(
file_system_context_->default_file_task_runner(), platform_path,
initial_offset_, FileStreamWriter::OPEN_EXISTING_FILE);
}
- QuotaManagerProxy* quota_manager_proxy =
+ const scoped_refptr<QuotaManagerProxy>& quota_manager_proxy =
file_system_context_->quota_manager_proxy();
if (!quota_manager_proxy) {
// If we don't have the quota manager or the requested filesystem type
@@ -227,7 +227,7 @@ void SandboxFileStreamWriter::DidWrite(int write_response) {
if (write_response <= 0) {
// TODO(crbug.com/1091792): Consider listening explicitly for out
// of space errors instead of surfacing all write errors to quota.
- QuotaManagerProxy* quota_manager_proxy =
+ const scoped_refptr<QuotaManagerProxy>& quota_manager_proxy =
file_system_context_->quota_manager_proxy();
if (quota_manager_proxy) {
quota_manager_proxy->NotifyWriteFailed(url_.storage_key());
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 6e173b48c6b..c02bd5e1a49 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
@@ -42,16 +42,19 @@ const char kURLOrigin[] = "http://remote/";
class SandboxFileStreamWriterTest : public FileStreamWriterTest {
public:
- SandboxFileStreamWriterTest() = default;
+ SandboxFileStreamWriterTest()
+ : special_storage_policy_(
+ base::MakeRefCounted<MockSpecialStoragePolicy>()) {}
+ ~SandboxFileStreamWriterTest() override = default;
void SetUp() override {
ASSERT_TRUE(dir_.CreateUniqueTempDir());
quota_manager_ = base::MakeRefCounted<storage::MockQuotaManager>(
is_incognito(), dir_.GetPath(), base::ThreadTaskRunnerHandle::Get(),
- nullptr);
+ special_storage_policy_);
quota_manager_proxy_ = base::MakeRefCounted<storage::MockQuotaManagerProxy>(
- quota_manager_.get(), base::ThreadTaskRunnerHandle::Get().get());
+ quota_manager_.get(), base::ThreadTaskRunnerHandle::Get());
file_system_context_ =
CreateFileSystemContext(quota_manager_proxy_.get(), dir_);
@@ -75,7 +78,8 @@ class SandboxFileStreamWriterTest : public FileStreamWriterTest {
}
protected:
- base::ScopedTempDir dir_;
+ scoped_refptr<MockSpecialStoragePolicy> special_storage_policy_;
+
scoped_refptr<FileSystemContext> file_system_context_;
scoped_refptr<MockQuotaManager> quota_manager_;
scoped_refptr<MockQuotaManagerProxy> quota_manager_proxy_;
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 f409b5885d9..c78d0586aa0 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
@@ -182,6 +182,7 @@ SandboxFileSystemBackendDelegate::SandboxFileSystemBackendDelegate(
scoped_refptr<QuotaManagerProxy> quota_manager_proxy,
scoped_refptr<base::SequencedTaskRunner> file_task_runner,
const base::FilePath& profile_path,
+ const base::FilePath& bucket_base_path,
scoped_refptr<SpecialStoragePolicy> special_storage_policy,
const FileSystemOptions& file_system_options,
leveldb::Env* env_override)
@@ -191,6 +192,7 @@ SandboxFileSystemBackendDelegate::SandboxFileSystemBackendDelegate(
std::make_unique<ObfuscatedFileUtil>(
special_storage_policy,
profile_path.Append(kFileSystemDirectory),
+ bucket_base_path,
env_override,
base::BindRepeating(&GetTypeStringForURL),
GetKnownTypeStrings(),
@@ -675,11 +677,13 @@ SandboxFileSystemBackendDelegate::memory_file_util_delegate() {
std::unique_ptr<ObfuscatedFileUtil> ObfuscatedFileUtil::CreateForTesting(
scoped_refptr<SpecialStoragePolicy> special_storage_policy,
const base::FilePath& file_system_directory,
+ const base::FilePath& bucket_base_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(),
+ std::move(special_storage_policy), file_system_directory,
+ bucket_base_path, env_override, base::BindRepeating(&GetTypeStringForURL),
+ GetKnownTypeStrings(),
/*sandbox_delegate=*/nullptr, is_incognito);
}
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 7abbc1a959e..b02945f4603 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
@@ -24,6 +24,7 @@
#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"
+#include "storage/browser/quota/quota_manager_proxy.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
namespace base {
@@ -99,6 +100,7 @@ class COMPONENT_EXPORT(STORAGE_BROWSER) SandboxFileSystemBackendDelegate
scoped_refptr<QuotaManagerProxy> quota_manager_proxy,
scoped_refptr<base::SequencedTaskRunner> file_task_runner,
const base::FilePath& profile_path,
+ const base::FilePath& bucket_base_path,
scoped_refptr<SpecialStoragePolicy> special_storage_policy,
const FileSystemOptions& file_system_options,
leveldb::Env* env_override);
@@ -210,6 +212,10 @@ class COMPONENT_EXPORT(STORAGE_BROWSER) SandboxFileSystemBackendDelegate
return file_system_options_;
}
+ const scoped_refptr<QuotaManagerProxy> quota_manager_proxy() const {
+ return quota_manager_proxy_;
+ }
+
FileSystemFileUtil* sync_file_util();
base::WeakPtr<ObfuscatedFileUtilMemoryDelegate> memory_file_util_delegate();
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..0f6a8f00bed 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
@@ -40,8 +40,9 @@ class SandboxFileSystemBackendDelegateTest : public testing::Test {
nullptr, base::ThreadTaskRunnerHandle::Get());
delegate_ = std::make_unique<SandboxFileSystemBackendDelegate>(
quota_manager_proxy_.get(), base::ThreadTaskRunnerHandle::Get().get(),
- data_dir_.GetPath(), /*special_storage_policy=*/nullptr,
- CreateAllowFileAccessOptions(), /*env_override=*/nullptr);
+ data_dir_.GetPath(), data_dir_.GetPath(),
+ /*special_storage_policy=*/nullptr, CreateAllowFileAccessOptions(),
+ /*env_override=*/nullptr);
}
bool IsAccessValid(const FileSystemURL& url) const {
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 1367e29082a..e1f98e46379 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
@@ -11,7 +11,6 @@
#include <vector>
#include "base/bind.h"
-#include "base/cxx17_backports.h"
#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
#include "base/run_loop.h"
@@ -93,7 +92,7 @@ class SandboxFileSystemBackendTest
incognito_env_override_ = leveldb_chrome::NewMemEnv("FileSystem");
delegate_ = std::make_unique<SandboxFileSystemBackendDelegate>(
/*quota_manager_proxy=*/nullptr, base::ThreadTaskRunnerHandle::Get(),
- data_dir_.GetPath(),
+ data_dir_.GetPath(), data_dir_.GetPath(),
/*special_storage_policy=*/nullptr, options,
options.is_in_memory() ? incognito_env_override_.get() : nullptr);
}
@@ -173,8 +172,8 @@ TEST_P(SandboxFileSystemBackendTest, EnumerateOrigins) {
"http://www.foo.com:8080/",
"http://www.foo.com:80/",
};
- size_t temporary_size = base::size(temporary_origins);
- size_t persistent_size = base::size(persistent_origins);
+ size_t temporary_size = std::size(temporary_origins);
+ size_t persistent_size = std::size(persistent_origins);
std::set<blink::StorageKey> temporary_set, persistent_set;
for (size_t i = 0; i < temporary_size; ++i) {
CreateOriginTypeDirectory(temporary_origins[i], kFileSystemTypeTemporary);
@@ -211,12 +210,11 @@ TEST_P(SandboxFileSystemBackendTest, EnumerateOrigins) {
}
TEST_P(SandboxFileSystemBackendTest, GetRootPathCreateAndExamine) {
- std::vector<base::FilePath> returned_root_path(
- base::size(kRootPathTestCases));
+ std::vector<base::FilePath> returned_root_path(std::size(kRootPathTestCases));
SetUpNewBackend(CreateAllowFileAccessOptions());
// Create a new root directory.
- for (size_t i = 0; i < base::size(kRootPathTestCases); ++i) {
+ for (size_t i = 0; i < std::size(kRootPathTestCases); ++i) {
SCOPED_TRACE(testing::Message() << "RootPath (create) #" << i << " "
<< kRootPathTestCases[i].expected_path);
@@ -235,7 +233,7 @@ TEST_P(SandboxFileSystemBackendTest, GetRootPathCreateAndExamine) {
// Get the root directory with create=false and see if we get the
// same directory.
- for (size_t i = 0; i < base::size(kRootPathTestCases); ++i) {
+ for (size_t i = 0; i < std::size(kRootPathTestCases); ++i) {
SCOPED_TRACE(testing::Message() << "RootPath (get) #" << i << " "
<< kRootPathTestCases[i].expected_path);
@@ -250,8 +248,7 @@ TEST_P(SandboxFileSystemBackendTest, GetRootPathCreateAndExamine) {
TEST_P(SandboxFileSystemBackendTest,
GetRootPathCreateAndExamineWithNewBackend) {
- std::vector<base::FilePath> returned_root_path(
- base::size(kRootPathTestCases));
+ std::vector<base::FilePath> returned_root_path(std::size(kRootPathTestCases));
SetUpNewBackend(CreateAllowFileAccessOptions());
base::FilePath root_path1;
@@ -270,7 +267,7 @@ TEST_P(SandboxFileSystemBackendTest, GetRootPathGetWithoutCreate) {
SetUpNewBackend(CreateDisallowFileAccessOptions());
// Try to get a root directory without creating.
- for (size_t i = 0; i < base::size(kRootPathTestCases); ++i) {
+ for (size_t i = 0; i < std::size(kRootPathTestCases); ++i) {
SCOPED_TRACE(testing::Message() << "RootPath (create=false) #" << i << " "
<< kRootPathTestCases[i].expected_path);
EXPECT_FALSE(GetRootPath(kRootPathTestCases[i].origin_url,
@@ -283,7 +280,7 @@ TEST_P(SandboxFileSystemBackendTest, GetRootPathInIncognito) {
SetUpNewBackend(CreateIncognitoFileSystemOptions());
// Try to get a root directory.
- for (size_t i = 0; i < base::size(kRootPathTestCases); ++i) {
+ for (size_t i = 0; i < std::size(kRootPathTestCases); ++i) {
SCOPED_TRACE(testing::Message() << "RootPath (incognito) #" << i << " "
<< kRootPathTestCases[i].expected_path);
EXPECT_EQ(IsPersistentFileSystemEnabledIncognito() ||
@@ -296,7 +293,7 @@ TEST_P(SandboxFileSystemBackendTest, GetRootPathInIncognito) {
TEST_P(SandboxFileSystemBackendTest, GetRootPathFileURI) {
SetUpNewBackend(CreateDisallowFileAccessOptions());
- for (size_t i = 0; i < base::size(kRootPathFileURITestCases); ++i) {
+ for (size_t i = 0; i < std::size(kRootPathFileURITestCases); ++i) {
SCOPED_TRACE(testing::Message()
<< "RootPathFileURI (disallow) #" << i << " "
<< kRootPathFileURITestCases[i].expected_path);
@@ -308,7 +305,7 @@ TEST_P(SandboxFileSystemBackendTest, GetRootPathFileURI) {
TEST_P(SandboxFileSystemBackendTest, GetRootPathFileURIWithAllowFlag) {
SetUpNewBackend(CreateAllowFileAccessOptions());
- for (size_t i = 0; i < base::size(kRootPathFileURITestCases); ++i) {
+ for (size_t i = 0; i < std::size(kRootPathFileURITestCases); ++i) {
SCOPED_TRACE(testing::Message()
<< "RootPathFileURI (allow) #" << i << " "
<< kRootPathFileURITestCases[i].expected_path);
diff --git a/chromium/storage/browser/file_system/sandbox_origin_database_unittest.cc b/chromium/storage/browser/file_system/sandbox_origin_database_unittest.cc
index 8f9c19880d4..95fa91ca997 100644
--- a/chromium/storage/browser/file_system/sandbox_origin_database_unittest.cc
+++ b/chromium/storage/browser/file_system/sandbox_origin_database_unittest.cc
@@ -2,6 +2,8 @@
// 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/sandbox_origin_database.h"
+
#include <stddef.h>
#include <algorithm>
@@ -11,12 +13,10 @@
#include <string>
#include <vector>
-#include "base/cxx17_backports.h"
#include "base/files/file.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
-#include "storage/browser/file_system/sandbox_origin_database.h"
#include "storage/browser/test/sandbox_database_test_helper.h"
#include "storage/common/file_system/file_system_util.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -208,7 +208,7 @@ TEST(SandboxOriginDatabaseTest, DatabaseRecoveryTest) {
};
auto database = std::make_unique<SandboxOriginDatabase>(kFSDir, nullptr);
- for (size_t i = 0; i < base::size(kOrigins); ++i) {
+ for (size_t i = 0; i < std::size(kOrigins); ++i) {
base::FilePath path;
EXPECT_FALSE(database->HasOriginPath(kOrigins[i]));
EXPECT_TRUE(database->GetPathForOrigin(kOrigins[i], &path));
@@ -242,7 +242,7 @@ TEST(SandboxOriginDatabaseTest, DatabaseRecoveryTest) {
// Expect all but last added origin will be repaired back, and kOrigins[1]
// should be dropped due to absence of backing directory.
- EXPECT_EQ(base::size(kOrigins) - 2, origins_in_db.size());
+ EXPECT_EQ(std::size(kOrigins) - 2, origins_in_db.size());
const std::string kOrigin("piyo.example.org");
EXPECT_FALSE(database->HasOriginPath(kOrigin));
diff --git a/chromium/storage/browser/file_system/task_runner_bound_observer_list.h b/chromium/storage/browser/file_system/task_runner_bound_observer_list.h
index 6f960a09dad..43cd2c210fc 100644
--- a/chromium/storage/browser/file_system/task_runner_bound_observer_list.h
+++ b/chromium/storage/browser/file_system/task_runner_bound_observer_list.h
@@ -12,7 +12,6 @@
#include "base/location.h"
#include "base/memory/scoped_refptr.h"
#include "base/task/sequenced_task_runner.h"
-#include "base/threading/thread.h"
namespace storage {
diff --git a/chromium/storage/browser/quota/OWNERS b/chromium/storage/browser/quota/OWNERS
index 96896d848b8..2d495dc641c 100644
--- a/chromium/storage/browser/quota/OWNERS
+++ b/chromium/storage/browser/quota/OWNERS
@@ -2,11 +2,9 @@
ayui@chromium.org
# Secondary
+asully@chromium.org
jarrydg@chromium.org
jsbell@chromium.org
-kinuko@chromium.org
-mek@chromium.org
-pwnall@chromium.org
per-file *.mojom=set noparent
-per-file *.mojom=file://ipc/SECURITY_OWNERS \ No newline at end of file
+per-file *.mojom=file://ipc/SECURITY_OWNERS
diff --git a/chromium/storage/browser/quota/quota_callbacks.h b/chromium/storage/browser/quota/quota_callbacks.h
index 5598c143d84..18eda095da5 100644
--- a/chromium/storage/browser/quota/quota_callbacks.h
+++ b/chromium/storage/browser/quota/quota_callbacks.h
@@ -29,7 +29,6 @@ struct UsageInfo;
using UsageInfoEntries = std::vector<UsageInfo>;
// Common callback types that are used throughout in the quota module.
-using AddChangeListenerCallback = base::OnceCallback<void()>;
using UsageCallback =
base::OnceCallback<void(int64_t usage, int64_t unlimited_usage)>;
using QuotaCallback =
diff --git a/chromium/storage/browser/quota/quota_client_type.cc b/chromium/storage/browser/quota/quota_client_type.cc
index cb737075211..02c4e4f1b5b 100644
--- a/chromium/storage/browser/quota/quota_client_type.cc
+++ b/chromium/storage/browser/quota/quota_client_type.cc
@@ -17,6 +17,7 @@ const QuotaClientTypes& AllQuotaClientTypes() {
QuotaClientType::kServiceWorker,
QuotaClientType::kBackgroundFetch,
QuotaClientType::kNativeIO,
+ QuotaClientType::kMediaLicense,
}};
return *all;
}
diff --git a/chromium/storage/browser/quota/quota_client_type.h b/chromium/storage/browser/quota/quota_client_type.h
index d90cf800803..59a245bad41 100644
--- a/chromium/storage/browser/quota/quota_client_type.h
+++ b/chromium/storage/browser/quota/quota_client_type.h
@@ -22,6 +22,7 @@ enum class QuotaClientType {
kServiceWorker = 5,
kBackgroundFetch = 6,
kNativeIO = 7,
+ kMediaLicense = 8,
};
// Set of QuotaClientType values.
diff --git a/chromium/storage/browser/quota/quota_database.cc b/chromium/storage/browser/quota/quota_database.cc
index dc62026cc97..38bbb9f343c 100644
--- a/chromium/storage/browser/quota/quota_database.cc
+++ b/chromium/storage/browser/quota/quota_database.cc
@@ -17,10 +17,12 @@
#include "base/dcheck_is_on.h"
#include "base/files/file_util.h"
#include "base/metrics/histogram_functions.h"
+#include "base/sequence_checker.h"
#include "components/services/storage/public/cpp/buckets/constants.h"
+#include "components/services/storage/public/cpp/quota_error_or.h"
#include "sql/database.h"
-#include "sql/error_metrics.h"
#include "sql/meta_table.h"
+#include "sql/sqlite_result_code.h"
#include "sql/statement.h"
#include "sql/transaction.h"
#include "storage/browser/quota/quota_database_migrations.h"
@@ -89,7 +91,7 @@ const QuotaDatabase::TableSchema QuotaDatabase::kTables[] = {
" last_modified INTEGER NOT NULL,"
" expiration INTEGER NOT NULL,"
" quota INTEGER NOT NULL)"}};
-const size_t QuotaDatabase::kTableCount = base::size(QuotaDatabase::kTables);
+const size_t QuotaDatabase::kTableCount = std::size(QuotaDatabase::kTables);
// static
const QuotaDatabase::IndexSchema QuotaDatabase::kIndexes[] = {
@@ -99,7 +101,7 @@ const QuotaDatabase::IndexSchema QuotaDatabase::kIndexes[] = {
{"buckets_by_last_modified", kBucketTable, "(type, last_modified)", false},
{"buckets_by_expiration", kBucketTable, "(expiration)", false},
};
-const size_t QuotaDatabase::kIndexCount = base::size(QuotaDatabase::kIndexes);
+const size_t QuotaDatabase::kIndexCount = std::size(QuotaDatabase::kIndexes);
QuotaDatabase::BucketTableEntry::BucketTableEntry() = default;
@@ -127,7 +129,18 @@ QuotaDatabase::BucketTableEntry::BucketTableEntry(
last_modified(last_modified) {}
// QuotaDatabase ------------------------------------------------------------
-QuotaDatabase::QuotaDatabase(const base::FilePath& path) : db_file_path_(path) {
+QuotaDatabase::QuotaDatabase(const base::FilePath& profile_path)
+ : storage_directory_(
+ profile_path.empty()
+ ? nullptr
+ : std::make_unique<StorageDirectory>(profile_path)),
+ db_file_path_(
+ profile_path.empty()
+ ? base::FilePath()
+ : storage_directory_->path().AppendASCII(kDatabaseName)),
+ legacy_db_file_path_(profile_path.empty()
+ ? base::FilePath()
+ : profile_path.AppendASCII(kDatabaseName)) {
DETACH_FROM_SEQUENCE(sequence_checker_);
}
@@ -138,10 +151,12 @@ QuotaDatabase::~QuotaDatabase() {
}
}
+constexpr char QuotaDatabase::kDatabaseName[];
+
QuotaErrorOr<int64_t> QuotaDatabase::GetHostQuota(const std::string& host,
StorageType type) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- QuotaError open_error = EnsureOpened(EnsureOpenedMode::kFailIfNotFound);
+ QuotaError open_error = EnsureOpened();
if (open_error != QuotaError::kNone)
return open_error;
@@ -163,7 +178,7 @@ QuotaError QuotaDatabase::SetHostQuota(const std::string& host,
int64_t quota) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK_GE(quota, 0);
- QuotaError open_error = EnsureOpened(EnsureOpenedMode::kCreateIfNotFound);
+ QuotaError open_error = EnsureOpened();
if (open_error != QuotaError::kNone)
return open_error;
@@ -228,16 +243,6 @@ QuotaErrorOr<BucketInfo> QuotaDatabase::CreateBucketForTesting(
blink::mojom::StorageType storage_type) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- // TODO(crbug/1210252): Update to not execute 2 sql statements on creation.
- QuotaErrorOr<BucketInfo> bucket_result =
- GetBucket(storage_key, bucket_name, storage_type);
-
- if (bucket_result.ok())
- return QuotaError::kEntryExistsError;
-
- if (bucket_result.error() != QuotaError::kNotFound)
- return bucket_result.error();
-
base::Time now = base::Time::Now();
return CreateBucketInternal(storage_key, storage_type, bucket_name,
/*use_count=*/0, now, now);
@@ -248,7 +253,7 @@ QuotaErrorOr<BucketInfo> QuotaDatabase::GetBucket(
const std::string& bucket_name,
blink::mojom::StorageType storage_type) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- QuotaError open_error = EnsureOpened(EnsureOpenedMode::kFailIfNotFound);
+ QuotaError open_error = EnsureOpened();
if (open_error != QuotaError::kNone)
return open_error;
@@ -273,10 +278,41 @@ QuotaErrorOr<BucketInfo> QuotaDatabase::GetBucket(
statement.ColumnInt(2));
}
+QuotaErrorOr<BucketInfo> QuotaDatabase::GetBucketById(BucketId bucket_id) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ QuotaError open_error = EnsureOpened();
+ if (open_error != QuotaError::kNone)
+ return open_error;
+
+ static constexpr char kSql[] =
+ // clang-format off
+ "SELECT storage_key, type, name, expiration, quota "
+ "FROM buckets "
+ "WHERE id = ?";
+ // clang-format on
+ sql::Statement statement(db_->GetCachedStatement(SQL_FROM_HERE, kSql));
+ statement.BindInt64(0, bucket_id.value());
+
+ if (!statement.Step()) {
+ return statement.Succeeded() ? QuotaError::kNotFound
+ : QuotaError::kDatabaseError;
+ }
+
+ absl::optional<StorageKey> storage_key =
+ StorageKey::Deserialize(statement.ColumnString(0));
+ if (!storage_key.has_value())
+ return QuotaError::kNotFound;
+
+ return BucketInfo(bucket_id, storage_key.value(),
+ static_cast<StorageType>(statement.ColumnInt(1)),
+ statement.ColumnString(2), statement.ColumnTime(3),
+ statement.ColumnInt(4));
+}
+
QuotaErrorOr<std::set<BucketLocator>> QuotaDatabase::GetBucketsForType(
StorageType type) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- QuotaError open_error = EnsureOpened(EnsureOpenedMode::kFailIfNotFound);
+ QuotaError open_error = EnsureOpened();
if (open_error != QuotaError::kNone)
return open_error;
@@ -303,7 +339,7 @@ QuotaErrorOr<std::set<BucketLocator>> QuotaDatabase::GetBucketsForHost(
const std::string& host,
blink::mojom::StorageType storage_type) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- QuotaError open_error = EnsureOpened(EnsureOpenedMode::kFailIfNotFound);
+ QuotaError open_error = EnsureOpened();
if (open_error != QuotaError::kNone)
return open_error;
@@ -331,7 +367,7 @@ QuotaErrorOr<std::set<BucketLocator>> QuotaDatabase::GetBucketsForStorageKey(
const StorageKey& storage_key,
StorageType type) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- QuotaError open_error = EnsureOpened(EnsureOpenedMode::kFailIfNotFound);
+ QuotaError open_error = EnsureOpened();
if (open_error != QuotaError::kNone)
return open_error;
@@ -355,27 +391,21 @@ QuotaError QuotaDatabase::SetStorageKeyLastAccessTime(
StorageType type,
base::Time last_accessed) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- QuotaError open_error = EnsureOpened(EnsureOpenedMode::kFailIfNotFound);
+ QuotaError open_error = EnsureOpened();
if (open_error != QuotaError::kNone)
return open_error;
- // Check if bucket exists first. Running an update statement on a bucket that
- // doesn't exist fails DCHECK and crashes.
- // TODO(crbug/1210252): Update to not execute 2 sql statements.
- QuotaErrorOr<BucketInfo> result =
- GetBucket(storage_key, kDefaultBucketName, type);
- if (!result.ok())
- return result.error();
-
// clang-format off
static constexpr char kSql[] =
"UPDATE buckets "
"SET use_count = use_count + 1, last_accessed = ? "
- "WHERE id = ?";
+ "WHERE storage_key = ? AND type = ? AND name = ?";
// clang-format on
sql::Statement statement(db_->GetCachedStatement(SQL_FROM_HERE, kSql));
statement.BindTime(0, last_accessed);
- statement.BindInt64(1, result->id.value());
+ statement.BindString(1, storage_key.Serialize());
+ statement.BindInt(2, static_cast<int>(type));
+ statement.BindString(3, kDefaultBucketName);
if (!statement.Run())
return QuotaError::kDatabaseError;
@@ -388,17 +418,10 @@ QuotaError QuotaDatabase::SetBucketLastAccessTime(BucketId bucket_id,
base::Time last_accessed) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(!bucket_id.is_null());
- QuotaError open_error = EnsureOpened(EnsureOpenedMode::kFailIfNotFound);
+ QuotaError open_error = EnsureOpened();
if (open_error != QuotaError::kNone)
return open_error;
- // Check if bucket exists first. Running an update statement on a bucket that
- // doesn't exist fails DCHECK and crashes.
- // TODO(crbug/1210252): Update to not execute 2 sql statements.
- QuotaErrorOr<BucketTableEntry> entry = GetBucketInfo(bucket_id);
- if (!entry.ok())
- return entry.error();
-
// clang-format off
static constexpr char kSql[] =
"UPDATE buckets "
@@ -420,17 +443,10 @@ QuotaError QuotaDatabase::SetBucketLastModifiedTime(BucketId bucket_id,
base::Time last_modified) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(!bucket_id.is_null());
- QuotaError open_error = EnsureOpened(EnsureOpenedMode::kFailIfNotFound);
+ QuotaError open_error = EnsureOpened();
if (open_error != QuotaError::kNone)
return open_error;
- // Check if bucket exists first. Running an update statement on a bucket that
- // doesn't exist fails DCHECK and crashes.
- // TODO(crbug/1210252): Update to not execute 2 sql statements.
- QuotaErrorOr<BucketTableEntry> entry = GetBucketInfo(bucket_id);
- if (!entry.ok())
- return entry.error();
-
static constexpr char kSql[] =
"UPDATE buckets SET last_modified = ? WHERE id = ?";
sql::Statement statement(db_->GetCachedStatement(SQL_FROM_HERE, kSql));
@@ -447,7 +463,7 @@ QuotaError QuotaDatabase::SetBucketLastModifiedTime(BucketId bucket_id,
QuotaError QuotaDatabase::RegisterInitialStorageKeyInfo(
base::flat_map<StorageType, std::set<StorageKey>> storage_keys_by_type) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- QuotaError open_error = EnsureOpened(EnsureOpenedMode::kCreateIfNotFound);
+ QuotaError open_error = EnsureOpened();
if (open_error != QuotaError::kNone)
return open_error;
@@ -487,7 +503,7 @@ QuotaErrorOr<QuotaDatabase::BucketTableEntry> QuotaDatabase::GetBucketInfo(
BucketId bucket_id) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(!bucket_id.is_null());
- QuotaError open_error = EnsureOpened(EnsureOpenedMode::kFailIfNotFound);
+ QuotaError open_error = EnsureOpened();
if (open_error != QuotaError::kNone)
return open_error;
@@ -525,7 +541,7 @@ QuotaErrorOr<QuotaDatabase::BucketTableEntry> QuotaDatabase::GetBucketInfo(
QuotaError QuotaDatabase::DeleteHostQuota(const std::string& host,
StorageType type) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- QuotaError open_error = EnsureOpened(EnsureOpenedMode::kFailIfNotFound);
+ QuotaError open_error = EnsureOpened();
if (open_error != QuotaError::kNone)
return open_error;
@@ -545,7 +561,7 @@ QuotaError QuotaDatabase::DeleteHostQuota(const std::string& host,
QuotaError QuotaDatabase::DeleteBucketInfo(BucketId bucket_id) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(!bucket_id.is_null());
- QuotaError open_error = EnsureOpened(EnsureOpenedMode::kFailIfNotFound);
+ QuotaError open_error = EnsureOpened();
if (open_error != QuotaError::kNone)
return open_error;
@@ -556,7 +572,19 @@ QuotaError QuotaDatabase::DeleteBucketInfo(BucketId bucket_id) {
if (!statement.Run())
return QuotaError::kDatabaseError;
+ // Scheduling this commit introduces the chance of inconsistencies
+ // between the buckets table and data stored on disk in the file system.
+ // If there is a crash or a battery failure before the transaction is
+ // committed, the bucket directory may be deleted from the file system,
+ // while an entry still may exist in the database.
+ //
+ // While this is not ideal, this does not introduce any new edge case.
+ // We should check that bucket IDs have existing associated directories,
+ // because database corruption could result in invalid bucket IDs.
+ // TODO(crbug.com/1314567): For handling inconsistencies between the db and
+ // the file system.
ScheduleCommit();
+
return QuotaError::kNone;
}
@@ -565,7 +593,7 @@ QuotaErrorOr<BucketLocator> QuotaDatabase::GetLRUBucket(
const std::set<BucketId>& bucket_exceptions,
SpecialStoragePolicy* special_storage_policy) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- QuotaError open_error = EnsureOpened(EnsureOpenedMode::kFailIfNotFound);
+ QuotaError open_error = EnsureOpened();
if (open_error != QuotaError::kNone)
return open_error;
@@ -606,7 +634,7 @@ QuotaErrorOr<BucketLocator> QuotaDatabase::GetLRUBucket(
QuotaErrorOr<std::set<StorageKey>> QuotaDatabase::GetStorageKeysForType(
StorageType type) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- QuotaError open_error = EnsureOpened(EnsureOpenedMode::kFailIfNotFound);
+ QuotaError open_error = EnsureOpened();
if (open_error != QuotaError::kNone)
return open_error;
@@ -632,7 +660,7 @@ QuotaErrorOr<std::set<BucketLocator>> QuotaDatabase::GetBucketsModifiedBetween(
base::Time begin,
base::Time end) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- QuotaError open_error = EnsureOpened(EnsureOpenedMode::kFailIfNotFound);
+ QuotaError open_error = EnsureOpened();
if (open_error != QuotaError::kNone)
return open_error;
@@ -664,7 +692,7 @@ QuotaErrorOr<std::set<BucketLocator>> QuotaDatabase::GetBucketsModifiedBetween(
bool QuotaDatabase::IsBootstrapped() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- if (EnsureOpened(EnsureOpenedMode::kCreateIfNotFound) != QuotaError::kNone)
+ if (EnsureOpened() != QuotaError::kNone)
return false;
int flag = 0;
@@ -673,7 +701,7 @@ bool QuotaDatabase::IsBootstrapped() {
QuotaError QuotaDatabase::SetIsBootstrapped(bool bootstrap_flag) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- QuotaError open_error = EnsureOpened(EnsureOpenedMode::kCreateIfNotFound);
+ QuotaError open_error = EnsureOpened();
if (open_error != QuotaError::kNone)
return open_error;
@@ -687,6 +715,30 @@ QuotaError QuotaDatabase::SetIsBootstrapped(bool bootstrap_flag) {
: QuotaError::kDatabaseError;
}
+QuotaError QuotaDatabase::RazeAndReopen() {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ // Try creating a database one last time if there isn't one.
+ if (!db_) {
+ if (!db_file_path_.empty()) {
+ DCHECK(!legacy_db_file_path_.empty());
+ sql::Database::Delete(db_file_path_);
+ sql::Database::Delete(legacy_db_file_path_);
+ }
+ return EnsureOpened();
+ }
+
+ // Abort the long-running transaction.
+ db_->RollbackTransaction();
+
+ // Raze and close the database. Reset `db_` to nullptr so EnsureOpened will
+ // recreate the database.
+ if (!db_->Raze())
+ return QuotaError::kDatabaseError;
+ db_ = nullptr;
+
+ return EnsureOpened();
+}
+
QuotaError QuotaDatabase::CorruptForTesting(
base::OnceCallback<void(const base::FilePath&)> corrupter) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
@@ -710,6 +762,11 @@ QuotaError QuotaDatabase::CorruptForTesting(
return QuotaError::kNone;
}
+void QuotaDatabase::SetDisabledForTesting(bool disable) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ is_disabled_ = disable;
+}
+
void QuotaDatabase::Commit() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (!db_)
@@ -733,7 +790,7 @@ void QuotaDatabase::ScheduleCommit() {
&QuotaDatabase::Commit);
}
-QuotaError QuotaDatabase::EnsureOpened(EnsureOpenedMode mode) {
+QuotaError QuotaDatabase::EnsureOpened() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (db_)
return QuotaError::kNone;
@@ -743,14 +800,12 @@ QuotaError QuotaDatabase::EnsureOpened(EnsureOpenedMode mode) {
if (is_disabled_)
return QuotaError::kDatabaseError;
- bool in_memory_only = db_file_path_.empty();
- if (mode == EnsureOpenedMode::kFailIfNotFound &&
- (in_memory_only || !base::PathExists(db_file_path_))) {
- return QuotaError::kNotFound;
- }
-
db_ = std::make_unique<sql::Database>(sql::DatabaseOptions{
.exclusive_locking = true,
+ // The quota database is a critical storage component. If it's corrupted,
+ // all client-side storage APIs fail, because they don't know where their
+ // data is stored.
+ .flush_to_media = true,
.page_size = 4096,
.cache_size = 500,
});
@@ -765,9 +820,21 @@ QuotaError QuotaDatabase::EnsureOpened(EnsureOpenedMode mode) {
sqlite_error_code);
}));
+ // Migrate an existing database from the old path.
+ if (!db_file_path_.empty() && !MoveLegacyDatabase()) {
+ if (!ResetStorage()) {
+ is_disabled_ = true;
+ db_.reset();
+ meta_table_.reset();
+ return QuotaError::kDatabaseError;
+ }
+ // ResetStorage() has succeeded and database is already open.
+ return QuotaError::kNone;
+ }
+
if (!OpenDatabase() || !EnsureDatabaseVersion()) {
LOG(ERROR) << "Could not open the quota database, resetting.";
- if (!ResetSchema()) {
+ if (db_file_path_.empty() || !ResetStorage()) {
LOG(ERROR) << "Failed to reset the quota database.";
is_disabled_ = true;
db_.reset();
@@ -782,7 +849,36 @@ QuotaError QuotaDatabase::EnsureOpened(EnsureOpenedMode mode) {
return QuotaError::kNone;
}
+bool QuotaDatabase::MoveLegacyDatabase() {
+ // Migration was added on 04/2022 (https://crrev.com/c/3513545).
+ // Cleanup after enough time has passed.
+ if (base::PathExists(db_file_path_) ||
+ !base::PathExists(legacy_db_file_path_)) {
+ return true;
+ }
+
+ if (!base::CreateDirectory(db_file_path_.DirName()) ||
+ !base::CopyFile(legacy_db_file_path_, db_file_path_)) {
+ sql::Database::Delete(db_file_path_);
+ return false;
+ }
+
+ base::FilePath legacy_journal_path =
+ sql::Database::JournalPath(legacy_db_file_path_);
+ if (base::PathExists(legacy_journal_path) &&
+ !base::CopyFile(legacy_journal_path,
+ sql::Database::JournalPath(db_file_path_))) {
+ sql::Database::Delete(db_file_path_);
+ return false;
+ }
+
+ sql::Database::Delete(legacy_db_file_path_);
+ return true;
+}
+
bool QuotaDatabase::OpenDatabase() {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
// Open in memory database.
if (db_file_path_.empty()) {
if (db_->OpenInMemory())
@@ -844,6 +940,8 @@ bool QuotaDatabase::EnsureDatabaseVersion() {
}
bool QuotaDatabase::CreateSchema() {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
// TODO(kinuko): Factor out the common code to create databases.
sql::Transaction transaction(db_.get());
if (!transaction.Begin())
@@ -868,6 +966,8 @@ bool QuotaDatabase::CreateSchema() {
}
bool QuotaDatabase::CreateTable(const TableSchema& table) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
std::string sql("CREATE TABLE ");
sql += table.table_name;
sql += table.columns;
@@ -879,6 +979,8 @@ bool QuotaDatabase::CreateTable(const TableSchema& table) {
}
bool QuotaDatabase::CreateIndex(const IndexSchema& index) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
std::string sql;
if (index.unique)
sql += "CREATE UNIQUE INDEX ";
@@ -895,51 +997,39 @@ bool QuotaDatabase::CreateIndex(const IndexSchema& index) {
return true;
}
-bool QuotaDatabase::ResetSchema() {
+bool QuotaDatabase::ResetStorage() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(!db_file_path_.empty());
- DCHECK(base::PathExists(db_file_path_));
+ DCHECK(storage_directory_);
DCHECK(!db_ || !db_->transaction_nesting());
VLOG(1) << "Deleting existing quota data and starting over.";
db_.reset();
meta_table_.reset();
- if (!sql::Database::Delete(db_file_path_))
- return false;
+ sql::Database::Delete(legacy_db_file_path_);
+ sql::Database::Delete(db_file_path_);
+
+ // Explicit file deletion to try and get consistent deletion across platforms.
+ base::DeleteFile(legacy_db_file_path_);
+ base::DeleteFile(db_file_path_);
+ base::DeleteFile(sql::Database::JournalPath(legacy_db_file_path_));
+ base::DeleteFile(sql::Database::JournalPath(db_file_path_));
+
+ storage_directory_->Doom();
+ storage_directory_->ClearDoomed();
// So we can't go recursive.
if (is_recreating_)
return false;
base::AutoReset<bool> auto_reset(&is_recreating_, true);
- return EnsureOpened(EnsureOpenedMode::kCreateIfNotFound) == QuotaError::kNone;
-}
-
-QuotaError QuotaDatabase::DumpQuotaTable(const QuotaTableCallback& callback) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- QuotaError open_error = EnsureOpened(EnsureOpenedMode::kCreateIfNotFound);
- if (open_error != QuotaError::kNone)
- return open_error;
-
- static constexpr char kSql[] = "SELECT * FROM quota";
- sql::Statement statement(db_->GetCachedStatement(SQL_FROM_HERE, kSql));
-
- while (statement.Step()) {
- QuotaTableEntry entry = {
- .host = statement.ColumnString(0),
- .type = static_cast<StorageType>(statement.ColumnInt(1)),
- .quota = statement.ColumnInt64(2)};
-
- if (!callback.Run(entry))
- return QuotaError::kNone;
- }
- return statement.Succeeded() ? QuotaError::kNone : QuotaError::kDatabaseError;
+ return EnsureOpened() == QuotaError::kNone;
}
QuotaError QuotaDatabase::DumpBucketTable(const BucketTableCallback& callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- QuotaError open_error = EnsureOpened(EnsureOpenedMode::kCreateIfNotFound);
+ QuotaError open_error = EnsureOpened();
if (open_error != QuotaError::kNone)
return open_error;
@@ -983,7 +1073,7 @@ QuotaErrorOr<BucketInfo> QuotaDatabase::CreateBucketInternal(
base::Time last_modified) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
// TODO(crbug/1210259): Add DCHECKs for input validation.
- QuotaError open_error = EnsureOpened(EnsureOpenedMode::kCreateIfNotFound);
+ QuotaError open_error = EnsureOpened();
if (open_error != QuotaError::kNone)
return open_error;
@@ -1014,24 +1104,16 @@ QuotaErrorOr<BucketInfo> QuotaDatabase::CreateBucketInternal(
if (!statement.Run())
return QuotaError::kDatabaseError;
- ScheduleCommit();
-
int64_t bucket_id = db_->GetLastInsertRowId();
DCHECK_GT(bucket_id, 0);
- return BucketInfo(BucketId(bucket_id), storage_key, type, bucket_name,
- base::Time::Max(), 0);
-}
-bool operator==(const QuotaDatabase::QuotaTableEntry& lhs,
- const QuotaDatabase::QuotaTableEntry& rhs) {
- return std::tie(lhs.host, lhs.type, lhs.quota) ==
- std::tie(rhs.host, rhs.type, rhs.quota);
-}
+ // Commit immediately so that we persist the bucket metadata to disk before we
+ // inform other services / web apps (via the Buckets API) that we did so.
+ // Once informed, that promise should persist across power failures.
+ Commit();
-bool operator<(const QuotaDatabase::QuotaTableEntry& lhs,
- const QuotaDatabase::QuotaTableEntry& rhs) {
- return std::tie(lhs.host, lhs.type, lhs.quota) <
- std::tie(rhs.host, rhs.type, rhs.quota);
+ return BucketInfo(BucketId(bucket_id), storage_key, type, bucket_name,
+ base::Time::Max(), 0);
}
bool operator<(const QuotaDatabase::BucketTableEntry& lhs,
diff --git a/chromium/storage/browser/quota/quota_database.h b/chromium/storage/browser/quota/quota_database.h
index 75de1871c82..5b59290c3e4 100644
--- a/chromium/storage/browser/quota/quota_database.h
+++ b/chromium/storage/browser/quota/quota_database.h
@@ -16,6 +16,7 @@
#include "base/component_export.h"
#include "base/files/file_path.h"
#include "base/sequence_checker.h"
+#include "base/thread_annotations.h"
#include "base/time/time.h"
#include "base/timer/timer.h"
#include "base/types/id_type.h"
@@ -24,6 +25,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/storage_directory.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
#include "third_party/blink/public/common/storage_key/storage_key.h"
#include "third_party/blink/public/mojom/quota/quota_types.mojom-shared.h"
@@ -55,8 +57,7 @@ enum class DatabaseResetReason {
//
// Instances are owned by QuotaManagerImpl. There is one instance per
// QuotaManagerImpl instance. All the methods of this class, except the
-// constructor, must called on the DB thread. QuotaDatabase should only be
-// subclassed in tests.
+// constructor, must called on the DB thread.
class COMPONENT_EXPORT(STORAGE_BROWSER) QuotaDatabase {
public:
struct COMPONENT_EXPORT(STORAGE_BROWSER) BucketTableEntry {
@@ -82,13 +83,15 @@ class COMPONENT_EXPORT(STORAGE_BROWSER) QuotaDatabase {
base::Time last_modified;
};
- // If 'path' is empty, an in memory database will be used.
- explicit QuotaDatabase(const base::FilePath& path);
+ static constexpr char kDatabaseName[] = "QuotaManager";
+
+ // If `profile_path` is empty, an in-memory database will be used.
+ explicit QuotaDatabase(const base::FilePath& profile_path);
QuotaDatabase(const QuotaDatabase&) = delete;
QuotaDatabase& operator=(const QuotaDatabase&) = delete;
- virtual ~QuotaDatabase();
+ ~QuotaDatabase();
// Returns quota if entry is found. Returns QuotaError::kNotFound no entry if
// found.
@@ -134,6 +137,11 @@ class COMPONENT_EXPORT(STORAGE_BROWSER) QuotaDatabase {
const std::string& bucket_name,
blink::mojom::StorageType storage_type);
+ // Retrieves BucketInfo of the bucket with `bucket_id`.
+ // Returns a QuotaError::kEntryNotFound if the bucket does not exist, or
+ // a QuotaError::kDatabaseError if the operation has failed.
+ QuotaErrorOr<BucketInfo> GetBucketById(BucketId bucket_id);
+
// Returns all buckets for `type` in the buckets table. Returns a QuotaError
// if the operation has failed.
QuotaErrorOr<std::set<BucketLocator>> GetBucketsForType(
@@ -181,8 +189,8 @@ class COMPONENT_EXPORT(STORAGE_BROWSER) QuotaDatabase {
// QuotaError if not found or the operation has failed.
QuotaErrorOr<BucketTableEntry> GetBucketInfo(BucketId bucket_id);
- // Deletes the specified bucket. This method is virtual for testing.
- virtual QuotaError DeleteBucketInfo(BucketId bucket_id);
+ // Deletes the specified bucket.
+ QuotaError DeleteBucketInfo(BucketId bucket_id);
// Returns the BucketLocator for the least recently used bucket. Will exclude
// buckets with ids in `bucket_exceptions` and origins that have the special
@@ -203,6 +211,8 @@ class COMPONENT_EXPORT(STORAGE_BROWSER) QuotaDatabase {
base::Time begin,
base::Time end);
+ base::FilePath GetStoragePath() const { return storage_directory_->path(); }
+
// Returns false if SetIsBootstrapped() has never been called before, which
// means existing storage keys may not have been registered. Bootstrapping
// ensures that there is a bucket entry in the buckets table for all storage
@@ -210,17 +220,27 @@ class COMPONENT_EXPORT(STORAGE_BROWSER) QuotaDatabase {
bool IsBootstrapped();
QuotaError SetIsBootstrapped(bool bootstrap_flag);
+ // Razes and re-opens the database. Will try to open a database again if
+ // one doesn't exist.
+ QuotaError RazeAndReopen();
+
+ // Testing support for database corruption handling.
+ //
+ // Runs `corrupter` on the same sequence used to do database I/O,
+ // guaranteeing that no other database operation is performed at the same
+ // time. `corrupter` receives the path to the underlying SQLite database as an
+ // argument. The underlying SQLite database is closed while `corrupter` runs,
+ // and reopened afterwards.
+
// Returns QuotaError::kNone if the database was successfully reopened after
// `corrupter` was run, or QuotaError::kDatabaseError otherwise.
QuotaError CorruptForTesting(
base::OnceCallback<void(const base::FilePath&)> corrupter);
// Manually disable database to test database error scenarios for testing.
- void SetDisabledForTesting(bool disable) { is_disabled_ = disable; }
+ void SetDisabledForTesting(bool disable);
private:
- enum class EnsureOpenedMode { kCreateIfNotFound, kFailIfNotFound };
-
struct COMPONENT_EXPORT(STORAGE_BROWSER) QuotaTableEntry {
std::string host;
blink::mojom::StorageType type = blink::mojom::StorageType::kUnknown;
@@ -260,11 +280,11 @@ class COMPONENT_EXPORT(STORAGE_BROWSER) QuotaDatabase {
void Commit();
void ScheduleCommit();
- QuotaError EnsureOpened(EnsureOpenedMode mode);
+ QuotaError EnsureOpened();
+ bool MoveLegacyDatabase();
bool OpenDatabase();
bool EnsureDatabaseVersion();
- bool ResetSchema();
- bool UpgradeSchema(int current_version);
+ bool ResetStorage();
bool CreateSchema();
bool CreateTable(const TableSchema& table);
@@ -285,14 +305,19 @@ class COMPONENT_EXPORT(STORAGE_BROWSER) QuotaDatabase {
base::Time last_accessed,
base::Time last_modified);
+ SEQUENCE_CHECKER(sequence_checker_);
+
+ const std::unique_ptr<StorageDirectory> storage_directory_;
const base::FilePath db_file_path_;
+ const base::FilePath legacy_db_file_path_;
- std::unique_ptr<sql::Database> db_;
- std::unique_ptr<sql::MetaTable> meta_table_;
- bool is_recreating_ = false;
- bool is_disabled_ = false;
+ std::unique_ptr<sql::Database> db_ GUARDED_BY_CONTEXT(sequence_checker_);
+ std::unique_ptr<sql::MetaTable> meta_table_
+ GUARDED_BY_CONTEXT(sequence_checker_);
+ bool is_recreating_ GUARDED_BY_CONTEXT(sequence_checker_) = false;
+ bool is_disabled_ GUARDED_BY_CONTEXT(sequence_checker_) = false;
- base::OneShotTimer timer_;
+ base::OneShotTimer timer_ GUARDED_BY_CONTEXT(sequence_checker_);
friend class QuotaDatabaseTest;
friend class QuotaDatabaseMigrations;
@@ -303,8 +328,6 @@ class COMPONENT_EXPORT(STORAGE_BROWSER) QuotaDatabase {
static const size_t kTableCount;
static const IndexSchema kIndexes[];
static const size_t kIndexCount;
-
- SEQUENCE_CHECKER(sequence_checker_);
};
} // namespace storage
diff --git a/chromium/storage/browser/quota/quota_database_migrations.cc b/chromium/storage/browser/quota/quota_database_migrations.cc
index 31780a3f513..9402fb2b1ad 100644
--- a/chromium/storage/browser/quota/quota_database_migrations.cc
+++ b/chromium/storage/browser/quota/quota_database_migrations.cc
@@ -6,6 +6,7 @@
#include <string>
+#include "base/sequence_checker.h"
#include "components/services/storage/public/cpp/buckets/bucket_id.h"
#include "sql/database.h"
#include "sql/meta_table.h"
@@ -18,11 +19,12 @@ namespace storage {
// static
bool QuotaDatabaseMigrations::UpgradeSchema(QuotaDatabase& quota_database) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(quota_database.sequence_checker_);
DCHECK_EQ(0, quota_database.db_->transaction_nesting());
// Reset tables for versions lower than 5 since they are unsupported.
if (quota_database.meta_table_->GetVersionNumber() < 5)
- return quota_database.ResetSchema();
+ return quota_database.ResetStorage();
if (quota_database.meta_table_->GetVersionNumber() == 5) {
if (!MigrateFromVersion5ToVersion7(quota_database))
@@ -44,6 +46,8 @@ bool QuotaDatabaseMigrations::UpgradeSchema(QuotaDatabase& quota_database) {
bool QuotaDatabaseMigrations::MigrateFromVersion5ToVersion7(
QuotaDatabase& quota_database) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(quota_database.sequence_checker_);
+
sql::Database* db = quota_database.db_.get();
sql::Transaction transaction(db);
if (!transaction.Begin())
@@ -147,6 +151,8 @@ bool QuotaDatabaseMigrations::MigrateFromVersion5ToVersion7(
bool QuotaDatabaseMigrations::MigrateFromVersion6ToVersion7(
QuotaDatabase& quota_database) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(quota_database.sequence_checker_);
+
sql::Database* db = quota_database.db_.get();
sql::Transaction transaction(db);
if (!transaction.Begin())
@@ -164,6 +170,8 @@ bool QuotaDatabaseMigrations::MigrateFromVersion6ToVersion7(
bool QuotaDatabaseMigrations::MigrateFromVersion7ToVersion8(
QuotaDatabase& quota_database) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(quota_database.sequence_checker_);
+
sql::Database* db = quota_database.db_.get();
sql::Transaction transaction(db);
if (!transaction.Begin())
diff --git a/chromium/storage/browser/quota/quota_database_migrations_unittest.cc b/chromium/storage/browser/quota/quota_database_migrations_unittest.cc
index 436552e8cf9..220d4d29286 100644
--- a/chromium/storage/browser/quota/quota_database_migrations_unittest.cc
+++ b/chromium/storage/browser/quota/quota_database_migrations_unittest.cc
@@ -5,6 +5,7 @@
#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
#include "base/path_service.h"
+#include "components/services/storage/public/cpp/constants.h"
#include "sql/database.h"
#include "sql/meta_table.h"
#include "sql/statement.h"
@@ -31,8 +32,12 @@ class QuotaDatabaseMigrationsTest : public testing::Test {
public:
void SetUp() override { ASSERT_TRUE(temp_directory_.CreateUniqueTempDir()); }
+ base::FilePath ProfilePath() { return temp_directory_.GetPath(); }
+
base::FilePath DbPath() {
- return temp_directory_.GetPath().AppendASCII("quota_manager.db");
+ return ProfilePath()
+ .Append(kWebStorageDirectory)
+ .AppendASCII("QuotaManager");
}
protected:
@@ -58,16 +63,17 @@ class QuotaDatabaseMigrationsTest : public testing::Test {
return false;
sql::Database db;
- if (!db.Open(db_path) || !db.Execute(contents.data()))
+ if (!base::CreateDirectory(db_path.DirName()) || !db.Open(db_path) ||
+ !db.Execute(contents.data()))
return false;
return true;
}
void MigrateDatabase() {
- QuotaDatabase db(DbPath());
- EXPECT_EQ(
- db.EnsureOpened(QuotaDatabase::EnsureOpenedMode::kCreateIfNotFound),
- QuotaError::kNone);
+ QuotaDatabase db(ProfilePath());
+ EXPECT_EQ(db.EnsureOpened(), QuotaError::kNone);
+
+ DCHECK_CALLED_ON_VALID_SEQUENCE(db.sequence_checker_);
EXPECT_TRUE(db.db_.get());
}
diff --git a/chromium/storage/browser/quota/quota_database_unittest.cc b/chromium/storage/browser/quota/quota_database_unittest.cc
index 18f6f282e6d..5f67178302f 100644
--- a/chromium/storage/browser/quota/quota_database_unittest.cc
+++ b/chromium/storage/browser/quota/quota_database_unittest.cc
@@ -7,6 +7,7 @@
#include <algorithm>
#include <iterator>
+#include <memory>
#include <set>
#include "base/bind.h"
@@ -15,14 +16,17 @@
#include "base/containers/flat_map.h"
#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
+#include "base/sequence_checker.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/task_environment.h"
#include "build/build_config.h"
#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/constants.h"
#include "sql/database.h"
-#include "sql/error_metrics.h"
#include "sql/meta_table.h"
+#include "sql/sqlite_result_code.h"
+#include "sql/sqlite_result_code_values.h"
#include "sql/statement.h"
#include "sql/test/scoped_error_expecter.h"
#include "sql/test/test_helpers.h"
@@ -44,6 +48,8 @@ static const blink::mojom::StorageType kTemp =
static const blink::mojom::StorageType kPerm =
blink::mojom::StorageType::kPersistent;
+static constexpr char kDatabaseName[] = "QuotaManager";
+
bool ContainsBucket(const std::set<BucketLocator>& buckets,
const BucketInfo& target_bucket) {
auto it = buckets.find(target_bucket.ToBucketLocator());
@@ -56,9 +62,7 @@ bool ContainsBucket(const std::set<BucketLocator>& buckets,
// mode. True will create the database in memory.
class QuotaDatabaseTest : public testing::TestWithParam<bool> {
protected:
- using QuotaTableEntry = QuotaDatabase::QuotaTableEntry;
using BucketTableEntry = QuotaDatabase::BucketTableEntry;
- using EnsureOpenedMode = QuotaDatabase::EnsureOpenedMode;
void SetUp() override { ASSERT_TRUE(temp_directory_.CreateUniqueTempDir()); }
@@ -66,12 +70,21 @@ class QuotaDatabaseTest : public testing::TestWithParam<bool> {
bool use_in_memory_db() const { return GetParam(); }
+ base::FilePath ProfilePath() { return temp_directory_.GetPath(); }
+
base::FilePath DbPath() {
- return temp_directory_.GetPath().AppendASCII("quota_manager.db");
+ return ProfilePath()
+ .Append(kWebStorageDirectory)
+ .AppendASCII(kDatabaseName);
+ }
+
+ std::unique_ptr<QuotaDatabase> CreateDatabase(bool is_incognito) {
+ return std::make_unique<QuotaDatabase>(is_incognito ? base::FilePath()
+ : ProfilePath());
}
- bool EnsureOpened(QuotaDatabase* db, EnsureOpenedMode mode) {
- return db->EnsureOpened(mode) == QuotaError::kNone;
+ bool EnsureOpened(QuotaDatabase* db) {
+ return db->EnsureOpened() == QuotaError::kNone;
}
template <typename EntryType>
@@ -123,7 +136,8 @@ class QuotaDatabaseTest : public testing::TestWithParam<bool> {
template <typename Container>
void AssignBucketTable(QuotaDatabase* quota_database, Container&& entries) {
- ASSERT_NE(quota_database->db_.get(), (sql::Database*)nullptr);
+ DCHECK_CALLED_ON_VALID_SEQUENCE(quota_database->sequence_checker_);
+ ASSERT_TRUE(quota_database->db_);
for (const auto& entry : entries) {
const char* kSql =
// clang-format off
@@ -164,9 +178,21 @@ class QuotaDatabaseTest : public testing::TestWithParam<bool> {
};
TEST_P(QuotaDatabaseTest, EnsureOpened) {
+ auto db = CreateDatabase(use_in_memory_db());
+ EXPECT_TRUE(EnsureOpened(db.get()));
+
+ if (GetParam()) {
+ // Path should not exist for incognito mode.
+ ASSERT_FALSE(base::PathExists(DbPath()));
+ } else {
+ ASSERT_TRUE(base::PathExists(DbPath()));
+ }
+}
+
+TEST_P(QuotaDatabaseTest, RazeAndReopenWithNoDb) {
QuotaDatabase db(use_in_memory_db() ? base::FilePath() : DbPath());
- EXPECT_FALSE(EnsureOpened(&db, EnsureOpenedMode::kFailIfNotFound));
- EXPECT_TRUE(EnsureOpened(&db, EnsureOpenedMode::kCreateIfNotFound));
+ // RazeAndReopen() with no db tries to create the db one last time.
+ EXPECT_EQ(db.RazeAndReopen(), QuotaError::kNone);
if (GetParam()) {
// Path should not exist for incognito mode.
@@ -177,59 +203,59 @@ TEST_P(QuotaDatabaseTest, EnsureOpened) {
}
TEST_P(QuotaDatabaseTest, HostQuota) {
- QuotaDatabase db(use_in_memory_db() ? base::FilePath() : DbPath());
- EXPECT_TRUE(EnsureOpened(&db, EnsureOpenedMode::kCreateIfNotFound));
+ auto db = CreateDatabase(use_in_memory_db());
+ EXPECT_TRUE(EnsureOpened(db.get()));
const char* kHost = "foo.com";
const int kQuota1 = 13579;
const int kQuota2 = kQuota1 + 1024;
- QuotaErrorOr<int64_t> result = db.GetHostQuota(kHost, kTemp);
+ QuotaErrorOr<int64_t> result = db->GetHostQuota(kHost, kTemp);
EXPECT_FALSE(result.ok());
EXPECT_EQ(result.error(), QuotaError::kNotFound);
- result = db.GetHostQuota(kHost, kPerm);
+ result = db->GetHostQuota(kHost, kPerm);
EXPECT_FALSE(result.ok());
EXPECT_EQ(result.error(), QuotaError::kNotFound);
// Insert quota for temporary.
- EXPECT_EQ(db.SetHostQuota(kHost, kTemp, kQuota1), QuotaError::kNone);
- result = db.GetHostQuota(kHost, kTemp);
+ EXPECT_EQ(db->SetHostQuota(kHost, kTemp, kQuota1), QuotaError::kNone);
+ result = db->GetHostQuota(kHost, kTemp);
EXPECT_TRUE(result.ok());
EXPECT_EQ(kQuota1, result.value());
// Update quota for temporary.
- EXPECT_EQ(db.SetHostQuota(kHost, kTemp, kQuota2), QuotaError::kNone);
- result = db.GetHostQuota(kHost, kTemp);
+ EXPECT_EQ(db->SetHostQuota(kHost, kTemp, kQuota2), QuotaError::kNone);
+ result = db->GetHostQuota(kHost, kTemp);
EXPECT_TRUE(result.ok());
EXPECT_EQ(kQuota2, result.value());
// Quota for persistent must not be updated.
- result = db.GetHostQuota(kHost, kPerm);
+ result = db->GetHostQuota(kHost, kPerm);
EXPECT_FALSE(result.ok());
EXPECT_EQ(result.error(), QuotaError::kNotFound);
// Delete temporary storage quota.
- EXPECT_EQ(db.DeleteHostQuota(kHost, kTemp), QuotaError::kNone);
- result = db.GetHostQuota(kHost, kTemp);
+ EXPECT_EQ(db->DeleteHostQuota(kHost, kTemp), QuotaError::kNone);
+ result = db->GetHostQuota(kHost, kTemp);
EXPECT_FALSE(result.ok());
EXPECT_EQ(result.error(), QuotaError::kNotFound);
// Delete persistent quota by setting it to zero.
- EXPECT_EQ(db.SetHostQuota(kHost, kPerm, 0), QuotaError::kNone);
- result = db.GetHostQuota(kHost, kPerm);
+ EXPECT_EQ(db->SetHostQuota(kHost, kPerm, 0), QuotaError::kNone);
+ result = db->GetHostQuota(kHost, kPerm);
EXPECT_FALSE(result.ok());
EXPECT_EQ(result.error(), QuotaError::kNotFound);
}
TEST_P(QuotaDatabaseTest, GetOrCreateBucket) {
- QuotaDatabase db(use_in_memory_db() ? base::FilePath() : DbPath());
- EXPECT_TRUE(EnsureOpened(&db, EnsureOpenedMode::kCreateIfNotFound));
+ auto db = CreateDatabase(use_in_memory_db());
+ EXPECT_TRUE(EnsureOpened(db.get()));
StorageKey storage_key =
StorageKey::CreateFromStringForTesting("http://google/");
std::string bucket_name = "google_bucket";
QuotaErrorOr<BucketInfo> result =
- db.GetOrCreateBucket(storage_key, bucket_name);
+ db->GetOrCreateBucket(storage_key, bucket_name);
ASSERT_TRUE(result.ok());
BucketInfo created_bucket = result.value();
@@ -239,7 +265,7 @@ TEST_P(QuotaDatabaseTest, GetOrCreateBucket) {
ASSERT_EQ(created_bucket.type, kTemp);
// Should return the same bucket when querying again.
- result = db.GetOrCreateBucket(storage_key, bucket_name);
+ result = db->GetOrCreateBucket(storage_key, bucket_name);
ASSERT_TRUE(result.ok());
BucketInfo retrieved_bucket = result.value();
@@ -250,14 +276,14 @@ TEST_P(QuotaDatabaseTest, GetOrCreateBucket) {
}
TEST_P(QuotaDatabaseTest, GetOrCreateBucketDeprecated) {
- QuotaDatabase db(use_in_memory_db() ? base::FilePath() : DbPath());
- EXPECT_TRUE(EnsureOpened(&db, EnsureOpenedMode::kCreateIfNotFound));
+ auto db = CreateDatabase(use_in_memory_db());
+ EXPECT_TRUE(EnsureOpened(db.get()));
StorageKey storage_key =
StorageKey::CreateFromStringForTesting("http://google/");
std::string bucket_name = "google_bucket";
QuotaErrorOr<BucketInfo> result =
- db.GetOrCreateBucketDeprecated(storage_key, bucket_name, kPerm);
+ db->GetOrCreateBucketDeprecated(storage_key, bucket_name, kPerm);
ASSERT_TRUE(result.ok());
BucketInfo created_bucket = result.value();
@@ -267,7 +293,7 @@ TEST_P(QuotaDatabaseTest, GetOrCreateBucketDeprecated) {
ASSERT_EQ(created_bucket.type, kPerm);
// Should return the same bucket when querying again.
- result = db.GetOrCreateBucketDeprecated(storage_key, bucket_name, kPerm);
+ result = db->GetOrCreateBucketDeprecated(storage_key, bucket_name, kPerm);
ASSERT_TRUE(result.ok());
BucketInfo retrieved_bucket = result.value();
@@ -278,15 +304,15 @@ TEST_P(QuotaDatabaseTest, GetOrCreateBucketDeprecated) {
}
TEST_P(QuotaDatabaseTest, GetBucket) {
- QuotaDatabase db(use_in_memory_db() ? base::FilePath() : DbPath());
- EXPECT_TRUE(EnsureOpened(&db, EnsureOpenedMode::kCreateIfNotFound));
+ auto db = CreateDatabase(use_in_memory_db());
+ EXPECT_TRUE(EnsureOpened(db.get()));
// Add a bucket entry into the bucket table.
StorageKey storage_key =
StorageKey::CreateFromStringForTesting("http://google/");
std::string bucket_name = "google_bucket";
QuotaErrorOr<BucketInfo> result =
- db.CreateBucketForTesting(storage_key, bucket_name, kPerm);
+ db->CreateBucketForTesting(storage_key, bucket_name, kPerm);
ASSERT_TRUE(result.ok());
BucketInfo created_bucket = result.value();
@@ -295,7 +321,7 @@ TEST_P(QuotaDatabaseTest, GetBucket) {
ASSERT_EQ(created_bucket.storage_key, storage_key);
ASSERT_EQ(created_bucket.type, kPerm);
- result = db.GetBucket(storage_key, bucket_name, kPerm);
+ result = db->GetBucket(storage_key, bucket_name, kPerm);
ASSERT_TRUE(result.ok());
EXPECT_EQ(result.value().id, created_bucket.id);
EXPECT_EQ(result.value().name, created_bucket.name);
@@ -303,21 +329,51 @@ TEST_P(QuotaDatabaseTest, GetBucket) {
ASSERT_EQ(result.value().type, created_bucket.type);
// Can't retrieve buckets with name mismatch.
- result = db.GetBucket(storage_key, "does_not_exist", kPerm);
+ result = db->GetBucket(storage_key, "does_not_exist", kPerm);
ASSERT_FALSE(result.ok());
EXPECT_EQ(result.error(), QuotaError::kNotFound);
// Can't retrieve buckets with StorageKey mismatch.
result =
- db.GetBucket(StorageKey::CreateFromStringForTesting("http://example/"),
- bucket_name, kPerm);
+ db->GetBucket(StorageKey::CreateFromStringForTesting("http://example/"),
+ bucket_name, kPerm);
+ ASSERT_FALSE(result.ok());
+ EXPECT_EQ(result.error(), QuotaError::kNotFound);
+}
+
+TEST_P(QuotaDatabaseTest, GetBucketById) {
+ auto db = CreateDatabase(use_in_memory_db());
+ EXPECT_TRUE(EnsureOpened(db.get()));
+
+ // Add a bucket entry into the bucket table.
+ StorageKey storage_key =
+ StorageKey::CreateFromStringForTesting("http://google/");
+ std::string bucket_name = "google_bucket";
+ QuotaErrorOr<BucketInfo> result =
+ db->CreateBucketForTesting(storage_key, bucket_name, kPerm);
+ ASSERT_TRUE(result.ok());
+
+ BucketInfo created_bucket = result.value();
+ ASSERT_GT(created_bucket.id.value(), 0);
+ ASSERT_EQ(created_bucket.name, bucket_name);
+ ASSERT_EQ(created_bucket.storage_key, storage_key);
+ ASSERT_EQ(created_bucket.type, kPerm);
+
+ result = db->GetBucketById(created_bucket.id);
+ ASSERT_TRUE(result.ok());
+ EXPECT_EQ(result.value().name, created_bucket.name);
+ EXPECT_EQ(result.value().storage_key, created_bucket.storage_key);
+ ASSERT_EQ(result.value().type, created_bucket.type);
+
+ constexpr BucketId kNonExistentBucketId(7777);
+ result = db->GetBucketById(BucketId(kNonExistentBucketId));
ASSERT_FALSE(result.ok());
EXPECT_EQ(result.error(), QuotaError::kNotFound);
}
TEST_P(QuotaDatabaseTest, GetBucketsForType) {
- QuotaDatabase db(use_in_memory_db() ? base::FilePath() : DbPath());
- EXPECT_TRUE(EnsureOpened(&db, EnsureOpenedMode::kCreateIfNotFound));
+ auto db = CreateDatabase(use_in_memory_db());
+ EXPECT_TRUE(EnsureOpened(db.get()));
const StorageKey storage_key1 =
StorageKey::CreateFromStringForTesting("http://example-a/");
@@ -327,30 +383,33 @@ TEST_P(QuotaDatabaseTest, GetBucketsForType) {
StorageKey::CreateFromStringForTesting("http://example-c/");
QuotaErrorOr<BucketInfo> bucket_result =
- db.CreateBucketForTesting(storage_key1, "temp_bucket", kTemp);
+ db->CreateBucketForTesting(storage_key1, "temp_bucket", kTemp);
ASSERT_TRUE(bucket_result.ok());
BucketInfo temp_bucket1 = bucket_result.value();
- bucket_result = db.CreateBucketForTesting(storage_key2, "temp_bucket", kTemp);
+ bucket_result =
+ db->CreateBucketForTesting(storage_key2, "temp_bucket", kTemp);
ASSERT_TRUE(bucket_result.ok());
BucketInfo temp_bucket2 = bucket_result.value();
- bucket_result = db.CreateBucketForTesting(storage_key1, "perm_bucket", kPerm);
+ bucket_result =
+ db->CreateBucketForTesting(storage_key1, "perm_bucket", kPerm);
ASSERT_TRUE(bucket_result.ok());
BucketInfo perm_bucket1 = bucket_result.value();
- bucket_result = db.CreateBucketForTesting(storage_key3, "perm_bucket", kPerm);
+ bucket_result =
+ db->CreateBucketForTesting(storage_key3, "perm_bucket", kPerm);
ASSERT_TRUE(bucket_result.ok());
BucketInfo perm_bucket2 = bucket_result.value();
- QuotaErrorOr<std::set<BucketLocator>> result = db.GetBucketsForType(kTemp);
+ QuotaErrorOr<std::set<BucketLocator>> result = db->GetBucketsForType(kTemp);
ASSERT_TRUE(result.ok());
std::set<BucketLocator> buckets = result.value();
ASSERT_EQ(2U, buckets.size());
EXPECT_TRUE(ContainsBucket(buckets, temp_bucket1));
EXPECT_TRUE(ContainsBucket(buckets, temp_bucket2));
- result = db.GetBucketsForType(kPerm);
+ result = db->GetBucketsForType(kPerm);
ASSERT_TRUE(result.ok());
buckets = result.value();
ASSERT_EQ(2U, buckets.size());
@@ -359,47 +418,47 @@ TEST_P(QuotaDatabaseTest, GetBucketsForType) {
}
TEST_P(QuotaDatabaseTest, GetBucketsForHost) {
- QuotaDatabase db(use_in_memory_db() ? base::FilePath() : DbPath());
- EXPECT_TRUE(EnsureOpened(&db, EnsureOpenedMode::kCreateIfNotFound));
+ auto db = CreateDatabase(use_in_memory_db());
+ EXPECT_TRUE(EnsureOpened(db.get()));
- QuotaErrorOr<BucketInfo> temp_example_bucket1 = db.CreateBucketForTesting(
+ QuotaErrorOr<BucketInfo> temp_example_bucket1 = db->CreateBucketForTesting(
StorageKey::CreateFromStringForTesting("https://example.com/"), "default",
kTemp);
- QuotaErrorOr<BucketInfo> temp_example_bucket2 = db.CreateBucketForTesting(
+ QuotaErrorOr<BucketInfo> temp_example_bucket2 = db->CreateBucketForTesting(
StorageKey::CreateFromStringForTesting("http://example.com:123/"),
"default", kTemp);
- QuotaErrorOr<BucketInfo> perm_google_bucket1 = db.CreateBucketForTesting(
+ QuotaErrorOr<BucketInfo> perm_google_bucket1 = db->CreateBucketForTesting(
StorageKey::CreateFromStringForTesting("http://google.com/"), "default",
kPerm);
- QuotaErrorOr<BucketInfo> temp_google_bucket2 = db.CreateBucketForTesting(
+ QuotaErrorOr<BucketInfo> temp_google_bucket2 = db->CreateBucketForTesting(
StorageKey::CreateFromStringForTesting("http://google.com:123/"),
"default", kTemp);
QuotaErrorOr<std::set<BucketLocator>> result =
- db.GetBucketsForHost("example.com", kTemp);
+ 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()));
- result = db.GetBucketsForHost("example.com", kPerm);
+ result = db->GetBucketsForHost("example.com", kPerm);
ASSERT_TRUE(result.ok());
ASSERT_EQ(result->size(), 0U);
- result = db.GetBucketsForHost("google.com", kPerm);
+ result = db->GetBucketsForHost("google.com", kPerm);
ASSERT_TRUE(result.ok());
ASSERT_EQ(result->size(), 1U);
EXPECT_TRUE(ContainsBucket(result.value(), perm_google_bucket1.value()));
- result = db.GetBucketsForHost("google.com", kTemp);
+ result = db->GetBucketsForHost("google.com", kTemp);
ASSERT_TRUE(result.ok());
ASSERT_EQ(result->size(), 1U);
EXPECT_TRUE(ContainsBucket(result.value(), temp_google_bucket2.value()));
}
TEST_P(QuotaDatabaseTest, GetBucketsForStorageKey) {
- QuotaDatabase db(use_in_memory_db() ? base::FilePath() : DbPath());
- EXPECT_TRUE(EnsureOpened(&db, EnsureOpenedMode::kCreateIfNotFound));
+ auto db = CreateDatabase(use_in_memory_db());
+ EXPECT_TRUE(EnsureOpened(db.get()));
const StorageKey storage_key1 =
StorageKey::CreateFromStringForTesting("http://example-a/");
@@ -407,84 +466,44 @@ TEST_P(QuotaDatabaseTest, GetBucketsForStorageKey) {
StorageKey::CreateFromStringForTesting("http://example-b/");
QuotaErrorOr<BucketInfo> bucket_result =
- db.CreateBucketForTesting(storage_key1, "temp_test1", kTemp);
+ db->CreateBucketForTesting(storage_key1, "temp_test1", kTemp);
ASSERT_TRUE(bucket_result.ok());
BucketInfo temp_bucket1 = bucket_result.value();
- bucket_result = db.CreateBucketForTesting(storage_key1, "temp_test2", kTemp);
+ bucket_result = db->CreateBucketForTesting(storage_key1, "temp_test2", kTemp);
ASSERT_TRUE(bucket_result.ok());
BucketInfo temp_bucket2 = bucket_result.value();
- bucket_result = db.CreateBucketForTesting(storage_key1, "perm_test", kPerm);
+ bucket_result = db->CreateBucketForTesting(storage_key1, "perm_test", kPerm);
ASSERT_TRUE(bucket_result.ok());
BucketInfo perm_bucket1 = bucket_result.value();
- bucket_result = db.CreateBucketForTesting(storage_key2, "perm_test", kPerm);
+ bucket_result = db->CreateBucketForTesting(storage_key2, "perm_test", kPerm);
ASSERT_TRUE(bucket_result.ok());
BucketInfo perm_bucket2 = bucket_result.value();
QuotaErrorOr<std::set<BucketLocator>> result =
- db.GetBucketsForStorageKey(storage_key1, kTemp);
+ db->GetBucketsForStorageKey(storage_key1, kTemp);
ASSERT_TRUE(result.ok());
std::set<BucketLocator> buckets = 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);
+ result = db->GetBucketsForStorageKey(storage_key2, kPerm);
ASSERT_TRUE(result.ok());
buckets = result.value();
ASSERT_EQ(1U, buckets.size());
EXPECT_TRUE(ContainsBucket(buckets, perm_bucket2));
}
-TEST_P(QuotaDatabaseTest, GetBucketWithNoDb) {
- QuotaDatabase db(use_in_memory_db() ? base::FilePath() : DbPath());
- EXPECT_FALSE(EnsureOpened(&db, EnsureOpenedMode::kFailIfNotFound));
-
- StorageKey storage_key =
- StorageKey::CreateFromStringForTesting("http://google/");
- std::string bucket_name = "google_bucket";
- QuotaErrorOr<BucketInfo> result =
- db.GetBucket(storage_key, bucket_name, kTemp);
- ASSERT_FALSE(result.ok());
- EXPECT_EQ(result.error(), QuotaError::kNotFound);
-}
-
-// TODO(crbug.com/1216094): Update test to have its behavior on Fuchsia/Win
-// match with other platforms, and enable test on all platforms.
-#if !BUILDFLAG(IS_FUCHSIA) && !BUILDFLAG(IS_WIN)
-TEST_F(QuotaDatabaseTest, GetBucketWithOpenDatabaseError) {
- base::HistogramTester histograms;
- sql::test::ScopedErrorExpecter expecter;
- expecter.ExpectError(SQLITE_CANTOPEN);
-
- base::ScopedTempDir temp_dir;
- ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
- QuotaDatabase db(temp_dir.GetPath());
-
- StorageKey storage_key =
- StorageKey::CreateFromStringForTesting("http://google/");
- std::string bucket_name = "google_bucket";
- QuotaErrorOr<BucketInfo> result =
- db.GetBucket(storage_key, bucket_name, kTemp);
- ASSERT_FALSE(result.ok());
- EXPECT_EQ(result.error(), QuotaError::kDatabaseError);
-
- EXPECT_TRUE(expecter.SawExpectedErrors());
- histograms.ExpectTotalCount("Quota.QuotaDatabaseReset", 1);
- histograms.ExpectBucketCount("Quota.QuotaDatabaseReset",
- DatabaseResetReason::kOpenDatabase, 1);
-}
-#endif // !BUILDFLAG(IS_FUCHSIA) && !BUILDFLAG(IS_WIN)
-
TEST_P(QuotaDatabaseTest, BucketLastAccessTimeLRU) {
- QuotaDatabase db(use_in_memory_db() ? base::FilePath() : DbPath());
- EXPECT_TRUE(EnsureOpened(&db, EnsureOpenedMode::kCreateIfNotFound));
+ auto db = CreateDatabase(use_in_memory_db());
+ EXPECT_TRUE(EnsureOpened(db.get()));
std::set<BucketId> bucket_exceptions;
QuotaErrorOr<BucketLocator> result =
- db.GetLRUBucket(kTemp, bucket_exceptions, nullptr);
+ db->GetLRUBucket(kTemp, bucket_exceptions, nullptr);
EXPECT_FALSE(result.ok());
EXPECT_EQ(result.error(), QuotaError::kNotFound);
@@ -504,25 +523,30 @@ TEST_P(QuotaDatabaseTest, BucketLastAccessTimeLRU) {
BucketId(4), StorageKey::CreateFromStringForTesting("http://example-d/"),
kPerm, "bucket_d", 5, now, now);
Entry kTableEntries[] = {bucket1, bucket2, bucket3, bucket4};
- AssignBucketTable(&db, kTableEntries);
+ AssignBucketTable(db.get(), kTableEntries);
// Update access time for three temporary storages, and
- EXPECT_EQ(db.SetBucketLastAccessTime(bucket1.bucket_id,
- base::Time::FromJavaTime(10)),
+ EXPECT_EQ(db->SetBucketLastAccessTime(bucket1.bucket_id,
+ base::Time::FromJavaTime(10)),
QuotaError::kNone);
- EXPECT_EQ(db.SetBucketLastAccessTime(bucket2.bucket_id,
- base::Time::FromJavaTime(20)),
+ EXPECT_EQ(db->SetBucketLastAccessTime(bucket2.bucket_id,
+ base::Time::FromJavaTime(20)),
QuotaError::kNone);
- EXPECT_EQ(db.SetBucketLastAccessTime(bucket3.bucket_id,
- base::Time::FromJavaTime(30)),
+ EXPECT_EQ(db->SetBucketLastAccessTime(bucket3.bucket_id,
+ base::Time::FromJavaTime(30)),
QuotaError::kNone);
- // one persistent.
- EXPECT_EQ(db.SetBucketLastAccessTime(bucket4.bucket_id,
- base::Time::FromJavaTime(40)),
+ // One persistent.
+ EXPECT_EQ(db->SetBucketLastAccessTime(bucket4.bucket_id,
+ base::Time::FromJavaTime(40)),
QuotaError::kNone);
- result = db.GetLRUBucket(kTemp, bucket_exceptions, nullptr);
+ // One non-existent.
+ EXPECT_EQ(
+ db->SetBucketLastAccessTime(BucketId(777), base::Time::FromJavaTime(40)),
+ QuotaError::kNone);
+
+ result = db->GetLRUBucket(kTemp, bucket_exceptions, nullptr);
EXPECT_TRUE(result.ok());
EXPECT_EQ(bucket1.bucket_id, result.value().id);
@@ -531,79 +555,79 @@ TEST_P(QuotaDatabaseTest, BucketLastAccessTimeLRU) {
auto policy = base::MakeRefCounted<MockSpecialStoragePolicy>();
policy->AddUnlimited(bucket1.storage_key.origin().GetURL());
policy->AddProtected(bucket2.storage_key.origin().GetURL());
- result = db.GetLRUBucket(kTemp, bucket_exceptions, policy.get());
+ result = db->GetLRUBucket(kTemp, bucket_exceptions, policy.get());
EXPECT_TRUE(result.ok());
EXPECT_EQ(bucket2.bucket_id, result.value().id);
// Test that durable origins are excluded from eviction.
policy->AddDurable(bucket2.storage_key.origin().GetURL());
- result = db.GetLRUBucket(kTemp, bucket_exceptions, policy.get());
+ result = db->GetLRUBucket(kTemp, bucket_exceptions, policy.get());
EXPECT_TRUE(result.ok());
EXPECT_EQ(bucket3.bucket_id, result.value().id);
// Bucket exceptions exclude specified buckets.
bucket_exceptions.insert(bucket1.bucket_id);
- result = db.GetLRUBucket(kTemp, bucket_exceptions, nullptr);
+ result = db->GetLRUBucket(kTemp, bucket_exceptions, nullptr);
EXPECT_TRUE(result.ok());
EXPECT_EQ(bucket2.bucket_id, result.value().id);
bucket_exceptions.insert(bucket2.bucket_id);
- result = db.GetLRUBucket(kTemp, bucket_exceptions, nullptr);
+ result = db->GetLRUBucket(kTemp, bucket_exceptions, nullptr);
EXPECT_TRUE(result.ok());
EXPECT_EQ(bucket3.bucket_id, result.value().id);
bucket_exceptions.insert(bucket3.bucket_id);
- result = db.GetLRUBucket(kTemp, bucket_exceptions, nullptr);
+ result = db->GetLRUBucket(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(bucket1.bucket_id, base::Time::Now()),
QuotaError::kNone);
// Delete storage_key/type last access time information.
- EXPECT_EQ(db.DeleteBucketInfo(bucket3.bucket_id), QuotaError::kNone);
+ EXPECT_EQ(db->DeleteBucketInfo(bucket3.bucket_id), QuotaError::kNone);
// Querying again to see if the deletion has worked.
bucket_exceptions.clear();
- result = db.GetLRUBucket(kTemp, bucket_exceptions, nullptr);
+ result = db->GetLRUBucket(kTemp, bucket_exceptions, nullptr);
EXPECT_TRUE(result.ok());
EXPECT_EQ(bucket2.bucket_id, result.value().id);
bucket_exceptions.insert(bucket1.bucket_id);
bucket_exceptions.insert(bucket2.bucket_id);
- result = db.GetLRUBucket(kTemp, bucket_exceptions, nullptr);
+ result = db->GetLRUBucket(kTemp, bucket_exceptions, nullptr);
EXPECT_FALSE(result.ok());
EXPECT_EQ(result.error(), QuotaError::kNotFound);
}
TEST_P(QuotaDatabaseTest, SetStorageKeyLastAccessTime) {
- QuotaDatabase db(use_in_memory_db() ? base::FilePath() : DbPath());
- EXPECT_TRUE(EnsureOpened(&db, EnsureOpenedMode::kCreateIfNotFound));
+ auto db = CreateDatabase(use_in_memory_db());
+ EXPECT_TRUE(EnsureOpened(db.get()));
const StorageKey storage_key =
StorageKey::CreateFromStringForTesting("http://example/");
base::Time now = base::Time::Now();
- // Should error if bucket doesn't exist.
- EXPECT_EQ(db.SetStorageKeyLastAccessTime(storage_key, kTemp, now),
- QuotaError::kNotFound);
+ // Doesn't error if bucket doesn't exist.
+ EXPECT_EQ(db->SetStorageKeyLastAccessTime(storage_key, kTemp, now),
+ QuotaError::kNone);
QuotaErrorOr<BucketInfo> bucket =
- db.CreateBucketForTesting(storage_key, kDefaultBucketName, kTemp);
+ db->CreateBucketForTesting(storage_key, kDefaultBucketName, kTemp);
- EXPECT_EQ(db.SetStorageKeyLastAccessTime(storage_key, kTemp, now),
+ EXPECT_EQ(db->SetStorageKeyLastAccessTime(storage_key, kTemp, now),
QuotaError::kNone);
QuotaErrorOr<QuotaDatabase::BucketTableEntry> info =
- db.GetBucketInfo(bucket->id);
+ db->GetBucketInfo(bucket->id);
EXPECT_TRUE(info.ok());
EXPECT_EQ(now, info->last_accessed);
EXPECT_EQ(1, info->use_count);
}
TEST_P(QuotaDatabaseTest, GetStorageKeysForType) {
- QuotaDatabase db(use_in_memory_db() ? base::FilePath() : DbPath());
- EXPECT_TRUE(EnsureOpened(&db, EnsureOpenedMode::kCreateIfNotFound));
+ auto db = CreateDatabase(use_in_memory_db());
+ EXPECT_TRUE(EnsureOpened(db.get()));
const StorageKey storage_key1 =
StorageKey::CreateFromStringForTesting("http://example-a/");
@@ -612,18 +636,18 @@ TEST_P(QuotaDatabaseTest, GetStorageKeysForType) {
const StorageKey storage_key3 =
StorageKey::CreateFromStringForTesting("http://example-c/");
- db.CreateBucketForTesting(storage_key1, "bucket_a", kTemp);
- db.CreateBucketForTesting(storage_key2, "bucket_b", kTemp);
- db.CreateBucketForTesting(storage_key2, "bucket_b", kPerm);
- db.CreateBucketForTesting(storage_key3, "bucket_c", kPerm);
+ db->CreateBucketForTesting(storage_key1, "bucket_a", kTemp);
+ db->CreateBucketForTesting(storage_key2, "bucket_b", kTemp);
+ db->CreateBucketForTesting(storage_key2, "bucket_b", kPerm);
+ db->CreateBucketForTesting(storage_key3, "bucket_c", kPerm);
- QuotaErrorOr<std::set<StorageKey>> result = db.GetStorageKeysForType(kTemp);
+ QuotaErrorOr<std::set<StorageKey>> result = db->GetStorageKeysForType(kTemp);
ASSERT_TRUE(result.ok());
ASSERT_TRUE(base::Contains(result.value(), storage_key1));
ASSERT_TRUE(base::Contains(result.value(), storage_key2));
ASSERT_FALSE(base::Contains(result.value(), storage_key3));
- result = db.GetStorageKeysForType(kPerm);
+ result = db->GetStorageKeysForType(kPerm);
ASSERT_TRUE(result.ok());
ASSERT_FALSE(base::Contains(result.value(), storage_key1));
ASSERT_TRUE(base::Contains(result.value(), storage_key2));
@@ -631,31 +655,31 @@ TEST_P(QuotaDatabaseTest, GetStorageKeysForType) {
}
TEST_P(QuotaDatabaseTest, BucketLastModifiedBetween) {
- QuotaDatabase db(use_in_memory_db() ? base::FilePath() : DbPath());
- EXPECT_TRUE(EnsureOpened(&db, EnsureOpenedMode::kCreateIfNotFound));
+ auto db = CreateDatabase(use_in_memory_db());
+ EXPECT_TRUE(EnsureOpened(db.get()));
QuotaErrorOr<std::set<BucketLocator>> result =
- db.GetBucketsModifiedBetween(kTemp, base::Time(), base::Time::Max());
+ db->GetBucketsModifiedBetween(kTemp, base::Time(), base::Time::Max());
EXPECT_TRUE(result.ok());
std::set<BucketLocator> buckets = result.value();
EXPECT_TRUE(buckets.empty());
- QuotaErrorOr<BucketInfo> result1 = db.CreateBucketForTesting(
+ QuotaErrorOr<BucketInfo> result1 = db->CreateBucketForTesting(
StorageKey::CreateFromStringForTesting("http://example-a/"), "bucket_a",
kTemp);
EXPECT_TRUE(result1.ok());
BucketInfo bucket1 = result1.value();
- QuotaErrorOr<BucketInfo> result2 = db.CreateBucketForTesting(
+ QuotaErrorOr<BucketInfo> result2 = db->CreateBucketForTesting(
StorageKey::CreateFromStringForTesting("http://example-b/"), "bucket_b",
kTemp);
EXPECT_TRUE(result2.ok());
BucketInfo bucket2 = result2.value();
- QuotaErrorOr<BucketInfo> result3 = db.CreateBucketForTesting(
+ QuotaErrorOr<BucketInfo> result3 = db->CreateBucketForTesting(
StorageKey::CreateFromStringForTesting("http://example-c/"), "bucket_c",
kTemp);
EXPECT_TRUE(result3.ok());
BucketInfo bucket3 = result3.value();
- QuotaErrorOr<BucketInfo> result4 = db.CreateBucketForTesting(
+ QuotaErrorOr<BucketInfo> result4 = db->CreateBucketForTesting(
StorageKey::CreateFromStringForTesting("http://example-d/"), "bucket_d",
kPerm);
EXPECT_TRUE(result4.ok());
@@ -663,19 +687,25 @@ TEST_P(QuotaDatabaseTest, BucketLastModifiedBetween) {
// Report last modified time for the buckets.
EXPECT_EQ(
- db.SetBucketLastModifiedTime(bucket1.id, base::Time::FromJavaTime(0)),
+ db->SetBucketLastModifiedTime(bucket1.id, base::Time::FromJavaTime(0)),
QuotaError::kNone);
EXPECT_EQ(
- db.SetBucketLastModifiedTime(bucket2.id, base::Time::FromJavaTime(10)),
+ db->SetBucketLastModifiedTime(bucket2.id, base::Time::FromJavaTime(10)),
QuotaError::kNone);
EXPECT_EQ(
- db.SetBucketLastModifiedTime(bucket3.id, base::Time::FromJavaTime(20)),
+ db->SetBucketLastModifiedTime(bucket3.id, base::Time::FromJavaTime(20)),
QuotaError::kNone);
EXPECT_EQ(
- db.SetBucketLastModifiedTime(bucket4.id, base::Time::FromJavaTime(30)),
+ db->SetBucketLastModifiedTime(bucket4.id, base::Time::FromJavaTime(30)),
QuotaError::kNone);
- result = db.GetBucketsModifiedBetween(kTemp, base::Time(), base::Time::Max());
+ // Non-existent bucket.
+ EXPECT_EQ(
+ db->SetBucketLastModifiedTime(BucketId(777), base::Time::FromJavaTime(0)),
+ QuotaError::kNone);
+
+ result =
+ db->GetBucketsModifiedBetween(kTemp, base::Time(), base::Time::Max());
EXPECT_TRUE(result.ok());
buckets = result.value();
EXPECT_EQ(3U, buckets.size());
@@ -684,8 +714,8 @@ TEST_P(QuotaDatabaseTest, BucketLastModifiedBetween) {
EXPECT_TRUE(ContainsBucket(buckets, bucket3));
EXPECT_FALSE(ContainsBucket(buckets, bucket4));
- result = db.GetBucketsModifiedBetween(kTemp, base::Time::FromJavaTime(5),
- base::Time::Max());
+ result = db->GetBucketsModifiedBetween(kTemp, base::Time::FromJavaTime(5),
+ base::Time::Max());
EXPECT_TRUE(result.ok());
buckets = result.value();
EXPECT_EQ(2U, buckets.size());
@@ -694,8 +724,8 @@ TEST_P(QuotaDatabaseTest, BucketLastModifiedBetween) {
EXPECT_TRUE(ContainsBucket(buckets, bucket3));
EXPECT_FALSE(ContainsBucket(buckets, bucket4));
- result = db.GetBucketsModifiedBetween(kTemp, base::Time::FromJavaTime(15),
- base::Time::Max());
+ result = db->GetBucketsModifiedBetween(kTemp, base::Time::FromJavaTime(15),
+ base::Time::Max());
EXPECT_TRUE(result.ok());
buckets = result.value();
EXPECT_EQ(1U, buckets.size());
@@ -704,14 +734,14 @@ TEST_P(QuotaDatabaseTest, BucketLastModifiedBetween) {
EXPECT_TRUE(ContainsBucket(buckets, bucket3));
EXPECT_FALSE(ContainsBucket(buckets, bucket4));
- result = db.GetBucketsModifiedBetween(kTemp, base::Time::FromJavaTime(25),
- base::Time::Max());
+ result = db->GetBucketsModifiedBetween(kTemp, base::Time::FromJavaTime(25),
+ base::Time::Max());
EXPECT_TRUE(result.ok());
buckets = result.value();
EXPECT_TRUE(buckets.empty());
- result = db.GetBucketsModifiedBetween(kTemp, base::Time::FromJavaTime(5),
- base::Time::FromJavaTime(15));
+ result = db->GetBucketsModifiedBetween(kTemp, base::Time::FromJavaTime(5),
+ base::Time::FromJavaTime(15));
EXPECT_TRUE(result.ok());
buckets = result.value();
EXPECT_EQ(1U, buckets.size());
@@ -720,8 +750,8 @@ TEST_P(QuotaDatabaseTest, BucketLastModifiedBetween) {
EXPECT_FALSE(ContainsBucket(buckets, bucket3));
EXPECT_FALSE(ContainsBucket(buckets, bucket4));
- result = db.GetBucketsModifiedBetween(kTemp, base::Time::FromJavaTime(0),
- base::Time::FromJavaTime(20));
+ result = db->GetBucketsModifiedBetween(kTemp, base::Time::FromJavaTime(0),
+ base::Time::FromJavaTime(20));
EXPECT_TRUE(result.ok());
buckets = result.value();
EXPECT_EQ(2U, buckets.size());
@@ -730,8 +760,8 @@ TEST_P(QuotaDatabaseTest, BucketLastModifiedBetween) {
EXPECT_FALSE(ContainsBucket(buckets, bucket3));
EXPECT_FALSE(ContainsBucket(buckets, bucket4));
- result = db.GetBucketsModifiedBetween(kPerm, base::Time::FromJavaTime(0),
- base::Time::FromJavaTime(35));
+ result = db->GetBucketsModifiedBetween(kPerm, base::Time::FromJavaTime(0),
+ base::Time::FromJavaTime(35));
EXPECT_TRUE(result.ok());
buckets = result.value();
EXPECT_EQ(1U, buckets.size());
@@ -742,7 +772,7 @@ TEST_P(QuotaDatabaseTest, BucketLastModifiedBetween) {
}
TEST_P(QuotaDatabaseTest, RegisterInitialStorageKeyInfo) {
- QuotaDatabase db(use_in_memory_db() ? base::FilePath() : DbPath());
+ auto db = CreateDatabase(use_in_memory_db());
base::flat_map<blink::mojom::StorageType, std::set<StorageKey>>
storage_keys_by_type;
@@ -755,54 +785,35 @@ TEST_P(QuotaDatabaseTest, RegisterInitialStorageKeyInfo) {
storage_keys_by_type.emplace(
kPerm, std::set<StorageKey>(kStorageKeys, std::end(kStorageKeys)));
- EXPECT_EQ(db.RegisterInitialStorageKeyInfo(storage_keys_by_type),
+ EXPECT_EQ(db->RegisterInitialStorageKeyInfo(storage_keys_by_type),
QuotaError::kNone);
QuotaErrorOr<BucketInfo> bucket_result =
- db.GetBucket(StorageKey::CreateFromStringForTesting("http://a/"),
- kDefaultBucketName, kTemp);
+ db->GetBucket(StorageKey::CreateFromStringForTesting("http://a/"),
+ kDefaultBucketName, kTemp);
ASSERT_TRUE(bucket_result.ok());
QuotaErrorOr<QuotaDatabase::BucketTableEntry> info =
- db.GetBucketInfo(bucket_result->id);
+ db->GetBucketInfo(bucket_result->id);
EXPECT_TRUE(info.ok());
EXPECT_EQ(0, info->use_count);
- EXPECT_EQ(db.SetStorageKeyLastAccessTime(
+ EXPECT_EQ(db->SetStorageKeyLastAccessTime(
StorageKey::CreateFromStringForTesting("http://a/"), kTemp,
base::Time::FromDoubleT(1.0)),
QuotaError::kNone);
- info = db.GetBucketInfo(bucket_result->id);
+ info = db->GetBucketInfo(bucket_result->id);
EXPECT_TRUE(info.ok());
EXPECT_EQ(1, info->use_count);
- EXPECT_EQ(db.RegisterInitialStorageKeyInfo(storage_keys_by_type),
+ EXPECT_EQ(db->RegisterInitialStorageKeyInfo(storage_keys_by_type),
QuotaError::kNone);
- info = db.GetBucketInfo(bucket_result->id);
+ info = db->GetBucketInfo(bucket_result->id);
EXPECT_TRUE(info.ok());
EXPECT_EQ(1, info->use_count);
}
-TEST_P(QuotaDatabaseTest, DumpQuotaTable) {
- QuotaTableEntry kTableEntries[] = {
- {.host = "http://go/", .type = kTemp, .quota = 1},
- {.host = "http://oo/", .type = kTemp, .quota = 2},
- {.host = "http://gle/", .type = kPerm, .quota = 3}};
-
- QuotaDatabase db(use_in_memory_db() ? base::FilePath() : DbPath());
- EXPECT_TRUE(EnsureOpened(&db, EnsureOpenedMode::kCreateIfNotFound));
- AssignQuotaTable(&db, kTableEntries);
-
- using Verifier = EntryVerifier<QuotaTableEntry>;
- Verifier verifier(kTableEntries, std::end(kTableEntries));
- EXPECT_EQ(
- DumpQuotaTable(&db, base::BindRepeating(&Verifier::Run,
- base::Unretained(&verifier))),
- QuotaError::kNone);
- EXPECT_TRUE(verifier.table.empty());
-}
-
TEST_P(QuotaDatabaseTest, DumpBucketTable) {
base::Time now = base::Time::Now();
using Entry = QuotaDatabase::BucketTableEntry;
@@ -815,16 +826,16 @@ TEST_P(QuotaDatabaseTest, DumpBucketTable) {
kTemp, kDefaultBucketName, 1, now, now),
};
- QuotaDatabase db(use_in_memory_db() ? base::FilePath() : DbPath());
- EXPECT_TRUE(EnsureOpened(&db, EnsureOpenedMode::kCreateIfNotFound));
- AssignBucketTable(&db, kTableEntries);
+ auto db = CreateDatabase(use_in_memory_db());
+ EXPECT_TRUE(EnsureOpened(db.get()));
+ AssignBucketTable(db.get(), kTableEntries);
using Verifier = EntryVerifier<Entry>;
Verifier verifier(kTableEntries, std::end(kTableEntries));
- EXPECT_EQ(
- DumpBucketTable(&db, base::BindRepeating(&Verifier::Run,
- base::Unretained(&verifier))),
- QuotaError::kNone);
+ EXPECT_EQ(DumpBucketTable(db.get(),
+ base::BindRepeating(&Verifier::Run,
+ base::Unretained(&verifier))),
+ QuotaError::kNone);
EXPECT_TRUE(verifier.table.empty());
}
@@ -834,13 +845,13 @@ TEST_P(QuotaDatabaseTest, GetBucketInfo) {
Entry(BucketId(123), StorageKey::CreateFromStringForTesting("http://go/"),
kTemp, "test_bucket", 100, base::Time(), base::Time())};
- QuotaDatabase db(use_in_memory_db() ? base::FilePath() : DbPath());
- EXPECT_TRUE(EnsureOpened(&db, EnsureOpenedMode::kCreateIfNotFound));
- AssignBucketTable(&db, kTableEntries);
+ 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);
+ db->GetBucketInfo(kTableEntries[0].bucket_id);
EXPECT_TRUE(entry.ok());
EXPECT_EQ(kTableEntries[0].bucket_id, entry->bucket_id);
EXPECT_EQ(kTableEntries[0].type, entry->type);
@@ -854,37 +865,47 @@ TEST_P(QuotaDatabaseTest, GetBucketInfo) {
{
// BucketId 456 is not in the database.
QuotaErrorOr<QuotaDatabase::BucketTableEntry> entry =
- db.GetBucketInfo(BucketId(456));
+ db->GetBucketInfo(BucketId(456));
EXPECT_FALSE(entry.ok());
}
}
// Non-parameterized tests.
TEST_F(QuotaDatabaseTest, BootstrapFlag) {
- QuotaDatabase db(DbPath());
+ auto db = CreateDatabase(/*is_incognito=*/false);
- EXPECT_FALSE(db.IsBootstrapped());
- EXPECT_EQ(db.SetIsBootstrapped(true), QuotaError::kNone);
- EXPECT_TRUE(db.IsBootstrapped());
- EXPECT_EQ(db.SetIsBootstrapped(false), QuotaError::kNone);
- EXPECT_FALSE(db.IsBootstrapped());
+ EXPECT_FALSE(db->IsBootstrapped());
+ EXPECT_EQ(db->SetIsBootstrapped(true), QuotaError::kNone);
+ EXPECT_TRUE(db->IsBootstrapped());
+ EXPECT_EQ(db->SetIsBootstrapped(false), QuotaError::kNone);
+ EXPECT_FALSE(db->IsBootstrapped());
}
TEST_F(QuotaDatabaseTest, OpenCorruptedDatabase) {
base::HistogramTester histograms;
// Create database, force corruption and close db by leaving scope.
{
- QuotaDatabase db(DbPath());
- ASSERT_TRUE(EnsureOpened(&db, EnsureOpenedMode::kCreateIfNotFound));
+ auto db = CreateDatabase(/*is_incognito=*/false);
+ ASSERT_TRUE(EnsureOpened(db.get()));
ASSERT_TRUE(sql::test::CorruptSizeInHeader(DbPath()));
+
+ // Add fake data into storage directory.
+ base::FilePath storage_path = db->GetStoragePath();
+ ASSERT_TRUE(base::CreateDirectory(storage_path));
+ ASSERT_TRUE(base::WriteFile(storage_path.AppendASCII("FakeStorage"),
+ "dummy_content"));
}
// Reopen database and verify schema reset on reopen.
{
sql::test::ScopedErrorExpecter expecter;
expecter.ExpectError(SQLITE_CORRUPT);
- QuotaDatabase db(DbPath());
- ASSERT_TRUE(EnsureOpened(&db, EnsureOpenedMode::kFailIfNotFound));
+ auto db = CreateDatabase(/*is_incognito=*/false);
+ ASSERT_TRUE(EnsureOpened(db.get()));
EXPECT_TRUE(expecter.SawExpectedErrors());
+
+ // Ensure data is deleted.
+ base::FilePath storage_path = db->GetStoragePath();
+ EXPECT_FALSE(base::IsDirectoryEmpty(storage_path));
}
histograms.ExpectTotalCount("Quota.QuotaDatabaseReset", 1);
@@ -897,8 +918,105 @@ TEST_F(QuotaDatabaseTest, OpenCorruptedDatabase) {
1);
}
+TEST_F(QuotaDatabaseTest, QuotaDatabasePathMigration) {
+ const base::FilePath kLegacyFilePath =
+ ProfilePath().AppendASCII(kDatabaseName);
+ const StorageKey kStorageKey =
+ StorageKey::CreateFromStringForTesting("http://google/");
+ const std::string kBucketName = "google_bucket";
+ // Create database, add bucket and close by leaving scope.
+ {
+ auto db = CreateDatabase(/*is_incognito=*/false);
+ auto result = db->GetOrCreateBucket(kStorageKey, kBucketName);
+ ASSERT_TRUE(result.ok());
+ }
+ // Move db file paths to legacy file path for path migration test setup.
+ {
+ base::Move(DbPath(), kLegacyFilePath);
+ base::Move(sql::Database::JournalPath(DbPath()),
+ sql::Database::JournalPath(kLegacyFilePath));
+ }
+ // Reopen database, check that db is migrated to new path with bucket data.
+ {
+ auto db = CreateDatabase(/*is_incognito=*/false);
+ auto result = db->GetBucket(kStorageKey, kBucketName, kTemp);
+ EXPECT_TRUE(result.ok());
+ EXPECT_FALSE(base::PathExists(kLegacyFilePath));
+ EXPECT_TRUE(base::PathExists(DbPath()));
+ }
+}
+
+// Test for crbug.com/1316581.
+TEST_F(QuotaDatabaseTest, QuotaDatabasePathBadMigration) {
+ const base::FilePath kLegacyFilePath =
+ ProfilePath().AppendASCII(kDatabaseName);
+ const StorageKey kStorageKey =
+ StorageKey::CreateFromStringForTesting("http://google/");
+ const std::string kBucketName = "google_bucket";
+ // Create database, add bucket and close by leaving scope.
+ {
+ auto db = CreateDatabase(/*is_incognito=*/false);
+ auto result = db->GetOrCreateBucket(kStorageKey, kBucketName);
+ ASSERT_TRUE(result.ok());
+ }
+ // Copy db file paths to legacy file path to mimic bad migration state.
+ base::CopyFile(DbPath(), kLegacyFilePath);
+
+ // Reopen database, check that db is migrated and is in a good state.
+ {
+ auto db = CreateDatabase(/*is_incognito=*/false);
+ auto result = db->GetBucket(kStorageKey, kBucketName, kTemp);
+ EXPECT_TRUE(result.ok());
+ EXPECT_TRUE(base::PathExists(DbPath()));
+ }
+}
+
+// Test for crbug.com/1322375.
+//
+// base::CreateDirectory behaves differently on Mac and allows directory
+// migration to succeed when we expect failure.
+#if !BUILDFLAG(IS_MAC)
+TEST_F(QuotaDatabaseTest, QuotaDatabaseDirectoryMigrationError) {
+ const base::FilePath kLegacyFilePath =
+ ProfilePath().AppendASCII(kDatabaseName);
+ const StorageKey kGoogleStorageKey =
+ StorageKey::CreateFromStringForTesting("http://google/");
+ const StorageKey kExampleStorageKey =
+ StorageKey::CreateFromStringForTesting("http://example/");
+ BucketId example_id;
+ // Create database, add bucket and close by leaving scope.
+ {
+ auto db = CreateDatabase(/*is_incognito=*/false);
+ // Create two buckets to check that ids are different after database reset.
+ auto result = db->GetOrCreateBucket(kGoogleStorageKey, kDefaultBucketName);
+ ASSERT_TRUE(result.ok());
+ result = db->GetOrCreateBucket(kExampleStorageKey, kDefaultBucketName);
+ ASSERT_TRUE(result.ok());
+ example_id = result->id;
+ }
+ {
+ // Delete database files to force a bad migration state.
+ base::DeleteFile(DbPath());
+ base::DeleteFile(sql::Database::JournalPath(DbPath()));
+
+ // Create a directory with the database file path to force directory
+ // migration to fail.
+ base::CreateDirectory(kLegacyFilePath);
+ }
+ {
+ // Open database to trigger migration. Migration failure forces a database
+ // reset.
+ auto db = CreateDatabase(/*is_incognito=*/false);
+ auto result = db->GetOrCreateBucket(kExampleStorageKey, kDefaultBucketName);
+ ASSERT_TRUE(result.ok());
+ // Validate database reset by checking that bucket id doesn't match.
+ EXPECT_NE(result->id, example_id);
+ }
+}
+#endif // !BUILDFLAG(IS_MAC)
+
TEST_F(QuotaDatabaseTest, GetOrCreateBucket_CorruptedDatabase) {
- QuotaDatabase db(DbPath());
+ QuotaDatabase db(ProfilePath());
StorageKey storage_key =
StorageKey::CreateFromStringForTesting("http://google/");
std::string bucket_name = "google_bucket";
diff --git a/chromium/storage/browser/quota/quota_features.cc b/chromium/storage/browser/quota/quota_features.cc
index 4d6dee2ee72..c2cb26451d9 100644
--- a/chromium/storage/browser/quota/quota_features.cc
+++ b/chromium/storage/browser/quota/quota_features.cc
@@ -42,7 +42,7 @@ constexpr base::FeatureParam<double> kShouldRemainAvailableRatio{
// Whether the StoragePolicyObserver only sends updates for modified origins.
const base::Feature kOnlySendStoragePolicyUpdatesForModifiedOrigins{
"OnlySendStoragePolicyUpdatesForModifiedOrigins",
- base::FEATURE_DISABLED_BY_DEFAULT};
+ base::FEATURE_ENABLED_BY_DEFAULT};
} // namespace features
} // namespace storage
diff --git a/chromium/storage/browser/quota/quota_internals.mojom b/chromium/storage/browser/quota/quota_internals.mojom
index 226b34d91b7..fc6b351ca57 100644
--- a/chromium/storage/browser/quota/quota_internals.mojom
+++ b/chromium/storage/browser/quota/quota_internals.mojom
@@ -4,10 +4,31 @@
module storage.mojom;
+import "mojo/public/mojom/base/time.mojom";
import "url/mojom/origin.mojom";
+// Represents a single Storage Bucket entry.
+struct BucketTableEntry {
+ int64 bucket_id;
+ string storage_key;
+ string host;
+ string type;
+ string name;
+ int64 use_count;
+ mojo_base.mojom.Time last_accessed;
+ mojo_base.mojom.Time last_modified;
+};
+
+// Represents the Storage Type for a given host.
+// This is a subset of blink::mojom::StorageType.
+enum StorageType {
+ kTemporary = 0,
+ kPersistent = 1,
+ kSyncable = 2,
+};
+
// Interface for controlling Quota Internals.
-// Hosted on chrome://quota-internals" for WebUI content::QuotaInternalsUI.
+// Hosted on "chrome://quota-internals" for WebUI content::QuotaInternalsUI.
interface QuotaInternalsHandler {
// Returns the total and available disk space in bits for a user,
// which is then converted to bytes and displayed on the Quota Internals UI.
@@ -21,4 +42,15 @@ interface QuotaInternalsHandler {
// Used by the quota-internals page to test behavior of the storage pressure
// callback and trigger a storage pressure notification.
SimulateStoragePressure(url.mojom.Origin origin_url);
+
+ // 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);
}; \ No newline at end of file
diff --git a/chromium/storage/browser/quota/quota_manager_impl.cc b/chromium/storage/browser/quota/quota_manager_impl.cc
index cada5f89dd9..f58e4f1b4f4 100644
--- a/chromium/storage/browser/quota/quota_manager_impl.cc
+++ b/chromium/storage/browser/quota/quota_manager_impl.cc
@@ -8,6 +8,7 @@
#include <stdint.h>
#include <algorithm>
+#include <cstdint>
#include <functional>
#include <limits>
#include <memory>
@@ -16,6 +17,7 @@
#include "base/barrier_closure.h"
#include "base/bind.h"
#include "base/callback.h"
+#include "base/callback_forward.h"
#include "base/callback_helpers.h"
#include "base/command_line.h"
#include "base/containers/contains.h"
@@ -31,7 +33,6 @@
#include "base/strings/strcat.h"
#include "base/strings/string_number_conversions.h"
#include "base/system/sys_info.h"
-#include "base/task/post_task.h"
#include "base/task/sequenced_task_runner.h"
#include "base/task/single_thread_task_runner.h"
#include "base/task/task_runner_util.h"
@@ -47,6 +48,7 @@
#include "components/services/storage/public/mojom/quota_client.mojom.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "storage/browser/quota/client_usage_tracker.h"
+#include "storage/browser/quota/quota_callbacks.h"
#include "storage/browser/quota/quota_client_type.h"
#include "storage/browser/quota/quota_features.h"
#include "storage/browser/quota/quota_macros.h"
@@ -100,152 +102,30 @@ bool IsSupportedIncognitoType(StorageType type) {
return type == StorageType::kTemporary || type == StorageType::kPersistent;
}
-QuotaErrorOr<BucketInfo> GetOrCreateBucketOnDBThread(
- const StorageKey& storage_key,
- const std::string& bucket_name,
- QuotaDatabase* database) {
- DCHECK(database);
- return database->GetOrCreateBucket(storage_key, bucket_name);
-}
-
-QuotaErrorOr<BucketInfo> GetOrCreateBucketDeprecatedOnDBThread(
- const StorageKey& storage_key,
- const std::string& bucket_name,
- blink::mojom::StorageType storage_type,
- QuotaDatabase* database) {
- DCHECK(database);
- return database->GetOrCreateBucketDeprecated(storage_key, bucket_name,
- storage_type);
-}
-
-QuotaErrorOr<BucketInfo> CreateBucketOnDBThread(
- const StorageKey& storage_key,
- const std::string& bucket_name,
- blink::mojom::StorageType storage_type,
- QuotaDatabase* database) {
- DCHECK(database);
- return database->CreateBucketForTesting(storage_key, bucket_name, // IN-TEST
- storage_type);
-}
-
-QuotaErrorOr<BucketInfo> GetBucketOnDBThread(const StorageKey& storage_key,
- const std::string& bucket_name,
- blink::mojom::StorageType type,
- QuotaDatabase* database) {
- DCHECK(database);
- return database->GetBucket(storage_key, bucket_name, type);
-}
-
-QuotaErrorOr<std::set<StorageKey>> GetStorageKeysForTypeOnDBThread(
- StorageType type,
- QuotaDatabase* database) {
- DCHECK(database);
- return database->GetStorageKeysForType(type);
-}
-
-QuotaErrorOr<std::set<BucketLocator>> GetBucketsForTypeOnDBThread(
- StorageType type,
- QuotaDatabase* database) {
- DCHECK(database);
- return database->GetBucketsForType(type);
-}
-
-QuotaErrorOr<std::set<BucketLocator>> GetBucketsForHostOnDBThread(
- const std::string& host,
- StorageType type,
- QuotaDatabase* database) {
- DCHECK(database);
- return database->GetBucketsForHost(host, type);
-}
-
-QuotaErrorOr<std::set<BucketLocator>> GetBucketsForStorageKeyOnDBThread(
- const StorageKey& storage_key,
- StorageType type,
- QuotaDatabase* database) {
- DCHECK(database);
- return database->GetBucketsForStorageKey(storage_key, type);
-}
-
-QuotaErrorOr<std::set<BucketLocator>> GetModifiedBetweenOnDBThread(
- StorageType type,
- base::Time begin,
- base::Time end,
- QuotaDatabase* database) {
- DCHECK(database);
- return database->GetBucketsModifiedBetween(type, begin, end);
-}
-
-QuotaErrorOr<int64_t> GetPersistentHostQuotaOnDBThread(
- const std::string& host,
- QuotaDatabase* database) {
- DCHECK(database);
- return database->GetHostQuota(host, StorageType::kPersistent);
-}
-
-QuotaError SetPersistentHostQuotaOnDBThread(const std::string& host,
- int64_t* new_quota,
- QuotaDatabase* database) {
- DCHECK(database);
- return database->SetHostQuota(host, StorageType::kPersistent, *new_quota);
-}
-
-QuotaError SetDatabaseBootstrappedOnDBThread(QuotaDatabase* database) {
- DCHECK(database);
- return database->SetIsBootstrapped(true);
-}
-
-QuotaErrorOr<BucketLocator> GetLRUBucketOnDBThread(
- StorageType type,
- const std::set<BucketId>& bucket_exceptions,
- SpecialStoragePolicy* policy,
- QuotaDatabase* database) {
- DCHECK(database);
- return database->GetLRUBucket(type, bucket_exceptions, policy);
-}
-
-QuotaError DeleteBucketInfoOnDBThread(BucketId bucket_id,
- QuotaDatabase* database) {
- DCHECK(database);
- return database->DeleteBucketInfo(bucket_id);
-}
-
-QuotaErrorOr<QuotaDatabase::BucketTableEntry>
-GetBucketInfoForEvictionOnDBThread(BucketId bucket_id,
- QuotaDatabase* database) {
- DCHECK(database);
- return database->GetBucketInfo(bucket_id);
-}
-
-QuotaError BootstrapDatabaseOnDBThread(
- base::flat_map<StorageType, std::set<StorageKey>> storage_keys_by_type,
- QuotaDatabase* database) {
- DCHECK(database);
- // Register existing storage keys with 0 last time access.
- return database->RegisterInitialStorageKeyInfo(
- std::move(storage_keys_by_type));
-}
-
-QuotaError UpdateAccessTimeOnDBThread(const StorageKey& storage_key,
- StorageType type,
- base::Time accessed_time,
- QuotaDatabase* database) {
- DCHECK(database);
- return database->SetStorageKeyLastAccessTime(storage_key, type,
- accessed_time);
-}
-
-QuotaError UpdateBucketAccessTimeOnDBThread(BucketId bucket_id,
- base::Time accessed_time,
- QuotaDatabase* database) {
- DCHECK(database);
- return database->SetBucketLastAccessTime(bucket_id, accessed_time);
+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";
+ }
}
-QuotaError UpdateBucketModifiedTimeOnDBThread(BucketId bucket_id,
- base::Time modified_time,
- QuotaDatabase* database) {
- DCHECK(database);
- return database->SetBucketLastModifiedTime(bucket_id, modified_time);
+StorageType GetBlinkStorageType(storage::mojom::StorageType type) {
+ switch (type) {
+ case storage::mojom::StorageType::kTemporary:
+ return StorageType::kTemporary;
+ case storage::mojom::StorageType::kPersistent:
+ return StorageType::kPersistent;
+ case storage::mojom::StorageType::kSyncable:
+ return StorageType::kSyncable;
+ }
}
void DidGetUsageAndQuotaStripBreakdown(
@@ -1075,43 +955,7 @@ class QuotaManagerImpl::StorageCleanupHelper : public QuotaTask {
// Gather storage key info table for quota-internals page.
//
// This class is granted ownership of itself when it is passed to
-// DidDumpQuotaTable() via base::Owned(). When the closure for said function
-// goes out of scope, the object is deleted.
-// This class is not thread-safe because there can be a race when entries_ is
-// modified.
-class QuotaManagerImpl::DumpQuotaTableHelper {
- public:
- QuotaError DumpQuotaTableOnDBThread(QuotaDatabase* database) {
- DCHECK(database);
- return database->DumpQuotaTable(base::BindRepeating(
- &DumpQuotaTableHelper::AppendEntry, base::Unretained(this)));
- }
-
- void DidDumpQuotaTable(const base::WeakPtr<QuotaManagerImpl>& manager,
- DumpQuotaTableCallback callback,
- QuotaError error) {
- if (!manager) {
- // The operation was aborted.
- std::move(callback).Run(QuotaTableEntries());
- return;
- }
- manager->DidDatabaseWork(error != QuotaError::kDatabaseError);
- std::move(callback).Run(entries_);
- }
-
- private:
- bool AppendEntry(const QuotaTableEntry& entry) {
- entries_.push_back(entry);
- return true;
- }
-
- QuotaTableEntries entries_;
-};
-
-// Gather storage key info table for quota-internals page.
-//
-// This class is granted ownership of itself when it is passed to
-// DidDumpQuotaTable() via base::Owned(). When the closure for said function
+// DidDumpBucketTable() via base::Owned(). When the closure for said function
// goes out of scope, the object is deleted.
// This class is not thread-safe because there can be races when entries_ is
// modified.
@@ -1156,7 +1000,9 @@ QuotaManagerImpl::QuotaManagerImpl(
: RefCountedDeleteOnSequence<QuotaManagerImpl>(io_thread),
is_incognito_(is_incognito),
profile_path_(profile_path),
- proxy_(base::MakeRefCounted<QuotaManagerProxy>(this, io_thread)),
+ proxy_(base::MakeRefCounted<QuotaManagerProxy>(this,
+ io_thread,
+ profile_path)),
io_thread_(std::move(io_thread)),
db_runner_(base::ThreadPool::CreateSequencedTaskRunner(
{base::MayBlock(), base::TaskPriority::USER_VISIBLE,
@@ -1195,7 +1041,13 @@ void QuotaManagerImpl::GetOrCreateBucket(
return;
}
PostTaskAndReplyWithResultForDBThread(
- base::BindOnce(&GetOrCreateBucketOnDBThread, storage_key, bucket_name),
+ base::BindOnce(
+ [](const StorageKey& storage_key, const std::string& bucket_name,
+ QuotaDatabase* database) {
+ DCHECK(database);
+ return database->GetOrCreateBucket(storage_key, bucket_name);
+ },
+ storage_key, bucket_name),
base::BindOnce(&QuotaManagerImpl::DidGetBucket,
weak_factory_.GetWeakPtr(), std::move(callback)));
}
@@ -1214,8 +1066,14 @@ void QuotaManagerImpl::GetOrCreateBucketDeprecated(
return;
}
PostTaskAndReplyWithResultForDBThread(
- base::BindOnce(&GetOrCreateBucketDeprecatedOnDBThread, storage_key,
- bucket_name, storage_type),
+ base::BindOnce(
+ [](const StorageKey& storage_key, const std::string& bucket_name,
+ blink::mojom::StorageType storage_type, QuotaDatabase* database) {
+ DCHECK(database);
+ return database->GetOrCreateBucketDeprecated(
+ storage_key, bucket_name, storage_type);
+ },
+ storage_key, bucket_name, storage_type),
base::BindOnce(&QuotaManagerImpl::DidGetBucket,
weak_factory_.GetWeakPtr(), std::move(callback)));
}
@@ -1234,8 +1092,14 @@ void QuotaManagerImpl::CreateBucketForTesting(
return;
}
PostTaskAndReplyWithResultForDBThread(
- base::BindOnce(&CreateBucketOnDBThread, storage_key, bucket_name,
- storage_type),
+ base::BindOnce(
+ [](const StorageKey& storage_key, const std::string& bucket_name,
+ blink::mojom::StorageType storage_type, QuotaDatabase* database) {
+ DCHECK(database);
+ return database->CreateBucketForTesting( // IN-TEST
+ storage_key, bucket_name, storage_type);
+ },
+ storage_key, bucket_name, storage_type),
base::BindOnce(&QuotaManagerImpl::DidGetBucket,
weak_factory_.GetWeakPtr(), std::move(callback)));
}
@@ -1254,7 +1118,13 @@ void QuotaManagerImpl::GetBucket(
return;
}
PostTaskAndReplyWithResultForDBThread(
- base::BindOnce(&GetBucketOnDBThread, storage_key, bucket_name, type),
+ base::BindOnce(
+ [](const StorageKey& storage_key, const std::string& bucket_name,
+ blink::mojom::StorageType type, QuotaDatabase* database) {
+ DCHECK(database);
+ return database->GetBucket(storage_key, bucket_name, type);
+ },
+ storage_key, bucket_name, type),
base::BindOnce(&QuotaManagerImpl::DidGetBucket,
weak_factory_.GetWeakPtr(), std::move(callback)));
}
@@ -1270,7 +1140,12 @@ void QuotaManagerImpl::GetStorageKeysForType(blink::mojom::StorageType type,
return;
}
PostTaskAndReplyWithResultForDBThread(
- base::BindOnce(&GetStorageKeysForTypeOnDBThread, type),
+ base::BindOnce(
+ [](blink::mojom::StorageType type, QuotaDatabase* database) {
+ DCHECK(database);
+ return database->GetStorageKeysForType(type);
+ },
+ type),
base::BindOnce(&QuotaManagerImpl::DidGetStorageKeys,
weak_factory_.GetWeakPtr(), std::move(callback)));
}
@@ -1287,7 +1162,12 @@ void QuotaManagerImpl::GetBucketsForType(
return;
}
PostTaskAndReplyWithResultForDBThread(
- base::BindOnce(&GetBucketsForTypeOnDBThread, type),
+ base::BindOnce(
+ [](StorageType type, QuotaDatabase* database) {
+ DCHECK(database);
+ return database->GetBucketsForType(type);
+ },
+ type),
base::BindOnce(&QuotaManagerImpl::DidGetBuckets,
weak_factory_.GetWeakPtr(), std::move(callback)));
}
@@ -1305,7 +1185,13 @@ void QuotaManagerImpl::GetBucketsForHost(
return;
}
PostTaskAndReplyWithResultForDBThread(
- base::BindOnce(&GetBucketsForHostOnDBThread, host, type),
+ base::BindOnce(
+ [](const std::string& host, StorageType type,
+ QuotaDatabase* database) {
+ DCHECK(database);
+ return database->GetBucketsForHost(host, type);
+ },
+ host, type),
base::BindOnce(&QuotaManagerImpl::DidGetBuckets,
weak_factory_.GetWeakPtr(), std::move(callback)));
}
@@ -1323,7 +1209,13 @@ void QuotaManagerImpl::GetBucketsForStorageKey(
return;
}
PostTaskAndReplyWithResultForDBThread(
- base::BindOnce(&GetBucketsForStorageKeyOnDBThread, storage_key, type),
+ base::BindOnce(
+ [](const StorageKey& storage_key, StorageType type,
+ QuotaDatabase* database) {
+ DCHECK(database);
+ return database->GetBucketsForStorageKey(storage_key, type);
+ },
+ storage_key, type),
base::BindOnce(&QuotaManagerImpl::DidGetBuckets,
weak_factory_.GetWeakPtr(), std::move(callback)));
}
@@ -1489,8 +1381,13 @@ void QuotaManagerImpl::FindAndDeleteBucketData(const StorageKey& storage_key,
return;
}
PostTaskAndReplyWithResultForDBThread(
- base::BindOnce(&GetBucketOnDBThread, storage_key, bucket_name,
- StorageType::kTemporary),
+ base::BindOnce(
+ [](const StorageKey& storage_key, const std::string& bucket_name,
+ blink::mojom::StorageType type, QuotaDatabase* database) {
+ DCHECK(database);
+ return database->GetBucket(storage_key, bucket_name, type);
+ },
+ storage_key, bucket_name, StorageType::kTemporary),
base::BindOnce(&QuotaManagerImpl::DidGetBucketForDeletion,
weak_factory_.GetWeakPtr(), std::move(callback)));
}
@@ -1599,7 +1496,12 @@ void QuotaManagerImpl::GetPersistentHostQuota(const std::string& host,
return;
PostTaskAndReplyWithResultForDBThread(
- base::BindOnce(&GetPersistentHostQuotaOnDBThread, host),
+ base::BindOnce(
+ [](const std::string& host, QuotaDatabase* database) {
+ DCHECK(database);
+ return database->GetHostQuota(host, StorageType::kPersistent);
+ },
+ host),
base::BindOnce(&QuotaManagerImpl::DidGetPersistentHostQuota,
weak_factory_.GetWeakPtr(), host));
}
@@ -1635,8 +1537,14 @@ void QuotaManagerImpl::SetPersistentHostQuota(const std::string& host,
}
int64_t* new_quota_ptr = new int64_t(new_quota);
PostTaskAndReplyWithResultForDBThread(
- base::BindOnce(&SetPersistentHostQuotaOnDBThread, host,
- base::Unretained(new_quota_ptr)),
+ base::BindOnce(
+ [](const std::string& host, int64_t* new_quota,
+ QuotaDatabase* database) {
+ DCHECK(database);
+ return database->SetHostQuota(host, StorageType::kPersistent,
+ *new_quota);
+ },
+ host, base::Unretained(new_quota_ptr)),
base::BindOnce(&QuotaManagerImpl::DidSetPersistentHostQuota,
weak_factory_.GetWeakPtr(), host, std::move(callback),
base::Owned(new_quota_ptr)));
@@ -1653,6 +1561,19 @@ void QuotaManagerImpl::GetGlobalUsage(StorageType type,
usage_tracker->GetGlobalUsage(std::move(callback));
}
+void QuotaManagerImpl::GetGlobalUsageForInternals(
+ storage::mojom::StorageType storage_type,
+ GetGlobalUsageForInternalsCallback callback) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ DCHECK(callback);
+ EnsureDatabaseOpened();
+
+ StorageType type = GetBlinkStorageType(storage_type);
+ UsageTracker* usage_tracker = GetUsageTracker(type);
+ DCHECK(usage_tracker);
+ usage_tracker->GetGlobalUsage(std::move(callback));
+}
+
void QuotaManagerImpl::GetHostUsageWithBreakdown(
const std::string& host,
StorageType type,
@@ -1665,6 +1586,22 @@ void QuotaManagerImpl::GetHostUsageWithBreakdown(
usage_tracker->GetHostUsageWithBreakdown(host, 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::IsStorageUnlimited(const StorageKey& storage_key,
StorageType type) const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
@@ -1694,7 +1631,13 @@ void QuotaManagerImpl::GetBucketsModifiedBetween(StorageType type,
}
PostTaskAndReplyWithResultForDBThread(
- base::BindOnce(&GetModifiedBetweenOnDBThread, type, begin, end),
+ base::BindOnce(
+ [](blink::mojom::StorageType type, base::Time begin, base::Time end,
+ QuotaDatabase* database) {
+ DCHECK(database);
+ return database->GetBucketsModifiedBetween(type, begin, end);
+ },
+ type, begin, end),
base::BindOnce(&QuotaManagerImpl::DidGetModifiedBetween,
weak_factory_.GetWeakPtr(), std::move(callback), type));
}
@@ -1744,9 +1687,8 @@ void QuotaManagerImpl::EnsureDatabaseOpened() {
}
// Use an empty path to open an in-memory only database for incognito.
- database_ = std::make_unique<QuotaDatabase>(
- is_incognito_ ? base::FilePath()
- : profile_path_.AppendASCII(kDatabaseName));
+ database_ = std::make_unique<QuotaDatabase>(is_incognito_ ? base::FilePath()
+ : profile_path_);
temporary_usage_tracker_ = std::make_unique<UsageTracker>(
this, client_types_[StorageType::kTemporary], StorageType::kTemporary,
@@ -1804,8 +1746,15 @@ void QuotaManagerImpl::DidGetStorageKeysForBootstrap(
storage_key_gatherer_.reset();
PostTaskAndReplyWithResultForDBThread(
- base::BindOnce(&BootstrapDatabaseOnDBThread,
- std::move(storage_keys_by_type)),
+ base::BindOnce(
+ [](base::flat_map<StorageType, std::set<StorageKey>>
+ storage_keys_by_type,
+ QuotaDatabase* database) {
+ DCHECK(database);
+ return database->RegisterInitialStorageKeyInfo(
+ std::move(storage_keys_by_type));
+ },
+ std::move(storage_keys_by_type)),
base::BindOnce(&QuotaManagerImpl::DidBootstrapDatabase,
weak_factory_.GetWeakPtr()),
FROM_HERE,
@@ -1814,10 +1763,14 @@ void QuotaManagerImpl::DidGetStorageKeysForBootstrap(
void QuotaManagerImpl::DidBootstrapDatabase(QuotaError error) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- DidDatabaseWork(error != QuotaError::kDatabaseError);
+ DidDatabaseWork(error != QuotaError::kDatabaseError,
+ /*is_bootstrap_work=*/true);
PostTaskAndReplyWithResultForDBThread(
- base::BindOnce(&SetDatabaseBootstrappedOnDBThread),
+ base::BindOnce([](QuotaDatabase* database) {
+ DCHECK(database);
+ return database->SetIsBootstrapped(true);
+ }),
base::BindOnce(&QuotaManagerImpl::DidSetDatabaseBootstrapped,
weak_factory_.GetWeakPtr()),
FROM_HERE,
@@ -1828,7 +1781,8 @@ void QuotaManagerImpl::DidSetDatabaseBootstrapped(QuotaError error) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(is_bootstrapping_database_);
is_bootstrapping_database_ = false;
- DidDatabaseWork(error != QuotaError::kDatabaseError);
+ DidDatabaseWork(error != QuotaError::kDatabaseError,
+ /*is_bootstrap_work=*/true);
RunDatabaseCallbacks();
StartEviction();
@@ -1872,6 +1826,16 @@ 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) {
@@ -1886,8 +1850,14 @@ void QuotaManagerImpl::NotifyStorageAccessed(const StorageKey& storage_key,
if (db_disabled_)
return;
PostTaskAndReplyWithResultForDBThread(
- base::BindOnce(&UpdateAccessTimeOnDBThread, storage_key, type,
- access_time),
+ base::BindOnce(
+ [](const StorageKey& storage_key, StorageType type,
+ base::Time accessed_time, QuotaDatabase* database) {
+ DCHECK(database);
+ return database->SetStorageKeyLastAccessTime(storage_key, type,
+ accessed_time);
+ },
+ storage_key, type, access_time),
base::BindOnce(&QuotaManagerImpl::OnComplete,
weak_factory_.GetWeakPtr()));
}
@@ -1905,7 +1875,13 @@ void QuotaManagerImpl::NotifyBucketAccessed(BucketId bucket_id,
if (db_disabled_)
return;
PostTaskAndReplyWithResultForDBThread(
- base::BindOnce(&UpdateBucketAccessTimeOnDBThread, bucket_id, access_time),
+ base::BindOnce(
+ [](BucketId bucket_id, base::Time accessed_time,
+ QuotaDatabase* database) {
+ DCHECK(database);
+ return database->SetBucketLastAccessTime(bucket_id, accessed_time);
+ },
+ bucket_id, access_time),
base::BindOnce(&QuotaManagerImpl::OnComplete,
weak_factory_.GetWeakPtr()));
}
@@ -1928,8 +1904,13 @@ void QuotaManagerImpl::NotifyStorageModified(QuotaClientType client_id,
}
PostTaskAndReplyWithResultForDBThread(
- base::BindOnce(&GetBucketOnDBThread, storage_key, kDefaultBucketName,
- type),
+ base::BindOnce(
+ [](const StorageKey& storage_key, const std::string& bucket_name,
+ blink::mojom::StorageType type, QuotaDatabase* database) {
+ DCHECK(database);
+ return database->GetBucket(storage_key, bucket_name, type);
+ },
+ storage_key, kDefaultBucketName, type),
base::BindOnce(&QuotaManagerImpl::DidGetBucketForUsage,
weak_factory_.GetWeakPtr(), client_id, delta,
modification_time, std::move(callback)));
@@ -1944,57 +1925,69 @@ void QuotaManagerImpl::NotifyBucketModified(QuotaClientType client_id,
DCHECK(callback);
EnsureDatabaseOpened();
- if (callback)
- std::move(callback).Run();
-
- if (db_disabled_)
- return;
-
- // TODO(crbug.com/1199417): Update bucket usage in UsageTracker once
- // QuotaClient & UsageTracker operate by bucket. UsageTracker should be
- // updated after ensuring there is a entry in the QuotaDatabase.
- // Run `callback` on completion.
-
PostTaskAndReplyWithResultForDBThread(
- base::BindOnce(&UpdateBucketModifiedTimeOnDBThread, bucket_id,
- modification_time),
- base::BindOnce(&QuotaManagerImpl::OnComplete,
- weak_factory_.GetWeakPtr()));
+ base::BindOnce(
+ [](BucketId bucket_id, QuotaDatabase* database) {
+ DCHECK(database);
+ return database->GetBucketById(bucket_id);
+ },
+ bucket_id),
+ base::BindOnce(&QuotaManagerImpl::DidGetBucketForUsage,
+ weak_factory_.GetWeakPtr(), client_id, delta,
+ modification_time, std::move(callback)));
}
-void QuotaManagerImpl::DumpQuotaTable(DumpQuotaTableCallback callback) {
+void QuotaManagerImpl::DumpBucketTable(DumpBucketTableCallback callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(callback);
- if (db_disabled_) {
- std::move(callback).Run(QuotaTableEntries());
+ if (db_disabled_ || !database_) {
+ std::move(callback).Run(BucketTableEntries());
return;
}
-
- DumpQuotaTableHelper* helper = new DumpQuotaTableHelper;
+ DumpBucketTableHelper* helper = new DumpBucketTableHelper;
PostTaskAndReplyWithResultForDBThread(
- base::BindOnce(&DumpQuotaTableHelper::DumpQuotaTableOnDBThread,
+ base::BindOnce(&DumpBucketTableHelper::DumpBucketTableOnDBThread,
base::Unretained(helper)),
- base::BindOnce(&DumpQuotaTableHelper::DidDumpQuotaTable,
+ base::BindOnce(&DumpBucketTableHelper::DidDumpBucketTable,
base::Owned(helper), weak_factory_.GetWeakPtr(),
std::move(callback)));
}
+void QuotaManagerImpl::DidRetrieveBucketsTable(
+ RetrieveBucketsTableCallback callback,
+ const BucketTableEntries& entries) {
+ std::vector<storage::mojom::BucketTableEntryPtr> mojo_entries;
-void QuotaManagerImpl::DumpBucketTable(DumpBucketTableCallback callback) {
+ for (auto& n : entries) {
+ DCHECK(IsSupportedType(n.type));
+ storage::mojom::BucketTableEntryPtr entry =
+ storage::mojom::BucketTableEntry::New();
+ entry->bucket_id = n.bucket_id.value();
+ entry->storage_key = n.storage_key.Serialize();
+ entry->host = n.storage_key.origin().host();
+ entry->type = StorageTypeEnumToString(n.type);
+ entry->name = n.name;
+ entry->use_count = n.use_count;
+ entry->last_accessed = n.last_accessed;
+ entry->last_modified = n.last_modified;
+ mojo_entries.push_back(std::move(entry));
+ }
+ std::move(callback).Run(std::move(mojo_entries));
+}
+
+void QuotaManagerImpl::RetrieveBucketsTable(
+ RetrieveBucketsTableCallback callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(callback);
if (db_disabled_) {
- std::move(callback).Run(BucketTableEntries());
+ std::move(callback).Run({});
return;
}
- DumpBucketTableHelper* helper = new DumpBucketTableHelper;
- PostTaskAndReplyWithResultForDBThread(
- base::BindOnce(&DumpBucketTableHelper::DumpBucketTableOnDBThread,
- base::Unretained(helper)),
- base::BindOnce(&DumpBucketTableHelper::DidDumpBucketTable,
- base::Owned(helper), weak_factory_.GetWeakPtr(),
- std::move(callback)));
+
+ DumpBucketTable(base::BindOnce(&QuotaManagerImpl::DidRetrieveBucketsTable,
+ weak_factory_.GetWeakPtr(),
+ std::move(callback)));
}
void QuotaManagerImpl::StartEviction() {
@@ -2021,7 +2014,12 @@ void QuotaManagerImpl::DeleteBucketFromDatabase(
}
PostTaskAndReplyWithResultForDBThread(
- base::BindOnce(&DeleteBucketInfoOnDBThread, bucket_id),
+ base::BindOnce(
+ [](BucketId bucket_id, QuotaDatabase* database) {
+ DCHECK(database);
+ return database->DeleteBucketInfo(bucket_id);
+ },
+ bucket_id),
std::move(callback));
}
@@ -2208,21 +2206,18 @@ void QuotaManagerImpl::SetQuotaChangeCallbackForTesting(
quota_change_callback_ = std::move(storage_pressure_event_callback);
}
-void QuotaManagerImpl::SetQuotaDatabaseForTesting(
- std::unique_ptr<QuotaDatabase> database) {
- DCHECK(database);
- database_ = std::move(database);
-
- // Initialize usage trackers after database is set.
- temporary_usage_tracker_ = std::make_unique<UsageTracker>(
- this, client_types_[StorageType::kTemporary], StorageType::kTemporary,
- special_storage_policy_.get());
- persistent_usage_tracker_ = std::make_unique<UsageTracker>(
- this, client_types_[StorageType::kPersistent], StorageType::kPersistent,
- special_storage_policy_.get());
- syncable_usage_tracker_ = std::make_unique<UsageTracker>(
- this, client_types_[StorageType::kSyncable], StorageType::kSyncable,
- special_storage_policy_.get());
+void QuotaManagerImpl::CorruptDatabaseForTesting(
+ base::OnceCallback<void(const base::FilePath&)> corrupter,
+ base::OnceCallback<void(QuotaError)> callback) {
+ PostTaskAndReplyWithResultForDBThread(
+ base::BindOnce(
+ [](base::OnceCallback<void(const base::FilePath&)> corrupter,
+ QuotaDatabase* database) {
+ return database->CorruptForTesting( // IN-TEST
+ std::move(corrupter));
+ },
+ std::move(corrupter)),
+ std::move(callback));
}
void QuotaManagerImpl::ReportHistogram() {
@@ -2382,7 +2377,12 @@ void QuotaManagerImpl::EvictBucketData(const BucketLocator& bucket,
eviction_context_.evict_bucket_data_callback = std::move(callback);
PostTaskAndReplyWithResultForDBThread(
- base::BindOnce(&GetBucketInfoForEvictionOnDBThread, bucket.id),
+ base::BindOnce(
+ [](BucketId bucket_id, QuotaDatabase* database) {
+ DCHECK(database);
+ return database->GetBucketInfo(bucket_id);
+ },
+ bucket.id),
base::BindOnce(&QuotaManagerImpl::DidGetBucketInfoForEviction,
weak_factory_.GetWeakPtr(), bucket));
}
@@ -2439,9 +2439,14 @@ void QuotaManagerImpl::GetLRUBucket(StorageType type,
}
PostTaskAndReplyWithResultForDBThread(
- base::BindOnce(&GetLRUBucketOnDBThread, type,
- GetEvictionBucketExceptions(),
- base::RetainedRef(special_storage_policy_)),
+ base::BindOnce(
+ [](StorageType type, const std::set<BucketId>& bucket_exceptions,
+ SpecialStoragePolicy* policy, QuotaDatabase* database) {
+ DCHECK(database);
+ return database->GetLRUBucket(type, bucket_exceptions, policy);
+ },
+ type, GetEvictionBucketExceptions(),
+ base::RetainedRef(special_storage_policy_)),
base::BindOnce(&QuotaManagerImpl::DidGetLRUBucket,
weak_factory_.GetWeakPtr()));
}
@@ -2592,14 +2597,58 @@ void QuotaManagerImpl::DidGetStorageCapacity(
DetermineStoragePressure(total_space, available_space);
}
-void QuotaManagerImpl::DidDatabaseWork(bool success) {
+void QuotaManagerImpl::DidDatabaseWork(bool success, bool is_bootstrap_work) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (success)
return;
+ // Ignore any errors that happen while a new bootstrap attempt is already in
+ // progress or queued.
+ if (is_bootstrapping_database_)
+ return;
+
db_error_count_++;
- if (db_error_count_ >= QuotaManagerImpl::kThresholdOfErrorsToDisableDatabase)
- db_disabled_ = true;
+
+ if (db_error_count_ >=
+ QuotaManagerImpl::kThresholdOfErrorsToDisableDatabase) {
+ if (bootstrap_disabled_for_testing_ || is_bootstrap_work) {
+ // If we got an error during bootstrapping there is no point in
+ // immediately trying again. Disable the database instead.
+ db_disabled_ = true;
+ return;
+ }
+
+ // Start another bootstrapping process. Pause eviction while bootstrapping
+ // is in progress. When bootstrapping finishes a new Evictor will be
+ // created.
+ is_bootstrapping_database_ = true;
+ temporary_storage_evictor_ = nullptr;
+ db_error_count_ = 0;
+
+ // Wipe the database before triggering another bootstrap.
+ base::PostTaskAndReplyWithResult(
+ db_runner_.get(), FROM_HERE,
+ base::BindOnce(&QuotaDatabase::RazeAndReopen,
+ base::Unretained(database_.get())),
+ base::BindOnce(&QuotaManagerImpl::DidRazeForReBootstrap,
+ weak_factory_.GetWeakPtr()));
+ }
+}
+
+void QuotaManagerImpl::DidRazeForReBootstrap(
+ QuotaError raze_and_reopen_result) {
+ if (raze_and_reopen_result == QuotaError::kNone) {
+ BootstrapDatabase();
+ return;
+ }
+
+ // Deleting the database failed. Disable the database and hope we'll recover
+ // after Chrome restarts instead.
+ db_disabled_ = true;
+ is_bootstrapping_database_ = false;
+ RunDatabaseCallbacks();
+ // No reason to restart eviction here. Without a working database there is
+ // nothing to evict.
}
void QuotaManagerImpl::OnComplete(QuotaError result) {
@@ -2666,8 +2715,14 @@ void QuotaManagerImpl::DidGetBucketForUsage(QuotaClientType client_type,
std::move(callback).Run();
PostTaskAndReplyWithResultForDBThread(
- base::BindOnce(&UpdateBucketModifiedTimeOnDBThread, bucket.id,
- modification_time),
+ base::BindOnce(
+ [](BucketId bucket_id, base::Time modified_time,
+ QuotaDatabase* database) {
+ DCHECK(database);
+ return database->SetBucketLastModifiedTime(bucket_id,
+ modified_time);
+ },
+ bucket.id, modification_time),
base::BindOnce(&QuotaManagerImpl::OnComplete,
weak_factory_.GetWeakPtr()));
return;
diff --git a/chromium/storage/browser/quota/quota_manager_impl.h b/chromium/storage/browser/quota/quota_manager_impl.h
index bc2eb685441..e64592831f7 100644
--- a/chromium/storage/browser/quota/quota_manager_impl.h
+++ b/chromium/storage/browser/quota/quota_manager_impl.h
@@ -354,6 +354,14 @@ class COMPONENT_EXPORT(STORAGE_BROWSER) QuotaManagerImpl
// storage::mojom::QuotaInternalsHandler implementation
void GetDiskAvailability(GetDiskAvailabilityCallback 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;
// Called by UI and internal modules.
void GetPersistentHostQuota(const std::string& host, QuotaCallback callback);
@@ -424,12 +432,31 @@ class COMPONENT_EXPORT(STORAGE_BROWSER) QuotaManagerImpl
eviction_disabled_ = disable;
}
- void SetQuotaDatabaseForTesting(std::unique_ptr<QuotaDatabase> database);
+ // Testing support for handling corruption in the underlying database.
+ //
+ // Runs `corrupter` on the same sequence used to do database I/O,
+ // guaranteeing that no other database operation is performed at the same
+ // time. `corrupter` receives the path to the underlying SQLite database as an
+ // argument. The underlying SQLite database is closed while `corrupter` runs,
+ // and reopened afterwards.
+ //
+ // `callback` is called with QuotaError::kNone if the database was
+ // successfully reopened after `corrupter` was run, or with
+ // QuotaError::kDatabaseError otherwise.
+ void CorruptDatabaseForTesting(
+ base::OnceCallback<void(const base::FilePath&)> corrupter,
+ base::OnceCallback<void(QuotaError)> callback);
void SetBootstrapDisabledForTesting(bool disable) {
bootstrap_disabled_for_testing_ = disable;
}
+ bool is_bootstrapping_database_for_testing() {
+ return is_bootstrapping_database_;
+ }
+
+ bool is_db_disabled_for_testing() { return db_disabled_; }
+
protected:
~QuotaManagerImpl() override;
void SetQuotaChangeCallbackForTesting(
@@ -451,7 +478,6 @@ class COMPONENT_EXPORT(STORAGE_BROWSER) QuotaManagerImpl
class StorageKeyGathererTask;
class BucketDataDeleter;
class HostDataDeleter;
- class DumpQuotaTableHelper;
class DumpBucketTableHelper;
class StorageCleanupHelper;
@@ -468,17 +494,13 @@ class COMPONENT_EXPORT(STORAGE_BROWSER) QuotaManagerImpl
std::set<int> active_override_session_ids;
};
- using QuotaTableEntry = QuotaDatabase::QuotaTableEntry;
using BucketTableEntry = QuotaDatabase::BucketTableEntry;
- using QuotaTableEntries = std::vector<QuotaTableEntry>;
using BucketTableEntries = std::vector<BucketTableEntry>;
using StorageKeysByType =
base::flat_map<blink::mojom::StorageType, std::set<blink::StorageKey>>;
using QuotaSettingsCallback = base::OnceCallback<void(const QuotaSettings&)>;
- using DumpQuotaTableCallback =
- base::OnceCallback<void(const QuotaTableEntries&)>;
using DumpBucketTableCallback =
base::OnceCallback<void(const BucketTableEntries&)>;
@@ -520,8 +542,13 @@ class COMPONENT_EXPORT(STORAGE_BROWSER) QuotaManagerImpl
UsageTracker* GetUsageTracker(blink::mojom::StorageType type) const;
- void DumpQuotaTable(DumpQuotaTableCallback callback);
void DumpBucketTable(DumpBucketTableCallback callback);
+ void DidRetrieveBucketsTable(RetrieveBucketsTableCallback callback,
+ const BucketTableEntries& entries);
+ void OnGetHostUsageForInternals(
+ GetHostUsageForInternalsCallback callback,
+ int64_t usage,
+ blink::mojom::UsageBreakdownPtr usage_breakdown);
// Runs BucketDataDeleter which calls QuotaClients to clear data for the
// bucket. Once the task is complete, calls the QuotaDatabase to delete the
@@ -601,7 +628,8 @@ class COMPONENT_EXPORT(STORAGE_BROWSER) QuotaManagerImpl
void DidGetStorageCapacity(
const std::tuple<int64_t, int64_t>& total_and_available);
- void DidDatabaseWork(bool success);
+ void DidDatabaseWork(bool success, bool is_bootstrap_work = false);
+ void DidRazeForReBootstrap(QuotaError raze_and_reopen_result);
void OnComplete(QuotaError result);
void DidGetBucket(base::OnceCallback<void(QuotaErrorOr<BucketInfo>)> callback,
@@ -636,7 +664,6 @@ class COMPONENT_EXPORT(STORAGE_BROWSER) QuotaManagerImpl
// pressure event dispatch if appropriate.
// TODO(crbug.com/1088004): Implement UsageAndQuotaInfoGatherer::Completed()
// to use DetermineStoragePressure().
- // TODO(crbug.com/1102433): Define and explain StoragePressure in the README.
void DetermineStoragePressure(int64_t free_space, int64_t total_space);
absl::optional<int64_t> GetQuotaOverrideForStorageKey(
@@ -660,12 +687,6 @@ class COMPONENT_EXPORT(STORAGE_BROWSER) QuotaManagerImpl
const base::FilePath& path);
static std::tuple<int64_t, int64_t> GetVolumeInfo(const base::FilePath& path);
- bool is_bootstrapping_database_for_testing() {
- return is_bootstrapping_database_;
- }
-
- bool is_db_disabled_for_testing() { return db_disabled_; }
-
const bool is_incognito_;
const base::FilePath profile_path_;
diff --git a/chromium/storage/browser/quota/quota_manager_proxy.cc b/chromium/storage/browser/quota/quota_manager_proxy.cc
index 8cce82b9af9..c4c37ec1bd0 100644
--- a/chromium/storage/browser/quota/quota_manager_proxy.cc
+++ b/chromium/storage/browser/quota/quota_manager_proxy.cc
@@ -15,9 +15,13 @@
#include "base/location.h"
#include "base/memory/scoped_refptr.h"
#include "base/sequence_checker.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/synchronization/waitable_event.h"
#include "base/task/sequenced_task_runner.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/time/time.h"
+#include "components/services/storage/public/cpp/buckets/bucket_locator.h"
+#include "components/services/storage/public/cpp/constants.h"
#include "components/services/storage/public/mojom/quota_client.mojom.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "storage/browser/quota/quota_client_type.h"
@@ -65,15 +69,45 @@ void DidGetStatus(
QuotaManagerProxy::QuotaManagerProxy(
QuotaManagerImpl* quota_manager_impl,
- scoped_refptr<base::SequencedTaskRunner> quota_manager_impl_task_runner)
+ scoped_refptr<base::SequencedTaskRunner> quota_manager_impl_task_runner,
+ const base::FilePath& profile_path)
: quota_manager_impl_(quota_manager_impl),
quota_manager_impl_task_runner_(
- std::move(quota_manager_impl_task_runner)) {
+ std::move(quota_manager_impl_task_runner)),
+ profile_path_(profile_path) {
DCHECK(quota_manager_impl_task_runner_.get());
DETACH_FROM_SEQUENCE(quota_manager_impl_sequence_checker_);
}
+base::FilePath QuotaManagerProxy::GetBucketPath(const BucketLocator& bucket) {
+ return profile_path_.Append(kWebStorageDirectory)
+ .AppendASCII(base::NumberToString(bucket.id.value()));
+}
+
+base::FilePath QuotaManagerProxy::GetClientBucketPath(
+ const BucketLocator& bucket,
+ QuotaClientType client_type) {
+ base::FilePath bucket_directory = GetBucketPath(bucket);
+
+ switch (client_type) {
+ case QuotaClientType::kFileSystem:
+ return bucket_directory.Append(kFileSystemDirectory);
+ case QuotaClientType::kIndexedDatabase:
+ return bucket_directory.Append(kIndexedDbDirectory);
+ case QuotaClientType::kBackgroundFetch:
+ case QuotaClientType::kServiceWorkerCache:
+ return bucket_directory.Append(kCacheStorageDirectory);
+ case QuotaClientType::kServiceWorker:
+ return bucket_directory.Append(kScriptCacheDirectory);
+ case QuotaClientType::kMediaLicense:
+ return bucket_directory.Append(kMediaLicenseDirectory);
+ default:
+ NOTREACHED() << "Unsupported QuotaClientType";
+ return base::FilePath();
+ }
+}
+
void QuotaManagerProxy::RegisterClient(
mojo::PendingRemote<mojom::QuotaClient> client,
QuotaClientType client_type,
@@ -136,6 +170,28 @@ void QuotaManagerProxy::GetOrCreateBucket(
std::move(callback)));
}
+QuotaErrorOr<BucketInfo> QuotaManagerProxy::GetOrCreateBucketSync(
+ const StorageKey& storage_key,
+ const std::string& bucket_name) {
+ // Ensure that the task runner we want is free and can be blocked on.
+ DCHECK(!quota_manager_impl_task_runner_->RunsTasksInCurrentSequence());
+ QuotaErrorOr<BucketInfo> bucket;
+ base::WaitableEvent waiter(base::WaitableEvent::ResetPolicy::AUTOMATIC,
+ base::WaitableEvent::InitialState::NOT_SIGNALED);
+ // Call the async GetOrCreateBucket but block until it completes.
+ GetOrCreateBucket(
+ storage_key, bucket_name, quota_manager_impl_task_runner_,
+ base::BindOnce(
+ [](base::WaitableEvent* waiter, QuotaErrorOr<BucketInfo>* sync_bucket,
+ QuotaErrorOr<BucketInfo> result_bucket) {
+ *sync_bucket = std::move(result_bucket);
+ waiter->Signal();
+ },
+ &waiter, &bucket));
+ waiter.Wait();
+ return bucket;
+}
+
void QuotaManagerProxy::GetOrCreateBucketDeprecated(
const StorageKey& storage_key,
const std::string& bucket_name,
diff --git a/chromium/storage/browser/quota/quota_manager_proxy.h b/chromium/storage/browser/quota/quota_manager_proxy.h
index 1b68cc3e359..d6d3baa02ed 100644
--- a/chromium/storage/browser/quota/quota_manager_proxy.h
+++ b/chromium/storage/browser/quota/quota_manager_proxy.h
@@ -38,6 +38,7 @@ class SequencedTaskRunner;
namespace storage {
+struct BucketLocator;
class QuotaOverrideHandle;
// Thread-safe proxy for QuotaManagerImpl.
@@ -57,7 +58,8 @@ class COMPONENT_EXPORT(STORAGE_BROWSER) QuotaManagerProxy
// `quota_manager_impl` isn't a base::WeakPtr<QuotaManagerImpl>.
QuotaManagerProxy(
QuotaManagerImpl* quota_manager_impl,
- scoped_refptr<base::SequencedTaskRunner> quota_manager_impl_task_runner);
+ scoped_refptr<base::SequencedTaskRunner> quota_manager_impl_task_runner,
+ const base::FilePath& profile_path);
QuotaManagerProxy(const QuotaManagerProxy&) = delete;
QuotaManagerProxy& operator=(const QuotaManagerProxy&) = delete;
@@ -70,6 +72,15 @@ class COMPONENT_EXPORT(STORAGE_BROWSER) QuotaManagerProxy
virtual void BindInternalsHandler(
mojo::PendingReceiver<mojom::QuotaInternalsHandler> receiver);
+ // Constructs path where `bucket` data is persisted to disk for partitioned
+ // storage.
+ base::FilePath GetBucketPath(const BucketLocator& bucket);
+
+ // Constructs path where `bucket` and `client_type` data is persisted to disk
+ // for partitioned storage.
+ base::FilePath GetClientBucketPath(const BucketLocator& bucket,
+ QuotaClientType client_type);
+
// Gets the bucket with `bucket_name` for the `storage_key` for StorageType
// kTemporary and returns the BucketInfo. If one doesn't exist, it creates
// a new bucket with the specified policies. Returns a QuotaError if the
@@ -80,6 +91,20 @@ class COMPONENT_EXPORT(STORAGE_BROWSER) QuotaManagerProxy
scoped_refptr<base::SequencedTaskRunner> callback_task_runner,
base::OnceCallback<void(QuotaErrorOr<BucketInfo>)> callback);
+ // Synchronously gets the bucket with `bucket_name` for the `storage_key` for
+ // StorageType kTemporary and returns the BucketInfo. If one doesn't exist, it
+ // creates a new bucket with the specified policies. Returns a QuotaError if
+ // the operation has failed. This function calls the asynchronous
+ // GetOrCreateBucket function but blocks until completion.
+ //
+ // NOTE: this function cannot be called from the
+ // 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.
+ virtual QuotaErrorOr<BucketInfo> GetOrCreateBucketSync(
+ const blink::StorageKey& storage_key,
+ const std::string& bucket_name);
+
// Same as GetOrCreateBucket but takes in StorageType. This should only be
// used by FileSystem, and is expected to be removed when
// StorageType::kSyncable and StorageType::kPersistent are deprecated.
@@ -240,6 +265,8 @@ class COMPONENT_EXPORT(STORAGE_BROWSER) QuotaManagerProxy
// to the same object), and the object it points to is thread-safe.
const scoped_refptr<base::SequencedTaskRunner>
quota_manager_impl_task_runner_;
+
+ const base::FilePath profile_path_;
};
} // namespace storage
diff --git a/chromium/storage/browser/quota/quota_manager_proxy_unittest.cc b/chromium/storage/browser/quota/quota_manager_proxy_unittest.cc
new file mode 100644
index 00000000000..7037150d138
--- /dev/null
+++ b/chromium/storage/browser/quota/quota_manager_proxy_unittest.cc
@@ -0,0 +1,109 @@
+// Copyright 2022 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/quota/quota_manager_proxy.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/memory/scoped_refptr.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/test/task_environment.h"
+#include "base/test/test_future.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "components/services/storage/public/cpp/buckets/bucket_info.h"
+#include "components/services/storage/public/cpp/constants.h"
+#include "components/services/storage/public/cpp/quota_error_or.h"
+#include "storage/browser/quota/quota_client_type.h"
+#include "storage/browser/quota/quota_manager_impl.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/public/common/storage_key/storage_key.h"
+
+namespace storage {
+
+class QuotaManagerProxyTest : public testing::Test {
+ public:
+ void SetUp() override {
+ EXPECT_TRUE(profile_path_.CreateUniqueTempDir());
+ quota_manager_ = base::MakeRefCounted<QuotaManagerImpl>(
+ /*is_incognito*/ false, profile_path_.GetPath(),
+ base::ThreadTaskRunnerHandle::Get().get(),
+ /*quota_change_callback=*/base::DoNothing(),
+ /*storage_policy=*/nullptr, GetQuotaSettingsFunc());
+ quota_manager_proxy_ = base::MakeRefCounted<QuotaManagerProxy>(
+ quota_manager_.get(), base::ThreadTaskRunnerHandle::Get(),
+ profile_path_.GetPath());
+ }
+
+ void TearDown() override {
+ quota_manager_proxy_ = nullptr;
+ quota_manager_ = nullptr;
+ }
+
+ protected:
+ base::ScopedTempDir profile_path_;
+ scoped_refptr<QuotaManagerImpl> quota_manager_;
+ scoped_refptr<QuotaManagerProxy> quota_manager_proxy_;
+
+ base::test::TaskEnvironment task_environment_;
+};
+
+TEST_F(QuotaManagerProxyTest, GetBucketPath) {
+ base::test::TestFuture<storage::QuotaErrorOr<storage::BucketInfo>> future;
+ quota_manager_proxy_->GetOrCreateBucket(
+ blink::StorageKey::CreateFromStringForTesting("http://example.com"),
+ "draft_bucket", base::ThreadTaskRunnerHandle::Get(),
+ future.GetCallback());
+ auto bucket = future.Take();
+ EXPECT_TRUE(bucket.ok());
+
+ base::FilePath expected_path =
+ profile_path_.GetPath()
+ .AppendASCII("WebStorage")
+ .AppendASCII(base::NumberToString(bucket->id.value()));
+ EXPECT_EQ(quota_manager_proxy_->GetBucketPath(bucket->ToBucketLocator()),
+ expected_path);
+}
+
+TEST_F(QuotaManagerProxyTest, GetClientBucketPath) {
+ base::test::TestFuture<storage::QuotaErrorOr<storage::BucketInfo>> future;
+ quota_manager_proxy_->GetOrCreateBucket(
+ blink::StorageKey::CreateFromStringForTesting("http://example.com"),
+ "draft_bucket", base::ThreadTaskRunnerHandle::Get(),
+ future.GetCallback());
+ auto bucket = future.Take();
+ EXPECT_TRUE(bucket.ok());
+
+ base::FilePath bucket_path =
+ profile_path_.GetPath()
+ .AppendASCII("WebStorage")
+ .AppendASCII(base::NumberToString(bucket->id.value()));
+
+ // FileSystem
+ base::FilePath expected_path = bucket_path.AppendASCII("FileSystem");
+ EXPECT_EQ(quota_manager_proxy_->GetClientBucketPath(
+ bucket->ToBucketLocator(), QuotaClientType::kFileSystem),
+ expected_path);
+
+ // IndexedDb
+ expected_path = bucket_path.AppendASCII("IndexedDB");
+ EXPECT_EQ(quota_manager_proxy_->GetClientBucketPath(
+ bucket->ToBucketLocator(), QuotaClientType::kIndexedDatabase),
+ expected_path);
+
+ // BackgroundFetch/CacheStorage
+ expected_path = bucket_path.AppendASCII("CacheStorage");
+ EXPECT_EQ(quota_manager_proxy_->GetClientBucketPath(
+ bucket->ToBucketLocator(), QuotaClientType::kBackgroundFetch),
+ expected_path);
+ EXPECT_EQ(
+ quota_manager_proxy_->GetClientBucketPath(
+ bucket->ToBucketLocator(), QuotaClientType::kServiceWorkerCache),
+ expected_path);
+
+ // ServiceWorker
+ expected_path = bucket_path.AppendASCII("ScriptCache");
+ EXPECT_EQ(quota_manager_proxy_->GetClientBucketPath(
+ bucket->ToBucketLocator(), QuotaClientType::kServiceWorker),
+ expected_path);
+}
+
+} // namespace storage
diff --git a/chromium/storage/browser/quota/quota_manager_unittest.cc b/chromium/storage/browser/quota/quota_manager_unittest.cc
index 96ab2a51517..70e037bdef8 100644
--- a/chromium/storage/browser/quota/quota_manager_unittest.cc
+++ b/chromium/storage/browser/quota/quota_manager_unittest.cc
@@ -24,6 +24,7 @@
#include "base/memory/weak_ptr.h"
#include "base/run_loop.h"
#include "base/system/sys_info.h"
+#include "base/task/thread_pool.h"
#include "base/test/bind.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/scoped_feature_list.h"
@@ -36,14 +37,15 @@
#include "components/services/storage/public/mojom/quota_client.mojom.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "mojo/public/cpp/bindings/self_owned_receiver.h"
+#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_features.h"
+#include "storage/browser/quota/quota_internals.mojom.h"
#include "storage/browser/quota/quota_manager_impl.h"
#include "storage/browser/quota/quota_manager_proxy.h"
#include "storage/browser/quota/quota_override_handle.h"
#include "storage/browser/test/mock_quota_client.h"
-#include "storage/browser/test/mock_quota_database.h"
#include "storage/browser/test/mock_special_storage_policy.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -110,6 +112,19 @@ StorageKey ToStorageKey(const std::string& url) {
return StorageKey::CreateFromStringForTesting(url);
}
+const storage::mojom::BucketTableEntry* FindBucketTableEntry(
+ const std::vector<storage::mojom::BucketTableEntryPtr>& bucket_entries,
+ BucketId& id) {
+ auto it = base::ranges::find_if(
+ bucket_entries, [id](const storage::mojom::BucketTableEntryPtr& entry) {
+ return entry->bucket_id == id.value();
+ });
+ if (it == bucket_entries.end()) {
+ return nullptr;
+ }
+ return it->get();
+}
+
MATCHER_P3(MatchesBucketTableEntry, storage_key, type, use_count, "") {
return testing::ExplainMatchResult(storage_key, arg.storage_key,
result_listener) &&
@@ -121,8 +136,6 @@ MATCHER_P3(MatchesBucketTableEntry, storage_key, type, use_count, "") {
class QuotaManagerImplTest : public testing::Test {
protected:
- using QuotaTableEntry = QuotaManagerImpl::QuotaTableEntry;
- using QuotaTableEntries = QuotaManagerImpl::QuotaTableEntries;
using BucketTableEntries = QuotaManagerImpl::BucketTableEntries;
public:
@@ -422,13 +435,6 @@ class QuotaManagerImplTest : public testing::Test {
return future.Get<0>();
}
- QuotaTableEntries DumpQuotaTable() {
- base::test::TestFuture<QuotaTableEntries> future;
- quota_manager_impl_->DumpQuotaTable(
- future.GetCallback<const QuotaTableEntries&>());
- return future.Get();
- }
-
BucketTableEntries DumpBucketTable() {
base::test::TestFuture<BucketTableEntries> future;
quota_manager_impl_->DumpBucketTable(
@@ -436,6 +442,13 @@ class QuotaManagerImplTest : public testing::Test {
return future.Get();
}
+ std::vector<storage::mojom::BucketTableEntryPtr> RetrieveBucketsTable() {
+ base::test::TestFuture<std::vector<storage::mojom::BucketTableEntryPtr>>
+ future;
+ quota_manager_impl_->RetrieveBucketsTable(future.GetCallback());
+ return future.Take();
+ }
+
void DidGetUsageAndQuotaWithBreakdown(
base::OnceClosure quit_closure,
QuotaStatusCode status,
@@ -519,8 +532,12 @@ class QuotaManagerImplTest : public testing::Test {
quota_manager_impl_->SetQuotaChangeCallbackForTesting(std::move(cb));
}
- void SetQuotaDatabase(std::unique_ptr<QuotaDatabase> database) {
- quota_manager_impl_->SetQuotaDatabaseForTesting(std::move(database));
+ QuotaError CorruptDatabaseForTesting(
+ base::OnceCallback<void(const base::FilePath&)> corrupter) {
+ base::test::TestFuture<QuotaError> corruption_future;
+ quota_manager_impl_->CorruptDatabaseForTesting(
+ std::move(corrupter), corruption_future.GetCallback());
+ return corruption_future.Get();
}
bool is_db_bootstrapping() {
@@ -531,8 +548,16 @@ class QuotaManagerImplTest : public testing::Test {
return quota_manager_impl_->is_db_disabled_for_testing();
}
- void disable_quota_database(bool disable) {
- quota_manager_impl_->database_->SetDisabledForTesting(disable);
+ void DisableQuotaDatabase() {
+ base::RunLoop run_loop;
+ quota_manager_impl_->PostTaskAndReplyWithResultForDBThread(
+ base::BindLambdaForTesting([&](QuotaDatabase* db) {
+ db->SetDisabledForTesting(true);
+ return QuotaError::kNone;
+ }),
+ base::BindLambdaForTesting([&](QuotaError error) { run_loop.Quit(); }),
+ FROM_HERE, /*is_bootstrap_task=*/false);
+ run_loop.Run();
}
void disable_database_bootstrap(bool disable) {
@@ -625,6 +650,74 @@ TEST_F(QuotaManagerImplTest, QuotaDatabaseBootstrap) {
ASSERT_TRUE(bucket.ok());
}
+TEST_F(QuotaManagerImplTest, CorruptionRecovery) {
+ // Setup clients with both unmigrated and migrated data. Before corruption the
+ // bucket data will be used, while after corruption recovery data should be
+ // migrated again.
+ static const ClientBucketData kData1[] = {
+ {"http://foo.com/", kDefaultBucketName, kTemp, 10},
+ {"http://foo.com:8080/", kDefaultBucketName, kTemp, 15},
+ };
+ static const UnmigratedStorageKeyData kUnmigratedData1[] = {
+ {"http://foo.com/", kTemp, 10},
+ {"http://foo.com:8080/", kTemp, 15},
+ };
+ static const ClientBucketData kData2[] = {
+ {"https://foo.com/", kDefaultBucketName, kTemp, 30},
+ {"https://foo.com:8081/", kDefaultBucketName, kTemp, 35},
+ };
+ static const UnmigratedStorageKeyData kUnmigratedData2[] = {
+ {"https://foo.com/", kTemp, 30},
+ {"https://foo.com:8081/", kTemp, 35},
+ };
+ MockQuotaClient* fs_client = CreateAndRegisterClient(
+ QuotaClientType::kFileSystem, {kTemp, kPerm}, kUnmigratedData1);
+ MockQuotaClient* database_client = CreateAndRegisterClient(
+ QuotaClientType::kDatabase, {kTemp, kPerm}, kUnmigratedData2);
+ RegisterClientBucketData(fs_client, kData1);
+ RegisterClientBucketData(database_client, kData2);
+
+ // Basic sanity checks, make sure setup worked correctly.
+ auto bucket =
+ GetBucket(ToStorageKey("http://foo.com/"), kDefaultBucketName, kTemp);
+ ASSERT_TRUE(bucket.ok());
+ bucket = GetBucket(ToStorageKey("http://foo.com:8080/"), kDefaultBucketName,
+ kTemp);
+ ASSERT_TRUE(bucket.ok());
+ bucket = GetBucket(ToStorageKey("https://foo.com:8081/"), kDefaultBucketName,
+ kTemp);
+ ASSERT_TRUE(bucket.ok());
+
+ // Corrupt the database to make bucket lookup fail.
+ QuotaError corruption_error = CorruptDatabaseForTesting(
+ base::BindOnce([](const base::FilePath& db_path) {
+ ASSERT_TRUE(
+ sql::test::CorruptIndexRootPage(db_path, "buckets_by_storage_key"));
+ }));
+ ASSERT_EQ(QuotaError::kNone, corruption_error);
+
+ // Try to lookup a bucket, this should fail until the error threshold is
+ // reached.
+ for (int i = 0; i < QuotaManagerImpl::kThresholdOfErrorsToDisableDatabase;
+ ++i) {
+ EXPECT_FALSE(quota_manager_impl_->is_db_disabled_for_testing());
+ EXPECT_FALSE(is_db_bootstrapping());
+
+ bucket =
+ GetBucket(ToStorageKey("http://foo.com/"), kDefaultBucketName, kTemp);
+ ASSERT_FALSE(bucket.ok());
+ EXPECT_EQ(QuotaError::kDatabaseError, bucket.error());
+ }
+
+ // The last lookup attempt should have started another bootstrap attempt.
+ EXPECT_TRUE(is_db_bootstrapping());
+
+ // And with that bucket lookup should be working again.
+ bucket =
+ GetBucket(ToStorageKey("http://foo.com/"), kDefaultBucketName, kTemp);
+ ASSERT_TRUE(bucket.ok());
+}
+
TEST_F(QuotaManagerImplTest, GetUsageInfo) {
static const ClientBucketData kData1[] = {
{"http://foo.com/", kDefaultBucketName, kTemp, 10},
@@ -661,7 +754,7 @@ TEST_F(QuotaManagerImplTest, DatabaseDisabledAfterThreshold) {
OpenDatabase();
// Disable quota database for database error behavior.
- disable_quota_database(true);
+ DisableQuotaDatabase();
ASSERT_FALSE(is_db_disabled());
@@ -696,6 +789,32 @@ TEST_F(QuotaManagerImplTest, GetOrCreateBucket) {
EXPECT_EQ(bucket.value().id, created_bucket_id);
}
+TEST_F(QuotaManagerImplTest, GetOrCreateBucketSync) {
+ base::RunLoop loop;
+ // Post the function call on a different thread to ensure that the
+ // production DCHECK in GetOrCreateBucketSync passes.
+ base::ThreadPool::PostTask(
+ FROM_HERE, {base::WithBaseSyncPrimitives()},
+ base::BindLambdaForTesting([&]() {
+ StorageKey storage_key = ToStorageKey("http://b.com");
+ std::string bucket_name = "bucket_b";
+ // Ensure that the synchronous function returns a bucket.
+ auto bucket = quota_manager_impl_->proxy()->GetOrCreateBucketSync(
+ storage_key, bucket_name);
+ ASSERT_TRUE(bucket.ok());
+ BucketId created_bucket_id = bucket.value().id;
+
+ // Ensure that the synchronous function does not create a new bucket
+ // each time.
+ bucket = quota_manager_impl_->proxy()->GetOrCreateBucketSync(
+ storage_key, bucket_name);
+ EXPECT_TRUE(bucket.ok());
+ EXPECT_EQ(bucket.value().id, created_bucket_id);
+ loop.Quit();
+ }));
+ loop.Run();
+}
+
TEST_F(QuotaManagerImplTest, GetBucket) {
StorageKey storage_key = ToStorageKey("http://a.com/");
std::string bucket_name = "bucket_a";
@@ -745,7 +864,7 @@ TEST_F(QuotaManagerImplTest, GetStorageKeysForTypeWithDatabaseError) {
OpenDatabase();
// Disable quota database for database error behavior.
- disable_quota_database(true);
+ DisableQuotaDatabase();
// Return empty set when error is encountered.
std::set<StorageKey> storage_keys = GetStorageKeysForType(kTemp);
@@ -1695,6 +1814,55 @@ TEST_F(QuotaManagerImplTest, GetUsage_WithModification) {
EXPECT_EQ(usage(), 4000 + 50000 + 900000000);
}
+TEST_F(QuotaManagerImplTest, GetUsage_WithBucketModification) {
+ static const ClientBucketData kData[] = {
+ {"http://foo.com/", kDefaultBucketName, kTemp, 1},
+ {"http://foo.com/", kDefaultBucketName, kPerm, 50},
+ {"http://bar.com/", "logs", kTemp, 100},
+ };
+
+ MockQuotaClient* client =
+ CreateAndRegisterClient(QuotaClientType::kFileSystem, {kTemp, kPerm});
+ RegisterClientBucketData(client, kData);
+
+ auto global_usage_result = GetGlobalUsage(kPerm);
+ EXPECT_EQ(global_usage_result.usage, 50);
+ EXPECT_EQ(global_usage_result.unlimited_usage, 0);
+
+ auto foo_temp_bucket =
+ GetBucket(ToStorageKey("http://foo.com/"), kDefaultBucketName, kTemp);
+ ASSERT_TRUE(foo_temp_bucket.ok());
+ client->ModifyBucketAndNotify(foo_temp_bucket->id, 80000000);
+
+ global_usage_result = GetGlobalUsage(kTemp);
+ EXPECT_EQ(global_usage_result.usage, 1 + 100 + 80000000);
+ EXPECT_EQ(global_usage_result.unlimited_usage, 0);
+
+ global_usage_result = GetGlobalUsage(kPerm);
+ EXPECT_EQ(global_usage_result.usage, 50);
+ EXPECT_EQ(global_usage_result.unlimited_usage, 0);
+
+ auto foo_perm_bucket =
+ GetBucket(ToStorageKey("http://foo.com/"), kDefaultBucketName, kPerm);
+ ASSERT_TRUE(foo_perm_bucket.ok());
+ client->ModifyBucketAndNotify(foo_perm_bucket->id, 200);
+
+ global_usage_result = GetGlobalUsage(kPerm);
+ EXPECT_EQ(global_usage_result.usage, 50 + 200);
+ EXPECT_EQ(global_usage_result.unlimited_usage, 0);
+
+ GetHostUsageWithBreakdown("bar.com", kTemp);
+ EXPECT_EQ(usage(), 100);
+
+ auto bar_temp_bucket =
+ GetBucket(ToStorageKey("http://bar.com/"), "logs", kTemp);
+ ASSERT_TRUE(bar_temp_bucket.ok());
+ client->ModifyBucketAndNotify(bar_temp_bucket->id, 900000000);
+
+ GetHostUsageWithBreakdown("bar.com", kTemp);
+ EXPECT_EQ(usage(), 100 + 900000000);
+}
+
TEST_F(QuotaManagerImplTest, GetUsage_WithDeleteBucket) {
static const ClientBucketData kData[] = {
{"http://foo.com/", kDefaultBucketName, kTemp, 1},
@@ -2409,22 +2577,23 @@ TEST_F(QuotaManagerImplTest, FindAndDeleteBucketDataWithDBError) {
MockQuotaClient* fs_client =
CreateAndRegisterClient(QuotaClientType::kFileSystem, {kTemp, kPerm});
- auto quota_db = std::make_unique<MockQuotaDatabase>(
- data_dir_.GetPath().AppendASCII("QuotaManager"));
- MockQuotaDatabase* mock_database = quota_db.get();
- SetQuotaDatabase(std::move(quota_db));
-
RegisterClientBucketData(fs_client, kData);
// Check usage data before deletion.
GetHostUsageWithBreakdown("foo.com", kTemp);
ASSERT_EQ(123, usage());
- EXPECT_CALL(*mock_database, DeleteBucketInfo)
- .Times(1)
- .WillOnce(testing::Return(QuotaError::kDatabaseError));
+ // Bucket lookup uses the `buckets_by_storage_key` index. So, we can corrupt
+ // any other index, and SQLite will only detect the corruption when trying to
+ // delete a bucket.
+ QuotaError corruption_error = CorruptDatabaseForTesting(
+ base::BindOnce([](const base::FilePath& db_path) {
+ ASSERT_TRUE(sql::test::CorruptIndexRootPage(
+ db_path, "buckets_by_last_accessed"));
+ }));
+ ASSERT_EQ(QuotaError::kNone, corruption_error);
- // Trying to delete bucket for "http://foo.com/" should return error.
+ // Deleting the bucket will result in an error.
EXPECT_EQ(FindAndDeleteBucketData(ToStorageKey("http://foo.com"),
kDefaultBucketName),
QuotaStatusCode::kErrorInvalidModification);
@@ -2436,6 +2605,32 @@ TEST_F(QuotaManagerImplTest, FindAndDeleteBucketDataWithDBError) {
EXPECT_EQ(0, 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, NotifyAndLRUBucket) {
static const ClientBucketData kData[] = {
{"http://a.com/", kDefaultBucketName, kTemp, 0},
@@ -2576,7 +2771,7 @@ TEST_F(QuotaManagerImplTest, GetBucketsModifiedBetweenWithDatabaseError) {
OpenDatabase();
// Disable quota database for database error behavior.
- disable_quota_database(true);
+ DisableQuotaDatabase();
auto buckets =
GetBucketsModifiedBetween(kTemp, base::Time(), base::Time::Max());
@@ -2585,23 +2780,11 @@ TEST_F(QuotaManagerImplTest, GetBucketsModifiedBetweenWithDatabaseError) {
EXPECT_TRUE(buckets.empty());
}
-TEST_F(QuotaManagerImplTest, DumpQuotaTable) {
- SetPersistentHostQuota("example1.com", 1);
- SetPersistentHostQuota("example2.com", 20);
- SetPersistentHostQuota("example3.com", 300);
- task_environment_.RunUntilIdle();
-
- const QuotaTableEntries& entries = DumpQuotaTable();
- EXPECT_THAT(
- entries,
- testing::UnorderedElementsAre(
- QuotaTableEntry{.host = "example1.com", .type = kPerm, .quota = 1},
- QuotaTableEntry{.host = "example2.com", .type = kPerm, .quota = 20},
- QuotaTableEntry{
- .host = "example3.com", .type = kPerm, .quota = 300}));
-}
-
TEST_F(QuotaManagerImplTest, DumpBucketTable) {
+ // Dumping an unpopulated bucket table returns an empty vector.
+ const BucketTableEntries& initial_entries = DumpBucketTable();
+ EXPECT_TRUE(initial_entries.empty());
+
const StorageKey kStorageKey = ToStorageKey("http://example.com/");
CreateBucketForTesting(kStorageKey, kDefaultBucketName, kTemp);
CreateBucketForTesting(kStorageKey, kDefaultBucketName, kPerm);
@@ -2620,6 +2803,64 @@ TEST_F(QuotaManagerImplTest, DumpBucketTable) {
MatchesBucketTableEntry(kStorageKey, kPerm, 2)));
}
+TEST_F(QuotaManagerImplTest, RetrieveBucketsTable) {
+ const StorageKey kStorageKey = ToStorageKey("http://example.com/");
+ const std::string kSerializedStorageKey = kStorageKey.Serialize();
+ const base::Time kAccessTime = base::Time::Now();
+
+ static const ClientBucketData kData[] = {
+ {"http://example.com/", kDefaultBucketName, kTemp, 0},
+ {"http://example.com/", kDefaultBucketName, kPerm, 0},
+ };
+
+ MockQuotaClient* client =
+ CreateAndRegisterClient(QuotaClientType::kFileSystem, {kTemp, kPerm});
+ RegisterClientBucketData(client, kData);
+
+ quota_manager_impl()->NotifyStorageAccessed(kStorageKey, kTemp, kAccessTime);
+ quota_manager_impl()->NotifyStorageAccessed(kStorageKey, kPerm, kAccessTime);
+
+ 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);
+ base::Time time3 = client->IncrementMockTime();
+
+ auto temp_bucket = GetBucket(kStorageKey, kDefaultBucketName, kTemp);
+ auto perm_bucket = GetBucket(kStorageKey, kDefaultBucketName, kPerm);
+
+ const std::vector<storage::mojom::BucketTableEntryPtr> bucket_table_entries =
+ RetrieveBucketsTable();
+
+ auto* temp_entry =
+ 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->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);
+
+ 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->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);
+}
+
TEST_F(QuotaManagerImplTest, QuotaForEmptyHost) {
EXPECT_EQ(GetPersistentHostQuota(std::string()), 0);
diff --git a/chromium/storage/browser/quota/quota_settings.cc b/chromium/storage/browser/quota/quota_settings.cc
index 3a55be13bfe..c2a5a209635 100644
--- a/chromium/storage/browser/quota/quota_settings.cc
+++ b/chromium/storage/browser/quota/quota_settings.cc
@@ -13,7 +13,6 @@
#include "base/no_destructor.h"
#include "base/rand_util.h"
#include "base/system/sys_info.h"
-#include "base/task/post_task.h"
#include "base/task/thread_pool.h"
#include "base/threading/scoped_blocking_call.h"
#include "build/build_config.h"
diff --git a/chromium/storage/browser/quota/quota_settings.h b/chromium/storage/browser/quota/quota_settings.h
index d8fd5702fe0..a17bc3c3823 100644
--- a/chromium/storage/browser/quota/quota_settings.h
+++ b/chromium/storage/browser/quota/quota_settings.h
@@ -72,9 +72,9 @@ using GetQuotaSettingsFunc =
// Posts a background task to calculate and report quota settings to the
// |callback| function based on the size of the volume containing the storage
// partition and a guestimate of the size required for the OS. The refresh
-// interval is 60 seconds to accomodate changes to the size of the volume.
-// Except, in the case of incognito, the poolize and quota values are based
-// on the amount of physical memory and the rerfresh interval is max'd out.
+// interval is 60 seconds to accommodate changes to the size of the volume.
+// Except, in the case of incognito, the pool size and quota values are based
+// on the amount of physical memory and the refresh interval is maxed out.
COMPONENT_EXPORT(STORAGE_BROWSER)
void GetNominalDynamicSettings(const base::FilePath& partition_path,
bool is_incognito,
diff --git a/chromium/storage/browser/quota/quota_temporary_storage_evictor.h b/chromium/storage/browser/quota/quota_temporary_storage_evictor.h
index b130c16a1cb..c07ffd74d6b 100644
--- a/chromium/storage/browser/quota/quota_temporary_storage_evictor.h
+++ b/chromium/storage/browser/quota/quota_temporary_storage_evictor.h
@@ -15,6 +15,7 @@
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/sequence_checker.h"
+#include "base/time/time.h"
#include "base/timer/timer.h"
#include "components/services/storage/public/cpp/buckets/bucket_locator.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
diff --git a/chromium/storage/browser/quota/special_storage_policy.cc b/chromium/storage/browser/quota/special_storage_policy.cc
index bc0ae145a0c..f7774c8973d 100644
--- a/chromium/storage/browser/quota/special_storage_policy.cc
+++ b/chromium/storage/browser/quota/special_storage_policy.cc
@@ -4,6 +4,8 @@
#include "storage/browser/quota/special_storage_policy.h"
+#include "base/observer_list.h"
+
namespace storage {
SpecialStoragePolicy::Observer::~Observer() = default;
diff --git a/chromium/storage/browser/quota/storage_directory.cc b/chromium/storage/browser/quota/storage_directory.cc
new file mode 100644
index 00000000000..11b85fdb293
--- /dev/null
+++ b/chromium/storage/browser/quota/storage_directory.cc
@@ -0,0 +1,62 @@
+// Copyright 2022 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/quota/storage_directory.h"
+
+#include "base/files/file_enumerator.h"
+#include "base/files/file_util.h"
+#include "base/notreached.h"
+#include "base/strings/strcat.h"
+#include "components/services/storage/public/cpp/constants.h"
+
+namespace storage {
+namespace {
+const base::FilePath::CharType kDoomedPathName[] =
+ FILE_PATH_LITERAL("-doomed-");
+}
+
+StorageDirectory::StorageDirectory(const base::FilePath& profile_path)
+ : web_storage_path_(profile_path.Append(kWebStorageDirectory)) {
+ DCHECK(!profile_path.empty()) << "Should not be called in incognito mode.";
+}
+
+StorageDirectory::~StorageDirectory() = default;
+
+bool StorageDirectory::Create() {
+ return base::CreateDirectory(web_storage_path_);
+}
+
+bool StorageDirectory::Doom() {
+ if (!base::PathExists(web_storage_path_))
+ return true;
+
+ base::FilePath doomed_dir;
+ base::CreateTemporaryDirInDir(
+ web_storage_path_.DirName(),
+ base::StrCat({kWebStorageDirectory, kDoomedPathName}), &doomed_dir);
+ return base::Move(web_storage_path_, doomed_dir);
+}
+
+void StorageDirectory::ClearDoomed() {
+ std::set<base::FilePath> paths = EnumerateDoomedDirectories();
+
+ for (const base::FilePath& path : paths)
+ base::DeletePathRecursively(path);
+}
+
+std::set<base::FilePath> StorageDirectory::EnumerateDoomedDirectories() {
+ base::FileEnumerator enumerator(
+ web_storage_path_.DirName(), /*recursive=*/false,
+ base::FileEnumerator::DIRECTORIES,
+ base::StrCat(
+ {kWebStorageDirectory, kDoomedPathName, FILE_PATH_LITERAL("*")}));
+
+ std::set<base::FilePath> paths;
+ base::FilePath path;
+ while (path = enumerator.Next(), !path.empty())
+ paths.insert(path);
+ return paths;
+}
+
+} // namespace storage
diff --git a/chromium/storage/browser/quota/storage_directory.h b/chromium/storage/browser/quota/storage_directory.h
new file mode 100644
index 00000000000..8e51798589b
--- /dev/null
+++ b/chromium/storage/browser/quota/storage_directory.h
@@ -0,0 +1,51 @@
+// Copyright 2022 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_QUOTA_STORAGE_DIRECTORY_H_
+#define STORAGE_BROWSER_QUOTA_STORAGE_DIRECTORY_H_
+
+#include <set>
+
+#include "base/component_export.h"
+#include "base/files/file_path.h"
+
+namespace storage {
+
+// Interface for handling the WebStorage directory for a profile where
+// Storage Buckets data is stored.
+class COMPONENT_EXPORT(STORAGE_BROWSER) StorageDirectory {
+ public:
+ explicit StorageDirectory(const base::FilePath& profile_path);
+ StorageDirectory(const StorageDirectory&) = delete;
+ StorageDirectory& operator=(const StorageDirectory&) = delete;
+ ~StorageDirectory();
+
+ // Creates storage directory and returns true if creation succeeds or
+ // directory already exists.
+ bool Create();
+
+ // Marks the current storage directory for deletion and returns true on
+ // success.
+ bool Doom();
+
+ // Deletes doomed storage directories.
+ void ClearDoomed();
+
+ // Returns path where WebStorage data is persisted to disk. Returns empty path
+ // for incognito.
+ const base::FilePath& path() const { return web_storage_path_; }
+
+ std::set<base::FilePath> EnumerateDoomedDirectoriesForTesting() {
+ return EnumerateDoomedDirectories();
+ }
+
+ private:
+ std::set<base::FilePath> EnumerateDoomedDirectories();
+
+ const base::FilePath web_storage_path_;
+};
+
+} // namespace storage
+
+#endif // STORAGE_BROWSER_QUOTA_STORAGE_DIRECTORY_H_
diff --git a/chromium/storage/browser/quota/storage_directory_unittest.cc b/chromium/storage/browser/quota/storage_directory_unittest.cc
new file mode 100644
index 00000000000..e1f50200994
--- /dev/null
+++ b/chromium/storage/browser/quota/storage_directory_unittest.cc
@@ -0,0 +1,82 @@
+// Copyright 2022 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 <set>
+
+#include "base/files/file_enumerator.h"
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/files/scoped_temp_dir.h"
+#include "storage/browser/quota/storage_directory.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace storage {
+
+class StorageDirectoryTest : public testing::Test {
+ public:
+ void SetUp() override {
+ ASSERT_TRUE(temp_directory_.CreateUniqueTempDir());
+ storage_directory_ =
+ std::make_unique<StorageDirectory>(temp_directory_.GetPath());
+ }
+ void TearDown() override { ASSERT_TRUE(temp_directory_.Delete()); }
+
+ protected:
+ base::ScopedTempDir temp_directory_;
+ std::unique_ptr<StorageDirectory> storage_directory_;
+};
+
+TEST_F(StorageDirectoryTest, CreateDirectory) {
+ base::FilePath storage_path = storage_directory_->path();
+
+ EXPECT_FALSE(base::PathExists(storage_path));
+
+ ASSERT_TRUE(storage_directory_->Create());
+ EXPECT_TRUE(base::PathExists(storage_path));
+
+ // Should still return true if it already exists.
+ ASSERT_TRUE(storage_directory_->Create());
+ EXPECT_TRUE(base::PathExists(storage_path));
+}
+
+TEST_F(StorageDirectoryTest, DoomAndClearStorage) {
+ base::FilePath storage_path = storage_directory_->path();
+ ASSERT_TRUE(storage_directory_->Create());
+ EXPECT_TRUE(base::PathExists(storage_path));
+
+ // Write data into directory.
+ base::WriteFile(storage_path.AppendASCII("FakeStorage"), "dummy_content");
+
+ ASSERT_TRUE(storage_directory_->Doom());
+ EXPECT_FALSE(base::PathExists(storage_path));
+
+ std::set<base::FilePath> directories =
+ storage_directory_->EnumerateDoomedDirectoriesForTesting();
+ EXPECT_EQ(directories.size(), 1u);
+
+ storage_directory_->ClearDoomed();
+ directories = storage_directory_->EnumerateDoomedDirectoriesForTesting();
+ EXPECT_EQ(directories.size(), 0u);
+}
+
+TEST_F(StorageDirectoryTest, ClearDoomedMultiple) {
+ base::FilePath storage_path = storage_directory_->path();
+
+ // Create and doom storage directory multiple times.
+ for (unsigned int i = 0; i < 5; i++) {
+ ASSERT_TRUE(storage_directory_->Create());
+ ASSERT_TRUE(storage_directory_->Doom());
+ }
+
+ std::set<base::FilePath> directories =
+ storage_directory_->EnumerateDoomedDirectoriesForTesting();
+ EXPECT_EQ(directories.size(), 5u);
+
+ storage_directory_->ClearDoomed();
+ directories = storage_directory_->EnumerateDoomedDirectoriesForTesting();
+ EXPECT_EQ(directories.size(), 0u);
+}
+
+} // namespace storage
diff --git a/chromium/storage/browser/quota/storage_policy_observer.cc b/chromium/storage/browser/quota/storage_policy_observer.cc
index 884ade794c5..73dde9d81b8 100644
--- a/chromium/storage/browser/quota/storage_policy_observer.cc
+++ b/chromium/storage/browser/quota/storage_policy_observer.cc
@@ -7,7 +7,6 @@
#include <utility>
#include "base/feature_list.h"
-#include "base/task/post_task.h"
#include "storage/browser/quota/quota_features.h"
#include "url/origin.h"
diff --git a/chromium/storage/browser/quota/usage_tracker.cc b/chromium/storage/browser/quota/usage_tracker.cc
index f6018b20d7d..1cceaf24cf5 100644
--- a/chromium/storage/browser/quota/usage_tracker.cc
+++ b/chromium/storage/browser/quota/usage_tracker.cc
@@ -271,6 +271,13 @@ void UsageTracker::AccumulateClientHostUsage(base::OnceClosure barrier_callback,
case QuotaClientType::kNativeIO:
info->usage_breakdown->fileSystem += total_usage;
break;
+ case QuotaClientType::kMediaLicense:
+ // Media license data does not count against quota and should always
+ // report 0 usage.
+ // TODO(crbug.com/1305441): Consider counting media license data against
+ // quota.
+ DCHECK_EQ(total_usage, 0);
+ break;
}
std::move(barrier_callback).Run();
diff --git a/chromium/storage/browser/quota/usage_tracker_unittest.cc b/chromium/storage/browser/quota/usage_tracker_unittest.cc
index 477d8fc4455..f361f86ed21 100644
--- a/chromium/storage/browser/quota/usage_tracker_unittest.cc
+++ b/chromium/storage/browser/quota/usage_tracker_unittest.cc
@@ -14,6 +14,7 @@
#include "base/memory/scoped_refptr.h"
#include "base/run_loop.h"
#include "base/task/single_thread_task_runner.h"
+#include "base/test/bind.h"
#include "base/test/task_environment.h"
#include "base/test/test_future.h"
#include "base/threading/thread_task_runner_handle.h"
@@ -175,8 +176,16 @@ class UsageTrackerTest : public testing::Test {
void OpenDatabase() { quota_manager_->EnsureDatabaseOpened(); }
- void disable_quota_database(bool disable) {
- quota_manager_->database_->SetDisabledForTesting(disable);
+ void DisableQuotaDatabase() {
+ base::RunLoop run_loop;
+ quota_manager_->PostTaskAndReplyWithResultForDBThread(
+ base::BindLambdaForTesting([&](QuotaDatabase* db) {
+ db->SetDisabledForTesting(true);
+ return QuotaError::kNone;
+ }),
+ base::BindLambdaForTesting([&](QuotaError error) { run_loop.Quit(); }),
+ FROM_HERE, /*is_bootstrap_task=*/false);
+ run_loop.Run();
}
void disable_database_bootstrap(bool disable) {
@@ -462,7 +471,7 @@ TEST_F(UsageTrackerTest, QuotaDatabaseDisabled) {
disable_database_bootstrap(true);
OpenDatabase();
- disable_quota_database(true);
+ DisableQuotaDatabase();
int64_t total_usage = 0;
int64_t unlimited_usage = 0;
diff --git a/chromium/storage/common/database/database_identifier.cc b/chromium/storage/common/database/database_identifier.cc
index 9e369f69521..1b23ec9c2f0 100644
--- a/chromium/storage/common/database/database_identifier.cc
+++ b/chromium/storage/common/database/database_identifier.cc
@@ -6,7 +6,6 @@
#include <stddef.h>
-#include "base/cxx17_backports.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
#include "url/url_canon.h"
@@ -116,7 +115,7 @@ DatabaseIdentifier DatabaseIdentifier::Parse(const std::string& identifier) {
if (identifier.find("..") != std::string::npos)
return DatabaseIdentifier();
static const char kForbidden[] = {'\\', '/', ':', '\0'};
- if (identifier.find_first_of(kForbidden, 0, base::size(kForbidden)) !=
+ if (identifier.find_first_of(kForbidden, 0, std::size(kForbidden)) !=
std::string::npos) {
return DatabaseIdentifier();
}
diff --git a/chromium/storage/common/database/database_identifier_unittest.cc b/chromium/storage/common/database/database_identifier_unittest.cc
index 01597087c04..a71b52afaa8 100644
--- a/chromium/storage/common/database/database_identifier_unittest.cc
+++ b/chromium/storage/common/database/database_identifier_unittest.cc
@@ -6,7 +6,6 @@
#include <stddef.h>
-#include "base/cxx17_backports.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
#include "url/origin.h"
@@ -165,7 +164,7 @@ TEST(DatabaseIdentifierTest, CreateIdentifierAllHostChars) {
{"x\x80x", "__0", false},
};
- for (size_t i = 0; i < base::size(cases); ++i) {
+ for (size_t i = 0; i < std::size(cases); ++i) {
GURL origin_url("http://" + cases[i].hostname);
url::Origin origin = url::Origin::Create(origin_url);
DatabaseIdentifier identifier_from_url =
diff --git a/chromium/storage/common/file_system/OWNERS b/chromium/storage/common/file_system/OWNERS
deleted file mode 100644
index d872f10c932..00000000000
--- a/chromium/storage/common/file_system/OWNERS
+++ /dev/null
@@ -1,5 +0,0 @@
-mek@chromium.org
-nhiroki@chromium.org
-
-per-file *_type_converter*.*=set noparent
-per-file *_type_converter*.*=file://ipc/SECURITY_OWNERS