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 "storage/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 "storage/browser/fileapi/file_system_usage_cache.h"
15#include "storage/browser/quota/quota_client.h"
16#include "storage/browser/quota/quota_manager_proxy.h"
17#include "storage/common/fileapi/file_system_util.h"
18
19namespace storage {
20
21QuotaBackendImpl::QuotaBackendImpl(
22    base::SequencedTaskRunner* file_task_runner,
23    ObfuscatedFileUtil* obfuscated_file_util,
24    FileSystemUsageCache* file_system_usage_cache,
25    storage::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
33QuotaBackendImpl::~QuotaBackendImpl() {
34}
35
36void 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_.get());
47  quota_manager_proxy_->GetUsageAndQuota(
48      file_task_runner_.get(),
49      origin,
50      FileSystemTypeToQuotaStorageType(type),
51      base::Bind(&QuotaBackendImpl::DidGetUsageAndQuotaForReserveQuota,
52                 weak_ptr_factory_.GetWeakPtr(),
53                 QuotaReservationInfo(origin, type, delta),
54                 callback));
55}
56
57void QuotaBackendImpl::ReleaseReservedQuota(const GURL& origin,
58                                            FileSystemType type,
59                                            int64 size) {
60  DCHECK(file_task_runner_->RunsTasksOnCurrentThread());
61  DCHECK(origin.is_valid());
62  DCHECK_LE(0, size);
63  if (!size)
64    return;
65  ReserveQuotaInternal(QuotaReservationInfo(origin, type, -size));
66}
67
68void QuotaBackendImpl::CommitQuotaUsage(const GURL& origin,
69                                        FileSystemType type,
70                                        int64 delta) {
71  DCHECK(file_task_runner_->RunsTasksOnCurrentThread());
72  DCHECK(origin.is_valid());
73  if (!delta)
74    return;
75  ReserveQuotaInternal(QuotaReservationInfo(origin, type, delta));
76  base::FilePath path;
77  if (GetUsageCachePath(origin, type, &path) != base::File::FILE_OK)
78    return;
79  bool result = file_system_usage_cache_->AtomicUpdateUsageByDelta(path, delta);
80  DCHECK(result);
81}
82
83void QuotaBackendImpl::IncrementDirtyCount(const GURL& origin,
84                                           FileSystemType type) {
85  DCHECK(file_task_runner_->RunsTasksOnCurrentThread());
86  DCHECK(origin.is_valid());
87  base::FilePath path;
88  if (GetUsageCachePath(origin, type, &path) != base::File::FILE_OK)
89    return;
90  DCHECK(file_system_usage_cache_);
91  file_system_usage_cache_->IncrementDirty(path);
92}
93
94void QuotaBackendImpl::DecrementDirtyCount(const GURL& origin,
95                                           FileSystemType type) {
96  DCHECK(file_task_runner_->RunsTasksOnCurrentThread());
97  DCHECK(origin.is_valid());
98  base::FilePath path;
99  if (GetUsageCachePath(origin, type, &path) != base::File::FILE_OK)
100    return;
101  DCHECK(file_system_usage_cache_);
102  file_system_usage_cache_->DecrementDirty(path);
103}
104
105void QuotaBackendImpl::DidGetUsageAndQuotaForReserveQuota(
106    const QuotaReservationInfo& info,
107    const ReserveQuotaCallback& callback,
108    storage::QuotaStatusCode status,
109    int64 usage,
110    int64 quota) {
111  DCHECK(file_task_runner_->RunsTasksOnCurrentThread());
112  DCHECK(info.origin.is_valid());
113  DCHECK_LE(0, usage);
114  DCHECK_LE(0, quota);
115  if (status != storage::kQuotaStatusOk) {
116    callback.Run(base::File::FILE_ERROR_FAILED, 0);
117    return;
118  }
119
120  QuotaReservationInfo normalized_info = info;
121  if (info.delta > 0) {
122    int64 new_usage =
123        base::saturated_cast<int64>(usage + static_cast<uint64>(info.delta));
124    if (quota < new_usage)
125      new_usage = quota;
126    normalized_info.delta = std::max(static_cast<int64>(0), new_usage - usage);
127  }
128
129  ReserveQuotaInternal(normalized_info);
130  if (callback.Run(base::File::FILE_OK, normalized_info.delta))
131    return;
132  // The requester could not accept the reserved quota. Revert it.
133  ReserveQuotaInternal(
134      QuotaReservationInfo(normalized_info.origin,
135                           normalized_info.type,
136                           -normalized_info.delta));
137}
138
139void QuotaBackendImpl::ReserveQuotaInternal(const QuotaReservationInfo& info) {
140  DCHECK(file_task_runner_->RunsTasksOnCurrentThread());
141  DCHECK(info.origin.is_valid());
142  DCHECK(quota_manager_proxy_.get());
143  quota_manager_proxy_->NotifyStorageModified(
144      storage::QuotaClient::kFileSystem,
145      info.origin,
146      FileSystemTypeToQuotaStorageType(info.type),
147      info.delta);
148}
149
150base::File::Error QuotaBackendImpl::GetUsageCachePath(
151    const GURL& origin,
152    FileSystemType type,
153    base::FilePath* usage_file_path) {
154  DCHECK(file_task_runner_->RunsTasksOnCurrentThread());
155  DCHECK(origin.is_valid());
156  DCHECK(usage_file_path);
157  base::File::Error error = base::File::FILE_OK;
158  *usage_file_path =
159      SandboxFileSystemBackendDelegate::GetUsageCachePathForOriginAndType(
160          obfuscated_file_util_, origin, type, &error);
161  return error;
162}
163
164QuotaBackendImpl::QuotaReservationInfo::QuotaReservationInfo(
165    const GURL& origin, FileSystemType type, int64 delta)
166    : origin(origin), type(type), delta(delta) {
167}
168
169QuotaBackendImpl::QuotaReservationInfo::~QuotaReservationInfo() {
170}
171
172}  // namespace storage
173