| // Copyright 2013 The Chromium Authors |
| // 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/quota/quota_backend_impl.h" |
| |
| #include <stdint.h> |
| |
| #include <algorithm> |
| #include <string> |
| #include <utility> |
| |
| #include "base/check_op.h" |
| #include "base/files/file_error_or.h" |
| #include "base/functional/bind.h" |
| #include "base/functional/callback.h" |
| #include "base/numerics/safe_conversions.h" |
| #include "base/task/sequenced_task_runner.h" |
| #include "base/types/expected_macros.h" |
| #include "storage/browser/file_system/file_system_usage_cache.h" |
| #include "storage/browser/quota/quota_client_type.h" |
| #include "storage/browser/quota/quota_manager_proxy.h" |
| #include "storage/common/file_system/file_system_util.h" |
| #include "third_party/blink/public/common/storage_key/storage_key.h" |
| #include "url/origin.h" |
| |
| namespace storage { |
| |
| QuotaBackendImpl::QuotaBackendImpl( |
| scoped_refptr<base::SequencedTaskRunner> file_task_runner, |
| ObfuscatedFileUtil* obfuscated_file_util, |
| FileSystemUsageCache* file_system_usage_cache, |
| scoped_refptr<QuotaManagerProxy> quota_manager_proxy) |
| : file_task_runner_(std::move(file_task_runner)), |
| obfuscated_file_util_(obfuscated_file_util), |
| file_system_usage_cache_(file_system_usage_cache), |
| quota_manager_proxy_(std::move(quota_manager_proxy)) {} |
| |
| QuotaBackendImpl::~QuotaBackendImpl() = default; |
| |
| void QuotaBackendImpl::ReserveQuota(const url::Origin& origin, |
| FileSystemType type, |
| int64_t delta, |
| ReserveQuotaCallback callback) { |
| DCHECK(file_task_runner_->RunsTasksInCurrentSequence()); |
| DCHECK(!origin.opaque()); |
| if (!delta) { |
| std::move(callback).Run(base::File::FILE_OK, 0); |
| return; |
| } |
| DCHECK(quota_manager_proxy_.get()); |
| quota_manager_proxy_->GetUsageAndQuota( |
| blink::StorageKey::CreateFirstParty(origin), file_task_runner_, |
| base::BindOnce(&QuotaBackendImpl::DidGetUsageAndQuotaForReserveQuota, |
| weak_ptr_factory_.GetWeakPtr(), |
| QuotaReservationInfo(origin, type, delta), |
| std::move(callback))); |
| } |
| |
| void QuotaBackendImpl::ReleaseReservedQuota(const url::Origin& origin, |
| FileSystemType type, |
| int64_t size) { |
| DCHECK(file_task_runner_->RunsTasksInCurrentSequence()); |
| DCHECK(!origin.opaque()); |
| DCHECK_LE(0, size); |
| if (!size) |
| return; |
| ReserveQuotaInternal(QuotaReservationInfo(origin, type, -size)); |
| } |
| |
| void QuotaBackendImpl::CommitQuotaUsage(const url::Origin& origin, |
| FileSystemType type, |
| int64_t delta) { |
| DCHECK(file_task_runner_->RunsTasksInCurrentSequence()); |
| DCHECK(!origin.opaque()); |
| if (!delta) |
| return; |
| ReserveQuotaInternal(QuotaReservationInfo(origin, type, delta)); |
| ASSIGN_OR_RETURN(base::FilePath path, GetUsageCachePath(origin, type), |
| [](auto) {}); |
| bool result = file_system_usage_cache_->AtomicUpdateUsageByDelta( |
| std::move(path), delta); |
| DCHECK(result); |
| } |
| |
| void QuotaBackendImpl::IncrementDirtyCount(const url::Origin& origin, |
| FileSystemType type) { |
| DCHECK(file_task_runner_->RunsTasksInCurrentSequence()); |
| DCHECK(!origin.opaque()); |
| ASSIGN_OR_RETURN(base::FilePath path, GetUsageCachePath(origin, type), |
| [](auto) {}); |
| DCHECK(file_system_usage_cache_); |
| file_system_usage_cache_->IncrementDirty(std::move(path)); |
| } |
| |
| void QuotaBackendImpl::DecrementDirtyCount(const url::Origin& origin, |
| FileSystemType type) { |
| DCHECK(file_task_runner_->RunsTasksInCurrentSequence()); |
| DCHECK(!origin.opaque()); |
| ASSIGN_OR_RETURN(base::FilePath path, GetUsageCachePath(origin, type), |
| [](auto) {}); |
| DCHECK(file_system_usage_cache_); |
| file_system_usage_cache_->DecrementDirty(std::move(path)); |
| } |
| |
| void QuotaBackendImpl::DidGetUsageAndQuotaForReserveQuota( |
| const QuotaReservationInfo& info, |
| ReserveQuotaCallback callback, |
| blink::mojom::QuotaStatusCode status, |
| int64_t usage, |
| int64_t quota) { |
| DCHECK(file_task_runner_->RunsTasksInCurrentSequence()); |
| DCHECK(!info.origin.opaque()); |
| DCHECK_LE(0, usage); |
| DCHECK_LE(0, quota); |
| if (status != blink::mojom::QuotaStatusCode::kOk) { |
| std::move(callback).Run(base::File::FILE_ERROR_FAILED, 0); |
| return; |
| } |
| |
| QuotaReservationInfo normalized_info = info; |
| if (info.delta > 0) { |
| int64_t new_usage = base::saturated_cast<int64_t>( |
| usage + static_cast<uint64_t>(info.delta)); |
| if (quota < new_usage) |
| new_usage = quota; |
| normalized_info.delta = |
| std::max(static_cast<int64_t>(0), new_usage - usage); |
| } |
| |
| ReserveQuotaInternal(normalized_info); |
| if (std::move(callback).Run(base::File::FILE_OK, normalized_info.delta)) |
| return; |
| // The requester could not accept the reserved quota. Revert it. |
| ReserveQuotaInternal(QuotaReservationInfo( |
| normalized_info.origin, normalized_info.type, -normalized_info.delta)); |
| } |
| |
| void QuotaBackendImpl::ReserveQuotaInternal(const QuotaReservationInfo& info) { |
| DCHECK(file_task_runner_->RunsTasksInCurrentSequence()); |
| DCHECK(!info.origin.opaque()); |
| DCHECK(quota_manager_proxy_.get()); |
| auto bucket = BucketLocator::ForDefaultBucket( |
| blink::StorageKey::CreateFirstParty(info.origin)); |
| quota_manager_proxy_->NotifyBucketModified( |
| QuotaClientType::kFileSystem, bucket, info.delta, base::Time::Now(), |
| base::SequencedTaskRunner::GetCurrentDefault(), base::DoNothing()); |
| } |
| |
| base::FileErrorOr<base::FilePath> QuotaBackendImpl::GetUsageCachePath( |
| const url::Origin& origin, |
| FileSystemType type) { |
| DCHECK(file_task_runner_->RunsTasksInCurrentSequence()); |
| DCHECK(!origin.opaque()); |
| return SandboxFileSystemBackendDelegate:: |
| GetUsageCachePathForStorageKeyAndType( |
| obfuscated_file_util_, blink::StorageKey::CreateFirstParty(origin), |
| type); |
| } |
| |
| QuotaBackendImpl::QuotaReservationInfo::QuotaReservationInfo( |
| const url::Origin& origin, |
| FileSystemType type, |
| int64_t delta) |
| : origin(origin), type(type), delta(delta) {} |
| |
| QuotaBackendImpl::QuotaReservationInfo::~QuotaReservationInfo() = default; |
| |
| } // namespace storage |