Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=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/. */
7 #include "FileManager.h"
9 #include "mozIStorageConnection.h"
10 #include "mozIStorageStatement.h"
11 #include "nsIInputStream.h"
12 #include "nsISimpleEnumerator.h"
14 #include "mozilla/dom/quota/Utilities.h"
15 #include "mozStorageCID.h"
16 #include "mozStorageHelper.h"
18 #include "Client.h"
19 #include "FileInfo.h"
20 #include "IndexedDatabaseManager.h"
21 #include "OpenDatabaseHelper.h"
23 #include "IndexedDatabaseInlines.h"
24 #include <algorithm>
26 USING_INDEXEDDB_NAMESPACE
27 using mozilla::dom::quota::AssertIsOnIOThread;
29 namespace {
31 PLDHashOperator
32 EnumerateToTArray(const uint64_t& aKey,
33 FileInfo* aValue,
34 void* aUserArg)
35 {
36 NS_ASSERTION(aValue, "Null pointer!");
37 NS_ASSERTION(aUserArg, "Null pointer!");
39 nsTArray<FileInfo*>* array =
40 static_cast<nsTArray<FileInfo*>*>(aUserArg);
42 array->AppendElement(aValue);
44 return PL_DHASH_NEXT;
45 }
47 already_AddRefed<nsIFile>
48 GetDirectoryFor(const nsAString& aDirectoryPath)
49 {
50 nsCOMPtr<nsIFile> directory =
51 do_CreateInstance(NS_LOCAL_FILE_CONTRACTID);
52 NS_ENSURE_TRUE(directory, nullptr);
54 nsresult rv = directory->InitWithPath(aDirectoryPath);
55 NS_ENSURE_SUCCESS(rv, nullptr);
57 return directory.forget();
58 }
60 } // anonymous namespace
62 nsresult
63 FileManager::Init(nsIFile* aDirectory,
64 mozIStorageConnection* aConnection)
65 {
66 AssertIsOnIOThread();
67 NS_ASSERTION(aDirectory, "Null directory!");
68 NS_ASSERTION(aConnection, "Null connection!");
70 bool exists;
71 nsresult rv = aDirectory->Exists(&exists);
72 NS_ENSURE_SUCCESS(rv, rv);
74 if (exists) {
75 bool isDirectory;
76 rv = aDirectory->IsDirectory(&isDirectory);
77 NS_ENSURE_SUCCESS(rv, rv);
78 NS_ENSURE_TRUE(isDirectory, NS_ERROR_FAILURE);
79 }
80 else {
81 rv = aDirectory->Create(nsIFile::DIRECTORY_TYPE, 0755);
82 NS_ENSURE_SUCCESS(rv, rv);
83 }
85 rv = aDirectory->GetPath(mDirectoryPath);
86 NS_ENSURE_SUCCESS(rv, rv);
88 nsCOMPtr<nsIFile> journalDirectory;
89 rv = aDirectory->Clone(getter_AddRefs(journalDirectory));
90 NS_ENSURE_SUCCESS(rv, rv);
92 rv = journalDirectory->Append(NS_LITERAL_STRING(JOURNAL_DIRECTORY_NAME));
93 NS_ENSURE_SUCCESS(rv, rv);
95 rv = journalDirectory->Exists(&exists);
96 NS_ENSURE_SUCCESS(rv, rv);
98 if (exists) {
99 bool isDirectory;
100 rv = journalDirectory->IsDirectory(&isDirectory);
101 NS_ENSURE_SUCCESS(rv, rv);
102 NS_ENSURE_TRUE(isDirectory, NS_ERROR_FAILURE);
103 }
105 rv = journalDirectory->GetPath(mJournalDirectoryPath);
106 NS_ENSURE_SUCCESS(rv, rv);
108 nsCOMPtr<mozIStorageStatement> stmt;
109 rv = aConnection->CreateStatement(NS_LITERAL_CSTRING(
110 "SELECT id, refcount "
111 "FROM file"
112 ), getter_AddRefs(stmt));
113 NS_ENSURE_SUCCESS(rv, rv);
115 bool hasResult;
116 while (NS_SUCCEEDED(stmt->ExecuteStep(&hasResult)) && hasResult) {
117 int64_t id;
118 rv = stmt->GetInt64(0, &id);
119 NS_ENSURE_SUCCESS(rv, rv);
121 int32_t refcount;
122 rv = stmt->GetInt32(1, &refcount);
123 NS_ENSURE_SUCCESS(rv, rv);
125 NS_ASSERTION(refcount, "This shouldn't happen!");
127 nsRefPtr<FileInfo> fileInfo = FileInfo::Create(this, id);
128 fileInfo->mDBRefCnt = refcount;
130 mFileInfos.Put(id, fileInfo);
132 mLastFileId = std::max(id, mLastFileId);
133 }
135 return NS_OK;
136 }
138 nsresult
139 FileManager::Invalidate()
140 {
141 if (IndexedDatabaseManager::IsClosed()) {
142 NS_ERROR("Shouldn't be called after shutdown!");
143 return NS_ERROR_UNEXPECTED;
144 }
146 nsTArray<FileInfo*> fileInfos;
147 {
148 MutexAutoLock lock(IndexedDatabaseManager::FileMutex());
150 NS_ASSERTION(!mInvalidated, "Invalidate more than once?!");
151 mInvalidated = true;
153 fileInfos.SetCapacity(mFileInfos.Count());
154 mFileInfos.EnumerateRead(EnumerateToTArray, &fileInfos);
155 }
157 for (uint32_t i = 0; i < fileInfos.Length(); i++) {
158 FileInfo* fileInfo = fileInfos.ElementAt(i);
159 fileInfo->ClearDBRefs();
160 }
162 return NS_OK;
163 }
165 already_AddRefed<nsIFile>
166 FileManager::GetDirectory()
167 {
168 return GetDirectoryFor(mDirectoryPath);
169 }
171 already_AddRefed<nsIFile>
172 FileManager::GetJournalDirectory()
173 {
174 return GetDirectoryFor(mJournalDirectoryPath);
175 }
177 already_AddRefed<nsIFile>
178 FileManager::EnsureJournalDirectory()
179 {
180 NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
182 nsCOMPtr<nsIFile> journalDirectory = GetDirectoryFor(mJournalDirectoryPath);
183 NS_ENSURE_TRUE(journalDirectory, nullptr);
185 bool exists;
186 nsresult rv = journalDirectory->Exists(&exists);
187 NS_ENSURE_SUCCESS(rv, nullptr);
189 if (exists) {
190 bool isDirectory;
191 rv = journalDirectory->IsDirectory(&isDirectory);
192 NS_ENSURE_SUCCESS(rv, nullptr);
193 NS_ENSURE_TRUE(isDirectory, nullptr);
194 }
195 else {
196 rv = journalDirectory->Create(nsIFile::DIRECTORY_TYPE, 0755);
197 NS_ENSURE_SUCCESS(rv, nullptr);
198 }
200 return journalDirectory.forget();
201 }
203 already_AddRefed<FileInfo>
204 FileManager::GetFileInfo(int64_t aId)
205 {
206 if (IndexedDatabaseManager::IsClosed()) {
207 NS_ERROR("Shouldn't be called after shutdown!");
208 return nullptr;
209 }
211 FileInfo* fileInfo = nullptr;
212 {
213 MutexAutoLock lock(IndexedDatabaseManager::FileMutex());
214 fileInfo = mFileInfos.Get(aId);
215 }
216 nsRefPtr<FileInfo> result = fileInfo;
217 return result.forget();
218 }
220 already_AddRefed<FileInfo>
221 FileManager::GetNewFileInfo()
222 {
223 if (IndexedDatabaseManager::IsClosed()) {
224 NS_ERROR("Shouldn't be called after shutdown!");
225 return nullptr;
226 }
228 nsAutoPtr<FileInfo> fileInfo;
230 {
231 MutexAutoLock lock(IndexedDatabaseManager::FileMutex());
233 int64_t id = mLastFileId + 1;
235 fileInfo = FileInfo::Create(this, id);
237 mFileInfos.Put(id, fileInfo);
239 mLastFileId = id;
240 }
242 nsRefPtr<FileInfo> result = fileInfo.forget();
243 return result.forget();
244 }
246 // static
247 already_AddRefed<nsIFile>
248 FileManager::GetFileForId(nsIFile* aDirectory, int64_t aId)
249 {
250 NS_ASSERTION(aDirectory, "Null pointer!");
252 nsAutoString id;
253 id.AppendInt(aId);
255 nsCOMPtr<nsIFile> file;
256 nsresult rv = aDirectory->Clone(getter_AddRefs(file));
257 NS_ENSURE_SUCCESS(rv, nullptr);
259 rv = file->Append(id);
260 NS_ENSURE_SUCCESS(rv, nullptr);
262 return file.forget();
263 }
265 // static
266 nsresult
267 FileManager::InitDirectory(nsIFile* aDirectory,
268 nsIFile* aDatabaseFile,
269 PersistenceType aPersistenceType,
270 const nsACString& aGroup,
271 const nsACString& aOrigin)
272 {
273 AssertIsOnIOThread();
274 NS_ASSERTION(aDirectory, "Null directory!");
275 NS_ASSERTION(aDatabaseFile, "Null database file!");
277 bool exists;
278 nsresult rv = aDirectory->Exists(&exists);
279 NS_ENSURE_SUCCESS(rv, rv);
281 if (!exists) {
282 return NS_OK;
283 }
285 bool isDirectory;
286 rv = aDirectory->IsDirectory(&isDirectory);
287 NS_ENSURE_SUCCESS(rv, rv);
288 NS_ENSURE_TRUE(isDirectory, NS_ERROR_FAILURE);
290 nsCOMPtr<nsIFile> journalDirectory;
291 rv = aDirectory->Clone(getter_AddRefs(journalDirectory));
292 NS_ENSURE_SUCCESS(rv, rv);
294 rv = journalDirectory->Append(NS_LITERAL_STRING(JOURNAL_DIRECTORY_NAME));
295 NS_ENSURE_SUCCESS(rv, rv);
297 rv = journalDirectory->Exists(&exists);
298 NS_ENSURE_SUCCESS(rv, rv);
300 if (exists) {
301 rv = journalDirectory->IsDirectory(&isDirectory);
302 NS_ENSURE_SUCCESS(rv, rv);
303 NS_ENSURE_TRUE(isDirectory, NS_ERROR_FAILURE);
305 nsCOMPtr<nsISimpleEnumerator> entries;
306 rv = journalDirectory->GetDirectoryEntries(getter_AddRefs(entries));
307 NS_ENSURE_SUCCESS(rv, rv);
309 bool hasElements;
310 rv = entries->HasMoreElements(&hasElements);
311 NS_ENSURE_SUCCESS(rv, rv);
313 if (hasElements) {
314 nsCOMPtr<mozIStorageConnection> connection;
315 rv = OpenDatabaseHelper::CreateDatabaseConnection(aDatabaseFile,
316 aDirectory, NullString(), aPersistenceType, aGroup, aOrigin,
317 getter_AddRefs(connection));
318 NS_ENSURE_SUCCESS(rv, rv);
320 mozStorageTransaction transaction(connection, false);
322 rv = connection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
323 "CREATE VIRTUAL TABLE fs USING filesystem;"
324 ));
325 NS_ENSURE_SUCCESS(rv, rv);
327 nsCOMPtr<mozIStorageStatement> stmt;
328 rv = connection->CreateStatement(NS_LITERAL_CSTRING(
329 "SELECT name, (name IN (SELECT id FROM file)) FROM fs "
330 "WHERE path = :path"
331 ), getter_AddRefs(stmt));
332 NS_ENSURE_SUCCESS(rv, rv);
334 nsString path;
335 rv = journalDirectory->GetPath(path);
336 NS_ENSURE_SUCCESS(rv, rv);
338 rv = stmt->BindStringByName(NS_LITERAL_CSTRING("path"), path);
339 NS_ENSURE_SUCCESS(rv, rv);
341 bool hasResult;
342 while (NS_SUCCEEDED(stmt->ExecuteStep(&hasResult)) && hasResult) {
343 nsString name;
344 rv = stmt->GetString(0, name);
345 NS_ENSURE_SUCCESS(rv, rv);
347 int32_t flag = stmt->AsInt32(1);
349 if (!flag) {
350 nsCOMPtr<nsIFile> file;
351 rv = aDirectory->Clone(getter_AddRefs(file));
352 NS_ENSURE_SUCCESS(rv, rv);
354 rv = file->Append(name);
355 NS_ENSURE_SUCCESS(rv, rv);
357 if (NS_FAILED(file->Remove(false))) {
358 NS_WARNING("Failed to remove orphaned file!");
359 }
360 }
362 nsCOMPtr<nsIFile> journalFile;
363 rv = journalDirectory->Clone(getter_AddRefs(journalFile));
364 NS_ENSURE_SUCCESS(rv, rv);
366 rv = journalFile->Append(name);
367 NS_ENSURE_SUCCESS(rv, rv);
369 if (NS_FAILED(journalFile->Remove(false))) {
370 NS_WARNING("Failed to remove journal file!");
371 }
372 }
374 rv = connection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
375 "DROP TABLE fs;"
376 ));
377 NS_ENSURE_SUCCESS(rv, rv);
379 transaction.Commit();
380 }
381 }
383 return NS_OK;
384 }
386 // static
387 nsresult
388 FileManager::GetUsage(nsIFile* aDirectory, uint64_t* aUsage)
389 {
390 AssertIsOnIOThread();
392 bool exists;
393 nsresult rv = aDirectory->Exists(&exists);
394 NS_ENSURE_SUCCESS(rv, rv);
396 if (!exists) {
397 *aUsage = 0;
398 return NS_OK;
399 }
401 nsCOMPtr<nsISimpleEnumerator> entries;
402 rv = aDirectory->GetDirectoryEntries(getter_AddRefs(entries));
403 NS_ENSURE_SUCCESS(rv, rv);
405 uint64_t usage = 0;
407 bool hasMore;
408 while (NS_SUCCEEDED((rv = entries->HasMoreElements(&hasMore))) && hasMore) {
409 nsCOMPtr<nsISupports> entry;
410 rv = entries->GetNext(getter_AddRefs(entry));
411 NS_ENSURE_SUCCESS(rv, rv);
413 nsCOMPtr<nsIFile> file = do_QueryInterface(entry);
414 NS_ENSURE_TRUE(file, NS_NOINTERFACE);
416 nsString leafName;
417 rv = file->GetLeafName(leafName);
418 NS_ENSURE_SUCCESS(rv, rv);
420 if (leafName.EqualsLiteral(JOURNAL_DIRECTORY_NAME)) {
421 continue;
422 }
424 int64_t fileSize;
425 rv = file->GetFileSize(&fileSize);
426 NS_ENSURE_SUCCESS(rv, rv);
428 quota::IncrementUsage(&usage, uint64_t(fileSize));
429 }
431 *aUsage = usage;
432 return NS_OK;
433 }