dom/indexedDB/FileManager.cpp

Wed, 31 Dec 2014 06:55:50 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:55:50 +0100
changeset 2
7e26c7da4463
permissions
-rw-r--r--

Added tag UPSTREAM_283F7C6 for changeset ca08bd8f51b2

michael@0 1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
michael@0 2 /* vim: set ts=2 et sw=2 tw=80: */
michael@0 3 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 4 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 6
michael@0 7 #include "FileManager.h"
michael@0 8
michael@0 9 #include "mozIStorageConnection.h"
michael@0 10 #include "mozIStorageStatement.h"
michael@0 11 #include "nsIInputStream.h"
michael@0 12 #include "nsISimpleEnumerator.h"
michael@0 13
michael@0 14 #include "mozilla/dom/quota/Utilities.h"
michael@0 15 #include "mozStorageCID.h"
michael@0 16 #include "mozStorageHelper.h"
michael@0 17
michael@0 18 #include "Client.h"
michael@0 19 #include "FileInfo.h"
michael@0 20 #include "IndexedDatabaseManager.h"
michael@0 21 #include "OpenDatabaseHelper.h"
michael@0 22
michael@0 23 #include "IndexedDatabaseInlines.h"
michael@0 24 #include <algorithm>
michael@0 25
michael@0 26 USING_INDEXEDDB_NAMESPACE
michael@0 27 using mozilla::dom::quota::AssertIsOnIOThread;
michael@0 28
michael@0 29 namespace {
michael@0 30
michael@0 31 PLDHashOperator
michael@0 32 EnumerateToTArray(const uint64_t& aKey,
michael@0 33 FileInfo* aValue,
michael@0 34 void* aUserArg)
michael@0 35 {
michael@0 36 NS_ASSERTION(aValue, "Null pointer!");
michael@0 37 NS_ASSERTION(aUserArg, "Null pointer!");
michael@0 38
michael@0 39 nsTArray<FileInfo*>* array =
michael@0 40 static_cast<nsTArray<FileInfo*>*>(aUserArg);
michael@0 41
michael@0 42 array->AppendElement(aValue);
michael@0 43
michael@0 44 return PL_DHASH_NEXT;
michael@0 45 }
michael@0 46
michael@0 47 already_AddRefed<nsIFile>
michael@0 48 GetDirectoryFor(const nsAString& aDirectoryPath)
michael@0 49 {
michael@0 50 nsCOMPtr<nsIFile> directory =
michael@0 51 do_CreateInstance(NS_LOCAL_FILE_CONTRACTID);
michael@0 52 NS_ENSURE_TRUE(directory, nullptr);
michael@0 53
michael@0 54 nsresult rv = directory->InitWithPath(aDirectoryPath);
michael@0 55 NS_ENSURE_SUCCESS(rv, nullptr);
michael@0 56
michael@0 57 return directory.forget();
michael@0 58 }
michael@0 59
michael@0 60 } // anonymous namespace
michael@0 61
michael@0 62 nsresult
michael@0 63 FileManager::Init(nsIFile* aDirectory,
michael@0 64 mozIStorageConnection* aConnection)
michael@0 65 {
michael@0 66 AssertIsOnIOThread();
michael@0 67 NS_ASSERTION(aDirectory, "Null directory!");
michael@0 68 NS_ASSERTION(aConnection, "Null connection!");
michael@0 69
michael@0 70 bool exists;
michael@0 71 nsresult rv = aDirectory->Exists(&exists);
michael@0 72 NS_ENSURE_SUCCESS(rv, rv);
michael@0 73
michael@0 74 if (exists) {
michael@0 75 bool isDirectory;
michael@0 76 rv = aDirectory->IsDirectory(&isDirectory);
michael@0 77 NS_ENSURE_SUCCESS(rv, rv);
michael@0 78 NS_ENSURE_TRUE(isDirectory, NS_ERROR_FAILURE);
michael@0 79 }
michael@0 80 else {
michael@0 81 rv = aDirectory->Create(nsIFile::DIRECTORY_TYPE, 0755);
michael@0 82 NS_ENSURE_SUCCESS(rv, rv);
michael@0 83 }
michael@0 84
michael@0 85 rv = aDirectory->GetPath(mDirectoryPath);
michael@0 86 NS_ENSURE_SUCCESS(rv, rv);
michael@0 87
michael@0 88 nsCOMPtr<nsIFile> journalDirectory;
michael@0 89 rv = aDirectory->Clone(getter_AddRefs(journalDirectory));
michael@0 90 NS_ENSURE_SUCCESS(rv, rv);
michael@0 91
michael@0 92 rv = journalDirectory->Append(NS_LITERAL_STRING(JOURNAL_DIRECTORY_NAME));
michael@0 93 NS_ENSURE_SUCCESS(rv, rv);
michael@0 94
michael@0 95 rv = journalDirectory->Exists(&exists);
michael@0 96 NS_ENSURE_SUCCESS(rv, rv);
michael@0 97
michael@0 98 if (exists) {
michael@0 99 bool isDirectory;
michael@0 100 rv = journalDirectory->IsDirectory(&isDirectory);
michael@0 101 NS_ENSURE_SUCCESS(rv, rv);
michael@0 102 NS_ENSURE_TRUE(isDirectory, NS_ERROR_FAILURE);
michael@0 103 }
michael@0 104
michael@0 105 rv = journalDirectory->GetPath(mJournalDirectoryPath);
michael@0 106 NS_ENSURE_SUCCESS(rv, rv);
michael@0 107
michael@0 108 nsCOMPtr<mozIStorageStatement> stmt;
michael@0 109 rv = aConnection->CreateStatement(NS_LITERAL_CSTRING(
michael@0 110 "SELECT id, refcount "
michael@0 111 "FROM file"
michael@0 112 ), getter_AddRefs(stmt));
michael@0 113 NS_ENSURE_SUCCESS(rv, rv);
michael@0 114
michael@0 115 bool hasResult;
michael@0 116 while (NS_SUCCEEDED(stmt->ExecuteStep(&hasResult)) && hasResult) {
michael@0 117 int64_t id;
michael@0 118 rv = stmt->GetInt64(0, &id);
michael@0 119 NS_ENSURE_SUCCESS(rv, rv);
michael@0 120
michael@0 121 int32_t refcount;
michael@0 122 rv = stmt->GetInt32(1, &refcount);
michael@0 123 NS_ENSURE_SUCCESS(rv, rv);
michael@0 124
michael@0 125 NS_ASSERTION(refcount, "This shouldn't happen!");
michael@0 126
michael@0 127 nsRefPtr<FileInfo> fileInfo = FileInfo::Create(this, id);
michael@0 128 fileInfo->mDBRefCnt = refcount;
michael@0 129
michael@0 130 mFileInfos.Put(id, fileInfo);
michael@0 131
michael@0 132 mLastFileId = std::max(id, mLastFileId);
michael@0 133 }
michael@0 134
michael@0 135 return NS_OK;
michael@0 136 }
michael@0 137
michael@0 138 nsresult
michael@0 139 FileManager::Invalidate()
michael@0 140 {
michael@0 141 if (IndexedDatabaseManager::IsClosed()) {
michael@0 142 NS_ERROR("Shouldn't be called after shutdown!");
michael@0 143 return NS_ERROR_UNEXPECTED;
michael@0 144 }
michael@0 145
michael@0 146 nsTArray<FileInfo*> fileInfos;
michael@0 147 {
michael@0 148 MutexAutoLock lock(IndexedDatabaseManager::FileMutex());
michael@0 149
michael@0 150 NS_ASSERTION(!mInvalidated, "Invalidate more than once?!");
michael@0 151 mInvalidated = true;
michael@0 152
michael@0 153 fileInfos.SetCapacity(mFileInfos.Count());
michael@0 154 mFileInfos.EnumerateRead(EnumerateToTArray, &fileInfos);
michael@0 155 }
michael@0 156
michael@0 157 for (uint32_t i = 0; i < fileInfos.Length(); i++) {
michael@0 158 FileInfo* fileInfo = fileInfos.ElementAt(i);
michael@0 159 fileInfo->ClearDBRefs();
michael@0 160 }
michael@0 161
michael@0 162 return NS_OK;
michael@0 163 }
michael@0 164
michael@0 165 already_AddRefed<nsIFile>
michael@0 166 FileManager::GetDirectory()
michael@0 167 {
michael@0 168 return GetDirectoryFor(mDirectoryPath);
michael@0 169 }
michael@0 170
michael@0 171 already_AddRefed<nsIFile>
michael@0 172 FileManager::GetJournalDirectory()
michael@0 173 {
michael@0 174 return GetDirectoryFor(mJournalDirectoryPath);
michael@0 175 }
michael@0 176
michael@0 177 already_AddRefed<nsIFile>
michael@0 178 FileManager::EnsureJournalDirectory()
michael@0 179 {
michael@0 180 NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
michael@0 181
michael@0 182 nsCOMPtr<nsIFile> journalDirectory = GetDirectoryFor(mJournalDirectoryPath);
michael@0 183 NS_ENSURE_TRUE(journalDirectory, nullptr);
michael@0 184
michael@0 185 bool exists;
michael@0 186 nsresult rv = journalDirectory->Exists(&exists);
michael@0 187 NS_ENSURE_SUCCESS(rv, nullptr);
michael@0 188
michael@0 189 if (exists) {
michael@0 190 bool isDirectory;
michael@0 191 rv = journalDirectory->IsDirectory(&isDirectory);
michael@0 192 NS_ENSURE_SUCCESS(rv, nullptr);
michael@0 193 NS_ENSURE_TRUE(isDirectory, nullptr);
michael@0 194 }
michael@0 195 else {
michael@0 196 rv = journalDirectory->Create(nsIFile::DIRECTORY_TYPE, 0755);
michael@0 197 NS_ENSURE_SUCCESS(rv, nullptr);
michael@0 198 }
michael@0 199
michael@0 200 return journalDirectory.forget();
michael@0 201 }
michael@0 202
michael@0 203 already_AddRefed<FileInfo>
michael@0 204 FileManager::GetFileInfo(int64_t aId)
michael@0 205 {
michael@0 206 if (IndexedDatabaseManager::IsClosed()) {
michael@0 207 NS_ERROR("Shouldn't be called after shutdown!");
michael@0 208 return nullptr;
michael@0 209 }
michael@0 210
michael@0 211 FileInfo* fileInfo = nullptr;
michael@0 212 {
michael@0 213 MutexAutoLock lock(IndexedDatabaseManager::FileMutex());
michael@0 214 fileInfo = mFileInfos.Get(aId);
michael@0 215 }
michael@0 216 nsRefPtr<FileInfo> result = fileInfo;
michael@0 217 return result.forget();
michael@0 218 }
michael@0 219
michael@0 220 already_AddRefed<FileInfo>
michael@0 221 FileManager::GetNewFileInfo()
michael@0 222 {
michael@0 223 if (IndexedDatabaseManager::IsClosed()) {
michael@0 224 NS_ERROR("Shouldn't be called after shutdown!");
michael@0 225 return nullptr;
michael@0 226 }
michael@0 227
michael@0 228 nsAutoPtr<FileInfo> fileInfo;
michael@0 229
michael@0 230 {
michael@0 231 MutexAutoLock lock(IndexedDatabaseManager::FileMutex());
michael@0 232
michael@0 233 int64_t id = mLastFileId + 1;
michael@0 234
michael@0 235 fileInfo = FileInfo::Create(this, id);
michael@0 236
michael@0 237 mFileInfos.Put(id, fileInfo);
michael@0 238
michael@0 239 mLastFileId = id;
michael@0 240 }
michael@0 241
michael@0 242 nsRefPtr<FileInfo> result = fileInfo.forget();
michael@0 243 return result.forget();
michael@0 244 }
michael@0 245
michael@0 246 // static
michael@0 247 already_AddRefed<nsIFile>
michael@0 248 FileManager::GetFileForId(nsIFile* aDirectory, int64_t aId)
michael@0 249 {
michael@0 250 NS_ASSERTION(aDirectory, "Null pointer!");
michael@0 251
michael@0 252 nsAutoString id;
michael@0 253 id.AppendInt(aId);
michael@0 254
michael@0 255 nsCOMPtr<nsIFile> file;
michael@0 256 nsresult rv = aDirectory->Clone(getter_AddRefs(file));
michael@0 257 NS_ENSURE_SUCCESS(rv, nullptr);
michael@0 258
michael@0 259 rv = file->Append(id);
michael@0 260 NS_ENSURE_SUCCESS(rv, nullptr);
michael@0 261
michael@0 262 return file.forget();
michael@0 263 }
michael@0 264
michael@0 265 // static
michael@0 266 nsresult
michael@0 267 FileManager::InitDirectory(nsIFile* aDirectory,
michael@0 268 nsIFile* aDatabaseFile,
michael@0 269 PersistenceType aPersistenceType,
michael@0 270 const nsACString& aGroup,
michael@0 271 const nsACString& aOrigin)
michael@0 272 {
michael@0 273 AssertIsOnIOThread();
michael@0 274 NS_ASSERTION(aDirectory, "Null directory!");
michael@0 275 NS_ASSERTION(aDatabaseFile, "Null database file!");
michael@0 276
michael@0 277 bool exists;
michael@0 278 nsresult rv = aDirectory->Exists(&exists);
michael@0 279 NS_ENSURE_SUCCESS(rv, rv);
michael@0 280
michael@0 281 if (!exists) {
michael@0 282 return NS_OK;
michael@0 283 }
michael@0 284
michael@0 285 bool isDirectory;
michael@0 286 rv = aDirectory->IsDirectory(&isDirectory);
michael@0 287 NS_ENSURE_SUCCESS(rv, rv);
michael@0 288 NS_ENSURE_TRUE(isDirectory, NS_ERROR_FAILURE);
michael@0 289
michael@0 290 nsCOMPtr<nsIFile> journalDirectory;
michael@0 291 rv = aDirectory->Clone(getter_AddRefs(journalDirectory));
michael@0 292 NS_ENSURE_SUCCESS(rv, rv);
michael@0 293
michael@0 294 rv = journalDirectory->Append(NS_LITERAL_STRING(JOURNAL_DIRECTORY_NAME));
michael@0 295 NS_ENSURE_SUCCESS(rv, rv);
michael@0 296
michael@0 297 rv = journalDirectory->Exists(&exists);
michael@0 298 NS_ENSURE_SUCCESS(rv, rv);
michael@0 299
michael@0 300 if (exists) {
michael@0 301 rv = journalDirectory->IsDirectory(&isDirectory);
michael@0 302 NS_ENSURE_SUCCESS(rv, rv);
michael@0 303 NS_ENSURE_TRUE(isDirectory, NS_ERROR_FAILURE);
michael@0 304
michael@0 305 nsCOMPtr<nsISimpleEnumerator> entries;
michael@0 306 rv = journalDirectory->GetDirectoryEntries(getter_AddRefs(entries));
michael@0 307 NS_ENSURE_SUCCESS(rv, rv);
michael@0 308
michael@0 309 bool hasElements;
michael@0 310 rv = entries->HasMoreElements(&hasElements);
michael@0 311 NS_ENSURE_SUCCESS(rv, rv);
michael@0 312
michael@0 313 if (hasElements) {
michael@0 314 nsCOMPtr<mozIStorageConnection> connection;
michael@0 315 rv = OpenDatabaseHelper::CreateDatabaseConnection(aDatabaseFile,
michael@0 316 aDirectory, NullString(), aPersistenceType, aGroup, aOrigin,
michael@0 317 getter_AddRefs(connection));
michael@0 318 NS_ENSURE_SUCCESS(rv, rv);
michael@0 319
michael@0 320 mozStorageTransaction transaction(connection, false);
michael@0 321
michael@0 322 rv = connection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
michael@0 323 "CREATE VIRTUAL TABLE fs USING filesystem;"
michael@0 324 ));
michael@0 325 NS_ENSURE_SUCCESS(rv, rv);
michael@0 326
michael@0 327 nsCOMPtr<mozIStorageStatement> stmt;
michael@0 328 rv = connection->CreateStatement(NS_LITERAL_CSTRING(
michael@0 329 "SELECT name, (name IN (SELECT id FROM file)) FROM fs "
michael@0 330 "WHERE path = :path"
michael@0 331 ), getter_AddRefs(stmt));
michael@0 332 NS_ENSURE_SUCCESS(rv, rv);
michael@0 333
michael@0 334 nsString path;
michael@0 335 rv = journalDirectory->GetPath(path);
michael@0 336 NS_ENSURE_SUCCESS(rv, rv);
michael@0 337
michael@0 338 rv = stmt->BindStringByName(NS_LITERAL_CSTRING("path"), path);
michael@0 339 NS_ENSURE_SUCCESS(rv, rv);
michael@0 340
michael@0 341 bool hasResult;
michael@0 342 while (NS_SUCCEEDED(stmt->ExecuteStep(&hasResult)) && hasResult) {
michael@0 343 nsString name;
michael@0 344 rv = stmt->GetString(0, name);
michael@0 345 NS_ENSURE_SUCCESS(rv, rv);
michael@0 346
michael@0 347 int32_t flag = stmt->AsInt32(1);
michael@0 348
michael@0 349 if (!flag) {
michael@0 350 nsCOMPtr<nsIFile> file;
michael@0 351 rv = aDirectory->Clone(getter_AddRefs(file));
michael@0 352 NS_ENSURE_SUCCESS(rv, rv);
michael@0 353
michael@0 354 rv = file->Append(name);
michael@0 355 NS_ENSURE_SUCCESS(rv, rv);
michael@0 356
michael@0 357 if (NS_FAILED(file->Remove(false))) {
michael@0 358 NS_WARNING("Failed to remove orphaned file!");
michael@0 359 }
michael@0 360 }
michael@0 361
michael@0 362 nsCOMPtr<nsIFile> journalFile;
michael@0 363 rv = journalDirectory->Clone(getter_AddRefs(journalFile));
michael@0 364 NS_ENSURE_SUCCESS(rv, rv);
michael@0 365
michael@0 366 rv = journalFile->Append(name);
michael@0 367 NS_ENSURE_SUCCESS(rv, rv);
michael@0 368
michael@0 369 if (NS_FAILED(journalFile->Remove(false))) {
michael@0 370 NS_WARNING("Failed to remove journal file!");
michael@0 371 }
michael@0 372 }
michael@0 373
michael@0 374 rv = connection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
michael@0 375 "DROP TABLE fs;"
michael@0 376 ));
michael@0 377 NS_ENSURE_SUCCESS(rv, rv);
michael@0 378
michael@0 379 transaction.Commit();
michael@0 380 }
michael@0 381 }
michael@0 382
michael@0 383 return NS_OK;
michael@0 384 }
michael@0 385
michael@0 386 // static
michael@0 387 nsresult
michael@0 388 FileManager::GetUsage(nsIFile* aDirectory, uint64_t* aUsage)
michael@0 389 {
michael@0 390 AssertIsOnIOThread();
michael@0 391
michael@0 392 bool exists;
michael@0 393 nsresult rv = aDirectory->Exists(&exists);
michael@0 394 NS_ENSURE_SUCCESS(rv, rv);
michael@0 395
michael@0 396 if (!exists) {
michael@0 397 *aUsage = 0;
michael@0 398 return NS_OK;
michael@0 399 }
michael@0 400
michael@0 401 nsCOMPtr<nsISimpleEnumerator> entries;
michael@0 402 rv = aDirectory->GetDirectoryEntries(getter_AddRefs(entries));
michael@0 403 NS_ENSURE_SUCCESS(rv, rv);
michael@0 404
michael@0 405 uint64_t usage = 0;
michael@0 406
michael@0 407 bool hasMore;
michael@0 408 while (NS_SUCCEEDED((rv = entries->HasMoreElements(&hasMore))) && hasMore) {
michael@0 409 nsCOMPtr<nsISupports> entry;
michael@0 410 rv = entries->GetNext(getter_AddRefs(entry));
michael@0 411 NS_ENSURE_SUCCESS(rv, rv);
michael@0 412
michael@0 413 nsCOMPtr<nsIFile> file = do_QueryInterface(entry);
michael@0 414 NS_ENSURE_TRUE(file, NS_NOINTERFACE);
michael@0 415
michael@0 416 nsString leafName;
michael@0 417 rv = file->GetLeafName(leafName);
michael@0 418 NS_ENSURE_SUCCESS(rv, rv);
michael@0 419
michael@0 420 if (leafName.EqualsLiteral(JOURNAL_DIRECTORY_NAME)) {
michael@0 421 continue;
michael@0 422 }
michael@0 423
michael@0 424 int64_t fileSize;
michael@0 425 rv = file->GetFileSize(&fileSize);
michael@0 426 NS_ENSURE_SUCCESS(rv, rv);
michael@0 427
michael@0 428 quota::IncrementUsage(&usage, uint64_t(fileSize));
michael@0 429 }
michael@0 430
michael@0 431 *aUsage = usage;
michael@0 432 return NS_OK;
michael@0 433 }

mercurial