1 // Copyright 2013 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "webkit/browser/fileapi/quota/quota_backend_impl.h" 6 7 #include <string> 8 9 #include "base/bind.h" 10 #include "base/callback.h" 11 #include "base/logging.h" 12 #include "base/numerics/safe_conversions.h" 13 #include "base/sequenced_task_runner.h" 14 #include "webkit/browser/fileapi/file_system_usage_cache.h" 15 #include "webkit/browser/quota/quota_client.h" 16 #include "webkit/browser/quota/quota_manager_proxy.h" 17 #include "webkit/common/fileapi/file_system_util.h" 18 19 namespace fileapi { 20 21 QuotaBackendImpl::QuotaBackendImpl( 22 base::SequencedTaskRunner* file_task_runner, 23 ObfuscatedFileUtil* obfuscated_file_util, 24 FileSystemUsageCache* file_system_usage_cache, 25 quota::QuotaManagerProxy* quota_manager_proxy) 26 : file_task_runner_(file_task_runner), 27 obfuscated_file_util_(obfuscated_file_util), 28 file_system_usage_cache_(file_system_usage_cache), 29 quota_manager_proxy_(quota_manager_proxy), 30 weak_ptr_factory_(this) { 31 } 32 33 QuotaBackendImpl::~QuotaBackendImpl() { 34 } 35 36 void QuotaBackendImpl::ReserveQuota(const GURL& origin, 37 FileSystemType type, 38 int64 delta, 39 const ReserveQuotaCallback& callback) { 40 DCHECK(file_task_runner_->RunsTasksOnCurrentThread()); 41 DCHECK(origin.is_valid()); 42 if (!delta) { 43 callback.Run(base::File::FILE_OK, 0); 44 return; 45 } 46 DCHECK(quota_manager_proxy_); 47 quota_manager_proxy_->GetUsageAndQuota( 48 file_task_runner_, origin, FileSystemTypeToQuotaStorageType(type), 49 base::Bind(&QuotaBackendImpl::DidGetUsageAndQuotaForReserveQuota, 50 weak_ptr_factory_.GetWeakPtr(), 51 QuotaReservationInfo(origin, type, delta), callback)); 52 } 53 54 void QuotaBackendImpl::ReleaseReservedQuota(const GURL& origin, 55 FileSystemType type, 56 int64 size) { 57 DCHECK(file_task_runner_->RunsTasksOnCurrentThread()); 58 DCHECK(origin.is_valid()); 59 DCHECK_LE(0, size); 60 if (!size) 61 return; 62 ReserveQuotaInternal(QuotaReservationInfo(origin, type, -size)); 63 } 64 65 void QuotaBackendImpl::CommitQuotaUsage(const GURL& origin, 66 FileSystemType type, 67 int64 delta) { 68 DCHECK(file_task_runner_->RunsTasksOnCurrentThread()); 69 DCHECK(origin.is_valid()); 70 if (!delta) 71 return; 72 ReserveQuotaInternal(QuotaReservationInfo(origin, type, delta)); 73 base::FilePath path; 74 if (GetUsageCachePath(origin, type, &path) != base::File::FILE_OK) 75 return; 76 bool result = file_system_usage_cache_->AtomicUpdateUsageByDelta(path, delta); 77 DCHECK(result); 78 } 79 80 void QuotaBackendImpl::IncrementDirtyCount(const GURL& origin, 81 FileSystemType type) { 82 DCHECK(file_task_runner_->RunsTasksOnCurrentThread()); 83 DCHECK(origin.is_valid()); 84 base::FilePath path; 85 if (GetUsageCachePath(origin, type, &path) != base::File::FILE_OK) 86 return; 87 DCHECK(file_system_usage_cache_); 88 file_system_usage_cache_->IncrementDirty(path); 89 } 90 91 void QuotaBackendImpl::DecrementDirtyCount(const GURL& origin, 92 FileSystemType type) { 93 DCHECK(file_task_runner_->RunsTasksOnCurrentThread()); 94 DCHECK(origin.is_valid()); 95 base::FilePath path; 96 if (GetUsageCachePath(origin, type, &path) != base::File::FILE_OK) 97 return; 98 DCHECK(file_system_usage_cache_); 99 file_system_usage_cache_->DecrementDirty(path); 100 } 101 102 void QuotaBackendImpl::DidGetUsageAndQuotaForReserveQuota( 103 const QuotaReservationInfo& info, 104 const ReserveQuotaCallback& callback, 105 quota::QuotaStatusCode status, int64 usage, int64 quota) { 106 DCHECK(file_task_runner_->RunsTasksOnCurrentThread()); 107 DCHECK(info.origin.is_valid()); 108 DCHECK_LE(0, usage); 109 DCHECK_LE(0, quota); 110 if (status != quota::kQuotaStatusOk) { 111 callback.Run(base::File::FILE_ERROR_FAILED, 0); 112 return; 113 } 114 115 QuotaReservationInfo normalized_info = info; 116 if (info.delta > 0) { 117 int64 new_usage = 118 base::saturated_cast<int64>(usage + static_cast<uint64>(info.delta)); 119 if (quota < new_usage) 120 new_usage = quota; 121 normalized_info.delta = std::max(static_cast<int64>(0), new_usage - usage); 122 } 123 124 ReserveQuotaInternal(normalized_info); 125 if (callback.Run(base::File::FILE_OK, normalized_info.delta)) 126 return; 127 // The requester could not accept the reserved quota. Revert it. 128 ReserveQuotaInternal( 129 QuotaReservationInfo(normalized_info.origin, 130 normalized_info.type, 131 -normalized_info.delta)); 132 } 133 134 void QuotaBackendImpl::ReserveQuotaInternal(const QuotaReservationInfo& info) { 135 DCHECK(file_task_runner_->RunsTasksOnCurrentThread()); 136 DCHECK(info.origin.is_valid()); 137 DCHECK(quota_manager_proxy_); 138 quota_manager_proxy_->NotifyStorageModified( 139 quota::QuotaClient::kFileSystem, info.origin, 140 FileSystemTypeToQuotaStorageType(info.type), info.delta); 141 } 142 143 base::File::Error QuotaBackendImpl::GetUsageCachePath( 144 const GURL& origin, 145 FileSystemType type, 146 base::FilePath* usage_file_path) { 147 DCHECK(file_task_runner_->RunsTasksOnCurrentThread()); 148 DCHECK(origin.is_valid()); 149 DCHECK(usage_file_path); 150 base::File::Error error = base::File::FILE_OK; 151 *usage_file_path = 152 SandboxFileSystemBackendDelegate::GetUsageCachePathForOriginAndType( 153 obfuscated_file_util_, origin, type, &error); 154 return error; 155 } 156 157 QuotaBackendImpl::QuotaReservationInfo::QuotaReservationInfo( 158 const GURL& origin, FileSystemType type, int64 delta) 159 : origin(origin), type(type), delta(delta) { 160 } 161 162 QuotaBackendImpl::QuotaReservationInfo::~QuotaReservationInfo() { 163 } 164 165 } // namespace fileapi 166