Line data Source code
1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 : /* This Source Code Form is subject to the terms of the Mozilla Public
4 : * License, v. 2.0. If a copy of the MPL was not distributed with this
5 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 :
7 : #include "mozilla/dom/cache/QuotaClient.h"
8 :
9 : #include "mozilla/dom/cache/Manager.h"
10 : #include "mozilla/dom/quota/QuotaManager.h"
11 : #include "mozilla/dom/quota/UsageInfo.h"
12 : #include "mozilla/ipc/BackgroundParent.h"
13 : #include "nsIFile.h"
14 : #include "nsISimpleEnumerator.h"
15 : #include "nsThreadUtils.h"
16 :
17 : namespace {
18 :
19 : using mozilla::Atomic;
20 : using mozilla::dom::ContentParentId;
21 : using mozilla::dom::cache::Manager;
22 : using mozilla::dom::quota::Client;
23 : using mozilla::dom::quota::PersistenceType;
24 : using mozilla::dom::quota::QuotaManager;
25 : using mozilla::dom::quota::UsageInfo;
26 : using mozilla::ipc::AssertIsOnBackgroundThread;
27 :
28 : static nsresult
29 0 : GetBodyUsage(nsIFile* aDir, const Atomic<bool>& aCanceled,
30 : UsageInfo* aUsageInfo)
31 : {
32 0 : nsCOMPtr<nsISimpleEnumerator> entries;
33 0 : nsresult rv = aDir->GetDirectoryEntries(getter_AddRefs(entries));
34 0 : if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
35 :
36 : bool hasMore;
37 0 : while (NS_SUCCEEDED(rv = entries->HasMoreElements(&hasMore)) && hasMore &&
38 0 : !aCanceled) {
39 0 : nsCOMPtr<nsISupports> entry;
40 0 : rv = entries->GetNext(getter_AddRefs(entry));
41 0 : if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
42 :
43 0 : nsCOMPtr<nsIFile> file = do_QueryInterface(entry);
44 :
45 : bool isDir;
46 0 : rv = file->IsDirectory(&isDir);
47 0 : if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
48 :
49 0 : if (isDir) {
50 0 : rv = GetBodyUsage(file, aCanceled, aUsageInfo);
51 0 : if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
52 0 : continue;
53 : }
54 :
55 : int64_t fileSize;
56 0 : rv = file->GetFileSize(&fileSize);
57 0 : if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
58 0 : MOZ_DIAGNOSTIC_ASSERT(fileSize >= 0);
59 :
60 0 : aUsageInfo->AppendToFileUsage(fileSize);
61 : }
62 :
63 0 : return NS_OK;
64 : }
65 :
66 0 : class CacheQuotaClient final : public Client
67 : {
68 : public:
69 : virtual Type
70 0 : GetType() override
71 : {
72 0 : return DOMCACHE;
73 : }
74 :
75 : virtual nsresult
76 0 : InitOrigin(PersistenceType aPersistenceType, const nsACString& aGroup,
77 : const nsACString& aOrigin, const AtomicBool& aCanceled,
78 : UsageInfo* aUsageInfo) override
79 : {
80 : // The QuotaManager passes a nullptr UsageInfo if there is no quota being
81 : // enforced against the origin.
82 0 : if (!aUsageInfo) {
83 0 : return NS_OK;
84 : }
85 :
86 : return GetUsageForOrigin(aPersistenceType, aGroup, aOrigin, aCanceled,
87 0 : aUsageInfo);
88 : }
89 :
90 : virtual nsresult
91 0 : GetUsageForOrigin(PersistenceType aPersistenceType, const nsACString& aGroup,
92 : const nsACString& aOrigin, const AtomicBool& aCanceled,
93 : UsageInfo* aUsageInfo) override
94 : {
95 0 : MOZ_DIAGNOSTIC_ASSERT(aUsageInfo);
96 :
97 0 : QuotaManager* qm = QuotaManager::Get();
98 0 : MOZ_DIAGNOSTIC_ASSERT(qm);
99 :
100 0 : nsCOMPtr<nsIFile> dir;
101 0 : nsresult rv = qm->GetDirectoryForOrigin(aPersistenceType, aOrigin,
102 0 : getter_AddRefs(dir));
103 0 : if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
104 :
105 0 : rv = dir->Append(NS_LITERAL_STRING(DOMCACHE_DIRECTORY_NAME));
106 0 : if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
107 :
108 0 : nsCOMPtr<nsISimpleEnumerator> entries;
109 0 : rv = dir->GetDirectoryEntries(getter_AddRefs(entries));
110 0 : if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
111 :
112 : bool hasMore;
113 0 : while (NS_SUCCEEDED(rv = entries->HasMoreElements(&hasMore)) && hasMore &&
114 0 : !aCanceled) {
115 0 : nsCOMPtr<nsISupports> entry;
116 0 : rv = entries->GetNext(getter_AddRefs(entry));
117 0 : if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
118 :
119 0 : nsCOMPtr<nsIFile> file = do_QueryInterface(entry);
120 :
121 0 : nsAutoString leafName;
122 0 : rv = file->GetLeafName(leafName);
123 0 : if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
124 :
125 : bool isDir;
126 0 : rv = file->IsDirectory(&isDir);
127 0 : if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
128 :
129 0 : if (isDir) {
130 0 : if (leafName.EqualsLiteral("morgue")) {
131 0 : rv = GetBodyUsage(file, aCanceled, aUsageInfo);
132 0 : if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
133 : } else {
134 0 : NS_WARNING("Unknown Cache directory found!");
135 : }
136 :
137 0 : continue;
138 : }
139 :
140 : // Ignore transient sqlite files and marker files
141 0 : if (leafName.EqualsLiteral("caches.sqlite-journal") ||
142 0 : leafName.EqualsLiteral("caches.sqlite-shm") ||
143 0 : leafName.Find(NS_LITERAL_CSTRING("caches.sqlite-mj"), false, 0, 0) == 0 ||
144 0 : leafName.EqualsLiteral("context_open.marker")) {
145 0 : continue;
146 : }
147 :
148 0 : if (leafName.EqualsLiteral("caches.sqlite") ||
149 0 : leafName.EqualsLiteral("caches.sqlite-wal")) {
150 : int64_t fileSize;
151 0 : rv = file->GetFileSize(&fileSize);
152 0 : if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
153 0 : MOZ_DIAGNOSTIC_ASSERT(fileSize >= 0);
154 :
155 0 : aUsageInfo->AppendToDatabaseUsage(fileSize);
156 0 : continue;
157 : }
158 :
159 0 : NS_WARNING("Unknown Cache file found!");
160 : }
161 :
162 0 : return NS_OK;
163 : }
164 :
165 : virtual void
166 0 : OnOriginClearCompleted(PersistenceType aPersistenceType,
167 : const nsACString& aOrigin) override
168 : {
169 : // Nothing to do here.
170 0 : }
171 :
172 : virtual void
173 0 : ReleaseIOThreadObjects() override
174 : {
175 : // Nothing to do here as the Context handles cleaning everything up
176 : // automatically.
177 0 : }
178 :
179 : virtual void
180 0 : AbortOperations(const nsACString& aOrigin) override
181 : {
182 0 : AssertIsOnBackgroundThread();
183 :
184 0 : Manager::Abort(aOrigin);
185 0 : }
186 :
187 : virtual void
188 0 : AbortOperationsForProcess(ContentParentId aContentParentId) override
189 : {
190 : // The Cache and Context can be shared by multiple client processes. They
191 : // are not exclusively owned by a single process.
192 : //
193 : // As far as I can tell this is used by QuotaManager to abort operations
194 : // when a particular process goes away. We definitely don't want this
195 : // since we are shared. Also, the Cache actor code already properly
196 : // handles asynchronous actor destruction when the child process dies.
197 : //
198 : // Therefore, do nothing here.
199 0 : }
200 :
201 : virtual void
202 0 : StartIdleMaintenance() override
203 0 : { }
204 :
205 : virtual void
206 0 : StopIdleMaintenance() override
207 0 : { }
208 :
209 : virtual void
210 0 : ShutdownWorkThreads() override
211 : {
212 0 : AssertIsOnBackgroundThread();
213 :
214 : // spins the event loop and synchronously shuts down all Managers
215 0 : Manager::ShutdownAll();
216 0 : }
217 :
218 : private:
219 0 : ~CacheQuotaClient()
220 0 : {
221 0 : AssertIsOnBackgroundThread();
222 0 : }
223 :
224 0 : NS_INLINE_DECL_REFCOUNTING(CacheQuotaClient, override)
225 : };
226 :
227 : } // namespace
228 :
229 : namespace mozilla {
230 : namespace dom {
231 : namespace cache {
232 :
233 0 : already_AddRefed<quota::Client> CreateQuotaClient()
234 : {
235 0 : AssertIsOnBackgroundThread();
236 :
237 0 : RefPtr<CacheQuotaClient> ref = new CacheQuotaClient();
238 0 : return ref.forget();
239 : }
240 :
241 : } // namespace cache
242 : } // namespace dom
243 : } // namespace mozilla
|